1 /*
2  * IPP test program for CUPS.
3  *
4  * Copyright 2007-2017 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 */
main(int argc,char * argv[])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
hex_dump(const char * title,ipp_uchar_t * buffer,size_t bytes)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
print_attributes(ipp_t * ipp,int indent)810 print_attributes(ipp_t *ipp,		/* I - IPP request */
811                  int   indent)		/* I - Indentation */
812 {
813   ipp_tag_t		group;		/* Current group */
814   ipp_attribute_t	*attr;		/* Current attribute */
815   char                  buffer[2048];   /* Value string */
816 
817 
818   for (group = IPP_TAG_ZERO, attr = ipp->attrs; attr; attr = attr->next)
819   {
820     if (!attr->name && indent == 4)
821     {
822       group = IPP_TAG_ZERO;
823       putchar('\n');
824       continue;
825     }
826 
827     if (group != attr->group_tag)
828     {
829       group = attr->group_tag;
830 
831       printf("\n%*s%s:\n\n", indent - 4, "", ippTagString(group));
832     }
833 
834     ippAttributeString(attr, buffer, sizeof(buffer));
835 
836     printf("%*s%s (%s%s): %s\n", indent, "", attr->name ? attr->name : "(null)", attr->num_values > 1 ? "1setOf " : "", ippTagString(attr->value_tag), buffer);
837   }
838 }
839 
840 
841 /*
842  * 'read_cb()' - Read data from a buffer.
843  */
844 
845 ssize_t					/* O - Number of bytes read */
read_cb(_ippdata_t * data,ipp_uchar_t * buffer,size_t bytes)846 read_cb(_ippdata_t   *data,		/* I - Data */
847         ipp_uchar_t *buffer,		/* O - Buffer to read */
848 	size_t      bytes)		/* I - Number of bytes to read */
849 {
850   size_t	count;			/* Number of bytes */
851 
852 
853  /*
854   * Copy bytes from the data buffer to the read buffer...
855   */
856 
857   if ((count = data->wsize - data->rpos) > bytes)
858     count = bytes;
859 
860   memcpy(buffer, data->wbuffer + data->rpos, count);
861   data->rpos += count;
862 
863  /*
864   * Return the number of bytes read...
865   */
866 
867   return ((ssize_t)count);
868 }
869 
870 
871 /*
872  * 'write_cb()' - Write data into a buffer.
873  */
874 
875 ssize_t					/* O - Number of bytes written */
write_cb(_ippdata_t * data,ipp_uchar_t * buffer,size_t bytes)876 write_cb(_ippdata_t   *data,		/* I - Data */
877          ipp_uchar_t *buffer,		/* I - Buffer to write */
878 	 size_t      bytes)		/* I - Number of bytes to write */
879 {
880   size_t	count;			/* Number of bytes */
881 
882 
883  /*
884   * Loop until all bytes are written...
885   */
886 
887   if ((count = data->wsize - data->wused) > bytes)
888     count = bytes;
889 
890   memcpy(data->wbuffer + data->wused, buffer, count);
891   data->wused += count;
892 
893  /*
894   * Return the number of bytes written...
895   */
896 
897   return ((ssize_t)count);
898 }
899