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