From 1e4bcd0ac188222fd60fcb93ca19735b657d101e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20T=C5=AFma?= Date: Wed, 3 May 2017 21:34:13 +0200 Subject: [PATCH] Added support for OZF3 map files --- src/offlinemap.cpp | 8 ++-- src/ozf.cpp | 110 +++++++++++++++++++++++++++++++++++++++++---- src/ozf.h | 7 +++ 3 files changed, 112 insertions(+), 13 deletions(-) diff --git a/src/offlinemap.cpp b/src/offlinemap.cpp index a31be8d7..af970652 100644 --- a/src/offlinemap.cpp +++ b/src/offlinemap.cpp @@ -348,12 +348,12 @@ bool OfflineMap::getImageInfo(const QString &path) } QString suffix = ii.suffix().toLower(); - if (suffix == "ozf3" || suffix == "ozfx3" || suffix == "ozf4" - || suffix == "ozfx4") { - _errorString = QString("%1: Obfuscated image files not supported") + if (suffix == "ozf4" || suffix == "ozfx4") { + _errorString = QString("%1: OZF4 image files not supported") .arg(QFileInfo(_imgPath).fileName()); return false; - } else if (suffix == "ozf2" || suffix == "ozfx2") { + } else if (suffix == "ozf2" || suffix == "ozfx2" || suffix == "ozf3" + || suffix == "ozfx3") { _ozf.load(_imgPath); _size = _ozf.size(); } else { diff --git a/src/ozf.cpp b/src/ozf.cpp index 64f74480..90adf8de 100644 --- a/src/ozf.cpp +++ b/src/ozf.cpp @@ -3,8 +3,23 @@ #include "ozf.h" -#define OZF2_MAGIC 0x7778 -#define OZF2_SEPARATOR 0x77777777 +#define OZF2_MAGIC 0x7778 +#define OZF3_MAGIC 0x7780 +#define SEPARATOR 0x77777777 + +static const quint8 XKEY[] = +{ + 0x2D, 0x4A, 0x43, 0xF1, 0x27, 0x9B, 0x69, 0x4F, + 0x36, 0x52, 0x87, 0xEC, 0x5F, 0x42, 0x53, 0x22, + 0x9E, 0x8B, 0x2D, 0x83, 0x3D, 0xD2, 0x84, 0xBA, + 0xD8, 0x5B +}; + +static void decrypt(void *data, size_t size, quint8 init) +{ + for (size_t i = 0; i < size; i++) + reinterpret_cast(data)[i] ^= XKEY[i % sizeof(XKEY)] + init; +} template bool OZF::readValue(T &val) { @@ -13,6 +28,9 @@ template bool OZF::readValue(T &val) if (_file.read((char*)&data, sizeof(T)) < (qint64)sizeof(T)) return false; + if (_decrypt) + decrypt(&data, sizeof(T), _key); + if (sizeof(T) > 1) val = qFromLittleEndian(data); else @@ -21,17 +39,88 @@ template bool OZF::readValue(T &val) return true; } +bool OZF::read(void *data, size_t size) +{ + if (_file.read((char*)data, size) < (qint64)size) + return false; + + if (_decrypt) + decrypt(data, size, _key); + + return true; +} + +bool OZF::readKey() +{ + quint8 randomNumber, initial; + quint32 keyblock; + + + if (!_file.seek(14)) + return false; + if (!readValue(randomNumber)) + return false; + + if (!_file.seek(162)) + return false; + if (!readValue(initial)) + return false; + + _decrypt = true; _key = initial; + if (!_file.seek(15 + randomNumber)) + return false; + if (!readValue(keyblock)) + return false; + + switch (keyblock & 0xFF) { + case 0xf1: + initial += 0x8a; + break; + case 0x18: + case 0x54: + initial += 0xa0; + break; + case 0x56: + initial += 0xb9; + break; + case 0x43: + initial += 0x6a; + break; + case 0x83: + initial += 0xa4; + break; + case 0xc5: + initial += 0x7e; + break; + case 0x38: + initial += 0xc1; + break; + default: + break; + } + + _key = initial; + + return true; +} + bool OZF::readHeaders() { quint16 magic; quint32 separator; - if (!readValue(magic) || magic != OZF2_MAGIC) + if (!readValue(magic)) return false; - if (!_file.seek(_file.pos() + 52)) - return false; - if (!readValue(separator) || separator != OZF2_SEPARATOR) + if (magic == OZF2_MAGIC) { + if (!_file.seek(_file.pos() + 52)) + return false; + if (!readValue(separator) || separator != SEPARATOR) + return false; + } else if (magic == OZF3_MAGIC) { + if (!readKey()) + return false; + } else return false; return true; @@ -69,9 +158,10 @@ bool OZF::readTileTable() _dim = QSize(x, y); _palette = QVector(256); + if (!read(&(_palette[0]), sizeof(quint32) * 256)) + return false; for (int i = 0; i < _palette.size(); i++) { - if (!readValue(bgr0)) - return false; + bgr0 = qFromLittleEndian(_palette.at(i)); quint32 b = (bgr0 & 0x000000FF); quint32 g = (bgr0 & 0x0000FF00) >> 8; @@ -98,7 +188,7 @@ bool OZF::load(const QString &path) return false; if (!readHeaders()) { - qWarning("%s: not a OZF2 file", qPrintable(_file.fileName())); + qWarning("%s: not a OZF2/OZF3 file", qPrintable(_file.fileName())); _file.close(); return false; } @@ -128,6 +218,8 @@ QPixmap OZF::tile(int x, int y) QByteArray ba = _file.read(size); if (ba.size() != size) return QPixmap(); + if (_decrypt) + decrypt(ba.data(), qMin(16, ba.size()), _key); quint32 bes = qToBigEndian(tileSize().width() * tileSize().height()); ba.prepend(QByteArray((char*)&bes, sizeof(bes))); QByteArray uba = qUncompress(ba); diff --git a/src/ozf.h b/src/ozf.h index 65a44890..ccce0246 100644 --- a/src/ozf.h +++ b/src/ozf.h @@ -11,6 +11,8 @@ class OZF { public: + OZF() : _decrypt(false), _key(0) {} + bool load(const QString &path); QString fileName() const {return _file.fileName();} @@ -22,9 +24,14 @@ public: private: template bool readValue(T &val); + bool read(void *data, size_t size); + bool readKey(); bool readHeaders(); bool readTileTable(); + bool _decrypt; + quint8 _key; + QSize _size; QSize _dim; QVector _palette;