diff --git a/dlls/wineps/afm.c b/dlls/wineps/afm.c index 486131c5343..10b3074c86a 100644 --- a/dlls/wineps/afm.c +++ b/dlls/wineps/afm.c @@ -10,7 +10,9 @@ #include #include #include -#include "winnt.h" /* HEAP_ZERO_MEMORY */ +#include /* INT_MIN */ +#include /* FLT_MAX */ +#include "winnt.h" /* HEAP_ZERO_MEMORY */ #include "psdrv.h" #include "options.h" #include "debugtools.h" @@ -22,6 +24,58 @@ DEFAULT_DEBUG_CHANNEL(psdrv); /* ptr to fonts for which we have afm files */ FONTFAMILY *PSDRV_AFMFontList = NULL; +/******************************************************************************* + * CheckMetrics + * + * Check an AFMMETRICS structure to make sure all elements have been properly + * filled in. + * + */ +static const AFMMETRICS badMetrics = +{ + INT_MIN, /* C */ + FLT_MAX, /* WX */ + NULL, /* N */ + { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX }, /* B */ + NULL /* L */ +}; + +inline static BOOL CheckMetrics(const AFMMETRICS *metrics) +{ + if ( metrics->C == badMetrics.C || + metrics->WX == badMetrics.WX || + metrics->N == badMetrics.N || + metrics->B.llx == badMetrics.B.llx || + metrics->B.lly == badMetrics.B.lly || + metrics->B.urx == badMetrics.B.urx || + metrics->B.ury == badMetrics.B.ury ) + return FALSE; + + return TRUE; +} + +/******************************************************************************* + * FreeAFM + * + * Free an AFM structure and any subsidiary objects that have been allocated + * + */ +static void FreeAFM(AFM *afm) +{ + if (afm->FontName != NULL) + HeapFree(PSDRV_Heap, 0, afm->FontName); + if (afm->FullName != NULL) + HeapFree(PSDRV_Heap, 0, afm->FullName); + if (afm->FamilyName != NULL) + HeapFree(PSDRV_Heap, 0, afm->FamilyName); + if (afm->EncodingScheme != NULL) + HeapFree(PSDRV_Heap, 0, afm->EncodingScheme); + if (afm->Metrics != NULL) + HeapFree(PSDRV_Heap, 0, afm->Metrics); + + HeapFree(PSDRV_Heap, 0, afm); +} + /*********************************************************** * @@ -32,21 +86,28 @@ FONTFAMILY *PSDRV_AFMFontList = NULL; * Actually only collects the widths of numbered chars and puts then in * afm->CharWidths. */ -static void PSDRV_AFMGetCharMetrics(AFM *afm, FILE *fp) +static BOOL PSDRV_AFMGetCharMetrics(AFM *afm, FILE *fp) { unsigned char line[256], valbuf[256]; unsigned char *cp, *item, *value, *curpos, *endpos; int i; AFMMETRICS *metric; - afm->Metrics = metric = HeapAlloc( PSDRV_Heap, HEAP_ZERO_MEMORY, + afm->Metrics = metric = HeapAlloc( PSDRV_Heap, 0, afm->NumofMetrics * sizeof(AFMMETRICS) ); + if (metric == NULL) + return FALSE; + for(i = 0; i < afm->NumofMetrics; i++, metric++) { + + *metric = badMetrics; do { if(!fgets(line, sizeof(line), fp)) { ERR("Unexpected EOF\n"); - return; + HeapFree(PSDRV_Heap, 0, afm->Metrics); + afm->Metrics = NULL; + return FALSE; } cp = line + strlen(line); do { @@ -61,11 +122,21 @@ static void PSDRV_AFMGetCharMetrics(AFM *afm, FILE *fp) while(isspace(*item)) item++; value = strpbrk(item, " \t"); - if (!value) { ERR("No whitespace found.\n");return;} + if (!value) { + ERR("No whitespace found.\n"); + HeapFree(PSDRV_Heap, 0, afm->Metrics); + afm->Metrics = NULL; + return FALSE; + } while(isspace(*value)) value++; cp = endpos = strchr(value, ';'); - if (!cp) { ERR("missing ;, failed. [%s]\n", line); return; } + if (!cp) { + ERR("missing ;, failed. [%s]\n", line); + HeapFree(PSDRV_Heap, 0, afm->Metrics); + afm->Metrics = NULL; + return FALSE; + } while(isspace(*--cp)) ; memcpy(valbuf, value, cp - value + 1); @@ -104,13 +175,20 @@ static void PSDRV_AFMGetCharMetrics(AFM *afm, FILE *fp) curpos = endpos + 1; } + + if (CheckMetrics(metric) == FALSE) { + ERR("Error parsing character metrics\n"); + HeapFree(PSDRV_Heap, 0, afm->Metrics); + afm->Metrics = NULL; + return FALSE; + } TRACE("Metrics for '%s' WX = %f B = %f,%f - %f,%f\n", metric->N->sz, metric->WX, metric->B.llx, metric->B.lly, metric->B.urx, metric->B.ury); } - return; + return TRUE; } /*********************************************************** @@ -123,6 +201,7 @@ static void PSDRV_AFMGetCharMetrics(AFM *afm, FILE *fp) * * This is not complete (we don't handle kerning yet) and not efficient */ + static AFM *PSDRV_AFMParse(char const *file) { FILE *fp; @@ -178,16 +257,31 @@ static AFM *PSDRV_AFMParse(char const *file) if(!strncmp("FontName", buf, 8)) { afm->FontName = HEAP_strdupA(PSDRV_Heap, 0, value); + if (afm->FontName == NULL) { + fclose(fp); + FreeAFM(afm); + return NULL; + } continue; } if(!strncmp("FullName", buf, 8)) { afm->FullName = HEAP_strdupA(PSDRV_Heap, 0, value); + if (afm->FullName == NULL) { + fclose(fp); + FreeAFM(afm); + return NULL; + } continue; } if(!strncmp("FamilyName", buf, 10)) { afm->FamilyName = HEAP_strdupA(PSDRV_Heap, 0, value); + if (afm->FamilyName == NULL) { + fclose(fp); + FreeAFM(afm); + return NULL; + } continue; } @@ -264,12 +358,21 @@ static AFM *PSDRV_AFMParse(char const *file) if(!strncmp("StartCharMetrics", buf, 16)) { sscanf(value, "%d", &(afm->NumofMetrics) ); - PSDRV_AFMGetCharMetrics(afm, fp); + if (PSDRV_AFMGetCharMetrics(afm, fp) == FALSE) { + fclose(fp); + FreeAFM(afm); + return NULL; + } continue; } if(!strncmp("EncodingScheme", buf, 14)) { afm->EncodingScheme = HEAP_strdupA(PSDRV_Heap, 0, value); + if (afm->EncodingScheme == NULL) { + fclose(fp); + FreeAFM(afm); + return NULL; + } continue; } @@ -284,11 +387,21 @@ static AFM *PSDRV_AFMParse(char const *file) if(afm->FontName == NULL) { WARN("%s contains no FontName.\n", file); afm->FontName = HEAP_strdupA(PSDRV_Heap, 0, "nofont"); + if (afm->FontName == NULL) { + FreeAFM(afm); + return NULL; + } } + if(afm->FullName == NULL) afm->FullName = HEAP_strdupA(PSDRV_Heap, 0, afm->FontName); if(afm->FamilyName == NULL) - afm->FamilyName = HEAP_strdupA(PSDRV_Heap, 0, afm->FontName); + afm->FamilyName = HEAP_strdupA(PSDRV_Heap, 0, afm->FontName); + if (afm->FullName == NULL || afm->FamilyName == NULL) { + FreeAFM(afm); + return NULL; + } + if(afm->Ascender == 0.0) afm->Ascender = afm->FontBBox.ury; if(afm->Descender == 0.0) @@ -351,7 +464,7 @@ AFM *PSDRV_FindAFMinList(FONTFAMILY *head, char *name) * Adds an afm to the list whose head is pointed to by head. Creates new * family node if necessary and always creates a new AFMLISTENTRY. */ -void PSDRV_AddAFMtoList(FONTFAMILY **head, AFM *afm) +BOOL PSDRV_AddAFMtoList(FONTFAMILY **head, AFM *afm) { FONTFAMILY *family = *head; FONTFAMILY **insert = head; @@ -359,6 +472,9 @@ void PSDRV_AddAFMtoList(FONTFAMILY **head, AFM *afm) newafmle = HeapAlloc(PSDRV_Heap, HEAP_ZERO_MEMORY, sizeof(*newafmle)); + if (newafmle == NULL) + return FALSE; + newafmle->afm = afm; while(family) { @@ -371,11 +487,20 @@ void PSDRV_AddAFMtoList(FONTFAMILY **head, AFM *afm) if(!family) { family = HeapAlloc(PSDRV_Heap, HEAP_ZERO_MEMORY, sizeof(*family)); + if (family == NULL) { + HeapFree(PSDRV_Heap, 0, newafmle); + return FALSE; + } *insert = family; family->FamilyName = HEAP_strdupA(PSDRV_Heap, 0, afm->FamilyName); + if (family->FamilyName == NULL) { + HeapFree(PSDRV_Heap, 0, family); + HeapFree(PSDRV_Heap, 0, newafmle); + return FALSE; + } family->afmlist = newafmle; - return; + return TRUE; } tmpafmle = family->afmlist; @@ -384,7 +509,7 @@ void PSDRV_AddAFMtoList(FONTFAMILY **head, AFM *afm) tmpafmle->next = newafmle; - return; + return TRUE; } /********************************************************** @@ -446,11 +571,13 @@ static void PSDRV_DumpFontList(void) * * PSDRV_GetFontMetrics * - * Only exported function in this file. Parses all afm files listed in - * [afmfiles] and [afmdirs] of wine.conf . + * Parses all afm files listed in [afmfiles] and [afmdirs] of wine.conf + * + * If this function fails, PSDRV_Init will destroy PSDRV_Heap, so don't worry + * about freeing all the memory that's been allocated. */ -static void PSDRV_ReadAFMDir(const char* afmdir) { +static BOOL PSDRV_ReadAFMDir(const char* afmdir) { DIR *dir; AFM *afm; @@ -461,7 +588,12 @@ static void PSDRV_ReadAFMDir(const char* afmdir) { if (strstr(dent->d_name,".afm")) { char *afmfn; - afmfn=(char*)HeapAlloc(GetProcessHeap(),0,strlen(afmdir)+strlen(dent->d_name)+2); + afmfn=(char*)HeapAlloc(PSDRV_Heap,0, + strlen(afmdir)+strlen(dent->d_name)+2); + if (afmfn == NULL) { + closedir(dir); + return FALSE; + } strcpy(afmfn,afmdir); strcat(afmfn,"/"); strcat(afmfn,dent->d_name); @@ -472,13 +604,25 @@ static void PSDRV_ReadAFMDir(const char* afmdir) { !strcmp(afm->EncodingScheme,"AdobeStandardEncoding")) { PSDRV_ReencodeCharWidths(afm); } - PSDRV_AddAFMtoList(&PSDRV_AFMFontList, afm); + if (PSDRV_AddAFMtoList(&PSDRV_AFMFontList, afm) == FALSE) { + closedir(dir); + FreeAFM(afm); + return FALSE; + } } - HeapFree(GetProcessHeap(),0,afmfn); + else { + WARN("Error parsing %s\n", afmfn); + } + HeapFree(PSDRV_Heap,0,afmfn); } } closedir(dir); } + else { + WARN("Error opening %s\n", afmdir); + } + + return TRUE; } BOOL PSDRV_GetFontMetrics(void) @@ -490,22 +634,29 @@ BOOL PSDRV_GetFontMetrics(void) if (PSDRV_GlyphListInit() != 0) return FALSE; - while (PROFILE_EnumWineIniString( "afmfiles", idx++, key, sizeof(key), value, sizeof(value))) + while (PROFILE_EnumWineIniString( "afmfiles", idx++, key, sizeof(key), + value, sizeof(value))) { AFM* afm = PSDRV_AFMParse(value); - if (afm) - { + + if (afm) { if(afm->EncodingScheme && !strcmp(afm->EncodingScheme, "AdobeStandardEncoding")) { PSDRV_ReencodeCharWidths(afm); } - PSDRV_AddAFMtoList(&PSDRV_AFMFontList, afm); + if (PSDRV_AddAFMtoList(&PSDRV_AFMFontList, afm) == FALSE) { + return FALSE; + } } + else { + WARN("Error parsing %s\n", value); + } } for (idx = 0; PROFILE_EnumWineIniString ("afmdirs", idx, key, sizeof (key), value, sizeof (value)); ++idx) - PSDRV_ReadAFMDir (value); + if (PSDRV_ReadAFMDir (value) == FALSE) + return FALSE; PSDRV_DumpGlyphList(); PSDRV_DumpFontList(); diff --git a/dlls/wineps/init.c b/dlls/wineps/init.c index c09b2627df6..e53415098a1 100644 --- a/dlls/wineps/init.c +++ b/dlls/wineps/init.c @@ -219,7 +219,6 @@ static PSDRV_DEVMODEA DefaultDevmode = /* dummy */ 0 }, { /* dmDrvPrivate */ - /* ppdfilename */ "default.ppd", /* numInstalledOptions */ 0 } }; @@ -467,27 +466,43 @@ PRINTERINFO *PSDRV_FindPrinterInfo(LPCSTR name) AFM *afm; HANDLE hPrinter; const char *ppd = NULL; + char ppdFileName[256]; TRACE("'%s'\n", name); + /* + * If this loop completes, last will point to the 'next' element of the + * final PRINTERINFO in the list + */ for( ; pi; last = &pi->next, pi = pi->next) if(!strcmp(pi->FriendlyName, name)) return pi; - pi = *last = HeapAlloc( PSDRV_Heap, 0, sizeof(*pi) ); + pi = *last = HeapAlloc( PSDRV_Heap, HEAP_ZERO_MEMORY, sizeof(*pi) ); + if (pi == NULL) + return NULL; + pi->FriendlyName = HEAP_strdupA( PSDRV_Heap, 0, name ); + if (pi->FriendlyName == NULL) + goto fail; + + /* Use Get|SetPrinterDataExA instead? */ + res = DrvGetPrinterData16((LPSTR)name, (LPSTR)INT_PD_DEFAULT_DEVMODE, &type, NULL, 0, &needed ); if(res == ERROR_INVALID_PRINTER_NAME || needed != sizeof(DefaultDevmode)) { pi->Devmode = HeapAlloc( PSDRV_Heap, 0, sizeof(DefaultDevmode) ); + if (pi->Devmode == NULL) + goto cleanup; memcpy(pi->Devmode, &DefaultDevmode, sizeof(DefaultDevmode) ); strcpy(pi->Devmode->dmPublic.dmDeviceName,name); DrvSetPrinterData16((LPSTR)name, (LPSTR)INT_PD_DEFAULT_DEVMODE, REG_BINARY, (LPBYTE)&DefaultDevmode, sizeof(DefaultDevmode) ); /* need to do something here AddPrinter?? */ - } else { + } + else { pi->Devmode = HeapAlloc( PSDRV_Heap, 0, needed ); DrvGetPrinterData16((LPSTR)name, (LPSTR)INT_PD_DEFAULT_DEVMODE, &type, (LPBYTE)pi->Devmode, needed, &needed); @@ -497,29 +512,48 @@ PRINTERINFO *PSDRV_FindPrinterInfo(LPCSTR name) ERR ("OpenPrinterA failed with code %li\n", GetLastError ()); goto cleanup; } - pi->Devmode->dmDrvPrivate.ppdFileName[0]='\0'; + + ppdFileName[0]='\0'; + #ifdef HAVE_CUPS { ppd = cupsGetPPD(name); if (ppd) { - strcpy(pi->Devmode->dmDrvPrivate.ppdFileName,ppd); - res = ERROR_SUCCESS; - /* we should unlink() that file later */ - } else { + strncpy(ppdFileName, ppd, sizeof(ppdFileName)); + res = ERROR_SUCCESS; + /* we should unlink() that file later */ + } + else { ERR("Did not find ppd for %s\n",name); } } #endif - if (!pi->Devmode->dmDrvPrivate.ppdFileName[0]) { - res = GetPrinterDataA (hPrinter, "PPD File", NULL, - pi->Devmode->dmDrvPrivate.ppdFileName, 256, &needed); + + if (!ppdFileName[0]) { + res = GetPrinterDataA (hPrinter, "PPD File", NULL, ppdFileName, + sizeof(ppdFileName), &needed); } + if (res != ERROR_SUCCESS) { ERR ("Error %li getting PPD file name for printer '%s'\n", res, name); goto closeprinter; } - + + ppdFileName[sizeof(ppdFileName) - 1] = '\0'; + + pi->ppd = PSDRV_ParsePPD(ppdFileName); + if(!pi->ppd) { + MESSAGE("Couldn't find PPD file '%s', expect a crash now!\n", + ppdFileName); + goto closeprinter; + } + + /* + * This is a hack. The default paper size should be read in as part of + * the Devmode structure, but Wine doesn't currently provide a convenient + * way to configure printers. + */ res = GetPrinterDataA (hPrinter, "Paper Size", NULL, (LPBYTE) &dwPaperSize, sizeof (DWORD), &needed); if (res == ERROR_SUCCESS) @@ -533,10 +567,10 @@ PRINTERINFO *PSDRV_FindPrinterInfo(LPCSTR name) res = EnumPrinterDataExA (hPrinter, "PrinterDriverData\\FontSubTable", NULL, 0, &needed, &pi->FontSubTableSize); - if (res == ERROR_SUCCESS) + if (res == ERROR_SUCCESS || res == ERROR_FILE_NOT_FOUND) { TRACE ("No 'FontSubTable' for printer '%s'\n", name); - else if (res == ERROR_MORE_DATA) - { + } + else if (res == ERROR_MORE_DATA) { pi->FontSubTable = HeapAlloc (PSDRV_Heap, 0, needed); if (pi->FontSubTable == NULL) { ERR ("Failed to allocate %li bytes from heap\n", needed); @@ -550,9 +584,10 @@ PRINTERINFO *PSDRV_FindPrinterInfo(LPCSTR name) ERR ("EnumPrinterDataExA returned %li\n", res); goto closeprinter; } - } else { - FIXME ("EnumPrinterDataExA returned %li\n", res); - /* ignore error */ + } + else { + ERR("EnumPrinterDataExA returned %li\n", res); + goto closeprinter; } if (ClosePrinter (hPrinter) == 0) { @@ -560,22 +595,21 @@ PRINTERINFO *PSDRV_FindPrinterInfo(LPCSTR name) goto cleanup; } - pi->ppd = PSDRV_ParsePPD(pi->Devmode->dmDrvPrivate.ppdFileName); - if(!pi->ppd) { - MESSAGE("Couldn't find PPD file '%s', expect a crash now!\n", - pi->Devmode->dmDrvPrivate.ppdFileName); - goto cleanup; - } - pi->next = NULL; pi->Fonts = NULL; for(font = pi->ppd->InstalledFonts; font; font = font->next) { afm = PSDRV_FindAFMinList(PSDRV_AFMFontList, font->Name); - if(!afm) - TRACE( "Couldn't find AFM file for installed printer font '%s' - ignoring\n", font->Name); - else - PSDRV_AddAFMtoList(&pi->Fonts, afm); + if(!afm) { + TRACE( "Couldn't find AFM file for installed printer font '%s' - " + "ignoring\n", font->Name); + } + else { + if (PSDRV_AddAFMtoList(&pi->Fonts, afm) == FALSE) { + PSDRV_FreeAFMList(pi->Fonts); + goto cleanup; + } + } } if (ppd) unlink(ppd); @@ -584,9 +618,13 @@ PRINTERINFO *PSDRV_FindPrinterInfo(LPCSTR name) closeprinter: ClosePrinter(hPrinter); cleanup: - HeapFree (PSDRV_Heap, 0, pi->FontSubTable); - HeapFree(PSDRV_Heap, 0, pi->FriendlyName); - HeapFree(PSDRV_Heap, 0, pi->Devmode); + if (pi->FontSubTable) + HeapFree(PSDRV_Heap, 0, pi->FontSubTable); + if (pi->FriendlyName) + HeapFree(PSDRV_Heap, 0, pi->FriendlyName); + if (pi->Devmode) + HeapFree(PSDRV_Heap, 0, pi->Devmode); +fail: HeapFree(PSDRV_Heap, 0, pi); if (ppd) unlink(ppd); *last = NULL; diff --git a/dlls/wineps/psdrv.h b/dlls/wineps/psdrv.h index a15b498611e..2c45f41ee52 100644 --- a/dlls/wineps/psdrv.h +++ b/dlls/wineps/psdrv.h @@ -170,7 +170,6 @@ typedef struct { int dummy; } dmDocPrivate; struct _tagdrvprivate { - char ppdFileName[256]; /* Hack */ UINT numInstalledOptions; /* Options at end of struct */ } dmDrvPrivate; @@ -274,7 +273,7 @@ extern BOOL PSDRV_GetFontMetrics(void); extern PPD *PSDRV_ParsePPD(char *fname); extern PRINTERINFO *PSDRV_FindPrinterInfo(LPCSTR name); extern AFM *PSDRV_FindAFMinList(FONTFAMILY *head, char *name); -extern void PSDRV_AddAFMtoList(FONTFAMILY **head, AFM *afm); +extern BOOL PSDRV_AddAFMtoList(FONTFAMILY **head, AFM *afm); extern void PSDRV_FreeAFMList( FONTFAMILY *head ); extern BOOL WINAPI PSDRV_Init(HINSTANCE hinst, DWORD reason, LPVOID reserved);