* Fixed some bugs

This commit is contained in:
Antidote 2014-02-26 21:46:26 -08:00
parent ebca406d71
commit 304baa45bb
5 changed files with 221 additions and 174 deletions

View File

@ -18,6 +18,10 @@
#include <string> #include <string>
#define __STRX(x) #x
#define __STR(x) __STRX(x)
#define __LINE_STRING__ __STR(__LINE__)
namespace zelda namespace zelda
{ {
namespace error namespace error
@ -53,4 +57,10 @@ protected:
} // error } // error
} // zelda } // zelda
#define THROW_EXCEPTION(msg) \
do \
{ \
throw zelda::error::Exception(__LINE_STRING__ " " __FILE__ " " msg); \
} while(0)
#endif #endif

View File

@ -2,6 +2,7 @@
#define INVALIDDATAEXCEPTION_HPP #define INVALIDDATAEXCEPTION_HPP
#include "Exception.hpp" #include "Exception.hpp"
#include <sstream>
namespace zelda namespace zelda
{ {
@ -20,10 +21,17 @@ class InvalidDataException : public Exception
{ {
public: public:
inline InvalidDataException(const std::string& error) inline InvalidDataException(const std::string& error)
: Exception("InvalidDataException: " + error) : Exception(error)
{ {
} }
}; };
} }
} }
#define THROW_INVALID_DATA(msg) \
do \
{ \
throw zelda::error::InvalidDataException(__LINE_STRING__ " " __FILE__ " " msg); \
} while(0)
#endif // INVALIDDATAEXCEPTION_HPP #endif // INVALIDDATAEXCEPTION_HPP

View File

