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