Coverage Report

Created: 2026-10-28 08:05

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
32.1k
{
106
32.1k
    int count_controls = 0;
107
32.1k
    int count_hi = 0;
108
32.1k
    int count_tabs = 0;
109
32.1k
    int plausibly_utf8 = 1;
110
32.1k
    int i;
111
112
    /* UTF-8 with a BOM */
113
32.1k
    if (len >= 3 && s[0] == 0xef && s[1] == 0xbb && s[2] == 0xbf)
114
21
        return TXT_UTF8;
115
    /* UTF-16 (little endian) */
116
32.0k
    if (len >= 2 && s[0] == 0xff && s[1] == 0xfe)
117
195
        return TXT_UTF16_LE;
118
    /* UTF-16 (big endian) */
119
31.9k
    if (len >= 2 && s[0] == 0xfe && s[1] == 0xff)
120
218
        return TXT_UTF16_BE;
121
122
    /* Gather some stats. */
123
37.0M
    for (i = 0; i < len; i++)
124
37.0M
    {
125
37.0M
        if (s[i] == 9)
126
128k
        {
127
128k
            count_tabs++;
128
128k
        }
129
36.8M
        else if (s[i] == 12)
130
167k
        {
131
            /* Form feed. We'll let that slide. */
132
167k
        }
133
36.7M
        else if (s[i] == 10)
134
329k
        {
135
329k
           if (i+1 < len && s[i+1] == 13)
136
37.5k
                i++;
137
329k
        }
138
36.3M
        else if (s[i] == 13)
139
1.13M
        {
140
1.13M
           if (i+1 < len && s[i+1] == 10)
141
152k
                i++;
142
1.13M
        }
143
35.2M
        else if (s[i] < 32 || s[i] == 0x7f)
144
7.61M
        {
145
7.61M
            count_controls++;
146
7.61M
        }
147
27.6M
        else if (s[i] < 0x7f)
148
20.7M
        {
149
            /* Seems like a reasonable ASCII value. */
150
20.7M
        }
151
6.86M
        else
152
6.86M
        {
153
6.86M
            count_hi++;
154
6.86M
            if ((s[i] & 0xF8) == 0xF0)
155
347k
            {
156
                /* 3 following bytes */
157
347k
                if (i+1 < len && (s[i+1] & 0xC0) != 0x80)
158
327k
                    plausibly_utf8 = 0;
159
19.8k
                else if (i+2 < len && (s[i+2] & 0xC0) != 0x80)
160
10.8k
                    plausibly_utf8 = 0;
161
8.95k
                else if (i+3 < len && (s[i+3] & 0xC0) != 0x80)
162
3.55k
                    plausibly_utf8 = 0;
163
5.40k
                else
164
5.40k
                    i+=3;
165
347k
            }
166
6.52M
            else if ((s[i] & 0xF0) == 0xE0)
167
504k
            {
168
                /* 2 following bytes */
169
504k
                if (i+1 < len && (s[i+1] & 0xC0) != 0x80)
170
456k
                    plausibly_utf8 = 0;
171
48.0k
                else if (i+2 < len && (s[i+2] & 0xC0) != 0x80)
172
30.0k
                    plausibly_utf8 = 0;
173
18.0k
                else
174
18.0k
                    i+=2;
175
504k
            }
176
6.01M
            else if ((s[i] & 0xE0) == 0xC0)
177
1.78M
            {
178
                /* 1 following bytes */
179
1.78M
                if (i+1 < len && (s[i+1] & 0xC0) != 0x80)
180
1.62M
                    plausibly_utf8 = 0;
181
159k
                else
182
159k
                    i++;
183
1.78M
            }
184
4.22M
            else
185
4.22M
                plausibly_utf8 = 0;
186
6.86M
        }
187
37.0M
    }
188
189
    /* Any (non tab/cr/lf/ff) control characters probably means this isn't text. */
190
31.6k
    if (count_controls > 0)
191
29.2k
        return TXT_UNKNOWN;
192
    /* If we've managed to decode all that as utf8 without problem, it's probably text. */
193
2.47k
    if (plausibly_utf8)
194
1.76k
        return TXT_UTF8_MAYBE;
195
    /* If we're hitting too many top bit set chars, give up. */
196
714
    if (count_hi > len/10)
197
260
        return TXT_UNKNOWN;
198
199
454
    return TXT_ASCII;
200
714
}
201
202
static int
203
txt_detect_language(const char *t, int len)
204
31.1k
{
205
31.1k
    const unsigned char *s = (const unsigned char *)t;
206
207
31.1k
    switch (identify_from_buffer(s, len))
208
31.1k
    {
209
11
    case TXT_UTF8:
210
111
    case TXT_UTF16_LE:
211
232
    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
232
        return 70;
215
1.17k
    case TXT_UTF8_MAYBE:
216
1.48k
    case TXT_ASCII:
217
1.48k
        return 60;
218
0
    default:
219
29.4k
    case TXT_UNKNOWN:
220
29.4k
        break;
221
31.1k
    }
222
223
29.4k
    return 0;
224
31.1k
}
225
226
static const pl_interp_characteristics_t *
227
txt_impl_characteristics(const pl_interp_implementation_t *pimpl)
228
66.0k
{
229
66.0k
    static pl_interp_characteristics_t txt_characteristics =
230
66.0k
    {
231
66.0k
        "TXT",
232
66.0k
        txt_detect_language,
233
66.0k
    };
234
66.0k
    return &txt_characteristics;
235
66.0k
}
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.0k
{
242
16.0k
    txt_interp_instance_t *instance;
243
244
16.0k
    instance = (txt_interp_instance_t *) gs_alloc_bytes(pmem,
245
16.0k
            sizeof(txt_interp_instance_t), "txt_impl_allocate_interp_instance");
246
247
16.0k
    if (!instance)
248
0
        return_error(gs_error_VMerror);
249
250
16.0k
    instance->memory = pmem;
251
16.0k
    instance->sub = NULL;
252
253
16.0k
    impl->interp_client_data = instance;
254
255
16.0k
    return 0;
256
16.0k
}
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
930
{
263
930
    txt_interp_instance_t *instance = impl->interp_client_data;
264
265
930
    instance->device = pdevice;
266
930
    instance->state = TXT_STATE_INIT;
267
930
    instance->buffered = 0;
268
930
    instance->detected = TXT_UNDETECTED;
269
930
    instance->just_had_lf = 0;
270
930
    instance->just_had_cr = 0;
271
930
    instance->col = 0;
272
273
930
    instance->sub = pl_main_get_pcl_instance(instance->memory);
274
275
930
    return pl_init_job(instance->sub, instance->device);
276
930
}
277
278
8.40k
#define ESC 27
279
280
static int
281
send_bytes(txt_interp_instance_t *instance, const byte *p, int n)
282
2.80M
{
283
2.80M
    stream_cursor_read cursor;
284
285
#ifdef DEBUG_DUMP_PCL
286
    debug_as_pcl(p, n);
287
#endif
288
289
2.80M
    stream_cursor_read_init(&cursor, p, n);
290
291
2.80M
    return instance->sub->proc_process(instance->sub, &cursor);
292
2.80M
}
293
294
static void
295
drop_buffered(txt_interp_instance_t *instance, int n)
296
2.02M
{
297
2.02M
    assert(instance->buffered >= n);
298
2.02M
    instance->buffered -= n;
299
2.02M
    if (instance->buffered > 0)
300
2.27k
        memmove(instance->buffer, &instance->buffer[n], instance->buffered);
301
2.02M
}
302
303
static int
304
send_pcl_init(txt_interp_instance_t *instance)
305
764
{
306
764
    static byte init[] = {
307
764
            ESC, 'E',                     /* Reset */
308
764
            ESC, '&', 'l', '0', 'O',      /* Orientation */
309
764
            ESC, '&', 'k', '1', '0', 'H', /* Horizontal spacing 10/120 of an inch. */
310
764
            ESC, '&', 'l', '8', 'C',      /* Vertical line spacing 8/48 of an inch. */
311
764
            ESC, '&', 't', '8', '3', 'P', /* &t = double byte parsing, 83 = utf-8, P = ? */
312
764
            ESC, '(', '1', '8', 'N',      /* Primary symbol set = 18N = Unicode */
313
764
            ESC, '(', 's', '0', 'P',      /* Fixed pitch */
314
764
            ESC, '(', 's', '1', '2', 'H', /* Secondary fixed pitch 12cpi */
315
764
            ESC, '(', 's', '8', 'V',      /* Point size 8 */
316
764
            ESC, '(', 's', '3', 'T',      /* Typeface number 3 */
317
764
            ESC, '&', 's', '0', 'C'       /* Wrappity wrap wrap */
318
764
    };
319
320
764
    return send_bytes(instance, init, sizeof(init));
321
764
}
322
323
static int
324
send_urc(txt_interp_instance_t *instance, int n)
325
597
{
326
597
    static byte unicode_replacement_char_as_utf8[] = { 0xe3, 0xbf, 0xbd };
327
328
597
    if (instance->state == TXT_STATE_UTF8_MAYBE)
329
70
    {
330
        /* We were guessing that this was UTF8. Now we know it's not. Drop back to ascii. */
331
70
        instance->state = TXT_STATE_ASCII;
332
70
        return 0;
333
70
    }
334
335
527
    drop_buffered(instance, n);
336
337
527
    instance->sent = 1;
338
527
    return send_bytes(instance, unicode_replacement_char_as_utf8, sizeof(unicode_replacement_char_as_utf8));
339
597
}
340
341
static int
342
send_utf8(txt_interp_instance_t *instance, int val)
343
2.80M
{
344
2.80M
    byte buf[4];
345
2.80M
    int n;
346
347
    /* Finally, send the val! */
348
2.80M
    if (val < 0x80)
349
2.25M
    {
350
2.25M
        buf[0] = val;
351
2.25M
        n = 1;
352
2.25M
    }
353
546k
    else if (val < 0x800)
354
129k
    {
355
129k
        buf[0] = 0xC0 + (val>>6);
356
129k
        buf[1] = 0x80 + (val & 0x3F);
357
129k
        n = 2;
358
129k
    }
359
416k
    else if (val < 0x10000)
360
398k
    {
361
398k
        buf[0] = 0xE0 + (val>>12);
362
398k
        buf[1] = 0x80 + ((val>>6) & 0x3F);
363
398k
        buf[2] = 0x80 + (val & 0x3F);
364
398k
        n = 3;
365
398k
    }
366
17.5k
    else
367
17.5k
    {
368
17.5k
        buf[0] = 0xF0 + (val>>18);
369
17.5k
        buf[1] = 0x80 + ((val>>12) & 0x3F);
370
17.5k
        buf[2] = 0x80 + ((val>>6) & 0x3F);
371
17.5k
        buf[3] = 0x80 + (val & 0x3F);
372
17.5k
        n = 4;
373
17.5k
    }
374
2.80M
    return send_bytes(instance, buf, n);
375
2.80M
}
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
2.02M
{
382
2.02M
    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
2.02M
    instance->sent = 1;
389
    /* Tidy up whatever mess of CR/LF we are passed. */
390
2.02M
    if (val == '\r')
391
54.2k
    {
392
        /* If we've got a CR and we've just had a LF, swallow this. */
393
54.2k
        if (instance->just_had_lf)
394
24.3k
        {
395
24.3k
            instance->just_had_lf = 0;
396
24.3k
            return 0;
397
24.3k
        }
398
29.8k
        instance->just_had_cr = 1;
399
29.8k
        val = '\n';
400
29.8k
    }
401
1.97M
    else if (val == '\n')
402
59.3k
    {
403
        /* If we've got a LF and we've just had a CR, swallow this. */
404
59.3k
        if (instance->just_had_cr)
405
16.5k
        {
406
16.5k
            instance->just_had_cr = 0;
407
16.5k
            return 0;
408
16.5k
        }
409
42.8k
        instance->just_had_lf = 1;
410
42.8k
    }
411
1.91M
    else
412
1.91M
    {
413
1.91M
        instance->just_had_cr = 0;
414
1.91M
        instance->just_had_lf = 0;
415
1.91M
    }
416
417
    /* Keep track of what column we're at to so we can do tab handling. */
418
1.98M
    if (val == '\n')
419
72.6k
    {
420
72.6k
        instance->col = 0;
421
72.6k
        code = send_utf8(instance, '\n');
422
72.6k
        if (code < 0 && code != gs_error_NeedInput)
423
0
            return code;
424
72.6k
        return send_utf8(instance, '\r');
425
72.6k
    }
426
1.91M
    if (val == '\t')
427
108k
    {
428
108k
        int spaces = 8 - (instance->col & 7);
429
958k
        while (spaces--)
430
850k
        {
431
850k
            int code = send_utf8(instance, ' ');
432
850k
            if (code < 0 && code != gs_error_NeedInput)
433
0
                return code;
434
850k
            instance->col++;
435
850k
        }
436
108k
        return 0;
437
108k
    }
438
1.80M
    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.80M
    return send_utf8(instance, val);
455
1.91M
}
456
457
static int
458
process_block(txt_interp_instance_t *instance, const byte *ptr, int n)
459
2.60k
{
460
2.60k
    int code;
461
2.60k
    byte *s = &instance->buffer[0];
462
2.60k
    int old_state = instance->state;
463
2.60k
    int val;
464
465
2.60k
    if (instance->detected == TXT_UNDETECTED)
466
930
    {
467
930
        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
930
        if (instance->detected == TXT_ASCII)
471
147
            instance->state = TXT_STATE_ASCII;
472
930
    }
473
474
2.60k
    instance->sent = 0;
475
2.73M
    while (n)
476
2.73M
    {
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.73M
        if (instance->state == old_state && (!instance->sent || instance->buffered == 0))
483
2.72M
        {
484
2.72M
            assert(instance->buffered < 4);
485
2.72M
            s[instance->buffered++] = *ptr++;
486
2.72M
            n--;
487
2.72M
        }
488
2.73M
        old_state = instance->state;
489
490
2.73M
        instance->sent = 0;
491
2.73M
        switch (instance->state)
492
2.73M
        {
493
2.12k
        case TXT_STATE_INIT:
494
495
2.12k
            if (instance->buffered == 3 && s[0] == 0xef && s[1] == 0xbb && s[2] == 0xbf)
496
10
            {
497
10
                instance->state = TXT_STATE_UTF8;
498
10
                drop_buffered(instance, 3);
499
10
            }
500
2.11k
            else if (instance->buffered == 2 && s[0] == 0xff && s[1] == 0xfe)
501
95
            {
502
95
                instance->state = TXT_STATE_UTF16_LE;
503
95
                drop_buffered(instance, 2);
504
95
            }
505
2.01k
            else if (instance->buffered == 2 && s[0] == 0xfe && s[1] == 0xff)
506
97
            {
507
97
                instance->state = TXT_STATE_UTF16_BE;
508
97
                drop_buffered(instance, 2);
509
97
            }
510
1.92k
            else if (instance->buffered >= 3)
511
562
            {
512
                /* We haven't found a BOM, try for utf8. */
513
562
                instance->state = TXT_STATE_UTF8_MAYBE;
514
562
            }
515
516
            /* If we've recognised the BOM, then send the init string. */
517
2.12k
            if (instance->state != TXT_STATE_INIT)
518
764
            {
519
764
                code = send_pcl_init(instance);
520
764
                if (code < 0) {
521
764
                    if (code != gs_error_NeedInput || n == 0)
522
3
                        return code;
523
764
                }
524
764
            }
525
2.12k
            break;
526
2.12k
        case TXT_STATE_UTF8:
527
968k
        case TXT_STATE_UTF8_MAYBE:
528
968k
            if ((s[0] & 0xF8) == 0xF0)
529
70.1k
            {
530
                /* 3 following bytes */
531
70.1k
                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
70.1k
                else if (instance->buffered >= 3 && (s[2] & 0xC0) != 0x80)
540
1
                {
541
1
                    code = send_urc(instance, 2);
542
1
                    if (code < 0) {
543
0
                        if (code != gs_error_NeedInput || n == 0)
544
0
                            return code;
545
0
                    }
546
1
                }
547
70.1k
                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
70.1k
                else if (instance->buffered == 4)
556
17.5k
                {
557
                    /* Valid encoding of 4 bytes */
558
17.5k
                    val = ((s[0] & 0x7)<<18) | ((s[1] & 0x3f)<<12) | ((s[2] & 0x3f)<<6) |  (s[3] & 0x3f);
559
17.5k
                    drop_buffered(instance, 4);
560
17.5k
                    code = send_codepoint(instance, val);
561
17.5k
                    if (code < 0) {
562
17.5k
                        if (code != gs_error_NeedInput || n == 0)
563
34
                            return code;
564
17.5k
                    }
565
17.5k
                }
566
52.5k
                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
70.1k
            }
572
898k
            else if ((s[0] & 0xF0) == 0xE0)
573
116k
            {
574
                /* 2 following bytes */
575
116k
                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
116k
                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
116k
                else if (instance->buffered == 3)
592
38.7k
                {
593
                    /* Valid encoding of 3 bytes */
594
38.7k
                    val = ((s[0] & 0xF)<<12) | ((s[1] & 0x3f)<<6) | (s[2] & 0x3f);
595
38.7k
                    drop_buffered(instance, 3);
596
38.7k
                    code = send_codepoint(instance, val);
597
38.7k
                    if (code < 0) {
598
38.7k
                        if (code != gs_error_NeedInput || n == 0)
599
37
                            return code;
600
38.7k
                    }
601
38.7k
                }
602
77.5k
                else if (instance->buffered != 1 && instance->buffered != 2)
603
10
                {
604
                    /* Should never happen. */
605
10
                    return_error(gs_error_Fatal);
606
10
                }
607
116k
            }
608
781k
            else if ((s[0] & 0xE0) == 0xC0)
609
55.2k
            {
610
                /* 1 following bytes */
611
55.2k
                if (instance->buffered >= 2 && (s[1] & 0xC0) != 0x80)
612
12
                {
613
12
                    code = send_urc(instance, 1);
614
12
                    if (code < 0) {
615
0
                        if (code != gs_error_NeedInput || n == 0)
616
0
                            return code;
617
0
                    }
618
12
                }
619
55.2k
                else if (instance->buffered == 2)
620
27.6k
                {
621
                    /* Valid encoding of 2 bytes */
622
27.6k
                    val = ((s[0] & 0x1F)<<6) | (s[1] & 0x3f);
623
27.6k
                    drop_buffered(instance, 2);
624
27.6k
                    code = send_codepoint(instance, val);
625
27.6k
                    if (code < 0) {
626
27.6k
                        if (code != gs_error_NeedInput || n == 0)
627
48
                            return code;
628
27.6k
                    }
629
27.6k
                }
630
27.6k
                else if (instance->buffered != 1)
631
4
                {
632
                    /* Should never happen. */
633
4
                    return_error(gs_error_Fatal);
634
4
                }
635
55.2k
            }
636
726k
            else if ((s[0] & 0xC0) == 0x80)
637
5
            {
638
                /* A continuation byte at the start. Should never see this. */
639
5
                code = send_urc(instance, 1);
640
5
                if (code < 0) {
641
0
                    if (code != gs_error_NeedInput || n == 0)
642
0
                        return code;
643
0
                }
644
5
            }
645
726k
            else if (s[0] < 0x80)
646
726k
            {
647
                /* Simple byte. */
648
726k
                val = s[0];
649
726k
                drop_buffered(instance, 1);
650
726k
                code = send_codepoint(instance, val);
651
726k
                if (code < 0) {
652
679k
                    if (code != gs_error_NeedInput || n == 0)
653
637
                        return code;
654
679k
                }
655
726k
            }
656
41
            else
657
41
            {
658
                /* Bytes we should never see in a UTF-8 file! (0xf8-0xff) */
659
41
                code = send_urc(instance, 1);
660
41
                if (code < 0) {
661
0
                    if (code != gs_error_NeedInput || n == 0)
662
0
                        return code;
663
0
                }
664
41
            }
665
967k
            break;
666
967k
        case TXT_STATE_UTF16_LE:
667
579k
            if (instance->buffered < 2)
668
255k
                break;
669
323k
            if (s[1] >= 0xD8 && s[1] < 0xDC)
670
100k
            {
671
                /* High surrogate */
672
100k
                if (instance->buffered < 4)
673
67.1k
                    break;
674
33.5k
                if (s[3] < 0xDC || s[3] > 0xDF)
675
266
                {
676
                    /* Not followed by a low surrogate! Ignore the high surrogate. */
677
266
                    code = send_urc(instance, 2);
678
266
                    if (code < 0)
679
266
                        return code;
680
0
                    break;
681
266
                }
682
33.3k
                val = (((s[0] | (s[1]<<8)) - 0xdc00)<<10) + (s[2] | (s[3]<<8)) - 0xdc00 + 0x10000;
683
33.3k
                drop_buffered(instance, 4);
684
33.3k
            }
685
222k
            else
686
222k
            {
687
222k
                val = s[0] | (s[1]<<8);
688
222k
                drop_buffered(instance, 2);
689
222k
            }
690
255k
            code = send_codepoint(instance, val);
691
255k
            if (code < 0) {
692
255k
                if (code != gs_error_NeedInput || n == 0)
693
213
                    return code;
694
255k
            }
695
255k
            break;
696
396k
        case TXT_STATE_UTF16_BE:
697
396k
            if (instance->buffered < 2)
698
176k
                break;
699
219k
            if (s[0] >= 0xD8 && s[0] < 0xDC)
700
64.2k
            {
701
                /* High surrogate */
702
64.2k
                if (instance->buffered < 4)
703
42.8k
                    break;
704
21.4k
                if (s[2] < 0xDC || s[2] > 0xDF)
705
261
                {
706
                    /* Not followed by a low surrogate! Ignore the high surrogate. */
707
261
                    code = send_urc(instance, 2);
708
261
                    if (code < 0)
709
261
                        return code;
710
0
                    break;
711
261
                }
712
21.1k
                val = (((s[1] | (s[0]<<8)) - 0xdc00)<<10) + (s[3] | (s[2]<<8)) - 0xdc00 + 0x10000;
713
21.1k
                drop_buffered(instance, 4);
714
21.1k
            }
715
155k
            else
716
155k
            {
717
155k
                val = s[1] | (s[0]<<8);
718
155k
                drop_buffered(instance, 2);
719
155k
            }
720
176k
            code = send_codepoint(instance, val);
721
176k
            if (code < 0) {
722
176k
                if (code != gs_error_NeedInput || n == 0)
723
189
                    return code;
724
176k
            }
725
176k
            break;
726
785k
        case TXT_STATE_ASCII:
727
1.57M
            while (instance->buffered > 0)
728
785k
            {
729
785k
                code = send_codepoint(instance, s[0]);
730
785k
                if (code < 0) {
731
683k
                    if (code != gs_error_NeedInput || n == 0)
732
504
                        return code;
733
683k
                }
734
785k
                drop_buffered(instance, 1);
735
785k
            }
736
784k
            break;
737
784k
        default:
738
0
            return_error(gs_error_Fatal);
739
2.73M
        }
740
2.73M
    }
741
394
    return 0;
742
2.60k
}
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
930
{
779
930
    return 0;
780
930
}
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.60k
{
786
2.60k
    txt_interp_instance_t *instance = impl->interp_client_data;
787
2.60k
    int avail;
788
2.60k
    int code;
789
790
2.60k
    avail = cursor->limit - cursor->ptr;
791
2.60k
    code = process_block(instance, cursor->ptr + 1, avail);
792
2.60k
    cursor->ptr = cursor->limit;
793
794
2.60k
    return code;
795
2.60k
}
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
930
{
800
930
    return 0;
801
930
}
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
87
{
809
    /* assume SO files cannot be pjl embedded */
810
87
    pcursor->ptr = pcursor->limit;
811
87
    return 0;
812
87
}
813
814
/* Parser action for end-of-file */
815
static int
816
txt_impl_process_eof(pl_interp_implementation_t *impl)
817
916
{
818
916
    txt_interp_instance_t *instance = impl->interp_client_data;
819
820
916
    if (instance->sub)
821
916
        return pl_process_eof(instance->sub);
822
823
0
    return 0;
824
916
}
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
14
{
834
14
    txt_interp_instance_t *instance = impl->interp_client_data;
835
14
    int ret = 0;
836
837
14
    if (instance->sub)
838
14
        ret = pl_report_errors(instance->sub, code, file_position, force_to_cout);
839
840
14
    return ret;
841
14
}
842
843
/* Wrap up interp instance after a "job" */
844
static int
845
txt_impl_dnit_job(pl_interp_implementation_t *impl)
846
930
{
847
930
    txt_interp_instance_t *instance = impl->interp_client_data;
848
930
    int code = 0;
849
850
930
    if (instance->sub)
851
930
        code = pl_dnit_job(instance->sub);
852
930
    instance->sub = NULL;
853
930
    instance->device = NULL;
854
855
930
    return code;
856
930
}
857
858
/* Deallocate a interpreter instance */
859
static int
860
txt_impl_deallocate_interp_instance(pl_interp_implementation_t *impl)
861
16.0k
{
862
16.0k
    txt_interp_instance_t *instance = impl->interp_client_data;
863
864
16.0k
    gs_free_object(instance->memory, instance, "so_impl_deallocate_interp_instance");
865
866
16.0k
    return 0;
867
16.0k
}
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
};