Home | History | Annotate | Download | only in cups
      1 /*
      2  * IPP test program for CUPS.
      3  *
      4  * Copyright 2007-2014 by Apple Inc.
      5  * Copyright 1997-2005 by Easy Software Products.
      6  *
      7  * These coded instructions, statements, and computer programs are the
      8  * property of Apple Inc. and are protected by Federal copyright
      9  * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
     10  * which should have been included with this file.  If this file is
     11  * missing or damaged, see the license at "http://www.cups.org/".
     12  *
     13  * This file is subject to the Apple OS-Developed Software exception.
     14  */
     15 
     16 /*
     17  * Include necessary headers...
     18  */
     19 
     20 #include "file.h"
     21 #include "string-private.h"
     22 #include "ipp-private.h"
     23 #ifdef WIN32
     24 #  include <io.h>
     25 #else
     26 #  include <unistd.h>
     27 #  include <fcntl.h>
     28 #endif /* WIN32 */
     29 
     30 
     31 /*
     32  * Local types...
     33  */
     34 
     35 typedef struct _ippdata_t
     36 {
     37   size_t	rpos,			/* Read position */
     38 		wused,			/* Bytes used */
     39 		wsize;			/* Max size of buffer */
     40   ipp_uchar_t	*wbuffer;		/* Buffer */
     41 } _ippdata_t;
     42 
     43 
     44 /*
     45  * Local globals...
     46  */
     47 
     48 static ipp_uchar_t collection[] =	/* Collection buffer */
     49 		{
     50 		  0x01, 0x01,		/* IPP version */
     51 		  0x00, 0x02,		/* Print-Job operation */
     52 		  0x00, 0x00, 0x00, 0x01,
     53 		  			/* Request ID */
     54 
     55 		  IPP_TAG_OPERATION,
     56 
     57 		  IPP_TAG_CHARSET,
     58 		  0x00, 0x12,		/* Name length + name */
     59 		  'a','t','t','r','i','b','u','t','e','s','-',
     60 		  'c','h','a','r','s','e','t',
     61 		  0x00, 0x05,		/* Value length + value */
     62 		  'u','t','f','-','8',
     63 
     64 		  IPP_TAG_LANGUAGE,
     65 		  0x00, 0x1b,		/* Name length + name */
     66 		  'a','t','t','r','i','b','u','t','e','s','-',
     67 		  'n','a','t','u','r','a','l','-','l','a','n',
     68 		  'g','u','a','g','e',
     69 		  0x00, 0x02,		/* Value length + value */
     70 		  'e','n',
     71 
     72 		  IPP_TAG_URI,
     73 		  0x00, 0x0b,		/* Name length + name */
     74 		  'p','r','i','n','t','e','r','-','u','r','i',
     75 		  0x00, 0x1c,			/* Value length + value */
     76 		  'i','p','p',':','/','/','l','o','c','a','l',
     77 		  'h','o','s','t','/','p','r','i','n','t','e',
     78 		  'r','s','/','f','o','o',
     79 
     80 		  IPP_TAG_JOB,		/* job group tag */
     81 
     82 		  IPP_TAG_BEGIN_COLLECTION,
     83 		  			/* begCollection tag */
     84 		  0x00, 0x09,		/* Name length + name */
     85 		  'm', 'e', 'd', 'i', 'a', '-', 'c', 'o', 'l',
     86 		  0x00, 0x00,		/* No value */
     87 		    IPP_TAG_MEMBERNAME,	/* memberAttrName tag */
     88 		    0x00, 0x00,		/* No name */
     89 		    0x00, 0x0a,		/* Value length + value */
     90 		    'm', 'e', 'd', 'i', 'a', '-', 's', 'i', 'z', 'e',
     91 		    IPP_TAG_BEGIN_COLLECTION,
     92 		    			/* begCollection tag */
     93 		    0x00, 0x00,		/* Name length + name */
     94 		    0x00, 0x00,		/* No value */
     95 		      IPP_TAG_MEMBERNAME,
     96 		      			/* memberAttrName tag */
     97 		      0x00, 0x00,	/* No name */
     98 		      0x00, 0x0b,	/* Value length + value */
     99 		      'x', '-', 'd', 'i', 'm', 'e', 'n', 's', 'i', 'o', 'n',
    100 		      IPP_TAG_INTEGER,	/* integer tag */
    101 		      0x00, 0x00,	/* No name */
    102 		      0x00, 0x04,	/* Value length + value */
    103 		      0x00, 0x00, 0x54, 0x56,
    104 		      IPP_TAG_MEMBERNAME,
    105 		      			/* memberAttrName tag */
    106 		      0x00, 0x00,	/* No name */
    107 		      0x00, 0x0b,	/* Value length + value */
    108 		      'y', '-', 'd', 'i', 'm', 'e', 'n', 's', 'i', 'o', 'n',
    109 		      IPP_TAG_INTEGER,	/* integer tag */
    110 		      0x00, 0x00,	/* No name */
    111 		      0x00, 0x04,	/* Value length + value */
    112 		      0x00, 0x00, 0x6d, 0x24,
    113 		    IPP_TAG_END_COLLECTION,
    114 		    			/* endCollection tag */
    115 		    0x00, 0x00,		/* No name */
    116 		    0x00, 0x00,		/* No value */
    117 		    IPP_TAG_MEMBERNAME,	/* memberAttrName tag */
    118 		    0x00, 0x00,		/* No name */
    119 		    0x00, 0x0b,		/* Value length + value */
    120 		    'm', 'e', 'd', 'i', 'a', '-', 'c', 'o', 'l', 'o', 'r',
    121 		    IPP_TAG_KEYWORD,	/* keyword tag */
    122 		    0x00, 0x00,		/* No name */
    123 		    0x00, 0x04,		/* Value length + value */
    124 		    'b', 'l', 'u', 'e',
    125 
    126 		    IPP_TAG_MEMBERNAME,	/* memberAttrName tag */
    127 		    0x00, 0x00,		/* No name */
    128 		    0x00, 0x0a,		/* Value length + value */
    129 		    'm', 'e', 'd', 'i', 'a', '-', 't', 'y', 'p', 'e',
    130 		    IPP_TAG_KEYWORD,	/* keyword tag */
    131 		    0x00, 0x00,		/* No name */
    132 		    0x00, 0x05,		/* Value length + value */
    133 		    'p', 'l', 'a', 'i', 'n',
    134 		  IPP_TAG_END_COLLECTION,
    135 		  			/* endCollection tag */
    136 		  0x00, 0x00,		/* No name */
    137 		  0x00, 0x00,		/* No value */
    138 
    139 		  IPP_TAG_BEGIN_COLLECTION,
    140 		  			/* begCollection tag */
    141 		  0x00, 0x00,		/* No name */
    142 		  0x00, 0x00,		/* No value */
    143 		    IPP_TAG_MEMBERNAME,	/* memberAttrName tag */
    144 		    0x00, 0x00,		/* No name */
    145 		    0x00, 0x0a,		/* Value length + value */
    146 		    'm', 'e', 'd', 'i', 'a', '-', 's', 'i', 'z', 'e',
    147 		    IPP_TAG_BEGIN_COLLECTION,
    148 		    			/* begCollection tag */
    149 		    0x00, 0x00,		/* Name length + name */
    150 		    0x00, 0x00,		/* No value */
    151 		      IPP_TAG_MEMBERNAME,
    152 		      			/* memberAttrName tag */
    153 		      0x00, 0x00,	/* No name */
    154 		      0x00, 0x0b,	/* Value length + value */
    155 		      'x', '-', 'd', 'i', 'm', 'e', 'n', 's', 'i', 'o', 'n',
    156 		      IPP_TAG_INTEGER,	/* integer tag */
    157 		      0x00, 0x00,	/* No name */
    158 		      0x00, 0x04,	/* Value length + value */
    159 		      0x00, 0x00, 0x52, 0x08,
    160 		      IPP_TAG_MEMBERNAME,
    161 		      			/* memberAttrName tag */
    162 		      0x00, 0x00,	/* No name */
    163 		      0x00, 0x0b,	/* Value length + value */
    164 		      'y', '-', 'd', 'i', 'm', 'e', 'n', 's', 'i', 'o', 'n',
    165 		      IPP_TAG_INTEGER,	/* integer tag */
    166 		      0x00, 0x00,	/* No name */
    167 		      0x00, 0x04,	/* Value length + value */
    168 		      0x00, 0x00, 0x74, 0x04,
    169 		    IPP_TAG_END_COLLECTION,
    170 		    			/* endCollection tag */
    171 		    0x00, 0x00,		/* No name */
    172 		    0x00, 0x00,		/* No value */
    173 		    IPP_TAG_MEMBERNAME,	/* memberAttrName tag */
    174 		    0x00, 0x00,		/* No name */
    175 		    0x00, 0x0b,		/* Value length + value */
    176 		    'm', 'e', 'd', 'i', 'a', '-', 'c', 'o', 'l', 'o', 'r',
    177 		    IPP_TAG_KEYWORD,	/* keyword tag */
    178 		    0x00, 0x00,		/* No name */
    179 		    0x00, 0x05,		/* Value length + value */
    180 		    'p', 'l', 'a', 'i', 'd',
    181 
    182 		    IPP_TAG_MEMBERNAME,	/* memberAttrName tag */
    183 		    0x00, 0x00,		/* No name */
    184 		    0x00, 0x0a,		/* Value length + value */
    185 		    'm', 'e', 'd', 'i', 'a', '-', 't', 'y', 'p', 'e',
    186 		    IPP_TAG_KEYWORD,	/* keyword tag */
    187 		    0x00, 0x00,		/* No name */
    188 		    0x00, 0x06,		/* Value length + value */
    189 		    'g', 'l', 'o', 's', 's', 'y',
    190 		  IPP_TAG_END_COLLECTION,
    191 		  			/* endCollection tag */
    192 		  0x00, 0x00,		/* No name */
    193 		  0x00, 0x00,		/* No value */
    194 
    195 		  IPP_TAG_END		/* end tag */
    196 		};
    197 
    198 static ipp_uchar_t mixed[] =		/* Mixed value buffer */
    199 		{
    200 		  0x01, 0x01,		/* IPP version */
    201 		  0x00, 0x02,		/* Print-Job operation */
    202 		  0x00, 0x00, 0x00, 0x01,
    203 		  			/* Request ID */
    204 
    205 		  IPP_TAG_OPERATION,
    206 
    207 		  IPP_TAG_INTEGER,	/* integer tag */
    208 		  0x00, 0x1f,		/* Name length + name */
    209 		  'n', 'o', 't', 'i', 'f', 'y', '-', 'l', 'e', 'a', 's', 'e',
    210 		  '-', 'd', 'u', 'r', 'a', 't', 'i', 'o', 'n', '-', 's', 'u',
    211 		  'p', 'p', 'o', 'r', 't', 'e', 'd',
    212 		  0x00, 0x04,		/* Value length + value */
    213 		  0x00, 0x00, 0x00, 0x01,
    214 
    215 		  IPP_TAG_RANGE,	/* rangeOfInteger tag */
    216 		  0x00, 0x00,		/* No name */
    217 		  0x00, 0x08,		/* Value length + value */
    218 		  0x00, 0x00, 0x00, 0x10,
    219 		  0x00, 0x00, 0x00, 0x20,
    220 
    221 		  IPP_TAG_END		/* end tag */
    222 		};
    223 
    224 
    225 /*
    226  * Local functions...
    227  */
    228 
    229 void	hex_dump(const char *title, ipp_uchar_t *buffer, size_t bytes);
    230 void	print_attributes(ipp_t *ipp, int indent);
    231 ssize_t	read_cb(_ippdata_t *data, ipp_uchar_t *buffer, size_t bytes);
    232 ssize_t	write_cb(_ippdata_t *data, ipp_uchar_t *buffer, size_t bytes);
    233 
    234 
    235 /*
    236  * 'main()' - Main entry.
    237  */
    238 
    239 int				/* O - Exit status */
    240 main(int  argc,			/* I - Number of command-line arguments */
    241      char *argv[])		/* I - Command-line arguments */
    242 {
    243   _ippdata_t	data;		/* IPP buffer */
    244   ipp_uchar_t	buffer[8192];	/* Write buffer data */
    245   ipp_t		*cols[2],	/* Collections */
    246 		*size;		/* media-size collection */
    247   ipp_t		*request;	/* Request */
    248   ipp_attribute_t *media_col,	/* media-col attribute */
    249 		*media_size,	/* media-size attribute */
    250 		*attr;		/* Other attribute */
    251   ipp_state_t	state;		/* State */
    252   size_t	length;		/* Length of data */
    253   cups_file_t	*fp;		/* File pointer */
    254   size_t	i;		/* Looping var */
    255   int		status;		/* Status of tests (0 = success, 1 = fail) */
    256 #ifdef DEBUG
    257   const char	*name;		/* Option name */
    258 #endif /* DEBUG */
    259 
    260 
    261   status = 0;
    262 
    263   if (argc == 1)
    264   {
    265    /*
    266     * Test request generation code...
    267     */
    268 
    269     printf("Create Sample Request: ");
    270 
    271     request = ippNew();
    272     request->request.op.version[0]   = 0x01;
    273     request->request.op.version[1]   = 0x01;
    274     request->request.op.operation_id = IPP_OP_PRINT_JOB;
    275     request->request.op.request_id   = 1;
    276 
    277     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
    278         	 "attributes-charset", NULL, "utf-8");
    279     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
    280         	 "attributes-natural-language", NULL, "en");
    281     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
    282         	 "printer-uri", NULL, "ipp://localhost/printers/foo");
    283 
    284     cols[0] = ippNew();
    285     size    = ippNew();
    286     ippAddInteger(size, IPP_TAG_ZERO, IPP_TAG_INTEGER, "x-dimension", 21590);
    287     ippAddInteger(size, IPP_TAG_ZERO, IPP_TAG_INTEGER, "y-dimension", 27940);
    288     ippAddCollection(cols[0], IPP_TAG_JOB, "media-size", size);
    289     ippDelete(size);
    290     ippAddString(cols[0], IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-color", NULL,
    291                  "blue");
    292     ippAddString(cols[0], IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-type", NULL,
    293                  "plain");
    294 
    295     cols[1] = ippNew();
    296     size    = ippNew();
    297     ippAddInteger(size, IPP_TAG_ZERO, IPP_TAG_INTEGER, "x-dimension", 21000);
    298     ippAddInteger(size, IPP_TAG_ZERO, IPP_TAG_INTEGER, "y-dimension", 29700);
    299     ippAddCollection(cols[1], IPP_TAG_JOB, "media-size", size);
    300     ippDelete(size);
    301     ippAddString(cols[1], IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-color", NULL,
    302                  "plaid");
    303     ippAddString(cols[1], IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-type", NULL,
    304 		 "glossy");
    305 
    306     ippAddCollections(request, IPP_TAG_JOB, "media-col", 2,
    307                       (const ipp_t **)cols);
    308     ippDelete(cols[0]);
    309     ippDelete(cols[1]);
    310 
    311     length = ippLength(request);
    312     if (length != sizeof(collection))
    313     {
    314       printf("FAIL - wrong ippLength(), %d instead of %d bytes!\n",
    315              (int)length, (int)sizeof(collection));
    316       status = 1;
    317     }
    318     else
    319       puts("PASS");
    320 
    321    /*
    322     * Write test #1...
    323     */
    324 
    325     printf("Write Sample to Memory: ");
    326 
    327     data.wused   = 0;
    328     data.wsize   = sizeof(buffer);
    329     data.wbuffer = buffer;
    330 
    331     while ((state = ippWriteIO(&data, (ipp_iocb_t)write_cb, 1, NULL,
    332                                request)) != IPP_STATE_DATA)
    333       if (state == IPP_STATE_ERROR)
    334 	break;
    335 
    336     if (state != IPP_STATE_DATA)
    337     {
    338       printf("FAIL - %d bytes written.\n", (int)data.wused);
    339       status = 1;
    340     }
    341     else if (data.wused != sizeof(collection))
    342     {
    343       printf("FAIL - wrote %d bytes, expected %d bytes!\n", (int)data.wused,
    344              (int)sizeof(collection));
    345       hex_dump("Bytes Written", data.wbuffer, data.wused);
    346       hex_dump("Baseline", collection, sizeof(collection));
    347       status = 1;
    348     }
    349     else if (memcmp(data.wbuffer, collection, data.wused))
    350     {
    351       for (i = 0; i < data.wused; i ++)
    352         if (data.wbuffer[i] != collection[i])
    353 	  break;
    354 
    355       printf("FAIL - output does not match baseline at 0x%04x!\n", (unsigned)i);
    356       hex_dump("Bytes Written", data.wbuffer, data.wused);
    357       hex_dump("Baseline", collection, sizeof(collection));
    358       status = 1;
    359     }
    360     else
    361       puts("PASS");
    362 
    363     ippDelete(request);
    364 
    365    /*
    366     * Read the data back in and confirm...
    367     */
    368 
    369     printf("Read Sample from Memory: ");
    370 
    371     request     = ippNew();
    372     data.rpos = 0;
    373 
    374     while ((state = ippReadIO(&data, (ipp_iocb_t)read_cb, 1, NULL,
    375                               request)) != IPP_STATE_DATA)
    376       if (state == IPP_STATE_ERROR)
    377 	break;
    378 
    379     length = ippLength(request);
    380 
    381     if (state != IPP_STATE_DATA)
    382     {
    383       printf("FAIL - %d bytes read.\n", (int)data.rpos);
    384       status = 1;
    385     }
    386     else if (data.rpos != data.wused)
    387     {
    388       printf("FAIL - read %d bytes, expected %d bytes!\n", (int)data.rpos,
    389              (int)data.wused);
    390       print_attributes(request, 8);
    391       status = 1;
    392     }
    393     else if (length != sizeof(collection))
    394     {
    395       printf("FAIL - wrong ippLength(), %d instead of %d bytes!\n",
    396              (int)length, (int)sizeof(collection));
    397       print_attributes(request, 8);
    398       status = 1;
    399     }
    400     else
    401       puts("PASS");
    402 
    403     fputs("ippFindAttribute(media-col): ", stdout);
    404     if ((media_col = ippFindAttribute(request, "media-col",
    405                                       IPP_TAG_BEGIN_COLLECTION)) == NULL)
    406     {
    407       if ((media_col = ippFindAttribute(request, "media-col",
    408                                         IPP_TAG_ZERO)) == NULL)
    409         puts("FAIL (not found)");
    410       else
    411         printf("FAIL (wrong type - %s)\n", ippTagString(media_col->value_tag));
    412 
    413       status = 1;
    414     }
    415     else if (media_col->num_values != 2)
    416     {
    417       printf("FAIL (wrong count - %d)\n", media_col->num_values);
    418       status = 1;
    419     }
    420     else
    421       puts("PASS");
    422 
    423     if (media_col)
    424     {
    425       fputs("ippFindAttribute(media-size 1): ", stdout);
    426       if ((media_size = ippFindAttribute(media_col->values[0].collection,
    427 					 "media-size",
    428 					 IPP_TAG_BEGIN_COLLECTION)) == NULL)
    429       {
    430 	if ((media_size = ippFindAttribute(media_col->values[0].collection,
    431 					   "media-col",
    432 					   IPP_TAG_ZERO)) == NULL)
    433 	  puts("FAIL (not found)");
    434 	else
    435 	  printf("FAIL (wrong type - %s)\n",
    436 	         ippTagString(media_size->value_tag));
    437 
    438 	status = 1;
    439       }
    440       else
    441       {
    442 	if ((attr = ippFindAttribute(media_size->values[0].collection,
    443 				     "x-dimension", IPP_TAG_INTEGER)) == NULL)
    444 	{
    445 	  if ((attr = ippFindAttribute(media_size->values[0].collection,
    446 				       "x-dimension", IPP_TAG_ZERO)) == NULL)
    447 	    puts("FAIL (missing x-dimension)");
    448 	  else
    449 	    printf("FAIL (wrong type for x-dimension - %s)\n",
    450 		   ippTagString(attr->value_tag));
    451 
    452 	  status = 1;
    453 	}
    454 	else if (attr->values[0].integer != 21590)
    455 	{
    456 	  printf("FAIL (wrong value for x-dimension - %d)\n",
    457 		 attr->values[0].integer);
    458 	  status = 1;
    459 	}
    460 	else if ((attr = ippFindAttribute(media_size->values[0].collection,
    461 					  "y-dimension",
    462 					  IPP_TAG_INTEGER)) == NULL)
    463 	{
    464 	  if ((attr = ippFindAttribute(media_size->values[0].collection,
    465 				       "y-dimension", IPP_TAG_ZERO)) == NULL)
    466 	    puts("FAIL (missing y-dimension)");
    467 	  else
    468 	    printf("FAIL (wrong type for y-dimension - %s)\n",
    469 		   ippTagString(attr->value_tag));
    470 
    471 	  status = 1;
    472 	}
    473 	else if (attr->values[0].integer != 27940)
    474 	{
    475 	  printf("FAIL (wrong value for y-dimension - %d)\n",
    476 		 attr->values[0].integer);
    477 	  status = 1;
    478 	}
    479 	else
    480 	  puts("PASS");
    481       }
    482 
    483       fputs("ippFindAttribute(media-size 2): ", stdout);
    484       if ((media_size = ippFindAttribute(media_col->values[1].collection,
    485 					 "media-size",
    486 					 IPP_TAG_BEGIN_COLLECTION)) == NULL)
    487       {
    488 	if ((media_size = ippFindAttribute(media_col->values[1].collection,
    489 					   "media-col",
    490 					   IPP_TAG_ZERO)) == NULL)
    491 	  puts("FAIL (not found)");
    492 	else
    493 	  printf("FAIL (wrong type - %s)\n",
    494 	         ippTagString(media_size->value_tag));
    495 
    496 	status = 1;
    497       }
    498       else
    499       {
    500 	if ((attr = ippFindAttribute(media_size->values[0].collection,
    501 				     "x-dimension",
    502 				     IPP_TAG_INTEGER)) == NULL)
    503 	{
    504 	  if ((attr = ippFindAttribute(media_size->values[0].collection,
    505 				       "x-dimension", IPP_TAG_ZERO)) == NULL)
    506 	    puts("FAIL (missing x-dimension)");
    507 	  else
    508 	    printf("FAIL (wrong type for x-dimension - %s)\n",
    509 		   ippTagString(attr->value_tag));
    510 
    511 	  status = 1;
    512 	}
    513 	else if (attr->values[0].integer != 21000)
    514 	{
    515 	  printf("FAIL (wrong value for x-dimension - %d)\n",
    516 		 attr->values[0].integer);
    517 	  status = 1;
    518 	}
    519 	else if ((attr = ippFindAttribute(media_size->values[0].collection,
    520 					  "y-dimension",
    521 					  IPP_TAG_INTEGER)) == NULL)
    522 	{
    523 	  if ((attr = ippFindAttribute(media_size->values[0].collection,
    524 				       "y-dimension", IPP_TAG_ZERO)) == NULL)
    525 	    puts("FAIL (missing y-dimension)");
    526 	  else
    527 	    printf("FAIL (wrong type for y-dimension - %s)\n",
    528 		   ippTagString(attr->value_tag));
    529 
    530 	  status = 1;
    531 	}
    532 	else if (attr->values[0].integer != 29700)
    533 	{
    534 	  printf("FAIL (wrong value for y-dimension - %d)\n",
    535 		 attr->values[0].integer);
    536 	  status = 1;
    537 	}
    538 	else
    539 	  puts("PASS");
    540       }
    541     }
    542 
    543    /*
    544     * Test hierarchical find...
    545     */
    546 
    547     fputs("ippFindAttribute(media-col/media-size/x-dimension): ", stdout);
    548     if ((attr = ippFindAttribute(request, "media-col/media-size/x-dimension", IPP_TAG_INTEGER)) != NULL)
    549     {
    550       if (ippGetInteger(attr, 0) != 21590)
    551       {
    552         printf("FAIL (wrong value for x-dimension - %d)\n", ippGetInteger(attr, 0));
    553         status = 1;
    554       }
    555       else
    556         puts("PASS");
    557     }
    558     else
    559     {
    560       puts("FAIL (not found)");
    561       status = 1;
    562     }
    563 
    564     fputs("ippFindNextAttribute(media-col/media-size/x-dimension): ", stdout);
    565     if ((attr = ippFindNextAttribute(request, "media-col/media-size/x-dimension", IPP_TAG_INTEGER)) != NULL)
    566     {
    567       if (ippGetInteger(attr, 0) != 21000)
    568       {
    569         printf("FAIL (wrong value for x-dimension - %d)\n", ippGetInteger(attr, 0));
    570         status = 1;
    571       }
    572       else
    573         puts("PASS");
    574     }
    575     else
    576     {
    577       puts("FAIL (not found)");
    578       status = 1;
    579     }
    580 
    581     fputs("ippFindNextAttribute(media-col/media-size/x-dimension) again: ", stdout);
    582     if ((attr = ippFindNextAttribute(request, "media-col/media-size/x-dimension", IPP_TAG_INTEGER)) != NULL)
    583     {
    584       printf("FAIL (got %d, expected nothing)\n", ippGetInteger(attr, 0));
    585       status = 1;
    586     }
    587     else
    588       puts("PASS");
    589 
    590     ippDelete(request);
    591 
    592    /*
    593     * Read the mixed data and confirm we converted everything to rangeOfInteger
    594     * values...
    595     */
    596 
    597     printf("Read Mixed integer/rangeOfInteger from Memory: ");
    598 
    599     request = ippNew();
    600     data.rpos    = 0;
    601     data.wused   = sizeof(mixed);
    602     data.wsize   = sizeof(mixed);
    603     data.wbuffer = mixed;
    604 
    605     while ((state = ippReadIO(&data, (ipp_iocb_t)read_cb, 1, NULL,
    606                               request)) != IPP_STATE_DATA)
    607       if (state == IPP_STATE_ERROR)
    608 	break;
    609 
    610     length = ippLength(request);
    611 
    612     if (state != IPP_STATE_DATA)
    613     {
    614       printf("FAIL - %d bytes read.\n", (int)data.rpos);
    615       status = 1;
    616     }
    617     else if (data.rpos != sizeof(mixed))
    618     {
    619       printf("FAIL - read %d bytes, expected %d bytes!\n", (int)data.rpos,
    620              (int)sizeof(mixed));
    621       print_attributes(request, 8);
    622       status = 1;
    623     }
    624     else if (length != (sizeof(mixed) + 4))
    625     {
    626       printf("FAIL - wrong ippLength(), %d instead of %d bytes!\n",
    627              (int)length, (int)sizeof(mixed) + 4);
    628       print_attributes(request, 8);
    629       status = 1;
    630     }
    631     else
    632       puts("PASS");
    633 
    634     fputs("ippFindAttribute(notify-lease-duration-supported): ", stdout);
    635     if ((attr = ippFindAttribute(request, "notify-lease-duration-supported",
    636                                  IPP_TAG_ZERO)) == NULL)
    637     {
    638       puts("FAIL (not found)");
    639       status = 1;
    640     }
    641     else if (attr->value_tag != IPP_TAG_RANGE)
    642     {
    643       printf("FAIL (wrong type - %s)\n", ippTagString(attr->value_tag));
    644       status = 1;
    645     }
    646     else if (attr->num_values != 2)
    647     {
    648       printf("FAIL (wrong count - %d)\n", attr->num_values);
    649       status = 1;
    650     }
    651     else if (attr->values[0].range.lower != 1 ||
    652              attr->values[0].range.upper != 1 ||
    653              attr->values[1].range.lower != 16 ||
    654              attr->values[1].range.upper != 32)
    655     {
    656       printf("FAIL (wrong values - %d,%d and %d,%d)\n",
    657              attr->values[0].range.lower,
    658              attr->values[0].range.upper,
    659              attr->values[1].range.lower,
    660              attr->values[1].range.upper);
    661       status = 1;
    662     }
    663     else
    664       puts("PASS");
    665 
    666     ippDelete(request);
    667 
    668 #ifdef DEBUG
    669    /*
    670     * Test that private option array is sorted...
    671     */
    672 
    673     fputs("_ippCheckOptions: ", stdout);
    674     if ((name = _ippCheckOptions()) == NULL)
    675       puts("PASS");
    676     else
    677     {
    678       printf("FAIL (\"%s\" out of order)\n", name);
    679       status = 1;
    680     }
    681 #endif /* DEBUG */
    682 
    683    /*
    684     * Test _ippFindOption() private API...
    685     */
    686 
    687     fputs("_ippFindOption(\"printer-type\"): ", stdout);
    688     if (_ippFindOption("printer-type"))
    689       puts("PASS");
    690     else
    691     {
    692       puts("FAIL");
    693       status = 1;
    694     }
    695 
    696    /*
    697     * Summarize...
    698     */
    699 
    700     putchar('\n');
    701 
    702     if (status)
    703       puts("Core IPP tests failed.");
    704     else
    705       puts("Core IPP tests passed.");
    706   }
    707   else
    708   {
    709    /*
    710     * Read IPP files...
    711     */
    712 
    713     for (i = 1; i < (size_t)argc; i ++)
    714     {
    715       if ((fp = cupsFileOpen(argv[i], "r")) == NULL)
    716       {
    717 	printf("Unable to open \"%s\" - %s\n", argv[i], strerror(errno));
    718 	status = 1;
    719 	continue;
    720       }
    721 
    722       request = ippNew();
    723       while ((state = ippReadIO(fp, (ipp_iocb_t)cupsFileRead, 1, NULL,
    724                                 request)) == IPP_STATE_ATTRIBUTE);
    725 
    726       if (state != IPP_STATE_DATA)
    727       {
    728 	printf("Error reading IPP message from \"%s\"!\n", argv[i]);
    729 	status = 1;
    730       }
    731       else
    732       {
    733 	printf("\n%s:\n", argv[i]);
    734 	print_attributes(request, 4);
    735       }
    736 
    737       ippDelete(request);
    738       cupsFileClose(fp);
    739     }
    740   }
    741 
    742   return (status);
    743 }
    744 
    745 
    746 /*
    747  * 'hex_dump()' - Produce a hex dump of a buffer.
    748  */
    749 
    750 void
    751 hex_dump(const char  *title,		/* I - Title */
    752          ipp_uchar_t *buffer,		/* I - Buffer to dump */
    753          size_t      bytes)		/* I - Number of bytes */
    754 {
    755   size_t	i, j;			/* Looping vars */
    756   int		ch;			/* Current ASCII char */
    757 
    758 
    759  /*
    760   * Show lines of 16 bytes at a time...
    761   */
    762 
    763   printf("    %s:\n", title);
    764 
    765   for (i = 0; i < bytes; i += 16)
    766   {
    767    /*
    768     * Show the offset...
    769     */
    770 
    771     printf("    %04x ", (unsigned)i);
    772 
    773    /*
    774     * Then up to 16 bytes in hex...
    775     */
    776 
    777     for (j = 0; j < 16; j ++)
    778       if ((i + j) < bytes)
    779         printf(" %02x", buffer[i + j]);
    780       else
    781         printf("   ");
    782 
    783    /*
    784     * Then the ASCII representation of the bytes...
    785     */
    786 
    787     putchar(' ');
    788     putchar(' ');
    789 
    790     for (j = 0; j < 16 && (i + j) < bytes; j ++)
    791     {
    792       ch = buffer[i + j] & 127;
    793 
    794       if (ch < ' ' || ch == 127)
    795         putchar('.');
    796       else
    797         putchar(ch);
    798     }
    799 
    800     putchar('\n');
    801   }
    802 }
    803 
    804 
    805 /*
    806  * 'print_attributes()' - Print the attributes in a request...
    807  */
    808 
    809 void
    810 print_attributes(ipp_t *ipp,		/* I - IPP request */
    811                  int   indent)		/* I - Indentation */
    812 {
    813   int			i;		/* Looping var */
    814   ipp_tag_t		group;		/* Current group */
    815   ipp_attribute_t	*attr;		/* Current attribute */
    816   _ipp_value_t		*val;		/* Current value */
    817   static const char * const tags[] =	/* Value/group tag strings */
    818 			{
    819 			  "reserved-00",
    820 			  "operation-attributes-tag",
    821 			  "job-attributes-tag",
    822 			  "end-of-attributes-tag",
    823 			  "printer-attributes-tag",
    824 			  "unsupported-attributes-tag",
    825 			  "subscription-attributes-tag",
    826 			  "event-attributes-tag",
    827 			  "reserved-08",
    828 			  "reserved-09",
    829 			  "reserved-0A",
    830 			  "reserved-0B",
    831 			  "reserved-0C",
    832 			  "reserved-0D",
    833 			  "reserved-0E",
    834 			  "reserved-0F",
    835 			  "unsupported",
    836 			  "default",
    837 			  "unknown",
    838 			  "no-value",
    839 			  "reserved-14",
    840 			  "not-settable",
    841 			  "delete-attr",
    842 			  "admin-define",
    843 			  "reserved-18",
    844 			  "reserved-19",
    845 			  "reserved-1A",
    846 			  "reserved-1B",
    847 			  "reserved-1C",
    848 			  "reserved-1D",
    849 			  "reserved-1E",
    850 			  "reserved-1F",
    851 			  "reserved-20",
    852 			  "integer",
    853 			  "boolean",
    854 			  "enum",
    855 			  "reserved-24",
    856 			  "reserved-25",
    857 			  "reserved-26",
    858 			  "reserved-27",
    859 			  "reserved-28",
    860 			  "reserved-29",
    861 			  "reserved-2a",
    862 			  "reserved-2b",
    863 			  "reserved-2c",
    864 			  "reserved-2d",
    865 			  "reserved-2e",
    866 			  "reserved-2f",
    867 			  "octetString",
    868 			  "dateTime",
    869 			  "resolution",
    870 			  "rangeOfInteger",
    871 			  "begCollection",
    872 			  "textWithLanguage",
    873 			  "nameWithLanguage",
    874 			  "endCollection",
    875 			  "reserved-38",
    876 			  "reserved-39",
    877 			  "reserved-3a",
    878 			  "reserved-3b",
    879 			  "reserved-3c",
    880 			  "reserved-3d",
    881 			  "reserved-3e",
    882 			  "reserved-3f",
    883 			  "reserved-40",
    884 			  "textWithoutLanguage",
    885 			  "nameWithoutLanguage",
    886 			  "reserved-43",
    887 			  "keyword",
    888 			  "uri",
    889 			  "uriScheme",
    890 			  "charset",
    891 			  "naturalLanguage",
    892 			  "mimeMediaType",
    893 			  "memberName"
    894 			};
    895 
    896 
    897   for (group = IPP_TAG_ZERO, attr = ipp->attrs; attr; attr = attr->next)
    898   {
    899     if (!attr->name && indent == 4)
    900     {
    901       group = IPP_TAG_ZERO;
    902       putchar('\n');
    903       continue;
    904     }
    905 
    906     if (group != attr->group_tag)
    907     {
    908       group = attr->group_tag;
    909 
    910       printf("\n%*s%s:\n\n", indent - 4, "", tags[group]);
    911     }
    912 
    913     printf("%*s%s (", indent, "", attr->name ? attr->name : "(null)");
    914     if (attr->num_values > 1)
    915       printf("1setOf ");
    916     printf("%s):", tags[attr->value_tag]);
    917 
    918     switch (attr->value_tag)
    919     {
    920       case IPP_TAG_ENUM :
    921       case IPP_TAG_INTEGER :
    922           for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
    923 	    printf(" %d", val->integer);
    924           putchar('\n');
    925           break;
    926 
    927       case IPP_TAG_BOOLEAN :
    928           for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
    929 	    printf(" %s", val->boolean ? "true" : "false");
    930           putchar('\n');
    931           break;
    932 
    933       case IPP_TAG_RANGE :
    934           for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
    935 	    printf(" %d-%d", val->range.lower, val->range.upper);
    936           putchar('\n');
    937           break;
    938 
    939       case IPP_TAG_DATE :
    940           {
    941 	    char	vstring[256];	/* Formatted time */
    942 
    943 	    for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
    944 	      printf(" (%s)", _cupsStrDate(vstring, sizeof(vstring), ippDateToTime(val->date)));
    945           }
    946           putchar('\n');
    947           break;
    948 
    949       case IPP_TAG_RESOLUTION :
    950           for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
    951 	    printf(" %dx%d%s", val->resolution.xres, val->resolution.yres,
    952 	           val->resolution.units == IPP_RES_PER_INCH ? "dpi" : "dpcm");
    953           putchar('\n');
    954           break;
    955 
    956       case IPP_TAG_STRING :
    957       case IPP_TAG_TEXTLANG :
    958       case IPP_TAG_NAMELANG :
    959       case IPP_TAG_TEXT :
    960       case IPP_TAG_NAME :
    961       case IPP_TAG_KEYWORD :
    962       case IPP_TAG_URI :
    963       case IPP_TAG_URISCHEME :
    964       case IPP_TAG_CHARSET :
    965       case IPP_TAG_LANGUAGE :
    966       case IPP_TAG_MIMETYPE :
    967           for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
    968 	    printf(" \"%s\"", val->string.text);
    969           putchar('\n');
    970           break;
    971 
    972       case IPP_TAG_BEGIN_COLLECTION :
    973           putchar('\n');
    974 
    975           for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
    976 	  {
    977 	    if (i)
    978 	      putchar('\n');
    979 	    print_attributes(val->collection, indent + 4);
    980 	  }
    981           break;
    982 
    983       default :
    984           printf("UNKNOWN (%d values)\n", attr->num_values);
    985           break;
    986     }
    987   }
    988 }
    989 
    990 
    991 /*
    992  * 'read_cb()' - Read data from a buffer.
    993  */
    994 
    995 ssize_t					/* O - Number of bytes read */
    996 read_cb(_ippdata_t   *data,		/* I - Data */
    997         ipp_uchar_t *buffer,		/* O - Buffer to read */
    998 	size_t      bytes)		/* I - Number of bytes to read */
    999 {
   1000   size_t	count;			/* Number of bytes */
   1001 
   1002 
   1003  /*
   1004   * Copy bytes from the data buffer to the read buffer...
   1005   */
   1006 
   1007   if ((count = data->wsize - data->rpos) > bytes)
   1008     count = bytes;
   1009 
   1010   memcpy(buffer, data->wbuffer + data->rpos, count);
   1011   data->rpos += count;
   1012 
   1013  /*
   1014   * Return the number of bytes read...
   1015   */
   1016 
   1017   return ((ssize_t)count);
   1018 }
   1019 
   1020 
   1021 /*
   1022  * 'write_cb()' - Write data into a buffer.
   1023  */
   1024 
   1025 ssize_t					/* O - Number of bytes written */
   1026 write_cb(_ippdata_t   *data,		/* I - Data */
   1027          ipp_uchar_t *buffer,		/* I - Buffer to write */
   1028 	 size_t      bytes)		/* I - Number of bytes to write */
   1029 {
   1030   size_t	count;			/* Number of bytes */
   1031 
   1032 
   1033  /*
   1034   * Loop until all bytes are written...
   1035   */
   1036 
   1037   if ((count = data->wsize - data->wused) > bytes)
   1038     count = bytes;
   1039 
   1040   memcpy(data->wbuffer + data->wused, buffer, count);
   1041   data->wused += count;
   1042 
   1043  /*
   1044   * Return the number of bytes written...
   1045   */
   1046 
   1047   return ((ssize_t)count);
   1048 }
   1049