]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/ipp-file.c
Add missing DNSSD.LIB functions.
[thirdparty/cups.git] / cups / ipp-file.c
CommitLineData
fd96ad89
MS
1/*
2 * IPP data file parsing functions.
3 *
4 * Copyright © 2007-2018 by Apple Inc.
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"
17#include "debug-private.h"
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
220 while ((ch = cupsFileGetChar(f->fp)) != EOF)
221 {
222 if (_cups_isspace(ch))
223 {
224 /*
225 * Whitespace...
226 */
227
228 if (ch == '\n')
229 f->linenum ++;
230 }
231 else if (ch == '#')
232 {
233 /*
234 * Comment...
235 */
236
237 while ((ch = cupsFileGetChar(f->fp)) != EOF)
238 {
239 if (ch == '\n')
240 break;
241 }
242
243 if (ch == '\n')
244 f->linenum ++;
245 else
246 break;
247 }
248 else
249 break;
250 }
251
252 if (ch == EOF)
253 {
254 DEBUG_puts("1_ippFileReadToken: EOF");
255 return (0);
256 }
257
258 /*
259 * Read a token...
260 */
261
262 while (ch != EOF)
263 {
8e2e09c1
MS
264 if (ch == '\n')
265 f->linenum ++;
266
fd96ad89
MS
267 if (ch == quote)
268 {
269 /*
270 * End of quoted text...
271 */
272
273 *tokptr = '\0';
274 DEBUG_printf(("1_ippFileReadToken: Returning \"%s\".", token));
275 return (1);
276 }
277 else if (!quote && _cups_isspace(ch))
278 {
279 /*
280 * End of unquoted text...
281 */
282
283 *tokptr = '\0';
284 DEBUG_printf(("1_ippFileReadToken: Returning \"%s\".", token));
285 return (1);
286 }
287 else if (!quote && (ch == '\'' || ch == '\"'))
288 {
289 /*
290 * Start of quoted text or regular expression...
291 */
292
293 quote = ch;
294 }
295 else if (!quote && ch == '#')
296 {
297 /*
298 * Start of comment...
299 */
300
301 cupsFileSeek(f->fp, cupsFileTell(f->fp) - 1);
302 *tokptr = '\0';
303 DEBUG_printf(("1_ippFileReadToken: Returning \"%s\".", token));
304 return (1);
305 }
306 else if (!quote && (ch == '{' || ch == '}' || ch == ','))
307 {
308 /*
309 * Delimiter...
310 */
311
312 if (tokptr > token)
313 {
314 /*
315 * Return the preceding token first...
316 */
317
318 cupsFileSeek(f->fp, cupsFileTell(f->fp) - 1);
319 }
320 else
321 {
322 /*
323 * Return this delimiter by itself...
324 */
325
326 *tokptr++ = (char)ch;
327 }
328
329 *tokptr = '\0';
330 DEBUG_printf(("1_ippFileReadToken: Returning \"%s\".", token));
331 return (1);
332 }
333 else
334 {
335 if (ch == '\\')
336 {
337 /*
338 * Quoted character...
339 */
340
341 if ((ch = cupsFileGetChar(f->fp)) == EOF)
342 {
343 *token = '\0';
344 DEBUG_puts("1_ippFileReadToken: EOF");
345 return (0);
346 }
8e2e09c1
MS
347 else if (ch == '\n')
348 f->linenum ++;
fd96ad89
MS
349 }
350
351 if (tokptr < tokend)
352 {
353 /*
354 * Add to current token...
355 */
356
357 *tokptr++ = (char)ch;
358 }
359 else
360 {
361 /*
362 * Token too long...
363 */
364
365 *tokptr = '\0';
366 DEBUG_printf(("1_ippFileReadToken: Too long: \"%s\".", token));
367 return (0);
368 }
369 }
370
371 /*
372 * Get the next character...
373 */
374
375 ch = cupsFileGetChar(f->fp);
376 }
377
378 *tokptr = '\0';
379 DEBUG_printf(("1_ippFileReadToken: Returning \"%s\".", token));
380
381 return (tokptr > token);
382}
383
384
385/*
386 * 'parse_collection()' - Parse an IPP collection value.
387 */
388
389static ipp_t * /* O - Collection value or @code NULL@ on error */
390parse_collection(
391 _ipp_file_t *f, /* I - IPP data file */
392 _ipp_vars_t *v, /* I - IPP variables */
fd96ad89
MS
393 void *user_data) /* I - User data pointer */
394{
395 ipp_t *col = ippNew(); /* Collection value */
396 ipp_attribute_t *attr = NULL; /* Current member attribute */
397 char token[1024]; /* Token string */
398
399
400 /*
401 * Parse the collection value...
402 */
403
404 while (_ippFileReadToken(f, token, sizeof(token)))
405 {
406 if (!_cups_strcasecmp(token, "}"))
407 {
408 /*
409 * End of collection value...
410 */
411
412 break;
413 }
414 else if (!_cups_strcasecmp(token, "MEMBER"))
415 {
416 /*
417 * Member attribute definition...
418 */
419
420 char syntax[128], /* Attribute syntax (value tag) */
421 name[128]; /* Attribute name */
422 ipp_tag_t value_tag; /* Value tag */
423
424 attr = NULL;
425
426 if (!_ippFileReadToken(f, syntax, sizeof(syntax)))
427 {
a166e933 428 report_error(f, v, user_data, "Missing ATTR syntax on line %d of \"%s\".", f->linenum, f->filename);
fd96ad89
MS
429 ippDelete(col);
430 col = NULL;
431 break;
432 }
433 else if ((value_tag = ippTagValue(syntax)) < IPP_TAG_UNSUPPORTED_VALUE)
434 {
a166e933 435 report_error(f, v, user_data, "Bad ATTR syntax \"%s\" on line %d of \"%s\".", syntax, f->linenum, f->filename);
fd96ad89
MS
436 ippDelete(col);
437 col = NULL;
438 break;
439 }
440
441 if (!_ippFileReadToken(f, name, sizeof(name)) || !name[0])
442 {
a166e933 443 report_error(f, v, user_data, "Missing ATTR name on line %d of \"%s\".", f->linenum, f->filename);
fd96ad89
MS
444 ippDelete(col);
445 col = NULL;
446 break;
447 }
448
449 if (value_tag < IPP_TAG_INTEGER)
450 {
451 /*
452 * Add out-of-band attribute - no value string needed...
453 */
454
455 ippAddOutOfBand(col, IPP_TAG_ZERO, value_tag, name);
456 }
457 else
458 {
459 /*
460 * Add attribute with one or more values...
461 */
462
463 attr = ippAddString(col, IPP_TAG_ZERO, value_tag, name, NULL, NULL);
464
a166e933 465 if (!parse_value(f, v, user_data, col, &attr, 0))
fd96ad89
MS
466 {
467 ippDelete(col);
468 col = NULL;
469 break;
470 }
471 }
472
473 }
474 else if (attr && !_cups_strcasecmp(token, ","))
475 {
476 /*
477 * Additional value...
478 */
479
a166e933 480 if (!parse_value(f, v, user_data, col, &attr, ippGetCount(attr)))
fd96ad89
MS
481 {
482 ippDelete(col);
483 col = NULL;
484 break;
485 }
486 }
487 else
488 {
489 /*
490 * Something else...
491 */
492
a166e933 493 report_error(f, v, user_data, "Unknown directive \"%s\" on line %d of \"%s\".", token, f->linenum, f->filename);
fd96ad89
MS
494 ippDelete(col);
495 col = NULL;
496 attr = NULL;
497 break;
498
499 }
500 }
501
502 return (col);
503}
504
505
506/*
507 * 'parse_value()' - Parse an IPP value.
508 */
509
510static int /* O - 1 on success or 0 on error */
511parse_value(_ipp_file_t *f, /* I - IPP data file */
512 _ipp_vars_t *v, /* I - IPP variables */
fd96ad89
MS
513 void *user_data,/* I - User data pointer */
514 ipp_t *ipp, /* I - IPP message */
515 ipp_attribute_t **attr, /* IO - IPP attribute */
516 int element) /* I - Element number */
517{
518 char value[1024], /* Value string */
519 temp[1024]; /* Temporary string */
520
521
522 if (!_ippFileReadToken(f, temp, sizeof(temp)))
523 {
a166e933 524 report_error(f, v, user_data, "Missing value on line %d of \"%s\".", f->linenum, f->filename);
fd96ad89
MS
525 return (0);
526 }
527
528 _ippVarsExpand(v, value, temp, sizeof(value));
529
530 switch (ippGetValueTag(*attr))
531 {
532 case IPP_TAG_BOOLEAN :
533 return (ippSetBoolean(ipp, attr, element, !_cups_strcasecmp(value, "true")));
534 break;
535
536 case IPP_TAG_ENUM :
537 case IPP_TAG_INTEGER :
564cd57d 538 return (ippSetInteger(ipp, attr, element, (int)strtol(value, NULL, 0)));
fd96ad89
MS
539 break;
540
06e1afc3
MS
541 case IPP_TAG_DATE :
542 {
543 int year, /* Year */
544 month, /* Month */
545 day, /* Day of month */
546 hour, /* Hour */
547 minute, /* Minute */
548 second, /* Second */
549 utc_offset = 0; /* Timezone offset from UTC */
550 ipp_uchar_t date[11]; /* dateTime value */
551
f17549fb 552 if (sscanf(value, "%d-%d-%dT%d:%d:%d%d", &year, &month, &day, &hour, &minute, &second, &utc_offset) < 6)
06e1afc3
MS
553 {
554 report_error(f, v, user_data, "Bad dateTime value \"%s\" on line %d of \"%s\".", value, f->linenum, f->filename);
555 return (0);
556 }
557
558 date[0] = (ipp_uchar_t)(year >> 8);
559 date[1] = (ipp_uchar_t)(year & 255);
560 date[2] = (ipp_uchar_t)month;
561 date[3] = (ipp_uchar_t)day;
562 date[4] = (ipp_uchar_t)hour;
563 date[5] = (ipp_uchar_t)minute;
564 date[6] = (ipp_uchar_t)second;
565 date[7] = 0;
566 if (utc_offset < 0)
567 {
568 utc_offset = -utc_offset;
569 date[8] = (ipp_uchar_t)'-';
570 }
571 else
572 {
573 date[8] = (ipp_uchar_t)'+';
574 }
575
576 date[9] = (ipp_uchar_t)(utc_offset / 100);
577 date[10] = (ipp_uchar_t)(utc_offset % 100);
578
579 return (ippSetDate(ipp, attr, element, date));
580 }
581 break;
582
fd96ad89
MS
583 case IPP_TAG_RESOLUTION :
584 {
585 int xres, /* X resolution */
586 yres; /* Y resolution */
587 char *ptr; /* Pointer into value */
588
589 xres = yres = (int)strtol(value, (char **)&ptr, 10);
590 if (ptr > value && xres > 0)
591 {
592 if (*ptr == 'x')
593 yres = (int)strtol(ptr + 1, (char **)&ptr, 10);
594 }
595
596 if (ptr <= value || xres <= 0 || yres <= 0 || !ptr || (_cups_strcasecmp(ptr, "dpi") && _cups_strcasecmp(ptr, "dpc") && _cups_strcasecmp(ptr, "dpcm") && _cups_strcasecmp(ptr, "other")))
597 {
a166e933 598 report_error(f, v, user_data, "Bad resolution value \"%s\" on line %d of \"%s\".", value, f->linenum, f->filename);
fd96ad89
MS
599 return (0);
600 }
601
602 if (!_cups_strcasecmp(ptr, "dpi"))
603 return (ippSetResolution(ipp, attr, element, IPP_RES_PER_INCH, xres, yres));
604 else if (!_cups_strcasecmp(ptr, "dpc") || !_cups_strcasecmp(ptr, "dpcm"))
605 return (ippSetResolution(ipp, attr, element, IPP_RES_PER_CM, xres, yres));
606 else
607 return (ippSetResolution(ipp, attr, element, (ipp_res_t)0, xres, yres));
608 }
609 break;
610
611 case IPP_TAG_RANGE :
612 {
613 int lower, /* Lower value */
614 upper; /* Upper value */
615
616 if (sscanf(value, "%d-%d", &lower, &upper) != 2)
617 {
a166e933 618 report_error(f, v, user_data, "Bad rangeOfInteger value \"%s\" on line %d of \"%s\".", value, f->linenum, f->filename);
fd96ad89
MS
619 return (0);
620 }
621
622 return (ippSetRange(ipp, attr, element, lower, upper));
623 }
624 break;
625
626 case IPP_TAG_STRING :
627 return (ippSetOctetString(ipp, attr, element, value, (int)strlen(value)));
628 break;
629
630 case IPP_TAG_TEXTLANG :
631 case IPP_TAG_NAMELANG :
632 case IPP_TAG_TEXT :
633 case IPP_TAG_NAME :
634 case IPP_TAG_KEYWORD :
635 case IPP_TAG_URI :
636 case IPP_TAG_URISCHEME :
637 case IPP_TAG_CHARSET :
638 case IPP_TAG_LANGUAGE :
639 case IPP_TAG_MIMETYPE :
640 return (ippSetString(ipp, attr, element, value));
641 break;
642
643 case IPP_TAG_BEGIN_COLLECTION :
644 {
645 int status; /* Add status */
646 ipp_t *col; /* Collection value */
647
648 if (strcmp(value, "{"))
649 {
a166e933 650 report_error(f, v, user_data, "Bad ATTR collection value on line %d of \"%s\".", f->linenum, f->filename);
fd96ad89
MS
651 return (0);
652 }
653
a166e933 654 if ((col = parse_collection(f, v, user_data)) == NULL)
fd96ad89
MS
655 return (0);
656
657 status = ippSetCollection(ipp, attr, element, col);
658 ippDelete(col);
659
660 return (status);
661 }
662 break;
663
664 default :
a166e933 665 report_error(f, v, user_data, "Unsupported ATTR value on line %d of \"%s\".", f->linenum, f->filename);
fd96ad89
MS
666 return (0);
667 }
668
669 return (1);
670}
671
672
673/*
674 * 'report_error()' - Report an error.
675 */
676
677static void
678report_error(
a166e933
MS
679 _ipp_file_t *f, /* I - IPP data file */
680 _ipp_vars_t *v, /* I - Error callback function, if any */
681 void *user_data, /* I - User data pointer */
682 const char *message, /* I - Printf-style message */
fd96ad89
MS
683 ...) /* I - Additional arguments as needed */
684{
685 char buffer[8192]; /* Formatted string */
686 va_list ap; /* Argument pointer */
687
688
689 va_start(ap, message);
690 vsnprintf(buffer, sizeof(buffer), message, ap);
691 va_end(ap);
692
a166e933
MS
693 if (v->errorcb)
694 (*v->errorcb)(f, user_data, buffer);
fd96ad89
MS
695 else
696 fprintf(stderr, "%s\n", buffer);
697}