summaryrefslogtreecommitdiff
path: root/src/shared/zip.cpp
diff options
context:
space:
mode:
authorxolatile2025-08-06 22:54:55 +0200
committerxolatile2025-08-06 22:54:55 +0200
commit0a1172b75f571685c264a8b9d8ee224bbf11381f (patch)
treed041fdc68a60f0ebb48a3852bbcce6d9432f83d5 /src/shared/zip.cpp
parentaffde05dc07a94643f1fd2751b2b441f57f73d7d (diff)
downloadxolatile-badassbug-0a1172b75f571685c264a8b9d8ee224bbf11381f.tar.xz
xolatile-badassbug-0a1172b75f571685c264a8b9d8ee224bbf11381f.tar.zst
Please do not hate me, it makes sense...
Diffstat (limited to 'src/shared/zip.cpp')
-rw-r--r--src/shared/zip.cpp241
1 files changed, 68 insertions, 173 deletions
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<zipfile> 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<uint>(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<zipfile> &files)
-{
+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)
- {
+ 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<ziparchive *> 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<zipfile> &files, const char *prefix, int prefixlen)
-{
- loopv(files)
- {
+static bool checkprefix(vector<zipfile> &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<zipfile> &files, const char *mountdir, const char *stripdir)
-{
+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)
- {
+ 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<zipfile> &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<zipfile> &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<zipfile> 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<char *> &files)
-{
+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)
- {
+ 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));