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