153 lines
4.2 KiB
C++
153 lines
4.2 KiB
C++
/* 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
|