Coverage Report

Created: 2025-11-09 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cups/cups/ppd.c
Line
Count
Source
1
/*
2
 * PPD file routines for CUPS.
3
 *
4
 * Copyright © 2020-2025 by OpenPrinting.
5
 * Copyright © 2007-2019 by Apple Inc.
6
 * Copyright © 1997-2007 by Easy Software Products, all rights reserved.
7
 *
8
 * Licensed under Apache License v2.0.  See the file "LICENSE" for more
9
 * information.
10
 *
11
 * PostScript is a trademark of Adobe Systems, Inc.
12
 */
13
14
#include "cups-private.h"
15
#include "ppd-private.h"
16
#include "debug-internal.h"
17
18
19
/*
20
 * Definitions...
21
 */
22
23
2.78M
#define PPD_KEYWORD 1    /* Line contained a keyword */
24
1.33M
#define PPD_OPTION  2    /* Line contained an option name */
25
64.8k
#define PPD_TEXT  4    /* Line contained human-readable text */
26
2.70M
#define PPD_STRING  8    /* Line contained a string or code */
27
28
3.11k
#define PPD_HASHSIZE  512    /* Size of hash */
29
30
31
/*
32
 * Line buffer structure...
33
 */
34
35
typedef struct _ppd_line_s
36
{
37
  char    *buffer;    /* Pointer to buffer */
38
  size_t  bufsize;    /* Size of the buffer */
39
} _ppd_line_t;
40
41
42
/*
43
 * Local globals...
44
 */
45
46
static cups_thread_key_t ppd_globals_key = CUPS_THREADKEY_INITIALIZER;
47
          /* Thread local storage key */
48
#ifdef HAVE_PTHREAD_H
49
static pthread_once_t ppd_globals_key_once = PTHREAD_ONCE_INIT;
50
          /* One-time initialization object */
51
#endif /* HAVE_PTHREAD_H */
52
53
54
/*
55
 * Local functions...
56
 */
57
58
static ppd_attr_t *ppd_add_attr(ppd_file_t *ppd, const char *name,
59
                    const char *spec, const char *text,
60
              const char *value);
61
static ppd_choice_t *ppd_add_choice(ppd_option_t *option, const char *name);
62
static ppd_size_t *ppd_add_size(ppd_file_t *ppd, const char *name);
63
static int ppd_compare_attrs(ppd_attr_t *a, ppd_attr_t *b, void *data);
64
static int ppd_compare_choices(ppd_choice_t *a, ppd_choice_t *b, void *data);
65
static int ppd_compare_coptions(ppd_coption_t *a, ppd_coption_t *b, void *data);
66
static int ppd_compare_options(ppd_option_t *a, ppd_option_t *b, void *data);
67
static int    ppd_decode(char *string);
68
static void   ppd_free_filters(ppd_file_t *ppd);
69
static void   ppd_free_group(ppd_group_t *group);
70
static void   ppd_free_option(ppd_option_t *option);
71
static ppd_coption_t  *ppd_get_coption(ppd_file_t *ppd, const char *name);
72
static ppd_cparam_t *ppd_get_cparam(ppd_coption_t *opt, const char *param,
73
                                    const char *text);
74
static ppd_group_t *ppd_get_group(ppd_file_t *ppd, const char *name,
75
                                  const char *text, _ppd_globals_t *pg,
76
                                  cups_encoding_t encoding);
77
static ppd_option_t *ppd_get_option(ppd_group_t *group, const char *name);
78
static _ppd_globals_t *ppd_globals_alloc(void);
79
#if defined(HAVE_PTHREAD_H) || defined(_WIN32)
80
static void   ppd_globals_free(_ppd_globals_t *g);
81
#endif /* HAVE_PTHREAD_H || _WIN32 */
82
#ifdef HAVE_PTHREAD_H
83
static void   ppd_globals_init(void);
84
#endif /* HAVE_PTHREAD_H */
85
static int    ppd_hash_option(ppd_option_t *option, void *data);
86
static int    ppd_read(cups_file_t *fp, _ppd_line_t *line,
87
                        char *keyword, char *option, char *text,
88
                        char **string, int ignoreblank,
89
                        _ppd_globals_t *pg);
90
static int    ppd_update_filters(ppd_file_t *ppd,
91
                                 _ppd_globals_t *pg);
92
93
94
/*
95
 * 'ppdClose()' - Free all memory used by the PPD file.
96
 */
97
98
void
99
ppdClose(ppd_file_t *ppd)   /* I - PPD file record */
100
6.49k
{
101
6.49k
  int     i;    /* Looping var */
102
6.49k
  ppd_group_t   *group;   /* Current group */
103
6.49k
  char      **font;   /* Current font */
104
6.49k
  ppd_attr_t    **attr;   /* Current attribute */
105
6.49k
  ppd_coption_t   *coption; /* Current custom option */
106
6.49k
  ppd_cparam_t    *cparam;  /* Current custom parameter */
107
108
109
 /*
110
  * Range check arguments...
111
  */
112
113
6.49k
  if (!ppd)
114
0
    return;
115
116
 /*
117
  * Free all strings at the top level...
118
  */
119
120
6.49k
  free(ppd->lang_encoding);
121
6.49k
  free(ppd->nickname);
122
6.49k
  free(ppd->patches);
123
6.49k
  free(ppd->emulations);
124
6.49k
  free(ppd->jcl_begin);
125
6.49k
  free(ppd->jcl_end);
126
6.49k
  free(ppd->jcl_ps);
127
128
 /*
129
  * Free any UI groups, subgroups, and options...
130
  */
131
132
6.49k
  if (ppd->num_groups > 0)
133
2.98k
  {
134
8.86k
    for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
135
5.88k
      ppd_free_group(group);
136
137
2.98k
    free(ppd->groups);
138
2.98k
  }
139
140
6.49k
  cupsArrayDelete(ppd->options);
141
6.49k
  cupsArrayDelete(ppd->marked);
142
143
 /*
144
  * Free any page sizes...
145
  */
146
147
6.49k
  if (ppd->num_sizes > 0)
148
1.71k
    free(ppd->sizes);
149
150
 /*
151
  * Free any constraints...
152
  */
153
154
6.49k
  if (ppd->num_consts > 0)
155
653
    free(ppd->consts);
156
157
 /*
158
  * Free any filters...
159
  */
160
161
6.49k
  ppd_free_filters(ppd);
162
163
 /*
164
  * Free any fonts...
165
  */
166
167
6.49k
  if (ppd->num_fonts > 0)
168
25
  {
169
716
    for (i = ppd->num_fonts, font = ppd->fonts; i > 0; i --, font ++)
170
691
      free(*font);
171
172
25
    free(ppd->fonts);
173
25
  }
174
175
 /*
176
  * Free any profiles...
177
  */
178
179
6.49k
  if (ppd->num_profiles > 0)
180
47
    free(ppd->profiles);
181
182
 /*
183
  * Free any attributes...
184
  */
185
186
6.49k
  if (ppd->num_attrs > 0)
187
5.60k
  {
188
463k
    for (i = ppd->num_attrs, attr = ppd->attrs; i > 0; i --, attr ++)
189
457k
    {
190
457k
      free((*attr)->value);
191
457k
      free(*attr);
192
457k
    }
193
194
5.60k
    free(ppd->attrs);
195
5.60k
  }
196
197
6.49k
  cupsArrayDelete(ppd->sorted_attrs);
198
199
 /*
200
  * Free custom options...
201
  */
202
203
6.49k
  for (coption = (ppd_coption_t *)cupsArrayFirst(ppd->coptions);
204
7.50k
       coption;
205
6.49k
       coption = (ppd_coption_t *)cupsArrayNext(ppd->coptions))
206
1.00k
  {
207
1.00k
    for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
208
1.26k
         cparam;
209
1.00k
   cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
210
258
    {
211
258
      switch (cparam->type)
212
258
      {
213
10
        case PPD_CUSTOM_PASSCODE :
214
20
        case PPD_CUSTOM_PASSWORD :
215
20
        case PPD_CUSTOM_STRING :
216
20
            free(cparam->current.custom_string);
217
20
      break;
218
219
238
  default :
220
238
      break;
221
258
      }
222
223
258
      free(cparam);
224
258
    }
225
226
1.00k
    cupsArrayDelete(coption->params);
227
228
1.00k
    free(coption);
229
1.00k
  }
230
231
6.49k
  cupsArrayDelete(ppd->coptions);
232
233
 /*
234
  * Free constraints...
235
  */
236
237
6.49k
  if (ppd->cups_uiconstraints)
238
3.11k
  {
239
3.11k
    _ppd_cups_uiconsts_t *consts; /* Current constraints */
240
241
242
3.11k
    for (consts = (_ppd_cups_uiconsts_t *)cupsArrayFirst(ppd->cups_uiconstraints);
243
6.57k
         consts;
244
3.45k
   consts = (_ppd_cups_uiconsts_t *)cupsArrayNext(ppd->cups_uiconstraints))
245
3.45k
    {
246
3.45k
      free(consts->constraints);
247
3.45k
      free(consts);
248
3.45k
    }
249
250
3.11k
    cupsArrayDelete(ppd->cups_uiconstraints);
251
3.11k
  }
252
253
 /*
254
  * Free any PPD cache/mapping data...
255
  */
256
257
6.49k
  if (ppd->cache)
258
0
    _ppdCacheDestroy(ppd->cache);
259
260
 /*
261
  * Free the whole record...
262
  */
263
264
6.49k
  free(ppd);
265
6.49k
}
266
267
268
/*
269
 * 'ppdErrorString()' - Returns the text associated with a status.
270
 *
271
 * @since CUPS 1.1.19@
272
 */
273
274
const char *        /* O - Status string */
275
ppdErrorString(ppd_status_t status) /* I - PPD status */
276
0
{
277
0
  static const char * const messages[] =/* Status messages */
278
0
    {
279
0
      _("OK"),
280
0
      _("Unable to open PPD file"),
281
0
      _("NULL PPD file pointer"),
282
0
      _("Memory allocation error"),
283
0
      _("Missing PPD-Adobe-4.x header"),
284
0
      _("Missing value string"),
285
0
      _("Internal error"),
286
0
      _("Bad OpenGroup"),
287
0
      _("OpenGroup without a CloseGroup first"),
288
0
      _("Bad OpenUI/JCLOpenUI"),
289
0
      _("OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"),
290
0
      _("Bad OrderDependency"),
291
0
      _("Bad UIConstraints"),
292
0
      _("Missing asterisk in column 1"),
293
0
      _("Line longer than the maximum allowed (255 characters)"),
294
0
      _("Illegal control character"),
295
0
      _("Illegal main keyword string"),
296
0
      _("Illegal option keyword string"),
297
0
      _("Illegal translation string"),
298
0
      _("Illegal whitespace character"),
299
0
      _("Bad custom parameter"),
300
0
      _("Missing option keyword"),
301
0
      _("Bad value string"),
302
0
      _("Missing CloseGroup"),
303
0
      _("Bad CloseUI/JCLCloseUI"),
304
0
      _("Missing CloseUI/JCLCloseUI")
305
0
    };
306
307
308
0
  if (status < PPD_OK || status >= PPD_MAX_STATUS)
309
0
    return (_cupsLangString(cupsLangDefault(), _("Unknown")));
310
0
  else
311
0
    return (_cupsLangString(cupsLangDefault(), messages[status]));
312
0
}
313
314
315
/*
316
 * '_ppdGetEncoding()' - Get the CUPS encoding value for the given
317
 *                       LanguageEncoding.
318
 */
319
320
cups_encoding_t       /* O - CUPS encoding value */
321
_ppdGetEncoding(const char *name) /* I - LanguageEncoding string */
322
409
{
323
409
  if (!_cups_strcasecmp(name, "ISOLatin1"))
324
0
    return (CUPS_ISO8859_1);
325
409
  else if (!_cups_strcasecmp(name, "ISOLatin2"))
326
0
    return (CUPS_ISO8859_2);
327
409
  else if (!_cups_strcasecmp(name, "ISOLatin5"))
328
0
    return (CUPS_ISO8859_5);
329
409
  else if (!_cups_strcasecmp(name, "JIS83-RKSJ"))
330
0
    return (CUPS_JIS_X0213);
331
409
  else if (!_cups_strcasecmp(name, "MacStandard"))
332
0
    return (CUPS_MAC_ROMAN);
333
409
  else if (!_cups_strcasecmp(name, "WindowsANSI"))
334
0
    return (CUPS_WINDOWS_1252);
335
409
  else
336
409
    return (CUPS_UTF8);
337
409
}
338
339
340
/*
341
 * '_ppdGlobals()' - Return a pointer to thread local storage
342
 */
343
344
_ppd_globals_t *      /* O - Pointer to global data */
345
_ppdGlobals(void)
346
15.2k
{
347
15.2k
  _ppd_globals_t *pg;     /* Pointer to global data */
348
349
350
15.2k
#ifdef HAVE_PTHREAD_H
351
 /*
352
  * Initialize the global data exactly once...
353
  */
354
355
15.2k
  pthread_once(&ppd_globals_key_once, ppd_globals_init);
356
15.2k
#endif /* HAVE_PTHREAD_H */
357
358
 /*
359
  * See if we have allocated the data yet...
360
  */
361
362
15.2k
  if ((pg = (_ppd_globals_t *)cupsThreadGetData(ppd_globals_key)) == NULL)
363
1
  {
364
   /*
365
    * No, allocate memory as set the pointer for the key...
366
    */
367
368
1
    if ((pg = ppd_globals_alloc()) != NULL)
369
1
      cupsThreadSetData(ppd_globals_key, pg);
370
1
  }
371
372
 /*
373
  * Return the pointer to the data...
374
  */
375
376
15.2k
  return (pg);
377
15.2k
}
378
379
380
/*
381
 * 'ppdLastError()' - Return the status from the last ppdOpen*().
382
 *
383
 * @since CUPS 1.1.19@
384
 */
385
386
ppd_status_t        /* O - Status code */
387
ppdLastError(int *line)     /* O - Line number */
388
0
{
389
0
  _ppd_globals_t  *pg = _ppdGlobals();
390
          /* Global data */
391
392
393
0
  if (line)
394
0
    *line = pg->ppd_line;
395
396
0
  return (pg->ppd_status);
397
0
}
398
399
400
/*
401
 * '_ppdOpen()' - Read a PPD file into memory.
402
 *
403
 * @since CUPS 1.2@
404
 */
405
406
ppd_file_t *        /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
407
_ppdOpen(
408
    cups_file_t   *fp,    /* I - File to read from */
409
    _ppd_localization_t localization) /* I - Localization to load */
