]> 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 5826 2006-08-15 19:04:11Z 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
2041 return (strcasecmp(a->spec, b->spec));
2042 }
2043
2044
2045 /*
2046 * 'ppd_compare_coptions()' - Compare two custom options.
2047 */
2048
2049 static int /* O - Result of comparison */
2050 ppd_compare_coptions(ppd_coption_t *a, /* I - First option */
2051 ppd_coption_t *b) /* I - Second option */
2052 {
2053 return (strcasecmp(a->keyword, b->keyword));
2054 }
2055
2056
2057 /*
2058 * 'ppd_compare_cparams()' - Compare two custom parameters.
2059 */
2060
2061 static int /* O - Result of comparison */
2062 ppd_compare_cparams(ppd_cparam_t *a, /* I - First parameter */
2063 ppd_cparam_t *b) /* I - Second parameter */
2064 {
2065 return (strcasecmp(a->name, b->name));
2066 }
2067
2068
2069 /*
2070 * 'ppd_compare_options()' - Compare two options.
2071 */
2072
2073 static int /* O - Result of comparison */
2074 ppd_compare_options(ppd_option_t *a, /* I - First option */
2075 ppd_option_t *b) /* I - Second option */
2076 {
2077 return (strcasecmp(a->keyword, b->keyword));
2078 }
2079
2080
2081 /*
2082 * 'ppd_decode()' - Decode a string value...
2083 */
2084
2085 static int /* O - Length of decoded string */
2086 ppd_decode(char *string) /* I - String to decode */
2087 {
2088 char *inptr, /* Input pointer */
2089 *outptr; /* Output pointer */
2090
2091
2092 inptr = string;
2093 outptr = string;
2094
2095 while (*inptr != '\0')
2096 if (*inptr == '<' && isxdigit(inptr[1] & 255))
2097 {
2098 /*
2099 * Convert hex to 8-bit values...
2100 */
2101
2102 inptr ++;
2103 while (isxdigit(*inptr & 255))
2104 {
2105 if (isalpha(*inptr))
2106 *outptr = (tolower(*inptr) - 'a' + 10) << 4;
2107 else
2108 *outptr = (*inptr - '0') << 4;
2109
2110 inptr ++;
2111
2112 if (!isxdigit(*inptr & 255))
2113 break;
2114
2115 if (isalpha(*inptr))
2116 *outptr |= tolower(*inptr) - 'a' + 10;
2117 else
2118 *outptr |= *inptr - '0';
2119
2120 inptr ++;
2121 outptr ++;
2122 }
2123
2124 while (*inptr != '>' && *inptr != '\0')
2125 inptr ++;
2126 while (*inptr == '>')
2127 inptr ++;
2128 }
2129 else
2130 *outptr++ = *inptr++;
2131
2132 *outptr = '\0';
2133
2134 return ((int)(outptr - string));
2135 }
2136
2137
2138 /*
2139 * 'ppd_free_group()' - Free a single UI group.
2140 */
2141
2142 static void
2143 ppd_free_group(ppd_group_t *group) /* I - Group to free */
2144 {
2145 int i; /* Looping var */
2146 ppd_option_t *option; /* Current option */
2147 ppd_group_t *subgroup; /* Current sub-group */
2148
2149
2150 if (group->num_options > 0)
2151 {
2152 for (i = group->num_options, option = group->options;
2153 i > 0;
2154 i --, option ++)
2155 ppd_free_option(option);
2156
2157 ppd_free(group->options);
2158 }
2159
2160 if (group->num_subgroups > 0)
2161 {
2162 for (i = group->num_subgroups, subgroup = group->subgroups;
2163 i > 0;
2164 i --, subgroup ++)
2165 ppd_free_group(subgroup);
2166
2167 ppd_free(group->subgroups);
2168 }
2169 }
2170
2171
2172 /*
2173 * 'ppd_free_option()' - Free a single option.
2174 */
2175
2176 static void
2177 ppd_free_option(ppd_option_t *option) /* I - Option to free */
2178 {
2179 int i; /* Looping var */
2180 ppd_choice_t *choice; /* Current choice */
2181
2182
2183 if (option->num_choices > 0)
2184 {
2185 for (i = option->num_choices, choice = option->choices;
2186 i > 0;
2187 i --, choice ++)
2188 {
2189 ppd_free(choice->code);
2190 }
2191
2192 ppd_free(option->choices);
2193 }
2194 }
2195
2196
2197 /*
2198 * 'ppd_get_coption()' - Get a custom option record.
2199 */
2200
2201 static ppd_coption_t * /* O - Custom option... */
2202 ppd_get_coption(ppd_file_t *ppd, /* I - PPD file */
2203 const char *name) /* I - Name of option */
2204 {
2205 ppd_coption_t *copt; /* New custom option */
2206
2207
2208 /*
2209 * See if the option already exists...
2210 */
2211
2212 if ((copt = ppdFindCustomOption(ppd, name)) != NULL)
2213 return (copt);
2214
2215 /*
2216 * Not found, so create the custom option record...
2217 */
2218
2219 if ((copt = calloc(1, sizeof(ppd_coption_t))) == NULL)
2220 return (NULL);
2221
2222 strlcpy(copt->keyword, name, sizeof(copt->keyword));
2223
2224 copt->params = cupsArrayNew((cups_array_func_t)ppd_compare_cparams, NULL);
2225
2226 cupsArrayAdd(ppd->coptions, copt);
2227
2228 /*
2229 * Return the new record...
2230 */
2231
2232 return (copt);
2233 }
2234
2235
2236 /*
2237 * 'ppd_get_cparam()' - Get a custom parameter record.
2238 */
2239
2240 static ppd_cparam_t * /* O - Extended option... */
2241 ppd_get_cparam(ppd_coption_t *opt, /* I - PPD file */
2242 const char *param, /* I - Name of parameter */
2243 const char *text) /* I - Human-readable text */
2244 {
2245 ppd_cparam_t *cparam; /* New custom parameter */
2246
2247
2248 /*
2249 * See if the parameter already exists...
2250 */
2251
2252 if ((cparam = ppdFindCustomParam(opt, param)) != NULL)
2253 return (cparam);
2254
2255 /*
2256 * Not found, so create the custom parameter record...
2257 */
2258
2259 if ((cparam = calloc(1, sizeof(ppd_cparam_t))) == NULL)
2260 return (NULL);
2261
2262 strlcpy(cparam->name, param, sizeof(cparam->name));
2263 strlcpy(cparam->text, text, sizeof(cparam->text));
2264
2265 /*
2266 * Add this record to the array...
2267 */
2268
2269 cupsArrayAdd(opt->params, cparam);
2270
2271 /*
2272 * Return the new record...
2273 */
2274
2275 return (cparam);
2276 }
2277
2278
2279 /*
2280 * 'ppd_get_group()' - Find or create the named group as needed.
2281 */
2282
2283 static ppd_group_t * /* O - Named group */
2284 ppd_get_group(ppd_file_t *ppd, /* I - PPD file */
2285 const char *name, /* I - Name of group */
2286 const char *text, /* I - Text for group */
2287 _cups_globals_t *cg, /* I - Global data */
2288 cups_encoding_t encoding) /* I - Encoding of text */
2289 {
2290 int i; /* Looping var */
2291 ppd_group_t *group; /* Group */
2292
2293
2294 DEBUG_printf(("ppd_get_group(ppd=%p, name=\"%s\", text=\"%s\", cg=%p)\n",
2295 ppd, name, text, cg));
2296
2297 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
2298 if (!strcmp(group->name, name))
2299 break;
2300
2301 if (i == 0)
2302 {
2303 DEBUG_printf(("Adding group %s...\n", name));
2304
2305 if (cg->ppd_conform == PPD_CONFORM_STRICT && strlen(text) >= sizeof(group->text))
2306 {
2307 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
2308
2309 return (NULL);
2310 }
2311
2312 if (ppd->num_groups == 0)
2313 group = malloc(sizeof(ppd_group_t));
2314 else
2315 group = realloc(ppd->groups,
2316 (ppd->num_groups + 1) * sizeof(ppd_group_t));
2317
2318 if (group == NULL)
2319 {
2320 cg->ppd_status = PPD_ALLOC_ERROR;
2321
2322 return (NULL);
2323 }
2324
2325 ppd->groups = group;
2326 group += ppd->num_groups;
2327 ppd->num_groups ++;
2328
2329 memset(group, 0, sizeof(ppd_group_t));
2330 strlcpy(group->name, name, sizeof(group->name));
2331
2332 cupsCharsetToUTF8((cups_utf8_t *)group->text, text,
2333 sizeof(group->text), encoding);
2334 }
2335
2336 return (group);
2337 }
2338
2339
2340 /*
2341 * 'ppd_get_option()' - Find or create the named option as needed.
2342 */
2343
2344 static ppd_option_t * /* O - Named option */
2345 ppd_get_option(ppd_group_t *group, /* I - Group */
2346 const char *name) /* I - Name of option */
2347 {
2348 int i; /* Looping var */
2349 ppd_option_t *option; /* Option */
2350
2351
2352 DEBUG_printf(("ppd_get_option(group=%p(\"%s\"), name=\"%s\")\n",
2353 group, group->name, name));
2354
2355 for (i = group->num_options, option = group->options; i > 0; i --, option ++)
2356 if (!strcmp(option->keyword, name))
2357 break;
2358
2359 if (i == 0)
2360 {
2361 if (group->num_options == 0)
2362 option = malloc(sizeof(ppd_option_t));
2363 else
2364 option = realloc(group->options,
2365 (group->num_options + 1) * sizeof(ppd_option_t));
2366
2367 if (option == NULL)
2368 return (NULL);
2369
2370 group->options = option;
2371 option += group->num_options;
2372 group->num_options ++;
2373
2374 memset(option, 0, sizeof(ppd_option_t));
2375 strlcpy(option->keyword, name, sizeof(option->keyword));
2376 }
2377
2378 return (option);
2379 }
2380
2381
2382 /*
2383 * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
2384 * necessary.
2385 */
2386
2387 static int /* O - Bitmask of fields read */
2388 ppd_read(cups_file_t *fp, /* I - File to read from */
2389 char *keyword, /* O - Keyword from line */
2390 char *option, /* O - Option from line */
2391 char *text, /* O - Human-readable text from line */
2392 char **string, /* O - Code/string data */
2393 int ignoreblank, /* I - Ignore blank lines? */
2394 _cups_globals_t *cg) /* I - Global data */
2395 {
2396 int ch, /* Character from file */
2397 col, /* Column in line */
2398 colon, /* Colon seen? */
2399 endquote, /* Waiting for an end quote */
2400 mask, /* Mask to be returned */
2401 startline, /* Start line */
2402 textlen; /* Length of text */
2403 char *keyptr, /* Keyword pointer */
2404 *optptr, /* Option pointer */
2405 *textptr, /* Text pointer */
2406 *strptr, /* Pointer into string */
2407 *lineptr, /* Current position in line buffer */
2408 *line; /* Line buffer */
2409 int linesize; /* Current size of line buffer */
2410
2411 /*
2412 * Range check everything...
2413 */
2414
2415 if (!fp || !keyword || !option || !text || !string)
2416 return (0);
2417
2418 /*
2419 * Now loop until we have a valid line...
2420 */
2421
2422 *string = NULL;
2423 col = 0;
2424 startline = cg->ppd_line + 1;
2425 linesize = 1024;
2426 line = malloc(linesize);
2427
2428 if (!line)
2429 return (0);
2430
2431 do
2432 {
2433 /*
2434 * Read the line...
2435 */
2436
2437 lineptr = line;
2438 endquote = 0;
2439 colon = 0;
2440
2441 while ((ch = cupsFileGetChar(fp)) != EOF)
2442 {
2443 if (lineptr >= (line + linesize - 1))
2444 {
2445 /*
2446 * Expand the line buffer...
2447 */
2448
2449 char *temp; /* Temporary line pointer */
2450
2451
2452 linesize += 1024;
2453 if (linesize > 262144)
2454 {
2455 /*
2456 * Don't allow lines longer than 256k!
2457 */
2458
2459 cg->ppd_line = startline;
2460 cg->ppd_status = PPD_LINE_TOO_LONG;
2461
2462 free(line);
2463
2464 return (0);
2465 }
2466
2467 temp = realloc(line, linesize);
2468 if (!temp)
2469 {
2470 cg->ppd_line = startline;
2471 cg->ppd_status = PPD_LINE_TOO_LONG;
2472
2473 free(line);
2474
2475 return (0);
2476 }
2477
2478 lineptr = temp + (lineptr - line);
2479 line = temp;
2480 }
2481
2482 if (ch == '\r' || ch == '\n')
2483 {
2484 /*
2485 * Line feed or carriage return...
2486 */
2487
2488 cg->ppd_line ++;
2489 col = 0;
2490
2491 if (ch == '\r')
2492 {
2493 /*
2494 * Check for a trailing line feed...
2495 */
2496
2497 if ((ch = cupsFilePeekChar(fp)) == EOF)
2498 {
2499 ch = '\n';
2500 break;
2501 }
2502
2503 if (ch == 0x0a)
2504 cupsFileGetChar(fp);
2505 }
2506
2507 if (lineptr == line && ignoreblank)
2508 continue; /* Skip blank lines */
2509
2510 ch = '\n';
2511
2512 if (!endquote) /* Continue for multi-line text */
2513 break;
2514
2515 *lineptr++ = '\n';
2516 }
2517 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
2518 {
2519 /*
2520 * Other control characters...
2521 */
2522
2523 cg->ppd_line = startline;
2524 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
2525
2526 free(line);
2527
2528 return (0);
2529 }
2530 else if (ch != 0x1a)
2531 {
2532 /*
2533 * Any other character...
2534 */
2535
2536 *lineptr++ = ch;
2537 col ++;
2538
2539 if (col > (PPD_MAX_LINE - 1))
2540 {
2541 /*
2542 * Line is too long...
2543 */
2544
2545 cg->ppd_line = startline;
2546 cg->ppd_status = PPD_LINE_TOO_LONG;
2547
2548 free(line);
2549
2550 return (0);
2551 }
2552
2553 if (ch == ':' && strncmp(line, "*%", 2) != 0)
2554 colon = 1;
2555
2556 if (ch == '\"' && colon)
2557 endquote = !endquote;
2558 }
2559 }
2560
2561 if (endquote)
2562 {
2563 /*
2564 * Didn't finish this quoted string...
2565 */
2566
2567 while ((ch = cupsFileGetChar(fp)) != EOF)
2568 if (ch == '\"')
2569 break;
2570 else if (ch == '\r' || ch == '\n')
2571 {
2572 cg->ppd_line ++;
2573 col = 0;
2574
2575 if (ch == '\r')
2576 {
2577 /*
2578 * Check for a trailing line feed...
2579 */
2580
2581 if ((ch = cupsFilePeekChar(fp)) == EOF)
2582 break;
2583 if (ch == 0x0a)
2584 cupsFileGetChar(fp);
2585 }
2586
2587 ch = '\n';
2588 }
2589 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
2590 {
2591 /*
2592 * Other control characters...
2593 */
2594
2595 cg->ppd_line = startline;
2596 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
2597
2598 free(line);
2599
2600 return (0);
2601 }
2602 else if (ch != 0x1a)
2603 {
2604 col ++;
2605
2606 if (col > (PPD_MAX_LINE - 1))
2607 {
2608 /*
2609 * Line is too long...
2610 */
2611
2612 cg->ppd_line = startline;
2613 cg->ppd_status = PPD_LINE_TOO_LONG;
2614
2615 free(line);
2616
2617 return (0);
2618 }
2619 }
2620 }
2621
2622 if (ch != '\n')
2623 {
2624 /*
2625 * Didn't finish this line...
2626 */
2627
2628 while ((ch = cupsFileGetChar(fp)) != EOF)
2629 if (ch == '\r' || ch == '\n')
2630 {
2631 /*
2632 * Line feed or carriage return...
2633 */
2634
2635 cg->ppd_line ++;
2636 col = 0;
2637
2638 if (ch == '\r')
2639 {
2640 /*
2641 * Check for a trailing line feed...
2642 */
2643
2644 if ((ch = cupsFilePeekChar(fp)) == EOF)
2645 break;
2646 if (ch == 0x0a)
2647 cupsFileGetChar(fp);
2648 }
2649
2650 break;
2651 }
2652 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
2653 {
2654 /*
2655 * Other control characters...
2656 */
2657
2658 cg->ppd_line = startline;
2659 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
2660
2661 free(line);
2662
2663 return (0);
2664 }
2665 else if (ch != 0x1a)
2666 {
2667 col ++;
2668
2669 if (col > (PPD_MAX_LINE - 1))
2670 {
2671 /*
2672 * Line is too long...
2673 */
2674
2675 cg->ppd_line = startline;
2676 cg->ppd_status = PPD_LINE_TOO_LONG;
2677
2678 free(line);
2679
2680 return (0);
2681 }
2682 }
2683 }
2684
2685 if (lineptr > line && lineptr[-1] == '\n')
2686 lineptr --;
2687
2688 *lineptr = '\0';
2689
2690 DEBUG_printf(("LINE = \"%s\"\n", line));
2691
2692 /*
2693 * The dynamically created PPDs for older style Mac OS X
2694 * drivers include a large blob of data inserted as comments
2695 * at the end of the file. As an optimization we can stop
2696 * reading the PPD when we get to the start of this data.
2697 */
2698
2699 if (!strcmp(line, "*%APLWORKSET START"))
2700 {
2701 free(line);
2702 return (0);
2703 }
2704
2705 if (ch == EOF && lineptr == line)
2706 {
2707 free(line);
2708 return (0);
2709 }
2710
2711 /*
2712 * Now parse it...
2713 */
2714
2715 mask = 0;
2716 lineptr = line + 1;
2717
2718 keyword[0] = '\0';
2719 option[0] = '\0';
2720 text[0] = '\0';
2721 *string = NULL;
2722
2723 if ((!line[0] || /* Blank line */
2724 !strncmp(line, "*%", 2) || /* Comment line */
2725 !strcmp(line, "*End")) && /* End of multi-line string */
2726 ignoreblank) /* Ignore these? */
2727 {
2728 startline = cg->ppd_line + 1;
2729 continue;
2730 }
2731
2732 if (!strcmp(line, "*")) /* (Bad) comment line */
2733 {
2734 if (cg->ppd_conform == PPD_CONFORM_RELAXED)
2735 {
2736 startline = cg->ppd_line + 1;
2737 continue;
2738 }
2739 else
2740 {
2741 cg->ppd_line = startline;
2742 cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
2743
2744 free(line);
2745 return (0);
2746 }
2747 }
2748
2749 if (line[0] != '*') /* All lines start with an asterisk */
2750 {
2751 /*
2752 * Allow lines consisting of just whitespace...
2753 */
2754
2755 for (lineptr = line; *lineptr; lineptr ++)
2756 if (!isspace(*lineptr & 255))
2757 break;
2758
2759 if (*lineptr)
2760 {
2761 cg->ppd_status = PPD_MISSING_ASTERISK;
2762 free(line);
2763 return (0);
2764 }
2765 else if (ignoreblank)
2766 continue;
2767 else
2768 {
2769 free(line);
2770 return (0);
2771 }
2772 }
2773
2774 /*
2775 * Get a keyword...
2776 */
2777
2778 keyptr = keyword;
2779
2780 while (*lineptr != '\0' && *lineptr != ':' && !isspace(*lineptr & 255))
2781 {
2782 if (*lineptr <= ' ' || *lineptr > 126 || *lineptr == '/' ||
2783 (keyptr - keyword) >= (PPD_MAX_NAME - 1))
2784 {
2785 cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
2786 free(line);
2787 return (0);
2788 }
2789
2790 *keyptr++ = *lineptr++;
2791 }
2792
2793 *keyptr = '\0';
2794
2795 if (!strcmp(keyword, "End"))
2796 continue;
2797
2798 mask |= PPD_KEYWORD;
2799
2800 /* DEBUG_printf(("keyword = \"%s\", lineptr = \"%s\"\n", keyword, lineptr));*/
2801
2802 if (isspace(*lineptr & 255))
2803 {
2804 /*
2805 * Get an option name...
2806 */
2807
2808 while (isspace(*lineptr & 255))
2809 lineptr ++;
2810
2811 optptr = option;
2812
2813 while (*lineptr != '\0' && !isspace(*lineptr & 255) && *lineptr != ':' &&
2814 *lineptr != '/')
2815 {
2816 if (*lineptr <= ' ' || *lineptr > 126 ||
2817 (optptr - option) >= (PPD_MAX_NAME - 1))
2818 {
2819 cg->ppd_status = PPD_ILLEGAL_OPTION_KEYWORD;
2820 free(line);
2821 return (0);
2822 }
2823
2824 *optptr++ = *lineptr++;
2825 }
2826
2827 *optptr = '\0';
2828
2829 if (isspace(*lineptr & 255) && cg->ppd_conform == PPD_CONFORM_STRICT)
2830 {
2831 cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
2832 free(line);
2833 return (0);
2834 }
2835
2836 while (isspace(*lineptr & 255))
2837 lineptr ++;
2838
2839 mask |= PPD_OPTION;
2840
2841 /* DEBUG_printf(("option = \"%s\", lineptr = \"%s\"\n", option, lineptr));*/
2842
2843 if (*lineptr == '/')
2844 {
2845 /*
2846 * Get human-readable text...
2847 */
2848
2849 lineptr ++;
2850
2851 textptr = text;
2852
2853 while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':')
2854 {
2855 if (((unsigned char)*lineptr < ' ' && *lineptr != '\t') ||
2856 (textptr - text) >= (PPD_MAX_LINE - 1))
2857 {
2858 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
2859 free(line);
2860 return (0);
2861 }
2862
2863 *textptr++ = *lineptr++;
2864 }
2865
2866 *textptr = '\0';
2867 textlen = ppd_decode(text);
2868
2869 if (textlen > PPD_MAX_TEXT && cg->ppd_conform == PPD_CONFORM_STRICT)
2870 {
2871 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
2872 free(line);
2873 return (0);
2874 }
2875
2876 mask |= PPD_TEXT;
2877 }
2878
2879 /* DEBUG_printf(("text = \"%s\", lineptr = \"%s\"\n", text, lineptr));*/
2880 }
2881
2882 if (isspace(*lineptr & 255) && cg->ppd_conform == PPD_CONFORM_STRICT)
2883 {
2884 cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
2885 free(line);
2886 return (0);
2887 }
2888
2889 while (isspace(*lineptr & 255))
2890 lineptr ++;
2891
2892 if (*lineptr == ':')
2893 {
2894 /*
2895 * Get string after triming leading and trailing whitespace...
2896 */
2897
2898 lineptr ++;
2899 while (isspace(*lineptr & 255))
2900 lineptr ++;
2901
2902 strptr = lineptr + strlen(lineptr) - 1;
2903 while (strptr >= lineptr && isspace(*strptr & 255))
2904 *strptr-- = '\0';
2905
2906 if (*strptr == '\"')
2907 {
2908 /*
2909 * Quoted string by itself...
2910 */
2911
2912 *string = malloc(strlen(lineptr) + 1);
2913
2914 strptr = *string;
2915
2916 for (; *lineptr != '\0'; lineptr ++)
2917 if (*lineptr != '\"')
2918 *strptr++ = *lineptr;
2919
2920 *strptr = '\0';
2921 }
2922 else
2923 *string = strdup(lineptr);
2924
2925 /* DEBUG_printf(("string = \"%s\", lineptr = \"%s\"\n", *string, lineptr));*/
2926
2927 mask |= PPD_STRING;
2928 }
2929 }
2930 while (mask == 0);
2931
2932 free(line);
2933
2934 return (mask);
2935 }
2936
2937
2938 /*
2939 * End of "$Id: ppd.c 5826 2006-08-15 19:04:11Z mike $".
2940 */