Coverage Report

Created: 2026-07-24 07:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/pcl/pl/pjparse.c
Line
Count
Source
1
/* Copyright (C) 2001-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
17
/* pjparse.c */
18
/* PJL parser */
19
#include "stat_.h"
20
#include "memory_.h"
21
#include "stdio_.h"
22
#include "string_.h"
23
#include "scommon.h"
24
#include "gdebug.h"
25
#include "gp.h"
26
#include "gpmisc.h"
27
#include "gxiodev.h"
28
#include "pjparse.h"
29
#include "plfont.h"
30
#include "plver.h"              /* PJL_VOLUME_0 PJL_VOLUME_1 */
31
#include "plmain.h"
32
#include "ctype_.h"             /* for toupper() */
33
#include <stdlib.h>             /* for atoi() */
34
#include "gserrors.h"
35
36
/* ------ pjl state definitions ------ */
37
38
#define PJL_STRING_LENGTH (256)
39
33.0M
#define PJL_PATH_NAME_LENGTH (256)
40
0
#define MAXPATHLEN 1024
41
42
/* definitions for fontsource and font number table entries */
43
#define pjl_fontsource_body\
44
    char designator[2]; \
45
    PJCONST char *pathname; \
46
    PJCONST char *fontnumber
47
48
#define PJCONST
49
typedef struct pjl_fontsource
50
{
51
  pjl_fontsource_body;
52
} pjl_fontsource_t;
53
#undef PJCONST
54
55
#define PJCONST const
56
typedef struct pjl_fontsource_default
57
{
58
  pjl_fontsource_body;
59
} pjl_fontsource_default_t;
60
#undef PJCONST
61
62
/* definitions for variable names and values */
63
#define pjl_envir_var_body\
64
  PJCONST char *var; \
65
  PJCONST char *value
66
67
#define PJCONST
68
typedef struct pjl_envir_var_s {
69
  pjl_envir_var_body;
70
} pjl_envir_var_t;
71
#undef PJCONST
72
73
#define PJCONST const
74
typedef struct pjl_envir_var_default_s {
75
  pjl_envir_var_body;
76
} pjl_envir_var_default_t;
77
#undef PJCONST
78
79
/* the pjl current environment and the default user environment.  Note
80
   the default environment should be stored in NVRAM on embedded print
81
   systems. */
82
typedef struct pjl_parser_state_s
83
{
84
    char *line;                 /* buffered command line */
85
    int line_size;
86
    int bytes_to_write;         /* data processing by fsdownload */
87
    int bytes_to_read;          /* data processed by fsupload */
88
    gp_file *fp;                   /* fsdownload or fsupload file */
89
    int pos;                    /* current position in line */
90
    pjl_envir_var_t *defaults;  /* the default environment (i.e. set default) */
91
    pjl_envir_var_t *envir;     /* the pjl environment */
92
    /* these are seperated out from the default and environmnet for no good reason */
93
    pjl_fontsource_t *font_defaults;
94
    pjl_fontsource_t *font_envir;
95
    char *environment_font_path;        /* if there is an operating sytem env
96
                                           var it is used instead of the
97
                                           default pjl fontsource */
98
    /* permenant soft font slots - bit n is the n'th font number. */
99
0
    #define MAX_PERMANENT_FONTS 256 /* multiple of 8 */
100
    unsigned char permanent_soft_fonts[MAX_PERMANENT_FONTS / 8];
101
102
    gs_memory_t *mem;
103
} pjl_parser_state_t;
104
105
/* provide factory defaults for pjl commands.  Note these are not pjl
106
   defaults but initial values set in the printer when shipped.  In an
107
   embedded system these would be defined in ROM */
108
static pjl_envir_var_default_t pjl_factory_defaults[] = {
109
    {"formlines", "60"},
110
    {"formlines_set", "off"},
111
    {"widea4", "no"},
112
    {"edgetoedge", "no"},
113
    {"fontsource", "I"},
114
    {"fontnumber", "0"},
115
    {"pitch", "10.00"},
116
    {"ptsize", "12.00"},
117
    /* NB pc8 is used on 6mp, clj4550, clj4600
118
       roman8 is used on most other HP devices */
119
    {"symset", "pc8"},
120
    {"copies", "1"},
121
    {"paper", "letter"},
122
    {"orientation", "portrait"},
123
    {"duplex", "off"},
124
    {"binding", "longedge"},
125
    {"manualfeed", "off"},
126
    {"fontsource", "I"},
127
    {"fontnumber", "0"},
128
    {"personality", "pcl5c"},
129
    {"language", "auto"},
130
    {"disklock", "off"},
131
    {"plotsizeoverride", "off"},        /* override hpgl/2 PS command args */
132
    {"plotsize1", "0"},         /* 1st arg to PS - plotter units */
133
    {"plotsize2", "0"},         /* 2nd arg to PS - plotter units */
134
    {"paperwidth", ""},
135
    {"paperlength", ""},
136
    {"resolution", "0"},
137
    /*    {"personality", "rtl"}, */
138
    {"pdfmark", ""},
139
    {"setdistillerparams", ""},
140
    {"", ""}
141
};
142
143
/* NB this must be kept synchronized with the table above and we
144
   should probably have index definitions for each variable */
145
179
#define FDEF_PAPER_INDX 8
146
147
/* FONTS I (Internal Fonts) C, C1, C2 (Cartridge Fonts) S (Permanent
148
   Soft Fonts) M1, M2, M3, M4 (fonts stored in one of the printer's
149
   ROM SIMM slots).  Simulate cartridge, permanent soft fonts, and
150
   printer ROM SIMMS with sub directories.  See table below.  Also
151
   resources can be set up as lists of resources which is useful for
152
   host based systems.  Entries are seperated with a semi-colon.  Note
153
   there is some unnecessary overlap in the factory default and font
154
   source table. */
155
static pjl_fontsource_default_t pjl_fontsource_table[] = {
156
    {"I",
157
     "%rom%ttfonts/;urwfonts/;pcl/urwfonts/;ghostpdl/pcl/urwfonts/;/windows/fonts/;", ""},
158
    {"C", "CART0/", ""},
159
    {"C1", "CART1/", ""},
160
    {"C2", "CART2/", ""},
161
    {"S", "MEM0/", ""},
162
    {"M1", "MEM1/", ""},
163
    {"M2", "MEM2/", ""},
164
    {"M3", "MEM3/", ""},
165
    {"M4", "MEM4/", ""},
166
    {"", "", ""}
167
};
168
169
/* pjl tokens parsed */
170
typedef enum
171
{
172
    DONE,
173
    SET,
174
    DEFAULT,
175
    EQUAL,
176
    VARIABLE,
177
    SETTING,
178
    UNIDENTIFIED,               /* NB not used */
179
    LPARM,                      /* NB not used */
180
    PREFIX,                     /* @PJL */
181
    INITIALIZE,
182
    RESET,
183
    INQUIRE,
184
    DINQUIRE,
185
    ENTER,
186
    LANGUAGE,
187
    ENTRY,
188
    COUNT,
189
    OFFSET,
190
    FSDOWNLOAD,
191
    FSAPPEND,
192
    FSDELETE,
193
    FSDIRLIST,
194
    FSINIT,
195
    FSMKDIR,
196
    FSQUERY,
197
    FSUPLOAD,
198
    FORMATBINARY,               /* this nonsense is ignored.
199
                                   all data is treated as binary */
200
    NAME,                       /* used for pathnames */
201
    SIZE,                       /* size of data */
202
    VOLUME,                     /* volume indicator for filesystem initialization */
203
    DISKLOCK,
204
    GSSET,
205
    GSSETSTRING
206
} pjl_token_type_t;
207
208
/* lookup table to map strings to pjl tokens */
209
typedef struct pjl_lookup_table_s
210
{
211
    char pjl_string[PJL_STRING_LENGTH + 1];
212
    pjl_token_type_t pjl_token;
213
} pjl_lookup_table_t;
214
215
static const pjl_lookup_table_t pjl_table[] = {
216
    {"@PJL", PREFIX},
217
    {"SET", SET},
218
    {"DEFAULT", DEFAULT},
219
    {"INITIALIZE", INITIALIZE},
220
    {"=", EQUAL},
221
    {"DINQUIRE", DINQUIRE},
222
    {"INQUIRE", INQUIRE},
223
    {"ENTER", ENTER},
224
    /* File system related variables */
225
    {"FSDOWNLOAD", FSDOWNLOAD},
226
    {"FSAPPEND", FSAPPEND},
227
    {"FSDELETE", FSDELETE},
228
    {"FSDIRLIST", FSDIRLIST},
229
    {"FSINIT", FSINIT},
230
    {"FSMKDIR", FSMKDIR},
231
    {"FSQUERY", FSQUERY},
232
    {"FSUPLOAD", FSUPLOAD},
233
    {"FORMAT:BINARY", FORMATBINARY},    /* this nonsense is ignored.
234
                                           all data is treated as binary */
235
    {"NAME", NAME},             /* used for pathnames */
236
    {"SIZE", SIZE},             /* size of data */
237
    {"VOLUME", VOLUME},         /* used for volume name */
238
    {"ENTRY", ENTRY},
239
    {"COUNT", COUNT},
240
    {"OFFSET", OFFSET},
241
    {"DISKLOCK", DISKLOCK},
242
    {"GSSET", GSSET},
243
    {"GSSETSTRING", GSSETSTRING},
244
    {"", (pjl_token_type_t) 0 /* don't care */ }
245
};
246
247
#include "gdevpxen.h"
248
249
#define PJLMEDIA(ms, mstr, res, w, h) \
250
    { mstr, w, h },
251
static const struct
252
{
253
    const char *media_name;
254
    float width, height;
255
} pjl_media[] = {
256
    px_enumerate_media(PJLMEDIA)
257
};
258
259
/* ----- private functions and definitions ------------ */
260
261
/* forward declaration */
262
static int pjl_set(pjl_parser_state_t * pst, char *variable, char *value,
263
                   bool defaults);
264
static int set_pjl_defaults_to_factory(gs_memory_t * mem, pjl_envir_var_t **def);
265
static int set_pjl_defaults(gs_memory_t * mem, pjl_envir_var_t **def, pjl_envir_var_t *from);
266
static int set_pjl_environment_to_factory(gs_memory_t * mem, pjl_envir_var_t **env);
267
static int set_pjl_environment(gs_memory_t * mem, pjl_envir_var_t **env, pjl_envir_var_t *from);
268
static int set_pjl_fontsource_to_factory(gs_memory_t * mem, pjl_fontsource_t **fontenv);
269
static int set_pjl_fontsource(gs_memory_t * mem, pjl_fontsource_t **fontenv, pjl_fontsource_t *from);
270
static int set_pjl_default_fontsource_to_factory(gs_memory_t * mem, pjl_fontsource_t **fontdef);
271
static int set_pjl_default_fontsource(gs_memory_t * mem, pjl_fontsource_t **fontdef, pjl_fontsource_t *from);
272
static int free_pjl_defaults(gs_memory_t * mem, pjl_envir_var_t **def);
273
static int free_pjl_environment(gs_memory_t * mem, pjl_envir_var_t **env);
274
static int free_pjl_fontsource(gs_memory_t * mem, pjl_fontsource_t **fontenv);
275
static int free_pjl_default_fontsource(gs_memory_t * mem, pjl_fontsource_t **fontdef);
276
277
/* lookup a paper size and return the index in the media return letter
278
   if no match. */
