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