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