Coverage Report

Created: 2026-10-14 06:52

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