279
280
/* somewhat awkward,  */
281
179
#define LETTER_PAPER_INDEX 1
282
283
static int
284
pjl_get_media_index(const char *paper)
285
179
{
286
179
    int i;
287
288
7.87k
    for (i = 0; i < countof(pjl_media); i++)
289
7.69k
        if (!pjl_compare(paper, pjl_media[i].media_name))
290
0
            return i;
291
179
    return LETTER_PAPER_INDEX;
292
179
}
293
294
/* calculate the number of lines per page as a function of page
295
   length */
296
static int
297
pjl_calc_formlines_new_page_size(int page_length)
298
179
{
299
300
    /* note the units are 300 dpi units as pcl traditional
301
       documentation dictates.  This is not properly documented in the
302
       technical reference manual but the formula appears to be:
303
       formlines = ((page_length - 300 dots) / 50.0 dots) 50.0 dots
304
       corresponds with the default pcl 6 lines per inch and 300 with
305
       1 inch of margin - so the empirical results look plausible.
306
     */
307
308
179
    double formlines = (page_length - 300.0) / 50.0;
309
310
179
    return (int)(formlines + 0.5);
311
179
}
312
313
/* handle pjl variables which affect the state of other variables - we
314
   don't handle all of these yet.  NB not complete. */
315
static void
316
pjl_side_effects(pjl_parser_state_t * pst, char *variable, char *value,
317
                 bool defaults)
318
7.64k
{
319
7.64k
    if (!pjl_compare(variable, "PAPER") ||
320
7.46k
        !pjl_compare(variable, "ORIENTATION")) {
321
322
179
        pjl_envir_var_t *table = (defaults ? pst->defaults : pst->envir);
323
179
        int indx = pjl_get_media_index(table[FDEF_PAPER_INDX].value);
324
179
        int page_length = (!pjl_compare(variable, "ORIENTATION") &&
325
0
                           !pjl_compare(value, "LANDSCAPE") ?
326
0
                           (int)(pjl_media[indx].width) :
327
179
                           (int)(pjl_media[indx].height));
328
179
        int formlines = pjl_calc_formlines_new_page_size(page_length);
329
179
        char text[32];
330
331
179
        gs_snprintf(text, sizeof(text), "%d", formlines);
332
179
        pjl_set(pst, (char *)"FORMLINES", text, defaults);
333
179
    }
334
    /* fill in other side effects here */
335
7.64k
    return;
336
7.64k
}
337
338
/* set a pjl environment or default variable. */
339
static int
340
pjl_set(pjl_parser_state_t * pst, char *variable, char *value, bool defaults)
341
7.64k
{
342
7.64k
    pjl_envir_var_t *table = (defaults ? pst->defaults : pst->envir);
343
7.64k
    int i=0;
344
345
7.64k
    if (defaults)               /* default also sets current environment. */
346
0
        pjl_set(pst, variable, value, false);
347
348
148k
    while (table[i].var) {
349
148k
        if (!pjl_compare(table[i].var, variable)) {
350
            /* set the value */
351
7.64k
            char *newvalue = (char *)gs_alloc_bytes(pst->mem, strlen(value) + 1, "pjl_set, create new value");
352
7.64k
            if (!newvalue)
353
0
                return 0;
354
7.64k
            strcpy(newvalue, value);
355
7.64k
            gs_free_object(pst->mem, table[i].value, "pjl_set free old value");
356
7.64k
            table[i].value = newvalue;
357
            /* set any side effects of setting the value */
358
7.64k
            pjl_side_effects(pst, variable, value, defaults);
359
7.64k
            return 1;
360
7.64k
        }
361
140k
        i++;
362
140k
    }
363
    /* didn't find variable */
364
0
    return 0;
365
7.64k
}
366
367
/* get next token from the command line buffer */
368
static pjl_token_type_t
369
pjl_get_token(pjl_parser_state_t * pst, char token[])
370
146k
{
371
146k
    int c;
372
146k
    int start_pos;
373
    /* skip any whitespace if we need to.  */
374
208k
    while ((c = pst->line[pst->pos]) == ' ' || c == '\t')
375
62.2k
        pst->pos++;
376
377
    /* special case to allow = with no intevervening spaces between
378
       lhs and rhs */
379
146k
    if (c == '=') {
380
20.1k
        pst->pos++;
381
20.1k
        return EQUAL;
382
20.1k
    }
383
384
    /* set the starting position */
385
126k
    start_pos = pst->pos;
386
387
    /* end of line reached; null shouldn't happen but we check anyway */
388
126k
    if (c == '\0' || c == '\n')
389
7.61k
        return DONE;
390
391
    /* check for a quoted string.  It should not span a line */
392
118k
    if (c == '"') {
393
1.67k
        pst->pos++;
394
35.7k
        while ((c = pst->line[pst->pos]) != '"' && c != '\0' && c != '\n')
395
34.1k
            pst->pos++;
396
        /* this routine doesn't yet support real error handling - here
397
           we should check if c == '"' */
398
1.67k
        if (c == '"')
399
1.46k
            pst->pos++;
400
205
        else
401
205
            return DONE;
402
117k
    } else {
403
        /* set the ptr to the next delimeter. */
404
696k
        while ((c = pst->line[pst->pos]) != ' ' &&
405
626k
               c != '\t' && c != '\r' && c != '\n' && c != '=' && c != '\0')
406
579k
            pst->pos++;
407
117k
    }
408
409
    /* build the token */
410
118k
    {
411
118k
        int slength = pst->pos - start_pos;
412
118k
        int i;
413
414
        /* we allow = to special case for allowing
415
           token doesn't fit or is empty */
416
118k
        if (slength == 0)
417
6.48k
            return DONE;
418
        /* now the string can be safely copied */
419
112k
        strncpy(token, &pst->line[start_pos], slength);
420
112k
        token[slength] = '\0';
421
422
        /* for known tokens */
423
1.58M
        for (i = 0; pjl_table[i].pjl_string[0]; i++)
424
1.52M
            if (!pjl_compare(pjl_table[i].pjl_string, token))
425
57.4k
                return pjl_table[i].pjl_token;
426
427
        /* NB add other cases here */
428
        /* check for variables that we support */
429
54.8k
        i = 0;
430
1.52M
        while (pst->envir[i].var) {
431
1.47M
            if (!pjl_compare(pst->envir[i].var, token))
432
7.48k
                return VARIABLE;
433
1.46M
            i++;
434
1.46M
        }
435
436
        /* NB assume this is a setting yuck */
437
47.3k
        return SETTING;
438
54.8k
    }
439
    /* shouldn't happen */
440
0
    return DONE;
441
54.8k
}
442
443
/* check if fonts exist in the current font source path */
444
static char *
445
pjl_check_font_path(char *path_list, gs_memory_t * mem)
446
657k
{
447
    /* lookup a font path and check if any files (presumably fonts are
448
       present) */
449
657k
    char path[PJL_PATH_NAME_LENGTH + 1];
450
657k
    char *pathp = path, *tplast = NULL;
451
657k
    const char pattern[] = "*";
452
657k
    char path_and_pattern[PJL_PATH_NAME_LENGTH + 1 + 1];    /* pattern + null */
453
657k
    char *dirname;
454
657k
    char fontfilename[MAXPATHLEN + 1];
455
456
    /* Ignore error if the path list is too long, a single path may be
457
       okay. */
458
657k
    gs_strlcpy(path, path_list, sizeof(path));
459
    /* for each path search for fonts.  If we find them return we only
460
       check if the directory resource has files without checking if
461
       the files are indeed fonts. */
462
916k
    while ((dirname = gs_strtok(pathp, ";", &tplast)) != NULL) {
463
657k
        file_enum *fe;
464
465
657k
        if (gs_strlcpy(path_and_pattern, dirname, sizeof(path_and_pattern)) >= sizeof(path_and_pattern))
466
0
            continue;
467
468
657k
        if (gs_strlcat(path_and_pattern, pattern, sizeof(path_and_pattern)) >= sizeof(path_and_pattern))
469
0
            continue;
470
471
657k
        fe = gs_enumerate_files_init(mem, path_and_pattern,
472
657k
                                     strlen(path_and_pattern));
473
657k
        if (fe == NULL
474
657k
            ||
475
657k
            (gs_enumerate_files_next(mem, fe, fontfilename, PJL_PATH_NAME_LENGTH))
476
657k
            == -1) {
477
258k
            pathp = NULL;
478
399k
        } else {
479
            /* wind through the rest of the files.  This should close
480
               things up as well.  All we need to do is clean up but
481
               gs_enumerate_files_close() does not close the current
482
               directory */
483
32.3M
            while (1) {
484
32.3M
                int fstatus =
485
32.3M
                    (int)gs_enumerate_files_next(mem, fe, fontfilename,
486
32.3M
                                                 PJL_PATH_NAME_LENGTH);
487
                /* we don't care if the file does not fit (return +1) */
488
32.3M
                if (fstatus == -1)
489
399k
                    break;
490
32.3M
            }
491
            /* replace : separated path with real path.  The path list
492
               is of equal or greater length than dirname, so it can't
493
               fail, but we check anyway. */
494
399k
            if (strlen(path_list) < strlen(dirname))
495
0
                return NULL;
496
399k
            else {
497
399k
                strcpy(path_list, dirname);
498
399k
                return path_list;
499
399k
            }
500
399k
        }
501
657k
    }
502
258k
    return NULL;
503
657k
}
504
505
/* initilize both pjl state and default environment to default font
506
   number if font resources are present.  Note we depend on the PDL
507
   (pcl) to provide information about 'S' permanent soft fonts.  For
508
   all other resources we check for filenames which should correspond
509
   to fonts. */
510
static void
511
pjl_reset_fontsource_fontnumbers(pjl_parser_state_t * pst)
512
16.1k
{
513
16.1k
    char default_font_number[] = {0x30, 0x00};   /* default number if resources are present */
514
16.1k
    gs_memory_t *mem = pst->mem;
515
16.1k
    int i;
516
16.1k
    char *newvalue;
517
518
161k
    for (i = 0; pst->font_defaults[i].designator[0]; i++) {
519
145k
        if (pjl_check_font_path(pst->font_defaults[i].pathname, mem)) {
520
16.1k
            newvalue = (char *)gs_alloc_bytes(mem, strlen(default_font_number) + 1, "pjl_reset_fontsource_fontnumbers, create new value");
521
16.1k
            if (newvalue) {
522
16.1k
                gs_free_object(mem, pst->font_defaults[i].fontnumber, "pjl_reset_fontsource_fontnumbers");
523
16.1k
                strcpy(newvalue, default_font_number);
524
16.1k
                pst->font_defaults[i].fontnumber = newvalue;
525
16.1k
            }
526
16.1k
        }
527
145k
        if (pjl_check_font_path(pst->font_envir[i].pathname, mem)) {
528
16.1k
            newvalue = (char *)gs_alloc_bytes(mem, strlen(default_font_number) + 1, "pjl_reset_fontsource_fontnumbers, create new value");
529
16.1k
            if (newvalue) {
530
16.1k
                gs_free_object(mem, pst->font_envir[i].fontnumber, "pjl_reset_fontsource_fontnumbers");
531
16.1k
                strcpy(newvalue, default_font_number);
532
16.1k
                pst->font_envir[i].fontnumber = newvalue;
533
16.1k
            }
534
16.1k
        }
535
145k
    }
536
16.1k
}
537
538
/* Strips off extra quotes '"'
539
 * and changes pjl volume from 0: to makefile specifed PJL_VOLUME_0 directory
540
 * and translates '\\' to '/'
541
 * result in fnamep,
542
 * ie: ""0:\\dir\subdir\file"" --> "PJL_VOLUME_0/dir/subdir/file"
543
 */
