Coverage Report

Created: 2026-08-08 08:00

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.9k
{
106
28.9k
    int count_controls = 0;
107
28.9k
    int count_hi = 0;
108
28.9k
    int count_tabs = 0;
109
28.9k
    int plausibly_utf8 = 1;
110
28.9k
    int i;
111
112
    /* UTF-8 with a BOM */
113
28.9k
    if (len >= 3 && s[0] == 0xef && s[1] == 0xbb && s[2] == 0xbf)
114
14
        return TXT_UTF8;
115
    /* UTF-16 (little endian) */
116
28.9k
    if (len >= 2 && s[0] == 0xff && s[1] == 0xfe)
117
149
        return TXT_UTF16_LE;
118
    /* UTF-16 (big endian) */
119
28.8k
    if (len >= 2 && s[0] == 0xfe && s[1] == 0xff)
120
206
        return TXT_UTF16_BE;
121
122
    /* Gather some stats. */
123
30.4M
    for (i = 0; i < len; i++)
124
30.4M
    {
125
30.4M
        if (s[i] == 9)
126
119k
        {
127
119k
            count_tabs++;
128
119k
        }
129
30.3M
        else if (s[i] == 12)
130
152k
        {
131
            /* Form feed. We'll let that slide. */
132
152k
        }
133
30.1M
        else if (s[i] == 10)
134
265k
        {
135
265k
           if (i+1 < len && s[i+1] == 13)
136
35.3k
                i++;
137
265k
        }
138
29.9M
        else if (s[i] == 13)
139
455k
        {
140
455k
           if (i+1 < len && s[i+1] == 10)
141
126k
                i++;
142
455k
        }
143
29.4M
        else if (s[i] < 32 || s[i] == 0x7f)
144
6.94M
        {
145
6.94M
            count_controls++;
146
6.94M
        }
147
22.5M
        else if (s[i] < 0x7f)
148
16.4M
        {
149
            /* Seems like a reasonable ASCII value. */
150
16.4M
        }
151
6.04M
        else
152
6.04M
        {
153
6.04M
            count_hi++;
154
6.04M
            if ((s[i] & 0xF8) == 0xF0)
155
321k
            {
156
                /* 3 following bytes */
157
321k
                if (i+1 < len && (s[i+1] & 0xC0) != 0x80)
158
303k
                    plausibly_utf8 = 0;
159
17.5k
                else if (i+2 < len && (s[i+2] & 0xC0) != 0x80)
160
10.1k
                    plausibly_utf8 = 0;
161
7.43k
                else if (i+3 < len && (s[i+3] & 0xC0) != 0x80)
162
3.40k
                    plausibly_utf8 = 0;
163
4.02k
                else
164
4.02k
                    i+=3;
165
321k
            }
166
5.72M
            else if ((s[i] & 0xF0) == 0xE0)
167
407k
            {
168
                /* 2 following bytes */
169
407k
                if (i+1 < len && (s[i+1] & 0xC0) != 0x80)
170
364k
                    plausibly_utf8 = 0;
171
42.3k
                else if (i+2 < len && (s[i+2] & 0xC0) != 0x80)
172
28.1k
                    plausibly_utf8 = 0;
173
14.1k
                else
174
14.1k
                    i+=2;
175
407k
            }
176
5.31M
            else if ((s[i] & 0xE0) == 0xC0)
177
1.56M
            {
178
                /* 1 following bytes */
179
1.56M
                if (i+1 < len && (s[i+1] & 0xC0) != 0x80)
180
1.43M
                    plausibly_utf8 = 0;
181
131k
                else
182
131k
                    i++;
183
1.56M
            }
184
3.74M
            else
185
3.74M
                plausibly_utf8 = 0;
186
6.04M
        }
187
30.4M
    }
188
189
    /* Any (non tab/cr/lf/ff) control characters probably means this isn't text. */
190
28.6k
    if (count_controls > 0)
191
26.4k
        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.55k
        return TXT_UTF8_MAYBE;
195
    /* If we're hitting too many top bit set chars, give up. */
196
611
    if (count_hi > len/10)
197
225
        return TXT_UNKNOWN;
198
199
386
    return TXT_ASCII;
200
611
}
201
202
static int
203
txt_detect_language(const char *t, int len)
204
28.1k
{
205
28.1k
    const unsigned char *s = (const unsigned char *)t;
206
207
28.1k
    switch (identify_from_buffer(s, len))
208
28.1k
    {
209
7
    case TXT_UTF8:
210
85
    case TXT_UTF16_LE:
211
203
    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
203
        return 70;
215
1.06k
    case TXT_UTF8_MAYBE:
216
1.32k
    case TXT_ASCII:
217
1.32k
        return 60;
218
0
    default:
219
26.6k
    case TXT_UNKNOWN:
220
26.6k
        break;
221
28.1k
    }
222
223
26.6k
    return 0;
224
28.1k
}
225
226
static const pl_interp_characteristics_t *
227
txt_impl_characteristics(const pl_interp_implementation_t *pimpl)
228
59.4k
{
229
59.4k
    static pl_interp_characteristics_t txt_characteristics =
230
59.4k
    {
231
59.4k
        "TXT",
232
59.4k
        txt_detect_language,
233
59.4k
    };
234
59.4k
    return &txt_characteristics;
235
59.4k
}
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
781
{
263
781
    txt_interp_instance_t *instance = impl->interp_client_data;
264
265
781
    instance->device = pdevice;
266
781
    instance->state = TXT_STATE_INIT;
267
781
    instance->buffered = 0;
268
781
    instance->detected = TXT_UNDETECTED;
269
781
    instance->just_had_lf = 0;
270
781
    instance->just_had_cr = 0;
271
781
    instance->col = 0;
272
273
781
    instance->sub = pl_main_get_pcl_instance(instance->memory);
274
275
781
    return pl_init_job(instance->sub, instance->device);
276
781
}
277
278
7.00k
#define ESC 27
279
280
static int
281
send_bytes(txt_interp_instance_t *instance, const byte *p, int n)
282
2.31M
{
283
2.31M
    stream_cursor_read cursor;
284
285
#ifdef DEBUG_DUMP_PCL
286
    debug_as_pcl(p, n);
287
#endif
288
289
2.31M
    stream_cursor_read_init(&cursor, p, n);
290
291
2.31M
    return instance->sub->proc_process(instance->sub, &cursor);
292
2.31M
}
293
294
static void
295
drop_buffered(txt_interp_instance_t *instance, int n)
296
1.56M
{
297
1.56M
    assert(instance->buffered >= n);
298
1.56M
    instance->buffered -= n;
299
1.56M
    if (instance->buffered > 0)
300
2.05k
        memmove(instance->buffer, &instance->buffer[n], instance->buffered);
301
1.56M
}
302
303
static int
304
send_pcl_init(txt_interp_instance_t *instance)
305
637
{
306
637
    static byte init[] = {
307
637
            ESC, 'E',                     /* Reset */
308
637
            ESC, '&', 'l', '0', 'O',      /* Orientation */
309
637
            ESC, '&', 'k', '1', '0', 'H', /* Horizontal spacing 10/120 of an inch. */
310
637
            ESC, '&', 'l', '8', 'C',      /* Vertical line spacing 8/48 of an inch. */
311
637
            ESC, '&', 't', '8', '3', 'P', /* &t = double byte parsing, 83 = utf-8, P = ? */
312
637
            ESC, '(', '1', '8', 'N',      /* Primary symbol set = 18N = Unicode */
313
637
            ESC, '(', 's', '0', 'P',      /* Fixed pitch */
314
637
            ESC, '(', 's', '1', '2', 'H', /* Secondary fixed pitch 12cpi */
315
637
            ESC, '(', 's', '8', 'V',      /* Point size 8 */
316
637
            ESC, '(', 's', '3', 'T',      /* Typeface number 3 */
317
637
            ESC, '&', 's', '0', 'C'       /* Wrappity wrap wrap */
318
637
    };
319
320
637
    return send_bytes(instance, init, sizeof(init));
321
637
}
322
323
static int
324
send_urc(txt_interp_instance_t *instance, int n)
325
571
{
326
571
    static byte unicode_replacement_char_as_utf8[] = { 0xe3, 0xbf, 0xbd };
327
328
571
    if (instance->state == TXT_STATE_UTF8_MAYBE)
329
57
    {
330
        /* We were guessing that this was UTF8. Now we know it's not. Drop back to ascii. */
331
57
        instance->state = TXT_STATE_ASCII;
332
57
        return 0;
333
57
    }
334
335
514
    drop_buffered(instance, n);
336
337
514
    instance->sent = 1;
338
514
    return send_bytes(instance, unicode_replacement_char_as_utf8, sizeof(unicode_replacement_char_as_utf8));
339
571
}
340
341
static int
342
send_utf8(txt_interp_instance_t *instance, int val)
343
2.31M
{
344
2.31M
    byte buf[4];
345
2.31M
    int n;
346
347
    /* Finally, send the val! */
348
2.31M
    if (val < 0x80)
349
1.89M
    {
350
1.89M
        buf[0] = val;
351
1.89M
        n = 1;
352
1.89M
    }
353
416k
    else if (val < 0x800)
354
151k
    {
355
151k
        buf[0] = 0xC0 + (val>>6);
356
151k
        buf[1] = 0x80 + (val & 0x3F);
357
151k
        n = 2;
358
151k
    }
359
265k
    else if (val < 0x10000)
360
264k
    {
361
264k
        buf[0] = 0xE0 + (val>>12);
362
264k
        buf[1] = 0x80 + ((val>>6) & 0x3F);
363
264k
        buf[2] = 0x80 + (val & 0x3F);
364
264k
        n = 3;
365
264k
    }
366
623
    else
367
623
    {
368
623
        buf[0] = 0xF0 + (val>>18);
369
623
        buf[1] = 0x80 + ((val>>12) & 0x3F);
370
623
        buf[2] = 0x80 + ((val>>6) & 0x3F);
371
623
        buf[3] = 0x80 + (val & 0x3F);
372
623
        n = 4;
373
623
    }
374
2.31M
    return send_bytes(instance, buf, n);
375
2.31M
}
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.56M
{
382
1.56M
    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.56M
    instance->sent = 1;
389
    /* Tidy up whatever mess of CR/LF we are passed. */
390
1.56M
    if (val == '\r')
391
62.5k
    {
392
        /* If we've got a CR and we've just had a LF, swallow this. */
393
62.5k
        if (instance->just_had_lf)
394
19.8k
        {
395
19.8k
            instance->just_had_lf = 0;
396
19.8k
            return 0;
397
19.8k
        }
398
42.7k
        instance->just_had_cr = 1;
399
42.7k
        val = '\n';
400
42.7k
    }
401
1.50M
    else if (val == '\n')
402
67.6k
    {
403
        /* If we've got a LF and we've just had a CR, swallow this. */
404
67.6k
        if (instance->just_had_cr)
405
40.1k
        {
406
40.1k
            instance->just_had_cr = 0;
407
40.1k
            return 0;
408
40.1k
        }
409
27.5k
        instance->just_had_lf = 1;
410
27.5k
    }
411
1.43M
    else
412
1.43M
    {
413
1.43M
        instance->just_had_cr = 0;
414
1.43M
        instance->just_had_lf = 0;
415
1.43M
    }
416
417
    /* Keep track of what column we're at to so we can do tab handling. */
418
1.50M
    if (val == '\n')
419
70.2k
    {
420
70.2k
        instance->col = 0;
421
70.2k
        code = send_utf8(instance, '\n');
422
70.2k
        if (code < 0 && code != gs_error_NeedInput)
423
0
            return code;
424
70.2k
        return send_utf8(instance, '\r');
425
70.2k
    }
426
1.43M
    if (val == '\t')
427
107k
    {
428
107k
        int spaces = 8 - (instance->col & 7);
429
951k
        while (spaces--)
430
844k
        {
431
844k
            int code = send_utf8(instance, ' ');
432
844k
            if (code < 0 && code != gs_error_NeedInput)
433
0
                return code;
434
844k
            instance->col++;
435
844k
        }
436
107k
        return 0;
437
107k
    }
438
1.33M
    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.33M
    return send_utf8(instance, val);
455
1.43M
}
456
457
static int
458
process_block(txt_interp_instance_t *instance, const byte *ptr, int n)
459
2.05k
{
460
2.05k
    int code;
461
2.05k
    byte *s = &instance->buffer[0];
462
2.05k
    int old_state = instance->state;
463
2.05k
    int val;
464
465
2.05k
    if (instance->detected == TXT_UNDETECTED)
466
781
    {
467
781
        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
781
        if (instance->detected == TXT_ASCII)
471
127
            instance->state = TXT_STATE_ASCII;
472
781
    }
473
474
2.05k
    instance->sent = 0;
475
1.92M
    while (n)
476
1.92M
    {
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
1.92M
        if (instance->state == old_state && (!instance->sent || instance->buffered == 0))
483
1.92M
        {
484
1.92M
            assert(instance->buffered < 4);
485
1.92M
            s[instance->buffered++] = *ptr++;
486
1.92M
            n--;
487
1.92M
        }
488
1.92M
        old_state = instance->state;
489
490
1.92M
        instance->sent = 0;
491
1.92M
        switch (instance->state)
492
1.92M
        {
493
1.77k
        case TXT_STATE_INIT:
494
495
1.77k
            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.76k
            else if (instance->buffered == 2 && s[0] == 0xff && s[1] == 0xfe)
501
71
            {
502
71
                instance->state = TXT_STATE_UTF16_LE;
503
71
                drop_buffered(instance, 2);
504
71
            }
505
1.69k
            else if (instance->buffered == 2 && s[0] == 0xfe && s[1] == 0xff)
506
88
            {
507
88
                instance->state = TXT_STATE_UTF16_BE;
508
88
                drop_buffered(instance, 2);
509
88
            }
510
1.60k
            else if (instance->buffered >= 3)
511
471
            {
512
                /* We haven't found a BOM, try for utf8. */
513
471
                instance->state = TXT_STATE_UTF8_MAYBE;
514
471
            }
515
516
            /* If we've recognised the BOM, then send the init string. */
517
1.77k
            if (instance->state != TXT_STATE_INIT)
518
637
            {
519
637
                code = send_pcl_init(instance);
520
637
                if (code < 0) {
521
637
                    if (code != gs_error_NeedInput || n == 0)
522
3
                        return code;
523
637
                }
524
637
            }
525
1.76k
            break;
526
1.76k
        case TXT_STATE_UTF8:
527
495k
        case TXT_STATE_UTF8_MAYBE:
528
495k
            if ((s[0] & 0xF8) == 0xF0)
529
2.49k
            {
530
                /* 3 following bytes */
531
2.49k
                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.48k
                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.48k
                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.48k
                else if (instance->buffered == 4)
556
623
                {
557
                    /* Valid encoding of 4 bytes */
558
623
                    val = ((s[0] & 0x7)<<18) | ((s[1] & 0x3f)<<12) | ((s[2] & 0x3f)<<6) |  (s[3] & 0x3f);
559
623
                    drop_buffered(instance, 4);
560
623
                    code = send_codepoint(instance, val);
561
623
                    if (code < 0) {
562
623
                        if (code != gs_error_NeedInput || n == 0)
563
17
                            return code;
564
623
                    }
565
623
                }
566
1.86k
                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.49k
            }
572
493k
            else if ((s[0] & 0xF0) == 0xE0)
573
3.65k
            {
574
                /* 2 following bytes */
575
3.65k
                if (instance->buffered >= 2 && (s[1] & 0xC0) != 0x80)
576
6
                {
577
6
                    code = send_urc(instance, 1);
578
6
                    if (code < 0) {
579
0
                        if (code != gs_error_NeedInput || n == 0)
580
0
                            return code;
581
0
                    }
582
6
                }
583
3.64k
                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.64k
                else if (instance->buffered == 3)
592
1.22k
                {
593
                    /* Valid encoding of 3 bytes */
594
1.22k
                    val = ((s[0] & 0xF)<<12) | ((s[1] & 0x3f)<<6) | (s[2] & 0x3f);
595
1.22k
                    drop_buffered(instance, 3);
596
1.22k
                    code = send_codepoint(instance, val);
597
1.22k
                    if (code < 0) {
598
1.22k
                        if (code != gs_error_NeedInput || n == 0)
599
18
                            return code;
600
1.22k
                    }
601
1.22k
                }
602
2.42k
                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.65k
            }
608
489k
            else if ((s[0] & 0xE0) == 0xC0)
609
2.85k
            {
610
                /* 1 following bytes */
611
2.85k
                if (instance->buffered >= 2 && (s[1] & 0xC0) != 0x80)
612
6
                {
613
6
                    code = send_urc(instance, 1);
614
6
                    if (code < 0) {
615
0
                        if (code != gs_error_NeedInput || n == 0)
616
0
                            return code;
617
0
                    }
618
6
                }
619
2.85k
                else if (instance->buffered == 2)
620
1.42k
                {
621
                    /* Valid encoding of 2 bytes */
622
1.42k
                    val = ((s[0] & 0x1F)<<6) | (s[1] & 0x3f);
623
1.42k
                    drop_buffered(instance, 2);
624
1.42k
                    code = send_codepoint(instance, val);
625
1.42k
                    if (code < 0) {
626
1.42k
                        if (code != gs_error_NeedInput || n == 0)
627
10
                            return code;
628
1.42k
                    }
629
1.42k
                }
630
1.43k
                else if (instance->buffered != 1)
631
6
                {
632
                    /* Should never happen. */
633
6
                    return_error(gs_error_Fatal);
634
6
                }
635
2.85k
            }
636
486k
            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
486k
            else if (s[0] < 0x80)
646
486k
            {
647
                /* Simple byte. */
648
486k
                val = s[0];
649
486k
                drop_buffered(instance, 1);
650
486k
                code = send_codepoint(instance, val);
651
486k
                if (code < 0) {
652
435k
                    if (code != gs_error_NeedInput || n == 0)
653
466
                        return code;
654
435k
                }
655
486k
            }
656
31
            else
657
31
            {
658
                /* Bytes we should never see in a UTF-8 file! (0xf8-0xff) */
659
31
                code = send_urc(instance, 1);
660
31
                if (code < 0) {
661
0
                    if (code != gs_error_NeedInput || n == 0)
662
0
                        return code;
663
0
                }
664
31
            }
665
495k
            break;
666
495k
        case TXT_STATE_UTF16_LE:
667
417k
            if (instance->buffered < 2)
668
208k
                break;
669
208k
            if (s[1] >= 0xD8 && s[1] < 0xDC)
670
909
            {
671
                /* High surrogate */
672
909
                if (instance->buffered < 4)
673
603
                    break;
674
306
                if (s[3] < 0xDC || s[3] > 0xDF)
675
249
                {
676
                    /* Not followed by a low surrogate! Ignore the high surrogate. */
677
249
                    code = send_urc(instance, 2);
678
249
                    if (code < 0)
679
249
                        return code;
680
0
                    break;
681
249
                }
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
208k
            else
686
208k
            {
687
208k
                val = s[0] | (s[1]<<8);
688
208k
                drop_buffered(instance, 2);
689
208k
            }
690
208k
            code = send_codepoint(instance, val);
691
208k
            if (code < 0) {
692
207k
                if (code != gs_error_NeedInput || n == 0)
693
166
                    return code;
694
207k
            }
695
207k
            break;
696
267k
        case TXT_STATE_UTF16_BE:
697
267k
            if (instance->buffered < 2)
698
122k
                break;
699
145k
            if (s[0] >= 0xD8 && s[0] < 0xDC)
700
33.5k
            {
701
                /* High surrogate */
702
33.5k
                if (instance->buffered < 4)
703
22.3k
                    break;
704
11.2k
                if (s[2] < 0xDC || s[2] > 0xDF)
705
265
                {
706
                    /* Not followed by a low surrogate! Ignore the high surrogate. */
707
265
                    code = send_urc(instance, 2);
708
265
                    if (code < 0)
709
265
                        return code;
710
0
                    break;
711
265
                }
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
111k
            else
716
111k
            {
717
111k
                val = s[1] | (s[0]<<8);
718
111k
                drop_buffered(instance, 2);
719
111k
            }
720
122k
            code = send_codepoint(instance, val);
721
122k
            if (code < 0) {
722
122k
                if (code != gs_error_NeedInput || n == 0)
723
134
                    return code;
724
122k
            }
725
122k
            break;
726
747k
        case TXT_STATE_ASCII:
727
1.49M
            while (instance->buffered > 0)
728
747k
            {
729
747k
                code = send_codepoint(instance, s[0]);
730
747k
                if (code < 0) {
731
631k
                    if (code != gs_error_NeedInput || n == 0)
732
450
                        return code;
733
631k
                }
734
747k
                drop_buffered(instance, 1);
735
747k
            }
736
746k
            break;
737
746k
        default:
738
0
            return_error(gs_error_Fatal);
739
1.92M
        }
740
1.92M
    }
741
264
    return 0;
742
2.05k
}
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
781
{
779
781
    return 0;
780
781
}
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.05k
{
786
2.05k
    txt_interp_instance_t *instance = impl->interp_client_data;
787
2.05k
    int avail;
788
2.05k
    int code;
789
790
2.05k
    avail = cursor->limit - cursor->ptr;
791
2.05k
    code = process_block(instance, cursor->ptr + 1, avail);
792
2.05k
    cursor->ptr = cursor->limit;
793
794
2.05k
    return code;
795
2.05k
}
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
781
{
800
781
    return 0;
801
781
}
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
79
{
809
    /* assume SO files cannot be pjl embedded */
810
79
    pcursor->ptr = pcursor->limit;
811
79
    return 0;
812
79
}
813
814
/* Parser action for end-of-file */
815
static int
816
txt_impl_process_eof(pl_interp_implementation_t *impl)
817
768
{
818
768
    txt_interp_instance_t *instance = impl->interp_client_data;
819
820
768
    if (instance->sub)
821
768
        return pl_process_eof(instance->sub);
822
823
0
    return 0;
824
768
}
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
13
{
834
13
    txt_interp_instance_t *instance = impl->interp_client_data;
835
13
    int ret = 0;
836
837
13
    if (instance->sub)
838
13
        ret = pl_report_errors(instance->sub, code, file_position, force_to_cout);
839
840
13
    return ret;
841
13
}
842
843
/* Wrap up interp instance after a "job" */
844
static int
845
txt_impl_dnit_job(pl_interp_implementation_t *impl)
846
781
{
847
781
    txt_interp_instance_t *instance = impl->interp_client_data;
848
781
    int code = 0;
849
850
781
    if (instance->sub)
851
781
        code = pl_dnit_job(instance->sub);
852
781
    instance->sub = NULL;
853
781
    instance->device = NULL;
854
855
781
    return code;
856
781
}
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
};