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