1 //========================================================================
2 //
3 // Function.cc
4 //
5 // Copyright 2001-2003 Glyph & Cog, LLC
6 //
7 //========================================================================
8
9 //========================================================================
10 //
11 // Modified under the Poppler project - http://poppler.freedesktop.org
12 //
13 // All changes made under the Poppler project to this file are licensed
14 // under GPL version 2 or later
15 //
16 // Copyright (C) 2006, 2008-2010, 2013-2015, 2017-2020 Albert Astals Cid <aacid@kde.org>
17 // Copyright (C) 2006 Jeff Muizelaar <jeff@infidigm.net>
18 // Copyright (C) 2010 Christian Feuersänger <cfeuersaenger@googlemail.com>
19 // Copyright (C) 2011 Andrea Canciani <ranma42@gmail.com>
20 // Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
21 // Copyright (C) 2012 Adam Reichold <adamreichold@myopera.com>
22 // Copyright (C) 2013 Fabio D'Urso <fabiodurso@hotmail.it>
23 //
24 // To see a description of the changes please see the Changelog file that
25 // came with your tarball or type make ChangeLog if you are building from git
26 //
27 //========================================================================
28
29 #include <config.h>
30
31 #include <cstdlib>
32 #include <cstring>
33 #include <cctype>
34 #include <cmath>
35 #include "goo/gmem.h"
36 #include "goo/gstrtod.h"
37 #include "Object.h"
38 #include "Dict.h"
39 #include "Stream.h"
40 #include "Error.h"
41 #include "Function.h"
42
43 #ifndef M_PI
44 # define M_PI 3.14159265358979323846
45 #endif
46
47 //------------------------------------------------------------------------
48 // Function
49 //------------------------------------------------------------------------
50
Function()51 Function::Function() : domain {} { }
52
~Function()53 Function::~Function() { }
54
parse(Object * funcObj)55 Function *Function::parse(Object *funcObj)
56 {
57 std::set<int> usedParents;
58 return parse(funcObj, &usedParents);
59 }
60
parse(Object * funcObj,std::set<int> * usedParents)61 Function *Function::parse(Object *funcObj, std::set<int> *usedParents)
62 {
63 Function *func;
64 Dict *dict;
65 int funcType;
66
67 if (funcObj->isStream()) {
68 dict = funcObj->streamGetDict();
69 } else if (funcObj->isDict()) {
70 dict = funcObj->getDict();
71 } else if (funcObj->isName("Identity")) {
72 return new IdentityFunction();
73 } else {
74 error(errSyntaxError, -1, "Expected function dictionary or stream");
75 return nullptr;
76 }
77
78 Object obj1 = dict->lookup("FunctionType");
79 if (!obj1.isInt()) {
80 error(errSyntaxError, -1, "Function type is missing or wrong type");
81 return nullptr;
82 }
83 funcType = obj1.getInt();
84
85 if (funcType == 0) {
86 func = new SampledFunction(funcObj, dict);
87 } else if (funcType == 2) {
88 func = new ExponentialFunction(funcObj, dict);
89 } else if (funcType == 3) {
90 func = new StitchingFunction(funcObj, dict, usedParents);
91 } else if (funcType == 4) {
92 func = new PostScriptFunction(funcObj, dict);
93 } else {
94 error(errSyntaxError, -1, "Unimplemented function type ({0:d})", funcType);
95 return nullptr;
96 }
97 if (!func->isOk()) {
98 delete func;
99 return nullptr;
100 }
101
102 return func;
103 }
104
Function(const Function * func)105 Function::Function(const Function *func)
106 {
107 m = func->m;
108 n = func->n;
109
110 memcpy(domain, func->domain, funcMaxInputs * 2 * sizeof(double));
111 memcpy(range, func->range, funcMaxOutputs * 2 * sizeof(double));
112
113 hasRange = func->hasRange;
114 }
115
init(Dict * dict)116 bool Function::init(Dict *dict)
117 {
118 Object obj1;
119 int i;
120
121 //----- Domain
122 obj1 = dict->lookup("Domain");
123 if (!obj1.isArray()) {
124 error(errSyntaxError, -1, "Function is missing domain");
125 return false;
126 }
127 m = obj1.arrayGetLength() / 2;
128 if (m > funcMaxInputs) {
129 error(errSyntaxError, -1, "Functions with more than {0:d} inputs are unsupported", funcMaxInputs);
130 return false;
131 }
132 for (i = 0; i < m; ++i) {
133 Object obj2 = obj1.arrayGet(2 * i);
134 if (!obj2.isNum()) {
135 error(errSyntaxError, -1, "Illegal value in function domain array");
136 return false;
137 }
138 domain[i][0] = obj2.getNum();
139 obj2 = obj1.arrayGet(2 * i + 1);
140 if (!obj2.isNum()) {
141 error(errSyntaxError, -1, "Illegal value in function domain array");
142 return false;
143 }
144 domain[i][1] = obj2.getNum();
145 }
146
147 //----- Range
148 hasRange = false;
149 n = 0;
150 obj1 = dict->lookup("Range");
151 if (obj1.isArray()) {
152 hasRange = true;
153 n = obj1.arrayGetLength() / 2;
154 if (n > funcMaxOutputs) {
155 error(errSyntaxError, -1, "Functions with more than {0:d} outputs are unsupported", funcMaxOutputs);
156 return false;
157 }
158 for (i = 0; i < n; ++i) {
159 Object obj2 = obj1.arrayGet(2 * i);
160 if (!obj2.isNum()) {
161 error(errSyntaxError, -1, "Illegal value in function range array");
162 return false;
163 }
164 range[i][0] = obj2.getNum();
165 obj2 = obj1.arrayGet(2 * i + 1);
166 if (!obj2.isNum()) {
167 error(errSyntaxError, -1, "Illegal value in function range array");
168 return false;
169 }
170 range[i][1] = obj2.getNum();
171 }
172 }
173
174 return true;
175 }
176
177 //------------------------------------------------------------------------
178 // IdentityFunction
179 //------------------------------------------------------------------------
180
IdentityFunction()181 IdentityFunction::IdentityFunction()
182 {
183 int i;
184
185 // fill these in with arbitrary values just in case they get used
186 // somewhere
187 m = funcMaxInputs;
188 n = funcMaxOutputs;
189 for (i = 0; i < funcMaxInputs; ++i) {
190 domain[i][0] = 0;
191 domain[i][1] = 1;
192 }
193 hasRange = false;
194 }
195
~IdentityFunction()196 IdentityFunction::~IdentityFunction() { }
197
transform(const double * in,double * out) const198 void IdentityFunction::transform(const double *in, double *out) const
199 {
200 int i;
201
202 for (i = 0; i < funcMaxOutputs; ++i) {
203 out[i] = in[i];
204 }
205 }
206
207 //------------------------------------------------------------------------
208 // SampledFunction
209 //------------------------------------------------------------------------
210
SampledFunction(Object * funcObj,Dict * dict)211 SampledFunction::SampledFunction(Object *funcObj, Dict *dict) : cacheOut {}
212 {
213 Stream *str;
214 int sampleBits;
215 double sampleMul;
216 Object obj1;
217 unsigned int buf, bitMask;
218 int bits;
219 unsigned int s;
220 double in[funcMaxInputs];
221 int i, j, t, bit, idx;
222
223 idxOffset = nullptr;
224 samples = nullptr;
225 sBuf = nullptr;
226 ok = false;
227
228 //----- initialize the generic stuff
229 if (!init(dict)) {
230 return;
231 }
232 if (!hasRange) {
233 error(errSyntaxError, -1, "Type 0 function is missing range");
234 return;
235 }
236 if (m > sampledFuncMaxInputs) {
237 error(errSyntaxError, -1, "Sampled functions with more than {0:d} inputs are unsupported", sampledFuncMaxInputs);
238 return;
239 }
240
241 //----- buffer
242 sBuf = (double *)gmallocn(1 << m, sizeof(double));
243
244 //----- get the stream
245 if (!funcObj->isStream()) {
246 error(errSyntaxError, -1, "Type 0 function isn't a stream");
247 return;
248 }
249 str = funcObj->getStream();
250
251 //----- Size
252 obj1 = dict->lookup("Size");
253 if (!obj1.isArray() || obj1.arrayGetLength() != m) {
254 error(errSyntaxError, -1, "Function has missing or invalid size array");
255 return;
256 }
257 for (i = 0; i < m; ++i) {
258 Object obj2 = obj1.arrayGet(i);
259 if (!obj2.isInt()) {
260 error(errSyntaxError, -1, "Illegal value in function size array");
261 return;
262 }
263 sampleSize[i] = obj2.getInt();
264 if (sampleSize[i] <= 0) {
265 error(errSyntaxError, -1, "Illegal non-positive value in function size array");
266 return;
267 }
268 }
269 idxOffset = (int *)gmallocn(1 << m, sizeof(int));
270 for (i = 0; i < (1 << m); ++i) {
271 idx = 0;
272 for (j = m - 1, t = i; j >= 1; --j, t <<= 1) {
273 if (sampleSize[j] == 1) {
274 bit = 0;
275 } else {
276 bit = (t >> (m - 1)) & 1;
277 }
278 idx = (idx + bit) * sampleSize[j - 1];
279 }
280 if (m > 0 && sampleSize[0] == 1) {
281 bit = 0;
282 } else {
283 bit = (t >> (m - 1)) & 1;
284 }
285 idxOffset[i] = (idx + bit) * n;
286 }
287
288 //----- BitsPerSample
289 obj1 = dict->lookup("BitsPerSample");
290 if (!obj1.isInt()) {
291 error(errSyntaxError, -1, "Function has missing or invalid BitsPerSample");
292 return;
293 }
294 sampleBits = obj1.getInt();
295 if (unlikely(sampleBits < 1 || sampleBits > 32)) {
296 error(errSyntaxError, -1, "Function invalid BitsPerSample");
297 return;
298 }
299 sampleMul = 1.0 / (pow(2.0, (double)sampleBits) - 1);
300
301 //----- Encode
302 obj1 = dict->lookup("Encode");
303 if (obj1.isArray() && obj1.arrayGetLength() == 2 * m) {
304 for (i = 0; i < m; ++i) {
305 Object obj2 = obj1.arrayGet(2 * i);
306 if (!obj2.isNum()) {
307 error(errSyntaxError, -1, "Illegal value in function encode array");
308 return;
309 }
310 encode[i][0] = obj2.getNum();
311 obj2 = obj1.arrayGet(2 * i + 1);
312 if (!obj2.isNum()) {
313 error(errSyntaxError, -1, "Illegal value in function encode array");
314 return;
315 }
316 encode[i][1] = obj2.getNum();
317 }
318 } else {
319 for (i = 0; i < m; ++i) {
320 encode[i][0] = 0;
321 encode[i][1] = sampleSize[i] - 1;
322 }
323 }
324 for (i = 0; i < m; ++i) {
325 if (unlikely((domain[i][1] - domain[i][0]) == 0)) {
326 error(errSyntaxError, -1, "Illegal value in function domain array");
327 return;
328 }
329 inputMul[i] = (encode[i][1] - encode[i][0]) / (domain[i][1] - domain[i][0]);
330 }
331
332 //----- Decode
333 obj1 = dict->lookup("Decode");
334 if (obj1.isArray() && obj1.arrayGetLength() == 2 * n) {
335 for (i = 0; i < n; ++i) {
336 Object obj2 = obj1.arrayGet(2 * i);
337 if (!obj2.isNum()) {
338 error(errSyntaxError, -1, "Illegal value in function decode array");
339 return;
340 }
341 decode[i][0] = obj2.getNum();
342 obj2 = obj1.arrayGet(2 * i + 1);
343 if (!obj2.isNum()) {
344 error(errSyntaxError, -1, "Illegal value in function decode array");
345 return;
346 }
347 decode[i][1] = obj2.getNum();
348 }
349 } else {
350 for (i = 0; i < n; ++i) {
351 decode[i][0] = range[i][0];
352 decode[i][1] = range[i][1];
353 }
354 }
355
356 //----- samples
357 nSamples = n;
358 for (i = 0; i < m; ++i)
359 nSamples *= sampleSize[i];
360 samples = (double *)gmallocn_checkoverflow(nSamples, sizeof(double));
361 if (!samples) {
362 error(errSyntaxError, -1, "Function has invalid number of samples");
363 return;
364 }
365 buf = 0;
366 bits = 0;
367 bitMask = (1 << sampleBits) - 1;
368 str->reset();
369 for (i = 0; i < nSamples; ++i) {
370 if (sampleBits == 8) {
371 s = str->getChar();
372 } else if (sampleBits == 16) {
373 s = str->getChar();
374 s = (s << 8) + str->getChar();
375 } else if (sampleBits == 32) {
376 s = str->getChar();
377 s = (s << 8) + str->getChar();
378 s = (s << 8) + str->getChar();
379 s = (s << 8) + str->getChar();
380 } else {
381 while (bits < sampleBits) {
382 buf = (buf << 8) | (str->getChar() & 0xff);
383 bits += 8;
384 }
385 s = (buf >> (bits - sampleBits)) & bitMask;
386 bits -= sampleBits;
387 }
388 samples[i] = (double)s * sampleMul;
389 }
390 str->close();
391
392 // set up the cache
393 for (i = 0; i < m; ++i) {
394 in[i] = domain[i][0];
395 cacheIn[i] = in[i] - 1;
396 }
397 transform(in, cacheOut);
398
399 ok = true;
400 }
401
~SampledFunction()402 SampledFunction::~SampledFunction()
403 {
404 if (idxOffset) {
405 gfree(idxOffset);
406 }
407 if (samples) {
408 gfree(samples);
409 }
410 if (sBuf) {
411 gfree(sBuf);
412 }
413 }
414
SampledFunction(const SampledFunction * func)415 SampledFunction::SampledFunction(const SampledFunction *func) : Function(func)
416 {
417 memcpy(sampleSize, func->sampleSize, funcMaxInputs * sizeof(int));
418
419 memcpy(encode, func->encode, funcMaxInputs * 2 * sizeof(double));
420 memcpy(decode, func->decode, funcMaxOutputs * 2 * sizeof(double));
421
422 memcpy(inputMul, func->inputMul, funcMaxInputs * sizeof(double));
423
424 nSamples = func->nSamples;
425
426 idxOffset = (int *)gmallocn(1 << m, sizeof(int));
427 memcpy(idxOffset, func->idxOffset, (1 << m) * (int)sizeof(int));
428
429 samples = (double *)gmallocn(nSamples, sizeof(double));
430 memcpy(samples, func->samples, nSamples * sizeof(double));
431
432 sBuf = (double *)gmallocn(1 << m, sizeof(double));
433
434 memcpy(cacheIn, func->cacheIn, funcMaxInputs * sizeof(double));
435 memcpy(cacheOut, func->cacheOut, funcMaxOutputs * sizeof(double));
436
437 ok = func->ok;
438 }
439
transform(const double * in,double * out) const440 void SampledFunction::transform(const double *in, double *out) const
441 {
442 double x;
443 int e[funcMaxInputs];
444 double efrac0[funcMaxInputs];
445 double efrac1[funcMaxInputs];
446
447 // check the cache
448 bool inCache = true;
449 for (int i = 0; i < m; ++i) {
450 if (in[i] != cacheIn[i]) {
451 inCache = false;
452 break;
453 }
454 }
455 if (inCache) {
456 for (int i = 0; i < n; ++i) {
457 out[i] = cacheOut[i];
458 }
459 return;
460 }
461
462 // map input values into sample array
463 for (int i = 0; i < m; ++i) {
464 x = (in[i] - domain[i][0]) * inputMul[i] + encode[i][0];
465 if (x < 0 || x != x) { // x!=x is a more portable version of isnan(x)
466 x = 0;
467 } else if (x > sampleSize[i] - 1) {
468 x = sampleSize[i] - 1;
469 }
470 e[i] = (int)x;
471 if (e[i] == sampleSize[i] - 1 && sampleSize[i] > 1) {
472 // this happens if in[i] = domain[i][1]
473 e[i] = sampleSize[i] - 2;
474 }
475 efrac1[i] = x - e[i];
476 efrac0[i] = 1 - efrac1[i];
477 }
478
479 // compute index for the first sample to be used
480 int idx0 = 0;
481 for (int k = m - 1; k >= 1; --k) {
482 idx0 = (idx0 + e[k]) * sampleSize[k - 1];
483 }
484 idx0 = (idx0 + e[0]) * n;
485
486 // for each output, do m-linear interpolation
487 for (int i = 0; i < n; ++i) {
488
489 // pull 2^m values out of the sample array
490 for (int j = 0; j < (1 << m); ++j) {
491 int idx = idx0 + idxOffset[j] + i;
492 if (likely(idx >= 0 && idx < nSamples)) {
493 sBuf[j] = samples[idx];
494 } else {
495 sBuf[j] = 0; // TODO Investigate if this is what Adobe does
496 }
497 }
498
499 // do m sets of interpolations
500 for (int j = 0, t = (1 << m); j < m; ++j, t >>= 1) {
501 for (int k = 0; k < t; k += 2) {
502 sBuf[k >> 1] = efrac0[j] * sBuf[k] + efrac1[j] * sBuf[k + 1];
503 }
504 }
505
506 // map output value to range
507 out[i] = sBuf[0] * (decode[i][1] - decode[i][0]) + decode[i][0];
508 if (out[i] < range[i][0]) {
509 out[i] = range[i][0];
510 } else if (out[i] > range[i][1]) {
511 out[i] = range[i][1];
512 }
513 }
514
515 // save current result in the cache
516 for (int i = 0; i < m; ++i) {
517 cacheIn[i] = in[i];
518 }
519 for (int i = 0; i < n; ++i) {
520 cacheOut[i] = out[i];
521 }
522 }
523
hasDifferentResultSet(const Function * func) const524 bool SampledFunction::hasDifferentResultSet(const Function *func) const
525 {
526 if (func->getType() == 0) {
527 SampledFunction *compTo = (SampledFunction *)func;
528 if (compTo->getSampleNumber() != nSamples)
529 return true;
530 const double *compSamples = compTo->getSamples();
531 for (int i = 0; i < nSamples; i++) {
532 if (samples[i] != compSamples[i])
533 return true;
534 }
535 }
536 return false;
537 }
538
539 //------------------------------------------------------------------------
540 // ExponentialFunction
541 //------------------------------------------------------------------------
542
ExponentialFunction(Object * funcObj,Dict * dict)543 ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict)
544 {
545 Object obj1;
546
547 ok = false;
548
549 //----- initialize the generic stuff
550 if (!init(dict)) {
551 return;
552 }
553 if (m != 1) {
554 error(errSyntaxError, -1, "Exponential function with more than one input");
555 return;
556 }
557
558 //----- C0
559 obj1 = dict->lookup("C0");
560 if (obj1.isArray()) {
561 if (hasRange && obj1.arrayGetLength() != n) {
562 error(errSyntaxError, -1, "Function's C0 array is wrong length");
563 return;
564 }
565 n = obj1.arrayGetLength();
566 if (unlikely(n > funcMaxOutputs)) {
567 error(errSyntaxError, -1, "Function's C0 array is wrong length");
568 n = funcMaxOutputs;
569 }
570 for (int i = 0; i < n; ++i) {
571 Object obj2 = obj1.arrayGet(i);
572 if (!obj2.isNum()) {
573 error(errSyntaxError, -1, "Illegal value in function C0 array");
574 return;
575 }
576 c0[i] = obj2.getNum();
577 }
578 } else {
579 if (hasRange && n != 1) {
580 error(errSyntaxError, -1, "Function's C0 array is wrong length");
581 return;
582 }
583 n = 1;
584 c0[0] = 0;
585 }
586
587 //----- C1
588 obj1 = dict->lookup("C1");
589 if (obj1.isArray()) {
590 if (obj1.arrayGetLength() != n) {
591 error(errSyntaxError, -1, "Function's C1 array is wrong length");
592 return;
593 }
594 for (int i = 0; i < n; ++i) {
595 Object obj2 = obj1.arrayGet(i);
596 if (!obj2.isNum()) {
597 error(errSyntaxError, -1, "Illegal value in function C1 array");
598 return;
599 }
600 c1[i] = obj2.getNum();
601 }
602 } else {
603 if (n != 1) {
604 error(errSyntaxError, -1, "Function's C1 array is wrong length");
605 return;
606 }
607 c1[0] = 1;
608 }
609
610 //----- N (exponent)
611 obj1 = dict->lookup("N");
612 if (!obj1.isNum()) {
613 error(errSyntaxError, -1, "Function has missing or invalid N");
614 return;
615 }
616 e = obj1.getNum();
617
618 isLinear = fabs(e - 1.) < 1e-10;
619 ok = true;
620 }
621
~ExponentialFunction()622 ExponentialFunction::~ExponentialFunction() { }
623
ExponentialFunction(const ExponentialFunction * func)624 ExponentialFunction::ExponentialFunction(const ExponentialFunction *func) : Function(func)
625 {
626 memcpy(c0, func->c0, funcMaxOutputs * sizeof(double));
627 memcpy(c1, func->c1, funcMaxOutputs * sizeof(double));
628
629 e = func->e;
630 isLinear = func->isLinear;
631 ok = func->ok;
632 }
633
transform(const double * in,double * out) const634 void ExponentialFunction::transform(const double *in, double *out) const
635 {
636 double x;
637 int i;
638
639 if (in[0] < domain[0][0]) {
640 x = domain[0][0];
641 } else if (in[0] > domain[0][1]) {
642 x = domain[0][1];
643 } else {
644 x = in[0];
645 }
646 for (i = 0; i < n; ++i) {
647 out[i] = c0[i] + (isLinear ? x : pow(x, e)) * (c1[i] - c0[i]);
648 if (hasRange) {
649 if (out[i] < range[i][0]) {
650 out[i] = range[i][0];
651 } else if (out[i] > range[i][1]) {
652 out[i] = range[i][1];
653 }
654 }
655 }
656 return;
657 }
658
659 //------------------------------------------------------------------------
660 // StitchingFunction
661 //------------------------------------------------------------------------
662
StitchingFunction(Object * funcObj,Dict * dict,std::set<int> * usedParents)663 StitchingFunction::StitchingFunction(Object *funcObj, Dict *dict, std::set<int> *usedParents)
664 {
665 Object obj1;
666 int i;
667
668 ok = false;
669 funcs = nullptr;
670 bounds = nullptr;
671 encode = nullptr;
672 scale = nullptr;
673
674 //----- initialize the generic stuff
675 if (!init(dict)) {
676 return;
677 }
678 if (m != 1) {
679 error(errSyntaxError, -1, "Stitching function with more than one input");
680 return;
681 }
682
683 //----- Functions
684 obj1 = dict->lookup("Functions");
685 if (!obj1.isArray()) {
686 error(errSyntaxError, -1, "Missing 'Functions' entry in stitching function");
687 return;
688 }
689 k = obj1.arrayGetLength();
690 funcs = (Function **)gmallocn(k, sizeof(Function *));
691 bounds = (double *)gmallocn(k + 1, sizeof(double));
692 encode = (double *)gmallocn(2 * k, sizeof(double));
693 scale = (double *)gmallocn(k, sizeof(double));
694 for (i = 0; i < k; ++i) {
695 funcs[i] = nullptr;
696 }
697 for (i = 0; i < k; ++i) {
698 std::set<int> usedParentsAux = *usedParents;
699 Ref ref;
700 Object obj2 = obj1.getArray()->get(i, &ref);
701 if (ref != Ref::INVALID()) {
702 if (usedParentsAux.find(ref.num) == usedParentsAux.end()) {
703 usedParentsAux.insert(ref.num);
704 } else {
705 return;
706 }
707 }
708 if (!(funcs[i] = Function::parse(&obj2, &usedParentsAux))) {
709 return;
710 }
711 if (funcs[i]->getInputSize() != 1 || (i > 0 && funcs[i]->getOutputSize() != funcs[0]->getOutputSize())) {
712 error(errSyntaxError, -1, "Incompatible subfunctions in stitching function");
713 return;
714 }
715 }
716
717 //----- Bounds
718 obj1 = dict->lookup("Bounds");
719 if (!obj1.isArray() || obj1.arrayGetLength() != k - 1) {
720 error(errSyntaxError, -1, "Missing or invalid 'Bounds' entry in stitching function");
721 return;
722 }
723 bounds[0] = domain[0][0];
724 for (i = 1; i < k; ++i) {
725 Object obj2 = obj1.arrayGet(i - 1);
726 if (!obj2.isNum()) {
727 error(errSyntaxError, -1, "Invalid type in 'Bounds' array in stitching function");
728 return;
729 }
730 bounds[i] = obj2.getNum();
731 }
732 bounds[k] = domain[0][1];
733
734 //----- Encode
735 obj1 = dict->lookup("Encode");
736 if (!obj1.isArray() || obj1.arrayGetLength() != 2 * k) {
737 error(errSyntaxError, -1, "Missing or invalid 'Encode' entry in stitching function");
738 return;
739 }
740 for (i = 0; i < 2 * k; ++i) {
741 Object obj2 = obj1.arrayGet(i);
742 if (!obj2.isNum()) {
743 error(errSyntaxError, -1, "Invalid type in 'Encode' array in stitching function");
744 return;
745 }
746 encode[i] = obj2.getNum();
747 }
748
749 //----- pre-compute the scale factors
750 for (i = 0; i < k; ++i) {
751 if (bounds[i] == bounds[i + 1]) {
752 // avoid a divide-by-zero -- in this situation, function i will
753 // never be used anyway
754 scale[i] = 0;
755 } else {
756 scale[i] = (encode[2 * i + 1] - encode[2 * i]) / (bounds[i + 1] - bounds[i]);
757 }
758 }
759
760 n = funcs[0]->getOutputSize();
761 ok = true;
762 return;
763 }
764
StitchingFunction(const StitchingFunction * func)765 StitchingFunction::StitchingFunction(const StitchingFunction *func) : Function(func)
766 {
767 k = func->k;
768
769 funcs = (Function **)gmallocn(k, sizeof(Function *));
770 for (int i = 0; i < k; ++i) {
771 funcs[i] = func->funcs[i]->copy();
772 }
773
774 bounds = (double *)gmallocn(k + 1, sizeof(double));
775 memcpy(bounds, func->bounds, (k + 1) * sizeof(double));
776
777 encode = (double *)gmallocn(2 * k, sizeof(double));
778 memcpy(encode, func->encode, 2 * k * sizeof(double));
779
780 scale = (double *)gmallocn(k, sizeof(double));
781 memcpy(scale, func->scale, k * sizeof(double));
782
783 ok = func->ok;
784 }
785
~StitchingFunction()786 StitchingFunction::~StitchingFunction()
787 {
788 int i;
789
790 if (funcs) {
791 for (i = 0; i < k; ++i) {
792 if (funcs[i]) {
793 delete funcs[i];
794 }
795 }
796 }
797 gfree(funcs);
798 gfree(bounds);
799 gfree(encode);
800 gfree(scale);
801 }
802
transform(const double * in,double * out) const803 void StitchingFunction::transform(const double *in, double *out) const
804 {
805 double x;
806 int i;
807
808 if (in[0] < domain[0][0]) {
809 x = domain[0][0];
810 } else if (in[0] > domain[0][1]) {
811 x = domain[0][1];
812 } else {
813 x = in[0];
814 }
815 for (i = 0; i < k - 1; ++i) {
816 if (x < bounds[i + 1]) {
817 break;
818 }
819 }
820 x = encode[2 * i] + (x - bounds[i]) * scale[i];
821 funcs[i]->transform(&x, out);
822 }
823
824 //------------------------------------------------------------------------
825 // PostScriptFunction
826 //------------------------------------------------------------------------
827
828 enum PSOp
829 {
830 psOpAbs,
831 psOpAdd,
832 psOpAnd,
833 psOpAtan,
834 psOpBitshift,
835 psOpCeiling,
836 psOpCopy,
837 psOpCos,
838 psOpCvi,
839 psOpCvr,
840 psOpDiv,
841 psOpDup,
842 psOpEq,
843 psOpExch,
844 psOpExp,
845 psOpFalse,
846 psOpFloor,
847 psOpGe,
848 psOpGt,
849 psOpIdiv,
850 psOpIndex,
851 psOpLe,
852 psOpLn,
853 psOpLog,
854 psOpLt,
855 psOpMod,
856 psOpMul,
857 psOpNe,
858 psOpNeg,
859 psOpNot,
860 psOpOr,
861 psOpPop,
862 psOpRoll,
863 psOpRound,
864 psOpSin,
865 psOpSqrt,
866 psOpSub,
867 psOpTrue,
868 psOpTruncate,
869 psOpXor,
870 psOpIf,
871 psOpIfelse,
872 psOpReturn
873 };
874
875 // Note: 'if' and 'ifelse' are parsed separately.
876 // The rest are listed here in alphabetical order.
877 // The index in this table is equivalent to the entry in PSOp.
878 static const char *psOpNames[] = { "abs", "add", "and", "atan", "bitshift", "ceiling", "copy", "cos", "cvi", "cvr", "div", "dup", "eq", "exch", "exp", "false", "floor", "ge", "gt", "idiv",
879 "index", "le", "ln", "log", "lt", "mod", "mul", "ne", "neg", "not", "or", "pop", "roll", "round", "sin", "sqrt", "sub", "true", "truncate", "xor" };
880
881 #define nPSOps (sizeof(psOpNames) / sizeof(char *))
882
883 enum PSObjectType
884 {
885 psBool,
886 psInt,
887 psReal,
888 psOperator,
889 psBlock
890 };
891
892 // In the code array, 'if'/'ifelse' operators take up three slots
893 // plus space for the code in the subclause(s).
894 //
895 // +---------------------------------+
896 // | psOperator: psOpIf / psOpIfelse |
897 // +---------------------------------+
898 // | psBlock: ptr=<A> |
899 // +---------------------------------+
900 // | psBlock: ptr=<B> |
901 // +---------------------------------+
902 // | if clause |
903 // | ... |
904 // | psOperator: psOpReturn |
905 // +---------------------------------+
906 // <A> | else clause |
907 // | ... |
908 // | psOperator: psOpReturn |
909 // +---------------------------------+
910 // <B> | ... |
911 //
912 // For 'if', pointer <A> is present in the code stream but unused.
913
914 struct PSObject
915 {
916 PSObjectType type;
917 union {
918 bool booln; // boolean (stack only)
919 int intg; // integer (stack and code)
920 double real; // real (stack and code)
921 PSOp op; // operator (code only)
922 int blk; // if/ifelse block pointer (code only)
923 };
924 };
925
926 #define psStackSize 100
927
928 class PSStack
929 {
930 public:
PSStack()931 PSStack() { sp = psStackSize; }
clear()932 void clear() { sp = psStackSize; }
pushBool(bool booln)933 void pushBool(bool booln)
934 {
935 if (checkOverflow()) {
936 stack[--sp].type = psBool;
937 stack[sp].booln = booln;
938 }
939 }
pushInt(int intg)940 void pushInt(int intg)
941 {
942 if (checkOverflow()) {
943 stack[--sp].type = psInt;
944 stack[sp].intg = intg;
945 }
946 }
pushReal(double real)947 void pushReal(double real)
948 {
949 if (checkOverflow()) {
950 stack[--sp].type = psReal;
951 stack[sp].real = real;
952 }
953 }
popBool()954 bool popBool()
955 {
956 if (checkUnderflow() && checkType(psBool, psBool)) {
957 return stack[sp++].booln;
958 }
959 return false;
960 }
popInt()961 int popInt()
962 {
963 if (checkUnderflow() && checkType(psInt, psInt)) {
964 return stack[sp++].intg;
965 }
966 return 0;
967 }
popNum()968 double popNum()
969 {
970 double ret;
971
972 if (checkUnderflow() && checkType(psInt, psReal)) {
973 ret = (stack[sp].type == psInt) ? (double)stack[sp].intg : stack[sp].real;
974 ++sp;
975 return ret;
976 }
977 return 0;
978 }
empty()979 bool empty() { return sp == psStackSize; }
topIsInt()980 bool topIsInt() { return sp < psStackSize && stack[sp].type == psInt; }
topTwoAreInts()981 bool topTwoAreInts() { return sp < psStackSize - 1 && stack[sp].type == psInt && stack[sp + 1].type == psInt; }
topIsReal()982 bool topIsReal() { return sp < psStackSize && stack[sp].type == psReal; }
topTwoAreNums()983 bool topTwoAreNums() { return sp < psStackSize - 1 && (stack[sp].type == psInt || stack[sp].type == psReal) && (stack[sp + 1].type == psInt || stack[sp + 1].type == psReal); }
984 void copy(int n);
985 void roll(int n, int j);
index(int i)986 void index(int i)
987 {
988 if (!checkOverflow()) {
989 return;
990 }
991 --sp;
992 if (unlikely(sp + i + 1 >= psStackSize)) {
993 error(errSyntaxError, -1, "Stack underflow in PostScript function");
994 return;
995 }
996 if (unlikely(sp + i + 1 < 0)) {
997 error(errSyntaxError, -1, "Stack overflow in PostScript function");
998 return;
999 }
1000 stack[sp] = stack[sp + 1 + i];
1001 }
pop()1002 void pop()
1003 {
1004 if (!checkUnderflow()) {
1005 return;
1006 }
1007 ++sp;
1008 }
1009
1010 private:
checkOverflow(int n=1)1011 bool checkOverflow(int n = 1)
1012 {
1013 if (sp - n < 0) {
1014 error(errSyntaxError, -1, "Stack overflow in PostScript function");
1015 return false;
1016 }
1017 return true;
1018 }
checkUnderflow()1019 bool checkUnderflow()
1020 {
1021 if (sp == psStackSize) {
1022 error(errSyntaxError, -1, "Stack underflow in PostScript function");
1023 return false;
1024 }
1025 return true;
1026 }
checkType(PSObjectType t1,PSObjectType t2)1027 bool checkType(PSObjectType t1, PSObjectType t2)
1028 {
1029 if (stack[sp].type != t1 && stack[sp].type != t2) {
1030 error(errSyntaxError, -1, "Type mismatch in PostScript function");
1031 return false;
1032 }
1033 return true;
1034 }
1035 PSObject stack[psStackSize];
1036 int sp;
1037 };
1038
copy(int n)1039 void PSStack::copy(int n)
1040 {
1041 int i;
1042
1043 int aux;
1044 if (unlikely(checkedAdd(sp, n, &aux) || aux > psStackSize)) {
1045 error(errSyntaxError, -1, "Stack underflow in PostScript function");
1046 return;
1047 }
1048 if (unlikely(checkedSubtraction(sp, n, &aux) || aux > psStackSize)) {
1049 error(errSyntaxError, -1, "Stack underflow in PostScript function");
1050 return;
1051 }
1052 if (!checkOverflow(n)) {
1053 return;
1054 }
1055 for (i = sp + n - 1; i >= sp; --i) {
1056 stack[i - n] = stack[i];
1057 }
1058 sp -= n;
1059 }
1060
roll(int n,int j)1061 void PSStack::roll(int n, int j)
1062 {
1063 PSObject obj;
1064 int i, k;
1065
1066 if (unlikely(n == 0)) {
1067 return;
1068 }
1069 if (j >= 0) {
1070 j %= n;
1071 } else {
1072 j = -j % n;
1073 if (j != 0) {
1074 j = n - j;
1075 }
1076 }
1077 if (n <= 0 || j == 0 || n > psStackSize || sp + n > psStackSize) {
1078 return;
1079 }
1080 if (j <= n / 2) {
1081 for (i = 0; i < j; ++i) {
1082 obj = stack[sp];
1083 for (k = sp; k < sp + n - 1; ++k) {
1084 stack[k] = stack[k + 1];
1085 }
1086 stack[sp + n - 1] = obj;
1087 }
1088 } else {
1089 j = n - j;
1090 for (i = 0; i < j; ++i) {
1091 obj = stack[sp + n - 1];
1092 for (k = sp + n - 1; k > sp; --k) {
1093 stack[k] = stack[k - 1];
1094 }
1095 stack[sp] = obj;
1096 }
1097 }
1098 }
1099
PostScriptFunction(Object * funcObj,Dict * dict)1100 PostScriptFunction::PostScriptFunction(Object *funcObj, Dict *dict)
1101 {
1102 Stream *str;
1103 int codePtr;
1104 double in[funcMaxInputs];
1105 int i;
1106
1107 code = nullptr;
1108 codeString = nullptr;
1109 codeSize = 0;
1110 ok = false;
1111
1112 //----- initialize the generic stuff
1113 if (!init(dict)) {
1114 goto err1;
1115 }
1116 if (!hasRange) {
1117 error(errSyntaxError, -1, "Type 4 function is missing range");
1118 goto err1;
1119 }
1120
1121 //----- get the stream
1122 if (!funcObj->isStream()) {
1123 error(errSyntaxError, -1, "Type 4 function isn't a stream");
1124 goto err1;
1125 }
1126 str = funcObj->getStream();
1127
1128 //----- parse the function
1129 codeString = new GooString();
1130 str->reset();
1131 if (getToken(str).cmp("{") != 0) {
1132 error(errSyntaxError, -1, "Expected '{{' at start of PostScript function");
1133 goto err1;
1134 }
1135 codePtr = 0;
1136 if (!parseCode(str, &codePtr)) {
1137 goto err2;
1138 }
1139 str->close();
1140
1141 //----- set up the cache
1142 for (i = 0; i < m; ++i) {
1143 in[i] = domain[i][0];
1144 cacheIn[i] = in[i] - 1;
1145 }
1146 transform(in, cacheOut);
1147
1148 ok = true;
1149
1150 err2:
1151 str->close();
1152 err1:
1153 return;
1154 }
1155
PostScriptFunction(const PostScriptFunction * func)1156 PostScriptFunction::PostScriptFunction(const PostScriptFunction *func) : Function(func)
1157 {
1158 codeSize = func->codeSize;
1159
1160 code = (PSObject *)gmallocn(codeSize, sizeof(PSObject));
1161 memcpy(code, func->code, codeSize * sizeof(PSObject));
1162
1163 codeString = func->codeString->copy();
1164
1165 memcpy(cacheIn, func->cacheIn, funcMaxInputs * sizeof(double));
1166 memcpy(cacheOut, func->cacheOut, funcMaxOutputs * sizeof(double));
1167
1168 ok = func->ok;
1169 }
1170
~PostScriptFunction()1171 PostScriptFunction::~PostScriptFunction()
1172 {
1173 gfree(code);
1174 delete codeString;
1175 }
1176
transform(const double * in,double * out) const1177 void PostScriptFunction::transform(const double *in, double *out) const
1178 {
1179 PSStack stack;
1180 int i;
1181
1182 // check the cache
1183 for (i = 0; i < m; ++i) {
1184 if (in[i] != cacheIn[i]) {
1185 break;
1186 }
1187 }
1188 if (i == m) {
1189 for (i = 0; i < n; ++i) {
1190 out[i] = cacheOut[i];
1191 }
1192 return;
1193 }
1194
1195 for (i = 0; i < m; ++i) {
1196 //~ may need to check for integers here
1197 stack.pushReal(in[i]);
1198 }
1199 exec(&stack, 0);
1200 for (i = n - 1; i >= 0; --i) {
1201 out[i] = stack.popNum();
1202 if (out[i] < range[i][0]) {
1203 out[i] = range[i][0];
1204 } else if (out[i] > range[i][1]) {
1205 out[i] = range[i][1];
1206 }
1207 }
1208 stack.clear();
1209
1210 // if (!stack->empty()) {
1211 // error(errSyntaxWarning, -1,
1212 // "Extra values on stack at end of PostScript function");
1213 // }
1214
1215 // save current result in the cache
1216 for (i = 0; i < m; ++i) {
1217 cacheIn[i] = in[i];
1218 }
1219 for (i = 0; i < n; ++i) {
1220 cacheOut[i] = out[i];
1221 }
1222 }
1223
parseCode(Stream * str,int * codePtr)1224 bool PostScriptFunction::parseCode(Stream *str, int *codePtr)
1225 {
1226 bool isReal;
1227 int opPtr, elsePtr;
1228 int a, b, mid, cmp;
1229
1230 while (true) {
1231 GooString tok = getToken(str);
1232 const char *p = tok.c_str();
1233 if (isdigit(*p) || *p == '.' || *p == '-') {
1234 isReal = false;
1235 for (; *p; ++p) {
1236 if (*p == '.') {
1237 isReal = true;
1238 break;
1239 }
1240 }
1241 resizeCode(*codePtr);
1242 if (isReal) {
1243 code[*codePtr].type = psReal;
1244 code[*codePtr].real = gatof(tok.c_str());
1245 } else {
1246 code[*codePtr].type = psInt;
1247 code[*codePtr].intg = atoi(tok.c_str());
1248 }
1249 ++*codePtr;
1250 } else if (!tok.cmp("{")) {
1251 opPtr = *codePtr;
1252 *codePtr += 3;
1253 resizeCode(opPtr + 2);
1254 if (!parseCode(str, codePtr)) {
1255 return false;
1256 }
1257 tok = getToken(str);
1258 if (!tok.cmp("{")) {
1259 elsePtr = *codePtr;
1260 if (!parseCode(str, codePtr)) {
1261 return false;
1262 }
1263 tok = getToken(str);
1264 } else {
1265 elsePtr = -1;
1266 }
1267 if (!tok.cmp("if")) {
1268 if (elsePtr >= 0) {
1269 error(errSyntaxError, -1, "Got 'if' operator with two blocks in PostScript function");
1270 return false;
1271 }
1272 code[opPtr].type = psOperator;
1273 code[opPtr].op = psOpIf;
1274 code[opPtr + 2].type = psBlock;
1275 code[opPtr + 2].blk = *codePtr;
1276 } else if (!tok.cmp("ifelse")) {
1277 if (elsePtr < 0) {
1278 error(errSyntaxError, -1, "Got 'ifelse' operator with one block in PostScript function");
1279 return false;
1280 }
1281 code[opPtr].type = psOperator;
1282 code[opPtr].op = psOpIfelse;
1283 code[opPtr + 1].type = psBlock;
1284 code[opPtr + 1].blk = elsePtr;
1285 code[opPtr + 2].type = psBlock;
1286 code[opPtr + 2].blk = *codePtr;
1287 } else {
1288 error(errSyntaxError, -1, "Expected if/ifelse operator in PostScript function");
1289 return false;
1290 }
1291 } else if (!tok.cmp("}")) {
1292 resizeCode(*codePtr);
1293 code[*codePtr].type = psOperator;
1294 code[*codePtr].op = psOpReturn;
1295 ++*codePtr;
1296 break;
1297 } else {
1298 a = -1;
1299 b = nPSOps;
1300 cmp = 0; // make gcc happy
1301 // invariant: psOpNames[a] < tok < psOpNames[b]
1302 while (b - a > 1) {
1303 mid = (a + b) / 2;
1304 cmp = tok.cmp(psOpNames[mid]);
1305 if (cmp > 0) {
1306 a = mid;
1307 } else if (cmp < 0) {
1308 b = mid;
1309 } else {
1310 a = b = mid;
1311 }
1312 }
1313 if (cmp != 0) {
1314 error(errSyntaxError, -1, "Unknown operator '{0:t}' in PostScript function", &tok);
1315 return false;
1316 }
1317 resizeCode(*codePtr);
1318 code[*codePtr].type = psOperator;
1319 code[*codePtr].op = (PSOp)a;
1320 ++*codePtr;
1321 }
1322 }
1323 return true;
1324 }
1325
getToken(Stream * str)1326 GooString PostScriptFunction::getToken(Stream *str)
1327 {
1328 int c;
1329 bool comment;
1330
1331 GooString s;
1332 comment = false;
1333 while (true) {
1334 if ((c = str->getChar()) == EOF) {
1335 break;
1336 }
1337 codeString->append(c);
1338 if (comment) {
1339 if (c == '\x0a' || c == '\x0d') {
1340 comment = false;
1341 }
1342 } else if (c == '%') {
1343 comment = true;
1344 } else if (!isspace(c)) {
1345 break;
1346 }
1347 }
1348 if (c == '{' || c == '}') {
1349 s.append((char)c);
1350 } else if (isdigit(c) || c == '.' || c == '-') {
1351 while (true) {
1352 s.append((char)c);
1353 c = str->lookChar();
1354 if (c == EOF || !(isdigit(c) || c == '.' || c == '-')) {
1355 break;
1356 }
1357 str->getChar();
1358 codeString->append(c);
1359 }
1360 } else {
1361 while (true) {
1362 s.append((char)c);
1363 c = str->lookChar();
1364 if (c == EOF || !isalnum(c)) {
1365 break;
1366 }
1367 str->getChar();
1368 codeString->append(c);
1369 }
1370 }
1371 return s;
1372 }
1373
resizeCode(int newSize)1374 void PostScriptFunction::resizeCode(int newSize)
1375 {
1376 if (newSize >= codeSize) {
1377 codeSize += 64;
1378 code = (PSObject *)greallocn(code, codeSize, sizeof(PSObject));
1379 }
1380 }
1381
exec(PSStack * stack,int codePtr) const1382 void PostScriptFunction::exec(PSStack *stack, int codePtr) const
1383 {
1384 int i1, i2;
1385 double r1, r2, result;
1386 bool b1, b2;
1387
1388 while (true) {
1389 switch (code[codePtr].type) {
1390 case psInt:
1391 stack->pushInt(code[codePtr++].intg);
1392 break;
1393 case psReal:
1394 stack->pushReal(code[codePtr++].real);
1395 break;
1396 case psOperator:
1397 switch (code[codePtr++].op) {
1398 case psOpAbs:
1399 if (stack->topIsInt()) {
1400 stack->pushInt(abs(stack->popInt()));
1401 } else {
1402 stack->pushReal(fabs(stack->popNum()));
1403 }
1404 break;
1405 case psOpAdd:
1406 if (stack->topTwoAreInts()) {
1407 i2 = stack->popInt();
1408 i1 = stack->popInt();
1409 stack->pushInt(i1 + i2);
1410 } else {
1411 r2 = stack->popNum();
1412 r1 = stack->popNum();
1413 stack->pushReal(r1 + r2);
1414 }
1415 break;
1416 case psOpAnd:
1417 if (stack->topTwoAreInts()) {
1418 i2 = stack->popInt();
1419 i1 = stack->popInt();
1420 stack->pushInt(i1 & i2);
1421 } else {
1422 b2 = stack->popBool();
1423 b1 = stack->popBool();
1424 stack->pushBool(b1 && b2);
1425 }
1426 break;
1427 case psOpAtan:
1428 r2 = stack->popNum();
1429 r1 = stack->popNum();
1430 result = atan2(r1, r2) * 180.0 / M_PI;
1431 if (result < 0)
1432 result += 360.0;
1433 stack->pushReal(result);
1434 break;
1435 case psOpBitshift:
1436 i2 = stack->popInt();
1437 i1 = stack->popInt();
1438 if (i2 > 0) {
1439 stack->pushInt(i1 << i2);
1440 } else if (i2 < 0) {
1441 stack->pushInt((int)((unsigned int)i1 >> -i2));
1442 } else {
1443 stack->pushInt(i1);
1444 }
1445 break;
1446 case psOpCeiling:
1447 if (!stack->topIsInt()) {
1448 stack->pushReal(ceil(stack->popNum()));
1449 }
1450 break;
1451 case psOpCopy:
1452 stack->copy(stack->popInt());
1453 break;
1454 case psOpCos:
1455 stack->pushReal(cos(stack->popNum() * M_PI / 180.0));
1456 break;
1457 case psOpCvi:
1458 if (!stack->topIsInt()) {
1459 stack->pushInt((int)stack->popNum());
1460 }
1461 break;
1462 case psOpCvr:
1463 if (!stack->topIsReal()) {
1464 stack->pushReal(stack->popNum());
1465 }
1466 break;
1467 case psOpDiv:
1468 r2 = stack->popNum();
1469 r1 = stack->popNum();
1470 stack->pushReal(r1 / r2);
1471 break;
1472 case psOpDup:
1473 stack->copy(1);
1474 break;
1475 case psOpEq:
1476 if (stack->topTwoAreInts()) {
1477 i2 = stack->popInt();
1478 i1 = stack->popInt();
1479 stack->pushBool(i1 == i2);
1480 } else if (stack->topTwoAreNums()) {
1481 r2 = stack->popNum();
1482 r1 = stack->popNum();
1483 stack->pushBool(r1 == r2);
1484 } else {
1485 b2 = stack->popBool();
1486 b1 = stack->popBool();
1487 stack->pushBool(b1 == b2);
1488 }
1489 break;
1490 case psOpExch:
1491 stack->roll(2, 1);
1492 break;
1493 case psOpExp:
1494 r2 = stack->popNum();
1495 r1 = stack->popNum();
1496 stack->pushReal(pow(r1, r2));
1497 break;
1498 case psOpFalse:
1499 stack->pushBool(false);
1500 break;
1501 case psOpFloor:
1502 if (!stack->topIsInt()) {
1503 stack->pushReal(floor(stack->popNum()));
1504 }
1505 break;
1506 case psOpGe:
1507 if (stack->topTwoAreInts()) {
1508 i2 = stack->popInt();
1509 i1 = stack->popInt();
1510 stack->pushBool(i1 >= i2);
1511 } else {
1512 r2 = stack->popNum();
1513 r1 = stack->popNum();
1514 stack->pushBool(r1 >= r2);
1515 }
1516 break;
1517 case psOpGt:
1518 if (stack->topTwoAreInts()) {
1519 i2 = stack->popInt();
1520 i1 = stack->popInt();
1521 stack->pushBool(i1 > i2);
1522 } else {
1523 r2 = stack->popNum();
1524 r1 = stack->popNum();
1525 stack->pushBool(r1 > r2);
1526 }
1527 break;
1528 case psOpIdiv:
1529 i2 = stack->popInt();
1530 i1 = stack->popInt();
1531 if (likely((i2 != 0) && !(i2 == -1 && i1 == INT_MIN))) {
1532 stack->pushInt(i1 / i2);
1533 }
1534 break;
1535 case psOpIndex:
1536 stack->index(stack->popInt());
1537 break;
1538 case psOpLe:
1539 if (stack->topTwoAreInts()) {
1540 i2 = stack->popInt();
1541 i1 = stack->popInt();
1542 stack->pushBool(i1 <= i2);
1543 } else {
1544 r2 = stack->popNum();
1545 r1 = stack->popNum();
1546 stack->pushBool(r1 <= r2);
1547 }
1548 break;
1549 case psOpLn:
1550 stack->pushReal(log(stack->popNum()));
1551 break;
1552 case psOpLog:
1553 stack->pushReal(log10(stack->popNum()));
1554 break;
1555 case psOpLt:
1556 if (stack->topTwoAreInts()) {
1557 i2 = stack->popInt();
1558 i1 = stack->popInt();
1559 stack->pushBool(i1 < i2);
1560 } else {
1561 r2 = stack->popNum();
1562 r1 = stack->popNum();
1563 stack->pushBool(r1 < r2);
1564 }
1565 break;
1566 case psOpMod:
1567 i2 = stack->popInt();
1568 i1 = stack->popInt();
1569 if (likely(i2 != 0)) {
1570 stack->pushInt(i1 % i2);
1571 }
1572 break;
1573 case psOpMul:
1574 if (stack->topTwoAreInts()) {
1575 i2 = stack->popInt();
1576 i1 = stack->popInt();
1577 //~ should check for out-of-range, and push a real instead
1578 stack->pushInt(i1 * i2);
1579 } else {
1580 r2 = stack->popNum();
1581 r1 = stack->popNum();
1582 stack->pushReal(r1 * r2);
1583 }
1584 break;
1585 case psOpNe:
1586 if (stack->topTwoAreInts()) {
1587 i2 = stack->popInt();
1588 i1 = stack->popInt();
1589 stack->pushBool(i1 != i2);
1590 } else if (stack->topTwoAreNums()) {
1591 r2 = stack->popNum();
1592 r1 = stack->popNum();
1593 stack->pushBool(r1 != r2);
1594 } else {
1595 b2 = stack->popBool();
1596 b1 = stack->popBool();
1597 stack->pushBool(b1 != b2);
1598 }
1599 break;
1600 case psOpNeg:
1601 if (stack->topIsInt()) {
1602 stack->pushInt(-stack->popInt());
1603 } else {
1604 stack->pushReal(-stack->popNum());
1605 }
1606 break;
1607 case psOpNot:
1608 if (stack->topIsInt()) {
1609 stack->pushInt(~stack->popInt());
1610 } else {
1611 stack->pushBool(!stack->popBool());
1612 }
1613 break;
1614 case psOpOr:
1615 if (stack->topTwoAreInts()) {
1616 i2 = stack->popInt();
1617 i1 = stack->popInt();
1618 stack->pushInt(i1 | i2);
1619 } else {
1620 b2 = stack->popBool();
1621 b1 = stack->popBool();
1622 stack->pushBool(b1 || b2);
1623 }
1624 break;
1625 case psOpPop:
1626 stack->pop();
1627 break;
1628 case psOpRoll:
1629 i2 = stack->popInt();
1630 i1 = stack->popInt();
1631 stack->roll(i1, i2);
1632 break;
1633 case psOpRound:
1634 if (!stack->topIsInt()) {
1635 r1 = stack->popNum();
1636 stack->pushReal((r1 >= 0) ? floor(r1 + 0.5) : ceil(r1 - 0.5));
1637 }
1638 break;
1639 case psOpSin:
1640 stack->pushReal(sin(stack->popNum() * M_PI / 180.0));
1641 break;
1642 case psOpSqrt:
1643 stack->pushReal(sqrt(stack->popNum()));
1644 break;
1645 case psOpSub:
1646 if (stack->topTwoAreInts()) {
1647 i2 = stack->popInt();
1648 i1 = stack->popInt();
1649 stack->pushInt(i1 - i2);
1650 } else {
1651 r2 = stack->popNum();
1652 r1 = stack->popNum();
1653 stack->pushReal(r1 - r2);
1654 }
1655 break;
1656 case psOpTrue:
1657 stack->pushBool(true);
1658 break;
1659 case psOpTruncate:
1660 if (!stack->topIsInt()) {
1661 r1 = stack->popNum();
1662 stack->pushReal((r1 >= 0) ? floor(r1) : ceil(r1));
1663 }
1664 break;
1665 case psOpXor:
1666 if (stack->topTwoAreInts()) {
1667 i2 = stack->popInt();
1668 i1 = stack->popInt();
1669 stack->pushInt(i1 ^ i2);
1670 } else {
1671 b2 = stack->popBool();
1672 b1 = stack->popBool();
1673 stack->pushBool(b1 ^ b2);
1674 }
1675 break;
1676 case psOpIf:
1677 b1 = stack->popBool();
1678 if (b1) {
1679 exec(stack, codePtr + 2);
1680 }
1681 codePtr = code[codePtr + 1].blk;
1682 break;
1683 case psOpIfelse:
1684 b1 = stack->popBool();
1685 if (b1) {
1686 exec(stack, codePtr + 2);
1687 } else {
1688 exec(stack, code[codePtr].blk);
1689 }
1690 codePtr = code[codePtr + 1].blk;
1691 break;
1692 case psOpReturn:
1693 return;
1694 }
1695 break;
1696 default:
1697 error(errSyntaxError, -1, "Internal: bad object in PostScript function code");
1698 break;
1699 }
1700 }
1701 }
1702