1/* 2 * "$Id: ppd-cache.c 12131 2014-08-28 23:38:16Z msweet $" 3 * 4 * PPD cache implementation for CUPS. 5 * 6 * Copyright 2010-2014 by Apple Inc. 7 * 8 * These coded instructions, statements, and computer programs are the 9 * property of Apple Inc. and are protected by Federal copyright 10 * law. Distribution and use rights are outlined in the file "LICENSE.txt" 11 * which should have been included with this file. If this file is 12 * file is missing or damaged, see the license at "http://www.cups.org/". 13 * 14 * This file is subject to the Apple OS-Developed Software exception. 15 */ 16 17/* 18 * Include necessary headers... 19 */ 20 21#include "cups-private.h" 22#include <math.h> 23 24 25/* 26 * Macro to test for two almost-equal PWG measurements. 27 */ 28 29#define _PWG_EQUIVALENT(x, y) (abs((x)-(y)) < 2) 30 31 32/* 33 * Local functions... 34 */ 35 36static int pwg_compare_finishings(_pwg_finishings_t *a, 37 _pwg_finishings_t *b); 38static void pwg_free_finishings(_pwg_finishings_t *f); 39static void pwg_ppdize_name(const char *ipp, char *name, size_t namesize); 40static void pwg_unppdize_name(const char *ppd, char *name, size_t namesize, 41 const char *dashchars); 42 43 44/* 45 * '_ppdCacheCreateWithFile()' - Create PPD cache and mapping data from a 46 * written file. 47 * 48 * Use the @link _ppdCacheWriteFile@ function to write PWG mapping data to a 49 * file. 50 */ 51 52_ppd_cache_t * /* O - PPD cache and mapping data */ 53_ppdCacheCreateWithFile( 54 const char *filename, /* I - File to read */ 55 ipp_t **attrs) /* IO - IPP attributes, if any */ 56{ 57 cups_file_t *fp; /* File */ 58 _ppd_cache_t *pc; /* PWG mapping data */ 59 pwg_size_t *size; /* Current size */ 60 pwg_map_t *map; /* Current map */ 61 _pwg_finishings_t *finishings; /* Current finishings option */ 62 int linenum, /* Current line number */ 63 num_bins, /* Number of bins in file */ 64 num_sizes, /* Number of sizes in file */ 65 num_sources, /* Number of sources in file */ 66 num_types; /* Number of types in file */ 67 char line[2048], /* Current line */ 68 *value, /* Pointer to value in line */ 69 *valueptr, /* Pointer into value */ 70 pwg_keyword[128], /* PWG keyword */ 71 ppd_keyword[PPD_MAX_NAME]; 72 /* PPD keyword */ 73 _pwg_print_color_mode_t print_color_mode; 74 /* Print color mode for preset */ 75 _pwg_print_quality_t print_quality; /* Print quality for preset */ 76 77 78 DEBUG_printf(("_ppdCacheCreateWithFile(filename=\"%s\")", filename)); 79 80 /* 81 * Range check input... 82 */ 83 84 if (attrs) 85 *attrs = NULL; 86 87 if (!filename) 88 { 89 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); 90 return (NULL); 91 } 92 93 /* 94 * Open the file... 95 */ 96 97 if ((fp = cupsFileOpen(filename, "r")) == NULL) 98 { 99 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); 100 return (NULL); 101 } 102 103 /* 104 * Read the first line and make sure it has "#CUPS-PPD-CACHE-version" in it... 105 */ 106 107 if (!cupsFileGets(fp, line, sizeof(line))) 108 { 109 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); 110 DEBUG_puts("_ppdCacheCreateWithFile: Unable to read first line."); 111 cupsFileClose(fp); 112 return (NULL); 113 } 114 115 if (strncmp(line, "#CUPS-PPD-CACHE-", 16)) 116 { 117 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1); 118 DEBUG_printf(("_ppdCacheCreateWithFile: Wrong first line \"%s\".", line)); 119 cupsFileClose(fp); 120 return (NULL); 121 } 122 123 if (atoi(line + 16) != _PPD_CACHE_VERSION) 124 { 125 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Out of date PPD cache file."), 1); 126 DEBUG_printf(("_ppdCacheCreateWithFile: Cache file has version %s, " 127 "expected %d.", line + 16, _PPD_CACHE_VERSION)); 128 cupsFileClose(fp); 129 return (NULL); 130 } 131 132 /* 133 * Allocate the mapping data structure... 134 */ 135 136 if ((pc = calloc(1, sizeof(_ppd_cache_t))) == NULL) 137 { 138 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); 139 DEBUG_puts("_ppdCacheCreateWithFile: Unable to allocate _ppd_cache_t."); 140 goto create_error; 141 } 142 143 pc->max_copies = 9999; 144 145 /* 146 * Read the file... 147 */ 148 149 linenum = 0; 150 num_bins = 0; 151 num_sizes = 0; 152 num_sources = 0; 153 num_types = 0; 154 155 while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum)) 156 { 157 DEBUG_printf(("_ppdCacheCreateWithFile: line=\"%s\", value=\"%s\", " 158 "linenum=%d", line, value, linenum)); 159 160 if (!value) 161 { 162 DEBUG_printf(("_ppdCacheCreateWithFile: Missing value on line %d.", 163 linenum)); 164 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1); 165 goto create_error; 166 } 167 else if (!_cups_strcasecmp(line, "Filter")) 168 { 169 if (!pc->filters) 170 pc->filters = cupsArrayNew3(NULL, NULL, NULL, 0, 171 (cups_acopy_func_t)_cupsStrAlloc, 172 (cups_afree_func_t)_cupsStrFree); 173 174 cupsArrayAdd(pc->filters, value); 175 } 176 else if (!_cups_strcasecmp(line, "PreFilter")) 177 { 178 if (!pc->prefilters) 179 pc->prefilters = cupsArrayNew3(NULL, NULL, NULL, 0, 180 (cups_acopy_func_t)_cupsStrAlloc, 181 (cups_afree_func_t)_cupsStrFree); 182 183 cupsArrayAdd(pc->prefilters, value); 184 } 185 else if (!_cups_strcasecmp(line, "Product")) 186 { 187 pc->product = _cupsStrAlloc(value); 188 } 189 else if (!_cups_strcasecmp(line, "SingleFile")) 190 { 191 pc->single_file = !_cups_strcasecmp(value, "true"); 192 } 193 else if (!_cups_strcasecmp(line, "IPP")) 194 { 195 off_t pos = cupsFileTell(fp), /* Position in file */ 196 length = strtol(value, NULL, 10); 197 /* Length of IPP attributes */ 198 199 if (attrs && *attrs) 200 { 201 DEBUG_puts("_ppdCacheCreateWithFile: IPP listed multiple times."); 202 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1); 203 goto create_error; 204 } 205 else if (length <= 0) 206 { 207 DEBUG_puts("_ppdCacheCreateWithFile: Bad IPP length."); 208 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1); 209 goto create_error; 210 } 211 212 if (attrs) 213 { 214 /* 215 * Read IPP attributes into the provided variable... 216 */ 217 218 *attrs = ippNew(); 219 220 if (ippReadIO(fp, (ipp_iocb_t)cupsFileRead, 1, NULL, 221 *attrs) != IPP_STATE_DATA) 222 { 223 DEBUG_puts("_ppdCacheCreateWithFile: Bad IPP data."); 224 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1); 225 goto create_error; 226 } 227 } 228 else 229 { 230 /* 231 * Skip the IPP data entirely... 232 */ 233 234 cupsFileSeek(fp, pos + length); 235 } 236 237 if (cupsFileTell(fp) != (pos + length)) 238 { 239 DEBUG_puts("_ppdCacheCreateWithFile: Bad IPP data."); 240 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1); 241 goto create_error; 242 } 243 } 244 else if (!_cups_strcasecmp(line, "NumBins")) 245 { 246 if (num_bins > 0) 247 { 248 DEBUG_puts("_ppdCacheCreateWithFile: NumBins listed multiple times."); 249 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1); 250 goto create_error; 251 } 252 253 if ((num_bins = atoi(value)) <= 0 || num_bins > 65536) 254 { 255 DEBUG_printf(("_ppdCacheCreateWithFile: Bad NumBins value %d on line " 256 "%d.", num_sizes, linenum)); 257 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1); 258 goto create_error; 259 } 260 261 if ((pc->bins = calloc((size_t)num_bins, sizeof(pwg_map_t))) == NULL) 262 { 263 DEBUG_printf(("_ppdCacheCreateWithFile: Unable to allocate %d bins.", 264 num_sizes)); 265 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); 266 goto create_error; 267 } 268 } 269 else if (!_cups_strcasecmp(line, "Bin")) 270 { 271 if (sscanf(value, "%127s%40s", pwg_keyword, ppd_keyword) != 2) 272 { 273 DEBUG_printf(("_ppdCacheCreateWithFile: Bad Bin on line %d.", linenum)); 274 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1); 275 goto create_error; 276 } 277 278 if (pc->num_bins >= num_bins) 279 { 280 DEBUG_printf(("_ppdCacheCreateWithFile: Too many Bin's on line %d.", 281 linenum)); 282 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1); 283 goto create_error; 284 } 285 286 map = pc->bins + pc->num_bins; 287 map->pwg = _cupsStrAlloc(pwg_keyword); 288 map->ppd = _cupsStrAlloc(ppd_keyword); 289 290 pc->num_bins ++; 291 } 292 else if (!_cups_strcasecmp(line, "NumSizes")) 293 { 294 if (num_sizes > 0) 295 { 296 DEBUG_puts("_ppdCacheCreateWithFile: NumSizes listed multiple times."); 297 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1); 298 goto create_error; 299 } 300 301 if ((num_sizes = atoi(value)) < 0 || num_sizes > 65536) 302 { 303 DEBUG_printf(("_ppdCacheCreateWithFile: Bad NumSizes value %d on line " 304 "%d.", num_sizes, linenum)); 305 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1); 306 goto create_error; 307 } 308 309 if (num_sizes > 0) 310 { 311 if ((pc->sizes = calloc((size_t)num_sizes, sizeof(pwg_size_t))) == NULL) 312 { 313 DEBUG_printf(("_ppdCacheCreateWithFile: Unable to allocate %d sizes.", 314 num_sizes)); 315 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); 316 goto create_error; 317 } 318 } 319 } 320 else if (!_cups_strcasecmp(line, "Size")) 321 { 322 if (pc->num_sizes >= num_sizes) 323 { 324 DEBUG_printf(("_ppdCacheCreateWithFile: Too many Size's on line %d.", 325 linenum)); 326 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1); 327 goto create_error; 328 } 329 330 size = pc->sizes + pc->num_sizes; 331 332 if (sscanf(value, "%127s%40s%d%d%d%d%d%d", pwg_keyword, ppd_keyword, 333 &(size->width), &(size->length), &(size->left), 334 &(size->bottom), &(size->right), &(size->top)) != 8) 335 { 336 DEBUG_printf(("_ppdCacheCreateWithFile: Bad Size on line %d.", 337 linenum)); 338 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1); 339 goto create_error; 340 } 341 342 size->map.pwg = _cupsStrAlloc(pwg_keyword); 343 size->map.ppd = _cupsStrAlloc(ppd_keyword); 344 345 pc->num_sizes ++; 346 } 347 else if (!_cups_strcasecmp(line, "CustomSize")) 348 { 349 if (pc->custom_max_width > 0) 350 { 351 DEBUG_printf(("_ppdCacheCreateWithFile: Too many CustomSize's on line " 352 "%d.", linenum)); 353 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1); 354 goto create_error; 355 } 356 357 if (sscanf(value, "%d%d%d%d%d%d%d%d", &(pc->custom_max_width), 358 &(pc->custom_max_length), &(pc->custom_min_width), 359 &(pc->custom_min_length), &(pc->custom_size.left), 360 &(pc->custom_size.bottom), &(pc->custom_size.right), 361 &(pc->custom_size.top)) != 8) 362 { 363 DEBUG_printf(("_ppdCacheCreateWithFile: Bad CustomSize on line %d.", 364 linenum)); 365 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1); 366 goto create_error; 367 } 368 369 pwgFormatSizeName(pwg_keyword, sizeof(pwg_keyword), "custom", "max", 370 pc->custom_max_width, pc->custom_max_length, NULL); 371 pc->custom_max_keyword = _cupsStrAlloc(pwg_keyword); 372 373 pwgFormatSizeName(pwg_keyword, sizeof(pwg_keyword), "custom", "min", 374 pc->custom_min_width, pc->custom_min_length, NULL); 375 pc->custom_min_keyword = _cupsStrAlloc(pwg_keyword); 376 } 377 else if (!_cups_strcasecmp(line, "SourceOption")) 378 { 379 pc->source_option = _cupsStrAlloc(value); 380 } 381 else if (!_cups_strcasecmp(line, "NumSources")) 382 { 383 if (num_sources > 0) 384 { 385 DEBUG_puts("_ppdCacheCreateWithFile: NumSources listed multiple " 386 "times."); 387 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1); 388 goto create_error; 389 } 390 391 if ((num_sources = atoi(value)) <= 0 || num_sources > 65536) 392 { 393 DEBUG_printf(("_ppdCacheCreateWithFile: Bad NumSources value %d on " 394 "line %d.", num_sources, linenum)); 395 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1); 396 goto create_error; 397 } 398 399 if ((pc->sources = calloc((size_t)num_sources, sizeof(pwg_map_t))) == NULL) 400 { 401 DEBUG_printf(("_ppdCacheCreateWithFile: Unable to allocate %d sources.", 402 num_sources)); 403 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); 404 goto create_error; 405 } 406 } 407 else if (!_cups_strcasecmp(line, "Source")) 408 { 409 if (sscanf(value, "%127s%40s", pwg_keyword, ppd_keyword) != 2) 410 { 411 DEBUG_printf(("_ppdCacheCreateWithFile: Bad Source on line %d.", 412 linenum)); 413 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1); 414 goto create_error; 415 } 416 417 if (pc->num_sources >= num_sources) 418 { 419 DEBUG_printf(("_ppdCacheCreateWithFile: Too many Source's on line %d.", 420 linenum)); 421 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1); 422 goto create_error; 423 } 424 425 map = pc->sources + pc->num_sources; 426 map->pwg = _cupsStrAlloc(pwg_keyword); 427 map->ppd = _cupsStrAlloc(ppd_keyword); 428 429 pc->num_sources ++; 430 } 431 else if (!_cups_strcasecmp(line, "NumTypes")) 432 { 433 if (num_types > 0) 434 { 435 DEBUG_puts("_ppdCacheCreateWithFile: NumTypes listed multiple times."); 436 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1); 437 goto create_error; 438 } 439 440 if ((num_types = atoi(value)) <= 0 || num_types > 65536) 441 { 442 DEBUG_printf(("_ppdCacheCreateWithFile: Bad NumTypes value %d on " 443 "line %d.", num_types, linenum)); 444 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1); 445 goto create_error; 446 } 447 448 if ((pc->types = calloc((size_t)num_types, sizeof(pwg_map_t))) == NULL) 449 { 450 DEBUG_printf(("_ppdCacheCreateWithFile: Unable to allocate %d types.", 451 num_types)); 452 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); 453 goto create_error; 454 } 455 } 456 else if (!_cups_strcasecmp(line, "Type")) 457 { 458 if (sscanf(value, "%127s%40s", pwg_keyword, ppd_keyword) != 2) 459 { 460 DEBUG_printf(("_ppdCacheCreateWithFile: Bad Type on line %d.", 461 linenum)); 462 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1); 463 goto create_error; 464 } 465 466 if (pc->num_types >= num_types) 467 { 468 DEBUG_printf(("_ppdCacheCreateWithFile: Too many Type's on line %d.", 469 linenum)); 470 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1); 471 goto create_error; 472 } 473 474 map = pc->types + pc->num_types; 475 map->pwg = _cupsStrAlloc(pwg_keyword); 476 map->ppd = _cupsStrAlloc(ppd_keyword); 477 478 pc->num_types ++; 479 } 480 else if (!_cups_strcasecmp(line, "Preset")) 481 { 482 /* 483 * Preset output-mode print-quality name=value ... 484 */ 485 486 print_color_mode = (_pwg_print_color_mode_t)strtol(value, &valueptr, 10); 487 print_quality = (_pwg_print_quality_t)strtol(valueptr, &valueptr, 10); 488 489 if (print_color_mode < _PWG_PRINT_COLOR_MODE_MONOCHROME || 490 print_color_mode >= _PWG_PRINT_COLOR_MODE_MAX || 491 print_quality < _PWG_PRINT_QUALITY_DRAFT || 492 print_quality >= _PWG_PRINT_QUALITY_MAX || 493 valueptr == value || !*valueptr) 494 { 495 DEBUG_printf(("_ppdCacheCreateWithFile: Bad Preset on line %d.", 496 linenum)); 497 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1); 498 goto create_error; 499 } 500 501 pc->num_presets[print_color_mode][print_quality] = 502 cupsParseOptions(valueptr, 0, 503 pc->presets[print_color_mode] + print_quality); 504 } 505 else if (!_cups_strcasecmp(line, "SidesOption")) 506 pc->sides_option = _cupsStrAlloc(value); 507 else if (!_cups_strcasecmp(line, "Sides1Sided")) 508 pc->sides_1sided = _cupsStrAlloc(value); 509 else if (!_cups_strcasecmp(line, "Sides2SidedLong")) 510 pc->sides_2sided_long = _cupsStrAlloc(value); 511 else if (!_cups_strcasecmp(line, "Sides2SidedShort")) 512 pc->sides_2sided_short = _cupsStrAlloc(value); 513 else if (!_cups_strcasecmp(line, "Finishings")) 514 { 515 if (!pc->finishings) 516 pc->finishings = 517 cupsArrayNew3((cups_array_func_t)pwg_compare_finishings, 518 NULL, NULL, 0, NULL, 519 (cups_afree_func_t)pwg_free_finishings); 520 521 if ((finishings = calloc(1, sizeof(_pwg_finishings_t))) == NULL) 522 goto create_error; 523 524 finishings->value = (ipp_finishings_t)strtol(value, &valueptr, 10); 525 finishings->num_options = cupsParseOptions(valueptr, 0, 526 &(finishings->options)); 527 528 cupsArrayAdd(pc->finishings, finishings); 529 } 530 else if (!_cups_strcasecmp(line, "MaxCopies")) 531 pc->max_copies = atoi(value); 532 else if (!_cups_strcasecmp(line, "ChargeInfoURI")) 533 pc->charge_info_uri = _cupsStrAlloc(value); 534 else if (!_cups_strcasecmp(line, "JobAccountId")) 535 pc->account_id = !_cups_strcasecmp(value, "true"); 536 else if (!_cups_strcasecmp(line, "JobAccountingUserId")) 537 pc->accounting_user_id = !_cups_strcasecmp(value, "true"); 538 else if (!_cups_strcasecmp(line, "JobPassword")) 539 pc->password = _cupsStrAlloc(value); 540 else if (!_cups_strcasecmp(line, "Mandatory")) 541 { 542 if (pc->mandatory) 543 _cupsArrayAddStrings(pc->mandatory, value, ' '); 544 else 545 pc->mandatory = _cupsArrayNewStrings(value, ' '); 546 } 547 else if (!_cups_strcasecmp(line, "SupportFile")) 548 { 549 if (!pc->support_files) 550 pc->support_files = cupsArrayNew3(NULL, NULL, NULL, 0, 551 (cups_acopy_func_t)_cupsStrAlloc, 552 (cups_afree_func_t)_cupsStrFree); 553 554 cupsArrayAdd(pc->support_files, value); 555 } 556 else 557 { 558 DEBUG_printf(("_ppdCacheCreateWithFile: Unknown %s on line %d.", line, 559 linenum)); 560 } 561 } 562 563 if (pc->num_sizes < num_sizes) 564 { 565 DEBUG_printf(("_ppdCacheCreateWithFile: Not enough sizes (%d < %d).", 566 pc->num_sizes, num_sizes)); 567 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1); 568 goto create_error; 569 } 570 571 if (pc->num_sources < num_sources) 572 { 573 DEBUG_printf(("_ppdCacheCreateWithFile: Not enough sources (%d < %d).", 574 pc->num_sources, num_sources)); 575 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1); 576 goto create_error; 577 } 578 579 if (pc->num_types < num_types) 580 { 581 DEBUG_printf(("_ppdCacheCreateWithFile: Not enough types (%d < %d).", 582 pc->num_types, num_types)); 583 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1); 584 goto create_error; 585 } 586 587 cupsFileClose(fp); 588 589 return (pc); 590 591 /* 592 * If we get here the file was bad - free any data and return... 593 */ 594 595 create_error: 596 597 cupsFileClose(fp); 598 _ppdCacheDestroy(pc); 599 600 if (attrs) 601 { 602 ippDelete(*attrs); 603 *attrs = NULL; 604 } 605 606 return (NULL); 607} 608 609 610/* 611 * '_ppdCacheCreateWithPPD()' - Create PWG mapping data from a PPD file. 612 */ 613 614_ppd_cache_t * /* O - PPD cache and mapping data */ 615_ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ 616{ 617 int i, j, k; /* Looping vars */ 618 _ppd_cache_t *pc; /* PWG mapping data */ 619 ppd_option_t *input_slot, /* InputSlot option */ 620 *media_type, /* MediaType option */ 621 *output_bin, /* OutputBin option */ 622 *color_model, /* ColorModel option */ 623 *duplex; /* Duplex option */ 624 ppd_choice_t *choice; /* Current InputSlot/MediaType */ 625 pwg_map_t *map; /* Current source/type map */ 626 ppd_attr_t *ppd_attr; /* Current PPD preset attribute */ 627 int num_options; /* Number of preset options and props */ 628 cups_option_t *options; /* Preset options and properties */ 629 ppd_size_t *ppd_size; /* Current PPD size */ 630 pwg_size_t *pwg_size; /* Current PWG size */ 631 char pwg_keyword[3 + PPD_MAX_NAME + 1 + 12 + 1 + 12 + 3], 632 /* PWG keyword string */ 633 ppd_name[PPD_MAX_NAME]; 634 /* Normalized PPD name */ 635 const char *pwg_name; /* Standard PWG media name */ 636 pwg_media_t *pwg_media; /* PWG media data */ 637 _pwg_print_color_mode_t pwg_print_color_mode; 638 /* print-color-mode index */ 639 _pwg_print_quality_t pwg_print_quality; 640 /* print-quality index */ 641 int similar; /* Are the old and new size similar? */ 642 pwg_size_t *old_size; /* Current old size */ 643 int old_imageable, /* Old imageable length in 2540ths */ 644 old_borderless, /* Old borderless state */ 645 old_known_pwg; /* Old PWG name is well-known */ 646 int new_width, /* New width in 2540ths */ 647 new_length, /* New length in 2540ths */ 648 new_left, /* New left margin in 2540ths */ 649 new_bottom, /* New bottom margin in 2540ths */ 650 new_right, /* New right margin in 2540ths */ 651 new_top, /* New top margin in 2540ths */ 652 new_imageable, /* New imageable length in 2540ths */ 653 new_borderless, /* New borderless state */ 654 new_known_pwg; /* New PWG name is well-known */ 655 pwg_size_t *new_size; /* New size to add, if any */ 656 const char *filter; /* Current filter */ 657 _pwg_finishings_t *finishings; /* Current finishings value */ 658 659 660 DEBUG_printf(("_ppdCacheCreateWithPPD(ppd=%p)", ppd)); 661 662 /* 663 * Range check input... 664 */ 665 666 if (!ppd) 667 return (NULL); 668 669 /* 670 * Allocate memory... 671 */ 672 673 if ((pc = calloc(1, sizeof(_ppd_cache_t))) == NULL) 674 { 675 DEBUG_puts("_ppdCacheCreateWithPPD: Unable to allocate _ppd_cache_t."); 676 goto create_error; 677 } 678 679 /* 680 * Copy and convert size data... 681 */ 682 683 if (ppd->num_sizes > 0) 684 { 685 if ((pc->sizes = calloc((size_t)ppd->num_sizes, sizeof(pwg_size_t))) == NULL) 686 { 687 DEBUG_printf(("_ppdCacheCreateWithPPD: Unable to allocate %d " 688 "pwg_size_t's.", ppd->num_sizes)); 689 goto create_error; 690 } 691 692 for (i = ppd->num_sizes, pwg_size = pc->sizes, ppd_size = ppd->sizes; 693 i > 0; 694 i --, ppd_size ++) 695 { 696 /* 697 * Don't copy over custom size... 698 */ 699 700 if (!_cups_strcasecmp(ppd_size->name, "Custom")) 701 continue; 702 703 /* 704 * Convert the PPD size name to the corresponding PWG keyword name. 705 */ 706 707 if ((pwg_media = pwgMediaForPPD(ppd_size->name)) != NULL) 708 { 709 /* 710 * Standard name, do we have conflicts? 711 */ 712 713 for (j = 0; j < pc->num_sizes; j ++) 714 if (!strcmp(pc->sizes[j].map.pwg, pwg_media->pwg)) 715 { 716 pwg_media = NULL; 717 break; 718 } 719 } 720 721 if (pwg_media) 722 { 723 /* 724 * Standard name and no conflicts, use it! 725 */ 726 727 pwg_name = pwg_media->pwg; 728 new_known_pwg = 1; 729 } 730 else 731 { 732 /* 733 * Not a standard name; convert it to a PWG vendor name of the form: 734 * 735 * pp_lowerppd_WIDTHxHEIGHTuu 736 */ 737 738 pwg_name = pwg_keyword; 739 new_known_pwg = 0; 740 741 pwg_unppdize_name(ppd_size->name, ppd_name, sizeof(ppd_name), "_."); 742 pwgFormatSizeName(pwg_keyword, sizeof(pwg_keyword), NULL, ppd_name, 743 PWG_FROM_POINTS(ppd_size->width), 744 PWG_FROM_POINTS(ppd_size->length), NULL); 745 } 746 747 /* 748 * If we have a similar paper with non-zero margins then we only want to 749 * keep it if it has a larger imageable area length. The NULL check is for 750 * dimensions that are <= 0... 751 */ 752 753 if ((pwg_media = _pwgMediaNearSize(PWG_FROM_POINTS(ppd_size->width), 754 PWG_FROM_POINTS(ppd_size->length), 755 0)) == NULL) 756 continue; 757 758 new_width = pwg_media->width; 759 new_length = pwg_media->length; 760 new_left = PWG_FROM_POINTS(ppd_size->left); 761 new_bottom = PWG_FROM_POINTS(ppd_size->bottom); 762 new_right = PWG_FROM_POINTS(ppd_size->width - ppd_size->right); 763 new_top = PWG_FROM_POINTS(ppd_size->length - ppd_size->top); 764 new_imageable = new_length - new_top - new_bottom; 765 new_borderless = new_bottom == 0 && new_top == 0 && 766 new_left == 0 && new_right == 0; 767 768 for (k = pc->num_sizes, similar = 0, old_size = pc->sizes, new_size = NULL; 769 k > 0 && !similar; 770 k --, old_size ++) 771 { 772 old_imageable = old_size->length - old_size->top - old_size->bottom; 773 old_borderless = old_size->left == 0 && old_size->bottom == 0 && 774 old_size->right == 0 && old_size->top == 0; 775 old_known_pwg = strncmp(old_size->map.pwg, "oe_", 3) && 776 strncmp(old_size->map.pwg, "om_", 3); 777 778 similar = old_borderless == new_borderless && 779 _PWG_EQUIVALENT(old_size->width, new_width) && 780 _PWG_EQUIVALENT(old_size->length, new_length); 781 782 if (similar && 783 (new_known_pwg || (!old_known_pwg && new_imageable > old_imageable))) 784 { 785 /* 786 * The new paper has a larger imageable area so it could replace 787 * the older paper. Regardless of the imageable area, we always 788 * prefer the size with a well-known PWG name. 789 */ 790 791 new_size = old_size; 792 _cupsStrFree(old_size->map.ppd); 793 _cupsStrFree(old_size->map.pwg); 794 } 795 } 796 797 if (!similar) 798 { 799 /* 800 * The paper was unique enough to deserve its own entry so add it to the 801 * end. 802 */ 803 804 new_size = pwg_size ++; 805 pc->num_sizes ++; 806 } 807 808 if (new_size) 809 { 810 /* 811 * Save this size... 812 */ 813 814 new_size->map.ppd = _cupsStrAlloc(ppd_size->name); 815 new_size->map.pwg = _cupsStrAlloc(pwg_name); 816 new_size->width = new_width; 817 new_size->length = new_length; 818 new_size->left = new_left; 819 new_size->bottom = new_bottom; 820 new_size->right = new_right; 821 new_size->top = new_top; 822 } 823 } 824 } 825 826 if (ppd->variable_sizes) 827 { 828 /* 829 * Generate custom size data... 830 */ 831 832 pwgFormatSizeName(pwg_keyword, sizeof(pwg_keyword), "custom", "max", 833 PWG_FROM_POINTS(ppd->custom_max[0]), 834 PWG_FROM_POINTS(ppd->custom_max[1]), NULL); 835 pc->custom_max_keyword = _cupsStrAlloc(pwg_keyword); 836 pc->custom_max_width = PWG_FROM_POINTS(ppd->custom_max[0]); 837 pc->custom_max_length = PWG_FROM_POINTS(ppd->custom_max[1]); 838 839 pwgFormatSizeName(pwg_keyword, sizeof(pwg_keyword), "custom", "min", 840 PWG_FROM_POINTS(ppd->custom_min[0]), 841 PWG_FROM_POINTS(ppd->custom_min[1]), NULL); 842 pc->custom_min_keyword = _cupsStrAlloc(pwg_keyword); 843 pc->custom_min_width = PWG_FROM_POINTS(ppd->custom_min[0]); 844 pc->custom_min_length = PWG_FROM_POINTS(ppd->custom_min[1]); 845 846 pc->custom_size.left = PWG_FROM_POINTS(ppd->custom_margins[0]); 847 pc->custom_size.bottom = PWG_FROM_POINTS(ppd->custom_margins[1]); 848 pc->custom_size.right = PWG_FROM_POINTS(ppd->custom_margins[2]); 849 pc->custom_size.top = PWG_FROM_POINTS(ppd->custom_margins[3]); 850 } 851 852 /* 853 * Copy and convert InputSlot data... 854 */ 855 856 if ((input_slot = ppdFindOption(ppd, "InputSlot")) == NULL) 857 input_slot = ppdFindOption(ppd, "HPPaperSource"); 858 859 if (input_slot) 860 { 861 pc->source_option = _cupsStrAlloc(input_slot->keyword); 862 863 if ((pc->sources = calloc((size_t)input_slot->num_choices, sizeof(pwg_map_t))) == NULL) 864 { 865 DEBUG_printf(("_ppdCacheCreateWithPPD: Unable to allocate %d " 866 "pwg_map_t's for InputSlot.", input_slot->num_choices)); 867 goto create_error; 868 } 869 870 pc->num_sources = input_slot->num_choices; 871 872 for (i = input_slot->num_choices, choice = input_slot->choices, 873 map = pc->sources; 874 i > 0; 875 i --, choice ++, map ++) 876 { 877 if (!_cups_strncasecmp(choice->choice, "Auto", 4) || 878 !_cups_strcasecmp(choice->choice, "Default")) 879 pwg_name = "auto"; 880 else if (!_cups_strcasecmp(choice->choice, "Cassette")) 881 pwg_name = "main"; 882 else if (!_cups_strcasecmp(choice->choice, "PhotoTray")) 883 pwg_name = "photo"; 884 else if (!_cups_strcasecmp(choice->choice, "CDTray")) 885 pwg_name = "disc"; 886 else if (!_cups_strncasecmp(choice->choice, "Multipurpose", 12) || 887 !_cups_strcasecmp(choice->choice, "MP") || 888 !_cups_strcasecmp(choice->choice, "MPTray")) 889 pwg_name = "by-pass-tray"; 890 else if (!_cups_strcasecmp(choice->choice, "LargeCapacity")) 891 pwg_name = "large-capacity"; 892 else if (!_cups_strncasecmp(choice->choice, "Lower", 5)) 893 pwg_name = "bottom"; 894 else if (!_cups_strncasecmp(choice->choice, "Middle", 6)) 895 pwg_name = "middle"; 896 else if (!_cups_strncasecmp(choice->choice, "Upper", 5)) 897 pwg_name = "top"; 898 else if (!_cups_strncasecmp(choice->choice, "Side", 4)) 899 pwg_name = "side"; 900 else if (!_cups_strcasecmp(choice->choice, "Roll")) 901 pwg_name = "main-roll"; 902 else 903 { 904 /* 905 * Convert PPD name to lowercase... 906 */ 907 908 pwg_name = pwg_keyword; 909 pwg_unppdize_name(choice->choice, pwg_keyword, sizeof(pwg_keyword), 910 "_"); 911 } 912 913 map->pwg = _cupsStrAlloc(pwg_name); 914 map->ppd = _cupsStrAlloc(choice->choice); 915 } 916 } 917 918 /* 919 * Copy and convert MediaType data... 920 */ 921 922 if ((media_type = ppdFindOption(ppd, "MediaType")) != NULL) 923 { 924 if ((pc->types = calloc((size_t)media_type->num_choices, sizeof(pwg_map_t))) == NULL) 925 { 926 DEBUG_printf(("_ppdCacheCreateWithPPD: Unable to allocate %d " 927 "pwg_map_t's for MediaType.", media_type->num_choices)); 928 goto create_error; 929 } 930 931 pc->num_types = media_type->num_choices; 932 933 for (i = media_type->num_choices, choice = media_type->choices, 934 map = pc->types; 935 i > 0; 936 i --, choice ++, map ++) 937 { 938 if (!_cups_strncasecmp(choice->choice, "Auto", 4) || 939 !_cups_strcasecmp(choice->choice, "Any") || 940 !_cups_strcasecmp(choice->choice, "Default")) 941 pwg_name = "auto"; 942 else if (!_cups_strncasecmp(choice->choice, "Card", 4)) 943 pwg_name = "cardstock"; 944 else if (!_cups_strncasecmp(choice->choice, "Env", 3)) 945 pwg_name = "envelope"; 946 else if (!_cups_strncasecmp(choice->choice, "Gloss", 5)) 947 pwg_name = "photographic-glossy"; 948 else if (!_cups_strcasecmp(choice->choice, "HighGloss")) 949 pwg_name = "photographic-high-gloss"; 950 else if (!_cups_strcasecmp(choice->choice, "Matte")) 951 pwg_name = "photographic-matte"; 952 else if (!_cups_strncasecmp(choice->choice, "Plain", 5)) 953 pwg_name = "stationery"; 954 else if (!_cups_strncasecmp(choice->choice, "Coated", 6)) 955 pwg_name = "stationery-coated"; 956 else if (!_cups_strcasecmp(choice->choice, "Inkjet")) 957 pwg_name = "stationery-inkjet"; 958 else if (!_cups_strcasecmp(choice->choice, "Letterhead")) 959 pwg_name = "stationery-letterhead"; 960 else if (!_cups_strncasecmp(choice->choice, "Preprint", 8)) 961 pwg_name = "stationery-preprinted"; 962 else if (!_cups_strcasecmp(choice->choice, "Recycled")) 963 pwg_name = "stationery-recycled"; 964 else if (!_cups_strncasecmp(choice->choice, "Transparen", 10)) 965 pwg_name = "transparency"; 966 else 967 { 968 /* 969 * Convert PPD name to lowercase... 970 */ 971 972 pwg_name = pwg_keyword; 973 pwg_unppdize_name(choice->choice, pwg_keyword, sizeof(pwg_keyword), 974 "_"); 975 } 976 977 map->pwg = _cupsStrAlloc(pwg_name); 978 map->ppd = _cupsStrAlloc(choice->choice); 979 } 980 } 981 982 /* 983 * Copy and convert OutputBin data... 984 */ 985 986 if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL) 987 { 988 if ((pc->bins = calloc((size_t)output_bin->num_choices, sizeof(pwg_map_t))) == NULL) 989 { 990 DEBUG_printf(("_ppdCacheCreateWithPPD: Unable to allocate %d " 991 "pwg_map_t's for OutputBin.", output_bin->num_choices)); 992 goto create_error; 993 } 994 995 pc->num_bins = output_bin->num_choices; 996 997 for (i = output_bin->num_choices, choice = output_bin->choices, 998 map = pc->bins; 999 i > 0; 1000 i --, choice ++, map ++) 1001 { 1002 pwg_unppdize_name(choice->choice, pwg_keyword, sizeof(pwg_keyword), "_"); 1003 1004 map->pwg = _cupsStrAlloc(pwg_keyword); 1005 map->ppd = _cupsStrAlloc(choice->choice); 1006 } 1007 } 1008 1009 if ((ppd_attr = ppdFindAttr(ppd, "APPrinterPreset", NULL)) != NULL) 1010 { 1011 /* 1012 * Copy and convert APPrinterPreset (output-mode + print-quality) data... 1013 */ 1014 1015 const char *quality, /* com.apple.print.preset.quality value */ 1016 *output_mode, /* com.apple.print.preset.output-mode value */ 1017 *color_model_val, /* ColorModel choice */ 1018 *graphicsType, /* com.apple.print.preset.graphicsType value */ 1019 *media_front_coating; /* com.apple.print.preset.media-front-coating value */ 1020 1021 do 1022 { 1023 num_options = _ppdParseOptions(ppd_attr->value, 0, &options, 1024 _PPD_PARSE_ALL); 1025 1026 if ((quality = cupsGetOption("com.apple.print.preset.quality", 1027 num_options, options)) != NULL) 1028 { 1029 /* 1030 * Get the print-quality for this preset... 1031 */ 1032 1033 if (!strcmp(quality, "low")) 1034 pwg_print_quality = _PWG_PRINT_QUALITY_DRAFT; 1035 else if (!strcmp(quality, "high")) 1036 pwg_print_quality = _PWG_PRINT_QUALITY_HIGH; 1037 else 1038 pwg_print_quality = _PWG_PRINT_QUALITY_NORMAL; 1039 1040 /* 1041 * Ignore graphicsType "Photo" presets that are not high quality. 1042 */ 1043 1044 graphicsType = cupsGetOption("com.apple.print.preset.graphicsType", 1045 num_options, options); 1046 1047 if (pwg_print_quality != _PWG_PRINT_QUALITY_HIGH && graphicsType && 1048 !strcmp(graphicsType, "Photo")) 1049 continue; 1050 1051 /* 1052 * Ignore presets for normal and draft quality where the coating 1053 * isn't "none" or "autodetect". 1054 */ 1055 1056 media_front_coating = cupsGetOption( 1057 "com.apple.print.preset.media-front-coating", 1058 num_options, options); 1059 1060 if (pwg_print_quality != _PWG_PRINT_QUALITY_HIGH && 1061 media_front_coating && 1062 strcmp(media_front_coating, "none") && 1063 strcmp(media_front_coating, "autodetect")) 1064 continue; 1065 1066 /* 1067 * Get the output mode for this preset... 1068 */ 1069 1070 output_mode = cupsGetOption("com.apple.print.preset.output-mode", 1071 num_options, options); 1072 color_model_val = cupsGetOption("ColorModel", num_options, options); 1073 1074 if (output_mode) 1075 { 1076 if (!strcmp(output_mode, "monochrome")) 1077 pwg_print_color_mode = _PWG_PRINT_COLOR_MODE_MONOCHROME; 1078 else 1079 pwg_print_color_mode = _PWG_PRINT_COLOR_MODE_COLOR; 1080 } 1081 else if (color_model_val) 1082 { 1083 if (!_cups_strcasecmp(color_model_val, "Gray")) 1084 pwg_print_color_mode = _PWG_PRINT_COLOR_MODE_MONOCHROME; 1085 else 1086 pwg_print_color_mode = _PWG_PRINT_COLOR_MODE_COLOR; 1087 } 1088 else 1089 pwg_print_color_mode = _PWG_PRINT_COLOR_MODE_COLOR; 1090 1091 /* 1092 * Save the options for this combination as needed... 1093 */ 1094 1095 if (!pc->num_presets[pwg_print_color_mode][pwg_print_quality]) 1096 pc->num_presets[pwg_print_color_mode][pwg_print_quality] = 1097 _ppdParseOptions(ppd_attr->value, 0, 1098 pc->presets[pwg_print_color_mode] + 1099 pwg_print_quality, _PPD_PARSE_OPTIONS); 1100 } 1101 1102 cupsFreeOptions(num_options, options); 1103 } 1104 while ((ppd_attr = ppdFindNextAttr(ppd, "APPrinterPreset", NULL)) != NULL); 1105 } 1106 1107 if (!pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][_PWG_PRINT_QUALITY_DRAFT] && 1108 !pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][_PWG_PRINT_QUALITY_NORMAL] && 1109 !pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][_PWG_PRINT_QUALITY_HIGH]) 1110 { 1111 /* 1112 * Try adding some common color options to create grayscale presets. These 1113 * are listed in order of popularity... 1114 */ 1115 1116 const char *color_option = NULL, /* Color control option */ 1117 *gray_choice = NULL; /* Choice to select grayscale */ 1118 1119 if ((color_model = ppdFindOption(ppd, "ColorModel")) != NULL && 1120 ppdFindChoice(color_model, "Gray")) 1121 { 1122 color_option = "ColorModel"; 1123 gray_choice = "Gray"; 1124 } 1125 else if ((color_model = ppdFindOption(ppd, "HPColorMode")) != NULL && 1126 ppdFindChoice(color_model, "grayscale")) 1127 { 1128 color_option = "HPColorMode"; 1129 gray_choice = "grayscale"; 1130 } 1131 else if ((color_model = ppdFindOption(ppd, "BRMonoColor")) != NULL && 1132 ppdFindChoice(color_model, "Mono")) 1133 { 1134 color_option = "BRMonoColor"; 1135 gray_choice = "Mono"; 1136 } 1137 else if ((color_model = ppdFindOption(ppd, "CNIJSGrayScale")) != NULL && 1138 ppdFindChoice(color_model, "1")) 1139 { 1140 color_option = "CNIJSGrayScale"; 1141 gray_choice = "1"; 1142 } 1143 else if ((color_model = ppdFindOption(ppd, "HPColorAsGray")) != NULL && 1144 ppdFindChoice(color_model, "True")) 1145 { 1146 color_option = "HPColorAsGray"; 1147 gray_choice = "True"; 1148 } 1149 1150 if (color_option && gray_choice) 1151 { 1152 /* 1153 * Copy and convert ColorModel (output-mode) data... 1154 */ 1155 1156 cups_option_t *coption, /* Color option */ 1157 *moption; /* Monochrome option */ 1158 1159 for (pwg_print_quality = _PWG_PRINT_QUALITY_DRAFT; 1160 pwg_print_quality < _PWG_PRINT_QUALITY_MAX; 1161 pwg_print_quality ++) 1162 { 1163 if (pc->num_presets[_PWG_PRINT_COLOR_MODE_COLOR][pwg_print_quality]) 1164 { 1165 /* 1166 * Copy the color options... 1167 */ 1168 1169 num_options = pc->num_presets[_PWG_PRINT_COLOR_MODE_COLOR] 1170 [pwg_print_quality]; 1171 options = calloc(sizeof(cups_option_t), (size_t)num_options); 1172 1173 if (options) 1174 { 1175 for (i = num_options, moption = options, 1176 coption = pc->presets[_PWG_PRINT_COLOR_MODE_COLOR] 1177 [pwg_print_quality]; 1178 i > 0; 1179 i --, moption ++, coption ++) 1180 { 1181 moption->name = _cupsStrRetain(coption->name); 1182 moption->value = _cupsStrRetain(coption->value); 1183 } 1184 1185 pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][pwg_print_quality] = 1186 num_options; 1187 pc->presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][pwg_print_quality] = 1188 options; 1189 } 1190 } 1191 else if (pwg_print_quality != _PWG_PRINT_QUALITY_NORMAL) 1192 continue; 1193 1194 /* 1195 * Add the grayscale option to the preset... 1196 */ 1197 1198 pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][pwg_print_quality] = 1199 cupsAddOption(color_option, gray_choice, 1200 pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME] 1201 [pwg_print_quality], 1202 pc->presets[_PWG_PRINT_COLOR_MODE_MONOCHROME] + 1203 pwg_print_quality); 1204 } 1205 } 1206 } 1207 1208 /* 1209 * Copy and convert Duplex (sides) data... 1210 */ 1211 1212 if ((duplex = ppdFindOption(ppd, "Duplex")) == NULL) 1213 if ((duplex = ppdFindOption(ppd, "JCLDuplex")) == NULL) 1214 if ((duplex = ppdFindOption(ppd, "EFDuplex")) == NULL) 1215 if ((duplex = ppdFindOption(ppd, "EFDuplexing")) == NULL) 1216 duplex = ppdFindOption(ppd, "KD03Duplex"); 1217 1218 if (duplex) 1219 { 1220 pc->sides_option = _cupsStrAlloc(duplex->keyword); 1221 1222 for (i = duplex->num_choices, choice = duplex->choices; 1223 i > 0; 1224 i --, choice ++) 1225 { 1226 if ((!_cups_strcasecmp(choice->choice, "None") || 1227 !_cups_strcasecmp(choice->choice, "False")) && !pc->sides_1sided) 1228 pc->sides_1sided = _cupsStrAlloc(choice->choice); 1229 else if ((!_cups_strcasecmp(choice->choice, "DuplexNoTumble") || 1230 !_cups_strcasecmp(choice->choice, "LongEdge") || 1231 !_cups_strcasecmp(choice->choice, "Top")) && !pc->sides_2sided_long) 1232 pc->sides_2sided_long = _cupsStrAlloc(choice->choice); 1233 else if ((!_cups_strcasecmp(choice->choice, "DuplexTumble") || 1234 !_cups_strcasecmp(choice->choice, "ShortEdge") || 1235 !_cups_strcasecmp(choice->choice, "Bottom")) && 1236 !pc->sides_2sided_short) 1237 pc->sides_2sided_short = _cupsStrAlloc(choice->choice); 1238 } 1239 } 1240 1241 /* 1242 * Copy filters and pre-filters... 1243 */ 1244 1245 pc->filters = cupsArrayNew3(NULL, NULL, NULL, 0, 1246 (cups_acopy_func_t)_cupsStrAlloc, 1247 (cups_afree_func_t)_cupsStrFree); 1248 1249 cupsArrayAdd(pc->filters, 1250 "application/vnd.cups-raw application/octet-stream 0 -"); 1251 1252 if ((ppd_attr = ppdFindAttr(ppd, "cupsFilter2", NULL)) != NULL) 1253 { 1254 do 1255 { 1256 cupsArrayAdd(pc->filters, ppd_attr->value); 1257 } 1258 while ((ppd_attr = ppdFindNextAttr(ppd, "cupsFilter2", NULL)) != NULL); 1259 } 1260 else if (ppd->num_filters > 0) 1261 { 1262 for (i = 0; i < ppd->num_filters; i ++) 1263 cupsArrayAdd(pc->filters, ppd->filters[i]); 1264 } 1265 else 1266 cupsArrayAdd(pc->filters, "application/vnd.cups-postscript 0 -"); 1267 1268 /* 1269 * See if we have a command filter... 1270 */ 1271 1272 for (filter = (const char *)cupsArrayFirst(pc->filters); 1273 filter; 1274 filter = (const char *)cupsArrayNext(pc->filters)) 1275 if (!_cups_strncasecmp(filter, "application/vnd.cups-command", 28) && 1276 _cups_isspace(filter[28])) 1277 break; 1278 1279 if (!filter && 1280 ((ppd_attr = ppdFindAttr(ppd, "cupsCommands", NULL)) == NULL || 1281 _cups_strcasecmp(ppd_attr->value, "none"))) 1282 { 1283 /* 1284 * No command filter and no cupsCommands keyword telling us not to use one. 1285 * See if this is a PostScript printer, and if so add a PostScript command 1286 * filter... 1287 */ 1288 1289 for (filter = (const char *)cupsArrayFirst(pc->filters); 1290 filter; 1291 filter = (const char *)cupsArrayNext(pc->filters)) 1292 if (!_cups_strncasecmp(filter, "application/vnd.cups-postscript", 31) && 1293 _cups_isspace(filter[31])) 1294 break; 1295 1296 if (filter) 1297 cupsArrayAdd(pc->filters, 1298 "application/vnd.cups-command application/postscript 100 " 1299 "commandtops"); 1300 } 1301 1302 if ((ppd_attr = ppdFindAttr(ppd, "cupsPreFilter", NULL)) != NULL) 1303 { 1304 pc->prefilters = cupsArrayNew3(NULL, NULL, NULL, 0, 1305 (cups_acopy_func_t)_cupsStrAlloc, 1306 (cups_afree_func_t)_cupsStrFree); 1307 1308 do 1309 { 1310 cupsArrayAdd(pc->prefilters, ppd_attr->value); 1311 } 1312 while ((ppd_attr = ppdFindNextAttr(ppd, "cupsPreFilter", NULL)) != NULL); 1313 } 1314 1315 if ((ppd_attr = ppdFindAttr(ppd, "cupsSingleFile", NULL)) != NULL) 1316 pc->single_file = !_cups_strcasecmp(ppd_attr->value, "true"); 1317 1318 /* 1319 * Copy the product string, if any... 1320 */ 1321 1322 if (ppd->product) 1323 pc->product = _cupsStrAlloc(ppd->product); 1324 1325 /* 1326 * Copy finishings mapping data... 1327 */ 1328 1329 if ((ppd_attr = ppdFindAttr(ppd, "cupsIPPFinishings", NULL)) != NULL) 1330 { 1331 pc->finishings = cupsArrayNew3((cups_array_func_t)pwg_compare_finishings, 1332 NULL, NULL, 0, NULL, 1333 (cups_afree_func_t)pwg_free_finishings); 1334 1335 do 1336 { 1337 if ((finishings = calloc(1, sizeof(_pwg_finishings_t))) == NULL) 1338 goto create_error; 1339 1340 finishings->value = (ipp_finishings_t)atoi(ppd_attr->spec); 1341 finishings->num_options = _ppdParseOptions(ppd_attr->value, 0, 1342 &(finishings->options), 1343 _PPD_PARSE_OPTIONS); 1344 1345 cupsArrayAdd(pc->finishings, finishings); 1346 } 1347 while ((ppd_attr = ppdFindNextAttr(ppd, "cupsIPPFinishings", 1348 NULL)) != NULL); 1349 } 1350 1351 /* 1352 * Max copies... 1353 */ 1354 1355 if ((ppd_attr = ppdFindAttr(ppd, "cupsMaxCopies", NULL)) != NULL) 1356 pc->max_copies = atoi(ppd_attr->value); 1357 else if (ppd->manual_copies) 1358 pc->max_copies = 1; 1359 else 1360 pc->max_copies = 9999; 1361 1362 /* 1363 * cupsChargeInfoURI, cupsJobAccountId, cupsJobAccountingUserId, 1364 * cupsJobPassword, and cupsMandatory. 1365 */ 1366 1367 if ((ppd_attr = ppdFindAttr(ppd, "cupsChargeInfoURI", NULL)) != NULL) 1368 pc->charge_info_uri = _cupsStrAlloc(ppd_attr->value); 1369 1370 if ((ppd_attr = ppdFindAttr(ppd, "cupsJobAccountId", NULL)) != NULL) 1371 pc->account_id = !_cups_strcasecmp(ppd_attr->value, "true"); 1372 1373 if ((ppd_attr = ppdFindAttr(ppd, "cupsJobAccountingUserId", NULL)) != NULL) 1374 pc->accounting_user_id = !_cups_strcasecmp(ppd_attr->value, "true"); 1375 1376 if ((ppd_attr = ppdFindAttr(ppd, "cupsJobPassword", NULL)) != NULL) 1377 pc->password = _cupsStrAlloc(ppd_attr->value); 1378 1379 if ((ppd_attr = ppdFindAttr(ppd, "cupsMandatory", NULL)) != NULL) 1380 pc->mandatory = _cupsArrayNewStrings(ppd_attr->value, ' '); 1381 1382 /* 1383 * Support files... 1384 */ 1385 1386 pc->support_files = cupsArrayNew3(NULL, NULL, NULL, 0, 1387 (cups_acopy_func_t)_cupsStrAlloc, 1388 (cups_afree_func_t)_cupsStrFree); 1389 1390 for (ppd_attr = ppdFindAttr(ppd, "cupsICCProfile", NULL); 1391 ppd_attr; 1392 ppd_attr = ppdFindNextAttr(ppd, "cupsICCProfile", NULL)) 1393 cupsArrayAdd(pc->support_files, ppd_attr->value); 1394 1395 if ((ppd_attr = ppdFindAttr(ppd, "APPrinterIconPath", NULL)) != NULL) 1396 cupsArrayAdd(pc->support_files, ppd_attr->value); 1397 1398 /* 1399 * Return the cache data... 1400 */ 1401 1402 return (pc); 1403 1404 /* 1405 * If we get here we need to destroy the PWG mapping data and return NULL... 1406 */ 1407 1408 create_error: 1409 1410 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Out of memory."), 1); 1411 _ppdCacheDestroy(pc); 1412 1413 return (NULL); 1414} 1415 1416 1417/* 1418 * '_ppdCacheDestroy()' - Free all memory used for PWG mapping data. 1419 */ 1420 1421void 1422_ppdCacheDestroy(_ppd_cache_t *pc) /* I - PPD cache and mapping data */ 1423{ 1424 int i; /* Looping var */ 1425 pwg_map_t *map; /* Current map */ 1426 pwg_size_t *size; /* Current size */ 1427 1428 1429 /* 1430 * Range check input... 1431 */ 1432 1433 if (!pc) 1434 return; 1435 1436 /* 1437 * Free memory as needed... 1438 */ 1439 1440 if (pc->bins) 1441 { 1442 for (i = pc->num_bins, map = pc->bins; i > 0; i --, map ++) 1443 { 1444 _cupsStrFree(map->pwg); 1445 _cupsStrFree(map->ppd); 1446 } 1447 1448 free(pc->bins); 1449 } 1450 1451 if (pc->sizes) 1452 { 1453 for (i = pc->num_sizes, size = pc->sizes; i > 0; i --, size ++) 1454 { 1455 _cupsStrFree(size->map.pwg); 1456 _cupsStrFree(size->map.ppd); 1457 } 1458 1459 free(pc->sizes); 1460 } 1461 1462 if (pc->source_option) 1463 _cupsStrFree(pc->source_option); 1464 1465 if (pc->sources) 1466 { 1467 for (i = pc->num_sources, map = pc->sources; i > 0; i --, map ++) 1468 { 1469 _cupsStrFree(map->pwg); 1470 _cupsStrFree(map->ppd); 1471 } 1472 1473 free(pc->sources); 1474 } 1475 1476 if (pc->types) 1477 { 1478 for (i = pc->num_types, map = pc->types; i > 0; i --, map ++) 1479 { 1480 _cupsStrFree(map->pwg); 1481 _cupsStrFree(map->ppd); 1482 } 1483 1484 free(pc->types); 1485 } 1486 1487 if (pc->custom_max_keyword) 1488 _cupsStrFree(pc->custom_max_keyword); 1489 1490 if (pc->custom_min_keyword) 1491 _cupsStrFree(pc->custom_min_keyword); 1492 1493 _cupsStrFree(pc->product); 1494 cupsArrayDelete(pc->filters); 1495 cupsArrayDelete(pc->prefilters); 1496 cupsArrayDelete(pc->finishings); 1497 1498 _cupsStrFree(pc->charge_info_uri); 1499 _cupsStrFree(pc->password); 1500 1501 cupsArrayDelete(pc->mandatory); 1502 1503 cupsArrayDelete(pc->support_files); 1504 1505 free(pc); 1506} 1507 1508 1509/* 1510 * '_ppdCacheGetBin()' - Get the PWG output-bin keyword associated with a PPD 1511 * OutputBin. 1512 */ 1513 1514const char * /* O - output-bin or NULL */ 1515_ppdCacheGetBin( 1516 _ppd_cache_t *pc, /* I - PPD cache and mapping data */ 1517 const char *output_bin) /* I - PPD OutputBin string */ 1518{ 1519 int i; /* Looping var */ 1520 1521 1522 /* 1523 * Range check input... 1524 */ 1525 1526 if (!pc || !output_bin) 1527 return (NULL); 1528 1529 /* 1530 * Look up the OutputBin string... 1531 */ 1532 1533 1534 for (i = 0; i < pc->num_bins; i ++) 1535 if (!_cups_strcasecmp(output_bin, pc->bins[i].ppd)) 1536 return (pc->bins[i].pwg); 1537 1538 return (NULL); 1539} 1540 1541 1542/* 1543 * '_ppdCacheGetFinishingOptions()' - Get PPD finishing options for the given 1544 * IPP finishings value(s). 1545 */ 1546 1547int /* O - New number of options */ 1548_ppdCacheGetFinishingOptions( 1549 _ppd_cache_t *pc, /* I - PPD cache and mapping data */ 1550 ipp_t *job, /* I - Job attributes or NULL */ 1551 ipp_finishings_t value, /* I - IPP finishings value of IPP_FINISHINGS_NONE */ 1552 int num_options, /* I - Number of options */ 1553 cups_option_t **options) /* IO - Options */ 1554{ 1555 int i; /* Looping var */ 1556 _pwg_finishings_t *f, /* PWG finishings options */ 1557 key; /* Search key */ 1558 ipp_attribute_t *attr; /* Finishings attribute */ 1559 cups_option_t *option; /* Current finishings option */ 1560 1561 1562 /* 1563 * Range check input... 1564 */ 1565 1566 if (!pc || cupsArrayCount(pc->finishings) == 0 || !options || 1567 (!job && value == IPP_FINISHINGS_NONE)) 1568 return (num_options); 1569 1570 /* 1571 * Apply finishing options... 1572 */ 1573 1574 if (job && (attr = ippFindAttribute(job, "finishings", IPP_TAG_ENUM)) != NULL) 1575 { 1576 int num_values = ippGetCount(attr); /* Number of values */ 1577 1578 for (i = 0; i < num_values; i ++) 1579 { 1580 key.value = (ipp_finishings_t)ippGetInteger(attr, i); 1581 1582 if ((f = cupsArrayFind(pc->finishings, &key)) != NULL) 1583 { 1584 int j; /* Another looping var */ 1585 1586 for (j = f->num_options, option = f->options; j > 0; j --, option ++) 1587 num_options = cupsAddOption(option->name, option->value, 1588 num_options, options); 1589 } 1590 } 1591 } 1592 else if (value != IPP_FINISHINGS_NONE) 1593 { 1594 key.value = value; 1595 1596 if ((f = cupsArrayFind(pc->finishings, &key)) != NULL) 1597 { 1598 int j; /* Another looping var */ 1599 1600 for (j = f->num_options, option = f->options; j > 0; j --, option ++) 1601 num_options = cupsAddOption(option->name, option->value, 1602 num_options, options); 1603 } 1604 } 1605 1606 return (num_options); 1607} 1608 1609 1610/* 1611 * '_ppdCacheGetFinishingValues()' - Get IPP finishings value(s) from the given 1612 * PPD options. 1613 */ 1614 1615int /* O - Number of finishings values */ 1616_ppdCacheGetFinishingValues( 1617 _ppd_cache_t *pc, /* I - PPD cache and mapping data */ 1618 int num_options, /* I - Number of options */ 1619 cups_option_t *options, /* I - Options */ 1620 int max_values, /* I - Maximum number of finishings values */ 1621 int *values) /* O - Finishings values */ 1622{ 1623 int i, /* Looping var */ 1624 num_values = 0; /* Number of values */ 1625 _pwg_finishings_t *f; /* Current finishings option */ 1626 cups_option_t *option; /* Current option */ 1627 const char *val; /* Value for option */ 1628 1629 1630 /* 1631 * Range check input... 1632 */ 1633 1634 DEBUG_printf(("_ppdCacheGetFinishingValues(pc=%p, num_options=%d, options=%p, max_values=%d, values=%p)", pc, num_options, options, max_values, values)); 1635 1636 if (!pc || !pc->finishings || num_options < 1 || max_values < 1 || !values) 1637 { 1638 DEBUG_puts("_ppdCacheGetFinishingValues: Bad arguments, returning 0."); 1639 return (0); 1640 } 1641 1642 /* 1643 * Go through the finishings options and see what is set... 1644 */ 1645 1646 for (f = (_pwg_finishings_t *)cupsArrayFirst(pc->finishings); 1647 f; 1648 f = (_pwg_finishings_t *)cupsArrayNext(pc->finishings)) 1649 { 1650 DEBUG_printf(("_ppdCacheGetFinishingValues: Checking %d (%s)", f->value, ippEnumString("finishings", f->value))); 1651 1652 for (i = f->num_options, option = f->options; i > 0; i --, option ++) 1653 { 1654 DEBUG_printf(("_ppdCacheGetFinishingValues: %s=%s?", option->name, option->value)); 1655 1656 if ((val = cupsGetOption(option->name, num_options, options)) == NULL || 1657 _cups_strcasecmp(option->value, val)) 1658 { 1659 DEBUG_puts("_ppdCacheGetFinishingValues: NO"); 1660 break; 1661 } 1662 } 1663 1664 if (i == 0) 1665 { 1666 DEBUG_printf(("_ppdCacheGetFinishingValues: Adding %d.", f->value)); 1667 1668 values[num_values ++] = f->value; 1669 1670 if (num_values >= max_values) 1671 break; 1672 } 1673 } 1674 1675 DEBUG_printf(("_ppdCacheGetFinishingValues: Returning %d.", num_values)); 1676 1677 return (num_values); 1678} 1679 1680 1681/* 1682 * '_ppdCacheGetInputSlot()' - Get the PPD InputSlot associated with the job 1683 * attributes or a keyword string. 1684 */ 1685 1686const char * /* O - PPD InputSlot or NULL */ 1687_ppdCacheGetInputSlot( 1688 _ppd_cache_t *pc, /* I - PPD cache and mapping data */ 1689 ipp_t *job, /* I - Job attributes or NULL */ 1690 const char *keyword) /* I - Keyword string or NULL */ 1691{ 1692 /* 1693 * Range check input... 1694 */ 1695 1696 if (!pc || pc->num_sources == 0 || (!job && !keyword)) 1697 return (NULL); 1698 1699 if (job && !keyword) 1700 { 1701 /* 1702 * Lookup the media-col attribute and any media-source found there... 1703 */ 1704 1705 ipp_attribute_t *media_col, /* media-col attribute */ 1706 *media_source; /* media-source attribute */ 1707 pwg_size_t size; /* Dimensional size */ 1708 int margins_set; /* Were the margins set? */ 1709 1710 media_col = ippFindAttribute(job, "media-col", IPP_TAG_BEGIN_COLLECTION); 1711 if (media_col && 1712 (media_source = ippFindAttribute(ippGetCollection(media_col, 0), 1713 "media-source", 1714 IPP_TAG_KEYWORD)) != NULL) 1715 { 1716 /* 1717 * Use the media-source value from media-col... 1718 */ 1719 1720 keyword = ippGetString(media_source, 0, NULL); 1721 } 1722 else if (pwgInitSize(&size, job, &margins_set)) 1723 { 1724 /* 1725 * For media <= 5x7, look for a photo tray... 1726 */ 1727 1728 if (size.width <= (5 * 2540) && size.length <= (7 * 2540)) 1729 keyword = "photo"; 1730 } 1731 } 1732 1733 if (keyword) 1734 { 1735 int i; /* Looping var */ 1736 1737 for (i = 0; i < pc->num_sources; i ++) 1738 if (!_cups_strcasecmp(keyword, pc->sources[i].pwg)) 1739 return (pc->sources[i].ppd); 1740 } 1741 1742 return (NULL); 1743} 1744 1745 1746/* 1747 * '_ppdCacheGetMediaType()' - Get the PPD MediaType associated with the job 1748 * attributes or a keyword string. 1749 */ 1750 1751const char * /* O - PPD MediaType or NULL */ 1752_ppdCacheGetMediaType( 1753 _ppd_cache_t *pc, /* I - PPD cache and mapping data */ 1754 ipp_t *job, /* I - Job attributes or NULL */ 1755 const char *keyword) /* I - Keyword string or NULL */ 1756{ 1757 /* 1758 * Range check input... 1759 */ 1760 1761 if (!pc || pc->num_types == 0 || (!job && !keyword)) 1762 return (NULL); 1763 1764 if (job && !keyword) 1765 { 1766 /* 1767 * Lookup the media-col attribute and any media-source found there... 1768 */ 1769 1770 ipp_attribute_t *media_col, /* media-col attribute */ 1771 *media_type; /* media-type attribute */ 1772 1773 media_col = ippFindAttribute(job, "media-col", IPP_TAG_BEGIN_COLLECTION); 1774 if (media_col) 1775 { 1776 if ((media_type = ippFindAttribute(media_col->values[0].collection, 1777 "media-type", 1778 IPP_TAG_KEYWORD)) == NULL) 1779 media_type = ippFindAttribute(media_col->values[0].collection, 1780 "media-type", IPP_TAG_NAME); 1781 1782 if (media_type) 1783 keyword = media_type->values[0].string.text; 1784 } 1785 } 1786 1787 if (keyword) 1788 { 1789 int i; /* Looping var */ 1790 1791 for (i = 0; i < pc->num_types; i ++) 1792 if (!_cups_strcasecmp(keyword, pc->types[i].pwg)) 1793 return (pc->types[i].ppd); 1794 } 1795 1796 return (NULL); 1797} 1798 1799 1800/* 1801 * '_ppdCacheGetOutputBin()' - Get the PPD OutputBin associated with the keyword 1802 * string. 1803 */ 1804 1805const char * /* O - PPD OutputBin or NULL */ 1806_ppdCacheGetOutputBin( 1807 _ppd_cache_t *pc, /* I - PPD cache and mapping data */ 1808 const char *output_bin) /* I - Keyword string */ 1809{ 1810 int i; /* Looping var */ 1811 1812 1813 /* 1814 * Range check input... 1815 */ 1816 1817 if (!pc || !output_bin) 1818 return (NULL); 1819 1820 /* 1821 * Look up the OutputBin string... 1822 */ 1823 1824 1825 for (i = 0; i < pc->num_bins; i ++) 1826 if (!_cups_strcasecmp(output_bin, pc->bins[i].pwg)) 1827 return (pc->bins[i].ppd); 1828 1829 return (NULL); 1830} 1831 1832 1833/* 1834 * '_ppdCacheGetPageSize()' - Get the PPD PageSize associated with the job 1835 * attributes or a keyword string. 1836 */ 1837 1838const char * /* O - PPD PageSize or NULL */ 1839_ppdCacheGetPageSize( 1840 _ppd_cache_t *pc, /* I - PPD cache and mapping data */ 1841 ipp_t *job, /* I - Job attributes or NULL */ 1842 const char *keyword, /* I - Keyword string or NULL */ 1843 int *exact) /* O - 1 if exact match, 0 otherwise */ 1844{ 1845 int i; /* Looping var */ 1846 pwg_size_t *size, /* Current size */ 1847 *closest, /* Closest size */ 1848 jobsize; /* Size data from job */ 1849 int margins_set, /* Were the margins set? */ 1850 dwidth, /* Difference in width */ 1851 dlength, /* Difference in length */ 1852 dleft, /* Difference in left margins */ 1853 dright, /* Difference in right margins */ 1854 dbottom, /* Difference in bottom margins */ 1855 dtop, /* Difference in top margins */ 1856 dmin, /* Minimum difference */ 1857 dclosest; /* Closest difference */ 1858 const char *ppd_name; /* PPD media name */ 1859 1860 1861 DEBUG_printf(("_ppdCacheGetPageSize(pc=%p, job=%p, keyword=\"%s\", exact=%p)", 1862 pc, job, keyword, exact)); 1863 1864 /* 1865 * Range check input... 1866 */ 1867 1868 if (!pc || (!job && !keyword)) 1869 return (NULL); 1870 1871 if (exact) 1872 *exact = 0; 1873 1874 ppd_name = keyword; 1875 1876 if (job) 1877 { 1878 /* 1879 * Try getting the PPD media name from the job attributes... 1880 */ 1881 1882 ipp_attribute_t *attr; /* Job attribute */ 1883 1884 if ((attr = ippFindAttribute(job, "PageSize", IPP_TAG_ZERO)) == NULL) 1885 if ((attr = ippFindAttribute(job, "PageRegion", IPP_TAG_ZERO)) == NULL) 1886 attr = ippFindAttribute(job, "media", IPP_TAG_ZERO); 1887 1888#ifdef DEBUG 1889 if (attr) 1890 DEBUG_printf(("1_ppdCacheGetPageSize: Found attribute %s (%s)", 1891 attr->name, ippTagString(attr->value_tag))); 1892 else 1893 DEBUG_puts("1_ppdCacheGetPageSize: Did not find media attribute."); 1894#endif /* DEBUG */ 1895 1896 if (attr && (attr->value_tag == IPP_TAG_NAME || 1897 attr->value_tag == IPP_TAG_KEYWORD)) 1898 ppd_name = attr->values[0].string.text; 1899 } 1900 1901 DEBUG_printf(("1_ppdCacheGetPageSize: ppd_name=\"%s\"", ppd_name)); 1902 1903 if (ppd_name) 1904 { 1905 /* 1906 * Try looking up the named PPD size first... 1907 */ 1908 1909 for (i = pc->num_sizes, size = pc->sizes; i > 0; i --, size ++) 1910 { 1911 DEBUG_printf(("2_ppdCacheGetPageSize: size[%d]=[\"%s\" \"%s\"]", 1912 (int)(size - pc->sizes), size->map.pwg, size->map.ppd)); 1913 1914 if (!_cups_strcasecmp(ppd_name, size->map.ppd) || 1915 !_cups_strcasecmp(ppd_name, size->map.pwg)) 1916 { 1917 if (exact) 1918 *exact = 1; 1919 1920 DEBUG_printf(("1_ppdCacheGetPageSize: Returning \"%s\"", ppd_name)); 1921 1922 return (size->map.ppd); 1923 } 1924 } 1925 } 1926 1927 if (job && !keyword) 1928 { 1929 /* 1930 * Get the size using media-col or media, with the preference being 1931 * media-col. 1932 */ 1933 1934 if (!pwgInitSize(&jobsize, job, &margins_set)) 1935 return (NULL); 1936 } 1937 else 1938 { 1939 /* 1940 * Get the size using a media keyword... 1941 */ 1942 1943 pwg_media_t *media; /* Media definition */ 1944 1945 1946 if ((media = pwgMediaForPWG(keyword)) == NULL) 1947 if ((media = pwgMediaForLegacy(keyword)) == NULL) 1948 if ((media = pwgMediaForPPD(keyword)) == NULL) 1949 return (NULL); 1950 1951 jobsize.width = media->width; 1952 jobsize.length = media->length; 1953 margins_set = 0; 1954 } 1955 1956 /* 1957 * Now that we have the dimensions and possibly the margins, look at the 1958 * available sizes and find the match... 1959 */ 1960 1961 closest = NULL; 1962 dclosest = 999999999; 1963 1964 if (!ppd_name || _cups_strncasecmp(ppd_name, "Custom.", 7) || 1965 _cups_strncasecmp(ppd_name, "custom_", 7)) 1966 { 1967 for (i = pc->num_sizes, size = pc->sizes; i > 0; i --, size ++) 1968 { 1969 /* 1970 * Adobe uses a size matching algorithm with an epsilon of 5 points, which 1971 * is just about 176/2540ths... 1972 */ 1973 1974 dwidth = size->width - jobsize.width; 1975 dlength = size->length - jobsize.length; 1976 1977 if (dwidth <= -176 || dwidth >= 176 || dlength <= -176 || dlength >= 176) 1978 continue; 1979 1980 if (margins_set) 1981 { 1982 /* 1983 * Use a tighter epsilon of 1 point (35/2540ths) for margins... 1984 */ 1985 1986 dleft = size->left - jobsize.left; 1987 dright = size->right - jobsize.right; 1988 dtop = size->top - jobsize.top; 1989 dbottom = size->bottom - jobsize.bottom; 1990 1991 if (dleft <= -35 || dleft >= 35 || dright <= -35 || dright >= 35 || 1992 dtop <= -35 || dtop >= 35 || dbottom <= -35 || dbottom >= 35) 1993 { 1994 dleft = dleft < 0 ? -dleft : dleft; 1995 dright = dright < 0 ? -dright : dright; 1996 dbottom = dbottom < 0 ? -dbottom : dbottom; 1997 dtop = dtop < 0 ? -dtop : dtop; 1998 dmin = dleft + dright + dbottom + dtop; 1999 2000 if (dmin < dclosest) 2001 { 2002 dclosest = dmin; 2003 closest = size; 2004 } 2005 2006 continue; 2007 } 2008 } 2009 2010 if (exact) 2011 *exact = 1; 2012 2013 DEBUG_printf(("1_ppdCacheGetPageSize: Returning \"%s\"", size->map.ppd)); 2014 2015 return (size->map.ppd); 2016 } 2017 } 2018 2019 if (closest) 2020 { 2021 DEBUG_printf(("1_ppdCacheGetPageSize: Returning \"%s\" (closest)", 2022 closest->map.ppd)); 2023 2024 return (closest->map.ppd); 2025 } 2026 2027 /* 2028 * If we get here we need to check for custom page size support... 2029 */ 2030 2031 if (jobsize.width >= pc->custom_min_width && 2032 jobsize.width <= pc->custom_max_width && 2033 jobsize.length >= pc->custom_min_length && 2034 jobsize.length <= pc->custom_max_length) 2035 { 2036 /* 2037 * In range, format as Custom.WWWWxLLLL (points). 2038 */ 2039 2040 snprintf(pc->custom_ppd_size, sizeof(pc->custom_ppd_size), "Custom.%dx%d", 2041 (int)PWG_TO_POINTS(jobsize.width), (int)PWG_TO_POINTS(jobsize.length)); 2042 2043 if (margins_set && exact) 2044 { 2045 dleft = pc->custom_size.left - jobsize.left; 2046 dright = pc->custom_size.right - jobsize.right; 2047 dtop = pc->custom_size.top - jobsize.top; 2048 dbottom = pc->custom_size.bottom - jobsize.bottom; 2049 2050 if (dleft > -35 && dleft < 35 && dright > -35 && dright < 35 && 2051 dtop > -35 && dtop < 35 && dbottom > -35 && dbottom < 35) 2052 *exact = 1; 2053 } 2054 else if (exact) 2055 *exact = 1; 2056 2057 DEBUG_printf(("1_ppdCacheGetPageSize: Returning \"%s\" (custom)", 2058 pc->custom_ppd_size)); 2059 2060 return (pc->custom_ppd_size); 2061 } 2062 2063 /* 2064 * No custom page size support or the size is out of range - return NULL. 2065 */ 2066 2067 DEBUG_puts("1_ppdCacheGetPageSize: Returning NULL"); 2068 2069 return (NULL); 2070} 2071 2072 2073/* 2074 * '_ppdCacheGetSize()' - Get the PWG size associated with a PPD PageSize. 2075 */ 2076 2077pwg_size_t * /* O - PWG size or NULL */ 2078_ppdCacheGetSize( 2079 _ppd_cache_t *pc, /* I - PPD cache and mapping data */ 2080 const char *page_size) /* I - PPD PageSize */ 2081{ 2082 int i; /* Looping var */ 2083 pwg_media_t *media; /* Media */ 2084 pwg_size_t *size; /* Current size */ 2085 2086 2087 /* 2088 * Range check input... 2089 */ 2090 2091 if (!pc || !page_size) 2092 return (NULL); 2093 2094 if (!_cups_strncasecmp(page_size, "Custom.", 7)) 2095 { 2096 /* 2097 * Custom size; size name can be one of the following: 2098 * 2099 * Custom.WIDTHxLENGTHin - Size in inches 2100 * Custom.WIDTHxLENGTHft - Size in feet 2101 * Custom.WIDTHxLENGTHcm - Size in centimeters 2102 * Custom.WIDTHxLENGTHmm - Size in millimeters 2103 * Custom.WIDTHxLENGTHm - Size in meters 2104 * Custom.WIDTHxLENGTH[pt] - Size in points 2105 */ 2106 2107 double w, l; /* Width and length of page */ 2108 char *ptr; /* Pointer into PageSize */ 2109 struct lconv *loc; /* Locale data */ 2110 2111 loc = localeconv(); 2112 w = (float)_cupsStrScand(page_size + 7, &ptr, loc); 2113 if (!ptr || *ptr != 'x') 2114 return (NULL); 2115 2116 l = (float)_cupsStrScand(ptr + 1, &ptr, loc); 2117 if (!ptr) 2118 return (NULL); 2119 2120 if (!_cups_strcasecmp(ptr, "in")) 2121 { 2122 w *= 2540.0; 2123 l *= 2540.0; 2124 } 2125 else if (!_cups_strcasecmp(ptr, "ft")) 2126 { 2127 w *= 12.0 * 2540.0; 2128 l *= 12.0 * 2540.0; 2129 } 2130 else if (!_cups_strcasecmp(ptr, "mm")) 2131 { 2132 w *= 100.0; 2133 l *= 100.0; 2134 } 2135 else if (!_cups_strcasecmp(ptr, "cm")) 2136 { 2137 w *= 1000.0; 2138 l *= 1000.0; 2139 } 2140 else if (!_cups_strcasecmp(ptr, "m")) 2141 { 2142 w *= 100000.0; 2143 l *= 100000.0; 2144 } 2145 else 2146 { 2147 w *= 2540.0 / 72.0; 2148 l *= 2540.0 / 72.0; 2149 } 2150 2151 pc->custom_size.width = (int)w; 2152 pc->custom_size.length = (int)l; 2153 2154 return (&(pc->custom_size)); 2155 } 2156 2157 /* 2158 * Not a custom size - look it up... 2159 */ 2160 2161 for (i = pc->num_sizes, size = pc->sizes; i > 0; i --, size ++) 2162 if (!_cups_strcasecmp(page_size, size->map.ppd) || 2163 !_cups_strcasecmp(page_size, size->map.pwg)) 2164 return (size); 2165 2166 /* 2167 * Look up standard sizes... 2168 */ 2169 2170 if ((media = pwgMediaForPPD(page_size)) == NULL) 2171 if ((media = pwgMediaForLegacy(page_size)) == NULL) 2172 media = pwgMediaForPWG(page_size); 2173 2174 if (media) 2175 { 2176 pc->custom_size.width = media->width; 2177 pc->custom_size.length = media->length; 2178 2179 return (&(pc->custom_size)); 2180 } 2181 2182 return (NULL); 2183} 2184 2185 2186/* 2187 * '_ppdCacheGetSource()' - Get the PWG media-source associated with a PPD 2188 * InputSlot. 2189 */ 2190 2191const char * /* O - PWG media-source keyword */ 2192_ppdCacheGetSource( 2193 _ppd_cache_t *pc, /* I - PPD cache and mapping data */ 2194 const char *input_slot) /* I - PPD InputSlot */ 2195{ 2196 int i; /* Looping var */ 2197 pwg_map_t *source; /* Current source */ 2198 2199 2200 /* 2201 * Range check input... 2202 */ 2203 2204 if (!pc || !input_slot) 2205 return (NULL); 2206 2207 for (i = pc->num_sources, source = pc->sources; i > 0; i --, source ++) 2208 if (!_cups_strcasecmp(input_slot, source->ppd)) 2209 return (source->pwg); 2210 2211 return (NULL); 2212} 2213 2214 2215/* 2216 * '_ppdCacheGetType()' - Get the PWG media-type associated with a PPD 2217 * MediaType. 2218 */ 2219 2220const char * /* O - PWG media-type keyword */ 2221_ppdCacheGetType( 2222 _ppd_cache_t *pc, /* I - PPD cache and mapping data */ 2223 const char *media_type) /* I - PPD MediaType */ 2224{ 2225 int i; /* Looping var */ 2226 pwg_map_t *type; /* Current type */ 2227 2228 2229 /* 2230 * Range check input... 2231 */ 2232 2233 if (!pc || !media_type) 2234 return (NULL); 2235 2236 for (i = pc->num_types, type = pc->types; i > 0; i --, type ++) 2237 if (!_cups_strcasecmp(media_type, type->ppd)) 2238 return (type->pwg); 2239 2240 return (NULL); 2241} 2242 2243 2244/* 2245 * '_ppdCacheWriteFile()' - Write PWG mapping data to a file. 2246 */ 2247 2248int /* O - 1 on success, 0 on failure */ 2249_ppdCacheWriteFile( 2250 _ppd_cache_t *pc, /* I - PPD cache and mapping data */ 2251 const char *filename, /* I - File to write */ 2252 ipp_t *attrs) /* I - Attributes to write, if any */ 2253{ 2254 int i, j, k; /* Looping vars */ 2255 cups_file_t *fp; /* Output file */ 2256 pwg_size_t *size; /* Current size */ 2257 pwg_map_t *map; /* Current map */ 2258 _pwg_finishings_t *f; /* Current finishing option */ 2259 cups_option_t *option; /* Current option */ 2260 const char *value; /* Filter/pre-filter value */ 2261 char newfile[1024]; /* New filename */ 2262 2263 2264 /* 2265 * Range check input... 2266 */ 2267 2268 if (!pc || !filename) 2269 { 2270 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); 2271 return (0); 2272 } 2273 2274 /* 2275 * Open the file and write with compression... 2276 */ 2277 2278 snprintf(newfile, sizeof(newfile), "%s.N", filename); 2279 if ((fp = cupsFileOpen(newfile, "w9")) == NULL) 2280 { 2281 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); 2282 return (0); 2283 } 2284 2285 /* 2286 * Standard header... 2287 */ 2288 2289 cupsFilePrintf(fp, "#CUPS-PPD-CACHE-%d\n", _PPD_CACHE_VERSION); 2290 2291 /* 2292 * Output bins... 2293 */ 2294 2295 if (pc->num_bins > 0) 2296 { 2297 cupsFilePrintf(fp, "NumBins %d\n", pc->num_bins); 2298 for (i = pc->num_bins, map = pc->bins; i > 0; i --, map ++) 2299 cupsFilePrintf(fp, "Bin %s %s\n", map->pwg, map->ppd); 2300 } 2301 2302 /* 2303 * Media sizes... 2304 */ 2305 2306 cupsFilePrintf(fp, "NumSizes %d\n", pc->num_sizes); 2307 for (i = pc->num_sizes, size = pc->sizes; i > 0; i --, size ++) 2308 cupsFilePrintf(fp, "Size %s %s %d %d %d %d %d %d\n", size->map.pwg, 2309 size->map.ppd, size->width, size->length, size->left, 2310 size->bottom, size->right, size->top); 2311 if (pc->custom_max_width > 0) 2312 cupsFilePrintf(fp, "CustomSize %d %d %d %d %d %d %d %d\n", 2313 pc->custom_max_width, pc->custom_max_length, 2314 pc->custom_min_width, pc->custom_min_length, 2315 pc->custom_size.left, pc->custom_size.bottom, 2316 pc->custom_size.right, pc->custom_size.top); 2317 2318 /* 2319 * Media sources... 2320 */ 2321 2322 if (pc->source_option) 2323 cupsFilePrintf(fp, "SourceOption %s\n", pc->source_option); 2324 2325 if (pc->num_sources > 0) 2326 { 2327 cupsFilePrintf(fp, "NumSources %d\n", pc->num_sources); 2328 for (i = pc->num_sources, map = pc->sources; i > 0; i --, map ++) 2329 cupsFilePrintf(fp, "Source %s %s\n", map->pwg, map->ppd); 2330 } 2331 2332 /* 2333 * Media types... 2334 */ 2335 2336 if (pc->num_types > 0) 2337 { 2338 cupsFilePrintf(fp, "NumTypes %d\n", pc->num_types); 2339 for (i = pc->num_types, map = pc->types; i > 0; i --, map ++) 2340 cupsFilePrintf(fp, "Type %s %s\n", map->pwg, map->ppd); 2341 } 2342 2343 /* 2344 * Presets... 2345 */ 2346 2347 for (i = _PWG_PRINT_COLOR_MODE_MONOCHROME; i < _PWG_PRINT_COLOR_MODE_MAX; i ++) 2348 for (j = _PWG_PRINT_QUALITY_DRAFT; j < _PWG_PRINT_QUALITY_MAX; j ++) 2349 if (pc->num_presets[i][j]) 2350 { 2351 cupsFilePrintf(fp, "Preset %d %d", i, j); 2352 for (k = pc->num_presets[i][j], option = pc->presets[i][j]; 2353 k > 0; 2354 k --, option ++) 2355 cupsFilePrintf(fp, " %s=%s", option->name, option->value); 2356 cupsFilePutChar(fp, '\n'); 2357 } 2358 2359 /* 2360 * Duplex/sides... 2361 */ 2362 2363 if (pc->sides_option) 2364 cupsFilePrintf(fp, "SidesOption %s\n", pc->sides_option); 2365 2366 if (pc->sides_1sided) 2367 cupsFilePrintf(fp, "Sides1Sided %s\n", pc->sides_1sided); 2368 2369 if (pc->sides_2sided_long) 2370 cupsFilePrintf(fp, "Sides2SidedLong %s\n", pc->sides_2sided_long); 2371 2372 if (pc->sides_2sided_short) 2373 cupsFilePrintf(fp, "Sides2SidedShort %s\n", pc->sides_2sided_short); 2374 2375 /* 2376 * Product, cupsFilter, cupsFilter2, and cupsPreFilter... 2377 */ 2378 2379 if (pc->product) 2380 cupsFilePutConf(fp, "Product", pc->product); 2381 2382 for (value = (const char *)cupsArrayFirst(pc->filters); 2383 value; 2384 value = (const char *)cupsArrayNext(pc->filters)) 2385 cupsFilePutConf(fp, "Filter", value); 2386 2387 for (value = (const char *)cupsArrayFirst(pc->prefilters); 2388 value; 2389 value = (const char *)cupsArrayNext(pc->prefilters)) 2390 cupsFilePutConf(fp, "PreFilter", value); 2391 2392 cupsFilePrintf(fp, "SingleFile %s\n", pc->single_file ? "true" : "false"); 2393 2394 /* 2395 * Finishing options... 2396 */ 2397 2398 for (f = (_pwg_finishings_t *)cupsArrayFirst(pc->finishings); 2399 f; 2400 f = (_pwg_finishings_t *)cupsArrayNext(pc->finishings)) 2401 { 2402 cupsFilePrintf(fp, "Finishings %d", f->value); 2403 for (i = f->num_options, option = f->options; i > 0; i --, option ++) 2404 cupsFilePrintf(fp, " %s=%s", option->name, option->value); 2405 cupsFilePutChar(fp, '\n'); 2406 } 2407 2408 /* 2409 * Max copies... 2410 */ 2411 2412 cupsFilePrintf(fp, "MaxCopies %d\n", pc->max_copies); 2413 2414 /* 2415 * Accounting/quota/PIN/managed printing values... 2416 */ 2417 2418 if (pc->charge_info_uri) 2419 cupsFilePutConf(fp, "ChargeInfoURI", pc->charge_info_uri); 2420 2421 cupsFilePrintf(fp, "AccountId %s\n", pc->account_id ? "true" : "false"); 2422 cupsFilePrintf(fp, "AccountingUserId %s\n", 2423 pc->accounting_user_id ? "true" : "false"); 2424 2425 if (pc->password) 2426 cupsFilePutConf(fp, "Password", pc->password); 2427 2428 for (value = (char *)cupsArrayFirst(pc->mandatory); 2429 value; 2430 value = (char *)cupsArrayNext(pc->mandatory)) 2431 cupsFilePutConf(fp, "Mandatory", value); 2432 2433 /* 2434 * Support files... 2435 */ 2436 2437 for (value = (char *)cupsArrayFirst(pc->support_files); 2438 value; 2439 value = (char *)cupsArrayNext(pc->support_files)) 2440 cupsFilePutConf(fp, "SupportFile", value); 2441 2442 /* 2443 * IPP attributes, if any... 2444 */ 2445 2446 if (attrs) 2447 { 2448 cupsFilePrintf(fp, "IPP " CUPS_LLFMT "\n", CUPS_LLCAST ippLength(attrs)); 2449 2450 attrs->state = IPP_STATE_IDLE; 2451 ippWriteIO(fp, (ipp_iocb_t)cupsFileWrite, 1, NULL, attrs); 2452 } 2453 2454 /* 2455 * Close and return... 2456 */ 2457 2458 if (cupsFileClose(fp)) 2459 { 2460 unlink(newfile); 2461 return (0); 2462 } 2463 2464 unlink(filename); 2465 return (!rename(newfile, filename)); 2466} 2467 2468 2469/* 2470 * '_pwgInputSlotForSource()' - Get the InputSlot name for the given PWG 2471 * media-source. 2472 */ 2473 2474const char * /* O - InputSlot name */ 2475_pwgInputSlotForSource( 2476 const char *media_source, /* I - PWG media-source */ 2477 char *name, /* I - Name buffer */ 2478 size_t namesize) /* I - Size of name buffer */ 2479{ 2480 /* 2481 * Range check input... 2482 */ 2483 2484 if (!media_source || !name || namesize < PPD_MAX_NAME) 2485 return (NULL); 2486 2487 if (_cups_strcasecmp(media_source, "main")) 2488 strlcpy(name, "Cassette", namesize); 2489 else if (_cups_strcasecmp(media_source, "alternate")) 2490 strlcpy(name, "Multipurpose", namesize); 2491 else if (_cups_strcasecmp(media_source, "large-capacity")) 2492 strlcpy(name, "LargeCapacity", namesize); 2493 else if (_cups_strcasecmp(media_source, "bottom")) 2494 strlcpy(name, "Lower", namesize); 2495 else if (_cups_strcasecmp(media_source, "middle")) 2496 strlcpy(name, "Middle", namesize); 2497 else if (_cups_strcasecmp(media_source, "top")) 2498 strlcpy(name, "Upper", namesize); 2499 else if (_cups_strcasecmp(media_source, "rear")) 2500 strlcpy(name, "Rear", namesize); 2501 else if (_cups_strcasecmp(media_source, "side")) 2502 strlcpy(name, "Side", namesize); 2503 else if (_cups_strcasecmp(media_source, "envelope")) 2504 strlcpy(name, "Envelope", namesize); 2505 else if (_cups_strcasecmp(media_source, "main-roll")) 2506 strlcpy(name, "Roll", namesize); 2507 else if (_cups_strcasecmp(media_source, "alternate-roll")) 2508 strlcpy(name, "Roll2", namesize); 2509 else 2510 pwg_ppdize_name(media_source, name, namesize); 2511 2512 return (name); 2513} 2514 2515 2516/* 2517 * '_pwgMediaTypeForType()' - Get the MediaType name for the given PWG 2518 * media-type. 2519 */ 2520 2521const char * /* O - MediaType name */ 2522_pwgMediaTypeForType( 2523 const char *media_type, /* I - PWG media-type */ 2524 char *name, /* I - Name buffer */ 2525 size_t namesize) /* I - Size of name buffer */ 2526{ 2527 /* 2528 * Range check input... 2529 */ 2530 2531 if (!media_type || !name || namesize < PPD_MAX_NAME) 2532 return (NULL); 2533 2534 if (_cups_strcasecmp(media_type, "auto")) 2535 strlcpy(name, "Auto", namesize); 2536 else if (_cups_strcasecmp(media_type, "cardstock")) 2537 strlcpy(name, "Cardstock", namesize); 2538 else if (_cups_strcasecmp(media_type, "envelope")) 2539 strlcpy(name, "Envelope", namesize); 2540 else if (_cups_strcasecmp(media_type, "photographic-glossy")) 2541 strlcpy(name, "Glossy", namesize); 2542 else if (_cups_strcasecmp(media_type, "photographic-high-gloss")) 2543 strlcpy(name, "HighGloss", namesize); 2544 else if (_cups_strcasecmp(media_type, "photographic-matte")) 2545 strlcpy(name, "Matte", namesize); 2546 else if (_cups_strcasecmp(media_type, "stationery")) 2547 strlcpy(name, "Plain", namesize); 2548 else if (_cups_strcasecmp(media_type, "stationery-coated")) 2549 strlcpy(name, "Coated", namesize); 2550 else if (_cups_strcasecmp(media_type, "stationery-inkjet")) 2551 strlcpy(name, "Inkjet", namesize); 2552 else if (_cups_strcasecmp(media_type, "stationery-letterhead")) 2553 strlcpy(name, "Letterhead", namesize); 2554 else if (_cups_strcasecmp(media_type, "stationery-preprinted")) 2555 strlcpy(name, "Preprinted", namesize); 2556 else if (_cups_strcasecmp(media_type, "transparency")) 2557 strlcpy(name, "Transparency", namesize); 2558 else 2559 pwg_ppdize_name(media_type, name, namesize); 2560 2561 return (name); 2562} 2563 2564 2565/* 2566 * '_pwgPageSizeForMedia()' - Get the PageSize name for the given media. 2567 */ 2568 2569const char * /* O - PageSize name */ 2570_pwgPageSizeForMedia( 2571 pwg_media_t *media, /* I - Media */ 2572 char *name, /* I - PageSize name buffer */ 2573 size_t namesize) /* I - Size of name buffer */ 2574{ 2575 const char *sizeptr, /* Pointer to size in PWG name */ 2576 *dimptr; /* Pointer to dimensions in PWG name */ 2577 2578 2579 /* 2580 * Range check input... 2581 */ 2582 2583 if (!media || !name || namesize < PPD_MAX_NAME) 2584 return (NULL); 2585 2586 /* 2587 * Copy or generate a PageSize name... 2588 */ 2589 2590 if (media->ppd) 2591 { 2592 /* 2593 * Use a standard Adobe name... 2594 */ 2595 2596 strlcpy(name, media->ppd, namesize); 2597 } 2598 else if (!media->pwg || !strncmp(media->pwg, "custom_", 7) || 2599 (sizeptr = strchr(media->pwg, '_')) == NULL || 2600 (dimptr = strchr(sizeptr + 1, '_')) == NULL || 2601 (size_t)(dimptr - sizeptr) > namesize) 2602 { 2603 /* 2604 * Use a name of the form "wNNNhNNN"... 2605 */ 2606 2607 snprintf(name, namesize, "w%dh%d", (int)PWG_TO_POINTS(media->width), 2608 (int)PWG_TO_POINTS(media->length)); 2609 } 2610 else 2611 { 2612 /* 2613 * Copy the size name from class_sizename_dimensions... 2614 */ 2615 2616 memcpy(name, sizeptr + 1, (size_t)(dimptr - sizeptr - 1)); 2617 name[dimptr - sizeptr - 1] = '\0'; 2618 } 2619 2620 return (name); 2621} 2622 2623 2624/* 2625 * 'pwg_compare_finishings()' - Compare two finishings values. 2626 */ 2627 2628static int /* O- Result of comparison */ 2629pwg_compare_finishings( 2630 _pwg_finishings_t *a, /* I - First finishings value */ 2631 _pwg_finishings_t *b) /* I - Second finishings value */ 2632{ 2633 return ((int)b->value - (int)a->value); 2634} 2635 2636 2637/* 2638 * 'pwg_free_finishings()' - Free a finishings value. 2639 */ 2640 2641static void 2642pwg_free_finishings( 2643 _pwg_finishings_t *f) /* I - Finishings value */ 2644{ 2645 cupsFreeOptions(f->num_options, f->options); 2646 free(f); 2647} 2648 2649 2650/* 2651 * 'pwg_ppdize_name()' - Convert an IPP keyword to a PPD keyword. 2652 */ 2653 2654static void 2655pwg_ppdize_name(const char *ipp, /* I - IPP keyword */ 2656 char *name, /* I - Name buffer */ 2657 size_t namesize) /* I - Size of name buffer */ 2658{ 2659 char *ptr, /* Pointer into name buffer */ 2660 *end; /* End of name buffer */ 2661 2662 2663 *name = (char)toupper(*ipp++); 2664 2665 for (ptr = name + 1, end = name + namesize - 1; *ipp && ptr < end;) 2666 { 2667 if (*ipp == '-' && _cups_isalpha(ipp[1])) 2668 { 2669 ipp ++; 2670 *ptr++ = (char)toupper(*ipp++ & 255); 2671 } 2672 else 2673 *ptr++ = *ipp++; 2674 } 2675 2676 *ptr = '\0'; 2677} 2678 2679 2680/* 2681 * 'pwg_unppdize_name()' - Convert a PPD keyword to a lowercase IPP keyword. 2682 */ 2683 2684static void 2685pwg_unppdize_name(const char *ppd, /* I - PPD keyword */ 2686 char *name, /* I - Name buffer */ 2687 size_t namesize, /* I - Size of name buffer */ 2688 const char *dashchars)/* I - Characters to be replaced by dashes */ 2689{ 2690 char *ptr, /* Pointer into name buffer */ 2691 *end; /* End of name buffer */ 2692 2693 2694 for (ptr = name, end = name + namesize - 1; *ppd && ptr < end; ppd ++) 2695 { 2696 if (_cups_isalnum(*ppd) || *ppd == '-') 2697 *ptr++ = (char)tolower(*ppd & 255); 2698 else if (strchr(dashchars, *ppd)) 2699 *ptr++ = '-'; 2700 else 2701 *ptr++ = *ppd; 2702 2703 if (!_cups_isupper(*ppd) && _cups_isalnum(*ppd) && 2704 _cups_isupper(ppd[1]) && ptr < end) 2705 *ptr++ = '-'; 2706 else if (!isdigit(*ppd & 255) && isdigit(ppd[1] & 255)) 2707 *ptr++ = '-'; 2708 } 2709 2710 *ptr = '\0'; 2711} 2712 2713 2714/* 2715 * End of "$Id: ppd-cache.c 12131 2014-08-28 23:38:16Z msweet $". 2716 */ 2717