544
static void
545
pjl_parsed_filename_to_string(char *fnamep, const char *pathname)
546
0
{
547
0
    size_t i, size, prefix_size;
548
0
    const char *prefix;
549
0
    char name[MAXPATHLEN];
550
0
    uint rlen;
551
552
0
    *fnamep = 0;                /* in case of bad input */
553
0
    if (pathname == 0 || strlen(pathname) < 4 ||
554
0
        pathname[0] != '"' || pathname[strlen(pathname)-1] != '"')
555
0
        return;                 /* bad input pjl file */
556
557
0
    if (pathname[1] == '0' && pathname[2] == ':') {
558
0
        prefix = PJL_VOLUME_0;
559
0
    } else if (pathname[1] == '1' && pathname[2] == ':') {
560
0
        prefix = PJL_VOLUME_1;
561
0
    } else
562
0
        return;                 /* bad input pjl file */
563
564
    /* the pathname parsed has whatever quoting mechanism was used
565
     * remove quotes, use forward slash, copy rest.
566
     */
567
0
    size = strlen(pathname);
568
0
    if (size - 4 > MAXPATHLEN)
569
0
        return;
570
0
    for (i = 3; i < size - 1; i++)
571
0
        name[i - 3] = (pathname[i] == '\\') ? '/' : pathname[i];
572
0
    size -= 4;
573
574
    /* copy pjl_volume string in. use strlen+1 to ensure that strncpy()
575
    appends '\0', to keep coverity quiet. */
576
0
    prefix_size = strlen(prefix);
577
0
    strncpy(fnamep, prefix, prefix_size + 1);
578
579
0
    if (size == 0)
580
0
        return;
581
582
0
    if (name[0] != '/')
583
0
        fnamep[prefix_size++] = '/';
584
585
0
    rlen = MAXPATHLEN - prefix_size;
586
0
    if (gp_file_name_reduce(name, size, fnamep + prefix_size, &rlen) == gp_combine_success)
587
0
        fnamep[prefix_size + rlen] = 0;
588
0
    else
589
0
        fnamep[0] = 0;
590
0
}
591
592
/* Verify a file write operation is ok.  The filesystem must be 0: or
593
   1:, no other pjl files can have pending writes, and the pjl
594
   disklock state variable must be false */
595
static int
596
pjl_verify_file_operation(pjl_parser_state_t * pst, char *fname, const char *access)
597
0
{
598
    /* make sure we are playing in the pjl sandbox */
599
0
    if (0 != strncmp(PJL_VOLUME_0, fname, strlen(PJL_VOLUME_0))
600
0
        && 0 != strncmp(PJL_VOLUME_1, fname, strlen(PJL_VOLUME_1))) {
601
0
        dmprintf1(pst->mem, "illegal path name %s\n", fname);
602
0
        return -1;
603
0
    }
604
605
0
    if (access != NULL && gp_validate_path(pst->mem, fname, access) != 0) {
606
0
        dmprintf1(pst->mem, "illegal path name %s\n", fname);
607
0
        return -1;
608
0
    }
609
610
    /* make sure we are not currently writing to a file.
611
       Simultaneously file writing is not supported */
612
0
    if (pst->bytes_to_write || pst->fp)
613
0
        return -1;
614
615
    /* no operation if disklocak is enabled */
616
0
    if (!pjl_compare(pjl_get_envvar(pst, "disklock"), "on"))
617
0
        return -1;
618
    /* ok */
619
0
    return 0;
620
0
}
621
622
/* debugging procedure to warn about writing to an extant file */
623
static void
624
pjl_warn_exists(const gs_memory_t * mem, char *fname)
625
0
{
626
0
    gp_file *fpdownload;
627
628
    /* issue a warning if the file exists */
629
0
    if ((fpdownload = gp_fopen(mem, fname, gp_fmode_rb)) != NULL) {
630
0
        gp_fclose(fpdownload);
631
0
        dmprintf1(mem, "warning file exists overwriting %s\n", fname);
632
0
    }
633
0
}
634
635
/* open a file for writing or appending */
636
static gp_file *
637
pjl_setup_file_for_writing(pjl_parser_state_t * pst, char *pathname, int size,
638
                           bool append)
639
0
{
640
0
    gp_file *fp;
641
0
    char fname[MAXPATHLEN];
642
643
0
    pjl_parsed_filename_to_string(fname, pathname);
644
0
    if (pjl_verify_file_operation(pst, fname, NULL) < 0)
645
0
        return NULL;
646
0
    pjl_warn_exists(pst->mem, fname);
647
0
    {
648
0
        char fmode[4];
649
650
0
        strcpy(fmode, gp_fmode_wb);
651
0
        if (append)
652
0
            strcat(fmode, "+");
653
0
        if ((fp = gp_fopen(pst->mem, fname, gp_fmode_wb)) == NULL) {
654
0
            dmprintf(pst->mem, "warning file open for writing failed\n");
655
0
            return NULL;
656
0
        }
657
0
    }
658
0
    return fp;
659
0
}
660
661
/* set up the state to download date to a pjl file */
662
static int
663
pjl_set_fs_download_state(pjl_parser_state_t * pst, char *pathname, int size)
664
0
{
665
    /* somethink is wrong if the state indicates we are already writing to a file */
666
0
    gp_file *fp =
667
0
        pjl_setup_file_for_writing(pst, pathname, size, false /* append */ );
668
0
    if (fp == NULL)
669
0
        return -1;
670
0
    pst->fp = fp;
671
0
    pst->bytes_to_write = size;
672
0
    return 0;
673
0
}
674
675
/* set up the state to append subsequent data from the input stream to
676
   a file */
677
static int
678
pjl_set_append_state(pjl_parser_state_t * pst, char *pathname, int size)
679
0
{
680
0
    gp_file *fp =
681
0
        pjl_setup_file_for_writing(pst, pathname, size, true /* append */ );
682
0
    if (fp == NULL)
683
0
        return -1;
684
0
    pst->fp = fp;
685
0
    pst->bytes_to_write = size;
686
0
    return 0;
687
0
}
688
689
/* create a pjl volume, this should create the volume 0: or 1: we
690
   simply create a directory with the volume name. */
691
static int
692
pjl_fsinit(pjl_parser_state_t * pst, char *pathname)
693
0
{
694
0
    char fname[MAXPATHLEN];
695
696
0
    pjl_parsed_filename_to_string(fname, pathname);
697
0
    if (pjl_verify_file_operation(pst, fname, "c") < 0)
698
0
        return -1;
699
#ifdef GS_NO_FILESYSTEM
700
    return -1;
701
#else
702
  #ifdef __WIN32__
703
    return _mkdir(fname);
704
  #else
705
0
    return mkdir(fname, 0777);
706
0
  #endif
707
0
#endif
708
0
}
709
710
/* make a pjl directory */
711
static int
712
pjl_fsmkdir(pjl_parser_state_t * pst, char *pathname)
713
0
{
714
0
    char fname[MAXPATHLEN];
715
716
0
    pjl_parsed_filename_to_string(fname, pathname);
717
0
    if (pjl_verify_file_operation(pst, fname, "c") < 0)
718
0
        return -1;
719
#ifdef GS_NO_FILESYSTEM
720
    return -1;
721
#else
722
  #ifdef __WIN32__
723
    return _mkdir(fname);
724
  #else
725
0
    return mkdir(fname, 0777);
726
0
  #endif
727
0
#endif
728
0
}
729
730
/* query a file in the pjl sandbox */
731
static int
732
pjl_fsquery(pjl_parser_state_t * pst, char *pathname)
733
0
{
734
    /* not implemented */
735
0
    return -1;
736
0
}
737
738
/* Upload a file from the pjl sandbox */
739
static int
740
pjl_fsupload(pjl_parser_state_t * pst, char *pathname, int offset, int size)
741
0
{
742
    /* not implemented */
743
0
    return -1;
744
0
}
745
746
/* search pathname for filename return a match in result.  result
747
   should be a 0 length string upon calling this routine.  If a match
748
   is found result will hold the matching path and filename.  Thie
749
   procedure recursively searches the directory tree "pathname" for
750
   "filename" */
751
static int
752
pjl_search_for_file(pjl_parser_state_t * pst, char *pathname, char *filename,
753
                    char *result)
754
0
{
755
0
    file_enum *fe;
756
0
    char fontfilename[MAXPATHLEN];
757
0
    struct stat stbuf;
758
759
    /* should check length */
760
0
    snprintf(fontfilename, sizeof(fontfilename), "%s/*", pathname);
761
0
    fe = gs_enumerate_files_init(pst->mem, fontfilename, strlen(fontfilename));
762
0
    if (fe) {
763
0
        do {
764
0
            uint fstatus =
765
0
                gs_enumerate_files_next(pst->mem, fe, fontfilename,
766
0
                                        PJL_PATH_NAME_LENGTH);
767
            /* done */
768
0
            if (fstatus == ~(uint) 0)
769
0
                return 0;
770
0
            if (fstatus > PJL_PATH_NAME_LENGTH)
771
0
                continue;
772
0
            fontfilename[fstatus] = '\0';
773
0
            if (fontfilename[fstatus - 1] != '.') {     /* skip over . and .. */
774
                /* a directory */
775
0
                if ((stat(fontfilename, &stbuf) >= 0) && stat_is_dir(stbuf))
776
0
                    pjl_search_for_file(pst, fontfilename, filename, result);
777
0
                else /* a file */
778
0
                if (!strcmp(strrchr(fontfilename, '/') + 1, filename))
779
0
                    strcpy(result, fontfilename);
780
0
            }
781
782
0
        } while (1);
783
0
    }
784
    /* not implemented */
785
0
    return -1;
786
0
}
787
788
static int
789
pjl_fsdirlist(pjl_parser_state_t * pst, char *pathname, int entry, int count)
790
0
{
791
0
    file_enum *fe;
792
0
    char fontfilename[MAXPATHLEN + 2];
793
794
0
    pjl_parsed_filename_to_string(fontfilename, pathname);
795
0
    if (pjl_verify_file_operation(pst, fontfilename, NULL) < 0)
796
0
        return -1;
797
798
    /* if this is a directory add * for the directory listing NB fix */
799
0
    strcat(fontfilename, "/*");
800
0
    fe = gs_enumerate_files_init(pst->mem, fontfilename, strlen(fontfilename));
801
0
    if (fe) {
802
0
        do {
803
0
            uint fstatus =
804
0
                gs_enumerate_files_next(pst->mem, fe, fontfilename,
805
0
                                        PJL_PATH_NAME_LENGTH);
806
            /* done */
807
0
            if (fstatus == ~(uint) 0)
808
0
                return 0;
809
0
            if (fstatus > PJL_PATH_NAME_LENGTH)
810
0
                continue;
811
0
            fontfilename[fstatus] = '\0';
812
            /* NB - debugging output only */
813
0
            dmprintf1(pst->mem, "%s\n", fontfilename);
814
0
        } while (1);
815
0
    }
816
    /* should not get here */
817
0
    return -1;
818
0
}
819
820
inline static int
821
pjl_write_remaining_data(pjl_parser_state_t * pst, const byte ** pptr,
822
                         const byte ** pplimit)
