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