Coverage Report

Created: 2023-09-25 06:41

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