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