* Include necessary headers...
*/
-#define _IPP_PRIVATE_STRUCTURES 0 /* Disable private IPP stuff */
#include <cups/cups-private.h>
-#include <cups/file-private.h>
#include <regex.h>
#include <sys/stat.h>
-#ifdef WIN32
+#ifdef _WIN32
# include <windows.h>
# ifndef R_OK
# define R_OK 0
#else
# include <signal.h>
# include <termios.h>
-#endif /* WIN32 */
+#endif /* _WIN32 */
#ifndef O_BINARY
# define O_BINARY 0
#endif /* !O_BINARY */
* Local functions...
*/
-static void add_stringf(cups_array_t *a, const char *s, ...) __attribute__ ((__format__ (__printf__, 2, 3)));
+static void add_stringf(cups_array_t *a, const char *s, ...) _CUPS_FORMAT(2, 3);
static int compare_uris(const char *a, const char *b);
+static void copy_hex_string(char *buffer, unsigned char *data, int datalen, size_t bufsize);
static int do_test(_ipp_file_t *f, _ipp_vars_t *vars, _cups_testdata_t *data);
static int do_tests(const char *testfile, _ipp_vars_t *vars, _cups_testdata_t *data);
static int error_cb(_ipp_file_t *f, _cups_testdata_t *data, const char *error);
static void pause_message(const char *message);
static void print_attr(cups_file_t *outfile, int output, ipp_attribute_t *attr, ipp_tag_t *group);
static void print_csv(_cups_testdata_t *data, ipp_t *ipp, ipp_attribute_t *attr, int num_displayed, char **displayed, size_t *widths);
-static void print_fatal_error(_cups_testdata_t *data, const char *s, ...) __attribute__ ((__format__ (__printf__, 2, 3)));
+static void print_fatal_error(_cups_testdata_t *data, const char *s, ...) _CUPS_FORMAT(2, 3);
static void print_ippserver_attr(_cups_testdata_t *data, ipp_attribute_t *attr, int indent);
static void print_ippserver_string(_cups_testdata_t *data, const char *s, size_t len);
static void print_line(_cups_testdata_t *data, ipp_t *ipp, ipp_attribute_t *attr, int num_displayed, char **displayed, size_t *widths);
static void print_xml_header(_cups_testdata_t *data);
static void print_xml_string(cups_file_t *outfile, const char *element, const char *s);
static void print_xml_trailer(_cups_testdata_t *data, int success, const char *message);
-#ifndef WIN32
+#ifndef _WIN32
static void sigterm_handler(int sig);
-#endif /* WIN32 */
+#endif /* _WIN32 */
static int timeout_cb(http_t *http, void *user_data);
static int token_cb(_ipp_file_t *f, _ipp_vars_t *vars, _cups_testdata_t *data, const char *token);
-static void usage(void) __attribute__((noreturn));
+static void usage(void) _CUPS_NORETURN;
static const char *with_flags_string(int flags);
static int with_value(_cups_testdata_t *data, cups_array_t *errors, char *value, int flags, ipp_attribute_t *attr, char *matchbuf, size_t matchlen);
static int with_value_from(cups_array_t *errors, ipp_attribute_t *fromattr, ipp_attribute_t *attr, char *matchbuf, size_t matchlen);
/* Global data */
-#ifndef WIN32
+#ifndef _WIN32
/*
* Catch SIGINT and SIGTERM...
*/
signal(SIGINT, sigterm_handler);
signal(SIGTERM, sigterm_handler);
-#endif /* !WIN32 */
+#endif /* !_WIN32 */
/*
* Initialize the locale and variables...
init_data(&data);
- _ippVarsInit(&vars);
+ _ippVarsInit(&vars, NULL, (_ipp_ferror_cb_t)error_cb, (_ipp_ftoken_cb_t)token_cb);
/*
* We need at least:
snprintf(filename, sizeof(filename), "%s.gz", argv[i]);
if (access(filename, 0) && filename[0] != '/'
-#ifdef WIN32
+#ifdef _WIN32
&& (!isalpha(filename[0] & 255) || filename[1] != ':')
-#endif /* WIN32 */
+#endif /* _WIN32 */
)
{
snprintf(filename, sizeof(filename), "%s/ipptool/%s", cg->cups_datadir, argv[i]);
}
if (access(argv[i], 0) && argv[i][0] != '/'
-#ifdef WIN32
+#ifdef _WIN32
&& (!isalpha(argv[i][0] & 255) || argv[i][1] != ':')
-#endif /* WIN32 */
+#endif /* _WIN32 */
)
{
snprintf(testname, sizeof(testname), "%s/ipptool/%s", cg->cups_datadir, argv[i]);
}
+/*
+ * 'copy_hex_string()' - Copy an octetString to a C string and encode as hex if
+ * needed.
+ */
+
+static void
+copy_hex_string(char *buffer, /* I - String buffer */
+ unsigned char *data, /* I - octetString data */
+ int datalen, /* I - octetString length */
+ size_t bufsize) /* I - Size of string buffer */
+{
+ char *bufptr, /* Pointer into string buffer */
+ *bufend = buffer + bufsize - 2;
+ /* End of string buffer */
+ unsigned char *dataptr, /* Pointer into octetString data */
+ *dataend = data + datalen;
+ /* End of octetString data */
+ static const char *hexdigits = "0123456789ABCDEF";
+ /* Hex digits */
+
+
+ /*
+ * First see if there are any non-ASCII bytes in the octetString...
+ */
+
+ for (dataptr = data; dataptr < dataend; dataptr ++)
+ if (*dataptr < 0x20 || *dataptr >= 0x7f)
+ break;
+
+ if (*dataptr)
+ {
+ /*
+ * Yes, encode as hex...
+ */
+
+ *buffer = '<';
+
+ for (bufptr = buffer + 1, dataptr = data; bufptr < bufend && dataptr < dataend; dataptr ++)
+ {
+ *bufptr++ = hexdigits[*dataptr >> 4];
+ *bufptr++ = hexdigits[*dataptr & 15];
+ }
+
+ if (bufptr < bufend)
+ *bufptr++ = '>';
+
+ *bufptr = '\0';
+ }
+ else
+ {
+ /*
+ * No, copy as a string...
+ */
+
+ if ((size_t)datalen > bufsize)
+ datalen = (int)bufsize - 1;
+
+ memcpy(buffer, data, (size_t)datalen);
+ buffer[datalen] = '\0';
+ }
+}
+
+
/*
* 'do_test()' - Do a single test from the test file.
*/
}
if (!Cancel && status == HTTP_STATUS_ERROR && httpError(data->http) != EINVAL &&
-#ifdef WIN32
+#ifdef _WIN32
httpError(data->http) != WSAETIMEDOUT)
#else
httpError(data->http) != ETIMEDOUT)
-#endif /* WIN32 */
+#endif /* _WIN32 */
{
if (httpReconnect2(data->http, 30000, NULL))
data->prev_pass = 0;
}
if (!Cancel && status == HTTP_STATUS_ERROR && httpError(data->http) != EINVAL &&
-#ifdef WIN32
+#ifdef _WIN32
httpError(data->http) != WSAETIMEDOUT)
#else
httpError(data->http) != ETIMEDOUT)
-#endif /* WIN32 */
+#endif /* _WIN32 */
{
if (httpReconnect2(data->http, 30000, NULL))
data->prev_pass = 0;
if (ippGetName(attrptr))
{
- if (cupsArrayFind(a, (void *)ippGetName(attrptr)))
+ if (cupsArrayFind(a, (void *)ippGetName(attrptr)) && data->output < _CUPS_OUTPUT_LIST)
add_stringf(data->errors, "Duplicate \"%s\" attribute in %s group",
ippGetName(attrptr), ippTagString(group));
for (i = data->num_expects, expect = data->expects; i > 0; i --, expect ++)
{
+ ipp_attribute_t *group_found; /* Found parent attribute for group tests */
+
if (expect->if_defined && !_ippVarsGet(vars, expect->if_defined))
continue;
_ippVarsGet(vars, expect->if_not_defined))
continue;
- found = ippFindAttribute(response, expect->name, IPP_TAG_ZERO);
+ if ((found = ippFindAttribute(response, expect->name, IPP_TAG_ZERO)) != NULL && expect->in_group && expect->in_group != ippGetGroupTag(found))
+ {
+ while ((found = ippFindNextAttribute(response, expect->name, IPP_TAG_ZERO)) != NULL)
+ if (expect->in_group == ippGetGroupTag(found))
+ break;
+ }
do
{
+ group_found = found;
+
+ if (expect->in_group && strchr(expect->name, '/'))
+ {
+ char group_name[256],/* Parent attribute name */
+ *group_ptr; /* Pointer into parent attribute name */
+
+ strlcpy(group_name, expect->name, sizeof(group_name));
+ if ((group_ptr = strchr(group_name, '/')) != NULL)
+ *group_ptr = '\0';
+
+ group_found = ippFindAttribute(response, group_name, IPP_TAG_ZERO);
+ }
+
if ((found && expect->not_expect) ||
(!found && !(expect->not_expect || expect->optional)) ||
(found && !expect_matches(expect, ippGetValueTag(found))) ||
- (found && expect->in_group &&
- ippGetGroupTag(found) != expect->in_group))
+ (group_found && expect->in_group && ippGetGroupTag(group_found) != expect->in_group))
{
if (expect->define_no_match)
_ippVarsSet(vars, expect->define_no_match, "1");
expect->name, expect->of_type,
ippTagString(ippGetValueTag(found)));
- if (expect->in_group && ippGetGroupTag(found) != expect->in_group)
+ if (expect->in_group && ippGetGroupTag(group_found) != expect->in_group)
add_stringf(data->errors, "EXPECTED: %s IN-GROUP %s (got %s).",
expect->name, ippTagString(expect->in_group),
- ippTagString(ippGetGroupTag(found)));
+ ippTagString(ippGetGroupTag(group_found)));
}
}
* Run tests...
*/
- _ippFileParse(vars, testfile, (_ipp_ftoken_cb_t)token_cb, (_ipp_ferror_cb_t)error_cb, (void *)data);
+ _ippFileParse(vars, testfile, (void *)data);
/*
* Close connection and return...
*dstptr = '\0';
}
else if (!access(src, R_OK) || *src == '/'
-#ifdef WIN32
+#ifdef _WIN32
|| (isalpha(*src & 255) && src[1] == ':')
-#endif /* WIN32 */
+#endif /* _WIN32 */
)
{
/*
static void
pause_message(const char *message) /* I - Message */
{
-#ifdef WIN32
+#ifdef _WIN32
HANDLE tty; /* Console handle */
DWORD mode; /* Console mode */
char key; /* Key press */
close(tty);
return;
}
-#endif /* WIN32 */
+#endif /* _WIN32 */
/*
* Display the prompt...
cupsFilePrintf(cupsFileStdout(), "%s\n---- PRESS ANY KEY ----", message);
-#ifdef WIN32
+#ifdef _WIN32
/*
* Read a key...
*/
tcsetattr(tty, TCSAFLUSH, &original);
close(tty);
-#endif /* WIN32 */
+#endif /* _WIN32 */
/*
* Erase the "press any key" prompt...
break;
default :
- cupsFilePuts(data->outfile, " \"\"");
+ /* Out-of-band value */
break;
}
}
-#ifndef WIN32
+#ifndef _WIN32
/*
* 'sigterm_handler()' - Handle SIGINT and SIGTERM.
*/
signal(SIGINT, SIG_DFL);
signal(SIGTERM, SIG_DFL);
}
-#endif /* !WIN32 */
+#endif /* !_WIN32 */
/*
!_cups_strcasecmp(token, "WITH-VALUE"))
{
off_t lastpos; /* Last file position */
+ int lastline; /* Last line number */
if (data->last_expect)
{
for (;;)
{
- lastpos = cupsFileTell(f->fp);
- ptr += strlen(ptr);
+ lastpos = cupsFileTell(f->fp);
+ lastline = f->linenum;
+ ptr += strlen(ptr);
if (!_ippFileReadToken(f, ptr, (sizeof(temp) - (size_t)(ptr - temp))))
break;
*/
cupsFileSeek(f->fp, lastpos);
+ f->linenum = lastline;
*ptr = '\0';
break;
}
}
break;
+ case IPP_TAG_STRING :
+ {
+ unsigned char withdata[1023], /* WITH-VALUE data */
+ *adata; /* Pointer to octetString data */
+ int withlen, /* Length of WITH-VALUE data */
+ adatalen; /* Length of octetString */
+
+ if (*value == '<')
+ {
+ /*
+ * Grab hex-encoded value...
+ */
+
+ if ((withlen = (int)strlen(value)) & 1 || withlen > (int)(2 * (sizeof(withdata) + 1)))
+ {
+ print_fatal_error(data, "Bad WITH-VALUE hex value.");
+ return (0);
+ }
+
+ withlen = withlen / 2 - 1;
+
+ for (valptr = value + 1, adata = withdata; *valptr; valptr += 2)
+ {
+ int ch; /* Current character/byte */
+
+ if (isdigit(valptr[0]))
+ ch = (valptr[0] - '0') << 4;
+ else if (isalpha(valptr[0]))
+ ch = (tolower(valptr[0]) - 'a' + 10) << 4;
+ else
+ break;
+
+ if (isdigit(valptr[1]))
+ ch |= valptr[1] - '0';
+ else if (isalpha(valptr[1]))
+ ch |= tolower(valptr[1]) - 'a' + 10;
+ else
+ break;
+
+ *adata++ = (unsigned char)ch;
+ }
+
+ if (*valptr)
+ {
+ print_fatal_error(data, "Bad WITH-VALUE hex value.");
+ return (0);
+ }
+ }
+ else
+ {
+ /*
+ * Copy literal string value...
+ */
+
+ withlen = (int)strlen(value);
+
+ memcpy(withdata, value, (size_t)withlen);
+ }
+
+ for (i = 0; i < count; i ++)
+ {
+ adata = ippGetOctetString(attr, i, &adatalen);
+
+ if (withlen == adatalen && !memcmp(withdata, adata, (size_t)withlen))
+ {
+ if (!matchbuf[0])
+ copy_hex_string(matchbuf, adata, adatalen, matchlen);
+
+ if (!(flags & _CUPS_WITH_ALL))
+ {
+ match = 1;
+ break;
+ }
+ }
+ else if (flags & _CUPS_WITH_ALL)
+ {
+ match = 0;
+ break;
+ }
+ }
+
+ if (!match && errors)
+ {
+ for (i = 0; i < count; i ++)
+ {
+ adata = ippGetOctetString(attr, i, &adatalen);
+ copy_hex_string(temp, adata, adatalen, sizeof(temp));
+ add_stringf(data->errors, "GOT: %s=\"%s\"", name, temp);
+ }
+ }
+ }
+ break;
+
default :
break;
}