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