• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * PPD model-specific attribute routines for CUPS.
3  *
4  * Copyright © 2020-2024 by OpenPrinting.
5  * Copyright 2007-2015 by Apple Inc.
6  * Copyright 1997-2006 by Easy Software Products.
7  *
8  * Licensed under Apache License v2.0.  See the file "LICENSE" for more
9  * information.
10  */
11 
12 /*
13  * Include necessary headers...
14  */
15 
16 #include "cups-private.h"
17 #include "ppd-private.h"
18 #include "debug-internal.h"
19 
20 
21 /*
22  * 'ppdFindAttr()' - Find the first matching attribute.
23  *
24  * @since CUPS 1.1.19/macOS 10.3@
25  */
26 
27 ppd_attr_t *				/* O - Attribute or @code NULL@ if not found */
ppdFindAttr(ppd_file_t * ppd,const char * name,const char * spec)28 ppdFindAttr(ppd_file_t *ppd,		/* I - PPD file data */
29             const char *name,		/* I - Attribute name */
30             const char *spec)		/* I - Specifier string or @code NULL@ */
31 {
32   ppd_attr_t	key,			/* Search key */
33 		*attr;			/* Current attribute */
34 
35 
36   DEBUG_printf(("2ppdFindAttr(ppd=%p, name=\"%s\", spec=\"%s\")", ppd, name,
37                 spec));
38 
39  /*
40   * Range check input...
41   */
42 
43   if (!ppd || !name || ppd->num_attrs == 0)
44     return (NULL);
45 
46  /*
47   * Search for a matching attribute...
48   */
49 
50   memset(&key, 0, sizeof(key));
51   strlcpy(key.name, name, sizeof(key.name));
52 
53  /*
54   * Return the first matching attribute, if any...
55   */
56 
57   if ((attr = (ppd_attr_t *)cupsArrayFind(ppd->sorted_attrs, &key)) != NULL)
58   {
59     if (spec)
60     {
61      /*
62       * Loop until we find the first matching attribute for "spec"...
63       */
64 
65       while (attr && _cups_strcasecmp(spec, attr->spec))
66       {
67         if ((attr = (ppd_attr_t *)cupsArrayNext(ppd->sorted_attrs)) != NULL &&
68 	    _cups_strcasecmp(attr->name, name))
69 	  attr = NULL;
70       }
71     }
72   }
73 
74   return (attr);
75 }
76 
77 
78 /*
79  * 'ppdFindNextAttr()' - Find the next matching attribute.
80  *
81  * @since CUPS 1.1.19/macOS 10.3@
82  */
83 
84 ppd_attr_t *				/* O - Attribute or @code NULL@ if not found */
ppdFindNextAttr(ppd_file_t * ppd,const char * name,const char * spec)85 ppdFindNextAttr(ppd_file_t *ppd,	/* I - PPD file data */
86                 const char *name,	/* I - Attribute name */
87 		const char *spec)	/* I - Specifier string or @code NULL@ */
88 {
89   ppd_attr_t	*attr;			/* Current attribute */
90 
91 
92  /*
93   * Range check input...
94   */
95 
96   if (!ppd || !name || ppd->num_attrs == 0)
97     return (NULL);
98 
99  /*
100   * See if there are more attributes to return...
101   */
102 
103   while ((attr = (ppd_attr_t *)cupsArrayNext(ppd->sorted_attrs)) != NULL)
104   {
105    /*
106     * Check the next attribute to see if it is a match...
107     */
108 
109     if (_cups_strcasecmp(attr->name, name))
110     {
111      /*
112       * Nope, reset the current pointer to the end of the array...
113       */
114 
115       cupsArrayIndex(ppd->sorted_attrs, cupsArrayCount(ppd->sorted_attrs));
116 
117       return (NULL);
118     }
119 
120     if (!spec || !_cups_strcasecmp(attr->spec, spec))
121       break;
122   }
123 
124  /*
125   * Return the next attribute's value...
126   */
127 
128   return (attr);
129 }
130 
131 
132 /*
133  * '_ppdNormalizeMakeAndModel()' - Normalize a product/make-and-model string.
134  *
135  * This function tries to undo the mistakes made by many printer manufacturers
136  * to produce a clean make-and-model string we can use.
137  */
138 
139 char *					/* O - Normalized make-and-model string or NULL on error */
_ppdNormalizeMakeAndModel(const char * make_and_model,char * buffer,size_t bufsize)140 _ppdNormalizeMakeAndModel(
141     const char *make_and_model,		/* I - Original make-and-model string */
142     char       *buffer,			/* I - String buffer */
143     size_t     bufsize)			/* I - Size of string buffer */
144 {
145   char	*bufptr;			/* Pointer into buffer */
146 
147 
148   if (!make_and_model || !buffer || bufsize < 1)
149   {
150     if (buffer)
151       *buffer = '\0';
152 
153     return (NULL);
154   }
155 
156  /*
157   * Skip leading whitespace...
158   */
159 
160   while (_cups_isspace(*make_and_model))
161     make_and_model ++;
162 
163  /*
164   * Remove parenthesis and add manufacturers as needed...
165   */
166 
167   if (make_and_model[0] == '(')
168   {
169     strlcpy(buffer, make_and_model + 1, bufsize);
170 
171     if ((bufptr = strrchr(buffer, ')')) != NULL)
172       *bufptr = '\0';
173   }
174   else if (!_cups_strncasecmp(make_and_model, "XPrint ", 7))
175   {
176    /*
177     * Xerox XPrint...
178     * Note: We check for the space after XPrint to ensure we do not display
179     * Xerox for Xprinter devices, which are NOT by Xerox.
180     */
181 
182     snprintf(buffer, bufsize, "Xerox %s", make_and_model);
183   }
184   else if (!_cups_strncasecmp(make_and_model, "Eastman", 7))
185   {
186    /*
187     * Kodak...
188     */
189 
190     snprintf(buffer, bufsize, "Kodak %s", make_and_model + 7);
191   }
192   else if (!_cups_strncasecmp(make_and_model, "laserwriter", 11))
193   {
194    /*
195     * Apple LaserWriter...
196     */
197 
198     snprintf(buffer, bufsize, "Apple LaserWriter%s", make_and_model + 11);
199   }
200   else if (!_cups_strncasecmp(make_and_model, "colorpoint", 10))
201   {
202    /*
203     * Seiko...
204     */
205 
206     snprintf(buffer, bufsize, "Seiko %s", make_and_model);
207   }
208   else if (!_cups_strncasecmp(make_and_model, "fiery", 5))
209   {
210    /*
211     * EFI...
212     */
213 
214     snprintf(buffer, bufsize, "EFI %s", make_and_model);
215   }
216   else if (!_cups_strncasecmp(make_and_model, "ps ", 3) ||
217 	   !_cups_strncasecmp(make_and_model, "colorpass", 9))
218   {
219    /*
220     * Canon...
221     */
222 
223     snprintf(buffer, bufsize, "Canon %s", make_and_model);
224   }
225   else if (!_cups_strncasecmp(make_and_model, "designjet", 9) ||
226            !_cups_strncasecmp(make_and_model, "deskjet", 7))
227   {
228    /*
229     * HP...
230     */
231 
232     snprintf(buffer, bufsize, "HP %s", make_and_model);
233   }
234   else
235     strlcpy(buffer, make_and_model, bufsize);
236 
237  /*
238   * Clean up the make...
239   */
240 
241   if (!_cups_strncasecmp(buffer, "agfa", 4))
242   {
243    /*
244     * Replace with AGFA (all uppercase)...
245     */
246 
247     buffer[0] = 'A';
248     buffer[1] = 'G';
249     buffer[2] = 'F';
250     buffer[3] = 'A';
251   }
252   else if (!_cups_strncasecmp(buffer, "Hewlett-Packard hp ", 19))
253   {
254    /*
255     * Just put "HP" on the front...
256     */
257 
258     buffer[0] = 'H';
259     buffer[1] = 'P';
260     _cups_strcpy(buffer + 2, buffer + 18);
261   }
262   else if (!_cups_strncasecmp(buffer, "Hewlett-Packard ", 16))
263   {
264    /*
265     * Just put "HP" on the front...
266     */
267 
268     buffer[0] = 'H';
269     buffer[1] = 'P';
270     _cups_strcpy(buffer + 2, buffer + 15);
271   }
272   else if (!_cups_strncasecmp(buffer, "Lexmark International", 21))
273   {
274    /*
275     * Strip "International"...
276     */
277 
278     _cups_strcpy(buffer + 8, buffer + 21);
279   }
280   else if (!_cups_strncasecmp(buffer, "herk", 4))
281   {
282    /*
283     * Replace with LHAG...
284     */
285 
286     buffer[0] = 'L';
287     buffer[1] = 'H';
288     buffer[2] = 'A';
289     buffer[3] = 'G';
290   }
291   else if (!_cups_strncasecmp(buffer, "linotype", 8))
292   {
293    /*
294     * Replace with LHAG...
295     */
296 
297     buffer[0] = 'L';
298     buffer[1] = 'H';
299     buffer[2] = 'A';
300     buffer[3] = 'G';
301     _cups_strcpy(buffer + 4, buffer + 8);
302   }
303 
304  /*
305   * Remove trailing whitespace and return...
306   */
307 
308   for (bufptr = buffer + strlen(buffer) - 1;
309        bufptr >= buffer && _cups_isspace(*bufptr);
310        bufptr --);
311 
312   bufptr[1] = '\0';
313 
314   return (buffer[0] ? buffer : NULL);
315 }
316