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