ppd_attr_t * /* O - Localized attribute or @code NULL@ if none exists */ ppdLocalizeAttr(ppd_file_t *ppd, /* I - PPD file */ const char *keyword, /* I - Main keyword */ const char *spec) /* I - Option keyword or @code NULL@ for none */ { ppd_attr_t *locattr; /* Localized attribute */ char ll_CC[6]; /* Language + country locale */ /* * Get the default language... */ ppd_ll_CC(ll_CC, sizeof(ll_CC)); /* * Find the localized attribute... */ if (spec) locattr = _ppdLocalizedAttr(ppd, keyword, spec, ll_CC); else locattr = _ppdLocalizedAttr(ppd, "Translation", keyword, ll_CC); if (!locattr) locattr = ppdFindAttr(ppd, keyword, spec); return (locattr); }
const char * /* O - Value or @code NULL@ if not found */ ppdLocalizeMarkerName( ppd_file_t *ppd, /* I - PPD file */ const char *name) /* I - Marker name to look up */ { ppd_attr_t *locattr; /* Localized attribute */ char ll_CC[6]; /* Language + country locale */ /* * Range check input... */ if (!ppd || !name) return (NULL); /* * Get the default language... */ ppd_ll_CC(ll_CC, sizeof(ll_CC)); /* * Find the localized attribute... */ if ((locattr = _ppdLocalizedAttr(ppd, "cupsMarkerName", name, ll_CC)) == NULL) locattr = ppdFindAttr(ppd, "cupsMarkerName", name); return (locattr ? locattr->text : NULL); }
static void colord_get_qualifier_format( ppd_file_t *ppd, /* I - PPD file data */ char *format[3]) /* I - Format tuple */ { const char *tmp; /* Temporary string */ ppd_attr_t *attr; /* Profile attributes */ /* * Get 1st section... */ if ((attr = ppdFindAttr(ppd, "cupsICCQualifier1", NULL)) != NULL) tmp = attr->value; else if (ppdFindAttr(ppd, "DefaultColorModel", NULL)) tmp = "ColorModel"; else if (ppdFindAttr(ppd, "DefaultColorSpace", NULL)) tmp = "ColorSpace"; else tmp = ""; format[0] = strdup(tmp); /* * Get 2nd section... */ if ((attr = ppdFindAttr(ppd, "cupsICCQualifier2", NULL)) != NULL) tmp = attr->value; else tmp = "MediaType"; format[1] = strdup(tmp); /* * Get 3rd section... */ if ((attr = ppdFindAttr(ppd, "cupsICCQualifier3", NULL)) != NULL) tmp = attr->value; else tmp = "Resolution"; format[2] = strdup(tmp); }
/* * Obtention d'une donnée du fichier PPD * Get a string from the PPD file */ PPDValue PPDFile::get(const char *name, const char *opt) { ppd_attr_t *attr; PPDValue val; if (!_ppd) { ERRORMSG(_("Trying to read a PPD file which wasn't opened")); return val; } if (!opt) attr = ppdFindAttr(_ppd, name, NULL); else attr = ppdFindAttr(_ppd, opt, name); if (!attr) { ppd_choice_t *choice; choice = ppdFindMarkedChoice(_ppd, name); if (!choice) return val; val.set(choice->choice); } else val.set(attr->value); return val; }
/* Read HPBOD attribute from PPD return 1 if set as 1 */ int require_bod() { int bodRequire = 0; ppd_attr_t *pattr = NULL; ppd_file_t *pppd = NULL; pppd = ppdOpenFile(getenv("PPD")); if (pppd == NULL) { fprintf (stderr, "HP PS : ppdOpenFile failed for %s\n", getenv("PPD")); return 0; } if (((pattr = ppdFindAttr(pppd, BOD_PPD_ATR, NULL)) != NULL) && (pattr && pattr->value != NULL)) { bodRequire = atoi(pattr->value); } return bodRequire; }
const char * /* O - Device URI or @code NULL@ */ cupsBackendDeviceURI(char **argv) /* I - Command-line arguments */ { const char *device_uri, /* Device URI */ *auth_info_required; /* AUTH_INFO_REQUIRED env var */ _cups_globals_t *cg = _cupsGlobals(); /* Global info */ int options; /* Resolve options */ ppd_file_t *ppd; /* PPD file */ ppd_attr_t *ppdattr; /* PPD attribute */ if ((device_uri = getenv("DEVICE_URI")) == NULL) { if (!argv || !argv[0] || !strchr(argv[0], ':')) return (NULL); device_uri = argv[0]; } options = _HTTP_RESOLVE_STDERR; if ((auth_info_required = getenv("AUTH_INFO_REQUIRED")) != NULL && !strcmp(auth_info_required, "negotiate")) options |= _HTTP_RESOLVE_FQDN; if ((ppd = ppdOpenFile(getenv("PPD"))) != NULL) { if ((ppdattr = ppdFindAttr(ppd, "cupsIPPFaxOut", NULL)) != NULL && !_cups_strcasecmp(ppdattr->value, "true")) options |= _HTTP_RESOLVE_FAXOUT; ppdClose(ppd); } return (_httpResolveURI(device_uri, cg->resolved_uri, sizeof(cg->resolved_uri), options, NULL, NULL)); }
static int /* O - Exit status */ auto_configure(ppd_file_t *ppd, /* I - PPD file */ const char *user) /* I - Printing user */ { int status = 0; /* Exit status */ ppd_option_t *option; /* Current option in PPD */ ppd_attr_t *attr; /* Query command attribute */ const char *valptr; /* Pointer into attribute value */ char buffer[1024], /* String buffer */ *bufptr; /* Pointer into buffer */ ssize_t bytes; /* Number of bytes read */ int datalen; /* Side-channel data length */ /* * See if the backend supports bidirectional I/O... */ datalen = 1; if (cupsSideChannelDoRequest(CUPS_SC_CMD_GET_BIDI, buffer, &datalen, 30.0) != CUPS_SC_STATUS_OK || buffer[0] != CUPS_SC_BIDI_SUPPORTED) { fputs("DEBUG: Unable to auto-configure PostScript Printer - no " "bidirectional I/O available!\n", stderr); return (1); } /* * Put the printer in PostScript mode... */ begin_ps(ppd, user); /* * (STR #4028) * * As a lot of PPDs contain bad PostScript query code, we need to prevent one * bad query sequence from affecting all auto-configuration. The following * error handler allows us to log PostScript errors to cupsd. */ puts("/cups_handleerror {\n" " $error /newerror false put\n" " (:PostScript error in \") print cups_query_keyword print (\": ) " "print\n" " $error /errorname get 128 string cvs print\n" " (; offending command:) print $error /command get 128 string cvs " "print (\n) print flush\n" "} bind def\n" "errordict /timeout {} put\n" "/cups_query_keyword (?Unknown) def\n"); fflush(stdout); /* * Wait for the printer to become connected... */ do { sleep(1); datalen = 1; } while (cupsSideChannelDoRequest(CUPS_SC_CMD_GET_CONNECTED, buffer, &datalen, 5.0) == CUPS_SC_STATUS_OK && !buffer[0]); /* * Then loop through every option in the PPD file and ask for the current * value... */ fputs("DEBUG: Auto-configuring PostScript printer...\n", stderr); for (option = ppdFirstOption(ppd); option; option = ppdNextOption(ppd)) { /* * See if we have a query command for this option... */ snprintf(buffer, sizeof(buffer), "?%s", option->keyword); if ((attr = ppdFindAttr(ppd, buffer, NULL)) == NULL || !attr->value) { fprintf(stderr, "DEBUG: Skipping %s option...\n", option->keyword); continue; } /* * Send the query code to the printer... */ fprintf(stderr, "DEBUG: Querying %s...\n", option->keyword); for (bufptr = buffer, valptr = attr->value; *valptr; valptr ++) { /* * Log the query code, breaking at newlines... */ if (*valptr == '\n') { *bufptr = '\0'; fprintf(stderr, "DEBUG: %s\\n\n", buffer); bufptr = buffer; } else if (*valptr < ' ') { if (bufptr >= (buffer + sizeof(buffer) - 4)) { *bufptr = '\0'; fprintf(stderr, "DEBUG: %s\n", buffer); bufptr = buffer; } if (*valptr == '\r') { *bufptr++ = '\\'; *bufptr++ = 'r'; } else if (*valptr == '\t') { *bufptr++ = '\\'; *bufptr++ = 't'; } else { *bufptr++ = '\\'; *bufptr++ = '0' + ((*valptr / 64) & 7); *bufptr++ = '0' + ((*valptr / 8) & 7); *bufptr++ = '0' + (*valptr & 7); } } else { if (bufptr >= (buffer + sizeof(buffer) - 1)) { *bufptr = '\0'; fprintf(stderr, "DEBUG: %s\n", buffer); bufptr = buffer; } *bufptr++ = *valptr; } } if (bufptr > buffer) { *bufptr = '\0'; fprintf(stderr, "DEBUG: %s\n", buffer); } printf("/cups_query_keyword (?%s) def\n", option->keyword); /* Set keyword for error reporting */ fputs("{ (", stdout); for (valptr = attr->value; *valptr; valptr ++) { if (*valptr == '(' || *valptr == ')' || *valptr == '\\') putchar('\\'); putchar(*valptr); } fputs(") cvx exec } stopped { cups_handleerror } if clear\n", stdout); /* Send query code */ fflush(stdout); datalen = 0; cupsSideChannelDoRequest(CUPS_SC_CMD_DRAIN_OUTPUT, buffer, &datalen, 5.0); /* * Read the response data... */ bufptr = buffer; buffer[0] = '\0'; while ((bytes = cupsBackChannelRead(bufptr, sizeof(buffer) - (size_t)(bufptr - buffer) - 1, 10.0)) > 0) { /* * No newline at the end? Go on reading ... */ bufptr += bytes; *bufptr = '\0'; if (bytes == 0 || (bufptr > buffer && bufptr[-1] != '\r' && bufptr[-1] != '\n')) continue; /* * Trim whitespace and control characters from both ends... */ bytes = bufptr - buffer; for (bufptr --; bufptr >= buffer; bufptr --) if (isspace(*bufptr & 255) || iscntrl(*bufptr & 255)) *bufptr = '\0'; else break; for (bufptr = buffer; isspace(*bufptr & 255) || iscntrl(*bufptr & 255); bufptr ++); if (bufptr > buffer) { _cups_strcpy(buffer, bufptr); bufptr = buffer; } fprintf(stderr, "DEBUG: Got %d bytes.\n", (int)bytes); /* * Skip blank lines... */ if (!buffer[0]) continue; /* * Check the response... */ if ((bufptr = strchr(buffer, ':')) != NULL) { /* * PostScript code for this option in the PPD is broken; show the * interpreter's error message that came back... */ fprintf(stderr, "DEBUG%s\n", bufptr); break; } /* * Verify the result is a valid option choice... */ if (!ppdFindChoice(option, buffer)) { if (!strcasecmp(buffer, "Unknown")) break; bufptr = buffer; buffer[0] = '\0'; continue; } /* * Write out the result and move on to the next option... */ fprintf(stderr, "PPD: Default%s=%s\n", option->keyword, buffer); break; } /* * Printer did not answer this option's query */ if (bytes <= 0) { fprintf(stderr, "DEBUG: No answer to query for option %s within 10 seconds.\n", option->keyword); status = 1; } } /* * Finish the job... */ fflush(stdout); end_ps(ppd); /* * Return... */ if (status) _cupsLangPrintFilter(stderr, "WARNING", _("Unable to configure printer options.")); return (0); }
int /* O - 1 if conflicts exist, 0 otherwise */ cupsMarkOptions( ppd_file_t *ppd, /* I - PPD file */ int num_options, /* I - Number of options */ cups_option_t *options) /* I - Options */ { int i, j; /* Looping vars */ char *ptr, /* Pointer into string */ s[255]; /* Temporary string */ const char *val, /* Pointer into value */ *media, /* media option */ *output_bin, /* output-bin option */ *page_size, /* PageSize option */ *ppd_keyword, /* PPD keyword */ *print_color_mode, /* print-color-mode option */ *print_quality, /* print-quality option */ *sides; /* sides option */ cups_option_t *optptr; /* Current option */ ppd_attr_t *attr; /* PPD attribute */ _ppd_cache_t *cache; /* PPD cache and mapping data */ /* * Check arguments... */ if (!ppd || num_options <= 0 || !options) return (0); ppd_debug_marked(ppd, "Before..."); /* * Do special handling for finishings, media, output-bin, output-mode, * print-color-mode, print-quality, and PageSize... */ media = cupsGetOption("media", num_options, options); output_bin = cupsGetOption("output-bin", num_options, options); page_size = cupsGetOption("PageSize", num_options, options); print_quality = cupsGetOption("print-quality", num_options, options); sides = cupsGetOption("sides", num_options, options); if ((print_color_mode = cupsGetOption("print-color-mode", num_options, options)) == NULL) print_color_mode = cupsGetOption("output-mode", num_options, options); if ((media || output_bin || print_color_mode || print_quality || sides) && !ppd->cache) { /* * Load PPD cache and mapping data as needed... */ ppd->cache = _ppdCacheCreateWithPPD(ppd); } cache = ppd->cache; if (media) { /* * Loop through the option string, separating it at commas and marking each * individual option as long as the corresponding PPD option (PageSize, * InputSlot, etc.) is not also set. * * For PageSize, we also check for an empty option value since some versions * of MacOS X use it to specify auto-selection of the media based solely on * the size. */ for (val = media; *val;) { /* * Extract the sub-option from the string... */ for (ptr = s; *val && *val != ',' && (ptr - s) < (sizeof(s) - 1);) *ptr++ = *val++; *ptr++ = '\0'; if (*val == ',') val ++; /* * Mark it... */ if (!page_size || !page_size[0]) { if (!_cups_strncasecmp(s, "Custom.", 7) || ppdPageSize(ppd, s)) ppd_mark_option(ppd, "PageSize", s); else if ((ppd_keyword = _ppdCacheGetPageSize(cache, NULL, s, NULL)) != NULL) ppd_mark_option(ppd, "PageSize", ppd_keyword); } if (cache && cache->source_option && !cupsGetOption(cache->source_option, num_options, options) && (ppd_keyword = _ppdCacheGetInputSlot(cache, NULL, s)) != NULL) ppd_mark_option(ppd, cache->source_option, ppd_keyword); if (!cupsGetOption("MediaType", num_options, options) && (ppd_keyword = _ppdCacheGetMediaType(cache, NULL, s)) != NULL) ppd_mark_option(ppd, "MediaType", ppd_keyword); } } if (cache) { if (!cupsGetOption("com.apple.print.DocumentTicket.PMSpoolFormat", num_options, options) && !cupsGetOption("APPrinterPreset", num_options, options) && (print_color_mode || print_quality)) { /* * Map output-mode and print-quality to a preset... */ _pwg_print_color_mode_t pwg_pcm;/* print-color-mode index */ _pwg_print_quality_t pwg_pq; /* print-quality index */ cups_option_t *preset;/* Current preset option */ if (print_color_mode && !strcmp(print_color_mode, "monochrome")) pwg_pcm = _PWG_PRINT_COLOR_MODE_MONOCHROME; else pwg_pcm = _PWG_PRINT_COLOR_MODE_COLOR; if (print_quality) { pwg_pq = atoi(print_quality) - IPP_QUALITY_DRAFT; if (pwg_pq < _PWG_PRINT_QUALITY_DRAFT) pwg_pq = _PWG_PRINT_QUALITY_DRAFT; else if (pwg_pq > _PWG_PRINT_QUALITY_HIGH) pwg_pq = _PWG_PRINT_QUALITY_HIGH; } else pwg_pq = _PWG_PRINT_QUALITY_NORMAL; if (cache->num_presets[pwg_pcm][pwg_pq] == 0) { /* * Try to find a preset that works so that we maximize the chances of us * getting a good print using IPP attributes. */ if (cache->num_presets[pwg_pcm][_PWG_PRINT_QUALITY_NORMAL] > 0) pwg_pq = _PWG_PRINT_QUALITY_NORMAL; else if (cache->num_presets[_PWG_PRINT_COLOR_MODE_COLOR][pwg_pq] > 0) pwg_pcm = _PWG_PRINT_COLOR_MODE_COLOR; else { pwg_pq = _PWG_PRINT_QUALITY_NORMAL; pwg_pcm = _PWG_PRINT_COLOR_MODE_COLOR; } } if (cache->num_presets[pwg_pcm][pwg_pq] > 0) { /* * Copy the preset options as long as the corresponding names are not * already defined in the IPP request... */ for (i = cache->num_presets[pwg_pcm][pwg_pq], preset = cache->presets[pwg_pcm][pwg_pq]; i > 0; i --, preset ++) { if (!cupsGetOption(preset->name, num_options, options)) ppd_mark_option(ppd, preset->name, preset->value); } } } if (output_bin && !cupsGetOption("OutputBin", num_options, options) && (ppd_keyword = _ppdCacheGetOutputBin(cache, output_bin)) != NULL) { /* * Map output-bin to OutputBin... */ ppd_mark_option(ppd, "OutputBin", ppd_keyword); } if (sides && cache->sides_option && !cupsGetOption(cache->sides_option, num_options, options)) { /* * Map sides to duplex option... */ if (!strcmp(sides, "one-sided") && cache->sides_1sided) ppd_mark_option(ppd, cache->sides_option, cache->sides_1sided); else if (!strcmp(sides, "two-sided-long-edge") && cache->sides_2sided_long) ppd_mark_option(ppd, cache->sides_option, cache->sides_2sided_long); else if (!strcmp(sides, "two-sided-short-edge") && cache->sides_2sided_short) ppd_mark_option(ppd, cache->sides_option, cache->sides_2sided_short); } } /* * Mark other options... */ for (i = num_options, optptr = options; i > 0; i --, optptr ++) if (!_cups_strcasecmp(optptr->name, "media") || !_cups_strcasecmp(optptr->name, "output-bin") || !_cups_strcasecmp(optptr->name, "output-mode") || !_cups_strcasecmp(optptr->name, "print-quality") || !_cups_strcasecmp(optptr->name, "sides")) continue; else if (!_cups_strcasecmp(optptr->name, "resolution") || !_cups_strcasecmp(optptr->name, "printer-resolution")) { ppd_mark_option(ppd, "Resolution", optptr->value); ppd_mark_option(ppd, "SetResolution", optptr->value); /* Calcomp, Linotype, QMS, Summagraphics, Tektronix, Varityper */ ppd_mark_option(ppd, "JCLResolution", optptr->value); /* HP */ ppd_mark_option(ppd, "CNRes_PGP", optptr->value); /* Canon */ } else if (!_cups_strcasecmp(optptr->name, "multiple-document-handling")) { if (!cupsGetOption("Collate", num_options, options) && ppdFindOption(ppd, "Collate")) { if (_cups_strcasecmp(optptr->value, "separate-documents-uncollated-copies")) ppd_mark_option(ppd, "Collate", "True"); else ppd_mark_option(ppd, "Collate", "False"); } } else if (!_cups_strcasecmp(optptr->name, "finishings")) { /* * Lookup cupsIPPFinishings attributes for each value... */ for (ptr = optptr->value; *ptr;) { /* * Get the next finishings number... */ if (!isdigit(*ptr & 255)) break; if ((j = strtol(ptr, &ptr, 10)) < 3) break; /* * Skip separator as needed... */ if (*ptr == ',') ptr ++; /* * Look it up in the PPD file... */ sprintf(s, "%d", j); if ((attr = ppdFindAttr(ppd, "cupsIPPFinishings", s)) == NULL) continue; /* * Apply "*Option Choice" settings from the attribute value... */ ppd_mark_choices(ppd, attr->value); } } else if (!_cups_strcasecmp(optptr->name, "APPrinterPreset")) { /* * Lookup APPrinterPreset value... */ if ((attr = ppdFindAttr(ppd, "APPrinterPreset", optptr->value)) != NULL) { /* * Apply "*Option Choice" settings from the attribute value... */ ppd_mark_choices(ppd, attr->value); } } else if (!_cups_strcasecmp(optptr->name, "mirror")) ppd_mark_option(ppd, "MirrorPrint", optptr->value); else ppd_mark_option(ppd, optptr->name, optptr->value); ppd_debug_marked(ppd, "After..."); return (ppdConflicts(ppd) > 0); }
ppd_attr_t * /* O - Localized attribute or NULL */ _ppdLocalizedAttr(ppd_file_t *ppd, /* I - PPD file */ const char *keyword, /* I - Main keyword */ const char *spec, /* I - Option keyword */ const char *ll_CC) /* I - Language + country locale */ { char lkeyword[PPD_MAX_NAME]; /* Localization keyword */ ppd_attr_t *attr; /* Current attribute */ DEBUG_printf(("4_ppdLocalizedAttr(ppd=%p, keyword=\"%s\", spec=\"%s\", " "ll_CC=\"%s\")", ppd, keyword, spec, ll_CC)); /* * Look for Keyword.ll_CC, then Keyword.ll... */ snprintf(lkeyword, sizeof(lkeyword), "%s.%s", ll_CC, keyword); if ((attr = ppdFindAttr(ppd, lkeyword, spec)) == NULL) { /* * <rdar://problem/22130168> * * Hong Kong locale needs special handling... Sigh... */ if (!strcmp(ll_CC, "zh_HK")) { snprintf(lkeyword, sizeof(lkeyword), "zh_TW.%s", keyword); attr = ppdFindAttr(ppd, lkeyword, spec); } if (!attr) { snprintf(lkeyword, sizeof(lkeyword), "%2.2s.%s", ll_CC, keyword); attr = ppdFindAttr(ppd, lkeyword, spec); } if (!attr) { if (!strncmp(ll_CC, "ja", 2)) { /* * Due to a bug in the CUPS DDK 1.1.0 ppdmerge program, Japanese * PPD files were incorrectly assigned "jp" as the locale name * instead of "ja". Support both the old (incorrect) and new * locale names for Japanese... */ snprintf(lkeyword, sizeof(lkeyword), "jp.%s", keyword); attr = ppdFindAttr(ppd, lkeyword, spec); } else if (!strncmp(ll_CC, "no", 2)) { /* * Norway has two languages, "Bokmal" (the primary one) * and "Nynorsk" (new Norwegian); we map "no" to "nb" here as * recommended by the locale folks... */ snprintf(lkeyword, sizeof(lkeyword), "nb.%s", keyword); attr = ppdFindAttr(ppd, lkeyword, spec); } } } #ifdef DEBUG if (attr) DEBUG_printf(("5_ppdLocalizedAttr: *%s %s/%s: \"%s\"\n", attr->name, attr->spec, attr->text, attr->value ? attr->value : "")); else DEBUG_puts("5_ppdLocalizedAttr: NOT FOUND"); #endif /* DEBUG */ return (attr); }
dt_printer_info_t *dt_get_printer_info(const char *printer_name) { cups_dest_t *dests; int num_dests = cupsGetDests(&dests); cups_dest_t *dest = cupsGetDest(printer_name, NULL, num_dests, dests); dt_printer_info_t *result = NULL; if (dest) { const char *PPDFile = cupsGetPPD (printer_name); result = (dt_printer_info_t *)malloc(sizeof(dt_printer_info_t)); g_strlcpy(result->name, dest->name, MAX_NAME); ppd_file_t *ppd = ppdOpenFile(PPDFile); if (ppd) { ppdMarkDefaults(ppd); cupsMarkOptions(ppd, dest->num_options, dest->options); // hardware margins ppd_attr_t *attr = ppdFindAttr(ppd, "HWMargins", NULL); if (attr) { sscanf(attr->value, "%lf %lf %lf %lf", &result->hw_margin_left, &result->hw_margin_bottom, &result->hw_margin_right, &result->hw_margin_top); result->hw_margin_left = dt_pdf_point_to_mm (result->hw_margin_left); result->hw_margin_bottom = dt_pdf_point_to_mm (result->hw_margin_bottom); result->hw_margin_right = dt_pdf_point_to_mm (result->hw_margin_right); result->hw_margin_top = dt_pdf_point_to_mm (result->hw_margin_top); } // default resolution attr = ppdFindAttr(ppd, "DefaultResolution", NULL); if (attr) { char *x = strstr(attr->value, "x"); if (x) sscanf (x+1, "%ddpi", &result->resolution); else sscanf (attr->value, "%ddpi", &result->resolution); } else result->resolution = 300; while(result->resolution>360) result->resolution /= 2.0; ppdClose(ppd); unlink(PPDFile); } } cupsFreeDests(num_dests, dests); return result; }
static void ppd_handle_media(ppd_file_t *ppd) /* I - PPD file */ { ppd_choice_t *manual_feed, /* ManualFeed choice, if any */ *input_slot; /* InputSlot choice, if any */ ppd_size_t *size; /* Current media size */ ppd_attr_t *rpr; /* RequiresPageRegion value */ /* * This function determines what page size code to use, if any, for the * current media size, InputSlot, and ManualFeed selections. * * We use the PageSize code if: * * 1. A custom media size is selected. * 2. ManualFeed and InputSlot are not selected (or do not exist). * 3. ManualFeed is selected but is False and InputSlot is not selected or * the selection has no code - the latter check done to support "auto" or * "printer default" InputSlot options. * * We use the PageRegion code if: * * 4. RequiresPageRegion does not exist and the PPD contains cupsFilter * keywords, indicating this is a CUPS-based driver. * 5. RequiresPageRegion exists for the selected InputSlot (or "All" for any * InputSlot or ManualFeed selection) and is True. * * If none of the 5 conditions are true, no page size code is used and we * unmark any existing PageSize or PageRegion choices. */ if ((size = ppdPageSize(ppd, NULL)) == NULL) return; manual_feed = ppdFindMarkedChoice(ppd, "ManualFeed"); input_slot = ppdFindMarkedChoice(ppd, "InputSlot"); if (input_slot != NULL) rpr = ppdFindAttr(ppd, "RequiresPageRegion", input_slot->choice); else rpr = NULL; if (!rpr) rpr = ppdFindAttr(ppd, "RequiresPageRegion", "All"); if (!_cups_strcasecmp(size->name, "Custom") || (!manual_feed && !input_slot) || (manual_feed && !_cups_strcasecmp(manual_feed->choice, "False") && (!input_slot || (input_slot->code && !input_slot->code[0]))) || (!rpr && ppd->num_filters > 0)) { /* * Use PageSize code... */ ppdMarkOption(ppd, "PageSize", size->name); } else if (rpr && rpr->value && !_cups_strcasecmp(rpr->value, "True")) { /* * Use PageRegion code... */ ppdMarkOption(ppd, "PageRegion", size->name); } else { /* * Do not use PageSize or PageRegion code... */ ppd_choice_t *page; /* PageSize/Region choice, if any */ if ((page = ppdFindMarkedChoice(ppd, "PageSize")) != NULL) { /* * Unmark PageSize... */ page->marked = 0; cupsArrayRemove(ppd->marked, page); } if ((page = ppdFindMarkedChoice(ppd, "PageRegion")) != NULL) { /* * Unmark PageRegion... */ page->marked = 0; cupsArrayRemove(ppd->marked, page); } } }
int /* O - 1 if custom sizes are supported, 0 otherwise */ ppdPageSizeLimits(ppd_file_t *ppd, /* I - PPD file record */ ppd_size_t *minimum, /* O - Minimum custom size */ ppd_size_t *maximum) /* O - Maximum custom size */ { ppd_choice_t *qualifier2, /* Second media qualifier */ *qualifier3; /* Third media qualifier */ ppd_attr_t *attr; /* Attribute */ float width, /* Min/max width */ length; /* Min/max length */ char spec[PPD_MAX_NAME]; /* Selector for min/max */ /* * Range check input... */ if (!ppd || !ppd->variable_sizes || !minimum || !maximum) { if (minimum) memset(minimum, 0, sizeof(ppd_size_t)); if (maximum) memset(maximum, 0, sizeof(ppd_size_t)); return (0); } /* * See if we have the cupsMediaQualifier2 and cupsMediaQualifier3 attributes... */ cupsArraySave(ppd->sorted_attrs); if ((attr = ppdFindAttr(ppd, "cupsMediaQualifier2", NULL)) != NULL && attr->value) qualifier2 = ppdFindMarkedChoice(ppd, attr->value); else qualifier2 = NULL; if ((attr = ppdFindAttr(ppd, "cupsMediaQualifier3", NULL)) != NULL && attr->value) qualifier3 = ppdFindMarkedChoice(ppd, attr->value); else qualifier3 = NULL; /* * Figure out the current minimum width and length... */ width = ppd->custom_min[0]; length = ppd->custom_min[1]; if (qualifier2) { /* * Try getting cupsMinSize... */ if (qualifier3) { snprintf(spec, sizeof(spec), ".%s.%s", qualifier2->choice, qualifier3->choice); attr = ppdFindAttr(ppd, "cupsMinSize", spec); } else attr = NULL; if (!attr) { snprintf(spec, sizeof(spec), ".%s.", qualifier2->choice); attr = ppdFindAttr(ppd, "cupsMinSize", spec); } if (!attr && qualifier3) { snprintf(spec, sizeof(spec), "..%s", qualifier3->choice); attr = ppdFindAttr(ppd, "cupsMinSize", spec); } if ((attr && attr->value && sscanf(attr->value, "%f%f", &width, &length) != 2) || !attr) { width = ppd->custom_min[0]; length = ppd->custom_min[1]; } } minimum->width = width; minimum->length = length; minimum->left = ppd->custom_margins[0]; minimum->bottom = ppd->custom_margins[1]; minimum->right = width - ppd->custom_margins[2]; minimum->top = length - ppd->custom_margins[3]; /* * Figure out the current maximum width and length... */ width = ppd->custom_max[0]; length = ppd->custom_max[1]; if (qualifier2) { /* * Try getting cupsMaxSize... */ if (qualifier3) { snprintf(spec, sizeof(spec), ".%s.%s", qualifier2->choice, qualifier3->choice); attr = ppdFindAttr(ppd, "cupsMaxSize", spec); } else attr = NULL; if (!attr) { snprintf(spec, sizeof(spec), ".%s.", qualifier2->choice); attr = ppdFindAttr(ppd, "cupsMaxSize", spec); } if (!attr && qualifier3) { snprintf(spec, sizeof(spec), "..%s", qualifier3->choice); attr = ppdFindAttr(ppd, "cupsMaxSize", spec); } if (!attr || (attr->value && sscanf(attr->value, "%f%f", &width, &length) != 2)) { width = ppd->custom_max[0]; length = ppd->custom_max[1]; } } maximum->width = width; maximum->length = length; maximum->left = ppd->custom_margins[0]; maximum->bottom = ppd->custom_margins[1]; maximum->right = width - ppd->custom_margins[2]; maximum->top = length - ppd->custom_margins[3]; /* * Return the min and max... */ cupsArrayRestore(ppd->sorted_attrs); return (1); }
DRIVER_ERROR HPCupsFilter::startPage (cups_page_header2_t *cups_header) { DRIVER_ERROR err = NO_ERROR; ppd_attr_t *attr; int xoverspray = 120; int yoverspray = 60; /* * Check for invalid data */ if (cups_header->HWResolution[0] == 100 && cups_header->HWResolution[1] == 100) { /* * Something went wrong, cups is defaulting to 100 dpi. * Some inkjet printers do not support 100 dpi. Return error. */ dbglog("ERROR: Unsupported resolution\n"); return JOB_CANCELED; } // XOverSpray and YOverSpray are entered as fractional value * 1000 if (((attr = ppdFindAttr(m_ppd, "HPXOverSpray", NULL)) != NULL) && (attr && attr->value != NULL)) { xoverspray = atoi(attr->value); } if (((attr = ppdFindAttr(m_ppd, "HPYOverSpray", NULL)) != NULL) && (attr && attr->value != NULL)) { yoverspray = atoi(attr->value); } if (m_iLogLevel & BASIC_LOG) { printCupsHeaderInfo(cups_header); } m_JA.quality_attributes.media_type = cups_header->cupsMediaType; m_JA.quality_attributes.print_quality = atoi(cups_header->OutputType); m_JA.quality_attributes.horizontal_resolution = cups_header->HWResolution[0]; m_JA.quality_attributes.vertical_resolution = cups_header->HWResolution[1]; m_JA.quality_attributes.actual_vertical_resolution = cups_header->HWResolution[1]; // Get the printer's actual resolution, may be different than what is reported char *p; if ((p = strstr (cups_header->OutputType, "_"))) { int x = 0, y = 0; p++; x = atoi(p); while (*p && *p != 'x') p++; if (*p && *p == 'x') { p++; y = atoi(p); } // Currently, there is one printer with one printmode that supports lower y-resolution if (y != 0) { m_JA.quality_attributes.actual_vertical_resolution = y; } } m_JA.color_mode = cups_header->cupsRowStep; m_JA.media_source = cups_header->MediaPosition; m_JA.print_borderless = (cups_header->ImagingBoundingBox[0] == 0) ? true : false; if (cups_header->Duplex) { m_JA.e_duplex_mode = (cups_header->Tumble == 0) ? DUPLEXMODE_BOOK : DUPLEXMODE_TABLET; } else { m_JA.e_duplex_mode = DUPLEXMODE_NONE; } m_JA.krgb_mode = (cups_header->cupsColorSpace == CUPS_CSPACE_RGBW) ? true : false; /* * Cups PageSize dimensions are in PostScript units, which are 72 units to an inch * and is stored as <width, height> * The ImagingBoundingBox is in PostScript units and are stored as <lower_left> <upper_right> * and <0, 0> is at the bottom left * lower_left_x = ImagingBoundingBox[0] * lower_left_y = ImagingBoundingBox[1] * upper_right_x = ImagingBoundingBox[2] * upper_right_y = ImagingBoundingBox[3] * We require <top_left> <bottom_right> values and <0, 0> is top left * So, * PrintableStartX = lower_left_x * PrintableStartY = PhysicalPageHeight - upper_right_y */ int horz_res = cups_header->HWResolution[0]; int vert_res = cups_header->HWResolution[1]; m_JA.media_attributes.pcl_id = cups_header->cupsInteger[0]; m_JA.media_attributes.printable_start_x = (cups_header->Margins[0] * horz_res) / 72; m_JA.media_attributes.printable_start_y = ((cups_header->PageSize[1] - cups_header->ImagingBoundingBox[3]) * vert_res) / 72; m_JA.media_attributes.horizontal_overspray = (xoverspray * horz_res) / 1000; m_JA.media_attributes.vertical_overspray = (yoverspray * vert_res) / 1000; /* * Left and top overspray in dots. We haven't defined ovespray for all classes in the drv. * Hence using default values in the case of older classes. */ m_JA.media_attributes.left_overspray = cups_header->cupsReal[0] ? (cups_header->cupsReal[0] * horz_res) : m_JA.media_attributes.horizontal_overspray / 2; m_JA.media_attributes.top_overspray = cups_header->cupsReal[1] ? (cups_header->cupsReal[1] * vert_res) : m_JA.media_attributes.vertical_overspray / 2; if (((attr = ppdFindAttr(m_ppd, "HPMechOffset", NULL)) != NULL) && (attr && attr->value != NULL)) { m_JA.mech_offset = atoi(attr->value); } if(cups_header->PageSize[0] > 612) // Check for B size paper. B Size paper has width > 8.5 inch (612 points) { //Check if HPMechOffsetBSize attribute is defined. If it is defined then use this offset value. if (((attr = ppdFindAttr(m_ppd, "HPMechOffsetBSize", NULL)) != NULL) && (attr && attr->value != NULL)) { m_JA.mech_offset = atoi(attr->value); } } // Get printer platform name if (((attr = ppdFindAttr(m_ppd, "hpPrinterPlatform", NULL)) != NULL) && (attr->value != NULL)) { strncpy(m_JA.printer_platform, attr->value, sizeof(m_JA.printer_platform)-1); if (m_iLogLevel & BASIC_LOG) { dbglog("HPCUPS: found Printer Platform, it is - %s\n", attr->value); } if (strcmp(m_JA.printer_platform, "ljzjscolor") == 0) { if (((attr = ppdFindAttr(m_ppd, "hpLJZjsColorVersion", NULL)) != NULL) && (attr->value != NULL)) { m_JA.printer_platform_version = atoi(attr->value); } } } //Get Raster Preprocessing status if (((attr = ppdFindAttr(m_ppd, "hpReverseRasterPages", NULL)) != NULL) && (attr->value != NULL)) { m_JA.pre_process_raster = atoi(attr->value); } if (((attr = ppdFindAttr(m_ppd, "HPSPDClass", NULL)) == NULL) || (attr && attr->value == NULL)) { m_JA.HPSPDClass = 0; } else { m_JA.HPSPDClass = atoi(attr->value); } // Get the encapsulation technology from ppd if (((attr = ppdFindAttr(m_ppd, "hpPrinterLanguage", NULL)) == NULL) || (attr && attr->value == NULL)) { dbglog("DEBUG: Bad PPD - hpPrinterLanguage not found\n"); ppdClose(m_ppd); m_ppd = NULL; return SYSTEM_ERROR; } strncpy(m_JA.printer_language, attr->value, sizeof(m_JA.printer_language)-1); if (strcmp(m_JA.printer_language, "hbpl1") == 0) { m_JA.media_attributes.physical_width = cups_header->PageSize[0]; m_JA.media_attributes.physical_height = cups_header->PageSize[1]; m_JA.media_attributes.printable_width = ((cups_header->ImagingBoundingBox[2]-cups_header->ImagingBoundingBox[0]) * horz_res) / 72; m_JA.media_attributes.printable_height = ((cups_header->ImagingBoundingBox[3]-cups_header->ImagingBoundingBox[1]) * vert_res) / 72; strncpy(m_JA.media_attributes.PageSizeName, &cups_header->cupsString[0][0], sizeof(m_JA.media_attributes.PageSizeName)); strncpy(m_JA.media_attributes.MediaTypeName, cups_header->MediaType, sizeof(m_JA.media_attributes.MediaTypeName)); strncpy(m_JA.quality_attributes.hbpl1_print_quality, cups_header->OutputType, sizeof(m_JA.quality_attributes.hbpl1_print_quality)); m_JA.color_mode = cups_header->cupsRowStep; } else { m_JA.media_attributes.physical_width = (cups_header->PageSize[0] * horz_res) / 72; m_JA.media_attributes.physical_height = (cups_header->PageSize[1] * vert_res) / 72; m_JA.media_attributes.printable_width = cups_header->cupsWidth; m_JA.media_attributes.printable_height = cups_header->cupsHeight; } if (m_iLogLevel & BASIC_LOG) { dbglog("HPCUPS: found Printer Language, it is - %s\n", attr->value); } // Fill in the other PCL header info struct utsname uts_name; uname(&uts_name); strncpy(m_JA.job_title, m_argv[3], sizeof(m_JA.job_title)-1); strncpy(m_JA.user_name, m_argv[2], sizeof(m_JA.user_name)-1); strncpy(m_JA.host_name, uts_name.nodename, sizeof(m_JA.host_name)-1); strncpy(m_JA.os_name, uts_name.sysname, sizeof(m_JA.os_name)-1); getdomainname(m_JA.domain_name, sizeof(m_JA.domain_name) - 1); int i = strlen(m_argv[0]) - 1; while (i >= 0 && m_argv[0][i] != '/') { i--; } snprintf(m_JA.driver_name, sizeof(m_JA.driver_name), "%s; %s", &m_argv[0][i+1], HP_FILE_VERSION_STR); char *ptr = getenv("DEVICE_URI"); i = 0; if (ptr) { while (*ptr) { if (*ptr == '%') { ptr += 3; m_JA.printer_name[i++] = ' '; } m_JA.printer_name[i++] = *ptr++; } } string strPrinterURI="" , strPrinterName= ""; if (getenv("DEVICE_URI")) m_DBusComm.initDBusComm(DBUS_PATH,DBUS_INTERFACE, getenv("DEVICE_URI"), m_JA.printer_name); ptr = strstr(m_argv[5], "job-uuid"); if (ptr) { strncpy(m_JA.uuid, ptr + strlen("job-uuid=urn:uuid:"), sizeof(m_JA.uuid)-1); } for (i = 0; i < 16; i++) m_JA.integer_values[i] = cups_header->cupsInteger[i]; if (cups_header->cupsString[0]) { strncpy(m_JA.quality_attributes.print_mode_name, &cups_header->cupsString[0][0], sizeof(m_JA.quality_attributes.print_mode_name)-1); } Encapsulator *encap_interface = EncapsulatorFactory::GetEncapsulator(m_JA.printer_language); if ((err = m_Job.Init(m_pSys, &m_JA, encap_interface)) != NO_ERROR) { if (err == PLUGIN_LIBRARY_MISSING) { fputs ("STATE: +hplip.plugin-error\n", stderr); m_DBusComm.sendEvent(EVENT_PRINT_FAILED_MISSING_PLUGIN, "Plugin missing", m_JA.job_id, m_JA.user_name); } dbglog ("m_Job initialization failed with error = %d\n", err); ppdClose(m_ppd); m_ppd = NULL; return err; } if (m_iLogLevel & BASIC_LOG) { dbglog("HPCUPS: returning NO_ERROR from startPage\n"); } m_pPrinterBuffer = new BYTE[cups_header->cupsWidth * 4 + 32]; return NO_ERROR; }
int DeviceAttributes_ ( ppd_file_t * ppd, oyOptions_s * options, oyConfig_s * device, const char * ppd_file_location ) { oyOption_s * o = 0; int error = !device; oyOption_s * value3 = oyOptions_Find( options, "device_context", oyNAME_PATTERN ); const char * device_name = oyConfig_FindString( device, "device_name", 0 ); if(!error) { char * manufacturer= 0, * model=0, * serial=0, * device_settings = 0; const char * system_port = 0, * host = 0; const char * keyword = 0; ppd_attr_t * attrs = 0; int attr_n, i, j; char ** color_key_words = 0, * tmp = 0; int color_key_words_n = 0; if(!device_name && !value3 && !ppd_file_location && !ppd) { message(oyMSG_WARN, (oyStruct_s*)options, _DBG_FORMAT_ "The \"device_name\" and \"device_context\" is\n" " missed to select a appropriate device.", _DBG_ARGS_ ); error = 1; return error; } if(!ppd) { message( oyMSG_DBG, (oyStruct_s*)0, _DBG_FORMAT_ "\n" "No PPD obtained for ", _DBG_ARGS_, device_name ); error = -1; return error; } manufacturer = ppd->manufacturer; model = ppd->modelname; serial = 0; /* Not known at this time. */ system_port = device_name; host = cupsServer(); attrs = ppdFindAttr(ppd, "cupsICCProfile", 0); if(attrs && attrs->text) device_settings = attrs->text; if(error <= 0) { size_t size = 0; char * data = 0; oyConfig_s * d = device; oyRankMap * rank_map = oyRankMapCopy( oyConfig_GetRankMap( device ), oyAllocateFunc_ ); if(!rank_map) rank_map = oyRankMapCopy( _api8.rank_map, oyAllocateFunc_ ); OPTIONS_ADD( oyConfig_GetOptions(d,"backend_core"), manufacturer ) OPTIONS_ADD( oyConfig_GetOptions(d,"backend_core"), model ) OPTIONS_ADD( oyConfig_GetOptions(d,"backend_core"), serial ) OPTIONS_ADD( oyConfig_GetOptions(d,"backend_core"), system_port ) OPTIONS_ADD( oyConfig_GetOptions(d,"backend_core"), host ) OPTIONS_ADD( oyConfig_GetOptions(d,"backend_core"), device_settings ) if (value3) { /* open the PPD data */ if(ppd_file_location) { FILE * fp = fopen( ppd_file_location, "r" ); size_t lsize = 0; /* Find the total size. */ fseek(fp , 0, SEEK_END); lsize = ftell(fp); rewind (fp); /* Create buffer to read contents into a profile. */ data = (char*) malloc (sizeof(char)*lsize + 1); if (data == NULL) fputs ("Unable to open PPD size.",stderr); size = fread( data, 1, lsize, fp); data[size] = 0; } if(!error && data && size) { o = oyOption_FromRegistration( CMM_BASE_REG OY_SLASH "device_context.PPD.text", 0 ); error = !o; if(!error) error = oyOption_SetFromData( o, data, size ); if(!error) oyOptions_MoveIn( *oyConfig_GetOptions(device,"data"), &o, -1 ); } } /* Collect all ColorKeyWords. */ attr_n = ppd->num_attrs; for(i = 0; i < attr_n; i++) { char key[16]; keyword = ppd->attrs[i]->name; /* we support keys beginning with ColorKeyWords, e.g. "ColorKeyWords" "ColorKeyWords" ... */ snprintf( &key[0], 16, "%s", keyword ); key[14] = 0; if (strcmp(key, "ColorKeyWords") == 0) { if( tmp && tmp[oyStrlen_(tmp) - 1] != ';' ) STRING_ADD( tmp, ";" ); STRING_ADD( tmp, ppd->attrs[i]->value ); } } if(tmp) { color_key_words = oyStringSplit( tmp, ';', &color_key_words_n, oyAllocateFunc_); oyDeAllocateFunc_( tmp ); tmp = 0; } /* add the key/value pairs to the devices backend_core options. */ for(j = 0; j < color_key_words_n; ++j) { const char * keyword = color_key_words[j], * value = NULL; ppd_choice_t * c = ppdFindMarkedChoice( ppd, keyword ); ppd_option_t * o = ppdFindOption( ppd, keyword ); char * reg_name = 0; /* take the marked choice */ if(c) value = c->choice; /* fall back to a default */ else if(o) value = o->defchoice; else /* Scan PPD attributes for matching the ColorKeyWords and */ for(i = 0; i < attr_n; i++) if(oyStrcmp_( ppd->attrs[i]->name, keyword ) == 0) value = ppd->attrs[i]->value; STRING_ADD( reg_name, CMM_BASE_REG OY_SLASH ); STRING_ADD( reg_name, keyword ); if(value) { error= oyOptions_SetFromText( oyConfig_GetOptions(d,"backend_core"), reg_name, value, OY_CREATE_NEW ); oyRankMapAppend( &rank_map, reg_name, 2, -2, 0, 0,0 ); } if(reg_name) oyDeAllocateFunc_( reg_name ); reg_name = 0; } if( color_key_words && color_key_words_n) oyStringListRelease_( &color_key_words, color_key_words_n, oyDeAllocateFunc_ ); else { ppd_option_t * o; while((o = ppdNextOption(ppd)) != 0) { const char * value = 0; char * reg_name = 0; keyword = o->keyword; STRING_ADD( reg_name, CMM_BASE_REG OY_SLASH ); STRING_ADD( reg_name, keyword ); /* take the marked choice */ for(i = 0; i < o->num_choices; ++i) if(o->choices[i].marked) { value = o->choices[i].choice; break; } if(!value) value = o->defchoice; if(value) { error = oyOptions_SetFromText( oyConfig_GetOptions(d,"backend_core"), reg_name, value, OY_CREATE_NEW ); oyRankMapAppend( &rank_map, reg_name, 2, -2, 0, 0,0 ); } if(reg_name) oyDeAllocateFunc_( reg_name ); reg_name = 0; } } oyConfig_SetRankMap( device, rank_map ); oyRankMapRelease( &rank_map, oyDeAllocateFunc_ ); }
int /* O - Exit status */ main(int argc, /* I - Number of command-line args */ char *argv[]) /* I - Command-line arguments */ { int fd; /* Raster file */ cups_raster_t *inras, /* Input raster stream */ *outras; /* Output raster stream */ cups_page_header2_t inheader, /* Input raster page header */ outheader; /* Output raster page header */ int y; /* Current line */ unsigned char *line; /* Line buffer */ int page = 0, /* Current page */ page_width, /* Actual page width */ page_height, /* Actual page height */ page_top, /* Top margin */ page_bottom, /* Bottom margin */ page_left, /* Left margin */ linesize, /* Bytes per line */ lineoffset; /* Offset into line */ unsigned char white; /* White pixel */ ppd_file_t *ppd; /* PPD file */ ppd_attr_t *back; /* cupsBackSize attribute */ _ppd_cache_t *cache; /* PPD cache */ _pwg_size_t *pwg_size; /* PWG media size */ _pwg_media_t *pwg_media; /* PWG media name */ int num_options; /* Number of options */ cups_option_t *options = NULL;/* Options */ const char *val; /* Option value */ if (argc < 6 || argc > 7) { puts("Usage: rastertopwg job user title copies options [filename]"); return (1); } else if (argc == 7) { if ((fd = open(argv[6], O_RDONLY)) < 0) { perror("ERROR: Unable to open print file"); return (1); } } else fd = 0; inras = cupsRasterOpen(fd, CUPS_RASTER_READ); outras = cupsRasterOpen(1, CUPS_RASTER_WRITE_PWG); ppd = ppdOpenFile(getenv("PPD")); back = ppdFindAttr(ppd, "cupsBackSide", NULL); num_options = cupsParseOptions(argv[5], 0, &options); ppdMarkDefaults(ppd); cupsMarkOptions(ppd, num_options, options); cache = ppd ? ppd->cache : NULL; while (cupsRasterReadHeader2(inras, &inheader)) { /* * Compute the real raster size... */ page ++; fprintf(stderr, "PAGE: %d %d\n", page, inheader.NumCopies); page_width = (int)(inheader.cupsPageSize[0] * inheader.HWResolution[0] / 72.0); page_height = (int)(inheader.cupsPageSize[1] * inheader.HWResolution[1] / 72.0); page_left = (int)(inheader.cupsImagingBBox[0] * inheader.HWResolution[0] / 72.0); page_bottom = (int)(inheader.cupsImagingBBox[1] * inheader.HWResolution[1] / 72.0); page_top = page_height - page_bottom - inheader.cupsHeight; linesize = (page_width * inheader.cupsBitsPerPixel + 7) / 8; lineoffset = page_left * inheader.cupsBitsPerPixel / 8; /* Round down */ switch (inheader.cupsColorSpace) { case CUPS_CSPACE_W : case CUPS_CSPACE_RGB : case CUPS_CSPACE_SW : case CUPS_CSPACE_SRGB : case CUPS_CSPACE_ADOBERGB : white = 255; break; case CUPS_CSPACE_K : case CUPS_CSPACE_CMYK : case CUPS_CSPACE_DEVICE1 : case CUPS_CSPACE_DEVICE2 : case CUPS_CSPACE_DEVICE3 : case CUPS_CSPACE_DEVICE4 : case CUPS_CSPACE_DEVICE5 : case CUPS_CSPACE_DEVICE6 : case CUPS_CSPACE_DEVICE7 : case CUPS_CSPACE_DEVICE8 : case CUPS_CSPACE_DEVICE9 : case CUPS_CSPACE_DEVICEA : case CUPS_CSPACE_DEVICEB : case CUPS_CSPACE_DEVICEC : case CUPS_CSPACE_DEVICED : case CUPS_CSPACE_DEVICEE : case CUPS_CSPACE_DEVICEF : white = 0; break; default : _cupsLangPrintFilter(stderr, "ERROR", _("Unsupported raster data.")); fprintf(stderr, "DEBUG: Unsupported cupsColorSpace %d on page %d.\n", inheader.cupsColorSpace, page); return (1); } if (inheader.cupsColorOrder != CUPS_ORDER_CHUNKED) { _cupsLangPrintFilter(stderr, "ERROR", _("Unsupported raster data.")); fprintf(stderr, "DEBUG: Unsupported cupsColorOrder %d on page %d.\n", inheader.cupsColorOrder, page); return (1); } if (inheader.cupsBitsPerPixel != 1 && inheader.cupsBitsPerColor != 8 && inheader.cupsBitsPerColor != 16) { _cupsLangPrintFilter(stderr, "ERROR", _("Unsupported raster data.")); fprintf(stderr, "DEBUG: Unsupported cupsBitsPerColor %d on page %d.\n", inheader.cupsBitsPerColor, page); return (1); } memcpy(&outheader, &inheader, sizeof(outheader)); outheader.cupsWidth = page_width; outheader.cupsHeight = page_height; outheader.cupsBytesPerLine = linesize; outheader.cupsInteger[14] = 0; /* VendorIdentifier */ outheader.cupsInteger[15] = 0; /* VendorLength */ if ((val = cupsGetOption("print-content-optimize", num_options, options)) != NULL) { if (!strcmp(val, "automatic")) strlcpy(outheader.OutputType, "Automatic", sizeof(outheader.OutputType)); else if (!strcmp(val, "graphics")) strlcpy(outheader.OutputType, "Graphics", sizeof(outheader.OutputType)); else if (!strcmp(val, "photo")) strlcpy(outheader.OutputType, "Photo", sizeof(outheader.OutputType)); else if (!strcmp(val, "text")) strlcpy(outheader.OutputType, "Text", sizeof(outheader.OutputType)); else if (!strcmp(val, "text-and-graphics")) strlcpy(outheader.OutputType, "TextAndGraphics", sizeof(outheader.OutputType)); else { fprintf(stderr, "DEBUG: Unsupported print-content-type \"%s\".\n", val); outheader.OutputType[0] = '\0'; } } if ((val = cupsGetOption("print-quality", num_options, options)) != NULL) { int quality = atoi(val); /* print-quality value */ if (quality >= IPP_QUALITY_DRAFT && quality <= IPP_QUALITY_HIGH) outheader.cupsInteger[8] = quality; else { fprintf(stderr, "DEBUG: Unsupported print-quality %d.\n", quality); outheader.cupsInteger[8] = 0; } } if ((val = cupsGetOption("print-rendering-intent", num_options, options)) != NULL) { if (!strcmp(val, "absolute")) strlcpy(outheader.cupsRenderingIntent, "Absolute", sizeof(outheader.cupsRenderingIntent)); else if (!strcmp(val, "automatic")) strlcpy(outheader.cupsRenderingIntent, "Automatic", sizeof(outheader.cupsRenderingIntent)); else if (!strcmp(val, "perceptual")) strlcpy(outheader.cupsRenderingIntent, "Perceptual", sizeof(outheader.cupsRenderingIntent)); else if (!strcmp(val, "relative")) strlcpy(outheader.cupsRenderingIntent, "Relative", sizeof(outheader.cupsRenderingIntent)); else if (!strcmp(val, "relative-bpc")) strlcpy(outheader.cupsRenderingIntent, "RelativeBpc", sizeof(outheader.cupsRenderingIntent)); else if (!strcmp(val, "saturation")) strlcpy(outheader.cupsRenderingIntent, "Saturation", sizeof(outheader.cupsRenderingIntent)); else { fprintf(stderr, "DEBUG: Unsupported print-rendering-intent \"%s\".\n", val); outheader.cupsRenderingIntent[0] = '\0'; } } if (inheader.cupsPageSizeName[0] && (pwg_size = _ppdCacheGetSize(cache, inheader.cupsPageSizeName)) != NULL) { strlcpy(outheader.cupsPageSizeName, pwg_size->map.pwg, sizeof(outheader.cupsPageSizeName)); } else { pwg_media = _pwgMediaForSize((int)(2540.0 * inheader.cupsPageSize[0] / 72.0), (int)(2540.0 * inheader.cupsPageSize[1] / 72.0)); if (pwg_media) strlcpy(outheader.cupsPageSizeName, pwg_media->pwg, sizeof(outheader.cupsPageSizeName)); else { fprintf(stderr, "DEBUG: Unsupported PageSize %.2fx%.2f.\n", inheader.cupsPageSize[0], inheader.cupsPageSize[1]); outheader.cupsPageSizeName[0] = '\0'; } } if (inheader.Duplex && !(page & 1) && back && _cups_strcasecmp(back->value, "Normal")) { if (_cups_strcasecmp(back->value, "Flipped")) { if (inheader.Tumble) { outheader.cupsInteger[1] = -1;/* CrossFeedTransform */ outheader.cupsInteger[2] = 1; /* FeedTransform */ outheader.cupsInteger[3] = page_width - page_left - inheader.cupsWidth; /* ImageBoxLeft */ outheader.cupsInteger[4] = page_top; /* ImageBoxTop */ outheader.cupsInteger[5] = page_width - page_left; /* ImageBoxRight */ outheader.cupsInteger[6] = page_height - page_bottom; /* ImageBoxBottom */ } else { outheader.cupsInteger[1] = 1; /* CrossFeedTransform */ outheader.cupsInteger[2] = -1;/* FeedTransform */ outheader.cupsInteger[3] = page_left; /* ImageBoxLeft */ outheader.cupsInteger[4] = page_bottom; /* ImageBoxTop */ outheader.cupsInteger[5] = page_left + inheader.cupsWidth; /* ImageBoxRight */ outheader.cupsInteger[6] = page_height - page_top; /* ImageBoxBottom */ } } else if (_cups_strcasecmp(back->value, "ManualTumble")) { if (inheader.Tumble) { outheader.cupsInteger[1] = -1;/* CrossFeedTransform */ outheader.cupsInteger[2] = -1;/* FeedTransform */ outheader.cupsInteger[3] = page_width - page_left - inheader.cupsWidth; /* ImageBoxLeft */ outheader.cupsInteger[4] = page_bottom; /* ImageBoxTop */ outheader.cupsInteger[5] = page_width - page_left; /* ImageBoxRight */ outheader.cupsInteger[6] = page_height - page_top; /* ImageBoxBottom */ } else { outheader.cupsInteger[1] = 1; /* CrossFeedTransform */ outheader.cupsInteger[2] = 1; /* FeedTransform */ outheader.cupsInteger[3] = page_left; /* ImageBoxLeft */ outheader.cupsInteger[4] = page_top; /* ImageBoxTop */ outheader.cupsInteger[5] = page_left + inheader.cupsWidth; /* ImageBoxRight */ outheader.cupsInteger[6] = page_height - page_bottom; /* ImageBoxBottom */ } } else if (_cups_strcasecmp(back->value, "Rotated")) { if (inheader.Tumble) { outheader.cupsInteger[1] = -1;/* CrossFeedTransform */ outheader.cupsInteger[2] = -1;/* FeedTransform */ outheader.cupsInteger[3] = page_width - page_left - inheader.cupsWidth; /* ImageBoxLeft */ outheader.cupsInteger[4] = page_bottom; /* ImageBoxTop */ outheader.cupsInteger[5] = page_width - page_left; /* ImageBoxRight */ outheader.cupsInteger[6] = page_height - page_top; /* ImageBoxBottom */ } else { outheader.cupsInteger[1] = 1; /* CrossFeedTransform */ outheader.cupsInteger[2] = 1; /* FeedTransform */ outheader.cupsInteger[3] = page_left; /* ImageBoxLeft */ outheader.cupsInteger[4] = page_top; /* ImageBoxTop */ outheader.cupsInteger[5] = page_left + inheader.cupsWidth; /* ImageBoxRight */ outheader.cupsInteger[6] = page_height - page_bottom; /* ImageBoxBottom */ } } else { /* * Unsupported value... */ fprintf(stderr, "DEBUG: Unsupported cupsBackSide \"%s\".\n", back->value); outheader.cupsInteger[1] = 1; /* CrossFeedTransform */ outheader.cupsInteger[2] = 1; /* FeedTransform */ outheader.cupsInteger[3] = page_left; /* ImageBoxLeft */ outheader.cupsInteger[4] = page_top; /* ImageBoxTop */ outheader.cupsInteger[5] = page_left + inheader.cupsWidth; /* ImageBoxRight */ outheader.cupsInteger[6] = page_height - page_bottom; /* ImageBoxBottom */ } } else { outheader.cupsInteger[1] = 1; /* CrossFeedTransform */ outheader.cupsInteger[2] = 1; /* FeedTransform */ outheader.cupsInteger[3] = page_left; /* ImageBoxLeft */ outheader.cupsInteger[4] = page_top; /* ImageBoxTop */ outheader.cupsInteger[5] = page_left + inheader.cupsWidth; /* ImageBoxRight */ outheader.cupsInteger[6] = page_height - page_bottom; /* ImageBoxBottom */ } if (!cupsRasterWriteHeader2(outras, &outheader)) { _cupsLangPrintFilter(stderr, "ERROR", _("Error sending raster data.")); fprintf(stderr, "DEBUG: Unable to write header for page %d.\n", page); return (1); } /* * Copy raster data... */ line = malloc(linesize); memset(line, white, linesize); for (y = page_top; y > 0; y --) if (!cupsRasterWritePixels(outras, line, outheader.cupsBytesPerLine)) { _cupsLangPrintFilter(stderr, "ERROR", _("Error sending raster data.")); fprintf(stderr, "DEBUG: Unable to write line %d for page %d.\n", page_top - y + 1, page); return (1); } for (y = inheader.cupsHeight; y > 0; y --) { cupsRasterReadPixels(inras, line + lineoffset, inheader.cupsBytesPerLine); if (!cupsRasterWritePixels(outras, line, outheader.cupsBytesPerLine)) { _cupsLangPrintFilter(stderr, "ERROR", _("Error sending raster data.")); fprintf(stderr, "DEBUG: Unable to write line %d for page %d.\n", inheader.cupsHeight - y + page_top + 1, page); return (1); } } memset(line, white, linesize); for (y = page_bottom; y > 0; y --) if (!cupsRasterWritePixels(outras, line, outheader.cupsBytesPerLine)) { _cupsLangPrintFilter(stderr, "ERROR", _("Error sending raster data.")); fprintf(stderr, "DEBUG: Unable to write line %d for page %d.\n", page_bottom - y + page_top + inheader.cupsHeight + 1, page); return (1); } free(line); } cupsRasterClose(inras); if (fd) close(fd); cupsRasterClose(outras); return (0); }
static void backend_init_supplies( int snmp_fd, /* I - SNMP socket */ http_addr_t *addr) /* I - Printer address */ { int i, /* Looping var */ type; /* Current marker type */ cups_file_t *cachefile; /* Cache file */ const char *cachedir; /* CUPS_CACHEDIR value */ char addrstr[1024], /* Address string */ cachefilename[1024], /* Cache filename */ description[CUPS_SNMP_MAX_STRING], /* Device description string */ value[CUPS_MAX_SUPPLIES * (CUPS_SNMP_MAX_STRING * 4 + 3)], /* Value string */ *ptr, /* Pointer into value string */ *name_ptr; /* Pointer into name string */ cups_snmp_t packet; /* SNMP response packet */ ppd_file_t *ppd; /* PPD file for this queue */ ppd_attr_t *ppdattr; /* cupsSNMPSupplies attribute */ static const char * const types[] = /* Supply types */ { "other", "unknown", "toner", "waste-toner", "ink", "ink-cartridge", "ink-ribbon", "waste-ink", "opc", "developer", "fuser-oil", "solid-wax", "ribbon-wax", "waste-wax", "fuser", "corona-wire", "fuser-oil-wick", "cleaner-unit", "fuser-cleaning-pad", "transfer-unit", "toner-cartridge", "fuser-oiler", "water", "waste-water", "glue-water-additive", "waste-paper", "binding-supply", "banding-supply", "stitching-wire", "shrink-wrap", "paper-wrap", "staples", "inserts", "covers" }; /* * Reset state information... */ current_addr = *addr; current_state = -1; num_supplies = -1; charset = -1; memset(supplies, 0, sizeof(supplies)); /* * See if we should be getting supply levels via SNMP... */ if ((ppd = ppdOpenFile(getenv("PPD"))) == NULL || ((ppdattr = ppdFindAttr(ppd, "cupsSNMPSupplies", NULL)) != NULL && ppdattr->value && _cups_strcasecmp(ppdattr->value, "true"))) { ppdClose(ppd); return; } if ((ppdattr = ppdFindAttr(ppd, "cupsSNMPQuirks", NULL)) != NULL) { if (!_cups_strcasecmp(ppdattr->value, "capacity")) quirks |= CUPS_SNMP_CAPACITY; } ppdClose(ppd); /* * Get the device description... */ if (!_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1, _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1, hrDeviceDescr)) return; if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) || packet.object_type != CUPS_ASN1_OCTET_STRING) { strlcpy(description, "Unknown", sizeof(description)); num_supplies = 0; } else strlcpy(description, (char *)packet.object_value.string.bytes, sizeof(description)); fprintf(stderr, "DEBUG2: hrDeviceDesc=\"%s\"\n", description); /* * See if we have already queried this device... */ httpAddrString(addr, addrstr, sizeof(addrstr)); if ((cachedir = getenv("CUPS_CACHEDIR")) == NULL) cachedir = CUPS_CACHEDIR; snprintf(cachefilename, sizeof(cachefilename), "%s/%s.snmp", cachedir, addrstr); if ((cachefile = cupsFileOpen(cachefilename, "r")) != NULL) { /* * Yes, read the cache file: * * 3 num_supplies charset * device description * supply structures... */ if (cupsFileGets(cachefile, value, sizeof(value))) { if (sscanf(value, "3 %d%d", &num_supplies, &charset) == 2 && num_supplies <= CUPS_MAX_SUPPLIES && cupsFileGets(cachefile, value, sizeof(value))) { if (!strcmp(description, value)) cupsFileRead(cachefile, (char *)supplies, (size_t)num_supplies * sizeof(backend_supplies_t)); else { num_supplies = -1; charset = -1; } } else { num_supplies = -1; charset = -1; } } cupsFileClose(cachefile); } /* * If the cache information isn't correct, scan for supplies... */ if (charset < 0) { /* * Get the configured character set... */ int oid[CUPS_SNMP_MAX_OID]; /* OID for character set */ if (!_cupsSNMPWrite(snmp_fd, ¤t_addr, CUPS_SNMP_VERSION_1, _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1, prtGeneralCurrentLocalization)) return; if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) || packet.object_type != CUPS_ASN1_INTEGER) { fprintf(stderr, "DEBUG: prtGeneralCurrentLocalization type is %x, expected %x!\n", packet.object_type, CUPS_ASN1_INTEGER); return; } fprintf(stderr, "DEBUG2: prtGeneralCurrentLocalization=%d\n", packet.object_value.integer); _cupsSNMPCopyOID(oid, prtLocalizationCharacterSet, CUPS_SNMP_MAX_OID); oid[prtLocalizationCharacterSetOffset - 2] = packet.object_value.integer; if (!_cupsSNMPWrite(snmp_fd, ¤t_addr, CUPS_SNMP_VERSION_1, _cupsSNMPDefaultCommunity(), CUPS_ASN1_GET_REQUEST, 1, oid)) return; if (!_cupsSNMPRead(snmp_fd, &packet, CUPS_SUPPLY_TIMEOUT) || packet.object_type != CUPS_ASN1_INTEGER) { fprintf(stderr, "DEBUG: prtLocalizationCharacterSet type is %x, expected %x!\n", packet.object_type, CUPS_ASN1_INTEGER); return; } fprintf(stderr, "DEBUG2: prtLocalizationCharacterSet=%d\n", packet.object_value.integer); charset = packet.object_value.integer; } if (num_supplies < 0) { /* * Walk the printer configuration information... */ _cupsSNMPWalk(snmp_fd, ¤t_addr, CUPS_SNMP_VERSION_1, _cupsSNMPDefaultCommunity(), prtMarkerSuppliesEntry, CUPS_SUPPLY_TIMEOUT, backend_walk_cb, NULL); } /* * Save the cached information... */ if (num_supplies < 0) num_supplies = 0; if ((cachefile = cupsFileOpen(cachefilename, "w")) != NULL) { cupsFilePrintf(cachefile, "3 %d %d\n", num_supplies, charset); cupsFilePrintf(cachefile, "%s\n", description); if (num_supplies > 0) cupsFileWrite(cachefile, (char *)supplies, (size_t)num_supplies * sizeof(backend_supplies_t)); cupsFileClose(cachefile); } if (num_supplies <= 0) return; /* * Get the colors... */ for (i = 0; i < num_supplies; i ++) strlcpy(supplies[i].color, "none", sizeof(supplies[i].color)); _cupsSNMPWalk(snmp_fd, ¤t_addr, CUPS_SNMP_VERSION_1, _cupsSNMPDefaultCommunity(), prtMarkerColorantValue, CUPS_SUPPLY_TIMEOUT, backend_walk_cb, NULL); /* * Output the marker-colors attribute... */ for (i = 0, ptr = value; i < num_supplies; i ++, ptr += strlen(ptr)) { if (i) *ptr++ = ','; strlcpy(ptr, supplies[i].color, sizeof(value) - (size_t)(ptr - value)); } fprintf(stderr, "ATTR: marker-colors=%s\n", value); /* * Output the marker-names attribute (the double quoting is necessary to deal * with embedded quotes and commas in the marker names...) */ for (i = 0, ptr = value; i < num_supplies; i ++) { if (i) *ptr++ = ','; *ptr++ = '\''; *ptr++ = '\"'; for (name_ptr = supplies[i].name; *name_ptr;) { if (*name_ptr == '\\' || *name_ptr == '\"' || *name_ptr == '\'') { *ptr++ = '\\'; *ptr++ = '\\'; *ptr++ = '\\'; } *ptr++ = *name_ptr++; } *ptr++ = '\"'; *ptr++ = '\''; } *ptr = '\0'; fprintf(stderr, "ATTR: marker-names=%s\n", value); /* * Output the marker-types attribute... */ for (i = 0, ptr = value; i < num_supplies; i ++, ptr += strlen(ptr)) { if (i) *ptr++ = ','; type = supplies[i].type; if (type < CUPS_TC_other || type > CUPS_TC_covers) strlcpy(ptr, "unknown", sizeof(value) - (size_t)(ptr - value)); else strlcpy(ptr, types[type - CUPS_TC_other], sizeof(value) - (size_t)(ptr - value)); } fprintf(stderr, "ATTR: marker-types=%s\n", value); }
static void colord_register_printer( cupsd_printer_t *p) /* I - printer */ { char ppdfile[1024], /* PPD filename */ iccfile[1024]; /* ICC filename */ ppd_file_t *ppd; /* PPD file */ cups_array_t *profiles; /* Profile paths array */ ppd_attr_t *attr; /* Profile attributes */ const char *device_colorspace; /* Device colorspace */ char *format[3]; /* Qualifier format tuple */ /* * Ensure we have a D-Bus connection... */ if (!colord_con) return; /* * Try opening the PPD file for this printer... */ snprintf(ppdfile, sizeof(ppdfile), "%s/ppd/%s.ppd", ServerRoot, p->name); if ((ppd = _ppdOpenFile(ppdfile, _PPD_LOCALIZATION_ICC_PROFILES)) == NULL) return; /* * Find out the qualifier format */ colord_get_qualifier_format(ppd, format); /* * See if we have any embedded profiles... */ profiles = cupsArrayNew3(NULL, NULL, NULL, 0, (cups_acopy_func_t)strdup, (cups_afree_func_t)free); for (attr = ppdFindAttr(ppd, "cupsICCProfile", NULL); attr; attr = ppdFindNextAttr(ppd, "cupsICCProfile", NULL)) if (attr->spec[0] && attr->value && attr->value[0]) { if (attr->value[0] != '/') snprintf(iccfile, sizeof(iccfile), "%s/profiles/%s", DataDir, attr->value); else strlcpy(iccfile, attr->value, sizeof(iccfile)); if (_cupsFileCheck(iccfile, _CUPS_FILE_CHECK_FILE, !RunUser, cupsdLogFCMessage, p)) continue; colord_create_profile(profiles, p->name, attr->spec, COLORD_SPACE_UNKNOWN, format, iccfile, COLORD_SCOPE_TEMP); } /* * Add the grayscale profile first. We always have a grayscale profile. */ colord_create_profile(profiles, p->name, "Gray..", COLORD_SPACE_GRAY, format, NULL, COLORD_SCOPE_TEMP); /* * Then add the RGB/CMYK/DeviceN color profile... */ device_colorspace = "unknown"; switch (ppd->colorspace) { case PPD_CS_RGB : case PPD_CS_CMY : device_colorspace = COLORD_SPACE_RGB; colord_create_profile(profiles, p->name, "RGB..", COLORD_SPACE_RGB, format, NULL, COLORD_SCOPE_TEMP); break; case PPD_CS_RGBK : case PPD_CS_CMYK : device_colorspace = COLORD_SPACE_CMYK; colord_create_profile(profiles, p->name, "CMYK..", COLORD_SPACE_CMYK, format, NULL, COLORD_SCOPE_TEMP); break; case PPD_CS_GRAY : device_colorspace = COLORD_SPACE_GRAY; break; case PPD_CS_N : colord_create_profile(profiles, p->name, "DeviceN..", COLORD_SPACE_UNKNOWN, format, NULL, COLORD_SCOPE_TEMP); break; } /* * Register the device with colord. */ cupsdLogMessage(CUPSD_LOG_INFO, "Registering ICC color profiles for \"%s\".", p->name); colord_create_device(p, ppd, profiles, device_colorspace, format, COLORD_RELATION_SOFT, COLORD_SCOPE_TEMP); /* * Free any memory we used... */ cupsArrayDelete(profiles); free(format[0]); free(format[1]); free(format[2]); ppdClose(ppd); }
static void apple_register_profiles( cupsd_printer_t *p) /* I - Printer */ { int i; /* Looping var */ char ppdfile[1024], /* PPD filename */ iccfile[1024], /* ICC filename */ selector[PPD_MAX_NAME]; /* Profile selection string */ ppd_file_t *ppd; /* PPD file */ ppd_attr_t *attr, /* Profile attributes */ *profileid_attr,/* cupsProfileID attribute */ *q1_attr, /* ColorModel (or other) qualifier */ *q2_attr, /* MediaType (or other) qualifier */ *q3_attr; /* Resolution (or other) qualifier */ char q_keyword[PPD_MAX_NAME]; /* Qualifier keyword */ const char *q1_choice, /* ColorModel (or other) choice */ *q2_choice, /* MediaType (or other) choice */ *q3_choice; /* Resolution (or other) choice */ ppd_option_t *cm_option; /* Color model option */ ppd_choice_t *cm_choice; /* Color model choice */ int num_profiles; /* Number of profiles */ OSStatus error = 0; /* Last error */ unsigned device_id, /* Printer device ID */ profile_id = 0, /* Profile ID */ default_profile_id = 0; /* Default profile ID */ CFMutableDictionaryRef device_name; /* Printer device name dictionary */ CFStringRef printer_name; /* Printer name string */ cups_array_t *languages; /* Languages array */ CFMutableDictionaryRef profiles, /* Dictionary of profiles */ profile; /* Current profile info dictionary */ CFStringRef dict_key; /* Key in factory profile dictionary */ /* * Make sure ColorSync is available... */ if (&ColorSyncRegisterDevice == NULL) return; /* * Try opening the PPD file for this printer... */ snprintf(ppdfile, sizeof(ppdfile), "%s/ppd/%s.ppd", ServerRoot, p->name); if ((ppd = _ppdOpenFile(ppdfile, _PPD_LOCALIZATION_ICC_PROFILES)) == NULL) return; /* * See if we have any profiles... */ for (num_profiles = 0, attr = ppdFindAttr(ppd, "cupsICCProfile", NULL); attr; attr = ppdFindNextAttr(ppd, "cupsICCProfile", NULL)) if (attr->spec[0] && attr->value && attr->value[0]) { if (attr->value[0] != '/') snprintf(iccfile, sizeof(iccfile), "%s/profiles/%s", DataDir, attr->value); else strlcpy(iccfile, attr->value, sizeof(iccfile)); if (access(iccfile, 0)) { cupsdLogMessage(CUPSD_LOG_ERROR, "%s: ICC Profile \"%s\" does not exist.", p->name, iccfile); cupsdSetPrinterReasons(p, "+cups-missing-filter-warning"); continue; } num_profiles ++; } /* * Create a dictionary for the factory profiles... */ profiles = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (!profiles) { cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to allocate memory for factory profiles."); ppdClose(ppd); return; } /* * If we have profiles, add them... */ if (num_profiles > 0) { /* * For CUPS PPDs, figure out the default profile selector values... */ if ((attr = ppdFindAttr(ppd, "cupsICCQualifier1", NULL)) != NULL && attr->value && attr->value[0]) { snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value); q1_attr = ppdFindAttr(ppd, q_keyword, NULL); } else if ((q1_attr = ppdFindAttr(ppd, "DefaultColorModel", NULL)) == NULL) q1_attr = ppdFindAttr(ppd, "DefaultColorSpace", NULL); if (q1_attr && q1_attr->value && q1_attr->value[0]) q1_choice = q1_attr->value; else q1_choice = ""; if ((attr = ppdFindAttr(ppd, "cupsICCQualifier2", NULL)) != NULL && attr->value && attr->value[0]) { snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value); q2_attr = ppdFindAttr(ppd, q_keyword, NULL); } else q2_attr = ppdFindAttr(ppd, "DefaultMediaType", NULL); if (q2_attr && q2_attr->value && q2_attr->value[0]) q2_choice = q2_attr->value; else q2_choice = NULL; if ((attr = ppdFindAttr(ppd, "cupsICCQualifier3", NULL)) != NULL && attr->value && attr->value[0]) { snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value); q3_attr = ppdFindAttr(ppd, q_keyword, NULL); } else q3_attr = ppdFindAttr(ppd, "DefaultResolution", NULL); if (q3_attr && q3_attr->value && q3_attr->value[0]) q3_choice = q3_attr->value; else q3_choice = NULL; /* * Loop through the profiles listed in the PPD... */ languages = _ppdGetLanguages(ppd); for (attr = ppdFindAttr(ppd, "cupsICCProfile", NULL); attr; attr = ppdFindNextAttr(ppd, "cupsICCProfile", NULL)) if (attr->spec[0] && attr->value && attr->value[0]) { /* * Add this profile... */ if (attr->value[0] != '/') snprintf(iccfile, sizeof(iccfile), "%s/profiles/%s", DataDir, attr->value); else strlcpy(iccfile, attr->value, sizeof(iccfile)); if (_cupsFileCheck(iccfile, _CUPS_FILE_CHECK_FILE, !RunUser, cupsdLogFCMessage, p)) iccfile[0] = '\0'; cupsArraySave(ppd->sorted_attrs); if ((profileid_attr = ppdFindAttr(ppd, "cupsProfileID", attr->spec)) != NULL && profileid_attr->value && isdigit(profileid_attr->value[0] & 255)) profile_id = (unsigned)strtoul(profileid_attr->value, NULL, 10); else profile_id = _ppdHashName(attr->spec); cupsArrayRestore(ppd->sorted_attrs); profile = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (!profile) { cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to allocate memory for color profile."); CFRelease(profiles); ppdClose(ppd); return; } apple_init_profile(ppd, languages, profile, profile_id, attr->spec, attr->text[0] ? attr->text : attr->spec, iccfile); dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%u"), profile_id); if (dict_key) { CFDictionarySetValue(profiles, dict_key, profile); CFRelease(dict_key); } CFRelease(profile); /* * See if this is the default profile... */ if (!default_profile_id && q1_choice && q2_choice && q3_choice) { snprintf(selector, sizeof(selector), "%s.%s.%s", q1_choice, q2_choice, q3_choice); if (!strcmp(selector, attr->spec)) default_profile_id = profile_id; } if (!default_profile_id && q1_choice && q2_choice) { snprintf(selector, sizeof(selector), "%s.%s.", q1_choice, q2_choice); if (!strcmp(selector, attr->spec)) default_profile_id = profile_id; } if (!default_profile_id && q1_choice && q3_choice) { snprintf(selector, sizeof(selector), "%s..%s", q1_choice, q3_choice); if (!strcmp(selector, attr->spec)) default_profile_id = profile_id; } if (!default_profile_id && q1_choice) { snprintf(selector, sizeof(selector), "%s..", q1_choice); if (!strcmp(selector, attr->spec)) default_profile_id = profile_id; } if (!default_profile_id && q2_choice && q3_choice) { snprintf(selector, sizeof(selector), ".%s.%s", q2_choice, q3_choice); if (!strcmp(selector, attr->spec)) default_profile_id = profile_id; } if (!default_profile_id && q2_choice) { snprintf(selector, sizeof(selector), ".%s.", q2_choice); if (!strcmp(selector, attr->spec)) default_profile_id = profile_id; } if (!default_profile_id && q3_choice) { snprintf(selector, sizeof(selector), "..%s", q3_choice); if (!strcmp(selector, attr->spec)) default_profile_id = profile_id; } } _ppdFreeLanguages(languages); } else if ((cm_option = ppdFindOption(ppd, "ColorModel")) != NULL) { /* * Extract profiles from ColorModel option... */ const char *profile_name; /* Name of generic profile */ num_profiles = cm_option->num_choices; for (i = cm_option->num_choices, cm_choice = cm_option->choices; i > 0; i --, cm_choice ++) { if (!strcmp(cm_choice->choice, "Gray") || !strcmp(cm_choice->choice, "Black")) profile_name = "Gray"; else if (!strcmp(cm_choice->choice, "RGB") || !strcmp(cm_choice->choice, "CMY")) profile_name = "RGB"; else if (!strcmp(cm_choice->choice, "CMYK") || !strcmp(cm_choice->choice, "KCMY")) profile_name = "CMYK"; else profile_name = "DeviceN"; snprintf(selector, sizeof(selector), "%s..", profile_name); profile_id = _ppdHashName(selector); profile = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (!profile) { cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to allocate memory for color profile."); CFRelease(profiles); ppdClose(ppd); return; } apple_init_profile(ppd, NULL, profile, profile_id, cm_choice->choice, cm_choice->text, NULL); dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%u"), profile_id); if (dict_key) { CFDictionarySetValue(profiles, dict_key, profile); CFRelease(dict_key); } CFRelease(profile); if (cm_choice->marked) default_profile_id = profile_id; } } else { /* * Use the default colorspace... */ attr = ppdFindAttr(ppd, "DefaultColorSpace", NULL); num_profiles = (attr && ppd->colorspace == PPD_CS_GRAY) ? 1 : 2; /* * Add the grayscale profile first. We always have a grayscale profile. */ profile = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (!profile) { cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to allocate memory for color profile."); CFRelease(profiles); ppdClose(ppd); return; } profile_id = _ppdHashName("Gray.."); apple_init_profile(ppd, NULL, profile, profile_id, "Gray", "Gray", NULL); dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%u"), profile_id); if (dict_key) { CFDictionarySetValue(profiles, dict_key, profile); CFRelease(dict_key); } CFRelease(profile); /* * Then add the RGB/CMYK/DeviceN color profile... */ profile = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (!profile) { cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to allocate memory for color profile."); CFRelease(profiles); ppdClose(ppd); return; } switch (ppd->colorspace) { default : case PPD_CS_RGB : case PPD_CS_CMY : profile_id = _ppdHashName("RGB.."); apple_init_profile(ppd, NULL, profile, profile_id, "RGB", "RGB", NULL); break; case PPD_CS_RGBK : case PPD_CS_CMYK : profile_id = _ppdHashName("CMYK.."); apple_init_profile(ppd, NULL, profile, profile_id, "CMYK", "CMYK", NULL); break; case PPD_CS_GRAY : if (attr) break; case PPD_CS_N : profile_id = _ppdHashName("DeviceN.."); apple_init_profile(ppd, NULL, profile, profile_id, "DeviceN", "DeviceN", NULL); break; } if (CFDictionaryGetCount(profile) > 0) { dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%u"), profile_id); if (dict_key) { CFDictionarySetValue(profiles, dict_key, profile); CFRelease(dict_key); } } CFRelease(profile); } if (num_profiles > 0) { /* * Make sure we have a default profile ID... */ if (!default_profile_id) default_profile_id = profile_id; /* Last profile */ dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%u"), default_profile_id); if (dict_key) { CFDictionarySetValue(profiles, kColorSyncDeviceDefaultProfileID, dict_key); CFRelease(dict_key); } /* * Get the device ID hash and pathelogical name dictionary. */ cupsdLogMessage(CUPSD_LOG_INFO, "Registering ICC color profiles for \"%s\"", p->name); device_id = _ppdHashName(p->name); device_name = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); printer_name = CFStringCreateWithCString(kCFAllocatorDefault, p->name, kCFStringEncodingUTF8); if (device_name && printer_name) { /* * Register the device with ColorSync... */ CFTypeRef deviceDictKeys[] = { /* Device keys */ kColorSyncDeviceDescriptions, kColorSyncFactoryProfiles, kColorSyncDeviceUserScope, kColorSyncDeviceHostScope }; CFTypeRef deviceDictVals[] = { /* Device values */ device_name, profiles, kCFPreferencesAnyUser, kCFPreferencesCurrentHost }; CFDictionaryRef deviceDict; /* Device dictionary */ CFUUIDRef deviceUUID; /* Device UUID */ CFDictionarySetValue(device_name, CFSTR("en_US"), printer_name); deviceDict = CFDictionaryCreate(kCFAllocatorDefault, (const void **)deviceDictKeys, (const void **)deviceDictVals, sizeof(deviceDictKeys) / sizeof(deviceDictKeys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); deviceUUID = ColorSyncCreateUUIDFromUInt32(device_id); if (!deviceDict || !deviceUUID || !ColorSyncRegisterDevice(kColorSyncPrinterDeviceClass, deviceUUID, deviceDict)) error = 1001; if (deviceUUID) CFRelease(deviceUUID); if (deviceDict) CFRelease(deviceDict); } else error = 1000; /* * Clean up... */ if (error != noErr) cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to register ICC color profiles for \"%s\": %d", p->name, (int)error); if (printer_name) CFRelease(printer_name); if (device_name) CFRelease(device_name); } /* * Free any memory we used... */ CFRelease(profiles); ppdClose(ppd); }
const char * /* O - Value or NULL if not found */ ppdLocalizeIPPReason( ppd_file_t *ppd, /* I - PPD file */ const char *reason, /* I - IPP reason keyword to look up */ const char *scheme, /* I - URI scheme or NULL for text */ char *buffer, /* I - Value buffer */ size_t bufsize) /* I - Size of value buffer */ { cups_lang_t *lang; /* Current language */ ppd_attr_t *locattr; /* Localized attribute */ char ll_CC[6], /* Language + country locale */ *bufptr, /* Pointer into buffer */ *bufend, /* Pointer to end of buffer */ *valptr; /* Pointer into value */ int ch; /* Hex-encoded character */ size_t schemelen; /* Length of scheme name */ /* * Range check input... */ if (buffer) *buffer = '\0'; if (!ppd || !reason || (scheme && !*scheme) || !buffer || bufsize < PPD_MAX_TEXT) return (NULL); /* * Get the default language... */ lang = ppd_ll_CC(ll_CC, sizeof(ll_CC)); /* * Find the localized attribute... */ if ((locattr = _ppdLocalizedAttr(ppd, "cupsIPPReason", reason, ll_CC)) == NULL) locattr = ppdFindAttr(ppd, "cupsIPPReason", reason); if (!locattr) { if (lang && (!scheme || !strcmp(scheme, "text"))) { /* * Try to localize a standard printer-state-reason keyword... */ const char *message = NULL; /* Localized message */ if (!strncmp(reason, "media-needed", 12)) message = _("Load paper."); else if (!strncmp(reason, "media-jam", 9)) message = _("Paper jam."); else if (!strncmp(reason, "offline", 7) || !strncmp(reason, "shutdown", 8)) message = _("The printer is not connected."); else if (!strncmp(reason, "toner-low", 9)) message = _("The printer is low on toner."); else if (!strncmp(reason, "toner-empty", 11)) message = _("The printer may be out of toner."); else if (!strncmp(reason, "cover-open", 10)) message = _("The printer's cover is open."); else if (!strncmp(reason, "interlock-open", 14)) message = _("The printer's interlock is open."); else if (!strncmp(reason, "door-open", 9)) message = _("The printer's door is open."); else if (!strncmp(reason, "input-tray-missing", 18)) message = _("Paper tray is missing."); else if (!strncmp(reason, "media-low", 9)) message = _("Paper tray is almost empty."); else if (!strncmp(reason, "media-empty", 11)) message = _("Paper tray is empty."); else if (!strncmp(reason, "output-tray-missing", 19)) message = _("Output bin is missing."); else if (!strncmp(reason, "output-area-almost-full", 23)) message = _("Output bin is almost full."); else if (!strncmp(reason, "output-area-full", 16)) message = _("Output bin is full."); else if (!strncmp(reason, "marker-supply-low", 17)) message = _("The printer is low on ink."); else if (!strncmp(reason, "marker-supply-empty", 19)) message = _("The printer may be out of ink."); else if (!strncmp(reason, "marker-waste-almost-full", 24)) message = _("The printer's waste bin is almost full."); else if (!strncmp(reason, "marker-waste-full", 17)) message = _("The printer's waste bin is full."); else if (!strncmp(reason, "fuser-over-temp", 15)) message = _("The fuser's temperature is high."); else if (!strncmp(reason, "fuser-under-temp", 16)) message = _("The fuser's temperature is low."); else if (!strncmp(reason, "opc-near-eol", 12)) message = _("The optical photoconductor will need to be replaced soon."); else if (!strncmp(reason, "opc-life-over", 13)) message = _("The optical photoconductor needs to be replaced."); else if (!strncmp(reason, "developer-low", 13)) message = _("The developer unit will need to be replaced soon."); else if (!strncmp(reason, "developer-empty", 15)) message = _("The developer unit needs to be replaced."); if (message) { strlcpy(buffer, _cupsLangString(lang, message), bufsize); return (buffer); } } return (NULL); } /* * Now find the value we need... */ bufend = buffer + bufsize - 1; if (!scheme || !strcmp(scheme, "text")) { /* * Copy a text value (either the translation text or text:... URIs from * the value... */ strlcpy(buffer, locattr->text, bufsize); for (valptr = locattr->value, bufptr = buffer; *valptr && bufptr < bufend;) { if (!strncmp(valptr, "text:", 5)) { /* * Decode text: URI and add to the buffer... */ valptr += 5; while (*valptr && !_cups_isspace(*valptr) && bufptr < bufend) { if (*valptr == '%' && isxdigit(valptr[1] & 255) && isxdigit(valptr[2] & 255)) { /* * Pull a hex-encoded character from the URI... */ valptr ++; if (isdigit(*valptr & 255)) ch = (*valptr - '0') << 4; else ch = (tolower(*valptr) - 'a' + 10) << 4; valptr ++; if (isdigit(*valptr & 255)) *bufptr++ = (char)(ch | (*valptr - '0')); else *bufptr++ = (char)(ch | (tolower(*valptr) - 'a' + 10)); valptr ++; } else if (*valptr == '+') { *bufptr++ = ' '; valptr ++; } else *bufptr++ = *valptr++; } } else { /* * Skip this URI... */ while (*valptr && !_cups_isspace(*valptr)) valptr++; } /* * Skip whitespace... */ while (_cups_isspace(*valptr)) valptr ++; } if (bufptr > buffer) *bufptr = '\0'; return (buffer); } else { /* * Copy a URI... */ schemelen = strlen(scheme); if (scheme[schemelen - 1] == ':') /* Force scheme to be just the name */ schemelen --; for (valptr = locattr->value, bufptr = buffer; *valptr && bufptr < bufend;) { if ((!strncmp(valptr, scheme, schemelen) && valptr[schemelen] == ':') || (*valptr == '/' && !strcmp(scheme, "file"))) { /* * Copy URI... */ while (*valptr && !_cups_isspace(*valptr) && bufptr < bufend) *bufptr++ = *valptr++; *bufptr = '\0'; return (buffer); } else { /* * Skip this URI... */ while (*valptr && !_cups_isspace(*valptr)) valptr++; } /* * Skip whitespace... */ while (_cups_isspace(*valptr)) valptr ++; } return (NULL); } }
int /* O - 0 on success, -1 on failure */ ppdEmitJCL(ppd_file_t *ppd, /* I - PPD file record */ FILE *fp, /* I - File to write to */ int job_id, /* I - Job ID */ const char *user, /* I - Username */ const char *title) /* I - Title */ { char *ptr; /* Pointer into JCL string */ char temp[65], /* Local title string */ displaymsg[33]; /* Local display string */ /* * Range check the input... */ if (!ppd || !ppd->jcl_begin || !ppd->jcl_ps) return (0); /* * See if the printer supports HP PJL... */ if (!strncmp(ppd->jcl_begin, "\033%-12345X@", 10)) { /* * This printer uses HP PJL commands for output; filter the output * so that we only have a single "@PJL JOB" command in the header... * * To avoid bugs in the PJL implementation of certain vendors' products * (Xerox in particular), we add a dummy "@PJL" command at the beginning * of the PJL commands to initialize PJL processing. */ ppd_attr_t *charset; /* PJL charset */ ppd_attr_t *display; /* PJL display command */ if ((charset = ppdFindAttr(ppd, "cupsPJLCharset", NULL)) != NULL) { if (!charset->value || _cups_strcasecmp(charset->value, "UTF-8")) charset = NULL; } if ((display = ppdFindAttr(ppd, "cupsPJLDisplay", NULL)) != NULL) { if (!display->value) display = NULL; } fputs("\033%-12345X@PJL\n", fp); for (ptr = ppd->jcl_begin + 9; *ptr;) if (!strncmp(ptr, "@PJL JOB", 8)) { /* * Skip job command... */ for (;*ptr; ptr ++) if (*ptr == '\n') break; if (*ptr) ptr ++; } else { /* * Copy line... */ for (;*ptr; ptr ++) { putc(*ptr, fp); if (*ptr == '\n') break; } if (*ptr) ptr ++; } /* * Clean up the job title... */ if ((ptr = strrchr(title, '/')) != NULL) { /* * Only show basename of file path... */ title = ptr + 1; } if (!strncmp(title, "smbprn.", 7)) { /* * Skip leading smbprn.######## from Samba jobs... */ for (title += 7; *title && isdigit(*title & 255); title ++); while (_cups_isspace(*title)) title ++; if ((ptr = strstr(title, " - ")) != NULL) { /* * Skip application name in "Some Application - Title of job"... */ title = ptr + 3; } } /* * Replace double quotes with single quotes and UTF-8 characters with * question marks so that the title does not cause a PJL syntax error. */ strlcpy(temp, title, sizeof(temp)); for (ptr = temp; *ptr; ptr ++) if (*ptr == '\"') *ptr = '\''; else if (!charset && (*ptr & 128)) *ptr = '?'; /* * CUPS STR #3125: Long PJL JOB NAME causes problems with some printers * * Generate the display message, truncating at 32 characters + nul to avoid * issues with some printer's PJL implementations... */ snprintf(displaymsg, sizeof(displaymsg), "%d %s %s", job_id, user, temp); /* * Send PJL JOB and PJL RDYMSG commands before we enter PostScript mode... */ if (display && strcmp(display->value, "job")) fprintf(fp, "@PJL JOB NAME = \"%s\"\n", temp); else if (display && !strcmp(display->value, "rdymsg")) fprintf(fp, "@PJL RDYMSG DISPLAY = \"%s\"\n", displaymsg); else fprintf(fp, "@PJL JOB NAME = \"%s\" DISPLAY = \"%s\"\n", temp, displaymsg); /* * Replace double quotes with single quotes and UTF-8 characters with * question marks so that the user does not cause a PJL syntax error. */ strlcpy(temp, user, sizeof(temp)); for (ptr = temp; *ptr; ptr ++) if (*ptr == '\"') *ptr = '\''; else if (!charset && (*ptr & 128)) *ptr = '?'; fprintf(fp, "@PJL SET USERNAME = \"%s\"\n", temp); } else fputs(ppd->jcl_begin, fp); ppdEmit(ppd, fp, PPD_ORDER_JCL); fputs(ppd->jcl_ps, fp); return (0); }
int /* O - 0 on success, -1 on error */ ppdLocalize(ppd_file_t *ppd) /* I - PPD file */ { int i, j, k; /* Looping vars */ ppd_group_t *group; /* Current group */ ppd_option_t *option; /* Current option */ ppd_choice_t *choice; /* Current choice */ ppd_coption_t *coption; /* Current custom option */ ppd_cparam_t *cparam; /* Current custom parameter */ ppd_attr_t *attr, /* Current attribute */ *locattr; /* Localized attribute */ char ckeyword[PPD_MAX_NAME], /* Custom keyword */ ll_CC[6]; /* Language + country locale */ /* * Range check input... */ DEBUG_printf(("ppdLocalize(ppd=%p)", ppd)); if (!ppd) return (-1); /* * Get the default language... */ ppd_ll_CC(ll_CC, sizeof(ll_CC)); /* * Now lookup all of the groups, options, choices, etc. */ for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++) { if ((locattr = _ppdLocalizedAttr(ppd, "Translation", group->name, ll_CC)) != NULL) strlcpy(group->text, locattr->text, sizeof(group->text)); for (j = group->num_options, option = group->options; j > 0; j --, option ++) { if ((locattr = _ppdLocalizedAttr(ppd, "Translation", option->keyword, ll_CC)) != NULL) strlcpy(option->text, locattr->text, sizeof(option->text)); for (k = option->num_choices, choice = option->choices; k > 0; k --, choice ++) { if (strcmp(choice->choice, "Custom") || !ppdFindCustomOption(ppd, option->keyword)) locattr = _ppdLocalizedAttr(ppd, option->keyword, choice->choice, ll_CC); else { snprintf(ckeyword, sizeof(ckeyword), "Custom%s", option->keyword); locattr = _ppdLocalizedAttr(ppd, ckeyword, "True", ll_CC); } if (locattr) strlcpy(choice->text, locattr->text, sizeof(choice->text)); } } } /* * Translate any custom parameters... */ for (coption = (ppd_coption_t *)cupsArrayFirst(ppd->coptions); coption; coption = (ppd_coption_t *)cupsArrayNext(ppd->coptions)) { for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params); cparam; cparam = (ppd_cparam_t *)cupsArrayNext(coption->params)) { snprintf(ckeyword, sizeof(ckeyword), "ParamCustom%s", coption->keyword); if ((locattr = _ppdLocalizedAttr(ppd, ckeyword, cparam->name, ll_CC)) != NULL) strlcpy(cparam->text, locattr->text, sizeof(cparam->text)); } } /* * Translate ICC profile names... */ if ((attr = ppdFindAttr(ppd, "APCustomColorMatchingName", NULL)) != NULL) { if ((locattr = _ppdLocalizedAttr(ppd, "APCustomColorMatchingName", attr->spec, ll_CC)) != NULL) strlcpy(attr->text, locattr->text, sizeof(attr->text)); } for (attr = ppdFindAttr(ppd, "cupsICCProfile", NULL); attr; attr = ppdFindNextAttr(ppd, "cupsICCProfile", NULL)) { cupsArraySave(ppd->sorted_attrs); if ((locattr = _ppdLocalizedAttr(ppd, "cupsICCProfile", attr->spec, ll_CC)) != NULL) strlcpy(attr->text, locattr->text, sizeof(attr->text)); cupsArrayRestore(ppd->sorted_attrs); } /* * Translate printer presets... */ for (attr = ppdFindAttr(ppd, "APPrinterPreset", NULL); attr; attr = ppdFindNextAttr(ppd, "APPrinterPreset", NULL)) { cupsArraySave(ppd->sorted_attrs); if ((locattr = _ppdLocalizedAttr(ppd, "APPrinterPreset", attr->spec, ll_CC)) != NULL) strlcpy(attr->text, locattr->text, sizeof(attr->text)); cupsArrayRestore(ppd->sorted_attrs); } return (0); }
char * /* O - String containing option code or @code NULL@ if there is no option code */ ppdEmitString(ppd_file_t *ppd, /* I - PPD file record */ ppd_section_t section, /* I - Section to write */ float min_order) /* I - Lowest OrderDependency */ { int i, j, /* Looping vars */ count; /* Number of choices */ ppd_choice_t **choices; /* Choices */ ppd_size_t *size; /* Custom page size */ ppd_coption_t *coption; /* Custom option */ ppd_cparam_t *cparam; /* Custom parameter */ size_t bufsize; /* Size of string buffer needed */ char *buffer, /* String buffer */ *bufptr, /* Pointer into buffer */ *bufend; /* End of buffer */ struct lconv *loc; /* Locale data */ DEBUG_printf(("ppdEmitString(ppd=%p, section=%d, min_order=%f)", ppd, section, min_order)); /* * Range check input... */ if (!ppd) return (NULL); /* * Use PageSize or PageRegion as required... */ ppd_handle_media(ppd); /* * Collect the options we need to emit... */ if ((count = ppdCollect2(ppd, section, min_order, &choices)) == 0) return (NULL); /* * Count the number of bytes that are required to hold all of the * option code... */ for (i = 0, bufsize = 1; i < count; i ++) { if (section == PPD_ORDER_JCL) { if (!_cups_strcasecmp(choices[i]->choice, "Custom") && (coption = ppdFindCustomOption(ppd, choices[i]->option->keyword)) != NULL) { /* * Add space to account for custom parameter substitution... */ for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params); cparam; cparam = (ppd_cparam_t *)cupsArrayNext(coption->params)) { switch (cparam->type) { case PPD_CUSTOM_CURVE : case PPD_CUSTOM_INVCURVE : case PPD_CUSTOM_POINTS : case PPD_CUSTOM_REAL : case PPD_CUSTOM_INT : bufsize += 10; break; case PPD_CUSTOM_PASSCODE : case PPD_CUSTOM_PASSWORD : case PPD_CUSTOM_STRING : if (cparam->current.custom_string) bufsize += strlen(cparam->current.custom_string); break; } } } } else if (section != PPD_ORDER_EXIT) { bufsize += 3; /* [{\n */ if ((!_cups_strcasecmp(choices[i]->option->keyword, "PageSize") || !_cups_strcasecmp(choices[i]->option->keyword, "PageRegion")) && !_cups_strcasecmp(choices[i]->choice, "Custom")) { DEBUG_puts("2ppdEmitString: Custom size set!"); bufsize += 37; /* %%BeginFeature: *CustomPageSize True\n */ bufsize += 50; /* Five 9-digit numbers + newline */ } else if (!_cups_strcasecmp(choices[i]->choice, "Custom") && (coption = ppdFindCustomOption(ppd, choices[i]->option->keyword)) != NULL) { bufsize += 23 + strlen(choices[i]->option->keyword) + 6; /* %%BeginFeature: *Customkeyword True\n */ for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params); cparam; cparam = (ppd_cparam_t *)cupsArrayNext(coption->params)) { switch (cparam->type) { case PPD_CUSTOM_CURVE : case PPD_CUSTOM_INVCURVE : case PPD_CUSTOM_POINTS : case PPD_CUSTOM_REAL : case PPD_CUSTOM_INT : bufsize += 10; break; case PPD_CUSTOM_PASSCODE : case PPD_CUSTOM_PASSWORD : case PPD_CUSTOM_STRING : bufsize += 3; if (cparam->current.custom_string) bufsize += 4 * strlen(cparam->current.custom_string); break; } } } else bufsize += 17 + strlen(choices[i]->option->keyword) + 1 + strlen(choices[i]->choice) + 1; /* %%BeginFeature: *keyword choice\n */ bufsize += 13; /* %%EndFeature\n */ bufsize += 22; /* } stopped cleartomark\n */ } if (choices[i]->code) bufsize += strlen(choices[i]->code) + 1; else bufsize += strlen(ppd_custom_code); } /* * Allocate memory... */ DEBUG_printf(("2ppdEmitString: Allocating %d bytes for string...", (int)bufsize)); if ((buffer = calloc(1, bufsize)) == NULL) { free(choices); return (NULL); } bufend = buffer + bufsize - 1; loc = localeconv(); /* * Copy the option code to the buffer... */ for (i = 0, bufptr = buffer; i < count; i ++, bufptr += strlen(bufptr)) if (section == PPD_ORDER_JCL) { if (!_cups_strcasecmp(choices[i]->choice, "Custom") && choices[i]->code && (coption = ppdFindCustomOption(ppd, choices[i]->option->keyword)) != NULL) { /* * Handle substitutions in custom JCL options... */ char *cptr; /* Pointer into code */ int pnum; /* Parameter number */ for (cptr = choices[i]->code; *cptr && bufptr < bufend;) { if (*cptr == '\\') { cptr ++; if (isdigit(*cptr & 255)) { /* * Substitute parameter... */ pnum = *cptr++ - '0'; while (isdigit(*cptr & 255)) pnum = pnum * 10 + *cptr++ - '0'; for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params); cparam; cparam = (ppd_cparam_t *)cupsArrayNext(coption->params)) if (cparam->order == pnum) break; if (cparam) { switch (cparam->type) { case PPD_CUSTOM_CURVE : case PPD_CUSTOM_INVCURVE : case PPD_CUSTOM_POINTS : case PPD_CUSTOM_REAL : bufptr = _cupsStrFormatd(bufptr, bufend, cparam->current.custom_real, loc); break; case PPD_CUSTOM_INT : snprintf(bufptr, bufend - bufptr, "%d", cparam->current.custom_int); bufptr += strlen(bufptr); break; case PPD_CUSTOM_PASSCODE : case PPD_CUSTOM_PASSWORD : case PPD_CUSTOM_STRING : if (cparam->current.custom_string) { strlcpy(bufptr, cparam->current.custom_string, bufend - bufptr); bufptr += strlen(bufptr); } break; } } } else if (*cptr) *bufptr++ = *cptr++; } else *bufptr++ = *cptr++; } } else { /* * Otherwise just copy the option code directly... */ strlcpy(bufptr, choices[i]->code, bufend - bufptr + 1); bufptr += strlen(bufptr); } } else if (section != PPD_ORDER_EXIT) { /* * Add wrapper commands to prevent printer errors for unsupported * options... */ strlcpy(bufptr, "[{\n", bufend - bufptr + 1); bufptr += 3; /* * Send DSC comments with option... */ DEBUG_printf(("2ppdEmitString: Adding code for %s=%s...", choices[i]->option->keyword, choices[i]->choice)); if ((!_cups_strcasecmp(choices[i]->option->keyword, "PageSize") || !_cups_strcasecmp(choices[i]->option->keyword, "PageRegion")) && !_cups_strcasecmp(choices[i]->choice, "Custom")) { /* * Variable size; write out standard size options, using the * parameter positions defined in the PPD file... */ ppd_attr_t *attr; /* PPD attribute */ int pos, /* Position of custom value */ orientation; /* Orientation to use */ float values[5]; /* Values for custom command */ strlcpy(bufptr, "%%BeginFeature: *CustomPageSize True\n", bufend - bufptr + 1); bufptr += 37; size = ppdPageSize(ppd, "Custom"); memset(values, 0, sizeof(values)); if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", "Width")) != NULL) { pos = atoi(attr->value) - 1; if (pos < 0 || pos > 4) pos = 0; } else pos = 0; values[pos] = size->width; if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", "Height")) != NULL) { pos = atoi(attr->value) - 1; if (pos < 0 || pos > 4) pos = 1; } else pos = 1; values[pos] = size->length; /* * According to the Adobe PPD specification, an orientation of 1 * will produce a print that comes out upside-down with the X * axis perpendicular to the direction of feed, which is exactly * what we want to be consistent with non-PS printers. * * We could also use an orientation of 3 to produce output that * comes out rightside-up (this is the default for many large format * printer PPDs), however for consistency we will stick with the * value 1. * * If we wanted to get fancy, we could use orientations of 0 or * 2 and swap the width and length, however we don't want to get * fancy, we just want it to work consistently. * * The orientation value is range limited by the Orientation * parameter definition, so certain non-PS printer drivers that * only support an Orientation of 0 will get the value 0 as * expected. */ orientation = 1; if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", "Orientation")) != NULL) { int min_orient, max_orient; /* Minimum and maximum orientations */ if (sscanf(attr->value, "%d%*s%d%d", &pos, &min_orient, &max_orient) != 3) pos = 4; else { pos --; if (pos < 0 || pos > 4) pos = 4; if (orientation > max_orient) orientation = max_orient; else if (orientation < min_orient) orientation = min_orient; } } else pos = 4; values[pos] = (float)orientation; for (pos = 0; pos < 5; pos ++) { bufptr = _cupsStrFormatd(bufptr, bufend, values[pos], loc); *bufptr++ = '\n'; } if (!choices[i]->code) { /* * This can happen with certain buggy PPD files that don't include * a CustomPageSize command sequence... We just use a generic * Level 2 command sequence... */ strlcpy(bufptr, ppd_custom_code, bufend - bufptr + 1); bufptr += strlen(bufptr); } } else if (!_cups_strcasecmp(choices[i]->choice, "Custom") && (coption = ppdFindCustomOption(ppd, choices[i]->option->keyword)) != NULL) { /* * Custom option... */ const char *s; /* Pointer into string value */ cups_array_t *params; /* Parameters in the correct output order */ params = cupsArrayNew((cups_array_func_t)ppd_compare_cparams, NULL); for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params); cparam; cparam = (ppd_cparam_t *)cupsArrayNext(coption->params)) cupsArrayAdd(params, cparam); snprintf(bufptr, bufend - bufptr + 1, "%%%%BeginFeature: *Custom%s True\n", coption->keyword); bufptr += strlen(bufptr); for (cparam = (ppd_cparam_t *)cupsArrayFirst(params); cparam; cparam = (ppd_cparam_t *)cupsArrayNext(params)) { switch (cparam->type) { case PPD_CUSTOM_CURVE : case PPD_CUSTOM_INVCURVE : case PPD_CUSTOM_POINTS : case PPD_CUSTOM_REAL : bufptr = _cupsStrFormatd(bufptr, bufend, cparam->current.custom_real, loc); *bufptr++ = '\n'; break; case PPD_CUSTOM_INT : snprintf(bufptr, bufend - bufptr + 1, "%d\n", cparam->current.custom_int); bufptr += strlen(bufptr); break; case PPD_CUSTOM_PASSCODE : case PPD_CUSTOM_PASSWORD : case PPD_CUSTOM_STRING : *bufptr++ = '('; if (cparam->current.custom_string) { for (s = cparam->current.custom_string; *s; s ++) { if (*s < ' ' || *s == '(' || *s == ')' || *s >= 127) { snprintf(bufptr, bufend - bufptr + 1, "\\%03o", *s & 255); bufptr += strlen(bufptr); } else *bufptr++ = *s; } } *bufptr++ = ')'; *bufptr++ = '\n'; break; } } cupsArrayDelete(params); } else { snprintf(bufptr, bufend - bufptr + 1, "%%%%BeginFeature: *%s %s\n", choices[i]->option->keyword, choices[i]->choice); bufptr += strlen(bufptr); } if (choices[i]->code && choices[i]->code[0]) { j = (int)strlen(choices[i]->code); memcpy(bufptr, choices[i]->code, j); bufptr += j; if (choices[i]->code[j - 1] != '\n') *bufptr++ = '\n'; } strlcpy(bufptr, "%%EndFeature\n" "} stopped cleartomark\n", bufend - bufptr + 1); bufptr += strlen(bufptr); DEBUG_printf(("2ppdEmitString: Offset in string is %d...", (int)(bufptr - buffer))); } else { strlcpy(bufptr, choices[i]->code, bufend - bufptr + 1); bufptr += strlen(bufptr); } /* * Nul-terminate, free, and return... */ *bufptr = '\0'; free(choices); return (buffer); }
int /* O - Number of options marked */ ppdCollect2(ppd_file_t *ppd, /* I - PPD file data */ ppd_section_t section, /* I - Section to collect */ float min_order, /* I - Minimum OrderDependency value */ ppd_choice_t ***choices) /* O - Pointers to choices */ { ppd_choice_t *c; /* Current choice */ ppd_section_t csection; /* Current section */ float corder; /* Current OrderDependency value */ int count; /* Number of choices collected */ ppd_choice_t **collect; /* Collected choices */ float *orders; /* Collected order values */ DEBUG_printf(("ppdCollect2(ppd=%p, section=%d, min_order=%f, choices=%p)", ppd, section, min_order, choices)); if (!ppd || !choices) { if (choices) *choices = NULL; return (0); } /* * Allocate memory for up to N selected choices... */ count = 0; if ((collect = calloc(sizeof(ppd_choice_t *), cupsArrayCount(ppd->marked))) == NULL) { *choices = NULL; return (0); } if ((orders = calloc(sizeof(float), cupsArrayCount(ppd->marked))) == NULL) { *choices = NULL; free(collect); return (0); } /* * Loop through all options and add choices as needed... */ for (c = (ppd_choice_t *)cupsArrayFirst(ppd->marked); c; c = (ppd_choice_t *)cupsArrayNext(ppd->marked)) { csection = c->option->section; corder = c->option->order; if (!strcmp(c->choice, "Custom")) { ppd_attr_t *attr; /* NonUIOrderDependency value */ float aorder; /* Order value */ char asection[17], /* Section name */ amain[PPD_MAX_NAME + 1], aoption[PPD_MAX_NAME]; /* *CustomFoo and True */ for (attr = ppdFindAttr(ppd, "NonUIOrderDependency", NULL); attr; attr = ppdFindNextAttr(ppd, "NonUIOrderDependency", NULL)) if (attr->value && sscanf(attr->value, "%f%16s%41s%40s", &aorder, asection, amain, aoption) == 4 && !strncmp(amain, "*Custom", 7) && !strcmp(amain + 7, c->option->keyword) && !strcmp(aoption, "True")) { /* * Use this NonUIOrderDependency... */ corder = aorder; if (!strcmp(asection, "DocumentSetup")) csection = PPD_ORDER_DOCUMENT; else if (!strcmp(asection, "ExitServer")) csection = PPD_ORDER_EXIT; else if (!strcmp(asection, "JCLSetup")) csection = PPD_ORDER_JCL; else if (!strcmp(asection, "PageSetup")) csection = PPD_ORDER_PAGE; else if (!strcmp(asection, "Prolog")) csection = PPD_ORDER_PROLOG; else csection = PPD_ORDER_ANY; break; } } if (csection == section && corder >= min_order) { collect[count] = c; orders[count] = corder; count ++; } } /* * If we have more than 1 marked choice, sort them... */ if (count > 1) { int i, j; /* Looping vars */ for (i = 0; i < (count - 1); i ++) for (j = i + 1; j < count; j ++) if (orders[i] > orders[j]) { c = collect[i]; corder = orders[i]; collect[i] = collect[j]; orders[i] = orders[j]; collect[j] = c; orders[j] = corder; } } free(orders); DEBUG_printf(("2ppdCollect2: %d marked choices...", count)); /* * Return the array and number of choices; if 0, free the array since * it isn't needed. */ if (count > 0) { *choices = collect; return (count); } else { *choices = NULL; free(collect); return (0); } }
cups_array_t * /* O - Languages array */ _ppdGetLanguages(ppd_file_t *ppd) /* I - PPD file */ { cups_array_t *languages; /* Languages array */ ppd_attr_t *attr; /* cupsLanguages attribute */ char *value, /* Copy of attribute value */ *start, /* Start of current language */ *ptr; /* Pointer into languages */ /* * See if we have a cupsLanguages attribute... */ if ((attr = ppdFindAttr(ppd, "cupsLanguages", NULL)) == NULL || !attr->value) return (NULL); /* * Yes, load the list... */ if ((languages = cupsArrayNew((cups_array_func_t)strcmp, NULL)) == NULL) return (NULL); if ((value = strdup(attr->value)) == NULL) { cupsArrayDelete(languages); return (NULL); } for (ptr = value; *ptr;) { /* * Skip leading whitespace... */ while (_cups_isspace(*ptr)) ptr ++; if (!*ptr) break; /* * Find the end of this language name... */ for (start = ptr; *ptr && !_cups_isspace(*ptr); ptr ++); if (*ptr) *ptr++ = '\0'; if (!strcmp(start, "en")) continue; cupsArrayAdd(languages, strdup(start)); } /* * Free the temporary string and return either an array with one or more * values or a NULL pointer... */ free(value); if (cupsArrayCount(languages) == 0) { cupsArrayDelete(languages); return (NULL); } else return (languages); }
int /* O - 1 on success, 0 on failure */ cupsResolveConflicts( ppd_file_t *ppd, /* I - PPD file */ const char *option, /* I - Newly selected option or @code NULL@ for none */ const char *choice, /* I - Newly selected choice or @code NULL@ for none */ int *num_options, /* IO - Number of additional selected options */ cups_option_t **options) /* IO - Additional selected options */ { int i, /* Looping var */ tries, /* Number of tries */ num_newopts; /* Number of new options */ cups_option_t *newopts; /* New options */ cups_array_t *active = NULL, /* Active constraints */ *pass, /* Resolvers for this pass */ *resolvers, /* Resolvers we have used */ *test; /* Test array for conflicts */ _ppd_cups_uiconsts_t *consts; /* Current constraints */ _ppd_cups_uiconst_t *constptr; /* Current constraint */ ppd_attr_t *resolver; /* Current resolver */ const char *resval; /* Pointer into resolver value */ char resoption[PPD_MAX_NAME], /* Current resolver option */ reschoice[PPD_MAX_NAME], /* Current resolver choice */ *resptr, /* Pointer into option/choice */ firstpage[255]; /* AP_FIRSTPAGE_Keyword string */ const char *value; /* Selected option value */ int changed; /* Did we change anything? */ ppd_choice_t *marked; /* Marked choice */ /* * Range check input... */ if (!ppd || !num_options || !options || (option == NULL) != (choice == NULL)) return (0); /* * Build a shadow option array... */ num_newopts = 0; newopts = NULL; for (i = 0; i < *num_options; i ++) num_newopts = cupsAddOption((*options)[i].name, (*options)[i].value, num_newopts, &newopts); if (option && _cups_strcasecmp(option, "Collate")) num_newopts = cupsAddOption(option, choice, num_newopts, &newopts); /* * Loop until we have no conflicts... */ cupsArraySave(ppd->sorted_attrs); resolvers = NULL; pass = cupsArrayNew((cups_array_func_t)_cups_strcasecmp, NULL); tries = 0; while (tries < 100 && (active = ppd_test_constraints(ppd, NULL, NULL, num_newopts, newopts, _PPD_ALL_CONSTRAINTS)) != NULL) { tries ++; if (!resolvers) resolvers = cupsArrayNew((cups_array_func_t)_cups_strcasecmp, NULL); for (consts = (_ppd_cups_uiconsts_t *)cupsArrayFirst(active), changed = 0; consts; consts = (_ppd_cups_uiconsts_t *)cupsArrayNext(active)) { if (consts->resolver[0]) { /* * Look up the resolver... */ if (cupsArrayFind(pass, consts->resolver)) continue; /* Already applied this resolver... */ if (cupsArrayFind(resolvers, consts->resolver)) { /* * Resolver loop! */ DEBUG_printf(("1cupsResolveConflicts: Resolver loop with %s!", consts->resolver)); goto error; } if ((resolver = ppdFindAttr(ppd, "cupsUIResolver", consts->resolver)) == NULL) { DEBUG_printf(("1cupsResolveConflicts: Resolver %s not found!", consts->resolver)); goto error; } if (!resolver->value) { DEBUG_printf(("1cupsResolveConflicts: Resolver %s has no value!", consts->resolver)); goto error; } /* * Add the options from the resolver... */ cupsArrayAdd(pass, consts->resolver); cupsArrayAdd(resolvers, consts->resolver); for (resval = resolver->value; *resval && !changed;) { while (_cups_isspace(*resval)) resval ++; if (*resval != '*') break; for (resval ++, resptr = resoption; *resval && !_cups_isspace(*resval); resval ++) if (resptr < (resoption + sizeof(resoption) - 1)) *resptr++ = *resval; *resptr = '\0'; while (_cups_isspace(*resval)) resval ++; for (resptr = reschoice; *resval && !_cups_isspace(*resval); resval ++) if (resptr < (reschoice + sizeof(reschoice) - 1)) *resptr++ = *resval; *resptr = '\0'; if (!resoption[0] || !reschoice[0]) break; /* * Is this the option we are changing? */ snprintf(firstpage, sizeof(firstpage), "AP_FIRSTPAGE_%s", resoption); if (option && (!_cups_strcasecmp(resoption, option) || !_cups_strcasecmp(firstpage, option) || (!_cups_strcasecmp(option, "PageSize") && !_cups_strcasecmp(resoption, "PageRegion")) || (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageSize") && !_cups_strcasecmp(resoption, "PageSize")) || (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageSize") && !_cups_strcasecmp(resoption, "PageRegion")) || (!_cups_strcasecmp(option, "PageRegion") && !_cups_strcasecmp(resoption, "PageSize")) || (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageRegion") && !_cups_strcasecmp(resoption, "PageSize")) || (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageRegion") && !_cups_strcasecmp(resoption, "PageRegion")))) continue; /* * Try this choice... */ if ((test = ppd_test_constraints(ppd, resoption, reschoice, num_newopts, newopts, _PPD_ALL_CONSTRAINTS)) == NULL) { /* * That worked... */ changed = 1; } else cupsArrayDelete(test); /* * Add the option/choice from the resolver regardless of whether it * worked; this makes sure that we can cascade several changes to * make things resolve... */ num_newopts = cupsAddOption(resoption, reschoice, num_newopts, &newopts); } } else { /* * Try resolving by choosing the default values for non-installable * options, then by iterating through the possible choices... */ int j; /* Looping var */ ppd_choice_t *cptr; /* Current choice */ ppd_size_t *size; /* Current page size */ for (i = consts->num_constraints, constptr = consts->constraints; i > 0 && !changed; i --, constptr ++) { /* * Can't resolve by changing an installable option... */ if (constptr->installable) continue; /* * Is this the option we are changing? */ if (option && (!_cups_strcasecmp(constptr->option->keyword, option) || (!_cups_strcasecmp(option, "PageSize") && !_cups_strcasecmp(constptr->option->keyword, "PageRegion")) || (!_cups_strcasecmp(option, "PageRegion") && !_cups_strcasecmp(constptr->option->keyword, "PageSize")))) continue; /* * Get the current option choice... */ if ((value = cupsGetOption(constptr->option->keyword, num_newopts, newopts)) == NULL) { if (!_cups_strcasecmp(constptr->option->keyword, "PageSize") || !_cups_strcasecmp(constptr->option->keyword, "PageRegion")) { if ((value = cupsGetOption("PageSize", num_newopts, newopts)) == NULL) value = cupsGetOption("PageRegion", num_newopts, newopts); if (!value) { if ((size = ppdPageSize(ppd, NULL)) != NULL) value = size->name; else value = ""; } } else { marked = ppdFindMarkedChoice(ppd, constptr->option->keyword); value = marked ? marked->choice : ""; } } if (!_cups_strncasecmp(value, "Custom.", 7)) value = "Custom"; /* * Try the default choice... */ test = NULL; if (_cups_strcasecmp(value, constptr->option->defchoice) && (test = ppd_test_constraints(ppd, constptr->option->keyword, constptr->option->defchoice, num_newopts, newopts, _PPD_OPTION_CONSTRAINTS)) == NULL) { /* * That worked... */ num_newopts = cupsAddOption(constptr->option->keyword, constptr->option->defchoice, num_newopts, &newopts); changed = 1; } else { /* * Try each choice instead... */ for (j = constptr->option->num_choices, cptr = constptr->option->choices; j > 0; j --, cptr ++) { cupsArrayDelete(test); test = NULL; if (_cups_strcasecmp(value, cptr->choice) && _cups_strcasecmp(constptr->option->defchoice, cptr->choice) && _cups_strcasecmp("Custom", cptr->choice) && (test = ppd_test_constraints(ppd, constptr->option->keyword, cptr->choice, num_newopts, newopts, _PPD_OPTION_CONSTRAINTS)) == NULL) { /* * This choice works... */ num_newopts = cupsAddOption(constptr->option->keyword, cptr->choice, num_newopts, &newopts); changed = 1; break; } } cupsArrayDelete(test); } } } } if (!changed) { DEBUG_puts("1cupsResolveConflicts: Unable to automatically resolve " "constraint!"); goto error; } cupsArrayClear(pass); cupsArrayDelete(active); active = NULL; } if (tries >= 100) goto error; /* * Free the caller's option array... */ cupsFreeOptions(*num_options, *options); /* * If Collate is the option we are testing, add it here. Otherwise, remove * any Collate option from the resolve list since the filters automatically * handle manual collation... */ if (option && !_cups_strcasecmp(option, "Collate")) num_newopts = cupsAddOption(option, choice, num_newopts, &newopts); else num_newopts = cupsRemoveOption("Collate", num_newopts, &newopts); /* * Return the new list of options to the caller... */ *num_options = num_newopts; *options = newopts; cupsArrayDelete(pass); cupsArrayDelete(resolvers); cupsArrayRestore(ppd->sorted_attrs); DEBUG_printf(("1cupsResolveConflicts: Returning %d options:", num_newopts)); #ifdef DEBUG for (i = 0; i < num_newopts; i ++) DEBUG_printf(("1cupsResolveConflicts: options[%d]: %s=%s", i, newopts[i].name, newopts[i].value)); #endif /* DEBUG */ return (1); /* * If we get here, we failed to resolve... */ error: cupsFreeOptions(num_newopts, newopts); cupsArrayDelete(active); cupsArrayDelete(pass); cupsArrayDelete(resolvers); cupsArrayRestore(ppd->sorted_attrs); DEBUG_puts("1cupsResolveConflicts: Unable to resolve conflicts!"); return (0); }
void * /* O - Data or NULL */ ppdxReadData(ppd_file_t *ppd, /* I - PPD file */ const char *name, /* I - Keyword prefix */ size_t *datasize) /* O - Size of data or NULL for don't care */ { char keyword[PPD_MAX_NAME], /* Keyword name */ decoded[PPDX_MAX_CHUNK + 1]; /* Decoded string */ unsigned chunk = 0; /* Current chunk number */ int len; /* Length of current chunk */ ppd_attr_t *attr; /* Keyword/value from PPD file */ Bytef *data; /* Pointer to data */ size_t alloc_size; /* Allocated size of data buffer */ z_stream decomp; /* Decompressor stream */ int error; /* Error/status from inflate() */ /* * Range check input... */ if (datasize) *datasize = 0; if (!ppd || !name) return (NULL); /* * First see if there are any instances of the named keyword in the PPD... */ snprintf(keyword, sizeof(keyword), "%s%04x", name, chunk); if ((attr = ppdFindAttr(ppd, keyword, NULL)) == NULL) return (NULL); /* * Allocate some memory and start decoding... */ data = malloc(257); alloc_size = 256; memset(&decomp, 0, sizeof(decomp)); decomp.next_out = data; decomp.avail_out = 256; inflateInit(&decomp); do { /* * Grab the data from the current attribute and decode it... */ len = sizeof(decoded); if (!httpDecode64_2(decoded, &len, attr->value) || len == 0) break; // printf("chunk %04x has length %d\n", chunk, len); /* * Decompress this chunk... */ decomp.next_in = decoded; decomp.avail_in = len; do { Bytef *temp; /* Temporary pointer */ size_t temp_size; /* Temporary allocation size */ // printf("Before inflate: avail_in=%d, avail_out=%d\n", decomp.avail_in, // decomp.avail_out); if ((error = inflate(&decomp, Z_NO_FLUSH)) < Z_OK) { fprintf(stderr, "ERROR: inflate returned %d (%s)\n", error, decomp.msg); break; } // printf("After inflate: avail_in=%d, avail_out=%d, error=%d\n", // decomp.avail_in, decomp.avail_out, error); if (decomp.avail_out == 0) { if (alloc_size < 2048) temp_size = alloc_size * 2; else if (alloc_size < PPDX_MAX_DATA) temp_size = alloc_size + 2048; else break; if ((temp = realloc(data, temp_size + 1)) == NULL) { free(data); return (NULL); } decomp.next_out = temp + (decomp.next_out - data); decomp.avail_out = temp_size - alloc_size; data = temp; alloc_size = temp_size; } } while (decomp.avail_in > 0); chunk ++; snprintf(keyword, sizeof(keyword), "%s%04x", name, chunk); } while ((attr = ppdFindAttr(ppd, keyword, NULL)) != NULL); inflateEnd(&decomp); /* * Nul-terminate the data (usually a string)... */ *(decomp.next_out) = '\0'; if (datasize) *datasize = decomp.next_out - data; return (data); }
static void ppd_load_constraints(ppd_file_t *ppd) /* I - PPD file */ { int i; /* Looping var */ ppd_const_t *oldconst; /* Current UIConstraints data */ ppd_attr_t *constattr; /* Current cupsUIConstraints attribute */ _ppd_cups_uiconsts_t *consts; /* Current cupsUIConstraints data */ _ppd_cups_uiconst_t *constptr; /* Current constraint */ ppd_group_t *installable; /* Installable options group */ const char *vptr; /* Pointer into constraint value */ char option[PPD_MAX_NAME], /* Option name/MainKeyword */ choice[PPD_MAX_NAME], /* Choice/OptionKeyword */ *ptr; /* Pointer into option or choice */ DEBUG_printf(("7ppd_load_constraints(ppd=%p)", ppd)); /* * Create an array to hold the constraint data... */ ppd->cups_uiconstraints = cupsArrayNew(NULL, NULL); /* * Find the installable options group if it exists... */ for (i = ppd->num_groups, installable = ppd->groups; i > 0; i --, installable ++) if (!_cups_strcasecmp(installable->name, "InstallableOptions")) break; if (i <= 0) installable = NULL; /* * Load old-style [Non]UIConstraints data... */ for (i = ppd->num_consts, oldconst = ppd->consts; i > 0; i --, oldconst ++) { /* * Weed out nearby duplicates, since the PPD spec requires that you * define both "*Foo foo *Bar bar" and "*Bar bar *Foo foo"... */ if (i > 1 && !_cups_strcasecmp(oldconst[0].option1, oldconst[1].option2) && !_cups_strcasecmp(oldconst[0].choice1, oldconst[1].choice2) && !_cups_strcasecmp(oldconst[0].option2, oldconst[1].option1) && !_cups_strcasecmp(oldconst[0].choice2, oldconst[1].choice1)) continue; /* * Allocate memory... */ if ((consts = calloc(1, sizeof(_ppd_cups_uiconsts_t))) == NULL) { DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for " "UIConstraints!"); return; } if ((constptr = calloc(2, sizeof(_ppd_cups_uiconst_t))) == NULL) { free(consts); DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for " "UIConstraints!"); return; } /* * Fill in the information... */ consts->num_constraints = 2; consts->constraints = constptr; if (!_cups_strncasecmp(oldconst->option1, "Custom", 6) && !_cups_strcasecmp(oldconst->choice1, "True")) { constptr[0].option = ppdFindOption(ppd, oldconst->option1 + 6); constptr[0].choice = ppdFindChoice(constptr[0].option, "Custom"); constptr[0].installable = 0; } else { constptr[0].option = ppdFindOption(ppd, oldconst->option1); constptr[0].choice = ppdFindChoice(constptr[0].option, oldconst->choice1); constptr[0].installable = ppd_is_installable(installable, oldconst->option1); } if (!constptr[0].option || (!constptr[0].choice && oldconst->choice1[0])) { DEBUG_printf(("8ppd_load_constraints: Unknown option *%s %s!", oldconst->option1, oldconst->choice1)); free(consts->constraints); free(consts); continue; } if (!_cups_strncasecmp(oldconst->option2, "Custom", 6) && !_cups_strcasecmp(oldconst->choice2, "True")) { constptr[1].option = ppdFindOption(ppd, oldconst->option2 + 6); constptr[1].choice = ppdFindChoice(constptr[1].option, "Custom"); constptr[1].installable = 0; } else { constptr[1].option = ppdFindOption(ppd, oldconst->option2); constptr[1].choice = ppdFindChoice(constptr[1].option, oldconst->choice2); constptr[1].installable = ppd_is_installable(installable, oldconst->option2); } if (!constptr[1].option || (!constptr[1].choice && oldconst->choice2[0])) { DEBUG_printf(("8ppd_load_constraints: Unknown option *%s %s!", oldconst->option2, oldconst->choice2)); free(consts->constraints); free(consts); continue; } consts->installable = constptr[0].installable || constptr[1].installable; /* * Add it to the constraints array... */ cupsArrayAdd(ppd->cups_uiconstraints, consts); } /* * Then load new-style constraints... */ for (constattr = ppdFindAttr(ppd, "cupsUIConstraints", NULL); constattr; constattr = ppdFindNextAttr(ppd, "cupsUIConstraints", NULL)) { if (!constattr->value) { DEBUG_puts("8ppd_load_constraints: Bad cupsUIConstraints value!"); continue; } for (i = 0, vptr = strchr(constattr->value, '*'); vptr; i ++, vptr = strchr(vptr + 1, '*')); if (i == 0) { DEBUG_puts("8ppd_load_constraints: Bad cupsUIConstraints value!"); continue; } if ((consts = calloc(1, sizeof(_ppd_cups_uiconsts_t))) == NULL) { DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for " "cupsUIConstraints!"); return; } if ((constptr = calloc((size_t)i, sizeof(_ppd_cups_uiconst_t))) == NULL) { free(consts); DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for " "cupsUIConstraints!"); return; } consts->num_constraints = i; consts->constraints = constptr; strlcpy(consts->resolver, constattr->spec, sizeof(consts->resolver)); for (i = 0, vptr = strchr(constattr->value, '*'); vptr; i ++, vptr = strchr(vptr, '*'), constptr ++) { /* * Extract "*Option Choice" or just "*Option"... */ for (vptr ++, ptr = option; *vptr && !_cups_isspace(*vptr); vptr ++) if (ptr < (option + sizeof(option) - 1)) *ptr++ = *vptr; *ptr = '\0'; while (_cups_isspace(*vptr)) vptr ++; if (*vptr == '*') choice[0] = '\0'; else { for (ptr = choice; *vptr && !_cups_isspace(*vptr); vptr ++) if (ptr < (choice + sizeof(choice) - 1)) *ptr++ = *vptr; *ptr = '\0'; } if (!_cups_strncasecmp(option, "Custom", 6) && !_cups_strcasecmp(choice, "True")) { _cups_strcpy(option, option + 6); strlcpy(choice, "Custom", sizeof(choice)); } constptr->option = ppdFindOption(ppd, option); constptr->choice = ppdFindChoice(constptr->option, choice); constptr->installable = ppd_is_installable(installable, option); consts->installable |= constptr->installable; if (!constptr->option || (!constptr->choice && choice[0])) { DEBUG_printf(("8ppd_load_constraints: Unknown option *%s %s!", option, choice)); break; } } if (!vptr) cupsArrayAdd(ppd->cups_uiconstraints, consts); else { free(consts->constraints); free(consts); } } }
void dt_get_printer_info(const char *printer_name, dt_printer_info_t *pinfo) { cups_dest_t *dests; int num_dests = cupsGetDests(&dests); cups_dest_t *dest = cupsGetDest(printer_name, NULL, num_dests, dests); if (dest) { const char *PPDFile = cupsGetPPD (printer_name); g_strlcpy(pinfo->name, dest->name, MAX_NAME); ppd_file_t *ppd = ppdOpenFile(PPDFile); if (ppd) { ppdMarkDefaults(ppd); cupsMarkOptions(ppd, dest->num_options, dest->options); // first check if this is turboprint drived printer, two solutions: // 1. ModelName constains TurboPrint // 2. zedoPrinterDriver exists ppd_attr_t *attr = ppdFindAttr(ppd, "ModelName", NULL); if (attr) { pinfo->is_turboprint = strstr(attr->value, "TurboPrint") != NULL; } // hardware margins attr = ppdFindAttr(ppd, "HWMargins", NULL); if (attr) { sscanf(attr->value, "%lf %lf %lf %lf", &pinfo->hw_margin_left, &pinfo->hw_margin_bottom, &pinfo->hw_margin_right, &pinfo->hw_margin_top); pinfo->hw_margin_left = dt_pdf_point_to_mm (pinfo->hw_margin_left); pinfo->hw_margin_bottom = dt_pdf_point_to_mm (pinfo->hw_margin_bottom); pinfo->hw_margin_right = dt_pdf_point_to_mm (pinfo->hw_margin_right); pinfo->hw_margin_top = dt_pdf_point_to_mm (pinfo->hw_margin_top); } // default resolution attr = ppdFindAttr(ppd, "DefaultResolution", NULL); if (attr) { char *x = strstr(attr->value, "x"); if (x) sscanf (x+1, "%ddpi", &pinfo->resolution); else sscanf (attr->value, "%ddpi", &pinfo->resolution); } else pinfo->resolution = 300; while(pinfo->resolution>360) pinfo->resolution /= 2.0; ppdClose(ppd); g_unlink(PPDFile); } } cupsFreeDests(num_dests, dests); }
int /* O - Exit status */ main(int argc, /* I - Number of command-line arguments */ char *argv[]) /* I - Command-line arguments */ { int i; /* Looping var */ ppd_file_t *ppd; /* PPD file loaded from disk */ int status; /* Status of tests (0 = success, 1 = fail) */ int conflicts; /* Number of conflicts */ char *s; /* String */ char buffer[8192]; /* String buffer */ const char *text, /* Localized text */ *val; /* Option value */ int num_options; /* Number of options */ cups_option_t *options; /* Options */ ppd_size_t minsize, /* Minimum size */ maxsize, /* Maximum size */ *size; /* Current size */ ppd_attr_t *attr; /* Current attribute */ _ppd_cache_t *pc; /* PPD cache */ status = 0; if (argc == 1) { /* * Setup directories for locale stuff... */ if (access("locale", 0)) { mkdir("locale", 0777); mkdir("locale/fr", 0777); symlink("../../../locale/cups_fr.po", "locale/fr/cups_fr.po"); mkdir("locale/zh_TW", 0777); symlink("../../../locale/cups_zh_TW.po", "locale/zh_TW/cups_zh_TW.po"); } putenv("LOCALEDIR=locale"); putenv("SOFTWARE=CUPS"); /* * Do tests with test.ppd... */ fputs("ppdOpenFile(test.ppd): ", stdout); if ((ppd = _ppdOpenFile("test.ppd", _PPD_LOCALIZATION_ALL)) != NULL) puts("PASS"); else { ppd_status_t err; /* Last error in file */ int line; /* Line number in file */ status ++; err = ppdLastError(&line); printf("FAIL (%s on line %d)\n", ppdErrorString(err), line); } fputs("ppdFindAttr(wildcard): ", stdout); if ((attr = ppdFindAttr(ppd, "cupsTest", NULL)) == NULL) { status ++; puts("FAIL (not found)"); } else if (strcmp(attr->name, "cupsTest") || strcmp(attr->spec, "Foo")) { status ++; printf("FAIL (got \"%s %s\")\n", attr->name, attr->spec); } else puts("PASS"); fputs("ppdFindNextAttr(wildcard): ", stdout); if ((attr = ppdFindNextAttr(ppd, "cupsTest", NULL)) == NULL) { status ++; puts("FAIL (not found)"); } else if (strcmp(attr->name, "cupsTest") || strcmp(attr->spec, "Bar")) { status ++; printf("FAIL (got \"%s %s\")\n", attr->name, attr->spec); } else puts("PASS"); fputs("ppdFindAttr(Foo): ", stdout); if ((attr = ppdFindAttr(ppd, "cupsTest", "Foo")) == NULL) { status ++; puts("FAIL (not found)"); } else if (strcmp(attr->name, "cupsTest") || strcmp(attr->spec, "Foo")) { status ++; printf("FAIL (got \"%s %s\")\n", attr->name, attr->spec); } else puts("PASS"); fputs("ppdFindNextAttr(Foo): ", stdout); if ((attr = ppdFindNextAttr(ppd, "cupsTest", "Foo")) != NULL) { status ++; printf("FAIL (got \"%s %s\")\n", attr->name, attr->spec); } else puts("PASS"); fputs("ppdMarkDefaults: ", stdout); ppdMarkDefaults(ppd); if ((conflicts = ppdConflicts(ppd)) == 0) puts("PASS"); else { status ++; printf("FAIL (%d conflicts)\n", conflicts); } fputs("ppdEmitString (defaults): ", stdout); if ((s = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL && !strcmp(s, default_code)) puts("PASS"); else { status ++; printf("FAIL (%d bytes instead of %d)\n", s ? (int)strlen(s) : 0, (int)strlen(default_code)); if (s) puts(s); } if (s) free(s); fputs("ppdEmitString (custom size and string): ", stdout); ppdMarkOption(ppd, "PageSize", "Custom.400x500"); ppdMarkOption(ppd, "StringOption", "{String1=\"value 1\" String2=value(2)}"); if ((s = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL && !strcmp(s, custom_code)) puts("PASS"); else { status ++; printf("FAIL (%d bytes instead of %d)\n", s ? (int)strlen(s) : 0, (int)strlen(custom_code)); if (s) puts(s); } if (s) free(s); /* * Test constraints... */ fputs("cupsGetConflicts(InputSlot=Envelope): ", stdout); ppdMarkOption(ppd, "PageSize", "Letter"); num_options = cupsGetConflicts(ppd, "InputSlot", "Envelope", &options); if (num_options != 2 || (val = cupsGetOption("PageRegion", num_options, options)) == NULL || _cups_strcasecmp(val, "Letter") || (val = cupsGetOption("PageSize", num_options, options)) == NULL || _cups_strcasecmp(val, "Letter")) { printf("FAIL (%d options:", num_options); for (i = 0; i < num_options; i ++) printf(" %s=%s", options[i].name, options[i].value); puts(")"); status ++; } else puts("PASS"); fputs("ppdConflicts(): ", stdout); ppdMarkOption(ppd, "InputSlot", "Envelope"); if ((conflicts = ppdConflicts(ppd)) == 2) puts("PASS (2)"); else { printf("FAIL (%d)\n", conflicts); status ++; } fputs("cupsResolveConflicts(InputSlot=Envelope): ", stdout); num_options = 0; options = NULL; if (!cupsResolveConflicts(ppd, "InputSlot", "Envelope", &num_options, &options)) { puts("FAIL (Unable to resolve)"); status ++; } else if (num_options != 2 || !cupsGetOption("PageSize", num_options, options)) { printf("FAIL (%d options:", num_options); for (i = 0; i < num_options; i ++) printf(" %s=%s", options[i].name, options[i].value); puts(")"); status ++; } else puts("PASS (Resolved by changing PageSize)"); cupsFreeOptions(num_options, options); fputs("cupsResolveConflicts(No option/choice): ", stdout); num_options = 0; options = NULL; if (cupsResolveConflicts(ppd, NULL, NULL, &num_options, &options) && num_options == 1 && !_cups_strcasecmp(options[0].name, "InputSlot") && !_cups_strcasecmp(options[0].value, "Tray")) puts("PASS (Resolved by changing InputSlot)"); else if (num_options > 0) { printf("FAIL (%d options:", num_options); for (i = 0; i < num_options; i ++) printf(" %s=%s", options[i].name, options[i].value); puts(")"); status ++; } else { puts("FAIL (Unable to resolve)"); status ++; } cupsFreeOptions(num_options, options); fputs("ppdInstallableConflict(): ", stdout); if (ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble") && !ppdInstallableConflict(ppd, "Duplex", "None")) puts("PASS"); else if (!ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble")) { puts("FAIL (Duplex=DuplexNoTumble did not conflict)"); status ++; } else { puts("FAIL (Duplex=None conflicted)"); status ++; } /* * ppdPageSizeLimits */ fputs("ppdPageSizeLimits: ", stdout); if (ppdPageSizeLimits(ppd, &minsize, &maxsize)) { if (minsize.width != 36 || minsize.length != 36 || maxsize.width != 1080 || maxsize.length != 86400) { printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, " "expected min=36x36, max=1080x86400)\n", minsize.width, minsize.length, maxsize.width, maxsize.length); status ++; } else puts("PASS"); } else { puts("FAIL (returned 0)"); status ++; } /* * cupsMarkOptions with PWG and IPP size names. */ fputs("cupsMarkOptions(media=iso-a4): ", stdout); num_options = cupsAddOption("media", "iso-a4", 0, &options); cupsMarkOptions(ppd, num_options, options); cupsFreeOptions(num_options, options); size = ppdPageSize(ppd, NULL); if (!size || strcmp(size->name, "A4")) { printf("FAIL (%s)\n", size ? size->name : "unknown"); status ++; } else puts("PASS"); fputs("cupsMarkOptions(media=na_letter_8.5x11in): ", stdout); num_options = cupsAddOption("media", "na_letter_8.5x11in", 0, &options); cupsMarkOptions(ppd, num_options, options); cupsFreeOptions(num_options, options); size = ppdPageSize(ppd, NULL); if (!size || strcmp(size->name, "Letter")) { printf("FAIL (%s)\n", size ? size->name : "unknown"); status ++; } else puts("PASS"); fputs("cupsMarkOptions(media=oe_letter-fullbleed_8.5x11in): ", stdout); num_options = cupsAddOption("media", "oe_letter-fullbleed_8.5x11in", 0, &options); cupsMarkOptions(ppd, num_options, options); cupsFreeOptions(num_options, options); size = ppdPageSize(ppd, NULL); if (!size || strcmp(size->name, "Letter.Fullbleed")) { printf("FAIL (%s)\n", size ? size->name : "unknown"); status ++; } else puts("PASS"); fputs("cupsMarkOptions(media=A4): ", stdout); num_options = cupsAddOption("media", "A4", 0, &options); cupsMarkOptions(ppd, num_options, options); cupsFreeOptions(num_options, options); size = ppdPageSize(ppd, NULL); if (!size || strcmp(size->name, "A4")) { printf("FAIL (%s)\n", size ? size->name : "unknown"); status ++; } else puts("PASS"); /* * Custom sizes... */ fputs("cupsMarkOptions(media=Custom.8x10in): ", stdout); num_options = cupsAddOption("media", "Custom.8x10in", 0, &options); cupsMarkOptions(ppd, num_options, options); cupsFreeOptions(num_options, options); size = ppdPageSize(ppd, NULL); if (!size || strcmp(size->name, "Custom") || size->width != 576 || size->length != 720) { printf("FAIL (%s - %gx%g)\n", size ? size->name : "unknown", size ? size->width : 0.0, size ? size->length : 0.0); status ++; } else puts("PASS"); /* * Test localization... */ fputs("ppdLocalizeIPPReason(text): ", stdout); if (ppdLocalizeIPPReason(ppd, "foo", NULL, buffer, sizeof(buffer)) && !strcmp(buffer, "Foo Reason")) puts("PASS"); else { status ++; printf("FAIL (\"%s\" instead of \"Foo Reason\")\n", buffer); } fputs("ppdLocalizeIPPReason(http): ", stdout); if (ppdLocalizeIPPReason(ppd, "foo", "http", buffer, sizeof(buffer)) && !strcmp(buffer, "http://foo/bar.html")) puts("PASS"); else { status ++; printf("FAIL (\"%s\" instead of \"http://foo/bar.html\")\n", buffer); } fputs("ppdLocalizeIPPReason(help): ", stdout); if (ppdLocalizeIPPReason(ppd, "foo", "help", buffer, sizeof(buffer)) && !strcmp(buffer, "help:anchor='foo'%20bookID=Vendor%20Help")) puts("PASS"); else { status ++; printf("FAIL (\"%s\" instead of \"help:anchor='foo'%%20bookID=Vendor%%20Help\")\n", buffer); } fputs("ppdLocalizeIPPReason(file): ", stdout); if (ppdLocalizeIPPReason(ppd, "foo", "file", buffer, sizeof(buffer)) && !strcmp(buffer, "/help/foo/bar.html")) puts("PASS"); else { status ++; printf("FAIL (\"%s\" instead of \"/help/foo/bar.html\")\n", buffer); } putenv("LANG=fr"); putenv("LC_ALL=fr"); putenv("LC_CTYPE=fr"); putenv("LC_MESSAGES=fr"); fputs("ppdLocalizeIPPReason(fr text): ", stdout); if (ppdLocalizeIPPReason(ppd, "foo", NULL, buffer, sizeof(buffer)) && !strcmp(buffer, "La Long Foo Reason")) puts("PASS"); else { status ++; printf("FAIL (\"%s\" instead of \"La Long Foo Reason\")\n", buffer); } putenv("LANG=zh_TW"); putenv("LC_ALL=zh_TW"); putenv("LC_CTYPE=zh_TW"); putenv("LC_MESSAGES=zh_TW"); fputs("ppdLocalizeIPPReason(zh_TW text): ", stdout); if (ppdLocalizeIPPReason(ppd, "foo", NULL, buffer, sizeof(buffer)) && !strcmp(buffer, "Number 1 Foo Reason")) puts("PASS"); else { status ++; printf("FAIL (\"%s\" instead of \"Number 1 Foo Reason\")\n", buffer); } /* * cupsMarkerName localization... */ putenv("LANG=en"); putenv("LC_ALL=en"); putenv("LC_CTYPE=en"); putenv("LC_MESSAGES=en"); fputs("ppdLocalizeMarkerName(bogus): ", stdout); if ((text = ppdLocalizeMarkerName(ppd, "bogus")) != NULL) { status ++; printf("FAIL (\"%s\" instead of NULL)\n", text); } else puts("PASS"); fputs("ppdLocalizeMarkerName(cyan): ", stdout); if ((text = ppdLocalizeMarkerName(ppd, "cyan")) != NULL && !strcmp(text, "Cyan Toner")) puts("PASS"); else { status ++; printf("FAIL (\"%s\" instead of \"Cyan Toner\")\n", text ? text : "(null)"); } putenv("LANG=fr"); putenv("LC_ALL=fr"); putenv("LC_CTYPE=fr"); putenv("LC_MESSAGES=fr"); fputs("ppdLocalizeMarkerName(fr cyan): ", stdout); if ((text = ppdLocalizeMarkerName(ppd, "cyan")) != NULL && !strcmp(text, "La Toner Cyan")) puts("PASS"); else { status ++; printf("FAIL (\"%s\" instead of \"La Toner Cyan\")\n", text ? text : "(null)"); } putenv("LANG=zh_TW"); putenv("LC_ALL=zh_TW"); putenv("LC_CTYPE=zh_TW"); putenv("LC_MESSAGES=zh_TW"); fputs("ppdLocalizeMarkerName(zh_TW cyan): ", stdout); if ((text = ppdLocalizeMarkerName(ppd, "cyan")) != NULL && !strcmp(text, "Number 1 Cyan Toner")) puts("PASS"); else { status ++; printf("FAIL (\"%s\" instead of \"Number 1 Cyan Toner\")\n", text ? text : "(null)"); } ppdClose(ppd); /* * Test new constraints... */ fputs("ppdOpenFile(test2.ppd): ", stdout); if ((ppd = ppdOpenFile("test2.ppd")) != NULL) puts("PASS"); else { ppd_status_t err; /* Last error in file */ int line; /* Line number in file */ status ++; err = ppdLastError(&line); printf("FAIL (%s on line %d)\n", ppdErrorString(err), line); } fputs("ppdMarkDefaults: ", stdout); ppdMarkDefaults(ppd); if ((conflicts = ppdConflicts(ppd)) == 0) puts("PASS"); else { status ++; printf("FAIL (%d conflicts)\n", conflicts); } fputs("ppdEmitString (defaults): ", stdout); if ((s = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL && !strcmp(s, default2_code)) puts("PASS"); else { status ++; printf("FAIL (%d bytes instead of %d)\n", s ? (int)strlen(s) : 0, (int)strlen(default2_code)); if (s) puts(s); } if (s) free(s); fputs("ppdConflicts(): ", stdout); ppdMarkOption(ppd, "PageSize", "Env10"); ppdMarkOption(ppd, "InputSlot", "Envelope"); ppdMarkOption(ppd, "Quality", "Photo"); if ((conflicts = ppdConflicts(ppd)) == 1) puts("PASS (1)"); else { printf("FAIL (%d)\n", conflicts); status ++; } fputs("cupsResolveConflicts(Quality=Photo): ", stdout); num_options = 0; options = NULL; if (cupsResolveConflicts(ppd, "Quality", "Photo", &num_options, &options)) { printf("FAIL (%d options:", num_options); for (i = 0; i < num_options; i ++) printf(" %s=%s", options[i].name, options[i].value); puts(")"); status ++; } else puts("PASS (Unable to resolve)"); cupsFreeOptions(num_options, options); fputs("cupsResolveConflicts(No option/choice): ", stdout); num_options = 0; options = NULL; if (cupsResolveConflicts(ppd, NULL, NULL, &num_options, &options) && num_options == 1 && !_cups_strcasecmp(options->name, "Quality") && !_cups_strcasecmp(options->value, "Normal")) puts("PASS"); else if (num_options > 0) { printf("FAIL (%d options:", num_options); for (i = 0; i < num_options; i ++) printf(" %s=%s", options[i].name, options[i].value); puts(")"); status ++; } else { puts("FAIL (Unable to resolve!)"); status ++; } cupsFreeOptions(num_options, options); fputs("cupsResolveConflicts(loop test): ", stdout); ppdMarkOption(ppd, "PageSize", "A4"); ppdMarkOption(ppd, "InputSlot", "Tray"); ppdMarkOption(ppd, "Quality", "Photo"); num_options = 0; options = NULL; if (!cupsResolveConflicts(ppd, NULL, NULL, &num_options, &options)) puts("PASS"); else if (num_options > 0) { printf("FAIL (%d options:", num_options); for (i = 0; i < num_options; i ++) printf(" %s=%s", options[i].name, options[i].value); puts(")"); } else puts("FAIL (No conflicts!)"); fputs("ppdInstallableConflict(): ", stdout); if (ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble") && !ppdInstallableConflict(ppd, "Duplex", "None")) puts("PASS"); else if (!ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble")) { puts("FAIL (Duplex=DuplexNoTumble did not conflict)"); status ++; } else { puts("FAIL (Duplex=None conflicted)"); status ++; } /* * ppdPageSizeLimits */ ppdMarkDefaults(ppd); fputs("ppdPageSizeLimits(default): ", stdout); if (ppdPageSizeLimits(ppd, &minsize, &maxsize)) { if (minsize.width != 36 || minsize.length != 36 || maxsize.width != 1080 || maxsize.length != 86400) { printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, " "expected min=36x36, max=1080x86400)\n", minsize.width, minsize.length, maxsize.width, maxsize.length); status ++; } else puts("PASS"); } else { puts("FAIL (returned 0)"); status ++; } ppdMarkOption(ppd, "InputSlot", "Manual"); fputs("ppdPageSizeLimits(InputSlot=Manual): ", stdout); if (ppdPageSizeLimits(ppd, &minsize, &maxsize)) { if (minsize.width != 100 || minsize.length != 100 || maxsize.width != 1000 || maxsize.length != 1000) { printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, " "expected min=100x100, max=1000x1000)\n", minsize.width, minsize.length, maxsize.width, maxsize.length); status ++; } else puts("PASS"); } else { puts("FAIL (returned 0)"); status ++; } ppdMarkOption(ppd, "Quality", "Photo"); fputs("ppdPageSizeLimits(Quality=Photo): ", stdout); if (ppdPageSizeLimits(ppd, &minsize, &maxsize)) { if (minsize.width != 200 || minsize.length != 200 || maxsize.width != 1000 || maxsize.length != 1000) { printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, " "expected min=200x200, max=1000x1000)\n", minsize.width, minsize.length, maxsize.width, maxsize.length); status ++; } else puts("PASS"); } else { puts("FAIL (returned 0)"); status ++; } ppdMarkOption(ppd, "InputSlot", "Tray"); fputs("ppdPageSizeLimits(Quality=Photo): ", stdout); if (ppdPageSizeLimits(ppd, &minsize, &maxsize)) { if (minsize.width != 300 || minsize.length != 300 || maxsize.width != 1080 || maxsize.length != 86400) { printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, " "expected min=300x300, max=1080x86400)\n", minsize.width, minsize.length, maxsize.width, maxsize.length); status ++; } else puts("PASS"); } else { puts("FAIL (returned 0)"); status ++; } } else { const char *filename; /* PPD filename */ struct stat fileinfo; /* File information */ if (!strncmp(argv[1], "-d", 2)) { const char *printer; /* Printer name */ if (argv[1][2]) printer = argv[1] + 2; else if (argv[2]) printer = argv[2]; else { puts("Usage: ./testppd -d printer"); return (1); } filename = cupsGetPPD(printer); if (!filename) { printf("%s: %s\n", printer, cupsLastErrorString()); return (1); } } else filename = argv[1]; if (lstat(filename, &fileinfo)) { printf("%s: %s\n", filename, strerror(errno)); return (1); } if (S_ISLNK(fileinfo.st_mode)) { char realfile[1024]; /* Real file path */ ssize_t realsize; /* Size of real file path */ if ((realsize = readlink(filename, realfile, sizeof(realfile) - 1)) < 0) strlcpy(realfile, "Unknown", sizeof(realfile)); else realfile[realsize] = '\0'; if (stat(realfile, &fileinfo)) printf("%s: symlink to \"%s\", %s\n", filename, realfile, strerror(errno)); else printf("%s: symlink to \"%s\", %ld bytes\n", filename, realfile, (long)fileinfo.st_size); } else printf("%s: regular file, %ld bytes\n", filename, (long)fileinfo.st_size); if ((ppd = ppdOpenFile(filename)) == NULL) { ppd_status_t err; /* Last error in file */ int line; /* Line number in file */ status ++; err = ppdLastError(&line); printf("%s: %s on line %d\n", argv[1], ppdErrorString(err), line); } else { int j, k; /* Looping vars */ ppd_group_t *group; /* Option group */ ppd_option_t *option; /* Option */ ppd_coption_t *coption; /* Custom option */ ppd_cparam_t *cparam; /* Custom parameter */ ppd_const_t *c; /* UIConstraints */ char lang[255], /* LANG environment variable */ lc_all[255], /* LC_ALL environment variable */ lc_ctype[255], /* LC_CTYPE environment variable */ lc_messages[255];/* LC_MESSAGES environment variable */ if (argc > 2) { snprintf(lang, sizeof(lang), "LANG=%s", argv[2]); putenv(lang); snprintf(lc_all, sizeof(lc_all), "LC_ALL=%s", argv[2]); putenv(lc_all); snprintf(lc_ctype, sizeof(lc_ctype), "LC_CTYPE=%s", argv[2]); putenv(lc_ctype); snprintf(lc_messages, sizeof(lc_messages), "LC_MESSAGES=%s", argv[2]); putenv(lc_messages); } ppdLocalize(ppd); ppdMarkDefaults(ppd); if (argc > 3) { text = ppdLocalizeIPPReason(ppd, argv[3], NULL, buffer, sizeof(buffer)); printf("ppdLocalizeIPPReason(%s)=%s\n", argv[3], text ? text : "(null)"); return (text == NULL); } for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++) { printf("%s (%s):\n", group->name, group->text); for (j = group->num_options, option = group->options; j > 0; j --, option ++) { printf(" %s (%s):\n", option->keyword, option->text); for (k = 0; k < option->num_choices; k ++) printf(" - %s%s (%s)\n", option->choices[k].marked ? "*" : "", option->choices[k].choice, option->choices[k].text); if ((coption = ppdFindCustomOption(ppd, option->keyword)) != NULL) { for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params); cparam; cparam = (ppd_cparam_t *)cupsArrayNext(coption->params)) { switch (cparam->type) { case PPD_CUSTOM_CURVE : printf(" %s(%s): PPD_CUSTOM_CURVE (%g to %g)\n", cparam->name, cparam->text, cparam->minimum.custom_curve, cparam->maximum.custom_curve); break; case PPD_CUSTOM_INT : printf(" %s(%s): PPD_CUSTOM_INT (%d to %d)\n", cparam->name, cparam->text, cparam->minimum.custom_int, cparam->maximum.custom_int); break; case PPD_CUSTOM_INVCURVE : printf(" %s(%s): PPD_CUSTOM_INVCURVE (%g to %g)\n", cparam->name, cparam->text, cparam->minimum.custom_invcurve, cparam->maximum.custom_invcurve); break; case PPD_CUSTOM_PASSCODE : printf(" %s(%s): PPD_CUSTOM_PASSCODE (%d to %d)\n", cparam->name, cparam->text, cparam->minimum.custom_passcode, cparam->maximum.custom_passcode); break; case PPD_CUSTOM_PASSWORD : printf(" %s(%s): PPD_CUSTOM_PASSWORD (%d to %d)\n", cparam->name, cparam->text, cparam->minimum.custom_password, cparam->maximum.custom_password); break; case PPD_CUSTOM_POINTS : printf(" %s(%s): PPD_CUSTOM_POINTS (%g to %g)\n", cparam->name, cparam->text, cparam->minimum.custom_points, cparam->maximum.custom_points); break; case PPD_CUSTOM_REAL : printf(" %s(%s): PPD_CUSTOM_REAL (%g to %g)\n", cparam->name, cparam->text, cparam->minimum.custom_real, cparam->maximum.custom_real); break; case PPD_CUSTOM_STRING : printf(" %s(%s): PPD_CUSTOM_STRING (%d to %d)\n", cparam->name, cparam->text, cparam->minimum.custom_string, cparam->maximum.custom_string); break; } } } } } puts("\nSizes:"); for (i = ppd->num_sizes, size = ppd->sizes; i > 0; i --, size ++) printf(" %s = %gx%g, [%g %g %g %g]\n", size->name, size->width, size->length, size->left, size->bottom, size->right, size->top); puts("\nConstraints:"); for (i = ppd->num_consts, c = ppd->consts; i > 0; i --, c ++) printf(" *UIConstraints: *%s %s *%s %s\n", c->option1, c->choice1, c->option2, c->choice2); if (ppd->num_consts == 0) puts(" NO CONSTRAINTS"); puts("\nFilters:"); for (i = 0; i < ppd->num_filters; i ++) printf(" %s\n", ppd->filters[i]); if (ppd->num_filters == 0) puts(" NO FILTERS"); puts("\nAttributes:"); for (attr = (ppd_attr_t *)cupsArrayFirst(ppd->sorted_attrs); attr; attr = (ppd_attr_t *)cupsArrayNext(ppd->sorted_attrs)) printf(" *%s %s/%s: \"%s\"\n", attr->name, attr->spec, attr->text, attr->value ? attr->value : ""); puts("\nPPD Cache:"); if ((pc = _ppdCacheCreateWithPPD(ppd)) == NULL) printf(" Unable to create: %s\n", cupsLastErrorString()); else { _ppdCacheWriteFile(pc, "t.cache", NULL); puts(" Wrote t.cache."); } } if (!strncmp(argv[1], "-d", 2)) unlink(filename); } #ifdef __APPLE__ if (getenv("MallocStackLogging") && getenv("MallocStackLoggingNoCompact")) { char command[1024]; /* malloc_history command */ snprintf(command, sizeof(command), "malloc_history %d -all_by_size", getpid()); fflush(stdout); system(command); } #endif /* __APPLE__ */ ppdClose(ppd); return (status); }