1 //
2 // PPD file import methods for the CUPS PPD Compiler.
3 //
4 // Copyright 2007-2011 by Apple Inc.
5 // Copyright 2002-2006 by Easy Software Products.
6 //
7 // Licensed under Apache License v2.0. See the file "LICENSE" for more information.
8 //
9
10 //
11 // Include necessary headers...
12 //
13
14 #include "ppdc-private.h"
15 #include <cups/ppd.h>
16
17
18 //
19 // 'ppdcSource::import_ppd()' - Import a PPD file.
20 //
21
22 int // O - 1 on success, 0 on failure
import_ppd(const char * f)23 ppdcSource::import_ppd(const char *f) // I - Filename
24 {
25 int i, j, k; // Looping vars
26 cups_file_t *fp; // File
27 char line[256], // Comment line
28 *ptr; // Pointer into line
29 int cost; // Cost for filter
30 ppd_file_t *ppd; // PPD file data
31 ppd_group_t *group; // PPD group
32 ppd_option_t *option; // PPD option
33 ppd_choice_t *choice; // PPD choice
34 ppd_attr_t *attr; // PPD attribute
35 ppd_const_t *constraint; // PPD UI constraint
36 ppd_const_t *constraint2; // Temp PPD UI constraint
37 ppd_size_t *size; // PPD page size
38 ppdcDriver *driver; // Driver
39 ppdcFilter *filter; // Current filter
40 ppdcFont *font; // Font
41 ppdcGroup *cgroup; // UI group
42 ppdcOption *coption; // UI option
43 ppdcChoice *cchoice; // UI choice
44 ppdcConstraint *cconstraint; // UI constraint
45 ppdcMediaSize *csize; // Media size
46
47
48 // Try opening the PPD file...
49 if ((ppd = ppdOpenFile(f)) == NULL)
50 return (0);
51
52 // All PPD files need a PCFileName attribute...
53 if (!ppd->pcfilename)
54 {
55 ppdClose(ppd);
56 return (0);
57 }
58
59 // See if the driver has already been imported...
60 if ((driver = find_driver(ppd->pcfilename)) == NULL)
61 {
62 // Create a new PPD file...
63 if ((fp = cupsFileOpen(f, "r")) == NULL)
64 {
65 ppdClose(ppd);
66 return (0);
67 }
68
69 driver = new ppdcDriver();
70 driver->type = PPDC_DRIVER_PS;
71
72 drivers->add(driver);
73
74 // Read the initial comments from the PPD file and use them as the
75 // copyright/license text...
76 cupsFileGets(fp, line, sizeof(line));
77 // Skip *PPD-Adobe-M.m
78
79 while (cupsFileGets(fp, line, sizeof(line)))
80 if (strncmp(line, "*%", 2))
81 break;
82 else if (strncmp(line, "*%%%% ", 6))
83 {
84 for (ptr = line + 2; isspace(*ptr); ptr ++);
85
86 driver->add_copyright(ptr);
87 }
88
89 cupsFileClose(fp);
90
91 // Then add the stuff from the PPD file...
92 if (ppd->modelname && ppd->manufacturer &&
93 !_cups_strncasecmp(ppd->modelname, ppd->manufacturer,
94 strlen(ppd->manufacturer)))
95 {
96 ptr = ppd->modelname + strlen(ppd->manufacturer);
97
98 while (isspace(*ptr))
99 ptr ++;
100 }
101 else
102 ptr = ppd->modelname;
103
104 if (ppd->nickname)
105 driver->add_attr(new ppdcAttr("NickName", NULL, NULL, ppd->nickname));
106
107 if (ppd->shortnickname)
108 driver->add_attr(new ppdcAttr("ShortNickName", NULL, NULL,
109 ppd->shortnickname));
110
111 driver->manufacturer = new ppdcString(ppd->manufacturer);
112 driver->model_name = new ppdcString(ptr);
113 driver->pc_file_name = new ppdcString(ppd->pcfilename);
114 attr = ppdFindAttr(ppd, "FileVersion", NULL);
115 driver->version = new ppdcString(attr ? attr->value : NULL);
116 driver->model_number = ppd->model_number;
117 driver->manual_copies = ppd->manual_copies;
118 driver->color_device = ppd->color_device;
119 driver->throughput = ppd->throughput;
120 driver->variable_paper_size = ppd->variable_sizes;
121 driver->max_width = ppd->custom_max[0];
122 driver->max_length = ppd->custom_max[1];
123 driver->min_width = ppd->custom_min[0];
124 driver->min_length = ppd->custom_min[1];
125 driver->left_margin = ppd->custom_margins[0];
126 driver->bottom_margin = ppd->custom_margins[1];
127 driver->right_margin = ppd->custom_margins[2];
128 driver->top_margin = ppd->custom_margins[3];
129
130 for (i = 0; i < ppd->num_filters; i ++)
131 {
132 strlcpy(line, ppd->filters[i], sizeof(line));
133
134 for (ptr = line; *ptr; ptr ++)
135 if (isspace(*ptr & 255))
136 break;
137 *ptr++ = '\0';
138
139 cost = strtol(ptr, &ptr, 10);
140
141 while (isspace(*ptr & 255))
142 ptr ++;
143
144 filter = new ppdcFilter(line, ptr, cost);
145 driver->add_filter(filter);
146 }
147
148 attr = ppdFindAttr(ppd, "DefaultFont", NULL);
149 driver->default_font = new ppdcString(attr ? attr->value : NULL);
150
151 // Collect media sizes...
152 ppd_option_t *region_option, // PageRegion option
153 *size_option; // PageSize option
154 ppd_choice_t *region_choice, // PageRegion choice
155 *size_choice; // PageSize choice
156
157 region_option = ppdFindOption(ppd, "PageRegion");
158 size_option = ppdFindOption(ppd, "PageSize");
159
160 for (i = ppd->num_sizes, size = ppd->sizes; i > 0; i --, size ++)
161 {
162 // Don't do custom size here...
163 if (!_cups_strcasecmp(size->name, "Custom"))
164 continue;
165
166 // Get the code for the PageSize and PageRegion options...
167 region_choice = ppdFindChoice(region_option, size->name);
168 size_choice = ppdFindChoice(size_option, size->name);
169
170 // Create a new media size record and add it to the driver...
171 csize = new ppdcMediaSize(size->name, size_choice->text, size->width,
172 size->length, size->left, size->bottom,
173 size->width - size->right,
174 size->length - size->top,
175 size_choice->code, region_choice->code);
176
177 driver->add_size(csize);
178
179 if (!_cups_strcasecmp(size_option->defchoice, size->name))
180 driver->set_default_size(csize);
181 }
182
183 // Now all of the options...
184 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
185 {
186 cgroup = new ppdcGroup(group->name, group->text);
187 driver->add_group(cgroup);
188
189 for (j = group->num_options, option = group->options; j > 0; j --, option ++)
190 {
191 if (!strcmp(option->keyword, "PageSize") || !strcmp(option->keyword, "PageRegion"))
192 continue;
193
194 coption = new ppdcOption((ppdcOptType)option->ui, option->keyword,
195 option->text, (ppdcOptSection)option->section,
196 option->order);
197 cgroup->add_option(coption);
198
199 for (k = option->num_choices, choice = option->choices; k > 0; k --, choice ++)
200 {
201 if (!strcmp(choice->choice, "Custom"))
202 continue;
203
204 cchoice = new ppdcChoice(choice->choice, choice->text, choice->code);
205 coption->add_choice(cchoice);
206
207 if (!_cups_strcasecmp(option->defchoice, choice->choice))
208 coption->set_defchoice(cchoice);
209 }
210 }
211 }
212
213 // Now the constraints...
214 for (i = ppd->num_consts, constraint = ppd->consts;
215 i > 0;
216 i --, constraint ++)
217 {
218 // Look for mirrored constraints...
219 for (j = i - 1, constraint2 = constraint + 1;
220 j > 0;
221 j --, constraint2 ++)
222 if (!strcmp(constraint->option1, constraint2->option2) &&
223 !strcmp(constraint->choice1, constraint2->choice2) &&
224 !strcmp(constraint->option2, constraint2->option1) &&
225 !strcmp(constraint->choice2, constraint2->choice1))
226 break;
227
228 if (j)
229 continue;
230
231 cconstraint = new ppdcConstraint(constraint->option2, constraint->choice2,
232 constraint->option1, constraint->choice1);
233 driver->add_constraint(cconstraint);
234 }
235
236 for (i = 0; i < ppd->num_attrs; i ++)
237 {
238 attr = ppd->attrs[i];
239
240 if (!strcmp(attr->name, "Font"))
241 {
242 // Font...
243 char encoding[256], // Encoding string
244 version[256], // Version string
245 charset[256], // Charset string
246 status[256]; // Status string
247 ppdcFontStatus fstatus; // Status enumeration
248
249
250 if (sscanf(attr->value, "%s%*[^\"]\"%[^\"]\"%s%s", encoding, version,
251 charset, status) != 4)
252 {
253 _cupsLangPrintf(stderr, _("ppdc: Bad font attribute: %s"),
254 attr->value);
255 continue;
256 }
257
258 if (!strcmp(status, "ROM"))
259 fstatus = PPDC_FONT_ROM;
260 else
261 fstatus = PPDC_FONT_DISK;
262
263 font = new ppdcFont(attr->spec, encoding, version, charset, fstatus);
264
265 driver->add_font(font);
266 }
267 else if (!strcmp(attr->name, "CustomPageSize"))
268 {
269 driver->set_custom_size_code(attr->value);
270 }
271 else if ((strncmp(attr->name, "Default", 7) ||
272 !strcmp(attr->name, "DefaultColorSpace")) &&
273 strcmp(attr->name, "ColorDevice") &&
274 strcmp(attr->name, "Manufacturer") &&
275 strcmp(attr->name, "ModelName") &&
276 strcmp(attr->name, "MaxMediaHeight") &&
277 strcmp(attr->name, "MaxMediaWidth") &&
278 strcmp(attr->name, "NickName") &&
279 strcmp(attr->name, "ParamCustomPageSize") &&
280 strcmp(attr->name, "ShortNickName") &&
281 strcmp(attr->name, "Throughput") &&
282 strcmp(attr->name, "PCFileName") &&
283 strcmp(attr->name, "FileVersion") &&
284 strcmp(attr->name, "FormatVersion") &&
285 strcmp(attr->name, "HWMargins") &&
286 strcmp(attr->name, "VariablePaperSize") &&
287 strcmp(attr->name, "LanguageEncoding") &&
288 strcmp(attr->name, "LanguageVersion") &&
289 strcmp(attr->name, "cupsFilter") &&
290 strcmp(attr->name, "cupsFlipDuplex") &&
291 strcmp(attr->name, "cupsLanguages") &&
292 strcmp(attr->name, "cupsManualCopies") &&
293 strcmp(attr->name, "cupsModelNumber") &&
294 strcmp(attr->name, "cupsVersion"))
295 {
296 if ((ptr = strchr(attr->name, '.')) != NULL &&
297 ((ptr - attr->name) == 2 || (ptr - attr->name) == 5))
298 {
299 // Might be a localization attribute; test further...
300 if (isalpha(attr->name[0] & 255) &&
301 isalpha(attr->name[1] & 255) &&
302 (attr->name[2] == '.' ||
303 (attr->name[2] == '_' && isalpha(attr->name[3] & 255) &&
304 isalpha(attr->name[4] & 255))))
305 continue;
306 }
307
308 // Attribute...
309 driver->add_attr(new ppdcAttr(attr->name, attr->spec, attr->text,
310 attr->value));
311 }
312 else if (!strncmp(attr->name, "Default", 7) &&
313 !ppdFindOption(ppd, attr->name + 7) &&
314 strcmp(attr->name, "DefaultFont") &&
315 strcmp(attr->name, "DefaultImageableArea") &&
316 strcmp(attr->name, "DefaultPaperDimension") &&
317 strcmp(attr->name, "DefaultFont"))
318 {
319 // Default attribute...
320 driver->add_attr(new ppdcAttr(attr->name, attr->spec, attr->text,
321 attr->value));
322 }
323 }
324 }
325
326 return (1);
327 }
328