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

Last change on this file since 257 was 257, checked in by Eugene Romanenko, 13 years ago

PDF plugin: Poppler library updated to version 0.10.0

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