]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/pwg-ppd.c
Merge changes from CUPS 1.5svn-r9198.
[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
226 if ((input_slot = ppdFindOption(ppd, "InputSlot")) != NULL)
227 {
228 if ((pwg->sources = calloc(input_slot->num_choices,
229 sizeof(_pwg_map_t))) == NULL)
230 {
231 DEBUG_printf(("_pwgCreateWithPPD: Unable to allocate %d _pwg_map_t's "
232 "for InputSlot.", input_slot->num_choices));
233 goto create_error;
234 }
235
236 pwg->num_sources = input_slot->num_choices;
237
238 for (i = input_slot->num_choices, choice = input_slot->choices,
239 map = pwg->sources;
240 i > 0;
241 i --, choice ++, map ++)
242 {
243 if (!strncasecmp(choice->choice, "Auto", 4) ||
244 !strcasecmp(choice->choice, "Default"))
245 pwg_name = "auto";
246 else if (!strcasecmp(choice->choice, "Cassette"))
aaf19ab0 247 pwg_name = "main";
54afec33
MS
248 else if (!strncasecmp(choice->choice, "Multipurpose", 12) ||
249 !strcasecmp(choice->choice, "MP") ||
250 !strcasecmp(choice->choice, "MPTray"))
aaf19ab0 251 pwg_name = "alternate";
54afec33 252 else if (!strcasecmp(choice->choice, "LargeCapacity"))
aaf19ab0 253 pwg_name = "large-capacity";
54afec33 254 else if (!strncasecmp(choice->choice, "Lower", 5))
aaf19ab0 255 pwg_name = "bottom";
54afec33 256 else if (!strncasecmp(choice->choice, "Middle", 6))
aaf19ab0 257 pwg_name = "middle";
54afec33 258 else if (!strncasecmp(choice->choice, "Upper", 5))
aaf19ab0 259 pwg_name = "top";
54afec33 260 else if (!strncasecmp(choice->choice, "Side", 4))
aaf19ab0 261 pwg_name = "side";
54afec33 262 else if (!strcasecmp(choice->choice, "Roll") ||
aaf19ab0 263 !strcasecmp(choice->choice, "Roll1"))
54afec33
MS
264 pwg_name = "main-roll";
265 else if (!strcasecmp(choice->choice, "Roll2"))
266 pwg_name = "alternate-roll";
267 else
268 {
269 /*
270 * Convert PPD name to lowercase...
271 */
272
273 pwg_name = pwg_keyword;
274 pwg_unppdize_name(choice->choice, pwg_keyword, sizeof(pwg_keyword));
275 }
276
277 map->pwg = _cupsStrAlloc(pwg_name);
278 map->ppd = _cupsStrAlloc(choice->choice);
279 }
280 }
281
282 /*
283 * Copy and convert MediaType data...
284 */
285
286 if ((media_type = ppdFindOption(ppd, "MediaType")) != NULL)
287 {
288 if ((pwg->types = calloc(media_type->num_choices,
289 sizeof(_pwg_map_t))) == NULL)
290 {
291 DEBUG_printf(("_pwgCreateWithPPD: Unable to allocate %d _pwg_map_t's "
aaf19ab0 292 "for MediaType.", media_type->num_choices));
54afec33
MS
293 goto create_error;
294 }
295
296 pwg->num_types = media_type->num_choices;
297
298 for (i = media_type->num_choices, choice = media_type->choices,
299 map = pwg->types;
300 i > 0;
301 i --, choice ++, map ++)
302 {
303 if (!strncasecmp(choice->choice, "Auto", 4) ||
304 !strcasecmp(choice->choice, "Any") ||
305 !strcasecmp(choice->choice, "Default"))
306 pwg_name = "auto";
307 else if (!strncasecmp(choice->choice, "Card", 4))
308 pwg_name = "cardstock";
309 else if (!strncasecmp(choice->choice, "Env", 3))
310 pwg_name = "envelope";
311 else if (!strncasecmp(choice->choice, "Gloss", 5))
312 pwg_name = "photographic-glossy";
313 else if (!strcasecmp(choice->choice, "HighGloss"))
314 pwg_name = "photographic-high-gloss";
315 else if (!strcasecmp(choice->choice, "Matte"))
316 pwg_name = "photographic-matte";
317 else if (!strncasecmp(choice->choice, "Plain", 5))
318 pwg_name = "stationery";
319 else if (!strncasecmp(choice->choice, "Coated", 6))
320 pwg_name = "stationery-coated";
321 else if (!strcasecmp(choice->choice, "Inkjet"))
322 pwg_name = "stationery-inkjet";
323 else if (!strcasecmp(choice->choice, "Letterhead"))
324 pwg_name = "stationery-letterhead";
325 else if (!strncasecmp(choice->choice, "Preprint", 8))
326 pwg_name = "stationery-preprinted";
327 else if (!strncasecmp(choice->choice, "Transparen", 10))
328 pwg_name = "transparency";
329 else
330 {
331 /*
332 * Convert PPD name to lowercase...
333 */
334
335 pwg_name = pwg_keyword;
336 pwg_unppdize_name(choice->choice, pwg_keyword, sizeof(pwg_keyword));
337 }
338
339 map->pwg = _cupsStrAlloc(pwg_name);
340 map->ppd = _cupsStrAlloc(choice->choice);
341 }
342 }
343
cc754834
MS
344
345 /*
346 * Copy and convert OutputBin data...
347 */
348
349 if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL)
350 {
351 if ((pwg->bins = calloc(output_bin->num_choices,
352 sizeof(_pwg_map_t))) == NULL)
353 {
354 DEBUG_printf(("_pwgCreateWithPPD: Unable to allocate %d _pwg_map_t's "
355 "for OutputBin.", output_bin->num_choices));
356 goto create_error;
357 }
358
359 pwg->num_bins = output_bin->num_choices;
360
361 for (i = output_bin->num_choices, choice = output_bin->choices,
362 map = pwg->bins;
363 i > 0;
364 i --, choice ++, map ++)
365 {
366 pwg_unppdize_name(choice->choice, pwg_keyword, sizeof(pwg_keyword));
367
368 map->pwg = _cupsStrAlloc(pwg_keyword);
369 map->ppd = _cupsStrAlloc(choice->choice);
370 }
371 }
372
c7017ecc
MS
373 if ((ppd_attr = ppdFindAttr(ppd, "APPrinterPreset", NULL)) != NULL)
374 {
375 /*
376 * Copy and convert APPrinterPreset (output-mode + print-quality) data...
377 */
378
379 const char *quality, /* com.apple.print.preset.quality value */
380 *output_mode, /* com.apple.print.preset.output-mode value */
381 *color_model_val; /* ColorModel choice */
382
383
384 do
385 {
386 num_options = _ppdParseOptions(ppd_attr->value, 0, &options,
387 _PPD_PARSE_ALL);
388
389 if ((quality = cupsGetOption("com.apple.print.preset.quality",
390 num_options, options)) != NULL)
391 {
392 /*
393 * Get the print-quality for this preset...
394 */
395
396 if (!strcmp(quality, "low"))
397 pwg_print_quality = _PWG_PRINT_QUALITY_DRAFT;
398 else if (!strcmp(quality, "high"))
399 pwg_print_quality = _PWG_PRINT_QUALITY_HIGH;
400 else
401 pwg_print_quality = _PWG_PRINT_QUALITY_NORMAL;
402
403 /*
404 * Get the output mode for this preset...
405 */
406
407 output_mode = cupsGetOption("com.apple.print.preset.output-mode",
408 num_options, options);
409 color_model_val = cupsGetOption("ColorModel", num_options, options);
410
411 if (output_mode)
412 {
413 if (!strcmp(output_mode, "monochrome"))
414 pwg_output_mode = _PWG_OUTPUT_MODE_MONOCHROME;
415 else
416 pwg_output_mode = _PWG_OUTPUT_MODE_COLOR;
417 }
418 else if (color_model_val)
419 {
420 if (!strcasecmp(color_model_val, "Gray"))
421 pwg_output_mode = _PWG_OUTPUT_MODE_MONOCHROME;
422 else
423 pwg_output_mode = _PWG_OUTPUT_MODE_COLOR;
424 }
425 else
426 pwg_output_mode = _PWG_OUTPUT_MODE_COLOR;
427
428 /*
429 * Save the options for this combination as needed...
430 */
431
432 if (!pwg->num_presets[pwg_output_mode][pwg_print_quality])
433 pwg->num_presets[pwg_output_mode][pwg_print_quality] =
434 _ppdParseOptions(ppd_attr->value, 0,
435 pwg->presets[pwg_output_mode] +
436 pwg_print_quality, _PPD_PARSE_OPTIONS);
437 }
438
439 cupsFreeOptions(num_options, options);
440 }
441 while ((ppd_attr = ppdFindNextAttr(ppd, "APPrinterPreset", NULL)) != NULL);
442 }
443
444 if (!pwg->num_presets[_PWG_OUTPUT_MODE_MONOCHROME][_PWG_PRINT_QUALITY_DRAFT] &&
445 !pwg->num_presets[_PWG_OUTPUT_MODE_MONOCHROME][_PWG_PRINT_QUALITY_NORMAL] &&
446 !pwg->num_presets[_PWG_OUTPUT_MODE_MONOCHROME][_PWG_PRINT_QUALITY_HIGH] &&
447 (color_model = ppdFindOption(ppd, "ColorModel")) != NULL &&
448 ppdFindChoice(color_model, "Gray"))
449 {
450 /*
451 * Copy and convert ColorModel (output-mode) data...
452 */
453
454 cups_option_t *coption, /* Color option */
455 *moption; /* Monochrome option */
456
457 for (pwg_print_quality = _PWG_PRINT_QUALITY_DRAFT;
458 pwg_print_quality < _PWG_PRINT_QUALITY_MAX;
459 pwg_print_quality ++)
460 {
461 if (pwg->num_presets[_PWG_OUTPUT_MODE_COLOR][pwg_print_quality])
462 {
463 /*
464 * Copy the color options...
465 */
466
467 num_options = pwg->num_presets[_PWG_OUTPUT_MODE_COLOR]
468 [pwg_print_quality];
469 options = calloc(sizeof(cups_option_t), num_options);
470
471 if (options)
472 {
473 for (i = num_options, moption = options,
474 coption = pwg->presets[_PWG_OUTPUT_MODE_COLOR]
475 [pwg_print_quality];
476 i > 0;
477 i --, moption ++, coption ++)
478 {
479 moption->name = _cupsStrRetain(coption->name);
480 moption->value = _cupsStrRetain(coption->value);
481 }
482
483 pwg->num_presets[_PWG_OUTPUT_MODE_MONOCHROME][pwg_print_quality] =
484 num_options;
485 pwg->presets[_PWG_OUTPUT_MODE_MONOCHROME][pwg_print_quality] =
486 options;
487 }
488 }
489 else if (pwg_print_quality != _PWG_PRINT_QUALITY_NORMAL)
490 continue;
491
492 /*
493 * Add ColorModel=Gray to the preset...
494 */
495
496 pwg->num_presets[_PWG_OUTPUT_MODE_MONOCHROME][pwg_print_quality] =
497 cupsAddOption("ColorModel", "Gray",
498 pwg->num_presets[_PWG_OUTPUT_MODE_MONOCHROME]
499 [pwg_print_quality],
500 pwg->presets[_PWG_OUTPUT_MODE_MONOCHROME] +
501 pwg_print_quality);
502 }
503 }
504
505 /*
506 * Copy and convert Duplex (sides) data...
507 */
508
509 if ((duplex = ppdFindOption(ppd, "Duplex")) == NULL)
510 if ((duplex = ppdFindOption(ppd, "JCLDuplex")) == NULL)
511 if ((duplex = ppdFindOption(ppd, "EFDuplex")) == NULL)
512 if ((duplex = ppdFindOption(ppd, "EFDuplexing")) == NULL)
513 duplex = ppdFindOption(ppd, "KD03Duplex");
514
515 if (duplex)
516 {
517 pwg->sides_option = _cupsStrAlloc(duplex->keyword);
518
519 for (i = duplex->num_choices, choice = duplex->choices;
520 i > 0;
521 i --, choice ++)
522 {
523 if ((!strcasecmp(choice->choice, "None") ||
524 !strcasecmp(choice->choice, "False")) && !pwg->sides_1sided)
525 pwg->sides_1sided = _cupsStrAlloc(choice->choice);
526 else if ((!strcasecmp(choice->choice, "DuplexNoTumble") ||
527 !strcasecmp(choice->choice, "LongEdge") ||
528 !strcasecmp(choice->choice, "Top")) && !pwg->sides_2sided_long)
529 pwg->sides_2sided_long = _cupsStrAlloc(choice->choice);
530 else if ((!strcasecmp(choice->choice, "DuplexTumble") ||
531 !strcasecmp(choice->choice, "ShortEdge") ||
532 !strcasecmp(choice->choice, "Bottom")) &&
533 !pwg->sides_2sided_short)
534 pwg->sides_2sided_short = _cupsStrAlloc(choice->choice);
535 }
536 }
537
54afec33
MS
538 return (pwg);
539
540 /*
541 * If we get here we need to destroy the PWG mapping data and return NULL...
542 */
543
544 create_error:
545
546 _cupsSetError(IPP_INTERNAL_ERROR, _("Out of memory."), 1);
547 _pwgDestroy(pwg);
548
549 return (NULL);
550}
551
552
cc754834
MS
553/*
554 * '_pwgGetBin()' - Get the PWG output-bin keyword associated with a PPD
555 * OutputBin.
556 */
557
558const char * /* O - output-bin or NULL */
559_pwgGetBin(_pwg_t *pwg, /* I - PWG mapping data */
560 const char *output_bin) /* I - PPD OutputBin string */
561{
562 int i; /* Looping var */
563
564
565 /*
566 * Range check input...
567 */
568
569 if (!pwg || !output_bin)
570 return (NULL);
571
572 /*
573 * Look up the OutputBin string...
574 */
575
576
577 for (i = 0; i < pwg->num_bins; i ++)
578 if (!strcasecmp(output_bin, pwg->bins[i].ppd))
579 return (pwg->bins[i].pwg);
580
581 return (NULL);
582}
583
584
54afec33
MS
585/*
586 * '_pwgGetInputSlot()' - Get the PPD InputSlot associated with the job
587 * attributes or a keyword string.
588 */
589
590const char * /* O - PPD InputSlot or NULL */
591_pwgGetInputSlot(_pwg_t *pwg, /* I - PWG mapping data */
592 ipp_t *job, /* I - Job attributes or NULL */
593 const char *keyword) /* I - Keyword string or NULL */
594{
595 /*
596 * Range check input...
597 */
598
599 if (!pwg || pwg->num_sources == 0 || (!job && !keyword))
600 return (NULL);
601
602 if (job && !keyword)
603 {
604 /*
605 * Lookup the media-col attribute and any media-source found there...
606 */
607
608 ipp_attribute_t *media_col, /* media-col attribute */
609 *media_source; /* media-source attribute */
610
611 media_col = ippFindAttribute(job, "media-col", IPP_TAG_BEGIN_COLLECTION);
612 if (media_col &&
613 (media_source = ippFindAttribute(media_col->values[0].collection,
614 "media-source",
615 IPP_TAG_KEYWORD)) != NULL)
616 keyword = media_source->values[0].string.text;
617 }
618
619 if (keyword)
620 {
621 int i; /* Looping var */
622
623 for (i = 0; i < pwg->num_sources; i ++)
624 if (!strcasecmp(keyword, pwg->sources[i].pwg))
625 return (pwg->sources[i].ppd);
626 }
627
628 return (NULL);
629}
630
631
632/*
633 * '_pwgGetMediaType()' - Get the PPD MediaType associated with the job
634 * attributes or a keyword string.
635 */
636
637const char * /* O - PPD MediaType or NULL */
638_pwgGetMediaType(_pwg_t *pwg, /* I - PWG mapping data */
639 ipp_t *job, /* I - Job attributes or NULL */
640 const char *keyword) /* I - Keyword string or NULL */
641{
642 /*
643 * Range check input...
644 */
645
646 if (!pwg || pwg->num_types == 0 || (!job && !keyword))
647 return (NULL);
648
649 if (job && !keyword)
650 {
651 /*
652 * Lookup the media-col attribute and any media-source found there...
653 */
654
655 ipp_attribute_t *media_col, /* media-col attribute */
656 *media_type; /* media-type attribute */
657
658 media_col = ippFindAttribute(job, "media-col", IPP_TAG_BEGIN_COLLECTION);
659 if (media_col)
660 {
661 if ((media_type = ippFindAttribute(media_col->values[0].collection,
662 "media-type",
663 IPP_TAG_KEYWORD)) == NULL)
664 media_type = ippFindAttribute(media_col->values[0].collection,
665 "media-type", IPP_TAG_NAME);
666
667 if (media_type)
668 keyword = media_type->values[0].string.text;
669 }
670 }
671
672 if (keyword)
673 {
674 int i; /* Looping var */
675
676 for (i = 0; i < pwg->num_types; i ++)
677 if (!strcasecmp(keyword, pwg->types[i].pwg))
678 return (pwg->types[i].ppd);
679 }
680
681 return (NULL);
682}
683
684
cc754834
MS
685/*
686 * '_pwgGetOutputBin()' - Get the PPD OutputBin associated with the keyword
687 * string.
688 */
689
690const char * /* O - PPD OutputBin or NULL */
691_pwgGetOutputBin(_pwg_t *pwg, /* I - PWG mapping data */
692 const char *output_bin)/* I - Keyword string */
693{
694 int i; /* Looping var */
695
696
697 /*
698 * Range check input...
699 */
700
701 if (!pwg || !output_bin)
702 return (NULL);
703
704 /*
705 * Look up the OutputBin string...
706 */
707
708
709 for (i = 0; i < pwg->num_bins; i ++)
710 if (!strcasecmp(output_bin, pwg->bins[i].pwg))
711 return (pwg->bins[i].ppd);
712
713 return (NULL);
714}
715
716
54afec33
MS
717/*
718 * '_pwgGetPageSize()' - Get the PPD PageSize associated with the job
719 * attributes or a keyword string.
720 */
721
722const char * /* O - PPD PageSize or NULL */
723_pwgGetPageSize(_pwg_t *pwg, /* I - PWG mapping data */
724 ipp_t *job, /* I - Job attributes or NULL */
725 const char *keyword, /* I - Keyword string or NULL */
726 int *exact) /* I - 1 if exact match, 0 otherwise */
727{
728 int i; /* Looping var */
729 _pwg_size_t *size, /* Current size */
730 *closest, /* Closest size */
731 jobsize; /* Size data from job */
732 int margins_set, /* Were the margins set? */
733 dwidth, /* Difference in width */
734 dlength, /* Difference in length */
735 dleft, /* Difference in left margins */
736 dright, /* Difference in right margins */
737 dbottom, /* Difference in bottom margins */
738 dtop, /* Difference in top margins */
739 dmin, /* Minimum difference */
740 dclosest; /* Closest difference */
741
742
743 /*
744 * Range check input...
745 */
746
747 if (!pwg || (!job && !keyword))
748 return (NULL);
749
750 if (exact)
751 *exact = 0;
752
753 if (job && !keyword)
754 {
755 /*
756 * Get the size using media-col or media, with the preference being
757 * media-col.
758 */
759
760 if (!_pwgInitSize(&jobsize, job, &margins_set))
761 return (NULL);
aaf19ab0 762 }
54afec33
MS
763 else
764 {
765 /*
766 * Get the size using a media keyword...
767 */
768
769 _pwg_media_t *media; /* Media definition */
770
771
772 if ((media = _pwgMediaForPWG(keyword)) == NULL)
773 if ((media = _pwgMediaForLegacy(keyword)) == NULL)
774 return (NULL);
775
776 jobsize.width = media->width;
777 jobsize.length = media->length;
778 margins_set = 0;
779 }
780
781 /*
782 * Now that we have the dimensions and possibly the margins, look at the
783 * available sizes and find the match...
784 */
785
786 closest = NULL;
787 dclosest = 999999999;
788
789 for (i = pwg->num_sizes, size = pwg->sizes; i > 0; i --, size ++)
790 {
791 /*
792 * Adobe uses a size matching algorithm with an epsilon of 5 points, which
793 * is just about 176/2540ths...
794 */
795
796 dwidth = size->width - jobsize.width;
797 dlength = size->length - jobsize.length;
798
799 if (dwidth <= -176 || dwidth >= 176 || dlength <= -176 || dlength >= 176)
800 continue;
801
802 if (margins_set)
803 {
804 /*
805 * Use a tighter epsilon of 1 point (35/2540ths) for margins...
806 */
807
808 dleft = size->left - jobsize.left;
809 dright = size->right - jobsize.right;
810 dtop = size->top - jobsize.top;
811 dbottom = size->bottom - jobsize.bottom;
812
813 if (dleft <= -35 || dleft >= 35 || dright <= -35 || dright >= 35 ||
814 dtop <= -35 || dtop >= 35 || dbottom <= -35 || dbottom >= 35)
815 {
816 dleft = dleft < 0 ? -dleft : dleft;
817 dright = dright < 0 ? -dright : dright;
818 dbottom = dbottom < 0 ? -dbottom : dbottom;
819 dtop = dtop < 0 ? -dtop : dtop;
820 dmin = dleft + dright + dbottom + dtop;
821
822 if (dmin < dclosest)
823 {
824 dclosest = dmin;
825 closest = size;
826 }
827
828 continue;
829 }
830 }
831
832 if (exact)
833 *exact = 1;
834
835 return (size->map.ppd);
836 }
837
838 if (closest)
839 return (closest->map.ppd);
840
841 /*
842 * If we get here we need to check for custom page size support...
843 */
844
845 if (jobsize.width >= pwg->custom_min_width &&
846 jobsize.width <= pwg->custom_max_width &&
847 jobsize.length >= pwg->custom_min_length &&
848 jobsize.length <= pwg->custom_max_length)
849 {
850 /*
851 * In range, format as Custom.WWWWxLLLL (points).
852 */
853
854 snprintf(pwg->custom_ppd_size, sizeof(pwg->custom_ppd_size), "Custom.%dx%d",
855 (int)_PWG_TOPTS(jobsize.width), (int)_PWG_TOPTS(jobsize.length));
856
857 if (margins_set && exact)
858 {
859 dleft = pwg->custom_size.left - jobsize.left;
860 dright = pwg->custom_size.right - jobsize.right;
861 dtop = pwg->custom_size.top - jobsize.top;
862 dbottom = pwg->custom_size.bottom - jobsize.bottom;
863
864 if (dleft > -35 && dleft < 35 && dright > -35 && dright < 35 &&
865 dtop > -35 && dtop < 35 && dbottom > -35 && dbottom < 35)
866 *exact = 1;
867 }
868 else if (exact)
869 *exact = 1;
870
871 return (pwg->custom_ppd_size);
872 }
873
874 /*
875 * No custom page size support or the size is out of range - return NULL.
876 */
877
878 return (NULL);
879}
880
881
882/*
883 * '_pwgGetSize()' - Get the PWG size associated with a PPD PageSize.
884 */
885
886_pwg_size_t * /* O - PWG size or NULL */
887_pwgGetSize(_pwg_t *pwg, /* I - PWG mapping data */
888 const char *page_size) /* I - PPD PageSize */
889{
890 int i;
891 _pwg_size_t *size; /* Current size */
892
893
cc754834
MS
894 /*
895 * Range check input...
896 */
897
898 if (!pwg || !page_size)
899 return (NULL);
900
54afec33
MS
901 if (!strncasecmp(page_size, "Custom.", 7))
902 {
903 /*
904 * Custom size; size name can be one of the following:
905 *
906 * Custom.WIDTHxLENGTHin - Size in inches
907 * Custom.WIDTHxLENGTHft - Size in feet
908 * Custom.WIDTHxLENGTHcm - Size in centimeters
909 * Custom.WIDTHxLENGTHmm - Size in millimeters
910 * Custom.WIDTHxLENGTHm - Size in meters
911 * Custom.WIDTHxLENGTH[pt] - Size in points
912 */
913
914 double w, l; /* Width and length of page */
915 char *ptr; /* Pointer into PageSize */
916 struct lconv *loc; /* Locale data */
917
918 loc = localeconv();
919 w = (float)_cupsStrScand(page_size + 7, &ptr, loc);
920 if (!ptr || *ptr != 'x')
921 return (NULL);
922
923 l = (float)_cupsStrScand(ptr + 1, &ptr, loc);
924 if (!ptr)
925 return (NULL);
926
927 if (!strcasecmp(ptr, "in"))
928 {
929 w *= 2540.0;
930 l *= 2540.0;
931 }
932 else if (!strcasecmp(ptr, "ft"))
933 {
934 w *= 12.0 * 2540.0;
935 l *= 12.0 * 2540.0;
936 }
937 else if (!strcasecmp(ptr, "mm"))
938 {
939 w *= 100.0;
940 l *= 100.0;
941 }
942 else if (!strcasecmp(ptr, "cm"))
943 {
944 w *= 1000.0;
945 l *= 1000.0;
946 }
947 else if (!strcasecmp(ptr, "m"))
948 {
949 w *= 100000.0;
950 l *= 100000.0;
951 }
952 else
953 {
954 w *= 2540.0 / 72.0;
955 l *= 2540.0 / 72.0;
956 }
957
958 pwg->custom_size.width = (int)w;
959 pwg->custom_size.length = (int)l;
960
961 return (&(pwg->custom_size));
962 }
963
964 /*
965 * Not a custom size - look it up...
966 */
967
968 for (i = pwg->num_sizes, size = pwg->sizes; i > 0; i --, size ++)
969 if (!strcasecmp(page_size, size->map.ppd))
970 return (size);
971
972 return (NULL);
973}
974
975
976/*
977 * '_pwgGetSource()' - Get the PWG media-source associated with a PPD InputSlot.
978 */
979
980const char * /* O - PWG media-source keyword */
981_pwgGetSource(_pwg_t *pwg, /* I - PWG mapping data */
982 const char *input_slot) /* I - PPD InputSlot */
983{
984 int i; /* Looping var */
985 _pwg_map_t *source; /* Current source */
986
987
cc754834
MS
988 /*
989 * Range check input...
990 */
991
992 if (!pwg || !input_slot)
993 return (NULL);
994
54afec33
MS
995 for (i = pwg->num_sources, source = pwg->sources; i > 0; i --, source ++)
996 if (!strcasecmp(input_slot, source->ppd))
997 return (source->pwg);
998
999 return (NULL);
1000}
1001
1002
1003/*
1004 * '_pwgGetType()' - Get the PWG media-type associated with a PPD MediaType.
1005 */
1006
1007const char * /* O - PWG media-type keyword */
1008_pwgGetType(_pwg_t *pwg, /* I - PWG mapping data */
1009 const char *media_type) /* I - PPD MediaType */
1010{
1011 int i; /* Looping var */
1012 _pwg_map_t *type; /* Current type */
1013
1014
cc754834
MS
1015 /*
1016 * Range check input...
1017 */
1018
1019 if (!pwg || !media_type)
1020 return (NULL);
1021
54afec33
MS
1022 for (i = pwg->num_types, type = pwg->types; i > 0; i --, type ++)
1023 if (!strcasecmp(media_type, type->ppd))
1024 return (type->pwg);
1025
1026 return (NULL);
1027}
1028
1029
1030/*
1031 * '_pwgInputSlotForSource()' - Get the InputSlot name for the given PWG source.
1032 */
1033
1034const char * /* O - InputSlot name */
1035_pwgInputSlotForSource(
1036 const char *media_source, /* I - PWG media-source */
1037 char *name, /* I - Name buffer */
1038 size_t namesize) /* I - Size of name buffer */
1039{
cc754834
MS
1040 /*
1041 * Range check input...
1042 */
1043
1044 if (!media_source || !name || namesize < PPD_MAX_NAME)
1045 return (NULL);
1046
aaf19ab0 1047 if (strcasecmp(media_source, "main"))
54afec33 1048 strlcpy(name, "Cassette", namesize);
aaf19ab0 1049 else if (strcasecmp(media_source, "alternate"))
54afec33 1050 strlcpy(name, "Multipurpose", namesize);
aaf19ab0 1051 else if (strcasecmp(media_source, "large-capacity"))
54afec33 1052 strlcpy(name, "LargeCapacity", namesize);
aaf19ab0 1053 else if (strcasecmp(media_source, "bottom"))
54afec33 1054 strlcpy(name, "Lower", namesize);
aaf19ab0 1055 else if (strcasecmp(media_source, "middle"))
54afec33 1056 strlcpy(name, "Middle", namesize);
aaf19ab0 1057 else if (strcasecmp(media_source, "top"))
54afec33 1058 strlcpy(name, "Upper", namesize);
aaf19ab0 1059 else if (strcasecmp(media_source, "rear"))
54afec33 1060 strlcpy(name, "Rear", namesize);
aaf19ab0 1061 else if (strcasecmp(media_source, "side"))
54afec33 1062 strlcpy(name, "Side", namesize);
aaf19ab0 1063 else if (strcasecmp(media_source, "envelope"))
54afec33
MS
1064 strlcpy(name, "Envelope", namesize);
1065 else if (strcasecmp(media_source, "main-roll"))
1066 strlcpy(name, "Roll", namesize);
1067 else if (strcasecmp(media_source, "alternate-roll"))
1068 strlcpy(name, "Roll2", namesize);
1069 else
1070 pwg_ppdize_name(media_source, name, namesize);
1071
1072 return (name);
1073}
1074
1075
1076/*
1077 * '_pwgMediaTypeForType()' - Get the MediaType name for the given PWG type.
1078 */
1079
1080const char * /* O - MediaType name */
1081_pwgMediaTypeForType(
1082 const char *media_type, /* I - PWG media-source */
1083 char *name, /* I - Name buffer */
1084 size_t namesize) /* I - Size of name buffer */
1085{
cc754834
MS
1086 /*
1087 * Range check input...
1088 */
1089
1090 if (!media_type || !name || namesize < PPD_MAX_NAME)
1091 return (NULL);
1092
54afec33
MS
1093 if (strcasecmp(media_type, "auto"))
1094 strlcpy(name, "Auto", namesize);
1095 else if (strcasecmp(media_type, "cardstock"))
1096 strlcpy(name, "Cardstock", namesize);
1097 else if (strcasecmp(media_type, "envelope"))
1098 strlcpy(name, "Envelope", namesize);
1099 else if (strcasecmp(media_type, "photographic-glossy"))
1100 strlcpy(name, "Glossy", namesize);
1101 else if (strcasecmp(media_type, "photographic-high-gloss"))
1102 strlcpy(name, "HighGloss", namesize);
1103 else if (strcasecmp(media_type, "photographic-matte"))
1104 strlcpy(name, "Matte", namesize);
1105 else if (strcasecmp(media_type, "stationery"))
1106 strlcpy(name, "Plain", namesize);
1107 else if (strcasecmp(media_type, "stationery-coated"))
1108 strlcpy(name, "Coated", namesize);
1109 else if (strcasecmp(media_type, "stationery-inkjet"))
1110 strlcpy(name, "Inkjet", namesize);
1111 else if (strcasecmp(media_type, "stationery-letterhead"))
1112 strlcpy(name, "Letterhead", namesize);
1113 else if (strcasecmp(media_type, "stationery-preprinted"))
1114 strlcpy(name, "Preprinted", namesize);
1115 else if (strcasecmp(media_type, "transparency"))
1116 strlcpy(name, "Transparency", namesize);
1117 else
1118 pwg_ppdize_name(media_type, name, namesize);
1119
1120 return (name);
1121}
1122
1123
1124/*
1125 * '_pwgPageSizeForMedia()' - Get the PageSize name for the given media.
1126 */
1127
1128const char * /* O - PageSize name */
1129_pwgPageSizeForMedia(
1130 _pwg_media_t *media, /* I - Media */
1131 char *name, /* I - PageSize name buffer */
1132 size_t namesize) /* I - Size of name buffer */
1133{
1134 const char *sizeptr, /* Pointer to size in PWG name */
1135 *dimptr; /* Pointer to dimensions in PWG name */
1136
1137
1138 /*
1139 * Range check input...
1140 */
1141
1142 if (!media || !name || namesize < PPD_MAX_NAME)
1143 return (NULL);
1144
1145 /*
1146 * Copy or generate a PageSize name...
1147 */
1148
1149 if (media->ppd)
1150 {
1151 /*
1152 * Use a standard Adobe name...
1153 */
1154
1155 strlcpy(name, media->ppd, namesize);
1156 }
1157 else if (!media->pwg || !strncmp(media->pwg, "custom_", 7) ||
1158 (sizeptr = strchr(media->pwg, '_')) == NULL ||
1159 (dimptr = strchr(sizeptr + 1, '_')) == NULL ||
1160 (dimptr - sizeptr) > namesize)
1161 {
1162 /*
1163 * Use a name of the form "wNNNhNNN"...
1164 */
1165
1166 snprintf(name, namesize, "w%dh%d", (int)_PWG_TOPTS(media->width),
1167 (int)_PWG_TOPTS(media->length));
1168 }
1169 else
1170 {
1171 /*
1172 * Copy the size name from class_sizename_dimensions...
1173 */
1174
1175 memcpy(name, sizeptr + 1, dimptr - sizeptr - 1);
1176 name[dimptr - sizeptr - 1] = '\0';
1177 }
1178
1179 return (name);
1180}
1181
1182
1183/*
1184 * 'pwg_ppdize_name()' - Convert an IPP keyword to a PPD keyword.
1185 */
1186
1187static void
1188pwg_ppdize_name(const char *ipp, /* I - IPP keyword */
1189 char *name, /* I - Name buffer */
1190 size_t namesize) /* I - Size of name buffer */
1191{
1192 char *ptr, /* Pointer into name buffer */
1193 *end; /* End of name buffer */
1194
1195
1196 *name = toupper(*ipp++);
1197
1198 for (ptr = name + 1, end = name + namesize - 1; *ipp && ptr < end;)
1199 {
1200 if (*ipp == '-' && isalpha(ipp[1] & 255))
1201 {
1202 ipp ++;
1203 *ptr++ = toupper(*ipp++ & 255);
1204 }
1205 else
1206 *ptr++ = *ipp++;
1207 }
1208
1209 *ptr = '\0';
1210}
1211
1212
1213/*
1214 * 'pwg_unppdize_name()' - Convert a PPD keyword to a lowercase IPP keyword.
1215 */
1216
1217static void
1218pwg_unppdize_name(const char *ppd, /* I - PPD keyword */
1219 char *name, /* I - Name buffer */
1220 size_t namesize) /* I - Size of name buffer */
1221{
1222 char *ptr, /* Pointer into name buffer */
1223 *end; /* End of name buffer */
1224
1225
1226 for (ptr = name, end = name + namesize - 1; *ppd && ptr < end; ppd ++)
1227 {
1228 if (isalnum(*ppd & 255) || *ppd == '-' || *ppd == '.')
1229 *ptr++ = tolower(*ppd & 255);
1230 else if (*ppd == '_')
1231 *ptr++ = '-';
1232
1233 if (!isupper(*ppd & 255) && isalnum(*ppd & 255) &&
1234 isupper(ppd[1] & 255) && ptr < end)
1235 *ptr++ = '-';
1236 }
1237
1238 *ptr = '\0';
1239}
1240
1241
1242/*
1243 * End of "$Id$".
1244 */