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