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