823
0
{
824
0
    const byte *ptr = *pptr;
825
0
    const byte *plimit = *pplimit;
826
0
    uint avail = plimit - ptr;
827
0
    uint bytes_written = min(avail, pst->bytes_to_write);
828
829
0
    if (gp_fwrite(ptr, 1, bytes_written, pst->fp) != bytes_written) {
830
        /* try to close the file before failing */
831
0
        gp_fclose(pst->fp);
832
0
        pst->fp = NULL;
833
0
        return -1;
834
0
    }
835
0
    pst->bytes_to_write -= bytes_written;
836
0
    if (pst->bytes_to_write == 0) {     /* done */
837
0
        gp_fclose(pst->fp);
838
0
        pst->fp = NULL;
839
0
    }
840
    /* update stream pointer */
841
0
    *pptr += bytes_written;
842
0
    return 0;
843
0
}
844
845
static int
846
pjl_delete_file(pjl_parser_state_t * pst, char *pathname)
847
0
{
848
0
    char fname[MAXPATHLEN];
849
850
0
    pjl_parsed_filename_to_string(fname, pathname);
851
0
    if (pjl_verify_file_operation(pst, fname, NULL) < 0)
852
0
        return -1;
853
0
    return gp_unlink(pst->mem, fname);
854
0
}
855
856
/* handle pattern foo = setting, e.g. volume = "0:", name = 0:]pcl.
857
   the setting will be returned in "token" if successful.  Return 0
858
   for success and -1 if we fail */
859
static int
860
pjl_get_setting(pjl_parser_state_t * pst, pjl_token_type_t tok, char *token)
861
0
{
862
0
    pjl_token_type_t lhs = pjl_get_token(pst, token);
863
864
0
    if (lhs != tok)
865
0
        return -1;
866
0
    if ((tok = pjl_get_token(pst, token)) != EQUAL)
867
0
        return -1;
868
0
    if ((tok = pjl_get_token(pst, token)) != SETTING)
869
0
        return -1;
870
0
    return 0;
871
0
}
872
873
static int
874
gs_set(pjl_parser_state_t *pst, const char *variable, const char *token, int string)
875
29
{
876
29
    int code;
877
29
    int len1 = strlen(variable)+1;
878
29
    int len2 = token == NULL ? 0 : strlen(token)+1;
879
29
    char *buffer = (char *)gs_alloc_bytes(pst->mem, len1+len2, "gs_set buffer");
880
881
29
    if (buffer == NULL)
882
0
        return -1;
883
884
29
    strcpy(buffer, variable);
885
29
    if (len2) {
886
9
        strcat(buffer, "=");
887
9
        strcat(buffer, token);
888
9
    }
889
890
29
    if (string)
891
0
        code = pl_main_set_string_param(pl_main_get_instance(pst->mem), buffer);
892
29
    else
893
29
        code = pl_main_set_param(pl_main_get_instance(pst->mem), buffer);
894
29
    gs_free_object(pst->mem, buffer, "gs_set buffer");
895
896
29
    return code;
897
29
}
898
899
900
/* parse and set up state for one line of pjl commands */
901
static int
902
pjl_parse_and_process_line(pjl_parser_state_t * pst)
903
34.7k
{
904
34.7k
    pjl_token_type_t tok;
905
34.7k
    char *token;
906
34.7k
    char pathname[MAXPATHLEN];
907
34.7k
    int bufsize = pst->pos + 1, code;
908
909
34.7k
    token = (char *)gs_alloc_bytes(pst->mem, bufsize, "working buffer for PJL parsing");
910
34.7k
    if (token == 0)
911
0
        return -1;
912
913
34.7k
    memset(token, 0x00, bufsize);
914
34.7k
    memset(pathname, 0x00, sizeof(pathname));
915
916
    /* reset the line position to the beginning of the line */
917
34.7k
    pst->pos = 0;
918
    /* all pjl commands start with the pjl prefix @PJL */
919
34.7k
    if ((tok = pjl_get_token(pst, token)) != PREFIX) {
920
248
        gs_free_object(pst->mem, token, "working buffer for PJL parsing");
921
248
        return -1;
922
248
    }
923
    /* NB we should check for required and optional used of whitespace
924
       but we don't see PJLTRM 2-6 PJL Command Syntax and Format. */
925
34.5k
    while ((tok = pjl_get_token(pst, token)) != DONE) {
926
34.4k
        switch (tok) {
927
18.1k
            case SET:
928
18.6k
            case DEFAULT:
929
18.6k
                {
930
18.6k
                    bool defaults;
931
932
21.6k
                    var:defaults = (tok == DEFAULT);
933
                    /* NB we skip over lparm and search for the variable */
934
62.3k
                    while ((tok = pjl_get_token(pst, token)) != DONE)
935
48.1k
                        if (tok == VARIABLE) {
936
7.47k
                            char *variable;
937
938
7.47k
                            variable = (char *)gs_alloc_bytes(pst->mem, bufsize, "2nd working buffer for PJL parsing");
939
7.47k
                            if (variable == 0) {
940
0
                                gs_free_object(pst->mem, token, "2nd working buffer for PJL parsing");
941
0
                                return -1;
942
0
                            }
943
7.47k
                            memset(variable, 0x00, bufsize);
944
945
7.47k
                            strcpy(variable, token);
946
7.47k
                            if (((tok = pjl_get_token(pst, token)) == EQUAL)
947
7.47k
                                && (tok = pjl_get_token(pst, token)) == SETTING) {
948
                                /* an unfortunate side effect - we have to
949
                                   identify FORMLINES being set here, for
950
                                   the benefit of PCL, see the
951
                                   documentation to the function
952
                                   pcursor.c:pcl_vmi_default() for
953
                                   details. */
954
7.46k
                                if (!pjl_compare(variable, "FORMLINES"))
955
0
                                    pjl_set(pst, (char *)"FORMLINES_SET",
956
0
                                            (char *)"on", defaults);
957
7.46k
                                code = pjl_set(pst, variable, token,
958
7.46k
                                               defaults);
959
7.46k
                            } else
960
10
                                code = -1; /* syntax error */
961
7.47k
                            gs_free_object(pst->mem, variable, "2nd working buffer for PJL parsing");
962
7.47k
                            gs_free_object(pst->mem, token, "working buffer for PJL parsing");
963
7.47k
                            return code;
964
7.47k
                        } else
965
40.6k
                            continue;
966
967
14.2k
                    gs_free_object(pst->mem, token, "working buffer for PJL parsing");
968
14.2k
                    return 0;
969
21.6k
                }
970
29
            case GSSET:
971
29
            case GSSETSTRING:
972
29
                {
973
29
                    bool string;
974
975
29
                    string = (tok == GSSETSTRING);
976
29
                    code = 0;
977
29
                    while ((tok = pjl_get_token(pst, token)) != DONE)
978
29
                        if (tok == VARIABLE || tok == SETTING) {
979
29
                            int len1 = strlen(token)+1;
980
29
                            char *variable = (char *)gs_alloc_bytes(pst->mem, len1,
981
29
                                                                    "2nd working buffer for PJL parsing");
982
29
                            if (variable == NULL)
983
0
                                code = -1;
984
29
                            else {
985
29
                                strcpy(variable, token);
986
29
                                if (((tok = pjl_get_token(pst, token)) == EQUAL) &&
987
25
                                    ((tok = pjl_get_token(pst, token)) == SETTING))
988
9
                                    code = gs_set(pst, variable, token, string);
989
20
                                else
990
20
                                    code = gs_set(pst, variable, NULL, string);
991
29
                                gs_free_object(pst->mem, variable, "2nd working buffer for PJL parsing");
992
29
                            }
993
29
                            break;
994
29
                        }
995
996
29
                    gs_free_object(pst->mem, token, "working buffer for PJL parsing");
997
29
                    return code;
998
29
                }
999
0
            case INITIALIZE:
1000
                /* set the user default environment to the factory default environment */
1001
0
                free_pjl_defaults(pst->mem, &pst->defaults);
1002
0
                set_pjl_defaults_to_factory(pst->mem, &pst->defaults);
1003
0
                free_pjl_default_fontsource(pst->mem, &pst->font_defaults);
1004
0
                set_pjl_default_fontsource_to_factory(pst->mem, &pst->font_defaults);
1005
0
                pjl_reset_fontsource_fontnumbers(pst);
1006
0
                gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1007
0
                return 0;
1008
                /* set the current environment to the user default environment */
1009
0
            case RESET:
1010
0
                free_pjl_defaults(pst->mem, &pst->defaults);
1011
0
                set_pjl_environment_to_factory(pst->mem, &pst->defaults);
1012
0
                free_pjl_fontsource(pst->mem, &pst->font_envir);
1013
0
                set_pjl_fontsource_to_factory(pst->mem, &pst->font_envir);
1014
0
                gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1015
0
                return 0;
1016
3.06k
            case ENTER:
1017
                /* there is no setting for the default language */
1018
3.06k
                tok = SET;
1019
3.06k
                goto var;
1020
0
            case FSDOWNLOAD:{
1021
                    /* consume and ignore FORMAT:BINARY foolishness. if it is
1022
                       present or search for the name */
1023
0
                    int size;
1024
1025
                    /* ignore format binary stuff */
1026
0
                    if ((tok = pjl_get_token(pst, token)) == FORMATBINARY) {
1027
0
                        ;
1028
0
                    }
1029
0
                    if (pjl_get_setting(pst, NAME, token) < 0 ||
1030
0
                        strlen(token) > MAXPATHLEN - 1)
1031
0
                        return -1;
1032
0
                    strcpy(pathname, token);
1033
0
                    if (pjl_get_setting(pst, SIZE, token) < 0)
1034
0
                        return -1;
1035
0
                    size = pjl_vartoi(token);
1036
0
                    gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1037
0
                    return pjl_set_fs_download_state(pst, pathname, size);
1038
0
                }
1039
0
            case FSAPPEND:{
1040
0
                    int size;
1041
1042
0
                    if ((tok = pjl_get_token(pst, token)) == FORMATBINARY) {
1043
0
                        ;
1044
0
                    }
1045
0
                    if (pjl_get_setting(pst, NAME, token) < 0 ||
1046
0
                        strlen(token) > MAXPATHLEN - 1)
1047
0
                        return -1;
1048
0
                    strcpy(pathname, token);
1049
0
                    if (pjl_get_setting(pst, SIZE, token) < 0)
1050
0
                        return -1;
1051
0
                    size = pjl_vartoi(token);
1052
0
                    gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1053
0
                    return pjl_set_append_state(pst, pathname, size);
1054
0
                }
1055
0
            case FSDELETE:
1056
0
                if (pjl_get_setting(pst, NAME, token) < 0 ||
1057
0
                    strlen(token) > MAXPATHLEN - 1)
1058
0
                    return -1;
1059
0
                strcpy(pathname, token);
1060
0
                gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1061
0
                return pjl_delete_file(pst, pathname);
1062
0
            case FSDIRLIST:{
1063
0
                    int entry;
1064
1065
0
                    int count;
1066
1067
0
                    if (pjl_get_setting(pst, NAME, token) < 0 ||
1068
0
                        strlen(token) > MAXPATHLEN - 1) {
1069
0
                        gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1070
0
                        return -1;
1071
0
                    }
1072
0
                    strcpy(pathname, token);
1073
0
                    if (pjl_get_setting(pst, ENTRY, token) < 0) {
1074
0
                        gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1075
0
                        return -1;
1076
0
                    }
1077
0
                    entry = pjl_vartoi(token);
1078
0
                    if (pjl_get_setting(pst, COUNT, token) < 0) {
1079
0
                        gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1080
0
                        return -1;
1081
0
                    }
1082
0
                    count = pjl_vartoi(token);
1083
0
                    gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1084
0
                    return pjl_fsdirlist(pst, pathname, entry, count);
1085
0
                }
1086
0
            case FSINIT:
1087
0
                if (pjl_get_setting(pst, VOLUME, token) < 0 ||
1088
0
                    strlen(token) > MAXPATHLEN - 1) {
1089
0
                    gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1090
0
                    return -1;
1091
0
                }
1092
0
                strcpy(pathname, token);
1093
0
                gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1094
0
                return pjl_fsinit(pst, pathname);
1095
0
            case FSMKDIR:
1096
0
                if (pjl_get_setting(pst, NAME, token) < 0 ||
1097
0
                    strlen(token) > MAXPATHLEN - 1) {
1098
0
                    gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1099
0
                    return -1;
1100
0
                }
1101
0
                strcpy(pathname, token);
1102
0
                gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1103
0
                return pjl_fsmkdir(pst, pathname);
1104
0
            case FSQUERY:
1105
0
                if (pjl_get_setting(pst, NAME, token) < 0 ||
1106
0
                    strlen(token) > MAXPATHLEN - 1) {
1107
0
                    gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1108
0
                    return -1;
1109
0
                }
1110
0
                strcpy(pathname, token);
1111
0
                gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1112
0
                return pjl_fsquery(pst, pathname);
1113
0
            case FSUPLOAD:{
1114
0
                    int size;
1115
1116
0
                    int offset;
1117
1118
0
                    if ((tok = pjl_get_token(pst, token)) == FORMATBINARY) {
1119
0
                        ;
1120
0
                    }
1121
0
                    if (pjl_get_setting(pst, NAME, token) < 0 ||
1122
0
                        strlen(token) > MAXPATHLEN - 1) {
1123
0
                        gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1124
0
                        return -1;
1125
0
                    }
1126
0
                    strcpy(pathname, token);
1127
0
                    if (pjl_get_setting(pst, OFFSET, token) < 0) {
1128
0
                        gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1129
0
                        return -1;
1130
0
                    }
1131
0
                    offset = pjl_vartoi(token);
1132
0
                    if (pjl_get_setting(pst, SIZE, token) < 0) {
1133
0
                        gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1134
0
                        return -1;
1135
0
                    }
1136
0
                    size = pjl_vartoi(token);
1137
0
                    gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1138
0
                    return pjl_fsupload(pst, pathname, offset, size);
1139
0
                }
1140
12.7k
            default:
1141
12.7k
                gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1142
12.7k
                return -1;
1143
34.4k
        }
1144
34.4k
    }
1145
72
    gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1146
72
    return 0;
1147
34.5k
}
1148
1149
/* get a file from 0: or 1: volume */
1150
static gp_file *
1151
get_fp(pjl_parser_state_t * pst, char *name)
1152
0
{
1153
0
    char result[MAXPATHLEN];
1154
1155
    /* 0: */
1156
0
    result[0] = '\0';
1157
0
    pjl_search_for_file(pst, (char *)PJL_VOLUME_0, name, result);
1158
0
    if (result[0] == '\0') {
1159
        /* try 1: */
1160
0
        pjl_search_for_file(pst, (char *)PJL_VOLUME_1, name, result);
1161
0
        if (result[0] == '\0')
1162
0
            return 0;
1163
0
    }
1164
0
    return gp_fopen(pst->mem, result, gp_fmode_rb);
1165
0
}
1166
1167
/* scan for a named resoource in the pcl sandbox 0: or 1: and return
1168
   the size of the object.  We do not distinguish between empty and
1169
   non-existant files */
