#include "ppd-private.h"
#include "pwg-private.h"
#include "globals.h"
#include "debug.h"
#include <stdlib.h>
#if defined(WIN32) || defined(__EMX__)
# define READ_BINARY "rb"
# define WRITE_BINARY "wb"
#else
# define READ_BINARY "r"
# define WRITE_BINARY "w"
#endif
#define ppd_free(p) if (p) free(p)
#define PPD_KEYWORD 1
#define PPD_OPTION 2
#define PPD_TEXT 4
#define PPD_STRING 8
#define PPD_HASHSIZE 512
typedef struct _ppd_line_s
{
char *buffer;
size_t bufsize;
} _ppd_line_t;
static ppd_attr_t *ppd_add_attr(ppd_file_t *ppd, const char *name,
const char *spec, const char *text,
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_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_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);
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,
cups_encoding_t encoding);
static ppd_option_t *ppd_get_option(ppd_group_t *group, const char *name);
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);
void
ppdClose(ppd_file_t *ppd)
{
int i;
ppd_emul_t *emul;
ppd_group_t *group;
char **font;
char **filter;
ppd_attr_t **attr;
ppd_coption_t *coption;
ppd_cparam_t *cparam;
if (!ppd)
return;
_cupsStrFree(ppd->lang_encoding);
_cupsStrFree(ppd->nickname);
if (ppd->patches)
free(ppd->patches);
_cupsStrFree(ppd->jcl_begin);
_cupsStrFree(ppd->jcl_end);
_cupsStrFree(ppd->jcl_ps);
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);
}
if (ppd->num_groups > 0)
{
for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
ppd_free_group(group);
ppd_free(ppd->groups);
}
cupsArrayDelete(ppd->options);
cupsArrayDelete(ppd->marked);
if (ppd->num_sizes > 0)
ppd_free(ppd->sizes);
if (ppd->num_consts > 0)
ppd_free(ppd->consts);
if (ppd->num_filters > 0)
{
for (i = ppd->num_filters, filter = ppd->filters; i > 0; i --, filter ++)
_cupsStrFree(*filter);
ppd_free(ppd->filters);
}
if (ppd->num_fonts > 0)
{
for (i = ppd->num_fonts, font = ppd->fonts; i > 0; i --, font ++)
_cupsStrFree(*font);
ppd_free(ppd->fonts);
}
if (ppd->num_profiles > 0)
ppd_free(ppd->profiles);
if (ppd->num_attrs > 0)
{
for (i = ppd->num_attrs, attr = ppd->attrs; i > 0; i --, attr ++)
{
_cupsStrFree((*attr)->value);
ppd_free(*attr);
}
ppd_free(ppd->attrs);
}
cupsArrayDelete(ppd->sorted_attrs);
for (coption = (ppd_coption_t *)cupsArrayFirst(ppd->coptions);
coption;
coption = (ppd_coption_t *)cupsArrayNext(ppd->coptions))
{
for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
cparam;
cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
{
switch (cparam->type)
{
case PPD_CUSTOM_PASSCODE :
case PPD_CUSTOM_PASSWORD :
case PPD_CUSTOM_STRING :
_cupsStrFree(cparam->current.custom_string);
break;
default :
break;
}
free(cparam);
}
cupsArrayDelete(coption->params);
free(coption);
}
cupsArrayDelete(ppd->coptions);
if (ppd->cups_uiconstraints)
{
_ppd_cups_uiconsts_t *consts;
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);
}
if (ppd->pwg)
_pwgDestroy((_pwg_t *)ppd->pwg);
ppd_free(ppd);
}
const char *
ppdErrorString(ppd_status_t status)
{
static const char * const messages[] =
{
_("OK"),
_("Unable to open PPD file"),
_("NULL PPD file pointer"),
_("Memory allocation error"),
_("Missing PPD-Adobe-4.x header"),
_("Missing value string"),
_("Internal error"),
_("Bad OpenGroup"),
_("OpenGroup without a CloseGroup first"),
_("Bad OpenUI/JCLOpenUI"),
_("OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"),
_("Bad OrderDependency"),
_("Bad UIConstraints"),
_("Missing asterisk in column 1"),
_("Line longer than the maximum allowed (255 characters)"),
_("Illegal control character"),
_("Illegal main keyword string"),
_("Illegal option keyword string"),
_("Illegal translation string"),
_("Illegal whitespace character"),
_("Bad custom parameter"),
_("Missing option keyword"),
_("Bad value string")
};
if (status < PPD_OK || status >= PPD_MAX_STATUS)
return (_cupsLangString(cupsLangDefault(), _("Unknown")));
else
return (_cupsLangString(cupsLangDefault(), messages[status]));
}
cups_encoding_t
_ppdGetEncoding(const char *name)
{
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);
}
ppd_status_t
ppdLastError(int *line)
{
_cups_globals_t *cg = _cupsGlobals();
if (line)
*line = cg->ppd_line;
return (cg->ppd_status);
}
ppd_file_t *
ppdOpen(FILE *fp)
{
ppd_file_t *ppd;
cups_file_t *cf;
if ((cf = cupsFileOpenFd(fileno(fp), "r")) == NULL)
return (NULL);
ppd = ppdOpen2(cf);
cupsFileClose(cf);
return (ppd);
}
ppd_file_t *
ppdOpen2(cups_file_t *fp)
{
int i, j, k;
int count;
_ppd_line_t line;
ppd_file_t *ppd;
ppd_group_t *group,
*subgroup;
ppd_option_t *option;
ppd_choice_t *choice;
ppd_const_t *constraint;
ppd_size_t *size;
int mask;
char keyword[PPD_MAX_NAME],
name[PPD_MAX_NAME],
text[PPD_MAX_LINE],
*string,
*sptr,
*nameptr,
*temp,
**tempfonts;
float order;
ppd_section_t section;
ppd_profile_t *profile;
char **filter;
cups_lang_t *language;
struct lconv *loc;
int ui_keyword;
cups_encoding_t encoding;
_cups_globals_t *cg = _cupsGlobals();
char custom_name[PPD_MAX_NAME];
ppd_attr_t *custom_attr;
static const char * const ui_keywords[] =
{
#ifdef CUPS_USE_FULL_UI_KEYWORDS_LIST
"BlackSubstitution",
"Booklet",
"Collate",
"ManualFeed",
"MirrorPrint",
"NegativePrint",
"Sorter",
"TraySwitch",
"AdvanceMedia",
"BindColor",
"BindEdge",
"BindType",
"BindWhen",
"BitsPerPixel",
"ColorModel",
"CutMedia",
"Duplex",
"FoldType",
"FoldWhen",
"InputSlot",
"JCLFrameBufferSize",
"JCLResolution",
"Jog",
"MediaColor",
"MediaType",
"MediaWeight",
"OutputBin",
"OutputMode",
"OutputOrder",
"PageRegion",
"PageSize",
"Resolution",
"Separations",
"Signature",
"Slipsheet",
"Smoothing",
"StapleLocation",
"StapleOrientation",
"StapleWhen",
"StapleX",
"StapleY"
#else
"PageRegion",
"PageSize"
#endif
};
DEBUG_printf(("ppdOpen2(fp=%p)", fp));
cg->ppd_status = PPD_OK;
cg->ppd_line = 0;
if (fp == NULL)
{
cg->ppd_status = PPD_NULL_FILE;
return (NULL);
}
line.buffer = NULL;
line.bufsize = 0;
mask = ppd_read(fp, &line, keyword, name, text, &string, 0, cg);
DEBUG_printf(("2ppdOpen2: mask=%x, keyword=\"%s\"...", mask, keyword));
if (mask == 0 ||
strcmp(keyword, "PPD-Adobe") ||
string == NULL || string[0] != '4')
{
if (cg->ppd_status == PPD_OK)
cg->ppd_status = PPD_MISSING_PPDADOBE4;
_cupsStrFree(string);
ppd_free(line.buffer);
return (NULL);
}
DEBUG_printf(("2ppdOpen2: keyword=%s, string=%p", keyword, string));
_cupsStrFree(string);
if ((ppd = calloc(1, sizeof(ppd_file_t))) == NULL)
{
cg->ppd_status = PPD_ALLOC_ERROR;
_cupsStrFree(string);
ppd_free(line.buffer);
return (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);
language = cupsLangDefault();
loc = localeconv();
group = NULL;
subgroup = NULL;
option = NULL;
choice = NULL;
ui_keyword = 0;
encoding = CUPS_ISO8859_1;
while ((mask = ppd_read(fp, &line, keyword, name, text, &string, 1, cg)) != 0)
{
DEBUG_printf(("2ppdOpen2: 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)
{
cg->ppd_status = PPD_MISSING_VALUE;
goto error;
}
else if (!string)
continue;
if (ui_keyword)
{
option = NULL;
ui_keyword = 0;
}
if (option == NULL &&
(mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) ==
(PPD_KEYWORD | PPD_OPTION | PPD_STRING))
{
for (i = 0; i < (int)(sizeof(ui_keywords) / sizeof(ui_keywords[0])); i ++)
if (!strcmp(keyword, ui_keywords[i]))
break;
if (i < (int)(sizeof(ui_keywords) / sizeof(ui_keywords[0])))
{
ui_keyword = 1;
DEBUG_printf(("2ppdOpen2: FOUND ADOBE UI KEYWORD %s WITHOUT OPENUI!",
keyword));
if (!group)
{
if ((group = ppd_get_group(ppd, "General", _("General"), cg,
encoding)) == NULL)
goto error;
DEBUG_printf(("2ppdOpen2: Adding to group %s...", group->text));
option = ppd_get_option(group, keyword);
group = NULL;
}
else
option = ppd_get_option(group, keyword);
if (option == NULL)
{
cg->ppd_status = PPD_ALLOC_ERROR;
goto error;
}
if (!strncmp(keyword, "JCL", 3))
option->section = PPD_ORDER_JCL;
else
option->section = PPD_ORDER_ANY;
option->order = 10.0f;
if (i < 8)
option->ui = PPD_UI_BOOLEAN;
else
option->ui = PPD_UI_PICKONE;
for (j = 0; j < ppd->num_attrs; j ++)
if (!strncmp(ppd->attrs[j]->name, "Default", 7) &&
!strcmp(ppd->attrs[j]->name + 7, keyword) &&
ppd->attrs[j]->value)
{
DEBUG_printf(("2ppdOpen2: Setting Default%s to %s via attribute...",
option->keyword, ppd->attrs[j]->value));
strlcpy(option->defchoice, ppd->attrs[j]->value,
sizeof(option->defchoice));
break;
}
if (!strcmp(keyword, "PageSize"))
strlcpy(option->text, _("Media Size"), sizeof(option->text));
else if (!strcmp(keyword, "MediaType"))
strlcpy(option->text, _("Media Type"), sizeof(option->text));
else if (!strcmp(keyword, "InputSlot"))
strlcpy(option->text, _("Media Source"), sizeof(option->text));
else if (!strcmp(keyword, "ColorModel"))
strlcpy(option->text, _("Output Mode"), sizeof(option->text));
else if (!strcmp(keyword, "Resolution"))
strlcpy(option->text, _("Resolution"), sizeof(option->text));
else
strlcpy(option->text, keyword, sizeof(option->text));
}
}
if (!strcmp(keyword, "LanguageLevel"))
ppd->language_level = atoi(string);
else if (!strcmp(keyword, "LanguageEncoding"))
{
ppd->lang_encoding = _cupsStrAlloc("UTF-8");
encoding = _ppdGetEncoding(string);
}
else if (!strcmp(keyword, "LanguageVersion"))
ppd->lang_version = string;
else if (!strcmp(keyword, "Manufacturer"))
ppd->manufacturer = string;
else if (!strcmp(keyword, "ModelName"))
ppd->modelname = string;
else if (!strcmp(keyword, "Protocols"))
ppd->protocols = string;
else if (!strcmp(keyword, "PCFileName"))
ppd->pcfilename = string;
else if (!strcmp(keyword, "NickName"))
{
if (encoding != CUPS_UTF8)
{
cups_utf8_t utf8[256];
cupsCharsetToUTF8(utf8, string, sizeof(utf8), encoding);
ppd->nickname = _cupsStrAlloc((char *)utf8);
}
else
ppd->nickname = _cupsStrAlloc(string);
}
else if (!strcmp(keyword, "Product"))
ppd->product = string;
else if (!strcmp(keyword, "ShortNickName"))
ppd->shortnickname = string;
else if (!strcmp(keyword, "TTRasterizer"))
ppd->ttrasterizer = string;
else if (!strcmp(keyword, "JCLBegin"))
{
ppd->jcl_begin = _cupsStrAlloc(string);
ppd_decode(ppd->jcl_begin);
}
else if (!strcmp(keyword, "JCLEnd"))
{
ppd->jcl_end = _cupsStrAlloc(string);
ppd_decode(ppd->jcl_end);
}
else if (!strcmp(keyword, "JCLToPSInterpreter"))
{
ppd->jcl_ps = _cupsStrAlloc(string);
ppd_decode(ppd->jcl_ps);
}
else if (!strcmp(keyword, "AccurateScreensSupport"))
ppd->accurate_screens = !strcmp(string, "True");
else if (!strcmp(keyword, "ColorDevice"))
ppd->color_device = !strcmp(string, "True");
else if (!strcmp(keyword, "ContoneOnly"))
ppd->contone_only = !strcmp(string, "True");
else if (!strcmp(keyword, "cupsFlipDuplex"))
ppd->flip_duplex = !strcmp(string, "True");
else if (!strcmp(keyword, "cupsManualCopies"))
ppd->manual_copies = !strcmp(string, "True");
else if (!strcmp(keyword, "cupsModelNumber"))
ppd->model_number = atoi(string);
else if (!strcmp(keyword, "cupsColorProfile"))
{
if (ppd->num_profiles == 0)
profile = malloc(sizeof(ppd_profile_t));
else
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 ++;
memset(profile, 0, sizeof(ppd_profile_t));
strlcpy(profile->resolution, name, sizeof(profile->resolution));
strlcpy(profile->media_type, text, sizeof(profile->media_type));
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 (ppd->num_filters == 0)
filter = malloc(sizeof(char *));
else
filter = realloc(ppd->filters, sizeof(char *) * (ppd->num_filters + 1));
if (filter == NULL)
{
cg->ppd_status = PPD_ALLOC_ERROR;
goto error;
}
ppd->filters = filter;
filter += ppd->num_filters;
ppd->num_filters ++;
*filter = string;
string = NULL;
}
else if (!strcmp(keyword, "Throughput"))
ppd->throughput = atoi(string);
else if (!strcmp(keyword, "Font"))
{
if (ppd->num_fonts == 0)
tempfonts = (char **)malloc(sizeof(char *));
else
tempfonts = (char **)realloc(ppd->fonts,
sizeof(char *) * (ppd->num_fonts + 1));
if (tempfonts == NULL)
{
cg->ppd_status = PPD_ALLOC_ERROR;
goto error;
}
ppd->fonts = tempfonts;
ppd->fonts[ppd->num_fonts] = _cupsStrAlloc(name);
ppd->num_fonts ++;
}
else if (!strncmp(keyword, "ParamCustom", 11))
{
ppd_coption_t *coption;
ppd_cparam_t *cparam;
int corder;
char ctype[33],
cminimum[65],
cmaximum[65];
if ((coption = ppd_get_coption(ppd, keyword + 11)) == NULL)
{
cg->ppd_status = PPD_ALLOC_ERROR;
goto error;
}
if ((cparam = ppd_get_cparam(coption, name, text)) == NULL)
{
cg->ppd_status = PPD_ALLOC_ERROR;
goto error;
}
if (!string ||
sscanf(string, "%d%32s%64s%64s", &corder, ctype, cminimum,
cmaximum) != 4)
{
cg->ppd_status = PPD_BAD_CUSTOM_PARAM;
goto error;
}
cparam->order = corder;
if (!strcmp(ctype, "curve"))
{
cparam->type = PPD_CUSTOM_CURVE;
cparam->minimum.custom_curve = (float)_cupsStrScand(cminimum, NULL, loc);
cparam->maximum.custom_curve = (float)_cupsStrScand(cmaximum, NULL, loc);
}
else if (!strcmp(ctype, "int"))
{
cparam->type = PPD_CUSTOM_INT;
cparam->minimum.custom_int = atoi(cminimum);
cparam->maximum.custom_int = atoi(cmaximum);
}
else if (!strcmp(ctype, "invcurve"))
{
cparam->type = PPD_CUSTOM_INVCURVE;
cparam->minimum.custom_invcurve = (float)_cupsStrScand(cminimum, NULL, loc);
cparam->maximum.custom_invcurve = (float)_cupsStrScand(cmaximum, NULL, loc);
}
else if (!strcmp(ctype, "passcode"))
{
cparam->type = PPD_CUSTOM_PASSCODE;
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 = atoi(cminimum);
cparam->maximum.custom_password = atoi(cmaximum);
}
else if (!strcmp(ctype, "points"))
{
cparam->type = PPD_CUSTOM_POINTS;
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 = (float)_cupsStrScand(cminimum, NULL, loc);
cparam->maximum.custom_real = (float)_cupsStrScand(cmaximum, NULL, loc);
}
else if (!strcmp(ctype, "string"))
{
cparam->type = PPD_CUSTOM_STRING;
cparam->minimum.custom_string = atoi(cminimum);
cparam->maximum.custom_string = atoi(cmaximum);
}
else
{
cg->ppd_status = PPD_BAD_CUSTOM_PARAM;
goto error;
}
if (!strcmp(coption->keyword, "PageSize"))
{
if (!strcmp(name, "Width"))
{
ppd->custom_min[0] = cparam->minimum.custom_points;
ppd->custom_max[0] = cparam->maximum.custom_points;
}
else if (!strcmp(name, "Height"))
{
ppd->custom_min[1] = cparam->minimum.custom_points;
ppd->custom_max[1] = cparam->maximum.custom_points;
}
}
}
else if (!strcmp(keyword, "HWMargins"))
{
for (i = 0, sptr = string; i < 4; i ++)
ppd->custom_margins[i] = (float)_cupsStrScand(sptr, &sptr, loc);
}
else if (!strncmp(keyword, "Custom", 6) && !strcmp(name, "True") && !option)
{
ppd_option_t *custom_option;
DEBUG_puts("2ppdOpen2: Processing Custom option...");
if (!ppd_get_coption(ppd, keyword + 6))
{
cg->ppd_status = PPD_ALLOC_ERROR;
goto error;
}
if (option && !strcasecmp(option->keyword, keyword + 6))
custom_option = option;
else
custom_option = ppdFindOption(ppd, keyword + 6);
if (custom_option)
{
if ((choice = ppdFindChoice(custom_option, "Custom")) == NULL)
if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL)
{
DEBUG_puts("1ppdOpen2: Unable to add Custom choice!");
cg->ppd_status = PPD_ALLOC_ERROR;
goto error;
}
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);
}
if (!strcmp(keyword, "CustomPageSize"))
{
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("1ppdOpen2: 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"))
{
if (!strcmp(string, "Minus90"))
ppd->landscape = -90;
else if (!strcmp(string, "Plus90"))
ppd->landscape = 90;
}
else if (!strcmp(keyword, "Emulators") && string)
{
for (count = 1, sptr = string; sptr != NULL;)
if ((sptr = strchr(sptr, ' ')) != NULL)
{
count ++;
while (*sptr == ' ')
sptr ++;
}
ppd->num_emulations = count;
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 ++)
{
for (nameptr = ppd->emulations[i].name;
*sptr != '\0' && *sptr != ' ';
sptr ++)
if (nameptr < (ppd->emulations[i].name + sizeof(ppd->emulations[i].name) - 1))
*nameptr++ = *sptr;
*nameptr = '\0';
while (*sptr == ' ')
sptr ++;
}
}
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 (isdigit(*string & 255))
{
for (sptr = string + 1; isdigit(*sptr & 255); sptr ++);
if (*sptr == ':')
{
cg->ppd_status = PPD_BAD_VALUE;
goto error;
}
}
if (!name[0])
{
cg->ppd_status = PPD_MISSING_OPTION_KEYWORD;
goto error;
}
if (ppd->patches == NULL)
ppd->patches = strdup(string);
else
{
temp = realloc(ppd->patches, strlen(ppd->patches) +
strlen(string) + 1);
if (temp == NULL)
{
cg->ppd_status = PPD_ALLOC_ERROR;
goto error;
}
ppd->patches = temp;
strcpy(ppd->patches + strlen(ppd->patches), string);
}
}
else if (!strcmp(keyword, "OpenUI"))
{
if (option && cg->ppd_conform == PPD_CONFORM_STRICT)
{
cg->ppd_status = PPD_NESTED_OPEN_UI;
goto error;
}
DEBUG_printf(("2ppdOpen2: name=\"%s\" (%d)", name, (int)strlen(name)));
if (name[0] == '*')
_cups_strcpy(name, name + 1);
for (i = (int)strlen(name) - 1; i > 0 && _cups_isspace(name[i]); i --)
name[i] = '\0';
DEBUG_printf(("2ppdOpen2: 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,
encoding)) == NULL)
goto error;
DEBUG_printf(("2ppdOpen2: Adding to group %s...", group->text));
option = ppd_get_option(group, name);
group = NULL;
}
else
option = ppd_get_option(group, name);
if (option == NULL)
{
cg->ppd_status = PPD_ALLOC_ERROR;
goto error;
}
if (string && !strcmp(string, "PickMany"))
option->ui = PPD_UI_PICKMANY;
else if (string && !strcmp(string, "Boolean"))
option->ui = PPD_UI_BOOLEAN;
else if (string && !strcmp(string, "PickOne"))
option->ui = PPD_UI_PICKONE;
else if (cg->ppd_conform == PPD_CONFORM_STRICT)
{
cg->ppd_status = PPD_BAD_OPEN_UI;
goto error;
}
else
option->ui = PPD_UI_PICKONE;
for (j = 0; j < ppd->num_attrs; j ++)
if (!strncmp(ppd->attrs[j]->name, "Default", 7) &&
!strcmp(ppd->attrs[j]->name + 7, name) &&
ppd->attrs[j]->value)
{
DEBUG_printf(("2ppdOpen2: Setting Default%s to %s via attribute...",
option->keyword, ppd->attrs[j]->value));
strlcpy(option->defchoice, ppd->attrs[j]->value,
sizeof(option->defchoice));
break;
}
if (text[0])
cupsCharsetToUTF8((cups_utf8_t *)option->text, text,
sizeof(option->text), encoding);
else
{
if (!strcmp(name, "PageSize"))
strlcpy(option->text, _("Media Size"), sizeof(option->text));
else if (!strcmp(name, "MediaType"))
strlcpy(option->text, _("Media Type"), sizeof(option->text));
else if (!strcmp(name, "InputSlot"))
strlcpy(option->text, _("Media Source"), sizeof(option->text));
else if (!strcmp(name, "ColorModel"))
strlcpy(option->text, _("Output Mode"), sizeof(option->text));
else if (!strcmp(name, "Resolution"))
strlcpy(option->text, _("Resolution"), sizeof(option->text));
else
strlcpy(option->text, name, sizeof(option->text));
}
option->section = PPD_ORDER_ANY;
_cupsStrFree(string);
string = NULL;
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("1ppdOpen2: 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"))
{
if (option && cg->ppd_conform == PPD_CONFORM_STRICT)
{
cg->ppd_status = PPD_NESTED_OPEN_UI;
goto error;
}
group = ppd_get_group(ppd, "JCL", _("JCL"), cg, encoding);
if (group == NULL)
goto error;
if (name[0] == '*')
_cups_strcpy(name, name + 1);
option = ppd_get_option(group, name);
if (option == NULL)
{
cg->ppd_status = PPD_ALLOC_ERROR;
goto error;
}
if (string && !strcmp(string, "PickMany"))
option->ui = PPD_UI_PICKMANY;
else if (string && !strcmp(string, "Boolean"))
option->ui = PPD_UI_BOOLEAN;
else if (string && !strcmp(string, "PickOne"))
option->ui = PPD_UI_PICKONE;
else
{
cg->ppd_status = PPD_BAD_OPEN_UI;
goto error;
}
for (j = 0; j < ppd->num_attrs; j ++)
if (!strncmp(ppd->attrs[j]->name, "Default", 7) &&
!strcmp(ppd->attrs[j]->name + 7, name) &&
ppd->attrs[j]->value)
{
DEBUG_printf(("2ppdOpen2: Setting Default%s to %s via attribute...",
option->keyword, ppd->attrs[j]->value));
strlcpy(option->defchoice, ppd->attrs[j]->value,
sizeof(option->defchoice));
break;
}
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;
_cupsStrFree(string);
string = NULL;
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("1ppdOpen2: 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;
_cupsStrFree(string);
string = NULL;
}
else if (!strcmp(keyword, "OpenGroup"))
{
if (group != NULL)
{
cg->ppd_status = PPD_NESTED_OPEN_GROUP;
goto error;
}
if (!string)
{
cg->ppd_status = PPD_BAD_OPEN_GROUP;
goto error;
}
if ((sptr = strchr(string, '/')) != NULL)
*sptr++ = '\0';
else
sptr = string;
ppd_decode(sptr);
group = ppd_get_group(ppd, string, sptr, cg, encoding);
if (group == NULL)
goto error;
_cupsStrFree(string);
string = NULL;
}
else if (!strcmp(keyword, "CloseGroup"))
{
group = NULL;
_cupsStrFree(string);
string = NULL;
}
else if (!strcmp(keyword, "OrderDependency"))
{
order = (float)_cupsStrScand(string, &sptr, loc);
if (!sptr || sscanf(sptr, "%40s%40s", name, keyword) != 2)
{
cg->ppd_status = PPD_BAD_ORDER_DEPENDENCY;
goto error;
}
if (keyword[0] == '*')
_cups_strcpy(keyword, keyword + 1);
if (!strcmp(name, "ExitServer"))
section = PPD_ORDER_EXIT;
else if (!strcmp(name, "Prolog"))
section = PPD_ORDER_PROLOG;
else if (!strcmp(name, "DocumentSetup"))
section = PPD_ORDER_DOCUMENT;
else if (!strcmp(name, "PageSetup"))
section = PPD_ORDER_PAGE;
else if (!strcmp(name, "JCLSetup"))
section = PPD_ORDER_JCL;
else
section = PPD_ORDER_ANY;
if (option == NULL)
{
ppd_group_t *gtemp;
for (i = ppd->num_groups, gtemp = ppd->groups; i > 0; i --, gtemp ++)
if (gtemp->text[0] == '\0')
break;
if (i > 0)
for (i = 0; i < gtemp->num_options; i ++)
if (!strcmp(keyword, gtemp->options[i].keyword))
{
gtemp->options[i].section = section;
gtemp->options[i].order = order;
break;
}
}
else
{
option->section = section;
option->order = order;
}
_cupsStrFree(string);
string = NULL;
}
else if (!strncmp(keyword, "Default", 7))
{
if (string == NULL)
continue;
if (strchr(string, '/') != NULL)
*strchr(string, '/') = '\0';
if (!strcmp(keyword, "DefaultColorSpace"))
{
if (!strcmp(string, "CMY"))
ppd->colorspace = PPD_CS_CMY;
else if (!strcmp(string, "CMYK"))
ppd->colorspace = PPD_CS_CMYK;
else if (!strcmp(string, "RGB"))
ppd->colorspace = PPD_CS_RGB;
else if (!strcmp(string, "RGBK"))
ppd->colorspace = PPD_CS_RGBK;
else if (!strcmp(string, "N"))
ppd->colorspace = PPD_CS_N;
else
ppd->colorspace = PPD_CS_GRAY;
}
else if (option && !strcmp(keyword + 7, option->keyword))
{
DEBUG_printf(("2ppdOpen2: Setting %s to %s...", keyword, string));
strlcpy(option->defchoice, string, sizeof(option->defchoice));
DEBUG_printf(("2ppdOpen2: %s is now %s...", keyword, option->defchoice));
}
else
{
ppd_option_t *toption;
if ((toption = ppdFindOption(ppd, keyword + 7)) != NULL)
{
DEBUG_printf(("2ppdOpen2: Setting %s to %s...", keyword, string));
strlcpy(toption->defchoice, string, sizeof(toption->defchoice));
}
}
}
else if (!strcmp(keyword, "UIConstraints") ||
!strcmp(keyword, "NonUIConstraints"))
{
if (!string)
{
cg->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));
if (constraint == NULL)
{
cg->ppd_status = PPD_ALLOC_ERROR;
goto error;
}
ppd->consts = constraint;
constraint += ppd->num_consts;
ppd->num_consts ++;
switch (sscanf(string, "%40s%40s%40s%40s", constraint->option1,
constraint->choice1, constraint->option2,
constraint->choice2))
{
case 0 :
case 1 :
cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
goto error;
case 2 :
if (cg->ppd_conform == PPD_CONFORM_STRICT &&
(!strcmp(constraint->option1, "*") ||
!strcmp(constraint->choice1, "*")))
{
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 (constraint->choice1[0] == '*')
_cups_strcpy(constraint->option2, constraint->choice1 + 1);
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 :
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;
}
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';
}
else
{
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 :
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;
}
_cupsStrFree(string);
string = NULL;
}
else if (!strcmp(keyword, "PaperDimension"))
{
if ((size = ppdPageSize(ppd, name)) == NULL)
size = ppd_add_size(ppd, name);
if (size == NULL)
{
cg->ppd_status = PPD_ALLOC_ERROR;
goto error;
}
size->width = (float)_cupsStrScand(string, &sptr, loc);
size->length = (float)_cupsStrScand(sptr, NULL, loc);
_cupsStrFree(string);
string = NULL;
}
else if (!strcmp(keyword, "ImageableArea"))
{
if ((size = ppdPageSize(ppd, name)) == NULL)
size = ppd_add_size(ppd, name);
if (size == NULL)
{
cg->ppd_status = PPD_ALLOC_ERROR;
goto error;
}
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);
_cupsStrFree(string);
string = NULL;
}
else if (option != NULL &&
(mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) ==
(PPD_KEYWORD | PPD_OPTION | PPD_STRING) &&
!strcmp(keyword, option->keyword))
{
DEBUG_printf(("2ppdOpen2: group=%p, subgroup=%p", group, subgroup));
if (!strcmp(keyword, "PageSize"))
{
if (ppdPageSize(ppd, name) == NULL)
ppd_add_size(ppd, 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,
sizeof(choice->text), encoding);
else if (!strcmp(name, "True"))
strcpy(choice->text, _("Yes"));
else if (!strcmp(name, "False"))
strcpy(choice->text, _("No"));
else
strlcpy(choice->text, name, sizeof(choice->text));
if (option->section == PPD_ORDER_JCL)
ppd_decode(string);
choice->code = string;
string = NULL;
}
if (string &&
(mask & (PPD_KEYWORD | PPD_STRING)) == (PPD_KEYWORD | PPD_STRING))
ppd_add_attr(ppd, keyword, name, text, string);
else
_cupsStrFree(string);
}
ppd_free(line.buffer);
cupsLangFree(language);
#ifdef DEBUG
if (!cupsFileEOF(fp))
DEBUG_printf(("1ppdOpen2: Premature EOF at %lu...\n",
(unsigned long)cupsFileTell(fp)));
#endif
if (cg->ppd_status != PPD_OK)
{
ppdClose(ppd);
return (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;
i --, group ++)
{
for (j = group->num_options, option = group->options;
j > 0;
j --, option ++)
{
ppd_coption_t *coption;
cupsArrayAdd(ppd->options, option);
for (k = 0; k < option->num_choices; k ++)
option->choices[k].option = option;
if ((coption = ppdFindCustomOption(ppd, option->keyword)) != NULL)
coption->option = option;
}
}
ppd->marked = cupsArrayNew((cups_array_func_t)ppd_compare_choices, NULL);
return (ppd);
error:
_cupsStrFree(string);
ppd_free(line.buffer);
ppdClose(ppd);
cupsLangFree(language);
return (NULL);
}
ppd_file_t *
ppdOpenFd(int fd)
{
cups_file_t *fp;
ppd_file_t *ppd;
_cups_globals_t *cg = _cupsGlobals();
cg->ppd_line = 0;
if (fd < 0)
{
cg->ppd_status = PPD_NULL_FILE;
return (NULL);
}
if ((fp = cupsFileOpenFd(fd, "r")) != NULL)
{
ppd = ppdOpen2(fp);
cupsFileClose(fp);
}
else
{
cg->ppd_status = PPD_FILE_OPEN_ERROR;
ppd = NULL;
}
return (ppd);
}
ppd_file_t *
ppdOpenFile(const char *filename)
{
cups_file_t *fp;
ppd_file_t *ppd;
_cups_globals_t *cg = _cupsGlobals();
cg->ppd_line = 0;
if (filename == NULL)
{
cg->ppd_status = PPD_NULL_FILE;
return (NULL);
}
if ((fp = cupsFileOpen(filename, "r")) != NULL)
{
ppd = ppdOpen2(fp);
cupsFileClose(fp);
}
else
{
cg->ppd_status = PPD_FILE_OPEN_ERROR;
ppd = NULL;
}
return (ppd);
}
void
ppdSetConformance(ppd_conform_t c)
{
_cups_globals_t *cg = _cupsGlobals();
cg->ppd_conform = c;
}
static ppd_attr_t *
ppd_add_attr(ppd_file_t *ppd,
const char *name,
const char *spec,
const char *text,
const char *value)
{
ppd_attr_t **ptr,
*temp;
if (ppd == NULL || name == NULL || spec == NULL)
return (NULL);
if (!ppd->sorted_attrs)
ppd->sorted_attrs = cupsArrayNew((cups_array_func_t)ppd_compare_attrs,
NULL);
if (ppd->num_attrs == 0)
ptr = malloc(sizeof(ppd_attr_t *));
else
ptr = realloc(ppd->attrs, (ppd->num_attrs + 1) * sizeof(ppd_attr_t *));
if (ptr == NULL)
return (NULL);
ppd->attrs = ptr;
ptr += ppd->num_attrs;
if ((temp = calloc(1, sizeof(ppd_attr_t))) == NULL)
return (NULL);
*ptr = temp;
ppd->num_attrs ++;
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;
cupsArrayAdd(ppd->sorted_attrs, temp);
return (temp);
}
static ppd_choice_t *
ppd_add_choice(ppd_option_t *option,
const char *name)
{
ppd_choice_t *choice;
if (option->num_choices == 0)
choice = malloc(sizeof(ppd_choice_t));
else
choice = realloc(option->choices,
sizeof(ppd_choice_t) * (option->num_choices + 1));
if (choice == NULL)
return (NULL);
option->choices = choice;
choice += option->num_choices;
option->num_choices ++;
memset(choice, 0, sizeof(ppd_choice_t));
strlcpy(choice->choice, name, sizeof(choice->choice));
return (choice);
}
static ppd_size_t *
ppd_add_size(ppd_file_t *ppd,
const char *name)
{
ppd_size_t *size;
if (ppd->num_sizes == 0)
size = malloc(sizeof(ppd_size_t));
else
size = realloc(ppd->sizes, sizeof(ppd_size_t) * (ppd->num_sizes + 1));
if (size == NULL)
return (NULL);
ppd->sizes = size;
size += ppd->num_sizes;
ppd->num_sizes ++;
memset(size, 0, sizeof(ppd_size_t));
strlcpy(size->name, name, sizeof(size->name));
return (size);
}
static int
ppd_compare_attrs(ppd_attr_t *a,
ppd_attr_t *b)
{
return (strcasecmp(a->name, b->name));
}
static int
ppd_compare_choices(ppd_choice_t *a,
ppd_choice_t *b)
{
return (strcmp(a->option->keyword, b->option->keyword));
}
static int
ppd_compare_coptions(ppd_coption_t *a,
ppd_coption_t *b)
{
return (strcasecmp(a->keyword, b->keyword));
}
static int
ppd_compare_cparams(ppd_cparam_t *a,
ppd_cparam_t *b)
{
return (strcasecmp(a->name, b->name));
}
static int
ppd_compare_options(ppd_option_t *a,
ppd_option_t *b)
{
return (strcasecmp(a->keyword, b->keyword));
}
static int
ppd_decode(char *string)
{
char *inptr,
*outptr;
inptr = string;
outptr = string;
while (*inptr != '\0')
if (*inptr == '<' && isxdigit(inptr[1] & 255))
{
inptr ++;
while (isxdigit(*inptr & 255))
{
if (_cups_isalpha(*inptr))
*outptr = (tolower(*inptr) - 'a' + 10) << 4;
else
*outptr = (*inptr - '0') << 4;
inptr ++;
if (!isxdigit(*inptr & 255))
break;
if (_cups_isalpha(*inptr))
*outptr |= tolower(*inptr) - 'a' + 10;
else
*outptr |= *inptr - '0';
inptr ++;
outptr ++;
}
while (*inptr != '>' && *inptr != '\0')
inptr ++;
while (*inptr == '>')
inptr ++;
}
else
*outptr++ = *inptr++;
*outptr = '\0';
return ((int)(outptr - string));
}
static void
ppd_free_group(ppd_group_t *group)
{
int i;
ppd_option_t *option;
ppd_group_t *subgroup;
if (group->num_options > 0)
{
for (i = group->num_options, option = group->options;
i > 0;
i --, option ++)
ppd_free_option(option);
ppd_free(group->options);
}
if (group->num_subgroups > 0)
{
for (i = group->num_subgroups, subgroup = group->subgroups;
i > 0;
i --, subgroup ++)
ppd_free_group(subgroup);
ppd_free(group->subgroups);
}
}
static void
ppd_free_option(ppd_option_t *option)
{
int i;
ppd_choice_t *choice;
if (option->num_choices > 0)
{
for (i = option->num_choices, choice = option->choices;
i > 0;
i --, choice ++)
{
_cupsStrFree(choice->code);
}
ppd_free(option->choices);
}
}
static ppd_coption_t *
ppd_get_coption(ppd_file_t *ppd,
const char *name)
{
ppd_coption_t *copt;
if ((copt = ppdFindCustomOption(ppd, name)) != NULL)
return (copt);
if ((copt = calloc(1, sizeof(ppd_coption_t))) == NULL)
return (NULL);
strlcpy(copt->keyword, name, sizeof(copt->keyword));
copt->params = cupsArrayNew((cups_array_func_t)ppd_compare_cparams, NULL);
cupsArrayAdd(ppd->coptions, copt);
return (copt);
}
static ppd_cparam_t *
ppd_get_cparam(ppd_coption_t *opt,
const char *param,
const char *text)
{
ppd_cparam_t *cparam;
if ((cparam = ppdFindCustomParam(opt, param)) != NULL)
return (cparam);
if ((cparam = calloc(1, sizeof(ppd_cparam_t))) == NULL)
return (NULL);
strlcpy(cparam->name, param, sizeof(cparam->name));
strlcpy(cparam->text, text[0] ? text : param, sizeof(cparam->text));
cupsArrayAdd(opt->params, cparam);
return (cparam);
}
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)
{
int i;
ppd_group_t *group;
DEBUG_printf(("7ppd_get_group(ppd=%p, name=\"%s\", text=\"%s\", cg=%p)",
ppd, name, text, cg));
for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
if (!strcmp(group->name, name))
break;
if (i == 0)
{
DEBUG_printf(("8ppd_get_group: Adding group %s...", name));
if (cg->ppd_conform == PPD_CONFORM_STRICT && strlen(text) >= sizeof(group->text))
{
cg->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));
if (group == NULL)
{
cg->ppd_status = PPD_ALLOC_ERROR;
return (NULL);
}
ppd->groups = group;
group += ppd->num_groups;
ppd->num_groups ++;
memset(group, 0, sizeof(ppd_group_t));
strlcpy(group->name, name, sizeof(group->name));
cupsCharsetToUTF8((cups_utf8_t *)group->text, text,
sizeof(group->text), encoding);
}
return (group);
}
static ppd_option_t *
ppd_get_option(ppd_group_t *group,
const char *name)
{
int i;
ppd_option_t *option;
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 ++)
if (!strcmp(option->keyword, name))
break;
if (i == 0)
{
if (group->num_options == 0)
option = malloc(sizeof(ppd_option_t));
else
option = realloc(group->options,
(group->num_options + 1) * sizeof(ppd_option_t));
if (option == NULL)
return (NULL);
group->options = option;
option += group->num_options;
group->num_options ++;
memset(option, 0, sizeof(ppd_option_t));
strlcpy(option->keyword, name, sizeof(option->keyword));
}
return (option);
}
static int
ppd_hash_option(ppd_option_t *option)
{
int hash = 0;
const char *k;
for (hash = option->keyword[0], k = option->keyword + 1; *k;)
hash = 33 * hash + *k++;
return (hash & 511);
}
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)
{
int ch,
col,
colon,
endquote,
mask,
startline,
textlen;
char *keyptr,
*optptr,
*textptr,
*strptr,
*lineptr;
*string = NULL;
col = 0;
startline = cg->ppd_line + 1;
if (!line->buffer)
{
line->bufsize = 1024;
line->buffer = malloc(1024);
if (!line->buffer)
return (0);
}
do
{
lineptr = line->buffer;
endquote = 0;
colon = 0;
while ((ch = cupsFileGetChar(fp)) != EOF)
{
if (lineptr >= (line->buffer + line->bufsize - 1))
{
char *temp;
line->bufsize += 1024;
if (line->bufsize > 262144)
{
cg->ppd_line = startline;
cg->ppd_status = PPD_LINE_TOO_LONG;
return (0);
}
temp = realloc(line->buffer, line->bufsize);
if (!temp)
{
cg->ppd_line = startline;
cg->ppd_status = PPD_LINE_TOO_LONG;
return (0);
}
lineptr = temp + (lineptr - line->buffer);
line->buffer = temp;
}
if (ch == '\r' || ch == '\n')
{
cg->ppd_line ++;
col = 0;
if (ch == '\r')
{
if ((ch = cupsFilePeekChar(fp)) == EOF)
{
ch = '\n';
break;
}
if (ch == 0x0a)
cupsFileGetChar(fp);
}
if (lineptr == line->buffer && ignoreblank)
continue;
ch = '\n';
if (!endquote)
break;
*lineptr++ = '\n';
}
else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
{
cg->ppd_line = startline;
cg->ppd_status = PPD_ILLEGAL_CHARACTER;
return (0);
}
else if (ch != 0x1a)
{
*lineptr++ = ch;
col ++;
if (col > (PPD_MAX_LINE - 1))
{
cg->ppd_line = startline;
cg->ppd_status = PPD_LINE_TOO_LONG;
return (0);
}
if (ch == ':' && strncmp(line->buffer, "*%", 2) != 0)
colon = 1;
if (ch == '\"' && colon)
endquote = !endquote;
}
}
if (endquote)
{
while ((ch = cupsFileGetChar(fp)) != EOF)
if (ch == '\"')
break;
else if (ch == '\r' || ch == '\n')
{
cg->ppd_line ++;
col = 0;
if (ch == '\r')
{
if ((ch = cupsFilePeekChar(fp)) == EOF)
break;
if (ch == 0x0a)
cupsFileGetChar(fp);
}
}
else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
{
cg->ppd_line = startline;
cg->ppd_status = PPD_ILLEGAL_CHARACTER;
return (0);
}
else if (ch != 0x1a)
{
col ++;
if (col > (PPD_MAX_LINE - 1))
{
cg->ppd_line = startline;
cg->ppd_status = PPD_LINE_TOO_LONG;
return (0);
}
}
}
if (ch != '\n')
{
while ((ch = cupsFileGetChar(fp)) != EOF)
if (ch == '\r' || ch == '\n')
{
cg->ppd_line ++;
col = 0;
if (ch == '\r')
{
if ((ch = cupsFilePeekChar(fp)) == EOF)
break;
if (ch == 0x0a)
cupsFileGetChar(fp);
}
break;
}
else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
{
cg->ppd_line = startline;
cg->ppd_status = PPD_ILLEGAL_CHARACTER;
return (0);
}
else if (ch != 0x1a)
{
col ++;
if (col > (PPD_MAX_LINE - 1))
{
cg->ppd_line = startline;
cg->ppd_status = PPD_LINE_TOO_LONG;
return (0);
}
}
}
if (lineptr > line->buffer && lineptr[-1] == '\n')
lineptr --;
*lineptr = '\0';
DEBUG_printf(("9ppd_read: LINE=\"%s\"", line->buffer));
if (!strcmp(line->buffer, "*%APLWORKSET START"))
return (0);
if (ch == EOF && lineptr == line->buffer)
return (0);
mask = 0;
lineptr = line->buffer + 1;
keyword[0] = '\0';
option[0] = '\0';
text[0] = '\0';
*string = NULL;
if ((!line->buffer[0] ||
!strncmp(line->buffer, "*%", 2) ||
!strcmp(line->buffer, "*End")) &&
ignoreblank)
{
startline = cg->ppd_line + 1;
continue;
}
if (!strcmp(line->buffer, "*"))
{
if (cg->ppd_conform == PPD_CONFORM_RELAXED)
{
startline = cg->ppd_line + 1;
continue;
}
else
{
cg->ppd_line = startline;
cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
return (0);
}
}
if (line->buffer[0] != '*')
{
for (lineptr = line->buffer; *lineptr; lineptr ++)
if (*lineptr && !_cups_isspace(*lineptr))
break;
if (*lineptr)
{
cg->ppd_status = PPD_MISSING_ASTERISK;
return (0);
}
else if (ignoreblank)
continue;
else
return (0);
}
keyptr = keyword;
while (*lineptr && *lineptr != ':' && !_cups_isspace(*lineptr))
{
if (*lineptr <= ' ' || *lineptr > 126 || *lineptr == '/' ||
(keyptr - keyword) >= (PPD_MAX_NAME - 1))
{
cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
return (0);
}
*keyptr++ = *lineptr++;
}
*keyptr = '\0';
if (!strcmp(keyword, "End"))
continue;
mask |= PPD_KEYWORD;
if (_cups_isspace(*lineptr))
{
while (_cups_isspace(*lineptr))
lineptr ++;
optptr = option;
while (*lineptr && !_cups_isspace(*lineptr) && *lineptr != ':' &&
*lineptr != '/')
{
if (*lineptr <= ' ' || *lineptr > 126 ||
(optptr - option) >= (PPD_MAX_NAME - 1))
{
cg->ppd_status = PPD_ILLEGAL_OPTION_KEYWORD;
return (0);
}
*optptr++ = *lineptr++;
}
*optptr = '\0';
if (_cups_isspace(*lineptr) && cg->ppd_conform == PPD_CONFORM_STRICT)
{
cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
return (0);
}
while (_cups_isspace(*lineptr))
lineptr ++;
mask |= PPD_OPTION;
if (*lineptr == '/')
{
lineptr ++;
textptr = text;
while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':')
{
if (((unsigned char)*lineptr < ' ' && *lineptr != '\t') ||
(textptr - text) >= (PPD_MAX_LINE - 1))
{
cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
return (0);
}
*textptr++ = *lineptr++;
}
*textptr = '\0';
textlen = ppd_decode(text);
if (textlen > PPD_MAX_TEXT && cg->ppd_conform == PPD_CONFORM_STRICT)
{
cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
return (0);
}
mask |= PPD_TEXT;
}
}
if (_cups_isspace(*lineptr) && cg->ppd_conform == PPD_CONFORM_STRICT)
{
cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
return (0);
}
while (_cups_isspace(*lineptr))
lineptr ++;
if (*lineptr == ':')
{
lineptr ++;
while (_cups_isspace(*lineptr))
lineptr ++;
strptr = lineptr + strlen(lineptr) - 1;
while (strptr >= lineptr && _cups_isspace(*strptr))
*strptr-- = '\0';
if (*strptr == '\"')
{
*strptr = '\0';
lineptr ++;
}
*string = _cupsStrAlloc(lineptr);
mask |= PPD_STRING;
}
}
while (mask == 0);
return (mask);
}