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