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