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