• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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