More error checking for PostScript driver
Ian Pilcher
ian.pilcher at home.com
Wed May 2 16:33:43 CDT 2001
This patch adds checks for memory allocation (and other) failures to the
AFM parsing code and PSDRV_FindPrinterInfo. It also gets the PPD file
name out of the PSDRV_DEVMODEA structure.
The changes to the AFM parsing code will make the driver ignore any AFM
files that have errors in them.
Modified files:
dlls/wineps: afm.c init.c psdrv.h
Log message:
Ian Pilcher
Misc. error checking in PostScript driver
--
========================================================================
Ian Pilcher ian.pilcher at home.com
========================================================================
-------------- next part --------------
diff -urN ../wine-20010502cvs/dlls/wineps/afm.c ./dlls/wineps/afm.c
--- ../wine-20010502cvs/dlls/wineps/afm.c Fri Apr 20 13:30:38 2001
+++ ./dlls/wineps/afm.c Wed May 2 15:23:54 2001
@@ -10,7 +10,9 @@
#include <stdio.h>
#include <sys/stat.h>
#include <dirent.h>
-#include "winnt.h" /* HEAP_ZERO_MEMORY */
+#include <limits.h> /* INT_MIN */
+#include <float.h> /* FLT_MAX */
+#include "winnt.h" /* HEAP_ZERO_MEMORY */
#include "psdrv.h"
#include "options.h"
#include "debugtools.h"
@@ -22,6 +24,58 @@
/* 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 @@
* 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 @@
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 @@
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 @@
*
* 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 @@
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 @@
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 @@
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 @@
* 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 @@
newafmle = HeapAlloc(PSDRV_Heap, HEAP_ZERO_MEMORY,
sizeof(*newafmle));
+ if (newafmle == NULL)
+ return FALSE;
+
newafmle->afm = afm;
while(family) {
@@ -371,11 +487,20 @@
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 @@
tmpafmle->next = newafmle;
- return;
+ return TRUE;
}
/**********************************************************
@@ -446,11 +571,13 @@
*
* 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 @@
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 @@
!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;
+ }
+ }
+ else {
+ WARN("Error parsing %s\n", afmfn);
}
- HeapFree(GetProcessHeap(),0,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 @@
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 -urN ../wine-20010502cvs/dlls/wineps/init.c ./dlls/wineps/init.c
--- ../wine-20010502cvs/dlls/wineps/init.c Wed May 2 12:57:30 2001
+++ ./dlls/wineps/init.c Wed May 2 15:27:49 2001
@@ -219,7 +219,6 @@
/* dummy */ 0
},
{ /* dmDrvPrivate */
- /* ppdfilename */ "default.ppd",
/* numInstalledOptions */ 0
}
};
@@ -467,27 +466,43 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 -urN ../wine-20010502cvs/dlls/wineps/psdrv.h ./dlls/wineps/psdrv.h
--- ../wine-20010502cvs/dlls/wineps/psdrv.h Mon Apr 23 13:12:45 2001
+++ ./dlls/wineps/psdrv.h Wed May 2 15:23:55 2001
@@ -170,7 +170,6 @@
int dummy;
} dmDocPrivate;
struct _tagdrvprivate {
- char ppdFileName[256]; /* Hack */
UINT numInstalledOptions; /* Options at end of struct */
} dmDrvPrivate;
@@ -274,7 +273,7 @@
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);
More information about the wine-patches
mailing list