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