* Added SkywardSword classes

* Added missing readUBytes function in zelda::io::Stream
This commit is contained in:
Antidote 2013-07-27 18:42:11 -07:00
parent 162d2753dc
commit baf16a6fbd
16 changed files with 357 additions and 5 deletions

View File

@ -177,6 +177,7 @@ protected:
#define BINARYREADER_BASE \
private: \
typedef zelda::io::BinaryReader base;
#endif // BINARYREADER_BASE
#endif // __BINARYREADER_HPP__

41
include/SSFile.hpp Normal file
View File

@ -0,0 +1,41 @@
#ifndef __SSFILE_HPP__
#define __SSFILE_HPP__
#include "Types.hpp"
// standard lib
#include <vector>
namespace zelda
{
class SSQuest;
class SSFile
{
public:
enum MagicNumbers
{
USMagic = 0x534F5545,
JAMagic = 0x534F554A,
EUMagic = 0x534F5550
};
SSFile();
SSFile(std::vector<SSQuest*> quests);
~SSFile();
void addQuest(SSQuest* q);
SSQuest* quest(Uint32 id);
std::vector<SSQuest*> questList() const;
void setRegion(Region region);
Region region() const;
private:
Region m_region;
// A vector is a bit overkill
std::vector<SSQuest*> m_quests;
Uint32 m_numQuests;
};
}
#endif // __SSFILE_HPP__

24
include/SSFileReader.hpp Normal file
View File

@ -0,0 +1,24 @@
#ifndef __SSFILEREADER_HPP__
#define __SSFILEREADER_HPP__
#include "BinaryReader.hpp"
namespace zelda
{
class SSFile;
namespace io
{
class SSFileReader : public BinaryReader
{
BINARYREADER_BASE
public:
SSFileReader(Uint8* data, Uint64 length);
SSFileReader(const std::string& filename);
SSFile* read();
};
} // io
} // zelda
#endif // __SSFILEREADER_HPP__

25
include/SSFileWriter.hpp Normal file
View File

@ -0,0 +1,25 @@
#ifndef __SSFILEWRITER_HPP__
#define __SSFILEWRITER_HPP__
#include "BinaryWriter.hpp"
namespace zelda
{
class SSFile;
namespace io
{
class SSFileWriter : public BinaryWriter
{
// Why does this fuck up my formatting in Qt Creator?
BINARYWRITER_BASE
public:
SSFileWriter(Uint8* data, Uint64 len);
SSFileWriter(const std::string& filename);
void write(SSFile* file);
};
}
}
#endif // __SSFILEWRITER_HPP__

28
include/SSQuest.hpp Normal file
View File

@ -0,0 +1,28 @@
#ifndef SSQUEST_HPP
#define SSQUEST_HPP
#include "ZQuestFile.hpp"
namespace zelda
{
// TODO: Handle game specific data
class SSQuest : public ZQuestFile
{
public:
SSQuest(Uint8* data, Uint32 len);
// TODO: Is len really needed?
void setSkipData(const Uint8* data, Uint32 len = 0x24);
Uint8* skipData() const;
Uint32 skipLength() const;
private:
Uint8* m_skipData;
Uint32 m_skipLength;
};
} // zelda
#endif // SSQUEST_HPP

View File

