| /* 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, NULL, "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; |
| } |
| |