// This file is part of libZelda. // // libZelda is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // libZelda is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with libZelda. If not, see #include "BinaryWriter.hpp" #include "IOException.hpp" #include "InvalidOperationException.hpp" #include "FileNotFoundException.hpp" #include "utility.hpp" #include "utf8.h" #include #include #include #include #ifdef HW_RVL #include #endif // HW_RVL namespace zelda { namespace io { BinaryWriter::BinaryWriter(const Uint8* data, Uint64 length) : Stream(data, length) {} BinaryWriter::BinaryWriter(const Stream& stream) : Stream(stream) {} BinaryWriter::BinaryWriter(const std::string& filename) : m_filepath(filename) { m_length = 0x10; m_bitPosition = 0; m_position = 0; #ifdef HW_RVL m_data = (Uint8*)memalign(32, m_length); #else m_data = new Uint8[m_length]; #endif if (!m_data) throw error::IOException("BinaryWriter::BinaryWriter -> Could not allocate memory!"); memset(m_data, 0, m_length); } void BinaryWriter::setFilepath(const std::string& filepath) { m_filepath = filepath; } std::string BinaryWriter::filepath() const { return m_filepath; } void BinaryWriter::save(const std::string& filename) { if (filename.empty() && m_filepath.empty()) throw error::InvalidOperationException("BinaryWriter::save -> No file specified, cannot save."); if (!filename.empty()) m_filepath = filename; FILE* out = fopen(m_filepath.c_str(), "wb"); if (!out) throw error::FileNotFoundException(m_filepath); Uint32 done = 0; Uint32 blocksize = BLOCKSZ; do { if (blocksize > m_length - done) blocksize = m_length - done; Int32 ret = fwrite(m_data + done, 1, blocksize, out); if (ret < 0) throw error::IOException("BinaryWriter::save Error writing data to disk"); else if (ret == 0) break; done += blocksize; }while (done < m_length); fclose(out); } Int8 BinaryWriter::readByte() { throw error::IOException("BinaryWriter::readByte -> Stream not open for reading"); } Int8* BinaryWriter::readBytes(Int64) { throw error::IOException("BinaryWriter::readBytes -> Stream not open for reading"); } void BinaryWriter::writeInt16(Int16 val) { if (m_bitPosition > 0) { m_bitPosition = 0; m_position += sizeof(Uint8); } if (m_position + sizeof(Int16) > m_length && m_autoResize) resize(m_position + sizeof(Int16)); else if (m_position > m_length) throw error::IOException("BinaryWriter::WriteInt16 -> Position outside stream bounds"); if ((!utility::isSystemBigEndian() && m_endian == BigEndian) || (utility::isSystemBigEndian() && m_endian == LittleEndian)) val = utility::swap16(val); *(Int16*)(m_data + m_position) = val; m_position += sizeof(Int16); } void BinaryWriter::writeUInt16(Uint16 val) { if (m_bitPosition > 0) { m_bitPosition = 0; m_position += sizeof(Uint8); } if (m_position + sizeof(Uint16) > m_length && m_autoResize) resize(m_position + sizeof(Uint16)); else if (m_position > m_length) throw error::IOException("BinaryWriter::WriteUInt16 -> Position outside stream bounds"); if ((!utility::isSystemBigEndian() && m_endian == BigEndian) || (utility::isSystemBigEndian() && m_endian == LittleEndian)) val = utility::swapU16(val); *(Uint16*)(m_data + m_position) = val; m_position += sizeof(Uint16); } void BinaryWriter::writeInt32(Int32 val) { if (m_bitPosition > 0) { m_bitPosition = 0; m_position += sizeof(Uint8); } if (m_position + sizeof(Int32) > m_length && m_autoResize) resize(m_position + sizeof(Int32)); else if (m_position > m_length) throw error::IOException("BinaryWriter::WriteInt32 -> Position outside stream bounds"); if ((!utility::isSystemBigEndian() && m_endian == BigEndian) || (utility::isSystemBigEndian() && m_endian == LittleEndian)) val = utility::swap32(val); *(Int32*)(m_data + m_position) = val; m_position += sizeof(Int32); } void BinaryWriter::writeUInt32(Uint32 val) { if (m_bitPosition > 0) { m_bitPosition = 0; m_position += sizeof(Uint8); } if (m_position + sizeof(Uint32) > m_length && m_autoResize) resize(m_position + sizeof(Uint32)); else if (m_position > m_length) throw error::IOException("BinaryWriter::WriteUInt32 -> Position outside stream bounds"); if ((!utility::isSystemBigEndian() && m_endian == BigEndian) || (utility::isSystemBigEndian() && m_endian == LittleEndian)) val = utility::swapU32(val); *(Uint32*)(m_data + m_position) = val; m_position += sizeof(Uint32); } void BinaryWriter::writeInt64(Int64 val) { if (m_bitPosition > 0) { m_bitPosition = 0; m_position += sizeof(Uint8); } if (m_position + sizeof(Int64) > m_length && m_autoResize) resize(m_position + sizeof(Int64)); else if (m_position > m_length) throw error::IOException("BinaryWriter::WriteInt64 -> Position outside stream bounds"); if ((!utility::isSystemBigEndian() && m_endian == BigEndian) || (utility::isSystemBigEndian() && m_endian == LittleEndian)) val = utility::swap64(val); *(Int64*)(m_data + m_position) = val; m_position += sizeof(Int64); } void BinaryWriter::writeUInt64(Uint64 val) { if (m_bitPosition > 0) { m_bitPosition = 0; m_position += sizeof(Uint8); } if (m_position + sizeof(Uint64) > m_length && m_autoResize) resize(m_position + sizeof(Uint64)); else if (m_position > m_length) throw error::IOException("BinaryWriter::WriteUInt64 -> Position outside stream bounds"); if ((!utility::isSystemBigEndian() && m_endian == BigEndian) || (utility::isSystemBigEndian() && m_endian == LittleEndian)) val = utility::swapU64(val); *(Uint64*)(m_data + m_position) = val; m_position += sizeof(Uint64); } void BinaryWriter::writeFloat(float val) { if (m_bitPosition > 0) { m_bitPosition = 0; m_position += sizeof(Uint8); } if (m_position + sizeof(float) > m_length && m_autoResize) resize(m_position + sizeof(float)); else if (m_position > m_length) throw error::IOException("BinaryWriter::WriteFloat -> Position outside stream bounds"); if ((!utility::isSystemBigEndian() && m_endian == BigEndian) || (utility::isSystemBigEndian() && m_endian == LittleEndian)) val = utility::swapFloat(val); *(float*)(m_data + m_position) = val; m_position += sizeof(float); } void BinaryWriter::writeDouble(double val) { if (m_bitPosition > 0) { m_bitPosition = 0; m_position += sizeof(Uint8); } if (m_position + sizeof(double) > m_length && m_autoResize) resize(m_position + sizeof(double)); else if (m_position > m_length) throw error::IOException("BinaryWriter::WriteDouble -> Position outside stream bounds"); if ((!utility::isSystemBigEndian() && m_endian == BigEndian) || (utility::isSystemBigEndian() && m_endian == LittleEndian)) val = utility::swapDouble(val); *(double*)(m_data + m_position)= val; m_position += sizeof(double); } void BinaryWriter::writeBool(bool val) { if (m_bitPosition > 0) { m_bitPosition = 0; m_position += sizeof(Uint8); } if (m_position + sizeof(bool) > m_length && m_autoResize) resize(m_position + sizeof(bool)); else if (m_position > m_length) throw error::IOException("BinaryWriter::WriteBool -> Position outside stream bounds"); *(bool*)(m_data + m_position) = val; m_position += sizeof(bool); } void BinaryWriter::writeUnicode(const std::string& str) { std::string tmpStr = "\xEF\xBB\xBF" + str; std::vector tmp; utf8::utf8to16(tmpStr.begin(), tmpStr.end(), back_inserter(tmp)); for (Uint16 chr : tmp) { if (chr != 0xFEFF) writeInt16(chr); } } void BinaryWriter::writeString(const std::string& str) { for (Uint8 c : str) { if (c != '\0') writeUByte(c); } writeUByte(0); } bool BinaryWriter::isOpenForReading() { return false; } } // io } // zelda