]> 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 6445 2007-04-04 23:43:26Z mike $"
3 *
4 * PPD file routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2007 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 = (float)_cupsStrScand(string, &sptr, loc);
823 profile->gamma = (float)_cupsStrScand(sptr, &sptr, loc);
824 profile->matrix[0][0] = (float)_cupsStrScand(sptr, &sptr, loc);
825 profile->matrix[0][1] = (float)_cupsStrScand(sptr, &sptr, loc);
826 profile->matrix[0][2] = (float)_cupsStrScand(sptr, &sptr, loc);
827 profile->matrix[1][0] = (float)_cupsStrScand(sptr, &sptr, loc);
828 profile->matrix[1][1] = (float)_cupsStrScand(sptr, &sptr, loc);
829 profile->matrix[1][2] = (float)_cupsStrScand(sptr, &sptr, loc);
830 profile->matrix[2][0] = (float)_cupsStrScand(sptr, &sptr, loc);
831 profile->matrix[2][1] = (float)_cupsStrScand(sptr, &sptr, loc);
832 profile->matrix[2][2] = (float)_cupsStrScand(sptr, &sptr, loc);
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 = (float)_cupsStrScand(cminimum, NULL, loc);
932 cparam->maximum.custom_curve = (float)_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 = (float)_cupsStrScand(cminimum, NULL, loc);
944 cparam->maximum.custom_invcurve = (float)_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 = (float)_cupsStrScand(cminimum, NULL, loc);
962 cparam->maximum.custom_points = (float)_cupsStrScand(cmaximum, NULL, loc);
963 }
964 else if (!strcmp(ctype, "real"))
965 {
966 cparam->type = PPD_CUSTOM_REAL;
967 cparam->minimum.custom_real = (float)_cupsStrScand(cminimum, NULL, loc);
968 cparam->maximum.custom_real = (float)_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] = (float)_cupsStrScand(sptr, &sptr, loc);
1005 }
1006 else if (!strncmp(keyword, "Custom", 6) && !strcmp(name, "True") && !option)
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 if ((option = ppdFindOption(ppd, "PageRegion")) == NULL)
1081 {
1082 ppd_group_t *gtemp; /* Temporary group */
1083
1084 if ((gtemp = ppd_get_group(ppd, "General", _("General"), cg,
1085 encoding)) == NULL)
1086 {
1087 DEBUG_puts("Unable to get general group!");
1088
1089 goto error;
1090 }
1091
1092 option = ppd_get_option(gtemp, "PageRegion");
1093 }
1094
1095 if ((choice = ppd_add_choice(option, "Custom")) == NULL)
1096 {
1097 DEBUG_puts("Unable to add Custom choice!");
1098
1099 cg->ppd_status = PPD_ALLOC_ERROR;
1100
1101 goto error;
1102 }
1103
1104 strlcpy(choice->text, text[0] ? text : _("Custom"),
1105 sizeof(choice->text));
1106 option = NULL;
1107 }
1108 }
1109 else if (!strcmp(keyword, "LandscapeOrientation"))
1110 {
1111 if (!strcmp(string, "Minus90"))
1112 ppd->landscape = -90;
1113 else if (!strcmp(string, "Plus90"))
1114 ppd->landscape = 90;
1115 }
1116 else if (!strcmp(keyword, "Emulators"))
1117 {
1118 for (count = 1, sptr = string; sptr != NULL;)
1119 if ((sptr = strchr(sptr, ' ')) != NULL)
1120 {
1121 count ++;
1122 while (*sptr == ' ')
1123 sptr ++;
1124 }
1125
1126 ppd->num_emulations = count;
1127 ppd->emulations = calloc(count, sizeof(ppd_emul_t));
1128
1129 for (i = 0, sptr = string; i < count; i ++)
1130 {
1131 for (nameptr = ppd->emulations[i].name;
1132 *sptr != '\0' && *sptr != ' ';
1133 sptr ++)
1134 if (nameptr < (ppd->emulations[i].name + sizeof(ppd->emulations[i].name) - 1))
1135 *nameptr++ = *sptr;
1136
1137 *nameptr = '\0';
1138
1139 while (*sptr == ' ')
1140 sptr ++;
1141 }
1142 }
1143 else if (!strncmp(keyword, "StartEmulator_", 14))
1144 {
1145 ppd_decode(string);
1146
1147 for (i = 0; i < ppd->num_emulations; i ++)
1148 if (!strcmp(keyword + 14, ppd->emulations[i].name))
1149 {
1150 ppd->emulations[i].start = string;
1151 string = NULL;
1152 }
1153 }
1154 else if (!strncmp(keyword, "StopEmulator_", 13))
1155 {
1156 ppd_decode(string);
1157
1158 for (i = 0; i < ppd->num_emulations; i ++)
1159 if (!strcmp(keyword + 13, ppd->emulations[i].name))
1160 {
1161 ppd->emulations[i].stop = string;
1162 string = NULL;
1163 }
1164 }
1165 else if (!strcmp(keyword, "JobPatchFile"))
1166 {
1167 if (ppd->patches == NULL)
1168 ppd->patches = strdup(string);
1169 else
1170 {
1171 temp = realloc(ppd->patches, strlen(ppd->patches) +
1172 strlen(string) + 1);
1173 if (temp == NULL)
1174 {
1175 cg->ppd_status = PPD_ALLOC_ERROR;
1176
1177 goto error;
1178 }
1179
1180 ppd->patches = temp;
1181
1182 strcpy(ppd->patches + strlen(ppd->patches), string);
1183 }
1184 }
1185 else if (!strcmp(keyword, "OpenUI"))
1186 {
1187 /*
1188 * Don't allow nesting of options...
1189 */
1190
1191 if (option && cg->ppd_conform == PPD_CONFORM_STRICT)
1192 {
1193 cg->ppd_status = PPD_NESTED_OPEN_UI;
1194
1195 goto error;
1196 }
1197
1198 /*
1199 * Add an option record to the current sub-group, group, or file...
1200 */
1201
1202 if (name[0] == '*')
1203 _cups_strcpy(name, name + 1); /* Eliminate leading asterisk */
1204
1205 for (i = (int)strlen(name) - 1; i > 0 && isspace(name[i] & 255); i --)
1206 name[i] = '\0'; /* Eliminate trailing spaces */
1207
1208 DEBUG_printf(("OpenUI of %s in group %s...\n", name,
1209 group ? group->text : "(null)"));
1210
1211 if (subgroup != NULL)
1212 option = ppd_get_option(subgroup, name);
1213 else if (group == NULL)
1214 {
1215 if ((group = ppd_get_group(ppd, "General", _("General"), cg,
1216 encoding)) == NULL)
1217 goto error;
1218
1219 DEBUG_printf(("Adding to group %s...\n", group->text));
1220 option = ppd_get_option(group, name);
1221 group = NULL;
1222 }
1223 else
1224 option = ppd_get_option(group, name);
1225
1226 if (option == NULL)
1227 {
1228 cg->ppd_status = PPD_ALLOC_ERROR;
1229
1230 goto error;
1231 }
1232
1233 /*
1234 * Now fill in the initial information for the option...
1235 */
1236
1237 if (string && !strcmp(string, "PickMany"))
1238 option->ui = PPD_UI_PICKMANY;
1239 else if (string && !strcmp(string, "Boolean"))
1240 option->ui = PPD_UI_BOOLEAN;
1241 else if (string && !strcmp(string, "PickOne"))
1242 option->ui = PPD_UI_PICKONE;
1243 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1244 {
1245 cg->ppd_status = PPD_BAD_OPEN_UI;
1246
1247 goto error;
1248 }
1249 else
1250 option->ui = PPD_UI_PICKONE;
1251
1252 for (j = 0; j < ppd->num_attrs; j ++)
1253 if (!strncmp(ppd->attrs[j]->name, "Default", 7) &&
1254 !strcmp(ppd->attrs[j]->name + 7, name) &&
1255 ppd->attrs[j]->value)
1256 {
1257 DEBUG_printf(("Setting Default%s to %s via attribute...\n",
1258 option->keyword, ppd->attrs[j]->value));
1259 strlcpy(option->defchoice, ppd->attrs[j]->value,
1260 sizeof(option->defchoice));
1261 break;
1262 }
1263
1264 if (text[0])
1265 cupsCharsetToUTF8((cups_utf8_t *)option->text, text,
1266 sizeof(option->text), encoding);
1267 else
1268 {
1269 if (!strcmp(name, "PageSize"))
1270 strlcpy(option->text, _("Media Size"), sizeof(option->text));
1271 else if (!strcmp(name, "MediaType"))
1272 strlcpy(option->text, _("Media Type"), sizeof(option->text));
1273 else if (!strcmp(name, "InputSlot"))
1274 strlcpy(option->text, _("Media Source"), sizeof(option->text));
1275 else if (!strcmp(name, "ColorModel"))
1276 strlcpy(option->text, _("Output Mode"), sizeof(option->text));
1277 else if (!strcmp(name, "Resolution"))
1278 strlcpy(option->text, _("Resolution"), sizeof(option->text));
1279 else
1280 strlcpy(option->text, name, sizeof(option->text));
1281 }
1282
1283 option->section = PPD_ORDER_ANY;
1284
1285 ppd_free(string);
1286 string = NULL;
1287 }
1288 else if (!strcmp(keyword, "JCLOpenUI"))
1289 {
1290 /*
1291 * Don't allow nesting of options...
1292 */
1293
1294 if (option && cg->ppd_conform == PPD_CONFORM_STRICT)
1295 {
1296 cg->ppd_status = PPD_NESTED_OPEN_UI;
1297
1298 goto error;
1299 }
1300
1301 /*
1302 * Find the JCL group, and add if needed...
1303 */
1304
1305 group = ppd_get_group(ppd, "JCL", _("JCL"), cg, encoding);
1306
1307 if (group == NULL)
1308 goto error;
1309
1310 /*
1311 * Add an option record to the current JCLs...
1312 */
1313
1314 if (name[0] == '*')
1315 _cups_strcpy(name, name + 1);
1316
1317 option = ppd_get_option(group, name);
1318
1319 if (option == NULL)
1320 {
1321 cg->ppd_status = PPD_ALLOC_ERROR;
1322
1323 goto error;
1324 }
1325
1326 /*
1327 * Now fill in the initial information for the option...
1328 */
1329
1330 if (string && !strcmp(string, "PickMany"))
1331 option->ui = PPD_UI_PICKMANY;
1332 else if (string && !strcmp(string, "Boolean"))
1333 option->ui = PPD_UI_BOOLEAN;
1334 else if (string && !strcmp(string, "PickOne"))
1335 option->ui = PPD_UI_PICKONE;
1336 else
1337 {
1338 cg->ppd_status = PPD_BAD_OPEN_UI;
1339
1340 goto error;
1341 }
1342
1343 for (j = 0; j < ppd->num_attrs; j ++)
1344 if (!strncmp(ppd->attrs[j]->name, "Default", 7) &&
1345 !strcmp(ppd->attrs[j]->name + 7, name) &&
1346 ppd->attrs[j]->value)
1347 {
1348 DEBUG_printf(("Setting Default%s to %s via attribute...\n",
1349 option->keyword, ppd->attrs[j]->value));
1350 strlcpy(option->defchoice, ppd->attrs[j]->value,
1351 sizeof(option->defchoice));
1352 break;
1353 }
1354
1355 if (text[0])
1356 cupsCharsetToUTF8((cups_utf8_t *)option->text, text,
1357 sizeof(option->text), encoding);
1358 else
1359 strlcpy(option->text, name, sizeof(option->text));
1360
1361 option->section = PPD_ORDER_JCL;
1362 group = NULL;
1363
1364 ppd_free(string);
1365 string = NULL;
1366 }
1367 else if (!strcmp(keyword, "CloseUI") || !strcmp(keyword, "JCLCloseUI"))
1368 {
1369 option = NULL;
1370
1371 ppd_free(string);
1372 string = NULL;
1373 }
1374 else if (!strcmp(keyword, "OpenGroup"))
1375 {
1376 /*
1377 * Open a new group...
1378 */
1379
1380 if (group != NULL)
1381 {
1382 cg->ppd_status = PPD_NESTED_OPEN_GROUP;
1383
1384 goto error;
1385 }
1386
1387 if (!string)
1388 {
1389 cg->ppd_status = PPD_BAD_OPEN_GROUP;
1390
1391 goto error;
1392 }
1393
1394 /*
1395 * Separate the group name from the text (name/text)...
1396 */
1397
1398 if ((sptr = strchr(string, '/')) != NULL)
1399 *sptr++ = '\0';
1400 else
1401 sptr = string;
1402
1403 /*
1404 * Fix up the text...
1405 */
1406
1407 ppd_decode(sptr);
1408
1409 /*
1410 * Find/add the group...
1411 */
1412
1413 group = ppd_get_group(ppd, string, sptr, cg, encoding);
1414
1415 if (group == NULL)
1416 goto error;
1417
1418 ppd_free(string);
1419 string = NULL;
1420 }
1421 else if (!strcmp(keyword, "CloseGroup"))
1422 {
1423 group = NULL;
1424
1425 ppd_free(string);
1426 string = NULL;
1427 }
1428 else if (!strcmp(keyword, "OrderDependency") ||
1429 !strcmp(keyword, "NonUIOrderDependency"))
1430 {
1431 order = (float)_cupsStrScand(string, &sptr, loc);
1432
1433 if (!sptr || sscanf(sptr, "%40s%40s", name, keyword) != 2)
1434 {
1435 cg->ppd_status = PPD_BAD_ORDER_DEPENDENCY;
1436
1437 goto error;
1438 }
1439
1440 if (keyword[0] == '*')
1441 _cups_strcpy(keyword, keyword + 1);
1442
1443 if (!strcmp(name, "ExitServer"))
1444 section = PPD_ORDER_EXIT;
1445 else if (!strcmp(name, "Prolog"))
1446 section = PPD_ORDER_PROLOG;
1447 else if (!strcmp(name, "DocumentSetup"))
1448 section = PPD_ORDER_DOCUMENT;
1449 else if (!strcmp(name, "PageSetup"))
1450 section = PPD_ORDER_PAGE;
1451 else if (!strcmp(name, "JCLSetup"))
1452 section = PPD_ORDER_JCL;
1453 else
1454 section = PPD_ORDER_ANY;
1455
1456 if (option == NULL)
1457 {
1458 ppd_group_t *gtemp;
1459
1460
1461 /*
1462 * Only valid for Non-UI options...
1463 */
1464
1465 for (i = ppd->num_groups, gtemp = ppd->groups; i > 0; i --, gtemp ++)
1466 if (gtemp->text[0] == '\0')
1467 break;
1468
1469 if (i > 0)
1470 for (i = 0; i < gtemp->num_options; i ++)
1471 if (!strcmp(keyword, gtemp->options[i].keyword))
1472 {
1473 gtemp->options[i].section = section;
1474 gtemp->options[i].order = order;
1475 break;
1476 }
1477 }
1478 else
1479 {
1480 option->section = section;
1481 option->order = order;
1482 }
1483
1484 ppd_free(string);
1485 string = NULL;
1486 }
1487 else if (!strncmp(keyword, "Default", 7))
1488 {
1489 if (string == NULL)
1490 continue;
1491
1492 /*
1493 * Drop UI text, if any, from value...
1494 */
1495
1496 if (strchr(string, '/') != NULL)
1497 *strchr(string, '/') = '\0';
1498
1499 /*
1500 * Assign the default value as appropriate...
1501 */
1502
1503 if (!strcmp(keyword, "DefaultColorSpace"))
1504 {
1505 /*
1506 * Set default colorspace...
1507 */
1508
1509 if (!strcmp(string, "CMY"))
1510 ppd->colorspace = PPD_CS_CMY;
1511 else if (!strcmp(string, "CMYK"))
1512 ppd->colorspace = PPD_CS_CMYK;
1513 else if (!strcmp(string, "RGB"))
1514 ppd->colorspace = PPD_CS_RGB;
1515 else if (!strcmp(string, "RGBK"))
1516 ppd->colorspace = PPD_CS_RGBK;
1517 else if (!strcmp(string, "N"))
1518 ppd->colorspace = PPD_CS_N;
1519 else
1520 ppd->colorspace = PPD_CS_GRAY;
1521 }
1522 else if (option && !strcmp(keyword + 7, option->keyword))
1523 {
1524 /*
1525 * Set the default as part of the current option...
1526 */
1527
1528 DEBUG_printf(("Setting %s to %s...\n", keyword, string));
1529
1530 strlcpy(option->defchoice, string, sizeof(option->defchoice));
1531
1532 DEBUG_printf(("%s is now %s...\n", keyword, option->defchoice));
1533 }
1534 else
1535 {
1536 /*
1537 * Lookup option and set if it has been defined...
1538 */
1539
1540 ppd_option_t *toption; /* Temporary option */
1541
1542
1543 if ((toption = ppdFindOption(ppd, keyword + 7)) != NULL)
1544 {
1545 DEBUG_printf(("Setting %s to %s...\n", keyword, string));
1546 strlcpy(toption->defchoice, string, sizeof(toption->defchoice));
1547 }
1548 }
1549 }
1550 else if (!strcmp(keyword, "UIConstraints") ||
1551 !strcmp(keyword, "NonUIConstraints"))
1552 {
1553 if (ppd->num_consts == 0)
1554 constraint = calloc(2, sizeof(ppd_const_t));
1555 else
1556 constraint = realloc(ppd->consts,
1557 (ppd->num_consts + 2) * sizeof(ppd_const_t));
1558
1559 if (constraint == NULL)
1560 {
1561 cg->ppd_status = PPD_ALLOC_ERROR;
1562
1563 goto error;
1564 }
1565
1566 ppd->consts = constraint;
1567 constraint += ppd->num_consts;
1568 ppd->num_consts ++;
1569
1570 switch (sscanf(string, "%40s%40s%40s%40s", constraint->option1,
1571 constraint->choice1, constraint->option2,
1572 constraint->choice2))
1573 {
1574 case 0 : /* Error */
1575 case 1 : /* Error */
1576 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1577 goto error;
1578
1579 case 2 : /* Two options... */
1580 /*
1581 * Check for broken constraints like "* Option"...
1582 */
1583
1584 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1585 (!strcmp(constraint->option1, "*") ||
1586 !strcmp(constraint->choice1, "*")))
1587 {
1588 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1589 goto error;
1590 }
1591
1592 /*
1593 * The following strcpy's are safe, as optionN and
1594 * choiceN are all the same size (size defined by PPD spec...)
1595 */
1596
1597 if (constraint->option1[0] == '*')
1598 _cups_strcpy(constraint->option1, constraint->option1 + 1);
1599 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1600 {
1601 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1602 goto error;
1603 }
1604
1605 if (constraint->choice1[0] == '*')
1606 _cups_strcpy(constraint->option2, constraint->choice1 + 1);
1607 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1608 {
1609 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1610 goto error;
1611 }
1612
1613 constraint->choice1[0] = '\0';
1614 constraint->choice2[0] = '\0';
1615 break;
1616
1617 case 3 : /* Two options, one choice... */
1618 /*
1619 * Check for broken constraints like "* Option"...
1620 */
1621
1622 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1623 (!strcmp(constraint->option1, "*") ||
1624 !strcmp(constraint->choice1, "*") ||
1625 !strcmp(constraint->option2, "*")))
1626 {
1627 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1628 goto error;
1629 }
1630
1631 /*
1632 * The following _cups_strcpy's are safe, as optionN and
1633 * choiceN are all the same size (size defined by PPD spec...)
1634 */
1635
1636 if (constraint->option1[0] == '*')
1637 _cups_strcpy(constraint->option1, constraint->option1 + 1);
1638 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1639 {
1640 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1641 goto error;
1642 }
1643
1644 if (constraint->choice1[0] == '*')
1645 {
1646 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1647 constraint->option2[0] == '*')
1648 {
1649 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1650 goto error;
1651 }
1652
1653 _cups_strcpy(constraint->choice2, constraint->option2);
1654 _cups_strcpy(constraint->option2, constraint->choice1 + 1);
1655 constraint->choice1[0] = '\0';
1656 }
1657 else
1658 {
1659 if (constraint->option2[0] == '*')
1660 _cups_strcpy(constraint->option2, constraint->option2 + 1);
1661 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1662 {
1663 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1664 goto error;
1665 }
1666
1667 constraint->choice2[0] = '\0';
1668 }
1669 break;
1670
1671 case 4 : /* Two options, two choices... */
1672 /*
1673 * Check for broken constraints like "* Option"...
1674 */
1675
1676 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1677 (!strcmp(constraint->option1, "*") ||
1678 !strcmp(constraint->choice1, "*") ||
1679 !strcmp(constraint->option2, "*") ||
1680 !strcmp(constraint->choice2, "*")))
1681 {
1682 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1683 goto error;
1684 }
1685
1686 if (constraint->option1[0] == '*')
1687 _cups_strcpy(constraint->option1, constraint->option1 + 1);
1688 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1689 {
1690 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1691 goto error;
1692 }
1693
1694 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1695 constraint->choice1[0] == '*')
1696 {
1697 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1698 goto error;
1699 }
1700
1701 if (constraint->option2[0] == '*')
1702 _cups_strcpy(constraint->option2, constraint->option2 + 1);
1703 else if (cg->ppd_conform == PPD_CONFORM_STRICT)
1704 {
1705 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1706 goto error;
1707 }
1708
1709 if (cg->ppd_conform == PPD_CONFORM_STRICT &&
1710 constraint->choice2[0] == '*')
1711 {
1712 cg->ppd_status = PPD_BAD_UI_CONSTRAINTS;
1713 goto error;
1714 }
1715 break;
1716 }
1717
1718 /*
1719 * For CustomPageSize and InputSlot/ManualFeed, create a duplicate
1720 * constraint for PageRegion...
1721 */
1722
1723 if (!strcasecmp(constraint->option1, "CustomPageSize") &&
1724 (!strcasecmp(constraint->option2, "InputSlot") ||
1725 !strcasecmp(constraint->option2, "ManualFeed")))
1726 {
1727 ppd->num_consts ++;
1728
1729 strcpy(constraint[1].option1, "PageRegion");
1730 strcpy(constraint[1].choice1, "Custom");
1731 strcpy(constraint[1].option2, constraint->option2);
1732 strcpy(constraint[1].choice2, constraint->choice2);
1733 }
1734 else if (!strcasecmp(constraint->option2, "CustomPageSize") &&
1735 (!strcasecmp(constraint->option1, "InputSlot") ||
1736 !strcasecmp(constraint->option1, "ManualFeed")))
1737 {
1738 ppd->num_consts ++;
1739
1740 strcpy(constraint[1].option1, constraint->option1);
1741 strcpy(constraint[1].choice1, constraint->choice1);
1742 strcpy(constraint[1].option2, "PageRegion");
1743 strcpy(constraint[1].choice2, "Custom");
1744 }
1745
1746 /*
1747 * Handle CustomFoo option constraints...
1748 */
1749
1750 if (!strncasecmp(constraint->option1, "Custom", 6) &&
1751 !strcasecmp(constraint->choice1, "True"))
1752 {
1753 _cups_strcpy(constraint->option1, constraint->option1 + 6);
1754 strcpy(constraint->choice1, "Custom");
1755 }
1756
1757 if (!strncasecmp(constraint->option2, "Custom", 6) &&
1758 !strcasecmp(constraint->choice2, "True"))
1759 {
1760 _cups_strcpy(constraint->option2, constraint->option2 + 6);
1761 strcpy(constraint->choice2, "Custom");
1762 }
1763
1764 /*
1765 * Don't add this one as an attribute...
1766 */
1767
1768 ppd_free(string);
1769 string = NULL;
1770 }
1771 else if (!strcmp(keyword, "PaperDimension"))
1772 {
1773 if ((size = ppdPageSize(ppd, name)) == NULL)
1774 size = ppd_add_size(ppd, name);
1775
1776 if (size == NULL)
1777 {
1778 /*
1779 * Unable to add or find size!
1780 */
1781
1782 cg->ppd_status = PPD_ALLOC_ERROR;
1783
1784 goto error;
1785 }
1786
1787 size->width = (float)_cupsStrScand(string, &sptr, loc);
1788 size->length = (float)_cupsStrScand(sptr, NULL, loc);
1789
1790 ppd_free(string);
1791 string = NULL;
1792 }
1793 else if (!strcmp(keyword, "ImageableArea"))
1794 {
1795 if ((size = ppdPageSize(ppd, name)) == NULL)
1796 size = ppd_add_size(ppd, name);
1797
1798 if (size == NULL)
1799 {
1800 /*
1801 * Unable to add or find size!
1802 */
1803
1804 cg->ppd_status = PPD_ALLOC_ERROR;
1805
1806 goto error;
1807 }
1808
1809 size->left = (float)_cupsStrScand(string, &sptr, loc);
1810 size->bottom = (float)_cupsStrScand(sptr, &sptr, loc);
1811 size->right = (float)_cupsStrScand(sptr, &sptr, loc);
1812 size->top = (float)_cupsStrScand(sptr, NULL, loc);
1813
1814 ppd_free(string);
1815 string = NULL;
1816 }
1817 else if (option != NULL &&
1818 (mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) ==
1819 (PPD_KEYWORD | PPD_OPTION | PPD_STRING) &&
1820 !strcmp(keyword, option->keyword))
1821 {
1822 DEBUG_printf(("group = %p, subgroup = %p\n", group, subgroup));
1823
1824 if (!strcmp(keyword, "PageSize"))
1825 {
1826 /*
1827 * Add a page size...
1828 */
1829
1830 if (ppdPageSize(ppd, name) == NULL)
1831 ppd_add_size(ppd, name);
1832 }
1833
1834 /*
1835 * Add the option choice...
1836 */
1837
1838 choice = ppd_add_choice(option, name);
1839
1840 if (text[0])
1841 cupsCharsetToUTF8((cups_utf8_t *)choice->text, text,
1842 sizeof(choice->text), encoding);
1843 else if (!strcmp(name, "True"))
1844 strcpy(choice->text, _("Yes"));
1845 else if (!strcmp(name, "False"))
1846 strcpy(choice->text, _("No"));
1847 else
1848 strlcpy(choice->text, name, sizeof(choice->text));
1849
1850 if (option->section == PPD_ORDER_JCL)
1851 ppd_decode(string); /* Decode quoted string */
1852
1853 choice->code = string;
1854 string = NULL; /* Don't add as an attribute below */
1855 }
1856
1857 /*
1858 * Add remaining lines with keywords and string values as attributes...
1859 */
1860
1861 if (string &&
1862 (mask & (PPD_KEYWORD | PPD_STRING)) == (PPD_KEYWORD | PPD_STRING))
1863 ppd_add_attr(ppd, keyword, name, text, string);
1864 else
1865 ppd_free(string);
1866 }
1867
1868 /*
1869 * Reset language preferences...
1870 */
1871
1872 cupsLangFree(language);
1873
1874 #ifdef DEBUG
1875 if (!feof(fp))
1876 printf("Premature EOF at %lu...\n", (unsigned long)ftell(fp));
1877 #endif /* DEBUG */
1878
1879 if (cg->ppd_status != PPD_OK)
1880 {
1881 /*
1882 * Had an error reading the PPD file, cannot continue!
1883 */
1884
1885 ppdClose(ppd);
1886
1887 return (NULL);
1888 }
1889
1890 /*
1891 * Create the sorted options array and set the option back-pointer for
1892 * each choice and custom option...
1893 */
1894
1895 ppd->options = cupsArrayNew((cups_array_func_t)ppd_compare_options, NULL);
1896
1897 for (i = ppd->num_groups, group = ppd->groups;
1898 i > 0;
1899 i --, group ++)
1900 {
1901 for (j = group->num_options, option = group->options;
1902 j > 0;
1903 j --, option ++)
1904 {
1905 ppd_coption_t *coption; /* Custom option */
1906
1907
1908 cupsArrayAdd(ppd->options, option);
1909
1910 for (k = 0; k < option->num_choices; k ++)
1911 option->choices[k].option = option;
1912
1913 if ((coption = ppdFindCustomOption(ppd, option->keyword)) != NULL)
1914 coption->option = option;
1915 }
1916 }
1917
1918 /*
1919 * Return the PPD file structure...
1920 */
1921
1922 return (ppd);
1923
1924 /*
1925 * Common exit point for errors to save code size...
1926 */
1927
1928 error:
1929
1930 ppd_free(string);
1931
1932 ppdClose(ppd);
1933
1934 cupsLangFree(language);
1935
1936 return (NULL);
1937 }
1938
1939
1940 /*
1941 * 'ppdOpenFd()' - Read a PPD file into memory.
1942 */
1943
1944 ppd_file_t * /* O - PPD file record */
1945 ppdOpenFd(int fd) /* I - File to read from */
1946 {
1947 cups_file_t *fp; /* CUPS file pointer */
1948 ppd_file_t *ppd; /* PPD file record */
1949 _cups_globals_t *cg = _cupsGlobals();
1950 /* Global data */
1951
1952
1953 /*
1954 * Set the line number to 0...
1955 */
1956
1957 cg->ppd_line = 0;
1958
1959 /*
1960 * Range check input...
1961 */
1962
1963 if (fd < 0)
1964 {
1965 cg->ppd_status = PPD_NULL_FILE;
1966
1967 return (NULL);
1968 }
1969
1970 /*
1971 * Try to open the file and parse it...
1972 */
1973
1974 if ((fp = cupsFileOpenFd(fd, "r")) != NULL)
1975 {
1976 ppd = ppdOpen2(fp);
1977
1978 cupsFileClose(fp);
1979 }
1980 else
1981 {
1982 cg->ppd_status = PPD_FILE_OPEN_ERROR;
1983 ppd = NULL;
1984 }
1985
1986 return (ppd);
1987 }
1988
1989
1990 /*
1991 * 'ppdOpenFile()' - Read a PPD file into memory.
1992 */
1993
1994 ppd_file_t * /* O - PPD file record */
1995 ppdOpenFile(const char *filename) /* I - File to read from */
1996 {
1997 cups_file_t *fp; /* File pointer */
1998 ppd_file_t *ppd; /* PPD file record */
1999 _cups_globals_t *cg = _cupsGlobals();
2000 /* Global data */
2001
2002
2003 /*
2004 * Set the line number to 0...
2005 */
2006
2007 cg->ppd_line = 0;
2008
2009 /*
2010 * Range check input...
2011 */
2012
2013 if (filename == NULL)
2014 {
2015 cg->ppd_status = PPD_NULL_FILE;
2016
2017 return (NULL);
2018 }
2019
2020 /*
2021 * Try to open the file and parse it...
2022 */
2023
2024 if ((fp = cupsFileOpen(filename, "r")) != NULL)
2025 {
2026 ppd = ppdOpen2(fp);
2027
2028 cupsFileClose(fp);
2029 }
2030 else
2031 {
2032 cg->ppd_status = PPD_FILE_OPEN_ERROR;
2033 ppd = NULL;
2034 }
2035
2036 return (ppd);
2037 }
2038
2039
2040 /*
2041 * 'ppdSetConformance()' - Set the conformance level for PPD files.
2042 *
2043 * @since CUPS 1.1.20@
2044 */
2045
2046 void
2047 ppdSetConformance(ppd_conform_t c) /* I - Conformance level */
2048 {
2049 _cups_globals_t *cg = _cupsGlobals();
2050 /* Global data */
2051
2052
2053 cg->ppd_conform = c;
2054 }
2055
2056
2057 /*
2058 * 'ppd_add_attr()' - Add an attribute to the PPD data.
2059 */
2060
2061 static ppd_attr_t * /* O - New attribute */
2062 ppd_add_attr(ppd_file_t *ppd, /* I - PPD file data */
2063 const char *name, /* I - Attribute name */
2064 const char *spec, /* I - Specifier string, if any */
2065 const char *text, /* I - Text string, if any */
2066 const char *value) /* I - Value of attribute */
2067 {
2068 ppd_attr_t **ptr, /* New array */
2069 *temp; /* New attribute */
2070
2071
2072 /*
2073 * Range check input...
2074 */
2075
2076 if (ppd == NULL || name == NULL || spec == NULL)
2077 return (NULL);
2078
2079 /*
2080 * Create the array as needed...
2081 */
2082
2083 if (!ppd->sorted_attrs)
2084 ppd->sorted_attrs = cupsArrayNew((cups_array_func_t)ppd_compare_attrs,
2085 NULL);
2086
2087 /*
2088 * Allocate memory for the new attribute...
2089 */
2090
2091 if (ppd->num_attrs == 0)
2092 ptr = malloc(sizeof(ppd_attr_t *));
2093 else
2094 ptr = realloc(ppd->attrs, (ppd->num_attrs + 1) * sizeof(ppd_attr_t *));
2095
2096 if (ptr == NULL)
2097 return (NULL);
2098
2099 ppd->attrs = ptr;
2100 ptr += ppd->num_attrs;
2101
2102 if ((temp = calloc(1, sizeof(ppd_attr_t))) == NULL)
2103 return (NULL);
2104
2105 *ptr = temp;
2106
2107 ppd->num_attrs ++;
2108
2109 /*
2110 * Copy data over...
2111 */
2112
2113 strlcpy(temp->name, name, sizeof(temp->name));
2114 strlcpy(temp->spec, spec, sizeof(temp->spec));
2115 strlcpy(temp->text, text, sizeof(temp->text));
2116 temp->value = (char *)value;
2117
2118 /*
2119 * Add the attribute to the sorted array...
2120 */
2121
2122 cupsArrayAdd(ppd->sorted_attrs, temp);
2123
2124 /*
2125 * Return the attribute...
2126 */
2127
2128 return (temp);
2129 }
2130
2131
2132 /*
2133 * 'ppd_add_choice()' - Add a choice to an option.
2134 */
2135
2136 static ppd_choice_t * /* O - Named choice */
2137 ppd_add_choice(ppd_option_t *option, /* I - Option */
2138 const char *name) /* I - Name of choice */
2139 {
2140 ppd_choice_t *choice; /* Choice */
2141
2142
2143 if (option->num_choices == 0)
2144 choice = malloc(sizeof(ppd_choice_t));
2145 else
2146 choice = realloc(option->choices,
2147 sizeof(ppd_choice_t) * (option->num_choices + 1));
2148
2149 if (choice == NULL)
2150 return (NULL);
2151
2152 option->choices = choice;
2153 choice += option->num_choices;
2154 option->num_choices ++;
2155
2156 memset(choice, 0, sizeof(ppd_choice_t));
2157 strlcpy(choice->choice, name, sizeof(choice->choice));
2158
2159 return (choice);
2160 }
2161
2162
2163 /*
2164 * 'ppd_add_size()' - Add a page size.
2165 */
2166
2167 static ppd_size_t * /* O - Named size */
2168 ppd_add_size(ppd_file_t *ppd, /* I - PPD file */
2169 const char *name) /* I - Name of size */
2170 {
2171 ppd_size_t *size; /* Size */
2172
2173
2174 if (ppd->num_sizes == 0)
2175 size = malloc(sizeof(ppd_size_t));
2176 else
2177 size = realloc(ppd->sizes, sizeof(ppd_size_t) * (ppd->num_sizes + 1));
2178
2179 if (size == NULL)
2180 return (NULL);
2181
2182 ppd->sizes = size;
2183 size += ppd->num_sizes;
2184 ppd->num_sizes ++;
2185
2186 memset(size, 0, sizeof(ppd_size_t));
2187 strlcpy(size->name, name, sizeof(size->name));
2188
2189 return (size);
2190 }
2191
2192
2193 /*
2194 * 'ppd_compare_attrs()' - Compare two attributes.
2195 */
2196
2197 static int /* O - Result of comparison */
2198 ppd_compare_attrs(ppd_attr_t *a, /* I - First attribute */
2199 ppd_attr_t *b) /* I - Second attribute */
2200 {
2201 int ret; /* Result of comparison */
2202
2203
2204 if ((ret = strcasecmp(a->name, b->name)) != 0)
2205 return (ret);
2206 else
2207 return (strcasecmp(a->spec, b->spec));
2208 }
2209
2210
2211 /*
2212 * 'ppd_compare_coptions()' - Compare two custom options.
2213 */
2214
2215 static int /* O - Result of comparison */
2216 ppd_compare_coptions(ppd_coption_t *a, /* I - First option */
2217 ppd_coption_t *b) /* I - Second option */
2218 {
2219 return (strcasecmp(a->keyword, b->keyword));
2220 }
2221
2222
2223 /*
2224 * 'ppd_compare_cparams()' - Compare two custom parameters.
2225 */
2226
2227 static int /* O - Result of comparison */
2228 ppd_compare_cparams(ppd_cparam_t *a, /* I - First parameter */
2229 ppd_cparam_t *b) /* I - Second parameter */
2230 {
2231 return (strcasecmp(a->name, b->name));
2232 }
2233
2234
2235 /*
2236 * 'ppd_compare_options()' - Compare two options.
2237 */
2238
2239 static int /* O - Result of comparison */
2240 ppd_compare_options(ppd_option_t *a, /* I - First option */
2241 ppd_option_t *b) /* I - Second option */
2242 {
2243 return (strcasecmp(a->keyword, b->keyword));
2244 }
2245
2246
2247 /*
2248 * 'ppd_decode()' - Decode a string value...
2249 */
2250
2251 static int /* O - Length of decoded string */
2252 ppd_decode(char *string) /* I - String to decode */
2253 {
2254 char *inptr, /* Input pointer */
2255 *outptr; /* Output pointer */
2256
2257
2258 inptr = string;
2259 outptr = string;
2260
2261 while (*inptr != '\0')
2262 if (*inptr == '<' && isxdigit(inptr[1] & 255))
2263 {
2264 /*
2265 * Convert hex to 8-bit values...
2266 */
2267
2268 inptr ++;
2269 while (isxdigit(*inptr & 255))
2270 {
2271 if (isalpha(*inptr))
2272 *outptr = (tolower(*inptr) - 'a' + 10) << 4;
2273 else
2274 *outptr = (*inptr - '0') << 4;
2275
2276 inptr ++;
2277
2278 if (!isxdigit(*inptr & 255))
2279 break;
2280
2281 if (isalpha(*inptr))
2282 *outptr |= tolower(*inptr) - 'a' + 10;
2283 else
2284 *outptr |= *inptr - '0';
2285
2286 inptr ++;
2287 outptr ++;
2288 }
2289
2290 while (*inptr != '>' && *inptr != '\0')
2291 inptr ++;
2292 while (*inptr == '>')
2293 inptr ++;
2294 }
2295 else
2296 *outptr++ = *inptr++;
2297
2298 *outptr = '\0';
2299
2300 return ((int)(outptr - string));
2301 }
2302
2303
2304 /*
2305 * 'ppd_free_group()' - Free a single UI group.
2306 */
2307
2308 static void
2309 ppd_free_group(ppd_group_t *group) /* I - Group to free */
2310 {
2311 int i; /* Looping var */
2312 ppd_option_t *option; /* Current option */
2313 ppd_group_t *subgroup; /* Current sub-group */
2314
2315
2316 if (group->num_options > 0)
2317 {
2318 for (i = group->num_options, option = group->options;
2319 i > 0;
2320 i --, option ++)
2321 ppd_free_option(option);
2322
2323 ppd_free(group->options);
2324 }
2325
2326 if (group->num_subgroups > 0)
2327 {
2328 for (i = group->num_subgroups, subgroup = group->subgroups;
2329 i > 0;
2330 i --, subgroup ++)
2331 ppd_free_group(subgroup);
2332
2333 ppd_free(group->subgroups);
2334 }
2335 }
2336
2337
2338 /*
2339 * 'ppd_free_option()' - Free a single option.
2340 */
2341
2342 static void
2343 ppd_free_option(ppd_option_t *option) /* I - Option to free */
2344 {
2345 int i; /* Looping var */
2346 ppd_choice_t *choice; /* Current choice */
2347
2348
2349 if (option->num_choices > 0)
2350 {
2351 for (i = option->num_choices, choice = option->choices;
2352 i > 0;
2353 i --, choice ++)
2354 {
2355 ppd_free(choice->code);
2356 }
2357
2358 ppd_free(option->choices);
2359 }
2360 }
2361
2362
2363 /*
2364 * 'ppd_get_coption()' - Get a custom option record.
2365 */
2366
2367 static ppd_coption_t * /* O - Custom option... */
2368 ppd_get_coption(ppd_file_t *ppd, /* I - PPD file */
2369 const char *name) /* I - Name of option */
2370 {
2371 ppd_coption_t *copt; /* New custom option */
2372
2373
2374 /*
2375 * See if the option already exists...
2376 */
2377
2378 if ((copt = ppdFindCustomOption(ppd, name)) != NULL)
2379 return (copt);
2380
2381 /*
2382 * Not found, so create the custom option record...
2383 */
2384
2385 if ((copt = calloc(1, sizeof(ppd_coption_t))) == NULL)
2386 return (NULL);
2387
2388 strlcpy(copt->keyword, name, sizeof(copt->keyword));
2389
2390 copt->params = cupsArrayNew((cups_array_func_t)ppd_compare_cparams, NULL);
2391
2392 cupsArrayAdd(ppd->coptions, copt);
2393
2394 /*
2395 * Return the new record...
2396 */
2397
2398 return (copt);
2399 }
2400
2401
2402 /*
2403 * 'ppd_get_cparam()' - Get a custom parameter record.
2404 */
2405
2406 static ppd_cparam_t * /* O - Extended option... */
2407 ppd_get_cparam(ppd_coption_t *opt, /* I - PPD file */
2408 const char *param, /* I - Name of parameter */
2409 const char *text) /* I - Human-readable text */
2410 {
2411 ppd_cparam_t *cparam; /* New custom parameter */
2412
2413
2414 /*
2415 * See if the parameter already exists...
2416 */
2417
2418 if ((cparam = ppdFindCustomParam(opt, param)) != NULL)
2419 return (cparam);
2420
2421 /*
2422 * Not found, so create the custom parameter record...
2423 */
2424
2425 if ((cparam = calloc(1, sizeof(ppd_cparam_t))) == NULL)
2426 return (NULL);
2427
2428 strlcpy(cparam->name, param, sizeof(cparam->name));
2429 strlcpy(cparam->text, text[0] ? text : param, sizeof(cparam->text));
2430
2431 /*
2432 * Add this record to the array...
2433 */
2434
2435 cupsArrayAdd(opt->params, cparam);
2436
2437 /*
2438 * Return the new record...
2439 */
2440
2441 return (cparam);
2442 }
2443
2444
2445 /*
2446 * 'ppd_get_group()' - Find or create the named group as needed.
2447 */
2448
2449 static ppd_group_t * /* O - Named group */
2450 ppd_get_group(ppd_file_t *ppd, /* I - PPD file */
2451 const char *name, /* I - Name of group */
2452 const char *text, /* I - Text for group */
2453 _cups_globals_t *cg, /* I - Global data */
2454 cups_encoding_t encoding) /* I - Encoding of text */
2455 {
2456 int i; /* Looping var */
2457 ppd_group_t *group; /* Group */
2458
2459
2460 DEBUG_printf(("ppd_get_group(ppd=%p, name=\"%s\", text=\"%s\", cg=%p)\n",
2461 ppd, name, text, cg));
2462
2463 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
2464 if (!strcmp(group->name, name))
2465 break;
2466
2467 if (i == 0)
2468 {
2469 DEBUG_printf(("Adding group %s...\n", name));
2470
2471 if (cg->ppd_conform == PPD_CONFORM_STRICT && strlen(text) >= sizeof(group->text))
2472 {
2473 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
2474
2475 return (NULL);
2476 }
2477
2478 if (ppd->num_groups == 0)
2479 group = malloc(sizeof(ppd_group_t));
2480 else
2481 group = realloc(ppd->groups,
2482 (ppd->num_groups + 1) * sizeof(ppd_group_t));
2483
2484 if (group == NULL)
2485 {
2486 cg->ppd_status = PPD_ALLOC_ERROR;
2487
2488 return (NULL);
2489 }
2490
2491 ppd->groups = group;
2492 group += ppd->num_groups;
2493 ppd->num_groups ++;
2494
2495 memset(group, 0, sizeof(ppd_group_t));
2496 strlcpy(group->name, name, sizeof(group->name));
2497
2498 cupsCharsetToUTF8((cups_utf8_t *)group->text, text,
2499 sizeof(group->text), encoding);
2500 }
2501
2502 return (group);
2503 }
2504
2505
2506 /*
2507 * 'ppd_get_option()' - Find or create the named option as needed.
2508 */
2509
2510 static ppd_option_t * /* O - Named option */
2511 ppd_get_option(ppd_group_t *group, /* I - Group */
2512 const char *name) /* I - Name of option */
2513 {
2514 int i; /* Looping var */
2515 ppd_option_t *option; /* Option */
2516
2517
2518 DEBUG_printf(("ppd_get_option(group=%p(\"%s\"), name=\"%s\")\n",
2519 group, group->name, name));
2520
2521 for (i = group->num_options, option = group->options; i > 0; i --, option ++)
2522 if (!strcmp(option->keyword, name))
2523 break;
2524
2525 if (i == 0)
2526 {
2527 if (group->num_options == 0)
2528 option = malloc(sizeof(ppd_option_t));
2529 else
2530 option = realloc(group->options,
2531 (group->num_options + 1) * sizeof(ppd_option_t));
2532
2533 if (option == NULL)
2534 return (NULL);
2535
2536 group->options = option;
2537 option += group->num_options;
2538 group->num_options ++;
2539
2540 memset(option, 0, sizeof(ppd_option_t));
2541 strlcpy(option->keyword, name, sizeof(option->keyword));
2542 }
2543
2544 return (option);
2545 }
2546
2547
2548 /*
2549 * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
2550 * necessary.
2551 */
2552
2553 static int /* O - Bitmask of fields read */
2554 ppd_read(cups_file_t *fp, /* I - File to read from */
2555 char *keyword, /* O - Keyword from line */
2556 char *option, /* O - Option from line */
2557 char *text, /* O - Human-readable text from line */
2558 char **string, /* O - Code/string data */
2559 int ignoreblank, /* I - Ignore blank lines? */
2560 _cups_globals_t *cg) /* I - Global data */
2561 {
2562 int ch, /* Character from file */
2563 col, /* Column in line */
2564 colon, /* Colon seen? */
2565 endquote, /* Waiting for an end quote */
2566 mask, /* Mask to be returned */
2567 startline, /* Start line */
2568 textlen; /* Length of text */
2569 char *keyptr, /* Keyword pointer */
2570 *optptr, /* Option pointer */
2571 *textptr, /* Text pointer */
2572 *strptr, /* Pointer into string */
2573 *lineptr, /* Current position in line buffer */
2574 *line; /* Line buffer */
2575 int linesize; /* Current size of line buffer */
2576
2577 /*
2578 * Range check everything...
2579 */
2580
2581 if (!fp || !keyword || !option || !text || !string)
2582 return (0);
2583
2584 /*
2585 * Now loop until we have a valid line...
2586 */
2587
2588 *string = NULL;
2589 col = 0;
2590 startline = cg->ppd_line + 1;
2591 linesize = 1024;
2592 line = malloc(linesize);
2593
2594 if (!line)
2595 return (0);
2596
2597 do
2598 {
2599 /*
2600 * Read the line...
2601 */
2602
2603 lineptr = line;
2604 endquote = 0;
2605 colon = 0;
2606
2607 while ((ch = cupsFileGetChar(fp)) != EOF)
2608 {
2609 if (lineptr >= (line + linesize - 1))
2610 {
2611 /*
2612 * Expand the line buffer...
2613 */
2614
2615 char *temp; /* Temporary line pointer */
2616
2617
2618 linesize += 1024;
2619 if (linesize > 262144)
2620 {
2621 /*
2622 * Don't allow lines longer than 256k!
2623 */
2624
2625 cg->ppd_line = startline;
2626 cg->ppd_status = PPD_LINE_TOO_LONG;
2627
2628 free(line);
2629
2630 return (0);
2631 }
2632
2633 temp = realloc(line, linesize);
2634 if (!temp)
2635 {
2636 cg->ppd_line = startline;
2637 cg->ppd_status = PPD_LINE_TOO_LONG;
2638
2639 free(line);
2640
2641 return (0);
2642 }
2643
2644 lineptr = temp + (lineptr - line);
2645 line = temp;
2646 }
2647
2648 if (ch == '\r' || ch == '\n')
2649 {
2650 /*
2651 * Line feed or carriage return...
2652 */
2653
2654 cg->ppd_line ++;
2655 col = 0;
2656
2657 if (ch == '\r')
2658 {
2659 /*
2660 * Check for a trailing line feed...
2661 */
2662
2663 if ((ch = cupsFilePeekChar(fp)) == EOF)
2664 {
2665 ch = '\n';
2666 break;
2667 }
2668
2669 if (ch == 0x0a)
2670 cupsFileGetChar(fp);
2671 }
2672
2673 if (lineptr == line && ignoreblank)
2674 continue; /* Skip blank lines */
2675
2676 ch = '\n';
2677
2678 if (!endquote) /* Continue for multi-line text */
2679 break;
2680
2681 *lineptr++ = '\n';
2682 }
2683 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
2684 {
2685 /*
2686 * Other control characters...
2687 */
2688
2689 cg->ppd_line = startline;
2690 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
2691
2692 free(line);
2693
2694 return (0);
2695 }
2696 else if (ch != 0x1a)
2697 {
2698 /*
2699 * Any other character...
2700 */
2701
2702 *lineptr++ = ch;
2703 col ++;
2704
2705 if (col > (PPD_MAX_LINE - 1))
2706 {
2707 /*
2708 * Line is too long...
2709 */
2710
2711 cg->ppd_line = startline;
2712 cg->ppd_status = PPD_LINE_TOO_LONG;
2713
2714 free(line);
2715
2716 return (0);
2717 }
2718
2719 if (ch == ':' && strncmp(line, "*%", 2) != 0)
2720 colon = 1;
2721
2722 if (ch == '\"' && colon)
2723 endquote = !endquote;
2724 }
2725 }
2726
2727 if (endquote)
2728 {
2729 /*
2730 * Didn't finish this quoted string...
2731 */
2732
2733 while ((ch = cupsFileGetChar(fp)) != EOF)
2734 if (ch == '\"')
2735 break;
2736 else if (ch == '\r' || ch == '\n')
2737 {
2738 cg->ppd_line ++;
2739 col = 0;
2740
2741 if (ch == '\r')
2742 {
2743 /*
2744 * Check for a trailing line feed...
2745 */
2746
2747 if ((ch = cupsFilePeekChar(fp)) == EOF)
2748 break;
2749 if (ch == 0x0a)
2750 cupsFileGetChar(fp);
2751 }
2752
2753 ch = '\n';
2754 }
2755 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
2756 {
2757 /*
2758 * Other control characters...
2759 */
2760
2761 cg->ppd_line = startline;
2762 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
2763
2764 free(line);
2765
2766 return (0);
2767 }
2768 else if (ch != 0x1a)
2769 {
2770 col ++;
2771
2772 if (col > (PPD_MAX_LINE - 1))
2773 {
2774 /*
2775 * Line is too long...
2776 */
2777
2778 cg->ppd_line = startline;
2779 cg->ppd_status = PPD_LINE_TOO_LONG;
2780
2781 free(line);
2782
2783 return (0);
2784 }
2785 }
2786 }
2787
2788 if (ch != '\n')
2789 {
2790 /*
2791 * Didn't finish this line...
2792 */
2793
2794 while ((ch = cupsFileGetChar(fp)) != EOF)
2795 if (ch == '\r' || ch == '\n')
2796 {
2797 /*
2798 * Line feed or carriage return...
2799 */
2800
2801 cg->ppd_line ++;
2802 col = 0;
2803
2804 if (ch == '\r')
2805 {
2806 /*
2807 * Check for a trailing line feed...
2808 */
2809
2810 if ((ch = cupsFilePeekChar(fp)) == EOF)
2811 break;
2812 if (ch == 0x0a)
2813 cupsFileGetChar(fp);
2814 }
2815
2816 break;
2817 }
2818 else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT)
2819 {
2820 /*
2821 * Other control characters...
2822 */
2823
2824 cg->ppd_line = startline;
2825 cg->ppd_status = PPD_ILLEGAL_CHARACTER;
2826
2827 free(line);
2828
2829 return (0);
2830 }
2831 else if (ch != 0x1a)
2832 {
2833 col ++;
2834
2835 if (col > (PPD_MAX_LINE - 1))
2836 {
2837 /*
2838 * Line is too long...
2839 */
2840
2841 cg->ppd_line = startline;
2842 cg->ppd_status = PPD_LINE_TOO_LONG;
2843
2844 free(line);
2845
2846 return (0);
2847 }
2848 }
2849 }
2850
2851 if (lineptr > line && lineptr[-1] == '\n')
2852 lineptr --;
2853
2854 *lineptr = '\0';
2855
2856 DEBUG_printf(("LINE = \"%s\"\n", line));
2857
2858 /*
2859 * The dynamically created PPDs for older style Mac OS X
2860 * drivers include a large blob of data inserted as comments
2861 * at the end of the file. As an optimization we can stop
2862 * reading the PPD when we get to the start of this data.
2863 */
2864
2865 if (!strcmp(line, "*%APLWORKSET START"))
2866 {
2867 free(line);
2868 return (0);
2869 }
2870
2871 if (ch == EOF && lineptr == line)
2872 {
2873 free(line);
2874 return (0);
2875 }
2876
2877 /*
2878 * Now parse it...
2879 */
2880
2881 mask = 0;
2882 lineptr = line + 1;
2883
2884 keyword[0] = '\0';
2885 option[0] = '\0';
2886 text[0] = '\0';
2887 *string = NULL;
2888
2889 if ((!line[0] || /* Blank line */
2890 !strncmp(line, "*%", 2) || /* Comment line */
2891 !strcmp(line, "*End")) && /* End of multi-line string */
2892 ignoreblank) /* Ignore these? */
2893 {
2894 startline = cg->ppd_line + 1;
2895 continue;
2896 }
2897
2898 if (!strcmp(line, "*")) /* (Bad) comment line */
2899 {
2900 if (cg->ppd_conform == PPD_CONFORM_RELAXED)
2901 {
2902 startline = cg->ppd_line + 1;
2903 continue;
2904 }
2905 else
2906 {
2907 cg->ppd_line = startline;
2908 cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
2909
2910 free(line);
2911 return (0);
2912 }
2913 }
2914
2915 if (line[0] != '*') /* All lines start with an asterisk */
2916 {
2917 /*
2918 * Allow lines consisting of just whitespace...
2919 */
2920
2921 for (lineptr = line; *lineptr; lineptr ++)
2922 if (!isspace(*lineptr & 255))
2923 break;
2924
2925 if (*lineptr)
2926 {
2927 cg->ppd_status = PPD_MISSING_ASTERISK;
2928 free(line);
2929 return (0);
2930 }
2931 else if (ignoreblank)
2932 continue;
2933 else
2934 {
2935 free(line);
2936 return (0);
2937 }
2938 }
2939
2940 /*
2941 * Get a keyword...
2942 */
2943
2944 keyptr = keyword;
2945
2946 while (*lineptr != '\0' && *lineptr != ':' && !isspace(*lineptr & 255))
2947 {
2948 if (*lineptr <= ' ' || *lineptr > 126 || *lineptr == '/' ||
2949 (keyptr - keyword) >= (PPD_MAX_NAME - 1))
2950 {
2951 cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD;
2952 free(line);
2953 return (0);
2954 }
2955
2956 *keyptr++ = *lineptr++;
2957 }
2958
2959 *keyptr = '\0';
2960
2961 if (!strcmp(keyword, "End"))
2962 continue;
2963
2964 mask |= PPD_KEYWORD;
2965
2966 /* DEBUG_printf(("keyword = \"%s\", lineptr = \"%s\"\n", keyword, lineptr));*/
2967
2968 if (isspace(*lineptr & 255))
2969 {
2970 /*
2971 * Get an option name...
2972 */
2973
2974 while (isspace(*lineptr & 255))
2975 lineptr ++;
2976
2977 optptr = option;
2978
2979 while (*lineptr != '\0' && !isspace(*lineptr & 255) && *lineptr != ':' &&
2980 *lineptr != '/')
2981 {
2982 if (*lineptr <= ' ' || *lineptr > 126 ||
2983 (optptr - option) >= (PPD_MAX_NAME - 1))
2984 {
2985 cg->ppd_status = PPD_ILLEGAL_OPTION_KEYWORD;
2986 free(line);
2987 return (0);
2988 }
2989
2990 *optptr++ = *lineptr++;
2991 }
2992
2993 *optptr = '\0';
2994
2995 if (isspace(*lineptr & 255) && cg->ppd_conform == PPD_CONFORM_STRICT)
2996 {
2997 cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
2998 free(line);
2999 return (0);
3000 }
3001
3002 while (isspace(*lineptr & 255))
3003 lineptr ++;
3004
3005 mask |= PPD_OPTION;
3006
3007 /* DEBUG_printf(("option = \"%s\", lineptr = \"%s\"\n", option, lineptr));*/
3008
3009 if (*lineptr == '/')
3010 {
3011 /*
3012 * Get human-readable text...
3013 */
3014
3015 lineptr ++;
3016
3017 textptr = text;
3018
3019 while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':')
3020 {
3021 if (((unsigned char)*lineptr < ' ' && *lineptr != '\t') ||
3022 (textptr - text) >= (PPD_MAX_LINE - 1))
3023 {
3024 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
3025 free(line);
3026 return (0);
3027 }
3028
3029 *textptr++ = *lineptr++;
3030 }
3031
3032 *textptr = '\0';
3033 textlen = ppd_decode(text);
3034
3035 if (textlen > PPD_MAX_TEXT && cg->ppd_conform == PPD_CONFORM_STRICT)
3036 {
3037 cg->ppd_status = PPD_ILLEGAL_TRANSLATION;
3038 free(line);
3039 return (0);
3040 }
3041
3042 mask |= PPD_TEXT;
3043 }
3044
3045 /* DEBUG_printf(("text = \"%s\", lineptr = \"%s\"\n", text, lineptr));*/
3046 }
3047
3048 if (isspace(*lineptr & 255) && cg->ppd_conform == PPD_CONFORM_STRICT)
3049 {
3050 cg->ppd_status = PPD_ILLEGAL_WHITESPACE;
3051 free(line);
3052 return (0);
3053 }
3054
3055 while (isspace(*lineptr & 255))
3056 lineptr ++;
3057
3058 if (*lineptr == ':')
3059 {
3060 /*
3061 * Get string after triming leading and trailing whitespace...
3062 */
3063
3064 lineptr ++;
3065 while (isspace(*lineptr & 255))
3066 lineptr ++;
3067
3068 strptr = lineptr + strlen(lineptr) - 1;
3069 while (strptr >= lineptr && isspace(*strptr & 255))
3070 *strptr-- = '\0';
3071
3072 if (*strptr == '\"')
3073 {
3074 /*
3075 * Quoted string by itself...
3076 */
3077
3078 *string = malloc(strlen(lineptr) + 1);
3079
3080 strptr = *string;
3081
3082 for (; *lineptr != '\0'; lineptr ++)
3083 if (*lineptr != '\"')
3084 *strptr++ = *lineptr;
3085
3086 *strptr = '\0';
3087 }
3088 else
3089 *string = strdup(lineptr);
3090
3091 /* DEBUG_printf(("string = \"%s\", lineptr = \"%s\"\n", *string, lineptr));*/
3092
3093 mask |= PPD_STRING;
3094 }
3095 }
3096 while (mask == 0);
3097
3098 free(line);
3099
3100 return (mask);
3101 }
3102
3103
3104 /*
3105 * End of "$Id: ppd.c 6445 2007-04-04 23:43:26Z mike $".
3106 */