summaryrefslogtreecommitdiff
path: root/src/shared/zip.cpp
diff options
context:
space:
mode:
authorxolatile2025-08-04 22:53:42 +0200
committerxolatile2025-08-04 22:53:42 +0200
commitd309df4ce4d8ad0ed995a8e1c4267412a7782021 (patch)
tree999ca8d785ecc1681e5eb7538ce2e6a18d244fa5 /src/shared/zip.cpp
parent29d613d9cb65a0faa7e3f80e75bea0b6d910cb9a (diff)
downloadxolatile-badassbug-d309df4ce4d8ad0ed995a8e1c4267412a7782021.tar.xz
xolatile-badassbug-d309df4ce4d8ad0ed995a8e1c4267412a7782021.tar.zst
Bunch of small changes...
Diffstat (limited to 'src/shared/zip.cpp')
-rw-r--r--src/shared/zip.cpp994
1 files changed, 489 insertions, 505 deletions
diff --git a/src/shared/zip.cpp b/src/shared/zip.cpp
index 40a3e9c..83b2952 100644
--- a/src/shared/zip.cpp
+++ b/src/shared/zip.cpp
@@ -2,583 +2,567 @@
enum
{
- ZIP_LOCAL_FILE_SIGNATURE = 0x04034B50,
- ZIP_LOCAL_FILE_SIZE = 30,
- ZIP_FILE_SIGNATURE = 0x02014B50,
- ZIP_FILE_SIZE = 46,
- ZIP_DIRECTORY_SIGNATURE = 0x06054B50,
- ZIP_DIRECTORY_SIZE = 22
+ ZIP_LOCAL_FILE_SIGNATURE = 0x04034B50,
+ ZIP_LOCAL_FILE_SIZE = 30,
+ ZIP_FILE_SIGNATURE = 0x02014B50,
+ ZIP_FILE_SIZE = 46,
+ ZIP_DIRECTORY_SIGNATURE = 0x06054B50,
+ ZIP_DIRECTORY_SIZE = 22
};
struct ziplocalfileheader
{
- uint signature;
- ushort version, flags, compression, modtime, moddate;
- uint crc32, compressedsize, uncompressedsize;
- ushort namelength, extralength;
+ uint signature;
+ ushort version, flags, compression, modtime, moddate;
+ uint crc32, compressedsize, uncompressedsize;
+ ushort namelength, extralength;
};
struct zipfileheader
{
- uint signature;
- ushort version, needversion, flags, compression, modtime, moddate;
- uint crc32, compressedsize, uncompressedsize;
- ushort namelength, extralength, commentlength, disknumber, internalattribs;
- uint externalattribs, offset;
+ uint signature;
+ ushort version, needversion, flags, compression, modtime, moddate;
+ uint crc32, compressedsize, uncompressedsize;
+ ushort namelength, extralength, commentlength, disknumber, internalattribs;
+ uint externalattribs, offset;
};
struct zipdirectoryheader
{
- uint signature;
- ushort disknumber, directorydisk, diskentries, entries;
- uint size, offset;
- ushort commentlength;
+ uint signature;
+ ushort disknumber, directorydisk, diskentries, entries;
+ uint size, offset;
+ ushort commentlength;
};
struct zipfile
{
- char *name;
- uint header, offset, size, compressedsize;
-
- zipfile() : name(NULL), header(0), offset(~0U), size(0), compressedsize(0)
- {
- }
- ~zipfile()
- {
- DELETEA(name);
- }
+ char *name;
+ uint header, offset, size, compressedsize;
+
+ zipfile() : name(NULL), header(0), offset(~0U), size(0), compressedsize(0)
+ {
+ }
+ ~zipfile()
+ {
+ DELETEA(name);
+ }
};
struct zipstream;
struct ziparchive
{
- char *name;
- FILE *data;
- hashnameset<zipfile> files;
- int openfiles;
- zipstream *owner;
-
- ziparchive() : name(NULL), data(NULL), files(512), openfiles(0), owner(NULL)
- {
- }
- ~ziparchive()
- {
- DELETEA(name);
- if(data) { fclose(data); data = NULL; }
- }
+ char *name;
+ FILE *data;
+ hashnameset<zipfile> files;
+ int openfiles;
+ zipstream *owner;
+
+ ziparchive() : name(NULL), data(NULL), files(512), openfiles(0), owner(NULL)
+ {
+ }
+ ~ziparchive()
+ {
+ DELETEA(name);
+ if(data) { fclose(data); data = NULL; }
+ }
};
static bool findzipdirectory(FILE *f, zipdirectoryheader &hdr)
{
- if(fseek(f, 0, SEEK_END) < 0) return false;
-
- long offset = ftell(f);
- if(offset < 0) return false;
-
- uchar buf[1024], *src = NULL;
- long end = max(offset - 0xFFFFL - ZIP_DIRECTORY_SIZE, 0L);
- size_t len = 0;
- const uint signature = lilswap<uint>(ZIP_DIRECTORY_SIGNATURE);
-
- while(offset > end)
- {
- size_t carry = min(len, size_t(ZIP_DIRECTORY_SIZE-1)), next = min(sizeof(buf) - carry, size_t(offset - end));
- offset -= next;
- memmove(&buf[next], buf, carry);
- if(next + carry < ZIP_DIRECTORY_SIZE || fseek(f, offset, SEEK_SET) < 0 || fread(buf, 1, next, f) != next) return false;
- len = next + carry;
- uchar *search = &buf[next-1];
- for(; search >= buf; search--) if(*(uint *)search == signature) break;
- if(search >= buf) { src = search; break; }
- }
-
- if(!src || &buf[len] - src < ZIP_DIRECTORY_SIZE) return false;
-
- hdr.signature = lilswap(*(uint *)src); src += 4;
- hdr.disknumber = lilswap(*(ushort *)src); src += 2;
- hdr.directorydisk = lilswap(*(ushort *)src); src += 2;
- hdr.diskentries = lilswap(*(ushort *)src); src += 2;
- hdr.entries = lilswap(*(ushort *)src); src += 2;
- hdr.size = lilswap(*(uint *)src); src += 4;
- hdr.offset = lilswap(*(uint *)src); src += 4;
- hdr.commentlength = lilswap(*(ushort *)src); src += 2;
-
- if(hdr.signature != ZIP_DIRECTORY_SIGNATURE || hdr.disknumber != hdr.directorydisk || hdr.diskentries != hdr.entries) return false;
-
- return true;
+ if(fseek(f, 0, SEEK_END) < 0) return false;
+
+ long offset = ftell(f);
+ if(offset < 0) return false;
+
+ uchar buf[1024], *src = NULL;
+ long end = max(offset - 0xFFFFL - ZIP_DIRECTORY_SIZE, 0L);
+ size_t len = 0;
+ const uint signature = lilswap<uint>(ZIP_DIRECTORY_SIGNATURE);
+
+ while(offset > end)
+ {
+ size_t carry = min(len, size_t(ZIP_DIRECTORY_SIZE-1)), next = min(sizeof(buf) - carry, size_t(offset - end));
+ offset -= next;
+ memmove(&buf[next], buf, carry);
+ if(next + carry < ZIP_DIRECTORY_SIZE || fseek(f, offset, SEEK_SET) < 0 || fread(buf, 1, next, f) != next) return false;
+ len = next + carry;
+ uchar *search = &buf[next-1];
+ for(; search >= buf; search--) if(*(uint *)search == signature) break;
+ if(search >= buf) { src = search; break; }
+ }
+
+ if(!src || &buf[len] - src < ZIP_DIRECTORY_SIZE) return false;
+
+ hdr.signature = lilswap(*(uint *)src); src += 4;
+ hdr.disknumber = lilswap(*(ushort *)src); src += 2;
+ hdr.directorydisk = lilswap(*(ushort *)src); src += 2;
+ hdr.diskentries = lilswap(*(ushort *)src); src += 2;
+ hdr.entries = lilswap(*(ushort *)src); src += 2;
+ hdr.size = lilswap(*(uint *)src); src += 4;
+ hdr.offset = lilswap(*(uint *)src); src += 4;
+ hdr.commentlength = lilswap(*(ushort *)src); src += 2;
+
+ if(hdr.signature != ZIP_DIRECTORY_SIGNATURE || hdr.disknumber != hdr.directorydisk || hdr.diskentries != hdr.entries) return false;
+
+ return true;
}
-#ifndef STANDALONE
-VAR(dbgzip, 0, 0, 1);
-#endif
-
static bool readzipdirectory(const char *archname, FILE *f, int entries, int offset, uint size, vector<zipfile> &files)
{
- uchar *buf = new (false) uchar[size], *src = buf;
- if(!buf || fseek(f, offset, SEEK_SET) < 0 || fread(buf, 1, size, f) != size) { delete[] buf; return false; }
- loopi(entries)
- {
- if(src + ZIP_FILE_SIZE > &buf[size]) break;
-
- zipfileheader hdr;
- hdr.signature = lilswap(*(uint *)src); src += 4;
- hdr.version = lilswap(*(ushort *)src); src += 2;
- hdr.needversion = lilswap(*(ushort *)src); src += 2;
- hdr.flags = lilswap(*(ushort *)src); src += 2;
- hdr.compression = lilswap(*(ushort *)src); src += 2;
- hdr.modtime = lilswap(*(ushort *)src); src += 2;
- hdr.moddate = lilswap(*(ushort *)src); src += 2;
- hdr.crc32 = lilswap(*(uint *)src); src += 4;
- hdr.compressedsize = lilswap(*(uint *)src); src += 4;
- hdr.uncompressedsize = lilswap(*(uint *)src); src += 4;
- hdr.namelength = lilswap(*(ushort *)src); src += 2;
- hdr.extralength = lilswap(*(ushort *)src); src += 2;
- hdr.commentlength = lilswap(*(ushort *)src); src += 2;
- hdr.disknumber = lilswap(*(ushort *)src); src += 2;
- hdr.internalattribs = lilswap(*(ushort *)src); src += 2;
- hdr.externalattribs = lilswap(*(uint *)src); src += 4;
- hdr.offset = lilswap(*(uint *)src); src += 4;
- if(hdr.signature != ZIP_FILE_SIGNATURE) break;
- if(!hdr.namelength || !hdr.uncompressedsize || (hdr.compression && (hdr.compression != Z_DEFLATED || !hdr.compressedsize)))
- {
- src += hdr.namelength + hdr.extralength + hdr.commentlength;
- continue;
- }
- if(src + hdr.namelength > &buf[size]) break;
-
- string pname;
- int namelen = min((int)hdr.namelength, (int)sizeof(pname)-1);
- memcpy(pname, src, namelen);
- pname[namelen] = '\0';
- path(pname);
- char *name = newstring(pname);
-
- zipfile &f = files.add();
- f.name = name;
- f.header = hdr.offset;
- f.size = hdr.uncompressedsize;
- f.compressedsize = hdr.compression ? hdr.compressedsize : 0;
-#ifndef STANDALONE
- if(dbgzip) conoutf(CON_DEBUG, "%s: file %s, size %d, compress %d, flags %x", archname, name, hdr.uncompressedsize, hdr.compression, hdr.flags);
-#endif
-
- src += hdr.namelength + hdr.extralength + hdr.commentlength;
- }
- delete[] buf;
-
- return files.length() > 0;
+ uchar *buf = new (false) uchar[size], *src = buf;
+ if(!buf || fseek(f, offset, SEEK_SET) < 0 || fread(buf, 1, size, f) != size) { delete[] buf; return false; }
+ loopi(entries)
+ {
+ if(src + ZIP_FILE_SIZE > &buf[size]) break;
+
+ zipfileheader hdr;
+ hdr.signature = lilswap(*(uint *)src); src += 4;
+ hdr.version = lilswap(*(ushort *)src); src += 2;
+ hdr.needversion = lilswap(*(ushort *)src); src += 2;
+ hdr.flags = lilswap(*(ushort *)src); src += 2;
+ hdr.compression = lilswap(*(ushort *)src); src += 2;
+ hdr.modtime = lilswap(*(ushort *)src); src += 2;
+ hdr.moddate = lilswap(*(ushort *)src); src += 2;
+ hdr.crc32 = lilswap(*(uint *)src); src += 4;
+ hdr.compressedsize = lilswap(*(uint *)src); src += 4;
+ hdr.uncompressedsize = lilswap(*(uint *)src); src += 4;
+ hdr.namelength = lilswap(*(ushort *)src); src += 2;
+ hdr.extralength = lilswap(*(ushort *)src); src += 2;
+ hdr.commentlength = lilswap(*(ushort *)src); src += 2;
+ hdr.disknumber = lilswap(*(ushort *)src); src += 2;
+ hdr.internalattribs = lilswap(*(ushort *)src); src += 2;
+ hdr.externalattribs = lilswap(*(uint *)src); src += 4;
+ hdr.offset = lilswap(*(uint *)src); src += 4;
+ if(hdr.signature != ZIP_FILE_SIGNATURE) break;
+ if(!hdr.namelength || !hdr.uncompressedsize || (hdr.compression && (hdr.compression != Z_DEFLATED || !hdr.compressedsize)))
+ {
+ src += hdr.namelength + hdr.extralength + hdr.commentlength;
+ continue;
+ }
+ if(src + hdr.namelength > &buf[size]) break;
+
+ string pname;
+ int namelen = min((int)hdr.namelength, (int)sizeof(pname)-1);
+ memcpy(pname, src, namelen);
+ pname[namelen] = '\0';
+ path(pname);
+ char *name = newstring(pname);
+
+ zipfile &f = files.add();
+ f.name = name;
+ f.header = hdr.offset;
+ f.size = hdr.uncompressedsize;
+ f.compressedsize = hdr.compression ? hdr.compressedsize : 0;
+
+ src += hdr.namelength + hdr.extralength + hdr.commentlength;
+ }
+ delete[] buf;
+
+ return files.length() > 0;
}
static bool readlocalfileheader(FILE *f, ziplocalfileheader &h, uint offset)
{
- uchar buf[ZIP_LOCAL_FILE_SIZE];
- if(fseek(f, offset, SEEK_SET) < 0 || fread(buf, 1, ZIP_LOCAL_FILE_SIZE, f) != ZIP_LOCAL_FILE_SIZE)
- return false;
- uchar *src = buf;
- h.signature = lilswap(*(uint *)src); src += 4;
- h.version = lilswap(*(ushort *)src); src += 2;
- h.flags = lilswap(*(ushort *)src); src += 2;
- h.compression = lilswap(*(ushort *)src); src += 2;
- h.modtime = lilswap(*(ushort *)src); src += 2;
- h.moddate = lilswap(*(ushort *)src); src += 2;
- h.crc32 = lilswap(*(uint *)src); src += 4;
- h.compressedsize = lilswap(*(uint *)src); src += 4;
- h.uncompressedsize = lilswap(*(uint *)src); src += 4;
- h.namelength = lilswap(*(ushort *)src); src += 2;
- h.extralength = lilswap(*(ushort *)src); src += 2;
- if(h.signature != ZIP_LOCAL_FILE_SIGNATURE) return false;
- // h.uncompressedsize or h.compressedsize may be zero - so don't validate
- return true;
+ uchar buf[ZIP_LOCAL_FILE_SIZE];
+ if(fseek(f, offset, SEEK_SET) < 0 || fread(buf, 1, ZIP_LOCAL_FILE_SIZE, f) != ZIP_LOCAL_FILE_SIZE)
+ return false;
+ uchar *src = buf;
+ h.signature = lilswap(*(uint *)src); src += 4;
+ h.version = lilswap(*(ushort *)src); src += 2;
+ h.flags = lilswap(*(ushort *)src); src += 2;
+ h.compression = lilswap(*(ushort *)src); src += 2;
+ h.modtime = lilswap(*(ushort *)src); src += 2;
+ h.moddate = lilswap(*(ushort *)src); src += 2;
+ h.crc32 = lilswap(*(uint *)src); src += 4;
+ h.compressedsize = lilswap(*(uint *)src); src += 4;
+ h.uncompressedsize = lilswap(*(uint *)src); src += 4;
+ h.namelength = lilswap(*(ushort *)src); src += 2;
+ h.extralength = lilswap(*(ushort *)src); src += 2;
+ if(h.signature != ZIP_LOCAL_FILE_SIGNATURE) return false;
+ // h.uncompressedsize or h.compressedsize may be zero - so don't validate
+ return true;
}
static vector<ziparchive *> archives;
ziparchive *findzip(const char *name)
{
- loopv(archives) if(!strcmp(name, archives[i]->name)) return archives[i];
- return NULL;
+ loopv(archives) if(!strcmp(name, archives[i]->name)) return archives[i];
+ return NULL;
}
static bool checkprefix(vector<zipfile> &files, const char *prefix, int prefixlen)
{
- loopv(files)
- {
- if(!strncmp(files[i].name, prefix, prefixlen)) return false;
- }
- return true;
+ loopv(files)
+ {
+ if(!strncmp(files[i].name, prefix, prefixlen)) return false;
+ }
+ return true;
}
static void mountzip(ziparchive &arch, vector<zipfile> &files, const char *mountdir, const char *stripdir)
{
- string packagesdir = "packages/";
- path(packagesdir);
- size_t striplen = stripdir ? strlen(stripdir) : 0;
- if(!mountdir && !stripdir) loopv(files)
- {
- zipfile &f = files[i];
- const char *foundpackages = strstr(f.name, packagesdir);
- if(foundpackages)
- {
- if(foundpackages > f.name)
- {
- stripdir = f.name;
- striplen = foundpackages - f.name;
- }
- break;
- }
- const char *foundogz = strstr(f.name, ".ogz");
- if(foundogz)
- {
- const char *ogzdir = foundogz;
- while(--ogzdir >= f.name && *ogzdir != PATHDIV);
- if(ogzdir < f.name || checkprefix(files, f.name, ogzdir + 1 - f.name))
- {
- if(ogzdir >= f.name)
- {
- stripdir = f.name;
- striplen = ogzdir + 1 - f.name;
- }
- if(!mountdir) mountdir = "packages/maps/";
- break;
- }
- }
- }
- string mdir = "", fname;
- if(mountdir)
- {
- copystring(mdir, mountdir);
- if(fixpackagedir(mdir) <= 1) mdir[0] = '\0';
- }
- loopv(files)
- {
- zipfile &f = files[i];
- formatstring(fname, "%s%s", mdir, striplen && !strncmp(f.name, stripdir, striplen) ? &f.name[striplen] : f.name);
- if(arch.files.access(fname)) continue;
- char *mname = newstring(fname);
- zipfile &mf = arch.files[mname];
- mf = f;
- mf.name = mname;
- }
+ string packagesdir = "packages/";
+ path(packagesdir);
+ size_t striplen = stripdir ? strlen(stripdir) : 0;
+ if(!mountdir && !stripdir) loopv(files)
+ {
+ zipfile &f = files[i];
+ const char *foundpackages = strstr(f.name, packagesdir);
+ if(foundpackages)
+ {
+ if(foundpackages > f.name)
+ {
+ stripdir = f.name;
+ striplen = foundpackages - f.name;
+ }
+ break;
+ }
+ const char *foundogz = strstr(f.name, ".ogz");
+ if(foundogz)
+ {
+ const char *ogzdir = foundogz;
+ while(--ogzdir >= f.name && *ogzdir != PATHDIV);
+ if(ogzdir < f.name || checkprefix(files, f.name, ogzdir + 1 - f.name))
+ {
+ if(ogzdir >= f.name)
+ {
+ stripdir = f.name;
+ striplen = ogzdir + 1 - f.name;
+ }
+ if(!mountdir) mountdir = "packages/maps/";
+ break;
+ }
+ }
+ }
+ string mdir = "", fname;
+ if(mountdir)
+ {
+ copystring(mdir, mountdir);
+ if(fixpackagedir(mdir) <= 1) mdir[0] = '\0';
+ }
+ loopv(files)
+ {
+ zipfile &f = files[i];
+ formatstring(fname, "%s%s", mdir, striplen && !strncmp(f.name, stripdir, striplen) ? &f.name[striplen] : f.name);
+ if(arch.files.access(fname)) continue;
+ char *mname = newstring(fname);
+ zipfile &mf = arch.files[mname];
+ mf = f;
+ mf.name = mname;
+ }
}
bool addzip(const char *name, const char *mount = NULL, const char *strip = NULL)
{
- string pname;
- copystring(pname, name);
- path(pname);
- size_t plen = strlen(pname);
- if(plen < 4 || !strchr(&pname[plen-4], '.')) concatstring(pname, ".zip");
-
- ziparchive *exists = findzip(pname);
- if(exists)
- {
- conoutf(CON_ERROR, "already added zip %s", pname);
- return true;
- }
-
- FILE *f = fopen(findfile(pname, "rb"), "rb");
- if(!f)
- {
- conoutf(CON_ERROR, "could not open file %s", pname);
- return false;
- }
- zipdirectoryheader h;
- vector<zipfile> files;
- if(!findzipdirectory(f, h) || !readzipdirectory(pname, f, h.entries, h.offset, h.size, files))
- {
- conoutf(CON_ERROR, "could not read directory in zip %s", pname);
- fclose(f);
- return false;
- }
-
- ziparchive *arch = new ziparchive;
- arch->name = newstring(pname);
- arch->data = f;
- mountzip(*arch, files, mount, strip);
- archives.add(arch);
-
- conoutf("added zip %s", pname);
- return true;
+ string pname;
+ copystring(pname, name);
+ path(pname);
+ size_t plen = strlen(pname);
+ if(plen < 4 || !strchr(&pname[plen-4], '.')) concatstring(pname, ".zip");
+
+ ziparchive *exists = findzip(pname);
+ if(exists)
+ {
+ conoutf(CON_ERROR, "already added zip %s", pname);
+ return true;
+ }
+
+ FILE *f = fopen(findfile(pname, "rb"), "rb");
+ if(!f)
+ {
+ conoutf(CON_ERROR, "could not open file %s", pname);
+ return false;
+ }
+ zipdirectoryheader h;
+ vector<zipfile> files;
+ if(!findzipdirectory(f, h) || !readzipdirectory(pname, f, h.entries, h.offset, h.size, files))
+ {
+ conoutf(CON_ERROR, "could not read directory in zip %s", pname);
+ fclose(f);
+ return false;
+ }
+
+ ziparchive *arch = new ziparchive;
+ arch->name = newstring(pname);
+ arch->data = f;
+ mountzip(*arch, files, mount, strip);
+ archives.add(arch);
+
+ conoutf("added zip %s", pname);
+ return true;
}
bool removezip(const char *name)
{
- string pname;
- copystring(pname, name);
- path(pname);
- int plen = (int)strlen(pname);
- if(plen < 4 || !strchr(&pname[plen-4], '.')) concatstring(pname, ".zip");
- ziparchive *exists = findzip(pname);
- if(!exists)
- {
- conoutf(CON_ERROR, "zip %s is not loaded", pname);
- return false;
- }
- if(exists->openfiles)
- {
- conoutf(CON_ERROR, "zip %s has open files", pname);
- return false;
- }
- conoutf("removed zip %s", exists->name);
- archives.removeobj(exists);
- delete exists;
- return true;
+ string pname;
+ copystring(pname, name);
+ path(pname);
+ int plen = (int)strlen(pname);
+ if(plen < 4 || !strchr(&pname[plen-4], '.')) concatstring(pname, ".zip");
+ ziparchive *exists = findzip(pname);
+ if(!exists)
+ {
+ conoutf(CON_ERROR, "zip %s is not loaded", pname);
+ return false;
+ }
+ if(exists->openfiles)
+ {
+ conoutf(CON_ERROR, "zip %s has open files", pname);
+ return false;
+ }
+ conoutf("removed zip %s", exists->name);
+ archives.removeobj(exists);
+ delete exists;
+ return true;
}
struct zipstream : stream
{
- enum
- {
- BUFSIZE = 16384
- };
-
- ziparchive *arch;
- zipfile *info;
- z_stream zfile;
- uchar *buf;
- uint reading;
- bool ended;
-
- zipstream() : arch(NULL), info(NULL), buf(NULL), reading(~0U), ended(false)
- {
- zfile.zalloc = NULL;
- zfile.zfree = NULL;
- zfile.opaque = NULL;
- zfile.next_in = zfile.next_out = NULL;
- zfile.avail_in = zfile.avail_out = 0;
- }
-
- ~zipstream()
- {
- close();
- }
-
- void readbuf(uint size = BUFSIZE)
- {
- if(!zfile.avail_in) zfile.next_in = (Bytef *)buf;
- size = min(size, uint(&buf[BUFSIZE] - &zfile.next_in[zfile.avail_in]));
- if(arch->owner != this)
- {
- arch->owner = NULL;
- if(fseek(arch->data, reading, SEEK_SET) >= 0) arch->owner = this;
- else return;
- }
- uint remaining = info->offset + info->compressedsize - reading,
- n = arch->owner == this ? fread(zfile.next_in + zfile.avail_in, 1, min(size, remaining), arch->data) : 0U;
- zfile.avail_in += n;
- reading += n;
- }
-
- bool open(ziparchive *a, zipfile *f)
- {
- if(f->offset == ~0U)
- {
- ziplocalfileheader h;
- a->owner = NULL;
- if(!readlocalfileheader(a->data, h, f->header)) return false;
- f->offset = f->header + ZIP_LOCAL_FILE_SIZE + h.namelength + h.extralength;
- }
-
- if(f->compressedsize && inflateInit2(&zfile, -MAX_WBITS) != Z_OK) return false;
-
- a->openfiles++;
- arch = a;
- info = f;
- reading = f->offset;
- ended = false;
- if(f->compressedsize) buf = new uchar[BUFSIZE];
- return true;
- }
-
- void stopreading()
- {
- if(reading == ~0U) return;
-#ifndef STANDALONE
- if(dbgzip) conoutf(CON_DEBUG, info->compressedsize ? "%s: zfile.total_out %u, info->size %u" : "%s: reading %u, info->size %u", info->name, info->compressedsize ? uint(zfile.total_out) : reading - info->offset, info->size);
-#endif
- if(info->compressedsize) inflateEnd(&zfile);
- reading = ~0U;
- }
-
- void close()
- {
- stopreading();
- DELETEA(buf);
- if(arch) { arch->owner = NULL; arch->openfiles--; arch = NULL; }
- }
-
- offset size() { return info->size; }
- bool end() { return reading == ~0U || ended; }
- offset tell() { return reading != ~0U ? (info->compressedsize ? zfile.total_out : reading - info->offset) : offset(-1); }
-
- bool seek(offset pos, int whence)
- {
- if(reading == ~0U) return false;
- if(!info->compressedsize)
- {
- switch(whence)
- {
- case SEEK_END: pos += info->offset + info->size; break;
- case SEEK_CUR: pos += reading; break;
- case SEEK_SET: pos += info->offset; break;
- default: return false;
- }
- pos = clamp(pos, offset(info->offset), offset(info->offset + info->size));
- arch->owner = NULL;
- if(fseek(arch->data, int(pos), SEEK_SET) < 0) return false;
- arch->owner = this;
- reading = pos;
- ended = false;
- return true;
- }
-
- switch(whence)
- {
- case SEEK_END: pos += info->size; break;
- case SEEK_CUR: pos += zfile.total_out; break;
- case SEEK_SET: break;
- default: return false;
- }
-
- if(pos >= (offset)info->size)
- {
- reading = info->offset + info->compressedsize;
- zfile.next_in += zfile.avail_in;
- zfile.avail_in = 0;
- zfile.total_in = info->compressedsize;
- zfile.total_out = info->size;
- arch->owner = NULL;
- ended = false;
- return true;
- }
-
- if(pos < 0) return false;
- if(pos >= (offset)zfile.total_out) pos -= zfile.total_out;
- else
- {
- if(zfile.next_in && zfile.total_in <= uint(zfile.next_in - buf))
- {
- zfile.avail_in += zfile.total_in;
- zfile.next_in -= zfile.total_in;
- }
- else
- {
- arch->owner = NULL;
- zfile.avail_in = 0;
- zfile.next_in = NULL;
- reading = info->offset;
- }
- inflateReset(&zfile);
- }
-
- uchar skip[512];
- while(pos > 0)
- {
- size_t skipped = (size_t)min(pos, (offset)sizeof(skip));
- if(read(skip, skipped) != skipped) return false;
- pos -= skipped;
- }
-
- ended = false;
- return true;
- }
-
- size_t read(void *buf, size_t len)
- {
- if(reading == ~0U || !buf || !len) return 0;
- if(!info->compressedsize)
- {
- if(arch->owner != this)
- {
- arch->owner = NULL;
- if(fseek(arch->data, reading, SEEK_SET) < 0) { stopreading(); return 0; }
- arch->owner = this;
- }
-
- size_t n = fread(buf, 1, min(len, size_t(info->size + info->offset - reading)), arch->data);
- reading += n;
- if(n < len) ended = true;
- return n;
- }
-
- zfile.next_out = (Bytef *)buf;
- zfile.avail_out = len;
- while(zfile.avail_out > 0)
- {
- if(!zfile.avail_in) readbuf(BUFSIZE);
- int err = inflate(&zfile, Z_NO_FLUSH);
- if(err != Z_OK)
- {
- if(err == Z_STREAM_END) ended = true;
- else
- {
-#ifndef STANDALONE
- if(dbgzip) conoutf(CON_DEBUG, "inflate error: %s", zError(err));
-#endif
- stopreading();
- }
- break;
- }
- }
- return len - zfile.avail_out;
- }
+ enum
+ {
+ BUFSIZE = 16384
+ };
+
+ ziparchive *arch;
+ zipfile *info;
+ z_stream zfile;
+ uchar *buf;
+ uint reading;
+ bool ended;
+
+ zipstream() : arch(NULL), info(NULL), buf(NULL), reading(~0U), ended(false)
+ {
+ zfile.zalloc = NULL;
+ zfile.zfree = NULL;
+ zfile.opaque = NULL;
+ zfile.next_in = zfile.next_out = NULL;
+ zfile.avail_in = zfile.avail_out = 0;
+ }
+
+ ~zipstream()
+ {
+ close();
+ }
+
+ void readbuf(uint size = BUFSIZE)
+ {
+ if(!zfile.avail_in) zfile.next_in = (Bytef *)buf;
+ size = min(size, uint(&buf[BUFSIZE] - &zfile.next_in[zfile.avail_in]));
+ if(arch->owner != this)
+ {
+ arch->owner = NULL;
+ if(fseek(arch->data, reading, SEEK_SET) >= 0) arch->owner = this;
+ else return;
+ }
+ uint remaining = info->offset + info->compressedsize - reading,
+ n = arch->owner == this ? fread(zfile.next_in + zfile.avail_in, 1, min(size, remaining), arch->data) : 0U;
+ zfile.avail_in += n;
+ reading += n;
+ }
+
+ bool open(ziparchive *a, zipfile *f)
+ {
+ if(f->offset == ~0U)
+ {
+ ziplocalfileheader h;
+ a->owner = NULL;
+ if(!readlocalfileheader(a->data, h, f->header)) return false;
+ f->offset = f->header + ZIP_LOCAL_FILE_SIZE + h.namelength + h.extralength;
+ }
+
+ if(f->compressedsize && inflateInit2(&zfile, -MAX_WBITS) != Z_OK) return false;
+
+ a->openfiles++;
+ arch = a;
+ info = f;
+ reading = f->offset;
+ ended = false;
+ if(f->compressedsize) buf = new uchar[BUFSIZE];
+ return true;
+ }
+
+ void stopreading()
+ {
+ if(reading == ~0U) return;
+ if(info->compressedsize) inflateEnd(&zfile);
+ reading = ~0U;
+ }
+
+ void close()
+ {
+ stopreading();
+ DELETEA(buf);
+ if(arch) { arch->owner = NULL; arch->openfiles--; arch = NULL; }
+ }
+
+ offset size() { return info->size; }
+ bool end() { return reading == ~0U || ended; }
+ offset tell() { return reading != ~0U ? (info->compressedsize ? zfile.total_out : reading - info->offset) : offset(-1); }
+
+ bool seek(offset pos, int whence)
+ {
+ if(reading == ~0U) return false;
+ if(!info->compressedsize)
+ {
+ switch(whence)
+ {
+ case SEEK_END: pos += info->offset + info->size; break;
+ case SEEK_CUR: pos += reading; break;
+ case SEEK_SET: pos += info->offset; break;
+ default: return false;
+ }
+ pos = clamp(pos, offset(info->offset), offset(info->offset + info->size));
+ arch->owner = NULL;
+ if(fseek(arch->data, int(pos), SEEK_SET) < 0) return false;
+ arch->owner = this;
+ reading = pos;
+ ended = false;
+ return true;
+ }
+
+ switch(whence)
+ {
+ case SEEK_END: pos += info->size; break;
+ case SEEK_CUR: pos += zfile.total_out; break;
+ case SEEK_SET: break;
+ default: return false;
+ }
+
+ if(pos >= (offset)info->size)
+ {
+ reading = info->offset + info->compressedsize;
+ zfile.next_in += zfile.avail_in;
+ zfile.avail_in = 0;
+ zfile.total_in = info->compressedsize;
+ zfile.total_out = info->size;
+ arch->owner = NULL;
+ ended = false;
+ return true;
+ }
+
+ if(pos < 0) return false;
+ if(pos >= (offset)zfile.total_out) pos -= zfile.total_out;
+ else
+ {
+ if(zfile.next_in && zfile.total_in <= uint(zfile.next_in - buf))
+ {
+ zfile.avail_in += zfile.total_in;
+ zfile.next_in -= zfile.total_in;
+ }
+ else
+ {
+ arch->owner = NULL;
+ zfile.avail_in = 0;
+ zfile.next_in = NULL;
+ reading = info->offset;
+ }
+ inflateReset(&zfile);
+ }
+
+ uchar skip[512];
+ while(pos > 0)
+ {
+ size_t skipped = (size_t)min(pos, (offset)sizeof(skip));
+ if(read(skip, skipped) != skipped) return false;
+ pos -= skipped;
+ }
+
+ ended = false;
+ return true;
+ }
+
+ size_t read(void *buf, size_t len)
+ {
+ if(reading == ~0U || !buf || !len) return 0;
+ if(!info->compressedsize)
+ {
+ if(arch->owner != this)
+ {
+ arch->owner = NULL;
+ if(fseek(arch->data, reading, SEEK_SET) < 0) { stopreading(); return 0; }
+ arch->owner = this;
+ }
+
+ size_t n = fread(buf, 1, min(len, size_t(info->size + info->offset - reading)), arch->data);
+ reading += n;
+ if(n < len) ended = true;
+ return n;
+ }
+
+ zfile.next_out = (Bytef *)buf;
+ zfile.avail_out = len;
+ while(zfile.avail_out > 0)
+ {
+ if(!zfile.avail_in) readbuf(BUFSIZE);
+ int err = inflate(&zfile, Z_NO_FLUSH);
+ if(err != Z_OK)
+ {
+ if(err == Z_STREAM_END) ended = true;
+ else stopreading();
+ break;
+ }
+ }
+ return len - zfile.avail_out;
+ }
};
stream *openzipfile(const char *name, const char *mode)
{
- for(; *mode; mode++) if(*mode=='w' || *mode=='a') return NULL;
- loopvrev(archives)
- {
- ziparchive *arch = archives[i];
- zipfile *f = arch->files.access(name);
- if(!f) continue;
- zipstream *s = new zipstream;
- if(s->open(arch, f)) return s;
- delete s;
- }
- return NULL;
+ for(; *mode; mode++) if(*mode=='w' || *mode=='a') return NULL;
+ loopvrev(archives)
+ {
+ ziparchive *arch = archives[i];
+ zipfile *f = arch->files.access(name);
+ if(!f) continue;
+ zipstream *s = new zipstream;
+ if(s->open(arch, f)) return s;
+ delete s;
+ }
+ return NULL;
}
bool findzipfile(const char *name)
{
- loopvrev(archives)
- {
- ziparchive *arch = archives[i];
- if(arch->files.access(name)) return true;
- }
- return false;
+ loopvrev(archives)
+ {
+ ziparchive *arch = archives[i];
+ if(arch->files.access(name)) return true;
+ }
+ return false;
}
int listzipfiles(const char *dir, const char *ext, vector<char *> &files)
{
- size_t extsize = ext ? strlen(ext)+1 : 0, dirsize = strlen(dir);
- int dirs = 0;
- loopvrev(archives)
- {
- ziparchive *arch = archives[i];
- int oldsize = files.length();
- enumerate(arch->files, zipfile, f,
- {
- if(strncmp(f.name, dir, dirsize)) continue;
- const char *name = f.name + dirsize;
- if(name[0] == PATHDIV) name++;
- if(strchr(name, PATHDIV)) continue;
- if(!ext) files.add(newstring(name));
- else
- {
- size_t namelen = strlen(name);
- if(namelen > extsize)
- {
- namelen -= extsize;
- if(name[namelen] == '.' && strncmp(name+namelen+1, ext, extsize-1)==0)
- files.add(newstring(name, namelen));
- }
- }
- });
- if(files.length() > oldsize) dirs++;
- }
- return dirs;
+ size_t extsize = ext ? strlen(ext)+1 : 0, dirsize = strlen(dir);
+ int dirs = 0;
+ loopvrev(archives)
+ {
+ ziparchive *arch = archives[i];
+ int oldsize = files.length();
+ enumerate(arch->files, zipfile, f,
+ {
+ if(strncmp(f.name, dir, dirsize)) continue;
+ const char *name = f.name + dirsize;
+ if(name[0] == PATHDIV) name++;
+ if(strchr(name, PATHDIV)) continue;
+ if(!ext) files.add(newstring(name));
+ else
+ {
+ size_t namelen = strlen(name);
+ if(namelen > extsize)
+ {
+ namelen -= extsize;
+ if(name[namelen] == '.' && strncmp(name+namelen+1, ext, extsize-1)==0)
+ files.add(newstring(name, namelen));
+ }
+ }
+ });
+ if(files.length() > oldsize) dirs++;
+ }
+ return dirs;
}
#ifndef STANDALONE