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