Coverage Report

Created: 2026-04-09 07:06

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
12.1M
#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
222
#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
222
#define LETTER_PAPER_INDEX 1
282
283
static int
284
pjl_get_media_index(const char *paper)
285
222
{
286
222
    int i;
287
288
9.76k
    for (i = 0; i < countof(pjl_media); i++)
289
9.54k
        if (!pjl_compare(paper, pjl_media[i].media_name))
290
0
            return i;
291
222
    return LETTER_PAPER_INDEX;
292
222
}
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
222
{
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
222
    double formlines = (page_length - 300.0) / 50.0;
309
310
222
    return (int)(formlines + 0.5);
311
222
}
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.00k
{
319
7.00k
    if (!pjl_compare(variable, "PAPER") ||
320
6.78k
        !pjl_compare(variable, "ORIENTATION")) {
321
322
222
        pjl_envir_var_t *table = (defaults ? pst->defaults : pst->envir);
323
222
        int indx = pjl_get_media_index(table[FDEF_PAPER_INDX].value);
324
222
        int page_length = (!pjl_compare(variable, "ORIENTATION") &&
325
0
                           !pjl_compare(value, "LANDSCAPE") ?
326
0
                           (int)(pjl_media[indx].width) :
327
222
                           (int)(pjl_media[indx].height));
328
222
        int formlines = pjl_calc_formlines_new_page_size(page_length);
329
222
        char text[32];
330
331
222
        gs_snprintf(text, sizeof(text), "%d", formlines);
332
222
        pjl_set(pst, (char *)"FORMLINES", text, defaults);
333
222
    }
334
    /* fill in other side effects here */
335
7.00k
    return;
336
7.00k
}
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.00k
{
342
7.00k
    pjl_envir_var_t *table = (defaults ? pst->defaults : pst->envir);
343
7.00k
    int i=0;
344
345
7.00k
    if (defaults)               /* default also sets current environment. */
346
0
        pjl_set(pst, variable, value, false);
347
348
133k
    while (table[i].var) {
349
133k
        if (!pjl_compare(table[i].var, variable)) {
350
            /* set the value */
351
7.00k
            char *newvalue = (char *)gs_alloc_bytes(pst->mem, strlen(value) + 1, "pjl_set, create new value");
352
7.00k
            if (!newvalue)
353
0
                return 0;
354
7.00k
            strcpy(newvalue, value);
355
7.00k
            gs_free_object(pst->mem, table[i].value, "pjl_set free old value");
356
7.00k
            table[i].value = newvalue;
357
            /* set any side effects of setting the value */
358
7.00k
            pjl_side_effects(pst, variable, value, defaults);
359
7.00k
            return 1;
360
7.00k
        }
361
126k
        i++;
362
126k
    }
363
    /* didn't find variable */
364
0
    return 0;
365
7.00k
}
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
132k
{
371
132k
    int c;
372
132k
    int start_pos;
373
    /* skip any whitespace if we need to.  */
374
188k
    while ((c = pst->line[pst->pos]) == ' ' || c == '\t')
375
55.8k
        pst->pos++;
376
377
    /* special case to allow = with no intevervening spaces between
378
       lhs and rhs */
379
132k
    if (c == '=') {
380
18.2k
        pst->pos++;
381
18.2k
        return EQUAL;
382
18.2k
    }
383
384
    /* set the starting position */
385
114k
    start_pos = pst->pos;
386
387
    /* end of line reached; null shouldn't happen but we check anyway */
388
114k
    if (c == '\0' || c == '\n')
389
6.35k
        return DONE;
390
391
    /* check for a quoted string.  It should not span a line */
392
107k
    if (c == '"') {
393
2.05k
        pst->pos++;
394
40.4k
        while ((c = pst->line[pst->pos]) != '"' && c != '\0' && c != '\n')
395
38.4k
            pst->pos++;
396
        /* this routine doesn't yet support real error handling - here
397
           we should check if c == '"' */
398
2.05k
        if (c == '"')
399
1.87k
            pst->pos++;
400
183
        else
401
183
            return DONE;
402
105k
    } else {
403
        /* set the ptr to the next delimeter. */
404
627k
        while ((c = pst->line[pst->pos]) != ' ' &&
405
563k
               c != '\t' && c != '\r' && c != '\n' && c != '=' && c != '\0')
406
521k
            pst->pos++;
407
105k
    }
408
409
    /* build the token */
410
107k
    {
411
107k
        int slength = pst->pos - start_pos;
412
107k
        int i;
413
414
        /* we allow = to special case for allowing
415
           token doesn't fit or is empty */
416
107k
        if (slength == 0)
417
6.07k
            return DONE;
418
        /* now the string can be safely copied */
419
101k
        strncpy(token, &pst->line[start_pos], slength);
420
101k
        token[slength] = '\0';
421
422
        /* for known tokens */
423
1.43M
        for (i = 0; pjl_table[i].pjl_string[0]; i++)
424
1.38M
            if (!pjl_compare(pjl_table[i].pjl_string, token))
425
51.6k
                return pjl_table[i].pjl_token;
426
427
        /* NB add other cases here */
428
        /* check for variables that we support */
429
50.0k
        i = 0;
430
1.38M
        while (pst->envir[i].var) {
431
1.34M
            if (!pjl_compare(pst->envir[i].var, token))
432
6.80k
                return VARIABLE;
433
1.33M
            i++;
434
1.33M
        }
435
436
        /* NB assume this is a setting yuck */
437
43.1k
        return SETTING;
438
50.0k
    }
439
    /* shouldn't happen */
440
0
    return DONE;
441
50.0k
}
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
290k
{
447
    /* lookup a font path and check if any files (presumably fonts are
448
       present) */
449
290k
    char path[PJL_PATH_NAME_LENGTH + 1];
450
290k
    char *pathp = path, *tplast = NULL;
451
290k
    const char pattern[] = "*";
452
290k
    char path_and_pattern[PJL_PATH_NAME_LENGTH + 1 + 1];    /* pattern + null */
453
290k
    char *dirname;
454
290k
    char fontfilename[MAXPATHLEN + 1];
455
456
    /* Ignore error if the path list is too long, a single path may be
457
       okay. */
458
290k
    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
434k
    while ((dirname = gs_strtok(pathp, ";", &tplast)) != NULL) {
463
290k
        file_enum *fe;
464
465
290k
        if (gs_strlcpy(path_and_pattern, dirname, sizeof(path_and_pattern)) >= sizeof(path_and_pattern))
466
0
            continue;
467
468
290k
        if (gs_strlcat(path_and_pattern, pattern, sizeof(path_and_pattern)) >= sizeof(path_and_pattern))
469
0
            continue;
470
471
290k
        fe = gs_enumerate_files_init(mem, path_and_pattern,
472
290k
                                     strlen(path_and_pattern));
473
290k
        if (fe == NULL
474
290k
            ||
475
290k
            (gs_enumerate_files_next(mem, fe, fontfilename, PJL_PATH_NAME_LENGTH))
476
290k
            == -1) {
477
143k
            pathp = NULL;
478
146k
        } 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
11.8M
            while (1) {
484
11.8M
                int fstatus =
485
11.8M
                    (int)gs_enumerate_files_next(mem, fe, fontfilename,
486
11.8M
                                                 PJL_PATH_NAME_LENGTH);
487
                /* we don't care if the file does not fit (return +1) */
488
11.8M
                if (fstatus == -1)
489
146k
                    break;
490
11.8M
            }
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
146k
            if (strlen(path_list) < strlen(dirname))
495
0
                return NULL;
496
146k
            else {
497
146k
                strcpy(path_list, dirname);
498
146k
                return path_list;
499
146k
            }
500
146k
        }
501
290k
    }
502
143k
    return NULL;
