]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/ipp-file.c
Update ipp documentation to reflect the behavior of configuring WiFi on IPP USB printers.
[thirdparty/cups.git] / cups / ipp-file.c
CommitLineData
fd96ad89
MS
1/*
2 * IPP data file parsing functions.
3 *
bd516571 4 * Copyright © 2007-2019 by Apple Inc.
fd96ad89
MS
5 * Copyright © 1997-2007 by Easy Software Products.
6 *
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more
8 * information.
9 */
10
11/*
12 * Include necessary headers...
13 */
14
15#include "ipp-private.h"
16#include "string-private.h"
fb863569 17#include "debug-internal.h"
fd96ad89
MS
18
19
20/*
21 * Local functions...
22 */
23
a166e933
MS
24static ipp_t *parse_collection(_ipp_file_t *f, _ipp_vars_t *v, void *user_data);
25static int parse_value(_ipp_file_t *f, _ipp_vars_t *v, void *user_data, ipp_t *ipp, ipp_attribute_t **attr, int element);
86206ccf 26static void report_error(_ipp_file_t *f, _ipp_vars_t *v, void *user_data, const char *message, ...) _CUPS_FORMAT(4, 5);
fd96ad89
MS
27
28
29/*
30 * '_ippFileParse()' - Parse an IPP data file.
31 */
32
33ipp_t * /* O - IPP attributes or @code NULL@ on failure */
34_ippFileParse(
35 _ipp_vars_t *v, /* I - Variables */
36 const char *filename, /* I - Name of file to parse */
fd96ad89
MS
37 void *user_data) /* I - User data pointer */
38{
39 _ipp_file_t f; /* IPP data file information */
a166e933 40 ipp_t *attrs = NULL; /* Active IPP message */
fd96ad89
MS
41 ipp_attribute_t *attr = NULL; /* Current attribute */
42 char token[1024]; /* Token string */
a166e933 43 ipp_t *ignored = NULL; /* Ignored attributes */
fd96ad89
MS
44
45
a166e933 46 DEBUG_printf(("_ippFileParse(v=%p, filename=\"%s\", user_data=%p)", (void *)v, filename, user_data));
fd96ad89
MS
47
48 /*
49 * Initialize file info...
50 */
51
52 memset(&f, 0, sizeof(f));
53 f.filename = filename;
54 f.linenum = 1;
55
56 if ((f.fp = cupsFileOpen(filename, "r")) == NULL)
57 {
58 DEBUG_printf(("1_ippFileParse: Unable to open \"%s\": %s", filename, strerror(errno)));
59 return (0);
60 }
61
62 /*
63 * Do the callback with a NULL token to setup any initial state...
64 */
65
a166e933 66 (*v->tokencb)(&f, v, user_data, NULL);
fd96ad89
MS
67
68 /*
69 * Read data file, using the callback function as needed...
70 */
71
72 while (_ippFileReadToken(&f, token, sizeof(token)))
73 {
74 if (!_cups_strcasecmp(token, "DEFINE") || !_cups_strcasecmp(token, "DEFINE-DEFAULT"))
75 {
76 char name[128], /* Variable name */
77 value[1024], /* Variable value */
78 temp[1024]; /* Temporary string */
79
80 attr = NULL;
81
82 if (_ippFileReadToken(&f, name, sizeof(name)) && _ippFileReadToken(&f, temp, sizeof(temp)))
83 {
367068f3
MS
84 if (_cups_strcasecmp(token, "DEFINE-DEFAULT") || !_ippVarsGet(v, name))
85 {
86 _ippVarsExpand(v, value, temp, sizeof(value));
87 _ippVarsSet(v, name, value);
88 }
fd96ad89
MS
89 }
90 else
91 {
a166e933 92 report_error(&f, v, user_data, "Missing %s name and/or value on line %d of \"%s\".", token, f.linenum, f.filename);
fd96ad89
MS
93 break;
94 }
95 }
96 else if (f.attrs && !_cups_strcasecmp(token, "ATTR"))
97 {
98 /*
99 * Attribute definition...
100 */
101
102 char syntax[128], /* Attribute syntax (value tag) */
103 name[128]; /* Attribute name */
104 ipp_tag_t value_tag; /* Value tag */
105
106 attr = NULL;
107
108 if (!_ippFileReadToken(&f, syntax, sizeof(syntax)))
109 {
a166e933 110 report_error(&f, v, user_data, "Missing ATTR syntax on line %d of \"%s\".", f.linenum, f.filename);
fd96ad89
MS
111 break;
112 }
113 else if ((value_tag = ippTagValue(syntax)) < IPP_TAG_UNSUPPORTED_VALUE)
114 {
a166e933 115 report_error(&f, v, user_data, "Bad ATTR syntax \"%s\" on line %d of \"%s\".", syntax, f.linenum, f.filename);
fd96ad89
MS
116 break;
117 }
118
119 if (!_ippFileReadToken(&f, name, sizeof(name)) || !name[0])
120 {
a166e933 121 report_error(&f, v, user_data, "Missing ATTR name on line %d of \"%s\".", f.linenum, f.filename);
fd96ad89
MS
122 break;
123 }
124
a166e933
MS
125 if (!v->attrcb || (*v->attrcb)(&f, user_data, name))
126 {
127 /*
128 * Add this attribute...
129 */
130
131 attrs = f.attrs;
132 }
133 else
134 {
135 /*
136 * Ignore this attribute...
137 */
138
139 if (!ignored)
140 ignored = ippNew();
141
142 attrs = ignored;
143 }
144
fd96ad89
MS
145 if (value_tag < IPP_TAG_INTEGER)
146 {
147 /*
148 * Add out-of-band attribute - no value string needed...
149 */
150
a166e933 151 ippAddOutOfBand(attrs, f.group_tag, value_tag, name);
fd96ad89
MS
152 }
153 else
154 {
155 /*
156 * Add attribute with one or more values...
157 */
158
a166e933 159 attr = ippAddString(attrs, f.group_tag, value_tag, name, NULL, NULL);
fd96ad89 160
a166e933 161 if (!parse_value(&f, v, user_data, attrs, &attr, 0))
fd96ad89 162 break;
fd96ad89
MS
163 }
164
165 }
166 else if (attr && !_cups_strcasecmp(token, ","))
167 {
168 /*
169 * Additional value...
170 */
171
a166e933 172 if (!parse_value(&f, v, user_data, attrs, &attr, ippGetCount(attr)))
fd96ad89 173 break;
fd96ad89
MS
174 }
175 else
176 {
177 /*
178 * Something else...
179 */
180
a166e933
MS
181 attr = NULL;
182 attrs = NULL;
fd96ad89 183
a166e933 184 if (!(*v->tokencb)(&f, v, user_data, token))
fd96ad89
MS
185 break;
186 }
187 }
188
189 /*
a166e933
MS
190 * Close the file and free ignored attributes, then return any attributes we
191 * kept...
fd96ad89
MS
192 */
193
194 cupsFileClose(f.fp);
a166e933 195 ippDelete(ignored);
fd96ad89
MS
196
197 return (f.attrs);
198}
199
200
201/*
202 * '_ippFileReadToken()' - Read a token from an IPP data file.
203 */
204
205int /* O - 1 on success, 0 on failure */
206_ippFileReadToken(_ipp_file_t *f, /* I - File to read from */
207 char *token, /* I - Token string buffer */
208 size_t tokensize)/* I - Size of token string buffer */
209{
210 int ch, /* Character from file */
211 quote = 0; /* Quoting character */
212 char *tokptr = token, /* Pointer into token buffer */
213 *tokend = token + tokensize - 1;/* End of token buffer */
214
215
216 /*
217 * Skip whitespace and comments...
218 */
219
0b353e63
MS
220 DEBUG_printf(("1_ippFileReadToken: linenum=%d, pos=%ld", f->linenum, (long)cupsFileTell(f->fp)));
221
fd96ad89
MS
222 while ((ch = cupsFileGetChar(f->fp)) != EOF)
223 {
224 if (_cups_isspace(ch))
225 {
226 /*
227 * Whitespace...
228 */
229
230 if (ch == '\n')
0b353e63 231 {
fd96ad89 232 f->linenum ++;
0b353e63
MS
233 DEBUG_printf(("1_ippFileReadToken: LF in leading whitespace, linenum=%d, pos=%ld", f->linenum, (long)cupsFileTell(f->fp)));
234 }
fd96ad89
MS
235 }
236 else if (ch == '#')
237 {
238 /*
239 * Comment...
240 */
241
0b353e63
MS
242 DEBUG_puts("1_ippFileReadToken: Skipping comment in leading whitespace...");
243
fd96ad89
MS
244 while ((ch = cupsFileGetChar(f->fp)) != EOF)
245 {
246 if (ch == '\n')
247 break;
248 }
249
250 if (ch == '\n')
0b353e63 251 {
fd96ad89 252 f->linenum ++;
0b353e63
MS
253 DEBUG_printf(("1_ippFileReadToken: LF at end of comment, linenum=%d, pos=%ld", f->linenum, (long)cupsFileTell(f->fp)));
254 }
fd96ad89
MS
255 else
256 break;
257 }
258 else
259 break;
260 }
261
262 if (ch == EOF)
263 {
264 DEBUG_puts("1_ippFileReadToken: EOF");
265 return (0);
266 }
267
268 /*
269 * Read a token...
270 */
271
272 while (ch != EOF)
273 {
8e2e09c1 274 if (ch == '\n')
0b353e63 275 {
8e2e09c1 276 f->linenum ++;
0b353e63
MS
277 DEBUG_printf(("1_ippFileReadToken: LF in token, linenum=%d, pos=%ld", f->linenum, (long)cupsFileTell(f->fp)));
278 }
8e2e09c1 279
fd96ad89
MS
280 if (ch == quote)
281 {
282 /*
283 * End of quoted text...
284 */
285
286 *tokptr = '\0';
0b353e63 287 DEBUG_printf(("1_ippFileReadToken: Returning \"%s\" at closing quote.", token));
fd96ad89
MS
288 return (1);
289 }
290 else if (!quote && _cups_isspace(ch))
291 {
292 /*
293 * End of unquoted text...
294 */
295
296 *tokptr = '\0';
0b353e63 297 DEBUG_printf(("1_ippFileReadToken: Returning \"%s\" before whitespace.", token));
fd96ad89
MS
298 return (1);
299 }
cb480624 300 else if (!quote && (ch == '\'' || ch == '\"'))
fd96ad89
MS
301 {
302 /*
303 * Start of quoted text or regular expression...
304 */
305
baa764fa 306 quote = ch;
0b353e63
MS
307
308 DEBUG_printf(("1_ippFileReadToken: Start of quoted string, quote=%c, pos=%ld", quote, (long)cupsFileTell(f->fp)));
fd96ad89
MS
309 }
310 else if (!quote && ch == '#')
311 {
312 /*
313 * Start of comment...
314 */
315
316 cupsFileSeek(f->fp, cupsFileTell(f->fp) - 1);
317 *tokptr = '\0';
0b353e63 318 DEBUG_printf(("1_ippFileReadToken: Returning \"%s\" before comment.", token));
fd96ad89
MS
319 return (1);
320 }
321 else if (!quote && (ch == '{' || ch == '}' || ch == ','))
322 {
323 /*
324 * Delimiter...
325 */
326
327 if (tokptr > token)
328 {
329 /*
330 * Return the preceding token first...
331 */
332
333 cupsFileSeek(f->fp, cupsFileTell(f->fp) - 1);
334 }
335 else
336 {
337 /*
338 * Return this delimiter by itself...
339 */
340
341 *tokptr++ = (char)ch;
342 }
343
344 *tokptr = '\0';
345 DEBUG_printf(("1_ippFileReadToken: Returning \"%s\".", token));
346 return (1);
347 }
348 else
349 {
350 if (ch == '\\')
351 {
352 /*
353 * Quoted character...
354 */
355
0b353e63
MS
356 DEBUG_printf(("1_ippFileReadToken: Quoted character at pos=%ld", (long)cupsFileTell(f->fp)));
357
fd96ad89
MS
358 if ((ch = cupsFileGetChar(f->fp)) == EOF)
359 {
360 *token = '\0';
361 DEBUG_puts("1_ippFileReadToken: EOF");
362 return (0);
363 }
8e2e09c1 364 else if (ch == '\n')
0b353e63 365 {
8e2e09c1 366 f->linenum ++;
0b353e63
MS
367 DEBUG_printf(("1_ippFileReadToken: quoted LF, linenum=%d, pos=%ld", f->linenum, (long)cupsFileTell(f->fp)));
368 }
0c178dec
MS
369 else if (ch == 'a')
370 ch = '\a';
371 else if (ch == 'b')
372 ch = '\b';
373 else if (ch == 'f')
374 ch = '\f';
375 else if (ch == 'n')
376 ch = '\n';
377 else if (ch == 'r')
378 ch = '\r';
379 else if (ch == 't')
380 ch = '\t';
381 else if (ch == 'v')
382 ch = '\v';
fd96ad89
MS
383 }
384
cb480624 385 if (tokptr < tokend)
fd96ad89 386 {
cb480624
MS
387 /*
388 * Add to current token...
389 */
fd96ad89 390
cb480624
MS
391 *tokptr++ = (char)ch;
392 }
393 else
394 {
395 /*
396 * Token too long...
397 */
fd96ad89 398
cb480624
MS
399 *tokptr = '\0';
400 DEBUG_printf(("1_ippFileReadToken: Too long: \"%s\".", token));
401 return (0);
fd96ad89
MS
402 }
403 }
404
405 /*
406 * Get the next character...
407 */
408
409 ch = cupsFileGetChar(f->fp);
410 }
411
412 *tokptr = '\0';
0b353e63 413 DEBUG_printf(("1_ippFileReadToken: Returning \"%s\" at EOF.", token));
fd96ad89
MS
414
415 return (tokptr > token);
416}
417
418
419/*
420 * 'parse_collection()' - Parse an IPP collection value.
421 */
422
423static ipp_t * /* O - Collection value or @code NULL@ on error */
424parse_collection(
425 _ipp_file_t *f, /* I - IPP data file */
426 _ipp_vars_t *v, /* I - IPP variables */
fd96ad89
MS
427 void *user_data) /* I - User data pointer */
428{
429 ipp_t *col = ippNew(); /* Collection value */
430 ipp_attribute_t *attr = NULL; /* Current member attribute */
431 char token[1024]; /* Token string */
432
433
434 /*
435 * Parse the collection value...
436 */
437
438 while (_ippFileReadToken(f, token, sizeof(token)))
439 {
440 if (!_cups_strcasecmp(token, "}"))
441 {
442 /*
443 * End of collection value...
444 */
445
446 break;
447 }
448 else if (!_cups_strcasecmp(token, "MEMBER"))
449 {
450 /*
451 * Member attribute definition...
452 */
453
454 char syntax[128], /* Attribute syntax (value tag) */
455 name[128]; /* Attribute name */
456 ipp_tag_t value_tag; /* Value tag */
457
458 attr = NULL;
459
460 if (!_ippFileReadToken(f, syntax, sizeof(syntax)))
461 {
c674bfbe 462 report_error(f, v, user_data, "Missing MEMBER syntax on line %d of \"%s\".", f->linenum, f->filename);
fd96ad89
MS
463 ippDelete(col);
464 col = NULL;
465 break;
466 }
467 else if ((value_tag = ippTagValue(syntax)) < IPP_TAG_UNSUPPORTED_VALUE)
468 {
c674bfbe 469 report_error(f, v, user_data, "Bad MEMBER syntax \"%s\" on line %d of \"%s\".", syntax, f->linenum, f->filename);
fd96ad89
MS
470 ippDelete(col);
471 col = NULL;
472 break;
473 }
474
475 if (!_ippFileReadToken(f, name, sizeof(name)) || !name[0])
476 {
c674bfbe 477 report_error(f, v, user_data, "Missing MEMBER name on line %d of \"%s\".", f->linenum, f->filename);
fd96ad89
MS
478 ippDelete(col);
479 col = NULL;
480 break;
481 }
482
483 if (value_tag < IPP_TAG_INTEGER)
484 {
485 /*
486 * Add out-of-band attribute - no value string needed...
487 */
488
489 ippAddOutOfBand(col, IPP_TAG_ZERO, value_tag, name);
490 }
491 else
492 {
493 /*
494 * Add attribute with one or more values...
495 */
496
497 attr = ippAddString(col, IPP_TAG_ZERO, value_tag, name, NULL, NULL);
498
a166e933 499 if (!parse_value(f, v, user_data, col, &attr, 0))
fd96ad89
MS
500 {
501 ippDelete(col);
502 col = NULL;
503 break;
504 }
505 }
506
507 }
508 else if (attr && !_cups_strcasecmp(token, ","))
509 {
510 /*
511 * Additional value...
512 */
513
a166e933 514 if (!parse_value(f, v, user_data, col, &attr, ippGetCount(attr)))
fd96ad89
MS
515 {
516 ippDelete(col);
517 col = NULL;
518 break;
519 }
520 }
521 else
522 {
523 /*
524 * Something else...
525 */
526
a166e933 527 report_error(f, v, user_data, "Unknown directive \"%s\" on line %d of \"%s\".", token, f->linenum, f->filename);
fd96ad89
MS
528 ippDelete(col);
529 col = NULL;
530 attr = NULL;
531 break;
532
533 }
534 }
535
536 return (col);
537}
538
539
540/*
541 * 'parse_value()' - Parse an IPP value.
542 */
543
544static int /* O - 1 on success or 0 on error */
545parse_value(_ipp_file_t *f, /* I - IPP data file */
546 _ipp_vars_t *v, /* I - IPP variables */
fd96ad89
MS
547 void *user_data,/* I - User data pointer */
548 ipp_t *ipp, /* I - IPP message */
549 ipp_attribute_t **attr, /* IO - IPP attribute */
550 int element) /* I - Element number */
551{
bd516571
MS
552 char value[2049], /* Value string */
553 *valueptr, /* Pointer into value string */
554 temp[2049], /* Temporary string */
555 *tempptr; /* Pointer into temporary string */
556 size_t valuelen; /* Length of value */
fd96ad89
MS
557
558
559 if (!_ippFileReadToken(f, temp, sizeof(temp)))
560 {
a166e933 561 report_error(f, v, user_data, "Missing value on line %d of \"%s\".", f->linenum, f->filename);
fd96ad89
MS
562 return (0);
563 }
564
565 _ippVarsExpand(v, value, temp, sizeof(value));
566
567 switch (ippGetValueTag(*attr))
568 {
569 case IPP_TAG_BOOLEAN :
570 return (ippSetBoolean(ipp, attr, element, !_cups_strcasecmp(value, "true")));
fd96ad89
MS
571
572 case IPP_TAG_ENUM :
573 case IPP_TAG_INTEGER :
564cd57d 574 return (ippSetInteger(ipp, attr, element, (int)strtol(value, NULL, 0)));
fd96ad89 575
06e1afc3
MS
576 case IPP_TAG_DATE :
577 {
578 int year, /* Year */
579 month, /* Month */
580 day, /* Day of month */
581 hour, /* Hour */
582 minute, /* Minute */
583 second, /* Second */
584 utc_offset = 0; /* Timezone offset from UTC */
585 ipp_uchar_t date[11]; /* dateTime value */
586
c8d7d4bf 587 if (*value == 'P')
06e1afc3 588 {
c8d7d4bf
MS
589 /*
590 * Time period...
591 */
592
593 time_t curtime; /* Current time in seconds */
594 int period = 0, /* Current period value */
595 saw_T = 0; /* Saw time separator */
596
597 curtime = time(NULL);
598
599 for (valueptr = value + 1; *valueptr; valueptr ++)
600 {
601 if (isdigit(*valueptr & 255))
602 {
1b032cbf 603 period = (int)strtol(valueptr, &valueptr, 10);
c8d7d4bf
MS
604
605 if (!valueptr || period < 0)
606 {
607 report_error(f, v, user_data, "Bad dateTime value \"%s\" on line %d of \"%s\".", value, f->linenum, f->filename);
608 return (0);
609 }
610 }
611
612 if (*valueptr == 'Y')
613 {
614 curtime += 365 * 86400 * period;
615 period = 0;
616 }
617 else if (*valueptr == 'M')
618 {
619 if (saw_T)
620 curtime += 60 * period;
621 else
622 curtime += 30 * 86400 * period;
623
624 period = 0;
625 }
626 else if (*valueptr == 'D')
627 {
628 curtime += 86400 * period;
629 period = 0;
630 }
631 else if (*valueptr == 'H')
632 {
633 curtime += 3600 * period;
634 period = 0;
635 }
636 else if (*valueptr == 'S')
637 {
638 curtime += period;
639 period = 0;
640 }
641 else if (*valueptr == 'T')
642 {
643 saw_T = 1;
644 period = 0;
645 }
646 else
647 {
648 report_error(f, v, user_data, "Bad dateTime value \"%s\" on line %d of \"%s\".", value, f->linenum, f->filename);
649 return (0);
650 }
651 }
652
653 return (ippSetDate(ipp, attr, element, ippTimeToDate(curtime)));
654 }
655 else if (sscanf(value, "%d-%d-%dT%d:%d:%d%d", &year, &month, &day, &hour, &minute, &second, &utc_offset) < 6)
656 {
657 /*
658 * Date/time value did not parse...
659 */
660
06e1afc3
MS
661 report_error(f, v, user_data, "Bad dateTime value \"%s\" on line %d of \"%s\".", value, f->linenum, f->filename);
662 return (0);
663 }
664
665 date[0] = (ipp_uchar_t)(year >> 8);
666 date[1] = (ipp_uchar_t)(year & 255);
667 date[2] = (ipp_uchar_t)month;
668 date[3] = (ipp_uchar_t)day;
669 date[4] = (ipp_uchar_t)hour;
670 date[5] = (ipp_uchar_t)minute;
671 date[6] = (ipp_uchar_t)second;
672 date[7] = 0;
673 if (utc_offset < 0)
674 {
675 utc_offset = -utc_offset;
676 date[8] = (ipp_uchar_t)'-';
677 }
678 else
679 {
680 date[8] = (ipp_uchar_t)'+';
681 }
682
683 date[9] = (ipp_uchar_t)(utc_offset / 100);
684 date[10] = (ipp_uchar_t)(utc_offset % 100);
685
686 return (ippSetDate(ipp, attr, element, date));
687 }
06e1afc3 688
fd96ad89
MS
689 case IPP_TAG_RESOLUTION :
690 {
691 int xres, /* X resolution */
692 yres; /* Y resolution */
693 char *ptr; /* Pointer into value */
694
695 xres = yres = (int)strtol(value, (char **)&ptr, 10);
696 if (ptr > value && xres > 0)
697 {
698 if (*ptr == 'x')
699 yres = (int)strtol(ptr + 1, (char **)&ptr, 10);
700 }
701
702 if (ptr <= value || xres <= 0 || yres <= 0 || !ptr || (_cups_strcasecmp(ptr, "dpi") && _cups_strcasecmp(ptr, "dpc") && _cups_strcasecmp(ptr, "dpcm") && _cups_strcasecmp(ptr, "other")))
703 {
a166e933 704 report_error(f, v, user_data, "Bad resolution value \"%s\" on line %d of \"%s\".", value, f->linenum, f->filename);
fd96ad89
MS
705 return (0);
706 }
707
708 if (!_cups_strcasecmp(ptr, "dpi"))
709 return (ippSetResolution(ipp, attr, element, IPP_RES_PER_INCH, xres, yres));
710 else if (!_cups_strcasecmp(ptr, "dpc") || !_cups_strcasecmp(ptr, "dpcm"))
711 return (ippSetResolution(ipp, attr, element, IPP_RES_PER_CM, xres, yres));
712 else
713 return (ippSetResolution(ipp, attr, element, (ipp_res_t)0, xres, yres));
714 }
fd96ad89
MS
715
716 case IPP_TAG_RANGE :
717 {
718 int lower, /* Lower value */
719 upper; /* Upper value */
720
721 if (sscanf(value, "%d-%d", &lower, &upper) != 2)
722 {
a166e933 723 report_error(f, v, user_data, "Bad rangeOfInteger value \"%s\" on line %d of \"%s\".", value, f->linenum, f->filename);
fd96ad89
MS
724 return (0);
725 }
726
727 return (ippSetRange(ipp, attr, element, lower, upper));
728 }
fd96ad89
MS
729
730 case IPP_TAG_STRING :
bd516571
MS
731 valuelen = strlen(value);
732
733 if (value[0] == '<' && value[strlen(value) - 1] == '>')
734 {
735 if (valuelen & 1)
736 {
c674bfbe 737 report_error(f, v, user_data, "Bad octetString value on line %d of \"%s\".", f->linenum, f->filename);
bd516571
MS
738 return (0);
739 }
740
741 valueptr = value + 1;
742 tempptr = temp;
743
744 while (*valueptr && *valueptr != '>')
745 {
746 if (!isxdigit(valueptr[0] & 255) || !isxdigit(valueptr[1] & 255))
747 {
c674bfbe 748 report_error(f, v, user_data, "Bad octetString value on line %d of \"%s\".", f->linenum, f->filename);
bd516571
MS
749 return (0);
750 }
751
752 if (valueptr[0] >= '0' && valueptr[0] <= '9')
753 *tempptr = (char)((valueptr[0] - '0') << 4);
754 else
755 *tempptr = (char)((tolower(valueptr[0]) - 'a' + 10) << 4);
756
757 if (valueptr[1] >= '0' && valueptr[1] <= '9')
758 *tempptr |= (valueptr[1] - '0');
759 else
760 *tempptr |= (tolower(valueptr[1]) - 'a' + 10);
761
762 tempptr ++;
763 }
764
765 return (ippSetOctetString(ipp, attr, element, temp, (int)(tempptr - temp)));
766 }
767 else
768 return (ippSetOctetString(ipp, attr, element, value, (int)valuelen));
fd96ad89
MS
769
770 case IPP_TAG_TEXTLANG :
771 case IPP_TAG_NAMELANG :
772 case IPP_TAG_TEXT :
773 case IPP_TAG_NAME :
774 case IPP_TAG_KEYWORD :
775 case IPP_TAG_URI :
776 case IPP_TAG_URISCHEME :
777 case IPP_TAG_CHARSET :
778 case IPP_TAG_LANGUAGE :
779 case IPP_TAG_MIMETYPE :
780 return (ippSetString(ipp, attr, element, value));
fd96ad89
MS
781
782 case IPP_TAG_BEGIN_COLLECTION :
783 {
784 int status; /* Add status */
785 ipp_t *col; /* Collection value */
786
787 if (strcmp(value, "{"))
788 {
c674bfbe 789 report_error(f, v, user_data, "Bad collection value on line %d of \"%s\".", f->linenum, f->filename);
fd96ad89
MS
790 return (0);
791 }
792
a166e933 793 if ((col = parse_collection(f, v, user_data)) == NULL)
fd96ad89
MS
794 return (0);
795
796 status = ippSetCollection(ipp, attr, element, col);
797 ippDelete(col);
798
799 return (status);
800 }
fd96ad89
MS
801
802 default :
c674bfbe 803 report_error(f, v, user_data, "Unsupported value on line %d of \"%s\".", f->linenum, f->filename);
fd96ad89
MS
804 return (0);
805 }
fd96ad89
MS
806}
807
808
809/*
810 * 'report_error()' - Report an error.
811 */
812
813static void
814report_error(
a166e933
MS
815 _ipp_file_t *f, /* I - IPP data file */
816 _ipp_vars_t *v, /* I - Error callback function, if any */
817 void *user_data, /* I - User data pointer */
818 const char *message, /* I - Printf-style message */
fd96ad89
MS
819 ...) /* I - Additional arguments as needed */
820{
821 char buffer[8192]; /* Formatted string */
822 va_list ap; /* Argument pointer */
823
824
825 va_start(ap, message);
826 vsnprintf(buffer, sizeof(buffer), message, ap);
827 va_end(ap);
828
a166e933
MS
829 if (v->errorcb)
830 (*v->errorcb)(f, user_data, buffer);
fd96ad89
MS
831 else
832 fprintf(stderr, "%s\n", buffer);
833}