From 8234d33f0d4d5892b9e0df2e598989862d79c017 Mon Sep 17 00:00:00 2001 From: Antidote Date: Sat, 20 Jul 2013 20:51:26 -0700 Subject: [PATCH] * Fix botched push --- include/ZQuest.hpp | 73 ++++++++++++++++++++++ include/ZQuestFileReader.hpp | 22 +++++++ include/ZQuestFileWriter.hpp | 21 +++++++ src/ZQuest.cpp | 117 +++++++++++++++++++++++++++++++++++ src/ZQuestFileReader.cpp | 62 +++++++++++++++++++ src/ZQuestFileWriter.cpp | 59 ++++++++++++++++++ 6 files changed, 354 insertions(+) create mode 100644 include/ZQuest.hpp create mode 100644 include/ZQuestFileReader.hpp create mode 100644 include/ZQuestFileWriter.hpp create mode 100644 src/ZQuest.cpp create mode 100644 src/ZQuestFileReader.cpp create mode 100644 src/ZQuestFileWriter.cpp diff --git a/include/ZQuest.hpp b/include/ZQuest.hpp new file mode 100644 index 0000000..63f71fb --- /dev/null +++ b/include/ZQuest.hpp @@ -0,0 +1,73 @@ +#ifndef ZQUEST_HPP +#define ZQUEST_HPP + +#include +#include +#include + +namespace zelda +{ +class ZQuest +{ +public: + static const Uint32 Major; + static const Uint32 Minor; + static const Uint32 Revision; + static const Uint32 Build; + static const Uint32 Version; + + static const Uint32 Magic; + + enum Game + { + NoGame, + LegendofZelda, + AdventureOfLink, + ALinkToThePast, + LinksAwakening, + OcarinaOfTime, + OcarinaOfTime3D, + MajorasMask, + OracleOfSeasons, + OracleOfAges, + FourSwords, + WindWaker, + FourSwordsAdventures, + MinishCap, + TwilightPrincess, + PhantomHourglass, + SpiritTracks, + SkywardSword, + ALinkBetweenWorlds // Not released + }; + + ZQuest(); + ZQuest(Game game, Endian endian, Uint8* data, Uint32 length); + ~ZQuest(); + + void setGame(Game game); + Game game() const; + + void setEndian(Endian endian); + Endian endian() const; + + void setData(Uint8* data); + Uint8* data() const; + + void setLength(Uint32 length); + Uint32 length() const; + + std::string gameString() const; +private: + Game m_game; + Endian m_endian; + Uint8* m_data; + Uint32 m_length; + + // Game strings support + std::vector m_gameStrings; + void initGameStrings(); +}; +} // zelda + +#endif // ZQUEST_HPP diff --git a/include/ZQuestFileReader.hpp b/include/ZQuestFileReader.hpp new file mode 100644 index 0000000..cca1072 --- /dev/null +++ b/include/ZQuestFileReader.hpp @@ -0,0 +1,22 @@ +#ifndef ZQUESTFILEREADER_HPP +#define ZQUESTFILEREADER_HPP + +#include "BinaryReader.hpp" + +namespace zelda +{ +class ZQuest; + +class ZQuestFileReader : public io::BinaryReader +{ + BINARYREADER_BASE + +public: + ZQuestFileReader(Uint8* data, Uint64 length); + ZQuestFileReader(const std::string& filename); + + ZQuest* read(); +}; +} // zelda + +#endif // ZQUESTFILEREADER_HPP diff --git a/include/ZQuestFileWriter.hpp b/include/ZQuestFileWriter.hpp new file mode 100644 index 0000000..2728641 --- /dev/null +++ b/include/ZQuestFileWriter.hpp @@ -0,0 +1,21 @@ +#ifndef ZQUESTFILEWRITER_HPP +#define ZQUESTFILEWRITER_HPP + +#include + +namespace zelda +{ +class ZQuest; + +class ZQuestFileWriter : public io::BinaryWriter +{ + BINARYWRITER_BASE + +public: + ZQuestFileWriter(Uint8* data, Uint64 length); + ZQuestFileWriter(const std::string& filename); + + void write(ZQuest* quest, bool compress = true); +}; +} +#endif // ZQUESTFILEWRITER_HPP diff --git a/src/ZQuest.cpp b/src/ZQuest.cpp new file mode 100644 index 0000000..5f5ebf1 --- /dev/null +++ b/src/ZQuest.cpp @@ -0,0 +1,117 @@ +#include "ZQuest.hpp" + +namespace zelda +{ + +const Uint32 ZQuest::Major = 1; +const Uint32 ZQuest::Minor = 0; +const Uint32 ZQuest::Revision = 0; +const Uint32 ZQuest::Build = 0; + +const Uint32 ZQuest::Version = Major | (Minor << 8) | (Revision << 16) | (Build << 24); + +const Uint32 ZQuest::Magic = 'Z' | ('Q' << 8) | ('S' << 16) | ('1' << 24); + +ZQuest::ZQuest() + : m_game(NoGame), + m_endian(LittleEndian), + m_data(NULL), + m_length(0) +{ + initGameStrings(); +} + +ZQuest::ZQuest(ZQuest::Game game, Endian endian, Uint8* data, Uint32 length) + : m_game(game), + m_endian(endian), + m_data(data), + m_length(length) +{ + initGameStrings(); +} + +ZQuest::~ZQuest() +{ + delete[] m_data; + m_data = NULL; + m_length = 0; +} + +void ZQuest::setGame(ZQuest::Game game) +{ + m_game = game; +} + +ZQuest::Game ZQuest::game() const +{ + return m_game; +} + +void ZQuest::setEndian(Endian endian) +{ + m_endian = endian; +} + +Endian ZQuest::endian() const +{ + return m_endian; +} + +void ZQuest::setData(Uint8* data) +{ + // ensure we're not overwritting our data without freeing first + // or assigning unnecessisarily + if (!m_data || m_data != data) + { + delete[] m_data; + m_data = data; + } +} + +Uint8* ZQuest::data() const +{ + return m_data; +} + +void ZQuest::setLength(Uint32 length) +{ + m_length = length; +} + +Uint32 ZQuest::length() const +{ + return m_length; +} + +std::string ZQuest::gameString() const +{ + if (m_game > m_gameStrings.size() - 1) + return "Unsupported Game"; + + return m_gameStrings[m_game]; +} + +void ZQuest::initGameStrings() +{ + 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)"); +} + +} diff --git a/src/ZQuestFileReader.cpp b/src/ZQuestFileReader.cpp new file mode 100644 index 0000000..f757606 --- /dev/null +++ b/src/ZQuestFileReader.cpp @@ -0,0 +1,62 @@ +#include "ZQuestFileReader.hpp" +#include "ZQuest.hpp" +#include "IOException.hpp" +#include "Compression.hpp" + +namespace zelda +{ + +ZQuestFileReader::ZQuestFileReader(Uint8 *data, Uint64 length) + : base(data, length) +{ +} + +ZQuestFileReader::ZQuestFileReader(const std::string &filename) + : base(filename) +{ +} + +ZQuest *ZQuestFileReader::read() +{ + Uint32 magic, version, compressedLen, uncompressedLen; + ZQuest::Game game; + Uint16 BOM; + Uint8* data; + + magic = base::readUInt32(); + + if (magic != ZQuest::Magic) + throw IOException("ZQuestFileReader::read -> Not a valid ZQuest file"); + + version = base::readUInt32(); + + if (version != ZQuest::Version) + throw IOException("ZQuestFileReader::read -> Unsupported ZQuest version"); + + compressedLen = base::readUInt32(); + uncompressedLen = base::readUInt32(); + game = (ZQuest::Game)base::readUInt32(); + BOM = base::readUInt16(); + base::seek(0x0A); + data = (Uint8*)base::readBytes(compressedLen); // compressedLen is always the total file size + + if (compressedLen != uncompressedLen) + { + Uint8* dst = new Uint8[uncompressedLen]; + Uint32 dstLen = io::Compression::decompressZlib(data, compressedLen, dst, uncompressedLen); + + if (dstLen != uncompressedLen) + { + delete[] dst; + delete[] data; + throw IOException("ZQuestFileReader::read -> Error decompressing data"); + } + + delete[] data; + data = dst; + } + + return new ZQuest(game, BOM == 0xFEFF ? BigEndian : LittleEndian, data, uncompressedLen); +} + +} // zelda diff --git a/src/ZQuestFileWriter.cpp b/src/ZQuestFileWriter.cpp new file mode 100644 index 0000000..48cdea0 --- /dev/null +++ b/src/ZQuestFileWriter.cpp @@ -0,0 +1,59 @@ +#include "ZQuestFileWriter.hpp" +#include "InvalidOperationException.hpp" +#include "ZQuest.hpp" +#include "Compression.hpp" + +namespace zelda +{ + +ZQuestFileWriter::ZQuestFileWriter(Uint8* data, Uint64 length) + : base(data, length) +{ +} + +ZQuestFileWriter::ZQuestFileWriter(const std::string& filename) + : base(filename) +{ +} + +void ZQuestFileWriter::write(ZQuest* quest, bool compress) +{ + if (!quest) + throw InvalidOperationException("ZQuestFileWriter::writer -> quest cannot be NULL"); + + base::writeUInt32(ZQuest::Magic); + base::writeUInt32(ZQuest::Version); + Uint8* questData = quest->data(); + Uint32 compLen = quest->length(); + if (compress) + { + Uint8* compData = new Uint8[quest->length() + 0x20]; // add 20 bytes because sometimes the file grows with compression + io::Compression::compressZlib(questData, quest->length(), compData, &compLen); + + // if the compressed data is the same length or larger than the original data, just store the original + if (compLen >= quest->length()) + { + compLen = quest->length(); + // Delete the compressed data since we won't be using it + delete[] compData; + compData = NULL; + base::writeUInt32(quest->length()); + } + else + { + // Don't do delete on data + questData = compData; + base::writeUInt32(compLen); + } + } + else + base::writeUInt32(quest->length()); + + base::writeUInt32(quest->length()); + base::writeUInt32(quest->game()); + base::writeUInt16(quest->endian() == BigEndian ? 0xFEFF : 0xFFFE); + base::seek(0x0A); + base::writeUBytes(questData, compLen); +} + +} // zelda