#include "progsint.h" #include "qcc.h" #if !defined(FTE_TARGET_WEB) && !defined(NACL) && !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 #ifdef _WIN64 //# pragma comment (lib, "../libs/zlib64.lib") #else //# pragma comment (lib, "../libs/zlib.lib") #endif #else #include #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; } #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); } #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; const unsigned char *eocd; const unsigned char *cd; 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)) { 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 eocd = blob; eocd += blobsize-22; if (QC_ReadRawInt(eocd+0) != 0x06054b50) return ret; if (QC_ReadRawShort(eocd+4) || QC_ReadRawShort(eocd+6) || QC_ReadRawShort(eocd+20) || QC_ReadRawShort(eocd+8) != QC_ReadRawShort(eocd+10)) return ret; cd = blob; cd += QC_ReadRawInt(eocd+16); cdlen = QC_ReadRawInt(eocd+12); cdentries = QC_ReadRawShort(eocd+10); if (cd+cdlen>=(const unsigned char*)blob+blobsize) return ret; for(; cdentries --> 0 && (QC_ReadRawInt(cd+0) == 0x02014b50); cd += 46 + cd_nl+cd_el+cd_cl) { 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+1version != 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; } */