410
7.60k
{
411
7.60k
  int     i, j, k;  /* Looping vars */
412
7.60k
  _ppd_line_t   line;   /* Line buffer */
413
7.60k
  ppd_file_t    *ppd;   /* PPD file record */
414
7.60k
  ppd_group_t   *group,   /* Current group */
415
7.60k
      *subgroup;  /* Current sub-group */
416
7.60k
  ppd_option_t    *option;  /* Current option */
417
7.60k
  ppd_choice_t    *choice;  /* Current choice */
418
7.60k
  ppd_const_t   *constraint;  /* Current constraint */
419
7.60k
  ppd_size_t    *size;    /* Current page size */
420
7.60k
  int     mask;   /* Line data mask */
421
7.60k
  char      keyword[PPD_MAX_NAME],
422
            /* Keyword from file */
423
7.60k
      name[PPD_MAX_NAME],
424
          /* Option from file */
425
7.60k
      text[PPD_MAX_LINE],
426
          /* Human-readable text from file */
427
7.60k
      *string,  /* Code/text from file */
428
7.60k
      *sptr,    /* Pointer into string */
429
7.60k
      *temp,    /* Temporary string pointer */
430
7.60k
      **tempfonts;  /* Temporary fonts pointer */
431
7.60k
  float     order;    /* Order dependency number */
432
7.60k
  ppd_section_t   section;  /* Order dependency section */
433
7.60k
  ppd_profile_t   *profile; /* Pointer to color profile */
434
7.60k
  char      **filter; /* Pointer to filter */
435
7.60k
  struct lconv    *loc;   /* Locale data */
436
7.60k
  int     ui_keyword; /* Is this line a UI keyword? */
437
7.60k
  cups_lang_t   *lang;    /* Language data */
438
7.60k
  cups_encoding_t encoding; /* Encoding of PPD file */
439
7.60k
  _ppd_globals_t  *pg = _ppdGlobals();
440
          /* Global data */
441
7.60k
  char      custom_name[PPD_MAX_NAME];
442
          /* CustomFoo attribute name */
443
7.60k
  ppd_attr_t    *custom_attr; /* CustomFoo attribute */
444
7.60k
  char      ll[7],    /* Base language + '.' */
445
7.60k
      ll_CC[7]; /* Language w/country + '.' */
446
7.60k
  size_t    ll_len = 0, /* Base language length */
447
7.60k
      ll_CC_len = 0;  /* Language w/country length */
448
7.60k
  static const char * const ui_keywords[] =
449
7.60k
      {
450
#ifdef CUPS_USE_FULL_UI_KEYWORDS_LIST
451
 /*
452
  * Adobe defines some 41 keywords as "UI", meaning that they are
453
  * user interface elements and that they should be treated as such
454
  * even if the PPD creator doesn't use Open/CloseUI around them.
455
  *
456
  * Since this can cause previously invisible options to appear and
457
  * confuse users, the default is to only treat the PageSize and
458
  * PageRegion keywords this way.
459
  */
460
        /* Boolean keywords */
461
        "BlackSubstitution",
462
        "Booklet",
463
        "Collate",
464
        "ManualFeed",
465
        "MirrorPrint",
466
        "NegativePrint",
467
        "Sorter",
468
        "TraySwitch",
469
470
        /* PickOne keywords */
471
        "AdvanceMedia",
472
        "BindColor",
473
        "BindEdge",
474
        "BindType",
475
        "BindWhen",
476
        "BitsPerPixel",
477
        "ColorModel",
478
        "CutMedia",
479
        "Duplex",
480
        "FoldType",
481
        "FoldWhen",
482
        "InputSlot",
483
        "JCLFrameBufferSize",
484
        "JCLResolution",
485
        "Jog",
486
        "MediaColor",
487
        "MediaType",
488
        "MediaWeight",
489
        "OutputBin",
490
        "OutputMode",
491
        "OutputOrder",
492
        "PageRegion",
493
        "PageSize",
494
        "Resolution",
495
        "Separations",
496
        "Signature",
497
        "Slipsheet",
498
        "Smoothing",
499
        "StapleLocation",
500
        "StapleOrientation",
501
        "StapleWhen",
502
        "StapleX",
503
        "StapleY"
504
#else /* !CUPS_USE_FULL_UI_KEYWORDS_LIST */
505
7.60k
        "PageRegion",
506
7.60k
        "PageSize"
507
7.60k
#endif /* CUPS_USE_FULL_UI_KEYWORDS_LIST */
508
7.60k
      };
509
7.60k
  static const char * const color_keywords[] =  /* Keywords associated with color profiles */
510
7.60k
      {
511
7.60k
        ".cupsICCProfile",
512
7.60k
        ".ColorModel",
513
7.60k
      };
514
515
516
7.60k
  DEBUG_printf("_ppdOpen(fp=%p)", (void *)fp);
517
518
 /*
519
  * Default to "OK" status...
520
  */
521
522
7.60k
  pg->ppd_status = PPD_OK;
523
7.60k
  pg->ppd_line   = 0;
524
525
 /*
526
  * Range check input...
527
  */
528
529
7.60k
  if (fp == NULL)
530
0
  {
531
0
    pg->ppd_status = PPD_NULL_FILE;
532
0
    return (NULL);
533
0
  }
534
535
 /*
536
  * If only loading a single localization set up the strings to match...
537
  */
538
539
7.60k
  if (localization == _PPD_LOCALIZATION_DEFAULT)
540
7.60k
  {
541
7.60k
    if ((lang = cupsLangDefault()) == NULL)
542
0
      return (NULL);
543
544
7.60k
    snprintf(ll_CC, sizeof(ll_CC), "%s.", lang->language);
545
546
   /*
547
    * <rdar://problem/22130168>
548
    * <rdar://problem/27245567>
549
    *
550
    * Need to use a different base language for some locales...
551
    */
552
553
7.60k
    if (!strcmp(lang->language, "zh_HK"))
554
0
    {         /* Traditional Chinese + variants */
555
0
      cupsCopyString(ll_CC, "zh_TW.", sizeof(ll_CC));
556
0
      cupsCopyString(ll, "zh_", sizeof(ll));
557
0
    }
558
7.60k
    else if (!strncmp(lang->language, "zh", 2))
559
0
      cupsCopyString(ll, "zh_", sizeof(ll)); /* Any Chinese variant */
560
7.60k
    else if (!strncmp(lang->language, "jp", 2))
561
0
    {         /* Any Japanese variant */
562
0
      cupsCopyString(ll_CC, "ja", sizeof(ll_CC));
563
0
      cupsCopyString(ll, "jp", sizeof(ll));
564
0
    }
565
7.60k
    else if (!strncmp(lang->language, "nb", 2) || !strncmp(lang->language, "no", 2))
566
0
    {         /* Any Norwegian variant */
567
0
      cupsCopyString(ll_CC, "nb", sizeof(ll_CC));
568
0
      cupsCopyString(ll, "no", sizeof(ll));
569
0
    }
570
7.60k
    else
571
7.60k
      snprintf(ll, sizeof(ll), "%2.2s.", lang->language);
572
573
7.60k
    ll_CC_len = strlen(ll_CC);
574
7.60k
    ll_len    = strlen(ll);
575
576
7.60k
    DEBUG_printf("2_ppdOpen: Loading localizations matching \"%s\" and \"%s\"", ll_CC, ll);
577
7.60k
  }
578
579
 /*
580
  * Grab the first line and make sure it reads '*PPD-Adobe: "major.minor"'...
581
  */
582
583
7.60k
  line.buffer  = NULL;
584
7.60k
  line.bufsize = 0;
585
586
7.60k
  mask = ppd_read(fp, &line, keyword, name, text, &string, 0, pg);
587
588
7.60k
  DEBUG_printf("2_ppdOpen: mask=%x, keyword=\"%s\"...", mask, keyword);
589
590
7.60k
  if (mask == 0 ||
591
7.06k
      strcmp(keyword, "PPD-Adobe") ||
592
6.50k
      string == NULL || string[0] != '4')
593
1.10k
  {
594
   /*
595
    * Either this is not a PPD file, or it is not a 4.x PPD file.
596
    */
597
598
1.10k
    if (pg->ppd_status == PPD_OK)
599
796
      pg->ppd_status = PPD_MISSING_PPDADOBE4;
600
601
1.10k
    free(string);
602
1.10k
    free(line.buffer);
603
604
1.10k
    return (NULL);
605
1.10k
  }
606
607
6.49k
  DEBUG_printf("2_ppdOpen: keyword=%s, string=%p", keyword, (void *)string);
608
609
 /*
610
  * Allocate memory for the PPD file record...
611
  */
612
613
6.49k
  if ((ppd = calloc(1, sizeof(ppd_file_t))) == NULL)
614
0
  {
615
0
    pg->ppd_status = PPD_ALLOC_ERROR;
616
617
0
    free(string);
618
0
    free(line.buffer);
619
620
0
    return (NULL);
621
0
  }
622
623
6.49k
  free(string);
624
6.49k
  string = NULL;
625
626
6.49k
  ppd->language_level = 2;
627
6.49k
  ppd->color_device   = 0;
628
6.49k
  ppd->colorspace     = PPD_CS_N;
629
6.49k
  ppd->landscape      = -90;
630
6.49k
  ppd->coptions       = cupsArrayNew((cups_array_func_t)ppd_compare_coptions, NULL);
631
632
 /*
633
  * Read lines from the PPD file and add them to the file record...
634
  */
635
636
6.49k
  group      = NULL;
637
6.49k
  subgroup   = NULL;
638
6.49k
  option     = NULL;
639
6.49k
  choice     = NULL;
640
6.49k
  ui_keyword = 0;
641
6.49k
  encoding   = CUPS_ISO8859_1;
642
6.49k
  loc        = localeconv();
643
644
707k
  while ((mask = ppd_read(fp, &line, keyword, name, text, &string, 1, pg)) != 0)
645
701k
  {
646
701k
    DEBUG_printf("2_ppdOpen: mask=%x, keyword=\"%s\", name=\"%s\", text=\"%s\", string=%d chars...", mask, keyword, name, text, string ? (int)strlen(string) : 0);
647
648
701k
    if (strncmp(keyword, "Default", 7) && !string &&
649
81.5k
        pg->ppd_conform != PPD_CONFORM_RELAXED)
650
0
    {
651
     /*
652
      * Need a string value!
653
      */
654
655
0
      pg->ppd_status = PPD_MISSING_VALUE;
656
657
0
      goto error;
658
0
    }
659
701k
    else if (!string)
660
83.8k
      continue;
661
662
   /*
663
    * Certain main keywords (as defined by the PPD spec) may be used
664
    * without the usual OpenUI/CloseUI stuff.  Presumably this is just
665
    * so that Adobe wouldn't completely break compatibility with PPD
666
    * files prior to v4.0 of the spec, but it is hopelessly
667
    * inconsistent...  Catch these main keywords and automatically
668
    * create the corresponding option, as needed...
669
    */
670
671
617k
    if (ui_keyword)
672
47.7k
    {
673
     /*
674
      * Previous line was a UI keyword...
675
      */
676
677
47.7k
      option     = NULL;
678
47.7k
      ui_keyword = 0;
679
47.7k
    }
680
681
   /*
682
    * If we are filtering out keyword localizations, see if this line needs to
683
    * be used...
684
    */
685
686
617k
    if (localization != _PPD_LOCALIZATION_ALL &&
687
617k
        (temp = strchr(keyword, '.')) != NULL &&
688
14.1k
        ((temp - keyword) == 2 || (temp - keyword) == 5) &&
689
8.58k
        _cups_isalpha(keyword[0]) &&
690
4.00k
        _cups_isalpha(keyword[1]) &&
691
3.12k
        (keyword[2] == '.' ||
692
1.89k
         (keyword[2] == '_' && _cups_isalpha(keyword[3]) &&
693
974
          _cups_isalpha(keyword[4]) && keyword[5] == '.')))
694
1.95k
    {
695
1.95k
      if (localization == _PPD_LOCALIZATION_NONE ||
696
1.95k
    (localization == _PPD_LOCALIZATION_DEFAULT &&
697
1.95k
     strncmp(ll_CC, keyword, ll_CC_len) &&
698
1.84k
     strncmp(ll, keyword, ll_len)))
699
1.69k
      {
700
1.69k
  DEBUG_printf("2_ppdOpen: Ignoring localization: \"%s\"\n", keyword);
701
1.69k
  free(string);
702
1.69k
  string = NULL;
703
1.69k
  continue;
704
1.69k
      }
705
254
      else if (localization == _PPD_LOCALIZATION_ICC_PROFILES)
706
0
      {
707
       /*
708
        * Only load localizations for the color profile related keywords...
709
        */
710
711
0
  for (i = 0;
712
0
       i < (int)(sizeof(color_keywords) / sizeof(color_keywords[0]));
713
0
       i ++)
714
0
  {
715
0
    if (!_cups_strcasecmp(temp, color_keywords[i]))
716
0
      break;
717
0
  }
718
719
0
  if (i >= (int)(sizeof(color_keywords) / sizeof(color_keywords[0])))
720
0
  {
721
0
    DEBUG_printf("2_ppdOpen: Ignoring localization: \"%s\"\n", keyword);
722
0
    free(string);
723
0
    string = NULL;
724
0
    continue;
725
0
  }
726
0
      }
727
1.95k
    }
728
729
615k
    if (option == NULL &&
730
477k
        (mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) ==
731
477k
      (PPD_KEYWORD | PPD_OPTION | PPD_STRING))
732
77.3k
    {
733
183k
      for (i = 0; i < (int)(sizeof(ui_keywords) / sizeof(ui_keywords[0])); i ++)
734
154k
        if (!strcmp(keyword, ui_keywords[i]))
735
48.0k
    break;
736
737
77.3k
      if (i < (int)(sizeof(ui_keywords) / sizeof(ui_keywords[0])))
738
48.0k
      {
739
       /*
740
        * Create the option in the appropriate group...
741
  */
742
743
48.0k
        ui_keyword = 1;
744
745
48.0k
        DEBUG_printf("2_ppdOpen: FOUND ADOBE UI KEYWORD %s WITHOUT OPENUI!", keyword);
746
747
48.0k
        if (!group)
748
43.1k
  {
749
43.1k
          if ((group = ppd_get_group(ppd, "General", _("General"), pg,
750
43.1k
                               encoding)) == NULL)
751
0
      goto error;
752
753
43.1k
          DEBUG_printf("2_ppdOpen: Adding to group %s...", group->text);
754
43.1k
          option = ppd_get_option(group, keyword);
755
43.1k
    group  = NULL;
756
43.1k
  }
757
4.88k
  else
758
4.88k
          option = ppd_get_option(group, keyword);
759
760
48.0k
  if (option == NULL)
761
0
  {
762
0
          pg->ppd_status = PPD_ALLOC_ERROR;
763
764
0
          goto error;
765
0
  }
766
767
       /*
768
  * Now fill in the initial information for the option...
769
  */
770
771
48.0k
  if (!strncmp(keyword, "JCL", 3))
772
0
          option->section = PPD_ORDER_JCL;
773
48.0k
  else
774
48.0k
          option->section = PPD_ORDER_ANY;
775
776
48.0k
  option->order = 10.0f;
777
778
48.0k
  if (i < 8)
779
48.0k
          option->ui = PPD_UI_BOOLEAN;
780
0
  else
781
0
          option->ui = PPD_UI_PICKONE;
782
783
22.2M
        for (j = 0; j < ppd->num_attrs; j ++)
784
22.1M
    if (!strncmp(ppd->attrs[j]->name, "Default", 7) &&
785
64.1k
        !strcmp(ppd->attrs[j]->name + 7, keyword) &&
786
13.1k
        ppd->attrs[j]->value)
787
13.1k
    {
788
13.1k
      DEBUG_printf("2_ppdOpen: Setting Default%s to %s via attribute...", option->keyword, ppd->attrs[j]->value);
789
13.1k
      cupsCopyString(option->defchoice, ppd->attrs[j]->value,
790
13.1k
              sizeof(option->defchoice));
791
13.1k
      break;
792
13.1k
    }
793
794
48.0k
        if (!strcmp(keyword, "PageSize"))
795
47.9k
    cupsCopyString(option->text, _("Media Size"), sizeof(option->text));
796
120
  else if (!strcmp(keyword, "MediaType"))
797
0
    cupsCopyString(option->text, _("Media Type"), sizeof(option->text));
798
120
  else if (!strcmp(keyword, "InputSlot"))
799
0
    cupsCopyString(option->text, _("Media Source"), sizeof(option->text));
800
120
  else if (!strcmp(keyword, "ColorModel"))
801
0
    cupsCopyString(option->text, _("Output Mode"), sizeof(option->text));
802
120
  else if (!strcmp(keyword, "Resolution"))
803
0
    cupsCopyString(option->text, _("Resolution"), sizeof(option->text));
804
120
        else
805
120
    cupsCopyString(option->text, keyword, sizeof(option->text));
806
48.0k
      }
807
77.3k
    }
808
809
615k
    if (!strcmp(keyword, "LanguageLevel"))
810
1.08k
      ppd->language_level = atoi(string);
811
614k
    else if (!strcmp(keyword, "LanguageEncoding"))
812
409
    {
813
     /*
814
      * Say all PPD files are UTF-8, since we convert to UTF-8...
815
      */
816
817
409
      ppd->lang_encoding = strdup("UTF-8");
818
409
      encoding           = _ppdGetEncoding(string);
819
409
    }
820
614k
    else if (!strcmp(keyword, "LanguageVersion"))
821
183
      ppd->lang_version = string;
822
613k
    else if (!strcmp(keyword, "Manufacturer"))
823
590
      ppd->manufacturer = string;
824
613k
    else if (!strcmp(keyword, "ModelName"))
825
594
      ppd->modelname = string;
826
612k
    else if (!strcmp(keyword, "Protocols"))
827
1.11k
      ppd->protocols = string;
828
611k
    else if (!strcmp(keyword, "PCFileName"))
829
104
      ppd->pcfilename = string;
830
611k
    else if (!strcmp(keyword, "NickName"))
831
1.23k
    {
832
1.23k
      if (encoding != CUPS_UTF8)
833
750
      {
834
750
        cups_utf8_t utf8[256];  /* UTF-8 version of NickName */
835
836
837
750
        cupsCharsetToUTF8(utf8, string, sizeof(utf8), encoding);
838
750
  ppd->nickname = strdup((char *)utf8);
839
750
      }
840
482
      else
841
482
        ppd->nickname = strdup(string);
842
1.23k
    }
843
610k
    else if (!strcmp(keyword, "Product"))
844
310
      ppd->product = string;
845
609k
    else if (!strcmp(keyword, "ShortNickName"))
846
778
      ppd->shortnickname = string;
847
609k
    else if (!strcmp(keyword, "TTRasterizer"))
848
801
      ppd->ttrasterizer = string;
849
608k
    else if (!strcmp(keyword, "JCLBegin"))
850
1.36k
    {
851
1.36k
      ppd->jcl_begin = strdup(string);
852
1.36k
      ppd_decode(ppd->jcl_begin); /* Decode quoted string */
853
1.36k
    }
854
606k
    else if (!strcmp(keyword, "JCLEnd"))
855
106
    {
856
106
      ppd->jcl_end = strdup(string);
857
106
      ppd_decode(ppd->jcl_end);   /* Decode quoted string */
858
106
    }
859
606k
    else if (!strcmp(keyword, "JCLToPSInterpreter"))
860
372
    {
861
372
      ppd->jcl_ps = strdup(string);
862
372
      ppd_decode(ppd->jcl_ps);    /* Decode quoted string */
863
372
    }
864
606k
    else if (!strcmp(keyword, "AccurateScreensSupport"))
865
1.76k
      ppd->accurate_screens = !strcasecmp(string, "True");
866
604k
    else if (!strcmp(keyword, "ColorDevice"))
867
680
      ppd->color_device = !strcasecmp(string, "True");
868
604k
    else if (!strcmp(keyword, "ContoneOnly"))
869
256
      ppd->contone_only = !strcasecmp(string, "True");
870
603k
    else if (!strcmp(keyword, "cupsFlipDuplex"))
871
345
      ppd->flip_duplex = !strcasecmp(string, "True");
872
603k
    else if (!strcmp(keyword, "cupsManualCopies"))
873
920
      ppd->manual_copies = !strcasecmp(string, "True");
874
602k
    else if (!strcmp(keyword, "cupsModelNumber"))
875
110
      ppd->model_number = atoi(string);
876
602k
    else if (!strcmp(keyword, "cupsColorProfile"))
877
646
    {
878
646
      if (ppd->num_profiles == 0)
879
47
        profile = malloc(sizeof(ppd_profile_t));
880
599
      else
881
599
        profile = realloc(ppd->profiles, sizeof(ppd_profile_t) * (size_t)(ppd->num_profiles + 1));
882
883
646
      if (!profile)
884
0
      {
885
0
        pg->ppd_status = PPD_ALLOC_ERROR;
886
887
0
  goto error;
888
0
      }
889
890
646
      ppd->profiles     = profile;
891
646
      profile           += ppd->num_profiles;
892
646
      ppd->num_profiles ++;
893
894
646
      memset(profile, 0, sizeof(ppd_profile_t));
895
646
      cupsCopyString(profile->resolution, name, sizeof(profile->resolution));
896
646
      cupsCopyString(profile->media_type, text, sizeof(profile->media_type));
897
898
646
      profile->density      = (float)_cupsStrScand(string, &sptr, loc);
899
646
      profile->gamma        = (float)_cupsStrScand(sptr, &sptr, loc);
900
646
      profile->matrix[0][0] = (float)_cupsStrScand(sptr, &sptr, loc);
901
646
      profile->matrix[0][1] = (float)_cupsStrScand(sptr, &sptr, loc);
902
646
      profile->matrix[0][2] = (float)_cupsStrScand(sptr, &sptr, loc);
903
646
      profile->matrix[1][0] = (float)_cupsStrScand(sptr, &sptr, loc);
904
646
      profile->matrix[1][1] = (float)_cupsStrScand(sptr, &sptr, loc);
905
646
      profile->matrix[1][2] = (float)_cupsStrScand(sptr, &sptr, loc);
906
646
      profile->matrix[2][0] = (float)_cupsStrScand(sptr, &sptr, loc);
907
646
      profile->matrix[2][1] = (float)_cupsStrScand(sptr, &sptr, loc);
908
646
      profile->matrix[2][2] = (float)_cupsStrScand(sptr, &sptr, loc);
909
646
    }
910
601k
    else if (!strcmp(keyword, "cupsFilter"))
911
80.8k
    {
912
80.8k
      if (ppd->num_filters == 0)
913
105
        filter = malloc(sizeof(char *));
914
80.7k
      else
915
80.7k
        filter = realloc(ppd->filters, sizeof(char *) * (size_t)(ppd->num_filters + 1));
916
917
80.8k
      if (filter == NULL)
918
0
      {
919
0
        pg->ppd_status = PPD_ALLOC_ERROR;
920
921
0
  goto error;
922
0
      }
923
924
80.8k
      ppd->filters     = filter;
925
80.8k
      filter           += ppd->num_filters;
926
80.8k
      ppd->num_filters ++;
927
928
     /*
929
      * Make a copy of the filter string...
930
      */
931
932
80.8k
      *filter = strdup(string);
933
80.8k
    }
934
520k
    else if (!strcmp(keyword, "Throughput"))
935
1.19k
      ppd->throughput = atoi(string);
936
519k
    else if (!strcmp(keyword, "Font"))
937
691
    {
938
     /*
939
      * Add this font to the list of available fonts...
940
      */
941
942
691
      if (ppd->num_fonts == 0)
943
25
        tempfonts = (char **)malloc(sizeof(char *));
944
666
      else
945
666
        tempfonts = (char **)realloc(ppd->fonts, sizeof(char *) * (size_t)(ppd->num_fonts + 1));
946
947
691
      if (tempfonts == NULL)
948
0
      {
949
0
        pg->ppd_status = PPD_ALLOC_ERROR;
950
951
0
  goto error;
952
0
      }
953
954
691
      ppd->fonts                 = tempfonts;
955
691
      ppd->fonts[ppd->num_fonts] = strdup(name);
956
691
      ppd->num_fonts ++;
957
691
    }
958
518k
    else if (!strncmp(keyword, "ParamCustom", 11))
959
270
    {
960
270
      ppd_coption_t *coption; /* Custom option */
961
270
      ppd_cparam_t  *cparam;  /* Custom parameter */
962
270
      int   corder;   /* Order number */
963
270
      char    ctype[33],  /* Data type */
964
270
      cminimum[65], /* Minimum value */
965
270
      cmaximum[65]; /* Maximum value */
966
967
968
     /*
969
      * Get the custom option and parameter...
970
      */
971
972
270
      if ((coption = ppd_get_coption(ppd, keyword + 11)) == NULL)
973
0
      {
974
0
        pg->ppd_status = PPD_ALLOC_ERROR;
975
976
0
  goto error;
977
0
      }
978
979
270
      if ((cparam = ppd_get_cparam(coption, name, text)) == NULL)
980
0
      {
981
0
        pg->ppd_status = PPD_ALLOC_ERROR;
982
983
0
  goto error;
984
0
      }
985
986
270
      if (cparam->type != PPD_CUSTOM_UNKNOWN)
987
12
      {
988
12
        pg->ppd_status = PPD_BAD_CUSTOM_PARAM;
989
990
12
        goto error;
991
12
      }
992
993
     /*
994
      * Get the parameter data...
995
      */
996
997
258
      if (!string ||
998
258
          sscanf(string, "%d%32s%64s%64s", &corder, ctype, cminimum,
999
258
                 cmaximum) != 4)
1000
12
      {
1001
12
        pg->ppd_status = PPD_BAD_CUSTOM_PARAM;
1002
1003
12
  goto error;
1004
12
      }
1005
1006
246
      cparam->order = corder;
1007
1008
246
      if (!strcmp(ctype, "curve"))
1009
36
      {
1010
36
        cparam->type = PPD_CUSTOM_CURVE;
1011
36
  cparam->minimum.custom_curve = (float)_cupsStrScand(cminimum, NULL, loc);
1012
36
  cparam->maximum.custom_curve = (float)_cupsStrScand(cmaximum, NULL, loc);
1013
36
      }
1014
210
      else if (!strcmp(ctype, "int"))
1015
31
      {
1016
31
        cparam->type = PPD_CUSTOM_INT;
1017
31
  cparam->minimum.custom_int = atoi(cminimum);
1018
31
  cparam->maximum.custom_int = atoi(cmaximum);
1019
31
      }
1020
179
      else if (!strcmp(ctype, "invcurve"))
1021
46
      {
1022
46
        cparam->type = PPD_CUSTOM_INVCURVE;
1023
46
  cparam->minimum.custom_invcurve = (float)_cupsStrScand(cminimum, NULL, loc);
1024
46
  cparam->maximum.custom_invcurve = (float)_cupsStrScand(cmaximum, NULL, loc);
1025
46
      }
1026
133
      else if (!strcmp(ctype, "passcode"))
1027
10
      {
1028
10
        cparam->type = PPD_CUSTOM_PASSCODE;
1029
10
  cparam->minimum.custom_passcode = atoi(cminimum);
1030
10
  cparam->maximum.custom_passcode = atoi(cmaximum);
1031
10
      }
1032
123
      else if (!strcmp(ctype, "password"))
1033
10
      {
1034
10
        cparam->type = PPD_CUSTOM_PASSWORD;
1035
10
  cparam->minimum.custom_password = atoi(cminimum);
1036
10
  cparam->maximum.custom_password = atoi(cmaximum);
1037
10
      }
1038
113
      else if (!strcmp(ctype, "points"))
1039
0
      {
1040
0
        cparam->type = PPD_CUSTOM_POINTS;
1041
0
  cparam->minimum.custom_points = (float)_cupsStrScand(cminimum, NULL, loc);
1042
0
  cparam->maximum.custom_points = (float)_cupsStrScand(cmaximum, NULL, loc);
1043
0
      }
1044
113
      else if (!strcmp(ctype, "real"))
1045
14
      {
1046
14
        cparam->type = PPD_CUSTOM_REAL;
1047
14
  cparam->minimum.custom_real = (float)_cupsStrScand(cminimum, NULL, loc);
1048
14
  cparam->maximum.custom_real = (float)_cupsStrScand(cmaximum, NULL, loc);
1049
14
      }
1050
99
      else if (!strcmp(ctype, "string"))
1051
0
      {
1052
0
        cparam->type = PPD_CUSTOM_STRING;
1053
0
  cparam->minimum.custom_string = atoi(cminimum);
1054
0
  cparam->maximum.custom_string = atoi(cmaximum);
1055
0
      }
1056
99
      else
1057
99
      {
1058
99
        pg->ppd_status = PPD_BAD_CUSTOM_PARAM;
1059
1060
99
  goto error;
1061
99
      }
1062
1063
     /*
1064
      * Now special-case for CustomPageSize...
1065
      */
1066
1067
147
      if (!strcmp(coption->keyword, "PageSize"))
1068
2
      {
1069
2
  if (!strcmp(name, "Width"))
1070
0
  {
1071
0
    ppd->custom_min[0] = cparam->minimum.custom_points;
1072
0
    ppd->custom_max[0] = cparam->maximum.custom_points;
1073
0
  }
1074
2
  else if (!strcmp(name, "Height"))
1075
0
  {
1076
0
    ppd->custom_min[1] = cparam->minimum.custom_points;
1077
0
    ppd->custom_max[1] = cparam->maximum.custom_points;
1078
0
  }
1079
2
      }
1080
147
    }
1081
518k
    else if (!strcmp(keyword, "HWMargins"))
1082
1.57k
    {
1083
7.88k
      for (i = 0, sptr = string; i < 4; i ++)
1084
6.30k
        ppd->custom_margins[i] = (float)_cupsStrScand(sptr, &sptr, loc);
1085
1.57k
    }
1086
517k
    else if (!strncmp(keyword, "Custom", 6) && !strcmp(name, "True") && !option)
1087
7.02k
    {
1088
7.02k
      ppd_option_t  *custom_option; /* Custom option */
1089
1090
7.02k
      DEBUG_puts("2_ppdOpen: Processing Custom option...");
1091
1092
     /*
1093
      * Get the option and custom option...
1094
      */
1095
1096
7.02k
      if (!ppd_get_coption(ppd, keyword + 6))
1097
0
      {
1098
0
        pg->ppd_status = PPD_ALLOC_ERROR;
1099
1100
0
  goto error;
1101
0
      }
1102
1103
7.02k
      if (option && !_cups_strcasecmp(option->keyword, keyword + 6))
1104
0
        custom_option = option;
1105
7.02k
      else
1106
7.02k
        custom_option = ppdFindOption(ppd, keyword + 6);
1107
1108
7.02k
      if (custom_option)
1109
4.84k
      {
1110
       /*
1111
  * Add the "custom" option...
1112
  */
1113
1114
4.84k
        if ((choice = ppdFindChoice(custom_option, "Custom")) == NULL)
1115
154
    if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL)
1116
0
    {
1117
0
      DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
1118
1119
0
      pg->ppd_status = PPD_ALLOC_ERROR;
1120
1121
0
      goto error;
1122
0
    }
1123
1124
4.84k
  cupsCopyString(choice->text, text[0] ? text : _("Custom"),
1125
4.84k
    sizeof(choice->text));
1126
1127
4.84k
  choice->code = strdup(string);
1128
1129
4.84k
  if (custom_option->section == PPD_ORDER_JCL)
1130
615
    ppd_decode(choice->code);
1131
4.84k
      }
1132
1133
     /*
1134
      * Now process custom page sizes specially...
1135
      */
1136
1137
7.02k
      if (!strcmp(keyword, "CustomPageSize"))
1138
6.28k
      {
1139
       /*
1140
  * Add a "Custom" page size entry...
1141
  */
1142
1143
6.28k
  ppd->variable_sizes = 1;
1144
1145
6.28k
  ppd_add_size(ppd, "Custom");
1146
1147
6.28k
  if (option && !_cups_strcasecmp(option->keyword, "PageRegion"))
1148
0
    custom_option = option;
1149
6.28k
  else
1150
6.28k
    custom_option = ppdFindOption(ppd, "PageRegion");
1151
1152
6.28k
        if (custom_option)
1153
764
  {
1154
764
    if ((choice = ppdFindChoice(custom_option, "Custom")) == NULL)
1155
28
      if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL)
1156
0
      {
1157
0
        DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
1158
1159
0
        pg->ppd_status = PPD_ALLOC_ERROR;
1160
1161
0
        goto error;
1162
0
      }
1163
1164
764
    cupsCopyString(choice->text, text[0] ? text : _("Custom"),
1165
764
      sizeof(choice->text));
1166
764
        }
1167
6.28k
      }
1168
7.02k
    }
