significant virtual-method refactor to streaming interface

This commit is contained in:
Jack Andersen 2015-07-07 16:53:39 -10:00
parent ce917d4aca
commit 97dfabb265
25 changed files with 1526 additions and 2552 deletions

View File

@ -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

View File

@ -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 \

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,9 +1,9 @@
#ifndef GLOBAL_HPP
#define GLOBAL_HPP
#include <iostream>
#include "Athena/Types.hpp"
#include "Athena/Utility.hpp"
#include <iostream>
#ifdef _MSC_VER
#pragma warning(disable : 4996)

View File

@ -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;
};
}
}

View File

@ -1,6 +1,8 @@
#ifndef ISTREAMREADER_HPP
#define ISTREAMREADER_HPP
#include <locale>
#include <codecvt>
#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.<br />
* 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.<br />
*/
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<std::codecvt_utf8<wchar_t>> 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;
};
}
}

View File

@ -1,6 +1,8 @@
#ifndef ISTREAMWRITER_HPP
#define ISTREAMWRITER_HPP
#include <locale>
#include <codecvt>
#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.<br />
* 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.<br />
*/
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<std::codecvt_utf8<wchar_t>> 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<fixedLen ; ++i)
{
atUint16 chr;
if (it == tmp.end())
chr = 0;
else
chr = *it++;
if (chr == 0xFEFF)
{
--i;
continue;
}
writeUint16(chr);
}
}
}
/*! \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
*/
inline void writeString(const std::string& str, atInt32 fixedLen = -1)
{
if (fixedLen < 0)
{
for (atUint8 c : str)
{
writeUByte(c);
if (c == '\0')
break;
}
writeUByte(0);
}
else
{
auto it = str.begin();
for (atInt32 i=0 ; i<fixedLen ; ++i)
{
atUint8 chr;
if (it == str.end())
chr = 0;
else
chr = *it++;
writeUByte(chr);
}
}
}
/*! \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
*/
inline void writeWString(const std::wstring& str, atInt32 fixedLen = -1)
{
if (fixedLen < 0)
{
for (atUint16 c : str)
{
writeUint16(c);
if (c == L'\0')
break;
}
writeUint16(0);
}
else
{
auto it = str.begin();
for (atInt32 i=0 ; i<fixedLen ; ++i)
{
atUint16 chr;
if (it == str.end())
chr = 0;
else
chr = *it++;
writeUint16(chr);
}
}
}
inline void fill(atUint8 val, atUint64 length)
{for (atUint64 l=0 ; l<length ; ++l) writeUBytes(&val, 1);}
inline void fill(atInt8 val, atUint64 length)
{fill((atUint8)val, length);}
protected:
Endian m_endian;
};
}
}

View File

@ -9,8 +9,8 @@ namespace Athena
{
namespace io
{
/*! \class BinaryReader
* \brief A Stream class for reading binary data
/*! \class MemoryReader
* \brief A Stream class for reading data from a memory position
*
* A Class for reading binary data from a file or memory stream,
* all work is done using a memory buffer, and not read directly from the disk
@ -20,6 +20,8 @@ namespace io
class MemoryReader : public IStreamReader
{
public:
~MemoryReader();
/*! \brief This constructor takes an existing buffer to read from.
*
* \param data The existing buffer
@ -31,45 +33,7 @@ public:
*
* \param filename The file to create the stream from
*/
MemoryReader(const std::string& filename, std::function<void(int)> 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.<br />
* 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.<br />
*/
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.<br />
@ -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<void(int)> 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<void(int)> m_progressCallback;
};
} // io

View File

@ -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<void(int)> 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.<br />
* 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.<br />
*/
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.<br />
* <b>BEWARE:</b> As this deletes the current buffer it WILL cause a loss of data
* if that was not the intent.<br />
@ -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<void(int)> 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<void(int)> m_progressCallback;
private:
void resize(atUint64 newSize);
};

View File

@ -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_

23
include/aes.hpp Normal file
View File

@ -0,0 +1,23 @@
#ifndef __AES_HPP__
#define __AES_HPP__
#include <stdint.h>
#include <stdlib.h>
#include <memory>
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<IAES> NewAES();
}
#endif //__AES_HPP__

View File

@ -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;

View File

@ -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)

View File

@ -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<atUint16> 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

View File

