Coverage Report

Created: 2026-07-24 07:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/gpdl/txttop.c
Line
Count
Source
1
/* Copyright (C) 2026 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
/* Top-level API implementation for text file handling */
17
18
/* Language wrapper implementation (see pltop.h) */
19
20
21
/* Enable the following for a dump of the codepoints to stdout. */
22
/* #define DEBUG_CODEPOINTS */
23
24
/* Enable the following for a hacky dump of the output PCL to file. */
25
/* #define DEBUG_DUMP_PCL */
26
27
#ifdef DEBUG_DUMP_PCL
28
#include <stdio.h>
29
static FILE *debug_pcl_out = NULL;
30
static void wipe(void)
31
{
32
        fclose(debug_pcl_out);
33
        debug_pcl_out = NULL;
34
}
35
static void
36
debug_as_pcl(const char *p, int n)
37
{
38
        if (debug_pcl_out == NULL)
39
        {
40
            debug_pcl_out = fopen("debug_pcl_out", "wb");
41
            atexit(wipe);
42
        }
43
        fwrite(p, n, 1, debug_pcl_out);
44
}
45
#endif
46
47
#include "pltop.h"
48
#include "plmain.h"
49
50
#include "plparse.h" /* for e_ExitLanguage */
51
#include "plmain.h"
52
#include "gxdevice.h" /* so we can include gxht.h below */
53
#include "gserrors.h"
54
#include "gp.h"
55
#include "assert_.h"
56
57
/*
58
 * The TXT interpeter is identical to pl_interp_t.
59
 * The TXT interpreter instance is derived from pl_interp_implementation_t.
60
 */