503
290k
}
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
8.97k
{
513
8.97k
    char default_font_number[] = {0x30, 0x00};   /* default number if resources are present */
514
8.97k
    gs_memory_t *mem = pst->mem;
515
8.97k
    int i;
516
8.97k
    char *newvalue;
517
518
89.7k
    for (i = 0; pst->font_defaults[i].designator[0]; i++) {
519
80.7k
        if (pjl_check_font_path(pst->font_defaults[i].pathname, mem)) {
520
8.97k
            newvalue = (char *)gs_alloc_bytes(mem, strlen(default_font_number) + 1, "pjl_reset_fontsource_fontnumbers, create new value");
521
8.97k
            if (newvalue) {
522
8.97k
                gs_free_object(mem, pst->font_defaults[i].fontnumber, "pjl_reset_fontsource_fontnumbers");
523
8.97k
                strcpy(newvalue, default_font_number);
524
8.97k
                pst->font_defaults[i].fontnumber = newvalue;
525
8.97k
            }
526
8.97k
        }
527
80.7k
        if (pjl_check_font_path(pst->font_envir[i].pathname, mem)) {
528
8.97k
            newvalue = (char *)gs_alloc_bytes(mem, strlen(default_font_number) + 1, "pjl_reset_fontsource_fontnumbers, create new value");
529
8.97k
            if (newvalue) {
530
8.97k
                gs_free_object(mem, pst->font_envir[i].fontnumber, "pjl_reset_fontsource_fontnumbers");
531
8.97k
                strcpy(newvalue, default_font_number);
532
8.97k
                pst->font_envir[i].fontnumber = newvalue;
533
8.97k
            }
534
8.97k
        }
535
80.7k
    }
536
8.97k
}
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
            fontfilename[fstatus] = '\0';
771
0
            if (fontfilename[fstatus - 1] != '.') {     /* skip over . and .. */
772
                /* a directory */
773
0
                if ((stat(fontfilename, &stbuf) >= 0) && stat_is_dir(stbuf))
774
0
                    pjl_search_for_file(pst, fontfilename, filename, result);
775
0
                else /* a file */
776
0
                if (!strcmp(strrchr(fontfilename, '/') + 1, filename))
777
0
                    strcpy(result, fontfilename);
778
0
            }
779
780
0
        } while (1);
781
0
    }
782
    /* not implemented */
783
0
    return -1;
784
0
}
785
786
static int
787
pjl_fsdirlist(pjl_parser_state_t * pst, char *pathname, int entry, int count)
788
0
{
789
0
    file_enum *fe;
790
0
    char fontfilename[MAXPATHLEN + 2];
791
792
0
    pjl_parsed_filename_to_string(fontfilename, pathname);
793
0
    if (pjl_verify_file_operation(pst, fontfilename, NULL) < 0)
794
0
        return -1;
795
796
    /* if this is a directory add * for the directory listing NB fix */
797
0
    strcat(fontfilename, "/*");
798
0
    fe = gs_enumerate_files_init(pst->mem, fontfilename, strlen(fontfilename));
799
0
    if (fe) {
800
0
        do {
801
0
            uint fstatus =
802
0
                gs_enumerate_files_next(pst->mem, fe, fontfilename,
803
0
                                        PJL_PATH_NAME_LENGTH);
804
            /* done */
805
0
            if (fstatus == ~(uint) 0)
806
0
                return 0;
807
0
            fontfilename[fstatus] = '\0';
808
            /* NB - debugging output only */
809
0
            dmprintf1(pst->mem, "%s\n", fontfilename);
810
0
        } while (1);
811
0
    }
812
    /* should not get here */
813
0
    return -1;
814
0
}
815
816
inline static int
817
pjl_write_remaining_data(pjl_parser_state_t * pst, const byte ** pptr,
818
                         const byte ** pplimit)
819
0
{
820
0
    const byte *ptr = *pptr;
821
0
    const byte *plimit = *pplimit;
822
0
    uint avail = plimit - ptr;
823
0
    uint bytes_written = min(avail, pst->bytes_to_write);
824
825
0
    if (gp_fwrite(ptr, 1, bytes_written, pst->fp) != bytes_written) {
826
        /* try to close the file before failing */
827
0
        gp_fclose(pst->fp);
828
0
        pst->fp = NULL;
829
0
        return -1;
830
0
    }
831
0
    pst->bytes_to_write -= bytes_written;
832
0
    if (pst->bytes_to_write == 0) {     /* done */
833
0
        gp_fclose(pst->fp);
834
0
        pst->fp = NULL;
835
0
    }
836
    /* update stream pointer */
837
0
    *pptr += bytes_written;
838
0
    return 0;
839
0
}
840
841
static int
842
pjl_delete_file(pjl_parser_state_t * pst, char *pathname)
843
0
{
844
0
    char fname[MAXPATHLEN];
845
846
0
    pjl_parsed_filename_to_string(fname, pathname);
847
0
    if (pjl_verify_file_operation(pst, fname, NULL) < 0)
848
0
        return -1;
849
0
    return gp_unlink(pst->mem, fname);
850
0
}
851
852
/* handle pattern foo = setting, e.g. volume = "0:", name = 0:]pcl.
853
   the setting will be returned in "token" if successful.  Return 0
854
   for success and -1 if we fail */
