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