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