* 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:
Antidote 2014-04-18 18:36:46 -07:00
parent 496906c5de
commit 1a389de296
5 changed files with 118 additions and 57 deletions

View File

@ -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;
Endian m_endian;
Uint8* m_data;
Uint32 m_length;
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

View File

@ -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)
{

View File

@ -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;
}
}

View File

@ -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();
game = (ZQuestFile::Game)base::readUInt32();
BOM = base::readUInt16();
base::seek(0x0A);
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

View File

@ -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();