]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/ppd.c
Merge changes from CUPS 1.4svn-r7282.
[thirdparty/cups.git] / cups / ppd.c
CommitLineData
ef416fc2 1/*
2e4ff8af 2 * "$Id: ppd.c 6937 2007-09-10 21:13:31Z mike $"
ef416fc2 3 *
4 * PPD file routines for the Common UNIX Printing System (CUPS).
5 *
91c84a35 6 * Copyright 2007-2008 by Apple Inc.
b86bc4cf 7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
ef416fc2 8 *
9 * These coded instructions, statements, and computer programs are the
bc44d920 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/".
ef416fc2 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 *
fa73b229 28 * ppdClose() - Free all memory used by the PPD file.
29 * ppdErrorString() - Returns the text assocated with a status.
80ca4592 30 * _ppdGetEncoding() - Get the CUPS encoding value for the given
31 * LanguageEncoding.
fa73b229 32 * ppdLastError() - Return the status from the last ppdOpen*().
33 * ppdOpen() - Read a PPD file into memory.
bd7854cb 34 * ppdOpen2() - Read a PPD file into memory.
fa73b229 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.
bd7854cb 41 * ppd_compare_attrs() - Compare two attributes.
b94498cf 42 * ppd_compare_choices() - Compare two choices...
43 * ppd_compare_consts() - Compare two constraints.
fa73b229 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.
b94498cf 54 * ppd_hash_option() - Generate a hash of the option name...
fa73b229 55 * ppd_read() - Read a line from a PPD file, skipping comment
56 * lines as necessary.
ef416fc2 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
b94498cf 87#define PPD_HASHSIZE 512 /* Size of hash */
88
ef416fc2 89
2e4ff8af
MS
90/*
91 * Line buffer structure...
92 */
93
94typedef 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
ef416fc2 101/*
102 * Local functions...
103 */
104
105static ppd_attr_t *ppd_add_attr(ppd_file_t *ppd, const char *name,
106 const char *spec, const char *text,
107 const char *value);
108static ppd_choice_t *ppd_add_choice(ppd_option_t *option, const char *name);
109static ppd_size_t *ppd_add_size(ppd_file_t *ppd, const char *name);
bd7854cb 110static int ppd_compare_attrs(ppd_attr_t *a, ppd_attr_t *b);
b94498cf 111static int ppd_compare_choices(ppd_choice_t *a, ppd_choice_t *b);
112static int ppd_compare_consts(ppd_const_t *a, ppd_const_t *b);
bd7854cb 113static int ppd_compare_coptions(ppd_coption_t *a,
114 ppd_coption_t *b);
fa73b229 115static int ppd_compare_cparams(ppd_cparam_t *a, ppd_cparam_t *b);
116static int ppd_compare_options(ppd_option_t *a, ppd_option_t *b);
ef416fc2 117static int ppd_decode(char *string);
118static void ppd_free_group(ppd_group_t *group);
119static void ppd_free_option(ppd_option_t *option);
fa73b229 120static ppd_coption_t *ppd_get_coption(ppd_file_t *ppd, const char *name);
121static ppd_cparam_t *ppd_get_cparam(ppd_coption_t *opt,
122 const char *param,
123 const char *text);
ef416fc2 124static ppd_group_t *ppd_get_group(ppd_file_t *ppd, const char *name,
e1d6a774 125 const char *text, _cups_globals_t *cg,
126 cups_encoding_t encoding);
ef416fc2 127static ppd_option_t *ppd_get_option(ppd_group_t *group, const char *name);
b94498cf 128static int ppd_hash_option(ppd_option_t *option);
2e4ff8af
MS
129static int ppd_read(cups_file_t *fp, _ppd_line_t *line,
130 char *keyword, char *option, char *text,
131 char **string, int ignoreblank,
ef416fc2 132 _cups_globals_t *cg);
133
134
ef416fc2 135/*
136 * 'ppdClose()' - Free all memory used by the PPD file.
137 */
138
139void
140ppdClose(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 */
fa73b229 148 ppd_coption_t *coption; /* Current custom option */
149 ppd_cparam_t *cparam; /* Current custom parameter */
ef416fc2 150
151
152 /*
fa73b229 153 * Range check arguments...
ef416fc2 154 */
155
fa73b229 156 if (!ppd)
ef416fc2 157 return;
158
159 /*
160 * Free all strings at the top level...
161 */
162
2e4ff8af
MS
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);
ef416fc2 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 {
2e4ff8af
MS
178 _cupsStrFree(emul->start);
179 _cupsStrFree(emul->stop);
ef416fc2 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
fa73b229 197 cupsArrayDelete(ppd->options);
b94498cf 198 cupsArrayDelete(ppd->marked);
fa73b229 199
ef416fc2 200 /*
201 * Free any page sizes...
202 */
203
204 if (ppd->num_sizes > 0)
ef416fc2 205 ppd_free(ppd->sizes);
ef416fc2 206
207 /*
208 * Free any constraints...
209 */
210
211 if (ppd->num_consts > 0)
ef416fc2 212 ppd_free(ppd->consts);
ef416fc2 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 ++)
2e4ff8af 221 _cupsStrFree(*filter);
ef416fc2 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 ++)
2e4ff8af 233 _cupsStrFree(*font);
ef416fc2 234
235 ppd_free(ppd->fonts);
236 }
237
238 /*
239 * Free any profiles...
240 */
241
242 if (ppd->num_profiles > 0)
ef416fc2 243 ppd_free(ppd->profiles);
ef416fc2 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 {
2e4ff8af 253 _cupsStrFree((*attr)->value);
ef416fc2 254 ppd_free(*attr);
255 }
256
257 ppd_free(ppd->attrs);
258 }
259
b423cd4c 260 cupsArrayDelete(ppd->sorted_attrs);
261
fa73b229 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))
ef416fc2 269 {
fa73b229 270 for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
271 cparam;
272 cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
ef416fc2 273 {
fa73b229 274 switch (cparam->type)
275 {
276 case PPD_CUSTOM_PASSCODE :
277 case PPD_CUSTOM_PASSWORD :
278 case PPD_CUSTOM_STRING :
2e4ff8af 279 _cupsStrFree(cparam->current.custom_string);
fa73b229 280 break;
ef416fc2 281
fa73b229 282 default :
283 break;
284 }
ef416fc2 285
fa73b229 286 free(cparam);
ef416fc2 287 }
288
fa73b229 289 cupsArrayDelete(coption->params);
290
291 free(coption);
ef416fc2 292 }
fa73b229 293
294 cupsArrayDelete(ppd->coptions);
ef416fc2 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
310const char * /* O - Status string */
311ppdErrorString(ppd_status_t status) /* I - PPD status */
312{
313 static const char * const messages[] =/* Status messages */
314 {
fa73b229 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")
ef416fc2 336 };
337
338
339 if (status < PPD_OK || status > PPD_ILLEGAL_WHITESPACE)
fa73b229 340 return (_cupsLangString(cupsLangDefault(), _("Unknown")));
ef416fc2 341 else
fa73b229 342 return (_cupsLangString(cupsLangDefault(), messages[status]));
ef416fc2 343}
344
345
80ca4592 346/*
347 * '_ppdGetEncoding()' - Get the CUPS encoding value for the given
348 * LanguageEncoding.
349 */
350
351cups_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
ef416fc2 371/*
372 * 'ppdLastError()' - Return the status from the last ppdOpen*().
373 *
374 * @since CUPS 1.1.19@
375 */
376
377ppd_status_t /* O - Status code */
378ppdLastError(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
395ppd_file_t * /* O - PPD file record */
396ppdOpen(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
5a738aea 431ppd_file_t * /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
ef416fc2 432ppdOpen2(cups_file_t *fp) /* I - File to read from */
433{
fa73b229 434 int i, j, k; /* Looping vars */
ef416fc2 435 int count; /* Temporary count */
2e4ff8af 436 _ppd_line_t line; /* Line buffer */
ef416fc2 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 */
757d2cad 461 struct lconv *loc; /* Locale data */
ef416fc2 462 int ui_keyword; /* Is this line a UI keyword? */
e1d6a774 463 cups_encoding_t encoding; /* Encoding of PPD file */
ef416fc2 464 _cups_globals_t *cg = _cupsGlobals();
465 /* Global data */
0a682745
MS
466 char custom_name[PPD_MAX_NAME];
467 /* CustomFoo attribute name */
468 ppd_attr_t *custom_attr; /* CustomFoo attribute */
ef416fc2 469 static const char * const ui_keywords[] =
470 {
bd7854cb 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 */
ef416fc2 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"
bd7854cb 525#else /* !CUPS_USE_FULL_UI_KEYWORDS_LIST */
526 "PageRegion",
527 "PageSize"
528#endif /* CUPS_USE_FULL_UI_KEYWORDS_LIST */
ef416fc2 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
2e4ff8af
MS
553 line.buffer = NULL;
554 line.bufsize = 0;
555
556 mask = ppd_read(fp, &line, keyword, name, text, &string, 0, cg);
ef416fc2 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
2e4ff8af 571 _cupsStrFree(string);
ef416fc2 572
573 return (NULL);
574 }
575
576 DEBUG_printf(("ppdOpen: keyword = %s, string = %p\n", keyword, string));
577
2e4ff8af 578 _cupsStrFree(string);
ef416fc2 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
355e94dc 591 ppd->language_level = 2;
ef416fc2 592 ppd->color_device = 0;
593 ppd->colorspace = PPD_CS_GRAY;
594 ppd->landscape = -90;
fa73b229 595 ppd->coptions = cupsArrayNew((cups_array_func_t)ppd_compare_coptions,
596 NULL);
ef416fc2 597
598 /*
599 * Get the default language for the user...
600 */
601
602 language = cupsLangDefault();
757d2cad 603 loc = localeconv();
ef416fc2 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;
e1d6a774 614 encoding = CUPS_ISO8859_1;
ef416fc2 615
2e4ff8af 616 while ((mask = ppd_read(fp, &line, keyword, name, text, &string, 1, cg)) != 0)
ef416fc2 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 {
e1d6a774 693 if ((group = ppd_get_group(ppd, "General", _("General"), cg,
694 encoding)) == NULL)
ef416fc2 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"))
e1d6a774 757 {
758 /*
759 * Say all PPD files are UTF-8, since we convert to UTF-8...
760 */
761
2e4ff8af 762 ppd->lang_encoding = _cupsStrAlloc("UTF-8");
80ca4592 763 encoding = _ppdGetEncoding(string);
e1d6a774 764 }
ef416fc2 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"))
e1d6a774 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);
2e4ff8af 783 ppd->nickname = _cupsStrAlloc((char *)utf8);
e1d6a774 784 }
785 else
2e4ff8af 786 ppd->nickname = _cupsStrAlloc(string);
e1d6a774 787 }
ef416fc2 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 {
2e4ff8af 796 ppd->jcl_begin = _cupsStrAlloc(string);
ef416fc2 797 ppd_decode(ppd->jcl_begin); /* Decode quoted string */
798 }
799 else if (!strcmp(keyword, "JCLEnd"))
800 {
2e4ff8af 801 ppd->jcl_end = _cupsStrAlloc(string);
ef416fc2 802 ppd_decode(ppd->jcl_end); /* Decode quoted string */
803 }
804 else if (!strcmp(keyword, "JCLToPSInterpreter"))
805 {
2e4ff8af 806 ppd->jcl_ps = _cupsStrAlloc(string);
ef416fc2 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
91c84a35
MS
829 if (!profile)
830 {
831 cg->ppd_status = PPD_ALLOC_ERROR;
832
833 goto error;
834 }
835
ef416fc2 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));
757d2cad 843
b86bc4cf 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);
ef416fc2 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 {
ef416fc2 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;
2e4ff8af 903 ppd->fonts[ppd->num_fonts] = _cupsStrAlloc(name);
ef416fc2 904 ppd->num_fonts ++;
905 }
fa73b229 906 else if (!strncmp(keyword, "ParamCustom", 11))
ef416fc2 907 {
fa73b229 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 */
ef416fc2 919
fa73b229 920 if ((coption = ppd_get_coption(ppd, keyword + 11)) == NULL)
ef416fc2 921 {
fa73b229 922 cg->ppd_status = PPD_ALLOC_ERROR;
ef416fc2 923
fa73b229 924 goto error;
925 }
ef416fc2 926
fa73b229 927 if ((cparam = ppd_get_cparam(coption, name, text)) == NULL)
928 {
929 cg->ppd_status = PPD_ALLOC_ERROR;
ef416fc2 930
fa73b229 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;
ef416fc2 947
fa73b229 948 if (!strcmp(ctype, "curve"))
949 {
950 cparam->type = PPD_CUSTOM_CURVE;
b86bc4cf 951 cparam->minimum.custom_curve = (float)_cupsStrScand(cminimum, NULL, loc);
952 cparam->maximum.custom_curve = (float)_cupsStrScand(cmaximum, NULL, loc);
fa73b229 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;
b86bc4cf 963 cparam->minimum.custom_invcurve = (float)_cupsStrScand(cminimum, NULL, loc);
964 cparam->maximum.custom_invcurve = (float)_cupsStrScand(cmaximum, NULL, loc);
fa73b229 965 }
966 else if (!strcmp(ctype, "passcode"))
967 {
968 cparam->type = PPD_CUSTOM_PASSCODE;
b423cd4c 969 cparam->minimum.custom_passcode = atoi(cminimum);
970 cparam->maximum.custom_passcode = atoi(cmaximum);
fa73b229 971 }
972 else if (!strcmp(ctype, "password"))
973 {
974 cparam->type = PPD_CUSTOM_PASSWORD;
b423cd4c 975 cparam->minimum.custom_password = atoi(cminimum);
976 cparam->maximum.custom_password = atoi(cmaximum);
fa73b229 977 }
978 else if (!strcmp(ctype, "points"))
979 {
980 cparam->type = PPD_CUSTOM_POINTS;
b86bc4cf 981 cparam->minimum.custom_points = (float)_cupsStrScand(cminimum, NULL, loc);
982 cparam->maximum.custom_points = (float)_cupsStrScand(cmaximum, NULL, loc);
fa73b229 983 }
984 else if (!strcmp(ctype, "real"))
985 {
986 cparam->type = PPD_CUSTOM_REAL;
b86bc4cf 987 cparam->minimum.custom_real = (float)_cupsStrScand(cminimum, NULL, loc);
988 cparam->maximum.custom_real = (float)_cupsStrScand(cmaximum, NULL, loc);
fa73b229 989 }
990 else if (!strcmp(ctype, "string"))
991 {
992 cparam->type = PPD_CUSTOM_STRING;
b423cd4c 993 cparam->minimum.custom_string = atoi(cminimum);
994 cparam->maximum.custom_string = atoi(cmaximum);
fa73b229 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"))
ef416fc2 1015 {
fa73b229 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"))
757d2cad 1022 {
1023 for (i = 0, sptr = string; i < 4; i ++)
b86bc4cf 1024 ppd->custom_margins[i] = (float)_cupsStrScand(sptr, &sptr, loc);
757d2cad 1025 }
323c5de1 1026 else if (!strncmp(keyword, "Custom", 6) && !strcmp(name, "True") && !option)
fa73b229 1027 {
0a682745
MS
1028 ppd_option_t *custom_option; /* Custom option */
1029
fa73b229 1030 DEBUG_puts("Processing Custom option...");
ef416fc2 1031
fa73b229 1032 /*
1033 * Get the option and custom option...
1034 */
ef416fc2 1035
e1d6a774 1036 if (!ppd_get_coption(ppd, keyword + 6))
ef416fc2 1037 {
fa73b229 1038 cg->ppd_status = PPD_ALLOC_ERROR;
ef416fc2 1039
1040 goto error;
1041 }
1042
0a682745
MS
1043 if (option && !strcasecmp(option->keyword, keyword + 6))
1044 custom_option = option;
1045 else
1046 custom_option = ppdFindOption(ppd, keyword + 6);
fa73b229 1047
0a682745 1048 if (custom_option)
ef416fc2 1049 {
0a682745
MS
1050 /*
1051 * Add the "custom" option...
1052 */
ef416fc2 1053
0a682745
MS
1054 if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL)
1055 {
1056 DEBUG_puts("Unable to add Custom choice!");
ef416fc2 1057
0a682745
MS
1058 cg->ppd_status = PPD_ALLOC_ERROR;
1059
1060 goto error;
1061 }
ef416fc2 1062
0a682745
MS
1063 strlcpy(choice->text, text[0] ? text : _("Custom"),
1064 sizeof(choice->text));
fa73b229 1065
0a682745
MS
1066 choice->code = _cupsStrAlloc(string);
1067 }
fa73b229 1068
1069 /*
1070 * Now process custom page sizes specially...
1071 */
1072
1073 if (!strcmp(keyword, "CustomPageSize"))
1074 {
fa73b229 1075 /*
1076 * Add a "Custom" page size entry...
1077 */
1078
0a682745 1079 ppd->variable_sizes = 1;
323c5de1 1080
0a682745 1081 ppd_add_size(ppd, "Custom");
323c5de1 1082
0a682745
MS
1083 if (option && !strcasecmp(option->keyword, "PageRegion"))
1084 custom_option = option;
1085 else
1086 custom_option = ppdFindOption(ppd, "PageRegion");
09a101d6 1087
0a682745
MS
1088 if (custom_option)
1089 {
1090 if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL)
323c5de1 1091 {
0a682745
MS
1092 DEBUG_puts("Unable to add Custom choice!");
1093
1094 cg->ppd_status = PPD_ALLOC_ERROR;
323c5de1 1095
1096 goto error;
1097 }
1098
0a682745
MS
1099 strlcpy(choice->text, text[0] ? text : _("Custom"),
1100 sizeof(choice->text));
323c5de1 1101 }
fa73b229 1102 }
ef416fc2 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;
91c84a35
MS
1122 if ((ppd->emulations = calloc(count, sizeof(ppd_emul_t))) == NULL)
1123 {
1124 cg->ppd_status = PPD_ALLOC_ERROR;
1125
1126 goto error;
1127 }
ef416fc2 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)
2e4ff8af 1168 ppd->patches = _cupsStrAlloc(string);
ef416fc2 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
bc44d920 1202 DEBUG_printf(("name=\"%s\" (%d)\n", name, strlen(name)));
1203
ef416fc2 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 {
e1d6a774 1217 if ((group = ppd_get_group(ppd, "General", _("General"), cg,
1218 encoding)) == NULL)
ef416fc2 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])
e1d6a774 1267 cupsCharsetToUTF8((cups_utf8_t *)option->text, text,
1268 sizeof(option->text), encoding);
ef416fc2 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
2e4ff8af 1287 _cupsStrFree(string);
ef416fc2 1288 string = NULL;
0a682745
MS
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 }
ef416fc2 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
e1d6a774 1334 group = ppd_get_group(ppd, "JCL", _("JCL"), cg, encoding);
ef416fc2 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
e1d6a774 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));
ef416fc2 1389
1390 option->section = PPD_ORDER_JCL;
1391 group = NULL;
1392
2e4ff8af 1393 _cupsStrFree(string);
ef416fc2 1394 string = NULL;
0a682745
MS
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 }
ef416fc2 1419 }
1420 else if (!strcmp(keyword, "CloseUI") || !strcmp(keyword, "JCLCloseUI"))
1421 {
1422 option = NULL;
1423
2e4ff8af 1424 _cupsStrFree(string);
ef416fc2 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
e1d6a774 1466 group = ppd_get_group(ppd, string, sptr, cg, encoding);
ef416fc2 1467
1468 if (group == NULL)
1469 goto error;
1470
2e4ff8af 1471 _cupsStrFree(string);
ef416fc2 1472 string = NULL;
1473 }
1474 else if (!strcmp(keyword, "CloseGroup"))
1475 {
1476 group = NULL;
1477
2e4ff8af 1478 _cupsStrFree(string);
ef416fc2 1479 string = NULL;
1480 }
0a682745 1481 else if (!strcmp(keyword, "OrderDependency"))
ef416fc2 1482 {
b86bc4cf 1483 order = (float)_cupsStrScand(string, &sptr, loc);
757d2cad 1484
1485 if (!sptr || sscanf(sptr, "%40s%40s", name, keyword) != 2)
ef416fc2 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
2e4ff8af 1536 _cupsStrFree(string);
ef416fc2 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)
323c5de1 1606 constraint = calloc(2, sizeof(ppd_const_t));
ef416fc2 1607 else
1608 constraint = realloc(ppd->consts,
323c5de1 1609 (ppd->num_consts + 2) * sizeof(ppd_const_t));
ef416fc2 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... */
2abf387c 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
ef416fc2 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);
2abf387c 1651 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1652 {
1653 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1654 goto error;
1655 }
ef416fc2 1656
1657 if (constraint->choice1[0] == '*')
1658 _cups_strcpy(constraint->option2, constraint->choice1 + 1);
2abf387c 1659 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1660 {
1661 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1662 goto error;
1663 }
ef416fc2 1664
1665 constraint->choice1[0] = '\0';
1666 constraint->choice2[0] = '\0';
1667 break;
1668
1669 case 3 : /* Two options, one choice... */
2abf387c 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
ef416fc2 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);
2abf387c 1690 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1691 {
1692 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1693 goto error;
1694 }
ef416fc2 1695
1696 if (constraint->choice1[0] == '*')
1697 {
2abf387c 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
ef416fc2 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);
2abf387c 1713 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1714 {
1715 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1716 goto error;
1717 }
ef416fc2 1718
1719 constraint->choice2[0] = '\0';
1720 }
1721 break;
1722
1723 case 4 : /* Two options, two choices... */
2abf387c 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
ef416fc2 1738 if (constraint->option1[0] == '*')
1739 _cups_strcpy(constraint->option1, constraint->option1 + 1);
2abf387c 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 }
ef416fc2 1752
1753 if (constraint->option2[0] == '*')
1754 _cups_strcpy(constraint->option2, constraint->option2 + 1);
2abf387c 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 }
ef416fc2 1767 break;
1768 }
1769
323c5de1 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
2abf387c 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
2e4ff8af 1820 _cupsStrFree(string);
ef416fc2 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
b86bc4cf 1839 size->width = (float)_cupsStrScand(string, &sptr, loc);
1840 size->length = (float)_cupsStrScand(sptr, NULL, loc);
ef416fc2 1841
2e4ff8af 1842 _cupsStrFree(string);
ef416fc2 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
b86bc4cf 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);
ef416fc2 1865
2e4ff8af 1866 _cupsStrFree(string);
ef416fc2 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
91c84a35
MS
1890 if ((choice = ppd_add_choice(option, name)) == NULL)
1891 {
1892 cg->ppd_status = PPD_ALLOC_ERROR;
1893
1894 goto error;
1895 }
ef416fc2 1896
e1d6a774 1897 if (text[0])
1898 cupsCharsetToUTF8((cups_utf8_t *)choice->text, text,
1899 sizeof(choice->text), encoding);
ef416fc2 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 }
ef416fc2 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
2e4ff8af 1922 _cupsStrFree(string);
ef416fc2 1923 }
1924
2e4ff8af
MS
1925 if (line.buffer)
1926 free(line.buffer);
1927
ef416fc2 1928 /*
1929 * Reset language preferences...
1930 */
1931
1932 cupsLangFree(language);
1933
ef416fc2 1934#ifdef DEBUG
bc44d920 1935 if (!cupsFileEOF(fp))
1936 printf("Premature EOF at %lu...\n", (unsigned long)cupsFileTell(fp));
ef416fc2 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
ef416fc2 1950 /*
fa73b229 1951 * Create the sorted options array and set the option back-pointer for
1952 * each choice and custom option...
ef416fc2 1953 */
1954
b94498cf 1955 ppd->options = cupsArrayNew2((cups_array_func_t)ppd_compare_options, NULL,
1956 (cups_ahash_func_t)ppd_hash_option,
1957 PPD_HASHSIZE);
ef416fc2 1958
1959 for (i = ppd->num_groups, group = ppd->groups;
1960 i > 0;
1961 i --, group ++)
1962 {
ef416fc2 1963 for (j = group->num_options, option = group->options;
1964 j > 0;
1965 j --, option ++)
1966 {
fa73b229 1967 ppd_coption_t *coption; /* Custom option */
ef416fc2 1968
ef416fc2 1969
fa73b229 1970 cupsArrayAdd(ppd->options, option);
ef416fc2 1971
fa73b229 1972 for (k = 0; k < option->num_choices; k ++)
1973 option->choices[k].option = option;
ef416fc2 1974
fa73b229 1975 if ((coption = ppdFindCustomOption(ppd, option->keyword)) != NULL)
1976 coption->option = option;
1977 }
1978 }
ef416fc2 1979
b94498cf 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
ef416fc2 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
2e4ff8af
MS
2006 if (line.buffer)
2007 free(line.buffer);
2008
2009 _cupsStrFree(string);
ef416fc2 2010
2011 ppdClose(ppd);
2012
2013 cupsLangFree(language);
2014
ef416fc2 2015 return (NULL);
2016}
2017
2018
2019/*
2020 * 'ppdOpenFd()' - Read a PPD file into memory.
2021 */
2022
5a738aea 2023ppd_file_t * /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
ef416fc2 2024ppdOpenFd(int fd) /* I - File to read from */
2025{
fa73b229 2026 cups_file_t *fp; /* CUPS file pointer */
ef416fc2 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
fa73b229 2053 if ((fp = cupsFileOpenFd(fd, "r")) != NULL)
ef416fc2 2054 {
fa73b229 2055 ppd = ppdOpen2(fp);
ef416fc2 2056
fa73b229 2057 cupsFileClose(fp);
ef416fc2 2058 }
2059 else
2060 {
2061 cg->ppd_status = PPD_FILE_OPEN_ERROR;
fa73b229 2062 ppd = NULL;
ef416fc2 2063 }
2064
2065 return (ppd);
2066}
2067
2068
2069/*
2070 * 'ppdOpenFile()' - Read a PPD file into memory.
2071 */
2072
5a738aea 2073ppd_file_t * /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
ef416fc2 2074ppdOpenFile(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
2125void
2126ppdSetConformance(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
2140static ppd_attr_t * /* O - New attribute */
2141ppd_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
bd7854cb 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
ef416fc2 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
bd7854cb 2197 /*
2198 * Add the attribute to the sorted array...
2199 */
2200
2201 cupsArrayAdd(ppd->sorted_attrs, temp);
2202
ef416fc2 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
2215static ppd_choice_t * /* O - Named choice */
2216ppd_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
2246static ppd_size_t * /* O - Named size */
2247ppd_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
bd7854cb 2272/*
2273 * 'ppd_compare_attrs()' - Compare two attributes.
2274 */
2275
2276static int /* O - Result of comparison */
2277ppd_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);
bd7854cb 2285 else
d09495fa 2286 return (strcasecmp(a->spec, b->spec));
bd7854cb 2287}
2288
2289
b94498cf 2290/*
2291 * 'ppd_compare_choices()' - Compare two choices...
2292 */
2293
2294static int /* O - Result of comparison */
2295ppd_compare_choices(ppd_choice_t *a, /* I - First choice */
2296 ppd_choice_t *b) /* I - Second choice */
2297{
355e94dc 2298 return (strcmp(a->option->keyword, b->option->keyword));
b94498cf 2299}
2300
2301
2302/*
2303 * 'ppd_compare_consts()' - Compare two constraints.
2304 */
2305
2306static int /* O - Result of comparison */
2307ppd_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
ef416fc2 2324/*
fa73b229 2325 * 'ppd_compare_coptions()' - Compare two custom options.
ef416fc2 2326 */
2327
2328static int /* O - Result of comparison */
fa73b229 2329ppd_compare_coptions(ppd_coption_t *a, /* I - First option */
2330 ppd_coption_t *b) /* I - Second option */
ef416fc2 2331{
fa73b229 2332 return (strcasecmp(a->keyword, b->keyword));
2333}
2334
2335
2336/*
2337 * 'ppd_compare_cparams()' - Compare two custom parameters.
2338 */
2339
2340static int /* O - Result of comparison */
2341ppd_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));
ef416fc2 2345}
2346
2347
2348/*
2349 * 'ppd_compare_options()' - Compare two options.
2350 */
2351
2352static int /* O - Result of comparison */
fa73b229 2353ppd_compare_options(ppd_option_t *a, /* I - First option */
2354 ppd_option_t *b) /* I - Second option */
ef416fc2 2355{
fa73b229 2356 return (strcasecmp(a->keyword, b->keyword));
ef416fc2 2357}
ef416fc2 2358
2359
2360/*
2361 * 'ppd_decode()' - Decode a string value...
2362 */
2363
2364static int /* O - Length of decoded string */
2365ppd_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
2421static void
2422ppd_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
2455static void
2456ppd_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 {
2e4ff8af 2468 _cupsStrFree(choice->code);
ef416fc2 2469 }
2470
2471 ppd_free(option->choices);
2472 }
2473}
2474
2475
ef416fc2 2476/*
fa73b229 2477 * 'ppd_get_coption()' - Get a custom option record.
ef416fc2 2478 */
2479
fa73b229 2480static ppd_coption_t * /* O - Custom option... */
2481ppd_get_coption(ppd_file_t *ppd, /* I - PPD file */
2482 const char *name) /* I - Name of option */
ef416fc2 2483{
fa73b229 2484 ppd_coption_t *copt; /* New custom option */
ef416fc2 2485
2486
2487 /*
2488 * See if the option already exists...
2489 */
2490
fa73b229 2491 if ((copt = ppdFindCustomOption(ppd, name)) != NULL)
2492 return (copt);
ef416fc2 2493
2494 /*
fa73b229 2495 * Not found, so create the custom option record...
ef416fc2 2496 */
2497
fa73b229 2498 if ((copt = calloc(1, sizeof(ppd_coption_t))) == NULL)
ef416fc2 2499 return (NULL);
2500
fa73b229 2501 strlcpy(copt->keyword, name, sizeof(copt->keyword));
ef416fc2 2502
fa73b229 2503 copt->params = cupsArrayNew((cups_array_func_t)ppd_compare_cparams, NULL);
ef416fc2 2504
fa73b229 2505 cupsArrayAdd(ppd->coptions, copt);
ef416fc2 2506
2507 /*
2508 * Return the new record...
2509 */
2510
fa73b229 2511 return (copt);
ef416fc2 2512}
2513
2514
2515/*
fa73b229 2516 * 'ppd_get_cparam()' - Get a custom parameter record.
ef416fc2 2517 */
2518
fa73b229 2519static ppd_cparam_t * /* O - Extended option... */
2520ppd_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 */
ef416fc2 2523{
fa73b229 2524 ppd_cparam_t *cparam; /* New custom parameter */
ef416fc2 2525
2526
2527 /*
2528 * See if the parameter already exists...
2529 */
2530
fa73b229 2531 if ((cparam = ppdFindCustomParam(opt, param)) != NULL)
2532 return (cparam);
ef416fc2 2533
2534 /*
fa73b229 2535 * Not found, so create the custom parameter record...
ef416fc2 2536 */
2537
fa73b229 2538 if ((cparam = calloc(1, sizeof(ppd_cparam_t))) == NULL)
ef416fc2 2539 return (NULL);
2540
fa73b229 2541 strlcpy(cparam->name, param, sizeof(cparam->name));
b86bc4cf 2542 strlcpy(cparam->text, text[0] ? text : param, sizeof(cparam->text));
ef416fc2 2543
2544 /*
fa73b229 2545 * Add this record to the array...
ef416fc2 2546 */
2547
fa73b229 2548 cupsArrayAdd(opt->params, cparam);
ef416fc2 2549
2550 /*
2551 * Return the new record...
2552 */
2553
fa73b229 2554 return (cparam);
ef416fc2 2555}
ef416fc2 2556
2557
2558/*
2559 * 'ppd_get_group()' - Find or create the named group as needed.
2560 */
2561
2562static ppd_group_t * /* O - Named group */
e1d6a774 2563ppd_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 */
ef416fc2 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));
e1d6a774 2610
2611 cupsCharsetToUTF8((cups_utf8_t *)group->text, text,
2612 sizeof(group->text), encoding);
ef416fc2 2613 }
2614
2615 return (group);
2616}
2617
2618
2619/*
2620 * 'ppd_get_option()' - Find or create the named option as needed.
2621 */
2622
2623static ppd_option_t * /* O - Named option */
2624ppd_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
b94498cf 2661/*
2662 * 'ppd_hash_option()' - Generate a hash of the option name...
2663 */
2664
2665static int /* O - Hash index */
2666ppd_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
ef416fc2 2679/*
2680 * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
2681 * necessary.
2682 */
2683
2684static int /* O - Bitmask of fields read */
2685ppd_read(cups_file_t *fp, /* I - File to read from */
2e4ff8af 2686 _ppd_line_t *line, /* I - Line buffer */
ef416fc2 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 */
2e4ff8af 2705 *lineptr; /* Current position in line buffer */
ef416fc2 2706
ef416fc2 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;
ef416fc2 2715
2e4ff8af
MS
2716 if (!line->buffer)
2717 {
2718 line->bufsize = 1024;
2719 line->buffer = malloc(1024);
2720
2721 if (!line->buffer)
2722 return (0);
2723 }
ef416fc2 2724
2725 do
2726 {
2727 /*
2728 * Read the line...
2729 */
2730
2e4ff8af 2731 lineptr = line->buffer;
ef416fc2 2732 endquote = 0;
2733 colon = 0;
2734
2735 while ((ch = cupsFileGetChar(fp)) != EOF)
2736 {
2e4ff8af 2737 if (lineptr >= (line->buffer + line->bufsize - 1))
ef416fc2 2738 {
2739 /*
2740 * Expand the line buffer...
2741 */
2742
2743 char *temp; /* Temporary line pointer */
2744
2745
2e4ff8af
MS
2746 line->bufsize += 1024;
2747 if (line->bufsize > 262144)
ef416fc2 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
ef416fc2 2756 return (0);
2757 }
2758
2e4ff8af 2759 temp = realloc(line->buffer, line->bufsize);
ef416fc2 2760 if (!temp)
2761 {
2762 cg->ppd_line = startline;
2763 cg->ppd_status = PPD_LINE_TOO_LONG;
2764
ef416fc2 2765 return (0);
2766 }
2767
2e4ff8af
MS
2768 lineptr = temp + (lineptr - line->buffer);
2769 line->buffer = temp;
ef416fc2 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)
fa73b229 2788 {
2789 ch = '\n';
ef416fc2 2790 break;
fa73b229 2791 }
2792
ef416fc2 2793 if (ch == 0x0a)
2794 cupsFileGetChar(fp);
2795 }
2796
2e4ff8af 2797 if (lineptr == line->buffer && ignoreblank)
ef416fc2 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
ef416fc2 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
ef416fc2 2836 return (0);
2837 }
2838
2e4ff8af 2839 if (ch == ':' && strncmp(line->buffer, "*%", 2) != 0)
ef416fc2 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
ef416fc2 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
ef416fc2 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
ef416fc2 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
ef416fc2 2958 return (0);
2959 }
2960 }
2961 }
2962
2e4ff8af 2963 if (lineptr > line->buffer && lineptr[-1] == '\n')
ef416fc2 2964 lineptr --;
2965
2966 *lineptr = '\0';
2967
2968 DEBUG_printf(("LINE = \"%s\"\n", line));
2969
bd7854cb 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
2e4ff8af 2977 if (!strcmp(line->buffer, "*%APLWORKSET START"))
bd7854cb 2978 return (0);
bd7854cb 2979
2e4ff8af 2980 if (ch == EOF && lineptr == line->buffer)
ef416fc2 2981 return (0);
ef416fc2 2982
2983 /*
2984 * Now parse it...
2985 */
2986
2987 mask = 0;
2e4ff8af 2988 lineptr = line->buffer + 1;
ef416fc2 2989
2990 keyword[0] = '\0';
2991 option[0] = '\0';
2992 text[0] = '\0';
2993 *string = NULL;
2994
2e4ff8af
MS
2995 if ((!line->buffer[0] || /* Blank line */
2996 !strncmp(line->buffer, "*%", 2) || /* Comment line */
2997 !strcmp(line->buffer, "*End")) && /* End of multi-line string */
ef416fc2 2998 ignoreblank) /* Ignore these? */
2999 {
3000 startline = cg->ppd_line + 1;
3001 continue;
3002 }
3003
2e4ff8af 3004 if (!strcmp(line->buffer, "*")) /* (Bad) comment line */
ef416fc2 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
ef416fc2 3016 return (0);
3017 }
3018 }
3019
2e4ff8af 3020 if (line->buffer[0] != '*') /* All lines start with an asterisk */
ef416fc2 3021 {
ef416fc2 3022 /*
3023 * Allow lines consisting of just whitespace...
3024 */
3025
2e4ff8af 3026 for (lineptr = line->buffer; *lineptr; lineptr ++)
ef416fc2 3027 if (!isspace(*lineptr & 255))
3028 break;
3029
3030 if (*lineptr)
3031 {
3032 cg->ppd_status = PPD_MISSING_ASTERISK;
ef416fc2 3033 return (0);
3034 }
3035 else if (ignoreblank)
3036 continue;
3037 else
ef416fc2 3038 return (0);
ef416fc2 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;
ef416fc2 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;
ef416fc2 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;
ef416fc2 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;
ef416fc2 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;
ef416fc2 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;
ef416fc2 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 /*
2e4ff8af 3170 * Quoted string by itself, remove quotes...
ef416fc2 3171 */
3172
2e4ff8af
MS
3173 *strptr = '\0';
3174 lineptr ++;
ef416fc2 3175 }
2e4ff8af
MS
3176
3177 *string = _cupsStrAlloc(lineptr);
ef416fc2 3178
3179/* DEBUG_printf(("string = \"%s\", lineptr = \"%s\"\n", *string, lineptr));*/
3180
3181 mask |= PPD_STRING;
3182 }
3183 }
3184 while (mask == 0);
3185
ef416fc2 3186 return (mask);
3187}
3188
3189
3190/*
2e4ff8af 3191 * End of "$Id: ppd.c 6937 2007-09-10 21:13:31Z mike $".
ef416fc2 3192 */