61
62
typedef enum
63
{
64
    TXT_STATE_INIT = 0,
65
    TXT_STATE_UTF8,
66
    TXT_STATE_UTF8_MAYBE,
67
    TXT_STATE_UTF16_LE,
68
    TXT_STATE_UTF16_BE,
69
    TXT_STATE_ASCII
70
} txt_state_t;
71
72
typedef struct txt_interp_instance_s txt_interp_instance_t;
73
74
struct txt_interp_instance_s
75
{
76
    gs_memory_t *memory;                /* memory allocator to use */
77
78
    pl_interp_implementation_t *sub;
79
    gx_device *device;
80
81
    int buffered;
82
    byte buffer[4];
83
84
    int state;
85
    int detected;
86
    int just_had_lf;
87
    int just_had_cr;
88
    int col;
89
    int sent;
90
};
91
92
enum
93
{
94
    TXT_UNDETECTED = -1,
95
    TXT_UNKNOWN,
96
    TXT_UTF8,
97
    TXT_UTF8_MAYBE,
98
    TXT_UTF16_LE,
99
    TXT_UTF16_BE,
100
    TXT_ASCII,
101
};
102
103
static int
104
identify_from_buffer(const unsigned char *s, int len)
105
28.8k
{
106
28.8k
    int count_controls = 0;
107
28.8k
    int count_hi = 0;
108
28.8k
    int count_tabs = 0;
109
28.8k
    int plausibly_utf8 = 1;
110
28.8k
    int i;
111
112
    /* UTF-8 with a BOM */
113
28.8k
    if (len >= 3 && s[0] == 0xef && s[1] == 0xbb && s[2] == 0xbf)
114
14
        return TXT_UTF8;
115
    /* UTF-16 (little endian) */
116
28.8k
    if (len >= 2 && s[0] == 0xff && s[1] == 0xfe)
117
151
        return TXT_UTF16_LE;
118
    /* UTF-16 (big endian) */
119
28.6k
    if (len >= 2 && s[0] == 0xfe && s[1] == 0xff)
120
212
        return TXT_UTF16_BE;
121
122
    /* Gather some stats. */
123
30.1M
    for (i = 0; i < len; i++)
124
30.1M
    {
125
30.1M
        if (s[i] == 9)
126
118k
        {
127
118k
            count_tabs++;
128
118k
        }
129
30.0M
        else if (s[i] == 12)
130
154k
        {
131
            /* Form feed. We'll let that slide. */
132
154k
        }
133
29.8M
        else if (s[i] == 10)
134
268k
        {
135
268k
           if (i+1 < len && s[i+1] == 13)
136
39.9k
                i++;
137
268k
        }
138
29.5M
        else if (s[i] == 13)
139
196k
        {
140
196k
           if (i+1 < len && s[i+1] == 10)
141
129k
                i++;
142
196k
        }
143
29.3M
        else if (s[i] < 32 || s[i] == 0x7f)
144
6.98M
        {
145
6.98M
            count_controls++;
146
6.98M
        }
147
22.4M
        else if (s[i] < 0x7f)
148
16.3M
        {
149
            /* Seems like a reasonable ASCII value. */
150
16.3M
        }
151
6.03M
        else
152
6.03M
        {
153
6.03M
            count_hi++;
154
6.03M
            if ((s[i] & 0xF8) == 0xF0)
155
324k
            {
156
                /* 3 following bytes */
157
324k
                if (i+1 < len && (s[i+1] & 0xC0) != 0x80)
158
306k
                    plausibly_utf8 = 0;
159
17.2k
                else if (i+2 < len && (s[i+2] & 0xC0) != 0x80)
160
10.0k
                    plausibly_utf8 = 0;
161
7.23k
                else if (i+3 < len && (s[i+3] & 0xC0) != 0x80)
162
3.34k
                    plausibly_utf8 = 0;
163
3.88k
                else
164
3.88k
                    i+=3;
165
324k
            }
166
5.71M
            else if ((s[i] & 0xF0) == 0xE0)
167
388k
            {
168
                /* 2 following bytes */
169
388k
                if (i+1 < len && (s[i+1] & 0xC0) != 0x80)
170
346k
                    plausibly_utf8 = 0;
171
42.0k
                else if (i+2 < len && (s[i+2] & 0xC0) != 0x80)
172
27.9k
                    plausibly_utf8 = 0;
173
14.0k
                else
174
14.0k
                    i+=2;
175
388k
            }
176
5.32M
            else if ((s[i] & 0xE0) == 0xC0)
177
1.57M
            {
178
                /* 1 following bytes */
179
1.57M
                if (i+1 < len && (s[i+1] & 0xC0) != 0x80)
180
1.44M
                    plausibly_utf8 = 0;
181
131k
                else
182
131k
                    i++;
183
1.57M
            }
184
3.74M
            else
185
3.74M
                plausibly_utf8 = 0;
186
6.03M
        }
187
30.1M
    }
188
189
    /* Any (non tab/cr/lf/ff) control characters probably means this isn't text. */
190
28.4k
    if (count_controls > 0)
191
26.3k
        return TXT_UNKNOWN;
192
    /* If we've managed to decode all that as utf8 without problem, it's probably text. */
193
2.16k
    if (plausibly_utf8)
194
1.54k
        return TXT_UTF8_MAYBE;
195
    /* If we're hitting too many top bit set chars, give up. */
196
619
    if (count_hi > len/10)
197
224
        return TXT_UNKNOWN;
198
199
395
    return TXT_ASCII;
200
619
}
201
202
static int
203
txt_detect_language(const char *t, int len)
204
28.0k
{
205
28.0k
    const unsigned char *s = (const unsigned char *)t;
206
207
28.0k
    switch (identify_from_buffer(s, len))
208
28.0k
    {
209
7
    case TXT_UTF8:
210
86
    case TXT_UTF16_LE:
211
207
    case TXT_UTF16_BE:
212
        /* PCL spots files with lots of ESCs in them at confidence
213
         * level 80. We'll use 70, cos we don't want to override that. */
214
207
        return 70;
215
1.05k
    case TXT_UTF8_MAYBE:
216
1.31k
    case TXT_ASCII:
217
1.31k
        return 60;
218
0
    default:
219
26.5k
    case TXT_UNKNOWN:
220
26.5k
        break;
221
28.0k
    }
222
223
26.5k
    return 0;
224
28.0k
}
225
226
static const pl_interp_characteristics_t *
227
txt_impl_characteristics(const pl_interp_implementation_t *pimpl)
228
59.1k
{
229
59.1k
    static pl_interp_characteristics_t txt_characteristics =
230
59.1k
    {
231
59.1k
        "TXT",
232
59.1k
        txt_detect_language,
233
59.1k
    };
234
59.1k
    return &txt_characteristics;
235
59.1k
}
236
237
/* Do per-instance interpreter allocation/init. No device is set yet */
238
static int
239
txt_impl_allocate_interp_instance(pl_interp_implementation_t *impl,
240
                                  gs_memory_t *pmem)
