2 * PPD cache implementation for CUPS.
4 * Copyright 2010-2017 by Apple Inc.
6 * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
10 * Include necessary headers...
13 #include "cups-private.h"
14 #include "ppd-private.h"
19 * Macro to test for two almost-equal PWG measurements.
22 #define _PWG_EQUIVALENT(x, y) (abs((x)-(y)) < 2)
29 static int cups_get_url(http_t
**http
, const char *url
, char *name
, size_t namesize
);
30 static void pwg_add_finishing(cups_array_t
*finishings
, ipp_finishings_t
template, const char *name
, const char *value
);
31 static int pwg_compare_finishings(_pwg_finishings_t
*a
, _pwg_finishings_t
*b
);
32 static int pwg_compare_sizes(cups_size_t
*a
, cups_size_t
*b
);
33 static cups_size_t
*pwg_copy_size(cups_size_t
*size
);
34 static void pwg_free_finishings(_pwg_finishings_t
*f
);
35 static void pwg_ppdize_name(const char *ipp
, char *name
, size_t namesize
);
36 static void pwg_ppdize_resolution(ipp_attribute_t
*attr
, int element
, int *xres
, int *yres
, char *name
, size_t namesize
);
37 static void pwg_unppdize_name(const char *ppd
, char *name
, size_t namesize
,
38 const char *dashchars
);
42 * '_cupsConvertOptions()' - Convert printer options to standard IPP attributes.
44 * This functions converts PPD and CUPS-specific options to their standard IPP
45 * attributes and values and adds them to the specified IPP request.
48 int /* O - New number of copies */
50 ipp_t
*request
, /* I - IPP request */
51 ppd_file_t
*ppd
, /* I - PPD file */
52 _ppd_cache_t
*pc
, /* I - PPD cache info */
53 ipp_attribute_t
*media_col_sup
, /* I - media-col-supported values */
54 ipp_attribute_t
*doc_handling_sup
, /* I - multiple-document-handling-supported values */
55 ipp_attribute_t
*print_color_mode_sup
,
56 /* I - Printer supports print-color-mode */
57 const char *user
, /* I - User info */
58 const char *format
, /* I - document-format value */
59 int copies
, /* I - Number of copies */
60 int num_options
, /* I - Number of options */
61 cups_option_t
*options
) /* I - Options */
63 int i
; /* Looping var */
64 const char *keyword
, /* PWG keyword */
65 *password
; /* Password string */
66 pwg_size_t
*size
; /* PWG media size */
67 ipp_t
*media_col
, /* media-col value */
68 *media_size
; /* media-size value */
69 const char *media_source
, /* media-source value */
70 *media_type
, /* media-type value */
71 *collate_str
, /* multiple-document-handling value */
72 *color_attr_name
, /* Supported color attribute */
73 *mandatory
, /* Mandatory attributes */
74 *finishing_template
; /* Finishing template */
75 int num_finishings
= 0, /* Number of finishing values */
76 finishings
[10]; /* Finishing enum values */
77 ppd_choice_t
*choice
; /* Marked choice */
78 int finishings_copies
= copies
;
79 /* Number of copies for finishings */
83 * Send standard IPP attributes...
86 if (pc
->password
&& (password
= cupsGetOption("job-password", num_options
, options
)) != NULL
&& ippGetOperation(request
) != IPP_OP_VALIDATE_JOB
)
88 ipp_attribute_t
*attr
= NULL
; /* job-password attribute */
90 if ((keyword
= cupsGetOption("job-password-encryption", num_options
, options
)) == NULL
)
93 if (!strcmp(keyword
, "none"))
96 * Add plain-text job-password...
99 attr
= ippAddOctetString(request
, IPP_TAG_OPERATION
, "job-password", password
, (int)strlen(password
));
104 * Add hashed job-password...
107 unsigned char hash
[64]; /* Hash of password */
108 ssize_t hashlen
; /* Length of hash */
110 if ((hashlen
= cupsHashData(keyword
, password
, strlen(password
), hash
, sizeof(hash
))) > 0)
111 attr
= ippAddOctetString(request
, IPP_TAG_OPERATION
, "job-password", hash
, (int)hashlen
);
115 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
, "job-password-encryption", NULL
, keyword
);
120 if ((keyword
= cupsGetOption("job-account-id", num_options
, options
)) == NULL
)
121 keyword
= cupsGetOption("job-billing", num_options
, options
);
124 ippAddString(request
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-account-id", NULL
, keyword
);
127 if (pc
->accounting_user_id
)
129 if ((keyword
= cupsGetOption("job-accounting-user-id", num_options
, options
)) == NULL
)
133 ippAddString(request
, IPP_TAG_JOB
, IPP_TAG_NAME
, "job-accounting-user-id", NULL
, keyword
);
136 for (mandatory
= (const char *)cupsArrayFirst(pc
->mandatory
); mandatory
; mandatory
= (const char *)cupsArrayNext(pc
->mandatory
))
138 if (strcmp(mandatory
, "copies") &&
139 strcmp(mandatory
, "destination-uris") &&
140 strcmp(mandatory
, "finishings") &&
141 strcmp(mandatory
, "finishings-col") &&
142 strcmp(mandatory
, "finishing-template") &&
143 strcmp(mandatory
, "job-account-id") &&
144 strcmp(mandatory
, "job-accounting-user-id") &&
145 strcmp(mandatory
, "job-password") &&
146 strcmp(mandatory
, "job-password-encryption") &&
147 strcmp(mandatory
, "media") &&
148 strncmp(mandatory
, "media-col", 9) &&
149 strcmp(mandatory
, "multiple-document-handling") &&
150 strcmp(mandatory
, "output-bin") &&
151 strcmp(mandatory
, "print-color-mode") &&
152 strcmp(mandatory
, "print-quality") &&
153 strcmp(mandatory
, "sides") &&
154 (keyword
= cupsGetOption(mandatory
, num_options
, options
)) != NULL
)
156 _ipp_option_t
*opt
= _ippFindOption(mandatory
);
158 ipp_tag_t value_tag
= opt
? opt
->value_tag
: IPP_TAG_NAME
;
163 case IPP_TAG_INTEGER
:
165 ippAddInteger(request
, IPP_TAG_JOB
, value_tag
, mandatory
, atoi(keyword
));
167 case IPP_TAG_BOOLEAN
:
168 ippAddBoolean(request
, IPP_TAG_JOB
, mandatory
, !_cups_strcasecmp(keyword
, "true"));
172 int lower
, upper
; /* Range */
174 if (sscanf(keyword
, "%d-%d", &lower
, &upper
) != 2)
175 lower
= upper
= atoi(keyword
);
177 ippAddRange(request
, IPP_TAG_JOB
, mandatory
, lower
, upper
);
180 case IPP_TAG_STRING
:
181 ippAddOctetString(request
, IPP_TAG_JOB
, mandatory
, keyword
, (int)strlen(keyword
));
184 if (!strcmp(mandatory
, "print-color-mode") && !strcmp(keyword
, "monochrome"))
186 if (ippContainsString(print_color_mode_sup
, "auto-monochrome"))
187 keyword
= "auto-monochrome";
188 else if (ippContainsString(print_color_mode_sup
, "process-monochrome") && !ippContainsString(print_color_mode_sup
, "monochrome"))
189 keyword
= "process-monochrome";
192 ippAddString(request
, IPP_TAG_JOB
, value_tag
, mandatory
, NULL
, keyword
);
198 if ((keyword
= cupsGetOption("PageSize", num_options
, options
)) == NULL
)
199 keyword
= cupsGetOption("media", num_options
, options
);
201 media_source
= _ppdCacheGetSource(pc
, cupsGetOption("InputSlot", num_options
, options
));
202 media_type
= _ppdCacheGetType(pc
, cupsGetOption("MediaType", num_options
, options
));
203 size
= _ppdCacheGetSize(pc
, keyword
);
205 if (size
|| media_source
|| media_type
)
208 * Add a media-col value...
211 media_col
= ippNew();
215 media_size
= ippNew();
216 ippAddInteger(media_size
, IPP_TAG_ZERO
, IPP_TAG_INTEGER
,
217 "x-dimension", size
->width
);
218 ippAddInteger(media_size
, IPP_TAG_ZERO
, IPP_TAG_INTEGER
,
219 "y-dimension", size
->length
);
221 ippAddCollection(media_col
, IPP_TAG_ZERO
, "media-size", media_size
);
224 for (i
= 0; i
< media_col_sup
->num_values
; i
++)
226 if (size
&& !strcmp(media_col_sup
->values
[i
].string
.text
, "media-left-margin"))
227 ippAddInteger(media_col
, IPP_TAG_ZERO
, IPP_TAG_INTEGER
, "media-left-margin", size
->left
);
228 else if (size
&& !strcmp(media_col_sup
->values
[i
].string
.text
, "media-bottom-margin"))
229 ippAddInteger(media_col
, IPP_TAG_ZERO
, IPP_TAG_INTEGER
, "media-bottom-margin", size
->bottom
);
230 else if (size
&& !strcmp(media_col_sup
->values
[i
].string
.text
, "media-right-margin"))
231 ippAddInteger(media_col
, IPP_TAG_ZERO
, IPP_TAG_INTEGER
, "media-right-margin", size
->right
);
232 else if (size
&& !strcmp(media_col_sup
->values
[i
].string
.text
, "media-top-margin"))
233 ippAddInteger(media_col
, IPP_TAG_ZERO
, IPP_TAG_INTEGER
, "media-top-margin", size
->top
);
234 else if (media_source
&& !strcmp(media_col_sup
->values
[i
].string
.text
, "media-source"))
235 ippAddString(media_col
, IPP_TAG_ZERO
, IPP_TAG_KEYWORD
, "media-source", NULL
, media_source
);
236 else if (media_type
&& !strcmp(media_col_sup
->values
[i
].string
.text
, "media-type"))
237 ippAddString(media_col
, IPP_TAG_ZERO
, IPP_TAG_KEYWORD
, "media-type", NULL
, media_type
);
240 ippAddCollection(request
, IPP_TAG_JOB
, "media-col", media_col
);
243 if ((keyword
= cupsGetOption("output-bin", num_options
, options
)) == NULL
)
245 if ((choice
= ppdFindMarkedChoice(ppd
, "OutputBin")) != NULL
)
246 keyword
= _ppdCacheGetBin(pc
, choice
->choice
);
250 ippAddString(request
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
, "output-bin", NULL
, keyword
);
252 color_attr_name
= print_color_mode_sup
? "print-color-mode" : "output-mode";
254 if ((keyword
= cupsGetOption("print-color-mode", num_options
, options
)) == NULL
)
256 if ((choice
= ppdFindMarkedChoice(ppd
, "ColorModel")) != NULL
)
258 if (!_cups_strcasecmp(choice
->choice
, "Gray"))
259 keyword
= "monochrome";
265 if (keyword
&& !strcmp(keyword
, "monochrome"))
267 if (ippContainsString(print_color_mode_sup
, "auto-monochrome"))
268 keyword
= "auto-monochrome";
269 else if (ippContainsString(print_color_mode_sup
, "process-monochrome") && !ippContainsString(print_color_mode_sup
, "monochrome"))
270 keyword
= "process-monochrome";
274 ippAddString(request
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
, color_attr_name
, NULL
, keyword
);
276 if ((keyword
= cupsGetOption("print-quality", num_options
, options
)) != NULL
)
277 ippAddInteger(request
, IPP_TAG_JOB
, IPP_TAG_ENUM
, "print-quality", atoi(keyword
));
278 else if ((choice
= ppdFindMarkedChoice(ppd
, "cupsPrintQuality")) != NULL
)
280 if (!_cups_strcasecmp(choice
->choice
, "draft"))
281 ippAddInteger(request
, IPP_TAG_JOB
, IPP_TAG_ENUM
, "print-quality", IPP_QUALITY_DRAFT
);
282 else if (!_cups_strcasecmp(choice
->choice
, "normal"))
283 ippAddInteger(request
, IPP_TAG_JOB
, IPP_TAG_ENUM
, "print-quality", IPP_QUALITY_NORMAL
);
284 else if (!_cups_strcasecmp(choice
->choice
, "high"))
285 ippAddInteger(request
, IPP_TAG_JOB
, IPP_TAG_ENUM
, "print-quality", IPP_QUALITY_HIGH
);
288 if ((keyword
= cupsGetOption("sides", num_options
, options
)) != NULL
)
289 ippAddString(request
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
, "sides", NULL
, keyword
);
290 else if (pc
->sides_option
&& (choice
= ppdFindMarkedChoice(ppd
, pc
->sides_option
)) != NULL
)
292 if (!_cups_strcasecmp(choice
->choice
, pc
->sides_1sided
))
293 ippAddString(request
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
, "sides", NULL
, "one-sided");
294 else if (!_cups_strcasecmp(choice
->choice
, pc
->sides_2sided_long
))
295 ippAddString(request
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
, "sides", NULL
, "two-sided-long-edge");
296 if (!_cups_strcasecmp(choice
->choice
, pc
->sides_2sided_short
))
297 ippAddString(request
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
, "sides", NULL
, "two-sided-short-edge");
304 if ((keyword
= cupsGetOption("multiple-document-handling", num_options
, options
)) != NULL
)
306 if (strstr(keyword
, "uncollated"))
311 else if ((keyword
= cupsGetOption("collate", num_options
, options
)) == NULL
)
316 if (!_cups_strcasecmp(format
, "image/gif") ||
317 !_cups_strcasecmp(format
, "image/jp2") ||
318 !_cups_strcasecmp(format
, "image/jpeg") ||
319 !_cups_strcasecmp(format
, "image/png") ||
320 !_cups_strcasecmp(format
, "image/tiff") ||
321 !_cups_strncasecmp(format
, "image/x-", 8))
324 * Collation makes no sense for single page image formats...
329 else if (!_cups_strncasecmp(format
, "image/", 6) ||
330 !_cups_strcasecmp(format
, "application/vnd.cups-raster"))
333 * Multi-page image formats will have copies applied by the upstream
341 if (doc_handling_sup
)
343 if (!_cups_strcasecmp(keyword
, "true"))
344 collate_str
= "separate-documents-collated-copies";
346 collate_str
= "separate-documents-uncollated-copies";
348 for (i
= 0; i
< doc_handling_sup
->num_values
; i
++)
350 if (!strcmp(doc_handling_sup
->values
[i
].string
.text
, collate_str
))
352 ippAddString(request
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
, "multiple-document-handling", NULL
, collate_str
);
357 if (i
>= doc_handling_sup
->num_values
)
362 * Map finishing options...
365 if ((finishing_template
= cupsGetOption("cupsFinishingTemplate", num_options
, options
)) == NULL
)
366 finishing_template
= cupsGetOption("finishing-template", num_options
, options
);
368 if (finishing_template
)
370 ipp_t
*fin_col
= ippNew(); /* finishings-col value */
372 ippAddString(fin_col
, IPP_TAG_JOB
, IPP_TAG_KEYWORD
, "finishing-template", NULL
, finishing_template
);
373 ippAddCollection(request
, IPP_TAG_JOB
, "finishings-col", fin_col
);
376 if (copies
!= finishings_copies
&& (keyword
= cupsGetOption("job-impressions", num_options
, options
)) != NULL
)
379 * Send job-pages-per-set attribute to apply finishings correctly...
382 ippAddInteger(request
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-pages-per-set", atoi(keyword
) / finishings_copies
);
387 num_finishings
= _ppdCacheGetFinishingValues(pc
, num_options
, options
, (int)(sizeof(finishings
) / sizeof(finishings
[0])), finishings
);
388 if (num_finishings
> 0)
390 ippAddIntegers(request
, IPP_TAG_JOB
, IPP_TAG_ENUM
, "finishings", num_finishings
, finishings
);
392 if (copies
!= finishings_copies
&& (keyword
= cupsGetOption("job-impressions", num_options
, options
)) != NULL
)
395 * Send job-pages-per-set attribute to apply finishings correctly...
398 ippAddInteger(request
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-pages-per-set", atoi(keyword
) / finishings_copies
);
408 * '_ppdCacheCreateWithFile()' - Create PPD cache and mapping data from a
411 * Use the @link _ppdCacheWriteFile@ function to write PWG mapping data to a
415 _ppd_cache_t
* /* O - PPD cache and mapping data */
416 _ppdCacheCreateWithFile(
417 const char *filename
, /* I - File to read */
418 ipp_t
**attrs
) /* IO - IPP attributes, if any */
420 cups_file_t
*fp
; /* File */
421 _ppd_cache_t
*pc
; /* PWG mapping data */
422 pwg_size_t
*size
; /* Current size */
423 pwg_map_t
*map
; /* Current map */
424 _pwg_finishings_t
*finishings
; /* Current finishings option */
425 int linenum
, /* Current line number */
426 num_bins
, /* Number of bins in file */
427 num_sizes
, /* Number of sizes in file */
428 num_sources
, /* Number of sources in file */
429 num_types
; /* Number of types in file */
430 char line
[2048], /* Current line */
431 *value
, /* Pointer to value in line */
432 *valueptr
, /* Pointer into value */
433 pwg_keyword
[128], /* PWG keyword */
434 ppd_keyword
[PPD_MAX_NAME
];
436 _pwg_print_color_mode_t print_color_mode
;
437 /* Print color mode for preset */
438 _pwg_print_quality_t print_quality
; /* Print quality for preset */
441 DEBUG_printf(("_ppdCacheCreateWithFile(filename=\"%s\")", filename
));
444 * Range check input...
452 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(EINVAL
), 0);
460 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
462 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(errno
), 0);
467 * Read the first line and make sure it has "#CUPS-PPD-CACHE-version" in it...
470 if (!cupsFileGets(fp
, line
, sizeof(line
)))
472 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(errno
), 0);
473 DEBUG_puts("_ppdCacheCreateWithFile: Unable to read first line.");
478 if (strncmp(line
, "#CUPS-PPD-CACHE-", 16))
480 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Bad PPD cache file."), 1);
481 DEBUG_printf(("_ppdCacheCreateWithFile: Wrong first line \"%s\".", line
));
486 if (atoi(line
+ 16) != _PPD_CACHE_VERSION
)
488 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Out of date PPD cache file."), 1);
489 DEBUG_printf(("_ppdCacheCreateWithFile: Cache file has version %s, "
490 "expected %d.", line
+ 16, _PPD_CACHE_VERSION
));
496 * Allocate the mapping data structure...
499 if ((pc
= calloc(1, sizeof(_ppd_cache_t
))) == NULL
)
501 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(errno
), 0);
502 DEBUG_puts("_ppdCacheCreateWithFile: Unable to allocate _ppd_cache_t.");
506 pc
->max_copies
= 9999;
518 while (cupsFileGetConf(fp
, line
, sizeof(line
), &value
, &linenum
))
520 DEBUG_printf(("_ppdCacheCreateWithFile: line=\"%s\", value=\"%s\", "
521 "linenum=%d", line
, value
, linenum
));
525 DEBUG_printf(("_ppdCacheCreateWithFile: Missing value on line %d.",
527 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Bad PPD cache file."), 1);
530 else if (!_cups_strcasecmp(line
, "Filter"))
533 pc
->filters
= cupsArrayNew3(NULL
, NULL
, NULL
, 0,
534 (cups_acopy_func_t
)_cupsStrAlloc
,
535 (cups_afree_func_t
)_cupsStrFree
);
537 cupsArrayAdd(pc
->filters
, value
);
539 else if (!_cups_strcasecmp(line
, "PreFilter"))
542 pc
->prefilters
= cupsArrayNew3(NULL
, NULL
, NULL
, 0,
543 (cups_acopy_func_t
)_cupsStrAlloc
,
544 (cups_afree_func_t
)_cupsStrFree
);
546 cupsArrayAdd(pc
->prefilters
, value
);
548 else if (!_cups_strcasecmp(line
, "Product"))
550 pc
->product
= _cupsStrAlloc(value
);
552 else if (!_cups_strcasecmp(line
, "SingleFile"))
554 pc
->single_file
= !_cups_strcasecmp(value
, "true");
556 else if (!_cups_strcasecmp(line
, "IPP"))
558 off_t pos
= cupsFileTell(fp
), /* Position in file */
559 length
= strtol(value
, NULL
, 10);
560 /* Length of IPP attributes */
564 DEBUG_puts("_ppdCacheCreateWithFile: IPP listed multiple times.");
565 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Bad PPD cache file."), 1);
568 else if (length
<= 0)
570 DEBUG_puts("_ppdCacheCreateWithFile: Bad IPP length.");
571 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Bad PPD cache file."), 1);
578 * Read IPP attributes into the provided variable...
583 if (ippReadIO(fp
, (ipp_iocb_t
)cupsFileRead
, 1, NULL
,
584 *attrs
) != IPP_STATE_DATA
)
586 DEBUG_puts("_ppdCacheCreateWithFile: Bad IPP data.");
587 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Bad PPD cache file."), 1);
594 * Skip the IPP data entirely...
597 cupsFileSeek(fp
, pos
+ length
);
600 if (cupsFileTell(fp
) != (pos
+ length
))
602 DEBUG_puts("_ppdCacheCreateWithFile: Bad IPP data.");
603 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Bad PPD cache file."), 1);
607 else if (!_cups_strcasecmp(line
, "NumBins"))
611 DEBUG_puts("_ppdCacheCreateWithFile: NumBins listed multiple times.");
612 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Bad PPD cache file."), 1);
616 if ((num_bins
= atoi(value
)) <= 0 || num_bins
> 65536)
618 DEBUG_printf(("_ppdCacheCreateWithFile: Bad NumBins value %d on line "
619 "%d.", num_sizes
, linenum
));
620 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Bad PPD cache file."), 1);
624 if ((pc
->bins
= calloc((size_t)num_bins
, sizeof(pwg_map_t
))) == NULL
)
626 DEBUG_printf(("_ppdCacheCreateWithFile: Unable to allocate %d bins.",
628 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(errno
), 0);
632 else if (!_cups_strcasecmp(line
, "Bin"))
634 if (sscanf(value
, "%127s%40s", pwg_keyword
, ppd_keyword
) != 2)
636 DEBUG_printf(("_ppdCacheCreateWithFile: Bad Bin on line %d.", linenum
));
637 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Bad PPD cache file."), 1);
641 if (pc
->num_bins
>= num_bins
)
643 DEBUG_printf(("_ppdCacheCreateWithFile: Too many Bin's on line %d.",
645 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Bad PPD cache file."), 1);
649 map
= pc
->bins
+ pc
->num_bins
;
650 map
->pwg
= _cupsStrAlloc(pwg_keyword
);
651 map
->ppd
= _cupsStrAlloc(ppd_keyword
);
655 else if (!_cups_strcasecmp(line
, "NumSizes"))
659 DEBUG_puts("_ppdCacheCreateWithFile: NumSizes listed multiple times.");
660 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Bad PPD cache file."), 1);
664 if ((num_sizes
= atoi(value
)) < 0 || num_sizes
> 65536)
666 DEBUG_printf(("_ppdCacheCreateWithFile: Bad NumSizes value %d on line "
667 "%d.", num_sizes
, linenum
));
668 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Bad PPD cache file."), 1);
674 if ((pc
->sizes
= calloc((size_t)num_sizes
, sizeof(pwg_size_t
))) == NULL
)
676 DEBUG_printf(("_ppdCacheCreateWithFile: Unable to allocate %d sizes.",
678 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(errno
), 0);
683 else if (!_cups_strcasecmp(line
, "Size"))
685 if (pc
->num_sizes
>= num_sizes
)
687 DEBUG_printf(("_ppdCacheCreateWithFile: Too many Size's on line %d.",
689 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Bad PPD cache file."), 1);
693 size
= pc
->sizes
+ pc
->num_sizes
;
695 if (sscanf(value
, "%127s%40s%d%d%d%d%d%d", pwg_keyword
, ppd_keyword
,
696 &(size
->width
), &(size
->length
), &(size
->left
),
697 &(size
->bottom
), &(size
->right
), &(size
->top
)) != 8)
699 DEBUG_printf(("_ppdCacheCreateWithFile: Bad Size on line %d.",
701 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Bad PPD cache file."), 1);
705 size
->map
.pwg
= _cupsStrAlloc(pwg_keyword
);
706 size
->map
.ppd
= _cupsStrAlloc(ppd_keyword
);
710 else if (!_cups_strcasecmp(line
, "CustomSize"))
712 if (pc
->custom_max_width
> 0)
714 DEBUG_printf(("_ppdCacheCreateWithFile: Too many CustomSize's on line "
716 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Bad PPD cache file."), 1);
720 if (sscanf(value
, "%d%d%d%d%d%d%d%d", &(pc
->custom_max_width
),
721 &(pc
->custom_max_length
), &(pc
->custom_min_width
),
722 &(pc
->custom_min_length
), &(pc
->custom_size
.left
),
723 &(pc
->custom_size
.bottom
), &(pc
->custom_size
.right
),
724 &(pc
->custom_size
.top
)) != 8)
726 DEBUG_printf(("_ppdCacheCreateWithFile: Bad CustomSize on line %d.",
728 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Bad PPD cache file."), 1);
732 pwgFormatSizeName(pwg_keyword
, sizeof(pwg_keyword
), "custom", "max",
733 pc
->custom_max_width
, pc
->custom_max_length
, NULL
);
734 pc
->custom_max_keyword
= _cupsStrAlloc(pwg_keyword
);
736 pwgFormatSizeName(pwg_keyword
, sizeof(pwg_keyword
), "custom", "min",
737 pc
->custom_min_width
, pc
->custom_min_length
, NULL
);
738 pc
->custom_min_keyword
= _cupsStrAlloc(pwg_keyword
);
740 else if (!_cups_strcasecmp(line
, "SourceOption"))
742 pc
->source_option
= _cupsStrAlloc(value
);
744 else if (!_cups_strcasecmp(line
, "NumSources"))
748 DEBUG_puts("_ppdCacheCreateWithFile: NumSources listed multiple "
750 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Bad PPD cache file."), 1);
754 if ((num_sources
= atoi(value
)) <= 0 || num_sources
> 65536)
756 DEBUG_printf(("_ppdCacheCreateWithFile: Bad NumSources value %d on "
757 "line %d.", num_sources
, linenum
));
758 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Bad PPD cache file."), 1);
762 if ((pc
->sources
= calloc((size_t)num_sources
, sizeof(pwg_map_t
))) == NULL
)
764 DEBUG_printf(("_ppdCacheCreateWithFile: Unable to allocate %d sources.",
766 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(errno
), 0);
770 else if (!_cups_strcasecmp(line
, "Source"))
772 if (sscanf(value
, "%127s%40s", pwg_keyword
, ppd_keyword
) != 2)
774 DEBUG_printf(("_ppdCacheCreateWithFile: Bad Source on line %d.",
776 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Bad PPD cache file."), 1);
780 if (pc
->num_sources
>= num_sources
)
782 DEBUG_printf(("_ppdCacheCreateWithFile: Too many Source's on line %d.",
784 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Bad PPD cache file."), 1);
788 map
= pc
->sources
+ pc
->num_sources
;
789 map
->pwg
= _cupsStrAlloc(pwg_keyword
);
790 map
->ppd
= _cupsStrAlloc(ppd_keyword
);
794 else if (!_cups_strcasecmp(line
, "NumTypes"))
798 DEBUG_puts("_ppdCacheCreateWithFile: NumTypes listed multiple times.");
799 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Bad PPD cache file."), 1);
803 if ((num_types
= atoi(value
)) <= 0 || num_types
> 65536)
805 DEBUG_printf(("_ppdCacheCreateWithFile: Bad NumTypes value %d on "
806 "line %d.", num_types
, linenum
));
807 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Bad PPD cache file."), 1);
811 if ((pc
->types
= calloc((size_t)num_types
, sizeof(pwg_map_t
))) == NULL
)
813 DEBUG_printf(("_ppdCacheCreateWithFile: Unable to allocate %d types.",
815 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(errno
), 0);
819 else if (!_cups_strcasecmp(line
, "Type"))
821 if (sscanf(value
, "%127s%40s", pwg_keyword
, ppd_keyword
) != 2)
823 DEBUG_printf(("_ppdCacheCreateWithFile: Bad Type on line %d.",
825 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Bad PPD cache file."), 1);
829 if (pc
->num_types
>= num_types
)
831 DEBUG_printf(("_ppdCacheCreateWithFile: Too many Type's on line %d.",
833 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Bad PPD cache file."), 1);
837 map
= pc
->types
+ pc
->num_types
;
838 map
->pwg
= _cupsStrAlloc(pwg_keyword
);
839 map
->ppd
= _cupsStrAlloc(ppd_keyword
);
843 else if (!_cups_strcasecmp(line
, "Preset"))
846 * Preset output-mode print-quality name=value ...
849 print_color_mode
= (_pwg_print_color_mode_t
)strtol(value
, &valueptr
, 10);
850 print_quality
= (_pwg_print_quality_t
)strtol(valueptr
, &valueptr
, 10);
852 if (print_color_mode
< _PWG_PRINT_COLOR_MODE_MONOCHROME
||
853 print_color_mode
>= _PWG_PRINT_COLOR_MODE_MAX
||
854 print_quality
< _PWG_PRINT_QUALITY_DRAFT
||
855 print_quality
>= _PWG_PRINT_QUALITY_MAX
||
856 valueptr
== value
|| !*valueptr
)
858 DEBUG_printf(("_ppdCacheCreateWithFile: Bad Preset on line %d.",
860 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Bad PPD cache file."), 1);
864 pc
->num_presets
[print_color_mode
][print_quality
] =
865 cupsParseOptions(valueptr
, 0,
866 pc
->presets
[print_color_mode
] + print_quality
);
868 else if (!_cups_strcasecmp(line
, "SidesOption"))
869 pc
->sides_option
= _cupsStrAlloc(value
);
870 else if (!_cups_strcasecmp(line
, "Sides1Sided"))
871 pc
->sides_1sided
= _cupsStrAlloc(value
);
872 else if (!_cups_strcasecmp(line
, "Sides2SidedLong"))
873 pc
->sides_2sided_long
= _cupsStrAlloc(value
);
874 else if (!_cups_strcasecmp(line
, "Sides2SidedShort"))
875 pc
->sides_2sided_short
= _cupsStrAlloc(value
);
876 else if (!_cups_strcasecmp(line
, "Finishings"))
880 cupsArrayNew3((cups_array_func_t
)pwg_compare_finishings
,
882 (cups_afree_func_t
)pwg_free_finishings
);
884 if ((finishings
= calloc(1, sizeof(_pwg_finishings_t
))) == NULL
)
887 finishings
->value
= (ipp_finishings_t
)strtol(value
, &valueptr
, 10);
888 finishings
->num_options
= cupsParseOptions(valueptr
, 0,
889 &(finishings
->options
));
891 cupsArrayAdd(pc
->finishings
, finishings
);
893 else if (!_cups_strcasecmp(line
, "FinishingTemplate"))
896 pc
->templates
= cupsArrayNew3((cups_array_func_t
)strcmp
, NULL
, NULL
, 0, (cups_acopy_func_t
)_cupsStrAlloc
, (cups_afree_func_t
)_cupsStrFree
);
898 cupsArrayAdd(pc
->templates
, value
);
900 else if (!_cups_strcasecmp(line
, "MaxCopies"))
901 pc
->max_copies
= atoi(value
);
902 else if (!_cups_strcasecmp(line
, "ChargeInfoURI"))
903 pc
->charge_info_uri
= _cupsStrAlloc(value
);
904 else if (!_cups_strcasecmp(line
, "JobAccountId"))
905 pc
->account_id
= !_cups_strcasecmp(value
, "true");
906 else if (!_cups_strcasecmp(line
, "JobAccountingUserId"))
907 pc
->accounting_user_id
= !_cups_strcasecmp(value
, "true");
908 else if (!_cups_strcasecmp(line
, "JobPassword"))
909 pc
->password
= _cupsStrAlloc(value
);
910 else if (!_cups_strcasecmp(line
, "Mandatory"))
913 _cupsArrayAddStrings(pc
->mandatory
, value
, ' ');
915 pc
->mandatory
= _cupsArrayNewStrings(value
, ' ');
917 else if (!_cups_strcasecmp(line
, "StringsURI"))
918 pc
->strings_uri
= _cupsStrAlloc(value
);
919 else if (!_cups_strcasecmp(line
, "SupportFile"))
921 if (!pc
->support_files
)
922 pc
->support_files
= cupsArrayNew3(NULL
, NULL
, NULL
, 0,
923 (cups_acopy_func_t
)_cupsStrAlloc
,
924 (cups_afree_func_t
)_cupsStrFree
);
926 cupsArrayAdd(pc
->support_files
, value
);
930 DEBUG_printf(("_ppdCacheCreateWithFile: Unknown %s on line %d.", line
,
935 if (pc
->num_sizes
< num_sizes
)
937 DEBUG_printf(("_ppdCacheCreateWithFile: Not enough sizes (%d < %d).",
938 pc
->num_sizes
, num_sizes
));
939 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Bad PPD cache file."), 1);
943 if (pc
->num_sources
< num_sources
)
945 DEBUG_printf(("_ppdCacheCreateWithFile: Not enough sources (%d < %d).",
946 pc
->num_sources
, num_sources
));
947 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Bad PPD cache file."), 1);
951 if (pc
->num_types
< num_types
)
953 DEBUG_printf(("_ppdCacheCreateWithFile: Not enough types (%d < %d).",
954 pc
->num_types
, num_types
));
955 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Bad PPD cache file."), 1);
964 * If we get here the file was bad - free any data and return...
970 _ppdCacheDestroy(pc
);
983 * '_ppdCacheCreateWithPPD()' - Create PWG mapping data from a PPD file.
986 _ppd_cache_t
* /* O - PPD cache and mapping data */
987 _ppdCacheCreateWithPPD(ppd_file_t
*ppd
) /* I - PPD file */
989 int i
, j
, k
; /* Looping vars */
990 _ppd_cache_t
*pc
; /* PWG mapping data */
991 ppd_option_t
*input_slot
, /* InputSlot option */
992 *media_type
, /* MediaType option */
993 *output_bin
, /* OutputBin option */
994 *color_model
, /* ColorModel option */
995 *duplex
, /* Duplex option */
996 *ppd_option
; /* Other PPD option */
997 ppd_choice_t
*choice
; /* Current InputSlot/MediaType */
998 pwg_map_t
*map
; /* Current source/type map */
999 ppd_attr_t
*ppd_attr
; /* Current PPD preset attribute */
1000 int num_options
; /* Number of preset options and props */
1001 cups_option_t
*options
; /* Preset options and properties */
1002 ppd_size_t
*ppd_size
; /* Current PPD size */
1003 pwg_size_t
*pwg_size
; /* Current PWG size */
1004 char pwg_keyword
[3 + PPD_MAX_NAME
+ 1 + 12 + 1 + 12 + 3],
1005 /* PWG keyword string */
1006 ppd_name
[PPD_MAX_NAME
];
1007 /* Normalized PPD name */
1008 const char *pwg_name
; /* Standard PWG media name */
1009 pwg_media_t
*pwg_media
; /* PWG media data */
1010 _pwg_print_color_mode_t pwg_print_color_mode
;
1011 /* print-color-mode index */
1012 _pwg_print_quality_t pwg_print_quality
;
1013 /* print-quality index */
1014 int similar
; /* Are the old and new size similar? */
1015 pwg_size_t
*old_size
; /* Current old size */
1016 int old_imageable
, /* Old imageable length in 2540ths */
1017 old_borderless
, /* Old borderless state */
1018 old_known_pwg
; /* Old PWG name is well-known */
1019 int new_width
, /* New width in 2540ths */
1020 new_length
, /* New length in 2540ths */
1021 new_left
, /* New left margin in 2540ths */
1022 new_bottom
, /* New bottom margin in 2540ths */
1023 new_right
, /* New right margin in 2540ths */
1024 new_top
, /* New top margin in 2540ths */
1025 new_imageable
, /* New imageable length in 2540ths */
1026 new_borderless
, /* New borderless state */
1027 new_known_pwg
; /* New PWG name is well-known */
1028 pwg_size_t
*new_size
; /* New size to add, if any */
1029 const char *filter
; /* Current filter */
1030 _pwg_finishings_t
*finishings
; /* Current finishings value */
1033 DEBUG_printf(("_ppdCacheCreateWithPPD(ppd=%p)", ppd
));
1036 * Range check input...
1043 * Allocate memory...
1046 if ((pc
= calloc(1, sizeof(_ppd_cache_t
))) == NULL
)
1048 DEBUG_puts("_ppdCacheCreateWithPPD: Unable to allocate _ppd_cache_t.");
1053 * Copy and convert size data...
1056 if (ppd
->num_sizes
> 0)
1058 if ((pc
->sizes
= calloc((size_t)ppd
->num_sizes
, sizeof(pwg_size_t
))) == NULL
)
1060 DEBUG_printf(("_ppdCacheCreateWithPPD: Unable to allocate %d "
1061 "pwg_size_t's.", ppd
->num_sizes
));
1065 for (i
= ppd
->num_sizes
, pwg_size
= pc
->sizes
, ppd_size
= ppd
->sizes
;
1070 * Don't copy over custom size...
1073 if (!_cups_strcasecmp(ppd_size
->name
, "Custom"))
1077 * Convert the PPD size name to the corresponding PWG keyword name.
1080 if ((pwg_media
= pwgMediaForPPD(ppd_size
->name
)) != NULL
)
1083 * Standard name, do we have conflicts?
1086 for (j
= 0; j
< pc
->num_sizes
; j
++)
1087 if (!strcmp(pc
->sizes
[j
].map
.pwg
, pwg_media
->pwg
))
1097 * Standard name and no conflicts, use it!
1100 pwg_name
= pwg_media
->pwg
;
1106 * Not a standard name; convert it to a PWG vendor name of the form:
1108 * pp_lowerppd_WIDTHxHEIGHTuu
1111 pwg_name
= pwg_keyword
;
1114 pwg_unppdize_name(ppd_size
->name
, ppd_name
, sizeof(ppd_name
), "_.");
1115 pwgFormatSizeName(pwg_keyword
, sizeof(pwg_keyword
), NULL
, ppd_name
,
1116 PWG_FROM_POINTS(ppd_size
->width
),
1117 PWG_FROM_POINTS(ppd_size
->length
), NULL
);
1121 * If we have a similar paper with non-zero margins then we only want to
1122 * keep it if it has a larger imageable area length. The NULL check is for
1123 * dimensions that are <= 0...
1126 if ((pwg_media
= _pwgMediaNearSize(PWG_FROM_POINTS(ppd_size
->width
),
1127 PWG_FROM_POINTS(ppd_size
->length
),
1131 new_width
= pwg_media
->width
;
1132 new_length
= pwg_media
->length
;
1133 new_left
= PWG_FROM_POINTS(ppd_size
->left
);
1134 new_bottom
= PWG_FROM_POINTS(ppd_size
->bottom
);
1135 new_right
= PWG_FROM_POINTS(ppd_size
->width
- ppd_size
->right
);
1136 new_top
= PWG_FROM_POINTS(ppd_size
->length
- ppd_size
->top
);
1137 new_imageable
= new_length
- new_top
- new_bottom
;
1138 new_borderless
= new_bottom
== 0 && new_top
== 0 &&
1139 new_left
== 0 && new_right
== 0;
1141 for (k
= pc
->num_sizes
, similar
= 0, old_size
= pc
->sizes
, new_size
= NULL
;
1145 old_imageable
= old_size
->length
- old_size
->top
- old_size
->bottom
;
1146 old_borderless
= old_size
->left
== 0 && old_size
->bottom
== 0 &&
1147 old_size
->right
== 0 && old_size
->top
== 0;
1148 old_known_pwg
= strncmp(old_size
->map
.pwg
, "oe_", 3) &&
1149 strncmp(old_size
->map
.pwg
, "om_", 3);
1151 similar
= old_borderless
== new_borderless
&&
1152 _PWG_EQUIVALENT(old_size
->width
, new_width
) &&
1153 _PWG_EQUIVALENT(old_size
->length
, new_length
);
1156 (new_known_pwg
|| (!old_known_pwg
&& new_imageable
> old_imageable
)))
1159 * The new paper has a larger imageable area so it could replace
1160 * the older paper. Regardless of the imageable area, we always
1161 * prefer the size with a well-known PWG name.
1164 new_size
= old_size
;
1165 _cupsStrFree(old_size
->map
.ppd
);
1166 _cupsStrFree(old_size
->map
.pwg
);
1173 * The paper was unique enough to deserve its own entry so add it to the
1177 new_size
= pwg_size
++;
1187 new_size
->map
.ppd
= _cupsStrAlloc(ppd_size
->name
);
1188 new_size
->map
.pwg
= _cupsStrAlloc(pwg_name
);
1189 new_size
->width
= new_width
;
1190 new_size
->length
= new_length
;
1191 new_size
->left
= new_left
;
1192 new_size
->bottom
= new_bottom
;
1193 new_size
->right
= new_right
;
1194 new_size
->top
= new_top
;
1199 if (ppd
->variable_sizes
)
1202 * Generate custom size data...
1205 pwgFormatSizeName(pwg_keyword
, sizeof(pwg_keyword
), "custom", "max",
1206 PWG_FROM_POINTS(ppd
->custom_max
[0]),
1207 PWG_FROM_POINTS(ppd
->custom_max
[1]), NULL
);
1208 pc
->custom_max_keyword
= _cupsStrAlloc(pwg_keyword
);
1209 pc
->custom_max_width
= PWG_FROM_POINTS(ppd
->custom_max
[0]);
1210 pc
->custom_max_length
= PWG_FROM_POINTS(ppd
->custom_max
[1]);
1212 pwgFormatSizeName(pwg_keyword
, sizeof(pwg_keyword
), "custom", "min",
1213 PWG_FROM_POINTS(ppd
->custom_min
[0]),
1214 PWG_FROM_POINTS(ppd
->custom_min
[1]), NULL
);
1215 pc
->custom_min_keyword
= _cupsStrAlloc(pwg_keyword
);
1216 pc
->custom_min_width
= PWG_FROM_POINTS(ppd
->custom_min
[0]);
1217 pc
->custom_min_length
= PWG_FROM_POINTS(ppd
->custom_min
[1]);
1219 pc
->custom_size
.left
= PWG_FROM_POINTS(ppd
->custom_margins
[0]);
1220 pc
->custom_size
.bottom
= PWG_FROM_POINTS(ppd
->custom_margins
[1]);
1221 pc
->custom_size
.right
= PWG_FROM_POINTS(ppd
->custom_margins
[2]);
1222 pc
->custom_size
.top
= PWG_FROM_POINTS(ppd
->custom_margins
[3]);
1226 * Copy and convert InputSlot data...
1229 if ((input_slot
= ppdFindOption(ppd
, "InputSlot")) == NULL
)
1230 input_slot
= ppdFindOption(ppd
, "HPPaperSource");
1234 pc
->source_option
= _cupsStrAlloc(input_slot
->keyword
);
1236 if ((pc
->sources
= calloc((size_t)input_slot
->num_choices
, sizeof(pwg_map_t
))) == NULL
)
1238 DEBUG_printf(("_ppdCacheCreateWithPPD: Unable to allocate %d "
1239 "pwg_map_t's for InputSlot.", input_slot
->num_choices
));
1243 pc
->num_sources
= input_slot
->num_choices
;
1245 for (i
= input_slot
->num_choices
, choice
= input_slot
->choices
,
1248 i
--, choice
++, map
++)
1250 if (!_cups_strncasecmp(choice
->choice
, "Auto", 4) ||
1251 !_cups_strcasecmp(choice
->choice
, "Default"))
1253 else if (!_cups_strcasecmp(choice
->choice
, "Cassette"))
1255 else if (!_cups_strcasecmp(choice
->choice
, "PhotoTray"))
1257 else if (!_cups_strcasecmp(choice
->choice
, "CDTray"))
1259 else if (!_cups_strncasecmp(choice
->choice
, "Multipurpose", 12) ||
1260 !_cups_strcasecmp(choice
->choice
, "MP") ||
1261 !_cups_strcasecmp(choice
->choice
, "MPTray"))
1262 pwg_name
= "by-pass-tray";
1263 else if (!_cups_strcasecmp(choice
->choice
, "LargeCapacity"))
1264 pwg_name
= "large-capacity";
1265 else if (!_cups_strncasecmp(choice
->choice
, "Lower", 5))
1266 pwg_name
= "bottom";
1267 else if (!_cups_strncasecmp(choice
->choice
, "Middle", 6))
1268 pwg_name
= "middle";
1269 else if (!_cups_strncasecmp(choice
->choice
, "Upper", 5))
1271 else if (!_cups_strncasecmp(choice
->choice
, "Side", 4))
1273 else if (!_cups_strcasecmp(choice
->choice
, "Roll"))
1274 pwg_name
= "main-roll";
1278 * Convert PPD name to lowercase...
1281 pwg_name
= pwg_keyword
;
1282 pwg_unppdize_name(choice
->choice
, pwg_keyword
, sizeof(pwg_keyword
),
1286 map
->pwg
= _cupsStrAlloc(pwg_name
);
1287 map
->ppd
= _cupsStrAlloc(choice
->choice
);
1292 * Copy and convert MediaType data...
1295 if ((media_type
= ppdFindOption(ppd
, "MediaType")) != NULL
)
1297 if ((pc
->types
= calloc((size_t)media_type
->num_choices
, sizeof(pwg_map_t
))) == NULL
)
1299 DEBUG_printf(("_ppdCacheCreateWithPPD: Unable to allocate %d "
1300 "pwg_map_t's for MediaType.", media_type
->num_choices
));
1304 pc
->num_types
= media_type
->num_choices
;
1306 for (i
= media_type
->num_choices
, choice
= media_type
->choices
,
1309 i
--, choice
++, map
++)
1311 if (!_cups_strncasecmp(choice
->choice
, "Auto", 4) ||
1312 !_cups_strcasecmp(choice
->choice
, "Any") ||
1313 !_cups_strcasecmp(choice
->choice
, "Default"))
1315 else if (!_cups_strncasecmp(choice
->choice
, "Card", 4))
1316 pwg_name
= "cardstock";
1317 else if (!_cups_strncasecmp(choice
->choice
, "Env", 3))
1318 pwg_name
= "envelope";
1319 else if (!_cups_strncasecmp(choice
->choice
, "Gloss", 5))
1320 pwg_name
= "photographic-glossy";
1321 else if (!_cups_strcasecmp(choice
->choice
, "HighGloss"))
1322 pwg_name
= "photographic-high-gloss";
1323 else if (!_cups_strcasecmp(choice
->choice
, "Matte"))
1324 pwg_name
= "photographic-matte";
1325 else if (!_cups_strncasecmp(choice
->choice
, "Plain", 5))
1326 pwg_name
= "stationery";
1327 else if (!_cups_strncasecmp(choice
->choice
, "Coated", 6))
1328 pwg_name
= "stationery-coated";
1329 else if (!_cups_strcasecmp(choice
->choice
, "Inkjet"))
1330 pwg_name
= "stationery-inkjet";
1331 else if (!_cups_strcasecmp(choice
->choice
, "Letterhead"))
1332 pwg_name
= "stationery-letterhead";
1333 else if (!_cups_strncasecmp(choice
->choice
, "Preprint", 8))
1334 pwg_name
= "stationery-preprinted";
1335 else if (!_cups_strcasecmp(choice
->choice
, "Recycled"))
1336 pwg_name
= "stationery-recycled";
1337 else if (!_cups_strncasecmp(choice
->choice
, "Transparen", 10))
1338 pwg_name
= "transparency";
1342 * Convert PPD name to lowercase...
1345 pwg_name
= pwg_keyword
;
1346 pwg_unppdize_name(choice
->choice
, pwg_keyword
, sizeof(pwg_keyword
),
1350 map
->pwg
= _cupsStrAlloc(pwg_name
);
1351 map
->ppd
= _cupsStrAlloc(choice
->choice
);
1356 * Copy and convert OutputBin data...
1359 if ((output_bin
= ppdFindOption(ppd
, "OutputBin")) != NULL
)
1361 if ((pc
->bins
= calloc((size_t)output_bin
->num_choices
, sizeof(pwg_map_t
))) == NULL
)
1363 DEBUG_printf(("_ppdCacheCreateWithPPD: Unable to allocate %d "
1364 "pwg_map_t's for OutputBin.", output_bin
->num_choices
));
1368 pc
->num_bins
= output_bin
->num_choices
;
1370 for (i
= output_bin
->num_choices
, choice
= output_bin
->choices
,
1373 i
--, choice
++, map
++)
1375 pwg_unppdize_name(choice
->choice
, pwg_keyword
, sizeof(pwg_keyword
), "_");
1377 map
->pwg
= _cupsStrAlloc(pwg_keyword
);
1378 map
->ppd
= _cupsStrAlloc(choice
->choice
);
1382 if ((ppd_attr
= ppdFindAttr(ppd
, "APPrinterPreset", NULL
)) != NULL
)
1385 * Copy and convert APPrinterPreset (output-mode + print-quality) data...
1388 const char *quality
, /* com.apple.print.preset.quality value */
1389 *output_mode
, /* com.apple.print.preset.output-mode value */
1390 *color_model_val
, /* ColorModel choice */
1391 *graphicsType
, /* com.apple.print.preset.graphicsType value */
1392 *media_front_coating
; /* com.apple.print.preset.media-front-coating value */
1396 num_options
= _ppdParseOptions(ppd_attr
->value
, 0, &options
,
1399 if ((quality
= cupsGetOption("com.apple.print.preset.quality",
1400 num_options
, options
)) != NULL
)
1403 * Get the print-quality for this preset...
1406 if (!strcmp(quality
, "low"))
1407 pwg_print_quality
= _PWG_PRINT_QUALITY_DRAFT
;
1408 else if (!strcmp(quality
, "high"))
1409 pwg_print_quality
= _PWG_PRINT_QUALITY_HIGH
;
1411 pwg_print_quality
= _PWG_PRINT_QUALITY_NORMAL
;
1414 * Ignore graphicsType "Photo" presets that are not high quality.
1417 graphicsType
= cupsGetOption("com.apple.print.preset.graphicsType",
1418 num_options
, options
);
1420 if (pwg_print_quality
!= _PWG_PRINT_QUALITY_HIGH
&& graphicsType
&&
1421 !strcmp(graphicsType
, "Photo"))
1425 * Ignore presets for normal and draft quality where the coating
1426 * isn't "none" or "autodetect".
1429 media_front_coating
= cupsGetOption(
1430 "com.apple.print.preset.media-front-coating",
1431 num_options
, options
);
1433 if (pwg_print_quality
!= _PWG_PRINT_QUALITY_HIGH
&&
1434 media_front_coating
&&
1435 strcmp(media_front_coating
, "none") &&
1436 strcmp(media_front_coating
, "autodetect"))
1440 * Get the output mode for this preset...
1443 output_mode
= cupsGetOption("com.apple.print.preset.output-mode",
1444 num_options
, options
);
1445 color_model_val
= cupsGetOption("ColorModel", num_options
, options
);
1449 if (!strcmp(output_mode
, "monochrome"))
1450 pwg_print_color_mode
= _PWG_PRINT_COLOR_MODE_MONOCHROME
;
1452 pwg_print_color_mode
= _PWG_PRINT_COLOR_MODE_COLOR
;
1454 else if (color_model_val
)
1456 if (!_cups_strcasecmp(color_model_val
, "Gray"))
1457 pwg_print_color_mode
= _PWG_PRINT_COLOR_MODE_MONOCHROME
;
1459 pwg_print_color_mode
= _PWG_PRINT_COLOR_MODE_COLOR
;
1462 pwg_print_color_mode
= _PWG_PRINT_COLOR_MODE_COLOR
;
1465 * Save the options for this combination as needed...
1468 if (!pc
->num_presets
[pwg_print_color_mode
][pwg_print_quality
])
1469 pc
->num_presets
[pwg_print_color_mode
][pwg_print_quality
] =
1470 _ppdParseOptions(ppd_attr
->value
, 0,
1471 pc
->presets
[pwg_print_color_mode
] +
1472 pwg_print_quality
, _PPD_PARSE_OPTIONS
);
1475 cupsFreeOptions(num_options
, options
);
1477 while ((ppd_attr
= ppdFindNextAttr(ppd
, "APPrinterPreset", NULL
)) != NULL
);
1480 if (!pc
->num_presets
[_PWG_PRINT_COLOR_MODE_MONOCHROME
][_PWG_PRINT_QUALITY_DRAFT
] &&
1481 !pc
->num_presets
[_PWG_PRINT_COLOR_MODE_MONOCHROME
][_PWG_PRINT_QUALITY_NORMAL
] &&
1482 !pc
->num_presets
[_PWG_PRINT_COLOR_MODE_MONOCHROME
][_PWG_PRINT_QUALITY_HIGH
])
1485 * Try adding some common color options to create grayscale presets. These
1486 * are listed in order of popularity...
1489 const char *color_option
= NULL
, /* Color control option */
1490 *gray_choice
= NULL
; /* Choice to select grayscale */
1492 if ((color_model
= ppdFindOption(ppd
, "ColorModel")) != NULL
&&
1493 ppdFindChoice(color_model
, "Gray"))
1495 color_option
= "ColorModel";
1496 gray_choice
= "Gray";
1498 else if ((color_model
= ppdFindOption(ppd
, "HPColorMode")) != NULL
&&
1499 ppdFindChoice(color_model
, "grayscale"))
1501 color_option
= "HPColorMode";
1502 gray_choice
= "grayscale";
1504 else if ((color_model
= ppdFindOption(ppd
, "BRMonoColor")) != NULL
&&
1505 ppdFindChoice(color_model
, "Mono"))
1507 color_option
= "BRMonoColor";
1508 gray_choice
= "Mono";
1510 else if ((color_model
= ppdFindOption(ppd
, "CNIJSGrayScale")) != NULL
&&
1511 ppdFindChoice(color_model
, "1"))
1513 color_option
= "CNIJSGrayScale";
1516 else if ((color_model
= ppdFindOption(ppd
, "HPColorAsGray")) != NULL
&&
1517 ppdFindChoice(color_model
, "True"))
1519 color_option
= "HPColorAsGray";
1520 gray_choice
= "True";
1523 if (color_option
&& gray_choice
)
1526 * Copy and convert ColorModel (output-mode) data...
1529 cups_option_t
*coption
, /* Color option */
1530 *moption
; /* Monochrome option */
1532 for (pwg_print_quality
= _PWG_PRINT_QUALITY_DRAFT
;
1533 pwg_print_quality
< _PWG_PRINT_QUALITY_MAX
;
1534 pwg_print_quality
++)
1536 if (pc
->num_presets
[_PWG_PRINT_COLOR_MODE_COLOR
][pwg_print_quality
])
1539 * Copy the color options...
1542 num_options
= pc
->num_presets
[_PWG_PRINT_COLOR_MODE_COLOR
]
1543 [pwg_print_quality
];
1544 options
= calloc(sizeof(cups_option_t
), (size_t)num_options
);
1548 for (i
= num_options
, moption
= options
,
1549 coption
= pc
->presets
[_PWG_PRINT_COLOR_MODE_COLOR
]
1550 [pwg_print_quality
];
1552 i
--, moption
++, coption
++)
1554 moption
->name
= _cupsStrRetain(coption
->name
);
1555 moption
->value
= _cupsStrRetain(coption
->value
);
1558 pc
->num_presets
[_PWG_PRINT_COLOR_MODE_MONOCHROME
][pwg_print_quality
] =
1560 pc
->presets
[_PWG_PRINT_COLOR_MODE_MONOCHROME
][pwg_print_quality
] =
1564 else if (pwg_print_quality
!= _PWG_PRINT_QUALITY_NORMAL
)
1568 * Add the grayscale option to the preset...
1571 pc
->num_presets
[_PWG_PRINT_COLOR_MODE_MONOCHROME
][pwg_print_quality
] =
1572 cupsAddOption(color_option
, gray_choice
,
1573 pc
->num_presets
[_PWG_PRINT_COLOR_MODE_MONOCHROME
]
1574 [pwg_print_quality
],
1575 pc
->presets
[_PWG_PRINT_COLOR_MODE_MONOCHROME
] +
1582 * Copy and convert Duplex (sides) data...
1585 if ((duplex
= ppdFindOption(ppd
, "Duplex")) == NULL
)
1586 if ((duplex
= ppdFindOption(ppd
, "JCLDuplex")) == NULL
)
1587 if ((duplex
= ppdFindOption(ppd
, "EFDuplex")) == NULL
)
1588 if ((duplex
= ppdFindOption(ppd
, "EFDuplexing")) == NULL
)
1589 duplex
= ppdFindOption(ppd
, "KD03Duplex");
1593 pc
->sides_option
= _cupsStrAlloc(duplex
->keyword
);
1595 for (i
= duplex
->num_choices
, choice
= duplex
->choices
;
1599 if ((!_cups_strcasecmp(choice
->choice
, "None") ||
1600 !_cups_strcasecmp(choice
->choice
, "False")) && !pc
->sides_1sided
)
1601 pc
->sides_1sided
= _cupsStrAlloc(choice
->choice
);
1602 else if ((!_cups_strcasecmp(choice
->choice
, "DuplexNoTumble") ||
1603 !_cups_strcasecmp(choice
->choice
, "LongEdge") ||
1604 !_cups_strcasecmp(choice
->choice
, "Top")) && !pc
->sides_2sided_long
)
1605 pc
->sides_2sided_long
= _cupsStrAlloc(choice
->choice
);
1606 else if ((!_cups_strcasecmp(choice
->choice
, "DuplexTumble") ||
1607 !_cups_strcasecmp(choice
->choice
, "ShortEdge") ||
1608 !_cups_strcasecmp(choice
->choice
, "Bottom")) &&
1609 !pc
->sides_2sided_short
)
1610 pc
->sides_2sided_short
= _cupsStrAlloc(choice
->choice
);
1615 * Copy filters and pre-filters...
1618 pc
->filters
= cupsArrayNew3(NULL
, NULL
, NULL
, 0,
1619 (cups_acopy_func_t
)_cupsStrAlloc
,
1620 (cups_afree_func_t
)_cupsStrFree
);
1622 cupsArrayAdd(pc
->filters
,
1623 "application/vnd.cups-raw application/octet-stream 0 -");
1625 if ((ppd_attr
= ppdFindAttr(ppd
, "cupsFilter2", NULL
)) != NULL
)
1629 cupsArrayAdd(pc
->filters
, ppd_attr
->value
);
1631 while ((ppd_attr
= ppdFindNextAttr(ppd
, "cupsFilter2", NULL
)) != NULL
);
1633 else if (ppd
->num_filters
> 0)
1635 for (i
= 0; i
< ppd
->num_filters
; i
++)
1636 cupsArrayAdd(pc
->filters
, ppd
->filters
[i
]);
1639 cupsArrayAdd(pc
->filters
, "application/vnd.cups-postscript 0 -");
1642 * See if we have a command filter...
1645 for (filter
= (const char *)cupsArrayFirst(pc
->filters
);
1647 filter
= (const char *)cupsArrayNext(pc
->filters
))
1648 if (!_cups_strncasecmp(filter
, "application/vnd.cups-command", 28) &&
1649 _cups_isspace(filter
[28]))
1653 ((ppd_attr
= ppdFindAttr(ppd
, "cupsCommands", NULL
)) == NULL
||
1654 _cups_strcasecmp(ppd_attr
->value
, "none")))
1657 * No command filter and no cupsCommands keyword telling us not to use one.
1658 * See if this is a PostScript printer, and if so add a PostScript command
1662 for (filter
= (const char *)cupsArrayFirst(pc
->filters
);
1664 filter
= (const char *)cupsArrayNext(pc
->filters
))
1665 if (!_cups_strncasecmp(filter
, "application/vnd.cups-postscript", 31) &&
1666 _cups_isspace(filter
[31]))
1670 cupsArrayAdd(pc
->filters
,
1671 "application/vnd.cups-command application/postscript 100 "
1675 if ((ppd_attr
= ppdFindAttr(ppd
, "cupsPreFilter", NULL
)) != NULL
)
1677 pc
->prefilters
= cupsArrayNew3(NULL
, NULL
, NULL
, 0,
1678 (cups_acopy_func_t
)_cupsStrAlloc
,
1679 (cups_afree_func_t
)_cupsStrFree
);
1683 cupsArrayAdd(pc
->prefilters
, ppd_attr
->value
);
1685 while ((ppd_attr
= ppdFindNextAttr(ppd
, "cupsPreFilter", NULL
)) != NULL
);
1688 if ((ppd_attr
= ppdFindAttr(ppd
, "cupsSingleFile", NULL
)) != NULL
)
1689 pc
->single_file
= !_cups_strcasecmp(ppd_attr
->value
, "true");
1692 * Copy the product string, if any...
1696 pc
->product
= _cupsStrAlloc(ppd
->product
);
1699 * Copy finishings mapping data...
1702 if ((ppd_attr
= ppdFindAttr(ppd
, "cupsIPPFinishings", NULL
)) != NULL
)
1705 * Have proper vendor mapping of IPP finishings values to PPD options...
1708 pc
->finishings
= cupsArrayNew3((cups_array_func_t
)pwg_compare_finishings
,
1709 NULL
, NULL
, 0, NULL
,
1710 (cups_afree_func_t
)pwg_free_finishings
);
1714 if ((finishings
= calloc(1, sizeof(_pwg_finishings_t
))) == NULL
)
1717 finishings
->value
= (ipp_finishings_t
)atoi(ppd_attr
->spec
);
1718 finishings
->num_options
= _ppdParseOptions(ppd_attr
->value
, 0,
1719 &(finishings
->options
),
1720 _PPD_PARSE_OPTIONS
);
1722 cupsArrayAdd(pc
->finishings
, finishings
);
1724 while ((ppd_attr
= ppdFindNextAttr(ppd
, "cupsIPPFinishings",
1730 * No IPP mapping data, try to map common/standard PPD keywords...
1733 pc
->finishings
= cupsArrayNew3((cups_array_func_t
)pwg_compare_finishings
, NULL
, NULL
, 0, NULL
, (cups_afree_func_t
)pwg_free_finishings
);
1735 if ((ppd_option
= ppdFindOption(ppd
, "StapleLocation")) != NULL
)
1738 * Add staple finishings...
1741 if (ppdFindChoice(ppd_option
, "SinglePortrait"))
1742 pwg_add_finishing(pc
->finishings
, IPP_FINISHINGS_STAPLE_TOP_LEFT
, "StapleLocation", "SinglePortrait");
1743 if (ppdFindChoice(ppd_option
, "UpperLeft")) /* Ricoh extension */
1744 pwg_add_finishing(pc
->finishings
, IPP_FINISHINGS_STAPLE_TOP_LEFT
, "StapleLocation", "UpperLeft");
1745 if (ppdFindChoice(ppd_option
, "UpperRight")) /* Ricoh extension */
1746 pwg_add_finishing(pc
->finishings
, IPP_FINISHINGS_STAPLE_TOP_RIGHT
, "StapleLocation", "UpperRight");
1747 if (ppdFindChoice(ppd_option
, "SingleLandscape"))
1748 pwg_add_finishing(pc
->finishings
, IPP_FINISHINGS_STAPLE_BOTTOM_LEFT
, "StapleLocation", "SingleLandscape");
1749 if (ppdFindChoice(ppd_option
, "DualLandscape"))
1750 pwg_add_finishing(pc
->finishings
, IPP_FINISHINGS_STAPLE_DUAL_LEFT
, "StapleLocation", "DualLandscape");
1753 if ((ppd_option
= ppdFindOption(ppd
, "RIPunch")) != NULL
)
1756 * Add (Ricoh) punch finishings...
1759 if (ppdFindChoice(ppd_option
, "Left2"))
1760 pwg_add_finishing(pc
->finishings
, IPP_FINISHINGS_PUNCH_DUAL_LEFT
, "RIPunch", "Left2");
1761 if (ppdFindChoice(ppd_option
, "Left3"))
1762 pwg_add_finishing(pc
->finishings
, IPP_FINISHINGS_PUNCH_TRIPLE_LEFT
, "RIPunch", "Left3");
1763 if (ppdFindChoice(ppd_option
, "Left4"))
1764 pwg_add_finishing(pc
->finishings
, IPP_FINISHINGS_PUNCH_QUAD_LEFT
, "RIPunch", "Left4");
1765 if (ppdFindChoice(ppd_option
, "Right2"))
1766 pwg_add_finishing(pc
->finishings
, IPP_FINISHINGS_PUNCH_DUAL_RIGHT
, "RIPunch", "Right2");
1767 if (ppdFindChoice(ppd_option
, "Right3"))
1768 pwg_add_finishing(pc
->finishings
, IPP_FINISHINGS_PUNCH_TRIPLE_RIGHT
, "RIPunch", "Right3");
1769 if (ppdFindChoice(ppd_option
, "Right4"))
1770 pwg_add_finishing(pc
->finishings
, IPP_FINISHINGS_PUNCH_QUAD_RIGHT
, "RIPunch", "Right4");
1771 if (ppdFindChoice(ppd_option
, "Upper2"))
1772 pwg_add_finishing(pc
->finishings
, IPP_FINISHINGS_PUNCH_DUAL_TOP
, "RIPunch", "Upper2");
1773 if (ppdFindChoice(ppd_option
, "Upper3"))
1774 pwg_add_finishing(pc
->finishings
, IPP_FINISHINGS_PUNCH_TRIPLE_TOP
, "RIPunch", "Upper3");
1775 if (ppdFindChoice(ppd_option
, "Upper4"))
1776 pwg_add_finishing(pc
->finishings
, IPP_FINISHINGS_PUNCH_QUAD_TOP
, "RIPunch", "Upper4");
1779 if ((ppd_option
= ppdFindOption(ppd
, "BindEdge")) != NULL
)
1782 * Add bind finishings...
1785 if (ppdFindChoice(ppd_option
, "Left"))
1786 pwg_add_finishing(pc
->finishings
, IPP_FINISHINGS_BIND_LEFT
, "BindEdge", "Left");
1787 if (ppdFindChoice(ppd_option
, "Right"))
1788 pwg_add_finishing(pc
->finishings
, IPP_FINISHINGS_BIND_RIGHT
, "BindEdge", "Right");
1789 if (ppdFindChoice(ppd_option
, "Top"))
1790 pwg_add_finishing(pc
->finishings
, IPP_FINISHINGS_BIND_TOP
, "BindEdge", "Top");
1791 if (ppdFindChoice(ppd_option
, "Bottom"))
1792 pwg_add_finishing(pc
->finishings
, IPP_FINISHINGS_BIND_BOTTOM
, "BindEdge", "Bottom");
1795 if ((ppd_option
= ppdFindOption(ppd
, "FoldType")) != NULL
)
1798 * Add (Adobe) fold finishings...
1801 if (ppdFindChoice(ppd_option
, "ZFold"))
1802 pwg_add_finishing(pc
->finishings
, IPP_FINISHINGS_FOLD_Z
, "FoldType", "ZFold");
1803 if (ppdFindChoice(ppd_option
, "Saddle"))
1804 pwg_add_finishing(pc
->finishings
, IPP_FINISHINGS_FOLD_HALF
, "FoldType", "Saddle");
1805 if (ppdFindChoice(ppd_option
, "DoubleGate"))
1806 pwg_add_finishing(pc
->finishings
, IPP_FINISHINGS_FOLD_DOUBLE_GATE
, "FoldType", "DoubleGate");
1807 if (ppdFindChoice(ppd_option
, "LeftGate"))
1808 pwg_add_finishing(pc
->finishings
, IPP_FINISHINGS_FOLD_LEFT_GATE
, "FoldType", "LeftGate");
1809 if (ppdFindChoice(ppd_option
, "RightGate"))
1810 pwg_add_finishing(pc
->finishings
, IPP_FINISHINGS_FOLD_RIGHT_GATE
, "FoldType", "RightGate");
1811 if (ppdFindChoice(ppd_option
, "Letter"))
1812 pwg_add_finishing(pc
->finishings
, IPP_FINISHINGS_FOLD_LETTER
, "FoldType", "Letter");
1813 if (ppdFindChoice(ppd_option
, "XFold"))
1814 pwg_add_finishing(pc
->finishings
, IPP_FINISHINGS_FOLD_POSTER
, "FoldType", "XFold");
1817 if ((ppd_option
= ppdFindOption(ppd
, "RIFoldType")) != NULL
)
1820 * Add (Ricoh) fold finishings...
1823 if (ppdFindChoice(ppd_option
, "OutsideTwoFold"))
1824 pwg_add_finishing(pc
->finishings
, IPP_FINISHINGS_FOLD_LETTER
, "RIFoldType", "OutsideTwoFold");
1827 if (cupsArrayCount(pc
->finishings
) == 0)
1829 cupsArrayDelete(pc
->finishings
);
1830 pc
->finishings
= NULL
;
1834 if ((ppd_option
= ppdFindOption(ppd
, "cupsFinishingTemplate")) != NULL
)
1836 pc
->templates
= cupsArrayNew3((cups_array_func_t
)strcmp
, NULL
, NULL
, 0, (cups_acopy_func_t
)_cupsStrAlloc
, (cups_afree_func_t
)_cupsStrFree
);
1838 for (choice
= ppd_option
->choices
, i
= ppd_option
->num_choices
; i
> 0; choice
++, i
--)
1839 cupsArrayAdd(pc
->templates
, (void *)choice
->choice
);
1846 if ((ppd_attr
= ppdFindAttr(ppd
, "cupsMaxCopies", NULL
)) != NULL
)
1847 pc
->max_copies
= atoi(ppd_attr
->value
);
1848 else if (ppd
->manual_copies
)
1851 pc
->max_copies
= 9999;
1854 * cupsChargeInfoURI, cupsJobAccountId, cupsJobAccountingUserId,
1855 * cupsJobPassword, and cupsMandatory.
1858 if ((ppd_attr
= ppdFindAttr(ppd
, "cupsChargeInfoURI", NULL
)) != NULL
)
1859 pc
->charge_info_uri
= _cupsStrAlloc(ppd_attr
->value
);
1861 if ((ppd_attr
= ppdFindAttr(ppd
, "cupsJobAccountId", NULL
)) != NULL
)
1862 pc
->account_id
= !_cups_strcasecmp(ppd_attr
->value
, "true");
1864 if ((ppd_attr
= ppdFindAttr(ppd
, "cupsJobAccountingUserId", NULL
)) != NULL
)
1865 pc
->accounting_user_id
= !_cups_strcasecmp(ppd_attr
->value
, "true");
1867 if ((ppd_attr
= ppdFindAttr(ppd
, "cupsJobPassword", NULL
)) != NULL
)
1868 pc
->password
= _cupsStrAlloc(ppd_attr
->value
);
1870 if ((ppd_attr
= ppdFindAttr(ppd
, "cupsMandatory", NULL
)) != NULL
)
1871 pc
->mandatory
= _cupsArrayNewStrings(ppd_attr
->value
, ' ');
1874 * Strings (remote) file...
1877 if ((ppd_attr
= ppdFindAttr(ppd
, "cupsStringsURI", NULL
)) != NULL
)
1878 pc
->strings_uri
= _cupsStrAlloc(ppd_attr
->value
);
1884 pc
->support_files
= cupsArrayNew3(NULL
, NULL
, NULL
, 0,
1885 (cups_acopy_func_t
)_cupsStrAlloc
,
1886 (cups_afree_func_t
)_cupsStrFree
);
1888 for (ppd_attr
= ppdFindAttr(ppd
, "cupsICCProfile", NULL
);
1890 ppd_attr
= ppdFindNextAttr(ppd
, "cupsICCProfile", NULL
))
1891 cupsArrayAdd(pc
->support_files
, ppd_attr
->value
);
1893 if ((ppd_attr
= ppdFindAttr(ppd
, "APPrinterIconPath", NULL
)) != NULL
)
1894 cupsArrayAdd(pc
->support_files
, ppd_attr
->value
);
1897 * Return the cache data...
1903 * If we get here we need to destroy the PWG mapping data and return NULL...
1908 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Out of memory."), 1);
1909 _ppdCacheDestroy(pc
);
1916 * '_ppdCacheDestroy()' - Free all memory used for PWG mapping data.
1920 _ppdCacheDestroy(_ppd_cache_t
*pc
) /* I - PPD cache and mapping data */
1922 int i
; /* Looping var */
1923 pwg_map_t
*map
; /* Current map */
1924 pwg_size_t
*size
; /* Current size */
1928 * Range check input...
1935 * Free memory as needed...
1940 for (i
= pc
->num_bins
, map
= pc
->bins
; i
> 0; i
--, map
++)
1942 _cupsStrFree(map
->pwg
);
1943 _cupsStrFree(map
->ppd
);
1951 for (i
= pc
->num_sizes
, size
= pc
->sizes
; i
> 0; i
--, size
++)
1953 _cupsStrFree(size
->map
.pwg
);
1954 _cupsStrFree(size
->map
.ppd
);
1960 if (pc
->source_option
)
1961 _cupsStrFree(pc
->source_option
);
1965 for (i
= pc
->num_sources
, map
= pc
->sources
; i
> 0; i
--, map
++)
1967 _cupsStrFree(map
->pwg
);
1968 _cupsStrFree(map
->ppd
);
1976 for (i
= pc
->num_types
, map
= pc
->types
; i
> 0; i
--, map
++)
1978 _cupsStrFree(map
->pwg
);
1979 _cupsStrFree(map
->ppd
);
1985 if (pc
->custom_max_keyword
)
1986 _cupsStrFree(pc
->custom_max_keyword
);
1988 if (pc
->custom_min_keyword
)
1989 _cupsStrFree(pc
->custom_min_keyword
);
1991 _cupsStrFree(pc
->product
);
1992 cupsArrayDelete(pc
->filters
);
1993 cupsArrayDelete(pc
->prefilters
);
1994 cupsArrayDelete(pc
->finishings
);
1996 _cupsStrFree(pc
->charge_info_uri
);
1997 _cupsStrFree(pc
->password
);
1999 cupsArrayDelete(pc
->mandatory
);
2001 cupsArrayDelete(pc
->support_files
);
2008 * '_ppdCacheGetBin()' - Get the PWG output-bin keyword associated with a PPD
2012 const char * /* O - output-bin or NULL */
2014 _ppd_cache_t
*pc
, /* I - PPD cache and mapping data */
2015 const char *output_bin
) /* I - PPD OutputBin string */
2017 int i
; /* Looping var */
2021 * Range check input...
2024 if (!pc
|| !output_bin
)
2028 * Look up the OutputBin string...
2032 for (i
= 0; i
< pc
->num_bins
; i
++)
2033 if (!_cups_strcasecmp(output_bin
, pc
->bins
[i
].ppd
))
2034 return (pc
->bins
[i
].pwg
);
2041 * '_ppdCacheGetFinishingOptions()' - Get PPD finishing options for the given
2042 * IPP finishings value(s).
2045 int /* O - New number of options */
2046 _ppdCacheGetFinishingOptions(
2047 _ppd_cache_t
*pc
, /* I - PPD cache and mapping data */
2048 ipp_t
*job
, /* I - Job attributes or NULL */
2049 ipp_finishings_t value
, /* I - IPP finishings value of IPP_FINISHINGS_NONE */
2050 int num_options
, /* I - Number of options */
2051 cups_option_t
**options
) /* IO - Options */
2053 int i
; /* Looping var */
2054 _pwg_finishings_t
*f
, /* PWG finishings options */
2055 key
; /* Search key */
2056 ipp_attribute_t
*attr
; /* Finishings attribute */
2057 cups_option_t
*option
; /* Current finishings option */
2061 * Range check input...
2064 if (!pc
|| cupsArrayCount(pc
->finishings
) == 0 || !options
||
2065 (!job
&& value
== IPP_FINISHINGS_NONE
))
2066 return (num_options
);
2069 * Apply finishing options...
2072 if (job
&& (attr
= ippFindAttribute(job
, "finishings", IPP_TAG_ENUM
)) != NULL
)
2074 int num_values
= ippGetCount(attr
); /* Number of values */
2076 for (i
= 0; i
< num_values
; i
++)
2078 key
.value
= (ipp_finishings_t
)ippGetInteger(attr
, i
);
2080 if ((f
= cupsArrayFind(pc
->finishings
, &key
)) != NULL
)
2082 int j
; /* Another looping var */
2084 for (j
= f
->num_options
, option
= f
->options
; j
> 0; j
--, option
++)
2085 num_options
= cupsAddOption(option
->name
, option
->value
,
2086 num_options
, options
);
2090 else if (value
!= IPP_FINISHINGS_NONE
)
2094 if ((f
= cupsArrayFind(pc
->finishings
, &key
)) != NULL
)
2096 int j
; /* Another looping var */
2098 for (j
= f
->num_options
, option
= f
->options
; j
> 0; j
--, option
++)
2099 num_options
= cupsAddOption(option
->name
, option
->value
,
2100 num_options
, options
);
2104 return (num_options
);
2109 * '_ppdCacheGetFinishingValues()' - Get IPP finishings value(s) from the given
2113 int /* O - Number of finishings values */
2114 _ppdCacheGetFinishingValues(
2115 _ppd_cache_t
*pc
, /* I - PPD cache and mapping data */
2116 int num_options
, /* I - Number of options */
2117 cups_option_t
*options
, /* I - Options */
2118 int max_values
, /* I - Maximum number of finishings values */
2119 int *values
) /* O - Finishings values */
2121 int i
, /* Looping var */
2122 num_values
= 0; /* Number of values */
2123 _pwg_finishings_t
*f
; /* Current finishings option */
2124 cups_option_t
*option
; /* Current option */
2125 const char *val
; /* Value for option */
2129 * Range check input...
2132 DEBUG_printf(("_ppdCacheGetFinishingValues(pc=%p, num_options=%d, options=%p, max_values=%d, values=%p)", pc
, num_options
, options
, max_values
, values
));
2134 if (!pc
|| max_values
< 1 || !values
)
2136 DEBUG_puts("_ppdCacheGetFinishingValues: Bad arguments, returning 0.");
2139 else if (!pc
->finishings
)
2141 DEBUG_puts("_ppdCacheGetFinishingValues: No finishings support, returning 0.");
2146 * Go through the finishings options and see what is set...
2149 for (f
= (_pwg_finishings_t
*)cupsArrayFirst(pc
->finishings
);
2151 f
= (_pwg_finishings_t
*)cupsArrayNext(pc
->finishings
))
2153 DEBUG_printf(("_ppdCacheGetFinishingValues: Checking %d (%s)", f
->value
, ippEnumString("finishings", f
->value
)));
2155 for (i
= f
->num_options
, option
= f
->options
; i
> 0; i
--, option
++)
2157 DEBUG_printf(("_ppdCacheGetFinishingValues: %s=%s?", option
->name
, option
->value
));
2159 if ((val
= cupsGetOption(option
->name
, num_options
, options
)) == NULL
||
2160 _cups_strcasecmp(option
->value
, val
))
2162 DEBUG_puts("_ppdCacheGetFinishingValues: NO");
2169 DEBUG_printf(("_ppdCacheGetFinishingValues: Adding %d (%s)", f
->value
, ippEnumString("finishings", f
->value
)));
2171 values
[num_values
++] = f
->value
;
2173 if (num_values
>= max_values
)
2178 if (num_values
== 0)
2181 * Always have at least "finishings" = 'none'...
2184 DEBUG_puts("_ppdCacheGetFinishingValues: Adding 3 (none).");
2185 values
[0] = IPP_FINISHINGS_NONE
;
2189 DEBUG_printf(("_ppdCacheGetFinishingValues: Returning %d.", num_values
));
2191 return (num_values
);
2196 * '_ppdCacheGetInputSlot()' - Get the PPD InputSlot associated with the job
2197 * attributes or a keyword string.
2200 const char * /* O - PPD InputSlot or NULL */
2201 _ppdCacheGetInputSlot(
2202 _ppd_cache_t
*pc
, /* I - PPD cache and mapping data */
2203 ipp_t
*job
, /* I - Job attributes or NULL */
2204 const char *keyword
) /* I - Keyword string or NULL */
2207 * Range check input...
2210 if (!pc
|| pc
->num_sources
== 0 || (!job
&& !keyword
))
2213 if (job
&& !keyword
)
2216 * Lookup the media-col attribute and any media-source found there...
2219 ipp_attribute_t
*media_col
, /* media-col attribute */
2220 *media_source
; /* media-source attribute */
2221 pwg_size_t size
; /* Dimensional size */
2222 int margins_set
; /* Were the margins set? */
2224 media_col
= ippFindAttribute(job
, "media-col", IPP_TAG_BEGIN_COLLECTION
);
2226 (media_source
= ippFindAttribute(ippGetCollection(media_col
, 0),
2228 IPP_TAG_KEYWORD
)) != NULL
)
2231 * Use the media-source value from media-col...
2234 keyword
= ippGetString(media_source
, 0, NULL
);
2236 else if (pwgInitSize(&size
, job
, &margins_set
))
2239 * For media <= 5x7, look for a photo tray...
2242 if (size
.width
<= (5 * 2540) && size
.length
<= (7 * 2540))
2249 int i
; /* Looping var */
2251 for (i
= 0; i
< pc
->num_sources
; i
++)
2252 if (!_cups_strcasecmp(keyword
, pc
->sources
[i
].pwg
))
2253 return (pc
->sources
[i
].ppd
);
2261 * '_ppdCacheGetMediaType()' - Get the PPD MediaType associated with the job
2262 * attributes or a keyword string.
2265 const char * /* O - PPD MediaType or NULL */
2266 _ppdCacheGetMediaType(
2267 _ppd_cache_t
*pc
, /* I - PPD cache and mapping data */
2268 ipp_t
*job
, /* I - Job attributes or NULL */
2269 const char *keyword
) /* I - Keyword string or NULL */
2272 * Range check input...
2275 if (!pc
|| pc
->num_types
== 0 || (!job
&& !keyword
))
2278 if (job
&& !keyword
)
2281 * Lookup the media-col attribute and any media-source found there...
2284 ipp_attribute_t
*media_col
, /* media-col attribute */
2285 *media_type
; /* media-type attribute */
2287 media_col
= ippFindAttribute(job
, "media-col", IPP_TAG_BEGIN_COLLECTION
);
2290 if ((media_type
= ippFindAttribute(media_col
->values
[0].collection
,
2292 IPP_TAG_KEYWORD
)) == NULL
)
2293 media_type
= ippFindAttribute(media_col
->values
[0].collection
,
2294 "media-type", IPP_TAG_NAME
);
2297 keyword
= media_type
->values
[0].string
.text
;
2303 int i
; /* Looping var */
2305 for (i
= 0; i
< pc
->num_types
; i
++)
2306 if (!_cups_strcasecmp(keyword
, pc
->types
[i
].pwg
))
2307 return (pc
->types
[i
].ppd
);
2315 * '_ppdCacheGetOutputBin()' - Get the PPD OutputBin associated with the keyword
2319 const char * /* O - PPD OutputBin or NULL */
2320 _ppdCacheGetOutputBin(
2321 _ppd_cache_t
*pc
, /* I - PPD cache and mapping data */
2322 const char *output_bin
) /* I - Keyword string */
2324 int i
; /* Looping var */
2328 * Range check input...
2331 if (!pc
|| !output_bin
)
2335 * Look up the OutputBin string...
2339 for (i
= 0; i
< pc
->num_bins
; i
++)
2340 if (!_cups_strcasecmp(output_bin
, pc
->bins
[i
].pwg
))
2341 return (pc
->bins
[i
].ppd
);
2348 * '_ppdCacheGetPageSize()' - Get the PPD PageSize associated with the job
2349 * attributes or a keyword string.
2352 const char * /* O - PPD PageSize or NULL */
2353 _ppdCacheGetPageSize(
2354 _ppd_cache_t
*pc
, /* I - PPD cache and mapping data */
2355 ipp_t
*job
, /* I - Job attributes or NULL */
2356 const char *keyword
, /* I - Keyword string or NULL */
2357 int *exact
) /* O - 1 if exact match, 0 otherwise */
2359 int i
; /* Looping var */
2360 pwg_size_t
*size
, /* Current size */
2361 *closest
, /* Closest size */
2362 jobsize
; /* Size data from job */
2363 int margins_set
, /* Were the margins set? */
2364 dwidth
, /* Difference in width */
2365 dlength
, /* Difference in length */
2366 dleft
, /* Difference in left margins */
2367 dright
, /* Difference in right margins */
2368 dbottom
, /* Difference in bottom margins */
2369 dtop
, /* Difference in top margins */
2370 dmin
, /* Minimum difference */
2371 dclosest
; /* Closest difference */
2372 const char *ppd_name
; /* PPD media name */
2375 DEBUG_printf(("_ppdCacheGetPageSize(pc=%p, job=%p, keyword=\"%s\", exact=%p)",
2376 pc
, job
, keyword
, exact
));
2379 * Range check input...
2382 if (!pc
|| (!job
&& !keyword
))
2393 * Try getting the PPD media name from the job attributes...
2396 ipp_attribute_t
*attr
; /* Job attribute */
2398 if ((attr
= ippFindAttribute(job
, "PageSize", IPP_TAG_ZERO
)) == NULL
)
2399 if ((attr
= ippFindAttribute(job
, "PageRegion", IPP_TAG_ZERO
)) == NULL
)
2400 attr
= ippFindAttribute(job
, "media", IPP_TAG_ZERO
);
2404 DEBUG_printf(("1_ppdCacheGetPageSize: Found attribute %s (%s)",
2405 attr
->name
, ippTagString(attr
->value_tag
)));
2407 DEBUG_puts("1_ppdCacheGetPageSize: Did not find media attribute.");
2410 if (attr
&& (attr
->value_tag
== IPP_TAG_NAME
||
2411 attr
->value_tag
== IPP_TAG_KEYWORD
))
2412 ppd_name
= attr
->values
[0].string
.text
;
2415 DEBUG_printf(("1_ppdCacheGetPageSize: ppd_name=\"%s\"", ppd_name
));
2420 * Try looking up the named PPD size first...
2423 for (i
= pc
->num_sizes
, size
= pc
->sizes
; i
> 0; i
--, size
++)
2425 DEBUG_printf(("2_ppdCacheGetPageSize: size[%d]=[\"%s\" \"%s\"]",
2426 (int)(size
- pc
->sizes
), size
->map
.pwg
, size
->map
.ppd
));
2428 if (!_cups_strcasecmp(ppd_name
, size
->map
.ppd
) ||
2429 !_cups_strcasecmp(ppd_name
, size
->map
.pwg
))
2434 DEBUG_printf(("1_ppdCacheGetPageSize: Returning \"%s\"", ppd_name
));
2436 return (size
->map
.ppd
);
2441 if (job
&& !keyword
)
2444 * Get the size using media-col or media, with the preference being
2448 if (!pwgInitSize(&jobsize
, job
, &margins_set
))
2454 * Get the size using a media keyword...
2457 pwg_media_t
*media
; /* Media definition */
2460 if ((media
= pwgMediaForPWG(keyword
)) == NULL
)
2461 if ((media
= pwgMediaForLegacy(keyword
)) == NULL
)
2462 if ((media
= pwgMediaForPPD(keyword
)) == NULL
)
2465 jobsize
.width
= media
->width
;
2466 jobsize
.length
= media
->length
;
2471 * Now that we have the dimensions and possibly the margins, look at the
2472 * available sizes and find the match...
2476 dclosest
= 999999999;
2478 if (!ppd_name
|| _cups_strncasecmp(ppd_name
, "Custom.", 7) ||
2479 _cups_strncasecmp(ppd_name
, "custom_", 7))
2481 for (i
= pc
->num_sizes
, size
= pc
->sizes
; i
> 0; i
--, size
++)
2484 * Adobe uses a size matching algorithm with an epsilon of 5 points, which
2485 * is just about 176/2540ths...
2488 dwidth
= size
->width
- jobsize
.width
;
2489 dlength
= size
->length
- jobsize
.length
;
2491 if (dwidth
<= -176 || dwidth
>= 176 || dlength
<= -176 || dlength
>= 176)
2497 * Use a tighter epsilon of 1 point (35/2540ths) for margins...
2500 dleft
= size
->left
- jobsize
.left
;
2501 dright
= size
->right
- jobsize
.right
;
2502 dtop
= size
->top
- jobsize
.top
;
2503 dbottom
= size
->bottom
- jobsize
.bottom
;
2505 if (dleft
<= -35 || dleft
>= 35 || dright
<= -35 || dright
>= 35 ||
2506 dtop
<= -35 || dtop
>= 35 || dbottom
<= -35 || dbottom
>= 35)
2508 dleft
= dleft
< 0 ? -dleft
: dleft
;
2509 dright
= dright
< 0 ? -dright
: dright
;
2510 dbottom
= dbottom
< 0 ? -dbottom
: dbottom
;
2511 dtop
= dtop
< 0 ? -dtop
: dtop
;
2512 dmin
= dleft
+ dright
+ dbottom
+ dtop
;
2514 if (dmin
< dclosest
)
2527 DEBUG_printf(("1_ppdCacheGetPageSize: Returning \"%s\"", size
->map
.ppd
));
2529 return (size
->map
.ppd
);
2535 DEBUG_printf(("1_ppdCacheGetPageSize: Returning \"%s\" (closest)",
2538 return (closest
->map
.ppd
);
2542 * If we get here we need to check for custom page size support...
2545 if (jobsize
.width
>= pc
->custom_min_width
&&
2546 jobsize
.width
<= pc
->custom_max_width
&&
2547 jobsize
.length
>= pc
->custom_min_length
&&
2548 jobsize
.length
<= pc
->custom_max_length
)
2551 * In range, format as Custom.WWWWxLLLL (points).
2554 snprintf(pc
->custom_ppd_size
, sizeof(pc
->custom_ppd_size
), "Custom.%dx%d",
2555 (int)PWG_TO_POINTS(jobsize
.width
), (int)PWG_TO_POINTS(jobsize
.length
));
2557 if (margins_set
&& exact
)
2559 dleft
= pc
->custom_size
.left
- jobsize
.left
;
2560 dright
= pc
->custom_size
.right
- jobsize
.right
;
2561 dtop
= pc
->custom_size
.top
- jobsize
.top
;
2562 dbottom
= pc
->custom_size
.bottom
- jobsize
.bottom
;
2564 if (dleft
> -35 && dleft
< 35 && dright
> -35 && dright
< 35 &&
2565 dtop
> -35 && dtop
< 35 && dbottom
> -35 && dbottom
< 35)
2571 DEBUG_printf(("1_ppdCacheGetPageSize: Returning \"%s\" (custom)",
2572 pc
->custom_ppd_size
));
2574 return (pc
->custom_ppd_size
);
2578 * No custom page size support or the size is out of range - return NULL.
2581 DEBUG_puts("1_ppdCacheGetPageSize: Returning NULL");
2588 * '_ppdCacheGetSize()' - Get the PWG size associated with a PPD PageSize.
2591 pwg_size_t
* /* O - PWG size or NULL */
2593 _ppd_cache_t
*pc
, /* I - PPD cache and mapping data */
2594 const char *page_size
) /* I - PPD PageSize */
2596 int i
; /* Looping var */
2597 pwg_media_t
*media
; /* Media */
2598 pwg_size_t
*size
; /* Current size */
2602 * Range check input...
2605 if (!pc
|| !page_size
)
2608 if (!_cups_strncasecmp(page_size
, "Custom.", 7))
2611 * Custom size; size name can be one of the following:
2613 * Custom.WIDTHxLENGTHin - Size in inches
2614 * Custom.WIDTHxLENGTHft - Size in feet
2615 * Custom.WIDTHxLENGTHcm - Size in centimeters
2616 * Custom.WIDTHxLENGTHmm - Size in millimeters
2617 * Custom.WIDTHxLENGTHm - Size in meters
2618 * Custom.WIDTHxLENGTH[pt] - Size in points
2621 double w
, l
; /* Width and length of page */
2622 char *ptr
; /* Pointer into PageSize */
2623 struct lconv
*loc
; /* Locale data */
2626 w
= (float)_cupsStrScand(page_size
+ 7, &ptr
, loc
);
2627 if (!ptr
|| *ptr
!= 'x')
2630 l
= (float)_cupsStrScand(ptr
+ 1, &ptr
, loc
);
2634 if (!_cups_strcasecmp(ptr
, "in"))
2639 else if (!_cups_strcasecmp(ptr
, "ft"))
2644 else if (!_cups_strcasecmp(ptr
, "mm"))
2649 else if (!_cups_strcasecmp(ptr
, "cm"))
2654 else if (!_cups_strcasecmp(ptr
, "m"))
2665 pc
->custom_size
.width
= (int)w
;
2666 pc
->custom_size
.length
= (int)l
;
2668 return (&(pc
->custom_size
));
2672 * Not a custom size - look it up...
2675 for (i
= pc
->num_sizes
, size
= pc
->sizes
; i
> 0; i
--, size
++)
2676 if (!_cups_strcasecmp(page_size
, size
->map
.ppd
) ||
2677 !_cups_strcasecmp(page_size
, size
->map
.pwg
))
2681 * Look up standard sizes...
2684 if ((media
= pwgMediaForPPD(page_size
)) == NULL
)
2685 if ((media
= pwgMediaForLegacy(page_size
)) == NULL
)
2686 media
= pwgMediaForPWG(page_size
);
2690 pc
->custom_size
.width
= media
->width
;
2691 pc
->custom_size
.length
= media
->length
;
2693 return (&(pc
->custom_size
));
2701 * '_ppdCacheGetSource()' - Get the PWG media-source associated with a PPD
2705 const char * /* O - PWG media-source keyword */
2707 _ppd_cache_t
*pc
, /* I - PPD cache and mapping data */
2708 const char *input_slot
) /* I - PPD InputSlot */
2710 int i
; /* Looping var */
2711 pwg_map_t
*source
; /* Current source */
2715 * Range check input...
2718 if (!pc
|| !input_slot
)
2721 for (i
= pc
->num_sources
, source
= pc
->sources
; i
> 0; i
--, source
++)
2722 if (!_cups_strcasecmp(input_slot
, source
->ppd
))
2723 return (source
->pwg
);
2730 * '_ppdCacheGetType()' - Get the PWG media-type associated with a PPD
2734 const char * /* O - PWG media-type keyword */
2736 _ppd_cache_t
*pc
, /* I - PPD cache and mapping data */
2737 const char *media_type
) /* I - PPD MediaType */
2739 int i
; /* Looping var */
2740 pwg_map_t
*type
; /* Current type */
2744 * Range check input...
2747 if (!pc
|| !media_type
)
2750 for (i
= pc
->num_types
, type
= pc
->types
; i
> 0; i
--, type
++)
2751 if (!_cups_strcasecmp(media_type
, type
->ppd
))
2759 * '_ppdCacheWriteFile()' - Write PWG mapping data to a file.
2762 int /* O - 1 on success, 0 on failure */
2764 _ppd_cache_t
*pc
, /* I - PPD cache and mapping data */
2765 const char *filename
, /* I - File to write */
2766 ipp_t
*attrs
) /* I - Attributes to write, if any */
2768 int i
, j
, k
; /* Looping vars */
2769 cups_file_t
*fp
; /* Output file */
2770 pwg_size_t
*size
; /* Current size */
2771 pwg_map_t
*map
; /* Current map */
2772 _pwg_finishings_t
*f
; /* Current finishing option */
2773 cups_option_t
*option
; /* Current option */
2774 const char *value
; /* String value */
2775 char newfile
[1024]; /* New filename */
2779 * Range check input...
2782 if (!pc
|| !filename
)
2784 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(EINVAL
), 0);
2789 * Open the file and write with compression...
2792 snprintf(newfile
, sizeof(newfile
), "%s.N", filename
);
2793 if ((fp
= cupsFileOpen(newfile
, "w9")) == NULL
)
2795 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(errno
), 0);
2800 * Standard header...
2803 cupsFilePrintf(fp
, "#CUPS-PPD-CACHE-%d\n", _PPD_CACHE_VERSION
);
2809 if (pc
->num_bins
> 0)
2811 cupsFilePrintf(fp
, "NumBins %d\n", pc
->num_bins
);
2812 for (i
= pc
->num_bins
, map
= pc
->bins
; i
> 0; i
--, map
++)
2813 cupsFilePrintf(fp
, "Bin %s %s\n", map
->pwg
, map
->ppd
);
2820 cupsFilePrintf(fp
, "NumSizes %d\n", pc
->num_sizes
);
2821 for (i
= pc
->num_sizes
, size
= pc
->sizes
; i
> 0; i
--, size
++)
2822 cupsFilePrintf(fp
, "Size %s %s %d %d %d %d %d %d\n", size
->map
.pwg
,
2823 size
->map
.ppd
, size
->width
, size
->length
, size
->left
,
2824 size
->bottom
, size
->right
, size
->top
);
2825 if (pc
->custom_max_width
> 0)
2826 cupsFilePrintf(fp
, "CustomSize %d %d %d %d %d %d %d %d\n",
2827 pc
->custom_max_width
, pc
->custom_max_length
,
2828 pc
->custom_min_width
, pc
->custom_min_length
,
2829 pc
->custom_size
.left
, pc
->custom_size
.bottom
,
2830 pc
->custom_size
.right
, pc
->custom_size
.top
);
2836 if (pc
->source_option
)
2837 cupsFilePrintf(fp
, "SourceOption %s\n", pc
->source_option
);
2839 if (pc
->num_sources
> 0)
2841 cupsFilePrintf(fp
, "NumSources %d\n", pc
->num_sources
);
2842 for (i
= pc
->num_sources
, map
= pc
->sources
; i
> 0; i
--, map
++)
2843 cupsFilePrintf(fp
, "Source %s %s\n", map
->pwg
, map
->ppd
);
2850 if (pc
->num_types
> 0)
2852 cupsFilePrintf(fp
, "NumTypes %d\n", pc
->num_types
);
2853 for (i
= pc
->num_types
, map
= pc
->types
; i
> 0; i
--, map
++)
2854 cupsFilePrintf(fp
, "Type %s %s\n", map
->pwg
, map
->ppd
);
2861 for (i
= _PWG_PRINT_COLOR_MODE_MONOCHROME
; i
< _PWG_PRINT_COLOR_MODE_MAX
; i
++)
2862 for (j
= _PWG_PRINT_QUALITY_DRAFT
; j
< _PWG_PRINT_QUALITY_MAX
; j
++)
2863 if (pc
->num_presets
[i
][j
])
2865 cupsFilePrintf(fp
, "Preset %d %d", i
, j
);
2866 for (k
= pc
->num_presets
[i
][j
], option
= pc
->presets
[i
][j
];
2869 cupsFilePrintf(fp
, " %s=%s", option
->name
, option
->value
);
2870 cupsFilePutChar(fp
, '\n');
2877 if (pc
->sides_option
)
2878 cupsFilePrintf(fp
, "SidesOption %s\n", pc
->sides_option
);
2880 if (pc
->sides_1sided
)
2881 cupsFilePrintf(fp
, "Sides1Sided %s\n", pc
->sides_1sided
);
2883 if (pc
->sides_2sided_long
)
2884 cupsFilePrintf(fp
, "Sides2SidedLong %s\n", pc
->sides_2sided_long
);
2886 if (pc
->sides_2sided_short
)
2887 cupsFilePrintf(fp
, "Sides2SidedShort %s\n", pc
->sides_2sided_short
);
2890 * Product, cupsFilter, cupsFilter2, and cupsPreFilter...
2894 cupsFilePutConf(fp
, "Product", pc
->product
);
2896 for (value
= (const char *)cupsArrayFirst(pc
->filters
);
2898 value
= (const char *)cupsArrayNext(pc
->filters
))
2899 cupsFilePutConf(fp
, "Filter", value
);
2901 for (value
= (const char *)cupsArrayFirst(pc
->prefilters
);
2903 value
= (const char *)cupsArrayNext(pc
->prefilters
))
2904 cupsFilePutConf(fp
, "PreFilter", value
);
2906 cupsFilePrintf(fp
, "SingleFile %s\n", pc
->single_file
? "true" : "false");
2909 * Finishing options...
2912 for (f
= (_pwg_finishings_t
*)cupsArrayFirst(pc
->finishings
);
2914 f
= (_pwg_finishings_t
*)cupsArrayNext(pc
->finishings
))
2916 cupsFilePrintf(fp
, "Finishings %d", f
->value
);
2917 for (i
= f
->num_options
, option
= f
->options
; i
> 0; i
--, option
++)
2918 cupsFilePrintf(fp
, " %s=%s", option
->name
, option
->value
);
2919 cupsFilePutChar(fp
, '\n');
2922 for (value
= (const char *)cupsArrayFirst(pc
->templates
); value
; value
= (const char *)cupsArrayNext(pc
->templates
))
2923 cupsFilePutConf(fp
, "FinishingTemplate", value
);
2929 cupsFilePrintf(fp
, "MaxCopies %d\n", pc
->max_copies
);
2932 * Accounting/quota/PIN/managed printing values...
2935 if (pc
->charge_info_uri
)
2936 cupsFilePutConf(fp
, "ChargeInfoURI", pc
->charge_info_uri
);
2938 cupsFilePrintf(fp
, "AccountId %s\n", pc
->account_id
? "true" : "false");
2939 cupsFilePrintf(fp
, "AccountingUserId %s\n",
2940 pc
->accounting_user_id
? "true" : "false");
2943 cupsFilePutConf(fp
, "Password", pc
->password
);
2945 for (value
= (char *)cupsArrayFirst(pc
->mandatory
);
2947 value
= (char *)cupsArrayNext(pc
->mandatory
))
2948 cupsFilePutConf(fp
, "Mandatory", value
);
2951 * (Remote) strings file...
2954 if (pc
->strings_uri
)
2955 cupsFilePutConf(fp
, "StringsURI", pc
->strings_uri
);
2961 for (value
= (char *)cupsArrayFirst(pc
->support_files
);
2963 value
= (char *)cupsArrayNext(pc
->support_files
))
2964 cupsFilePutConf(fp
, "SupportFile", value
);
2967 * IPP attributes, if any...
2972 cupsFilePrintf(fp
, "IPP " CUPS_LLFMT
"\n", CUPS_LLCAST
ippLength(attrs
));
2974 attrs
->state
= IPP_STATE_IDLE
;
2975 ippWriteIO(fp
, (ipp_iocb_t
)cupsFileWrite
, 1, NULL
, attrs
);
2979 * Close and return...
2982 if (cupsFileClose(fp
))
2989 return (!rename(newfile
, filename
));
2994 * '_ppdCreateFromIPP()' - Create a PPD file describing the capabilities
2995 * of an IPP printer.
2998 char * /* O - PPD filename or @code NULL@ on error */
2999 _ppdCreateFromIPP(char *buffer
, /* I - Filename buffer */
3000 size_t bufsize
, /* I - Size of filename buffer */
3001 ipp_t
*response
) /* I - Get-Printer-Attributes response */
3003 cups_file_t
*fp
; /* PPD file */
3004 cups_array_t
*sizes
; /* Media sizes supported by printer */
3005 cups_size_t
*size
; /* Current media size */
3006 ipp_attribute_t
*attr
, /* xxx-supported */
3007 *defattr
, /* xxx-default */
3008 *quality
, /* print-quality-supported */
3009 *x_dim
, *y_dim
; /* Media dimensions */
3010 ipp_t
*media_col
, /* Media collection */
3011 *media_size
; /* Media size collection */
3012 char make
[256], /* Make and model */
3013 *model
, /* Model name */
3014 ppdname
[PPD_MAX_NAME
];
3016 int i
, j
, /* Looping vars */
3017 count
, /* Number of values */
3018 bottom
, /* Largest bottom margin */
3019 left
, /* Largest left margin */
3020 right
, /* Largest right margin */
3021 top
, /* Largest top margin */
3022 max_length
= 0, /* Maximum custom size */
3024 min_length
= INT_MAX
,
3025 /* Minimum custom size */
3026 min_width
= INT_MAX
,
3027 is_apple
= 0, /* Does the printer support Apple raster? */
3028 is_pdf
= 0, /* Does the printer support PDF? */
3029 is_pwg
= 0; /* Does the printer support PWG Raster? */
3030 pwg_media_t
*pwg
; /* PWG media size */
3031 int xres
, yres
; /* Resolution values */
3032 int resolutions
[1000];
3033 /* Array of resolution indices */
3034 char msgid
[256]; /* Message identifier (attr.value) */
3035 const char *keyword
, /* Keyword value */
3036 *msgstr
; /* Localized string */
3037 cups_lang_t
*lang
= cupsLangDefault();
3038 /* Localization info */
3039 cups_array_t
*strings
= NULL
;/* Printer strings file */
3040 struct lconv
*loc
= localeconv();
3042 cups_array_t
*fin_options
= NULL
;
3043 /* Finishing options */
3047 * Range check input...
3053 if (!buffer
|| bufsize
< 1)
3055 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(EINVAL
), 0);
3061 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("No IPP attributes."), 1);
3066 * Open a temporary file for the PPD...
3069 if ((fp
= cupsTempFile2(buffer
, (int)bufsize
)) == NULL
)
3071 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(errno
), 0);
3076 * Standard stuff for PPD file...
3079 cupsFilePuts(fp
, "*PPD-Adobe: \"4.3\"\n");
3080 cupsFilePuts(fp
, "*FormatVersion: \"4.3\"\n");
3081 cupsFilePrintf(fp
, "*FileVersion: \"%d.%d\"\n", CUPS_VERSION_MAJOR
, CUPS_VERSION_MINOR
);
3082 cupsFilePuts(fp
, "*LanguageVersion: English\n");
3083 cupsFilePuts(fp
, "*LanguageEncoding: ISOLatin1\n");
3084 cupsFilePuts(fp
, "*PSVersion: \"(3010.000) 0\"\n");
3085 cupsFilePuts(fp
, "*LanguageLevel: \"3\"\n");
3086 cupsFilePuts(fp
, "*FileSystem: False\n");
3087 cupsFilePuts(fp
, "*PCFileName: \"ippeve.ppd\"\n");
3089 if ((attr
= ippFindAttribute(response
, "printer-make-and-model", IPP_TAG_TEXT
)) != NULL
)
3090 strlcpy(make
, ippGetString(attr
, 0, NULL
), sizeof(make
));
3092 strlcpy(make
, "Unknown Printer", sizeof(make
));
3094 if (!_cups_strncasecmp(make
, "Hewlett Packard ", 16) ||
3095 !_cups_strncasecmp(make
, "Hewlett-Packard ", 16))
3098 strlcpy(make
, "HP", sizeof(make
));
3100 else if ((model
= strchr(make
, ' ')) != NULL
)
3105 cupsFilePrintf(fp
, "*Manufacturer: \"%s\"\n", make
);
3106 cupsFilePrintf(fp
, "*ModelName: \"%s\"\n", model
);
3107 cupsFilePrintf(fp
, "*Product: \"(%s)\"\n", model
);
3108 cupsFilePrintf(fp
, "*NickName: \"%s\"\n", model
);
3109 cupsFilePrintf(fp
, "*ShortNickName: \"%s\"\n", model
);
3111 if ((attr
= ippFindAttribute(response
, "color-supported", IPP_TAG_BOOLEAN
)) != NULL
&& ippGetBoolean(attr
, 0))
3112 cupsFilePuts(fp
, "*ColorDevice: True\n");
3114 cupsFilePuts(fp
, "*ColorDevice: False\n");
3116 cupsFilePrintf(fp
, "*cupsVersion: %d.%d\n", CUPS_VERSION_MAJOR
, CUPS_VERSION_MINOR
);
3117 cupsFilePuts(fp
, "*cupsSNMPSupplies: False\n");
3118 cupsFilePrintf(fp
, "*cupsLanguages: \"%s\"\n", lang
->language
);
3120 if ((attr
= ippFindAttribute(response
, "printer-more-info", IPP_TAG_URI
)) != NULL
)
3121 cupsFilePrintf(fp
, "*APSupplies: \"%s\"\n", ippGetString(attr
, 0, NULL
));
3123 if ((attr
= ippFindAttribute(response
, "printer-charge-info-uri", IPP_TAG_URI
)) != NULL
)
3124 cupsFilePrintf(fp
, "*cupsChargeInfoURI: \"%s\"\n", ippGetString(attr
, 0, NULL
));
3126 if ((attr
= ippFindAttribute(response
, "printer-strings-uri", IPP_TAG_URI
)) != NULL
)
3128 http_t
*http
= NULL
; /* Connection to printer */
3129 char stringsfile
[1024]; /* Temporary strings file */
3131 if (cups_get_url(&http
, ippGetString(attr
, 0, NULL
), stringsfile
, sizeof(stringsfile
)))
3133 cupsFilePrintf(fp
, "*cupsStringsURI: \"%s\"\n", ippGetString(attr
, 0, NULL
));
3135 strings
= _cupsMessageLoad(stringsfile
, _CUPS_MESSAGE_STRINGS
| _CUPS_MESSAGE_UNQUOTE
);
3137 unlink(stringsfile
);
3148 if ((attr
= ippFindAttribute(response
, "document-format-supported", IPP_TAG_MIMETYPE
)) != NULL
)
3150 is_apple
= ippContainsString(attr
, "image/urf");
3151 is_pdf
= ippContainsString(attr
, "application/pdf");
3152 is_pwg
= ippContainsString(attr
, "image/pwg-raster");
3154 for (i
= 0, count
= ippGetCount(attr
); i
< count
; i
++)
3156 const char *format
= ippGetString(attr
, i
, NULL
);
3160 * Write cupsFilter2 lines for supported formats...
3163 if (!_cups_strcasecmp(format
, "application/pdf"))
3164 cupsFilePuts(fp
, "*cupsFilter2: \"application/vnd.cups-pdf application/pdf 10 -\"\n");
3165 else if (!_cups_strcasecmp(format
, "image/jpeg") || !_cups_strcasecmp(format
, "image/png"))
3166 cupsFilePrintf(fp
, "*cupsFilter2: \"%s %s 0 -\"\n", format
, format
);
3167 else if (!_cups_strcasecmp(format
, "image/pwg-raster") || !_cups_strcasecmp(format
, "image/urf"))
3168 cupsFilePrintf(fp
, "*cupsFilter2: \"%s %s 100 -\"\n", format
, format
);
3172 if (!is_apple
&& !is_pdf
&& !is_pwg
)
3176 * PageSize/PageRegion/ImageableArea/PaperDimension
3179 if ((attr
= ippFindAttribute(response
, "media-bottom-margin-supported", IPP_TAG_INTEGER
)) != NULL
)
3181 for (i
= 1, bottom
= ippGetInteger(attr
, 0), count
= ippGetCount(attr
); i
< count
; i
++)
3182 if (ippGetInteger(attr
, i
) > bottom
)
3183 bottom
= ippGetInteger(attr
, i
);
3188 if ((attr
= ippFindAttribute(response
, "media-left-margin-supported", IPP_TAG_INTEGER
)) != NULL
)
3190 for (i
= 1, left
= ippGetInteger(attr
, 0), count
= ippGetCount(attr
); i
< count
; i
++)
3191 if (ippGetInteger(attr
, i
) > left
)
3192 left
= ippGetInteger(attr
, i
);
3197 if ((attr
= ippFindAttribute(response
, "media-right-margin-supported", IPP_TAG_INTEGER
)) != NULL
)
3199 for (i
= 1, right
= ippGetInteger(attr
, 0), count
= ippGetCount(attr
); i
< count
; i
++)
3200 if (ippGetInteger(attr
, i
) > right
)
3201 right
= ippGetInteger(attr
, i
);
3206 if ((attr
= ippFindAttribute(response
, "media-top-margin-supported", IPP_TAG_INTEGER
)) != NULL
)
3208 for (i
= 1, top
= ippGetInteger(attr
, 0), count
= ippGetCount(attr
); i
< count
; i
++)
3209 if (ippGetInteger(attr
, i
) > top
)
3210 top
= ippGetInteger(attr
, i
);
3215 if ((defattr
= ippFindAttribute(response
, "media-col-default", IPP_TAG_BEGIN_COLLECTION
)) != NULL
)
3217 if ((attr
= ippFindAttribute(ippGetCollection(defattr
, 0), "media-size", IPP_TAG_BEGIN_COLLECTION
)) != NULL
)
3219 media_size
= ippGetCollection(attr
, 0);
3220 x_dim
= ippFindAttribute(media_size
, "x-dimension", IPP_TAG_INTEGER
);
3221 y_dim
= ippFindAttribute(media_size
, "y-dimension", IPP_TAG_INTEGER
);
3223 if (x_dim
&& y_dim
&& (pwg
= pwgMediaForSize(ippGetInteger(x_dim
, 0), ippGetInteger(y_dim
, 0))) != NULL
)
3224 strlcpy(ppdname
, pwg
->ppd
, sizeof(ppdname
));
3226 strlcpy(ppdname
, "Unknown", sizeof(ppdname
));
3229 strlcpy(ppdname
, "Unknown", sizeof(ppdname
));
3231 else if ((pwg
= pwgMediaForPWG(ippGetString(ippFindAttribute(response
, "media-default", IPP_TAG_ZERO
), 0, NULL
))) != NULL
)
3232 strlcpy(ppdname
, pwg
->ppd
, sizeof(ppdname
));
3234 strlcpy(ppdname
, "Unknown", sizeof(ppdname
));
3236 sizes
= cupsArrayNew3((cups_array_func_t
)pwg_compare_sizes
, NULL
, NULL
, 0, (cups_acopy_func_t
)pwg_copy_size
, (cups_afree_func_t
)free
);
3238 if ((attr
= ippFindAttribute(response
, "media-col-database", IPP_TAG_BEGIN_COLLECTION
)) != NULL
)
3240 for (i
= 0, count
= ippGetCount(attr
); i
< count
; i
++)
3242 cups_size_t temp
; /* Current size */
3243 ipp_attribute_t
*margin
; /* media-xxx-margin attribute */
3245 media_col
= ippGetCollection(attr
, i
);
3246 media_size
= ippGetCollection(ippFindAttribute(media_col
, "media-size", IPP_TAG_BEGIN_COLLECTION
), 0);
3247 x_dim
= ippFindAttribute(media_size
, "x-dimension", IPP_TAG_ZERO
);
3248 y_dim
= ippFindAttribute(media_size
, "y-dimension", IPP_TAG_ZERO
);
3249 pwg
= pwgMediaForSize(ippGetInteger(x_dim
, 0), ippGetInteger(y_dim
, 0));
3253 temp
.width
= pwg
->width
;
3254 temp
.length
= pwg
->length
;
3256 if ((margin
= ippFindAttribute(media_col
, "media-bottom-margin", IPP_TAG_INTEGER
)) != NULL
)
3257 temp
.bottom
= ippGetInteger(margin
, 0);
3259 temp
.bottom
= bottom
;
3261 if ((margin
= ippFindAttribute(media_col
, "media-left-margin", IPP_TAG_INTEGER
)) != NULL
)
3262 temp
.left
= ippGetInteger(margin
, 0);
3266 if ((margin
= ippFindAttribute(media_col
, "media-right-margin", IPP_TAG_INTEGER
)) != NULL
)
3267 temp
.right
= ippGetInteger(margin
, 0);
3271 if ((margin
= ippFindAttribute(media_col
, "media-top-margin", IPP_TAG_INTEGER
)) != NULL
)
3272 temp
.top
= ippGetInteger(margin
, 0);
3276 if (temp
.bottom
== 0 && temp
.left
== 0 && temp
.right
== 0 && temp
.top
== 0)
3277 snprintf(temp
.media
, sizeof(temp
.media
), "%s.Borderless", pwg
->ppd
);
3279 strlcpy(temp
.media
, pwg
->ppd
, sizeof(temp
.media
));
3281 if (!cupsArrayFind(sizes
, &temp
))
3282 cupsArrayAdd(sizes
, &temp
);
3284 else if (ippGetValueTag(x_dim
) == IPP_TAG_RANGE
|| ippGetValueTag(y_dim
) == IPP_TAG_RANGE
)
3287 * Custom size - record the min/max values...
3290 int lower
, upper
; /* Range values */
3292 if (ippGetValueTag(x_dim
) == IPP_TAG_RANGE
)
3293 lower
= ippGetRange(x_dim
, 0, &upper
);
3295 lower
= upper
= ippGetInteger(x_dim
, 0);
3297 if (lower
< min_width
)
3299 if (upper
> max_width
)
3302 if (ippGetValueTag(y_dim
) == IPP_TAG_RANGE
)
3303 lower
= ippGetRange(y_dim
, 0, &upper
);
3305 lower
= upper
= ippGetInteger(y_dim
, 0);
3307 if (lower
< min_length
)
3309 if (upper
> max_length
)
3314 if ((max_width
== 0 || max_length
== 0) && (attr
= ippFindAttribute(response
, "media-size-supported", IPP_TAG_BEGIN_COLLECTION
)) != NULL
)
3317 * Some printers don't list custom size support in media-col-database...
3320 for (i
= 0, count
= ippGetCount(attr
); i
< count
; i
++)
3322 media_size
= ippGetCollection(attr
, i
);
3323 x_dim
= ippFindAttribute(media_size
, "x-dimension", IPP_TAG_ZERO
);
3324 y_dim
= ippFindAttribute(media_size
, "y-dimension", IPP_TAG_ZERO
);
3326 if (ippGetValueTag(x_dim
) == IPP_TAG_RANGE
|| ippGetValueTag(y_dim
) == IPP_TAG_RANGE
)
3329 * Custom size - record the min/max values...
3332 int lower
, upper
; /* Range values */
3334 if (ippGetValueTag(x_dim
) == IPP_TAG_RANGE
)
3335 lower
= ippGetRange(x_dim
, 0, &upper
);
3337 lower
= upper
= ippGetInteger(x_dim
, 0);
3339 if (lower
< min_width
)
3341 if (upper
> max_width
)
3344 if (ippGetValueTag(y_dim
) == IPP_TAG_RANGE
)
3345 lower
= ippGetRange(y_dim
, 0, &upper
);
3347 lower
= upper
= ippGetInteger(y_dim
, 0);
3349 if (lower
< min_length
)
3351 if (upper
> max_length
)
3357 else if ((attr
= ippFindAttribute(response
, "media-size-supported", IPP_TAG_BEGIN_COLLECTION
)) != NULL
)
3359 for (i
= 0, count
= ippGetCount(attr
); i
< count
; i
++)
3361 cups_size_t temp
; /* Current size */
3363 media_size
= ippGetCollection(attr
, i
);
3364 x_dim
= ippFindAttribute(media_size
, "x-dimension", IPP_TAG_ZERO
);
3365 y_dim
= ippFindAttribute(media_size
, "y-dimension", IPP_TAG_ZERO
);
3366 pwg
= pwgMediaForSize(ippGetInteger(x_dim
, 0), ippGetInteger(y_dim
, 0));
3370 temp
.width
= pwg
->width
;
3371 temp
.length
= pwg
->length
;
3372 temp
.bottom
= bottom
;
3377 if (temp
.bottom
== 0 && temp
.left
== 0 && temp
.right
== 0 && temp
.top
== 0)
3378 snprintf(temp
.media
, sizeof(temp
.media
), "%s.Borderless", pwg
->ppd
);
3380 strlcpy(temp
.media
, pwg
->ppd
, sizeof(temp
.media
));
3382 if (!cupsArrayFind(sizes
, &temp
))
3383 cupsArrayAdd(sizes
, &temp
);
3385 else if (ippGetValueTag(x_dim
) == IPP_TAG_RANGE
|| ippGetValueTag(y_dim
) == IPP_TAG_RANGE
)
3388 * Custom size - record the min/max values...
3391 int lower
, upper
; /* Range values */
3393 if (ippGetValueTag(x_dim
) == IPP_TAG_RANGE
)
3394 lower
= ippGetRange(x_dim
, 0, &upper
);
3396 lower
= upper
= ippGetInteger(x_dim
, 0);
3398 if (lower
< min_width
)
3400 if (upper
> max_width
)
3403 if (ippGetValueTag(y_dim
) == IPP_TAG_RANGE
)
3404 lower
= ippGetRange(y_dim
, 0, &upper
);
3406 lower
= upper
= ippGetInteger(y_dim
, 0);
3408 if (lower
< min_length
)
3410 if (upper
> max_length
)
3415 else if ((attr
= ippFindAttribute(response
, "media-supported", IPP_TAG_ZERO
)) != NULL
)
3417 for (i
= 0, count
= ippGetCount(attr
); i
< count
; i
++)
3419 const char *pwg_size
= ippGetString(attr
, i
, NULL
);
3421 cups_size_t temp
; /* Current size */
3423 if ((pwg
= pwgMediaForPWG(pwg_size
)) != NULL
)
3425 if (strstr(pwg_size
, "_max_") || strstr(pwg_size
, "_max."))
3427 if (pwg
->width
> max_width
)
3428 max_width
= pwg
->width
;
3429 if (pwg
->length
> max_length
)
3430 max_length
= pwg
->length
;
3432 else if (strstr(pwg_size
, "_min_") || strstr(pwg_size
, "_min."))
3434 if (pwg
->width
< min_width
)
3435 min_width
= pwg
->width
;
3436 if (pwg
->length
< min_length
)
3437 min_length
= pwg
->length
;
3441 temp
.width
= pwg
->width
;
3442 temp
.length
= pwg
->length
;
3443 temp
.bottom
= bottom
;
3448 if (temp
.bottom
== 0 && temp
.left
== 0 && temp
.right
== 0 && temp
.top
== 0)
3449 snprintf(temp
.media
, sizeof(temp
.media
), "%s.Borderless", pwg
->ppd
);
3451 strlcpy(temp
.media
, pwg
->ppd
, sizeof(temp
.media
));
3453 if (!cupsArrayFind(sizes
, &temp
))
3454 cupsArrayAdd(sizes
, &temp
);
3460 if (cupsArrayCount(sizes
) > 0)
3463 * List all of the standard sizes...
3466 char tleft
[256], /* Left string */
3467 tbottom
[256], /* Bottom string */
3468 tright
[256], /* Right string */
3469 ttop
[256], /* Top string */
3470 twidth
[256], /* Width string */
3471 tlength
[256]; /* Length string */
3473 cupsFilePrintf(fp
, "*OpenUI *PageSize: PickOne\n"
3474 "*OrderDependency: 10 AnySetup *PageSize\n"
3475 "*DefaultPageSize: %s\n", ppdname
);
3476 for (size
= (cups_size_t
*)cupsArrayFirst(sizes
); size
; size
= (cups_size_t
*)cupsArrayNext(sizes
))
3478 _cupsStrFormatd(twidth
, twidth
+ sizeof(twidth
), size
->width
* 72.0 / 2540.0, loc
);
3479 _cupsStrFormatd(tlength
, tlength
+ sizeof(tlength
), size
->length
* 72.0 / 2540.0, loc
);
3481 cupsFilePrintf(fp
, "*PageSize %s: \"<</PageSize[%s %s]>>setpagedevice\"\n", size
->media
, twidth
, tlength
);
3483 cupsFilePuts(fp
, "*CloseUI: *PageSize\n");
3485 cupsFilePrintf(fp
, "*OpenUI *PageRegion: PickOne\n"
3486 "*OrderDependency: 10 AnySetup *PageRegion\n"
3487 "*DefaultPageRegion: %s\n", ppdname
);
3488 for (size
= (cups_size_t
*)cupsArrayFirst(sizes
); size
; size
= (cups_size_t
*)cupsArrayNext(sizes
))
3490 _cupsStrFormatd(twidth
, twidth
+ sizeof(twidth
), size
->width
* 72.0 / 2540.0, loc
);
3491 _cupsStrFormatd(tlength
, tlength
+ sizeof(tlength
), size
->length
* 72.0 / 2540.0, loc
);
3493 cupsFilePrintf(fp
, "*PageRegion %s: \"<</PageSize[%s %s]>>setpagedevice\"\n", size
->media
, twidth
, tlength
);
3495 cupsFilePuts(fp
, "*CloseUI: *PageRegion\n");
3497 cupsFilePrintf(fp
, "*DefaultImageableArea: %s\n"
3498 "*DefaultPaperDimension: %s\n", ppdname
, ppdname
);
3500 for (size
= (cups_size_t
*)cupsArrayFirst(sizes
); size
; size
= (cups_size_t
*)cupsArrayNext(sizes
))
3502 _cupsStrFormatd(tleft
, tleft
+ sizeof(tleft
), size
->left
* 72.0 / 2540.0, loc
);
3503 _cupsStrFormatd(tbottom
, tbottom
+ sizeof(tbottom
), size
->bottom
* 72.0 / 2540.0, loc
);
3504 _cupsStrFormatd(tright
, tright
+ sizeof(tright
), (size
->width
- size
->right
) * 72.0 / 2540.0, loc
);
3505 _cupsStrFormatd(ttop
, ttop
+ sizeof(ttop
), (size
->length
- size
->top
) * 72.0 / 2540.0, loc
);
3506 _cupsStrFormatd(twidth
, twidth
+ sizeof(twidth
), size
->width
* 72.0 / 2540.0, loc
);
3507 _cupsStrFormatd(tlength
, tlength
+ sizeof(tlength
), size
->length
* 72.0 / 2540.0, loc
);
3509 cupsFilePrintf(fp
, "*ImageableArea %s: \"%s %s %s %s\"\n", size
->media
, tleft
, tbottom
, tright
, ttop
);
3510 cupsFilePrintf(fp
, "*PaperDimension %s: \"%s %s\"\n", size
->media
, twidth
, tlength
);
3513 cupsArrayDelete(sizes
);
3516 * Custom size support...
3519 if (max_width
> 0 && min_width
< INT_MAX
&& max_length
> 0 && min_length
< INT_MAX
)
3521 char tmax
[256], tmin
[256]; /* Min/max values */
3523 _cupsStrFormatd(tleft
, tleft
+ sizeof(tleft
), left
* 72.0 / 2540.0, loc
);
3524 _cupsStrFormatd(tbottom
, tbottom
+ sizeof(tbottom
), bottom
* 72.0 / 2540.0, loc
);
3525 _cupsStrFormatd(tright
, tright
+ sizeof(tright
), right
* 72.0 / 2540.0, loc
);
3526 _cupsStrFormatd(ttop
, ttop
+ sizeof(ttop
), top
* 72.0 / 2540.0, loc
);
3528 cupsFilePrintf(fp
, "*HWMargins: \"%s %s %s %s\"\n", tleft
, tbottom
, tright
, ttop
);
3530 _cupsStrFormatd(tmax
, tmax
+ sizeof(tmax
), max_width
* 72.0 / 2540.0, loc
);
3531 _cupsStrFormatd(tmin
, tmin
+ sizeof(tmin
), min_width
* 72.0 / 2540.0, loc
);
3532 cupsFilePrintf(fp
, "*ParamCustomPageSize Width: 1 points %s %s\n", tmin
, tmax
);
3534 _cupsStrFormatd(tmax
, tmax
+ sizeof(tmax
), max_length
* 72.0 / 2540.0, loc
);
3535 _cupsStrFormatd(tmin
, tmin
+ sizeof(tmin
), min_length
* 72.0 / 2540.0, loc
);
3536 cupsFilePrintf(fp
, "*ParamCustomPageSize Height: 2 points %s %s\n", tmin
, tmax
);
3538 cupsFilePuts(fp
, "*ParamCustomPageSize WidthOffset: 3 points 0 0\n");
3539 cupsFilePuts(fp
, "*ParamCustomPageSize HeightOffset: 4 points 0 0\n");
3540 cupsFilePuts(fp
, "*ParamCustomPageSize Orientation: 5 int 0 3\n");
3541 cupsFilePuts(fp
, "*CustomPageSize True: \"pop pop pop <</PageSize[5 -2 roll]/ImagingBBox null>>setpagedevice\"\n");
3546 cupsArrayDelete(sizes
);
3554 if ((attr
= ippFindAttribute(ippGetCollection(defattr
, 0), "media-source", IPP_TAG_ZERO
)) != NULL
)
3555 pwg_ppdize_name(ippGetString(attr
, 0, NULL
), ppdname
, sizeof(ppdname
));
3557 strlcpy(ppdname
, "Unknown", sizeof(ppdname
));
3559 if ((attr
= ippFindAttribute(response
, "media-source-supported", IPP_TAG_ZERO
)) != NULL
&& (count
= ippGetCount(attr
)) > 1)
3561 static const char * const sources
[] =
3562 { /* Standard "media-source" strings */
3615 cupsFilePrintf(fp
, "*OpenUI *InputSlot: PickOne\n"
3616 "*OrderDependency: 10 AnySetup *InputSlot\n"
3617 "*DefaultInputSlot: %s\n", ppdname
);
3618 for (i
= 0, count
= ippGetCount(attr
); i
< count
; i
++)
3620 keyword
= ippGetString(attr
, i
, NULL
);
3622 pwg_ppdize_name(keyword
, ppdname
, sizeof(ppdname
));
3624 for (j
= 0; j
< (int)(sizeof(sources
) / sizeof(sources
[0])); j
++)
3625 if (!strcmp(sources
[j
], keyword
))
3627 snprintf(msgid
, sizeof(msgid
), "media-source.%s", keyword
);
3628 cupsFilePrintf(fp
, "*InputSlot %s/%s: \"<</MediaPosition %d>>setpagedevice\"\n", ppdname
, _cupsLangString(lang
, msgid
), j
);
3632 cupsFilePuts(fp
, "*CloseUI: *InputSlot\n");
3639 if ((attr
= ippFindAttribute(ippGetCollection(defattr
, 0), "media-type", IPP_TAG_ZERO
)) != NULL
)
3640 pwg_ppdize_name(ippGetString(attr
, 0, NULL
), ppdname
, sizeof(ppdname
));
3642 strlcpy(ppdname
, "Unknown", sizeof(ppdname
));
3644 if ((attr
= ippFindAttribute(response
, "media-type-supported", IPP_TAG_ZERO
)) != NULL
&& (count
= ippGetCount(attr
)) > 1)
3646 cupsFilePrintf(fp
, "*OpenUI *MediaType: PickOne\n"
3647 "*OrderDependency: 10 AnySetup *MediaType\n"
3648 "*DefaultMediaType: %s\n", ppdname
);
3649 for (i
= 0; i
< count
; i
++)
3651 keyword
= ippGetString(attr
, i
, NULL
);
3653 pwg_ppdize_name(keyword
, ppdname
, sizeof(ppdname
));
3655 snprintf(msgid
, sizeof(msgid
), "media-type.%s", keyword
);
3656 if ((msgstr
= _cupsLangString(lang
, msgid
)) == msgid
|| !strcmp(msgid
, msgstr
))
3657 if ((msgstr
= _cupsMessageLookup(strings
, msgid
)) == msgid
)
3660 cupsFilePrintf(fp
, "*MediaType %s/%s: \"<</MediaType(%s)>>setpagedevice\"\n", ppdname
, msgstr
, ppdname
);
3662 cupsFilePuts(fp
, "*CloseUI: *MediaType\n");
3669 if ((attr
= ippFindAttribute(response
, "urf-supported", IPP_TAG_KEYWORD
)) == NULL
)
3670 if ((attr
= ippFindAttribute(response
, "pwg-raster-document-type-supported", IPP_TAG_KEYWORD
)) == NULL
)
3671 if ((attr
= ippFindAttribute(response
, "print-color-mode-supported", IPP_TAG_KEYWORD
)) == NULL
)
3672 attr
= ippFindAttribute(response
, "output-mode-supported", IPP_TAG_KEYWORD
);
3676 const char *default_color
= NULL
; /* Default */
3678 for (i
= 0, count
= ippGetCount(attr
); i
< count
; i
++)
3680 keyword
= ippGetString(attr
, i
, NULL
);
3682 if (!strcasecmp(keyword
, "black_1") || !strcmp(keyword
, "bi-level") || !strcmp(keyword
, "process-bi-level"))
3685 cupsFilePrintf(fp
, "*OpenUI *ColorModel/%s: PickOne\n"
3686 "*OrderDependency: 10 AnySetup *ColorModel\n", _cupsLangString(lang
, _("Color Mode")));
3688 cupsFilePrintf(fp
, "*ColorModel FastGray/%s: \"<</cupsColorSpace 3/cupsBitsPerColor 1/cupsColorOrder 0/cupsCompression 0>>setpagedevice\"\n", _cupsLangString(lang
, _("Fast Grayscale")));
3691 default_color
= "FastGray";
3693 else if (!strcasecmp(keyword
, "sgray_8") || !strcmp(keyword
, "W8") || !strcmp(keyword
, "monochrome") || !strcmp(keyword
, "process-monochrome"))
3696 cupsFilePrintf(fp
, "*OpenUI *ColorModel/%s: PickOne\n"
3697 "*OrderDependency: 10 AnySetup *ColorModel\n", _cupsLangString(lang
, _("Color Mode")));
3699 cupsFilePrintf(fp
, "*ColorModel Gray/%s: \"<</cupsColorSpace 18/cupsBitsPerColor 8/cupsColorOrder 0/cupsCompression 0>>setpagedevice\"\n", _cupsLangString(lang
, _("Grayscale")));
3701 if (!default_color
|| !strcmp(default_color
, "FastGray"))
3702 default_color
= "Gray";
3704 else if (!strcasecmp(keyword
, "srgb_8") || !strcmp(keyword
, "SRGB24") || !strcmp(keyword
, "color"))
3707 cupsFilePrintf(fp
, "*OpenUI *ColorModel/%s: PickOne\n"
3708 "*OrderDependency: 10 AnySetup *ColorModel\n", _cupsLangString(lang
, _("Color Mode")));
3710 cupsFilePrintf(fp
, "*ColorModel RGB/%s: \"<</cupsColorSpace 19/cupsBitsPerColor 8/cupsColorOrder 0/cupsCompression 0>>setpagedevice\"\n", _cupsLangString(lang
, _("Color")));
3712 default_color
= "RGB";
3714 else if (!strcasecmp(keyword
, "adobe-rgb_16") || !strcmp(keyword
, "ADOBERGB48"))
3717 cupsFilePrintf(fp
, "*OpenUI *ColorModel/%s: PickOne\n"
3718 "*OrderDependency: 10 AnySetup *ColorModel\n", _cupsLangString(lang
, _("Color Mode")));
3720 cupsFilePrintf(fp
, "*ColorModel AdobeRGB/%s: \"<</cupsColorSpace 20/cupsBitsPerColor 16/cupsColorOrder 0/cupsCompression 0>>setpagedevice\"\n", _cupsLangString(lang
, _("Deep Color")));
3723 default_color
= "AdobeRGB";
3729 cupsFilePrintf(fp
, "*DefaultColorModel: %s\n", default_color
);
3730 cupsFilePuts(fp
, "*CloseUI: *ColorModel\n");
3738 if ((attr
= ippFindAttribute(response
, "sides-supported", IPP_TAG_KEYWORD
)) != NULL
&& ippContainsString(attr
, "two-sided-long-edge"))
3740 cupsFilePrintf(fp
, "*OpenUI *Duplex/%s: PickOne\n"
3741 "*OrderDependency: 10 AnySetup *Duplex\n"
3742 "*DefaultDuplex: None\n"
3743 "*Duplex None/%s: \"<</Duplex false>>setpagedevice\"\n"
3744 "*Duplex DuplexNoTumble/%s: \"<</Duplex true/Tumble false>>setpagedevice\"\n"
3745 "*Duplex DuplexTumble/%s: \"<</Duplex true/Tumble true>>setpagedevice\"\n"
3746 "*CloseUI: *Duplex\n", _cupsLangString(lang
, _("2-Sided Printing")), _cupsLangString(lang
, _("Off (1-Sided)")), _cupsLangString(lang
, _("Long-Edge (Portrait)")), _cupsLangString(lang
, _("Short-Edge (Landscape)")));
3748 if ((attr
= ippFindAttribute(response
, "urf-supported", IPP_TAG_KEYWORD
)) != NULL
)
3750 for (i
= 0, count
= ippGetCount(attr
); i
< count
; i
++)
3752 const char *dm
= ippGetString(attr
, i
, NULL
);
3755 if (!_cups_strcasecmp(dm
, "DM1"))
3757 cupsFilePuts(fp
, "*cupsBackSide: Normal\n");
3760 else if (!_cups_strcasecmp(dm
, "DM2"))
3762 cupsFilePuts(fp
, "*cupsBackSide: Flipped\n");
3765 else if (!_cups_strcasecmp(dm
, "DM3"))
3767 cupsFilePuts(fp
, "*cupsBackSide: Rotated\n");
3770 else if (!_cups_strcasecmp(dm
, "DM4"))
3772 cupsFilePuts(fp
, "*cupsBackSide: ManualTumble\n");
3777 else if ((attr
= ippFindAttribute(response
, "pwg-raster-document-sheet-back", IPP_TAG_KEYWORD
)) != NULL
)
3779 keyword
= ippGetString(attr
, 0, NULL
);
3781 if (!strcmp(keyword
, "flipped"))
3782 cupsFilePuts(fp
, "*cupsBackSide: Flipped\n");
3783 else if (!strcmp(keyword
, "manual-tumble"))
3784 cupsFilePuts(fp
, "*cupsBackSide: ManualTumble\n");
3785 else if (!strcmp(keyword
, "normal"))
3786 cupsFilePuts(fp
, "*cupsBackSide: Normal\n");
3788 cupsFilePuts(fp
, "*cupsBackSide: Rotated\n");
3796 if ((attr
= ippFindAttribute(response
, "output-bin-default", IPP_TAG_ZERO
)) != NULL
)
3797 pwg_ppdize_name(ippGetString(attr
, 0, NULL
), ppdname
, sizeof(ppdname
));
3799 strlcpy(ppdname
, "Unknown", sizeof(ppdname
));
3801 if ((attr
= ippFindAttribute(response
, "output-bin-supported", IPP_TAG_ZERO
)) != NULL
&& (count
= ippGetCount(attr
)) > 1)
3803 cupsFilePrintf(fp
, "*OpenUI *OutputBin: PickOne\n"
3804 "*OrderDependency: 10 AnySetup *OutputBin\n"
3805 "*DefaultOutputBin: %s\n", ppdname
);
3806 for (i
= 0; i
< count
; i
++)
3808 keyword
= ippGetString(attr
, i
, NULL
);
3810 pwg_ppdize_name(keyword
, ppdname
, sizeof(ppdname
));
3812 snprintf(msgid
, sizeof(msgid
), "output-bin.%s", keyword
);
3813 if ((msgstr
= _cupsLangString(lang
, msgid
)) == msgid
|| !strcmp(msgid
, msgstr
))
3814 if ((msgstr
= _cupsMessageLookup(strings
, msgid
)) == msgid
)
3817 cupsFilePrintf(fp
, "*OutputBin %s/%s: \"\"\n", ppdname
, msgstr
);
3819 cupsFilePuts(fp
, "*CloseUI: *OutputBin\n");
3823 * Finishing options...
3826 if ((attr
= ippFindAttribute(response
, "finishings-supported", IPP_TAG_ENUM
)) != NULL
)
3828 int value
; /* Enum value */
3829 cups_array_t
*names
; /* Names we've added */
3831 count
= ippGetCount(attr
);
3832 names
= cupsArrayNew3((cups_array_func_t
)strcmp
, NULL
, NULL
, 0, (cups_acopy_func_t
)strdup
, (cups_afree_func_t
)free
);
3833 fin_options
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
3836 * Staple/Bind/Stitch
3839 for (i
= 0; i
< count
; i
++)
3841 value
= ippGetInteger(attr
, i
);
3842 keyword
= ippEnumString("finishings", value
);
3844 if (!strncmp(keyword
, "staple-", 7) || !strncmp(keyword
, "bind-", 5) || !strncmp(keyword
, "edge-stitch-", 12) || !strcmp(keyword
, "saddle-stitch"))
3850 cupsArrayAdd(fin_options
, "*StapleLocation");
3852 cupsFilePrintf(fp
, "*OpenUI *StapleLocation/%s: PickOne\n", _cupsLangString(lang
, _("Staple")));
3853 cupsFilePuts(fp
, "*OrderDependency: 10 AnySetup *StapleLocation\n");
3854 cupsFilePuts(fp
, "*DefaultStapleLocation: None\n");
3855 cupsFilePrintf(fp
, "*StapleLocation None/%s: \"\"\n", _cupsLangString(lang
, _("None")));
3857 for (; i
< count
; i
++)
3859 value
= ippGetInteger(attr
, i
);
3860 keyword
= ippEnumString("finishings", value
);
3862 if (strncmp(keyword
, "staple-", 7) && strncmp(keyword
, "bind-", 5) && strncmp(keyword
, "edge-stitch-", 12) && strcmp(keyword
, "saddle-stitch"))
3865 if (cupsArrayFind(names
, (char *)keyword
))
3866 continue; /* Already did this finishing template */
3868 cupsArrayAdd(names
, (char *)keyword
);
3870 snprintf(msgid
, sizeof(msgid
), "finishings.%d", value
);
3871 if ((msgstr
= _cupsLangString(lang
, msgid
)) == msgid
|| !strcmp(msgid
, msgstr
))
3872 if ((msgstr
= _cupsMessageLookup(strings
, msgid
)) == msgid
)
3875 cupsFilePrintf(fp
, "*StapleLocation %s/%s: \"\"\n", keyword
, msgstr
);
3876 cupsFilePrintf(fp
, "*cupsIPPFinishings %d/%s: \"*StapleLocation %s\"\n", value
, keyword
, keyword
);
3879 cupsFilePuts(fp
, "*CloseUI: *StapleLocation\n");
3886 for (i
= 0; i
< count
; i
++)
3888 value
= ippGetInteger(attr
, i
);
3889 keyword
= ippEnumString("finishings", value
);
3891 if (!strncmp(keyword
, "fold-", 5))
3897 cupsArrayAdd(fin_options
, "*FoldType");
3899 cupsFilePrintf(fp
, "*OpenUI *FoldType/%s: PickOne\n", _cupsLangString(lang
, _("Fold")));
3900 cupsFilePuts(fp
, "*OrderDependency: 10 AnySetup *FoldType\n");
3901 cupsFilePuts(fp
, "*DefaultFoldType: None\n");
3902 cupsFilePrintf(fp
, "*FoldType None/%s: \"\"\n", _cupsLangString(lang
, _("None")));
3904 for (; i
< count
; i
++)
3906 value
= ippGetInteger(attr
, i
);
3907 keyword
= ippEnumString("finishings", value
);
3909 if (strncmp(keyword
, "fold-", 5))
3912 if (cupsArrayFind(names
, (char *)keyword
))
3913 continue; /* Already did this finishing template */
3915 cupsArrayAdd(names
, (char *)keyword
);
3917 snprintf(msgid
, sizeof(msgid
), "finishings.%d", value
);
3918 if ((msgstr
= _cupsLangString(lang
, msgid
)) == msgid
|| !strcmp(msgid
, msgstr
))
3919 if ((msgstr
= _cupsMessageLookup(strings
, msgid
)) == msgid
)
3922 cupsFilePrintf(fp
, "*FoldType %s/%s: \"\"\n", keyword
, msgstr
);
3923 cupsFilePrintf(fp
, "*cupsIPPFinishings %d/%s: \"*FoldType %s\"\n", value
, keyword
, keyword
);
3926 cupsFilePuts(fp
, "*CloseUI: *FoldType\n");
3933 for (i
= 0; i
< count
; i
++)
3935 value
= ippGetInteger(attr
, i
);
3936 keyword
= ippEnumString("finishings", value
);
3938 if (!strncmp(keyword
, "punch-", 6))
3944 cupsArrayAdd(fin_options
, "*PunchMedia");
3946 cupsFilePrintf(fp
, "*OpenUI *PunchMedia/%s: PickOne\n", _cupsLangString(lang
, _("Punch")));
3947 cupsFilePuts(fp
, "*OrderDependency: 10 AnySetup *PunchMedia\n");
3948 cupsFilePuts(fp
, "*DefaultPunchMedia: None\n");
3949 cupsFilePrintf(fp
, "*PunchMedia None/%s: \"\"\n", _cupsLangString(lang
, _("None")));
3951 for (i
= 0; i
< count
; i
++)
3953 value
= ippGetInteger(attr
, i
);
3954 keyword
= ippEnumString("finishings", value
);
3956 if (strncmp(keyword
, "punch-", 6))
3959 if (cupsArrayFind(names
, (char *)keyword
))
3960 continue; /* Already did this finishing template */
3962 cupsArrayAdd(names
, (char *)keyword
);
3964 snprintf(msgid
, sizeof(msgid
), "finishings.%d", value
);
3965 if ((msgstr
= _cupsLangString(lang
, msgid
)) == msgid
|| !strcmp(msgid
, msgstr
))
3966 if ((msgstr
= _cupsMessageLookup(strings
, msgid
)) == msgid
)
3969 cupsFilePrintf(fp
, "*PunchMedia %s/%s: \"\"\n", keyword
, msgstr
);
3970 cupsFilePrintf(fp
, "*cupsIPPFinishings %d/%s: \"*PunchMedia %s\"\n", value
, keyword
, keyword
);
3973 cupsFilePuts(fp
, "*CloseUI: *PunchMedia\n");
3980 if (ippContainsInteger(attr
, IPP_FINISHINGS_BOOKLET_MAKER
))
3982 cupsArrayAdd(fin_options
, "*Booklet");
3984 cupsFilePrintf(fp
, "*OpenUI *Booklet/%s: Boolean\n", _cupsLangString(lang
, _("Booklet")));
3985 cupsFilePuts(fp
, "*OrderDependency: 10 AnySetup *Booklet\n");
3986 cupsFilePuts(fp
, "*DefaultBooklet: False\n");
3987 cupsFilePuts(fp
, "*Booklet False: \"\"\n");
3988 cupsFilePuts(fp
, "*Booklet True: \"\"\n");
3989 cupsFilePrintf(fp
, "*cupsIPPFinishings %d/booklet-maker: \"*Booklet True\"\n", IPP_FINISHINGS_BOOKLET_MAKER
);
3990 cupsFilePuts(fp
, "*CloseUI: *Booklet\n");
3993 cupsArrayDelete(names
);
3996 if ((attr
= ippFindAttribute(response
, "finishings-col-database", IPP_TAG_BEGIN_COLLECTION
)) != NULL
)
3998 ipp_t
*finishing_col
; /* Current finishing collection */
3999 ipp_attribute_t
*finishing_attr
; /* Current finishing member attribute */
4000 cups_array_t
*templates
; /* Finishing templates */
4002 cupsFilePrintf(fp
, "*OpenUI *cupsFinishingTemplate/%s: PickOne\n", _cupsLangString(lang
, _("Finishing Preset")));
4003 cupsFilePuts(fp
, "*OrderDependency: 10 AnySetup *cupsFinishingTemplate\n");
4004 cupsFilePuts(fp
, "*DefaultcupsFinishingTemplate: none\n");
4005 cupsFilePrintf(fp
, "*cupsFinishingTemplate none/%s: \"\"\n", _cupsLangString(lang
, _("None")));
4007 templates
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
4008 count
= ippGetCount(attr
);
4010 for (i
= 0; i
< count
; i
++)
4012 finishing_col
= ippGetCollection(attr
, i
);
4013 keyword
= ippGetString(ippFindAttribute(finishing_col
, "finishing-template", IPP_TAG_ZERO
), 0, NULL
);
4015 if (!keyword
|| cupsArrayFind(templates
, (void *)keyword
))
4018 if (strncmp(keyword
, "fold-", 5) && (strstr(keyword
, "-bottom") || strstr(keyword
, "-left") || strstr(keyword
, "-right") || strstr(keyword
, "-top")))
4021 cupsArrayAdd(templates
, (void *)keyword
);
4023 snprintf(msgid
, sizeof(msgid
), "finishing-template.%s", keyword
);
4024 if ((msgstr
= _cupsLangString(lang
, msgid
)) == msgid
|| !strcmp(msgid
, msgstr
))
4025 if ((msgstr
= _cupsMessageLookup(strings
, msgid
)) == msgid
)
4028 cupsFilePrintf(fp
, "*cupsFinishingTemplate %s/%s: \"\n", keyword
, msgstr
);
4029 for (finishing_attr
= ippFirstAttribute(finishing_col
); finishing_attr
; finishing_attr
= ippNextAttribute(finishing_col
))
4031 if (ippGetValueTag(finishing_attr
) == IPP_TAG_BEGIN_COLLECTION
)
4033 const char *name
= ippGetName(finishing_attr
);
4034 /* Member attribute name */
4036 if (strcmp(name
, "media-size"))
4037 cupsFilePrintf(fp
, "%s\n", name
);
4040 cupsFilePuts(fp
, "\"\n");
4041 cupsFilePuts(fp
, "*End\n");
4044 cupsFilePuts(fp
, "*CloseUI: *cupsFinishingTemplate\n");
4046 if (cupsArrayCount(fin_options
))
4048 const char *fin_option
; /* Current finishing option */
4050 cupsFilePuts(fp
, "*cupsUIConstraint finishing-template: \"*cupsFinishingTemplate");
4051 for (fin_option
= (const char *)cupsArrayFirst(fin_options
); fin_option
; fin_option
= (const char *)cupsArrayNext(fin_options
))
4052 cupsFilePrintf(fp
, " %s", fin_option
);
4053 cupsFilePuts(fp
, "\"\n");
4055 cupsFilePuts(fp
, "*cupsUIResolver finishing-template: \"*cupsFinishingTemplate None");
4056 for (fin_option
= (const char *)cupsArrayFirst(fin_options
); fin_option
; fin_option
= (const char *)cupsArrayNext(fin_options
))
4057 cupsFilePrintf(fp
, " %s None", fin_option
);
4058 cupsFilePuts(fp
, "\"\n");
4061 cupsArrayDelete(templates
);
4064 cupsArrayDelete(fin_options
);
4067 * cupsPrintQuality and DefaultResolution...
4070 quality
= ippFindAttribute(response
, "print-quality-supported", IPP_TAG_ENUM
);
4072 if ((attr
= ippFindAttribute(response
, "urf-supported", IPP_TAG_KEYWORD
)) != NULL
)
4074 int lowdpi
= 0, hidpi
= 0; /* Lower and higher resolution */
4076 for (i
= 0, count
= ippGetCount(attr
); i
< count
; i
++)
4078 const char *rs
= ippGetString(attr
, i
, NULL
);
4081 if (_cups_strncasecmp(rs
, "RS", 2))
4084 lowdpi
= atoi(rs
+ 2);
4085 if ((rs
= strrchr(rs
, '-')) != NULL
)
4086 hidpi
= atoi(rs
+ 1);
4095 * Invalid "urf-supported" value...
4103 * Generate print qualities based on low and high DPIs...
4106 cupsFilePrintf(fp
, "*DefaultResolution: %ddpi\n", lowdpi
);
4108 cupsFilePrintf(fp
, "*OpenUI *cupsPrintQuality/%s: PickOne\n"
4109 "*OrderDependency: 10 AnySetup *cupsPrintQuality\n"
4110 "*DefaultcupsPrintQuality: Normal\n", _cupsLangString(lang
, _("Print Quality")));
4111 if ((lowdpi
& 1) == 0)
4112 cupsFilePrintf(fp
, "*cupsPrintQuality Draft/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang
, _("Draft")), lowdpi
, lowdpi
/ 2);
4113 else if (ippContainsInteger(quality
, IPP_QUALITY_DRAFT
))
4114 cupsFilePrintf(fp
, "*cupsPrintQuality Draft/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang
, _("Draft")), lowdpi
, lowdpi
);
4115 cupsFilePrintf(fp
, "*cupsPrintQuality Normal/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang
, _("Normal")), lowdpi
, lowdpi
);
4116 if (hidpi
> lowdpi
|| ippContainsInteger(quality
, IPP_QUALITY_HIGH
))
4117 cupsFilePrintf(fp
, "*cupsPrintQuality High/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang
, _("High")), hidpi
, hidpi
);
4118 cupsFilePuts(fp
, "*CloseUI: *cupsPrintQuality\n");
4121 else if ((attr
= ippFindAttribute(response
, "pwg-raster-document-resolution-supported", IPP_TAG_RESOLUTION
)) != NULL
)
4124 * Make a sorted list of resolutions.
4127 count
= ippGetCount(attr
);
4128 if (count
> (int)(sizeof(resolutions
) / sizeof(resolutions
[0])))
4129 count
= (int)(sizeof(resolutions
) / sizeof(resolutions
[0]));
4131 resolutions
[0] = 0; /* Not in loop to silence Clang static analyzer... */
4132 for (i
= 1; i
< count
; i
++)
4135 for (i
= 0; i
< (count
- 1); i
++)
4137 for (j
= i
+ 1; j
< count
; j
++)
4139 int ix
, iy
, /* First X and Y resolution */
4140 jx
, jy
, /* Second X and Y resolution */
4141 temp
; /* Swap variable */
4142 ipp_res_t units
; /* Resolution units */
4144 ix
= ippGetResolution(attr
, resolutions
[i
], &iy
, &units
);
4145 jx
= ippGetResolution(attr
, resolutions
[j
], &jy
, &units
);
4147 if (ix
> jx
|| (ix
== jx
&& iy
> jy
))
4150 * Swap these two resolutions...
4153 temp
= resolutions
[i
];
4154 resolutions
[i
] = resolutions
[j
];
4155 resolutions
[j
] = temp
;
4161 * Generate print quality options...
4164 pwg_ppdize_resolution(attr
, resolutions
[count
/ 2], &xres
, &yres
, ppdname
, sizeof(ppdname
));
4165 cupsFilePrintf(fp
, "*DefaultResolution: %s\n", ppdname
);
4167 cupsFilePrintf(fp
, "*OpenUI *cupsPrintQuality/%s: PickOne\n"
4168 "*OrderDependency: 10 AnySetup *cupsPrintQuality\n"
4169 "*DefaultcupsPrintQuality: Normal\n", _cupsLangString(lang
, _("Print Quality")));
4170 if (count
> 2 || ippContainsInteger(quality
, IPP_QUALITY_DRAFT
))
4172 pwg_ppdize_resolution(attr
, resolutions
[0], &xres
, &yres
, NULL
, 0);
4173 cupsFilePrintf(fp
, "*cupsPrintQuality Draft/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang
, _("Draft")), xres
, yres
);
4175 pwg_ppdize_resolution(attr
, resolutions
[count
/ 2], &xres
, &yres
, NULL
, 0);
4176 cupsFilePrintf(fp
, "*cupsPrintQuality Normal/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang
, _("Normal")), xres
, yres
);
4177 if (count
> 1 || ippContainsInteger(quality
, IPP_QUALITY_HIGH
))
4179 pwg_ppdize_resolution(attr
, resolutions
[count
- 1], &xres
, &yres
, NULL
, 0);
4180 cupsFilePrintf(fp
, "*cupsPrintQuality High/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang
, _("High")), xres
, yres
);
4183 cupsFilePuts(fp
, "*CloseUI: *cupsPrintQuality\n");
4185 else if (is_apple
|| is_pwg
)
4189 if ((attr
= ippFindAttribute(response
, "printer-resolution-default", IPP_TAG_RESOLUTION
)) != NULL
)
4191 pwg_ppdize_resolution(attr
, 0, &xres
, &yres
, ppdname
, sizeof(ppdname
));
4196 strlcpy(ppdname
, "300dpi", sizeof(ppdname
));
4199 cupsFilePrintf(fp
, "*DefaultResolution: %s\n", ppdname
);
4201 cupsFilePrintf(fp
, "*OpenUI *cupsPrintQuality/%s: PickOne\n"
4202 "*OrderDependency: 10 AnySetup *cupsPrintQuality\n"
4203 "*DefaultcupsPrintQuality: Normal\n", _cupsLangString(lang
, _("Print Quality")));
4204 if (ippContainsInteger(quality
, IPP_QUALITY_DRAFT
))
4205 cupsFilePrintf(fp
, "*cupsPrintQuality Draft/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang
, _("Draft")), xres
, yres
);
4206 cupsFilePrintf(fp
, "*cupsPrintQuality Normal/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang
, _("Normal")), xres
, yres
);
4207 if (ippContainsInteger(quality
, IPP_QUALITY_HIGH
))
4208 cupsFilePrintf(fp
, "*cupsPrintQuality High/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang
, _("High")), xres
, yres
);
4209 cupsFilePuts(fp
, "*CloseUI: *cupsPrintQuality\n");
4216 if ((attr
= ippFindAttribute(response
, "job-presets-supported", IPP_TAG_BEGIN_COLLECTION
)) != NULL
)
4218 for (i
= 0, count
= ippGetCount(attr
); i
< count
; i
++)
4220 ipp_t
*preset
= ippGetCollection(attr
, i
);
4221 /* Preset collection */
4222 const char *preset_name
= ippGetString(ippFindAttribute(preset
, "preset-name", IPP_TAG_ZERO
), 0, NULL
),
4224 *localized_name
; /* Localized preset name */
4225 ipp_attribute_t
*member
; /* Member attribute in preset */
4226 const char *member_name
; /* Member attribute name */
4227 char member_value
[256]; /* Member attribute value */
4229 if (!preset
|| !preset_name
)
4232 if ((localized_name
= _cupsMessageLookup(strings
, preset_name
)) == preset_name
)
4233 cupsFilePrintf(fp
, "*APPrinterPreset %s: \"\n", preset_name
);
4235 cupsFilePrintf(fp
, "*APPrinterPreset %s/%s: \"\n", preset_name
, localized_name
);
4237 for (member
= ippFirstAttribute(preset
); member
; member
= ippNextAttribute(preset
))
4239 member_name
= ippGetName(member
);
4241 if (!member_name
|| !strcmp(member_name
, "preset-name"))
4244 if (!strcmp(member_name
, "finishings"))
4246 for (i
= 0, count
= ippGetCount(member
); i
< count
; i
++)
4248 const char *option
= NULL
; /* PPD option name */
4250 keyword
= ippEnumString("finishings", ippGetInteger(member
, i
));
4252 if (!strcmp(keyword
, "booklet-maker"))
4257 else if (!strncmp(keyword
, "fold-", 5))
4258 option
= "FoldType";
4259 else if (!strncmp(keyword
, "punch-", 6))
4260 option
= "PunchMedia";
4261 else if (!strncmp(keyword
, "bind-", 5) || !strncmp(keyword
, "edge-stitch-", 12) || !strcmp(keyword
, "saddle-stitch") || !strncmp(keyword
, "staple-", 7))
4262 option
= "StapleLocation";
4264 if (option
&& keyword
)
4265 cupsFilePrintf(fp
, "*%s %s\n", option
, keyword
);
4268 else if (!strcmp(member_name
, "finishings-col"))
4270 ipp_t
*fin_col
; /* finishings-col value */
4272 for (i
= 0, count
= ippGetCount(member
); i
< count
; i
++)
4274 fin_col
= ippGetCollection(member
, i
);
4276 if ((keyword
= ippGetString(ippFindAttribute(fin_col
, "finishing-template", IPP_TAG_ZERO
), 0, NULL
)) != NULL
)
4277 cupsFilePrintf(fp
, "*cupsFinishingTemplate %s\n", keyword
);
4280 else if (!strcmp(member_name
, "media"))
4283 * Map media to PageSize...
4286 if ((pwg
= pwgMediaForPWG(ippGetString(member
, 0, NULL
))) != NULL
&& pwg
->ppd
)
4287 cupsFilePrintf(fp
, "*PageSize %s\n", pwg
->ppd
);
4289 else if (!strcmp(member_name
, "media-col"))
4291 media_col
= ippGetCollection(member
, 0);
4293 if ((media_size
= ippGetCollection(ippFindAttribute(media_col
, "media-size", IPP_TAG_BEGIN_COLLECTION
), 0)) != NULL
)
4295 x_dim
= ippFindAttribute(media_size
, "x-dimension", IPP_TAG_INTEGER
);
4296 y_dim
= ippFindAttribute(media_size
, "y-dimension", IPP_TAG_INTEGER
);
4297 if ((pwg
= pwgMediaForSize(ippGetInteger(x_dim
, 0), ippGetInteger(y_dim
, 0))) != NULL
&& pwg
->ppd
)
4298 cupsFilePrintf(fp
, "*PageSize %s\n", pwg
->ppd
);
4301 if ((keyword
= ippGetString(ippFindAttribute(media_col
, "media-source", IPP_TAG_ZERO
), 0, NULL
)) != NULL
)
4303 pwg_ppdize_name(keyword
, ppdname
, sizeof(ppdname
));
4304 cupsFilePrintf(fp
, "*InputSlot %s\n", keyword
);
4307 if ((keyword
= ippGetString(ippFindAttribute(media_col
, "media-type", IPP_TAG_ZERO
), 0, NULL
)) != NULL
)
4309 pwg_ppdize_name(keyword
, ppdname
, sizeof(ppdname
));
4310 cupsFilePrintf(fp
, "*MediaType %s\n", keyword
);
4313 else if (!strcmp(member_name
, "print-quality"))
4316 * Map print-quality to cupsPrintQuality...
4319 int qval
= ippGetInteger(member
, 0);
4320 /* print-quality value */
4321 static const char * const qualities
[] = { "Draft", "Normal", "High" };
4322 /* cupsPrintQuality values */
4324 if (qval
>= IPP_QUALITY_DRAFT
&& qval
<= IPP_QUALITY_HIGH
)
4325 cupsFilePrintf(fp
, "*cupsPrintQuality %s\n", qualities
[qval
- IPP_QUALITY_DRAFT
]);
4327 else if (!strcmp(member_name
, "output-bin"))
4329 pwg_ppdize_name(ippGetString(member
, 0, NULL
), ppdname
, sizeof(ppdname
));
4330 cupsFilePrintf(fp
, "*OutputBin %s\n", ppdname
);
4332 else if (!strcmp(member_name
, "sides"))
4334 keyword
= ippGetString(member
, 0, NULL
);
4335 if (keyword
&& !strcmp(keyword
, "one-sided"))
4336 cupsFilePuts(fp
, "*Duplex None\n");
4337 else if (keyword
&& !strcmp(keyword
, "two-sided-long-edge"))
4338 cupsFilePuts(fp
, "*Duplex DuplexNoTumble\n");
4339 else if (keyword
&& !strcmp(keyword
, "two-sided-short-edge"))
4340 cupsFilePuts(fp
, "*Duplex DuplexTumble\n");
4345 * Add attribute name and value as-is...
4348 ippAttributeString(member
, member_value
, sizeof(member_value
));
4349 cupsFilePrintf(fp
, "*%s %s\n", member_name
, member_value
);
4353 cupsFilePuts(fp
, "\"\n*End\n");
4358 * Close up and return...
4366 * If we get here then there was a problem creating the PPD...
4375 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Printer does not support required IPP attributes or document formats."), 1);
4382 * '_pwgInputSlotForSource()' - Get the InputSlot name for the given PWG
4386 const char * /* O - InputSlot name */
4387 _pwgInputSlotForSource(
4388 const char *media_source
, /* I - PWG media-source */
4389 char *name
, /* I - Name buffer */
4390 size_t namesize
) /* I - Size of name buffer */
4393 * Range check input...
4396 if (!media_source
|| !name
|| namesize
< PPD_MAX_NAME
)
4399 if (_cups_strcasecmp(media_source
, "main"))
4400 strlcpy(name
, "Cassette", namesize
);
4401 else if (_cups_strcasecmp(media_source
, "alternate"))
4402 strlcpy(name
, "Multipurpose", namesize
);
4403 else if (_cups_strcasecmp(media_source
, "large-capacity"))
4404 strlcpy(name
, "LargeCapacity", namesize
);
4405 else if (_cups_strcasecmp(media_source
, "bottom"))
4406 strlcpy(name
, "Lower", namesize
);
4407 else if (_cups_strcasecmp(media_source
, "middle"))
4408 strlcpy(name
, "Middle", namesize
);
4409 else if (_cups_strcasecmp(media_source
, "top"))
4410 strlcpy(name
, "Upper", namesize
);
4411 else if (_cups_strcasecmp(media_source
, "rear"))
4412 strlcpy(name
, "Rear", namesize
);
4413 else if (_cups_strcasecmp(media_source
, "side"))
4414 strlcpy(name
, "Side", namesize
);
4415 else if (_cups_strcasecmp(media_source
, "envelope"))
4416 strlcpy(name
, "Envelope", namesize
);
4417 else if (_cups_strcasecmp(media_source
, "main-roll"))
4418 strlcpy(name
, "Roll", namesize
);
4419 else if (_cups_strcasecmp(media_source
, "alternate-roll"))
4420 strlcpy(name
, "Roll2", namesize
);
4422 pwg_ppdize_name(media_source
, name
, namesize
);
4429 * '_pwgMediaTypeForType()' - Get the MediaType name for the given PWG
4433 const char * /* O - MediaType name */
4434 _pwgMediaTypeForType(
4435 const char *media_type
, /* I - PWG media-type */
4436 char *name
, /* I - Name buffer */
4437 size_t namesize
) /* I - Size of name buffer */
4440 * Range check input...
4443 if (!media_type
|| !name
|| namesize
< PPD_MAX_NAME
)
4446 if (_cups_strcasecmp(media_type
, "auto"))
4447 strlcpy(name
, "Auto", namesize
);
4448 else if (_cups_strcasecmp(media_type
, "cardstock"))
4449 strlcpy(name
, "Cardstock", namesize
);
4450 else if (_cups_strcasecmp(media_type
, "envelope"))
4451 strlcpy(name
, "Envelope", namesize
);
4452 else if (_cups_strcasecmp(media_type
, "photographic-glossy"))
4453 strlcpy(name
, "Glossy", namesize
);
4454 else if (_cups_strcasecmp(media_type
, "photographic-high-gloss"))
4455 strlcpy(name
, "HighGloss", namesize
);
4456 else if (_cups_strcasecmp(media_type
, "photographic-matte"))
4457 strlcpy(name
, "Matte", namesize
);
4458 else if (_cups_strcasecmp(media_type
, "stationery"))
4459 strlcpy(name
, "Plain", namesize
);
4460 else if (_cups_strcasecmp(media_type
, "stationery-coated"))
4461 strlcpy(name
, "Coated", namesize
);
4462 else if (_cups_strcasecmp(media_type
, "stationery-inkjet"))
4463 strlcpy(name
, "Inkjet", namesize
);
4464 else if (_cups_strcasecmp(media_type
, "stationery-letterhead"))
4465 strlcpy(name
, "Letterhead", namesize
);
4466 else if (_cups_strcasecmp(media_type
, "stationery-preprinted"))
4467 strlcpy(name
, "Preprinted", namesize
);
4468 else if (_cups_strcasecmp(media_type
, "transparency"))
4469 strlcpy(name
, "Transparency", namesize
);
4471 pwg_ppdize_name(media_type
, name
, namesize
);
4478 * '_pwgPageSizeForMedia()' - Get the PageSize name for the given media.
4481 const char * /* O - PageSize name */
4482 _pwgPageSizeForMedia(
4483 pwg_media_t
*media
, /* I - Media */
4484 char *name
, /* I - PageSize name buffer */
4485 size_t namesize
) /* I - Size of name buffer */
4487 const char *sizeptr
, /* Pointer to size in PWG name */
4488 *dimptr
; /* Pointer to dimensions in PWG name */
4492 * Range check input...
4495 if (!media
|| !name
|| namesize
< PPD_MAX_NAME
)
4499 * Copy or generate a PageSize name...
4505 * Use a standard Adobe name...
4508 strlcpy(name
, media
->ppd
, namesize
);
4510 else if (!media
->pwg
|| !strncmp(media
->pwg
, "custom_", 7) ||
4511 (sizeptr
= strchr(media
->pwg
, '_')) == NULL
||
4512 (dimptr
= strchr(sizeptr
+ 1, '_')) == NULL
||
4513 (size_t)(dimptr
- sizeptr
) > namesize
)
4516 * Use a name of the form "wNNNhNNN"...
4519 snprintf(name
, namesize
, "w%dh%d", (int)PWG_TO_POINTS(media
->width
),
4520 (int)PWG_TO_POINTS(media
->length
));
4525 * Copy the size name from class_sizename_dimensions...
4528 memcpy(name
, sizeptr
+ 1, (size_t)(dimptr
- sizeptr
- 1));
4529 name
[dimptr
- sizeptr
- 1] = '\0';
4537 * 'cups_get_url()' - Get a copy of the file at the given URL.
4540 static int /* O - 1 on success, 0 on failure */
4541 cups_get_url(http_t
**http
, /* IO - Current HTTP connection */
4542 const char *url
, /* I - URL to get */
4543 char *name
, /* I - Temporary filename */
4544 size_t namesize
) /* I - Size of temporary filename buffer */
4546 char scheme
[32], /* URL scheme */
4547 userpass
[256], /* URL username:password */
4548 host
[256], /* URL host */
4549 curhost
[256], /* Current host */
4550 resource
[256]; /* URL resource */
4551 int port
; /* URL port */
4552 http_encryption_t encryption
; /* Type of encryption to use */
4553 http_status_t status
; /* Status of GET request */
4554 int fd
; /* Temporary file */
4557 if (httpSeparateURI(HTTP_URI_CODING_ALL
, url
, scheme
, sizeof(scheme
), userpass
, sizeof(userpass
), host
, sizeof(host
), &port
, resource
, sizeof(resource
)) < HTTP_URI_STATUS_OK
)
4560 if (port
== 443 || !strcmp(scheme
, "https"))
4561 encryption
= HTTP_ENCRYPTION_ALWAYS
;
4563 encryption
= HTTP_ENCRYPTION_IF_REQUESTED
;
4565 if (!*http
|| strcasecmp(host
, httpGetHostname(*http
, curhost
, sizeof(curhost
))) || httpAddrPort(httpGetAddress(*http
)) != port
)
4568 *http
= httpConnect2(host
, port
, NULL
, AF_UNSPEC
, encryption
, 1, 5000, NULL
);
4574 if ((fd
= cupsTempFd(name
, (int)namesize
)) < 0)
4577 status
= cupsGetFd(*http
, resource
, fd
);
4581 if (status
!= HTTP_STATUS_OK
)
4593 * 'pwg_add_finishing()' - Add a finishings value.
4598 cups_array_t
*finishings
, /* I - Finishings array */
4599 ipp_finishings_t
template, /* I - Finishing template */
4600 const char *name
, /* I - PPD option */
4601 const char *value
) /* I - PPD choice */
4603 _pwg_finishings_t
*f
; /* New finishings value */
4606 if ((f
= (_pwg_finishings_t
*)calloc(1, sizeof(_pwg_finishings_t
))) != NULL
)
4608 f
->value
= template;
4609 f
->num_options
= cupsAddOption(name
, value
, 0, &f
->options
);
4611 cupsArrayAdd(finishings
, f
);
4617 * 'pwg_compare_finishings()' - Compare two finishings values.
4620 static int /* O - Result of comparison */
4621 pwg_compare_finishings(
4622 _pwg_finishings_t
*a
, /* I - First finishings value */
4623 _pwg_finishings_t
*b
) /* I - Second finishings value */
4625 return ((int)b
->value
- (int)a
->value
);
4630 * 'pwg_compare_sizes()' - Compare two media sizes...
4633 static int /* O - Result of comparison */
4634 pwg_compare_sizes(cups_size_t
*a
, /* I - First media size */
4635 cups_size_t
*b
) /* I - Second media size */
4637 return (strcmp(a
->media
, b
->media
));
4642 * 'pwg_copy_size()' - Copy a media size.
4645 static cups_size_t
* /* O - New media size */
4646 pwg_copy_size(cups_size_t
*size
) /* I - Media size to copy */
4648 cups_size_t
*newsize
= (cups_size_t
*)calloc(1, sizeof(cups_size_t
));
4649 /* New media size */
4652 memcpy(newsize
, size
, sizeof(cups_size_t
));
4659 * 'pwg_free_finishings()' - Free a finishings value.
4663 pwg_free_finishings(
4664 _pwg_finishings_t
*f
) /* I - Finishings value */
4666 cupsFreeOptions(f
->num_options
, f
->options
);
4672 * 'pwg_ppdize_name()' - Convert an IPP keyword to a PPD keyword.
4676 pwg_ppdize_name(const char *ipp
, /* I - IPP keyword */
4677 char *name
, /* I - Name buffer */
4678 size_t namesize
) /* I - Size of name buffer */
4680 char *ptr
, /* Pointer into name buffer */
4681 *end
; /* End of name buffer */
4690 *name
= (char)toupper(*ipp
++);
4692 for (ptr
= name
+ 1, end
= name
+ namesize
- 1; *ipp
&& ptr
< end
;)
4694 if (*ipp
== '-' && _cups_isalnum(ipp
[1]))
4697 *ptr
++ = (char)toupper(*ipp
++ & 255);
4708 * 'pwg_ppdize_resolution()' - Convert PWG resolution values to PPD values.
4712 pwg_ppdize_resolution(
4713 ipp_attribute_t
*attr
, /* I - Attribute to convert */
4714 int element
, /* I - Element to convert */
4715 int *xres
, /* O - X resolution in DPI */
4716 int *yres
, /* O - Y resolution in DPI */
4717 char *name
, /* I - Name buffer */
4718 size_t namesize
) /* I - Size of name buffer */
4720 ipp_res_t units
; /* Units for resolution */
4723 *xres
= ippGetResolution(attr
, element
, yres
, &units
);
4725 if (units
== IPP_RES_PER_CM
)
4727 *xres
= (int)(*xres
* 2.54);
4728 *yres
= (int)(*yres
* 2.54);
4731 if (name
&& namesize
> 4)
4734 snprintf(name
, namesize
, "%ddpi", *xres
);
4736 snprintf(name
, namesize
, "%dx%ddpi", *xres
, *yres
);
4742 * 'pwg_unppdize_name()' - Convert a PPD keyword to a lowercase IPP keyword.
4746 pwg_unppdize_name(const char *ppd
, /* I - PPD keyword */
4747 char *name
, /* I - Name buffer */
4748 size_t namesize
, /* I - Size of name buffer */
4749 const char *dashchars
)/* I - Characters to be replaced by dashes */
4751 char *ptr
, /* Pointer into name buffer */
4752 *end
; /* End of name buffer */
4755 if (_cups_islower(*ppd
))
4758 * Already lowercase name, use as-is?
4761 const char *ppdptr
; /* Pointer into PPD keyword */
4763 for (ppdptr
= ppd
+ 1; *ppdptr
; ppdptr
++)
4764 if (_cups_isupper(*ppdptr
) || strchr(dashchars
, *ppdptr
))
4769 strlcpy(name
, ppd
, namesize
);
4774 for (ptr
= name
, end
= name
+ namesize
- 1; *ppd
&& ptr
< end
; ppd
++)
4776 if (_cups_isalnum(*ppd
) || *ppd
== '-')
4777 *ptr
++ = (char)tolower(*ppd
& 255);
4778 else if (strchr(dashchars
, *ppd
))
4783 if (!_cups_isupper(*ppd
) && _cups_isalnum(*ppd
) &&
4784 _cups_isupper(ppd
[1]) && ptr
< end
)
4786 else if (!isdigit(*ppd
& 255) && isdigit(ppd
[1] & 255))