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)