diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index ef2c10f..0000000 --- a/.travis.yml +++ /dev/null @@ -1,14 +0,0 @@ -compiler: - - clang - -before_install: - - sudo add-apt-repository --yes "deb http://llvm.org/apt/precise/ llvm-toolchain-precise-3.6 main" - - wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key | sudo apt-key add -; - - sudo add-apt-repository --yes ppa:ubuntu-sdk-team/ppa - - sudo add-apt-repository --yes ppa:ubuntu-toolchain-r/test - - sudo apt-get update -qq - - sudo apt-get install -qq qt5-default clang-3.6 - -script: - - qmake QMAKE_CXX=clang++-3.6 QMAKE_CC=clang-3.6 Athena.pro - - make diff --git a/AthenaWiiSave.pri b/AthenaWiiSave.pri index 2c60074..933920c 100644 --- a/AthenaWiiSave.pri +++ b/AthenaWiiSave.pri @@ -14,7 +14,7 @@ SOURCES += \ $$PWD/src/ec.cpp \ $$PWD/src/md5.cpp \ $$PWD/src/sha1.cpp \ - $$PWD/src/aes.c + $$PWD/src/aes.cpp HEADERS += \ $$PWD/include/Athena/WiiBanner.hpp \ @@ -23,7 +23,7 @@ HEADERS += \ $$PWD/include/Athena/WiiSave.hpp \ $$PWD/include/Athena/WiiSaveReader.hpp \ $$PWD/include/Athena/WiiSaveWriter.hpp \ - $$PWD/include/aes.h \ + $$PWD/include/aes.hpp \ $$PWD/include/bn.h \ $$PWD/include/ec.h \ $$PWD/include/md5.h \ diff --git a/CMakeLists.txt b/CMakeLists.txt index 5c2b562..3f9eacc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,10 +53,6 @@ add_library(AthenaCore include/LZ77/LZLookupTable.hpp include/LZ77/LZType10.hpp include/LZ77/LZType11.hpp - include/utf8.h - include/utf8/checked.h - include/utf8/core.h - include/utf8/unchecked.h include/Athena/FileInfo.hpp include/Athena/Dir.hpp include/gekko_support.h @@ -90,7 +86,7 @@ add_library(AthenaWiiSave src/ec.cpp src/md5.cpp src/sha1.cpp - src/aes.c + src/aes.cpp include/Athena/WiiBanner.hpp include/Athena/WiiFile.hpp @@ -98,12 +94,13 @@ add_library(AthenaWiiSave include/Athena/WiiSave.hpp include/Athena/WiiSaveReader.hpp include/Athena/WiiSaveWriter.hpp - include/aes.h + include/aes.hpp include/bn.h include/ec.h include/md5.h include/sha1.h ) +set_source_files_properties(src/aes.cpp PROPERTIES COMPILE_FLAGS -maes) add_library(AthenaZelda src/Athena/ALTTPFile.cpp diff --git a/include/Athena/FileReader.hpp b/include/Athena/FileReader.hpp index 211b7db..b9ed7f1 100644 --- a/include/Athena/FileReader.hpp +++ b/include/Athena/FileReader.hpp @@ -17,64 +17,20 @@ public: inline const std::string& filename() const {return m_filename;} - inline void setEndian(Endian endian) - {m_endian = endian;} - inline Endian endian() const - {return m_endian;} - inline bool isBigEndian() const - {return (m_endian == Endian::BigEndian);} - inline bool isLittleEndian() const - {return (m_endian == Endian::LittleEndian);} - void open(); void close(); inline bool isOpen() const {return m_fileHandle != NULL;} bool save(); void seek(atInt64 pos, SeekOrigin origin = SeekOrigin::Current); - inline void seekAlign32() - {FileReader::seek(ROUND_UP_32(FileReader::position()), SeekOrigin::Begin);} - bool atEnd() const; atUint64 position() const; atUint64 length() const; - - - void seekBit(int); - bool readBit(); - atUint8 readUByte(); - inline atInt8 readByte() - {return (atInt8)FileReader::readUByte();} - atUint8* readUBytes(atUint64 len); - inline atInt8* readBytes(atUint64 len) - {return (atInt8*)FileReader::readUBytes(len);} - atUint64 readBytesToBuf(void* buf, atUint64 len) - {return FileReader::readUBytesToBuf(buf, len);} atUint64 readUBytesToBuf(void* buf, atUint64 len); - atUint16 readUint16(); - inline atInt16 readInt16() - {return (atInt16)FileReader::readUint16();} - atUint32 readUint32(); - inline atInt32 readInt32() - {return (atInt32)FileReader::readUint32();} - atUint64 readUint64(); - inline atInt64 readInt64() - {return (atInt64)FileReader::readUint64();} - double readDouble(); - float readFloat(); - inline bool readBool() - {return (FileReader::readByte() != 0);} - atVec3f readVec3f(); - atVec4f readVec4f(); - std::string readString(atInt32 fixedLen = -1); - std::wstring readWString(atInt32 fixedLen = -1); - std::string readUnicode(atInt32 fixedLen = -1); + protected: std::string m_filename; FILE* m_fileHandle; - Endian m_endian; - atUint8 m_currentByte; - atUint8 m_bitShift; - bool m_bitValid; + atUint8 m_currentByte; }; } // io } // Athena diff --git a/include/Athena/FileWriter.hpp b/include/Athena/FileWriter.hpp index a95709c..04faceb 100644 --- a/include/Athena/FileWriter.hpp +++ b/include/Athena/FileWriter.hpp @@ -14,62 +14,20 @@ public: FileWriter(const std::string& filename, bool overwrite = true); virtual ~FileWriter(); - inline void setEndian(Endian endian) - {m_endian = endian;} - inline Endian endian() const - {return m_endian;} - inline bool isBigEndian() const - {return (m_endian == Endian::BigEndian);} - inline bool isLittleEndian() const - {return (m_endian == Endian::LittleEndian);} - void open(bool overwrite = true); void close(); inline bool isOpen() const {return m_fileHandle != NULL;} void seek(atInt64 pos, SeekOrigin origin = SeekOrigin::Current); - inline void seekAlign32() {seek(ROUND_UP_32(position()), SeekOrigin::Begin);} - bool atEnd() const; atUint64 position() const; atUint64 length() const; - - void writeBit(bool val); - void seekBit(int bit); - void writeUByte(atUint8 val); - inline void writeByte(atInt8 val) - {FileWriter::writeUByte(val);} void writeUBytes(const atUint8* data, atUint64 len); - void writeBytes(const atInt8* data, atUint64 len) - {FileWriter::writeUBytes((atUint8*)data, len);} - void writeUint16(atUint16 val); - inline void writeInt16(atInt16 val) - {FileWriter::writeUint16(val);} - void writeUint32(atUint32 val); - inline void writeInt32(atInt32 val) - {FileWriter::writeUint32(val);} - void writeUint64(atUint64 val); - inline void writeInt64(atInt64 val) - {FileWriter::writeUint64(val);} - void writeDouble(double val); - void writeFloat(float val); - inline void writeBool(bool val) - {FileWriter::writeByte(val);} - void writeVec3f(atVec3f vec); - void writeVec4f(atVec4f vec); - void writeString(const std::string& val, atInt32 fixedLen = -1); - void writeWString(const std::wstring& str, atInt32 fixedLen = -1); - void writeUnicode(const std::string& str, atInt32 fixedLen = -1); - void fill(atInt8 byte, atUint64 len); - inline void fill(atUint8 byte, atUint64 len) - {FileWriter::fill((atInt8)byte, len);} + private: std::string m_filename; FILE* m_fileHandle; - Endian m_endian; atUint8 m_currentByte; atUint64 m_bytePosition; - atUint8 m_bitShift; - bool m_bitValid; }; } } // Athena diff --git a/include/Athena/Global.hpp b/include/Athena/Global.hpp index 0fb83d0..3bb9461 100644 --- a/include/Athena/Global.hpp +++ b/include/Athena/Global.hpp @@ -1,9 +1,9 @@ #ifndef GLOBAL_HPP #define GLOBAL_HPP +#include #include "Athena/Types.hpp" #include "Athena/Utility.hpp" -#include #ifdef _MSC_VER #pragma warning(disable : 4996) diff --git a/include/Athena/IStream.hpp b/include/Athena/IStream.hpp index b4c29b6..0057436 100644 --- a/include/Athena/IStream.hpp +++ b/include/Athena/IStream.hpp @@ -19,12 +19,10 @@ public: virtual Endian endian() const = 0; virtual bool isBigEndian() const = 0; virtual bool isLittleEndian()const = 0; - virtual bool isOpen() const = 0; virtual void seek(atInt64, SeekOrigin) = 0; virtual bool atEnd() const = 0; virtual atUint64 position() const = 0; virtual atUint64 length() const = 0; - virtual void seekBit(int) = 0; }; } } diff --git a/include/Athena/IStreamReader.hpp b/include/Athena/IStreamReader.hpp index 6c3cfc6..43d041f 100644 --- a/include/Athena/IStreamReader.hpp +++ b/include/Athena/IStreamReader.hpp @@ -1,6 +1,8 @@ #ifndef ISTREAMREADER_HPP #define ISTREAMREADER_HPP +#include +#include #include "IStream.hpp" namespace Athena @@ -11,38 +13,353 @@ class IStreamReader : public IStream { public: virtual ~IStreamReader() {} - virtual void setEndian(Endian) = 0; - virtual Endian endian() const = 0; - virtual bool isBigEndian() const = 0; - virtual bool isLittleEndian()const = 0; - virtual bool isOpen() const = 0; - virtual void seek(atInt64, SeekOrigin) = 0; - virtual void seekAlign32() = 0; - virtual bool atEnd() const = 0; - virtual atUint64 position() const = 0; - virtual atUint64 length() const = 0; - virtual void seekBit(int) = 0; - virtual bool readBit() = 0; - virtual atUint8 readUByte() = 0; - virtual atInt8 readByte() = 0; - virtual atUint8* readUBytes(atUint64) = 0; - virtual atInt8* readBytes(atUint64) = 0; - virtual atUint64 readUBytesToBuf(void*, atUint64) = 0; - virtual atUint64 readBytesToBuf(void*, atUint64) = 0; - virtual atUint16 readUint16() = 0; - virtual atInt16 readInt16() = 0; - virtual atUint32 readUint32() = 0; - virtual atInt32 readInt32() = 0; - virtual atUint64 readUint64() = 0; - virtual atInt64 readInt64() = 0; - virtual double readDouble() = 0; - virtual float readFloat() = 0; - virtual bool readBool() = 0; - virtual atVec3f readVec3f() = 0; - virtual atVec4f readVec4f() = 0; - virtual std::string readUnicode(atInt32 = -1) = 0; - virtual std::string readString(atInt32 = -1) = 0; - virtual std::wstring readWString(atInt32 = -1) = 0; + + /*! \brief Sets the Endianss of the stream + * + * \param endian The Endianess to set \sa Endian + */ + inline void setEndian(Endian endian) + {m_endian = endian;} + + /*! \brief Returns the current Endianness of the stream + * + * \return Endian The current Stream Endianess + */ + inline Endian endian() const + {return m_endian;} + + /*! \brief Returns whether the stream is BigEndian + * + * \return bool True for BigEndian; False for LittleEndian + */ + inline bool isBigEndian() const + {return (m_endian == Endian::BigEndian);} + + /*! \brief Returns whether the stream is LittleEndian + * + * \return bool True for LittleEndian; False for BigEndian + */ + inline bool isLittleEndian()const + {return (m_endian == Endian::LittleEndian);} + + + /*! \brief Sets the buffers position relative to the specified position.
+ * It seeks relative to the current position by default. + * \param position where in the buffer to seek + * \param origin The Origin to seek \sa SeekOrigin + */ + virtual void seek(atInt64 pos, SeekOrigin origin = SeekOrigin::Current)=0; + + /*! \brief Sets the buffers position relative to the next 32-byte aligned position.
+ */ + inline void seekAlign32() {seek(ROUND_UP_32(position()), SeekOrigin::Begin);} + + /*! \brief Returns whether or not the stream is at the end. + * + * \return bool True if at end; False otherwise. + */ + inline bool atEnd() const + {return position() >= length();} + + /*! \brief Returns the current position in the stream. + * + * \return Int64 The current position in the stream. + */ + virtual atUint64 position() const=0; + + /*! \brief Returns whether or not the stream is at the end. + * + * \return bool True if at end; False otherwise. + */ + virtual atUint64 length() const=0; + + /*! \brief Reads a byte at the current position and advances the current position + * + * \return Int8 The value at the current position + */ + inline atInt8 readByte() {atInt8 val; readUBytesToBuf(&val, 1); return val;} + + /*! \brief Reads a byte at the current position and advances the current position + * + * \return Uint8 The value at the current position + */ + inline atUint8 readUByte() {return 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. + */ + inline atInt8* readBytes(atUint64 length) + {atInt8* buf = new atInt8[length]; readUBytesToBuf(buf, length); return buf;} + + /*! \brief Reads a byte at the current position and advances the current position. + * + * \return Int8* The buffer at the current position from the given length. + */ + inline atUint8* readUBytes(atUint64 length) {return (atUint8*)readBytes(length);} + + inline atUint64 readBytesToBuf(void* buf, atUint64 len) {return readUBytesToBuf(buf, len);} + virtual atUint64 readUBytesToBuf(void* buf, atUint64 len)=0; + + /*! \brief Reads a Int16 and swaps to proper endianness depending on platform + * and Stream settings, and advances the current position + * + * \sa Endian + * + * \return Int16 The value at the current address + * \throw IOException when address is out of range + */ + inline atInt16 readInt16() + { + atInt16 val; + readUBytesToBuf(&val, 2); + return m_endian == BigEndian ? utility::BigInt16(val) : utility::LittleInt16(val); + } + + /*! \brief Reads a Uint16 and swaps to proper endianness depending on platform + * and Stream settings, and advances the current position + * + * \sa Endian + * + * \return Uint16 The value at the current address + * \throw IOException when address is out of range + */ + inline atUint16 readUint16() + {return readInt16();} + + /*! \brief Reads a Int32 and swaps to proper endianness depending on platform + * and Stream settings, and advances the current position + * + * \sa Endian + * + * \return Int32 The value at the current address + * \throw IOException when address is out of range + */ + inline atInt32 readInt32() + { + atInt32 val; + readUBytesToBuf(&val, 4); + return m_endian == BigEndian ? utility::BigInt32(val) : utility::LittleInt32(val); + } + + /*! \brief Reads a Uint32 and swaps to proper endianness depending on platform + * and Stream settings, and advances the current position + * + * \sa Endian + * + * \return Uint32 The value at the current address + * \throw IOException when address is out of range + */ + inline atUint32 readUint32() + {return readInt32();} + + /*! \brief Reads a Int64 and swaps to proper endianness depending on platform + * and Stream settings, and advances the current position + * + * \sa Endian + * + * \return Int64 The value at the current address + * \throw IOException when address is out of range + */ + inline atInt64 readInt64() + { + atInt64 val; + readUBytesToBuf(&val, 8); + return m_endian == BigEndian ? utility::BigInt64(val) : utility::LittleInt64(val); + } + + /*! \brief Reads a Uint64 and swaps to proper endianness depending on platform + * and Stream settings, and advances the current position + * + * \sa Endian + * + * \return Uint64 The value at the current address + * \throw IOException when address is out of range + */ + inline atUint64 readUint64() + {return readInt64();} + + /*! \brief Reads a float and swaps to proper endianness depending on platform + * and Stream settings, and advances the current position + * + * \sa Endian + * + * \return float The value at the current address + * \throw IOException when address is out of range + */ + inline float readFloat() + { + float val; + readUBytesToBuf(&val, 4); + return m_endian == BigEndian ? utility::BigFloat(val) : utility::LittleFloat(val); + } + + /*! \brief Reads a double and swaps to proper endianness depending on platform + * and Stream settings, and advances the current position + * + * \sa Endian + * + * \return double The value at the current address + * \throw IOException when address is out of range + */ + inline double readDouble() + { + double val; + readUBytesToBuf(&val, 8); + return m_endian == BigEndian ? utility::BigDouble(val) : utility::LittleDouble(val); + } + + /*! \brief Reads a bool and advances the current position + * + * \return bool The value at the current address + * \throw IOException when address is out of range + */ + inline bool readBool() + { + atUint8 val; + readUBytesToBuf(&val, 1); + return val != 0; + } + + /*! \brief Reads an atVec3f (12 bytes) and advances the current position + * + * \return atVec3f The value at the current address + * \throw IOException when address is out of range + */ + inline atVec3f readVec3f() + { + atVec3f val; + readUBytesToBuf(&val, 12); + if (m_endian == BigEndian) + { + utility::BigFloat(val.vec[0]); + utility::BigFloat(val.vec[1]); + utility::BigFloat(val.vec[2]); + } + else + { + utility::LittleFloat(val.vec[0]); + utility::LittleFloat(val.vec[1]); + utility::LittleFloat(val.vec[2]); + } + return val; + } + + /*! \brief Reads an atVec4f (16 bytes) and advances the current position + * + * \return atVec4f The value at the current address + * \throw IOException when address is out of range + */ + inline atVec4f readVec4f() + { + atVec4f val; + readUBytesToBuf(&val, 16); + if (m_endian == BigEndian) + { + utility::BigFloat(val.vec[0]); + utility::BigFloat(val.vec[1]); + utility::BigFloat(val.vec[2]); + utility::BigFloat(val.vec[3]); + } + else + { + utility::LittleFloat(val.vec[0]); + utility::LittleFloat(val.vec[1]); + utility::LittleFloat(val.vec[2]); + utility::LittleFloat(val.vec[3]); + } + return val; + } + + /*! \brief Reads a Unicode string and advances the position in the file + * + * \param fixedLen If non-negative, this is a fixed-length string read + * \return std::string The value at the current address + * \throw IOException when address is out of range + */ + inline std::string readUnicode(atInt32 fixedLen = -1) + { + std::wstring tmp; + atUint16 chr = readUint16(); + + atInt32 i; + for (i = 0 ;; ++i) + { + if (fixedLen >= 0 && i >= fixedLen - 1) + break; + + if (!chr) + break; + + tmp.push_back(chr); + chr = readUint16(); + } + + if (fixedLen >= 0 && i < fixedLen) + seek(fixedLen - i); + + std::wstring_convert> conv; + return conv.to_bytes(tmp); + } + + /*! \brief Reads a string and advances the position in the file + * + * \param fixedLen If non-negative, this is a fixed-length string read + * \return std::string The value at the current address + * \throw IOException when address is out of range + */ + inline std::string readString(atInt32 fixedLen = -1) + { + std::string ret; + atUint8 chr = readByte(); + + atInt32 i; + for (i = 1 ; chr != 0 ; ++i) + { + ret += chr; + + if (fixedLen >= 0 && i >= fixedLen) + break; + + chr = readByte(); + } + + if (fixedLen >= 0 && i < fixedLen) + seek(fixedLen - i); + + return ret; + } + + /*! \brief Reads a wstring and advances the position in the file + * + * \param fixedLen If non-negative, this is a fixed-length string read + * \return std::wstring The value at the current address + * \throw IOException when address is out of range + */ + inline std::wstring readWString(atInt32 fixedLen = -1) + { + std::wstring ret; + atUint16 chr = readUint16(); + + atInt32 i; + for (i = 1 ; chr != 0 ; ++i) + { + ret += chr; + + if (fixedLen >= 0 && i >= fixedLen) + break; + + chr = readUint16(); + } + + if (fixedLen >= 0 && i < fixedLen) + seek(fixedLen - i); + + return ret; + } + +protected: + Endian m_endian; }; } } diff --git a/include/Athena/IStreamWriter.hpp b/include/Athena/IStreamWriter.hpp index 6f7dc23..b3edc55 100644 --- a/include/Athena/IStreamWriter.hpp +++ b/include/Athena/IStreamWriter.hpp @@ -1,6 +1,8 @@ #ifndef ISTREAMWRITER_HPP #define ISTREAMWRITER_HPP +#include +#include #include "IStream.hpp" namespace Athena @@ -11,38 +13,365 @@ class IStreamWriter : public IStream { public: virtual ~IStreamWriter() {} - virtual void setEndian(Endian) = 0; - virtual Endian endian() const = 0; - virtual bool isBigEndian() const = 0; - virtual bool isLittleEndian()const = 0; - virtual bool isOpen() const = 0; - virtual void seek(atInt64, SeekOrigin) = 0; - virtual void seekAlign32() = 0; - virtual bool atEnd() const = 0; - virtual atUint64 position() const = 0; - virtual atUint64 length() const = 0; - virtual void seekBit(int) = 0; - virtual void writeBit(bool) = 0; - virtual void writeUByte(atUint8) = 0; - virtual void writeByte(atInt8) = 0; - virtual void writeUBytes(const atUint8*, atUint64) = 0; - virtual void writeBytes(const atInt8*, atUint64) = 0; - virtual void writeUint16(atUint16) = 0; - virtual void writeInt16(atInt16) = 0; - virtual void writeUint32(atUint32) = 0; - virtual void writeInt32(atInt32) = 0; - virtual void writeUint64(atUint64) = 0; - virtual void writeInt64(atInt64) = 0; - virtual void writeDouble(double) = 0; - virtual void writeFloat(float) = 0; - virtual void writeBool(bool) = 0; - virtual void writeVec3f(atVec3f vec) = 0; - virtual void writeVec4f(atVec4f vec) = 0; - virtual void writeString(const std::string&, atInt32 = -1) = 0; - virtual void writeWString(const std::wstring&, atInt32 = -1) = 0; - virtual void writeUnicode(const std::string&, atInt32 = -1) = 0; - virtual void fill(atUint8, atUint64) = 0; - virtual void fill(atInt8, atUint64) = 0; + /*! \brief Sets the Endianss of the stream + * + * \param endian The Endianess to set \sa Endian + */ + inline void setEndian(Endian endian) + {m_endian = endian;} + + /*! \brief Returns the current Endianness of the stream + * + * \return Endian The current Stream Endianess + */ + inline Endian endian() const + {return m_endian;} + + /*! \brief Returns whether the stream is BigEndian + * + * \return bool True for BigEndian; False for LittleEndian + */ + inline bool isBigEndian() const + {return (m_endian == Endian::BigEndian);} + + /*! \brief Returns whether the stream is LittleEndian + * + * \return bool True for LittleEndian; False for BigEndian + */ + inline bool isLittleEndian() const + {return (m_endian == Endian::LittleEndian);} + + /*! \brief Sets the buffers position relative to the specified position.
+ * It seeks relative to the current position by default. + * \param position where in the buffer to seek + * \param origin The Origin to seek \sa SeekOrigin + */ + virtual void seek(atInt64 pos, SeekOrigin origin = SeekOrigin::Current)=0; + + /*! \brief Sets the buffers position relative to the next 32-byte aligned position.
+ */ + inline void seekAlign32() {seek(ROUND_UP_32(position()), SeekOrigin::Begin);} + + /*! \brief Returns whether or not the stream is at the end. + * + * \return bool True if at end; False otherwise. + */ + inline bool atEnd() const {return position() >= length();} + + /*! \brief Returns the current position in the stream. + * + * \return Int64 The current position in the stream. + */ + virtual atUint64 position() const=0; + + /*! \brief Returns whether or not the stream is at the end. + * + * \return bool True if at end; False otherwise. + */ + virtual atUint64 length() const=0; + + /*! \brief Writes a byte at the current position and advances the position by one byte. + * \param byte The value to write + */ + inline void writeUByte(atUint8 val) {writeUBytes(&val, 1);} + + /*! \brief Writes a byte at the current position and advances the position by one byte. + * \param byte The value to write + * \throw IOException + */ + inline void writeByte(atInt8 val) {writeUByte(val);} + + /*! \brief Writes the given buffer with the specified length, buffers can be bigger than the length + * however it's undefined behavior to try and write a buffer which is smaller than the given length. + * + * \param data The buffer to write + * \param length The amount to write + */ + virtual void writeUBytes(const atUint8* data, atUint64 len)=0; + + /*! \brief Writes the given buffer with the specified length, buffers can be bigger than the length + * however it's undefined behavior to try and write a buffer which is smaller than the given length. + * + * \param data The buffer to write + * \param length The amount to write + */ + inline void writeBytes(const atInt8* data, atUint64 len) {writeUBytes((atUint8*)data, len);} + + /*! \brief Writes an Int16 to the buffer and advances the buffer. + * It also swaps the bytes depending on the platform and Stream settings. + * + * \sa Endian + * \param val The value to write to the buffer + */ + inline void writeInt16(atInt16 val) + { + if (m_endian == BigEndian) + utility::BigInt16(val); + else + utility::LittleInt16(val); + writeUBytes((atUint8*)&val, 2); + } + + /*! \brief Writes an Uint16 to the buffer and advances the buffer. + * It also swaps the bytes depending on the platform and Stream settings + * + * \sa Endian + * \param val The value to write to the buffer + */ + inline void writeUint16(atUint16 val) {writeInt16(val);} + + /*! \brief Writes an Int32 to the buffer and advances the buffer. + * It also swaps the bytes depending on the platform and Stream settings. + * + * \sa Endian + * \param val The value to write to the buffer + */ + inline void writeInt32(atInt32 val) + { + if (m_endian == BigEndian) + utility::BigInt32(val); + else + utility::LittleInt32(val); + writeUBytes((atUint8*)&val, 4); + } + + /*! \brief Writes an Uint32 to the buffer and advances the buffer. + * It also swaps the bytes depending on the platform and Stream settings. + * + * \sa Endian + * \param val The value to write to the buffer + */ + inline void writeUint32(atUint32 val) {writeInt32(val);} + + /*! \brief Writes an Int64 to the buffer and advances the buffer. + * It also swaps the bytes depending on the platform and Stream settings. + * + * \sa Endian + * \param val The value to write to the buffer + */ + inline void writeInt64(atInt64 val) + { + if (m_endian == BigEndian) + utility::BigInt64(val); + else + utility::LittleInt64(val); + writeUBytes((atUint8*)&val, 8); + } + + /*! \brief Writes an Uint64 to the buffer and advances the buffer. + * It also swaps the bytes depending on the platform and Stream settings. + * + * \sa Endian + * \param val The value to write to the buffer + */ + inline void writeUint64(atUint64 val) {writeInt64(val);} + + /*! \brief Writes an float to the buffer and advances the buffer. + * It also swaps the bytes depending on the platform and Stream settings. + * + * \sa Endian + * \param val The value to write to the buffer + */ + inline void writeFloat(float val) + { + if (m_endian == BigEndian) + utility::BigFloat(val); + else + utility::LittleFloat(val); + writeUBytes((atUint8*)&val, 4); + } + + /*! \brief Writes an double to the buffer and advances the buffer. + * It also swaps the bytes depending on the platform and Stream settings. + * + * \sa Endian + * \param val The value to write to the buffer + */ + inline void writeDouble(double val) + { + if (m_endian == BigEndian) + utility::BigDouble(val); + else + utility::LittleDouble(val); + writeUBytes((atUint8*)&val, 8); + } + + /*! \brief Writes an bool to the buffer and advances the buffer. + * It also swaps the bytes depending on the platform and Stream settings. + * + * \sa Endian + * \param val The value to write to the buffer + */ + inline void writeBool(bool val) {writeUBytes((atUint8*)&val, 1);} + + /*! \brief Writes an atVec3f (12 bytes) to the buffer and advances the buffer. + * It also swaps the bytes depending on the platform and Stream settings. + * + * \sa Endian + * \param vec The value to write to the buffer + */ + inline void writeVec3f(atVec3f vec) + { + if (m_endian == BigEndian) + { + utility::BigFloat(vec.vec[0]); + utility::BigFloat(vec.vec[1]); + utility::BigFloat(vec.vec[2]); + } + else + { + utility::LittleFloat(vec.vec[0]); + utility::LittleFloat(vec.vec[1]); + utility::LittleFloat(vec.vec[2]); + } + writeUBytes((atUint8*)&vec, 12); + } + + /*! \brief Writes an atVec4f (16 bytes) to the buffer and advances the buffer. + * It also swaps the bytes depending on the platform and Stream settings. + * + * \sa Endian + * \param vec The value to write to the buffer + */ + inline void writeVec4f(atVec4f vec) + { + if (m_endian == BigEndian) + { + utility::BigFloat(vec.vec[0]); + utility::BigFloat(vec.vec[1]); + utility::BigFloat(vec.vec[2]); + utility::BigFloat(vec.vec[3]); + } + else + { + utility::LittleFloat(vec.vec[0]); + utility::LittleFloat(vec.vec[1]); + utility::LittleFloat(vec.vec[2]); + utility::LittleFloat(vec.vec[3]); + } + writeUBytes((atUint8*)&vec, 16); + } + + /*! \brief Writes an unicode string to the buffer and advances the buffer. + * It also swaps the bytes depending on the platform and Stream settings. + * + * \sa Endian + * \param str The string to write to the buffer + * \param fixedLen If not -1, the number of characters to zero-fill string to + */ + inline void writeUnicode(const std::string& str, atInt32 fixedLen = -1) + { + std::string tmpStr = "\xEF\xBB\xBF" + str; + + std::wstring_convert> conv; + std::wstring tmp = conv.from_bytes(tmpStr); + + if (fixedLen < 0) + { + for (atUint16 chr : tmp) + { + if (chr != 0xFEFF) + writeUint16(chr); + } + writeUint16(0); + } + else + { + auto it = tmp.begin(); + for (atInt32 i=0 ; i progressFun = nullptr); - - virtual ~MemoryReader(); - - /*! \brief Sets the Endianss of the stream - * - * \param endian The Endianess to set \sa Endian - */ - inline void setEndian(Endian endian) - {m_endian = endian;} - - /*! \brief Returns the current Endianness of the stream - * - * \return Endian The current Stream Endianess - */ - inline Endian endian() const - {return m_endian;} - - /*! \brief Returns whether the stream is BigEndian - * - * \return bool True for BigEndian; False for LittleEndian - */ - inline bool isBigEndian() const - {return (m_endian == Endian::BigEndian);} - - /*! \brief Returns whether the stream is LittleEndian - * - * \return bool True for LittleEndian; False for BigEndian - */ - inline bool isLittleEndian()const - {return (m_endian == Endian::LittleEndian);} - - /*! \brief Retuns whether or not the Stream is open. - * - * \return True if open; False otherwise. - */ - inline bool isOpen() const - {return m_data != nullptr;} - + MemoryReader(const std::string& filename); /*! \brief Sets the buffers position relative to the specified position.
* It seeks relative to the current position by default. @@ -78,17 +42,6 @@ public: */ void seek(atInt64 pos, SeekOrigin origin = SeekOrigin::Current); - /*! \brief Sets the buffers position relative to the next 32-byte aligned position.
- */ - inline void seekAlign32() {seek(ROUND_UP_32(m_position), SeekOrigin::Begin);} - - /*! \brief Returns whether or not the stream is at the end. - * - * \return bool True if at end; False otherwise. - */ - inline bool atEnd() const - {return m_position >= m_length;} - /*! \brief Returns the current position in the stream. * * \return Int64 The current position in the stream. @@ -113,7 +66,7 @@ public: * \param length The length of the new buffer. * \throw IOException */ - void setData(const atUint8* data, atUint64 length); + void setData(const atUint8* data, atUint64 length); /*! \brief Returns a copy of the current buffer.
@@ -125,199 +78,14 @@ public: */ atUint8* data() const; - /*! \brief Sets the target file - * - * \sa Endian - * \param filepath The path to write to. - */ - inline void setFilepath(const std::string& filepath) - {m_filepath = filepath;} - - /*! \brief Returns the target file - * - */ - inline std::string filepath() const - {return m_filepath;} - - - /*! - * \brief Seeks to the specified bit within the current byte - * \param bit Bit to seek to, range is 0 - 7 - */ - void seekBit(int bit); - - /*! \brief Reads a bit at the current position and advances the current position - * - * \return bool The value at the current position - */ - bool readBit(); - - /*! \brief Reads a byte at the current position and advances the current position - * - * \return Int8 The value at the current position - */ - atInt8 readByte(); - - /*! \brief Reads a byte at the current position and advances the current position - * - * \return Uint8 The value at the current position - */ - atUint8 readUByte(); - - /*! \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. - */ - inline atInt8* readBytes(atUint64 length) {return (atInt8*)readUBytes(length);} - - /*! \brief Reads a byte at the current position and advances the current position. - * - * \return Int8* The buffer at the current position from the given length. - */ - atUint8* readUBytes(atUint64 length); - - atUint64 readBytesToBuf(void* buf, atUint64 len) {return readUBytesToBuf(buf, len);} atUint64 readUBytesToBuf(void* buf, atUint64 len); - /*! \brief Reads a Int16 and swaps to proper endianness depending on platform - * and Stream settings, and advances the current position - * - * \sa Endian - * - * \return Int16 The value at the current address - * \throw IOException when address is out of range - */ - atInt16 readInt16(); - - /*! \brief Reads a Uint16 and swaps to proper endianness depending on platform - * and Stream settings, and advances the current position - * - * \sa Endian - * - * \return Uint16 The value at the current address - * \throw IOException when address is out of range - */ - inline atUint16 readUint16() - {return MemoryReader::readInt16();} - - /*! \brief Reads a Int32 and swaps to proper endianness depending on platform - * and Stream settings, and advances the current position - * - * \sa Endian - * - * \return Int32 The value at the current address - * \throw IOException when address is out of range - */ - atInt32 readInt32(); - - /*! \brief Reads a Uint32 and swaps to proper endianness depending on platform - * and Stream settings, and advances the current position - * - * \sa Endian - * - * \return Uint32 The value at the current address - * \throw IOException when address is out of range - */ - inline atUint32 readUint32() - {return MemoryReader::readInt32();} - - /*! \brief Reads a Int64 and swaps to proper endianness depending on platform - * and Stream settings, and advances the current position - * - * \sa Endian - * - * \return Int64 The value at the current address - * \throw IOException when address is out of range - */ - atInt64 readInt64(); - - /*! \brief Reads a Uint64 and swaps to proper endianness depending on platform - * and Stream settings, and advances the current position - * - * \sa Endian - * - * \return Uint64 The value at the current address - * \throw IOException when address is out of range - */ - inline atUint64 readUint64() - {return MemoryReader::readInt64();} - - /*! \brief Reads a float and swaps to proper endianness depending on platform - * and Stream settings, and advances the current position - * - * \sa Endian - * - * \return float The value at the current address - * \throw IOException when address is out of range - */ - float readFloat(); - - /*! \brief Reads a double and swaps to proper endianness depending on platform - * and Stream settings, and advances the current position - * - * \sa Endian - * - * \return double The value at the current address - * \throw IOException when address is out of range - */ - double readDouble(); - - /*! \brief Reads a bool and advances the current position - * - * \return bool The value at the current address - * \throw IOException when address is out of range - */ - bool readBool(); - - /*! \brief Reads an atVec3f (12 bytes) and advances the current position - * - * \return atVec3f The value at the current address - * \throw IOException when address is out of range - */ - atVec3f readVec3f(); - - /*! \brief Reads an atVec4f (16 bytes) and advances the current position - * - * \return atVec4f The value at the current address - * \throw IOException when address is out of range - */ - atVec4f readVec4f(); - - /*! \brief Reads a Unicode string and advances the position in the file - * - * \param fixedLen If non-negative, this is a fixed-length string read - * \return std::string The value at the current address - * \throw IOException when address is out of range - */ - std::string readUnicode(atInt32 fixedLen = -1); - - /*! \brief Reads a string and advances the position in the file - * - * \param fixedLen If non-negative, this is a fixed-length string read - * \return std::string The value at the current address - * \throw IOException when address is out of range - */ - std::string readString(atInt32 fixedLen = -1); - - /*! \brief Reads a wstring and advances the position in the file - * - * \param fixedLen If non-negative, this is a fixed-length string read - * \return std::wstring The value at the current address - * \throw IOException when address is out of range - */ - std::wstring readWString(atInt32 fixedLen = -1); - - inline void setProgressCallback(std::function cb) - {m_progressCallback = cb;} protected: void loadData(); atUint8* m_data; atUint64 m_length; - std::string m_filepath; //!< Path to the target file + std::string m_filepath; //!< Path to the target file atUint64 m_position; - atUint64 m_bitPosition; - Endian m_endian; - std::function m_progressCallback; }; } // io diff --git a/include/Athena/MemoryWriter.hpp b/include/Athena/MemoryWriter.hpp index 5681d04..b575265 100644 --- a/include/Athena/MemoryWriter.hpp +++ b/include/Athena/MemoryWriter.hpp @@ -10,8 +10,8 @@ namespace Athena namespace io { -/*! \class BinaryWriter - * \brief A Stream class for writing binary data +/*! \class MemoryWriter + * \brief A Stream class for writing data to a memory position * * A Class for writing binary data to a file or memory stream, * all work is done using a memory buffer, and not written directly to the disk @@ -21,6 +21,8 @@ namespace io class MemoryWriter : public IStreamWriter { public: + ~MemoryWriter(); + /*! \brief This constructor takes an existing buffer to write to. * * \param data The existing buffer @@ -34,43 +36,6 @@ public: */ MemoryWriter(const std::string& filename, std::function progressFun = nullptr); - virtual ~MemoryWriter(); - - /*! \brief Sets the Endianss of the stream - * - * \param endian The Endianess to set \sa Endian - */ - inline void setEndian(Endian endian) - {m_endian = endian;} - - /*! \brief Returns the current Endianness of the stream - * - * \return Endian The current Stream Endianess - */ - inline Endian endian() const - {return m_endian;} - - /*! \brief Returns whether the stream is BigEndian - * - * \return bool True for BigEndian; False for LittleEndian - */ - inline bool isBigEndian() const - {return (m_endian == Endian::BigEndian);} - - /*! \brief Returns whether the stream is LittleEndian - * - * \return bool True for LittleEndian; False for BigEndian - */ - inline bool isLittleEndian() const - {return (m_endian == Endian::LittleEndian);} - - /*! \brief Retuns whether or not the Stream is open. - * - * \return True if open; False otherwise. - */ - inline bool isOpen() const - {return m_data != nullptr;} - /*! \brief Sets the buffers position relative to the specified position.
* It seeks relative to the current position by default. @@ -79,18 +44,6 @@ public: */ void seek(atInt64 pos, SeekOrigin origin = SeekOrigin::Current); - /*! \brief Sets the buffers position relative to the next 32-byte aligned position.
- */ - inline void seekAlign32() {seek(ROUND_UP_32(m_position), SeekOrigin::Begin);} - - - /*! \brief Returns whether or not the stream is at the end. - * - * \return bool True if at end; False otherwise. - */ - inline bool atEnd() const - {return m_position >= m_length;} - /*! \brief Returns the current position in the stream. * @@ -106,6 +59,8 @@ public: inline atUint64 length() const {return m_length;} + inline bool isOpen() const {return true;} + /*! \brief Sets the buffer to the given one, deleting the current one.
* BEWARE: As this deletes the current buffer it WILL cause a loss of data * if that was not the intent.
@@ -147,30 +102,6 @@ public: */ void save(const std::string& filename = ""); - /*! - * \brief Seeks to the specified bit within the current byte - * \param bit Bit to seek to, range is 0 - 7 - */ - void seekBit(int bit); - - /*! \brief Writes a bit at the current position and advances the position by one bit. - * \param val the value to write - * \throw IOException - */ - 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 - */ - void writeUByte(atUint8 val); - - /*! \brief Writes a byte at the current position and advances the position by one byte. - * \param byte The value to write - * \throw IOException - */ - inline void writeByte(atInt8 val) - {MemoryWriter::writeUByte(val);} - /*! \brief Writes the given buffer with the specified length, buffers can be bigger than the length * however it's undefined behavior to try and write a buffer which is smaller than the given length. * @@ -179,147 +110,11 @@ public: */ void writeUBytes(const atUint8* data, atUint64 len); - /*! \brief Writes the given buffer with the specified length, buffers can be bigger than the length - * however it's undefined behavior to try and write a buffer which is smaller than the given length. - * - * \param data The buffer to write - * \param length The amount to write - */ - inline void writeBytes(const atInt8* data, atUint64 len) - {MemoryWriter::writeUBytes((atUint8*)data, len);} - - /*! \brief Writes an Int16 to the buffer and advances the buffer. - * It also swaps the bytes depending on the platform and Stream settings. - * - * \sa Endian - * \param val The value to write to the buffer - */ - void writeInt16(atInt16 val); - - /*! \brief Writes an Uint16 to the buffer and advances the buffer. - * It also swaps the bytes depending on the platform and Stream settings - * - * \sa Endian - * \param val The value to write to the buffer - */ - inline void writeUint16(atUint16 val) - {MemoryWriter::writeInt16(val);} - - /*! \brief Writes an Int32 to the buffer and advances the buffer. - * It also swaps the bytes depending on the platform and Stream settings. - * - * \sa Endian - * \param val The value to write to the buffer - */ - void writeInt32(atInt32); - - /*! \brief Writes an Uint32 to the buffer and advances the buffer. - * It also swaps the bytes depending on the platform and Stream settings. - * - * \sa Endian - * \param val The value to write to the buffer - */ - void writeUint32(atUint32 val) - {MemoryWriter::writeInt32(val);} - - /*! \brief Writes an Int64 to the buffer and advances the buffer. - * It also swaps the bytes depending on the platform and Stream settings. - * - * \sa Endian - * \param val The value to write to the buffer - */ - void writeInt64(atInt64); - - /*! \brief Writes an Uint64 to the buffer and advances the buffer. - * It also swaps the bytes depending on the platform and Stream settings. - * - * \sa Endian - * \param val The value to write to the buffer - */ - inline void writeUint64(atUint64 val) - {MemoryWriter::writeInt64(val);} - - /*! \brief Writes an float to the buffer and advances the buffer. - * It also swaps the bytes depending on the platform and Stream settings. - * - * \sa Endian - * \param val The value to write to the buffer - */ - void writeFloat(float); - - /*! \brief Writes an double to the buffer and advances the buffer. - * It also swaps the bytes depending on the platform and Stream settings. - * - * \sa Endian - * \param val The value to write to the buffer - */ - void writeDouble(double); - - /*! \brief Writes an bool to the buffer and advances the buffer. - * It also swaps the bytes depending on the platform and Stream settings. - * - * \sa Endian - * \param val The value to write to the buffer - */ - void writeBool(bool); - - /*! \brief Writes an atVec3f (12 bytes) to the buffer and advances the buffer. - * It also swaps the bytes depending on the platform and Stream settings. - * - * \sa Endian - * \param vec The value to write to the buffer - */ - void writeVec3f(atVec3f vec); - - /*! \brief Writes an atVec4f (16 bytes) to the buffer and advances the buffer. - * It also swaps the bytes depending on the platform and Stream settings. - * - * \sa Endian - * \param vec The value to write to the buffer - */ - void writeVec4f(atVec4f vec); - - /*! \brief Writes an unicode string to the buffer and advances the buffer. - * It also swaps the bytes depending on the platform and Stream settings. - * - * \sa Endian - * \param str The string to write to the buffer - * \param fixedLen If not -1, the number of characters to zero-fill string to - */ - void writeUnicode(const std::string& str, atInt32 fixedLen = -1); - - /*! \brief Writes an string to the buffer and advances the buffer. - * - * \sa Endian - * \param str The string to write to the buffer - * \param fixedLen If not -1, the number of characters to zero-fill string to - */ - void writeString(const std::string& str, atInt32 fixedLen = -1); - - /*! \brief Writes an wstring to the buffer and advances the buffer. - * - * \sa Endian - * \param str The string to write to the buffer - * \param fixedLen If not -1, the number of characters to zero-fill string to - */ - void writeWString(const std::wstring& str, atInt32 fixedLen = -1); - - - void fill(atUint8 val, atUint64 length); - inline void fill(atInt8 val, atUint64 length) - {MemoryWriter::fill((atUint8)val, length);} - - inline void setProgressCallback(std::function cb) - {m_progressCallback = cb;} protected: - void loadData(); atUint8* m_data; atUint64 m_length; - std::string m_filepath; //!< Path to the target file + std::string m_filepath; //!< Path to the target file atUint64 m_position; - atUint64 m_bitPosition; - Endian m_endian; - std::function m_progressCallback; private: void resize(atUint64 newSize); }; diff --git a/include/aes.h b/include/aes.h deleted file mode 100644 index f3cd1ae..0000000 --- a/include/aes.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef __AES_H_ -#define __AES_H_ - -#include "Athena/Types.hpp" - -#ifdef __cplusplus -extern "C" { -#endif - -void aes_encrypt(atUint8* iv, const atUint8* inbuf, atUint8* outbuf, atUint64 len); -void aes_decrypt(atUint8* iv, const atUint8* inbuf, atUint8* outbuf, atUint64 len); -void aes_set_key(const atUint8* key); - -#ifdef __cplusplus -} -#endif - -#endif //__AES_H_ diff --git a/include/aes.hpp b/include/aes.hpp new file mode 100644 index 0000000..803f3f4 --- /dev/null +++ b/include/aes.hpp @@ -0,0 +1,23 @@ +#ifndef __AES_HPP__ +#define __AES_HPP__ + +#include +#include +#include + +namespace Athena +{ + +class IAES +{ +public: + virtual void encrypt(const uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, uint64_t len)=0; + virtual void decrypt(const uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, uint64_t len)=0; + virtual void setKey(const uint8_t* key)=0; +}; + +std::unique_ptr NewAES(); + +} + +#endif //__AES_HPP__ diff --git a/src/Athena/ALTTPFileReader.cpp b/src/Athena/ALTTPFileReader.cpp index a96b1b3..947e086 100644 --- a/src/Athena/ALTTPFileReader.cpp +++ b/src/Athena/ALTTPFileReader.cpp @@ -83,10 +83,11 @@ ALTTPFile* ALTTPFileReader::readFile() quest->setArrowUpgrades(base::readByte()); quest->setHealthFiller(base::readByte()); quest->setMagicFiller(base::readByte()); + atUint8 pendantsByte = base::readUByte(); ALTTPPendants pendants; - pendants.Courage = base::readBit(); - pendants.Wisdom = base::readBit(); - pendants.Power = base::readBit(); + pendants.Courage = pendantsByte & 1; + pendants.Wisdom = (pendantsByte >> 1) & 1; + pendants.Power = (pendantsByte >> 2) & 1; pendants.Unused1 = false; pendants.Unused2 = false; pendants.Unused3 = false; @@ -97,15 +98,16 @@ ALTTPFile* ALTTPFileReader::readFile() quest->setArrowFiller(base::readByte()); quest->setArrows(base::readByte()); base::seek(1); + atUint8 abilitiesByte = base::readUByte(); ALTTPAbilities abilities; - abilities.Nothing = base::readBit(); - abilities.Swim = base::readBit(); - abilities.Dash = base::readBit(); - abilities.Pull = base::readBit(); - abilities.Unknown1 = base::readBit(); - abilities.Talk = base::readBit(); - abilities.Read = base::readBit(); - abilities.Unknown2 = base::readBit(); + abilities.Nothing = abilitiesByte & 1; + abilities.Swim = (abilitiesByte >> 1) & 1; + abilities.Dash = (abilitiesByte >> 2) & 1; + abilities.Pull = (abilitiesByte >> 3) & 1; + abilities.Unknown1 = (abilitiesByte >> 4) & 1; + abilities.Talk = (abilitiesByte >> 5) & 1; + abilities.Read = (abilitiesByte >> 6) & 1; + abilities.Unknown2 = (abilitiesByte >> 7) & 1; quest->setAbilityFlags(abilities); quest->setCrystals((ALTTPCrystals&)*base::readBytes(sizeof(ALTTPCrystals))); quest->setMagicUsage((ALTTPMagicUsage&)*base::readBytes(sizeof(ALTTPMagicUsage))); @@ -186,22 +188,24 @@ ALTTPFile* ALTTPFileReader::readFile() ALTTPRoomFlags* ALTTPFileReader::readRoomFlags() { ALTTPRoomFlags* flags = new ALTTPRoomFlags; - flags->Chest1 = base::readBit(); - flags->Chest2 = base::readBit(); - flags->Chest3 = base::readBit(); - flags->Chest4 = base::readBit(); - flags->Quadrant1 = base::readBit(); - flags->Quadrant2 = base::readBit(); - flags->Quadrant3 = base::readBit(); - flags->Quadrant4 = base::readBit(); - flags->Door1 = base::readBit(); - flags->Door2 = base::readBit(); - flags->Door3 = base::readBit(); - flags->Door4 = base::readBit(); - flags->BossBattleWon = base::readBit(); - flags->Key = base::readBit(); - flags->KeyOrChest = base::readBit(); - flags->ChestOrTile = base::readBit(); + atUint8 flagsByte = base::readUByte(); + flags->Chest1 = flagsByte & 1; + flags->Chest2 = (flagsByte >> 1) & 1; + flags->Chest3 = (flagsByte >> 2) & 1; + flags->Chest4 = (flagsByte >> 3) & 1; + flags->Quadrant1 = (flagsByte >> 4) & 1; + flags->Quadrant2 = (flagsByte >> 5) & 1; + flags->Quadrant3 = (flagsByte >> 6) & 1; + flags->Quadrant4 = (flagsByte >> 7) & 1; + flagsByte = base::readUByte(); + flags->Door1 = flagsByte & 1; + flags->Door2 = (flagsByte >> 1) & 1; + flags->Door3 = (flagsByte >> 2) & 1; + flags->Door4 = (flagsByte >> 3) & 1; + flags->BossBattleWon = (flagsByte >> 4) & 1; + flags->Key = (flagsByte >> 5) & 1; + flags->KeyOrChest = (flagsByte >> 6) & 1; + flags->ChestOrTile = (flagsByte >> 7) & 1; return flags; } @@ -209,36 +213,39 @@ ALTTPRoomFlags* ALTTPFileReader::readRoomFlags() ALTTPOverworldEvent* ALTTPFileReader::readOverworldEvent() { ALTTPOverworldEvent* event = new ALTTPOverworldEvent; - event->Unused1 = base::readBit(); - event->HeartPiece = base::readBit(); - event->Overlay = base::readBit(); - event->Unused2 = base::readBit(); - event->Unused3 = base::readBit(); - event->Unused4 = base::readBit(); - event->Set = base::readBit(); - event->Unused5 = base::readBit(); + atUint8 flagsByte = base::readUByte(); + event->Unused1 = flagsByte & 1; + event->HeartPiece = (flagsByte >> 1) & 1; + event->Overlay = (flagsByte >> 2) & 1; + event->Unused2 = (flagsByte >> 3) & 1; + event->Unused3 = (flagsByte >> 4) & 1; + event->Unused4 = (flagsByte >> 5) & 1; + event->Set = (flagsByte >> 6) & 1; + event->Unused5 = (flagsByte >> 7) & 1; return event; } ALTTPDungeonItemFlags ALTTPFileReader::readDungeonFlags() { ALTTPDungeonItemFlags flags; - flags.Unused1 = base::readBit(); - flags.Unused2 = base::readBit(); - flags.GanonsTower = base::readBit(); - flags.TurtleRock = base::readBit(); - flags.GargoylesDomain = base::readBit(); - flags.TowerOfHera = base::readBit(); - flags.IcePalace = base::readBit(); - flags.SkullWoods = base::readBit(); - flags.MiseryMire = base::readBit(); - flags.DarkPalace = base::readBit(); - flags.SwampPalace = base::readBit(); - flags.HyruleCastle2 = base::readBit(); - flags.DesertPalace = base::readBit(); - flags.EasternPalace = base::readBit(); - flags.HyruleCastle = base::readBit(); - flags.SewerPassage = base::readBit(); + atUint8 flagsByte = base::readUByte(); + flags.Unused1 = flagsByte & 1; + flags.Unused2 = (flagsByte >> 1) & 1; + flags.GanonsTower = (flagsByte >> 2) & 1; + flags.TurtleRock = (flagsByte >> 3) & 1; + flags.GargoylesDomain = (flagsByte >> 4) & 1; + flags.TowerOfHera = (flagsByte >> 5) & 1; + flags.IcePalace = (flagsByte >> 6) & 1; + flags.SkullWoods = (flagsByte >> 7) & 1; + flagsByte = base::readUByte(); + flags.MiseryMire = flagsByte & 1; + flags.DarkPalace = (flagsByte >> 1) & 1; + flags.SwampPalace = (flagsByte >> 2) & 1; + flags.HyruleCastle2 = (flagsByte >> 3) & 1; + flags.DesertPalace = (flagsByte >> 4) & 1; + flags.EasternPalace = (flagsByte >> 5) & 1; + flags.HyruleCastle = (flagsByte >> 6) & 1; + flags.SewerPassage = (flagsByte >> 7) & 1; aDebug() << std::hex << flags.flags1 << " " << flags.flags2 << std::dec << std::endl; return flags; diff --git a/src/Athena/ALTTPFileWriter.cpp b/src/Athena/ALTTPFileWriter.cpp index 97e0a07..0eee70b 100644 --- a/src/Athena/ALTTPFileWriter.cpp +++ b/src/Athena/ALTTPFileWriter.cpp @@ -72,22 +72,26 @@ void ALTTPFileWriter::writeFile(ALTTPFile* file) base::writeByte(quest->healthFiller()); base::writeByte(quest->magicFiller()); ALTTPPendants pendants = quest->pendants(); - base::writeBit(pendants.Courage); - base::writeBit(pendants.Wisdom); - base::writeBit(pendants.Power); + atUint8 pendantsByte = 0; + pendantsByte |= pendants.Courage; + pendantsByte |= pendants.Wisdom << 1; + pendantsByte |= pendants.Power << 2; + base::writeUByte(pendantsByte); base::writeByte(quest->bombFiller()); base::writeByte(quest->arrowFiller()); base::writeByte(quest->arrows()); base::seek(1); ALTTPAbilities abilities = quest->abilityFlags(); - base::writeBit(abilities.Nothing); - base::writeBit(abilities.Swim); - base::writeBit(abilities.Dash); - base::writeBit(abilities.Pull); - base::writeBit(abilities.Unknown1); - base::writeBit(abilities.Talk); - base::writeBit(abilities.Read); - base::writeBit(abilities.Unknown2); + atUint8 abilitiesByte = 0; + abilitiesByte |= abilities.Nothing; + abilitiesByte |= abilities.Swim << 1; + abilitiesByte |= abilities.Dash << 2; + abilitiesByte |= abilities.Pull << 3; + abilitiesByte |= abilities.Unknown1 << 4; + abilitiesByte |= abilities.Talk << 5; + abilitiesByte |= abilities.Read << 6; + abilitiesByte |= abilities.Unknown2 << 7; + base::writeUByte(abilitiesByte); ALTTPCrystals crystals = quest->crystals(); base::writeBytes((atInt8*)&crystals, sizeof(ALTTPCrystals)); ALTTPMagicUsage magicUsage = quest->magicUsage(); @@ -137,53 +141,63 @@ void ALTTPFileWriter::writeFile(ALTTPFile* file) void ALTTPFileWriter::writeRoomFlags(ALTTPRoomFlags* flags) { - base::writeBit(flags->Chest1); - base::writeBit(flags->Chest2); - base::writeBit(flags->Chest3); - base::writeBit(flags->Chest4); - base::writeBit(flags->Quadrant1); - base::writeBit(flags->Quadrant2); - base::writeBit(flags->Quadrant3); - base::writeBit(flags->Quadrant4); - base::writeBit(flags->Door1); - base::writeBit(flags->Door2); - base::writeBit(flags->Door3); - base::writeBit(flags->Door4); - base::writeBit(flags->BossBattleWon); - base::writeBit(flags->Key); - base::writeBit(flags->KeyOrChest); - base::writeBit(flags->ChestOrTile); + atUint8 flagsByte = 0; + flagsByte |= flags->Chest1; + flagsByte |= flags->Chest2 << 1; + flagsByte |= flags->Chest3 << 2; + flagsByte |= flags->Chest4 << 3; + flagsByte |= flags->Quadrant1 << 4; + flagsByte |= flags->Quadrant2 << 5; + flagsByte |= flags->Quadrant3 << 6; + flagsByte |= flags->Quadrant4 << 7; + base::writeUByte(flagsByte); + flagsByte = 0; + flagsByte |= flags->Door1; + flagsByte |= flags->Door2 << 1; + flagsByte |= flags->Door3 << 2; + flagsByte |= flags->Door4 << 3; + flagsByte |= flags->BossBattleWon << 4; + flagsByte |= flags->Key << 5; + flagsByte |= flags->KeyOrChest << 6; + flagsByte |= flags->ChestOrTile << 7; + base::writeUByte(flagsByte); } void ALTTPFileWriter::writeOverworldEvent(ALTTPOverworldEvent* event) { - base::writeBit(event->Unused1); - base::writeBit(event->HeartPiece); - base::writeBit(event->Overlay); - base::writeBit(event->Unused2); - base::writeBit(event->Unused3); - base::writeBit(event->Unused4); - base::writeBit(event->Set); - base::writeBit(event->Unused5); + atUint8 flagsByte = 0; + flagsByte |= event->Unused1; + flagsByte |= event->HeartPiece << 1; + flagsByte |= event->Overlay << 2; + flagsByte |= event->Unused2 << 3; + flagsByte |= event->Unused3 << 4; + flagsByte |= event->Unused4 << 5; + flagsByte |= event->Set << 6; + flagsByte |= event->Unused5 << 7; + base::writeUByte(flagsByte); } void ALTTPFileWriter::writeDungeonItems(ALTTPDungeonItemFlags flags) { - base::writeBit(flags.Unused1); - base::writeBit(flags.Unused2); - base::writeBit(flags.GanonsTower); - base::writeBit(flags.TurtleRock); - base::writeBit(flags.TowerOfHera); - base::writeBit(flags.IcePalace); - base::writeBit(flags.SkullWoods); - base::writeBit(flags.MiseryMire); - base::writeBit(flags.DarkPalace); - base::writeBit(flags.SwampPalace); - base::writeBit(flags.HyruleCastle2); - base::writeBit(flags.DesertPalace); - base::writeBit(flags.EasternPalace); - base::writeBit(flags.HyruleCastle); - base::writeBit(flags.SewerPassage); + atUint8 flagsByte = 0; + flagsByte |= flags.Unused1; + flagsByte |= flags.Unused2 << 1; + flagsByte |= flags.GanonsTower << 2; + flagsByte |= flags.TurtleRock << 3; + flagsByte |= flags.TowerOfHera << 4; + flagsByte |= flags.IcePalace << 5; + flagsByte |= flags.SkullWoods << 6; + flagsByte |= flags.MiseryMire << 7; + base::writeUByte(flagsByte); + flagsByte = 0; + flagsByte |= flags.DarkPalace; + flagsByte |= flags.SwampPalace << 1; + flagsByte |= flags.HyruleCastle2 << 2; + flagsByte |= flags.DesertPalace << 3; + flagsByte |= flags.EasternPalace << 4; + flagsByte |= flags.HyruleCastle << 5; + flagsByte |= flags.SewerPassage << 6; + base::writeUByte(flagsByte); } atUint16 ALTTPFileWriter::calculateChecksum(atUint32 game) diff --git a/src/Athena/FileReader.cpp b/src/Athena/FileReader.cpp index 044b5e5..39f621d 100644 --- a/src/Athena/FileReader.cpp +++ b/src/Athena/FileReader.cpp @@ -3,7 +3,6 @@ #include "Athena/InvalidDataException.hpp" #include "Athena/InvalidOperationException.hpp" #include "Athena/IOException.hpp" -#include "utf8.h" #if _WIN32 #include "win32_largefilewrapper.h" @@ -17,9 +16,7 @@ namespace io { FileReader::FileReader(const std::string& filename) : m_filename(filename), - m_fileHandle(NULL), - m_endian(Endian::LittleEndian), - m_bitValid(false) + m_fileHandle(NULL) { open(); } @@ -57,14 +54,6 @@ void FileReader::seek(atInt64 pos, SeekOrigin origin) THROW_INVALID_OPERATION_EXCEPTION("Unable to seek in file"); } -bool FileReader::atEnd() const -{ - if (!isOpen()) - THROW_INVALID_OPERATION_EXCEPTION_RETURN(true, "File not open"); - - return feof(m_fileHandle) != 0; -} - atUint64 FileReader::position() const { if (!isOpen()) @@ -81,259 +70,13 @@ atUint64 FileReader::length() const return utility::fileSize(m_filename); } -void FileReader::seekBit(int bit) -{ - if (!isOpen()) - THROW_INVALID_OPERATION_EXCEPTION("File not open"); - - if (bit < 0 || bit > 7) - THROW_INVALID_OPERATION_EXCEPTION("bit out of range"); - - m_bitShift = bit; -} - -bool FileReader::readBit() -{ - if (!isOpen()) - THROW_INVALID_OPERATION_EXCEPTION_RETURN(false, "File is not open for reading"); - - if (!m_bitValid) - { - size_t size = fread(&m_currentByte, 1, 1, m_fileHandle); - - if (size != sizeof(atUint8)) - THROW_IO_EXCEPTION_RETURN(false, "Error reading from file."); - - m_bitShift = 0; - m_bitValid = true; - } - - atUint8 flag = (1 << m_bitShift); - m_bitShift++; - - if (m_bitShift > 7) - m_bitValid = false; - - return ((m_currentByte & flag) == flag); -} - -atUint8 FileReader::readUByte() -{ - if (!isOpen()) - THROW_INVALID_OPERATION_EXCEPTION_RETURN(0, "File not open for reading"); - - m_bitValid = false; - atUint8 val = 0; - fread(&val, 1, 1, m_fileHandle); - return val; -} - -atUint8* FileReader::readUBytes(atUint64 len) -{ - if (!isOpen()) - THROW_INVALID_OPERATION_EXCEPTION_RETURN(nullptr, "File not open for reading"); - - m_bitValid = false; - atUint8* val = new atUint8[len]; - fread(val, 1, len, m_fileHandle); - return val; -} - atUint64 FileReader::readUBytesToBuf(void* buf, atUint64 len) { if (!isOpen()) THROW_INVALID_OPERATION_EXCEPTION_RETURN(0, "File not open for reading"); - m_bitValid = false; return fread(buf, 1, len, m_fileHandle); } -atUint16 FileReader::readUint16() -{ - if (!isOpen()) - THROW_INVALID_OPERATION_EXCEPTION_RETURN(0, "File not open for reading"); - - m_bitValid = false; - atUint16 val; - fread(&val, 1, sizeof(atUint16), m_fileHandle); - - if ((!utility::isSystemBigEndian() && isBigEndian()) || (utility::isSystemBigEndian() && isLittleEndian())) - val = utility::swapU16(val); - - return val; -} - -atUint32 FileReader::readUint32() -{ - if (!isOpen()) - THROW_INVALID_OPERATION_EXCEPTION_RETURN(0, "File not open for reading"); - - m_bitValid = false; - atUint32 val; - fread(&val, 1, sizeof(atUint32), m_fileHandle); - - if ((!utility::isSystemBigEndian() && isBigEndian()) || (utility::isSystemBigEndian() && isLittleEndian())) - val = utility::swapU32(val); - - return val; -} - -atUint64 FileReader::readUint64() -{ - if (!isOpen()) - THROW_INVALID_OPERATION_EXCEPTION_RETURN(0, "File not open for reading"); - - m_bitValid = false; - atUint64 val; - fread(&val, 1, sizeof(atUint64), m_fileHandle); - - if ((!utility::isSystemBigEndian() && isBigEndian()) || (utility::isSystemBigEndian() && isLittleEndian())) - val = utility::swapU64(val); - - return val; -} - -double FileReader::readDouble() -{ - if (!isOpen()) - THROW_INVALID_OPERATION_EXCEPTION_RETURN(0, "File not open for reading"); - - m_bitValid = false; - double val; - fread(&val, 1, sizeof(double), m_fileHandle); - - if ((!utility::isSystemBigEndian() && isBigEndian()) || (utility::isSystemBigEndian() && isLittleEndian())) - val = utility::swapDouble(val); - - return val; -} - -float FileReader::readFloat() -{ - if (!isOpen()) - THROW_INVALID_OPERATION_EXCEPTION_RETURN(0, "File not open for reading"); - - m_bitValid = false; - float val; - fread(&val, 1, sizeof(float), m_fileHandle); - - if ((!utility::isSystemBigEndian() && isBigEndian()) || (utility::isSystemBigEndian() && isLittleEndian())) - val = utility::swapFloat(val); - - return val; -} - -atVec3f FileReader::readVec3f() -{ - atVec3f val = {}; - if (!isOpen()) - THROW_INVALID_OPERATION_EXCEPTION_RETURN(val, "File not open for reading"); - - m_bitValid = false; - fread(&val, 1, 12, m_fileHandle); - - if ((!utility::isSystemBigEndian() && isBigEndian()) || (utility::isSystemBigEndian() && isLittleEndian())) - { - val.vec[0] = utility::swapFloat(val.vec[0]); - val.vec[1] = utility::swapFloat(val.vec[1]); - val.vec[2] = utility::swapFloat(val.vec[2]); - } - - return val; -} - -atVec4f FileReader::readVec4f() -{ - atVec4f val = {}; - if (!isOpen()) - THROW_INVALID_OPERATION_EXCEPTION_RETURN(val, "File not open for reading"); - - m_bitValid = false; - fread(&val, 1, 16, m_fileHandle); - - if ((!utility::isSystemBigEndian() && isBigEndian()) || (utility::isSystemBigEndian() && isLittleEndian())) - { - val.vec[0] = utility::swapFloat(val.vec[0]); - val.vec[1] = utility::swapFloat(val.vec[1]); - val.vec[2] = utility::swapFloat(val.vec[2]); - val.vec[3] = utility::swapFloat(val.vec[3]); - } - - return val; -} - -std::string FileReader::readString(atInt32 fixedLen) -{ - std::string ret; - - atUint8 chr = readByte(); - atInt32 i; - for (i = 1 ; chr != 0 ; ++i) - { - ret += chr; - - if (fixedLen >= 0 && i >= fixedLen) - break; - - chr = readByte(); - } - - if (fixedLen >= 0 && i < fixedLen) - seek(fixedLen - i); - - return ret; -} - -std::wstring FileReader::readWString(atInt32 fixedLen) -{ - std::wstring ret; - atUint16 chr = readUint16(); - - atInt32 i; - for (i = 1 ; chr != 0 ; ++i) - { - ret += chr; - - if (fixedLen >= 0 && i >= fixedLen) - break; - - chr = readUint16(); - } - - if (fixedLen >= 0 && i < fixedLen) - seek(fixedLen - i); - - return ret; -} - -std::string FileReader::readUnicode(atInt32 fixedLen) -{ - if (!isOpen()) - THROW_INVALID_OPERATION_EXCEPTION_RETURN(std::string(), "File not open for reading"); - - std::string ret; - std::vector tmp; - atInt32 i; - for (i = 0 ;; ++i) - { - if (fixedLen >= 0 && i >= fixedLen - 1) - break; - - atUint16 chr = readUint16(); - - if (chr) - tmp.push_back(chr); - else - break; - }; - - if (fixedLen >= 0 && i < fixedLen) - seek(fixedLen - i); - - utf8::utf16to8(tmp.begin(), tmp.end(), back_inserter(ret)); - - return ret; -} - } // io } // Athena diff --git a/src/Athena/FileWriter.cpp b/src/Athena/FileWriter.cpp index 1fa7b8e..50ace89 100644 --- a/src/Athena/FileWriter.cpp +++ b/src/Athena/FileWriter.cpp @@ -10,8 +10,6 @@ #include "osx_largefilewrapper.h" #endif -#include "utf8.h" - namespace Athena { namespace io @@ -19,10 +17,7 @@ namespace io FileWriter::FileWriter(const std::string& filename, bool overwrite) : m_filename(filename), m_fileHandle(NULL), - m_endian(Endian::LittleEndian), - m_bytePosition(0), - m_bitShift(0), - m_bitValid(false) + m_bytePosition(0) { open(overwrite); } @@ -63,11 +58,6 @@ void FileWriter::seek(atInt64 pos, SeekOrigin origin) THROW_IO_EXCEPTION("Unable to seek in file"); } -bool FileWriter::atEnd() const -{ - return feof(m_fileHandle) != 0; -} - atUint64 FileWriter::position() const { return ftello64(m_fileHandle); @@ -78,292 +68,14 @@ atUint64 FileWriter::length() const return utility::fileSize(m_filename); } -void FileWriter::writeBit(bool val) -{ - if (!isOpen()) - THROW_INVALID_OPERATION_EXCEPTION("File not open for writing"); - - if (!m_bitValid) - { - m_bitValid = true; - m_bitShift = 0; - m_bytePosition = ftello64(m_fileHandle); - } - - - if (val) - m_currentByte |= (1 << m_bitShift++); - else - m_currentByte &= ~(1 << m_bitShift++); - - if (m_bitShift > 7) - m_bitValid = false; - - fseeko64(m_fileHandle, m_bytePosition, (int)SeekOrigin::Begin); - - if (fwrite(&m_currentByte, 1, 1, m_fileHandle) != sizeof(atInt8)) - THROW_IO_EXCEPTION("Unable to data to file"); -} - -void FileWriter::seekBit(int bit) -{ - if (bit < 0 || bit > 7) - THROW_INVALID_OPERATION_EXCEPTION("bit must be >= 0 and <= 7"); - - m_bitShift = bit; - m_bitValid = true; -} - -void FileWriter::writeUByte(atUint8 val) -{ - if (!isOpen()) - THROW_INVALID_OPERATION_EXCEPTION("File not open for writing"); - - m_bitValid = false; - - if (fwrite(&val, 1, sizeof(atUint8), m_fileHandle) != sizeof(atUint8)) - THROW_IO_EXCEPTION("Unable to write to stream"); -} - void FileWriter::writeUBytes(const atUint8* data, atUint64 len) { if (!isOpen()) THROW_INVALID_OPERATION_EXCEPTION("File not open for writing"); - m_bitValid = false; - if (fwrite(data, 1, len, m_fileHandle) != len) THROW_IO_EXCEPTION("Unable to write to stream"); } -void FileWriter::writeUint16(atUint16 val) -{ - if (!isOpen()) - THROW_INVALID_OPERATION_EXCEPTION("File not open for writing"); - - m_bitValid = false; - - if ((!utility::isSystemBigEndian() && isBigEndian()) || (utility::isSystemBigEndian() && isLittleEndian())) - val = utility::swapU16(val); - - if (fwrite(&val, 1, sizeof(atUint16), m_fileHandle) != sizeof(atUint16)) - THROW_IO_EXCEPTION("Unable to write to stream"); -} - -void FileWriter::writeUint32(atUint32 val) -{ - if (!isOpen()) - THROW_INVALID_OPERATION_EXCEPTION("File not open for writing"); - - m_bitValid = false; - - if ((!utility::isSystemBigEndian() && isBigEndian()) || (utility::isSystemBigEndian() && isLittleEndian())) - val = utility::swapU32(val); - - if (fwrite(&val, 1, sizeof(atUint32), m_fileHandle) != sizeof(atUint32)) - THROW_IO_EXCEPTION("Unable to write to stream"); -} - -void FileWriter::writeUint64(atUint64 val) -{ - if (!isOpen()) - THROW_INVALID_OPERATION_EXCEPTION("File not open for writing"); - - m_bitValid = false; - - if ((!utility::isSystemBigEndian() && isBigEndian()) || (utility::isSystemBigEndian() && isLittleEndian())) - val = utility::swapU64(val); - - if (fwrite(&val, 1, sizeof(atUint64), m_fileHandle) != sizeof(atUint64)) - THROW_IO_EXCEPTION("Unable to write to stream"); -} - -void FileWriter::writeDouble(double val) -{ - if (!isOpen()) - THROW_INVALID_OPERATION_EXCEPTION("File not open for writing"); - - m_bitValid = false; - - if ((!utility::isSystemBigEndian() && isBigEndian()) || (utility::isSystemBigEndian() && isLittleEndian())) - val = utility::swapDouble(val); - - if (fwrite(&val, 1, sizeof(double), m_fileHandle) != sizeof(double)) - THROW_IO_EXCEPTION("Unable to write to stream"); -} - -void FileWriter::writeFloat(float val) -{ - if (!isOpen()) - THROW_INVALID_OPERATION_EXCEPTION("File not open for writing"); - - m_bitValid = false; - - if ((!utility::isSystemBigEndian() && isBigEndian()) || (utility::isSystemBigEndian() && isLittleEndian())) - val = utility::swapFloat(val); - - if (fwrite(&val, 1, sizeof(float), m_fileHandle) != sizeof(float)) - THROW_IO_EXCEPTION("Unable to write to stream"); -} - -void FileWriter::writeVec3f(atVec3f vec) -{ - if (!isOpen()) - THROW_INVALID_OPERATION_EXCEPTION("File not open for writing"); - - m_bitValid = false; - - if ((!utility::isSystemBigEndian() && isBigEndian()) || (utility::isSystemBigEndian() && isLittleEndian())) - { - vec.vec[0] = utility::swapFloat(vec.vec[0]); - vec.vec[1] = utility::swapFloat(vec.vec[1]); - vec.vec[2] = utility::swapFloat(vec.vec[2]); - } - - if (fwrite(&vec, 1, 12, m_fileHandle) != 12) - THROW_IO_EXCEPTION("Unable to write to stream"); -} - -void FileWriter::writeVec4f(atVec4f vec) -{ - if (!isOpen()) - THROW_INVALID_OPERATION_EXCEPTION("File not open for writing"); - - m_bitValid = false; - - if ((!utility::isSystemBigEndian() && isBigEndian()) || (utility::isSystemBigEndian() && isLittleEndian())) - { - vec.vec[0] = utility::swapFloat(vec.vec[0]); - vec.vec[1] = utility::swapFloat(vec.vec[1]); - vec.vec[2] = utility::swapFloat(vec.vec[2]); - vec.vec[3] = utility::swapFloat(vec.vec[3]); - } - - if (fwrite(&vec, 1, 16, m_fileHandle) != 16) - THROW_IO_EXCEPTION("Unable to write to stream"); -} - -void FileWriter::writeString(const std::string& val, atInt32 fixedLen) -{ - if (!isOpen()) - THROW_INVALID_OPERATION_EXCEPTION("File not open for writing"); - - m_bitValid = false; - char term = '\0'; - - if (fixedLen < 0) - { - if (fwrite(val.c_str(), 1, val.length(), m_fileHandle) != val.length()) - THROW_IO_EXCEPTION("Unable to write to stream"); - - if (fwrite(&term, 1, 1, m_fileHandle) != 1) - THROW_IO_EXCEPTION("Unable to write to stream"); - } - else - { - if ((atInt32)val.length() >= fixedLen) - { - if ((atInt32)fwrite(val.c_str(), 1, fixedLen, m_fileHandle) != fixedLen) - THROW_IO_EXCEPTION("Unable to write to stream"); - } - else - { - if (fwrite(val.c_str(), 1, val.length(), m_fileHandle) != val.length()) - THROW_IO_EXCEPTION("Unable to write to stream"); - for (atInt32 i=val.length() ; i= fixedLen) - { - if ((atInt32)fwrite(val.c_str(), 2, fixedLen, m_fileHandle) != fixedLen) - THROW_IO_EXCEPTION("Unable to write to stream"); - } - else - { - if (fwrite(val.c_str(), 2, val.length(), m_fileHandle) != val.length()) - THROW_IO_EXCEPTION("Unable to write to stream"); - for (atInt32 i=val.length() ; i tmp; - - utf8::utf8to16(tmpStr.begin(), tmpStr.end(), back_inserter(tmp)); - - if (fixedLen < 0) - { - for (atUint16 chr : tmp) - { - if (chr != 0xFEFF) - writeUint16(chr); - } - writeUint16(0); - } - else - { - auto it = tmp.begin(); - for (atInt32 i=0 ; i #include @@ -21,10 +20,7 @@ namespace io { MemoryReader::MemoryReader(const atUint8* data, atUint64 length) : m_length(length), - m_position(0), - m_bitPosition(0), - m_endian(Endian::LittleEndian), - m_progressCallback(nullptr) + m_position(0) { if (!data) THROW_INVALID_DATA_EXCEPTION("data cannot be NULL"); @@ -36,14 +32,11 @@ MemoryReader::MemoryReader(const atUint8* data, atUint64 length) memcpy(m_data, data, m_length); } -MemoryReader::MemoryReader(const std::string& filename, std::function progFun) +MemoryReader::MemoryReader(const std::string& filename) : m_data(NULL), m_length(0), m_filepath(filename), - m_position(0), - m_bitPosition(0), - m_endian(Endian::LittleEndian), - m_progressCallback(progFun) + m_position(0) { loadData(); } @@ -89,7 +82,6 @@ void MemoryReader::setData(const atUint8* data, atUint64 length) m_data = (atUint8*)data; m_length = length; m_position = 0; - m_bitPosition = 0; } atUint8* MemoryReader::data() const @@ -100,108 +92,11 @@ atUint8* MemoryReader::data() const return ret; } -void MemoryReader::seekBit(int bit) -{ - if (!m_data) - loadData(); - - if (bit < 0 || bit > 7) - THROW_INVALID_OPERATION_EXCEPTION("bit out of range %i %s", bit, (bit < 0 ? "< 0" : "> 7")); - - m_bitPosition = bit; -} - -bool MemoryReader::readBit() -{ - if (!m_data) - loadData(); - - if (m_position > m_length) - THROW_IO_EXCEPTION_RETURN(false, "Position %0.8X outside stream bounds ", m_position); - - bool ret = (*(atUint8*)(m_data + m_position) & (1 << m_bitPosition)) != 0; - - m_bitPosition++; - - if (m_bitPosition > 7) - { - m_bitPosition = 0; - m_position += sizeof(atUint8); - } - - return ret; -} - -atInt8 MemoryReader::readByte() -{ - if (!m_data) - loadData(); - - if (m_bitPosition > 0) - { - m_bitPosition = 0; - m_position += sizeof(atUint8); - } - - if (m_position + 1 > m_length) - THROW_IO_EXCEPTION_RETURN(0, "Position %0.8X outside stream bounds ", m_position); - - return *(atInt8*)(m_data + m_position++); -} - -atUint8 MemoryReader::readUByte() -{ - if (!m_data) - loadData(); - - if (!m_data) - loadData(); - - if (m_bitPosition > 0) - { - m_bitPosition = 0; - m_position += sizeof(atUint8); - } - - if (m_position + 1 > m_length) - THROW_IO_EXCEPTION_RETURN(0, "Position %0.8X outside stream bounds ", m_position); - - return *(atUint8*)(m_data + m_position++); -} - -atUint8* MemoryReader::readUBytes(atUint64 length) -{ - if (!m_data) - loadData(); - - if (m_bitPosition > 0) - { - m_bitPosition = 0; - m_position += sizeof(atUint8); - } - - if (m_position + length > m_length) - THROW_IO_EXCEPTION_RETURN(nullptr, "Position %0.8X outside stream bounds ", m_position); - - atUint8* ret; - ret = new atUint8[length]; - - memcpy(ret, (const atUint8*)(m_data + m_position), length); - m_position += length; - return ret; -} - atUint64 MemoryReader::readUBytesToBuf(void* buf, atUint64 length) { if (!m_data) loadData(); - if (m_bitPosition > 0) - { - m_bitPosition = 0; - m_position += sizeof(atUint8); - } - if (m_position + length > m_length) THROW_IO_EXCEPTION_RETURN(0, "Position %0.8X outside stream bounds ", m_position); @@ -210,298 +105,6 @@ atUint64 MemoryReader::readUBytesToBuf(void* buf, atUint64 length) return length; } -atInt16 MemoryReader::readInt16() -{ - if (!m_data) - loadData(); - - if (m_bitPosition > 0) - { - m_bitPosition = 0; - m_position += sizeof(atUint8); - } - - if (m_position + sizeof(atInt16) > m_length) - THROW_IO_EXCEPTION_RETURN(0, "Position %0.8X outside stream bounds ", m_position); - - atInt16 ret = *(atInt16*)(m_data + m_position); - m_position += sizeof(atInt16); - - if (isBigEndian()) - utility::BigInt16(ret); - else - utility::LittleInt16(ret); - - return ret; -} - -atInt32 MemoryReader::readInt32() -{ - if (!m_data) - loadData(); - - if (m_bitPosition > 0) - { - m_bitPosition = 0; - m_position += sizeof(atUint8); - } - - if (m_position + sizeof(atInt32) > m_length) - THROW_IO_EXCEPTION_RETURN(0, "Position %0.8X outside stream bounds ", m_position); - - atInt32 ret = *(atInt32*)(m_data + m_position); - m_position += 4; - - if (isBigEndian()) - utility::BigInt32(ret); - else - utility::LittleInt32(ret); - - return ret; -} - - -atInt64 MemoryReader::readInt64() -{ - if (!m_data) - loadData(); - - if (m_bitPosition > 0) - { - m_bitPosition = 0; - m_position += sizeof(atUint8); - } - - if (m_position + sizeof(atInt64) > m_length) - THROW_IO_EXCEPTION_RETURN(0, "Position %0.8X outside stream bounds ", m_position); - - atInt64 ret = *(atInt64*)(m_data + m_position); - m_position += 8; - - if (isBigEndian()) - utility::BigInt64(ret); - else - utility::LittleInt64(ret); - - return ret; -} - -float MemoryReader::readFloat() -{ - if (!m_data) - loadData(); - - if (m_bitPosition > 0) - { - m_bitPosition = 0; - m_position += sizeof(atUint8); - } - - if (m_position + sizeof(float) > m_length) - THROW_IO_EXCEPTION_RETURN(0, "Position %0.8X outside stream bounds ", m_position); - - float ret = *(float*)(m_data + m_position); - m_position += 4; - - if (isBigEndian()) - utility::BigFloat(ret); - else - utility::LittleFloat(ret); - - return ret; -} - -double MemoryReader::readDouble() -{ - if (!m_data) - loadData(); - - if (m_bitPosition > 0) - { - m_bitPosition = 0; - m_position += sizeof(atUint8); - } - - if (m_position + sizeof(double) > m_length) - THROW_IO_EXCEPTION_RETURN(0, "Position %0.8X outside stream bounds ", m_position); - - double ret = *(double*)(m_data + m_position); - m_position += 8; - - if (isBigEndian()) - utility::BigDouble(ret); - else - utility::LittleDouble(ret); - - return ret; -} - -bool MemoryReader::readBool() -{ - if (!m_data) - loadData(); - - if (m_bitPosition > 0) - { - m_bitPosition = 0; - m_position += sizeof(atUint8); - } - - if (m_position + sizeof(bool) > m_length) - THROW_IO_EXCEPTION_RETURN(false, "Position %0.8X outside stream bounds ", m_position); - - bool ret = *(bool*)(m_data + m_position); - m_position += 1; - return ret; -} - -atVec3f MemoryReader::readVec3f() -{ - if (!m_data) - loadData(); - - if (m_bitPosition > 0) - { - m_bitPosition = 0; - m_position += sizeof(atUint8); - } - - if (m_position + 12 > m_length) - { - atVec3f zero = {}; - THROW_IO_EXCEPTION_RETURN(zero, "Position %0.8X outside stream bounds ", m_position); - } - - float* source = (float*)(m_data + m_position); - atVec3f result = {source[0], source[1], source[2]}; - if (isBigEndian()) - { - utility::BigFloat(result.vec[0]); - utility::BigFloat(result.vec[1]); - utility::BigFloat(result.vec[2]); - } - else - { - utility::LittleFloat(result.vec[0]); - utility::LittleFloat(result.vec[1]); - utility::LittleFloat(result.vec[2]); - } - - m_position += 12; - return result; -} - -atVec4f MemoryReader::readVec4f() -{ - if (!m_data) - loadData(); - - if (m_bitPosition > 0) - { - m_bitPosition = 0; - m_position += sizeof(atUint8); - } - - if (m_position + 16 > m_length) - { - atVec4f zero = {}; - THROW_IO_EXCEPTION_RETURN(zero, "Position %0.8X outside stream bounds ", m_position); - } - - float* source = (float*)(m_data + m_position); - atVec4f result = {source[0], source[1], source[2], source[3]}; - if (isBigEndian()) - { - utility::BigFloat(result.vec[0]); - utility::BigFloat(result.vec[1]); - utility::BigFloat(result.vec[2]); - utility::BigFloat(result.vec[3]); - } - else - { - utility::LittleFloat(result.vec[0]); - utility::LittleFloat(result.vec[1]); - utility::LittleFloat(result.vec[2]); - utility::LittleFloat(result.vec[3]); - } - - m_position += 16; - return result; -} - -std::string MemoryReader::readUnicode(atInt32 fixedLen) -{ - if (!m_data) - loadData(); - - std::string ret; - std::vector tmp; - atUint16 chr = readUint16(); - - atInt32 i; - for (i = 0 ;; ++i) - { - if (fixedLen >= 0 && i >= fixedLen - 1) - break; - - if (!chr) - break; - - tmp.push_back(chr); - chr = readUint16(); - } - - if (fixedLen >= 0 && i < fixedLen) - seek(fixedLen - i); - - utf8::utf16to8(tmp.begin(), tmp.end(), back_inserter(ret)); - return ret; -} - -std::string MemoryReader::readString(atInt32 fixedLen) -{ - std::string ret; - atUint8 chr = readByte(); - - atInt32 i; - for (i = 1 ; chr != 0 ; ++i) - { - ret += chr; - - if (fixedLen >= 0 && i >= fixedLen) - break; - - chr = readByte(); - } - - if (fixedLen >= 0 && i < fixedLen) - seek(fixedLen - i); - - return ret; -} - -std::wstring MemoryReader::readWString(atInt32 fixedLen) -{ - std::wstring ret; - atUint16 chr = readUint16(); - - atInt32 i; - for (i = 1 ; chr != 0 ; ++i) - { - ret += chr; - - if (fixedLen >= 0 && i >= fixedLen) - break; - - chr = readUint16(); - } - - if (fixedLen >= 0 && i < fixedLen) - seek(fixedLen - i); - - return ret; -} - void MemoryReader::loadData() { FILE* in; @@ -533,8 +136,6 @@ void MemoryReader::loadData() done += ret; - if (m_progressCallback) - m_progressCallback((int)((float)(done * 100.f) / length)); } while (done < length); @@ -542,7 +143,6 @@ void MemoryReader::loadData() fclose(in); m_length = length; m_position = 0; - m_bitPosition = 0; } } diff --git a/src/Athena/MemoryWriter.cpp b/src/Athena/MemoryWriter.cpp index 37de306..9ab8ac7 100644 --- a/src/Athena/MemoryWriter.cpp +++ b/src/Athena/MemoryWriter.cpp @@ -3,7 +3,6 @@ #include "Athena/InvalidOperationException.hpp" #include "Athena/InvalidDataException.hpp" #include "Athena/FileNotFoundException.hpp" -#include "utf8.h" #include #include @@ -22,10 +21,7 @@ namespace io MemoryWriter::MemoryWriter(atUint8* data, atUint64 length) : m_data((atUint8*)data), m_length(length), - m_position(0), - m_bitPosition(0), - m_endian(Endian::LittleEndian), - m_progressCallback(nullptr) + m_position(0) { if (!m_data && m_length > 0) m_data = new atUint8[m_length]; @@ -34,13 +30,9 @@ MemoryWriter::MemoryWriter(atUint8* data, atUint64 length) MemoryWriter::MemoryWriter(const std::string& filename, std::function progressFun) : m_length(0), m_filepath(filename), - m_position(0), - m_bitPosition(0), - m_endian(Endian::LittleEndian), - m_progressCallback(progressFun) + m_position(0) { m_length = 0x10; - m_bitPosition = 0; m_position = 0; m_data = new atUint8[m_length]; @@ -100,7 +92,6 @@ void MemoryWriter::setData(const atUint8* data, atUint64 length) m_data = (atUint8*)data; m_length = length; m_position = 0; - m_bitPosition = 0; } atUint8* MemoryWriter::data() const @@ -150,66 +141,11 @@ void MemoryWriter::save(const std::string& filename) fclose(out); } -void MemoryWriter::seekBit(int bit) -{ - if (bit < 0 || bit > 7) - THROW_INVALID_OPERATION_EXCEPTION("bit out of range"); - - m_bitPosition = bit; -} - -void MemoryWriter::writeBit(bool val) -{ - if (!isOpen()) - resize(sizeof(atUint8)); - - if (m_position + sizeof(atUint8) > m_length) - resize(m_position + sizeof(atUint8)); - - if (val) - *(atUint8*)(m_data + m_position) |= (1 << m_bitPosition); - else - *(atUint8*)(m_data + m_position) &= ~(1 << m_bitPosition); - - m_bitPosition++; - - if (m_bitPosition > 7) - { - m_bitPosition = 0; - m_position += sizeof(atUint8); - } -} - -void MemoryWriter::writeUByte(atUint8 val) -{ - if (!isOpen()) - resize(sizeof(atUint8)); - - if (m_bitPosition > 0) - { - m_bitPosition = 0; - m_position += sizeof(atUint8); - } - - if (m_position + 1 > m_length) - resize(m_position + 1); - - *(atUint8*)(m_data + m_position) = val; - - m_position++; -} - void MemoryWriter::writeUBytes(const atUint8* data, atUint64 length) { if (!isOpen()) resize(sizeof(atUint8) * length); - if (m_bitPosition > 0) - { - m_bitPosition = 0; - m_position += sizeof(atUint8); - } - if (!data) THROW_INVALID_DATA_EXCEPTION("data cannnot be NULL"); @@ -221,309 +157,6 @@ void MemoryWriter::writeUBytes(const atUint8* data, atUint64 length) m_position += length; } -void MemoryWriter::writeInt16(atInt16 val) -{ - if (!isOpen()) - resize(sizeof(atInt16)); - - if (m_bitPosition > 0) - { - m_bitPosition = 0; - m_position += sizeof(atUint8); - } - - if (m_position + sizeof(atInt16) > m_length) - resize(m_position + sizeof(atInt16)); - - if (isBigEndian()) - utility::BigInt16(val); - else - utility::LittleInt16(val); - - *(atInt16*)(m_data + m_position) = val; - m_position += sizeof(atInt16); -} - -void MemoryWriter::writeInt32(atInt32 val) -{ - if (!isOpen()) - resize(sizeof(atInt32)); - - if (m_bitPosition > 0) - { - m_bitPosition = 0; - m_position += sizeof(atUint8); - } - - if (m_position + sizeof(atInt32) > m_length) - resize(m_position + sizeof(atInt32)); - - if (isBigEndian()) - utility::BigInt32(val); - else - utility::LittleInt32(val); - - *(atInt32*)(m_data + m_position) = val; - m_position += sizeof(atInt32); -} - -void MemoryWriter::writeInt64(atInt64 val) -{ - if (!isOpen()) - resize(sizeof(atInt64)); - - if (m_bitPosition > 0) - { - m_bitPosition = 0; - m_position += sizeof(atUint8); - } - - if (m_position + sizeof(atInt64) > m_length) - resize(m_position + sizeof(atInt64)); - - - if (isBigEndian()) - utility::BigInt64(val); - else - utility::LittleInt64(val); - - *(atInt64*)(m_data + m_position) = val; - m_position += sizeof(atInt64); -} - -void MemoryWriter::writeFloat(float val) -{ - if (!isOpen()) - resize(sizeof(float)); - - if (m_bitPosition > 0) - { - m_bitPosition = 0; - m_position += sizeof(atUint8); - } - - if (m_position + sizeof(float) > m_length) - resize(m_position + sizeof(float)); - - if (isBigEndian()) - utility::BigFloat(val); - else - utility::LittleFloat(val); - - - *(float*)(m_data + m_position) = val; - m_position += sizeof(float); -} - -void MemoryWriter::writeDouble(double val) -{ - if (!isOpen()) - resize(sizeof(double)); - - if (m_bitPosition > 0) - { - m_bitPosition = 0; - m_position += sizeof(atUint8); - } - - if (m_position + sizeof(double) > m_length) - resize(m_position + sizeof(double)); - - if (isBigEndian()) - utility::BigDouble(val); - else - utility::LittleDouble(val); - - *(double*)(m_data + m_position) = val; - m_position += sizeof(double); -} - -void MemoryWriter::writeBool(bool val) -{ - if (m_bitPosition > 0) - { - m_bitPosition = 0; - m_position += sizeof(atUint8); - } - - if (m_position + sizeof(bool) > m_length) - resize(m_position + sizeof(bool)); - - *(bool*)(m_data + m_position) = val; - m_position += sizeof(bool); -} - -void MemoryWriter::writeVec3f(atVec3f vec) -{ - if (!isOpen()) - resize(12); - - if (m_bitPosition > 0) - { - m_bitPosition = 0; - m_position += sizeof(atUint8); - } - - if (m_position + 12 > m_length) - resize(m_position + 12); - - if (isBigEndian()) - { - utility::BigFloat(vec.vec[0]); - utility::BigFloat(vec.vec[1]); - utility::BigFloat(vec.vec[2]); - } - else - { - utility::LittleFloat(vec.vec[0]); - utility::LittleFloat(vec.vec[1]); - utility::LittleFloat(vec.vec[2]); - } - - ((float*)(m_data + m_position))[0] = vec.vec[0]; - ((float*)(m_data + m_position))[1] = vec.vec[1]; - ((float*)(m_data + m_position))[2] = vec.vec[2]; - m_position += 12; -} - -void MemoryWriter::writeVec4f(atVec4f vec) -{ - if (!isOpen()) - resize(16); - - if (m_bitPosition > 0) - { - m_bitPosition = 0; - m_position += sizeof(atUint8); - } - - if (m_position + 16 > m_length) - resize(m_position + 16); - - if (isBigEndian()) - { - utility::BigFloat(vec.vec[0]); - utility::BigFloat(vec.vec[1]); - utility::BigFloat(vec.vec[2]); - utility::BigFloat(vec.vec[3]); - } - else - { - utility::LittleFloat(vec.vec[0]); - utility::LittleFloat(vec.vec[1]); - utility::LittleFloat(vec.vec[2]); - utility::LittleFloat(vec.vec[3]); - } - - ((float*)(m_data + m_position))[0] = vec.vec[0]; - ((float*)(m_data + m_position))[1] = vec.vec[1]; - ((float*)(m_data + m_position))[2] = vec.vec[2]; - ((float*)(m_data + m_position))[3] = vec.vec[3]; - m_position += 16; -} - -void MemoryWriter::writeUnicode(const std::string& str, atInt32 fixedLen) -{ - std::string tmpStr = "\xEF\xBB\xBF" + str; - - std::vector tmp; - - utf8::utf8to16(tmpStr.begin(), tmpStr.end(), back_inserter(tmp)); - - if (fixedLen < 0) - { - for (atUint16 chr : tmp) - { - if (chr != 0xFEFF) - writeUint16(chr); - } - writeUint16(0); - } - else - { - auto it = tmp.begin(); - for (atInt32 i=0 ; i 0) - writeUByte(val); -} - void MemoryWriter::resize(atUint64 newSize) { if (newSize < m_length) diff --git a/src/Athena/SkywardSwordQuest.cpp b/src/Athena/SkywardSwordQuest.cpp index a76f0b0..b88386e 100644 --- a/src/Athena/SkywardSwordQuest.cpp +++ b/src/Athena/SkywardSwordQuest.cpp @@ -17,7 +17,9 @@ #include "Athena/SkywardSwordQuest.hpp" #include "Athena/Checksums.hpp" #include -#include "utf8.h" +#include +#include + namespace Athena { @@ -79,8 +81,8 @@ void SkywardSwordQuest::setPlayerName(const std::string& name) if (name.length() > 8) aDebug() << "WARNING: name cannot be greater than 8 characters, automatically truncating" << std::endl; - std::vector val; - utf8::utf8to16(name.begin(), name.end(), std::back_inserter(val)); + std::wstring_convert> conv; + std::wstring val = conv.from_bytes(name); for (atUint32 i = 0; i < 8; i++) { @@ -99,7 +101,7 @@ void SkywardSwordQuest::setPlayerName(const std::string& name) std::string SkywardSwordQuest::playerName() const { - std::vector val; + std::wstring val; for (atUint32 i = 0; i < 8; i++) { @@ -112,9 +114,8 @@ std::string SkywardSwordQuest::playerName() const val.push_back(c); } - std::string ret; - utf8::utf16to8(val.begin(), val.end(), std::back_inserter(ret)); - return std::string(ret.c_str()); + std::wstring_convert> conv; + return conv.to_bytes(val); } void SkywardSwordQuest::setRupeeCount(atUint16 value) diff --git a/src/Athena/WiiSave.cpp b/src/Athena/WiiSave.cpp index fdd4146..690e16a 100644 --- a/src/Athena/WiiSave.cpp +++ b/src/Athena/WiiSave.cpp @@ -20,7 +20,7 @@ #include "Athena/MemoryReader.hpp" #include "Athena/MemoryWriter.hpp" #include "Athena/Utility.hpp" -#include "aes.h" +#include "aes.hpp" #include "ec.h" #include "md5.h" #include "sha1.h" diff --git a/src/Athena/WiiSaveReader.cpp b/src/Athena/WiiSaveReader.cpp index d30afcd..3d262bb 100644 --- a/src/Athena/WiiSaveReader.cpp +++ b/src/Athena/WiiSaveReader.cpp @@ -25,7 +25,7 @@ #include "Athena/InvalidDataException.hpp" #include "Athena/FileWriter.hpp" #include "md5.h" -#include "aes.h" +#include "aes.hpp" #include "ec.h" #include "sha1.h" #include @@ -129,8 +129,9 @@ WiiBanner* WiiSaveReader::readBanner() memcpy(tmpIV, SD_IV, 16); std::cout << "Decrypting: banner.bin..."; - aes_set_key(SD_KEY); - aes_decrypt(tmpIV, data, dec, 0xF0C0); + std::unique_ptr aes = NewAES(); + aes->setKey(SD_KEY); + aes->decrypt(tmpIV, data, dec, 0xF0C0); std::cout << "done" << std::endl; memset(md5, 0, 16); @@ -296,8 +297,9 @@ WiiFile* WiiSaveReader::readFile() // Decrypt file std::cout << "Decrypting: " << ret->filename() << "..."; atUint8* decData = new atUint8[roundedLen]; - aes_set_key(SD_KEY); - aes_decrypt(iv, filedata, decData, roundedLen); + std::unique_ptr aes = NewAES(); + aes->setKey(SD_KEY); + aes->decrypt(iv, filedata, decData, roundedLen); delete filedata; ret->setData(decData); ret->setLength(fileLen); diff --git a/src/Athena/WiiSaveWriter.cpp b/src/Athena/WiiSaveWriter.cpp index a5b2212..f9ea5e9 100644 --- a/src/Athena/WiiSaveWriter.cpp +++ b/src/Athena/WiiSaveWriter.cpp @@ -27,7 +27,7 @@ #include "Athena/InvalidOperationException.hpp" #include "Athena/InvalidDataException.hpp" -#include "aes.h" +#include "aes.hpp" #include "ec.h" #include "md5.h" #include "sha1.h" @@ -146,12 +146,13 @@ void WiiSaveWriter::writeBanner(WiiBanner* banner) base::seek(0x0E, SeekOrigin::Begin); base::writeBytes((atInt8*)hash, 0x10); - aes_set_key(SD_KEY); + std::unique_ptr aes = NewAES(); + aes->setKey(SD_KEY); atUint8 data[0xF0C0]; memcpy(data, base::data(), 0xF0C0); atUint8 tmpIV[26]; memcpy(tmpIV, SD_IV, 16); - aes_encrypt(tmpIV, data, data, 0xF0C0); + aes->encrypt(tmpIV, data, data, 0xF0C0); base::seek(0, SeekOrigin::Begin); base::writeBytes((atInt8*)data, 0xF0C0); @@ -187,8 +188,9 @@ atUint32 WiiSaveWriter::writeFile(WiiFile* file) atUint8* data = new atUint8[roundedSize]; memset(data, 0, roundedSize); - aes_set_key(SD_KEY); - aes_encrypt(iv, file->data(), data, roundedSize); + std::unique_ptr aes = NewAES(); + aes->setKey(SD_KEY); + aes->encrypt(iv, file->data(), data, roundedSize); base::writeBytes((atInt8*)data, roundedSize); ret += roundedSize; diff --git a/src/aes.c b/src/aes.c deleted file mode 100644 index 637e161..0000000 --- a/src/aes.c +++ /dev/null @@ -1,467 +0,0 @@ -/* Rijndael Block Cipher - aes.c - - Written by Mike Scott 21st April 1999 - mike@compapp.dcu.ie - - Permission for free direct or derivative use is granted subject - to compliance with any conditions that the originators of the - algorithm place on its exploitation. - -*/ -#include "aes.h" -#include -//#include -#include - -/* rotates x one bit to the left */ - -#define ROTL(x) (((x)>>7)|((x)<<1)) - -/* Rotates 32-bit word left by 1, 2 or 3 byte */ - -#define ROTL8(x) (((x)<<8)|((x)>>24)) -#define ROTL16(x) (((x)<<16)|((x)>>16)) -#define ROTL24(x) (((x)<<24)|((x)>>8)) - -/* Fixed Data */ - -static atUint8 InCo[4] = {0xB, 0xD, 0x9, 0xE}; /* Inverse Coefficients */ - -static atUint8 fbsub[256]; -static atUint8 rbsub[256]; -static atUint8 ptab[256], ltab[256]; -static atUint32 ftable[256]; -static atUint32 rtable[256]; -static atUint32 rco[30]; - -/* Parameter-dependent data */ - -int Nk, Nb, Nr; -atUint8 fi[24], ri[24]; -atUint32 fkey[120]; -atUint32 rkey[120]; - -static atUint32 pack(const atUint8* b) -{ - /* pack bytes into a 32-bit Word */ - return ((atUint32)b[3] << 24) | ((atUint32)b[2] << 16) | ((atUint32)b[1] << 8) | (atUint32)b[0]; -} - -static void unpack(atUint32 a, atUint8* b) -{ - /* unpack bytes from a word */ - b[0] = (atUint8)a; - b[1] = (atUint8)(a >> 8); - b[2] = (atUint8)(a >> 16); - b[3] = (atUint8)(a >> 24); -} - -static atUint8 xtime(atUint8 a) -{ - atUint8 b; - - if (a & 0x80) b = 0x1B; - else b = 0; - - a <<= 1; - a ^= b; - return a; -} - -static atUint8 bmul(atUint8 x, atUint8 y) -{ - /* x.y= AntiLog(Log(x) + Log(y)) */ - if (x && y) return ptab[(ltab[x] + ltab[y]) % 255]; - else return 0; -} - -static atUint32 SubByte(atUint32 a) -{ - atUint8 b[4]; - unpack(a, b); - b[0] = fbsub[b[0]]; - b[1] = fbsub[b[1]]; - b[2] = fbsub[b[2]]; - b[3] = fbsub[b[3]]; - return pack(b); -} - -static atUint8 product(atUint32 x, atUint32 y) -{ - /* dot product of two 4-byte arrays */ - atUint8 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 atUint32 InvMixCol(atUint32 x) -{ - /* matrix Multiplication */ - atUint32 y, m; - atUint8 b[4]; - - m = pack(InCo); - b[3] = product(m, x); - m = ROTL24(m); - b[2] = product(m, x); - m = ROTL24(m); - b[1] = product(m, x); - m = ROTL24(m); - b[0] = product(m, x); - y = pack(b); - return y; -} - -atUint8 ByteSub(atUint8 x) -{ - atUint8 y = ptab[255 - ltab[x]]; /* multiplicative inverse */ - x = y; - x = ROTL(x); - y ^= x; - x = ROTL(x); - y ^= x; - x = ROTL(x); - y ^= x; - x = ROTL(x); - y ^= x; - y ^= 0x63; - return y; -} - -void gentables(void) -{ - /* generate tables */ - int i; - atUint8 y, b[4]; - - /* use 3 as primitive root to generate power and log tables */ - - ltab[0] = 0; - ptab[0] = 1; - ltab[1] = 0; - ptab[1] = 3; - ltab[3] = 1; - - for (i = 2; i < 256; i++) - { - ptab[i] = ptab[i - 1] ^ xtime(ptab[i - 1]); - ltab[ptab[i]] = i; - } - - /* affine transformation:- each bit is xored with itself shifted one bit */ - - fbsub[0] = 0x63; - rbsub[0x63] = 0; - - for (i = 1; i < 256; i++) - { - y = ByteSub((atUint8)i); - fbsub[i] = y; - rbsub[y] = i; - } - - for (i = 0, y = 1; i < 30; i++) - { - rco[i] = y; - y = xtime(y); - } - - /* calculate forward and reverse tables */ - for (i = 0; i < 256; i++) - { - y = fbsub[i]; - b[3] = y ^ xtime(y); - b[2] = y; - b[1] = y; - b[0] = xtime(y); - ftable[i] = pack(b); - - y = rbsub[i]; - b[3] = bmul(InCo[0], y); - b[2] = bmul(InCo[1], y); - b[1] = bmul(InCo[2], y); - b[0] = bmul(InCo[3], y); - rtable[i] = pack(b); - } -} - -void gkey(int nb, int nk, const atUint8* 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; - atUint32 CipherKey[8]; - - Nb = nb; - Nk = nk; - - /* Nr is number of rounds */ - if (Nb >= Nk) Nr = 6 + Nb; - else Nr = 6 + Nk; - - C1 = 1; - - if (Nb < 8) { C2 = 2; C3 = 3; } - else { C2 = 3; C3 = 4; } - - /* pre-calculate forward and reverse increments */ - for (m = j = 0; j < nb; j++, m += 3) - { - fi[m] = (j + C1) % nb; - fi[m + 1] = (j + C2) % nb; - fi[m + 2] = (j + C3) % nb; - ri[m] = (nb + j - C1) % nb; - ri[m + 1] = (nb + j - C2) % nb; - ri[m + 2] = (nb + j - C3) % nb; - } - - N = Nb * (Nr + 1); - - for (i = j = 0; i < Nk; i++, j += 4) - { - CipherKey[i] = pack(key + j); - } - - for (i = 0; i < Nk; i++) fkey[i] = CipherKey[i]; - - for (j = Nk, k = 0; j < N; j += Nk, k++) - { - fkey[j] = fkey[j - Nk] ^ SubByte(ROTL24(fkey[j - 1]))^rco[k]; - - if (Nk <= 6) - { - for (i = 1; i < Nk && (i + j) < N; i++) - fkey[i + j] = fkey[i + j - Nk] ^ fkey[i + j - 1]; - } - else - { - for (i = 1; i < 4 && (i + j) < N; i++) - fkey[i + j] = fkey[i + j - Nk] ^ fkey[i + j - 1]; - - if ((j + 4) < N) fkey[j + 4] = fkey[j + 4 - Nk] ^ SubByte(fkey[j + 3]); - - for (i = 5; i < Nk && (i + j) < N; i++) - fkey[i + j] = fkey[i + j - Nk] ^ fkey[i + j - 1]; - } - - } - - /* now for the expanded decrypt key in reverse order */ - - for (j = 0; j < Nb; j++) rkey[j + N - Nb] = fkey[j]; - - for (i = Nb; i < N - Nb; i += Nb) - { - k = N - Nb - i; - - for (j = 0; j < Nb; j++) rkey[k + j] = InvMixCol(fkey[i + j]); - } - - for (j = N - Nb; j < N; j++) rkey[j - N + Nb] = fkey[j]; -} - - -/* There is an obvious time/space trade-off possible here. * - * Instead of just one ftable[], I could have 4, the other * - * 3 pre-rotated to save the ROTL8, ROTL16 and ROTL24 overhead */ - -void encrypt(atUint8* buff) -{ - int i, j, k, m; - atUint32 a[8], b[8], *x, *y, *t; - - for (i = j = 0; i < Nb; i++, j += 4) - { - a[i] = pack(buff + j); - a[i] ^= fkey[i]; - } - - k = Nb; - x = a; - y = b; - - /* State alternates between a and b */ - for (i = 1; i < Nr; i++) - { - /* Nr is number of rounds. May be odd. */ - - /* if Nb is fixed - unroll this next - loop and hard-code in the values of fi[] */ - - 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[(atUint8)x[j]] ^ - ROTL8(ftable[(atUint8)(x[fi[m]] >> 8)])^ - ROTL16(ftable[(atUint8)(x[fi[m + 1]] >> 16)])^ - ROTL24(ftable[(atUint8)(x[fi[m + 2]] >> 24)]); - } - - t = x; - x = y; - y = t; /* swap pointers */ - } - - /* Last Round - unroll if possible */ - for (m = j = 0; j < Nb; j++, m += 3) - { - y[j] = fkey[k++] ^ (atUint32)fbsub[(atUint8)x[j]] ^ - ROTL8((atUint32)fbsub[(atUint8)(x[fi[m]] >> 8)])^ - ROTL16((atUint32)fbsub[(atUint8)(x[fi[m + 1]] >> 16)])^ - ROTL24((atUint32)fbsub[(atUint8)(x[fi[m + 2]] >> 24)]); - } - - for (i = j = 0; i < Nb; i++, j += 4) - { - unpack(y[i], (atUint8*)&buff[j]); - x[i] = y[i] = 0; /* clean up stack */ - } - - return; -} - -void decrypt(atUint8* buff) -{ - int i, j, k, m; - atUint32 a[8], b[8], *x, *y, *t; - - for (i = j = 0; i < Nb; i++, j += 4) - { - a[i] = pack(buff + j); - a[i] ^= rkey[i]; - } - - k = Nb; - x = a; - y = b; - - /* State alternates between a and b */ - for (i = 1; i < Nr; i++) - { - /* Nr is number of rounds. May be odd. */ - - /* if Nb is fixed - unroll this next - loop and hard-code in the values of ri[] */ - - for (m = j = 0; j < Nb; j++, m += 3) - { - /* This is the time-critical bit */ - y[j] = rkey[k++] ^ rtable[(atUint8)x[j]] ^ - ROTL8(rtable[(atUint8)(x[ri[m]] >> 8)])^ - ROTL16(rtable[(atUint8)(x[ri[m + 1]] >> 16)])^ - ROTL24(rtable[(atUint8)(x[ri[m + 2]] >> 24)]); - } - - t = x; - x = y; - y = t; /* swap pointers */ - } - - /* Last Round - unroll if possible */ - for (m = j = 0; j < Nb; j++, m += 3) - { - y[j] = rkey[k++] ^ (atUint32)rbsub[(atUint8)x[j]] ^ - ROTL8((atUint32)rbsub[(atUint8)(x[ri[m]] >> 8)])^ - ROTL16((atUint32)rbsub[(atUint8)(x[ri[m + 1]] >> 16)])^ - ROTL24((atUint32)rbsub[(atUint8)(x[ri[m + 2]] >> 24)]); - } - - for (i = j = 0; i < Nb; i++, j += 4) - { - unpack(y[i], (atUint8*)&buff[j]); - x[i] = y[i] = 0; /* clean up stack */ - } - - return; -} - -void aes_set_key(const atUint8* key) -{ - gentables(); - gkey(4, 4, key); -} - -// CBC mode decryption -void aes_decrypt(atUint8* iv, const atUint8* inbuf, atUint8* outbuf, atUint64 len) -{ - atUint8 block[16]; - atUint8* ctext_ptr; - unsigned int blockno = 0, i; - - //fprintf( stderr,"aes_decrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len ); - //printf("aes_decrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len); - - for (blockno = 0; blockno <= (len / sizeof(block)); blockno++) - { - unsigned int fraction; - - if (blockno == (len / sizeof(block))) // last block - { - fraction = len % sizeof(block); - - if (fraction == 0) break; - - memset(block, 0, sizeof(block)); - } - else fraction = 16; - - // debug_printf("block %d: fraction = %d\n", blockno, fraction); - memcpy(block, inbuf + blockno * sizeof(block), fraction); - decrypt(block); - - if (blockno == 0) ctext_ptr = iv; - else ctext_ptr = (atUint8*)(inbuf + (blockno - 1) * sizeof(block)); - - for (i = 0; i < fraction; i++) - outbuf[blockno * sizeof(block) + i] = - ctext_ptr[i] ^ block[i]; - - // debug_printf("Block %d output: ", blockno); - // hexdump(outbuf + blockno*sizeof(block), 16); - } -} - -// CBC mode encryption -void aes_encrypt(atUint8* iv, const atUint8* inbuf, atUint8* outbuf, atUint64 len) -{ - atUint8 block[16]; - unsigned int blockno = 0, i; - - //printf("aes_decrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len); - //fprintf( stderr,"aes_encrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len); - - for (blockno = 0; blockno <= (len / sizeof(block)); blockno++) - { - unsigned int fraction; - - if (blockno == (len / sizeof(block))) // last block - { - fraction = len % sizeof(block); - - if (fraction == 0) break; - - memset(block, 0, sizeof(block)); - } - else fraction = 16; - - // debug_printf("block %d: fraction = %d\n", blockno, fraction); - memcpy(block, inbuf + blockno * sizeof(block), fraction); - - for (i = 0; i < fraction; i++) - block[i] = inbuf[blockno * sizeof(block) + i] ^ iv[i]; - - encrypt(block); - memcpy(iv, block, sizeof(block)); - memcpy(outbuf + blockno * sizeof(block), block, sizeof(block)); - // debug_printf("Block %d output: ", blockno); - // hexdump(outbuf + blockno*sizeof(block), 16); - } -} - - - diff --git a/src/aes.cpp b/src/aes.cpp new file mode 100644 index 0000000..b9f1688 --- /dev/null +++ b/src/aes.cpp @@ -0,0 +1,618 @@ +#include "aes.hpp" +#include +#include +#include + +namespace Athena +{ + +/* rotates x one bit to the left */ + +#define ROTL(x) (((x)>>7)|((x)<<1)) + +/* Rotates 32-bit word left by 1, 2 or 3 byte */ + +#define ROTL8(x) (((x)<<8)|((x)>>24)) +#define ROTL16(x) (((x)<<16)|((x)>>16)) +#define ROTL24(x) (((x)<<24)|((x)>>8)) + +/* Fixed Data */ + +static const uint8_t InCo[4] = {0xB, 0xD, 0x9, 0xE}; /* Inverse Coefficients */ + +static inline uint32_t pack(const uint8_t* b) +{ + /* pack bytes into a 32-bit Word */ + return ((uint32_t)b[3] << 24) | ((uint32_t)b[2] << 16) | ((uint32_t)b[1] << 8) | (uint32_t)b[0]; +} + +static inline void unpack(uint32_t a, uint8_t* b) +{ + /* unpack bytes from a word */ + b[0] = (uint8_t)a; + b[1] = (uint8_t)(a >> 8); + b[2] = (uint8_t)(a >> 16); + b[3] = (uint8_t)(a >> 24); +} + +static inline uint8_t xtime(uint8_t a) +{ + uint8_t b; + + if (a & 0x80) b = 0x1B; + else b = 0; + + a <<= 1; + a ^= b; + return a; +} + +class SoftwareAES : public IAES +{ +protected: + uint8_t fbsub[256]; + uint8_t rbsub[256]; + uint8_t ptab[256], ltab[256]; + uint32_t ftable[256]; + uint32_t rtable[256]; + uint32_t rco[30]; + + /* Parameter-dependent data */ + + int Nk, Nb, Nr; + uint8_t fi[24], ri[24]; + uint32_t fkey[120]; + uint32_t rkey[120]; + + + uint8_t bmul(uint8_t x, uint8_t y); + uint32_t SubByte(uint32_t a); + uint8_t product(uint32_t x, uint32_t y); + uint32_t InvMixCol(uint32_t x); + uint8_t ByteSub(uint8_t x); + void gentables(void); + void gkey(int nb, int nk, const uint8_t* key); + void _encrypt(uint8_t* buff); + void _decrypt(uint8_t* buff); + +public: + void encrypt(const uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, uint64_t len); + void decrypt(const uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, uint64_t len); + void setKey(const uint8_t* key); +}; + +uint8_t SoftwareAES::bmul(uint8_t x, uint8_t y) +{ + /* x.y= AntiLog(Log(x) + Log(y)) */ + if (x && y) return ptab[(ltab[x] + ltab[y]) % 255]; + else return 0; +} + +uint32_t SoftwareAES::SubByte(uint32_t a) +{ + uint8_t b[4]; + unpack(a, b); + b[0] = fbsub[b[0]]; + b[1] = fbsub[b[1]]; + b[2] = fbsub[b[2]]; + b[3] = fbsub[b[3]]; + return pack(b); +} + +uint8_t SoftwareAES::product(uint32_t x, uint32_t y) +{ + /* dot product of two 4-byte arrays */ + uint8_t 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]); +} + +uint32_t SoftwareAES::InvMixCol(uint32_t x) +{ + /* matrix Multiplication */ + uint32_t y, m; + uint8_t b[4]; + + m = pack(InCo); + b[3] = product(m, x); + m = ROTL24(m); + b[2] = product(m, x); + m = ROTL24(m); + b[1] = product(m, x); + m = ROTL24(m); + b[0] = product(m, x); + y = pack(b); + return y; +} + +uint8_t SoftwareAES::ByteSub(uint8_t x) +{ + uint8_t y = ptab[255 - ltab[x]]; /* multiplicative inverse */ + x = y; + x = ROTL(x); + y ^= x; + x = ROTL(x); + y ^= x; + x = ROTL(x); + y ^= x; + x = ROTL(x); + y ^= x; + y ^= 0x63; + return y; +} + +void SoftwareAES::gentables(void) +{ + /* generate tables */ + int i; + uint8_t y, b[4]; + + /* use 3 as primitive root to generate power and log tables */ + + ltab[0] = 0; + ptab[0] = 1; + ltab[1] = 0; + ptab[1] = 3; + ltab[3] = 1; + + for (i = 2; i < 256; i++) + { + ptab[i] = ptab[i - 1] ^ xtime(ptab[i - 1]); + ltab[ptab[i]] = i; + } + + /* affine transformation:- each bit is xored with itself shifted one bit */ + + fbsub[0] = 0x63; + rbsub[0x63] = 0; + + for (i = 1; i < 256; i++) + { + y = ByteSub((uint8_t)i); + fbsub[i] = y; + rbsub[y] = i; + } + + for (i = 0, y = 1; i < 30; i++) + { + rco[i] = y; + y = xtime(y); + } + + /* calculate forward and reverse tables */ + for (i = 0; i < 256; i++) + { + y = fbsub[i]; + b[3] = y ^ xtime(y); + b[2] = y; + b[1] = y; + b[0] = xtime(y); + ftable[i] = pack(b); + + y = rbsub[i]; + b[3] = bmul(InCo[0], y); + b[2] = bmul(InCo[1], y); + b[1] = bmul(InCo[2], y); + b[0] = bmul(InCo[3], y); + rtable[i] = pack(b); + } +} + +void SoftwareAES::gkey(int nb, int nk, const uint8_t* 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; + uint32_t CipherKey[8]; + + Nb = nb; + Nk = nk; + + /* Nr is number of rounds */ + if (Nb >= Nk) Nr = 6 + Nb; + else Nr = 6 + Nk; + + C1 = 1; + + if (Nb < 8) { C2 = 2; C3 = 3; } + else { C2 = 3; C3 = 4; } + + /* pre-calculate forward and reverse increments */ + for (m = j = 0; j < nb; j++, m += 3) + { + fi[m] = (j + C1) % nb; + fi[m + 1] = (j + C2) % nb; + fi[m + 2] = (j + C3) % nb; + ri[m] = (nb + j - C1) % nb; + ri[m + 1] = (nb + j - C2) % nb; + ri[m + 2] = (nb + j - C3) % nb; + } + + N = Nb * (Nr + 1); + + for (i = j = 0; i < Nk; i++, j += 4) + { + CipherKey[i] = pack(key + j); + } + + for (i = 0; i < Nk; i++) fkey[i] = CipherKey[i]; + + for (j = Nk, k = 0; j < N; j += Nk, k++) + { + fkey[j] = fkey[j - Nk] ^ SubByte(ROTL24(fkey[j - 1]))^rco[k]; + + if (Nk <= 6) + { + for (i = 1; i < Nk && (i + j) < N; i++) + fkey[i + j] = fkey[i + j - Nk] ^ fkey[i + j - 1]; + } + else + { + for (i = 1; i < 4 && (i + j) < N; i++) + fkey[i + j] = fkey[i + j - Nk] ^ fkey[i + j - 1]; + + if ((j + 4) < N) fkey[j + 4] = fkey[j + 4 - Nk] ^ SubByte(fkey[j + 3]); + + for (i = 5; i < Nk && (i + j) < N; i++) + fkey[i + j] = fkey[i + j - Nk] ^ fkey[i + j - 1]; + } + + } + + /* now for the expanded decrypt key in reverse order */ + + for (j = 0; j < Nb; j++) rkey[j + N - Nb] = fkey[j]; + + for (i = Nb; i < N - Nb; i += Nb) + { + k = N - Nb - i; + + for (j = 0; j < Nb; j++) rkey[k + j] = InvMixCol(fkey[i + j]); + } + + for (j = N - Nb; j < N; j++) rkey[j - N + Nb] = fkey[j]; +} + + +/* There is an obvious time/space trade-off possible here. * + * Instead of just one ftable[], I could have 4, the other * + * 3 pre-rotated to save the ROTL8, ROTL16 and ROTL24 overhead */ + +void SoftwareAES::_encrypt(uint8_t* buff) +{ + int i, j, k, m; + uint32_t a[8], b[8], *x, *y, *t; + + for (i = j = 0; i < Nb; i++, j += 4) + { + a[i] = pack(buff + j); + a[i] ^= fkey[i]; + } + + k = Nb; + x = a; + y = b; + + /* State alternates between a and b */ + for (i = 1; i < Nr; i++) + { + /* Nr is number of rounds. May be odd. */ + + /* if Nb is fixed - unroll this next + loop and hard-code in the values of fi[] */ + + 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[(uint8_t)x[j]] ^ + ROTL8(ftable[(uint8_t)(x[fi[m]] >> 8)])^ + ROTL16(ftable[(uint8_t)(x[fi[m + 1]] >> 16)])^ + ROTL24(ftable[(uint8_t)(x[fi[m + 2]] >> 24)]); + } + + t = x; + x = y; + y = t; /* swap pointers */ + } + + /* Last Round - unroll if possible */ + for (m = j = 0; j < Nb; j++, m += 3) + { + y[j] = fkey[k++] ^ (uint32_t)fbsub[(uint8_t)x[j]] ^ + ROTL8((uint32_t)fbsub[(uint8_t)(x[fi[m]] >> 8)])^ + ROTL16((uint32_t)fbsub[(uint8_t)(x[fi[m + 1]] >> 16)])^ + ROTL24((uint32_t)fbsub[(uint8_t)(x[fi[m + 2]] >> 24)]); + } + + for (i = j = 0; i < Nb; i++, j += 4) + { + unpack(y[i], (uint8_t*)&buff[j]); + x[i] = y[i] = 0; /* clean up stack */ + } + + return; +} + +void SoftwareAES::_decrypt(uint8_t* buff) +{ + int i, j, k, m; + uint32_t a[8], b[8], *x, *y, *t; + + for (i = j = 0; i < Nb; i++, j += 4) + { + a[i] = pack(buff + j); + a[i] ^= rkey[i]; + } + + k = Nb; + x = a; + y = b; + + /* State alternates between a and b */ + for (i = 1; i < Nr; i++) + { + /* Nr is number of rounds. May be odd. */ + + /* if Nb is fixed - unroll this next + loop and hard-code in the values of ri[] */ + + for (m = j = 0; j < Nb; j++, m += 3) + { + /* This is the time-critical bit */ + y[j] = rkey[k++] ^ rtable[(uint8_t)x[j]] ^ + ROTL8(rtable[(uint8_t)(x[ri[m]] >> 8)])^ + ROTL16(rtable[(uint8_t)(x[ri[m + 1]] >> 16)])^ + ROTL24(rtable[(uint8_t)(x[ri[m + 2]] >> 24)]); + } + + t = x; + x = y; + y = t; /* swap pointers */ + } + + /* Last Round - unroll if possible */ + for (m = j = 0; j < Nb; j++, m += 3) + { + y[j] = rkey[k++] ^ (uint32_t)rbsub[(uint8_t)x[j]] ^ + ROTL8((uint32_t)rbsub[(uint8_t)(x[ri[m]] >> 8)])^ + ROTL16((uint32_t)rbsub[(uint8_t)(x[ri[m + 1]] >> 16)])^ + ROTL24((uint32_t)rbsub[(uint8_t)(x[ri[m + 2]] >> 24)]); + } + + for (i = j = 0; i < Nb; i++, j += 4) + { + unpack(y[i], (uint8_t*)&buff[j]); + x[i] = y[i] = 0; /* clean up stack */ + } + + return; +} + +void SoftwareAES::setKey(const uint8_t* key) +{ + gentables(); + gkey(4, 4, key); +} + +// CBC mode decryption +void SoftwareAES::decrypt(const uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, size_t len) +{ + uint8_t block[16]; + const uint8_t* ctext_ptr; + unsigned int blockno = 0, i; + + //fprintf( stderr,"aes_decrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len ); + //printf("aes_decrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len); + + for (blockno = 0; blockno <= (len / sizeof(block)); blockno++) + { + unsigned int fraction; + + if (blockno == (len / sizeof(block))) // last block + { + fraction = len % sizeof(block); + + if (fraction == 0) break; + + memset(block, 0, sizeof(block)); + } + else fraction = 16; + + // debug_printf("block %d: fraction = %d\n", blockno, fraction); + memcpy(block, inbuf + blockno * sizeof(block), fraction); + _decrypt(block); + + if (blockno == 0) ctext_ptr = iv; + else ctext_ptr = (uint8_t*)(inbuf + (blockno - 1) * sizeof(block)); + + for (i = 0; i < fraction; i++) + outbuf[blockno * sizeof(block) + i] = + ctext_ptr[i] ^ block[i]; + + // debug_printf("Block %d output: ", blockno); + // hexdump(outbuf + blockno*sizeof(block), 16); + } +} + +// CBC mode encryption +void SoftwareAES::encrypt(const uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, uint64_t len) +{ + uint8_t block[16]; + uint8_t feedback[16]; + memcpy(feedback, iv, 16); + unsigned int blockno = 0, i; + + //printf("aes_decrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len); + //fprintf( stderr,"aes_encrypt(%p, %p, %p, %lld)\n", iv, inbuf, outbuf, len); + + for (blockno = 0; blockno <= (len / sizeof(block)); blockno++) + { + unsigned int fraction; + + if (blockno == (len / sizeof(block))) // last block + { + fraction = len % sizeof(block); + + if (fraction == 0) break; + + memset(block, 0, sizeof(block)); + } + else fraction = 16; + + // debug_printf("block %d: fraction = %d\n", blockno, fraction); + memcpy(block, inbuf + blockno * sizeof(block), fraction); + + for (i = 0; i < fraction; i++) + block[i] = inbuf[blockno * sizeof(block) + i] ^ feedback[i]; + + _encrypt(block); + memcpy(feedback, block, sizeof(block)); + memcpy(outbuf + blockno * sizeof(block), block, sizeof(block)); + // debug_printf("Block %d output: ", blockno); + // hexdump(outbuf + blockno*sizeof(block), 16); + } +} + +#if __AES__ + +#include + +class NiAES : public IAES +{ + __m128i m_ekey[11]; + __m128i m_dkey[11]; +public: + void encrypt(const uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, uint64_t len) + { + __m128i feedback,data; + uint64_t i,j; + if (len%16) + len = len/16+1; + else + len /= 16; + feedback = _mm_loadu_si128((__m128i*)iv); + for (i=0 ; i NewAES() +{ +#if __AES__ + if (HAS_AES_NI == -1) + { + unsigned int a,b,c,d; + __cpuid(1, a,b,c,d); + HAS_AES_NI = ((c & 0x2000000) != 0); + } + if (HAS_AES_NI) + return std::unique_ptr(new NiAES); + else + return std::unique_ptr(new SoftwareAES); +#else + return std::unique_ptr(new SoftwareAES); +#endif +} + +} +