1169
510k
    else if (!strcmp(keyword, "LandscapeOrientation"))
1170
1.23k
    {
1171
1.23k
      if (!strcmp(string, "Minus90"))
1172
10
        ppd->landscape = -90;
1173
1.22k
      else if (!strcmp(string, "Plus90"))
1174
344
        ppd->landscape = 90;
1175
1.23k
    }
1176
508k
    else if (!strcmp(keyword, "Emulators") && string && ppd->num_emulations == 0)
1177
36
    {
1178
     /*
1179
      * Issue #5562: Samsung printer drivers incorrectly use Emulators keyword
1180
      *              to configure themselves
1181
      *
1182
      * The Emulators keyword was loaded but never used by anything in CUPS,
1183
      * and has no valid purpose in CUPS.  The old code was removed due to a
1184
      * memory leak (Issue #5475), so the following (new) code supports a single
1185
      * name for the Emulators keyword, allowing these drivers to work until we
1186
      * remove PPD and driver support entirely in a future version of CUPS.
1187
      */
1188
1189
36
      ppd->num_emulations = 1;
1190
36
      ppd->emulations     = calloc(1, sizeof(ppd_emul_t));
1191
1192
36
      cupsCopyString(ppd->emulations[0].name, string, sizeof(ppd->emulations[0].name));
1193
36
    }
1194
508k
    else if (!strcmp(keyword, "JobPatchFile"))
1195
1.00k
    {
1196
     /*
1197
      * CUPS STR #3421: Check for "*JobPatchFile: int: string"
1198
      */
1199
1200
1.00k
      if (isdigit(*string & 255))
1201
481
      {
1202
3.12k
        for (sptr = string + 1; isdigit(*sptr & 255); sptr ++);
1203
1204
481
        if (*sptr == ':')
1205
1
        {
1206
         /*
1207
          * Found "*JobPatchFile: int: string"...
1208
          */
1209
1210
1
          pg->ppd_status = PPD_BAD_VALUE;
1211
1212
1
    goto error;
1213
1
        }
1214
481
      }
1215
1216
1.00k
      if (!name[0] && pg->ppd_conform == PPD_CONFORM_STRICT)
1217
0
      {
1218
       /*
1219
        * Found "*JobPatchFile: string"...
1220
        */
1221
1222
0
        pg->ppd_status = PPD_MISSING_OPTION_KEYWORD;
1223
1224
0
  goto error;
1225
0
      }
1226
1227
1.00k
      if (ppd->patches == NULL)
1228
71
        ppd->patches = strdup(string);
1229
935
      else
1230
935
      {
1231
935
        temp = realloc(ppd->patches, strlen(ppd->patches) +
1232
935
                               strlen(string) + 1);
1233
935
        if (temp == NULL)
1234
0
  {
1235
0
          pg->ppd_status = PPD_ALLOC_ERROR;
1236
1237
0
    goto error;
1238
0
  }
1239
1240
935
        ppd->patches = temp;
1241
1242
935
        memcpy(ppd->patches + strlen(ppd->patches), string, strlen(string) + 1);
1243
935
      }
1244
1.00k
    }
1245
507k
    else if (!strcmp(keyword, "OpenUI"))
