Coverage Report

Created: 2026-04-01 07:17

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
10.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
216
#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
216
#define LETTER_PAPER_INDEX 1
282
283
static int
284
pjl_get_media_index(const char *paper)
285
216
{
286
216
    int i;
287
288
9.50k
    for (i = 0; i < countof(pjl_media); i++)
289
9.28k
        if (!pjl_compare(paper, pjl_media[i].media_name))
290
0
            return i;
291
216
    return LETTER_PAPER_INDEX;
292
216
}
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
216
{
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
216
    double formlines = (page_length - 300.0) / 50.0;
309
310
216
    return (int)(formlines + 0.5);
311
216
}
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
6.33k
{
319
6.33k
    if (!pjl_compare(variable, "PAPER") ||
320
6.11k
        !pjl_compare(variable, "ORIENTATION")) {
321
322
216
        pjl_envir_var_t *table = (defaults ? pst->defaults : pst->envir);
323
216
        int indx = pjl_get_media_index(table[FDEF_PAPER_INDX].value);
324
216
        int page_length = (!pjl_compare(variable, "ORIENTATION") &&
325
0
                           !pjl_compare(value, "LANDSCAPE") ?
326
0
                           (int)(pjl_media[indx].width) :
327
216
                           (int)(pjl_media[indx].height));
328
216
        int formlines = pjl_calc_formlines_new_page_size(page_length);
329
216
        char text[32];
330
331
216
        gs_snprintf(text, sizeof(text), "%d", formlines);
332
216
        pjl_set(pst, (char *)"FORMLINES", text, defaults);
333
216
    }
334
    /* fill in other side effects here */
335
6.33k
    return;
336
6.33k
}
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
6.33k
{
342
6.33k
    pjl_envir_var_t *table = (defaults ? pst->defaults : pst->envir);
343
6.33k
    int i=0;
344
345
6.33k
    if (defaults)               /* default also sets current environment. */
346
0
        pjl_set(pst, variable, value, false);
347
348
120k
    while (table[i].var) {
349
120k
        if (!pjl_compare(table[i].var, variable)) {
350
            /* set the value */
351
6.33k
            char *newvalue = (char *)gs_alloc_bytes(pst->mem, strlen(value) + 1, "pjl_set, create new value");
352
6.33k
            if (!newvalue)
353
0
                return 0;
354
6.33k
            strcpy(newvalue, value);
355
6.33k
            gs_free_object(pst->mem, table[i].value, "pjl_set free old value");
356
6.33k
            table[i].value = newvalue;
357
            /* set any side effects of setting the value */
358
6.33k
            pjl_side_effects(pst, variable, value, defaults);
359
6.33k
            return 1;
360
6.33k
        }
361
114k
        i++;
362
114k
    }
363
    /* didn't find variable */
364
0
    return 0;
365
6.33k
}
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
119k
{
371
119k
    int c;
372
119k
    int start_pos;
373
    /* skip any whitespace if we need to.  */
374
169k
    while ((c = pst->line[pst->pos]) == ' ' || c == '\t')
375
50.2k
        pst->pos++;
376
377
    /* special case to allow = with no intevervening spaces between
378
       lhs and rhs */
379
119k
    if (c == '=') {
380
16.4k
        pst->pos++;
381
16.4k
        return EQUAL;
382
16.4k
    }
383
384
    /* set the starting position */
385
103k
    start_pos = pst->pos;
386
387
    /* end of line reached; null shouldn't happen but we check anyway */
388
103k
    if (c == '\0' || c == '\n')
389
5.53k
        return DONE;
390
391
    /* check for a quoted string.  It should not span a line */
392
97.5k
    if (c == '"') {
393
2.02k
        pst->pos++;
394
40.2k
        while ((c = pst->line[pst->pos]) != '"' && c != '\0' && c != '\n')
395
38.2k
            pst->pos++;
396
        /* this routine doesn't yet support real error handling - here
397
           we should check if c == '"' */
398
2.02k
        if (c == '"')
399
1.84k
            pst->pos++;
400
188
        else
401
188
            return DONE;
402
95.5k
    } else {
403
        /* set the ptr to the next delimeter. */
404
567k
        while ((c = pst->line[pst->pos]) != ' ' &&
405
509k
               c != '\t' && c != '\r' && c != '\n' && c != '=' && c != '\0')
406
472k
            pst->pos++;
407
95.5k
    }
408
409
    /* build the token */
410
97.3k
    {
411
97.3k
        int slength = pst->pos - start_pos;
412
97.3k
        int i;
413
414
        /* we allow = to special case for allowing
415
           token doesn't fit or is empty */
416
97.3k
        if (slength == 0)
417
5.58k
            return DONE;
418
        /* now the string can be safely copied */
419
91.7k
        strncpy(token, &pst->line[start_pos], slength);
420
91.7k
        token[slength] = '\0';
421
422
        /* for known tokens */
423
1.29M
        for (i = 0; pjl_table[i].pjl_string[0]; i++)
424
1.25M
            if (!pjl_compare(pjl_table[i].pjl_string, token))
425
46.6k
                return pjl_table[i].pjl_token;
426
427
        /* NB add other cases here */
428
        /* check for variables that we support */
429
45.1k
        i = 0;
430
1.25M
        while (pst->envir[i].var) {
431
1.21M
            if (!pjl_compare(pst->envir[i].var, token))
432
6.13k
                return VARIABLE;
433
1.20M
            i++;
434
1.20M
        }
435
436
        /* NB assume this is a setting yuck */
437
39.0k
        return SETTING;
438
45.1k
    }
439
    /* shouldn't happen */
440
0
    return DONE;
441
45.1k
}
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
251k
{
447
    /* lookup a font path and check if any files (presumably fonts are
448
       present) */
449
251k
    char path[PJL_PATH_NAME_LENGTH + 1];
450
251k
    char *pathp = path, *tplast = NULL;
451
251k
    const char pattern[] = "*";
452
251k
    char path_and_pattern[PJL_PATH_NAME_LENGTH + 1 + 1];    /* pattern + null */
453
251k
    char *dirname;
454
251k
    char fontfilename[MAXPATHLEN + 1];
455
456
    /* Ignore error if the path list is too long, a single path may be
457
       okay. */
458
251k
    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
380k
    while ((dirname = gs_strtok(pathp, ";", &tplast)) != NULL) {
463
251k
        file_enum *fe;
464
465
251k
        if (gs_strlcpy(path_and_pattern, dirname, sizeof(path_and_pattern)) >= sizeof(path_and_pattern))
466
0
            continue;
467
468
251k
        if (gs_strlcat(path_and_pattern, pattern, sizeof(path_and_pattern)) >= sizeof(path_and_pattern))
469
0
            continue;
470
471
251k
        fe = gs_enumerate_files_init(mem, path_and_pattern,
472
251k
                                     strlen(path_and_pattern));
473
251k
        if (fe == NULL
474
251k
            ||
475
251k
            (gs_enumerate_files_next(mem, fe, fontfilename, PJL_PATH_NAME_LENGTH))
476
251k
            == -1) {
477
129k
            pathp = NULL;
478
129k
        } 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
9.85M
            while (1) {
484
9.85M
                int fstatus =
485
9.85M
                    (int)gs_enumerate_files_next(mem, fe, fontfilename,
486
9.85M
                                                 PJL_PATH_NAME_LENGTH);
487
                /* we don't care if the file does not fit (return +1) */
488
9.85M
                if (fstatus == -1)
489
121k
                    break;
490
9.85M
            }
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
121k
            if (strlen(path_list) < strlen(dirname))
495
0
                return NULL;
496
121k
            else {
497
121k
                strcpy(path_list, dirname);
498
121k
                return path_list;
499
121k
            }
500
121k
        }
501
251k
    }
