/*
- * "$Id: ppd.c 5302 2006-03-18 00:49:17Z mike $"
+ * "$Id: ppd.c 7906 2008-09-03 20:19:43Z mike $"
*
* PPD file routines for the Common UNIX Printing System (CUPS).
*
- * Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ * Copyright 2007-2008 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
- * property of Easy Software Products 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 missing or damaged please contact Easy Software Products
- * at:
- *
- * Attn: CUPS Licensing Information
- * Easy Software Products
- * 44141 Airport View Drive, Suite 204
- * Hollywood, Maryland 20636 USA
- *
- * Voice: (301) 373-9600
- * EMail: cups-info@cups.org
- * WWW: http://www.cups.org
+ * 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.
*
*
* 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.
* 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_free_option() - Free a single option.
* ppd_get_coption() - Get a custom option record.
* ppd_get_cparam() - Get a custom parameter record.
- * ppd_get_encoding() - Get the CUPS encoding value for the given
- * LanguageEncoding.
* 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.
*/
* Include necessary headers.
*/
+#include "ppd-private.h"
#include "globals.h"
#include "debug.h"
#include <stdlib.h>
#define PPD_TEXT 4 /* Line contained human-readable text */
#define PPD_STRING 8 /* Line contained a string or code */
+#define PPD_HASHSIZE 512 /* Size of hash */
+
+
+/*
+ * Line buffer structure...
+ */
+
+typedef struct _ppd_line_s
+{
+ char *buffer; /* Pointer to buffer */
+ size_t bufsize; /* Size of the buffer */
+} _ppd_line_t;
+
/*
* Local functions...
static ppd_choice_t *ppd_add_choice(ppd_option_t *option, const char *name);
static ppd_size_t *ppd_add_size(ppd_file_t *ppd, const char *name);
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 ppd_cparam_t *ppd_get_cparam(ppd_coption_t *opt,
const char *param,
const char *text);
-static cups_encoding_t ppd_get_encoding(const char *name);
static ppd_group_t *ppd_get_group(ppd_file_t *ppd, const char *name,
const char *text, _cups_globals_t *cg,
cups_encoding_t encoding);
static ppd_option_t *ppd_get_option(ppd_group_t *group, const char *name);
-static int ppd_read(cups_file_t *fp, char *keyword, char *option,
- char *text, char **string, int ignoreblank,
+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);
* Free all strings at the top level...
*/
- ppd_free(ppd->lang_encoding);
- ppd_free(ppd->nickname);
- ppd_free(ppd->patches);
- ppd_free(ppd->jcl_begin);
- ppd_free(ppd->jcl_end);
- ppd_free(ppd->jcl_ps);
+ _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...
{
for (i = ppd->num_emulations, emul = ppd->emulations; i > 0; i --, emul ++)
{
- ppd_free(emul->start);
- ppd_free(emul->stop);
+ _cupsStrFree(emul->start);
+ _cupsStrFree(emul->stop);
}
ppd_free(ppd->emulations);
}
cupsArrayDelete(ppd->options);
+ cupsArrayDelete(ppd->marked);
/*
* Free any page sizes...
if (ppd->num_filters > 0)
{
for (i = ppd->num_filters, filter = ppd->filters; i > 0; i --, filter ++)
- {
- ppd_free(*filter);
- }
+ _cupsStrFree(*filter);
ppd_free(ppd->filters);
}
if (ppd->num_fonts > 0)
{
for (i = ppd->num_fonts, font = ppd->fonts; i > 0; i --, font ++)
- {
- ppd_free(*font);
- }
+ _cupsStrFree(*font);
ppd_free(ppd->fonts);
}
{
for (i = ppd->num_attrs, attr = ppd->attrs; i > 0; i --, attr ++)
{
- ppd_free((*attr)->value);
+ _cupsStrFree((*attr)->value);
ppd_free(*attr);
}
case PPD_CUSTOM_PASSCODE :
case PPD_CUSTOM_PASSWORD :
case PPD_CUSTOM_STRING :
- ppd_free(cparam->current.custom_string);
+ _cupsStrFree(cparam->current.custom_string);
break;
default :
cupsArrayDelete(ppd->coptions);
+ /*
+ * Free constraints...
+ */
+
+ if (ppd->cups_uiconstraints)
+ {
+ _ppd_cups_uiconsts_t *consts; /* Current constraints */
+
+
+ for (consts = (_ppd_cups_uiconsts_t *)cupsArrayFirst(ppd->cups_uiconstraints);
+ consts;
+ consts = (_ppd_cups_uiconsts_t *)cupsArrayNext(ppd->cups_uiconstraints))
+ {
+ free(consts->constraints);
+ free(consts);
+ }
+
+ cupsArrayDelete(ppd->cups_uiconstraints);
+ }
+
/*
* Free the whole record...
*/
/*
* 'ppdErrorString()' - Returns the text assocated with a status.
*
- * @since CUPS 1.1.19@
+ * @since CUPS 1.1.19/Mac OS X 10.3@
*/
const char * /* O - Status string */
}
+/*
+ * '_ppdGetEncoding()' - Get the CUPS encoding value for the given
+ * LanguageEncoding.
+ */
+
+cups_encoding_t /* O - CUPS encoding value */
+_ppdGetEncoding(const char *name) /* I - LanguageEncoding string */
+{
+ if (!strcasecmp(name, "ISOLatin1"))
+ return (CUPS_ISO8859_1);
+ else if (!strcasecmp(name, "ISOLatin2"))
+ return (CUPS_ISO8859_2);
+ else if (!strcasecmp(name, "ISOLatin5"))
+ return (CUPS_ISO8859_5);
+ else if (!strcasecmp(name, "JIS83-RKSJ"))
+ return (CUPS_JIS_X0213);
+ else if (!strcasecmp(name, "MacStandard"))
+ return (CUPS_MAC_ROMAN);
+ else if (!strcasecmp(name, "WindowsANSI"))
+ return (CUPS_WINDOWS_1252);
+ else
+ return (CUPS_UTF8);
+}
+
+
/*
* 'ppdLastError()' - Return the status from the last ppdOpen*().
*
- * @since CUPS 1.1.19@
+ * @since CUPS 1.1.19/Mac OS X 10.3@
*/
ppd_status_t /* O - Status code */
/*
* 'ppdOpen2()' - Read a PPD file into memory.
*
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
*/
-ppd_file_t * /* O - PPD file record */
+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 */
{
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 */
*subgroup; /* Current sub-group */
cups_encoding_t encoding; /* Encoding of PPD file */
_cups_globals_t *cg = _cupsGlobals();
/* Global data */
+ char custom_name[PPD_MAX_NAME];
+ /* CustomFoo attribute name */
+ ppd_attr_t *custom_attr; /* CustomFoo attribute */
static const char * const ui_keywords[] =
{
#ifdef CUPS_USE_FULL_UI_KEYWORDS_LIST
* Grab the first line and make sure it reads '*PPD-Adobe: "major.minor"'...
*/
- mask = ppd_read(fp, keyword, name, text, &string, 0, cg);
+ line.buffer = NULL;
+ line.bufsize = 0;
+
+ mask = ppd_read(fp, &line, keyword, name, text, &string, 0, cg);
DEBUG_printf(("mask=%x, keyword=\"%s\"...\n", mask, keyword));
if (cg->ppd_status == PPD_OK)
cg->ppd_status = PPD_MISSING_PPDADOBE4;
- ppd_free(string);
+ _cupsStrFree(string);
+ ppd_free(line.buffer);
return (NULL);
}
DEBUG_printf(("ppdOpen: keyword = %s, string = %p\n", keyword, string));
- ppd_free(string);
+ _cupsStrFree(string);
/*
* Allocate memory for the PPD file record...
{
cg->ppd_status = PPD_ALLOC_ERROR;
+ _cupsStrFree(string);
+ ppd_free(line.buffer);
+
return (NULL);
}
- ppd->language_level = 1;
+ ppd->language_level = 2;
ppd->color_device = 0;
- ppd->colorspace = PPD_CS_GRAY;
+ ppd->colorspace = PPD_CS_N;
ppd->landscape = -90;
ppd->coptions = cupsArrayNew((cups_array_func_t)ppd_compare_coptions,
NULL);
ui_keyword = 0;
encoding = CUPS_ISO8859_1;
- while ((mask = ppd_read(fp, keyword, name, text, &string, 1, cg)) != 0)
+ while ((mask = ppd_read(fp, &line, keyword, name, text, &string, 1, cg)) != 0)
{
-#ifdef DEBUG
- printf("mask = %x, keyword = \"%s\"", mask, keyword);
-
- if (name[0] != '\0')
- printf(", name = \"%s\"", name);
+ DEBUG_printf(("mask=%x, keyword=\"%s\", name=\"%s\", text=\"%s\", "
+ "string=%d chars...", mask, keyword, name, text,
+ string ? (int)strlen(string) : 0));
- if (text[0] != '\0')
- printf(", text = \"%s\"", text);
-
- if (string != NULL)
- {
- if (strlen(string) > 40)
- printf(", string = %p", string);
- else
- printf(", string = \"%s\"", string);
- }
-
- puts("");
-#endif /* DEBUG */
-
- if (strcmp(keyword, "CloseUI") && strcmp(keyword, "CloseGroup") &&
- strcmp(keyword, "CloseSubGroup") && strncmp(keyword, "Default", 7) &&
- strcmp(keyword, "JCLCloseUI") && strcmp(keyword, "JCLOpenUI") &&
- strcmp(keyword, "OpenUI") && strcmp(keyword, "OpenGroup") &&
- strcmp(keyword, "OpenSubGroup") && string == NULL)
+ if (strncmp(keyword, "Default", 7) && !string &&
+ cg->ppd_conform != PPD_CONFORM_RELAXED)
{
/*
* Need a string value!
* Say all PPD files are UTF-8, since we convert to UTF-8...
*/
- ppd->lang_encoding = strdup("UTF-8");
- encoding = ppd_get_encoding(string);
+ ppd->lang_encoding = _cupsStrAlloc("UTF-8");
+ encoding = _ppdGetEncoding(string);
}
else if (!strcmp(keyword, "LanguageVersion"))
ppd->lang_version = string;
cupsCharsetToUTF8(utf8, string, sizeof(utf8), encoding);
- ppd->nickname = strdup((char *)utf8);
+ ppd->nickname = _cupsStrAlloc((char *)utf8);
}
else
- ppd->nickname = strdup(string);
+ ppd->nickname = _cupsStrAlloc(string);
}
else if (!strcmp(keyword, "Product"))
ppd->product = string;
ppd->ttrasterizer = string;
else if (!strcmp(keyword, "JCLBegin"))
{
- ppd->jcl_begin = strdup(string);
+ ppd->jcl_begin = _cupsStrAlloc(string);
ppd_decode(ppd->jcl_begin); /* Decode quoted string */
}
else if (!strcmp(keyword, "JCLEnd"))
{
- ppd->jcl_end = strdup(string);
+ ppd->jcl_end = _cupsStrAlloc(string);
ppd_decode(ppd->jcl_end); /* Decode quoted string */
}
else if (!strcmp(keyword, "JCLToPSInterpreter"))
{
- ppd->jcl_ps = strdup(string);
+ ppd->jcl_ps = _cupsStrAlloc(string);
ppd_decode(ppd->jcl_ps); /* Decode quoted string */
}
else if (!strcmp(keyword, "AccurateScreensSupport"))
profile = realloc(ppd->profiles, sizeof(ppd_profile_t) *
(ppd->num_profiles + 1));
+ if (!profile)
+ {
+ cg->ppd_status = PPD_ALLOC_ERROR;
+
+ goto error;
+ }
+
ppd->profiles = profile;
profile += ppd->num_profiles;
ppd->num_profiles ++;
strlcpy(profile->resolution, name, sizeof(profile->resolution));
strlcpy(profile->media_type, text, sizeof(profile->media_type));
- profile->density = _cupsStrScand(string, &sptr, loc);
- profile->gamma = _cupsStrScand(sptr, &sptr, loc);
- profile->matrix[0][0] = _cupsStrScand(sptr, &sptr, loc);
- profile->matrix[0][1] = _cupsStrScand(sptr, &sptr, loc);
- profile->matrix[0][2] = _cupsStrScand(sptr, &sptr, loc);
- profile->matrix[1][0] = _cupsStrScand(sptr, &sptr, loc);
- profile->matrix[1][1] = _cupsStrScand(sptr, &sptr, loc);
- profile->matrix[1][2] = _cupsStrScand(sptr, &sptr, loc);
- profile->matrix[2][0] = _cupsStrScand(sptr, &sptr, loc);
- profile->matrix[2][1] = _cupsStrScand(sptr, &sptr, loc);
- profile->matrix[2][2] = _cupsStrScand(sptr, &sptr, loc);
+ profile->density = (float)_cupsStrScand(string, &sptr, loc);
+ profile->gamma = (float)_cupsStrScand(sptr, &sptr, loc);
+ profile->matrix[0][0] = (float)_cupsStrScand(sptr, &sptr, loc);
+ profile->matrix[0][1] = (float)_cupsStrScand(sptr, &sptr, loc);
+ profile->matrix[0][2] = (float)_cupsStrScand(sptr, &sptr, loc);
+ profile->matrix[1][0] = (float)_cupsStrScand(sptr, &sptr, loc);
+ profile->matrix[1][1] = (float)_cupsStrScand(sptr, &sptr, loc);
+ profile->matrix[1][2] = (float)_cupsStrScand(sptr, &sptr, loc);
+ profile->matrix[2][0] = (float)_cupsStrScand(sptr, &sptr, loc);
+ profile->matrix[2][1] = (float)_cupsStrScand(sptr, &sptr, loc);
+ profile->matrix[2][2] = (float)_cupsStrScand(sptr, &sptr, loc);
}
else if (!strcmp(keyword, "cupsFilter"))
{
if (filter == NULL)
{
- ppd_free(filter);
-
cg->ppd_status = PPD_ALLOC_ERROR;
goto error;
}
ppd->fonts = tempfonts;
- ppd->fonts[ppd->num_fonts] = strdup(name);
+ ppd->fonts[ppd->num_fonts] = _cupsStrAlloc(name);
ppd->num_fonts ++;
}
else if (!strncmp(keyword, "ParamCustom", 11))
if (!strcmp(ctype, "curve"))
{
cparam->type = PPD_CUSTOM_CURVE;
- cparam->minimum.custom_curve = _cupsStrScand(cminimum, NULL, loc);
- cparam->maximum.custom_curve = _cupsStrScand(cmaximum, NULL, loc);
+ cparam->minimum.custom_curve = (float)_cupsStrScand(cminimum, NULL, loc);
+ cparam->maximum.custom_curve = (float)_cupsStrScand(cmaximum, NULL, loc);
}
else if (!strcmp(ctype, "int"))
{
else if (!strcmp(ctype, "invcurve"))
{
cparam->type = PPD_CUSTOM_INVCURVE;
- cparam->minimum.custom_invcurve = _cupsStrScand(cminimum, NULL, loc);
- cparam->maximum.custom_invcurve = _cupsStrScand(cmaximum, NULL, loc);
+ cparam->minimum.custom_invcurve = (float)_cupsStrScand(cminimum, NULL, loc);
+ cparam->maximum.custom_invcurve = (float)_cupsStrScand(cmaximum, NULL, loc);
}
else if (!strcmp(ctype, "passcode"))
{
else if (!strcmp(ctype, "points"))
{
cparam->type = PPD_CUSTOM_POINTS;
- cparam->minimum.custom_points = _cupsStrScand(cminimum, NULL, loc);
- cparam->maximum.custom_points = _cupsStrScand(cmaximum, NULL, loc);
+ cparam->minimum.custom_points = (float)_cupsStrScand(cminimum, NULL, loc);
+ cparam->maximum.custom_points = (float)_cupsStrScand(cmaximum, NULL, loc);
}
else if (!strcmp(ctype, "real"))
{
cparam->type = PPD_CUSTOM_REAL;
- cparam->minimum.custom_real = _cupsStrScand(cminimum, NULL, loc);
- cparam->maximum.custom_real = _cupsStrScand(cmaximum, NULL, loc);
+ cparam->minimum.custom_real = (float)_cupsStrScand(cminimum, NULL, loc);
+ cparam->maximum.custom_real = (float)_cupsStrScand(cmaximum, NULL, loc);
}
else if (!strcmp(ctype, "string"))
{
else if (!strcmp(keyword, "HWMargins"))
{
for (i = 0, sptr = string; i < 4; i ++)
- ppd->custom_margins[i] = _cupsStrScand(sptr, &sptr, loc);
+ ppd->custom_margins[i] = (float)_cupsStrScand(sptr, &sptr, loc);
}
- else if (!strncmp(keyword, "Custom", 6) && !strcmp(name, "True"))
+ else if (!strncmp(keyword, "Custom", 6) && !strcmp(name, "True") && !option)
{
+ ppd_option_t *custom_option; /* Custom option */
+
DEBUG_puts("Processing Custom option...");
/*
* Get the option and custom option...
*/
- if ((option = ppdFindOption(ppd, keyword + 6)) == NULL)
- {
- ppd_group_t *gtemp; /* Temporary group */
-
-
- DEBUG_printf(("%s option not found for %s...\n", keyword + 6, keyword));
-
- if ((gtemp = ppd_get_group(ppd, "General", _("General"), cg,
- encoding)) == NULL)
- {
- DEBUG_puts("Unable to get general group!");
-
- goto error;
- }
-
- if ((option = ppd_get_option(gtemp, keyword + 6)) == NULL)
- {
- DEBUG_printf(("Unable to get %s option!\n", keyword + 6));
-
- cg->ppd_status = PPD_ALLOC_ERROR;
-
- goto error;
- }
- }
-
if (!ppd_get_coption(ppd, keyword + 6))
{
cg->ppd_status = PPD_ALLOC_ERROR;
goto error;
}
- /*
- * Add the "custom" option...
- */
+ if (option && !strcasecmp(option->keyword, keyword + 6))
+ custom_option = option;
+ else
+ custom_option = ppdFindOption(ppd, keyword + 6);
- if ((choice = ppd_add_choice(option, "Custom")) == NULL)
+ if (custom_option)
{
- DEBUG_puts("Unable to add Custom choice!");
+ /*
+ * Add the "custom" option...
+ */
- cg->ppd_status = PPD_ALLOC_ERROR;
+ if ((choice = ppdFindChoice(custom_option, "Custom")) == NULL)
+ if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL)
+ {
+ DEBUG_puts("Unable to add Custom choice!");
- goto error;
- }
+ cg->ppd_status = PPD_ALLOC_ERROR;
- strlcpy(choice->text, text[0] ? text : _("Custom"),
- sizeof(choice->text));
+ goto error;
+ }
- choice->code = string;
- string = NULL; /* Don't add as an attribute below */
- option = NULL;
+ strlcpy(choice->text, text[0] ? text : _("Custom"),
+ sizeof(choice->text));
+
+ choice->code = _cupsStrAlloc(string);
+
+ if (custom_option->section == PPD_ORDER_JCL)
+ ppd_decode(choice->code);
+ }
/*
* Now process custom page sizes specially...
if (!strcmp(keyword, "CustomPageSize"))
{
- ppd->variable_sizes = 1;
-
/*
* Add a "Custom" page size entry...
*/
+ ppd->variable_sizes = 1;
+
ppd_add_size(ppd, "Custom");
+
+ if (option && !strcasecmp(option->keyword, "PageRegion"))
+ custom_option = option;
+ else
+ custom_option = ppdFindOption(ppd, "PageRegion");
+
+ if (custom_option)
+ {
+ if ((choice = ppdFindChoice(custom_option, "Custom")) == NULL)
+ if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL)
+ {
+ DEBUG_puts("Unable to add Custom choice!");
+
+ cg->ppd_status = PPD_ALLOC_ERROR;
+
+ goto error;
+ }
+
+ strlcpy(choice->text, text[0] ? text : _("Custom"),
+ sizeof(choice->text));
+ }
}
}
else if (!strcmp(keyword, "LandscapeOrientation"))
else if (!strcmp(string, "Plus90"))
ppd->landscape = 90;
}
- else if (!strcmp(keyword, "Emulators"))
+ else if (!strcmp(keyword, "Emulators") && string)
{
for (count = 1, sptr = string; sptr != NULL;)
if ((sptr = strchr(sptr, ' ')) != NULL)
}
ppd->num_emulations = count;
- ppd->emulations = calloc(count, sizeof(ppd_emul_t));
+ if ((ppd->emulations = calloc(count, sizeof(ppd_emul_t))) == NULL)
+ {
+ cg->ppd_status = PPD_ALLOC_ERROR;
+
+ goto error;
+ }
for (i = 0, sptr = string; i < count; i ++)
{
else if (!strcmp(keyword, "JobPatchFile"))
{
if (ppd->patches == NULL)
- ppd->patches = strdup(string);
+ ppd->patches = _cupsStrAlloc(string);
else
{
temp = realloc(ppd->patches, strlen(ppd->patches) +
* Add an option record to the current sub-group, group, or file...
*/
+ DEBUG_printf(("name=\"%s\" (%d)\n", name, (int)strlen(name)));
+
if (name[0] == '*')
_cups_strcpy(name, name + 1); /* Eliminate leading asterisk */
option->section = PPD_ORDER_ANY;
- ppd_free(string);
+ _cupsStrFree(string);
string = NULL;
+
+ /*
+ * Add a custom option choice if we have already seen a CustomFoo
+ * attribute...
+ */
+
+ if (!strcasecmp(name, "PageRegion"))
+ strcpy(custom_name, "CustomPageSize");
+ else
+ snprintf(custom_name, sizeof(custom_name), "Custom%s", name);
+
+ if ((custom_attr = ppdFindAttr(ppd, custom_name, "True")) != NULL)
+ {
+ if ((choice = ppdFindChoice(option, "Custom")) == NULL)
+ if ((choice = ppd_add_choice(option, "Custom")) == NULL)
+ {
+ DEBUG_puts("Unable to add Custom choice!");
+
+ cg->ppd_status = PPD_ALLOC_ERROR;
+
+ goto error;
+ }
+
+ strlcpy(choice->text,
+ custom_attr->text[0] ? custom_attr->text : _("Custom"),
+ sizeof(choice->text));
+ choice->code = _cupsStrRetain(custom_attr->value);
+ }
}
else if (!strcmp(keyword, "JCLOpenUI"))
{
option->section = PPD_ORDER_JCL;
group = NULL;
- ppd_free(string);
+ _cupsStrFree(string);
string = NULL;
+
+ /*
+ * Add a custom option choice if we have already seen a CustomFoo
+ * attribute...
+ */
+
+ snprintf(custom_name, sizeof(custom_name), "Custom%s", name);
+
+ if ((custom_attr = ppdFindAttr(ppd, custom_name, "True")) != NULL)
+ {
+ if ((choice = ppd_add_choice(option, "Custom")) == NULL)
+ {
+ DEBUG_puts("Unable to add Custom choice!");
+
+ cg->ppd_status = PPD_ALLOC_ERROR;
+
+ goto error;
+ }
+
+ strlcpy(choice->text,
+ custom_attr->text[0] ? custom_attr->text : _("Custom"),
+ sizeof(choice->text));
+ choice->code = _cupsStrRetain(custom_attr->value);
+ }
}
else if (!strcmp(keyword, "CloseUI") || !strcmp(keyword, "JCLCloseUI"))
{
option = NULL;
- ppd_free(string);
+ _cupsStrFree(string);
string = NULL;
}
else if (!strcmp(keyword, "OpenGroup"))
if (group == NULL)
goto error;
- ppd_free(string);
+ _cupsStrFree(string);
string = NULL;
}
else if (!strcmp(keyword, "CloseGroup"))
{
group = NULL;
- ppd_free(string);
+ _cupsStrFree(string);
string = NULL;
}
- else if (!strcmp(keyword, "OrderDependency") ||
- !strcmp(keyword, "NonUIOrderDependency"))
+ else if (!strcmp(keyword, "OrderDependency"))
{
- order = _cupsStrScand(string, &sptr, loc);
+ order = (float)_cupsStrScand(string, &sptr, loc);
if (!sptr || sscanf(sptr, "%40s%40s", name, keyword) != 2)
{
option->order = order;
}
- ppd_free(string);
+ _cupsStrFree(string);
string = NULL;
}
else if (!strncmp(keyword, "Default", 7))
!strcmp(keyword, "NonUIConstraints"))
{
if (ppd->num_consts == 0)
- constraint = calloc(1, sizeof(ppd_const_t));
+ constraint = calloc(2, sizeof(ppd_const_t));
else
constraint = realloc(ppd->consts,
- (ppd->num_consts + 1) * sizeof(ppd_const_t));
+ (ppd->num_consts + 2) * sizeof(ppd_const_t));
if (constraint == NULL)
{
goto error;
case 2 : /* Two options... */
+ /*
+ * Check for broken constraints like "* Option"...
+ */
+
+ if (cg->ppd_conform == PPD_CONFORM_STRICT &&
+ (!strcmp(constraint->option1, "*") ||
+ !strcmp(constraint->choice1, "*")))
+ {
+ cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
+ goto error;
+ }
+
/*
* The following strcpy's are safe, as optionN and
* choiceN are all the same size (size defined by PPD spec...)
if (constraint->option1[0] == '*')
_cups_strcpy(constraint->option1, constraint->option1 + 1);
+ else if (cg->ppd_conform == PPD_CONFORM_STRICT)
+ {
+ cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
+ goto error;
+ }
if (constraint->choice1[0] == '*')
_cups_strcpy(constraint->option2, constraint->choice1 + 1);
- else
- _cups_strcpy(constraint->option2, constraint->choice1);
+ else if (cg->ppd_conform == PPD_CONFORM_STRICT)
+ {
+ cg->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 &&
+ (!strcmp(constraint->option1, "*") ||
+ !strcmp(constraint->choice1, "*") ||
+ !strcmp(constraint->option2, "*")))
+ {
+ cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
+ goto error;
+ }
+
/*
* The following _cups_strcpy's are safe, as optionN and
* choiceN are all the same size (size defined by PPD spec...)
if (constraint->option1[0] == '*')
_cups_strcpy(constraint->option1, constraint->option1 + 1);
+ else if (cg->ppd_conform == PPD_CONFORM_STRICT)
+ {
+ cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
+ goto error;
+ }
if (constraint->choice1[0] == '*')
{
+ if (cg->ppd_conform == PPD_CONFORM_STRICT &&
+ constraint->option2[0] == '*')
+ {
+ cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
+ goto error;
+ }
+
_cups_strcpy(constraint->choice2, constraint->option2);
_cups_strcpy(constraint->option2, constraint->choice1 + 1);
constraint->choice1[0] = '\0';
{
if (constraint->option2[0] == '*')
_cups_strcpy(constraint->option2, constraint->option2 + 1);
+ else if (cg->ppd_conform == PPD_CONFORM_STRICT)
+ {
+ cg->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 &&
+ (!strcmp(constraint->option1, "*") ||
+ !strcmp(constraint->choice1, "*") ||
+ !strcmp(constraint->option2, "*") ||
+ !strcmp(constraint->choice2, "*")))
+ {
+ cg->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)
+ {
+ cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
+ goto error;
+ }
+
+ if (cg->ppd_conform == PPD_CONFORM_STRICT &&
+ constraint->choice1[0] == '*')
+ {
+ cg->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)
+ {
+ cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
+ goto error;
+ }
+
+ if (cg->ppd_conform == PPD_CONFORM_STRICT &&
+ constraint->choice2[0] == '*')
+ {
+ cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
+ goto error;
+ }
break;
}
- ppd_free(string);
+ /*
+ * Don't add this one as an attribute...
+ */
+
+ _cupsStrFree(string);
string = NULL;
}
else if (!strcmp(keyword, "PaperDimension"))
goto error;
}
- size->width = _cupsStrScand(string, &sptr, loc);
- size->length = _cupsStrScand(sptr, NULL, loc);
+ size->width = (float)_cupsStrScand(string, &sptr, loc);
+ size->length = (float)_cupsStrScand(sptr, NULL, loc);
- ppd_free(string);
+ _cupsStrFree(string);
string = NULL;
}
else if (!strcmp(keyword, "ImageableArea"))
goto error;
}
- size->left = _cupsStrScand(string, &sptr, loc);
- size->bottom = _cupsStrScand(sptr, &sptr, loc);
- size->right = _cupsStrScand(sptr, &sptr, loc);
- size->top = _cupsStrScand(sptr, NULL, loc);
+ size->left = (float)_cupsStrScand(string, &sptr, loc);
+ size->bottom = (float)_cupsStrScand(sptr, &sptr, loc);
+ size->right = (float)_cupsStrScand(sptr, &sptr, loc);
+ size->top = (float)_cupsStrScand(sptr, NULL, loc);
- ppd_free(string);
+ _cupsStrFree(string);
string = NULL;
}
else if (option != NULL &&
* Add the option choice...
*/
- choice = ppd_add_choice(option, name);
+ if ((choice = ppd_add_choice(option, name)) == NULL)
+ {
+ cg->ppd_status = PPD_ALLOC_ERROR;
+
+ goto error;
+ }
if (text[0])
cupsCharsetToUTF8((cups_utf8_t *)choice->text, text,
(mask & (PPD_KEYWORD | PPD_STRING)) == (PPD_KEYWORD | PPD_STRING))
ppd_add_attr(ppd, keyword, name, text, string);
else
- ppd_free(string);
+ _cupsStrFree(string);
}
+ ppd_free(line.buffer);
+
/*
* Reset language preferences...
*/
cupsLangFree(language);
#ifdef DEBUG
- if (!feof(fp))
- printf("Premature EOF at %lu...\n", (unsigned long)ftell(fp));
+ if (!cupsFileEOF(fp))
+ DEBUG_printf(("Premature EOF at %lu...\n",
+ (unsigned long)cupsFileTell(fp)));
#endif /* DEBUG */
if (cg->ppd_status != PPD_OK)
* each choice and custom option...
*/
- ppd->options = cupsArrayNew((cups_array_func_t)ppd_compare_options, NULL);
+ ppd->options = cupsArrayNew2((cups_array_func_t)ppd_compare_options, NULL,
+ (cups_ahash_func_t)ppd_hash_option,
+ PPD_HASHSIZE);
for (i = ppd->num_groups, group = ppd->groups;
i > 0;
}
}
+ /*
+ * Create an array to track the marked choices...
+ */
+
+ ppd->marked = cupsArrayNew((cups_array_func_t)ppd_compare_choices, NULL);
+
/*
* Return the PPD file structure...
*/
error:
- ppd_free(string);
+ _cupsStrFree(string);
+ ppd_free(line.buffer);
ppdClose(ppd);
* 'ppdOpenFd()' - Read a PPD file into memory.
*/
-ppd_file_t * /* O - PPD file record */
+ppd_file_t * /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
ppdOpenFd(int fd) /* I - File to read from */
{
cups_file_t *fp; /* CUPS file pointer */
* 'ppdOpenFile()' - Read a PPD file into memory.
*/
-ppd_file_t * /* O - PPD file record */
+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 */
{
cups_file_t *fp; /* File pointer */
/*
* 'ppdSetConformance()' - Set the conformance level for PPD files.
*
- * @since CUPS 1.1.20@
+ * @since CUPS 1.1.20/Mac OS X 10.4@
*/
void
ppd_compare_attrs(ppd_attr_t *a, /* I - First attribute */
ppd_attr_t *b) /* I - Second attribute */
{
- int ret; /* Result of comparison */
+ return (strcasecmp(a->name, b->name));
+}
- if ((ret = strcasecmp(a->name, b->name)) != 0)
- return (ret);
- else if (a->spec[0] && b->spec[0])
- return (strcasecmp(a->spec, b->spec));
- else
- return (0);
+/*
+ * 'ppd_compare_choices()' - Compare two choices...
+ */
+
+static int /* O - Result of comparison */
+ppd_compare_choices(ppd_choice_t *a, /* I - First choice */
+ ppd_choice_t *b) /* I - Second choice */
+{
+ return (strcmp(a->option->keyword, b->option->keyword));
}
i > 0;
i --, choice ++)
{
- ppd_free(choice->code);
+ _cupsStrFree(choice->code);
}
ppd_free(option->choices);
return (NULL);
strlcpy(cparam->name, param, sizeof(cparam->name));
- strlcpy(cparam->text, text, sizeof(cparam->text));
+ strlcpy(cparam->text, text[0] ? text : param, sizeof(cparam->text));
/*
* Add this record to the array...
}
-/*
- * 'ppd_get_encoding()' - Get the CUPS encoding value for the given
- * LanguageEncoding.
- */
-
-static cups_encoding_t /* O - CUPS encoding value */
-ppd_get_encoding(const char *name) /* I - LanguageEncoding string */
-{
- if (!strcasecmp(name, "ISOLatin1"))
- return (CUPS_ISO8859_1);
- else if (!strcasecmp(name, "ISOLatin2"))
- return (CUPS_ISO8859_2);
- else if (!strcasecmp(name, "ISOLatin5"))
- return (CUPS_ISO8859_5);
- else if (!strcasecmp(name, "JIS83-RKSJ"))
- return (CUPS_WINDOWS_932);
- else if (!strcasecmp(name, "MacStandard"))
- return (CUPS_MAC_ROMAN);
- else if (!strcasecmp(name, "WindowsANSI"))
- return (CUPS_WINDOWS_1252);
- else
- return (CUPS_UTF8);
-}
-
-
/*
* 'ppd_get_group()' - Find or create the named group as needed.
*/
}
+/*
+ * 'ppd_hash_option()' - Generate a hash of the option name...
+ */
+
+static int /* O - Hash index */
+ppd_hash_option(ppd_option_t *option) /* I - Option */
+{
+ int hash = 0; /* Hash index */
+ const char *k; /* Pointer into keyword */
+
+
+ for (hash = option->keyword[0], k = option->keyword + 1; *k;)
+ hash = 33 * hash + *k++;
+
+ return (hash & 511);
+}
+
+
/*
* 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
* necessary.
static int /* O - Bitmask of fields read */
ppd_read(cups_file_t *fp, /* I - File to read from */
+ _ppd_line_t *line, /* I - Line buffer */
char *keyword, /* O - Keyword from line */
char *option, /* O - Option from line */
char *text, /* O - Human-readable text from line */
*optptr, /* Option pointer */
*textptr, /* Text pointer */
*strptr, /* Pointer into string */
- *lineptr, /* Current position in line buffer */
- *line; /* Line buffer */
- int linesize; /* Current size of line buffer */
+ *lineptr; /* Current position in line buffer */
- /*
- * Range check everything...
- */
-
- if (!fp || !keyword || !option || !text || !string)
- return (0);
/*
* Now loop until we have a valid line...
*string = NULL;
col = 0;
startline = cg->ppd_line + 1;
- linesize = 1024;
- line = malloc(linesize);
- if (!line)
- return (0);
+ if (!line->buffer)
+ {
+ line->bufsize = 1024;
+ line->buffer = malloc(1024);
+
+ if (!line->buffer)
+ return (0);
+ }
do
{
* Read the line...
*/
- lineptr = line;
+ lineptr = line->buffer;
endquote = 0;
colon = 0;
while ((ch = cupsFileGetChar(fp)) != EOF)
{
- if (lineptr >= (line + linesize - 1))
+ if (lineptr >= (line->buffer + line->bufsize - 1))
{
/*
* Expand the line buffer...
char *temp; /* Temporary line pointer */
- linesize += 1024;
- if (linesize > 262144)
+ line->bufsize += 1024;
+ if (line->bufsize > 262144)
{
/*
* Don't allow lines longer than 256k!
cg->ppd_line = startline;
cg->ppd_status = PPD_LINE_TOO_LONG;
- free(line);
-
return (0);
}
- temp = realloc(line, linesize);
+ temp = realloc(line->buffer, line->bufsize);
if (!temp)
{
cg->ppd_line = startline;
cg->ppd_status = PPD_LINE_TOO_LONG;
- free(line);
-
return (0);
}
- lineptr = temp + (lineptr - line);
- line = temp;
+ lineptr = temp + (lineptr - line->buffer);
+ line->buffer = temp;
}
if (ch == '\r' || ch == '\n')
cupsFileGetChar(fp);
}
- if (lineptr == line && ignoreblank)
+ if (lineptr == line->buffer && ignoreblank)
continue; /* Skip blank lines */
ch = '\n';
cg->ppd_line = startline;
cg->ppd_status = PPD_ILLEGAL_CHARACTER;
- free(line);
-
return (0);
}
else if (ch != 0x1a)
cg->ppd_line = startline;
cg->ppd_status = PPD_LINE_TOO_LONG;
- free(line);
-
return (0);
}
- if (ch == ':' && strncmp(line, "*%", 2) != 0)
+ if (ch == ':' && strncmp(line->buffer, "*%", 2) != 0)
colon = 1;
if (ch == '\"' && colon)
if (ch == 0x0a)
cupsFileGetChar(fp);
}
-
- ch = '\n';
}
else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
{
cg->ppd_line = startline;
cg->ppd_status = PPD_ILLEGAL_CHARACTER;
- free(line);
-
return (0);
}
else if (ch != 0x1a)
cg->ppd_line = startline;
cg->ppd_status = PPD_LINE_TOO_LONG;
- free(line);
-
return (0);
}
}
cg->ppd_line = startline;
cg->ppd_status = PPD_ILLEGAL_CHARACTER;
- free(line);
-
return (0);
}
else if (ch != 0x1a)
cg->ppd_line = startline;
cg->ppd_status = PPD_LINE_TOO_LONG;
- free(line);
-
return (0);
}
}
}
- if (lineptr > line && lineptr[-1] == '\n')
+ if (lineptr > line->buffer && lineptr[-1] == '\n')
lineptr --;
*lineptr = '\0';
- DEBUG_printf(("LINE = \"%s\"\n", line));
+ DEBUG_printf(("LINE=\"%s\"\n", line->buffer));
/*
* The dynamically created PPDs for older style Mac OS X
* reading the PPD when we get to the start of this data.
*/
- if (!strcmp(line, "*%APLWORKSET START"))
- {
- free(line);
+ if (!strcmp(line->buffer, "*%APLWORKSET START"))
return (0);
- }
- if (ch == EOF && lineptr == line)
- {
- free(line);
+ if (ch == EOF && lineptr == line->buffer)
return (0);
- }
/*
* Now parse it...
*/
mask = 0;
- lineptr = line + 1;
+ lineptr = line->buffer + 1;
keyword[0] = '\0';
option[0] = '\0';
text[0] = '\0';
*string = NULL;
- if ((!line[0] || /* Blank line */
- !strncmp(line, "*%", 2) || /* Comment line */
- !strcmp(line, "*End")) && /* End of multi-line string */
+ if ((!line->buffer[0] || /* Blank line */
+ !strncmp(line->buffer, "*%", 2) || /* Comment line */
+ !strcmp(line->buffer, "*End")) && /* End of multi-line string */
ignoreblank) /* Ignore these? */
{
startline = cg->ppd_line + 1;
continue;
}
- if (!strcmp(line, "*")) /* (Bad) comment line */
+ if (!strcmp(line->buffer, "*")) /* (Bad) comment line */
{
if (cg->ppd_conform == PPD_CONFORM_RELAXED)
{
cg->ppd_line = startline;
cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
- free(line);
return (0);
}
}
- if (line[0] != '*') /* All lines start with an asterisk */
+ if (line->buffer[0] != '*') /* All lines start with an asterisk */
{
/*
* Allow lines consisting of just whitespace...
*/
- for (lineptr = line; *lineptr; lineptr ++)
+ for (lineptr = line->buffer; *lineptr; lineptr ++)
if (!isspace(*lineptr & 255))
break;
if (*lineptr)
{
cg->ppd_status = PPD_MISSING_ASTERISK;
- free(line);
return (0);
}
else if (ignoreblank)
continue;
else
- {
- free(line);
return (0);
- }
}
/*
(keyptr - keyword) >= (PPD_MAX_NAME - 1))
{
cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
- free(line);
return (0);
}
(optptr - option) >= (PPD_MAX_NAME - 1))
{
cg->ppd_status = PPD_ILLEGAL_OPTION_KEYWORD;
- free(line);
return (0);
}
if (isspace(*lineptr & 255) && cg->ppd_conform == PPD_CONFORM_STRICT)
{
cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
- free(line);
return (0);
}
(textptr - text) >= (PPD_MAX_LINE - 1))
{
cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
- free(line);
return (0);
}
if (textlen > PPD_MAX_TEXT && cg->ppd_conform == PPD_CONFORM_STRICT)
{
cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
- free(line);
return (0);
}
if (isspace(*lineptr & 255) && cg->ppd_conform == PPD_CONFORM_STRICT)
{
cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
- free(line);
return (0);
}
if (*strptr == '\"')
{
/*
- * Quoted string by itself...
+ * Quoted string by itself, remove quotes...
*/
- *string = malloc(strlen(lineptr) + 1);
-
- strptr = *string;
-
- for (; *lineptr != '\0'; lineptr ++)
- if (*lineptr != '\"')
- *strptr++ = *lineptr;
-
- *strptr = '\0';
+ *strptr = '\0';
+ lineptr ++;
}
- else
- *string = strdup(lineptr);
+
+ *string = _cupsStrAlloc(lineptr);
/* DEBUG_printf(("string = \"%s\", lineptr = \"%s\"\n", *string, lineptr));*/
}
while (mask == 0);
- free(line);
-
return (mask);
}
/*
- * End of "$Id: ppd.c 5302 2006-03-18 00:49:17Z mike $".
+ * End of "$Id: ppd.c 7906 2008-09-03 20:19:43Z mike $".
*/