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