1246
36.6k
    {
1247
     /*
1248
      * Don't allow nesting of options...
1249
      */
1250
1251
36.6k
      if (option && pg->ppd_conform == PPD_CONFORM_STRICT)
1252
0
      {
1253
0
        pg->ppd_status = PPD_NESTED_OPEN_UI;
1254
1255
0
  goto error;
1256
0
      }
1257
1258
     /*
1259
      * Add an option record to the current sub-group, group, or file...
1260
      */
1261
1262
36.6k
      DEBUG_printf("2_ppdOpen: name=\"%s\" (%d)", name, (int)strlen(name));
1263
1264
36.6k
      if (name[0] == '*')
1265
34.4k
        _cups_strcpy(name, name + 1); /* Eliminate leading asterisk */
1266
1267
36.6k
      for (i = (int)strlen(name) - 1; i > 0 && _cups_isspace(name[i]); i --)
1268
0
        name[i] = '\0'; /* Eliminate trailing spaces */
1269
1270
36.6k
      DEBUG_printf("2_ppdOpen: OpenUI of %s in group %s...", name, group ? group->text : "(null)");
1271
1272
36.6k
      if (subgroup != NULL)
1273
0
        option = ppd_get_option(subgroup, name);
1274
36.6k
      else if (group == NULL)
1275
34.5k
      {
1276
34.5k
  if ((group = ppd_get_group(ppd, "General", _("General"), pg,
1277
34.5k
                             encoding)) == NULL)
1278
0
    goto error;
1279
1280
34.5k
        DEBUG_printf("2_ppdOpen: Adding to group %s...", group->text);
1281
34.5k
        option = ppd_get_option(group, name);
1282
34.5k
  group  = NULL;
1283
34.5k
      }
1284
2.09k
      else
1285
2.09k
        option = ppd_get_option(group, name);
1286
1287
36.6k
      if (option == NULL)
1288
0
      {
1289
0
        pg->ppd_status = PPD_ALLOC_ERROR;
1290
1291
0
  goto error;
1292
0
      }
1293
1294
     /*
1295
      * Now fill in the initial information for the option...
1296
      */
1297
1298
36.6k
      if (string && !strcmp(string, "PickMany"))
1299
124
        option->ui = PPD_UI_PICKMANY;
1300
36.5k
      else if (string && !strcmp(string, "Boolean"))
1301
272
        option->ui = PPD_UI_BOOLEAN;
1302
36.2k
      else if (string && !strcmp(string, "PickOne"))
1303
23.2k
        option->ui = PPD_UI_PICKONE;
1304
13.0k
      else if (pg->ppd_conform == PPD_CONFORM_STRICT)
1305
0
      {
1306
0
        pg->ppd_status = PPD_BAD_OPEN_UI;
1307
1308
0
  goto error;
1309
0
      }
1310
13.0k
      else
1311
13.0k
        option->ui = PPD_UI_PICKONE;
1312
1313
3.40M
      for (j = 0; j < ppd->num_attrs; j ++)
1314
3.37M
  if (!strncmp(ppd->attrs[j]->name, "Default", 7) &&
1315
58.3k
      !strcmp(ppd->attrs[j]->name + 7, name) &&
1316
6.42k
      ppd->attrs[j]->value)
1317
6.42k
  {
1318
6.42k
    DEBUG_printf("2_ppdOpen: Setting Default%s to %s via attribute...", option->keyword, ppd->attrs[j]->value);
1319
6.42k
    cupsCopyString(option->defchoice, ppd->attrs[j]->value,
1320
6.42k
            sizeof(option->defchoice));
1321
6.42k
    break;
1322
6.42k
  }
1323
1324
36.6k
      if (text[0])
1325
28.3k
        cupsCharsetToUTF8((cups_utf8_t *)option->text, text,
1326
28.3k
                     sizeof(option->text), encoding);
1327
8.37k
      else
1328
8.37k
      {
1329
8.37k
        if (!strcmp(name, "PageSize"))
1330
730
    cupsCopyString(option->text, _("Media Size"), sizeof(option->text));
1331
7.64k
  else if (!strcmp(name, "MediaType"))
1332
443
    cupsCopyString(option->text, _("Media Type"), sizeof(option->text));
1333
7.20k
  else if (!strcmp(name, "InputSlot"))
1334
344
    cupsCopyString(option->text, _("Media Source"), sizeof(option->text));
1335
6.85k
  else if (!strcmp(name, "ColorModel"))
1336
97
    cupsCopyString(option->text, _("Output Mode"), sizeof(option->text));
1337
6.75k
  else if (!strcmp(name, "Resolution"))
1338
232
    cupsCopyString(option->text, _("Resolution"), sizeof(option->text));
1339
6.52k
        else
1340
6.52k
    cupsCopyString(option->text, name, sizeof(option->text));
1341
8.37k
      }
1342
1343
36.6k
      option->section = PPD_ORDER_ANY;
1344
1345
36.6k
      free(string);
1346
36.6k
      string = NULL;
1347
1348
     /*
1349
      * Add a custom option choice if we have already seen a CustomFoo
1350
      * attribute...
1351
      */
1352
1353
36.6k
      if (!_cups_strcasecmp(name, "PageRegion"))
1354
278
        cupsCopyString(custom_name, "CustomPageSize", sizeof(custom_name));
1355
36.4k
      else
1356
36.6k
        snprintf(custom_name, sizeof(custom_name), "Custom%s", name);
1357
1358
36.6k
      if ((custom_attr = ppdFindAttr(ppd, custom_name, "True")) != NULL)
1359
3.14k
      {
1360
3.14k
        if ((choice = ppdFindChoice(option, "Custom")) == NULL)
1361
850
    if ((choice = ppd_add_choice(option, "Custom")) == NULL)
1362
0
    {
1363
0
      DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
1364
1365
0
      pg->ppd_status = PPD_ALLOC_ERROR;
1366
1367
0
      goto error;
1368
0
    }
1369
1370
3.14k
  cupsCopyString(choice->text,
1371
3.14k
          custom_attr->text[0] ? custom_attr->text : _("Custom"),
1372
3.14k
    sizeof(choice->text));
1373
3.14k
        choice->code = strdup(custom_attr->value);
1374
3.14k
      }
1375
36.6k
    }
1376
471k
    else if (!strcmp(keyword, "JCLOpenUI"))
1377
4.74k
    {
1378
     /*
1379
      * Don't allow nesting of options...
1380
      */
1381
1382
4.74k
      if (option && pg->ppd_conform == PPD_CONFORM_STRICT)
1383
0
      {
1384
0
        pg->ppd_status = PPD_NESTED_OPEN_UI;
1385
1386
0
  goto error;
1387
0
      }
1388
1389
     /*
1390
      * Find the JCL group, and add if needed...
1391
      */
1392
1393
4.74k
      group = ppd_get_group(ppd, "JCL", _("JCL"), pg, encoding);
1394
1395
4.74k
      if (group == NULL)
1396
0
  goto error;
1397
1398
     /*
1399
      * Add an option record to the current JCLs...
1400
      */
1401
1402
4.74k
      if (name[0] == '*')
1403
3.30k
        _cups_strcpy(name, name + 1);
1404
1405
4.74k
      option = ppd_get_option(group, name);
1406
1407
4.74k
      if (option == NULL)
1408
0
      {
1409
0
        pg->ppd_status = PPD_ALLOC_ERROR;
1410
1411
0
  goto error;
1412
0
      }
1413
1414
     /*
1415
      * Now fill in the initial information for the option...
1416
      */
1417
1418
4.74k
      if (string && !strcmp(string, "PickMany"))
1419
75
        option->ui = PPD_UI_PICKMANY;
1420
4.67k
      else if (string && !strcmp(string, "Boolean"))
1421
886
        option->ui = PPD_UI_BOOLEAN;
1422
3.78k
      else if (string && !strcmp(string, "PickOne"))
1423
3.64k
        option->ui = PPD_UI_PICKONE;
1424
142
      else
1425
142
      {
1426
142
        pg->ppd_status = PPD_BAD_OPEN_UI;
1427
1428
142
  goto error;
1429
142
      }
1430
1431
1.49M
      for (j = 0; j < ppd->num_attrs; j ++)
1432
1.48M
  if (!strncmp(ppd->attrs[j]->name, "Default", 7) &&
1433
145k
      !strcmp(ppd->attrs[j]->name + 7, name) &&
1434
412
      ppd->attrs[j]->value)
1435
412
  {
1436
412
    DEBUG_printf("2_ppdOpen: Setting Default%s to %s via attribute...", option->keyword, ppd->attrs[j]->value);
1437
412
    cupsCopyString(option->defchoice, ppd->attrs[j]->value,
1438
412
            sizeof(option->defchoice));
1439
412
    break;
1440
412
  }
1441
1442
4.60k
      if (text[0])
1443
3.67k
        cupsCharsetToUTF8((cups_utf8_t *)option->text, text,
1444
3.67k
                     sizeof(option->text), encoding);
1445
928
      else
1446
928
        cupsCopyString(option->text, name, sizeof(option->text));
1447
1448
4.60k
      option->section = PPD_ORDER_JCL;
1449
4.60k
      group = NULL;
1450
1451
4.60k
      free(string);
1452
4.60k
      string = NULL;
1453
1454
     /*
1455
      * Add a custom option choice if we have already seen a CustomFoo
1456
      * attribute...
1457
      */
1458
1459
4.60k
      snprintf(custom_name, sizeof(custom_name), "Custom%s", name);
1460
1461
4.60k
      if ((custom_attr = ppdFindAttr(ppd, custom_name, "True")) != NULL)
1462
2.17k
      {
1463
2.17k
  if ((choice = ppd_add_choice(option, "Custom")) == NULL)
1464
0
  {
1465
0
    DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
1466
1467
0
    pg->ppd_status = PPD_ALLOC_ERROR;
1468
1469
0
    goto error;
1470
0
  }
1471
1472
2.17k
  cupsCopyString(choice->text,
1473
2.17k
          custom_attr->text[0] ? custom_attr->text : _("Custom"),
1474
2.17k
    sizeof(choice->text));
1475
2.17k
        choice->code = strdup(custom_attr->value);
1476
2.17k
      }
1477
4.60k
    }
1478
466k
    else if (!strcmp(keyword, "CloseUI"))
1479
1.59k
    {
1480
1.59k
      if ((!option || option->section == PPD_ORDER_JCL) && pg->ppd_conform == PPD_CONFORM_STRICT)
1481
0
      {
1482
0
        pg->ppd_status = PPD_BAD_CLOSE_UI;
1483
1484
0
  goto error;
1485
0
      }
1486
1487
1.59k
      if (option && (!_cups_strcasecmp(option->defchoice, "custom") || !_cups_strncasecmp(option->defchoice, "custom.", 7)))
1488
566
      {
1489
       /*
1490
  * "*DefaultOption: Custom..." may set the default to a custom value
1491
  * or (for a very small number of incompatible PPD files) select a
1492
  * standard choice for the option, which CUPS renames to "_Custom..."
1493
  * to avoid compatibility issues.  See which this is...
1494
  */
1495
1496
566
        char tchoice[PPD_MAX_NAME]; /* Temporary choice name */
1497
1498
566
  snprintf(tchoice, sizeof(tchoice), "_%s", option->defchoice);
1499
1500
566
  if (ppdFindChoice(option, tchoice))
1501
291
  {
1502
291
    cupsCopyString(option->defchoice, tchoice, sizeof(option->defchoice));
1503
1504
291
    DEBUG_printf("2_ppdOpen: Reset Default%s to %s...", option->keyword, tchoice);
1505
291
  }
1506
566
      }
1507
1508
1.59k
      option = NULL;
1509
1510
1.59k
      free(string);
1511
1.59k
      string = NULL;
1512
1.59k
    }
1513
464k
    else if (!strcmp(keyword, "JCLCloseUI"))
1514
4.11k
    {
1515
4.11k
      if ((!option || option->section != PPD_ORDER_JCL) && pg->ppd_conform == PPD_CONFORM_STRICT)
1516
0
      {
1517
0
        pg->ppd_status = PPD_BAD_CLOSE_UI;
1518
1519
0
  goto error;
1520
0
      }
1521
1522
4.11k
      if (option && (!_cups_strcasecmp(option->defchoice, "custom") || !_cups_strncasecmp(option->defchoice, "custom.", 7)))
1523
1.47k
      {
1524
       /*
1525
  * "*DefaultOption: Custom..." may set the default to a custom value
1526
  * or (for a very small number of incompatible PPD files) select a
1527
  * standard choice for the option, which CUPS renames to "_Custom..."
1528
  * to avoid compatibility issues.  See which this is...
1529
  */
1530
1531
1.47k
        char tchoice[PPD_MAX_NAME]; /* Temporary choice name */
1532
1533
1.47k
  snprintf(tchoice, sizeof(tchoice), "_%s", option->defchoice);
1534
1535
1.47k
  if (ppdFindChoice(option, tchoice))
1536
809
  {
1537
809
    cupsCopyString(option->defchoice, tchoice, sizeof(option->defchoice));
1538
1539
809
    DEBUG_printf("2_ppdOpen: Reset Default%s to %s...", option->keyword, tchoice);
1540
809
  }
1541
1.47k
      }
1542
1543
4.11k
      option = NULL;
1544
1545
4.11k
      free(string);
1546
4.11k
      string = NULL;
1547
4.11k
    }
1548
460k
    else if (!strcmp(keyword, "OpenGroup"))
1549
3.35k
    {
1550
     /*
1551
      * Open a new group...
1552
      */
1553
1554
3.35k
      if (group != NULL)
1555
25
      {
1556
25
        pg->ppd_status = PPD_NESTED_OPEN_GROUP;
1557
1558
25
  goto error;
1559
25
      }
1560
1561
3.33k
      if (!string)
1562
0
      {
1563
0
        pg->ppd_status = PPD_BAD_OPEN_GROUP;
1564
1565
0
  goto error;
1566
0
      }
1567
1568
     /*
1569
      * Separate the group name from the text (name/text)...
1570
      */
1571
1572
3.33k
      if ((sptr = strchr(string, '/')) != NULL)
1573
302
        *sptr++ = '\0';
1574
3.03k
      else
1575
3.03k
        sptr = string;
1576
1577
     /*
1578
      * Fix up the text...
1579
      */
1580
1581
3.33k
      ppd_decode(sptr);
1582
1583
     /*
1584
      * Find/add the group...
1585
      */
1586
1587
3.33k
      group = ppd_get_group(ppd, string, sptr, pg, encoding);
1588
1589
3.33k
      if (group == NULL)
1590
0
  goto error;
1591
1592
3.33k
      free(string);
1593
3.33k
      string = NULL;
1594
3.33k
    }
1595
457k
    else if (!strcmp(keyword, "CloseGroup"))
1596
3.84k
    {
1597
3.84k
      group = NULL;
1598
1599
3.84k
      free(string);
1600
3.84k
      string = NULL;
1601
3.84k
    }
1602
453k
    else if (!strcmp(keyword, "OrderDependency"))
1603
16.6k
    {
1604
16.6k
      order = (float)_cupsStrScand(string, &sptr, loc);
1605
1606
16.6k
      if (!sptr || sscanf(sptr, "%40s%40s", name, keyword) != 2)
1607
115
      {
1608
115
        pg->ppd_status = PPD_BAD_ORDER_DEPENDENCY;
1609
1610
115
  goto error;
1611
115
      }
1612
1613
16.5k
      if (keyword[0] == '*')
1614
5.01k
        _cups_strcpy(keyword, keyword + 1);
1615
1616
16.5k
      if (!strcmp(name, "ExitServer"))
1617
37
        section = PPD_ORDER_EXIT;
1618
16.5k
      else if (!strcmp(name, "Prolog"))
1619
384
        section = PPD_ORDER_PROLOG;
1620
16.1k
      else if (!strcmp(name, "DocumentSetup"))
1621
245
        section = PPD_ORDER_DOCUMENT;
1622
15.8k
      else if (!strcmp(name, "PageSetup"))
1623
879
        section = PPD_ORDER_PAGE;
1624
15.0k
      else if (!strcmp(name, "JCLSetup"))
1625
3.39k
        section = PPD_ORDER_JCL;
1626
11.6k
      else
1627
11.6k
        section = PPD_ORDER_ANY;
1628
1629
16.5k
      if (option == NULL)
1630
8.83k
      {
1631
8.83k
        ppd_group_t *gtemp;
1632
1633
1634
       /*
1635
        * Only valid for Non-UI options...
1636
  */
1637
1638
16.7k
        for (i = ppd->num_groups, gtemp = ppd->groups; i > 0; i --, gtemp ++)
1639
10.3k
          if (gtemp->text[0] == '\0')
1640
2.44k
      break;
1641
1642
8.83k
        if (i > 0)
1643
3.85k
          for (i = 0; i < gtemp->num_options; i ++)
1644
2.54k
      if (!strcmp(keyword, gtemp->options[i].keyword))
1645
1.13k
      {
1646
1.13k
        gtemp->options[i].section = section;
1647
1.13k
        gtemp->options[i].order   = order;
1648
1.13k
        break;
1649
1.13k
      }
1650
8.83k
      }
1651
7.71k
      else
1652
7.71k
      {
1653
7.71k
        option->section = section;
1654
7.71k
  option->order   = order;
1655
7.71k
      }
1656
1657
16.5k
      free(string);
1658
16.5k
      string = NULL;
1659
16.5k
    }
