]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/testipp.c
Merge changes from CUPS 1.4svn-r8252.
[thirdparty/cups.git] / cups / testipp.c
1 /*
2 * "$Id: testipp.c 6649 2007-07-11 21:46:42Z mike $"
3 *
4 * IPP test program for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2007-2009 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 * Contents:
18 *
19 * main() - Main entry.
20 */
21
22 /*
23 * Include necessary headers...
24 */
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <cups/string.h>
29 #include <errno.h>
30 #include "ipp-private.h"
31 #ifdef WIN32
32 # include <io.h>
33 #else
34 # include <unistd.h>
35 # include <fcntl.h>
36 #endif /* WIN32 */
37
38
39 /*
40 * Local globals...
41 */
42
43 int rpos; /* Current position in buffer */
44 ipp_uchar_t wbuffer[8192]; /* Write buffer */
45 int wused; /* Number of bytes in buffer */
46 ipp_uchar_t collection[] = /* Collection buffer */
47 {
48 0x01, 0x01, /* IPP version */
49 0x00, 0x02, /* Print-Job operation */
50 0x00, 0x00, 0x00, 0x01, /* Request ID */
51
52 IPP_TAG_OPERATION,
53
54 IPP_TAG_CHARSET,
55 0x00, 0x12, /* Name length + name */
56 'a','t','t','r','i','b','u','t','e','s','-',
57 'c','h','a','r','s','e','t',
58 0x00, 0x05, /* Value length + value */
59 'u','t','f','-','8',
60
61 IPP_TAG_LANGUAGE,
62 0x00, 0x1b, /* Name length + name */
63 'a','t','t','r','i','b','u','t','e','s','-',
64 'n','a','t','u','r','a','l','-','l','a','n',
65 'g','u','a','g','e',
66 0x00, 0x02, /* Value length + value */
67 'e','n',
68
69 IPP_TAG_URI,
70 0x00, 0x0b, /* Name length + name */
71 'p','r','i','n','t','e','r','-','u','r','i',
72 0x00, 0x1c, /* Value length + value */
73 'i','p','p',':','/','/','l','o','c','a','l',
74 'h','o','s','t','/','p','r','i','n','t','e',
75 'r','s','/','f','o','o',
76
77 IPP_TAG_JOB, /* job group tag */
78
79 IPP_TAG_BEGIN_COLLECTION, /* 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, 0x0b, /* Value length + value */
86 'm', 'e', 'd', 'i', 'a', '-', 'c', 'o', 'l', 'o', 'r',
87 IPP_TAG_KEYWORD, /* keyword tag */
88 0x00, 0x00, /* No name */
89 0x00, 0x04, /* Value length + value */
90 'b', 'l', 'u', 'e',
91
92 IPP_TAG_MEMBERNAME, /* memberAttrName tag */
93 0x00, 0x00, /* No name */
94 0x00, 0x0a, /* Value length + value */
95 'm', 'e', 'd', 'i', 'a', '-', 't', 'y', 'p', 'e',
96 IPP_TAG_KEYWORD, /* keyword tag */
97 0x00, 0x00, /* No name */
98 0x00, 0x05, /* Value length + value */
99 'p', 'l', 'a', 'i', 'n',
100 IPP_TAG_END_COLLECTION, /* endCollection tag */
101 0x00, 0x00, /* No name */
102 0x00, 0x00, /* No value */
103
104 IPP_TAG_BEGIN_COLLECTION, /* begCollection tag */
105 0x00, 0x00, /* No name */
106 0x00, 0x00, /* No value */
107 IPP_TAG_MEMBERNAME, /* memberAttrName tag */
108 0x00, 0x00, /* No name */
109 0x00, 0x0b, /* Value length + value */
110 'm', 'e', 'd', 'i', 'a', '-', 'c', 'o', 'l', 'o', 'r',
111 IPP_TAG_KEYWORD, /* keyword tag */
112 0x00, 0x00, /* No name */
113 0x00, 0x05, /* Value length + value */
114 'p', 'l', 'a', 'i', 'd',
115
116 IPP_TAG_MEMBERNAME, /* memberAttrName tag */
117 0x00, 0x00, /* No name */
118 0x00, 0x0a, /* Value length + value */
119 'm', 'e', 'd', 'i', 'a', '-', 't', 'y', 'p', 'e',
120 IPP_TAG_KEYWORD, /* keyword tag */
121 0x00, 0x00, /* No name */
122 0x00, 0x06, /* Value length + value */
123 'g', 'l', 'o', 's', 's', 'y',
124 IPP_TAG_END_COLLECTION, /* endCollection tag */
125 0x00, 0x00, /* No name */
126 0x00, 0x00, /* No value */
127
128 IPP_TAG_END /* end tag */
129 };
130
131
132 /*
133 * Local functions...
134 */
135
136 void hex_dump(const char *title, ipp_uchar_t *buffer, int bytes);
137 void print_attributes(ipp_t *ipp, int indent);
138 ssize_t read_cb(void *data, ipp_uchar_t *buffer, size_t bytes);
139 ssize_t write_cb(void *data, ipp_uchar_t *buffer, size_t bytes);
140
141
142 /*
143 * 'main()' - Main entry.
144 */
145
146 int /* O - Exit status */
147 main(int argc, /* I - Number of command-line arguments */
148 char *argv[]) /* I - Command-line arguments */
149 {
150 ipp_t *cols[2]; /* Collections */
151 ipp_t *request; /* Request */
152 ipp_state_t state; /* State */
153 int length; /* Length of data */
154 int fd; /* File descriptor */
155 int i; /* Looping var */
156 int status; /* Status of tests (0 = success, 1 = fail) */
157
158
159 status = 0;
160
161 if (argc == 1)
162 {
163 /*
164 * Test request generation code...
165 */
166
167 printf("Create Sample Request: ");
168
169 request = ippNew();
170 request->request.op.version[0] = 0x01;
171 request->request.op.version[1] = 0x01;
172 request->request.op.operation_id = IPP_PRINT_JOB;
173 request->request.op.request_id = 1;
174
175 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
176 "attributes-charset", NULL, "utf-8");
177 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
178 "attributes-natural-language", NULL, "en");
179 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
180 "printer-uri", NULL, "ipp://localhost/printers/foo");
181
182 cols[0] = ippNew();
183 ippAddString(cols[0], IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-color", NULL, "blue");
184 ippAddString(cols[0], IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-type", NULL, "plain");
185
186 cols[1] = ippNew();
187 ippAddString(cols[1], IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-color", NULL, "plaid");
188 ippAddString(cols[1], IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-type", NULL, "glossy");
189
190 ippAddCollections(request, IPP_TAG_JOB, "media-col", 2, (const ipp_t **)cols);
191
192 length = ippLength(request);
193 if (length != sizeof(collection))
194 {
195 printf("FAIL - wrong ippLength(), %d instead of %d bytes!\n",
196 length, (int)sizeof(collection));
197 status = 1;
198 }
199 else
200 puts("PASS");
201
202 /*
203 * Write test #1...
204 */
205
206 printf("Write Sample to Memory: ");
207
208 wused = 0;
209 while ((state = ippWriteIO(wbuffer, write_cb, 1, NULL, request)) != IPP_DATA)
210 if (state == IPP_ERROR)
211 break;
212
213 if (state != IPP_DATA)
214 {
215 printf("FAIL - %d bytes written.\n", wused);
216 status = 1;
217 }
218 else if (wused != sizeof(collection))
219 {
220 printf("FAIL - wrote %d bytes, expected %d bytes!\n", wused,
221 (int)sizeof(collection));
222 hex_dump("Bytes Written", wbuffer, wused);
223 hex_dump("Baseline", collection, sizeof(collection));
224 status = 1;
225 }
226 else if (memcmp(wbuffer, collection, wused))
227 {
228 puts("FAIL - output does not match baseline!");
229 hex_dump("Bytes Written", wbuffer, wused);
230 hex_dump("Baseline", collection, sizeof(collection));
231 status = 1;
232 }
233 else
234 puts("PASS");
235
236 ippDelete(request);
237
238 /*
239 * Read the data back in and confirm...
240 */
241
242 printf("Read Sample from Memory: ");
243
244 request = ippNew();
245 rpos = 0;
246
247 while ((state = ippReadIO(wbuffer, read_cb, 1, NULL, request)) != IPP_DATA)
248 if (state == IPP_ERROR)
249 break;
250
251 length = ippLength(request);
252
253 if (state != IPP_DATA)
254 {
255 printf("FAIL - %d bytes read.\n", rpos);
256 status = 1;
257 }
258 else if (rpos != wused)
259 {
260 printf("FAIL - read %d bytes, expected %d bytes!\n", rpos, wused);
261 print_attributes(request, 8);
262 status = 1;
263 }
264 else if (length != sizeof(collection))
265 {
266 printf("FAIL - wrong ippLength(), %d instead of %d bytes!\n",
267 length, (int)sizeof(collection));
268 print_attributes(request, 8);
269 status = 1;
270 }
271 else
272 puts("PASS");
273
274 ippDelete(request);
275
276 /*
277 * Test _ippFindOption() private API...
278 */
279
280 fputs("_ippFindOption(\"printer-type\"): ", stdout);
281 if (_ippFindOption("printer-type"))
282 puts("PASS");
283 else
284 {
285 puts("FAIL");
286 status = 1;
287 }
288
289 /*
290 * Summarize...
291 */
292
293 putchar('\n');
294
295 if (status)
296 puts("Core IPP tests failed.");
297 else
298 puts("Core IPP tests passed.");
299 }
300 else
301 {
302 /*
303 * Read IPP files...
304 */
305
306 for (i = 1; i < argc; i ++)
307 {
308 if ((fd = open(argv[i], O_RDONLY)) < 0)
309 {
310 printf("Unable to open \"%s\" - %s\n", argv[i], strerror(errno));
311 status = 1;
312 continue;
313 }
314
315 request = ippNew();
316 while ((state = ippReadFile(fd, request)) == IPP_ATTRIBUTE);
317
318 if (state != IPP_DATA)
319 {
320 printf("Error reading IPP message from \"%s\"!\n", argv[i]);
321 status = 1;
322 }
323 else
324 {
325 printf("\n%s:\n", argv[i]);
326 print_attributes(request, 4);
327 }
328
329 ippDelete(request);
330 close(fd);
331 }
332 }
333
334 return (status);
335 }
336
337
338 /*
339 * 'hex_dump()' - Produce a hex dump of a buffer.
340 */
341
342 void
343 hex_dump(const char *title, /* I - Title */
344 ipp_uchar_t *buffer, /* I - Buffer to dump */
345 int bytes) /* I - Number of bytes */
346 {
347 int i, j; /* Looping vars */
348 int ch; /* Current ASCII char */
349
350
351 /*
352 * Show lines of 16 bytes at a time...
353 */
354
355 printf(" %s:\n", title);
356
357 for (i = 0; i < bytes; i += 16)
358 {
359 /*
360 * Show the offset...
361 */
362
363 printf(" %04x ", i);
364
365 /*
366 * Then up to 16 bytes in hex...
367 */
368
369 for (j = 0; j < 16; j ++)
370 if ((i + j) < bytes)
371 printf(" %02x", buffer[i + j]);
372 else
373 printf(" ");
374
375 /*
376 * Then the ASCII representation of the bytes...
377 */
378
379 putchar(' ');
380 putchar(' ');
381
382 for (j = 0; j < 16 && (i + j) < bytes; j ++)
383 {
384 ch = buffer[i + j] & 127;
385
386 if (ch < ' ' || ch == 127)
387 putchar('.');
388 else
389 putchar(ch);
390 }
391
392 putchar('\n');
393 }
394 }
395
396
397 /*
398 * 'print_attributes()' - Print the attributes in a request...
399 */
400
401 void
402 print_attributes(ipp_t *ipp, /* I - IPP request */
403 int indent) /* I - Indentation */
404 {
405 int i; /* Looping var */
406 ipp_tag_t group; /* Current group */
407 ipp_attribute_t *attr; /* Current attribute */
408 ipp_value_t *val; /* Current value */
409 static const char * const tags[] = /* Value/group tag strings */
410 {
411 "reserved-00",
412 "operation-attributes-tag",
413 "job-attributes-tag",
414 "end-of-attributes-tag",
415 "printer-attributes-tag",
416 "unsupported-attributes-tag",
417 "subscription-attributes-tag",
418 "event-attributes-tag",
419 "reserved-08",
420 "reserved-09",
421 "reserved-0A",
422 "reserved-0B",
423 "reserved-0C",
424 "reserved-0D",
425 "reserved-0E",
426 "reserved-0F",
427 "unsupported",
428 "default",
429 "unknown",
430 "no-value",
431 "reserved-14",
432 "not-settable",
433 "delete-attr",
434 "admin-define",
435 "reserved-18",
436 "reserved-19",
437 "reserved-1A",
438 "reserved-1B",
439 "reserved-1C",
440 "reserved-1D",
441 "reserved-1E",
442 "reserved-1F",
443 "reserved-20",
444 "integer",
445 "boolean",
446 "enum",
447 "reserved-24",
448 "reserved-25",
449 "reserved-26",
450 "reserved-27",
451 "reserved-28",
452 "reserved-29",
453 "reserved-2a",
454 "reserved-2b",
455 "reserved-2c",
456 "reserved-2d",
457 "reserved-2e",
458 "reserved-2f",
459 "octetString",
460 "dateTime",
461 "resolution",
462 "rangeOfInteger",
463 "begCollection",
464 "textWithLanguage",
465 "nameWithLanguage",
466 "endCollection",
467 "reserved-38",
468 "reserved-39",
469 "reserved-3a",
470 "reserved-3b",
471 "reserved-3c",
472 "reserved-3d",
473 "reserved-3e",
474 "reserved-3f",
475 "reserved-40",
476 "textWithoutLanguage",
477 "nameWithoutLanguage",
478 "reserved-43",
479 "keyword",
480 "uri",
481 "uriScheme",
482 "charset",
483 "naturalLanguage",
484 "mimeMediaType",
485 "memberName"
486 };
487
488
489 for (group = IPP_TAG_ZERO, attr = ipp->attrs; attr; attr = attr->next)
490 {
491 if (!attr->name && indent == 4)
492 {
493 group = IPP_TAG_ZERO;
494 putchar('\n');
495 continue;
496 }
497
498 if (group != attr->group_tag)
499 {
500 group = attr->group_tag;
501
502 printf("\n%*s%s:\n\n", indent - 4, "", tags[group]);
503 }
504
505 printf("%*s%s (", indent, "", attr->name ? attr->name : "(null)");
506 if (attr->num_values > 1)
507 printf("1setOf ");
508 printf("%s):", tags[attr->value_tag]);
509
510 switch (attr->value_tag)
511 {
512 case IPP_TAG_ENUM :
513 case IPP_TAG_INTEGER :
514 for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
515 printf(" %d", val->integer);
516 putchar('\n');
517 break;
518
519 case IPP_TAG_BOOLEAN :
520 for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
521 printf(" %s", val->boolean ? "true" : "false");
522 putchar('\n');
523 break;
524
525 case IPP_TAG_RANGE :
526 for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
527 printf(" %d-%d", val->range.lower, val->range.upper);
528 putchar('\n');
529 break;
530
531 case IPP_TAG_DATE :
532 {
533 time_t vtime; /* Date/Time value */
534 struct tm *vdate; /* Date info */
535 char vstring[256]; /* Formatted time */
536
537 for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
538 {
539 vtime = ippDateToTime(val->date);
540 vdate = localtime(&vtime);
541 strftime(vstring, sizeof(vstring), "%c", vdate);
542 printf(" (%s)", vstring);
543 }
544 }
545 putchar('\n');
546 break;
547
548 case IPP_TAG_RESOLUTION :
549 for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
550 printf(" %dx%d%s", val->resolution.xres, val->resolution.yres,
551 val->resolution.units == IPP_RES_PER_INCH ? "dpi" : "dpc");
552 putchar('\n');
553 break;
554
555 case IPP_TAG_STRING :
556 case IPP_TAG_TEXTLANG :
557 case IPP_TAG_NAMELANG :
558 case IPP_TAG_TEXT :
559 case IPP_TAG_NAME :
560 case IPP_TAG_KEYWORD :
561 case IPP_TAG_URI :
562 case IPP_TAG_URISCHEME :
563 case IPP_TAG_CHARSET :
564 case IPP_TAG_LANGUAGE :
565 case IPP_TAG_MIMETYPE :
566 for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
567 printf(" \"%s\"", val->string.text);
568 putchar('\n');
569 break;
570
571 case IPP_TAG_BEGIN_COLLECTION :
572 putchar('\n');
573
574 for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++)
575 {
576 if (i)
577 putchar('\n');
578 print_attributes(val->collection, indent + 4);
579 }
580 break;
581
582 default :
583 printf("UNKNOWN (%d values)\n", attr->num_values);
584 break;
585 }
586 }
587 }
588
589
590 /*
591 * 'read_cb()' - Read data from a buffer.
592 */
593
594 ssize_t /* O - Number of bytes read */
595 read_cb(void *data, /* I - Data */
596 ipp_uchar_t *buffer, /* O - Buffer to read */
597 size_t bytes) /* I - Number of bytes to read */
598 {
599 int count; /* Number of bytes */
600
601
602 /*
603 * Copy bytes from the data buffer to the read buffer...
604 */
605
606 for (count = bytes; count > 0 && rpos < wused; count --, rpos ++)
607 *buffer++ = wbuffer[rpos];
608
609 /*
610 * Return the number of bytes read...
611 */
612
613 return (bytes - count);
614 }
615
616
617 /*
618 * 'write_cb()' - Write data into a buffer.
619 */
620
621 ssize_t /* O - Number of bytes written */
622 write_cb(void *data, /* I - Data */
623 ipp_uchar_t *buffer, /* I - Buffer to write */
624 size_t bytes) /* I - Number of bytes to write */
625 {
626 int count; /* Number of bytes */
627
628
629 /*
630 * Loop until all bytes are written...
631 */
632
633 for (count = bytes; count > 0 && wused < sizeof(wbuffer); count --, wused ++)
634 wbuffer[wused] = *buffer++;
635
636 /*
637 * Return the number of bytes written...
638 */
639
640 return (bytes - count);
641 }
642
643
644 /*
645 * End of "$Id: testipp.c 6649 2007-07-11 21:46:42Z mike $".
646 */