Revert manifest to default one
[external/cups.git] / cups / encode.c
1 /*
2  * "$Id: encode.c 9793 2011-05-20 03:49:49Z mike $"
3  *
4  *   Option encoding routines for CUPS.
5  *
6  *   Copyright 2007-2011 by Apple Inc.
7  *   Copyright 1997-2007 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  *   cupsEncodeOptions()   - Encode printer options into IPP attributes.
20  *   cupsEncodeOptions2()  - Encode printer options into IPP attributes for
21  *                           a group.
22  *   _ippFindOption()      - Find the attribute information for an option.
23  *   compare_ipp_options() - Compare two IPP options.
24  */
25
26 /*
27  * Include necessary headers...
28  */
29
30 #include "cups-private.h"
31
32
33 /*
34  * Local list of option names and the value tags they should use...
35  *
36  * **** THIS LIST MUST BE SORTED ****
37  */
38
39 static const _ipp_option_t ipp_options[] =
40 {
41   { 1, "auth-info",             IPP_TAG_TEXT,           IPP_TAG_JOB },
42   { 1, "auth-info-required",    IPP_TAG_KEYWORD,        IPP_TAG_PRINTER },
43   { 0, "blackplot",             IPP_TAG_BOOLEAN,        IPP_TAG_JOB },
44   { 0, "blackplot-default",     IPP_TAG_BOOLEAN,        IPP_TAG_PRINTER },
45   { 0, "brightness",            IPP_TAG_INTEGER,        IPP_TAG_JOB },
46   { 0, "brightness-default",    IPP_TAG_INTEGER,        IPP_TAG_PRINTER },
47   { 0, "columns",               IPP_TAG_INTEGER,        IPP_TAG_JOB },
48   { 0, "columns-default",       IPP_TAG_INTEGER,        IPP_TAG_PRINTER },
49   { 0, "compression",           IPP_TAG_KEYWORD,        IPP_TAG_OPERATION },
50   { 0, "copies",                IPP_TAG_INTEGER,        IPP_TAG_JOB },
51   { 0, "copies-default",        IPP_TAG_INTEGER,        IPP_TAG_PRINTER },
52   { 0, "device-uri",            IPP_TAG_URI,            IPP_TAG_PRINTER },
53   { 0, "document-format",       IPP_TAG_MIMETYPE,       IPP_TAG_OPERATION },
54   { 0, "document-format-default", IPP_TAG_MIMETYPE,     IPP_TAG_PRINTER },
55   { 1, "exclude-schemes",       IPP_TAG_NAME,           IPP_TAG_OPERATION },
56   { 1, "finishings",            IPP_TAG_ENUM,           IPP_TAG_JOB },
57   { 1, "finishings-default",    IPP_TAG_ENUM,           IPP_TAG_PRINTER },
58   { 0, "fit-to-page",           IPP_TAG_BOOLEAN,        IPP_TAG_JOB },
59   { 0, "fit-to-page-default",   IPP_TAG_BOOLEAN,        IPP_TAG_PRINTER },
60   { 0, "fitplot",               IPP_TAG_BOOLEAN,        IPP_TAG_JOB },
61   { 0, "fitplot-default",       IPP_TAG_BOOLEAN,        IPP_TAG_PRINTER },
62   { 0, "gamma",                 IPP_TAG_INTEGER,        IPP_TAG_JOB },
63   { 0, "gamma-default",         IPP_TAG_INTEGER,        IPP_TAG_PRINTER },
64   { 0, "hue",                   IPP_TAG_INTEGER,        IPP_TAG_JOB },
65   { 0, "hue-default",           IPP_TAG_INTEGER,        IPP_TAG_PRINTER },
66   { 1, "include-schemes",       IPP_TAG_NAME,           IPP_TAG_OPERATION },
67   { 0, "job-impressions",       IPP_TAG_INTEGER,        IPP_TAG_JOB },
68   { 0, "job-k-limit",           IPP_TAG_INTEGER,        IPP_TAG_PRINTER },
69   { 0, "job-page-limit",        IPP_TAG_INTEGER,        IPP_TAG_PRINTER },
70   { 0, "job-priority",          IPP_TAG_INTEGER,        IPP_TAG_JOB },
71   { 0, "job-quota-period",      IPP_TAG_INTEGER,        IPP_TAG_PRINTER },
72   { 1, "job-sheets",            IPP_TAG_NAME,           IPP_TAG_JOB },
73   { 1, "job-sheets-default",    IPP_TAG_NAME,           IPP_TAG_PRINTER },
74   { 0, "job-uuid",              IPP_TAG_URI,            IPP_TAG_JOB },
75   { 0, "landscape",             IPP_TAG_BOOLEAN,        IPP_TAG_JOB },
76   { 1, "marker-change-time",    IPP_TAG_INTEGER,        IPP_TAG_PRINTER },
77   { 1, "marker-colors",         IPP_TAG_NAME,           IPP_TAG_PRINTER },
78   { 1, "marker-high-levels",    IPP_TAG_INTEGER,        IPP_TAG_PRINTER },
79   { 1, "marker-levels",         IPP_TAG_INTEGER,        IPP_TAG_PRINTER },
80   { 1, "marker-low-levels",     IPP_TAG_INTEGER,        IPP_TAG_PRINTER },
81   { 0, "marker-message",        IPP_TAG_TEXT,           IPP_TAG_PRINTER },
82   { 1, "marker-names",          IPP_TAG_NAME,           IPP_TAG_PRINTER },
83   { 1, "marker-types",          IPP_TAG_KEYWORD,        IPP_TAG_PRINTER },
84   { 1, "media",                 IPP_TAG_KEYWORD,        IPP_TAG_JOB },
85   { 0, "media-col",             IPP_TAG_BEGIN_COLLECTION, IPP_TAG_JOB },
86   { 0, "media-col-default",     IPP_TAG_BEGIN_COLLECTION, IPP_TAG_PRINTER },
87   { 0, "media-color",           IPP_TAG_KEYWORD,        IPP_TAG_JOB },
88   { 1, "media-default",         IPP_TAG_KEYWORD,        IPP_TAG_PRINTER },
89   { 0, "media-key",             IPP_TAG_KEYWORD,        IPP_TAG_JOB },
90   { 0, "media-size",            IPP_TAG_BEGIN_COLLECTION, IPP_TAG_JOB },
91   { 0, "media-type",            IPP_TAG_KEYWORD,        IPP_TAG_JOB },
92   { 0, "mirror",                IPP_TAG_BOOLEAN,        IPP_TAG_JOB },
93   { 0, "mirror-default",        IPP_TAG_BOOLEAN,        IPP_TAG_PRINTER },
94   { 0, "natural-scaling",       IPP_TAG_INTEGER,        IPP_TAG_JOB },
95   { 0, "natural-scaling-default", IPP_TAG_INTEGER,      IPP_TAG_PRINTER },
96   { 0, "notify-charset",        IPP_TAG_CHARSET,        IPP_TAG_SUBSCRIPTION },
97   { 1, "notify-events",         IPP_TAG_KEYWORD,        IPP_TAG_SUBSCRIPTION },
98   { 1, "notify-events-default", IPP_TAG_KEYWORD,        IPP_TAG_PRINTER },
99   { 0, "notify-lease-duration", IPP_TAG_INTEGER,        IPP_TAG_SUBSCRIPTION },
100   { 0, "notify-lease-duration-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER },
101   { 0, "notify-natural-language", IPP_TAG_LANGUAGE,     IPP_TAG_SUBSCRIPTION },
102   { 0, "notify-pull-method",    IPP_TAG_KEYWORD,        IPP_TAG_SUBSCRIPTION },
103   { 0, "notify-recipient-uri",  IPP_TAG_URI,            IPP_TAG_SUBSCRIPTION },
104   { 0, "notify-time-interval",  IPP_TAG_INTEGER,        IPP_TAG_SUBSCRIPTION },
105   { 0, "notify-user-data",      IPP_TAG_STRING,         IPP_TAG_SUBSCRIPTION },
106   { 0, "number-up",             IPP_TAG_INTEGER,        IPP_TAG_JOB },
107   { 0, "number-up-default",     IPP_TAG_INTEGER,        IPP_TAG_PRINTER },
108   { 0, "orientation-requested", IPP_TAG_ENUM,           IPP_TAG_JOB },
109   { 0, "orientation-requested-default", IPP_TAG_ENUM,   IPP_TAG_PRINTER },
110   { 0, "page-bottom",           IPP_TAG_INTEGER,        IPP_TAG_JOB },
111   { 0, "page-bottom-default",   IPP_TAG_INTEGER,        IPP_TAG_PRINTER },
112   { 0, "page-left",             IPP_TAG_INTEGER,        IPP_TAG_JOB },
113   { 0, "page-left-default",     IPP_TAG_INTEGER,        IPP_TAG_PRINTER },
114   { 1, "page-ranges",           IPP_TAG_RANGE,          IPP_TAG_JOB },
115   { 1, "page-ranges-default",   IPP_TAG_RANGE,          IPP_TAG_PRINTER },
116   { 0, "page-right",            IPP_TAG_INTEGER,        IPP_TAG_JOB },
117   { 0, "page-right-default",    IPP_TAG_INTEGER,        IPP_TAG_PRINTER },
118   { 0, "page-top",              IPP_TAG_INTEGER,        IPP_TAG_JOB },
119   { 0, "page-top-default",      IPP_TAG_INTEGER,        IPP_TAG_PRINTER },
120   { 0, "penwidth",              IPP_TAG_INTEGER,        IPP_TAG_JOB },
121   { 0, "penwidth-default",      IPP_TAG_INTEGER,        IPP_TAG_PRINTER },
122   { 0, "port-monitor",          IPP_TAG_NAME,           IPP_TAG_PRINTER },
123   { 0, "ppd-name",              IPP_TAG_NAME,           IPP_TAG_PRINTER },
124   { 0, "ppi",                   IPP_TAG_INTEGER,        IPP_TAG_JOB },
125   { 0, "ppi-default",           IPP_TAG_INTEGER,        IPP_TAG_PRINTER },
126   { 0, "prettyprint",           IPP_TAG_BOOLEAN,        IPP_TAG_JOB },
127   { 0, "prettyprint-default",   IPP_TAG_BOOLEAN,        IPP_TAG_PRINTER },
128   { 0, "print-quality",         IPP_TAG_ENUM,           IPP_TAG_JOB },
129   { 0, "print-quality-default", IPP_TAG_ENUM,           IPP_TAG_PRINTER },
130   { 1, "printer-commands",      IPP_TAG_KEYWORD,        IPP_TAG_PRINTER },
131   { 0, "printer-error-policy",  IPP_TAG_NAME,           IPP_TAG_PRINTER },
132   { 0, "printer-info",          IPP_TAG_TEXT,           IPP_TAG_PRINTER },
133   { 0, "printer-is-accepting-jobs", IPP_TAG_BOOLEAN,    IPP_TAG_PRINTER },
134   { 0, "printer-is-shared",     IPP_TAG_BOOLEAN,        IPP_TAG_PRINTER },
135   { 0, "printer-location",      IPP_TAG_TEXT,           IPP_TAG_PRINTER },
136   { 0, "printer-make-and-model", IPP_TAG_TEXT,          IPP_TAG_PRINTER },
137   { 0, "printer-more-info",     IPP_TAG_URI,            IPP_TAG_PRINTER },
138   { 0, "printer-op-policy",     IPP_TAG_NAME,           IPP_TAG_PRINTER },
139   { 0, "printer-resolution",    IPP_TAG_RESOLUTION,     IPP_TAG_JOB },
140   { 0, "printer-state",         IPP_TAG_ENUM,           IPP_TAG_PRINTER },
141   { 0, "printer-state-change-time", IPP_TAG_INTEGER,    IPP_TAG_PRINTER },
142   { 1, "printer-state-reasons", IPP_TAG_KEYWORD,        IPP_TAG_PRINTER },
143   { 0, "printer-type",          IPP_TAG_ENUM,           IPP_TAG_PRINTER },
144   { 0, "printer-uri",           IPP_TAG_URI,            IPP_TAG_OPERATION },
145   { 1, "printer-uri-supported", IPP_TAG_URI,            IPP_TAG_PRINTER },
146   { 0, "queued-job-count",      IPP_TAG_INTEGER,        IPP_TAG_PRINTER },
147   { 0, "raw",                   IPP_TAG_MIMETYPE,       IPP_TAG_OPERATION },
148   { 1, "requested-attributes",  IPP_TAG_NAME,           IPP_TAG_OPERATION },
149   { 1, "requesting-user-name-allowed", IPP_TAG_NAME,    IPP_TAG_PRINTER },
150   { 1, "requesting-user-name-denied", IPP_TAG_NAME,     IPP_TAG_PRINTER },
151   { 0, "resolution",            IPP_TAG_RESOLUTION,     IPP_TAG_JOB },
152   { 0, "resolution-default",    IPP_TAG_RESOLUTION,     IPP_TAG_PRINTER },
153   { 0, "saturation",            IPP_TAG_INTEGER,        IPP_TAG_JOB },
154   { 0, "saturation-default",    IPP_TAG_INTEGER,        IPP_TAG_PRINTER },
155   { 0, "scaling",               IPP_TAG_INTEGER,        IPP_TAG_JOB },
156   { 0, "scaling-default",       IPP_TAG_INTEGER,        IPP_TAG_PRINTER },
157   { 0, "sides",                 IPP_TAG_KEYWORD,        IPP_TAG_JOB },
158   { 0, "sides-default",         IPP_TAG_KEYWORD,        IPP_TAG_PRINTER },
159   { 0, "wrap",                  IPP_TAG_BOOLEAN,        IPP_TAG_JOB },
160   { 0, "wrap-default",          IPP_TAG_BOOLEAN,        IPP_TAG_PRINTER },
161   { 0, "x-dimension",           IPP_TAG_INTEGER,        IPP_TAG_JOB },
162   { 0, "y-dimension",           IPP_TAG_INTEGER,        IPP_TAG_JOB }
163 };
164
165
166 /*
167  * Local functions...
168  */
169
170 static int      compare_ipp_options(_ipp_option_t *a, _ipp_option_t *b);
171
172
173 /*
174  * 'cupsEncodeOptions()' - Encode printer options into IPP attributes.
175  *
176  * This function adds operation, job, and then subscription attributes,
177  * in that order. Use the cupsEncodeOptions2() function to add attributes
178  * for a single group.
179  */
180
181 void
182 cupsEncodeOptions(ipp_t         *ipp,           /* I - Request to add to */
183                   int           num_options,    /* I - Number of options */
184                   cups_option_t *options)       /* I - Options */
185 {
186   DEBUG_printf(("cupsEncodeOptions(%p, %d, %p)", ipp, num_options, options));
187
188  /*
189   * Add the options in the proper groups & order...
190   */
191
192   cupsEncodeOptions2(ipp, num_options, options, IPP_TAG_OPERATION);
193   cupsEncodeOptions2(ipp, num_options, options, IPP_TAG_JOB);
194   cupsEncodeOptions2(ipp, num_options, options, IPP_TAG_SUBSCRIPTION);
195 }
196
197
198 /*
199  * 'cupsEncodeOptions2()' - Encode printer options into IPP attributes for a group.
200  *
201  * This function only adds attributes for a single group. Call this
202  * function multiple times for each group, or use cupsEncodeOptions()
203  * to add the standard groups.
204  *
205  * @since CUPS 1.2/Mac OS X 10.5@
206  */
207
208 void
209 cupsEncodeOptions2(
210     ipp_t         *ipp,                 /* I - Request to add to */
211     int           num_options,          /* I - Number of options */
212     cups_option_t *options,             /* I - Options */
213     ipp_tag_t     group_tag)            /* I - Group to encode */
214 {
215   int           i, j;                   /* Looping vars */
216   int           count;                  /* Number of values */
217   char          *s,                     /* Pointer into option value */
218                 *val,                   /* Pointer to option value */
219                 *copy,                  /* Copy of option value */
220                 *sep,                   /* Option separator */
221                 quote;                  /* Quote character */
222   ipp_attribute_t *attr;                /* IPP attribute */
223   ipp_tag_t     value_tag;              /* IPP value tag */
224   cups_option_t *option;                /* Current option */
225   ipp_t         *collection;            /* Collection value */
226   int           num_cols;               /* Number of collection values */
227   cups_option_t *cols;                  /* Collection values */
228
229
230   DEBUG_printf(("cupsEncodeOptions2(ipp=%p, num_options=%d, options=%p, "
231                 "group_tag=%x)", ipp, num_options, options, group_tag));
232
233  /*
234   * Range check input...
235   */
236
237   if (!ipp || num_options < 1 || !options)
238     return;
239
240  /*
241   * Do special handling for the document-format/raw options...
242   */
243
244   if (group_tag == IPP_TAG_OPERATION)
245   {
246    /*
247     * Handle the document format stuff first...
248     */
249
250     if ((val = (char *)cupsGetOption("document-format", num_options, options)) != NULL)
251       ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format",
252                    NULL, val);
253     else if (cupsGetOption("raw", num_options, options))
254       ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format",
255                    NULL, "application/vnd.cups-raw");
256     else
257       ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format",
258                    NULL, "application/octet-stream");
259   }
260
261  /*
262   * Then loop through the options...
263   */
264
265   for (i = num_options, option = options; i > 0; i --, option ++)
266   {
267     _ipp_option_t       *match;         /* Matching attribute */
268
269
270    /*
271     * Skip document format options that are handled above...
272     */
273
274     if (!_cups_strcasecmp(option->name, "raw") ||
275         !_cups_strcasecmp(option->name, "document-format") ||
276         !option->name[0])
277       continue;
278
279    /*
280     * Figure out the proper value and group tags for this option...
281     */
282
283     if ((match = _ippFindOption(option->name)) != NULL)
284     {
285       if (match->group_tag != group_tag)
286         continue;
287
288       value_tag = match->value_tag;
289     }
290     else
291     {
292       int       namelen;                /* Length of name */
293
294
295       namelen = (int)strlen(option->name);
296
297       if (namelen < 9 || strcmp(option->name + namelen - 8, "-default"))
298       {
299         if (group_tag != IPP_TAG_JOB)
300           continue;
301       }
302       else if (group_tag != IPP_TAG_PRINTER)
303         continue;
304
305       if (!_cups_strcasecmp(option->value, "true") ||
306           !_cups_strcasecmp(option->value, "false"))
307         value_tag = IPP_TAG_BOOLEAN;
308       else
309         value_tag = IPP_TAG_NAME;
310     }
311
312    /*
313     * Count the number of values...
314     */
315
316     if (match && match->multivalue)
317     {
318       for (count = 1, sep = option->value, quote = 0; *sep; sep ++)
319       {
320         if (*sep == quote)
321           quote = 0;
322         else if (!quote && (*sep == '\'' || *sep == '\"'))
323         {
324          /*
325           * Skip quoted option value...
326           */
327
328           quote = *sep++;
329         }
330         else if (*sep == ',' && !quote)
331           count ++;
332         else if (*sep == '\\' && sep[1])
333           sep ++;
334       }
335     }
336     else
337       count = 1;
338
339     DEBUG_printf(("2cupsEncodeOptions2: option=\"%s\", count=%d",
340                   option->name, count));
341
342    /*
343     * Allocate memory for the attribute values...
344     */
345
346     if ((attr = _ippAddAttr(ipp, count)) == NULL)
347     {
348      /*
349       * Ran out of memory!
350       */
351
352       DEBUG_puts("1cupsEncodeOptions2: Ran out of memory for attributes!");
353       return;
354     }
355
356    /*
357     * Now figure out what type of value we have...
358     */
359
360     attr->group_tag = group_tag;
361     attr->value_tag = value_tag;
362
363    /*
364     * Copy the name over...
365     */
366
367     attr->name = _cupsStrAlloc(option->name);
368
369     if (count > 1)
370     {
371      /*
372       * Make a copy of the value we can fiddle with...
373       */
374
375       if ((copy = strdup(option->value)) == NULL)
376       {
377        /*
378         * Ran out of memory!
379         */
380
381         DEBUG_puts("1cupsEncodeOptions2: Ran out of memory for value copy!");
382         ippDeleteAttribute(ipp, attr);
383         return;
384       }
385
386       val = copy;
387     }
388     else
389     {
390      /*
391       * Since we have a single value, use the value directly...
392       */
393
394       val  = option->value;
395       copy = NULL;
396     }
397
398    /*
399     * Scan the value string for values...
400     */
401
402     for (j = 0, sep = val; j < count; val = sep, j ++)
403     {
404      /*
405       * Find the end of this value and mark it if needed...
406       */
407
408       if (count > 1)
409       {
410         for (quote = 0; *sep; sep ++)
411         {
412           if (*sep == quote)
413           {
414            /*
415             * Finish quoted value...
416             */
417
418             quote = 0;
419           }
420           else if (!quote && (*sep == '\'' || *sep == '\"'))
421           {
422            /*
423             * Handle quoted option value...
424             */
425
426             quote = *sep;
427           }
428           else if (*sep == ',' && count > 1)
429             break;
430           else if (*sep == '\\' && sep[1])
431           {
432            /*
433             * Skip quoted character...
434             */
435
436             sep ++;
437           }
438         }
439
440         if (*sep == ',')
441           *sep++ = '\0';
442       }
443
444      /*
445       * Copy the option value(s) over as needed by the type...
446       */
447
448       switch (attr->value_tag)
449       {
450         case IPP_TAG_INTEGER :
451         case IPP_TAG_ENUM :
452            /*
453             * Integer/enumeration value...
454             */
455
456             attr->values[j].integer = strtol(val, &s, 10);
457
458             DEBUG_printf(("2cupsEncodeOptions2: Added integer option value "
459                           "%d...", attr->values[j].integer));
460             break;
461
462         case IPP_TAG_BOOLEAN :
463             if (!_cups_strcasecmp(val, "true") ||
464                 !_cups_strcasecmp(val, "on") ||
465                 !_cups_strcasecmp(val, "yes"))
466             {
467              /*
468               * Boolean value - true...
469               */
470
471               attr->values[j].boolean = 1;
472
473               DEBUG_puts("2cupsEncodeOptions2: Added boolean true value...");
474             }
475             else
476             {
477              /*
478               * Boolean value - false...
479               */
480
481               attr->values[j].boolean = 0;
482
483               DEBUG_puts("2cupsEncodeOptions2: Added boolean false value...");
484             }
485             break;
486
487         case IPP_TAG_RANGE :
488            /*
489             * Range...
490             */
491
492             if (*val == '-')
493             {
494               attr->values[j].range.lower = 1;
495               s = val;
496             }
497             else
498               attr->values[j].range.lower = strtol(val, &s, 10);
499
500             if (*s == '-')
501             {
502               if (s[1])
503                 attr->values[j].range.upper = strtol(s + 1, NULL, 10);
504               else
505                 attr->values[j].range.upper = 2147483647;
506             }
507             else
508               attr->values[j].range.upper = attr->values[j].range.lower;
509
510             DEBUG_printf(("2cupsEncodeOptions2: Added range option value "
511                           "%d-%d...", attr->values[j].range.lower,
512                           attr->values[j].range.upper));
513             break;
514
515         case IPP_TAG_RESOLUTION :
516            /*
517             * Resolution...
518             */
519
520             attr->values[j].resolution.xres = strtol(val, &s, 10);
521
522             if (*s == 'x')
523               attr->values[j].resolution.yres = strtol(s + 1, &s, 10);
524             else
525               attr->values[j].resolution.yres = attr->values[j].resolution.xres;
526
527             if (!_cups_strcasecmp(s, "dpc"))
528               attr->values[j].resolution.units = IPP_RES_PER_CM;
529             else
530               attr->values[j].resolution.units = IPP_RES_PER_INCH;
531
532             DEBUG_printf(("2cupsEncodeOptions2: Added resolution option value "
533                           "%s...", val));
534             break;
535
536         case IPP_TAG_STRING :
537            /*
538             * octet-string
539             */
540
541             attr->values[j].unknown.length = (int)strlen(val);
542             attr->values[j].unknown.data   = strdup(val);
543
544             DEBUG_printf(("2cupsEncodeOptions2: Added octet-string value "
545                           "\"%s\"...", (char *)attr->values[j].unknown.data));
546             break;
547
548         case IPP_TAG_BEGIN_COLLECTION :
549            /*
550             * Collection value
551             */
552
553             num_cols   = cupsParseOptions(val, 0, &cols);
554             if ((collection = ippNew()) == NULL)
555             {
556               cupsFreeOptions(num_cols, cols);
557
558               if (copy)
559                 free(copy);
560
561               ippDeleteAttribute(ipp, attr);
562               return;
563             }
564
565             attr->values[j].collection = collection;
566             cupsEncodeOptions2(collection, num_cols, cols, IPP_TAG_JOB);
567             cupsFreeOptions(num_cols, cols);
568             break;
569
570         default :
571             if ((attr->values[j].string.text = _cupsStrAlloc(val)) == NULL)
572             {
573              /*
574               * Ran out of memory!
575               */
576
577               DEBUG_puts("1cupsEncodeOptions2: Ran out of memory for string!");
578
579               if (copy)
580                 free(copy);
581
582               ippDeleteAttribute(ipp, attr);
583               return;
584             }
585
586             DEBUG_printf(("2cupsEncodeOptions2: Added string value \"%s\"...",
587                           val));
588             break;
589       }
590     }
591
592     if (copy)
593       free(copy);
594   }
595 }
596
597
598 /*
599  * '_ippFindOption()' - Find the attribute information for an option.
600  */
601
602 _ipp_option_t *                         /* O - Attribute information */
603 _ippFindOption(const char *name)        /* I - Option/attribute name */
604 {
605   _ipp_option_t key;                    /* Search key */
606
607
608  /*
609   * Lookup the proper value and group tags for this option...
610   */
611
612   key.name = name;
613
614   return ((_ipp_option_t *)bsearch(&key, ipp_options,
615                                    sizeof(ipp_options) / sizeof(ipp_options[0]),
616                                    sizeof(ipp_options[0]),
617                                    (int (*)(const void *, const void *))
618                                        compare_ipp_options));
619 }
620
621
622 /*
623  * 'compare_ipp_options()' - Compare two IPP options.
624  */
625
626 static int                              /* O - Result of comparison */
627 compare_ipp_options(_ipp_option_t *a,   /* I - First option */
628                     _ipp_option_t *b)   /* I - Second option */
629 {
630   return (strcmp(a->name, b->name));
631 }
632
633
634 /*
635  * End of "$Id: encode.c 9793 2011-05-20 03:49:49Z mike $".
636  */