Index: ipp.c =================================================================== --- ipp.c (revision 4650) +++ ipp.c (working copy) @@ -1010,6 +1010,10 @@ if (attr->value_tag == IPP_TAG_ZERO) { + /* + * Setting the value of a collection member... + */ + attr->value_tag = tag; } else if (attr->value_tag == IPP_TAG_STRING || @@ -1045,22 +1049,25 @@ */ if ((temp = realloc(attr, sizeof(ipp_attribute_t) + - (attr->num_values + IPP_MAX_VALUES - 1) * + (attr->num_values + IPP_MAX_VALUES) * sizeof(ipp_value_t))) == NULL) return (IPP_ERROR); - /* - * Reset pointers in the list... - */ + if (temp != attr) + { + /* + * Reset pointers in the list... + */ - for (ptr = ipp->attrs; ptr && ptr->next != attr; ptr = ptr->next); + for (ptr = ipp->attrs; ptr && ptr->next != attr; ptr = ptr->next); - if (ptr) - ptr->next = temp; - else - ipp->attrs = temp; + if (ptr) + ptr->next = temp; + else + ipp->attrs = temp; - attr = ipp->current = ipp->last = temp; + attr = ipp->current = ipp->last = temp; + } } } else if (tag == IPP_TAG_MEMBERNAME) @@ -1271,8 +1278,8 @@ case IPP_TAG_MEMBERNAME : /* - * The value the name of the member in the collection, which - * we need to carry over... + * The value is the name of the member in the collection, + * which we need to carry over... */ attr->name = calloc(n + 1, 1); @@ -1283,6 +1290,14 @@ return (IPP_ERROR); } + /* + * Since collection members are encoded differently than + * regular attributes, make sure we don't start with an + * empty value... + */ + + attr->num_values --; + DEBUG_printf(("ippReadIO: member name = \"%s\"\n", attr->name)); break; Index: testipp.c =================================================================== --- testipp.c (revision 4650) +++ testipp.c (working copy) @@ -57,13 +57,16 @@ 0x01, 0x01, /* IPP version */ 0x00, 0x02, /* Print-Job operation */ 0x00, 0x00, 0x00, 0x01, /* Request ID */ + IPP_TAG_OPERATION, + IPP_TAG_CHARSET, 0x00, 0x12, /* Name length + name */ 'a','t','t','r','i','b','u','t','e','s','-', 'c','h','a','r','s','e','t', 0x00, 0x05, /* Value length + value */ 'u','t','f','-','8', + IPP_TAG_LANGUAGE, 0x00, 0x1b, /* Name length + name */ 'a','t','t','r','i','b','u','t','e','s','-', @@ -71,6 +74,7 @@ 'g','u','a','g','e', 0x00, 0x02, /* Value length + value */ 'e','n', + IPP_TAG_URI, 0x00, 0x0b, /* Name length + name */ 'p','r','i','n','t','e','r','-','u','r','i', @@ -78,22 +82,58 @@ 'i','p','p',':','/','/','l','o','c','a','l', 'h','o','s','t','/','p','r','i','n','t','e', 'r','s','/','f','o','o', + IPP_TAG_JOB, /* job group tag */ + IPP_TAG_BEGIN_COLLECTION, /* begCollection tag */ 0x00, 0x09, /* Name length + name */ 'm', 'e', 'd', 'i', 'a', '-', 'c', 'o', 'l', 0x00, 0x00, /* No value */ - IPP_TAG_MEMBERNAME, /* memberAttrName tag */ + IPP_TAG_MEMBERNAME, /* memberAttrName tag */ + 0x00, 0x00, /* No name */ + 0x00, 0x0b, /* Value length + value */ + 'm', 'e', 'd', 'i', 'a', '-', 'c', 'o', 'l', 'o', 'r', + IPP_TAG_KEYWORD, /* keyword tag */ + 0x00, 0x00, /* No name */ + 0x00, 0x04, /* Value length + value */ + 'b', 'l', 'u', 'e', + + IPP_TAG_MEMBERNAME, /* memberAttrName tag */ + 0x00, 0x00, /* No name */ + 0x00, 0x0a, /* Value length + value */ + 'm', 'e', 'd', 'i', 'a', '-', 't', 'y', 'p', 'e', + IPP_TAG_KEYWORD, /* keyword tag */ + 0x00, 0x00, /* No name */ + 0x00, 0x05, /* Value length + value */ + 'p', 'l', 'a', 'i', 'n', + IPP_TAG_END_COLLECTION, /* endCollection tag */ 0x00, 0x00, /* No name */ - 0x00, 0x0b, /* Value length + value */ - 'm', 'e', 'd', 'i', 'a', '-', 'c', 'o', 'l', 'o', 'r', - IPP_TAG_KEYWORD, /* keyword tag */ + 0x00, 0x00, /* No value */ + + IPP_TAG_BEGIN_COLLECTION, /* begCollection tag */ 0x00, 0x00, /* No name */ - 0x00, 0x04, /* Value length + value */ - 'b', 'l', 'u', 'e', + 0x00, 0x00, /* No value */ + IPP_TAG_MEMBERNAME, /* memberAttrName tag */ + 0x00, 0x00, /* No name */ + 0x00, 0x0b, /* Value length + value */ + 'm', 'e', 'd', 'i', 'a', '-', 'c', 'o', 'l', 'o', 'r', + IPP_TAG_KEYWORD, /* keyword tag */ + 0x00, 0x00, /* No name */ + 0x00, 0x05, /* Value length + value */ + 'p', 'l', 'a', 'i', 'd', + + IPP_TAG_MEMBERNAME, /* memberAttrName tag */ + 0x00, 0x00, /* No name */ + 0x00, 0x0a, /* Value length + value */ + 'm', 'e', 'd', 'i', 'a', '-', 't', 'y', 'p', 'e', + IPP_TAG_KEYWORD, /* keyword tag */ + 0x00, 0x00, /* No name */ + 0x00, 0x06, /* Value length + value */ + 'g', 'l', 'o', 's', 's', 'y', IPP_TAG_END_COLLECTION, /* endCollection tag */ 0x00, 0x00, /* No name */ 0x00, 0x00, /* No value */ + IPP_TAG_END /* end tag */ }; @@ -102,7 +142,7 @@ * Local functions... */ -void hex_dump(ipp_uchar_t *buffer, int bytes); +void hex_dump(const char *title, ipp_uchar_t *buffer, int bytes); void print_attributes(ipp_t *ipp, int indent); int read_cb(void *data, ipp_uchar_t *buffer, int bytes); int write_cb(void *data, ipp_uchar_t *buffer, int bytes); @@ -116,99 +156,178 @@ main(int argc, /* I - Number of command-line arguments */ char *argv[]) /* I - Command-line arguments */ { - ipp_t *col; /* Collection */ + ipp_t *cols[2]; /* Collections */ ipp_t *request; /* Request */ ipp_state_t state; /* State */ int length; /* Length of data */ int fd; /* File descriptor */ int i; /* Looping var */ + int status; /* Status of tests (0 = success, 1 = fail) */ - request = ippNew(); - request->request.op.version[0] = 0x01; - request->request.op.version[1] = 0x01; - request->request.op.operation_id = IPP_PRINT_JOB; - request->request.op.request_id = 1; + status = 0; - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, - "attributes-charset", NULL, "utf-8"); - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, - "attributes-natural-language", NULL, "en"); - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, - "printer-uri", NULL, "ipp://localhost/printers/foo"); + if (argc == 1) + { + /* + * Test request generation code... + */ - col = ippNew(); - ippAddString(col, IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-color", NULL, "blue"); - ippAddCollection(request, IPP_TAG_JOB, "media-col", col); + printf("Create Sample Request: "); - length = ippLength(request); - if (length != sizeof(collection)) - printf("ERROR ippLength didn't compute the correct length (%d instead of %d bytes!)\n", - length, sizeof(collection)); + request = ippNew(); + request->request.op.version[0] = 0x01; + request->request.op.version[1] = 0x01; + request->request.op.operation_id = IPP_PRINT_JOB; + request->request.op.request_id = 1; - wused = 0; - while ((state = ippWriteIO(wbuffer, write_cb, 1, NULL, request)) != IPP_DATA) - if (state == IPP_ERROR) - break; + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, "utf-8"); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, "en"); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, + "printer-uri", NULL, "ipp://localhost/printers/foo"); - if (state != IPP_DATA) - puts("ERROR writing collection attribute!"); + cols[0] = ippNew(); + ippAddString(cols[0], IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-color", NULL, "blue"); + ippAddString(cols[0], IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-type", NULL, "plain"); - printf("%d bytes written:\n", wused); - hex_dump(wbuffer, wused); + cols[1] = ippNew(); + ippAddString(cols[1], IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-color", NULL, "plaid"); + ippAddString(cols[1], IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-type", NULL, "glossy"); - if (wused != sizeof(collection)) - { - printf("ERROR expected %d bytes!\n", sizeof(collection)); - hex_dump(collection, sizeof(collection)); - } - else if (memcmp(wbuffer, collection, wused)) - { - puts("ERROR output does not match baseline!"); - hex_dump(collection, sizeof(collection)); - } + ippAddCollections(request, IPP_TAG_JOB, "media-col", 2, (const ipp_t **)cols); - ippDelete(col); - ippDelete(request); + length = ippLength(request); + if (length != sizeof(collection)) + { + printf("FAIL - wrong ippLength(), %d instead of %d bytes!\n", + length, sizeof(collection)); + status = 1; + } + else + puts("PASS"); - request = ippNew(); - rpos = 0; + /* + * Write test #1... + */ - while ((state = ippReadIO(wbuffer, read_cb, 1, NULL, request)) != IPP_DATA) - if (state == IPP_ERROR) - break; + printf("Write Sample to Memory: "); - if (state != IPP_DATA) - puts("ERROR reading collection attribute!"); + wused = 0; + while ((state = ippWriteIO(wbuffer, write_cb, 1, NULL, request)) != IPP_DATA) + if (state == IPP_ERROR) + break; - printf("%d bytes read.\n", rpos); - - puts("Core IPP tests passed."); - - for (i = 1; i < argc; i ++) - { - if ((fd = open(argv[i], O_RDONLY)) < 0) + if (state != IPP_DATA) { - printf("Unable to open \"%s\" - %s\n", argv[i], strerror(errno)); - continue; + printf("FAIL - %d bytes written.\n", wused); + status = 1; } + else if (wused != sizeof(collection)) + { + printf("FAIL - wrote %d bytes, expected %d bytes!\n", wused, + sizeof(collection)); + hex_dump("Bytes Written", wbuffer, wused); + hex_dump("Baseline", collection, sizeof(collection)); + status = 1; + } + else if (memcmp(wbuffer, collection, wused)) + { + puts("FAIL - output does not match baseline!"); + hex_dump("Bytes Written", wbuffer, wused); + hex_dump("Baseline", collection, sizeof(collection)); + status = 1; + } + else + puts("PASS"); + ippDelete(request); + + /* + * Read the data back in and confirm... + */ + + printf("Read Sample from Memory: "); + request = ippNew(); - while ((state = ippReadFile(fd, request)) == IPP_ATTRIBUTE); + rpos = 0; + while ((state = ippReadIO(wbuffer, read_cb, 1, NULL, request)) != IPP_DATA) + if (state == IPP_ERROR) + break; + + length = ippLength(request); + if (state != IPP_DATA) - printf("Error reading IPP message from \"%s\"!\n", argv[i]); - else { - printf("\n%s:\n", argv[i]); - print_attributes(request, 4); + printf("FAIL - %d bytes read.\n", rpos); + status = 1; } + else if (rpos != wused) + { + printf("FAIL - read %d bytes, expected %d bytes!\n", rpos, wused); + print_attributes(request, 8); + status = 1; + } + else if (length != sizeof(collection)) + { + printf("FAIL - wrong ippLength(), %d instead of %d bytes!\n", + length, sizeof(collection)); + print_attributes(request, 8); + status = 1; + } + else + puts("PASS"); ippDelete(request); - close(fd); + + /* + * Summarize... + */ + + putchar('\n'); + + if (status) + puts("Core IPP tests failed."); + else + puts("Core IPP tests passed."); } + else + { + /* + * Read IPP files... + */ - return (0); + for (i = 1; i < argc; i ++) + { + if ((fd = open(argv[i], O_RDONLY)) < 0) + { + printf("Unable to open \"%s\" - %s\n", argv[i], strerror(errno)); + status = 1; + continue; + } + + request = ippNew(); + while ((state = ippReadFile(fd, request)) == IPP_ATTRIBUTE); + + if (state != IPP_DATA) + { + printf("Error reading IPP message from \"%s\"!\n", argv[i]); + status = 1; + } + else + { + printf("\n%s:\n", argv[i]); + print_attributes(request, 4); + } + + ippDelete(request); + close(fd); + } + } + + return (status); } @@ -217,7 +336,8 @@ */ void -hex_dump(ipp_uchar_t *buffer, /* I - Buffer to dump */ +hex_dump(const char *title, /* I - Title */ + ipp_uchar_t *buffer, /* I - Buffer to dump */ int bytes) /* I - Number of bytes */ { int i, j; /* Looping vars */ @@ -228,13 +348,15 @@ * Show lines of 16 bytes at a time... */ + printf(" %s:\n", title); + for (i = 0; i < bytes; i += 16) { /* * Show the offset... */ - printf("%04x ", i); + printf(" %04x ", i); /* * Then up to 16 bytes in hex... @@ -362,7 +484,7 @@ for (group = IPP_TAG_ZERO, attr = ipp->attrs; attr; attr = attr->next) { - if (attr->group_tag == IPP_TAG_ZERO || !attr->name) + if ((attr->group_tag == IPP_TAG_ZERO && indent <= 8) || !attr->name) { group = IPP_TAG_ZERO; putchar('\n'); @@ -374,7 +496,7 @@ group = attr->group_tag; putchar('\n'); - for (i = 2; i < indent; i ++) + for (i = 4; i < indent; i ++) putchar(' '); printf("%s:\n\n", tags[group]); @@ -383,7 +505,10 @@ for (i = 0; i < indent; i ++) putchar(' '); - printf("%s (%s):", attr->name, tags[attr->value_tag]); + printf("%s (", attr->name); + if (attr->num_values > 1) + printf("1setOf "); + printf("%s):", tags[attr->value_tag]); switch (attr->value_tag) { @@ -450,14 +575,17 @@ putchar('\n'); for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) + { + if (i) + putchar('\n'); print_attributes(val->collection, indent + 4); + } break; default : - putchar('\n'); + printf("UNKNOWN (%d values)\n", attr->num_values); break; } - } }