Add deflate64 support, cos why not.

This commit is contained in:
Shpoike 2023-03-27 13:53:40 +01:00
parent 84035c8ae2
commit 505061a8d2
4 changed files with 391 additions and 91 deletions

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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))?cd_nl+1:sizeof(name));
else
QC_strlcpy(name, "?", sizeof(name));
//1=encrypted
//2,4=encoder flags
@ -240,35 +323,41 @@ int QC_EnumerateFilesFromBlob(const void *blob, size_t blobsize, void (*cb)(cons
//1000=enh comp
//2000=masked localheader
//4000,8000=reserved
if (QC_ReadRawShort(cd+8) & ~0x80e)
continue;
if (!(QC_ReadRawShort(cd+8) & ~0x80e)) //only accept known cd general purpose flags
{
const unsigned char *le = (const unsigned char*)blob + QC_ReadRawInt(cd+42);
unsigned int csize, usize, method;
char name[256];
if (ofs_le+46 < blobsize)
{
le = (const unsigned char*)blob + QC_ReadRawInt(cd+42);
if (QC_ReadRawInt(le+0) != 0x04034b50)
continue;
if (QC_ReadRawShort(le+6) & ~0x80e) //general purpose flags
continue;
method = QC_ReadRawShort(le+8);
if (method != 0 && method != 8)
continue;
if (nl != QC_ReadRawShort(le+26))
continue; //name is weird...
// if (el != QC_ReadRawShort(le+28))
// continue; //extradata is weird...
if (QC_ReadRawInt(le+0) == 0x04034b50) //needs proper local entry tag
if (!(QC_ReadRawShort(le+6) & ~0x80e)) //ignore unsupported general purpose flags
{
le_nl = QC_ReadRawShort(le+26);
le_el = QC_ReadRawShort(le+28);
if (cd_nl == le_nl) //name (length) must match...
// if (cd_el != le_el) //extras does NOT match
{
csize = QC_ReadRawInt(le+18);
usize = QC_ReadRawInt(le+22);
csize = QC_ReadRawInt(le+18);
usize = QC_ReadRawInt(le+22);
if (nl >= sizeof(name))
continue; //name is too long
QC_strlcpy(name, cd+46, (nl+1<sizeof(name))?nl+1:sizeof(name));
data = le+30+le_nl+le_el;
cb(name, le+30+QC_ReadRawShort(le+26)+QC_ReadRawShort(le+28), csize, method, usize);
ret++;
method = QC_ReadRawShort(le+8);
if (method != 0
#ifdef AVAIL_ZLIB
&& method != 8
#endif
#ifdef ZLIB_DEFLATE64
&& method != 9
#endif
)
method=-1-method;
}
}
}
}
cb(name, data, csize, method, usize);
ret++;
}
return ret;
}