1170
long int
1171
pjl_get_named_resource_size(pjl_parser_state_t * pst, char *name)
1172
0
{
1173
0
    long int size;
1174
0
    gp_file *fp = get_fp(pst, name);
1175
1176
0
    if (fp == NULL)
1177
0
        return 0;
1178
0
    size = gp_fseek(fp, 0L, SEEK_END);
1179
0
    if (size >= 0)
1180
0
        size = gp_ftell(fp);
1181
0
    else
1182
0
        size = 0;
1183
0
    gp_fclose(fp);
1184
0
    return size;
1185
0
}
1186
1187
/* get the contents of a file on 0: or 1: and return the result in the
1188
   client allocated memory */
1189
int
1190
pjl_get_named_resource(pjl_parser_state * pst, char *name, byte * data, long int datasize)
1191
0
{
1192
0
    long int size;
1193
0
    int code = 0;
1194
0
    gp_file *fp = get_fp(pst, name);
1195
1196
0
    if (fp == NULL)
1197
0
        return 0;
1198
0
    size = gp_fseek(fp, 0L, SEEK_END);
1199
0
    if (size >= 0)
1200
0
        size = gp_ftell(fp);
1201
0
    gp_rewind(fp);
1202
0
    if (size < 0 || size != datasize || (size != gp_fread(data, 1, size, fp))) {
1203
0
        code = -1;
1204
0
    }
1205
0
    gp_fclose(fp);
1206
0
    return code;
1207
0
}
1208
1209
/* set the initial environment to the default environment, this should
1210
   be done at the beginning of each job */
1211
int
1212
pjl_set_init_from_defaults(pjl_parser_state_t * pst)
1213
41.4k
{
1214
41.4k
    int code = free_pjl_environment(pst->mem, &pst->envir);
1215
41.4k
    if (code < 0)
1216
0
        return code;
1217
41.4k
    code = set_pjl_environment(pst->mem, &pst->envir, pst->defaults);
1218
41.4k
    if (code < 0)
1219
0
        return code;
1220
1221
41.4k
    code = free_pjl_fontsource(pst->mem, &pst->font_envir);
1222
41.4k
    if (code < 0)
1223
0
        return code;
1224
41.4k
    return set_pjl_fontsource(pst->mem, &pst->font_envir, pst->font_defaults);
1225
41.4k
}
1226
1227
void
1228
pjl_set_next_fontsource(pjl_parser_state_t * pst)
1229
0
{
1230
0
    int current_source;
1231
0
    pjl_envvar_t *current_font_source = pjl_get_envvar(pst, "fontsource");
1232
1233
    /* find the index of the current resource then work backwards
1234
       until we find font resources.  We assume the internal source
1235
       will have fonts */
1236
0
    for (current_source = 0; pst->font_envir[current_source].designator[0];
1237
0
         current_source++)
1238
0
        if (!pjl_compare(pst->font_envir[current_source].designator,
1239
0
                         current_font_source))
1240
0
            break;
1241
1242
    /* next resource is not internal 'I' */
1243
0
    if (current_source != 0) {
1244
0
        while (current_source > 0) {
1245
0
            current_source--;   /* go to next fontsource */
1246
            /* check if it contains fonts, i.e. fontnumber != null */
1247
0
            if (pst->font_envir[current_source].fontnumber[0])
1248
0
                break;
1249
0
        }
1250
0
    }
1251
    /* set both default and environment font source, the spec is not clear
1252
       about this */
1253
0
    pjl_set(pst, (char *)"fontsource",
1254
0
            pst->font_envir[current_source].designator, true);
1255
0
    pjl_set(pst, (char *)"fontsource",
1256
0
            pst->font_defaults[current_source].designator, false);
1257
0
}
1258
1259
/* get a pjl environment variable from the current environment - not
1260
   the user default environment */
1261
pjl_envvar_t *
1262
pjl_get_envvar(pjl_parser_state * pst, const char *pjl_var)
1263
3.00M
{
1264
3.00M
    int i=0;
1265
3.00M
    pjl_envir_var_t *env = pst->envir;
1266
1267
    /* lookup up the value */
1268
26.1M
    while(env[i].var) {
1269
26.1M
        if (!pjl_compare(env[i].var, pjl_var)) {
1270
3.00M
            return env[i].value;
1271
3.00M
        }
1272
23.1M
        i++;
1273
23.1M
    }
1274
0
    return NULL;
1275
3.00M
}
1276
1277
/* get a pjl environment variable from the current environment - not
1278
   the user default environment */
1279
pjl_envvar_t *
1280
pjl_set_envvar(pjl_parser_state * pst, const char *pjl_var, const char *data)
1281
0
{
1282
0
    int i=0;
1283
0
    pjl_envir_var_t *env = pst->envir;
1284
0
    char *newvalue;
1285
1286
    /* Find the current value */
1287
0
    while(env[i].var) {
1288
0
        if (!pjl_compare(env[i].var, pjl_var)) {
1289
0
            if (env[i].value)
1290
0
                gs_free_object(pst->mem, env[i].value, "pjl_set_envvar value");
1291
0
            newvalue = (char *)gs_alloc_bytes(pst->mem, strlen(data) + 1, "pjl_set_envvar, value");
1292
0
            if (newvalue != NULL) {
1293
0
                strcpy(newvalue, data);
1294
0
                env[i].value = newvalue;
1295
0
            }
1296
0
        }
1297
0
        i++;
1298
0
    }
1299
0
    return NULL;
1300
0
}
1301
1302
/* get a pjl environment variable from the current environment - not
1303
   the user default environment */
1304
pjl_envvar_t *
1305
pjl_set_defvar(pjl_parser_state * pst, const char *pjl_var, const char *data)
1306
0
{
1307
0
    int i=0;
1308
0
    pjl_envir_var_t *env = pst->defaults;
1309
0
    char *newvalue;
1310
1311
    /* Find the current value */
1312
0
    while(env[i].var) {
1313
0
        if (!pjl_compare(env[i].var, pjl_var)) {
1314
0
            if (env[i].value)
1315
0
                gs_free_object(pst->mem, env[i].value, "pjl_set_defvar value");
1316
0
            newvalue = (char *)gs_alloc_bytes(pst->mem, strlen(data) + 1, "pjl_set_defvar, value");
1317
0
            if (newvalue != NULL) {
1318
0
                strcpy(newvalue, data);
1319
0
                env[i].value = newvalue;
1320
0
            }
1321
0
        }
1322
0
        i++;
1323
0
    }
1324
0
    return NULL;
1325
0
}
1326
/*
1327
 * Detect illegal characters when preprocessing each line of PJL.
1328
 */