241
16.1k
{
242
16.1k
    txt_interp_instance_t *instance;
243
244
16.1k
    instance = (txt_interp_instance_t *) gs_alloc_bytes(pmem,
245
16.1k
            sizeof(txt_interp_instance_t), "txt_impl_allocate_interp_instance");
246
247
16.1k
    if (!instance)
248
0
        return_error(gs_error_VMerror);
249
250
16.1k
    instance->memory = pmem;
251
16.1k
    instance->sub = NULL;
252
253
16.1k
    impl->interp_client_data = instance;
254
255
16.1k
    return 0;
256
16.1k
}
257
258
/* Prepare interp instance for the next "job" */
259
static int
260
txt_impl_init_job(pl_interp_implementation_t *impl,
261
                  gx_device                  *pdevice)
262
791
{
263
791
    txt_interp_instance_t *instance = impl->interp_client_data;
264
265
791
    instance->device = pdevice;
266
791
    instance->state = TXT_STATE_INIT;
267
791
    instance->buffered = 0;
268
791
    instance->detected = TXT_UNDETECTED;
269
791
    instance->just_had_lf = 0;
270
791
    instance->just_had_cr = 0;
271
791
    instance->col = 0;
272
273
791
    instance->sub = pl_main_get_pcl_instance(instance->memory);
274
275
791
    return pl_init_job(instance->sub, instance->device);
276
791
}
277
278
7.07k
#define ESC 27
279
280
static int
281
send_bytes(txt_interp_instance_t *instance, const byte *p, int n)
282
2.42M
{
283
2.42M
    stream_cursor_read cursor;
284
285
#ifdef DEBUG_DUMP_PCL
286
    debug_as_pcl(p, n);
287
#endif
288
289
2.42M
    stream_cursor_read_init(&cursor, p, n);
290
291
2.42M
    return instance->sub->proc_process(instance->sub, &cursor);
292
2.42M
}
293
294
static void
295
drop_buffered(txt_interp_instance_t *instance, int n)
296
1.66M
{
297
1.66M
    assert(instance->buffered >= n);
298
1.66M
    instance->buffered -= n;
299
1.66M
    if (instance->buffered > 0)
300
2.11k
        memmove(instance->buffer, &instance->buffer[n], instance->buffered);
301
1.66M
}
302
303
static int
304
send_pcl_init(txt_interp_instance_t *instance)
305
643
{
306
643
    static byte init[] = {
307
643
            ESC, 'E',                     /* Reset */
308
643
            ESC, '&', 'l', '0', 'O',      /* Orientation */
309
643
            ESC, '&', 'k', '1', '0', 'H', /* Horizontal spacing 10/120 of an inch. */
310
643
            ESC, '&', 'l', '8', 'C',      /* Vertical line spacing 8/48 of an inch. */
311
643
            ESC, '&', 't', '8', '3', 'P', /* &t = double byte parsing, 83 = utf-8, P = ? */
312
643
            ESC, '(', '1', '8', 'N',      /* Primary symbol set = 18N = Unicode */
313
643
            ESC, '(', 's', '0', 'P',      /* Fixed pitch */
314
643
            ESC, '(', 's', '1', '2', 'H', /* Secondary fixed pitch 12cpi */
315
643
            ESC, '(', 's', '8', 'V',      /* Point size 8 */
316
643
            ESC, '(', 's', '3', 'T',      /* Typeface number 3 */
317
643
            ESC, '&', 's', '0', 'C'       /* Wrappity wrap wrap */
318
643
    };
319
320
643
    return send_bytes(instance, init, sizeof(init));
321
643
}
322
323
static int
324
send_urc(txt_interp_instance_t *instance, int n)
325
588
{
326
588
    static byte unicode_replacement_char_as_utf8[] = { 0xe3, 0xbf, 0xbd };
327
328
588
    if (instance->state == TXT_STATE_UTF8_MAYBE)
329
62
    {
330
        /* We were guessing that this was UTF8. Now we know it's not. Drop back to ascii. */
331
62
        instance->state = TXT_STATE_ASCII;
332
62
        return 0;
333
62
    }
334
335
526
    drop_buffered(instance, n);
336
337
526
    instance->sent = 1;
338
526
    return send_bytes(instance, unicode_replacement_char_as_utf8, sizeof(unicode_replacement_char_as_utf8));
339
588
}
340
341
static int
342
send_utf8(txt_interp_instance_t *instance, int val)
343
2.42M
{
344
2.42M
    byte buf[4];
345
2.42M
    int n;
346
347
    /* Finally, send the val! */
348
2.42M
    if (val < 0x80)
349
1.99M
    {
350
1.99M
        buf[0] = val;
351
1.99M
        n = 1;
352
1.99M
    }
353
429k
    else if (val < 0x800)
354
168k
    {
355
168k
        buf[0] = 0xC0 + (val>>6);
356
168k
        buf[1] = 0x80 + (val & 0x3F);
357
168k
        n = 2;
358
168k
    }
359
261k
    else if (val < 0x10000)
360
260k
    {
361
260k
        buf[0] = 0xE0 + (val>>12);
362
260k
        buf[1] = 0x80 + ((val>>6) & 0x3F);
363
260k
        buf[2] = 0x80 + (val & 0x3F);
364
260k
        n = 3;
365
260k
    }
366
657
    else
367
657
    {
368
657
        buf[0] = 0xF0 + (val>>18);
369
657
        buf[1] = 0x80 + ((val>>12) & 0x3F);
370
657
        buf[2] = 0x80 + ((val>>6) & 0x3F);
371
657
        buf[3] = 0x80 + (val & 0x3F);
372
657
        n = 4;
373
657
    }
374
2.42M
    return send_bytes(instance, buf, n);
375
2.42M
}
376
377
/* All our actual codepoints should flow through here. So this is where
378
 * we do the housekeeping. */
