2 * PPD file routines for CUPS.
4 * Copyright 2007-2017 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>
582 * <rdar://problem/27245567>
584 * Need to use a different base language for some locales...
587 if (!strcmp(lang
->language
, "zh_HK"))
588 { /* Traditional Chinese + variants */
589 strlcpy(ll_CC
, "zh_TW.", sizeof(ll_CC
));
590 strlcpy(ll
, "zh_", sizeof(ll
));
592 else if (!strncmp(lang
->language
, "zh", 2))
593 strlcpy(ll
, "zh_", sizeof(ll
)); /* Any Chinese variant */
594 else if (!strncmp(lang
->language
, "jp", 2))
595 { /* Any Japanese variant */
596 strlcpy(ll_CC
, "ja", sizeof(ll_CC
));
597 strlcpy(ll
, "jp", sizeof(ll
));
599 else if (!strncmp(lang
->language
, "nb", 2) || !strncmp(lang
->language
, "no", 2))
600 { /* Any Norwegian variant */
601 strlcpy(ll_CC
, "nb", sizeof(ll_CC
));
602 strlcpy(ll
, "no", sizeof(ll
));
605 snprintf(ll
, sizeof(ll
), "%2.2s.", lang
->language
);
607 ll_CC_len
= strlen(ll_CC
);
610 DEBUG_printf(("2_ppdOpen: Loading localizations matching \"%s\" and \"%s\"",
615 * Grab the first line and make sure it reads '*PPD-Adobe: "major.minor"'...
621 mask
= ppd_read(fp
, &line
, keyword
, name
, text
, &string
, 0, pg
);
623 DEBUG_printf(("2_ppdOpen: mask=%x, keyword=\"%s\"...", mask
, keyword
));
626 strcmp(keyword
, "PPD-Adobe") ||
627 string
== NULL
|| string
[0] != '4')
630 * Either this is not a PPD file, or it is not a 4.x PPD file.
633 if (pg
->ppd_status
== PPD_OK
)
634 pg
->ppd_status
= PPD_MISSING_PPDADOBE4
;
636 _cupsStrFree(string
);
637 ppd_free(line
.buffer
);
642 DEBUG_printf(("2_ppdOpen: keyword=%s, string=%p", keyword
, string
));
644 _cupsStrFree(string
);
647 * Allocate memory for the PPD file record...
650 if ((ppd
= calloc(1, sizeof(ppd_file_t
))) == NULL
)
652 pg
->ppd_status
= PPD_ALLOC_ERROR
;
654 _cupsStrFree(string
);
655 ppd_free(line
.buffer
);
660 ppd
->language_level
= 2;
661 ppd
->color_device
= 0;
662 ppd
->colorspace
= PPD_CS_N
;
663 ppd
->landscape
= -90;
664 ppd
->coptions
= cupsArrayNew((cups_array_func_t
)ppd_compare_coptions
,
668 * Read lines from the PPD file and add them to the file record...
676 encoding
= CUPS_ISO8859_1
;
679 while ((mask
= ppd_read(fp
, &line
, keyword
, name
, text
, &string
, 1, pg
)) != 0)
681 DEBUG_printf(("2_ppdOpen: mask=%x, keyword=\"%s\", name=\"%s\", "
682 "text=\"%s\", string=%d chars...", mask
, keyword
, name
, text
,
683 string
? (int)strlen(string
) : 0));
685 if (strncmp(keyword
, "Default", 7) && !string
&&
686 pg
->ppd_conform
!= PPD_CONFORM_RELAXED
)
689 * Need a string value!
692 pg
->ppd_status
= PPD_MISSING_VALUE
;
700 * Certain main keywords (as defined by the PPD spec) may be used
701 * without the usual OpenUI/CloseUI stuff. Presumably this is just
702 * so that Adobe wouldn't completely break compatibility with PPD
703 * files prior to v4.0 of the spec, but it is hopelessly
704 * inconsistent... Catch these main keywords and automatically
705 * create the corresponding option, as needed...
711 * Previous line was a UI keyword...
719 * If we are filtering out keyword localizations, see if this line needs to
723 if (localization
!= _PPD_LOCALIZATION_ALL
&&
724 (temp
= strchr(keyword
, '.')) != NULL
&&
725 ((temp
- keyword
) == 2 || (temp
- keyword
) == 5) &&
726 _cups_isalpha(keyword
[0]) &&
727 _cups_isalpha(keyword
[1]) &&
728 (keyword
[2] == '.' ||
729 (keyword
[2] == '_' && _cups_isalpha(keyword
[3]) &&
730 _cups_isalpha(keyword
[4]) && keyword
[5] == '.')))
732 if (localization
== _PPD_LOCALIZATION_NONE
||
733 (localization
== _PPD_LOCALIZATION_DEFAULT
&&
734 strncmp(ll_CC
, keyword
, ll_CC_len
) &&
735 strncmp(ll
, keyword
, ll_len
)))
737 DEBUG_printf(("2_ppdOpen: Ignoring localization: \"%s\"\n", keyword
));
740 else if (localization
== _PPD_LOCALIZATION_ICC_PROFILES
)
743 * Only load localizations for the color profile related keywords...
747 i
< (int)(sizeof(color_keywords
) / sizeof(color_keywords
[0]));
750 if (!_cups_strcasecmp(temp
, color_keywords
[i
]))
754 if (i
>= (int)(sizeof(color_keywords
) / sizeof(color_keywords
[0])))
756 DEBUG_printf(("2_ppdOpen: Ignoring localization: \"%s\"\n", keyword
));
762 if (option
== NULL
&&
763 (mask
& (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
)) ==
764 (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
))
766 for (i
= 0; i
< (int)(sizeof(ui_keywords
) / sizeof(ui_keywords
[0])); i
++)
767 if (!strcmp(keyword
, ui_keywords
[i
]))
770 if (i
< (int)(sizeof(ui_keywords
) / sizeof(ui_keywords
[0])))
773 * Create the option in the appropriate group...
778 DEBUG_printf(("2_ppdOpen: FOUND ADOBE UI KEYWORD %s WITHOUT OPENUI!",
783 if ((group
= ppd_get_group(ppd
, "General", _("General"), pg
,
787 DEBUG_printf(("2_ppdOpen: Adding to group %s...", group
->text
));
788 option
= ppd_get_option(group
, keyword
);
792 option
= ppd_get_option(group
, keyword
);
796 pg
->ppd_status
= PPD_ALLOC_ERROR
;
802 * Now fill in the initial information for the option...
805 if (!strncmp(keyword
, "JCL", 3))
806 option
->section
= PPD_ORDER_JCL
;
808 option
->section
= PPD_ORDER_ANY
;
810 option
->order
= 10.0f
;
813 option
->ui
= PPD_UI_BOOLEAN
;
815 option
->ui
= PPD_UI_PICKONE
;
817 for (j
= 0; j
< ppd
->num_attrs
; j
++)
818 if (!strncmp(ppd
->attrs
[j
]->name
, "Default", 7) &&
819 !strcmp(ppd
->attrs
[j
]->name
+ 7, keyword
) &&
820 ppd
->attrs
[j
]->value
)
822 DEBUG_printf(("2_ppdOpen: Setting Default%s to %s via attribute...",
823 option
->keyword
, ppd
->attrs
[j
]->value
));
824 strlcpy(option
->defchoice
, ppd
->attrs
[j
]->value
,
825 sizeof(option
->defchoice
));
829 if (!strcmp(keyword
, "PageSize"))
830 strlcpy(option
->text
, _("Media Size"), sizeof(option
->text
));
831 else if (!strcmp(keyword
, "MediaType"))
832 strlcpy(option
->text
, _("Media Type"), sizeof(option
->text
));
833 else if (!strcmp(keyword
, "InputSlot"))
834 strlcpy(option
->text
, _("Media Source"), sizeof(option
->text
));
835 else if (!strcmp(keyword
, "ColorModel"))
836 strlcpy(option
->text
, _("Output Mode"), sizeof(option
->text
));
837 else if (!strcmp(keyword
, "Resolution"))
838 strlcpy(option
->text
, _("Resolution"), sizeof(option
->text
));
840 strlcpy(option
->text
, keyword
, sizeof(option
->text
));
844 if (!strcmp(keyword
, "LanguageLevel"))
845 ppd
->language_level
= atoi(string
);
846 else if (!strcmp(keyword
, "LanguageEncoding"))
849 * Say all PPD files are UTF-8, since we convert to UTF-8...
852 ppd
->lang_encoding
= _cupsStrAlloc("UTF-8");
853 encoding
= _ppdGetEncoding(string
);
855 else if (!strcmp(keyword
, "LanguageVersion"))
856 ppd
->lang_version
= string
;
857 else if (!strcmp(keyword
, "Manufacturer"))
858 ppd
->manufacturer
= string
;
859 else if (!strcmp(keyword
, "ModelName"))
860 ppd
->modelname
= string
;
861 else if (!strcmp(keyword
, "Protocols"))
862 ppd
->protocols
= string
;
863 else if (!strcmp(keyword
, "PCFileName"))
864 ppd
->pcfilename
= string
;
865 else if (!strcmp(keyword
, "NickName"))
867 if (encoding
!= CUPS_UTF8
)
869 cups_utf8_t utf8
[256]; /* UTF-8 version of NickName */
872 cupsCharsetToUTF8(utf8
, string
, sizeof(utf8
), encoding
);
873 ppd
->nickname
= _cupsStrAlloc((char *)utf8
);
876 ppd
->nickname
= _cupsStrAlloc(string
);
878 else if (!strcmp(keyword
, "Product"))
879 ppd
->product
= string
;
880 else if (!strcmp(keyword
, "ShortNickName"))
881 ppd
->shortnickname
= string
;
882 else if (!strcmp(keyword
, "TTRasterizer"))
883 ppd
->ttrasterizer
= string
;
884 else if (!strcmp(keyword
, "JCLBegin"))
886 ppd
->jcl_begin
= _cupsStrAlloc(string
);
887 ppd_decode(ppd
->jcl_begin
); /* Decode quoted string */
889 else if (!strcmp(keyword
, "JCLEnd"))
891 ppd
->jcl_end
= _cupsStrAlloc(string
);
892 ppd_decode(ppd
->jcl_end
); /* Decode quoted string */
894 else if (!strcmp(keyword
, "JCLToPSInterpreter"))
896 ppd
->jcl_ps
= _cupsStrAlloc(string
);
897 ppd_decode(ppd
->jcl_ps
); /* Decode quoted string */
899 else if (!strcmp(keyword
, "AccurateScreensSupport"))
900 ppd
->accurate_screens
= !strcmp(string
, "True");
901 else if (!strcmp(keyword
, "ColorDevice"))
902 ppd
->color_device
= !strcmp(string
, "True");
903 else if (!strcmp(keyword
, "ContoneOnly"))
904 ppd
->contone_only
= !strcmp(string
, "True");
905 else if (!strcmp(keyword
, "cupsFlipDuplex"))
906 ppd
->flip_duplex
= !strcmp(string
, "True");
907 else if (!strcmp(keyword
, "cupsManualCopies"))
908 ppd
->manual_copies
= !strcmp(string
, "True");
909 else if (!strcmp(keyword
, "cupsModelNumber"))
910 ppd
->model_number
= atoi(string
);
911 else if (!strcmp(keyword
, "cupsColorProfile"))
913 if (ppd
->num_profiles
== 0)
914 profile
= malloc(sizeof(ppd_profile_t
));
916 profile
= realloc(ppd
->profiles
, sizeof(ppd_profile_t
) * (size_t)(ppd
->num_profiles
+ 1));
920 pg
->ppd_status
= PPD_ALLOC_ERROR
;
925 ppd
->profiles
= profile
;
926 profile
+= ppd
->num_profiles
;
927 ppd
->num_profiles
++;
929 memset(profile
, 0, sizeof(ppd_profile_t
));
930 strlcpy(profile
->resolution
, name
, sizeof(profile
->resolution
));
931 strlcpy(profile
->media_type
, text
, sizeof(profile
->media_type
));
933 profile
->density
= (float)_cupsStrScand(string
, &sptr
, loc
);
934 profile
->gamma
= (float)_cupsStrScand(sptr
, &sptr
, loc
);
935 profile
->matrix
[0][0] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
936 profile
->matrix
[0][1] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
937 profile
->matrix
[0][2] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
938 profile
->matrix
[1][0] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
939 profile
->matrix
[1][1] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
940 profile
->matrix
[1][2] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
941 profile
->matrix
[2][0] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
942 profile
->matrix
[2][1] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
943 profile
->matrix
[2][2] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
945 else if (!strcmp(keyword
, "cupsFilter"))
947 if (ppd
->num_filters
== 0)
948 filter
= malloc(sizeof(char *));
950 filter
= realloc(ppd
->filters
, sizeof(char *) * (size_t)(ppd
->num_filters
+ 1));
954 pg
->ppd_status
= PPD_ALLOC_ERROR
;
959 ppd
->filters
= filter
;
960 filter
+= ppd
->num_filters
;
964 * Retain a copy of the filter string...
967 *filter
= _cupsStrRetain(string
);
969 else if (!strcmp(keyword
, "Throughput"))
970 ppd
->throughput
= atoi(string
);
971 else if (!strcmp(keyword
, "Font"))
974 * Add this font to the list of available fonts...
977 if (ppd
->num_fonts
== 0)
978 tempfonts
= (char **)malloc(sizeof(char *));
980 tempfonts
= (char **)realloc(ppd
->fonts
, sizeof(char *) * (size_t)(ppd
->num_fonts
+ 1));
982 if (tempfonts
== NULL
)
984 pg
->ppd_status
= PPD_ALLOC_ERROR
;
989 ppd
->fonts
= tempfonts
;
990 ppd
->fonts
[ppd
->num_fonts
] = _cupsStrAlloc(name
);
993 else if (!strncmp(keyword
, "ParamCustom", 11))
995 ppd_coption_t
*coption
; /* Custom option */
996 ppd_cparam_t
*cparam
; /* Custom parameter */
997 int corder
; /* Order number */
998 char ctype
[33], /* Data type */
999 cminimum
[65], /* Minimum value */
1000 cmaximum
[65]; /* Maximum value */
1004 * Get the custom option and parameter...
1007 if ((coption
= ppd_get_coption(ppd
, keyword
+ 11)) == NULL
)
1009 pg
->ppd_status
= PPD_ALLOC_ERROR
;
1014 if ((cparam
= ppd_get_cparam(coption
, name
, text
)) == NULL
)
1016 pg
->ppd_status
= PPD_ALLOC_ERROR
;
1022 * Get the parameter data...
1026 sscanf(string
, "%d%32s%64s%64s", &corder
, ctype
, cminimum
,
1029 pg
->ppd_status
= PPD_BAD_CUSTOM_PARAM
;
1034 cparam
->order
= corder
;
1036 if (!strcmp(ctype
, "curve"))
1038 cparam
->type
= PPD_CUSTOM_CURVE
;
1039 cparam
->minimum
.custom_curve
= (float)_cupsStrScand(cminimum
, NULL
, loc
);
1040 cparam
->maximum
.custom_curve
= (float)_cupsStrScand(cmaximum
, NULL
, loc
);
1042 else if (!strcmp(ctype
, "int"))
1044 cparam
->type
= PPD_CUSTOM_INT
;
1045 cparam
->minimum
.custom_int
= atoi(cminimum
);
1046 cparam
->maximum
.custom_int
= atoi(cmaximum
);
1048 else if (!strcmp(ctype
, "invcurve"))
1050 cparam
->type
= PPD_CUSTOM_INVCURVE
;
1051 cparam
->minimum
.custom_invcurve
= (float)_cupsStrScand(cminimum
, NULL
, loc
);
1052 cparam
->maximum
.custom_invcurve
= (float)_cupsStrScand(cmaximum
, NULL
, loc
);
1054 else if (!strcmp(ctype
, "passcode"))
1056 cparam
->type
= PPD_CUSTOM_PASSCODE
;
1057 cparam
->minimum
.custom_passcode
= atoi(cminimum
);
1058 cparam
->maximum
.custom_passcode
= atoi(cmaximum
);
1060 else if (!strcmp(ctype
, "password"))
1062 cparam
->type
= PPD_CUSTOM_PASSWORD
;
1063 cparam
->minimum
.custom_password
= atoi(cminimum
);
1064 cparam
->maximum
.custom_password
= atoi(cmaximum
);
1066 else if (!strcmp(ctype
, "points"))
1068 cparam
->type
= PPD_CUSTOM_POINTS
;
1069 cparam
->minimum
.custom_points
= (float)_cupsStrScand(cminimum
, NULL
, loc
);
1070 cparam
->maximum
.custom_points
= (float)_cupsStrScand(cmaximum
, NULL
, loc
);
1072 else if (!strcmp(ctype
, "real"))
1074 cparam
->type
= PPD_CUSTOM_REAL
;
1075 cparam
->minimum
.custom_real
= (float)_cupsStrScand(cminimum
, NULL
, loc
);
1076 cparam
->maximum
.custom_real
= (float)_cupsStrScand(cmaximum
, NULL
, loc
);
1078 else if (!strcmp(ctype
, "string"))
1080 cparam
->type
= PPD_CUSTOM_STRING
;
1081 cparam
->minimum
.custom_string
= atoi(cminimum
);
1082 cparam
->maximum
.custom_string
= atoi(cmaximum
);
1086 pg
->ppd_status
= PPD_BAD_CUSTOM_PARAM
;
1092 * Now special-case for CustomPageSize...
1095 if (!strcmp(coption
->keyword
, "PageSize"))
1097 if (!strcmp(name
, "Width"))
1099 ppd
->custom_min
[0] = cparam
->minimum
.custom_points
;
1100 ppd
->custom_max
[0] = cparam
->maximum
.custom_points
;
1102 else if (!strcmp(name
, "Height"))
1104 ppd
->custom_min
[1] = cparam
->minimum
.custom_points
;
1105 ppd
->custom_max
[1] = cparam
->maximum
.custom_points
;
1109 else if (!strcmp(keyword
, "HWMargins"))
1111 for (i
= 0, sptr
= string
; i
< 4; i
++)
1112 ppd
->custom_margins
[i
] = (float)_cupsStrScand(sptr
, &sptr
, loc
);
1114 else if (!strncmp(keyword
, "Custom", 6) && !strcmp(name
, "True") && !option
)
1116 ppd_option_t
*custom_option
; /* Custom option */
1118 DEBUG_puts("2_ppdOpen: Processing Custom option...");
1121 * Get the option and custom option...
1124 if (!ppd_get_coption(ppd
, keyword
+ 6))
1126 pg
->ppd_status
= PPD_ALLOC_ERROR
;
1131 if (option
&& !_cups_strcasecmp(option
->keyword
, keyword
+ 6))
1132 custom_option
= option
;
1134 custom_option
= ppdFindOption(ppd
, keyword
+ 6);
1139 * Add the "custom" option...
1142 if ((choice
= ppdFindChoice(custom_option
, "Custom")) == NULL
)
1143 if ((choice
= ppd_add_choice(custom_option
, "Custom")) == NULL
)
1145 DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
1147 pg
->ppd_status
= PPD_ALLOC_ERROR
;
1152 strlcpy(choice
->text
, text
[0] ? text
: _("Custom"),
1153 sizeof(choice
->text
));
1155 choice
->code
= _cupsStrAlloc(string
);
1157 if (custom_option
->section
== PPD_ORDER_JCL
)
1158 ppd_decode(choice
->code
);
1162 * Now process custom page sizes specially...
1165 if (!strcmp(keyword
, "CustomPageSize"))
1168 * Add a "Custom" page size entry...
1171 ppd
->variable_sizes
= 1;
1173 ppd_add_size(ppd
, "Custom");
1175 if (option
&& !_cups_strcasecmp(option
->keyword
, "PageRegion"))
1176 custom_option
= option
;
1178 custom_option
= ppdFindOption(ppd
, "PageRegion");
1182 if ((choice
= ppdFindChoice(custom_option
, "Custom")) == NULL
)
1183 if ((choice
= ppd_add_choice(custom_option
, "Custom")) == NULL
)
1185 DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
1187 pg
->ppd_status
= PPD_ALLOC_ERROR
;
1192 strlcpy(choice
->text
, text
[0] ? text
: _("Custom"),
1193 sizeof(choice
->text
));
1197 else if (!strcmp(keyword
, "LandscapeOrientation"))
1199 if (!strcmp(string
, "Minus90"))
1200 ppd
->landscape
= -90;
1201 else if (!strcmp(string
, "Plus90"))
1202 ppd
->landscape
= 90;
1204 else if (!strcmp(keyword
, "Emulators") && string
)
1206 for (count
= 1, sptr
= string
; sptr
!= NULL
;)
1207 if ((sptr
= strchr(sptr
, ' ')) != NULL
)
1210 while (*sptr
== ' ')
1214 ppd
->num_emulations
= count
;
1215 if ((ppd
->emulations
= calloc((size_t)count
, sizeof(ppd_emul_t
))) == NULL
)
1217 pg
->ppd_status
= PPD_ALLOC_ERROR
;
1222 for (i
= 0, sptr
= string
; i
< count
; i
++)
1224 for (nameptr
= ppd
->emulations
[i
].name
;
1225 *sptr
!= '\0' && *sptr
!= ' ';
1227 if (nameptr
< (ppd
->emulations
[i
].name
+ sizeof(ppd
->emulations
[i
].name
) - 1))
1232 while (*sptr
== ' ')
1236 else if (!strncmp(keyword
, "StartEmulator_", 14))
1240 for (i
= 0; i
< ppd
->num_emulations
; i
++)
1241 if (!strcmp(keyword
+ 14, ppd
->emulations
[i
].name
))
1243 ppd
->emulations
[i
].start
= string
;
1247 else if (!strncmp(keyword
, "StopEmulator_", 13))
1251 for (i
= 0; i
< ppd
->num_emulations
; i
++)
1252 if (!strcmp(keyword
+ 13, ppd
->emulations
[i
].name
))
1254 ppd
->emulations
[i
].stop
= string
;
1258 else if (!strcmp(keyword
, "JobPatchFile"))
1261 * CUPS STR #3421: Check for "*JobPatchFile: int: string"
1264 if (isdigit(*string
& 255))
1266 for (sptr
= string
+ 1; isdigit(*sptr
& 255); sptr
++);
1271 * Found "*JobPatchFile: int: string"...
1274 pg
->ppd_status
= PPD_BAD_VALUE
;
1280 if (!name
[0] && pg
->ppd_conform
== PPD_CONFORM_STRICT
)
1283 * Found "*JobPatchFile: string"...
1286 pg
->ppd_status
= PPD_MISSING_OPTION_KEYWORD
;
1291 if (ppd
->patches
== NULL
)
1292 ppd
->patches
= strdup(string
);
1295 temp
= realloc(ppd
->patches
, strlen(ppd
->patches
) +
1296 strlen(string
) + 1);
1299 pg
->ppd_status
= PPD_ALLOC_ERROR
;
1304 ppd
->patches
= temp
;
1306 memcpy(ppd
->patches
+ strlen(ppd
->patches
), string
, strlen(string
) + 1);
1309 else if (!strcmp(keyword
, "OpenUI"))
1312 * Don't allow nesting of options...
1315 if (option
&& pg
->ppd_conform
== PPD_CONFORM_STRICT
)
1317 pg
->ppd_status
= PPD_NESTED_OPEN_UI
;
1323 * Add an option record to the current sub-group, group, or file...
1326 DEBUG_printf(("2_ppdOpen: name=\"%s\" (%d)", name
, (int)strlen(name
)));
1329 _cups_strcpy(name
, name
+ 1); /* Eliminate leading asterisk */
1331 for (i
= (int)strlen(name
) - 1; i
> 0 && _cups_isspace(name
[i
]); i
--)
1332 name
[i
] = '\0'; /* Eliminate trailing spaces */
1334 DEBUG_printf(("2_ppdOpen: OpenUI of %s in group %s...", name
,
1335 group
? group
->text
: "(null)"));
1337 if (subgroup
!= NULL
)
1338 option
= ppd_get_option(subgroup
, name
);
1339 else if (group
== NULL
)
1341 if ((group
= ppd_get_group(ppd
, "General", _("General"), pg
,
1345 DEBUG_printf(("2_ppdOpen: Adding to group %s...", group
->text
));
1346 option
= ppd_get_option(group
, name
);
1350 option
= ppd_get_option(group
, name
);
1354 pg
->ppd_status
= PPD_ALLOC_ERROR
;
1360 * Now fill in the initial information for the option...
1363 if (string
&& !strcmp(string
, "PickMany"))
1364 option
->ui
= PPD_UI_PICKMANY
;
1365 else if (string
&& !strcmp(string
, "Boolean"))
1366 option
->ui
= PPD_UI_BOOLEAN
;
1367 else if (string
&& !strcmp(string
, "PickOne"))
1368 option
->ui
= PPD_UI_PICKONE
;
1369 else if (pg
->ppd_conform
== PPD_CONFORM_STRICT
)
1371 pg
->ppd_status
= PPD_BAD_OPEN_UI
;
1376 option
->ui
= PPD_UI_PICKONE
;
1378 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1379 if (!strncmp(ppd
->attrs
[j
]->name
, "Default", 7) &&
1380 !strcmp(ppd
->attrs
[j
]->name
+ 7, name
) &&
1381 ppd
->attrs
[j
]->value
)
1383 DEBUG_printf(("2_ppdOpen: Setting Default%s to %s via attribute...",
1384 option
->keyword
, ppd
->attrs
[j
]->value
));
1385 strlcpy(option
->defchoice
, ppd
->attrs
[j
]->value
,
1386 sizeof(option
->defchoice
));
1391 cupsCharsetToUTF8((cups_utf8_t
*)option
->text
, text
,
1392 sizeof(option
->text
), encoding
);
1395 if (!strcmp(name
, "PageSize"))
1396 strlcpy(option
->text
, _("Media Size"), sizeof(option
->text
));
1397 else if (!strcmp(name
, "MediaType"))
1398 strlcpy(option
->text
, _("Media Type"), sizeof(option
->text
));
1399 else if (!strcmp(name
, "InputSlot"))
1400 strlcpy(option
->text
, _("Media Source"), sizeof(option
->text
));
1401 else if (!strcmp(name
, "ColorModel"))
1402 strlcpy(option
->text
, _("Output Mode"), sizeof(option
->text
));
1403 else if (!strcmp(name
, "Resolution"))
1404 strlcpy(option
->text
, _("Resolution"), sizeof(option
->text
));
1406 strlcpy(option
->text
, name
, sizeof(option
->text
));
1409 option
->section
= PPD_ORDER_ANY
;
1411 _cupsStrFree(string
);
1415 * Add a custom option choice if we have already seen a CustomFoo
1419 if (!_cups_strcasecmp(name
, "PageRegion"))
1420 strlcpy(custom_name
, "CustomPageSize", sizeof(custom_name
));
1422 snprintf(custom_name
, sizeof(custom_name
), "Custom%s", name
);
1424 if ((custom_attr
= ppdFindAttr(ppd
, custom_name
, "True")) != NULL
)
1426 if ((choice
= ppdFindChoice(option
, "Custom")) == NULL
)
1427 if ((choice
= ppd_add_choice(option
, "Custom")) == NULL
)
1429 DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
1431 pg
->ppd_status
= PPD_ALLOC_ERROR
;
1436 strlcpy(choice
->text
,
1437 custom_attr
->text
[0] ? custom_attr
->text
: _("Custom"),
1438 sizeof(choice
->text
));
1439 choice
->code
= _cupsStrRetain(custom_attr
->value
);
1442 else if (!strcmp(keyword
, "JCLOpenUI"))
1445 * Don't allow nesting of options...
1448 if (option
&& pg
->ppd_conform
== PPD_CONFORM_STRICT
)
1450 pg
->ppd_status
= PPD_NESTED_OPEN_UI
;
1456 * Find the JCL group, and add if needed...
1459 group
= ppd_get_group(ppd
, "JCL", _("JCL"), pg
, encoding
);
1465 * Add an option record to the current JCLs...
1469 _cups_strcpy(name
, name
+ 1);
1471 option
= ppd_get_option(group
, name
);
1475 pg
->ppd_status
= PPD_ALLOC_ERROR
;
1481 * Now fill in the initial information for the option...
1484 if (string
&& !strcmp(string
, "PickMany"))
1485 option
->ui
= PPD_UI_PICKMANY
;
1486 else if (string
&& !strcmp(string
, "Boolean"))
1487 option
->ui
= PPD_UI_BOOLEAN
;
1488 else if (string
&& !strcmp(string
, "PickOne"))
1489 option
->ui
= PPD_UI_PICKONE
;
1492 pg
->ppd_status
= PPD_BAD_OPEN_UI
;
1497 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1498 if (!strncmp(ppd
->attrs
[j
]->name
, "Default", 7) &&
1499 !strcmp(ppd
->attrs
[j
]->name
+ 7, name
) &&
1500 ppd
->attrs
[j
]->value
)
1502 DEBUG_printf(("2_ppdOpen: Setting Default%s to %s via attribute...",
1503 option
->keyword
, ppd
->attrs
[j
]->value
));
1504 strlcpy(option
->defchoice
, ppd
->attrs
[j
]->value
,
1505 sizeof(option
->defchoice
));
1510 cupsCharsetToUTF8((cups_utf8_t
*)option
->text
, text
,
1511 sizeof(option
->text
), encoding
);
1513 strlcpy(option
->text
, name
, sizeof(option
->text
));
1515 option
->section
= PPD_ORDER_JCL
;
1518 _cupsStrFree(string
);
1522 * Add a custom option choice if we have already seen a CustomFoo
1526 snprintf(custom_name
, sizeof(custom_name
), "Custom%s", name
);
1528 if ((custom_attr
= ppdFindAttr(ppd
, custom_name
, "True")) != NULL
)
1530 if ((choice
= ppd_add_choice(option
, "Custom")) == NULL
)
1532 DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
1534 pg
->ppd_status
= PPD_ALLOC_ERROR
;
1539 strlcpy(choice
->text
,
1540 custom_attr
->text
[0] ? custom_attr
->text
: _("Custom"),
1541 sizeof(choice
->text
));
1542 choice
->code
= _cupsStrRetain(custom_attr
->value
);
1545 else if (!strcmp(keyword
, "CloseUI") || !strcmp(keyword
, "JCLCloseUI"))
1549 _cupsStrFree(string
);
1552 else if (!strcmp(keyword
, "OpenGroup"))
1555 * Open a new group...
1560 pg
->ppd_status
= PPD_NESTED_OPEN_GROUP
;
1567 pg
->ppd_status
= PPD_BAD_OPEN_GROUP
;
1573 * Separate the group name from the text (name/text)...
1576 if ((sptr
= strchr(string
, '/')) != NULL
)
1582 * Fix up the text...
1588 * Find/add the group...
1591 group
= ppd_get_group(ppd
, string
, sptr
, pg
, encoding
);
1596 _cupsStrFree(string
);
1599 else if (!strcmp(keyword
, "CloseGroup"))
1603 _cupsStrFree(string
);
1606 else if (!strcmp(keyword
, "OrderDependency"))
1608 order
= (float)_cupsStrScand(string
, &sptr
, loc
);
1610 if (!sptr
|| sscanf(sptr
, "%40s%40s", name
, keyword
) != 2)
1612 pg
->ppd_status
= PPD_BAD_ORDER_DEPENDENCY
;
1617 if (keyword
[0] == '*')
1618 _cups_strcpy(keyword
, keyword
+ 1);
1620 if (!strcmp(name
, "ExitServer"))
1621 section
= PPD_ORDER_EXIT
;
1622 else if (!strcmp(name
, "Prolog"))
1623 section
= PPD_ORDER_PROLOG
;
1624 else if (!strcmp(name
, "DocumentSetup"))
1625 section
= PPD_ORDER_DOCUMENT
;
1626 else if (!strcmp(name
, "PageSetup"))
1627 section
= PPD_ORDER_PAGE
;
1628 else if (!strcmp(name
, "JCLSetup"))
1629 section
= PPD_ORDER_JCL
;
1631 section
= PPD_ORDER_ANY
;
1639 * Only valid for Non-UI options...
1642 for (i
= ppd
->num_groups
, gtemp
= ppd
->groups
; i
> 0; i
--, gtemp
++)
1643 if (gtemp
->text
[0] == '\0')
1647 for (i
= 0; i
< gtemp
->num_options
; i
++)
1648 if (!strcmp(keyword
, gtemp
->options
[i
].keyword
))
1650 gtemp
->options
[i
].section
= section
;
1651 gtemp
->options
[i
].order
= order
;
1657 option
->section
= section
;
1658 option
->order
= order
;
1661 _cupsStrFree(string
);
1664 else if (!strncmp(keyword
, "Default", 7))
1670 * Drop UI text, if any, from value...
1673 if (strchr(string
, '/') != NULL
)
1674 *strchr(string
, '/') = '\0';
1677 * Assign the default value as appropriate...
1680 if (!strcmp(keyword
, "DefaultColorSpace"))
1683 * Set default colorspace...
1686 if (!strcmp(string
, "CMY"))
1687 ppd
->colorspace
= PPD_CS_CMY
;
1688 else if (!strcmp(string
, "CMYK"))
1689 ppd
->colorspace
= PPD_CS_CMYK
;
1690 else if (!strcmp(string
, "RGB"))
1691 ppd
->colorspace
= PPD_CS_RGB
;
1692 else if (!strcmp(string
, "RGBK"))
1693 ppd
->colorspace
= PPD_CS_RGBK
;
1694 else if (!strcmp(string
, "N"))
1695 ppd
->colorspace
= PPD_CS_N
;
1697 ppd
->colorspace
= PPD_CS_GRAY
;
1699 else if (option
&& !strcmp(keyword
+ 7, option
->keyword
))
1702 * Set the default as part of the current option...
1705 DEBUG_printf(("2_ppdOpen: Setting %s to %s...", keyword
, string
));
1707 strlcpy(option
->defchoice
, string
, sizeof(option
->defchoice
));
1709 DEBUG_printf(("2_ppdOpen: %s is now %s...", keyword
, option
->defchoice
));
1714 * Lookup option and set if it has been defined...
1717 ppd_option_t
*toption
; /* Temporary option */
1720 if ((toption
= ppdFindOption(ppd
, keyword
+ 7)) != NULL
)
1722 DEBUG_printf(("2_ppdOpen: Setting %s to %s...", keyword
, string
));
1723 strlcpy(toption
->defchoice
, string
, sizeof(toption
->defchoice
));
1727 else if (!strcmp(keyword
, "UIConstraints") ||
1728 !strcmp(keyword
, "NonUIConstraints"))
1732 pg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1736 if (ppd
->num_consts
== 0)
1737 constraint
= calloc(2, sizeof(ppd_const_t
));
1739 constraint
= realloc(ppd
->consts
, (size_t)(ppd
->num_consts
+ 2) * sizeof(ppd_const_t
));
1741 if (constraint
== NULL
)
1743 pg
->ppd_status
= PPD_ALLOC_ERROR
;
1748 ppd
->consts
= constraint
;
1749 constraint
+= ppd
->num_consts
;
1752 switch (sscanf(string
, "%40s%40s%40s%40s", constraint
->option1
,
1753 constraint
->choice1
, constraint
->option2
,
1754 constraint
->choice2
))
1756 case 0 : /* Error */
1757 case 1 : /* Error */
1758 pg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1761 case 2 : /* Two options... */
1763 * Check for broken constraints like "* Option"...
1766 if (pg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1767 (!strcmp(constraint
->option1
, "*") ||
1768 !strcmp(constraint
->choice1
, "*")))
1770 pg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1775 * The following strcpy's are safe, as optionN and
1776 * choiceN are all the same size (size defined by PPD spec...)
1779 if (constraint
->option1
[0] == '*')
1780 _cups_strcpy(constraint
->option1
, constraint
->option1
+ 1);
1781 else if (pg
->ppd_conform
== PPD_CONFORM_STRICT
)
1783 pg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1787 if (constraint
->choice1
[0] == '*')
1788 _cups_strcpy(constraint
->option2
, constraint
->choice1
+ 1);
1789 else if (pg
->ppd_conform
== PPD_CONFORM_STRICT
)
1791 pg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1795 constraint
->choice1
[0] = '\0';
1796 constraint
->choice2
[0] = '\0';
1799 case 3 : /* Two options, one choice... */
1801 * Check for broken constraints like "* Option"...
1804 if (pg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1805 (!strcmp(constraint
->option1
, "*") ||
1806 !strcmp(constraint
->choice1
, "*") ||
1807 !strcmp(constraint
->option2
, "*")))
1809 pg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1814 * The following _cups_strcpy's are safe, as optionN and
1815 * choiceN are all the same size (size defined by PPD spec...)
1818 if (constraint
->option1
[0] == '*')
1819 _cups_strcpy(constraint
->option1
, constraint
->option1
+ 1);
1820 else if (pg
->ppd_conform
== PPD_CONFORM_STRICT
)
1822 pg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1826 if (constraint
->choice1
[0] == '*')
1828 if (pg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1829 constraint
->option2
[0] == '*')
1831 pg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1835 _cups_strcpy(constraint
->choice2
, constraint
->option2
);
1836 _cups_strcpy(constraint
->option2
, constraint
->choice1
+ 1);
1837 constraint
->choice1
[0] = '\0';
1841 if (constraint
->option2
[0] == '*')
1842 _cups_strcpy(constraint
->option2
, constraint
->option2
+ 1);
1843 else if (pg
->ppd_conform
== PPD_CONFORM_STRICT
)
1845 pg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1849 constraint
->choice2
[0] = '\0';
1853 case 4 : /* Two options, two choices... */
1855 * Check for broken constraints like "* Option"...
1858 if (pg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1859 (!strcmp(constraint
->option1
, "*") ||
1860 !strcmp(constraint
->choice1
, "*") ||
1861 !strcmp(constraint
->option2
, "*") ||
1862 !strcmp(constraint
->choice2
, "*")))
1864 pg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1868 if (constraint
->option1
[0] == '*')
1869 _cups_strcpy(constraint
->option1
, constraint
->option1
+ 1);
1870 else if (pg
->ppd_conform
== PPD_CONFORM_STRICT
)
1872 pg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1876 if (pg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1877 constraint
->choice1
[0] == '*')
1879 pg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1883 if (constraint
->option2
[0] == '*')
1884 _cups_strcpy(constraint
->option2
, constraint
->option2
+ 1);
1885 else if (pg
->ppd_conform
== PPD_CONFORM_STRICT
)
1887 pg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1891 if (pg
->ppd_conform
== PPD_CONFORM_STRICT
&&
1892 constraint
->choice2
[0] == '*')
1894 pg
->ppd_status
= PPD_BAD_UI_CONSTRAINTS
;
1901 * Don't add this one as an attribute...
1904 _cupsStrFree(string
);
1907 else if (!strcmp(keyword
, "PaperDimension"))
1909 if ((size
= ppdPageSize(ppd
, name
)) == NULL
)
1910 size
= ppd_add_size(ppd
, name
);
1915 * Unable to add or find size!
1918 pg
->ppd_status
= PPD_ALLOC_ERROR
;
1923 size
->width
= (float)_cupsStrScand(string
, &sptr
, loc
);
1924 size
->length
= (float)_cupsStrScand(sptr
, NULL
, loc
);
1926 _cupsStrFree(string
);
1929 else if (!strcmp(keyword
, "ImageableArea"))
1931 if ((size
= ppdPageSize(ppd
, name
)) == NULL
)
1932 size
= ppd_add_size(ppd
, name
);
1937 * Unable to add or find size!
1940 pg
->ppd_status
= PPD_ALLOC_ERROR
;
1945 size
->left
= (float)_cupsStrScand(string
, &sptr
, loc
);
1946 size
->bottom
= (float)_cupsStrScand(sptr
, &sptr
, loc
);
1947 size
->right
= (float)_cupsStrScand(sptr
, &sptr
, loc
);
1948 size
->top
= (float)_cupsStrScand(sptr
, NULL
, loc
);
1950 _cupsStrFree(string
);
1953 else if (option
!= NULL
&&
1954 (mask
& (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
)) ==
1955 (PPD_KEYWORD
| PPD_OPTION
| PPD_STRING
) &&
1956 !strcmp(keyword
, option
->keyword
))
1958 DEBUG_printf(("2_ppdOpen: group=%p, subgroup=%p", group
, subgroup
));
1960 if (!strcmp(keyword
, "PageSize"))
1963 * Add a page size...
1966 if (ppdPageSize(ppd
, name
) == NULL
)
1967 ppd_add_size(ppd
, name
);
1971 * Add the option choice...
1974 if ((choice
= ppd_add_choice(option
, name
)) == NULL
)
1976 pg
->ppd_status
= PPD_ALLOC_ERROR
;
1982 cupsCharsetToUTF8((cups_utf8_t
*)choice
->text
, text
,
1983 sizeof(choice
->text
), encoding
);
1984 else if (!strcmp(name
, "True"))
1985 strlcpy(choice
->text
, _("Yes"), sizeof(choice
->text
));
1986 else if (!strcmp(name
, "False"))
1987 strlcpy(choice
->text
, _("No"), sizeof(choice
->text
));
1989 strlcpy(choice
->text
, name
, sizeof(choice
->text
));
1991 if (option
->section
== PPD_ORDER_JCL
)
1992 ppd_decode(string
); /* Decode quoted string */
1994 choice
->code
= string
;
1995 string
= NULL
; /* Don't add as an attribute below */
1999 * Add remaining lines with keywords and string values as attributes...
2003 (mask
& (PPD_KEYWORD
| PPD_STRING
)) == (PPD_KEYWORD
| PPD_STRING
))
2004 ppd_add_attr(ppd
, keyword
, name
, text
, string
);
2006 _cupsStrFree(string
);
2010 * Check for a missing CloseGroup...
2013 if (group
&& pg
->ppd_conform
== PPD_CONFORM_STRICT
)
2015 pg
->ppd_status
= PPD_MISSING_CLOSE_GROUP
;
2019 ppd_free(line
.buffer
);
2022 * Reset language preferences...
2026 if (!cupsFileEOF(fp
))
2027 DEBUG_printf(("1_ppdOpen: Premature EOF at %lu...\n",
2028 (unsigned long)cupsFileTell(fp
)));
2031 if (pg
->ppd_status
!= PPD_OK
)
2034 * Had an error reading the PPD file, cannot continue!
2043 * Update the filters array as needed...
2046 if (!ppd_update_filters(ppd
, pg
))
2054 * Create the sorted options array and set the option back-pointer for
2055 * each choice and custom option...
2058 ppd
->options
= cupsArrayNew2((cups_array_func_t
)ppd_compare_options
, NULL
,
2059 (cups_ahash_func_t
)ppd_hash_option
,
2062 for (i
= ppd
->num_groups
, group
= ppd
->groups
;
2066 for (j
= group
->num_options
, option
= group
->options
;
2070 ppd_coption_t
*coption
; /* Custom option */
2073 cupsArrayAdd(ppd
->options
, option
);
2075 for (k
= 0; k
< option
->num_choices
; k
++)
2076 option
->choices
[k
].option
= option
;
2078 if ((coption
= ppdFindCustomOption(ppd
, option
->keyword
)) != NULL
)
2079 coption
->option
= option
;
2084 * Create an array to track the marked choices...
2087 ppd
->marked
= cupsArrayNew((cups_array_func_t
)ppd_compare_choices
, NULL
);
2090 * Return the PPD file structure...
2096 * Common exit point for errors to save code size...
2101 _cupsStrFree(string
);
2102 ppd_free(line
.buffer
);
2111 * 'ppdOpen()' - Read a PPD file into memory.
2114 ppd_file_t
* /* O - PPD file record */
2115 ppdOpen(FILE *fp
) /* I - File to read from */
2117 ppd_file_t
*ppd
; /* PPD file record */
2118 cups_file_t
*cf
; /* CUPS file */
2122 * Reopen the stdio file as a CUPS file...
2125 if ((cf
= cupsFileOpenFd(fileno(fp
), "r")) == NULL
)
2129 * Load the PPD file using the newer API...
2132 ppd
= _ppdOpen(cf
, _PPD_LOCALIZATION_DEFAULT
);
2135 * Close the CUPS file and return the PPD...
2145 * 'ppdOpen2()' - Read a PPD file into memory.
2147 * @since CUPS 1.2/macOS 10.5@
2150 ppd_file_t
* /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
2151 ppdOpen2(cups_file_t
*fp
) /* I - File to read from */
2153 return _ppdOpen(fp
, _PPD_LOCALIZATION_DEFAULT
);
2158 * 'ppdOpenFd()' - Read a PPD file into memory.
2161 ppd_file_t
* /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
2162 ppdOpenFd(int fd
) /* I - File to read from */
2164 cups_file_t
*fp
; /* CUPS file pointer */
2165 ppd_file_t
*ppd
; /* PPD file record */
2166 _ppd_globals_t
*pg
= _ppdGlobals();
2171 * Set the line number to 0...
2177 * Range check input...
2182 pg
->ppd_status
= PPD_NULL_FILE
;
2188 * Try to open the file and parse it...
2191 if ((fp
= cupsFileOpenFd(fd
, "r")) != NULL
)
2199 pg
->ppd_status
= PPD_FILE_OPEN_ERROR
;
2208 * '_ppdOpenFile()' - Read a PPD file into memory.
2211 ppd_file_t
* /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
2212 _ppdOpenFile(const char *filename
, /* I - File to read from */
2213 _ppd_localization_t localization
) /* I - Localization to load */
2215 cups_file_t
*fp
; /* File pointer */
2216 ppd_file_t
*ppd
; /* PPD file record */
2217 _ppd_globals_t
*pg
= _ppdGlobals();
2222 * Set the line number to 0...
2228 * Range check input...
2231 if (filename
== NULL
)
2233 pg
->ppd_status
= PPD_NULL_FILE
;
2239 * Try to open the file and parse it...
2242 if ((fp
= cupsFileOpen(filename
, "r")) != NULL
)
2244 ppd
= _ppdOpen(fp
, localization
);
2250 pg
->ppd_status
= PPD_FILE_OPEN_ERROR
;
2259 * 'ppdOpenFile()' - Read a PPD file into memory.
2262 ppd_file_t
* /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
2263 ppdOpenFile(const char *filename
) /* I - File to read from */
2265 return _ppdOpenFile(filename
, _PPD_LOCALIZATION_DEFAULT
);
2270 * 'ppdSetConformance()' - Set the conformance level for PPD files.
2272 * @since CUPS 1.1.20/macOS 10.4@
2276 ppdSetConformance(ppd_conform_t c
) /* I - Conformance level */
2278 _ppd_globals_t
*pg
= _ppdGlobals();
2282 pg
->ppd_conform
= c
;
2287 * 'ppd_add_attr()' - Add an attribute to the PPD data.
2290 static ppd_attr_t
* /* O - New attribute */
2291 ppd_add_attr(ppd_file_t
*ppd
, /* I - PPD file data */
2292 const char *name
, /* I - Attribute name */
2293 const char *spec
, /* I - Specifier string, if any */
2294 const char *text
, /* I - Text string, if any */
2295 const char *value
) /* I - Value of attribute */
2297 ppd_attr_t
**ptr
, /* New array */
2298 *temp
; /* New attribute */
2302 * Range check input...
2305 if (ppd
== NULL
|| name
== NULL
|| spec
== NULL
)
2309 * Create the array as needed...
2312 if (!ppd
->sorted_attrs
)
2313 ppd
->sorted_attrs
= cupsArrayNew((cups_array_func_t
)ppd_compare_attrs
,
2317 * Allocate memory for the new attribute...
2320 if (ppd
->num_attrs
== 0)
2321 ptr
= malloc(sizeof(ppd_attr_t
*));
2323 ptr
= realloc(ppd
->attrs
, (size_t)(ppd
->num_attrs
+ 1) * sizeof(ppd_attr_t
*));
2329 ptr
+= ppd
->num_attrs
;
2331 if ((temp
= calloc(1, sizeof(ppd_attr_t
))) == NULL
)
2342 strlcpy(temp
->name
, name
, sizeof(temp
->name
));
2343 strlcpy(temp
->spec
, spec
, sizeof(temp
->spec
));
2344 strlcpy(temp
->text
, text
, sizeof(temp
->text
));
2345 temp
->value
= (char *)value
;
2348 * Add the attribute to the sorted array...
2351 cupsArrayAdd(ppd
->sorted_attrs
, temp
);
2354 * Return the attribute...
2362 * 'ppd_add_choice()' - Add a choice to an option.
2365 static ppd_choice_t
* /* O - Named choice */
2366 ppd_add_choice(ppd_option_t
*option
, /* I - Option */
2367 const char *name
) /* I - Name of choice */
2369 ppd_choice_t
*choice
; /* Choice */
2372 if (option
->num_choices
== 0)
2373 choice
= malloc(sizeof(ppd_choice_t
));
2375 choice
= realloc(option
->choices
, sizeof(ppd_choice_t
) * (size_t)(option
->num_choices
+ 1));
2380 option
->choices
= choice
;
2381 choice
+= option
->num_choices
;
2382 option
->num_choices
++;
2384 memset(choice
, 0, sizeof(ppd_choice_t
));
2385 strlcpy(choice
->choice
, name
, sizeof(choice
->choice
));
2392 * 'ppd_add_size()' - Add a page size.
2395 static ppd_size_t
* /* O - Named size */
2396 ppd_add_size(ppd_file_t
*ppd
, /* I - PPD file */
2397 const char *name
) /* I - Name of size */
2399 ppd_size_t
*size
; /* Size */
2402 if (ppd
->num_sizes
== 0)
2403 size
= malloc(sizeof(ppd_size_t
));
2405 size
= realloc(ppd
->sizes
, sizeof(ppd_size_t
) * (size_t)(ppd
->num_sizes
+ 1));
2411 size
+= ppd
->num_sizes
;
2414 memset(size
, 0, sizeof(ppd_size_t
));
2415 strlcpy(size
->name
, name
, sizeof(size
->name
));
2422 * 'ppd_compare_attrs()' - Compare two attributes.
2425 static int /* O - Result of comparison */
2426 ppd_compare_attrs(ppd_attr_t
*a
, /* I - First attribute */
2427 ppd_attr_t
*b
) /* I - Second attribute */
2429 return (_cups_strcasecmp(a
->name
, b
->name
));
2434 * 'ppd_compare_choices()' - Compare two choices...
2437 static int /* O - Result of comparison */
2438 ppd_compare_choices(ppd_choice_t
*a
, /* I - First choice */
2439 ppd_choice_t
*b
) /* I - Second choice */
2441 return (strcmp(a
->option
->keyword
, b
->option
->keyword
));
2446 * 'ppd_compare_coptions()' - Compare two custom options.
2449 static int /* O - Result of comparison */
2450 ppd_compare_coptions(ppd_coption_t
*a
, /* I - First option */
2451 ppd_coption_t
*b
) /* I - Second option */
2453 return (_cups_strcasecmp(a
->keyword
, b
->keyword
));
2458 * 'ppd_compare_options()' - Compare two options.
2461 static int /* O - Result of comparison */
2462 ppd_compare_options(ppd_option_t
*a
, /* I - First option */
2463 ppd_option_t
*b
) /* I - Second option */
2465 return (_cups_strcasecmp(a
->keyword
, b
->keyword
));
2470 * 'ppd_decode()' - Decode a string value...
2473 static int /* O - Length of decoded string */
2474 ppd_decode(char *string
) /* I - String to decode */
2476 char *inptr
, /* Input pointer */
2477 *outptr
; /* Output pointer */
2483 while (*inptr
!= '\0')
2484 if (*inptr
== '<' && isxdigit(inptr
[1] & 255))
2487 * Convert hex to 8-bit values...
2491 while (isxdigit(*inptr
& 255))
2493 if (_cups_isalpha(*inptr
))
2494 *outptr
= (char)((tolower(*inptr
) - 'a' + 10) << 4);
2496 *outptr
= (char)((*inptr
- '0') << 4);
2500 if (!isxdigit(*inptr
& 255))
2503 if (_cups_isalpha(*inptr
))
2504 *outptr
|= (char)(tolower(*inptr
) - 'a' + 10);
2506 *outptr
|= (char)(*inptr
- '0');
2512 while (*inptr
!= '>' && *inptr
!= '\0')
2514 while (*inptr
== '>')
2518 *outptr
++ = *inptr
++;
2522 return ((int)(outptr
- string
));
2527 * 'ppd_free_filters()' - Free the filters array.
2531 ppd_free_filters(ppd_file_t
*ppd
) /* I - PPD file */
2533 int i
; /* Looping var */
2534 char **filter
; /* Current filter */
2537 if (ppd
->num_filters
> 0)
2539 for (i
= ppd
->num_filters
, filter
= ppd
->filters
; i
> 0; i
--, filter
++)
2540 _cupsStrFree(*filter
);
2542 ppd_free(ppd
->filters
);
2544 ppd
->num_filters
= 0;
2545 ppd
->filters
= NULL
;
2551 * 'ppd_free_group()' - Free a single UI group.
2555 ppd_free_group(ppd_group_t
*group
) /* I - Group to free */
2557 int i
; /* Looping var */
2558 ppd_option_t
*option
; /* Current option */
2559 ppd_group_t
*subgroup
; /* Current sub-group */
2562 if (group
->num_options
> 0)
2564 for (i
= group
->num_options
, option
= group
->options
;
2567 ppd_free_option(option
);
2569 ppd_free(group
->options
);
2572 if (group
->num_subgroups
> 0)
2574 for (i
= group
->num_subgroups
, subgroup
= group
->subgroups
;
2577 ppd_free_group(subgroup
);
2579 ppd_free(group
->subgroups
);
2585 * 'ppd_free_option()' - Free a single option.
2589 ppd_free_option(ppd_option_t
*option
) /* I - Option to free */
2591 int i
; /* Looping var */
2592 ppd_choice_t
*choice
; /* Current choice */
2595 if (option
->num_choices
> 0)
2597 for (i
= option
->num_choices
, choice
= option
->choices
;
2601 _cupsStrFree(choice
->code
);
2604 ppd_free(option
->choices
);
2610 * 'ppd_get_coption()' - Get a custom option record.
2613 static ppd_coption_t
* /* O - Custom option... */
2614 ppd_get_coption(ppd_file_t
*ppd
, /* I - PPD file */
2615 const char *name
) /* I - Name of option */
2617 ppd_coption_t
*copt
; /* New custom option */
2621 * See if the option already exists...
2624 if ((copt
= ppdFindCustomOption(ppd
, name
)) != NULL
)
2628 * Not found, so create the custom option record...
2631 if ((copt
= calloc(1, sizeof(ppd_coption_t
))) == NULL
)
2634 strlcpy(copt
->keyword
, name
, sizeof(copt
->keyword
));
2636 copt
->params
= cupsArrayNew((cups_array_func_t
)NULL
, NULL
);
2638 cupsArrayAdd(ppd
->coptions
, copt
);
2641 * Return the new record...
2649 * 'ppd_get_cparam()' - Get a custom parameter record.
2652 static ppd_cparam_t
* /* O - Extended option... */
2653 ppd_get_cparam(ppd_coption_t
*opt
, /* I - PPD file */
2654 const char *param
, /* I - Name of parameter */
2655 const char *text
) /* I - Human-readable text */
2657 ppd_cparam_t
*cparam
; /* New custom parameter */
2661 * See if the parameter already exists...
2664 if ((cparam
= ppdFindCustomParam(opt
, param
)) != NULL
)
2668 * Not found, so create the custom parameter record...
2671 if ((cparam
= calloc(1, sizeof(ppd_cparam_t
))) == NULL
)
2674 strlcpy(cparam
->name
, param
, sizeof(cparam
->name
));
2675 strlcpy(cparam
->text
, text
[0] ? text
: param
, sizeof(cparam
->text
));
2678 * Add this record to the array...
2681 cupsArrayAdd(opt
->params
, cparam
);
2684 * Return the new record...
2692 * 'ppd_get_group()' - Find or create the named group as needed.
2695 static ppd_group_t
* /* O - Named group */
2696 ppd_get_group(ppd_file_t
*ppd
, /* I - PPD file */
2697 const char *name
, /* I - Name of group */
2698 const char *text
, /* I - Text for group */
2699 _ppd_globals_t
*pg
, /* I - Global data */
2700 cups_encoding_t encoding
) /* I - Encoding of text */
2702 int i
; /* Looping var */
2703 ppd_group_t
*group
; /* Group */
2706 DEBUG_printf(("7ppd_get_group(ppd=%p, name=\"%s\", text=\"%s\", cg=%p)",
2707 ppd
, name
, text
, pg
));
2709 for (i
= ppd
->num_groups
, group
= ppd
->groups
; i
> 0; i
--, group
++)
2710 if (!strcmp(group
->name
, name
))
2715 DEBUG_printf(("8ppd_get_group: Adding group %s...", name
));
2717 if (pg
->ppd_conform
== PPD_CONFORM_STRICT
&& strlen(text
) >= sizeof(group
->text
))
2719 pg
->ppd_status
= PPD_ILLEGAL_TRANSLATION
;
2724 if (ppd
->num_groups
== 0)
2725 group
= malloc(sizeof(ppd_group_t
));
2727 group
= realloc(ppd
->groups
, (size_t)(ppd
->num_groups
+ 1) * sizeof(ppd_group_t
));
2731 pg
->ppd_status
= PPD_ALLOC_ERROR
;
2736 ppd
->groups
= group
;
2737 group
+= ppd
->num_groups
;
2740 memset(group
, 0, sizeof(ppd_group_t
));
2741 strlcpy(group
->name
, name
, sizeof(group
->name
));
2743 cupsCharsetToUTF8((cups_utf8_t
*)group
->text
, text
,
2744 sizeof(group
->text
), encoding
);
2752 * 'ppd_get_option()' - Find or create the named option as needed.
2755 static ppd_option_t
* /* O - Named option */
2756 ppd_get_option(ppd_group_t
*group
, /* I - Group */
2757 const char *name
) /* I - Name of option */
2759 int i
; /* Looping var */
2760 ppd_option_t
*option
; /* Option */
2763 DEBUG_printf(("7ppd_get_option(group=%p(\"%s\"), name=\"%s\")",
2764 group
, group
->name
, name
));
2766 for (i
= group
->num_options
, option
= group
->options
; i
> 0; i
--, option
++)
2767 if (!strcmp(option
->keyword
, name
))
2772 if (group
->num_options
== 0)
2773 option
= malloc(sizeof(ppd_option_t
));
2775 option
= realloc(group
->options
, (size_t)(group
->num_options
+ 1) * sizeof(ppd_option_t
));
2780 group
->options
= option
;
2781 option
+= group
->num_options
;
2782 group
->num_options
++;
2784 memset(option
, 0, sizeof(ppd_option_t
));
2785 strlcpy(option
->keyword
, name
, sizeof(option
->keyword
));
2793 * 'ppd_globals_alloc()' - Allocate and initialize global data.
2796 static _ppd_globals_t
* /* O - Pointer to global data */
2797 ppd_globals_alloc(void)
2799 return ((_ppd_globals_t
*)calloc(1, sizeof(_ppd_globals_t
)));
2804 * 'ppd_globals_free()' - Free global data.
2807 #if defined(HAVE_PTHREAD_H) || defined(WIN32)
2809 ppd_globals_free(_ppd_globals_t
*pg
) /* I - Pointer to global data */
2813 #endif /* HAVE_PTHREAD_H || WIN32 */
2816 #ifdef HAVE_PTHREAD_H
2818 * 'ppd_globals_init()' - Initialize per-thread globals...
2822 ppd_globals_init(void)
2825 * Register the global data for this thread...
2828 pthread_key_create(&ppd_globals_key
, (void (*)(void *))ppd_globals_free
);
2830 #endif /* HAVE_PTHREAD_H */
2834 * 'ppd_hash_option()' - Generate a hash of the option name...
2837 static int /* O - Hash index */
2838 ppd_hash_option(ppd_option_t
*option
) /* I - Option */
2840 int hash
= 0; /* Hash index */
2841 const char *k
; /* Pointer into keyword */
2844 for (hash
= option
->keyword
[0], k
= option
->keyword
+ 1; *k
;)
2845 hash
= 33 * hash
+ *k
++;
2847 return (hash
& 511);
2852 * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
2856 static int /* O - Bitmask of fields read */
2857 ppd_read(cups_file_t
*fp
, /* I - File to read from */
2858 _ppd_line_t
*line
, /* I - Line buffer */
2859 char *keyword
, /* O - Keyword from line */
2860 char *option
, /* O - Option from line */
2861 char *text
, /* O - Human-readable text from line */
2862 char **string
, /* O - Code/string data */
2863 int ignoreblank
, /* I - Ignore blank lines? */
2864 _ppd_globals_t
*pg
) /* I - Global data */
2866 int ch
, /* Character from file */
2867 col
, /* Column in line */
2868 colon
, /* Colon seen? */
2869 endquote
, /* Waiting for an end quote */
2870 mask
, /* Mask to be returned */
2871 startline
, /* Start line */
2872 textlen
; /* Length of text */
2873 char *keyptr
, /* Keyword pointer */
2874 *optptr
, /* Option pointer */
2875 *textptr
, /* Text pointer */
2876 *strptr
, /* Pointer into string */
2877 *lineptr
; /* Current position in line buffer */
2881 * Now loop until we have a valid line...
2886 startline
= pg
->ppd_line
+ 1;
2890 line
->bufsize
= 1024;
2891 line
->buffer
= malloc(1024);
2903 lineptr
= line
->buffer
;
2907 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
2909 if (lineptr
>= (line
->buffer
+ line
->bufsize
- 1))
2912 * Expand the line buffer...
2915 char *temp
; /* Temporary line pointer */
2918 line
->bufsize
+= 1024;
2919 if (line
->bufsize
> 262144)
2922 * Don't allow lines longer than 256k!
2925 pg
->ppd_line
= startline
;
2926 pg
->ppd_status
= PPD_LINE_TOO_LONG
;
2931 temp
= realloc(line
->buffer
, line
->bufsize
);
2934 pg
->ppd_line
= startline
;
2935 pg
->ppd_status
= PPD_LINE_TOO_LONG
;
2940 lineptr
= temp
+ (lineptr
- line
->buffer
);
2941 line
->buffer
= temp
;
2944 if (ch
== '\r' || ch
== '\n')
2947 * Line feed or carriage return...
2956 * Check for a trailing line feed...
2959 if ((ch
= cupsFilePeekChar(fp
)) == EOF
)
2966 cupsFileGetChar(fp
);
2969 if (lineptr
== line
->buffer
&& ignoreblank
)
2970 continue; /* Skip blank lines */
2974 if (!endquote
) /* Continue for multi-line text */
2979 else if (ch
< ' ' && ch
!= '\t' && pg
->ppd_conform
== PPD_CONFORM_STRICT
)
2982 * Other control characters...
2985 pg
->ppd_line
= startline
;
2986 pg
->ppd_status
= PPD_ILLEGAL_CHARACTER
;
2990 else if (ch
!= 0x1a)
2993 * Any other character...
2996 *lineptr
++ = (char)ch
;
2999 if (col
> (PPD_MAX_LINE
- 1))
3002 * Line is too long...
3005 pg
->ppd_line
= startline
;
3006 pg
->ppd_status
= PPD_LINE_TOO_LONG
;
3011 if (ch
== ':' && strncmp(line
->buffer
, "*%", 2) != 0)
3014 if (ch
== '\"' && colon
)
3015 endquote
= !endquote
;
3022 * Didn't finish this quoted string...
3025 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
3028 else if (ch
== '\r' || ch
== '\n')
3036 * Check for a trailing line feed...
3039 if ((ch
= cupsFilePeekChar(fp
)) == EOF
)
3042 cupsFileGetChar(fp
);
3045 else if (ch
< ' ' && ch
!= '\t' && pg
->ppd_conform
== PPD_CONFORM_STRICT
)
3048 * Other control characters...
3051 pg
->ppd_line
= startline
;
3052 pg
->ppd_status
= PPD_ILLEGAL_CHARACTER
;
3056 else if (ch
!= 0x1a)
3060 if (col
> (PPD_MAX_LINE
- 1))
3063 * Line is too long...
3066 pg
->ppd_line
= startline
;
3067 pg
->ppd_status
= PPD_LINE_TOO_LONG
;
3077 * Didn't finish this line...
3080 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
3081 if (ch
== '\r' || ch
== '\n')
3084 * Line feed or carriage return...
3093 * Check for a trailing line feed...
3096 if ((ch
= cupsFilePeekChar(fp
)) == EOF
)
3099 cupsFileGetChar(fp
);
3104 else if (ch
< ' ' && ch
!= '\t' && pg
->ppd_conform
== PPD_CONFORM_STRICT
)
3107 * Other control characters...
3110 pg
->ppd_line
= startline
;
3111 pg
->ppd_status
= PPD_ILLEGAL_CHARACTER
;
3115 else if (ch
!= 0x1a)
3119 if (col
> (PPD_MAX_LINE
- 1))
3122 * Line is too long...
3125 pg
->ppd_line
= startline
;
3126 pg
->ppd_status
= PPD_LINE_TOO_LONG
;
3133 if (lineptr
> line
->buffer
&& lineptr
[-1] == '\n')
3138 DEBUG_printf(("9ppd_read: LINE=\"%s\"", line
->buffer
));
3141 * The dynamically created PPDs for older style macOS
3142 * drivers include a large blob of data inserted as comments
3143 * at the end of the file. As an optimization we can stop
3144 * reading the PPD when we get to the start of this data.
3147 if (!strcmp(line
->buffer
, "*%APLWORKSET START"))
3150 if (ch
== EOF
&& lineptr
== line
->buffer
)
3158 lineptr
= line
->buffer
+ 1;
3165 if ((!line
->buffer
[0] || /* Blank line */
3166 !strncmp(line
->buffer
, "*%", 2) || /* Comment line */
3167 !strcmp(line
->buffer
, "*End")) && /* End of multi-line string */
3168 ignoreblank
) /* Ignore these? */
3170 startline
= pg
->ppd_line
+ 1;
3174 if (!strcmp(line
->buffer
, "*")) /* (Bad) comment line */
3176 if (pg
->ppd_conform
== PPD_CONFORM_RELAXED
)
3178 startline
= pg
->ppd_line
+ 1;
3183 pg
->ppd_line
= startline
;
3184 pg
->ppd_status
= PPD_ILLEGAL_MAIN_KEYWORD
;
3190 if (line
->buffer
[0] != '*') /* All lines start with an asterisk */
3193 * Allow lines consisting of just whitespace...
3196 for (lineptr
= line
->buffer
; *lineptr
; lineptr
++)
3197 if (*lineptr
&& !_cups_isspace(*lineptr
))
3202 pg
->ppd_status
= PPD_MISSING_ASTERISK
;
3205 else if (ignoreblank
)
3217 while (*lineptr
&& *lineptr
!= ':' && !_cups_isspace(*lineptr
))
3219 if (*lineptr
<= ' ' || *lineptr
> 126 || *lineptr
== '/' ||
3220 (keyptr
- keyword
) >= (PPD_MAX_NAME
- 1))
3222 pg
->ppd_status
= PPD_ILLEGAL_MAIN_KEYWORD
;
3226 *keyptr
++ = *lineptr
++;
3231 if (!strcmp(keyword
, "End"))
3234 mask
|= PPD_KEYWORD
;
3236 if (_cups_isspace(*lineptr
))
3239 * Get an option name...
3242 while (_cups_isspace(*lineptr
))
3247 while (*lineptr
&& !_cups_isspace(*lineptr
) && *lineptr
!= ':' &&
3250 if (*lineptr
<= ' ' || *lineptr
> 126 ||
3251 (optptr
- option
) >= (PPD_MAX_NAME
- 1))
3253 pg
->ppd_status
= PPD_ILLEGAL_OPTION_KEYWORD
;
3257 *optptr
++ = *lineptr
++;
3262 if (_cups_isspace(*lineptr
) && pg
->ppd_conform
== PPD_CONFORM_STRICT
)
3264 pg
->ppd_status
= PPD_ILLEGAL_WHITESPACE
;
3268 while (_cups_isspace(*lineptr
))
3273 if (*lineptr
== '/')
3276 * Get human-readable text...
3283 while (*lineptr
!= '\0' && *lineptr
!= '\n' && *lineptr
!= ':')
3285 if (((unsigned char)*lineptr
< ' ' && *lineptr
!= '\t') ||
3286 (textptr
- text
) >= (PPD_MAX_LINE
- 1))
3288 pg
->ppd_status
= PPD_ILLEGAL_TRANSLATION
;
3292 *textptr
++ = *lineptr
++;
3296 textlen
= ppd_decode(text
);
3298 if (textlen
> PPD_MAX_TEXT
&& pg
->ppd_conform
== PPD_CONFORM_STRICT
)
3300 pg
->ppd_status
= PPD_ILLEGAL_TRANSLATION
;
3308 if (_cups_isspace(*lineptr
) && pg
->ppd_conform
== PPD_CONFORM_STRICT
)
3310 pg
->ppd_status
= PPD_ILLEGAL_WHITESPACE
;
3314 while (_cups_isspace(*lineptr
))
3317 if (*lineptr
== ':')
3320 * Get string after triming leading and trailing whitespace...
3324 while (_cups_isspace(*lineptr
))
3327 strptr
= lineptr
+ strlen(lineptr
) - 1;
3328 while (strptr
>= lineptr
&& _cups_isspace(*strptr
))
3331 if (*strptr
== '\"')
3334 * Quoted string by itself, remove quotes...
3341 *string
= _cupsStrAlloc(lineptr
);
3353 * 'ppd_update_filters()' - Update the filters array as needed.
3355 * This function re-populates the filters array with cupsFilter2 entries that
3356 * have been stripped of the destination MIME media types and any maxsize hints.
3358 * (All for backwards-compatibility)
3361 static int /* O - 1 on success, 0 on failure */
3362 ppd_update_filters(ppd_file_t
*ppd
, /* I - PPD file */
3363 _ppd_globals_t
*pg
) /* I - Global data */
3365 ppd_attr_t
*attr
; /* Current cupsFilter2 value */
3366 char srcsuper
[16], /* Source MIME media type */
3368 dstsuper
[16], /* Destination MIME media type */
3370 program
[1024], /* Command to run */
3371 *ptr
, /* Pointer into command to run */
3372 buffer
[1024], /* Re-written cupsFilter value */
3373 **filter
; /* Current filter */
3374 int cost
; /* Cost of filter */
3377 DEBUG_printf(("4ppd_update_filters(ppd=%p, cg=%p)", ppd
, pg
));
3380 * See if we have any cupsFilter2 lines...
3383 if ((attr
= ppdFindAttr(ppd
, "cupsFilter2", NULL
)) == NULL
)
3385 DEBUG_puts("5ppd_update_filters: No cupsFilter2 keywords present.");
3390 * Yes, free the cupsFilter-defined filters and re-build...
3393 ppd_free_filters(ppd
);
3398 * Parse the cupsFilter2 string:
3400 * src/type dst/type cost program
3401 * src/type dst/type cost maxsize(n) program
3404 DEBUG_printf(("5ppd_update_filters: cupsFilter2=\"%s\"", attr
->value
));
3406 if (sscanf(attr
->value
, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]",
3407 srcsuper
, srctype
, dstsuper
, dsttype
, &cost
, program
) != 6)
3409 DEBUG_puts("5ppd_update_filters: Bad cupsFilter2 line.");
3410 pg
->ppd_status
= PPD_BAD_VALUE
;
3415 DEBUG_printf(("5ppd_update_filters: srcsuper=\"%s\", srctype=\"%s\", "
3416 "dstsuper=\"%s\", dsttype=\"%s\", cost=%d, program=\"%s\"",
3417 srcsuper
, srctype
, dstsuper
, dsttype
, cost
, program
));
3419 if (!strncmp(program
, "maxsize(", 8) &&
3420 (ptr
= strchr(program
+ 8, ')')) != NULL
)
3422 DEBUG_puts("5ppd_update_filters: Found maxsize(nnn).");
3425 while (_cups_isspace(*ptr
))
3428 _cups_strcpy(program
, ptr
);
3429 DEBUG_printf(("5ppd_update_filters: New program=\"%s\"", program
));
3433 * Convert to cupsFilter format:
3435 * src/type cost program
3438 snprintf(buffer
, sizeof(buffer
), "%s/%s %d %s", srcsuper
, srctype
, cost
,
3440 DEBUG_printf(("5ppd_update_filters: Adding \"%s\".", buffer
));
3443 * Add a cupsFilter-compatible string to the filters array.
3446 if (ppd
->num_filters
== 0)
3447 filter
= malloc(sizeof(char *));
3449 filter
= realloc(ppd
->filters
, sizeof(char *) * (size_t)(ppd
->num_filters
+ 1));
3453 DEBUG_puts("5ppd_update_filters: Out of memory.");
3454 pg
->ppd_status
= PPD_ALLOC_ERROR
;
3459 ppd
->filters
= filter
;
3460 filter
+= ppd
->num_filters
;
3461 ppd
->num_filters
++;
3463 *filter
= _cupsStrAlloc(buffer
);
3465 while ((attr
= ppdFindNextAttr(ppd
, "cupsFilter2", NULL
)) != NULL
);
3467 DEBUG_puts("5ppd_update_filters: Completed OK.");