wine/dlls/wineps/ppd.c
Huw Davies 5d275962eb Instead of trying to download the Type 42 glpyh metrics incrementally
(which most printers don't seem to understand), we'll download the
whole hmtx table in one go (sigh) unless it's larger than 64K in which
case we'll go back to using a Type 1 font.
2002-11-13 23:51:44 +00:00

851 lines
24 KiB
C

/* 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;
}
TRACE("*TTRasterizer = %d\n", ppd->TTRasterizer);
}
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;
}