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