@ -122,6 +122,12 @@ public:
* \throw IOException
*/
virtual Int8 readByte();
/*! \brief Reads a byte at the current position and advances the current position.
*
* \return Uint8* The buffer at the current position from the given length.
* \throw IOException
*/
virtual Uint8* readUBytes(Int64 length);
/*! \brief Reads a byte at the current position and advances the current position.
*

View File

@ -30,6 +30,13 @@ enum Endian
LittleEndian, //!< Specifies that the Stream is Little Endian (LSB)
BigEndian //!< Specifies that the Stream is Big Endian (MSB)
};
enum Region
{
NTSCURegion,
NTSCJRegion,
PALRegion
};
} // zelda
#endif

View File

@ -1,10 +1,12 @@
CONFIG += staticlib
TEMPLATE=lib
DESTDIR = ./
CONFIG(debug, debug|release){
DEFINES += DEBUG
TARGET=zelda-d
}
CONFIG(release, release|debug){
DEFINES -= DEBUG
TARGET=zelda
@ -52,7 +54,11 @@ HEADERS += \
include/ZQuestFileReader.hpp \
include/Compression.hpp \
include/WiiImage.hpp \
include/ZQuestFile.hpp
include/ZQuestFile.hpp \
include/SSQuest.hpp \
include/SSFileWriter.hpp \
include/SSFileReader.hpp \
include/SSFile.hpp
SOURCES += \
src/utility.cpp \
@ -81,7 +87,11 @@ SOURCES += \
src/ZQuestFileReader.cpp \
src/Compression.cpp \
src/WiiImage.cpp \
src/ZQuestFile.cpp
src/ZQuestFile.cpp \
src/SSQuest.cpp \
src/SSFileWriter.cpp \
src/SSFileReader.cpp \
src/SSFile.cpp
system("exec doxygen libzelda.conf")
#system("cd doc/latex && make")

57
src/SSFile.cpp Normal file
View File

@ -0,0 +1,57 @@
#include "SSFile.hpp"
#include "SSQuest.hpp"
#include "InvalidOperationException.hpp"
namespace zelda
{
SSFile::SSFile()
: m_numQuests(0)
{
}
SSFile::SSFile(std::vector<SSQuest*> quests)
: m_numQuests(0)
{
m_quests = quests;
}
SSFile::~SSFile()
{
}
void SSFile::addQuest(zelda::SSQuest *q)
{
// Do not allow more than 3 quests
if (m_quests.size() >= 3)
return;
m_quests.push_back(q);
}
SSQuest *SSFile::quest(Uint32 id)
{
if (id > m_quests.size() - 1)
throw zelda::error::InvalidOperationException("SSFile::quest -> id cannot be "
"greater than the number of quests");
return m_quests[id];
}
std::vector<SSQuest*> SSFile::questList() const
{
return m_quests;
}
void SSFile::setRegion(Region region)
{
m_region = region;
}
Region SSFile::region() const
{
return m_region;
}
} // zelda

59
src/SSFileReader.cpp Normal file
View File

@ -0,0 +1,59 @@
#include "SSFileReader.hpp"
#include "SSFile.hpp"
#include "SSQuest.hpp"
#include "InvalidOperationException.hpp"
#include <iostream>
namespace zelda
{
namespace io
{
SSFileReader::SSFileReader(Uint8* data, Uint64 length)
: base(data, length)
{
base::setEndianess(BigEndian);
}
SSFileReader::SSFileReader(const std::string& filename)
: base(filename)
{
base::setEndianess(BigEndian);
}
SSFile* SSFileReader::read()
{
SSFile* file = NULL;
if (base::length() != 0xFBE0)
throw zelda::error::InvalidOperationException("SSFileReader::read -> File not the expected size of 0xFBE0");
Uint32 magic = base::readUInt32();
if (magic != SSFile::USMagic && magic != SSFile::JAMagic && magic != SSFile::EUMagic)
throw zelda::error::InvalidOperationException("SSFileReader::read -> Not a valid Skyward Sword save file");
base::seek(0x01C, base::Beginning);
Uint32 headerSize = base::readUInt32(); // Seems to be (headerSize - 1)
if (headerSize != 0x1D)
throw zelda::error::InvalidOperationException("SSFileHeader::read -> Invalid header size, Corrupted data?");
// Time to read in each slot
file = new SSFile;
file->setRegion((magic == SSFile::USMagic ? NTSCURegion : (magic == SSFile::JAMagic ? NTSCJRegion : PALRegion)));
for (int i = 0; i < 3; i++)
{
SSQuest* q = new SSQuest((Uint8*)base::readBytes(0x53C0), 0x53C0);
Uint64 pos = base::position();
// seek to the skip data for this particular quest
base::seek(0xFB60 + (i * 0x24), base::Beginning);
q->setSkipData(base::readUBytes(0x24));
base::seek(pos, base::Beginning);
file->addQuest(q);
}
return file;
}
} // io
} // zelda

51
src/SSFileWriter.cpp Normal file
View File

@ -0,0 +1,51 @@
#include "SSFileWriter.hpp"
#include "SSFile.hpp"
#include "SSQuest.hpp"
namespace zelda
{
namespace io
{
SSFileWriter::SSFileWriter(Uint8 *data, Uint64 len)
: base(data, len)
{
base::setEndianess(BigEndian);
}
SSFileWriter::SSFileWriter(const std::string &filename)
: base(filename)
{
base::setEndianess(BigEndian);
}
void SSFileWriter::write(SSFile *file)
{
Uint32 magic = (file->region() == NTSCURegion ? SSFile::USMagic :
(file->region() == NTSCJRegion ? SSFile::JAMagic : SSFile::EUMagic));
base::writeUInt32(magic);
base::seek(0x1C, base::Beginning);
base::writeUInt32(0x1D);
std::vector<SSQuest*> quests = file->questList();
int i = 0;
for (SSQuest* q : quests)
{
// Write the save data
base::writeUBytes(q->data(), q->length());
Uint64 pos = base::position();
// Write the slots skip data
base::seek(0xFB60 + (i * 0x24), base::Beginning);
base::writeUBytes(q->skipData(), q->skipLength());
base::seek(pos, base::Beginning);
i++;
}
// write those padding bytes
base::seek(0xFBE0, base::Beginning);
save();
}
} // io
} // zelda

34
src/SSQuest.cpp Normal file
View File

@ -0,0 +1,34 @@
#include "SSQuest.hpp"
namespace zelda
{
SSQuest::SSQuest(Uint8 *data, Uint32 len)
: ZQuestFile(ZQuestFile::SS, BigEndian, data, len),
m_skipData(NULL),
m_skipLength(0)
{
}
void SSQuest::setSkipData(const Uint8 *data, Uint32 len)
{
if (m_skipData)
{
delete[] m_skipData;
m_skipData = NULL;
}
m_skipData = (Uint8*)data;
m_skipLength = len;
}
Uint8 *SSQuest::skipData() const
{
return m_skipData;
}
Uint32 SSQuest::skipLength() const
{
return m_skipLength;
}
} // zelda

View File

@ -180,6 +180,11 @@ Int8 Stream::readByte()
return *(Int8*)(m_data + m_position++);
}
Uint8 *Stream::readUBytes(Int64 length)
{
return (Uint8*)readBytes(length);
}
Int8* Stream::readBytes(Int64 length)
{
if (m_bitPosition > 0)

View File

@ -81,6 +81,8 @@ void ZQuestFile::setData(Uint8* data, Uint32 length)
{
delete[] m_data;
m_data = new Uint8[length];
// Why is this memcpy needed?
// I get SIGABRT without it, need to research
memcpy(m_data, data, length);
m_length = length;
}
@ -107,6 +109,7 @@ std::string ZQuestFile::gameString() const
void ZQuestFile::initGameStrings()
{
// Populate game strings
m_gameStrings.push_back("No Game");
m_gameStrings.push_back("Legend Of Zelda");
m_gameStrings.push_back("Adventure of Link");
@ -125,7 +128,7 @@ void ZQuestFile::initGameStrings()
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)");
m_gameStrings.push_back("A Link Between Worlds (Unreleased)"); // Probably should have this, but.....
}
}

View File

@ -66,6 +66,7 @@ ZQuestFile *ZQuestFileReader::read()
{
delete[] dst;
delete[] data;
// TODO: Make proper exception
throw error::InvalidOperationException("ZQuestFileReader::read -> Error decompressing data");
}

View File

@ -72,12 +72,12 @@ void ZQuestFileWriter::write(ZQuestFile* quest, bool compress)
base::writeUInt32(quest->length());
base::writeUInt32(quest->game());
base::writeUInt16(quest->endian() == BigEndian ? 0xFEFF : 0xFFFE);
base::writeUInt16(quest->endian() == BigEndian ? 0xFFFE : 0xFEFF);
base::seek(0x0A);
base::writeUBytes(questData, compLen);
base::save();
// Delete compressed data to preven memory leaks
// Delete compressed data to prevent memory leaks
if (questData != quest->data())
{
delete[] questData;