@ -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 ; ++i)
{
if (fwrite(&term, 1, 1, m_fileHandle) != 1)
THROW_IO_EXCEPTION("Unable to write to stream");
}
}
}
}
void FileWriter::writeWString(const std::wstring& val, atInt32 fixedLen)
{
if (!isOpen())
THROW_INVALID_OPERATION_EXCEPTION("File not open for writing");
m_bitValid = false;
wchar_t term = L'\0';
if (fixedLen < 0)
{
if (fwrite(val.c_str(), 2, val.length(), m_fileHandle) != val.length())
THROW_IO_EXCEPTION("Unable to write to stream");
if (fwrite(&term, 2, 1, m_fileHandle) != 1)
THROW_IO_EXCEPTION("Unable to write to stream");
}
else
{
if ((atInt32)val.length() >= 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<fixedLen ; ++i)
{
if (fwrite(&term, 2, 1, m_fileHandle) != 1)
THROW_IO_EXCEPTION("Unable to write to stream");
}
}
}
}
void FileWriter::writeUnicode(const std::string& str, atInt32 fixedLen)
{
if (!isOpen())
THROW_INVALID_OPERATION_EXCEPTION("File not open for writing");
std::string tmpStr = "\xEF\xBB\xBF" + str;
std::vector<atUint16> 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<fixedLen ; ++i)
{
atUint16 chr;
if (it == tmp.end())
chr = 0;
else
chr = *it++;
if (chr == 0xFEFF)
{
--i;
continue;
}
writeUint16(chr);
}
}
}
void FileWriter::fill(atInt8 byte, atUint64 len)
{
if (!isOpen())
THROW_INVALID_OPERATION_EXCEPTION("File not open for writing");
fwrite(&byte, 1, len, m_fileHandle);
}
}
} // Athena

View File

@ -3,7 +3,6 @@
#include "Athena/FileNotFoundException.hpp"
#include "Athena/InvalidDataException.hpp"
#include "Athena/InvalidOperationException.hpp"
#include "utf8.h"
#include <stdio.h>
#include <stdlib.h>
@ -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<void(int)> 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<short> 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;
}
}

View File

@ -3,7 +3,6 @@
#include "Athena/InvalidOperationException.hpp"
#include "Athena/InvalidDataException.hpp"
#include "Athena/FileNotFoundException.hpp"
#include "utf8.h"
#include <stdio.h>
#include <string.h>
@ -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<void(int)> 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<atUint16> 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<fixedLen ; ++i)
{
atUint16 chr;
if (it == tmp.end())
chr = 0;
else
chr = *it++;
if (chr == 0xFEFF)
{
--i;
continue;
}
writeUint16(chr);
}
}
}
void MemoryWriter::writeString(const std::string& str, atInt32 fixedLen)
{
if (fixedLen < 0)
{
for (atUint8 c : str)
{
writeUByte(c);
if (c == '\0')
break;
}
writeUByte(0);
}
else
{
auto it = str.begin();
for (atInt32 i=0 ; i<fixedLen ; ++i)
{
atUint8 chr;
if (it == str.end())
chr = 0;
else
chr = *it++;
writeUByte(chr);
}
}
}
void MemoryWriter::writeWString(const std::wstring& str, atInt32 fixedLen)
{
if (fixedLen < 0)
{
for (atUint16 c : str)
{
writeUint16(c);
if (c == L'\0')
break;
}
writeUint16(0);
}
else
{
auto it = str.begin();
for (atInt32 i=0 ; i<fixedLen ; ++i)
{
atUint16 chr;
if (it == str.end())
chr = 0;
else
chr = *it++;
writeUint16(chr);
}
}
}
void MemoryWriter::fill(atUint8 val, atUint64 length)
{
while ((length--) > 0)
writeUByte(val);
}
void MemoryWriter::resize(atUint64 newSize)
{
if (newSize < m_length)

View File

@ -17,7 +17,9 @@
#include "Athena/SkywardSwordQuest.hpp"
#include "Athena/Checksums.hpp"
#include <sstream>
#include "utf8.h"
#include <locale>
#include <codecvt>
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<atUint16> val;
utf8::utf8to16(name.begin(), name.end(), std::back_inserter(val));
std::wstring_convert<std::codecvt_utf8<wchar_t>> 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<atUint16> 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<std::codecvt_utf8<wchar_t>> conv;
return conv.to_bytes(val);
}
void SkywardSwordQuest::setRupeeCount(atUint16 value)

View File

@ -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"

View File

@ -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 <iostream>
@ -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<IAES> 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<IAES> aes = NewAES();
aes->setKey(SD_KEY);
aes->decrypt(iv, filedata, decData, roundedLen);
delete filedata;
ret->setData(decData);
ret->setLength(fileLen);

View File

@ -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<IAES> 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<IAES> aes = NewAES();
aes->setKey(SD_KEY);
aes->encrypt(iv, file->data(), data, roundedSize);
base::writeBytes((atInt8*)data, roundedSize);
ret += roundedSize;

467
src/aes.c
View File

