Coverage Report

Created: 2025-10-28 06:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}