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