1 //========================================================================
5 // Copyright 2001-2003 Glyph & Cog, LLC
7 //========================================================================
9 //========================================================================
11 // Modified under the Poppler project - http://poppler.freedesktop.org
13 // All changes made under the Poppler project to this file are licensed
14 // under GPL version 2 or later
16 // Copyright (C) 2006, 2008-2010, 2013, 2014 Albert Astals Cid <aacid@kde.org>
17 // Copyright (C) 2006 Jeff Muizelaar <jeff@infidigm.net>
18 // Copyright (C) 2010 Christian Feuersänger <cfeuersaenger@googlemail.com>
19 // Copyright (C) 2011 Andrea Canciani <ranma42@gmail.com>
20 // Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
21 // Copyright (C) 2012 Adam Reichold <adamreichold@myopera.com>
22 // Copyright (C) 2013 Fabio D'Urso <fabiodurso@hotmail.it>
24 // To see a description of the changes please see the Changelog file that
25 // came with your tarball or type make ChangeLog if you are building from git
27 //========================================================================
31 #ifdef USE_GCC_PRAGMAS
32 #pragma implementation
40 #include "goo/gstrtod.h"
48 #define M_PI 3.14159265358979323846
51 //------------------------------------------------------------------------
53 //------------------------------------------------------------------------
55 Function::Function() {
58 Function::~Function() {
61 Function
*Function::parse(Object
*funcObj
) {
62 std::set
<int> usedParents
;
63 return parse(funcObj
, &usedParents
);
66 Function
*Function::parse(Object
*funcObj
, std::set
<int> *usedParents
) {
72 if (funcObj
->isStream()) {
73 dict
= funcObj
->streamGetDict();
74 } else if (funcObj
->isDict()) {
75 dict
= funcObj
->getDict();
76 } else if (funcObj
->isName("Identity")) {
77 return new IdentityFunction();
79 error(errSyntaxError
, -1, "Expected function dictionary or stream");
83 if (!dict
->lookup("FunctionType", &obj1
)->isInt()) {
84 error(errSyntaxError
, -1, "Function type is missing or wrong type");
88 funcType
= obj1
.getInt();
92 func
= new SampledFunction(funcObj
, dict
);
93 } else if (funcType
== 2) {
94 func
= new ExponentialFunction(funcObj
, dict
);
95 } else if (funcType
== 3) {
96 func
= new StitchingFunction(funcObj
, dict
, usedParents
);
97 } else if (funcType
== 4) {
98 func
= new PostScriptFunction(funcObj
, dict
);
100 error(errSyntaxError
, -1, "Unimplemented function type ({0:d})", funcType
);
111 Function::Function(const Function
*func
) {
115 memcpy(domain
, func
->domain
, funcMaxInputs
* 2 * sizeof(double));
116 memcpy(range
, func
->range
, funcMaxOutputs
* 2 * sizeof(double));
118 hasRange
= func
->hasRange
;
121 GBool
Function::init(Dict
*dict
) {
126 if (!dict
->lookup("Domain", &obj1
)->isArray()) {
127 error(errSyntaxError
, -1, "Function is missing domain");
130 m
= obj1
.arrayGetLength() / 2;
131 if (m
> funcMaxInputs
) {
132 error(errSyntaxError
, -1, "Functions with more than {0:d} inputs are unsupported",
136 for (i
= 0; i
< m
; ++i
) {
137 obj1
.arrayGet(2*i
, &obj2
);
139 error(errSyntaxError
, -1, "Illegal value in function domain array");
142 domain
[i
][0] = obj2
.getNum();
144 obj1
.arrayGet(2*i
+1, &obj2
);
146 error(errSyntaxError
, -1, "Illegal value in function domain array");
149 domain
[i
][1] = obj2
.getNum();
157 if (dict
->lookup("Range", &obj1
)->isArray()) {
159 n
= obj1
.arrayGetLength() / 2;
160 if (n
> funcMaxOutputs
) {
161 error(errSyntaxError
, -1, "Functions with more than {0:d} outputs are unsupported",
165 for (i
= 0; i
< n
; ++i
) {
166 obj1
.arrayGet(2*i
, &obj2
);
168 error(errSyntaxError
, -1, "Illegal value in function range array");
171 range
[i
][0] = obj2
.getNum();
173 obj1
.arrayGet(2*i
+1, &obj2
);
175 error(errSyntaxError
, -1, "Illegal value in function range array");
178 range
[i
][1] = obj2
.getNum();
193 //------------------------------------------------------------------------
195 //------------------------------------------------------------------------
197 IdentityFunction::IdentityFunction() {
200 // fill these in with arbitrary values just in case they get used
204 for (i
= 0; i
< funcMaxInputs
; ++i
) {
211 IdentityFunction::~IdentityFunction() {
214 void IdentityFunction::transform(double *in
, double *out
) {
217 for (i
= 0; i
< funcMaxOutputs
; ++i
) {
222 //------------------------------------------------------------------------
224 //------------------------------------------------------------------------
226 SampledFunction::SampledFunction(Object
*funcObj
, Dict
*dict
) {
234 double in
[funcMaxInputs
];
235 int i
, j
, t
, bit
, idx
;
242 //----- initialize the generic stuff
247 error(errSyntaxError
, -1, "Type 0 function is missing range");
250 if (m
> sampledFuncMaxInputs
) {
251 error(errSyntaxError
, -1, "Sampled functions with more than {0:d} inputs are unsupported",
252 sampledFuncMaxInputs
);
257 sBuf
= (double *)gmallocn(1 << m
, sizeof(double));
259 //----- get the stream
260 if (!funcObj
->isStream()) {
261 error(errSyntaxError
, -1, "Type 0 function isn't a stream");
264 str
= funcObj
->getStream();
267 if (!dict
->lookup("Size", &obj1
)->isArray() ||
268 obj1
.arrayGetLength() != m
) {
269 error(errSyntaxError
, -1, "Function has missing or invalid size array");
272 for (i
= 0; i
< m
; ++i
) {
273 obj1
.arrayGet(i
, &obj2
);
275 error(errSyntaxError
, -1, "Illegal value in function size array");
278 sampleSize
[i
] = obj2
.getInt();
279 if (sampleSize
[i
] <= 0) {
280 error(errSyntaxError
, -1, "Illegal non-positive value in function size array");
286 idxOffset
= (int *)gmallocn(1 << m
, sizeof(int));
287 for (i
= 0; i
< (1<<m
); ++i
) {
289 for (j
= m
- 1, t
= i
; j
>= 1; --j
, t
<<= 1) {
290 if (sampleSize
[j
] == 1) {
293 bit
= (t
>> (m
- 1)) & 1;
295 idx
= (idx
+ bit
) * sampleSize
[j
-1];
297 if (sampleSize
[0] == 1) {
300 bit
= (t
>> (m
- 1)) & 1;
302 idxOffset
[i
] = (idx
+ bit
) * n
;
305 //----- BitsPerSample
306 if (!dict
->lookup("BitsPerSample", &obj1
)->isInt()) {
307 error(errSyntaxError
, -1, "Function has missing or invalid BitsPerSample");
310 sampleBits
= obj1
.getInt();
311 sampleMul
= 1.0 / (pow(2.0, (double)sampleBits
) - 1);
315 if (dict
->lookup("Encode", &obj1
)->isArray() &&
316 obj1
.arrayGetLength() == 2*m
) {
317 for (i
= 0; i
< m
; ++i
) {
318 obj1
.arrayGet(2*i
, &obj2
);
320 error(errSyntaxError
, -1, "Illegal value in function encode array");
323 encode
[i
][0] = obj2
.getNum();
325 obj1
.arrayGet(2*i
+1, &obj2
);
327 error(errSyntaxError
, -1, "Illegal value in function encode array");
330 encode
[i
][1] = obj2
.getNum();
334 for (i
= 0; i
< m
; ++i
) {
336 encode
[i
][1] = sampleSize
[i
] - 1;
340 for (i
= 0; i
< m
; ++i
) {
341 inputMul
[i
] = (encode
[i
][1] - encode
[i
][0]) /
342 (domain
[i
][1] - domain
[i
][0]);
346 if (dict
->lookup("Decode", &obj1
)->isArray() &&
347 obj1
.arrayGetLength() == 2*n
) {
348 for (i
= 0; i
< n
; ++i
) {
349 obj1
.arrayGet(2*i
, &obj2
);
351 error(errSyntaxError
, -1, "Illegal value in function decode array");
354 decode
[i
][0] = obj2
.getNum();
356 obj1
.arrayGet(2*i
+1, &obj2
);
358 error(errSyntaxError
, -1, "Illegal value in function decode array");
361 decode
[i
][1] = obj2
.getNum();
365 for (i
= 0; i
< n
; ++i
) {
366 decode
[i
][0] = range
[i
][0];
367 decode
[i
][1] = range
[i
][1];
374 for (i
= 0; i
< m
; ++i
)
375 nSamples
*= sampleSize
[i
];
376 samples
= (double *)gmallocn(nSamples
, sizeof(double));
379 bitMask
= (1 << sampleBits
) - 1;
381 for (i
= 0; i
< nSamples
; ++i
) {
382 if (sampleBits
== 8) {
384 } else if (sampleBits
== 16) {
386 s
= (s
<< 8) + str
->getChar();
387 } else if (sampleBits
== 32) {
389 s
= (s
<< 8) + str
->getChar();
390 s
= (s
<< 8) + str
->getChar();
391 s
= (s
<< 8) + str
->getChar();
393 while (bits
< sampleBits
) {
394 buf
= (buf
<< 8) | (str
->getChar() & 0xff);
397 s
= (buf
>> (bits
- sampleBits
)) & bitMask
;
400 samples
[i
] = (double)s
* sampleMul
;
405 for (i
= 0; i
< m
; ++i
) {
406 in
[i
] = domain
[i
][0];
407 cacheIn
[i
] = in
[i
] - 1;
409 transform(in
, cacheOut
);
422 SampledFunction::~SampledFunction() {
434 SampledFunction::SampledFunction(const SampledFunction
*func
) : Function(func
) {
435 memcpy(sampleSize
, func
->sampleSize
, funcMaxInputs
* sizeof(int));
437 memcpy(encode
, func
->encode
, funcMaxInputs
* 2 * sizeof(double));
438 memcpy(decode
, func
->decode
, funcMaxOutputs
* 2 * sizeof(double));
440 memcpy(inputMul
, func
->inputMul
, funcMaxInputs
* sizeof(double));
442 nSamples
= func
->nSamples
;
444 idxOffset
= (int *)gmallocn(1 << m
, sizeof(int));
445 memcpy(idxOffset
, func
->idxOffset
, (1 << m
) * (int)sizeof(int));
447 samples
= (double *)gmallocn(nSamples
, sizeof(double));
448 memcpy(samples
, func
->samples
, nSamples
* sizeof(double));
450 sBuf
= (double *)gmallocn(1 << m
, sizeof(double));
452 memcpy(cacheIn
, func
->cacheIn
, funcMaxInputs
* sizeof(double));
453 memcpy(cacheOut
, func
->cacheOut
, funcMaxOutputs
* sizeof(double));
458 void SampledFunction::transform(double *in
, double *out
) {
460 int e
[funcMaxInputs
];
461 double efrac0
[funcMaxInputs
];
462 double efrac1
[funcMaxInputs
];
463 int i
, j
, k
, idx0
, t
;
466 for (i
= 0; i
< m
; ++i
) {
467 if (in
[i
] != cacheIn
[i
]) {
472 for (i
= 0; i
< n
; ++i
) {
473 out
[i
] = cacheOut
[i
];
478 // map input values into sample array
479 for (i
= 0; i
< m
; ++i
) {
480 x
= (in
[i
] - domain
[i
][0]) * inputMul
[i
] + encode
[i
][0];
481 if (x
< 0 || x
!= x
) { // x!=x is a more portable version of isnan(x)
483 } else if (x
> sampleSize
[i
] - 1) {
484 x
= sampleSize
[i
] - 1;
487 if (e
[i
] == sampleSize
[i
] - 1 && sampleSize
[i
] > 1) {
488 // this happens if in[i] = domain[i][1]
489 e
[i
] = sampleSize
[i
] - 2;
491 efrac1
[i
] = x
- e
[i
];
492 efrac0
[i
] = 1 - efrac1
[i
];
495 // compute index for the first sample to be used
497 for (k
= m
- 1; k
>= 1; --k
) {
498 idx0
= (idx0
+ e
[k
]) * sampleSize
[k
-1];
500 idx0
= (idx0
+ e
[0]) * n
;
502 // for each output, do m-linear interpolation
503 for (i
= 0; i
< n
; ++i
) {
505 // pull 2^m values out of the sample array
506 for (j
= 0; j
< (1<<m
); ++j
) {
507 int idx
= idx0
+ idxOffset
[j
] + i
;
508 if (likely(idx
>= 0 && idx
< nSamples
)) {
509 sBuf
[j
] = samples
[idx
];
511 sBuf
[j
] = 0; // TODO Investigate if this is what Adobe does
515 // do m sets of interpolations
516 for (j
= 0, t
= (1<<m
); j
< m
; ++j
, t
>>= 1) {
517 for (k
= 0; k
< t
; k
+= 2) {
518 sBuf
[k
>> 1] = efrac0
[j
] * sBuf
[k
] + efrac1
[j
] * sBuf
[k
+1];
522 // map output value to range
523 out
[i
] = sBuf
[0] * (decode
[i
][1] - decode
[i
][0]) + decode
[i
][0];
524 if (out
[i
] < range
[i
][0]) {
525 out
[i
] = range
[i
][0];
526 } else if (out
[i
] > range
[i
][1]) {
527 out
[i
] = range
[i
][1];
531 // save current result in the cache
532 for (i
= 0; i
< m
; ++i
) {
535 for (i
= 0; i
< n
; ++i
) {
536 cacheOut
[i
] = out
[i
];
540 GBool
SampledFunction::hasDifferentResultSet(Function
*func
) {
541 if (func
->getType() == 0) {
542 SampledFunction
*compTo
= (SampledFunction
*) func
;
543 if (compTo
->getSampleNumber() != nSamples
)
545 double *compSamples
= compTo
->getSamples();
546 for (int i
= 0; i
< nSamples
; i
++) {
547 if (samples
[i
] != compSamples
[i
])
554 //------------------------------------------------------------------------
555 // ExponentialFunction
556 //------------------------------------------------------------------------
558 ExponentialFunction::ExponentialFunction(Object
*funcObj
, Dict
*dict
) {
564 //----- initialize the generic stuff
569 error(errSyntaxError
, -1, "Exponential function with more than one input");
574 if (dict
->lookup("C0", &obj1
)->isArray()) {
575 if (hasRange
&& obj1
.arrayGetLength() != n
) {
576 error(errSyntaxError
, -1, "Function's C0 array is wrong length");
579 n
= obj1
.arrayGetLength();
580 for (i
= 0; i
< n
; ++i
) {
581 obj1
.arrayGet(i
, &obj2
);
583 error(errSyntaxError
, -1, "Illegal value in function C0 array");
586 c0
[i
] = obj2
.getNum();
590 if (hasRange
&& n
!= 1) {
591 error(errSyntaxError
, -1, "Function's C0 array is wrong length");
600 if (dict
->lookup("C1", &obj1
)->isArray()) {
601 if (obj1
.arrayGetLength() != n
) {
602 error(errSyntaxError
, -1, "Function's C1 array is wrong length");
605 for (i
= 0; i
< n
; ++i
) {
606 obj1
.arrayGet(i
, &obj2
);
608 error(errSyntaxError
, -1, "Illegal value in function C1 array");
611 c1
[i
] = obj2
.getNum();
616 error(errSyntaxError
, -1, "Function's C1 array is wrong length");
624 if (!dict
->lookup("N", &obj1
)->isNum()) {
625 error(errSyntaxError
, -1, "Function has missing or invalid N");
631 isLinear
= fabs(e
-1.) < 1e-10;
643 ExponentialFunction::~ExponentialFunction() {
646 ExponentialFunction::ExponentialFunction(const ExponentialFunction
*func
) : Function(func
) {
647 memcpy(c0
, func
->c0
, funcMaxOutputs
* sizeof(double));
648 memcpy(c1
, func
->c1
, funcMaxOutputs
* sizeof(double));
651 isLinear
= func
->isLinear
;
655 void ExponentialFunction::transform(double *in
, double *out
) {
659 if (in
[0] < domain
[0][0]) {
661 } else if (in
[0] > domain
[0][1]) {
666 for (i
= 0; i
< n
; ++i
) {
667 out
[i
] = c0
[i
] + (isLinear
? x
: pow(x
, e
)) * (c1
[i
] - c0
[i
]);
669 if (out
[i
] < range
[i
][0]) {
670 out
[i
] = range
[i
][0];
671 } else if (out
[i
] > range
[i
][1]) {
672 out
[i
] = range
[i
][1];
679 //------------------------------------------------------------------------
681 //------------------------------------------------------------------------
683 StitchingFunction::StitchingFunction(Object
*funcObj
, Dict
*dict
, std::set
<int> *usedParents
) {
693 //----- initialize the generic stuff
698 error(errSyntaxError
, -1, "Stitching function with more than one input");
703 if (!dict
->lookup("Functions", &obj1
)->isArray()) {
704 error(errSyntaxError
, -1, "Missing 'Functions' entry in stitching function");
707 k
= obj1
.arrayGetLength();
708 funcs
= (Function
**)gmallocn(k
, sizeof(Function
*));
709 bounds
= (double *)gmallocn(k
+ 1, sizeof(double));
710 encode
= (double *)gmallocn(2 * k
, sizeof(double));
711 scale
= (double *)gmallocn(k
, sizeof(double));
712 for (i
= 0; i
< k
; ++i
) {
715 for (i
= 0; i
< k
; ++i
) {
716 std::set
<int> usedParentsAux
= *usedParents
;
717 obj1
.arrayGetNF(i
, &obj2
);
719 const Ref ref
= obj2
.getRef();
720 if (usedParentsAux
.find(ref
.num
) == usedParentsAux
.end()) {
721 usedParentsAux
.insert(ref
.num
);
723 obj1
.arrayGet(i
, &obj2
);
728 if (!(funcs
[i
] = Function::parse(&obj2
, &usedParentsAux
))) {
731 if (funcs
[i
]->getInputSize() != 1 ||
732 (i
> 0 && funcs
[i
]->getOutputSize() != funcs
[0]->getOutputSize())) {
733 error(errSyntaxError
, -1,
734 "Incompatible subfunctions in stitching function");
742 if (!dict
->lookup("Bounds", &obj1
)->isArray() ||
743 obj1
.arrayGetLength() != k
- 1) {
744 error(errSyntaxError
, -1, "Missing or invalid 'Bounds' entry in stitching function");
747 bounds
[0] = domain
[0][0];
748 for (i
= 1; i
< k
; ++i
) {
749 if (!obj1
.arrayGet(i
- 1, &obj2
)->isNum()) {
750 error(errSyntaxError
, -1, "Invalid type in 'Bounds' array in stitching function");
753 bounds
[i
] = obj2
.getNum();
756 bounds
[k
] = domain
[0][1];
760 if (!dict
->lookup("Encode", &obj1
)->isArray() ||
761 obj1
.arrayGetLength() != 2 * k
) {
762 error(errSyntaxError
, -1, "Missing or invalid 'Encode' entry in stitching function");
765 for (i
= 0; i
< 2 * k
; ++i
) {
766 if (!obj1
.arrayGet(i
, &obj2
)->isNum()) {
767 error(errSyntaxError
, -1, "Invalid type in 'Encode' array in stitching function");
770 encode
[i
] = obj2
.getNum();
775 //----- pre-compute the scale factors
776 for (i
= 0; i
< k
; ++i
) {
777 if (bounds
[i
] == bounds
[i
+1]) {
778 // avoid a divide-by-zero -- in this situation, function i will
779 // never be used anyway
782 scale
[i
] = (encode
[2*i
+1] - encode
[2*i
]) / (bounds
[i
+1] - bounds
[i
]);
786 n
= funcs
[0]->getOutputSize();
796 StitchingFunction::StitchingFunction(const StitchingFunction
*func
) : Function(func
) {
799 funcs
= (Function
**)gmallocn(k
, sizeof(Function
*));
800 for (int i
= 0; i
< k
; ++i
) {
801 funcs
[i
] = func
->funcs
[i
]->copy();
804 bounds
= (double *)gmallocn(k
+ 1, sizeof(double));
805 memcpy(bounds
, func
->bounds
, (k
+ 1) * sizeof(double));
807 encode
= (double *)gmallocn(2 * k
, sizeof(double));
808 memcpy(encode
, func
->encode
, 2 * k
* sizeof(double));
810 scale
= (double *)gmallocn(k
, sizeof(double));
811 memcpy(scale
, func
->scale
, k
* sizeof(double));
816 StitchingFunction::~StitchingFunction() {
820 for (i
= 0; i
< k
; ++i
) {
832 void StitchingFunction::transform(double *in
, double *out
) {
836 if (in
[0] < domain
[0][0]) {
838 } else if (in
[0] > domain
[0][1]) {
843 for (i
= 0; i
< k
- 1; ++i
) {
844 if (x
< bounds
[i
+1]) {
848 x
= encode
[2*i
] + (x
- bounds
[i
]) * scale
[i
];
849 funcs
[i
]->transform(&x
, out
);
852 //------------------------------------------------------------------------
853 // PostScriptFunction
854 //------------------------------------------------------------------------
902 // Note: 'if' and 'ifelse' are parsed separately.
903 // The rest are listed here in alphabetical order.
904 // The index in this table is equivalent to the entry in PSOp.
905 static const char *psOpNames
[] = {
948 #define nPSOps (sizeof(psOpNames) / sizeof(char *))
958 // In the code array, 'if'/'ifelse' operators take up three slots
959 // plus space for the code in the subclause(s).
961 // +---------------------------------+
962 // | psOperator: psOpIf / psOpIfelse |
963 // +---------------------------------+
964 // | psBlock: ptr=<A> |
965 // +---------------------------------+
966 // | psBlock: ptr=<B> |
967 // +---------------------------------+
970 // | psOperator: psOpReturn |
971 // +---------------------------------+
972 // <A> | else clause |
974 // | psOperator: psOpReturn |
975 // +---------------------------------+
978 // For 'if', pointer <A> is present in the code stream but unused.
983 GBool booln
; // boolean (stack only)
984 int intg
; // integer (stack and code)
985 double real
; // real (stack and code)
986 PSOp op
; // operator (code only)
987 int blk
; // if/ifelse block pointer (code only)
991 #define psStackSize 100
996 PSStack() {sp
= psStackSize
; }
997 void clear() { sp
= psStackSize
; }
998 void pushBool(GBool booln
)
1000 if (checkOverflow()) {
1001 stack
[--sp
].type
= psBool
;
1002 stack
[sp
].booln
= booln
;
1005 void pushInt(int intg
)
1007 if (checkOverflow()) {
1008 stack
[--sp
].type
= psInt
;
1009 stack
[sp
].intg
= intg
;
1012 void pushReal(double real
)
1014 if (checkOverflow()) {
1015 stack
[--sp
].type
= psReal
;
1016 stack
[sp
].real
= real
;
1021 if (checkUnderflow() && checkType(psBool
, psBool
)) {
1022 return stack
[sp
++].booln
;
1028 if (checkUnderflow() && checkType(psInt
, psInt
)) {
1029 return stack
[sp
++].intg
;
1037 if (checkUnderflow() && checkType(psInt
, psReal
)) {
1038 ret
= (stack
[sp
].type
== psInt
) ? (double)stack
[sp
].intg
: stack
[sp
].real
;
1044 GBool
empty() { return sp
== psStackSize
; }
1045 GBool
topIsInt() { return sp
< psStackSize
&& stack
[sp
].type
== psInt
; }
1046 GBool
topTwoAreInts()
1047 { return sp
< psStackSize
- 1 &&
1048 stack
[sp
].type
== psInt
&&
1049 stack
[sp
+1].type
== psInt
; }
1050 GBool
topIsReal() { return sp
< psStackSize
&& stack
[sp
].type
== psReal
; }
1051 GBool
topTwoAreNums()
1052 { return sp
< psStackSize
- 1 &&
1053 (stack
[sp
].type
== psInt
|| stack
[sp
].type
== psReal
) &&
1054 (stack
[sp
+1].type
== psInt
|| stack
[sp
+1].type
== psReal
); }
1056 void roll(int n
, int j
);
1059 if (!checkOverflow()) {
1063 if (unlikely(sp
+ i
+ 1 >= psStackSize
)) {
1064 error(errSyntaxError
, -1, "Stack underflow in PostScript function");
1067 if (unlikely(sp
+ i
+ 1 < 0)) {
1068 error(errSyntaxError
, -1, "Stack overflow in PostScript function");
1071 stack
[sp
] = stack
[sp
+ 1 + i
];
1075 if (!checkUnderflow()) {
1083 GBool
checkOverflow(int n
= 1)
1086 error(errSyntaxError
, -1, "Stack overflow in PostScript function");
1091 GBool
checkUnderflow()
1093 if (sp
== psStackSize
) {
1094 error(errSyntaxError
, -1, "Stack underflow in PostScript function");
1099 GBool
checkType(PSObjectType t1
, PSObjectType t2
)
1101 if (stack
[sp
].type
!= t1
&& stack
[sp
].type
!= t2
) {
1102 error(errSyntaxError
, -1, "Type mismatch in PostScript function");
1107 PSObject stack
[psStackSize
];
1112 void PSStack::copy(int n
) {
1115 if (sp
+ n
> psStackSize
) {
1116 error(errSyntaxError
, -1, "Stack underflow in PostScript function");
1119 if (unlikely(sp
- n
> psStackSize
)) {
1120 error(errSyntaxError
, -1, "Stack underflow in PostScript function");
1123 if (!checkOverflow(n
)) {
1126 for (i
= sp
+ n
- 1; i
>= sp
; --i
) {
1127 stack
[i
- n
] = stack
[i
];
1132 void PSStack::roll(int n
, int j
) {
1136 if (unlikely(n
== 0)) {
1147 if (n
<= 0 || j
== 0 || n
> psStackSize
|| sp
+ n
> psStackSize
) {
1151 for (i
= 0; i
< j
; ++i
) {
1153 for (k
= sp
; k
< sp
+ n
- 1; ++k
) {
1154 stack
[k
] = stack
[k
+1];
1156 stack
[sp
+ n
- 1] = obj
;
1160 for (i
= 0; i
< j
; ++i
) {
1161 obj
= stack
[sp
+ n
- 1];
1162 for (k
= sp
+ n
- 1; k
> sp
; --k
) {
1163 stack
[k
] = stack
[k
-1];
1170 PostScriptFunction::PostScriptFunction(Object
*funcObj
, Dict
*dict
) {
1174 double in
[funcMaxInputs
];
1182 //----- initialize the generic stuff
1187 error(errSyntaxError
, -1, "Type 4 function is missing range");
1191 //----- get the stream
1192 if (!funcObj
->isStream()) {
1193 error(errSyntaxError
, -1, "Type 4 function isn't a stream");
1196 str
= funcObj
->getStream();
1198 //----- parse the function
1199 codeString
= new GooString();
1201 if (!(tok
= getToken(str
)) || tok
->cmp("{")) {
1202 error(errSyntaxError
, -1, "Expected '{{' at start of PostScript function");
1210 if (!parseCode(str
, &codePtr
)) {
1215 //----- set up the cache
1216 for (i
= 0; i
< m
; ++i
) {
1217 in
[i
] = domain
[i
][0];
1218 cacheIn
[i
] = in
[i
] - 1;
1220 transform(in
, cacheOut
);
1230 PostScriptFunction::PostScriptFunction(const PostScriptFunction
*func
) : Function(func
) {
1231 codeSize
= func
->codeSize
;
1233 code
= (PSObject
*)gmallocn(codeSize
, sizeof(PSObject
));
1234 memcpy(code
, func
->code
, codeSize
* sizeof(PSObject
));
1236 codeString
= func
->codeString
->copy();
1238 memcpy(cacheIn
, func
->cacheIn
, funcMaxInputs
* sizeof(double));
1239 memcpy(cacheOut
, func
->cacheOut
, funcMaxOutputs
* sizeof(double));
1244 PostScriptFunction::~PostScriptFunction() {
1249 void PostScriptFunction::transform(double *in
, double *out
) {
1254 for (i
= 0; i
< m
; ++i
) {
1255 if (in
[i
] != cacheIn
[i
]) {
1260 for (i
= 0; i
< n
; ++i
) {
1261 out
[i
] = cacheOut
[i
];
1266 for (i
= 0; i
< m
; ++i
) {
1267 //~ may need to check for integers here
1268 stack
.pushReal(in
[i
]);
1271 for (i
= n
- 1; i
>= 0; --i
) {
1272 out
[i
] = stack
.popNum();
1273 if (out
[i
] < range
[i
][0]) {
1274 out
[i
] = range
[i
][0];
1275 } else if (out
[i
] > range
[i
][1]) {
1276 out
[i
] = range
[i
][1];
1281 // if (!stack->empty()) {
1282 // error(errSyntaxWarning, -1,
1283 // "Extra values on stack at end of PostScript function");
1286 // save current result in the cache
1287 for (i
= 0; i
< m
; ++i
) {
1290 for (i
= 0; i
< n
; ++i
) {
1291 cacheOut
[i
] = out
[i
];
1295 GBool
PostScriptFunction::parseCode(Stream
*str
, int *codePtr
) {
1303 if (!(tok
= getToken(str
))) {
1304 error(errSyntaxError
, -1, "Unexpected end of PostScript function stream");
1307 p
= tok
->getCString();
1308 if (isdigit(*p
) || *p
== '.' || *p
== '-') {
1316 resizeCode(*codePtr
);
1318 code
[*codePtr
].type
= psReal
;
1319 code
[*codePtr
].real
= gatof(tok
->getCString());
1321 code
[*codePtr
].type
= psInt
;
1322 code
[*codePtr
].intg
= atoi(tok
->getCString());
1326 } else if (!tok
->cmp("{")) {
1330 resizeCode(opPtr
+ 2);
1331 if (!parseCode(str
, codePtr
)) {
1334 if (!(tok
= getToken(str
))) {
1335 error(errSyntaxError
, -1, "Unexpected end of PostScript function stream");
1338 if (!tok
->cmp("{")) {
1340 if (!parseCode(str
, codePtr
)) {
1344 if (!(tok
= getToken(str
))) {
1345 error(errSyntaxError
, -1, "Unexpected end of PostScript function stream");
1351 if (!tok
->cmp("if")) {
1353 error(errSyntaxError
, -1,
1354 "Got 'if' operator with two blocks in PostScript function");
1357 code
[opPtr
].type
= psOperator
;
1358 code
[opPtr
].op
= psOpIf
;
1359 code
[opPtr
+2].type
= psBlock
;
1360 code
[opPtr
+2].blk
= *codePtr
;
1361 } else if (!tok
->cmp("ifelse")) {
1363 error(errSyntaxError
, -1,
1364 "Got 'ifelse' operator with one block in PostScript function");
1367 code
[opPtr
].type
= psOperator
;
1368 code
[opPtr
].op
= psOpIfelse
;
1369 code
[opPtr
+1].type
= psBlock
;
1370 code
[opPtr
+1].blk
= elsePtr
;
1371 code
[opPtr
+2].type
= psBlock
;
1372 code
[opPtr
+2].blk
= *codePtr
;
1374 error(errSyntaxError
, -1,
1375 "Expected if/ifelse operator in PostScript function");
1380 } else if (!tok
->cmp("}")) {
1382 resizeCode(*codePtr
);
1383 code
[*codePtr
].type
= psOperator
;
1384 code
[*codePtr
].op
= psOpReturn
;
1390 cmp
= 0; // make gcc happy
1391 // invariant: psOpNames[a] < tok < psOpNames[b]
1394 cmp
= tok
->cmp(psOpNames
[mid
]);
1397 } else if (cmp
< 0) {
1404 error(errSyntaxError
, -1,
1405 "Unknown operator '{0:t}' in PostScript function",
1411 resizeCode(*codePtr
);
1412 code
[*codePtr
].type
= psOperator
;
1413 code
[*codePtr
].op
= (PSOp
)a
;
1420 GooString
*PostScriptFunction::getToken(Stream
*str
) {
1425 s
= new GooString();
1428 if ((c
= str
->getChar()) == EOF
) {
1431 codeString
->append(c
);
1433 if (c
== '\x0a' || c
== '\x0d') {
1436 } else if (c
== '%') {
1438 } else if (!isspace(c
)) {
1442 if (c
== '{' || c
== '}') {
1444 } else if (isdigit(c
) || c
== '.' || c
== '-') {
1447 c
= str
->lookChar();
1448 if (c
== EOF
|| !(isdigit(c
) || c
== '.' || c
== '-')) {
1452 codeString
->append(c
);
1457 c
= str
->lookChar();
1458 if (c
== EOF
|| !isalnum(c
)) {
1462 codeString
->append(c
);
1468 void PostScriptFunction::resizeCode(int newSize
) {
1469 if (newSize
>= codeSize
) {
1471 code
= (PSObject
*)greallocn(code
, codeSize
, sizeof(PSObject
));
1475 void PostScriptFunction::exec(PSStack
*stack
, int codePtr
) {
1477 double r1
, r2
, result
;
1481 switch (code
[codePtr
].type
) {
1483 stack
->pushInt(code
[codePtr
++].intg
);
1486 stack
->pushReal(code
[codePtr
++].real
);
1489 switch (code
[codePtr
++].op
) {
1491 if (stack
->topIsInt()) {
1492 stack
->pushInt(abs(stack
->popInt()));
1494 stack
->pushReal(fabs(stack
->popNum()));
1498 if (stack
->topTwoAreInts()) {
1499 i2
= stack
->popInt();
1500 i1
= stack
->popInt();
1501 stack
->pushInt(i1
+ i2
);
1503 r2
= stack
->popNum();
1504 r1
= stack
->popNum();
1505 stack
->pushReal(r1
+ r2
);
1509 if (stack
->topTwoAreInts()) {
1510 i2
= stack
->popInt();
1511 i1
= stack
->popInt();
1512 stack
->pushInt(i1
& i2
);
1514 b2
= stack
->popBool();
1515 b1
= stack
->popBool();
1516 stack
->pushBool(b1
&& b2
);
1520 r2
= stack
->popNum();
1521 r1
= stack
->popNum();
1522 result
= atan2(r1
, r2
) * 180.0 / M_PI
;
1523 if (result
< 0) result
+= 360.0;
1524 stack
->pushReal(result
);
1527 i2
= stack
->popInt();
1528 i1
= stack
->popInt();
1530 stack
->pushInt(i1
<< i2
);
1531 } else if (i2
< 0) {
1532 stack
->pushInt((int)((Guint
)i1
>> -i2
));
1538 if (!stack
->topIsInt()) {
1539 stack
->pushReal(ceil(stack
->popNum()));
1543 stack
->copy(stack
->popInt());
1546 stack
->pushReal(cos(stack
->popNum() * M_PI
/ 180.0));
1549 if (!stack
->topIsInt()) {
1550 stack
->pushInt((int)stack
->popNum());
1554 if (!stack
->topIsReal()) {
1555 stack
->pushReal(stack
->popNum());
1559 r2
= stack
->popNum();
1560 r1
= stack
->popNum();
1561 stack
->pushReal(r1
/ r2
);
1567 if (stack
->topTwoAreInts()) {
1568 i2
= stack
->popInt();
1569 i1
= stack
->popInt();
1570 stack
->pushBool(i1
== i2
);
1571 } else if (stack
->topTwoAreNums()) {
1572 r2
= stack
->popNum();
1573 r1
= stack
->popNum();
1574 stack
->pushBool(r1
== r2
);
1576 b2
= stack
->popBool();
1577 b1
= stack
->popBool();
1578 stack
->pushBool(b1
== b2
);
1585 r2
= stack
->popNum();
1586 r1
= stack
->popNum();
1587 stack
->pushReal(pow(r1
, r2
));
1590 stack
->pushBool(gFalse
);
1593 if (!stack
->topIsInt()) {
1594 stack
->pushReal(floor(stack
->popNum()));
1598 if (stack
->topTwoAreInts()) {
1599 i2
= stack
->popInt();
1600 i1
= stack
->popInt();
1601 stack
->pushBool(i1
>= i2
);
1603 r2
= stack
->popNum();
1604 r1
= stack
->popNum();
1605 stack
->pushBool(r1
>= r2
);
1609 if (stack
->topTwoAreInts()) {
1610 i2
= stack
->popInt();
1611 i1
= stack
->popInt();
1612 stack
->pushBool(i1
> i2
);
1614 r2
= stack
->popNum();
1615 r1
= stack
->popNum();
1616 stack
->pushBool(r1
> r2
);
1620 i2
= stack
->popInt();
1621 i1
= stack
->popInt();
1622 stack
->pushInt(i1
/ i2
);
1625 stack
->index(stack
->popInt());
1628 if (stack
->topTwoAreInts()) {
1629 i2
= stack
->popInt();
1630 i1
= stack
->popInt();
1631 stack
->pushBool(i1
<= i2
);
1633 r2
= stack
->popNum();
1634 r1
= stack
->popNum();
1635 stack
->pushBool(r1
<= r2
);
1639 stack
->pushReal(log(stack
->popNum()));
1642 stack
->pushReal(log10(stack
->popNum()));
1645 if (stack
->topTwoAreInts()) {
1646 i2
= stack
->popInt();
1647 i1
= stack
->popInt();
1648 stack
->pushBool(i1
< i2
);
1650 r2
= stack
->popNum();
1651 r1
= stack
->popNum();
1652 stack
->pushBool(r1
< r2
);
1656 i2
= stack
->popInt();
1657 i1
= stack
->popInt();
1658 stack
->pushInt(i1
% i2
);
1661 if (stack
->topTwoAreInts()) {
1662 i2
= stack
->popInt();
1663 i1
= stack
->popInt();
1664 //~ should check for out-of-range, and push a real instead
1665 stack
->pushInt(i1
* i2
);
1667 r2
= stack
->popNum();
1668 r1
= stack
->popNum();
1669 stack
->pushReal(r1
* r2
);
1673 if (stack
->topTwoAreInts()) {
1674 i2
= stack
->popInt();
1675 i1
= stack
->popInt();
1676 stack
->pushBool(i1
!= i2
);
1677 } else if (stack
->topTwoAreNums()) {
1678 r2
= stack
->popNum();
1679 r1
= stack
->popNum();
1680 stack
->pushBool(r1
!= r2
);
1682 b2
= stack
->popBool();
1683 b1
= stack
->popBool();
1684 stack
->pushBool(b1
!= b2
);
1688 if (stack
->topIsInt()) {
1689 stack
->pushInt(-stack
->popInt());
1691 stack
->pushReal(-stack
->popNum());
1695 if (stack
->topIsInt()) {
1696 stack
->pushInt(~stack
->popInt());
1698 stack
->pushBool(!stack
->popBool());
1702 if (stack
->topTwoAreInts()) {
1703 i2
= stack
->popInt();
1704 i1
= stack
->popInt();
1705 stack
->pushInt(i1
| i2
);
1707 b2
= stack
->popBool();
1708 b1
= stack
->popBool();
1709 stack
->pushBool(b1
|| b2
);
1716 i2
= stack
->popInt();
1717 i1
= stack
->popInt();
1718 stack
->roll(i1
, i2
);
1721 if (!stack
->topIsInt()) {
1722 r1
= stack
->popNum();
1723 stack
->pushReal((r1
>= 0) ? floor(r1
+ 0.5) : ceil(r1
- 0.5));
1727 stack
->pushReal(sin(stack
->popNum() * M_PI
/ 180.0));
1730 stack
->pushReal(sqrt(stack
->popNum()));
1733 if (stack
->topTwoAreInts()) {
1734 i2
= stack
->popInt();
1735 i1
= stack
->popInt();
1736 stack
->pushInt(i1
- i2
);
1738 r2
= stack
->popNum();
1739 r1
= stack
->popNum();
1740 stack
->pushReal(r1
- r2
);
1744 stack
->pushBool(gTrue
);
1747 if (!stack
->topIsInt()) {
1748 r1
= stack
->popNum();
1749 stack
->pushReal((r1
>= 0) ? floor(r1
) : ceil(r1
));
1753 if (stack
->topTwoAreInts()) {
1754 i2
= stack
->popInt();
1755 i1
= stack
->popInt();
1756 stack
->pushInt(i1
^ i2
);
1758 b2
= stack
->popBool();
1759 b1
= stack
->popBool();
1760 stack
->pushBool(b1
^ b2
);
1764 b1
= stack
->popBool();
1766 exec(stack
, codePtr
+ 2);
1768 codePtr
= code
[codePtr
+ 1].blk
;
1771 b1
= stack
->popBool();
1773 exec(stack
, codePtr
+ 2);
1775 exec(stack
, code
[codePtr
].blk
);
1777 codePtr
= code
[codePtr
+ 1].blk
;
1784 error(errSyntaxError
, -1, "Internal: bad object in PostScript function code");