]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/ppd.c
Changelog.
[thirdparty/cups.git] / cups / ppd.c
CommitLineData
90a24de4 1/*
b2e10895 2 * "$Id$"
90a24de4 3 *
64dd1836 4 * PPD file routines for CUPS.
90a24de4 5 *
c45401bb 6 * Copyright 2007-2012 by Apple Inc.
d220c7b8 7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
90a24de4 8 *
3a193f5e 9 * These coded instructions, statements, and computer programs are the
4e8d321f 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/".
90a24de4 14 *
2b85e375 15 * PostScript is a trademark of Adobe Systems, Inc.
16 *
b87e43e9 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 *
dab1a4d8 24 * This file is subject to the Apple OS-Developed Software exception.
25 *
90a24de4 26 * Contents:
27 *
ff6a82d3 28 * ppdClose() - Free all memory used by the PPD file.
29 * ppdErrorString() - Returns the text assocated with a status.
cae6fedc 30 * _ppdGetEncoding() - Get the CUPS encoding value for the given
31 * LanguageEncoding.
ff6a82d3 32 * ppdLastError() - Return the status from the last ppdOpen*().
33 * ppdOpen() - Read a PPD file into memory.
6ee6a397 34 * _ppdOpen() - Read a PPD file into memory.
91ac93ad 35 * ppdOpen2() - Read a PPD file into memory.
ff6a82d3 36 * ppdOpenFd() - Read a PPD file into memory.
6ee6a397 37 * _ppdOpenFile() - Read a PPD file into memory.
ff6a82d3 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.
91ac93ad 43 * ppd_compare_attrs() - Compare two attributes.
6482819f 44 * ppd_compare_choices() - Compare two choices...
ff6a82d3 45 * ppd_compare_coptions() - Compare two custom options.
ff6a82d3 46 * ppd_compare_options() - Compare two options.
47 * ppd_decode() - Decode a string value...
5772e663 48 * ppd_free_filters() - Free the filters array.
ff6a82d3 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.
6482819f 55 * ppd_hash_option() - Generate a hash of the option name...
ff6a82d3 56 * ppd_read() - Read a line from a PPD file, skipping comment
57 * lines as necessary.
5772e663 58 * ppd_update_filters() - Update the filters array as needed.
90a24de4 59 */
60
61/*
62 * Include necessary headers.
63 */
64
3d94661a 65#include "cups-private.h"
d085884a 66#include "ppd-private.h"
2b85e375 67
68
69/*
70 * Definitions...
71 */
72
3b960317 73#if defined(WIN32) || defined(__EMX__)
2b85e375 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 */
3b960317 79#endif /* WIN32 || __EMX__ */
2b85e375 80
1fdc6cd5 81#define ppd_free(p) if (p) free(p) /* Safe free macro */
08b247a9 82
2b85e375 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 */
554fab97 87
6482819f 88#define PPD_HASHSIZE 512 /* Size of hash */
89
2b85e375 90
80ad038a 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
2b85e375 102/*
103 * Local functions...
104 */
105
1fdc6cd5 106static ppd_attr_t *ppd_add_attr(ppd_file_t *ppd, const char *name,
1b98ab76 107 const char *spec, const char *text,
108 const char *value);
1fdc6cd5 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);
91ac93ad 111static int ppd_compare_attrs(ppd_attr_t *a, ppd_attr_t *b);
6482819f 112static int ppd_compare_choices(ppd_choice_t *a, ppd_choice_t *b);
91ac93ad 113static int ppd_compare_coptions(ppd_coption_t *a,
114 ppd_coption_t *b);
ff6a82d3 115static int ppd_compare_options(ppd_option_t *a, ppd_option_t *b);
0ca3829c 116static int ppd_decode(char *string);
5772e663 117static void ppd_free_filters(ppd_file_t *ppd);
6fdf969a 118static void ppd_free_group(ppd_group_t *group);
119static void ppd_free_option(ppd_option_t *option);
ff6a82d3 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);
83575f2d 124static ppd_group_t *ppd_get_group(ppd_file_t *ppd, const char *name,
ed04873a 125 const char *text, _cups_globals_t *cg,
126 cups_encoding_t encoding);
83575f2d 127static ppd_option_t *ppd_get_option(ppd_group_t *group, const char *name);
6482819f 128static int ppd_hash_option(ppd_option_t *option);
80ad038a 129static int ppd_read(cups_file_t *fp, _ppd_line_t *line,
130 char *keyword, char *option, char *text,
131 char **string, int ignoreblank,
2625096f 132 _cups_globals_t *cg);
5772e663 133static int ppd_update_filters(ppd_file_t *ppd,
134 _cups_globals_t *cg);
1fdc6cd5 135
136
2b85e375 137/*
138 * 'ppdClose()' - Free all memory used by the PPD file.
139 */
140
141void
1fdc6cd5 142ppdClose(ppd_file_t *ppd) /* I - PPD file record */
2b85e375 143{
08379093 144 int i; /* Looping var */
ab94f399 145 ppd_emul_t *emul; /* Current emulation */
146 ppd_group_t *group; /* Current group */
147 char **font; /* Current font */
ab94f399 148 ppd_attr_t **attr; /* Current attribute */
ff6a82d3 149 ppd_coption_t *coption; /* Current custom option */
150 ppd_cparam_t *cparam; /* Current custom parameter */
2b85e375 151
152
153 /*
ff6a82d3 154 * Range check arguments...
2b85e375 155 */
156
ff6a82d3 157 if (!ppd)
2b85e375 158 return;
159
160 /*
161 * Free all strings at the top level...
162 */
163
80ad038a 164 _cupsStrFree(ppd->lang_encoding);
165 _cupsStrFree(ppd->nickname);
a56d8322 166 if (ppd->patches)
167 free(ppd->patches);
80ad038a 168 _cupsStrFree(ppd->jcl_begin);
169 _cupsStrFree(ppd->jcl_end);
170 _cupsStrFree(ppd->jcl_ps);
2b85e375 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 {
80ad038a 180 _cupsStrFree(emul->start);
181 _cupsStrFree(emul->stop);
e8fda7b9 182 }
2b85e375 183
1fdc6cd5 184 ppd_free(ppd->emulations);
e8fda7b9 185 }
2b85e375 186
2b85e375 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
1fdc6cd5 196 ppd_free(ppd->groups);
e8fda7b9 197 }
2b85e375 198
ff6a82d3 199 cupsArrayDelete(ppd->options);
6482819f 200 cupsArrayDelete(ppd->marked);
ff6a82d3 201
2b85e375 202 /*
203 * Free any page sizes...
204 */
205
206 if (ppd->num_sizes > 0)
1fdc6cd5 207 ppd_free(ppd->sizes);
2b85e375 208
209 /*
210 * Free any constraints...
211 */
212
213 if (ppd->num_consts > 0)
1fdc6cd5 214 ppd_free(ppd->consts);
2b85e375 215
04de52f8 216 /*
217 * Free any filters...
218 */
219
5772e663 220 ppd_free_filters(ppd);
04de52f8 221
2b85e375 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 ++)
80ad038a 229 _cupsStrFree(*font);
2b85e375 230
1fdc6cd5 231 ppd_free(ppd->fonts);
e8fda7b9 232 }
2b85e375 233
b87e43e9 234 /*
235 * Free any profiles...
236 */
237
238 if (ppd->num_profiles > 0)
1fdc6cd5 239 ppd_free(ppd->profiles);
b87e43e9 240
da5bb70a 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 {
80ad038a 249 _cupsStrFree((*attr)->value);
1fdc6cd5 250 ppd_free(*attr);
da5bb70a 251 }
252
1fdc6cd5 253 ppd_free(ppd->attrs);
da5bb70a 254 }
255
df79d570 256 cupsArrayDelete(ppd->sorted_attrs);
257
ff6a82d3 258 /*
259 * Free custom options...
260 */
ab94f399 261
ff6a82d3 262 for (coption = (ppd_coption_t *)cupsArrayFirst(ppd->coptions);
263 coption;
264 coption = (ppd_coption_t *)cupsArrayNext(ppd->coptions))
265 {
266 for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
267 cparam;
268 cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
b9e18094 269 {
270 switch (cparam->type)
271 {
272 case PPD_CUSTOM_PASSCODE :
273 case PPD_CUSTOM_PASSWORD :
274 case PPD_CUSTOM_STRING :
80ad038a 275 _cupsStrFree(cparam->current.custom_string);
b9e18094 276 break;
277
278 default :
279 break;
280 }
281
ff6a82d3 282 free(cparam);
b9e18094 283 }
284
285 cupsArrayDelete(coption->params);
ab94f399 286
ff6a82d3 287 free(coption);
ab94f399 288 }
ff6a82d3 289
290 cupsArrayDelete(ppd->coptions);
ab94f399 291
d085884a 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
64dd1836 312 /*
8211508e 313 * Free any PPD cache/mapping data...
64dd1836 314 */
315
8211508e 316 if (ppd->cache)
317 _ppdCacheDestroy(ppd->cache);
64dd1836 318
2b85e375 319 /*
320 * Free the whole record...
321 */
322
1fdc6cd5 323 ppd_free(ppd);
6fdf969a 324}
325
326
79f448f9 327/*
328 * 'ppdErrorString()' - Returns the text assocated with a status.
0341722a 329 *
c45401bb 330 * @since CUPS 1.1.19/OS X 10.3@
79f448f9 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 {
ff6a82d3 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"),
b45cde5d 358 _("Bad custom parameter"),
359 _("Missing option keyword"),
f91e4743 360 _("Bad value string"),
361 _("Missing CloseGroup")
79f448f9 362 };
363
364
b45cde5d 365 if (status < PPD_OK || status >= PPD_MAX_STATUS)
ff6a82d3 366 return (_cupsLangString(cupsLangDefault(), _("Unknown")));
79f448f9 367 else
ff6a82d3 368 return (_cupsLangString(cupsLangDefault(), messages[status]));
79f448f9 369}
370
371
cae6fedc 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{
c6fab96f 380 if (!_cups_strcasecmp(name, "ISOLatin1"))
cae6fedc 381 return (CUPS_ISO8859_1);
c6fab96f 382 else if (!_cups_strcasecmp(name, "ISOLatin2"))
cae6fedc 383 return (CUPS_ISO8859_2);
c6fab96f 384 else if (!_cups_strcasecmp(name, "ISOLatin5"))
cae6fedc 385 return (CUPS_ISO8859_5);
c6fab96f 386 else if (!_cups_strcasecmp(name, "JIS83-RKSJ"))
78704eca 387 return (CUPS_JIS_X0213);
c6fab96f 388 else if (!_cups_strcasecmp(name, "MacStandard"))
cae6fedc 389 return (CUPS_MAC_ROMAN);
c6fab96f 390 else if (!_cups_strcasecmp(name, "WindowsANSI"))
cae6fedc 391 return (CUPS_WINDOWS_1252);
392 else
393 return (CUPS_UTF8);
394}
395
396
79f448f9 397/*
398 * 'ppdLastError()' - Return the status from the last ppdOpen*().
0341722a 399 *
c45401bb 400 * @since CUPS 1.1.19/OS X 10.3@
79f448f9 401 */
402
403ppd_status_t /* O - Status code */
404ppdLastError(int *line) /* O - Line number */
405{
2625096f 406 _cups_globals_t *cg = _cupsGlobals();
03f61bf3 407 /* Global data */
408
409
79f448f9 410 if (line)
03f61bf3 411 *line = cg->ppd_line;
79f448f9 412
03f61bf3 413 return (cg->ppd_status);
79f448f9 414}
415
416
2b85e375 417/*
6ee6a397 418 * '_ppdOpen()' - Read a PPD file into memory.
0341722a 419 *
c45401bb 420 * @since CUPS 1.2/OS X 10.5@
08379093 421 */
422
8f6753d3 423ppd_file_t * /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
6ee6a397 424_ppdOpen(
425 cups_file_t *fp, /* I - File to read from */
426 _ppd_localization_t localization) /* I - Localization to load */
2b85e375 427{
ff6a82d3 428 int i, j, k; /* Looping vars */
1fdc6cd5 429 int count; /* Temporary count */
80ad038a 430 _ppd_line_t line; /* Line buffer */
1fdc6cd5 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 */
1fdc6cd5 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 */
94ffdf17 454 struct lconv *loc; /* Locale data */
c3d3f40d 455 int ui_keyword; /* Is this line a UI keyword? */
6ee6a397 456 cups_lang_t *lang; /* Language data */
ed04873a 457 cups_encoding_t encoding; /* Encoding of PPD file */
2625096f 458 _cups_globals_t *cg = _cupsGlobals();
03f61bf3 459 /* Global data */
5412d0bc 460 char custom_name[PPD_MAX_NAME];
461 /* CustomFoo attribute name */
462 ppd_attr_t *custom_attr; /* CustomFoo attribute */
6ee6a397 463 char ll[4], /* Language + '.' */
464 ll_CC[7]; /* Language + country + '.' */
014b8cd5 465 size_t ll_len = 0, /* Language length */
466 ll_CC_len = 0; /* Language + country length */
b3291c5a 467 static const char * const ui_keywords[] =
468 {
91ac93ad 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 */
b3291c5a 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",
b3291c5a 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",
b3291c5a 514 "Separations",
b3291c5a 515 "Signature",
516 "Slipsheet",
517 "Smoothing",
518 "StapleLocation",
519 "StapleOrientation",
520 "StapleWhen",
521 "StapleX",
3ef42c86 522 "StapleY"
91ac93ad 523#else /* !CUPS_USE_FULL_UI_KEYWORDS_LIST */
524 "PageRegion",
525 "PageSize"
526#endif /* CUPS_USE_FULL_UI_KEYWORDS_LIST */
b3291c5a 527 };
6ee6a397 528 static const char * const color_keywords[] = /* Keywords associated with color profiles */
529 {
530 ".cupsICCProfile",
531 ".ColorModel",
532 };
2b85e375 533
534
6ee6a397 535 DEBUG_printf(("_ppdOpen(fp=%p)", fp));
bf830e05 536
79f448f9 537 /*
538 * Default to "OK" status...
539 */
540
03f61bf3 541 cg->ppd_status = PPD_OK;
542 cg->ppd_line = 0;
79f448f9 543
2b85e375 544 /*
545 * Range check input...
546 */
547
548 if (fp == NULL)
79f448f9 549 {
03f61bf3 550 cg->ppd_status = PPD_NULL_FILE;
2b85e375 551 return (NULL);
79f448f9 552 }
2b85e375 553
6ee6a397 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
2b85e375 573 /*
574 * Grab the first line and make sure it reads '*PPD-Adobe: "major.minor"'...
575 */
576
80ad038a 577 line.buffer = NULL;
578 line.bufsize = 0;
579
580 mask = ppd_read(fp, &line, keyword, name, text, &string, 0, cg);
60dc191d 581
6ee6a397 582 DEBUG_printf(("2_ppdOpen: mask=%x, keyword=\"%s\"...", mask, keyword));
2b85e375 583
584 if (mask == 0 ||
a501ad17 585 strcmp(keyword, "PPD-Adobe") ||
2b85e375 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
03f61bf3 592 if (cg->ppd_status == PPD_OK)
593 cg->ppd_status = PPD_MISSING_PPDADOBE4;
79f448f9 594
80ad038a 595 _cupsStrFree(string);
ac682d83 596 ppd_free(line.buffer);
2b85e375 597
598 return (NULL);
e8fda7b9 599 }
2b85e375 600
6ee6a397 601 DEBUG_printf(("2_ppdOpen: keyword=%s, string=%p", keyword, string));
923e8756 602
80ad038a 603 _cupsStrFree(string);
2b85e375 604
605 /*
606 * Allocate memory for the PPD file record...
607 */
608
ab94f399 609 if ((ppd = calloc(1, sizeof(ppd_file_t))) == NULL)
79f448f9 610 {
03f61bf3 611 cg->ppd_status = PPD_ALLOC_ERROR;
79f448f9 612
ac682d83 613 _cupsStrFree(string);
614 ppd_free(line.buffer);
615
2b85e375 616 return (NULL);
79f448f9 617 }
2b85e375 618
4a5dc55d 619 ppd->language_level = 2;
2b85e375 620 ppd->color_device = 0;
b6c39946 621 ppd->colorspace = PPD_CS_N;
6df23e27 622 ppd->landscape = -90;
ff6a82d3 623 ppd->coptions = cupsArrayNew((cups_array_func_t)ppd_compare_coptions,
624 NULL);
2b85e375 625
626 /*
627 * Read lines from the PPD file and add them to the file record...
628 */
629
c3d3f40d 630 group = NULL;
631 subgroup = NULL;
632 option = NULL;
633 choice = NULL;
634 ui_keyword = 0;
ed04873a 635 encoding = CUPS_ISO8859_1;
7ca891cd 636 loc = localeconv();
2b85e375 637
80ad038a 638 while ((mask = ppd_read(fp, &line, keyword, name, text, &string, 1, cg)) != 0)
2b85e375 639 {
6ee6a397 640 DEBUG_printf(("2_ppdOpen: mask=%x, keyword=\"%s\", name=\"%s\", "
bf830e05 641 "text=\"%s\", string=%d chars...", mask, keyword, name, text,
3e3edac4 642 string ? (int)strlen(string) : 0));
2b85e375 643
4f26eecc 644 if (strncmp(keyword, "Default", 7) && !string &&
645 cg->ppd_conform != PPD_CONFORM_RELAXED)
753453e4 646 {
647 /*
648 * Need a string value!
649 */
650
03f61bf3 651 cg->ppd_status = PPD_MISSING_VALUE;
79f448f9 652
5a617005 653 goto error;
753453e4 654 }
6c56d4a8 655 else if (!string)
656 continue;
753453e4 657
b3291c5a 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
c3d3f40d 667 if (ui_keyword)
668 {
669 /*
670 * Previous line was a UI keyword...
671 */
672
673 option = NULL;
674 ui_keyword = 0;
675 }
676
6ee6a397 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 &&
57c23e2d 684 ((temp - keyword) == 2 || (temp - keyword) == 5) &&
6ee6a397 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
6d266d67 721 if (option == NULL &&
722 (mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) ==
723 (PPD_KEYWORD | PPD_OPTION | PPD_STRING))
b3291c5a 724 {
725 for (i = 0; i < (int)(sizeof(ui_keywords) / sizeof(ui_keywords[0])); i ++)
a2b8b819 726 if (!strcmp(keyword, ui_keywords[i]))
b3291c5a 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
c3d3f40d 735 ui_keyword = 1;
736
6ee6a397 737 DEBUG_printf(("2_ppdOpen: FOUND ADOBE UI KEYWORD %s WITHOUT OPENUI!",
a2b8b819 738 keyword));
739
b3291c5a 740 if (!group)
741 {
ed04873a 742 if ((group = ppd_get_group(ppd, "General", _("General"), cg,
743 encoding)) == NULL)
5a617005 744 goto error;
b3291c5a 745
6ee6a397 746 DEBUG_printf(("2_ppdOpen: Adding to group %s...", group->text));
a2b8b819 747 option = ppd_get_option(group, keyword);
b3291c5a 748 group = NULL;
749 }
750 else
a2b8b819 751 option = ppd_get_option(group, keyword);
b3291c5a 752
753 if (option == NULL)
754 {
03f61bf3 755 cg->ppd_status = PPD_ALLOC_ERROR;
b3291c5a 756
5a617005 757 goto error;
b3291c5a 758 }
759
760 /*
761 * Now fill in the initial information for the option...
762 */
763
a2b8b819 764 if (!strncmp(keyword, "JCL", 3))
b3291c5a 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;
a2b8b819 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 {
6ee6a397 781 DEBUG_printf(("2_ppdOpen: Setting Default%s to %s via attribute...",
fd8e0b1e 782 option->keyword, ppd->attrs[j]->value));
a2b8b819 783 strlcpy(option->defchoice, ppd->attrs[j]->value,
784 sizeof(option->defchoice));
785 break;
786 }
0e245dd1 787
a501ad17 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));
0e245dd1 798 else
799 strlcpy(option->text, keyword, sizeof(option->text));
b3291c5a 800 }
801 }
802
a501ad17 803 if (!strcmp(keyword, "LanguageLevel"))
d23a857a 804 ppd->language_level = atoi(string);
a501ad17 805 else if (!strcmp(keyword, "LanguageEncoding"))
ed04873a 806 {
8c4a3f1a 807 /*
808 * Say all PPD files are UTF-8, since we convert to UTF-8...
809 */
810
80ad038a 811 ppd->lang_encoding = _cupsStrAlloc("UTF-8");
cae6fedc 812 encoding = _ppdGetEncoding(string);
ed04873a 813 }
a501ad17 814 else if (!strcmp(keyword, "LanguageVersion"))
d23a857a 815 ppd->lang_version = string;
a501ad17 816 else if (!strcmp(keyword, "Manufacturer"))
2b85e375 817 ppd->manufacturer = string;
a501ad17 818 else if (!strcmp(keyword, "ModelName"))
d23a857a 819 ppd->modelname = string;
a501ad17 820 else if (!strcmp(keyword, "Protocols"))
f103f1dc 821 ppd->protocols = string;
a501ad17 822 else if (!strcmp(keyword, "PCFileName"))
1fcd229c 823 ppd->pcfilename = string;
a501ad17 824 else if (!strcmp(keyword, "NickName"))
ed04873a 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);
80ad038a 832 ppd->nickname = _cupsStrAlloc((char *)utf8);
ed04873a 833 }
834 else
80ad038a 835 ppd->nickname = _cupsStrAlloc(string);
ed04873a 836 }
a501ad17 837 else if (!strcmp(keyword, "Product"))
2b85e375 838 ppd->product = string;
a501ad17 839 else if (!strcmp(keyword, "ShortNickName"))
2b85e375 840 ppd->shortnickname = string;
a501ad17 841 else if (!strcmp(keyword, "TTRasterizer"))
d23a857a 842 ppd->ttrasterizer = string;
a501ad17 843 else if (!strcmp(keyword, "JCLBegin"))
2b85e375 844 {
80ad038a 845 ppd->jcl_begin = _cupsStrAlloc(string);
2e8cd988 846 ppd_decode(ppd->jcl_begin); /* Decode quoted string */
2b85e375 847 }
a501ad17 848 else if (!strcmp(keyword, "JCLEnd"))
2b85e375 849 {
80ad038a 850 ppd->jcl_end = _cupsStrAlloc(string);
2e8cd988 851 ppd_decode(ppd->jcl_end); /* Decode quoted string */
2b85e375 852 }
a501ad17 853 else if (!strcmp(keyword, "JCLToPSInterpreter"))
2b85e375 854 {
80ad038a 855 ppd->jcl_ps = _cupsStrAlloc(string);
2e8cd988 856 ppd_decode(ppd->jcl_ps); /* Decode quoted string */
2b85e375 857 }
a501ad17 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"))
d23a857a 869 ppd->model_number = atoi(string);
a501ad17 870 else if (!strcmp(keyword, "cupsColorProfile"))
b87e43e9 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
09751e0f 878 if (!profile)
879 {
880 cg->ppd_status = PPD_ALLOC_ERROR;
881
882 goto error;
883 }
884
b87e43e9 885 ppd->profiles = profile;
886 profile += ppd->num_profiles;
887 ppd->num_profiles ++;
888
889 memset(profile, 0, sizeof(ppd_profile_t));
def978d5 890 strlcpy(profile->resolution, name, sizeof(profile->resolution));
891 strlcpy(profile->media_type, text, sizeof(profile->media_type));
94ffdf17 892
d220c7b8 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);
b87e43e9 904 }
a501ad17 905 else if (!strcmp(keyword, "cupsFilter"))
c493465a 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
0819478b 912 if (filter == NULL)
913 {
03f61bf3 914 cg->ppd_status = PPD_ALLOC_ERROR;
79f448f9 915
5a617005 916 goto error;
0819478b 917 }
918
c493465a 919 ppd->filters = filter;
920 filter += ppd->num_filters;
921 ppd->num_filters ++;
922
923 /*
5772e663 924 * Retain a copy of the filter string...
c493465a 925 */
926
5772e663 927 *filter = _cupsStrRetain(string);
c493465a 928 }
a501ad17 929 else if (!strcmp(keyword, "Throughput"))
7ebf3a09 930 ppd->throughput = atoi(string);
a501ad17 931 else if (!strcmp(keyword, "Font"))
b03923b8 932 {
933 /*
934 * Add this font to the list of available fonts...
935 */
936
937 if (ppd->num_fonts == 0)
0819478b 938 tempfonts = (char **)malloc(sizeof(char *));
b03923b8 939 else
0819478b 940 tempfonts = (char **)realloc(ppd->fonts,
941 sizeof(char *) * (ppd->num_fonts + 1));
b03923b8 942
0819478b 943 if (tempfonts == NULL)
b03923b8 944 {
03f61bf3 945 cg->ppd_status = PPD_ALLOC_ERROR;
79f448f9 946
5a617005 947 goto error;
b03923b8 948 }
c6fab96f 949
0819478b 950 ppd->fonts = tempfonts;
80ad038a 951 ppd->fonts[ppd->num_fonts] = _cupsStrAlloc(name);
b03923b8 952 ppd->num_fonts ++;
b03923b8 953 }
ff6a82d3 954 else if (!strncmp(keyword, "ParamCustom", 11))
6fdf969a 955 {
ff6a82d3 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 */
fd8e0b1e 962
ff6a82d3 963
964 /*
965 * Get the custom option and parameter...
966 */
967
968 if ((coption = ppd_get_coption(ppd, keyword + 11)) == NULL)
d1f2b9fe 969 {
ff6a82d3 970 cg->ppd_status = PPD_ALLOC_ERROR;
d1f2b9fe 971
ff6a82d3 972 goto error;
973 }
d1f2b9fe 974
ff6a82d3 975 if ((cparam = ppd_get_cparam(coption, name, text)) == NULL)
976 {
977 cg->ppd_status = PPD_ALLOC_ERROR;
d1f2b9fe 978
ff6a82d3 979 goto error;
980 }
981
982 /*
983 * Get the parameter data...
984 */
985
73c757e3 986 if (!string ||
987 sscanf(string, "%d%32s%64s%64s", &corder, ctype, cminimum,
ff6a82d3 988 cmaximum) != 4)
989 {
990 cg->ppd_status = PPD_BAD_CUSTOM_PARAM;
991
992 goto error;
993 }
994
995 cparam->order = corder;
996
997 if (!strcmp(ctype, "curve"))
998 {
999 cparam->type = PPD_CUSTOM_CURVE;
d220c7b8 1000 cparam->minimum.custom_curve = (float)_cupsStrScand(cminimum, NULL, loc);
1001 cparam->maximum.custom_curve = (float)_cupsStrScand(cmaximum, NULL, loc);
ff6a82d3 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;
d220c7b8 1012 cparam->minimum.custom_invcurve = (float)_cupsStrScand(cminimum, NULL, loc);
1013 cparam->maximum.custom_invcurve = (float)_cupsStrScand(cmaximum, NULL, loc);
ff6a82d3 1014 }
1015 else if (!strcmp(ctype, "passcode"))
1016 {
1017 cparam->type = PPD_CUSTOM_PASSCODE;
51890df6 1018 cparam->minimum.custom_passcode = atoi(cminimum);
1019 cparam->maximum.custom_passcode = atoi(cmaximum);
ff6a82d3 1020 }
1021 else if (!strcmp(ctype, "password"))
1022 {
1023 cparam->type = PPD_CUSTOM_PASSWORD;
51890df6 1024 cparam->minimum.custom_password = atoi(cminimum);
1025 cparam->maximum.custom_password = atoi(cmaximum);
ff6a82d3 1026 }
1027 else if (!strcmp(ctype, "points"))
1028 {
1029 cparam->type = PPD_CUSTOM_POINTS;
d220c7b8 1030 cparam->minimum.custom_points = (float)_cupsStrScand(cminimum, NULL, loc);
1031 cparam->maximum.custom_points = (float)_cupsStrScand(cmaximum, NULL, loc);
ff6a82d3 1032 }
1033 else if (!strcmp(ctype, "real"))
1034 {
1035 cparam->type = PPD_CUSTOM_REAL;
d220c7b8 1036 cparam->minimum.custom_real = (float)_cupsStrScand(cminimum, NULL, loc);
1037 cparam->maximum.custom_real = (float)_cupsStrScand(cmaximum, NULL, loc);
ff6a82d3 1038 }
1039 else if (!strcmp(ctype, "string"))
1040 {
1041 cparam->type = PPD_CUSTOM_STRING;
51890df6 1042 cparam->minimum.custom_string = atoi(cminimum);
1043 cparam->maximum.custom_string = atoi(cmaximum);
ff6a82d3 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 */
d1f2b9fe 1055
ff6a82d3 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"))
d1f2b9fe 1064 {
ff6a82d3 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"))
94ffdf17 1071 {
1072 for (i = 0, sptr = string; i < 4; i ++)
d220c7b8 1073 ppd->custom_margins[i] = (float)_cupsStrScand(sptr, &sptr, loc);
94ffdf17 1074 }
a0d73671 1075 else if (!strncmp(keyword, "Custom", 6) && !strcmp(name, "True") && !option)
ff6a82d3 1076 {
5412d0bc 1077 ppd_option_t *custom_option; /* Custom option */
1078
6ee6a397 1079 DEBUG_puts("2_ppdOpen: Processing Custom option...");
fd8e0b1e 1080
ff6a82d3 1081 /*
1082 * Get the option and custom option...
1083 */
7a1c86c5 1084
f64da201 1085 if (!ppd_get_coption(ppd, keyword + 6))
6fdf969a 1086 {
ff6a82d3 1087 cg->ppd_status = PPD_ALLOC_ERROR;
79f448f9 1088
5a617005 1089 goto error;
6fdf969a 1090 }
1091
c6fab96f 1092 if (option && !_cups_strcasecmp(option->keyword, keyword + 6))
5412d0bc 1093 custom_option = option;
1094 else
1095 custom_option = ppdFindOption(ppd, keyword + 6);
ff6a82d3 1096
5412d0bc 1097 if (custom_option)
6fdf969a 1098 {
5412d0bc 1099 /*
1100 * Add the "custom" option...
1101 */
7a1c86c5 1102
48c9a702 1103 if ((choice = ppdFindChoice(custom_option, "Custom")) == NULL)
1104 if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL)
1105 {
6ee6a397 1106 DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
79f448f9 1107
48c9a702 1108 cg->ppd_status = PPD_ALLOC_ERROR;
5412d0bc 1109
48c9a702 1110 goto error;
1111 }
6fdf969a 1112
5412d0bc 1113 strlcpy(choice->text, text[0] ? text : _("Custom"),
1114 sizeof(choice->text));
ff6a82d3 1115
5412d0bc 1116 choice->code = _cupsStrAlloc(string);
c53265fe 1117
1118 if (custom_option->section == PPD_ORDER_JCL)
1119 ppd_decode(choice->code);
5412d0bc 1120 }
ff6a82d3 1121
1122 /*
1123 * Now process custom page sizes specially...
1124 */
1125
1126 if (!strcmp(keyword, "CustomPageSize"))
1127 {
ff6a82d3 1128 /*
1129 * Add a "Custom" page size entry...
1130 */
1131
5412d0bc 1132 ppd->variable_sizes = 1;
a0d73671 1133
5412d0bc 1134 ppd_add_size(ppd, "Custom");
a0d73671 1135
c6fab96f 1136 if (option && !_cups_strcasecmp(option->keyword, "PageRegion"))
5412d0bc 1137 custom_option = option;
1138 else
1139 custom_option = ppdFindOption(ppd, "PageRegion");
d88e67b1 1140
5412d0bc 1141 if (custom_option)
1142 {
48c9a702 1143 if ((choice = ppdFindChoice(custom_option, "Custom")) == NULL)
1144 if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL)
1145 {
6ee6a397 1146 DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
5412d0bc 1147
48c9a702 1148 cg->ppd_status = PPD_ALLOC_ERROR;
a0d73671 1149
48c9a702 1150 goto error;
1151 }
a0d73671 1152
5412d0bc 1153 strlcpy(choice->text, text[0] ? text : _("Custom"),
1154 sizeof(choice->text));
a0d73671 1155 }
ff6a82d3 1156 }
6fdf969a 1157 }
a501ad17 1158 else if (!strcmp(keyword, "LandscapeOrientation"))
2b85e375 1159 {
a501ad17 1160 if (!strcmp(string, "Minus90"))
2b85e375 1161 ppd->landscape = -90;
a501ad17 1162 else if (!strcmp(string, "Plus90"))
2b85e375 1163 ppd->landscape = 90;
1164 }
c97b7208 1165 else if (!strcmp(keyword, "Emulators") && string)
8c1333e2 1166 {
d23a857a 1167 for (count = 1, sptr = string; sptr != NULL;)
8c1333e2 1168 if ((sptr = strchr(sptr, ' ')) != NULL)
1169 {
1170 count ++;
1171 while (*sptr == ' ')
1172 sptr ++;
e8fda7b9 1173 }
8c1333e2 1174
1175 ppd->num_emulations = count;
09751e0f 1176 if ((ppd->emulations = calloc(count, sizeof(ppd_emul_t))) == NULL)
1177 {
1178 cg->ppd_status = PPD_ALLOC_ERROR;
1179
1180 goto error;
1181 }
8c1333e2 1182
d23a857a 1183 for (i = 0, sptr = string; i < count; i ++)
8c1333e2 1184 {
d2e58bfa 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;
8c1333e2 1190
1191 *nameptr = '\0';
1192
1193 while (*sptr == ' ')
1194 sptr ++;
1195 }
1196 }
a501ad17 1197 else if (!strncmp(keyword, "StartEmulator_", 14))
8c1333e2 1198 {
1199 ppd_decode(string);
1200
1201 for (i = 0; i < ppd->num_emulations; i ++)
a501ad17 1202 if (!strcmp(keyword + 14, ppd->emulations[i].name))
8c1333e2 1203 {
1204 ppd->emulations[i].start = string;
1205 string = NULL;
1206 }
1207 }
a501ad17 1208 else if (!strncmp(keyword, "StopEmulator_", 13))
8c1333e2 1209 {
1210 ppd_decode(string);
1211
1212 for (i = 0; i < ppd->num_emulations; i ++)
a501ad17 1213 if (!strcmp(keyword + 13, ppd->emulations[i].name))
8c1333e2 1214 {
1215 ppd->emulations[i].stop = string;
1216 string = NULL;
1217 }
1218 }
a501ad17 1219 else if (!strcmp(keyword, "JobPatchFile"))
8c1333e2 1220 {
b45cde5d 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
de187cbc 1241 if (!name[0] && cg->ppd_conform == PPD_CONFORM_STRICT)
b45cde5d 1242 {
1243 /*
1244 * Found "*JobPatchFile: string"...
1245 */
1246
1247 cg->ppd_status = PPD_MISSING_OPTION_KEYWORD;
1248
1249 goto error;
1250 }
1251
8c1333e2 1252 if (ppd->patches == NULL)
a56d8322 1253 ppd->patches = strdup(string);
8c1333e2 1254 else
1255 {
0819478b 1256 temp = realloc(ppd->patches, strlen(ppd->patches) +
1257 strlen(string) + 1);
1258 if (temp == NULL)
1259 {
03f61bf3 1260 cg->ppd_status = PPD_ALLOC_ERROR;
79f448f9 1261
5a617005 1262 goto error;
0819478b 1263 }
1264
1265 ppd->patches = temp;
8c1333e2 1266
af882006 1267 memcpy(ppd->patches + strlen(ppd->patches), string, strlen(string) + 1);
8c1333e2 1268 }
1269 }
a501ad17 1270 else if (!strcmp(keyword, "OpenUI"))
2b85e375 1271 {
b3291c5a 1272 /*
1273 * Don't allow nesting of options...
1274 */
1275
03f61bf3 1276 if (option && cg->ppd_conform == PPD_CONFORM_STRICT)
b3291c5a 1277 {
03f61bf3 1278 cg->ppd_status = PPD_NESTED_OPEN_UI;
b3291c5a 1279
5a617005 1280 goto error;
b3291c5a 1281 }
1282
2b85e375 1283 /*
1284 * Add an option record to the current sub-group, group, or file...
1285 */
1286
6ee6a397 1287 DEBUG_printf(("2_ppdOpen: name=\"%s\" (%d)", name, (int)strlen(name)));
a8af2765 1288
2b85e375 1289 if (name[0] == '*')
2625096f 1290 _cups_strcpy(name, name + 1); /* Eliminate leading asterisk */
2b85e375 1291
e00a8345 1292 for (i = (int)strlen(name) - 1; i > 0 && _cups_isspace(name[i]); i --)
753453e4 1293 name[i] = '\0'; /* Eliminate trailing spaces */
1294
6ee6a397 1295 DEBUG_printf(("2_ppdOpen: OpenUI of %s in group %s...", name,
753453e4 1296 group ? group->text : "(null)"));
c21064d2 1297
652e598f 1298 if (subgroup != NULL)
1299 option = ppd_get_option(subgroup, name);
1300 else if (group == NULL)
1301 {
ed04873a 1302 if ((group = ppd_get_group(ppd, "General", _("General"), cg,
1303 encoding)) == NULL)
5a617005 1304 goto error;
caab0820 1305
6ee6a397 1306 DEBUG_printf(("2_ppdOpen: Adding to group %s...", group->text));
652e598f 1307 option = ppd_get_option(group, name);
1308 group = NULL;
1309 }
1310 else
1311 option = ppd_get_option(group, name);
2b85e375 1312
652e598f 1313 if (option == NULL)
1314 {
03f61bf3 1315 cg->ppd_status = PPD_ALLOC_ERROR;
79f448f9 1316
5a617005 1317 goto error;
652e598f 1318 }
2b85e375 1319
652e598f 1320 /*
1321 * Now fill in the initial information for the option...
1322 */
2b85e375 1323
a501ad17 1324 if (string && !strcmp(string, "PickMany"))
652e598f 1325 option->ui = PPD_UI_PICKMANY;
a501ad17 1326 else if (string && !strcmp(string, "Boolean"))
652e598f 1327 option->ui = PPD_UI_BOOLEAN;
a501ad17 1328 else if (string && !strcmp(string, "PickOne"))
652e598f 1329 option->ui = PPD_UI_PICKONE;
03f61bf3 1330 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
b3291c5a 1331 {
03f61bf3 1332 cg->ppd_status = PPD_BAD_OPEN_UI;
b3291c5a 1333
5a617005 1334 goto error;
b3291c5a 1335 }
9e678e84 1336 else
1337 option->ui = PPD_UI_PICKONE;
652e598f 1338
a2b8b819 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 {
6ee6a397 1344 DEBUG_printf(("2_ppdOpen: Setting Default%s to %s via attribute...",
fd8e0b1e 1345 option->keyword, ppd->attrs[j]->value));
a2b8b819 1346 strlcpy(option->defchoice, ppd->attrs[j]->value,
1347 sizeof(option->defchoice));
1348 break;
1349 }
1350
652e598f 1351 if (text[0])
8c4a3f1a 1352 cupsCharsetToUTF8((cups_utf8_t *)option->text, text,
1353 sizeof(option->text), encoding);
652e598f 1354 else
1355 {
a501ad17 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));
652e598f 1366 else
def978d5 1367 strlcpy(option->text, name, sizeof(option->text));
caab0820 1368 }
652e598f 1369
1370 option->section = PPD_ORDER_ANY;
2e8cd988 1371
80ad038a 1372 _cupsStrFree(string);
2e8cd988 1373 string = NULL;
5412d0bc 1374
1375 /*
1376 * Add a custom option choice if we have already seen a CustomFoo
1377 * attribute...
1378 */
1379
c6fab96f 1380 if (!_cups_strcasecmp(name, "PageRegion"))
af882006 1381 strlcpy(custom_name, "CustomPageSize", sizeof(custom_name));
5412d0bc 1382 else
1383 snprintf(custom_name, sizeof(custom_name), "Custom%s", name);
1384
1385 if ((custom_attr = ppdFindAttr(ppd, custom_name, "True")) != NULL)
1386 {
48c9a702 1387 if ((choice = ppdFindChoice(option, "Custom")) == NULL)
1388 if ((choice = ppd_add_choice(option, "Custom")) == NULL)
1389 {
6ee6a397 1390 DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
5412d0bc 1391
48c9a702 1392 cg->ppd_status = PPD_ALLOC_ERROR;
5412d0bc 1393
48c9a702 1394 goto error;
1395 }
5412d0bc 1396
1397 strlcpy(choice->text,
1398 custom_attr->text[0] ? custom_attr->text : _("Custom"),
1399 sizeof(choice->text));
0494d5a1 1400 choice->code = _cupsStrRetain(custom_attr->value);
5412d0bc 1401 }
2b85e375 1402 }
a501ad17 1403 else if (!strcmp(keyword, "JCLOpenUI"))
2b85e375 1404 {
b3291c5a 1405 /*
1406 * Don't allow nesting of options...
1407 */
1408
03f61bf3 1409 if (option && cg->ppd_conform == PPD_CONFORM_STRICT)
b3291c5a 1410 {
03f61bf3 1411 cg->ppd_status = PPD_NESTED_OPEN_UI;
b3291c5a 1412
5a617005 1413 goto error;
b3291c5a 1414 }
1415
58ec2a95 1416 /*
1417 * Find the JCL group, and add if needed...
1418 */
1419
ed04873a 1420 group = ppd_get_group(ppd, "JCL", _("JCL"), cg, encoding);
58ec2a95 1421
6fdf969a 1422 if (group == NULL)
5a617005 1423 goto error;
58ec2a95 1424
2b85e375 1425 /*
1426 * Add an option record to the current JCLs...
1427 */
1428
1429 if (name[0] == '*')
2625096f 1430 _cups_strcpy(name, name + 1);
2b85e375 1431
6fdf969a 1432 option = ppd_get_option(group, name);
2b85e375 1433
1434 if (option == NULL)
1435 {
03f61bf3 1436 cg->ppd_status = PPD_ALLOC_ERROR;
79f448f9 1437
5a617005 1438 goto error;
e8fda7b9 1439 }
2b85e375 1440
2b85e375 1441 /*
1442 * Now fill in the initial information for the option...
1443 */
1444
a501ad17 1445 if (string && !strcmp(string, "PickMany"))
2b85e375 1446 option->ui = PPD_UI_PICKMANY;
a501ad17 1447 else if (string && !strcmp(string, "Boolean"))
2b85e375 1448 option->ui = PPD_UI_BOOLEAN;
a501ad17 1449 else if (string && !strcmp(string, "PickOne"))
2b85e375 1450 option->ui = PPD_UI_PICKONE;
b3291c5a 1451 else
1452 {
03f61bf3 1453 cg->ppd_status = PPD_BAD_OPEN_UI;
b3291c5a 1454
5a617005 1455 goto error;
b3291c5a 1456 }
2b85e375 1457
a2b8b819 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 {
6ee6a397 1463 DEBUG_printf(("2_ppdOpen: Setting Default%s to %s via attribute...",
fd8e0b1e 1464 option->keyword, ppd->attrs[j]->value));
a2b8b819 1465 strlcpy(option->defchoice, ppd->attrs[j]->value,
1466 sizeof(option->defchoice));
1467 break;
1468 }
1469
ed04873a 1470 if (text[0])
8c4a3f1a 1471 cupsCharsetToUTF8((cups_utf8_t *)option->text, text,
1472 sizeof(option->text), encoding);
ed04873a 1473 else
1474 strlcpy(option->text, name, sizeof(option->text));
2b85e375 1475
1476 option->section = PPD_ORDER_JCL;
58ec2a95 1477 group = NULL;
2e8cd988 1478
80ad038a 1479 _cupsStrFree(string);
2e8cd988 1480 string = NULL;
5412d0bc 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 {
6ee6a397 1493 DEBUG_puts("1_ppdOpen: Unable to add Custom choice!");
5412d0bc 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));
0494d5a1 1503 choice->code = _cupsStrRetain(custom_attr->value);
5412d0bc 1504 }
2b85e375 1505 }
a501ad17 1506 else if (!strcmp(keyword, "CloseUI") || !strcmp(keyword, "JCLCloseUI"))
2e8cd988 1507 {
2b85e375 1508 option = NULL;
2e8cd988 1509
80ad038a 1510 _cupsStrFree(string);
2e8cd988 1511 string = NULL;
1512 }
a501ad17 1513 else if (!strcmp(keyword, "OpenGroup"))
2b85e375 1514 {
1515 /*
1516 * Open a new group...
1517 */
1518
1519 if (group != NULL)
1520 {
03f61bf3 1521 cg->ppd_status = PPD_NESTED_OPEN_GROUP;
79f448f9 1522
5a617005 1523 goto error;
e8fda7b9 1524 }
2b85e375 1525
b3291c5a 1526 if (!string)
1527 {
03f61bf3 1528 cg->ppd_status = PPD_BAD_OPEN_GROUP;
b3291c5a 1529
5a617005 1530 goto error;
b3291c5a 1531 }
1532
83575f2d 1533 /*
1534 * Separate the group name from the text (name/text)...
1535 */
2b85e375 1536
83575f2d 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);
83575f2d 1547
1548 /*
1549 * Find/add the group...
1550 */
1551
ed04873a 1552 group = ppd_get_group(ppd, string, sptr, cg, encoding);
2e8cd988 1553
6f83172d 1554 if (group == NULL)
1555 goto error;
1556
80ad038a 1557 _cupsStrFree(string);
2e8cd988 1558 string = NULL;
2b85e375 1559 }
a501ad17 1560 else if (!strcmp(keyword, "CloseGroup"))
2e8cd988 1561 {
2b85e375 1562 group = NULL;
2e8cd988 1563
80ad038a 1564 _cupsStrFree(string);
2e8cd988 1565 string = NULL;
1566 }
be140c52 1567 else if (!strcmp(keyword, "OrderDependency"))
2b85e375 1568 {
d220c7b8 1569 order = (float)_cupsStrScand(string, &sptr, loc);
94ffdf17 1570
1571 if (!sptr || sscanf(sptr, "%40s%40s", name, keyword) != 2)
2b85e375 1572 {
03f61bf3 1573 cg->ppd_status = PPD_BAD_ORDER_DEPENDENCY;
79f448f9 1574
5a617005 1575 goto error;
e8fda7b9 1576 }
2b85e375 1577
1578 if (keyword[0] == '*')
2625096f 1579 _cups_strcpy(keyword, keyword + 1);
2b85e375 1580
a501ad17 1581 if (!strcmp(name, "ExitServer"))
2b85e375 1582 section = PPD_ORDER_EXIT;
a501ad17 1583 else if (!strcmp(name, "Prolog"))
2b85e375 1584 section = PPD_ORDER_PROLOG;
a501ad17 1585 else if (!strcmp(name, "DocumentSetup"))
2b85e375 1586 section = PPD_ORDER_DOCUMENT;
a501ad17 1587 else if (!strcmp(name, "PageSetup"))
2b85e375 1588 section = PPD_ORDER_PAGE;
a501ad17 1589 else if (!strcmp(name, "JCLSetup"))
2b85e375 1590 section = PPD_ORDER_JCL;
1591 else
1592 section = PPD_ORDER_ANY;
1593
1594 if (option == NULL)
1595 {
08379093 1596 ppd_group_t *gtemp;
7d75b814 1597
1598
2b85e375 1599 /*
1600 * Only valid for Non-UI options...
1601 */
1602
08379093 1603 for (i = ppd->num_groups, gtemp = ppd->groups; i > 0; i --, gtemp ++)
1604 if (gtemp->text[0] == '\0')
2b85e375 1605 break;
58ec2a95 1606
1607 if (i > 0)
08379093 1608 for (i = 0; i < gtemp->num_options; i ++)
a501ad17 1609 if (!strcmp(keyword, gtemp->options[i].keyword))
58ec2a95 1610 {
08379093 1611 gtemp->options[i].section = section;
1612 gtemp->options[i].order = order;
58ec2a95 1613 break;
1614 }
2b85e375 1615 }
1616 else
1617 {
1618 option->section = section;
1619 option->order = order;
e8fda7b9 1620 }
2e8cd988 1621
80ad038a 1622 _cupsStrFree(string);
2e8cd988 1623 string = NULL;
2b85e375 1624 }
a501ad17 1625 else if (!strncmp(keyword, "Default", 7))
2b85e375 1626 {
6c73d44f 1627 if (string == NULL)
1628 continue;
1629
af50faa7 1630 /*
1631 * Drop UI text, if any, from value...
1632 */
1633
d23a857a 1634 if (strchr(string, '/') != NULL)
1635 *strchr(string, '/') = '\0';
58ec2a95 1636
af50faa7 1637 /*
1638 * Assign the default value as appropriate...
1639 */
43cd52be 1640
a501ad17 1641 if (!strcmp(keyword, "DefaultColorSpace"))
af50faa7 1642 {
1643 /*
1644 * Set default colorspace...
1645 */
43cd52be 1646
a501ad17 1647 if (!strcmp(string, "CMY"))
af50faa7 1648 ppd->colorspace = PPD_CS_CMY;
a501ad17 1649 else if (!strcmp(string, "CMYK"))
af50faa7 1650 ppd->colorspace = PPD_CS_CMYK;
a501ad17 1651 else if (!strcmp(string, "RGB"))
af50faa7 1652 ppd->colorspace = PPD_CS_RGB;
a501ad17 1653 else if (!strcmp(string, "RGBK"))
af50faa7 1654 ppd->colorspace = PPD_CS_RGBK;
a501ad17 1655 else if (!strcmp(string, "N"))
af50faa7 1656 ppd->colorspace = PPD_CS_N;
1657 else
1658 ppd->colorspace = PPD_CS_GRAY;
2b85e375 1659 }
a501ad17 1660 else if (option && !strcmp(keyword + 7, option->keyword))
af50faa7 1661 {
1662 /*
1663 * Set the default as part of the current option...
1664 */
1665
6ee6a397 1666 DEBUG_printf(("2_ppdOpen: Setting %s to %s...", keyword, string));
fd8e0b1e 1667
def978d5 1668 strlcpy(option->defchoice, string, sizeof(option->defchoice));
fd8e0b1e 1669
6ee6a397 1670 DEBUG_printf(("2_ppdOpen: %s is now %s...", keyword, option->defchoice));
af50faa7 1671 }
43cd52be 1672 else
1673 {
1674 /*
af50faa7 1675 * Lookup option and set if it has been defined...
43cd52be 1676 */
1677
af50faa7 1678 ppd_option_t *toption; /* Temporary option */
1679
43cd52be 1680
af50faa7 1681 if ((toption = ppdFindOption(ppd, keyword + 7)) != NULL)
fd8e0b1e 1682 {
6ee6a397 1683 DEBUG_printf(("2_ppdOpen: Setting %s to %s...", keyword, string));
af50faa7 1684 strlcpy(toption->defchoice, string, sizeof(toption->defchoice));
fd8e0b1e 1685 }
43cd52be 1686 }
2b85e375 1687 }
a501ad17 1688 else if (!strcmp(keyword, "UIConstraints") ||
1689 !strcmp(keyword, "NonUIConstraints"))
2b85e375 1690 {
73c757e3 1691 if (!string)
1692 {
1693 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1694 goto error;
1695 }
1696
2b85e375 1697 if (ppd->num_consts == 0)
a0d73671 1698 constraint = calloc(2, sizeof(ppd_const_t));
2b85e375 1699 else
1700 constraint = realloc(ppd->consts,
a0d73671 1701 (ppd->num_consts + 2) * sizeof(ppd_const_t));
2b85e375 1702
1703 if (constraint == NULL)
1704 {
03f61bf3 1705 cg->ppd_status = PPD_ALLOC_ERROR;
79f448f9 1706
5a617005 1707 goto error;
e8fda7b9 1708 }
2b85e375 1709
1710 ppd->consts = constraint;
1711 constraint += ppd->num_consts;
1712 ppd->num_consts ++;
1713
fafbba4f 1714 switch (sscanf(string, "%40s%40s%40s%40s", constraint->option1,
8c1333e2 1715 constraint->choice1, constraint->option2,
1716 constraint->choice2))
2b85e375 1717 {
1718 case 0 : /* Error */
1719 case 1 : /* Error */
03f61bf3 1720 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
5a617005 1721 goto error;
2b85e375 1722
8c1333e2 1723 case 2 : /* Two options... */
3f43ed60 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
d2e58bfa 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
2b85e375 1741 if (constraint->option1[0] == '*')
2625096f 1742 _cups_strcpy(constraint->option1, constraint->option1 + 1);
3f43ed60 1743 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1744 {
1745 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1746 goto error;
1747 }
8c1333e2 1748
1749 if (constraint->choice1[0] == '*')
2625096f 1750 _cups_strcpy(constraint->option2, constraint->choice1 + 1);
3f43ed60 1751 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1752 {
1753 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1754 goto error;
1755 }
2b85e375 1756
8c1333e2 1757 constraint->choice1[0] = '\0';
1758 constraint->choice2[0] = '\0';
2b85e375 1759 break;
c6fab96f 1760
8c1333e2 1761 case 3 : /* Two options, one choice... */
3f43ed60 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
d2e58bfa 1775 /*
2625096f 1776 * The following _cups_strcpy's are safe, as optionN and
d2e58bfa 1777 * choiceN are all the same size (size defined by PPD spec...)
1778 */
1779
2b85e375 1780 if (constraint->option1[0] == '*')
2625096f 1781 _cups_strcpy(constraint->option1, constraint->option1 + 1);
3f43ed60 1782 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1783 {
1784 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1785 goto error;
1786 }
8c1333e2 1787
1788 if (constraint->choice1[0] == '*')
2b85e375 1789 {
3f43ed60 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
2625096f 1797 _cups_strcpy(constraint->choice2, constraint->option2);
1798 _cups_strcpy(constraint->option2, constraint->choice1 + 1);
8c1333e2 1799 constraint->choice1[0] = '\0';
2b85e375 1800 }
9cbf7321 1801 else
1802 {
1803 if (constraint->option2[0] == '*')
2625096f 1804 _cups_strcpy(constraint->option2, constraint->option2 + 1);
3f43ed60 1805 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1806 {
1807 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1808 goto error;
1809 }
2b85e375 1810
9cbf7321 1811 constraint->choice2[0] = '\0';
1812 }
2b85e375 1813 break;
c6fab96f 1814
8c1333e2 1815 case 4 : /* Two options, two choices... */
3f43ed60 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
8c1333e2 1830 if (constraint->option1[0] == '*')
2625096f 1831 _cups_strcpy(constraint->option1, constraint->option1 + 1);
3f43ed60 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 }
2b85e375 1844
8c1333e2 1845 if (constraint->option2[0] == '*')
2625096f 1846 _cups_strcpy(constraint->option2, constraint->option2 + 1);
3f43ed60 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 }
2b85e375 1859 break;
e8fda7b9 1860 }
2e8cd988 1861
738de08b 1862 /*
1863 * Don't add this one as an attribute...
1864 */
1865
80ad038a 1866 _cupsStrFree(string);
2e8cd988 1867 string = NULL;
2b85e375 1868 }
a501ad17 1869 else if (!strcmp(keyword, "PaperDimension"))
2b85e375 1870 {
753453e4 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
03f61bf3 1880 cg->ppd_status = PPD_ALLOC_ERROR;
79f448f9 1881
5a617005 1882 goto error;
753453e4 1883 }
1884
d220c7b8 1885 size->width = (float)_cupsStrScand(string, &sptr, loc);
1886 size->length = (float)_cupsStrScand(sptr, NULL, loc);
2e8cd988 1887
80ad038a 1888 _cupsStrFree(string);
2e8cd988 1889 string = NULL;
2b85e375 1890 }
a501ad17 1891 else if (!strcmp(keyword, "ImageableArea"))
2b85e375 1892 {
753453e4 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
03f61bf3 1902 cg->ppd_status = PPD_ALLOC_ERROR;
79f448f9 1903
5a617005 1904 goto error;
753453e4 1905 }
1906
d220c7b8 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);
2e8cd988 1911
80ad038a 1912 _cupsStrFree(string);
2e8cd988 1913 string = NULL;
2b85e375 1914 }
1915 else if (option != NULL &&
1916 (mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) ==
a319615f 1917 (PPD_KEYWORD | PPD_OPTION | PPD_STRING) &&
a501ad17 1918 !strcmp(keyword, option->keyword))
2b85e375 1919 {
6ee6a397 1920 DEBUG_printf(("2_ppdOpen: group=%p, subgroup=%p", group, subgroup));
7d75b814 1921
a501ad17 1922 if (!strcmp(keyword, "PageSize"))
2b85e375 1923 {
1924 /*
1925 * Add a page size...
1926 */
1927
753453e4 1928 if (ppdPageSize(ppd, name) == NULL)
1929 ppd_add_size(ppd, name);
e8fda7b9 1930 }
2b85e375 1931
1932 /*
1fdc6cd5 1933 * Add the option choice...
1934 */
1935
18e6d242 1936 if ((choice = ppd_add_choice(option, name)) == NULL)
1937 {
1938 cg->ppd_status = PPD_ALLOC_ERROR;
1939
1940 goto error;
1941 }
1fdc6cd5 1942
ed04873a 1943 if (text[0])
8c4a3f1a 1944 cupsCharsetToUTF8((cups_utf8_t *)choice->text, text,
1945 sizeof(choice->text), encoding);
a501ad17 1946 else if (!strcmp(name, "True"))
af882006 1947 strlcpy(choice->text, _("Yes"), sizeof(choice->text));
a501ad17 1948 else if (!strcmp(name, "False"))
af882006 1949 strlcpy(choice->text, _("No"), sizeof(choice->text));
1fdc6cd5 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;
ff40b65e 1957 string = NULL; /* Don't add as an attribute below */
1fdc6cd5 1958 }
da5bb70a 1959
2e8cd988 1960 /*
1961 * Add remaining lines with keywords and string values as attributes...
1962 */
2b85e375 1963
2e8cd988 1964 if (string &&
1965 (mask & (PPD_KEYWORD | PPD_STRING)) == (PPD_KEYWORD | PPD_STRING))
1966 ppd_add_attr(ppd, keyword, name, text, string);
1967 else
80ad038a 1968 _cupsStrFree(string);
e8fda7b9 1969 }
2b85e375 1970
f91e4743 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
ac682d83 1981 ppd_free(line.buffer);
80ad038a 1982
7a1c86c5 1983 /*
1984 * Reset language preferences...
1985 */
1986
2b85e375 1987#ifdef DEBUG
a8af2765 1988 if (!cupsFileEOF(fp))
6ee6a397 1989 DEBUG_printf(("1_ppdOpen: Premature EOF at %lu...\n",
7e8f437e 1990 (unsigned long)cupsFileTell(fp)));
2b85e375 1991#endif /* DEBUG */
1992
03f61bf3 1993 if (cg->ppd_status != PPD_OK)
43cd52be 1994 {
1995 /*
1996 * Had an error reading the PPD file, cannot continue!
1997 */
1998
1999 ppdClose(ppd);
2000
2001 return (NULL);
2002 }
2003
5772e663 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
58ec2a95 2015 /*
ff6a82d3 2016 * Create the sorted options array and set the option back-pointer for
2017 * each choice and custom option...
58ec2a95 2018 */
2019
6482819f 2020 ppd->options = cupsArrayNew2((cups_array_func_t)ppd_compare_options, NULL,
2021 (cups_ahash_func_t)ppd_hash_option,
2022 PPD_HASHSIZE);
caab0820 2023
58ec2a95 2024 for (i = ppd->num_groups, group = ppd->groups;
2025 i > 0;
2026 i --, group ++)
2027 {
2028 for (j = group->num_options, option = group->options;
2029 j > 0;
2030 j --, option ++)
caab0820 2031 {
ff6a82d3 2032 ppd_coption_t *coption; /* Custom option */
caab0820 2033
58ec2a95 2034
ff6a82d3 2035 cupsArrayAdd(ppd->options, option);
58ec2a95 2036
ff6a82d3 2037 for (k = 0; k < option->num_choices; k ++)
2038 option->choices[k].option = option;
1fdc6cd5 2039
ff6a82d3 2040 if ((coption = ppdFindCustomOption(ppd, option->keyword)) != NULL)
2041 coption->option = option;
2042 }
2043 }
1fdc6cd5 2044
6482819f 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
79f448f9 2051 /*
2052 * Return the PPD file structure...
2053 */
2054
2b85e375 2055 return (ppd);
5a617005 2056
2057 /*
2058 * Common exit point for errors to save code size...
2059 */
2060
2061 error:
2062
80ad038a 2063 _cupsStrFree(string);
ac682d83 2064 ppd_free(line.buffer);
5a617005 2065
2066 ppdClose(ppd);
2067
5a617005 2068 return (NULL);
2b85e375 2069}
2070
2071
6ee6a397 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 *
c45401bb 2109 * @since CUPS 1.2/OS X 10.5@
6ee6a397 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
2b85e375 2119/*
2120 * 'ppdOpenFd()' - Read a PPD file into memory.
2121 */
2122
8f6753d3 2123ppd_file_t * /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
1fdc6cd5 2124ppdOpenFd(int fd) /* I - File to read from */
2b85e375 2125{
ff6a82d3 2126 cups_file_t *fp; /* CUPS file pointer */
03f61bf3 2127 ppd_file_t *ppd; /* PPD file record */
2625096f 2128 _cups_globals_t *cg = _cupsGlobals();
03f61bf3 2129 /* Global data */
2b85e375 2130
2131
79f448f9 2132 /*
031278ca 2133 * Set the line number to 0...
79f448f9 2134 */
2135
03f61bf3 2136 cg->ppd_line = 0;
79f448f9 2137
2b85e375 2138 /*
2139 * Range check input...
2140 */
2141
2142 if (fd < 0)
79f448f9 2143 {
03f61bf3 2144 cg->ppd_status = PPD_NULL_FILE;
79f448f9 2145
2b85e375 2146 return (NULL);
79f448f9 2147 }
2b85e375 2148
2149 /*
2150 * Try to open the file and parse it...
2151 */
2152
ff6a82d3 2153 if ((fp = cupsFileOpenFd(fd, "r")) != NULL)
2b85e375 2154 {
ff6a82d3 2155 ppd = ppdOpen2(fp);
2b85e375 2156
ff6a82d3 2157 cupsFileClose(fp);
2b85e375 2158 }
2159 else
79f448f9 2160 {
03f61bf3 2161 cg->ppd_status = PPD_FILE_OPEN_ERROR;
ff6a82d3 2162 ppd = NULL;
79f448f9 2163 }
2b85e375 2164
2165 return (ppd);
2166}
2167
2168
2169/*
6ee6a397 2170 * '_ppdOpenFile()' - Read a PPD file into memory.
2b85e375 2171 */
2172
8f6753d3 2173ppd_file_t * /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
6ee6a397 2174_ppdOpenFile(const char *filename, /* I - File to read from */
2175 _ppd_localization_t localization) /* I - Localization to load */
2b85e375 2176{
03f61bf3 2177 cups_file_t *fp; /* File pointer */
2178 ppd_file_t *ppd; /* PPD file record */
2625096f 2179 _cups_globals_t *cg = _cupsGlobals();
03f61bf3 2180 /* Global data */
2b85e375 2181
2182
79f448f9 2183 /*
031278ca 2184 * Set the line number to 0...
79f448f9 2185 */
2186
03f61bf3 2187 cg->ppd_line = 0;
79f448f9 2188
2b85e375 2189 /*
2190 * Range check input...
2191 */
2192
2193 if (filename == NULL)
79f448f9 2194 {
03f61bf3 2195 cg->ppd_status = PPD_NULL_FILE;
79f448f9 2196
2b85e375 2197 return (NULL);
79f448f9 2198 }
2b85e375 2199
2200 /*
2201 * Try to open the file and parse it...
2202 */
2203
03f61bf3 2204 if ((fp = cupsFileOpen(filename, "r")) != NULL)
2b85e375 2205 {
6ee6a397 2206 ppd = _ppdOpen(fp, localization);
2b85e375 2207
03f61bf3 2208 cupsFileClose(fp);
2b85e375 2209 }
2210 else
79f448f9 2211 {
03f61bf3 2212 cg->ppd_status = PPD_FILE_OPEN_ERROR;
2213 ppd = NULL;
79f448f9 2214 }
2b85e375 2215
1fdc6cd5 2216 return (ppd);
2217}
2218
2219
6ee6a397 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
49de8bd2 2231/*
2232 * 'ppdSetConformance()' - Set the conformance level for PPD files.
0341722a 2233 *
c45401bb 2234 * @since CUPS 1.1.20/OS X 10.4@
49de8bd2 2235 */
2236
2237void
2238ppdSetConformance(ppd_conform_t c) /* I - Conformance level */
2239{
2625096f 2240 _cups_globals_t *cg = _cupsGlobals();
03f61bf3 2241 /* Global data */
2242
2243
2244 cg->ppd_conform = c;
49de8bd2 2245}
2246
2247
1fdc6cd5 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 */
1b98ab76 2256 const char *text, /* I - Text string, if any */
1fdc6cd5 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
91ac93ad 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
1fdc6cd5 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));
1b98ab76 2306 strlcpy(temp->text, text, sizeof(temp->text));
1fdc6cd5 2307 temp->value = (char *)value;
2308
91ac93ad 2309 /*
2310 * Add the attribute to the sorted array...
2311 */
2312
2313 cupsArrayAdd(ppd->sorted_attrs, temp);
2314
1fdc6cd5 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
91ac93ad 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{
c6fab96f 2392 return (_cups_strcasecmp(a->name, b->name));
91ac93ad 2393}
2394
2395
6482819f 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{
e66fd5e4 2404 return (strcmp(a->option->keyword, b->option->keyword));
6482819f 2405}
2406
2407
1fdc6cd5 2408/*
ff6a82d3 2409 * 'ppd_compare_coptions()' - Compare two custom options.
2410 */
2411
2412static int /* O - Result of comparison */
2413ppd_compare_coptions(ppd_coption_t *a, /* I - First option */
2414 ppd_coption_t *b) /* I - Second option */
2415{
c6fab96f 2416 return (_cups_strcasecmp(a->keyword, b->keyword));
ff6a82d3 2417}
2418
2419
1fdc6cd5 2420/*
2421 * 'ppd_compare_options()' - Compare two options.
2422 */
2423
2424static int /* O - Result of comparison */
ff6a82d3 2425ppd_compare_options(ppd_option_t *a, /* I - First option */
2426 ppd_option_t *b) /* I - Second option */
1fdc6cd5 2427{
c6fab96f 2428 return (_cups_strcasecmp(a->keyword, b->keyword));
1fdc6cd5 2429}
2430
2431
2432/*
2433 * 'ppd_decode()' - Decode a string value...
2434 */
2435
0ca3829c 2436static int /* O - Length of decoded string */
1fdc6cd5 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')
64bbab09 2447 if (*inptr == '<' && isxdigit(inptr[1] & 255))
1fdc6cd5 2448 {
2449 /*
2450 * Convert hex to 8-bit values...
2451 */
2452
2453 inptr ++;
64bbab09 2454 while (isxdigit(*inptr & 255))
1fdc6cd5 2455 {
e00a8345 2456 if (_cups_isalpha(*inptr))
1fdc6cd5 2457 *outptr = (tolower(*inptr) - 'a' + 10) << 4;
2458 else
2459 *outptr = (*inptr - '0') << 4;
2460
2461 inptr ++;
2462
64bbab09 2463 if (!isxdigit(*inptr & 255))
2464 break;
2465
e00a8345 2466 if (_cups_isalpha(*inptr))
1fdc6cd5 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';
0ca3829c 2484
b296d7d9 2485 return ((int)(outptr - string));
1fdc6cd5 2486}
2487
2488
5772e663 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
15166848 2513/*
1fdc6cd5 2514 * 'ppd_free_group()' - Free a single UI group.
15166848 2515 */
2516
1fdc6cd5 2517static void
2518ppd_free_group(ppd_group_t *group) /* I - Group to free */
15166848 2519{
1fdc6cd5 2520 int i; /* Looping var */
2521 ppd_option_t *option; /* Current option */
2522 ppd_group_t *subgroup; /* Current sub-group */
15166848 2523
15166848 2524
1fdc6cd5 2525 if (group->num_options > 0)
15166848 2526 {
1fdc6cd5 2527 for (i = group->num_options, option = group->options;
2528 i > 0;
2529 i --, option ++)
2530 ppd_free_option(option);
15166848 2531
1fdc6cd5 2532 ppd_free(group->options);
15166848 2533 }
2534
1fdc6cd5 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);
15166848 2541
1fdc6cd5 2542 ppd_free(group->subgroups);
2543 }
15166848 2544}
2545
2546
caab0820 2547/*
1fdc6cd5 2548 * 'ppd_free_option()' - Free a single option.
caab0820 2549 */
2550
1fdc6cd5 2551static void
2552ppd_free_option(ppd_option_t *option) /* I - Option to free */
caab0820 2553{
1fdc6cd5 2554 int i; /* Looping var */
2555 ppd_choice_t *choice; /* Current choice */
caab0820 2556
2557
1fdc6cd5 2558 if (option->num_choices > 0)
2559 {
2560 for (i = option->num_choices, choice = option->choices;
2561 i > 0;
2562 i --, choice ++)
ff40b65e 2563 {
80ad038a 2564 _cupsStrFree(choice->code);
ff40b65e 2565 }
caab0820 2566
1fdc6cd5 2567 ppd_free(option->choices);
2568 }
caab0820 2569}
2570
2571
239e58b6 2572/*
ff6a82d3 2573 * 'ppd_get_coption()' - Get a custom option record.
239e58b6 2574 */
2575
ff6a82d3 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 */
239e58b6 2579{
ff6a82d3 2580 ppd_coption_t *copt; /* New custom option */
1fdc6cd5 2581
239e58b6 2582
1fdc6cd5 2583 /*
2584 * See if the option already exists...
2585 */
2586
ff6a82d3 2587 if ((copt = ppdFindCustomOption(ppd, name)) != NULL)
2588 return (copt);
239e58b6 2589
2590 /*
ff6a82d3 2591 * Not found, so create the custom option record...
239e58b6 2592 */
2593
ff6a82d3 2594 if ((copt = calloc(1, sizeof(ppd_coption_t))) == NULL)
239e58b6 2595 return (NULL);
2596
ff6a82d3 2597 strlcpy(copt->keyword, name, sizeof(copt->keyword));
239e58b6 2598
6981bf16 2599 copt->params = cupsArrayNew((cups_array_func_t)NULL, NULL);
239e58b6 2600
b9e18094 2601 cupsArrayAdd(ppd->coptions, copt);
2602
239e58b6 2603 /*
2604 * Return the new record...
2605 */
2606
ff6a82d3 2607 return (copt);
239e58b6 2608}
2609
2610
ab94f399 2611/*
ff6a82d3 2612 * 'ppd_get_cparam()' - Get a custom parameter record.
ab94f399 2613 */
2614
ff6a82d3 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 */
ab94f399 2619{
ff6a82d3 2620 ppd_cparam_t *cparam; /* New custom parameter */
ab94f399 2621
2622
2623 /*
2624 * See if the parameter already exists...
2625 */
2626
ff6a82d3 2627 if ((cparam = ppdFindCustomParam(opt, param)) != NULL)
2628 return (cparam);
ab94f399 2629
2630 /*
ff6a82d3 2631 * Not found, so create the custom parameter record...
ab94f399 2632 */
2633
ff6a82d3 2634 if ((cparam = calloc(1, sizeof(ppd_cparam_t))) == NULL)
ab94f399 2635 return (NULL);
2636
ff6a82d3 2637 strlcpy(cparam->name, param, sizeof(cparam->name));
c36c59b6 2638 strlcpy(cparam->text, text[0] ? text : param, sizeof(cparam->text));
ab94f399 2639
2640 /*
ff6a82d3 2641 * Add this record to the array...
ab94f399 2642 */
2643
ff6a82d3 2644 cupsArrayAdd(opt->params, cparam);
ab94f399 2645
2646 /*
2647 * Return the new record...
2648 */
2649
ff6a82d3 2650 return (cparam);
ab94f399 2651}
2652
2653
1fdc6cd5 2654/*
2655 * 'ppd_get_group()' - Find or create the named group as needed.
2656 */
2657
2658static ppd_group_t * /* O - Named group */
ed04873a 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 */
1fdc6cd5 2664{
2665 int i; /* Looping var */
2666 ppd_group_t *group; /* Group */
2667
2668
571af0ea 2669 DEBUG_printf(("7ppd_get_group(ppd=%p, name=\"%s\", text=\"%s\", cg=%p)",
03f61bf3 2670 ppd, name, text, cg));
1fdc6cd5 2671
2672 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
a501ad17 2673 if (!strcmp(group->name, name))
1fdc6cd5 2674 break;
2675
2676 if (i == 0)
2677 {
571af0ea 2678 DEBUG_printf(("8ppd_get_group: Adding group %s...", name));
1fdc6cd5 2679
03f61bf3 2680 if (cg->ppd_conform == PPD_CONFORM_STRICT && strlen(text) >= sizeof(group->text))
6f83172d 2681 {
03f61bf3 2682 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
6f83172d 2683
2684 return (NULL);
2685 }
c6fab96f 2686
1fdc6cd5 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)
6f83172d 2694 {
03f61bf3 2695 cg->ppd_status = PPD_ALLOC_ERROR;
6f83172d 2696
1fdc6cd5 2697 return (NULL);
6f83172d 2698 }
1fdc6cd5 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));
ed04873a 2706
8c4a3f1a 2707 cupsCharsetToUTF8((cups_utf8_t *)group->text, text,
2708 sizeof(group->text), encoding);
1fdc6cd5 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
571af0ea 2727 DEBUG_printf(("7ppd_get_option(group=%p(\"%s\"), name=\"%s\")",
fd8e0b1e 2728 group, group->name, name));
2729
1fdc6cd5 2730 for (i = group->num_options, option = group->options; i > 0; i --, option ++)
a501ad17 2731 if (!strcmp(option->keyword, name))
1fdc6cd5 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
6482819f 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;)
ed340630 2769 hash = 33 * hash + *k++;
6482819f 2770
2771 return (hash & 511);
2772}
2773
2774
2b85e375 2775/*
2776 * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
2777 * necessary.
2778 */
2779
1fdc6cd5 2780static int /* O - Bitmask of fields read */
03f61bf3 2781ppd_read(cups_file_t *fp, /* I - File to read from */
80ad038a 2782 _ppd_line_t *line, /* I - Line buffer */
03f61bf3 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? */
2625096f 2788 _cups_globals_t *cg) /* I - Global data */
2b85e375 2789{
1fdc6cd5 2790 int ch, /* Character from file */
43cd52be 2791 col, /* Column in line */
1fdc6cd5 2792 colon, /* Colon seen? */
2793 endquote, /* Waiting for an end quote */
eb885f10 2794 mask, /* Mask to be returned */
0ca3829c 2795 startline, /* Start line */
2796 textlen; /* Length of text */
1fdc6cd5 2797 char *keyptr, /* Keyword pointer */
2798 *optptr, /* Option pointer */
2799 *textptr, /* Text pointer */
2800 *strptr, /* Pointer into string */
80ad038a 2801 *lineptr; /* Current position in line buffer */
2b85e375 2802
2b85e375 2803
2804 /*
2805 * Now loop until we have a valid line...
2806 */
2807
eb885f10 2808 *string = NULL;
2809 col = 0;
03f61bf3 2810 startline = cg->ppd_line + 1;
5215179e 2811
80ad038a 2812 if (!line->buffer)
2813 {
2814 line->bufsize = 1024;
2815 line->buffer = malloc(1024);
2816
2817 if (!line->buffer)
2818 return (0);
2819 }
c5b83b99 2820
2b85e375 2821 do
2822 {
2823 /*
2824 * Read the line...
2825 */
2826
80ad038a 2827 lineptr = line->buffer;
2b85e375 2828 endquote = 0;
753453e4 2829 colon = 0;
2b85e375 2830
5215179e 2831 while ((ch = cupsFileGetChar(fp)) != EOF)
2b85e375 2832 {
80ad038a 2833 if (lineptr >= (line->buffer + line->bufsize - 1))
5215179e 2834 {
2835 /*
2836 * Expand the line buffer...
2837 */
2838
2839 char *temp; /* Temporary line pointer */
2840
2841
80ad038a 2842 line->bufsize += 1024;
2843 if (line->bufsize > 262144)
5215179e 2844 {
2845 /*
2846 * Don't allow lines longer than 256k!
2847 */
2848
03f61bf3 2849 cg->ppd_line = startline;
2850 cg->ppd_status = PPD_LINE_TOO_LONG;
5215179e 2851
5215179e 2852 return (0);
2853 }
2854
80ad038a 2855 temp = realloc(line->buffer, line->bufsize);
5215179e 2856 if (!temp)
2857 {
03f61bf3 2858 cg->ppd_line = startline;
2859 cg->ppd_status = PPD_LINE_TOO_LONG;
5215179e 2860
5215179e 2861 return (0);
2862 }
2863
80ad038a 2864 lineptr = temp + (lineptr - line->buffer);
2865 line->buffer = temp;
5215179e 2866 }
2867
2b85e375 2868 if (ch == '\r' || ch == '\n')
2869 {
2870 /*
2871 * Line feed or carriage return...
2872 */
2873
03f61bf3 2874 cg->ppd_line ++;
43cd52be 2875 col = 0;
79f448f9 2876
2b85e375 2877 if (ch == '\r')
2878 {
2879 /*
2880 * Check for a trailing line feed...
2881 */
2882
08379093 2883 if ((ch = cupsFilePeekChar(fp)) == EOF)
b0a98a63 2884 {
2885 ch = '\n';
2b85e375 2886 break;
b0a98a63 2887 }
2888
08379093 2889 if (ch == 0x0a)
2890 cupsFileGetChar(fp);
e8fda7b9 2891 }
2b85e375 2892
80ad038a 2893 if (lineptr == line->buffer && ignoreblank)
60dc191d 2894 continue; /* Skip blank lines */
e7186d00 2895
c5b83b99 2896 ch = '\n';
2b85e375 2897
2898 if (!endquote) /* Continue for multi-line text */
2899 break;
c5b83b99 2900
2901 *lineptr++ = '\n';
2b85e375 2902 }
03f61bf3 2903 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
43cd52be 2904 {
2905 /*
2906 * Other control characters...
2907 */
2908
03f61bf3 2909 cg->ppd_line = startline;
2910 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
43cd52be 2911
2912 return (0);
2913 }
974d95a1 2914 else if (ch != 0x1a)
2b85e375 2915 {
2916 /*
2917 * Any other character...
2918 */
2919
2920 *lineptr++ = ch;
43cd52be 2921 col ++;
2922
2923 if (col > (PPD_MAX_LINE - 1))
2924 {
2925 /*
2926 * Line is too long...
2927 */
2928
03f61bf3 2929 cg->ppd_line = startline;
2930 cg->ppd_status = PPD_LINE_TOO_LONG;
43cd52be 2931
2932 return (0);
2933 }
2b85e375 2934
80ad038a 2935 if (ch == ':' && strncmp(line->buffer, "*%", 2) != 0)
753453e4 2936 colon = 1;
2937
2938 if (ch == '\"' && colon)
132e0c72 2939 endquote = !endquote;
e8fda7b9 2940 }
2941 }
2b85e375 2942
c5b83b99 2943 if (endquote)
2944 {
2945 /*
2946 * Didn't finish this quoted string...
2947 */
2948
08379093 2949 while ((ch = cupsFileGetChar(fp)) != EOF)
c5b83b99 2950 if (ch == '\"')
2951 break;
43cd52be 2952 else if (ch == '\r' || ch == '\n')
2953 {
03f61bf3 2954 cg->ppd_line ++;
43cd52be 2955 col = 0;
2956
2957 if (ch == '\r')
2958 {
2959 /*
2960 * Check for a trailing line feed...
2961 */
2962
08379093 2963 if ((ch = cupsFilePeekChar(fp)) == EOF)
43cd52be 2964 break;
08379093 2965 if (ch == 0x0a)
2966 cupsFileGetChar(fp);
43cd52be 2967 }
43cd52be 2968 }
03f61bf3 2969 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
43cd52be 2970 {
2971 /*
2972 * Other control characters...
2973 */
2974
03f61bf3 2975 cg->ppd_line = startline;
2976 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
43cd52be 2977
2978 return (0);
2979 }
974d95a1 2980 else if (ch != 0x1a)
43cd52be 2981 {
2982 col ++;
2983
2984 if (col > (PPD_MAX_LINE - 1))
2985 {
2986 /*
2987 * Line is too long...
2988 */
2989
03f61bf3 2990 cg->ppd_line = startline;
2991 cg->ppd_status = PPD_LINE_TOO_LONG;
43cd52be 2992
2993 return (0);
2994 }
2995 }
c5b83b99 2996 }
2997
2998 if (ch != '\n')
2999 {
3000 /*
3001 * Didn't finish this line...
3002 */
3003
08379093 3004 while ((ch = cupsFileGetChar(fp)) != EOF)
c5b83b99 3005 if (ch == '\r' || ch == '\n')
3006 {
3007 /*
3008 * Line feed or carriage return...
3009 */
3010
03f61bf3 3011 cg->ppd_line ++;
43cd52be 3012 col = 0;
031278ca 3013
c5b83b99 3014 if (ch == '\r')
3015 {
3016 /*
3017 * Check for a trailing line feed...
3018 */
3019
08379093 3020 if ((ch = cupsFilePeekChar(fp)) == EOF)
c5b83b99 3021 break;
08379093 3022 if (ch == 0x0a)
3023 cupsFileGetChar(fp);
c5b83b99 3024 }
3025
3026 break;
3027 }
03f61bf3 3028 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
43cd52be 3029 {
3030 /*
3031 * Other control characters...
3032 */
3033
03f61bf3 3034 cg->ppd_line = startline;
3035 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
43cd52be 3036
3037 return (0);
3038 }
974d95a1 3039 else if (ch != 0x1a)
43cd52be 3040 {
3041 col ++;
3042
3043 if (col > (PPD_MAX_LINE - 1))
3044 {
3045 /*
3046 * Line is too long...
3047 */
3048
03f61bf3 3049 cg->ppd_line = startline;
3050 cg->ppd_status = PPD_LINE_TOO_LONG;
43cd52be 3051
3052 return (0);
3053 }
3054 }
c5b83b99 3055 }
3056
80ad038a 3057 if (lineptr > line->buffer && lineptr[-1] == '\n')
2b85e375 3058 lineptr --;
3059
3060 *lineptr = '\0';
3061
bf830e05 3062 DEBUG_printf(("9ppd_read: LINE=\"%s\"", line->buffer));
753453e4 3063
91ac93ad 3064 /*
c45401bb 3065 * The dynamically created PPDs for older style OS X
91ac93ad 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
80ad038a 3071 if (!strcmp(line->buffer, "*%APLWORKSET START"))
91ac93ad 3072 return (0);
91ac93ad 3073
80ad038a 3074 if (ch == EOF && lineptr == line->buffer)
2b85e375 3075 return (0);
3076
3077 /*
3078 * Now parse it...
3079 */
3080
3081 mask = 0;
80ad038a 3082 lineptr = line->buffer + 1;
2b85e375 3083
3084 keyword[0] = '\0';
3085 option[0] = '\0';
3086 text[0] = '\0';
3087 *string = NULL;
3088
80ad038a 3089 if ((!line->buffer[0] || /* Blank line */
3090 !strncmp(line->buffer, "*%", 2) || /* Comment line */
3091 !strcmp(line->buffer, "*End")) && /* End of multi-line string */
60dc191d 3092 ignoreblank) /* Ignore these? */
eb885f10 3093 {
03f61bf3 3094 startline = cg->ppd_line + 1;
2b85e375 3095 continue;
eb885f10 3096 }
2b85e375 3097
80ad038a 3098 if (!strcmp(line->buffer, "*")) /* (Bad) comment line */
49de8bd2 3099 {
03f61bf3 3100 if (cg->ppd_conform == PPD_CONFORM_RELAXED)
49de8bd2 3101 {
03f61bf3 3102 startline = cg->ppd_line + 1;
49de8bd2 3103 continue;
3104 }
3105 else
3106 {
03f61bf3 3107 cg->ppd_line = startline;
3108 cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
49de8bd2 3109
3110 return (0);
3111 }
3112 }
3113
80ad038a 3114 if (line->buffer[0] != '*') /* All lines start with an asterisk */
43cd52be 3115 {
b96c21b1 3116 /*
3117 * Allow lines consisting of just whitespace...
3118 */
3119
80ad038a 3120 for (lineptr = line->buffer; *lineptr; lineptr ++)
e00a8345 3121 if (*lineptr && !_cups_isspace(*lineptr))
b96c21b1 3122 break;
3123
3124 if (*lineptr)
3125 {
03f61bf3 3126 cg->ppd_status = PPD_MISSING_ASTERISK;
b96c21b1 3127 return (0);
3128 }
60dc191d 3129 else if (ignoreblank)
b96c21b1 3130 continue;
60dc191d 3131 else
3132 return (0);
43cd52be 3133 }
3134
2b85e375 3135 /*
3136 * Get a keyword...
3137 */
3138
3139 keyptr = keyword;
3140
e00a8345 3141 while (*lineptr && *lineptr != ':' && !_cups_isspace(*lineptr))
43cd52be 3142 {
3143 if (*lineptr <= ' ' || *lineptr > 126 || *lineptr == '/' ||
3144 (keyptr - keyword) >= (PPD_MAX_NAME - 1))
3145 {
03f61bf3 3146 cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
43cd52be 3147 return (0);
3148 }
3149
3150 *keyptr++ = *lineptr++;
3151 }
2b85e375 3152
3153 *keyptr = '\0';
753453e4 3154
a501ad17 3155 if (!strcmp(keyword, "End"))
753453e4 3156 continue;
3157
2b85e375 3158 mask |= PPD_KEYWORD;
3159
e00a8345 3160 if (_cups_isspace(*lineptr))
2b85e375 3161 {
3162 /*
3163 * Get an option name...
3164 */
3165
e00a8345 3166 while (_cups_isspace(*lineptr))
2b85e375 3167 lineptr ++;
3168
3169 optptr = option;
3170
e00a8345 3171 while (*lineptr && !_cups_isspace(*lineptr) && *lineptr != ':' &&
43cd52be 3172 *lineptr != '/')
3173 {
3174 if (*lineptr <= ' ' || *lineptr > 126 ||
3175 (optptr - option) >= (PPD_MAX_NAME - 1))
3176 {
03f61bf3 3177 cg->ppd_status = PPD_ILLEGAL_OPTION_KEYWORD;
43cd52be 3178 return (0);
3179 }
3180
3181 *optptr++ = *lineptr++;
3182 }
2b85e375 3183
3184 *optptr = '\0';
49de8bd2 3185
e00a8345 3186 if (_cups_isspace(*lineptr) && cg->ppd_conform == PPD_CONFORM_STRICT)
49de8bd2 3187 {
03f61bf3 3188 cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
49de8bd2 3189 return (0);
3190 }
3191
e00a8345 3192 while (_cups_isspace(*lineptr))
9e678e84 3193 lineptr ++;
3194
2b85e375 3195 mask |= PPD_OPTION;
3196
3197 if (*lineptr == '/')
3198 {
3199 /*
3200 * Get human-readable text...
3201 */
3202
3203 lineptr ++;
c6fab96f 3204
2b85e375 3205 textptr = text;
3206
43cd52be 3207 while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':')
3208 {
974d95a1 3209 if (((unsigned char)*lineptr < ' ' && *lineptr != '\t') ||
43cd52be 3210 (textptr - text) >= (PPD_MAX_LINE - 1))
3211 {
03f61bf3 3212 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
43cd52be 3213 return (0);
3214 }
3215
3216 *textptr++ = *lineptr++;
3217 }
2b85e375 3218
3219 *textptr = '\0';
0ca3829c 3220 textlen = ppd_decode(text);
2b85e375 3221
03f61bf3 3222 if (textlen > PPD_MAX_TEXT && cg->ppd_conform == PPD_CONFORM_STRICT)
0ca3829c 3223 {
03f61bf3 3224 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
0ca3829c 3225 return (0);
3226 }
c6fab96f 3227
2b85e375 3228 mask |= PPD_TEXT;
e8fda7b9 3229 }
3230 }
2b85e375 3231
e00a8345 3232 if (_cups_isspace(*lineptr) && cg->ppd_conform == PPD_CONFORM_STRICT)
49de8bd2 3233 {
03f61bf3 3234 cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
49de8bd2 3235 return (0);
3236 }
3237
e00a8345 3238 while (_cups_isspace(*lineptr))
49de8bd2 3239 lineptr ++;
3240
2b85e375 3241 if (*lineptr == ':')
3242 {
3243 /*
e7186d00 3244 * Get string after triming leading and trailing whitespace...
2b85e375 3245 */
3246
49de8bd2 3247 lineptr ++;
e00a8345 3248 while (_cups_isspace(*lineptr))
2b85e375 3249 lineptr ++;
3250
e2c9ebc5 3251 strptr = lineptr + strlen(lineptr) - 1;
e00a8345 3252 while (strptr >= lineptr && _cups_isspace(*strptr))
e7186d00 3253 *strptr-- = '\0';
3254
2e8cd988 3255 if (*strptr == '\"')
3256 {
3257 /*
80ad038a 3258 * Quoted string by itself, remove quotes...
2e8cd988 3259 */
3260
80ad038a 3261 *strptr = '\0';
3262 lineptr ++;
2e8cd988 3263 }
80ad038a 3264
3265 *string = _cupsStrAlloc(lineptr);
58ec2a95 3266
2b85e375 3267 mask |= PPD_STRING;
e8fda7b9 3268 }
2b85e375 3269 }
3270 while (mask == 0);
3271
3272 return (mask);
3273}
3274
3275
5772e663 3276/*
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
2b85e375 3396/*
b2e10895 3397 * End of "$Id$".
90a24de4 3398 */