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