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