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