source: trunk/poppler/mypoppler/poppler/Function.cc @ 461

Last change on this file since 461 was 461, checked in by Silvan Scherrer, 11 years ago

poppler update to 0.14.2

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