4 * PPD cache implementation for CUPS.
6 * Copyright 2010-2012 by Apple Inc.
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/".
14 * This file is subject to the Apple OS-Developed Software exception.
18 * _ppdCacheCreateWithFile() - Create PPD cache and mapping data from a
20 * _ppdCacheCreateWithPPD() - Create PWG mapping data from a PPD file.
21 * _ppdCacheDestroy() - Free all memory used for PWG mapping data.
22 * _ppdCacheGetBin() - Get the PWG output-bin keyword associated with
24 * _ppdCacheGetInputSlot() - Get the PPD InputSlot associated with the job
25 * attributes or a keyword string.
26 * _ppdCacheGetMediaType() - Get the PPD MediaType associated with the job
27 * attributes or a keyword string.
28 * _ppdCacheGetOutputBin() - Get the PPD OutputBin associated with the
30 * _ppdCacheGetPageSize() - Get the PPD PageSize associated with the job
31 * attributes or a keyword string.
32 * _ppdCacheGetSize() - Get the PWG size associated with a PPD
34 * _ppdCacheGetSource() - Get the PWG media-source associated with a PPD
36 * _ppdCacheGetType() - Get the PWG media-type associated with a PPD
38 * _ppdCacheWriteFile() - Write PWG mapping data to a file.
39 * _pwgInputSlotForSource() - Get the InputSlot name for the given PWG
41 * _pwgMediaTypeForType() - Get the MediaType name for the given PWG
43 * _pwgPageSizeForMedia() - Get the PageSize name for the given media.
44 * pwg_ppdize_name() - Convert an IPP keyword to a PPD keyword.
45 * pwg_unppdize_name() - Convert a PPD keyword to a lowercase IPP
50 * Include necessary headers...
53 #include "cups-private.h"
58 * Macro to test for two almost-equal PWG measurements.
61 #define _PWG_EQUIVALENT(x, y) (abs((x)-(y)) < 2)
68 static int pwg_compare_finishings(_pwg_finishings_t
*a
,
69 _pwg_finishings_t
*b
);
70 static void pwg_free_finishings(_pwg_finishings_t
*f
);
71 static void pwg_ppdize_name(const char *ipp
, char *name
, size_t namesize
);
72 static void pwg_unppdize_name(const char *ppd
, char *name
, size_t namesize
);
76 * '_ppdCacheCreateWithFile()' - Create PPD cache and mapping data from a
79 * Use the @link _ppdCacheWriteFile@ function to write PWG mapping data to a
83 _ppd_cache_t
* /* O - PPD cache and mapping data */
84 _ppdCacheCreateWithFile(
85 const char *filename
, /* I - File to read */
86 ipp_t
**attrs
) /* IO - IPP attributes, if any */
88 cups_file_t
*fp
; /* File */
89 _ppd_cache_t
*pc
; /* PWG mapping data */
90 _pwg_size_t
*size
; /* Current size */
91 _pwg_map_t
*map
; /* Current map */
92 _pwg_finishings_t
*finishings
; /* Current finishings option */
93 int linenum
, /* Current line number */
94 num_bins
, /* Number of bins in file */
95 num_sizes
, /* Number of sizes in file */
96 num_sources
, /* Number of sources in file */
97 num_types
; /* Number of types in file */
98 char line
[2048], /* Current line */
99 *value
, /* Pointer to value in line */
100 *valueptr
, /* Pointer into value */
101 pwg_keyword
[128], /* PWG keyword */
102 ppd_keyword
[PPD_MAX_NAME
];
104 _pwg_print_color_mode_t print_color_mode
;
105 /* Print color mode for preset */
106 _pwg_print_quality_t print_quality
; /* Print quality for preset */
109 DEBUG_printf(("_ppdCacheCreateWithFile(filename=\"%s\")", filename
));
112 * Range check input...
120 _cupsSetError(IPP_INTERNAL_ERROR
, strerror(EINVAL
), 0);
128 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
130 _cupsSetError(IPP_INTERNAL_ERROR
, strerror(errno
), 0);
135 * Read the first line and make sure it has "#CUPS-PPD-CACHE-version" in it...
138 if (!cupsFileGets(fp
, line
, sizeof(line
)))
140 _cupsSetError(IPP_INTERNAL_ERROR
, strerror(errno
), 0);
141 DEBUG_puts("_ppdCacheCreateWithFile: Unable to read first line.");
146 if (strncmp(line
, "#CUPS-PPD-CACHE-", 16))
148 _cupsSetError(IPP_INTERNAL_ERROR
, _("Bad PPD cache file."), 1);
149 DEBUG_printf(("_ppdCacheCreateWithFile: Wrong first line \"%s\".", line
));
154 if (atoi(line
+ 16) != _PPD_CACHE_VERSION
)
156 _cupsSetError(IPP_INTERNAL_ERROR
, _("Out of date PPD cache file."), 1);
157 DEBUG_printf(("_ppdCacheCreateWithFile: Cache file has version %s, "
158 "expected %d.", line
+ 16, _PPD_CACHE_VERSION
));
164 * Allocate the mapping data structure...
167 if ((pc
= calloc(1, sizeof(_ppd_cache_t
))) == NULL
)
169 _cupsSetError(IPP_INTERNAL_ERROR
, strerror(errno
), 0);
170 DEBUG_puts("_ppdCacheCreateWithFile: Unable to allocate _ppd_cache_t.");
174 pc
->max_copies
= 9999;
186 while (cupsFileGetConf(fp
, line
, sizeof(line
), &value
, &linenum
))
188 DEBUG_printf(("_ppdCacheCreateWithFile: line=\"%s\", value=\"%s\", "
189 "linenum=%d", line
, value
, linenum
));
193 DEBUG_printf(("_ppdCacheCreateWithFile: Missing value on line %d.",
195 _cupsSetError(IPP_INTERNAL_ERROR
, _("Bad PPD cache file."), 1);
198 else if (!_cups_strcasecmp(line
, "Filter"))
201 pc
->filters
= cupsArrayNew3(NULL
, NULL
, NULL
, 0,
202 (cups_acopy_func_t
)_cupsStrAlloc
,
203 (cups_afree_func_t
)_cupsStrFree
);
205 cupsArrayAdd(pc
->filters
, value
);
207 else if (!_cups_strcasecmp(line
, "PreFilter"))
210 pc
->prefilters
= cupsArrayNew3(NULL
, NULL
, NULL
, 0,
211 (cups_acopy_func_t
)_cupsStrAlloc
,
212 (cups_afree_func_t
)_cupsStrFree
);
214 cupsArrayAdd(pc
->prefilters
, value
);
216 else if (!_cups_strcasecmp(line
, "Product"))
218 pc
->product
= _cupsStrAlloc(value
);
220 else if (!_cups_strcasecmp(line
, "SingleFile"))
222 pc
->single_file
= !_cups_strcasecmp(value
, "true");
224 else if (!_cups_strcasecmp(line
, "IPP"))
226 off_t pos
= cupsFileTell(fp
), /* Position in file */
227 length
= strtol(value
, NULL
, 10);
228 /* Length of IPP attributes */
232 DEBUG_puts("_ppdCacheCreateWithFile: IPP listed multiple times.");
233 _cupsSetError(IPP_INTERNAL_ERROR
, _("Bad PPD cache file."), 1);
236 else if (length
<= 0)
238 DEBUG_puts("_ppdCacheCreateWithFile: Bad IPP length.");
239 _cupsSetError(IPP_INTERNAL_ERROR
, _("Bad PPD cache file."), 1);
246 * Read IPP attributes into the provided variable...
251 if (ippReadIO(fp
, (ipp_iocb_t
)cupsFileRead
, 1, NULL
,
254 DEBUG_puts("_ppdCacheCreateWithFile: Bad IPP data.");
255 _cupsSetError(IPP_INTERNAL_ERROR
, _("Bad PPD cache file."), 1);
262 * Skip the IPP data entirely...
265 cupsFileSeek(fp
, pos
+ length
);
268 if (cupsFileTell(fp
) != (pos
+ length
))
270 DEBUG_puts("_ppdCacheCreateWithFile: Bad IPP data.");
271 _cupsSetError(IPP_INTERNAL_ERROR
, _("Bad PPD cache file."), 1);
275 else if (!_cups_strcasecmp(line
, "NumBins"))
279 DEBUG_puts("_ppdCacheCreateWithFile: NumBins listed multiple times.");
280 _cupsSetError(IPP_INTERNAL_ERROR
, _("Bad PPD cache file."), 1);
284 if ((num_bins
= atoi(value
)) <= 0 || num_bins
> 65536)
286 DEBUG_printf(("_ppdCacheCreateWithFile: Bad NumBins value %d on line "
287 "%d.", num_sizes
, linenum
));
288 _cupsSetError(IPP_INTERNAL_ERROR
, _("Bad PPD cache file."), 1);
292 if ((pc
->bins
= calloc(num_bins
, sizeof(_pwg_map_t
))) == NULL
)
294 DEBUG_printf(("_ppdCacheCreateWithFile: Unable to allocate %d bins.",
296 _cupsSetError(IPP_INTERNAL_ERROR
, strerror(errno
), 0);
300 else if (!_cups_strcasecmp(line
, "Bin"))
302 if (sscanf(value
, "%127s%40s", pwg_keyword
, ppd_keyword
) != 2)
304 DEBUG_printf(("_ppdCacheCreateWithFile: Bad Bin on line %d.", linenum
));
305 _cupsSetError(IPP_INTERNAL_ERROR
, _("Bad PPD cache file."), 1);
309 if (pc
->num_bins
>= num_bins
)
311 DEBUG_printf(("_ppdCacheCreateWithFile: Too many Bin's on line %d.",
313 _cupsSetError(IPP_INTERNAL_ERROR
, _("Bad PPD cache file."), 1);
317 map
= pc
->bins
+ pc
->num_bins
;
318 map
->pwg
= _cupsStrAlloc(pwg_keyword
);
319 map
->ppd
= _cupsStrAlloc(ppd_keyword
);
323 else if (!_cups_strcasecmp(line
, "NumSizes"))
327 DEBUG_puts("_ppdCacheCreateWithFile: NumSizes listed multiple times.");
328 _cupsSetError(IPP_INTERNAL_ERROR
, _("Bad PPD cache file."), 1);
332 if ((num_sizes
= atoi(value
)) <= 0 || num_sizes
> 65536)
334 DEBUG_printf(("_ppdCacheCreateWithFile: Bad NumSizes value %d on line "
335 "%d.", num_sizes
, linenum
));
336 _cupsSetError(IPP_INTERNAL_ERROR
, _("Bad PPD cache file."), 1);
340 if ((pc
->sizes
= calloc(num_sizes
, sizeof(_pwg_size_t
))) == NULL
)
342 DEBUG_printf(("_ppdCacheCreateWithFile: Unable to allocate %d sizes.",
344 _cupsSetError(IPP_INTERNAL_ERROR
, strerror(errno
), 0);
348 else if (!_cups_strcasecmp(line
, "Size"))
350 if (pc
->num_sizes
>= num_sizes
)
352 DEBUG_printf(("_ppdCacheCreateWithFile: Too many Size's on line %d.",
354 _cupsSetError(IPP_INTERNAL_ERROR
, _("Bad PPD cache file."), 1);
358 size
= pc
->sizes
+ pc
->num_sizes
;
360 if (sscanf(value
, "%127s%40s%d%d%d%d%d%d", pwg_keyword
, ppd_keyword
,
361 &(size
->width
), &(size
->length
), &(size
->left
),
362 &(size
->bottom
), &(size
->right
), &(size
->top
)) != 8)
364 DEBUG_printf(("_ppdCacheCreateWithFile: Bad Size on line %d.",
366 _cupsSetError(IPP_INTERNAL_ERROR
, _("Bad PPD cache file."), 1);
370 size
->map
.pwg
= _cupsStrAlloc(pwg_keyword
);
371 size
->map
.ppd
= _cupsStrAlloc(ppd_keyword
);
375 else if (!_cups_strcasecmp(line
, "CustomSize"))
377 if (pc
->custom_max_width
> 0)
379 DEBUG_printf(("_ppdCacheCreateWithFile: Too many CustomSize's on line "
381 _cupsSetError(IPP_INTERNAL_ERROR
, _("Bad PPD cache file."), 1);
385 if (sscanf(value
, "%d%d%d%d%d%d%d%d", &(pc
->custom_max_width
),
386 &(pc
->custom_max_length
), &(pc
->custom_min_width
),
387 &(pc
->custom_min_length
), &(pc
->custom_size
.left
),
388 &(pc
->custom_size
.bottom
), &(pc
->custom_size
.right
),
389 &(pc
->custom_size
.top
)) != 8)
391 DEBUG_printf(("_ppdCacheCreateWithFile: Bad CustomSize on line %d.",
393 _cupsSetError(IPP_INTERNAL_ERROR
, _("Bad PPD cache file."), 1);
397 _pwgGenerateSize(pwg_keyword
, sizeof(pwg_keyword
), "custom", "max",
398 pc
->custom_max_width
, pc
->custom_max_length
);
399 pc
->custom_max_keyword
= _cupsStrAlloc(pwg_keyword
);
401 _pwgGenerateSize(pwg_keyword
, sizeof(pwg_keyword
), "custom", "min",
402 pc
->custom_min_width
, pc
->custom_min_length
);
403 pc
->custom_min_keyword
= _cupsStrAlloc(pwg_keyword
);
405 else if (!_cups_strcasecmp(line
, "SourceOption"))
407 pc
->source_option
= _cupsStrAlloc(value
);
409 else if (!_cups_strcasecmp(line
, "NumSources"))
413 DEBUG_puts("_ppdCacheCreateWithFile: NumSources listed multiple "
415 _cupsSetError(IPP_INTERNAL_ERROR
, _("Bad PPD cache file."), 1);
419 if ((num_sources
= atoi(value
)) <= 0 || num_sources
> 65536)
421 DEBUG_printf(("_ppdCacheCreateWithFile: Bad NumSources value %d on "
422 "line %d.", num_sources
, linenum
));
423 _cupsSetError(IPP_INTERNAL_ERROR
, _("Bad PPD cache file."), 1);
427 if ((pc
->sources
= calloc(num_sources
, sizeof(_pwg_map_t
))) == NULL
)
429 DEBUG_printf(("_ppdCacheCreateWithFile: Unable to allocate %d sources.",
431 _cupsSetError(IPP_INTERNAL_ERROR
, strerror(errno
), 0);
435 else if (!_cups_strcasecmp(line
, "Source"))
437 if (sscanf(value
, "%127s%40s", pwg_keyword
, ppd_keyword
) != 2)
439 DEBUG_printf(("_ppdCacheCreateWithFile: Bad Source on line %d.",
441 _cupsSetError(IPP_INTERNAL_ERROR
, _("Bad PPD cache file."), 1);
445 if (pc
->num_sources
>= num_sources
)
447 DEBUG_printf(("_ppdCacheCreateWithFile: Too many Source's on line %d.",
449 _cupsSetError(IPP_INTERNAL_ERROR
, _("Bad PPD cache file."), 1);
453 map
= pc
->sources
+ pc
->num_sources
;
454 map
->pwg
= _cupsStrAlloc(pwg_keyword
);
455 map
->ppd
= _cupsStrAlloc(ppd_keyword
);
459 else if (!_cups_strcasecmp(line
, "NumTypes"))
463 DEBUG_puts("_ppdCacheCreateWithFile: NumTypes listed multiple times.");
464 _cupsSetError(IPP_INTERNAL_ERROR
, _("Bad PPD cache file."), 1);
468 if ((num_types
= atoi(value
)) <= 0 || num_types
> 65536)
470 DEBUG_printf(("_ppdCacheCreateWithFile: Bad NumTypes value %d on "
471 "line %d.", num_types
, linenum
));
472 _cupsSetError(IPP_INTERNAL_ERROR
, _("Bad PPD cache file."), 1);
476 if ((pc
->types
= calloc(num_types
, sizeof(_pwg_map_t
))) == NULL
)
478 DEBUG_printf(("_ppdCacheCreateWithFile: Unable to allocate %d types.",
480 _cupsSetError(IPP_INTERNAL_ERROR
, strerror(errno
), 0);
484 else if (!_cups_strcasecmp(line
, "Type"))
486 if (sscanf(value
, "%127s%40s", pwg_keyword
, ppd_keyword
) != 2)
488 DEBUG_printf(("_ppdCacheCreateWithFile: Bad Type on line %d.",
490 _cupsSetError(IPP_INTERNAL_ERROR
, _("Bad PPD cache file."), 1);
494 if (pc
->num_types
>= num_types
)
496 DEBUG_printf(("_ppdCacheCreateWithFile: Too many Type's on line %d.",
498 _cupsSetError(IPP_INTERNAL_ERROR
, _("Bad PPD cache file."), 1);
502 map
= pc
->types
+ pc
->num_types
;
503 map
->pwg
= _cupsStrAlloc(pwg_keyword
);
504 map
->ppd
= _cupsStrAlloc(ppd_keyword
);
508 else if (!_cups_strcasecmp(line
, "Preset"))
511 * Preset output-mode print-quality name=value ...
514 print_color_mode
= (_pwg_print_color_mode_t
)strtol(value
, &valueptr
, 10);
515 print_quality
= (_pwg_print_quality_t
)strtol(valueptr
, &valueptr
, 10);
517 if (print_color_mode
< _PWG_PRINT_COLOR_MODE_MONOCHROME
||
518 print_color_mode
>= _PWG_PRINT_COLOR_MODE_MAX
||
519 print_quality
< _PWG_PRINT_QUALITY_DRAFT
||
520 print_quality
>= _PWG_PRINT_QUALITY_MAX
||
521 valueptr
== value
|| !*valueptr
)
523 DEBUG_printf(("_ppdCacheCreateWithFile: Bad Preset on line %d.",
525 _cupsSetError(IPP_INTERNAL_ERROR
, _("Bad PPD cache file."), 1);
529 pc
->num_presets
[print_color_mode
][print_quality
] =
530 cupsParseOptions(valueptr
, 0,
531 pc
->presets
[print_color_mode
] + print_quality
);
533 else if (!_cups_strcasecmp(line
, "SidesOption"))
534 pc
->sides_option
= _cupsStrAlloc(value
);
535 else if (!_cups_strcasecmp(line
, "Sides1Sided"))
536 pc
->sides_1sided
= _cupsStrAlloc(value
);
537 else if (!_cups_strcasecmp(line
, "Sides2SidedLong"))
538 pc
->sides_2sided_long
= _cupsStrAlloc(value
);
539 else if (!_cups_strcasecmp(line
, "Sides2SidedShort"))
540 pc
->sides_2sided_short
= _cupsStrAlloc(value
);
541 else if (!_cups_strcasecmp(line
, "Finishings"))
545 cupsArrayNew3((cups_array_func_t
)pwg_compare_finishings
,
547 (cups_afree_func_t
)pwg_free_finishings
);
549 if ((finishings
= calloc(1, sizeof(_pwg_finishings_t
))) == NULL
)
552 finishings
->value
= strtol(value
, &valueptr
, 10);
553 finishings
->num_options
= cupsParseOptions(valueptr
, 0,
554 &(finishings
->options
));
556 cupsArrayAdd(pc
->finishings
, finishings
);
558 else if (!_cups_strcasecmp(line
, "MaxCopies"))
559 pc
->max_copies
= atoi(value
);
562 DEBUG_printf(("_ppdCacheCreateWithFile: Unknown %s on line %d.", line
,
567 if (pc
->num_sizes
< num_sizes
)
569 DEBUG_printf(("_ppdCacheCreateWithFile: Not enough sizes (%d < %d).",
570 pc
->num_sizes
, num_sizes
));
571 _cupsSetError(IPP_INTERNAL_ERROR
, _("Bad PPD cache file."), 1);
575 if (pc
->num_sources
< num_sources
)
577 DEBUG_printf(("_ppdCacheCreateWithFile: Not enough sources (%d < %d).",
578 pc
->num_sources
, num_sources
));
579 _cupsSetError(IPP_INTERNAL_ERROR
, _("Bad PPD cache file."), 1);
583 if (pc
->num_types
< num_types
)
585 DEBUG_printf(("_ppdCacheCreateWithFile: Not enough types (%d < %d).",
586 pc
->num_types
, num_types
));
587 _cupsSetError(IPP_INTERNAL_ERROR
, _("Bad PPD cache file."), 1);
596 * If we get here the file was bad - free any data and return...
602 _ppdCacheDestroy(pc
);
615 * '_ppdCacheCreateWithPPD()' - Create PWG mapping data from a PPD file.
618 _ppd_cache_t
* /* O - PPD cache and mapping data */
619 _ppdCacheCreateWithPPD(ppd_file_t
*ppd
) /* I - PPD file */
621 int i
, j
, k
; /* Looping vars */
622 _ppd_cache_t
*pc
; /* PWG mapping data */
623 ppd_option_t
*input_slot
, /* InputSlot option */
624 *media_type
, /* MediaType option */
625 *output_bin
, /* OutputBin option */
626 *color_model
, /* ColorModel option */
627 *duplex
; /* Duplex option */
628 ppd_choice_t
*choice
; /* Current InputSlot/MediaType */
629 _pwg_map_t
*map
; /* Current source/type map */
630 ppd_attr_t
*ppd_attr
; /* Current PPD preset attribute */
631 int num_options
; /* Number of preset options and props */
632 cups_option_t
*options
; /* Preset options and properties */
633 ppd_size_t
*ppd_size
; /* Current PPD size */
634 _pwg_size_t
*pwg_size
; /* Current PWG size */
635 char pwg_keyword
[3 + PPD_MAX_NAME
+ 1 + 12 + 1 + 12 + 3],
636 /* PWG keyword string */
637 ppd_name
[PPD_MAX_NAME
];
638 /* Normalized PPD name */
639 const char *pwg_name
; /* Standard PWG media name */
640 _pwg_media_t
*pwg_media
; /* PWG media data */
641 _pwg_print_color_mode_t pwg_print_color_mode
;
642 /* print-color-mode index */
643 _pwg_print_quality_t pwg_print_quality
;
644 /* print-quality index */
645 int similar
; /* Are the old and new size similar? */
646 _pwg_size_t
*old_size
; /* Current old size */
647 int old_imageable
, /* Old imageable length in 2540ths */
648 old_borderless
, /* Old borderless state */
649 old_known_pwg
; /* Old PWG name is well-known */
650 int new_width
, /* New width in 2540ths */
651 new_length
, /* New length in 2540ths */
652 new_left
, /* New left margin in 2540ths */
653 new_bottom
, /* New bottom margin in 2540ths */
654 new_right
, /* New right margin in 2540ths */
655 new_top
, /* New top margin in 2540ths */
656 new_imageable
, /* New imageable length in 2540ths */
657 new_borderless
, /* New borderless state */
658 new_known_pwg
; /* New PWG name is well-known */
659 _pwg_size_t
*new_size
; /* New size to add, if any */
660 const char *filter
; /* Current filter */
661 _pwg_finishings_t
*finishings
; /* Current finishings value */
664 DEBUG_printf(("_ppdCacheCreateWithPPD(ppd=%p)", ppd
));
667 * Range check input...
677 if ((pc
= calloc(1, sizeof(_ppd_cache_t
))) == NULL
)
679 DEBUG_puts("_ppdCacheCreateWithPPD: Unable to allocate _ppd_cache_t.");
684 * Copy and convert size data...
687 if (ppd
->num_sizes
== 0)
689 DEBUG_puts("_ppdCacheCreateWithPPD: No page sizes in PPD.");
693 if ((pc
->sizes
= calloc(ppd
->num_sizes
, sizeof(_pwg_size_t
))) == NULL
)
695 DEBUG_printf(("_ppdCacheCreateWithPPD: Unable to allocate %d "
696 "_pwg_size_t's.", ppd
->num_sizes
));
700 for (i
= ppd
->num_sizes
, pwg_size
= pc
->sizes
, ppd_size
= ppd
->sizes
;
705 * Don't copy over custom size...
708 if (!_cups_strcasecmp(ppd_size
->name
, "Custom"))
712 * Convert the PPD size name to the corresponding PWG keyword name.
715 if ((pwg_media
= _pwgMediaForPPD(ppd_size
->name
)) != NULL
)
718 * Standard name, do we have conflicts?
721 for (j
= 0; j
< pc
->num_sizes
; j
++)
722 if (!strcmp(pc
->sizes
[j
].map
.pwg
, pwg_media
->pwg
))
732 * Standard name and no conflicts, use it!
735 pwg_name
= pwg_media
->pwg
;
741 * Not a standard name; convert it to a PWG vendor name of the form:
743 * pp_lowerppd_WIDTHxHEIGHTuu
746 pwg_name
= pwg_keyword
;
749 pwg_unppdize_name(ppd_size
->name
, ppd_name
, sizeof(ppd_name
));
750 _pwgGenerateSize(pwg_keyword
, sizeof(pwg_keyword
), NULL
, ppd_name
,
751 _PWG_FROMPTS(ppd_size
->width
),
752 _PWG_FROMPTS(ppd_size
->length
));
756 * If we have a similar paper with non-zero margins then we only
757 * want to keep it if it has a larger imageable area length.
760 pwg_media
= _pwgMediaForSize(_PWG_FROMPTS(ppd_size
->width
),
761 _PWG_FROMPTS(ppd_size
->length
));
762 new_width
= pwg_media
->width
;
763 new_length
= pwg_media
->length
;
764 new_left
= _PWG_FROMPTS(ppd_size
->left
);
765 new_bottom
= _PWG_FROMPTS(ppd_size
->bottom
);
766 new_right
= _PWG_FROMPTS(ppd_size
->width
- ppd_size
->right
);
767 new_top
= _PWG_FROMPTS(ppd_size
->length
- ppd_size
->top
);
768 new_imageable
= new_length
- new_top
- new_bottom
;
769 new_borderless
= new_bottom
== 0 && new_top
== 0 &&
770 new_left
== 0 && new_right
== 0;
772 for (k
= pc
->num_sizes
, similar
= 0, old_size
= pc
->sizes
, new_size
= NULL
;
776 old_imageable
= old_size
->length
- old_size
->top
- old_size
->bottom
;
777 old_borderless
= old_size
->left
== 0 && old_size
->bottom
== 0 &&
778 old_size
->right
== 0 && old_size
->top
== 0;
779 old_known_pwg
= strncmp(old_size
->map
.pwg
, "oe_", 3) &&
780 strncmp(old_size
->map
.pwg
, "om_", 3);
782 similar
= old_borderless
== new_borderless
&&
783 _PWG_EQUIVALENT(old_size
->width
, new_width
) &&
784 _PWG_EQUIVALENT(old_size
->length
, new_length
);
787 (new_known_pwg
|| (!old_known_pwg
&& new_imageable
> old_imageable
)))
790 * The new paper has a larger imageable area so it could replace
791 * the older paper. Regardless of the imageable area, we always
792 * prefer the size with a well-known PWG name.
796 _cupsStrFree(old_size
->map
.ppd
);
797 _cupsStrFree(old_size
->map
.pwg
);
804 * The paper was unique enough to deserve its own entry so add it to the
808 new_size
= pwg_size
++;
818 new_size
->map
.ppd
= _cupsStrAlloc(ppd_size
->name
);
819 new_size
->map
.pwg
= _cupsStrAlloc(pwg_name
);
820 new_size
->width
= new_width
;
821 new_size
->length
= new_length
;
822 new_size
->left
= new_left
;
823 new_size
->bottom
= new_bottom
;
824 new_size
->right
= new_right
;
825 new_size
->top
= new_top
;
829 if (ppd
->variable_sizes
)
832 * Generate custom size data...
835 _pwgGenerateSize(pwg_keyword
, sizeof(pwg_keyword
), "custom", "max",
836 _PWG_FROMPTS(ppd
->custom_max
[0]),
837 _PWG_FROMPTS(ppd
->custom_max
[1]));
838 pc
->custom_max_keyword
= _cupsStrAlloc(pwg_keyword
);
839 pc
->custom_max_width
= _PWG_FROMPTS(ppd
->custom_max
[0]);
840 pc
->custom_max_length
= _PWG_FROMPTS(ppd
->custom_max
[1]);
842 _pwgGenerateSize(pwg_keyword
, sizeof(pwg_keyword
), "custom", "min",
843 _PWG_FROMPTS(ppd
->custom_min
[0]),
844 _PWG_FROMPTS(ppd
->custom_min
[1]));
845 pc
->custom_min_keyword
= _cupsStrAlloc(pwg_keyword
);
846 pc
->custom_min_width
= _PWG_FROMPTS(ppd
->custom_min
[0]);
847 pc
->custom_min_length
= _PWG_FROMPTS(ppd
->custom_min
[1]);
849 pc
->custom_size
.left
= _PWG_FROMPTS(ppd
->custom_margins
[0]);
850 pc
->custom_size
.bottom
= _PWG_FROMPTS(ppd
->custom_margins
[1]);
851 pc
->custom_size
.right
= _PWG_FROMPTS(ppd
->custom_margins
[2]);
852 pc
->custom_size
.top
= _PWG_FROMPTS(ppd
->custom_margins
[3]);
856 * Copy and convert InputSlot data...
859 if ((input_slot
= ppdFindOption(ppd
, "InputSlot")) == NULL
)
860 input_slot
= ppdFindOption(ppd
, "HPPaperSource");
864 pc
->source_option
= _cupsStrAlloc(input_slot
->keyword
);
866 if ((pc
->sources
= calloc(input_slot
->num_choices
,
867 sizeof(_pwg_map_t
))) == NULL
)
869 DEBUG_printf(("_ppdCacheCreateWithPPD: Unable to allocate %d "
870 "_pwg_map_t's for InputSlot.", input_slot
->num_choices
));
874 pc
->num_sources
= input_slot
->num_choices
;
876 for (i
= input_slot
->num_choices
, choice
= input_slot
->choices
,
879 i
--, choice
++, map
++)
881 if (!_cups_strncasecmp(choice
->choice
, "Auto", 4) ||
882 !_cups_strcasecmp(choice
->choice
, "Default"))
884 else if (!_cups_strcasecmp(choice
->choice
, "Cassette"))
886 else if (!_cups_strcasecmp(choice
->choice
, "PhotoTray"))
888 else if (!_cups_strcasecmp(choice
->choice
, "CDTray"))
890 else if (!_cups_strncasecmp(choice
->choice
, "Multipurpose", 12) ||
891 !_cups_strcasecmp(choice
->choice
, "MP") ||
892 !_cups_strcasecmp(choice
->choice
, "MPTray"))
893 pwg_name
= "by-pass-tray";
894 else if (!_cups_strcasecmp(choice
->choice
, "LargeCapacity"))
895 pwg_name
= "large-capacity";
896 else if (!_cups_strncasecmp(choice
->choice
, "Lower", 5))
898 else if (!_cups_strncasecmp(choice
->choice
, "Middle", 6))
900 else if (!_cups_strncasecmp(choice
->choice
, "Upper", 5))
902 else if (!_cups_strncasecmp(choice
->choice
, "Side", 4))
904 else if (!_cups_strcasecmp(choice
->choice
, "Roll"))
905 pwg_name
= "main-roll";
909 * Convert PPD name to lowercase...
912 pwg_name
= pwg_keyword
;
913 pwg_unppdize_name(choice
->choice
, pwg_keyword
, sizeof(pwg_keyword
));
916 map
->pwg
= _cupsStrAlloc(pwg_name
);
917 map
->ppd
= _cupsStrAlloc(choice
->choice
);
922 * Copy and convert MediaType data...
925 if ((media_type
= ppdFindOption(ppd
, "MediaType")) != NULL
)
927 if ((pc
->types
= calloc(media_type
->num_choices
,
928 sizeof(_pwg_map_t
))) == NULL
)
930 DEBUG_printf(("_ppdCacheCreateWithPPD: Unable to allocate %d "
931 "_pwg_map_t's for MediaType.", media_type
->num_choices
));
935 pc
->num_types
= media_type
->num_choices
;
937 for (i
= media_type
->num_choices
, choice
= media_type
->choices
,
940 i
--, choice
++, map
++)
942 if (!_cups_strncasecmp(choice
->choice
, "Auto", 4) ||
943 !_cups_strcasecmp(choice
->choice
, "Any") ||
944 !_cups_strcasecmp(choice
->choice
, "Default"))
946 else if (!_cups_strncasecmp(choice
->choice
, "Card", 4))
947 pwg_name
= "cardstock";
948 else if (!_cups_strncasecmp(choice
->choice
, "Env", 3))
949 pwg_name
= "envelope";
950 else if (!_cups_strncasecmp(choice
->choice
, "Gloss", 5))
951 pwg_name
= "photographic-glossy";
952 else if (!_cups_strcasecmp(choice
->choice
, "HighGloss"))
953 pwg_name
= "photographic-high-gloss";
954 else if (!_cups_strcasecmp(choice
->choice
, "Matte"))
955 pwg_name
= "photographic-matte";
956 else if (!_cups_strncasecmp(choice
->choice
, "Plain", 5))
957 pwg_name
= "stationery";
958 else if (!_cups_strncasecmp(choice
->choice
, "Coated", 6))
959 pwg_name
= "stationery-coated";
960 else if (!_cups_strcasecmp(choice
->choice
, "Inkjet"))
961 pwg_name
= "stationery-inkjet";
962 else if (!_cups_strcasecmp(choice
->choice
, "Letterhead"))
963 pwg_name
= "stationery-letterhead";
964 else if (!_cups_strncasecmp(choice
->choice
, "Preprint", 8))
965 pwg_name
= "stationery-preprinted";
966 else if (!_cups_strcasecmp(choice
->choice
, "Recycled"))
967 pwg_name
= "stationery-recycled";
968 else if (!_cups_strncasecmp(choice
->choice
, "Transparen", 10))
969 pwg_name
= "transparency";
973 * Convert PPD name to lowercase...
976 pwg_name
= pwg_keyword
;
977 pwg_unppdize_name(choice
->choice
, pwg_keyword
, sizeof(pwg_keyword
));
980 map
->pwg
= _cupsStrAlloc(pwg_name
);
981 map
->ppd
= _cupsStrAlloc(choice
->choice
);
986 * Copy and convert OutputBin data...
989 if ((output_bin
= ppdFindOption(ppd
, "OutputBin")) != NULL
)
991 if ((pc
->bins
= calloc(output_bin
->num_choices
,
992 sizeof(_pwg_map_t
))) == NULL
)
994 DEBUG_printf(("_ppdCacheCreateWithPPD: Unable to allocate %d "
995 "_pwg_map_t's for OutputBin.", output_bin
->num_choices
));
999 pc
->num_bins
= output_bin
->num_choices
;
1001 for (i
= output_bin
->num_choices
, choice
= output_bin
->choices
,
1004 i
--, choice
++, map
++)
1006 pwg_unppdize_name(choice
->choice
, pwg_keyword
, sizeof(pwg_keyword
));
1008 map
->pwg
= _cupsStrAlloc(pwg_keyword
);
1009 map
->ppd
= _cupsStrAlloc(choice
->choice
);
1013 if ((ppd_attr
= ppdFindAttr(ppd
, "APPrinterPreset", NULL
)) != NULL
)
1016 * Copy and convert APPrinterPreset (output-mode + print-quality) data...
1019 const char *quality
, /* com.apple.print.preset.quality value */
1020 *output_mode
, /* com.apple.print.preset.output-mode value */
1021 *color_model_val
, /* ColorModel choice */
1022 *graphicsType
, /* com.apple.print.preset.graphicsType value */
1023 *media_front_coating
; /* com.apple.print.preset.media-front-coating value */
1027 num_options
= _ppdParseOptions(ppd_attr
->value
, 0, &options
,
1030 if ((quality
= cupsGetOption("com.apple.print.preset.quality",
1031 num_options
, options
)) != NULL
)
1034 * Get the print-quality for this preset...
1037 if (!strcmp(quality
, "low"))
1038 pwg_print_quality
= _PWG_PRINT_QUALITY_DRAFT
;
1039 else if (!strcmp(quality
, "high"))
1040 pwg_print_quality
= _PWG_PRINT_QUALITY_HIGH
;
1042 pwg_print_quality
= _PWG_PRINT_QUALITY_NORMAL
;
1045 * Ignore graphicsType "Photo" presets that are not high quality.
1048 graphicsType
= cupsGetOption("com.apple.print.preset.graphicsType",
1049 num_options
, options
);
1051 if (pwg_print_quality
!= _PWG_PRINT_QUALITY_HIGH
&& graphicsType
&&
1052 !strcmp(graphicsType
, "Photo"))
1056 * Ignore presets for normal and draft quality where the coating
1057 * isn't "none" or "autodetect".
1060 media_front_coating
= cupsGetOption(
1061 "com.apple.print.preset.media-front-coating",
1062 num_options
, options
);
1064 if (pwg_print_quality
!= _PWG_PRINT_QUALITY_HIGH
&&
1065 media_front_coating
&&
1066 strcmp(media_front_coating
, "none") &&
1067 strcmp(media_front_coating
, "autodetect"))
1071 * Get the output mode for this preset...
1074 output_mode
= cupsGetOption("com.apple.print.preset.output-mode",
1075 num_options
, options
);
1076 color_model_val
= cupsGetOption("ColorModel", num_options
, options
);
1080 if (!strcmp(output_mode
, "monochrome"))
1081 pwg_print_color_mode
= _PWG_PRINT_COLOR_MODE_MONOCHROME
;
1083 pwg_print_color_mode
= _PWG_PRINT_COLOR_MODE_COLOR
;
1085 else if (color_model_val
)
1087 if (!_cups_strcasecmp(color_model_val
, "Gray"))
1088 pwg_print_color_mode
= _PWG_PRINT_COLOR_MODE_MONOCHROME
;
1090 pwg_print_color_mode
= _PWG_PRINT_COLOR_MODE_COLOR
;
1093 pwg_print_color_mode
= _PWG_PRINT_COLOR_MODE_COLOR
;
1096 * Save the options for this combination as needed...
1099 if (!pc
->num_presets
[pwg_print_color_mode
][pwg_print_quality
])
1100 pc
->num_presets
[pwg_print_color_mode
][pwg_print_quality
] =
1101 _ppdParseOptions(ppd_attr
->value
, 0,
1102 pc
->presets
[pwg_print_color_mode
] +
1103 pwg_print_quality
, _PPD_PARSE_OPTIONS
);
1106 cupsFreeOptions(num_options
, options
);
1108 while ((ppd_attr
= ppdFindNextAttr(ppd
, "APPrinterPreset", NULL
)) != NULL
);
1111 if (!pc
->num_presets
[_PWG_PRINT_COLOR_MODE_MONOCHROME
][_PWG_PRINT_QUALITY_DRAFT
] &&
1112 !pc
->num_presets
[_PWG_PRINT_COLOR_MODE_MONOCHROME
][_PWG_PRINT_QUALITY_NORMAL
] &&
1113 !pc
->num_presets
[_PWG_PRINT_COLOR_MODE_MONOCHROME
][_PWG_PRINT_QUALITY_HIGH
])
1116 * Try adding some common color options to create grayscale presets. These
1117 * are listed in order of popularity...
1120 const char *color_option
= NULL
, /* Color control option */
1121 *gray_choice
= NULL
; /* Choice to select grayscale */
1123 if ((color_model
= ppdFindOption(ppd
, "ColorModel")) != NULL
&&
1124 ppdFindChoice(color_model
, "Gray"))
1126 color_option
= "ColorModel";
1127 gray_choice
= "Gray";
1129 else if ((color_model
= ppdFindOption(ppd
, "HPColorMode")) != NULL
&&
1130 ppdFindChoice(color_model
, "grayscale"))
1132 color_option
= "HPColorMode";
1133 gray_choice
= "grayscale";
1135 else if ((color_model
= ppdFindOption(ppd
, "BRMonoColor")) != NULL
&&
1136 ppdFindChoice(color_model
, "Mono"))
1138 color_option
= "BRMonoColor";
1139 gray_choice
= "Mono";
1141 else if ((color_model
= ppdFindOption(ppd
, "CNIJSGrayScale")) != NULL
&&
1142 ppdFindChoice(color_model
, "1"))
1144 color_option
= "CNIJSGrayScale";
1147 else if ((color_model
= ppdFindOption(ppd
, "HPColorAsGray")) != NULL
&&
1148 ppdFindChoice(color_model
, "True"))
1150 color_option
= "HPColorAsGray";
1151 gray_choice
= "True";
1154 if (color_option
&& gray_choice
)
1157 * Copy and convert ColorModel (output-mode) data...
1160 cups_option_t
*coption
, /* Color option */
1161 *moption
; /* Monochrome option */
1163 for (pwg_print_quality
= _PWG_PRINT_QUALITY_DRAFT
;
1164 pwg_print_quality
< _PWG_PRINT_QUALITY_MAX
;
1165 pwg_print_quality
++)
1167 if (pc
->num_presets
[_PWG_PRINT_COLOR_MODE_COLOR
][pwg_print_quality
])
1170 * Copy the color options...
1173 num_options
= pc
->num_presets
[_PWG_PRINT_COLOR_MODE_COLOR
]
1174 [pwg_print_quality
];
1175 options
= calloc(sizeof(cups_option_t
), num_options
);
1179 for (i
= num_options
, moption
= options
,
1180 coption
= pc
->presets
[_PWG_PRINT_COLOR_MODE_COLOR
]
1181 [pwg_print_quality
];
1183 i
--, moption
++, coption
++)
1185 moption
->name
= _cupsStrRetain(coption
->name
);
1186 moption
->value
= _cupsStrRetain(coption
->value
);
1189 pc
->num_presets
[_PWG_PRINT_COLOR_MODE_MONOCHROME
][pwg_print_quality
] =
1191 pc
->presets
[_PWG_PRINT_COLOR_MODE_MONOCHROME
][pwg_print_quality
] =
1195 else if (pwg_print_quality
!= _PWG_PRINT_QUALITY_NORMAL
)
1199 * Add the grayscale option to the preset...
1202 pc
->num_presets
[_PWG_PRINT_COLOR_MODE_MONOCHROME
][pwg_print_quality
] =
1203 cupsAddOption(color_option
, gray_choice
,
1204 pc
->num_presets
[_PWG_PRINT_COLOR_MODE_MONOCHROME
]
1205 [pwg_print_quality
],
1206 pc
->presets
[_PWG_PRINT_COLOR_MODE_MONOCHROME
] +
1213 * Copy and convert Duplex (sides) data...
1216 if ((duplex
= ppdFindOption(ppd
, "Duplex")) == NULL
)
1217 if ((duplex
= ppdFindOption(ppd
, "JCLDuplex")) == NULL
)
1218 if ((duplex
= ppdFindOption(ppd
, "EFDuplex")) == NULL
)
1219 if ((duplex
= ppdFindOption(ppd
, "EFDuplexing")) == NULL
)
1220 duplex
= ppdFindOption(ppd
, "KD03Duplex");
1224 pc
->sides_option
= _cupsStrAlloc(duplex
->keyword
);
1226 for (i
= duplex
->num_choices
, choice
= duplex
->choices
;
1230 if ((!_cups_strcasecmp(choice
->choice
, "None") ||
1231 !_cups_strcasecmp(choice
->choice
, "False")) && !pc
->sides_1sided
)
1232 pc
->sides_1sided
= _cupsStrAlloc(choice
->choice
);
1233 else if ((!_cups_strcasecmp(choice
->choice
, "DuplexNoTumble") ||
1234 !_cups_strcasecmp(choice
->choice
, "LongEdge") ||
1235 !_cups_strcasecmp(choice
->choice
, "Top")) && !pc
->sides_2sided_long
)
1236 pc
->sides_2sided_long
= _cupsStrAlloc(choice
->choice
);
1237 else if ((!_cups_strcasecmp(choice
->choice
, "DuplexTumble") ||
1238 !_cups_strcasecmp(choice
->choice
, "ShortEdge") ||
1239 !_cups_strcasecmp(choice
->choice
, "Bottom")) &&
1240 !pc
->sides_2sided_short
)
1241 pc
->sides_2sided_short
= _cupsStrAlloc(choice
->choice
);
1246 * Copy filters and pre-filters...
1249 pc
->filters
= cupsArrayNew3(NULL
, NULL
, NULL
, 0,
1250 (cups_acopy_func_t
)_cupsStrAlloc
,
1251 (cups_afree_func_t
)_cupsStrFree
);
1253 cupsArrayAdd(pc
->filters
,
1254 "application/vnd.cups-raw application/octet-stream 0 -");
1256 if ((ppd_attr
= ppdFindAttr(ppd
, "cupsFilter2", NULL
)) != NULL
)
1260 cupsArrayAdd(pc
->filters
, ppd_attr
->value
);
1262 while ((ppd_attr
= ppdFindNextAttr(ppd
, "cupsFilter2", NULL
)) != NULL
);
1264 else if (ppd
->num_filters
> 0)
1266 for (i
= 0; i
< ppd
->num_filters
; i
++)
1267 cupsArrayAdd(pc
->filters
, ppd
->filters
[i
]);
1270 cupsArrayAdd(pc
->filters
, "application/vnd.cups-postscript 0 -");
1273 * See if we have a command filter...
1276 for (filter
= (const char *)cupsArrayFirst(pc
->filters
);
1278 filter
= (const char *)cupsArrayNext(pc
->filters
))
1279 if (!_cups_strncasecmp(filter
, "application/vnd.cups-command", 28) &&
1280 _cups_isspace(filter
[28]))
1284 ((ppd_attr
= ppdFindAttr(ppd
, "cupsCommands", NULL
)) == NULL
||
1285 _cups_strcasecmp(ppd_attr
->value
, "none")))
1288 * No command filter and no cupsCommands keyword telling us not to use one.
1289 * See if this is a PostScript printer, and if so add a PostScript command
1293 for (filter
= (const char *)cupsArrayFirst(pc
->filters
);
1295 filter
= (const char *)cupsArrayNext(pc
->filters
))
1296 if (!_cups_strncasecmp(filter
, "application/vnd.cups-postscript", 31) &&
1297 _cups_isspace(filter
[31]))
1301 cupsArrayAdd(pc
->filters
,
1302 "application/vnd.cups-command application/postscript 100 "
1306 if ((ppd_attr
= ppdFindAttr(ppd
, "cupsPreFilter", NULL
)) != NULL
)
1308 pc
->prefilters
= cupsArrayNew3(NULL
, NULL
, NULL
, 0,
1309 (cups_acopy_func_t
)_cupsStrAlloc
,
1310 (cups_afree_func_t
)_cupsStrFree
);
1314 cupsArrayAdd(pc
->prefilters
, ppd_attr
->value
);
1316 while ((ppd_attr
= ppdFindNextAttr(ppd
, "cupsPreFilter", NULL
)) != NULL
);
1319 if ((ppd_attr
= ppdFindAttr(ppd
, "cupsSingleFile", NULL
)) != NULL
)
1320 pc
->single_file
= !_cups_strcasecmp(ppd_attr
->value
, "true");
1323 * Copy the product string, if any...
1327 pc
->product
= _cupsStrAlloc(ppd
->product
);
1330 * Copy finishings mapping data...
1333 if ((ppd_attr
= ppdFindAttr(ppd
, "cupsIPPFinishings", NULL
)) != NULL
)
1335 pc
->finishings
= cupsArrayNew3((cups_array_func_t
)pwg_compare_finishings
,
1336 NULL
, NULL
, 0, NULL
,
1337 (cups_afree_func_t
)pwg_free_finishings
);
1341 if ((finishings
= calloc(1, sizeof(_pwg_finishings_t
))) == NULL
)
1344 finishings
->value
= atoi(ppd_attr
->spec
);
1345 finishings
->num_options
= _ppdParseOptions(ppd_attr
->value
, 0,
1346 &(finishings
->options
),
1347 _PPD_PARSE_OPTIONS
);
1349 cupsArrayAdd(pc
->finishings
, finishings
);
1351 while ((ppd_attr
= ppdFindNextAttr(ppd
, "cupsIPPFinishings",
1359 if ((ppd_attr
= ppdFindAttr(ppd
, "cupsMaxCopies", NULL
)) != NULL
)
1360 pc
->max_copies
= atoi(ppd_attr
->value
);
1361 else if (ppd
->manual_copies
)
1364 pc
->max_copies
= 9999;
1367 * Return the cache data...
1373 * If we get here we need to destroy the PWG mapping data and return NULL...
1378 _cupsSetError(IPP_INTERNAL_ERROR
, _("Out of memory."), 1);
1379 _ppdCacheDestroy(pc
);
1386 * '_ppdCacheDestroy()' - Free all memory used for PWG mapping data.
1390 _ppdCacheDestroy(_ppd_cache_t
*pc
) /* I - PPD cache and mapping data */
1392 int i
; /* Looping var */
1393 _pwg_map_t
*map
; /* Current map */
1394 _pwg_size_t
*size
; /* Current size */
1398 * Range check input...
1405 * Free memory as needed...
1410 for (i
= pc
->num_bins
, map
= pc
->bins
; i
> 0; i
--, map
++)
1412 _cupsStrFree(map
->pwg
);
1413 _cupsStrFree(map
->ppd
);
1421 for (i
= pc
->num_sizes
, size
= pc
->sizes
; i
> 0; i
--, size
++)
1423 _cupsStrFree(size
->map
.pwg
);
1424 _cupsStrFree(size
->map
.ppd
);
1430 if (pc
->source_option
)
1431 _cupsStrFree(pc
->source_option
);
1435 for (i
= pc
->num_sources
, map
= pc
->sources
; i
> 0; i
--, map
++)
1437 _cupsStrFree(map
->pwg
);
1438 _cupsStrFree(map
->ppd
);
1446 for (i
= pc
->num_types
, map
= pc
->types
; i
> 0; i
--, map
++)
1448 _cupsStrFree(map
->pwg
);
1449 _cupsStrFree(map
->ppd
);
1455 if (pc
->custom_max_keyword
)
1456 _cupsStrFree(pc
->custom_max_keyword
);
1458 if (pc
->custom_min_keyword
)
1459 _cupsStrFree(pc
->custom_min_keyword
);
1461 _cupsStrFree(pc
->product
);
1462 cupsArrayDelete(pc
->filters
);
1463 cupsArrayDelete(pc
->prefilters
);
1464 cupsArrayDelete(pc
->finishings
);
1471 * '_ppdCacheGetBin()' - Get the PWG output-bin keyword associated with a PPD
1475 const char * /* O - output-bin or NULL */
1477 _ppd_cache_t
*pc
, /* I - PPD cache and mapping data */
1478 const char *output_bin
) /* I - PPD OutputBin string */
1480 int i
; /* Looping var */
1484 * Range check input...
1487 if (!pc
|| !output_bin
)
1491 * Look up the OutputBin string...
1495 for (i
= 0; i
< pc
->num_bins
; i
++)
1496 if (!_cups_strcasecmp(output_bin
, pc
->bins
[i
].ppd
))
1497 return (pc
->bins
[i
].pwg
);
1504 * '_ppdCacheGetFinishingOptions()' - Get PPD finishing options for the given
1505 * IPP finishings value(s).
1508 int /* O - New number of options */
1509 _ppdCacheGetFinishingOptions(
1510 _ppd_cache_t
*pc
, /* I - PPD cache and mapping data */
1511 ipp_t
*job
, /* I - Job attributes or NULL */
1512 ipp_finish_t value
, /* I - IPP finishings value of IPP_FINISHINGS_NONE */
1513 int num_options
, /* I - Number of options */
1514 cups_option_t
**options
) /* IO - Options */
1516 int i
; /* Looping var */
1517 _pwg_finishings_t
*f
, /* PWG finishings options */
1518 key
; /* Search key */
1519 ipp_attribute_t
*attr
; /* Finishings attribute */
1520 cups_option_t
*option
; /* Current finishings option */
1524 * Range check input...
1527 if (!pc
|| cupsArrayCount(pc
->finishings
) == 0 || !options
||
1528 (!job
&& value
== IPP_FINISHINGS_NONE
))
1529 return (num_options
);
1532 * Apply finishing options...
1535 if (job
&& (attr
= ippFindAttribute(job
, "finishings", IPP_TAG_ENUM
)) != NULL
)
1537 int num_values
= ippGetCount(attr
); /* Number of values */
1539 for (i
= 0; i
< num_values
; i
++)
1541 key
.value
= ippGetInteger(attr
, i
);
1543 if ((f
= cupsArrayFind(pc
->finishings
, &key
)) != NULL
)
1545 int j
; /* Another looping var */
1547 for (j
= f
->num_options
, option
= f
->options
; j
> 0; j
--, option
++)
1548 num_options
= cupsAddOption(option
->name
, option
->value
,
1549 num_options
, options
);
1553 else if (value
!= IPP_FINISHINGS_NONE
)
1557 if ((f
= cupsArrayFind(pc
->finishings
, &key
)) != NULL
)
1559 int j
; /* Another looping var */
1561 for (j
= f
->num_options
, option
= f
->options
; j
> 0; j
--, option
++)
1562 num_options
= cupsAddOption(option
->name
, option
->value
,
1563 num_options
, options
);
1567 return (num_options
);
1572 * '_ppdCacheGetFinishingValues()' - Get IPP finishings value(s) from the given
1576 int /* O - Number of finishings values */
1577 _ppdCacheGetFinishingValues(
1578 _ppd_cache_t
*pc
, /* I - PPD cache and mapping data */
1579 int num_options
, /* I - Number of options */
1580 cups_option_t
*options
, /* I - Options */
1581 int max_values
, /* I - Maximum number of finishings values */
1582 int *values
) /* O - Finishings values */
1584 int i
, /* Looping var */
1585 num_values
= 0; /* Number of values */
1586 _pwg_finishings_t
*f
; /* Current finishings option */
1587 cups_option_t
*option
; /* Current option */
1588 const char *val
; /* Value for option */
1592 * Range check input...
1595 if (!pc
|| !pc
->finishings
|| num_options
< 1 || max_values
< 1 || !values
)
1599 * Go through the finishings options and see what is set...
1602 for (f
= (_pwg_finishings_t
*)cupsArrayFirst(pc
->finishings
);
1604 f
= (_pwg_finishings_t
*)cupsArrayNext(pc
->finishings
))
1606 for (i
= f
->num_options
, option
= f
->options
; i
> 0; i
--, option
++)
1607 if ((val
= cupsGetOption(option
->name
, num_options
, options
)) == NULL
||
1608 _cups_strcasecmp(option
->value
, val
))
1613 values
[num_values
++] = f
->value
;
1615 if (num_values
>= max_values
)
1620 return (num_values
);
1625 * '_ppdCacheGetInputSlot()' - Get the PPD InputSlot associated with the job
1626 * attributes or a keyword string.
1629 const char * /* O - PPD InputSlot or NULL */
1630 _ppdCacheGetInputSlot(
1631 _ppd_cache_t
*pc
, /* I - PPD cache and mapping data */
1632 ipp_t
*job
, /* I - Job attributes or NULL */
1633 const char *keyword
) /* I - Keyword string or NULL */
1636 * Range check input...
1639 if (!pc
|| pc
->num_sources
== 0 || (!job
&& !keyword
))
1642 if (job
&& !keyword
)
1645 * Lookup the media-col attribute and any media-source found there...
1648 ipp_attribute_t
*media_col
, /* media-col attribute */
1649 *media_source
; /* media-source attribute */
1650 _pwg_size_t size
; /* Dimensional size */
1651 int margins_set
; /* Were the margins set? */
1653 media_col
= ippFindAttribute(job
, "media-col", IPP_TAG_BEGIN_COLLECTION
);
1655 (media_source
= ippFindAttribute(ippGetCollection(media_col
, 0),
1657 IPP_TAG_KEYWORD
)) != NULL
)
1660 * Use the media-source value from media-col...
1663 keyword
= ippGetString(media_source
, 0, NULL
);
1665 else if (_pwgInitSize(&size
, job
, &margins_set
))
1668 * For media <= 5x7, look for a photo tray...
1671 if (size
.width
<= (5 * 2540) && size
.length
<= (7 * 2540))
1678 int i
; /* Looping var */
1680 for (i
= 0; i
< pc
->num_sources
; i
++)
1681 if (!_cups_strcasecmp(keyword
, pc
->sources
[i
].pwg
))
1682 return (pc
->sources
[i
].ppd
);
1690 * '_ppdCacheGetMediaType()' - Get the PPD MediaType associated with the job
1691 * attributes or a keyword string.
1694 const char * /* O - PPD MediaType or NULL */
1695 _ppdCacheGetMediaType(
1696 _ppd_cache_t
*pc
, /* I - PPD cache and mapping data */
1697 ipp_t
*job
, /* I - Job attributes or NULL */
1698 const char *keyword
) /* I - Keyword string or NULL */
1701 * Range check input...
1704 if (!pc
|| pc
->num_types
== 0 || (!job
&& !keyword
))
1707 if (job
&& !keyword
)
1710 * Lookup the media-col attribute and any media-source found there...
1713 ipp_attribute_t
*media_col
, /* media-col attribute */
1714 *media_type
; /* media-type attribute */
1716 media_col
= ippFindAttribute(job
, "media-col", IPP_TAG_BEGIN_COLLECTION
);
1719 if ((media_type
= ippFindAttribute(media_col
->values
[0].collection
,
1721 IPP_TAG_KEYWORD
)) == NULL
)
1722 media_type
= ippFindAttribute(media_col
->values
[0].collection
,
1723 "media-type", IPP_TAG_NAME
);
1726 keyword
= media_type
->values
[0].string
.text
;
1732 int i
; /* Looping var */
1734 for (i
= 0; i
< pc
->num_types
; i
++)
1735 if (!_cups_strcasecmp(keyword
, pc
->types
[i
].pwg
))
1736 return (pc
->types
[i
].ppd
);
1744 * '_ppdCacheGetOutputBin()' - Get the PPD OutputBin associated with the keyword
1748 const char * /* O - PPD OutputBin or NULL */
1749 _ppdCacheGetOutputBin(
1750 _ppd_cache_t
*pc
, /* I - PPD cache and mapping data */
1751 const char *output_bin
) /* I - Keyword string */
1753 int i
; /* Looping var */
1757 * Range check input...
1760 if (!pc
|| !output_bin
)
1764 * Look up the OutputBin string...
1768 for (i
= 0; i
< pc
->num_bins
; i
++)
1769 if (!_cups_strcasecmp(output_bin
, pc
->bins
[i
].pwg
))
1770 return (pc
->bins
[i
].ppd
);
1777 * '_ppdCacheGetPageSize()' - Get the PPD PageSize associated with the job
1778 * attributes or a keyword string.
1781 const char * /* O - PPD PageSize or NULL */
1782 _ppdCacheGetPageSize(
1783 _ppd_cache_t
*pc
, /* I - PPD cache and mapping data */
1784 ipp_t
*job
, /* I - Job attributes or NULL */
1785 const char *keyword
, /* I - Keyword string or NULL */
1786 int *exact
) /* O - 1 if exact match, 0 otherwise */
1788 int i
; /* Looping var */
1789 _pwg_size_t
*size
, /* Current size */
1790 *closest
, /* Closest size */
1791 jobsize
; /* Size data from job */
1792 int margins_set
, /* Were the margins set? */
1793 dwidth
, /* Difference in width */
1794 dlength
, /* Difference in length */
1795 dleft
, /* Difference in left margins */
1796 dright
, /* Difference in right margins */
1797 dbottom
, /* Difference in bottom margins */
1798 dtop
, /* Difference in top margins */
1799 dmin
, /* Minimum difference */
1800 dclosest
; /* Closest difference */
1801 const char *ppd_name
; /* PPD media name */
1804 DEBUG_printf(("_ppdCacheGetPageSize(pc=%p, job=%p, keyword=\"%s\", exact=%p)",
1805 pc
, job
, keyword
, exact
));
1808 * Range check input...
1811 if (!pc
|| (!job
&& !keyword
))
1822 * Try getting the PPD media name from the job attributes...
1825 ipp_attribute_t
*attr
; /* Job attribute */
1827 if ((attr
= ippFindAttribute(job
, "PageSize", IPP_TAG_ZERO
)) == NULL
)
1828 if ((attr
= ippFindAttribute(job
, "PageRegion", IPP_TAG_ZERO
)) == NULL
)
1829 attr
= ippFindAttribute(job
, "media", IPP_TAG_ZERO
);
1833 DEBUG_printf(("1_ppdCacheGetPageSize: Found attribute %s (%s)",
1834 attr
->name
, ippTagString(attr
->value_tag
)));
1836 DEBUG_puts("1_ppdCacheGetPageSize: Did not find media attribute.");
1839 if (attr
&& (attr
->value_tag
== IPP_TAG_NAME
||
1840 attr
->value_tag
== IPP_TAG_KEYWORD
))
1841 ppd_name
= attr
->values
[0].string
.text
;
1844 DEBUG_printf(("1_ppdCacheGetPageSize: ppd_name=\"%s\"", ppd_name
));
1849 * Try looking up the named PPD size first...
1852 for (i
= pc
->num_sizes
, size
= pc
->sizes
; i
> 0; i
--, size
++)
1854 DEBUG_printf(("2_ppdCacheGetPageSize: size[%d]=[\"%s\" \"%s\"]",
1855 (int)(size
- pc
->sizes
), size
->map
.pwg
, size
->map
.ppd
));
1857 if (!_cups_strcasecmp(ppd_name
, size
->map
.ppd
) ||
1858 !_cups_strcasecmp(ppd_name
, size
->map
.pwg
))
1863 DEBUG_printf(("1_ppdCacheGetPageSize: Returning \"%s\"", ppd_name
));
1865 return (size
->map
.ppd
);
1870 if (job
&& !keyword
)
1873 * Get the size using media-col or media, with the preference being
1877 if (!_pwgInitSize(&jobsize
, job
, &margins_set
))
1883 * Get the size using a media keyword...
1886 _pwg_media_t
*media
; /* Media definition */
1889 if ((media
= _pwgMediaForPWG(keyword
)) == NULL
)
1890 if ((media
= _pwgMediaForLegacy(keyword
)) == NULL
)
1891 if ((media
= _pwgMediaForPPD(keyword
)) == NULL
)
1894 jobsize
.width
= media
->width
;
1895 jobsize
.length
= media
->length
;
1900 * Now that we have the dimensions and possibly the margins, look at the
1901 * available sizes and find the match...
1905 dclosest
= 999999999;
1907 if (!ppd_name
|| _cups_strncasecmp(ppd_name
, "Custom.", 7) ||
1908 _cups_strncasecmp(ppd_name
, "custom_", 7))
1910 for (i
= pc
->num_sizes
, size
= pc
->sizes
; i
> 0; i
--, size
++)
1913 * Adobe uses a size matching algorithm with an epsilon of 5 points, which
1914 * is just about 176/2540ths...
1917 dwidth
= size
->width
- jobsize
.width
;
1918 dlength
= size
->length
- jobsize
.length
;
1920 if (dwidth
<= -176 || dwidth
>= 176 || dlength
<= -176 || dlength
>= 176)
1926 * Use a tighter epsilon of 1 point (35/2540ths) for margins...
1929 dleft
= size
->left
- jobsize
.left
;
1930 dright
= size
->right
- jobsize
.right
;
1931 dtop
= size
->top
- jobsize
.top
;
1932 dbottom
= size
->bottom
- jobsize
.bottom
;
1934 if (dleft
<= -35 || dleft
>= 35 || dright
<= -35 || dright
>= 35 ||
1935 dtop
<= -35 || dtop
>= 35 || dbottom
<= -35 || dbottom
>= 35)
1937 dleft
= dleft
< 0 ? -dleft
: dleft
;
1938 dright
= dright
< 0 ? -dright
: dright
;
1939 dbottom
= dbottom
< 0 ? -dbottom
: dbottom
;
1940 dtop
= dtop
< 0 ? -dtop
: dtop
;
1941 dmin
= dleft
+ dright
+ dbottom
+ dtop
;
1943 if (dmin
< dclosest
)
1956 DEBUG_printf(("1_ppdCacheGetPageSize: Returning \"%s\"", size
->map
.ppd
));
1958 return (size
->map
.ppd
);
1964 DEBUG_printf(("1_ppdCacheGetPageSize: Returning \"%s\" (closest)",
1967 return (closest
->map
.ppd
);
1971 * If we get here we need to check for custom page size support...
1974 if (jobsize
.width
>= pc
->custom_min_width
&&
1975 jobsize
.width
<= pc
->custom_max_width
&&
1976 jobsize
.length
>= pc
->custom_min_length
&&
1977 jobsize
.length
<= pc
->custom_max_length
)
1980 * In range, format as Custom.WWWWxLLLL (points).
1983 snprintf(pc
->custom_ppd_size
, sizeof(pc
->custom_ppd_size
), "Custom.%dx%d",
1984 (int)_PWG_TOPTS(jobsize
.width
), (int)_PWG_TOPTS(jobsize
.length
));
1986 if (margins_set
&& exact
)
1988 dleft
= pc
->custom_size
.left
- jobsize
.left
;
1989 dright
= pc
->custom_size
.right
- jobsize
.right
;
1990 dtop
= pc
->custom_size
.top
- jobsize
.top
;
1991 dbottom
= pc
->custom_size
.bottom
- jobsize
.bottom
;
1993 if (dleft
> -35 && dleft
< 35 && dright
> -35 && dright
< 35 &&
1994 dtop
> -35 && dtop
< 35 && dbottom
> -35 && dbottom
< 35)
2000 DEBUG_printf(("1_ppdCacheGetPageSize: Returning \"%s\" (custom)",
2001 pc
->custom_ppd_size
));
2003 return (pc
->custom_ppd_size
);
2007 * No custom page size support or the size is out of range - return NULL.
2010 DEBUG_puts("1_ppdCacheGetPageSize: Returning NULL");
2017 * '_ppdCacheGetSize()' - Get the PWG size associated with a PPD PageSize.
2020 _pwg_size_t
* /* O - PWG size or NULL */
2022 _ppd_cache_t
*pc
, /* I - PPD cache and mapping data */
2023 const char *page_size
) /* I - PPD PageSize */
2025 int i
; /* Looping var */
2026 _pwg_media_t
*media
; /* Media */
2027 _pwg_size_t
*size
; /* Current size */
2031 * Range check input...
2034 if (!pc
|| !page_size
)
2037 if (!_cups_strncasecmp(page_size
, "Custom.", 7))
2040 * Custom size; size name can be one of the following:
2042 * Custom.WIDTHxLENGTHin - Size in inches
2043 * Custom.WIDTHxLENGTHft - Size in feet
2044 * Custom.WIDTHxLENGTHcm - Size in centimeters
2045 * Custom.WIDTHxLENGTHmm - Size in millimeters
2046 * Custom.WIDTHxLENGTHm - Size in meters
2047 * Custom.WIDTHxLENGTH[pt] - Size in points
2050 double w
, l
; /* Width and length of page */
2051 char *ptr
; /* Pointer into PageSize */
2052 struct lconv
*loc
; /* Locale data */
2055 w
= (float)_cupsStrScand(page_size
+ 7, &ptr
, loc
);
2056 if (!ptr
|| *ptr
!= 'x')
2059 l
= (float)_cupsStrScand(ptr
+ 1, &ptr
, loc
);
2063 if (!_cups_strcasecmp(ptr
, "in"))
2068 else if (!_cups_strcasecmp(ptr
, "ft"))
2073 else if (!_cups_strcasecmp(ptr
, "mm"))
2078 else if (!_cups_strcasecmp(ptr
, "cm"))
2083 else if (!_cups_strcasecmp(ptr
, "m"))
2094 pc
->custom_size
.width
= (int)w
;
2095 pc
->custom_size
.length
= (int)l
;
2097 return (&(pc
->custom_size
));
2101 * Not a custom size - look it up...
2104 for (i
= pc
->num_sizes
, size
= pc
->sizes
; i
> 0; i
--, size
++)
2105 if (!_cups_strcasecmp(page_size
, size
->map
.ppd
) ||
2106 !_cups_strcasecmp(page_size
, size
->map
.pwg
))
2110 * Look up standard sizes...
2113 if ((media
= _pwgMediaForPPD(page_size
)) == NULL
)
2114 if ((media
= _pwgMediaForLegacy(page_size
)) == NULL
)
2115 media
= _pwgMediaForPWG(page_size
);
2119 pc
->custom_size
.width
= media
->width
;
2120 pc
->custom_size
.length
= media
->length
;
2122 return (&(pc
->custom_size
));
2130 * '_ppdCacheGetSource()' - Get the PWG media-source associated with a PPD
2134 const char * /* O - PWG media-source keyword */
2136 _ppd_cache_t
*pc
, /* I - PPD cache and mapping data */
2137 const char *input_slot
) /* I - PPD InputSlot */
2139 int i
; /* Looping var */
2140 _pwg_map_t
*source
; /* Current source */
2144 * Range check input...
2147 if (!pc
|| !input_slot
)
2150 for (i
= pc
->num_sources
, source
= pc
->sources
; i
> 0; i
--, source
++)
2151 if (!_cups_strcasecmp(input_slot
, source
->ppd
))
2152 return (source
->pwg
);
2159 * '_ppdCacheGetType()' - Get the PWG media-type associated with a PPD
2163 const char * /* O - PWG media-type keyword */
2165 _ppd_cache_t
*pc
, /* I - PPD cache and mapping data */
2166 const char *media_type
) /* I - PPD MediaType */
2168 int i
; /* Looping var */
2169 _pwg_map_t
*type
; /* Current type */
2173 * Range check input...
2176 if (!pc
|| !media_type
)
2179 for (i
= pc
->num_types
, type
= pc
->types
; i
> 0; i
--, type
++)
2180 if (!_cups_strcasecmp(media_type
, type
->ppd
))
2188 * '_ppdCacheWriteFile()' - Write PWG mapping data to a file.
2191 int /* O - 1 on success, 0 on failure */
2193 _ppd_cache_t
*pc
, /* I - PPD cache and mapping data */
2194 const char *filename
, /* I - File to write */
2195 ipp_t
*attrs
) /* I - Attributes to write, if any */
2197 int i
, j
, k
; /* Looping vars */
2198 cups_file_t
*fp
; /* Output file */
2199 _pwg_size_t
*size
; /* Current size */
2200 _pwg_map_t
*map
; /* Current map */
2201 _pwg_finishings_t
*f
; /* Current finishing option */
2202 cups_option_t
*option
; /* Current option */
2203 const char *value
; /* Filter/pre-filter value */
2204 char newfile
[1024]; /* New filename */
2208 * Range check input...
2211 if (!pc
|| !filename
)
2213 _cupsSetError(IPP_INTERNAL_ERROR
, strerror(EINVAL
), 0);
2218 * Open the file and write with compression...
2221 snprintf(newfile
, sizeof(newfile
), "%s.N", filename
);
2222 if ((fp
= cupsFileOpen(newfile
, "w9")) == NULL
)
2224 _cupsSetError(IPP_INTERNAL_ERROR
, strerror(errno
), 0);
2229 * Standard header...
2232 cupsFilePrintf(fp
, "#CUPS-PPD-CACHE-%d\n", _PPD_CACHE_VERSION
);
2238 if (pc
->num_bins
> 0)
2240 cupsFilePrintf(fp
, "NumBins %d\n", pc
->num_bins
);
2241 for (i
= pc
->num_bins
, map
= pc
->bins
; i
> 0; i
--, map
++)
2242 cupsFilePrintf(fp
, "Bin %s %s\n", map
->pwg
, map
->ppd
);
2249 cupsFilePrintf(fp
, "NumSizes %d\n", pc
->num_sizes
);
2250 for (i
= pc
->num_sizes
, size
= pc
->sizes
; i
> 0; i
--, size
++)
2251 cupsFilePrintf(fp
, "Size %s %s %d %d %d %d %d %d\n", size
->map
.pwg
,
2252 size
->map
.ppd
, size
->width
, size
->length
, size
->left
,
2253 size
->bottom
, size
->right
, size
->top
);
2254 if (pc
->custom_max_width
> 0)
2255 cupsFilePrintf(fp
, "CustomSize %d %d %d %d %d %d %d %d\n",
2256 pc
->custom_max_width
, pc
->custom_max_length
,
2257 pc
->custom_min_width
, pc
->custom_min_length
,
2258 pc
->custom_size
.left
, pc
->custom_size
.bottom
,
2259 pc
->custom_size
.right
, pc
->custom_size
.top
);
2265 if (pc
->source_option
)
2266 cupsFilePrintf(fp
, "SourceOption %s\n", pc
->source_option
);
2268 if (pc
->num_sources
> 0)
2270 cupsFilePrintf(fp
, "NumSources %d\n", pc
->num_sources
);
2271 for (i
= pc
->num_sources
, map
= pc
->sources
; i
> 0; i
--, map
++)
2272 cupsFilePrintf(fp
, "Source %s %s\n", map
->pwg
, map
->ppd
);
2279 if (pc
->num_types
> 0)
2281 cupsFilePrintf(fp
, "NumTypes %d\n", pc
->num_types
);
2282 for (i
= pc
->num_types
, map
= pc
->types
; i
> 0; i
--, map
++)
2283 cupsFilePrintf(fp
, "Type %s %s\n", map
->pwg
, map
->ppd
);
2290 for (i
= _PWG_PRINT_COLOR_MODE_MONOCHROME
; i
< _PWG_PRINT_COLOR_MODE_MAX
; i
++)
2291 for (j
= _PWG_PRINT_QUALITY_DRAFT
; j
< _PWG_PRINT_QUALITY_MAX
; j
++)
2292 if (pc
->num_presets
[i
][j
])
2294 cupsFilePrintf(fp
, "Preset %d %d", i
, j
);
2295 for (k
= pc
->num_presets
[i
][j
], option
= pc
->presets
[i
][j
];
2298 cupsFilePrintf(fp
, " %s=%s", option
->name
, option
->value
);
2299 cupsFilePutChar(fp
, '\n');
2306 if (pc
->sides_option
)
2307 cupsFilePrintf(fp
, "SidesOption %s\n", pc
->sides_option
);
2309 if (pc
->sides_1sided
)
2310 cupsFilePrintf(fp
, "Sides1Sided %s\n", pc
->sides_1sided
);
2312 if (pc
->sides_2sided_long
)
2313 cupsFilePrintf(fp
, "Sides2SidedLong %s\n", pc
->sides_2sided_long
);
2315 if (pc
->sides_2sided_short
)
2316 cupsFilePrintf(fp
, "Sides2SidedShort %s\n", pc
->sides_2sided_short
);
2319 * Product, cupsFilter, cupsFilter2, and cupsPreFilter...
2323 cupsFilePutConf(fp
, "Product", pc
->product
);
2325 for (value
= (const char *)cupsArrayFirst(pc
->filters
);
2327 value
= (const char *)cupsArrayNext(pc
->filters
))
2328 cupsFilePutConf(fp
, "Filter", value
);
2330 for (value
= (const char *)cupsArrayFirst(pc
->prefilters
);
2332 value
= (const char *)cupsArrayNext(pc
->prefilters
))
2333 cupsFilePutConf(fp
, "PreFilter", value
);
2335 cupsFilePrintf(fp
, "SingleFile %s\n", pc
->single_file
? "true" : "false");
2338 * Finishing options...
2341 for (f
= (_pwg_finishings_t
*)cupsArrayFirst(pc
->finishings
);
2343 f
= (_pwg_finishings_t
*)cupsArrayNext(pc
->finishings
))
2345 cupsFilePrintf(fp
, "Finishings %d", f
->value
);
2346 for (i
= f
->num_options
, option
= f
->options
; i
> 0; i
--, option
++)
2347 cupsFilePrintf(fp
, " %s=%s", option
->name
, option
->value
);
2348 cupsFilePutChar(fp
, '\n');
2355 cupsFilePrintf(fp
, "MaxCopies %d\n", pc
->max_copies
);
2358 * IPP attributes, if any...
2363 cupsFilePrintf(fp
, "IPP " CUPS_LLFMT
"\n", CUPS_LLCAST
ippLength(attrs
));
2365 attrs
->state
= IPP_IDLE
;
2366 ippWriteIO(fp
, (ipp_iocb_t
)cupsFileWrite
, 1, NULL
, attrs
);
2370 * Close and return...
2373 if (cupsFileClose(fp
))
2380 return (!rename(newfile
, filename
));
2385 * '_pwgInputSlotForSource()' - Get the InputSlot name for the given PWG
2389 const char * /* O - InputSlot name */
2390 _pwgInputSlotForSource(
2391 const char *media_source
, /* I - PWG media-source */
2392 char *name
, /* I - Name buffer */
2393 size_t namesize
) /* I - Size of name buffer */
2396 * Range check input...
2399 if (!media_source
|| !name
|| namesize
< PPD_MAX_NAME
)
2402 if (_cups_strcasecmp(media_source
, "main"))
2403 strlcpy(name
, "Cassette", namesize
);
2404 else if (_cups_strcasecmp(media_source
, "alternate"))
2405 strlcpy(name
, "Multipurpose", namesize
);
2406 else if (_cups_strcasecmp(media_source
, "large-capacity"))
2407 strlcpy(name
, "LargeCapacity", namesize
);
2408 else if (_cups_strcasecmp(media_source
, "bottom"))
2409 strlcpy(name
, "Lower", namesize
);
2410 else if (_cups_strcasecmp(media_source
, "middle"))
2411 strlcpy(name
, "Middle", namesize
);
2412 else if (_cups_strcasecmp(media_source
, "top"))
2413 strlcpy(name
, "Upper", namesize
);
2414 else if (_cups_strcasecmp(media_source
, "rear"))
2415 strlcpy(name
, "Rear", namesize
);
2416 else if (_cups_strcasecmp(media_source
, "side"))
2417 strlcpy(name
, "Side", namesize
);
2418 else if (_cups_strcasecmp(media_source
, "envelope"))
2419 strlcpy(name
, "Envelope", namesize
);
2420 else if (_cups_strcasecmp(media_source
, "main-roll"))
2421 strlcpy(name
, "Roll", namesize
);
2422 else if (_cups_strcasecmp(media_source
, "alternate-roll"))
2423 strlcpy(name
, "Roll2", namesize
);
2425 pwg_ppdize_name(media_source
, name
, namesize
);
2432 * '_pwgMediaTypeForType()' - Get the MediaType name for the given PWG
2436 const char * /* O - MediaType name */
2437 _pwgMediaTypeForType(
2438 const char *media_type
, /* I - PWG media-type */
2439 char *name
, /* I - Name buffer */
2440 size_t namesize
) /* I - Size of name buffer */
2443 * Range check input...
2446 if (!media_type
|| !name
|| namesize
< PPD_MAX_NAME
)
2449 if (_cups_strcasecmp(media_type
, "auto"))
2450 strlcpy(name
, "Auto", namesize
);
2451 else if (_cups_strcasecmp(media_type
, "cardstock"))
2452 strlcpy(name
, "Cardstock", namesize
);
2453 else if (_cups_strcasecmp(media_type
, "envelope"))
2454 strlcpy(name
, "Envelope", namesize
);
2455 else if (_cups_strcasecmp(media_type
, "photographic-glossy"))
2456 strlcpy(name
, "Glossy", namesize
);
2457 else if (_cups_strcasecmp(media_type
, "photographic-high-gloss"))
2458 strlcpy(name
, "HighGloss", namesize
);
2459 else if (_cups_strcasecmp(media_type
, "photographic-matte"))
2460 strlcpy(name
, "Matte", namesize
);
2461 else if (_cups_strcasecmp(media_type
, "stationery"))
2462 strlcpy(name
, "Plain", namesize
);
2463 else if (_cups_strcasecmp(media_type
, "stationery-coated"))
2464 strlcpy(name
, "Coated", namesize
);
2465 else if (_cups_strcasecmp(media_type
, "stationery-inkjet"))
2466 strlcpy(name
, "Inkjet", namesize
);
2467 else if (_cups_strcasecmp(media_type
, "stationery-letterhead"))
2468 strlcpy(name
, "Letterhead", namesize
);
2469 else if (_cups_strcasecmp(media_type
, "stationery-preprinted"))
2470 strlcpy(name
, "Preprinted", namesize
);
2471 else if (_cups_strcasecmp(media_type
, "transparency"))
2472 strlcpy(name
, "Transparency", namesize
);
2474 pwg_ppdize_name(media_type
, name
, namesize
);
2481 * '_pwgPageSizeForMedia()' - Get the PageSize name for the given media.
2484 const char * /* O - PageSize name */
2485 _pwgPageSizeForMedia(
2486 _pwg_media_t
*media
, /* I - Media */
2487 char *name
, /* I - PageSize name buffer */
2488 size_t namesize
) /* I - Size of name buffer */
2490 const char *sizeptr
, /* Pointer to size in PWG name */
2491 *dimptr
; /* Pointer to dimensions in PWG name */
2495 * Range check input...
2498 if (!media
|| !name
|| namesize
< PPD_MAX_NAME
)
2502 * Copy or generate a PageSize name...
2508 * Use a standard Adobe name...
2511 strlcpy(name
, media
->ppd
, namesize
);
2513 else if (!media
->pwg
|| !strncmp(media
->pwg
, "custom_", 7) ||
2514 (sizeptr
= strchr(media
->pwg
, '_')) == NULL
||
2515 (dimptr
= strchr(sizeptr
+ 1, '_')) == NULL
||
2516 (size_t)(dimptr
- sizeptr
) > namesize
)
2519 * Use a name of the form "wNNNhNNN"...
2522 snprintf(name
, namesize
, "w%dh%d", (int)_PWG_TOPTS(media
->width
),
2523 (int)_PWG_TOPTS(media
->length
));
2528 * Copy the size name from class_sizename_dimensions...
2531 memcpy(name
, sizeptr
+ 1, dimptr
- sizeptr
- 1);
2532 name
[dimptr
- sizeptr
- 1] = '\0';
2540 * 'pwg_compare_finishings()' - Compare two finishings values.
2543 static int /* O- Result of comparison */
2544 pwg_compare_finishings(
2545 _pwg_finishings_t
*a
, /* I - First finishings value */
2546 _pwg_finishings_t
*b
) /* I - Second finishings value */
2548 return (b
->value
- a
->value
);
2553 * 'pwg_free_finishings()' - Free a finishings value.
2557 pwg_free_finishings(
2558 _pwg_finishings_t
*f
) /* I - Finishings value */
2560 cupsFreeOptions(f
->num_options
, f
->options
);
2566 * 'pwg_ppdize_name()' - Convert an IPP keyword to a PPD keyword.
2570 pwg_ppdize_name(const char *ipp
, /* I - IPP keyword */
2571 char *name
, /* I - Name buffer */
2572 size_t namesize
) /* I - Size of name buffer */
2574 char *ptr
, /* Pointer into name buffer */
2575 *end
; /* End of name buffer */
2578 *name
= toupper(*ipp
++);
2580 for (ptr
= name
+ 1, end
= name
+ namesize
- 1; *ipp
&& ptr
< end
;)
2582 if (*ipp
== '-' && _cups_isalpha(ipp
[1]))
2585 *ptr
++ = toupper(*ipp
++ & 255);
2596 * 'pwg_unppdize_name()' - Convert a PPD keyword to a lowercase IPP keyword.
2600 pwg_unppdize_name(const char *ppd
, /* I - PPD keyword */
2601 char *name
, /* I - Name buffer */
2602 size_t namesize
) /* I - Size of name buffer */
2604 char *ptr
, /* Pointer into name buffer */
2605 *end
; /* End of name buffer */
2608 for (ptr
= name
, end
= name
+ namesize
- 1; *ppd
&& ptr
< end
; ppd
++)
2610 if (_cups_isalnum(*ppd
) || *ppd
== '-')
2611 *ptr
++ = tolower(*ppd
& 255);
2612 else if (*ppd
== '_' || *ppd
== '.')
2615 if (!_cups_isupper(*ppd
) && _cups_isalnum(*ppd
) &&
2616 _cups_isupper(ppd
[1]) && ptr
< end
)