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