Initial commit
This commit is contained in:
152
engines/awe/pak.cpp
Normal file
152
engines/awe/pak.cpp
Normal file
@@ -0,0 +1,152 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "awe/pak.h"
|
||||
#include "awe/detection.h"
|
||||
|
||||
namespace Awe {
|
||||
|
||||
// static const uint32 XOR_KEY1 = 0x31111612;
|
||||
// static const uint32 CHECKSUM = 0x20202020;
|
||||
|
||||
static const uint32 XOR_KEY2 = 0x22683297;
|
||||
|
||||
static uint8 *decode_toodc(uint8 *p, int count) {
|
||||
uint32 key = XOR_KEY2;
|
||||
uint32 acc = 0;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
uint8 *q = p + i * 4;
|
||||
const uint32 data = READ_LE_UINT32(q) ^ key;
|
||||
uint32 r = (q[2] + q[1] + q[0]) ^ q[3];
|
||||
r += acc;
|
||||
key += r;
|
||||
acc += 0x4D;
|
||||
WRITE_LE_UINT32(q, data);
|
||||
}
|
||||
return p + 4;
|
||||
}
|
||||
|
||||
const char *Pak::FILENAME = "Pak01.pak";
|
||||
|
||||
Pak::Pak()
|
||||
: _entries(nullptr), _entriesCount(0) {
|
||||
}
|
||||
|
||||
Pak::~Pak() {
|
||||
close();
|
||||
}
|
||||
|
||||
void Pak::open(const char *dataPath) {
|
||||
_f.open(Common::Path(FILENAME));
|
||||
}
|
||||
|
||||
void Pak::close() {
|
||||
free(_entries);
|
||||
_entries = nullptr;
|
||||
_entriesCount = 0;
|
||||
}
|
||||
|
||||
static int comparePakEntry(const void *a, const void *b) {
|
||||
return scumm_stricmp(((const PakEntry *)a)->name, ((const PakEntry *)b)->name);
|
||||
}
|
||||
|
||||
void Pak::readEntries() {
|
||||
uint8 header[12];
|
||||
|
||||
memset(header, 0, sizeof(header));
|
||||
_f.read(header, sizeof(header));
|
||||
if (_f.err() || memcmp(header, "PACK", 4) != 0) {
|
||||
return;
|
||||
}
|
||||
const uint32 entriesOffset = READ_LE_UINT32(header + 4);
|
||||
_f.seek(entriesOffset);
|
||||
const uint32 entriesSize = READ_LE_UINT32(header + 8);
|
||||
_entriesCount = entriesSize / 0x40;
|
||||
debugC(kDebugPak, "Pak::readEntries() entries count %d", _entriesCount);
|
||||
_entries = (PakEntry *)calloc(_entriesCount, sizeof(PakEntry));
|
||||
if (!_entries) {
|
||||
_entriesCount = 0;
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < _entriesCount; ++i) {
|
||||
uint8 buf[0x40];
|
||||
_f.read(buf, sizeof(buf));
|
||||
if (_f.err()) {
|
||||
break;
|
||||
}
|
||||
const char *name = (const char *)buf;
|
||||
if (strncmp(name, "dlx/", 4) != 0) {
|
||||
continue;
|
||||
}
|
||||
PakEntry *e = &_entries[i];
|
||||
Common::strcpy_s(e->name, name + 4);
|
||||
e->offset = READ_LE_UINT32(buf + 0x38);
|
||||
e->size = READ_LE_UINT32(buf + 0x3C);
|
||||
debugC(kDebugPak, "Pak::readEntries() buf '%s' size %d", e->name, e->size);
|
||||
}
|
||||
qsort(_entries, _entriesCount, sizeof(PakEntry), comparePakEntry);
|
||||
|
||||
#if 0
|
||||
// the original executable descrambles the (ke)y.txt file and check the last 4 bytes.
|
||||
// this has been disabled in later re-releases and a key is bundled in the data files
|
||||
uint8 buf[128];
|
||||
const PakEntry *e = find("check.txt");
|
||||
if (e && e->size <= sizeof(buf)) {
|
||||
uint32 size = 0;
|
||||
loadData(e, buf, &size);
|
||||
assert(size >= 4);
|
||||
const uint32 num = READ_LE_UINT32(buf + size - 4);
|
||||
assert(num == CHECKSUM);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
const PakEntry *Pak::find(const char *name) {
|
||||
debugC(kDebugPak, "Pak::find() '%s'", name);
|
||||
PakEntry tmp;
|
||||
Common::strcpy_s(tmp.name, name);
|
||||
return (const PakEntry *)bsearch(&tmp, _entries, _entriesCount, sizeof(PakEntry), comparePakEntry);
|
||||
}
|
||||
|
||||
void Pak::loadData(const PakEntry *e, uint8 *buf, uint32 *size) {
|
||||
debugC(kDebugPak, "Pak::loadData() %d bytes from 0x%x", e->size, e->offset);
|
||||
_f.seek(e->offset);
|
||||
if (_f.err()) {
|
||||
*size = 0;
|
||||
return;
|
||||
}
|
||||
_f.read(buf, e->size);
|
||||
if (e->size > 5 && memcmp(buf, "TooDC", 5) == 0) {
|
||||
const int dataSize = e->size - 6;
|
||||
debugC(kDebugPak, "Pak::loadData() encoded TooDC data, size %d", dataSize);
|
||||
if ((dataSize & 3) != 0) {
|
||||
// descrambler operates on uint32
|
||||
warning("Unexpected size %d for encoded TooDC data '%s'", dataSize, e->name);
|
||||
}
|
||||
*size = dataSize - 4;
|
||||
decode_toodc(buf + 6, (dataSize + 3) / 4);
|
||||
memmove(buf, buf + 10, dataSize - 4);
|
||||
} else {
|
||||
*size = e->size;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Awe
|
||||
Reference in New Issue
Block a user