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