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