1329
static inline bool
1330
legal_pjl_char(const byte ch)
1331
1.11M
{
1332
1.11M
    return (ch >= 32 || isspace(ch));
1333
1.11M
}
1334
1335
/* -- public functions - see pjparse.h for interface documentation -- */
1336
1337
/* Process a buffer of PJL commands. */
1338
int
1339
pjl_process(pjl_parser_state * pst, void *pstate, stream_cursor_read * pr)
1340
8.68k
{
1341
8.68k
    const byte *p = pr->ptr;
1342
8.68k
    const byte *rlimit = pr->limit;
1343
8.68k
    int code = 0;
1344
1345
    /* first check if we are writing data to a file as part of the
1346
       file system commands */
1347
1348
1.12M
    while (p < rlimit) {
1349
1.12M
        if (pst->bytes_to_write != 0) {
1350
0
            p++;
1351
0
            if (pjl_write_remaining_data(pst, &p, &rlimit) == 0) {
1352
0
                p--;
1353
0
                continue;
1354
0
            } else
1355
0
                return -1;
1356
0
        }
1357
1358
1.12M
        if (pst->pos == 0) {    /* Look ahead for the @PJL prefix or a UEL. */
1359
43.0k
            uint avail = rlimit - p;
1360
1361
43.0k
            if (!memcmp(p + 1, "\033%-12345X", min(avail, 9))) {        /* Might be a UEL. */
1362
3.50k
                if (avail < 9) {        /* Not enough data to know yet. */
1363
3
                    code = gs_error_NeedInput;
1364
3
                    break;
1365
3
                }
1366
                /* Skip the UEL and continue. */
1367
3.49k
                p += 9;
1368
3.49k
                continue;
1369
39.5k
            } else {
1370
                /* We allow for a single CRLF at the start of a block of PJL.
1371
                 * This is in violation of the spec, but allows us to accept
1372
                 * files like bug 693269. This shouldn't adversely affect any
1373
                 * real world files. */
1374
39.5k
                if (avail > 0 && p[1] == '\r')
1375
31
                    p++, avail--;
1376
39.5k
                if (avail > 0 && p[1] == '\n')
1377
30
                    p++, avail--;
1378
39.5k
                if (!memcmp(p + 1, "@PJL", min(avail, 4))) { /* Might be PJL. */
1379
34.9k
                    if (avail < 4) {        /* Not enough data to know yet. */
1380
11
                        code = gs_error_NeedInput;
1381
11
                        break;
1382
11
                    }
1383
                    /* Definitely a PJL command. */
1384
34.9k
                } else {            /* Definitely not PJL. */
1385
4.64k
                    code = 1;
1386
4.64k
                    break;
1387
4.64k
                }
1388
39.5k
            }
1389
43.0k
        }
1390
1.11M
        if (!legal_pjl_char(p[1])) {
1391
3.82k
            code = 1;
1392
            /* If we haven't read anything yet, then just give up */
1393
3.82k
            if (pst->pos == 0) {
1394
0
                ++p;
1395
0
                break;
1396
0
            }
1397
            /* If we have, process what we had collected already before giving up. */
1398
            /* null terminate, parse and set the pjl state */
1399
3.82k
            pst->line[pst->pos] = '\0';
1400
            /*
1401
             * NB PJL continues not considering normal errors but we
1402
             * ignore memory failure errors here and shouldn't.
1403
             */
1404
3.82k
            (void)pjl_parse_and_process_line(pst);
1405
3.82k
            pst->pos = 0;
1406
3.82k
            break;
1407
3.82k
        }
1408
1.11M
        if (p[1] == '\n') {
1409
30.9k
            ++p;
1410
            /* null terminate, parse and set the pjl state */
1411
30.9k
            pst->line[pst->pos] = '\0';
1412
            /*
1413
             * NB PJL continues not considering normal errors but we
1414
             * ignore memory failure errors here and shouldn't.
1415
             */
1416
30.9k
            (void)pjl_parse_and_process_line(pst);
1417
30.9k
            pst->pos = 0;
1418
30.9k
            continue;
1419
30.9k
        }
1420
1421
        /* Copy the PJL line into the parser's line buffer. */
1422
        /* Always leave room for a terminator. */
1423
1.07M
        if (pst->pos == pst->line_size) {
1424
78
            char *temp = (char *)gs_alloc_bytes (pst->mem, pst->line_size + 256, "pjl_state increase line buffer");
1425
78
            if (temp != NULL) {
1426
78
                memcpy(temp, pst->line, pst->line_size);
1427
78
                gs_free_object(pst->mem, pst->line, "pjl_state line buffer");
1428
78
                pst->line = temp;
1429
78
                pst->line_size += 256;
1430
78
                pst->line[pst->pos] = p[1], pst->pos++;
1431
78
            } else {
1432
0
                code = -1;
1433
0
                break;
1434
0
            }
1435
78
        } else
1436
1.07M
            pst->line[pst->pos] = p[1], pst->pos++;
1437
1.07M
        ++p;
1438
1.07M
    }
1439
8.68k
    pr->ptr = p;
1440
8.68k
    return code;
1441
8.68k
}
1442
1443
/* Discard the remainder of a job.  Return true when we reach a UEL. */
1444
/* The input buffer must be at least large enough to hold an entire UEL. */
1445
bool
1446
pjl_skip_to_uel(stream_cursor_read * pr)
1447
0
{
1448
0
    const byte *p = pr->ptr;
1449
0
    const byte *rlimit = pr->limit;
1450
1451
0
    for (; p < rlimit; ++p)
1452
0
        if (p[1] == '\033') {
1453
0
            uint avail = rlimit - p;
1454
1455
0
            if (memcmp(p + 1, "\033%-12345X", min(avail, 9)))
1456
0
                continue;
1457
0
            if (avail < 9)
1458
0
                break;
1459
0
            pr->ptr = p + 9;
1460
0
            return true;
1461
0
        }
1462
0
    pr->ptr = p;
1463
0
    return false;
1464
0
}
1465
1466
/* PJL symbol set environment variable -> pcl symbol set numbers.
1467
   This probably should not be defined here :-( */
1468
static const struct
1469
{
1470
    const char *symname;
1471
    const int  pcl_code;
1472
} symbol_sets[] = {
1473
    {"ROMAN8",  277},
1474
    {"ISOL1",    14},
1475
    {"ISOL2",    78},
1476
    {"ISOL5",   174},
1477
    {"PC8",     341},
1478
    {"PC8DN",   373},
1479
    {"PC850",   405},
1480
    {"PC852",   565},
1481
    {"PC8TK",   308},
1482
    {"WINL1",   309},
1483
    {"WINL2",   293},
1484
    {"WINL5",   180},
1485
    {"DESKTOP", 234},
1486
    {"PSTEXT",  330},
1487
    {"VNINTL",  426},
1488
    {"VNUS",    458},
1489
    {"MSPUBL",  202},
1490
    {"MATH8",   269},
1491
    {"PSMATH",  173},
1492
    {"VNMATH",  205},
1493
    {"PIFONT",  501},
1494
    {"LEGAL",    53},
1495
    {"ISO4",     37},
1496
    {"ISO6",     21},
1497
    {"ISO11",    19},
1498
    {"ISO15",     9},
1499
    {"ISO17",    83},
1500
    {"ISO21",    39},
1501
    {"ISO60",     4},
1502
    {"ISO69",    38},
1503
    {NULL,       -1}
1504
};
1505
1506
/* map a pjl symbol table name to a pcl symbol table code */
1507
int
1508
pjl_map_pjl_sym_to_pcl_sym(const char *symname)
1509
359k
{
1510
359k
    int i;
1511
1512
1.79M
    for (i = 0; symbol_sets[i].symname; i++)
1513
1.79M
        if (!pjl_compare(symname, symbol_sets[i].symname))
1514
359k
            return symbol_sets[i].pcl_code;
1515
0
    return -1;
1516
359k
}
1517
1518
/* environment variable to integer */
1519
int
1520
pjl_vartoi(const pjl_envvar_t * s)
1521
416k
{
1522
416k
    return atoi(s);
1523
416k
}
1524
1525
/* environment variable to float */
1526
double
1527
pjl_vartof(const pjl_envvar_t * s)
1528
1.07M
{
1529
1.07M
    return atof(s);
1530
1.07M
}
1531
1532
/* convert a pjl font source to a pathname */
1533
char *
1534
pjl_fontsource_to_path(const pjl_parser_state * pjls,
1535
                       const pjl_envvar_t * fontsource)
