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