From 0a1172b75f571685c264a8b9d8ee224bbf11381f Mon Sep 17 00:00:00 2001 From: xolatile Date: Wed, 6 Aug 2025 22:54:55 +0200 Subject: Please do not hate me, it makes sense... --- src/shared/zip.cpp | 241 +++++++++++++++-------------------------------------- 1 file changed, 68 insertions(+), 173 deletions(-) (limited to 'src/shared/zip.cpp') diff --git a/src/shared/zip.cpp b/src/shared/zip.cpp index 83b2952..c60ea16 100644 --- a/src/shared/zip.cpp +++ b/src/shared/zip.cpp @@ -1,7 +1,6 @@ #include "cube.h" -enum -{ +enum { ZIP_LOCAL_FILE_SIGNATURE = 0x04034B50, ZIP_LOCAL_FILE_SIZE = 30, ZIP_FILE_SIGNATURE = 0x02014B50, @@ -10,16 +9,14 @@ enum ZIP_DIRECTORY_SIZE = 22 }; -struct ziplocalfileheader -{ +struct ziplocalfileheader { uint signature; ushort version, flags, compression, modtime, moddate; uint crc32, compressedsize, uncompressedsize; ushort namelength, extralength; }; -struct zipfileheader -{ +struct zipfileheader { uint signature; ushort version, needversion, flags, compression, modtime, moddate; uint crc32, compressedsize, uncompressedsize; @@ -27,62 +24,48 @@ struct zipfileheader uint externalattribs, offset; }; -struct zipdirectoryheader -{ +struct zipdirectoryheader { uint signature; ushort disknumber, directorydisk, diskentries, entries; uint size, offset; ushort commentlength; }; -struct zipfile -{ +struct zipfile { char *name; uint header, offset, size, compressedsize; - - zipfile() : name(NULL), header(0), offset(~0U), size(0), compressedsize(0) - { + zipfile() : name(NULL), header(0), offset(~0U), size(0), compressedsize(0) { } - ~zipfile() - { + ~zipfile() { DELETEA(name); } }; struct zipstream; -struct ziparchive -{ +struct ziparchive { char *name; FILE *data; hashnameset files; int openfiles; zipstream *owner; - - ziparchive() : name(NULL), data(NULL), files(512), openfiles(0), owner(NULL) - { + ziparchive() : name(NULL), data(NULL), files(512), openfiles(0), owner(NULL) { } - ~ziparchive() - { + ~ziparchive() { DELETEA(name); if(data) { fclose(data); data = NULL; } } }; -static bool findzipdirectory(FILE *f, zipdirectoryheader &hdr) -{ +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(ZIP_DIRECTORY_SIGNATURE); - - while(offset > end) - { + 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); @@ -92,9 +75,7 @@ static bool findzipdirectory(FILE *f, zipdirectoryheader &hdr) 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; @@ -103,20 +84,15 @@ static bool findzipdirectory(FILE *f, zipdirectoryheader &hdr) 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; } -static bool readzipdirectory(const char *archname, FILE *f, int entries, int offset, uint size, vector &files) -{ +static bool readzipdirectory(const char *archname, FILE *f, int entries, int offset, uint size, vector &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) - { + 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; @@ -136,35 +112,29 @@ static bool readzipdirectory(const char *archname, FILE *f, int entries, int off 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))) - { + 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) -{ +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; @@ -187,48 +157,38 @@ static bool readlocalfileheader(FILE *f, ziplocalfileheader &h, uint offset) static vector archives; -ziparchive *findzip(const char *name) -{ +ziparchive *findzip(const char *name) { loopv(archives) if(!strcmp(name, archives[i]->name)) return archives[i]; return NULL; } -static bool checkprefix(vector &files, const char *prefix, int prefixlen) -{ - loopv(files) - { +static bool checkprefix(vector &files, const char *prefix, int prefixlen) { + loopv(files) { if(!strncmp(files[i].name, prefix, prefixlen)) return false; } return true; } -static void mountzip(ziparchive &arch, vector &files, const char *mountdir, const char *stripdir) -{ +static void mountzip(ziparchive &arch, vector &files, const char *mountdir, const char *stripdir) { string packagesdir = "packages/"; path(packagesdir); size_t striplen = stripdir ? strlen(stripdir) : 0; - if(!mountdir && !stripdir) loopv(files) - { + if(!mountdir && !stripdir) loopv(files) { zipfile &f = files[i]; const char *foundpackages = strstr(f.name, packagesdir); - if(foundpackages) - { - if(foundpackages > f.name) - { + if(foundpackages) { + if(foundpackages > f.name) { stripdir = f.name; striplen = foundpackages - f.name; } break; } const char *foundogz = strstr(f.name, ".ogz"); - if(foundogz) - { + 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) - { + if(ogzdir < f.name || checkprefix(files, f.name, ogzdir + 1 - f.name)) { + if(ogzdir >= f.name) { stripdir = f.name; striplen = ogzdir + 1 - f.name; } @@ -238,13 +198,11 @@ static void mountzip(ziparchive &arch, vector &files, const char *mount } } string mdir = "", fname; - if(mountdir) - { + if(mountdir) { copystring(mdir, mountdir); if(fixpackagedir(mdir) <= 1) mdir[0] = '\0'; } - loopv(files) - { + 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; @@ -255,61 +213,50 @@ static void mountzip(ziparchive &arch, vector &files, const char *mount } } -bool addzip(const char *name, const char *mount = NULL, const char *strip = NULL) -{ +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) - { + if(exists) { conoutf(CON_ERROR, "already added zip %s", pname); return true; } - FILE *f = fopen(findfile(pname, "rb"), "rb"); - if(!f) - { + if(!f) { conoutf(CON_ERROR, "could not open file %s", pname); return false; } zipdirectoryheader h; vector files; - if(!findzipdirectory(f, h) || !readzipdirectory(pname, f, h.entries, h.offset, h.size, 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) -{ +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) - { + if(!exists) { conoutf(CON_ERROR, "zip %s is not loaded", pname); return false; } - if(exists->openfiles) - { + if(exists->openfiles) { conoutf(CON_ERROR, "zip %s has open files", pname); return false; } @@ -319,40 +266,30 @@ bool removezip(const char *name) return true; } -struct zipstream : stream -{ - enum - { +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) - { + 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() - { + ~zipstream() { close(); } - - void readbuf(uint size = BUFSIZE) - { + 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) - { + if(arch->owner != this) { arch->owner = NULL; if(fseek(arch->data, reading, SEEK_SET) >= 0) arch->owner = this; else return; @@ -362,19 +299,14 @@ struct zipstream : stream zfile.avail_in += n; reading += n; } - - bool open(ziparchive *a, zipfile *f) - { - if(f->offset == ~0U) - { + 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; @@ -383,32 +315,23 @@ struct zipstream : stream if(f->compressedsize) buf = new uchar[BUFSIZE]; return true; } - - void stopreading() - { + void stopreading() { if(reading == ~0U) return; if(info->compressedsize) inflateEnd(&zfile); reading = ~0U; } - - void close() - { + 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) - { + bool seek(offset pos, int whence) { if(reading == ~0U) return false; - if(!info->compressedsize) - { - switch(whence) - { + 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; @@ -422,17 +345,13 @@ struct zipstream : stream ended = false; return true; } - - switch(whence) - { + 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) - { + if(pos >= (offset)info->size) { reading = info->offset + info->compressedsize; zfile.next_in += zfile.avail_in; zfile.avail_in = 0; @@ -442,18 +361,14 @@ struct zipstream : stream 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)) - { + 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 - { + else { arch->owner = NULL; zfile.avail_in = 0; zfile.next_in = NULL; @@ -461,45 +376,34 @@ struct zipstream : stream } inflateReset(&zfile); } - uchar skip[512]; - while(pos > 0) - { + 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) - { + size_t read(void *buf, size_t len) { if(reading == ~0U || !buf || !len) return 0; - if(!info->compressedsize) - { - if(arch->owner != this) - { + 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) - { + 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_OK) { if(err == Z_STREAM_END) ended = true; else stopreading(); break; @@ -509,11 +413,9 @@ struct zipstream : stream } }; -stream *openzipfile(const char *name, const char *mode) -{ +stream *openzipfile(const char *name, const char *mode) { for(; *mode; mode++) if(*mode=='w' || *mode=='a') return NULL; - loopvrev(archives) - { + loopvrev(archives) { ziparchive *arch = archives[i]; zipfile *f = arch->files.access(name); if(!f) continue; @@ -524,36 +426,29 @@ stream *openzipfile(const char *name, const char *mode) return NULL; } -bool findzipfile(const char *name) -{ - loopvrev(archives) - { +bool findzipfile(const char *name) { + loopvrev(archives) { ziparchive *arch = archives[i]; if(arch->files.access(name)) return true; } return false; } -int listzipfiles(const char *dir, const char *ext, vector &files) -{ +int listzipfiles(const char *dir, const char *ext, vector &files) { size_t extsize = ext ? strlen(ext)+1 : 0, dirsize = strlen(dir); int dirs = 0; - loopvrev(archives) - { + loopvrev(archives) { ziparchive *arch = archives[i]; int oldsize = files.length(); - enumerate(arch->files, zipfile, f, - { + 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 - { + else { size_t namelen = strlen(name); - if(namelen > extsize) - { + if(namelen > extsize) { namelen -= extsize; if(name[namelen] == '.' && strncmp(name+namelen+1, ext, extsize-1)==0) files.add(newstring(name, namelen)); -- cgit v1.2.3