Skip to content

Instantly share code, notes, and snippets.

@uyjulian
Created Mar 10, 2015
Embed
What would you like to do?
s3rc cleaned up
#include "dbpf.h"
#define assert(expr)
struct word
{
byte lo, hi;
};
struct dword
{
word lo, hi;
};
static inline unsigned get(const word &w)
{
return w.lo + w.hi * 256;
}
static inline unsigned get(const dword &dw)
{
return get(dw.lo) + get(dw.hi) * 65536;
}
static inline void put(word &w, unsigned x)
{
w.lo = x;
w.hi = x >> 8;
}
static inline void put(dword &dw, unsigned x)
{
put(dw.lo, x);
put(dw.hi, x >> 16);
}
struct word3be
{
byte hi, mid, lo;
};
static inline unsigned get(const word3be &w3)
{
return w3.hi * 65536 + w3.mid * 256 + w3.lo;
}
static inline void put(word3be &w3, unsigned x)
{
w3.hi = x >> 16;
w3.mid = x >> 8;
w3.lo = x;
}
class dbpf_compressed_file_header // 9 bytes
{
public:
word compression_id;
word3be ucsize;
int sz(byte cidlo)
{
bool flag = (cidlo & 0x80) != 0;
bool flag2 = (cidlo & 1) != 0;
return ((flag ? 4 : 3) * (flag2 ? 2 : 1)) + sizeof(word);
}
};
#define DBPF_COMPRESSION_QFS (0xFB10)
bool benrg_decompress(const byte *src, int compressed_size, byte *dst, int uncompressed_size, bool truncate)
{
const byte *src_end = src + compressed_size;
byte *dst_end = dst + uncompressed_size;
byte *dst_start = dst;
dbpf_compressed_file_header *hdr = (dbpf_compressed_file_header *)src;
if (compressed_size < hdr->sz(hdr->compression_id.lo) + 1)
return false;
if ((hdr->compression_id.lo & 0x3e) != 0x10 || hdr->compression_id.hi != 0xFB)
{
return false;
}
src += hdr->sz(hdr->compression_id.lo);
unsigned b0;
do
{
int lit, copy, offset;
b0 = *src++;
if (b0 < 0x80)
{
if (src == src_end)
return false;
unsigned b1 = *src++;
lit = b0 & 0x03; // 0..3
copy = ((b0 & 0x1C) >> 2) + 3; // 3..10
offset = ((b0 & 0x60) << 3) + b1 + 1; // 1..1024
}
else if (b0 < 0xC0)
{
if (src + 2 > src_end)
return false;
unsigned b1 = *src++;
unsigned b2 = *src++;
lit = (b1 & 0xC0) >> 6; // 0..3
copy = (b0 & 0x3F) + 4; // 4..67
offset = ((b1 & 0x3F) << 8) + b2 + 1; // 1..16384
}
else if (b0 < 0xE0)
{
if (src + 3 > src_end)
return false;
unsigned b1 = *src++;
unsigned b2 = *src++;
unsigned b3 = *src++;
lit = b0 & 0x03; // 0..3
copy = ((b0 & 0x0C) << 6) + b3 + 5; // 5..1028
offset = ((b0 & 0x10) << 12) + (b1 << 8) + b2 + 1; // 1..131072
}
else if (b0 < 0xFC)
{
lit = (b0 - 0xDF) * 4; // 4..112
copy = 0;
offset = 0;
}
else
{
lit = b0 - 0xFC;
copy = 0;
offset = 0;
}
if (src + lit > src_end || dst + lit + copy > dst_end)
{
if (!truncate)
return false;
if (lit > dst_end - dst)
lit = dst_end - dst;
if (copy > dst_end - dst - lit)
copy = dst_end - dst - lit;
if (src + lit > src_end)
return false;
}
if (lit)
{
memcpy(dst, src, lit);
dst += lit;
src += lit;
}
if (copy)
{
if (offset > dst - dst_start)
return false;
if (offset == 1)
{
memset(dst, dst[-1], copy);
dst += copy;
}
else
{
do
{
*dst = *(dst - offset);
++dst;
} while (--copy);
}
}
} while (src < src_end && dst < dst_end);
if (truncate)
{
return (dst == dst_end);
}
else
{
while (src < src_end && *src == 0xFC)
++src;
return (src == src_end && dst == dst_end);
}
}
/*
* Try to compress the data and return the result in a buffer (which the
* caller must delete). If it's uncompressable, return NULL.
*/
byte *try_compress(const byte *src, uint32 srclen, uint32 *dstlen)
{
// There are only 3 byte for the uncompressed size in the header,
// so I guess we can only compress files larger than 16MB...
if (srclen < 14 || srclen >= 16777216)
return 0;
// We only want the compressed output if it's smaller than the
// uncompressed.
byte *dst = (byte *)malloc(srclen - 1);
if (!dst)
return 0;
byte *dstend = compress(src, src + srclen, dst, dst + srclen - 1, false);
if (dstend)
{
*dstlen = dstend - dst;
return dst;
}
else
{
*dstlen = 0;
if (dst)
free(dst);
return 0;
}
}
#define MAX_MATCH 1028
#define MIN_MATCH 3
#define MIN_LOOKAHEAD (MAX_MATCH + MIN_MATCH + 1)
// corresponds to zlib compression level 9
#define GOOD_LENGTH 32
#define MAX_LAZY 258
#define NICE_LENGTH 258
#define MAX_CHAIN 4096
#define HASH_BITS 16
#define HASH_SIZE 65536
#define HASH_MASK 65535
#define HASH_SHIFT 6
#define W_SIZE 131072
#define MAX_DIST W_SIZE
#define W_MASK (W_SIZE - 1)
class Hash
{
private:
unsigned hash;
int *head, *prev;
public:
Hash()
{
hash = 0;
head = (int *)malloc(sizeof(int) * HASH_SIZE);
for (int i = 0; i < HASH_SIZE; ++i)
head[i] = -1;
prev = (int *)malloc(sizeof(int) * W_SIZE);
}
~Hash()
{
if (head)
free(head);
if (prev)
free(prev);
}
int getprev(unsigned pos) const { return prev[pos & W_MASK]; }
void update(unsigned c) { hash = ((hash << HASH_SHIFT) ^ c) & HASH_MASK; }
int insert(unsigned pos)
{
int match_head = prev[pos & W_MASK] = head[hash];
head[hash] = pos;
return match_head;
}
};
class CompressedOutput
{
private:
byte *dstpos;
byte *dstend;
const byte *src;
unsigned srcpos;
public:
CompressedOutput(const byte *src_, byte *dst, byte *dstend_)
{
dstpos = dst;
dstend = dstend_;
src = src_;
srcpos = 0;
}
byte *get_end() { return dstpos; }
bool emit(unsigned from_pos, unsigned to_pos, unsigned count)
{
if (count)
assert(memcmp(src + from_pos, src + to_pos, count) == 0);
unsigned lit = to_pos - srcpos;
while (lit >= 4)
{
unsigned amt = lit >> 2;
if (amt > 28)
amt = 28;
if (dstpos + amt * 4 >= dstend)
return false;
*dstpos++ = 0xE0 + amt - 1;
memcpy(dstpos, src + srcpos, amt * 4);
dstpos += amt * 4;
srcpos += amt * 4;
lit -= amt * 4;
}
unsigned offset = to_pos - from_pos - 1;
if (count == 0)
{
if (dstpos + 1 + lit > dstend)
return false;
*dstpos++ = 0xFC + lit;
}
else if (offset < 1024 && 3 <= count && count <= 10)
{
if (dstpos + 2 + lit > dstend)
return false;
*dstpos++ = ((offset >> 3) & 0x60) + ((count - 3) * 4) + lit;
*dstpos++ = offset;
}
else if (offset < 16384 && 4 <= count && count <= 67)
{
if (dstpos + 3 + lit > dstend)
return false;
*dstpos++ = 0x80 + (count - 4);
*dstpos++ = lit * 0x40 + (offset >> 8);
*dstpos++ = offset;
}
else /* if (offset < 131072 && 5 <= count && count <= 1028) */
{
if (dstpos + 4 + lit > dstend)
return false;
*dstpos++ = 0xC0 + ((offset >> 12) & 0x10) + (((count - 5) >> 6) & 0x0C) + lit;
*dstpos++ = offset >> 8;
*dstpos++ = offset;
*dstpos++ = (count - 5);
}
for (; lit; --lit)
*dstpos++ = src[srcpos++];
srcpos += count;
return true;
}
};
/*
* The following two functions (longest_match and compress) are loosely
* adapted from zlib 1.2.3's deflate.c, and are probably still covered by
* the zlib license, which carries this notice:
*/
/* zlib.h -- interface of the 'zlib' general purpose compression library
version 1.2.3, July 18th, 2005
Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Jean-loup Gailly Mark Adler
jloup@gzip.org madler@alumni.caltech.edu
The data format used by the zlib library is described by RFCs (Request for
Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt
(zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
*/
static inline unsigned longest_match(int cur_match, const Hash &hash, const byte *const src, const byte *const srcend,
unsigned const pos, unsigned const remaining, unsigned const prev_length,
unsigned *pmatch_start)
{
unsigned chain_length = MAX_CHAIN; /* max hash chain length */
int best_len = prev_length; /* best match length so far */
int nice_match = NICE_LENGTH; /* stop if match long enough */
int limit = pos > MAX_DIST ? pos - MAX_DIST + 1 : 0;
/* Stop when cur_match becomes < limit. */
const byte *const scan = src + pos;
/* This is important to avoid reading past the end of the memory block */
if (best_len >= (int)remaining)
return remaining;
const int max_match = (remaining < MAX_MATCH) ? remaining : MAX_MATCH;
byte scan_end1 = scan[best_len - 1];
byte scan_end = scan[best_len];
/* Do not waste too much time if we already have a good match: */
if (prev_length >= GOOD_LENGTH)
{
chain_length >>= 2;
}
/* Do not look for matches beyond the end of the input. This is necessary
* to make deflate deterministic.
*/
if ((unsigned)nice_match > remaining)
nice_match = remaining;
do
{
assert(cur_match < pos);
const byte *match = src + cur_match;
/* Skip to next match if the match length cannot increase
* or if the match length is less than 2.
*/
if (match[best_len] != scan_end || match[best_len - 1] != scan_end1 || match[0] != scan[0] ||
match[1] != scan[1])
continue;
/* It is not necessary to compare scan[2] and match[2] since they
* are always equal when the other bytes match, given that
* the hash keys are equal and that HASH_BITS >= 8.
*/
assert(scan[2] == match[2]);
int len = 2;
do
{
++len;
} while (len < max_match && scan[len] == match[len]);
if (len > best_len)
{
*pmatch_start = cur_match;
best_len = len;
if (len >= nice_match || scan + len >= srcend)
break;
scan_end1 = scan[best_len - 1];
scan_end = scan[best_len];
}
} while ((cur_match = hash.getprev(cur_match)) >= limit && --chain_length > 0);
return best_len;
}
/* Returns the end of the compressed data if successful, or NULL if we overran the output buffer */
byte *compress(const byte *src, const byte *srcend, byte *dst, byte *dstend, bool pad)
{
unsigned match_start = 0;
unsigned match_length = MIN_MATCH - 1; /* length of best match */
bool match_available = false; /* set if previous match exists */
unsigned pos = 0, remaining = srcend - src;
if (remaining >= 16777216)
return 0;
dbpf_compressed_file_header *hdr = NULL;
CompressedOutput compressed_output(src, dst + hdr->sz(0x10), dstend);
Hash hash;
hash.update(src[0]);
hash.update(src[1]);
while (remaining)
{
unsigned prev_length = match_length;
unsigned prev_match = match_start;
match_length = MIN_MATCH - 1;
int hash_head = -1;
if (remaining >= MIN_MATCH)
{
hash.update(src[pos + MIN_MATCH - 1]);
hash_head = hash.insert(pos);
}
if (hash_head >= 0 && prev_length < MAX_LAZY && pos - hash_head <= MAX_DIST)
{
match_length = longest_match(hash_head, hash, src, srcend, pos, remaining, prev_length, &match_start);
/* If we can't encode it, drop it. */
if ((match_length <= 3 && pos - match_start > 1024) || (match_length <= 4 && pos - match_start > 16384))
match_length = MIN_MATCH - 1;
}
/* If there was a match at the previous step and the current
* match is not better, output the previous match:
*/
if (prev_length >= MIN_MATCH && match_length <= prev_length)
{
if (!compressed_output.emit(prev_match, pos - 1, prev_length))
return 0;
/* Insert in hash table all strings up to the end of the match.
* pos-1 and pos are already inserted. If there is not
* enough lookahead, the last two strings are not inserted in
* the hash table.
*/
remaining -= prev_length - 1;
prev_length -= 2;
do
{
++pos;
if (src + pos <= srcend - MIN_MATCH)
{
hash.update(src[pos + MIN_MATCH - 1]);
hash.insert(pos);
}
} while (--prev_length != 0);
match_available = false;
match_length = MIN_MATCH - 1;
++pos;
}
else
{
match_available = true;
++pos;
--remaining;
}
}
assert(pos == srcend - src);
if (!compressed_output.emit(pos, pos, 0))
return 0;
byte *dstsize = compressed_output.get_end();
if (pad && dstsize < dstend)
{
memset(dstsize, 0xFC, dstend - dstsize);
dstsize = dstend;
}
hdr = (dbpf_compressed_file_header *)dst;
put(hdr->compression_id, DBPF_COMPRESSION_QFS);
put(hdr->ucsize, srcend - src);
return dstsize;
}
cmake_minimum_required(VERSION 3.0)
project(s3rc)
set(s3rc_src
benrg.cpp
dbpf.cpp
dbpp.cpp
hash.cpp
s3pack.cpp
s3rc.cpp
)
add_executable(s3rc ${s3rc_src})
#include "dbpf.h"
DBPF::DBPF()
{
memset(&hdr, 0, sizeof(DBPF_HEADER));
strncpy(hdr.magic, "DBPF", 4);
hdr.maj_ver = 2;
hdr.idxsize = 4;
hdr.idxver = 3;
hdr.idxoffs = 0x60;
files = NULL;
}
DBPF::DBPF(FILE *fp, uint32 length)
{
memset(&hdr, 0, sizeof(DBPF_HEADER));
uint32 sos = ftell(fp);
if (length == 0)
{
fseek(fp, 0, SEEK_END);
length = ftell(fp) - sos;
fseek(fp, sos, SEEK_SET);
}
fread(&hdr, sizeof(hdr), 1, fp);
if (!strncmp(hdr.magic, "DBPP", 4))
{
if (!fix_header(fp, &hdr, sos, sos + length, false))
{
printf("FAIL: Couldn't fix bad DBPF header!\n");
exit(1);
}
}
if (strncmp(hdr.magic, "DBPF", 4))
{
printf("FATAL: Specified file is not "
"recognizeable DBPF!\n");
exit(1);
}
files = (DBPF_ENTRY **)calloc(hdr.idxcount, sizeof(DBPF_ENTRY *));
byte *idxdata = (byte *)calloc(hdr.idxsize, 1);
fseek(fp, sos + hdr.idxoffs, SEEK_SET);
fread(idxdata, hdr.idxsize, 1, fp);
DBPF_INDEX *idx = new DBPF_INDEX(idxdata, hdr.idxcount);
free(idxdata);
uint32 i, j;
for (i = 0; i < hdr.idxcount; i++)
{
INDEX_ENTRY *ie = idx->getentry(i);
if (ie == NULL)
continue;
fseek(fp, sos + ie->offset, SEEK_SET);
DBPF_ENTRY *de = new DBPF_ENTRY(fp, ie);
files[i] = de;
de->root = this;
if (!i || files[i]->ie == NULL || files[i]->xlp != NULL)
continue;
j = i;
do
{
j--;
if (files[j]->ie == NULL || files[j]->heir != NULL ||
files[i]->ie->compress_size != files[j]->ie->compress_size)
continue;
if (files[i]->ie->offset == files[j]->ie->offset ||
!memcmp(files[i]->data, files[j]->data, files[i]->ie->compress_size & ~0x80000000))
{
files[i]->xlp = files[j];
files[j]->heir = files[i];
if (--files[i]->data->refs <= 0)
delete files[i]->data;
files[i]->data = files[j]->data;
files[j]->data->refs++;
files[i]->update_idx();
break;
}
} while (j);
}
delete idx;
return;
}
DBPF::~DBPF()
{
if (this->files)
{
for (uint32 i = 0; i < hdr.idxcount; i++)
{
if (files[i])
delete files[i];
files[i] = NULL;
}
free(files);
}
}
void DBPF::append(DBPF *adb)
{
if (adb->hdr.idxcount <= 0 || (this->hdr.idxcount + adb->hdr.idxcount) == 0)
return;
for (uint32 i = this->hdr.idxcount; i < this->hdr.idxcount + adb->hdr.idxcount; i++)
{
DBPF_ENTRY *ne = new DBPF_ENTRY(adb->files[i - this->hdr.idxcount]);
append(ne);
}
return;
}
void DBPF::append(DBPF_ENTRY *ne)
{
uint32 oe = get(ne->ie->type, ne->ie->group, ne->ie->instance);
if (oe != 0xFFFFFFFF)
{
delete this->files[oe];
this->files[oe] = ne;
}
else
{
DBPF_ENTRY **nfiles = (DBPF_ENTRY **)calloc(1, sizeof(DBPF_ENTRY *) * (this->hdr.idxcount + 1));
if (this->files)
{
memcpy(nfiles, this->files, sizeof(DBPF_ENTRY *) * this->hdr.idxcount);
free(files);
}
files = nfiles;
files[hdr.idxcount] = ne;
hdr.idxcount++;
}
ne->root = this;
int i = hdr.idxcount - 1;
for (int j = i - 1; j >= 0; j--)
{
if (files[j]->ie == NULL || files[j]->heir != NULL ||
files[i]->ie->compress_size != files[j]->ie->compress_size)
continue;
if (files[i]->ie->offset == files[j]->ie->offset ||
!memcmp(files[i]->data, files[j]->data, files[i]->ie->compress_size & ~0x80000000))
{
files[i]->xlp = files[j];
files[j]->heir = files[i];
if (--files[i]->data->refs <= 0)
delete files[i]->data;
files[i]->data = files[j]->data;
files[j]->data->refs++;
files[i]->update_idx();
break;
}
}
return;
}
void DBPF::compress()
{
if (hdr.idxcount <= 0 || files == NULL)
return;
for (uint32 i = 0; i < hdr.idxcount; i++)
{
if (files[i] && files[i]->xlp == NULL)
files[i]->compress();
files[i]->update_idx();
}
return;
}
void DBPF::decompress()
{
if (hdr.idxcount <= 0 || files == NULL)
return;
for (uint32 i = 0; i < hdr.idxcount; i++)
{
if (files[i] && files[i]->xlp == NULL)
files[i]->decompress();
files[i]->update_idx();
}
return;
}
void DBPF::recompress()
{
if (hdr.idxcount <= 0 || files == NULL)
return;
for (uint32 i = 0; i < hdr.idxcount; i++)
{
if (files[i] && files[i]->xlp == NULL && files[i]->ie->compress_flags)
files[i]->compress();
files[i]->update_idx();
}
return;
}
void DBPF::cleanse_evil()
{
for (uint32 i = 0; i < hdr.idxcount; i++)
{
files[i]->cleanse_evil();
}
}
void DBPF::write(FILE *fp)
{
uint32 i;
uint32 os, sos = ftell(fp);
fwrite(&hdr, sizeof(DBPF_HEADER), 1, fp);
filesize();
DBPF_INDEX *idx = new DBPF_INDEX(hdr.idxcount);
for (i = 0; i < hdr.idxcount; i++)
{
if (files[i]->xlp == NULL)
files[i]->write(fp);
memcpy(idx->getentry(i), files[i]->ie, sizeof(INDEX_ENTRY));
}
os = ftell(fp);
idx->refactor();
hdr.idxoffs = os - sos;
hdr.idxsize = idx->size();
fseek(fp, sos, SEEK_SET);
fwrite(&hdr, sizeof(DBPF_HEADER), 1, fp);
fseek(fp, os, SEEK_SET);
idx->writeall(fp);
delete idx;
return;
}
uint32 DBPF::get(uint32 type, uint32 group, uint64 instance)
{
for (uint32 i = 0; i < this->hdr.idxcount; i++)
{
if (files[i]->ie->type == type && files[i]->ie->group == group && files[i]->ie->instance == instance)
return i;
}
return 0xFFFFFFFF;
}
uint32 DBPF::filesize()
{
uint32 csz = 0;
csz += sizeof(DBPF_HEADER);
DBPF_INDEX *idx = new DBPF_INDEX(hdr.idxcount);
for (uint32 i = 0; i < hdr.idxcount; i++)
{
files[i]->ie->offset = csz;
if (files[i]->xlp)
{
files[i]->update_idx();
}
else
{
csz += files[i]->ie->compress_size & ~0x80000000;
}
memcpy(idx->getentry(i), files[i]->ie, sizeof(INDEX_ENTRY));
}
idx->refactor();
hdr.idxoffs = csz;
hdr.idxsize = idx->size();
csz += hdr.idxsize;
delete idx;
return csz;
}
DBPF_INDEX::DBPF_INDEX(uint32 sz)
{
memset(this, 0, sizeof(DBPF_INDEX));
this->header = (uint32 *)malloc(sizeof(uint32) * 4);
memset(this->header, 0, sizeof(uint32) * 4);
this->entry_count = sz;
this->entries = (INDEX_ENTRY *)malloc(sizeof(INDEX_ENTRY) * sz);
memset(entries, 0, sizeof(INDEX_ENTRY) * sz);
}
DBPF_INDEX::DBPF_INDEX(byte *data, uint32 count)
{
uint32 *hptr;
byte *dptr;
uint32 i, f;
uint64 ih;
memset(this, 0, sizeof(DBPF_INDEX));
header = (uint32 *)calloc(4, sizeof(uint32));
i = 0;
hptr = (uint32 *)data;
header[IDX_HDR_FLAGS] = hptr[i++];
f = header[IDX_HDR_FLAGS];
if (f & IDX_HAS_PACKAGE_TYPE)
{
header[IDX_HDR_TYPE] = hptr[i++];
}
else
{
header[IDX_HDR_TYPE] = 0;
}
if (f & IDX_HAS_PACKAGE_GROUP)
{
header[IDX_HDR_GROUP] = hptr[i++];
}
else
{
header[IDX_HDR_HIINST] = 0;
}
if (f & IDX_HAS_PACKAGE_HIINST)
{
header[IDX_HDR_HIINST] = hptr[i++];
}
else
{
header[IDX_HDR_HIINST] = 0;
}
entry_count = count;
entries = (INDEX_ENTRY *)malloc(sizeof(INDEX_ENTRY) * entry_count);
memset(entries, 0, sizeof(INDEX_ENTRY) * entry_count);
#if defined(DEBUG)
printf("Header Flags: 0x%X, Size: %d, ES: %d\n", f, header_size(), entry_size());
#endif
for (i = 0; i < entry_count; i++)
{
dptr = data + header_size() + (entry_size() * i);
if (f & IDX_HAS_PACKAGE_TYPE)
{
entries[i].type = header[IDX_HDR_TYPE];
hptr += 1;
}
else
{
memcpy(&entries[i].type, dptr, sizeof(uint32));
dptr += sizeof(uint32);
}
if (f & IDX_HAS_PACKAGE_GROUP)
{
entries[i].group = header[IDX_HDR_GROUP];
}
else
{
memcpy(&entries[i].group, dptr, sizeof(uint32));
dptr += sizeof(uint32);
}
if (f & IDX_HAS_PACKAGE_HIINST)
{
ih = header[IDX_HDR_HIINST];
entries[i].instance = 0;
memcpy(&entries[i].instance, dptr, sizeof(uint32));
dptr += sizeof(uint32);
entries[i].instance |= (ih << 32) & 0xFFFFFFFF00000000;
}
else
{
memcpy(((uint32 *)(&entries[i].instance)) + 1, dptr, sizeof(uint32));
dptr += sizeof(uint32);
memcpy(((uint32 *)(&entries[i].instance)), dptr, sizeof(uint32));
dptr += sizeof(uint32);
}
#if defined(DEBUG)
printf("Entry %d, Got instance 0x%16.16I64X\n", i, entries[i].instance);
#endif
memcpy(&entries[i].offset, dptr, sizeof(uint32));
dptr += sizeof(uint32);
memcpy(&entries[i].compress_size, dptr, sizeof(uint32));
dptr += sizeof(uint32);
memcpy(&entries[i].decompress_size, dptr, sizeof(uint32));
dptr += sizeof(uint32);
memcpy(&entries[i].compress_flags, dptr, sizeof(uint16));
dptr += sizeof(uint16);
memcpy(&entries[i].flags, dptr, sizeof(uint16));
dptr += sizeof(uint16);
}
return;
}
DBPF_INDEX::~DBPF_INDEX()
{
if (header)
free(header);
if (entries)
free(entries);
}
uint32 DBPF_INDEX::flags()
{
if (header != NULL)
{
return header[IDX_HDR_FLAGS];
}
else
{
return 0;
}
}
INDEX_ENTRY *DBPF_INDEX::getentry(uint32 i)
{
if (entries && i < entry_count)
{
return entries + i;
}
return NULL;
}
uint32 DBPF_INDEX::header_size(uint32 flgs)
{
int sz = sizeof(uint32);
if (flgs & IDX_HAS_PACKAGE_TYPE)
{
sz += sizeof(uint32);
}
if (flgs & IDX_HAS_PACKAGE_GROUP)
{
sz += sizeof(uint32);
}
if (flgs & IDX_HAS_PACKAGE_HIINST)
{
sz += sizeof(uint32);
}
return sz;
}
uint32 DBPF_INDEX::entry_size()
{
uint32 sz = sizeof(INDEX_ENTRY);
if (flags() & IDX_HAS_PACKAGE_TYPE)
{
sz -= sizeof(uint32);
}
if (flags() & IDX_HAS_PACKAGE_GROUP)
{
sz -= sizeof(uint32);
}
if (flags() & IDX_HAS_PACKAGE_HIINST)
{
sz -= sizeof(uint32);
}
return sz;
}
uint32 DBPF_INDEX::size()
{
return header_size() + (entry_size() * (entry_count - discards));
}
void DBPF_INDEX::writeall(FILE *fp)
{
uint32 i;
fwrite(header, sizeof(uint32), 1, fp);
if (flags() & IDX_HAS_PACKAGE_TYPE)
{
fwrite(header + IDX_HDR_TYPE, sizeof(uint32), 1, fp);
}
if (flags() & IDX_HAS_PACKAGE_GROUP)
{
fwrite(header + IDX_HDR_GROUP, sizeof(uint32), 1, fp);
}
if (flags() & IDX_HAS_PACKAGE_HIINST)
{
fwrite(header + IDX_HDR_HIINST, sizeof(uint32), 1, fp);
}
for (i = 0; i < entry_count; i++)
{
if (entries[i].offset == 0xFFFFFFFF)
continue;
write_entry(fp, i);
}
return;
}
void DBPF_INDEX::write_entry(FILE *fp, uint32 i)
{
INDEX_ENTRY *entry = getentry(i);
uint32 j;
if (entry == NULL)
return;
if (!(flags() & IDX_HAS_PACKAGE_TYPE))
{
fwrite(&entry->type, sizeof(uint32), 1, fp);
}
if (!(flags() & IDX_HAS_PACKAGE_GROUP))
{
fwrite(&entry->group, sizeof(uint32), 1, fp);
}
if (flags() & IDX_HAS_PACKAGE_HIINST)
{
j = (uint32)(entry->instance & 0xFFFFFFFF);
fwrite(&j, sizeof(uint32), 1, fp);
}
else
{
j = (uint32)((entry->instance >> 32) & 0xFFFFFFFF);
fwrite(&j, sizeof(uint32), 1, fp);
j = (uint32)(entry->instance & 0xFFFFFFFF);
fwrite(&j, sizeof(uint32), 1, fp);
}
fwrite(&entry->offset, sizeof(uint32), 1, fp);
fwrite(&entry->compress_size, sizeof(uint32), 1, fp);
fwrite(&entry->decompress_size, sizeof(uint32), 1, fp);
fwrite(&entry->compress_flags, sizeof(uint16), 1, fp);
fwrite(&entry->flags, sizeof(uint16), 1, fp);
}
void DBPF_INDEX::refactor()
{
uint32 i;
if (entry_count > 0)
{
header[IDX_HDR_TYPE] = entries[0].type;
header[IDX_HDR_GROUP] = entries[0].group;
header[IDX_HDR_HIINST] = (uint32)((entries[0].instance >> 32) & 0x00000000FFFFFFFF);
header[IDX_HDR_FLAGS] = IDX_HAS_PACKAGE_TYPE | IDX_HAS_PACKAGE_GROUP | IDX_HAS_PACKAGE_HIINST;
}
else
{
return;
}
for (i = 0; i < entry_count; i++)
{
if (entries[i].offset == 0xFFFFFFFF)
continue;
if (header[IDX_HDR_TYPE] != entries[i].type)
{
header[IDX_HDR_FLAGS] &= ~IDX_HAS_PACKAGE_TYPE;
}
if (header[IDX_HDR_GROUP] != entries[i].group)
{
header[IDX_HDR_FLAGS] &= ~IDX_HAS_PACKAGE_GROUP;
}
if (header[IDX_HDR_HIINST] != (uint32)((entries[i].instance >> 32) & 0x00000000FFFFFFFF))
{
header[IDX_HDR_FLAGS] &= ~IDX_HAS_PACKAGE_HIINST;
}
}
return;
}
DBPF_ENTRY::DBPF_ENTRY(DBPF_ENTRY *orig)
{
memset(this, 0, sizeof(DBPF_ENTRY));
if (orig->ie == NULL)
{
this->ie = NULL;
this->data = NULL;
return;
}
this->ie = (INDEX_ENTRY *)calloc(1, sizeof(INDEX_ENTRY));
memcpy(this->ie, orig->ie, sizeof(INDEX_ENTRY));
this->data = orig->data;
this->data->refs++;
return;
}
DBPF_ENTRY::DBPF_ENTRY(FILE *fp, INDEX_ENTRY *ies)
{
memset(this, 0, sizeof(DBPF_ENTRY));
ie = (INDEX_ENTRY *)calloc(1, sizeof(INDEX_ENTRY));
memcpy(ie, ies, sizeof(INDEX_ENTRY));
data = new DATA(ie->compress_size & ~0x80000000);
fread(data->data, ie->compress_size & ~0x80000000, 1, fp);
}
DBPF_ENTRY::~DBPF_ENTRY()
{
if (this->xlp != NULL)
this->xlp->heir = this->heir;
if (this->heir != NULL)
this->heir->xlp = this->xlp;
if (ie)
free(ie);
if (data && --data->refs <= 0)
delete data;
}
void DBPF_ENTRY::compress()
{
uint32 d32;
if (data == NULL)
return;
byte *recompressed = NULL, *uncompressed = getdata();
if ((ie->compress_size & ~0x80000000) != ie->decompress_size)
{
uncompressed = (byte *)calloc(1, ie->decompress_size);
if (!benrg_decompress(getdata(), ie->compress_size & ~0x80000000, uncompressed, ie->decompress_size, false))
{
printf("FATAL: Couldn't decompress data at 0x%X: Probably corrupt file\n", ie->offset);
free(uncompressed);
exit(1);
}
}
recompressed = try_compress(uncompressed, ie->decompress_size, &d32);
if (recompressed != NULL && d32 < (ie->compress_size & ~0x80000000))
{
if (uncompressed != getdata())
free(this->data->data);
this->data->data = recompressed;
ie->compress_flags = 0xFFFF;
ie->compress_size = d32 | 0x80000000;
}
else
{
if (recompressed)
free(recompressed);
}
if (uncompressed != getdata())
free(uncompressed);
}
void DBPF_ENTRY::decompress()
{
if ((ie->compress_size & ~0x80000000) != ie->decompress_size)
{
byte *uncompressed = (byte *)calloc(1, ie->decompress_size);
if (!benrg_decompress(getdata(), ie->compress_size & ~0x80000000, uncompressed, ie->decompress_size, false))
{
printf("FATAL: Couldn't decompress data at 0x%X: Probably corrupt file\n", ie->offset);
free(uncompressed);
exit(1);
}
free(this->data->data);
this->data->data = uncompressed;
ie->compress_size = ie->decompress_size | 0x80000000;
ie->compress_flags = 0;
}
return;
}
void DBPF_ENTRY::write(FILE *fp)
{
fwrite(getdata(), ie->compress_size & ~0x80000000, 1, fp);
}
void DBPF_ENTRY::update_idx()
{
if (this->xlp)
{
this->xlp->update_idx();
uint32 ty = this->ie->type;
uint32 gr = this->ie->group;
uint64 in = this->ie->instance;
memcpy(this->ie, this->xlp->ie, sizeof(INDEX_ENTRY));
this->ie->type = ty;
this->ie->group = gr;
this->ie->instance = in;
}
return;
}
#define IS_EVIL_GID(g) (((g)&0xFF000000) == 0x01000000 || ((g)&0xFF000000) == 0x03000000)
#define REMOVE_EVIL(g) (g &= 0xFEFFFFFF)
void DBPF_ENTRY::cleanse_evil()
{
if (IS_EVIL_GID(ie->group))
{
#if defined(DEBUG)
printf("Cleansing EVIL in T:0x%8.8X G:0x%8.8X I:0x%16.16I64X!\n", ie->type, ie->group, ie->instance);
#endif
REMOVE_EVIL(ie->group);
}
uint32 ty, gr;
uint64 in;
if (this->xlp)
{
update_idx();
return;
}
if (this->ie->decompress_size == 0)
return;
bool compressed = false, dirty = false;
byte *s = NULL, *e = NULL;
uint32 *gp = NULL;
char *c;
uint64 qword = 0;
uint32 dworda = 0, dwordb = 0, i = 0, j = 0;
uint16 sword = 0;
byte hword = 0;
compressed = this->ie->compress_flags != 0;
switch (this->ie->type)
{
default:
compressed = false;
break;
case 0x73E93EEB:
if (compressed)
this->decompress();
this->data->data = (byte *)realloc(this->data->data, this->ie->decompress_size + 1);
this->data->data[this->ie->decompress_size] = 0;
while ((s = (byte *)strstr((char *)this->data->data, "paidcontent=\"true\"")))
{
e = this->data->data + this->ie->decompress_size;
char *nd = (char *)calloc(1, this->ie->decompress_size + 2);
memcpy(nd, this->data->data, s - this->data->data);
uint32 ks = s - this->data->data;
sprintf(nd + ks, "paidcontent=\"false\"");
s += strlen("paidcontent=\"false\"");
memcpy(nd + ks + strlen("paidcontent=\"false\"") + 1, s, e - s);
s = (byte *)nd + (s - this->data->data) + strlen("paidcontent=\"false\"");
free(this->data->data);
this->data->data = (byte *)nd;
this->ie->decompress_size++;
this->ie->compress_size++;
}
s = this->data->data;
while ((s = (byte *)strstr((char *)s, "<reskey>")))
{
if ((s = (byte *)strstr((char *)s, ":")) && *(s + 9) == ':')
{
#if defined(DEBUG)
char buf[35];
#endif
s += 9;
if (!strncmp((char *)s, ":01", 3))
{
#if defined(DEBUG)
memset(buf, 0, 35);
memcpy(buf, s - 8, 34);
printf("Cleared EVIL %s from manifest!\n", buf);
#endif
memcpy(s, ":00", 3);
}
else if (!strncmp((char *)s, ":03", 3))
{
#if defined(DEBUG)
memset(buf, 0, 35);
memcpy(buf, s - 8, 34);
printf("Cleared EVIL %s from manifest!\n", buf);
#endif
memcpy(s, ":02", 3);
}
}
#if defined(DEBUG)
else
{
printf("WARNING: Mangled manifest entry!\n");
}
#endif
}
break;
case 0x0358B08A:
case 0x0418FE2A:
case 0x049CA4CD:
case 0x04F3CC01:
case 0x062C8204:
case 0x02DC343F:
case 0x319E4F1D:
if (compressed)
this->decompress();
s = this->data->data + sizeof(uint32);
memcpy(&dworda, s, sizeof(uint32));
s += sizeof(uint32);
memcpy(&dwordb, s, sizeof(uint32));
if (dwordb == 0)
break;
s += dworda;
memcpy(&dwordb, s, sizeof(uint32));
s += sizeof(uint32);
for (i = 0; i < dwordb; i++)
{
memcpy(&ty, s, sizeof(uint32));
memcpy(&gr, s + sizeof(uint32), sizeof(uint32));
memcpy(&in, s + sizeof(uint32) + sizeof(uint32), sizeof(uint64));
if (IS_EVIL_GID(gr))
{
#if defined(DEBUG)
printf("Cleansing EVIL reference in 0x%8.8X to T:0x%8.8X G:0x%8.8X I:0x%16.16I64X!\n", ie->type, ty, gr,
in);
#endif
REMOVE_EVIL(gr);
memcpy(s + sizeof(uint32), &gr, sizeof(uint32));
}
s += sizeof(uint64) + (2 * sizeof(uint32));
}
break;
case 0x034AEECB:
if (compressed)
this->decompress();
s = this->data->data + (2 * sizeof(uint32));
memcpy(&dworda, s, sizeof(uint32));
s += sizeof(uint32);
for (i = 0; i < dworda; i++)
{
memcpy(&dwordb, s, sizeof(uint32));
s += sizeof(uint32);
e = (byte *)calloc(dwordb + 1, 1);
for (j = 0; j < dwordb; j++)
{
memcpy(e + j, s + (sizeof(uint16) * j), sizeof(byte));
}
c = (char *)e;
dirty = false;
while ((c = strstr(c, "=\"key:")))
{
c += strlen("=\"key:");
c += 8;
if (!strncmp(c, ":01", 3))
{
dirty = true;
memcpy(c, ":00", 3);
#if defined(DEBUG)
printf("Cleansing EVIL reference in CASPart T:0x%8.8X G:0x%8.8X I:0x%16.16I64X!\n", ie->type,
ie->group, ie->instance);
#endif
}
}
if (dirty)
{
for (j = 0; j < dwordb; j++)
{
memcpy(s + (sizeof(uint16) * j), e + j, sizeof(byte));
}
}
free(e);
e = NULL;
s += sizeof(uint16) * dwordb;
s += sizeof(uint32);
}
case 0x025ED6F4:
case 0x033A1435:
case 0x0341ACC9:
if (compressed && ie->type != 0x034AEECB)
this->decompress();
s = this->data->data + sizeof(uint32);
memcpy(&dworda, s, sizeof(uint32));
hword = sizeof(byte);
switch (ie->type)
{
case 0x033A1435:
case 0x0341ACC9:
s += sizeof(uint32) - 1;
break;
case 0x025ED6F4:
case 0x034AEECB:
s += sizeof(uint32);
break;
}
s += dworda;
memcpy(&hword, s, sizeof(byte));
s += sizeof(byte);
for (i = 0; i < hword; i++)
{
memcpy(&in, s, sizeof(uint64));
memcpy(&gr, s + sizeof(uint64), sizeof(uint32));
memcpy(&ty, s + sizeof(uint64) + sizeof(uint32), sizeof(uint32));
if (IS_EVIL_GID(gr))
{
#if defined(DEBUG)
printf("Cleansing EVIL reference to T:0x%8.8X G:0x%8.8X I:0x%16.16I64X!\n", ty, gr, in);
#endif
REMOVE_EVIL(gr);
memcpy(s + sizeof(uint64), &gr, sizeof(uint32));
} /*if((in&0xFFFFFFFFFF000000)==0x0000000001000000){
#if defined(DEBUG)
printf("Fixing Crapulated CASPart T:0x%8.8X G:0x%8.8X I:0x%16.16I64X ->
0x%16.16I64X!\n",ty,gr,in,in&0xFFFFFFFF00FFFFFF);
#endif
in&=0xFFFFFFFF00FFFFFF;memcpy(s,&in,sizeof(uint64));}*/
s += sizeof(uint64) + (2 * sizeof(uint32));
}
break;
case 0x736884F1:
if ((ie->instance & 0xFFFFFFFFFF000000) == 0x0000000001000000)
{
#if defined(DEBUG)
printf("Fixing Crapulated T:0x%8.8X G:0x%8.8X I:0x%16.16I64X -> 0x%16.16I64X!\n", ie->type, ie->group,
ie->instance, ie->instance & 0xFFFFFFFF00FFFFFF);
#endif
}
case 0x015A1849:
case 0x01661233:
case 0x01D10F34:
case 0x0355E0A6:
case 0x03B4C61D:
case 0x63A33EA7:
case 0xD3044521:
case 0xD382BF57:
if (compressed)
this->decompress();
s = this->data->data;
s += 3 * sizeof(uint32);
memcpy(&dworda, s, sizeof(uint32));
s += sizeof(uint32);
memcpy(&dwordb, s, sizeof(uint32));
s += sizeof(uint32);
for (i = 0; i < dwordb; i++)
{
memcpy(&in, s, sizeof(uint64));
memcpy(&ty, s + sizeof(uint64), sizeof(uint32));
memcpy(&gr, s + sizeof(uint64) + sizeof(uint32), sizeof(uint32));
if ((gr & 0xFF000000) == 0x01000000 || (gr & 0xFF000000) == 0x03000000)
{
#if defined(DEBUG)
printf("Cleansing EVIL reference to T:0x%8.8X G:0x%8.8X I:0x%16.16I64X!\n", ty, gr, in);
#endif
REMOVE_EVIL(gr);
memcpy(s + sizeof(uint64) + sizeof(uint32), &gr, sizeof(uint32));
} /*if((in&0xFFFFFFFFFF000000)==0x0000000001000000){
#if defined(DEBUG)
printf("Fixing Crapulated RCOL T:0x%8.8X G:0x%8.8X I:0x%16.16I64X -> 0x%16.16I64X!\n",ty,gr,in,in&0xFFFFFFFF00FFFFFF);
#endif
in&=0xFFFFFFFF00FFFFFF;memcpy(s,&in,sizeof(uint64));}*/
s += sizeof(uint64) + sizeof(uint32) + sizeof(uint32);
}
for (i = 0; i < dworda; i++)
{
memcpy(&in, s, sizeof(uint64));
memcpy(&ty, s + sizeof(uint64), sizeof(uint32));
memcpy(&gr, s + sizeof(uint64) + sizeof(uint32), sizeof(uint32));
if (IS_EVIL_GID(gr))
{
#if defined(DEBUG)
printf("Cleansing EVIL reference to T:0x%8.8X G:0x%8.8X I:0x%16.16I64X!\n", ty, gr, in);
#endif
REMOVE_EVIL(gr);
memcpy(s + sizeof(uint64) + sizeof(uint32), &gr, sizeof(uint32));
}
s += sizeof(uint64) + sizeof(uint32) + sizeof(uint32);
}
for (i = 0; i < dwordb; i++)
{
uint32 dwordc, dwordd;
memcpy(&dworda, s, sizeof(uint32));
s += sizeof(uint32);
memcpy(&dwordc, s, sizeof(uint32));
s += sizeof(uint32);
c = (char *)calloc(dwordc, 1);
memcpy(c, this->data->data + dworda, dwordc);
dirty = false;
memcpy(&dwordd, c, sizeof(uint32));
if (!strncmp(c, "VPXY", 4) || !strncmp(c, "GEOM", 4))
{
char magic[5];
memset(magic, 0, 5);
memcpy(magic, c, 4);
e = (byte *)c + sizeof(uint32) * 2;
memcpy(&dwordd, e, sizeof(uint32));
e += sizeof(uint32);
memcpy(&j, e, sizeof(uint32));
if (j > 0)
{
e += dwordd;
memcpy(&dwordd, e, sizeof(uint32));
e += sizeof(uint32);
}
else
{
dwordd = 0;
}
for (j = 0; j < dwordd; j++)
{
memcpy(&ty, e, sizeof(uint32));
memcpy(&gr, e + sizeof(uint32), sizeof(uint32));
memcpy(&in, e + (sizeof(uint32) * 2), sizeof(uint64));
if (IS_EVIL_GID(gr))
{
#if defined(DEBUG)
printf("Cleansing EVIL reference in %s to T:0x%8.8X G:0x%8.8X I:0x%16.16I64X!\n", magic, ty, gr,
in);
#endif
REMOVE_EVIL(gr);
memcpy(e + sizeof(uint32), &gr, sizeof(uint32));
dirty = true;
}
e += (sizeof(uint32) * 2) + sizeof(uint64);
}
}
if (dirty)
memcpy(this->data->data + dworda, c, dwordc);
free(c);
}
break;
case 0xD4D9FBE5:
if (compressed)
this->decompress();
s = this->data->data;
while ((e = (byte *)memmem(s, ie->decompress_size, "key:0333406c:01", strlen("key:0333406c:01"))) != NULL)
{
memcpy(e, "key:0333406c:00", strlen("key:0333406c:01"));
}
break;
case 0x06B981ED:
if (compressed)
this->decompress();
s = this->data->data;
memcpy(&dworda, s, sizeof(uint32));
s += sizeof(uint32);
if (strncmp((char *)s, "OBJS", 4))
{
printf("Bad OBJS: Unrecognized magic!\n");
break;
}
s += sizeof(uint32);
if (dworda < 0x500)
{
printf("Bad OBJS: Version 0x%X < 0x500!\n", dworda);
break;
}
s += 2 * sizeof(uint32);
s += 2 * sizeof(uint32);
memcpy(&dworda, s, sizeof(uint32));
s = this->data->data + dworda;
memcpy(&dworda, s, sizeof(uint32));
s += sizeof(uint32);
for (i = 0; i < dworda; i++)
{
memcpy(&ty, s, sizeof(uint32));
memcpy(&gr, s + sizeof(uint32), sizeof(uint32));
memcpy(&in, s + sizeof(uint32) + sizeof(uint32), sizeof(uint64));
if (IS_EVIL_GID(gr))
{
#if defined(DEBUG)
printf("OBJS Ref T:0x%8.8X G:0x%8.8X I:0x%16.16I64X fixed!\n", ty, gr, in);
#endif
REMOVE_EVIL(gr);
memcpy(s + sizeof(uint32), &gr, sizeof(uint32));
}
s += sizeof(uint32) + sizeof(uint32) + sizeof(uint64);
}
break;
case 0x05ED1226:
if (compressed)
this->decompress();
s = this->data->data;
memcpy(&sword, s, sizeof(uint16));
s += sizeof(uint16);
if (sword >= 3)
{
memcpy(&hword, s, sizeof(byte));
s += sizeof(byte);
}
memcpy(&dworda, s, sizeof(uint32));
s += sizeof(uint32);
if (sword >= 3)
{
hword = hword ? 4 : 2;
}
else
{
hword = dworda >= 65535 ? 4 : 2;
}
for (i = 0; i < dworda; i++)
{
if ((s + sizeof(uint32) + sizeof(uint32) + sizeof(uint64) + hword) >
this->data->data + this->ie->decompress_size)
{
printf("ERROR: BUFFER OVERRUN IN T:0x%8.8X! G:0x%8.8X I:%16.16LX!\n", ie->type, ie->group,
ie->instance);
break;
}
memcpy(&ty, s, sizeof(uint32));
memcpy(&gr, s + sizeof(uint32), sizeof(uint32));
memcpy(&in, s + sizeof(uint32) + sizeof(uint32), sizeof(uint64));
if (IS_EVIL_GID(gr))
{
#if defined(DEBUG)
printf("Clearing EVIL reference: 0x%8.8X:0x%8.8X:0x%16.16I64X\n", ty, gr, in);
fflush(stdout);
#endif
REMOVE_EVIL(gr);
memcpy(s + sizeof(uint32), &gr, sizeof(uint32));
}
s += sizeof(uint32) + sizeof(uint32) + sizeof(uint64) + hword;
}
break;
case 0xCF9A4ACE:
if (compressed)
this->decompress();
s = this->data->data;
s += sizeof(uint16);
memcpy(&dworda, s, sizeof(uint32));
s += sizeof(uint32) + dworda;
memcpy(&dworda, s, sizeof(uint32));
s += sizeof(uint32);
for (i = 0; i < dworda; i++)
{
memcpy(&ty, s, sizeof(uint32));
memcpy(&gr, s + sizeof(uint32), sizeof(uint32));
memcpy(&in, s + sizeof(uint32) + sizeof(uint32), sizeof(uint64));
if (IS_EVIL_GID(gr))
{
#if defined(DEBUG)
printf("Clearing EVIL reference: 0x%8.8X:0x%8.8X:0x%16.16I64X\n", ty, gr, in);
fflush(stdout);
#endif
REMOVE_EVIL(gr);
memcpy(s + sizeof(uint32), &gr, sizeof(uint32));
}
s += sizeof(uint32) + sizeof(uint32) + sizeof(uint64);
}
break;
case 0x34E5247C:
if (compressed)
this->decompress();
{
s = this->data->data;
dworda = 0x01661233;
dwordb = 0x01000001;
e = (byte *)&qword;
memcpy(e, &dworda, 4);
memcpy(e + 4, &dwordb, 4);
e = this->data->data;
i = this->ie->decompress_size;
while ((e = (byte *)memmem(s, i, &qword, sizeof(qword))) != NULL)
{
i -= e - s;
gp = (uint32 *)e;
gp++;
REMOVE_EVIL(*gp);
s = e;
}
s = this->data->data;
dworda = 0x319e4f1d;
dwordb = 0x01000000;
e = (byte *)&qword;
memcpy(e, &dworda, 4);
memcpy(e + 4, &dwordb, 4);
e = this->data->data;
i = this->ie->decompress_size;
while ((e = (byte *)memmem(s, i, &qword, sizeof(qword))) != NULL)
{
i -= e - s;
gp = (uint32 *)e;
gp++;
REMOVE_EVIL(*gp);
s = e;
}
}
break;
}
if (compressed)
this->compress();
return;
}
#if !defined(__DBPF_H)
#define __DBPF_H 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "files.h"
typedef struct dbpf_header
{
char magic[4]; // 0x00 - "DBPF"
uint32 maj_ver; // 0x04 - 2
uint32 min_ver; // 0x08 - 0
uint32 u_0C;
uint32 u_10;
uint32 u_14;
uint32 u_18;
uint32 u_1C;
uint32 u_20;
uint32 idxcount; // 0x24 - entrycount
uint32 u_28;
uint32 idxsize; // 0x2C - idxsize
uint32 u_30;
uint32 u_34;
uint32 u_38;
uint32 idxver; // 0x3C - 3
uint32 idxoffs; // 0x40
uint32 u_44;
uint32 u_48;
uint32 u_4C;
uint32 u_50;
uint32 u_54;
uint32 u_58;
uint32 u_5C;
} DBPF_HEADER;
typedef struct index_entry
{
uint32 type;
uint32 group;
uint64 instance;
uint32 offset;
uint32 compress_size;
uint32 decompress_size;
uint16 compress_flags;
uint16 flags;
} INDEX_ENTRY;
#define IDX_HAS_PACKAGE_TYPE 0x00000001
#define IDX_HAS_PACKAGE_GROUP 0x00000002
#define IDX_HAS_PACKAGE_HIINST 0x00000004
#define IDX_HDR_FLAGS 0
#define IDX_HDR_TYPE 1
#define IDX_HDR_GROUP 2
#define IDX_HDR_HIINST 3
class DATA
{
public:
byte *data;
int refs;
DATA()
{
memset(this, 0, sizeof(DATA));
refs++;
}
DATA(uint32 sz)
{
memset(this, 0, sizeof(DATA));
data = (byte *)calloc(1, sz);
refs++;
}
DATA(byte *dp)
{
memset(this, 0, sizeof(DATA));
data = dp;
refs++;
}
~DATA()
{
if (data)
free(data);
}
};
class DBPF;
class DBPF_ENTRY
{
public:
DBPF *root;
INDEX_ENTRY *ie;
DBPF_ENTRY *xlp;
DBPF_ENTRY *heir;
DATA *data;
DBPF_ENTRY() { memset(this, 0, sizeof(DBPF_ENTRY)); }
DBPF_ENTRY(DBPF_ENTRY *);
DBPF_ENTRY(FILE *, INDEX_ENTRY *);
~DBPF_ENTRY();
byte *getdata() { return data->data; }
void compress();
void decompress();
void write(FILE *);
void update_idx();
void cleanse_evil();
};
class DBPF : public BASICFILE
{
public:
DBPF_HEADER hdr;
DBPF_ENTRY **files;
DBPF();
DBPF(FILE *, uint32 length = 0);
~DBPF();
void append(DBPF *);
void append(DBPF_ENTRY *);
void compress();
void decompress();
void recompress();
void cleanse_evil();
virtual void write(FILE *);
virtual byte filetype() { return TYPE_DBPF; }
virtual uint32 filesize();
uint32 get(uint32 type, uint32 group, uint64 instance);
};
class DBPF_INDEX
{
public:
uint32 *header;
INDEX_ENTRY *entries;
uint32 entry_count;
uint32 discards;
DBPF_INDEX(uint32 sz);
DBPF_INDEX(byte *data, uint32 count);
~DBPF_INDEX();
uint32 flags();
INDEX_ENTRY *getentry(uint32 i);
uint32 header_size() { return header_size(flags()); }
uint32 header_size(uint32 flgs);
uint32 entry_size();
uint32 size();
void writeall(FILE *);
void write_entry(FILE *, uint32 i);
void refactor();
};
bool benrg_decompress(const byte *src, int compressed_size, byte *dst, int uncompressed_size, bool truncate);
byte *compress(const byte *src, const byte *srcend, byte *dst, byte *dstend, bool pad);
byte *try_compress(const byte *src, uint32 srclen, uint32 *dstlen);
bool fix_header(FILE *, DBPF_HEADER *);
bool fix_header(FILE *, DBPF_HEADER *, bool);
bool fix_header(FILE *, DBPF_HEADER *, int, int);
bool fix_header(FILE *, DBPF_HEADER *, int, int, bool);
uint64 fnv64(const byte *, uint32);
uint64 crc64(const byte *, uint32);
uint64 S3PackCRC64(const byte *, uint32);
#define UMAX(a, b) (((a) > (b)) ? (a) : (b))
#define UMIN(a, b) (((a) < (b)) ? (a) : (b))
#endif
#include "dbpf.h"
#define COMPTAIL_0 0x00010000
#define COMPTAIL_1 0x0001FFFF
bool fix_header(FILE *kinky, DBPF_HEADER *hdr)
{
fseek(kinky, 0, SEEK_END);
int end = ftell(kinky);
return fix_header(kinky, hdr, 0, end, false);
}
bool fix_header(FILE *kinky, DBPF_HEADER *hdr, bool force)
{
fseek(kinky, 0, SEEK_END);
int end = ftell(kinky);
return fix_header(kinky, hdr, 0, end, force);
}
bool fix_header(FILE *kinky, DBPF_HEADER *hdr, int start, int end)
{
return fix_header(kinky, hdr, start, end, false);
}
bool fix_header(FILE *kinky, DBPF_HEADER *hdr, int start, int end, bool force)
{
uint32 off, entrysize = 0;
uint32 idxcount = 1, idxsize = 0, hsize = 0;
char magic[4];
uint32 d32;
uint32 i, f, fc;
uint32 cs, ucs;
uint16 cf, fl;
fseek(kinky, start, SEEK_SET);
fread(magic, 4, 1, kinky);
if (!strncmp(magic, "DBPF", 4))
{
if (!force)
{
return false;
}
}
else if (strncmp(magic, "DBPP", 4))
{
return false;
}
if (end - start < 96)
{
return false;
}
fseek(kinky, end - 4, SEEK_SET);
off = ftell(kinky);
fread(&d32, sizeof(d32), 1, kinky);
fseek(kinky, off, SEEK_SET);
if (d32 != COMPTAIL_0 && d32 != COMPTAIL_1)
{
printf("Unrecognized compression tail 0x%X!\n", d32);
return false;
}
fc = 0;
do
{
#if defined(DEBUG)
printf("Index Size Guess Attempt #%d\n", fc + 1);
#endif
fseek(kinky, end - 20, SEEK_SET);
off = ftell(kinky);
entrysize = idxsize = hsize = f = 0;
idxcount = 1;
while (off - start >= 96)
{
fread(&d32, sizeof(d32), 1, kinky);
if (d32 == COMPTAIL_0 || d32 == COMPTAIL_1)
{
if (++f > fc)
{
fseek(kinky, 0, SEEK_CUR);
off = ftell(kinky);
entrysize = end - off;
#if defined(DEBUG)
printf("Guessing index entry size of %d\n", entrysize);
#endif
break;
}
}
fseek(kinky, off - 4, SEEK_SET);
off = ftell(kinky);
}
if (entrysize == 0)
{
fc++;
continue;
}
fseek(kinky, end - 4, SEEK_SET);
off = ftell(kinky);
while (1)
{
fseek(kinky, off - entrysize, SEEK_SET);
off = ftell(kinky);
fread(&d32, 1, sizeof(d32), kinky);
if (d32 == COMPTAIL_0 || d32 == COMPTAIL_1)
{
idxcount++;
}
else
{
break;
}
}
switch (entrysize - 16)
{
case 16:
hsize = 4;
break;
case 12:
hsize = 8;
break;
case 8:
hsize = 12;
break;
case 4:
hsize = 16;
break;
default:
hsize = 0xFFFFFFFF;
break;
}
if (hsize == 0xFFFFFFFF)
{
d32 = 0xFFFFFFFF;
}
else
{
fseek(kinky, end - (idxcount * entrysize) - hsize, SEEK_SET);
off = ftell(kinky);
fread(&d32, 1, sizeof(d32), kinky);
}
fc++;
if (!(d32 & ~0x0007))
{
#if defined(DEBUG)
printf("Possible valid index candidate for hsize %d, flags %d, entrysize %d, entrycount %d?\n", hsize, d32,
entrysize, idxcount);
#endif
fseek(kinky, off + hsize, SEEK_SET);
for (i = 0; i < idxcount; i++)
{
fseek(kinky, entrysize - 12, SEEK_CUR);
fread(&cs, sizeof(uint32), 1, kinky);
fread(&ucs, sizeof(uint32), 1, kinky);
fread(&cf, sizeof(uint16), 1, kinky);
fread(&fl, sizeof(uint16), 1, kinky);
if (cs & 0x80000000)
{
cs &= ~0x80000000;
}
else
{
#if defined(DEBUG)
printf("CS flag not set!\n");
#endif
break;
}
if (fl != 0x0001)
{
#if defined(DEBUG)
printf("Flag is 0x%X, not 0x0001\n", fl);
#endif
break;
}
if (cf == 0x0000)
{
if (cs != ucs)
{
#if defined(DEBUG)
printf("Not compressed, but cs!=ucs\n");
#endif
break;
}
}
else
{
if (cs > ucs)
{
#if defined(DEBUG)
printf("Compressed but cs > ucs? Probably wrong.\n");
#endif
break;
}
}
}
if (i < idxcount)
{
#if defined(DEBUG)
printf("Nope, try again.\n");
#endif
d32 = 0xFFFFFFFF;
}
#if defined(DEBUG)
else
{
printf("Looks good!\n");
}
#endif
}
} while (d32 & ~0x0007 && fc < 32);
if (d32 & ~0x0007)
{
printf("Bad index: 0x%X\n", d32);
return false;
}
memset(hdr, 0, sizeof(DBPF_HEADER));
strncpy(hdr->magic, "DBPF", 4);
hdr->maj_ver = 2;
hdr->idxcount = idxcount;
hdr->idxsize = end - off;
hdr->idxver = 3;
hdr->idxoffs = off - start;
return true;
}
#if !defined(__FILE_H)
#define __FILE_H
#include <stdint.h>
typedef uint64_t uint64;
typedef uint32_t uint32;
typedef uint16_t uint16;
typedef uint8_t byte;
#define TYPE_CRAP 0x00
#define TYPE_DBPF 0x01
#define TYPE_S3PACK 0x02
class BASICFILE
{
public:
virtual void write(FILE *) {}
virtual byte filetype() { return TYPE_CRAP; }
virtual uint32 filesize() { return 0; }
};
class CRAPFILE : public BASICFILE
{
public:
CRAPFILE(FILE *fp, uint32 sz)
{
data = (byte *)calloc(1, sz);
fread(data, sz, 1, fp);
size = sz;
}
~CRAPFILE()
{
if (data)
free(data);
size = 0;
}
virtual void write(FILE *fp) { fwrite(data, size, 1, fp); }
virtual uint32 filesize() { return size; }
uint32 size;
byte *data;
};
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <ctype.h>
#include "dbpf.h"
uint64 fnv64(const byte *data, uint32 length)
{
uint64 rez = 0xCBF29CE484222325;
uint32 i;
for (i = 0; i < length; i++)
{
rez *= 0x00000100000001B3;
rez ^= tolower(data[i]);
}
return rez;
}
static const uint64 g_au64CRC64[] = {
0x0000000000000000, 0x01B0000000000000, 0x0360000000000000, 0x02D0000000000000, 0x06C0000000000000,
0x0770000000000000, 0x05A0000000000000, 0x0410000000000000, 0x0D80000000000000, 0x0C30000000000000,
0x0EE0000000000000, 0x0F50000000000000, 0x0B40000000000000, 0x0AF0000000000000, 0x0820000000000000,
0x0990000000000000, 0x1B00000000000000, 0x1AB0000000000000, 0x1860000000000000, 0x19D0000000000000,
0x1DC0000000000000, 0x1C70000000000000, 0x1EA0000000000000, 0x1F10000000000000, 0x1680000000000000,
0x1730000000000000, 0x15E0000000000000, 0x1450000000000000, 0x1040000000000000, 0x11F0000000000000,
0x1320000000000000, 0x1290000000000000, 0x3600000000000000, 0x37B0000000000000, 0x3560000000000000,
0x34D0000000000000, 0x30C0000000000000, 0x3170000000000000, 0x33A0000000000000, 0x3210000000000000,
0x3B80000000000000, 0x3A30000000000000, 0x38E0000000000000, 0x3950000000000000, 0x3D40000000000000,
0x3CF0000000000000, 0x3E20000000000000, 0x3F90000000000000, 0x2D00000000000000, 0x2CB0000000000000,
0x2E60000000000000, 0x2FD0000000000000, 0x2BC0000000000000, 0x2A70000000000000, 0x28A0000000000000,
0x2910000000000000, 0x2080000000000000, 0x2130000000000000, 0x23E0000000000000, 0x2250000000000000,
0x2640000000000000, 0x27F0000000000000, 0x2520000000000000, 0x2490000000000000, 0x6C00000000000000,
0x6DB0000000000000, 0x6F60000000000000, 0x6ED0000000000000, 0x6AC0000000000000, 0x6B70000000000000,
0x69A0000000000000, 0x6810000000000000, 0x6180000000000000, 0x6030000000000000, 0x62E0000000000000,
0x6350000000000000, 0x6740000000000000, 0x66F0000000000000, 0x6420000000000000, 0x6590000000000000,
0x7700000000000000, 0x76B0000000000000, 0x7460000000000000, 0x75D0000000000000, 0x71C0000000000000,
0x7070000000000000, 0x72A0000000000000, 0x7310000000000000, 0x7A80000000000000, 0x7B30000000000000,
0x79E0000000000000, 0x7850000000000000, 0x7C40000000000000, 0x7DF0000000000000, 0x7F20000000000000,
0x7E90000000000000, 0x5A00000000000000, 0x5BB0000000000000, 0x5960000000000000, 0x58D0000000000000,
0x5CC0000000000000, 0x5D70000000000000, 0x5FA0000000000000, 0x5E10000000000000, 0x5780000000000000,
0x5630000000000000, 0x54E0000000000000, 0x5550000000000000, 0x5140000000000000, 0x50F0000000000000,
0x5220000000000000, 0x5390000000000000, 0x4100000000000000, 0x40B0000000000000, 0x4260000000000000,
0x43D0000000000000, 0x47C0000000000000, 0x4670000000000000, 0x44A0000000000000, 0x4510000000000000,
0x4C80000000000000, 0x4D30000000000000, 0x4FE0000000000000, 0x4E50000000000000, 0x4A40000000000000,
0x4BF0000000000000, 0x4920000000000000, 0x4890000000000000, 0xD800000000000000, 0xD9B0000000000000,
0xDB60000000000000, 0xDAD0000000000000, 0xDEC0000000000000, 0xDF70000000000000, 0xDDA0000000000000,
0xDC10000000000000, 0xD580000000000000, 0xD430000000000000, 0xD6E0000000000000, 0xD750000000000000,
0xD340000000000000, 0xD2F0000000000000, 0xD020000000000000, 0xD190000000000000, 0xC300000000000000,
0xC2B0000000000000, 0xC060000000000000, 0xC1D0000000000000, 0xC5C0000000000000, 0xC470000000000000,
0xC6A0000000000000, 0xC710000000000000, 0xCE80000000000000, 0xCF30000000000000, 0xCDE0000000000000,
0xCC50000000000000, 0xC840000000000000, 0xC9F0000000000000, 0xCB20000000000000, 0xCA90000000000000,
0xEE00000000000000, 0xEFB0000000000000, 0xED60000000000000, 0xECD0000000000000, 0xE8C0000000000000,
0xE970000000000000, 0xEBA0000000000000, 0xEA10000000000000, 0xE380000000000000, 0xE230000000000000,
0xE0E0000000000000, 0xE150000000000000, 0xE540000000000000, 0xE4F0000000000000, 0xE620000000000000,
0xE790000000000000, 0xF500000000000000, 0xF4B0000000000000, 0xF660000000000000, 0xF7D0000000000000,
0xF3C0000000000000, 0xF270000000000000, 0xF0A0000000000000, 0xF110000000000000, 0xF880000000000000,
0xF930000000000000, 0xFBE0000000000000, 0xFA50000000000000, 0xFE40000000000000, 0xFFF0000000000000,
0xFD20000000000000, 0xFC90000000000000, 0xB400000000000000, 0xB5B0000000000000, 0xB760000000000000,
0xB6D0000000000000, 0xB2C0000000000000, 0xB370000000000000, 0xB1A0000000000000, 0xB010000000000000,
0xB980000000000000, 0xB830000000000000, 0xBAE0000000000000, 0xBB50000000000000, 0xBF40000000000000,
0xBEF0000000000000, 0xBC20000000000000, 0xBD90000000000000, 0xAF00000000000000, 0xAEB0000000000000,
0xAC60000000000000, 0xADD0000000000000, 0xA9C0000000000000, 0xA870000000000000, 0xAAA0000000000000,
0xAB10000000000000, 0xA280000000000000, 0xA330000000000000, 0xA1E0000000000000, 0xA050000000000000,
0xA440000000000000, 0xA5F0000000000000, 0xA720000000000000, 0xA690000000000000, 0x8200000000000000,
0x83B0000000000000, 0x8160000000000000, 0x80D0000000000000, 0x84C0000000000000, 0x8570000000000000,
0x87A0000000000000, 0x8610000000000000, 0x8F80000000000000, 0x8E30000000000000, 0x8CE0000000000000,
0x8D50000000000000, 0x8940000000000000, 0x88F0000000000000, 0x8A20000000000000, 0x8B90000000000000,
0x9900000000000000, 0x98B0000000000000, 0x9A60000000000000, 0x9BD0000000000000, 0x9FC0000000000000,
0x9E70000000000000, 0x9CA0000000000000, 0x9D10000000000000, 0x9480000000000000, 0x9530000000000000,
0x97E0000000000000, 0x9650000000000000, 0x9240000000000000, 0x93F0000000000000, 0x9120000000000000,
0x9090000000000000};
uint64 crc64(const byte *arg, uint32 cb)
{
const byte *pu8 = arg;
uint64 uCRC64 = 0;
while (cb--)
{
uCRC64 = g_au64CRC64[(uCRC64 ^ *pu8++) & 0xff] ^ (uCRC64 >> 8);
}
return uCRC64;
}
static const uint64 table[] = {
0x0000000000000000, 0x9336EAA9EBE1F042, 0x266DD453D7C3E185, 0xB55B3EFA3C2211C7, 0xDFEC420E45663349,
0x4CDAA8A7AE87C30B, 0xF981965D92A5D2CC, 0x6AB77CF47944228E, 0xBED9851C8ACC6692, 0x2DEF6FB5612D96D0,
0x98B4514F5D0F8717, 0x0B82BBE6B6EE7755, 0x6135C712CFAA55DB, 0xF2032DBB244BA599, 0x475813411869B45E,
0xD46EF9E8F388441C, 0xEF85E190FF783D66, 0x7CB30B391499CD24, 0xC9E835C328BBDCE3, 0x5ADEDF6AC35A2CA1,
0x3069A39EBA1E0E2F, 0xA35F493751FFFE6D, 0x160477CD6DDDEFAA, 0x85329D64863C1FE8, 0x515C648C75B45BF4,
0xC26A8E259E55ABB6, 0x7731B0DFA277BA71, 0xE4075A7649964A33, 0x8EB0268230D268BD, 0x1D86CC2BDB3398FF,
0xA8DDF2D1E7118938, 0x3BEB18780CF0797A, 0xDE0BC321FFF17ACC, 0x4D3D298814108A8E, 0xF866177228329B49,
0x6B50FDDBC3D36B0B, 0x01E7812FBA974985, 0x92D16B865176B9C7, 0x278A557C6D54A800, 0xB4BCBFD586B55842,
0x60D2463D753D1C5E, 0xF3E4AC949EDCEC1C, 0x46BF926EA2FEFDDB, 0xD58978C7491F0D99, 0xBF3E0433305B2F17,
0x2C08EE9ADBBADF55, 0x9953D060E798CE92, 0x0A653AC90C793ED0, 0x318E22B1008947AA, 0xA2B8C818EB68B7E8,
0x17E3F6E2D74AA62F, 0x84D51C4B3CAB566D, 0xEE6260BF45EF74E3, 0x7D548A16AE0E84A1, 0xC80FB4EC922C9566,
0x5B395E4579CD6524, 0x8F57A7AD8A452138, 0x1C614D0461A4D17A, 0xA93A73FE5D86C0BD, 0x3A0C9957B66730FF,
0x50BBE5A3CF231271, 0xC38D0F0A24C2E233, 0x76D631F018E0F3F4, 0xE5E0DB59F30103B6, 0x2F216CEA150205DA,
0xBC178643FEE3F598, 0x094CB8B9C2C1E45F, 0x9A7A52102920141D, 0xF0CD2EE450643693, 0x63FBC44DBB85C6D1,
0xD6A0FAB787A7D716, 0x4596101E6C462754, 0x91F8E9F69FCE6348, 0x02CE035F742F930A, 0xB7953DA5480D82CD,
0x24A3D70CA3EC728F, 0x4E14ABF8DAA85001, 0xDD2241513149A043, 0x68797FAB0D6BB184, 0xFB4F9502E68A41C6,
0xC0A48D7AEA7A38BC, 0x539267D3019BC8FE, 0xE6C959293DB9D939, 0x75FFB380D658297B, 0x1F48CF74AF1C0BF5,
0x8C7E25DD44FDFBB7, 0x39251B2778DFEA70, 0xAA13F18E933E1A32, 0x7E7D086660B65E2E, 0xED4BE2CF8B57AE6C,
0x5810DC35B775BFAB, 0xCB26369C5C944FE9, 0xA1914A6825D06D67, 0x32A7A0C1CE319D25, 0x87FC9E3BF2138CE2,
0x14CA749219F27CA0, 0xF12AAFCBEAF37F16, 0x621C456201128F54, 0xD7477B983D309E93, 0x44719131D6D16ED1,
0x2EC6EDC5AF954C5F, 0xBDF0076C4474BC1D, 0x08AB39967856ADDA, 0x9B9DD33F93B75D98, 0x4FF32AD7603F1984,
0xDCC5C07E8BDEE9C6, 0x699EFE84B7FCF801, 0xFAA8142D5C1D0843, 0x901F68D925592ACD, 0x03298270CEB8DA8F,
0xB672BC8AF29ACB48, 0x25445623197B3B0A, 0x1EAF4E5B158B4270, 0x8D99A4F2FE6AB232, 0x38C29A08C248A3F5,
0xABF470A129A953B7, 0xC1430C5550ED7139, 0x5275E6FCBB0C817B, 0xE72ED806872E90BC, 0x741832AF6CCF60FE,
0xA076CB479F4724E2, 0x334021EE74A6D4A0, 0x861B1F144884C567, 0x152DF5BDA3653525, 0x7F9A8949DA2117AB,
0xECAC63E031C0E7E9, 0x59F75D1A0DE2F62E, 0xCAC1B7B3E603066C, 0xCD74327DC0E5FAF6, 0x5E42D8D42B040AB4,
0xEB19E62E17261B73, 0x782F0C87FCC7EB31, 0x129870738583C9BF, 0x81AE9ADA6E6239FD, 0x34F5A4205240283A,
0xA7C34E89B9A1D878, 0x73ADB7614A299C64, 0xE09B5DC8A1C86C26, 0x55C063329DEA7DE1, 0xC6F6899B760B8DA3,
0xAC41F56F0F4FAF2D, 0x3F771FC6E4AE5F6F, 0x8A2C213CD88C4EA8, 0x191ACB95336DBEEA, 0x22F1D3ED3F9DC790,
0xB1C73944D47C37D2, 0x049C07BEE85E2615, 0x97AAED1703BFD657, 0xFD1D91E37AFBF4D9, 0x6E2B7B4A911A049B,
0xDB7045B0AD38155C, 0x4846AF1946D9E51E, 0x9C2856F1B551A102, 0x0F1EBC585EB05140, 0xBA4582A262924087,
0x2973680B8973B0C5, 0x43C414FFF037924B, 0xD0F2FE561BD66209, 0x65A9C0AC27F473CE, 0xF69F2A05CC15838C,
0x137FF15C3F14803A, 0x80491BF5D4F57078, 0x3512250FE8D761BF, 0xA624CFA6033691FD, 0xCC93B3527A72B373,
0x5FA559FB91934331, 0xEAFE6701ADB152F6, 0x79C88DA84650A2B4, 0xADA67440B5D8E6A8, 0x3E909EE95E3916EA,
0x8BCBA013621B072D, 0x18FD4ABA89FAF76F, 0x724A364EF0BED5E1, 0xE17CDCE71B5F25A3, 0x5427E21D277D3464,
0xC71108B4CC9CC426, 0xFCFA10CCC06CBD5C, 0x6FCCFA652B8D4D1E, 0xDA97C49F17AF5CD9, 0x49A12E36FC4EAC9B,
0x231652C2850A8E15, 0xB020B86B6EEB7E57, 0x057B869152C96F90, 0x964D6C38B9289FD2, 0x422395D04AA0DBCE,
0xD1157F79A1412B8C, 0x644E41839D633A4B, 0xF778AB2A7682CA09, 0x9DCFD7DE0FC6E887, 0x0EF93D77E42718C5,
0xBBA2038DD8050902, 0x2894E92433E4F940, 0xE2555E97D5E7FF2C, 0x7163B43E3E060F6E, 0xC4388AC402241EA9,
0x570E606DE9C5EEEB, 0x3DB91C999081CC65, 0xAE8FF6307B603C27, 0x1BD4C8CA47422DE0, 0x88E22263ACA3DDA2,
0x5C8CDB8B5F2B99BE, 0xCFBA3122B4CA69FC, 0x7AE10FD888E8783B, 0xE9D7E57163098879, 0x836099851A4DAAF7,
0x1056732CF1AC5AB5, 0xA50D4DD6CD8E4B72, 0x363BA77F266FBB30, 0x0DD0BF072A9FC24A, 0x9EE655AEC17E3208,
0x2BBD6B54FD5C23CF, 0xB88B81FD16BDD38D, 0xD23CFD096FF9F103, 0x410A17A084180141, 0xF451295AB83A1086,
0x6767C3F353DBE0C4, 0xB3093A1BA053A4D8, 0x203FD0B24BB2549A, 0x9564EE487790455D, 0x065204E19C71B51F,
0x6CE57815E5359791, 0xFFD392BC0ED467D3, 0x4A88AC4632F67614, 0xD9BE46EFD9178656, 0x3C5E9DB62A1685E0,
0xAF68771FC1F775A2, 0x1A3349E5FDD56465, 0x8905A34C16349427, 0xE3B2DFB86F70B6A9, 0x70843511849146EB,
0xC5DF0BEBB8B3572C, 0x56E9E1425352A76E, 0x828718AAA0DAE372, 0x11B1F2034B3B1330, 0xA4EACCF9771902F7,
0x37DC26509CF8F2B5, 0x5D6B5AA4E5BCD03B, 0xCE5DB00D0E5D2079, 0x7B068EF7327F31BE, 0xE830645ED99EC1FC,
0xD3DB7C26D56EB886, 0x40ED968F3E8F48C4, 0xF5B6A87502AD5903, 0x668042DCE94CA941, 0x0C373E2890088BCF,
0x9F01D4817BE97B8D, 0x2A5AEA7B47CB6A4A, 0xB96C00D2AC2A9A08, 0x6D02F93A5FA2DE14, 0xFE341393B4432E56,
0x4B6F2D6988613F91, 0xD859C7C06380CFD3, 0xB2EEBB341AC4ED5D, 0x21D8519DF1251D1F, 0x94836F67CD070CD8,
0x07B585CE26E6FC9A,
};
static uint64 Seed64 = 0xFFFFFFFFFFFFFFFF;
uint64 S3PackCRC64(const byte *buffer, uint32 size)
{
uint64 crc = 0xFFFFFFFFFFFF;
for (uint32 i = 0; i < size; i++)
{
crc = (crc >> 8) ^ table[(buffer[i] ^ crc) & 0xFF];
}
crc = (crc >> 56) | ((crc << 40) & 0x00FF000000000000) | ((crc << 24) & 0x0000FF0000000000) |
((crc << 8) & 0x000000FF00000000) | ((crc >> 8) & 0x00000000FF000000) | ((crc >> 24) & 0x0000000000FF0000) |
((crc >> 40) & 0x000000000000FF00) | (crc << 56);
return crc;
}
#include "dbpf.h"
#include "s3pack.h"
S3PACK::S3PACK(FILE *fp)
{
hdr = NULL;
itamz = NULL;
fcount = hdrsize = 0;
char rbuf[2048];
char magic[8];
uint32 i, datastart;
uint16 d;
uint32 sos = ftell(fp);
fread(&i, sizeof(uint32), 1, fp);
if (i != 7)
{
printf("ERROR: Got unexpected value %d instead of 7?\n", i);
exit(1);
}
memset(magic, 0, 8);
memset(rbuf, 0, 2048);
fread(magic, 7, 1, fp);
if (strncmp(magic, "TS3Pack", 7))
{
printf("ERROR: Got junk '%s' instead of 'TS3Pack'!\n", magic);
}
fread(&d, sizeof(uint16), 1, fp);
fread(&datastart, sizeof(uint32), 1, fp);
datastart += 0x11;
fseek(fp, sos + 0x11, SEEK_SET);
hdrsize = datastart - sos;
hdr = (char *)calloc(hdrsize + 1, 1);
fread(hdr, datastart - sos, 1, fp);
char *sdata = strstr(hdr, PFSTART);
if (sdata == NULL)
return;
hdrsize = (sdata - hdr);
do
{
char *s, *e;
byte *d = NULL;
s = e = NULL;
if ((s = strstr(sdata, PFSTART)) && (e = strstr(s, PFEND)))
{
e += PFENDL;
d = (byte *)calloc(1 + e - s, 1);
memcpy(d, s, e - s);
S3PACK_ITEM *nitm = new S3PACK_ITEM(d);
this->itamz = (S3PACK_ITEM **)realloc(itamz, sizeof(S3PACK_ITEM *) * (fcount + 1));
this->itamz[fcount] = nitm;
fcount++;
sdata = e;
}
else
{
break;
}
} while (1);
hdr = (char *)realloc(hdr, hdrsize);
for (i = 0; i < fcount; i++)
{
memset(rbuf, 0, 2048);
fseek(fp, sos + datastart + itamz[i]->offset, SEEK_SET);
fread(rbuf, 4, 1, fp);
fseek(fp, sos + datastart + itamz[i]->offset, SEEK_SET);
if (!strncmp(rbuf, "DBPF", 4) || !strncmp(rbuf, "DBPP", 4))
{
itamz[i]->data = new DBPF(fp, itamz[i]->size);
}
else
{
itamz[i]->data = new CRAPFILE(fp, itamz[i]->size);
}
}
}
S3PACK::~S3PACK()
{
if (this->hdr)
free(this->hdr);
for (uint32 i = 0; i < fcount; i++)
{
if (itamz[i])
{
delete itamz[i];
itamz[i] = NULL;
}
}
free(this->itamz);
}
void S3PACK::cleanse_evil()
{
for (uint32 i = 0; i < fcount; i++)
{
if (itamz[i] && itamz[i]->data->filetype() == TYPE_DBPF)
{
DBPF *db = (DBPF *)itamz[i]->data;
db->cleanse_evil();
}
}
}
void S3PACK::decompress()
{
for (uint32 i = 0; i < fcount; i++)
{
if (itamz[i] && itamz[i]->data->filetype() == TYPE_DBPF)
{
DBPF *db = (DBPF *)itamz[i]->data;
db->decompress();
}
}
}
void S3PACK::recompress()
{
for (uint32 i = 0; i < fcount; i++)
{
if (itamz[i] && itamz[i]->data->filetype() == TYPE_DBPF)
{
DBPF *db = (DBPF *)itamz[i]->data;
db->recompress();
}
}
}
void S3PACK::write(FILE *fp)
{
char magic[8] = "TS3Pack";
uint32 sos = ftell(fp);
uint32 i = 0x00000007;
uint16 d = 0x0101;
fwrite(&i, sizeof(uint32), 1, fp);
fwrite(magic, 7, 1, fp);
fwrite(&d, sizeof(uint16), 1, fp);
fwrite(&this->hdrsize, sizeof(uint32), 1, fp);
fwrite(this->hdr, this->hdrsize, 1, fp);
uint32 ios = 0;
for (i = 0; i < this->fcount; i++)
{
itamz[i]->offset = ios;
itamz[i]->size = itamz[i]->data->filesize();
ios += itamz[i]->size;
itamz[i]->writehdr(fp);
}
fprintf(fp, "\r\n</Sims3Package>");
memset(magic, 0, 8);
fwrite(magic, 8, 1, fp);
ios = ftell(fp) - sos - 0x11;
fseek(fp, sos + 0xD, SEEK_SET);
fwrite(&ios, sizeof(uint32), 1, fp);
fseek(fp, ios + sos + 0x11, SEEK_SET);
for (i = 0; i < this->fcount; i++)
{
itamz[i]->data->write(fp);
}
}
S3PACK_ITEM::S3PACK_ITEM(byte *hd)
{
char *os, *oe, *ss, *se, *hdc = (char *)hd;
os = oe = ss = se = NULL;
header = hd;
char buf[256];
memset(this, 0, sizeof(S3PACK_ITEM));
header = hd;
if ((os = strstr(hdc, "<Offset>")) && (oe = strstr(os, "</Offset>")))
{
os += strlen("<Offset>");
memset(buf, 0, 256);
memcpy(buf, os, oe - os);
this->offset = atoi(buf);
}
if ((ss = strstr(hdc, "<Length>")) && (se = strstr(ss, "</Length>")))
{
ss += strlen("<Length>");
memset(buf, 0, 256);
memcpy(buf, ss, se - ss);
this->size = atoi(buf);
}
return;
}
S3PACK_ITEM::~S3PACK_ITEM()
{
if (this->name)
free(this->name);
if (this->header)
free(this->header);
}
void S3PACK_ITEM::recalc()
{
char buf[1024];
memset(buf, 0, 1024);
sprintf(buf, ".tmp.%s", this->name ? this->name : "junk");
FILE *fp = fopen(buf, "w+b");
if (fp == NULL)
return;
data->write(fp);
fseek(fp, 0, SEEK_END);
uint32 len = ftell(fp);
byte *bdata = (byte *)calloc(len, 1);
fseek(fp, 0, SEEK_SET);
fread(bdata, len, 1, fp);
this->size = len;
this->crc = S3PackCRC64(bdata, len);
fclose(fp);
unlink(buf);
memset(buf, 0, 1024);
memset(bdata, 0, len);
free(bdata);
}
void S3PACK_ITEM::writehdr(FILE *fp)
{
char *s = (char *)header, *os, *oe, *ss, *se, *cs, *ce, *sts, *ste;
recalc();
os = oe = ss = se = cs = ce = sts = ste = NULL;
if ((os = strstr(s, "<Offset>")))
{
oe = strstr(os, "</Offset>");
sts = os;
ste = oe;
}
if ((ss = strstr(s, "<Length>")))
{
se = strstr(ss, "</Length>");
sts = UMIN(ste, ss);
ste = UMIN(ste, se);
}
if ((cs = strstr(s, "<Crc>")))
{
ce = strstr(cs, "</Crc>");
sts = UMIN(sts, cs);
ste = UMIN(ste, ce);
}
do
{
fwrite(s, sts - s, 1, fp);
if (sts == os)
{
fprintf(fp, "<Offset>%d</Offset>", this->offset);
s = ste + strlen("</Offset>");
os = NULL;
}
else if (sts == ss)
{
fprintf(fp, "<Length>%d</Length>", this->size);
s = ste + strlen("</Length>");
ss = NULL;
}
else if (sts == cs)
{
fprintf(fp, "<Crc>%I64X</Crc>", this->crc);
s = ste + strlen("</Crc>");
cs = NULL;
}
memset(&sts, 0xFF, sizeof(char *));
memset(&ste, 0xFF, sizeof(char *));
if (os >= s)
{
sts = UMIN(sts, os);
ste = UMIN(ste, oe);
}
if (ss >= s)
{
sts = UMIN(sts, ss);
ste = UMIN(ste, se);
}
if (cs >= s)
{
sts = UMIN(sts, cs);
ste = UMIN(ste, ce);
}
} while (os || ss || cs);
fprintf(fp, "%s", s);
}
#if !defined(__S3PACK_H)
#define __S3PACK_H 1
#define PFSTART "<PackagedFile>"
#define PFSTARTL 14
#define PFEND "</PackagedFile>"
#define PFENDL 15
typedef struct s3pack_entry
{
uint32 offset;
uint32 size;
uint32 pos_offset;
uint32 pos_len;
uint32 len_offset;
uint32 len_len;
uint64 crc;
} S3PACK_ENTRY;
class S3PACK_ITEM
{
public:
uint32 offset;
uint32 size;
uint64 guid;
uint64 crc;
char *name;
byte *header;
BASICFILE *data;
S3PACK_ITEM(byte *);
~S3PACK_ITEM();
void writehdr(FILE *);
private:
void recalc();
};
class S3PACK : public BASICFILE
{
public:
S3PACK(FILE *);
~S3PACK();
char *hdr;
uint32 hdrsize;
S3PACK_ITEM **itamz;
uint32 fcount;
void cleanse_evil();
void decompress();
void recompress();
virtual void write(FILE *);
virtual byte filetype() { return TYPE_S3PACK; }
};
#endif
#include "dbpf.h"
#include "s3pack.h"
#include "s3rc.h"
void print_usage(int, char *argv[]);
int main(int argc, char *argv[])
{
uint32 flags = 0;
char **oargv = argv;
int i, oargc = argc;
argv++;
argc--;
while (argc > 0)
{
if (argv[0][0] == '-')
{
for (i = 1; argv[0][i] != '\0'; i++)
{
switch (argv[0][i])
{
case 'd':
flags |= CMP_DECOMPRESS;
break;
case 'f':
flags |= CMP_FIXONLY;
break;
case 'r':
flags |= CMP_FORCEREPAIR;
break;
case 's':
flags |= CMP_ENSMALLENSAVE;
break;
case 'x':
case 'D':
flags |= CMP_DECRAPIFY;
break;
default:
printf("Unrecognized option '%c'\n", argv[0][i]);
break;
}
}
argv++;
argc--;
}
else
{
break;
}
}
if (argc < 1 || ((flags & CMP_FIXONLY) && (flags & CMP_DECOMPRESS)))
{
print_usage(oargc, oargv);
return 0;
}
for (i = 0; i < argc; i++)
{
compressify(argv[i], flags);
}
printf("Done!\n");
return 0;
}
void print_usage(int argc, char *argv[])
{
printf("usage: %s [-d|-f] [-r] a.package [b.package ...]\n", argv[0]);
printf(" -d decompress all files\n");
printf(" -f fix only\n");
printf(" -r force repair\n");
printf(" -s ensmallen save file\n");
printf(" -D decrapify bad Sims3Packs & packages\n");
return;
}
void compressify(const char *filename, uint32 flags)
{
DBPF_HEADER hdr;
DBPF_INDEX *idx = NULL;
FILE *kinky;
uint32 d32, size, off;
char tfn[8];
if (flags & CMP_FIXONLY)
{
if ((kinky = fopen(filename, "r+b")) == NULL)
{
printf("Could not stat %s\n", filename);
return;
}
}
else
{
if ((kinky = fopen(filename, "rb")) == NULL)
{
printf("Could not stat %s\n", filename);
return;
}
}
fseek(kinky, 0, SEEK_END);
size = off = ftell(kinky);
if (off < 96)
{
printf("%s: Bad file %d!\n", filename, off);
fclose(kinky);
return;
}
fseek(kinky, 0, SEEK_SET);
fread(&hdr, sizeof(hdr), 1, kinky);
if (!strncmp(hdr.magic, "DBPP", 4))
{
fix_header(kinky, &hdr, (flags & CMP_FORCEREPAIR) != 0);
if (flags & CMP_FIXONLY)
{
fseek(kinky, 0, SEEK_SET);
fwrite(&hdr, sizeof(hdr), 1, kinky);
printf("%s - fix only\n", filename);
fclose(kinky);
return;
}
}
if (strncmp(hdr.magic, "DBPF", 4))
{
memset(tfn, 0, 8);
fseek(kinky, 0, SEEK_SET);
fread(&d32, sizeof(d32), 1, kinky);
fread(tfn, 7, 1, kinky);
if (!strncmp(tfn, "TS3Pack", 7))
{
fseek(kinky, 0, SEEK_SET);
S3PACK *sp = new S3PACK(kinky);
fclose(kinky);
if (flags & CMP_DECRAPIFY)
sp->cleanse_evil();
if (!(flags & CMP_FIXONLY) && !(flags & CMP_DECOMPRESS))
sp->recompress();
if (flags & CMP_DECOMPRESS)
sp->decompress();
if ((kinky = fopen(filename, "wb")) == NULL)
{
printf("ERROR: Couldn't reopen %s as writeable!\n", filename);
}
else
{
sp->write(kinky);
fclose(kinky);
printf("%s\n", filename);
}
delete sp;
}
return;
}
if (hdr.maj_ver != 2 || hdr.min_ver != 0)
{
printf("%s: not a Sims3 package?\n", filename);
fclose(kinky);
return;
}
fseek(kinky, 0, SEEK_SET);
DBPF *db = new DBPF(kinky);
fclose(kinky);
if (flags & CMP_DECOMPRESS)
db->decompress();
if (flags & CMP_DECRAPIFY)
{
db->cleanse_evil();
if (!(flags & CMP_FIXONLY))
db->recompress();
}
else if (!(flags & CMP_FIXONLY) && !(flags & CMP_DECOMPRESS))
{
db->compress();
}
if ((kinky = fopen(filename, "wb")) == NULL)
{
printf("Couldn't open %s for writing!\n", filename);
}
else
{
db->write(kinky);
fclose(kinky);
printf("%s\n", filename);
}
delete db;
return;
return;
}
#if !defined(__S3RC_H)
#define __S3RC_H 1
void compressify(const char *, uint32);
void fix_s3pack(FILE *, const char *, uint32);
uint64 crc64(const byte *, uint32);
#define CMP_DECOMPRESS 0x00000001
#define CMP_FIXONLY 0x00000002
#define CMP_FORCEREPAIR 0x00000004
#define CMP_ENSMALLENSAVE 0x00000010
#define CMP_DECRAPIFY 0x00000020
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment