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