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