855
static int
856
pjl_get_setting(pjl_parser_state_t * pst, pjl_token_type_t tok, char *token)
857
0
{
858
0
    pjl_token_type_t lhs = pjl_get_token(pst, token);
859
860
0
    if (lhs != tok)
861
0
        return -1;
862
0
    if ((tok = pjl_get_token(pst, token)) != EQUAL)
863
0
        return -1;
864
0
    if ((tok = pjl_get_token(pst, token)) != SETTING)
865
0
        return -1;
866
0
    return 0;
867
0
}
868
869
static int
870
gs_set(pjl_parser_state_t *pst, const char *variable, const char *token, int string)
871
0
{
872
0
    int code;
873
0
    int len1 = strlen(variable)+1;
874
0
    int len2 = token == NULL ? 0 : strlen(token)+1;
875
0
    char *buffer = (char *)gs_alloc_bytes(pst->mem, len1+len2, "gs_set buffer");
876
877
0
    if (buffer == NULL)
878
0
        return -1;
879
880
0
    strcpy(buffer, variable);
881
0
    if (len2) {
882
0
        strcat(buffer, "=");
883
0
        strcat(buffer, token);
884
0
    }
885
886
0
    if (string)
887
0
        code = pl_main_set_string_param(pl_main_get_instance(pst->mem), buffer);
888
0
    else
889
0
        code = pl_main_set_param(pl_main_get_instance(pst->mem), buffer);
890
0
    gs_free_object(pst->mem, buffer, "gs_set buffer");
891
892
0
    return code;
893
0
}
894
895
896
/* parse and set up state for one line of pjl commands */
897
static int
898
pjl_parse_and_process_line(pjl_parser_state_t * pst)
899
31.7k
{
900
31.7k
    pjl_token_type_t tok;
901
31.7k
    char *token;
902
31.7k
    char pathname[MAXPATHLEN];
903
31.7k
    int bufsize = pst->pos + 1, code;
904
905
31.7k
    token = (char *)gs_alloc_bytes(pst->mem, bufsize, "working buffer for PJL parsing");
906
31.7k
    if (token == 0)
907
0
        return -1;
908
909
31.7k
    memset(token, 0x00, bufsize);
910
31.7k
    memset(pathname, 0x00, sizeof(pathname));
911
912
    /* reset the line position to the beginning of the line */
913
31.7k
    pst->pos = 0;
914
    /* all pjl commands start with the pjl prefix @PJL */
915
31.7k
    if ((tok = pjl_get_token(pst, token)) != PREFIX) {
916
149
        gs_free_object(pst->mem, token, "working buffer for PJL parsing");
917
149
        return -1;
918
149
    }
919
    /* NB we should check for required and optional used of whitespace
920
       but we don't see PJLTRM 2-6 PJL Command Syntax and Format. */
921
31.5k
    while ((tok = pjl_get_token(pst, token)) != DONE) {
922
31.5k
        switch (tok) {
923
16.1k
            case SET:
924
16.6k
            case DEFAULT:
925
16.6k
                {
926
16.6k
                    bool defaults;
927
928
19.3k
                    var:defaults = (tok == DEFAULT);
929
                    /* NB we skip over lparm and search for the variable */
930
55.6k
                    while ((tok = pjl_get_token(pst, token)) != DONE)
931
43.0k
                        if (tok == VARIABLE) {
932
6.79k
                            char *variable;
933
934
6.79k
                            variable = (char *)gs_alloc_bytes(pst->mem, bufsize, "2nd working buffer for PJL parsing");
935
6.79k
                            if (variable == 0) {
936
0
                                gs_free_object(pst->mem, token, "2nd working buffer for PJL parsing");
937
0
                                return -1;
938
0
                            }
939
6.79k
                            memset(variable, 0x00, bufsize);
940
941
6.79k
                            strcpy(variable, token);
942
6.79k
                            if (((tok = pjl_get_token(pst, token)) == EQUAL)
943
6.79k
                                && (tok = pjl_get_token(pst, token)) == SETTING) {
944
                                /* an unfortunate side effect - we have to
945
                                   identify FORMLINES being set here, for
946
                                   the benefit of PCL, see the
947
                                   documentation to the function
948
                                   pcursor.c:pcl_vmi_default() for
949
                                   details. */
950
6.78k
                                if (!pjl_compare(variable, "FORMLINES"))
951
0
                                    pjl_set(pst, (char *)"FORMLINES_SET",
952
0
                                            (char *)"on", defaults);
953
6.78k
                                code = pjl_set(pst, variable, token,
954
6.78k
                                               defaults);
955
6.78k
                            } else
956
12
                                code = -1; /* syntax error */
957
6.79k
                            gs_free_object(pst->mem, variable, "2nd working buffer for PJL parsing");
958
6.79k
                            gs_free_object(pst->mem, token, "working buffer for PJL parsing");
959
6.79k
                            return code;
960
6.79k
                        } else
961
36.2k
                            continue;
962
963
12.5k
                    gs_free_object(pst->mem, token, "working buffer for PJL parsing");
964
12.5k
                    return 0;
965
19.3k
                }
966
0
            case GSSET:
967
0
            case GSSETSTRING:
968
0
                {
969
0
                    bool string;
970
971
0
                    string = (tok == GSSETSTRING);
972
0
                    code = 0;
973
0
                    while ((tok = pjl_get_token(pst, token)) != DONE)
974
0
                        if (tok == VARIABLE || tok == SETTING) {
975
0
                            int len1 = strlen(token)+1;
976
0
                            char *variable = (char *)gs_alloc_bytes(pst->mem, len1,
977
0
                                                                    "2nd working buffer for PJL parsing");
978
0
                            if (variable == NULL)
979
0
                                code = -1;
980
0
                            else {
981
0
                                strcpy(variable, token);
982
0
                                if (((tok = pjl_get_token(pst, token)) == EQUAL) &&
983
0
                                    ((tok = pjl_get_token(pst, token)) == SETTING))
984
0
                                    code = gs_set(pst, variable, token, string);
985
0
                                else
986
0
                                    code = gs_set(pst, variable, NULL, string);
987
0
                                gs_free_object(pst->mem, variable, "2nd working buffer for PJL parsing");
988
0
                            }
989
0
                            break;
990
0
                        }
991
992
0
                    gs_free_object(pst->mem, token, "working buffer for PJL parsing");
993
0
                    return code;
994
0
                }
995
0
            case INITIALIZE:
996
                /* set the user default environment to the factory default environment */
997
0
                free_pjl_defaults(pst->mem, &pst->defaults);
998
0
                set_pjl_defaults_to_factory(pst->mem, &pst->defaults);
999
0
                free_pjl_default_fontsource(pst->mem, &pst->font_defaults);
1000
0
                set_pjl_default_fontsource_to_factory(pst->mem, &pst->font_defaults);
1001
0
                pjl_reset_fontsource_fontnumbers(pst);
1002
0
                gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1003
0
                return 0;
1004
                /* set the current environment to the user default environment */
1005
0
            case RESET:
1006
0
                free_pjl_defaults(pst->mem, &pst->defaults);
1007
0
                set_pjl_environment_to_factory(pst->mem, &pst->defaults);
1008
0
                free_pjl_fontsource(pst->mem, &pst->font_envir);
1009
0
                set_pjl_fontsource_to_factory(pst->mem, &pst->font_envir);
1010
0
                gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1011
0
                return 0;
1012
2.71k
            case ENTER:
1013
                /* there is no setting for the default language */
1014
2.71k
                tok = SET;
1015
2.71k
                goto var;
1016
0
            case FSDOWNLOAD:{
1017
                    /* consume and ignore FORMAT:BINARY foolishness. if it is
1018
                       present or search for the name */
1019
0
                    int size;
1020
1021
                    /* ignore format binary stuff */
1022
0
                    if ((tok = pjl_get_token(pst, token)) == FORMATBINARY) {
1023
0
                        ;
1024
0
                    }
1025
0
                    if (pjl_get_setting(pst, NAME, token) < 0 ||
1026
0
                        strlen(token) > MAXPATHLEN - 1)
1027
0
                        return -1;
1028
0
                    strcpy(pathname, token);
1029
0
                    if (pjl_get_setting(pst, SIZE, token) < 0)
1030
0
                        return -1;
1031
0
                    size = pjl_vartoi(token);
1032
0
                    gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1033
0
                    return pjl_set_fs_download_state(pst, pathname, size);
1034
0
                }
1035
0
            case FSAPPEND:{
1036
0
                    int size;
1037
1038
0
                    if ((tok = pjl_get_token(pst, token)) == FORMATBINARY) {
1039
0
                        ;
1040
0
                    }
1041
0
                    if (pjl_get_setting(pst, NAME, token) < 0 ||
1042
0
                        strlen(token) > MAXPATHLEN - 1)
1043
0
                        return -1;
1044
0
                    strcpy(pathname, token);
1045
0
                    if (pjl_get_setting(pst, SIZE, token) < 0)
1046
0
                        return -1;
1047
0
                    size = pjl_vartoi(token);
1048
0
                    gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1049
0
                    return pjl_set_append_state(pst, pathname, size);
1050
0
                }
1051
0
            case FSDELETE:
1052
0
                if (pjl_get_setting(pst, NAME, token) < 0 ||
1053
0
                    strlen(token) > MAXPATHLEN - 1)
1054
0
                    return -1;
1055
0
                strcpy(pathname, token);
1056
0
                gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1057
0
                return pjl_delete_file(pst, pathname);
1058
0
            case FSDIRLIST:{
1059
0
                    int entry;
1060
1061
0
                    int count;
1062
1063
0
                    if (pjl_get_setting(pst, NAME, token) < 0 ||
1064
0
                        strlen(token) > MAXPATHLEN - 1) {
1065
0
                        gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1066
0
                        return -1;
1067
0
                    }
1068
0
                    strcpy(pathname, token);
1069
0
                    if (pjl_get_setting(pst, ENTRY, token) < 0) {
1070
0
                        gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1071
0
                        return -1;
1072
0
                    }
1073
0
                    entry = pjl_vartoi(token);
1074
0
                    if (pjl_get_setting(pst, COUNT, token) < 0) {
1075
0
                        gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1076
0
                        return -1;
1077
0
                    }
1078
0
                    count = pjl_vartoi(token);
1079
0
                    gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1080
0
                    return pjl_fsdirlist(pst, pathname, entry, count);
1081
0
                }
1082
0
            case FSINIT:
1083
0
                if (pjl_get_setting(pst, VOLUME, token) < 0 ||
1084
0
                    strlen(token) > MAXPATHLEN - 1) {
1085
0
                    gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1086
0
                    return -1;
1087
0
                }
1088
0
                strcpy(pathname, token);
1089
0
                gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1090
0
                return pjl_fsinit(pst, pathname);
1091
0
            case FSMKDIR:
1092
0
                if (pjl_get_setting(pst, NAME, token) < 0 ||
1093
0
                    strlen(token) > MAXPATHLEN - 1) {
1094
0
                    gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1095
0
                    return -1;
1096
0
                }
1097
0
                strcpy(pathname, token);
1098
0
                gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1099
0
                return pjl_fsmkdir(pst, pathname);
1100
0
            case FSQUERY:
1101
0
                if (pjl_get_setting(pst, NAME, token) < 0 ||
1102
0
                    strlen(token) > MAXPATHLEN - 1) {
1103
0
                    gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1104
0
                    return -1;
1105
0
                }
1106
0
                strcpy(pathname, token);
1107
0
                gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1108
0
                return pjl_fsquery(pst, pathname);
1109
0
            case FSUPLOAD:{
1110
0
                    int size;
1111
1112
0
                    int offset;
1113
1114
0
                    if ((tok = pjl_get_token(pst, token)) == FORMATBINARY) {
1115
0
                        ;
1116
0
                    }
1117
0
                    if (pjl_get_setting(pst, NAME, token) < 0 ||
1118
0
                        strlen(token) > MAXPATHLEN - 1) {
1119
0
                        gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1120
0
                        return -1;
1121
0
                    }
1122
0
                    strcpy(pathname, token);
1123
0
                    if (pjl_get_setting(pst, OFFSET, token) < 0) {
1124
0
                        gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1125
0
                        return -1;
1126
0
                    }
1127
0
                    offset = pjl_vartoi(token);
1128
0
                    if (pjl_get_setting(pst, SIZE, token) < 0) {
1129
0
                        gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1130
0
                        return -1;
1131
0
                    }
1132
0
                    size = pjl_vartoi(token);
1133
0
                    gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1134
0
                    return pjl_fsupload(pst, pathname, offset, size);
1135
0
                }
1136
12.1k
            default:
1137
12.1k
                gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1138
12.1k
                return -1;
1139
31.5k
        }
1140
31.5k
    }
1141
60
    gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1142
60
    return 0;
1143
31.5k
}
1144
1145
/* get a file from 0: or 1: volume */
1146
static gp_file *
1147
get_fp(pjl_parser_state_t * pst, char *name)
1148
0
{
1149
0
    char result[MAXPATHLEN];
1150
1151
    /* 0: */
1152
0
    result[0] = '\0';
1153
0
    pjl_search_for_file(pst, (char *)PJL_VOLUME_0, name, result);
1154
0
    if (result[0] == '\0') {
1155
        /* try 1: */
1156
0
        pjl_search_for_file(pst, (char *)PJL_VOLUME_1, name, result);
1157
0
        if (result[0] == '\0')
1158
0
            return 0;
1159
0
    }
1160
0
    return gp_fopen(pst->mem, result, gp_fmode_rb);
1161
0
}
1162
1163
/* scan for a named resoource in the pcl sandbox 0: or 1: and return
1164
   the size of the object.  We do not distinguish between empty and
1165
   non-existant files */
