Skip to content

Commit

Permalink
UNKEYBIF: Add support for BZF files
Browse files Browse the repository at this point in the history
Found in Aspyr's Android and iOS ports of Knights of the Old Republic.
  • Loading branch information
DrMcCoy committed Aug 5, 2018
1 parent daf129f commit b9fb901
Show file tree
Hide file tree
Showing 7 changed files with 381 additions and 41 deletions.
20 changes: 12 additions & 8 deletions src/aurora/biffile.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
#include "src/common/scopedptr.h"

#include "src/aurora/types.h"
#include "src/aurora/archive.h"
#include "src/aurora/keydatafile.h"
#include "src/aurora/aurorafile.h"

namespace Common {
Expand All @@ -53,7 +53,11 @@ class KEYFile;
* BIF files can in turn index different resources of the same BIF
* file.
*
* See also classes KEYFile in keyfile.h.
* Additionally, there are BZF files. A BZF is a compressed variation
* of a BIF file, found exclusively in the Android and iOS version of
* Knights of the Old Republic.
*
* See also classes KEYFile in keyfile.h and BZFFile in bzffile.h.
*
* There are two versions of BIF files known and supported
* - V1, used by Neverwinter Nights, Neverwinter Nights 2, Knight of
Expand All @@ -64,7 +68,7 @@ class KEYFile;
* games (Baldur's Gate et al) are not supported at all, even though
* they claim to be V1.
*/
class BIFFile : public Archive, public AuroraFile {
class BIFFile : public KEYDataFile, public AuroraFile {
public:
/** Take over this stream and read a BIF file out of it. */
BIFFile(Common::SeekableReadStream *bif);
Expand All @@ -82,15 +86,15 @@ class BIFFile : public Archive, public AuroraFile {
/** Return a stream of the resource's contents. */
Common::SeekableReadStream *getResource(uint32 index, bool tryNoCopy = false) const;

/** Merge information from the KEY into the BIF.
/** Merge information from the KEY into the data file.
*
* Without this step, this BIFFile archive does not contain any
* Without this step, this data file archive does not contain any
* resource names at all.
*
* @param key A KEYFile with information about this BIF.
* @param bifIndex The index this BIF has within the KEY file.
* @param key A KEYFile with information about this data file.
* @param dataFileIndex The index this data file has within the KEY file.
*/
void mergeKEY(const KEYFile &key, uint32 bifIndex);
void mergeKEY(const KEYFile &key, uint32 dataFileIndex);

private:
/** Internal resource information. */
Expand Down
155 changes: 155 additions & 0 deletions src/aurora/bzffile.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
/* xoreos-tools - Tools to help with xoreos development
*
* xoreos-tools is the legal property of its developers, whose names
* can be found in the AUTHORS file distributed with this source
* distribution.
*
* xoreos-tools 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.
*
* xoreos-tools 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 xoreos-tools. If not, see <http://www.gnu.org/licenses/>.
*/

/** @file
* Handling BioWare's BZFs (resource data files), used in the Android
* and iOS versions of Knights of the Old Republic.
*
* Essentially, they are BIF files with LZMA-compressed data.
*/

#include <cassert>

#include "src/common/util.h"
#include "src/common/strutil.h"
#include "src/common/error.h"
#include "src/common/memreadstream.h"
#include "src/common/lzma.h"

#include "src/aurora/bzffile.h"
#include "src/aurora/keyfile.h"

static const uint32 kBZFID = MKTAG('B', 'I', 'F', 'F');
static const uint32 kVersion1 = MKTAG('V', '1', ' ', ' ');

namespace Aurora {

BZFFile::BZFFile(Common::SeekableReadStream *bzf) : _bzf(bzf) {
assert(_bzf);

load(*_bzf);
}

BZFFile::~BZFFile() {
}

void BZFFile::load(Common::SeekableReadStream &bzf) {
readHeader(bzf);

if (_id != kBZFID)
throw Common::Exception("Not a BZF file (%s)", Common::debugTag(_id).c_str());

if (_version != kVersion1)
throw Common::Exception("Unsupported BZF file version %s", Common::debugTag(_version).c_str());

uint32 varResCount = bzf.readUint32LE();
uint32 fixResCount = bzf.readUint32LE();

if (fixResCount != 0)
throw Common::Exception("TODO: Fixed BZF resources");

_iResources.resize(varResCount);

uint32 offVarResTable = bzf.readUint32LE();

try {

readVarResTable(bzf, offVarResTable);

} catch (Common::Exception &e) {
e.add("Failed reading BZF file");
throw;
}

}

void BZFFile::readVarResTable(Common::SeekableReadStream &bzf, uint32 offset) {
bzf.seek(offset);

for (uint32 i = 0; i < _iResources.size(); i++) {
bzf.skip(4); // ID

_iResources[i].offset = bzf.readUint32LE();
_iResources[i].size = bzf.readUint32LE();
_iResources[i].type = (FileType) bzf.readUint32LE();

if (i > 0)
_iResources[i - 1].packedSize = _iResources[i].offset - _iResources[i - 1].offset;
}

if (!_iResources.empty())
_iResources.back().packedSize = bzf.size() - _iResources.back().offset;
}

void BZFFile::mergeKEY(const KEYFile &key, uint32 bifIndex) {
const KEYFile::ResourceList &keyResList = key.getResources();

for (KEYFile::ResourceList::const_iterator keyRes = keyResList.begin(); keyRes != keyResList.end(); ++keyRes) {
if (keyRes->bifIndex != bifIndex)
continue;

if (keyRes->resIndex >= _iResources.size()) {
warning("Resource index out of range (%d/%d)", keyRes->resIndex, (int) _iResources.size());
continue;
}

if (keyRes->type != _iResources[keyRes->resIndex].type)
warning("KEY and BZF disagree on the type of the resource \"%s\" (%d, %d). Trusting the BZF",
keyRes->name.c_str(), keyRes->type, _iResources[keyRes->resIndex].type);

Resource res;

res.name = keyRes->name;
res.type = _iResources[keyRes->resIndex].type;
res.index = keyRes->resIndex;

_resources.push_back(res);
}

}

uint32 BZFFile::getInternalResourceCount() const {
return _iResources.size();
}

const Archive::ResourceList &BZFFile::getResources() const {
return _resources;
}

const BZFFile::IResource &BZFFile::getIResource(uint32 index) const {
if (index >= _iResources.size())
throw Common::Exception("Resource index out of range (%u/%u)", index, (uint)_iResources.size());

return _iResources[index];
}

uint32 BZFFile::getResourceSize(uint32 index) const {
return getIResource(index).size;
}

Common::SeekableReadStream *BZFFile::getResource(uint32 index, bool UNUSED(tryNoCopy)) const {
const IResource &res = getIResource(index);

_bzf->seek(res.offset);

return Common::decompressLZMA1(*_bzf, res.packedSize, res.size, true);
}

} // End of namespace Aurora
112 changes: 112 additions & 0 deletions src/aurora/bzffile.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/* xoreos-tools - Tools to help with xoreos development
*
* xoreos-tools is the legal property of its developers, whose names
* can be found in the AUTHORS file distributed with this source
* distribution.
*
* xoreos-tools 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.
*
* xoreos-tools 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 xoreos-tools. If not, see <http://www.gnu.org/licenses/>.
*/

/** @file
* Handling BioWare's BZFs (resource data files), used in the Android
* and iOS versions of Knights of the Old Republic.
*
* Essentially, they are BIF files with LZMA-compressed data.
*/

#ifndef AURORA_BZFFILE_H
#define AURORA_BZFFILE_H

#include <vector>

#include "src/common/types.h"
#include "src/common/scopedptr.h"

#include "src/aurora/types.h"
#include "src/aurora/keydatafile.h"
#include "src/aurora/aurorafile.h"

namespace Common {
class SeekableReadStream;
}

namespace Aurora {

class KEYFile;

/** Class to hold resource data information of a BZF file.
*
* A BZF is a compressed variation of a BIF file, found exclusively
* in the Android and iOS version of Knights of the Old Republic.
*
* See also classes KEYFile in keyfile.h and BIFFile in biffile.h.
*/
class BZFFile : public KEYDataFile, public AuroraFile {
public:
/** Take over this stream and read a BZF file out of it. */
BZFFile(Common::SeekableReadStream *bzf);
~BZFFile();

/** Return the number of internal resources (including unmerged ones). */
uint32 getInternalResourceCount() const;

/** Return the list of resources. */
const ResourceList &getResources() const;

/** Return the size of a resource. */
uint32 getResourceSize(uint32 index) const;

/** Return a stream of the resource's contents. */
Common::SeekableReadStream *getResource(uint32 index, bool tryNoCopy = false) const;

/** Merge information from the KEY into the data file.
*
* Without this step, this data file archive does not contain any
* resource names at all.
*
* @param key A KEYFile with information about this data file.
* @param dataFileIndex The index this data file has within the KEY file.
*/
void mergeKEY(const KEYFile &key, uint32 dataFileIndex);

private:
/** Internal resource information. */
struct IResource {
FileType type; ///< The resource's type.

uint32 offset; ///< The offset of the resource within the BZF.
uint32 size; ///< The resource's size.

uint32 packedSize; ///< Raw, compressed data size.
};

typedef std::vector<IResource> IResourceList;

Common::ScopedPtr<Common::SeekableReadStream> _bzf;

/** External list of resource names and types. */
ResourceList _resources;

/** Internal list of resource offsets and sizes. */
IResourceList _iResources;

void load(Common::SeekableReadStream &bzf);
void readVarResTable(Common::SeekableReadStream &bzf, uint32 offset);

const IResource &getIResource(uint32 index) const;
};

} // End of namespace Aurora

#endif // AURORA_BZFFILE_H
56 changes: 56 additions & 0 deletions src/aurora/keydatafile.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/* xoreos-tools - Tools to help with xoreos development
*
* xoreos-tools is the legal property of its developers, whose names
* can be found in the AUTHORS file distributed with this source
* distribution.
*
* xoreos-tools 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.
*
* xoreos-tools 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 xoreos-tools. If not, see <http://www.gnu.org/licenses/>.
*/

/** @file
* An abstract KEY data file (BIF or BZF).
*/

#ifndef AURORA_KEYDATAFILE_H
#define AURORA_KEYDATAFILE_H

#include "src/common/types.h"

#include "src/aurora/archive.h"

namespace Aurora {

class KEYFile;

class KEYDataFile : public Archive {
public:
virtual ~KEYDataFile() { }

/** Return the number of internal resources (including unmerged ones). */
virtual uint32 getInternalResourceCount() const = 0;

/** Merge information from the KEY into the data file.
*
* Without this step, this data file archive does not contain any
* resource names at all.
*
* @param key A KEYFile with information about this data file.
* @param dataFileIndex The index this data file has within the KEY file.
*/
virtual void mergeKEY(const KEYFile &key, uint32 dataFileIndex) = 0;
};

} // End of namespace Aurora

#endif // AURORA_KEYDATAFILE_H
6 changes: 5 additions & 1 deletion src/aurora/keyfile.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@ namespace Aurora {
* BIF files can in turn index different resources of the same BIF
* file.
*
* See also class BIFFile in biffile.h.
* Additionally, there are BZF files. A BZF is a compressed variation
* of a BIF file, found exclusively in the Android and iOS versions of
* Knights of the Old Republic.
*
* See also classes BIFFile in biffile.h and BZFFile in bzffile.h.
*
* There are two versions of KEY files known and supported
* - V1, used by Neverwinter Nights, Neverwinter Nights 2, Knight of
Expand Down

0 comments on commit b9fb901

Please sign in to comment.