From 505061a8d2d9bee304e7f080abb55d9b68ac3042 Mon Sep 17 00:00:00 2001 From: Shpoike Date: Mon, 27 Mar 2023 13:53:40 +0100 Subject: [PATCH] Add deflate64 support, cos why not. --- engine/Makefile | 19 ++++- engine/common/fs_zip.c | 138 +++++++++++++++++++++++++++++-- engine/qclib/qcctui.c | 174 ++++++++++++++++++++++++++++------------ engine/qclib/qcd_main.c | 151 +++++++++++++++++++++++++++------- 4 files changed, 391 insertions(+), 91 deletions(-) diff --git a/engine/Makefile b/engine/Makefile index d143a043c..ab94569d8 100644 --- a/engine/Makefile +++ b/engine/Makefile @@ -1044,6 +1044,14 @@ endif ifeq (1,$(LINK_ZLIB)) CLIENTLIBFLAGS+=-DZLIB_STATIC CLIENTLDDEPS+=-lz + + #and deflate64, because why not. + ifneq ("$(wildcard $(ARCHLIBS)/infback9.h)","") + CLIENTLIBFLAGS+=-DZLIB_DEFLATE64 + CLIENTLDDEPS+=-lz9 + QCC_CFLAGS+=-DZLIB_DEFLATE64 + QCC_LDFLAGS+=-lz9 + endif endif ifeq (1,$(LINK_ODE)) ALL_CFLAGS+=$(shell $(PKGCONFIG) ode --cflags --silence-errors) -DODE_STATIC @@ -2124,7 +2132,7 @@ m-profile: _qcc-tmp: $(REQDIR) - @$(MAKE) $(TYPE) EXE_NAME="$(EXE_NAME)$(EXEPOSTFIX)" PRECOMPHEADERS="" OUT_DIR="$(OUT_DIR)" WCFLAGS="$(CLIENT_ONLY_CFLAGS) $(WCFLAGS)" LDFLAGS="$(LDFLAGS) $(QCC_LDFLAGS)" OBJS="QCC_OBJS SOBJS" + @$(MAKE) $(TYPE) EXE_NAME="$(EXE_NAME)$(EXEPOSTFIX)" PRECOMPHEADERS="" OUT_DIR="$(OUT_DIR)" WCFLAGS="$(QCC_CFLAGS) $(WCFLAGS)" LDFLAGS="$(LDFLAGS) $(QCC_LDFLAGS)" OBJS="QCC_OBJS SOBJS" qcc-rel: @$(MAKE) _qcc-tmp TYPE=_out-rel REQDIR=reldir EXE_NAME="../fteqcc$(BITS)" OUT_DIR="$(RELEASE_DIR)/$(NCDIRPREFIX)$(QCC_DIR)" SOBJS="qcctui.o packager.o $(if $(findstring win,$(FTE_TARGET)),fteqcc.o)" qccgui-rel: @@ -2429,6 +2437,13 @@ libs-$(ARCH)/libz.a libs-$(ARCH)/libz.pc: test -f zlib-$(ZLIBVER).tar.gz || wget http://zlib.net/zlib-$(ZLIBVER).tar.gz -test -f libs-$(ARCH)/libz.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../zlib-$(ZLIBVER).tar.gz && cd zlib-$(ZLIBVER) && $(TOOLOVERRIDES) ./configure --static && $(TOOLOVERRIDES) $(MAKE) libz.a CC="$(CC) $(W32_CFLAGS) -fPIC" && cp libz.a ../ && $(TOOLOVERRIDES) $(AR) -s ../libz.a && cp zlib.h zconf.h zutil.h zlib.pc ../ ) endif +libs-$(ARCH)/libz9.a: libs-$(ARCH)/libz.a + (cd libs-$(ARCH)/zlib-$(ZLIBVER) && \ + $(CC) -o contrib/infback9/infback9.o -c contrib/infback9/infback9.c -I. && \ + $(CC) -o contrib/infback9/inftree9.o -c contrib/infback9/inftree9.c -I. && \ + cp contrib/infback9/infback9.h .. && \ + $(AR) rcs ../libz9.a contrib/infback9/infback9.o contrib/infback9/inftree9.o) + libs-$(ARCH)/libpng.a libs-$(ARCH)/libpng.pc: libs-$(ARCH)/libz.a libs-$(ARCH)/libz.pc test -f libpng-$(PNGVER).tar.gz || wget http://prdownloads.sourceforge.net/libpng/libpng-$(PNGVER).tar.gz?download -O libpng-$(PNGVER).tar.gz @@ -2465,7 +2480,7 @@ libs-$(ARCH)/libBulletDynamics.a: ifeq ($(FTE_TARGET),web) makelibs: libs-$(ARCH)/libz.a $(MAKELIBS) else -makelibs: libs-$(ARCH)/libjpeg.a libs-$(ARCH)/libz.a libs-$(ARCH)/libpng.a libs-$(ARCH)/libogg.a libs-$(ARCH)/libvorbis.a libs-$(ARCH)/libopus.a libs-$(ARCH)/libspeex.a libs-$(ARCH)/libspeexdsp.a libs-$(ARCH)/libfreetype.a $(MAKELIBS) +makelibs: libs-$(ARCH)/libjpeg.a libs-$(ARCH)/libz9.a libs-$(ARCH)/libz.a libs-$(ARCH)/libpng.a libs-$(ARCH)/libogg.a libs-$(ARCH)/libvorbis.a libs-$(ARCH)/libopus.a libs-$(ARCH)/libspeex.a libs-$(ARCH)/libspeexdsp.a libs-$(ARCH)/libfreetype.a $(MAKELIBS) endif HTTP_OBJECTS=http/httpserver.c http/iwebiface.c common/fs_stdio.c http/ftpserver.c diff --git a/engine/common/fs_zip.c b/engine/common/fs_zip.c index fcb771327..760bb101a 100644 --- a/engine/common/fs_zip.c +++ b/engine/common/fs_zip.c @@ -607,6 +607,9 @@ typedef struct #define ZFL_SYMLINK (1u<<3) //file is a symlink #define ZFL_CORRUPT (1u<<4) //file is corrupt or otherwise unreadable (usually just means we don't support reading it rather than actually corrupt, but hey). #define ZFL_WEAKENCRYPT (1u<<5) //traditional zip encryption +#define ZFL_DEFLATE64D (1u<<6) //need to use zlib's 'inflateBack9' stuff. + +#define ZFL_COMPRESSIONTYPE (ZFL_STORED|ZFL_CORRUPT|ZFL_DEFLATED|ZFL_DEFLATE64D|ZFL_BZIP2) typedef struct zipfile_s @@ -1030,6 +1033,95 @@ static struct decompressstate *FSZIP_Deflate_Init(zipfile_t *source, qofs_t star } #endif +#if defined(ZLIB_DEFLATE64) && !defined(AVAIL_ZLIB) + #undef ZLIB_DEFLATE64 //don't be silly. +#endif +#if defined(ZLIB_DEFLATE64) +#include "infback9.h" //an obscure compile-your-own part of zlib. +struct def64ctx +{ + vfsfile_t *src; + vfsfile_t *dst; + qofs_t csize; + qofs_t usize; + unsigned int crc; + + qbyte inbuf[0x8000]; +}; +static unsigned int FSZIP_Deflate64_Grab(void *vctx, unsigned char **bufptr) +{ + struct def64ctx *ctx = vctx; + int avail; + avail = sizeof(ctx->inbuf); + if (avail > ctx->csize) + avail = ctx->csize; //don't over-read. + if (avail <= 0) + { + *bufptr = NULL; + return 0; + } + + avail = VFS_READ(ctx->src, ctx->inbuf, avail); + *bufptr = ctx->inbuf; + + if (avail < 0) + avail = 0; //treated as eof... + ctx->csize -= avail; + return avail; +} +static int FSZIP_Deflate64_Spew(void *vctx, unsigned char *buf, unsigned int buflen) +{ + struct def64ctx *ctx = vctx; + + //update the crc + ctx->crc = crc32(ctx->crc, buf, buflen); + ctx->usize += buflen; + + if (VFS_WRITE(ctx->dst, buf, buflen) != buflen) + return 1; //failure returns non-zero. + return 0; +} +//inflateBack stuff is apparently not restartable, and must read the entire file +static vfsfile_t *FSZIP_Deflate64(vfsfile_t *src, qofs_t csize, qofs_t usize, unsigned int crc32) +{ + z_stream strm = {NULL}; + qbyte window[65536]; + struct def64ctx ctx; + ctx.src = src; + ctx.dst = VFSPIPE_Open(1, true); + ctx.csize = csize; + ctx.usize = 0; + ctx.crc = 0; + + strm.data_type = Z_UNKNOWN; + inflateBack9Init(&strm, window); + //getting inflateBack9 to + if (Z_STREAM_END != inflateBack9(&strm, FSZIP_Deflate64_Grab, &ctx, FSZIP_Deflate64_Spew, &ctx)) + { //some stream error? + Con_Printf("Decompression error\n"); + VFS_CLOSE(ctx.dst); + ctx.dst = NULL; + } + else if (ctx.csize != 0 || ctx.usize != usize) + { //corrupt file table? + Con_Printf("Decompression size error\n"); + Con_Printf("read %i of %i bytes\n", (unsigned)ctx.csize, (unsigned)csize); + Con_Printf("wrote %i of %i bytes\n", (unsigned)ctx.usize, (unsigned)usize); + VFS_CLOSE(ctx.dst); + ctx.dst = NULL; + } + else if (ctx.crc != crc32) + { //corrupt file table? + Con_Printf("CRC32 error\n"); + VFS_CLOSE(ctx.dst); + ctx.dst = NULL; + } + inflateBack9End(&strm); + + return ctx.dst; +} +#endif + #ifdef AVAIL_BZLIB //if the offset is still within our decompressed block then we can just rewind a smidge static qboolean FSZIP_BZip2_Seek(struct decompressstate *st, qofs_t *offset, qofs_t newoffset) @@ -1403,13 +1495,40 @@ static vfsfile_t *QDECL FSZIP_OpenVFS(searchpathfuncs_t *handle, flocation_t *lo vfsz->funcs.WriteBytes = NULL; vfsz->funcs.seekstyle = SS_SLOW; + //NOTE: pf->name is the quakeified name, and may have an extra prefix/stripped prefix for certain zips - different from what you'd see if you opened the zip yourself. this is only relevant for debugging, whuch might be misleading but is not fatal. if (!FSZIP_ValidateLocalHeader(zip, pf, &vfsz->startpos, &datasize)) { - Con_Printf("file %s:%s is incompatible or inconsistent with zip central directory\n", zip->filename, pf->name); + Con_Printf(CON_WARNING"file %s:%s is incompatible or inconsistent with zip central directory\n", zip->filename, pf->name); Z_Free(vfsz); return NULL; } + if (flags & ZFL_DEFLATE64D) + { //crap +#if defined(ZLIB_DEFLATE64) + vfsfile_t *tmp = NULL; + qofs_t startpos = vfsz->startpos; + qofs_t usize = vfsz->length; + qofs_t csize = datasize; + Z_Free(vfsz); + + Con_Printf(CON_WARNING"file %s:%s was compressed with deflate64\n", zip->filename, pf->name); + + if (Sys_LockMutex(zip->mutex)) + { + VFS_SEEK(vfsz->parent->raw, startpos); + tmp = FSZIP_Deflate64(zip->raw, csize, usize, pf->crc); + Sys_UnlockMutex(zip->mutex); + } + + return tmp; +#else + Con_Printf(CON_WARNING"%s:%s: deflate64 not supported\n", COM_SkipPath(zip->filename), pf->name); + Z_Free(vfsz); + return NULL; +#endif + } + if (flags & ZFL_DEFLATED) { #ifdef AVAIL_ZLIB @@ -1670,11 +1789,19 @@ static qboolean FSZIP_ValidateLocalHeader(zipfile_t *zip, zpackfile_t *zfile, qo return false; //FIXME: proper spanned zips fragment compressed data over multiple spans, but we don't support that if (local.cmethod == 0) - return (zfile->flags & (ZFL_STORED|ZFL_CORRUPT|ZFL_DEFLATED|ZFL_BZIP2)) == ZFL_STORED; + return (zfile->flags & ZFL_COMPRESSIONTYPE) == ZFL_STORED; +#if defined(AVAIL_ZLIB) if (local.cmethod == 8) - return (zfile->flags & (ZFL_STORED|ZFL_CORRUPT|ZFL_DEFLATED|ZFL_BZIP2)) == ZFL_DEFLATED; + return (zfile->flags & ZFL_COMPRESSIONTYPE) == ZFL_DEFLATED; +#endif +#if defined(ZLIB_DEFLATE64) + if (local.cmethod == 9) + return (zfile->flags & ZFL_COMPRESSIONTYPE) == ZFL_DEFLATE64D; +#endif +#ifdef AVAIL_BZLIB if (local.cmethod == 12) - return (zfile->flags & (ZFL_STORED|ZFL_CORRUPT|ZFL_DEFLATED|ZFL_BZIP2)) == ZFL_BZIP2; + return (zfile->flags & ZFL_COMPRESSIONTYPE) == ZFL_BZIP2; +#endif return false; //some other method that we don't know. } @@ -1850,7 +1977,8 @@ static qboolean FSZIP_ReadCentralEntry(zipfile_t *zip, qbyte *data, struct zipce //7: tokenize else if (entry->cmethod == 8) //8: deflate entry->flags |= ZFL_DEFLATED; - //9: deflate64 - patented. sometimes written by microsoft's crap, so this might be problematic. only minor improvements. + else if (entry->cmethod == 9) //9: deflate64 - patented. sometimes written by microsoft's crap, so this might be problematic. only minor improvements. + entry->flags |= ZFL_DEFLATE64D; //10: implode else if (entry->cmethod == 12) //12: bzip2 entry->flags |= ZFL_BZIP2; diff --git a/engine/qclib/qcctui.c b/engine/qclib/qcctui.c index c7879557c..fd15effed 100644 --- a/engine/qclib/qcctui.c +++ b/engine/qclib/qcctui.c @@ -120,7 +120,16 @@ static void QCC_FileList(const char *name, const void *compdata, size_t compsize { totalsize += plainsize; filecount += 1; - if (!method && compsize==plainsize) + if (method < 0) + { + if (method == -1-9) + externs->Printf("%s%8u DF64 %s%s\n", col_error, (unsigned)plainsize, name, col_none); + else if (method == -1) //general error + externs->Printf("%s%8u ERR %s%s\n", col_error, (unsigned)plainsize, name, col_none); + else + externs->Printf("%s%8u m%-3i %s%s\n", col_error, (unsigned)plainsize, -1-method, name, col_none); + } + else if (!method && compsize==plainsize) externs->Printf("%8u %s\n", (unsigned)plainsize, name); else externs->Printf("%8u %3u%% %s\n", (unsigned)plainsize, plainsize?(unsigned)((100*compsize)/plainsize):100u, name); @@ -191,10 +200,13 @@ int qcc_wildcmp(const char *wild, const char *string) -static const char *extractonly; -static pbool extractonlyfound; +static const char *extractonly; //the file we're looking for +static pbool extractonlyfound; //for errors. +static pbool extractecho; //print the file to stdout instead of writing it. static void QCC_FileExtract(const char *name, const void *compdata, size_t compsize, int method, size_t plainsize) { + if (method < 0) + return; //QC_decode will fail. provided for enumeration reasons. if (extractonly) { const char *sl = strrchr(extractonly, '/'); @@ -216,11 +228,19 @@ static void QCC_FileExtract(const char *name, const void *compdata, size_t comps void *buffer = malloc(plainsize); if (buffer && QC_decode(progfuncs, compsize, plainsize, method, compdata, buffer)) { - QCC_Mkdir(name); - if (!QCC_WriteFile(name, buffer, plainsize)) - externs->Printf(" write failure\n"); + if (extractecho) + { + externs->Printf("\n"); + fwrite(buffer, 1, plainsize, stdout); + } else - externs->Printf(" done\n"); + { + QCC_Mkdir(name); + if (!QCC_WriteFile(name, buffer, plainsize)) + externs->Printf(" write failure\n"); + else + externs->Printf(" done\n"); + } } else externs->Printf(" read failure\n"); @@ -253,6 +273,7 @@ int main (int argc, const char **argv) pbool writelog = false; //other systems are sane. #endif int colours = 2; //auto + int ziparg = -1; progexterns_t ext; progfuncs_t funcs; progfuncs = &funcs; @@ -265,52 +286,6 @@ int main (int argc, const char **argv) funcs.funcs.parms->Printf = logprintf; funcs.funcs.parms->Sys_Error = Sys_Error; - if ((argc == 3 && !strcmp(argv[1], "-l")) || (argc >= 3 && !strcmp(argv[1], "-x"))) - { - size_t blobsize; - void *blob = QCC_ReadFile(argv[2], NULL, NULL, &blobsize, false); - if (!blob) - { - logprintf("Unable to read %s\n", argv[2]); - return EXIT_FAILURE; - } - if (argc > 3) - { - for (i = 3; i < argc; i++) - { - extractonly = argv[i]; - extractonlyfound = false; - QC_EnumerateFilesFromBlob(blob, blobsize, QCC_FileExtract); - if (!extractonlyfound) - externs->Printf("Unable to find file %s\n", extractonly); - } - extractonly = NULL; - } - else if (argv[1][1] == 'x') - QC_EnumerateFilesFromBlob(blob, blobsize, QCC_FileExtract); - else - { - QC_EnumerateFilesFromBlob(blob, blobsize, QCC_FileList); - externs->Printf("Total size %u bytes, %u files\n", (unsigned)totalsize, (unsigned)filecount); - } - free(blob); - return EXIT_SUCCESS; - } - if (argc == 3 && (!strncmp(argv[1], "-z", 2) || !strcmp(argv[1], "-0") || !strcmp(argv[1], "-9"))) - { //exe -0 foo.pk3dir - enum pkgtype_e t; - if (argv[1][1] == '9') - t = PACKAGER_PK3; - else if (argv[1][1] == '0') - t = PACKAGER_PAK; //not really any difference but oh well - else - t = PACKAGER_PK3_SPANNED; - - if (Packager_CompressDir(argv[2], t, QCC_PR_PackagerMessage, NULL)) - return EXIT_SUCCESS; - else - return EXIT_FAILURE; - } for (i = 0; i < argc; i++) { if (!argv[i]) @@ -327,7 +302,20 @@ int main (int argc, const char **argv) colours = 0; else if (!strcmp(argv[i], "--color=auto")) colours = 2; + else if (!strcmp(argv[i], "-l") || + !strcmp(argv[i], "-x") || + !strcmp(argv[i], "-p") || + !strcmp(argv[i], "-z") || + !strcmp(argv[i], "-0") || + !strcmp(argv[i], "-9")) + { + ziparg = i; + break; //other args are all filenames. don't misinterpret stuff. + } } + + for (i = 0; i < COL_MAX; i++) + qcccol[i] = ""; #if defined(__linux__) || defined(__unix__) if (colours == 2) colours = isatty(STDOUT_FILENO); @@ -346,6 +334,86 @@ int main (int argc, const char **argv) (void)colours; #endif + if (ziparg >= 0) + { + if (ziparg+1 >= argc) + { + logprintf("archive name not specified\n"); + return EXIT_FAILURE; + } + switch(argv[ziparg][1]) + { + case 'l': //list all files. + { + size_t blobsize; + void *blob = QCC_ReadFile(argv[ziparg+1], NULL, NULL, &blobsize, false); + if (blob) + { + QC_EnumerateFilesFromBlob(blob, blobsize, QCC_FileList); + externs->Printf("Total size %lu bytes, %u files\n", (unsigned long)totalsize, (unsigned)filecount); + free(blob); + return EXIT_SUCCESS; + } + logprintf("Unable to read %s\n", argv[ziparg+1]); + } + break; + case 'p': //print (named) files to stdout. + extractecho = true; + //fall through + case 'x': //extract (named) files to working directory. + { //list/extract/view + size_t blobsize; + void *blob = QCC_ReadFile(argv[ziparg+1], NULL, NULL, &blobsize, false); + int ret = EXIT_FAILURE; + if (!blob) + logprintf("Unable to read %s\n", argv[ziparg+1]); + else if (ziparg+2 < argc) + { + for (i = ziparg+2; i < argc; i++) + { + extractonly = argv[i]; + extractonlyfound = false; + QC_EnumerateFilesFromBlob(blob, blobsize, QCC_FileExtract); + if (!extractonlyfound) + externs->Printf("Unable to find file %s\n", extractonly); + else + ret = EXIT_SUCCESS; + } + extractonly = NULL; + } + else + { + QC_EnumerateFilesFromBlob(blob, blobsize, QCC_FileExtract); + ret = EXIT_SUCCESS; + } + free(blob); + return ret; + } + case 'z': //fancy spanned stuff + case '0': //store-only (pak) + case '9': //best compression (pk3) + + { //exe -0 foo.pk3dir + enum pkgtype_e t; + if (argv[1][1] == '9') + t = PACKAGER_PK3; + else if (argv[1][1] == '0') + t = PACKAGER_PAK; //not really any difference but oh well + else + t = PACKAGER_PK3_SPANNED; + + if (Packager_CompressDir(argv[ziparg+1], t, QCC_PR_PackagerMessage, NULL)) + return EXIT_SUCCESS; + } + break; + default: + //should be unreachable. + break; + } + return EXIT_FAILURE; + } + + logfile = writelog?fopen("fteqcc.log", "wt"):false; if (logfile) diff --git a/engine/qclib/qcd_main.c b/engine/qclib/qcd_main.c index ea8ea0ff3..5b731de01 100644 --- a/engine/qclib/qcd_main.c +++ b/engine/qclib/qcd_main.c @@ -41,6 +41,44 @@ pbool QC_decodeMethodSupported(int method) return false; } + +#ifdef ZLIB_DEFLATE64 +#include "infback9.h" //an obscure compile-your-own part of zlib. +struct def64ctx +{ + const char *in; + char *out; + size_t csize; + size_t usize; + + char window[65536]; +}; +static unsigned int QC_Deflate64_Grab(void *vctx, unsigned char **bufptr) +{ + struct def64ctx *ctx = vctx; + + unsigned int avail = ctx->csize; + *bufptr = (unsigned char *)ctx->in; + ctx->csize = 0; + ctx->in += avail; + + return avail; +} +static int QC_Deflate64_Spew(void *vctx, unsigned char *buf, unsigned int buflen) +{ + struct def64ctx *ctx = vctx; + + if (buflen > ctx->usize) + return 1; //over the size of our buffer... + memcpy(ctx->out, buf, buflen); + ctx->out += buflen; + ctx->usize -= buflen; + return 0; +} +#endif + + + char *QC_decode(progfuncs_t *progfuncs, int complen, int len, int method, const void *info, char *buffer) { int i; @@ -87,6 +125,35 @@ char *QC_decode(progfuncs_t *progfuncs, int complen, int len, int method, const externs->Sys_Error("Failed block decompression\n"); inflateEnd(&strm); } +#endif +#ifdef ZLIB_DEFLATE64 + else if (method == 9) + { + z_stream strm = {NULL}; + struct def64ctx ctx; + ctx.in = info; + ctx.csize = complen; + ctx.out = buffer; + ctx.usize = len; + + strm.data_type = Z_UNKNOWN; + inflateBack9Init(&strm, ctx.window); + //getting inflateBack9 to + if (Z_STREAM_END != inflateBack9(&strm, QC_Deflate64_Grab, &ctx, QC_Deflate64_Spew, &ctx)) + { //some stream error? + externs->Printf("Decompression error\n"); + buffer = NULL; + } + else if (ctx.csize != 0 || ctx.usize != 0) + { //corrupt file table? + externs->Printf("Decompression size error\n"); + externs->Printf("read %i of %i bytes\n", (unsigned)ctx.csize, (unsigned)complen); + externs->Printf("wrote %i of %i bytes\n", (unsigned)ctx.usize, (unsigned)len); + buffer = NULL; + } + inflateBack9End(&strm); + return buffer; + } #endif //add your decryption/decompression routine here. else @@ -191,8 +258,17 @@ int QC_EnumerateFilesFromBlob(const void *blob, size_t blobsize, void (*cb)(cons unsigned int cdlen; const unsigned char *eocd; const unsigned char *cd; - int nl,el,cl; + unsigned int ofs_le; + unsigned int cd_nl,cd_el,cd_cl; int ret = 0; + + const unsigned char *le; + unsigned int csize, usize, method; + unsigned int le_nl,le_el; + char name[256]; + + const void *data; + if (blobsize < 22) return ret; if (!strncmp(blob, "PACK", 4)) @@ -221,13 +297,20 @@ int QC_EnumerateFilesFromBlob(const void *blob, size_t blobsize, void (*cb)(cons return ret; - for(; cdentries --> 0; cd += 46 + nl+el+cl) + for(; cdentries --> 0 && (QC_ReadRawInt(cd+0) == 0x02014b50); cd += 46 + cd_nl+cd_el+cd_cl) { - if (QC_ReadRawInt(cd+0) != 0x02014b50) - break; - nl = QC_ReadRawShort(cd+28); - el = QC_ReadRawShort(cd+30); - cl = QC_ReadRawShort(cd+32); + data = NULL, csize=usize=0, method=-1; + + cd_nl = QC_ReadRawShort(cd+28); //name length + cd_el = QC_ReadRawShort(cd+30); //extras length + cd_cl = QC_ReadRawShort(cd+32); //comment length + + ofs_le = QC_ReadRawInt(cd+42); + + if (cd_nl < sizeof(name)) //make can't be too long... + QC_strlcpy(name, cd+46, (cd_nl+1= sizeof(name)) - continue; //name is too long - QC_strlcpy(name, cd+46, (nl+1