2 * PPD file routines for CUPS.
4 * Copyright 2007-2018 by Apple Inc.
5 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more
10 * PostScript is a trademark of Adobe Systems, Inc.
14 * Include necessary headers.
17 #include "cups-private.h"
18 #include "ppd-private.h"
19 #include "debug-internal.h"
26 #define ppd_free(p) if (p) free(p) /* Safe free macro */
28 #define PPD_KEYWORD 1 /* Line contained a keyword */
29 #define PPD_OPTION 2 /* Line contained an option name */
30 #define PPD_TEXT 4 /* Line contained human-readable text */
31 #define PPD_STRING 8 /* Line contained a string or code */
33 #define PPD_HASHSIZE 512 /* Size of hash */
37 * Line buffer structure...
40 typedef struct _ppd_line_s
42 char *buffer
; /* Pointer to buffer */
43 size_t bufsize
; /* Size of the buffer */
51 static _cups_threadkey_t ppd_globals_key
= _CUPS_THREADKEY_INITIALIZER
;
52 /* Thread local storage key */
54 static pthread_once_t ppd_globals_key_once
= PTHREAD_ONCE_INIT
;
55 /* One-time initialization object */
56 #endif /* HAVE_PTHREAD_H */
63 static ppd_attr_t
*ppd_add_attr(ppd_file_t
*ppd
, const char *name
,
64 const char *spec
, const char *text
,
66 static ppd_choice_t
*ppd_add_choice(ppd_option_t
*option
, const char *name
);
67 static ppd_size_t
*ppd_add_size(ppd_file_t
*ppd
, const char *name
);
68 static int ppd_compare_attrs(ppd_attr_t
*a
, ppd_attr_t
*b
);
69 static int ppd_compare_choices(ppd_choice_t
*a
, ppd_choice_t
*b
);
70 static int ppd_compare_coptions(ppd_coption_t
*a
,
72 static int ppd_compare_options(ppd_option_t
*a
, ppd_option_t
*b
);
73 static int ppd_decode(char *string
);
74 static void ppd_free_filters(ppd_file_t
*ppd
);
75 static void ppd_free_group(ppd_group_t
*group
);
76 static void ppd_free_option(ppd_option_t
*option
);
77 static ppd_coption_t
*ppd_get_coption(ppd_file_t
*ppd
, const char *name
);
78 static ppd_cparam_t
*ppd_get_cparam(ppd_coption_t
*opt
,
81 static ppd_group_t
*ppd_get_group(ppd_file_t
*ppd
, const char *name
,
82 const char *text
, _ppd_globals_t
*pg
,
83 cups_encoding_t encoding
);
84 static ppd_option_t
*ppd_get_option(ppd_group_t
*group
, const char *name
);
85 static _ppd_globals_t
*ppd_globals_alloc(void);
86 #if defined(HAVE_PTHREAD_H) || defined(_WIN32)
87 static void ppd_globals_free(_ppd_globals_t
*g
);
88 #endif /* HAVE_PTHREAD_H || _WIN32 */
90 static void ppd_globals_init(void);
91 #endif /* HAVE_PTHREAD_H */
92 static int ppd_hash_option(ppd_option_t
*option
);
93 static int ppd_read(cups_file_t
*fp
, _ppd_line_t
*line
,
94 char *keyword
, char *option
, char *text
,
95 char **string
, int ignoreblank
,
97 static int ppd_update_filters(ppd_file_t
*ppd
,
102 * 'ppdClose()' - Free all memory used by the PPD file.
106 ppdClose(ppd_file_t
*ppd
) /* I - PPD file record */
108 int i
; /* Looping var */
109 ppd_emul_t
*emul
; /* Current emulation */
110 ppd_group_t
*group
; /* Current group */
111 char **font
; /* Current font */
112 ppd_attr_t
**attr
; /* Current attribute */
113 ppd_coption_t
*coption
; /* Current custom option */
114 ppd_cparam_t
*cparam
; /* Current custom parameter */
118 * Range check arguments...
125 * Free all strings at the top level...
128 _cupsStrFree(ppd
->lang_encoding
);
129 _cupsStrFree(ppd
->nickname
);
132 _cupsStrFree(ppd
->jcl_begin
);
133 _cupsStrFree(ppd
->jcl_end
);
134 _cupsStrFree(ppd
->jcl_ps
);
137 * Free any emulations...
140 if (ppd
->num_emulations
> 0)
142 for (i
= ppd
->num_emulations
, emul
= ppd
->emulations
; i
> 0; i
--, emul
++)
144 _cupsStrFree(emul
->start
);
145 _cupsStrFree(emul
->stop
);
148 ppd_free(ppd
->emulations
);
152 * Free any UI groups, subgroups, and options...
155 if (ppd
->num_groups
> 0)
157 for (i
= ppd
->num_groups
, group
= ppd
->groups
; i
> 0; i
--, group
++)
158 ppd_free_group(group
);
160 ppd_free(ppd
->groups
);
163 cupsArrayDelete(ppd
->options
);
164 cupsArrayDelete(ppd
->marked
);
167 * Free any page sizes...
170 if (ppd
->num_sizes
> 0)
171 ppd_free(ppd
->sizes
);
174 * Free any constraints...
177 if (ppd
->num_consts
> 0)
178 ppd_free(ppd
->consts
);
181 * Free any filters...
184 ppd_free_filters(ppd
);
190 if (ppd
->num_fonts
> 0)
192 for (i
= ppd
->num_fonts
, font
= ppd
->fonts
; i
> 0; i
--, font
++)
195 ppd_free(ppd
->fonts
);
199 * Free any profiles...
202 if (ppd
->num_profiles
> 0)
203 ppd_free(ppd
->profiles
);
206 * Free any attributes...
209 if (ppd
->num_attrs
> 0)
211 for (i
= ppd
->num_attrs
, attr
= ppd
->attrs
; i
> 0; i
--, attr
++)
213 _cupsStrFree((*attr
)->value
);
217 ppd_free(ppd
->attrs
);
220 cupsArrayDelete(ppd
->sorted_attrs
);
223 * Free custom options...
226 for (coption
= (ppd_coption_t
*)cupsArrayFirst(ppd
->coptions
);
228 coption
= (ppd_coption_t
*)cupsArrayNext(ppd
->coptions
))
230 for (cparam
= (ppd_cparam_t
*)cupsArrayFirst(coption
->params
);
232 cparam
= (ppd_cparam_t
*)cupsArrayNext(coption
->params
))
234 switch (cparam
->type
)
236 case PPD_CUSTOM_PASSCODE
:
237 case PPD_CUSTOM_PASSWORD
:
238 case PPD_CUSTOM_STRING
:
239 _cupsStrFree(cparam
->current
.custom_string
);
249 cupsArrayDelete(coption
->params
);
254 cupsArrayDelete(ppd
->coptions
);
257 * Free constraints...
260 if (ppd
->cups_uiconstraints
)
262 _ppd_cups_uiconsts_t
*consts
; /* Current constraints */
265 for (consts
= (_ppd_cups_uiconsts_t
*)cupsArrayFirst(ppd
->cups_uiconstraints
);
267 consts
= (_ppd_cups_uiconsts_t
*)cupsArrayNext(ppd
->cups_uiconstraints
))
269 free(consts
->constraints
);
273 cupsArrayDelete(ppd
->cups_uiconstraints
);
277 * Free any PPD cache/mapping data...
281 _ppdCacheDestroy(ppd
->cache
);
284 * Free the whole record...
292 * 'ppdErrorString()' - Returns the text associated with a status.
294 * @since CUPS 1.1.19/macOS 10.3@
297 const char * /* O - Status string */
298 ppdErrorString(ppd_status_t status
) /* I - PPD status */
300 static const char * const messages
[] =/* Status messages */
303 _("Unable to open PPD file"),
304 _("NULL PPD file pointer"),
305 _("Memory allocation error"),
306 _("Missing PPD-Adobe-4.x header"),
307 _("Missing value string"),
310 _("OpenGroup without a CloseGroup first"),
311 _("Bad OpenUI/JCLOpenUI"),
312 _("OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"),
313 _("Bad OrderDependency"),
314 _("Bad UIConstraints"),
315 _("Missing asterisk in column 1"),
316 _("Line longer than the maximum allowed (255 characters)"),
317 _("Illegal control character"),
318 _("Illegal main keyword string"),
319 _("Illegal option keyword string"),
320 _("Illegal translation string"),
321 _("Illegal whitespace character"),
322 _("Bad custom parameter"),
323 _("Missing option keyword"),
324 _("Bad value string"),
325 _("Missing CloseGroup"),
326 _("Bad CloseUI/JCLCloseUI"),
327 _("Missing CloseUI/JCLCloseUI")
331 if (status
< PPD_OK
|| status
>= PPD_MAX_STATUS
)
332 return (_cupsLangString(cupsLangDefault(), _("Unknown")));
334 return (_cupsLangString(cupsLangDefault(), messages
[status
]));
339 * '_ppdGetEncoding()' - Get the CUPS encoding value for the given
343 cups_encoding_t
/* O - CUPS encoding value */
344 _ppdGetEncoding(const char *name
) /* I - LanguageEncoding string */
346 if (!_cups_strcasecmp(name
, "ISOLatin1"))
347 return (CUPS_ISO8859_1
);
348 else if (!_cups_strcasecmp(name
, "ISOLatin2"))
349 return (CUPS_ISO8859_2
);
350 else if (!_cups_strcasecmp(name
, "ISOLatin5"))
351 return (CUPS_ISO8859_5
);
352 else if (!_cups_strcasecmp(name
, "JIS83-RKSJ"))
353 return (CUPS_JIS_X0213
);
354 else if (!_cups_strcasecmp(name
, "MacStandard"))
355 return (CUPS_MAC_ROMAN
);
356 else if (!_cups_strcasecmp(name
, "WindowsANSI"))
357 return (CUPS_WINDOWS_1252
);
364 * '_ppdGlobals()' - Return a pointer to thread local storage
367 _ppd_globals_t
* /* O - Pointer to global data */
370 _ppd_globals_t
*pg
; /* Pointer to global data */
373 #ifdef HAVE_PTHREAD_H
375 * Initialize the global data exactly once...
378 pthread_once(&ppd_globals_key_once
, ppd_globals_init
);
379 #endif /* HAVE_PTHREAD_H */
382 * See if we have allocated the data yet...
385 if ((pg
= (_ppd_globals_t
*)_cupsThreadGetData(ppd_globals_key
)) == NULL
)
388 * No, allocate memory as set the pointer for the key...
391 if ((pg
= ppd_globals_alloc()) != NULL
)
392 _cupsThreadSetData(ppd_globals_key
, pg
);
396 * Return the pointer to the data...
404 * 'ppdLastError()' - Return the status from the last ppdOpen*().
406 * @since CUPS 1.1.19/macOS 10.3@
409 ppd_status_t
/* O - Status code */
410 ppdLastError(int *line
) /* O - Line number */
412 _ppd_globals_t
*pg
= _ppdGlobals();
417 *line
= pg
->ppd_line
;
419 return (pg
->ppd_status
);
424 * '_ppdOpen()' - Read a PPD file into memory.
426 * @since CUPS 1.2/macOS 10.5@
429 ppd_file_t
* /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
431 cups_file_t
*fp
, /* I - File to read from */
432 _ppd_localization_t localization
) /* I - Localization to load */
434 int i
, j
, k
; /* Looping vars */
435 int count
; /* Temporary count */
436 _ppd_line_t line
; /* Line buffer */
437 ppd_file_t
*ppd
; /* PPD file record */
438 ppd_group_t
*group
, /* Current group */
439 *subgroup
; /* Current sub-group */
440 ppd_option_t
*option
; /* Current option */
441 ppd_choice_t
*choice
; /* Current choice */
442 ppd_const_t
*constraint
; /* Current constraint */
443 ppd_size_t
*size
; /* Current page size */
444 int mask
; /* Line data mask */
445 char keyword
[PPD_MAX_NAME
],
446 /* Keyword from file */
448 /* Option from file */
450 /* Human-readable text from file */
451 *string
, /* Code/text from file */
452 *sptr
, /* Pointer into string */
453 *nameptr
, /* Pointer into name */
454 *temp
, /* Temporary string pointer */
455 **tempfonts
; /* Temporary fonts pointer */
456 float order
; /* Order dependency number */
457 ppd_section_t section
; /* Order dependency section */
458 ppd_profile_t
*profile
; /* Pointer to color profile */
459 char **filter
; /* Pointer to filter */
460 struct lconv
*loc
; /* Locale data */
461 int ui_keyword
; /* Is this line a UI keyword? */
462 cups_lang_t
*lang
; /* Language data */
463 cups_encoding_t encoding
; /* Encoding of PPD file */
464 _ppd_globals_t
*pg
= _ppdGlobals();
466 char custom_name
[PPD_MAX_NAME
];
467 /* CustomFoo attribute name */
468 ppd_attr_t
*custom_attr
; /* CustomFoo attribute */
469 char ll
[7], /* Base language + '.' */
470 ll_CC
[7]; /* Language w/country + '.' */
471 size_t ll_len
= 0, /* Base language length */
472 ll_CC_len
= 0; /* Language w/country length */
473 static const char * const ui_keywords
[] =
475 #ifdef CUPS_USE_FULL_UI_KEYWORDS_LIST
477 * Adobe defines some 41 keywords as "UI", meaning that they are
478 * user interface elements and that they should be treated as such
479 * even if the PPD creator doesn't use Open/CloseUI around them.
481 * Since this can cause previously invisible options to appear and
482 * confuse users, the default is to only treat the PageSize and
483 * PageRegion keywords this way.
485 /* Boolean keywords */
495 /* PickOne keywords */
508 "JCLFrameBufferSize",
529 #else /* !CUPS_USE_FULL_UI_KEYWORDS_LIST */
532 #endif /* CUPS_USE_FULL_UI_KEYWORDS_LIST */
534 static const char * const color_keywords
[] = /* Keywords associated with color profiles */
541 DEBUG_printf(("_ppdOpen(fp=%p)", fp
));
544 * Default to "OK" status...
547 pg
->ppd_status
= PPD_OK
;
551 * Range check input...
556 pg
->ppd_status
= PPD_NULL_FILE
;
561 * If only loading a single localization set up the strings to match...
564 if (localization
== _PPD_LOCALIZATION_DEFAULT
)
566 if ((lang
= cupsLangDefault()) == NULL
)
569 snprintf(ll_CC
, sizeof(ll_CC
), "%s.", lang
->language
);
572 * <rdar://problem/22130168>
573 * <rdar://problem/27245567>
575 * Need to use a different base language for some locales...
578 if (!strcmp(lang
->language
, "zh_HK"))
579 { /* Traditional Chinese + variants */
580 strlcpy(ll_CC
, "zh_TW.", sizeof(ll_CC
));
581 strlcpy(ll
, "zh_", sizeof(ll
));
583 else if (!strncmp(lang
->language
, "zh", 2))
584 strlcpy(ll
, "zh_", sizeof(ll
)); /* Any Chinese variant */
585 else if (!strncmp(lang
->language
, "jp", 2))
586 { /* Any Japanese variant */
587 strlcpy(ll_CC
, "ja", sizeof(ll_CC
));
588 strlcpy(ll
, "jp", sizeof(ll
));
590 else if (!strncmp(lang
->language
, "nb", 2) || !strncmp(lang
->language
, "no", 2))
591 { /* Any Norwegian variant */
592 strlcpy(ll_CC
, "nb", sizeof(ll_CC
));
593 strlcpy(ll
, "no", sizeof(ll
));
596 snprintf(ll
, sizeof(ll
), "%2.2s.", lang
->language
);
598 ll_CC_len
= strlen(ll_CC
);
601 DEBUG_printf(("2_ppdOpen: Loading localizations matching \"%s\" and \"%s\"",
606 * Grab the first line and make sure it reads '*PPD-Adobe: "major.minor"'...
612 mask
= ppd_read(fp
, &line
, keyword
, name
, text
, &string
, 0, pg
);
614 DEBUG_printf(("2_ppdOpen: mask=%x, keyword=\"%s\"...", mask
, keyword
));
617 strcmp(keyword
, "PPD-Adobe") ||
618 string
== NULL
|| string
[0] != '4')
621 * Either this is not a PPD file, or it is not a 4.x PPD file.
624 if (pg
->ppd_status
== PPD_OK
)
625 pg
->ppd_status
= PPD_MISSING_PPDADOBE4
;
627 _cupsStrFree(string
);
628 ppd_free(line
.buffer
);
633 DEBUG_printf(("2_ppdOpen: keyword=%s, string=%p", keyword
, string
));
635 _cupsStrFree(string
);
638 * Allocate memory for the PPD file record...
641 if ((ppd
= calloc(1, sizeof(ppd_file_t
))) == NULL
)
643 pg
->ppd_status
= PPD_ALLOC_ERROR
;
645 _cupsStrFree(string
);
646 ppd_free(line
.buffer
);
651 ppd
->language_level
= 2;
652 ppd
->color_device
= 0;
653 ppd
->colorspace
= PPD_CS_N
;
654 ppd
->landscape
= -90;
655 ppd
->coptions
= cupsArrayNew((cups_array_func_t
)ppd_compare_coptions
,
659 * Read lines from the PPD file and add them to the file record...
667 encoding
= CUPS_ISO8859_1
;
670 while ((mask
= ppd_read(fp
, &line
, keyword
, name
, text
, &string
, 1, pg
)) != 0)
672 DEBUG_printf(("2_ppdOpen: mask=%x, keyword=\"%s\", name=\"%s\", "
673 "text=\"%s\", string=%d chars...", mask
, keyword
, name
, text
,
674 string
? (int)strlen(string
) : 0));
676 if (strncmp(keyword
, "Default", 7) && !string
&&
677 pg
->ppd_conform
!= PPD_CONFORM_RELAXED
)
680 * Need a string value!
683 pg
->ppd_status
= PPD_MISSING_VALUE
;
691 * Certain main keywords (as defined by the PPD spec) may be used
692 * without the usual OpenUI/CloseUI stuff. Presumably this is just
693 * so that Adobe wouldn't completely break compatibility with PPD
694 * files prior to v4.0 of the spec, but it is hopelessly
695 * inconsistent... Catch these main keywords and automatically
696 * create the corresponding option, as needed...
702 * Previous line was a UI keyword...
710 * If we are filtering out keyword localizations, see if this line needs to
714 if (localization
!= _PPD_LOCALIZATION_ALL
&&
715 (temp
= strchr(keyword
, '.')) != NULL
&&
716 ((temp
- keyword
) == 2 || (temp
- keyword
) == 5) &&
717 _cups_isalpha(keyword
[0]) &&
718 _cups_isalpha(keyword
[1]) &&
719 (keyword
[2] == '.' ||
720 (keyword
[2] == '_' && _cups_isalpha(keyword
[3]) &&
721 _cups_isalpha(keyword
[4]) && keyword
[5] == '.')))
723 if (localization
== _PPD_LOCALIZATION_NONE
||
724 (localization
== _PPD_LOCALIZATION_DEFAULT
&&
725 strncmp(ll_CC
, keyword
, ll_CC_len
) &&
726 strncmp(ll
, keyword
, ll_len
)))
728 DEBUG_printf(("2_ppdOpen: Ignoring localization: \"%s\"\n", keyword
));
731 else if (localization
== _PPD_LOCALIZATION_ICC_PROFILES
)
734 * Only load localizations for the color profile related keywords...
738 i
< (int)(sizeof(color_keywords
) / sizeof(color_keywords
[0]));
741 if (!_cups_strcasecmp(temp
, color_keywords
[i
]))
745 if (i
>= (int)(sizeof(color_keywords
) / sizeof(color_keywords
[0])))
747 DEBUG_printf(("2_ppdOpen: Ignoring localization: \"%s\"\n", keyword
));
753 if (option
== NULL
&&
754 (mask
& (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
)) ==
755 (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
))
757 for (i
= 0; i
< (int)(sizeof(ui_keywords
) / sizeof(ui_keywords
[0])); i
++)
758 if (!strcmp(keyword
, ui_keywords
[i
]))
761 if (i
< (int)(sizeof(ui_keywords
) / sizeof(ui_keywords
[0])))
764 * Create the option in the appropriate group...
769 DEBUG_printf(("2_ppdOpen: FOUND ADOBE UI KEYWORD %s WITHOUT OPENUI!",
774 if ((group
= ppd_get_group(ppd
, "General", _("General"), pg
,
778 DEBUG_printf(("2_ppdOpen: Adding to group %s...", group
->text
));
779 option
= ppd_get_option(group
, keyword
);
783 option
= ppd_get_option(group
, keyword
);
787 pg
->ppd_status
= PPD_ALLOC_ERROR
;
793 * Now fill in the initial information for the option...
796 if (!strncmp(keyword
, "JCL", 3))
797 option
->section
= PPD_ORDER_JCL
;
799 option
->section
= PPD_ORDER_ANY
;
801 option
->order
= 10.0f
;
804 option
->ui
= PPD_UI_BOOLEAN
;
806 option
->ui
= PPD_UI_PICKONE
;
808 for (j
= 0; j
< ppd
->num_attrs
; j
++)
809 if (!strncmp(ppd
->attrs
[j
]->name
, "Default", 7) &&
810 !strcmp(ppd
->attrs
[j
]->name
+ 7, keyword
) &&
811 ppd
->attrs
[j
]->value
)
813 DEBUG_printf(("2_ppdOpen: Setting Default%s to %s via attribute...",
814 option
->keyword
, ppd
->attrs
[j
]->value
));
815 strlcpy(option
->defchoice
, ppd
->attrs
[j
]->value
,
816 sizeof(option
->defchoice
));
820 if (!strcmp(keyword
, "PageSize"))
821 strlcpy(option
->text
, _("Media Size"), sizeof(option
->text
));
822 else if (!strcmp(keyword
, "MediaType"))
823 strlcpy(option
->text
, _("Media Type"), sizeof(option
->text
));
824 else if (!strcmp(keyword
, "InputSlot"))
825 strlcpy(option
->text
, _("Media Source"), sizeof(option
->text
));
826 else if (!strcmp(keyword
, "ColorModel"))
827 strlcpy(option
->text
, _("Output Mode"), sizeof(option
->text
));
828 else if (!strcmp(keyword
, "Resolution"))
829 strlcpy(option
->text
, _("Resolution"), sizeof(option
->text
));
831 strlcpy(option
->text
, keyword
, sizeof(option
->text
));
835 if (!strcmp(keyword
, "LanguageLevel"))
836 ppd
->language_level
= atoi(string
);
837 else if (!strcmp(keyword
, "LanguageEncoding"))
840 * Say all PPD files are UTF-8, since we convert to UTF-8...
843 ppd
->lang_encoding
= _cupsStrAlloc("UTF-8");
844 encoding
= _ppdGetEncoding(string
);
846 else if (!strcmp(keyword
, "LanguageVersion"))
847 ppd
->lang_version
= string
;
848 else if (!strcmp(keyword
, "Manufacturer"))
849 ppd
->manufacturer
= string
;
850 else if (!strcmp(keyword
, "ModelName"))
851 ppd
->modelname
= string
;
852 else if (!strcmp(keyword
, "Protocols"))
853 ppd
->protocols
= string
;
854 else if (!strcmp(keyword
, "PCFileName"))
855 ppd
->pcfilename
= string
;
856 else if (!strcmp(keyword
, "NickName"))
858 if (encoding
!= CUPS_UTF8
)
860 cups_utf8_t utf8
[256]; /* UTF-8 version of NickName */
863 cupsCharsetToUTF8(utf8
, string
, sizeof(utf8
), encoding
);
864 ppd
->nickname
= _cupsStrAlloc((char *)utf8
);
867 ppd
->nickname
= _cupsStrAlloc(string
);
869 else if (!strcmp(keyword
, "Product"))
870 ppd
->product
= string
;
871 else if (!strcmp(keyword
, "ShortNickName"))
872 ppd
->shortnickname
= string
;
873 else if (!strcmp(keyword
, "TTRasterizer"))
874 ppd
->ttrasterizer
= string
;
875 else if (!strcmp(keyword
, "JCLBegin"))
877 ppd
->jcl_begin
= _cupsStrAlloc(string
);
878 ppd_decode(ppd
->jcl_begin
); /* Decode quoted string */
880 else if (!strcmp(keyword
, "JCLEnd"))
882 ppd
->jcl_end
= _cupsStrAlloc(string
);
883 ppd_decode(ppd
->jcl_end
); /* Decode quoted string */
885 else if (!strcmp(keyword
, "JCLToPSInterpreter"))
887 ppd
->jcl_ps
= _cupsStrAlloc(string
);
888 ppd_decode(ppd
->jcl_ps
); /* Decode quoted string */
890 else if (!strcmp(keyword
, "AccurateScreensSupport"))
891 ppd
->accurate_screens
= !strcmp(string
, "True");
892 else if (!strcmp(keyword
, "ColorDevice"))
893 ppd
->color_device
= !strcmp(string
, "True");
894 else if (!strcmp(keyword
, "ContoneOnly"))
895 ppd
->contone_only
= !strcmp(string
, "True");
896 else if (!strcmp(keyword
, "cupsFlipDuplex"))
897 ppd
->flip_duplex
= !strcmp(string
, "True");
898 else if (!strcmp(keyword
, "cupsManualCopies"))
899 ppd
->manual_copies
= !strcmp(string
, "True");
900 else if (!strcmp(keyword
, "cupsModelNumber"))
901 ppd
->model_number
= atoi(string
);
902 else if (!strcmp(keyword
, "cupsColorProfile"))
904 if (ppd
->num_profiles
== 0)
905 profile
= malloc(sizeof(ppd_profile_t
));
907 profile
= realloc(ppd
->profiles
, sizeof(ppd_profile_t
) * (size_t)(ppd
->num_profiles
+ 1));
911 pg
->ppd_status
= PPD_ALLOC_ERROR
;
916 ppd
->profiles
= profile
;
917 profile
+= ppd
->num_profiles
;
918 ppd
->num_profiles
++;
920 memset(profile
, 0, sizeof(ppd_profile_t
));
921 strlcpy(profile
->resolution
, name
, sizeof(profile
->resolution
));
922 strlcpy(profile
->media_type
, text
, sizeof(profile
->media_type
));
924 profile
->density
= (float)_cupsStrScand(string
, &sptr
, loc
);
925 profile
->gamma
= (float)_cupsStrScand(sptr
, &sptr
, loc
);
926 profile
->matrix
[0][0] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
927 profile
->matrix
[0][1] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
928 profile
->matrix
[0][2] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
929 profile
->matrix
[1][0] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
930 profile
->matrix
[1][1] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
931 profile
->matrix
[1][2] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
932 profile
->matrix
[2][0] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
933 profile
->matrix
[2][1] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
934 profile
->matrix
[2][2] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
936 else if (!strcmp(keyword
, "cupsFilter"))
938 if (ppd
->num_filters
== 0)
939 filter
= malloc(sizeof(char *));
941 filter
= realloc(ppd
->filters
, sizeof(char *) * (size_t)(ppd
->num_filters
+ 1));
945 pg
->ppd_status
= PPD_ALLOC_ERROR
;
950 ppd
->filters
= filter
;
951 filter
+= ppd
->num_filters
;
955 * Retain a copy of the filter string...
958 *filter
= _cupsStrRetain(string
);
960 else if (!strcmp(keyword
, "Throughput"))
961 ppd
->throughput
= atoi(string
);
962 else if (!strcmp(keyword
, "Font"))
965 * Add this font to the list of available fonts...
968 if (ppd
->num_fonts
== 0)
969 tempfonts
= (char **)malloc(sizeof(char *));
971 tempfonts
= (char **)realloc(ppd
->fonts
, sizeof(char *) * (size_t)(ppd
->num_fonts
+ 1));
973 if (tempfonts
== NULL
)
975 pg
->ppd_status
= PPD_ALLOC_ERROR
;
980 ppd
->fonts
= tempfonts
;
981 ppd
->fonts
[ppd
->num_fonts
] = _cupsStrAlloc(name
);
984 else if (!strncmp(keyword
, "ParamCustom", 11))
986 ppd_coption_t
*coption
; /* Custom option */
987 ppd_cparam_t
*cparam
; /* Custom parameter */
988 int corder
; /* Order number */
989 char ctype
[33], /* Data type */
990 cminimum
[65], /* Minimum value */
991 cmaximum
[65]; /* Maximum value */
995 * Get the custom option and parameter...
998 if ((coption
= ppd_get_coption(ppd
, keyword
+ 11)) == NULL
)
1000 pg
->ppd_status
= PPD_ALLOC_ERROR
;
1005 if ((cparam
= ppd_get_cparam(coption
, name
, text
)) == NULL
)
1007 pg
->ppd_status
= PPD_ALLOC_ERROR
;
1013 * Get the parameter data...
1017 sscanf(string
, "%d%32s%64s%64s", &corder
, ctype
, cminimum
,
1020 pg
->ppd_status
= PPD_BAD_CUSTOM_PARAM
;
1025 cparam
->order
= corder
;
1027 if (!strcmp(ctype
, "curve"))
1029 cparam
->type
= PPD_CUSTOM_CURVE
;
1030 cparam
->minimum
.custom_curve
= (float)_cupsStrScand(cminimum
, NULL
, loc
);
1031 cparam
->maximum
.custom_curve
= (float)_cupsStrScand(cmaximum
, NULL
, loc
);
1033 else if (!strcmp(ctype
, "int"))
1035 cparam
->type
= PPD_CUSTOM_INT
;
1036 cparam
->minimum
.custom_int
= atoi(cminimum
);
1037 cparam
->maximum
.custom_int
= atoi(cmaximum
);
1039 else if (!strcmp(ctype
, "invcurve"))
1041 cparam
->type
= PPD_CUSTOM_INVCURVE
;
1042 cparam
->minimum
.custom_invcurve
= (float)_cupsStrScand(cminimum
, NULL
, loc
);
1043 cparam
->maximum
.custom_invcurve
= (float)_cupsStrScand(cmaximum
, NULL
, loc
);
1045 else if (!strcmp(ctype
, "passcode"))
1047 cparam
->type
= PPD_CUSTOM_PASSCODE
;
1048 cparam
->minimum
.custom_passcode
= atoi(cminimum
);
1049 cparam
->maximum
.custom_passcode
= atoi(cmaximum
);
1051 else if (!strcmp(ctype
, "password"))
1053 cparam
->type
= PPD_CUSTOM_PASSWORD
;
1054 cparam
->minimum
.custom_password
= atoi(cminimum
);
1055 cparam
->maximum
.custom_password
= atoi(cmaximum
);
1057 else if (!strcmp(ctype
, "points"))
1059 cparam
->type
= PPD_CUSTOM_POINTS
;
1060 cparam
->minimum
.custom_points
= (float)_cupsStrScand(cminimum
, NULL
, loc
);
1061 cparam
->maximum
.custom_points
= (float)_cupsStrScand(cmaximum
, NULL
, loc
);
1063 else if (!strcmp(ctype
, "real"))
1065 cparam
->type
= PPD_CUSTOM_REAL
;
1066 cparam
->minimum
.custom_real
= (float)_cupsStrScand(cminimum
, NULL
, loc
);
1067 cparam
->maximum
.custom_real
= (float)_cupsStrScand(cmaximum
, NULL
, loc
);
1069 else if (!strcmp(ctype
, "string"))
1071 cparam
->type
= PPD_CUSTOM_STRING
;
1072 cparam
->minimum
.custom_string
= atoi(cminimum
);
1073 cparam
->maximum
.custom_string
= atoi(cmaximum
);
1077 pg
->ppd_status
= PPD_BAD_CUSTOM_PARAM
;
1083 * Now special-case for CustomPageSize...
1086 if (!strcmp(coption
->keyword
, "PageSize"))
1088 if (!strcmp(name
, "Width"))
1090 ppd
->custom_min
[0] = cparam
->minimum
.custom_points
;
1091 ppd
->custom_max
[0] = cparam
->maximum
.custom_points
;
1093 else if (!strcmp(name
, "Height"))
1095 ppd
->custom_min
[1] = cparam
->minimum
.custom_points
;
1096 ppd
->custom_max
[1] = cparam
->maximum
.custom_points
;
1100 else if (!strcmp(keyword
, "HWMargins"))
1102 for (i
= 0, sptr
= string
; i
< 4; i
++)
1103 ppd
->custom_margins
[i
] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
1105 else if (!strncmp(keyword
, "Custom", 6) && !strcmp(name
, "True") && !option
)
1107 ppd_option_t
*custom_option
; /* Custom option */
1109 DEBUG_puts("2_ppdOpen: Processing Custom option...");
1112 * Get the option and custom option...
1115 if (!ppd_get_coption(ppd
, keyword
+ 6))
1117 pg
->ppd_status
= PPD_ALLOC_ERROR
;
1122 if (option
&& !_cups_strcasecmp(option
->keyword
, keyword
+ 6))
1123 custom_option
= option
;
1125 custom_option
= ppdFindOption(ppd
, keyword
+ 6);
1130 * Add the "custom" option...
1133 if ((choice
= ppdFindChoice(custom_option
, "Custom")) == NULL
)
1134 if ((choice
= ppd_add_choice(custom_option
, "Custom")) == NULL
)
1136 DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
1138 pg
->ppd_status
= PPD_ALLOC_ERROR
;
1143 strlcpy(choice
->text
, text
[0] ? text
: _("Custom"),
1144 sizeof(choice
->text
));
1146 choice
->code
= _cupsStrAlloc(string
);
1148 if (custom_option
->section
== PPD_ORDER_JCL
)
1149 ppd_decode(choice
->code
);
1153 * Now process custom page sizes specially...
1156 if (!strcmp(keyword
, "CustomPageSize"))
1159 * Add a "Custom" page size entry...
1162 ppd
->variable_sizes
= 1;
1164 ppd_add_size(ppd
, "Custom");
1166 if (option
&& !_cups_strcasecmp(option
->keyword
, "PageRegion"))
1167 custom_option
= option
;
1169 custom_option
= ppdFindOption(ppd
, "PageRegion");
1173 if ((choice
= ppdFindChoice(custom_option
, "Custom")) == NULL
)
1174 if ((choice
= ppd_add_choice(custom_option
, "Custom")) == NULL
)
1176 DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
1178 pg
->ppd_status
= PPD_ALLOC_ERROR
;
1183 strlcpy(choice
->text
, text
[0] ? text
: _("Custom"),
1184 sizeof(choice
->text
));
1188 else if (!strcmp(keyword
, "LandscapeOrientation"))
1190 if (!strcmp(string
, "Minus90"))
1191 ppd
->landscape
= -90;
1192 else if (!strcmp(string
, "Plus90"))
1193 ppd
->landscape
= 90;
1195 else if (!strcmp(keyword
, "Emulators") && string
)
1197 for (count
= 1, sptr
= string
; sptr
!= NULL
;)
1198 if ((sptr
= strchr(sptr
, ' ')) != NULL
)
1201 while (*sptr
== ' ')
1205 ppd
->num_emulations
= count
;
1206 if ((ppd
->emulations
= calloc((size_t)count
, sizeof(ppd_emul_t
))) == NULL
)
1208 pg
->ppd_status
= PPD_ALLOC_ERROR
;
1213 for (i
= 0, sptr
= string
; i
< count
; i
++)
1215 for (nameptr
= ppd
->emulations
[i
].name
;
1216 *sptr
!= '\0' && *sptr
!= ' ';
1218 if (nameptr
< (ppd
->emulations
[i
].name
+ sizeof(ppd
->emulations
[i
].name
) - 1))
1223 while (*sptr
== ' ')
1227 else if (!strncmp(keyword
, "StartEmulator_", 14))
1231 for (i
= 0; i
< ppd
->num_emulations
; i
++)
1232 if (!strcmp(keyword
+ 14, ppd
->emulations
[i
].name
))
1234 ppd
->emulations
[i
].start
= string
;
1238 else if (!strncmp(keyword
, "StopEmulator_", 13))
1242 for (i
= 0; i
< ppd
->num_emulations
; i
++)
1243 if (!strcmp(keyword
+ 13, ppd
->emulations
[i
].name
))
1245 ppd
->emulations
[i
].stop
= string
;
1249 else if (!strcmp(keyword
, "JobPatchFile"))
1252 * CUPS STR #3421: Check for "*JobPatchFile: int: string"
1255 if (isdigit(*string
& 255))
1257 for (sptr
= string
+ 1; isdigit(*sptr
& 255); sptr
++);
1262 * Found "*JobPatchFile: int: string"...
1265 pg
->ppd_status
= PPD_BAD_VALUE
;
1271 if (!name
[0] && pg
->ppd_conform
== PPD_CONFORM_STRICT
)
1274 * Found "*JobPatchFile: string"...
1277 pg
->ppd_status
= PPD_MISSING_OPTION_KEYWORD
;
1282 if (ppd
->patches
== NULL
)
1283 ppd
->patches
= strdup(string
);
1286 temp
= realloc(ppd
->patches
, strlen(ppd
->patches
) +
1287 strlen(string
) + 1);
1290 pg
->ppd_status
= PPD_ALLOC_ERROR
;
1295 ppd
->patches
= temp
;
1297 memcpy(ppd
->patches
+ strlen(ppd
->patches
), string
, strlen(string
) + 1);
1300 else if (!strcmp(keyword
, "OpenUI"))
1303 * Don't allow nesting of options...
1306 if (option
&& pg
->ppd_conform
== PPD_CONFORM_STRICT
)
1308 pg
->ppd_status
= PPD_NESTED_OPEN_UI
;
1314 * Add an option record to the current sub-group, group, or file...
1317 DEBUG_printf(("2_ppdOpen: name=\"%s\" (%d)", name
, (int)strlen(name
)));
1320 _cups_strcpy(name
, name
+ 1); /* Eliminate leading asterisk */
1322 for (i
= (int)strlen(name
) - 1; i
> 0 && _cups_isspace(name
[i
]); i
--)
1323 name
[i
] = '\0'; /* Eliminate trailing spaces */
1325 DEBUG_printf(("2_ppdOpen: OpenUI of %s in group %s...", name
,
1326 group
? group
->text
: "(null)"));
1328 if (subgroup
!= NULL
)
1329 option
= ppd_get_option(subgroup
, name
);
1330 else if (group
== NULL
)
1332 if ((group
= ppd_get_group(ppd
, "General", _("General"), pg
,
1336 DEBUG_printf(("2_ppdOpen: Adding to group %s...", group
->text
));
1337 option
= ppd_get_option(group
, name
);
1341 option
= ppd_get_option(group
, name
);
1345 pg
->ppd_status
= PPD_ALLOC_ERROR
;
1351 * Now fill in the initial information for the option...
1354 if (string
&& !strcmp(string
, "PickMany"))
1355 option
->ui
= PPD_UI_PICKMANY
;
1356 else if (string
&& !strcmp(string
, "Boolean"))
1357 option
->ui
= PPD_UI_BOOLEAN
;
1358 else if (string
&& !strcmp(string
, "PickOne"))
1359 option
->ui
= PPD_UI_PICKONE
;
1360 else if (pg
->ppd_conform
== PPD_CONFORM_STRICT
)
1362 pg
->ppd_status
= PPD_BAD_OPEN_UI
;
1367 option
->ui
= PPD_UI_PICKONE
;
1369 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1370 if (!strncmp(ppd
->attrs
[j
]->name
, "Default", 7) &&
1371 !strcmp(ppd
->attrs
[j
]->name
+ 7, name
) &&
1372 ppd
->attrs
[j
]->value
)
1374 DEBUG_printf(("2_ppdOpen: Setting Default%s to %s via attribute...",
1375 option
->keyword
, ppd
->attrs
[j
]->value
));
1376 strlcpy(option
->defchoice
, ppd
->attrs
[j
]->value
,
1377 sizeof(option
->defchoice
));
1382 cupsCharsetToUTF8((cups_utf8_t
*)option
->text
, text
,
1383 sizeof(option
->text
), encoding
);
1386 if (!strcmp(name
, "PageSize"))
1387 strlcpy(option
->text
, _("Media Size"), sizeof(option
->text
));
1388 else if (!strcmp(name
, "MediaType"))
1389 strlcpy(option
->text
, _("Media Type"), sizeof(option
->text
));
1390 else if (!strcmp(name
, "InputSlot"))
1391 strlcpy(option
->text
, _("Media Source"), sizeof(option
->text
));
1392 else if (!strcmp(name
, "ColorModel"))
1393 strlcpy(option
->text
, _("Output Mode"), sizeof(option
->text
));
1394 else if (!strcmp(name
, "Resolution"))
1395 strlcpy(option
->text
, _("Resolution"), sizeof(option
->text
));
1397 strlcpy(option
->text
, name
, sizeof(option
->text
));
1400 option
->section
= PPD_ORDER_ANY
;
1402 _cupsStrFree(string
);
1406 * Add a custom option choice if we have already seen a CustomFoo
1410 if (!_cups_strcasecmp(name
, "PageRegion"))
1411 strlcpy(custom_name
, "CustomPageSize", sizeof(custom_name
));
1413 snprintf(custom_name
, sizeof(custom_name
), "Custom%s", name
);
1415 if ((custom_attr
= ppdFindAttr(ppd
, custom_name
, "True")) != NULL
)
1417 if ((choice
= ppdFindChoice(option
, "Custom")) == NULL
)
1418 if ((choice
= ppd_add_choice(option
, "Custom")) == NULL
)
1420 DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
1422 pg
->ppd_status
= PPD_ALLOC_ERROR
;
1427 strlcpy(choice
->text
,
1428 custom_attr
->text
[0] ? custom_attr
->text
: _("Custom"),
1429 sizeof(choice
->text
));
1430 choice
->code
= _cupsStrRetain(custom_attr
->value
);
1433 else if (!strcmp(keyword
, "JCLOpenUI"))
1436 * Don't allow nesting of options...
1439 if (option
&& pg
->ppd_conform
== PPD_CONFORM_STRICT
)
1441 pg
->ppd_status
= PPD_NESTED_OPEN_UI
;
1447 * Find the JCL group, and add if needed...
1450 group
= ppd_get_group(ppd
, "JCL", _("JCL"), pg
, encoding
);
1456 * Add an option record to the current JCLs...
1460 _cups_strcpy(name
, name
+ 1);
1462 option
= ppd_get_option(group
, name
);
1466 pg
->ppd_status
= PPD_ALLOC_ERROR
;
1472 * Now fill in the initial information for the option...
1475 if (string
&& !strcmp(string
, "PickMany"))
1476 option
->ui
= PPD_UI_PICKMANY
;
1477 else if (string
&& !strcmp(string
, "Boolean"))
1478 option
->ui
= PPD_UI_BOOLEAN
;
1479 else if (string
&& !strcmp(string
, "PickOne"))
1480 option
->ui
= PPD_UI_PICKONE
;
1483 pg
->ppd_status
= PPD_BAD_OPEN_UI
;
1488 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1489 if (!strncmp(ppd
->attrs
[j
]->name
, "Default", 7) &&
1490 !strcmp(ppd
->attrs
[j
]->name
+ 7, name
) &&
1491 ppd
->attrs
[j
]->value
)
1493 DEBUG_printf(("2_ppdOpen: Setting Default%s to %s via attribute...",
1494 option
->keyword
, ppd
->attrs
[j
]->value
));
1495 strlcpy(option
->defchoice
, ppd
->attrs
[j
]->value
,
1496 sizeof(option
->defchoice
));
1501 cupsCharsetToUTF8((cups_utf8_t
*)option
->text
, text
,
1502 sizeof(option
->text
), encoding
);
1504 strlcpy(option
->text
, name
, sizeof(option
->text
));
1506 option
->section
= PPD_ORDER_JCL
;
1509 _cupsStrFree(string
);
1513 * Add a custom option choice if we have already seen a CustomFoo
1517 snprintf(custom_name
, sizeof(custom_name
), "Custom%s", name
);
1519 if ((custom_attr
= ppdFindAttr(ppd
, custom_name
, "True")) != NULL
)
1521 if ((choice
= ppd_add_choice(option
, "Custom")) == NULL
)
1523 DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
1525 pg
->ppd_status
= PPD_ALLOC_ERROR
;
1530 strlcpy(choice
->text
,
1531 custom_attr
->text
[0] ? custom_attr
->text
: _("Custom"),
1532 sizeof(choice
->text
));
1533 choice
->code
= _cupsStrRetain(custom_attr
->value
);
1536 else if (!strcmp(keyword
, "CloseUI"))
1538 if ((!option
|| option
->section
== PPD_ORDER_JCL
) && pg
->ppd_conform
== PPD_CONFORM_STRICT
)
1540 pg
->ppd_status
= PPD_BAD_CLOSE_UI
;
1547 _cupsStrFree(string
);
1550 else if (!strcmp(keyword
, "JCLCloseUI"))
1552 if ((!option
|| option
->section
!= PPD_ORDER_JCL
) && pg
->ppd_conform
== PPD_CONFORM_STRICT
)
1554 pg
->ppd_status
= PPD_BAD_CLOSE_UI
;
1561 _cupsStrFree(string
);
1564 else if (!strcmp(keyword
, "OpenGroup"))
1567 * Open a new group...
1572 pg
->ppd_status
= PPD_NESTED_OPEN_GROUP
;
1579 pg
->ppd_status
= PPD_BAD_OPEN_GROUP
;
1585 * Separate the group name from the text (name/text)...
1588 if ((sptr
= strchr(string
, '/')) != NULL
)
1594 * Fix up the text...
1600 * Find/add the group...
1603 group
= ppd_get_group(ppd
, string
, sptr
, pg
, encoding
);
1608 _cupsStrFree(string
);
1611 else if (!strcmp(keyword
, "CloseGroup"))
1615 _cupsStrFree(string
);
1618 else if (!strcmp(keyword
, "OrderDependency"))
1620 order
= (float)_cupsStrScand(string
, &sptr
, loc
);
1622 if (!sptr
|| sscanf(sptr
, "%40s%40s", name
, keyword
) != 2)
1624 pg
->ppd_status
= PPD_BAD_ORDER_DEPENDENCY
;
1629 if (keyword
[0] == '*')
1630 _cups_strcpy(keyword
, keyword
+ 1);
1632 if (!strcmp(name
, "ExitServer"))
1633 section
= PPD_ORDER_EXIT
;
1634 else if (!strcmp(name
, "Prolog"))
1635 section
= PPD_ORDER_PROLOG
;
1636 else if (!strcmp(name
, "DocumentSetup"))
1637 section
= PPD_ORDER_DOCUMENT
;
1638 else if (!strcmp(name
, "PageSetup"))
1639 section
= PPD_ORDER_PAGE
;
1640 else if (!strcmp(name
, "JCLSetup"))
1641 section
= PPD_ORDER_JCL
;
1643 section
= PPD_ORDER_ANY
;
1651 * Only valid for Non-UI options...
1654 for (i
= ppd
->num_groups
, gtemp
= ppd
->groups
; i
> 0; i
--, gtemp
++)
1655 if (gtemp
->text
[0] == '\0')
1659 for (i
= 0; i
< gtemp
->num_options
; i
++)
1660 if (!strcmp(keyword
, gtemp
->options
[i
].keyword
))
1662 gtemp
->options
[i
].section
= section
;
1663 gtemp
->options
[i
].order
= order
;
1669 option
->section
= section
;
1670 option
->order
= order
;
1673 _cupsStrFree(string
);
1676 else if (!strncmp(keyword
, "Default", 7))
1682 * Drop UI text, if any, from value...
1685 if (strchr(string
, '/') != NULL
)
1686 *strchr(string
, '/') = '\0';
1689 * Assign the default value as appropriate...
1692 if (!strcmp(keyword
, "DefaultColorSpace"))
1695 * Set default colorspace...
1698 if (!strcmp(string
, "CMY"))
1699 ppd
->colorspace
= PPD_CS_CMY
;
1700 else if (!strcmp(string
, "CMYK"))
1701 ppd
->colorspace
= PPD_CS_CMYK
;
1702 else if (!strcmp(string
, "RGB"))
1703 ppd
->colorspace
= PPD_CS_RGB
;
1704 else if (!strcmp(string
, "RGBK"))
1705 ppd
->colorspace
= PPD_CS_RGBK
;
1706 else if (!strcmp(string
, "N"))
1707 ppd
->colorspace
= PPD_CS_N
;
1709 ppd
->colorspace
= PPD_CS_GRAY
;
1711 else if (option
&& !strcmp(keyword
+ 7, option
->keyword
))
1714 * Set the default as part of the current option...
1717 DEBUG_printf(("2_ppdOpen: Setting %s to %s...", keyword
, string
));
1719 strlcpy(option
->defchoice
, string
, sizeof(option
->defchoice
));
1721 DEBUG_printf(("2_ppdOpen: %s is now %s...", keyword
, option
->defchoice
));
1726 * Lookup option and set if it has been defined...
1729 ppd_option_t
*toption
; /* Temporary option */
1732 if ((toption
= ppdFindOption(ppd
, keyword
+ 7)) != NULL
)
1734 DEBUG_printf(("2_ppdOpen: Setting %s to %s...", keyword
, string
));
1735 strlcpy(toption
->defchoice
, string
, sizeof(toption
->defchoice
));
1739 else if (!strcmp(keyword
, "UIConstraints") ||
1740 !strcmp(keyword
, "NonUIConstraints"))
1744 pg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1748 if (ppd
->num_consts
== 0)
1749 constraint
= calloc(2, sizeof(ppd_const_t
));
1751 constraint
= realloc(ppd
->consts
, (size_t)(ppd
->num_consts
+ 2) * sizeof(ppd_const_t
));
1753 if (constraint
== NULL
)
1755 pg
->ppd_status
= PPD_ALLOC_ERROR
;
1760 ppd
->consts
= constraint
;
1761 constraint
+= ppd
->num_consts
;
1764 switch (sscanf(string
, "%40s%40s%40s%40s", constraint
->option1
,
1765 constraint
->choice1
, constraint
->option2
,
1766 constraint
->choice2
))
1768 case 0 : /* Error */
1769 case 1 : /* Error */
1770 pg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1773 case 2 : /* Two options... */
1775 * Check for broken constraints like "* Option"...
1778 if (pg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1779 (!strcmp(constraint
->option1
, "*") ||
1780 !strcmp(constraint
->choice1
, "*")))
1782 pg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1787 * The following strcpy's are safe, as optionN and
1788 * choiceN are all the same size (size defined by PPD spec...)
1791 if (constraint
->option1
[0] == '*')
1792 _cups_strcpy(constraint
->option1
, constraint
->option1
+ 1);
1793 else if (pg
->ppd_conform
== PPD_CONFORM_STRICT
)
1795 pg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1799 if (constraint
->choice1
[0] == '*')
1800 _cups_strcpy(constraint
->option2
, constraint
->choice1
+ 1);
1801 else if (pg
->ppd_conform
== PPD_CONFORM_STRICT
)
1803 pg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1807 constraint
->choice1
[0] = '\0';
1808 constraint
->choice2
[0] = '\0';
1811 case 3 : /* Two options, one choice... */
1813 * Check for broken constraints like "* Option"...
1816 if (pg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1817 (!strcmp(constraint
->option1
, "*") ||
1818 !strcmp(constraint
->choice1
, "*") ||
1819 !strcmp(constraint
->option2
, "*")))
1821 pg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1826 * The following _cups_strcpy's are safe, as optionN and
1827 * choiceN are all the same size (size defined by PPD spec...)
1830 if (constraint
->option1
[0] == '*')
1831 _cups_strcpy(constraint
->option1
, constraint
->option1
+ 1);
1832 else if (pg
->ppd_conform
== PPD_CONFORM_STRICT
)
1834 pg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1838 if (constraint
->choice1
[0] == '*')
1840 if (pg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1841 constraint
->option2
[0] == '*')
1843 pg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1847 _cups_strcpy(constraint
->choice2
, constraint
->option2
);
1848 _cups_strcpy(constraint
->option2
, constraint
->choice1
+ 1);
1849 constraint
->choice1
[0] = '\0';
1853 if (constraint
->option2
[0] == '*')
1854 _cups_strcpy(constraint
->option2
, constraint
->option2
+ 1);
1855 else if (pg
->ppd_conform
== PPD_CONFORM_STRICT
)
1857 pg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1861 constraint
->choice2
[0] = '\0';
1865 case 4 : /* Two options, two choices... */
1867 * Check for broken constraints like "* Option"...
1870 if (pg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1871 (!strcmp(constraint
->option1
, "*") ||
1872 !strcmp(constraint
->choice1
, "*") ||
1873 !strcmp(constraint
->option2
, "*") ||
1874 !strcmp(constraint
->choice2
, "*")))
1876 pg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1880 if (constraint
->option1
[0] == '*')
1881 _cups_strcpy(constraint
->option1
, constraint
->option1
+ 1);
1882 else if (pg
->ppd_conform
== PPD_CONFORM_STRICT
)
1884 pg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1888 if (pg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1889 constraint
->choice1
[0] == '*')
1891 pg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1895 if (constraint
->option2
[0] == '*')
1896 _cups_strcpy(constraint
->option2
, constraint
->option2
+ 1);
1897 else if (pg
->ppd_conform
== PPD_CONFORM_STRICT
)
1899 pg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1903 if (pg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1904 constraint
->choice2
[0] == '*')
1906 pg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1913 * Don't add this one as an attribute...
1916 _cupsStrFree(string
);
1919 else if (!strcmp(keyword
, "PaperDimension"))
1921 if ((size
= ppdPageSize(ppd
, name
)) == NULL
)
1922 size
= ppd_add_size(ppd
, name
);
1927 * Unable to add or find size!
1930 pg
->ppd_status
= PPD_ALLOC_ERROR
;
1935 size
->width
= (float)_cupsStrScand(string
, &sptr
, loc
);
1936 size
->length
= (float)_cupsStrScand(sptr
, NULL
, loc
);
1938 _cupsStrFree(string
);
1941 else if (!strcmp(keyword
, "ImageableArea"))
1943 if ((size
= ppdPageSize(ppd
, name
)) == NULL
)
1944 size
= ppd_add_size(ppd
, name
);
1949 * Unable to add or find size!
1952 pg
->ppd_status
= PPD_ALLOC_ERROR
;
1957 size
->left
= (float)_cupsStrScand(string
, &sptr
, loc
);
1958 size
->bottom
= (float)_cupsStrScand(sptr
, &sptr
, loc
);
1959 size
->right
= (float)_cupsStrScand(sptr
, &sptr
, loc
);
1960 size
->top
= (float)_cupsStrScand(sptr
, NULL
, loc
);
1962 _cupsStrFree(string
);
1965 else if (option
!= NULL
&&
1966 (mask
& (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
)) ==
1967 (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
) &&
1968 !strcmp(keyword
, option
->keyword
))
1970 DEBUG_printf(("2_ppdOpen: group=%p, subgroup=%p", group
, subgroup
));
1972 if (!strcmp(keyword
, "PageSize"))
1975 * Add a page size...
1978 if (ppdPageSize(ppd
, name
) == NULL
)
1979 ppd_add_size(ppd
, name
);
1983 * Add the option choice...
1986 if ((choice
= ppd_add_choice(option
, name
)) == NULL
)
1988 pg
->ppd_status
= PPD_ALLOC_ERROR
;
1994 cupsCharsetToUTF8((cups_utf8_t
*)choice
->text
, text
,
1995 sizeof(choice
->text
), encoding
);
1996 else if (!strcmp(name
, "True"))
1997 strlcpy(choice
->text
, _("Yes"), sizeof(choice
->text
));
1998 else if (!strcmp(name
, "False"))
1999 strlcpy(choice
->text
, _("No"), sizeof(choice
->text
));
2001 strlcpy(choice
->text
, name
, sizeof(choice
->text
));
2003 if (option
->section
== PPD_ORDER_JCL
)
2004 ppd_decode(string
); /* Decode quoted string */
2006 choice
->code
= string
;
2007 string
= NULL
; /* Don't add as an attribute below */
2011 * Add remaining lines with keywords and string values as attributes...
2015 (mask
& (PPD_KEYWORD
| PPD_STRING
)) == (PPD_KEYWORD
| PPD_STRING
))
2016 ppd_add_attr(ppd
, keyword
, name
, text
, string
);
2018 _cupsStrFree(string
);
2022 * Check for a missing CloseUI/JCLCloseUI...
2025 if (option
&& pg
->ppd_conform
== PPD_CONFORM_STRICT
)
2027 pg
->ppd_status
= PPD_MISSING_CLOSE_UI
;
2032 * Check for a missing CloseGroup...
2035 if (group
&& pg
->ppd_conform
== PPD_CONFORM_STRICT
)
2037 pg
->ppd_status
= PPD_MISSING_CLOSE_GROUP
;
2041 ppd_free(line
.buffer
);
2044 * Reset language preferences...
2048 if (!cupsFileEOF(fp
))
2049 DEBUG_printf(("1_ppdOpen: Premature EOF at %lu...\n",
2050 (unsigned long)cupsFileTell(fp
)));
2053 if (pg
->ppd_status
!= PPD_OK
)
2056 * Had an error reading the PPD file, cannot continue!
2065 * Update the filters array as needed...
2068 if (!ppd_update_filters(ppd
, pg
))
2076 * Create the sorted options array and set the option back-pointer for
2077 * each choice and custom option...
2080 ppd
->options
= cupsArrayNew2((cups_array_func_t
)ppd_compare_options
, NULL
,
2081 (cups_ahash_func_t
)ppd_hash_option
,
2084 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
2088 for (j
= group
->num_options
, option
= group
->options
;
2092 ppd_coption_t
*coption
; /* Custom option */
2095 cupsArrayAdd(ppd
->options
, option
);
2097 for (k
= 0; k
< option
->num_choices
; k
++)
2098 option
->choices
[k
].option
= option
;
2100 if ((coption
= ppdFindCustomOption(ppd
, option
->keyword
)) != NULL
)
2101 coption
->option
= option
;
2106 * Create an array to track the marked choices...
2109 ppd
->marked
= cupsArrayNew((cups_array_func_t
)ppd_compare_choices
, NULL
);
2112 * Return the PPD file structure...
2118 * Common exit point for errors to save code size...
2123 _cupsStrFree(string
);
2124 ppd_free(line
.buffer
);
2133 * 'ppdOpen()' - Read a PPD file into memory.
2136 ppd_file_t
* /* O - PPD file record */
2137 ppdOpen(FILE *fp
) /* I - File to read from */
2139 ppd_file_t
*ppd
; /* PPD file record */
2140 cups_file_t
*cf
; /* CUPS file */
2144 * Reopen the stdio file as a CUPS file...
2147 if ((cf
= cupsFileOpenFd(fileno(fp
), "r")) == NULL
)
2151 * Load the PPD file using the newer API...
2154 ppd
= _ppdOpen(cf
, _PPD_LOCALIZATION_DEFAULT
);
2157 * Close the CUPS file and return the PPD...
2167 * 'ppdOpen2()' - Read a PPD file into memory.
2169 * @since CUPS 1.2/macOS 10.5@
2172 ppd_file_t
* /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
2173 ppdOpen2(cups_file_t
*fp
) /* I - File to read from */
2175 return _ppdOpen(fp
, _PPD_LOCALIZATION_DEFAULT
);
2180 * 'ppdOpenFd()' - Read a PPD file into memory.
2183 ppd_file_t
* /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
2184 ppdOpenFd(int fd
) /* I - File to read from */
2186 cups_file_t
*fp
; /* CUPS file pointer */
2187 ppd_file_t
*ppd
; /* PPD file record */
2188 _ppd_globals_t
*pg
= _ppdGlobals();
2193 * Set the line number to 0...
2199 * Range check input...
2204 pg
->ppd_status
= PPD_NULL_FILE
;
2210 * Try to open the file and parse it...
2213 if ((fp
= cupsFileOpenFd(fd
, "r")) != NULL
)
2221 pg
->ppd_status
= PPD_FILE_OPEN_ERROR
;
2230 * '_ppdOpenFile()' - Read a PPD file into memory.
2233 ppd_file_t
* /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
2234 _ppdOpenFile(const char *filename
, /* I - File to read from */
2235 _ppd_localization_t localization
) /* I - Localization to load */
2237 cups_file_t
*fp
; /* File pointer */
2238 ppd_file_t
*ppd
; /* PPD file record */
2239 _ppd_globals_t
*pg
= _ppdGlobals();
2244 * Set the line number to 0...
2250 * Range check input...
2253 if (filename
== NULL
)
2255 pg
->ppd_status
= PPD_NULL_FILE
;
2261 * Try to open the file and parse it...
2264 if ((fp
= cupsFileOpen(filename
, "r")) != NULL
)
2266 ppd
= _ppdOpen(fp
, localization
);
2272 pg
->ppd_status
= PPD_FILE_OPEN_ERROR
;
2281 * 'ppdOpenFile()' - Read a PPD file into memory.
2284 ppd_file_t
* /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
2285 ppdOpenFile(const char *filename
) /* I - File to read from */
2287 return _ppdOpenFile(filename
, _PPD_LOCALIZATION_DEFAULT
);
2292 * 'ppdSetConformance()' - Set the conformance level for PPD files.
2294 * @since CUPS 1.1.20/macOS 10.4@
2298 ppdSetConformance(ppd_conform_t c
) /* I - Conformance level */
2300 _ppd_globals_t
*pg
= _ppdGlobals();
2304 pg
->ppd_conform
= c
;
2309 * 'ppd_add_attr()' - Add an attribute to the PPD data.
2312 static ppd_attr_t
* /* O - New attribute */
2313 ppd_add_attr(ppd_file_t
*ppd
, /* I - PPD file data */
2314 const char *name
, /* I - Attribute name */
2315 const char *spec
, /* I - Specifier string, if any */
2316 const char *text
, /* I - Text string, if any */
2317 const char *value
) /* I - Value of attribute */
2319 ppd_attr_t
**ptr
, /* New array */
2320 *temp
; /* New attribute */
2324 * Range check input...
2327 if (ppd
== NULL
|| name
== NULL
|| spec
== NULL
)
2331 * Create the array as needed...
2334 if (!ppd
->sorted_attrs
)
2335 ppd
->sorted_attrs
= cupsArrayNew((cups_array_func_t
)ppd_compare_attrs
,
2339 * Allocate memory for the new attribute...
2342 if (ppd
->num_attrs
== 0)
2343 ptr
= malloc(sizeof(ppd_attr_t
*));
2345 ptr
= realloc(ppd
->attrs
, (size_t)(ppd
->num_attrs
+ 1) * sizeof(ppd_attr_t
*));
2351 ptr
+= ppd
->num_attrs
;
2353 if ((temp
= calloc(1, sizeof(ppd_attr_t
))) == NULL
)
2364 strlcpy(temp
->name
, name
, sizeof(temp
->name
));
2365 strlcpy(temp
->spec
, spec
, sizeof(temp
->spec
));
2366 strlcpy(temp
->text
, text
, sizeof(temp
->text
));
2367 temp
->value
= (char *)value
;
2370 * Add the attribute to the sorted array...
2373 cupsArrayAdd(ppd
->sorted_attrs
, temp
);
2376 * Return the attribute...
2384 * 'ppd_add_choice()' - Add a choice to an option.
2387 static ppd_choice_t
* /* O - Named choice */
2388 ppd_add_choice(ppd_option_t
*option
, /* I - Option */
2389 const char *name
) /* I - Name of choice */
2391 ppd_choice_t
*choice
; /* Choice */
2394 if (option
->num_choices
== 0)
2395 choice
= malloc(sizeof(ppd_choice_t
));
2397 choice
= realloc(option
->choices
, sizeof(ppd_choice_t
) * (size_t)(option
->num_choices
+ 1));
2402 option
->choices
= choice
;
2403 choice
+= option
->num_choices
;
2404 option
->num_choices
++;
2406 memset(choice
, 0, sizeof(ppd_choice_t
));
2407 strlcpy(choice
->choice
, name
, sizeof(choice
->choice
));
2414 * 'ppd_add_size()' - Add a page size.
2417 static ppd_size_t
* /* O - Named size */
2418 ppd_add_size(ppd_file_t
*ppd
, /* I - PPD file */
2419 const char *name
) /* I - Name of size */
2421 ppd_size_t
*size
; /* Size */
2424 if (ppd
->num_sizes
== 0)
2425 size
= malloc(sizeof(ppd_size_t
));
2427 size
= realloc(ppd
->sizes
, sizeof(ppd_size_t
) * (size_t)(ppd
->num_sizes
+ 1));
2433 size
+= ppd
->num_sizes
;
2436 memset(size
, 0, sizeof(ppd_size_t
));
2437 strlcpy(size
->name
, name
, sizeof(size
->name
));
2444 * 'ppd_compare_attrs()' - Compare two attributes.
2447 static int /* O - Result of comparison */
2448 ppd_compare_attrs(ppd_attr_t
*a
, /* I - First attribute */
2449 ppd_attr_t
*b
) /* I - Second attribute */
2451 return (_cups_strcasecmp(a
->name
, b
->name
));
2456 * 'ppd_compare_choices()' - Compare two choices...
2459 static int /* O - Result of comparison */
2460 ppd_compare_choices(ppd_choice_t
*a
, /* I - First choice */
2461 ppd_choice_t
*b
) /* I - Second choice */
2463 return (strcmp(a
->option
->keyword
, b
->option
->keyword
));
2468 * 'ppd_compare_coptions()' - Compare two custom options.
2471 static int /* O - Result of comparison */
2472 ppd_compare_coptions(ppd_coption_t
*a
, /* I - First option */
2473 ppd_coption_t
*b
) /* I - Second option */
2475 return (_cups_strcasecmp(a
->keyword
, b
->keyword
));
2480 * 'ppd_compare_options()' - Compare two options.
2483 static int /* O - Result of comparison */
2484 ppd_compare_options(ppd_option_t
*a
, /* I - First option */
2485 ppd_option_t
*b
) /* I - Second option */
2487 return (_cups_strcasecmp(a
->keyword
, b
->keyword
));
2492 * 'ppd_decode()' - Decode a string value...
2495 static int /* O - Length of decoded string */
2496 ppd_decode(char *string
) /* I - String to decode */
2498 char *inptr
, /* Input pointer */
2499 *outptr
; /* Output pointer */
2505 while (*inptr
!= '\0')
2506 if (*inptr
== '<' && isxdigit(inptr
[1] & 255))
2509 * Convert hex to 8-bit values...
2513 while (isxdigit(*inptr
& 255))
2515 if (_cups_isalpha(*inptr
))
2516 *outptr
= (char)((tolower(*inptr
) - 'a' + 10) << 4);
2518 *outptr
= (char)((*inptr
- '0') << 4);
2522 if (!isxdigit(*inptr
& 255))
2525 if (_cups_isalpha(*inptr
))
2526 *outptr
|= (char)(tolower(*inptr
) - 'a' + 10);
2528 *outptr
|= (char)(*inptr
- '0');
2534 while (*inptr
!= '>' && *inptr
!= '\0')
2536 while (*inptr
== '>')
2540 *outptr
++ = *inptr
++;
2544 return ((int)(outptr
- string
));
2549 * 'ppd_free_filters()' - Free the filters array.
2553 ppd_free_filters(ppd_file_t
*ppd
) /* I - PPD file */
2555 int i
; /* Looping var */
2556 char **filter
; /* Current filter */
2559 if (ppd
->num_filters
> 0)
2561 for (i
= ppd
->num_filters
, filter
= ppd
->filters
; i
> 0; i
--, filter
++)
2562 _cupsStrFree(*filter
);
2564 ppd_free(ppd
->filters
);
2566 ppd
->num_filters
= 0;
2567 ppd
->filters
= NULL
;
2573 * 'ppd_free_group()' - Free a single UI group.
2577 ppd_free_group(ppd_group_t
*group
) /* I - Group to free */
2579 int i
; /* Looping var */
2580 ppd_option_t
*option
; /* Current option */
2581 ppd_group_t
*subgroup
; /* Current sub-group */
2584 if (group
->num_options
> 0)
2586 for (i
= group
->num_options
, option
= group
->options
;
2589 ppd_free_option(option
);
2591 ppd_free(group
->options
);
2594 if (group
->num_subgroups
> 0)
2596 for (i
= group
->num_subgroups
, subgroup
= group
->subgroups
;
2599 ppd_free_group(subgroup
);
2601 ppd_free(group
->subgroups
);
2607 * 'ppd_free_option()' - Free a single option.
2611 ppd_free_option(ppd_option_t
*option
) /* I - Option to free */
2613 int i
; /* Looping var */
2614 ppd_choice_t
*choice
; /* Current choice */
2617 if (option
->num_choices
> 0)
2619 for (i
= option
->num_choices
, choice
= option
->choices
;
2623 _cupsStrFree(choice
->code
);
2626 ppd_free(option
->choices
);
2632 * 'ppd_get_coption()' - Get a custom option record.
2635 static ppd_coption_t
* /* O - Custom option... */
2636 ppd_get_coption(ppd_file_t
*ppd
, /* I - PPD file */
2637 const char *name
) /* I - Name of option */
2639 ppd_coption_t
*copt
; /* New custom option */
2643 * See if the option already exists...
2646 if ((copt
= ppdFindCustomOption(ppd
, name
)) != NULL
)
2650 * Not found, so create the custom option record...
2653 if ((copt
= calloc(1, sizeof(ppd_coption_t
))) == NULL
)
2656 strlcpy(copt
->keyword
, name
, sizeof(copt
->keyword
));
2658 copt
->params
= cupsArrayNew((cups_array_func_t
)NULL
, NULL
);
2660 cupsArrayAdd(ppd
->coptions
, copt
);
2663 * Return the new record...
2671 * 'ppd_get_cparam()' - Get a custom parameter record.
2674 static ppd_cparam_t
* /* O - Extended option... */
2675 ppd_get_cparam(ppd_coption_t
*opt
, /* I - PPD file */
2676 const char *param
, /* I - Name of parameter */
2677 const char *text
) /* I - Human-readable text */
2679 ppd_cparam_t
*cparam
; /* New custom parameter */
2683 * See if the parameter already exists...
2686 if ((cparam
= ppdFindCustomParam(opt
, param
)) != NULL
)
2690 * Not found, so create the custom parameter record...
2693 if ((cparam
= calloc(1, sizeof(ppd_cparam_t
))) == NULL
)
2696 strlcpy(cparam
->name
, param
, sizeof(cparam
->name
));
2697 strlcpy(cparam
->text
, text
[0] ? text
: param
, sizeof(cparam
->text
));
2700 * Add this record to the array...
2703 cupsArrayAdd(opt
->params
, cparam
);
2706 * Return the new record...
2714 * 'ppd_get_group()' - Find or create the named group as needed.
2717 static ppd_group_t
* /* O - Named group */
2718 ppd_get_group(ppd_file_t
*ppd
, /* I - PPD file */
2719 const char *name
, /* I - Name of group */
2720 const char *text
, /* I - Text for group */
2721 _ppd_globals_t
*pg
, /* I - Global data */
2722 cups_encoding_t encoding
) /* I - Encoding of text */
2724 int i
; /* Looping var */
2725 ppd_group_t
*group
; /* Group */
2728 DEBUG_printf(("7ppd_get_group(ppd=%p, name=\"%s\", text=\"%s\", cg=%p)",
2729 ppd
, name
, text
, pg
));
2731 for (i
= ppd
->num_groups
, group
= ppd
->groups
; i
> 0; i
--, group
++)
2732 if (!strcmp(group
->name
, name
))
2737 DEBUG_printf(("8ppd_get_group: Adding group %s...", name
));
2739 if (pg
->ppd_conform
== PPD_CONFORM_STRICT
&& strlen(text
) >= sizeof(group
->text
))
2741 pg
->ppd_status
= PPD_ILLEGAL_TRANSLATION
;
2746 if (ppd
->num_groups
== 0)
2747 group
= malloc(sizeof(ppd_group_t
));
2749 group
= realloc(ppd
->groups
, (size_t)(ppd
->num_groups
+ 1) * sizeof(ppd_group_t
));
2753 pg
->ppd_status
= PPD_ALLOC_ERROR
;
2758 ppd
->groups
= group
;
2759 group
+= ppd
->num_groups
;
2762 memset(group
, 0, sizeof(ppd_group_t
));
2763 strlcpy(group
->name
, name
, sizeof(group
->name
));
2765 cupsCharsetToUTF8((cups_utf8_t
*)group
->text
, text
,
2766 sizeof(group
->text
), encoding
);
2774 * 'ppd_get_option()' - Find or create the named option as needed.
2777 static ppd_option_t
* /* O - Named option */
2778 ppd_get_option(ppd_group_t
*group
, /* I - Group */
2779 const char *name
) /* I - Name of option */
2781 int i
; /* Looping var */
2782 ppd_option_t
*option
; /* Option */
2785 DEBUG_printf(("7ppd_get_option(group=%p(\"%s\"), name=\"%s\")",
2786 group
, group
->name
, name
));
2788 for (i
= group
->num_options
, option
= group
->options
; i
> 0; i
--, option
++)
2789 if (!strcmp(option
->keyword
, name
))
2794 if (group
->num_options
== 0)
2795 option
= malloc(sizeof(ppd_option_t
));
2797 option
= realloc(group
->options
, (size_t)(group
->num_options
+ 1) * sizeof(ppd_option_t
));
2802 group
->options
= option
;
2803 option
+= group
->num_options
;
2804 group
->num_options
++;
2806 memset(option
, 0, sizeof(ppd_option_t
));
2807 strlcpy(option
->keyword
, name
, sizeof(option
->keyword
));
2815 * 'ppd_globals_alloc()' - Allocate and initialize global data.
2818 static _ppd_globals_t
* /* O - Pointer to global data */
2819 ppd_globals_alloc(void)
2821 return ((_ppd_globals_t
*)calloc(1, sizeof(_ppd_globals_t
)));
2826 * 'ppd_globals_free()' - Free global data.
2829 #if defined(HAVE_PTHREAD_H) || defined(_WIN32)
2831 ppd_globals_free(_ppd_globals_t
*pg
) /* I - Pointer to global data */
2835 #endif /* HAVE_PTHREAD_H || _WIN32 */
2838 #ifdef HAVE_PTHREAD_H
2840 * 'ppd_globals_init()' - Initialize per-thread globals...
2844 ppd_globals_init(void)
2847 * Register the global data for this thread...
2850 pthread_key_create(&ppd_globals_key
, (void (*)(void *))ppd_globals_free
);
2852 #endif /* HAVE_PTHREAD_H */
2856 * 'ppd_hash_option()' - Generate a hash of the option name...
2859 static int /* O - Hash index */
2860 ppd_hash_option(ppd_option_t
*option
) /* I - Option */
2862 int hash
= 0; /* Hash index */
2863 const char *k
; /* Pointer into keyword */
2866 for (hash
= option
->keyword
[0], k
= option
->keyword
+ 1; *k
;)
2867 hash
= 33 * hash
+ *k
++;
2869 return (hash
& 511);
2874 * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
2878 static int /* O - Bitmask of fields read */
2879 ppd_read(cups_file_t
*fp
, /* I - File to read from */
2880 _ppd_line_t
*line
, /* I - Line buffer */
2881 char *keyword
, /* O - Keyword from line */
2882 char *option
, /* O - Option from line */
2883 char *text
, /* O - Human-readable text from line */
2884 char **string
, /* O - Code/string data */
2885 int ignoreblank
, /* I - Ignore blank lines? */
2886 _ppd_globals_t
*pg
) /* I - Global data */
2888 int ch
, /* Character from file */
2889 col
, /* Column in line */
2890 colon
, /* Colon seen? */
2891 endquote
, /* Waiting for an end quote */
2892 mask
, /* Mask to be returned */
2893 startline
, /* Start line */
2894 textlen
; /* Length of text */
2895 char *keyptr
, /* Keyword pointer */
2896 *optptr
, /* Option pointer */
2897 *textptr
, /* Text pointer */
2898 *strptr
, /* Pointer into string */
2899 *lineptr
; /* Current position in line buffer */
2903 * Now loop until we have a valid line...
2908 startline
= pg
->ppd_line
+ 1;
2912 line
->bufsize
= 1024;
2913 line
->buffer
= malloc(1024);
2925 lineptr
= line
->buffer
;
2929 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
2931 if (lineptr
>= (line
->buffer
+ line
->bufsize
- 1))
2934 * Expand the line buffer...
2937 char *temp
; /* Temporary line pointer */
2940 line
->bufsize
+= 1024;
2941 if (line
->bufsize
> 262144)
2944 * Don't allow lines longer than 256k!
2947 pg
->ppd_line
= startline
;
2948 pg
->ppd_status
= PPD_LINE_TOO_LONG
;
2953 temp
= realloc(line
->buffer
, line
->bufsize
);
2956 pg
->ppd_line
= startline
;
2957 pg
->ppd_status
= PPD_LINE_TOO_LONG
;
2962 lineptr
= temp
+ (lineptr
- line
->buffer
);
2963 line
->buffer
= temp
;
2966 if (ch
== '\r' || ch
== '\n')
2969 * Line feed or carriage return...
2978 * Check for a trailing line feed...
2981 if ((ch
= cupsFilePeekChar(fp
)) == EOF
)
2988 cupsFileGetChar(fp
);
2991 if (lineptr
== line
->buffer
&& ignoreblank
)
2992 continue; /* Skip blank lines */
2996 if (!endquote
) /* Continue for multi-line text */
3001 else if (ch
< ' ' && ch
!= '\t' && pg
->ppd_conform
== PPD_CONFORM_STRICT
)
3004 * Other control characters...
3007 pg
->ppd_line
= startline
;
3008 pg
->ppd_status
= PPD_ILLEGAL_CHARACTER
;
3012 else if (ch
!= 0x1a)
3015 * Any other character...
3018 *lineptr
++ = (char)ch
;
3021 if (col
> (PPD_MAX_LINE
- 1))
3024 * Line is too long...
3027 pg
->ppd_line
= startline
;
3028 pg
->ppd_status
= PPD_LINE_TOO_LONG
;
3033 if (ch
== ':' && strncmp(line
->buffer
, "*%", 2) != 0)
3036 if (ch
== '\"' && colon
)
3037 endquote
= !endquote
;
3044 * Didn't finish this quoted string...
3047 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
3050 else if (ch
== '\r' || ch
== '\n')
3058 * Check for a trailing line feed...
3061 if ((ch
= cupsFilePeekChar(fp
)) == EOF
)
3064 cupsFileGetChar(fp
);
3067 else if (ch
< ' ' && ch
!= '\t' && pg
->ppd_conform
== PPD_CONFORM_STRICT
)
3070 * Other control characters...
3073 pg
->ppd_line
= startline
;
3074 pg
->ppd_status
= PPD_ILLEGAL_CHARACTER
;
3078 else if (ch
!= 0x1a)
3082 if (col
> (PPD_MAX_LINE
- 1))
3085 * Line is too long...
3088 pg
->ppd_line
= startline
;
3089 pg
->ppd_status
= PPD_LINE_TOO_LONG
;
3099 * Didn't finish this line...
3102 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
3103 if (ch
== '\r' || ch
== '\n')
3106 * Line feed or carriage return...
3115 * Check for a trailing line feed...
3118 if ((ch
= cupsFilePeekChar(fp
)) == EOF
)
3121 cupsFileGetChar(fp
);
3126 else if (ch
< ' ' && ch
!= '\t' && pg
->ppd_conform
== PPD_CONFORM_STRICT
)
3129 * Other control characters...
3132 pg
->ppd_line
= startline
;
3133 pg
->ppd_status
= PPD_ILLEGAL_CHARACTER
;
3137 else if (ch
!= 0x1a)
3141 if (col
> (PPD_MAX_LINE
- 1))
3144 * Line is too long...
3147 pg
->ppd_line
= startline
;
3148 pg
->ppd_status
= PPD_LINE_TOO_LONG
;
3155 if (lineptr
> line
->buffer
&& lineptr
[-1] == '\n')
3160 DEBUG_printf(("9ppd_read: LINE=\"%s\"", line
->buffer
));
3163 * The dynamically created PPDs for older style macOS
3164 * drivers include a large blob of data inserted as comments
3165 * at the end of the file. As an optimization we can stop
3166 * reading the PPD when we get to the start of this data.
3169 if (!strcmp(line
->buffer
, "*%APLWORKSET START"))
3172 if (ch
== EOF
&& lineptr
== line
->buffer
)
3180 lineptr
= line
->buffer
+ 1;
3187 if ((!line
->buffer
[0] || /* Blank line */
3188 !strncmp(line
->buffer
, "*%", 2) || /* Comment line */
3189 !strcmp(line
->buffer
, "*End")) && /* End of multi-line string */
3190 ignoreblank
) /* Ignore these? */
3192 startline
= pg
->ppd_line
+ 1;
3196 if (!strcmp(line
->buffer
, "*")) /* (Bad) comment line */
3198 if (pg
->ppd_conform
== PPD_CONFORM_RELAXED
)
3200 startline
= pg
->ppd_line
+ 1;
3205 pg
->ppd_line
= startline
;
3206 pg
->ppd_status
= PPD_ILLEGAL_MAIN_KEYWORD
;
3212 if (line
->buffer
[0] != '*') /* All lines start with an asterisk */
3215 * Allow lines consisting of just whitespace...
3218 for (lineptr
= line
->buffer
; *lineptr
; lineptr
++)
3219 if (*lineptr
&& !_cups_isspace(*lineptr
))
3224 pg
->ppd_status
= PPD_MISSING_ASTERISK
;
3227 else if (ignoreblank
)
3239 while (*lineptr
&& *lineptr
!= ':' && !_cups_isspace(*lineptr
))
3241 if (*lineptr
<= ' ' || *lineptr
> 126 || *lineptr
== '/' ||
3242 (keyptr
- keyword
) >= (PPD_MAX_NAME
- 1))
3244 pg
->ppd_status
= PPD_ILLEGAL_MAIN_KEYWORD
;
3248 *keyptr
++ = *lineptr
++;
3253 if (!strcmp(keyword
, "End"))
3256 mask
|= PPD_KEYWORD
;
3258 if (_cups_isspace(*lineptr
))
3261 * Get an option name...
3264 while (_cups_isspace(*lineptr
))
3269 while (*lineptr
&& !_cups_isspace(*lineptr
) && *lineptr
!= ':' &&
3272 if (*lineptr
<= ' ' || *lineptr
> 126 ||
3273 (optptr
- option
) >= (PPD_MAX_NAME
- 1))
3275 pg
->ppd_status
= PPD_ILLEGAL_OPTION_KEYWORD
;
3279 *optptr
++ = *lineptr
++;
3284 if (_cups_isspace(*lineptr
) && pg
->ppd_conform
== PPD_CONFORM_STRICT
)
3286 pg
->ppd_status
= PPD_ILLEGAL_WHITESPACE
;
3290 while (_cups_isspace(*lineptr
))
3295 if (*lineptr
== '/')
3298 * Get human-readable text...
3305 while (*lineptr
!= '\0' && *lineptr
!= '\n' && *lineptr
!= ':')
3307 if (((unsigned char)*lineptr
< ' ' && *lineptr
!= '\t') ||
3308 (textptr
- text
) >= (PPD_MAX_LINE
- 1))
3310 pg
->ppd_status
= PPD_ILLEGAL_TRANSLATION
;
3314 *textptr
++ = *lineptr
++;
3318 textlen
= ppd_decode(text
);
3320 if (textlen
> PPD_MAX_TEXT
&& pg
->ppd_conform
== PPD_CONFORM_STRICT
)
3322 pg
->ppd_status
= PPD_ILLEGAL_TRANSLATION
;
3330 if (_cups_isspace(*lineptr
) && pg
->ppd_conform
== PPD_CONFORM_STRICT
)
3332 pg
->ppd_status
= PPD_ILLEGAL_WHITESPACE
;
3336 while (_cups_isspace(*lineptr
))
3339 if (*lineptr
== ':')
3342 * Get string after triming leading and trailing whitespace...
3346 while (_cups_isspace(*lineptr
))
3349 strptr
= lineptr
+ strlen(lineptr
) - 1;
3350 while (strptr
>= lineptr
&& _cups_isspace(*strptr
))
3353 if (*strptr
== '\"')
3356 * Quoted string by itself, remove quotes...
3363 *string
= _cupsStrAlloc(lineptr
);
3375 * 'ppd_update_filters()' - Update the filters array as needed.
3377 * This function re-populates the filters array with cupsFilter2 entries that
3378 * have been stripped of the destination MIME media types and any maxsize hints.
3380 * (All for backwards-compatibility)
3383 static int /* O - 1 on success, 0 on failure */
3384 ppd_update_filters(ppd_file_t
*ppd
, /* I - PPD file */
3385 _ppd_globals_t
*pg
) /* I - Global data */
3387 ppd_attr_t
*attr
; /* Current cupsFilter2 value */
3388 char srcsuper
[16], /* Source MIME media type */
3390 dstsuper
[16], /* Destination MIME media type */
3392 program
[1024], /* Command to run */
3393 *ptr
, /* Pointer into command to run */
3394 buffer
[1024], /* Re-written cupsFilter value */
3395 **filter
; /* Current filter */
3396 int cost
; /* Cost of filter */
3399 DEBUG_printf(("4ppd_update_filters(ppd=%p, cg=%p)", ppd
, pg
));
3402 * See if we have any cupsFilter2 lines...
3405 if ((attr
= ppdFindAttr(ppd
, "cupsFilter2", NULL
)) == NULL
)
3407 DEBUG_puts("5ppd_update_filters: No cupsFilter2 keywords present.");
3412 * Yes, free the cupsFilter-defined filters and re-build...
3415 ppd_free_filters(ppd
);
3420 * Parse the cupsFilter2 string:
3422 * src/type dst/type cost program
3423 * src/type dst/type cost maxsize(n) program
3426 DEBUG_printf(("5ppd_update_filters: cupsFilter2=\"%s\"", attr
->value
));
3428 if (sscanf(attr
->value
, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]",
3429 srcsuper
, srctype
, dstsuper
, dsttype
, &cost
, program
) != 6)
3431 DEBUG_puts("5ppd_update_filters: Bad cupsFilter2 line.");
3432 pg
->ppd_status
= PPD_BAD_VALUE
;
3437 DEBUG_printf(("5ppd_update_filters: srcsuper=\"%s\", srctype=\"%s\", "
3438 "dstsuper=\"%s\", dsttype=\"%s\", cost=%d, program=\"%s\"",
3439 srcsuper
, srctype
, dstsuper
, dsttype
, cost
, program
));
3441 if (!strncmp(program
, "maxsize(", 8) &&
3442 (ptr
= strchr(program
+ 8, ')')) != NULL
)
3444 DEBUG_puts("5ppd_update_filters: Found maxsize(nnn).");
3447 while (_cups_isspace(*ptr
))
3450 _cups_strcpy(program
, ptr
);
3451 DEBUG_printf(("5ppd_update_filters: New program=\"%s\"", program
));
3455 * Convert to cupsFilter format:
3457 * src/type cost program
3460 snprintf(buffer
, sizeof(buffer
), "%s/%s %d %s", srcsuper
, srctype
, cost
,
3462 DEBUG_printf(("5ppd_update_filters: Adding \"%s\".", buffer
));
3465 * Add a cupsFilter-compatible string to the filters array.
3468 if (ppd
->num_filters
== 0)
3469 filter
= malloc(sizeof(char *));
3471 filter
= realloc(ppd
->filters
, sizeof(char *) * (size_t)(ppd
->num_filters
+ 1));
3475 DEBUG_puts("5ppd_update_filters: Out of memory.");
3476 pg
->ppd_status
= PPD_ALLOC_ERROR
;
3481 ppd
->filters
= filter
;
3482 filter
+= ppd
->num_filters
;
3483 ppd
->num_filters
++;
3485 *filter
= _cupsStrAlloc(buffer
);
3487 while ((attr
= ppdFindNextAttr(ppd
, "cupsFilter2", NULL
)) != NULL
);
3489 DEBUG_puts("5ppd_update_filters: Completed OK.");