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