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