@ -24,32 +24,41 @@ SkywardSwordFileReader::SkywardSwordFileReader(const std::string& filename)
SkywardSwordFile* SkywardSwordFileReader::read() SkywardSwordFile* SkywardSwordFileReader::read()
{ {
SkywardSwordFile* file = NULL; SkywardSwordFile* file = NULL;
if (base::length() != 0xFBE0) try
throw zelda::error::InvalidOperationException("SSFileReader::read -> File not the expected size of 0xFBE0");
Uint32 magic = base::readUInt32();
if (magic != SkywardSwordFile::USMagic && magic != SkywardSwordFile::JAMagic && magic != SkywardSwordFile::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 SkywardSwordFile;
file->setRegion((magic == SkywardSwordFile::USMagic ? NTSCURegion : (magic == SkywardSwordFile::JAMagic ? NTSCJRegion : PALRegion)));
for (int i = 0; i < 3; i++)
{ {
SkywardSwordQuest* q = new SkywardSwordQuest((Uint8*)base::readBytes(0x53C0), 0x53C0); if (base::length() != 0xFBE0)
Uint64 pos = base::position(); throw zelda::error::InvalidOperationException("SSFileReader::read -> File not the expected size of 0xFBE0");
// seek to the skip data for this particular quest
base::seek(0xFB60 + (i * 0x24), base::Beginning); Uint32 magic = base::readUInt32();
q->setSkipData(base::readUBytes(0x24));
base::seek(pos, base::Beginning); if (magic != SkywardSwordFile::USMagic && magic != SkywardSwordFile::JAMagic && magic != SkywardSwordFile::EUMagic)
file->addQuest(q); 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 SkywardSwordFile;
file->setRegion((magic == SkywardSwordFile::USMagic ? NTSCURegion : (magic == SkywardSwordFile::JAMagic ? NTSCJRegion : PALRegion)));
for (int i = 0; i < 3; i++)
{
SkywardSwordQuest* q = new SkywardSwordQuest((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);
}
}
catch(...)
{
delete file;
file = NULL;
throw;
} }
return file; return file;

View File

@ -23,124 +23,134 @@ SpriteFileReader::SpriteFileReader(const std::string& filepath)
Sakura::SpriteFile* SpriteFileReader::readFile() Sakura::SpriteFile* SpriteFileReader::readFile()
{ {
Uint32 magic = base::readUInt32(); Sakura::SpriteFile* ret = NULL;
try
if (magic != Sakura::SpriteFile::Magic)
throw zelda::error::InvalidOperationException("Not a valid Sakura Sprite container");
Uint32 version = base::readUInt32();
// TODO: Make this more verbose
if (version != Sakura::SpriteFile::Version)
throw zelda::error::InvalidOperationException("Unsupported version");
// After reading in the magic and version we need to load some
// metadata about the file.
// Such as the texture count, it's dimensions, and it's origin.
// After that we have the number of sprites contained in this
// sprite container.
Uint16 textureCount = base::readUInt16(); // Having it as a Uint16 gives us the ability to have up to 65536 different states
// This is probably overkill, but it's better safe than sorry.
Uint32 width = base::readUInt32();
Uint32 height = base::readUInt32();
float originX = base::readFloat();
float originY = base::readFloat();
Uint16 spriteCount = base::readUInt16();
// Lets go ahead and create or new container.
Sakura::SpriteFile* ret = new Sakura::SpriteFile(width, height, originX, originY);
// The next four bytes are reserved to keep the header 32 byte aligned.
// This isn't necessary for most systems, but it's eventually planned
// to migrate this code to Big Endian based systems, such as the wii
// which require data to be 32 byte aligned, or it causes some issues.
// It's also convenient to have this, for later expansion.
Uint32 reserved = base::readUInt32();
UNUSED(reserved);
// Next we have to load the textures
// If we tried to add them one at a time to the sprite container
// it will be slow as hell, so we store them in a vector locally
// then give that vector the the container, this bypasses the de-reference
// for each texture
std::vector<Sakura::STexture*> textures;
for (Uint16 i = 0; i < textureCount; i++)
{ {
Sakura::STexture* texture = new Sakura::STexture; Uint32 magic = base::readUInt32();
texture->Filepath = base::readString();
texture->Preload = base::readBool();
textures.push_back(texture);
}
ret->setTextures(textures); if (magic != Sakura::SpriteFile::Magic)
throw zelda::error::InvalidOperationException("Not a valid Sakura Sprite container");
// Now for the sprites Uint32 version = base::readUInt32();
// The sprites are a bit more difficult, they are stored in an unordered_map
// with it's name as the key, this means we can't have two sprites with the same name
// Normally this isn't a problem, but someone may decide to copy and paste a sprite
// and forget to change the name, that needs to be handled, but it's outside the scope
// of this reader.
std::unordered_map <std::string, Sakura::Sprite*> sprites;
for (Uint16 i = 0; i < spriteCount; i++) // TODO: Make this more verbose
{ if (version != Sakura::SpriteFile::Version)
Sakura::Sprite* sprite = new Sakura::Sprite(ret); throw zelda::error::InvalidOperationException("Unsupported version");
sprite->setName(base::readString());
Uint16 partCount = base::readUInt16();
Uint16 stateCount = base::readUInt16();
// Each state id corresponds to a texture held in the parent class // After reading in the magic and version we need to load some
std::vector<int> stateIds; // metadata about the file.
for (int j = 0; j < stateCount; j++) // Such as the texture count, it's dimensions, and it's origin.
stateIds.push_back(base::readUInt16()); // After that we have the number of sprites contained in this
// sprite container.
Uint16 textureCount = base::readUInt16(); // Having it as a Uint16 gives us the ability to have up to 65536 different states
// This is probably overkill, but it's better safe than sorry.
Uint32 width = base::readUInt32();
Uint32 height = base::readUInt32();
float originX = base::readFloat();
float originY = base::readFloat();
Uint16 spriteCount = base::readUInt16();
// Lets go ahead and create or new container.
ret = new Sakura::SpriteFile(width, height, originX, originY);
sprite->setStateIds(stateIds); // The next four bytes are reserved to keep the header 32 byte aligned.
// This isn't necessary for most systems, but it's eventually planned
// to migrate this code to Big Endian based systems, such as the wii
// which require data to be 32 byte aligned, or it causes some issues.
// It's also convenient to have this, for later expansion.
Uint32 reserved = base::readUInt32();
UNUSED(reserved);
// Now to read the sprite parts. // Next we have to load the textures
// The parts allow us to build retro style sprites very easily // If we tried to add them one at a time to the sprite container
// making it possible to use one texture atlas for all possible // it will be slow as hell, so we store them in a vector locally
// frame combinations, this reduces the amount of memory overhead // then give that vector the the container, this bypasses the de-reference
// and the storage footprint, while Sakura supports packs and zips // for each texture
// it's still a bad idea to have a metric ton of texture resources std::vector<Sakura::STexture*> textures;
// littering the place
std::vector<Sakura::SpritePart*> parts; for (Uint16 i = 0; i < textureCount; i++)
for (Uint8 j = 0; j < partCount; j++)
{ {
Sakura::SpritePart* part = new Sakura::SpritePart(sprite); Sakura::STexture* texture = new Sakura::STexture;
part->setName(base::readString()); texture->Filepath = base::readString();
part->setCollision(base::readBool()); texture->Preload = base::readBool();
textures.push_back(texture);
Uint32 frameCount = base::readUInt32();
std::vector<Sakura::SpriteFrame*> frames;
for (Uint32 k = 0; k < frameCount; k++)
{
float xOff = base::readFloat();
float yOff = base::readFloat();
float texXOff = base::readFloat();
float texYOff = base::readFloat();
Uint32 width = base::readUInt32();
Uint32 height = base::readUInt32();
float frameTime = base::readFloat();
bool flippedH = base::readBool();
bool flippedV = base::readBool();
frames.push_back(new Sakura::SpriteFrame(xOff, yOff, texXOff, texYOff, width, height, frameTime, flippedH, flippedV));
}
part->setFrames(frames);
parts.push_back(part);
} }
sprite->setParts(parts); ret->setTextures(textures);
if (sprite->name() != std::string())
sprites[sprite->name()] = sprite;
else
throw zelda::error::IOException("SSpriteFileReader::readFile -> Sprite names cannot be empty");
}
ret->setSprites(sprites); // Now for the sprites
// The sprites are a bit more difficult, they are stored in an unordered_map
// with it's name as the key, this means we can't have two sprites with the same name
// Normally this isn't a problem, but someone may decide to copy and paste a sprite
// and forget to change the name, that needs to be handled, but it's outside the scope
// of this reader.
std::unordered_map <std::string, Sakura::Sprite*> sprites;
for (Uint16 i = 0; i < spriteCount; i++)
{
Sakura::Sprite* sprite = new Sakura::Sprite(ret);
sprite->setName(base::readString());
Uint16 partCount = base::readUInt16();
Uint16 stateCount = base::readUInt16();
// Each state id corresponds to a texture held in the parent class
std::vector<int> stateIds;
for (int j = 0; j < stateCount; j++)
stateIds.push_back(base::readUInt16());
sprite->setStateIds(stateIds);
// Now to read the sprite parts.
// The parts allow us to build retro style sprites very easily
// making it possible to use one texture atlas for all possible
// frame combinations, this reduces the amount of memory overhead
// and the storage footprint, while Sakura supports packs and zips
// it's still a bad idea to have a metric ton of texture resources
// littering the place
std::vector<Sakura::SpritePart*> parts;
for (Uint8 j = 0; j < partCount; j++)
{
Sakura::SpritePart* part = new Sakura::SpritePart(sprite);
part->setName(base::readString());
part->setCollision(base::readBool());
Uint32 frameCount = base::readUInt32();
std::vector<Sakura::SpriteFrame*> frames;
for (Uint32 k = 0; k < frameCount; k++)
{
float xOff = base::readFloat();
float yOff = base::readFloat();
float texXOff = base::readFloat();
float texYOff = base::readFloat();
Uint32 width = base::readUInt32();
Uint32 height = base::readUInt32();
float frameTime = base::readFloat();
bool flippedH = base::readBool();
bool flippedV = base::readBool();
frames.push_back(new Sakura::SpriteFrame(xOff, yOff, texXOff, texYOff, width, height, frameTime, flippedH, flippedV));
}
part->setFrames(frames);
parts.push_back(part);
}
sprite->setParts(parts);
if (sprite->name() != std::string())
sprites[sprite->name()] = sprite;
else
throw zelda::error::IOException("SSpriteFileReader::readFile -> Sprite names cannot be empty");
}
ret->setSprites(sprites);
}
catch(...)
{
delete ret;
ret = NULL;
throw;
}
return ret; return ret;
} }

View File

@ -54,50 +54,60 @@ WiiSaveReader::WiiSaveReader(const std::string& filename)
WiiSave* WiiSaveReader::readSave() WiiSave* WiiSaveReader::readSave()
{ {
WiiSave* ret = new WiiSave; WiiSave* ret = new WiiSave;
if (length() < 0xF0C0) try
throw error::InvalidOperationException("WiiSaveReader::readSave -> Not a valid WiiSave");
WiiBanner* banner = this->readBanner();
if (!banner)
throw error::InvalidOperationException("WiiSaveReader::readSave -> Invalid banner");
ret->setBanner(banner);
Uint32 bkVer = base::readUInt32();
if (bkVer != 0x00000070)
throw error::InvalidOperationException("WiiSaveReader::readSave -> Invalid BacKup header size");
Uint32 bkMagic = base::readUInt32();
bkMagic = bkMagic;
if (bkMagic != 0x426B0001)
throw error::InvalidOperationException("WiiSaveReader::readSave -> Invalid BacKup header magic");
Uint32 ngId = base::readUInt32();
ngId = ngId;
Uint32 numFiles = base::readUInt32();
/*int fileSize =*/ base::readUInt32();
base::seek(8); // skip unknown data;
Uint32 totalSize = base::readUInt32();
base::seek(64); // Unknown (Most likely padding)
base::seek(8);
base::seek(6);
base::seek(2);
base::seek(0x10);
std::unordered_map<std::string, WiiFile*> files;
for (Uint32 i = 0; i < numFiles; ++i)
{ {
WiiFile* file = readFile(); if (length() < 0xF0C0)
if (file) throw error::InvalidOperationException("WiiSaveReader::readSave -> Not a valid WiiSave");
files["/"+file->filename()] = file;
WiiBanner* banner = this->readBanner();
if (!banner)
throw error::InvalidOperationException("WiiSaveReader::readSave -> Invalid banner");
ret->setBanner(banner);
Uint32 bkVer = base::readUInt32();
if (bkVer != 0x00000070)
throw error::InvalidOperationException("WiiSaveReader::readSave -> Invalid BacKup header size");
Uint32 bkMagic = base::readUInt32();
bkMagic = bkMagic;
if (bkMagic != 0x426B0001)
throw error::InvalidOperationException("WiiSaveReader::readSave -> Invalid BacKup header magic");
Uint32 ngId = base::readUInt32();
ngId = ngId;
Uint32 numFiles = base::readUInt32();
/*int fileSize =*/ base::readUInt32();
base::seek(8); // skip unknown data;
Uint32 totalSize = base::readUInt32();
base::seek(64); // Unknown (Most likely padding)
base::seek(8);
base::seek(6);
base::seek(2);
base::seek(0x10);
std::unordered_map<std::string, WiiFile*> files;
for (Uint32 i = 0; i < numFiles; ++i)
{
WiiFile* file = readFile();
if (file)
files["/"+file->filename()] = file;
}
ret->setFiles(files);
readCerts(totalSize);
}
catch(...)
{
delete ret;
ret = NULL;
throw;
} }
ret->setFiles(files);
readCerts(totalSize);
return ret; return ret;
} }
@ -154,7 +164,7 @@ WiiBanner* WiiSaveReader::readBanner()
gameId = base::readUInt64(); gameId = base::readUInt64();
bannerSize = base::readUInt32(); bannerSize = base::readUInt32();
permissions = base::readByte(); permissions = base::readByte();
/* unk =*/ base::readByte(); /* unk =*/ base::readByte();
base::seek(0x10); base::seek(0x10);
// skip padding // skip padding
base::seek(2); base::seek(2);