From 58526c45f2f6f2d04d961045b770a9165de9b2e7 Mon Sep 17 00:00:00 2001 From: ketmar Date: Sat, 17 Mar 2012 17:57:25 +0200 Subject: [PATCH] added libwdx as another possible resource packer (ok, ok, it's faster and better than rnc) --- Jamfile | 1 + src/Jamfile | 5 +- src/libwdx/Jamfile | 6 + src/libwdx/libwdx.c | 436 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/libwdx/libwdx.h | 43 ++++++ src/resfile.c | 49 ++++++ tools/wdx/Jamfile | 7 + tools/wdx/wpack.c | 225 +++++++++++++++++++++++++++ 8 files changed, 770 insertions(+), 2 deletions(-) create mode 100644 src/libwdx/Jamfile create mode 100644 src/libwdx/libwdx.c create mode 100644 src/libwdx/libwdx.h create mode 100644 tools/wdx/Jamfile create mode 100644 tools/wdx/wpack.c diff --git a/Jamfile b/Jamfile index ce15f93..1fc814b 100644 --- a/Jamfile +++ b/Jamfile @@ -3,3 +3,4 @@ SubDir TOP ; SubInclude TOP src ; SubInclude TOP tools rnc ; +if ! $(WINDOZE) { SubInclude TOP tools wdx ; } diff --git a/src/Jamfile b/src/Jamfile index db7adbf..cb3aeec 100644 --- a/src/Jamfile +++ b/src/Jamfile @@ -13,10 +13,11 @@ SDLMain awish : game.c awish.c ; -LinkLibraries awish : libvm.a librnc.a ; +LinkLibraries awish : libvm.a librnc.a libwdx.a ; Main awasm : awasm.c ; -LinkLibraries awasm : libvm.a librnc.a ; +LinkLibraries awasm : libvm.a ; SubInclude TOP src librnc ; +SubInclude TOP src libwdx ; diff --git a/src/libwdx/Jamfile b/src/libwdx/Jamfile new file mode 100644 index 0000000..d3e0044 --- /dev/null +++ b/src/libwdx/Jamfile @@ -0,0 +1,6 @@ +SubDir TOP src libwdx ; + + +Library libwdx.a : + libwdx.c +; diff --git a/src/libwdx/libwdx.c b/src/libwdx/libwdx.c new file mode 100644 index 0000000..57dd371 --- /dev/null +++ b/src/libwdx/libwdx.c @@ -0,0 +1,436 @@ +/* + * original code: WDOSX-Pack v1.07, (c) 1999-2001 by Joergen Ibsen / Jibz + * for data and executable compression software: http://www.ibsensoftware.com/ + */ +#include "libwdx.h" + +#include + +#include +#include +#include +#include + + +#ifndef WDX_EXCLUDE_CRC +uint32_t wdxCRC32 (const void *src, int len) { + static const unsigned int crctab[16] = { + 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, + 0x6b6b51f4, 0x4db26158, 0x5005713c, 0xedb88320, 0xf00f9344, + 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, + 0xbdbdf21c + }; + const uint8_t *buf = (const uint8_t *)src; + uint32_t crc = 0xffffffffUL; + // + if (src == NULL || len < 1) return 0; + while (len--) { + crc ^= *buf++; + crc = crctab[crc&0x0f]^(crc>>4); + crc = crctab[crc&0x0f]^(crc>>4); + } + return crc^0xffffffffUL; +} +#endif + + +#define WDXUNPACK_LEN2_LIMIT 1920 + +#define WDXFatalError() longjmp(errJP, 666) + + +#ifndef WDX_EXCLUDE_PACKER +int wdxPackBufferSize (int inSize) { + if (inSize < 1) return 0; + return inSize+((inSize+7)/8)+2; +} + + +int wdxPack (void *dest, int destSize, const void *source, int length) { + typedef struct { + uint32_t pos; + uint32_t len; + } TheMatch; + /* global variables */ + const uint8_t *inBuffer = (const uint8_t *)source, *sourceOfs, *backPtr; + uint8_t *outBuffer = (uint8_t *)dest; + uint32_t nextBackEntry; + uint8_t *tagByte; + int bitCount; + uint32_t *backTable; /* back-table, array */ + //uint32_t lookup[256][256]; /* lookup-table */ /*FIXME: made dynamic*/ + uint32_t *lookup = NULL; /* lookup-table */ /*FIXME: made dynamic*/ + uint32_t lastMatchPos = 0; + int lastWasMatch = 0; + jmp_buf errJP; + uint32_t bytesOut = 0; + + void advanceTagByte (int bit) { + /* check bitcount and then decrement */ + if (bitCount == 0) { + if (--destSize < 0) WDXFatalError(); + bitCount = 8; + tagByte = outBuffer++; + *tagByte = 0; + ++bytesOut; + } + /* shift in bit */ + *tagByte = ((*tagByte)<<1)|(bit?1:0); + --bitCount; + } + + /* output Gamma2-code for val in range [2..?] ... */ + void outputGamma (uint32_t val) { + uint32_t invertlen = 0, invert = 0; + // + /* rotate bits into invert (except last) */ + do { + invert = (invert<<1)|(val&0x01); + ++invertlen; + val = (val>>1)&0x7FFFFFFF; + } while (val > 1); + /* output Gamma2-encoded bits */ + for (--invertlen; invertlen > 0; --invertlen) { + advanceTagByte(invert&0x01); + advanceTagByte(1); + invert >>= 1; + } + advanceTagByte(invert&0x01); + advanceTagByte(0); + } + + void outputLiteral (uint8_t lit) { + lastWasMatch = 0; + advanceTagByte(0); /* 0 indicates a literal */ + if (--destSize < 0) WDXFatalError(); + *outBuffer++ = lit; /* output the literal */ + ++bytesOut; + } + + void outputCodePair (uint32_t pos, uint32_t len, const uint8_t *buffer) { + /* if we just had a match, don't use lastMatchPos */ + if (lastWasMatch) { + /* if a short match is too far away, encode it as two literals instead */ + if (pos > WDXUNPACK_LEN2_LIMIT && len == 2) { + outputLiteral(buffer[0]); + outputLiteral(buffer[1]); + } else { + advanceTagByte(1); /* 1 indicates a match */ + /* a match more than WDXUNPACK_LEN2_LIMIT bytes back will be longer than 2 */ + if (pos > WDXUNPACK_LEN2_LIMIT) --len; + outputGamma(len); /* output length */ + lastMatchPos = pos--; + /*assert(pos >= 0);*/ + outputGamma(((pos>>6)&0x3FFFFFFF)+2); /* output high part of position */ + /* output low 6 bits of position */ + advanceTagByte(pos&0x20); + advanceTagByte(pos&0x10); + advanceTagByte(pos&0x08); + advanceTagByte(pos&0x04); + advanceTagByte(pos&0x02); + advanceTagByte(pos&0x01); + } + } else { + lastWasMatch = 1; + /* if a short match is too far away, encode it as two literals instead */ + if (pos > WDXUNPACK_LEN2_LIMIT && len == 2 && pos != lastMatchPos) { + outputLiteral(buffer[0]); + outputLiteral(buffer[1]); + } else { + advanceTagByte(1); /* 1 indicates a match */ + /* a match more than WDXUNPACK_LEN2_LIMIT bytes back will be longer than 2 */ + if (pos > WDXUNPACK_LEN2_LIMIT && pos != lastMatchPos) --len; + outputGamma(len); /* output length */ + /* output position */ + if (pos == lastMatchPos) { + /* a match with position 0 means use last position */ + advanceTagByte(0); + advanceTagByte(0); + } else { + lastMatchPos = pos--; + /*assert(pos >= 0);*/ + outputGamma(((pos>>6)&0x3FFFFFFF)+3); /* output high part of position */ + /* output low 6 bits of position */ + advanceTagByte(pos&0x20); + advanceTagByte(pos&0x10); + advanceTagByte(pos&0x08); + advanceTagByte(pos&0x04); + advanceTagByte(pos&0x02); + advanceTagByte(pos&0x01); + } + } + } + } + + void findMatch (TheMatch *thematch, const uint8_t *buffer, uint32_t lookback, uint32_t lookforward) { + uint32_t backPos, matchLen, bestMatchLen, bestMatchPos; + const uint8_t *ptr; + uint32_t i0, i1; + uint32_t idx0, idx1; + // + /* temporary variables to avoid indirect addressing into the match */ + bestMatchLen = 0; bestMatchPos = 0; + /* update lookup- and backtable up to current position */ + while (backPtr < buffer) { + idx0 = backPtr[0]; + idx1 = backPtr[1]; + backTable[nextBackEntry] = lookup[idx0*256+idx1]; + lookup[idx0*256+idx1] = nextBackEntry; + ++nextBackEntry; + ++backPtr; + } + /* get position by looking up next two bytes */ + backPos = lookup[buffer[0]*256+buffer[1]]; + if (backPos != 0 && lookforward > 1) { + ptr = backPos+sourceOfs; + /* go backwards until before buffer */ + while (ptr >= buffer && backPos != 0) { + /*backPos := PInt(Integer(backTable)+backPos*4)^;*/ + backPos = backTable[backPos]; + ptr = backPos+sourceOfs; + } + /* search through table entries */ + while (backPos != 0 && buffer-ptr <= lookback) { + matchLen = 2; + /* if this position has a chance to be better */ + if (*(ptr+bestMatchLen) == *(buffer+bestMatchLen)) { + /* scan it */ + while (matchLen < lookforward && *(ptr+matchLen) == *(buffer+matchLen)) ++matchLen; + /* check it */ + i0 = buffer-ptr==lastMatchPos ? 1 : 0; + i1 = bestMatchPos==lastMatchPos ? 1 : 0; + if (matchLen+i0 > bestMatchLen+i1) { + bestMatchLen = matchLen; + if (bestMatchLen == lookforward) backPos = 0; + bestMatchPos = buffer-ptr; + } + } + /* move backwards to next position */ + /*backPos := PInt(Integer(backTable)+backPos*4)^;*/ + backPos = backTable[backPos]; + ptr = backPos+sourceOfs; + } + } + /* forget match if too far away */ + if (bestMatchPos > WDXUNPACK_LEN2_LIMIT && bestMatchLen == 2 && bestMatchPos != lastMatchPos) { + bestMatchLen = 0; + bestMatchPos = 0; + } + /* update the match with best match */ + thematch->len = bestMatchLen; + thematch->pos = bestMatchPos; + } + + /* main code */ + TheMatch match, nextmatch, literalmatch, testmatch; + uint32_t pos, lastpos, literalCount; + //int i, j; + uint32_t i0, i1; + + if (length < 1) return 0; + if (destSize < 2) return -1; + if (!(backTable = malloc((length+4)*4))) return -2; /* out of memory */ + if (!(lookup = malloc(256*256*4))) { free(backTable); return -2; } /* out of memory */ + + if (setjmp(errJP)) { + /* compressing error */ + free(lookup); + free(backTable); + return -1; + } + + memset(&match, 0, sizeof(match)); + memset(&nextmatch, 0, sizeof(nextmatch)); + memset(&literalmatch, 0, sizeof(literalmatch)); + memset(&testmatch, 0, sizeof(testmatch)); + literalmatch.pos = literalmatch.len = 0; + sourceOfs = inBuffer-1; + /* init lookup- and backtable */ + /*for (i = 0; i <= 255; ++i) for (j = 0; j <= 255; ++j) lookup[i*256+j] = 0;*/ + memset(lookup, 0, 256*256*4); + memset(backTable, 0, (length+4)*4); + backPtr = inBuffer; + backTable[0] = 0; + nextBackEntry = 1; + lastpos = -1; + lastMatchPos = -1; + lastWasMatch = 0; + literalCount = 0; + /* the first byte is sent verbatim */ + *outBuffer++ = *inBuffer++; + --destSize; + ++bytesOut; + /* init tag-byte */ + bitCount = 8; + *(tagByte = outBuffer++) = 0; + --destSize; + ++bytesOut; + /* pack data */ + pos = 1; + while (pos < length) { + /* find best match at current position (if not already found) */ + if (pos == lastpos) { + match.len = nextmatch.len; + match.pos = nextmatch.pos; + } else { + findMatch(&match, inBuffer, pos, length-pos); + } + /* if we found a match, find the best match at the next position */ + if (match.len != 0) { + findMatch(&nextmatch, inBuffer+1, pos+1, length-(pos+1)); + lastpos = pos+1; + } else { + nextmatch.len = 0; + } + /* decide if we should output a match or a literal */ + i0 = (match.pos==lastMatchPos ? 1 : 0); + i1 = (nextmatch.pos==lastMatchPos ? 1 : 0); + if (match.len != 0 && match.len+i0 >= nextmatch.len+i1) { + /* output any pending literals */ + if (literalCount != 0) { + if (literalCount == 1) { + outputLiteral(inBuffer[-1]); + } else { + /* check if there is a closer match with the required length */ + findMatch(&testmatch, inBuffer-literalCount, literalmatch.pos, literalCount); + if (testmatch.len >= literalCount) outputCodePair(testmatch.pos, literalCount, inBuffer-literalCount); + else outputCodePair(literalmatch.pos, literalCount, inBuffer-literalCount); + } + literalCount = 0; + } + /* output match */ + outputCodePair(match.pos, match.len, inBuffer); + inBuffer += match.len; + pos += match.len; + } else { + /* check if we are allready collecting literals */ + if (literalCount != 0) { + /* if so, continue.. */ + ++literalCount; + /* have we collected as many as possible? */ + if (literalCount == literalmatch.len) { + outputCodePair(literalmatch.pos, literalCount, inBuffer-literalCount+1); + literalCount = 0; + } + } else { + /* if we had a match which was not good enough, then save it.. */ + if (match.len != 0) { + literalmatch.len = match.len; + literalmatch.pos = match.pos; + ++literalCount; + } else { + /* if not, we have to output the literal now */ + outputLiteral(inBuffer[0]); + } + } + ++inBuffer; + ++pos; + } + } + /* output any remaining literal bytes */ + if (literalCount != 0) { + if (literalCount == 1) outputLiteral(inBuffer[-1]); + else outputCodePair(literalmatch.pos, literalCount, inBuffer-literalCount); + } + /* switch last tagByte into position */ + if (bitCount != 8) *tagByte <<= bitCount; + // + free(lookup); + free(backTable); + return bytesOut; +} +#endif + + +#ifndef WDX_EXCLUDE_UNPACKER +int wdxUnpack (void *bufOut, int outSize, const void *bufIn, int inSize) { + const uint8_t *src = (const uint8_t *)bufIn; + uint8_t *dest = (uint8_t *)bufOut, *pp; + uint8_t fbyte = 0; + int lastMatchPos = 0, lastWasMatch = 0, len, pos, b, bCount = 0, origOutSz = outSize; + jmp_buf errJP; + int itsOk = 0; + + int getBit (void) { + int res; + // + if (bCount <= 0) { + if (inSize < 1) WDXFatalError(); + fbyte = *src++; + --inSize; + bCount = 8; + } + res = (fbyte&0x80)!=0 ? 1 : 0; + fbyte = (fbyte&0x7f)<<1; + --bCount; + return res; + } + + int getGamma (void) { + int res = 1; + // + do { + res = (res<<1)|getBit(); + } while (getBit() == 1); + return res; + } + + /* get 6 low bits of position */ + int getLoPos (int pos) { + for (int f = 0; f < 6; ++f) pos = (pos<<1)|getBit(); + return pos; + } + + /* main code */ + if (outSize < 1) return 0; + if (inSize < 1) return -1; /* out of input data */ + + if (setjmp(errJP)) { + /* decompressing error */ + if (!itsOk) return -1; + return origOutSz-outSize; + } + + /* the first byte was sent verbatim */ + *dest++ = *src++; + --inSize; + --outSize; + while (outSize > 0) { + itsOk = 1; + b = getBit(); + itsOk = 0; + if (b == 0) { + /* literal */ + if (inSize < 1) break; + *dest++ = *src++; + --inSize; + --outSize; + lastWasMatch = 0; + } else { + /* match */ + len = getGamma(); + if (lastWasMatch) { + pos = getGamma()-2; + pos = getLoPos(pos)+1; + lastMatchPos = pos; + if (pos > WDXUNPACK_LEN2_LIMIT) ++len; + } else { + lastWasMatch = 1; + pos = getGamma()-2; + /* same position as last match? */ + if (pos == 0) pos = lastMatchPos; + else { + pos = getLoPos(pos-1)+1; + lastMatchPos = pos; + if (pos > WDXUNPACK_LEN2_LIMIT) ++len; + } + } + /* copy match */ + pp = dest-pos; + if ((void *)pp < (void *)bufOut) return -1; /* shit! */ + for (; len > 0 && outSize > 0; --outSize, --len) *dest++ = *pp++; + } + } + return origOutSz-outSize; +} +#endif diff --git a/src/libwdx/libwdx.h b/src/libwdx/libwdx.h new file mode 100644 index 0000000..82e63b2 --- /dev/null +++ b/src/libwdx/libwdx.h @@ -0,0 +1,43 @@ +/* + * original code: WDOSX-Pack v1.07, (c) 1999-2001 by Joergen Ibsen / Jibz + * for data and executable compression software: http://www.ibsensoftware.com/ + */ +#ifndef WDXLIB_H +#define WDXLIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + + +#ifndef WDX_EXCLUDE_CRC +/* poly: 0xedb88320L: ISO 3309, ITU-T V.42 */ +extern uint32_t wdxCRC32 (const void *src, int len); +#endif + +#ifndef WDX_EXCLUDE_PACKER +/* compress buffer + * return -1 or size of the packed data + * uncompressible data may be expanded by up to 1 bit per byte: + * i.e. the destination should be length+((length+7)/8)+2 bytes + */ +extern int wdxPack (void *dest, int destSize, const void *source, int length); + +/* returs max size of the packed data with the given length */ +extern int wdxPackBufferSize (int inSize); +#endif + +#ifndef WDX_EXCLUDE_UNPACKER +/* decompress buffer + * return -1 or size of the unpacked data + */ +extern int wdxUnpack (void *bufOut, int outSize, const void *bufIn, int inSize); +#endif + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/resfile.c b/src/resfile.c index 0b76be3..028a210 100644 --- a/src/resfile.c +++ b/src/resfile.c @@ -22,6 +22,7 @@ #include #include "librnc/librnc.h" +#include "libwdx/libwdx.h" #include "resfile.h" @@ -93,6 +94,14 @@ static const char *getHomeDir (void) { #endif +static uint32_t getUInt (const uint8_t *buf) { + uint32_t res = 0; + // + for (int f = 3; f >= 0; --f) res = (res<<8)|buf[f]; + return res; +} + + static int tryInitResFile (ResFile *resfile, const char *fname) { uint8_t fcnt; uint8_t sign[3]; @@ -275,6 +284,26 @@ uint8_t *tryDiskFile (const char *fname, int *rsz) { //if (goobers) fprintf(stderr, "RNC: %d -> %d (%d)\n", (int)size, ulen, uplen); if (uplen != ulen) goto quit; size = ulen; + } else if (size >= 20 && memcmp(res, "WDX0", 4) == 0) { + uint32_t crc, ncrc; + const uint8_t *ibuf = (const uint8_t *)res; + uint8_t *obuf; + int osz, psz, xsz; + // + ibuf += 4; /* skip signature */ + osz = getUInt(ibuf); ibuf += 4; /* unpacked size */ + crc = getUInt(ibuf); ibuf += 4; /* crc */ + psz = getUInt(ibuf); ibuf += 4; /* packed size */ + if (psz+4*4 > size) goto quit; + obuf = malloc(osz); + if (obuf == NULL) goto quit; + xsz = wdxUnpack(obuf, osz, ibuf, psz); + if (xsz < 0 || xsz != osz) goto quit; + free(res); + res = obuf; + ncrc = wdxCRC32(obuf, xsz); + if (ncrc != crc) goto quit; + size = xsz; } fclose(fl); fl = NULL; @@ -476,6 +505,26 @@ static uint8_t *tryResFile (ResFile *resfile, int idx, int *rsz, UnpackCB unp, i res = udata; if (uplen != ulen) { free(res); return NULL; } size = ulen; + } else if (size >= 20 && memcmp(res, "WDX0", 4) == 0) { + uint32_t crc, ncrc; + const uint8_t *ibuf = (const uint8_t *)res; + uint8_t *obuf; + int osz, psz, xsz; + // + ibuf += 4; /* skip signature */ + osz = getUInt(ibuf); ibuf += 4; /* unpacked size */ + crc = getUInt(ibuf); ibuf += 4; /* crc */ + psz = getUInt(ibuf); ibuf += 4; /* packed size */ + if (psz+4*4 > size) return NULL; + obuf = malloc(osz); + if (obuf == NULL) return NULL; + xsz = wdxUnpack(obuf, osz, ibuf, psz); + if (xsz < 0 || xsz != osz) { free(obuf); return NULL; } + free(res); + res = obuf; + ncrc = wdxCRC32(obuf, xsz); + if (ncrc != crc) { free(res); return NULL; } + size = xsz; } // if (!unp) { diff --git a/tools/wdx/Jamfile b/tools/wdx/Jamfile new file mode 100644 index 0000000..5a27ab1 --- /dev/null +++ b/tools/wdx/Jamfile @@ -0,0 +1,7 @@ +SubDir TOP tools wdx ; + +Main wpack : wpack.c ; +LinkLibraries wpack : libwdx.a ; + + +SubInclude TOP src libwdx ; diff --git a/tools/wdx/wpack.c b/tools/wdx/wpack.c new file mode 100644 index 0000000..2063bbd --- /dev/null +++ b/tools/wdx/wpack.c @@ -0,0 +1,225 @@ +/* coded by Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar) + * Understanding is not required. Only obedience. + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ +#ifndef _BSD_SOURCE +# define _BSD_SOURCE +#endif +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libwdx/libwdx.h" + + +static void reportError (void) { + fprintf(stderr, "ERROR: %s\n", strerror(errno)); +} + + +static void *loadWholeFile (const char *fname, int *fsize) { + void *res = NULL; + off_t fsz; + int fd = open(fname, O_RDONLY); + // + if (fd < 0) goto error; + fsz = lseek(fd, 0, SEEK_END); + if (fsz <= (off_t)-1) goto error; + if (fsz > 0x7fffffff) { fprintf(stderr, "ERROR: file too big\n"); goto error1; } + if (lseek(fd, 0, SEEK_SET) <= (off_t)-1) goto error; + res = malloc(fsz+1); + if (!res) goto error; + if (fsz > 0) { + if (read(fd, res, fsz) != fsz) goto error; + } + if (close(fd) < 0) { fd = -1; goto error; } + *fsize = fsz; + return res; +error: + reportError(); +error1: + if (fd >= 0) close(fd); + if (res) free(res); + return NULL; +} + + +static int writeUInt (int fd, uint32_t i) { + uint32_t v = htole32(i); + // + if (write(fd, &v, 4) != 4) { reportError(); return -1; } + return 0; +} + + +static uint32_t getUInt (const void *buf) { + uint32_t res; + // + memcpy(&res, buf, 4); + return le32toh(res); +} + + +static int writeWDX (const char *fname, const void *pbuf, int pSize, int origSize, uint32_t crc) { + static char *sign = "WDX0"; + int fd; + // + if (pSize < 0) return -1; + fd = open(fname, O_CREAT | O_WRONLY | O_TRUNC, 0644); + if (fd < 0) goto error; + if (write(fd, sign, 4) != 4) goto error; + if (writeUInt(fd, (uint32_t)origSize)) goto error1; + if (writeUInt(fd, crc)) goto error1; + if (writeUInt(fd, (uint32_t)pSize)) goto error1; + if (write(fd, pbuf, pSize) != pSize) goto error1; + if (close(fd) < 0) { unlink(fname); fd = -1; goto error; } + return 0; +error: + reportError(); +error1: + if (fd >= 0) { + close(fd); + unlink(fname); + } + return -1; +} + + +static int pack (const char *fin, const char *fout) { + uint32_t crc; + void *ibuf, *obuf; + int isz, osz, psz; + // + if (!(ibuf = loadWholeFile(fin, &isz))) { + fprintf(stderr, "ERROR: can't read input file: %s\n", fin); + return 1; + } + osz = wdxPackBufferSize(isz); + obuf = malloc(osz); + if (!obuf) { + free(ibuf); + fprintf(stderr, "ERROR: out of memory!\n"); + return 1; + } + crc = wdxCRC32(ibuf, isz); + fprintf(stdout, "packing %d bytes ... ", isz); fflush(stdout); + psz = wdxPack(obuf, osz, ibuf, isz); + free(ibuf); + if (psz < 0) { + free(obuf); + fprintf(stdout, "FAILED!\n"); + fprintf(stderr, "ERROR: can't pack!\n"); + return 1; + } + fprintf(stdout, "got %d packed bytes\n", psz); fflush(stdout); + osz = writeWDX(fout, obuf, psz, isz, crc); + free(obuf); + if (osz) { + fprintf(stderr, "ERROR: can't write output file: %s\n", fout); + return 1; + } + return 0; +} + + +static int unpack (const char *fin, const char *fout) { + uint32_t crc, ncrc; + uint8_t *ibuf, *obuf, *origBuf; + int isz, osz, psz, xsz; + int fo = -1; + // + if (!(ibuf = loadWholeFile(fin, &isz))) { + fprintf(stderr, "ERROR: can't read input file: %s\n", fin); + return 1; + } + if (isz < 16 || ibuf[0] != 'W' || ibuf[1] != 'D' || ibuf[2] != 'X' || ibuf[3] != '0') { + fprintf(stderr, "ERROR: invalid input file: %s\n", fin); + return 1; + } + origBuf = ibuf; + ibuf += 4; /* skip signature */ + osz = getUInt(ibuf); ibuf += 4; /* unpacked size */ + crc = getUInt(ibuf); ibuf += 4; /* crc */ + psz = getUInt(ibuf); ibuf += 4; /* packed size */ + obuf = malloc(osz); + if (!obuf) { + free(origBuf); + fprintf(stderr, "ERROR: out of memory!\n"); + return 1; + } + fprintf(stdout, "unpacking %d bytes to %d bytes ... ", psz, osz); fflush(stdout); + xsz = wdxUnpack(obuf, osz, ibuf, psz); + free(origBuf); + if (xsz < 0 || xsz != osz) { + free(obuf); + fprintf(stdout, "FAILED!\n"); + fprintf(stderr, "ERROR: can't unpack! (%d)\n", xsz); + return 1; + } + ncrc = wdxCRC32(obuf, xsz); + if (ncrc != crc) { + free(obuf); + fprintf(stdout, "FAILED!\n"); + fprintf(stderr, "ERROR: CRC check failed!\n"); + return 1; + } + fprintf(stdout, "OK\n"); + fo = open(fout, O_CREAT | O_WRONLY | O_TRUNC, 0644); + if (fo < 0) { + reportError(); + fprintf(stderr, "ERROR: can't write output file: %s\n", fout); + goto error; + } + if (write(fo, obuf, xsz) != xsz) { + reportError(); + fprintf(stderr, "ERROR: can't write output file (1): %s\n", fout); + goto error; + } + if (close(fo) < 0) { + reportError(); + fprintf(stderr, "ERROR: can't write output file (2): %s\n", fout); + unlink(fout); + fo = -1; + goto error; + } + free(obuf); + return 0; +error: + if (fo > 0) { + close(fo); + unlink(fout); + } + free(obuf); + return 0; +} + + +int main (int argc, char *argv[]) { + const char *inname = NULL, *outname = NULL; + // + if (argc == 3) { + inname = argv[2]; + outname = argv[2]; + } else if (argc > 3) { + inname = argv[2]; + outname = argv[3]; + } else { + fprintf(stderr, "usage: %s infile [outfile]\n", argv[0]); + return 1; + } + if (!strcmp("c", argv[1]) || !strcmp("-c", argv[1])) return pack(inname, outname); + return unpack(inname, outname); +} -- 2.11.4.GIT