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