| /* PostScript Printer Description (PPD) file parser | |
| * | |
| * See http://www.adobe.com/supportservice/devrelations/PDFS/TN/5003.PPD_Spec_v4.3.pdf | |
| * | |
| * Copyright 1998 Huw D M Davies | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| */ | |
| #include <string.h> | |
| #include <stdio.h> | |
| #include <ctype.h> | |
| #include "winnt.h" /* HEAP_ZERO_MEMORY */ | |
| #include "wine/debug.h" | |
| #include "psdrv.h" | |
| #include "winspool.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(psdrv); | |
| typedef struct { | |
| char *key; | |
| char *option; | |
| char *opttrans; | |
| char *value; | |
| char *valtrans; | |
| } PPDTuple; | |
| /* map of page names in ppd file to Windows paper constants */ | |
| static struct { | |
| char *PSName; | |
| WORD WinPage; | |
| } PageTrans[] = { | |
| {"10x11", DMPAPER_10X11}, | |
| {"10x14", DMPAPER_10X14}, | |
| {"11x17", DMPAPER_11X17}, /* not in Adobe PPD file spec */ | |
| {"12x11", DMPAPER_12X11}, | |
| {"15x11", DMPAPER_15X11}, | |
| {"9x11", DMPAPER_9X11}, | |
| {"A2", DMPAPER_A2}, | |
| {"A3", DMPAPER_A3}, | |
| {"A3.Transverse", DMPAPER_A3_TRANSVERSE}, | |
| {"A3Extra", DMPAPER_A3_EXTRA}, | |
| {"A3Extra.Transverse", DMPAPER_A3_EXTRA_TRANSVERSE}, | |
| {"A3Rotated", DMPAPER_A3_ROTATED}, | |
| {"A4", DMPAPER_A4}, | |
| {"A4.Transverse", DMPAPER_A4_TRANSVERSE}, | |
| {"A4Extra", DMPAPER_A4_EXTRA}, | |
| {"A4Plus", DMPAPER_A4_PLUS}, | |
| {"A4Rotated", DMPAPER_A4_ROTATED}, | |
| {"A4Small", DMPAPER_A4SMALL}, | |
| {"A5", DMPAPER_A5}, | |
| {"A5.Transverse", DMPAPER_A5_TRANSVERSE}, | |
| {"A5Extra", DMPAPER_A5_EXTRA}, | |
| {"A5Rotated", DMPAPER_A5_ROTATED}, | |
| {"A6", DMPAPER_A6}, | |
| {"A6Rotated", DMPAPER_A6_ROTATED}, | |
| {"ARCHC", DMPAPER_CSHEET}, | |
| {"ARCHD", DMPAPER_DSHEET}, | |
| {"ARCHE", DMPAPER_ESHEET}, | |
| {"B4", DMPAPER_B4}, | |
| {"B4Rotated", DMPAPER_B4_JIS_ROTATED}, | |
| {"B5", DMPAPER_B5}, | |
| {"B5.Transverse", DMPAPER_B5_TRANSVERSE}, | |
| {"B5Rotated", DMPAPER_B5_JIS_ROTATED}, | |
| {"B6", DMPAPER_B6_JIS}, | |
| {"B6Rotated", DMPAPER_B6_JIS_ROTATED}, | |
| {"C4", DMPAPER_ENV_C4}, /* use EnvC4 */ | |
| {"C5", DMPAPER_ENV_C5}, /* use EnvC5 */ | |
| {"C6", DMPAPER_ENV_C6}, /* use EnvC6 */ | |
| {"Comm10", DMPAPER_ENV_10}, /* use Env10 */ | |
| {"DL", DMPAPER_ENV_DL}, /* use EnvDL */ | |
| {"DoublePostcard", DMPAPER_DBL_JAPANESE_POSTCARD}, | |
| {"DoublePostcardRotated", DMPAPER_DBL_JAPANESE_POSTCARD_ROTATED}, | |
| {"Env10", DMPAPER_ENV_10}, | |
| {"Env11", DMPAPER_ENV_11}, | |
| {"Env12", DMPAPER_ENV_12}, | |
| {"Env14", DMPAPER_ENV_14}, | |
| {"Env9", DMPAPER_ENV_9}, | |
| {"EnvC3", DMPAPER_ENV_C3}, | |
| {"EnvC4", DMPAPER_ENV_C4}, | |
| {"EnvC5", DMPAPER_ENV_C5}, | |
| {"EnvC6", DMPAPER_ENV_C6}, | |
| {"EnvC65", DMPAPER_ENV_C65}, | |
| {"EnvChou3", DMPAPER_JENV_CHOU3}, | |
| {"EnvChou3Rotated", DMPAPER_JENV_CHOU3_ROTATED}, | |
| {"EnvChou4", DMPAPER_JENV_CHOU4}, | |
| {"EnvChou4Rotated", DMPAPER_JENV_CHOU4_ROTATED}, | |
| {"EnvDL", DMPAPER_ENV_DL}, | |
| {"EnvISOB4", DMPAPER_ENV_B4}, | |
| {"EnvISOB5", DMPAPER_ENV_B5}, | |
| {"EnvISOB6", DMPAPER_ENV_B6}, | |
| {"EnvInvite", DMPAPER_ENV_INVITE}, | |
| {"EnvItalian", DMPAPER_ENV_ITALY}, | |
| {"EnvKaku2", DMPAPER_JENV_KAKU2}, | |
| {"EnvKaku2Rotated", DMPAPER_JENV_KAKU2_ROTATED}, | |
| {"EnvKaku3", DMPAPER_JENV_KAKU3}, | |
| {"EnvKaku3Rotated", DMPAPER_JENV_KAKU3_ROTATED}, | |
| {"EnvMonarch", DMPAPER_ENV_MONARCH}, | |
| {"EnvPRC1", DMPAPER_PENV_1}, | |
| {"EnvPRC10", DMPAPER_PENV_10}, | |
| {"EnvPRC10Rotated", DMPAPER_PENV_10_ROTATED}, | |
| {"EnvPRC1Rotated", DMPAPER_PENV_1_ROTATED}, | |
| {"EnvPRC2", DMPAPER_PENV_2}, | |
| {"EnvPRC2Rotated", DMPAPER_PENV_2_ROTATED}, | |
| {"EnvPRC3", DMPAPER_PENV_3}, | |
| {"EnvPRC3Rotated", DMPAPER_PENV_3_ROTATED}, | |
| {"EnvPRC4", DMPAPER_PENV_4}, | |
| {"EnvPRC4Rotated", DMPAPER_PENV_4_ROTATED}, | |
| {"EnvPRC5", DMPAPER_PENV_5}, | |
| {"EnvPRC5Rotated", DMPAPER_PENV_5_ROTATED}, | |
| {"EnvPRC6", DMPAPER_PENV_6}, | |
| {"EnvPRC6Rotated", DMPAPER_PENV_6_ROTATED}, | |
| {"EnvPRC7", DMPAPER_PENV_7}, | |
| {"EnvPRC7Rotated", DMPAPER_PENV_7_ROTATED}, | |
| {"EnvPRC8", DMPAPER_PENV_8}, | |
| {"EnvPRC8Rotated", DMPAPER_PENV_8_ROTATED}, | |
| {"EnvPRC9", DMPAPER_PENV_9}, | |
| {"EnvPRC9Rotated", DMPAPER_PENV_9_ROTATED}, | |
| {"EnvPersonal", DMPAPER_ENV_PERSONAL}, | |
| {"EnvYou4", DMPAPER_JENV_YOU4}, | |
| {"EnvYou4Rotated", DMPAPER_JENV_YOU4_ROTATED}, | |
| {"Executive", DMPAPER_EXECUTIVE}, | |
| {"FanFoldGerman", DMPAPER_FANFOLD_STD_GERMAN}, | |
| {"FanFoldGermanLegal", DMPAPER_FANFOLD_LGL_GERMAN}, | |
| {"FanFoldUS", DMPAPER_FANFOLD_US}, | |
| {"Folio", DMPAPER_FOLIO}, | |
| {"ISOB4", DMPAPER_ISO_B4}, | |
| {"ISOB5Extra", DMPAPER_B5_EXTRA}, | |
| {"Ledger", DMPAPER_LEDGER}, | |
| {"Legal", DMPAPER_LEGAL}, | |
| {"LegalExtra", DMPAPER_LEGAL_EXTRA}, | |
| {"Letter", DMPAPER_LETTER}, | |
| {"Letter.Transverse", DMPAPER_LETTER_TRANSVERSE}, | |
| {"LetterExtra", DMPAPER_LETTER_EXTRA}, | |
| {"LetterExtra.Transverse", DMPAPER_LETTER_EXTRA_TRANSVERSE}, | |
| {"LetterPlus", DMPAPER_LETTER_PLUS}, | |
| {"LetterRotated", DMPAPER_LETTER_ROTATED}, | |
| {"LetterSmall", DMPAPER_LETTERSMALL}, | |
| {"Monarch", DMPAPER_ENV_MONARCH}, /* use EnvMonarch */ | |
| {"Note", DMPAPER_NOTE}, | |
| {"PRC16K", DMPAPER_P16K}, | |
| {"PRC16KRotated", DMPAPER_P16K_ROTATED}, | |
| {"PRC32K", DMPAPER_P32K}, | |
| {"PRC32KBig", DMPAPER_P32KBIG}, | |
| {"PRC32KBigRotated", DMPAPER_P32KBIG_ROTATED}, | |
| {"PRC32KRotated", DMPAPER_P32K_ROTATED}, | |
| {"Postcard", DMPAPER_JAPANESE_POSTCARD}, | |
| {"PostcardRotated", DMPAPER_JAPANESE_POSTCARD_ROTATED}, | |
| {"Quarto", DMPAPER_QUARTO}, | |
| {"Statement", DMPAPER_STATEMENT}, | |
| {"SuperA", DMPAPER_A_PLUS}, | |
| {"SuperB", DMPAPER_B_PLUS}, | |
| {"Tabloid", DMPAPER_TABLOID}, | |
| {"TabloidExtra", DMPAPER_TABLOID_EXTRA}, | |
| {NULL, 0} | |
| }; | |
| static WORD UserPageType = DMPAPER_USER; | |
| static WORD UserBinType = DMBIN_USER; | |
| /*********************************************************************** | |
| * | |
| * PSDRV_PPDDecodeHex | |
| * | |
| * Copies str into a newly allocated string from the process heap subsituting | |
| * hex strings enclosed in '<' and '>' for their byte codes. | |
| * | |
| */ | |
| static char *PSDRV_PPDDecodeHex(char *str) | |
| { | |
| char *buf, *in, *out; | |
| BOOL inhex = FALSE; | |
| buf = HeapAlloc(PSDRV_Heap, 0, strlen(str) + 1); | |
| if(!buf) | |
| return NULL; | |
| for(in = str, out = buf; *in; in++) { | |
| if(!inhex) { | |
| if(*in != '<') | |
| *out++ = *in; | |
| else | |
| inhex = TRUE; | |
| } else { | |
| if(*in == '>') { | |
| inhex = FALSE; | |
| continue; | |
| } | |
| else if(isspace(*in)) | |
| continue; | |
| else { | |
| int i; | |
| if(!isxdigit(*in) || !isxdigit(*(in + 1))) { | |
| ERR("Invalid hex char in hex string\n"); | |
| HeapFree(PSDRV_Heap, 0, buf); | |
| return NULL; | |
| } | |
| *out = 0; | |
| for(i = 0; i < 2; i++) { | |
| if(isdigit(*(in + i))) | |
| *out |= (*(in + i) - '0') << ((1-i) * 4); | |
| else | |
| *out |= (toupper(*(in + i)) - 'A' + 10) << ((1-i) * 4); | |
| } | |
| out++; | |
| in++; | |
| } | |
| } | |
| } | |
| *out = '\0'; | |
| return buf; | |
| } | |
| /*********************************************************************** | |
| * | |
| * PSDRV_PPDGetTransValue | |
| * | |
| */ | |
| static BOOL PSDRV_PPDGetTransValue(char *start, PPDTuple *tuple) | |
| { | |
| char *buf, *end; | |
| end = strpbrk(start, "\r\n"); | |
| if(end == start) return FALSE; | |
| if(!end) end = start + strlen(start); | |
| buf = HeapAlloc( PSDRV_Heap, 0, end - start + 1 ); | |
| memcpy(buf, start, end - start); | |
| *(buf + (end - start)) = '\0'; | |
| tuple->valtrans = PSDRV_PPDDecodeHex(buf); | |
| HeapFree( PSDRV_Heap, 0, buf ); | |
| return TRUE; | |
| } | |
| /*********************************************************************** | |
| * | |
| * PSDRV_PPDGetInvocationValue | |
| * | |
| * Passed string that should be surrounded by `"'s, return string alloced | |
| * from process heap. | |
| */ | |
| static BOOL PSDRV_PPDGetInvocationValue(FILE *fp, char *pos, PPDTuple *tuple) | |
| { | |
| char *start, *end, *buf; | |
| char line[257]; | |
| int len; | |
| start = pos + 1; | |
| buf = HeapAlloc( PSDRV_Heap, 0, strlen(start) + 1 ); | |
| len = 0; | |
| do { | |
| end = strchr(start, '"'); | |
| if(end) { | |
| buf = HeapReAlloc( PSDRV_Heap, 0, buf, | |
| len + (end - start) + 1 ); | |
| memcpy(buf + len, start, end - start); | |
| *(buf + len + (end - start)) = '\0'; | |
| tuple->value = buf; | |
| start = strchr(end, '/'); | |
| if(start) | |
| return PSDRV_PPDGetTransValue(start + 1, tuple); | |
| return TRUE; | |
| } else { | |
| int sl = strlen(start); | |
| buf = HeapReAlloc( PSDRV_Heap, 0, buf, len + sl + 1 ); | |
| strcpy(buf + len, start); | |
| len += sl; | |
| } | |
| } while( fgets((start = line), sizeof(line), fp) ); | |
| tuple->value = NULL; | |
| HeapFree( PSDRV_Heap, 0, buf ); | |
| return FALSE; | |
| } | |
| /*********************************************************************** | |
| * | |
| * PSDRV_PPDGetQuotedValue | |
| * | |
| * Passed string that should be surrounded by `"'s. Expand <xx> as hex | |
| * return string alloced from process heap. | |
| */ | |
| static BOOL PSDRV_PPDGetQuotedValue(FILE *fp, char *pos, PPDTuple *tuple) | |
| { | |
| char *buf; | |
| if(!PSDRV_PPDGetInvocationValue(fp, pos, tuple)) | |
| return FALSE; | |
| buf = PSDRV_PPDDecodeHex(tuple->value); | |
| HeapFree(PSDRV_Heap, 0, tuple->value); | |
| tuple->value = buf; | |
| return TRUE; | |
| } | |
| /*********************************************************************** | |
| * | |
| * PSDRV_PPDGetStringValue | |
| * | |
| * Just strip leading white space. | |
| */ | |
| static BOOL PSDRV_PPDGetStringValue(char *str, PPDTuple *tuple) | |
| { | |
| char *start = str, *end; | |
| while(*start != '\0' && isspace(*start)) | |
| start++; | |
| end = strpbrk(start, "/\r\n"); | |
| if(!end) end = start + strlen(start); | |
| tuple->value = HeapAlloc( PSDRV_Heap, 0, (end - start) + 1 ); | |
| memcpy(tuple->value, start, end - start); | |
| *(tuple->value + (end - start)) = '\0'; | |
| if(*end == '/') | |
| PSDRV_PPDGetTransValue(end + 1, tuple); | |
| return TRUE; | |
| } | |
| /*********************************************************************** | |
| * | |
| * PSDRV_PPDSymbolValue | |
| * | |
| * Not implemented yet. | |
| */ | |
| static BOOL PSDRV_PPDGetSymbolValue(char *pos, PPDTuple *tuple) | |
| { | |
| FIXME("Stub\n"); | |
| return FALSE; | |
| } | |
| /********************************************************************* | |
| * | |
| * PSDRV_PPDGetNextTuple | |
| * | |
| * Gets the next Keyword Option Value tuple from the file. Allocs space off | |
| * the process heap which should be free()ed by the caller if not needed. | |
| */ | |
| static BOOL PSDRV_PPDGetNextTuple(FILE *fp, PPDTuple *tuple) | |
| { | |
| char line[257], *opt = NULL, *cp, *trans, *endkey; | |
| BOOL gotoption = TRUE; | |
| memset(tuple, 0, sizeof(*tuple)); | |
| do { | |
| if(!fgets(line, sizeof(line), fp)) | |
| return FALSE; | |
| if(line[0] == '*' && line[1] != '%' && strncmp(line, "*End", 4)) | |
| break; | |
| } while(1); | |
| if(line[strlen(line)-1] != '\n') { | |
| ERR("Line too long.\n"); | |
| return FALSE; | |
| } | |
| for(cp = line; !isspace(*cp) && *cp != ':'; cp++) | |
| ; | |
| endkey = cp; | |
| if(*cp == ':') { /* <key>: */ | |
| gotoption = FALSE; | |
| } else { | |
| while(isspace(*cp)) | |
| cp++; | |
| if(*cp == ':') { /* <key> : */ | |
| gotoption = FALSE; | |
| } else { /* <key> <option> */ | |
| opt = cp; | |
| } | |
| } | |
| tuple->key = HeapAlloc( PSDRV_Heap, 0, endkey - line + 1 ); | |
| if(!tuple->key) return FALSE; | |
| memcpy(tuple->key, line, endkey - line); | |
| tuple->key[endkey - line] = '\0'; | |
| if(gotoption) { /* opt points to 1st non-space character of the option */ | |
| cp = strpbrk(opt, ":/"); | |
| if(!cp) { | |
| ERR("Error in line '%s'?\n", line); | |
| return FALSE; | |
| } | |
| tuple->option = HeapAlloc( PSDRV_Heap, 0, cp - opt + 1 ); | |
| if(!tuple->option) return FALSE; | |
| memcpy(tuple->option, opt, cp - opt); | |
| tuple->option[cp - opt] = '\0'; | |
| if(*cp == '/') { | |
| char *buf; | |
| trans = cp + 1; | |
| cp = strchr(trans, ':'); | |
| if(!cp) { | |
| ERR("Error in line '%s'?\n", line); | |
| return FALSE; | |
| } | |
| buf = HeapAlloc( PSDRV_Heap, 0, cp - trans + 1 ); | |
| if(!buf) return FALSE; | |
| memcpy(buf, trans, cp - trans); | |
| buf[cp - trans] = '\0'; | |
| tuple->opttrans = PSDRV_PPDDecodeHex(buf); | |
| HeapFree( PSDRV_Heap, 0, buf ); | |
| } | |
| } | |
| /* cp should point to a ':', so we increment past it */ | |
| cp++; | |
| while(isspace(*cp)) | |
| cp++; | |
| switch(*cp) { | |
| case '"': | |
| if( (!gotoption && strncmp(tuple->key, "*?", 2) ) || | |
| !strncmp(tuple->key, "*JCL", 4)) | |
| PSDRV_PPDGetQuotedValue(fp, cp, tuple); | |
| else | |
| PSDRV_PPDGetInvocationValue(fp, cp, tuple); | |
| break; | |
| case '^': | |
| PSDRV_PPDGetSymbolValue(cp, tuple); | |
| break; | |
| default: | |
| PSDRV_PPDGetStringValue(cp, tuple); | |
| } | |
| return TRUE; | |
| } | |
| /********************************************************************* | |
| * | |
| * PSDRV_PPDGetPageSizeInfo | |
| * | |
| * Searches ppd PageSize list to return entry matching name or creates new | |
| * entry which is appended to the list if name is not found. | |
| * | |
| */ | |
| PAGESIZE *PSDRV_PPDGetPageSizeInfo(PPD *ppd, char *name) | |
| { | |
| PAGESIZE *page = ppd->PageSizes, *lastpage; | |
| if(!page) { | |
| page = ppd->PageSizes = HeapAlloc( PSDRV_Heap, | |
| HEAP_ZERO_MEMORY, sizeof(*page) ); | |
| return page; | |
| } else { | |
| for( ; page; page = page->next) { | |
| if(!strcmp(page->Name, name)) | |
| return page; | |
| lastpage = page; | |
| } | |
| lastpage->next = HeapAlloc( PSDRV_Heap, | |
| HEAP_ZERO_MEMORY, sizeof(*page) ); | |
| return lastpage->next; | |
| } | |
| } | |
| /********************************************************************** | |
| * | |
| * PSDRV_PPDGetWord | |
| * | |
| * Returns ptr alloced from heap to first word in str. Strips leading spaces. | |
| * Puts ptr to next word in next | |
| */ | |
| static char *PSDRV_PPDGetWord(char *str, char **next) | |
| { | |
| char *start, *end, *ret; | |
| start = str; | |
| while(start && *start && isspace(*start)) | |
| start++; | |
| if(!start || !*start) return FALSE; | |
| end = start; | |
| while(*end && !isspace(*end)) | |
| end++; | |
| ret = HeapAlloc( PSDRV_Heap, 0, end - start + 1 ); | |
| memcpy(ret, start, end - start ); | |
| *(ret + (end - start)) = '\0'; | |
| while(*end && isspace(*end)) | |
| end++; | |
| if(*end) | |
| *next = end; | |
| else | |
| *next = NULL; | |
| return ret; | |
| } | |
| /******************************************************************************* | |
| * PSDRV_AddSlot | |
| * | |
| */ | |
| static INT PSDRV_AddSlot(PPD *ppd, LPSTR szName, LPSTR szFullName, | |
| LPSTR szInvocationString, WORD wWinBin) | |
| { | |
| INPUTSLOT *slot, **insert = &ppd->InputSlots; | |
| while (*insert) | |
| insert = &((*insert)->next); | |
| slot = *insert = HeapAlloc(PSDRV_Heap, HEAP_ZERO_MEMORY, sizeof(INPUTSLOT)); | |
| if (!slot) | |
| { | |
| ERR("Failed to allocate %i bytes of memory\n", sizeof(INPUTSLOT)); | |
| return 1; | |
| } | |
| slot->Name = szName; | |
| slot->FullName = szFullName; | |
| slot->InvocationString = szInvocationString; | |
| slot->WinBin = wWinBin; | |
| return 0; | |
| } | |
| /*********************************************************************** | |
| * | |
| * PSDRV_ParsePPD | |
| * | |
| * | |
| */ | |
| PPD *PSDRV_ParsePPD(char *fname) | |
| { | |
| FILE *fp; | |
| PPD *ppd; | |
| PPDTuple tuple; | |
| TRACE("file '%s'\n", fname); | |
| if((fp = fopen(fname, "r")) == NULL) { | |
| WARN("Couldn't open ppd file '%s'\n", fname); | |
| return NULL; | |
| } | |
| ppd = HeapAlloc( PSDRV_Heap, HEAP_ZERO_MEMORY, sizeof(*ppd)); | |
| if(!ppd) { | |
| ERR("Unable to allocate memory for ppd\n"); | |
| fclose(fp); | |
| return NULL; | |
| } | |
| /* | |
| * The Windows PostScript drivers create the following "virtual bin" for | |
| * every PostScript printer | |
| */ | |
| if (PSDRV_AddSlot(ppd, NULL, "Automatically Select", NULL, | |
| DMBIN_FORMSOURCE)) | |
| { | |
| HeapFree (PSDRV_Heap, 0, ppd); | |
| fclose(fp); | |
| return NULL; | |
| } | |
| while( PSDRV_PPDGetNextTuple(fp, &tuple)) { | |
| if(!strcmp("*NickName", tuple.key)) { | |
| ppd->NickName = tuple.value; | |
| tuple.value = NULL; | |
| TRACE("NickName = '%s'\n", ppd->NickName); | |
| } | |
| else if(!strcmp("*LanguageLevel", tuple.key)) { | |
| sscanf(tuple.value, "%d", &(ppd->LanguageLevel)); | |
| TRACE("LanguageLevel = %d\n", ppd->LanguageLevel); | |
| } | |
| else if(!strcmp("*ColorDevice", tuple.key)) { | |
| if(!strcasecmp(tuple.value, "true")) | |
| ppd->ColorDevice = TRUE; | |
| TRACE("ColorDevice = %d\n", (int)ppd->ColorDevice); | |
| } | |
| else if((!strcmp("*DefaultResolution", tuple.key)) || | |
| (!strcmp("*DefaultJCLResolution", tuple.key))) { | |
| sscanf(tuple.value, "%d", &(ppd->DefaultResolution)); | |
| TRACE("DefaultResolution = %d\n", ppd->DefaultResolution); | |
| } | |
| else if(!strcmp("*Font", tuple.key)) { | |
| FONTNAME *fn; | |
| for(fn = ppd->InstalledFonts; fn && fn->next; fn = fn->next) | |
| ; | |
| if(!fn) { | |
| ppd->InstalledFonts = HeapAlloc(PSDRV_Heap, | |
| HEAP_ZERO_MEMORY, sizeof(*fn)); | |
| fn = ppd->InstalledFonts; | |
| } else { | |
| fn->next = HeapAlloc(PSDRV_Heap, | |
| HEAP_ZERO_MEMORY, sizeof(*fn)); | |
| fn = fn->next; | |
| } | |
| fn->Name = tuple.option; | |
| tuple.option = NULL; | |
| } | |
| else if(!strcmp("*DefaultFont", tuple.key)) { | |
| ppd->DefaultFont = tuple.value; | |
| tuple.value = NULL; | |
| } | |
| else if(!strcmp("*JCLBegin", tuple.key)) { | |
| ppd->JCLBegin = tuple.value; | |
| tuple.value = NULL; | |
| } | |
| else if(!strcmp("*JCLToPSInterpreter", tuple.key)) { | |
| ppd->JCLToPSInterpreter = tuple.value; | |
| tuple.value = NULL; | |
| } | |
| else if(!strcmp("*JCLEnd", tuple.key)) { | |
| ppd->JCLEnd = tuple.value; | |
| tuple.value = NULL; | |
| } | |
| else if(!strcmp("*PageSize", tuple.key)) { | |
| PAGESIZE *page; | |
| page = PSDRV_PPDGetPageSizeInfo(ppd, tuple.option); | |
| if(!page->Name) { | |
| int i; | |
| page->Name = tuple.option; | |
| tuple.option = NULL; | |
| for(i = 0; PageTrans[i].PSName; i++) { | |
| if(!strcmp(PageTrans[i].PSName, page->Name)) { /* case ? */ | |
| page->WinPage = PageTrans[i].WinPage; | |
| break; | |
| } | |
| } | |
| if(!page->WinPage) { | |
| TRACE("Can't find Windows page type for '%s' - using %u\n", | |
| page->Name, UserPageType); | |
| page->WinPage = UserPageType++; | |
| } | |
| } | |
| if(!page->FullName) { | |
| if(tuple.opttrans) { | |
| page->FullName = tuple.opttrans; | |
| tuple.opttrans = NULL; | |
| } else | |
| { | |
| page->FullName = HeapAlloc( PSDRV_Heap, 0, strlen(page->Name)+1 ); | |
| strcpy( page->FullName, page->Name ); | |
| } | |
| } | |
| if(!page->InvocationString) { | |
| page->InvocationString = tuple.value; | |
| tuple.value = NULL; | |
| } | |
| } | |
| else if(!strcmp("*ImageableArea", tuple.key)) { | |
| PAGESIZE *page; | |
| page = PSDRV_PPDGetPageSizeInfo(ppd, tuple.option); | |
| if(!page->Name) { | |
| page->Name = tuple.option; | |
| tuple.option = NULL; | |
| } | |
| if(!page->FullName) { | |
| page->FullName = tuple.opttrans; | |
| tuple.opttrans = NULL; | |
| } | |
| #define PIA page->ImageableArea | |
| if(!PIA) { | |
| PIA = HeapAlloc( PSDRV_Heap, 0, sizeof(*PIA) ); | |
| sscanf(tuple.value, "%f%f%f%f", &PIA->llx, &PIA->lly, | |
| &PIA->urx, &PIA->ury); | |
| } | |
| #undef PIA | |
| } | |
| else if(!strcmp("*PaperDimension", tuple.key)) { | |
| PAGESIZE *page; | |
| page = PSDRV_PPDGetPageSizeInfo(ppd, tuple.option); | |
| if(!page->Name) { | |
| page->Name = tuple.option; | |
| tuple.option = NULL; | |
| } | |
| if(!page->FullName) { | |
| page->FullName = tuple.opttrans; | |
| tuple.opttrans = NULL; | |
| } | |
| #define PD page->PaperDimension | |
| if(!PD) { | |
| PD = HeapAlloc( PSDRV_Heap, 0, sizeof(*PD) ); | |
| sscanf(tuple.value, "%f%f", &PD->x, &PD->y); | |
| } | |
| #undef PD | |
| } | |
| else if(!strcmp("*LandscapeOrientation", tuple.key)) { | |
| if(!strcmp(tuple.value, "Plus90")) | |
| ppd->LandscapeOrientation = 90; | |
| else if(!strcmp(tuple.value, "Minus90")) | |
| ppd->LandscapeOrientation = -90; | |
| /* anything else, namely 'any', leaves value at 0 */ | |
| TRACE("LandscapeOrientation = %d\n", | |
| ppd->LandscapeOrientation); | |
| } | |
| else if(!strcmp("*UIConstraints", tuple.key)) { | |
| char *start; | |
| CONSTRAINT *con, **insert = &ppd->Constraints; | |
| while(*insert) | |
| insert = &((*insert)->next); | |
| con = *insert = HeapAlloc( PSDRV_Heap, HEAP_ZERO_MEMORY, | |
| sizeof(*con) ); | |
| start = tuple.value; | |
| con->Feature1 = PSDRV_PPDGetWord(start, &start); | |
| con->Value1 = PSDRV_PPDGetWord(start, &start); | |
| con->Feature2 = PSDRV_PPDGetWord(start, &start); | |
| con->Value2 = PSDRV_PPDGetWord(start, &start); | |
| } | |
| else if (!strcmp("*InputSlot", tuple.key)) | |
| { | |
| if (!tuple.opttrans) | |
| tuple.opttrans = tuple.option; | |
| TRACE("Using Windows bin type %u for '%s'\n", UserBinType, | |
| tuple.option); | |
| /* FIXME - should check for failure */ | |
| PSDRV_AddSlot(ppd, tuple.option, tuple.opttrans, tuple.value, | |
| UserBinType++); | |
| tuple.option = tuple.opttrans = tuple.value = NULL; | |
| } | |
| /* | |
| * Windows treats "manual feed" as another paper source. Most PPD | |
| * files, however, treat it as a separate option which is either on or | |
| * off. | |
| */ | |
| else if (!strcmp("*ManualFeed", tuple.key) && tuple.option && | |
| !strcmp ("True", tuple.option)) | |
| { | |
| /* FIXME - should check for failure */ | |
| PSDRV_AddSlot(ppd, "Manual Feed", "Manual Feed", tuple.value, DMBIN_MANUAL); | |
| tuple.value = NULL; | |
| } | |
| else if(!strcmp("*TTRasterizer", tuple.key)) { | |
| if(!strcasecmp("None", tuple.value)) | |
| ppd->TTRasterizer = RO_None; | |
| else if(!strcasecmp("Accept68K", tuple.value)) | |
| ppd->TTRasterizer = RO_Accept68K; | |
| else if(!strcasecmp("Type42", tuple.value)) | |
| ppd->TTRasterizer = RO_Type42; | |
| else if(!strcasecmp("TrueImage", tuple.value)) | |
| ppd->TTRasterizer = RO_TrueImage; | |
| else { | |
| FIXME("Unknown option %s for *TTRasterizer\n", | |
| tuple.value); | |
| ppd->TTRasterizer = RO_None; | |
| } | |
| } | |
| if(tuple.key) HeapFree(PSDRV_Heap, 0, tuple.key); | |
| if(tuple.option) HeapFree(PSDRV_Heap, 0, tuple.option); | |
| if(tuple.value) HeapFree(PSDRV_Heap, 0, tuple.value); | |
| if(tuple.opttrans) HeapFree(PSDRV_Heap, 0, tuple.opttrans); | |
| if(tuple.valtrans) HeapFree(PSDRV_Heap, 0, tuple.valtrans); | |
| } | |
| { | |
| FONTNAME *fn; | |
| PAGESIZE *page; | |
| CONSTRAINT *con; | |
| INPUTSLOT *slot; | |
| OPTION *option; | |
| OPTIONENTRY *optionEntry; | |
| for(fn = ppd->InstalledFonts; fn; fn = fn->next) | |
| TRACE("'%s'\n", fn->Name); | |
| for(page = ppd->PageSizes; page; page = page->next) { | |
| TRACE("'%s' aka '%s' (%d) invoked by '%s'\n", page->Name, | |
| page->FullName, page->WinPage, page->InvocationString); | |
| if(page->ImageableArea) | |
| TRACE("Area = %.2f,%.2f - %.2f, %.2f\n", | |
| page->ImageableArea->llx, page->ImageableArea->lly, | |
| page->ImageableArea->urx, page->ImageableArea->ury); | |
| if(page->PaperDimension) | |
| TRACE("Dimension = %.2f x %.2f\n", | |
| page->PaperDimension->x, page->PaperDimension->y); | |
| } | |
| for(con = ppd->Constraints; con; con = con->next) | |
| TRACE("CONSTRAINTS@ %s %s %s %s\n", con->Feature1, | |
| con->Value1, con->Feature2, con->Value2); | |
| for(option = ppd->InstalledOptions; option; option = option->next) { | |
| TRACE("OPTION: %s %s %s\n", option->OptionName, | |
| option->FullName, option->DefaultOption); | |
| for(optionEntry = option->Options; optionEntry; | |
| optionEntry = optionEntry->next) | |
| TRACE("\tOPTIONENTRY: %s %s %s\n", optionEntry->Name, | |
| optionEntry->FullName, optionEntry->InvocationString); | |
| } | |
| for(slot = ppd->InputSlots; slot; slot = slot->next) | |
| TRACE("INPUTSLOTS '%s' Name '%s' (%d) Invocation '%s'\n", | |
| slot->Name, slot->FullName, slot->WinBin, | |
| slot->InvocationString); | |
| } | |
| return ppd; | |
| } |