/*
- * "$Id: ppd.c 4990 2006-01-26 02:21:45Z mike $"
+ * "$Id: ppd.c 177 2006-06-21 00:20:03Z jlovell $"
*
* PPD file routines for the Common UNIX Printing System (CUPS).
*
*
* Contents:
*
- * _ppd_attr_compare() - Compare two attributes.
* 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_coptions() - Compare two custom options.
* ppd_compare_cparams() - Compare two custom parameters.
* ppd_compare_options() - Compare two options.
const char *value);
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_coptions(ppd_coption_t *a, ppd_coption_t *b);
+static int ppd_compare_attrs(ppd_attr_t *a, ppd_attr_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);
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, _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,
_cups_globals_t *cg);
-/*
- * '_ppd_attr_compare()' - Compare two attributes.
- */
-
-int /* O - Result of comparison */
-_ppd_attr_compare(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 if ((*a)->spec[0] && (*b)->spec[0])
- return (strcasecmp((*a)->spec, (*b)->spec));
- else
- return (0);
-}
-
-
/*
* 'ppdClose()' - Free all memory used by the PPD file.
*/
* 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->attrs);
}
+ cupsArrayDelete(ppd->sorted_attrs);
+
/*
* Free custom options...
*/
case PPD_CUSTOM_PASSWORD :
case PPD_CUSTOM_STRING :
ppd_free(cparam->current.custom_string);
- ppd_free(cparam->minimum.custom_string);
- ppd_free(cparam->maximum.custom_string);
break;
default :
}
+/*
+ * '_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_WINDOWS_932);
+ 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*().
*
ppd_file_t * /* O - PPD file record */
ppdOpen2(cups_file_t *fp) /* I - File to read from */
{
- char *oldlocale; /* Old locale settings */
int i, j, k; /* Looping vars */
int count; /* Temporary count */
ppd_file_t *ppd; /* PPD file record */
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_encoding_t encoding; /* Encoding of PPD file */
_cups_globals_t *cg = _cupsGlobals();
/* Global data */
static const char * const ui_keywords[] =
{
+#ifdef CUPS_USE_FULL_UI_KEYWORDS_LIST
+ /*
+ * Adobe defines some 41 keywords as "UI", meaning that they are
+ * user interface elements and that they should be treated as such
+ * even if the PPD creator doesn't use Open/CloseUI around them.
+ *
+ * Since this can cause previously invisible options to appear and
+ * confuse users, the default is to only treat the PageSize and
+ * PageRegion keywords this way.
+ */
/* Boolean keywords */
"BlackSubstitution",
"Booklet",
"StapleWhen",
"StapleX",
"StapleY"
+#else /* !CUPS_USE_FULL_UI_KEYWORDS_LIST */
+ "PageRegion",
+ "PageSize"
+#endif /* CUPS_USE_FULL_UI_KEYWORDS_LIST */
};
*/
language = cupsLangDefault();
-
-#ifdef LC_NUMERIC
- oldlocale = _cupsSaveLocale(LC_NUMERIC, "C");
-#else
- oldlocale = _cupsSaveLocale(LC_ALL, "C");
-#endif /* LC_NUMERIC */
+ loc = localeconv();
/*
* Read lines from the PPD file and add them to the file record...
option = NULL;
choice = NULL;
ui_keyword = 0;
+ encoding = CUPS_ISO8859_1;
while ((mask = ppd_read(fp, keyword, name, text, &string, 1, cg)) != 0)
{
if (!group)
{
- if (strcmp(keyword, "Collate") && strcmp(keyword, "Duplex") &&
- strcmp(keyword, "InputSlot") && strcmp(keyword, "ManualFeed") &&
- strcmp(keyword, "MediaType") && strcmp(keyword, "MediaColor") &&
- strcmp(keyword, "MediaWeight") && strcmp(keyword, "OutputBin") &&
- strcmp(keyword, "OutputMode") && strcmp(keyword, "OutputOrder") &&
- strcmp(keyword, "PageSize") && strcmp(keyword, "PageRegion"))
- group = ppd_get_group(ppd, "Extra", _("Extra"), cg);
- else
- group = ppd_get_group(ppd, "General", _("General"), cg);
-
- if (group == NULL)
+ if ((group = ppd_get_group(ppd, "General", _("General"), cg,
+ encoding)) == NULL)
goto error;
DEBUG_printf(("Adding to group %s...\n", group->text));
if (!strcmp(keyword, "LanguageLevel"))
ppd->language_level = atoi(string);
else if (!strcmp(keyword, "LanguageEncoding"))
- ppd->lang_encoding = string;
+ {
+ /*
+ * Say all PPD files are UTF-8, since we convert to UTF-8...
+ */
+
+ ppd->lang_encoding = strdup("UTF-8");
+ encoding = _ppdGetEncoding(string);
+ }
else if (!strcmp(keyword, "LanguageVersion"))
ppd->lang_version = string;
else if (!strcmp(keyword, "Manufacturer"))
else if (!strcmp(keyword, "PCFileName"))
ppd->pcfilename = string;
else if (!strcmp(keyword, "NickName"))
- ppd->nickname = string;
+ {
+ if (encoding != CUPS_UTF8)
+ {
+ cups_utf8_t utf8[256]; /* UTF-8 version of NickName */
+
+
+ cupsCharsetToUTF8(utf8, string, sizeof(utf8), encoding);
+ ppd->nickname = strdup((char *)utf8);
+ }
+ else
+ ppd->nickname = strdup(string);
+ }
else if (!strcmp(keyword, "Product"))
ppd->product = string;
else if (!strcmp(keyword, "ShortNickName"))
memset(profile, 0, sizeof(ppd_profile_t));
strlcpy(profile->resolution, name, sizeof(profile->resolution));
strlcpy(profile->media_type, text, sizeof(profile->media_type));
- sscanf(string, "%f%f%f%f%f%f%f%f%f%f%f", &(profile->density),
- &(profile->gamma),
- profile->matrix[0] + 0, profile->matrix[0] + 1,
- profile->matrix[0] + 2, profile->matrix[1] + 0,
- profile->matrix[1] + 1, profile->matrix[1] + 2,
- profile->matrix[2] + 0, profile->matrix[2] + 1,
- profile->matrix[2] + 2);
+
+ 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);
}
else if (!strcmp(keyword, "cupsFilter"))
{
ppd->fonts[ppd->num_fonts] = strdup(name);
ppd->num_fonts ++;
}
-#if 0
- else if (!strcmp(keyword, "ParamCustomPageSize"))
- {
- if (!strcmp(name, "Width"))
- sscanf(string, "%*s%*s%f%f", ppd->custom_min + 0,
- ppd->custom_max + 0);
- else if (!strcmp(name, "Height"))
- sscanf(string, "%*s%*s%f%f", ppd->custom_min + 1,
- ppd->custom_max + 1);
- }
-#endif /* 0 */
else if (!strncmp(keyword, "ParamCustom", 11))
{
ppd_coption_t *coption; /* Custom option */
if (!strcmp(ctype, "curve"))
{
cparam->type = PPD_CUSTOM_CURVE;
- cparam->minimum.custom_curve = atof(cminimum);
- cparam->maximum.custom_curve = atof(cmaximum);
+ cparam->minimum.custom_curve = _cupsStrScand(cminimum, NULL, loc);
+ cparam->maximum.custom_curve = _cupsStrScand(cmaximum, NULL, loc);
}
else if (!strcmp(ctype, "int"))
{
else if (!strcmp(ctype, "invcurve"))
{
cparam->type = PPD_CUSTOM_INVCURVE;
- cparam->minimum.custom_invcurve = atof(cminimum);
- cparam->maximum.custom_invcurve = atof(cmaximum);
+ cparam->minimum.custom_invcurve = _cupsStrScand(cminimum, NULL, loc);
+ cparam->maximum.custom_invcurve = _cupsStrScand(cmaximum, NULL, loc);
}
else if (!strcmp(ctype, "passcode"))
{
cparam->type = PPD_CUSTOM_PASSCODE;
- cparam->minimum.custom_passcode = strdup(cminimum);
- cparam->maximum.custom_passcode = strdup(cmaximum);
+ cparam->minimum.custom_passcode = atoi(cminimum);
+ cparam->maximum.custom_passcode = atoi(cmaximum);
}
else if (!strcmp(ctype, "password"))
{
cparam->type = PPD_CUSTOM_PASSWORD;
- cparam->minimum.custom_password = strdup(cminimum);
- cparam->maximum.custom_password = strdup(cmaximum);
+ cparam->minimum.custom_password = atoi(cminimum);
+ cparam->maximum.custom_password = atoi(cmaximum);
}
else if (!strcmp(ctype, "points"))
{
cparam->type = PPD_CUSTOM_POINTS;
- cparam->minimum.custom_points = atof(cminimum);
- cparam->maximum.custom_points = atof(cmaximum);
+ cparam->minimum.custom_points = _cupsStrScand(cminimum, NULL, loc);
+ cparam->maximum.custom_points = _cupsStrScand(cmaximum, NULL, loc);
}
else if (!strcmp(ctype, "real"))
{
cparam->type = PPD_CUSTOM_REAL;
- cparam->minimum.custom_real = atof(cminimum);
- cparam->maximum.custom_real = atof(cmaximum);
+ cparam->minimum.custom_real = _cupsStrScand(cminimum, NULL, loc);
+ cparam->maximum.custom_real = _cupsStrScand(cmaximum, NULL, loc);
}
else if (!strcmp(ctype, "string"))
{
cparam->type = PPD_CUSTOM_STRING;
- cparam->minimum.custom_string = strdup(cminimum);
- cparam->maximum.custom_string = strdup(cmaximum);
+ cparam->minimum.custom_string = atoi(cminimum);
+ cparam->maximum.custom_string = atoi(cmaximum);
}
else
{
}
}
else if (!strcmp(keyword, "HWMargins"))
- sscanf(string, "%f%f%f%f", ppd->custom_margins + 0,
- ppd->custom_margins + 1, ppd->custom_margins + 2,
- ppd->custom_margins + 3);
+ {
+ for (i = 0, sptr = string; i < 4; i ++)
+ ppd->custom_margins[i] = _cupsStrScand(sptr, &sptr, loc);
+ }
else if (!strncmp(keyword, "Custom", 6) && !strcmp(name, "True"))
{
- ppd_coption_t *coption; /* Custom option */
-
-
DEBUG_puts("Processing Custom option...");
/*
DEBUG_printf(("%s option not found for %s...\n", keyword + 6, keyword));
- if ((gtemp = ppd_get_group(ppd, "General", _("General"), cg)) == NULL)
+ if ((gtemp = ppd_get_group(ppd, "General", _("General"), cg,
+ encoding)) == NULL)
{
DEBUG_puts("Unable to get general group!");
}
}
- if ((coption = ppd_get_coption(ppd, keyword + 6)) == NULL)
+ if (!ppd_get_coption(ppd, keyword + 6))
{
cg->ppd_status = PPD_ALLOC_ERROR;
option = ppd_get_option(subgroup, name);
else if (group == NULL)
{
- if (strcmp(name, "Collate") && strcmp(name, "Duplex") &&
- strcmp(name, "InputSlot") && strcmp(name, "ManualFeed") &&
- strcmp(name, "MediaType") && strcmp(name, "MediaColor") &&
- strcmp(name, "MediaWeight") && strcmp(name, "OutputBin") &&
- strcmp(name, "OutputMode") && strcmp(name, "OutputOrder") &&
- strcmp(name, "PageSize") && strcmp(name, "PageRegion"))
- group = ppd_get_group(ppd, "Extra", _("Extra"), cg);
- else
- group = ppd_get_group(ppd, "General", _("General"), cg);
-
- if (group == NULL)
+ if ((group = ppd_get_group(ppd, "General", _("General"), cg,
+ encoding)) == NULL)
goto error;
DEBUG_printf(("Adding to group %s...\n", group->text));
}
if (text[0])
- strlcpy(option->text, text, sizeof(option->text));
+ cupsCharsetToUTF8((cups_utf8_t *)option->text, text,
+ sizeof(option->text), encoding);
else
{
if (!strcmp(name, "PageSize"))
* Find the JCL group, and add if needed...
*/
- group = ppd_get_group(ppd, "JCL", _("JCL"), cg);
+ group = ppd_get_group(ppd, "JCL", _("JCL"), cg, encoding);
if (group == NULL)
goto error;
break;
}
- strlcpy(option->text, text, sizeof(option->text));
+ if (text[0])
+ cupsCharsetToUTF8((cups_utf8_t *)option->text, text,
+ sizeof(option->text), encoding);
+ else
+ strlcpy(option->text, name, sizeof(option->text));
option->section = PPD_ORDER_JCL;
group = NULL;
* Find/add the group...
*/
- group = ppd_get_group(ppd, string, sptr, cg);
+ group = ppd_get_group(ppd, string, sptr, cg, encoding);
if (group == NULL)
goto error;
else if (!strcmp(keyword, "OrderDependency") ||
!strcmp(keyword, "NonUIOrderDependency"))
{
- if (sscanf(string, "%f%40s%40s", &order, name, keyword) != 3)
+ order = _cupsStrScand(string, &sptr, loc);
+
+ if (!sptr || sscanf(sptr, "%40s%40s", name, keyword) != 2)
{
cg->ppd_status = PPD_BAD_ORDER_DEPENDENCY;
goto error;
}
- sscanf(string, "%f%f", &(size->width), &(size->length));
+ size->width = _cupsStrScand(string, &sptr, loc);
+ size->length = _cupsStrScand(sptr, NULL, loc);
ppd_free(string);
string = NULL;
goto error;
}
- sscanf(string, "%f%f%f%f", &(size->left), &(size->bottom),
- &(size->right), &(size->top));
+ size->left = _cupsStrScand(string, &sptr, loc);
+ size->bottom = _cupsStrScand(sptr, &sptr, loc);
+ size->right = _cupsStrScand(sptr, &sptr, loc);
+ size->top = _cupsStrScand(sptr, NULL, loc);
ppd_free(string);
string = NULL;
choice = ppd_add_choice(option, name);
- if (mask & PPD_TEXT)
- strlcpy(choice->text, text, sizeof(choice->text));
+ if (text[0])
+ cupsCharsetToUTF8((cups_utf8_t *)choice->text, text,
+ sizeof(choice->text), encoding);
else if (!strcmp(name, "True"))
strcpy(choice->text, _("Yes"));
else if (!strcmp(name, "False"))
cupsLangFree(language);
-#ifdef LC_NUMERIC
- _cupsRestoreLocale(LC_NUMERIC, oldlocale);
-#else
- _cupsRestoreLocale(LC_ALL, oldlocale);
-#endif /* LC_NUMERIC */
-
#ifdef DEBUG
if (!feof(fp))
printf("Premature EOF at %lu...\n", (unsigned long)ftell(fp));
}
}
- /*
- * Sort the attributes...
- */
-
- if (ppd->num_attrs > 1)
- qsort(ppd->attrs, ppd->num_attrs, sizeof(ppd_attr_t *),
- (int (*)(const void *, const void *))_ppd_attr_compare);
-
/*
* Return the PPD file structure...
*/
cupsLangFree(language);
-#ifdef LC_NUMERIC
- _cupsRestoreLocale(LC_NUMERIC, oldlocale);
-#else
- _cupsRestoreLocale(LC_ALL, oldlocale);
-#endif /* LC_NUMERIC */
-
return (NULL);
}
if (ppd == NULL || name == NULL || spec == NULL)
return (NULL);
+ /*
+ * Create the array as needed...
+ */
+
+ if (!ppd->sorted_attrs)
+ ppd->sorted_attrs = cupsArrayNew((cups_array_func_t)ppd_compare_attrs,
+ NULL);
+
/*
* Allocate memory for the new attribute...
*/
strlcpy(temp->text, text, sizeof(temp->text));
temp->value = (char *)value;
+ /*
+ * Add the attribute to the sorted array...
+ */
+
+ cupsArrayAdd(ppd->sorted_attrs, temp);
+
/*
* Return the attribute...
*/
}
+/*
+ * 'ppd_compare_attrs()' - Compare two attributes.
+ */
+
+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 if (a->spec[0] && b->spec[0])
+ return (strcasecmp(a->spec, b->spec));
+ else
+ return (0);
+}
+
+
/*
* 'ppd_compare_coptions()' - Compare two custom options.
*/
*/
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_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 */
+ cups_encoding_t encoding) /* I - Encoding of text */
{
int i; /* Looping var */
ppd_group_t *group; /* Group */
memset(group, 0, sizeof(ppd_group_t));
strlcpy(group->name, name, sizeof(group->name));
- strlcpy(group->text, text, sizeof(group->text));
+
+ cupsCharsetToUTF8((cups_utf8_t *)group->text, text,
+ sizeof(group->text), encoding);
}
return (group);
DEBUG_printf(("LINE = \"%s\"\n", line));
+ /*
+ * The dynamically created PPDs for older style Mac OS X
+ * 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.
+ */
+
+ if (!strcmp(line, "*%APLWORKSET START"))
+ {
+ free(line);
+ return (0);
+ }
+
if (ch == EOF && lineptr == line)
{
free(line);
/*
- * End of "$Id: ppd.c 4990 2006-01-26 02:21:45Z mike $".
+ * End of "$Id: ppd.c 177 2006-06-21 00:20:03Z jlovell $".
*/