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

source code of poppler/poppler/Function.cc