1166
long int
1167
pjl_get_named_resource_size(pjl_parser_state_t * pst, char *name)
1168
0
{
1169
0
    long int size;
1170
0
    gp_file *fp = get_fp(pst, name);
1171
1172
0
    if (fp == NULL)
1173
0
        return 0;
1174
0
    size = gp_fseek(fp, 0L, SEEK_END);
1175
0
    if (size >= 0)
1176
0
        size = gp_ftell(fp);
1177
0
    else
1178
0
        size = 0;
1179
0
    gp_fclose(fp);
1180
0
    return size;
1181
0
}
1182
1183
/* get the contents of a file on 0: or 1: and return the result in the
1184
   client allocated memory */
1185
int
1186
pjl_get_named_resource(pjl_parser_state * pst, char *name, byte * data, long int datasize)
1187
0
{
1188
0
    long int size;
1189
0
    int code = 0;
1190
0
    gp_file *fp = get_fp(pst, name);
1191
1192
0
    if (fp == NULL)
1193
0
        return 0;
1194
0
    size = gp_fseek(fp, 0L, SEEK_END);
1195
0
    if (size >= 0)
1196
0
        size = gp_ftell(fp);
1197
0
    gp_rewind(fp);
1198
0
    if (size < 0 || size != datasize || (size != gp_fread(data, 1, size, fp))) {
1199
0
        code = -1;
1200
0
    }
1201
0
    gp_fclose(fp);
1202
0
    return code;
1203
0
}
1204
1205
/* set the initial environment to the default environment, this should
1206
   be done at the beginning of each job */
1207
int
1208
pjl_set_init_from_defaults(pjl_parser_state_t * pst)
1209
25.9k
{
1210
25.9k
    int code = free_pjl_environment(pst->mem, &pst->envir);
1211
25.9k
    if (code < 0)
1212
0
        return code;
1213
25.9k
    code = set_pjl_environment(pst->mem, &pst->envir, pst->defaults);
1214
25.9k
    if (code < 0)
1215
0
        return code;
1216
1217
25.9k
    code = free_pjl_fontsource(pst->mem, &pst->font_envir);
1218
25.9k
    if (code < 0)
1219
0
        return code;
1220
25.9k
    return set_pjl_fontsource(pst->mem, &pst->font_envir, pst->font_defaults);
1221
25.9k
}
1222
1223
void
1224
pjl_set_next_fontsource(pjl_parser_state_t * pst)
1225
0
{
1226
0
    int current_source;
1227
0
    pjl_envvar_t *current_font_source = pjl_get_envvar(pst, "fontsource");
1228
1229
    /* find the index of the current resource then work backwards
1230
       until we find font resources.  We assume the internal source
1231
       will have fonts */
1232
0
    for (current_source = 0; pst->font_envir[current_source].designator[0];
1233
0
         current_source++)
1234
0
        if (!pjl_compare(pst->font_envir[current_source].designator,
1235
0
                         current_font_source))
1236
0
            break;
1237
1238
    /* next resource is not internal 'I' */
1239
0
    if (current_source != 0) {
1240
0
        while (current_source > 0) {
1241
0
            current_source--;   /* go to next fontsource */
1242
            /* check if it contains fonts, i.e. fontnumber != null */
1243
0
            if (pst->font_envir[current_source].fontnumber[0])
1244
0
                break;
1245
0
        }
1246
0
    }
1247
    /* set both default and environment font source, the spec is not clear
1248
       about this */
1249
0
    pjl_set(pst, (char *)"fontsource",
1250
0
            pst->font_envir[current_source].designator, true);
1251
0
    pjl_set(pst, (char *)"fontsource",
1252
0
            pst->font_defaults[current_source].designator, false);
1253
0
}
1254
1255
/* get a pjl environment variable from the current environment - not
1256
   the user default environment */
1257
pjl_envvar_t *
1258
pjl_get_envvar(pjl_parser_state * pst, const char *pjl_var)
1259
1.37M
{
1260
1.37M
    int i=0;
1261
1.37M
    pjl_envir_var_t *env = pst->envir;
1262
1263
    /* lookup up the value */
1264
13.2M
    while(env[i].var) {
1265
13.2M
        if (!pjl_compare(env[i].var, pjl_var)) {
1266
1.37M
            return env[i].value;
1267
1.37M
        }
1268
11.9M
        i++;
1269
11.9M
    }
1270
0
    return NULL;
1271
1.37M
}
1272
1273
/* get a pjl environment variable from the current environment - not
1274
   the user default environment */
1275
pjl_envvar_t *
1276
pjl_set_envvar(pjl_parser_state * pst, const char *pjl_var, const char *data)
1277
0
{
1278
0
    int i=0;
1279
0
    pjl_envir_var_t *env = pst->envir;
1280
0
    char *newvalue;
1281
1282
    /* Find the current value */
1283
0
    while(env[i].var) {
1284
0
        if (!pjl_compare(env[i].var, pjl_var)) {
1285
0
            if (env[i].value)
1286
0
                gs_free_object(pst->mem, env[i].value, "pjl_set_envvar value");
1287
0
            newvalue = (char *)gs_alloc_bytes(pst->mem, strlen(data) + 1, "pjl_set_envvar, value");
1288
0
            if (newvalue != NULL) {
1289
0
                strcpy(newvalue, data);
1290
0
                env[i].value = newvalue;
1291
0
            }
1292
0
        }
1293
0
        i++;
1294
0
    }
1295
0
    return NULL;
1296
0
}
1297
1298
/* get a pjl environment variable from the current environment - not
1299
   the user default environment */
1300
pjl_envvar_t *
1301
pjl_set_defvar(pjl_parser_state * pst, const char *pjl_var, const char *data)
1302
0
{
1303
0
    int i=0;
1304
0
    pjl_envir_var_t *env = pst->defaults;
1305
0
    char *newvalue;
1306
1307
    /* Find the current value */
1308
0
    while(env[i].var) {
1309
0
        if (!pjl_compare(env[i].var, pjl_var)) {
1310
0
            if (env[i].value)
1311
0
                gs_free_object(pst->mem, env[i].value, "pjl_set_defvar value");
1312
0
            newvalue = (char *)gs_alloc_bytes(pst->mem, strlen(data) + 1, "pjl_set_defvar, value");
1313
0
            if (newvalue != NULL) {
1314
0
                strcpy(newvalue, data);
1315
0
                env[i].value = newvalue;
1316
0
            }
1317
0
        }
1318
0
        i++;
1319
0
    }
1320
0
    return NULL;
1321
0
}
1322
/*
1323
 * Detect illegal characters when preprocessing each line of PJL.
1324
 */
