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