379
static int
380
send_codepoint(txt_interp_instance_t *instance, int val)
381
1.66M
{
382
1.66M
    int code;
383
384
#ifdef DEBUG_CODEPOINTS
385
    dprintf3("Sending codepoint %d (%x) %c\n", val, val, val >= 32 && val <= 255 && val != 127 ? val : '.');
386
#endif
387
388
1.66M
    instance->sent = 1;
389
    /* Tidy up whatever mess of CR/LF we are passed. */
390
1.66M
    if (val == '\r')
391
71.5k
    {
392
        /* If we've got a CR and we've just had a LF, swallow this. */
393
71.5k
        if (instance->just_had_lf)
394
24.8k
        {
395
24.8k
            instance->just_had_lf = 0;
396
24.8k
            return 0;
397
24.8k
        }
398
46.6k
        instance->just_had_cr = 1;
399
46.6k
        val = '\n';
400
46.6k
    }
401
1.59M
    else if (val == '\n')
402
76.8k
    {
403
        /* If we've got a LF and we've just had a CR, swallow this. */
404
76.8k
        if (instance->just_had_cr)
405
43.7k
        {
406
43.7k
            instance->just_had_cr = 0;
407
43.7k
            return 0;
408
43.7k
        }
409
33.1k
        instance->just_had_lf = 1;
410
33.1k
    }
411
1.51M
    else
412
1.51M
    {
413
1.51M
        instance->just_had_cr = 0;
414
1.51M
        instance->just_had_lf = 0;
415
1.51M
    }
416
417
    /* Keep track of what column we're at to so we can do tab handling. */
418
1.59M
    if (val == '\n')
419
79.8k
    {
420
79.8k
        instance->col = 0;
421
79.8k
        code = send_utf8(instance, '\n');
422
79.8k
        if (code < 0 && code != gs_error_NeedInput)
423
0
            return code;
424
79.8k
        return send_utf8(instance, '\r');
425
79.8k
    }
426
1.51M
    if (val == '\t')
427
108k
    {
428
108k
        int spaces = 8 - (instance->col & 7);
429
966k
        while (spaces--)
430
857k
        {
431
857k
            int code = send_utf8(instance, ' ');
432
857k
            if (code < 0 && code != gs_error_NeedInput)
433
0
                return code;
434
857k
            instance->col++;
435
857k
        }
436
108k
        return 0;
437
108k
    }
438
1.40M
    instance->col++;
439
440
#if 0
441
    /* No need for this as PCL line wrapping works for us. If PCL ever
442
     * decides to wrap at a number of columns that aren't a multiple of
443
     * 8 then we'll need to do it manually again!. */
444
    if (instance->col == 80)
445
    {
446
        instance->col = 0;
447
        code = send_utf8(instance, '\n');
448
        if (code < 0 && code != gs_error_NeedInput))
449
            return code;
450
        return send_utf8(instance, '\r');
451
    }
452
#endif
453
454
1.40M
    return send_utf8(instance, val);
