X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fcups.git;a=blobdiff_plain;f=cups%2Fppd.c;h=ac5dbc62bb8d78aa8de022f8f9bb854d4525eaa8;hp=2488ff31148d519ea340776d7bb211fd52eeaafd;hb=HEAD;hpb=c5571a1d68de6e20e127c9745aa7a4dbf4e4474d diff --git a/cups/ppd.c b/cups/ppd.c index 2488ff311..ac5dbc62b 100644 --- a/cups/ppd.c +++ b/cups/ppd.c @@ -1,84 +1,28 @@ /* - * "$Id: ppd.c 7552 2008-05-12 17:42:15Z mike $" + * PPD file routines for CUPS. * - * PPD file routines for the Common UNIX Printing System (CUPS). + * Copyright © 2007-2019 by Apple Inc. + * Copyright © 1997-2007 by Easy Software Products, all rights reserved. * - * Copyright 2007-2008 by Apple Inc. - * Copyright 1997-2007 by Easy Software Products, all rights reserved. + * Licensed under Apache License v2.0. See the file "LICENSE" for more + * information. * - * These coded instructions, statements, and computer programs are the - * property of Apple Inc. and are protected by Federal copyright - * law. Distribution and use rights are outlined in the file "LICENSE.txt" - * which should have been included with this file. If this file is - * file is missing or damaged, see the license at "http://www.cups.org/". - * - * PostScript is a trademark of Adobe Systems, Inc. - * - * This code and any derivative of it may be used and distributed - * freely under the terms of the GNU General Public License when - * used with GNU Ghostscript or its derivatives. Use of the code - * (or any derivative of it) with software other than GNU - * GhostScript (or its derivatives) is governed by the CUPS license - * agreement. - * - * This file is subject to the Apple OS-Developed Software exception. - * - * Contents: - * - * ppdClose() - Free all memory used by the PPD file. - * ppdErrorString() - Returns the text assocated with a status. - * _ppdGetEncoding() - Get the CUPS encoding value for the given - * LanguageEncoding. - * ppdLastError() - Return the status from the last ppdOpen*(). - * ppdOpen() - Read a PPD file into memory. - * ppdOpen2() - Read a PPD file into memory. - * ppdOpenFd() - Read a PPD file into memory. - * ppdOpenFile() - Read a PPD file into memory. - * ppdSetConformance() - Set the conformance level for PPD files. - * ppd_add_attr() - Add an attribute to the PPD data. - * ppd_add_choice() - Add a choice to an option. - * ppd_add_size() - Add a page size. - * ppd_compare_attrs() - Compare two attributes. - * ppd_compare_choices() - Compare two choices... - * ppd_compare_coptions() - Compare two custom options. - * ppd_compare_cparams() - Compare two custom parameters. - * ppd_compare_options() - Compare two options. - * ppd_decode() - Decode a string value... - * ppd_free_group() - Free a single UI group. - * ppd_free_option() - Free a single option. - * ppd_get_coption() - Get a custom option record. - * ppd_get_cparam() - Get a custom parameter record. - * ppd_get_group() - Find or create the named group as needed. - * ppd_get_option() - Find or create the named option as needed. - * ppd_hash_option() - Generate a hash of the option name... - * ppd_read() - Read a line from a PPD file, skipping comment - * lines as necessary. + * PostScript is a trademark of Adobe Systems, Inc. */ /* * Include necessary headers. */ +#include "cups-private.h" #include "ppd-private.h" -#include "globals.h" -#include "debug.h" -#include +#include "debug-internal.h" /* * Definitions... */ -#if defined(WIN32) || defined(__EMX__) -# define READ_BINARY "rb" /* Open a binary file for reading */ -# define WRITE_BINARY "wb" /* Open a binary file for writing */ -#else -# define READ_BINARY "r" /* Open a binary file for reading */ -# define WRITE_BINARY "w" /* Open a binary file for writing */ -#endif /* WIN32 || __EMX__ */ - -#define ppd_free(p) if (p) free(p) /* Safe free macro */ - #define PPD_KEYWORD 1 /* Line contained a keyword */ #define PPD_OPTION 2 /* Line contained an option name */ #define PPD_TEXT 4 /* Line contained human-readable text */ @@ -98,6 +42,18 @@ typedef struct _ppd_line_s } _ppd_line_t; +/* + * Local globals... + */ + +static _cups_threadkey_t ppd_globals_key = _CUPS_THREADKEY_INITIALIZER; + /* Thread local storage key */ +#ifdef HAVE_PTHREAD_H +static pthread_once_t ppd_globals_key_once = PTHREAD_ONCE_INIT; + /* One-time initialization object */ +#endif /* HAVE_PTHREAD_H */ + + /* * Local functions... */ @@ -111,9 +67,9 @@ static int ppd_compare_attrs(ppd_attr_t *a, ppd_attr_t *b); static int ppd_compare_choices(ppd_choice_t *a, ppd_choice_t *b); static int ppd_compare_coptions(ppd_coption_t *a, ppd_coption_t *b); -static int ppd_compare_cparams(ppd_cparam_t *a, ppd_cparam_t *b); static int ppd_compare_options(ppd_option_t *a, ppd_option_t *b); static int ppd_decode(char *string); +static void ppd_free_filters(ppd_file_t *ppd); static void ppd_free_group(ppd_group_t *group); static void ppd_free_option(ppd_option_t *option); static ppd_coption_t *ppd_get_coption(ppd_file_t *ppd, const char *name); @@ -121,14 +77,23 @@ static ppd_cparam_t *ppd_get_cparam(ppd_coption_t *opt, const char *param, const char *text); static ppd_group_t *ppd_get_group(ppd_file_t *ppd, const char *name, - const char *text, _cups_globals_t *cg, + const char *text, _ppd_globals_t *pg, cups_encoding_t encoding); static ppd_option_t *ppd_get_option(ppd_group_t *group, const char *name); +static _ppd_globals_t *ppd_globals_alloc(void); +#if defined(HAVE_PTHREAD_H) || defined(_WIN32) +static void ppd_globals_free(_ppd_globals_t *g); +#endif /* HAVE_PTHREAD_H || _WIN32 */ +#ifdef HAVE_PTHREAD_H +static void ppd_globals_init(void); +#endif /* HAVE_PTHREAD_H */ static int ppd_hash_option(ppd_option_t *option); static int ppd_read(cups_file_t *fp, _ppd_line_t *line, char *keyword, char *option, char *text, char **string, int ignoreblank, - _cups_globals_t *cg); + _ppd_globals_t *pg); +static int ppd_update_filters(ppd_file_t *ppd, + _ppd_globals_t *pg); /* @@ -139,10 +104,8 @@ void ppdClose(ppd_file_t *ppd) /* I - PPD file record */ { int i; /* Looping var */ - ppd_emul_t *emul; /* Current emulation */ ppd_group_t *group; /* Current group */ char **font; /* Current font */ - char **filter; /* Current filter */ ppd_attr_t **attr; /* Current attribute */ ppd_coption_t *coption; /* Current custom option */ ppd_cparam_t *cparam; /* Current custom parameter */ @@ -159,27 +122,13 @@ ppdClose(ppd_file_t *ppd) /* I - PPD file record */ * Free all strings at the top level... */ - _cupsStrFree(ppd->lang_encoding); - _cupsStrFree(ppd->nickname); - _cupsStrFree(ppd->patches); - _cupsStrFree(ppd->jcl_begin); - _cupsStrFree(ppd->jcl_end); - _cupsStrFree(ppd->jcl_ps); - - /* - * Free any emulations... - */ - - if (ppd->num_emulations > 0) - { - for (i = ppd->num_emulations, emul = ppd->emulations; i > 0; i --, emul ++) - { - _cupsStrFree(emul->start); - _cupsStrFree(emul->stop); - } - - ppd_free(ppd->emulations); - } + free(ppd->lang_encoding); + free(ppd->nickname); + free(ppd->patches); + free(ppd->emulations); + free(ppd->jcl_begin); + free(ppd->jcl_end); + free(ppd->jcl_ps); /* * Free any UI groups, subgroups, and options... @@ -190,7 +139,7 @@ ppdClose(ppd_file_t *ppd) /* I - PPD file record */ for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++) ppd_free_group(group); - ppd_free(ppd->groups); + free(ppd->groups); } cupsArrayDelete(ppd->options); @@ -201,26 +150,20 @@ ppdClose(ppd_file_t *ppd) /* I - PPD file record */ */ if (ppd->num_sizes > 0) - ppd_free(ppd->sizes); + free(ppd->sizes); /* * Free any constraints... */ if (ppd->num_consts > 0) - ppd_free(ppd->consts); + free(ppd->consts); /* * Free any filters... */ - if (ppd->num_filters > 0) - { - for (i = ppd->num_filters, filter = ppd->filters; i > 0; i --, filter ++) - _cupsStrFree(*filter); - - ppd_free(ppd->filters); - } + ppd_free_filters(ppd); /* * Free any fonts... @@ -229,9 +172,9 @@ ppdClose(ppd_file_t *ppd) /* I - PPD file record */ if (ppd->num_fonts > 0) { for (i = ppd->num_fonts, font = ppd->fonts; i > 0; i --, font ++) - _cupsStrFree(*font); + free(*font); - ppd_free(ppd->fonts); + free(ppd->fonts); } /* @@ -239,7 +182,7 @@ ppdClose(ppd_file_t *ppd) /* I - PPD file record */ */ if (ppd->num_profiles > 0) - ppd_free(ppd->profiles); + free(ppd->profiles); /* * Free any attributes... @@ -249,11 +192,11 @@ ppdClose(ppd_file_t *ppd) /* I - PPD file record */ { for (i = ppd->num_attrs, attr = ppd->attrs; i > 0; i --, attr ++) { - _cupsStrFree((*attr)->value); - ppd_free(*attr); + free((*attr)->value); + free(*attr); } - ppd_free(ppd->attrs); + free(ppd->attrs); } cupsArrayDelete(ppd->sorted_attrs); @@ -275,7 +218,7 @@ ppdClose(ppd_file_t *ppd) /* I - PPD file record */ case PPD_CUSTOM_PASSCODE : case PPD_CUSTOM_PASSWORD : case PPD_CUSTOM_STRING : - _cupsStrFree(cparam->current.custom_string); + free(cparam->current.custom_string); break; default : @@ -312,18 +255,25 @@ ppdClose(ppd_file_t *ppd) /* I - PPD file record */ cupsArrayDelete(ppd->cups_uiconstraints); } + /* + * Free any PPD cache/mapping data... + */ + + if (ppd->cache) + _ppdCacheDestroy(ppd->cache); + /* * Free the whole record... */ - ppd_free(ppd); + free(ppd); } /* - * 'ppdErrorString()' - Returns the text assocated with a status. + * 'ppdErrorString()' - Returns the text associated with a status. * - * @since CUPS 1.1.19@ + * @since CUPS 1.1.19/macOS 10.3@ */ const char * /* O - Status string */ @@ -351,11 +301,16 @@ ppdErrorString(ppd_status_t status) /* I - PPD status */ _("Illegal option keyword string"), _("Illegal translation string"), _("Illegal whitespace character"), - _("Bad custom parameter") + _("Bad custom parameter"), + _("Missing option keyword"), + _("Bad value string"), + _("Missing CloseGroup"), + _("Bad CloseUI/JCLCloseUI"), + _("Missing CloseUI/JCLCloseUI") }; - if (status < PPD_OK || status > PPD_ILLEGAL_WHITESPACE) + if (status < PPD_OK || status >= PPD_MAX_STATUS) return (_cupsLangString(cupsLangDefault(), _("Unknown"))); else return (_cupsLangString(cupsLangDefault(), messages[status])); @@ -370,17 +325,17 @@ ppdErrorString(ppd_status_t status) /* I - PPD status */ cups_encoding_t /* O - CUPS encoding value */ _ppdGetEncoding(const char *name) /* I - LanguageEncoding string */ { - if (!strcasecmp(name, "ISOLatin1")) + if (!_cups_strcasecmp(name, "ISOLatin1")) return (CUPS_ISO8859_1); - else if (!strcasecmp(name, "ISOLatin2")) + else if (!_cups_strcasecmp(name, "ISOLatin2")) return (CUPS_ISO8859_2); - else if (!strcasecmp(name, "ISOLatin5")) + else if (!_cups_strcasecmp(name, "ISOLatin5")) return (CUPS_ISO8859_5); - else if (!strcasecmp(name, "JIS83-RKSJ")) - return (CUPS_WINDOWS_932); - else if (!strcasecmp(name, "MacStandard")) + else if (!_cups_strcasecmp(name, "JIS83-RKSJ")) + return (CUPS_JIS_X0213); + else if (!_cups_strcasecmp(name, "MacStandard")) return (CUPS_MAC_ROMAN); - else if (!strcasecmp(name, "WindowsANSI")) + else if (!_cups_strcasecmp(name, "WindowsANSI")) return (CUPS_WINDOWS_1252); else return (CUPS_UTF8); @@ -388,70 +343,77 @@ _ppdGetEncoding(const char *name) /* I - LanguageEncoding string */ /* - * 'ppdLastError()' - Return the status from the last ppdOpen*(). - * - * @since CUPS 1.1.19@ + * '_ppdGlobals()' - Return a pointer to thread local storage */ -ppd_status_t /* O - Status code */ -ppdLastError(int *line) /* O - Line number */ +_ppd_globals_t * /* O - Pointer to global data */ +_ppdGlobals(void) { - _cups_globals_t *cg = _cupsGlobals(); - /* Global data */ - + _ppd_globals_t *pg; /* Pointer to global data */ - if (line) - *line = cg->ppd_line; - return (cg->ppd_status); -} +#ifdef HAVE_PTHREAD_H + /* + * Initialize the global data exactly once... + */ + pthread_once(&ppd_globals_key_once, ppd_globals_init); +#endif /* HAVE_PTHREAD_H */ -/* - * 'ppdOpen()' - Read a PPD file into memory. - */ + /* + * See if we have allocated the data yet... + */ -ppd_file_t * /* O - PPD file record */ -ppdOpen(FILE *fp) /* I - File to read from */ -{ - ppd_file_t *ppd; /* PPD file record */ - cups_file_t *cf; /* CUPS file */ + if ((pg = (_ppd_globals_t *)_cupsThreadGetData(ppd_globals_key)) == NULL) + { + /* + * No, allocate memory as set the pointer for the key... + */ + if ((pg = ppd_globals_alloc()) != NULL) + _cupsThreadSetData(ppd_globals_key, pg); + } /* - * Reopen the stdio file as a CUPS file... + * Return the pointer to the data... */ - if ((cf = cupsFileOpenFd(fileno(fp), "r")) == NULL) - return (NULL); + return (pg); +} - /* - * Load the PPD file using the newer API... - */ - ppd = ppdOpen2(cf); +/* + * 'ppdLastError()' - Return the status from the last ppdOpen*(). + * + * @since CUPS 1.1.19/macOS 10.3@ + */ - /* - * Close the CUPS file and return the PPD... - */ +ppd_status_t /* O - Status code */ +ppdLastError(int *line) /* O - Line number */ +{ + _ppd_globals_t *pg = _ppdGlobals(); + /* Global data */ - cupsFileClose(cf); - return (ppd); + if (line) + *line = pg->ppd_line; + + return (pg->ppd_status); } /* - * 'ppdOpen2()' - Read a PPD file into memory. + * '_ppdOpen()' - Read a PPD file into memory. * - * @since CUPS 1.2@ + * @since CUPS 1.2/macOS 10.5@ */ ppd_file_t * /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */ -ppdOpen2(cups_file_t *fp) /* I - File to read from */ +_ppdOpen( + cups_file_t *fp, /* I - File to read from */ + _ppd_localization_t localization) /* I - Localization to load */ { int i, j, k; /* Looping vars */ - int count; /* Temporary count */ _ppd_line_t line; /* Line buffer */ ppd_file_t *ppd; /* PPD file record */ ppd_group_t *group, /* Current group */ @@ -469,22 +431,25 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ /* Human-readable text from file */ *string, /* Code/text from file */ *sptr, /* Pointer into string */ - *nameptr, /* Pointer into name */ *temp, /* Temporary string pointer */ **tempfonts; /* Temporary fonts pointer */ float order; /* Order dependency number */ ppd_section_t section; /* Order dependency section */ ppd_profile_t *profile; /* Pointer to color profile */ char **filter; /* Pointer to filter */ - cups_lang_t *language; /* Default language */ struct lconv *loc; /* Locale data */ int ui_keyword; /* Is this line a UI keyword? */ + cups_lang_t *lang; /* Language data */ cups_encoding_t encoding; /* Encoding of PPD file */ - _cups_globals_t *cg = _cupsGlobals(); + _ppd_globals_t *pg = _ppdGlobals(); /* Global data */ char custom_name[PPD_MAX_NAME]; /* CustomFoo attribute name */ ppd_attr_t *custom_attr; /* CustomFoo attribute */ + char ll[7], /* Base language + '.' */ + ll_CC[7]; /* Language w/country + '.' */ + size_t ll_len = 0, /* Base language length */ + ll_CC_len = 0; /* Language w/country length */ static const char * const ui_keywords[] = { #ifdef CUPS_USE_FULL_UI_KEYWORDS_LIST @@ -546,14 +511,21 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ "PageSize" #endif /* CUPS_USE_FULL_UI_KEYWORDS_LIST */ }; + static const char * const color_keywords[] = /* Keywords associated with color profiles */ + { + ".cupsICCProfile", + ".ColorModel", + }; + DEBUG_printf(("_ppdOpen(fp=%p)", fp)); + /* * Default to "OK" status... */ - cg->ppd_status = PPD_OK; - cg->ppd_line = 0; + pg->ppd_status = PPD_OK; + pg->ppd_line = 0; /* * Range check input... @@ -561,10 +533,55 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ if (fp == NULL) { - cg->ppd_status = PPD_NULL_FILE; + pg->ppd_status = PPD_NULL_FILE; return (NULL); } + /* + * If only loading a single localization set up the strings to match... + */ + + if (localization == _PPD_LOCALIZATION_DEFAULT) + { + if ((lang = cupsLangDefault()) == NULL) + return (NULL); + + snprintf(ll_CC, sizeof(ll_CC), "%s.", lang->language); + + /* + * + * + * + * Need to use a different base language for some locales... + */ + + if (!strcmp(lang->language, "zh_HK")) + { /* Traditional Chinese + variants */ + strlcpy(ll_CC, "zh_TW.", sizeof(ll_CC)); + strlcpy(ll, "zh_", sizeof(ll)); + } + else if (!strncmp(lang->language, "zh", 2)) + strlcpy(ll, "zh_", sizeof(ll)); /* Any Chinese variant */ + else if (!strncmp(lang->language, "jp", 2)) + { /* Any Japanese variant */ + strlcpy(ll_CC, "ja", sizeof(ll_CC)); + strlcpy(ll, "jp", sizeof(ll)); + } + else if (!strncmp(lang->language, "nb", 2) || !strncmp(lang->language, "no", 2)) + { /* Any Norwegian variant */ + strlcpy(ll_CC, "nb", sizeof(ll_CC)); + strlcpy(ll, "no", sizeof(ll)); + } + else + snprintf(ll, sizeof(ll), "%2.2s.", lang->language); + + ll_CC_len = strlen(ll_CC); + ll_len = strlen(ll); + + DEBUG_printf(("2_ppdOpen: Loading localizations matching \"%s\" and \"%s\"", + ll_CC, ll)); + } + /* * Grab the first line and make sure it reads '*PPD-Adobe: "major.minor"'... */ @@ -572,9 +589,9 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ line.buffer = NULL; line.bufsize = 0; - mask = ppd_read(fp, &line, keyword, name, text, &string, 0, cg); + mask = ppd_read(fp, &line, keyword, name, text, &string, 0, pg); - DEBUG_printf(("mask=%x, keyword=\"%s\"...\n", mask, keyword)); + DEBUG_printf(("2_ppdOpen: mask=%x, keyword=\"%s\"...", mask, keyword)); if (mask == 0 || strcmp(keyword, "PPD-Adobe") || @@ -584,18 +601,16 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ * Either this is not a PPD file, or it is not a 4.x PPD file. */ - if (cg->ppd_status == PPD_OK) - cg->ppd_status = PPD_MISSING_PPDADOBE4; + if (pg->ppd_status == PPD_OK) + pg->ppd_status = PPD_MISSING_PPDADOBE4; - _cupsStrFree(string); - ppd_free(line.buffer); + free(string); + free(line.buffer); return (NULL); } - DEBUG_printf(("ppdOpen: keyword = %s, string = %p\n", keyword, string)); - - _cupsStrFree(string); + DEBUG_printf(("2_ppdOpen: keyword=%s, string=%p", keyword, string)); /* * Allocate memory for the PPD file record... @@ -603,27 +618,22 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ if ((ppd = calloc(1, sizeof(ppd_file_t))) == NULL) { - cg->ppd_status = PPD_ALLOC_ERROR; + pg->ppd_status = PPD_ALLOC_ERROR; - _cupsStrFree(string); - ppd_free(line.buffer); + free(string); + free(line.buffer); return (NULL); } + free(string); + string = NULL; + ppd->language_level = 2; ppd->color_device = 0; ppd->colorspace = PPD_CS_N; ppd->landscape = -90; - ppd->coptions = cupsArrayNew((cups_array_func_t)ppd_compare_coptions, - NULL); - - /* - * Get the default language for the user... - */ - - language = cupsLangDefault(); - loc = localeconv(); + ppd->coptions = cupsArrayNew((cups_array_func_t)ppd_compare_coptions, NULL); /* * Read lines from the PPD file and add them to the file record... @@ -635,24 +645,27 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ choice = NULL; ui_keyword = 0; encoding = CUPS_ISO8859_1; + loc = localeconv(); - while ((mask = ppd_read(fp, &line, keyword, name, text, &string, 1, cg)) != 0) + while ((mask = ppd_read(fp, &line, keyword, name, text, &string, 1, pg)) != 0) { - DEBUG_printf(("mask=%x, keyword=\"%s\", name=\"%s\", text=\"%s\", " - "string=%d chars...", mask, keyword, name, text, + DEBUG_printf(("2_ppdOpen: mask=%x, keyword=\"%s\", name=\"%s\", " + "text=\"%s\", string=%d chars...", mask, keyword, name, text, string ? (int)strlen(string) : 0)); if (strncmp(keyword, "Default", 7) && !string && - cg->ppd_conform != PPD_CONFORM_RELAXED) + pg->ppd_conform != PPD_CONFORM_RELAXED) { /* * Need a string value! */ - cg->ppd_status = PPD_MISSING_VALUE; + pg->ppd_status = PPD_MISSING_VALUE; goto error; } + else if (!string) + continue; /* * Certain main keywords (as defined by the PPD spec) may be used @@ -673,6 +686,54 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ ui_keyword = 0; } + /* + * If we are filtering out keyword localizations, see if this line needs to + * be used... + */ + + if (localization != _PPD_LOCALIZATION_ALL && + (temp = strchr(keyword, '.')) != NULL && + ((temp - keyword) == 2 || (temp - keyword) == 5) && + _cups_isalpha(keyword[0]) && + _cups_isalpha(keyword[1]) && + (keyword[2] == '.' || + (keyword[2] == '_' && _cups_isalpha(keyword[3]) && + _cups_isalpha(keyword[4]) && keyword[5] == '.'))) + { + if (localization == _PPD_LOCALIZATION_NONE || + (localization == _PPD_LOCALIZATION_DEFAULT && + strncmp(ll_CC, keyword, ll_CC_len) && + strncmp(ll, keyword, ll_len))) + { + DEBUG_printf(("2_ppdOpen: Ignoring localization: \"%s\"\n", keyword)); + free(string); + string = NULL; + continue; + } + else if (localization == _PPD_LOCALIZATION_ICC_PROFILES) + { + /* + * Only load localizations for the color profile related keywords... + */ + + for (i = 0; + i < (int)(sizeof(color_keywords) / sizeof(color_keywords[0])); + i ++) + { + if (!_cups_strcasecmp(temp, color_keywords[i])) + break; + } + + if (i >= (int)(sizeof(color_keywords) / sizeof(color_keywords[0]))) + { + DEBUG_printf(("2_ppdOpen: Ignoring localization: \"%s\"\n", keyword)); + free(string); + string = NULL; + continue; + } + } + } + if (option == NULL && (mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) == (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) @@ -689,16 +750,16 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ ui_keyword = 1; - DEBUG_printf(("**** FOUND ADOBE UI KEYWORD %s WITHOUT OPENUI!\n", + DEBUG_printf(("2_ppdOpen: FOUND ADOBE UI KEYWORD %s WITHOUT OPENUI!", keyword)); if (!group) { - if ((group = ppd_get_group(ppd, "General", _("General"), cg, + if ((group = ppd_get_group(ppd, "General", _("General"), pg, encoding)) == NULL) goto error; - DEBUG_printf(("Adding to group %s...\n", group->text)); + DEBUG_printf(("2_ppdOpen: Adding to group %s...", group->text)); option = ppd_get_option(group, keyword); group = NULL; } @@ -707,7 +768,7 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ if (option == NULL) { - cg->ppd_status = PPD_ALLOC_ERROR; + pg->ppd_status = PPD_ALLOC_ERROR; goto error; } @@ -733,7 +794,7 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ !strcmp(ppd->attrs[j]->name + 7, keyword) && ppd->attrs[j]->value) { - DEBUG_printf(("Setting Default%s to %s via attribute...\n", + DEBUG_printf(("2_ppdOpen: Setting Default%s to %s via attribute...", option->keyword, ppd->attrs[j]->value)); strlcpy(option->defchoice, ppd->attrs[j]->value, sizeof(option->defchoice)); @@ -763,7 +824,7 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ * Say all PPD files are UTF-8, since we convert to UTF-8... */ - ppd->lang_encoding = _cupsStrAlloc("UTF-8"); + ppd->lang_encoding = strdup("UTF-8"); encoding = _ppdGetEncoding(string); } else if (!strcmp(keyword, "LanguageVersion")) @@ -784,10 +845,10 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ cupsCharsetToUTF8(utf8, string, sizeof(utf8), encoding); - ppd->nickname = _cupsStrAlloc((char *)utf8); + ppd->nickname = strdup((char *)utf8); } else - ppd->nickname = _cupsStrAlloc(string); + ppd->nickname = strdup(string); } else if (!strcmp(keyword, "Product")) ppd->product = string; @@ -797,29 +858,29 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ ppd->ttrasterizer = string; else if (!strcmp(keyword, "JCLBegin")) { - ppd->jcl_begin = _cupsStrAlloc(string); + ppd->jcl_begin = strdup(string); ppd_decode(ppd->jcl_begin); /* Decode quoted string */ } else if (!strcmp(keyword, "JCLEnd")) { - ppd->jcl_end = _cupsStrAlloc(string); + ppd->jcl_end = strdup(string); ppd_decode(ppd->jcl_end); /* Decode quoted string */ } else if (!strcmp(keyword, "JCLToPSInterpreter")) { - ppd->jcl_ps = _cupsStrAlloc(string); + ppd->jcl_ps = strdup(string); ppd_decode(ppd->jcl_ps); /* Decode quoted string */ } else if (!strcmp(keyword, "AccurateScreensSupport")) - ppd->accurate_screens = !strcmp(string, "True"); + ppd->accurate_screens = !strcasecmp(string, "True"); else if (!strcmp(keyword, "ColorDevice")) - ppd->color_device = !strcmp(string, "True"); + ppd->color_device = !strcasecmp(string, "True"); else if (!strcmp(keyword, "ContoneOnly")) - ppd->contone_only = !strcmp(string, "True"); + ppd->contone_only = !strcasecmp(string, "True"); else if (!strcmp(keyword, "cupsFlipDuplex")) - ppd->flip_duplex = !strcmp(string, "True"); + ppd->flip_duplex = !strcasecmp(string, "True"); else if (!strcmp(keyword, "cupsManualCopies")) - ppd->manual_copies = !strcmp(string, "True"); + ppd->manual_copies = !strcasecmp(string, "True"); else if (!strcmp(keyword, "cupsModelNumber")) ppd->model_number = atoi(string); else if (!strcmp(keyword, "cupsColorProfile")) @@ -827,12 +888,11 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ if (ppd->num_profiles == 0) profile = malloc(sizeof(ppd_profile_t)); else - profile = realloc(ppd->profiles, sizeof(ppd_profile_t) * - (ppd->num_profiles + 1)); + profile = realloc(ppd->profiles, sizeof(ppd_profile_t) * (size_t)(ppd->num_profiles + 1)); if (!profile) { - cg->ppd_status = PPD_ALLOC_ERROR; + pg->ppd_status = PPD_ALLOC_ERROR; goto error; } @@ -862,11 +922,11 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ if (ppd->num_filters == 0) filter = malloc(sizeof(char *)); else - filter = realloc(ppd->filters, sizeof(char *) * (ppd->num_filters + 1)); + filter = realloc(ppd->filters, sizeof(char *) * (size_t)(ppd->num_filters + 1)); if (filter == NULL) { - cg->ppd_status = PPD_ALLOC_ERROR; + pg->ppd_status = PPD_ALLOC_ERROR; goto error; } @@ -876,11 +936,10 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ ppd->num_filters ++; /* - * Copy filter string and prevent it from being freed below... + * Make a copy of the filter string... */ - *filter = string; - string = NULL; + *filter = strdup(string); } else if (!strcmp(keyword, "Throughput")) ppd->throughput = atoi(string); @@ -893,18 +952,17 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ if (ppd->num_fonts == 0) tempfonts = (char **)malloc(sizeof(char *)); else - tempfonts = (char **)realloc(ppd->fonts, - sizeof(char *) * (ppd->num_fonts + 1)); + tempfonts = (char **)realloc(ppd->fonts, sizeof(char *) * (size_t)(ppd->num_fonts + 1)); if (tempfonts == NULL) { - cg->ppd_status = PPD_ALLOC_ERROR; + pg->ppd_status = PPD_ALLOC_ERROR; goto error; } - + ppd->fonts = tempfonts; - ppd->fonts[ppd->num_fonts] = _cupsStrAlloc(name); + ppd->fonts[ppd->num_fonts] = strdup(name); ppd->num_fonts ++; } else if (!strncmp(keyword, "ParamCustom", 11)) @@ -923,26 +981,34 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ if ((coption = ppd_get_coption(ppd, keyword + 11)) == NULL) { - cg->ppd_status = PPD_ALLOC_ERROR; + pg->ppd_status = PPD_ALLOC_ERROR; goto error; } if ((cparam = ppd_get_cparam(coption, name, text)) == NULL) { - cg->ppd_status = PPD_ALLOC_ERROR; + pg->ppd_status = PPD_ALLOC_ERROR; goto error; } + if (cparam->type != PPD_CUSTOM_UNKNOWN) + { + pg->ppd_status = PPD_BAD_CUSTOM_PARAM; + + goto error; + } + /* * Get the parameter data... */ - if (sscanf(string, "%d%32s%64s%64s", &corder, ctype, cminimum, + if (!string || + sscanf(string, "%d%32s%64s%64s", &corder, ctype, cminimum, cmaximum) != 4) { - cg->ppd_status = PPD_BAD_CUSTOM_PARAM; + pg->ppd_status = PPD_BAD_CUSTOM_PARAM; goto error; } @@ -999,7 +1065,7 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ } else { - cg->ppd_status = PPD_BAD_CUSTOM_PARAM; + pg->ppd_status = PPD_BAD_CUSTOM_PARAM; goto error; } @@ -1031,7 +1097,7 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ { ppd_option_t *custom_option; /* Custom option */ - DEBUG_puts("Processing Custom option..."); + DEBUG_puts("2_ppdOpen: Processing Custom option..."); /* * Get the option and custom option... @@ -1039,12 +1105,12 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ if (!ppd_get_coption(ppd, keyword + 6)) { - cg->ppd_status = PPD_ALLOC_ERROR; + pg->ppd_status = PPD_ALLOC_ERROR; goto error; } - if (option && !strcasecmp(option->keyword, keyword + 6)) + if (option && !_cups_strcasecmp(option->keyword, keyword + 6)) custom_option = option; else custom_option = ppdFindOption(ppd, keyword + 6); @@ -1058,9 +1124,9 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ if ((choice = ppdFindChoice(custom_option, "Custom")) == NULL) if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL) { - DEBUG_puts("Unable to add Custom choice!"); + DEBUG_puts("1_ppdOpen: Unable to add Custom choice!"); - cg->ppd_status = PPD_ALLOC_ERROR; + pg->ppd_status = PPD_ALLOC_ERROR; goto error; } @@ -1068,7 +1134,7 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ strlcpy(choice->text, text[0] ? text : _("Custom"), sizeof(choice->text)); - choice->code = _cupsStrAlloc(string); + choice->code = strdup(string); if (custom_option->section == PPD_ORDER_JCL) ppd_decode(choice->code); @@ -1088,7 +1154,7 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ ppd_add_size(ppd, "Custom"); - if (option && !strcasecmp(option->keyword, "PageRegion")) + if (option && !_cups_strcasecmp(option->keyword, "PageRegion")) custom_option = option; else custom_option = ppdFindOption(ppd, "PageRegion"); @@ -1098,9 +1164,9 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ if ((choice = ppdFindChoice(custom_option, "Custom")) == NULL) if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL) { - DEBUG_puts("Unable to add Custom choice!"); + DEBUG_puts("1_ppdOpen: Unable to add Custom choice!"); - cg->ppd_status = PPD_ALLOC_ERROR; + pg->ppd_status = PPD_ALLOC_ERROR; goto error; } @@ -1117,78 +1183,73 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ else if (!strcmp(string, "Plus90")) ppd->landscape = 90; } - else if (!strcmp(keyword, "Emulators") && string) + else if (!strcmp(keyword, "Emulators") && string && ppd->num_emulations == 0) { - for (count = 1, sptr = string; sptr != NULL;) - if ((sptr = strchr(sptr, ' ')) != NULL) - { - count ++; - while (*sptr == ' ') - sptr ++; - } + /* + * Issue #5562: Samsung printer drivers incorrectly use Emulators keyword + * to configure themselves + * + * The Emulators keyword was loaded but never used by anything in CUPS, + * and has no valid purpose in CUPS. The old code was removed due to a + * memory leak (Issue #5475), so the following (new) code supports a single + * name for the Emulators keyword, allowing these drivers to work until we + * remove PPD and driver support entirely in a future version of CUPS. + */ + + ppd->num_emulations = 1; + ppd->emulations = calloc(1, sizeof(ppd_emul_t)); - ppd->num_emulations = count; - if ((ppd->emulations = calloc(count, sizeof(ppd_emul_t))) == NULL) + strlcpy(ppd->emulations[0].name, string, sizeof(ppd->emulations[0].name)); + } + else if (!strcmp(keyword, "JobPatchFile")) + { + /* + * CUPS STR #3421: Check for "*JobPatchFile: int: string" + */ + + if (isdigit(*string & 255)) { - cg->ppd_status = PPD_ALLOC_ERROR; + for (sptr = string + 1; isdigit(*sptr & 255); sptr ++); - goto error; + if (*sptr == ':') + { + /* + * Found "*JobPatchFile: int: string"... + */ + + pg->ppd_status = PPD_BAD_VALUE; + + goto error; + } } - for (i = 0, sptr = string; i < count; i ++) + if (!name[0] && pg->ppd_conform == PPD_CONFORM_STRICT) { - for (nameptr = ppd->emulations[i].name; - *sptr != '\0' && *sptr != ' '; - sptr ++) - if (nameptr < (ppd->emulations[i].name + sizeof(ppd->emulations[i].name) - 1)) - *nameptr++ = *sptr; + /* + * Found "*JobPatchFile: string"... + */ - *nameptr = '\0'; + pg->ppd_status = PPD_MISSING_OPTION_KEYWORD; - while (*sptr == ' ') - sptr ++; + goto error; } - } - else if (!strncmp(keyword, "StartEmulator_", 14)) - { - ppd_decode(string); - - for (i = 0; i < ppd->num_emulations; i ++) - if (!strcmp(keyword + 14, ppd->emulations[i].name)) - { - ppd->emulations[i].start = string; - string = NULL; - } - } - else if (!strncmp(keyword, "StopEmulator_", 13)) - { - ppd_decode(string); - for (i = 0; i < ppd->num_emulations; i ++) - if (!strcmp(keyword + 13, ppd->emulations[i].name)) - { - ppd->emulations[i].stop = string; - string = NULL; - } - } - else if (!strcmp(keyword, "JobPatchFile")) - { if (ppd->patches == NULL) - ppd->patches = _cupsStrAlloc(string); + ppd->patches = strdup(string); else { temp = realloc(ppd->patches, strlen(ppd->patches) + strlen(string) + 1); if (temp == NULL) { - cg->ppd_status = PPD_ALLOC_ERROR; + pg->ppd_status = PPD_ALLOC_ERROR; goto error; } ppd->patches = temp; - strcpy(ppd->patches + strlen(ppd->patches), string); + memcpy(ppd->patches + strlen(ppd->patches), string, strlen(string) + 1); } } else if (!strcmp(keyword, "OpenUI")) @@ -1197,9 +1258,9 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ * Don't allow nesting of options... */ - if (option && cg->ppd_conform == PPD_CONFORM_STRICT) + if (option && pg->ppd_conform == PPD_CONFORM_STRICT) { - cg->ppd_status = PPD_NESTED_OPEN_UI; + pg->ppd_status = PPD_NESTED_OPEN_UI; goto error; } @@ -1208,26 +1269,26 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ * Add an option record to the current sub-group, group, or file... */ - DEBUG_printf(("name=\"%s\" (%d)\n", name, (int)strlen(name))); + DEBUG_printf(("2_ppdOpen: name=\"%s\" (%d)", name, (int)strlen(name))); if (name[0] == '*') _cups_strcpy(name, name + 1); /* Eliminate leading asterisk */ - for (i = (int)strlen(name) - 1; i > 0 && isspace(name[i] & 255); i --) + for (i = (int)strlen(name) - 1; i > 0 && _cups_isspace(name[i]); i --) name[i] = '\0'; /* Eliminate trailing spaces */ - DEBUG_printf(("OpenUI of %s in group %s...\n", name, + DEBUG_printf(("2_ppdOpen: OpenUI of %s in group %s...", name, group ? group->text : "(null)")); if (subgroup != NULL) option = ppd_get_option(subgroup, name); else if (group == NULL) { - if ((group = ppd_get_group(ppd, "General", _("General"), cg, + if ((group = ppd_get_group(ppd, "General", _("General"), pg, encoding)) == NULL) goto error; - DEBUG_printf(("Adding to group %s...\n", group->text)); + DEBUG_printf(("2_ppdOpen: Adding to group %s...", group->text)); option = ppd_get_option(group, name); group = NULL; } @@ -1236,7 +1297,7 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ if (option == NULL) { - cg->ppd_status = PPD_ALLOC_ERROR; + pg->ppd_status = PPD_ALLOC_ERROR; goto error; } @@ -1251,9 +1312,9 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ option->ui = PPD_UI_BOOLEAN; else if (string && !strcmp(string, "PickOne")) option->ui = PPD_UI_PICKONE; - else if (cg->ppd_conform == PPD_CONFORM_STRICT) + else if (pg->ppd_conform == PPD_CONFORM_STRICT) { - cg->ppd_status = PPD_BAD_OPEN_UI; + pg->ppd_status = PPD_BAD_OPEN_UI; goto error; } @@ -1265,7 +1326,7 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ !strcmp(ppd->attrs[j]->name + 7, name) && ppd->attrs[j]->value) { - DEBUG_printf(("Setting Default%s to %s via attribute...\n", + DEBUG_printf(("2_ppdOpen: Setting Default%s to %s via attribute...", option->keyword, ppd->attrs[j]->value)); strlcpy(option->defchoice, ppd->attrs[j]->value, sizeof(option->defchoice)); @@ -1293,7 +1354,7 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ option->section = PPD_ORDER_ANY; - _cupsStrFree(string); + free(string); string = NULL; /* @@ -1301,8 +1362,8 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ * attribute... */ - if (!strcasecmp(name, "PageRegion")) - strcpy(custom_name, "CustomPageSize"); + if (!_cups_strcasecmp(name, "PageRegion")) + strlcpy(custom_name, "CustomPageSize", sizeof(custom_name)); else snprintf(custom_name, sizeof(custom_name), "Custom%s", name); @@ -1311,9 +1372,9 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ if ((choice = ppdFindChoice(option, "Custom")) == NULL) if ((choice = ppd_add_choice(option, "Custom")) == NULL) { - DEBUG_puts("Unable to add Custom choice!"); + DEBUG_puts("1_ppdOpen: Unable to add Custom choice!"); - cg->ppd_status = PPD_ALLOC_ERROR; + pg->ppd_status = PPD_ALLOC_ERROR; goto error; } @@ -1321,7 +1382,7 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ strlcpy(choice->text, custom_attr->text[0] ? custom_attr->text : _("Custom"), sizeof(choice->text)); - choice->code = _cupsStrAlloc(custom_attr->value); + choice->code = strdup(custom_attr->value); } } else if (!strcmp(keyword, "JCLOpenUI")) @@ -1330,9 +1391,9 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ * Don't allow nesting of options... */ - if (option && cg->ppd_conform == PPD_CONFORM_STRICT) + if (option && pg->ppd_conform == PPD_CONFORM_STRICT) { - cg->ppd_status = PPD_NESTED_OPEN_UI; + pg->ppd_status = PPD_NESTED_OPEN_UI; goto error; } @@ -1341,7 +1402,7 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ * Find the JCL group, and add if needed... */ - group = ppd_get_group(ppd, "JCL", _("JCL"), cg, encoding); + group = ppd_get_group(ppd, "JCL", _("JCL"), pg, encoding); if (group == NULL) goto error; @@ -1357,7 +1418,7 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ if (option == NULL) { - cg->ppd_status = PPD_ALLOC_ERROR; + pg->ppd_status = PPD_ALLOC_ERROR; goto error; } @@ -1374,7 +1435,7 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ option->ui = PPD_UI_PICKONE; else { - cg->ppd_status = PPD_BAD_OPEN_UI; + pg->ppd_status = PPD_BAD_OPEN_UI; goto error; } @@ -1384,7 +1445,7 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ !strcmp(ppd->attrs[j]->name + 7, name) && ppd->attrs[j]->value) { - DEBUG_printf(("Setting Default%s to %s via attribute...\n", + DEBUG_printf(("2_ppdOpen: Setting Default%s to %s via attribute...", option->keyword, ppd->attrs[j]->value)); strlcpy(option->defchoice, ppd->attrs[j]->value, sizeof(option->defchoice)); @@ -1400,7 +1461,7 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ option->section = PPD_ORDER_JCL; group = NULL; - _cupsStrFree(string); + free(string); string = NULL; /* @@ -1414,9 +1475,9 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ { if ((choice = ppd_add_choice(option, "Custom")) == NULL) { - DEBUG_puts("Unable to add Custom choice!"); + DEBUG_puts("1_ppdOpen: Unable to add Custom choice!"); - cg->ppd_status = PPD_ALLOC_ERROR; + pg->ppd_status = PPD_ALLOC_ERROR; goto error; } @@ -1424,14 +1485,77 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ strlcpy(choice->text, custom_attr->text[0] ? custom_attr->text : _("Custom"), sizeof(choice->text)); - choice->code = _cupsStrAlloc(custom_attr->value); + choice->code = strdup(custom_attr->value); } } - else if (!strcmp(keyword, "CloseUI") || !strcmp(keyword, "JCLCloseUI")) + else if (!strcmp(keyword, "CloseUI")) { + if ((!option || option->section == PPD_ORDER_JCL) && pg->ppd_conform == PPD_CONFORM_STRICT) + { + pg->ppd_status = PPD_BAD_CLOSE_UI; + + goto error; + } + + if (option && (!_cups_strcasecmp(option->defchoice, "custom") || !_cups_strncasecmp(option->defchoice, "custom.", 7))) + { + /* + * "*DefaultOption: Custom..." may set the default to a custom value + * or (for a very small number of incompatible PPD files) select a + * standard choice for the option, which CUPS renames to "_Custom..." + * to avoid compatibility issues. See which this is... + */ + + char tchoice[PPD_MAX_NAME]; /* Temporary choice name */ + + snprintf(tchoice, sizeof(tchoice), "_%s", option->defchoice); + + if (ppdFindChoice(option, tchoice)) + { + strlcpy(option->defchoice, tchoice, sizeof(option->defchoice)); + + DEBUG_printf(("2_ppdOpen: Reset Default%s to %s...", option->keyword, tchoice)); + } + } + option = NULL; - _cupsStrFree(string); + free(string); + string = NULL; + } + else if (!strcmp(keyword, "JCLCloseUI")) + { + if ((!option || option->section != PPD_ORDER_JCL) && pg->ppd_conform == PPD_CONFORM_STRICT) + { + pg->ppd_status = PPD_BAD_CLOSE_UI; + + goto error; + } + + if (option && (!_cups_strcasecmp(option->defchoice, "custom") || !_cups_strncasecmp(option->defchoice, "custom.", 7))) + { + /* + * "*DefaultOption: Custom..." may set the default to a custom value + * or (for a very small number of incompatible PPD files) select a + * standard choice for the option, which CUPS renames to "_Custom..." + * to avoid compatibility issues. See which this is... + */ + + char tchoice[PPD_MAX_NAME]; /* Temporary choice name */ + + snprintf(tchoice, sizeof(tchoice), "_%s", option->defchoice); + + if (ppdFindChoice(option, tchoice)) + { + strlcpy(option->defchoice, tchoice, sizeof(option->defchoice)); + + DEBUG_printf(("2_ppdOpen: Reset Default%s to %s...", option->keyword, tchoice)); + } + } + + option = NULL; + + free(string); string = NULL; } else if (!strcmp(keyword, "OpenGroup")) @@ -1442,14 +1566,14 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ if (group != NULL) { - cg->ppd_status = PPD_NESTED_OPEN_GROUP; + pg->ppd_status = PPD_NESTED_OPEN_GROUP; goto error; } if (!string) { - cg->ppd_status = PPD_BAD_OPEN_GROUP; + pg->ppd_status = PPD_BAD_OPEN_GROUP; goto error; } @@ -1473,19 +1597,19 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ * Find/add the group... */ - group = ppd_get_group(ppd, string, sptr, cg, encoding); + group = ppd_get_group(ppd, string, sptr, pg, encoding); if (group == NULL) goto error; - _cupsStrFree(string); + free(string); string = NULL; } else if (!strcmp(keyword, "CloseGroup")) { group = NULL; - _cupsStrFree(string); + free(string); string = NULL; } else if (!strcmp(keyword, "OrderDependency")) @@ -1494,7 +1618,7 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ if (!sptr || sscanf(sptr, "%40s%40s", name, keyword) != 2) { - cg->ppd_status = PPD_BAD_ORDER_DEPENDENCY; + pg->ppd_status = PPD_BAD_ORDER_DEPENDENCY; goto error; } @@ -1543,7 +1667,7 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ option->order = order; } - _cupsStrFree(string); + free(string); string = NULL; } else if (!strncmp(keyword, "Default", 7)) @@ -1587,11 +1711,9 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ * Set the default as part of the current option... */ - DEBUG_printf(("Setting %s to %s...\n", keyword, string)); - - strlcpy(option->defchoice, string, sizeof(option->defchoice)); + strlcpy(option->defchoice, string, sizeof(option->defchoice)); - DEBUG_printf(("%s is now %s...\n", keyword, option->defchoice)); + DEBUG_printf(("2_ppdOpen: Set %s to %s...", keyword, option->defchoice)); } else { @@ -1601,26 +1723,47 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ ppd_option_t *toption; /* Temporary option */ - if ((toption = ppdFindOption(ppd, keyword + 7)) != NULL) { - DEBUG_printf(("Setting %s to %s...\n", keyword, string)); - strlcpy(toption->defchoice, string, sizeof(toption->defchoice)); + if (!_cups_strcasecmp(string, "custom") || !_cups_strncasecmp(string, "custom.", 7)) + { + /* + * "*DefaultOption: Custom..." may set the default to a custom value + * or (for a very small number of incompatible PPD files) select a + * standard choice for the option, which CUPS renames to "_Custom..." + * to avoid compatibility issues. See which this is... + */ + + snprintf(toption->defchoice, sizeof(toption->defchoice), "_%s", string); + if (!ppdFindChoice(toption, toption->defchoice)) + strlcpy(toption->defchoice, string, sizeof(toption->defchoice)); + } + else + { + strlcpy(toption->defchoice, string, sizeof(toption->defchoice)); + } + + DEBUG_printf(("2_ppdOpen: Set %s to %s...", keyword, toption->defchoice)); } } } else if (!strcmp(keyword, "UIConstraints") || !strcmp(keyword, "NonUIConstraints")) { + if (!string) + { + pg->ppd_status = PPD_BAD_UI_CONSTRAINTS; + goto error; + } + if (ppd->num_consts == 0) constraint = calloc(2, sizeof(ppd_const_t)); else - constraint = realloc(ppd->consts, - (ppd->num_consts + 2) * sizeof(ppd_const_t)); + constraint = realloc(ppd->consts, (size_t)(ppd->num_consts + 2) * sizeof(ppd_const_t)); if (constraint == NULL) { - cg->ppd_status = PPD_ALLOC_ERROR; + pg->ppd_status = PPD_ALLOC_ERROR; goto error; } @@ -1633,9 +1776,8 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ constraint->choice1, constraint->option2, constraint->choice2)) { - case 0 : /* Error */ - case 1 : /* Error */ - cg->ppd_status = PPD_BAD_UI_CONSTRAINTS; + default : /* Error */ + pg->ppd_status = PPD_BAD_UI_CONSTRAINTS; goto error; case 2 : /* Two options... */ @@ -1643,11 +1785,11 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ * Check for broken constraints like "* Option"... */ - if (cg->ppd_conform == PPD_CONFORM_STRICT && + if (pg->ppd_conform == PPD_CONFORM_STRICT && (!strcmp(constraint->option1, "*") || !strcmp(constraint->choice1, "*"))) { - cg->ppd_status = PPD_BAD_UI_CONSTRAINTS; + pg->ppd_status = PPD_BAD_UI_CONSTRAINTS; goto error; } @@ -1658,35 +1800,35 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ if (constraint->option1[0] == '*') _cups_strcpy(constraint->option1, constraint->option1 + 1); - else if (cg->ppd_conform == PPD_CONFORM_STRICT) + else if (pg->ppd_conform == PPD_CONFORM_STRICT) { - cg->ppd_status = PPD_BAD_UI_CONSTRAINTS; + pg->ppd_status = PPD_BAD_UI_CONSTRAINTS; goto error; } if (constraint->choice1[0] == '*') _cups_strcpy(constraint->option2, constraint->choice1 + 1); - else if (cg->ppd_conform == PPD_CONFORM_STRICT) + else if (pg->ppd_conform == PPD_CONFORM_STRICT) { - cg->ppd_status = PPD_BAD_UI_CONSTRAINTS; + pg->ppd_status = PPD_BAD_UI_CONSTRAINTS; goto error; } constraint->choice1[0] = '\0'; constraint->choice2[0] = '\0'; break; - + case 3 : /* Two options, one choice... */ /* * Check for broken constraints like "* Option"... */ - if (cg->ppd_conform == PPD_CONFORM_STRICT && + if (pg->ppd_conform == PPD_CONFORM_STRICT && (!strcmp(constraint->option1, "*") || !strcmp(constraint->choice1, "*") || !strcmp(constraint->option2, "*"))) { - cg->ppd_status = PPD_BAD_UI_CONSTRAINTS; + pg->ppd_status = PPD_BAD_UI_CONSTRAINTS; goto error; } @@ -1697,18 +1839,18 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ if (constraint->option1[0] == '*') _cups_strcpy(constraint->option1, constraint->option1 + 1); - else if (cg->ppd_conform == PPD_CONFORM_STRICT) + else if (pg->ppd_conform == PPD_CONFORM_STRICT) { - cg->ppd_status = PPD_BAD_UI_CONSTRAINTS; + pg->ppd_status = PPD_BAD_UI_CONSTRAINTS; goto error; } if (constraint->choice1[0] == '*') { - if (cg->ppd_conform == PPD_CONFORM_STRICT && + if (pg->ppd_conform == PPD_CONFORM_STRICT && constraint->option2[0] == '*') { - cg->ppd_status = PPD_BAD_UI_CONSTRAINTS; + pg->ppd_status = PPD_BAD_UI_CONSTRAINTS; goto error; } @@ -1720,58 +1862,58 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ { if (constraint->option2[0] == '*') _cups_strcpy(constraint->option2, constraint->option2 + 1); - else if (cg->ppd_conform == PPD_CONFORM_STRICT) + else if (pg->ppd_conform == PPD_CONFORM_STRICT) { - cg->ppd_status = PPD_BAD_UI_CONSTRAINTS; + pg->ppd_status = PPD_BAD_UI_CONSTRAINTS; goto error; } constraint->choice2[0] = '\0'; } break; - + case 4 : /* Two options, two choices... */ /* * Check for broken constraints like "* Option"... */ - if (cg->ppd_conform == PPD_CONFORM_STRICT && + if (pg->ppd_conform == PPD_CONFORM_STRICT && (!strcmp(constraint->option1, "*") || !strcmp(constraint->choice1, "*") || !strcmp(constraint->option2, "*") || !strcmp(constraint->choice2, "*"))) { - cg->ppd_status = PPD_BAD_UI_CONSTRAINTS; + pg->ppd_status = PPD_BAD_UI_CONSTRAINTS; goto error; } if (constraint->option1[0] == '*') _cups_strcpy(constraint->option1, constraint->option1 + 1); - else if (cg->ppd_conform == PPD_CONFORM_STRICT) + else if (pg->ppd_conform == PPD_CONFORM_STRICT) { - cg->ppd_status = PPD_BAD_UI_CONSTRAINTS; + pg->ppd_status = PPD_BAD_UI_CONSTRAINTS; goto error; } - if (cg->ppd_conform == PPD_CONFORM_STRICT && + if (pg->ppd_conform == PPD_CONFORM_STRICT && constraint->choice1[0] == '*') { - cg->ppd_status = PPD_BAD_UI_CONSTRAINTS; + pg->ppd_status = PPD_BAD_UI_CONSTRAINTS; goto error; } if (constraint->option2[0] == '*') _cups_strcpy(constraint->option2, constraint->option2 + 1); - else if (cg->ppd_conform == PPD_CONFORM_STRICT) + else if (pg->ppd_conform == PPD_CONFORM_STRICT) { - cg->ppd_status = PPD_BAD_UI_CONSTRAINTS; + pg->ppd_status = PPD_BAD_UI_CONSTRAINTS; goto error; } - if (cg->ppd_conform == PPD_CONFORM_STRICT && + if (pg->ppd_conform == PPD_CONFORM_STRICT && constraint->choice2[0] == '*') { - cg->ppd_status = PPD_BAD_UI_CONSTRAINTS; + pg->ppd_status = PPD_BAD_UI_CONSTRAINTS; goto error; } break; @@ -1781,11 +1923,18 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ * Don't add this one as an attribute... */ - _cupsStrFree(string); + free(string); string = NULL; } else if (!strcmp(keyword, "PaperDimension")) { + if (!_cups_strcasecmp(name, "custom") || !_cups_strncasecmp(name, "custom.", 7)) + { + char cname[PPD_MAX_NAME]; /* Rewrite with a leading underscore */ + snprintf(cname, sizeof(cname), "_%s", name); + strlcpy(name, cname, sizeof(name)); + } + if ((size = ppdPageSize(ppd, name)) == NULL) size = ppd_add_size(ppd, name); @@ -1795,7 +1944,7 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ * Unable to add or find size! */ - cg->ppd_status = PPD_ALLOC_ERROR; + pg->ppd_status = PPD_ALLOC_ERROR; goto error; } @@ -1803,11 +1952,18 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ size->width = (float)_cupsStrScand(string, &sptr, loc); size->length = (float)_cupsStrScand(sptr, NULL, loc); - _cupsStrFree(string); + free(string); string = NULL; } else if (!strcmp(keyword, "ImageableArea")) { + if (!_cups_strcasecmp(name, "custom") || !_cups_strncasecmp(name, "custom.", 7)) + { + char cname[PPD_MAX_NAME]; /* Rewrite with a leading underscore */ + snprintf(cname, sizeof(cname), "_%s", name); + strlcpy(name, cname, sizeof(name)); + } + if ((size = ppdPageSize(ppd, name)) == NULL) size = ppd_add_size(ppd, name); @@ -1817,7 +1973,7 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ * Unable to add or find size! */ - cg->ppd_status = PPD_ALLOC_ERROR; + pg->ppd_status = PPD_ALLOC_ERROR; goto error; } @@ -1827,7 +1983,7 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ size->right = (float)_cupsStrScand(sptr, &sptr, loc); size->top = (float)_cupsStrScand(sptr, NULL, loc); - _cupsStrFree(string); + free(string); string = NULL; } else if (option != NULL && @@ -1835,7 +1991,14 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ (PPD_KEYWORD | PPD_OPTION | PPD_STRING) && !strcmp(keyword, option->keyword)) { - DEBUG_printf(("group = %p, subgroup = %p\n", group, subgroup)); + DEBUG_printf(("2_ppdOpen: group=%p, subgroup=%p", group, subgroup)); + + if (!_cups_strcasecmp(name, "custom") || !_cups_strncasecmp(name, "custom.", 7)) + { + char cname[PPD_MAX_NAME]; /* Rewrite with a leading underscore */ + snprintf(cname, sizeof(cname), "_%s", name); + strlcpy(name, cname, sizeof(name)); + } if (!strcmp(keyword, "PageSize")) { @@ -1853,7 +2016,7 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ if ((choice = ppd_add_choice(option, name)) == NULL) { - cg->ppd_status = PPD_ALLOC_ERROR; + pg->ppd_status = PPD_ALLOC_ERROR; goto error; } @@ -1862,9 +2025,9 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ cupsCharsetToUTF8((cups_utf8_t *)choice->text, text, sizeof(choice->text), encoding); else if (!strcmp(name, "True")) - strcpy(choice->text, _("Yes")); + strlcpy(choice->text, _("Yes"), sizeof(choice->text)); else if (!strcmp(name, "False")) - strcpy(choice->text, _("No")); + strlcpy(choice->text, _("No"), sizeof(choice->text)); else strlcpy(choice->text, name, sizeof(choice->text)); @@ -1883,24 +2046,42 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ (mask & (PPD_KEYWORD | PPD_STRING)) == (PPD_KEYWORD | PPD_STRING)) ppd_add_attr(ppd, keyword, name, text, string); else - _cupsStrFree(string); + free(string); } - ppd_free(line.buffer); + /* + * Check for a missing CloseUI/JCLCloseUI... + */ + + if (option && pg->ppd_conform == PPD_CONFORM_STRICT) + { + pg->ppd_status = PPD_MISSING_CLOSE_UI; + goto error; + } /* - * Reset language preferences... + * Check for a missing CloseGroup... */ - cupsLangFree(language); + if (group && pg->ppd_conform == PPD_CONFORM_STRICT) + { + pg->ppd_status = PPD_MISSING_CLOSE_GROUP; + goto error; + } + + free(line.buffer); + + /* + * Reset language preferences... + */ #ifdef DEBUG if (!cupsFileEOF(fp)) - DEBUG_printf(("Premature EOF at %lu...\n", + DEBUG_printf(("1_ppdOpen: Premature EOF at %lu...\n", (unsigned long)cupsFileTell(fp))); #endif /* DEBUG */ - if (cg->ppd_status != PPD_OK) + if (pg->ppd_status != PPD_OK) { /* * Had an error reading the PPD file, cannot continue! @@ -1911,6 +2092,17 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ return (NULL); } + /* + * Update the filters array as needed... + */ + + if (!ppd_update_filters(ppd, pg)) + { + ppdClose(ppd); + + return (NULL); + } + /* * Create the sorted options array and set the option back-pointer for * each choice and custom option... @@ -1959,17 +2151,62 @@ ppdOpen2(cups_file_t *fp) /* I - File to read from */ error: - _cupsStrFree(string); - ppd_free(line.buffer); + free(string); + free(line.buffer); ppdClose(ppd); - cupsLangFree(language); - return (NULL); } +/* + * 'ppdOpen()' - Read a PPD file into memory. + */ + +ppd_file_t * /* O - PPD file record */ +ppdOpen(FILE *fp) /* I - File to read from */ +{ + ppd_file_t *ppd; /* PPD file record */ + cups_file_t *cf; /* CUPS file */ + + + /* + * Reopen the stdio file as a CUPS file... + */ + + if ((cf = cupsFileOpenFd(fileno(fp), "r")) == NULL) + return (NULL); + + /* + * Load the PPD file using the newer API... + */ + + ppd = _ppdOpen(cf, _PPD_LOCALIZATION_DEFAULT); + + /* + * Close the CUPS file and return the PPD... + */ + + cupsFileClose(cf); + + return (ppd); +} + + +/* + * 'ppdOpen2()' - Read a PPD file into memory. + * + * @since CUPS 1.2/macOS 10.5@ + */ + +ppd_file_t * /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */ +ppdOpen2(cups_file_t *fp) /* I - File to read from */ +{ + return _ppdOpen(fp, _PPD_LOCALIZATION_DEFAULT); +} + + /* * 'ppdOpenFd()' - Read a PPD file into memory. */ @@ -1979,7 +2216,7 @@ ppdOpenFd(int fd) /* I - File to read from */ { cups_file_t *fp; /* CUPS file pointer */ ppd_file_t *ppd; /* PPD file record */ - _cups_globals_t *cg = _cupsGlobals(); + _ppd_globals_t *pg = _ppdGlobals(); /* Global data */ @@ -1987,7 +2224,7 @@ ppdOpenFd(int fd) /* I - File to read from */ * Set the line number to 0... */ - cg->ppd_line = 0; + pg->ppd_line = 0; /* * Range check input... @@ -1995,7 +2232,7 @@ ppdOpenFd(int fd) /* I - File to read from */ if (fd < 0) { - cg->ppd_status = PPD_NULL_FILE; + pg->ppd_status = PPD_NULL_FILE; return (NULL); } @@ -2012,7 +2249,7 @@ ppdOpenFd(int fd) /* I - File to read from */ } else { - cg->ppd_status = PPD_FILE_OPEN_ERROR; + pg->ppd_status = PPD_FILE_OPEN_ERROR; ppd = NULL; } @@ -2021,15 +2258,16 @@ ppdOpenFd(int fd) /* I - File to read from */ /* - * 'ppdOpenFile()' - Read a PPD file into memory. + * '_ppdOpenFile()' - Read a PPD file into memory. */ ppd_file_t * /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */ -ppdOpenFile(const char *filename) /* I - File to read from */ +_ppdOpenFile(const char *filename, /* I - File to read from */ + _ppd_localization_t localization) /* I - Localization to load */ { cups_file_t *fp; /* File pointer */ ppd_file_t *ppd; /* PPD file record */ - _cups_globals_t *cg = _cupsGlobals(); + _ppd_globals_t *pg = _ppdGlobals(); /* Global data */ @@ -2037,7 +2275,7 @@ ppdOpenFile(const char *filename) /* I - File to read from */ * Set the line number to 0... */ - cg->ppd_line = 0; + pg->ppd_line = 0; /* * Range check input... @@ -2045,7 +2283,7 @@ ppdOpenFile(const char *filename) /* I - File to read from */ if (filename == NULL) { - cg->ppd_status = PPD_NULL_FILE; + pg->ppd_status = PPD_NULL_FILE; return (NULL); } @@ -2056,13 +2294,13 @@ ppdOpenFile(const char *filename) /* I - File to read from */ if ((fp = cupsFileOpen(filename, "r")) != NULL) { - ppd = ppdOpen2(fp); + ppd = _ppdOpen(fp, localization); cupsFileClose(fp); } else { - cg->ppd_status = PPD_FILE_OPEN_ERROR; + pg->ppd_status = PPD_FILE_OPEN_ERROR; ppd = NULL; } @@ -2070,20 +2308,31 @@ ppdOpenFile(const char *filename) /* I - File to read from */ } +/* + * 'ppdOpenFile()' - Read a PPD file into memory. + */ + +ppd_file_t * /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */ +ppdOpenFile(const char *filename) /* I - File to read from */ +{ + return _ppdOpenFile(filename, _PPD_LOCALIZATION_DEFAULT); +} + + /* * 'ppdSetConformance()' - Set the conformance level for PPD files. * - * @since CUPS 1.1.20@ + * @since CUPS 1.1.20/macOS 10.4@ */ void ppdSetConformance(ppd_conform_t c) /* I - Conformance level */ { - _cups_globals_t *cg = _cupsGlobals(); + _ppd_globals_t *pg = _ppdGlobals(); /* Global data */ - cg->ppd_conform = c; + pg->ppd_conform = c; } @@ -2124,7 +2373,7 @@ ppd_add_attr(ppd_file_t *ppd, /* I - PPD file data */ if (ppd->num_attrs == 0) ptr = malloc(sizeof(ppd_attr_t *)); else - ptr = realloc(ppd->attrs, (ppd->num_attrs + 1) * sizeof(ppd_attr_t *)); + ptr = realloc(ppd->attrs, (size_t)(ppd->num_attrs + 1) * sizeof(ppd_attr_t *)); if (ptr == NULL) return (NULL); @@ -2143,8 +2392,16 @@ ppd_add_attr(ppd_file_t *ppd, /* I - PPD file data */ * Copy data over... */ + if (!_cups_strcasecmp(spec, "custom") || !_cups_strncasecmp(spec, "custom.", 7)) + { + temp->spec[0] = '_'; + strlcpy(temp->spec + 1, spec, sizeof(temp->spec) - 1); + } + else { + strlcpy(temp->spec, spec, sizeof(temp->spec)); + } + strlcpy(temp->name, name, sizeof(temp->name)); - strlcpy(temp->spec, spec, sizeof(temp->spec)); strlcpy(temp->text, text, sizeof(temp->text)); temp->value = (char *)value; @@ -2176,8 +2433,7 @@ ppd_add_choice(ppd_option_t *option, /* I - Option */ if (option->num_choices == 0) choice = malloc(sizeof(ppd_choice_t)); else - choice = realloc(option->choices, - sizeof(ppd_choice_t) * (option->num_choices + 1)); + choice = realloc(option->choices, sizeof(ppd_choice_t) * (size_t)(option->num_choices + 1)); if (choice == NULL) return (NULL); @@ -2207,7 +2463,7 @@ ppd_add_size(ppd_file_t *ppd, /* I - PPD file */ if (ppd->num_sizes == 0) size = malloc(sizeof(ppd_size_t)); else - size = realloc(ppd->sizes, sizeof(ppd_size_t) * (ppd->num_sizes + 1)); + size = realloc(ppd->sizes, sizeof(ppd_size_t) * (size_t)(ppd->num_sizes + 1)); if (size == NULL) return (NULL); @@ -2231,13 +2487,7 @@ static int /* O - Result of comparison */ ppd_compare_attrs(ppd_attr_t *a, /* I - First attribute */ ppd_attr_t *b) /* I - Second attribute */ { - int ret; /* Result of comparison */ - - - if ((ret = strcasecmp(a->name, b->name)) != 0) - return (ret); - else - return (strcasecmp(a->spec, b->spec)); + return (_cups_strcasecmp(a->name, b->name)); } @@ -2261,19 +2511,7 @@ static int /* O - Result of comparison */ ppd_compare_coptions(ppd_coption_t *a, /* I - First option */ ppd_coption_t *b) /* I - Second option */ { - return (strcasecmp(a->keyword, b->keyword)); -} - - -/* - * 'ppd_compare_cparams()' - Compare two custom parameters. - */ - -static int /* O - Result of comparison */ -ppd_compare_cparams(ppd_cparam_t *a, /* I - First parameter */ - ppd_cparam_t *b) /* I - Second parameter */ -{ - return (strcasecmp(a->name, b->name)); + return (_cups_strcasecmp(a->keyword, b->keyword)); } @@ -2285,7 +2523,7 @@ static int /* O - Result of comparison */ ppd_compare_options(ppd_option_t *a, /* I - First option */ ppd_option_t *b) /* I - Second option */ { - return (strcasecmp(a->keyword, b->keyword)); + return (_cups_strcasecmp(a->keyword, b->keyword)); } @@ -2313,20 +2551,20 @@ ppd_decode(char *string) /* I - String to decode */ inptr ++; while (isxdigit(*inptr & 255)) { - if (isalpha(*inptr)) - *outptr = (tolower(*inptr) - 'a' + 10) << 4; + if (_cups_isalpha(*inptr)) + *outptr = (char)((tolower(*inptr) - 'a' + 10) << 4); else - *outptr = (*inptr - '0') << 4; + *outptr = (char)((*inptr - '0') << 4); inptr ++; if (!isxdigit(*inptr & 255)) break; - if (isalpha(*inptr)) - *outptr |= tolower(*inptr) - 'a' + 10; + if (_cups_isalpha(*inptr)) + *outptr |= (char)(tolower(*inptr) - 'a' + 10); else - *outptr |= *inptr - '0'; + *outptr |= (char)(*inptr - '0'); inptr ++; outptr ++; @@ -2346,6 +2584,30 @@ ppd_decode(char *string) /* I - String to decode */ } +/* + * 'ppd_free_filters()' - Free the filters array. + */ + +static void +ppd_free_filters(ppd_file_t *ppd) /* I - PPD file */ +{ + int i; /* Looping var */ + char **filter; /* Current filter */ + + + if (ppd->num_filters > 0) + { + for (i = ppd->num_filters, filter = ppd->filters; i > 0; i --, filter ++) + free(*filter); + + free(ppd->filters); + + ppd->num_filters = 0; + ppd->filters = NULL; + } +} + + /* * 'ppd_free_group()' - Free a single UI group. */ @@ -2365,7 +2627,7 @@ ppd_free_group(ppd_group_t *group) /* I - Group to free */ i --, option ++) ppd_free_option(option); - ppd_free(group->options); + free(group->options); } if (group->num_subgroups > 0) @@ -2375,7 +2637,7 @@ ppd_free_group(ppd_group_t *group) /* I - Group to free */ i --, subgroup ++) ppd_free_group(subgroup); - ppd_free(group->subgroups); + free(group->subgroups); } } @@ -2397,10 +2659,10 @@ ppd_free_option(ppd_option_t *option) /* I - Option to free */ i > 0; i --, choice ++) { - _cupsStrFree(choice->code); + free(choice->code); } - ppd_free(option->choices); + free(option->choices); } } @@ -2432,7 +2694,7 @@ ppd_get_coption(ppd_file_t *ppd, /* I - PPD file */ strlcpy(copt->keyword, name, sizeof(copt->keyword)); - copt->params = cupsArrayNew((cups_array_func_t)ppd_compare_cparams, NULL); + copt->params = cupsArrayNew((cups_array_func_t)NULL, NULL); cupsArrayAdd(ppd->coptions, copt); @@ -2470,6 +2732,7 @@ ppd_get_cparam(ppd_coption_t *opt, /* I - PPD file */ if ((cparam = calloc(1, sizeof(ppd_cparam_t))) == NULL) return (NULL); + cparam->type = PPD_CUSTOM_UNKNOWN; strlcpy(cparam->name, param, sizeof(cparam->name)); strlcpy(cparam->text, text[0] ? text : param, sizeof(cparam->text)); @@ -2495,15 +2758,15 @@ static ppd_group_t * /* O - Named group */ ppd_get_group(ppd_file_t *ppd, /* I - PPD file */ const char *name, /* I - Name of group */ const char *text, /* I - Text for group */ - _cups_globals_t *cg, /* I - Global data */ + _ppd_globals_t *pg, /* I - Global data */ cups_encoding_t encoding) /* I - Encoding of text */ { int i; /* Looping var */ ppd_group_t *group; /* Group */ - DEBUG_printf(("ppd_get_group(ppd=%p, name=\"%s\", text=\"%s\", cg=%p)\n", - ppd, name, text, cg)); + DEBUG_printf(("7ppd_get_group(ppd=%p, name=\"%s\", text=\"%s\", cg=%p)", + ppd, name, text, pg)); for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++) if (!strcmp(group->name, name)) @@ -2511,24 +2774,23 @@ ppd_get_group(ppd_file_t *ppd, /* I - PPD file */ if (i == 0) { - DEBUG_printf(("Adding group %s...\n", name)); + DEBUG_printf(("8ppd_get_group: Adding group %s...", name)); - if (cg->ppd_conform == PPD_CONFORM_STRICT && strlen(text) >= sizeof(group->text)) + if (pg->ppd_conform == PPD_CONFORM_STRICT && strlen(text) >= sizeof(group->text)) { - cg->ppd_status = PPD_ILLEGAL_TRANSLATION; + pg->ppd_status = PPD_ILLEGAL_TRANSLATION; return (NULL); } - + if (ppd->num_groups == 0) group = malloc(sizeof(ppd_group_t)); else - group = realloc(ppd->groups, - (ppd->num_groups + 1) * sizeof(ppd_group_t)); + group = realloc(ppd->groups, (size_t)(ppd->num_groups + 1) * sizeof(ppd_group_t)); if (group == NULL) { - cg->ppd_status = PPD_ALLOC_ERROR; + pg->ppd_status = PPD_ALLOC_ERROR; return (NULL); } @@ -2560,7 +2822,7 @@ ppd_get_option(ppd_group_t *group, /* I - Group */ ppd_option_t *option; /* Option */ - DEBUG_printf(("ppd_get_option(group=%p(\"%s\"), name=\"%s\")\n", + DEBUG_printf(("7ppd_get_option(group=%p(\"%s\"), name=\"%s\")", group, group->name, name)); for (i = group->num_options, option = group->options; i > 0; i --, option ++) @@ -2572,8 +2834,7 @@ ppd_get_option(ppd_group_t *group, /* I - Group */ if (group->num_options == 0) option = malloc(sizeof(ppd_option_t)); else - option = realloc(group->options, - (group->num_options + 1) * sizeof(ppd_option_t)); + option = realloc(group->options, (size_t)(group->num_options + 1) * sizeof(ppd_option_t)); if (option == NULL) return (NULL); @@ -2590,6 +2851,47 @@ ppd_get_option(ppd_group_t *group, /* I - Group */ } +/* + * 'ppd_globals_alloc()' - Allocate and initialize global data. + */ + +static _ppd_globals_t * /* O - Pointer to global data */ +ppd_globals_alloc(void) +{ + return ((_ppd_globals_t *)calloc(1, sizeof(_ppd_globals_t))); +} + + +/* + * 'ppd_globals_free()' - Free global data. + */ + +#if defined(HAVE_PTHREAD_H) || defined(_WIN32) +static void +ppd_globals_free(_ppd_globals_t *pg) /* I - Pointer to global data */ +{ + free(pg); +} +#endif /* HAVE_PTHREAD_H || _WIN32 */ + + +#ifdef HAVE_PTHREAD_H +/* + * 'ppd_globals_init()' - Initialize per-thread globals... + */ + +static void +ppd_globals_init(void) +{ + /* + * Register the global data for this thread... + */ + + pthread_key_create(&ppd_globals_key, (void (*)(void *))ppd_globals_free); +} +#endif /* HAVE_PTHREAD_H */ + + /* * 'ppd_hash_option()' - Generate a hash of the option name... */ @@ -2602,7 +2904,7 @@ ppd_hash_option(ppd_option_t *option) /* I - Option */ for (hash = option->keyword[0], k = option->keyword + 1; *k;) - hash = 33 * hash + *k++; + hash = (int)(33U * (unsigned)hash) + *k++; return (hash & 511); } @@ -2621,7 +2923,7 @@ ppd_read(cups_file_t *fp, /* I - File to read from */ char *text, /* O - Human-readable text from line */ char **string, /* O - Code/string data */ int ignoreblank, /* I - Ignore blank lines? */ - _cups_globals_t *cg) /* I - Global data */ + _ppd_globals_t *pg) /* I - Global data */ { int ch, /* Character from file */ col, /* Column in line */ @@ -2643,7 +2945,7 @@ ppd_read(cups_file_t *fp, /* I - File to read from */ *string = NULL; col = 0; - startline = cg->ppd_line + 1; + startline = pg->ppd_line + 1; if (!line->buffer) { @@ -2682,8 +2984,8 @@ ppd_read(cups_file_t *fp, /* I - File to read from */ * Don't allow lines longer than 256k! */ - cg->ppd_line = startline; - cg->ppd_status = PPD_LINE_TOO_LONG; + pg->ppd_line = startline; + pg->ppd_status = PPD_LINE_TOO_LONG; return (0); } @@ -2691,8 +2993,8 @@ ppd_read(cups_file_t *fp, /* I - File to read from */ temp = realloc(line->buffer, line->bufsize); if (!temp) { - cg->ppd_line = startline; - cg->ppd_status = PPD_LINE_TOO_LONG; + pg->ppd_line = startline; + pg->ppd_status = PPD_LINE_TOO_LONG; return (0); } @@ -2707,7 +3009,7 @@ ppd_read(cups_file_t *fp, /* I - File to read from */ * Line feed or carriage return... */ - cg->ppd_line ++; + pg->ppd_line ++; col = 0; if (ch == '\r') @@ -2736,14 +3038,14 @@ ppd_read(cups_file_t *fp, /* I - File to read from */ *lineptr++ = '\n'; } - else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT) + else if (ch < ' ' && ch != '\t' && pg->ppd_conform == PPD_CONFORM_STRICT) { /* * Other control characters... */ - cg->ppd_line = startline; - cg->ppd_status = PPD_ILLEGAL_CHARACTER; + pg->ppd_line = startline; + pg->ppd_status = PPD_ILLEGAL_CHARACTER; return (0); } @@ -2753,7 +3055,7 @@ ppd_read(cups_file_t *fp, /* I - File to read from */ * Any other character... */ - *lineptr++ = ch; + *lineptr++ = (char)ch; col ++; if (col > (PPD_MAX_LINE - 1)) @@ -2762,8 +3064,8 @@ ppd_read(cups_file_t *fp, /* I - File to read from */ * Line is too long... */ - cg->ppd_line = startline; - cg->ppd_status = PPD_LINE_TOO_LONG; + pg->ppd_line = startline; + pg->ppd_status = PPD_LINE_TOO_LONG; return (0); } @@ -2787,7 +3089,7 @@ ppd_read(cups_file_t *fp, /* I - File to read from */ break; else if (ch == '\r' || ch == '\n') { - cg->ppd_line ++; + pg->ppd_line ++; col = 0; if (ch == '\r') @@ -2802,14 +3104,14 @@ ppd_read(cups_file_t *fp, /* I - File to read from */ cupsFileGetChar(fp); } } - else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT) + else if (ch < ' ' && ch != '\t' && pg->ppd_conform == PPD_CONFORM_STRICT) { /* * Other control characters... */ - cg->ppd_line = startline; - cg->ppd_status = PPD_ILLEGAL_CHARACTER; + pg->ppd_line = startline; + pg->ppd_status = PPD_ILLEGAL_CHARACTER; return (0); } @@ -2823,8 +3125,8 @@ ppd_read(cups_file_t *fp, /* I - File to read from */ * Line is too long... */ - cg->ppd_line = startline; - cg->ppd_status = PPD_LINE_TOO_LONG; + pg->ppd_line = startline; + pg->ppd_status = PPD_LINE_TOO_LONG; return (0); } @@ -2844,7 +3146,7 @@ ppd_read(cups_file_t *fp, /* I - File to read from */ * Line feed or carriage return... */ - cg->ppd_line ++; + pg->ppd_line ++; col = 0; if (ch == '\r') @@ -2861,14 +3163,14 @@ ppd_read(cups_file_t *fp, /* I - File to read from */ break; } - else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT) + else if (ch < ' ' && ch != '\t' && pg->ppd_conform == PPD_CONFORM_STRICT) { /* * Other control characters... */ - cg->ppd_line = startline; - cg->ppd_status = PPD_ILLEGAL_CHARACTER; + pg->ppd_line = startline; + pg->ppd_status = PPD_ILLEGAL_CHARACTER; return (0); } @@ -2882,8 +3184,8 @@ ppd_read(cups_file_t *fp, /* I - File to read from */ * Line is too long... */ - cg->ppd_line = startline; - cg->ppd_status = PPD_LINE_TOO_LONG; + pg->ppd_line = startline; + pg->ppd_status = PPD_LINE_TOO_LONG; return (0); } @@ -2895,10 +3197,10 @@ ppd_read(cups_file_t *fp, /* I - File to read from */ *lineptr = '\0'; - DEBUG_printf(("LINE=\"%s\"\n", line->buffer)); + DEBUG_printf(("9ppd_read: LINE=\"%s\"", line->buffer)); /* - * The dynamically created PPDs for older style Mac OS X + * The dynamically created PPDs for older style macOS * drivers include a large blob of data inserted as comments * at the end of the file. As an optimization we can stop * reading the PPD when we get to the start of this data. @@ -2927,21 +3229,21 @@ ppd_read(cups_file_t *fp, /* I - File to read from */ !strcmp(line->buffer, "*End")) && /* End of multi-line string */ ignoreblank) /* Ignore these? */ { - startline = cg->ppd_line + 1; + startline = pg->ppd_line + 1; continue; } if (!strcmp(line->buffer, "*")) /* (Bad) comment line */ { - if (cg->ppd_conform == PPD_CONFORM_RELAXED) + if (pg->ppd_conform == PPD_CONFORM_RELAXED) { - startline = cg->ppd_line + 1; + startline = pg->ppd_line + 1; continue; } else { - cg->ppd_line = startline; - cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD; + pg->ppd_line = startline; + pg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD; return (0); } @@ -2954,12 +3256,12 @@ ppd_read(cups_file_t *fp, /* I - File to read from */ */ for (lineptr = line->buffer; *lineptr; lineptr ++) - if (!isspace(*lineptr & 255)) + if (*lineptr && !_cups_isspace(*lineptr)) break; if (*lineptr) { - cg->ppd_status = PPD_MISSING_ASTERISK; + pg->ppd_status = PPD_MISSING_ASTERISK; return (0); } else if (ignoreblank) @@ -2974,12 +3276,12 @@ ppd_read(cups_file_t *fp, /* I - File to read from */ keyptr = keyword; - while (*lineptr != '\0' && *lineptr != ':' && !isspace(*lineptr & 255)) + while (*lineptr && *lineptr != ':' && !_cups_isspace(*lineptr)) { if (*lineptr <= ' ' || *lineptr > 126 || *lineptr == '/' || (keyptr - keyword) >= (PPD_MAX_NAME - 1)) { - cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD; + pg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD; return (0); } @@ -2993,26 +3295,24 @@ ppd_read(cups_file_t *fp, /* I - File to read from */ mask |= PPD_KEYWORD; -/* DEBUG_printf(("keyword = \"%s\", lineptr = \"%s\"\n", keyword, lineptr));*/ - - if (isspace(*lineptr & 255)) + if (_cups_isspace(*lineptr)) { /* * Get an option name... */ - while (isspace(*lineptr & 255)) + while (_cups_isspace(*lineptr)) lineptr ++; optptr = option; - while (*lineptr != '\0' && !isspace(*lineptr & 255) && *lineptr != ':' && + while (*lineptr && !_cups_isspace(*lineptr) && *lineptr != ':' && *lineptr != '/') { if (*lineptr <= ' ' || *lineptr > 126 || (optptr - option) >= (PPD_MAX_NAME - 1)) { - cg->ppd_status = PPD_ILLEGAL_OPTION_KEYWORD; + pg->ppd_status = PPD_ILLEGAL_OPTION_KEYWORD; return (0); } @@ -3021,19 +3321,17 @@ ppd_read(cups_file_t *fp, /* I - File to read from */ *optptr = '\0'; - if (isspace(*lineptr & 255) && cg->ppd_conform == PPD_CONFORM_STRICT) + if (_cups_isspace(*lineptr) && pg->ppd_conform == PPD_CONFORM_STRICT) { - cg->ppd_status = PPD_ILLEGAL_WHITESPACE; + pg->ppd_status = PPD_ILLEGAL_WHITESPACE; return (0); } - while (isspace(*lineptr & 255)) + while (_cups_isspace(*lineptr)) lineptr ++; mask |= PPD_OPTION; -/* DEBUG_printf(("option = \"%s\", lineptr = \"%s\"\n", option, lineptr));*/ - if (*lineptr == '/') { /* @@ -3041,7 +3339,7 @@ ppd_read(cups_file_t *fp, /* I - File to read from */ */ lineptr ++; - + textptr = text; while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':') @@ -3049,7 +3347,7 @@ ppd_read(cups_file_t *fp, /* I - File to read from */ if (((unsigned char)*lineptr < ' ' && *lineptr != '\t') || (textptr - text) >= (PPD_MAX_LINE - 1)) { - cg->ppd_status = PPD_ILLEGAL_TRANSLATION; + pg->ppd_status = PPD_ILLEGAL_TRANSLATION; return (0); } @@ -3059,25 +3357,23 @@ ppd_read(cups_file_t *fp, /* I - File to read from */ *textptr = '\0'; textlen = ppd_decode(text); - if (textlen > PPD_MAX_TEXT && cg->ppd_conform == PPD_CONFORM_STRICT) + if (textlen > PPD_MAX_TEXT && pg->ppd_conform == PPD_CONFORM_STRICT) { - cg->ppd_status = PPD_ILLEGAL_TRANSLATION; + pg->ppd_status = PPD_ILLEGAL_TRANSLATION; return (0); } - + mask |= PPD_TEXT; } - -/* DEBUG_printf(("text = \"%s\", lineptr = \"%s\"\n", text, lineptr));*/ } - if (isspace(*lineptr & 255) && cg->ppd_conform == PPD_CONFORM_STRICT) + if (_cups_isspace(*lineptr) && pg->ppd_conform == PPD_CONFORM_STRICT) { - cg->ppd_status = PPD_ILLEGAL_WHITESPACE; + pg->ppd_status = PPD_ILLEGAL_WHITESPACE; return (0); } - while (isspace(*lineptr & 255)) + while (_cups_isspace(*lineptr)) lineptr ++; if (*lineptr == ':') @@ -3087,11 +3383,11 @@ ppd_read(cups_file_t *fp, /* I - File to read from */ */ lineptr ++; - while (isspace(*lineptr & 255)) + while (_cups_isspace(*lineptr)) lineptr ++; strptr = lineptr + strlen(lineptr) - 1; - while (strptr >= lineptr && isspace(*strptr & 255)) + while (strptr >= lineptr && _cups_isspace(*strptr)) *strptr-- = '\0'; if (*strptr == '\"') @@ -3104,9 +3400,7 @@ ppd_read(cups_file_t *fp, /* I - File to read from */ lineptr ++; } - *string = _cupsStrAlloc(lineptr); - -/* DEBUG_printf(("string = \"%s\", lineptr = \"%s\"\n", *string, lineptr));*/ + *string = strdup(lineptr); mask |= PPD_STRING; } @@ -3118,5 +3412,120 @@ ppd_read(cups_file_t *fp, /* I - File to read from */ /* - * End of "$Id: ppd.c 7552 2008-05-12 17:42:15Z mike $". + * 'ppd_update_filters()' - Update the filters array as needed. + * + * This function re-populates the filters array with cupsFilter2 entries that + * have been stripped of the destination MIME media types and any maxsize hints. + * + * (All for backwards-compatibility) */ + +static int /* O - 1 on success, 0 on failure */ +ppd_update_filters(ppd_file_t *ppd, /* I - PPD file */ + _ppd_globals_t *pg) /* I - Global data */ +{ + ppd_attr_t *attr; /* Current cupsFilter2 value */ + char srcsuper[16], /* Source MIME media type */ + srctype[256], + dstsuper[16], /* Destination MIME media type */ + dsttype[256], + program[1024], /* Command to run */ + *ptr, /* Pointer into command to run */ + buffer[1024], /* Re-written cupsFilter value */ + **filter; /* Current filter */ + int cost; /* Cost of filter */ + + + DEBUG_printf(("4ppd_update_filters(ppd=%p, cg=%p)", ppd, pg)); + + /* + * See if we have any cupsFilter2 lines... + */ + + if ((attr = ppdFindAttr(ppd, "cupsFilter2", NULL)) == NULL) + { + DEBUG_puts("5ppd_update_filters: No cupsFilter2 keywords present."); + return (1); + } + + /* + * Yes, free the cupsFilter-defined filters and re-build... + */ + + ppd_free_filters(ppd); + + do + { + /* + * Parse the cupsFilter2 string: + * + * src/type dst/type cost program + * src/type dst/type cost maxsize(n) program + */ + + DEBUG_printf(("5ppd_update_filters: cupsFilter2=\"%s\"", attr->value)); + + if (sscanf(attr->value, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]", + srcsuper, srctype, dstsuper, dsttype, &cost, program) != 6) + { + DEBUG_puts("5ppd_update_filters: Bad cupsFilter2 line."); + pg->ppd_status = PPD_BAD_VALUE; + + return (0); + } + + DEBUG_printf(("5ppd_update_filters: srcsuper=\"%s\", srctype=\"%s\", " + "dstsuper=\"%s\", dsttype=\"%s\", cost=%d, program=\"%s\"", + srcsuper, srctype, dstsuper, dsttype, cost, program)); + + if (!strncmp(program, "maxsize(", 8) && + (ptr = strchr(program + 8, ')')) != NULL) + { + DEBUG_puts("5ppd_update_filters: Found maxsize(nnn)."); + + ptr ++; + while (_cups_isspace(*ptr)) + ptr ++; + + _cups_strcpy(program, ptr); + DEBUG_printf(("5ppd_update_filters: New program=\"%s\"", program)); + } + + /* + * Convert to cupsFilter format: + * + * src/type cost program + */ + + snprintf(buffer, sizeof(buffer), "%s/%s %d %s", srcsuper, srctype, cost, + program); + DEBUG_printf(("5ppd_update_filters: Adding \"%s\".", buffer)); + + /* + * Add a cupsFilter-compatible string to the filters array. + */ + + if (ppd->num_filters == 0) + filter = malloc(sizeof(char *)); + else + filter = realloc(ppd->filters, sizeof(char *) * (size_t)(ppd->num_filters + 1)); + + if (filter == NULL) + { + DEBUG_puts("5ppd_update_filters: Out of memory."); + pg->ppd_status = PPD_ALLOC_ERROR; + + return (0); + } + + ppd->filters = filter; + filter += ppd->num_filters; + ppd->num_filters ++; + + *filter = strdup(buffer); + } + while ((attr = ppdFindNextAttr(ppd, "cupsFilter2", NULL)) != NULL); + + DEBUG_puts("5ppd_update_filters: Completed OK."); + return (1); +}