#include <stdio.h>
#include <stdlib.h>
#include <cups/file.h>
#include <cups/string.h>
#include <errno.h>
#include "ipp-private.h"
#ifdef WIN32
# include <io.h>
#else
# include <unistd.h>
# include <fcntl.h>
#endif
int rpos;
ipp_uchar_t wbuffer[8192];
int wused;
ipp_uchar_t collection[] =
{
0x01, 0x01,
0x00, 0x02,
0x00, 0x00, 0x00, 0x01,
IPP_TAG_OPERATION,
IPP_TAG_CHARSET,
0x00, 0x12,
'a','t','t','r','i','b','u','t','e','s','-',
'c','h','a','r','s','e','t',
0x00, 0x05,
'u','t','f','-','8',
IPP_TAG_LANGUAGE,
0x00, 0x1b,
'a','t','t','r','i','b','u','t','e','s','-',
'n','a','t','u','r','a','l','-','l','a','n',
'g','u','a','g','e',
0x00, 0x02,
'e','n',
IPP_TAG_URI,
0x00, 0x0b,
'p','r','i','n','t','e','r','-','u','r','i',
0x00, 0x1c,
'i','p','p',':','/','/','l','o','c','a','l',
'h','o','s','t','/','p','r','i','n','t','e',
'r','s','/','f','o','o',
IPP_TAG_JOB,
IPP_TAG_BEGIN_COLLECTION,
0x00, 0x09,
'm', 'e', 'd', 'i', 'a', '-', 'c', 'o', 'l',
0x00, 0x00,
IPP_TAG_MEMBERNAME,
0x00, 0x00,
0x00, 0x0a,
'm', 'e', 'd', 'i', 'a', '-', 's', 'i', 'z', 'e',
IPP_TAG_BEGIN_COLLECTION,
0x00, 0x00,
0x00, 0x00,
IPP_TAG_MEMBERNAME,
0x00, 0x00,
0x00, 0x0b,
'x', '-', 'd', 'i', 'm', 'e', 'n', 's', 'i', 'o', 'n',
IPP_TAG_INTEGER,
0x00, 0x00,
0x00, 0x04,
0x00, 0x00, 0x54, 0x56,
IPP_TAG_MEMBERNAME,
0x00, 0x00,
0x00, 0x0b,
'y', '-', 'd', 'i', 'm', 'e', 'n', 's', 'i', 'o', 'n',
IPP_TAG_INTEGER,
0x00, 0x00,
0x00, 0x04,
0x00, 0x00, 0x6d, 0x24,
IPP_TAG_END_COLLECTION,
0x00, 0x00,
0x00, 0x00,
IPP_TAG_MEMBERNAME,
0x00, 0x00,
0x00, 0x0b,
'm', 'e', 'd', 'i', 'a', '-', 'c', 'o', 'l', 'o', 'r',
IPP_TAG_KEYWORD,
0x00, 0x00,
0x00, 0x04,
'b', 'l', 'u', 'e',
IPP_TAG_MEMBERNAME,
0x00, 0x00,
0x00, 0x0a,
'm', 'e', 'd', 'i', 'a', '-', 't', 'y', 'p', 'e',
IPP_TAG_KEYWORD,
0x00, 0x00,
0x00, 0x05,
'p', 'l', 'a', 'i', 'n',
IPP_TAG_END_COLLECTION,
0x00, 0x00,
0x00, 0x00,
IPP_TAG_BEGIN_COLLECTION,
0x00, 0x00,
0x00, 0x00,
IPP_TAG_MEMBERNAME,
0x00, 0x00,
0x00, 0x0a,
'm', 'e', 'd', 'i', 'a', '-', 's', 'i', 'z', 'e',
IPP_TAG_BEGIN_COLLECTION,
0x00, 0x00,
0x00, 0x00,
IPP_TAG_MEMBERNAME,
0x00, 0x00,
0x00, 0x0b,
'x', '-', 'd', 'i', 'm', 'e', 'n', 's', 'i', 'o', 'n',
IPP_TAG_INTEGER,
0x00, 0x00,
0x00, 0x04,
0x00, 0x00, 0x52, 0x08,
IPP_TAG_MEMBERNAME,
0x00, 0x00,
0x00, 0x0b,
'y', '-', 'd', 'i', 'm', 'e', 'n', 's', 'i', 'o', 'n',
IPP_TAG_INTEGER,
0x00, 0x00,
0x00, 0x04,
0x00, 0x00, 0x74, 0x04,
IPP_TAG_END_COLLECTION,
0x00, 0x00,
0x00, 0x00,
IPP_TAG_MEMBERNAME,
0x00, 0x00,
0x00, 0x0b,
'm', 'e', 'd', 'i', 'a', '-', 'c', 'o', 'l', 'o', 'r',
IPP_TAG_KEYWORD,
0x00, 0x00,
0x00, 0x05,
'p', 'l', 'a', 'i', 'd',
IPP_TAG_MEMBERNAME,
0x00, 0x00,
0x00, 0x0a,
'm', 'e', 'd', 'i', 'a', '-', 't', 'y', 'p', 'e',
IPP_TAG_KEYWORD,
0x00, 0x00,
0x00, 0x06,
'g', 'l', 'o', 's', 's', 'y',
IPP_TAG_END_COLLECTION,
0x00, 0x00,
0x00, 0x00,
IPP_TAG_END
};
void hex_dump(const char *title, ipp_uchar_t *buffer, int bytes);
void print_attributes(ipp_t *ipp, int indent);
ssize_t read_cb(void *data, ipp_uchar_t *buffer, size_t bytes);
ssize_t write_cb(void *data, ipp_uchar_t *buffer, size_t bytes);
int
main(int argc,
char *argv[])
{
ipp_t *cols[2],
*size;
ipp_t *request;
ipp_attribute_t *media_col,
*media_size,
*attr;
ipp_state_t state;
int length;
cups_file_t *fp;
int i;
int status;
status = 0;
if (argc == 1)
{
printf("Create Sample Request: ");
request = ippNew();
request->request.op.version[0] = 0x01;
request->request.op.version[1] = 0x01;
request->request.op.operation_id = IPP_PRINT_JOB;
request->request.op.request_id = 1;
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
"attributes-charset", NULL, "utf-8");
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
"attributes-natural-language", NULL, "en");
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
"printer-uri", NULL, "ipp://localhost/printers/foo");
cols[0] = ippNew();
size = ippNew();
ippAddInteger(size, IPP_TAG_ZERO, IPP_TAG_INTEGER, "x-dimension", 21590);
ippAddInteger(size, IPP_TAG_ZERO, IPP_TAG_INTEGER, "y-dimension", 27940);
ippAddCollection(cols[0], IPP_TAG_JOB, "media-size", size);
ippDelete(size);
ippAddString(cols[0], IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-color", NULL,
"blue");
ippAddString(cols[0], IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-type", NULL,
"plain");
cols[1] = ippNew();
size = ippNew();
ippAddInteger(size, IPP_TAG_ZERO, IPP_TAG_INTEGER, "x-dimension", 21000);
ippAddInteger(size, IPP_TAG_ZERO, IPP_TAG_INTEGER, "y-dimension", 29700);
ippAddCollection(cols[1], IPP_TAG_JOB, "media-size", size);
ippDelete(size);
ippAddString(cols[1], IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-color", NULL,
"plaid");
ippAddString(cols[1], IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-type", NULL,
"glossy");
ippAddCollections(request, IPP_TAG_JOB, "media-col", 2,
(const ipp_t **)cols);
ippDelete(cols[0]);
ippDelete(cols[1]);
length = ippLength(request);
if (length != sizeof(collection))
{
printf("FAIL - wrong ippLength(), %d instead of %d bytes!\n",
length, (int)sizeof(collection));
status = 1;
}
else
puts("PASS");
printf("Write Sample to Memory: ");
wused = 0;
while ((state = ippWriteIO(wbuffer, write_cb, 1, NULL,
request)) != IPP_DATA)
if (state == IPP_ERROR)
break;
if (state != IPP_DATA)
{
printf("FAIL - %d bytes written.\n", wused);
status = 1;
}
else if (wused != sizeof(collection))
{
printf("FAIL - wrote %d bytes, expected %d bytes!\n", wused,
(int)sizeof(collection));
hex_dump("Bytes Written", wbuffer, wused);
hex_dump("Baseline", collection, sizeof(collection));
status = 1;
}
else if (memcmp(wbuffer, collection, wused))
{
for (i = 0; i < wused; i ++)
if (wbuffer[i] != collection[i])
break;
printf("FAIL - output does not match baseline at 0x%04x!\n", i);
hex_dump("Bytes Written", wbuffer, wused);
hex_dump("Baseline", collection, sizeof(collection));
status = 1;
}
else
puts("PASS");
ippDelete(request);
printf("Read Sample from Memory: ");
request = ippNew();
rpos = 0;
while ((state = ippReadIO(wbuffer, read_cb, 1, NULL, request)) != IPP_DATA)
if (state == IPP_ERROR)
break;
length = ippLength(request);
if (state != IPP_DATA)
{
printf("FAIL - %d bytes read.\n", rpos);
status = 1;
}
else if (rpos != wused)
{
printf("FAIL - read %d bytes, expected %d bytes!\n", rpos, wused);
print_attributes(request, 8);
status = 1;
}
else if (length != sizeof(collection))
{
printf("FAIL - wrong ippLength(), %d instead of %d bytes!\n",
length, (int)sizeof(collection));
print_attributes(request, 8);
status = 1;
}
else
puts("PASS");
fputs("ippFindAttribute(media-col): ", stdout);
if ((media_col = ippFindAttribute(request, "media-col",
IPP_TAG_BEGIN_COLLECTION)) == NULL)
{
if ((media_col = ippFindAttribute(request, "media-col",
IPP_TAG_ZERO)) == NULL)
puts("FAIL (not found)");
else
printf("FAIL (wrong type - %s)\n", ippTagString(media_col->value_tag));
status = 1;
}
else if (media_col->num_values != 2)
{
printf("FAIL (wrong count - %d)\n", media_col->num_values);
status = 1;
}
else
puts("PASS");
if (media_col)
{
fputs("ippFindAttribute(media-size 1): ", stdout);
if ((media_size = ippFindAttribute(media_col->values[0].collection,
"media-size",
IPP_TAG_BEGIN_COLLECTION)) == NULL)
{
if ((media_size = ippFindAttribute(media_col->values[0].collection,
"media-col",
IPP_TAG_ZERO)) == NULL)
puts("FAIL (not found)");
else
printf("FAIL (wrong type - %s)\n",
ippTagString(media_size->value_tag));
status = 1;
}
else
{
if ((attr = ippFindAttribute(media_size->values[0].collection,
"x-dimension", IPP_TAG_INTEGER)) == NULL)
{
if ((attr = ippFindAttribute(media_size->values[0].collection,
"x-dimension", IPP_TAG_ZERO)) == NULL)
puts("FAIL (missing x-dimension)");
else
printf("FAIL (wrong type for x-dimension - %s)\n",
ippTagString(attr->value_tag));
status = 1;
}
else if (attr->values[0].integer != 21590)
{
printf("FAIL (wrong value for x-dimension - %d)\n",
attr->values[0].integer);
status = 1;
}
else if ((attr = ippFindAttribute(media_size->values[0].collection,
"y-dimension",
IPP_TAG_INTEGER)) == NULL)
{
if ((attr = ippFindAttribute(media_size->values[0].collection,
"y-dimension", IPP_TAG_ZERO)) == NULL)
puts("FAIL (missing y-dimension)");
else
printf("FAIL (wrong type for y-dimension - %s)\n",
ippTagString(attr->value_tag));
status = 1;
}
else if (attr->values[0].integer != 27940)
{
printf("FAIL (wrong value for y-dimension - %d)\n",
attr->values[0].integer);
status = 1;
}
else
puts("PASS");
}
fputs("ippFindAttribute(media-size 2): ", stdout);
if ((media_size = ippFindAttribute(media_col->values[1].collection,
"media-size",
IPP_TAG_BEGIN_COLLECTION)) == NULL)
{
if ((media_size = ippFindAttribute(media_col->values[1].collection,
"media-col",
IPP_TAG_ZERO)) == NULL)
puts("FAIL (not found)");
else
printf("FAIL (wrong type - %s)\n",
ippTagString(media_size->value_tag));
status = 1;
}
else
{
if ((attr = ippFindAttribute(media_size->values[0].collection,
"x-dimension",
IPP_TAG_INTEGER)) == NULL)
{
if ((attr = ippFindAttribute(media_size->values[0].collection,
"x-dimension", IPP_TAG_ZERO)) == NULL)
puts("FAIL (missing x-dimension)");
else
printf("FAIL (wrong type for x-dimension - %s)\n",
ippTagString(attr->value_tag));
status = 1;
}
else if (attr->values[0].integer != 21000)
{
printf("FAIL (wrong value for x-dimension - %d)\n",
attr->values[0].integer);
status = 1;
}
else if ((attr = ippFindAttribute(media_size->values[0].collection,
"y-dimension",
IPP_TAG_INTEGER)) == NULL)
{
if ((attr = ippFindAttribute(media_size->values[0].collection,
"y-dimension", IPP_TAG_ZERO)) == NULL)
puts("FAIL (missing y-dimension)");
else
printf("FAIL (wrong type for y-dimension - %s)\n",
ippTagString(attr->value_tag));
status = 1;
}
else if (attr->values[0].integer != 29700)
{
printf("FAIL (wrong value for y-dimension - %d)\n",
attr->values[0].integer);
status = 1;
}
else
puts("PASS");
}
}
ippDelete(request);
fputs("_ippFindOption(printer-type): ", stdout);
if (_ippFindOption("printer-type"))
puts("PASS");
else
{
puts("FAIL");
status = 1;
}
putchar('\n');
if (status)
puts("Core IPP tests failed.");
else
puts("Core IPP tests passed.");
}
else
{
for (i = 1; i < argc; i ++)
{
if ((fp = cupsFileOpen(argv[i], "r")) == NULL)
{
printf("Unable to open \"%s\" - %s\n", argv[i], strerror(errno));
status = 1;
continue;
}
request = ippNew();
while ((state = ippReadIO(fp, (ipp_iocb_t)cupsFileRead, 1, NULL,
request)) == IPP_ATTRIBUTE);
if (state != IPP_DATA)
{
printf("Error reading IPP message from \"%s\"!\n", argv[i]);
status = 1;
}
else
{
printf("\n%s:\n", argv[i]);
print_attributes(request, 4);
}
ippDelete(request);
cupsFileClose(fp);
}
}
return (status);
}
void
hex_dump(const char *title,
ipp_uchar_t *buffer,
int bytes)
{
int i, j;
int ch;
printf(" %s:\n", title);
for (i = 0; i < bytes; i += 16)
{
printf(" %04x ", i);
for (j = 0; j < 16; j ++)
if ((i + j) < bytes)
printf(" %02x", buffer[i + j]);
else
printf(" ");
putchar(' ');
putchar(' ');
for (j = 0; j < 16 && (i + j) < bytes; j ++)
{
ch = buffer[i + j] & 127;
if (ch < ' ' || ch == 127)
putchar('.');
else
putchar(ch);
}
putchar('\n');
}
}
void
print_attributes(ipp_t *ipp,
int indent)
{
int i;
ipp_tag_t group;
ipp_attribute_t *attr;
ipp_value_t *val;
static const char * const tags[] =
{
"reserved-00",
"operation-attributes-tag",
"job-attributes-tag",
"end-of-attributes-tag",
"printer-attributes-tag",
"unsupported-attributes-tag",
"subscription-attributes-tag",
"event-attributes-tag",
"reserved-08",
"reserved-09",
"reserved-0A",
"reserved-0B",
"reserved-0C",
"reserved-0D",
"reserved-0E",
"reserved-0F",
"unsupported",
"default",
"unknown",
"no-value",
"reserved-14",
"not-settable",
"delete-attr",
"admin-define",
"reserved-18",
"reserved-19",
"reserved-1A",
"reserved-1B",
"reserved-1C",
"reserved-1D",
"reserved-1E",
"reserved-1F",
"reserved-20",
"integer",
"boolean",
"enum",
"reserved-24",
"reserved-25",
"reserved-26",
"reserved-27",
"reserved-28",
"reserved-29",
"reserved-2a",
"reserved-2b",
"reserved-2c",
"reserved-2d",
"reserved-2e",
"reserved-2f",
"octetString",
"dateTime",
"resolution",
"rangeOfInteger",
"begCollection",
"textWithLanguage",
"nameWithLanguage",
"endCollection",
"reserved-38",
"reserved-39",
"reserved-3a",
"reserved-3b",
"reserved-3c",
"reserved-3d",
"reserved-3e",
"reserved-3f",
"reserved-40",
"textWithoutLanguage",
"nameWithoutLanguage",
"reserved-43",
"keyword",
"uri",
"uriScheme",
"charset",
"naturalLanguage",
"mimeMediaType",
"memberName"
};
for (group = IPP_TAG_ZERO, attr = ipp->attrs; attr; attr = attr->next)
{
if (!attr->name && indent == 4)
{
group = IPP_TAG_ZERO;
putchar('\n');
continue;
}
if (group != attr->group_tag)
{
group = attr->group_tag;
printf("\n%*s%s:\n\n", indent - 4, "", tags[group]);
}
printf("%*s%s (", indent, "", attr->name ? attr->name : "(null)");
if (attr->num_values > 1)
printf("1setOf ");
printf("%s):", tags[attr->value_tag]);
switch (attr->value_tag)
{
case IPP_TAG_ENUM :
case IPP_TAG_INTEGER :
for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
printf(" %d", val->integer);
putchar('\n');
break;
case IPP_TAG_BOOLEAN :
for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
printf(" %s", val->boolean ? "true" : "false");
putchar('\n');
break;
case IPP_TAG_RANGE :
for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
printf(" %d-%d", val->range.lower, val->range.upper);
putchar('\n');
break;
case IPP_TAG_DATE :
{
time_t vtime;
struct tm *vdate;
char vstring[256];
for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
{
vtime = ippDateToTime(val->date);
vdate = localtime(&vtime);
strftime(vstring, sizeof(vstring), "%c", vdate);
printf(" (%s)", vstring);
}
}
putchar('\n');
break;
case IPP_TAG_RESOLUTION :
for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
printf(" %dx%d%s", val->resolution.xres, val->resolution.yres,
val->resolution.units == IPP_RES_PER_INCH ? "dpi" : "dpc");
putchar('\n');
break;
case IPP_TAG_STRING :
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 :
for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
printf(" \"%s\"", val->string.text);
putchar('\n');
break;
case IPP_TAG_BEGIN_COLLECTION :
putchar('\n');
for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
{
if (i)
putchar('\n');
print_attributes(val->collection, indent + 4);
}
break;
default :
printf("UNKNOWN (%d values)\n", attr->num_values);
break;
}
}
}
ssize_t
read_cb(void *data,
ipp_uchar_t *buffer,
size_t bytes)
{
int count;
for (count = bytes; count > 0 && rpos < wused; count --, rpos ++)
*buffer++ = wbuffer[rpos];
return (bytes - count);
}
ssize_t
write_cb(void *data,
ipp_uchar_t *buffer,
size_t bytes)
{
int count;
for (count = bytes; count > 0 && wused < sizeof(wbuffer); count --, wused ++)
wbuffer[wused] = *buffer++;
return (bytes - count);
}