root/middleware-offline/trunk/_src/eidmw/pteid-poppler/poppler/Function.cc @ 226

Revision 226, 38.2 KB (checked in by vsilva, 8 years ago)

Improve PDF native Signature

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