Coverage Report

Created: 2025-07-12 07:51

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