1325
static inline bool
1326
legal_pjl_char(const byte ch)
1327
1.06M
{
1328
1.06M
    return (ch >= 32 || isspace(ch));
1329
1.06M
}
1330
1331
/* -- public functions - see pjparse.h for interface documentation -- */
1332
1333
/* Process a buffer of PJL commands. */
1334
int
1335
pjl_process(pjl_parser_state * pst, void *pstate, stream_cursor_read * pr)
1336
7.30k
{
1337
7.30k
    const byte *p = pr->ptr;
1338
7.30k
    const byte *rlimit = pr->limit;
1339
7.30k
    int code = 0;
1340
1341
    /* first check if we are writing data to a file as part of the
1342
       file system commands */
1343
1344
1.07M
    while (p < rlimit) {
1345
1.07M
        if (pst->bytes_to_write != 0) {
1346
0
            p++;
1347
0
            if (pjl_write_remaining_data(pst, &p, &rlimit) == 0) {
1348
0
                p--;
1349
0
                continue;
1350
0
            } else
1351
0
                return -1;
1352
0
        }
1353
1354
1.07M
        if (pst->pos == 0) {    /* Look ahead for the @PJL prefix or a UEL. */
1355
38.8k
            uint avail = rlimit - p;
1356
1357
38.8k
            if (!memcmp(p + 1, "\033%-12345X", min(avail, 9))) {        /* Might be a UEL. */
1358
2.91k
                if (avail < 9) {        /* Not enough data to know yet. */
1359
3
                    code = gs_error_NeedInput;
1360
3
                    break;
1361
3
                }
1362
                /* Skip the UEL and continue. */
1363
2.91k
                p += 9;
1364
2.91k
                continue;
1365
35.9k
            } else {
1366
                /* We allow for a single CRLF at the start of a block of PJL.
1367
                 * This is in violation of the spec, but allows us to accept
1368
                 * files like bug 693269. This shouldn't adversely affect any
1369
                 * real world files. */
1370
35.9k
                if (avail > 0 && p[1] == '\r')
1371
8
                    p++, avail--;
1372
35.9k
                if (avail > 0 && p[1] == '\n')
1373
4
                    p++, avail--;
1374
35.9k
                if (!memcmp(p + 1, "@PJL", min(avail, 4))) { /* Might be PJL. */
1375
31.8k
                    if (avail < 4) {        /* Not enough data to know yet. */
1376
10
                        code = gs_error_NeedInput;
1377
10
                        break;
1378
10
                    }
1379
                    /* Definitely a PJL command. */
1380
31.8k
                } else {            /* Definitely not PJL. */
1381
4.13k
                    code = 1;
1382
4.13k
                    break;
1383
4.13k
                }
1384
35.9k
            }
1385
38.8k
        }
1386
1.06M
        if (!legal_pjl_char(p[1])) {
1387
2.99k
            code = 1;
1388
            /* If we haven't read anything yet, then just give up */
1389
2.99k
            if (pst->pos == 0) {
1390
0
                ++p;
1391
0
                break;
1392
0
            }
1393
            /* If we have, process what we had collected already before giving up. */
1394
            /* null terminate, parse and set the pjl state */
1395
2.99k
            pst->line[pst->pos] = '\0';
1396
            /*
1397
             * NB PJL continues not considering normal errors but we
1398
             * ignore memory failure errors here and shouldn't.
1399
             */
1400
2.99k
            (void)pjl_parse_and_process_line(pst);
1401
2.99k
            pst->pos = 0;
1402
2.99k
            break;
1403
2.99k
        }
1404
1.06M
        if (p[1] == '\n') {
1405
28.7k
            ++p;
1406
            /* null terminate, parse and set the pjl state */
1407
28.7k
            pst->line[pst->pos] = '\0';
1408
            /*
1409
             * NB PJL continues not considering normal errors but we
1410
             * ignore memory failure errors here and shouldn't.
1411
             */
1412
28.7k
            (void)pjl_parse_and_process_line(pst);
1413
28.7k
            pst->pos = 0;
1414
28.7k
            continue;
1415
28.7k
        }
1416
1417
        /* Copy the PJL line into the parser's line buffer. */
1418
        /* Always leave room for a terminator. */
1419
1.03M
        if (pst->pos == pst->line_size) {
1420
101
            char *temp = (char *)gs_alloc_bytes (pst->mem, pst->line_size + 256, "pjl_state increase line buffer");
1421
101
            if (temp != NULL) {
1422
101
                memcpy(temp, pst->line, pst->line_size);
1423
101
                gs_free_object(pst->mem, pst->line, "pjl_state line buffer");
1424
101
                pst->line = temp;
1425
101
                pst->line_size += 256;
1426
101
                pst->line[pst->pos] = p[1], pst->pos++;
1427
101
            }
1428
101
        } else
1429
1.03M
            pst->line[pst->pos] = p[1], pst->pos++;
1430
1.03M
        ++p;
1431
1.03M
    }
1432
7.30k
    pr->ptr = p;
1433
7.30k
    return code;
1434
7.30k
}
1435
1436
/* Discard the remainder of a job.  Return true when we reach a UEL. */
1437
/* The input buffer must be at least large enough to hold an entire UEL. */
1438
bool
1439
pjl_skip_to_uel(stream_cursor_read * pr)
1440
0
{
1441
0
    const byte *p = pr->ptr;
1442
0
    const byte *rlimit = pr->limit;
1443
1444
0
    for (; p < rlimit; ++p)
1445
0
        if (p[1] == '\033') {
1446
0
            uint avail = rlimit - p;
1447
1448
0
            if (memcmp(p + 1, "\033%-12345X", min(avail, 9)))
1449
0
                continue;
1450
0
            if (avail < 9)
1451
0
                break;
1452
0
            pr->ptr = p + 9;
1453
0
            return true;
1454
0
        }
1455
0
    pr->ptr = p;
1456
0
    return false;
1457
0
}
1458
1459
/* PJL symbol set environment variable -> pcl symbol set numbers.
1460
   This probably should not be defined here :-( */
1461
static const struct
1462
{
1463
    const char *symname;
1464
    const int  pcl_code;
1465
} symbol_sets[] = {
1466
    {"ROMAN8",  277},
1467
    {"ISOL1",    14},
1468
    {"ISOL2",    78},
1469
    {"ISOL5",   174},
1470
    {"PC8",     341},
1471
    {"PC8DN",   373},
1472
    {"PC850",   405},
1473
    {"PC852",   565},
1474
    {"PC8TK",   308},
1475
    {"WINL1",   309},
1476
    {"WINL2",   293},
1477
    {"WINL5",   180},
1478
    {"DESKTOP", 234},
1479
    {"PSTEXT",  330},
1480
    {"VNINTL",  426},
1481
    {"VNUS",    458},
1482
    {"MSPUBL",  202},
1483
    {"MATH8",   269},
1484
    {"PSMATH",  173},
1485
    {"VNMATH",  205},
1486
    {"PIFONT",  501},
1487
    {"LEGAL",    53},
1488
    {"ISO4",     37},
1489
    {"ISO6",     21},
1490
    {"ISO11",    19},
1491
    {"ISO15",     9},
1492
    {"ISO17",    83},
1493
    {"ISO21",    39},
1494
    {"ISO60",     4},
1495
    {"ISO69",    38},
1496
    {NULL,       -1}
1497
};
1498
1499
/* map a pjl symbol table name to a pcl symbol table code */
1500
int
1501
pjl_map_pjl_sym_to_pcl_sym(const char *symname)
1502
121k
{
1503
121k
    int i;
1504
1505
608k
    for (i = 0; symbol_sets[i].symname; i++)
1506
608k
        if (!pjl_compare(symname, symbol_sets[i].symname))
1507
121k
            return symbol_sets[i].pcl_code;
1508
0
    return -1;
1509
121k
}
1510
1511
/* environment variable to integer */
1512
int
1513
pjl_vartoi(const pjl_envvar_t * s)
1514
164k
{
1515
164k
    return atoi(s);
1516
164k
}
1517
1518
/* environment variable to float */
1519
double
1520
pjl_vartof(const pjl_envvar_t * s)
1521
365k
{
1522
365k
    return atof(s);
1523
365k
}
1524
1525
/* convert a pjl font source to a pathname */
1526
char *
1527
pjl_fontsource_to_path(const pjl_parser_state * pjls,
1528
                       const pjl_envvar_t * fontsource)
