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

Last change on this file since 2 was 2, checked in by Eugene Romanenko, 16 years ago

First import

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