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