You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
847 lines
20 KiB
847 lines
20 KiB
/*
|
|
* IPP data file parsing functions.
|
|
*
|
|
* Copyright © 2007-2019 by Apple Inc.
|
|
* Copyright © 1997-2007 by Easy Software Products.
|
|
*
|
|
* Licensed under Apache License v2.0. See the file "LICENSE" for more
|
|
* information.
|
|
*/
|
|
|
|
/*
|
|
* Include necessary headers...
|
|
*/
|
|
|
|
#include "ipp-private.h"
|
|
#include "string-private.h"
|
|
#include "debug-internal.h"
|
|
|
|
|
|
/*
|
|
* Local functions...
|
|
*/
|
|
|
|
static ipp_t *parse_collection(_ipp_file_t *f, _ipp_vars_t *v, void *user_data);
|
|
static int parse_value(_ipp_file_t *f, _ipp_vars_t *v, void *user_data, ipp_t *ipp, ipp_attribute_t **attr, int element);
|
|
static void report_error(_ipp_file_t *f, _ipp_vars_t *v, void *user_data, const char *message, ...) _CUPS_FORMAT(4, 5);
|
|
|
|
|
|
/*
|
|
* '_ippFileParse()' - Parse an IPP data file.
|
|
*/
|
|
|
|
ipp_t * /* O - IPP attributes or @code NULL@ on failure */
|
|
_ippFileParse(
|
|
_ipp_vars_t *v, /* I - Variables */
|
|
const char *filename, /* I - Name of file to parse */
|
|
void *user_data) /* I - User data pointer */
|
|
{
|
|
_ipp_file_t f; /* IPP data file information */
|
|
ipp_t *attrs = NULL; /* Active IPP message */
|
|
ipp_attribute_t *attr = NULL; /* Current attribute */
|
|
char token[1024]; /* Token string */
|
|
ipp_t *ignored = NULL; /* Ignored attributes */
|
|
|
|
|
|
DEBUG_printf(("_ippFileParse(v=%p, filename=\"%s\", user_data=%p)", (void *)v, filename, user_data));
|
|
|
|
/*
|
|
* Initialize file info...
|
|
*/
|
|
|
|
memset(&f, 0, sizeof(f));
|
|
f.filename = filename;
|
|
f.linenum = 1;
|
|
|
|
if ((f.fp = cupsFileOpen(filename, "r")) == NULL)
|
|
{
|
|
DEBUG_printf(("1_ippFileParse: Unable to open \"%s\": %s", filename, strerror(errno)));
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Do the callback with a NULL token to setup any initial state...
|
|
*/
|
|
|
|
(*v->tokencb)(&f, v, user_data, NULL);
|
|
|
|
/*
|
|
* Read data file, using the callback function as needed...
|
|
*/
|
|
|
|
while (_ippFileReadToken(&f, token, sizeof(token)))
|
|
{
|
|
if (!_cups_strcasecmp(token, "DEFINE") || !_cups_strcasecmp(token, "DEFINE-DEFAULT"))
|
|
{
|
|
char name[128], /* Variable name */
|
|
value[1024], /* Variable value */
|
|
temp[1024]; /* Temporary string */
|
|
|
|
attr = NULL;
|
|
|
|
if (_ippFileReadToken(&f, name, sizeof(name)) && _ippFileReadToken(&f, temp, sizeof(temp)))
|
|
{
|
|
if (_cups_strcasecmp(token, "DEFINE-DEFAULT") || !_ippVarsGet(v, name))
|
|
{
|
|
_ippVarsExpand(v, value, temp, sizeof(value));
|
|
_ippVarsSet(v, name, value);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
report_error(&f, v, user_data, "Missing %s name and/or value on line %d of \"%s\".", token, f.linenum, f.filename);
|
|
break;
|
|
}
|
|
}
|
|
else if (f.attrs && !_cups_strcasecmp(token, "ATTR"))
|
|
{
|
|
/*
|
|
* Attribute definition...
|
|
*/
|
|
|
|
char syntax[128], /* Attribute syntax (value tag) */
|
|
name[128]; /* Attribute name */
|
|
ipp_tag_t value_tag; /* Value tag */
|
|
|
|
attr = NULL;
|
|
|
|
if (!_ippFileReadToken(&f, syntax, sizeof(syntax)))
|
|
{
|
|
report_error(&f, v, user_data, "Missing ATTR syntax on line %d of \"%s\".", f.linenum, f.filename);
|
|
break;
|
|
}
|
|
else if ((value_tag = ippTagValue(syntax)) < IPP_TAG_UNSUPPORTED_VALUE)
|
|
{
|
|
report_error(&f, v, user_data, "Bad ATTR syntax \"%s\" on line %d of \"%s\".", syntax, f.linenum, f.filename);
|
|
break;
|
|
}
|
|
|
|
if (!_ippFileReadToken(&f, name, sizeof(name)) || !name[0])
|
|
{
|
|
report_error(&f, v, user_data, "Missing ATTR name on line %d of \"%s\".", f.linenum, f.filename);
|
|
break;
|
|
}
|
|
|
|
if (!v->attrcb || (*v->attrcb)(&f, user_data, name))
|
|
{
|
|
/*
|
|
* Add this attribute...
|
|
*/
|
|
|
|
attrs = f.attrs;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Ignore this attribute...
|
|
*/
|
|
|
|
if (!ignored)
|
|
ignored = ippNew();
|
|
|
|
attrs = ignored;
|
|
}
|
|
|
|
if (value_tag < IPP_TAG_INTEGER)
|
|
{
|
|
/*
|
|
* Add out-of-band attribute - no value string needed...
|
|
*/
|
|
|
|
ippAddOutOfBand(attrs, f.group_tag, value_tag, name);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Add attribute with one or more values...
|
|
*/
|
|
|
|
attr = ippAddString(attrs, f.group_tag, value_tag, name, NULL, NULL);
|
|
|
|
if (!parse_value(&f, v, user_data, attrs, &attr, 0))
|
|
break;
|
|
}
|
|
|
|
}
|
|
else if (attr && !_cups_strcasecmp(token, ","))
|
|
{
|
|
/*
|
|
* Additional value...
|
|
*/
|
|
|
|
if (!parse_value(&f, v, user_data, attrs, &attr, ippGetCount(attr)))
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Something else...
|
|
*/
|
|
|
|
attr = NULL;
|
|
attrs = NULL;
|
|
|
|
if (!(*v->tokencb)(&f, v, user_data, token))
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Close the file and free ignored attributes, then return any attributes we
|
|
* kept...
|
|
*/
|
|
|
|
cupsFileClose(f.fp);
|
|
ippDelete(ignored);
|
|
|
|
return (f.attrs);
|
|
}
|
|
|
|
|
|
/*
|
|
* '_ippFileReadToken()' - Read a token from an IPP data file.
|
|
*/
|
|
|
|
int /* O - 1 on success, 0 on failure */
|
|
_ippFileReadToken(_ipp_file_t *f, /* I - File to read from */
|
|
char *token, /* I - Token string buffer */
|
|
size_t tokensize)/* I - Size of token string buffer */
|
|
{
|
|
int ch, /* Character from file */
|
|
quote = 0; /* Quoting character */
|
|
char *tokptr = token, /* Pointer into token buffer */
|
|
*tokend = token + tokensize - 1;/* End of token buffer */
|
|
|
|
|
|
/*
|
|
* Skip whitespace and comments...
|
|
*/
|
|
|
|
DEBUG_printf(("1_ippFileReadToken: linenum=%d, pos=%ld", f->linenum, (long)cupsFileTell(f->fp)));
|
|
|
|
while ((ch = cupsFileGetChar(f->fp)) != EOF)
|
|
{
|
|
if (_cups_isspace(ch))
|
|
{
|
|
/*
|
|
* Whitespace...
|
|
*/
|
|
|
|
if (ch == '\n')
|
|
{
|
|
f->linenum ++;
|
|
DEBUG_printf(("1_ippFileReadToken: LF in leading whitespace, linenum=%d, pos=%ld", f->linenum, (long)cupsFileTell(f->fp)));
|
|
}
|
|
}
|
|
else if (ch == '#')
|
|
{
|
|
/*
|
|
* Comment...
|
|
*/
|
|
|
|
DEBUG_puts("1_ippFileReadToken: Skipping comment in leading whitespace...");
|
|
|
|
while ((ch = cupsFileGetChar(f->fp)) != EOF)
|
|
{
|
|
if (ch == '\n')
|
|
break;
|
|
}
|
|
|
|
if (ch == '\n')
|
|
{
|
|
f->linenum ++;
|
|
DEBUG_printf(("1_ippFileReadToken: LF at end of comment, linenum=%d, pos=%ld", f->linenum, (long)cupsFileTell(f->fp)));
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (ch == EOF)
|
|
{
|
|
DEBUG_puts("1_ippFileReadToken: EOF");
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Read a token...
|
|
*/
|
|
|
|
while (ch != EOF)
|
|
{
|
|
if (ch == '\n')
|
|
{
|
|
f->linenum ++;
|
|
DEBUG_printf(("1_ippFileReadToken: LF in token, linenum=%d, pos=%ld", f->linenum, (long)cupsFileTell(f->fp)));
|
|
}
|
|
|
|
if (ch == quote)
|
|
{
|
|
/*
|
|
* End of quoted text...
|
|
*/
|
|
|
|
*tokptr = '\0';
|
|
DEBUG_printf(("1_ippFileReadToken: Returning \"%s\" at closing quote.", token));
|
|
return (1);
|
|
}
|
|
else if (!quote && _cups_isspace(ch))
|
|
{
|
|
/*
|
|
* End of unquoted text...
|
|
*/
|
|
|
|
*tokptr = '\0';
|
|
DEBUG_printf(("1_ippFileReadToken: Returning \"%s\" before whitespace.", token));
|
|
return (1);
|
|
}
|
|
else if (!quote && (ch == '\'' || ch == '\"'))
|
|
{
|
|
/*
|
|
* Start of quoted text or regular expression...
|
|
*/
|
|
|
|
if (ch == '<')
|
|
quote = '>';
|
|
else
|
|
quote = ch;
|
|
|
|
DEBUG_printf(("1_ippFileReadToken: Start of quoted string, quote=%c, pos=%ld", quote, (long)cupsFileTell(f->fp)));
|
|
}
|
|
else if (!quote && ch == '#')
|
|
{
|
|
/*
|
|
* Start of comment...
|
|
*/
|
|
|
|
cupsFileSeek(f->fp, cupsFileTell(f->fp) - 1);
|
|
*tokptr = '\0';
|
|
DEBUG_printf(("1_ippFileReadToken: Returning \"%s\" before comment.", token));
|
|
return (1);
|
|
}
|
|
else if (!quote && (ch == '{' || ch == '}' || ch == ','))
|
|
{
|
|
/*
|
|
* Delimiter...
|
|
*/
|
|
|
|
if (tokptr > token)
|
|
{
|
|
/*
|
|
* Return the preceding token first...
|
|
*/
|
|
|
|
cupsFileSeek(f->fp, cupsFileTell(f->fp) - 1);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Return this delimiter by itself...
|
|
*/
|
|
|
|
*tokptr++ = (char)ch;
|
|
}
|
|
|
|
*tokptr = '\0';
|
|
DEBUG_printf(("1_ippFileReadToken: Returning \"%s\".", token));
|
|
return (1);
|
|
}
|
|
else
|
|
{
|
|
if (ch == '\\')
|
|
{
|
|
/*
|
|
* Quoted character...
|
|
*/
|
|
|
|
DEBUG_printf(("1_ippFileReadToken: Quoted character at pos=%ld", (long)cupsFileTell(f->fp)));
|
|
|
|
if ((ch = cupsFileGetChar(f->fp)) == EOF)
|
|
{
|
|
*token = '\0';
|
|
DEBUG_puts("1_ippFileReadToken: EOF");
|
|
return (0);
|
|
}
|
|
else if (ch == '\n')
|
|
{
|
|
f->linenum ++;
|
|
DEBUG_printf(("1_ippFileReadToken: quoted LF, linenum=%d, pos=%ld", f->linenum, (long)cupsFileTell(f->fp)));
|
|
}
|
|
else if (ch == 'a')
|
|
ch = '\a';
|
|
else if (ch == 'b')
|
|
ch = '\b';
|
|
else if (ch == 'f')
|
|
ch = '\f';
|
|
else if (ch == 'n')
|
|
ch = '\n';
|
|
else if (ch == 'r')
|
|
ch = '\r';
|
|
else if (ch == 't')
|
|
ch = '\t';
|
|
else if (ch == 'v')
|
|
ch = '\v';
|
|
}
|
|
|
|
if (tokptr < tokend)
|
|
{
|
|
/*
|
|
* Add to current token...
|
|
*/
|
|
|
|
*tokptr++ = (char)ch;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Token too long...
|
|
*/
|
|
|
|
*tokptr = '\0';
|
|
DEBUG_printf(("1_ippFileReadToken: Too long: \"%s\".", token));
|
|
return (0);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Get the next character...
|
|
*/
|
|
|
|
ch = cupsFileGetChar(f->fp);
|
|
}
|
|
|
|
*tokptr = '\0';
|
|
DEBUG_printf(("1_ippFileReadToken: Returning \"%s\" at EOF.", token));
|
|
|
|
return (tokptr > token);
|
|
}
|
|
|
|
|
|
/*
|
|
* 'parse_collection()' - Parse an IPP collection value.
|
|
*/
|
|
|
|
static ipp_t * /* O - Collection value or @code NULL@ on error */
|
|
parse_collection(
|
|
_ipp_file_t *f, /* I - IPP data file */
|
|
_ipp_vars_t *v, /* I - IPP variables */
|
|
void *user_data) /* I - User data pointer */
|
|
{
|
|
ipp_t *col = ippNew(); /* Collection value */
|
|
ipp_attribute_t *attr = NULL; /* Current member attribute */
|
|
char token[1024]; /* Token string */
|
|
|
|
|
|
/*
|
|
* Parse the collection value...
|
|
*/
|
|
|
|
while (_ippFileReadToken(f, token, sizeof(token)))
|
|
{
|
|
if (!_cups_strcasecmp(token, "}"))
|
|
{
|
|
/*
|
|
* End of collection value...
|
|
*/
|
|
|
|
break;
|
|
}
|
|
else if (!_cups_strcasecmp(token, "MEMBER"))
|
|
{
|
|
/*
|
|
* Member attribute definition...
|
|
*/
|
|
|
|
char syntax[128], /* Attribute syntax (value tag) */
|
|
name[128]; /* Attribute name */
|
|
ipp_tag_t value_tag; /* Value tag */
|
|
|
|
attr = NULL;
|
|
|
|
if (!_ippFileReadToken(f, syntax, sizeof(syntax)))
|
|
{
|
|
report_error(f, v, user_data, "Missing MEMBER syntax on line %d of \"%s\".", f->linenum, f->filename);
|
|
ippDelete(col);
|
|
col = NULL;
|
|
break;
|
|
}
|
|
else if ((value_tag = ippTagValue(syntax)) < IPP_TAG_UNSUPPORTED_VALUE)
|
|
{
|
|
report_error(f, v, user_data, "Bad MEMBER syntax \"%s\" on line %d of \"%s\".", syntax, f->linenum, f->filename);
|
|
ippDelete(col);
|
|
col = NULL;
|
|
break;
|
|
}
|
|
|
|
if (!_ippFileReadToken(f, name, sizeof(name)) || !name[0])
|
|
{
|
|
report_error(f, v, user_data, "Missing MEMBER name on line %d of \"%s\".", f->linenum, f->filename);
|
|
ippDelete(col);
|
|
col = NULL;
|
|
break;
|
|
}
|
|
|
|
if (value_tag < IPP_TAG_INTEGER)
|
|
{
|
|
/*
|
|
* Add out-of-band attribute - no value string needed...
|
|
*/
|
|
|
|
ippAddOutOfBand(col, IPP_TAG_ZERO, value_tag, name);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Add attribute with one or more values...
|
|
*/
|
|
|
|
attr = ippAddString(col, IPP_TAG_ZERO, value_tag, name, NULL, NULL);
|
|
|
|
if (!parse_value(f, v, user_data, col, &attr, 0))
|
|
{
|
|
ippDelete(col);
|
|
col = NULL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
else if (attr && !_cups_strcasecmp(token, ","))
|
|
{
|
|
/*
|
|
* Additional value...
|
|
*/
|
|
|
|
if (!parse_value(f, v, user_data, col, &attr, ippGetCount(attr)))
|
|
{
|
|
ippDelete(col);
|
|
col = NULL;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Something else...
|
|
*/
|
|
|
|
report_error(f, v, user_data, "Unknown directive \"%s\" on line %d of \"%s\".", token, f->linenum, f->filename);
|
|
ippDelete(col);
|
|
col = NULL;
|
|
attr = NULL;
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
return (col);
|
|
}
|
|
|
|
|
|
/*
|
|
* 'parse_value()' - Parse an IPP value.
|
|
*/
|
|
|
|
static int /* O - 1 on success or 0 on error */
|
|
parse_value(_ipp_file_t *f, /* I - IPP data file */
|
|
_ipp_vars_t *v, /* I - IPP variables */
|
|
void *user_data,/* I - User data pointer */
|
|
ipp_t *ipp, /* I - IPP message */
|
|
ipp_attribute_t **attr, /* IO - IPP attribute */
|
|
int element) /* I - Element number */
|
|
{
|
|
char value[2049], /* Value string */
|
|
*valueptr, /* Pointer into value string */
|
|
temp[2049], /* Temporary string */
|
|
*tempptr; /* Pointer into temporary string */
|
|
size_t valuelen; /* Length of value */
|
|
|
|
|
|
if (!_ippFileReadToken(f, temp, sizeof(temp)))
|
|
{
|
|
report_error(f, v, user_data, "Missing value on line %d of \"%s\".", f->linenum, f->filename);
|
|
return (0);
|
|
}
|
|
|
|
_ippVarsExpand(v, value, temp, sizeof(value));
|
|
|
|
switch (ippGetValueTag(*attr))
|
|
{
|
|
case IPP_TAG_BOOLEAN :
|
|
return (ippSetBoolean(ipp, attr, element, !_cups_strcasecmp(value, "true")));
|
|
break;
|
|
|
|
case IPP_TAG_ENUM :
|
|
case IPP_TAG_INTEGER :
|
|
return (ippSetInteger(ipp, attr, element, (int)strtol(value, NULL, 0)));
|
|
break;
|
|
|
|
case IPP_TAG_DATE :
|
|
{
|
|
int year, /* Year */
|
|
month, /* Month */
|
|
day, /* Day of month */
|
|
hour, /* Hour */
|
|
minute, /* Minute */
|
|
second, /* Second */
|
|
utc_offset = 0; /* Timezone offset from UTC */
|
|
ipp_uchar_t date[11]; /* dateTime value */
|
|
|
|
if (*value == 'P')
|
|
{
|
|
/*
|
|
* Time period...
|
|
*/
|
|
|
|
time_t curtime; /* Current time in seconds */
|
|
int period = 0, /* Current period value */
|
|
saw_T = 0; /* Saw time separator */
|
|
|
|
curtime = time(NULL);
|
|
|
|
for (valueptr = value + 1; *valueptr; valueptr ++)
|
|
{
|
|
if (isdigit(*valueptr & 255))
|
|
{
|
|
period = (int)strtol(valueptr, &valueptr, 10);
|
|
|
|
if (!valueptr || period < 0)
|
|
{
|
|
report_error(f, v, user_data, "Bad dateTime value \"%s\" on line %d of \"%s\".", value, f->linenum, f->filename);
|
|
return (0);
|
|
}
|
|
}
|
|
|
|
if (*valueptr == 'Y')
|
|
{
|
|
curtime += 365 * 86400 * period;
|
|
period = 0;
|
|
}
|
|
else if (*valueptr == 'M')
|
|
{
|
|
if (saw_T)
|
|
curtime += 60 * period;
|
|
else
|
|
curtime += 30 * 86400 * period;
|
|
|
|
period = 0;
|
|
}
|
|
else if (*valueptr == 'D')
|
|
{
|
|
curtime += 86400 * period;
|
|
period = 0;
|
|
}
|
|
else if (*valueptr == 'H')
|
|
{
|
|
curtime += 3600 * period;
|
|
period = 0;
|
|
}
|
|
else if (*valueptr == 'S')
|
|
{
|
|
curtime += period;
|
|
period = 0;
|
|
}
|
|
else if (*valueptr == 'T')
|
|
{
|
|
saw_T = 1;
|
|
period = 0;
|
|
}
|
|
else
|
|
{
|
|
report_error(f, v, user_data, "Bad dateTime value \"%s\" on line %d of \"%s\".", value, f->linenum, f->filename);
|
|
return (0);
|
|
}
|
|
}
|
|
|
|
return (ippSetDate(ipp, attr, element, ippTimeToDate(curtime)));
|
|
}
|
|
else if (sscanf(value, "%d-%d-%dT%d:%d:%d%d", &year, &month, &day, &hour, &minute, &second, &utc_offset) < 6)
|
|
{
|
|
/*
|
|
* Date/time value did not parse...
|
|
*/
|
|
|
|
report_error(f, v, user_data, "Bad dateTime value \"%s\" on line %d of \"%s\".", value, f->linenum, f->filename);
|
|
return (0);
|
|
}
|
|
|
|
date[0] = (ipp_uchar_t)(year >> 8);
|
|
date[1] = (ipp_uchar_t)(year & 255);
|
|
date[2] = (ipp_uchar_t)month;
|
|
date[3] = (ipp_uchar_t)day;
|
|
date[4] = (ipp_uchar_t)hour;
|
|
date[5] = (ipp_uchar_t)minute;
|
|
date[6] = (ipp_uchar_t)second;
|
|
date[7] = 0;
|
|
if (utc_offset < 0)
|
|
{
|
|
utc_offset = -utc_offset;
|
|
date[8] = (ipp_uchar_t)'-';
|
|
}
|
|
else
|
|
{
|
|
date[8] = (ipp_uchar_t)'+';
|
|
}
|
|
|
|
date[9] = (ipp_uchar_t)(utc_offset / 100);
|
|
date[10] = (ipp_uchar_t)(utc_offset % 100);
|
|
|
|
return (ippSetDate(ipp, attr, element, date));
|
|
}
|
|
break;
|
|
|
|
case IPP_TAG_RESOLUTION :
|
|
{
|
|
int xres, /* X resolution */
|
|
yres; /* Y resolution */
|
|
char *ptr; /* Pointer into value */
|
|
|
|
xres = yres = (int)strtol(value, (char **)&ptr, 10);
|
|
if (ptr > value && xres > 0)
|
|
{
|
|
if (*ptr == 'x')
|
|
yres = (int)strtol(ptr + 1, (char **)&ptr, 10);
|
|
}
|
|
|
|
if (ptr <= value || xres <= 0 || yres <= 0 || !ptr || (_cups_strcasecmp(ptr, "dpi") && _cups_strcasecmp(ptr, "dpc") && _cups_strcasecmp(ptr, "dpcm") && _cups_strcasecmp(ptr, "other")))
|
|
{
|
|
report_error(f, v, user_data, "Bad resolution value \"%s\" on line %d of \"%s\".", value, f->linenum, f->filename);
|
|
return (0);
|
|
}
|
|
|
|
if (!_cups_strcasecmp(ptr, "dpi"))
|
|
return (ippSetResolution(ipp, attr, element, IPP_RES_PER_INCH, xres, yres));
|
|
else if (!_cups_strcasecmp(ptr, "dpc") || !_cups_strcasecmp(ptr, "dpcm"))
|
|
return (ippSetResolution(ipp, attr, element, IPP_RES_PER_CM, xres, yres));
|
|
else
|
|
return (ippSetResolution(ipp, attr, element, (ipp_res_t)0, xres, yres));
|
|
}
|
|
break;
|
|
|
|
case IPP_TAG_RANGE :
|
|
{
|
|
int lower, /* Lower value */
|
|
upper; /* Upper value */
|
|
|
|
if (sscanf(value, "%d-%d", &lower, &upper) != 2)
|
|
{
|
|
report_error(f, v, user_data, "Bad rangeOfInteger value \"%s\" on line %d of \"%s\".", value, f->linenum, f->filename);
|
|
return (0);
|
|
}
|
|
|
|
return (ippSetRange(ipp, attr, element, lower, upper));
|
|
}
|
|
break;
|
|
|
|
case IPP_TAG_STRING :
|
|
valuelen = strlen(value);
|
|
|
|
if (value[0] == '<' && value[strlen(value) - 1] == '>')
|
|
{
|
|
if (valuelen & 1)
|
|
{
|
|
report_error(f, v, user_data, "Bad octetString value on line %d of \"%s\".", f->linenum, f->filename);
|
|
return (0);
|
|
}
|
|
|
|
valueptr = value + 1;
|
|
tempptr = temp;
|
|
|
|
while (*valueptr && *valueptr != '>')
|
|
{
|
|
if (!isxdigit(valueptr[0] & 255) || !isxdigit(valueptr[1] & 255))
|
|
{
|
|
report_error(f, v, user_data, "Bad octetString value on line %d of \"%s\".", f->linenum, f->filename);
|
|
return (0);
|
|
}
|
|
|
|
if (valueptr[0] >= '0' && valueptr[0] <= '9')
|
|
*tempptr = (char)((valueptr[0] - '0') << 4);
|
|
else
|
|
*tempptr = (char)((tolower(valueptr[0]) - 'a' + 10) << 4);
|
|
|
|
if (valueptr[1] >= '0' && valueptr[1] <= '9')
|
|
*tempptr |= (valueptr[1] - '0');
|
|
else
|
|
*tempptr |= (tolower(valueptr[1]) - 'a' + 10);
|
|
|
|
tempptr ++;
|
|
}
|
|
|
|
return (ippSetOctetString(ipp, attr, element, temp, (int)(tempptr - temp)));
|
|
}
|
|
else
|
|
return (ippSetOctetString(ipp, attr, element, value, (int)valuelen));
|
|
break;
|
|
|
|
case IPP_TAG_TEXTLANG :
|
|
case IPP_TAG_NAMELANG :
|
|
case IPP_TAG_TEXT :
|
|
case IPP_TAG_NAME :
|
|
case IPP_TAG_KEYWORD :
|
|
case IPP_TAG_URI :
|
|
case IPP_TAG_URISCHEME :
|
|
case IPP_TAG_CHARSET :
|
|
case IPP_TAG_LANGUAGE :
|
|
case IPP_TAG_MIMETYPE :
|
|
return (ippSetString(ipp, attr, element, value));
|
|
break;
|
|
|
|
case IPP_TAG_BEGIN_COLLECTION :
|
|
{
|
|
int status; /* Add status */
|
|
ipp_t *col; /* Collection value */
|
|
|
|
if (strcmp(value, "{"))
|
|
{
|
|
report_error(f, v, user_data, "Bad collection value on line %d of \"%s\".", f->linenum, f->filename);
|
|
return (0);
|
|
}
|
|
|
|
if ((col = parse_collection(f, v, user_data)) == NULL)
|
|
return (0);
|
|
|
|
status = ippSetCollection(ipp, attr, element, col);
|
|
ippDelete(col);
|
|
|
|
return (status);
|
|
}
|
|
break;
|
|
|
|
default :
|
|
report_error(f, v, user_data, "Unsupported value on line %d of \"%s\".", f->linenum, f->filename);
|
|
return (0);
|
|
}
|
|
|
|
return (1);
|
|
}
|
|
|
|
|
|
/*
|
|
* 'report_error()' - Report an error.
|
|
*/
|
|
|
|
static void
|
|
report_error(
|
|
_ipp_file_t *f, /* I - IPP data file */
|
|
_ipp_vars_t *v, /* I - Error callback function, if any */
|
|
void *user_data, /* I - User data pointer */
|
|
const char *message, /* I - Printf-style message */
|
|
...) /* I - Additional arguments as needed */
|
|
{
|
|
char buffer[8192]; /* Formatted string */
|
|
va_list ap; /* Argument pointer */
|
|
|
|
|
|
va_start(ap, message);
|
|
vsnprintf(buffer, sizeof(buffer), message, ap);
|
|
va_end(ap);
|
|
|
|
if (v->errorcb)
|
|
(*v->errorcb)(f, user_data, buffer);
|
|
else
|
|
fprintf(stderr, "%s\n", buffer);
|
|
}
|