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