455
1.51M
}
456
457
static int
458
process_block(txt_interp_instance_t *instance, const byte *ptr, int n)
459
2.12k
{
460
2.12k
    int code;
461
2.12k
    byte *s = &instance->buffer[0];
462
2.12k
    int old_state = instance->state;
463
2.12k
    int val;
464
465
2.12k
    if (instance->detected == TXT_UNDETECTED)
466
791
    {
467
791
        instance->detected = identify_from_buffer(ptr, n);
468
        /* If we're thinking we're ASCII, go straight there. Otherwise, we'll let the
469
         * BOM detection below run its course. */
470
791
        if (instance->detected == TXT_ASCII)
471
130
            instance->state = TXT_STATE_ASCII;
472
791
    }
473
474
2.12k
    instance->sent = 0;
475
2.02M
    while (n)
476
2.02M
    {
477
        /* instance->sent records whether we pulled anything out of the buffer
478
         * last time round the loop. If we changed state, then don't refill the
479
         * buffer. Otherwise only fill the buffer if we didn't a char last time
480
         * (maybe we need char 2 of a 2 char sequence?) or if we haven't got
481
         * anything in the buffer already. */
482
2.02M
        if (instance->state == old_state && (!instance->sent || instance->buffered == 0))
483
2.01M
        {
484
2.01M
            assert(instance->buffered < 4);
485
2.01M
            s[instance->buffered++] = *ptr++;
486
2.01M
            n--;
487
2.01M
        }
488
2.02M
        old_state = instance->state;
489
490
2.02M
        instance->sent = 0;
491
2.02M
        switch (instance->state)
492
2.02M
        {
493
1.78k
        case TXT_STATE_INIT:
494
495
1.78k
            if (instance->buffered == 3 && s[0] == 0xef && s[1] == 0xbb && s[2] == 0xbf)
496
7
            {
497
7
                instance->state = TXT_STATE_UTF8;
498
7
                drop_buffered(instance, 3);
499
7
            }
500
1.78k
            else if (instance->buffered == 2 && s[0] == 0xff && s[1] == 0xfe)
501
72
            {
502
72
                instance->state = TXT_STATE_UTF16_LE;
503
72
                drop_buffered(instance, 2);
504
72
            }
505
1.70k
            else if (instance->buffered == 2 && s[0] == 0xfe && s[1] == 0xff)
506
91
            {
507
91
                instance->state = TXT_STATE_UTF16_BE;
508
91
                drop_buffered(instance, 2);
509
91
            }
510
1.61k
            else if (instance->buffered >= 3)
511
473
            {
512
                /* We haven't found a BOM, try for utf8. */
513
473
                instance->state = TXT_STATE_UTF8_MAYBE;
514
473
            }
515
516
            /* If we've recognised the BOM, then send the init string. */
517
1.78k
            if (instance->state != TXT_STATE_INIT)
518
643
            {
519
643
                code = send_pcl_init(instance);
520
643
                if (code < 0) {
521
643
                    if (code != gs_error_NeedInput || n == 0)
522
3
                        return code;
523
643
                }
524
643
            }
525
1.78k
            break;
526
1.78k
        case TXT_STATE_UTF8:
527
541k
        case TXT_STATE_UTF8_MAYBE:
528
541k
            if ((s[0] & 0xF8) == 0xF0)
529
2.62k
            {
530
                /* 3 following bytes */
531
2.62k
                if (instance->buffered >= 2 && (s[1] & 0xC0) != 0x80)
532
2
                {
533
2
                    code = send_urc(instance, 1);
534
2
                    if (code < 0) {
535
0
                        if (code != gs_error_NeedInput || n == 0)
536
0
                            return code;
537
0
                    }
538
2
                }
539
2.62k
                else if (instance->buffered >= 3 && (s[2] & 0xC0) != 0x80)
540
2
                {
541
2
                    code = send_urc(instance, 2);
542
2
                    if (code < 0) {
543
0
                        if (code != gs_error_NeedInput || n == 0)
544
0
                            return code;
545
0
                    }
546
2
                }
547
2.62k
                else if (instance->buffered == 4 && (s[3] & 0xC0) != 0x80)
548
1
                {
549
1
                    code = send_urc(instance, 3);
550
1
                    if (code < 0) {
551
0
                        if (code != gs_error_NeedInput || n == 0)
552
0
                            return code;
553
0
                    }
554
1
                }
555
2.62k
                else if (instance->buffered == 4)
556
657
                {
557
                    /* Valid encoding of 4 bytes */
558
657
                    val = ((s[0] & 0x7)<<18) | ((s[1] & 0x3f)<<12) | ((s[2] & 0x3f)<<6) |  (s[3] & 0x3f);
559
657
                    drop_buffered(instance, 4);
560
657
                    code = send_codepoint(instance, val);
561
657
                    if (code < 0) {
562
657
                        if (code != gs_error_NeedInput || n == 0)
563
17
                            return code;
564
657
                    }
565
657
                }
566
1.96k
                else if (instance->buffered != 1 && instance->buffered != 2 && instance->buffered != 3)
567
0
                {
568
                    /* Should never happen. */
569
0
                    return_error(gs_error_Fatal);
570
0
                }
571
2.62k
            }
572
538k
            else if ((s[0] & 0xF0) == 0xE0)
573
3.64k
            {
574
                /* 2 following bytes */
575
3.64k
                if (instance->buffered >= 2 && (s[1] & 0xC0) != 0x80)
576
7
                {
577
7
                    code = send_urc(instance, 1);
578
7
                    if (code < 0) {
579
0
                        if (code != gs_error_NeedInput || n == 0)
580
0
                            return code;
581
0
                    }
582
7
                }
583
3.63k
                else if (instance->buffered >= 3 && (s[2] & 0xC0) != 0x80)
584
2
                {
585
2
                    code = send_urc(instance, 2);
586
2
                    if (code < 0) {
587
0
                        if (code != gs_error_NeedInput || n == 0)
588
0
                            return code;
589
0
                    }
590
2
                }
591
3.63k
                else if (instance->buffered == 3)
592
1.21k
                {
593
                    /* Valid encoding of 3 bytes */
594
1.21k
                    val = ((s[0] & 0xF)<<12) | ((s[1] & 0x3f)<<6) | (s[2] & 0x3f);
595
1.21k
                    drop_buffered(instance, 3);
596
1.21k
                    code = send_codepoint(instance, val);
597
1.21k
                    if (code < 0) {
598
1.21k
                        if (code != gs_error_NeedInput || n == 0)
599
17
                            return code;
600
1.21k
                    }
601
1.21k
                }
602
2.41k
                else if (instance->buffered != 1 && instance->buffered != 2)
603
7
                {
604
                    /* Should never happen. */
605
7
                    return_error(gs_error_Fatal);
606
7
                }
607
3.64k
            }
608
534k
            else if ((s[0] & 0xE0) == 0xC0)
609
2.95k
            {
610
                /* 1 following bytes */
611
2.95k
                if (instance->buffered >= 2 && (s[1] & 0xC0) != 0x80)
612
7
                {
613
7
                    code = send_urc(instance, 1);
614
7
                    if (code < 0) {
615
0
                        if (code != gs_error_NeedInput || n == 0)
616
0
                            return code;
617
0
                    }
618
7
                }
619
2.94k
                else if (instance->buffered == 2)
620
1.46k
                {
621
                    /* Valid encoding of 2 bytes */
622
1.46k
                    val = ((s[0] & 0x1F)<<6) | (s[1] & 0x3f);
623
1.46k
                    drop_buffered(instance, 2);
624
1.46k
                    code = send_codepoint(instance, val);
625
1.46k
                    if (code < 0) {
626
1.46k
                        if (code != gs_error_NeedInput || n == 0)
627
10
                            return code;
628
1.46k
                    }
629
1.46k
                }
630
1.48k
                else if (instance->buffered != 1)
631
5
                {
632
                    /* Should never happen. */
633
5
                    return_error(gs_error_Fatal);
634
5
                }
635
2.95k
            }
636
531k
            else if ((s[0] & 0xC0) == 0x80)
637
7
            {
638
                /* A continuation byte at the start. Should never see this. */
639
7
                code = send_urc(instance, 1);
640
7
                if (code < 0) {
641
0
                    if (code != gs_error_NeedInput || n == 0)
642
0
                        return code;
643
0
                }
644
7
            }
645
531k
            else if (s[0] < 0x80)
646
531k
            {
647
                /* Simple byte. */
648
531k
                val = s[0];
649
531k
                drop_buffered(instance, 1);
650
531k
                code = send_codepoint(instance, val);
651
531k
                if (code < 0) {
652
474k
                    if (code != gs_error_NeedInput || n == 0)
653
480
                        return code;
654
474k
                }
655
531k
            }
656
34
            else
657
34
            {
658
                /* Bytes we should never see in a UTF-8 file! (0xf8-0xff) */
659
34
                code = send_urc(instance, 1);
660
34
                if (code < 0) {
661
0
                    if (code != gs_error_NeedInput || n == 0)
662
0
                        return code;
663
0
                }
664
34
            }
665
540k
            break;
666
540k
        case TXT_STATE_UTF16_LE:
667
402k
            if (instance->buffered < 2)
668
201k
                break;
669
201k
            if (s[1] >= 0xD8 && s[1] < 0xDC)
670
898
            {
671
                /* High surrogate */
672
898
                if (instance->buffered < 4)
673
596
                    break;
674
302
                if (s[3] < 0xDC || s[3] > 0xDF)
675
245
                {
676
                    /* Not followed by a low surrogate! Ignore the high surrogate. */
677
245
                    code = send_urc(instance, 2);
678
245
                    if (code < 0)
679
245
                        return code;
680
0
                    break;
681
245
                }
682
57
                val = (((s[0] | (s[1]<<8)) - 0xdc00)<<10) + (s[2] | (s[3]<<8)) - 0xdc00 + 0x10000;
683
57
                drop_buffered(instance, 4);
684
57
            }
685
200k
            else
686
200k
            {
687
200k
                val = s[0] | (s[1]<<8);
688
200k
                drop_buffered(instance, 2);
689
200k
            }
690
200k
            code = send_codepoint(instance, val);
691
200k
            if (code < 0) {
692
200k
                if (code != gs_error_NeedInput || n == 0)
693
163
                    return code;
694
200k
            }
695
200k
            break;
696
269k
        case TXT_STATE_UTF16_BE:
697
269k
            if (instance->buffered < 2)
698
123k
                break;
699
146k
            if (s[0] >= 0xD8 && s[0] < 0xDC)
700
33.6k
            {
701
                /* High surrogate */
702
33.6k
                if (instance->buffered < 4)
703
22.4k
                    break;
704
11.2k
                if (s[2] < 0xDC || s[2] > 0xDF)
705
281
                {
706
                    /* Not followed by a low surrogate! Ignore the high surrogate. */
707
281
                    code = send_urc(instance, 2);
708
281
                    if (code < 0)
709
281
                        return code;
710
0
                    break;
711
281
                }
712
10.9k
                val = (((s[1] | (s[0]<<8)) - 0xdc00)<<10) + (s[3] | (s[2]<<8)) - 0xdc00 + 0x10000;
713
10.9k
                drop_buffered(instance, 4);
714
10.9k
            }
715
112k
            else
716
112k
            {
717
112k
                val = s[1] | (s[0]<<8);
718
112k
                drop_buffered(instance, 2);
719
112k
            }
720
123k
            code = send_codepoint(instance, val);
721
123k
            if (code < 0) {
722
123k
                if (code != gs_error_NeedInput || n == 0)
723
134
                    return code;
724
123k
            }
725
123k
            break;
726
805k
        case TXT_STATE_ASCII:
727
1.61M
            while (instance->buffered > 0)
728
805k
            {
729
805k
                code = send_codepoint(instance, s[0]);
730
805k
                if (code < 0) {
731
686k
                    if (code != gs_error_NeedInput || n == 0)
732
482
                        return code;
733
686k
                }
734
805k
                drop_buffered(instance, 1);
735
805k
            }
736
805k
            break;
737
805k
        default:
738
0
            return_error(gs_error_Fatal);
739
2.02M
        }
740
2.02M
    }
741
278
    return 0;
742
2.12k
}
743
744
/* Parse an entire random access file */
745
#if 0
746
static int
747
txt_impl_process_file(pl_interp_implementation_t *impl, const char *filename)
748
{
749
    txt_interp_instance_t *instance = impl->interp_client_data;
750
    int code, code1;
751
    gp_file *file;
752
753
    file = gp_fopen(instance->memory, filename, "rb");
754
    if (file == 0)
755
        return_error(gs_error_ioerror);
756
757
    instance->sub = pl_main_get_pcl_instance(instance->memory);
758
759
    code = pl_init_job(instance->sub, instance->device);
760
    if (code >= 0)
761
    {
762
        code = pl_process_file(instance->sub, filename);
763
    }
764
765
    code1 = pl_dnit_job(instance->sub);
766
    if (code >= 0)
767
        code = code1;
768
769
    gp_fclose(file);
770
771
    return code;
772
}
773
#endif
774
775
/* Do any setup for parser per-cursor */
776
static int                      /* ret 0 or +ve if ok, else -ve error code */
777
txt_impl_process_begin(pl_interp_implementation_t * impl)
778
791
{
779
791
    return 0;
780
791
}
781
782
/* Parse a cursor-full of data */
783
static int
784
txt_impl_process(pl_interp_implementation_t *impl, stream_cursor_read *cursor)
785
2.12k
{
786
2.12k
    txt_interp_instance_t *instance = impl->interp_client_data;
787
2.12k
    int avail;
788
2.12k
    int code;
789
790
2.12k
    avail = cursor->limit - cursor->ptr;
791
2.12k
    code = process_block(instance, cursor->ptr + 1, avail);
792
2.12k
    cursor->ptr = cursor->limit;
793
794
2.12k
    return code;
795
2.12k
}
796
797
static int                      /* ret 0 or +ve if ok, else -ve error code */
798
txt_impl_process_end(pl_interp_implementation_t * impl)
799
791
{
800
791
    return 0;
801
791
}
802
803
/* Skip to end of job.
804
 * Return 1 if done, 0 ok but EOJ not found, else negative error code.
805
 */