1660
436k
    else if (!strncmp(keyword, "Default", 7))
1661
15.4k
    {
1662
15.4k
      if (string == NULL)
1663
0
        continue;
1664
1665
     /*
1666
      * Drop UI text, if any, from value...
1667
      */
1668
1669
15.4k
      if (strchr(string, '/') != NULL)
1670
359
        *strchr(string, '/') = '\0';
1671
1672
     /*
1673
      * Assign the default value as appropriate...
1674
      */
1675
1676
15.4k
      if (!strcmp(keyword, "DefaultColorSpace"))
1677
2.25k
      {
1678
       /*
1679
        * Set default colorspace...
1680
  */
1681
1682
2.25k
  if (!strcmp(string, "CMY"))
1683
304
          ppd->colorspace = PPD_CS_CMY;
1684
1.95k
  else if (!strcmp(string, "CMYK"))
1685
293
          ppd->colorspace = PPD_CS_CMYK;
1686
1.66k
  else if (!strcmp(string, "RGB"))
1687
648
          ppd->colorspace = PPD_CS_RGB;
1688
1.01k
  else if (!strcmp(string, "RGBK"))
1689
205
          ppd->colorspace = PPD_CS_RGBK;
1690
809
  else if (!strcmp(string, "N"))
1691
72
          ppd->colorspace = PPD_CS_N;
1692
737
  else
1693
737
          ppd->colorspace = PPD_CS_GRAY;
1694
2.25k
      }
1695
13.2k
      else if (option && !strcmp(keyword + 7, option->keyword))
1696
1.31k
      {
1697
       /*
1698
        * Set the default as part of the current option...
1699
  */
1700
1701
1.31k
  cupsCopyString(option->defchoice, string, sizeof(option->defchoice));
1702
1703
1.31k
        DEBUG_printf("2_ppdOpen: Set %s to %s...", keyword, option->defchoice);
1704
1.31k
      }
1705
11.9k
      else
1706
11.9k
      {
1707
       /*
1708
        * Lookup option and set if it has been defined...
1709
  */
1710
1711
11.9k
        ppd_option_t  *toption; /* Temporary option */
1712
1713
11.9k
        if ((toption = ppdFindOption(ppd, keyword + 7)) != NULL)
1714
5.12k
  {
1715
5.12k
    if (!_cups_strcasecmp(string, "custom") || !_cups_strncasecmp(string, "custom.", 7))
1716
1.53k
    {
1717
     /*
1718
      * "*DefaultOption: Custom..." may set the default to a custom value
1719
      * or (for a very small number of incompatible PPD files) select a
1720
      * standard choice for the option, which CUPS renames to "_Custom..."
1721
      * to avoid compatibility issues.  See which this is...
1722
      */
1723
1724
1.53k
      snprintf(toption->defchoice, sizeof(toption->defchoice), "_%s", string);
1725
1.53k
      if (!ppdFindChoice(toption, toption->defchoice))
1726
678
        cupsCopyString(toption->defchoice, string, sizeof(toption->defchoice));
1727
1.53k
    }
1728
3.59k
    else
1729
3.59k
    {
1730
3.59k
      cupsCopyString(toption->defchoice, string, sizeof(toption->defchoice));
1731
3.59k
    }
1732
1733
5.12k
    DEBUG_printf("2_ppdOpen: Set %s to %s...", keyword, toption->defchoice);
1734
5.12k
  }
1735
11.9k
      }
1736
15.4k
    }
1737
421k
    else if (!strcmp(keyword, "UIConstraints") ||
1738
393k
             !strcmp(keyword, "NonUIConstraints"))
1739
27.8k
    {
1740
27.8k
      if (!string)
1741
0
      {
1742
0
  pg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1743
0
  goto error;
1744
0
      }
1745
1746
27.8k
      if (ppd->num_consts == 0)
1747
653
  constraint = calloc(2, sizeof(ppd_const_t));
1748
27.2k
      else
1749
27.2k
  constraint = realloc(ppd->consts, (size_t)(ppd->num_consts + 2) * sizeof(ppd_const_t));
1750
1751
27.8k
      if (constraint == NULL)
1752
0
      {
1753
0
        pg->ppd_status = PPD_ALLOC_ERROR;
1754
1755
0
  goto error;
1756
0
      }
1757
1758
27.8k
      ppd->consts = constraint;
1759
27.8k
      constraint += ppd->num_consts;
1760
27.8k
      ppd->num_consts ++;
1761
1762
27.8k
      switch (sscanf(string, "%40s%40s%40s%40s", constraint->option1,
1763
27.8k
                     constraint->choice1, constraint->option2,
1764
27.8k
         constraint->choice2))
1765
27.8k
      {
1766
18
        default : /* Error */
1767
18
      pg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1768
18
      goto error;
1769
1770
4.50k
  case 2 : /* Two options... */
1771
     /*
1772
      * Check for broken constraints like "* Option"...
1773
      */
1774
1775
4.50k
      if (pg->ppd_conform == PPD_CONFORM_STRICT &&
1776
0
          (!strcmp(constraint->option1, "*") ||
1777
0
           !strcmp(constraint->choice1, "*")))
1778
0
      {
1779
0
        pg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1780
0
        goto error;
1781
0
      }
1782
1783
     /*
1784
      * The following strcpy's are safe, as optionN and
1785
      * choiceN are all the same size (size defined by PPD spec...)
1786
      */
1787
1788
4.50k
      if (constraint->option1[0] == '*')
1789
1.76k
        _cups_strcpy(constraint->option1, constraint->option1 + 1);
1790
2.74k
      else if (pg->ppd_conform == PPD_CONFORM_STRICT)
1791
0
      {
1792
0
        pg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1793
0
        goto error;
1794
0
      }
1795
1796
4.50k
      if (constraint->choice1[0] == '*')
1797
1.03k
        _cups_strcpy(constraint->option2, constraint->choice1 + 1);
1798
3.47k
      else if (pg->ppd_conform == PPD_CONFORM_STRICT)
1799
0
      {
1800
0
        pg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1801
0
        goto error;
1802
0
      }
1803
1804
4.50k
            constraint->choice1[0] = '\0';
1805
4.50k
            constraint->choice2[0] = '\0';
1806
4.50k
      break;
1807
1808
15.8k
  case 3 : /* Two options, one choice... */
1809
     /*
1810
      * Check for broken constraints like "* Option"...
1811
      */
1812
1813
15.8k
      if (pg->ppd_conform == PPD_CONFORM_STRICT &&
1814
0
          (!strcmp(constraint->option1, "*") ||
1815
0
           !strcmp(constraint->choice1, "*") ||
1816
0
           !strcmp(constraint->option2, "*")))
1817
0
      {
1818
0
        pg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1819
0
        goto error;
1820
0
      }
1821
1822
     /*
1823
      * The following _cups_strcpy's are safe, as optionN and
1824
      * choiceN are all the same size (size defined by PPD spec...)
1825
      */
1826
1827
15.8k
      if (constraint->option1[0] == '*')
1828
8.78k
        _cups_strcpy(constraint->option1, constraint->option1 + 1);
1829
7.01k
      else if (pg->ppd_conform == PPD_CONFORM_STRICT)
1830
0
      {
1831
0
        pg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1832
0
        goto error;
1833
0
      }
1834
1835
15.8k
      if (constraint->choice1[0] == '*')
1836
9.25k
      {
1837
9.25k
        if (pg->ppd_conform == PPD_CONFORM_STRICT &&
1838
0
            constraint->option2[0] == '*')
1839
0
        {
1840
0
    pg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1841
0
    goto error;
1842
0
        }
1843
1844
9.25k
        _cups_strcpy(constraint->choice2, constraint->option2);
1845
9.25k
        _cups_strcpy(constraint->option2, constraint->choice1 + 1);
1846
9.25k
              constraint->choice1[0] = '\0';
1847
9.25k
      }
1848
6.54k
      else
1849
6.54k
      {
1850
6.54k
        if (constraint->option2[0] == '*')
1851
315
            _cups_strcpy(constraint->option2, constraint->option2 + 1);
1852
6.23k
        else if (pg->ppd_conform == PPD_CONFORM_STRICT)
1853
0
        {
1854
0
    pg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1855
0
    goto error;
1856
0
        }
1857
1858
6.54k
              constraint->choice2[0] = '\0';
1859
6.54k
      }
1860
15.8k
      break;
1861
1862
15.8k
  case 4 : /* Two options, two choices... */
1863
     /*
1864
      * Check for broken constraints like "* Option"...
1865
      */
1866
1867
7.54k
      if (pg->ppd_conform == PPD_CONFORM_STRICT &&
1868
0
          (!strcmp(constraint->option1, "*") ||
1869
0
           !strcmp(constraint->choice1, "*") ||
1870
0
           !strcmp(constraint->option2, "*") ||
1871
0
           !strcmp(constraint->choice2, "*")))
1872
0
      {
1873
0
        pg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1874
0
        goto error;
1875
0
      }
1876
1877
7.54k
      if (constraint->option1[0] == '*')
1878
1.56k
        _cups_strcpy(constraint->option1, constraint->option1 + 1);
1879
5.97k
      else if (pg->ppd_conform == PPD_CONFORM_STRICT)
1880
0
      {
1881
0
        pg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1882
0
        goto error;
1883
0
      }
1884
1885
7.54k
            if (pg->ppd_conform == PPD_CONFORM_STRICT &&
1886
0
          constraint->choice1[0] == '*')
1887
0
      {
1888
0
        pg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1889
0
        goto error;
1890
0
      }
1891
1892
7.54k
      if (constraint->option2[0] == '*')
1893
1.19k
          _cups_strcpy(constraint->option2, constraint->option2 + 1);
1894
6.35k
      else if (pg->ppd_conform == PPD_CONFORM_STRICT)
1895
0
      {
1896
0
        pg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1897
0
        goto error;
1898
0
      }
1899
1900
7.54k
            if (pg->ppd_conform == PPD_CONFORM_STRICT &&
1901
0
          constraint->choice2[0] == '*')
1902
0
      {
1903
0
        pg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1904
0
        goto error;
1905
0
      }
1906
7.54k
      break;
1907
27.8k
      }
1908
1909
     /*
1910
      * Don't add this one as an attribute...
1911
      */
1912
1913
27.8k
      free(string);
1914
27.8k
      string = NULL;
1915
27.8k
    }
1916
393k
    else if (!strcmp(keyword, "PaperDimension"))
1917
1.26k
    {
1918
1.26k
      if (!_cups_strcasecmp(name, "custom") || !_cups_strncasecmp(name, "custom.", 7))
1919
327
      {
1920
327
        char cname[PPD_MAX_NAME]; /* Rewrite with a leading underscore */
1921
327
        snprintf(cname, sizeof(cname), "_%s", name);
1922
327
        cupsCopyString(name, cname, sizeof(name));
1923
327
      }
1924
1925
1.26k
      if ((size = ppdPageSize(ppd, name)) == NULL)
1926
265
  size = ppd_add_size(ppd, name);
1927
1928
1.26k
      if (size == NULL)
1929
0
      {
1930
       /*
1931
        * Unable to add or find size!
1932
  */
1933
1934
0
        pg->ppd_status = PPD_ALLOC_ERROR;
1935
1936
0
  goto error;
1937
0
      }
1938
1939
1.26k
      size->width  = (float)_cupsStrScand(string, &sptr, loc);
1940
1.26k
      size->length = (float)_cupsStrScand(sptr, NULL, loc);
1941
1942
1.26k
      free(string);
1943
1.26k
      string = NULL;
1944
1.26k
    }
1945
392k
    else if (!strcmp(keyword, "ImageableArea"))
1946
4.50k
    {
1947
4.50k
      if (!_cups_strcasecmp(name, "custom") || !_cups_strncasecmp(name, "custom.", 7))
1948
669
      {
1949
669
        char cname[PPD_MAX_NAME]; /* Rewrite with a leading underscore */
1950
669
        snprintf(cname, sizeof(cname), "_%s", name);
1951
669
        cupsCopyString(name, cname, sizeof(name));
1952
669
      }
1953
1954
4.50k
      if ((size = ppdPageSize(ppd, name)) == NULL)
1955
200
  size = ppd_add_size(ppd, name);
1956
1957
4.50k
      if (size == NULL)
1958
0
      {
1959
       /*
1960
        * Unable to add or find size!
1961
  */
1962
1963
0
        pg->ppd_status = PPD_ALLOC_ERROR;
1964
1965
0
  goto error;
1966
0
      }
1967
1968
4.50k
      size->left   = (float)_cupsStrScand(string, &sptr, loc);
1969
4.50k
      size->bottom = (float)_cupsStrScand(sptr, &sptr, loc);
1970
4.50k
      size->right  = (float)_cupsStrScand(sptr, &sptr, loc);
1971
4.50k
      size->top    = (float)_cupsStrScand(sptr, NULL, loc);
1972
1973
4.50k
      free(string);
1974
4.50k
      string = NULL;
1975
4.50k
    }
1976
387k
    else if (option != NULL &&
1977
103k
             (mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) ==
1978
103k
           (PPD_KEYWORD | PPD_OPTION | PPD_STRING) &&
1979
65.1k
       !strcmp(keyword, option->keyword))
1980
53.3k
    {
1981
53.3k
      DEBUG_printf("2_ppdOpen: group=%p, subgroup=%p", (void *)group, (void *)subgroup);
1982
1983
53.3k
      if (!_cups_strcasecmp(name, "custom") || !_cups_strncasecmp(name, "custom.", 7))
1984
8.02k
      {
1985
8.02k
        char cname[PPD_MAX_NAME]; /* Rewrite with a leading underscore */
1986
8.02k
        snprintf(cname, sizeof(cname), "_%s", name);
1987
8.02k
        cupsCopyString(name, cname, sizeof(name));
1988
8.02k
      }
1989
1990
53.3k
      if (!strcmp(keyword, "PageSize"))
1991
52.9k
      {
1992
       /*
1993
        * Add a page size...
1994
  */
1995
1996
52.9k
        if (ppdPageSize(ppd, name) == NULL)
1997
2.26k
    ppd_add_size(ppd, name);
1998
52.9k
      }
1999
2000
     /*
2001
      * Add the option choice...
2002
      */
2003
2004
53.3k
      if ((choice = ppd_add_choice(option, name)) == NULL)
2005
0
      {
2006
0
        pg->ppd_status = PPD_ALLOC_ERROR;
2007
2008
0
  goto error;
2009
0
      }
2010
2011
53.3k
      if (text[0])
2012
3.75k
        cupsCharsetToUTF8((cups_utf8_t *)choice->text, text,
2013
3.75k
                     sizeof(choice->text), encoding);
2014
49.5k
      else if (!strcmp(name, "True"))
2015
713
        cupsCopyString(choice->text, _("Yes"), sizeof(choice->text));
2016
48.8k
      else if (!strcmp(name, "False"))
2017
292
        cupsCopyString(choice->text, _("No"), sizeof(choice->text));
2018
48.5k
      else
2019
48.5k
        cupsCopyString(choice->text, name, sizeof(choice->text));
2020
2021
53.3k
      if (option->section == PPD_ORDER_JCL)
2022
651
        ppd_decode(string);   /* Decode quoted string */
2023
2024
53.3k
      choice->code = string;
2025
53.3k
      string       = NULL;   /* Don't add as an attribute below */
2026
53.3k
    }
2027
2028
   /*
2029
    * Add remaining lines with keywords and string values as attributes...
2030
    */
2031
2032
615k
    if (string &&
2033
457k
        (mask & (PPD_KEYWORD | PPD_STRING)) == (PPD_KEYWORD | PPD_STRING))
2034
457k
      ppd_add_attr(ppd, keyword, name, text, string);
2035
157k
    else
2036
157k
      free(string);
2037
615k
  }
2038
2039
 /*
2040
  * Check for a missing CloseUI/JCLCloseUI...
2041
  */
2042
2043
6.07k
  if (option && pg->ppd_conform == PPD_CONFORM_STRICT)
2044
0
  {
2045
0
    pg->ppd_status = PPD_MISSING_CLOSE_UI;
2046
0
    goto error;
2047
0
  }
2048
2049
 /*
2050
  * Check for a missing CloseGroup...
2051
  */
2052
2053
6.07k
  if (group && pg->ppd_conform == PPD_CONFORM_STRICT)
2054
0
  {
2055
0
    pg->ppd_status = PPD_MISSING_CLOSE_GROUP;
2056
0
    goto error;
2057
0
  }
2058
2059
6.07k
  free(line.buffer);
2060
2061
 /*
2062
  * Reset language preferences...
2063
  */
2064
2065
#ifdef DEBUG
2066
  if (!cupsFileEOF(fp))
2067
    DEBUG_printf("1_ppdOpen: Premature EOF at %lu...\n", (unsigned long)cupsFileTell(fp));
2068
#endif /* DEBUG */
2069
2070
6.07k
  if (pg->ppd_status != PPD_OK)