@ -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 <stdio.h>
//#include <stdlib.h>
#include <string.h>
/* 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);
}
}

618
src/aes.cpp Normal file
View File

@ -0,0 +1,618 @@
#include "aes.hpp"
#include <stdio.h>
#include <string.h>
#include <cpuid.h>
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 <wmmintrin.h>
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<len ; i++)
{
data = _mm_loadu_si128(&((__m128i*)inbuf)[i]);
feedback = _mm_xor_si128(data, feedback);
feedback = _mm_xor_si128(feedback, m_ekey[0]);
for (j=1 ; j<10 ; j++)
feedback = _mm_aesenc_si128(feedback, m_ekey[j]);
feedback = _mm_aesenclast_si128(feedback, m_ekey[j]);
_mm_storeu_si128(&((__m128i*)outbuf)[i], feedback);
}
}
void decrypt(const uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, uint64_t len)
{
__m128i data,feedback,last_in;
uint64_t i,j;
if (len%16)
len = len/16+1;
else
len /= 16;
feedback = _mm_loadu_si128((__m128i*)iv);
for (i=0 ; i<len ; i++)
{
last_in=_mm_loadu_si128(&((__m128i*)inbuf)[i]);
data = _mm_xor_si128(last_in, m_dkey[0]);
for (j=1 ; j<10 ; j++)
data = _mm_aesdec_si128(data, m_dkey[j]);
data = _mm_aesdeclast_si128(data, m_dkey[j]);
data = _mm_xor_si128(data, feedback);
_mm_storeu_si128(&((__m128i*)outbuf)[i], data);
feedback = last_in;
}
}
static inline __m128i AES_128_ASSIST (__m128i temp1, __m128i temp2)
{
__m128i temp3;
temp2 = _mm_shuffle_epi32 (temp2 ,0xff);
temp3 = _mm_slli_si128 (temp1, 0x4);
temp1 = _mm_xor_si128 (temp1, temp3);
temp3 = _mm_slli_si128 (temp3, 0x4);
temp1 = _mm_xor_si128 (temp1, temp3);
temp3 = _mm_slli_si128 (temp3, 0x4);
temp1 = _mm_xor_si128 (temp1, temp3);
temp1 = _mm_xor_si128 (temp1, temp2);
return temp1;
}
void setKey(const uint8_t* key)
{
__m128i temp1, temp2;
temp1 = _mm_loadu_si128((__m128i*)key);
m_ekey[0] = temp1;
m_dkey[10] = temp1;
temp2 = _mm_aeskeygenassist_si128(temp1, 0x1);
temp1 = AES_128_ASSIST(temp1, temp2);
m_ekey[1] = temp1;
m_dkey[9] = _mm_aesimc_si128(temp1);
temp2 = _mm_aeskeygenassist_si128(temp1, 0x2);
temp1 = AES_128_ASSIST(temp1, temp2);
m_ekey[2] = temp1;
m_dkey[8] = _mm_aesimc_si128(temp1);
temp2 = _mm_aeskeygenassist_si128(temp1, 0x4);
temp1 = AES_128_ASSIST(temp1, temp2);
m_ekey[3] = temp1;
m_dkey[7] = _mm_aesimc_si128(temp1);
temp2 = _mm_aeskeygenassist_si128(temp1, 0x8);
temp1 = AES_128_ASSIST(temp1, temp2);
m_ekey[4] = temp1;
m_dkey[6] = _mm_aesimc_si128(temp1);
temp2 = _mm_aeskeygenassist_si128(temp1, 0x10);
temp1 = AES_128_ASSIST(temp1, temp2);
m_ekey[5] = temp1;
m_dkey[5] = _mm_aesimc_si128(temp1);
temp2 = _mm_aeskeygenassist_si128(temp1, 0x20);
temp1 = AES_128_ASSIST(temp1, temp2);
m_ekey[6] = temp1;
m_dkey[4] = _mm_aesimc_si128(temp1);
temp2 = _mm_aeskeygenassist_si128(temp1, 0x40);
temp1 = AES_128_ASSIST(temp1, temp2);
m_ekey[7] = temp1;
m_dkey[3] = _mm_aesimc_si128(temp1);
temp2 = _mm_aeskeygenassist_si128(temp1, 0x80);
temp1 = AES_128_ASSIST(temp1, temp2);
m_ekey[8] = temp1;
m_dkey[2] = _mm_aesimc_si128(temp1);
temp2 = _mm_aeskeygenassist_si128(temp1, 0x1b);
temp1 = AES_128_ASSIST(temp1, temp2);
m_ekey[9] = temp1;
m_dkey[1] = _mm_aesimc_si128(temp1);
temp2 = _mm_aeskeygenassist_si128(temp1, 0x36);
temp1 = AES_128_ASSIST(temp1, temp2);
m_ekey[10] = temp1;
m_dkey[0] = temp1;
}
};
#endif
static int HAS_AES_NI = -1;
std::unique_ptr<IAES> 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<IAES>(new NiAES);
else
return std::unique_ptr<IAES>(new SoftwareAES);
#else
return std::unique_ptr<IAES>(new SoftwareAES);
#endif
}
}