806
static int
807
txt_impl_flush_to_eoj(pl_interp_implementation_t *impl, stream_cursor_read *pcursor)
808
78
{
809
    /* assume SO files cannot be pjl embedded */
810
78
    pcursor->ptr = pcursor->limit;
811
78
    return 0;
812
78
}
813
814
/* Parser action for end-of-file */
815
static int
816
txt_impl_process_eof(pl_interp_implementation_t *impl)
817
779
{
818
779
    txt_interp_instance_t *instance = impl->interp_client_data;
819
820
779
    if (instance->sub)
821
779
        return pl_process_eof(instance->sub);
822
823
0
    return 0;
824
779
}
825
826
/* Report any errors after running a job */
827
static int
828
txt_impl_report_errors(pl_interp_implementation_t *impl,
829
                       int code,           /* prev termination status */
830
                       long file_position, /* file position of error, -1 if unknown */
831
                       bool force_to_cout  /* force errors to cout */
832
                       )
833
12
{
834
12
    txt_interp_instance_t *instance = impl->interp_client_data;
835
12
    int ret = 0;
836
837
12
    if (instance->sub)
838
12
        ret = pl_report_errors(instance->sub, code, file_position, force_to_cout);
839
840
12
    return ret;
841
12
}
842
843
/* Wrap up interp instance after a "job" */
844
static int
845
txt_impl_dnit_job(pl_interp_implementation_t *impl)
846
791
{
847
791
    txt_interp_instance_t *instance = impl->interp_client_data;
848
791
    int code = 0;
849
850
791
    if (instance->sub)
851
791
        code = pl_dnit_job(instance->sub);
852
791
    instance->sub = NULL;
853
791
    instance->device = NULL;
854
855
791
    return code;
856
791
}
857
858
/* Deallocate a interpreter instance */
859
static int
860
txt_impl_deallocate_interp_instance(pl_interp_implementation_t *impl)
861
16.1k
{
862
16.1k
    txt_interp_instance_t *instance = impl->interp_client_data;
863
864
16.1k
    gs_free_object(instance->memory, instance, "so_impl_deallocate_interp_instance");
865
866
16.1k
    return 0;
867
16.1k
}
868
869
/* Parser implementation descriptor */
870
pl_interp_implementation_t txt_implementation =
871
{
872
    txt_impl_characteristics,
873
    txt_impl_allocate_interp_instance,
874
    NULL,                       /* get_device_memory */
875
    NULL,                       /* set_param */
876
    NULL,                       /* add_path */
877
    NULL,                       /* post_args_init */
878
    txt_impl_init_job,
879
    NULL,                       /* run_prefix_commands */
880
    NULL,                       /* txt_impl_process_file, */
881
    txt_impl_process_begin,
882
    txt_impl_process,
883
    txt_impl_process_end,
884
    txt_impl_flush_to_eoj,
885
    txt_impl_process_eof,
886
    txt_impl_report_errors,
887
    txt_impl_dnit_job,
888
    txt_impl_deallocate_interp_instance,
889
    NULL,
890
};