1529
128k
{
1530
128k
    int i;
1531
1532
    /* if an environment variable is set we use it, otherwise use the PJL
1533
       machinery */
1534
128k
    if (pjls->environment_font_path != NULL)
1535
0
        return pjl_check_font_path(pjls->environment_font_path, pjls->mem);
1536
128k
    for (i = 0; pjls->font_envir[i].designator[0]; i++)
1537
128k
        if (!pjl_compare(pjls->font_envir[i].designator, fontsource))
1538
128k
            return pjl_check_font_path(pjls->font_envir[i].pathname,
1539
128k
                                       pjls->mem);
1540
0
    return NULL;
1541
128k
}
1542
1543
static int set_pjl_defaults_to_factory(gs_memory_t * mem, pjl_envir_var_t **def)
1544
8.97k
{
1545
8.97k
    return set_pjl_defaults(mem, def, (pjl_envir_var_t *)&pjl_factory_defaults);
1546
8.97k
}
1547
1548
static int set_pjl_defaults(gs_memory_t * mem, pjl_envir_var_t **def, pjl_envir_var_t *from)
1549
8.97k
{
1550
8.97k
    pjl_envir_var_t *pjl_def;
1551
8.97k
    char *key, *value, *newkey, *newvalue;
1552
8.97k
    int i = 0;
1553
8.97k
    int limit = 0;
1554
1555
260k
    while (from[limit].var && from[limit].var[0] != 0x00)
1556
251k
        limit++;
1557
1558
8.97k
    pjl_def = (pjl_envir_var_t *) gs_alloc_bytes(mem,
1559
8.97k
                                                  sizeof
1560
8.97k
                                                  (pjl_envir_var_t) * (limit + 1),
1561
8.97k
                                                  "pjl_envir");
1562
8.97k
    if (!pjl_def)
1563
0
        return -1;
1564
1565
8.97k
    memset(pjl_def, 0x00, sizeof(pjl_envir_var_t) * (limit + 1));
1566
260k
    while (i < limit) {
1567
251k
        key = from[i].var;
1568
251k
        value = from[i].value;
1569
1570
251k
        newkey = (char *)gs_alloc_bytes(mem, strlen(key) + 1, "new_pjl_defaults, key");
1571
251k
        newvalue = (char *)gs_alloc_bytes(mem, strlen(value) + 1, "new_pjl_defaults, value");
1572
251k
        if (!newkey || !newvalue) {
1573
0
            gs_free_object(mem, newkey, "new_pjl_defaults, key");
1574
0
            free_pjl_defaults(mem, &pjl_def);
1575
0
            return -1;
1576
0
        }
1577
251k
        strcpy(newkey, key);
1578
251k
        strcpy(newvalue, value);
1579
251k
        pjl_def[i].var = newkey;
1580
251k
        pjl_def[i].value = newvalue;
1581
1582
251k
        i++;
1583
251k
    }
1584
8.97k
    *def = pjl_def;
1585
8.97k
    return 0;
1586
8.97k
}
1587
1588
static int set_pjl_environment_to_factory(gs_memory_t * mem, pjl_envir_var_t **env)
1589
8.97k
{
1590
8.97k
    return set_pjl_environment(mem, env, (pjl_envir_var_t *)&pjl_factory_defaults);
1591
8.97k
}
1592
1593
static int set_pjl_environment(gs_memory_t * mem, pjl_envir_var_t **env, pjl_envir_var_t *from)
1594
34.9k
{
1595
34.9k
    pjl_envir_var_t *pjl_env;
1596
34.9k
    char *key, *value, *newkey, *newvalue;
1597
34.9k
    int i = 0;
1598
34.9k
    int limit = 0;
1599
1600
1.01M
    while (from[limit].var && from[limit].var[0] != 0x00)
1601
979k
        limit++;
1602
1603
34.9k
    pjl_env = (pjl_envir_var_t *) gs_alloc_bytes(mem,
1604
34.9k
                                                  (size_t)sizeof
1605
34.9k
                                                  (pjl_envir_var_t) * (limit + 1),
1606
34.9k
                                                  "pjl_envir");
1607
34.9k
    if (!pjl_env)
1608
0
        return -1;
1609
1610
34.9k
    memset(pjl_env, 0x00, sizeof(pjl_envir_var_t) * (limit + 1));
1611
1.01M
    while (i < limit) {
1612
979k
        key = from[i].var;
1613
979k
        value = from[i].value;
1614
979k
        newkey = (char *)gs_alloc_bytes(mem, strlen(key) + 1, "pjl_envir, key");
1615
979k
        newvalue = (char *)gs_alloc_bytes(mem, strlen(value) + 1, "pjl_envir, value");
1616
979k
        if (!newkey || !newvalue) {
1617
0
            gs_free_object(mem, newkey, "pjl_envir, key");
1618
0
            free_pjl_environment(mem, &pjl_env);
1619
0
            return -1;
1620
0
        }
1621
979k
        strcpy(newkey, key);
1622
979k
        strcpy(newvalue, value);
1623
979k
        pjl_env[i].var = newkey;
1624
979k
        pjl_env[i].value = newvalue;
1625
1626
979k
        i++;
1627
979k
    }
1628
34.9k
    *env = pjl_env;
1629
34.9k
    return 0;
1630
34.9k
}
1631
1632
static int set_pjl_fontsource_to_factory(gs_memory_t * mem, pjl_fontsource_t **fontenv)
1633
8.97k
{
1634
8.97k
    return set_pjl_fontsource(mem, fontenv, (pjl_fontsource_t *)pjl_fontsource_table);
1635
8.97k
}
1636
1637
static int set_pjl_fontsource(gs_memory_t * mem, pjl_fontsource_t **fontenv, pjl_fontsource_t *from)
1638
34.9k
{
1639
34.9k
    pjl_fontsource_t *pjl_fontenv;
1640
34.9k
    char *key, *value, *newkey, *newvalue;
1641
34.9k
    int i = 0;
1642
34.9k
    int limit = 0;
1643
1644
349k
    while (from[limit].pathname && from[limit].pathname[0] != 0x00)
1645
314k
        limit++;
1646
1647
34.9k
    pjl_fontenv = (pjl_fontsource_t *) gs_alloc_bytes(mem,
1648
34.9k
                                                      (size_t)sizeof
1649
34.9k
                                                      (pjl_fontsource_t) * (limit + 1),
1650
34.9k
                                                      "font_envir");
1651
34.9k
    if (!pjl_fontenv)
1652
0
        return -1;
1653
1654
34.9k
    memset(pjl_fontenv, 0x00, sizeof(pjl_fontsource_t) * (limit + 1));
1655
349k
    while (i < limit) {
1656
314k
        key = from[i].pathname;
1657
314k
        value = from[i].fontnumber;
1658
1659
314k
        newkey = (char *)gs_alloc_bytes(mem, strlen(key) + 1, "new_font_envir, pathname");
1660
314k
        if (!newkey) {
1661
0
            free_pjl_fontsource(mem, &pjl_fontenv);
1662
0
            return -1;
1663
0
        }
1664
314k
        strcpy(newkey, key);
1665
314k
        pjl_fontenv[i].pathname = newkey;
1666
314k
        if (value) {
1667
314k
            newvalue = (char *)gs_alloc_bytes(mem, strlen(value) + 1, "new_font_envir, fontnumber");
1668
314k
            if (!newvalue) {
1669
0
                free_pjl_fontsource(mem, &pjl_fontenv);
1670
0
                return -1;
1671
0
            }
1672
314k
            strcpy(newvalue, value);
1673
314k
            pjl_fontenv[i].fontnumber = newvalue;
1674
314k
        } else {
1675
0
            pjl_fontenv[i].fontnumber = 0x00;
1676
0
        }
1677
314k
        memcpy(pjl_fontenv[i].designator, pjl_fontsource_table[i].designator, 2);
1678
1679
314k
        i++;
1680
314k
    }
1681
34.9k
    *fontenv = pjl_fontenv;
1682
34.9k
    return 0;
1683
34.9k
}
1684
1685
static int set_pjl_default_fontsource_to_factory(gs_memory_t * mem, pjl_fontsource_t **fontdef)
1686
8.97k
{
1687
8.97k
    return set_pjl_default_fontsource(mem, fontdef, (pjl_fontsource_t *)&pjl_fontsource_table);
1688
8.97k
}
1689
1690
static int set_pjl_default_fontsource(gs_memory_t * mem, pjl_fontsource_t **fontdef, pjl_fontsource_t *from)
1691
8.97k
{
1692
8.97k
    pjl_fontsource_t *pjl_fontdef;
1693
8.97k
    char *key, *value, *newkey, *newvalue;
1694
8.97k
    int i = 0;
1695
8.97k
    int limit = 0;
1696
1697
89.7k
    while (from[limit].pathname && from[limit].pathname[0] != 0x00)
1698
80.7k
        limit++;
1699
1700
8.97k
    pjl_fontdef = (pjl_fontsource_t *) gs_alloc_bytes(mem,
1701
8.97k
                                                      (size_t)sizeof
1702
8.97k
                                                      (pjl_fontsource_t) * (limit + 1),
1703
8.97k
                                                      "new_font_defaults");
1704
8.97k
    if (!pjl_fontdef)
1705
0
        return -1;
1706
1707
8.97k
    memset(pjl_fontdef, 0x00, sizeof(pjl_fontsource_t) * (limit + 1));
1708
89.7k
    while (i < limit) {
1709
80.7k
        key = from[i].pathname;
1710
80.7k
        value = from[i].fontnumber;
1711
1712
80.7k
        newkey = (char *)gs_alloc_bytes(mem, strlen(key) + 1, "new_font_defaults, pathname");
1713
80.7k
        if (!newkey) {
1714
0
            free_pjl_default_fontsource(mem, &pjl_fontdef);
1715
0
            return -1;
1716
0
        }
1717
80.7k
        strcpy(newkey, key);
1718
80.7k
        pjl_fontdef[i].pathname = newkey;
1719
80.7k
        if (value) {
1720
80.7k
            newvalue = (char *)gs_alloc_bytes(mem, strlen(value) + 1, "new_font_defaults, fontnumber");
1721
80.7k
            if (!newvalue) {
1722
0
                free_pjl_default_fontsource(mem, &pjl_fontdef);
1723
0
                return -1;
1724
0
            }
1725
80.7k
            strcpy(newvalue, value);
1726
80.7k
            pjl_fontdef[i].fontnumber = newvalue;
1727
80.7k
        } else {
1728
0
            pjl_fontdef[i].fontnumber = 0x00;
1729
0
        }
1730
80.7k
        memcpy(pjl_fontdef[i].designator, pjl_fontsource_table[i].designator, 2);
1731
1732
80.7k
        i++;
1733
80.7k
    }
1734
8.97k
    *fontdef = pjl_fontdef;
1735
8.97k
    return 0;
1736
8.97k
}
1737
1738
static int free_pjl_defaults(gs_memory_t * mem, pjl_envir_var_t **def)
1739
8.97k
{
1740
8.97k
    int i=0;
1741
8.97k
    pjl_envir_var_t *pjl_def = *def;
1742
1743
260k
    while (pjl_def[i].var) {
1744
251k
        gs_free_object(mem, pjl_def[i].var, "free pjl_defaults key");
1745
251k
        gs_free_object(mem, pjl_def[i].value, "free pjl_defaults value");
1746
251k
        i++;
1747
251k
    }
1748
8.97k
    gs_free_object(mem, pjl_def, "pjl_defaults");
1749
8.97k
    *def = 0x00;
1750
8.97k
    return 0;
1751
8.97k
}
1752
1753
int free_pjl_environment(gs_memory_t * mem, pjl_envir_var_t **env)
1754
34.9k
{
1755
34.9k
    int i=0;
1756
34.9k
    pjl_envir_var_t *pjl_env = *env;
1757
1758
34.9k
    if (pjl_env == NULL)
1759
0
        return 0;
1760
1761
1.01M
    while (pjl_env[i].var) {
1762
979k
        gs_free_object(mem, pjl_env[i].var, "free pjl_environment key");
1763
979k
        gs_free_object(mem, pjl_env[i].value, "free pjl_environment value");
1764
979k
        i++;
1765
979k
    }
1766
34.9k
    gs_free_object(mem, pjl_env, "pjl_environment");
1767
34.9k
    *env = 0x00;
1768
34.9k
    return 0;
1769
34.9k
}
1770
1771
int free_pjl_fontsource(gs_memory_t * mem, pjl_fontsource_t **fontenv)
1772
34.9k
{
1773
34.9k
    int i=0;
1774
34.9k
    pjl_fontsource_t *pjl_fontenv = *fontenv;
1775
1776
34.9k
    if (pjl_fontenv == NULL)
1777
0
        return 0;
1778
1779
349k
    while (pjl_fontenv[i].pathname) {
1780
314k
        gs_free_object(mem, pjl_fontenv[i].pathname, "pjl_font_envir pathname");
1781
314k
        gs_free_object(mem, pjl_fontenv[i].fontnumber, "pjl_font_envir fontnumber");
1782
314k
        i++;
1783
314k
    }
1784
34.9k
    gs_free_object(mem, pjl_fontenv, "pjl_font_envir");
1785
34.9k
    *fontenv = 0x00;
1786
34.9k
    return 0;
1787
34.9k
}
1788
1789
int free_pjl_default_fontsource(gs_memory_t * mem, pjl_fontsource_t **fontdef)
1790
8.97k
{
1791
8.97k
    int i=0;
1792
8.97k
    pjl_fontsource_t *pjl_fontdef = *fontdef;
1793
1794
89.7k
    while (pjl_fontdef[i].pathname) {
1795
80.7k
        gs_free_object(mem, pjl_fontdef[i].pathname, "pjl_font_defaults pathname");
1796
80.7k
        gs_free_object(mem, pjl_fontdef[i].fontnumber, "pjl_font_defaults fontnumber");
1797
80.7k
        i++;
1798
80.7k
    }
1799
8.97k
    gs_free_object(mem, pjl_fontdef, "pjl_font_defaults");
1800
8.97k
    *fontdef = 0x00;
1801
8.97k
    return 0;
1802
8.97k
}
1803
1804
/* Create and initialize a new state. */
1805
pjl_parser_state *
1806
pjl_process_init(gs_memory_t * mem)
1807
8.97k
{
1808
8.97k
    pjl_envir_var_t *pjl_env, *pjl_def;
1809
8.97k
    pjl_fontsource_t *pjl_fontenv, *pjl_fontdef;
1810
1811
8.97k
    pjl_parser_state_t *pjlstate = (pjl_parser_state *) gs_alloc_bytes(mem,
1812
8.97k
                                                                       sizeof
1813
8.97k
                                                                       (pjl_parser_state_t),
1814
8.97k
                                                                       "pjl_state");
1815
1816
8.97k
    if (pjlstate == NULL)
1817
0
        return NULL;            /* should be fatal so we don't bother piecemeal frees */
1818
1819
8.97k
    pjlstate->line = (char *)gs_alloc_bytes(mem, 256, "pjl_state line buffer");
1820
8.97k
    if (pjlstate->line == NULL) {
1821
0
        gs_free_object(mem, pjlstate, "pjl_state");
1822
0
        return NULL;
1823
0
    }
1824
8.97k
    pjlstate->line_size = 255;
1825
1826
    /* check for an environment variable */
1827
8.97k
    {
1828
8.97k
        int pathlen, code;
1829
1830
        /* The environment variable exists if the function fails to
1831
           fit in the null - odd but it works.  We allow an
1832
           environment variable to override the font default PJL font
1833
           path for desktop setups */
1834
8.97k
        pathlen = 0;
1835
8.97k
        if ((code = gp_getenv("PCLFONTSOURCE", (char *)0, &pathlen)) < 0) {
1836
0
            char *path =
1837
0
                (char *)gs_alloc_bytes(mem, pathlen + 1, "pjl_font_path");
1838
            /* if the allocation fails we use the pjl fontsource */
1839
0
            if (path == NULL)
1840
0
                pjlstate->environment_font_path = NULL;
1841
0
            else {
1842
0
                const char * const sepr = gp_file_name_separator();
1843
0
                const int lsepr = strlen(sepr);
1844
0
                gp_getenv("PCLFONTSOURCE", path, &pathlen);     /* can't fail */
1845
1846
                /* We want to ensure a trailing "/" is present */
1847
0
                if (gs_file_name_check_separator(path + (pathlen - (lsepr + 1)), lsepr, path + pathlen - 1) != 1) {
1848
0
                    strncat(path, gp_file_name_separator(), pathlen + 1);
1849
0
                }
1850
0
                code = gs_add_control_path(mem, gs_permit_file_reading, path);
1851
0
                if (code < 0) {
1852
0
                    gs_free_object(mem, path, "pjl_font_path");
1853
0
                    goto fail1;
1854
0
                }
1855
0
                pjlstate->environment_font_path = path;
1856
0
            }
1857
0
        } else                  /* environmet variable does not exist use pjl fontsource */
1858
8.97k
            pjlstate->environment_font_path = NULL;
1859
8.97k
    }
1860
1861
    /* initialize the default and initial pjl environment.  We assume
1862
       that these are the same layout as the factory defaults. */
1863
8.97k
    if (set_pjl_defaults_to_factory(mem, &pjl_def) < 0) {
1864
0
        goto fail1;
1865
0
    }
1866
8.97k
    if (set_pjl_environment_to_factory(mem, &pjl_env) < 0) {
1867
0
        goto fail2;
1868
0
    }
1869
8.97k
    if (set_pjl_fontsource_to_factory(mem, &pjl_fontenv) < 0) {
1870
0
        goto fail3;
1871
0
    }
1872
8.97k
    if (set_pjl_default_fontsource_to_factory(mem, &pjl_fontdef) < 0) {
1873
0
        goto fail4;
1874
0
    }
1875
1876
    /* initialize the font repository data as well */
1877
8.97k
    pjlstate->defaults = pjl_def;
1878
8.97k
    pjlstate->envir = pjl_env;
1879
8.97k
    pjlstate->font_envir = pjl_fontenv;
1880
8.97k
    pjlstate->font_defaults = pjl_fontdef;
1881
1882
    /* initialize the current position in the line array and bytes pending */
1883
8.97k
    pjlstate->bytes_to_read = 0;
1884
8.97k
    pjlstate->bytes_to_write = 0;
1885
8.97k
    pjlstate->fp = 0;
1886
    /* line pos */
1887
8.97k
    pjlstate->pos = 0;
1888
8.97k
    pjlstate->mem = mem;
1889
    /* initialize available font sources */
1890
8.97k
    pjl_reset_fontsource_fontnumbers(pjlstate);
1891
8.97k
    {
1892
8.97k
        int i;
1893
1894
296k
        for (i = 0; i < countof(pjlstate->permanent_soft_fonts); i++)
1895
287k
            pjlstate->permanent_soft_fonts[i] = 0;
1896
8.97k
    }
1897
8.97k
    return (pjl_parser_state *) pjlstate;
1898
1899
0
fail4:
1900
0
    free_pjl_fontsource(mem, &pjl_fontenv);
1901
0
fail3:
1902
0
    free_pjl_environment(mem, &pjl_env);
1903
0
fail2:
1904
0
    free_pjl_defaults(mem, &pjl_def);
1905
0
fail1:
1906
0
    gs_free_object(mem, pjlstate->line, "pjl_state line buffer");
1907
0
    gs_free_object(mem, pjlstate, "pjl_state");
1908
0
    return NULL;
1909
0
}
1910
1911
/* case insensitive comparison of two null terminated strings. */
1912
int
1913
pjl_compare(const pjl_envvar_t * s1, const char *s2)
1914
17.3M
{
1915
33.8M
    for (; toupper(*s1) == toupper(*s2); ++s1, ++s2)
1916
18.3M
        if (*s1 == '\0')
1917
1.87M
            return (0);
1918
15.5M
    return 1;
1919
17.3M
}
1920
1921
/* free all memory associated with the PJL state */
1922
void
1923
pjl_process_destroy(pjl_parser_state * pst)
1924
8.97k
{
1925
8.97k
    gs_memory_t *mem;
1926
1927
8.97k
    if (pst == NULL)
1928
0
        return;
1929
1930
8.97k
    mem = pst->mem;
1931
1932
8.97k
    free_pjl_defaults(mem, &pst->defaults);
1933
8.97k
    free_pjl_environment(mem, &pst->envir);
1934
8.97k
    free_pjl_fontsource(mem, &pst->font_envir);
1935
8.97k
    free_pjl_default_fontsource(mem, &pst->font_defaults);
1936
1937
8.97k
    if (pst->environment_font_path)
1938
0
        gs_free_object(mem, pst->environment_font_path, "pjl_state");
1939
8.97k
    gs_free_object(mem, pst->line, "pjl_state line buffer");
1940
8.97k
    gs_free_object(mem, pst, "pjl_state");
1941
8.97k
}
1942
1943
/* delete a permanent soft font */
1944
int
1945
pjl_register_permanent_soft_font_deletion(pjl_parser_state * pst,
1946
                                          int font_number)
