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