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