]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/ppd.c
4018d803b094e9c7765c8d87014dc316a5194283
[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 (sscanf(string, "%d%32s%64s%64s", &corder, ctype, cminimum,
946 cmaximum) != 4)
947 {
948 cg->ppd_status = PPD_BAD_CUSTOM_PARAM;
949
950 goto error;
951 }
952
953 cparam->order = corder;
954
955 if (!strcmp(ctype, "curve"))
956 {
957 cparam->type = PPD_CUSTOM_CURVE;
958 cparam->minimum.custom_curve = (float)_cupsStrScand(cminimum, NULL, loc);
959 cparam->maximum.custom_curve = (float)_cupsStrScand(cmaximum, NULL, loc);
960 }
961 else if (!strcmp(ctype, "int"))
962 {
963 cparam->type = PPD_CUSTOM_INT;
964 cparam->minimum.custom_int = atoi(cminimum);
965 cparam->maximum.custom_int = atoi(cmaximum);
966 }
967 else if (!strcmp(ctype, "invcurve"))
968 {
969 cparam->type = PPD_CUSTOM_INVCURVE;
970 cparam->minimum.custom_invcurve = (float)_cupsStrScand(cminimum, NULL, loc);
971 cparam->maximum.custom_invcurve = (float)_cupsStrScand(cmaximum, NULL, loc);
972 }
973 else if (!strcmp(ctype, "passcode"))
974 {
975 cparam->type = PPD_CUSTOM_PASSCODE;
976 cparam->minimum.custom_passcode = atoi(cminimum);
977 cparam->maximum.custom_passcode = atoi(cmaximum);
978 }
979 else if (!strcmp(ctype, "password"))
980 {
981 cparam->type = PPD_CUSTOM_PASSWORD;
982 cparam->minimum.custom_password = atoi(cminimum);
983 cparam->maximum.custom_password = atoi(cmaximum);
984 }
985 else if (!strcmp(ctype, "points"))
986 {
987 cparam->type = PPD_CUSTOM_POINTS;
988 cparam->minimum.custom_points = (float)_cupsStrScand(cminimum, NULL, loc);
989 cparam->maximum.custom_points = (float)_cupsStrScand(cmaximum, NULL, loc);
990 }
991 else if (!strcmp(ctype, "real"))
992 {
993 cparam->type = PPD_CUSTOM_REAL;
994 cparam->minimum.custom_real = (float)_cupsStrScand(cminimum, NULL, loc);
995 cparam->maximum.custom_real = (float)_cupsStrScand(cmaximum, NULL, loc);
996 }
997 else if (!strcmp(ctype, "string"))
998 {
999 cparam->type = PPD_CUSTOM_STRING;
1000 cparam->minimum.custom_string = atoi(cminimum);
1001 cparam->maximum.custom_string = atoi(cmaximum);
1002 }
1003 else
1004 {
1005 cg->ppd_status = PPD_BAD_CUSTOM_PARAM;
1006
1007 goto error;
1008 }
1009
1010 /*
1011 * Now special-case for CustomPageSize...
1012 */
1013
1014 if (!strcmp(coption->keyword, "PageSize"))
1015 {
1016 if (!strcmp(name, "Width"))
1017 {
1018 ppd->custom_min[0] = cparam->minimum.custom_points;
1019 ppd->custom_max[0] = cparam->maximum.custom_points;
1020 }
1021 else if (!strcmp(name, "Height"))
1022 {
1023 ppd->custom_min[1] = cparam->minimum.custom_points;
1024 ppd->custom_max[1] = cparam->maximum.custom_points;
1025 }
1026 }
1027 }
1028 else if (!strcmp(keyword, "HWMargins"))
1029 {
1030 for (i = 0, sptr = string; i < 4; i ++)
1031 ppd->custom_margins[i] = (float)_cupsStrScand(sptr, &sptr, loc);
1032 }
1033 else if (!strncmp(keyword, "Custom", 6) && !strcmp(name, "True") && !option)
1034 {
1035 ppd_option_t *custom_option; /* Custom option */
1036
1037 DEBUG_puts("2ppdOpen2: Processing Custom option...");
1038
1039 /*
1040 * Get the option and custom option...
1041 */
1042
1043 if (!ppd_get_coption(ppd, keyword + 6))
1044 {
1045 cg->ppd_status = PPD_ALLOC_ERROR;
1046
1047 goto error;
1048 }
1049
1050 if (option && !strcasecmp(option->keyword, keyword + 6))
1051 custom_option = option;
1052 else
1053 custom_option = ppdFindOption(ppd, keyword + 6);
1054
1055 if (custom_option)
1056 {
1057 /*
1058 * Add the "custom" option...
1059 */
1060
1061 if ((choice = ppdFindChoice(custom_option, "Custom")) == NULL)
1062 if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL)
1063 {
1064 DEBUG_puts("1ppdOpen2: Unable to add Custom choice!");
1065
1066 cg->ppd_status = PPD_ALLOC_ERROR;
1067
1068 goto error;
1069 }
1070
1071 strlcpy(choice->text, text[0] ? text : _("Custom"),
1072 sizeof(choice->text));
1073
1074 choice->code = _cupsStrAlloc(string);
1075
1076 if (custom_option->section == PPD_ORDER_JCL)
1077 ppd_decode(choice->code);
1078 }
1079
1080 /*
1081 * Now process custom page sizes specially...
1082 */
1083
1084 if (!strcmp(keyword, "CustomPageSize"))
1085 {
1086 /*
1087 * Add a "Custom" page size entry...
1088 */
1089
1090 ppd->variable_sizes = 1;
1091
1092 ppd_add_size(ppd, "Custom");
1093
1094 if (option && !strcasecmp(option->keyword, "PageRegion"))
1095 custom_option = option;
1096 else
1097 custom_option = ppdFindOption(ppd, "PageRegion");
1098
1099 if (custom_option)
1100 {
1101 if ((choice = ppdFindChoice(custom_option, "Custom")) == NULL)
1102 if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL)
1103 {
1104 DEBUG_puts("1ppdOpen2: Unable to add Custom choice!");
1105
1106 cg->ppd_status = PPD_ALLOC_ERROR;
1107
1108 goto error;
1109 }
1110
1111 strlcpy(choice->text, text[0] ? text : _("Custom"),
1112 sizeof(choice->text));
1113 }
1114 }
1115 }
1116 else if (!strcmp(keyword, "LandscapeOrientation"))
1117 {
1118 if (!strcmp(string, "Minus90"))
1119 ppd->landscape = -90;
1120 else if (!strcmp(string, "Plus90"))
1121 ppd->landscape = 90;
1122 }
1123 else if (!strcmp(keyword, "Emulators") && string)
1124 {
1125 for (count = 1, sptr = string; sptr != NULL;)
1126 if ((sptr = strchr(sptr, ' ')) != NULL)
1127 {
1128 count ++;
1129 while (*sptr == ' ')
1130 sptr ++;
1131 }
1132
1133 ppd->num_emulations = count;
1134 if ((ppd->emulations = calloc(count, sizeof(ppd_emul_t))) == NULL)
1135 {
1136 cg->ppd_status = PPD_ALLOC_ERROR;
1137
1138 goto error;
1139 }
1140
1141 for (i = 0, sptr = string; i < count; i ++)
1142 {
1143 for (nameptr = ppd->emulations[i].name;
1144 *sptr != '\0' && *sptr != ' ';
1145 sptr ++)
1146 if (nameptr < (ppd->emulations[i].name + sizeof(ppd->emulations[i].name) - 1))
1147 *nameptr++ = *sptr;
1148
1149 *nameptr = '\0';
1150
1151 while (*sptr == ' ')
1152 sptr ++;
1153 }
1154 }
1155 else if (!strncmp(keyword, "StartEmulator_", 14))
1156 {
1157 ppd_decode(string);
1158
1159 for (i = 0; i < ppd->num_emulations; i ++)
1160 if (!strcmp(keyword + 14, ppd->emulations[i].name))
1161 {
1162 ppd->emulations[i].start = string;
1163 string = NULL;
1164 }
1165 }
1166 else if (!strncmp(keyword, "StopEmulator_", 13))
1167 {
1168 ppd_decode(string);
1169
1170 for (i = 0; i < ppd->num_emulations; i ++)
1171 if (!strcmp(keyword + 13, ppd->emulations[i].name))
1172 {
1173 ppd->emulations[i].stop = string;
1174 string = NULL;
1175 }
1176 }
1177 else if (!strcmp(keyword, "JobPatchFile"))
1178 {
1179 if (ppd->patches == NULL)
1180 ppd->patches = strdup(string);
1181 else
1182 {
1183 temp = realloc(ppd->patches, strlen(ppd->patches) +
1184 strlen(string) + 1);
1185 if (temp == NULL)
1186 {
1187 cg->ppd_status = PPD_ALLOC_ERROR;
1188
1189 goto error;
1190 }
1191
1192 ppd->patches = temp;
1193
1194 strcpy(ppd->patches + strlen(ppd->patches), string);
1195 }
1196 }
1197 else if (!strcmp(keyword, "OpenUI"))
1198 {
1199 /*
1200 * Don't allow nesting of options...
1201 */
1202
1203 if (option && cg->ppd_conform == PPD_CONFORM_STRICT)
1204 {
1205 cg->ppd_status = PPD_NESTED_OPEN_UI;
1206
1207 goto error;
1208 }
1209
1210 /*
1211 * Add an option record to the current sub-group, group, or file...
1212 */
1213
1214 DEBUG_printf(("2ppdOpen2: name=\"%s\" (%d)", name, (int)strlen(name)));
1215
1216 if (name[0] == '*')
1217 _cups_strcpy(name, name + 1); /* Eliminate leading asterisk */
1218
1219 for (i = (int)strlen(name) - 1; i > 0 && isspace(name[i] & 255); i --)
1220 name[i] = '\0'; /* Eliminate trailing spaces */
1221
1222 DEBUG_printf(("2ppdOpen2: OpenUI of %s in group %s...", name,
1223 group ? group->text : "(null)"));
1224
1225 if (subgroup != NULL)
1226 option = ppd_get_option(subgroup, name);
1227 else if (group == NULL)
1228 {
1229 if ((group = ppd_get_group(ppd, "General", _("General"), cg,
1230 encoding)) == NULL)
1231 goto error;
1232
1233 DEBUG_printf(("2ppdOpen2: Adding to group %s...", group->text));
1234 option = ppd_get_option(group, name);
1235 group = NULL;
1236 }
1237 else
1238 option = ppd_get_option(group, name);
1239
1240 if (option == NULL)
1241 {
1242 cg->ppd_status = PPD_ALLOC_ERROR;
1243
1244 goto error;
1245 }
1246
1247 /*
1248 * Now fill in the initial information for the option...
1249 */
1250
1251 if (string && !strcmp(string, "PickMany"))
1252 option->ui = PPD_UI_PICKMANY;
1253 else if (string && !strcmp(string, "Boolean"))
1254 option->ui = PPD_UI_BOOLEAN;
1255 else if (string && !strcmp(string, "PickOne"))
1256 option->ui = PPD_UI_PICKONE;
1257 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1258 {
1259 cg->ppd_status = PPD_BAD_OPEN_UI;
1260
1261 goto error;
1262 }
1263 else
1264 option->ui = PPD_UI_PICKONE;
1265
1266 for (j = 0; j < ppd->num_attrs; j ++)
1267 if (!strncmp(ppd->attrs[j]->name, "Default", 7) &&
1268 !strcmp(ppd->attrs[j]->name + 7, name) &&
1269 ppd->attrs[j]->value)
1270 {
1271 DEBUG_printf(("2ppdOpen2: Setting Default%s to %s via attribute...",
1272 option->keyword, ppd->attrs[j]->value));
1273 strlcpy(option->defchoice, ppd->attrs[j]->value,
1274 sizeof(option->defchoice));
1275 break;
1276 }
1277
1278 if (text[0])
1279 cupsCharsetToUTF8((cups_utf8_t *)option->text, text,
1280 sizeof(option->text), encoding);
1281 else
1282 {
1283 if (!strcmp(name, "PageSize"))
1284 strlcpy(option->text, _("Media Size"), sizeof(option->text));
1285 else if (!strcmp(name, "MediaType"))
1286 strlcpy(option->text, _("Media Type"), sizeof(option->text));
1287 else if (!strcmp(name, "InputSlot"))
1288 strlcpy(option->text, _("Media Source"), sizeof(option->text));
1289 else if (!strcmp(name, "ColorModel"))
1290 strlcpy(option->text, _("Output Mode"), sizeof(option->text));
1291 else if (!strcmp(name, "Resolution"))
1292 strlcpy(option->text, _("Resolution"), sizeof(option->text));
1293 else
1294 strlcpy(option->text, name, sizeof(option->text));
1295 }
1296
1297 option->section = PPD_ORDER_ANY;
1298
1299 _cupsStrFree(string);
1300 string = NULL;
1301
1302 /*
1303 * Add a custom option choice if we have already seen a CustomFoo
1304 * attribute...
1305 */
1306
1307 if (!strcasecmp(name, "PageRegion"))
1308 strcpy(custom_name, "CustomPageSize");
1309 else
1310 snprintf(custom_name, sizeof(custom_name), "Custom%s", name);
1311
1312 if ((custom_attr = ppdFindAttr(ppd, custom_name, "True")) != NULL)
1313 {
1314 if ((choice = ppdFindChoice(option, "Custom")) == NULL)
1315 if ((choice = ppd_add_choice(option, "Custom")) == NULL)
1316 {
1317 DEBUG_puts("1ppdOpen2: Unable to add Custom choice!");
1318
1319 cg->ppd_status = PPD_ALLOC_ERROR;
1320
1321 goto error;
1322 }
1323
1324 strlcpy(choice->text,
1325 custom_attr->text[0] ? custom_attr->text : _("Custom"),
1326 sizeof(choice->text));
1327 choice->code = _cupsStrRetain(custom_attr->value);
1328 }
1329 }
1330 else if (!strcmp(keyword, "JCLOpenUI"))
1331 {
1332 /*
1333 * Don't allow nesting of options...
1334 */
1335
1336 if (option && cg->ppd_conform == PPD_CONFORM_STRICT)
1337 {
1338 cg->ppd_status = PPD_NESTED_OPEN_UI;
1339
1340 goto error;
1341 }
1342
1343 /*
1344 * Find the JCL group, and add if needed...
1345 */
1346
1347 group = ppd_get_group(ppd, "JCL", _("JCL"), cg, encoding);
1348
1349 if (group == NULL)
1350 goto error;
1351
1352 /*
1353 * Add an option record to the current JCLs...
1354 */
1355
1356 if (name[0] == '*')
1357 _cups_strcpy(name, name + 1);
1358
1359 option = ppd_get_option(group, name);
1360
1361 if (option == NULL)
1362 {
1363 cg->ppd_status = PPD_ALLOC_ERROR;
1364
1365 goto error;
1366 }
1367
1368 /*
1369 * Now fill in the initial information for the option...
1370 */
1371
1372 if (string && !strcmp(string, "PickMany"))
1373 option->ui = PPD_UI_PICKMANY;
1374 else if (string && !strcmp(string, "Boolean"))
1375 option->ui = PPD_UI_BOOLEAN;
1376 else if (string && !strcmp(string, "PickOne"))
1377 option->ui = PPD_UI_PICKONE;
1378 else
1379 {
1380 cg->ppd_status = PPD_BAD_OPEN_UI;
1381
1382 goto error;
1383 }
1384
1385 for (j = 0; j < ppd->num_attrs; j ++)
1386 if (!strncmp(ppd->attrs[j]->name, "Default", 7) &&
1387 !strcmp(ppd->attrs[j]->name + 7, name) &&
1388 ppd->attrs[j]->value)
1389 {
1390 DEBUG_printf(("2ppdOpen2: Setting Default%s to %s via attribute...",
1391 option->keyword, ppd->attrs[j]->value));
1392 strlcpy(option->defchoice, ppd->attrs[j]->value,
1393 sizeof(option->defchoice));
1394 break;
1395 }
1396
1397 if (text[0])
1398 cupsCharsetToUTF8((cups_utf8_t *)option->text, text,
1399 sizeof(option->text), encoding);
1400 else
1401 strlcpy(option->text, name, sizeof(option->text));
1402
1403 option->section = PPD_ORDER_JCL;
1404 group = NULL;
1405
1406 _cupsStrFree(string);
1407 string = NULL;
1408
1409 /*
1410 * Add a custom option choice if we have already seen a CustomFoo
1411 * attribute...
1412 */
1413
1414 snprintf(custom_name, sizeof(custom_name), "Custom%s", name);
1415
1416 if ((custom_attr = ppdFindAttr(ppd, custom_name, "True")) != NULL)
1417 {
1418 if ((choice = ppd_add_choice(option, "Custom")) == NULL)
1419 {
1420 DEBUG_puts("1ppdOpen2: Unable to add Custom choice!");
1421
1422 cg->ppd_status = PPD_ALLOC_ERROR;
1423
1424 goto error;
1425 }
1426
1427 strlcpy(choice->text,
1428 custom_attr->text[0] ? custom_attr->text : _("Custom"),
1429 sizeof(choice->text));
1430 choice->code = _cupsStrRetain(custom_attr->value);
1431 }
1432 }
1433 else if (!strcmp(keyword, "CloseUI") || !strcmp(keyword, "JCLCloseUI"))
1434 {
1435 option = NULL;
1436
1437 _cupsStrFree(string);
1438 string = NULL;
1439 }
1440 else if (!strcmp(keyword, "OpenGroup"))
1441 {
1442 /*
1443 * Open a new group...
1444 */
1445
1446 if (group != NULL)
1447 {
1448 cg->ppd_status = PPD_NESTED_OPEN_GROUP;
1449
1450 goto error;
1451 }
1452
1453 if (!string)
1454 {
1455 cg->ppd_status = PPD_BAD_OPEN_GROUP;
1456
1457 goto error;
1458 }
1459
1460 /*
1461 * Separate the group name from the text (name/text)...
1462 */
1463
1464 if ((sptr = strchr(string, '/')) != NULL)
1465 *sptr++ = '\0';
1466 else
1467 sptr = string;
1468
1469 /*
1470 * Fix up the text...
1471 */
1472
1473 ppd_decode(sptr);
1474
1475 /*
1476 * Find/add the group...
1477 */
1478
1479 group = ppd_get_group(ppd, string, sptr, cg, encoding);
1480
1481 if (group == NULL)
1482 goto error;
1483
1484 _cupsStrFree(string);
1485 string = NULL;
1486 }
1487 else if (!strcmp(keyword, "CloseGroup"))
1488 {
1489 group = NULL;
1490
1491 _cupsStrFree(string);
1492 string = NULL;
1493 }
1494 else if (!strcmp(keyword, "OrderDependency"))
1495 {
1496 order = (float)_cupsStrScand(string, &sptr, loc);
1497
1498 if (!sptr || sscanf(sptr, "%40s%40s", name, keyword) != 2)
1499 {
1500 cg->ppd_status = PPD_BAD_ORDER_DEPENDENCY;
1501
1502 goto error;
1503 }
1504
1505 if (keyword[0] == '*')
1506 _cups_strcpy(keyword, keyword + 1);
1507
1508 if (!strcmp(name, "ExitServer"))
1509 section = PPD_ORDER_EXIT;
1510 else if (!strcmp(name, "Prolog"))
1511 section = PPD_ORDER_PROLOG;
1512 else if (!strcmp(name, "DocumentSetup"))
1513 section = PPD_ORDER_DOCUMENT;
1514 else if (!strcmp(name, "PageSetup"))
1515 section = PPD_ORDER_PAGE;
1516 else if (!strcmp(name, "JCLSetup"))
1517 section = PPD_ORDER_JCL;
1518 else
1519 section = PPD_ORDER_ANY;
1520
1521 if (option == NULL)
1522 {
1523 ppd_group_t *gtemp;
1524
1525
1526 /*
1527 * Only valid for Non-UI options...
1528 */
1529
1530 for (i = ppd->num_groups, gtemp = ppd->groups; i > 0; i --, gtemp ++)
1531 if (gtemp->text[0] == '\0')
1532 break;
1533
1534 if (i > 0)
1535 for (i = 0; i < gtemp->num_options; i ++)
1536 if (!strcmp(keyword, gtemp->options[i].keyword))
1537 {
1538 gtemp->options[i].section = section;
1539 gtemp->options[i].order = order;
1540 break;
1541 }
1542 }
1543 else
1544 {
1545 option->section = section;
1546 option->order = order;
1547 }
1548
1549 _cupsStrFree(string);
1550 string = NULL;
1551 }
1552 else if (!strncmp(keyword, "Default", 7))
1553 {
1554 if (string == NULL)
1555 continue;
1556
1557 /*
1558 * Drop UI text, if any, from value...
1559 */
1560
1561 if (strchr(string, '/') != NULL)
1562 *strchr(string, '/') = '\0';
1563
1564 /*
1565 * Assign the default value as appropriate...
1566 */
1567
1568 if (!strcmp(keyword, "DefaultColorSpace"))
1569 {
1570 /*
1571 * Set default colorspace...
1572 */
1573
1574 if (!strcmp(string, "CMY"))
1575 ppd->colorspace = PPD_CS_CMY;
1576 else if (!strcmp(string, "CMYK"))
1577 ppd->colorspace = PPD_CS_CMYK;
1578 else if (!strcmp(string, "RGB"))
1579 ppd->colorspace = PPD_CS_RGB;
1580 else if (!strcmp(string, "RGBK"))
1581 ppd->colorspace = PPD_CS_RGBK;
1582 else if (!strcmp(string, "N"))
1583 ppd->colorspace = PPD_CS_N;
1584 else
1585 ppd->colorspace = PPD_CS_GRAY;
1586 }
1587 else if (option && !strcmp(keyword + 7, option->keyword))
1588 {
1589 /*
1590 * Set the default as part of the current option...
1591 */
1592
1593 DEBUG_printf(("2ppdOpen2: Setting %s to %s...", keyword, string));
1594
1595 strlcpy(option->defchoice, string, sizeof(option->defchoice));
1596
1597 DEBUG_printf(("2ppdOpen2: %s is now %s...", keyword, option->defchoice));
1598 }
1599 else
1600 {
1601 /*
1602 * Lookup option and set if it has been defined...
1603 */
1604
1605 ppd_option_t *toption; /* Temporary option */
1606
1607
1608 if ((toption = ppdFindOption(ppd, keyword + 7)) != NULL)
1609 {
1610 DEBUG_printf(("2ppdOpen2: Setting %s to %s...", keyword, string));
1611 strlcpy(toption->defchoice, string, sizeof(toption->defchoice));
1612 }
1613 }
1614 }
1615 else if (!strcmp(keyword, "UIConstraints") ||
1616 !strcmp(keyword, "NonUIConstraints"))
1617 {
1618 if (ppd->num_consts == 0)
1619 constraint = calloc(2, sizeof(ppd_const_t));
1620 else
1621 constraint = realloc(ppd->consts,
1622 (ppd->num_consts + 2) * sizeof(ppd_const_t));
1623
1624 if (constraint == NULL)
1625 {
1626 cg->ppd_status = PPD_ALLOC_ERROR;
1627
1628 goto error;
1629 }
1630
1631 ppd->consts = constraint;
1632 constraint += ppd->num_consts;
1633 ppd->num_consts ++;
1634
1635 switch (sscanf(string, "%40s%40s%40s%40s", constraint->option1,
1636 constraint->choice1, constraint->option2,
1637 constraint->choice2))
1638 {
1639 case 0 : /* Error */
1640 case 1 : /* Error */
1641 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1642 goto error;
1643
1644 case 2 : /* Two options... */
1645 /*
1646 * Check for broken constraints like "* Option"...
1647 */
1648
1649 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1650 (!strcmp(constraint->option1, "*") ||
1651 !strcmp(constraint->choice1, "*")))
1652 {
1653 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1654 goto error;
1655 }
1656
1657 /*
1658 * The following strcpy's are safe, as optionN and
1659 * choiceN are all the same size (size defined by PPD spec...)
1660 */
1661
1662 if (constraint->option1[0] == '*')
1663 _cups_strcpy(constraint->option1, constraint->option1 + 1);
1664 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1665 {
1666 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1667 goto error;
1668 }
1669
1670 if (constraint->choice1[0] == '*')
1671 _cups_strcpy(constraint->option2, constraint->choice1 + 1);
1672 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1673 {
1674 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1675 goto error;
1676 }
1677
1678 constraint->choice1[0] = '\0';
1679 constraint->choice2[0] = '\0';
1680 break;
1681
1682 case 3 : /* Two options, one choice... */
1683 /*
1684 * Check for broken constraints like "* Option"...
1685 */
1686
1687 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1688 (!strcmp(constraint->option1, "*") ||
1689 !strcmp(constraint->choice1, "*") ||
1690 !strcmp(constraint->option2, "*")))
1691 {
1692 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1693 goto error;
1694 }
1695
1696 /*
1697 * The following _cups_strcpy's are safe, as optionN and
1698 * choiceN are all the same size (size defined by PPD spec...)
1699 */
1700
1701 if (constraint->option1[0] == '*')
1702 _cups_strcpy(constraint->option1, constraint->option1 + 1);
1703 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1704 {
1705 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1706 goto error;
1707 }
1708
1709 if (constraint->choice1[0] == '*')
1710 {
1711 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1712 constraint->option2[0] == '*')
1713 {
1714 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1715 goto error;
1716 }
1717
1718 _cups_strcpy(constraint->choice2, constraint->option2);
1719 _cups_strcpy(constraint->option2, constraint->choice1 + 1);
1720 constraint->choice1[0] = '\0';
1721 }
1722 else
1723 {
1724 if (constraint->option2[0] == '*')
1725 _cups_strcpy(constraint->option2, constraint->option2 + 1);
1726 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1727 {
1728 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1729 goto error;
1730 }
1731
1732 constraint->choice2[0] = '\0';
1733 }
1734 break;
1735
1736 case 4 : /* Two options, two choices... */
1737 /*
1738 * Check for broken constraints like "* Option"...
1739 */
1740
1741 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1742 (!strcmp(constraint->option1, "*") ||
1743 !strcmp(constraint->choice1, "*") ||
1744 !strcmp(constraint->option2, "*") ||
1745 !strcmp(constraint->choice2, "*")))
1746 {
1747 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1748 goto error;
1749 }
1750
1751 if (constraint->option1[0] == '*')
1752 _cups_strcpy(constraint->option1, constraint->option1 + 1);
1753 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1754 {
1755 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1756 goto error;
1757 }
1758
1759 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1760 constraint->choice1[0] == '*')
1761 {
1762 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1763 goto error;
1764 }
1765
1766 if (constraint->option2[0] == '*')
1767 _cups_strcpy(constraint->option2, constraint->option2 + 1);
1768 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1769 {
1770 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1771 goto error;
1772 }
1773
1774 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1775 constraint->choice2[0] == '*')
1776 {
1777 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1778 goto error;
1779 }
1780 break;
1781 }
1782
1783 /*
1784 * Don't add this one as an attribute...
1785 */
1786
1787 _cupsStrFree(string);
1788 string = NULL;
1789 }
1790 else if (!strcmp(keyword, "PaperDimension"))
1791 {
1792 if ((size = ppdPageSize(ppd, name)) == NULL)
1793 size = ppd_add_size(ppd, name);
1794
1795 if (size == NULL)
1796 {
1797 /*
1798 * Unable to add or find size!
1799 */
1800
1801 cg->ppd_status = PPD_ALLOC_ERROR;
1802
1803 goto error;
1804 }
1805
1806 size->width = (float)_cupsStrScand(string, &sptr, loc);
1807 size->length = (float)_cupsStrScand(sptr, NULL, loc);
1808
1809 _cupsStrFree(string);
1810 string = NULL;
1811 }
1812 else if (!strcmp(keyword, "ImageableArea"))
1813 {
1814 if ((size = ppdPageSize(ppd, name)) == NULL)
1815 size = ppd_add_size(ppd, name);
1816
1817 if (size == NULL)
1818 {
1819 /*
1820 * Unable to add or find size!
1821 */
1822
1823 cg->ppd_status = PPD_ALLOC_ERROR;
1824
1825 goto error;
1826 }
1827
1828 size->left = (float)_cupsStrScand(string, &sptr, loc);
1829 size->bottom = (float)_cupsStrScand(sptr, &sptr, loc);
1830 size->right = (float)_cupsStrScand(sptr, &sptr, loc);
1831 size->top = (float)_cupsStrScand(sptr, NULL, loc);
1832
1833 _cupsStrFree(string);
1834 string = NULL;
1835 }
1836 else if (option != NULL &&
1837 (mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) ==
1838 (PPD_KEYWORD | PPD_OPTION | PPD_STRING) &&
1839 !strcmp(keyword, option->keyword))
1840 {
1841 DEBUG_printf(("2ppdOpen2: group=%p, subgroup=%p", group, subgroup));
1842
1843 if (!strcmp(keyword, "PageSize"))
1844 {
1845 /*
1846 * Add a page size...
1847 */
1848
1849 if (ppdPageSize(ppd, name) == NULL)
1850 ppd_add_size(ppd, name);
1851 }
1852
1853 /*
1854 * Add the option choice...
1855 */
1856
1857 if ((choice = ppd_add_choice(option, name)) == NULL)
1858 {
1859 cg->ppd_status = PPD_ALLOC_ERROR;
1860
1861 goto error;
1862 }
1863
1864 if (text[0])
1865 cupsCharsetToUTF8((cups_utf8_t *)choice->text, text,
1866 sizeof(choice->text), encoding);
1867 else if (!strcmp(name, "True"))
1868 strcpy(choice->text, _("Yes"));
1869 else if (!strcmp(name, "False"))
1870 strcpy(choice->text, _("No"));
1871 else
1872 strlcpy(choice->text, name, sizeof(choice->text));
1873
1874 if (option->section == PPD_ORDER_JCL)
1875 ppd_decode(string); /* Decode quoted string */
1876
1877 choice->code = string;
1878 string = NULL; /* Don't add as an attribute below */
1879 }
1880
1881 /*
1882 * Add remaining lines with keywords and string values as attributes...
1883 */
1884
1885 if (string &&
1886 (mask & (PPD_KEYWORD | PPD_STRING)) == (PPD_KEYWORD | PPD_STRING))
1887 ppd_add_attr(ppd, keyword, name, text, string);
1888 else
1889 _cupsStrFree(string);
1890 }
1891
1892 ppd_free(line.buffer);
1893
1894 /*
1895 * Reset language preferences...
1896 */
1897
1898 cupsLangFree(language);
1899
1900 #ifdef DEBUG
1901 if (!cupsFileEOF(fp))
1902 DEBUG_printf(("1ppdOpen2: Premature EOF at %lu...\n",
1903 (unsigned long)cupsFileTell(fp)));
1904 #endif /* DEBUG */
1905
1906 if (cg->ppd_status != PPD_OK)
1907 {
1908 /*
1909 * Had an error reading the PPD file, cannot continue!
1910 */
1911
1912 ppdClose(ppd);
1913
1914 return (NULL);
1915 }
1916
1917 /*
1918 * Create the sorted options array and set the option back-pointer for
1919 * each choice and custom option...
1920 */
1921
1922 ppd->options = cupsArrayNew2((cups_array_func_t)ppd_compare_options, NULL,
1923 (cups_ahash_func_t)ppd_hash_option,
1924 PPD_HASHSIZE);
1925
1926 for (i = ppd->num_groups, group = ppd->groups;
1927 i > 0;
1928 i --, group ++)
1929 {
1930 for (j = group->num_options, option = group->options;
1931 j > 0;
1932 j --, option ++)
1933 {
1934 ppd_coption_t *coption; /* Custom option */
1935
1936
1937 cupsArrayAdd(ppd->options, option);
1938
1939 for (k = 0; k < option->num_choices; k ++)
1940 option->choices[k].option = option;
1941
1942 if ((coption = ppdFindCustomOption(ppd, option->keyword)) != NULL)
1943 coption->option = option;
1944 }
1945 }
1946
1947 /*
1948 * Create an array to track the marked choices...
1949 */
1950
1951 ppd->marked = cupsArrayNew((cups_array_func_t)ppd_compare_choices, NULL);
1952
1953 /*
1954 * Return the PPD file structure...
1955 */
1956
1957 return (ppd);
1958
1959 /*
1960 * Common exit point for errors to save code size...
1961 */
1962
1963 error:
1964
1965 _cupsStrFree(string);
1966 ppd_free(line.buffer);
1967
1968 ppdClose(ppd);
1969
1970 cupsLangFree(language);
1971
1972 return (NULL);
1973 }
1974
1975
1976 /*
1977 * 'ppdOpenFd()' - Read a PPD file into memory.
1978 */
1979
1980 ppd_file_t * /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
1981 ppdOpenFd(int fd) /* I - File to read from */
1982 {
1983 cups_file_t *fp; /* CUPS file pointer */
1984 ppd_file_t *ppd; /* PPD file record */
1985 _cups_globals_t *cg = _cupsGlobals();
1986 /* Global data */
1987
1988
1989 /*
1990 * Set the line number to 0...
1991 */
1992
1993 cg->ppd_line = 0;
1994
1995 /*
1996 * Range check input...
1997 */
1998
1999 if (fd < 0)
2000 {
2001 cg->ppd_status = PPD_NULL_FILE;
2002
2003 return (NULL);
2004 }
2005
2006 /*
2007 * Try to open the file and parse it...
2008 */
2009
2010 if ((fp = cupsFileOpenFd(fd, "r")) != NULL)
2011 {
2012 ppd = ppdOpen2(fp);
2013
2014 cupsFileClose(fp);
2015 }
2016 else
2017 {
2018 cg->ppd_status = PPD_FILE_OPEN_ERROR;
2019 ppd = NULL;
2020 }
2021
2022 return (ppd);
2023 }
2024
2025
2026 /*
2027 * 'ppdOpenFile()' - Read a PPD file into memory.
2028 */
2029
2030 ppd_file_t * /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
2031 ppdOpenFile(const char *filename) /* I - File to read from */
2032 {
2033 cups_file_t *fp; /* File pointer */
2034 ppd_file_t *ppd; /* PPD file record */
2035 _cups_globals_t *cg = _cupsGlobals();
2036 /* Global data */
2037
2038
2039 /*
2040 * Set the line number to 0...
2041 */
2042
2043 cg->ppd_line = 0;
2044
2045 /*
2046 * Range check input...
2047 */
2048
2049 if (filename == NULL)
2050 {
2051 cg->ppd_status = PPD_NULL_FILE;
2052
2053 return (NULL);
2054 }
2055
2056 /*
2057 * Try to open the file and parse it...
2058 */
2059
2060 if ((fp = cupsFileOpen(filename, "r")) != NULL)
2061 {
2062 ppd = ppdOpen2(fp);
2063
2064 cupsFileClose(fp);
2065 }
2066 else
2067 {
2068 cg->ppd_status = PPD_FILE_OPEN_ERROR;
2069 ppd = NULL;
2070 }
2071
2072 return (ppd);
2073 }
2074
2075
2076 /*
2077 * 'ppdSetConformance()' - Set the conformance level for PPD files.
2078 *
2079 * @since CUPS 1.1.20/Mac OS X 10.4@
2080 */
2081
2082 void
2083 ppdSetConformance(ppd_conform_t c) /* I - Conformance level */
2084 {
2085 _cups_globals_t *cg = _cupsGlobals();
2086 /* Global data */
2087
2088
2089 cg->ppd_conform = c;
2090 }
2091
2092
2093 /*
2094 * 'ppd_add_attr()' - Add an attribute to the PPD data.
2095 */
2096
2097 static ppd_attr_t * /* O - New attribute */
2098 ppd_add_attr(ppd_file_t *ppd, /* I - PPD file data */
2099 const char *name, /* I - Attribute name */
2100 const char *spec, /* I - Specifier string, if any */
2101 const char *text, /* I - Text string, if any */
2102 const char *value) /* I - Value of attribute */
2103 {
2104 ppd_attr_t **ptr, /* New array */
2105 *temp; /* New attribute */
2106
2107
2108 /*
2109 * Range check input...
2110 */
2111
2112 if (ppd == NULL || name == NULL || spec == NULL)
2113 return (NULL);
2114
2115 /*
2116 * Create the array as needed...
2117 */
2118
2119 if (!ppd->sorted_attrs)
2120 ppd->sorted_attrs = cupsArrayNew((cups_array_func_t)ppd_compare_attrs,
2121 NULL);
2122
2123 /*
2124 * Allocate memory for the new attribute...
2125 */
2126
2127 if (ppd->num_attrs == 0)
2128 ptr = malloc(sizeof(ppd_attr_t *));
2129 else
2130 ptr = realloc(ppd->attrs, (ppd->num_attrs + 1) * sizeof(ppd_attr_t *));
2131
2132 if (ptr == NULL)
2133 return (NULL);
2134
2135 ppd->attrs = ptr;
2136 ptr += ppd->num_attrs;
2137
2138 if ((temp = calloc(1, sizeof(ppd_attr_t))) == NULL)
2139 return (NULL);
2140
2141 *ptr = temp;
2142
2143 ppd->num_attrs ++;
2144
2145 /*
2146 * Copy data over...
2147 */
2148
2149 strlcpy(temp->name, name, sizeof(temp->name));
2150 strlcpy(temp->spec, spec, sizeof(temp->spec));
2151 strlcpy(temp->text, text, sizeof(temp->text));
2152 temp->value = (char *)value;
2153
2154 /*
2155 * Add the attribute to the sorted array...
2156 */
2157
2158 cupsArrayAdd(ppd->sorted_attrs, temp);
2159
2160 /*
2161 * Return the attribute...
2162 */
2163
2164 return (temp);
2165 }
2166
2167
2168 /*
2169 * 'ppd_add_choice()' - Add a choice to an option.
2170 */
2171
2172 static ppd_choice_t * /* O - Named choice */
2173 ppd_add_choice(ppd_option_t *option, /* I - Option */
2174 const char *name) /* I - Name of choice */
2175 {
2176 ppd_choice_t *choice; /* Choice */
2177
2178
2179 if (option->num_choices == 0)
2180 choice = malloc(sizeof(ppd_choice_t));
2181 else
2182 choice = realloc(option->choices,
2183 sizeof(ppd_choice_t) * (option->num_choices + 1));
2184
2185 if (choice == NULL)
2186 return (NULL);
2187
2188 option->choices = choice;
2189 choice += option->num_choices;
2190 option->num_choices ++;
2191
2192 memset(choice, 0, sizeof(ppd_choice_t));
2193 strlcpy(choice->choice, name, sizeof(choice->choice));
2194
2195 return (choice);
2196 }
2197
2198
2199 /*
2200 * 'ppd_add_size()' - Add a page size.
2201 */
2202
2203 static ppd_size_t * /* O - Named size */
2204 ppd_add_size(ppd_file_t *ppd, /* I - PPD file */
2205 const char *name) /* I - Name of size */
2206 {
2207 ppd_size_t *size; /* Size */
2208
2209
2210 if (ppd->num_sizes == 0)
2211 size = malloc(sizeof(ppd_size_t));
2212 else
2213 size = realloc(ppd->sizes, sizeof(ppd_size_t) * (ppd->num_sizes + 1));
2214
2215 if (size == NULL)
2216 return (NULL);
2217
2218 ppd->sizes = size;
2219 size += ppd->num_sizes;
2220 ppd->num_sizes ++;
2221
2222 memset(size, 0, sizeof(ppd_size_t));
2223 strlcpy(size->name, name, sizeof(size->name));
2224
2225 return (size);
2226 }
2227
2228
2229 /*
2230 * 'ppd_compare_attrs()' - Compare two attributes.
2231 */
2232
2233 static int /* O - Result of comparison */
2234 ppd_compare_attrs(ppd_attr_t *a, /* I - First attribute */
2235 ppd_attr_t *b) /* I - Second attribute */
2236 {
2237 return (strcasecmp(a->name, b->name));
2238 }
2239
2240
2241 /*
2242 * 'ppd_compare_choices()' - Compare two choices...
2243 */
2244
2245 static int /* O - Result of comparison */
2246 ppd_compare_choices(ppd_choice_t *a, /* I - First choice */
2247 ppd_choice_t *b) /* I - Second choice */
2248 {
2249 return (strcmp(a->option->keyword, b->option->keyword));
2250 }
2251
2252
2253 /*
2254 * 'ppd_compare_coptions()' - Compare two custom options.
2255 */
2256
2257 static int /* O - Result of comparison */
2258 ppd_compare_coptions(ppd_coption_t *a, /* I - First option */
2259 ppd_coption_t *b) /* I - Second option */
2260 {
2261 return (strcasecmp(a->keyword, b->keyword));
2262 }
2263
2264
2265 /*
2266 * 'ppd_compare_cparams()' - Compare two custom parameters.
2267 */
2268
2269 static int /* O - Result of comparison */
2270 ppd_compare_cparams(ppd_cparam_t *a, /* I - First parameter */
2271 ppd_cparam_t *b) /* I - Second parameter */
2272 {
2273 return (strcasecmp(a->name, b->name));
2274 }
2275
2276
2277 /*
2278 * 'ppd_compare_options()' - Compare two options.
2279 */
2280
2281 static int /* O - Result of comparison */
2282 ppd_compare_options(ppd_option_t *a, /* I - First option */
2283 ppd_option_t *b) /* I - Second option */
2284 {
2285 return (strcasecmp(a->keyword, b->keyword));
2286 }
2287
2288
2289 /*
2290 * 'ppd_decode()' - Decode a string value...
2291 */
2292
2293 static int /* O - Length of decoded string */
2294 ppd_decode(char *string) /* I - String to decode */
2295 {
2296 char *inptr, /* Input pointer */
2297 *outptr; /* Output pointer */
2298
2299
2300 inptr = string;
2301 outptr = string;
2302
2303 while (*inptr != '\0')
2304 if (*inptr == '<' && isxdigit(inptr[1] & 255))
2305 {
2306 /*
2307 * Convert hex to 8-bit values...
2308 */
2309
2310 inptr ++;
2311 while (isxdigit(*inptr & 255))
2312 {
2313 if (isalpha(*inptr))
2314 *outptr = (tolower(*inptr) - 'a' + 10) << 4;
2315 else
2316 *outptr = (*inptr - '0') << 4;
2317
2318 inptr ++;
2319
2320 if (!isxdigit(*inptr & 255))
2321 break;
2322
2323 if (isalpha(*inptr))
2324 *outptr |= tolower(*inptr) - 'a' + 10;
2325 else
2326 *outptr |= *inptr - '0';
2327
2328 inptr ++;
2329 outptr ++;
2330 }
2331
2332 while (*inptr != '>' && *inptr != '\0')
2333 inptr ++;
2334 while (*inptr == '>')
2335 inptr ++;
2336 }
2337 else
2338 *outptr++ = *inptr++;
2339
2340 *outptr = '\0';
2341
2342 return ((int)(outptr - string));
2343 }
2344
2345
2346 /*
2347 * 'ppd_free_group()' - Free a single UI group.
2348 */
2349
2350 static void
2351 ppd_free_group(ppd_group_t *group) /* I - Group to free */
2352 {
2353 int i; /* Looping var */
2354 ppd_option_t *option; /* Current option */
2355 ppd_group_t *subgroup; /* Current sub-group */
2356
2357
2358 if (group->num_options > 0)
2359 {
2360 for (i = group->num_options, option = group->options;
2361 i > 0;
2362 i --, option ++)
2363 ppd_free_option(option);
2364
2365 ppd_free(group->options);
2366 }
2367
2368 if (group->num_subgroups > 0)
2369 {
2370 for (i = group->num_subgroups, subgroup = group->subgroups;
2371 i > 0;
2372 i --, subgroup ++)
2373 ppd_free_group(subgroup);
2374
2375 ppd_free(group->subgroups);
2376 }
2377 }
2378
2379
2380 /*
2381 * 'ppd_free_option()' - Free a single option.
2382 */
2383
2384 static void
2385 ppd_free_option(ppd_option_t *option) /* I - Option to free */
2386 {
2387 int i; /* Looping var */
2388 ppd_choice_t *choice; /* Current choice */
2389
2390
2391 if (option->num_choices > 0)
2392 {
2393 for (i = option->num_choices, choice = option->choices;
2394 i > 0;
2395 i --, choice ++)
2396 {
2397 _cupsStrFree(choice->code);
2398 }
2399
2400 ppd_free(option->choices);
2401 }
2402 }
2403
2404
2405 /*
2406 * 'ppd_get_coption()' - Get a custom option record.
2407 */
2408
2409 static ppd_coption_t * /* O - Custom option... */
2410 ppd_get_coption(ppd_file_t *ppd, /* I - PPD file */
2411 const char *name) /* I - Name of option */
2412 {
2413 ppd_coption_t *copt; /* New custom option */
2414
2415
2416 /*
2417 * See if the option already exists...
2418 */
2419
2420 if ((copt = ppdFindCustomOption(ppd, name)) != NULL)
2421 return (copt);
2422
2423 /*
2424 * Not found, so create the custom option record...
2425 */
2426
2427 if ((copt = calloc(1, sizeof(ppd_coption_t))) == NULL)
2428 return (NULL);
2429
2430 strlcpy(copt->keyword, name, sizeof(copt->keyword));
2431
2432 copt->params = cupsArrayNew((cups_array_func_t)ppd_compare_cparams, NULL);
2433
2434 cupsArrayAdd(ppd->coptions, copt);
2435
2436 /*
2437 * Return the new record...
2438 */
2439
2440 return (copt);
2441 }
2442
2443
2444 /*
2445 * 'ppd_get_cparam()' - Get a custom parameter record.
2446 */
2447
2448 static ppd_cparam_t * /* O - Extended option... */
2449 ppd_get_cparam(ppd_coption_t *opt, /* I - PPD file */
2450 const char *param, /* I - Name of parameter */
2451 const char *text) /* I - Human-readable text */
2452 {
2453 ppd_cparam_t *cparam; /* New custom parameter */
2454
2455
2456 /*
2457 * See if the parameter already exists...
2458 */
2459
2460 if ((cparam = ppdFindCustomParam(opt, param)) != NULL)
2461 return (cparam);
2462
2463 /*
2464 * Not found, so create the custom parameter record...
2465 */
2466
2467 if ((cparam = calloc(1, sizeof(ppd_cparam_t))) == NULL)
2468 return (NULL);
2469
2470 strlcpy(cparam->name, param, sizeof(cparam->name));
2471 strlcpy(cparam->text, text[0] ? text : param, sizeof(cparam->text));
2472
2473 /*
2474 * Add this record to the array...
2475 */
2476
2477 cupsArrayAdd(opt->params, cparam);
2478
2479 /*
2480 * Return the new record...
2481 */
2482
2483 return (cparam);
2484 }
2485
2486
2487 /*
2488 * 'ppd_get_group()' - Find or create the named group as needed.
2489 */
2490
2491 static ppd_group_t * /* O - Named group */
2492 ppd_get_group(ppd_file_t *ppd, /* I - PPD file */
2493 const char *name, /* I - Name of group */
2494 const char *text, /* I - Text for group */
2495 _cups_globals_t *cg, /* I - Global data */
2496 cups_encoding_t encoding) /* I - Encoding of text */
2497 {
2498 int i; /* Looping var */
2499 ppd_group_t *group; /* Group */
2500
2501
2502 DEBUG_printf(("7ppd_get_group(ppd=%p, name=\"%s\", text=\"%s\", cg=%p)",
2503 ppd, name, text, cg));
2504
2505 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
2506 if (!strcmp(group->name, name))
2507 break;
2508
2509 if (i == 0)
2510 {
2511 DEBUG_printf(("8ppd_get_group: Adding group %s...", name));
2512
2513 if (cg->ppd_conform == PPD_CONFORM_STRICT && strlen(text) >= sizeof(group->text))
2514 {
2515 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
2516
2517 return (NULL);
2518 }
2519
2520 if (ppd->num_groups == 0)
2521 group = malloc(sizeof(ppd_group_t));
2522 else
2523 group = realloc(ppd->groups,
2524 (ppd->num_groups + 1) * sizeof(ppd_group_t));
2525
2526 if (group == NULL)
2527 {
2528 cg->ppd_status = PPD_ALLOC_ERROR;
2529
2530 return (NULL);
2531 }
2532
2533 ppd->groups = group;
2534 group += ppd->num_groups;
2535 ppd->num_groups ++;
2536
2537 memset(group, 0, sizeof(ppd_group_t));
2538 strlcpy(group->name, name, sizeof(group->name));
2539
2540 cupsCharsetToUTF8((cups_utf8_t *)group->text, text,
2541 sizeof(group->text), encoding);
2542 }
2543
2544 return (group);
2545 }
2546
2547
2548 /*
2549 * 'ppd_get_option()' - Find or create the named option as needed.
2550 */
2551
2552 static ppd_option_t * /* O - Named option */
2553 ppd_get_option(ppd_group_t *group, /* I - Group */
2554 const char *name) /* I - Name of option */
2555 {
2556 int i; /* Looping var */
2557 ppd_option_t *option; /* Option */
2558
2559
2560 DEBUG_printf(("7ppd_get_option(group=%p(\"%s\"), name=\"%s\")",
2561 group, group->name, name));
2562
2563 for (i = group->num_options, option = group->options; i > 0; i --, option ++)
2564 if (!strcmp(option->keyword, name))
2565 break;
2566
2567 if (i == 0)
2568 {
2569 if (group->num_options == 0)
2570 option = malloc(sizeof(ppd_option_t));
2571 else
2572 option = realloc(group->options,
2573 (group->num_options + 1) * sizeof(ppd_option_t));
2574
2575 if (option == NULL)
2576 return (NULL);
2577
2578 group->options = option;
2579 option += group->num_options;
2580 group->num_options ++;
2581
2582 memset(option, 0, sizeof(ppd_option_t));
2583 strlcpy(option->keyword, name, sizeof(option->keyword));
2584 }
2585
2586 return (option);
2587 }
2588
2589
2590 /*
2591 * 'ppd_hash_option()' - Generate a hash of the option name...
2592 */
2593
2594 static int /* O - Hash index */
2595 ppd_hash_option(ppd_option_t *option) /* I - Option */
2596 {
2597 int hash = 0; /* Hash index */
2598 const char *k; /* Pointer into keyword */
2599
2600
2601 for (hash = option->keyword[0], k = option->keyword + 1; *k;)
2602 hash = 33 * hash + *k++;
2603
2604 return (hash & 511);
2605 }
2606
2607
2608 /*
2609 * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
2610 * necessary.
2611 */
2612
2613 static int /* O - Bitmask of fields read */
2614 ppd_read(cups_file_t *fp, /* I - File to read from */
2615 _ppd_line_t *line, /* I - Line buffer */
2616 char *keyword, /* O - Keyword from line */
2617 char *option, /* O - Option from line */
2618 char *text, /* O - Human-readable text from line */
2619 char **string, /* O - Code/string data */
2620 int ignoreblank, /* I - Ignore blank lines? */
2621 _cups_globals_t *cg) /* I - Global data */
2622 {
2623 int ch, /* Character from file */
2624 col, /* Column in line */
2625 colon, /* Colon seen? */
2626 endquote, /* Waiting for an end quote */
2627 mask, /* Mask to be returned */
2628 startline, /* Start line */
2629 textlen; /* Length of text */
2630 char *keyptr, /* Keyword pointer */
2631 *optptr, /* Option pointer */
2632 *textptr, /* Text pointer */
2633 *strptr, /* Pointer into string */
2634 *lineptr; /* Current position in line buffer */
2635
2636
2637 /*
2638 * Now loop until we have a valid line...
2639 */
2640
2641 *string = NULL;
2642 col = 0;
2643 startline = cg->ppd_line + 1;
2644
2645 if (!line->buffer)
2646 {
2647 line->bufsize = 1024;
2648 line->buffer = malloc(1024);
2649
2650 if (!line->buffer)
2651 return (0);
2652 }
2653
2654 do
2655 {
2656 /*
2657 * Read the line...
2658 */
2659
2660 lineptr = line->buffer;
2661 endquote = 0;
2662 colon = 0;
2663
2664 while ((ch = cupsFileGetChar(fp)) != EOF)
2665 {
2666 if (lineptr >= (line->buffer + line->bufsize - 1))
2667 {
2668 /*
2669 * Expand the line buffer...
2670 */
2671
2672 char *temp; /* Temporary line pointer */
2673
2674
2675 line->bufsize += 1024;
2676 if (line->bufsize > 262144)
2677 {
2678 /*
2679 * Don't allow lines longer than 256k!
2680 */
2681
2682 cg->ppd_line = startline;
2683 cg->ppd_status = PPD_LINE_TOO_LONG;
2684
2685 return (0);
2686 }
2687
2688 temp = realloc(line->buffer, line->bufsize);
2689 if (!temp)
2690 {
2691 cg->ppd_line = startline;
2692 cg->ppd_status = PPD_LINE_TOO_LONG;
2693
2694 return (0);
2695 }
2696
2697 lineptr = temp + (lineptr - line->buffer);
2698 line->buffer = temp;
2699 }
2700
2701 if (ch == '\r' || ch == '\n')
2702 {
2703 /*
2704 * Line feed or carriage return...
2705 */
2706
2707 cg->ppd_line ++;
2708 col = 0;
2709
2710 if (ch == '\r')
2711 {
2712 /*
2713 * Check for a trailing line feed...
2714 */
2715
2716 if ((ch = cupsFilePeekChar(fp)) == EOF)
2717 {
2718 ch = '\n';
2719 break;
2720 }
2721
2722 if (ch == 0x0a)
2723 cupsFileGetChar(fp);
2724 }
2725
2726 if (lineptr == line->buffer && ignoreblank)
2727 continue; /* Skip blank lines */
2728
2729 ch = '\n';
2730
2731 if (!endquote) /* Continue for multi-line text */
2732 break;
2733
2734 *lineptr++ = '\n';
2735 }
2736 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
2737 {
2738 /*
2739 * Other control characters...
2740 */
2741
2742 cg->ppd_line = startline;
2743 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
2744
2745 return (0);
2746 }
2747 else if (ch != 0x1a)
2748 {
2749 /*
2750 * Any other character...
2751 */
2752
2753 *lineptr++ = ch;
2754 col ++;
2755
2756 if (col > (PPD_MAX_LINE - 1))
2757 {
2758 /*
2759 * Line is too long...
2760 */
2761
2762 cg->ppd_line = startline;
2763 cg->ppd_status = PPD_LINE_TOO_LONG;
2764
2765 return (0);
2766 }
2767
2768 if (ch == ':' && strncmp(line->buffer, "*%", 2) != 0)
2769 colon = 1;
2770
2771 if (ch == '\"' && colon)
2772 endquote = !endquote;
2773 }
2774 }
2775
2776 if (endquote)
2777 {
2778 /*
2779 * Didn't finish this quoted string...
2780 */
2781
2782 while ((ch = cupsFileGetChar(fp)) != EOF)
2783 if (ch == '\"')
2784 break;
2785 else if (ch == '\r' || ch == '\n')
2786 {
2787 cg->ppd_line ++;
2788 col = 0;
2789
2790 if (ch == '\r')
2791 {
2792 /*
2793 * Check for a trailing line feed...
2794 */
2795
2796 if ((ch = cupsFilePeekChar(fp)) == EOF)
2797 break;
2798 if (ch == 0x0a)
2799 cupsFileGetChar(fp);
2800 }
2801 }
2802 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
2803 {
2804 /*
2805 * Other control characters...
2806 */
2807
2808 cg->ppd_line = startline;
2809 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
2810
2811 return (0);
2812 }
2813 else if (ch != 0x1a)
2814 {
2815 col ++;
2816
2817 if (col > (PPD_MAX_LINE - 1))
2818 {
2819 /*
2820 * Line is too long...
2821 */
2822
2823 cg->ppd_line = startline;
2824 cg->ppd_status = PPD_LINE_TOO_LONG;
2825
2826 return (0);
2827 }
2828 }
2829 }
2830
2831 if (ch != '\n')
2832 {
2833 /*
2834 * Didn't finish this line...
2835 */
2836
2837 while ((ch = cupsFileGetChar(fp)) != EOF)
2838 if (ch == '\r' || ch == '\n')
2839 {
2840 /*
2841 * Line feed or carriage return...
2842 */
2843
2844 cg->ppd_line ++;
2845 col = 0;
2846
2847 if (ch == '\r')
2848 {
2849 /*
2850 * Check for a trailing line feed...
2851 */
2852
2853 if ((ch = cupsFilePeekChar(fp)) == EOF)
2854 break;
2855 if (ch == 0x0a)
2856 cupsFileGetChar(fp);
2857 }
2858
2859 break;
2860 }
2861 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
2862 {
2863 /*
2864 * Other control characters...
2865 */
2866
2867 cg->ppd_line = startline;
2868 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
2869
2870 return (0);
2871 }
2872 else if (ch != 0x1a)
2873 {
2874 col ++;
2875
2876 if (col > (PPD_MAX_LINE - 1))
2877 {
2878 /*
2879 * Line is too long...
2880 */
2881
2882 cg->ppd_line = startline;
2883 cg->ppd_status = PPD_LINE_TOO_LONG;
2884
2885 return (0);
2886 }
2887 }
2888 }
2889
2890 if (lineptr > line->buffer && lineptr[-1] == '\n')
2891 lineptr --;
2892
2893 *lineptr = '\0';
2894
2895 DEBUG_printf(("9ppd_read: LINE=\"%s\"", line->buffer));
2896
2897 /*
2898 * The dynamically created PPDs for older style Mac OS X
2899 * drivers include a large blob of data inserted as comments
2900 * at the end of the file. As an optimization we can stop
2901 * reading the PPD when we get to the start of this data.
2902 */
2903
2904 if (!strcmp(line->buffer, "*%APLWORKSET START"))
2905 return (0);
2906
2907 if (ch == EOF && lineptr == line->buffer)
2908 return (0);
2909
2910 /*
2911 * Now parse it...
2912 */
2913
2914 mask = 0;
2915 lineptr = line->buffer + 1;
2916
2917 keyword[0] = '\0';
2918 option[0] = '\0';
2919 text[0] = '\0';
2920 *string = NULL;
2921
2922 if ((!line->buffer[0] || /* Blank line */
2923 !strncmp(line->buffer, "*%", 2) || /* Comment line */
2924 !strcmp(line->buffer, "*End")) && /* End of multi-line string */
2925 ignoreblank) /* Ignore these? */
2926 {
2927 startline = cg->ppd_line + 1;
2928 continue;
2929 }
2930
2931 if (!strcmp(line->buffer, "*")) /* (Bad) comment line */
2932 {
2933 if (cg->ppd_conform == PPD_CONFORM_RELAXED)
2934 {
2935 startline = cg->ppd_line + 1;
2936 continue;
2937 }
2938 else
2939 {
2940 cg->ppd_line = startline;
2941 cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
2942
2943 return (0);
2944 }
2945 }
2946
2947 if (line->buffer[0] != '*') /* All lines start with an asterisk */
2948 {
2949 /*
2950 * Allow lines consisting of just whitespace...
2951 */
2952
2953 for (lineptr = line->buffer; *lineptr; lineptr ++)
2954 if (!isspace(*lineptr & 255))
2955 break;
2956
2957 if (*lineptr)
2958 {
2959 cg->ppd_status = PPD_MISSING_ASTERISK;
2960 return (0);
2961 }
2962 else if (ignoreblank)
2963 continue;
2964 else
2965 return (0);
2966 }
2967
2968 /*
2969 * Get a keyword...
2970 */
2971
2972 keyptr = keyword;
2973
2974 while (*lineptr != '\0' && *lineptr != ':' && !isspace(*lineptr & 255))
2975 {
2976 if (*lineptr <= ' ' || *lineptr > 126 || *lineptr == '/' ||
2977 (keyptr - keyword) >= (PPD_MAX_NAME - 1))
2978 {
2979 cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
2980 return (0);
2981 }
2982
2983 *keyptr++ = *lineptr++;
2984 }
2985
2986 *keyptr = '\0';
2987
2988 if (!strcmp(keyword, "End"))
2989 continue;
2990
2991 mask |= PPD_KEYWORD;
2992
2993 if (isspace(*lineptr & 255))
2994 {
2995 /*
2996 * Get an option name...
2997 */
2998
2999 while (isspace(*lineptr & 255))
3000 lineptr ++;
3001
3002 optptr = option;
3003
3004 while (*lineptr != '\0' && !isspace(*lineptr & 255) && *lineptr != ':' &&
3005 *lineptr != '/')
3006 {
3007 if (*lineptr <= ' ' || *lineptr > 126 ||
3008 (optptr - option) >= (PPD_MAX_NAME - 1))
3009 {
3010 cg->ppd_status = PPD_ILLEGAL_OPTION_KEYWORD;
3011 return (0);
3012 }
3013
3014 *optptr++ = *lineptr++;
3015 }
3016
3017 *optptr = '\0';
3018
3019 if (isspace(*lineptr & 255) && cg->ppd_conform == PPD_CONFORM_STRICT)
3020 {
3021 cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
3022 return (0);
3023 }
3024
3025 while (isspace(*lineptr & 255))
3026 lineptr ++;
3027
3028 mask |= PPD_OPTION;
3029
3030 if (*lineptr == '/')
3031 {
3032 /*
3033 * Get human-readable text...
3034 */
3035
3036 lineptr ++;
3037
3038 textptr = text;
3039
3040 while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':')
3041 {
3042 if (((unsigned char)*lineptr < ' ' && *lineptr != '\t') ||
3043 (textptr - text) >= (PPD_MAX_LINE - 1))
3044 {
3045 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
3046 return (0);
3047 }
3048
3049 *textptr++ = *lineptr++;
3050 }
3051
3052 *textptr = '\0';
3053 textlen = ppd_decode(text);
3054
3055 if (textlen > PPD_MAX_TEXT && cg->ppd_conform == PPD_CONFORM_STRICT)
3056 {
3057 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
3058 return (0);
3059 }
3060
3061 mask |= PPD_TEXT;
3062 }
3063 }
3064
3065 if (isspace(*lineptr & 255) && cg->ppd_conform == PPD_CONFORM_STRICT)
3066 {
3067 cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
3068 return (0);
3069 }
3070
3071 while (isspace(*lineptr & 255))
3072 lineptr ++;
3073
3074 if (*lineptr == ':')
3075 {
3076 /*
3077 * Get string after triming leading and trailing whitespace...
3078 */
3079
3080 lineptr ++;
3081 while (isspace(*lineptr & 255))
3082 lineptr ++;
3083
3084 strptr = lineptr + strlen(lineptr) - 1;
3085 while (strptr >= lineptr && isspace(*strptr & 255))
3086 *strptr-- = '\0';
3087
3088 if (*strptr == '\"')
3089 {
3090 /*
3091 * Quoted string by itself, remove quotes...
3092 */
3093
3094 *strptr = '\0';
3095 lineptr ++;
3096 }
3097
3098 *string = _cupsStrAlloc(lineptr);
3099
3100 mask |= PPD_STRING;
3101 }
3102 }
3103 while (mask == 0);
3104
3105 return (mask);
3106 }
3107
3108
3109 /*
3110 * End of "$Id: ppd.c 7906 2008-09-03 20:19:43Z mike $".
3111 */