]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/pwg-ppd.c
Merge changes from CUPS 1.5svn-r9214.
[thirdparty/cups.git] / cups / pwg-ppd.c
CommitLineData
54afec33
MS
1/*
2 * "$Id$"
3 *
4 * PWG PPD mapping API implementation for CUPS.
5 *
6 * Copyright 2010 by Apple Inc.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Apple Inc. and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
11 * which should have been included with this file. If this file is
12 * file is missing or damaged, see the license at "http://www.cups.org/".
13 *
14 * This file is subject to the Apple OS-Developed Software exception.
15 *
16 * Contents:
17 *
18 * _pwgCreateWithPPD() - Create PWG mapping data from a PPD file.
cc754834
MS
19 * _pwgGetBin() - Get the PWG output-bin keyword associated with a
20 * PPD OutputBin.
54afec33
MS
21 * _pwgGetInputSlot() - Get the PPD InputSlot associated with the job
22 * attributes or a keyword string.
23 * _pwgGetMediaType() - Get the PPD MediaType associated with the job
24 * attributes or a keyword string.
cc754834
MS
25 * _pwgGetOutputBin() - Get the PPD OutputBin associated with the
26 * keyword string.
54afec33
MS
27 * _pwgGetPageSize() - Get the PPD PageSize associated with the job
28 * attributes or a keyword string.
29 * _pwgGetSize() - Get the PWG size associated with a PPD PageSize.
30 * _pwgGetSource() - Get the PWG media-source associated with a PPD
31 * InputSlot.
32 * _pwgGetType() - Get the PWG media-type associated with a PPD
33 * MediaType.
34 * _pwgInputSlotForSource() - Get the InputSlot name for the given PWG source.
35 * _pwgMediaTypeForType() - Get the MediaType name for the given PWG type.
36 * _pwgPageSizeForMedia() - Get the PageSize name for the given media.
37 * pwg_ppdize_name() - Convert an IPP keyword to a PPD keyword.
38 * pwg_unppdize_name() - Convert a PPD keyword to a lowercase IPP
39 * keyword.
40 */
41
42/*
43 * Include necessary headers...
44 */
45
71e16022 46#include "cups-private.h"
54afec33
MS
47#include <math.h>
48
49
50/*
51 * Local functions...
52 */
53
54static void pwg_ppdize_name(const char *ipp, char *name, size_t namesize);
55static void pwg_unppdize_name(const char *ppd, char *name, size_t namesize);
56
57
58/*
59 * '_pwgCreateWithPPD()' - Create PWG mapping data from a PPD file.
60 */
61
62_pwg_t * /* O - PWG mapping data */
63_pwgCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */
64{
c7017ecc
MS
65 int i, j; /* Looping vars */
66 _pwg_t *pwg; /* PWG mapping data */
67 ppd_option_t *input_slot, /* InputSlot option */
68 *media_type, /* MediaType option */
69 *output_bin, /* OutputBin option */
70 *color_model, /* ColorModel option */
71 *duplex; /* Duplex option */
72 ppd_choice_t *choice; /* Current InputSlot/MediaType */
73 _pwg_map_t *map; /* Current source/type map */
74 ppd_attr_t *ppd_attr; /* Current PPD preset attribute */
75 int num_options; /* Number of preset options and props */
76 cups_option_t *options; /* Preset options and properties */
77 ppd_size_t *ppd_size; /* Current PPD size */
78 _pwg_size_t *pwg_size; /* Current PWG size */
79 char pwg_keyword[3 + PPD_MAX_NAME + 1 + 12 + 1 + 12 + 3],
54afec33 80 /* PWG keyword string */
c7017ecc
MS
81 ppd_name[PPD_MAX_NAME];
82 /* Normalized PPD name */
83 const char *pwg_name; /* Standard PWG media name */
84 _pwg_media_t *pwg_media; /* PWG media data */
85 _pwg_output_mode_t pwg_output_mode;/* output-mode index */
86 _pwg_print_quality_t pwg_print_quality;
87 /* print-quality index */
54afec33
MS
88
89
90 DEBUG_printf(("_pwgCreateWithPPD(ppd=%p)", ppd));
91
92 /*
93 * Range check input...
94 */
95
96 if (!ppd)
97 return (NULL);
98
99 /*
100 * Allocate memory...
101 */
102
103 if ((pwg = calloc(1, sizeof(_pwg_t))) == NULL)
104 {
105 DEBUG_puts("_pwgCreateWithPPD: Unable to allocate _pwg_t.");
106 goto create_error;
107 }
108
109 /*
110 * Copy and convert size data...
111 */
112
113 if (ppd->num_sizes == 0)
114 {
115 DEBUG_puts("_pwgCreateWithPPD: No page sizes in PPD.");
116 goto create_error;
117 }
118
119 if ((pwg->sizes = calloc(ppd->num_sizes, sizeof(_pwg_size_t))) == NULL)
120 {
121 DEBUG_printf(("_pwgCreateWithPPD: Unable to allocate %d _pwg_size_t's.",
122 ppd->num_sizes));
123 goto create_error;
124 }
125
54afec33
MS
126 for (i = ppd->num_sizes, pwg_size = pwg->sizes, ppd_size = ppd->sizes;
127 i > 0;
128 i --, ppd_size ++)
129 {
130 /*
131 * Don't copy over custom size...
132 */
133
134 if (!strcasecmp(ppd_size->name, "Custom"))
135 continue;
136
137 /*
138 * Convert the PPD size name to the corresponding PWG keyword name.
139 */
140
141 if ((pwg_media = _pwgMediaForPPD(ppd_size->name)) != NULL)
142 {
143 /*
144 * Standard name, do we have conflicts?
145 */
146
147 for (j = 0; j < pwg->num_sizes; j ++)
148 if (!strcmp(pwg->sizes[j].map.pwg, pwg_media->pwg))
149 {
150 pwg_media = NULL;
151 break;
152 }
153 }
154
155 if (pwg_media)
156 {
157 /*
158 * Standard name and no conflicts, use it!
159 */
160
161 pwg_name = pwg_media->pwg;
162 }
163 else
164 {
165 /*
166 * Not a standard name; convert it to a PWG vendor name of the form:
167 *
168 * pp_lowerppd_WIDTHxHEIGHTuu
169 */
170
171 pwg_name = pwg_keyword;
172
173 pwg_unppdize_name(ppd_size->name, ppd_name, sizeof(ppd_name));
174 _pwgGenerateSize(pwg_keyword, sizeof(pwg_keyword), NULL, ppd_name,
175 _PWG_FROMPTS(ppd_size->width),
176 _PWG_FROMPTS(ppd_size->length));
177 }
178
179 /*
180 * Save this size...
181 */
182
183 pwg_size->map.ppd = _cupsStrAlloc(ppd_size->name);
184 pwg_size->map.pwg = _cupsStrAlloc(pwg_name);
185 pwg_size->width = _PWG_FROMPTS(ppd_size->width);
186 pwg_size->length = _PWG_FROMPTS(ppd_size->length);
187 pwg_size->left = _PWG_FROMPTS(ppd_size->left);
188 pwg_size->bottom = _PWG_FROMPTS(ppd_size->bottom);
189 pwg_size->right = _PWG_FROMPTS(ppd_size->width - ppd_size->right);
190 pwg_size->top = _PWG_FROMPTS(ppd_size->length - ppd_size->top);
191
192 pwg->num_sizes ++;
193 pwg_size ++;
194 }
195
196 if (ppd->variable_sizes)
197 {
198 /*
199 * Generate custom size data...
200 */
201
202 _pwgGenerateSize(pwg_keyword, sizeof(pwg_keyword), "custom", "max",
203 _PWG_FROMPTS(ppd->custom_max[0]),
204 _PWG_FROMPTS(ppd->custom_max[1]));
205 pwg->custom_max_keyword = _cupsStrAlloc(pwg_keyword);
206 pwg->custom_max_width = _PWG_FROMPTS(ppd->custom_max[0]);
207 pwg->custom_max_length = _PWG_FROMPTS(ppd->custom_max[1]);
208
209 _pwgGenerateSize(pwg_keyword, sizeof(pwg_keyword), "custom", "min",
210 _PWG_FROMPTS(ppd->custom_min[0]),
211 _PWG_FROMPTS(ppd->custom_min[1]));
212 pwg->custom_min_keyword = _cupsStrAlloc(pwg_keyword);
213 pwg->custom_min_width = _PWG_FROMPTS(ppd->custom_min[0]);
214 pwg->custom_min_length = _PWG_FROMPTS(ppd->custom_min[1]);
215
216 pwg->custom_size.left = _PWG_FROMPTS(ppd->custom_margins[0]);
217 pwg->custom_size.bottom = _PWG_FROMPTS(ppd->custom_margins[1]);
218 pwg->custom_size.right = _PWG_FROMPTS(ppd->custom_margins[2]);
219 pwg->custom_size.top = _PWG_FROMPTS(ppd->custom_margins[3]);
220 }
221
222 /*
223 * Copy and convert InputSlot data...
224 */
225
4220952d
MS
226 if ((input_slot = ppdFindOption(ppd, "InputSlot")) == NULL)
227 input_slot = ppdFindOption(ppd, "HPPaperSource");
228
229 if (input_slot)
54afec33 230 {
4220952d
MS
231 pwg->source_option = _cupsStrAlloc(input_slot->keyword);
232
54afec33
MS
233 if ((pwg->sources = calloc(input_slot->num_choices,
234 sizeof(_pwg_map_t))) == NULL)
235 {
236 DEBUG_printf(("_pwgCreateWithPPD: Unable to allocate %d _pwg_map_t's "
237 "for InputSlot.", input_slot->num_choices));
238 goto create_error;
239 }
240
241 pwg->num_sources = input_slot->num_choices;
242
243 for (i = input_slot->num_choices, choice = input_slot->choices,
244 map = pwg->sources;
245 i > 0;
246 i --, choice ++, map ++)
247 {
248 if (!strncasecmp(choice->choice, "Auto", 4) ||
249 !strcasecmp(choice->choice, "Default"))
250 pwg_name = "auto";
251 else if (!strcasecmp(choice->choice, "Cassette"))
aaf19ab0 252 pwg_name = "main";
4220952d
MS
253 else if (!strcasecmp(choice->choice, "PhotoTray"))
254 pwg_name = "photo";
255 else if (!strcasecmp(choice->choice, "CDTray"))
256 pwg_name = "disc";
54afec33
MS
257 else if (!strncasecmp(choice->choice, "Multipurpose", 12) ||
258 !strcasecmp(choice->choice, "MP") ||
259 !strcasecmp(choice->choice, "MPTray"))
aaf19ab0 260 pwg_name = "alternate";
54afec33 261 else if (!strcasecmp(choice->choice, "LargeCapacity"))
aaf19ab0 262 pwg_name = "large-capacity";
54afec33 263 else if (!strncasecmp(choice->choice, "Lower", 5))
aaf19ab0 264 pwg_name = "bottom";
54afec33 265 else if (!strncasecmp(choice->choice, "Middle", 6))
aaf19ab0 266 pwg_name = "middle";
54afec33 267 else if (!strncasecmp(choice->choice, "Upper", 5))
aaf19ab0 268 pwg_name = "top";
54afec33 269 else if (!strncasecmp(choice->choice, "Side", 4))
aaf19ab0 270 pwg_name = "side";
54afec33 271 else if (!strcasecmp(choice->choice, "Roll") ||
aaf19ab0 272 !strcasecmp(choice->choice, "Roll1"))
54afec33
MS
273 pwg_name = "main-roll";
274 else if (!strcasecmp(choice->choice, "Roll2"))
275 pwg_name = "alternate-roll";
276 else
277 {
278 /*
279 * Convert PPD name to lowercase...
280 */
281
282 pwg_name = pwg_keyword;
283 pwg_unppdize_name(choice->choice, pwg_keyword, sizeof(pwg_keyword));
284 }
285
286 map->pwg = _cupsStrAlloc(pwg_name);
287 map->ppd = _cupsStrAlloc(choice->choice);
288 }
289 }
290
291 /*
292 * Copy and convert MediaType data...
293 */
294
295 if ((media_type = ppdFindOption(ppd, "MediaType")) != NULL)
296 {
297 if ((pwg->types = calloc(media_type->num_choices,
298 sizeof(_pwg_map_t))) == NULL)
299 {
300 DEBUG_printf(("_pwgCreateWithPPD: Unable to allocate %d _pwg_map_t's "
aaf19ab0 301 "for MediaType.", media_type->num_choices));
54afec33
MS
302 goto create_error;
303 }
304
305 pwg->num_types = media_type->num_choices;
306
307 for (i = media_type->num_choices, choice = media_type->choices,
308 map = pwg->types;
309 i > 0;
310 i --, choice ++, map ++)
311 {
312 if (!strncasecmp(choice->choice, "Auto", 4) ||
313 !strcasecmp(choice->choice, "Any") ||
314 !strcasecmp(choice->choice, "Default"))
315 pwg_name = "auto";
316 else if (!strncasecmp(choice->choice, "Card", 4))
317 pwg_name = "cardstock";
318 else if (!strncasecmp(choice->choice, "Env", 3))
319 pwg_name = "envelope";
320 else if (!strncasecmp(choice->choice, "Gloss", 5))
321 pwg_name = "photographic-glossy";
322 else if (!strcasecmp(choice->choice, "HighGloss"))
323 pwg_name = "photographic-high-gloss";
324 else if (!strcasecmp(choice->choice, "Matte"))
325 pwg_name = "photographic-matte";
326 else if (!strncasecmp(choice->choice, "Plain", 5))
327 pwg_name = "stationery";
328 else if (!strncasecmp(choice->choice, "Coated", 6))
329 pwg_name = "stationery-coated";
330 else if (!strcasecmp(choice->choice, "Inkjet"))
331 pwg_name = "stationery-inkjet";
332 else if (!strcasecmp(choice->choice, "Letterhead"))
333 pwg_name = "stationery-letterhead";
334 else if (!strncasecmp(choice->choice, "Preprint", 8))
335 pwg_name = "stationery-preprinted";
336 else if (!strncasecmp(choice->choice, "Transparen", 10))
337 pwg_name = "transparency";
338 else
339 {
340 /*
341 * Convert PPD name to lowercase...
342 */
343
344 pwg_name = pwg_keyword;
345 pwg_unppdize_name(choice->choice, pwg_keyword, sizeof(pwg_keyword));
346 }
347
348 map->pwg = _cupsStrAlloc(pwg_name);
349 map->ppd = _cupsStrAlloc(choice->choice);
350 }
351 }
352
cc754834
MS
353
354 /*
355 * Copy and convert OutputBin data...
356 */
357
358 if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL)
359 {
360 if ((pwg->bins = calloc(output_bin->num_choices,
361 sizeof(_pwg_map_t))) == NULL)
362 {
363 DEBUG_printf(("_pwgCreateWithPPD: Unable to allocate %d _pwg_map_t's "
364 "for OutputBin.", output_bin->num_choices));
365 goto create_error;
366 }
367
368 pwg->num_bins = output_bin->num_choices;
369
370 for (i = output_bin->num_choices, choice = output_bin->choices,
371 map = pwg->bins;
372 i > 0;
373 i --, choice ++, map ++)
374 {
375 pwg_unppdize_name(choice->choice, pwg_keyword, sizeof(pwg_keyword));
376
377 map->pwg = _cupsStrAlloc(pwg_keyword);
378 map->ppd = _cupsStrAlloc(choice->choice);
379 }
380 }
381
c7017ecc
MS
382 if ((ppd_attr = ppdFindAttr(ppd, "APPrinterPreset", NULL)) != NULL)
383 {
384 /*
385 * Copy and convert APPrinterPreset (output-mode + print-quality) data...
386 */
387
388 const char *quality, /* com.apple.print.preset.quality value */
389 *output_mode, /* com.apple.print.preset.output-mode value */
390 *color_model_val; /* ColorModel choice */
391
392
393 do
394 {
395 num_options = _ppdParseOptions(ppd_attr->value, 0, &options,
396 _PPD_PARSE_ALL);
397
398 if ((quality = cupsGetOption("com.apple.print.preset.quality",
399 num_options, options)) != NULL)
400 {
401 /*
402 * Get the print-quality for this preset...
403 */
404
405 if (!strcmp(quality, "low"))
406 pwg_print_quality = _PWG_PRINT_QUALITY_DRAFT;
407 else if (!strcmp(quality, "high"))
408 pwg_print_quality = _PWG_PRINT_QUALITY_HIGH;
409 else
410 pwg_print_quality = _PWG_PRINT_QUALITY_NORMAL;
411
412 /*
413 * Get the output mode for this preset...
414 */
415
416 output_mode = cupsGetOption("com.apple.print.preset.output-mode",
417 num_options, options);
418 color_model_val = cupsGetOption("ColorModel", num_options, options);
419
420 if (output_mode)
421 {
422 if (!strcmp(output_mode, "monochrome"))
423 pwg_output_mode = _PWG_OUTPUT_MODE_MONOCHROME;
424 else
425 pwg_output_mode = _PWG_OUTPUT_MODE_COLOR;
426 }
427 else if (color_model_val)
428 {
429 if (!strcasecmp(color_model_val, "Gray"))
430 pwg_output_mode = _PWG_OUTPUT_MODE_MONOCHROME;
431 else
432 pwg_output_mode = _PWG_OUTPUT_MODE_COLOR;
433 }
434 else
435 pwg_output_mode = _PWG_OUTPUT_MODE_COLOR;
436
437 /*
438 * Save the options for this combination as needed...
439 */
440
441 if (!pwg->num_presets[pwg_output_mode][pwg_print_quality])
442 pwg->num_presets[pwg_output_mode][pwg_print_quality] =
443 _ppdParseOptions(ppd_attr->value, 0,
444 pwg->presets[pwg_output_mode] +
445 pwg_print_quality, _PPD_PARSE_OPTIONS);
446 }
447
448 cupsFreeOptions(num_options, options);
449 }
450 while ((ppd_attr = ppdFindNextAttr(ppd, "APPrinterPreset", NULL)) != NULL);
451 }
452
453 if (!pwg->num_presets[_PWG_OUTPUT_MODE_MONOCHROME][_PWG_PRINT_QUALITY_DRAFT] &&
454 !pwg->num_presets[_PWG_OUTPUT_MODE_MONOCHROME][_PWG_PRINT_QUALITY_NORMAL] &&
4220952d 455 !pwg->num_presets[_PWG_OUTPUT_MODE_MONOCHROME][_PWG_PRINT_QUALITY_HIGH])
c7017ecc
MS
456 {
457 /*
4220952d
MS
458 * Try adding some common color options to create grayscale presets. These
459 * are listed in order of popularity...
c7017ecc
MS
460 */
461
4220952d
MS
462 const char *color_option = NULL, /* Color control option */
463 *gray_choice = NULL; /* Choice to select grayscale */
c7017ecc 464
4220952d
MS
465 if ((color_model = ppdFindOption(ppd, "ColorModel")) != NULL &&
466 ppdFindChoice(color_model, "Gray"))
c7017ecc 467 {
4220952d
MS
468 color_option = "ColorModel";
469 gray_choice = "Gray";
470 }
471 else if ((color_model = ppdFindOption(ppd, "HPColorMode")) != NULL &&
472 ppdFindChoice(color_model, "grayscale"))
473 {
474 color_option = "HPColorMode";
475 gray_choice = "grayscale";
476 }
477 else if ((color_model = ppdFindOption(ppd, "BRMonoColor")) != NULL &&
478 ppdFindChoice(color_model, "Mono"))
479 {
480 color_option = "BRMonoColor";
481 gray_choice = "Mono";
482 }
483 else if ((color_model = ppdFindOption(ppd, "CNIJSGrayScale")) != NULL &&
484 ppdFindChoice(color_model, "1"))
485 {
486 color_option = "CNIJSGrayScale";
487 gray_choice = "1";
488 }
489 else if ((color_model = ppdFindOption(ppd, "HPColorAsGray")) != NULL &&
490 ppdFindChoice(color_model, "True"))
491 {
492 color_option = "HPColorAsGray";
493 gray_choice = "True";
494 }
c7017ecc 495
4220952d
MS
496 if (color_option && gray_choice)
497 {
498 /*
499 * Copy and convert ColorModel (output-mode) data...
500 */
c7017ecc 501
4220952d
MS
502 cups_option_t *coption, /* Color option */
503 *moption; /* Monochrome option */
504
505 for (pwg_print_quality = _PWG_PRINT_QUALITY_DRAFT;
506 pwg_print_quality < _PWG_PRINT_QUALITY_MAX;
507 pwg_print_quality ++)
508 {
509 if (pwg->num_presets[_PWG_OUTPUT_MODE_COLOR][pwg_print_quality])
c7017ecc 510 {
4220952d
MS
511 /*
512 * Copy the color options...
513 */
514
515 num_options = pwg->num_presets[_PWG_OUTPUT_MODE_COLOR]
516 [pwg_print_quality];
517 options = calloc(sizeof(cups_option_t), num_options);
518
519 if (options)
c7017ecc 520 {
4220952d
MS
521 for (i = num_options, moption = options,
522 coption = pwg->presets[_PWG_OUTPUT_MODE_COLOR]
523 [pwg_print_quality];
524 i > 0;
525 i --, moption ++, coption ++)
526 {
527 moption->name = _cupsStrRetain(coption->name);
528 moption->value = _cupsStrRetain(coption->value);
529 }
530
531 pwg->num_presets[_PWG_OUTPUT_MODE_MONOCHROME][pwg_print_quality] =
532 num_options;
533 pwg->presets[_PWG_OUTPUT_MODE_MONOCHROME][pwg_print_quality] =
534 options;
c7017ecc 535 }
c7017ecc 536 }
4220952d
MS
537 else if (pwg_print_quality != _PWG_PRINT_QUALITY_NORMAL)
538 continue;
c7017ecc 539
4220952d
MS
540 /*
541 * Add the grayscale option to the preset...
542 */
c7017ecc 543
4220952d
MS
544 pwg->num_presets[_PWG_OUTPUT_MODE_MONOCHROME][pwg_print_quality] =
545 cupsAddOption(color_option, gray_choice,
546 pwg->num_presets[_PWG_OUTPUT_MODE_MONOCHROME]
547 [pwg_print_quality],
548 pwg->presets[_PWG_OUTPUT_MODE_MONOCHROME] +
549 pwg_print_quality);
550 }
c7017ecc
MS
551 }
552 }
553
554 /*
555 * Copy and convert Duplex (sides) data...
556 */
557
558 if ((duplex = ppdFindOption(ppd, "Duplex")) == NULL)
559 if ((duplex = ppdFindOption(ppd, "JCLDuplex")) == NULL)
560 if ((duplex = ppdFindOption(ppd, "EFDuplex")) == NULL)
561 if ((duplex = ppdFindOption(ppd, "EFDuplexing")) == NULL)
562 duplex = ppdFindOption(ppd, "KD03Duplex");
563
564 if (duplex)
565 {
566 pwg->sides_option = _cupsStrAlloc(duplex->keyword);
567
568 for (i = duplex->num_choices, choice = duplex->choices;
569 i > 0;
570 i --, choice ++)
571 {
572 if ((!strcasecmp(choice->choice, "None") ||
573 !strcasecmp(choice->choice, "False")) && !pwg->sides_1sided)
574 pwg->sides_1sided = _cupsStrAlloc(choice->choice);
575 else if ((!strcasecmp(choice->choice, "DuplexNoTumble") ||
576 !strcasecmp(choice->choice, "LongEdge") ||
577 !strcasecmp(choice->choice, "Top")) && !pwg->sides_2sided_long)
578 pwg->sides_2sided_long = _cupsStrAlloc(choice->choice);
579 else if ((!strcasecmp(choice->choice, "DuplexTumble") ||
580 !strcasecmp(choice->choice, "ShortEdge") ||
581 !strcasecmp(choice->choice, "Bottom")) &&
582 !pwg->sides_2sided_short)
583 pwg->sides_2sided_short = _cupsStrAlloc(choice->choice);
584 }
585 }
586
54afec33
MS
587 return (pwg);
588
589 /*
590 * If we get here we need to destroy the PWG mapping data and return NULL...
591 */
592
593 create_error:
594
595 _cupsSetError(IPP_INTERNAL_ERROR, _("Out of memory."), 1);
596 _pwgDestroy(pwg);
597
598 return (NULL);
599}
600
601
cc754834
MS
602/*
603 * '_pwgGetBin()' - Get the PWG output-bin keyword associated with a PPD
604 * OutputBin.
605 */
606
607const char * /* O - output-bin or NULL */
608_pwgGetBin(_pwg_t *pwg, /* I - PWG mapping data */
609 const char *output_bin) /* I - PPD OutputBin string */
610{
611 int i; /* Looping var */
612
613
614 /*
615 * Range check input...
616 */
617
618 if (!pwg || !output_bin)
619 return (NULL);
620
621 /*
622 * Look up the OutputBin string...
623 */
624
625
626 for (i = 0; i < pwg->num_bins; i ++)
627 if (!strcasecmp(output_bin, pwg->bins[i].ppd))
628 return (pwg->bins[i].pwg);
629
630 return (NULL);
631}
632
633
54afec33
MS
634/*
635 * '_pwgGetInputSlot()' - Get the PPD InputSlot associated with the job
636 * attributes or a keyword string.
637 */
638
639const char * /* O - PPD InputSlot or NULL */
640_pwgGetInputSlot(_pwg_t *pwg, /* I - PWG mapping data */
641 ipp_t *job, /* I - Job attributes or NULL */
642 const char *keyword) /* I - Keyword string or NULL */
643{
644 /*
645 * Range check input...
646 */
647
648 if (!pwg || pwg->num_sources == 0 || (!job && !keyword))
649 return (NULL);
650
651 if (job && !keyword)
652 {
653 /*
654 * Lookup the media-col attribute and any media-source found there...
655 */
656
657 ipp_attribute_t *media_col, /* media-col attribute */
658 *media_source; /* media-source attribute */
4220952d
MS
659 _pwg_size_t size; /* Dimensional size */
660 int margins_set; /* Were the margins set? */
54afec33
MS
661
662 media_col = ippFindAttribute(job, "media-col", IPP_TAG_BEGIN_COLLECTION);
663 if (media_col &&
664 (media_source = ippFindAttribute(media_col->values[0].collection,
665 "media-source",
666 IPP_TAG_KEYWORD)) != NULL)
4220952d
MS
667 {
668 /*
669 * Use the media-source value from media-col...
670 */
671
54afec33 672 keyword = media_source->values[0].string.text;
4220952d
MS
673 }
674 else if (_pwgInitSize(&size, job, &margins_set))
675 {
676 /*
677 * For media <= 5x7, look for a photo tray...
678 */
679
680 if (size.width <= (5 * 2540) && size.length <= (7 * 2540))
681 keyword = "photo";
682 }
54afec33
MS
683 }
684
685 if (keyword)
686 {
687 int i; /* Looping var */
688
689 for (i = 0; i < pwg->num_sources; i ++)
690 if (!strcasecmp(keyword, pwg->sources[i].pwg))
691 return (pwg->sources[i].ppd);
692 }
693
694 return (NULL);
695}
696
697
698/*
699 * '_pwgGetMediaType()' - Get the PPD MediaType associated with the job
700 * attributes or a keyword string.
701 */
702
703const char * /* O - PPD MediaType or NULL */
704_pwgGetMediaType(_pwg_t *pwg, /* I - PWG mapping data */
705 ipp_t *job, /* I - Job attributes or NULL */
706 const char *keyword) /* I - Keyword string or NULL */
707{
708 /*
709 * Range check input...
710 */
711
712 if (!pwg || pwg->num_types == 0 || (!job && !keyword))
713 return (NULL);
714
715 if (job && !keyword)
716 {
717 /*
718 * Lookup the media-col attribute and any media-source found there...
719 */
720
721 ipp_attribute_t *media_col, /* media-col attribute */
722 *media_type; /* media-type attribute */
723
724 media_col = ippFindAttribute(job, "media-col", IPP_TAG_BEGIN_COLLECTION);
725 if (media_col)
726 {
727 if ((media_type = ippFindAttribute(media_col->values[0].collection,
728 "media-type",
729 IPP_TAG_KEYWORD)) == NULL)
730 media_type = ippFindAttribute(media_col->values[0].collection,
731 "media-type", IPP_TAG_NAME);
732
733 if (media_type)
734 keyword = media_type->values[0].string.text;
735 }
736 }
737
738 if (keyword)
739 {
740 int i; /* Looping var */
741
742 for (i = 0; i < pwg->num_types; i ++)
743 if (!strcasecmp(keyword, pwg->types[i].pwg))
744 return (pwg->types[i].ppd);
745 }
746
747 return (NULL);
748}
749
750
cc754834
MS
751/*
752 * '_pwgGetOutputBin()' - Get the PPD OutputBin associated with the keyword
753 * string.
754 */
755
756const char * /* O - PPD OutputBin or NULL */
757_pwgGetOutputBin(_pwg_t *pwg, /* I - PWG mapping data */
758 const char *output_bin)/* I - Keyword string */
759{
760 int i; /* Looping var */
761
762
763 /*
764 * Range check input...
765 */
766
767 if (!pwg || !output_bin)
768 return (NULL);
769
770 /*
771 * Look up the OutputBin string...
772 */
773
774
775 for (i = 0; i < pwg->num_bins; i ++)
776 if (!strcasecmp(output_bin, pwg->bins[i].pwg))
777 return (pwg->bins[i].ppd);
778
779 return (NULL);
780}
781
782
54afec33
MS
783/*
784 * '_pwgGetPageSize()' - Get the PPD PageSize associated with the job
785 * attributes or a keyword string.
786 */
787
788const char * /* O - PPD PageSize or NULL */
789_pwgGetPageSize(_pwg_t *pwg, /* I - PWG mapping data */
790 ipp_t *job, /* I - Job attributes or NULL */
791 const char *keyword, /* I - Keyword string or NULL */
792 int *exact) /* I - 1 if exact match, 0 otherwise */
793{
794 int i; /* Looping var */
795 _pwg_size_t *size, /* Current size */
796 *closest, /* Closest size */
797 jobsize; /* Size data from job */
798 int margins_set, /* Were the margins set? */
799 dwidth, /* Difference in width */
800 dlength, /* Difference in length */
801 dleft, /* Difference in left margins */
802 dright, /* Difference in right margins */
803 dbottom, /* Difference in bottom margins */
804 dtop, /* Difference in top margins */
805 dmin, /* Minimum difference */
806 dclosest; /* Closest difference */
807
808
809 /*
810 * Range check input...
811 */
812
813 if (!pwg || (!job && !keyword))
814 return (NULL);
815
816 if (exact)
817 *exact = 0;
818
819 if (job && !keyword)
820 {
821 /*
822 * Get the size using media-col or media, with the preference being
823 * media-col.
824 */
825
826 if (!_pwgInitSize(&jobsize, job, &margins_set))
827 return (NULL);
aaf19ab0 828 }
54afec33
MS
829 else
830 {
831 /*
832 * Get the size using a media keyword...
833 */
834
835 _pwg_media_t *media; /* Media definition */
836
837
838 if ((media = _pwgMediaForPWG(keyword)) == NULL)
839 if ((media = _pwgMediaForLegacy(keyword)) == NULL)
840 return (NULL);
841
842 jobsize.width = media->width;
843 jobsize.length = media->length;
844 margins_set = 0;
845 }
846
847 /*
848 * Now that we have the dimensions and possibly the margins, look at the
849 * available sizes and find the match...
850 */
851
852 closest = NULL;
853 dclosest = 999999999;
854
855 for (i = pwg->num_sizes, size = pwg->sizes; i > 0; i --, size ++)
856 {
857 /*
858 * Adobe uses a size matching algorithm with an epsilon of 5 points, which
859 * is just about 176/2540ths...
860 */
861
862 dwidth = size->width - jobsize.width;
863 dlength = size->length - jobsize.length;
864
865 if (dwidth <= -176 || dwidth >= 176 || dlength <= -176 || dlength >= 176)
866 continue;
867
868 if (margins_set)
869 {
870 /*
871 * Use a tighter epsilon of 1 point (35/2540ths) for margins...
872 */
873
874 dleft = size->left - jobsize.left;
875 dright = size->right - jobsize.right;
876 dtop = size->top - jobsize.top;
877 dbottom = size->bottom - jobsize.bottom;
878
879 if (dleft <= -35 || dleft >= 35 || dright <= -35 || dright >= 35 ||
880 dtop <= -35 || dtop >= 35 || dbottom <= -35 || dbottom >= 35)
881 {
882 dleft = dleft < 0 ? -dleft : dleft;
883 dright = dright < 0 ? -dright : dright;
884 dbottom = dbottom < 0 ? -dbottom : dbottom;
885 dtop = dtop < 0 ? -dtop : dtop;
886 dmin = dleft + dright + dbottom + dtop;
887
888 if (dmin < dclosest)
889 {
890 dclosest = dmin;
891 closest = size;
892 }
893
894 continue;
895 }
896 }
897
898 if (exact)
899 *exact = 1;
900
901 return (size->map.ppd);
902 }
903
904 if (closest)
905 return (closest->map.ppd);
906
907 /*
908 * If we get here we need to check for custom page size support...
909 */
910
911 if (jobsize.width >= pwg->custom_min_width &&
912 jobsize.width <= pwg->custom_max_width &&
913 jobsize.length >= pwg->custom_min_length &&
914 jobsize.length <= pwg->custom_max_length)
915 {
916 /*
917 * In range, format as Custom.WWWWxLLLL (points).
918 */
919
920 snprintf(pwg->custom_ppd_size, sizeof(pwg->custom_ppd_size), "Custom.%dx%d",
921 (int)_PWG_TOPTS(jobsize.width), (int)_PWG_TOPTS(jobsize.length));
922
923 if (margins_set && exact)
924 {
925 dleft = pwg->custom_size.left - jobsize.left;
926 dright = pwg->custom_size.right - jobsize.right;
927 dtop = pwg->custom_size.top - jobsize.top;
928 dbottom = pwg->custom_size.bottom - jobsize.bottom;
929
930 if (dleft > -35 && dleft < 35 && dright > -35 && dright < 35 &&
931 dtop > -35 && dtop < 35 && dbottom > -35 && dbottom < 35)
932 *exact = 1;
933 }
934 else if (exact)
935 *exact = 1;
936
937 return (pwg->custom_ppd_size);
938 }
939
940 /*
941 * No custom page size support or the size is out of range - return NULL.
942 */
943
944 return (NULL);
945}
946
947
948/*
949 * '_pwgGetSize()' - Get the PWG size associated with a PPD PageSize.
950 */
951
952_pwg_size_t * /* O - PWG size or NULL */
953_pwgGetSize(_pwg_t *pwg, /* I - PWG mapping data */
954 const char *page_size) /* I - PPD PageSize */
955{
956 int i;
957 _pwg_size_t *size; /* Current size */
958
959
cc754834
MS
960 /*
961 * Range check input...
962 */
963
964 if (!pwg || !page_size)
965 return (NULL);
966
54afec33
MS
967 if (!strncasecmp(page_size, "Custom.", 7))
968 {
969 /*
970 * Custom size; size name can be one of the following:
971 *
972 * Custom.WIDTHxLENGTHin - Size in inches
973 * Custom.WIDTHxLENGTHft - Size in feet
974 * Custom.WIDTHxLENGTHcm - Size in centimeters
975 * Custom.WIDTHxLENGTHmm - Size in millimeters
976 * Custom.WIDTHxLENGTHm - Size in meters
977 * Custom.WIDTHxLENGTH[pt] - Size in points
978 */
979
980 double w, l; /* Width and length of page */
981 char *ptr; /* Pointer into PageSize */
982 struct lconv *loc; /* Locale data */
983
984 loc = localeconv();
985 w = (float)_cupsStrScand(page_size + 7, &ptr, loc);
986 if (!ptr || *ptr != 'x')
987 return (NULL);
988
989 l = (float)_cupsStrScand(ptr + 1, &ptr, loc);
990 if (!ptr)
991 return (NULL);
992
993 if (!strcasecmp(ptr, "in"))
994 {
995 w *= 2540.0;
996 l *= 2540.0;
997 }
998 else if (!strcasecmp(ptr, "ft"))
999 {
1000 w *= 12.0 * 2540.0;
1001 l *= 12.0 * 2540.0;
1002 }
1003 else if (!strcasecmp(ptr, "mm"))
1004 {
1005 w *= 100.0;
1006 l *= 100.0;
1007 }
1008 else if (!strcasecmp(ptr, "cm"))
1009 {
1010 w *= 1000.0;
1011 l *= 1000.0;
1012 }
1013 else if (!strcasecmp(ptr, "m"))
1014 {
1015 w *= 100000.0;
1016 l *= 100000.0;
1017 }
1018 else
1019 {
1020 w *= 2540.0 / 72.0;
1021 l *= 2540.0 / 72.0;
1022 }
1023
1024 pwg->custom_size.width = (int)w;
1025 pwg->custom_size.length = (int)l;
1026
1027 return (&(pwg->custom_size));
1028 }
1029
1030 /*
1031 * Not a custom size - look it up...
1032 */
1033
1034 for (i = pwg->num_sizes, size = pwg->sizes; i > 0; i --, size ++)
1035 if (!strcasecmp(page_size, size->map.ppd))
1036 return (size);
1037
1038 return (NULL);
1039}
1040
1041
1042/*
1043 * '_pwgGetSource()' - Get the PWG media-source associated with a PPD InputSlot.
1044 */
1045
1046const char * /* O - PWG media-source keyword */
1047_pwgGetSource(_pwg_t *pwg, /* I - PWG mapping data */
1048 const char *input_slot) /* I - PPD InputSlot */
1049{
1050 int i; /* Looping var */
1051 _pwg_map_t *source; /* Current source */
1052
1053
cc754834
MS
1054 /*
1055 * Range check input...
1056 */
1057
1058 if (!pwg || !input_slot)
1059 return (NULL);
1060
54afec33
MS
1061 for (i = pwg->num_sources, source = pwg->sources; i > 0; i --, source ++)
1062 if (!strcasecmp(input_slot, source->ppd))
1063 return (source->pwg);
1064
1065 return (NULL);
1066}
1067
1068
1069/*
1070 * '_pwgGetType()' - Get the PWG media-type associated with a PPD MediaType.
1071 */
1072
1073const char * /* O - PWG media-type keyword */
1074_pwgGetType(_pwg_t *pwg, /* I - PWG mapping data */
1075 const char *media_type) /* I - PPD MediaType */
1076{
1077 int i; /* Looping var */
1078 _pwg_map_t *type; /* Current type */
1079
1080
cc754834
MS
1081 /*
1082 * Range check input...
1083 */
1084
1085 if (!pwg || !media_type)
1086 return (NULL);
1087
54afec33
MS
1088 for (i = pwg->num_types, type = pwg->types; i > 0; i --, type ++)
1089 if (!strcasecmp(media_type, type->ppd))
1090 return (type->pwg);
1091
1092 return (NULL);
1093}
1094
1095
1096/*
1097 * '_pwgInputSlotForSource()' - Get the InputSlot name for the given PWG source.
1098 */
1099
1100const char * /* O - InputSlot name */
1101_pwgInputSlotForSource(
1102 const char *media_source, /* I - PWG media-source */
1103 char *name, /* I - Name buffer */
1104 size_t namesize) /* I - Size of name buffer */
1105{
cc754834
MS
1106 /*
1107 * Range check input...
1108 */
1109
1110 if (!media_source || !name || namesize < PPD_MAX_NAME)
1111 return (NULL);
1112
aaf19ab0 1113 if (strcasecmp(media_source, "main"))
54afec33 1114 strlcpy(name, "Cassette", namesize);
aaf19ab0 1115 else if (strcasecmp(media_source, "alternate"))
54afec33 1116 strlcpy(name, "Multipurpose", namesize);
aaf19ab0 1117 else if (strcasecmp(media_source, "large-capacity"))
54afec33 1118 strlcpy(name, "LargeCapacity", namesize);
aaf19ab0 1119 else if (strcasecmp(media_source, "bottom"))
54afec33 1120 strlcpy(name, "Lower", namesize);
aaf19ab0 1121 else if (strcasecmp(media_source, "middle"))
54afec33 1122 strlcpy(name, "Middle", namesize);
aaf19ab0 1123 else if (strcasecmp(media_source, "top"))
54afec33 1124 strlcpy(name, "Upper", namesize);
aaf19ab0 1125 else if (strcasecmp(media_source, "rear"))
54afec33 1126 strlcpy(name, "Rear", namesize);
aaf19ab0 1127 else if (strcasecmp(media_source, "side"))
54afec33 1128 strlcpy(name, "Side", namesize);
aaf19ab0 1129 else if (strcasecmp(media_source, "envelope"))
54afec33
MS
1130 strlcpy(name, "Envelope", namesize);
1131 else if (strcasecmp(media_source, "main-roll"))
1132 strlcpy(name, "Roll", namesize);
1133 else if (strcasecmp(media_source, "alternate-roll"))
1134 strlcpy(name, "Roll2", namesize);
1135 else
1136 pwg_ppdize_name(media_source, name, namesize);
1137
1138 return (name);
1139}
1140
1141
1142/*
1143 * '_pwgMediaTypeForType()' - Get the MediaType name for the given PWG type.
1144 */
1145
1146const char * /* O - MediaType name */
1147_pwgMediaTypeForType(
1148 const char *media_type, /* I - PWG media-source */
1149 char *name, /* I - Name buffer */
1150 size_t namesize) /* I - Size of name buffer */
1151{
cc754834
MS
1152 /*
1153 * Range check input...
1154 */
1155
1156 if (!media_type || !name || namesize < PPD_MAX_NAME)
1157 return (NULL);
1158
54afec33
MS
1159 if (strcasecmp(media_type, "auto"))
1160 strlcpy(name, "Auto", namesize);
1161 else if (strcasecmp(media_type, "cardstock"))
1162 strlcpy(name, "Cardstock", namesize);
1163 else if (strcasecmp(media_type, "envelope"))
1164 strlcpy(name, "Envelope", namesize);
1165 else if (strcasecmp(media_type, "photographic-glossy"))
1166 strlcpy(name, "Glossy", namesize);
1167 else if (strcasecmp(media_type, "photographic-high-gloss"))
1168 strlcpy(name, "HighGloss", namesize);
1169 else if (strcasecmp(media_type, "photographic-matte"))
1170 strlcpy(name, "Matte", namesize);
1171 else if (strcasecmp(media_type, "stationery"))
1172 strlcpy(name, "Plain", namesize);
1173 else if (strcasecmp(media_type, "stationery-coated"))
1174 strlcpy(name, "Coated", namesize);
1175 else if (strcasecmp(media_type, "stationery-inkjet"))
1176 strlcpy(name, "Inkjet", namesize);
1177 else if (strcasecmp(media_type, "stationery-letterhead"))
1178 strlcpy(name, "Letterhead", namesize);
1179 else if (strcasecmp(media_type, "stationery-preprinted"))
1180 strlcpy(name, "Preprinted", namesize);
1181 else if (strcasecmp(media_type, "transparency"))
1182 strlcpy(name, "Transparency", namesize);
1183 else
1184 pwg_ppdize_name(media_type, name, namesize);
1185
1186 return (name);
1187}
1188
1189
1190/*
1191 * '_pwgPageSizeForMedia()' - Get the PageSize name for the given media.
1192 */
1193
1194const char * /* O - PageSize name */
1195_pwgPageSizeForMedia(
1196 _pwg_media_t *media, /* I - Media */
1197 char *name, /* I - PageSize name buffer */
1198 size_t namesize) /* I - Size of name buffer */
1199{
1200 const char *sizeptr, /* Pointer to size in PWG name */
1201 *dimptr; /* Pointer to dimensions in PWG name */
1202
1203
1204 /*
1205 * Range check input...
1206 */
1207
1208 if (!media || !name || namesize < PPD_MAX_NAME)
1209 return (NULL);
1210
1211 /*
1212 * Copy or generate a PageSize name...
1213 */
1214
1215 if (media->ppd)
1216 {
1217 /*
1218 * Use a standard Adobe name...
1219 */
1220
1221 strlcpy(name, media->ppd, namesize);
1222 }
1223 else if (!media->pwg || !strncmp(media->pwg, "custom_", 7) ||
1224 (sizeptr = strchr(media->pwg, '_')) == NULL ||
1225 (dimptr = strchr(sizeptr + 1, '_')) == NULL ||
1226 (dimptr - sizeptr) > namesize)
1227 {
1228 /*
1229 * Use a name of the form "wNNNhNNN"...
1230 */
1231
1232 snprintf(name, namesize, "w%dh%d", (int)_PWG_TOPTS(media->width),
1233 (int)_PWG_TOPTS(media->length));
1234 }
1235 else
1236 {
1237 /*
1238 * Copy the size name from class_sizename_dimensions...
1239 */
1240
1241 memcpy(name, sizeptr + 1, dimptr - sizeptr - 1);
1242 name[dimptr - sizeptr - 1] = '\0';
1243 }
1244
1245 return (name);
1246}
1247
1248
1249/*
1250 * 'pwg_ppdize_name()' - Convert an IPP keyword to a PPD keyword.
1251 */
1252
1253static void
1254pwg_ppdize_name(const char *ipp, /* I - IPP keyword */
1255 char *name, /* I - Name buffer */
1256 size_t namesize) /* I - Size of name buffer */
1257{
1258 char *ptr, /* Pointer into name buffer */
1259 *end; /* End of name buffer */
1260
1261
1262 *name = toupper(*ipp++);
1263
1264 for (ptr = name + 1, end = name + namesize - 1; *ipp && ptr < end;)
1265 {
1266 if (*ipp == '-' && isalpha(ipp[1] & 255))
1267 {
1268 ipp ++;
1269 *ptr++ = toupper(*ipp++ & 255);
1270 }
1271 else
1272 *ptr++ = *ipp++;
1273 }
1274
1275 *ptr = '\0';
1276}
1277
1278
1279/*
1280 * 'pwg_unppdize_name()' - Convert a PPD keyword to a lowercase IPP keyword.
1281 */
1282
1283static void
1284pwg_unppdize_name(const char *ppd, /* I - PPD keyword */
1285 char *name, /* I - Name buffer */
1286 size_t namesize) /* I - Size of name buffer */
1287{
1288 char *ptr, /* Pointer into name buffer */
1289 *end; /* End of name buffer */
1290
1291
1292 for (ptr = name, end = name + namesize - 1; *ppd && ptr < end; ppd ++)
1293 {
1294 if (isalnum(*ppd & 255) || *ppd == '-' || *ppd == '.')
1295 *ptr++ = tolower(*ppd & 255);
1296 else if (*ppd == '_')
1297 *ptr++ = '-';
1298
1299 if (!isupper(*ppd & 255) && isalnum(*ppd & 255) &&
1300 isupper(ppd[1] & 255) && ptr < end)
1301 *ptr++ = '-';
1302 }
1303
1304 *ptr = '\0';
1305}
1306
1307
1308/*
1309 * End of "$Id$".
1310 */