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