mirror of https://github.com/libAthena/athena.git
* Generalize ZQuestFile and incremented version major to 2
* Fixed a bug in Stream::writeBit where it wasn't correctly setting the flag
This commit is contained in:
parent
496906c5de
commit
1a389de296
|
@ -20,10 +20,13 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#define ZQUEST_VERSION_CHECK(major, minor, revision) \
|
||||
(major | (minor << 8) | (revision << 16))
|
||||
|
||||
namespace zelda
|
||||
{
|
||||
/*!
|
||||
* \brief The ZQuest class
|
||||
* \brief ZQuestFile is an export format for save data.
|
||||
*/
|
||||
class ZQuestFile
|
||||
{
|
||||
|
@ -40,10 +43,6 @@ public:
|
|||
* \brief The current revision of the ZQuest format
|
||||
*/
|
||||
static const Uint32 Revision;
|
||||
/*!
|
||||
* \brief The current build of the ZQuest format
|
||||
*/
|
||||
static const Uint32 Build;
|
||||
/*!
|
||||
* \brief The current version of the ZQuest format
|
||||
*/
|
||||
|
@ -97,7 +96,7 @@ public:
|
|||
* \param data
|
||||
* \param length
|
||||
*/
|
||||
ZQuestFile(Game game, Endian endian, Uint8* data, Uint32 length);
|
||||
ZQuestFile(Game game, Endian endian, Uint8* data, Uint32 length, const std::string& gameString = std::string());
|
||||
~ZQuestFile();
|
||||
|
||||
/*!
|
||||
|
@ -143,20 +142,22 @@ public:
|
|||
*/
|
||||
Uint32 length() const;
|
||||
|
||||
void setGameString(const std::string& gameString);
|
||||
/*!
|
||||
* \brief gameString
|
||||
* \return
|
||||
*/
|
||||
std::string gameString() const;
|
||||
|
||||
static const std::vector<std::string> gameStringList();
|
||||
private:
|
||||
Game m_game;
|
||||
std::string m_gameString;
|
||||
Endian m_endian;
|
||||
Uint8* m_data;
|
||||
Uint32 m_length;
|
||||
|
||||
// Game strings support
|
||||
std::vector<std::string> m_gameStrings;
|
||||
void initGameStrings();
|
||||
};
|
||||
} // zelda
|
||||
|
||||
|
|
|
@ -110,7 +110,10 @@ void Stream::writeBit(bool val)
|
|||
else if (m_position > m_length)
|
||||
throw error::IOException("Stream::writeBit() -> Position outside stream bounds");
|
||||
|
||||
*(Uint8*)(m_data + m_position) |= ((Uint32)val << m_bitPosition);
|
||||
if (val)
|
||||
*(Uint8*)(m_data + m_position) |= (1 << m_bitPosition);
|
||||
else
|
||||
*(Uint8*)(m_data + m_position) &= ~(1 << m_bitPosition);
|
||||
m_bitPosition++;
|
||||
if (m_bitPosition > 7)
|
||||
{
|
||||
|
|
|
@ -18,15 +18,38 @@
|
|||
|
||||
namespace zelda
|
||||
{
|
||||
std::vector<std::string> GameStrings;
|
||||
void initGameStrings()
|
||||
{
|
||||
// Populate game strings
|
||||
GameStrings.push_back("No Game");
|
||||
GameStrings.push_back("Legend Of Zelda");
|
||||
GameStrings.push_back("Adventure of Link");
|
||||
GameStrings.push_back("A Link to the Past");
|
||||
GameStrings.push_back("Links Awakening");
|
||||
GameStrings.push_back("Ocarina of Time");
|
||||
GameStrings.push_back("Ocarina of Time 3D");
|
||||
GameStrings.push_back("Majora's Mask");
|
||||
GameStrings.push_back("Oracle of Seasons");
|
||||
GameStrings.push_back("Oracle of Ages");
|
||||
GameStrings.push_back("For Swords");
|
||||
GameStrings.push_back("Wind Waker");
|
||||
GameStrings.push_back("Four Swords Adventures");
|
||||
GameStrings.push_back("Minish Cap");
|
||||
GameStrings.push_back("Twilight Princess");
|
||||
GameStrings.push_back("Phantom Hourglass");
|
||||
GameStrings.push_back("Spirit Tracks");
|
||||
GameStrings.push_back("Skyward Sword");
|
||||
GameStrings.push_back("A Link Between Worlds");
|
||||
}
|
||||
|
||||
const Uint32 ZQuestFile::Major = 1;
|
||||
const Uint32 ZQuestFile::Major = 2;
|
||||
const Uint32 ZQuestFile::Minor = 0;
|
||||
const Uint32 ZQuestFile::Revision = 0;
|
||||
const Uint32 ZQuestFile::Build = 0;
|
||||
|
||||
const Uint32 ZQuestFile::Version = Major | (Minor << 8) | (Revision << 16) | (Build << 24);
|
||||
const Uint32 ZQuestFile::Version = Major | (Minor << 8) | (Revision << 16);
|
||||
|
||||
const Uint32 ZQuestFile::Magic = 'Z' | ('Q' << 8) | ('S' << 16) | ('1' << 24);
|
||||
const Uint32 ZQuestFile::Magic = 'Z' | ('Q' << 8) | ('S' << 16) | (('0' + ZQuestFile::Major) << 24);
|
||||
|
||||
ZQuestFile::ZQuestFile()
|
||||
: m_game(NoGame),
|
||||
|
@ -37,13 +60,16 @@ ZQuestFile::ZQuestFile()
|
|||
initGameStrings();
|
||||
}
|
||||
|
||||
ZQuestFile::ZQuestFile(ZQuestFile::Game game, Endian endian, Uint8* data, Uint32 length)
|
||||
ZQuestFile::ZQuestFile(ZQuestFile::Game game, Endian endian, Uint8* data, Uint32 length, const std::string& gameString)
|
||||
: m_game(game),
|
||||
m_gameString(gameString),
|
||||
m_endian(endian),
|
||||
m_data(data),
|
||||
m_length(length)
|
||||
{
|
||||
initGameStrings();
|
||||
if (gameString.empty() && (m_game < GameStrings.size() - 1))
|
||||
m_gameString = GameStrings[m_game];
|
||||
}
|
||||
|
||||
ZQuestFile::~ZQuestFile()
|
||||
|
@ -56,6 +82,10 @@ ZQuestFile::~ZQuestFile()
|
|||
void ZQuestFile::setGame(ZQuestFile::Game game)
|
||||
{
|
||||
m_game = game;
|
||||
if (m_game > GameStrings.size() - 1)
|
||||
return;
|
||||
|
||||
m_gameString = GameStrings[m_game];
|
||||
}
|
||||
|
||||
ZQuestFile::Game ZQuestFile::game() const
|
||||
|
@ -99,36 +129,20 @@ Uint32 ZQuestFile::length() const
|
|||
return m_length;
|
||||
}
|
||||
|
||||
void ZQuestFile::setGameString(const std::string& gameString)
|
||||
{
|
||||
m_gameString = gameString;
|
||||
}
|
||||
|
||||
std::string ZQuestFile::gameString() const
|
||||
{
|
||||
if (m_game > m_gameStrings.size() - 1)
|
||||
return "Unsupported Game";
|
||||
|
||||
return m_gameStrings[m_game];
|
||||
return m_gameString;
|
||||
}
|
||||
|
||||
void ZQuestFile::initGameStrings()
|
||||
const std::vector<std::string> ZQuestFile::gameStringList()
|
||||
{
|
||||
// Populate game strings
|
||||
m_gameStrings.push_back("No Game");
|
||||
m_gameStrings.push_back("Legend Of Zelda");
|
||||
m_gameStrings.push_back("Adventure of Link");
|
||||
m_gameStrings.push_back("A Link to the Past");
|
||||
m_gameStrings.push_back("Links Awakening");
|
||||
m_gameStrings.push_back("Ocarina of Time");
|
||||
m_gameStrings.push_back("Ocarina of Time 3D");
|
||||
m_gameStrings.push_back("Majora's Mask");
|
||||
m_gameStrings.push_back("Oracle of Seasons");
|
||||
m_gameStrings.push_back("Oracle of Ages");
|
||||
m_gameStrings.push_back("For Swords");
|
||||
m_gameStrings.push_back("Wind Waker");
|
||||
m_gameStrings.push_back("Four Swords Adventures");
|
||||
m_gameStrings.push_back("Minish Cap");
|
||||
m_gameStrings.push_back("Twilight Princess");
|
||||
m_gameStrings.push_back("Phantom Hourglass");
|
||||
m_gameStrings.push_back("Spirit Tracks");
|
||||
m_gameStrings.push_back("Skyward Sword");
|
||||
m_gameStrings.push_back("A Link Between Worlds (Unreleased)"); // Probably should have this, but.....
|
||||
if (GameStrings.size() <= 0)
|
||||
initGameStrings();
|
||||
return GameStrings;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,6 +17,11 @@
|
|||
#include "ZQuestFile.hpp"
|
||||
#include "InvalidOperationException.hpp"
|
||||
#include "Compression.hpp"
|
||||
#include "InvalidDataException.hpp"
|
||||
#include "Checksums.hpp"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <utility.hpp>
|
||||
|
||||
namespace zelda
|
||||
{
|
||||
|
@ -36,27 +41,64 @@ ZQuestFileReader::ZQuestFileReader(const std::string &filename)
|
|||
ZQuestFile *ZQuestFileReader::read()
|
||||
{
|
||||
Uint32 magic, version, compressedLen, uncompressedLen;
|
||||
ZQuestFile::Game game;
|
||||
ZQuestFile::Game game = ZQuestFile::NoGame;
|
||||
std::string gameString;
|
||||
Uint16 BOM;
|
||||
Uint32 checksum;
|
||||
Uint8* data;
|
||||
|
||||
magic = base::readUInt32();
|
||||
|
||||
if (magic != ZQuestFile::Magic)
|
||||
throw error::InvalidOperationException("ZQuestFileReader::read -> Not a valid ZQuest file");
|
||||
if ((magic & 0x00FFFFFF) != (ZQuestFile::Magic & 0x00FFFFFF))
|
||||
THROW_INVALID_DATA("Not a valid ZQuest file");
|
||||
|
||||
version = base::readUInt32();
|
||||
|
||||
if (version != ZQuestFile::Version)
|
||||
throw error::InvalidOperationException("ZQuestFileReader::read -> Unsupported ZQuest version");
|
||||
if (version > ZQuestFile::Version)
|
||||
THROW_INVALID_DATA("Unsupported ZQuest version");
|
||||
|
||||
compressedLen = base::readUInt32();
|
||||
uncompressedLen = base::readUInt32();
|
||||
|
||||
if (version >= ZQUEST_VERSION_CHECK(2, 0, 0))
|
||||
{
|
||||
gameString = ((const char*)base::readBytes(0x0A), 0x0A);
|
||||
for (size_t i = 0; i < ZQuestFile::gameStringList().size(); i++)
|
||||
{
|
||||
if (!ZQuestFile::gameStringList().at(i).substr(0, 0x0A).compare(gameString))
|
||||
{
|
||||
gameString = ZQuestFile::gameStringList().at(i);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
BOM = base::readUInt16();
|
||||
checksum = base::readUInt32();
|
||||
}
|
||||
else
|
||||
{
|
||||
game = (ZQuestFile::Game)base::readUInt32();
|
||||
BOM = base::readUInt16();
|
||||
std::cerr << "Test" << std::endl;
|
||||
base::seek(0x0A);
|
||||
}
|
||||
|
||||
data = (Uint8*)base::readBytes(compressedLen); // compressedLen is always the total file size
|
||||
|
||||
if (version >= ZQUEST_VERSION_CHECK(2, 0, 0))
|
||||
{
|
||||
if (checksum != zelda::Checksums::crc32(data, compressedLen))
|
||||
{
|
||||
delete[] data;
|
||||
THROW_INVALID_DATA("Checksum mismatch, data corrupt");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::clog << "ZQuest version 0x" << std::uppercase << std::setw(8) << std::setfill('0') << std::hex << zelda::utility::swapU32(version);
|
||||
std::clog << " has no checksum field" << std::endl;
|
||||
}
|
||||
|
||||
if (compressedLen != uncompressedLen)
|
||||
{
|
||||
Uint8* dst = new Uint8[uncompressedLen];
|
||||
|
@ -67,14 +109,14 @@ ZQuestFile *ZQuestFileReader::read()
|
|||
delete[] dst;
|
||||
delete[] data;
|
||||
// TODO: Make proper exception
|
||||
throw error::InvalidOperationException("ZQuestFileReader::read -> Error decompressing data");
|
||||
THROW_INVALID_DATA("Error decompressing data");
|
||||
}
|
||||
|
||||
delete[] data;
|
||||
data = dst;
|
||||
}
|
||||
|
||||
return new ZQuestFile(game, BOM == 0xFEFF ? BigEndian : LittleEndian, data, uncompressedLen);
|
||||
return new ZQuestFile(game, BOM == 0xFEFF ? BigEndian : LittleEndian, data, uncompressedLen, gameString);
|
||||
}
|
||||
|
||||
} // io
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "InvalidOperationException.hpp"
|
||||
#include "ZQuestFile.hpp"
|
||||
#include "Compression.hpp"
|
||||
#include "Checksums.hpp"
|
||||
|
||||
namespace zelda
|
||||
{
|
||||
|
@ -36,7 +37,7 @@ ZQuestFileWriter::ZQuestFileWriter(const std::string& filename)
|
|||
void ZQuestFileWriter::write(ZQuestFile* quest, bool compress)
|
||||
{
|
||||
if (!quest)
|
||||
throw error::InvalidOperationException("ZQuestFileWriter::write -> quest cannot be NULL");
|
||||
THROW_INVALIDOPERATION_EXCEPTION("quest cannot be NULL");
|
||||
|
||||
base::writeUInt32(ZQuestFile::Magic);
|
||||
base::writeUInt32(ZQuestFile::Version);
|
||||
|
@ -71,9 +72,9 @@ void ZQuestFileWriter::write(ZQuestFile* quest, bool compress)
|
|||
}
|
||||
|
||||
base::writeUInt32(quest->length());
|
||||
base::writeUInt32(quest->game());
|
||||
base::writeBytes((Int8*)quest->gameString().substr(0, 0x0A).c_str(), 0x0A);
|
||||
base::writeUInt16(quest->endian() == BigEndian ? 0xFFFE : 0xFEFF);
|
||||
base::seek(0x0A);
|
||||
base::writeUInt32(zelda::Checksums::crc32(questData, compLen));
|
||||
base::writeUBytes(questData, compLen);
|
||||
|
||||
base::save();
|
||||
|
|
Loading…
Reference in New Issue