upgrade to xpdf 3.00.
[swftools.git] / pdf2swf / xpdf / Function.cc
blob46b1912d9d0c854e6974af82ad1284fde8b1fdc3
1 //========================================================================
2 //
3 // Function.cc
4 //
5 // Copyright 2001-2003 Glyph & Cog, LLC
6 //
7 //========================================================================
9 #include <aconf.h>
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
13 #endif
15 #include <stdlib.h>
16 #include <string.h>
17 #include <ctype.h>
18 #include <math.h>
19 #include "gmem.h"
20 #include "Object.h"
21 #include "Dict.h"
22 #include "Stream.h"
23 #include "Error.h"
24 #include "Function.h"
26 //------------------------------------------------------------------------
27 // Function
28 //------------------------------------------------------------------------
30 Function::Function() {
33 Function::~Function() {
36 Function *Function::parse(Object *funcObj) {
37 Function *func;
38 Dict *dict;
39 int funcType;
40 Object obj1;
42 if (funcObj->isStream()) {
43 dict = funcObj->streamGetDict();
44 } else if (funcObj->isDict()) {
45 dict = funcObj->getDict();
46 } else if (funcObj->isName("Identity")) {
47 return new IdentityFunction();
48 } else {
49 error(-1, "Expected function dictionary or stream");
50 return NULL;
53 if (!dict->lookup("FunctionType", &obj1)->isInt()) {
54 error(-1, "Function type is missing or wrong type");
55 obj1.free();
56 return NULL;
58 funcType = obj1.getInt();
59 obj1.free();
61 if (funcType == 0) {
62 func = new SampledFunction(funcObj, dict);
63 } else if (funcType == 2) {
64 func = new ExponentialFunction(funcObj, dict);
65 } else if (funcType == 3) {
66 func = new StitchingFunction(funcObj, dict);
67 } else if (funcType == 4) {
68 func = new PostScriptFunction(funcObj, dict);
69 } else {
70 error(-1, "Unimplemented function type (%d)", funcType);
71 return NULL;
73 if (!func->isOk()) {
74 delete func;
75 return NULL;
78 return func;
81 GBool Function::init(Dict *dict) {
82 Object obj1, obj2;
83 int i;
85 //----- Domain
86 if (!dict->lookup("Domain", &obj1)->isArray()) {
87 error(-1, "Function is missing domain");
88 goto err2;
90 m = obj1.arrayGetLength() / 2;
91 if (m > funcMaxInputs) {
92 error(-1, "Functions with more than %d inputs are unsupported",
93 funcMaxInputs);
94 goto err2;
96 for (i = 0; i < m; ++i) {
97 obj1.arrayGet(2*i, &obj2);
98 if (!obj2.isNum()) {
99 error(-1, "Illegal value in function domain array");
100 goto err1;
102 domain[i][0] = obj2.getNum();
103 obj2.free();
104 obj1.arrayGet(2*i+1, &obj2);
105 if (!obj2.isNum()) {
106 error(-1, "Illegal value in function domain array");
107 goto err1;
109 domain[i][1] = obj2.getNum();
110 obj2.free();
112 obj1.free();
114 //----- Range
115 hasRange = gFalse;
116 n = 0;
117 if (dict->lookup("Range", &obj1)->isArray()) {
118 hasRange = gTrue;
119 n = obj1.arrayGetLength() / 2;
120 if (n > funcMaxOutputs) {
121 error(-1, "Functions with more than %d outputs are unsupported",
122 funcMaxOutputs);
123 goto err2;
125 for (i = 0; i < n; ++i) {
126 obj1.arrayGet(2*i, &obj2);
127 if (!obj2.isNum()) {
128 error(-1, "Illegal value in function range array");
129 goto err1;
131 range[i][0] = obj2.getNum();
132 obj2.free();
133 obj1.arrayGet(2*i+1, &obj2);
134 if (!obj2.isNum()) {
135 error(-1, "Illegal value in function range array");
136 goto err1;
138 range[i][1] = obj2.getNum();
139 obj2.free();
142 obj1.free();
144 return gTrue;
146 err1:
147 obj2.free();
148 err2:
149 obj1.free();
150 return gFalse;
153 //------------------------------------------------------------------------
154 // IdentityFunction
155 //------------------------------------------------------------------------
157 IdentityFunction::IdentityFunction() {
158 int i;
160 // fill these in with arbitrary values just in case they get used
161 // somewhere
162 m = funcMaxInputs;
163 n = funcMaxOutputs;
164 for (i = 0; i < funcMaxInputs; ++i) {
165 domain[i][0] = 0;
166 domain[i][1] = 1;
168 hasRange = gFalse;
171 IdentityFunction::~IdentityFunction() {
174 void IdentityFunction::transform(double *in, double *out) {
175 int i;
177 for (i = 0; i < funcMaxOutputs; ++i) {
178 out[i] = in[i];
182 //------------------------------------------------------------------------
183 // SampledFunction
184 //------------------------------------------------------------------------
186 SampledFunction::SampledFunction(Object *funcObj, Dict *dict) {
187 Stream *str;
188 int nSamples, sampleBits;
189 double sampleMul;
190 Object obj1, obj2;
191 Guint buf, bitMask;
192 int bits;
193 int s;
194 int i;
196 samples = NULL;
197 ok = gFalse;
199 //----- initialize the generic stuff
200 if (!init(dict)) {
201 goto err1;
203 if (!hasRange) {
204 error(-1, "Type 0 function is missing range");
205 goto err1;
208 //----- get the stream
209 if (!funcObj->isStream()) {
210 error(-1, "Type 0 function isn't a stream");
211 goto err1;
213 str = funcObj->getStream();
215 //----- Size
216 if (!dict->lookup("Size", &obj1)->isArray() ||
217 obj1.arrayGetLength() != m) {
218 error(-1, "Function has missing or invalid size array");
219 goto err2;
221 for (i = 0; i < m; ++i) {
222 obj1.arrayGet(i, &obj2);
223 if (!obj2.isInt()) {
224 error(-1, "Illegal value in function size array");
225 goto err3;
227 sampleSize[i] = obj2.getInt();
228 obj2.free();
230 obj1.free();
232 //----- BitsPerSample
233 if (!dict->lookup("BitsPerSample", &obj1)->isInt()) {
234 error(-1, "Function has missing or invalid BitsPerSample");
235 goto err2;
237 sampleBits = obj1.getInt();
238 sampleMul = 1.0 / (double)((1 << sampleBits) - 1);
239 obj1.free();
241 //----- Encode
242 if (dict->lookup("Encode", &obj1)->isArray() &&
243 obj1.arrayGetLength() == 2*m) {
244 for (i = 0; i < m; ++i) {
245 obj1.arrayGet(2*i, &obj2);
246 if (!obj2.isNum()) {
247 error(-1, "Illegal value in function encode array");
248 goto err3;
250 encode[i][0] = obj2.getNum();
251 obj2.free();
252 obj1.arrayGet(2*i+1, &obj2);
253 if (!obj2.isNum()) {
254 error(-1, "Illegal value in function encode array");
255 goto err3;
257 encode[i][1] = obj2.getNum();
258 obj2.free();
260 } else {
261 for (i = 0; i < m; ++i) {
262 encode[i][0] = 0;
263 encode[i][1] = sampleSize[i] - 1;
266 obj1.free();
268 //----- Decode
269 if (dict->lookup("Decode", &obj1)->isArray() &&
270 obj1.arrayGetLength() == 2*n) {
271 for (i = 0; i < n; ++i) {
272 obj1.arrayGet(2*i, &obj2);
273 if (!obj2.isNum()) {
274 error(-1, "Illegal value in function decode array");
275 goto err3;
277 decode[i][0] = obj2.getNum();
278 obj2.free();
279 obj1.arrayGet(2*i+1, &obj2);
280 if (!obj2.isNum()) {
281 error(-1, "Illegal value in function decode array");
282 goto err3;
284 decode[i][1] = obj2.getNum();
285 obj2.free();
287 } else {
288 for (i = 0; i < n; ++i) {
289 decode[i][0] = range[i][0];
290 decode[i][1] = range[i][1];
293 obj1.free();
295 //----- samples
296 nSamples = n;
297 for (i = 0; i < m; ++i)
298 nSamples *= sampleSize[i];
299 samples = (double *)gmalloc(nSamples * sizeof(double));
300 buf = 0;
301 bits = 0;
302 bitMask = (1 << sampleBits) - 1;
303 str->reset();
304 for (i = 0; i < nSamples; ++i) {
305 if (sampleBits == 8) {
306 s = str->getChar();
307 } else if (sampleBits == 16) {
308 s = str->getChar();
309 s = (s << 8) + str->getChar();
310 } else if (sampleBits == 32) {
311 s = str->getChar();
312 s = (s << 8) + str->getChar();
313 s = (s << 8) + str->getChar();
314 s = (s << 8) + str->getChar();
315 } else {
316 while (bits < sampleBits) {
317 buf = (buf << 8) | (str->getChar() & 0xff);
318 bits += 8;
320 s = (buf >> (bits - sampleBits)) & bitMask;
321 bits -= sampleBits;
323 samples[i] = (double)s * sampleMul;
325 str->close();
327 ok = gTrue;
328 return;
330 err3:
331 obj2.free();
332 err2:
333 obj1.free();
334 err1:
335 return;
338 SampledFunction::~SampledFunction() {
339 if (samples) {
340 gfree(samples);
344 SampledFunction::SampledFunction(SampledFunction *func) {
345 int nSamples, i;
347 memcpy(this, func, sizeof(SampledFunction));
349 nSamples = n;
350 for (i = 0; i < m; ++i) {
351 nSamples *= sampleSize[i];
353 samples = (double *)gmalloc(nSamples * sizeof(double));
354 memcpy(samples, func->samples, nSamples * sizeof(double));
357 void SampledFunction::transform(double *in, double *out) {
358 double x;
359 int e[2][funcMaxInputs];
360 double efrac[funcMaxInputs];
361 double s0[1 << funcMaxInputs], s1[1 << funcMaxInputs];
362 int i, j, k, idx;
364 // map input values into sample array
365 for (i = 0; i < m; ++i) {
366 x = ((in[i] - domain[i][0]) / (domain[i][1] - domain[i][0])) *
367 (encode[i][1] - encode[i][0]) + encode[i][0];
368 if (x < 0) {
369 x = 0;
370 } else if (x > sampleSize[i] - 1) {
371 x = sampleSize[i] - 1;
373 e[0][i] = (int)floor(x);
374 e[1][i] = (int)ceil(x);
375 efrac[i] = x - e[0][i];
378 // for each output, do m-linear interpolation
379 for (i = 0; i < n; ++i) {
381 // pull 2^m values out of the sample array
382 for (j = 0; j < (1<<m); ++j) {
383 idx = 0;
384 for (k = m - 1; k >= 0; --k) {
385 idx = idx * sampleSize[k] + e[(j >> k) & 1][k];
387 idx = idx * n + i;
388 s0[j] = samples[idx];
391 // do m sets of interpolations
392 for (j = 0; j < m; ++j) {
393 for (k = 0; k < (1 << (m - j)); k += 2) {
394 s1[k >> 1] = (1 - efrac[j]) * s0[k] + efrac[j] * s0[k+1];
396 memcpy(s0, s1, (1 << (m - j - 1)) * sizeof(double));
399 // map output value to range
400 out[i] = s0[0] * (decode[i][1] - decode[i][0]) + decode[i][0];
401 if (out[i] < range[i][0]) {
402 out[i] = range[i][0];
403 } else if (out[i] > range[i][1]) {
404 out[i] = range[i][1];
409 //------------------------------------------------------------------------
410 // ExponentialFunction
411 //------------------------------------------------------------------------
413 ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) {
414 Object obj1, obj2;
415 int i;
417 ok = gFalse;
419 //----- initialize the generic stuff
420 if (!init(dict)) {
421 goto err1;
423 if (m != 1) {
424 error(-1, "Exponential function with more than one input");
425 goto err1;
428 //----- C0
429 if (dict->lookup("C0", &obj1)->isArray()) {
430 if (hasRange && obj1.arrayGetLength() != n) {
431 error(-1, "Function's C0 array is wrong length");
432 goto err2;
434 n = obj1.arrayGetLength();
435 for (i = 0; i < n; ++i) {
436 obj1.arrayGet(i, &obj2);
437 if (!obj2.isNum()) {
438 error(-1, "Illegal value in function C0 array");
439 goto err3;
441 c0[i] = obj2.getNum();
442 obj2.free();
444 } else {
445 if (hasRange && n != 1) {
446 error(-1, "Function's C0 array is wrong length");
447 goto err2;
449 n = 1;
450 c0[0] = 0;
452 obj1.free();
454 //----- C1
455 if (dict->lookup("C1", &obj1)->isArray()) {
456 if (obj1.arrayGetLength() != n) {
457 error(-1, "Function's C1 array is wrong length");
458 goto err2;
460 for (i = 0; i < n; ++i) {
461 obj1.arrayGet(i, &obj2);
462 if (!obj2.isNum()) {
463 error(-1, "Illegal value in function C1 array");
464 goto err3;
466 c1[i] = obj2.getNum();
467 obj2.free();
469 } else {
470 if (n != 1) {
471 error(-1, "Function's C1 array is wrong length");
472 goto err2;
474 c1[0] = 1;
476 obj1.free();
478 //----- N (exponent)
479 if (!dict->lookup("N", &obj1)->isNum()) {
480 error(-1, "Function has missing or invalid N");
481 goto err2;
483 e = obj1.getNum();
484 obj1.free();
486 ok = gTrue;
487 return;
489 err3:
490 obj2.free();
491 err2:
492 obj1.free();
493 err1:
494 return;
497 ExponentialFunction::~ExponentialFunction() {
500 ExponentialFunction::ExponentialFunction(ExponentialFunction *func) {
501 memcpy(this, func, sizeof(ExponentialFunction));
504 void ExponentialFunction::transform(double *in, double *out) {
505 double x;
506 int i;
508 if (in[0] < domain[0][0]) {
509 x = domain[0][0];
510 } else if (in[0] > domain[0][1]) {
511 x = domain[0][1];
512 } else {
513 x = in[0];
515 for (i = 0; i < n; ++i) {
516 out[i] = c0[i] + pow(x, e) * (c1[i] - c0[i]);
517 if (hasRange) {
518 if (out[i] < range[i][0]) {
519 out[i] = range[i][0];
520 } else if (out[i] > range[i][1]) {
521 out[i] = range[i][1];
525 return;
528 //------------------------------------------------------------------------
529 // StitchingFunction
530 //------------------------------------------------------------------------
532 StitchingFunction::StitchingFunction(Object *funcObj, Dict *dict) {
533 Object obj1, obj2;
534 int i;
536 ok = gFalse;
537 funcs = NULL;
538 bounds = NULL;
539 encode = NULL;
541 //----- initialize the generic stuff
542 if (!init(dict)) {
543 goto err1;
545 if (m != 1) {
546 error(-1, "Stitching function with more than one input");
547 goto err1;
550 //----- Functions
551 if (!dict->lookup("Functions", &obj1)->isArray()) {
552 error(-1, "Missing 'Functions' entry in stitching function");
553 goto err1;
555 k = obj1.arrayGetLength();
556 funcs = (Function **)gmalloc(k * sizeof(Function *));
557 bounds = (double *)gmalloc((k + 1) * sizeof(double));
558 encode = (double *)gmalloc(2 * k * sizeof(double));
559 for (i = 0; i < k; ++i) {
560 funcs[i] = NULL;
562 for (i = 0; i < k; ++i) {
563 if (!(funcs[i] = Function::parse(obj1.arrayGet(i, &obj2)))) {
564 goto err2;
566 if (i > 0 && (funcs[i]->getInputSize() != 1 ||
567 funcs[i]->getOutputSize() != funcs[0]->getOutputSize())) {
568 error(-1, "Incompatible subfunctions in stitching function");
569 goto err2;
571 obj2.free();
573 obj1.free();
575 //----- Bounds
576 if (!dict->lookup("Bounds", &obj1)->isArray() ||
577 obj1.arrayGetLength() != k - 1) {
578 error(-1, "Missing or invalid 'Bounds' entry in stitching function");
579 goto err1;
581 bounds[0] = domain[0][0];
582 for (i = 1; i < k; ++i) {
583 if (!obj1.arrayGet(i - 1, &obj2)->isNum()) {
584 error(-1, "Invalid type in 'Bounds' array in stitching function");
585 goto err2;
587 bounds[i] = obj2.getNum();
588 obj2.free();
590 bounds[k] = domain[0][1];
591 obj1.free();
593 //----- Encode
594 if (!dict->lookup("Encode", &obj1)->isArray() ||
595 obj1.arrayGetLength() != 2 * k) {
596 error(-1, "Missing or invalid 'Encode' entry in stitching function");
597 goto err1;
599 for (i = 0; i < 2 * k; ++i) {
600 if (!obj1.arrayGet(i, &obj2)->isNum()) {
601 error(-1, "Invalid type in 'Encode' array in stitching function");
602 goto err2;
604 encode[i] = obj2.getNum();
605 obj2.free();
607 obj1.free();
609 ok = gTrue;
610 return;
612 err2:
613 obj2.free();
614 err1:
615 obj1.free();
618 StitchingFunction::StitchingFunction(StitchingFunction *func) {
619 int i;
621 k = func->k;
622 funcs = (Function **)gmalloc(k * sizeof(Function *));
623 for (i = 0; i < k; ++i) {
624 funcs[i] = func->funcs[i]->copy();
626 bounds = (double *)gmalloc((k + 1) * sizeof(double));
627 memcpy(bounds, func->bounds, (k + 1) * sizeof(double));
628 encode = (double *)gmalloc(2 * k * sizeof(double));
629 memcpy(encode, func->encode, 2 * k * sizeof(double));
630 ok = gTrue;
633 StitchingFunction::~StitchingFunction() {
634 int i;
636 if (funcs) {
637 for (i = 0; i < k; ++i) {
638 if (funcs[i]) {
639 delete funcs[i];
643 gfree(funcs);
644 gfree(bounds);
645 gfree(encode);
648 void StitchingFunction::transform(double *in, double *out) {
649 double x;
650 int i;
652 if (in[0] < domain[0][0]) {
653 x = domain[0][0];
654 } else if (in[0] > domain[0][1]) {
655 x = domain[0][1];
656 } else {
657 x = in[0];
659 for (i = 0; i < k - 1; ++i) {
660 if (x < bounds[i+1]) {
661 break;
664 x = encode[2*i] + ((x - bounds[i]) / (bounds[i+1] - bounds[i])) *
665 (encode[2*i+1] - encode[2*i]);
666 funcs[i]->transform(&x, out);
669 //------------------------------------------------------------------------
670 // PostScriptFunction
671 //------------------------------------------------------------------------
673 enum PSOp {
674 psOpAbs,
675 psOpAdd,
676 psOpAnd,
677 psOpAtan,
678 psOpBitshift,
679 psOpCeiling,
680 psOpCopy,
681 psOpCos,
682 psOpCvi,
683 psOpCvr,
684 psOpDiv,
685 psOpDup,
686 psOpEq,
687 psOpExch,
688 psOpExp,
689 psOpFalse,
690 psOpFloor,
691 psOpGe,
692 psOpGt,
693 psOpIdiv,
694 psOpIndex,
695 psOpLe,
696 psOpLn,
697 psOpLog,
698 psOpLt,
699 psOpMod,
700 psOpMul,
701 psOpNe,
702 psOpNeg,
703 psOpNot,
704 psOpOr,
705 psOpPop,
706 psOpRoll,
707 psOpRound,
708 psOpSin,
709 psOpSqrt,
710 psOpSub,
711 psOpTrue,
712 psOpTruncate,
713 psOpXor,
714 psOpIf,
715 psOpIfelse,
716 psOpReturn
719 // Note: 'if' and 'ifelse' are parsed separately.
720 // The rest are listed here in alphabetical order.
721 // The index in this table is equivalent to the entry in PSOp.
722 char *psOpNames[] = {
723 "abs",
724 "add",
725 "and",
726 "atan",
727 "bitshift",
728 "ceiling",
729 "copy",
730 "cos",
731 "cvi",
732 "cvr",
733 "div",
734 "dup",
735 "eq",
736 "exch",
737 "exp",
738 "false",
739 "floor",
740 "ge",
741 "gt",
742 "idiv",
743 "index",
744 "le",
745 "ln",
746 "log",
747 "lt",
748 "mod",
749 "mul",
750 "ne",
751 "neg",
752 "not",
753 "or",
754 "pop",
755 "roll",
756 "round",
757 "sin",
758 "sqrt",
759 "sub",
760 "true",
761 "truncate",
762 "xor"
765 #define nPSOps (sizeof(psOpNames) / sizeof(char *))
767 enum PSObjectType {
768 psBool,
769 psInt,
770 psReal,
771 psOperator,
772 psBlock
775 // In the code array, 'if'/'ifelse' operators take up three slots
776 // plus space for the code in the subclause(s).
778 // +---------------------------------+
779 // | psOperator: psOpIf / psOpIfelse |
780 // +---------------------------------+
781 // | psBlock: ptr=<A> |
782 // +---------------------------------+
783 // | psBlock: ptr=<B> |
784 // +---------------------------------+
785 // | if clause |
786 // | ... |
787 // | psOperator: psOpReturn |
788 // +---------------------------------+
789 // <A> | else clause |
790 // | ... |
791 // | psOperator: psOpReturn |
792 // +---------------------------------+
793 // <B> | ... |
795 // For 'if', pointer <A> is present in the code stream but unused.
797 struct PSObject {
798 PSObjectType type;
799 union {
800 GBool booln; // boolean (stack only)
801 int intg; // integer (stack and code)
802 double real; // real (stack and code)
803 PSOp op; // operator (code only)
804 int blk; // if/ifelse block pointer (code only)
808 #define psStackSize 100
810 class PSStack {
811 public:
813 PSStack() { sp = psStackSize; }
814 void pushBool(GBool booln);
815 void pushInt(int intg);
816 void pushReal(double real);
817 GBool popBool();
818 int popInt();
819 double popNum();
820 GBool empty() { return sp == psStackSize; }
821 GBool topIsInt() { return sp < psStackSize && stack[sp].type == psInt; }
822 GBool topTwoAreInts()
823 { return sp < psStackSize - 1 &&
824 stack[sp].type == psInt &&
825 stack[sp+1].type == psInt; }
826 GBool topIsReal() { return sp < psStackSize && stack[sp].type == psReal; }
827 GBool topTwoAreNums()
828 { return sp < psStackSize - 1 &&
829 (stack[sp].type == psInt || stack[sp].type == psReal) &&
830 (stack[sp+1].type == psInt || stack[sp+1].type == psReal); }
831 void copy(int n);
832 void roll(int n, int j);
833 void index(int i);
834 void pop();
836 private:
838 GBool checkOverflow(int n = 1);
839 GBool checkUnderflow();
840 GBool checkType(PSObjectType t1, PSObjectType t2);
842 PSObject stack[psStackSize];
843 int sp;
846 GBool PSStack::checkOverflow(int n) {
847 if (sp - n < 0) {
848 error(-1, "Stack overflow in PostScript function");
849 return gFalse;
851 return gTrue;
854 GBool PSStack::checkUnderflow() {
855 if (sp == psStackSize) {
856 error(-1, "Stack underflow in PostScript function");
857 return gFalse;
859 return gTrue;
862 GBool PSStack::checkType(PSObjectType t1, PSObjectType t2) {
863 if (stack[sp].type != t1 && stack[sp].type != t2) {
864 error(-1, "Type mismatch in PostScript function");
865 return gFalse;
867 return gTrue;
870 void PSStack::pushBool(GBool booln) {
871 if (checkOverflow()) {
872 stack[--sp].type = psBool;
873 stack[sp].booln = booln;
877 void PSStack::pushInt(int intg) {
878 if (checkOverflow()) {
879 stack[--sp].type = psInt;
880 stack[sp].intg = intg;
884 void PSStack::pushReal(double real) {
885 if (checkOverflow()) {
886 stack[--sp].type = psReal;
887 stack[sp].real = real;
891 GBool PSStack::popBool() {
892 if (checkUnderflow() && checkType(psBool, psBool)) {
893 return stack[sp++].booln;
895 return gFalse;
898 int PSStack::popInt() {
899 if (checkUnderflow() && checkType(psInt, psInt)) {
900 return stack[sp++].intg;
902 return 0;
905 double PSStack::popNum() {
906 double ret;
908 if (checkUnderflow() && checkType(psInt, psReal)) {
909 ret = (stack[sp].type == psInt) ? (double)stack[sp].intg : stack[sp].real;
910 ++sp;
911 return ret;
913 return 0;
916 void PSStack::copy(int n) {
917 int i;
919 if (!checkOverflow(n)) {
920 return;
922 for (i = sp + n - 1; i <= sp; ++i) {
923 stack[i - n] = stack[i];
925 sp -= n;
928 void PSStack::roll(int n, int j) {
929 PSObject obj;
930 int i, k;
932 if (j >= 0) {
933 j %= n;
934 } else {
935 j = -j % n;
936 if (j != 0) {
937 j = n - j;
940 if (n <= 0 || j == 0) {
941 return;
943 for (i = 0; i < j; ++i) {
944 obj = stack[sp];
945 for (k = sp; k < sp + n - 1; ++k) {
946 stack[k] = stack[k+1];
948 stack[sp + n - 1] = obj;
952 void PSStack::index(int i) {
953 if (!checkOverflow()) {
954 return;
956 --sp;
957 stack[sp] = stack[sp + 1 + i];
960 void PSStack::pop() {
961 if (!checkUnderflow()) {
962 return;
964 ++sp;
967 PostScriptFunction::PostScriptFunction(Object *funcObj, Dict *dict) {
968 Stream *str;
969 int codePtr;
970 GString *tok;
972 code = NULL;
973 codeSize = 0;
974 ok = gFalse;
976 //----- initialize the generic stuff
977 if (!init(dict)) {
978 goto err1;
980 if (!hasRange) {
981 error(-1, "Type 4 function is missing range");
982 goto err1;
985 //----- get the stream
986 if (!funcObj->isStream()) {
987 error(-1, "Type 4 function isn't a stream");
988 goto err1;
990 str = funcObj->getStream();
992 //----- parse the function
993 str->reset();
994 if (!(tok = getToken(str)) || tok->cmp("{")) {
995 error(-1, "Expected '{' at start of PostScript function");
996 if (tok) {
997 delete tok;
999 goto err1;
1001 delete tok;
1002 codePtr = 0;
1003 if (!parseCode(str, &codePtr)) {
1004 goto err2;
1006 str->close();
1008 ok = gTrue;
1010 err2:
1011 str->close();
1012 err1:
1013 return;
1016 PostScriptFunction::PostScriptFunction(PostScriptFunction *func) {
1017 memcpy(this, func, sizeof(PostScriptFunction));
1018 code = (PSObject *)gmalloc(codeSize * sizeof(PSObject));
1019 memcpy(code, func->code, codeSize * sizeof(PSObject));
1022 PostScriptFunction::~PostScriptFunction() {
1023 gfree(code);
1026 void PostScriptFunction::transform(double *in, double *out) {
1027 PSStack *stack;
1028 int i;
1030 stack = new PSStack();
1031 for (i = 0; i < m; ++i) {
1032 //~ may need to check for integers here
1033 stack->pushReal(in[i]);
1035 exec(stack, 0);
1036 for (i = n - 1; i >= 0; --i) {
1037 out[i] = stack->popNum();
1038 if (out[i] < range[i][0]) {
1039 out[i] = range[i][0];
1040 } else if (out[i] > range[i][1]) {
1041 out[i] = range[i][1];
1044 // if (!stack->empty()) {
1045 // error(-1, "Extra values on stack at end of PostScript function");
1046 // }
1047 delete stack;
1050 GBool PostScriptFunction::parseCode(Stream *str, int *codePtr) {
1051 GString *tok;
1052 char *p;
1053 GBool isReal;
1054 int opPtr, elsePtr;
1055 int a, b, mid, cmp;
1057 while (1) {
1058 if (!(tok = getToken(str))) {
1059 error(-1, "Unexpected end of PostScript function stream");
1060 return gFalse;
1062 p = tok->getCString();
1063 if (isdigit(*p) || *p == '.' || *p == '-') {
1064 isReal = gFalse;
1065 for (++p; *p; ++p) {
1066 if (*p == '.') {
1067 isReal = gTrue;
1068 break;
1071 resizeCode(*codePtr);
1072 if (isReal) {
1073 code[*codePtr].type = psReal;
1074 code[*codePtr].real = atof(tok->getCString());
1075 } else {
1076 code[*codePtr].type = psInt;
1077 code[*codePtr].intg = atoi(tok->getCString());
1079 ++*codePtr;
1080 delete tok;
1081 } else if (!tok->cmp("{")) {
1082 delete tok;
1083 opPtr = *codePtr;
1084 *codePtr += 3;
1085 resizeCode(opPtr + 2);
1086 if (!parseCode(str, codePtr)) {
1087 return gFalse;
1089 if (!(tok = getToken(str))) {
1090 error(-1, "Unexpected end of PostScript function stream");
1091 return gFalse;
1093 if (!tok->cmp("{")) {
1094 elsePtr = *codePtr;
1095 if (!parseCode(str, codePtr)) {
1096 return gFalse;
1098 delete tok;
1099 if (!(tok = getToken(str))) {
1100 error(-1, "Unexpected end of PostScript function stream");
1101 return gFalse;
1103 } else {
1104 elsePtr = -1;
1106 if (!tok->cmp("if")) {
1107 if (elsePtr >= 0) {
1108 error(-1, "Got 'if' operator with two blocks in PostScript function");
1109 return gFalse;
1111 code[opPtr].type = psOperator;
1112 code[opPtr].op = psOpIf;
1113 code[opPtr+2].type = psBlock;
1114 code[opPtr+2].blk = *codePtr;
1115 } else if (!tok->cmp("ifelse")) {
1116 if (elsePtr < 0) {
1117 error(-1, "Got 'ifelse' operator with one blocks in PostScript function");
1118 return gFalse;
1120 code[opPtr].type = psOperator;
1121 code[opPtr].op = psOpIfelse;
1122 code[opPtr+1].type = psBlock;
1123 code[opPtr+1].blk = elsePtr;
1124 code[opPtr+2].type = psBlock;
1125 code[opPtr+2].blk = *codePtr;
1126 } else {
1127 error(-1, "Expected if/ifelse operator in PostScript function");
1128 delete tok;
1129 return gFalse;
1131 delete tok;
1132 } else if (!tok->cmp("}")) {
1133 delete tok;
1134 resizeCode(*codePtr);
1135 code[*codePtr].type = psOperator;
1136 code[*codePtr].op = psOpReturn;
1137 ++*codePtr;
1138 break;
1139 } else {
1140 a = -1;
1141 b = nPSOps;
1142 // invariant: psOpNames[a] < tok < psOpNames[b]
1143 while (b - a > 1) {
1144 mid = (a + b) / 2;
1145 cmp = tok->cmp(psOpNames[mid]);
1146 if (cmp > 0) {
1147 a = mid;
1148 } else if (cmp < 0) {
1149 b = mid;
1150 } else {
1151 a = b = mid;
1154 if (cmp != 0) {
1155 error(-1, "Unknown operator '%s' in PostScript function",
1156 tok->getCString());
1157 delete tok;
1158 return gFalse;
1160 delete tok;
1161 resizeCode(*codePtr);
1162 code[*codePtr].type = psOperator;
1163 code[*codePtr].op = (PSOp)a;
1164 ++*codePtr;
1167 return gTrue;
1170 GString *PostScriptFunction::getToken(Stream *str) {
1171 GString *s;
1172 int c;
1174 s = new GString();
1175 do {
1176 c = str->getChar();
1177 } while (c != EOF && isspace(c));
1178 if (c == '{' || c == '}') {
1179 s->append((char)c);
1180 } else if (isdigit(c) || c == '.' || c == '-') {
1181 while (1) {
1182 s->append((char)c);
1183 c = str->lookChar();
1184 if (c == EOF || !(isdigit(c) || c == '.' || c == '-')) {
1185 break;
1187 str->getChar();
1189 } else {
1190 while (1) {
1191 s->append((char)c);
1192 c = str->lookChar();
1193 if (c == EOF || !isalnum(c)) {
1194 break;
1196 str->getChar();
1199 return s;
1202 void PostScriptFunction::resizeCode(int newSize) {
1203 if (newSize >= codeSize) {
1204 codeSize += 64;
1205 code = (PSObject *)grealloc(code, codeSize * sizeof(PSObject));
1209 void PostScriptFunction::exec(PSStack *stack, int codePtr) {
1210 int i1, i2;
1211 double r1, r2;
1212 GBool b1, b2;
1214 while (1) {
1215 switch (code[codePtr].type) {
1216 case psInt:
1217 stack->pushInt(code[codePtr++].intg);
1218 break;
1219 case psReal:
1220 stack->pushReal(code[codePtr++].real);
1221 break;
1222 case psOperator:
1223 switch (code[codePtr++].op) {
1224 case psOpAbs:
1225 if (stack->topIsInt()) {
1226 stack->pushInt(abs(stack->popInt()));
1227 } else {
1228 stack->pushReal(fabs(stack->popNum()));
1230 break;
1231 case psOpAdd:
1232 if (stack->topTwoAreInts()) {
1233 i2 = stack->popInt();
1234 i1 = stack->popInt();
1235 stack->pushInt(i1 + i2);
1236 } else {
1237 r2 = stack->popNum();
1238 r1 = stack->popNum();
1239 stack->pushReal(r1 + r2);
1241 break;
1242 case psOpAnd:
1243 if (stack->topTwoAreInts()) {
1244 i2 = stack->popInt();
1245 i1 = stack->popInt();
1246 stack->pushInt(i1 & i2);
1247 } else {
1248 b2 = stack->popBool();
1249 b1 = stack->popBool();
1250 stack->pushBool(b1 && b2);
1252 break;
1253 case psOpAtan:
1254 r2 = stack->popNum();
1255 r1 = stack->popNum();
1256 stack->pushReal(atan2(r1, r2));
1257 break;
1258 case psOpBitshift:
1259 i2 = stack->popInt();
1260 i1 = stack->popInt();
1261 if (i2 > 0) {
1262 stack->pushInt(i1 << i2);
1263 } else if (i2 < 0) {
1264 stack->pushInt((int)((Guint)i1 >> i2));
1265 } else {
1266 stack->pushInt(i1);
1268 break;
1269 case psOpCeiling:
1270 if (!stack->topIsInt()) {
1271 stack->pushReal(ceil(stack->popNum()));
1273 break;
1274 case psOpCopy:
1275 stack->copy(stack->popInt());
1276 break;
1277 case psOpCos:
1278 stack->pushReal(cos(stack->popNum()));
1279 break;
1280 case psOpCvi:
1281 if (!stack->topIsInt()) {
1282 stack->pushInt((int)stack->popNum());
1284 break;
1285 case psOpCvr:
1286 if (!stack->topIsReal()) {
1287 stack->pushReal(stack->popNum());
1289 break;
1290 case psOpDiv:
1291 r2 = stack->popNum();
1292 r1 = stack->popNum();
1293 stack->pushReal(r1 / r2);
1294 break;
1295 case psOpDup:
1296 stack->copy(1);
1297 break;
1298 case psOpEq:
1299 if (stack->topTwoAreInts()) {
1300 i2 = stack->popInt();
1301 i1 = stack->popInt();
1302 stack->pushBool(i1 == i2);
1303 } else if (stack->topTwoAreNums()) {
1304 r2 = stack->popNum();
1305 r1 = stack->popNum();
1306 stack->pushBool(r1 == r2);
1307 } else {
1308 b2 = stack->popBool();
1309 b1 = stack->popBool();
1310 stack->pushBool(b1 == b2);
1312 break;
1313 case psOpExch:
1314 stack->roll(2, 1);
1315 break;
1316 case psOpExp:
1317 r2 = stack->popNum();
1318 r1 = stack->popNum();
1319 stack->pushReal(pow(r1, r2));
1320 break;
1321 case psOpFalse:
1322 stack->pushBool(gFalse);
1323 break;
1324 case psOpFloor:
1325 if (!stack->topIsInt()) {
1326 stack->pushReal(floor(stack->popNum()));
1328 break;
1329 case psOpGe:
1330 if (stack->topTwoAreInts()) {
1331 i2 = stack->popInt();
1332 i1 = stack->popInt();
1333 stack->pushBool(i1 >= i2);
1334 } else {
1335 r2 = stack->popNum();
1336 r1 = stack->popNum();
1337 stack->pushBool(r1 >= r2);
1339 break;
1340 case psOpGt:
1341 if (stack->topTwoAreInts()) {
1342 i2 = stack->popInt();
1343 i1 = stack->popInt();
1344 stack->pushBool(i1 > i2);
1345 } else {
1346 r2 = stack->popNum();
1347 r1 = stack->popNum();
1348 stack->pushBool(r1 > r2);
1350 break;
1351 case psOpIdiv:
1352 i2 = stack->popInt();
1353 i1 = stack->popInt();
1354 stack->pushInt(i1 / i2);
1355 break;
1356 case psOpIndex:
1357 stack->index(stack->popInt());
1358 break;
1359 case psOpLe:
1360 if (stack->topTwoAreInts()) {
1361 i2 = stack->popInt();
1362 i1 = stack->popInt();
1363 stack->pushBool(i1 <= i2);
1364 } else {
1365 r2 = stack->popNum();
1366 r1 = stack->popNum();
1367 stack->pushBool(r1 <= r2);
1369 break;
1370 case psOpLn:
1371 stack->pushReal(log(stack->popNum()));
1372 break;
1373 case psOpLog:
1374 stack->pushReal(log10(stack->popNum()));
1375 break;
1376 case psOpLt:
1377 if (stack->topTwoAreInts()) {
1378 i2 = stack->popInt();
1379 i1 = stack->popInt();
1380 stack->pushBool(i1 < i2);
1381 } else {
1382 r2 = stack->popNum();
1383 r1 = stack->popNum();
1384 stack->pushBool(r1 < r2);
1386 break;
1387 case psOpMod:
1388 i2 = stack->popInt();
1389 i1 = stack->popInt();
1390 stack->pushInt(i1 % i2);
1391 break;
1392 case psOpMul:
1393 if (stack->topTwoAreInts()) {
1394 i2 = stack->popInt();
1395 i1 = stack->popInt();
1396 //~ should check for out-of-range, and push a real instead
1397 stack->pushInt(i1 * i2);
1398 } else {
1399 r2 = stack->popNum();
1400 r1 = stack->popNum();
1401 stack->pushReal(r1 * r2);
1403 break;
1404 case psOpNe:
1405 if (stack->topTwoAreInts()) {
1406 i2 = stack->popInt();
1407 i1 = stack->popInt();
1408 stack->pushBool(i1 != i2);
1409 } else if (stack->topTwoAreNums()) {
1410 r2 = stack->popNum();
1411 r1 = stack->popNum();
1412 stack->pushBool(r1 != r2);
1413 } else {
1414 b2 = stack->popBool();
1415 b1 = stack->popBool();
1416 stack->pushBool(b1 != b2);
1418 break;
1419 case psOpNeg:
1420 if (stack->topIsInt()) {
1421 stack->pushInt(-stack->popInt());
1422 } else {
1423 stack->pushReal(-stack->popNum());
1425 break;
1426 case psOpNot:
1427 if (stack->topIsInt()) {
1428 stack->pushInt(~stack->popInt());
1429 } else {
1430 stack->pushBool(!stack->popBool());
1432 break;
1433 case psOpOr:
1434 if (stack->topTwoAreInts()) {
1435 i2 = stack->popInt();
1436 i1 = stack->popInt();
1437 stack->pushInt(i1 | i2);
1438 } else {
1439 b2 = stack->popBool();
1440 b1 = stack->popBool();
1441 stack->pushBool(b1 || b2);
1443 break;
1444 case psOpPop:
1445 stack->pop();
1446 break;
1447 case psOpRoll:
1448 i2 = stack->popInt();
1449 i1 = stack->popInt();
1450 stack->roll(i1, i2);
1451 break;
1452 case psOpRound:
1453 if (!stack->topIsInt()) {
1454 r1 = stack->popNum();
1455 stack->pushReal((r1 >= 0) ? floor(r1 + 0.5) : ceil(r1 - 0.5));
1457 break;
1458 case psOpSin:
1459 stack->pushReal(sin(stack->popNum()));
1460 break;
1461 case psOpSqrt:
1462 stack->pushReal(sqrt(stack->popNum()));
1463 break;
1464 case psOpSub:
1465 if (stack->topTwoAreInts()) {
1466 i2 = stack->popInt();
1467 i1 = stack->popInt();
1468 stack->pushInt(i1 - i2);
1469 } else {
1470 r2 = stack->popNum();
1471 r1 = stack->popNum();
1472 stack->pushReal(r1 - r2);
1474 break;
1475 case psOpTrue:
1476 stack->pushBool(gTrue);
1477 break;
1478 case psOpTruncate:
1479 if (!stack->topIsInt()) {
1480 r1 = stack->popNum();
1481 stack->pushReal((r1 >= 0) ? floor(r1) : ceil(r1));
1483 break;
1484 case psOpXor:
1485 if (stack->topTwoAreInts()) {
1486 i2 = stack->popInt();
1487 i1 = stack->popInt();
1488 stack->pushInt(i1 ^ i2);
1489 } else {
1490 b2 = stack->popBool();
1491 b1 = stack->popBool();
1492 stack->pushBool(b1 ^ b2);
1494 break;
1495 case psOpIf:
1496 b1 = stack->popBool();
1497 if (b1) {
1498 exec(stack, codePtr + 2);
1500 codePtr = code[codePtr + 1].blk;
1501 break;
1502 case psOpIfelse:
1503 b1 = stack->popBool();
1504 if (b1) {
1505 exec(stack, codePtr + 2);
1506 } else {
1507 exec(stack, code[codePtr].blk);
1509 codePtr = code[codePtr + 1].blk;
1510 break;
1511 case psOpReturn:
1512 return;
1514 break;
1515 default:
1516 error(-1, "Internal: bad object in PostScript function code");
1517 break;