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