1536
367k
{
1537
367k
    int i;
1538
1539
    /* if an environment variable is set we use it, otherwise use the PJL
1540
       machinery */
1541
367k
    if (pjls->environment_font_path != NULL)
1542
0
        return pjl_check_font_path(pjls->environment_font_path, pjls->mem);
1543
367k
    for (i = 0; pjls->font_envir[i].designator[0]; i++)
1544
367k
        if (!pjl_compare(pjls->font_envir[i].designator, fontsource))
1545
367k
            return pjl_check_font_path(pjls->font_envir[i].pathname,
1546
367k
                                       pjls->mem);
1547
0
    return NULL;
1548
367k
}
1549
1550
static int set_pjl_defaults_to_factory(gs_memory_t * mem, pjl_envir_var_t **def)
1551
16.1k
{
1552
16.1k
    return set_pjl_defaults(mem, def, (pjl_envir_var_t *)&pjl_factory_defaults);
1553
16.1k
}
1554
1555
static int set_pjl_defaults(gs_memory_t * mem, pjl_envir_var_t **def, pjl_envir_var_t *from)
1556
16.1k
{
1557
16.1k
    pjl_envir_var_t *pjl_def;
1558
16.1k
    char *key, *value, *newkey, *newvalue;
1559
16.1k
    int i = 0;
1560
16.1k
    int limit = 0;
1561
1562
468k
    while (from[limit].var && from[limit].var[0] != 0x00)
1563
452k
        limit++;
1564
1565
16.1k
    pjl_def = (pjl_envir_var_t *) gs_alloc_bytes(mem,
1566
16.1k
                                                  sizeof
1567
16.1k
                                                  (pjl_envir_var_t) * (limit + 1),
1568
16.1k
                                                  "pjl_envir");
1569
16.1k
    if (!pjl_def)
1570
0
        return -1;
1571
1572
16.1k
    memset(pjl_def, 0x00, sizeof(pjl_envir_var_t) * (limit + 1));
1573
468k
    while (i < limit) {
1574
452k
        key = from[i].var;
1575
452k
        value = from[i].value;
1576
1577
452k
        newkey = (char *)gs_alloc_bytes(mem, strlen(key) + 1, "new_pjl_defaults, key");
1578
452k
        newvalue = (char *)gs_alloc_bytes(mem, strlen(value) + 1, "new_pjl_defaults, value");
1579
452k
        if (!newkey || !newvalue) {
1580
0
            gs_free_object(mem, newkey, "new_pjl_defaults, key");
1581
0
            free_pjl_defaults(mem, &pjl_def);
1582
0
            return -1;
1583
0
        }
1584
452k
        strcpy(newkey, key);
1585
452k
        strcpy(newvalue, value);
1586
452k
        pjl_def[i].var = newkey;
1587
452k
        pjl_def[i].value = newvalue;
1588
1589
452k
        i++;
1590
452k
    }
1591
16.1k
    *def = pjl_def;
1592
16.1k
    return 0;
1593
16.1k
}
1594
1595
static int set_pjl_environment_to_factory(gs_memory_t * mem, pjl_envir_var_t **env)
1596
16.1k
{
1597
16.1k
    return set_pjl_environment(mem, env, (pjl_envir_var_t *)&pjl_factory_defaults);
1598
16.1k
}
1599
1600
static int set_pjl_environment(gs_memory_t * mem, pjl_envir_var_t **env, pjl_envir_var_t *from)
1601
57.6k
{
1602
57.6k
    pjl_envir_var_t *pjl_env;
1603
57.6k
    char *key, *value, *newkey, *newvalue;
1604
57.6k
    int i = 0;
1605
57.6k
    int limit = 0;
1606
1607
1.67M
    while (from[limit].var && from[limit].var[0] != 0x00)
1608
1.61M
        limit++;
1609
1610
57.6k
    pjl_env = (pjl_envir_var_t *) gs_alloc_bytes(mem,
1611
57.6k
                                                  (size_t)sizeof
1612
57.6k
                                                  (pjl_envir_var_t) * (limit + 1),
1613
57.6k
                                                  "pjl_envir");
1614
57.6k
    if (!pjl_env)
1615
0
        return -1;
1616
1617
57.6k
    memset(pjl_env, 0x00, sizeof(pjl_envir_var_t) * (limit + 1));
1618
1.67M
    while (i < limit) {
1619
1.61M
        key = from[i].var;
1620
1.61M
        value = from[i].value;
1621
1.61M
        newkey = (char *)gs_alloc_bytes(mem, strlen(key) + 1, "pjl_envir, key");
1622
1.61M
        newvalue = (char *)gs_alloc_bytes(mem, strlen(value) + 1, "pjl_envir, value");
1623
1.61M
        if (!newkey || !newvalue) {
1624
0
            gs_free_object(mem, newkey, "pjl_envir, key");
1625
0
            free_pjl_environment(mem, &pjl_env);
1626
0
            return -1;
1627
0
        }
1628
1.61M
        strcpy(newkey, key);
1629
1.61M
        strcpy(newvalue, value);
1630
1.61M
        pjl_env[i].var = newkey;
1631
1.61M
        pjl_env[i].value = newvalue;
1632
1633
1.61M
        i++;
1634
1.61M
    }
1635
57.6k
    *env = pjl_env;
1636
57.6k
    return 0;
1637
57.6k
}
1638
1639
static int set_pjl_fontsource_to_factory(gs_memory_t * mem, pjl_fontsource_t **fontenv)
1640
16.1k
{
1641
16.1k
    return set_pjl_fontsource(mem, fontenv, (pjl_fontsource_t *)pjl_fontsource_table);
1642
16.1k
}
1643
1644
static int set_pjl_fontsource(gs_memory_t * mem, pjl_fontsource_t **fontenv, pjl_fontsource_t *from)
1645
57.6k
{
1646
57.6k
    pjl_fontsource_t *pjl_fontenv;
1647
57.6k
    char *key, *value, *newkey, *newvalue;
1648
57.6k
    int i = 0;
1649
57.6k
    int limit = 0;
1650
1651
576k
    while (from[limit].pathname && from[limit].pathname[0] != 0x00)
1652
518k
        limit++;
1653
1654
57.6k
    pjl_fontenv = (pjl_fontsource_t *) gs_alloc_bytes(mem,
1655
57.6k
                                                      (size_t)sizeof
1656
57.6k
                                                      (pjl_fontsource_t) * (limit + 1),
1657
57.6k
                                                      "font_envir");
1658
57.6k
    if (!pjl_fontenv)
1659
0
        return -1;
1660
1661
57.6k
    memset(pjl_fontenv, 0x00, sizeof(pjl_fontsource_t) * (limit + 1));
1662
576k
    while (i < limit) {
1663
518k
        key = from[i].pathname;
1664
518k
        value = from[i].fontnumber;
1665
1666
518k
        newkey = (char *)gs_alloc_bytes(mem, strlen(key) + 1, "new_font_envir, pathname");
1667
518k
        if (!newkey) {
1668
0
            free_pjl_fontsource(mem, &pjl_fontenv);
1669
0
            return -1;
1670
0
        }
1671
518k
        strcpy(newkey, key);
1672
518k
        pjl_fontenv[i].pathname = newkey;
1673
518k
        if (value) {
1674
518k
            newvalue = (char *)gs_alloc_bytes(mem, strlen(value) + 1, "new_font_envir, fontnumber");
1675
518k
            if (!newvalue) {
1676
0
                free_pjl_fontsource(mem, &pjl_fontenv);
1677
0
                return -1;
1678
0
            }
1679
518k
            strcpy(newvalue, value);
1680
518k
            pjl_fontenv[i].fontnumber = newvalue;
1681
518k
        } else {
1682
0
            pjl_fontenv[i].fontnumber = 0x00;
1683
0
        }
1684
518k
        memcpy(pjl_fontenv[i].designator, pjl_fontsource_table[i].designator, 2);
1685
1686
518k
        i++;
1687
518k
    }
1688
57.6k
    *fontenv = pjl_fontenv;
1689
57.6k
    return 0;
1690
57.6k
}
1691
1692
static int set_pjl_default_fontsource_to_factory(gs_memory_t * mem, pjl_fontsource_t **fontdef)
1693
16.1k
{
1694
16.1k
    return set_pjl_default_fontsource(mem, fontdef, (pjl_fontsource_t *)&pjl_fontsource_table);
1695
16.1k
}
1696
1697
static int set_pjl_default_fontsource(gs_memory_t * mem, pjl_fontsource_t **fontdef, pjl_fontsource_t *from)
1698
16.1k
{
1699
16.1k
    pjl_fontsource_t *pjl_fontdef;
1700
16.1k
    char *key, *value, *newkey, *newvalue;
1701
16.1k
    int i = 0;
1702
16.1k
    int limit = 0;
1703
1704
161k
    while (from[limit].pathname && from[limit].pathname[0] != 0x00)
1705
145k
        limit++;
1706
1707
16.1k
    pjl_fontdef = (pjl_fontsource_t *) gs_alloc_bytes(mem,
1708
16.1k
                                                      (size_t)sizeof
1709
16.1k
                                                      (pjl_fontsource_t) * (limit + 1),
1710
16.1k
                                                      "new_font_defaults");
1711
16.1k
    if (!pjl_fontdef)
1712
0
        return -1;
1713
1714
16.1k
    memset(pjl_fontdef, 0x00, sizeof(pjl_fontsource_t) * (limit + 1));
1715
161k
    while (i < limit) {
1716
145k
        key = from[i].pathname;
1717
145k
        value = from[i].fontnumber;
1718
1719
145k
        newkey = (char *)gs_alloc_bytes(mem, strlen(key) + 1, "new_font_defaults, pathname");
1720
145k
        if (!newkey) {
1721
0
            free_pjl_default_fontsource(mem, &pjl_fontdef);
1722
0
            return -1;
1723
0
        }
1724
145k
        strcpy(newkey, key);
1725
145k
        pjl_fontdef[i].pathname = newkey;
1726
145k
        if (value) {
1727
145k
            newvalue = (char *)gs_alloc_bytes(mem, strlen(value) + 1, "new_font_defaults, fontnumber");
1728
145k
            if (!newvalue) {
1729
0
                free_pjl_default_fontsource(mem, &pjl_fontdef);
1730
0
                return -1;
1731
0
            }
1732
145k
            strcpy(newvalue, value);
1733
145k
            pjl_fontdef[i].fontnumber = newvalue;
1734
145k
        } else {
1735
0
            pjl_fontdef[i].fontnumber = 0x00;
1736
0
        }
1737
145k
        memcpy(pjl_fontdef[i].designator, pjl_fontsource_table[i].designator, 2);
1738
1739
145k
        i++;
1740
145k
    }
1741
16.1k
    *fontdef = pjl_fontdef;
1742
16.1k
    return 0;
1743
16.1k
}
1744
1745
static int free_pjl_defaults(gs_memory_t * mem, pjl_envir_var_t **def)
1746
16.1k
{
1747
16.1k
    int i=0;
1748
16.1k
    pjl_envir_var_t *pjl_def = *def;
1749
1750
468k
    while (pjl_def[i].var) {
1751
452k
        gs_free_object(mem, pjl_def[i].var, "free pjl_defaults key");
1752
452k
        gs_free_object(mem, pjl_def[i].value, "free pjl_defaults value");
1753
452k
        i++;
1754
452k
    }
1755
16.1k
    gs_free_object(mem, pjl_def, "pjl_defaults");
1756
16.1k
    *def = 0x00;
1757
16.1k
    return 0;
1758
16.1k
}
1759
1760
int free_pjl_environment(gs_memory_t * mem, pjl_envir_var_t **env)
1761
57.6k
{
1762
57.6k
    int i=0;
1763
57.6k
    pjl_envir_var_t *pjl_env = *env;
1764
1765
57.6k
    if (pjl_env == NULL)
1766
0
        return 0;
1767
1768
1.67M
    while (pjl_env[i].var) {
1769
1.61M
        gs_free_object(mem, pjl_env[i].var, "free pjl_environment key");
1770
1.61M
        gs_free_object(mem, pjl_env[i].value, "free pjl_environment value");
1771
1.61M
        i++;
1772
1.61M
    }
1773
57.6k
    gs_free_object(mem, pjl_env, "pjl_environment");
1774
57.6k
    *env = 0x00;
1775
57.6k
    return 0;
1776
57.6k
}
1777
1778
int free_pjl_fontsource(gs_memory_t * mem, pjl_fontsource_t **fontenv)
1779
57.6k
{
1780
57.6k
    int i=0;
1781
57.6k
    pjl_fontsource_t *pjl_fontenv = *fontenv;
1782
1783
57.6k
    if (pjl_fontenv == NULL)
1784
0
        return 0;
1785
1786
576k
    while (pjl_fontenv[i].pathname) {
1787
518k
        gs_free_object(mem, pjl_fontenv[i].pathname, "pjl_font_envir pathname");
1788
518k
        gs_free_object(mem, pjl_fontenv[i].fontnumber, "pjl_font_envir fontnumber");
1789
518k
        i++;
1790
518k
    }
1791
57.6k
    gs_free_object(mem, pjl_fontenv, "pjl_font_envir");
1792
57.6k
    *fontenv = 0x00;
1793
57.6k
    return 0;
1794
57.6k
}
1795
1796
int free_pjl_default_fontsource(gs_memory_t * mem, pjl_fontsource_t **fontdef)
1797
16.1k
{
1798
16.1k
    int i=0;
1799
16.1k
    pjl_fontsource_t *pjl_fontdef = *fontdef;
1800
1801
161k
    while (pjl_fontdef[i].pathname) {
1802
145k
        gs_free_object(mem, pjl_fontdef[i].pathname, "pjl_font_defaults pathname");
1803
145k
        gs_free_object(mem, pjl_fontdef[i].fontnumber, "pjl_font_defaults fontnumber");
1804
145k
        i++;
1805
145k
    }
1806
16.1k
    gs_free_object(mem, pjl_fontdef, "pjl_font_defaults");
1807
16.1k
    *fontdef = 0x00;
1808
16.1k
    return 0;
1809
16.1k
}
1810
1811
/* Create and initialize a new state. */
1812
pjl_parser_state *
1813
pjl_process_init(gs_memory_t * mem)
1814
16.1k
{
1815
16.1k
    pjl_envir_var_t *pjl_env, *pjl_def;
1816
16.1k
    pjl_fontsource_t *pjl_fontenv, *pjl_fontdef;
1817
1818
16.1k
    pjl_parser_state_t *pjlstate = (pjl_parser_state *) gs_alloc_bytes(mem,
1819
16.1k
                                                                       sizeof
1820
16.1k
                                                                       (pjl_parser_state_t),
1821
16.1k
                                                                       "pjl_state");
1822
1823
16.1k
    if (pjlstate == NULL)
1824
0
        return NULL;            /* should be fatal so we don't bother piecemeal frees */
1825
1826
16.1k
    pjlstate->line = (char *)gs_alloc_bytes(mem, 256, "pjl_state line buffer");
1827
16.1k
    if (pjlstate->line == NULL) {
1828
0
        gs_free_object(mem, pjlstate, "pjl_state");
1829
0
        return NULL;
1830
0
    }
1831
16.1k
    pjlstate->line_size = 255;
1832
1833
    /* check for an environment variable */
1834
16.1k
    {
1835
16.1k
        int pathlen, code;
1836
1837
        /* The environment variable exists if the function fails to
1838
           fit in the null - odd but it works.  We allow an
1839
           environment variable to override the font default PJL font
1840
           path for desktop setups */
1841
16.1k
        pathlen = 0;
1842
16.1k
        if ((code = gp_getenv("PCLFONTSOURCE", (char *)0, &pathlen)) < 0) {
1843
0
            char *path =
1844
0
                (char *)gs_alloc_bytes(mem, pathlen + 1, "pjl_font_path");
1845
            /* if the allocation fails we use the pjl fontsource */
1846
0
            if (path == NULL)
1847
0
                pjlstate->environment_font_path = NULL;
1848
0
            else {
1849
0
                const char * const sepr = gp_file_name_separator();
1850
0
                const int lsepr = strlen(sepr);
1851
0
                gp_getenv("PCLFONTSOURCE", path, &pathlen);     /* can't fail */
1852
1853
                /* We want to ensure a trailing "/" is present */
1854
0
                if (gs_file_name_check_separator(path + (pathlen - (lsepr + 1)), lsepr, path + pathlen - 1) != 1) {
1855
0
                    strncat(path, gp_file_name_separator(), pathlen + 1);
1856
0
                }
1857
0
                code = gs_add_control_path(mem, gs_permit_file_reading, path);
1858
0
                if (code < 0) {
1859
0
                    gs_free_object(mem, path, "pjl_font_path");
1860
0
                    goto fail1;
1861
0
                }
1862
0
                pjlstate->environment_font_path = path;
1863
0
            }
1864
0
        } else                  /* environmet variable does not exist use pjl fontsource */
1865
16.1k
            pjlstate->environment_font_path = NULL;
1866
16.1k
    }
1867
1868
    /* initialize the default and initial pjl environment.  We assume
1869
       that these are the same layout as the factory defaults. */
1870
16.1k
    if (set_pjl_defaults_to_factory(mem, &pjl_def) < 0) {
1871
0
        goto fail1;
1872
0
    }
1873
16.1k
    if (set_pjl_environment_to_factory(mem, &pjl_env) < 0) {
1874
0
        goto fail2;
1875
0
    }
1876
16.1k
    if (set_pjl_fontsource_to_factory(mem, &pjl_fontenv) < 0) {
1877
0
        goto fail3;
1878
0
    }
1879
16.1k
    if (set_pjl_default_fontsource_to_factory(mem, &pjl_fontdef) < 0) {
1880
0
        goto fail4;
1881
0
    }
1882
1883
    /* initialize the font repository data as well */
1884
16.1k
    pjlstate->defaults = pjl_def;
1885
16.1k
    pjlstate->envir = pjl_env;
1886
16.1k
    pjlstate->font_envir = pjl_fontenv;
1887
16.1k
    pjlstate->font_defaults = pjl_fontdef;
1888
1889
    /* initialize the current position in the line array and bytes pending */
1890
16.1k
    pjlstate->bytes_to_read = 0;
1891
16.1k
    pjlstate->bytes_to_write = 0;
1892
16.1k
    pjlstate->fp = 0;
1893
    /* line pos */
1894
16.1k
    pjlstate->pos = 0;
1895
16.1k
    pjlstate->mem = mem;
1896
    /* initialize available font sources */
1897
16.1k
    pjl_reset_fontsource_fontnumbers(pjlstate);
1898
16.1k
    {
1899
16.1k
        int i;
1900
1901
532k
        for (i = 0; i < countof(pjlstate->permanent_soft_fonts); i++)
1902
516k
            pjlstate->permanent_soft_fonts[i] = 0;
1903
16.1k
    }
1904
16.1k
    return (pjl_parser_state *) pjlstate;
1905
1906
0
fail4:
1907
0
    free_pjl_fontsource(mem, &pjl_fontenv);
1908
0
fail3:
1909
0
    free_pjl_environment(mem, &pjl_env);
1910
0
fail2:
1911
0
    free_pjl_defaults(mem, &pjl_def);
1912
0
fail1:
1913
0
    gs_free_object(mem, pjlstate->line, "pjl_state line buffer");
1914
0
    gs_free_object(mem, pjlstate, "pjl_state");
1915
0
    return NULL;
1916
0
}
1917
1918
/* case insensitive comparison of two null terminated strings. */
1919
int
1920
pjl_compare(const pjl_envvar_t * s1, const char *s2)
1921
32.0M
{
1922
65.4M
    for (; toupper(*s1) == toupper(*s2); ++s1, ++s2)
1923
37.4M
        if (*s1 == '\0')
1924
4.04M
            return (0);
1925
28.0M
    return 1;
1926
32.0M
}
1927
1928
/* free all memory associated with the PJL state */
1929
void
1930
pjl_process_destroy(pjl_parser_state * pst)
1931
16.1k
{
1932
16.1k
    gs_memory_t *mem;
1933
1934
16.1k
    if (pst == NULL)
1935
0
        return;
1936
1937
16.1k
    mem = pst->mem;
1938
1939
16.1k
    free_pjl_defaults(mem, &pst->defaults);
1940
16.1k
    free_pjl_environment(mem, &pst->envir);
1941
16.1k
    free_pjl_fontsource(mem, &pst->font_envir);
1942
16.1k
    free_pjl_default_fontsource(mem, &pst->font_defaults);
1943
1944
16.1k
    if (pst->environment_font_path)
1945
0
        gs_free_object(mem, pst->environment_font_path, "pjl_state");
1946
16.1k
    gs_free_object(mem, pst->line, "pjl_state line buffer");
1947
16.1k
    gs_free_object(mem, pst, "pjl_state");
1948
16.1k
}
1949
1950
/* delete a permanent soft font */
1951
int
1952
pjl_register_permanent_soft_font_deletion(pjl_parser_state * pst,
1953
                                          int font_number)
