]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/ppd.c
Merge changes from CUPS 1.5svn-r9229.
[thirdparty/cups.git] / cups / ppd.c
CommitLineData
ef416fc2 1/*
b19ccc9e 2 * "$Id: ppd.c 7906 2008-09-03 20:19:43Z mike $"
ef416fc2 3 *
54afec33 4 * PPD file routines for CUPS.
ef416fc2 5 *
54afec33 6 * Copyright 2007-2010 by Apple Inc.
b86bc4cf 7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
ef416fc2 8 *
9 * These coded instructions, statements, and computer programs are the
bc44d920 10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
ef416fc2 14 *
15 * PostScript is a trademark of Adobe Systems, Inc.
16 *
17 * This code and any derivative of it may be used and distributed
18 * freely under the terms of the GNU General Public License when
19 * used with GNU Ghostscript or its derivatives. Use of the code
20 * (or any derivative of it) with software other than GNU
21 * GhostScript (or its derivatives) is governed by the CUPS license
22 * agreement.
23 *
24 * This file is subject to the Apple OS-Developed Software exception.
25 *
26 * Contents:
27 *
fa73b229 28 * ppdClose() - Free all memory used by the PPD file.
29 * ppdErrorString() - Returns the text assocated with a status.
80ca4592 30 * _ppdGetEncoding() - Get the CUPS encoding value for the given
31 * LanguageEncoding.
fa73b229 32 * ppdLastError() - Return the status from the last ppdOpen*().
33 * ppdOpen() - Read a PPD file into memory.
bd7854cb 34 * ppdOpen2() - Read a PPD file into memory.
fa73b229 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.
bd7854cb 41 * ppd_compare_attrs() - Compare two attributes.
b94498cf 42 * ppd_compare_choices() - Compare two choices...
fa73b229 43 * ppd_compare_coptions() - Compare two custom options.
44 * ppd_compare_cparams() - Compare two custom parameters.
45 * ppd_compare_options() - Compare two options.
46 * ppd_decode() - Decode a string value...
47 * ppd_free_group() - Free a single UI group.
48 * ppd_free_option() - Free a single option.
49 * ppd_get_coption() - Get a custom option record.
50 * ppd_get_cparam() - Get a custom parameter record.
51 * ppd_get_group() - Find or create the named group as needed.
52 * ppd_get_option() - Find or create the named option as needed.
b94498cf 53 * ppd_hash_option() - Generate a hash of the option name...
fa73b229 54 * ppd_read() - Read a line from a PPD file, skipping comment
55 * lines as necessary.
ef416fc2 56 */
57
58/*
59 * Include necessary headers.
60 */
61
71e16022 62#include "cups-private.h"
005dd1eb 63#include "ppd-private.h"
ef416fc2 64
65
66/*
67 * Definitions...
68 */
69
70#if defined(WIN32) || defined(__EMX__)
71# define READ_BINARY "rb" /* Open a binary file for reading */
72# define WRITE_BINARY "wb" /* Open a binary file for writing */
73#else
74# define READ_BINARY "r" /* Open a binary file for reading */
75# define WRITE_BINARY "w" /* Open a binary file for writing */
76#endif /* WIN32 || __EMX__ */
77
78#define ppd_free(p) if (p) free(p) /* Safe free macro */
79
80#define PPD_KEYWORD 1 /* Line contained a keyword */
81#define PPD_OPTION 2 /* Line contained an option name */
82#define PPD_TEXT 4 /* Line contained human-readable text */
83#define PPD_STRING 8 /* Line contained a string or code */
84
b94498cf 85#define PPD_HASHSIZE 512 /* Size of hash */
86
ef416fc2 87
2e4ff8af
MS
88/*
89 * Line buffer structure...
90 */
91
92typedef struct _ppd_line_s
93{
94 char *buffer; /* Pointer to buffer */
95 size_t bufsize; /* Size of the buffer */
96} _ppd_line_t;
97
98
ef416fc2 99/*
100 * Local functions...
101 */
102
103static ppd_attr_t *ppd_add_attr(ppd_file_t *ppd, const char *name,
104 const char *spec, const char *text,
105 const char *value);
106static ppd_choice_t *ppd_add_choice(ppd_option_t *option, const char *name);
107static ppd_size_t *ppd_add_size(ppd_file_t *ppd, const char *name);
bd7854cb 108static int ppd_compare_attrs(ppd_attr_t *a, ppd_attr_t *b);
b94498cf 109static int ppd_compare_choices(ppd_choice_t *a, ppd_choice_t *b);
bd7854cb 110static int ppd_compare_coptions(ppd_coption_t *a,
111 ppd_coption_t *b);
fa73b229 112static int ppd_compare_cparams(ppd_cparam_t *a, ppd_cparam_t *b);
113static int ppd_compare_options(ppd_option_t *a, ppd_option_t *b);
ef416fc2 114static int ppd_decode(char *string);
115static void ppd_free_group(ppd_group_t *group);
116static void ppd_free_option(ppd_option_t *option);
fa73b229 117static ppd_coption_t *ppd_get_coption(ppd_file_t *ppd, const char *name);
118static ppd_cparam_t *ppd_get_cparam(ppd_coption_t *opt,
119 const char *param,
120 const char *text);
ef416fc2 121static ppd_group_t *ppd_get_group(ppd_file_t *ppd, const char *name,
e1d6a774 122 const char *text, _cups_globals_t *cg,
123 cups_encoding_t encoding);
ef416fc2 124static ppd_option_t *ppd_get_option(ppd_group_t *group, const char *name);
b94498cf 125static int ppd_hash_option(ppd_option_t *option);
2e4ff8af
MS
126static int ppd_read(cups_file_t *fp, _ppd_line_t *line,
127 char *keyword, char *option, char *text,
128 char **string, int ignoreblank,
ef416fc2 129 _cups_globals_t *cg);
130
131
ef416fc2 132/*
133 * 'ppdClose()' - Free all memory used by the PPD file.
134 */
135
136void
137ppdClose(ppd_file_t *ppd) /* I - PPD file record */
138{
139 int i; /* Looping var */
140 ppd_emul_t *emul; /* Current emulation */
141 ppd_group_t *group; /* Current group */
142 char **font; /* Current font */
143 char **filter; /* Current filter */
144 ppd_attr_t **attr; /* Current attribute */
fa73b229 145 ppd_coption_t *coption; /* Current custom option */
146 ppd_cparam_t *cparam; /* Current custom parameter */
ef416fc2 147
148
149 /*
fa73b229 150 * Range check arguments...
ef416fc2 151 */
152
fa73b229 153 if (!ppd)
ef416fc2 154 return;
155
156 /*
157 * Free all strings at the top level...
158 */
159
2e4ff8af
MS
160 _cupsStrFree(ppd->lang_encoding);
161 _cupsStrFree(ppd->nickname);
745129be
MS
162 if (ppd->patches)
163 free(ppd->patches);
2e4ff8af
MS
164 _cupsStrFree(ppd->jcl_begin);
165 _cupsStrFree(ppd->jcl_end);
166 _cupsStrFree(ppd->jcl_ps);
ef416fc2 167
168 /*
169 * Free any emulations...
170 */
171
172 if (ppd->num_emulations > 0)
173 {
174 for (i = ppd->num_emulations, emul = ppd->emulations; i > 0; i --, emul ++)
175 {
2e4ff8af
MS
176 _cupsStrFree(emul->start);
177 _cupsStrFree(emul->stop);
ef416fc2 178 }
179
180 ppd_free(ppd->emulations);
181 }
182
183 /*
184 * Free any UI groups, subgroups, and options...
185 */
186
187 if (ppd->num_groups > 0)
188 {
189 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
190 ppd_free_group(group);
191
192 ppd_free(ppd->groups);
193 }
194
fa73b229 195 cupsArrayDelete(ppd->options);
b94498cf 196 cupsArrayDelete(ppd->marked);
fa73b229 197
ef416fc2 198 /*
199 * Free any page sizes...
200 */
201
202 if (ppd->num_sizes > 0)
ef416fc2 203 ppd_free(ppd->sizes);
ef416fc2 204
205 /*
206 * Free any constraints...
207 */
208
209 if (ppd->num_consts > 0)
ef416fc2 210 ppd_free(ppd->consts);
ef416fc2 211
212 /*
213 * Free any filters...
214 */
215
216 if (ppd->num_filters > 0)
217 {
218 for (i = ppd->num_filters, filter = ppd->filters; i > 0; i --, filter ++)
2e4ff8af 219 _cupsStrFree(*filter);
ef416fc2 220
221 ppd_free(ppd->filters);
222 }
223
224 /*
225 * Free any fonts...
226 */
227
228 if (ppd->num_fonts > 0)
229 {
230 for (i = ppd->num_fonts, font = ppd->fonts; i > 0; i --, font ++)
2e4ff8af 231 _cupsStrFree(*font);
ef416fc2 232
233 ppd_free(ppd->fonts);
234 }
235
236 /*
237 * Free any profiles...
238 */
239
240 if (ppd->num_profiles > 0)
ef416fc2 241 ppd_free(ppd->profiles);
ef416fc2 242
243 /*
244 * Free any attributes...
245 */
246
247 if (ppd->num_attrs > 0)
248 {
249 for (i = ppd->num_attrs, attr = ppd->attrs; i > 0; i --, attr ++)
250 {
2e4ff8af 251 _cupsStrFree((*attr)->value);
ef416fc2 252 ppd_free(*attr);
253 }
254
255 ppd_free(ppd->attrs);
256 }
257
b423cd4c 258 cupsArrayDelete(ppd->sorted_attrs);
259
fa73b229 260 /*
261 * Free custom options...
262 */
263
264 for (coption = (ppd_coption_t *)cupsArrayFirst(ppd->coptions);
265 coption;
266 coption = (ppd_coption_t *)cupsArrayNext(ppd->coptions))
ef416fc2 267 {
fa73b229 268 for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
269 cparam;
270 cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
ef416fc2 271 {
fa73b229 272 switch (cparam->type)
273 {
274 case PPD_CUSTOM_PASSCODE :
275 case PPD_CUSTOM_PASSWORD :
276 case PPD_CUSTOM_STRING :
2e4ff8af 277 _cupsStrFree(cparam->current.custom_string);
fa73b229 278 break;
ef416fc2 279
fa73b229 280 default :
281 break;
282 }
ef416fc2 283
fa73b229 284 free(cparam);
ef416fc2 285 }
286
fa73b229 287 cupsArrayDelete(coption->params);
288
289 free(coption);
ef416fc2 290 }
fa73b229 291
292 cupsArrayDelete(ppd->coptions);
ef416fc2 293
005dd1eb
MS
294 /*
295 * Free constraints...
296 */
297
298 if (ppd->cups_uiconstraints)
299 {
300 _ppd_cups_uiconsts_t *consts; /* Current constraints */
301
302
303 for (consts = (_ppd_cups_uiconsts_t *)cupsArrayFirst(ppd->cups_uiconstraints);
304 consts;
305 consts = (_ppd_cups_uiconsts_t *)cupsArrayNext(ppd->cups_uiconstraints))
306 {
307 free(consts->constraints);
308 free(consts);
309 }
310
311 cupsArrayDelete(ppd->cups_uiconstraints);
312 }
313
54afec33
MS
314 /*
315 * Free any PWG mapping data...
316 */
317
318 if (ppd->pwg)
319 _pwgDestroy((_pwg_t *)ppd->pwg);
320
ef416fc2 321 /*
322 * Free the whole record...
323 */
324
325 ppd_free(ppd);
326}
327
328
329/*
330 * 'ppdErrorString()' - Returns the text assocated with a status.
331 *
426c6a59 332 * @since CUPS 1.1.19/Mac OS X 10.3@
ef416fc2 333 */
334
335const char * /* O - Status string */
336ppdErrorString(ppd_status_t status) /* I - PPD status */
337{
338 static const char * const messages[] =/* Status messages */
339 {
fa73b229 340 _("OK"),
341 _("Unable to open PPD file"),
342 _("NULL PPD file pointer"),
343 _("Memory allocation error"),
344 _("Missing PPD-Adobe-4.x header"),
345 _("Missing value string"),
346 _("Internal error"),
347 _("Bad OpenGroup"),
348 _("OpenGroup without a CloseGroup first"),
349 _("Bad OpenUI/JCLOpenUI"),
350 _("OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first"),
351 _("Bad OrderDependency"),
352 _("Bad UIConstraints"),
353 _("Missing asterisk in column 1"),
354 _("Line longer than the maximum allowed (255 characters)"),
355 _("Illegal control character"),
356 _("Illegal main keyword string"),
357 _("Illegal option keyword string"),
358 _("Illegal translation string"),
359 _("Illegal whitespace character"),
ef55b745
MS
360 _("Bad custom parameter"),
361 _("Missing option keyword"),
362 _("Bad value string")
ef416fc2 363 };
364
365
ef55b745 366 if (status < PPD_OK || status >= PPD_MAX_STATUS)
fa73b229 367 return (_cupsLangString(cupsLangDefault(), _("Unknown")));
ef416fc2 368 else
fa73b229 369 return (_cupsLangString(cupsLangDefault(), messages[status]));
ef416fc2 370}
371
372
80ca4592 373/*
374 * '_ppdGetEncoding()' - Get the CUPS encoding value for the given
375 * LanguageEncoding.
376 */
377
378cups_encoding_t /* O - CUPS encoding value */
379_ppdGetEncoding(const char *name) /* I - LanguageEncoding string */
380{
381 if (!strcasecmp(name, "ISOLatin1"))
382 return (CUPS_ISO8859_1);
383 else if (!strcasecmp(name, "ISOLatin2"))
384 return (CUPS_ISO8859_2);
385 else if (!strcasecmp(name, "ISOLatin5"))
386 return (CUPS_ISO8859_5);
387 else if (!strcasecmp(name, "JIS83-RKSJ"))
4b3f67ff 388 return (CUPS_JIS_X0213);
80ca4592 389 else if (!strcasecmp(name, "MacStandard"))
390 return (CUPS_MAC_ROMAN);
391 else if (!strcasecmp(name, "WindowsANSI"))
392 return (CUPS_WINDOWS_1252);
393 else
394 return (CUPS_UTF8);
395}
396
397
ef416fc2 398/*
399 * 'ppdLastError()' - Return the status from the last ppdOpen*().
400 *
426c6a59 401 * @since CUPS 1.1.19/Mac OS X 10.3@
ef416fc2 402 */
403
404ppd_status_t /* O - Status code */
405ppdLastError(int *line) /* O - Line number */
406{
407 _cups_globals_t *cg = _cupsGlobals();
408 /* Global data */
409
410
411 if (line)
412 *line = cg->ppd_line;
413
414 return (cg->ppd_status);
415}
416
417
418/*
419 * 'ppdOpen()' - Read a PPD file into memory.
420 */
421
422ppd_file_t * /* O - PPD file record */
423ppdOpen(FILE *fp) /* I - File to read from */
424{
425 ppd_file_t *ppd; /* PPD file record */
426 cups_file_t *cf; /* CUPS file */
427
428
429 /*
430 * Reopen the stdio file as a CUPS file...
431 */
432
433 if ((cf = cupsFileOpenFd(fileno(fp), "r")) == NULL)
434 return (NULL);
435
436 /*
437 * Load the PPD file using the newer API...
438 */
439
440 ppd = ppdOpen2(cf);
441
442 /*
443 * Close the CUPS file and return the PPD...
444 */
445
446 cupsFileClose(cf);
447
448 return (ppd);
449}
450
451
452/*
453 * 'ppdOpen2()' - Read a PPD file into memory.
454 *
426c6a59 455 * @since CUPS 1.2/Mac OS X 10.5@
ef416fc2 456 */
457
5a738aea 458ppd_file_t * /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
ef416fc2 459ppdOpen2(cups_file_t *fp) /* I - File to read from */
460{
fa73b229 461 int i, j, k; /* Looping vars */
ef416fc2 462 int count; /* Temporary count */
2e4ff8af 463 _ppd_line_t line; /* Line buffer */
ef416fc2 464 ppd_file_t *ppd; /* PPD file record */
465 ppd_group_t *group, /* Current group */
466 *subgroup; /* Current sub-group */
467 ppd_option_t *option; /* Current option */
468 ppd_choice_t *choice; /* Current choice */
469 ppd_const_t *constraint; /* Current constraint */
470 ppd_size_t *size; /* Current page size */
471 int mask; /* Line data mask */
472 char keyword[PPD_MAX_NAME],
473 /* Keyword from file */
474 name[PPD_MAX_NAME],
475 /* Option from file */
476 text[PPD_MAX_LINE],
477 /* Human-readable text from file */
478 *string, /* Code/text from file */
479 *sptr, /* Pointer into string */
480 *nameptr, /* Pointer into name */
481 *temp, /* Temporary string pointer */
482 **tempfonts; /* Temporary fonts pointer */
483 float order; /* Order dependency number */
484 ppd_section_t section; /* Order dependency section */
485 ppd_profile_t *profile; /* Pointer to color profile */
486 char **filter; /* Pointer to filter */
487 cups_lang_t *language; /* Default language */
757d2cad 488 struct lconv *loc; /* Locale data */
ef416fc2 489 int ui_keyword; /* Is this line a UI keyword? */
e1d6a774 490 cups_encoding_t encoding; /* Encoding of PPD file */
ef416fc2 491 _cups_globals_t *cg = _cupsGlobals();
492 /* Global data */
0a682745
MS
493 char custom_name[PPD_MAX_NAME];
494 /* CustomFoo attribute name */
495 ppd_attr_t *custom_attr; /* CustomFoo attribute */
ef416fc2 496 static const char * const ui_keywords[] =
497 {
bd7854cb 498#ifdef CUPS_USE_FULL_UI_KEYWORDS_LIST
499 /*
500 * Adobe defines some 41 keywords as "UI", meaning that they are
501 * user interface elements and that they should be treated as such
502 * even if the PPD creator doesn't use Open/CloseUI around them.
503 *
504 * Since this can cause previously invisible options to appear and
505 * confuse users, the default is to only treat the PageSize and
506 * PageRegion keywords this way.
507 */
ef416fc2 508 /* Boolean keywords */
509 "BlackSubstitution",
510 "Booklet",
511 "Collate",
512 "ManualFeed",
513 "MirrorPrint",
514 "NegativePrint",
515 "Sorter",
516 "TraySwitch",
517
518 /* PickOne keywords */
519 "AdvanceMedia",
520 "BindColor",
521 "BindEdge",
522 "BindType",
523 "BindWhen",
524 "BitsPerPixel",
525 "ColorModel",
526 "CutMedia",
527 "Duplex",
528 "FoldType",
529 "FoldWhen",
530 "InputSlot",
531 "JCLFrameBufferSize",
532 "JCLResolution",
533 "Jog",
534 "MediaColor",
535 "MediaType",
536 "MediaWeight",
537 "OutputBin",
538 "OutputMode",
539 "OutputOrder",
540 "PageRegion",
541 "PageSize",
542 "Resolution",
543 "Separations",
544 "Signature",
545 "Slipsheet",
546 "Smoothing",
547 "StapleLocation",
548 "StapleOrientation",
549 "StapleWhen",
550 "StapleX",
551 "StapleY"
bd7854cb 552#else /* !CUPS_USE_FULL_UI_KEYWORDS_LIST */
553 "PageRegion",
554 "PageSize"
555#endif /* CUPS_USE_FULL_UI_KEYWORDS_LIST */
ef416fc2 556 };
557
558
e07d4801
MS
559 DEBUG_printf(("ppdOpen2(fp=%p)", fp));
560
ef416fc2 561 /*
562 * Default to "OK" status...
563 */
564
565 cg->ppd_status = PPD_OK;
566 cg->ppd_line = 0;
567
568 /*
569 * Range check input...
570 */
571
572 if (fp == NULL)
573 {
574 cg->ppd_status = PPD_NULL_FILE;
575 return (NULL);
576 }
577
578 /*
579 * Grab the first line and make sure it reads '*PPD-Adobe: "major.minor"'...
580 */
581
2e4ff8af
MS
582 line.buffer = NULL;
583 line.bufsize = 0;
584
585 mask = ppd_read(fp, &line, keyword, name, text, &string, 0, cg);
ef416fc2 586
e07d4801 587 DEBUG_printf(("2ppdOpen2: mask=%x, keyword=\"%s\"...", mask, keyword));
ef416fc2 588
589 if (mask == 0 ||
590 strcmp(keyword, "PPD-Adobe") ||
591 string == NULL || string[0] != '4')
592 {
593 /*
594 * Either this is not a PPD file, or it is not a 4.x PPD file.
595 */
596
597 if (cg->ppd_status == PPD_OK)
598 cg->ppd_status = PPD_MISSING_PPDADOBE4;
599
2e4ff8af 600 _cupsStrFree(string);
9f5eb9be 601 ppd_free(line.buffer);
ef416fc2 602
603 return (NULL);
604 }
605
e07d4801 606 DEBUG_printf(("2ppdOpen2: keyword=%s, string=%p", keyword, string));
ef416fc2 607
2e4ff8af 608 _cupsStrFree(string);
ef416fc2 609
610 /*
611 * Allocate memory for the PPD file record...
612 */
613
614 if ((ppd = calloc(1, sizeof(ppd_file_t))) == NULL)
615 {
616 cg->ppd_status = PPD_ALLOC_ERROR;
617
9f5eb9be
MS
618 _cupsStrFree(string);
619 ppd_free(line.buffer);
620
ef416fc2 621 return (NULL);
622 }
623
355e94dc 624 ppd->language_level = 2;
ef416fc2 625 ppd->color_device = 0;
839a51c8 626 ppd->colorspace = PPD_CS_N;
ef416fc2 627 ppd->landscape = -90;
fa73b229 628 ppd->coptions = cupsArrayNew((cups_array_func_t)ppd_compare_coptions,
629 NULL);
ef416fc2 630
631 /*
632 * Get the default language for the user...
633 */
634
635 language = cupsLangDefault();
757d2cad 636 loc = localeconv();
ef416fc2 637
638 /*
639 * Read lines from the PPD file and add them to the file record...
640 */
641
642 group = NULL;
643 subgroup = NULL;
644 option = NULL;
645 choice = NULL;
646 ui_keyword = 0;
e1d6a774 647 encoding = CUPS_ISO8859_1;
ef416fc2 648
2e4ff8af 649 while ((mask = ppd_read(fp, &line, keyword, name, text, &string, 1, cg)) != 0)
ef416fc2 650 {
e07d4801
MS
651 DEBUG_printf(("2ppdOpen2: mask=%x, keyword=\"%s\", name=\"%s\", "
652 "text=\"%s\", string=%d chars...", mask, keyword, name, text,
969307f0 653 string ? (int)strlen(string) : 0));
ef416fc2 654
c5571a1d
MS
655 if (strncmp(keyword, "Default", 7) && !string &&
656 cg->ppd_conform != PPD_CONFORM_RELAXED)
ef416fc2 657 {
658 /*
659 * Need a string value!
660 */
661
662 cg->ppd_status = PPD_MISSING_VALUE;
663
664 goto error;
665 }
666
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
676 if (ui_keyword)
677 {
678 /*
679 * Previous line was a UI keyword...
680 */
681
682 option = NULL;
683 ui_keyword = 0;
684 }
685
686 if (option == NULL &&
687 (mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) ==
688 (PPD_KEYWORD | PPD_OPTION | PPD_STRING))
689 {
690 for (i = 0; i < (int)(sizeof(ui_keywords) / sizeof(ui_keywords[0])); i ++)
691 if (!strcmp(keyword, ui_keywords[i]))
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
700 ui_keyword = 1;
701
e07d4801 702 DEBUG_printf(("2ppdOpen2: FOUND ADOBE UI KEYWORD %s WITHOUT OPENUI!",
ef416fc2 703 keyword));
704
705 if (!group)
706 {
e1d6a774 707 if ((group = ppd_get_group(ppd, "General", _("General"), cg,
708 encoding)) == NULL)
ef416fc2 709 goto error;
710
e07d4801 711 DEBUG_printf(("2ppdOpen2: Adding to group %s...", group->text));
ef416fc2 712 option = ppd_get_option(group, keyword);
713 group = NULL;
714 }
715 else
716 option = ppd_get_option(group, keyword);
717
718 if (option == NULL)
719 {
720 cg->ppd_status = PPD_ALLOC_ERROR;
721
722 goto error;
723 }
724
725 /*
726 * Now fill in the initial information for the option...
727 */
728
729 if (!strncmp(keyword, "JCL", 3))
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;
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 {
e07d4801 746 DEBUG_printf(("2ppdOpen2: Setting Default%s to %s via attribute...",
ef416fc2 747 option->keyword, ppd->attrs[j]->value));
748 strlcpy(option->defchoice, ppd->attrs[j]->value,
749 sizeof(option->defchoice));
750 break;
751 }
752
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));
763 else
764 strlcpy(option->text, keyword, sizeof(option->text));
765 }
766 }
767
768 if (!strcmp(keyword, "LanguageLevel"))
769 ppd->language_level = atoi(string);
770 else if (!strcmp(keyword, "LanguageEncoding"))
e1d6a774 771 {
772 /*
773 * Say all PPD files are UTF-8, since we convert to UTF-8...
774 */
775
2e4ff8af 776 ppd->lang_encoding = _cupsStrAlloc("UTF-8");
80ca4592 777 encoding = _ppdGetEncoding(string);
e1d6a774 778 }
ef416fc2 779 else if (!strcmp(keyword, "LanguageVersion"))
780 ppd->lang_version = string;
781 else if (!strcmp(keyword, "Manufacturer"))
782 ppd->manufacturer = string;
783 else if (!strcmp(keyword, "ModelName"))
784 ppd->modelname = string;
785 else if (!strcmp(keyword, "Protocols"))
786 ppd->protocols = string;
787 else if (!strcmp(keyword, "PCFileName"))
788 ppd->pcfilename = string;
789 else if (!strcmp(keyword, "NickName"))
e1d6a774 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);
2e4ff8af 797 ppd->nickname = _cupsStrAlloc((char *)utf8);
e1d6a774 798 }
799 else
2e4ff8af 800 ppd->nickname = _cupsStrAlloc(string);
e1d6a774 801 }
ef416fc2 802 else if (!strcmp(keyword, "Product"))
803 ppd->product = string;
804 else if (!strcmp(keyword, "ShortNickName"))
805 ppd->shortnickname = string;
806 else if (!strcmp(keyword, "TTRasterizer"))
807 ppd->ttrasterizer = string;
808 else if (!strcmp(keyword, "JCLBegin"))
809 {
2e4ff8af 810 ppd->jcl_begin = _cupsStrAlloc(string);
ef416fc2 811 ppd_decode(ppd->jcl_begin); /* Decode quoted string */
812 }
813 else if (!strcmp(keyword, "JCLEnd"))
814 {
2e4ff8af 815 ppd->jcl_end = _cupsStrAlloc(string);
ef416fc2 816 ppd_decode(ppd->jcl_end); /* Decode quoted string */
817 }
818 else if (!strcmp(keyword, "JCLToPSInterpreter"))
819 {
2e4ff8af 820 ppd->jcl_ps = _cupsStrAlloc(string);
ef416fc2 821 ppd_decode(ppd->jcl_ps); /* Decode quoted string */
822 }
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"))
834 ppd->model_number = atoi(string);
835 else if (!strcmp(keyword, "cupsColorProfile"))
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
91c84a35
MS
843 if (!profile)
844 {
845 cg->ppd_status = PPD_ALLOC_ERROR;
846
847 goto error;
848 }
849
ef416fc2 850 ppd->profiles = profile;
851 profile += ppd->num_profiles;
852 ppd->num_profiles ++;
853
854 memset(profile, 0, sizeof(ppd_profile_t));
855 strlcpy(profile->resolution, name, sizeof(profile->resolution));
856 strlcpy(profile->media_type, text, sizeof(profile->media_type));
757d2cad 857
b86bc4cf 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);
ef416fc2 869 }
870 else if (!strcmp(keyword, "cupsFilter"))
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
877 if (filter == NULL)
878 {
ef416fc2 879 cg->ppd_status = PPD_ALLOC_ERROR;
880
881 goto error;
882 }
883
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 }
895 else if (!strcmp(keyword, "Throughput"))
896 ppd->throughput = atoi(string);
897 else if (!strcmp(keyword, "Font"))
898 {
899 /*
900 * Add this font to the list of available fonts...
901 */
902
903 if (ppd->num_fonts == 0)
904 tempfonts = (char **)malloc(sizeof(char *));
905 else
906 tempfonts = (char **)realloc(ppd->fonts,
907 sizeof(char *) * (ppd->num_fonts + 1));
908
909 if (tempfonts == NULL)
910 {
911 cg->ppd_status = PPD_ALLOC_ERROR;
912
913 goto error;
914 }
915
916 ppd->fonts = tempfonts;
2e4ff8af 917 ppd->fonts[ppd->num_fonts] = _cupsStrAlloc(name);
ef416fc2 918 ppd->num_fonts ++;
919 }
fa73b229 920 else if (!strncmp(keyword, "ParamCustom", 11))
ef416fc2 921 {
fa73b229 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 */
928
929
930 /*
931 * Get the custom option and parameter...
932 */
ef416fc2 933
fa73b229 934 if ((coption = ppd_get_coption(ppd, keyword + 11)) == NULL)
ef416fc2 935 {
fa73b229 936 cg->ppd_status = PPD_ALLOC_ERROR;
ef416fc2 937
fa73b229 938 goto error;
939 }
ef416fc2 940
fa73b229 941 if ((cparam = ppd_get_cparam(coption, name, text)) == NULL)
942 {
943 cg->ppd_status = PPD_ALLOC_ERROR;
ef416fc2 944
fa73b229 945 goto error;
946 }
947
948 /*
949 * Get the parameter data...
950 */
951
b0f6947b
MS
952 if (!string ||
953 sscanf(string, "%d%32s%64s%64s", &corder, ctype, cminimum,
fa73b229 954 cmaximum) != 4)
955 {
956 cg->ppd_status = PPD_BAD_CUSTOM_PARAM;
957
958 goto error;
959 }
960
961 cparam->order = corder;
ef416fc2 962
fa73b229 963 if (!strcmp(ctype, "curve"))
964 {
965 cparam->type = PPD_CUSTOM_CURVE;
b86bc4cf 966 cparam->minimum.custom_curve = (float)_cupsStrScand(cminimum, NULL, loc);
967 cparam->maximum.custom_curve = (float)_cupsStrScand(cmaximum, NULL, loc);
fa73b229 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;
b86bc4cf 978 cparam->minimum.custom_invcurve = (float)_cupsStrScand(cminimum, NULL, loc);
979 cparam->maximum.custom_invcurve = (float)_cupsStrScand(cmaximum, NULL, loc);
fa73b229 980 }
981 else if (!strcmp(ctype, "passcode"))
982 {
983 cparam->type = PPD_CUSTOM_PASSCODE;
b423cd4c 984 cparam->minimum.custom_passcode = atoi(cminimum);
985 cparam->maximum.custom_passcode = atoi(cmaximum);
fa73b229 986 }
987 else if (!strcmp(ctype, "password"))
988 {
989 cparam->type = PPD_CUSTOM_PASSWORD;
b423cd4c 990 cparam->minimum.custom_password = atoi(cminimum);
991 cparam->maximum.custom_password = atoi(cmaximum);
fa73b229 992 }
993 else if (!strcmp(ctype, "points"))
994 {
995 cparam->type = PPD_CUSTOM_POINTS;
b86bc4cf 996 cparam->minimum.custom_points = (float)_cupsStrScand(cminimum, NULL, loc);
997 cparam->maximum.custom_points = (float)_cupsStrScand(cmaximum, NULL, loc);
fa73b229 998 }
999 else if (!strcmp(ctype, "real"))
1000 {
1001 cparam->type = PPD_CUSTOM_REAL;
b86bc4cf 1002 cparam->minimum.custom_real = (float)_cupsStrScand(cminimum, NULL, loc);
1003 cparam->maximum.custom_real = (float)_cupsStrScand(cmaximum, NULL, loc);
fa73b229 1004 }
1005 else if (!strcmp(ctype, "string"))
1006 {
1007 cparam->type = PPD_CUSTOM_STRING;
b423cd4c 1008 cparam->minimum.custom_string = atoi(cminimum);
1009 cparam->maximum.custom_string = atoi(cmaximum);
fa73b229 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 */
1021
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"))
ef416fc2 1030 {
fa73b229 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"))
757d2cad 1037 {
1038 for (i = 0, sptr = string; i < 4; i ++)
b86bc4cf 1039 ppd->custom_margins[i] = (float)_cupsStrScand(sptr, &sptr, loc);
757d2cad 1040 }
323c5de1 1041 else if (!strncmp(keyword, "Custom", 6) && !strcmp(name, "True") && !option)
fa73b229 1042 {
0a682745
MS
1043 ppd_option_t *custom_option; /* Custom option */
1044
e07d4801 1045 DEBUG_puts("2ppdOpen2: Processing Custom option...");
ef416fc2 1046
fa73b229 1047 /*
1048 * Get the option and custom option...
1049 */
ef416fc2 1050
e1d6a774 1051 if (!ppd_get_coption(ppd, keyword + 6))
ef416fc2 1052 {
fa73b229 1053 cg->ppd_status = PPD_ALLOC_ERROR;
ef416fc2 1054
1055 goto error;
1056 }
1057
0a682745
MS
1058 if (option && !strcasecmp(option->keyword, keyword + 6))
1059 custom_option = option;
1060 else
1061 custom_option = ppdFindOption(ppd, keyword + 6);
fa73b229 1062
0a682745 1063 if (custom_option)
ef416fc2 1064 {
0a682745
MS
1065 /*
1066 * Add the "custom" option...
1067 */
ef416fc2 1068
749b1e90
MS
1069 if ((choice = ppdFindChoice(custom_option, "Custom")) == NULL)
1070 if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL)
1071 {
e07d4801 1072 DEBUG_puts("1ppdOpen2: Unable to add Custom choice!");
ef416fc2 1073
749b1e90 1074 cg->ppd_status = PPD_ALLOC_ERROR;
0a682745 1075
749b1e90
MS
1076 goto error;
1077 }
ef416fc2 1078
0a682745
MS
1079 strlcpy(choice->text, text[0] ? text : _("Custom"),
1080 sizeof(choice->text));
fa73b229 1081
0a682745 1082 choice->code = _cupsStrAlloc(string);
005dd1eb
MS
1083
1084 if (custom_option->section == PPD_ORDER_JCL)
1085 ppd_decode(choice->code);
0a682745 1086 }
fa73b229 1087
1088 /*
1089 * Now process custom page sizes specially...
1090 */
1091
1092 if (!strcmp(keyword, "CustomPageSize"))
1093 {
fa73b229 1094 /*
1095 * Add a "Custom" page size entry...
1096 */
1097
0a682745 1098 ppd->variable_sizes = 1;
323c5de1 1099
0a682745 1100 ppd_add_size(ppd, "Custom");
323c5de1 1101
0a682745
MS
1102 if (option && !strcasecmp(option->keyword, "PageRegion"))
1103 custom_option = option;
1104 else
1105 custom_option = ppdFindOption(ppd, "PageRegion");
09a101d6 1106
0a682745
MS
1107 if (custom_option)
1108 {
749b1e90
MS
1109 if ((choice = ppdFindChoice(custom_option, "Custom")) == NULL)
1110 if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL)
1111 {
e07d4801 1112 DEBUG_puts("1ppdOpen2: Unable to add Custom choice!");
0a682745 1113
749b1e90 1114 cg->ppd_status = PPD_ALLOC_ERROR;
323c5de1 1115
749b1e90
MS
1116 goto error;
1117 }
323c5de1 1118
0a682745
MS
1119 strlcpy(choice->text, text[0] ? text : _("Custom"),
1120 sizeof(choice->text));
323c5de1 1121 }
fa73b229 1122 }
ef416fc2 1123 }
1124 else if (!strcmp(keyword, "LandscapeOrientation"))
1125 {
1126 if (!strcmp(string, "Minus90"))
1127 ppd->landscape = -90;
1128 else if (!strcmp(string, "Plus90"))
1129 ppd->landscape = 90;
1130 }
1f0275e3 1131 else if (!strcmp(keyword, "Emulators") && string)
ef416fc2 1132 {
1133 for (count = 1, sptr = string; sptr != NULL;)
1134 if ((sptr = strchr(sptr, ' ')) != NULL)
1135 {
1136 count ++;
1137 while (*sptr == ' ')
1138 sptr ++;
1139 }
1140
1141 ppd->num_emulations = count;
91c84a35
MS
1142 if ((ppd->emulations = calloc(count, sizeof(ppd_emul_t))) == NULL)
1143 {
1144 cg->ppd_status = PPD_ALLOC_ERROR;
1145
1146 goto error;
1147 }
ef416fc2 1148
1149 for (i = 0, sptr = string; i < count; i ++)
1150 {
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;
1156
1157 *nameptr = '\0';
1158
1159 while (*sptr == ' ')
1160 sptr ++;
1161 }
1162 }
1163 else if (!strncmp(keyword, "StartEmulator_", 14))
1164 {
1165 ppd_decode(string);
1166
1167 for (i = 0; i < ppd->num_emulations; i ++)
1168 if (!strcmp(keyword + 14, ppd->emulations[i].name))
1169 {
1170 ppd->emulations[i].start = string;
1171 string = NULL;
1172 }
1173 }
1174 else if (!strncmp(keyword, "StopEmulator_", 13))
1175 {
1176 ppd_decode(string);
1177
1178 for (i = 0; i < ppd->num_emulations; i ++)
1179 if (!strcmp(keyword + 13, ppd->emulations[i].name))
1180 {
1181 ppd->emulations[i].stop = string;
1182 string = NULL;
1183 }
1184 }
1185 else if (!strcmp(keyword, "JobPatchFile"))
1186 {
ef55b745
MS
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
ef416fc2 1218 if (ppd->patches == NULL)
745129be 1219 ppd->patches = strdup(string);
ef416fc2 1220 else
1221 {
1222 temp = realloc(ppd->patches, strlen(ppd->patches) +
1223 strlen(string) + 1);
1224 if (temp == NULL)
1225 {
1226 cg->ppd_status = PPD_ALLOC_ERROR;
1227
1228 goto error;
1229 }
1230
1231 ppd->patches = temp;
1232
1233 strcpy(ppd->patches + strlen(ppd->patches), string);
1234 }
1235 }
1236 else if (!strcmp(keyword, "OpenUI"))
1237 {
1238 /*
1239 * Don't allow nesting of options...
1240 */
1241
1242 if (option && cg->ppd_conform == PPD_CONFORM_STRICT)
1243 {
1244 cg->ppd_status = PPD_NESTED_OPEN_UI;
1245
1246 goto error;
1247 }
1248
1249 /*
1250 * Add an option record to the current sub-group, group, or file...
1251 */
1252
e07d4801 1253 DEBUG_printf(("2ppdOpen2: name=\"%s\" (%d)", name, (int)strlen(name)));
bc44d920 1254
ef416fc2 1255 if (name[0] == '*')
1256 _cups_strcpy(name, name + 1); /* Eliminate leading asterisk */
1257
1258 for (i = (int)strlen(name) - 1; i > 0 && isspace(name[i] & 255); i --)
1259 name[i] = '\0'; /* Eliminate trailing spaces */
1260
e07d4801 1261 DEBUG_printf(("2ppdOpen2: OpenUI of %s in group %s...", name,
ef416fc2 1262 group ? group->text : "(null)"));
1263
1264 if (subgroup != NULL)
1265 option = ppd_get_option(subgroup, name);
1266 else if (group == NULL)
1267 {
e1d6a774 1268 if ((group = ppd_get_group(ppd, "General", _("General"), cg,
1269 encoding)) == NULL)
ef416fc2 1270 goto error;
1271
e07d4801 1272 DEBUG_printf(("2ppdOpen2: Adding to group %s...", group->text));
ef416fc2 1273 option = ppd_get_option(group, name);
1274 group = NULL;
1275 }
1276 else
1277 option = ppd_get_option(group, name);
1278
1279 if (option == NULL)
1280 {
1281 cg->ppd_status = PPD_ALLOC_ERROR;
1282
1283 goto error;
1284 }
1285
1286 /*
1287 * Now fill in the initial information for the option...
1288 */
1289
1290 if (string && !strcmp(string, "PickMany"))
1291 option->ui = PPD_UI_PICKMANY;
1292 else if (string && !strcmp(string, "Boolean"))
1293 option->ui = PPD_UI_BOOLEAN;
1294 else if (string && !strcmp(string, "PickOne"))
1295 option->ui = PPD_UI_PICKONE;
1296 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1297 {
1298 cg->ppd_status = PPD_BAD_OPEN_UI;
1299
1300 goto error;
1301 }
1302 else
1303 option->ui = PPD_UI_PICKONE;
1304
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 {
e07d4801 1310 DEBUG_printf(("2ppdOpen2: Setting Default%s to %s via attribute...",
ef416fc2 1311 option->keyword, ppd->attrs[j]->value));
1312 strlcpy(option->defchoice, ppd->attrs[j]->value,
1313 sizeof(option->defchoice));
1314 break;
1315 }
1316
1317 if (text[0])
e1d6a774 1318 cupsCharsetToUTF8((cups_utf8_t *)option->text, text,
1319 sizeof(option->text), encoding);
ef416fc2 1320 else
1321 {
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));
1332 else
1333 strlcpy(option->text, name, sizeof(option->text));
1334 }
1335
1336 option->section = PPD_ORDER_ANY;
1337
2e4ff8af 1338 _cupsStrFree(string);
ef416fc2 1339 string = NULL;
0a682745
MS
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 {
749b1e90
MS
1353 if ((choice = ppdFindChoice(option, "Custom")) == NULL)
1354 if ((choice = ppd_add_choice(option, "Custom")) == NULL)
1355 {
e07d4801 1356 DEBUG_puts("1ppdOpen2: Unable to add Custom choice!");
0a682745 1357
749b1e90 1358 cg->ppd_status = PPD_ALLOC_ERROR;
0a682745 1359
749b1e90
MS
1360 goto error;
1361 }
0a682745
MS
1362
1363 strlcpy(choice->text,
1364 custom_attr->text[0] ? custom_attr->text : _("Custom"),
1365 sizeof(choice->text));
426c6a59 1366 choice->code = _cupsStrRetain(custom_attr->value);
0a682745 1367 }
ef416fc2 1368 }
1369 else if (!strcmp(keyword, "JCLOpenUI"))
1370 {
1371 /*
1372 * Don't allow nesting of options...
1373 */
1374
1375 if (option && cg->ppd_conform == PPD_CONFORM_STRICT)
1376 {
1377 cg->ppd_status = PPD_NESTED_OPEN_UI;
1378
1379 goto error;
1380 }
1381
1382 /*
1383 * Find the JCL group, and add if needed...
1384 */
1385
e1d6a774 1386 group = ppd_get_group(ppd, "JCL", _("JCL"), cg, encoding);
ef416fc2 1387
1388 if (group == NULL)
1389 goto error;
1390
1391 /*
1392 * Add an option record to the current JCLs...
1393 */
1394
1395 if (name[0] == '*')
1396 _cups_strcpy(name, name + 1);
1397
1398 option = ppd_get_option(group, name);
1399
1400 if (option == NULL)
1401 {
1402 cg->ppd_status = PPD_ALLOC_ERROR;
1403
1404 goto error;
1405 }
1406
1407 /*
1408 * Now fill in the initial information for the option...
1409 */
1410
1411 if (string && !strcmp(string, "PickMany"))
1412 option->ui = PPD_UI_PICKMANY;
1413 else if (string && !strcmp(string, "Boolean"))
1414 option->ui = PPD_UI_BOOLEAN;
1415 else if (string && !strcmp(string, "PickOne"))
1416 option->ui = PPD_UI_PICKONE;
1417 else
1418 {
1419 cg->ppd_status = PPD_BAD_OPEN_UI;
1420
1421 goto error;
1422 }
1423
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 {
e07d4801 1429 DEBUG_printf(("2ppdOpen2: Setting Default%s to %s via attribute...",
ef416fc2 1430 option->keyword, ppd->attrs[j]->value));
1431 strlcpy(option->defchoice, ppd->attrs[j]->value,
1432 sizeof(option->defchoice));
1433 break;
1434 }
1435
e1d6a774 1436 if (text[0])
1437 cupsCharsetToUTF8((cups_utf8_t *)option->text, text,
1438 sizeof(option->text), encoding);
1439 else
1440 strlcpy(option->text, name, sizeof(option->text));
ef416fc2 1441
1442 option->section = PPD_ORDER_JCL;
1443 group = NULL;
1444
2e4ff8af 1445 _cupsStrFree(string);
ef416fc2 1446 string = NULL;
0a682745
MS
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 {
e07d4801 1459 DEBUG_puts("1ppdOpen2: Unable to add Custom choice!");
0a682745
MS
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));
426c6a59 1469 choice->code = _cupsStrRetain(custom_attr->value);
0a682745 1470 }
ef416fc2 1471 }
1472 else if (!strcmp(keyword, "CloseUI") || !strcmp(keyword, "JCLCloseUI"))
1473 {
1474 option = NULL;
1475
2e4ff8af 1476 _cupsStrFree(string);
ef416fc2 1477 string = NULL;
1478 }
1479 else if (!strcmp(keyword, "OpenGroup"))
1480 {
1481 /*
1482 * Open a new group...
1483 */
1484
1485 if (group != NULL)
1486 {
1487 cg->ppd_status = PPD_NESTED_OPEN_GROUP;
1488
1489 goto error;
1490 }
1491
1492 if (!string)
1493 {
1494 cg->ppd_status = PPD_BAD_OPEN_GROUP;
1495
1496 goto error;
1497 }
1498
1499 /*
1500 * Separate the group name from the text (name/text)...
1501 */
1502
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);
1513
1514 /*
1515 * Find/add the group...
1516 */
1517
e1d6a774 1518 group = ppd_get_group(ppd, string, sptr, cg, encoding);
ef416fc2 1519
1520 if (group == NULL)
1521 goto error;
1522
2e4ff8af 1523 _cupsStrFree(string);
ef416fc2 1524 string = NULL;
1525 }
1526 else if (!strcmp(keyword, "CloseGroup"))
1527 {
1528 group = NULL;
1529
2e4ff8af 1530 _cupsStrFree(string);
ef416fc2 1531 string = NULL;
1532 }
0a682745 1533 else if (!strcmp(keyword, "OrderDependency"))
ef416fc2 1534 {
b86bc4cf 1535 order = (float)_cupsStrScand(string, &sptr, loc);
757d2cad 1536
1537 if (!sptr || sscanf(sptr, "%40s%40s", name, keyword) != 2)
ef416fc2 1538 {
1539 cg->ppd_status = PPD_BAD_ORDER_DEPENDENCY;
1540
1541 goto error;
1542 }
1543
1544 if (keyword[0] == '*')
1545 _cups_strcpy(keyword, keyword + 1);
1546
1547 if (!strcmp(name, "ExitServer"))
1548 section = PPD_ORDER_EXIT;
1549 else if (!strcmp(name, "Prolog"))
1550 section = PPD_ORDER_PROLOG;
1551 else if (!strcmp(name, "DocumentSetup"))
1552 section = PPD_ORDER_DOCUMENT;
1553 else if (!strcmp(name, "PageSetup"))
1554 section = PPD_ORDER_PAGE;
1555 else if (!strcmp(name, "JCLSetup"))
1556 section = PPD_ORDER_JCL;
1557 else
1558 section = PPD_ORDER_ANY;
1559
1560 if (option == NULL)
1561 {
1562 ppd_group_t *gtemp;
1563
1564
1565 /*
1566 * Only valid for Non-UI options...
1567 */
1568
1569 for (i = ppd->num_groups, gtemp = ppd->groups; i > 0; i --, gtemp ++)
1570 if (gtemp->text[0] == '\0')
1571 break;
1572
1573 if (i > 0)
1574 for (i = 0; i < gtemp->num_options; i ++)
1575 if (!strcmp(keyword, gtemp->options[i].keyword))
1576 {
1577 gtemp->options[i].section = section;
1578 gtemp->options[i].order = order;
1579 break;
1580 }
1581 }
1582 else
1583 {
1584 option->section = section;
1585 option->order = order;
1586 }
1587
2e4ff8af 1588 _cupsStrFree(string);
ef416fc2 1589 string = NULL;
1590 }
1591 else if (!strncmp(keyword, "Default", 7))
1592 {
1593 if (string == NULL)
1594 continue;
1595
1596 /*
1597 * Drop UI text, if any, from value...
1598 */
1599
1600 if (strchr(string, '/') != NULL)
1601 *strchr(string, '/') = '\0';
1602
1603 /*
1604 * Assign the default value as appropriate...
1605 */
1606
1607 if (!strcmp(keyword, "DefaultColorSpace"))
1608 {
1609 /*
1610 * Set default colorspace...
1611 */
1612
1613 if (!strcmp(string, "CMY"))
1614 ppd->colorspace = PPD_CS_CMY;
1615 else if (!strcmp(string, "CMYK"))
1616 ppd->colorspace = PPD_CS_CMYK;
1617 else if (!strcmp(string, "RGB"))
1618 ppd->colorspace = PPD_CS_RGB;
1619 else if (!strcmp(string, "RGBK"))
1620 ppd->colorspace = PPD_CS_RGBK;
1621 else if (!strcmp(string, "N"))
1622 ppd->colorspace = PPD_CS_N;
1623 else
1624 ppd->colorspace = PPD_CS_GRAY;
1625 }
1626 else if (option && !strcmp(keyword + 7, option->keyword))
1627 {
1628 /*
1629 * Set the default as part of the current option...
1630 */
1631
e07d4801 1632 DEBUG_printf(("2ppdOpen2: Setting %s to %s...", keyword, string));
ef416fc2 1633
1634 strlcpy(option->defchoice, string, sizeof(option->defchoice));
1635
e07d4801 1636 DEBUG_printf(("2ppdOpen2: %s is now %s...", keyword, option->defchoice));
ef416fc2 1637 }
1638 else
1639 {
1640 /*
1641 * Lookup option and set if it has been defined...
1642 */
1643
1644 ppd_option_t *toption; /* Temporary option */
1645
1646
1647 if ((toption = ppdFindOption(ppd, keyword + 7)) != NULL)
1648 {
e07d4801 1649 DEBUG_printf(("2ppdOpen2: Setting %s to %s...", keyword, string));
ef416fc2 1650 strlcpy(toption->defchoice, string, sizeof(toption->defchoice));
1651 }
1652 }
1653 }
1654 else if (!strcmp(keyword, "UIConstraints") ||
1655 !strcmp(keyword, "NonUIConstraints"))
1656 {
b0f6947b
MS
1657 if (!string)
1658 {
1659 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1660 goto error;
1661 }
1662
ef416fc2 1663 if (ppd->num_consts == 0)
323c5de1 1664 constraint = calloc(2, sizeof(ppd_const_t));
ef416fc2 1665 else
1666 constraint = realloc(ppd->consts,
323c5de1 1667 (ppd->num_consts + 2) * sizeof(ppd_const_t));
ef416fc2 1668
1669 if (constraint == NULL)
1670 {
1671 cg->ppd_status = PPD_ALLOC_ERROR;
1672
1673 goto error;
1674 }
1675
1676 ppd->consts = constraint;
1677 constraint += ppd->num_consts;
1678 ppd->num_consts ++;
1679
1680 switch (sscanf(string, "%40s%40s%40s%40s", constraint->option1,
1681 constraint->choice1, constraint->option2,
1682 constraint->choice2))
1683 {
1684 case 0 : /* Error */
1685 case 1 : /* Error */
1686 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1687 goto error;
1688
1689 case 2 : /* Two options... */
2abf387c 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
ef416fc2 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
1707 if (constraint->option1[0] == '*')
1708 _cups_strcpy(constraint->option1, constraint->option1 + 1);
2abf387c 1709 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1710 {
1711 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1712 goto error;
1713 }
ef416fc2 1714
1715 if (constraint->choice1[0] == '*')
1716 _cups_strcpy(constraint->option2, constraint->choice1 + 1);
2abf387c 1717 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1718 {
1719 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1720 goto error;
1721 }
ef416fc2 1722
1723 constraint->choice1[0] = '\0';
1724 constraint->choice2[0] = '\0';
1725 break;
1726
1727 case 3 : /* Two options, one choice... */
2abf387c 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
ef416fc2 1741 /*
1742 * The following _cups_strcpy's are safe, as optionN and
1743 * choiceN are all the same size (size defined by PPD spec...)
1744 */
1745
1746 if (constraint->option1[0] == '*')
1747 _cups_strcpy(constraint->option1, constraint->option1 + 1);
2abf387c 1748 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1749 {
1750 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1751 goto error;
1752 }
ef416fc2 1753
1754 if (constraint->choice1[0] == '*')
1755 {
2abf387c 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
ef416fc2 1763 _cups_strcpy(constraint->choice2, constraint->option2);
1764 _cups_strcpy(constraint->option2, constraint->choice1 + 1);
1765 constraint->choice1[0] = '\0';
1766 }
1767 else
1768 {
1769 if (constraint->option2[0] == '*')
1770 _cups_strcpy(constraint->option2, constraint->option2 + 1);
2abf387c 1771 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1772 {
1773 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1774 goto error;
1775 }
ef416fc2 1776
1777 constraint->choice2[0] = '\0';
1778 }
1779 break;
1780
1781 case 4 : /* Two options, two choices... */
2abf387c 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
ef416fc2 1796 if (constraint->option1[0] == '*')
1797 _cups_strcpy(constraint->option1, constraint->option1 + 1);
2abf387c 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 }
ef416fc2 1810
1811 if (constraint->option2[0] == '*')
1812 _cups_strcpy(constraint->option2, constraint->option2 + 1);
2abf387c 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 }
ef416fc2 1825 break;
1826 }
1827
2abf387c 1828 /*
1829 * Don't add this one as an attribute...
1830 */
1831
2e4ff8af 1832 _cupsStrFree(string);
ef416fc2 1833 string = NULL;
1834 }
1835 else if (!strcmp(keyword, "PaperDimension"))
1836 {
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
1846 cg->ppd_status = PPD_ALLOC_ERROR;
1847
1848 goto error;
1849 }
1850
b86bc4cf 1851 size->width = (float)_cupsStrScand(string, &sptr, loc);
1852 size->length = (float)_cupsStrScand(sptr, NULL, loc);
ef416fc2 1853
2e4ff8af 1854 _cupsStrFree(string);
ef416fc2 1855 string = NULL;
1856 }
1857 else if (!strcmp(keyword, "ImageableArea"))
1858 {
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
1868 cg->ppd_status = PPD_ALLOC_ERROR;
1869
1870 goto error;
1871 }
1872
b86bc4cf 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);
ef416fc2 1877
2e4ff8af 1878 _cupsStrFree(string);
ef416fc2 1879 string = NULL;
1880 }
1881 else if (option != NULL &&
1882 (mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) ==
1883 (PPD_KEYWORD | PPD_OPTION | PPD_STRING) &&
1884 !strcmp(keyword, option->keyword))
1885 {
e07d4801 1886 DEBUG_printf(("2ppdOpen2: group=%p, subgroup=%p", group, subgroup));
ef416fc2 1887
1888 if (!strcmp(keyword, "PageSize"))
1889 {
1890 /*
1891 * Add a page size...
1892 */
1893
1894 if (ppdPageSize(ppd, name) == NULL)
1895 ppd_add_size(ppd, name);
1896 }
1897
1898 /*
1899 * Add the option choice...
1900 */
1901
91c84a35
MS
1902 if ((choice = ppd_add_choice(option, name)) == NULL)
1903 {
1904 cg->ppd_status = PPD_ALLOC_ERROR;
1905
1906 goto error;
1907 }
ef416fc2 1908
e1d6a774 1909 if (text[0])
1910 cupsCharsetToUTF8((cups_utf8_t *)choice->text, text,
1911 sizeof(choice->text), encoding);
ef416fc2 1912 else if (!strcmp(name, "True"))
1913 strcpy(choice->text, _("Yes"));
1914 else if (!strcmp(name, "False"))
1915 strcpy(choice->text, _("No"));
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;
1923 string = NULL; /* Don't add as an attribute below */
1924 }
ef416fc2 1925
1926 /*
1927 * Add remaining lines with keywords and string values as attributes...
1928 */
1929
1930 if (string &&
1931 (mask & (PPD_KEYWORD | PPD_STRING)) == (PPD_KEYWORD | PPD_STRING))
1932 ppd_add_attr(ppd, keyword, name, text, string);
1933 else
2e4ff8af 1934 _cupsStrFree(string);
ef416fc2 1935 }
1936
9f5eb9be 1937 ppd_free(line.buffer);
2e4ff8af 1938
ef416fc2 1939 /*
1940 * Reset language preferences...
1941 */
1942
1943 cupsLangFree(language);
1944
ef416fc2 1945#ifdef DEBUG
bc44d920 1946 if (!cupsFileEOF(fp))
e07d4801 1947 DEBUG_printf(("1ppdOpen2: Premature EOF at %lu...\n",
ae71f5de 1948 (unsigned long)cupsFileTell(fp)));
ef416fc2 1949#endif /* DEBUG */
1950
1951 if (cg->ppd_status != PPD_OK)
1952 {
1953 /*
1954 * Had an error reading the PPD file, cannot continue!
1955 */
1956
1957 ppdClose(ppd);
1958
1959 return (NULL);
1960 }
1961
ef416fc2 1962 /*
fa73b229 1963 * Create the sorted options array and set the option back-pointer for
1964 * each choice and custom option...
ef416fc2 1965 */
1966
b94498cf 1967 ppd->options = cupsArrayNew2((cups_array_func_t)ppd_compare_options, NULL,
1968 (cups_ahash_func_t)ppd_hash_option,
1969 PPD_HASHSIZE);
ef416fc2 1970
1971 for (i = ppd->num_groups, group = ppd->groups;
1972 i > 0;
1973 i --, group ++)
1974 {
ef416fc2 1975 for (j = group->num_options, option = group->options;
1976 j > 0;
1977 j --, option ++)
1978 {
fa73b229 1979 ppd_coption_t *coption; /* Custom option */
ef416fc2 1980
ef416fc2 1981
fa73b229 1982 cupsArrayAdd(ppd->options, option);
ef416fc2 1983
fa73b229 1984 for (k = 0; k < option->num_choices; k ++)
1985 option->choices[k].option = option;
ef416fc2 1986
fa73b229 1987 if ((coption = ppdFindCustomOption(ppd, option->keyword)) != NULL)
1988 coption->option = option;
1989 }
1990 }
ef416fc2 1991
b94498cf 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
ef416fc2 1998 /*
1999 * Return the PPD file structure...
2000 */
2001
2002 return (ppd);
2003
2004 /*
2005 * Common exit point for errors to save code size...
2006 */
2007
2008 error:
2009
2e4ff8af 2010 _cupsStrFree(string);
9f5eb9be 2011 ppd_free(line.buffer);
ef416fc2 2012
2013 ppdClose(ppd);
2014
2015 cupsLangFree(language);
2016
ef416fc2 2017 return (NULL);
2018}
2019
2020
2021/*
2022 * 'ppdOpenFd()' - Read a PPD file into memory.
2023 */
2024
5a738aea 2025ppd_file_t * /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
ef416fc2 2026ppdOpenFd(int fd) /* I - File to read from */
2027{
fa73b229 2028 cups_file_t *fp; /* CUPS file pointer */
ef416fc2 2029 ppd_file_t *ppd; /* PPD file record */
2030 _cups_globals_t *cg = _cupsGlobals();
2031 /* Global data */
2032
2033
2034 /*
2035 * Set the line number to 0...
2036 */
2037
2038 cg->ppd_line = 0;
2039
2040 /*
2041 * Range check input...
2042 */
2043
2044 if (fd < 0)
2045 {
2046 cg->ppd_status = PPD_NULL_FILE;
2047
2048 return (NULL);
2049 }
2050
2051 /*
2052 * Try to open the file and parse it...
2053 */
2054
fa73b229 2055 if ((fp = cupsFileOpenFd(fd, "r")) != NULL)
ef416fc2 2056 {
fa73b229 2057 ppd = ppdOpen2(fp);
ef416fc2 2058
fa73b229 2059 cupsFileClose(fp);
ef416fc2 2060 }
2061 else
2062 {
2063 cg->ppd_status = PPD_FILE_OPEN_ERROR;
fa73b229 2064 ppd = NULL;
ef416fc2 2065 }
2066
2067 return (ppd);
2068}
2069
2070
2071/*
2072 * 'ppdOpenFile()' - Read a PPD file into memory.
2073 */
2074
5a738aea 2075ppd_file_t * /* O - PPD file record or @code NULL@ if the PPD file could not be opened. */
ef416fc2 2076ppdOpenFile(const char *filename) /* I - File to read from */
2077{
2078 cups_file_t *fp; /* File pointer */
2079 ppd_file_t *ppd; /* PPD file record */
2080 _cups_globals_t *cg = _cupsGlobals();
2081 /* Global data */
2082
2083
2084 /*
2085 * Set the line number to 0...
2086 */
2087
2088 cg->ppd_line = 0;
2089
2090 /*
2091 * Range check input...
2092 */
2093
2094 if (filename == NULL)
2095 {
2096 cg->ppd_status = PPD_NULL_FILE;
2097
2098 return (NULL);
2099 }
2100
2101 /*
2102 * Try to open the file and parse it...
2103 */
2104
2105 if ((fp = cupsFileOpen(filename, "r")) != NULL)
2106 {
2107 ppd = ppdOpen2(fp);
2108
2109 cupsFileClose(fp);
2110 }
2111 else
2112 {
2113 cg->ppd_status = PPD_FILE_OPEN_ERROR;
2114 ppd = NULL;
2115 }
2116
2117 return (ppd);
2118}
2119
2120
2121/*
2122 * 'ppdSetConformance()' - Set the conformance level for PPD files.
2123 *
426c6a59 2124 * @since CUPS 1.1.20/Mac OS X 10.4@
ef416fc2 2125 */
2126
2127void
2128ppdSetConformance(ppd_conform_t c) /* I - Conformance level */
2129{
2130 _cups_globals_t *cg = _cupsGlobals();
2131 /* Global data */
2132
2133
2134 cg->ppd_conform = c;
2135}
2136
2137
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 */
2146 const char *text, /* I - Text string, if any */
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
bd7854cb 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
ef416fc2 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));
2196 strlcpy(temp->text, text, sizeof(temp->text));
2197 temp->value = (char *)value;
2198
bd7854cb 2199 /*
2200 * Add the attribute to the sorted array...
2201 */
2202
2203 cupsArrayAdd(ppd->sorted_attrs, temp);
2204
ef416fc2 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
bd7854cb 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{
6e8b116d 2282 return (strcasecmp(a->name, b->name));
bd7854cb 2283}
2284
2285
b94498cf 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{
355e94dc 2294 return (strcmp(a->option->keyword, b->option->keyword));
b94498cf 2295}
2296
2297
ef416fc2 2298/*
fa73b229 2299 * 'ppd_compare_coptions()' - Compare two custom options.
ef416fc2 2300 */
2301
2302static int /* O - Result of comparison */
fa73b229 2303ppd_compare_coptions(ppd_coption_t *a, /* I - First option */
2304 ppd_coption_t *b) /* I - Second option */
ef416fc2 2305{
fa73b229 2306 return (strcasecmp(a->keyword, b->keyword));
2307}
2308
2309
2310/*
2311 * 'ppd_compare_cparams()' - Compare two custom parameters.
2312 */
2313
2314static int /* O - Result of comparison */
2315ppd_compare_cparams(ppd_cparam_t *a, /* I - First parameter */
2316 ppd_cparam_t *b) /* I - Second parameter */
2317{
2318 return (strcasecmp(a->name, b->name));
ef416fc2 2319}
2320
2321
2322/*
2323 * 'ppd_compare_options()' - Compare two options.
2324 */
2325
2326static int /* O - Result of comparison */
fa73b229 2327ppd_compare_options(ppd_option_t *a, /* I - First option */
2328 ppd_option_t *b) /* I - Second option */
ef416fc2 2329{
fa73b229 2330 return (strcasecmp(a->keyword, b->keyword));
ef416fc2 2331}
ef416fc2 2332
2333
2334/*
2335 * 'ppd_decode()' - Decode a string value...
2336 */
2337
2338static int /* O - Length of decoded string */
2339ppd_decode(char *string) /* I - String to decode */
2340{
2341 char *inptr, /* Input pointer */
2342 *outptr; /* Output pointer */
2343
2344
2345 inptr = string;
2346 outptr = string;
2347
2348 while (*inptr != '\0')
2349 if (*inptr == '<' && isxdigit(inptr[1] & 255))
2350 {
2351 /*
2352 * Convert hex to 8-bit values...
2353 */
2354
2355 inptr ++;
2356 while (isxdigit(*inptr & 255))
2357 {
2358 if (isalpha(*inptr))
2359 *outptr = (tolower(*inptr) - 'a' + 10) << 4;
2360 else
2361 *outptr = (*inptr - '0') << 4;
2362
2363 inptr ++;
2364
2365 if (!isxdigit(*inptr & 255))
2366 break;
2367
2368 if (isalpha(*inptr))
2369 *outptr |= tolower(*inptr) - 'a' + 10;
2370 else
2371 *outptr |= *inptr - '0';
2372
2373 inptr ++;
2374 outptr ++;
2375 }
2376
2377 while (*inptr != '>' && *inptr != '\0')
2378 inptr ++;
2379 while (*inptr == '>')
2380 inptr ++;
2381 }
2382 else
2383 *outptr++ = *inptr++;
2384
2385 *outptr = '\0';
2386
2387 return ((int)(outptr - string));
2388}
2389
2390
2391/*
2392 * 'ppd_free_group()' - Free a single UI group.
2393 */
2394
2395static void
2396ppd_free_group(ppd_group_t *group) /* I - Group to free */
2397{
2398 int i; /* Looping var */
2399 ppd_option_t *option; /* Current option */
2400 ppd_group_t *subgroup; /* Current sub-group */
2401
2402
2403 if (group->num_options > 0)
2404 {
2405 for (i = group->num_options, option = group->options;
2406 i > 0;
2407 i --, option ++)
2408 ppd_free_option(option);
2409
2410 ppd_free(group->options);
2411 }
2412
2413 if (group->num_subgroups > 0)
2414 {
2415 for (i = group->num_subgroups, subgroup = group->subgroups;
2416 i > 0;
2417 i --, subgroup ++)
2418 ppd_free_group(subgroup);
2419
2420 ppd_free(group->subgroups);
2421 }
2422}
2423
2424
2425/*
2426 * 'ppd_free_option()' - Free a single option.
2427 */
2428
2429static void
2430ppd_free_option(ppd_option_t *option) /* I - Option to free */
2431{
2432 int i; /* Looping var */
2433 ppd_choice_t *choice; /* Current choice */
2434
2435
2436 if (option->num_choices > 0)
2437 {
2438 for (i = option->num_choices, choice = option->choices;
2439 i > 0;
2440 i --, choice ++)
2441 {
2e4ff8af 2442 _cupsStrFree(choice->code);
ef416fc2 2443 }
2444
2445 ppd_free(option->choices);
2446 }
2447}
2448
2449
ef416fc2 2450/*
fa73b229 2451 * 'ppd_get_coption()' - Get a custom option record.
ef416fc2 2452 */
2453
fa73b229 2454static ppd_coption_t * /* O - Custom option... */
2455ppd_get_coption(ppd_file_t *ppd, /* I - PPD file */
2456 const char *name) /* I - Name of option */
ef416fc2 2457{
fa73b229 2458 ppd_coption_t *copt; /* New custom option */
ef416fc2 2459
2460
2461 /*
2462 * See if the option already exists...
2463 */
2464
fa73b229 2465 if ((copt = ppdFindCustomOption(ppd, name)) != NULL)
2466 return (copt);
ef416fc2 2467
2468 /*
fa73b229 2469 * Not found, so create the custom option record...
ef416fc2 2470 */
2471
fa73b229 2472 if ((copt = calloc(1, sizeof(ppd_coption_t))) == NULL)
ef416fc2 2473 return (NULL);
2474
fa73b229 2475 strlcpy(copt->keyword, name, sizeof(copt->keyword));
ef416fc2 2476
fa73b229 2477 copt->params = cupsArrayNew((cups_array_func_t)ppd_compare_cparams, NULL);
ef416fc2 2478
fa73b229 2479 cupsArrayAdd(ppd->coptions, copt);
ef416fc2 2480
2481 /*
2482 * Return the new record...
2483 */
2484
fa73b229 2485 return (copt);
ef416fc2 2486}
2487
2488
2489/*
fa73b229 2490 * 'ppd_get_cparam()' - Get a custom parameter record.
ef416fc2 2491 */
2492
fa73b229 2493static ppd_cparam_t * /* O - Extended option... */
2494ppd_get_cparam(ppd_coption_t *opt, /* I - PPD file */
2495 const char *param, /* I - Name of parameter */
2496 const char *text) /* I - Human-readable text */
ef416fc2 2497{
fa73b229 2498 ppd_cparam_t *cparam; /* New custom parameter */
ef416fc2 2499
2500
2501 /*
2502 * See if the parameter already exists...
2503 */
2504
fa73b229 2505 if ((cparam = ppdFindCustomParam(opt, param)) != NULL)
2506 return (cparam);
ef416fc2 2507
2508 /*
fa73b229 2509 * Not found, so create the custom parameter record...
ef416fc2 2510 */
2511
fa73b229 2512 if ((cparam = calloc(1, sizeof(ppd_cparam_t))) == NULL)
ef416fc2 2513 return (NULL);
2514
fa73b229 2515 strlcpy(cparam->name, param, sizeof(cparam->name));
b86bc4cf 2516 strlcpy(cparam->text, text[0] ? text : param, sizeof(cparam->text));
ef416fc2 2517
2518 /*
fa73b229 2519 * Add this record to the array...
ef416fc2 2520 */
2521
fa73b229 2522 cupsArrayAdd(opt->params, cparam);
ef416fc2 2523
2524 /*
2525 * Return the new record...
2526 */
2527
fa73b229 2528 return (cparam);
ef416fc2 2529}
ef416fc2 2530
2531
2532/*
2533 * 'ppd_get_group()' - Find or create the named group as needed.
2534 */
2535
2536static ppd_group_t * /* O - Named group */
e1d6a774 2537ppd_get_group(ppd_file_t *ppd, /* I - PPD file */
2538 const char *name, /* I - Name of group */
2539 const char *text, /* I - Text for group */
2540 _cups_globals_t *cg, /* I - Global data */
2541 cups_encoding_t encoding) /* I - Encoding of text */
ef416fc2 2542{
2543 int i; /* Looping var */
2544 ppd_group_t *group; /* Group */
2545
2546
e07d4801 2547 DEBUG_printf(("7ppd_get_group(ppd=%p, name=\"%s\", text=\"%s\", cg=%p)",
ef416fc2 2548 ppd, name, text, cg));
2549
2550 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
2551 if (!strcmp(group->name, name))
2552 break;
2553
2554 if (i == 0)
2555 {
e07d4801 2556 DEBUG_printf(("8ppd_get_group: Adding group %s...", name));
ef416fc2 2557
2558 if (cg->ppd_conform == PPD_CONFORM_STRICT && strlen(text) >= sizeof(group->text))
2559 {
2560 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
2561
2562 return (NULL);
2563 }
2564
2565 if (ppd->num_groups == 0)
2566 group = malloc(sizeof(ppd_group_t));
2567 else
2568 group = realloc(ppd->groups,
2569 (ppd->num_groups + 1) * sizeof(ppd_group_t));
2570
2571 if (group == NULL)
2572 {
2573 cg->ppd_status = PPD_ALLOC_ERROR;
2574
2575 return (NULL);
2576 }
2577
2578 ppd->groups = group;
2579 group += ppd->num_groups;
2580 ppd->num_groups ++;
2581
2582 memset(group, 0, sizeof(ppd_group_t));
2583 strlcpy(group->name, name, sizeof(group->name));
e1d6a774 2584
2585 cupsCharsetToUTF8((cups_utf8_t *)group->text, text,
2586 sizeof(group->text), encoding);
ef416fc2 2587 }
2588
2589 return (group);
2590}
2591
2592
2593/*
2594 * 'ppd_get_option()' - Find or create the named option as needed.
2595 */
2596
2597static ppd_option_t * /* O - Named option */
2598ppd_get_option(ppd_group_t *group, /* I - Group */
2599 const char *name) /* I - Name of option */
2600{
2601 int i; /* Looping var */
2602 ppd_option_t *option; /* Option */
2603
2604
e07d4801 2605 DEBUG_printf(("7ppd_get_option(group=%p(\"%s\"), name=\"%s\")",
ef416fc2 2606 group, group->name, name));
2607
2608 for (i = group->num_options, option = group->options; i > 0; i --, option ++)
2609 if (!strcmp(option->keyword, name))
2610 break;
2611
2612 if (i == 0)
2613 {
2614 if (group->num_options == 0)
2615 option = malloc(sizeof(ppd_option_t));
2616 else
2617 option = realloc(group->options,
2618 (group->num_options + 1) * sizeof(ppd_option_t));
2619
2620 if (option == NULL)
2621 return (NULL);
2622
2623 group->options = option;
2624 option += group->num_options;
2625 group->num_options ++;
2626
2627 memset(option, 0, sizeof(ppd_option_t));
2628 strlcpy(option->keyword, name, sizeof(option->keyword));
2629 }
2630
2631 return (option);
2632}
2633
2634
b94498cf 2635/*
2636 * 'ppd_hash_option()' - Generate a hash of the option name...
2637 */
2638
2639static int /* O - Hash index */
2640ppd_hash_option(ppd_option_t *option) /* I - Option */
2641{
2642 int hash = 0; /* Hash index */
2643 const char *k; /* Pointer into keyword */
2644
2645
2646 for (hash = option->keyword[0], k = option->keyword + 1; *k;)
2647 hash = 33 * hash + *k++;
2648
2649 return (hash & 511);
2650}
2651
2652
ef416fc2 2653/*
2654 * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
2655 * necessary.
2656 */
2657
2658static int /* O - Bitmask of fields read */
2659ppd_read(cups_file_t *fp, /* I - File to read from */
2e4ff8af 2660 _ppd_line_t *line, /* I - Line buffer */
ef416fc2 2661 char *keyword, /* O - Keyword from line */
2662 char *option, /* O - Option from line */
2663 char *text, /* O - Human-readable text from line */
2664 char **string, /* O - Code/string data */
2665 int ignoreblank, /* I - Ignore blank lines? */
2666 _cups_globals_t *cg) /* I - Global data */
2667{
2668 int ch, /* Character from file */
2669 col, /* Column in line */
2670 colon, /* Colon seen? */
2671 endquote, /* Waiting for an end quote */
2672 mask, /* Mask to be returned */
2673 startline, /* Start line */
2674 textlen; /* Length of text */
2675 char *keyptr, /* Keyword pointer */
2676 *optptr, /* Option pointer */
2677 *textptr, /* Text pointer */
2678 *strptr, /* Pointer into string */
2e4ff8af 2679 *lineptr; /* Current position in line buffer */
ef416fc2 2680
ef416fc2 2681
2682 /*
2683 * Now loop until we have a valid line...
2684 */
2685
2686 *string = NULL;
2687 col = 0;
2688 startline = cg->ppd_line + 1;
ef416fc2 2689
2e4ff8af
MS
2690 if (!line->buffer)
2691 {
2692 line->bufsize = 1024;
2693 line->buffer = malloc(1024);
2694
2695 if (!line->buffer)
2696 return (0);
2697 }
ef416fc2 2698
2699 do
2700 {
2701 /*
2702 * Read the line...
2703 */
2704
2e4ff8af 2705 lineptr = line->buffer;
ef416fc2 2706 endquote = 0;
2707 colon = 0;
2708
2709 while ((ch = cupsFileGetChar(fp)) != EOF)
2710 {
2e4ff8af 2711 if (lineptr >= (line->buffer + line->bufsize - 1))
ef416fc2 2712 {
2713 /*
2714 * Expand the line buffer...
2715 */
2716
2717 char *temp; /* Temporary line pointer */
2718
2719
2e4ff8af
MS
2720 line->bufsize += 1024;
2721 if (line->bufsize > 262144)
ef416fc2 2722 {
2723 /*
2724 * Don't allow lines longer than 256k!
2725 */
2726
2727 cg->ppd_line = startline;
2728 cg->ppd_status = PPD_LINE_TOO_LONG;
2729
ef416fc2 2730 return (0);
2731 }
2732
2e4ff8af 2733 temp = realloc(line->buffer, line->bufsize);
ef416fc2 2734 if (!temp)
2735 {
2736 cg->ppd_line = startline;
2737 cg->ppd_status = PPD_LINE_TOO_LONG;
2738
ef416fc2 2739 return (0);
2740 }
2741
2e4ff8af
MS
2742 lineptr = temp + (lineptr - line->buffer);
2743 line->buffer = temp;
ef416fc2 2744 }
2745
2746 if (ch == '\r' || ch == '\n')
2747 {
2748 /*
2749 * Line feed or carriage return...
2750 */
2751
2752 cg->ppd_line ++;
2753 col = 0;
2754
2755 if (ch == '\r')
2756 {
2757 /*
2758 * Check for a trailing line feed...
2759 */
2760
2761 if ((ch = cupsFilePeekChar(fp)) == EOF)
fa73b229 2762 {
2763 ch = '\n';
ef416fc2 2764 break;
fa73b229 2765 }
2766
ef416fc2 2767 if (ch == 0x0a)
2768 cupsFileGetChar(fp);
2769 }
2770
2e4ff8af 2771 if (lineptr == line->buffer && ignoreblank)
ef416fc2 2772 continue; /* Skip blank lines */
2773
2774 ch = '\n';
2775
2776 if (!endquote) /* Continue for multi-line text */
2777 break;
2778
2779 *lineptr++ = '\n';
2780 }
2781 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
2782 {
2783 /*
2784 * Other control characters...
2785 */
2786
2787 cg->ppd_line = startline;
2788 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
2789
ef416fc2 2790 return (0);
2791 }
2792 else if (ch != 0x1a)
2793 {
2794 /*
2795 * Any other character...
2796 */
2797
2798 *lineptr++ = ch;
2799 col ++;
2800
2801 if (col > (PPD_MAX_LINE - 1))
2802 {
2803 /*
2804 * Line is too long...
2805 */
2806
2807 cg->ppd_line = startline;
2808 cg->ppd_status = PPD_LINE_TOO_LONG;
2809
ef416fc2 2810 return (0);
2811 }
2812
2e4ff8af 2813 if (ch == ':' && strncmp(line->buffer, "*%", 2) != 0)
ef416fc2 2814 colon = 1;
2815
2816 if (ch == '\"' && colon)
2817 endquote = !endquote;
2818 }
2819 }
2820
2821 if (endquote)
2822 {
2823 /*
2824 * Didn't finish this quoted string...
2825 */
2826
2827 while ((ch = cupsFileGetChar(fp)) != EOF)
2828 if (ch == '\"')
2829 break;
2830 else if (ch == '\r' || ch == '\n')
2831 {
2832 cg->ppd_line ++;
2833 col = 0;
2834
2835 if (ch == '\r')
2836 {
2837 /*
2838 * Check for a trailing line feed...
2839 */
2840
2841 if ((ch = cupsFilePeekChar(fp)) == EOF)
2842 break;
2843 if (ch == 0x0a)
2844 cupsFileGetChar(fp);
2845 }
ef416fc2 2846 }
2847 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
2848 {
2849 /*
2850 * Other control characters...
2851 */
2852
2853 cg->ppd_line = startline;
2854 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
2855
ef416fc2 2856 return (0);
2857 }
2858 else if (ch != 0x1a)
2859 {
2860 col ++;
2861
2862 if (col > (PPD_MAX_LINE - 1))
2863 {
2864 /*
2865 * Line is too long...
2866 */
2867
2868 cg->ppd_line = startline;
2869 cg->ppd_status = PPD_LINE_TOO_LONG;
2870
ef416fc2 2871 return (0);
2872 }
2873 }
2874 }
2875
2876 if (ch != '\n')
2877 {
2878 /*
2879 * Didn't finish this line...
2880 */
2881
2882 while ((ch = cupsFileGetChar(fp)) != EOF)
2883 if (ch == '\r' || ch == '\n')
2884 {
2885 /*
2886 * Line feed or carriage return...
2887 */
2888
2889 cg->ppd_line ++;
2890 col = 0;
2891
2892 if (ch == '\r')
2893 {
2894 /*
2895 * Check for a trailing line feed...
2896 */
2897
2898 if ((ch = cupsFilePeekChar(fp)) == EOF)
2899 break;
2900 if (ch == 0x0a)
2901 cupsFileGetChar(fp);
2902 }
2903
2904 break;
2905 }
2906 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
2907 {
2908 /*
2909 * Other control characters...
2910 */
2911
2912 cg->ppd_line = startline;
2913 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
2914
ef416fc2 2915 return (0);
2916 }
2917 else if (ch != 0x1a)
2918 {
2919 col ++;
2920
2921 if (col > (PPD_MAX_LINE - 1))
2922 {
2923 /*
2924 * Line is too long...
2925 */
2926
2927 cg->ppd_line = startline;
2928 cg->ppd_status = PPD_LINE_TOO_LONG;
2929
ef416fc2 2930 return (0);
2931 }
2932 }
2933 }
2934
2e4ff8af 2935 if (lineptr > line->buffer && lineptr[-1] == '\n')
ef416fc2 2936 lineptr --;
2937
2938 *lineptr = '\0';
2939
e07d4801 2940 DEBUG_printf(("9ppd_read: LINE=\"%s\"", line->buffer));
ef416fc2 2941
bd7854cb 2942 /*
2943 * The dynamically created PPDs for older style Mac OS X
2944 * drivers include a large blob of data inserted as comments
2945 * at the end of the file. As an optimization we can stop
2946 * reading the PPD when we get to the start of this data.
2947 */
2948
2e4ff8af 2949 if (!strcmp(line->buffer, "*%APLWORKSET START"))
bd7854cb 2950 return (0);
bd7854cb 2951
2e4ff8af 2952 if (ch == EOF && lineptr == line->buffer)
ef416fc2 2953 return (0);
ef416fc2 2954
2955 /*
2956 * Now parse it...
2957 */
2958
2959 mask = 0;
2e4ff8af 2960 lineptr = line->buffer + 1;
ef416fc2 2961
2962 keyword[0] = '\0';
2963 option[0] = '\0';
2964 text[0] = '\0';
2965 *string = NULL;
2966
2e4ff8af
MS
2967 if ((!line->buffer[0] || /* Blank line */
2968 !strncmp(line->buffer, "*%", 2) || /* Comment line */
2969 !strcmp(line->buffer, "*End")) && /* End of multi-line string */
ef416fc2 2970 ignoreblank) /* Ignore these? */
2971 {
2972 startline = cg->ppd_line + 1;
2973 continue;
2974 }
2975
2e4ff8af 2976 if (!strcmp(line->buffer, "*")) /* (Bad) comment line */
ef416fc2 2977 {
2978 if (cg->ppd_conform == PPD_CONFORM_RELAXED)
2979 {
2980 startline = cg->ppd_line + 1;
2981 continue;
2982 }
2983 else
2984 {
2985 cg->ppd_line = startline;
2986 cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
2987
ef416fc2 2988 return (0);
2989 }
2990 }
2991
2e4ff8af 2992 if (line->buffer[0] != '*') /* All lines start with an asterisk */
ef416fc2 2993 {
ef416fc2 2994 /*
2995 * Allow lines consisting of just whitespace...
2996 */
2997
2e4ff8af 2998 for (lineptr = line->buffer; *lineptr; lineptr ++)
ef416fc2 2999 if (!isspace(*lineptr & 255))
3000 break;
3001
3002 if (*lineptr)
3003 {
3004 cg->ppd_status = PPD_MISSING_ASTERISK;
ef416fc2 3005 return (0);
3006 }
3007 else if (ignoreblank)
3008 continue;
3009 else
ef416fc2 3010 return (0);
ef416fc2 3011 }
3012
3013 /*
3014 * Get a keyword...
3015 */
3016
3017 keyptr = keyword;
3018
3019 while (*lineptr != '\0' && *lineptr != ':' && !isspace(*lineptr & 255))
3020 {
3021 if (*lineptr <= ' ' || *lineptr > 126 || *lineptr == '/' ||
3022 (keyptr - keyword) >= (PPD_MAX_NAME - 1))
3023 {
3024 cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
ef416fc2 3025 return (0);
3026 }
3027
3028 *keyptr++ = *lineptr++;
3029 }
3030
3031 *keyptr = '\0';
3032
3033 if (!strcmp(keyword, "End"))
3034 continue;
3035
3036 mask |= PPD_KEYWORD;
3037
ef416fc2 3038 if (isspace(*lineptr & 255))
3039 {
3040 /*
3041 * Get an option name...
3042 */
3043
3044 while (isspace(*lineptr & 255))
3045 lineptr ++;
3046
3047 optptr = option;
3048
3049 while (*lineptr != '\0' && !isspace(*lineptr & 255) && *lineptr != ':' &&
3050 *lineptr != '/')
3051 {
3052 if (*lineptr <= ' ' || *lineptr > 126 ||
3053 (optptr - option) >= (PPD_MAX_NAME - 1))
3054 {
3055 cg->ppd_status = PPD_ILLEGAL_OPTION_KEYWORD;
ef416fc2 3056 return (0);
3057 }
3058
3059 *optptr++ = *lineptr++;
3060 }
3061
3062 *optptr = '\0';
3063
3064 if (isspace(*lineptr & 255) && cg->ppd_conform == PPD_CONFORM_STRICT)
3065 {
3066 cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
ef416fc2 3067 return (0);
3068 }
3069
3070 while (isspace(*lineptr & 255))
3071 lineptr ++;
3072
3073 mask |= PPD_OPTION;
3074
ef416fc2 3075 if (*lineptr == '/')
3076 {
3077 /*
3078 * Get human-readable text...
3079 */
3080
3081 lineptr ++;
3082
3083 textptr = text;
3084
3085 while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':')
3086 {
3087 if (((unsigned char)*lineptr < ' ' && *lineptr != '\t') ||
3088 (textptr - text) >= (PPD_MAX_LINE - 1))
3089 {
3090 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
ef416fc2 3091 return (0);
3092 }
3093
3094 *textptr++ = *lineptr++;
3095 }
3096
3097 *textptr = '\0';
3098 textlen = ppd_decode(text);
3099
3100 if (textlen > PPD_MAX_TEXT && cg->ppd_conform == PPD_CONFORM_STRICT)
3101 {
3102 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
ef416fc2 3103 return (0);
3104 }
3105
3106 mask |= PPD_TEXT;
3107 }
ef416fc2 3108 }
3109
3110 if (isspace(*lineptr & 255) && cg->ppd_conform == PPD_CONFORM_STRICT)
3111 {
3112 cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
ef416fc2 3113 return (0);
3114 }
3115
3116 while (isspace(*lineptr & 255))
3117 lineptr ++;
3118
3119 if (*lineptr == ':')
3120 {
3121 /*
3122 * Get string after triming leading and trailing whitespace...
3123 */
3124
3125 lineptr ++;
3126 while (isspace(*lineptr & 255))
3127 lineptr ++;
3128
3129 strptr = lineptr + strlen(lineptr) - 1;
3130 while (strptr >= lineptr && isspace(*strptr & 255))
3131 *strptr-- = '\0';
3132
3133 if (*strptr == '\"')
3134 {
3135 /*
2e4ff8af 3136 * Quoted string by itself, remove quotes...
ef416fc2 3137 */
3138
2e4ff8af
MS
3139 *strptr = '\0';
3140 lineptr ++;
ef416fc2 3141 }
2e4ff8af
MS
3142
3143 *string = _cupsStrAlloc(lineptr);
ef416fc2 3144
ef416fc2 3145 mask |= PPD_STRING;
3146 }
3147 }
3148 while (mask == 0);
3149
ef416fc2 3150 return (mask);
3151}
3152
3153
3154/*
b19ccc9e 3155 * End of "$Id: ppd.c 7906 2008-09-03 20:19:43Z mike $".
ef416fc2 3156 */