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