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