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