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