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