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