Add deflate64 support, cos why not.
This commit is contained in:
parent
84035c8ae2
commit
505061a8d2
4 changed files with 391 additions and 91 deletions
|
@ -1044,6 +1044,14 @@ endif
|
||||||
ifeq (1,$(LINK_ZLIB))
|
ifeq (1,$(LINK_ZLIB))
|
||||||
CLIENTLIBFLAGS+=-DZLIB_STATIC
|
CLIENTLIBFLAGS+=-DZLIB_STATIC
|
||||||
CLIENTLDDEPS+=-lz
|
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
|
endif
|
||||||
ifeq (1,$(LINK_ODE))
|
ifeq (1,$(LINK_ODE))
|
||||||
ALL_CFLAGS+=$(shell $(PKGCONFIG) ode --cflags --silence-errors) -DODE_STATIC
|
ALL_CFLAGS+=$(shell $(PKGCONFIG) ode --cflags --silence-errors) -DODE_STATIC
|
||||||
|
@ -2124,7 +2132,7 @@ m-profile:
|
||||||
|
|
||||||
|
|
||||||
_qcc-tmp: $(REQDIR)
|
_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:
|
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)"
|
@$(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:
|
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 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 ../ )
|
-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
|
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
|
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
|
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)
|
ifeq ($(FTE_TARGET),web)
|
||||||
makelibs: libs-$(ARCH)/libz.a $(MAKELIBS)
|
makelibs: libs-$(ARCH)/libz.a $(MAKELIBS)
|
||||||
else
|
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
|
endif
|
||||||
|
|
||||||
HTTP_OBJECTS=http/httpserver.c http/iwebiface.c common/fs_stdio.c http/ftpserver.c
|
HTTP_OBJECTS=http/httpserver.c http/iwebiface.c common/fs_stdio.c http/ftpserver.c
|
||||||
|
|
|
@ -607,6 +607,9 @@ typedef struct
|
||||||
#define ZFL_SYMLINK (1u<<3) //file is a symlink
|
#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_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_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
|
typedef struct zipfile_s
|
||||||
|
@ -1030,6 +1033,95 @@ static struct decompressstate *FSZIP_Deflate_Init(zipfile_t *source, qofs_t star
|
||||||
}
|
}
|
||||||
#endif
|
#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
|
#ifdef AVAIL_BZLIB
|
||||||
//if the offset is still within our decompressed block then we can just rewind a smidge
|
//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)
|
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.WriteBytes = NULL;
|
||||||
vfsz->funcs.seekstyle = SS_SLOW;
|
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))
|
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);
|
Z_Free(vfsz);
|
||||||
return NULL;
|
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)
|
if (flags & ZFL_DEFLATED)
|
||||||
{
|
{
|
||||||
#ifdef AVAIL_ZLIB
|
#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
|
return false; //FIXME: proper spanned zips fragment compressed data over multiple spans, but we don't support that
|
||||||
|
|
||||||
if (local.cmethod == 0)
|
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)
|
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)
|
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.
|
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
|
//7: tokenize
|
||||||
else if (entry->cmethod == 8) //8: deflate
|
else if (entry->cmethod == 8) //8: deflate
|
||||||
entry->flags |= ZFL_DEFLATED;
|
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
|
//10: implode
|
||||||
else if (entry->cmethod == 12) //12: bzip2
|
else if (entry->cmethod == 12) //12: bzip2
|
||||||
entry->flags |= ZFL_BZIP2;
|
entry->flags |= ZFL_BZIP2;
|
||||||
|
|
|
@ -120,7 +120,16 @@ static void QCC_FileList(const char *name, const void *compdata, size_t compsize
|
||||||
{
|
{
|
||||||
totalsize += plainsize;
|
totalsize += plainsize;
|
||||||
filecount += 1;
|
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);
|
externs->Printf("%8u %s\n", (unsigned)plainsize, name);
|
||||||
else
|
else
|
||||||
externs->Printf("%8u %3u%% %s\n", (unsigned)plainsize, plainsize?(unsigned)((100*compsize)/plainsize):100u, name);
|
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 const char *extractonly; //the file we're looking for
|
||||||
static pbool extractonlyfound;
|
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)
|
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)
|
if (extractonly)
|
||||||
{
|
{
|
||||||
const char *sl = strrchr(extractonly, '/');
|
const char *sl = strrchr(extractonly, '/');
|
||||||
|
@ -215,6 +227,13 @@ static void QCC_FileExtract(const char *name, const void *compdata, size_t comps
|
||||||
{
|
{
|
||||||
void *buffer = malloc(plainsize);
|
void *buffer = malloc(plainsize);
|
||||||
if (buffer && QC_decode(progfuncs, compsize, plainsize, method, compdata, buffer))
|
if (buffer && QC_decode(progfuncs, compsize, plainsize, method, compdata, buffer))
|
||||||
|
{
|
||||||
|
if (extractecho)
|
||||||
|
{
|
||||||
|
externs->Printf("\n");
|
||||||
|
fwrite(buffer, 1, plainsize, stdout);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
QCC_Mkdir(name);
|
QCC_Mkdir(name);
|
||||||
if (!QCC_WriteFile(name, buffer, plainsize))
|
if (!QCC_WriteFile(name, buffer, plainsize))
|
||||||
|
@ -222,6 +241,7 @@ static void QCC_FileExtract(const char *name, const void *compdata, size_t comps
|
||||||
else
|
else
|
||||||
externs->Printf(" done\n");
|
externs->Printf(" done\n");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
externs->Printf(" read failure\n");
|
externs->Printf(" read failure\n");
|
||||||
|
|
||||||
|
@ -253,6 +273,7 @@ int main (int argc, const char **argv)
|
||||||
pbool writelog = false; //other systems are sane.
|
pbool writelog = false; //other systems are sane.
|
||||||
#endif
|
#endif
|
||||||
int colours = 2; //auto
|
int colours = 2; //auto
|
||||||
|
int ziparg = -1;
|
||||||
progexterns_t ext;
|
progexterns_t ext;
|
||||||
progfuncs_t funcs;
|
progfuncs_t funcs;
|
||||||
progfuncs = &funcs;
|
progfuncs = &funcs;
|
||||||
|
@ -265,52 +286,6 @@ int main (int argc, const char **argv)
|
||||||
funcs.funcs.parms->Printf = logprintf;
|
funcs.funcs.parms->Printf = logprintf;
|
||||||
funcs.funcs.parms->Sys_Error = Sys_Error;
|
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++)
|
for (i = 0; i < argc; i++)
|
||||||
{
|
{
|
||||||
if (!argv[i])
|
if (!argv[i])
|
||||||
|
@ -327,7 +302,20 @@ int main (int argc, const char **argv)
|
||||||
colours = 0;
|
colours = 0;
|
||||||
else if (!strcmp(argv[i], "--color=auto"))
|
else if (!strcmp(argv[i], "--color=auto"))
|
||||||
colours = 2;
|
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 defined(__linux__) || defined(__unix__)
|
||||||
if (colours == 2)
|
if (colours == 2)
|
||||||
colours = isatty(STDOUT_FILENO);
|
colours = isatty(STDOUT_FILENO);
|
||||||
|
@ -346,6 +334,86 @@ int main (int argc, const char **argv)
|
||||||
(void)colours;
|
(void)colours;
|
||||||
#endif
|
#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;
|
logfile = writelog?fopen("fteqcc.log", "wt"):false;
|
||||||
|
|
||||||
if (logfile)
|
if (logfile)
|
||||||
|
|
|
@ -41,6 +41,44 @@ pbool QC_decodeMethodSupported(int method)
|
||||||
return false;
|
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)
|
char *QC_decode(progfuncs_t *progfuncs, int complen, int len, int method, const void *info, char *buffer)
|
||||||
{
|
{
|
||||||
int i;
|
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");
|
externs->Sys_Error("Failed block decompression\n");
|
||||||
inflateEnd(&strm);
|
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
|
#endif
|
||||||
//add your decryption/decompression routine here.
|
//add your decryption/decompression routine here.
|
||||||
else
|
else
|
||||||
|
@ -191,8 +258,17 @@ int QC_EnumerateFilesFromBlob(const void *blob, size_t blobsize, void (*cb)(cons
|
||||||
unsigned int cdlen;
|
unsigned int cdlen;
|
||||||
const unsigned char *eocd;
|
const unsigned char *eocd;
|
||||||
const unsigned char *cd;
|
const unsigned char *cd;
|
||||||
int nl,el,cl;
|
unsigned int ofs_le;
|
||||||
|
unsigned int cd_nl,cd_el,cd_cl;
|
||||||
int ret = 0;
|
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)
|
if (blobsize < 22)
|
||||||
return ret;
|
return ret;
|
||||||
if (!strncmp(blob, "PACK", 4))
|
if (!strncmp(blob, "PACK", 4))
|
||||||
|
@ -221,13 +297,20 @@ int QC_EnumerateFilesFromBlob(const void *blob, size_t blobsize, void (*cb)(cons
|
||||||
return ret;
|
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)
|
data = NULL, csize=usize=0, method=-1;
|
||||||
break;
|
|
||||||
nl = QC_ReadRawShort(cd+28);
|
cd_nl = QC_ReadRawShort(cd+28); //name length
|
||||||
el = QC_ReadRawShort(cd+30);
|
cd_el = QC_ReadRawShort(cd+30); //extras length
|
||||||
cl = QC_ReadRawShort(cd+32);
|
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
|
//1=encrypted
|
||||||
//2,4=encoder flags
|
//2,4=encoder flags
|
||||||
|
@ -240,36 +323,42 @@ int QC_EnumerateFilesFromBlob(const void *blob, size_t blobsize, void (*cb)(cons
|
||||||
//1000=enh comp
|
//1000=enh comp
|
||||||
//2000=masked localheader
|
//2000=masked localheader
|
||||||
//4000,8000=reserved
|
//4000,8000=reserved
|
||||||
if (QC_ReadRawShort(cd+8) & ~0x80e)
|
if (!(QC_ReadRawShort(cd+8) & ~0x80e)) //only accept known cd general purpose flags
|
||||||
continue;
|
|
||||||
|
|
||||||
{
|
{
|
||||||
const unsigned char *le = (const unsigned char*)blob + QC_ReadRawInt(cd+42);
|
if (ofs_le+46 < blobsize)
|
||||||
unsigned int csize, usize, method;
|
{
|
||||||
char name[256];
|
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);
|
csize = QC_ReadRawInt(le+18);
|
||||||
usize = QC_ReadRawInt(le+22);
|
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));
|
|
||||||
|
|
||||||
cb(name, le+30+QC_ReadRawShort(le+26)+QC_ReadRawShort(le+28), csize, method, usize);
|
data = le+30+le_nl+le_el;
|
||||||
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue