mirror of https://github.com/libAthena/athena.git
* Fixed compression code, old code was unreliable and failed at random
(don't use zlib's compress function) * More refactory work, ready for merge
This commit is contained in:
parent
d06c96d3aa
commit
b7b4df52f3
|
@ -20,6 +20,9 @@
|
|||
|
||||
#include "Types.hpp"
|
||||
|
||||
namespace zelda
|
||||
{
|
||||
|
||||
enum BowType : char
|
||||
{
|
||||
BowNone,
|
||||
|
@ -105,5 +108,6 @@ enum ALTTPTagAlong
|
|||
AfterBoss
|
||||
};
|
||||
|
||||
} // zelda
|
||||
#endif // __DOXYGEN_IGNORE__
|
||||
#endif // __ALTTP_ENUMS_HPP__
|
||||
|
|
|
@ -24,9 +24,9 @@
|
|||
namespace zelda
|
||||
{
|
||||
class ALTTPFile;
|
||||
|
||||
namespace io
|
||||
{
|
||||
|
||||
/*! \class ALTTPFileReader
|
||||
* \brief A Link to the Past save data reader class
|
||||
*
|
||||
|
@ -34,10 +34,10 @@ namespace io
|
|||
* all work is done using a memory buffer, and not read directly from the disk.
|
||||
* \sa BinaryReader
|
||||
*/
|
||||
|
||||
class ALTTPFileReader : public io::BinaryReader
|
||||
class ALTTPFileReader : protected BinaryReader
|
||||
{
|
||||
BINARYREADER_BASE
|
||||
|
||||
public:
|
||||
/*! \brief This constructor takes an existing buffer to read from.
|
||||
*
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace io
|
|||
* all work is done using a memory buffer, and not written directly to the disk.
|
||||
* \sa BinaryReader
|
||||
*/
|
||||
class ALTTPFileWriter : public io::BinaryWriter
|
||||
class ALTTPFileWriter : protected BinaryWriter
|
||||
{
|
||||
BINARYWRITER_BASE
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ namespace zelda
|
|||
{
|
||||
namespace io
|
||||
{
|
||||
|
||||
/*! \class BinaryReader
|
||||
* \brief A Stream class for reading binary data
|
||||
*
|
||||
|
@ -177,4 +178,5 @@ protected:
|
|||
private: \
|
||||
typedef zelda::io::BinaryReader base;
|
||||
#endif // BINARYREADER_BASE
|
||||
|
||||
#endif // __BINARYREADER_HPP__
|
||||
|
|
|
@ -138,6 +138,13 @@ public:
|
|||
* \param str The string to write to the buffer
|
||||
*/
|
||||
void writeUnicode(const std::string& str);
|
||||
|
||||
/*! \brief Writes an string to the buffer and advances the buffer.
|
||||
*
|
||||
* \sa Endian
|
||||
* \param str The string to write to the buffer
|
||||
*/
|
||||
void writeString(const std::string& str);
|
||||
protected:
|
||||
Int8 readByte();
|
||||
Int8* readBytes(Int64);
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace io
|
|||
namespace Compression
|
||||
{
|
||||
Int32 decompressZlib(Uint8* src, Uint32 srcLen, Uint8* dst, Uint32 dstLen);
|
||||
void compressZlib(const Uint8* src, Uint32 srcLen, Uint8* dst, Uint32* dstLen);
|
||||
Int32 compressZlib(const Uint8* src, Uint32 srcLen, Uint8* dst, Uint32 dstLen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace io
|
|||
* all work is done using a memory buffer, and not read directly from the disk.
|
||||
* \sa BinaryReader
|
||||
*/
|
||||
class MCFileReader : public io::BinaryReader
|
||||
class MCFileReader : protected BinaryReader
|
||||
{
|
||||
BINARYREADER_BASE
|
||||
public:
|
||||
|
|
|
@ -24,6 +24,9 @@ namespace zelda
|
|||
|
||||
class MCFile;
|
||||
|
||||
namespace io
|
||||
{
|
||||
|
||||
/*! \class MCFileWriter
|
||||
* \brief The Minish Cap Save save data writer class
|
||||
*
|
||||
|
@ -31,7 +34,7 @@ class MCFile;
|
|||
* all work is done using a memory buffer, and not written directly from the disk.
|
||||
* \sa BinaryWriter
|
||||
*/
|
||||
class MCFileWriter : public io::BinaryWriter
|
||||
class MCFileWriter : protected BinaryWriter
|
||||
{
|
||||
BINARYWRITER_BASE
|
||||
public:
|
||||
|
@ -64,6 +67,7 @@ private:
|
|||
void unscramble();
|
||||
};
|
||||
|
||||
} // io
|
||||
} // zelda
|
||||
|
||||
#endif // __MCFILEWRITER_HPP__
|
||||
|
|
|
@ -80,16 +80,16 @@ public:
|
|||
* \throw IOException
|
||||
*/
|
||||
virtual void writeBit(bool val);
|
||||
|
||||
/*! \brief Writes a byte at the current position and advances the position by one byte.
|
||||
* \param byte The value to write
|
||||
* \throw IOException
|
||||
*/
|
||||
virtual void writeUByte(Uint8 byte);
|
||||
|
||||
/*! \brief Writes a byte at the current position and advances the position by one byte.
|
||||
* \param byte The value to write
|
||||
* \throw IOException
|
||||
*/
|
||||
* \param byte The value to write
|
||||
* \throw IOException
|
||||
*/
|
||||
virtual void writeByte(Int8 byte);
|
||||
|
||||
/*! \brief Writes the given buffer with the specified length, buffers can be bigger than the length
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace zelda
|
||||
{
|
||||
/*! \enum Endian
|
||||
* \brief Allows the user to specify the Endianness of data.<br />
|
||||
* The proper actions are automatically taken depending on platform and
|
||||
|
@ -27,6 +30,8 @@ enum Endian
|
|||
LittleEndian, //!< Specifies that the Stream is Little Endian (LSB)
|
||||
BigEndian //!< Specifies that the Stream is Big Endian (MSB)
|
||||
};
|
||||
} // zelda
|
||||
#endif
|
||||
|
||||
// 8 bits integer types
|
||||
#if UCHAR_MAX == 0xFF
|
||||
|
|
|
@ -12,12 +12,13 @@
|
|||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with libZelda. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
#ifndef __WII_SAVE_READER_HPP__
|
||||
#define __WII_SAVE_READER_HPP__
|
||||
|
||||
#include <Types.hpp>
|
||||
#include <utility.hpp>
|
||||
#include <BinaryReader.hpp>
|
||||
#include "Types.hpp"
|
||||
#include "utility.hpp"
|
||||
#include "BinaryReader.hpp"
|
||||
|
||||
namespace zelda
|
||||
{
|
||||
|
@ -36,7 +37,7 @@ namespace io
|
|||
* all work is done using a memory buffer, and not read directly from the disk.
|
||||
* \sa BinaryReader
|
||||
*/
|
||||
class WiiSaveReader : public io::BinaryReader
|
||||
class WiiSaveReader : protected BinaryReader
|
||||
{
|
||||
BINARYREADER_BASE
|
||||
public:
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
|
||||
namespace zelda
|
||||
{
|
||||
|
||||
class WiiSave;
|
||||
class WiiBanner;
|
||||
class WiiFile;
|
||||
|
@ -38,7 +37,7 @@ namespace io
|
|||
* all work is done using a memory buffer, and not written directly to the disk.
|
||||
* \sa BinaryReader
|
||||
*/
|
||||
class WiiSaveWriter : public io::BinaryWriter
|
||||
class WiiSaveWriter : protected BinaryWriter
|
||||
{
|
||||
BINARYWRITER_BASE
|
||||
public:
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#ifndef ZQUEST_HPP
|
||||
#define ZQUEST_HPP
|
||||
|
||||
#include <Types.hpp>
|
||||
#include "Types.hpp"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
@ -25,65 +25,70 @@ namespace zelda
|
|||
/*!
|
||||
* \brief The ZQuest class
|
||||
*/
|
||||
class ZQuest
|
||||
class ZQuestFile
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* \brief Major
|
||||
* \brief The current major version of the ZQuest format
|
||||
*/
|
||||
static const Uint32 Major;
|
||||
/*!
|
||||
* \brief Minor
|
||||
* \brief The current minor version of the ZQuest format
|
||||
*/
|
||||
static const Uint32 Minor;
|
||||
/*!
|
||||
* \brief Revision
|
||||
* \brief The current revision of the ZQuest format
|
||||
*/
|
||||
static const Uint32 Revision;
|
||||
/*!
|
||||
* \brief Build
|
||||
* \brief The current build of the ZQuest format
|
||||
*/
|
||||
static const Uint32 Build;
|
||||
/*!
|
||||
* \brief Version
|
||||
* \brief The current version of the ZQuest format
|
||||
*/
|
||||
static const Uint32 Version;
|
||||
|
||||
/*!
|
||||
* \brief Magic
|
||||
* \brief The magic number used to identify the file e.g. "ZQS1"
|
||||
*/
|
||||
static const Uint32 Magic;
|
||||
|
||||
/*!
|
||||
* \brief The Game enum
|
||||
* \enum Game
|
||||
* \brief The list of games currently supported by ZQuest
|
||||
*/
|
||||
enum Game
|
||||
{
|
||||
NoGame,
|
||||
LegendofZelda,
|
||||
AdventureOfLink,
|
||||
ALinkToThePast,
|
||||
LinksAwakening,
|
||||
OcarinaOfTime,
|
||||
OcarinaOfTime3D,
|
||||
MajorasMask,
|
||||
OracleOfSeasons,
|
||||
OracleOfAges,
|
||||
FourSwords,
|
||||
WindWaker,
|
||||
FourSwordsAdventures,
|
||||
MinishCap,
|
||||
TwilightPrincess,
|
||||
PhantomHourglass,
|
||||
SpiritTracks,
|
||||
SkywardSword,
|
||||
ALinkBetweenWorlds // Not released
|
||||
NoGame, //!< None or Unsupported
|
||||
LoZ, //!< Legend of Zelda
|
||||
AoL, //!< Adventure of Link
|
||||
ALttP, //!< A Link to the Past
|
||||
LA, //!< Links Awakening
|
||||
OoT, //!< Ocarin of Time
|
||||
OoT3D, //!< Ocarina of Time 3D
|
||||
MM, //!< Majora's Mask
|
||||
OoS, //!< Oracle of Season
|
||||
OoA, //!< Oracle of Ages
|
||||
FS, //!< Four Swords
|
||||
WW, //!< Wind Waker
|
||||
FSA, //!< Four Swords Adventures
|
||||
MC, //!< Minish Cap
|
||||
TP, //!< Twilight Princess
|
||||
PH, //!< Phantom Hourglass
|
||||
ST, //!< Spirit Tracks
|
||||
SS, //!< Skyward Sword
|
||||
ALBW, //!< A Link Between Worlds
|
||||
// Add more games here
|
||||
|
||||
// This must always be last
|
||||
GameCount //!< Total number of supported games
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief ZQuest
|
||||
*/
|
||||
ZQuest();
|
||||
ZQuestFile();
|
||||
|
||||
/*!
|
||||
* \brief ZQuest
|
||||
|
@ -92,8 +97,8 @@ public:
|
|||
* \param data
|
||||
* \param length
|
||||
*/
|
||||
ZQuest(Game game, Endian endian, Uint8* data, Uint32 length);
|
||||
~ZQuest();
|
||||
ZQuestFile(Game game, Endian endian, Uint8* data, Uint32 length);
|
||||
~ZQuestFile();
|
||||
|
||||
/*!
|
||||
* \brief setGame
|
||||
|
@ -121,9 +126,10 @@ public:
|
|||
|
||||
/*!
|
||||
* \brief setData
|
||||
* \param data
|
||||
* \param data The data to assign
|
||||
* \param length The length of the data
|
||||
*/
|
||||
void setData(Uint8* data);
|
||||
void setData(Uint8* data, Uint32 length);
|
||||
|
||||
/*!
|
||||
* \brief data
|
||||
|
@ -131,12 +137,6 @@ public:
|
|||
*/
|
||||
Uint8* data() const;
|
||||
|
||||
/*!
|
||||
* \brief setLength
|
||||
* \param length
|
||||
*/
|
||||
void setLength(Uint32 length);
|
||||
|
||||
/*!
|
||||
* \brief length
|
||||
* \return
|
|
@ -20,16 +20,18 @@
|
|||
|
||||
namespace zelda
|
||||
{
|
||||
class ZQuest;
|
||||
class ZQuestFile;
|
||||
|
||||
namespace io
|
||||
{
|
||||
|
||||
/*!
|
||||
* \brief The ZQuestFileReader class
|
||||
*/
|
||||
class ZQuestFileReader : public io::BinaryReader
|
||||
class ZQuestFileReader : protected BinaryReader
|
||||
{
|
||||
BINARYREADER_BASE
|
||||
|
||||
public:
|
||||
/*!
|
||||
* \brief ZQuestFileReader
|
||||
|
@ -48,7 +50,7 @@ public:
|
|||
* \brief read
|
||||
* \return
|
||||
*/
|
||||
ZQuest* read();
|
||||
ZQuestFile* read();
|
||||
};
|
||||
|
||||
} // io
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
namespace zelda
|
||||
{
|
||||
class ZQuest;
|
||||
class ZQuestFile;
|
||||
|
||||
namespace io
|
||||
{
|
||||
|
@ -28,7 +28,7 @@ namespace io
|
|||
/*!
|
||||
* \brief The ZQuestFileWriter class
|
||||
*/
|
||||
class ZQuestFileWriter : public io::BinaryWriter
|
||||
class ZQuestFileWriter : protected BinaryWriter
|
||||
{
|
||||
BINARYWRITER_BASE
|
||||
|
||||
|
@ -51,7 +51,7 @@ public:
|
|||
* \param quest
|
||||
* \param compress
|
||||
*/
|
||||
void write(ZQuest* quest, bool compress = true);
|
||||
void write(ZQuestFile* quest, bool compress = true);
|
||||
};
|
||||
|
||||
} // io
|
||||
|
|
|
@ -88,7 +88,7 @@ extern "C"
|
|||
* Typedefs:
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
typedef struct auth_md5Ctx_
|
||||
{
|
||||
unsigned int len;
|
||||
unsigned int ABCD[4];
|
||||
|
|
|
@ -19,13 +19,19 @@
|
|||
#include <string>
|
||||
#include "Types.hpp"
|
||||
|
||||
bool isEmpty(Int8*, size_t);
|
||||
namespace zelda
|
||||
{
|
||||
namespace utility
|
||||
{
|
||||
|
||||
unsigned short swapU16(unsigned short val );
|
||||
short swap16 (short val );
|
||||
unsigned int swapU32(unsigned int val);
|
||||
int swap32 (int val );
|
||||
long long swap64 (long long val);
|
||||
bool isEmpty(Int8*, Uint32);
|
||||
|
||||
Uint16 swapU16(Uint16 val );
|
||||
Int16 swap16 (Int16 val );
|
||||
Uint32 swapU32(Uint32 val);
|
||||
Int32 swap32 (Int32 val );
|
||||
Uint64 swapU64(Uint64 val);
|
||||
Int64 swap64 (Int64 val);
|
||||
|
||||
float swapFloat(float val);
|
||||
double swapDouble(double val);
|
||||
|
@ -36,4 +42,8 @@ void fillRandom(Uint8 * rndArea, Uint8 count);
|
|||
|
||||
void yaz0Decode(Uint8* src, Uint8* dst, Uint32 uncompressedSize);
|
||||
|
||||
|
||||
} // utility
|
||||
} // zelda
|
||||
|
||||
#endif
|
||||
|
|
|
@ -50,9 +50,9 @@ HEADERS += \
|
|||
include/MCFileWriter.hpp \
|
||||
include/ZQuestFileWriter.hpp \
|
||||
include/ZQuestFileReader.hpp \
|
||||
include/ZQuest.hpp \
|
||||
include/Compression.hpp \
|
||||
include/WiiImage.hpp
|
||||
include/WiiImage.hpp \
|
||||
include/ZQuestFile.hpp
|
||||
|
||||
SOURCES += \
|
||||
src/utility.cpp \
|
||||
|
@ -79,9 +79,9 @@ SOURCES += \
|
|||
src/MCFileWriter.cpp \
|
||||
src/ZQuestFileWriter.cpp \
|
||||
src/ZQuestFileReader.cpp \
|
||||
src/ZQuest.cpp \
|
||||
src/Compression.cpp \
|
||||
src/WiiImage.cpp
|
||||
src/WiiImage.cpp \
|
||||
src/ZQuestFile.cpp
|
||||
|
||||
system("exec doxygen libzelda.conf")
|
||||
#system("cd doc/latex && make")
|
||||
|
|
|
@ -103,8 +103,8 @@ Int16 BinaryReader::readInt16()
|
|||
Int16 ret = *(Int16*)(m_data + m_position);
|
||||
m_position += 2;
|
||||
|
||||
if ((!isSystemBigEndian() && m_endian == BigEndian) || (isSystemBigEndian() && m_endian == LittleEndian))
|
||||
ret = swap16(ret);
|
||||
if ((!utility::isSystemBigEndian() && m_endian == BigEndian) || (utility::isSystemBigEndian() && m_endian == LittleEndian))
|
||||
ret = utility::swap16(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -120,8 +120,8 @@ Uint16 BinaryReader::readUInt16()
|
|||
Uint16 ret = *(Uint16*)(m_data + m_position);
|
||||
m_position += 2;
|
||||
|
||||
if ((!isSystemBigEndian() && m_endian == BigEndian) || (isSystemBigEndian() && m_endian == LittleEndian))
|
||||
ret = swapU16(ret);
|
||||
if ((!utility::isSystemBigEndian() && m_endian == BigEndian) || (utility::isSystemBigEndian() && m_endian == LittleEndian))
|
||||
ret = utility::swapU16(ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -138,8 +138,8 @@ Int32 BinaryReader::readInt32()
|
|||
Int32 ret = *(Int32*)(m_data + m_position);
|
||||
m_position += 4;
|
||||
|
||||
if ((!isSystemBigEndian() && m_endian == BigEndian) || (isSystemBigEndian() && m_endian == LittleEndian))
|
||||
ret = swap32(ret);
|
||||
if ((!utility::isSystemBigEndian() && m_endian == BigEndian) || (utility::isSystemBigEndian() && m_endian == LittleEndian))
|
||||
ret = utility::swap32(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -156,8 +156,8 @@ Uint32 BinaryReader::readUInt32()
|
|||
Uint32 ret = *(Uint32*)(m_data + m_position);
|
||||
m_position += 4;
|
||||
|
||||
if ((!isSystemBigEndian() && m_endian == BigEndian) || (isSystemBigEndian() && m_endian == LittleEndian))
|
||||
ret = swapU32(ret);
|
||||
if ((!utility::isSystemBigEndian() && m_endian == BigEndian) || (utility::isSystemBigEndian() && m_endian == LittleEndian))
|
||||
ret = utility::swapU32(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -174,8 +174,8 @@ Int64 BinaryReader::readInt64()
|
|||
Int64 ret = *(Int64*)(m_data + m_position);
|
||||
m_position += 8;
|
||||
|
||||
if ((!isSystemBigEndian() && m_endian == BigEndian) || (isSystemBigEndian() && m_endian == LittleEndian))
|
||||
ret = swap64(ret);
|
||||
if ((!utility::isSystemBigEndian() && m_endian == BigEndian) || (utility::isSystemBigEndian() && m_endian == LittleEndian))
|
||||
ret = utility::swap64(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -191,8 +191,8 @@ Uint64 BinaryReader::readUInt64()
|
|||
Uint64 ret = *(Uint64*)(m_data + m_position);
|
||||
m_position += 8;
|
||||
|
||||
if ((!isSystemBigEndian() && m_endian == BigEndian) || (isSystemBigEndian() && m_endian == LittleEndian))
|
||||
ret = swap64(ret);
|
||||
if ((!utility::isSystemBigEndian() && m_endian == BigEndian) || (utility::isSystemBigEndian() && m_endian == LittleEndian))
|
||||
ret = utility::swapU64(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -209,8 +209,8 @@ float BinaryReader::readFloat()
|
|||
float ret = *(float*)(m_data + m_position);
|
||||
m_position += 4;
|
||||
|
||||
if ((!isSystemBigEndian() && m_endian == BigEndian) || (isSystemBigEndian() && m_endian == LittleEndian))
|
||||
ret = swapFloat(ret);
|
||||
if ((!utility::isSystemBigEndian() && m_endian == BigEndian) || (utility::isSystemBigEndian() && m_endian == LittleEndian))
|
||||
ret = utility::swapFloat(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -227,8 +227,8 @@ double BinaryReader::readDouble()
|
|||
double ret = *(double*)(m_data + m_position);
|
||||
m_position += 8;
|
||||
|
||||
if ((!isSystemBigEndian() && m_endian == BigEndian) || (isSystemBigEndian() && m_endian == LittleEndian))
|
||||
ret = swapDouble(ret);
|
||||
if ((!utility::isSystemBigEndian() && m_endian == BigEndian) || (utility::isSystemBigEndian() && m_endian == LittleEndian))
|
||||
ret = utility::swapDouble(ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -105,8 +105,8 @@ void BinaryWriter::writeInt16(Int16 val)
|
|||
else if (m_position > m_length)
|
||||
throw error::IOException("BinaryWriter::WriteInt16 -> Position outside stream bounds");
|
||||
|
||||
if ((!isSystemBigEndian() && m_endian == BigEndian) || (isSystemBigEndian() && m_endian == LittleEndian))
|
||||
val = swap16(val);
|
||||
if ((!utility::isSystemBigEndian() && m_endian == BigEndian) || (utility::isSystemBigEndian() && m_endian == LittleEndian))
|
||||
val = utility::swap16(val);
|
||||
|
||||
*(Int16*)(m_data + m_position) = val;
|
||||
m_position += sizeof(Int16);
|
||||
|
@ -126,8 +126,8 @@ void BinaryWriter::writeUInt16(Uint16 val)
|
|||
throw error::IOException("BinaryWriter::WriteUInt16 -> Position outside stream bounds");
|
||||
|
||||
|
||||
if ((!isSystemBigEndian() && m_endian == BigEndian) || (isSystemBigEndian() && m_endian == LittleEndian))
|
||||
val = swapU16(val);
|
||||
if ((!utility::isSystemBigEndian() && m_endian == BigEndian) || (utility::isSystemBigEndian() && m_endian == LittleEndian))
|
||||
val = utility::swapU16(val);
|
||||
|
||||
*(Uint16*)(m_data + m_position) = val;
|
||||
m_position += sizeof(Uint16);
|
||||
|
@ -146,8 +146,8 @@ void BinaryWriter::writeInt32(Int32 val)
|
|||
else if (m_position > m_length)
|
||||
throw error::IOException("BinaryWriter::WriteInt32 -> Position outside stream bounds");
|
||||
|
||||
if ((!isSystemBigEndian() && m_endian == BigEndian) || (isSystemBigEndian() && m_endian == LittleEndian))
|
||||
val = swap32(val);
|
||||
if ((!utility::isSystemBigEndian() && m_endian == BigEndian) || (utility::isSystemBigEndian() && m_endian == LittleEndian))
|
||||
val = utility::swap32(val);
|
||||
|
||||
*(Int32*)(m_data + m_position) = val;
|
||||
m_position += sizeof(Int32);
|
||||
|
@ -166,8 +166,8 @@ void BinaryWriter::writeUInt32(Uint32 val)
|
|||
else if (m_position > m_length)
|
||||
throw error::IOException("BinaryWriter::WriteUInt32 -> Position outside stream bounds");
|
||||
|
||||
if ((!isSystemBigEndian() && m_endian == BigEndian) || (isSystemBigEndian() && m_endian == LittleEndian))
|
||||
val = swap32(val);
|
||||
if ((!utility::isSystemBigEndian() && m_endian == BigEndian) || (utility::isSystemBigEndian() && m_endian == LittleEndian))
|
||||
val = utility::swapU32(val);
|
||||
|
||||
*(Uint32*)(m_data + m_position) = val;
|
||||
m_position += sizeof(Uint32);
|
||||
|
@ -187,8 +187,8 @@ void BinaryWriter::writeInt64(Int64 val)
|
|||
throw error::IOException("BinaryWriter::WriteInt64 -> Position outside stream bounds");
|
||||
|
||||
|
||||
if ((!isSystemBigEndian() && m_endian == BigEndian) || (isSystemBigEndian() && m_endian == LittleEndian))
|
||||
val = swap64(val);
|
||||
if ((!utility::isSystemBigEndian() && m_endian == BigEndian) || (utility::isSystemBigEndian() && m_endian == LittleEndian))
|
||||
val = utility::swap64(val);
|
||||
|
||||
*(Int64*)(m_data + m_position) = val;
|
||||
m_position += sizeof(Int64);
|
||||
|
@ -207,8 +207,8 @@ void BinaryWriter::writeUInt64(Uint64 val)
|
|||
else if (m_position > m_length)
|
||||
throw error::IOException("BinaryWriter::WriteUInt64 -> Position outside stream bounds");
|
||||
|
||||
if ((!isSystemBigEndian() && m_endian == BigEndian) || (isSystemBigEndian() && m_endian == LittleEndian))
|
||||
val = swap64(val);
|
||||
if ((!utility::isSystemBigEndian() && m_endian == BigEndian) || (utility::isSystemBigEndian() && m_endian == LittleEndian))
|
||||
val = utility::swapU64(val);
|
||||
|
||||
*(Uint64*)(m_data + m_position) = val;
|
||||
m_position += sizeof(Uint64);
|
||||
|
@ -227,8 +227,8 @@ void BinaryWriter::writeFloat(float val)
|
|||
else if (m_position > m_length)
|
||||
throw error::IOException("BinaryWriter::WriteFloat -> Position outside stream bounds");
|
||||
|
||||
if ((!isSystemBigEndian() && m_endian == BigEndian) || (isSystemBigEndian() && m_endian == LittleEndian))
|
||||
val = swapFloat(val);
|
||||
if ((!utility::isSystemBigEndian() && m_endian == BigEndian) || (utility::isSystemBigEndian() && m_endian == LittleEndian))
|
||||
val = utility::swapFloat(val);
|
||||
|
||||
*(float*)(m_data + m_position) = val;
|
||||
m_position += sizeof(float);
|
||||
|
@ -247,8 +247,8 @@ void BinaryWriter::writeDouble(double val)
|
|||
else if (m_position > m_length)
|
||||
throw error::IOException("BinaryWriter::WriteDouble -> Position outside stream bounds");
|
||||
|
||||
if ((!isSystemBigEndian() && m_endian == BigEndian) || (isSystemBigEndian() && m_endian == LittleEndian))
|
||||
val = swapDouble(val);
|
||||
if ((!utility::isSystemBigEndian() && m_endian == BigEndian) || (utility::isSystemBigEndian() && m_endian == LittleEndian))
|
||||
val = utility::swapDouble(val);
|
||||
|
||||
*(double*)(m_data + m_position)= val;
|
||||
m_position += sizeof(double);
|
||||
|
@ -287,6 +287,16 @@ void BinaryWriter::writeUnicode(const std::string& str)
|
|||
}
|
||||
}
|
||||
|
||||
void BinaryWriter::writeString(const std::string& str)
|
||||
{
|
||||
for (Uint8 c : str)
|
||||
{
|
||||
if (c != '\0')
|
||||
writeUByte(c);
|
||||
}
|
||||
writeUByte(0);
|
||||
}
|
||||
|
||||
bool BinaryWriter::isOpenForReading()
|
||||
{
|
||||
return false;
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
// along with libZelda. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
#include "Compression.hpp"
|
||||
#include "Exception.hpp"
|
||||
#include <iostream>
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
|
@ -26,7 +28,7 @@ namespace Compression
|
|||
|
||||
Int32 decompressZlib(Uint8 *src, Uint32 srcLen, Uint8* dst, Uint32 dstLen)
|
||||
{
|
||||
z_stream strm;
|
||||
z_stream strm = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
strm.total_in = strm.avail_in = srcLen;
|
||||
strm.total_out = strm.avail_out = dstLen;
|
||||
strm.next_in = (Bytef *) src;
|
||||
|
@ -39,18 +41,20 @@ Int32 decompressZlib(Uint8 *src, Uint32 srcLen, Uint8* dst, Uint32 dstLen)
|
|||
Int32 err = -1;
|
||||
Int32 ret = -1;
|
||||
|
||||
err = inflateInit2(&strm, (15 + 32)); //15 window bits, and the +32 tells zlib to to detect if using gzip or zlib
|
||||
if (err == Z_OK) {
|
||||
err = inflateInit(&strm); //15 window bits, and the +32 tells zlib to to detect if using gzip or zlib
|
||||
if (err == Z_OK)
|
||||
{
|
||||
err = inflate(&strm, Z_FINISH);
|
||||
if (err == Z_STREAM_END) {
|
||||
if (err == Z_STREAM_END)
|
||||
ret = strm.total_out;
|
||||
}
|
||||
else {
|
||||
inflateEnd(&strm);
|
||||
return err;
|
||||
else
|
||||
{
|
||||
inflateEnd(&strm);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
inflateEnd(&strm);
|
||||
return err;
|
||||
}
|
||||
|
@ -60,9 +64,43 @@ Int32 decompressZlib(Uint8 *src, Uint32 srcLen, Uint8* dst, Uint32 dstLen)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void compressZlib(const Uint8 *src, Uint32 srcLen, Uint8 *dst, Uint32* dstLen)
|
||||
Int32 compressZlib(const Uint8 *src, Uint32 srcLen, Uint8 *dst, Uint32 dstLen)
|
||||
{
|
||||
compress(dst, (uLongf*)dstLen, src, srcLen);
|
||||
z_stream strm = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
strm.total_in = strm.avail_in = srcLen;
|
||||
strm.total_out = strm.avail_out = dstLen;
|
||||
strm.next_in = (Bytef *) src;
|
||||
strm.next_out = (Bytef *) dst;
|
||||
|
||||
strm.zalloc = Z_NULL;
|
||||
strm.zfree = Z_NULL;
|
||||
strm.opaque = Z_NULL;
|
||||
|
||||
Int32 err = -1;
|
||||
Int32 ret = -1;
|
||||
|
||||
err = deflateInit(&strm, Z_BEST_COMPRESSION);
|
||||
|
||||
if (err == Z_OK)
|
||||
{
|
||||
err = deflate(&strm, Z_FINISH);
|
||||
if (err == Z_STREAM_END)
|
||||
ret = strm.total_out;
|
||||
else
|
||||
{
|
||||
deflateEnd(&strm);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
deflateEnd(&strm);
|
||||
return err;
|
||||
}
|
||||
|
||||
deflateEnd(&strm);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // Compression
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
namespace zelda
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
|
||||
MCFileWriter::MCFileWriter(Uint8* data, Uint64 length)
|
||||
: base(data, length)
|
||||
|
@ -93,4 +95,5 @@ void MCFileWriter::unscramble()
|
|||
}
|
||||
}
|
||||
|
||||
} // io
|
||||
} // zelda
|
||||
|
|
|
@ -156,9 +156,9 @@ std::vector<std::string> TextStream::readLines(Uint32 numLines)
|
|||
std::string TextStream::readLineAt(Uint32 line)
|
||||
{
|
||||
if (m_accessmode != ReadOnly && m_accessmode != ReadWrite)
|
||||
throw error::InvalidOperationException("Stream not open for reading");
|
||||
throw error::InvalidOperationException("TextStream::readLineAt -> Stream not open for reading");
|
||||
if (line <= 0)
|
||||
throw error::InvalidOperationException("A line cannot be zero indexed");
|
||||
throw error::InvalidOperationException("TextStream::readLineAt -> A line cannot be zero indexed");
|
||||
|
||||
if ((line - 1) >= m_lines.size())
|
||||
throw error::IOException("TextStream::readLineAt -> Line index out of range");
|
||||
|
|
|
@ -72,7 +72,7 @@ Uint8 *WiiImage::toRGBA()
|
|||
Uint16 oldpixel = *(Uint16*)(m_data + ((iv++) * 2));
|
||||
//if((x >= m_width) || (y >= m_height))
|
||||
// continue;
|
||||
oldpixel = swapU16(oldpixel);
|
||||
oldpixel = utility::swapU16(oldpixel);
|
||||
if(oldpixel & (1 << 15))
|
||||
{
|
||||
// RGB5
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#include "WiiBanner.hpp"
|
||||
#include "BinaryReader.hpp"
|
||||
#include "BinaryWriter.hpp"
|
||||
#include "IOException.hpp"
|
||||
#include "aes.h"
|
||||
#include "ec.h"
|
||||
#include "utility.hpp"
|
||||
|
|
|
@ -225,7 +225,7 @@ WiiImage* WiiSaveReader::readImage(Uint32 width, Uint32 height)
|
|||
{
|
||||
Uint8* image = (Uint8*)base::readBytes(width*height*2);
|
||||
|
||||
if (!isEmpty((Int8*)image, width*height*2))
|
||||
if (!utility::isEmpty((Int8*)image, width*height*2))
|
||||
return new WiiImage(width, height, image);
|
||||
|
||||
return NULL;
|
||||
|
|
|
@ -167,15 +167,15 @@ Uint32 WiiSaveWriter::writeFile(WiiFile *file)
|
|||
base::writeByte(file->type());
|
||||
|
||||
Uint8 name[0x45];
|
||||
fillRandom(name, 0x45);
|
||||
utility::fillRandom(name, 0x45);
|
||||
memcpy(name, file->filename().c_str(), file->filename().size());
|
||||
name[file->filename().size()] = '\0';
|
||||
base::writeBytes((Int8*)name, 0x45);
|
||||
Uint8 iv[16];
|
||||
fillRandom(iv, 0x10);
|
||||
utility::fillRandom(iv, 0x10);
|
||||
base::writeBytes((Int8*)iv, 0x10);
|
||||
Uint8 crap[0x20];
|
||||
fillRandom(crap, 0x20);
|
||||
utility::fillRandom(crap, 0x20);
|
||||
base::writeBytes((Int8*)crap, 0x20);
|
||||
|
||||
if (file->type() == WiiFile::File)
|
||||
|
@ -245,8 +245,8 @@ void WiiSaveWriter::writeCerts(Uint32 filesSize, Uint32 ngId, Uint8 *ngPriv, Uin
|
|||
|
||||
generate_ecdsa(sig, sig+30, apPriv, hash2);
|
||||
int stuff = 0x2f536969;
|
||||
if (!isSystemBigEndian())
|
||||
stuff = swap32(stuff);
|
||||
if (!utility::isSystemBigEndian())
|
||||
stuff = utility::swap32(stuff);
|
||||
|
||||
*(Uint32*)(sig+60) = stuff;
|
||||
delete[] hash2;
|
||||
|
|
|
@ -13,21 +13,21 @@
|
|||
// You should have received a copy of the GNU General Public License
|
||||
// along with libZelda. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
#include "ZQuest.hpp"
|
||||
#include "ZQuestFile.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 ZQuestFile::Major = 1;
|
||||
const Uint32 ZQuestFile::Minor = 0;
|
||||
const Uint32 ZQuestFile::Revision = 0;
|
||||
const Uint32 ZQuestFile::Build = 0;
|
||||
|
||||
const Uint32 ZQuest::Version = Major | (Minor << 8) | (Revision << 16) | (Build << 24);
|
||||
const Uint32 ZQuestFile::Version = Major | (Minor << 8) | (Revision << 16) | (Build << 24);
|
||||
|
||||
const Uint32 ZQuest::Magic = 'Z' | ('Q' << 8) | ('S' << 16) | ('1' << 24);
|
||||
const Uint32 ZQuestFile::Magic = 'Z' | ('Q' << 8) | ('S' << 16) | ('1' << 24);
|
||||
|
||||
ZQuest::ZQuest()
|
||||
ZQuestFile::ZQuestFile()
|
||||
: m_game(NoGame),
|
||||
m_endian(LittleEndian),
|
||||
m_data(NULL),
|
||||
|
@ -36,7 +36,7 @@ ZQuest::ZQuest()
|
|||
initGameStrings();
|
||||
}
|
||||
|
||||
ZQuest::ZQuest(ZQuest::Game game, Endian endian, Uint8* data, Uint32 length)
|
||||
ZQuestFile::ZQuestFile(ZQuestFile::Game game, Endian endian, Uint8* data, Uint32 length)
|
||||
: m_game(game),
|
||||
m_endian(endian),
|
||||
m_data(data),
|
||||
|
@ -45,34 +45,34 @@ ZQuest::ZQuest(ZQuest::Game game, Endian endian, Uint8* data, Uint32 length)
|
|||
initGameStrings();
|
||||
}
|
||||
|
||||
ZQuest::~ZQuest()
|
||||
ZQuestFile::~ZQuestFile()
|
||||
{
|
||||
delete[] m_data;
|
||||
m_data = NULL;
|
||||
m_length = 0;
|
||||
}
|
||||
|
||||
void ZQuest::setGame(ZQuest::Game game)
|
||||
void ZQuestFile::setGame(ZQuestFile::Game game)
|
||||
{
|
||||
m_game = game;
|
||||
}
|
||||
|
||||
ZQuest::Game ZQuest::game() const
|
||||
ZQuestFile::Game ZQuestFile::game() const
|
||||
{
|
||||
return m_game;
|
||||
}
|
||||
|
||||
void ZQuest::setEndian(Endian endian)
|
||||
void ZQuestFile::setEndian(Endian endian)
|
||||
{
|
||||
m_endian = endian;
|
||||
}
|
||||
|
||||
Endian ZQuest::endian() const
|
||||
Endian ZQuestFile::endian() const
|
||||
{
|
||||
return m_endian;
|
||||
}
|
||||
|
||||
void ZQuest::setData(Uint8* data)
|
||||
void ZQuestFile::setData(Uint8* data, Uint32 length)
|
||||
{
|
||||
// ensure we're not overwritting our data without freeing first
|
||||
// or assigning unnecessisarily
|
||||
|
@ -80,25 +80,22 @@ void ZQuest::setData(Uint8* data)
|
|||
{
|
||||
delete[] m_data;
|
||||
m_data = data;
|
||||
m_length = length;
|
||||
}
|
||||
}
|
||||
|
||||
Uint8* ZQuest::data() const
|
||||
Uint8* ZQuestFile::data() const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
void ZQuest::setLength(Uint32 length)
|
||||
{
|
||||
m_length = length;
|
||||
}
|
||||
|
||||
Uint32 ZQuest::length() const
|
||||
Uint32 ZQuestFile::length() const
|
||||
{
|
||||
return m_length;
|
||||
}
|
||||
|
||||
std::string ZQuest::gameString() const
|
||||
std::string ZQuestFile::gameString() const
|
||||
{
|
||||
if (m_game > m_gameStrings.size() - 1)
|
||||
return "Unsupported Game";
|
||||
|
@ -106,7 +103,7 @@ std::string ZQuest::gameString() const
|
|||
return m_gameStrings[m_game];
|
||||
}
|
||||
|
||||
void ZQuest::initGameStrings()
|
||||
void ZQuestFile::initGameStrings()
|
||||
{
|
||||
m_gameStrings.push_back("No Game");
|
||||
m_gameStrings.push_back("Legend Of Zelda");
|
|
@ -14,7 +14,7 @@
|
|||
// along with libZelda. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
#include "ZQuestFileReader.hpp"
|
||||
#include "ZQuest.hpp"
|
||||
#include "ZQuestFile.hpp"
|
||||
#include "InvalidOperationException.hpp"
|
||||
#include "Compression.hpp"
|
||||
|
||||
|
@ -33,26 +33,26 @@ ZQuestFileReader::ZQuestFileReader(const std::string &filename)
|
|||
{
|
||||
}
|
||||
|
||||
ZQuest *ZQuestFileReader::read()
|
||||
ZQuestFile *ZQuestFileReader::read()
|
||||
{
|
||||
Uint32 magic, version, compressedLen, uncompressedLen;
|
||||
ZQuest::Game game;
|
||||
ZQuestFile::Game game;
|
||||
Uint16 BOM;
|
||||
Uint8* data;
|
||||
|
||||
magic = base::readUInt32();
|
||||
|
||||
if (magic != ZQuest::Magic)
|
||||
if (magic != ZQuestFile::Magic)
|
||||
throw error::InvalidOperationException("ZQuestFileReader::read -> Not a valid ZQuest file");
|
||||
|
||||
version = base::readUInt32();
|
||||
|
||||
if (version != ZQuest::Version)
|
||||
if (version != ZQuestFile::Version)
|
||||
throw error::InvalidOperationException("ZQuestFileReader::read -> Unsupported ZQuest version");
|
||||
|
||||
compressedLen = base::readUInt32();
|
||||
uncompressedLen = base::readUInt32();
|
||||
game = (ZQuest::Game)base::readUInt32();
|
||||
game = (ZQuestFile::Game)base::readUInt32();
|
||||
BOM = base::readUInt16();
|
||||
base::seek(0x0A);
|
||||
data = (Uint8*)base::readBytes(compressedLen); // compressedLen is always the total file size
|
||||
|
@ -73,7 +73,7 @@ ZQuest *ZQuestFileReader::read()
|
|||
data = dst;
|
||||
}
|
||||
|
||||
return new ZQuest(game, BOM == 0xFEFF ? BigEndian : LittleEndian, data, uncompressedLen);
|
||||
return new ZQuestFile(game, BOM == 0xFEFF ? BigEndian : LittleEndian, data, uncompressedLen);
|
||||
}
|
||||
|
||||
} // io
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
#include "ZQuestFileWriter.hpp"
|
||||
#include "InvalidOperationException.hpp"
|
||||
#include "ZQuest.hpp"
|
||||
#include "ZQuestFile.hpp"
|
||||
#include "Compression.hpp"
|
||||
|
||||
namespace zelda
|
||||
|
@ -33,22 +33,23 @@ ZQuestFileWriter::ZQuestFileWriter(const std::string& filename)
|
|||
{
|
||||
}
|
||||
|
||||
void ZQuestFileWriter::write(ZQuest* quest, bool compress)
|
||||
void ZQuestFileWriter::write(ZQuestFile* quest, bool compress)
|
||||
{
|
||||
if (!quest)
|
||||
throw error::InvalidOperationException("ZQuestFileWriter::writer -> quest cannot be NULL");
|
||||
throw error::InvalidOperationException("ZQuestFileWriter::write -> quest cannot be NULL");
|
||||
|
||||
base::writeUInt32(ZQuest::Magic);
|
||||
base::writeUInt32(ZQuest::Version);
|
||||
base::writeUInt32(ZQuestFile::Magic);
|
||||
base::writeUInt32(ZQuestFile::Version);
|
||||
Uint8* questData = quest->data();
|
||||
Uint32 compLen = quest->length();
|
||||
Uint32 compLen;
|
||||
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);
|
||||
Uint8* compData = new Uint8[quest->length() + 0x40]; // add 20 bytes because sometimes the file grows with compression
|
||||
compLen = quest->length() + 0x40;
|
||||
compLen = 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())
|
||||
if (compLen >= quest->length() || compLen <= 0)
|
||||
{
|
||||
compLen = quest->length();
|
||||
// Delete the compressed data since we won't be using it
|
||||
|
@ -64,7 +65,10 @@ void ZQuestFileWriter::write(ZQuest* quest, bool compress)
|
|||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
compLen = quest->length();
|
||||
base::writeUInt32(quest->length());
|
||||
}
|
||||
|
||||
base::writeUInt32(quest->length());
|
||||
base::writeUInt32(quest->game());
|
||||
|
@ -73,6 +77,12 @@ void ZQuestFileWriter::write(ZQuest* quest, bool compress)
|
|||
base::writeUBytes(questData, compLen);
|
||||
|
||||
base::save();
|
||||
// Delete compressed data to preven memory leaks
|
||||
if (questData != quest->data())
|
||||
{
|
||||
delete[] questData;
|
||||
questData = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
} // io
|
||||
|
|
130
src/aes.c
130
src/aes.c
|
@ -8,15 +8,11 @@
|
|||
algorithm place on its exploitation.
|
||||
|
||||
*/
|
||||
|
||||
#include "aes.h"
|
||||
#include <stdio.h>
|
||||
//#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef unsigned char u8; /* 8 bits */
|
||||
typedef unsigned long u32; /* 32 bits */
|
||||
typedef unsigned long long u64;
|
||||
|
||||
/* rotates x one bit to the left */
|
||||
|
||||
#define ROTL(x) (((x)>>7)|((x)<<1))
|
||||
|
@ -29,38 +25,38 @@ typedef unsigned long long u64;
|
|||
|
||||
/* Fixed Data */
|
||||
|
||||
static u8 InCo[4]={0xB,0xD,0x9,0xE}; /* Inverse Coefficients */
|
||||
static Uint8 InCo[4]={0xB,0xD,0x9,0xE}; /* Inverse Coefficients */
|
||||
|
||||
static u8 fbsub[256];
|
||||
static u8 rbsub[256];
|
||||
static u8 ptab[256],ltab[256];
|
||||
static u32 ftable[256];
|
||||
static u32 rtable[256];
|
||||
static u32 rco[30];
|
||||
static Uint8 fbsub[256];
|
||||
static Uint8 rbsub[256];
|
||||
static Uint8 ptab[256],ltab[256];
|
||||
static Uint32 ftable[256];
|
||||
static Uint32 rtable[256];
|
||||
static Uint32 rco[30];
|
||||
|
||||
/* Parameter-dependent data */
|
||||
|
||||
int Nk,Nb,Nr;
|
||||
u8 fi[24],ri[24];
|
||||
u32 fkey[120];
|
||||
u32 rkey[120];
|
||||
Uint8 fi[24],ri[24];
|
||||
Uint32 fkey[120];
|
||||
Uint32 rkey[120];
|
||||
|
||||
static u32 pack(u8 *b)
|
||||
static Uint32 pack(const Uint8 *b)
|
||||
{ /* pack bytes into a 32-bit Word */
|
||||
return ((u32)b[3]<<24)|((u32)b[2]<<16)|((u32)b[1]<<8)|(u32)b[0];
|
||||
return ((Uint32)b[3]<<24)|((Uint32)b[2]<<16)|((Uint32)b[1]<<8)|(Uint32)b[0];
|
||||
}
|
||||
|
||||
static void unpack(u32 a,u8 *b)
|
||||
static void unpack(Uint32 a,Uint8 *b)
|
||||
{ /* unpack bytes from a word */
|
||||
b[0]=(u8)a;
|
||||
b[1]=(u8)(a>>8);
|
||||
b[2]=(u8)(a>>16);
|
||||
b[3]=(u8)(a>>24);
|
||||
b[0]=(Uint8)a;
|
||||
b[1]=(Uint8)(a>>8);
|
||||
b[2]=(Uint8)(a>>16);
|
||||
b[3]=(Uint8)(a>>24);
|
||||
}
|
||||
|
||||
static u8 xtime(u8 a)
|
||||
static Uint8 xtime(Uint8 a)
|
||||
{
|
||||
u8 b;
|
||||
Uint8 b;
|
||||
if (a&0x80) b=0x1B;
|
||||
else b=0;
|
||||
a<<=1;
|
||||
|
@ -68,15 +64,15 @@ static u8 xtime(u8 a)
|
|||
return a;
|
||||
}
|
||||
|
||||
static u8 bmul(u8 x,u8 y)
|
||||
static Uint8 bmul(Uint8 x,Uint8 y)
|
||||
{ /* x.y= AntiLog(Log(x) + Log(y)) */
|
||||
if (x && y) return ptab[(ltab[x]+ltab[y])%255];
|
||||
else return 0;
|
||||
}
|
||||
|
||||
static u32 SubByte(u32 a)
|
||||
static Uint32 SubByte(Uint32 a)
|
||||
{
|
||||
u8 b[4];
|
||||
Uint8 b[4];
|
||||
unpack(a,b);
|
||||
b[0]=fbsub[b[0]];
|
||||
b[1]=fbsub[b[1]];
|
||||
|
@ -85,18 +81,18 @@ static u32 SubByte(u32 a)
|
|||
return pack(b);
|
||||
}
|
||||
|
||||
static u8 product(u32 x,u32 y)
|
||||
static Uint8 product(Uint32 x,Uint32 y)
|
||||
{ /* dot product of two 4-byte arrays */
|
||||
u8 xb[4],yb[4];
|
||||
Uint8 xb[4],yb[4];
|
||||
unpack(x,xb);
|
||||
unpack(y,yb);
|
||||
return bmul(xb[0],yb[0])^bmul(xb[1],yb[1])^bmul(xb[2],yb[2])^bmul(xb[3],yb[3]);
|
||||
}
|
||||
|
||||
static u32 InvMixCol(u32 x)
|
||||
static Uint32 InvMixCol(Uint32 x)
|
||||
{ /* matrix Multiplication */
|
||||
u32 y,m;
|
||||
u8 b[4];
|
||||
Uint32 y,m;
|
||||
Uint8 b[4];
|
||||
|
||||
m=pack(InCo);
|
||||
b[3]=product(m,x);
|
||||
|
@ -110,9 +106,9 @@ static u32 InvMixCol(u32 x)
|
|||
return y;
|
||||
}
|
||||
|
||||
u8 ByteSub(u8 x)
|
||||
Uint8 ByteSub(Uint8 x)
|
||||
{
|
||||
u8 y=ptab[255-ltab[x]]; /* multiplicative inverse */
|
||||
Uint8 y=ptab[255-ltab[x]]; /* multiplicative inverse */
|
||||
x=y; x=ROTL(x);
|
||||
y^=x; x=ROTL(x);
|
||||
y^=x; x=ROTL(x);
|
||||
|
@ -124,7 +120,7 @@ u8 ByteSub(u8 x)
|
|||
void gentables(void)
|
||||
{ /* generate tables */
|
||||
int i;
|
||||
u8 y,b[4];
|
||||
Uint8 y,b[4];
|
||||
|
||||
/* use 3 as primitive root to generate power and log tables */
|
||||
|
||||
|
@ -143,7 +139,7 @@ void gentables(void)
|
|||
rbsub[0x63]=0;
|
||||
for (i=1;i<256;i++)
|
||||
{
|
||||
y=ByteSub((u8)i);
|
||||
y=ByteSub((Uint8)i);
|
||||
fbsub[i]=y; rbsub[y]=i;
|
||||
}
|
||||
|
||||
|
@ -168,14 +164,14 @@ void gentables(void)
|
|||
}
|
||||
}
|
||||
|
||||
void gkey(int nb,int nk,u8 *key)
|
||||
void gkey(int nb,int nk, const Uint8 *key)
|
||||
{ /* blocksize=32*nb bits. Key=32*nk bits */
|
||||
/* currently nb,bk = 4, 6 or 8 */
|
||||
/* key comes as 4*Nk bytes */
|
||||
/* Key Scheduler. Create expanded encryption key */
|
||||
int i,j,k,m,N;
|
||||
int C1,C2,C3;
|
||||
u32 CipherKey[8];
|
||||
Uint32 CipherKey[8];
|
||||
|
||||
Nb=nb; Nk=nk;
|
||||
|
||||
|
@ -240,10 +236,10 @@ void gkey(int nb,int nk,u8 *key)
|
|||
* Instead of just one ftable[], I could have 4, the other *
|
||||
* 3 pre-rotated to save the ROTL8, ROTL16 and ROTL24 overhead */
|
||||
|
||||
void encrypt(u8 *buff)
|
||||
void encrypt(Uint8 *buff)
|
||||
{
|
||||
int i,j,k,m;
|
||||
u32 a[8],b[8],*x,*y,*t;
|
||||
Uint32 a[8],b[8],*x,*y,*t;
|
||||
|
||||
for (i=j=0;i<Nb;i++,j+=4)
|
||||
{
|
||||
|
@ -263,10 +259,10 @@ void encrypt(u8 *buff)
|
|||
for (m=j=0;j<Nb;j++,m+=3)
|
||||
{ /* deal with each 32-bit element of the State */
|
||||
/* This is the time-critical bit */
|
||||
y[j]=fkey[k++]^ftable[(u8)x[j]]^
|
||||
ROTL8(ftable[(u8)(x[fi[m]]>>8)])^
|
||||
ROTL16(ftable[(u8)(x[fi[m+1]]>>16)])^
|
||||
ROTL24(ftable[(u8)(x[fi[m+2]]>>24)]);
|
||||
y[j]=fkey[k++]^ftable[(Uint8)x[j]]^
|
||||
ROTL8(ftable[(Uint8)(x[fi[m]]>>8)])^
|
||||
ROTL16(ftable[(Uint8)(x[fi[m+1]]>>16)])^
|
||||
ROTL24(ftable[(Uint8)(x[fi[m+2]]>>24)]);
|
||||
}
|
||||
t=x; x=y; y=t; /* swap pointers */
|
||||
}
|
||||
|
@ -274,23 +270,23 @@ void encrypt(u8 *buff)
|
|||
/* Last Round - unroll if possible */
|
||||
for (m=j=0;j<Nb;j++,m+=3)
|
||||
{
|
||||
y[j]=fkey[k++]^(u32)fbsub[(u8)x[j]]^
|
||||
ROTL8((u32)fbsub[(u8)(x[fi[m]]>>8)])^
|
||||
ROTL16((u32)fbsub[(u8)(x[fi[m+1]]>>16)])^
|
||||
ROTL24((u32)fbsub[(u8)(x[fi[m+2]]>>24)]);
|
||||
y[j]=fkey[k++]^(Uint32)fbsub[(Uint8)x[j]]^
|
||||
ROTL8((Uint32)fbsub[(Uint8)(x[fi[m]]>>8)])^
|
||||
ROTL16((Uint32)fbsub[(Uint8)(x[fi[m+1]]>>16)])^
|
||||
ROTL24((Uint32)fbsub[(Uint8)(x[fi[m+2]]>>24)]);
|
||||
}
|
||||
for (i=j=0;i<Nb;i++,j+=4)
|
||||
{
|
||||
unpack(y[i],(u8 *)&buff[j]);
|
||||
unpack(y[i],(Uint8 *)&buff[j]);
|
||||
x[i]=y[i]=0; /* clean up stack */
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void decrypt(u8 *buff)
|
||||
void decrypt(Uint8 *buff)
|
||||
{
|
||||
int i,j,k,m;
|
||||
u32 a[8],b[8],*x,*y,*t;
|
||||
Uint32 a[8],b[8],*x,*y,*t;
|
||||
|
||||
for (i=j=0;i<Nb;i++,j+=4)
|
||||
{
|
||||
|
@ -309,10 +305,10 @@ void decrypt(u8 *buff)
|
|||
|
||||
for (m=j=0;j<Nb;j++,m+=3)
|
||||
{ /* This is the time-critical bit */
|
||||
y[j]=rkey[k++]^rtable[(u8)x[j]]^
|
||||
ROTL8(rtable[(u8)(x[ri[m]]>>8)])^
|
||||
ROTL16(rtable[(u8)(x[ri[m+1]]>>16)])^
|
||||
ROTL24(rtable[(u8)(x[ri[m+2]]>>24)]);
|
||||
y[j]=rkey[k++]^rtable[(Uint8)x[j]]^
|
||||
ROTL8(rtable[(Uint8)(x[ri[m]]>>8)])^
|
||||
ROTL16(rtable[(Uint8)(x[ri[m+1]]>>16)])^
|
||||
ROTL24(rtable[(Uint8)(x[ri[m+2]]>>24)]);
|
||||
}
|
||||
t=x; x=y; y=t; /* swap pointers */
|
||||
}
|
||||
|
@ -320,28 +316,28 @@ void decrypt(u8 *buff)
|
|||
/* Last Round - unroll if possible */
|
||||
for (m=j=0;j<Nb;j++,m+=3)
|
||||
{
|
||||
y[j]=rkey[k++]^(u32)rbsub[(u8)x[j]]^
|
||||
ROTL8((u32)rbsub[(u8)(x[ri[m]]>>8)])^
|
||||
ROTL16((u32)rbsub[(u8)(x[ri[m+1]]>>16)])^
|
||||
ROTL24((u32)rbsub[(u8)(x[ri[m+2]]>>24)]);
|
||||
y[j]=rkey[k++]^(Uint32)rbsub[(Uint8)x[j]]^
|
||||
ROTL8((Uint32)rbsub[(Uint8)(x[ri[m]]>>8)])^
|
||||
ROTL16((Uint32)rbsub[(Uint8)(x[ri[m+1]]>>16)])^
|
||||
ROTL24((Uint32)rbsub[(Uint8)(x[ri[m+2]]>>24)]);
|
||||
}
|
||||
for (i=j=0;i<Nb;i++,j+=4)
|
||||
{
|
||||
unpack(y[i],(u8 *)&buff[j]);
|
||||
unpack(y[i],(Uint8 *)&buff[j]);
|
||||
x[i]=y[i]=0; /* clean up stack */
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void aes_set_key(u8 *key) {
|
||||
void aes_set_key(const Uint8 *key) {
|
||||
gentables();
|
||||
gkey(4, 4, key);
|
||||
}
|
||||
|
||||
// CBC mode decryption
|
||||
void aes_decrypt(u8 *iv, u8 *inbuf, u8 *outbuf, unsigned long long len) {
|
||||
u8 block[16];
|
||||
u8* ctext_ptr;
|
||||
void aes_decrypt(Uint8 *iv, const Uint8 *inbuf, Uint8 *outbuf, Uint64 len) {
|
||||
Uint8 block[16];
|
||||
Uint8* ctext_ptr;
|
||||
unsigned int blockno = 0, i;
|
||||
|
||||
//fprintf( stderr,"aes_decrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len );
|
||||
|
@ -359,7 +355,7 @@ void aes_decrypt(u8 *iv, u8 *inbuf, u8 *outbuf, unsigned long long len) {
|
|||
memcpy(block, inbuf + blockno * sizeof(block), fraction);
|
||||
decrypt(block);
|
||||
if (blockno == 0) ctext_ptr = iv;
|
||||
else ctext_ptr = inbuf + (blockno-1) * sizeof(block);
|
||||
else ctext_ptr = (Uint8*)(inbuf + (blockno-1) * sizeof(block));
|
||||
|
||||
for(i=0; i < fraction; i++)
|
||||
outbuf[blockno * sizeof(block) + i] =
|
||||
|
@ -370,8 +366,8 @@ void aes_decrypt(u8 *iv, u8 *inbuf, u8 *outbuf, unsigned long long len) {
|
|||
}
|
||||
|
||||
// CBC mode encryption
|
||||
void aes_encrypt(u8 *iv, u8 *inbuf, u8 *outbuf, unsigned long long len) {
|
||||
u8 block[16];
|
||||
void aes_encrypt(Uint8 *iv, const Uint8 *inbuf, Uint8 *outbuf, Uint64 len) {
|
||||
Uint8 block[16];
|
||||
unsigned int blockno = 0, i;
|
||||
|
||||
//printf("aes_decrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len);
|
||||
|
|
16
src/ec.cpp
16
src/ec.cpp
|
@ -321,14 +321,6 @@ static void point_mul(Uint8 *d, Uint8 *a, Uint8 *b) // a is bignum
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// DUPE FUNCTION! NUKE IT!!
|
||||
void sillyRandom(Uint8 * rndArea, Uint8 count)
|
||||
{
|
||||
for(Uint16 i = 0; i < count; i++)
|
||||
rndArea[i]=rand();
|
||||
}
|
||||
|
||||
void generate_ecdsa(Uint8 *R, Uint8 *S, Uint8 *k, Uint8 *hash)
|
||||
{
|
||||
Uint8 e[30];
|
||||
|
@ -341,7 +333,7 @@ void generate_ecdsa(Uint8 *R, Uint8 *S, Uint8 *k, Uint8 *hash)
|
|||
elt_zero(e);
|
||||
memcpy(e + 10, hash, 20);
|
||||
|
||||
sillyRandom(m, sizeof(m));
|
||||
zelda::utility::fillRandom(m, sizeof(m));
|
||||
m[0] = 0;
|
||||
|
||||
// R = (mG).x
|
||||
|
@ -416,11 +408,11 @@ bool check_ec(Uint8 *ng, Uint8 *ap, Uint8 *sig, Uint8 *sig_hash)
|
|||
void make_ec_cert(Uint8 *cert, Uint8 *sig, char *signer, char *name, Uint8 *priv, Uint32 key_id )
|
||||
{
|
||||
memset(cert, 0, 0x180);
|
||||
*(Uint32*)(cert) = swapU32(0x10002);
|
||||
*(Uint32*)(cert) = zelda::utility::swapU32(0x10002);
|
||||
memcpy((char*)cert + 4, sig, 60);
|
||||
strcpy((char*)cert + 0x80, signer);
|
||||
*(Uint32*)(cert + 0xc0) = swapU32(2);
|
||||
*(Uint32*)(cert + 0xc0) = zelda::utility::swapU32(2);
|
||||
strcpy((char*)cert + 0xc4, name);
|
||||
*(Uint32*)(cert + 0x104) = swapU32(key_id);
|
||||
*(Uint32*)(cert + 0x104) = zelda::utility::swapU32(key_id);
|
||||
ec_priv_to_pub(priv, cert + 0x108);
|
||||
}
|
||||
|
|
|
@ -386,8 +386,8 @@ Uint8* getSha1( Uint8 * stuff, Uint32 stuff_size )
|
|||
for( int i = 0; i < 5 ; i++ )
|
||||
{
|
||||
int val = sha.Message_Digest[ i ];
|
||||
if (!isSystemBigEndian())
|
||||
val = swap32(val);
|
||||
if (!zelda::utility::isSystemBigEndian())
|
||||
val = zelda::utility::swap32(val);
|
||||
|
||||
memcpy( (char*)ret + ( i * 4 ), &val, 4 );
|
||||
}
|
||||
|
|
155
src/utility.cpp
155
src/utility.cpp
|
@ -18,57 +18,65 @@
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
bool isEmpty(Int8* buf, size_t size)
|
||||
namespace zelda
|
||||
{
|
||||
namespace utility
|
||||
{
|
||||
|
||||
bool isEmpty(Int8* buf, Uint32 size)
|
||||
{
|
||||
return buf[0] == 0 && !memcmp(buf, buf + 1, size - 1);
|
||||
}
|
||||
|
||||
unsigned short swapU16(unsigned short val )
|
||||
Uint16 swapU16(Uint16 val )
|
||||
{
|
||||
return (val << 8) | (val >> 8 );
|
||||
return (Uint16)swap16(val);
|
||||
}
|
||||
|
||||
short swap16(short val )
|
||||
Int16 swap16(Int16 val )
|
||||
{
|
||||
return (val << 8) | ((val >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
unsigned int swapU32(unsigned int val)
|
||||
Uint32 swapU32(Uint32 val)
|
||||
{
|
||||
val = (val & 0x0000FFFF) << 16 | (val & 0xFFFF0000) >> 16;
|
||||
val = (val & 0x00FF00FF) << 8 | (val & 0xFF00FF00) >> 8;
|
||||
return (Uint32)val;
|
||||
return (Uint32)swap32(val);
|
||||
}
|
||||
|
||||
int swap32( int val )
|
||||
int swap32(Int32 val )
|
||||
{
|
||||
val = (val & 0x0000FFFF) << 16 | (val & 0xFFFF0000) >> 16;
|
||||
val = (val & 0x00FF00FF) << 8 | (val & 0xFF00FF00) >> 8;
|
||||
return val;
|
||||
}
|
||||
|
||||
long long swap64(long long val)
|
||||
Uint64 swapU64(Uint64 val)
|
||||
{
|
||||
return ((long long)((((long long)(val) & 0xFF00000000000000ULL) >> 56) |
|
||||
(((long long)(val) & 0x00FF000000000000ULL) >> 40) |
|
||||
(((long long)(val) & 0x0000FF0000000000ULL) >> 24) |
|
||||
(((long long)(val) & 0x000000FF00000000ULL) >> 8) |
|
||||
(((long long)(val) & 0x00000000FF000000ULL) << 8) |
|
||||
(((long long)(val) & 0x0000000000FF0000ULL) << 24) |
|
||||
(((long long)(val) & 0x000000000000FF00ULL) << 40) |
|
||||
(((long long)(val) & 0x00000000000000FFULL) << 56)));
|
||||
return (Uint64)swap64(val);
|
||||
}
|
||||
|
||||
Int64 swap64(Int64 val)
|
||||
{
|
||||
return ((Int64)((((Int64)(val) & 0xFF00000000000000ULL) >> 56) |
|
||||
(((Int64)(val) & 0x00FF000000000000ULL) >> 40) |
|
||||
(((Int64)(val) & 0x0000FF0000000000ULL) >> 24) |
|
||||
(((Int64)(val) & 0x000000FF00000000ULL) >> 8) |
|
||||
(((Int64)(val) & 0x00000000FF000000ULL) << 8) |
|
||||
(((Int64)(val) & 0x0000000000FF0000ULL) << 24) |
|
||||
(((Int64)(val) & 0x000000000000FF00ULL) << 40) |
|
||||
(((Int64)(val) & 0x00000000000000FFULL) << 56)));
|
||||
}
|
||||
|
||||
bool isSystemBigEndian()
|
||||
{
|
||||
char* test = (char*)"\xFE\xFF";
|
||||
return (*(unsigned short*)test == 0xFEFF);
|
||||
Uint8* test = (Uint8*)"\xFE\xFF";
|
||||
return (*(Uint16*)test == 0xFEFF);
|
||||
}
|
||||
|
||||
void fillRandom(Uint8 * rndArea, Uint8 count)
|
||||
{
|
||||
for(Uint16 i = 0; i < count; i++)
|
||||
rndArea[i]=rand();
|
||||
for(Uint16 i = 0; i < count; i++)
|
||||
rndArea[i]=rand();
|
||||
}
|
||||
|
||||
float swapFloat(float val)
|
||||
|
@ -108,57 +116,60 @@ double swapDouble(double val)
|
|||
//the second 4 bytes in the Yaz0 header).
|
||||
void yaz0Decode(Uint8* src, Uint8* dst, Uint32 uncompressedSize)
|
||||
{
|
||||
Uint32 srcPlace = 0, dstPlace = 0; //current read/write positions
|
||||
Uint32 srcPlace = 0, dstPlace = 0; //current read/write positions
|
||||
|
||||
Int32 validBitCount = 0; //number of valid bits left in "code" byte
|
||||
Uint8 currCodeByte;
|
||||
while(dstPlace < uncompressedSize)
|
||||
{
|
||||
//read new "code" byte if the current one is used up
|
||||
if(validBitCount == 0)
|
||||
Int32 validBitCount = 0; //number of valid bits left in "code" byte
|
||||
Uint8 currCodeByte;
|
||||
while(dstPlace < uncompressedSize)
|
||||
{
|
||||
currCodeByte = src[srcPlace];
|
||||
++srcPlace;
|
||||
validBitCount = 8;
|
||||
//read new "code" byte if the current one is used up
|
||||
if(validBitCount == 0)
|
||||
{
|
||||
currCodeByte = src[srcPlace];
|
||||
++srcPlace;
|
||||
validBitCount = 8;
|
||||
}
|
||||
|
||||
if((currCodeByte & 0x80) != 0)
|
||||
{
|
||||
//straight copy
|
||||
dst[dstPlace] = src[srcPlace];
|
||||
dstPlace++;
|
||||
srcPlace++;
|
||||
}
|
||||
else
|
||||
{
|
||||
//RLE part
|
||||
Uint8 byte1 = src[srcPlace];
|
||||
Uint8 byte2 = src[srcPlace + 1];
|
||||
srcPlace += 2;
|
||||
|
||||
Uint32 dist = ((byte1 & 0xF) << 8) | byte2;
|
||||
Uint32 copySource = dstPlace - (dist + 1);
|
||||
|
||||
Uint32 numBytes = byte1 >> 4;
|
||||
if(numBytes == 0)
|
||||
{
|
||||
numBytes = src[srcPlace] + 0x12;
|
||||
srcPlace++;
|
||||
}
|
||||
else
|
||||
numBytes += 2;
|
||||
|
||||
//copy run
|
||||
for(Uint32 i = 0; i < numBytes; ++i)
|
||||
{
|
||||
dst[dstPlace] = dst[copySource];
|
||||
copySource++;
|
||||
dstPlace++;
|
||||
}
|
||||
}
|
||||
|
||||
//use next bit from "code" byte
|
||||
currCodeByte <<= 1;
|
||||
validBitCount-=1;
|
||||
}
|
||||
|
||||
if((currCodeByte & 0x80) != 0)
|
||||
{
|
||||
//straight copy
|
||||
dst[dstPlace] = src[srcPlace];
|
||||
dstPlace++;
|
||||
srcPlace++;
|
||||
}
|
||||
else
|
||||
{
|
||||
//RLE part
|
||||
Uint8 byte1 = src[srcPlace];
|
||||
Uint8 byte2 = src[srcPlace + 1];
|
||||
srcPlace += 2;
|
||||
|
||||
Uint32 dist = ((byte1 & 0xF) << 8) | byte2;
|
||||
Uint32 copySource = dstPlace - (dist + 1);
|
||||
|
||||
Uint32 numBytes = byte1 >> 4;
|
||||
if(numBytes == 0)
|
||||
{
|
||||
numBytes = src[srcPlace] + 0x12;
|
||||
srcPlace++;
|
||||
}
|
||||
else
|
||||
numBytes += 2;
|
||||
|
||||
//copy run
|
||||
for(Uint32 i = 0; i < numBytes; ++i)
|
||||
{
|
||||
dst[dstPlace] = dst[copySource];
|
||||
copySource++;
|
||||
dstPlace++;
|
||||
}
|
||||
}
|
||||
|
||||
//use next bit from "code" byte
|
||||
currCodeByte <<= 1;
|
||||
validBitCount-=1;
|
||||
}
|
||||
}
|
||||
|
||||
} // utility
|
||||
} // zelda
|
||||
|
|
Loading…
Reference in New Issue