]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/ppd.c
Documentation updates (STR #4691, STR #4693)
[thirdparty/cups.git] / cups / ppd.c
1 /*
2 * "$Id$"
3 *
4 * PPD file routines for CUPS.
5 *
6 * Copyright 2007-2015 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
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 * PostScript is a trademark of Adobe Systems, Inc.
16 *
17 * This code and any derivative of it may be used and distributed
18 * freely under the terms of the GNU General Public License when
19 * used with GNU Ghostscript or its derivatives. Use of the code
20 * (or any derivative of it) with software other than GNU
21 * GhostScript (or its derivatives) is governed by the CUPS license
22 * agreement.
23 *
24 * This file is subject to the Apple OS-Developed Software exception.
25 */
26
27 /*
28 * Include necessary headers.
29 */
30
31 #include "cups-private.h"
32 #include "ppd-private.h"
33
34
35 /*
36 * Definitions...
37 */
38
39 #define ppd_free(p) if (p) free(p) /* Safe free macro */
40
41 #define PPD_KEYWORD 1 /* Line contained a keyword */
42 #define PPD_OPTION 2 /* Line contained an option name */
43 #define PPD_TEXT 4 /* Line contained human-readable text */
44 #define PPD_STRING 8 /* Line contained a string or code */
45
46 #define PPD_HASHSIZE 512 /* Size of hash */
47
48
49 /*
50 * Line buffer structure...
51 */
52
53 typedef struct _ppd_line_s
54 {
55 char *buffer; /* Pointer to buffer */
56 size_t bufsize; /* Size of the buffer */
57 } _ppd_line_t;
58
59
60 /*
61 * Local functions...
62 */
63
64 static ppd_attr_t *ppd_add_attr(ppd_file_t *ppd, const char *name,
65 const char *spec, const char *text,
66 const char *value);
67 static ppd_choice_t *ppd_add_choice(ppd_option_t *option, const char *name);
68 static ppd_size_t *ppd_add_size(ppd_file_t *ppd, const char *name);
69 static int ppd_compare_attrs(ppd_attr_t *a, ppd_attr_t *b);
70 static int ppd_compare_choices(ppd_choice_t *a, ppd_choice_t *b);
71 static int ppd_compare_coptions(ppd_coption_t *a,
72 ppd_coption_t *b);
73 static int ppd_compare_options(ppd_option_t *a, ppd_option_t *b);
74 static int ppd_decode(char *string);
75 static void ppd_free_filters(ppd_file_t *ppd);
76 static void ppd_free_group(ppd_group_t *group);
77 static void ppd_free_option(ppd_option_t *option);
78 static ppd_coption_t *ppd_get_coption(ppd_file_t *ppd, const char *name);
79 static ppd_cparam_t *ppd_get_cparam(ppd_coption_t *opt,
80 const char *param,
81 const char *text);
82 static ppd_group_t *ppd_get_group(ppd_file_t *ppd, const char *name,
83 const char *text, _cups_globals_t *cg,
84 cups_encoding_t encoding);
85 static ppd_option_t *ppd_get_option(ppd_group_t *group, const char *name);
86 static int ppd_hash_option(ppd_option_t *option);
87 static int ppd_read(cups_file_t *fp, _ppd_line_t *line,
88 char *keyword, char *option, char *text,
89 char **string, int ignoreblank,
90 _cups_globals_t *cg);
91 static int ppd_update_filters(ppd_file_t *ppd,
92 _cups_globals_t *cg);
93
94
95 /*
96 * 'ppdClose()' - Free all memory used by the PPD file.
97 */
98
99 void
100 ppdClose(ppd_file_t *ppd) /* I - PPD file record */
101 {
102 int i; /* Looping var */
103 ppd_emul_t *emul; /* Current emulation */
104 ppd_group_t *group; /* Current group */
105 char **font; /* Current font */
106 ppd_attr_t **attr; /* Current attribute */
107 ppd_coption_t *coption; /* Current custom option */
108 ppd_cparam_t *cparam; /* Current custom parameter */
109
110
111 /*
112 * Range check arguments...
113 */
114
115 if (!ppd)
116 return;
117
118 /*
119 * Free all strings at the top level...
120 */
121
122 _cupsStrFree(ppd->lang_encoding);
123 _cupsStrFree(ppd->nickname);
124 if (ppd->patches)
125 free(ppd->patches);
126 _cupsStrFree(ppd->jcl_begin);
127 _cupsStrFree(ppd->jcl_end);
128 _cupsStrFree(ppd->jcl_ps);
129
130 /*
131 * Free any emulations...
132 */
133
134 if (ppd->num_emulations > 0)
135 {
136 for (i = ppd->num_emulations, emul = ppd->emulations; i > 0; i --, emul ++)
137 {
138 _cupsStrFree(emul->start);
139 _cupsStrFree(emul->stop);
140 }
141
142 ppd_free(ppd->emulations);
143 }
144
145 /*
146 * Free any UI groups, subgroups, and options...
147 */
148
149 if (ppd->num_groups > 0)
150 {
151 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
152 ppd_free_group(group);
153
154 ppd_free(ppd->groups);
155 }
156
157 cupsArrayDelete(ppd->options);
158 cupsArrayDelete(ppd->marked);
159
160 /*
161 * Free any page sizes...
162 */
163
164 if (ppd->num_sizes > 0)
165 ppd_free(ppd->sizes);
166
167 /*
168 * Free any constraints...
169 */
170
171 if (ppd->num_consts > 0)
172 ppd_free(ppd->consts);
173
174 /*
175 * Free any filters...
176 */
177
178 ppd_free_filters(ppd);
179
180 /*
181 * Free any fonts...
182 */
183
184 if (ppd->num_fonts > 0)
185 {
186 for (i = ppd->num_fonts, font = ppd->fonts; i > 0; i --, font ++)
187 _cupsStrFree(*font);
188
189 ppd_free(ppd->fonts);
190 }
191
192 /*
193 * Free any profiles...
194 */
195
196 if (ppd->num_profiles > 0)
197 ppd_free(ppd->profiles);
198
199 /*
200 * Free any attributes...
201 */
202
203 if (ppd->num_attrs > 0)
204 {
205 for (i = ppd->num_attrs, attr = ppd->attrs; i > 0; i --, attr ++)
206 {
207 _cupsStrFree((*attr)->value);
208 ppd_free(*attr);
209 }
210
211 ppd_free(ppd->attrs);
212 }
213
214 cupsArrayDelete(ppd->sorted_attrs);
215
216 /*
217 * Free custom options...
218 */
219
220 for (coption = (ppd_coption_t *)cupsArrayFirst(ppd->coptions);
221 coption;
222 coption = (ppd_coption_t *)cupsArrayNext(ppd->coptions))
223 {
224 for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
225 cparam;
226 cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
227 {
228 switch (cparam->type)
229 {
230 case PPD_CUSTOM_PASSCODE :
231 case PPD_CUSTOM_PASSWORD :
232 case PPD_CUSTOM_STRING :
233 _cupsStrFree(cparam->current.custom_string);
234 break;
235
236 default :
237 break;
238 }
239
240 free(cparam);
241 }
242
243 cupsArrayDelete(coption->params);
244
245 free(coption);
246 }
247
248 cupsArrayDelete(ppd->coptions);
249
250 /*
251 * Free constraints...
252 */
253
254 if (ppd->cups_uiconstraints)
255 {
256 _ppd_cups_uiconsts_t *consts; /* Current constraints */
257
258
259 for (consts = (_ppd_cups_uiconsts_t *)cupsArrayFirst(ppd->cups_uiconstraints);
260 consts;
261 consts = (_ppd_cups_uiconsts_t *)cupsArrayNext(ppd->cups_uiconstraints))
262 {
263 free(consts->constraints);
264 free(consts);
265 }
266
267 cupsArrayDelete(ppd->cups_uiconstraints);
268 }
269
270 /*
271 * Free any PPD cache/mapping data...
272 */
273
274 if (ppd->cache)
275 _ppdCacheDestroy(ppd->cache);
276
277 /*
278 * Free the whole record...
279 */
280
281 ppd_free(ppd);
282 }
283
284
285 /*
286 * 'ppdErrorString()' - Returns the text associated with a status.
287 *
288 * @since CUPS 1.1.19/OS X 10.3@
289 */
290
291 const char * /* O - Status string */
292 ppdErrorString(ppd_status_t status) /* I - PPD status */
293 {
294 static const char * const messages[] =/* Status messages */
295 {
296 _("OK"),
297 _("Unable to open PPD file"),
298 _("NULL PPD file pointer"),
299 _("Memory allocation error"),
300 _("Missing PPD-Adobe-4.x header"),
301 _("Missing value string"),
302 _("Internal error"),
303 _("Bad OpenGroup"),
304 _("OpenGroup without a CloseGroup first"),
305 _("Bad OpenUI/JCLOpenUI"),
306 _("OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"),
307 _("Bad OrderDependency"),
308 _("Bad UIConstraints"),
309 _("Missing asterisk in column 1"),
310 _("Line longer than the maximum allowed (255 characters)"),
311 _("Illegal control character"),
312 _("Illegal main keyword string"),
313 _("Illegal option keyword string"),
314 _("Illegal translation string"),
315 _("Illegal whitespace character"),
316 _("Bad custom parameter"),
317 _("Missing option keyword"),
318 _("Bad value string"),
319 _("Missing CloseGroup")
320 };
321
322
323 if (status < PPD_OK || status >= PPD_MAX_STATUS)
324 return (_cupsLangString(cupsLangDefault(), _("Unknown")));
325 else
326 return (_cupsLangString(cupsLangDefault(), messages[status]));
327 }
328
329
330 /*
331 * '_ppdGetEncoding()' - Get the CUPS encoding value for the given
332 * LanguageEncoding.
333 */
334
335 cups_encoding_t /* O - CUPS encoding value */
336 _ppdGetEncoding(const char *name) /* I - LanguageEncoding string */
337 {
338 if (!_cups_strcasecmp(name, "ISOLatin1"))
339 return (CUPS_ISO8859_1);
340 else if (!_cups_strcasecmp(name, "ISOLatin2"))
341 return (CUPS_ISO8859_2);
342 else if (!_cups_strcasecmp(name, "ISOLatin5"))
343 return (CUPS_ISO8859_5);
344 else if (!_cups_strcasecmp(name, "JIS83-RKSJ"))
345 return (CUPS_JIS_X0213);
346 else if (!_cups_strcasecmp(name, "MacStandard"))
347 return (CUPS_MAC_ROMAN);
348 else if (!_cups_strcasecmp(name, "WindowsANSI"))
349 return (CUPS_WINDOWS_1252);
350 else
351 return (CUPS_UTF8);
352 }
353
354
355 /*
356 * 'ppdLastError()' - Return the status from the last ppdOpen*().
357 *
358 * @since CUPS 1.1.19/OS X 10.3@
359 */
360
361 ppd_status_t /* O - Status code */
362 ppdLastError(int *line) /* O - Line number */
363 {
364 _cups_globals_t *cg = _cupsGlobals();
365 /* Global data */
366
367
368 if (line)
369 *line = cg->ppd_line;
370
371 return (cg->ppd_status);
372 }
373
374
375 /*
376 * '_ppdOpen()' - Read a PPD file into memory.
377 *
378 * @since CUPS 1.2/OS X 10.5@
379 */
380
381 ppd_file_t * /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
382 _ppdOpen(
383 cups_file_t *fp, /* I - File to read from */
384 _ppd_localization_t localization) /* I - Localization to load */
385 {
386 int i, j, k; /* Looping vars */
387 int count; /* Temporary count */
388 _ppd_line_t line; /* Line buffer */
389 ppd_file_t *ppd; /* PPD file record */
390 ppd_group_t *group, /* Current group */
391 *subgroup; /* Current sub-group */
392 ppd_option_t *option; /* Current option */
393 ppd_choice_t *choice; /* Current choice */
394 ppd_const_t *constraint; /* Current constraint */
395 ppd_size_t *size; /* Current page size */
396 int mask; /* Line data mask */
397 char keyword[PPD_MAX_NAME],
398 /* Keyword from file */
399 name[PPD_MAX_NAME],
400 /* Option from file */
401 text[PPD_MAX_LINE],
402 /* Human-readable text from file */
403 *string, /* Code/text from file */
404 *sptr, /* Pointer into string */
405 *nameptr, /* Pointer into name */
406 *temp, /* Temporary string pointer */
407 **tempfonts; /* Temporary fonts pointer */
408 float order; /* Order dependency number */
409 ppd_section_t section; /* Order dependency section */
410 ppd_profile_t *profile; /* Pointer to color profile */
411 char **filter; /* Pointer to filter */
412 struct lconv *loc; /* Locale data */
413 int ui_keyword; /* Is this line a UI keyword? */
414 cups_lang_t *lang; /* Language data */
415 cups_encoding_t encoding; /* Encoding of PPD file */
416 _cups_globals_t *cg = _cupsGlobals();
417 /* Global data */
418 char custom_name[PPD_MAX_NAME];
419 /* CustomFoo attribute name */
420 ppd_attr_t *custom_attr; /* CustomFoo attribute */
421 char ll[7], /* Base language + '.' */
422 ll_CC[7]; /* Language w/country + '.' */
423 size_t ll_len = 0, /* Base language length */
424 ll_CC_len = 0; /* Language w/country length */
425 static const char * const ui_keywords[] =
426 {
427 #ifdef CUPS_USE_FULL_UI_KEYWORDS_LIST
428 /*
429 * Adobe defines some 41 keywords as "UI", meaning that they are
430 * user interface elements and that they should be treated as such
431 * even if the PPD creator doesn't use Open/CloseUI around them.
432 *
433 * Since this can cause previously invisible options to appear and
434 * confuse users, the default is to only treat the PageSize and
435 * PageRegion keywords this way.
436 */
437 /* Boolean keywords */
438 "BlackSubstitution",
439 "Booklet",
440 "Collate",
441 "ManualFeed",
442 "MirrorPrint",
443 "NegativePrint",
444 "Sorter",
445 "TraySwitch",
446
447 /* PickOne keywords */
448 "AdvanceMedia",
449 "BindColor",
450 "BindEdge",
451 "BindType",
452 "BindWhen",
453 "BitsPerPixel",
454 "ColorModel",
455 "CutMedia",
456 "Duplex",
457 "FoldType",
458 "FoldWhen",
459 "InputSlot",
460 "JCLFrameBufferSize",
461 "JCLResolution",
462 "Jog",
463 "MediaColor",
464 "MediaType",
465 "MediaWeight",
466 "OutputBin",
467 "OutputMode",
468 "OutputOrder",
469 "PageRegion",
470 "PageSize",
471 "Resolution",
472 "Separations",
473 "Signature",
474 "Slipsheet",
475 "Smoothing",
476 "StapleLocation",
477 "StapleOrientation",
478 "StapleWhen",
479 "StapleX",
480 "StapleY"
481 #else /* !CUPS_USE_FULL_UI_KEYWORDS_LIST */
482 "PageRegion",
483 "PageSize"
484 #endif /* CUPS_USE_FULL_UI_KEYWORDS_LIST */
485 };
486 static const char * const color_keywords[] = /* Keywords associated with color profiles */
487 {
488 ".cupsICCProfile",
489 ".ColorModel",
490 };
491
492
493 DEBUG_printf(("_ppdOpen(fp=%p)", fp));
494
495 /*
496 * Default to "OK" status...
497 */
498
499 cg->ppd_status = PPD_OK;
500 cg->ppd_line = 0;
501
502 /*
503 * Range check input...
504 */
505
506 if (fp == NULL)
507 {
508 cg->ppd_status = PPD_NULL_FILE;
509 return (NULL);
510 }
511
512 /*
513 * If only loading a single localization set up the strings to match...
514 */
515
516 if (localization == _PPD_LOCALIZATION_DEFAULT)
517 {
518 if ((lang = cupsLangDefault()) == NULL)
519 return (NULL);
520
521 snprintf(ll_CC, sizeof(ll_CC), "%s.", lang->language);
522
523 /*
524 * <rdar://problem/22130168>
525 *
526 * Need to use a different base language for some locales...
527 */
528
529 if (!strcmp(lang->language, "zh_HK"))
530 strlcpy(ll, "zh_TW.", sizeof(ll));
531 else
532 snprintf(ll, sizeof(ll), "%2.2s.", lang->language);
533
534 ll_CC_len = strlen(ll_CC);
535 ll_len = strlen(ll);
536
537 DEBUG_printf(("2_ppdOpen: Loading localizations matching \"%s\" and \"%s\"",
538 ll_CC, ll));
539 }
540
541 /*
542 * Grab the first line and make sure it reads '*PPD-Adobe: "major.minor"'...
543 */
544
545 line.buffer = NULL;
546 line.bufsize = 0;
547
548 mask = ppd_read(fp, &line, keyword, name, text, &string, 0, cg);
549
550 DEBUG_printf(("2_ppdOpen: mask=%x, keyword=\"%s\"...", mask, keyword));
551
552 if (mask == 0 ||
553 strcmp(keyword, "PPD-Adobe") ||
554 string == NULL || string[0] != '4')
555 {
556 /*
557 * Either this is not a PPD file, or it is not a 4.x PPD file.
558 */
559
560 if (cg->ppd_status == PPD_OK)
561 cg->ppd_status = PPD_MISSING_PPDADOBE4;
562
563 _cupsStrFree(string);
564 ppd_free(line.buffer);
565
566 return (NULL);
567 }
568
569 DEBUG_printf(("2_ppdOpen: keyword=%s, string=%p", keyword, string));
570
571 _cupsStrFree(string);
572
573 /*
574 * Allocate memory for the PPD file record...
575 */
576
577 if ((ppd = calloc(1, sizeof(ppd_file_t))) == NULL)
578 {
579 cg->ppd_status = PPD_ALLOC_ERROR;
580
581 _cupsStrFree(string);
582 ppd_free(line.buffer);
583
584 return (NULL);
585 }
586
587 ppd->language_level = 2;
588 ppd->color_device = 0;
589 ppd->colorspace = PPD_CS_N;
590 ppd->landscape = -90;
591 ppd->coptions = cupsArrayNew((cups_array_func_t)ppd_compare_coptions,
592 NULL);
593
594 /*
595 * Read lines from the PPD file and add them to the file record...
596 */
597
598 group = NULL;
599 subgroup = NULL;
600 option = NULL;
601 choice = NULL;
602 ui_keyword = 0;
603 encoding = CUPS_ISO8859_1;
604 loc = localeconv();
605
606 while ((mask = ppd_read(fp, &line, keyword, name, text, &string, 1, cg)) != 0)
607 {
608 DEBUG_printf(("2_ppdOpen: mask=%x, keyword=\"%s\", name=\"%s\", "
609 "text=\"%s\", string=%d chars...", mask, keyword, name, text,
610 string ? (int)strlen(string) : 0));
611
612 if (strncmp(keyword, "Default", 7) && !string &&
613 cg->ppd_conform != PPD_CONFORM_RELAXED)
614 {
615 /*
616 * Need a string value!
617 */
618
619 cg->ppd_status = PPD_MISSING_VALUE;
620
621 goto error;
622 }
623 else if (!string)
624 continue;
625
626 /*
627 * Certain main keywords (as defined by the PPD spec) may be used
628 * without the usual OpenUI/CloseUI stuff. Presumably this is just
629 * so that Adobe wouldn't completely break compatibility with PPD
630 * files prior to v4.0 of the spec, but it is hopelessly
631 * inconsistent... Catch these main keywords and automatically
632 * create the corresponding option, as needed...
633 */
634
635 if (ui_keyword)
636 {
637 /*
638 * Previous line was a UI keyword...
639 */
640
641 option = NULL;
642 ui_keyword = 0;
643 }
644
645 /*
646 * If we are filtering out keyword localizations, see if this line needs to
647 * be used...
648 */
649
650 if (localization != _PPD_LOCALIZATION_ALL &&
651 (temp = strchr(keyword, '.')) != NULL &&
652 ((temp - keyword) == 2 || (temp - keyword) == 5) &&
653 _cups_isalpha(keyword[0]) &&
654 _cups_isalpha(keyword[1]) &&
655 (keyword[2] == '.' ||
656 (keyword[2] == '_' && _cups_isalpha(keyword[3]) &&
657 _cups_isalpha(keyword[4]) && keyword[5] == '.')))
658 {
659 if (localization == _PPD_LOCALIZATION_NONE ||
660 (localization == _PPD_LOCALIZATION_DEFAULT &&
661 strncmp(ll_CC, keyword, ll_CC_len) &&
662 strncmp(ll, keyword, ll_len)))
663 {
664 DEBUG_printf(("2_ppdOpen: Ignoring localization: \"%s\"\n", keyword));
665 continue;
666 }
667 else if (localization == _PPD_LOCALIZATION_ICC_PROFILES)
668 {
669 /*
670 * Only load localizations for the color profile related keywords...
671 */
672
673 for (i = 0;
674 i < (int)(sizeof(color_keywords) / sizeof(color_keywords[0]));
675 i ++)
676 {
677 if (!_cups_strcasecmp(temp, color_keywords[i]))
678 break;
679 }
680
681 if (i >= (int)(sizeof(color_keywords) / sizeof(color_keywords[0])))
682 {
683 DEBUG_printf(("2_ppdOpen: Ignoring localization: \"%s\"\n", keyword));
684 continue;
685 }
686 }
687 }
688
689 if (option == NULL &&
690 (mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) ==
691 (PPD_KEYWORD | PPD_OPTION | PPD_STRING))
692 {
693 for (i = 0; i < (int)(sizeof(ui_keywords) / sizeof(ui_keywords[0])); i ++)
694 if (!strcmp(keyword, ui_keywords[i]))
695 break;
696
697 if (i < (int)(sizeof(ui_keywords) / sizeof(ui_keywords[0])))
698 {
699 /*
700 * Create the option in the appropriate group...
701 */
702
703 ui_keyword = 1;
704
705 DEBUG_printf(("2_ppdOpen: FOUND ADOBE UI KEYWORD %s WITHOUT OPENUI!",
706 keyword));
707
708 if (!group)
709 {
710 if ((group = ppd_get_group(ppd, "General", _("General"), cg,
711 encoding)) == NULL)
712 goto error;
713
714 DEBUG_printf(("2_ppdOpen: Adding to group %s...", group->text));
715 option = ppd_get_option(group, keyword);
716 group = NULL;
717 }
718 else
719 option = ppd_get_option(group, keyword);
720
721 if (option == NULL)
722 {
723 cg->ppd_status = PPD_ALLOC_ERROR;
724
725 goto error;
726 }
727
728 /*
729 * Now fill in the initial information for the option...
730 */
731
732 if (!strncmp(keyword, "JCL", 3))
733 option->section = PPD_ORDER_JCL;
734 else
735 option->section = PPD_ORDER_ANY;
736
737 option->order = 10.0f;
738
739 if (i < 8)
740 option->ui = PPD_UI_BOOLEAN;
741 else
742 option->ui = PPD_UI_PICKONE;
743
744 for (j = 0; j < ppd->num_attrs; j ++)
745 if (!strncmp(ppd->attrs[j]->name, "Default", 7) &&
746 !strcmp(ppd->attrs[j]->name + 7, keyword) &&
747 ppd->attrs[j]->value)
748 {
749 DEBUG_printf(("2_ppdOpen: Setting Default%s to %s via attribute...",
750 option->keyword, ppd->attrs[j]->value));
751 strlcpy(option->defchoice, ppd->attrs[j]->value,
752 sizeof(option->defchoice));
753 break;
754 }
755
756 if (!strcmp(keyword, "PageSize"))
757 strlcpy(option->text, _("Media Size"), sizeof(option->text));
758 else if (!strcmp(keyword, "MediaType"))
759 strlcpy(option->text, _("Media Type"), sizeof(option->text));
760 else if (!strcmp(keyword, "InputSlot"))
761 strlcpy(option->text, _("Media Source"), sizeof(option->text));
762 else if (!strcmp(keyword, "ColorModel"))
763 strlcpy(option->text, _("Output Mode"), sizeof(option->text));
764 else if (!strcmp(keyword, "Resolution"))
765 strlcpy(option->text, _("Resolution"), sizeof(option->text));
766 else
767 strlcpy(option->text, keyword, sizeof(option->text));
768 }
769 }
770
771 if (!strcmp(keyword, "LanguageLevel"))
772 ppd->language_level = atoi(string);
773 else if (!strcmp(keyword, "LanguageEncoding"))
774 {
775 /*
776 * Say all PPD files are UTF-8, since we convert to UTF-8...
777 */
778
779 ppd->lang_encoding = _cupsStrAlloc("UTF-8");
780 encoding = _ppdGetEncoding(string);
781 }
782 else if (!strcmp(keyword, "LanguageVersion"))
783 ppd->lang_version = string;
784 else if (!strcmp(keyword, "Manufacturer"))
785 ppd->manufacturer = string;
786 else if (!strcmp(keyword, "ModelName"))
787 ppd->modelname = string;
788 else if (!strcmp(keyword, "Protocols"))
789 ppd->protocols = string;
790 else if (!strcmp(keyword, "PCFileName"))
791 ppd->pcfilename = string;
792 else if (!strcmp(keyword, "NickName"))
793 {
794 if (encoding != CUPS_UTF8)
795 {
796 cups_utf8_t utf8[256]; /* UTF-8 version of NickName */
797
798
799 cupsCharsetToUTF8(utf8, string, sizeof(utf8), encoding);
800 ppd->nickname = _cupsStrAlloc((char *)utf8);
801 }
802 else
803 ppd->nickname = _cupsStrAlloc(string);
804 }
805 else if (!strcmp(keyword, "Product"))
806 ppd->product = string;
807 else if (!strcmp(keyword, "ShortNickName"))
808 ppd->shortnickname = string;
809 else if (!strcmp(keyword, "TTRasterizer"))
810 ppd->ttrasterizer = string;
811 else if (!strcmp(keyword, "JCLBegin"))
812 {
813 ppd->jcl_begin = _cupsStrAlloc(string);
814 ppd_decode(ppd->jcl_begin); /* Decode quoted string */
815 }
816 else if (!strcmp(keyword, "JCLEnd"))
817 {
818 ppd->jcl_end = _cupsStrAlloc(string);
819 ppd_decode(ppd->jcl_end); /* Decode quoted string */
820 }
821 else if (!strcmp(keyword, "JCLToPSInterpreter"))
822 {
823 ppd->jcl_ps = _cupsStrAlloc(string);
824 ppd_decode(ppd->jcl_ps); /* Decode quoted string */
825 }
826 else if (!strcmp(keyword, "AccurateScreensSupport"))
827 ppd->accurate_screens = !strcmp(string, "True");
828 else if (!strcmp(keyword, "ColorDevice"))
829 ppd->color_device = !strcmp(string, "True");
830 else if (!strcmp(keyword, "ContoneOnly"))
831 ppd->contone_only = !strcmp(string, "True");
832 else if (!strcmp(keyword, "cupsFlipDuplex"))
833 ppd->flip_duplex = !strcmp(string, "True");
834 else if (!strcmp(keyword, "cupsManualCopies"))
835 ppd->manual_copies = !strcmp(string, "True");
836 else if (!strcmp(keyword, "cupsModelNumber"))
837 ppd->model_number = atoi(string);
838 else if (!strcmp(keyword, "cupsColorProfile"))
839 {
840 if (ppd->num_profiles == 0)
841 profile = malloc(sizeof(ppd_profile_t));
842 else
843 profile = realloc(ppd->profiles, sizeof(ppd_profile_t) * (size_t)(ppd->num_profiles + 1));
844
845 if (!profile)
846 {
847 cg->ppd_status = PPD_ALLOC_ERROR;
848
849 goto error;
850 }
851
852 ppd->profiles = profile;
853 profile += ppd->num_profiles;
854 ppd->num_profiles ++;
855
856 memset(profile, 0, sizeof(ppd_profile_t));
857 strlcpy(profile->resolution, name, sizeof(profile->resolution));
858 strlcpy(profile->media_type, text, sizeof(profile->media_type));
859
860 profile->density = (float)_cupsStrScand(string, &sptr, loc);
861 profile->gamma = (float)_cupsStrScand(sptr, &sptr, loc);
862 profile->matrix[0][0] = (float)_cupsStrScand(sptr, &sptr, loc);
863 profile->matrix[0][1] = (float)_cupsStrScand(sptr, &sptr, loc);
864 profile->matrix[0][2] = (float)_cupsStrScand(sptr, &sptr, loc);
865 profile->matrix[1][0] = (float)_cupsStrScand(sptr, &sptr, loc);
866 profile->matrix[1][1] = (float)_cupsStrScand(sptr, &sptr, loc);
867 profile->matrix[1][2] = (float)_cupsStrScand(sptr, &sptr, loc);
868 profile->matrix[2][0] = (float)_cupsStrScand(sptr, &sptr, loc);
869 profile->matrix[2][1] = (float)_cupsStrScand(sptr, &sptr, loc);
870 profile->matrix[2][2] = (float)_cupsStrScand(sptr, &sptr, loc);
871 }
872 else if (!strcmp(keyword, "cupsFilter"))
873 {
874 if (ppd->num_filters == 0)
875 filter = malloc(sizeof(char *));
876 else
877 filter = realloc(ppd->filters, sizeof(char *) * (size_t)(ppd->num_filters + 1));
878
879 if (filter == NULL)
880 {
881 cg->ppd_status = PPD_ALLOC_ERROR;
882
883 goto error;
884 }
885
886 ppd->filters = filter;
887 filter += ppd->num_filters;
888 ppd->num_filters ++;
889
890 /*
891 * Retain a copy of the filter string...
892 */
893
894 *filter = _cupsStrRetain(string);
895 }
896 else if (!strcmp(keyword, "Throughput"))
897 ppd->throughput = atoi(string);
898 else if (!strcmp(keyword, "Font"))
899 {
900 /*
901 * Add this font to the list of available fonts...
902 */
903
904 if (ppd->num_fonts == 0)
905 tempfonts = (char **)malloc(sizeof(char *));
906 else
907 tempfonts = (char **)realloc(ppd->fonts, sizeof(char *) * (size_t)(ppd->num_fonts + 1));
908
909 if (tempfonts == NULL)
910 {
911 cg->ppd_status = PPD_ALLOC_ERROR;
912
913 goto error;
914 }
915
916 ppd->fonts = tempfonts;
917 ppd->fonts[ppd->num_fonts] = _cupsStrAlloc(name);
918 ppd->num_fonts ++;
919 }
920 else if (!strncmp(keyword, "ParamCustom", 11))
921 {
922 ppd_coption_t *coption; /* Custom option */
923 ppd_cparam_t *cparam; /* Custom parameter */
924 int corder; /* Order number */
925 char ctype[33], /* Data type */
926 cminimum[65], /* Minimum value */
927 cmaximum[65]; /* Maximum value */
928
929
930 /*
931 * Get the custom option and parameter...
932 */
933
934 if ((coption = ppd_get_coption(ppd, keyword + 11)) == NULL)
935 {
936 cg->ppd_status = PPD_ALLOC_ERROR;
937
938 goto error;
939 }
940
941 if ((cparam = ppd_get_cparam(coption, name, text)) == NULL)
942 {
943 cg->ppd_status = PPD_ALLOC_ERROR;
944
945 goto error;
946 }
947
948 /*
949 * Get the parameter data...
950 */
951
952 if (!string ||
953 sscanf(string, "%d%32s%64s%64s", &corder, ctype, cminimum,
954 cmaximum) != 4)
955 {
956 cg->ppd_status = PPD_BAD_CUSTOM_PARAM;
957
958 goto error;
959 }
960
961 cparam->order = corder;
962
963 if (!strcmp(ctype, "curve"))
964 {
965 cparam->type = PPD_CUSTOM_CURVE;
966 cparam->minimum.custom_curve = (float)_cupsStrScand(cminimum, NULL, loc);
967 cparam->maximum.custom_curve = (float)_cupsStrScand(cmaximum, NULL, loc);
968 }
969 else if (!strcmp(ctype, "int"))
970 {
971 cparam->type = PPD_CUSTOM_INT;
972 cparam->minimum.custom_int = atoi(cminimum);
973 cparam->maximum.custom_int = atoi(cmaximum);
974 }
975 else if (!strcmp(ctype, "invcurve"))
976 {
977 cparam->type = PPD_CUSTOM_INVCURVE;
978 cparam->minimum.custom_invcurve = (float)_cupsStrScand(cminimum, NULL, loc);
979 cparam->maximum.custom_invcurve = (float)_cupsStrScand(cmaximum, NULL, loc);
980 }
981 else if (!strcmp(ctype, "passcode"))
982 {
983 cparam->type = PPD_CUSTOM_PASSCODE;
984 cparam->minimum.custom_passcode = atoi(cminimum);
985 cparam->maximum.custom_passcode = atoi(cmaximum);
986 }
987 else if (!strcmp(ctype, "password"))
988 {
989 cparam->type = PPD_CUSTOM_PASSWORD;
990 cparam->minimum.custom_password = atoi(cminimum);
991 cparam->maximum.custom_password = atoi(cmaximum);
992 }
993 else if (!strcmp(ctype, "points"))
994 {
995 cparam->type = PPD_CUSTOM_POINTS;
996 cparam->minimum.custom_points = (float)_cupsStrScand(cminimum, NULL, loc);
997 cparam->maximum.custom_points = (float)_cupsStrScand(cmaximum, NULL, loc);
998 }
999 else if (!strcmp(ctype, "real"))
1000 {
1001 cparam->type = PPD_CUSTOM_REAL;
1002 cparam->minimum.custom_real = (float)_cupsStrScand(cminimum, NULL, loc);
1003 cparam->maximum.custom_real = (float)_cupsStrScand(cmaximum, NULL, loc);
1004 }
1005 else if (!strcmp(ctype, "string"))
1006 {
1007 cparam->type = PPD_CUSTOM_STRING;
1008 cparam->minimum.custom_string = atoi(cminimum);
1009 cparam->maximum.custom_string = atoi(cmaximum);
1010 }
1011 else
1012 {
1013 cg->ppd_status = PPD_BAD_CUSTOM_PARAM;
1014
1015 goto error;
1016 }
1017
1018 /*
1019 * Now special-case for CustomPageSize...
1020 */
1021
1022 if (!strcmp(coption->keyword, "PageSize"))
1023 {
1024 if (!strcmp(name, "Width"))
1025 {
1026 ppd->custom_min[0] = cparam->minimum.custom_points;
1027 ppd->custom_max[0] = cparam->maximum.custom_points;
1028 }
1029 else if (!strcmp(name, "Height"))
1030 {
1031 ppd->custom_min[1] = cparam->minimum.custom_points;
1032 ppd->custom_max[1] = cparam->maximum.custom_points;
1033 }
1034 }
1035 }
1036 else if (!strcmp(keyword, "HWMargins"))
1037 {
1038 for (i = 0, sptr = string; i < 4; i ++)
1039 ppd->custom_margins[i] = (float)_cupsStrScand(sptr, &sptr, loc);
1040 }
1041 else if (!strncmp(keyword, "Custom", 6) && !strcmp(name, "True") && !option)
1042 {
1043 ppd_option_t *custom_option; /* Custom option */
1044
1045 DEBUG_puts("2_ppdOpen: Processing Custom option...");
1046
1047 /*
1048 * Get the option and custom option...
1049 */
1050
1051 if (!ppd_get_coption(ppd, keyword + 6))
1052 {
1053 cg->ppd_status = PPD_ALLOC_ERROR;
1054
1055 goto error;
1056 }
1057
1058 if (option && !_cups_strcasecmp(option->keyword, keyword + 6))
1059 custom_option = option;
1060 else
1061 custom_option = ppdFindOption(ppd, keyword + 6);
1062
1063 if (custom_option)
1064 {
1065 /*
1066 * Add the "custom" option...
1067 */
1068
1069 if ((choice = ppdFindChoice(custom_option, "Custom")) == NULL)
1070 if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL)
1071 {
1072 DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
1073
1074 cg->ppd_status = PPD_ALLOC_ERROR;
1075
1076 goto error;
1077 }
1078
1079 strlcpy(choice->text, text[0] ? text : _("Custom"),
1080 sizeof(choice->text));
1081
1082 choice->code = _cupsStrAlloc(string);
1083
1084 if (custom_option->section == PPD_ORDER_JCL)
1085 ppd_decode(choice->code);
1086 }
1087
1088 /*
1089 * Now process custom page sizes specially...
1090 */
1091
1092 if (!strcmp(keyword, "CustomPageSize"))
1093 {
1094 /*
1095 * Add a "Custom" page size entry...
1096 */
1097
1098 ppd->variable_sizes = 1;
1099
1100 ppd_add_size(ppd, "Custom");
1101
1102 if (option && !_cups_strcasecmp(option->keyword, "PageRegion"))
1103 custom_option = option;
1104 else
1105 custom_option = ppdFindOption(ppd, "PageRegion");
1106
1107 if (custom_option)
1108 {
1109 if ((choice = ppdFindChoice(custom_option, "Custom")) == NULL)
1110 if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL)
1111 {
1112 DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
1113
1114 cg->ppd_status = PPD_ALLOC_ERROR;
1115
1116 goto error;
1117 }
1118
1119 strlcpy(choice->text, text[0] ? text : _("Custom"),
1120 sizeof(choice->text));
1121 }
1122 }
1123 }
1124 else if (!strcmp(keyword, "LandscapeOrientation"))
1125 {
1126 if (!strcmp(string, "Minus90"))
1127 ppd->landscape = -90;
1128 else if (!strcmp(string, "Plus90"))
1129 ppd->landscape = 90;
1130 }
1131 else if (!strcmp(keyword, "Emulators") && string)
1132 {
1133 for (count = 1, sptr = string; sptr != NULL;)
1134 if ((sptr = strchr(sptr, ' ')) != NULL)
1135 {
1136 count ++;
1137 while (*sptr == ' ')
1138 sptr ++;
1139 }
1140
1141 ppd->num_emulations = count;
1142 if ((ppd->emulations = calloc((size_t)count, sizeof(ppd_emul_t))) == NULL)
1143 {
1144 cg->ppd_status = PPD_ALLOC_ERROR;
1145
1146 goto error;
1147 }
1148
1149 for (i = 0, sptr = string; i < count; i ++)
1150 {
1151 for (nameptr = ppd->emulations[i].name;
1152 *sptr != '\0' && *sptr != ' ';
1153 sptr ++)
1154 if (nameptr < (ppd->emulations[i].name + sizeof(ppd->emulations[i].name) - 1))
1155 *nameptr++ = *sptr;
1156
1157 *nameptr = '\0';
1158
1159 while (*sptr == ' ')
1160 sptr ++;
1161 }
1162 }
1163 else if (!strncmp(keyword, "StartEmulator_", 14))
1164 {
1165 ppd_decode(string);
1166
1167 for (i = 0; i < ppd->num_emulations; i ++)
1168 if (!strcmp(keyword + 14, ppd->emulations[i].name))
1169 {
1170 ppd->emulations[i].start = string;
1171 string = NULL;
1172 }
1173 }
1174 else if (!strncmp(keyword, "StopEmulator_", 13))
1175 {
1176 ppd_decode(string);
1177
1178 for (i = 0; i < ppd->num_emulations; i ++)
1179 if (!strcmp(keyword + 13, ppd->emulations[i].name))
1180 {
1181 ppd->emulations[i].stop = string;
1182 string = NULL;
1183 }
1184 }
1185 else if (!strcmp(keyword, "JobPatchFile"))
1186 {
1187 /*
1188 * CUPS STR #3421: Check for "*JobPatchFile: int: string"
1189 */
1190
1191 if (isdigit(*string & 255))
1192 {
1193 for (sptr = string + 1; isdigit(*sptr & 255); sptr ++);
1194
1195 if (*sptr == ':')
1196 {
1197 /*
1198 * Found "*JobPatchFile: int: string"...
1199 */
1200
1201 cg->ppd_status = PPD_BAD_VALUE;
1202
1203 goto error;
1204 }
1205 }
1206
1207 if (!name[0] && cg->ppd_conform == PPD_CONFORM_STRICT)
1208 {
1209 /*
1210 * Found "*JobPatchFile: string"...
1211 */
1212
1213 cg->ppd_status = PPD_MISSING_OPTION_KEYWORD;
1214
1215 goto error;
1216 }
1217
1218 if (ppd->patches == NULL)
1219 ppd->patches = strdup(string);
1220 else
1221 {
1222 temp = realloc(ppd->patches, strlen(ppd->patches) +
1223 strlen(string) + 1);
1224 if (temp == NULL)
1225 {
1226 cg->ppd_status = PPD_ALLOC_ERROR;
1227
1228 goto error;
1229 }
1230
1231 ppd->patches = temp;
1232
1233 memcpy(ppd->patches + strlen(ppd->patches), string, strlen(string) + 1);
1234 }
1235 }
1236 else if (!strcmp(keyword, "OpenUI"))
1237 {
1238 /*
1239 * Don't allow nesting of options...
1240 */
1241
1242 if (option && cg->ppd_conform == PPD_CONFORM_STRICT)
1243 {
1244 cg->ppd_status = PPD_NESTED_OPEN_UI;
1245
1246 goto error;
1247 }
1248
1249 /*
1250 * Add an option record to the current sub-group, group, or file...
1251 */
1252
1253 DEBUG_printf(("2_ppdOpen: name=\"%s\" (%d)", name, (int)strlen(name)));
1254
1255 if (name[0] == '*')
1256 _cups_strcpy(name, name + 1); /* Eliminate leading asterisk */
1257
1258 for (i = (int)strlen(name) - 1; i > 0 && _cups_isspace(name[i]); i --)
1259 name[i] = '\0'; /* Eliminate trailing spaces */
1260
1261 DEBUG_printf(("2_ppdOpen: OpenUI of %s in group %s...", name,
1262 group ? group->text : "(null)"));
1263
1264 if (subgroup != NULL)
1265 option = ppd_get_option(subgroup, name);
1266 else if (group == NULL)
1267 {
1268 if ((group = ppd_get_group(ppd, "General", _("General"), cg,
1269 encoding)) == NULL)
1270 goto error;
1271
1272 DEBUG_printf(("2_ppdOpen: Adding to group %s...", group->text));
1273 option = ppd_get_option(group, name);
1274 group = NULL;
1275 }
1276 else
1277 option = ppd_get_option(group, name);
1278
1279 if (option == NULL)
1280 {
1281 cg->ppd_status = PPD_ALLOC_ERROR;
1282
1283 goto error;
1284 }
1285
1286 /*
1287 * Now fill in the initial information for the option...
1288 */
1289
1290 if (string && !strcmp(string, "PickMany"))
1291 option->ui = PPD_UI_PICKMANY;
1292 else if (string && !strcmp(string, "Boolean"))
1293 option->ui = PPD_UI_BOOLEAN;
1294 else if (string && !strcmp(string, "PickOne"))
1295 option->ui = PPD_UI_PICKONE;
1296 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1297 {
1298 cg->ppd_status = PPD_BAD_OPEN_UI;
1299
1300 goto error;
1301 }
1302 else
1303 option->ui = PPD_UI_PICKONE;
1304
1305 for (j = 0; j < ppd->num_attrs; j ++)
1306 if (!strncmp(ppd->attrs[j]->name, "Default", 7) &&
1307 !strcmp(ppd->attrs[j]->name + 7, name) &&
1308 ppd->attrs[j]->value)
1309 {
1310 DEBUG_printf(("2_ppdOpen: Setting Default%s to %s via attribute...",
1311 option->keyword, ppd->attrs[j]->value));
1312 strlcpy(option->defchoice, ppd->attrs[j]->value,
1313 sizeof(option->defchoice));
1314 break;
1315 }
1316
1317 if (text[0])
1318 cupsCharsetToUTF8((cups_utf8_t *)option->text, text,
1319 sizeof(option->text), encoding);
1320 else
1321 {
1322 if (!strcmp(name, "PageSize"))
1323 strlcpy(option->text, _("Media Size"), sizeof(option->text));
1324 else if (!strcmp(name, "MediaType"))
1325 strlcpy(option->text, _("Media Type"), sizeof(option->text));
1326 else if (!strcmp(name, "InputSlot"))
1327 strlcpy(option->text, _("Media Source"), sizeof(option->text));
1328 else if (!strcmp(name, "ColorModel"))
1329 strlcpy(option->text, _("Output Mode"), sizeof(option->text));
1330 else if (!strcmp(name, "Resolution"))
1331 strlcpy(option->text, _("Resolution"), sizeof(option->text));
1332 else
1333 strlcpy(option->text, name, sizeof(option->text));
1334 }
1335
1336 option->section = PPD_ORDER_ANY;
1337
1338 _cupsStrFree(string);
1339 string = NULL;
1340
1341 /*
1342 * Add a custom option choice if we have already seen a CustomFoo
1343 * attribute...
1344 */
1345
1346 if (!_cups_strcasecmp(name, "PageRegion"))
1347 strlcpy(custom_name, "CustomPageSize", sizeof(custom_name));
1348 else
1349 snprintf(custom_name, sizeof(custom_name), "Custom%s", name);
1350
1351 if ((custom_attr = ppdFindAttr(ppd, custom_name, "True")) != NULL)
1352 {
1353 if ((choice = ppdFindChoice(option, "Custom")) == NULL)
1354 if ((choice = ppd_add_choice(option, "Custom")) == NULL)
1355 {
1356 DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
1357
1358 cg->ppd_status = PPD_ALLOC_ERROR;
1359
1360 goto error;
1361 }
1362
1363 strlcpy(choice->text,
1364 custom_attr->text[0] ? custom_attr->text : _("Custom"),
1365 sizeof(choice->text));
1366 choice->code = _cupsStrRetain(custom_attr->value);
1367 }
1368 }
1369 else if (!strcmp(keyword, "JCLOpenUI"))
1370 {
1371 /*
1372 * Don't allow nesting of options...
1373 */
1374
1375 if (option && cg->ppd_conform == PPD_CONFORM_STRICT)
1376 {
1377 cg->ppd_status = PPD_NESTED_OPEN_UI;
1378
1379 goto error;
1380 }
1381
1382 /*
1383 * Find the JCL group, and add if needed...
1384 */
1385
1386 group = ppd_get_group(ppd, "JCL", _("JCL"), cg, encoding);
1387
1388 if (group == NULL)
1389 goto error;
1390
1391 /*
1392 * Add an option record to the current JCLs...
1393 */
1394
1395 if (name[0] == '*')
1396 _cups_strcpy(name, name + 1);
1397
1398 option = ppd_get_option(group, name);
1399
1400 if (option == NULL)
1401 {
1402 cg->ppd_status = PPD_ALLOC_ERROR;
1403
1404 goto error;
1405 }
1406
1407 /*
1408 * Now fill in the initial information for the option...
1409 */
1410
1411 if (string && !strcmp(string, "PickMany"))
1412 option->ui = PPD_UI_PICKMANY;
1413 else if (string && !strcmp(string, "Boolean"))
1414 option->ui = PPD_UI_BOOLEAN;
1415 else if (string && !strcmp(string, "PickOne"))
1416 option->ui = PPD_UI_PICKONE;
1417 else
1418 {
1419 cg->ppd_status = PPD_BAD_OPEN_UI;
1420
1421 goto error;
1422 }
1423
1424 for (j = 0; j < ppd->num_attrs; j ++)
1425 if (!strncmp(ppd->attrs[j]->name, "Default", 7) &&
1426 !strcmp(ppd->attrs[j]->name + 7, name) &&
1427 ppd->attrs[j]->value)
1428 {
1429 DEBUG_printf(("2_ppdOpen: Setting Default%s to %s via attribute...",
1430 option->keyword, ppd->attrs[j]->value));
1431 strlcpy(option->defchoice, ppd->attrs[j]->value,
1432 sizeof(option->defchoice));
1433 break;
1434 }
1435
1436 if (text[0])
1437 cupsCharsetToUTF8((cups_utf8_t *)option->text, text,
1438 sizeof(option->text), encoding);
1439 else
1440 strlcpy(option->text, name, sizeof(option->text));
1441
1442 option->section = PPD_ORDER_JCL;
1443 group = NULL;
1444
1445 _cupsStrFree(string);
1446 string = NULL;
1447
1448 /*
1449 * Add a custom option choice if we have already seen a CustomFoo
1450 * attribute...
1451 */
1452
1453 snprintf(custom_name, sizeof(custom_name), "Custom%s", name);
1454
1455 if ((custom_attr = ppdFindAttr(ppd, custom_name, "True")) != NULL)
1456 {
1457 if ((choice = ppd_add_choice(option, "Custom")) == NULL)
1458 {
1459 DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
1460
1461 cg->ppd_status = PPD_ALLOC_ERROR;
1462
1463 goto error;
1464 }
1465
1466 strlcpy(choice->text,
1467 custom_attr->text[0] ? custom_attr->text : _("Custom"),
1468 sizeof(choice->text));
1469 choice->code = _cupsStrRetain(custom_attr->value);
1470 }
1471 }
1472 else if (!strcmp(keyword, "CloseUI") || !strcmp(keyword, "JCLCloseUI"))
1473 {
1474 option = NULL;
1475
1476 _cupsStrFree(string);
1477 string = NULL;
1478 }
1479 else if (!strcmp(keyword, "OpenGroup"))
1480 {
1481 /*
1482 * Open a new group...
1483 */
1484
1485 if (group != NULL)
1486 {
1487 cg->ppd_status = PPD_NESTED_OPEN_GROUP;
1488
1489 goto error;
1490 }
1491
1492 if (!string)
1493 {
1494 cg->ppd_status = PPD_BAD_OPEN_GROUP;
1495
1496 goto error;
1497 }
1498
1499 /*
1500 * Separate the group name from the text (name/text)...
1501 */
1502
1503 if ((sptr = strchr(string, '/')) != NULL)
1504 *sptr++ = '\0';
1505 else
1506 sptr = string;
1507
1508 /*
1509 * Fix up the text...
1510 */
1511
1512 ppd_decode(sptr);
1513
1514 /*
1515 * Find/add the group...
1516 */
1517
1518 group = ppd_get_group(ppd, string, sptr, cg, encoding);
1519
1520 if (group == NULL)
1521 goto error;
1522
1523 _cupsStrFree(string);
1524 string = NULL;
1525 }
1526 else if (!strcmp(keyword, "CloseGroup"))
1527 {
1528 group = NULL;
1529
1530 _cupsStrFree(string);
1531 string = NULL;
1532 }
1533 else if (!strcmp(keyword, "OrderDependency"))
1534 {
1535 order = (float)_cupsStrScand(string, &sptr, loc);
1536
1537 if (!sptr || sscanf(sptr, "%40s%40s", name, keyword) != 2)
1538 {
1539 cg->ppd_status = PPD_BAD_ORDER_DEPENDENCY;
1540
1541 goto error;
1542 }
1543
1544 if (keyword[0] == '*')
1545 _cups_strcpy(keyword, keyword + 1);
1546
1547 if (!strcmp(name, "ExitServer"))
1548 section = PPD_ORDER_EXIT;
1549 else if (!strcmp(name, "Prolog"))
1550 section = PPD_ORDER_PROLOG;
1551 else if (!strcmp(name, "DocumentSetup"))
1552 section = PPD_ORDER_DOCUMENT;
1553 else if (!strcmp(name, "PageSetup"))
1554 section = PPD_ORDER_PAGE;
1555 else if (!strcmp(name, "JCLSetup"))
1556 section = PPD_ORDER_JCL;
1557 else
1558 section = PPD_ORDER_ANY;
1559
1560 if (option == NULL)
1561 {
1562 ppd_group_t *gtemp;
1563
1564
1565 /*
1566 * Only valid for Non-UI options...
1567 */
1568
1569 for (i = ppd->num_groups, gtemp = ppd->groups; i > 0; i --, gtemp ++)
1570 if (gtemp->text[0] == '\0')
1571 break;
1572
1573 if (i > 0)
1574 for (i = 0; i < gtemp->num_options; i ++)
1575 if (!strcmp(keyword, gtemp->options[i].keyword))
1576 {
1577 gtemp->options[i].section = section;
1578 gtemp->options[i].order = order;
1579 break;
1580 }
1581 }
1582 else
1583 {
1584 option->section = section;
1585 option->order = order;
1586 }
1587
1588 _cupsStrFree(string);
1589 string = NULL;
1590 }
1591 else if (!strncmp(keyword, "Default", 7))
1592 {
1593 if (string == NULL)
1594 continue;
1595
1596 /*
1597 * Drop UI text, if any, from value...
1598 */
1599
1600 if (strchr(string, '/') != NULL)
1601 *strchr(string, '/') = '\0';
1602
1603 /*
1604 * Assign the default value as appropriate...
1605 */
1606
1607 if (!strcmp(keyword, "DefaultColorSpace"))
1608 {
1609 /*
1610 * Set default colorspace...
1611 */
1612
1613 if (!strcmp(string, "CMY"))
1614 ppd->colorspace = PPD_CS_CMY;
1615 else if (!strcmp(string, "CMYK"))
1616 ppd->colorspace = PPD_CS_CMYK;
1617 else if (!strcmp(string, "RGB"))
1618 ppd->colorspace = PPD_CS_RGB;
1619 else if (!strcmp(string, "RGBK"))
1620 ppd->colorspace = PPD_CS_RGBK;
1621 else if (!strcmp(string, "N"))
1622 ppd->colorspace = PPD_CS_N;
1623 else
1624 ppd->colorspace = PPD_CS_GRAY;
1625 }
1626 else if (option && !strcmp(keyword + 7, option->keyword))
1627 {
1628 /*
1629 * Set the default as part of the current option...
1630 */
1631
1632 DEBUG_printf(("2_ppdOpen: Setting %s to %s...", keyword, string));
1633
1634 strlcpy(option->defchoice, string, sizeof(option->defchoice));
1635
1636 DEBUG_printf(("2_ppdOpen: %s is now %s...", keyword, option->defchoice));
1637 }
1638 else
1639 {
1640 /*
1641 * Lookup option and set if it has been defined...
1642 */
1643
1644 ppd_option_t *toption; /* Temporary option */
1645
1646
1647 if ((toption = ppdFindOption(ppd, keyword + 7)) != NULL)
1648 {
1649 DEBUG_printf(("2_ppdOpen: Setting %s to %s...", keyword, string));
1650 strlcpy(toption->defchoice, string, sizeof(toption->defchoice));
1651 }
1652 }
1653 }
1654 else if (!strcmp(keyword, "UIConstraints") ||
1655 !strcmp(keyword, "NonUIConstraints"))
1656 {
1657 if (!string)
1658 {
1659 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1660 goto error;
1661 }
1662
1663 if (ppd->num_consts == 0)
1664 constraint = calloc(2, sizeof(ppd_const_t));
1665 else
1666 constraint = realloc(ppd->consts, (size_t)(ppd->num_consts + 2) * sizeof(ppd_const_t));
1667
1668 if (constraint == NULL)
1669 {
1670 cg->ppd_status = PPD_ALLOC_ERROR;
1671
1672 goto error;
1673 }
1674
1675 ppd->consts = constraint;
1676 constraint += ppd->num_consts;
1677 ppd->num_consts ++;
1678
1679 switch (sscanf(string, "%40s%40s%40s%40s", constraint->option1,
1680 constraint->choice1, constraint->option2,
1681 constraint->choice2))
1682 {
1683 case 0 : /* Error */
1684 case 1 : /* Error */
1685 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1686 goto error;
1687
1688 case 2 : /* Two options... */
1689 /*
1690 * Check for broken constraints like "* Option"...
1691 */
1692
1693 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1694 (!strcmp(constraint->option1, "*") ||
1695 !strcmp(constraint->choice1, "*")))
1696 {
1697 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1698 goto error;
1699 }
1700
1701 /*
1702 * The following strcpy's are safe, as optionN and
1703 * choiceN are all the same size (size defined by PPD spec...)
1704 */
1705
1706 if (constraint->option1[0] == '*')
1707 _cups_strcpy(constraint->option1, constraint->option1 + 1);
1708 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1709 {
1710 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1711 goto error;
1712 }
1713
1714 if (constraint->choice1[0] == '*')
1715 _cups_strcpy(constraint->option2, constraint->choice1 + 1);
1716 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1717 {
1718 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1719 goto error;
1720 }
1721
1722 constraint->choice1[0] = '\0';
1723 constraint->choice2[0] = '\0';
1724 break;
1725
1726 case 3 : /* Two options, one choice... */
1727 /*
1728 * Check for broken constraints like "* Option"...
1729 */
1730
1731 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1732 (!strcmp(constraint->option1, "*") ||
1733 !strcmp(constraint->choice1, "*") ||
1734 !strcmp(constraint->option2, "*")))
1735 {
1736 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1737 goto error;
1738 }
1739
1740 /*
1741 * The following _cups_strcpy's are safe, as optionN and
1742 * choiceN are all the same size (size defined by PPD spec...)
1743 */
1744
1745 if (constraint->option1[0] == '*')
1746 _cups_strcpy(constraint->option1, constraint->option1 + 1);
1747 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1748 {
1749 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1750 goto error;
1751 }
1752
1753 if (constraint->choice1[0] == '*')
1754 {
1755 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1756 constraint->option2[0] == '*')
1757 {
1758 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1759 goto error;
1760 }
1761
1762 _cups_strcpy(constraint->choice2, constraint->option2);
1763 _cups_strcpy(constraint->option2, constraint->choice1 + 1);
1764 constraint->choice1[0] = '\0';
1765 }
1766 else
1767 {
1768 if (constraint->option2[0] == '*')
1769 _cups_strcpy(constraint->option2, constraint->option2 + 1);
1770 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1771 {
1772 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1773 goto error;
1774 }
1775
1776 constraint->choice2[0] = '\0';
1777 }
1778 break;
1779
1780 case 4 : /* Two options, two choices... */
1781 /*
1782 * Check for broken constraints like "* Option"...
1783 */
1784
1785 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1786 (!strcmp(constraint->option1, "*") ||
1787 !strcmp(constraint->choice1, "*") ||
1788 !strcmp(constraint->option2, "*") ||
1789 !strcmp(constraint->choice2, "*")))
1790 {
1791 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1792 goto error;
1793 }
1794
1795 if (constraint->option1[0] == '*')
1796 _cups_strcpy(constraint->option1, constraint->option1 + 1);
1797 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1798 {
1799 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1800 goto error;
1801 }
1802
1803 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1804 constraint->choice1[0] == '*')
1805 {
1806 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1807 goto error;
1808 }
1809
1810 if (constraint->option2[0] == '*')
1811 _cups_strcpy(constraint->option2, constraint->option2 + 1);
1812 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1813 {
1814 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1815 goto error;
1816 }
1817
1818 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1819 constraint->choice2[0] == '*')
1820 {
1821 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1822 goto error;
1823 }
1824 break;
1825 }
1826
1827 /*
1828 * Don't add this one as an attribute...
1829 */
1830
1831 _cupsStrFree(string);
1832 string = NULL;
1833 }
1834 else if (!strcmp(keyword, "PaperDimension"))
1835 {
1836 if ((size = ppdPageSize(ppd, name)) == NULL)
1837 size = ppd_add_size(ppd, name);
1838
1839 if (size == NULL)
1840 {
1841 /*
1842 * Unable to add or find size!
1843 */
1844
1845 cg->ppd_status = PPD_ALLOC_ERROR;
1846
1847 goto error;
1848 }
1849
1850 size->width = (float)_cupsStrScand(string, &sptr, loc);
1851 size->length = (float)_cupsStrScand(sptr, NULL, loc);
1852
1853 _cupsStrFree(string);
1854 string = NULL;
1855 }
1856 else if (!strcmp(keyword, "ImageableArea"))
1857 {
1858 if ((size = ppdPageSize(ppd, name)) == NULL)
1859 size = ppd_add_size(ppd, name);
1860
1861 if (size == NULL)
1862 {
1863 /*
1864 * Unable to add or find size!
1865 */
1866
1867 cg->ppd_status = PPD_ALLOC_ERROR;
1868
1869 goto error;
1870 }
1871
1872 size->left = (float)_cupsStrScand(string, &sptr, loc);
1873 size->bottom = (float)_cupsStrScand(sptr, &sptr, loc);
1874 size->right = (float)_cupsStrScand(sptr, &sptr, loc);
1875 size->top = (float)_cupsStrScand(sptr, NULL, loc);
1876
1877 _cupsStrFree(string);
1878 string = NULL;
1879 }
1880 else if (option != NULL &&
1881 (mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) ==
1882 (PPD_KEYWORD | PPD_OPTION | PPD_STRING) &&
1883 !strcmp(keyword, option->keyword))
1884 {
1885 DEBUG_printf(("2_ppdOpen: group=%p, subgroup=%p", group, subgroup));
1886
1887 if (!strcmp(keyword, "PageSize"))
1888 {
1889 /*
1890 * Add a page size...
1891 */
1892
1893 if (ppdPageSize(ppd, name) == NULL)
1894 ppd_add_size(ppd, name);
1895 }
1896
1897 /*
1898 * Add the option choice...
1899 */
1900
1901 if ((choice = ppd_add_choice(option, name)) == NULL)
1902 {
1903 cg->ppd_status = PPD_ALLOC_ERROR;
1904
1905 goto error;
1906 }
1907
1908 if (text[0])
1909 cupsCharsetToUTF8((cups_utf8_t *)choice->text, text,
1910 sizeof(choice->text), encoding);
1911 else if (!strcmp(name, "True"))
1912 strlcpy(choice->text, _("Yes"), sizeof(choice->text));
1913 else if (!strcmp(name, "False"))
1914 strlcpy(choice->text, _("No"), sizeof(choice->text));
1915 else
1916 strlcpy(choice->text, name, sizeof(choice->text));
1917
1918 if (option->section == PPD_ORDER_JCL)
1919 ppd_decode(string); /* Decode quoted string */
1920
1921 choice->code = string;
1922 string = NULL; /* Don't add as an attribute below */
1923 }
1924
1925 /*
1926 * Add remaining lines with keywords and string values as attributes...
1927 */
1928
1929 if (string &&
1930 (mask & (PPD_KEYWORD | PPD_STRING)) == (PPD_KEYWORD | PPD_STRING))
1931 ppd_add_attr(ppd, keyword, name, text, string);
1932 else
1933 _cupsStrFree(string);
1934 }
1935
1936 /*
1937 * Check for a missing CloseGroup...
1938 */
1939
1940 if (group && cg->ppd_conform == PPD_CONFORM_STRICT)
1941 {
1942 cg->ppd_status = PPD_MISSING_CLOSE_GROUP;
1943 goto error;
1944 }
1945
1946 ppd_free(line.buffer);
1947
1948 /*
1949 * Reset language preferences...
1950 */
1951
1952 #ifdef DEBUG
1953 if (!cupsFileEOF(fp))
1954 DEBUG_printf(("1_ppdOpen: Premature EOF at %lu...\n",
1955 (unsigned long)cupsFileTell(fp)));
1956 #endif /* DEBUG */
1957
1958 if (cg->ppd_status != PPD_OK)
1959 {
1960 /*
1961 * Had an error reading the PPD file, cannot continue!
1962 */
1963
1964 ppdClose(ppd);
1965
1966 return (NULL);
1967 }
1968
1969 /*
1970 * Update the filters array as needed...
1971 */
1972
1973 if (!ppd_update_filters(ppd, cg))
1974 {
1975 ppdClose(ppd);
1976
1977 return (NULL);
1978 }
1979
1980 /*
1981 * Create the sorted options array and set the option back-pointer for
1982 * each choice and custom option...
1983 */
1984
1985 ppd->options = cupsArrayNew2((cups_array_func_t)ppd_compare_options, NULL,
1986 (cups_ahash_func_t)ppd_hash_option,
1987 PPD_HASHSIZE);
1988
1989 for (i = ppd->num_groups, group = ppd->groups;
1990 i > 0;
1991 i --, group ++)
1992 {
1993 for (j = group->num_options, option = group->options;
1994 j > 0;
1995 j --, option ++)
1996 {
1997 ppd_coption_t *coption; /* Custom option */
1998
1999
2000 cupsArrayAdd(ppd->options, option);
2001
2002 for (k = 0; k < option->num_choices; k ++)
2003 option->choices[k].option = option;
2004
2005 if ((coption = ppdFindCustomOption(ppd, option->keyword)) != NULL)
2006 coption->option = option;
2007 }
2008 }
2009
2010 /*
2011 * Create an array to track the marked choices...
2012 */
2013
2014 ppd->marked = cupsArrayNew((cups_array_func_t)ppd_compare_choices, NULL);
2015
2016 /*
2017 * Return the PPD file structure...
2018 */
2019
2020 return (ppd);
2021
2022 /*
2023 * Common exit point for errors to save code size...
2024 */
2025
2026 error:
2027
2028 _cupsStrFree(string);
2029 ppd_free(line.buffer);
2030
2031 ppdClose(ppd);
2032
2033 return (NULL);
2034 }
2035
2036
2037 /*
2038 * 'ppdOpen()' - Read a PPD file into memory.
2039 */
2040
2041 ppd_file_t * /* O - PPD file record */
2042 ppdOpen(FILE *fp) /* I - File to read from */
2043 {
2044 ppd_file_t *ppd; /* PPD file record */
2045 cups_file_t *cf; /* CUPS file */
2046
2047
2048 /*
2049 * Reopen the stdio file as a CUPS file...
2050 */
2051
2052 if ((cf = cupsFileOpenFd(fileno(fp), "r")) == NULL)
2053 return (NULL);
2054
2055 /*
2056 * Load the PPD file using the newer API...
2057 */
2058
2059 ppd = _ppdOpen(cf, _PPD_LOCALIZATION_DEFAULT);
2060
2061 /*
2062 * Close the CUPS file and return the PPD...
2063 */
2064
2065 cupsFileClose(cf);
2066
2067 return (ppd);
2068 }
2069
2070
2071 /*
2072 * 'ppdOpen2()' - Read a PPD file into memory.
2073 *
2074 * @since CUPS 1.2/OS X 10.5@
2075 */
2076
2077 ppd_file_t * /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
2078 ppdOpen2(cups_file_t *fp) /* I - File to read from */
2079 {
2080 return _ppdOpen(fp, _PPD_LOCALIZATION_DEFAULT);
2081 }
2082
2083
2084 /*
2085 * 'ppdOpenFd()' - Read a PPD file into memory.
2086 */
2087
2088 ppd_file_t * /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
2089 ppdOpenFd(int fd) /* I - File to read from */
2090 {
2091 cups_file_t *fp; /* CUPS file pointer */
2092 ppd_file_t *ppd; /* PPD file record */
2093 _cups_globals_t *cg = _cupsGlobals();
2094 /* Global data */
2095
2096
2097 /*
2098 * Set the line number to 0...
2099 */
2100
2101 cg->ppd_line = 0;
2102
2103 /*
2104 * Range check input...
2105 */
2106
2107 if (fd < 0)
2108 {
2109 cg->ppd_status = PPD_NULL_FILE;
2110
2111 return (NULL);
2112 }
2113
2114 /*
2115 * Try to open the file and parse it...
2116 */
2117
2118 if ((fp = cupsFileOpenFd(fd, "r")) != NULL)
2119 {
2120 ppd = ppdOpen2(fp);
2121
2122 cupsFileClose(fp);
2123 }
2124 else
2125 {
2126 cg->ppd_status = PPD_FILE_OPEN_ERROR;
2127 ppd = NULL;
2128 }
2129
2130 return (ppd);
2131 }
2132
2133
2134 /*
2135 * '_ppdOpenFile()' - Read a PPD file into memory.
2136 */
2137
2138 ppd_file_t * /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
2139 _ppdOpenFile(const char *filename, /* I - File to read from */
2140 _ppd_localization_t localization) /* I - Localization to load */
2141 {
2142 cups_file_t *fp; /* File pointer */
2143 ppd_file_t *ppd; /* PPD file record */
2144 _cups_globals_t *cg = _cupsGlobals();
2145 /* Global data */
2146
2147
2148 /*
2149 * Set the line number to 0...
2150 */
2151
2152 cg->ppd_line = 0;
2153
2154 /*
2155 * Range check input...
2156 */
2157
2158 if (filename == NULL)
2159 {
2160 cg->ppd_status = PPD_NULL_FILE;
2161
2162 return (NULL);
2163 }
2164
2165 /*
2166 * Try to open the file and parse it...
2167 */
2168
2169 if ((fp = cupsFileOpen(filename, "r")) != NULL)
2170 {
2171 ppd = _ppdOpen(fp, localization);
2172
2173 cupsFileClose(fp);
2174 }
2175 else
2176 {
2177 cg->ppd_status = PPD_FILE_OPEN_ERROR;
2178 ppd = NULL;
2179 }
2180
2181 return (ppd);
2182 }
2183
2184
2185 /*
2186 * 'ppdOpenFile()' - Read a PPD file into memory.
2187 */
2188
2189 ppd_file_t * /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
2190 ppdOpenFile(const char *filename) /* I - File to read from */
2191 {
2192 return _ppdOpenFile(filename, _PPD_LOCALIZATION_DEFAULT);
2193 }
2194
2195
2196 /*
2197 * 'ppdSetConformance()' - Set the conformance level for PPD files.
2198 *
2199 * @since CUPS 1.1.20/OS X 10.4@
2200 */
2201
2202 void
2203 ppdSetConformance(ppd_conform_t c) /* I - Conformance level */
2204 {
2205 _cups_globals_t *cg = _cupsGlobals();
2206 /* Global data */
2207
2208
2209 cg->ppd_conform = c;
2210 }
2211
2212
2213 /*
2214 * 'ppd_add_attr()' - Add an attribute to the PPD data.
2215 */
2216
2217 static ppd_attr_t * /* O - New attribute */
2218 ppd_add_attr(ppd_file_t *ppd, /* I - PPD file data */
2219 const char *name, /* I - Attribute name */
2220 const char *spec, /* I - Specifier string, if any */
2221 const char *text, /* I - Text string, if any */
2222 const char *value) /* I - Value of attribute */
2223 {
2224 ppd_attr_t **ptr, /* New array */
2225 *temp; /* New attribute */
2226
2227
2228 /*
2229 * Range check input...
2230 */
2231
2232 if (ppd == NULL || name == NULL || spec == NULL)
2233 return (NULL);
2234
2235 /*
2236 * Create the array as needed...
2237 */
2238
2239 if (!ppd->sorted_attrs)
2240 ppd->sorted_attrs = cupsArrayNew((cups_array_func_t)ppd_compare_attrs,
2241 NULL);
2242
2243 /*
2244 * Allocate memory for the new attribute...
2245 */
2246
2247 if (ppd->num_attrs == 0)
2248 ptr = malloc(sizeof(ppd_attr_t *));
2249 else
2250 ptr = realloc(ppd->attrs, (size_t)(ppd->num_attrs + 1) * sizeof(ppd_attr_t *));
2251
2252 if (ptr == NULL)
2253 return (NULL);
2254
2255 ppd->attrs = ptr;
2256 ptr += ppd->num_attrs;
2257
2258 if ((temp = calloc(1, sizeof(ppd_attr_t))) == NULL)
2259 return (NULL);
2260
2261 *ptr = temp;
2262
2263 ppd->num_attrs ++;
2264
2265 /*
2266 * Copy data over...
2267 */
2268
2269 strlcpy(temp->name, name, sizeof(temp->name));
2270 strlcpy(temp->spec, spec, sizeof(temp->spec));
2271 strlcpy(temp->text, text, sizeof(temp->text));
2272 temp->value = (char *)value;
2273
2274 /*
2275 * Add the attribute to the sorted array...
2276 */
2277
2278 cupsArrayAdd(ppd->sorted_attrs, temp);
2279
2280 /*
2281 * Return the attribute...
2282 */
2283
2284 return (temp);
2285 }
2286
2287
2288 /*
2289 * 'ppd_add_choice()' - Add a choice to an option.
2290 */
2291
2292 static ppd_choice_t * /* O - Named choice */
2293 ppd_add_choice(ppd_option_t *option, /* I - Option */
2294 const char *name) /* I - Name of choice */
2295 {
2296 ppd_choice_t *choice; /* Choice */
2297
2298
2299 if (option->num_choices == 0)
2300 choice = malloc(sizeof(ppd_choice_t));
2301 else
2302 choice = realloc(option->choices, sizeof(ppd_choice_t) * (size_t)(option->num_choices + 1));
2303
2304 if (choice == NULL)
2305 return (NULL);
2306
2307 option->choices = choice;
2308 choice += option->num_choices;
2309 option->num_choices ++;
2310
2311 memset(choice, 0, sizeof(ppd_choice_t));
2312 strlcpy(choice->choice, name, sizeof(choice->choice));
2313
2314 return (choice);
2315 }
2316
2317
2318 /*
2319 * 'ppd_add_size()' - Add a page size.
2320 */
2321
2322 static ppd_size_t * /* O - Named size */
2323 ppd_add_size(ppd_file_t *ppd, /* I - PPD file */
2324 const char *name) /* I - Name of size */
2325 {
2326 ppd_size_t *size; /* Size */
2327
2328
2329 if (ppd->num_sizes == 0)
2330 size = malloc(sizeof(ppd_size_t));
2331 else
2332 size = realloc(ppd->sizes, sizeof(ppd_size_t) * (size_t)(ppd->num_sizes + 1));
2333
2334 if (size == NULL)
2335 return (NULL);
2336
2337 ppd->sizes = size;
2338 size += ppd->num_sizes;
2339 ppd->num_sizes ++;
2340
2341 memset(size, 0, sizeof(ppd_size_t));
2342 strlcpy(size->name, name, sizeof(size->name));
2343
2344 return (size);
2345 }
2346
2347
2348 /*
2349 * 'ppd_compare_attrs()' - Compare two attributes.
2350 */
2351
2352 static int /* O - Result of comparison */
2353 ppd_compare_attrs(ppd_attr_t *a, /* I - First attribute */
2354 ppd_attr_t *b) /* I - Second attribute */
2355 {
2356 return (_cups_strcasecmp(a->name, b->name));
2357 }
2358
2359
2360 /*
2361 * 'ppd_compare_choices()' - Compare two choices...
2362 */
2363
2364 static int /* O - Result of comparison */
2365 ppd_compare_choices(ppd_choice_t *a, /* I - First choice */
2366 ppd_choice_t *b) /* I - Second choice */
2367 {
2368 return (strcmp(a->option->keyword, b->option->keyword));
2369 }
2370
2371
2372 /*
2373 * 'ppd_compare_coptions()' - Compare two custom options.
2374 */
2375
2376 static int /* O - Result of comparison */
2377 ppd_compare_coptions(ppd_coption_t *a, /* I - First option */
2378 ppd_coption_t *b) /* I - Second option */
2379 {
2380 return (_cups_strcasecmp(a->keyword, b->keyword));
2381 }
2382
2383
2384 /*
2385 * 'ppd_compare_options()' - Compare two options.
2386 */
2387
2388 static int /* O - Result of comparison */
2389 ppd_compare_options(ppd_option_t *a, /* I - First option */
2390 ppd_option_t *b) /* I - Second option */
2391 {
2392 return (_cups_strcasecmp(a->keyword, b->keyword));
2393 }
2394
2395
2396 /*
2397 * 'ppd_decode()' - Decode a string value...
2398 */
2399
2400 static int /* O - Length of decoded string */
2401 ppd_decode(char *string) /* I - String to decode */
2402 {
2403 char *inptr, /* Input pointer */
2404 *outptr; /* Output pointer */
2405
2406
2407 inptr = string;
2408 outptr = string;
2409
2410 while (*inptr != '\0')
2411 if (*inptr == '<' && isxdigit(inptr[1] & 255))
2412 {
2413 /*
2414 * Convert hex to 8-bit values...
2415 */
2416
2417 inptr ++;
2418 while (isxdigit(*inptr & 255))
2419 {
2420 if (_cups_isalpha(*inptr))
2421 *outptr = (char)((tolower(*inptr) - 'a' + 10) << 4);
2422 else
2423 *outptr = (char)((*inptr - '0') << 4);
2424
2425 inptr ++;
2426
2427 if (!isxdigit(*inptr & 255))
2428 break;
2429
2430 if (_cups_isalpha(*inptr))
2431 *outptr |= (char)(tolower(*inptr) - 'a' + 10);
2432 else
2433 *outptr |= (char)(*inptr - '0');
2434
2435 inptr ++;
2436 outptr ++;
2437 }
2438
2439 while (*inptr != '>' && *inptr != '\0')
2440 inptr ++;
2441 while (*inptr == '>')
2442 inptr ++;
2443 }
2444 else
2445 *outptr++ = *inptr++;
2446
2447 *outptr = '\0';
2448
2449 return ((int)(outptr - string));
2450 }
2451
2452
2453 /*
2454 * 'ppd_free_filters()' - Free the filters array.
2455 */
2456
2457 static void
2458 ppd_free_filters(ppd_file_t *ppd) /* I - PPD file */
2459 {
2460 int i; /* Looping var */
2461 char **filter; /* Current filter */
2462
2463
2464 if (ppd->num_filters > 0)
2465 {
2466 for (i = ppd->num_filters, filter = ppd->filters; i > 0; i --, filter ++)
2467 _cupsStrFree(*filter);
2468
2469 ppd_free(ppd->filters);
2470
2471 ppd->num_filters = 0;
2472 ppd->filters = NULL;
2473 }
2474 }
2475
2476
2477 /*
2478 * 'ppd_free_group()' - Free a single UI group.
2479 */
2480
2481 static void
2482 ppd_free_group(ppd_group_t *group) /* I - Group to free */
2483 {
2484 int i; /* Looping var */
2485 ppd_option_t *option; /* Current option */
2486 ppd_group_t *subgroup; /* Current sub-group */
2487
2488
2489 if (group->num_options > 0)
2490 {
2491 for (i = group->num_options, option = group->options;
2492 i > 0;
2493 i --, option ++)
2494 ppd_free_option(option);
2495
2496 ppd_free(group->options);
2497 }
2498
2499 if (group->num_subgroups > 0)
2500 {
2501 for (i = group->num_subgroups, subgroup = group->subgroups;
2502 i > 0;
2503 i --, subgroup ++)
2504 ppd_free_group(subgroup);
2505
2506 ppd_free(group->subgroups);
2507 }
2508 }
2509
2510
2511 /*
2512 * 'ppd_free_option()' - Free a single option.
2513 */
2514
2515 static void
2516 ppd_free_option(ppd_option_t *option) /* I - Option to free */
2517 {
2518 int i; /* Looping var */
2519 ppd_choice_t *choice; /* Current choice */
2520
2521
2522 if (option->num_choices > 0)
2523 {
2524 for (i = option->num_choices, choice = option->choices;
2525 i > 0;
2526 i --, choice ++)
2527 {
2528 _cupsStrFree(choice->code);
2529 }
2530
2531 ppd_free(option->choices);
2532 }
2533 }
2534
2535
2536 /*
2537 * 'ppd_get_coption()' - Get a custom option record.
2538 */
2539
2540 static ppd_coption_t * /* O - Custom option... */
2541 ppd_get_coption(ppd_file_t *ppd, /* I - PPD file */
2542 const char *name) /* I - Name of option */
2543 {
2544 ppd_coption_t *copt; /* New custom option */
2545
2546
2547 /*
2548 * See if the option already exists...
2549 */
2550
2551 if ((copt = ppdFindCustomOption(ppd, name)) != NULL)
2552 return (copt);
2553
2554 /*
2555 * Not found, so create the custom option record...
2556 */
2557
2558 if ((copt = calloc(1, sizeof(ppd_coption_t))) == NULL)
2559 return (NULL);
2560
2561 strlcpy(copt->keyword, name, sizeof(copt->keyword));
2562
2563 copt->params = cupsArrayNew((cups_array_func_t)NULL, NULL);
2564
2565 cupsArrayAdd(ppd->coptions, copt);
2566
2567 /*
2568 * Return the new record...
2569 */
2570
2571 return (copt);
2572 }
2573
2574
2575 /*
2576 * 'ppd_get_cparam()' - Get a custom parameter record.
2577 */
2578
2579 static ppd_cparam_t * /* O - Extended option... */
2580 ppd_get_cparam(ppd_coption_t *opt, /* I - PPD file */
2581 const char *param, /* I - Name of parameter */
2582 const char *text) /* I - Human-readable text */
2583 {
2584 ppd_cparam_t *cparam; /* New custom parameter */
2585
2586
2587 /*
2588 * See if the parameter already exists...
2589 */
2590
2591 if ((cparam = ppdFindCustomParam(opt, param)) != NULL)
2592 return (cparam);
2593
2594 /*
2595 * Not found, so create the custom parameter record...
2596 */
2597
2598 if ((cparam = calloc(1, sizeof(ppd_cparam_t))) == NULL)
2599 return (NULL);
2600
2601 strlcpy(cparam->name, param, sizeof(cparam->name));
2602 strlcpy(cparam->text, text[0] ? text : param, sizeof(cparam->text));
2603
2604 /*
2605 * Add this record to the array...
2606 */
2607
2608 cupsArrayAdd(opt->params, cparam);
2609
2610 /*
2611 * Return the new record...
2612 */
2613
2614 return (cparam);
2615 }
2616
2617
2618 /*
2619 * 'ppd_get_group()' - Find or create the named group as needed.
2620 */
2621
2622 static ppd_group_t * /* O - Named group */
2623 ppd_get_group(ppd_file_t *ppd, /* I - PPD file */
2624 const char *name, /* I - Name of group */
2625 const char *text, /* I - Text for group */
2626 _cups_globals_t *cg, /* I - Global data */
2627 cups_encoding_t encoding) /* I - Encoding of text */
2628 {
2629 int i; /* Looping var */
2630 ppd_group_t *group; /* Group */
2631
2632
2633 DEBUG_printf(("7ppd_get_group(ppd=%p, name=\"%s\", text=\"%s\", cg=%p)",
2634 ppd, name, text, cg));
2635
2636 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
2637 if (!strcmp(group->name, name))
2638 break;
2639
2640 if (i == 0)
2641 {
2642 DEBUG_printf(("8ppd_get_group: Adding group %s...", name));
2643
2644 if (cg->ppd_conform == PPD_CONFORM_STRICT && strlen(text) >= sizeof(group->text))
2645 {
2646 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
2647
2648 return (NULL);
2649 }
2650
2651 if (ppd->num_groups == 0)
2652 group = malloc(sizeof(ppd_group_t));
2653 else
2654 group = realloc(ppd->groups, (size_t)(ppd->num_groups + 1) * sizeof(ppd_group_t));
2655
2656 if (group == NULL)
2657 {
2658 cg->ppd_status = PPD_ALLOC_ERROR;
2659
2660 return (NULL);
2661 }
2662
2663 ppd->groups = group;
2664 group += ppd->num_groups;
2665 ppd->num_groups ++;
2666
2667 memset(group, 0, sizeof(ppd_group_t));
2668 strlcpy(group->name, name, sizeof(group->name));
2669
2670 cupsCharsetToUTF8((cups_utf8_t *)group->text, text,
2671 sizeof(group->text), encoding);
2672 }
2673
2674 return (group);
2675 }
2676
2677
2678 /*
2679 * 'ppd_get_option()' - Find or create the named option as needed.
2680 */
2681
2682 static ppd_option_t * /* O - Named option */
2683 ppd_get_option(ppd_group_t *group, /* I - Group */
2684 const char *name) /* I - Name of option */
2685 {
2686 int i; /* Looping var */
2687 ppd_option_t *option; /* Option */
2688
2689
2690 DEBUG_printf(("7ppd_get_option(group=%p(\"%s\"), name=\"%s\")",
2691 group, group->name, name));
2692
2693 for (i = group->num_options, option = group->options; i > 0; i --, option ++)
2694 if (!strcmp(option->keyword, name))
2695 break;
2696
2697 if (i == 0)
2698 {
2699 if (group->num_options == 0)
2700 option = malloc(sizeof(ppd_option_t));
2701 else
2702 option = realloc(group->options, (size_t)(group->num_options + 1) * sizeof(ppd_option_t));
2703
2704 if (option == NULL)
2705 return (NULL);
2706
2707 group->options = option;
2708 option += group->num_options;
2709 group->num_options ++;
2710
2711 memset(option, 0, sizeof(ppd_option_t));
2712 strlcpy(option->keyword, name, sizeof(option->keyword));
2713 }
2714
2715 return (option);
2716 }
2717
2718
2719 /*
2720 * 'ppd_hash_option()' - Generate a hash of the option name...
2721 */
2722
2723 static int /* O - Hash index */
2724 ppd_hash_option(ppd_option_t *option) /* I - Option */
2725 {
2726 int hash = 0; /* Hash index */
2727 const char *k; /* Pointer into keyword */
2728
2729
2730 for (hash = option->keyword[0], k = option->keyword + 1; *k;)
2731 hash = 33 * hash + *k++;
2732
2733 return (hash & 511);
2734 }
2735
2736
2737 /*
2738 * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
2739 * necessary.
2740 */
2741
2742 static int /* O - Bitmask of fields read */
2743 ppd_read(cups_file_t *fp, /* I - File to read from */
2744 _ppd_line_t *line, /* I - Line buffer */
2745 char *keyword, /* O - Keyword from line */
2746 char *option, /* O - Option from line */
2747 char *text, /* O - Human-readable text from line */
2748 char **string, /* O - Code/string data */
2749 int ignoreblank, /* I - Ignore blank lines? */
2750 _cups_globals_t *cg) /* I - Global data */
2751 {
2752 int ch, /* Character from file */
2753 col, /* Column in line */
2754 colon, /* Colon seen? */
2755 endquote, /* Waiting for an end quote */
2756 mask, /* Mask to be returned */
2757 startline, /* Start line */
2758 textlen; /* Length of text */
2759 char *keyptr, /* Keyword pointer */
2760 *optptr, /* Option pointer */
2761 *textptr, /* Text pointer */
2762 *strptr, /* Pointer into string */
2763 *lineptr; /* Current position in line buffer */
2764
2765
2766 /*
2767 * Now loop until we have a valid line...
2768 */
2769
2770 *string = NULL;
2771 col = 0;
2772 startline = cg->ppd_line + 1;
2773
2774 if (!line->buffer)
2775 {
2776 line->bufsize = 1024;
2777 line->buffer = malloc(1024);
2778
2779 if (!line->buffer)
2780 return (0);
2781 }
2782
2783 do
2784 {
2785 /*
2786 * Read the line...
2787 */
2788
2789 lineptr = line->buffer;
2790 endquote = 0;
2791 colon = 0;
2792
2793 while ((ch = cupsFileGetChar(fp)) != EOF)
2794 {
2795 if (lineptr >= (line->buffer + line->bufsize - 1))
2796 {
2797 /*
2798 * Expand the line buffer...
2799 */
2800
2801 char *temp; /* Temporary line pointer */
2802
2803
2804 line->bufsize += 1024;
2805 if (line->bufsize > 262144)
2806 {
2807 /*
2808 * Don't allow lines longer than 256k!
2809 */
2810
2811 cg->ppd_line = startline;
2812 cg->ppd_status = PPD_LINE_TOO_LONG;
2813
2814 return (0);
2815 }
2816
2817 temp = realloc(line->buffer, line->bufsize);
2818 if (!temp)
2819 {
2820 cg->ppd_line = startline;
2821 cg->ppd_status = PPD_LINE_TOO_LONG;
2822
2823 return (0);
2824 }
2825
2826 lineptr = temp + (lineptr - line->buffer);
2827 line->buffer = temp;
2828 }
2829
2830 if (ch == '\r' || ch == '\n')
2831 {
2832 /*
2833 * Line feed or carriage return...
2834 */
2835
2836 cg->ppd_line ++;
2837 col = 0;
2838
2839 if (ch == '\r')
2840 {
2841 /*
2842 * Check for a trailing line feed...
2843 */
2844
2845 if ((ch = cupsFilePeekChar(fp)) == EOF)
2846 {
2847 ch = '\n';
2848 break;
2849 }
2850
2851 if (ch == 0x0a)
2852 cupsFileGetChar(fp);
2853 }
2854
2855 if (lineptr == line->buffer && ignoreblank)
2856 continue; /* Skip blank lines */
2857
2858 ch = '\n';
2859
2860 if (!endquote) /* Continue for multi-line text */
2861 break;
2862
2863 *lineptr++ = '\n';
2864 }
2865 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
2866 {
2867 /*
2868 * Other control characters...
2869 */
2870
2871 cg->ppd_line = startline;
2872 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
2873
2874 return (0);
2875 }
2876 else if (ch != 0x1a)
2877 {
2878 /*
2879 * Any other character...
2880 */
2881
2882 *lineptr++ = (char)ch;
2883 col ++;
2884
2885 if (col > (PPD_MAX_LINE - 1))
2886 {
2887 /*
2888 * Line is too long...
2889 */
2890
2891 cg->ppd_line = startline;
2892 cg->ppd_status = PPD_LINE_TOO_LONG;
2893
2894 return (0);
2895 }
2896
2897 if (ch == ':' && strncmp(line->buffer, "*%", 2) != 0)
2898 colon = 1;
2899
2900 if (ch == '\"' && colon)
2901 endquote = !endquote;
2902 }
2903 }
2904
2905 if (endquote)
2906 {
2907 /*
2908 * Didn't finish this quoted string...
2909 */
2910
2911 while ((ch = cupsFileGetChar(fp)) != EOF)
2912 if (ch == '\"')
2913 break;
2914 else if (ch == '\r' || ch == '\n')
2915 {
2916 cg->ppd_line ++;
2917 col = 0;
2918
2919 if (ch == '\r')
2920 {
2921 /*
2922 * Check for a trailing line feed...
2923 */
2924
2925 if ((ch = cupsFilePeekChar(fp)) == EOF)
2926 break;
2927 if (ch == 0x0a)
2928 cupsFileGetChar(fp);
2929 }
2930 }
2931 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
2932 {
2933 /*
2934 * Other control characters...
2935 */
2936
2937 cg->ppd_line = startline;
2938 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
2939
2940 return (0);
2941 }
2942 else if (ch != 0x1a)
2943 {
2944 col ++;
2945
2946 if (col > (PPD_MAX_LINE - 1))
2947 {
2948 /*
2949 * Line is too long...
2950 */
2951
2952 cg->ppd_line = startline;
2953 cg->ppd_status = PPD_LINE_TOO_LONG;
2954
2955 return (0);
2956 }
2957 }
2958 }
2959
2960 if (ch != '\n')
2961 {
2962 /*
2963 * Didn't finish this line...
2964 */
2965
2966 while ((ch = cupsFileGetChar(fp)) != EOF)
2967 if (ch == '\r' || ch == '\n')
2968 {
2969 /*
2970 * Line feed or carriage return...
2971 */
2972
2973 cg->ppd_line ++;
2974 col = 0;
2975
2976 if (ch == '\r')
2977 {
2978 /*
2979 * Check for a trailing line feed...
2980 */
2981
2982 if ((ch = cupsFilePeekChar(fp)) == EOF)
2983 break;
2984 if (ch == 0x0a)
2985 cupsFileGetChar(fp);
2986 }
2987
2988 break;
2989 }
2990 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
2991 {
2992 /*
2993 * Other control characters...
2994 */
2995
2996 cg->ppd_line = startline;
2997 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
2998
2999 return (0);
3000 }
3001 else if (ch != 0x1a)
3002 {
3003 col ++;
3004
3005 if (col > (PPD_MAX_LINE - 1))
3006 {
3007 /*
3008 * Line is too long...
3009 */
3010
3011 cg->ppd_line = startline;
3012 cg->ppd_status = PPD_LINE_TOO_LONG;
3013
3014 return (0);
3015 }
3016 }
3017 }
3018
3019 if (lineptr > line->buffer && lineptr[-1] == '\n')
3020 lineptr --;
3021
3022 *lineptr = '\0';
3023
3024 DEBUG_printf(("9ppd_read: LINE=\"%s\"", line->buffer));
3025
3026 /*
3027 * The dynamically created PPDs for older style OS X
3028 * drivers include a large blob of data inserted as comments
3029 * at the end of the file. As an optimization we can stop
3030 * reading the PPD when we get to the start of this data.
3031 */
3032
3033 if (!strcmp(line->buffer, "*%APLWORKSET START"))
3034 return (0);
3035
3036 if (ch == EOF && lineptr == line->buffer)
3037 return (0);
3038
3039 /*
3040 * Now parse it...
3041 */
3042
3043 mask = 0;
3044 lineptr = line->buffer + 1;
3045
3046 keyword[0] = '\0';
3047 option[0] = '\0';
3048 text[0] = '\0';
3049 *string = NULL;
3050
3051 if ((!line->buffer[0] || /* Blank line */
3052 !strncmp(line->buffer, "*%", 2) || /* Comment line */
3053 !strcmp(line->buffer, "*End")) && /* End of multi-line string */
3054 ignoreblank) /* Ignore these? */
3055 {
3056 startline = cg->ppd_line + 1;
3057 continue;
3058 }
3059
3060 if (!strcmp(line->buffer, "*")) /* (Bad) comment line */
3061 {
3062 if (cg->ppd_conform == PPD_CONFORM_RELAXED)
3063 {
3064 startline = cg->ppd_line + 1;
3065 continue;
3066 }
3067 else
3068 {
3069 cg->ppd_line = startline;
3070 cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
3071
3072 return (0);
3073 }
3074 }
3075
3076 if (line->buffer[0] != '*') /* All lines start with an asterisk */
3077 {
3078 /*
3079 * Allow lines consisting of just whitespace...
3080 */
3081
3082 for (lineptr = line->buffer; *lineptr; lineptr ++)
3083 if (*lineptr && !_cups_isspace(*lineptr))
3084 break;
3085
3086 if (*lineptr)
3087 {
3088 cg->ppd_status = PPD_MISSING_ASTERISK;
3089 return (0);
3090 }
3091 else if (ignoreblank)
3092 continue;
3093 else
3094 return (0);
3095 }
3096
3097 /*
3098 * Get a keyword...
3099 */
3100
3101 keyptr = keyword;
3102
3103 while (*lineptr && *lineptr != ':' && !_cups_isspace(*lineptr))
3104 {
3105 if (*lineptr <= ' ' || *lineptr > 126 || *lineptr == '/' ||
3106 (keyptr - keyword) >= (PPD_MAX_NAME - 1))
3107 {
3108 cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
3109 return (0);
3110 }
3111
3112 *keyptr++ = *lineptr++;
3113 }
3114
3115 *keyptr = '\0';
3116
3117 if (!strcmp(keyword, "End"))
3118 continue;
3119
3120 mask |= PPD_KEYWORD;
3121
3122 if (_cups_isspace(*lineptr))
3123 {
3124 /*
3125 * Get an option name...
3126 */
3127
3128 while (_cups_isspace(*lineptr))
3129 lineptr ++;
3130
3131 optptr = option;
3132
3133 while (*lineptr && !_cups_isspace(*lineptr) && *lineptr != ':' &&
3134 *lineptr != '/')
3135 {
3136 if (*lineptr <= ' ' || *lineptr > 126 ||
3137 (optptr - option) >= (PPD_MAX_NAME - 1))
3138 {
3139 cg->ppd_status = PPD_ILLEGAL_OPTION_KEYWORD;
3140 return (0);
3141 }
3142
3143 *optptr++ = *lineptr++;
3144 }
3145
3146 *optptr = '\0';
3147
3148 if (_cups_isspace(*lineptr) && cg->ppd_conform == PPD_CONFORM_STRICT)
3149 {
3150 cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
3151 return (0);
3152 }
3153
3154 while (_cups_isspace(*lineptr))
3155 lineptr ++;
3156
3157 mask |= PPD_OPTION;
3158
3159 if (*lineptr == '/')
3160 {
3161 /*
3162 * Get human-readable text...
3163 */
3164
3165 lineptr ++;
3166
3167 textptr = text;
3168
3169 while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':')
3170 {
3171 if (((unsigned char)*lineptr < ' ' && *lineptr != '\t') ||
3172 (textptr - text) >= (PPD_MAX_LINE - 1))
3173 {
3174 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
3175 return (0);
3176 }
3177
3178 *textptr++ = *lineptr++;
3179 }
3180
3181 *textptr = '\0';
3182 textlen = ppd_decode(text);
3183
3184 if (textlen > PPD_MAX_TEXT && cg->ppd_conform == PPD_CONFORM_STRICT)
3185 {
3186 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
3187 return (0);
3188 }
3189
3190 mask |= PPD_TEXT;
3191 }
3192 }
3193
3194 if (_cups_isspace(*lineptr) && cg->ppd_conform == PPD_CONFORM_STRICT)
3195 {
3196 cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
3197 return (0);
3198 }
3199
3200 while (_cups_isspace(*lineptr))
3201 lineptr ++;
3202
3203 if (*lineptr == ':')
3204 {
3205 /*
3206 * Get string after triming leading and trailing whitespace...
3207 */
3208
3209 lineptr ++;
3210 while (_cups_isspace(*lineptr))
3211 lineptr ++;
3212
3213 strptr = lineptr + strlen(lineptr) - 1;
3214 while (strptr >= lineptr && _cups_isspace(*strptr))
3215 *strptr-- = '\0';
3216
3217 if (*strptr == '\"')
3218 {
3219 /*
3220 * Quoted string by itself, remove quotes...
3221 */
3222
3223 *strptr = '\0';
3224 lineptr ++;
3225 }
3226
3227 *string = _cupsStrAlloc(lineptr);
3228
3229 mask |= PPD_STRING;
3230 }
3231 }
3232 while (mask == 0);
3233
3234 return (mask);
3235 }
3236
3237
3238 /*
3239 * 'ppd_update_filters()' - Update the filters array as needed.
3240 *
3241 * This function re-populates the filters array with cupsFilter2 entries that
3242 * have been stripped of the destination MIME media types and any maxsize hints.
3243 *
3244 * (All for backwards-compatibility)
3245 */
3246
3247 static int /* O - 1 on success, 0 on failure */
3248 ppd_update_filters(ppd_file_t *ppd,/* I - PPD file */
3249 _cups_globals_t *cg) /* I - Global data */
3250 {
3251 ppd_attr_t *attr; /* Current cupsFilter2 value */
3252 char srcsuper[16], /* Source MIME media type */
3253 srctype[256],
3254 dstsuper[16], /* Destination MIME media type */
3255 dsttype[256],
3256 program[1024], /* Command to run */
3257 *ptr, /* Pointer into command to run */
3258 buffer[1024], /* Re-written cupsFilter value */
3259 **filter; /* Current filter */
3260 int cost; /* Cost of filter */
3261
3262
3263 DEBUG_printf(("4ppd_update_filters(ppd=%p, cg=%p)", ppd, cg));
3264
3265 /*
3266 * See if we have any cupsFilter2 lines...
3267 */
3268
3269 if ((attr = ppdFindAttr(ppd, "cupsFilter2", NULL)) == NULL)
3270 {
3271 DEBUG_puts("5ppd_update_filters: No cupsFilter2 keywords present.");
3272 return (1);
3273 }
3274
3275 /*
3276 * Yes, free the cupsFilter-defined filters and re-build...
3277 */
3278
3279 ppd_free_filters(ppd);
3280
3281 do
3282 {
3283 /*
3284 * Parse the cupsFilter2 string:
3285 *
3286 * src/type dst/type cost program
3287 * src/type dst/type cost maxsize(n) program
3288 */
3289
3290 DEBUG_printf(("5ppd_update_filters: cupsFilter2=\"%s\"", attr->value));
3291
3292 if (sscanf(attr->value, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]",
3293 srcsuper, srctype, dstsuper, dsttype, &cost, program) != 6)
3294 {
3295 DEBUG_puts("5ppd_update_filters: Bad cupsFilter2 line.");
3296 cg->ppd_status = PPD_BAD_VALUE;
3297
3298 return (0);
3299 }
3300
3301 DEBUG_printf(("5ppd_update_filters: srcsuper=\"%s\", srctype=\"%s\", "
3302 "dstsuper=\"%s\", dsttype=\"%s\", cost=%d, program=\"%s\"",
3303 srcsuper, srctype, dstsuper, dsttype, cost, program));
3304
3305 if (!strncmp(program, "maxsize(", 8) &&
3306 (ptr = strchr(program + 8, ')')) != NULL)
3307 {
3308 DEBUG_puts("5ppd_update_filters: Found maxsize(nnn).");
3309
3310 ptr ++;
3311 while (_cups_isspace(*ptr))
3312 ptr ++;
3313
3314 _cups_strcpy(program, ptr);
3315 DEBUG_printf(("5ppd_update_filters: New program=\"%s\"", program));
3316 }
3317
3318 /*
3319 * Convert to cupsFilter format:
3320 *
3321 * src/type cost program
3322 */
3323
3324 snprintf(buffer, sizeof(buffer), "%s/%s %d %s", srcsuper, srctype, cost,
3325 program);
3326 DEBUG_printf(("5ppd_update_filters: Adding \"%s\".", buffer));
3327
3328 /*
3329 * Add a cupsFilter-compatible string to the filters array.
3330 */
3331
3332 if (ppd->num_filters == 0)
3333 filter = malloc(sizeof(char *));
3334 else
3335 filter = realloc(ppd->filters, sizeof(char *) * (size_t)(ppd->num_filters + 1));
3336
3337 if (filter == NULL)
3338 {
3339 DEBUG_puts("5ppd_update_filters: Out of memory.");
3340 cg->ppd_status = PPD_ALLOC_ERROR;
3341
3342 return (0);
3343 }
3344
3345 ppd->filters = filter;
3346 filter += ppd->num_filters;
3347 ppd->num_filters ++;
3348
3349 *filter = _cupsStrAlloc(buffer);
3350 }
3351 while ((attr = ppdFindNextAttr(ppd, "cupsFilter2", NULL)) != NULL);
3352
3353 DEBUG_puts("5ppd_update_filters: Completed OK.");
3354 return (1);
3355 }
3356
3357
3358 /*
3359 * End of "$Id$".
3360 */