Hi.

Here is a proposed fix for this problem.

The original code was using gzseek/gzeof/gztell to figure out the
uncompressed size of a compressed instrument bank file, to preallocate
the buffer for reading its contents, and something in zlib has broken
that. I know this is supposed to work, but it’s going to be slow anyway.
So this patch replaces that with incremental buffer allocation and
reading, in increments of 1 kiB. Looking at the existing bank files,
which seem to be only a few kiB in size, this should work OK in terms
of both speed and RAM usage.

Lawrence D’Oliveiro
--- src/Misc/XMLwrapper.cpp-orig	2009-07-16 07:48:41.000000000 +1200
+++ src/Misc/XMLwrapper.cpp	2012-04-24 16:42:11.968157362 +1200
@@ -300,50 +300,70 @@
     return(0);
 };
 
+/* wrappers with more convenient and consistent signatures than direct gzread and fread calls */
+static ssize_t read_compressed
+  (
+	void * thefile,
+	char * buffer,
+	size_t bufsize
+  )
+  {
+	return
+		gzread((gzFile)thefile, buffer, bufsize);
+  } /*gz_read*/
+
+static ssize_t read_uncompressed
+  (
+	void * thefile,
+	char * buffer,
+	size_t bufsize
+  )
+  {
+	return
+		fread(buffer, bufsize, 1, (FILE *)thefile);
+  } /*read_uncompressed*/
 
 char *XMLwrapper::doloadfile(const string &filename)
 {
     char *xmldata=NULL;
-    int filesize=-1;
+	size_t datasize = 0;
+    void * thefile;
+	ssize_t (*thefile_read)(void * thefile, char * buffer, size_t bufsize);
+	int (*thefile_close)(void * thefile);
+
+	thefile = gzopen(filename.c_str(),"rb");
+	if (thefile != NULL)
+	  {
+		thefile_read = read_compressed;
+		thefile_close = (int (*)(void *))gzclose;
+	  }
+	else
+	  {
+		thefile = fopen(filename.c_str(),"rb");
+        if (thefile==NULL) return(NULL);
+		thefile_read = read_uncompressed;
+		thefile_close = (int (*)(void *))fclose;
+	  } /*if*/
+	for (;;)
+	  {
+		const size_t increment = 1024; /* something convenient */
+		const size_t prevdatasize = datasize;
+		datasize += increment;
+		xmldata = (char *)realloc(xmldata, datasize + 1);
+		if (xmldata == NULL) return(NULL);
+		const ssize_t bytesread = thefile_read(thefile, xmldata + prevdatasize, increment);
+		if (bytesread < 0) return(NULL);
+		if (bytesread < increment)
+		  {
+			datasize = prevdatasize + bytesread;
+			xmldata = (char *)realloc(xmldata, datasize + 1); /* assume shrinking buffer won't fail! */
+			xmldata[datasize] = 0; /* terminating null */
+			break;
+		  } /*if*/
+	  } /*for*/
 
-    //try get filesize as gzip data (first)
-    gzFile gzfile=gzopen(filename.c_str(),"rb");
-    if (gzfile!=NULL) {//this is a gzip file
-        // first check it's size
-        while (!gzeof(gzfile)) {
-            gzseek (gzfile,1024*1024,SEEK_CUR);
-            if (gztell(gzfile)>10000000) {
-                gzclose(gzfile);
-                goto notgzip;//the file is too big
-            };
-        };
-        filesize=gztell(gzfile);
-
-        //rewind the file and load the data
-        xmldata=new char[filesize+1];
-        ZERO(xmldata,filesize+1);
-
-        gzrewind(gzfile);
-        gzread(gzfile,xmldata,filesize);
-
-        gzclose(gzfile);
-        return (xmldata);
-    } else {//this is not a gzip file
-notgzip:
-        FILE *file=fopen(filename.c_str(),"rb");
-        if (file==NULL) return(NULL);
-        fseek(file,0,SEEK_END);
-        filesize=ftell(file);
-
-        xmldata=new char [filesize+1];
-        ZERO(xmldata,filesize+1);
-
-        rewind(file);
-        fread(xmldata,filesize,1,file);
-
-        fclose(file);
-        return(xmldata);
-    };
+	thefile_close(thefile);
+	return(xmldata);
 };
 
 bool XMLwrapper::putXMLdata(const char *xmldata)

Reply via email to