]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/ppd.c
Load cups into easysw/current.
[thirdparty/cups.git] / cups / ppd.c
1 /*
2 * "$Id: ppd.c 5333 2006-03-24 00:52:21Z mike $"
3 *
4 * PPD file routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
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 *
37 * ppdClose() - Free all memory used by the PPD file.
38 * ppdErrorString() - Returns the text assocated with a status.
39 * _ppdGetEncoding() - Get the CUPS encoding value for the given
40 * LanguageEncoding.
41 * ppdLastError() - Return the status from the last ppdOpen*().
42 * ppdOpen() - Read a PPD file into memory.
43 * ppdOpen2() - Read a PPD file into memory.
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.
50 * ppd_compare_attrs() - Compare two attributes.
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.
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
98 static ppd_attr_t *ppd_add_attr(ppd_file_t *ppd, const char *name,
99 const char *spec, const char *text,
100 const char *value);
101 static ppd_choice_t *ppd_add_choice(ppd_option_t *option, const char *name);
102 static ppd_size_t *ppd_add_size(ppd_file_t *ppd, const char *name);
103 static int ppd_compare_attrs(ppd_attr_t *a, ppd_attr_t *b);
104 static int ppd_compare_coptions(ppd_coption_t *a,
105 ppd_coption_t *b);
106 static int ppd_compare_cparams(ppd_cparam_t *a, ppd_cparam_t *b);
107 static int ppd_compare_options(ppd_option_t *a, ppd_option_t *b);
108 static int ppd_decode(char *string);
109 static void ppd_free_group(ppd_group_t *group);
110 static void ppd_free_option(ppd_option_t *option);
111 static ppd_coption_t *ppd_get_coption(ppd_file_t *ppd, const char *name);
112 static ppd_cparam_t *ppd_get_cparam(ppd_coption_t *opt,
113 const char *param,
114 const char *text);
115 static ppd_group_t *ppd_get_group(ppd_file_t *ppd, const char *name,
116 const char *text, _cups_globals_t *cg,
117 cups_encoding_t encoding);
118 static ppd_option_t *ppd_get_option(ppd_group_t *group, const char *name);
119 static 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
124 /*
125 * 'ppdClose()' - Free all memory used by the PPD file.
126 */
127
128 void
129 ppdClose(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 */
137 ppd_coption_t *coption; /* Current custom option */
138 ppd_cparam_t *cparam; /* Current custom parameter */
139
140
141 /*
142 * Range check arguments...
143 */
144
145 if (!ppd)
146 return;
147
148 /*
149 * Free all strings at the top level...
150 */
151
152 ppd_free(ppd->lang_encoding);
153 ppd_free(ppd->nickname);
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
186 cupsArrayDelete(ppd->options);
187
188 /*
189 * Free any page sizes...
190 */
191
192 if (ppd->num_sizes > 0)
193 ppd_free(ppd->sizes);
194
195 /*
196 * Free any constraints...
197 */
198
199 if (ppd->num_consts > 0)
200 ppd_free(ppd->consts);
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)
235 ppd_free(ppd->profiles);
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
252 cupsArrayDelete(ppd->sorted_attrs);
253
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))
261 {
262 for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
263 cparam;
264 cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
265 {
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);
272 break;
273
274 default :
275 break;
276 }
277
278 free(cparam);
279 }
280
281 cupsArrayDelete(coption->params);
282
283 free(coption);
284 }
285
286 cupsArrayDelete(ppd->coptions);
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
302 const char * /* O - Status string */
303 ppdErrorString(ppd_status_t status) /* I - PPD status */
304 {
305 static const char * const messages[] =/* Status messages */
306 {
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")
328 };
329
330
331 if (status < PPD_OK || status > PPD_ILLEGAL_WHITESPACE)
332 return (_cupsLangString(cupsLangDefault(), _("Unknown")));
333 else
334 return (_cupsLangString(cupsLangDefault(), messages[status]));
335 }
336
337
338 /*
339 * '_ppdGetEncoding()' - Get the CUPS encoding value for the given
340 * LanguageEncoding.
341 */
342
343 cups_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
363 /*
364 * 'ppdLastError()' - Return the status from the last ppdOpen*().
365 *
366 * @since CUPS 1.1.19@
367 */
368
369 ppd_status_t /* O - Status code */
370 ppdLastError(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
387 ppd_file_t * /* O - PPD file record */
388 ppdOpen(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
423 ppd_file_t * /* O - PPD file record */
424 ppdOpen2(cups_file_t *fp) /* I - File to read from */
425 {
426 int i, j, k; /* Looping vars */
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 */
452 struct lconv *loc; /* Locale data */
453 int ui_keyword; /* Is this line a UI keyword? */
454 cups_encoding_t encoding; /* Encoding of PPD file */
455 _cups_globals_t *cg = _cupsGlobals();
456 /* Global data */
457 static const char * const ui_keywords[] =
458 {
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 */
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"
513 #else /* !CUPS_USE_FULL_UI_KEYWORDS_LIST */
514 "PageRegion",
515 "PageSize"
516 #endif /* CUPS_USE_FULL_UI_KEYWORDS_LIST */
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;
580 ppd->coptions = cupsArrayNew((cups_array_func_t)ppd_compare_coptions,
581 NULL);
582
583 /*
584 * Get the default language for the user...
585 */
586
587 language = cupsLangDefault();
588 loc = localeconv();
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;
599 encoding = CUPS_ISO8859_1;
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 {
678 if ((group = ppd_get_group(ppd, "General", _("General"), cg,
679 encoding)) == NULL)
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"))
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");
748 encoding = _ppdGetEncoding(string);
749 }
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"))
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 }
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));
821
822 profile->density = _cupsStrScand(string, &sptr, loc);
823 profile->gamma = _cupsStrScand(sptr, &sptr, loc);
824 profile->matrix[0][0] = _cupsStrScand(sptr, &sptr, loc);
825 profile->matrix[0][1] = _cupsStrScand(sptr, &sptr, loc);
826 profile->matrix[0][2] = _cupsStrScand(sptr, &sptr, loc);
827 profile->matrix[1][0] = _cupsStrScand(sptr, &sptr, loc);
828 profile->matrix[1][1] = _cupsStrScand(sptr, &sptr, loc);
829 profile->matrix[1][2] = _cupsStrScand(sptr, &sptr, loc);
830 profile->matrix[2][0] = _cupsStrScand(sptr, &sptr, loc);
831 profile->matrix[2][1] = _cupsStrScand(sptr, &sptr, loc);
832 profile->matrix[2][2] = _cupsStrScand(sptr, &sptr, loc);
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 }
886 else if (!strncmp(keyword, "ParamCustom", 11))
887 {
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 */
899
900 if ((coption = ppd_get_coption(ppd, keyword + 11)) == NULL)
901 {
902 cg->ppd_status = PPD_ALLOC_ERROR;
903
904 goto error;
905 }
906
907 if ((cparam = ppd_get_cparam(coption, name, text)) == NULL)
908 {
909 cg->ppd_status = PPD_ALLOC_ERROR;
910
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;
927
928 if (!strcmp(ctype, "curve"))
929 {
930 cparam->type = PPD_CUSTOM_CURVE;
931 cparam->minimum.custom_curve = _cupsStrScand(cminimum, NULL, loc);
932 cparam->maximum.custom_curve = _cupsStrScand(cmaximum, NULL, loc);
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;
943 cparam->minimum.custom_invcurve = _cupsStrScand(cminimum, NULL, loc);
944 cparam->maximum.custom_invcurve = _cupsStrScand(cmaximum, NULL, loc);
945 }
946 else if (!strcmp(ctype, "passcode"))
947 {
948 cparam->type = PPD_CUSTOM_PASSCODE;
949 cparam->minimum.custom_passcode = atoi(cminimum);
950 cparam->maximum.custom_passcode = atoi(cmaximum);
951 }
952 else if (!strcmp(ctype, "password"))
953 {
954 cparam->type = PPD_CUSTOM_PASSWORD;
955 cparam->minimum.custom_password = atoi(cminimum);
956 cparam->maximum.custom_password = atoi(cmaximum);
957 }
958 else if (!strcmp(ctype, "points"))
959 {
960 cparam->type = PPD_CUSTOM_POINTS;
961 cparam->minimum.custom_points = _cupsStrScand(cminimum, NULL, loc);
962 cparam->maximum.custom_points = _cupsStrScand(cmaximum, NULL, loc);
963 }
964 else if (!strcmp(ctype, "real"))
965 {
966 cparam->type = PPD_CUSTOM_REAL;
967 cparam->minimum.custom_real = _cupsStrScand(cminimum, NULL, loc);
968 cparam->maximum.custom_real = _cupsStrScand(cmaximum, NULL, loc);
969 }
970 else if (!strcmp(ctype, "string"))
971 {
972 cparam->type = PPD_CUSTOM_STRING;
973 cparam->minimum.custom_string = atoi(cminimum);
974 cparam->maximum.custom_string = atoi(cmaximum);
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"))
995 {
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"))
1002 {
1003 for (i = 0, sptr = string; i < 4; i ++)
1004 ppd->custom_margins[i] = _cupsStrScand(sptr, &sptr, loc);
1005 }
1006 else if (!strncmp(keyword, "Custom", 6) && !strcmp(name, "True"))
1007 {
1008 DEBUG_puts("Processing Custom option...");
1009
1010 /*
1011 * Get the option and custom option...
1012 */
1013
1014 if ((option = ppdFindOption(ppd, keyword + 6)) == NULL)
1015 {
1016 ppd_group_t *gtemp; /* Temporary group */
1017
1018
1019 DEBUG_printf(("%s option not found for %s...\n", keyword + 6, keyword));
1020
1021 if ((gtemp = ppd_get_group(ppd, "General", _("General"), cg,
1022 encoding)) == NULL)
1023 {
1024 DEBUG_puts("Unable to get general group!");
1025
1026 goto error;
1027 }
1028
1029 if ((option = ppd_get_option(gtemp, keyword + 6)) == NULL)
1030 {
1031 DEBUG_printf(("Unable to get %s option!\n", keyword + 6));
1032
1033 cg->ppd_status = PPD_ALLOC_ERROR;
1034
1035 goto error;
1036 }
1037 }
1038
1039 if (!ppd_get_coption(ppd, keyword + 6))
1040 {
1041 cg->ppd_status = PPD_ALLOC_ERROR;
1042
1043 goto error;
1044 }
1045
1046 /*
1047 * Add the "custom" option...
1048 */
1049
1050 if ((choice = ppd_add_choice(option, "Custom")) == NULL)
1051 {
1052 DEBUG_puts("Unable to add Custom choice!");
1053
1054 cg->ppd_status = PPD_ALLOC_ERROR;
1055
1056 goto error;
1057 }
1058
1059 strlcpy(choice->text, text[0] ? text : _("Custom"),
1060 sizeof(choice->text));
1061
1062 choice->code = string;
1063 string = NULL; /* Don't add as an attribute below */
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 }
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 {
1187 if ((group = ppd_get_group(ppd, "General", _("General"), cg,
1188 encoding)) == NULL)
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])
1237 cupsCharsetToUTF8((cups_utf8_t *)option->text, text,
1238 sizeof(option->text), encoding);
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
1277 group = ppd_get_group(ppd, "JCL", _("JCL"), cg, encoding);
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
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));
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
1385 group = ppd_get_group(ppd, string, sptr, cg, encoding);
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 {
1403 order = _cupsStrScand(string, &sptr, loc);
1404
1405 if (!sptr || sscanf(sptr, "%40s%40s", name, keyword) != 2)
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... */
1552 /*
1553 * The following strcpy's are safe, as optionN and
1554 * choiceN are all the same size (size defined by PPD spec...)
1555 */
1556
1557 if (constraint->option1[0] == '*')
1558 _cups_strcpy(constraint->option1, constraint->option1 + 1);
1559
1560 if (constraint->choice1[0] == '*')
1561 _cups_strcpy(constraint->option2, constraint->choice1 + 1);
1562 else
1563 _cups_strcpy(constraint->option2, constraint->choice1);
1564
1565 constraint->choice1[0] = '\0';
1566 constraint->choice2[0] = '\0';
1567 break;
1568
1569 case 3 : /* Two options, one choice... */
1570 /*
1571 * The following _cups_strcpy's are safe, as optionN and
1572 * choiceN are all the same size (size defined by PPD spec...)
1573 */
1574
1575 if (constraint->option1[0] == '*')
1576 _cups_strcpy(constraint->option1, constraint->option1 + 1);
1577
1578 if (constraint->choice1[0] == '*')
1579 {
1580 _cups_strcpy(constraint->choice2, constraint->option2);
1581 _cups_strcpy(constraint->option2, constraint->choice1 + 1);
1582 constraint->choice1[0] = '\0';
1583 }
1584 else
1585 {
1586 if (constraint->option2[0] == '*')
1587 _cups_strcpy(constraint->option2, constraint->option2 + 1);
1588
1589 constraint->choice2[0] = '\0';
1590 }
1591 break;
1592
1593 case 4 : /* Two options, two choices... */
1594 if (constraint->option1[0] == '*')
1595 _cups_strcpy(constraint->option1, constraint->option1 + 1);
1596
1597 if (constraint->option2[0] == '*')
1598 _cups_strcpy(constraint->option2, constraint->option2 + 1);
1599 break;
1600 }
1601
1602 ppd_free(string);
1603 string = NULL;
1604 }
1605 else if (!strcmp(keyword, "PaperDimension"))
1606 {
1607 if ((size = ppdPageSize(ppd, name)) == NULL)
1608 size = ppd_add_size(ppd, name);
1609
1610 if (size == NULL)
1611 {
1612 /*
1613 * Unable to add or find size!
1614 */
1615
1616 cg->ppd_status = PPD_ALLOC_ERROR;
1617
1618 goto error;
1619 }
1620
1621 size->width = _cupsStrScand(string, &sptr, loc);
1622 size->length = _cupsStrScand(sptr, NULL, loc);
1623
1624 ppd_free(string);
1625 string = NULL;
1626 }
1627 else if (!strcmp(keyword, "ImageableArea"))
1628 {
1629 if ((size = ppdPageSize(ppd, name)) == NULL)
1630 size = ppd_add_size(ppd, name);
1631
1632 if (size == NULL)
1633 {
1634 /*
1635 * Unable to add or find size!
1636 */
1637
1638 cg->ppd_status = PPD_ALLOC_ERROR;
1639
1640 goto error;
1641 }
1642
1643 size->left = _cupsStrScand(string, &sptr, loc);
1644 size->bottom = _cupsStrScand(sptr, &sptr, loc);
1645 size->right = _cupsStrScand(sptr, &sptr, loc);
1646 size->top = _cupsStrScand(sptr, NULL, loc);
1647
1648 ppd_free(string);
1649 string = NULL;
1650 }
1651 else if (option != NULL &&
1652 (mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) ==
1653 (PPD_KEYWORD | PPD_OPTION | PPD_STRING) &&
1654 !strcmp(keyword, option->keyword))
1655 {
1656 DEBUG_printf(("group = %p, subgroup = %p\n", group, subgroup));
1657
1658 if (!strcmp(keyword, "PageSize"))
1659 {
1660 /*
1661 * Add a page size...
1662 */
1663
1664 if (ppdPageSize(ppd, name) == NULL)
1665 ppd_add_size(ppd, name);
1666 }
1667
1668 /*
1669 * Add the option choice...
1670 */
1671
1672 choice = ppd_add_choice(option, name);
1673
1674 if (text[0])
1675 cupsCharsetToUTF8((cups_utf8_t *)choice->text, text,
1676 sizeof(choice->text), encoding);
1677 else if (!strcmp(name, "True"))
1678 strcpy(choice->text, _("Yes"));
1679 else if (!strcmp(name, "False"))
1680 strcpy(choice->text, _("No"));
1681 else
1682 strlcpy(choice->text, name, sizeof(choice->text));
1683
1684 if (option->section == PPD_ORDER_JCL)
1685 ppd_decode(string); /* Decode quoted string */
1686
1687 choice->code = string;
1688 string = NULL; /* Don't add as an attribute below */
1689 }
1690
1691 /*
1692 * Add remaining lines with keywords and string values as attributes...
1693 */
1694
1695 if (string &&
1696 (mask & (PPD_KEYWORD | PPD_STRING)) == (PPD_KEYWORD | PPD_STRING))
1697 ppd_add_attr(ppd, keyword, name, text, string);
1698 else
1699 ppd_free(string);
1700 }
1701
1702 /*
1703 * Reset language preferences...
1704 */
1705
1706 cupsLangFree(language);
1707
1708 #ifdef DEBUG
1709 if (!feof(fp))
1710 printf("Premature EOF at %lu...\n", (unsigned long)ftell(fp));
1711 #endif /* DEBUG */
1712
1713 if (cg->ppd_status != PPD_OK)
1714 {
1715 /*
1716 * Had an error reading the PPD file, cannot continue!
1717 */
1718
1719 ppdClose(ppd);
1720
1721 return (NULL);
1722 }
1723
1724 /*
1725 * Create the sorted options array and set the option back-pointer for
1726 * each choice and custom option...
1727 */
1728
1729 ppd->options = cupsArrayNew((cups_array_func_t)ppd_compare_options, NULL);
1730
1731 for (i = ppd->num_groups, group = ppd->groups;
1732 i > 0;
1733 i --, group ++)
1734 {
1735 for (j = group->num_options, option = group->options;
1736 j > 0;
1737 j --, option ++)
1738 {
1739 ppd_coption_t *coption; /* Custom option */
1740
1741
1742 cupsArrayAdd(ppd->options, option);
1743
1744 for (k = 0; k < option->num_choices; k ++)
1745 option->choices[k].option = option;
1746
1747 if ((coption = ppdFindCustomOption(ppd, option->keyword)) != NULL)
1748 coption->option = option;
1749 }
1750 }
1751
1752 /*
1753 * Return the PPD file structure...
1754 */
1755
1756 return (ppd);
1757
1758 /*
1759 * Common exit point for errors to save code size...
1760 */
1761
1762 error:
1763
1764 ppd_free(string);
1765
1766 ppdClose(ppd);
1767
1768 cupsLangFree(language);
1769
1770 return (NULL);
1771 }
1772
1773
1774 /*
1775 * 'ppdOpenFd()' - Read a PPD file into memory.
1776 */
1777
1778 ppd_file_t * /* O - PPD file record */
1779 ppdOpenFd(int fd) /* I - File to read from */
1780 {
1781 cups_file_t *fp; /* CUPS file pointer */
1782 ppd_file_t *ppd; /* PPD file record */
1783 _cups_globals_t *cg = _cupsGlobals();
1784 /* Global data */
1785
1786
1787 /*
1788 * Set the line number to 0...
1789 */
1790
1791 cg->ppd_line = 0;
1792
1793 /*
1794 * Range check input...
1795 */
1796
1797 if (fd < 0)
1798 {
1799 cg->ppd_status = PPD_NULL_FILE;
1800
1801 return (NULL);
1802 }
1803
1804 /*
1805 * Try to open the file and parse it...
1806 */
1807
1808 if ((fp = cupsFileOpenFd(fd, "r")) != NULL)
1809 {
1810 ppd = ppdOpen2(fp);
1811
1812 cupsFileClose(fp);
1813 }
1814 else
1815 {
1816 cg->ppd_status = PPD_FILE_OPEN_ERROR;
1817 ppd = NULL;
1818 }
1819
1820 return (ppd);
1821 }
1822
1823
1824 /*
1825 * 'ppdOpenFile()' - Read a PPD file into memory.
1826 */
1827
1828 ppd_file_t * /* O - PPD file record */
1829 ppdOpenFile(const char *filename) /* I - File to read from */
1830 {
1831 cups_file_t *fp; /* File pointer */
1832 ppd_file_t *ppd; /* PPD file record */
1833 _cups_globals_t *cg = _cupsGlobals();
1834 /* Global data */
1835
1836
1837 /*
1838 * Set the line number to 0...
1839 */
1840
1841 cg->ppd_line = 0;
1842
1843 /*
1844 * Range check input...
1845 */
1846
1847 if (filename == NULL)
1848 {
1849 cg->ppd_status = PPD_NULL_FILE;
1850
1851 return (NULL);
1852 }
1853
1854 /*
1855 * Try to open the file and parse it...
1856 */
1857
1858 if ((fp = cupsFileOpen(filename, "r")) != NULL)
1859 {
1860 ppd = ppdOpen2(fp);
1861
1862 cupsFileClose(fp);
1863 }
1864 else
1865 {
1866 cg->ppd_status = PPD_FILE_OPEN_ERROR;
1867 ppd = NULL;
1868 }
1869
1870 return (ppd);
1871 }
1872
1873
1874 /*
1875 * 'ppdSetConformance()' - Set the conformance level for PPD files.
1876 *
1877 * @since CUPS 1.1.20@
1878 */
1879
1880 void
1881 ppdSetConformance(ppd_conform_t c) /* I - Conformance level */
1882 {
1883 _cups_globals_t *cg = _cupsGlobals();
1884 /* Global data */
1885
1886
1887 cg->ppd_conform = c;
1888 }
1889
1890
1891 /*
1892 * 'ppd_add_attr()' - Add an attribute to the PPD data.
1893 */
1894
1895 static ppd_attr_t * /* O - New attribute */
1896 ppd_add_attr(ppd_file_t *ppd, /* I - PPD file data */
1897 const char *name, /* I - Attribute name */
1898 const char *spec, /* I - Specifier string, if any */
1899 const char *text, /* I - Text string, if any */
1900 const char *value) /* I - Value of attribute */
1901 {
1902 ppd_attr_t **ptr, /* New array */
1903 *temp; /* New attribute */
1904
1905
1906 /*
1907 * Range check input...
1908 */
1909
1910 if (ppd == NULL || name == NULL || spec == NULL)
1911 return (NULL);
1912
1913 /*
1914 * Create the array as needed...
1915 */
1916
1917 if (!ppd->sorted_attrs)
1918 ppd->sorted_attrs = cupsArrayNew((cups_array_func_t)ppd_compare_attrs,
1919 NULL);
1920
1921 /*
1922 * Allocate memory for the new attribute...
1923 */
1924
1925 if (ppd->num_attrs == 0)
1926 ptr = malloc(sizeof(ppd_attr_t *));
1927 else
1928 ptr = realloc(ppd->attrs, (ppd->num_attrs + 1) * sizeof(ppd_attr_t *));
1929
1930 if (ptr == NULL)
1931 return (NULL);
1932
1933 ppd->attrs = ptr;
1934 ptr += ppd->num_attrs;
1935
1936 if ((temp = calloc(1, sizeof(ppd_attr_t))) == NULL)
1937 return (NULL);
1938
1939 *ptr = temp;
1940
1941 ppd->num_attrs ++;
1942
1943 /*
1944 * Copy data over...
1945 */
1946
1947 strlcpy(temp->name, name, sizeof(temp->name));
1948 strlcpy(temp->spec, spec, sizeof(temp->spec));
1949 strlcpy(temp->text, text, sizeof(temp->text));
1950 temp->value = (char *)value;
1951
1952 /*
1953 * Add the attribute to the sorted array...
1954 */
1955
1956 cupsArrayAdd(ppd->sorted_attrs, temp);
1957
1958 /*
1959 * Return the attribute...
1960 */
1961
1962 return (temp);
1963 }
1964
1965
1966 /*
1967 * 'ppd_add_choice()' - Add a choice to an option.
1968 */
1969
1970 static ppd_choice_t * /* O - Named choice */
1971 ppd_add_choice(ppd_option_t *option, /* I - Option */
1972 const char *name) /* I - Name of choice */
1973 {
1974 ppd_choice_t *choice; /* Choice */
1975
1976
1977 if (option->num_choices == 0)
1978 choice = malloc(sizeof(ppd_choice_t));
1979 else
1980 choice = realloc(option->choices,
1981 sizeof(ppd_choice_t) * (option->num_choices + 1));
1982
1983 if (choice == NULL)
1984 return (NULL);
1985
1986 option->choices = choice;
1987 choice += option->num_choices;
1988 option->num_choices ++;
1989
1990 memset(choice, 0, sizeof(ppd_choice_t));
1991 strlcpy(choice->choice, name, sizeof(choice->choice));
1992
1993 return (choice);
1994 }
1995
1996
1997 /*
1998 * 'ppd_add_size()' - Add a page size.
1999 */
2000
2001 static ppd_size_t * /* O - Named size */
2002 ppd_add_size(ppd_file_t *ppd, /* I - PPD file */
2003 const char *name) /* I - Name of size */
2004 {
2005 ppd_size_t *size; /* Size */
2006
2007
2008 if (ppd->num_sizes == 0)
2009 size = malloc(sizeof(ppd_size_t));
2010 else
2011 size = realloc(ppd->sizes, sizeof(ppd_size_t) * (ppd->num_sizes + 1));
2012
2013 if (size == NULL)
2014 return (NULL);
2015
2016 ppd->sizes = size;
2017 size += ppd->num_sizes;
2018 ppd->num_sizes ++;
2019
2020 memset(size, 0, sizeof(ppd_size_t));
2021 strlcpy(size->name, name, sizeof(size->name));
2022
2023 return (size);
2024 }
2025
2026
2027 /*
2028 * 'ppd_compare_attrs()' - Compare two attributes.
2029 */
2030
2031 static int /* O - Result of comparison */
2032 ppd_compare_attrs(ppd_attr_t *a, /* I - First attribute */
2033 ppd_attr_t *b) /* I - Second attribute */
2034 {
2035 int ret; /* Result of comparison */
2036
2037
2038 if ((ret = strcasecmp(a->name, b->name)) != 0)
2039 return (ret);
2040 else if (a->spec[0] && b->spec[0])
2041 return (strcasecmp(a->spec, b->spec));
2042 else
2043 return (0);
2044 }
2045
2046
2047 /*
2048 * 'ppd_compare_coptions()' - Compare two custom options.
2049 */
2050
2051 static int /* O - Result of comparison */
2052 ppd_compare_coptions(ppd_coption_t *a, /* I - First option */
2053 ppd_coption_t *b) /* I - Second option */
2054 {
2055 return (strcasecmp(a->keyword, b->keyword));
2056 }
2057
2058
2059 /*
2060 * 'ppd_compare_cparams()' - Compare two custom parameters.
2061 */
2062
2063 static int /* O - Result of comparison */
2064 ppd_compare_cparams(ppd_cparam_t *a, /* I - First parameter */
2065 ppd_cparam_t *b) /* I - Second parameter */
2066 {
2067 return (strcasecmp(a->name, b->name));
2068 }
2069
2070
2071 /*
2072 * 'ppd_compare_options()' - Compare two options.
2073 */
2074
2075 static int /* O - Result of comparison */
2076 ppd_compare_options(ppd_option_t *a, /* I - First option */
2077 ppd_option_t *b) /* I - Second option */
2078 {
2079 return (strcasecmp(a->keyword, b->keyword));
2080 }
2081
2082
2083 /*
2084 * 'ppd_decode()' - Decode a string value...
2085 */
2086
2087 static int /* O - Length of decoded string */
2088 ppd_decode(char *string) /* I - String to decode */
2089 {
2090 char *inptr, /* Input pointer */
2091 *outptr; /* Output pointer */
2092
2093
2094 inptr = string;
2095 outptr = string;
2096
2097 while (*inptr != '\0')
2098 if (*inptr == '<' && isxdigit(inptr[1] & 255))
2099 {
2100 /*
2101 * Convert hex to 8-bit values...
2102 */
2103
2104 inptr ++;
2105 while (isxdigit(*inptr & 255))
2106 {
2107 if (isalpha(*inptr))
2108 *outptr = (tolower(*inptr) - 'a' + 10) << 4;
2109 else
2110 *outptr = (*inptr - '0') << 4;
2111
2112 inptr ++;
2113
2114 if (!isxdigit(*inptr & 255))
2115 break;
2116
2117 if (isalpha(*inptr))
2118 *outptr |= tolower(*inptr) - 'a' + 10;
2119 else
2120 *outptr |= *inptr - '0';
2121
2122 inptr ++;
2123 outptr ++;
2124 }
2125
2126 while (*inptr != '>' && *inptr != '\0')
2127 inptr ++;
2128 while (*inptr == '>')
2129 inptr ++;
2130 }
2131 else
2132 *outptr++ = *inptr++;
2133
2134 *outptr = '\0';
2135
2136 return ((int)(outptr - string));
2137 }
2138
2139
2140 /*
2141 * 'ppd_free_group()' - Free a single UI group.
2142 */
2143
2144 static void
2145 ppd_free_group(ppd_group_t *group) /* I - Group to free */
2146 {
2147 int i; /* Looping var */
2148 ppd_option_t *option; /* Current option */
2149 ppd_group_t *subgroup; /* Current sub-group */
2150
2151
2152 if (group->num_options > 0)
2153 {
2154 for (i = group->num_options, option = group->options;
2155 i > 0;
2156 i --, option ++)
2157 ppd_free_option(option);
2158
2159 ppd_free(group->options);
2160 }
2161
2162 if (group->num_subgroups > 0)
2163 {
2164 for (i = group->num_subgroups, subgroup = group->subgroups;
2165 i > 0;
2166 i --, subgroup ++)
2167 ppd_free_group(subgroup);
2168
2169 ppd_free(group->subgroups);
2170 }
2171 }
2172
2173
2174 /*
2175 * 'ppd_free_option()' - Free a single option.
2176 */
2177
2178 static void
2179 ppd_free_option(ppd_option_t *option) /* I - Option to free */
2180 {
2181 int i; /* Looping var */
2182 ppd_choice_t *choice; /* Current choice */
2183
2184
2185 if (option->num_choices > 0)
2186 {
2187 for (i = option->num_choices, choice = option->choices;
2188 i > 0;
2189 i --, choice ++)
2190 {
2191 ppd_free(choice->code);
2192 }
2193
2194 ppd_free(option->choices);
2195 }
2196 }
2197
2198
2199 /*
2200 * 'ppd_get_coption()' - Get a custom option record.
2201 */
2202
2203 static ppd_coption_t * /* O - Custom option... */
2204 ppd_get_coption(ppd_file_t *ppd, /* I - PPD file */
2205 const char *name) /* I - Name of option */
2206 {
2207 ppd_coption_t *copt; /* New custom option */
2208
2209
2210 /*
2211 * See if the option already exists...
2212 */
2213
2214 if ((copt = ppdFindCustomOption(ppd, name)) != NULL)
2215 return (copt);
2216
2217 /*
2218 * Not found, so create the custom option record...
2219 */
2220
2221 if ((copt = calloc(1, sizeof(ppd_coption_t))) == NULL)
2222 return (NULL);
2223
2224 strlcpy(copt->keyword, name, sizeof(copt->keyword));
2225
2226 copt->params = cupsArrayNew((cups_array_func_t)ppd_compare_cparams, NULL);
2227
2228 cupsArrayAdd(ppd->coptions, copt);
2229
2230 /*
2231 * Return the new record...
2232 */
2233
2234 return (copt);
2235 }
2236
2237
2238 /*
2239 * 'ppd_get_cparam()' - Get a custom parameter record.
2240 */
2241
2242 static ppd_cparam_t * /* O - Extended option... */
2243 ppd_get_cparam(ppd_coption_t *opt, /* I - PPD file */
2244 const char *param, /* I - Name of parameter */
2245 const char *text) /* I - Human-readable text */
2246 {
2247 ppd_cparam_t *cparam; /* New custom parameter */
2248
2249
2250 /*
2251 * See if the parameter already exists...
2252 */
2253
2254 if ((cparam = ppdFindCustomParam(opt, param)) != NULL)
2255 return (cparam);
2256
2257 /*
2258 * Not found, so create the custom parameter record...
2259 */
2260
2261 if ((cparam = calloc(1, sizeof(ppd_cparam_t))) == NULL)
2262 return (NULL);
2263
2264 strlcpy(cparam->name, param, sizeof(cparam->name));
2265 strlcpy(cparam->text, text, sizeof(cparam->text));
2266
2267 /*
2268 * Add this record to the array...
2269 */
2270
2271 cupsArrayAdd(opt->params, cparam);
2272
2273 /*
2274 * Return the new record...
2275 */
2276
2277 return (cparam);
2278 }
2279
2280
2281 /*
2282 * 'ppd_get_group()' - Find or create the named group as needed.
2283 */
2284
2285 static ppd_group_t * /* O - Named group */
2286 ppd_get_group(ppd_file_t *ppd, /* I - PPD file */
2287 const char *name, /* I - Name of group */
2288 const char *text, /* I - Text for group */
2289 _cups_globals_t *cg, /* I - Global data */
2290 cups_encoding_t encoding) /* I - Encoding of text */
2291 {
2292 int i; /* Looping var */
2293 ppd_group_t *group; /* Group */
2294
2295
2296 DEBUG_printf(("ppd_get_group(ppd=%p, name=\"%s\", text=\"%s\", cg=%p)\n",
2297 ppd, name, text, cg));
2298
2299 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
2300 if (!strcmp(group->name, name))
2301 break;
2302
2303 if (i == 0)
2304 {
2305 DEBUG_printf(("Adding group %s...\n", name));
2306
2307 if (cg->ppd_conform == PPD_CONFORM_STRICT && strlen(text) >= sizeof(group->text))
2308 {
2309 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
2310
2311 return (NULL);
2312 }
2313
2314 if (ppd->num_groups == 0)
2315 group = malloc(sizeof(ppd_group_t));
2316 else
2317 group = realloc(ppd->groups,
2318 (ppd->num_groups + 1) * sizeof(ppd_group_t));
2319
2320 if (group == NULL)
2321 {
2322 cg->ppd_status = PPD_ALLOC_ERROR;
2323
2324 return (NULL);
2325 }
2326
2327 ppd->groups = group;
2328 group += ppd->num_groups;
2329 ppd->num_groups ++;
2330
2331 memset(group, 0, sizeof(ppd_group_t));
2332 strlcpy(group->name, name, sizeof(group->name));
2333
2334 cupsCharsetToUTF8((cups_utf8_t *)group->text, text,
2335 sizeof(group->text), encoding);
2336 }
2337
2338 return (group);
2339 }
2340
2341
2342 /*
2343 * 'ppd_get_option()' - Find or create the named option as needed.
2344 */
2345
2346 static ppd_option_t * /* O - Named option */
2347 ppd_get_option(ppd_group_t *group, /* I - Group */
2348 const char *name) /* I - Name of option */
2349 {
2350 int i; /* Looping var */
2351 ppd_option_t *option; /* Option */
2352
2353
2354 DEBUG_printf(("ppd_get_option(group=%p(\"%s\"), name=\"%s\")\n",
2355 group, group->name, name));
2356
2357 for (i = group->num_options, option = group->options; i > 0; i --, option ++)
2358 if (!strcmp(option->keyword, name))
2359 break;
2360
2361 if (i == 0)
2362 {
2363 if (group->num_options == 0)
2364 option = malloc(sizeof(ppd_option_t));
2365 else
2366 option = realloc(group->options,
2367 (group->num_options + 1) * sizeof(ppd_option_t));
2368
2369 if (option == NULL)
2370 return (NULL);
2371
2372 group->options = option;
2373 option += group->num_options;
2374 group->num_options ++;
2375
2376 memset(option, 0, sizeof(ppd_option_t));
2377 strlcpy(option->keyword, name, sizeof(option->keyword));
2378 }
2379
2380 return (option);
2381 }
2382
2383
2384 /*
2385 * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
2386 * necessary.
2387 */
2388
2389 static int /* O - Bitmask of fields read */
2390 ppd_read(cups_file_t *fp, /* I - File to read from */
2391 char *keyword, /* O - Keyword from line */
2392 char *option, /* O - Option from line */
2393 char *text, /* O - Human-readable text from line */
2394 char **string, /* O - Code/string data */
2395 int ignoreblank, /* I - Ignore blank lines? */
2396 _cups_globals_t *cg) /* I - Global data */
2397 {
2398 int ch, /* Character from file */
2399 col, /* Column in line */
2400 colon, /* Colon seen? */
2401 endquote, /* Waiting for an end quote */
2402 mask, /* Mask to be returned */
2403 startline, /* Start line */
2404 textlen; /* Length of text */
2405 char *keyptr, /* Keyword pointer */
2406 *optptr, /* Option pointer */
2407 *textptr, /* Text pointer */
2408 *strptr, /* Pointer into string */
2409 *lineptr, /* Current position in line buffer */
2410 *line; /* Line buffer */
2411 int linesize; /* Current size of line buffer */
2412
2413 /*
2414 * Range check everything...
2415 */
2416
2417 if (!fp || !keyword || !option || !text || !string)
2418 return (0);
2419
2420 /*
2421 * Now loop until we have a valid line...
2422 */
2423
2424 *string = NULL;
2425 col = 0;
2426 startline = cg->ppd_line + 1;
2427 linesize = 1024;
2428 line = malloc(linesize);
2429
2430 if (!line)
2431 return (0);
2432
2433 do
2434 {
2435 /*
2436 * Read the line...
2437 */
2438
2439 lineptr = line;
2440 endquote = 0;
2441 colon = 0;
2442
2443 while ((ch = cupsFileGetChar(fp)) != EOF)
2444 {
2445 if (lineptr >= (line + linesize - 1))
2446 {
2447 /*
2448 * Expand the line buffer...
2449 */
2450
2451 char *temp; /* Temporary line pointer */
2452
2453
2454 linesize += 1024;
2455 if (linesize > 262144)
2456 {
2457 /*
2458 * Don't allow lines longer than 256k!
2459 */
2460
2461 cg->ppd_line = startline;
2462 cg->ppd_status = PPD_LINE_TOO_LONG;
2463
2464 free(line);
2465
2466 return (0);
2467 }
2468
2469 temp = realloc(line, linesize);
2470 if (!temp)
2471 {
2472 cg->ppd_line = startline;
2473 cg->ppd_status = PPD_LINE_TOO_LONG;
2474
2475 free(line);
2476
2477 return (0);
2478 }
2479
2480 lineptr = temp + (lineptr - line);
2481 line = temp;
2482 }
2483
2484 if (ch == '\r' || ch == '\n')
2485 {
2486 /*
2487 * Line feed or carriage return...
2488 */
2489
2490 cg->ppd_line ++;
2491 col = 0;
2492
2493 if (ch == '\r')
2494 {
2495 /*
2496 * Check for a trailing line feed...
2497 */
2498
2499 if ((ch = cupsFilePeekChar(fp)) == EOF)
2500 {
2501 ch = '\n';
2502 break;
2503 }
2504
2505 if (ch == 0x0a)
2506 cupsFileGetChar(fp);
2507 }
2508
2509 if (lineptr == line && ignoreblank)
2510 continue; /* Skip blank lines */
2511
2512 ch = '\n';
2513
2514 if (!endquote) /* Continue for multi-line text */
2515 break;
2516
2517 *lineptr++ = '\n';
2518 }
2519 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
2520 {
2521 /*
2522 * Other control characters...
2523 */
2524
2525 cg->ppd_line = startline;
2526 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
2527
2528 free(line);
2529
2530 return (0);
2531 }
2532 else if (ch != 0x1a)
2533 {
2534 /*
2535 * Any other character...
2536 */
2537
2538 *lineptr++ = ch;
2539 col ++;
2540
2541 if (col > (PPD_MAX_LINE - 1))
2542 {
2543 /*
2544 * Line is too long...
2545 */
2546
2547 cg->ppd_line = startline;
2548 cg->ppd_status = PPD_LINE_TOO_LONG;
2549
2550 free(line);
2551
2552 return (0);
2553 }
2554
2555 if (ch == ':' && strncmp(line, "*%", 2) != 0)
2556 colon = 1;
2557
2558 if (ch == '\"' && colon)
2559 endquote = !endquote;
2560 }
2561 }
2562
2563 if (endquote)
2564 {
2565 /*
2566 * Didn't finish this quoted string...
2567 */
2568
2569 while ((ch = cupsFileGetChar(fp)) != EOF)
2570 if (ch == '\"')
2571 break;
2572 else if (ch == '\r' || ch == '\n')
2573 {
2574 cg->ppd_line ++;
2575 col = 0;
2576
2577 if (ch == '\r')
2578 {
2579 /*
2580 * Check for a trailing line feed...
2581 */
2582
2583 if ((ch = cupsFilePeekChar(fp)) == EOF)
2584 break;
2585 if (ch == 0x0a)
2586 cupsFileGetChar(fp);
2587 }
2588
2589 ch = '\n';
2590 }
2591 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
2592 {
2593 /*
2594 * Other control characters...
2595 */
2596
2597 cg->ppd_line = startline;
2598 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
2599
2600 free(line);
2601
2602 return (0);
2603 }
2604 else if (ch != 0x1a)
2605 {
2606 col ++;
2607
2608 if (col > (PPD_MAX_LINE - 1))
2609 {
2610 /*
2611 * Line is too long...
2612 */
2613
2614 cg->ppd_line = startline;
2615 cg->ppd_status = PPD_LINE_TOO_LONG;
2616
2617 free(line);
2618
2619 return (0);
2620 }
2621 }
2622 }
2623
2624 if (ch != '\n')
2625 {
2626 /*
2627 * Didn't finish this line...
2628 */
2629
2630 while ((ch = cupsFileGetChar(fp)) != EOF)
2631 if (ch == '\r' || ch == '\n')
2632 {
2633 /*
2634 * Line feed or carriage return...
2635 */
2636
2637 cg->ppd_line ++;
2638 col = 0;
2639
2640 if (ch == '\r')
2641 {
2642 /*
2643 * Check for a trailing line feed...
2644 */
2645
2646 if ((ch = cupsFilePeekChar(fp)) == EOF)
2647 break;
2648 if (ch == 0x0a)
2649 cupsFileGetChar(fp);
2650 }
2651
2652 break;
2653 }
2654 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
2655 {
2656 /*
2657 * Other control characters...
2658 */
2659
2660 cg->ppd_line = startline;
2661 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
2662
2663 free(line);
2664
2665 return (0);
2666 }
2667 else if (ch != 0x1a)
2668 {
2669 col ++;
2670
2671 if (col > (PPD_MAX_LINE - 1))
2672 {
2673 /*
2674 * Line is too long...
2675 */
2676
2677 cg->ppd_line = startline;
2678 cg->ppd_status = PPD_LINE_TOO_LONG;
2679
2680 free(line);
2681
2682 return (0);
2683 }
2684 }
2685 }
2686
2687 if (lineptr > line && lineptr[-1] == '\n')
2688 lineptr --;
2689
2690 *lineptr = '\0';
2691
2692 DEBUG_printf(("LINE = \"%s\"\n", line));
2693
2694 /*
2695 * The dynamically created PPDs for older style Mac OS X
2696 * drivers include a large blob of data inserted as comments
2697 * at the end of the file. As an optimization we can stop
2698 * reading the PPD when we get to the start of this data.
2699 */
2700
2701 if (!strcmp(line, "*%APLWORKSET START"))
2702 {
2703 free(line);
2704 return (0);
2705 }
2706
2707 if (ch == EOF && lineptr == line)
2708 {
2709 free(line);
2710 return (0);
2711 }
2712
2713 /*
2714 * Now parse it...
2715 */
2716
2717 mask = 0;
2718 lineptr = line + 1;
2719
2720 keyword[0] = '\0';
2721 option[0] = '\0';
2722 text[0] = '\0';
2723 *string = NULL;
2724
2725 if ((!line[0] || /* Blank line */
2726 !strncmp(line, "*%", 2) || /* Comment line */
2727 !strcmp(line, "*End")) && /* End of multi-line string */
2728 ignoreblank) /* Ignore these? */
2729 {
2730 startline = cg->ppd_line + 1;
2731 continue;
2732 }
2733
2734 if (!strcmp(line, "*")) /* (Bad) comment line */
2735 {
2736 if (cg->ppd_conform == PPD_CONFORM_RELAXED)
2737 {
2738 startline = cg->ppd_line + 1;
2739 continue;
2740 }
2741 else
2742 {
2743 cg->ppd_line = startline;
2744 cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
2745
2746 free(line);
2747 return (0);
2748 }
2749 }
2750
2751 if (line[0] != '*') /* All lines start with an asterisk */
2752 {
2753 /*
2754 * Allow lines consisting of just whitespace...
2755 */
2756
2757 for (lineptr = line; *lineptr; lineptr ++)
2758 if (!isspace(*lineptr & 255))
2759 break;
2760
2761 if (*lineptr)
2762 {
2763 cg->ppd_status = PPD_MISSING_ASTERISK;
2764 free(line);
2765 return (0);
2766 }
2767 else if (ignoreblank)
2768 continue;
2769 else
2770 {
2771 free(line);
2772 return (0);
2773 }
2774 }
2775
2776 /*
2777 * Get a keyword...
2778 */
2779
2780 keyptr = keyword;
2781
2782 while (*lineptr != '\0' && *lineptr != ':' && !isspace(*lineptr & 255))
2783 {
2784 if (*lineptr <= ' ' || *lineptr > 126 || *lineptr == '/' ||
2785 (keyptr - keyword) >= (PPD_MAX_NAME - 1))
2786 {
2787 cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
2788 free(line);
2789 return (0);
2790 }
2791
2792 *keyptr++ = *lineptr++;
2793 }
2794
2795 *keyptr = '\0';
2796
2797 if (!strcmp(keyword, "End"))
2798 continue;
2799
2800 mask |= PPD_KEYWORD;
2801
2802 /* DEBUG_printf(("keyword = \"%s\", lineptr = \"%s\"\n", keyword, lineptr));*/
2803
2804 if (isspace(*lineptr & 255))
2805 {
2806 /*
2807 * Get an option name...
2808 */
2809
2810 while (isspace(*lineptr & 255))
2811 lineptr ++;
2812
2813 optptr = option;
2814
2815 while (*lineptr != '\0' && !isspace(*lineptr & 255) && *lineptr != ':' &&
2816 *lineptr != '/')
2817 {
2818 if (*lineptr <= ' ' || *lineptr > 126 ||
2819 (optptr - option) >= (PPD_MAX_NAME - 1))
2820 {
2821 cg->ppd_status = PPD_ILLEGAL_OPTION_KEYWORD;
2822 free(line);
2823 return (0);
2824 }
2825
2826 *optptr++ = *lineptr++;
2827 }
2828
2829 *optptr = '\0';
2830
2831 if (isspace(*lineptr & 255) && cg->ppd_conform == PPD_CONFORM_STRICT)
2832 {
2833 cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
2834 free(line);
2835 return (0);
2836 }
2837
2838 while (isspace(*lineptr & 255))
2839 lineptr ++;
2840
2841 mask |= PPD_OPTION;
2842
2843 /* DEBUG_printf(("option = \"%s\", lineptr = \"%s\"\n", option, lineptr));*/
2844
2845 if (*lineptr == '/')
2846 {
2847 /*
2848 * Get human-readable text...
2849 */
2850
2851 lineptr ++;
2852
2853 textptr = text;
2854
2855 while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':')
2856 {
2857 if (((unsigned char)*lineptr < ' ' && *lineptr != '\t') ||
2858 (textptr - text) >= (PPD_MAX_LINE - 1))
2859 {
2860 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
2861 free(line);
2862 return (0);
2863 }
2864
2865 *textptr++ = *lineptr++;
2866 }
2867
2868 *textptr = '\0';
2869 textlen = ppd_decode(text);
2870
2871 if (textlen > PPD_MAX_TEXT && cg->ppd_conform == PPD_CONFORM_STRICT)
2872 {
2873 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
2874 free(line);
2875 return (0);
2876 }
2877
2878 mask |= PPD_TEXT;
2879 }
2880
2881 /* DEBUG_printf(("text = \"%s\", lineptr = \"%s\"\n", text, lineptr));*/
2882 }
2883
2884 if (isspace(*lineptr & 255) && cg->ppd_conform == PPD_CONFORM_STRICT)
2885 {
2886 cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
2887 free(line);
2888 return (0);
2889 }
2890
2891 while (isspace(*lineptr & 255))
2892 lineptr ++;
2893
2894 if (*lineptr == ':')
2895 {
2896 /*
2897 * Get string after triming leading and trailing whitespace...
2898 */
2899
2900 lineptr ++;
2901 while (isspace(*lineptr & 255))
2902 lineptr ++;
2903
2904 strptr = lineptr + strlen(lineptr) - 1;
2905 while (strptr >= lineptr && isspace(*strptr & 255))
2906 *strptr-- = '\0';
2907
2908 if (*strptr == '\"')
2909 {
2910 /*
2911 * Quoted string by itself...
2912 */
2913
2914 *string = malloc(strlen(lineptr) + 1);
2915
2916 strptr = *string;
2917
2918 for (; *lineptr != '\0'; lineptr ++)
2919 if (*lineptr != '\"')
2920 *strptr++ = *lineptr;
2921
2922 *strptr = '\0';
2923 }
2924 else
2925 *string = strdup(lineptr);
2926
2927 /* DEBUG_printf(("string = \"%s\", lineptr = \"%s\"\n", *string, lineptr));*/
2928
2929 mask |= PPD_STRING;
2930 }
2931 }
2932 while (mask == 0);
2933
2934 free(line);
2935
2936 return (mask);
2937 }
2938
2939
2940 /*
2941 * End of "$Id: ppd.c 5333 2006-03-24 00:52:21Z mike $".
2942 */