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