1947
0
{
1948
0
    if ((font_number > MAX_PERMANENT_FONTS - 1) || (font_number < 0)) {
1949
0
        dmprintf(pst->mem,
1950
0
                 "pjparse.c:pjl_register_permanent_soft_font_deletion() bad font number\n");
1951
0
        return 0;
1952
0
    }
1953
    /* if the font is present. */
1954
0
    if ((pst->permanent_soft_fonts[font_number >> 3]) &
1955
0
        (128 >> (font_number & 7))) {
1956
        /* set the bit to zero to indicate the fontnumber has been deleted */
1957
0
        pst->permanent_soft_fonts[font_number >> 3] &=
1958
0
            ~(128 >> (font_number & 7));
1959
        /* if the current font source is 'S' and the current font number
1960
           is the highest number, and *any* soft font was deleted or if
1961
           the last font has been removed, set the stage for changing to
1962
           the next priority font source.  BLAME HP not me. */
1963
0
        {
1964
0
            bool is_S = !pjl_compare(pjl_get_envvar(pst, "fontsource"), "S");
1965
0
            bool empty = true;
1966
0
            int highest_fontnumber = -1;
1967
0
            int current_fontnumber =
1968
0
                pjl_vartoi(pjl_get_envvar(pst, "fontnumber"));
1969
0
            int i;
1970
1971
            /* check for no more fonts and the highest font number.
1972
               NB should look at longs not bits in the loop */
1973
0
            for (i = 0; i < MAX_PERMANENT_FONTS; i++)
1974
0
                if ((pst->permanent_soft_fonts[i >> 3]) & (128 >> (i & 7))) {
1975
0
                    empty = false;
1976
0
                    highest_fontnumber = i;
1977
0
                }
1978
0
            if (is_S && ((highest_fontnumber == current_fontnumber) || empty)) {
1979
0
#define SINDEX 4
1980
0
                pst->font_defaults[SINDEX].fontnumber[0] = '\0';
1981
0
                pst->font_envir[SINDEX].fontnumber[0] = '\0';
1982
0
                return 1;
1983
0
#undef SINDEX
1984
0
            }
1985
0
        }
1986
0
    }
1987
0
    return 0;
1988
0
}
1989
1990
/* request that pjl add a soft font and return a pjl font number for
1991
   the font. */
1992
int
1993
pjl_register_permanent_soft_font_addition(pjl_parser_state * pst)
1994
0
{
1995
    /* Find an empty slot in the table.  We have no HP documentation
1996
       that says how a soft font gets associated with a font number */
1997
0
    int font_num;
1998
0
    bool slot_found = false;
1999
2000
0
    for (font_num = 0; font_num < MAX_PERMANENT_FONTS; font_num++)
2001
0
        if (!
2002
0
            ((pst->permanent_soft_fonts[font_num >> 3]) &
2003
0
             (128 >> (font_num & 7)))) {
2004
0
            slot_found = true;
2005
0
            break;
2006
0
        }
2007
    /* yikes, shouldn't happen */
2008
0
    if (!slot_found) {
2009
0
        dmprintf(pst->mem,
2010
0
                 "pjparse.c:pjl_register_permanent_soft_font_addition()\
2011
0
                 font table full recycling font number 0\n");
2012
0
        font_num = 0;
2013
0
    }
2014
    /* set the bit to 1 to indicate the fontnumber has been added */
2015
0
    pst->permanent_soft_fonts[font_num >> 3] |= (128 >> (font_num & 7));
2016
0
    return font_num;
2017
0
}