fteqw/engine/qclib/qcd_main.c

524 lines
12 KiB
C
Raw Normal View History

#include "progsint.h"
#include "qcc.h"
#if !defined(FTE_TARGET_WEB) && !defined(_XBOX)
#ifndef AVAIL_ZLIB
#define AVAIL_ZLIB
#endif
#endif
#ifdef NO_ZLIB
#undef AVAIL_ZLIB
#endif
#ifdef AVAIL_ZLIB
#ifdef _WIN32
#define ZEXPORT VARGS
#include <zlib.h>
#ifdef _WIN64
//# pragma comment (lib, "../libs/zlib64.lib")
#else
//# pragma comment (lib, "../libs/zlib.lib")
#endif
#else
#include <zlib.h>
#endif
#endif
pbool QC_decodeMethodSupported(int method)
{
if (method == 0)
return true;
if (method == 1)
return true;
if (method == 2)
{
#ifdef AVAIL_ZLIB
return false;
#endif
}
return false;
}
2023-03-27 12:53:40 +00:00
#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;
if (method == 0) //copy
{
if (complen != len) externs->Sys_Error("lengths do not match");
memcpy(buffer, info, len);
}
else if (method == 1) //xor encryption
{
if (complen != len) externs->Sys_Error("lengths do not match");
for (i = 0; i < len; i++)
buffer[i] = ((const char*)info)[i] ^ 0xA5;
}
#ifdef AVAIL_ZLIB
else if (method == 2 || method == 8) //compression (ZLIB)
{
z_stream strm = {
(char*)info,
complen,
0,
buffer,
len,
0,
NULL,
NULL,
NULL,
NULL,
NULL,
Z_BINARY,
0,
0
};
if (method == 8)
inflateInit2(&strm, -MAX_WBITS);
else
inflateInit(&strm);
if (Z_STREAM_END != inflate(&strm, Z_FINISH)) //decompress it in one go.
externs->Sys_Error("Failed block decompression\n");
inflateEnd(&strm);
}
2023-03-27 12:53:40 +00:00
#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
externs->Sys_Error("Bad file encryption routine\n");
return buffer;
}
#if !defined(MINIMAL) && !defined(OMIT_QCC)
int QC_encodecrc(int len, char *in)
{
#ifdef AVAIL_ZLIB
return crc32(0, in, len);
#else
return 0;
#endif
}
void SafeWrite(int hand, const void *buf, long count);
int SafeSeek(int hand, int ofs, int mode);
//we are allowed to trash our input here.
int QC_encode(progfuncs_t *progfuncs, int len, int method, const char *in, int handle)
{
if (method == 0) //copy, allows a lame pass-through.
{
SafeWrite(handle, in, len);
return len;
}
/*else if (method == 1) //xor encryption, not secure. maybe useful for the string table.
{
for (i = 0; i < len; i++)
in[i] = in[i] ^ 0xA5;
SafeWrite(handle, in, len);
return len;
}*/
else if (method == 2 || method == 8) //compression (ZLIB)
{
#ifdef AVAIL_ZLIB
char out[8192];
int i=0;
z_stream strm = {
(char *)in,
len,
0,
out,
sizeof(out),
0,
NULL,
NULL,
NULL,
NULL,
NULL,
Z_BINARY,
0,
0
};
if (method == 8)
deflateInit2(&strm, 9, Z_DEFLATED, -MAX_WBITS, 9, Z_DEFAULT_STRATEGY); //zip deflate compression
else
deflateInit(&strm, Z_BEST_COMPRESSION); //zlib compression
while(deflate(&strm, Z_FINISH) == Z_OK)
{
SafeWrite(handle, out, sizeof(out) - strm.avail_out); //compress in chunks of 8192. Saves having to allocate a huge-mega-big buffer
i+=sizeof(out) - strm.avail_out;
strm.next_out = out;
strm.avail_out = sizeof(out);
}
SafeWrite(handle, out, sizeof(out) - strm.avail_out);
i+=sizeof(out) - strm.avail_out;
deflateEnd(&strm);
return i;
#endif
externs->Sys_Error("ZLIB compression not supported in this build");
return 0;
}
//add your compression/decryption routine here.
else
{
externs->Sys_Error("Wierd method");
return 0;
}
}
#endif
static int QC_ReadRawInt(const unsigned char *blob)
{
return (blob[0]<<0) | (blob[1]<<8) | (blob[2]<<16) | (blob[3]<<24);
}
static int QC_ReadRawShort(const unsigned char *blob)
{
return (blob[0]<<0) | (blob[1]<<8);
}
int QC_EnumerateFilesFromBlob(const void *blob, size_t blobsize, void (*cb)(const char *name, const void *compdata, size_t compsize, int method, size_t plainsize))
{
unsigned int cdentries;
unsigned int cdlen;
unsigned int cdstart;
unsigned int zipoffset = 0;
const unsigned char *eocd;
const unsigned char *cd;
2023-03-27 12:53:40 +00:00
unsigned int ofs_le;
unsigned int cd_nl,cd_el,cd_cl;
int ret = 0;
2023-03-27 12:53:40 +00:00
const unsigned char *le;
unsigned int csize, usize;
int method; //negatives for errors.
2023-03-27 12:53:40 +00:00
unsigned int le_nl,le_el;
char name[256];
const void *data;
if (blobsize < 22)
return ret;
if (!strncmp(blob, "PACK", 4))
{
const packheader_t *head = blob;
const packfile_t *f = (packfile_t*)((char*)blob + head->dirofs);
for (ret = 0; ret < head->dirlen/sizeof(*f); ret++, f++)
{
cb(f->name, (const char*)blob+f->filepos, f->filelen, 0, f->filelen);
}
return ret;
}
//treat it as a zip (with no comment, too lazy to scan)
eocd = blob;
eocd += blobsize-22;
for (cdlen = 0; ; eocd--, cdlen++)
{
if (cdlen > 65535 || eocd < (const unsigned char*)blob)
{
printf("No zip EOCD\n");
return ret;
}
if (QC_ReadRawInt(eocd+0) == 0x06054b50)
break;
}
if (QC_ReadRawShort(eocd+4) || QC_ReadRawShort(eocd+6) || QC_ReadRawShort(eocd+20)!=cdlen || QC_ReadRawShort(eocd+8) != QC_ReadRawShort(eocd+10))
{ //this-disk start-disk comment-length numfiles_thisdisk numfiles_all
printf("Unsupported zip\n");
return ret;
}
cdstart = QC_ReadRawInt(eocd+16);
cdlen = QC_ReadRawInt(eocd+12);
cdentries = QC_ReadRawShort(eocd+10);
cd = blob;
cd += cdstart + zipoffset;
if (cdlen < 46 || cd+cdlen>=(const unsigned char*)blob+blobsize || cd[0]!='P'||cd[1]!='K'||cd[2]!=1||cd[3]!=2)
{ //cd looks corrupt? assume eocd starts right after the cd and use that as an offset at the start of the zip (concatenated onto a binary or w/e)
zipoffset += (eocd-(const unsigned char*)blob) - (cdstart+cdlen);
cd = blob;
cd += cdstart + zipoffset;
if (cdlen < 46 || zipoffset > blobsize || cd+cdlen>=(const unsigned char*)blob+blobsize || cd[0]!='P'||cd[1]!='K'||cd[2]!=1||cd[3]!=2)
{
printf("Zip CentralDir not found: %s\n", cd);
return ret;
}
//okay, we're at an offset.
printf("Zip offset is %u\n", zipoffset);
}
2023-03-27 12:53:40 +00:00
for(; cdentries --> 0 && (QC_ReadRawInt(cd+0) == 0x02014b50); cd += 46 + cd_nl+cd_el+cd_cl)
{
2023-03-27 12:53:40 +00:00
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
//8=crc etc info is dodgy
//10=enhanced deflate
//20=patchdata
//40=strong encryption
//80,100,200,400=unused
//800=utf-8
//1000=enh comp
//2000=masked localheader
//4000,8000=reserved
2023-03-27 12:53:40 +00:00
if (!(QC_ReadRawShort(cd+8) & ~0x80e)) //only accept known cd general purpose flags
{
2023-03-27 12:53:40 +00:00
if (ofs_le+46 < blobsize)
{
le = (const unsigned char*)blob + zipoffset + QC_ReadRawInt(cd+42);
2023-03-27 12:53:40 +00:00
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
{
unsigned short gpflags = QC_ReadRawShort(le+6);
if (gpflags & (1u<<3))
{ //stream-compressed (csize+usize+crc are AFTER the data... just fall back to the central directory instead)
csize = QC_ReadRawInt(cd+20);
usize = QC_ReadRawInt(cd+24);
}
else
{
csize = QC_ReadRawInt(le+18);
usize = QC_ReadRawInt(le+22);
}
//parse extra
if (le_el)
{
const pbyte *extra = le + 30 + le_nl, *extraend = extra + le_el;
unsigned short extrachunk_tag;
unsigned short extrachunk_len;
while(extra+4 < extraend)
{
extrachunk_tag = QC_ReadRawShort(extra+0);
extrachunk_len = QC_ReadRawShort(extra+2);
if (extra + extrachunk_len > extraend)
break; //error
extra += 4;
switch(extrachunk_tag)
{
case 1: //zip64 extended information extra field. the attributes are only present if the reegular file info is nulled out with a -1
if (usize == 0xffffffffu)
{
usize = QC_ReadRawInt/*64*/(extra);
if (QC_ReadRawInt(extra+4))
method=-1-method;
extra += 8;
}
if (csize == 0xffffffffu)
{
csize = QC_ReadRawInt/*64*/(extra);
if (QC_ReadRawInt(extra+4))
method=-1-method;
extra += 8;
}
break;
default:
/* printf("Unknown chunk %x\n", extrachunk_tag);
case 0x000a: //NTFS (timestamps)
case 0x5455: //extended timestamp
case 0x7875: //unix uid/gid
*/ extra += extrachunk_len;
break;
}
}
}
2023-03-27 12:53:40 +00:00
data = le+30+le_nl+le_el;
method = QC_ReadRawShort(le+8);
if (method >= 0 && (method != 0
2023-03-27 12:53:40 +00:00
#ifdef AVAIL_ZLIB
&& method != 8
#endif
#ifdef ZLIB_DEFLATE64
&& method != 9
#endif
))
2023-03-27 12:53:40 +00:00
method=-1-method;
}
}
}
}
2023-03-27 12:53:40 +00:00
cb(name, data, csize, method, usize);
ret++;
}
return ret;
}
char *PDECL filefromprogs(pubprogfuncs_t *ppf, progsnum_t prnum, const char *fname, size_t *size, char *buffer)
{
------------------------------------------------------------------------ r4169 | acceptthis | 2013-01-17 08:55:12 +0000 (Thu, 17 Jan 2013) | 31 lines removed MAX_VISEDICTS limit. PEXT2_REPLACEMENTDELTAS tweaked, now has 4 million entity limit. still not enabled by default. TE_BEAM now maps to a separate TEQW_BEAM to avoid conflicts with QW. added android multitouch emulation for windows/rawinput (in_simulatemultitouch). split topcolor/bottomcolor from scoreboard, for dp's colormap|1024 feature. now using utf-8 for windows consoles. qcc warnings/errors now give clickable console links for quick+easy editing. disabled menutint when the currently active item changes contrast or gamma (for OneManClan). Added support for drawfont/drawfontscale. tweaked the qcvm a little to reduce the number of pointers. .doll file loading. still experimental and will likely crash. requires csqc active, even if its a dummy progs. this will be fixed in time. Still other things that need cleaning up. windows: gl_font "?" shows the standard windows font-selection dialog, and can be used to select windows fonts. not all work. and you probably don't want to use windings. fixed splitscreen support when playing mvds. added mini-scoreboards to splitscreen. editor/debugger now shows asm if there's no linenumber info. also, pressing f1 for help shows the shortcuts. Added support for .framegroups files for psk(psa) and iqm formats. True support for ezquake's colour codes. Mutually exclusive with background colours. path command output slightly more readable. added support for digest_hex (MD4, SHA1, CRC16). skingroups now colourmap correctly. Fix terrain colour hints, and litdata from the wrong bsp. fix ftp dual-homed issue. support epsv command, and enable ipv6 (eprt still not supported). remove d3d11 compilation from the makefile. the required headers are not provided by mingw, and are not available to the build bot, so don't bother. fix v *= v.x and similar opcodes. fteqcc: fixed support for áéíóú type chars in names. utf-8 files now properly supported (even with the utf-8 bom/identifier). utf-16 also supported. fteqcc: fixed '#if 1 == 3 && 4' parsing. fteqcc: -Werror acts on the warning, rather than as a separate error. Line numbers are thus more readable. fteqcc: copyright message now includes compile date instead. fteqccgui: the treeview control is now coloured depending on whether there were warnings/errors in the last compile. fteqccgui: the output window is now focused and scrolls down as compilation progresses. pr_dumpplatform command dumps out some pragmas to convert more serious warnings to errors. This is to avoid the infamous 'fteqcc sucks cos my code sucks' issue. rewrote prespawn/modelist/soundlist code. server tracks progress now. ------------------------------------------------------------------------ git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4167 fc73d0e0-1445-4013-8a0c-d673dee63da5
2013-03-12 22:29:40 +00:00
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
int num;
includeddatafile_t *s;
if (size)
*size = 0;
if (!pr_progstate[prnum].progs)
return NULL;
if (pr_progstate[prnum].progs->version != PROG_EXTENDEDVERSION)
return NULL;
if (pr_progstate[prnum].progs->secondaryversion != PROG_SECONDARYVERSION16 &&
pr_progstate[prnum].progs->secondaryversion != PROG_SECONDARYVERSION32)
return NULL;
num = *(int*)((char *)pr_progstate[prnum].progs + pr_progstate[prnum].progs->ofsfiles);
s = (includeddatafile_t *)((char *)pr_progstate[prnum].progs + pr_progstate[prnum].progs->ofsfiles+4);
while(num>0)
{
if (!strcmp(s->filename, fname))
{
if (size)
*size = s->size;
if (!buffer)
return NULL;
return QC_decode(progfuncs, s->compsize, s->size, s->compmethod, (char *)pr_progstate[prnum].progs+s->ofs, buffer);
}
s++;
num--;
}
if (size)
*size = 0;
return NULL;
}
/*
char *filefromnewprogs(progfuncs_t *progfuncs, const char *prname, const char *fname, int *size, char *buffer)
{
int num;
includeddatafile_t *s;
progstate_t progs;
if (!PR_ReallyLoadProgs(progfuncs, prname, -1, &progs, false))
{
if (size)
*size = 0;
return NULL;
}
if (progs.progs->version < PROG_EXTENDEDVERSION)
return NULL;
if (!progs.progs->ofsfiles)
return NULL;
num = *(int*)((char *)progs.progs + progs.progs->ofsfiles);
s = (includeddatafile_t *)((char *)progs.progs + progs.progs->ofsfiles+4);
while(num>0)
{
if (!strcmp(s->filename, fname))
{
if (size)
*size = s->size;
if (!buffer)
return (char *)0xffffffff;
return QC_decode(progfuncs, s->compsize, s->size, s->compmethod, (char *)progs.progs+s->ofs, buffer);
}
s++;
num--;
}
if (size)
*size = 0;
return NULL;
}
*/