1954
0
{
1955
0
    if ((font_number > MAX_PERMANENT_FONTS - 1) || (font_number < 0)) {
1956
0
        dmprintf(pst->mem,
1957
0
                 "pjparse.c:pjl_register_permanent_soft_font_deletion() bad font number\n");
1958
0
        return 0;
1959
0
    }
1960
    /* if the font is present. */
1961
0
    if ((pst->permanent_soft_fonts[font_number >> 3]) &
1962
0
        (128 >> (font_number & 7))) {
1963
        /* set the bit to zero to indicate the fontnumber has been deleted */
1964
0
        pst->permanent_soft_fonts[font_number >> 3] &=
1965
0
            ~(128 >> (font_number & 7));
1966
        /* if the current font source is 'S' and the current font number
1967
           is the highest number, and *any* soft font was deleted or if
1968
           the last font has been removed, set the stage for changing to
1969
           the next priority font source.  BLAME HP not me. */
1970
0
        {
1971
0
            bool is_S = !pjl_compare(pjl_get_envvar(pst, "fontsource"), "S");
1972
0
            bool empty = true;
1973
0
            int highest_fontnumber = -1;
1974
0
            int current_fontnumber =
1975
0
                pjl_vartoi(pjl_get_envvar(pst, "fontnumber"));
1976
0
            int i;
1977
1978
            /* check for no more fonts and the highest font number.
1979
               NB should look at longs not bits in the loop */
1980
0
            for (i = 0; i < MAX_PERMANENT_FONTS; i++)
1981
0
                if ((pst->permanent_soft_fonts[i >> 3]) & (128 >> (i & 7))) {
1982
0
                    empty = false;
1983
0
                    highest_fontnumber = i;
1984
0
                }
1985
0
            if (is_S && ((highest_fontnumber == current_fontnumber) || empty)) {
1986
0
#define SINDEX 4
1987
0
                pst->font_defaults[SINDEX].fontnumber[0] = '\0';
1988
0
                pst->font_envir[SINDEX].fontnumber[0] = '\0';
1989
0
                return 1;
1990
0
#undef SINDEX
1991
0
            }
1992
0
        }
1993
0
    }
1994
0
    return 0;
1995
0
}
1996
1997
/* request that pjl add a soft font and return a pjl font number for
1998
   the font. */
1999
int
2000
pjl_register_permanent_soft_font_addition(pjl_parser_state * pst)
2001
0
{
2002
    /* Find an empty slot in the table.  We have no HP documentation
2003
       that says how a soft font gets associated with a font number */
2004
0
    int font_num;
2005
0
    bool slot_found = false;
2006
2007
0
    for (font_num = 0; font_num < MAX_PERMANENT_FONTS; font_num++)
2008
0
        if (!
2009
0
            ((pst->permanent_soft_fonts[font_num >> 3]) &
2010
0
             (128 >> (font_num & 7)))) {
2011
0
            slot_found = true;
2012
0
            break;
2013
0
        }
2014
    /* yikes, shouldn't happen */
2015
0
    if (!slot_found) {
2016
0
        dmprintf(pst->mem,
2017
0
                 "pjparse.c:pjl_register_permanent_soft_font_addition()\
2018
0
                 font table full recycling font number 0\n");
2019
0
        font_num = 0;
2020
0
    }
2021
    /* set the bit to 1 to indicate the fontnumber has been added */
2022
0
    pst->permanent_soft_fonts[font_num >> 3] |= (128 >> (font_num & 7));
2023
0
    return font_num;
2024
0
}