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