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