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