2071
2.94k
  {
2072
   /*
2073
    * Had an error reading the PPD file, cannot continue!
2074
    */
2075
2076
2.94k
    ppdClose(ppd);
2077
2078
2.94k
    return (NULL);
2079
2.94k
  }
2080
2081
 /*
2082
  * Update the filters array as needed...
2083
  */
2084
2085
3.13k
  if (!ppd_update_filters(ppd, pg))
2086
13
  {
2087
13
    ppdClose(ppd);
2088
2089
13
    return (NULL);
2090
13
  }
2091
2092
 /*
2093
  * Create the sorted options array and set the option back-pointer for
2094
  * each choice and custom option...
2095
  */
2096
2097
3.11k
  ppd->options = cupsArrayNew2((cups_array_func_t)ppd_compare_options, NULL,
2098
3.11k
                               (cups_ahash_func_t)ppd_hash_option,
2099
3.11k
             PPD_HASHSIZE);
2100
2101
3.11k
  for (i = ppd->num_groups, group = ppd->groups;
2102
6.38k
       i > 0;
2103
3.26k
       i --, group ++)
2104
3.26k
  {
2105
3.26k
    for (j = group->num_options, option = group->options;
2106
6.72k
         j > 0;
2107
3.45k
   j --, option ++)
2108
3.45k
    {
2109
3.45k
      ppd_coption_t *coption; /* Custom option */
2110
2111
2112
3.45k
      cupsArrayAdd(ppd->options, option);
2113
2114
25.6k
      for (k = 0; k < option->num_choices; k ++)
2115
22.1k
        option->choices[k].option = option;
2116
2117
3.45k
      if ((coption = ppdFindCustomOption(ppd, option->keyword)) != NULL)
2118
517
        coption->option = option;
2119
3.45k
    }
2120
3.26k
  }
2121
2122
 /*
2123
  * Create an array to track the marked choices...
2124
  */
2125
2126
3.11k
  ppd->marked = cupsArrayNew((cups_array_func_t)ppd_compare_choices, NULL);
2127
2128
 /*
2129
  * Return the PPD file structure...
2130
  */
2131
2132
3.11k
  return (ppd);
2133
2134
 /*
2135
  * Common exit point for errors to save code size...
2136
  */
2137
2138
424
  error:
2139
2140
424
  free(string);
2141
424
  free(line.buffer);
2142
2143
424
  ppdClose(ppd);
2144
2145
424
  return (NULL);
2146
3.13k
}
2147
2148
2149
/*
2150
 * 'ppdOpen()' - Read a PPD file into memory.
2151
 */
2152
2153
ppd_file_t *        /* O - PPD file record */
2154
ppdOpen(FILE *fp)     /* I - File to read from */
2155
0
{
2156
0
  ppd_file_t  *ppd;     /* PPD file record */
2157
0
  cups_file_t *cf;      /* CUPS file */
2158
2159
2160
 /*
2161
  * Reopen the stdio file as a CUPS file...
2162
  */
2163
2164
0
  if ((cf = cupsFileOpenFd(fileno(fp), "r")) == NULL)
2165
0
    return (NULL);
2166
2167
 /*
2168
  * Load the PPD file using the newer API...
2169
  */
2170
2171
0
  ppd = _ppdOpen(cf, _PPD_LOCALIZATION_DEFAULT);
2172
2173
 /*
2174
  * Close the CUPS file and return the PPD...
2175
  */
2176
2177
0
  cupsFileClose(cf);
2178
2179
0
  return (ppd);
2180
0
}
2181
2182
2183
/*
2184
 * 'ppdOpen2()' - Read a PPD file into memory.
2185
 *
2186
 * @since CUPS 1.2@
2187
 */
2188
2189
ppd_file_t *        /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
2190
ppdOpen2(cups_file_t *fp)   /* I - File to read from */
2191
0
{
2192
0
  return _ppdOpen(fp, _PPD_LOCALIZATION_DEFAULT);
2193
0
}
2194
2195
2196
/*
2197
 * 'ppdOpenFd()' - Read a PPD file into memory.
2198
 */
2199
2200
ppd_file_t *        /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
2201
ppdOpenFd(int fd)     /* I - File to read from */
2202
0
{
2203
0
  cups_file_t   *fp;    /* CUPS file pointer */
2204
0
  ppd_file_t    *ppd;   /* PPD file record */
2205
0
  _ppd_globals_t  *pg = _ppdGlobals();
2206
          /* Global data */
2207
2208
2209
 /*
2210
  * Set the line number to 0...
2211
  */
2212
2213
0
  pg->ppd_line = 0;
2214
2215
 /*
2216
  * Range check input...
2217
  */
2218
2219
0
  if (fd < 0)
2220
0
  {
2221
0
    pg->ppd_status = PPD_NULL_FILE;
2222
2223
0
    return (NULL);
2224
0
  }
2225
2226
 /*
2227
  * Try to open the file and parse it...
2228
  */
2229
2230
0
  if ((fp = cupsFileOpenFd(fd, "r")) != NULL)
2231
0
  {
2232
0
    ppd = ppdOpen2(fp);
2233
2234
0
    cupsFileClose(fp);
2235
0
  }
2236
0
  else
2237
0
  {
2238
0
    pg->ppd_status = PPD_FILE_OPEN_ERROR;
2239
0
    ppd            = NULL;
2240
0
  }
2241
2242
0
  return (ppd);
2243
0
}
2244
2245
2246
/*
2247
 * '_ppdOpenFile()' - Read a PPD file into memory.
2248
 */
2249
2250
ppd_file_t *        /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
2251
_ppdOpenFile(const char     *filename,  /* I - File to read from */
2252
       _ppd_localization_t  localization) /* I - Localization to load */
2253
7.60k
{
2254
7.60k
  cups_file_t   *fp;    /* File pointer */
2255
7.60k
  ppd_file_t    *ppd;   /* PPD file record */
2256
7.60k
  _ppd_globals_t  *pg = _ppdGlobals();
2257
          /* Global data */
2258
2259
2260
 /*
2261
  * Set the line number to 0...
2262
  */
2263
2264
7.60k
  pg->ppd_line = 0;
2265
2266
 /*
2267
  * Range check input...
2268
  */
2269
2270
7.60k
  if (filename == NULL)
2271
0
  {
2272
0
    pg->ppd_status = PPD_NULL_FILE;
2273
2274
0
    return (NULL);
2275
0
  }
2276
2277
 /*
2278
  * Try to open the file and parse it...
2279
  */
2280
2281
7.60k
  if ((fp = cupsFileOpen(filename, "r")) != NULL)
2282
7.60k
  {
2283
7.60k
    ppd = _ppdOpen(fp, localization);
2284
2285
7.60k
    cupsFileClose(fp);
2286
7.60k
  }
2287
0
  else
2288
0
  {
2289
0
    pg->ppd_status = PPD_FILE_OPEN_ERROR;
2290
0
    ppd            = NULL;
2291
0
  }
2292
2293
7.60k
  return (ppd);
2294
7.60k
}
2295
2296
2297
/*
2298
 * 'ppdOpenFile()' - Read a PPD file into memory.
2299
 */
2300
2301
ppd_file_t *        /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
2302
ppdOpenFile(const char *filename) /* I - File to read from */
2303
7.60k
{
2304
7.60k
  return _ppdOpenFile(filename, _PPD_LOCALIZATION_DEFAULT);
2305
7.60k
}
2306
2307
2308
/*
2309
 * 'ppdSetConformance()' - Set the conformance level for PPD files.
2310
 *
2311
 * @since CUPS 1.1.20@
2312
 */
2313
2314
void
2315
ppdSetConformance(ppd_conform_t c)  /* I - Conformance level */
2316
0
{
2317
0
  _ppd_globals_t  *pg = _ppdGlobals();
2318
          /* Global data */
2319
2320
2321
0
  pg->ppd_conform = c;
2322
0
}
2323
2324
2325
/*
2326
 * 'ppd_add_attr()' - Add an attribute to the PPD data.
2327
 */
2328
2329
static ppd_attr_t *     /* O - New attribute */
2330
ppd_add_attr(ppd_file_t *ppd,   /* I - PPD file data */
2331
             const char *name,    /* I - Attribute name */
2332
             const char *spec,    /* I - Specifier string, if any */
2333
       const char *text,    /* I - Text string, if any */
2334
       const char *value)   /* I - Value of attribute */
2335
457k
{
2336
457k
  ppd_attr_t  **ptr,      /* New array */
2337
457k
    *temp;      /* New attribute */
2338
2339
2340
 /*
2341
  * Range check input...
2342
  */
2343
2344
457k
  if (ppd == NULL || name == NULL || spec == NULL)
2345
0
    return (NULL);
2346
2347
 /*
2348
  * Create the array as needed...
2349
  */
2350
2351
457k
  if (!ppd->sorted_attrs)
2352
5.60k
    ppd->sorted_attrs = cupsArrayNew((cups_array_func_t)ppd_compare_attrs,
2353
5.60k
                                     NULL);
2354
2355
 /*
2356
  * Allocate memory for the new attribute...
2357
  */
2358
2359
457k
  if (ppd->num_attrs == 0)
2360
5.60k
    ptr = malloc(sizeof(ppd_attr_t *));
2361
451k
  else
2362
451k
    ptr = realloc(ppd->attrs, (size_t)(ppd->num_attrs + 1) * sizeof(ppd_attr_t *));
2363
2364
457k
  if (ptr == NULL)
2365
0
    return (NULL);
2366
2367
457k
  ppd->attrs = ptr;
2368
457k
  ptr += ppd->num_attrs;
2369
2370
457k
  if ((temp = calloc(1, sizeof(ppd_attr_t))) == NULL)
2371
0
    return (NULL);
2372
2373
457k
  *ptr = temp;
2374
2375
457k
  ppd->num_attrs ++;
2376
2377
 /*
2378
  * Copy data over...
2379
  */
2380
2381
457k
  if (!_cups_strcasecmp(spec, "custom") || !_cups_strncasecmp(spec, "custom.", 7))
2382
2.27k
  {
2383
2.27k
    temp->spec[0] = '_';
2384
2.27k
    cupsCopyString(temp->spec + 1, spec, sizeof(temp->spec) - 1);
2385
2.27k
  }
2386
455k
  else {
2387
455k
      cupsCopyString(temp->spec, spec, sizeof(temp->spec));
2388
455k
  }
2389
2390
457k
  cupsCopyString(temp->name, name, sizeof(temp->name));
2391
457k
  cupsCopyString(temp->text, text, sizeof(temp->text));
2392
457k
  temp->value = (char *)value;
2393
2394
 /*
2395
  * Add the attribute to the sorted array...
2396
  */
2397
2398
457k
  cupsArrayAdd(ppd->sorted_attrs, temp);
2399
2400
 /*
2401
  * Return the attribute...
2402
  */
2403
2404
457k
  return (temp);
2405
457k
}
2406
2407
2408
/*
2409
 * 'ppd_add_choice()' - Add a choice to an option.
2410
 */
2411
2412
static ppd_choice_t *     /* O - Named choice */
2413
ppd_add_choice(ppd_option_t *option,  /* I - Option */
2414
               const char   *name)  /* I - Name of choice */
2415
56.5k
{
2416
56.5k
  ppd_choice_t  *choice;    /* Choice */
2417
2418
2419
56.5k
  if (option->num_choices == 0)
2420
2.59k
    choice = malloc(sizeof(ppd_choice_t));
2421
53.9k
  else
2422
53.9k
    choice = realloc(option->choices, sizeof(ppd_choice_t) * (size_t)(option->num_choices + 1));
2423
2424
56.5k
  if (choice == NULL)
2425
0
    return (NULL);
2426
2427
56.5k
  option->choices = choice;
2428
56.5k
  choice += option->num_choices;
2429
56.5k
  option->num_choices ++;
2430
2431
56.5k
  memset(choice, 0, sizeof(ppd_choice_t));
2432
56.5k
  cupsCopyString(choice->choice, name, sizeof(choice->choice));
2433
2434
56.5k
  return (choice);
2435
56.5k
}
2436
2437
2438
/*
2439
 * 'ppd_add_size()' - Add a page size.
2440
 */
2441
2442
static ppd_size_t *     /* O - Named size */
2443
ppd_add_size(ppd_file_t *ppd,   /* I - PPD file */
2444
             const char *name)    /* I - Name of size */
2445
9.01k
{
2446
9.01k
  ppd_size_t  *size;      /* Size */
2447
2448
2449
9.01k
  if (ppd->num_sizes == 0)
2450
1.71k
    size = malloc(sizeof(ppd_size_t));
2451
7.30k
  else
2452
7.30k
    size = realloc(ppd->sizes, sizeof(ppd_size_t) * (size_t)(ppd->num_sizes + 1));
2453
2454
9.01k
  if (size == NULL)
2455
0
    return (NULL);
2456
2457
9.01k
  ppd->sizes = size;
2458
9.01k
  size += ppd->num_sizes;
2459
9.01k
  ppd->num_sizes ++;
2460
2461
9.01k
  memset(size, 0, sizeof(ppd_size_t));
2462
9.01k
  cupsCopyString(size->name, name, sizeof(size->name));
2463
2464
9.01k
  return (size);
2465
9.01k
}
2466
2467
2468
/*
2469
 * 'ppd_compare_attrs()' - Compare two attributes.
2470
 */
2471
2472
static int                       /* O - Result of comparison */
2473
ppd_compare_attrs(ppd_attr_t *a, /* I - First attribute */
2474
                  ppd_attr_t *b, /* I - Second attribute */
2475
                  void *data)    /* Unused */
2476
44.0M
{
2477
44.0M
  (void)data;
2478
44.0M
  return (_cups_strcasecmp(a->name, b->name));
2479
44.0M
}
2480
2481
2482
/*
2483
 * 'ppd_compare_choices()' - Compare two choices...
2484
 */
2485
2486
static int                           /* O - Result of comparison */
2487
ppd_compare_choices(ppd_choice_t *a, /* I - First choice */
2488
                    ppd_choice_t *b, /* I - Second choice */
2489
                    void *data)      /* Unused */
2490
0
{
2491
0
  (void)data;
2492
0
  return (strcmp(a->option->keyword, b->option->keyword));
2493
0
}
2494
2495
2496
/*
2497
 * 'ppd_compare_coptions()' - Compare two custom options.
2498
 */
2499
2500
static int                             /* O - Result of comparison */
2501
ppd_compare_coptions(ppd_coption_t *a, /* I - First option */
2502
                     ppd_coption_t *b, /* I - Second option */
2503
                     void *data)       /* Unused */
2504
11.1k
{
2505
11.1k
  (void)data;
2506
11.1k
  return (_cups_strcasecmp(a->keyword, b->keyword));
2507
11.1k
}
2508
2509
2510
/*
2511
 * 'ppd_compare_options()' - Compare two options.
2512
 */
2513
2514
static int                           /* O - Result of comparison */
2515
ppd_compare_options(ppd_option_t *a, /* I - First option */
2516
                    ppd_option_t *b, /* I - Second option */
2517
                    void *data)      /* Unused */
2518
78.6k
{
2519
78.6k
  (void)data;
2520
78.6k
  return (_cups_strcasecmp(a->keyword, b->keyword));
2521
78.6k
}
2522
2523
2524
/*
2525
 * 'ppd_decode()' - Decode a string value...
2526
 */
2527
2528
static int        /* O - Length of decoded string */
2529
ppd_decode(char *string)    /* I - String to decode */
2530
71.2k
{
2531
71.2k
  char  *inptr,       /* Input pointer */
2532
71.2k
  *outptr;      /* Output pointer */
2533
2534
2535
71.2k
  inptr  = string;
2536
71.2k
  outptr = string;
2537
2538
1.34M
  while (*inptr != '\0')
2539
1.27M
    if (*inptr == '<' && isxdigit(inptr[1] & 255))
2540
1.33k
    {
2541
     /*
2542
      * Convert hex to 8-bit values...
2543
      */
2544
2545
1.33k
      inptr ++;
2546
1.33k
      while (isxdigit(*inptr & 255))
2547
3.46k
      {
2548
3.46k
  if (_cups_isalpha(*inptr))
2549
1.64k
    *outptr = (char)((tolower(*inptr) - 'a' + 10) << 4);
2550
1.82k
  else
2551
1.82k
    *outptr = (char)((*inptr - '0') << 4);
2552
2553
3.46k
  inptr ++;
2554
2555
3.46k
        if (!isxdigit(*inptr & 255))
2556
569
    break;
2557
2558
2.89k
  if (_cups_isalpha(*inptr))
2559
1.60k
    *outptr |= (char)(tolower(*inptr) - 'a' + 10);
2560
1.28k
  else
2561
1.28k
    *outptr |= (char)(*inptr - '0');
2562
2563
2.89k
  inptr ++;
2564
2.89k
  outptr ++;
2565
2.89k
      }
2566
2567
8.07k
      while (*inptr != '>' && *inptr != '\0')
2568
6.74k
  inptr ++;
2569
2.41k
      while (*inptr == '>')
2570
1.08k
  inptr ++;
2571
1.33k
    }
2572
1.27M
    else
2573
1.27M
      *outptr++ = *inptr++;
2574
2575
71.2k
  *outptr = '\0';
2576
2577
71.2k
  return ((int)(outptr - string));
2578
71.2k
}
2579
2580
2581
/*
2582
 * 'ppd_free_filters()' - Free the filters array.
2583
 */
