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