2 * PPD file routines for CUPS.
4 * Copyright 2007-2015 by Apple Inc.
5 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
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 * missing or damaged, see the license at "http://www.cups.org/".
13 * PostScript is a trademark of Adobe Systems, Inc.
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
22 * This file is subject to the Apple OS-Developed Software exception.
26 * Include necessary headers.
29 #include "cups-private.h"
30 #include "ppd-private.h"
37 #define ppd_free(p) if (p) free(p) /* Safe free macro */
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 */
44 #define PPD_HASHSIZE 512 /* Size of hash */
48 * Line buffer structure...
51 typedef struct _ppd_line_s
53 char *buffer; /* Pointer to buffer */
54 size_t bufsize; /* Size of the buffer */
62 static _cups_threadkey_t ppd_globals_key = _CUPS_THREADKEY_INITIALIZER;
63 /* Thread local storage key */
65 static pthread_once_t ppd_globals_key_once = PTHREAD_ONCE_INIT;
66 /* One-time initialization object */
67 #endif /* HAVE_PTHREAD_H */
74 static ppd_attr_t *ppd_add_attr(ppd_file_t *ppd, const char *name,
75 const char *spec, const char *text,
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,
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,
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,
108 static int ppd_update_filters(ppd_file_t *ppd,
113 * 'ppdClose()' - Free all memory used by the PPD file.
117 ppdClose(ppd_file_t *ppd) /* I - PPD file record */
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 */
129 * Range check arguments...
136 * Free all strings at the top level...
139 _cupsStrFree(ppd->lang_encoding);
140 _cupsStrFree(ppd->nickname);
143 _cupsStrFree(ppd->jcl_begin);
144 _cupsStrFree(ppd->jcl_end);
145 _cupsStrFree(ppd->jcl_ps);
148 * Free any emulations...
151 if (ppd->num_emulations > 0)
153 for (i = ppd->num_emulations, emul = ppd->emulations; i > 0; i --, emul ++)
155 _cupsStrFree(emul->start);
156 _cupsStrFree(emul->stop);
159 ppd_free(ppd->emulations);
163 * Free any UI groups, subgroups, and options...
166 if (ppd->num_groups > 0)
168 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
169 ppd_free_group(group);
171 ppd_free(ppd->groups);
174 cupsArrayDelete(ppd->options);
175 cupsArrayDelete(ppd->marked);
178 * Free any page sizes...
181 if (ppd->num_sizes > 0)
182 ppd_free(ppd->sizes);
185 * Free any constraints...
188 if (ppd->num_consts > 0)
189 ppd_free(ppd->consts);
192 * Free any filters...
195 ppd_free_filters(ppd);
201 if (ppd->num_fonts > 0)
203 for (i = ppd->num_fonts, font = ppd->fonts; i > 0; i --, font ++)
206 ppd_free(ppd->fonts);
210 * Free any profiles...
213 if (ppd->num_profiles > 0)
214 ppd_free(ppd->profiles);
217 * Free any attributes...
220 if (ppd->num_attrs > 0)
222 for (i = ppd->num_attrs, attr = ppd->attrs; i > 0; i --, attr ++)
224 _cupsStrFree((*attr)->value);
228 ppd_free(ppd->attrs);
231 cupsArrayDelete(ppd->sorted_attrs);
234 * Free custom options...
237 for (coption = (ppd_coption_t *)cupsArrayFirst(ppd->coptions);
239 coption = (ppd_coption_t *)cupsArrayNext(ppd->coptions))
241 for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
243 cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
245 switch (cparam->type)
247 case PPD_CUSTOM_PASSCODE :
248 case PPD_CUSTOM_PASSWORD :
249 case PPD_CUSTOM_STRING :
250 _cupsStrFree(cparam->current.custom_string);
260 cupsArrayDelete(coption->params);
265 cupsArrayDelete(ppd->coptions);
268 * Free constraints...
271 if (ppd->cups_uiconstraints)
273 _ppd_cups_uiconsts_t *consts; /* Current constraints */
276 for (consts = (_ppd_cups_uiconsts_t *)cupsArrayFirst(ppd->cups_uiconstraints);
278 consts = (_ppd_cups_uiconsts_t *)cupsArrayNext(ppd->cups_uiconstraints))
280 free(consts->constraints);
284 cupsArrayDelete(ppd->cups_uiconstraints);
288 * Free any PPD cache/mapping data...
292 _ppdCacheDestroy(ppd->cache);
295 * Free the whole record...
303 * 'ppdErrorString()' - Returns the text associated with a status.
305 * @since CUPS 1.1.19/macOS 10.3@
308 const char * /* O - Status string */
309 ppdErrorString(ppd_status_t status) /* I - PPD status */
311 static const char * const messages[] =/* Status messages */
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"),
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")
340 if (status < PPD_OK || status >= PPD_MAX_STATUS)
341 return (_cupsLangString(cupsLangDefault(), _("Unknown")));
343 return (_cupsLangString(cupsLangDefault(), messages[status]));
348 * '_ppdGetEncoding()' - Get the CUPS encoding value for the given
352 cups_encoding_t /* O - CUPS encoding value */
353 _ppdGetEncoding(const char *name) /* I - LanguageEncoding string */
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);
373 * '_ppdGlobals()' - Return a pointer to thread local storage
376 _ppd_globals_t * /* O - Pointer to global data */
379 _ppd_globals_t *pg; /* Pointer to global data */
382 #ifdef HAVE_PTHREAD_H
384 * Initialize the global data exactly once...
387 pthread_once(&ppd_globals_key_once, ppd_globals_init);
388 #endif /* HAVE_PTHREAD_H */
391 * See if we have allocated the data yet...
394 if ((pg = (_ppd_globals_t *)_cupsThreadGetData(ppd_globals_key)) == NULL)
397 * No, allocate memory as set the pointer for the key...
400 if ((pg = ppd_globals_alloc()) != NULL)
401 _cupsThreadSetData(ppd_globals_key, pg);
405 * Return the pointer to the data...
413 * 'ppdLastError()' - Return the status from the last ppdOpen*().
415 * @since CUPS 1.1.19/macOS 10.3@
418 ppd_status_t /* O - Status code */
419 ppdLastError(int *line) /* O - Line number */
421 _ppd_globals_t *pg = _ppdGlobals();
426 *line = pg->ppd_line;
428 return (pg->ppd_status);
433 * '_ppdOpen()' - Read a PPD file into memory.
435 * @since CUPS 1.2/macOS 10.5@
438 ppd_file_t * /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
440 cups_file_t *fp, /* I - File to read from */
441 _ppd_localization_t localization) /* I - Localization to load */
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 */
457 /* Option from file */
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();
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[] =
484 #ifdef CUPS_USE_FULL_UI_KEYWORDS_LIST
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.
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.
494 /* Boolean keywords */
504 /* PickOne keywords */
517 "JCLFrameBufferSize",
538 #else /* !CUPS_USE_FULL_UI_KEYWORDS_LIST */
541 #endif /* CUPS_USE_FULL_UI_KEYWORDS_LIST */
543 static const char * const color_keywords[] = /* Keywords associated with color profiles */
550 DEBUG_printf(("_ppdOpen(fp=%p)", fp));
553 * Default to "OK" status...
556 pg->ppd_status = PPD_OK;
560 * Range check input...
565 pg->ppd_status = PPD_NULL_FILE;
570 * If only loading a single localization set up the strings to match...
573 if (localization == _PPD_LOCALIZATION_DEFAULT)
575 if ((lang = cupsLangDefault()) == NULL)
578 snprintf(ll_CC, sizeof(ll_CC), "%s.", lang->language);
581 * <rdar://problem/22130168>
583 * Need to use a different base language for some locales...
586 if (!strcmp(lang->language, "zh_HK"))
587 strlcpy(ll, "zh_TW.", sizeof(ll));
589 snprintf(ll, sizeof(ll), "%2.2s.", lang->language);
591 ll_CC_len = strlen(ll_CC);
594 DEBUG_printf(("2_ppdOpen: Loading localizations matching \"%s\" and \"%s\"",
599 * Grab the first line and make sure it reads '*PPD-Adobe: "major.minor"'...
605 mask = ppd_read(fp, &line, keyword, name, text, &string, 0, pg);
607 DEBUG_printf(("2_ppdOpen: mask=%x, keyword=\"%s\"...", mask, keyword));
610 strcmp(keyword, "PPD-Adobe") ||
611 string == NULL || string[0] != '4')
614 * Either this is not a PPD file, or it is not a 4.x PPD file.
617 if (pg->ppd_status == PPD_OK)
618 pg->ppd_status = PPD_MISSING_PPDADOBE4;
620 _cupsStrFree(string);
621 ppd_free(line.buffer);
626 DEBUG_printf(("2_ppdOpen: keyword=%s, string=%p", keyword, string));
628 _cupsStrFree(string);
631 * Allocate memory for the PPD file record...
634 if ((ppd = calloc(1, sizeof(ppd_file_t))) == NULL)
636 pg->ppd_status = PPD_ALLOC_ERROR;
638 _cupsStrFree(string);
639 ppd_free(line.buffer);
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,
652 * Read lines from the PPD file and add them to the file record...
660 encoding = CUPS_ISO8859_1;
663 while ((mask = ppd_read(fp, &line, keyword, name, text, &string, 1, pg)) != 0)
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));
669 if (strncmp(keyword, "Default", 7) && !string &&
670 pg->ppd_conform != PPD_CONFORM_RELAXED)
673 * Need a string value!
676 pg->ppd_status = PPD_MISSING_VALUE;
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...
695 * Previous line was a UI keyword...
703 * If we are filtering out keyword localizations, see if this line needs to
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] == '.')))
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)))
721 DEBUG_printf(("2_ppdOpen: Ignoring localization: \"%s\"\n", keyword));
724 else if (localization == _PPD_LOCALIZATION_ICC_PROFILES)
727 * Only load localizations for the color profile related keywords...
731 i < (int)(sizeof(color_keywords) / sizeof(color_keywords[0]));
734 if (!_cups_strcasecmp(temp, color_keywords[i]))
738 if (i >= (int)(sizeof(color_keywords) / sizeof(color_keywords[0])))
740 DEBUG_printf(("2_ppdOpen: Ignoring localization: \"%s\"\n", keyword));
746 if (option == NULL &&
747 (mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) ==
748 (PPD_KEYWORD | PPD_OPTION | PPD_STRING))
750 for (i = 0; i < (int)(sizeof(ui_keywords) / sizeof(ui_keywords[0])); i ++)
751 if (!strcmp(keyword, ui_keywords[i]))
754 if (i < (int)(sizeof(ui_keywords) / sizeof(ui_keywords[0])))
757 * Create the option in the appropriate group...
762 DEBUG_printf(("2_ppdOpen: FOUND ADOBE UI KEYWORD %s WITHOUT OPENUI!",
767 if ((group = ppd_get_group(ppd, "General", _("General"), pg,
771 DEBUG_printf(("2_ppdOpen: Adding to group %s...", group->text));
772 option = ppd_get_option(group, keyword);
776 option = ppd_get_option(group, keyword);
780 pg->ppd_status = PPD_ALLOC_ERROR;
786 * Now fill in the initial information for the option...
789 if (!strncmp(keyword, "JCL", 3))
790 option->section = PPD_ORDER_JCL;
792 option->section = PPD_ORDER_ANY;
794 option->order = 10.0f;
797 option->ui = PPD_UI_BOOLEAN;
799 option->ui = PPD_UI_PICKONE;
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)
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));
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));
824 strlcpy(option->text, keyword, sizeof(option->text));
828 if (!strcmp(keyword, "LanguageLevel"))
829 ppd->language_level = atoi(string);
830 else if (!strcmp(keyword, "LanguageEncoding"))
833 * Say all PPD files are UTF-8, since we convert to UTF-8...
836 ppd->lang_encoding = _cupsStrAlloc("UTF-8");
837 encoding = _ppdGetEncoding(string);
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"))
851 if (encoding != CUPS_UTF8)
853 cups_utf8_t utf8[256]; /* UTF-8 version of NickName */
856 cupsCharsetToUTF8(utf8, string, sizeof(utf8), encoding);
857 ppd->nickname = _cupsStrAlloc((char *)utf8);
860 ppd->nickname = _cupsStrAlloc(string);
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"))
870 ppd->jcl_begin = _cupsStrAlloc(string);
871 ppd_decode(ppd->jcl_begin); /* Decode quoted string */
873 else if (!strcmp(keyword, "JCLEnd"))
875 ppd->jcl_end = _cupsStrAlloc(string);
876 ppd_decode(ppd->jcl_end); /* Decode quoted string */
878 else if (!strcmp(keyword, "JCLToPSInterpreter"))
880 ppd->jcl_ps = _cupsStrAlloc(string);
881 ppd_decode(ppd->jcl_ps); /* Decode quoted string */
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"))
897 if (ppd->num_profiles == 0)
898 profile = malloc(sizeof(ppd_profile_t));
900 profile = realloc(ppd->profiles, sizeof(ppd_profile_t) * (size_t)(ppd->num_profiles + 1));
904 pg->ppd_status = PPD_ALLOC_ERROR;
909 ppd->profiles = profile;
910 profile += ppd->num_profiles;
911 ppd->num_profiles ++;
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));
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);
929 else if (!strcmp(keyword, "cupsFilter"))
931 if (ppd->num_filters == 0)
932 filter = malloc(sizeof(char *));
934 filter = realloc(ppd->filters, sizeof(char *) * (size_t)(ppd->num_filters + 1));
938 pg->ppd_status = PPD_ALLOC_ERROR;
943 ppd->filters = filter;
944 filter += ppd->num_filters;
948 * Retain a copy of the filter string...
951 *filter = _cupsStrRetain(string);
953 else if (!strcmp(keyword, "Throughput"))
954 ppd->throughput = atoi(string);
955 else if (!strcmp(keyword, "Font"))
958 * Add this font to the list of available fonts...
961 if (ppd->num_fonts == 0)
962 tempfonts = (char **)malloc(sizeof(char *));
964 tempfonts = (char **)realloc(ppd->fonts, sizeof(char *) * (size_t)(ppd->num_fonts + 1));
966 if (tempfonts == NULL)
968 pg->ppd_status = PPD_ALLOC_ERROR;
973 ppd->fonts = tempfonts;
974 ppd->fonts[ppd->num_fonts] = _cupsStrAlloc(name);
977 else if (!strncmp(keyword, "ParamCustom", 11))
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 */
988 * Get the custom option and parameter...
991 if ((coption = ppd_get_coption(ppd, keyword + 11)) == NULL)
993 pg->ppd_status = PPD_ALLOC_ERROR;
998 if ((cparam = ppd_get_cparam(coption, name, text)) == NULL)
1000 pg->ppd_status = PPD_ALLOC_ERROR;
1006 * Get the parameter data...
1010 sscanf(string, "%d%32s%64s%64s", &corder, ctype, cminimum,
1013 pg->ppd_status = PPD_BAD_CUSTOM_PARAM;
1018 cparam->order = corder;
1020 if (!strcmp(ctype, "curve"))
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);
1026 else if (!strcmp(ctype, "int"))
1028 cparam->type = PPD_CUSTOM_INT;
1029 cparam->minimum.custom_int = atoi(cminimum);
1030 cparam->maximum.custom_int = atoi(cmaximum);
1032 else if (!strcmp(ctype, "invcurve"))
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);
1038 else if (!strcmp(ctype, "passcode"))
1040 cparam->type = PPD_CUSTOM_PASSCODE;
1041 cparam->minimum.custom_passcode = atoi(cminimum);
1042 cparam->maximum.custom_passcode = atoi(cmaximum);
1044 else if (!strcmp(ctype, "password"))
1046 cparam->type = PPD_CUSTOM_PASSWORD;
1047 cparam->minimum.custom_password = atoi(cminimum);
1048 cparam->maximum.custom_password = atoi(cmaximum);
1050 else if (!strcmp(ctype, "points"))
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);
1056 else if (!strcmp(ctype, "real"))
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);
1062 else if (!strcmp(ctype, "string"))
1064 cparam->type = PPD_CUSTOM_STRING;
1065 cparam->minimum.custom_string = atoi(cminimum);
1066 cparam->maximum.custom_string = atoi(cmaximum);
1070 pg->ppd_status = PPD_BAD_CUSTOM_PARAM;
1076 * Now special-case for CustomPageSize...
1079 if (!strcmp(coption->keyword, "PageSize"))
1081 if (!strcmp(name, "Width"))
1083 ppd->custom_min[0] = cparam->minimum.custom_points;
1084 ppd->custom_max[0] = cparam->maximum.custom_points;
1086 else if (!strcmp(name, "Height"))
1088 ppd->custom_min[1] = cparam->minimum.custom_points;
1089 ppd->custom_max[1] = cparam->maximum.custom_points;
1093 else if (!strcmp(keyword, "HWMargins"))
1095 for (i = 0, sptr = string; i < 4; i ++)
1096 ppd->custom_margins[i] = (float)_cupsStrScand(sptr, &sptr, loc);
1098 else if (!strncmp(keyword, "Custom", 6) && !strcmp(name, "True") && !option)
1100 ppd_option_t *custom_option; /* Custom option */
1102 DEBUG_puts("2_ppdOpen: Processing Custom option...");
1105 * Get the option and custom option...
1108 if (!ppd_get_coption(ppd, keyword + 6))
1110 pg->ppd_status = PPD_ALLOC_ERROR;
1115 if (option && !_cups_strcasecmp(option->keyword, keyword + 6))
1116 custom_option = option;
1118 custom_option = ppdFindOption(ppd, keyword + 6);
1123 * Add the "custom" option...
1126 if ((choice = ppdFindChoice(custom_option, "Custom")) == NULL)
1127 if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL)
1129 DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
1131 pg->ppd_status = PPD_ALLOC_ERROR;
1136 strlcpy(choice->text, text[0] ? text : _("Custom"),
1137 sizeof(choice->text));
1139 choice->code = _cupsStrAlloc(string);
1141 if (custom_option->section == PPD_ORDER_JCL)
1142 ppd_decode(choice->code);
1146 * Now process custom page sizes specially...
1149 if (!strcmp(keyword, "CustomPageSize"))
1152 * Add a "Custom" page size entry...
1155 ppd->variable_sizes = 1;
1157 ppd_add_size(ppd, "Custom");
1159 if (option && !_cups_strcasecmp(option->keyword, "PageRegion"))
1160 custom_option = option;
1162 custom_option = ppdFindOption(ppd, "PageRegion");
1166 if ((choice = ppdFindChoice(custom_option, "Custom")) == NULL)
1167 if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL)
1169 DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
1171 pg->ppd_status = PPD_ALLOC_ERROR;
1176 strlcpy(choice->text, text[0] ? text : _("Custom"),
1177 sizeof(choice->text));
1181 else if (!strcmp(keyword, "LandscapeOrientation"))
1183 if (!strcmp(string, "Minus90"))
1184 ppd->landscape = -90;
1185 else if (!strcmp(string, "Plus90"))
1186 ppd->landscape = 90;
1188 else if (!strcmp(keyword, "Emulators") && string)
1190 for (count = 1, sptr = string; sptr != NULL;)
1191 if ((sptr = strchr(sptr, ' ')) != NULL)
1194 while (*sptr == ' ')
1198 ppd->num_emulations = count;
1199 if ((ppd->emulations = calloc((size_t)count, sizeof(ppd_emul_t))) == NULL)
1201 pg->ppd_status = PPD_ALLOC_ERROR;
1206 for (i = 0, sptr = string; i < count; i ++)
1208 for (nameptr = ppd->emulations[i].name;
1209 *sptr != '\0' && *sptr != ' ';
1211 if (nameptr < (ppd->emulations[i].name + sizeof(ppd->emulations[i].name) - 1))
1216 while (*sptr == ' ')
1220 else if (!strncmp(keyword, "StartEmulator_", 14))
1224 for (i = 0; i < ppd->num_emulations; i ++)
1225 if (!strcmp(keyword + 14, ppd->emulations[i].name))
1227 ppd->emulations[i].start = string;
1231 else if (!strncmp(keyword, "StopEmulator_", 13))
1235 for (i = 0; i < ppd->num_emulations; i ++)
1236 if (!strcmp(keyword + 13, ppd->emulations[i].name))
1238 ppd->emulations[i].stop = string;
1242 else if (!strcmp(keyword, "JobPatchFile"))
1245 * CUPS STR #3421: Check for "*JobPatchFile: int: string"
1248 if (isdigit(*string & 255))
1250 for (sptr = string + 1; isdigit(*sptr & 255); sptr ++);
1255 * Found "*JobPatchFile: int: string"...
1258 pg->ppd_status = PPD_BAD_VALUE;
1264 if (!name[0] && pg->ppd_conform == PPD_CONFORM_STRICT)
1267 * Found "*JobPatchFile: string"...
1270 pg->ppd_status = PPD_MISSING_OPTION_KEYWORD;
1275 if (ppd->patches == NULL)
1276 ppd->patches = strdup(string);
1279 temp = realloc(ppd->patches, strlen(ppd->patches) +
1280 strlen(string) + 1);
1283 pg->ppd_status = PPD_ALLOC_ERROR;
1288 ppd->patches = temp;
1290 memcpy(ppd->patches + strlen(ppd->patches), string, strlen(string) + 1);
1293 else if (!strcmp(keyword, "OpenUI"))
1296 * Don't allow nesting of options...
1299 if (option && pg->ppd_conform == PPD_CONFORM_STRICT)
1301 pg->ppd_status = PPD_NESTED_OPEN_UI;
1307 * Add an option record to the current sub-group, group, or file...
1310 DEBUG_printf(("2_ppdOpen: name=\"%s\" (%d)", name, (int)strlen(name)));
1313 _cups_strcpy(name, name + 1); /* Eliminate leading asterisk */
1315 for (i = (int)strlen(name) - 1; i > 0 && _cups_isspace(name[i]); i --)
1316 name[i] = '\0'; /* Eliminate trailing spaces */
1318 DEBUG_printf(("2_ppdOpen: OpenUI of %s in group %s...", name,
1319 group ? group->text : "(null)"));
1321 if (subgroup != NULL)
1322 option = ppd_get_option(subgroup, name);
1323 else if (group == NULL)
1325 if ((group = ppd_get_group(ppd, "General", _("General"), pg,
1329 DEBUG_printf(("2_ppdOpen: Adding to group %s...", group->text));
1330 option = ppd_get_option(group, name);
1334 option = ppd_get_option(group, name);
1338 pg->ppd_status = PPD_ALLOC_ERROR;
1344 * Now fill in the initial information for the option...
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)
1355 pg->ppd_status = PPD_BAD_OPEN_UI;
1360 option->ui = PPD_UI_PICKONE;
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)
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));
1375 cupsCharsetToUTF8((cups_utf8_t *)option->text, text,
1376 sizeof(option->text), encoding);
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));
1390 strlcpy(option->text, name, sizeof(option->text));
1393 option->section = PPD_ORDER_ANY;
1395 _cupsStrFree(string);
1399 * Add a custom option choice if we have already seen a CustomFoo
1403 if (!_cups_strcasecmp(name, "PageRegion"))
1404 strlcpy(custom_name, "CustomPageSize", sizeof(custom_name));
1406 snprintf(custom_name, sizeof(custom_name), "Custom%s", name);
1408 if ((custom_attr = ppdFindAttr(ppd, custom_name, "True")) != NULL)
1410 if ((choice = ppdFindChoice(option, "Custom")) == NULL)
1411 if ((choice = ppd_add_choice(option, "Custom")) == NULL)
1413 DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
1415 pg->ppd_status = PPD_ALLOC_ERROR;
1420 strlcpy(choice->text,
1421 custom_attr->text[0] ? custom_attr->text : _("Custom"),
1422 sizeof(choice->text));
1423 choice->code = _cupsStrRetain(custom_attr->value);
1426 else if (!strcmp(keyword, "JCLOpenUI"))
1429 * Don't allow nesting of options...
1432 if (option && pg->ppd_conform == PPD_CONFORM_STRICT)
1434 pg->ppd_status = PPD_NESTED_OPEN_UI;
1440 * Find the JCL group, and add if needed...
1443 group = ppd_get_group(ppd, "JCL", _("JCL"), pg, encoding);
1449 * Add an option record to the current JCLs...
1453 _cups_strcpy(name, name + 1);
1455 option = ppd_get_option(group, name);
1459 pg->ppd_status = PPD_ALLOC_ERROR;
1465 * Now fill in the initial information for the option...
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;
1476 pg->ppd_status = PPD_BAD_OPEN_UI;
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)
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));
1494 cupsCharsetToUTF8((cups_utf8_t *)option->text, text,
1495 sizeof(option->text), encoding);
1497 strlcpy(option->text, name, sizeof(option->text));
1499 option->section = PPD_ORDER_JCL;
1502 _cupsStrFree(string);
1506 * Add a custom option choice if we have already seen a CustomFoo
1510 snprintf(custom_name, sizeof(custom_name), "Custom%s", name);
1512 if ((custom_attr = ppdFindAttr(ppd, custom_name, "True")) != NULL)
1514 if ((choice = ppd_add_choice(option, "Custom")) == NULL)
1516 DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
1518 pg->ppd_status = PPD_ALLOC_ERROR;
1523 strlcpy(choice->text,
1524 custom_attr->text[0] ? custom_attr->text : _("Custom"),
1525 sizeof(choice->text));
1526 choice->code = _cupsStrRetain(custom_attr->value);
1529 else if (!strcmp(keyword, "CloseUI") || !strcmp(keyword, "JCLCloseUI"))
1533 _cupsStrFree(string);
1536 else if (!strcmp(keyword, "OpenGroup"))
1539 * Open a new group...
1544 pg->ppd_status = PPD_NESTED_OPEN_GROUP;
1551 pg->ppd_status = PPD_BAD_OPEN_GROUP;
1557 * Separate the group name from the text (name/text)...
1560 if ((sptr = strchr(string, '/')) != NULL)
1566 * Fix up the text...
1572 * Find/add the group...
1575 group = ppd_get_group(ppd, string, sptr, pg, encoding);
1580 _cupsStrFree(string);
1583 else if (!strcmp(keyword, "CloseGroup"))
1587 _cupsStrFree(string);
1590 else if (!strcmp(keyword, "OrderDependency"))
1592 order = (float)_cupsStrScand(string, &sptr, loc);
1594 if (!sptr || sscanf(sptr, "%40s%40s", name, keyword) != 2)
1596 pg->ppd_status = PPD_BAD_ORDER_DEPENDENCY;
1601 if (keyword[0] == '*')
1602 _cups_strcpy(keyword, keyword + 1);
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;
1615 section = PPD_ORDER_ANY;
1623 * Only valid for Non-UI options...
1626 for (i = ppd->num_groups, gtemp = ppd->groups; i > 0; i --, gtemp ++)
1627 if (gtemp->text[0] == '\0')
1631 for (i = 0; i < gtemp->num_options; i ++)
1632 if (!strcmp(keyword, gtemp->options[i].keyword))
1634 gtemp->options[i].section = section;
1635 gtemp->options[i].order = order;
1641 option->section = section;
1642 option->order = order;
1645 _cupsStrFree(string);
1648 else if (!strncmp(keyword, "Default", 7))
1654 * Drop UI text, if any, from value...
1657 if (strchr(string, '/') != NULL)
1658 *strchr(string, '/') = '\0';
1661 * Assign the default value as appropriate...
1664 if (!strcmp(keyword, "DefaultColorSpace"))
1667 * Set default colorspace...
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;
1681 ppd->colorspace = PPD_CS_GRAY;
1683 else if (option && !strcmp(keyword + 7, option->keyword))
1686 * Set the default as part of the current option...
1689 DEBUG_printf(("2_ppdOpen: Setting %s to %s...", keyword, string));
1691 strlcpy(option->defchoice, string, sizeof(option->defchoice));
1693 DEBUG_printf(("2_ppdOpen: %s is now %s...", keyword, option->defchoice));
1698 * Lookup option and set if it has been defined...
1701 ppd_option_t *toption; /* Temporary option */
1704 if ((toption = ppdFindOption(ppd, keyword + 7)) != NULL)
1706 DEBUG_printf(("2_ppdOpen: Setting %s to %s...", keyword, string));
1707 strlcpy(toption->defchoice, string, sizeof(toption->defchoice));
1711 else if (!strcmp(keyword, "UIConstraints") ||
1712 !strcmp(keyword, "NonUIConstraints"))
1716 pg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1720 if (ppd->num_consts == 0)
1721 constraint = calloc(2, sizeof(ppd_const_t));
1723 constraint = realloc(ppd->consts, (size_t)(ppd->num_consts + 2) * sizeof(ppd_const_t));
1725 if (constraint == NULL)
1727 pg->ppd_status = PPD_ALLOC_ERROR;
1732 ppd->consts = constraint;
1733 constraint += ppd->num_consts;
1736 switch (sscanf(string, "%40s%40s%40s%40s", constraint->option1,
1737 constraint->choice1, constraint->option2,
1738 constraint->choice2))
1740 case 0 : /* Error */
1741 case 1 : /* Error */
1742 pg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1745 case 2 : /* Two options... */
1747 * Check for broken constraints like "* Option"...
1750 if (pg->ppd_conform == PPD_CONFORM_STRICT &&
1751 (!strcmp(constraint->option1, "*") ||
1752 !strcmp(constraint->choice1, "*")))
1754 pg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1759 * The following strcpy's are safe, as optionN and
1760 * choiceN are all the same size (size defined by PPD spec...)
1763 if (constraint->option1[0] == '*')
1764 _cups_strcpy(constraint->option1, constraint->option1 + 1);
1765 else if (pg->ppd_conform == PPD_CONFORM_STRICT)
1767 pg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1771 if (constraint->choice1[0] == '*')
1772 _cups_strcpy(constraint->option2, constraint->choice1 + 1);
1773 else if (pg->ppd_conform == PPD_CONFORM_STRICT)
1775 pg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1779 constraint->choice1[0] = '\0';
1780 constraint->choice2[0] = '\0';
1783 case 3 : /* Two options, one choice... */
1785 * Check for broken constraints like "* Option"...
1788 if (pg->ppd_conform == PPD_CONFORM_STRICT &&
1789 (!strcmp(constraint->option1, "*") ||
1790 !strcmp(constraint->choice1, "*") ||
1791 !strcmp(constraint->option2, "*")))
1793 pg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1798 * The following _cups_strcpy's are safe, as optionN and
1799 * choiceN are all the same size (size defined by PPD spec...)
1802 if (constraint->option1[0] == '*')
1803 _cups_strcpy(constraint->option1, constraint->option1 + 1);
1804 else if (pg->ppd_conform == PPD_CONFORM_STRICT)
1806 pg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1810 if (constraint->choice1[0] == '*')
1812 if (pg->ppd_conform == PPD_CONFORM_STRICT &&
1813 constraint->option2[0] == '*')
1815 pg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1819 _cups_strcpy(constraint->choice2, constraint->option2);
1820 _cups_strcpy(constraint->option2, constraint->choice1 + 1);
1821 constraint->choice1[0] = '\0';
1825 if (constraint->option2[0] == '*')
1826 _cups_strcpy(constraint->option2, constraint->option2 + 1);
1827 else if (pg->ppd_conform == PPD_CONFORM_STRICT)
1829 pg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1833 constraint->choice2[0] = '\0';
1837 case 4 : /* Two options, two choices... */
1839 * Check for broken constraints like "* Option"...
1842 if (pg->ppd_conform == PPD_CONFORM_STRICT &&
1843 (!strcmp(constraint->option1, "*") ||
1844 !strcmp(constraint->choice1, "*") ||
1845 !strcmp(constraint->option2, "*") ||
1846 !strcmp(constraint->choice2, "*")))
1848 pg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1852 if (constraint->option1[0] == '*')
1853 _cups_strcpy(constraint->option1, constraint->option1 + 1);
1854 else if (pg->ppd_conform == PPD_CONFORM_STRICT)
1856 pg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1860 if (pg->ppd_conform == PPD_CONFORM_STRICT &&
1861 constraint->choice1[0] == '*')
1863 pg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1867 if (constraint->option2[0] == '*')
1868 _cups_strcpy(constraint->option2, constraint->option2 + 1);
1869 else if (pg->ppd_conform == PPD_CONFORM_STRICT)
1871 pg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1875 if (pg->ppd_conform == PPD_CONFORM_STRICT &&
1876 constraint->choice2[0] == '*')
1878 pg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1885 * Don't add this one as an attribute...
1888 _cupsStrFree(string);
1891 else if (!strcmp(keyword, "PaperDimension"))
1893 if ((size = ppdPageSize(ppd, name)) == NULL)
1894 size = ppd_add_size(ppd, name);
1899 * Unable to add or find size!
1902 pg->ppd_status = PPD_ALLOC_ERROR;
1907 size->width = (float)_cupsStrScand(string, &sptr, loc);
1908 size->length = (float)_cupsStrScand(sptr, NULL, loc);
1910 _cupsStrFree(string);
1913 else if (!strcmp(keyword, "ImageableArea"))
1915 if ((size = ppdPageSize(ppd, name)) == NULL)
1916 size = ppd_add_size(ppd, name);
1921 * Unable to add or find size!
1924 pg->ppd_status = PPD_ALLOC_ERROR;
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);
1934 _cupsStrFree(string);
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))
1942 DEBUG_printf(("2_ppdOpen: group=%p, subgroup=%p", group, subgroup));
1944 if (!strcmp(keyword, "PageSize"))
1947 * Add a page size...
1950 if (ppdPageSize(ppd, name) == NULL)
1951 ppd_add_size(ppd, name);
1955 * Add the option choice...
1958 if ((choice = ppd_add_choice(option, name)) == NULL)
1960 pg->ppd_status = PPD_ALLOC_ERROR;
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));
1973 strlcpy(choice->text, name, sizeof(choice->text));
1975 if (option->section == PPD_ORDER_JCL)
1976 ppd_decode(string); /* Decode quoted string */
1978 choice->code = string;
1979 string = NULL; /* Don't add as an attribute below */
1983 * Add remaining lines with keywords and string values as attributes...
1987 (mask & (PPD_KEYWORD | PPD_STRING)) == (PPD_KEYWORD | PPD_STRING))
1988 ppd_add_attr(ppd, keyword, name, text, string);
1990 _cupsStrFree(string);
1994 * Check for a missing CloseGroup...
1997 if (group && pg->ppd_conform == PPD_CONFORM_STRICT)
1999 pg->ppd_status = PPD_MISSING_CLOSE_GROUP;
2003 ppd_free(line.buffer);
2006 * Reset language preferences...
2010 if (!cupsFileEOF(fp))
2011 DEBUG_printf(("1_ppdOpen: Premature EOF at %lu...\n",
2012 (unsigned long)cupsFileTell(fp)));
2015 if (pg->ppd_status != PPD_OK)
2018 * Had an error reading the PPD file, cannot continue!
2027 * Update the filters array as needed...
2030 if (!ppd_update_filters(ppd, pg))
2038 * Create the sorted options array and set the option back-pointer for
2039 * each choice and custom option...
2042 ppd->options = cupsArrayNew2((cups_array_func_t)ppd_compare_options, NULL,
2043 (cups_ahash_func_t)ppd_hash_option,
2046 for (i = ppd->num_groups, group = ppd->groups;
2050 for (j = group->num_options, option = group->options;
2054 ppd_coption_t *coption; /* Custom option */
2057 cupsArrayAdd(ppd->options, option);
2059 for (k = 0; k < option->num_choices; k ++)
2060 option->choices[k].option = option;
2062 if ((coption = ppdFindCustomOption(ppd, option->keyword)) != NULL)
2063 coption->option = option;
2068 * Create an array to track the marked choices...
2071 ppd->marked = cupsArrayNew((cups_array_func_t)ppd_compare_choices, NULL);
2074 * Return the PPD file structure...
2080 * Common exit point for errors to save code size...
2085 _cupsStrFree(string);
2086 ppd_free(line.buffer);
2095 * 'ppdOpen()' - Read a PPD file into memory.
2098 ppd_file_t * /* O - PPD file record */
2099 ppdOpen(FILE *fp) /* I - File to read from */
2101 ppd_file_t *ppd; /* PPD file record */
2102 cups_file_t *cf; /* CUPS file */
2106 * Reopen the stdio file as a CUPS file...
2109 if ((cf = cupsFileOpenFd(fileno(fp), "r")) == NULL)
2113 * Load the PPD file using the newer API...
2116 ppd = _ppdOpen(cf, _PPD_LOCALIZATION_DEFAULT);
2119 * Close the CUPS file and return the PPD...
2129 * 'ppdOpen2()' - Read a PPD file into memory.
2131 * @since CUPS 1.2/macOS 10.5@
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 */
2137 return _ppdOpen(fp, _PPD_LOCALIZATION_DEFAULT);
2142 * 'ppdOpenFd()' - Read a PPD file into memory.
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 */
2148 cups_file_t *fp; /* CUPS file pointer */
2149 ppd_file_t *ppd; /* PPD file record */
2150 _ppd_globals_t *pg = _ppdGlobals();
2155 * Set the line number to 0...
2161 * Range check input...
2166 pg->ppd_status = PPD_NULL_FILE;
2172 * Try to open the file and parse it...
2175 if ((fp = cupsFileOpenFd(fd, "r")) != NULL)
2183 pg->ppd_status = PPD_FILE_OPEN_ERROR;
2192 * '_ppdOpenFile()' - Read a PPD file into memory.
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 */
2199 cups_file_t *fp; /* File pointer */
2200 ppd_file_t *ppd; /* PPD file record */
2201 _ppd_globals_t *pg = _ppdGlobals();
2206 * Set the line number to 0...
2212 * Range check input...
2215 if (filename == NULL)
2217 pg->ppd_status = PPD_NULL_FILE;
2223 * Try to open the file and parse it...
2226 if ((fp = cupsFileOpen(filename, "r")) != NULL)
2228 ppd = _ppdOpen(fp, localization);
2234 pg->ppd_status = PPD_FILE_OPEN_ERROR;
2243 * 'ppdOpenFile()' - Read a PPD file into memory.
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 */
2249 return _ppdOpenFile(filename, _PPD_LOCALIZATION_DEFAULT);
2254 * 'ppdSetConformance()' - Set the conformance level for PPD files.
2256 * @since CUPS 1.1.20/macOS 10.4@
2260 ppdSetConformance(ppd_conform_t c) /* I - Conformance level */
2262 _ppd_globals_t *pg = _ppdGlobals();
2266 pg->ppd_conform = c;
2271 * 'ppd_add_attr()' - Add an attribute to the PPD data.
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 */
2281 ppd_attr_t **ptr, /* New array */
2282 *temp; /* New attribute */
2286 * Range check input...
2289 if (ppd == NULL || name == NULL || spec == NULL)
2293 * Create the array as needed...
2296 if (!ppd->sorted_attrs)
2297 ppd->sorted_attrs = cupsArrayNew((cups_array_func_t)ppd_compare_attrs,
2301 * Allocate memory for the new attribute...
2304 if (ppd->num_attrs == 0)
2305 ptr = malloc(sizeof(ppd_attr_t *));
2307 ptr = realloc(ppd->attrs, (size_t)(ppd->num_attrs + 1) * sizeof(ppd_attr_t *));
2313 ptr += ppd->num_attrs;
2315 if ((temp = calloc(1, sizeof(ppd_attr_t))) == NULL)
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;
2332 * Add the attribute to the sorted array...
2335 cupsArrayAdd(ppd->sorted_attrs, temp);
2338 * Return the attribute...
2346 * 'ppd_add_choice()' - Add a choice to an option.
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 */
2353 ppd_choice_t *choice; /* Choice */
2356 if (option->num_choices == 0)
2357 choice = malloc(sizeof(ppd_choice_t));
2359 choice = realloc(option->choices, sizeof(ppd_choice_t) * (size_t)(option->num_choices + 1));
2364 option->choices = choice;
2365 choice += option->num_choices;
2366 option->num_choices ++;
2368 memset(choice, 0, sizeof(ppd_choice_t));
2369 strlcpy(choice->choice, name, sizeof(choice->choice));
2376 * 'ppd_add_size()' - Add a page size.
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 */
2383 ppd_size_t *size; /* Size */
2386 if (ppd->num_sizes == 0)
2387 size = malloc(sizeof(ppd_size_t));
2389 size = realloc(ppd->sizes, sizeof(ppd_size_t) * (size_t)(ppd->num_sizes + 1));
2395 size += ppd->num_sizes;
2398 memset(size, 0, sizeof(ppd_size_t));
2399 strlcpy(size->name, name, sizeof(size->name));
2406 * 'ppd_compare_attrs()' - Compare two attributes.
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 */
2413 return (_cups_strcasecmp(a->name, b->name));
2418 * 'ppd_compare_choices()' - Compare two choices...
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 */
2425 return (strcmp(a->option->keyword, b->option->keyword));
2430 * 'ppd_compare_coptions()' - Compare two custom options.
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 */
2437 return (_cups_strcasecmp(a->keyword, b->keyword));
2442 * 'ppd_compare_options()' - Compare two options.
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 */
2449 return (_cups_strcasecmp(a->keyword, b->keyword));
2454 * 'ppd_decode()' - Decode a string value...
2457 static int /* O - Length of decoded string */
2458 ppd_decode(char *string) /* I - String to decode */
2460 char *inptr, /* Input pointer */
2461 *outptr; /* Output pointer */
2467 while (*inptr != '\0')
2468 if (*inptr == '<' && isxdigit(inptr[1] & 255))
2471 * Convert hex to 8-bit values...
2475 while (isxdigit(*inptr & 255))
2477 if (_cups_isalpha(*inptr))
2478 *outptr = (char)((tolower(*inptr) - 'a' + 10) << 4);
2480 *outptr = (char)((*inptr - '0') << 4);
2484 if (!isxdigit(*inptr & 255))
2487 if (_cups_isalpha(*inptr))
2488 *outptr |= (char)(tolower(*inptr) - 'a' + 10);
2490 *outptr |= (char)(*inptr - '0');
2496 while (*inptr != '>' && *inptr != '\0')
2498 while (*inptr == '>')
2502 *outptr++ = *inptr++;
2506 return ((int)(outptr - string));
2511 * 'ppd_free_filters()' - Free the filters array.
2515 ppd_free_filters(ppd_file_t *ppd) /* I - PPD file */
2517 int i; /* Looping var */
2518 char **filter; /* Current filter */
2521 if (ppd->num_filters > 0)
2523 for (i = ppd->num_filters, filter = ppd->filters; i > 0; i --, filter ++)
2524 _cupsStrFree(*filter);
2526 ppd_free(ppd->filters);
2528 ppd->num_filters = 0;
2529 ppd->filters = NULL;
2535 * 'ppd_free_group()' - Free a single UI group.
2539 ppd_free_group(ppd_group_t *group) /* I - Group to free */
2541 int i; /* Looping var */
2542 ppd_option_t *option; /* Current option */
2543 ppd_group_t *subgroup; /* Current sub-group */
2546 if (group->num_options > 0)
2548 for (i = group->num_options, option = group->options;
2551 ppd_free_option(option);
2553 ppd_free(group->options);
2556 if (group->num_subgroups > 0)
2558 for (i = group->num_subgroups, subgroup = group->subgroups;
2561 ppd_free_group(subgroup);
2563 ppd_free(group->subgroups);
2569 * 'ppd_free_option()' - Free a single option.
2573 ppd_free_option(ppd_option_t *option) /* I - Option to free */
2575 int i; /* Looping var */
2576 ppd_choice_t *choice; /* Current choice */
2579 if (option->num_choices > 0)
2581 for (i = option->num_choices, choice = option->choices;
2585 _cupsStrFree(choice->code);
2588 ppd_free(option->choices);
2594 * 'ppd_get_coption()' - Get a custom option record.
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 */
2601 ppd_coption_t *copt; /* New custom option */
2605 * See if the option already exists...
2608 if ((copt = ppdFindCustomOption(ppd, name)) != NULL)
2612 * Not found, so create the custom option record...
2615 if ((copt = calloc(1, sizeof(ppd_coption_t))) == NULL)
2618 strlcpy(copt->keyword, name, sizeof(copt->keyword));
2620 copt->params = cupsArrayNew((cups_array_func_t)NULL, NULL);
2622 cupsArrayAdd(ppd->coptions, copt);
2625 * Return the new record...
2633 * 'ppd_get_cparam()' - Get a custom parameter record.
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 */
2641 ppd_cparam_t *cparam; /* New custom parameter */
2645 * See if the parameter already exists...
2648 if ((cparam = ppdFindCustomParam(opt, param)) != NULL)
2652 * Not found, so create the custom parameter record...
2655 if ((cparam = calloc(1, sizeof(ppd_cparam_t))) == NULL)
2658 strlcpy(cparam->name, param, sizeof(cparam->name));
2659 strlcpy(cparam->text, text[0] ? text : param, sizeof(cparam->text));
2662 * Add this record to the array...
2665 cupsArrayAdd(opt->params, cparam);
2668 * Return the new record...
2676 * 'ppd_get_group()' - Find or create the named group as needed.
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 */
2686 int i; /* Looping var */
2687 ppd_group_t *group; /* Group */
2690 DEBUG_printf(("7ppd_get_group(ppd=%p, name=\"%s\", text=\"%s\", cg=%p)",
2691 ppd, name, text, pg));
2693 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
2694 if (!strcmp(group->name, name))
2699 DEBUG_printf(("8ppd_get_group: Adding group %s...", name));
2701 if (pg->ppd_conform == PPD_CONFORM_STRICT && strlen(text) >= sizeof(group->text))
2703 pg->ppd_status = PPD_ILLEGAL_TRANSLATION;
2708 if (ppd->num_groups == 0)
2709 group = malloc(sizeof(ppd_group_t));
2711 group = realloc(ppd->groups, (size_t)(ppd->num_groups + 1) * sizeof(ppd_group_t));
2715 pg->ppd_status = PPD_ALLOC_ERROR;
2720 ppd->groups = group;
2721 group += ppd->num_groups;
2724 memset(group, 0, sizeof(ppd_group_t));
2725 strlcpy(group->name, name, sizeof(group->name));
2727 cupsCharsetToUTF8((cups_utf8_t *)group->text, text,
2728 sizeof(group->text), encoding);
2736 * 'ppd_get_option()' - Find or create the named option as needed.
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 */
2743 int i; /* Looping var */
2744 ppd_option_t *option; /* Option */
2747 DEBUG_printf(("7ppd_get_option(group=%p(\"%s\"), name=\"%s\")",
2748 group, group->name, name));
2750 for (i = group->num_options, option = group->options; i > 0; i --, option ++)
2751 if (!strcmp(option->keyword, name))
2756 if (group->num_options == 0)
2757 option = malloc(sizeof(ppd_option_t));
2759 option = realloc(group->options, (size_t)(group->num_options + 1) * sizeof(ppd_option_t));
2764 group->options = option;
2765 option += group->num_options;
2766 group->num_options ++;
2768 memset(option, 0, sizeof(ppd_option_t));
2769 strlcpy(option->keyword, name, sizeof(option->keyword));
2777 * 'ppd_globals_alloc()' - Allocate and initialize global data.
2780 static _ppd_globals_t * /* O - Pointer to global data */
2781 ppd_globals_alloc(void)
2783 return ((_ppd_globals_t *)calloc(1, sizeof(_ppd_globals_t)));
2788 * 'ppd_globals_free()' - Free global data.
2791 #if defined(HAVE_PTHREAD_H) || defined(WIN32)
2793 ppd_globals_free(_ppd_globals_t *pg) /* I - Pointer to global data */
2797 #endif /* HAVE_PTHREAD_H || WIN32 */
2800 #ifdef HAVE_PTHREAD_H
2802 * 'ppd_globals_init()' - Initialize per-thread globals...
2806 ppd_globals_init(void)
2809 * Register the global data for this thread...
2812 pthread_key_create(&ppd_globals_key, (void (*)(void *))ppd_globals_free);
2814 #endif /* HAVE_PTHREAD_H */
2818 * 'ppd_hash_option()' - Generate a hash of the option name...
2821 static int /* O - Hash index */
2822 ppd_hash_option(ppd_option_t *option) /* I - Option */
2824 int hash = 0; /* Hash index */
2825 const char *k; /* Pointer into keyword */
2828 for (hash = option->keyword[0], k = option->keyword + 1; *k;)
2829 hash = 33 * hash + *k++;
2831 return (hash & 511);
2836 * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
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 */
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 */
2865 * Now loop until we have a valid line...
2870 startline = pg->ppd_line + 1;
2874 line->bufsize = 1024;
2875 line->buffer = malloc(1024);
2887 lineptr = line->buffer;
2891 while ((ch = cupsFileGetChar(fp)) != EOF)
2893 if (lineptr >= (line->buffer + line->bufsize - 1))
2896 * Expand the line buffer...
2899 char *temp; /* Temporary line pointer */
2902 line->bufsize += 1024;
2903 if (line->bufsize > 262144)
2906 * Don't allow lines longer than 256k!
2909 pg->ppd_line = startline;
2910 pg->ppd_status = PPD_LINE_TOO_LONG;
2915 temp = realloc(line->buffer, line->bufsize);
2918 pg->ppd_line = startline;
2919 pg->ppd_status = PPD_LINE_TOO_LONG;
2924 lineptr = temp + (lineptr - line->buffer);
2925 line->buffer = temp;
2928 if (ch == '\r' || ch == '\n')
2931 * Line feed or carriage return...
2940 * Check for a trailing line feed...
2943 if ((ch = cupsFilePeekChar(fp)) == EOF)
2950 cupsFileGetChar(fp);
2953 if (lineptr == line->buffer && ignoreblank)
2954 continue; /* Skip blank lines */
2958 if (!endquote) /* Continue for multi-line text */
2963 else if (ch < ' ' && ch != '\t' && pg->ppd_conform == PPD_CONFORM_STRICT)
2966 * Other control characters...
2969 pg->ppd_line = startline;
2970 pg->ppd_status = PPD_ILLEGAL_CHARACTER;
2974 else if (ch != 0x1a)
2977 * Any other character...
2980 *lineptr++ = (char)ch;
2983 if (col > (PPD_MAX_LINE - 1))
2986 * Line is too long...
2989 pg->ppd_line = startline;
2990 pg->ppd_status = PPD_LINE_TOO_LONG;
2995 if (ch == ':' && strncmp(line->buffer, "*%", 2) != 0)
2998 if (ch == '\"' && colon)
2999 endquote = !endquote;
3006 * Didn't finish this quoted string...
3009 while ((ch = cupsFileGetChar(fp)) != EOF)
3012 else if (ch == '\r' || ch == '\n')
3020 * Check for a trailing line feed...
3023 if ((ch = cupsFilePeekChar(fp)) == EOF)
3026 cupsFileGetChar(fp);
3029 else if (ch < ' ' && ch != '\t' && pg->ppd_conform == PPD_CONFORM_STRICT)
3032 * Other control characters...
3035 pg->ppd_line = startline;
3036 pg->ppd_status = PPD_ILLEGAL_CHARACTER;
3040 else if (ch != 0x1a)
3044 if (col > (PPD_MAX_LINE - 1))
3047 * Line is too long...
3050 pg->ppd_line = startline;
3051 pg->ppd_status = PPD_LINE_TOO_LONG;
3061 * Didn't finish this line...
3064 while ((ch = cupsFileGetChar(fp)) != EOF)
3065 if (ch == '\r' || ch == '\n')
3068 * Line feed or carriage return...
3077 * Check for a trailing line feed...
3080 if ((ch = cupsFilePeekChar(fp)) == EOF)
3083 cupsFileGetChar(fp);
3088 else if (ch < ' ' && ch != '\t' && pg->ppd_conform == PPD_CONFORM_STRICT)
3091 * Other control characters...
3094 pg->ppd_line = startline;
3095 pg->ppd_status = PPD_ILLEGAL_CHARACTER;
3099 else if (ch != 0x1a)
3103 if (col > (PPD_MAX_LINE - 1))
3106 * Line is too long...
3109 pg->ppd_line = startline;
3110 pg->ppd_status = PPD_LINE_TOO_LONG;
3117 if (lineptr > line->buffer && lineptr[-1] == '\n')
3122 DEBUG_printf(("9ppd_read: LINE=\"%s\"", line->buffer));
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.
3131 if (!strcmp(line->buffer, "*%APLWORKSET START"))
3134 if (ch == EOF && lineptr == line->buffer)
3142 lineptr = line->buffer + 1;
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? */
3154 startline = pg->ppd_line + 1;
3158 if (!strcmp(line->buffer, "*")) /* (Bad) comment line */
3160 if (pg->ppd_conform == PPD_CONFORM_RELAXED)
3162 startline = pg->ppd_line + 1;
3167 pg->ppd_line = startline;
3168 pg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
3174 if (line->buffer[0] != '*') /* All lines start with an asterisk */
3177 * Allow lines consisting of just whitespace...
3180 for (lineptr = line->buffer; *lineptr; lineptr ++)
3181 if (*lineptr && !_cups_isspace(*lineptr))
3186 pg->ppd_status = PPD_MISSING_ASTERISK;
3189 else if (ignoreblank)
3201 while (*lineptr && *lineptr != ':' && !_cups_isspace(*lineptr))
3203 if (*lineptr <= ' ' || *lineptr > 126 || *lineptr == '/' ||
3204 (keyptr - keyword) >= (PPD_MAX_NAME - 1))
3206 pg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
3210 *keyptr++ = *lineptr++;
3215 if (!strcmp(keyword, "End"))
3218 mask |= PPD_KEYWORD;
3220 if (_cups_isspace(*lineptr))
3223 * Get an option name...
3226 while (_cups_isspace(*lineptr))
3231 while (*lineptr && !_cups_isspace(*lineptr) && *lineptr != ':' &&
3234 if (*lineptr <= ' ' || *lineptr > 126 ||
3235 (optptr - option) >= (PPD_MAX_NAME - 1))
3237 pg->ppd_status = PPD_ILLEGAL_OPTION_KEYWORD;
3241 *optptr++ = *lineptr++;
3246 if (_cups_isspace(*lineptr) && pg->ppd_conform == PPD_CONFORM_STRICT)
3248 pg->ppd_status = PPD_ILLEGAL_WHITESPACE;
3252 while (_cups_isspace(*lineptr))
3257 if (*lineptr == '/')
3260 * Get human-readable text...
3267 while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':')
3269 if (((unsigned char)*lineptr < ' ' && *lineptr != '\t') ||
3270 (textptr - text) >= (PPD_MAX_LINE - 1))
3272 pg->ppd_status = PPD_ILLEGAL_TRANSLATION;
3276 *textptr++ = *lineptr++;
3280 textlen = ppd_decode(text);
3282 if (textlen > PPD_MAX_TEXT && pg->ppd_conform == PPD_CONFORM_STRICT)
3284 pg->ppd_status = PPD_ILLEGAL_TRANSLATION;
3292 if (_cups_isspace(*lineptr) && pg->ppd_conform == PPD_CONFORM_STRICT)
3294 pg->ppd_status = PPD_ILLEGAL_WHITESPACE;
3298 while (_cups_isspace(*lineptr))
3301 if (*lineptr == ':')
3304 * Get string after triming leading and trailing whitespace...
3308 while (_cups_isspace(*lineptr))
3311 strptr = lineptr + strlen(lineptr) - 1;
3312 while (strptr >= lineptr && _cups_isspace(*strptr))
3315 if (*strptr == '\"')
3318 * Quoted string by itself, remove quotes...
3325 *string = _cupsStrAlloc(lineptr);
3337 * 'ppd_update_filters()' - Update the filters array as needed.
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.
3342 * (All for backwards-compatibility)
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 */
3349 ppd_attr_t *attr; /* Current cupsFilter2 value */
3350 char srcsuper[16], /* Source MIME media type */
3352 dstsuper[16], /* Destination MIME media type */
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 */
3361 DEBUG_printf(("4ppd_update_filters(ppd=%p, cg=%p)", ppd, pg));
3364 * See if we have any cupsFilter2 lines...
3367 if ((attr = ppdFindAttr(ppd, "cupsFilter2", NULL)) == NULL)
3369 DEBUG_puts("5ppd_update_filters: No cupsFilter2 keywords present.");
3374 * Yes, free the cupsFilter-defined filters and re-build...
3377 ppd_free_filters(ppd);
3382 * Parse the cupsFilter2 string:
3384 * src/type dst/type cost program
3385 * src/type dst/type cost maxsize(n) program
3388 DEBUG_printf(("5ppd_update_filters: cupsFilter2=\"%s\"", attr->value));
3390 if (sscanf(attr->value, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]",
3391 srcsuper, srctype, dstsuper, dsttype, &cost, program) != 6)
3393 DEBUG_puts("5ppd_update_filters: Bad cupsFilter2 line.");
3394 pg->ppd_status = PPD_BAD_VALUE;
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));
3403 if (!strncmp(program, "maxsize(", 8) &&
3404 (ptr = strchr(program + 8, ')')) != NULL)
3406 DEBUG_puts("5ppd_update_filters: Found maxsize(nnn).");
3409 while (_cups_isspace(*ptr))
3412 _cups_strcpy(program, ptr);
3413 DEBUG_printf(("5ppd_update_filters: New program=\"%s\"", program));
3417 * Convert to cupsFilter format:
3419 * src/type cost program
3422 snprintf(buffer, sizeof(buffer), "%s/%s %d %s", srcsuper, srctype, cost,
3424 DEBUG_printf(("5ppd_update_filters: Adding \"%s\".", buffer));
3427 * Add a cupsFilter-compatible string to the filters array.
3430 if (ppd->num_filters == 0)
3431 filter = malloc(sizeof(char *));
3433 filter = realloc(ppd->filters, sizeof(char *) * (size_t)(ppd->num_filters + 1));
3437 DEBUG_puts("5ppd_update_filters: Out of memory.");
3438 pg->ppd_status = PPD_ALLOC_ERROR;
3443 ppd->filters = filter;
3444 filter += ppd->num_filters;
3445 ppd->num_filters ++;
3447 *filter = _cupsStrAlloc(buffer);
3449 while ((attr = ppdFindNextAttr(ppd, "cupsFilter2", NULL)) != NULL);
3451 DEBUG_puts("5ppd_update_filters: Completed OK.");