2584
2585
static void
2586
ppd_free_filters(ppd_file_t *ppd) /* I - PPD file */
2587
6.51k
{
2588
6.51k
  int i;        /* Looping var */
2589
6.51k
  char  **filter;     /* Current filter */
2590
2591
2592
6.51k
  if (ppd->num_filters > 0)
2593
105
  {
2594
80.9k
    for (i = ppd->num_filters, filter = ppd->filters; i > 0; i --, filter ++)
2595
80.8k
      free(*filter);
2596
2597
105
    free(ppd->filters);
2598
2599
105
    ppd->num_filters = 0;
2600
105
    ppd->filters     = NULL;
2601
105
  }
2602
6.51k
}
2603
2604
2605
/*
2606
 * 'ppd_free_group()' - Free a single UI group.
2607
 */
2608
2609
static void
2610
ppd_free_group(ppd_group_t *group)  /* I - Group to free */
2611
5.88k
{
2612
5.88k
  int   i;      /* Looping var */
2613
5.88k
  ppd_option_t  *option;    /* Current option */
2614
5.88k
  ppd_group_t *subgroup;    /* Current sub-group */
2615
2616
2617
5.88k
  if (group->num_options > 0)
2618
4.31k
  {
2619
4.31k
    for (i = group->num_options, option = group->options;
2620
10.8k
         i > 0;
2621
6.53k
   i --, option ++)
2622
6.53k
      ppd_free_option(option);
2623
2624
4.31k
    free(group->options);
2625
4.31k
  }
2626
2627
5.88k
  if (group->num_subgroups > 0)
2628
0
  {
2629
0
    for (i = group->num_subgroups, subgroup = group->subgroups;
2630
0
         i > 0;
2631
0
   i --, subgroup ++)
2632
0
      ppd_free_group(subgroup);
2633
2634
0
    free(group->subgroups);
2635
0
  }
2636
5.88k
}
2637
2638
2639
/*
2640
 * 'ppd_free_option()' - Free a single option.
2641
 */
2642
2643
static void
2644
ppd_free_option(ppd_option_t *option) /* I - Option to free */
2645
6.53k
{
2646
6.53k
  int   i;      /* Looping var */
2647
6.53k
  ppd_choice_t  *choice;    /* Current choice */
2648
2649
2650
6.53k
  if (option->num_choices > 0)
2651
2.59k
  {
2652
2.59k
    for (i = option->num_choices, choice = option->choices;
2653
59.1k
         i > 0;
2654
56.5k
         i --, choice ++)
2655
56.5k
    {
2656
56.5k
      free(choice->code);
2657
56.5k
    }
2658
2659
2.59k
    free(option->choices);
2660
2.59k
  }
2661
6.53k
}
2662
2663
2664
/*
2665
 * 'ppd_get_coption()' - Get a custom option record.
2666
 */
2667
2668
static ppd_coption_t  *   /* O - Custom option... */
2669
ppd_get_coption(ppd_file_t *ppd,  /* I - PPD file */
2670
                const char *name) /* I - Name of option */
2671
7.29k
{
2672
7.29k
  ppd_coption_t *copt;      /* New custom option */
2673
2674
2675
 /*
2676
  * See if the option already exists...
2677
  */
2678
2679
7.29k
  if ((copt = ppdFindCustomOption(ppd, name)) != NULL)
2680
6.28k
    return (copt);
2681
2682
 /*
2683
  * Not found, so create the custom option record...
2684
  */
2685
2686
1.00k
  if ((copt = calloc(1, sizeof(ppd_coption_t))) == NULL)
2687
0
    return (NULL);
2688
2689
1.00k
  cupsCopyString(copt->keyword, name, sizeof(copt->keyword));
2690
2691
1.00k
  copt->params = cupsArrayNew((cups_array_func_t)NULL, NULL);
2692
2693
1.00k
  cupsArrayAdd(ppd->coptions, copt);
2694
2695
 /*
2696
  * Return the new record...
2697
  */
2698
2699
1.00k
  return (copt);
2700
1.00k
}
2701
2702
2703
/*
2704
 * 'ppd_get_cparam()' - Get a custom parameter record.
2705
 */
2706
2707
static ppd_cparam_t *     /* O - Extended option... */
2708
ppd_get_cparam(ppd_coption_t *opt,  /* I - PPD file */
2709
               const char    *param,  /* I - Name of parameter */
2710
         const char    *text) /* I - Human-readable text */
2711
270
{
2712
270
  ppd_cparam_t  *cparam;    /* New custom parameter */
2713
2714
2715
 /*
2716
  * See if the parameter already exists...
2717
  */
2718
2719
270
  if ((cparam = ppdFindCustomParam(opt, param)) != NULL)
2720
12
    return (cparam);
2721
2722
 /*
2723
  * Not found, so create the custom parameter record...
2724
  */
2725
2726
258
  if ((cparam = calloc(1, sizeof(ppd_cparam_t))) == NULL)
2727
0
    return (NULL);
2728
2729
258
  cparam->type = PPD_CUSTOM_UNKNOWN;
2730
258
  cupsCopyString(cparam->name, param, sizeof(cparam->name));
2731
258
  cupsCopyString(cparam->text, text[0] ? text : param, sizeof(cparam->text));
2732
2733
 /*
2734
  * Add this record to the array...
2735
  */
2736
2737
258
  cupsArrayAdd(opt->params, cparam);
2738
2739
 /*
2740
  * Return the new record...
2741
  */
2742
2743
258
  return (cparam);
2744
258
}
2745
2746
2747
/*
2748
 * 'ppd_get_group()' - Find or create the named group as needed.
2749
 */
2750
2751
static ppd_group_t *      /* O - Named group */
2752
ppd_get_group(ppd_file_t      *ppd, /* I - PPD file */
2753
              const char      *name,  /* I - Name of group */
2754
        const char      *text,  /* I - Text for group */
2755
              _ppd_globals_t  *pg,  /* I - Global data */
2756
        cups_encoding_t encoding) /* I - Encoding of text */
2757
85.8k
{
2758
85.8k
  int   i;      /* Looping var */
2759
85.8k
  ppd_group_t *group;     /* Group */
2760
2761
2762
85.8k
  DEBUG_printf("7ppd_get_group(ppd=%p, name=\"%s\", text=\"%s\", cg=%p)", (void *)ppd, name, text, (void *)pg);
2763
2764
223k
  for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
2765
217k
    if (!strcmp(group->name, name))
2766
79.9k
      break;
2767
2768
85.8k
  if (i == 0)
2769
5.88k
  {
2770
5.88k
    DEBUG_printf("8ppd_get_group: Adding group %s...", name);
2771
2772
5.88k
    if (pg->ppd_conform == PPD_CONFORM_STRICT && strlen(text) >= sizeof(group->text))
2773
0
    {
2774
0
      pg->ppd_status = PPD_ILLEGAL_TRANSLATION;
2775
2776
0
      return (NULL);
2777
0
    }
2778
2779
5.88k
    if (ppd->num_groups == 0)
2780
2.98k
      group = malloc(sizeof(ppd_group_t));
2781
2.90k
    else
2782
2.90k
      group = realloc(ppd->groups, (size_t)(ppd->num_groups + 1) * sizeof(ppd_group_t));
2783
2784
5.88k
    if (group == NULL)
2785
0
    {
2786
0
      pg->ppd_status = PPD_ALLOC_ERROR;
2787
2788
0
      return (NULL);
2789
0
    }
2790
2791
5.88k
    ppd->groups = group;
2792
5.88k
    group += ppd->num_groups;
2793
5.88k
    ppd->num_groups ++;
2794
2795
5.88k
    memset(group, 0, sizeof(ppd_group_t));
2796
5.88k
    cupsCopyString(group->name, name, sizeof(group->name));
2797
2798
5.88k
    cupsCharsetToUTF8((cups_utf8_t *)group->text, text,
2799
5.88k
                 sizeof(group->text), encoding);
2800
5.88k
  }
2801
2802
85.8k
  return (group);
2803
85.8k
}
2804
2805
2806
/*
2807
 * 'ppd_get_option()' - Find or create the named option as needed.
2808
 */
2809
2810
static ppd_option_t *     /* O - Named option */
2811
ppd_get_option(ppd_group_t *group,  /* I - Group */
2812
               const char  *name) /* I - Name of option */
2813
89.4k
{
2814
89.4k
  int   i;      /* Looping var */
2815
89.4k
  ppd_option_t  *option;    /* Option */
2816
2817
2818
89.4k
  DEBUG_printf("7ppd_get_option(group=%p(\"%s\"), name=\"%s\")", (void *)group, group->name, name);
2819
2820
105k
  for (i = group->num_options, option = group->options; i > 0; i --, option ++)
2821
99.2k
    if (!strcmp(option->keyword, name))
2822
82.9k
      break;
2823
2824
89.4k
  if (i == 0)
2825
6.53k
  {
2826
6.53k
    if (group->num_options == 0)
2827
4.31k
      option = malloc(sizeof(ppd_option_t));
2828
2.21k
    else
2829
2.21k
      option = realloc(group->options, (size_t)(group->num_options + 1) * sizeof(ppd_option_t));
2830
2831
6.53k
    if (option == NULL)
2832
0
      return (NULL);
2833
2834
6.53k
    group->options = option;
2835
6.53k
    option += group->num_options;
2836
6.53k
    group->num_options ++;
2837
2838
6.53k
    memset(option, 0, sizeof(ppd_option_t));
2839
6.53k
    cupsCopyString(option->keyword, name, sizeof(option->keyword));
2840
6.53k
  }
2841
2842
89.4k
  return (option);
2843
89.4k
}
2844
2845
2846
/*
2847
 * 'ppd_globals_alloc()' - Allocate and initialize global data.
2848
 */
2849
2850
static _ppd_globals_t *   /* O - Pointer to global data */
2851
ppd_globals_alloc(void)
2852
1
{
2853
1
  return ((_ppd_globals_t *)calloc(1, sizeof(_ppd_globals_t)));
2854
1
}
2855
2856
2857
/*
2858
 * 'ppd_globals_free()' - Free global data.
2859
 */
2860
2861
#if defined(HAVE_PTHREAD_H) || defined(_WIN32)
2862
static void
2863
ppd_globals_free(_ppd_globals_t *pg)  /* I - Pointer to global data */
2864
0
{
2865
0
  free(pg);
2866
0
}
2867
#endif /* HAVE_PTHREAD_H || _WIN32 */
2868
2869
2870
#ifdef HAVE_PTHREAD_H
2871
/*
2872
 * 'ppd_globals_init()' - Initialize per-thread globals...
2873
 */
2874
2875
static void
2876
ppd_globals_init(void)
2877
1
{
2878
 /*
2879
  * Register the global data for this thread...
2880
  */
2881
2882
1
  pthread_key_create(&ppd_globals_key, (void (*)(void *))ppd_globals_free);
2883
1
}
2884
#endif /* HAVE_PTHREAD_H */
2885
2886
2887
/*
2888
 * 'ppd_hash_option()' - Generate a hash of the option name...
2889
 */
2890
2891
static int                            /* O - Hash index */
2892
ppd_hash_option(ppd_option_t *option, /* I - Option */
2893
25.7k
                void *data) {
2894
25.7k
  int   hash = 0;   /* Hash index */
2895
25.7k
  const char  *k;     /* Pointer into keyword */
2896
2897
25.7k
  (void)data;
2898
2899
199k
  for (hash = option->keyword[0], k = option->keyword + 1; *k;)
2900
173k
    hash = (int)(33U * (unsigned)hash) + *k++;
2901
2902
25.7k
  return (hash & 511);
2903
25.7k
}
2904
2905
2906
/*
2907
 * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
2908
 *                necessary.
2909
 */
2910
2911
static int        /* O - Bitmask of fields read */
2912
ppd_read(cups_file_t    *fp,    /* I - File to read from */
2913
         _ppd_line_t    *line,    /* I - Line buffer */
2914
         char           *keyword, /* O - Keyword from line */
2915
   char           *option,  /* O - Option from line */
2916
         char           *text,    /* O - Human-readable text from line */
2917
   char           **string, /* O - Code/string data */
2918
         int            ignoreblank,  /* I - Ignore blank lines? */
2919
   _ppd_globals_t *pg)    /* I - Global data */
