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