void cupsEncodeOptions2( ipp_t *ipp, /* I - Request to add to */ int num_options, /* I - Number of options */ cups_option_t *options, /* I - Options */ ipp_tag_t group_tag) /* I - Group to encode */ { int i, j; /* Looping vars */ int count; /* Number of values */ char *s, /* Pointer into option value */ *val, /* Pointer to option value */ *copy, /* Copy of option value */ *sep, /* Option separator */ quote; /* Quote character */ ipp_attribute_t *attr; /* IPP attribute */ ipp_tag_t value_tag; /* IPP value tag */ cups_option_t *option; /* Current option */ ipp_t *collection; /* Collection value */ int num_cols; /* Number of collection values */ cups_option_t *cols; /* Collection values */ DEBUG_printf(("cupsEncodeOptions2(ipp=%p, num_options=%d, options=%p, " "group_tag=%x)", ipp, num_options, options, group_tag)); /* * Range check input... */ if (!ipp || num_options < 1 || !options) return; /* * Do special handling for the document-format/raw options... */ if (group_tag == IPP_TAG_OPERATION) { /* * Handle the document format stuff first... */ if ((val = (char *)cupsGetOption("document-format", num_options, options)) != NULL) ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, val); else if (cupsGetOption("raw", num_options, options)) ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, "application/vnd.cups-raw"); else ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, "application/octet-stream"); } /* * Then loop through the options... */ for (i = num_options, option = options; i > 0; i --, option ++) { _ipp_option_t *match; /* Matching attribute */ /* * Skip document format options that are handled above... */ if (!_cups_strcasecmp(option->name, "raw") || !_cups_strcasecmp(option->name, "document-format") || !option->name[0]) continue; /* * Figure out the proper value and group tags for this option... */ if ((match = _ippFindOption(option->name)) != NULL) { if (match->group_tag != group_tag) continue; value_tag = match->value_tag; } else { int namelen; /* Length of name */ namelen = (int)strlen(option->name); if (namelen < 9 || strcmp(option->name + namelen - 8, "-default")) { if (group_tag != IPP_TAG_JOB) continue; } else if (group_tag != IPP_TAG_PRINTER) continue; if (!_cups_strcasecmp(option->value, "true") || !_cups_strcasecmp(option->value, "false")) value_tag = IPP_TAG_BOOLEAN; else value_tag = IPP_TAG_NAME; } /* * Count the number of values... */ if (match && match->multivalue) { for (count = 1, sep = option->value, quote = 0; *sep; sep ++) { if (*sep == quote) quote = 0; else if (!quote && (*sep == '\'' || *sep == '\"')) { /* * Skip quoted option value... */ quote = *sep++; } else if (*sep == ',' && !quote) count ++; else if (*sep == '\\' && sep[1]) sep ++; } } else count = 1; DEBUG_printf(("2cupsEncodeOptions2: option=\"%s\", count=%d", option->name, count)); /* * Allocate memory for the attribute values... */ if ((attr = _ippAddAttr(ipp, count)) == NULL) { /* * Ran out of memory! */ DEBUG_puts("1cupsEncodeOptions2: Ran out of memory for attributes!"); return; } /* * Now figure out what type of value we have... */ attr->group_tag = group_tag; attr->value_tag = value_tag; /* * Copy the name over... */ attr->name = _cupsStrAlloc(option->name); if (count > 1) { /* * Make a copy of the value we can fiddle with... */ if ((copy = strdup(option->value)) == NULL) { /* * Ran out of memory! */ DEBUG_puts("1cupsEncodeOptions2: Ran out of memory for value copy!"); ippDeleteAttribute(ipp, attr); return; } val = copy; } else { /* * Since we have a single value, use the value directly... */ val = option->value; copy = NULL; } /* * Scan the value string for values... */ for (j = 0, sep = val; j < count; val = sep, j ++) { /* * Find the end of this value and mark it if needed... */ if (count > 1) { for (quote = 0; *sep; sep ++) { if (*sep == quote) { /* * Finish quoted value... */ quote = 0; } else if (!quote && (*sep == '\'' || *sep == '\"')) { /* * Handle quoted option value... */ quote = *sep; } else if (*sep == ',' && count > 1) break; else if (*sep == '\\' && sep[1]) { /* * Skip quoted character... */ sep ++; } } if (*sep == ',') *sep++ = '\0'; } /* * Copy the option value(s) over as needed by the type... */ switch (attr->value_tag) { case IPP_TAG_INTEGER : case IPP_TAG_ENUM : /* * Integer/enumeration value... */ attr->values[j].integer = strtol(val, &s, 10); DEBUG_printf(("2cupsEncodeOptions2: Added integer option value " "%d...", attr->values[j].integer)); break; case IPP_TAG_BOOLEAN : if (!_cups_strcasecmp(val, "true") || !_cups_strcasecmp(val, "on") || !_cups_strcasecmp(val, "yes")) { /* * Boolean value - true... */ attr->values[j].boolean = 1; DEBUG_puts("2cupsEncodeOptions2: Added boolean true value..."); } else { /* * Boolean value - false... */ attr->values[j].boolean = 0; DEBUG_puts("2cupsEncodeOptions2: Added boolean false value..."); } break; case IPP_TAG_RANGE : /* * Range... */ if (*val == '-') { attr->values[j].range.lower = 1; s = val; } else attr->values[j].range.lower = strtol(val, &s, 10); if (*s == '-') { if (s[1]) attr->values[j].range.upper = strtol(s + 1, NULL, 10); else attr->values[j].range.upper = 2147483647; } else attr->values[j].range.upper = attr->values[j].range.lower; DEBUG_printf(("2cupsEncodeOptions2: Added range option value " "%d-%d...", attr->values[j].range.lower, attr->values[j].range.upper)); break; case IPP_TAG_RESOLUTION : /* * Resolution... */ attr->values[j].resolution.xres = strtol(val, &s, 10); if (*s == 'x') attr->values[j].resolution.yres = strtol(s + 1, &s, 10); else attr->values[j].resolution.yres = attr->values[j].resolution.xres; if (!_cups_strcasecmp(s, "dpc")) attr->values[j].resolution.units = IPP_RES_PER_CM; else attr->values[j].resolution.units = IPP_RES_PER_INCH; DEBUG_printf(("2cupsEncodeOptions2: Added resolution option value " "%s...", val)); break; case IPP_TAG_STRING : /* * octet-string */ attr->values[j].unknown.length = (int)strlen(val); attr->values[j].unknown.data = strdup(val); DEBUG_printf(("2cupsEncodeOptions2: Added octet-string value " "\"%s\"...", (char *)attr->values[j].unknown.data)); break; case IPP_TAG_BEGIN_COLLECTION : /* * Collection value */ num_cols = cupsParseOptions(val, 0, &cols); if ((collection = ippNew()) == NULL) { cupsFreeOptions(num_cols, cols); if (copy) free(copy); ippDeleteAttribute(ipp, attr); return; } attr->values[j].collection = collection; cupsEncodeOptions2(collection, num_cols, cols, IPP_TAG_JOB); cupsFreeOptions(num_cols, cols); break; default : if ((attr->values[j].string.text = _cupsStrAlloc(val)) == NULL) { /* * Ran out of memory! */ DEBUG_puts("1cupsEncodeOptions2: Ran out of memory for string!"); if (copy) free(copy); ippDeleteAttribute(ipp, attr); return; } DEBUG_printf(("2cupsEncodeOptions2: Added string value \"%s\"...", val)); break; } } if (copy) free(copy); } }
int /* O - Exit status */ main(int argc, /* I - Number of command-line arguments */ char *argv[]) /* I - Command-line arguments */ { _ippdata_t data; /* IPP buffer */ ipp_uchar_t buffer[8192]; /* Write buffer data */ ipp_t *cols[2], /* Collections */ *size; /* media-size collection */ ipp_t *request; /* Request */ ipp_attribute_t *media_col, /* media-col attribute */ *media_size, /* media-size attribute */ *attr; /* Other attribute */ ipp_state_t state; /* State */ size_t length; /* Length of data */ cups_file_t *fp; /* File pointer */ size_t i; /* Looping var */ int status; /* Status of tests (0 = success, 1 = fail) */ #ifdef DEBUG const char *name; /* Option name */ #endif /* DEBUG */ status = 0; if (argc == 1) { /* * Test request generation code... */ printf("Create Sample Request: "); request = ippNew(); request->request.op.version[0] = 0x01; request->request.op.version[1] = 0x01; request->request.op.operation_id = IPP_OP_PRINT_JOB; request->request.op.request_id = 1; 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"); cols[0] = ippNew(); size = ippNew(); ippAddInteger(size, IPP_TAG_ZERO, IPP_TAG_INTEGER, "x-dimension", 21590); ippAddInteger(size, IPP_TAG_ZERO, IPP_TAG_INTEGER, "y-dimension", 27940); ippAddCollection(cols[0], IPP_TAG_JOB, "media-size", size); ippDelete(size); 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"); cols[1] = ippNew(); size = ippNew(); ippAddInteger(size, IPP_TAG_ZERO, IPP_TAG_INTEGER, "x-dimension", 21000); ippAddInteger(size, IPP_TAG_ZERO, IPP_TAG_INTEGER, "y-dimension", 29700); ippAddCollection(cols[1], IPP_TAG_JOB, "media-size", size); ippDelete(size); 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"); ippAddCollections(request, IPP_TAG_JOB, "media-col", 2, (const ipp_t **)cols); ippDelete(cols[0]); ippDelete(cols[1]); length = ippLength(request); if (length != sizeof(collection)) { printf("FAIL - wrong ippLength(), %d instead of %d bytes!\n", (int)length, (int)sizeof(collection)); status = 1; } else puts("PASS"); /* * Write test #1... */ printf("Write Sample to Memory: "); data.wused = 0; data.wsize = sizeof(buffer); data.wbuffer = buffer; while ((state = ippWriteIO(&data, (ipp_iocb_t)write_cb, 1, NULL, request)) != IPP_STATE_DATA) if (state == IPP_STATE_ERROR) break; if (state != IPP_STATE_DATA) { printf("FAIL - %d bytes written.\n", (int)data.wused); status = 1; } else if (data.wused != sizeof(collection)) { printf("FAIL - wrote %d bytes, expected %d bytes!\n", (int)data.wused, (int)sizeof(collection)); hex_dump("Bytes Written", data.wbuffer, data.wused); hex_dump("Baseline", collection, sizeof(collection)); status = 1; } else if (memcmp(data.wbuffer, collection, data.wused)) { for (i = 0; i < data.wused; i ++) if (data.wbuffer[i] != collection[i]) break; printf("FAIL - output does not match baseline at 0x%04x!\n", (unsigned)i); hex_dump("Bytes Written", data.wbuffer, data.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(); data.rpos = 0; while ((state = ippReadIO(&data, (ipp_iocb_t)read_cb, 1, NULL, request)) != IPP_STATE_DATA) if (state == IPP_STATE_ERROR) break; length = ippLength(request); if (state != IPP_STATE_DATA) { printf("FAIL - %d bytes read.\n", (int)data.rpos); status = 1; } else if (data.rpos != data.wused) { printf("FAIL - read %d bytes, expected %d bytes!\n", (int)data.rpos, (int)data.wused); print_attributes(request, 8); status = 1; } else if (length != sizeof(collection)) { printf("FAIL - wrong ippLength(), %d instead of %d bytes!\n", (int)length, (int)sizeof(collection)); print_attributes(request, 8); status = 1; } else puts("PASS"); fputs("ippFindAttribute(media-col): ", stdout); if ((media_col = ippFindAttribute(request, "media-col", IPP_TAG_BEGIN_COLLECTION)) == NULL) { if ((media_col = ippFindAttribute(request, "media-col", IPP_TAG_ZERO)) == NULL) puts("FAIL (not found)"); else printf("FAIL (wrong type - %s)\n", ippTagString(media_col->value_tag)); status = 1; } else if (media_col->num_values != 2) { printf("FAIL (wrong count - %d)\n", media_col->num_values); status = 1; } else puts("PASS"); if (media_col) { fputs("ippFindAttribute(media-size 1): ", stdout); if ((media_size = ippFindAttribute(media_col->values[0].collection, "media-size", IPP_TAG_BEGIN_COLLECTION)) == NULL) { if ((media_size = ippFindAttribute(media_col->values[0].collection, "media-col", IPP_TAG_ZERO)) == NULL) puts("FAIL (not found)"); else printf("FAIL (wrong type - %s)\n", ippTagString(media_size->value_tag)); status = 1; } else { if ((attr = ippFindAttribute(media_size->values[0].collection, "x-dimension", IPP_TAG_INTEGER)) == NULL) { if ((attr = ippFindAttribute(media_size->values[0].collection, "x-dimension", IPP_TAG_ZERO)) == NULL) puts("FAIL (missing x-dimension)"); else printf("FAIL (wrong type for x-dimension - %s)\n", ippTagString(attr->value_tag)); status = 1; } else if (attr->values[0].integer != 21590) { printf("FAIL (wrong value for x-dimension - %d)\n", attr->values[0].integer); status = 1; } else if ((attr = ippFindAttribute(media_size->values[0].collection, "y-dimension", IPP_TAG_INTEGER)) == NULL) { if ((attr = ippFindAttribute(media_size->values[0].collection, "y-dimension", IPP_TAG_ZERO)) == NULL) puts("FAIL (missing y-dimension)"); else printf("FAIL (wrong type for y-dimension - %s)\n", ippTagString(attr->value_tag)); status = 1; } else if (attr->values[0].integer != 27940) { printf("FAIL (wrong value for y-dimension - %d)\n", attr->values[0].integer); status = 1; } else puts("PASS"); } fputs("ippFindAttribute(media-size 2): ", stdout); if ((media_size = ippFindAttribute(media_col->values[1].collection, "media-size", IPP_TAG_BEGIN_COLLECTION)) == NULL) { if ((media_size = ippFindAttribute(media_col->values[1].collection, "media-col", IPP_TAG_ZERO)) == NULL) puts("FAIL (not found)"); else printf("FAIL (wrong type - %s)\n", ippTagString(media_size->value_tag)); status = 1; } else { if ((attr = ippFindAttribute(media_size->values[0].collection, "x-dimension", IPP_TAG_INTEGER)) == NULL) { if ((attr = ippFindAttribute(media_size->values[0].collection, "x-dimension", IPP_TAG_ZERO)) == NULL) puts("FAIL (missing x-dimension)"); else printf("FAIL (wrong type for x-dimension - %s)\n", ippTagString(attr->value_tag)); status = 1; } else if (attr->values[0].integer != 21000) { printf("FAIL (wrong value for x-dimension - %d)\n", attr->values[0].integer); status = 1; } else if ((attr = ippFindAttribute(media_size->values[0].collection, "y-dimension", IPP_TAG_INTEGER)) == NULL) { if ((attr = ippFindAttribute(media_size->values[0].collection, "y-dimension", IPP_TAG_ZERO)) == NULL) puts("FAIL (missing y-dimension)"); else printf("FAIL (wrong type for y-dimension - %s)\n", ippTagString(attr->value_tag)); status = 1; } else if (attr->values[0].integer != 29700) { printf("FAIL (wrong value for y-dimension - %d)\n", attr->values[0].integer); status = 1; } else puts("PASS"); } } /* * Test hierarchical find... */ fputs("ippFindAttribute(media-col/media-size/x-dimension): ", stdout); if ((attr = ippFindAttribute(request, "media-col/media-size/x-dimension", IPP_TAG_INTEGER)) != NULL) { if (ippGetInteger(attr, 0) != 21590) { printf("FAIL (wrong value for x-dimension - %d)\n", ippGetInteger(attr, 0)); status = 1; } else puts("PASS"); } else { puts("FAIL (not found)"); status = 1; } fputs("ippFindNextAttribute(media-col/media-size/x-dimension): ", stdout); if ((attr = ippFindNextAttribute(request, "media-col/media-size/x-dimension", IPP_TAG_INTEGER)) != NULL) { if (ippGetInteger(attr, 0) != 21000) { printf("FAIL (wrong value for x-dimension - %d)\n", ippGetInteger(attr, 0)); status = 1; } else puts("PASS"); } else { puts("FAIL (not found)"); status = 1; } fputs("ippFindNextAttribute(media-col/media-size/x-dimension) again: ", stdout); if ((attr = ippFindNextAttribute(request, "media-col/media-size/x-dimension", IPP_TAG_INTEGER)) != NULL) { printf("FAIL (got %d, expected nothing)\n", ippGetInteger(attr, 0)); status = 1; } else puts("PASS"); ippDelete(request); /* * Read the mixed data and confirm we converted everything to rangeOfInteger * values... */ printf("Read Mixed integer/rangeOfInteger from Memory: "); request = ippNew(); data.rpos = 0; data.wused = sizeof(mixed); data.wsize = sizeof(mixed); data.wbuffer = mixed; while ((state = ippReadIO(&data, (ipp_iocb_t)read_cb, 1, NULL, request)) != IPP_STATE_DATA) if (state == IPP_STATE_ERROR) break; length = ippLength(request); if (state != IPP_STATE_DATA) { printf("FAIL - %d bytes read.\n", (int)data.rpos); status = 1; } else if (data.rpos != sizeof(mixed)) { printf("FAIL - read %d bytes, expected %d bytes!\n", (int)data.rpos, (int)sizeof(mixed)); print_attributes(request, 8); status = 1; } else if (length != (sizeof(mixed) + 4)) { printf("FAIL - wrong ippLength(), %d instead of %d bytes!\n", (int)length, (int)sizeof(mixed) + 4); print_attributes(request, 8); status = 1; } else puts("PASS"); fputs("ippFindAttribute(notify-lease-duration-supported): ", stdout); if ((attr = ippFindAttribute(request, "notify-lease-duration-supported", IPP_TAG_ZERO)) == NULL) { puts("FAIL (not found)"); status = 1; } else if (attr->value_tag != IPP_TAG_RANGE) { printf("FAIL (wrong type - %s)\n", ippTagString(attr->value_tag)); status = 1; } else if (attr->num_values != 2) { printf("FAIL (wrong count - %d)\n", attr->num_values); status = 1; } else if (attr->values[0].range.lower != 1 || attr->values[0].range.upper != 1 || attr->values[1].range.lower != 16 || attr->values[1].range.upper != 32) { printf("FAIL (wrong values - %d,%d and %d,%d)\n", attr->values[0].range.lower, attr->values[0].range.upper, attr->values[1].range.lower, attr->values[1].range.upper); status = 1; } else puts("PASS"); ippDelete(request); #ifdef DEBUG /* * Test that private option array is sorted... */ fputs("_ippCheckOptions: ", stdout); if ((name = _ippCheckOptions()) == NULL) puts("PASS"); else { printf("FAIL (\"%s\" out of order)\n", name); status = 1; } #endif /* DEBUG */ /* * Test _ippFindOption() private API... */ fputs("_ippFindOption(\"printer-type\"): ", stdout); if (_ippFindOption("printer-type")) puts("PASS"); else { puts("FAIL"); status = 1; } /* * Summarize... */ putchar('\n'); if (status) puts("Core IPP tests failed."); else puts("Core IPP tests passed."); } else { /* * Read IPP files... */ for (i = 1; i < (size_t)argc; i ++) { if ((fp = cupsFileOpen(argv[i], "r")) == NULL) { printf("Unable to open \"%s\" - %s\n", argv[i], strerror(errno)); status = 1; continue; } request = ippNew(); while ((state = ippReadIO(fp, (ipp_iocb_t)cupsFileRead, 1, NULL, request)) == IPP_STATE_ATTRIBUTE); if (state != IPP_STATE_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); cupsFileClose(fp); } } return (status); }