2920
714k
{
2921
714k
  int   ch,     /* Character from file */
2922
714k
    col,      /* Column in line */
2923
714k
    colon,      /* Colon seen? */
2924
714k
    endquote,   /* Waiting for an end quote */
2925
714k
    mask,     /* Mask to be returned */
2926
714k
    startline,    /* Start line */
2927
714k
    textlen;    /* Length of text */
2928
714k
  char    *keyptr,    /* Keyword pointer */
2929
714k
    *optptr,    /* Option pointer */
2930
714k
    *textptr,   /* Text pointer */
2931
714k
    *strptr,    /* Pointer into string */
2932
714k
    *lineptr;   /* Current position in line buffer */
2933
2934
2935
 /*
2936
  * Now loop until we have a valid line...
2937
  */
2938
2939
714k
  *string   = NULL;
2940
714k
  col       = 0;
2941
714k
  startline = pg->ppd_line + 1;
2942
2943
714k
  if (!line->buffer)
2944
7.60k
  {
2945
7.60k
    line->bufsize = 1024;
2946
7.60k
    line->buffer  = malloc(1024);
2947
2948
7.60k
    if (!line->buffer)
2949
0
      return (0);
2950
7.60k
  }
2951
2952
714k
  do
2953
763k
  {
2954
   /*
2955
    * Read the line...
2956
    */
2957
2958
763k
    lineptr  = line->buffer;
2959
763k
    endquote = 0;
2960
763k
    colon    = 0;
2961
2962
29.4M
    while ((ch = cupsFileGetChar(fp)) != EOF)
2963
29.4M
    {
2964
29.4M
      if (lineptr >= (line->buffer + line->bufsize - 1))
2965
2.35k
      {
2966
       /*
2967
        * Expand the line buffer...
2968
  */
2969
2970
2.35k
        char *temp;     /* Temporary line pointer */
2971
2972
2973
2.35k
        line->bufsize += 1024;
2974
2.35k
  if (line->bufsize > 262144)
2975
1
  {
2976
   /*
2977
    * Don't allow lines longer than 256k!
2978
    */
2979
2980
1
          pg->ppd_line   = startline;
2981
1
          pg->ppd_status = PPD_LINE_TOO_LONG;
2982
2983
1
    return (0);
2984
1
  }
2985
2986
2.35k
        temp = realloc(line->buffer, line->bufsize);
2987
2.35k
  if (!temp)
2988
0
  {
2989
0
          pg->ppd_line   = startline;
2990
0
          pg->ppd_status = PPD_LINE_TOO_LONG;
2991
2992
0
    return (0);
2993
0
  }
2994
2995
2.35k
        lineptr      = temp + (lineptr - line->buffer);
2996
2.35k
  line->buffer = temp;
2997
2.35k
      }
2998
2999
29.4M
      if (ch == '\r' || ch == '\n')
3000
1.61M
      {
3001
       /*
3002
  * Line feed or carriage return...
3003
  */
3004
3005
1.61M
        pg->ppd_line ++;
3006
1.61M
  col = 0;
3007
3008
1.61M
  if (ch == '\r')
3009
758k
  {
3010
   /*
3011
          * Check for a trailing line feed...
3012
    */
3013
3014
758k
    if ((ch = cupsFilePeekChar(fp)) == EOF)
3015
41
    {
3016
41
      ch = '\n';
3017
41
      break;
3018
41
    }
3019
3020
758k
    if (ch == 0x0a)
3021
1.86k
      cupsFileGetChar(fp);
3022
758k
  }
3023
3024
1.61M
  if (lineptr == line->buffer && ignoreblank)
3025
14.0k
          continue;      /* Skip blank lines */
3026
3027
1.60M
  ch = '\n';
3028
3029
1.60M
  if (!endquote)      /* Continue for multi-line text */
3030
755k
          break;
3031
3032
847k
  *lineptr++ = '\n';
3033
847k
      }
3034
27.8M
      else if (ch < ' ' && ch != '\t' && pg->ppd_conform == PPD_CONFORM_STRICT)
3035
0
      {
3036
       /*
3037
        * Other control characters...
3038
  */
3039
3040
0
        pg->ppd_line   = startline;
3041
0
        pg->ppd_status = PPD_ILLEGAL_CHARACTER;
3042
3043
0
        return (0);
3044
0
      }
3045
27.8M
      else if (ch != 0x1a)
3046
23.2M
      {
3047
       /*
3048
  * Any other character...
3049
  */
3050
3051
23.2M
  *lineptr++ = (char)ch;
3052
23.2M
  col ++;
3053
3054
23.2M
  if (col > (PPD_MAX_LINE - 1))
3055
22
  {
3056
   /*
3057
          * Line is too long...
3058
    */
3059
3060
22
          pg->ppd_line   = startline;
3061
22
          pg->ppd_status = PPD_LINE_TOO_LONG;
3062
3063
22
          return (0);
3064
22
  }
3065
3066
23.2M
  if (ch == ':' && strncmp(line->buffer, "*%", 2) != 0)
3067
836k
    colon = 1;
3068
3069
23.2M
  if (ch == '\"' && colon)
3070
432k
    endquote = !endquote;
3071
23.2M
      }
3072
29.4M
    }
3073
3074
763k
    if (endquote)
3075
1.09k
    {
3076
     /*
3077
      * Didn't finish this quoted string...
3078
      */
3079
3080
1.09k
      while ((ch = cupsFileGetChar(fp)) != EOF)
3081
0
        if (ch == '\"')
3082
0
    break;
3083
0
  else if (ch == '\r' || ch == '\n')
3084
0
  {
3085
0
    pg->ppd_line ++;
3086
0
    col = 0;
3087
3088
0
    if (ch == '\r')
3089
0
    {
3090
     /*
3091
            * Check for a trailing line feed...
3092
      */
3093
3094
0
      if ((ch = cupsFilePeekChar(fp)) == EOF)
3095
0
        break;
3096
0
      if (ch == 0x0a)
3097
0
        cupsFileGetChar(fp);
3098
0
    }
3099
0
  }
3100
0
  else if (ch < ' ' && ch != '\t' && pg->ppd_conform == PPD_CONFORM_STRICT)
3101
0
  {
3102
   /*
3103
          * Other control characters...
3104
    */
3105
3106
0
          pg->ppd_line   = startline;
3107
0
          pg->ppd_status = PPD_ILLEGAL_CHARACTER;
3108
3109
0
          return (0);
3110
0
  }
3111
0
  else if (ch != 0x1a)
3112
0
  {
3113
0
    col ++;
3114
3115
0
    if (col > (PPD_MAX_LINE - 1))
3116
0
    {
3117
     /*
3118
            * Line is too long...
3119
      */
3120
3121
0
            pg->ppd_line   = startline;
3122
0
            pg->ppd_status = PPD_LINE_TOO_LONG;
3123
3124
0
            return (0);
3125
0
    }
3126
0
  }
3127
1.09k
    }
3128
3129
763k
    if (ch != '\n')
3130
8.23k
    {
3131
     /*
3132
      * Didn't finish this line...
3133
      */
3134
3135
8.23k
      while ((ch = cupsFileGetChar(fp)) != EOF)
3136
0
  if (ch == '\r' || ch == '\n')
3137
0
  {
3138
   /*
3139
    * Line feed or carriage return...
3140
    */
3141
3142
0
          pg->ppd_line ++;
3143
0
    col = 0;
3144
3145
0
    if (ch == '\r')
3146
0
    {
3147
     /*
3148
            * Check for a trailing line feed...
3149
      */
3150
3151
0
      if ((ch = cupsFilePeekChar(fp)) == EOF)
3152
0
        break;
3153
0
      if (ch == 0x0a)
3154
0
        cupsFileGetChar(fp);
3155
0
    }
3156
3157
0
    break;
3158
0
  }
3159
0
  else if (ch < ' ' && ch != '\t' && pg->ppd_conform == PPD_CONFORM_STRICT)
3160
0
  {
3161
   /*
3162
          * Other control characters...
3163
    */
3164
3165
0
          pg->ppd_line   = startline;
3166
0
          pg->ppd_status = PPD_ILLEGAL_CHARACTER;
3167
3168
0
          return (0);
3169
0
  }
3170
0
  else if (ch != 0x1a)
3171
0
  {
3172
0
    col ++;
3173
3174
0
    if (col > (PPD_MAX_LINE - 1))
3175
0
    {
3176
     /*
3177
            * Line is too long...
3178
      */
3179
3180
0
            pg->ppd_line   = startline;
3181
0
            pg->ppd_status = PPD_LINE_TOO_LONG;
3182
3183
0
            return (0);
3184
0
    }
3185
0
  }
3186
8.23k
    }
3187
3188
763k
    if (lineptr > line->buffer && lineptr[-1] == '\n')
3189
176
      lineptr --;
3190
3191
763k
    *lineptr = '\0';
3192
3193
763k
    DEBUG_printf("9ppd_read: LINE=\"%s\"", line->buffer);
3194
3195
   /*
3196
    * The dynamically created PPDs for older style macOS
3197
    * drivers include a large blob of data inserted as comments
3198
    * at the end of the file.  As an optimization we can stop
3199
    * reading the PPD when we get to the start of this data.
3200
    */
3201
3202
763k
    if (!strcmp(line->buffer, "*%APLWORKSET START"))
3203
1
      return (0);
3204
3205
763k
    if (ch == EOF && lineptr == line->buffer)
3206
3.30k
      return (0);
3207
3208
   /*
3209
    * Now parse it...
3210
    */
3211
3212
760k
    mask    = 0;
3213
760k
    lineptr = line->buffer + 1;
3214
3215
760k
    keyword[0] = '\0';
3216
760k
    option[0]  = '\0';
3217
760k
    text[0]    = '\0';
3218
760k
    *string    = NULL;
3219
3220
760k
    if ((!line->buffer[0] ||   /* Blank line */
3221
757k
         !strncmp(line->buffer, "*%", 2) || /* Comment line */
3222
720k
         !strcmp(line->buffer, "*End")) && /* End of multi-line string */
3223
40.4k
        ignoreblank)      /* Ignore these? */
3224
39.8k
    {
3225
39.8k
      startline = pg->ppd_line + 1;
3226
39.8k
      continue;
3227
39.8k
    }
3228
3229
720k
    if (!strcmp(line->buffer, "*"))  /* (Bad) comment line */
3230
5.37k
    {
3231
5.37k
      if (pg->ppd_conform == PPD_CONFORM_RELAXED)
3232
5.37k
      {
3233
5.37k
  startline = pg->ppd_line + 1;
3234
5.37k
  continue;
3235
5.37k
      }
3236
0
      else
3237
0
      {
3238
0
        pg->ppd_line   = startline;
3239
0
        pg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
3240
3241
0
        return (0);
3242
0
      }
3243
5.37k
    }
3244
3245
715k
    if (line->buffer[0] != '*')    /* All lines start with an asterisk */
3246
1.90k
    {
3247
     /*
3248
      * Allow lines consisting of just whitespace...
3249
      */
3250
3251
3.56k
      for (lineptr = line->buffer; *lineptr; lineptr ++)
3252
3.14k
        if (*lineptr && !_cups_isspace(*lineptr))
3253
1.48k
    break;
3254
3255
1.90k
      if (*lineptr)
3256
1.48k
      {
3257
1.48k
        pg->ppd_status = PPD_MISSING_ASTERISK;
3258
1.48k
        return (0);
3259
1.48k
      }
3260
419
      else if (ignoreblank)
3261
357
        continue;
3262
62
      else
3263
62
        return (0);
3264
1.90k
    }
3265
3266
   /*
3267
    * Get a keyword...
3268
    */
3269
3270
713k
    keyptr = keyword;
3271
3272
5.67M
    while (*lineptr && *lineptr != ':' && !_cups_isspace(*lineptr))
3273
4.96M
    {
3274
4.96M
      if (*lineptr <= ' ' || *lineptr > 126 || *lineptr == '/' ||
3275
4.96M
          (keyptr - keyword) >= (PPD_MAX_NAME - 1))
3276
1.44k
      {
3277
1.44k
        pg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
3278
1.44k
  return (0);
3279
1.44k
      }
3280
3281
4.96M
      *keyptr++ = *lineptr++;
3282
4.96M
    }
3283
3284
711k
    *keyptr = '\0';
3285
3286
711k
    if (!strcmp(keyword, "End"))
3287
3.33k
      continue;
3288
3289
708k
    mask |= PPD_KEYWORD;
3290
3291
708k
    if (_cups_isspace(*lineptr))
3292
175k
    {
3293
     /*
3294
      * Get an option name...
3295
      */
3296
3297
355k
      while (_cups_isspace(*lineptr))
3298
179k
        lineptr ++;
3299
3300
175k
      optptr = option;
3301
3302
1.43M
      while (*lineptr && !_cups_isspace(*lineptr) && *lineptr != ':' &&
3303
1.32M
             *lineptr != '/')
3304
1.26M
      {
3305
1.26M
  if (*lineptr <= ' ' || *lineptr > 126 ||
3306
1.26M
      (optptr - option) >= (PPD_MAX_NAME - 1))
3307
269
        {
3308
269
          pg->ppd_status = PPD_ILLEGAL_OPTION_KEYWORD;
3309
269
    return (0);
3310
269
  }
3311
3312
1.26M
        *optptr++ = *lineptr++;
3313
1.26M
      }
3314
3315
175k
      *optptr = '\0';
3316
3317
175k
      if (_cups_isspace(*lineptr) && pg->ppd_conform == PPD_CONFORM_STRICT)
3318
0
      {
3319
0
        pg->ppd_status = PPD_ILLEGAL_WHITESPACE;
3320
0
  return (0);
3321
0
      }
3322
3323
194k
      while (_cups_isspace(*lineptr))
3324
18.4k
  lineptr ++;
3325
3326
175k
      mask |= PPD_OPTION;
3327
3328
175k
      if (*lineptr == '/')
3329
64.8k
      {
3330
       /*
3331
        * Get human-readable text...
3332
  */
3333
3334
64.8k
        lineptr ++;
3335
3336
64.8k
  textptr = text;
3337
3338
1.09M
  while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':')
3339
1.02M
  {
3340
1.02M
    if (((unsigned char)*lineptr < ' ' && *lineptr != '\t') ||
3341
1.02M
        (textptr - text) >= (PPD_MAX_LINE - 1))
3342
35
    {
3343
35
      pg->ppd_status = PPD_ILLEGAL_TRANSLATION;
3344
35
      return (0);
3345
35
    }
3346
3347
1.02M
    *textptr++ = *lineptr++;
3348
1.02M
        }
3349
3350
64.8k
  *textptr = '\0';
3351
64.8k
  textlen  = ppd_decode(text);
3352
3353
64.8k
  if (textlen > PPD_MAX_TEXT && pg->ppd_conform == PPD_CONFORM_STRICT)
3354
0
  {
3355
0
    pg->ppd_status = PPD_ILLEGAL_TRANSLATION;
3356
0
    return (0);
3357
0
  }
3358
3359
64.8k
  mask |= PPD_TEXT;
3360
64.8k
      }
3361
175k
    }
3362
3363
708k
    if (_cups_isspace(*lineptr) && pg->ppd_conform == PPD_CONFORM_STRICT)
3364
0
    {
3365
0
      pg->ppd_status = PPD_ILLEGAL_WHITESPACE;
3366
0
      return (0);
3367
0
    }
3368
3369
708k
    while (_cups_isspace(*lineptr))
3370
0
      lineptr ++;
3371
3372
708k
    if (*lineptr == ':')
3373
623k
    {
3374
     /*
3375
      * Get string after trimming leading and trailing whitespace...
3376
      */
3377
3378
623k
      lineptr ++;
3379
1.21M
      while (_cups_isspace(*lineptr))
3380
589k
        lineptr ++;
3381
3382
623k
      strptr = lineptr + strlen(lineptr) - 1;
3383
691k
      while (strptr >= lineptr && _cups_isspace(*strptr))
3384
67.9k
        *strptr-- = '\0';
3385
3386
623k
      if (*strptr == '\"')
3387
124k
      {
3388
       /*
3389
        * Quoted string by itself, remove quotes...
3390
  */
3391
3392
124k
        *strptr = '\0';
3393
124k
  lineptr ++;
3394
124k
      }
3395
3396
623k
      *string = strdup(lineptr);
3397
3398
623k
      mask |= PPD_STRING;
3399
623k
    }
3400
708k
  }
3401
757k
  while (mask == 0);
3402
3403
708k
  return (mask);
3404
714k
}
3405
3406
3407
/*
3408
 * 'ppd_update_filters()' - Update the filters array as needed.
3409
 *
3410
 * This function re-populates the filters array with cupsFilter2 entries that
3411
 * have been stripped of the destination MIME media types and any maxsize hints.
3412
 *
3413
 * (All for backwards-compatibility)
3414
 */
3415
3416
static int        /* O - 1 on success, 0 on failure */
3417
ppd_update_filters(ppd_file_t     *ppd, /* I - PPD file */
3418
                   _ppd_globals_t *pg)  /* I - Global data */
3419
3.13k
{
3420
3.13k
  ppd_attr_t  *attr;      /* Current cupsFilter2 value */
3421
3.13k
  char    srcsuper[16],   /* Source MIME media type */
3422
3.13k
    srctype[256],
3423
3.13k
    dstsuper[16],   /* Destination MIME media type */
3424
3.13k
    dsttype[256],
3425
3.13k
    *ptr,     /* Pointer into command to run */
3426
3.13k
    buffer[1024],   /* Re-written cupsFilter value */
3427
3.13k
    **filter;   /* Current filter */
3428
3.13k
  int   cost;     /* Cost of filter */
3429
3430
3.13k
  char    program[1024] = { 0 };  /* Command to run */
3431
3432
3.13k
  DEBUG_printf("4ppd_update_filters(ppd=%p, cg=%p)", (void *)ppd, (void *)pg);
3433
3434
 /*
3435
  * See if we have any cupsFilter2 lines...
3436
  */
3437
3438
3.13k
  if ((attr = ppdFindAttr(ppd, "cupsFilter2", NULL)) == NULL)
3439
3.11k
  {
3440
3.11k
    DEBUG_puts("5ppd_update_filters: No cupsFilter2 keywords present.");
3441
3.11k
    return (1);
3442
3.11k
  }
3443
3444
 /*
3445
  * Yes, free the cupsFilter-defined filters and re-build...
3446
  */
3447
3448
13
  ppd_free_filters(ppd);
3449
3450
13
  do
3451
13
  {
3452
   /*
3453
    * Parse the cupsFilter2 string:
3454
    *
3455
    *   src/type dst/type cost program
3456
    *   src/type dst/type cost maxsize(n) program
3457
    */
3458
3459
13
    DEBUG_printf("5ppd_update_filters: cupsFilter2=\"%s\"", attr->value);
3460
3461
13
    if (sscanf(attr->value, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]",
3462
13
         srcsuper, srctype, dstsuper, dsttype, &cost, program) != 6)
3463
13
    {
3464
13
      DEBUG_puts("5ppd_update_filters: Bad cupsFilter2 line.");
3465
13
      pg->ppd_status = PPD_BAD_VALUE;
3466
3467
13
      return (0);
3468
13
    }
3469
3470
0
    DEBUG_printf("5ppd_update_filters: srcsuper=\"%s\", srctype=\"%s\", dstsuper=\"%s\", dsttype=\"%s\", cost=%d, program=\"%s\"", srcsuper, srctype, dstsuper, dsttype, cost, program);
3471
3472
0
    if (!strncmp(program, "maxsize(", 8) &&
3473
0
        (ptr = strchr(program + 8, ')')) != NULL)
3474
0
    {
3475
0
      DEBUG_puts("5ppd_update_filters: Found maxsize(nnn).");
3476
3477
0
      ptr ++;
3478
0
      while (_cups_isspace(*ptr))
3479
0
  ptr ++;
3480
3481
0
      _cups_strcpy(program, ptr);
3482
0
      DEBUG_printf("5ppd_update_filters: New program=\"%s\"", program);
3483
0
    }
3484
3485
   /*
3486
    * Convert to cupsFilter format:
3487
    *
3488
    *   src/type cost program
3489
    */
3490
3491
0
    snprintf(buffer, sizeof(buffer), "%s/%s %d %s", srcsuper, srctype, cost,
3492
0
             program);
3493
0
    DEBUG_printf("5ppd_update_filters: Adding \"%s\".", buffer);
3494
3495
   /*
3496
    * Add a cupsFilter-compatible string to the filters array.
3497
    */
3498
3499
0
    if (ppd->num_filters == 0)
3500
0
      filter = malloc(sizeof(char *));
3501
0
    else
3502
0
      filter = realloc(ppd->filters, sizeof(char *) * (size_t)(ppd->num_filters + 1));
3503
3504
0
    if (filter == NULL)
3505
0
    {
3506
0
      DEBUG_puts("5ppd_update_filters: Out of memory.");
3507
0
      pg->ppd_status = PPD_ALLOC_ERROR;
3508
3509
0
      return (0);
3510
0
    }
3511
3512
0
    ppd->filters     = filter;
3513
0
    filter           += ppd->num_filters;
3514
0
    ppd->num_filters ++;
3515
3516
0
    *filter = strdup(buffer);
3517
0
  }
3518
13
  while ((attr = ppdFindNextAttr(ppd, "cupsFilter2", NULL)) != NULL);
3519
3520
0
  DEBUG_puts("5ppd_update_filters: Completed OK.");
3521
0
  return (1);
3522
13
}