502
129k
    return NULL;
503
251k
}
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.09k
{
513
8.09k
    char default_font_number[] = {0x30, 0x00};   /* default number if resources are present */
514
8.09k
    gs_memory_t *mem = pst->mem;
515
8.09k
    int i;
516
8.09k
    char *newvalue;
517
518
80.9k
    for (i = 0; pst->font_defaults[i].designator[0]; i++) {
519
72.8k
        if (pjl_check_font_path(pst->font_defaults[i].pathname, mem)) {
520
8.09k
            newvalue = (char *)gs_alloc_bytes(mem, strlen(default_font_number) + 1, "pjl_reset_fontsource_fontnumbers, create new value");
521
8.09k
            if (newvalue) {
522
8.09k
                gs_free_object(mem, pst->font_defaults[i].fontnumber, "pjl_reset_fontsource_fontnumbers");
523
8.09k
                strcpy(newvalue, default_font_number);
524
8.09k
                pst->font_defaults[i].fontnumber = newvalue;
525
8.09k
            }
526
8.09k
        }
527
72.8k
        if (pjl_check_font_path(pst->font_envir[i].pathname, mem)) {
528
8.09k
            newvalue = (char *)gs_alloc_bytes(mem, strlen(default_font_number) + 1, "pjl_reset_fontsource_fontnumbers, create new value");
529
8.09k
            if (newvalue) {
530
8.09k
                gs_free_object(mem, pst->font_envir[i].fontnumber, "pjl_reset_fontsource_fontnumbers");
531
8.09k
                strcpy(newvalue, default_font_number);
532
8.09k
                pst->font_envir[i].fontnumber = newvalue;
533
8.09k
            }
534
8.09k
        }
535
72.8k
    }
536
8.09k
}
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 = 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
28.8k
{
900
28.8k
    pjl_token_type_t tok;
901
28.8k
    char *token;
902
28.8k
    char pathname[MAXPATHLEN];
903
28.8k
    int bufsize = pst->pos + 1, code;
904
905
28.8k
    token = (char *)gs_alloc_bytes(pst->mem, bufsize, "working buffer for PJL parsing");
906
28.8k
    if (token == 0)
907
0
        return -1;
908
909
28.8k
    memset(token, 0x00, bufsize);
910
28.8k
    memset(pathname, 0x00, sizeof(pathname));
911
912
    /* reset the line position to the beginning of the line */
913
28.8k
    pst->pos = 0;
914
    /* all pjl commands start with the pjl prefix @PJL */
915
28.8k
    if ((tok = pjl_get_token(pst, token)) != PREFIX) {
916
132
        gs_free_object(pst->mem, token, "working buffer for PJL parsing");
917
132
        return -1;
918
132
    }
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
28.7k
    while ((tok = pjl_get_token(pst, token)) != DONE) {
922
28.6k
        switch (tok) {
923
14.4k
            case SET:
924
14.8k
            case DEFAULT:
925
14.8k
                {
926
14.8k
                    bool defaults;
927
928
17.3k
                    var:defaults = (tok == DEFAULT);
929
                    /* NB we skip over lparm and search for the variable */
930
49.6k
                    while ((tok = pjl_get_token(pst, token)) != DONE)
931
38.4k
                        if (tok == VARIABLE) {
932
6.12k
                            char *variable;
933
934
6.12k
                            variable = (char *)gs_alloc_bytes(pst->mem, bufsize, "2nd working buffer for PJL parsing");
935
6.12k
                            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.12k
                            memset(variable, 0x00, bufsize);
940
941
6.12k
                            strcpy(variable, token);
942
6.12k
                            if (((tok = pjl_get_token(pst, token)) == EQUAL)
943
6.12k
                                && (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.11k
                                if (!pjl_compare(variable, "FORMLINES"))
951
0
                                    pjl_set(pst, (char *)"FORMLINES_SET",
952
0
                                            (char *)"on", defaults);
953
6.11k
                                code = pjl_set(pst, variable, token,
954
6.11k
                                               defaults);
955
6.11k
                            } else
956
11
                                code = -1; /* syntax error */
957
6.12k
                            gs_free_object(pst->mem, variable, "2nd working buffer for PJL parsing");
958
6.12k
                            gs_free_object(pst->mem, token, "working buffer for PJL parsing");
959
6.12k
                            return code;
960
6.12k
                        } else
961
32.3k
                            continue;
962
963
11.2k
                    gs_free_object(pst->mem, token, "working buffer for PJL parsing");
964
11.2k
                    return 0;
965
17.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.47k
            case ENTER:
1013
                /* there is no setting for the default language */
1014
2.47k
                tok = SET;
1015
2.47k
                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
11.2k
            default:
1137
11.2k
                gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1138
11.2k
                return -1;
1139
28.6k
        }
1140
28.6k
    }
1141
60
    gs_free_object(pst->mem, token, "working buffer for PJL parsing");
1142
60
    return 0;
1143
28.7k
}
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
23.7k
{
1210
23.7k
    int code = free_pjl_environment(pst->mem, &pst->envir);
1211
23.7k
    if (code < 0)
1212
0
        return code;
1213
23.7k
    code = set_pjl_environment(pst->mem, &pst->envir, pst->defaults);
1214
23.7k
    if (code < 0)
1215
0
        return code;
1216
1217
23.7k
    code = free_pjl_fontsource(pst->mem, &pst->font_envir);
1218
23.7k
    if (code < 0)
1219
0
        return code;
1220
23.7k
    return set_pjl_fontsource(pst->mem, &pst->font_envir, pst->font_defaults);
1221
23.7k
}
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.19M
{
1260
1.19M
    int i=0;
1261
1.19M
    pjl_envir_var_t *env = pst->envir;
1262
1263
    /* lookup up the value */
1264
11.7M
    while(env[i].var) {
1265
11.7M
        if (!pjl_compare(env[i].var, pjl_var)) {
1266
1.19M
            return env[i].value;
1267
1.19M
        }
1268
10.5M
        i++;
1269
10.5M
    }
1270
0
    return NULL;
1271
1.19M
}
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
978k
{
1328
978k
    return (ch >= 32 || isspace(ch));
1329
978k
}
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
6.64k
{
1337
6.64k
    const byte *p = pr->ptr;
1338
6.64k
    const byte *rlimit = pr->limit;
1339
6.64k
    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
985k
    while (p < rlimit) {
1345
985k
        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
985k
        if (pst->pos == 0) {    /* Look ahead for the @PJL prefix or a UEL. */
1355
35.2k
            uint avail = rlimit - p;
1356
1357
35.2k
            if (!memcmp(p + 1, "\033%-12345X", min(avail, 9))) {        /* Might be a UEL. */
1358
2.55k
                if (avail < 9) {        /* Not enough data to know yet. */
1359
0
                    code = gs_error_NeedInput;
1360
0
                    break;
1361
0
                }
1362
                /* Skip the UEL and continue. */
1363
2.55k
                p += 9;
1364
2.55k
                continue;
1365
32.6k
            } 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
32.6k
                if (avail > 0 && p[1] == '\r')
1371
4
                    p++, avail--;
1372
32.6k
                if (avail > 0 && p[1] == '\n')
1373
6
                    p++, avail--;
1374
32.6k
                if (!memcmp(p + 1, "@PJL", min(avail, 4))) { /* Might be PJL. */
1375
28.9k
                    if (avail < 4) {        /* Not enough data to know yet. */
1376
5
                        code = gs_error_NeedInput;
1377
5
                        break;
1378
5
                    }
1379
                    /* Definitely a PJL command. */
1380
28.9k
                } else {            /* Definitely not PJL. */
1381
3.76k
                    code = 1;
1382
3.76k
                    break;
1383
3.76k
                }
1384
32.6k
            }
1385
35.2k
        }
1386
978k
        if (!legal_pjl_char(p[1])) {
1387
2.72k
            code = 1;
1388
            /* If we haven't read anything yet, then just give up */
1389
2.72k
            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.72k
            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.72k
            (void)pjl_parse_and_process_line(pst);
1401
2.72k
            pst->pos = 0;
1402
2.72k
            break;
1403
2.72k
        }
1404
976k
        if (p[1] == '\n') {
1405
26.1k
            ++p;
1406
            /* null terminate, parse and set the pjl state */
1407
26.1k
            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
26.1k
            (void)pjl_parse_and_process_line(pst);
1413
26.1k
            pst->pos = 0;
1414
26.1k
            continue;
1415
26.1k
        }
1416
1417
        /* Copy the PJL line into the parser's line buffer. */
1418
        /* Always leave room for a terminator. */
1419
950k
        if (pst->pos == pst->line_size) {
1420
90
            char *temp = (char *)gs_alloc_bytes (pst->mem, pst->line_size + 256, "pjl_state increase line buffer");
1421
90
            if (temp != NULL) {
1422
90
                memcpy(temp, pst->line, pst->line_size);
1423
90
                gs_free_object(pst->mem, pst->line, "pjl_state line buffer");
1424
90
                pst->line = temp;
1425
90
                pst->line_size += 256;
1426
90
                pst->line[pst->pos] = p[1], pst->pos++;
1427
90
            }
1428
90
        } else
1429
950k
            pst->line[pst->pos] = p[1], pst->pos++;
1430
950k
        ++p;
1431
950k
    }
1432
6.64k
    pr->ptr = p;
1433
6.64k
    return code;
1434
6.64k
}
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
99.1k
{
1503
99.1k
    int i;
1504
1505
495k
    for (i = 0; symbol_sets[i].symname; i++)
1506
495k
        if (!pjl_compare(symname, symbol_sets[i].symname))
1507
99.1k
            return symbol_sets[i].pcl_code;
1508
0
    return -1;
1509
99.1k
}
1510
1511
/* environment variable to integer */
1512
int
1513
pjl_vartoi(const pjl_envvar_t * s)
1514
138k
{
1515
138k
    return atoi(s);
1516
138k
}
1517
1518
/* environment variable to float */
1519
double
1520
pjl_vartof(const pjl_envvar_t * s)
1521
297k
{
1522
297k
    return atof(s);
1523
297k
}
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
105k
{
1530
105k
    int i;
1531
1532
    /* if an environment variable is set we use it, otherwise use the PJL
1533
       machinery */
1534
105k
    if (pjls->environment_font_path != NULL)
1535
0
        return pjl_check_font_path(pjls->environment_font_path, pjls->mem);
1536
105k
    for (i = 0; pjls->font_envir[i].designator[0]; i++)
1537
105k
        if (!pjl_compare(pjls->font_envir[i].designator, fontsource))
1538
105k
            return pjl_check_font_path(pjls->font_envir[i].pathname,
1539
105k
                                       pjls->mem);
1540
0
    return NULL;
1541
105k
}
1542
1543
static int set_pjl_defaults_to_factory(gs_memory_t * mem, pjl_envir_var_t **def)
1544
8.09k
{
1545
8.09k
    return set_pjl_defaults(mem, def, (pjl_envir_var_t *)&pjl_factory_defaults);
1546
8.09k
}
1547
1548
static int set_pjl_defaults(gs_memory_t * mem, pjl_envir_var_t **def, pjl_envir_var_t *from)
1549
8.09k
{
1550
8.09k
    pjl_envir_var_t *pjl_def;
1551
8.09k
    char *key, *value, *newkey, *newvalue;
1552
8.09k
    int i = 0;
1553
8.09k
    int limit = 0;
1554
1555
234k
    while (from[limit].var && from[limit].var[0] != 0x00)
1556
226k
        limit++;
1557
1558
8.09k
    pjl_def = (pjl_envir_var_t *) gs_alloc_bytes(mem,
1559
8.09k
                                                  sizeof
1560
8.09k
                                                  (pjl_envir_var_t) * (limit + 1),
1561
8.09k
                                                  "pjl_envir");
1562
8.09k
    if (!pjl_def)
1563
0
        return -1;
1564
1565
8.09k
    memset(pjl_def, 0x00, sizeof(pjl_envir_var_t) * (limit + 1));
1566
234k
    while (i < limit) {
1567
226k
        key = from[i].var;
1568
226k
        value = from[i].value;
1569
1570
226k
        newkey = (char *)gs_alloc_bytes(mem, strlen(key) + 1, "new_pjl_defaults, key");
1571
226k
        newvalue = (char *)gs_alloc_bytes(mem, strlen(value) + 1, "new_pjl_defaults, value");
1572
226k
        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
226k
        strcpy(newkey, key);
1578
226k
        strcpy(newvalue, value);
1579
226k
        pjl_def[i].var = newkey;
1580
226k
        pjl_def[i].value = newvalue;
1581
1582
226k
        i++;
1583
226k
    }
1584
8.09k
    *def = pjl_def;
1585
8.09k
    return 0;
1586
8.09k
}
1587
1588
static int set_pjl_environment_to_factory(gs_memory_t * mem, pjl_envir_var_t **env)
1589
8.09k
{
1590
8.09k
    return set_pjl_environment(mem, env, (pjl_envir_var_t *)&pjl_factory_defaults);
1591
8.09k
}
1592
1593
static int set_pjl_environment(gs_memory_t * mem, pjl_envir_var_t **env, pjl_envir_var_t *from)
1594
31.8k
{
1595
31.8k
    pjl_envir_var_t *pjl_env;
1596
31.8k
    char *key, *value, *newkey, *newvalue;
1597
31.8k
    int i = 0;
1598
31.8k
    int limit = 0;
1599
1600
922k
    while (from[limit].var && from[limit].var[0] != 0x00)
1601
890k
        limit++;
1602
1603
31.8k
    pjl_env = (pjl_envir_var_t *) gs_alloc_bytes(mem,
1604
31.8k
                                                  (size_t)sizeof
1605
31.8k
                                                  (pjl_envir_var_t) * (limit + 1),
1606
31.8k
                                                  "pjl_envir");
1607
31.8k
    if (!pjl_env)
1608
0
        return -1;
1609
1610
31.8k
    memset(pjl_env, 0x00, sizeof(pjl_envir_var_t) * (limit + 1));
1611
922k
    while (i < limit) {
1612
890k
        key = from[i].var;
1613
890k
        value = from[i].value;
1614
890k
        newkey = (char *)gs_alloc_bytes(mem, strlen(key) + 1, "pjl_envir, key");
1615
890k
        newvalue = (char *)gs_alloc_bytes(mem, strlen(value) + 1, "pjl_envir, value");
1616
890k
        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
890k
        strcpy(newkey, key);
1622
890k
        strcpy(newvalue, value);
1623
890k
        pjl_env[i].var = newkey;
1624
890k
        pjl_env[i].value = newvalue;
1625
1626
890k
        i++;
1627
890k
    }
1628
31.8k
    *env = pjl_env;
1629
31.8k
    return 0;
1630
31.8k
}
1631
1632
static int set_pjl_fontsource_to_factory(gs_memory_t * mem, pjl_fontsource_t **fontenv)
1633
8.09k
{
1634
8.09k
    return set_pjl_fontsource(mem, fontenv, (pjl_fontsource_t *)pjl_fontsource_table);
1635
8.09k
}
1636
1637
static int set_pjl_fontsource(gs_memory_t * mem, pjl_fontsource_t **fontenv, pjl_fontsource_t *from)
1638
31.8k
{
1639
31.8k
    pjl_fontsource_t *pjl_fontenv;
1640
31.8k
    char *key, *value, *newkey, *newvalue;
1641
31.8k
    int i = 0;
1642
31.8k
    int limit = 0;
1643
1644
318k
    while (from[limit].pathname && from[limit].pathname[0] != 0x00)
1645
286k
        limit++;
1646
1647
31.8k
    pjl_fontenv = (pjl_fontsource_t *) gs_alloc_bytes(mem,
1648
31.8k
                                                      (size_t)sizeof
1649
31.8k
                                                      (pjl_fontsource_t) * (limit + 1),
1650
31.8k
                                                      "font_envir");
1651
31.8k
    if (!pjl_fontenv)
1652
0
        return -1;
1653
1654
31.8k
    memset(pjl_fontenv, 0x00, sizeof(pjl_fontsource_t) * (limit + 1));
1655
318k
    while (i < limit) {
1656
286k
        key = from[i].pathname;
1657
286k
        value = from[i].fontnumber;
1658
1659
286k
        newkey = (char *)gs_alloc_bytes(mem, strlen(key) + 1, "new_font_envir, pathname");
1660
286k
        if (!newkey) {
1661
0
            free_pjl_fontsource(mem, &pjl_fontenv);
1662
0
            return -1;
1663
0
        }
1664
286k
        strcpy(newkey, key);
1665
286k
        pjl_fontenv[i].pathname = newkey;
1666
286k
        if (value) {
1667
286k
            newvalue = (char *)gs_alloc_bytes(mem, strlen(value) + 1, "new_font_envir, fontnumber");
1668
286k
            if (!newvalue) {
1669
0
                free_pjl_fontsource(mem, &pjl_fontenv);
1670
0
                return -1;
1671
0
            }
1672
286k
            strcpy(newvalue, value);
1673
286k
            pjl_fontenv[i].fontnumber = newvalue;
1674
286k
        } else {
1675
0
            pjl_fontenv[i].fontnumber = 0x00;
1676
0
        }
1677
286k
        memcpy(pjl_fontenv[i].designator, pjl_fontsource_table[i].designator, 2);
1678
1679
286k
        i++;
1680
286k
    }
1681
31.8k
    *fontenv = pjl_fontenv;
1682
31.8k
    return 0;
1683
31.8k
}
1684
1685
static int set_pjl_default_fontsource_to_factory(gs_memory_t * mem, pjl_fontsource_t **fontdef)
1686
8.09k
{
1687
8.09k
    return set_pjl_default_fontsource(mem, fontdef, (pjl_fontsource_t *)&pjl_fontsource_table);
1688
8.09k
}
1689
1690
static int set_pjl_default_fontsource(gs_memory_t * mem, pjl_fontsource_t **fontdef, pjl_fontsource_t *from)
1691
8.09k
{
1692
8.09k
    pjl_fontsource_t *pjl_fontdef;
1693
8.09k
    char *key, *value, *newkey, *newvalue;
1694
8.09k
    int i = 0;
1695
8.09k
    int limit = 0;
1696
1697
80.9k
    while (from[limit].pathname && from[limit].pathname[0] != 0x00)
1698
72.8k
        limit++;
1699
1700
8.09k
    pjl_fontdef = (pjl_fontsource_t *) gs_alloc_bytes(mem,
1701
8.09k
                                                      (size_t)sizeof
1702
8.09k
                                                      (pjl_fontsource_t) * (limit + 1),
1703
8.09k
                                                      "new_font_defaults");
1704
8.09k
    if (!pjl_fontdef)
1705
0
        return -1;
1706
1707
8.09k
    memset(pjl_fontdef, 0x00, sizeof(pjl_fontsource_t) * (limit + 1));
1708
80.9k
    while (i < limit) {
1709
72.8k
        key = from[i].pathname;
1710
72.8k
        value = from[i].fontnumber;
1711
1712
72.8k
        newkey = (char *)gs_alloc_bytes(mem, strlen(key) + 1, "new_font_defaults, pathname");
1713
72.8k
        if (!newkey) {
1714
0
            free_pjl_default_fontsource(mem, &pjl_fontdef);
1715
0
            return -1;
1716
0
        }
1717
72.8k
        strcpy(newkey, key);
1718
72.8k
        pjl_fontdef[i].pathname = newkey;
1719
72.8k
        if (value) {
1720
72.8k
            newvalue = (char *)gs_alloc_bytes(mem, strlen(value) + 1, "new_font_defaults, fontnumber");
1721
72.8k
            if (!newvalue) {
1722
0
                free_pjl_default_fontsource(mem, &pjl_fontdef);
1723
0
                return -1;
1724
0
            }
1725
72.8k
            strcpy(newvalue, value);
1726
72.8k
            pjl_fontdef[i].fontnumber = newvalue;
1727
72.8k
        } else {
1728
0
            pjl_fontdef[i].fontnumber = 0x00;
1729
0
        }
1730
72.8k
        memcpy(pjl_fontdef[i].designator, pjl_fontsource_table[i].designator, 2);
1731
1732
72.8k
        i++;
1733
72.8k
    }
1734
8.09k
    *fontdef = pjl_fontdef;
1735
8.09k
    return 0;
1736
8.09k
}
1737
1738
static int free_pjl_defaults(gs_memory_t * mem, pjl_envir_var_t **def)
1739
8.09k
{
1740
8.09k
    int i=0;
1741
8.09k
    pjl_envir_var_t *pjl_def = *def;
1742
1743
234k
    while (pjl_def[i].var) {
1744
226k
        gs_free_object(mem, pjl_def[i].var, "free pjl_defaults key");
1745
226k
        gs_free_object(mem, pjl_def[i].value, "free pjl_defaults value");
1746
226k
        i++;
1747
226k
    }
1748
8.09k
    gs_free_object(mem, pjl_def, "pjl_defaults");
1749
8.09k
    *def = 0x00;
1750
8.09k
    return 0;
1751
8.09k
}
1752
1753
int free_pjl_environment(gs_memory_t * mem, pjl_envir_var_t **env)
1754
31.8k
{
1755
31.8k
    int i=0;
1756
31.8k
    pjl_envir_var_t *pjl_env = *env;
1757
1758
31.8k
    if (pjl_env == NULL)
1759
0
        return 0;
1760
1761
922k
    while (pjl_env[i].var) {
1762
890k
        gs_free_object(mem, pjl_env[i].var, "free pjl_environment key");
1763
890k
        gs_free_object(mem, pjl_env[i].value, "free pjl_environment value");
1764
890k
        i++;
1765
890k
    }
1766
31.8k
    gs_free_object(mem, pjl_env, "pjl_environment");
1767
31.8k
    *env = 0x00;
1768
31.8k
    return 0;
1769
31.8k
}
1770
1771
int free_pjl_fontsource(gs_memory_t * mem, pjl_fontsource_t **fontenv)
1772
31.8k
{
1773
31.8k
    int i=0;
1774
31.8k
    pjl_fontsource_t *pjl_fontenv = *fontenv;
1775
1776
31.8k
    if (pjl_fontenv == NULL)
1777
0
        return 0;
1778
1779
318k
    while (pjl_fontenv[i].pathname) {
1780
286k
        gs_free_object(mem, pjl_fontenv[i].pathname, "pjl_font_envir pathname");
1781
286k
        gs_free_object(mem, pjl_fontenv[i].fontnumber, "pjl_font_envir fontnumber");
1782
286k
        i++;
1783
286k
    }
1784
31.8k
    gs_free_object(mem, pjl_fontenv, "pjl_font_envir");
1785
31.8k
    *fontenv = 0x00;
1786
31.8k
    return 0;
1787
31.8k
}
1788
1789
int free_pjl_default_fontsource(gs_memory_t * mem, pjl_fontsource_t **fontdef)
1790
8.09k
{
1791
8.09k
    int i=0;
1792
8.09k
    pjl_fontsource_t *pjl_fontdef = *fontdef;
1793
1794
80.9k
    while (pjl_fontdef[i].pathname) {
1795
72.8k
        gs_free_object(mem, pjl_fontdef[i].pathname, "pjl_font_defaults pathname");
1796
72.8k
        gs_free_object(mem, pjl_fontdef[i].fontnumber, "pjl_font_defaults fontnumber");
1797
72.8k
        i++;
1798
72.8k
    }
1799
8.09k
    gs_free_object(mem, pjl_fontdef, "pjl_font_defaults");
1800
8.09k
    *fontdef = 0x00;
1801
8.09k
    return 0;
1802
8.09k
}
1803
1804
/* Create and initialize a new state. */
1805
pjl_parser_state *
1806
pjl_process_init(gs_memory_t * mem)
1807
8.09k
{
1808
8.09k
    pjl_envir_var_t *pjl_env, *pjl_def;
1809
8.09k
    pjl_fontsource_t *pjl_fontenv, *pjl_fontdef;
1810
1811
8.09k
    pjl_parser_state_t *pjlstate = (pjl_parser_state *) gs_alloc_bytes(mem,
1812
8.09k
                                                                       sizeof
1813
8.09k
                                                                       (pjl_parser_state_t),
1814
8.09k
                                                                       "pjl_state");
1815
1816
8.09k
    if (pjlstate == NULL)
1817
0
        return NULL;            /* should be fatal so we don't bother piecemeal frees */
1818
1819
8.09k
    pjlstate->line = (char *)gs_alloc_bytes(mem, 256, "pjl_state line buffer");
1820
8.09k
    if (pjlstate->line == NULL) {
1821
0
        gs_free_object(mem, pjlstate, "pjl_state");
1822
0
        return NULL;
1823
0
    }
1824
8.09k
    pjlstate->line_size = 255;
1825
1826
    /* check for an environment variable */
1827
8.09k
    {
1828
8.09k
        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.09k
        pathlen = 0;
1835
8.09k
        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.09k
            pjlstate->environment_font_path = NULL;
1859
8.09k
    }
1860
1861
    /* initialize the default and initial pjl environment.  We assume
1862
       that these are the same layout as the factory defaults. */
1863
8.09k
    if (set_pjl_defaults_to_factory(mem, &pjl_def) < 0) {
1864
0
        goto fail1;
1865
0
    }
1866
8.09k
    if (set_pjl_environment_to_factory(mem, &pjl_env) < 0) {
1867
0
        goto fail2;
1868
0
    }
1869
8.09k
    if (set_pjl_fontsource_to_factory(mem, &pjl_fontenv) < 0) {
1870
0
        goto fail3;
1871
0
    }
1872
8.09k
    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.09k
    pjlstate->defaults = pjl_def;
1878
8.09k
    pjlstate->envir = pjl_env;
1879
8.09k
    pjlstate->font_envir = pjl_fontenv;
1880
8.09k
    pjlstate->font_defaults = pjl_fontdef;
1881
1882
    /* initialize the current position in the line array and bytes pending */
1883
8.09k
    pjlstate->bytes_to_read = 0;
1884
8.09k
    pjlstate->bytes_to_write = 0;
1885
8.09k
    pjlstate->fp = 0;
1886
    /* line pos */
1887
8.09k
    pjlstate->pos = 0;
1888
8.09k
    pjlstate->mem = mem;
1889
    /* initialize available font sources */
1890
8.09k
    pjl_reset_fontsource_fontnumbers(pjlstate);
1891
8.09k
    {
1892
8.09k
        int i;
1893
1894
267k
        for (i = 0; i < countof(pjlstate->permanent_soft_fonts); i++)
1895
259k
            pjlstate->permanent_soft_fonts[i] = 0;
1896
8.09k
    }
1897
8.09k
    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
15.4M
{
1915
29.8M
    for (; toupper(*s1) == toupper(*s2); ++s1, ++s2)
1916
16.1M
        if (*s1 == '\0')
1917
1.62M
            return (0);
1918
13.7M
    return 1;
1919
15.4M
}
1920
1921
/* free all memory associated with the PJL state */
1922
void
1923
pjl_process_destroy(pjl_parser_state * pst)
1924
8.09k
{
1925
8.09k
    gs_memory_t *mem;
1926
1927
8.09k
    if (pst == NULL)
1928
0
        return;
1929
1930
8.09k
    mem = pst->mem;
1931
1932
8.09k
    free_pjl_defaults(mem, &pst->defaults);
1933
8.09k
    free_pjl_environment(mem, &pst->envir);
1934
8.09k
    free_pjl_fontsource(mem, &pst->font_envir);
1935
8.09k
    free_pjl_default_fontsource(mem, &pst->font_defaults);
1936
1937
8.09k
    if (pst->environment_font_path)
1938
0
        gs_free_object(mem, pst->environment_font_path, "pjl_state");
1939
8.09k
    gs_free_object(mem, pst->line, "pjl_state line buffer");
1940
8.09k
    gs_free_object(mem, pst, "pjl_state");
1941
8.09k
}
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
}