diff --git a/CMakeLists.txt b/CMakeLists.txt index a535892e2..84d26fd0a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -216,9 +216,12 @@ add_library(sead OBJECT modules/src/resource/seadSZSDecompressor.cpp include/stream/seadBufferStream.h + include/stream/seadRamStream.h include/stream/seadStream.h include/stream/seadStreamFormat.h include/stream/seadStreamSrc.h + modules/src/stream/seadRamStream.cpp + modules/src/stream/seadStream.cpp include/thread/seadAtomic.h include/thread/seadCriticalSection.h diff --git a/include/stream/seadRamStream.h b/include/stream/seadRamStream.h new file mode 100644 index 000000000..28905eccb --- /dev/null +++ b/include/stream/seadRamStream.h @@ -0,0 +1,48 @@ +#pragma once + +#include "stream/seadStream.h" +#include "stream/seadStreamSrc.h" + +namespace sead +{ +class RamStreamSrc : public StreamSrc +{ +public: + RamStreamSrc(void* buffer, u32 bufferSize); + ~RamStreamSrc() override; + + u32 read(void* data, u32 size) override; + u32 write(const void* data, u32 size) override; + u32 skip(s32 offset) override; + void rewind() override; + bool isEOF() override; + +private: + u8* mBuffer = nullptr; + u32 mBufferSize = 0; + u32 mCurrentPos = 0; +}; + +class RamReadStream : public ReadStream +{ +public: + RamReadStream(const void* buffer, u32 buffer_size, Stream::Modes mode); + RamReadStream(const void* buffer, u32 buffer_size, StreamFormat* format); + ~RamReadStream() override; + +private: + RamStreamSrc mSrc; +}; + +class RamWriteStream : public WriteStream +{ +public: + RamWriteStream(void* buffer, u32 buffer_size, Stream::Modes mode); + RamWriteStream(void* buffer, u32 buffer_size, StreamFormat* format); + ~RamWriteStream() override; + +private: + RamStreamSrc mSrc; +}; + +} // namespace sead diff --git a/include/stream/seadStream.h b/include/stream/seadStream.h index 0a1ada0e7..df69589c0 100644 --- a/include/stream/seadStream.h +++ b/include/stream/seadStream.h @@ -23,8 +23,8 @@ class Stream Stream(StreamSrc* src, StreamFormat* format); virtual ~Stream() = default; - void skip(u32); - void skip(u32, u32); + void skip(u32 bytes); + void skip(u32 blockSize, u32 count); void rewind(); bool isEOF(); @@ -33,66 +33,74 @@ class Stream void setUserFormat(StreamFormat* format); protected: - StreamFormat* mFormat; - StreamSrc* mSrc; - Endian::Types mEndian; + static StreamFormat* BASIC_STREAM_FORMAT[2]; + + void setSrc(StreamSrc* src) { mSrc = src; } + + StreamFormat* mFormat = nullptr; + StreamSrc* mSrc = nullptr; + Endian::Types mEndian = Endian::getHostEndian(); }; class ReadStream : public Stream { public: u8 readU8(); - void readU8(u8&); + void readU8(u8& value); u16 readU16(); - void readU16(u16&); + void readU16(u16& value); u32 readU32(); - void readU32(u32&); + void readU32(u32& value); u64 readU64(); - void readU64(u64&); + void readU64(u64& value); s8 readS8(); - void readS8(s8&); + void readS8(s8& value); s16 readS16(); - void readS16(s16&); + void readS16(s16& value); s32 readS32(); - void readS32(s32&); + void readS32(s32& value); s64 readS64(); - void readS64(s64&); + void readS64(s64& value); f32 readF32(); - void readF32(f32&); - void readBit(void*, u32); - void readString(BufferedSafeString*, u32); - u32 readMemBlock(void*, u32); + void readF32(f32& value); + void readBit(void* data, u32 bits); + void readString(BufferedSafeString* str, u32 size); + u32 readMemBlock(void* buffer, u32 size); private: - f32 readF32BitImpl_(u32, u32); - f64 readF64BitImpl_(u32, u32); + f32 readF32BitImpl_(u32 integerBits, u32 fractionalBits); + f64 readF64BitImpl_(u32 integerBits, u32 fractionalBits); }; class WriteStream : public ReadStream { public: - ~WriteStream() override = default; + ~WriteStream() override + { + if (mSrc) + flush(); + } - void writeU8(u8); - void writeU16(u16); - void writeU32(u32); - void writeU64(u64); - void writeS8(s8); - void writeS16(s16); - void writeS32(s32); - void writeS64(s64); - void writeF32(f32); - void writeBit(const void*, u32); - void writeString(const SafeString&, u32); - void writeMemBlock(const void*, u32); - void writeComment(const SafeString&); - void writeLineComment(const SafeString&); - void writeDecorationText(const SafeString&); + void writeU8(u8 value); + void writeU16(u16 value); + void writeU32(u32 value); + void writeU64(u64 value); + void writeS8(s8 value); + void writeS16(s16 value); + void writeS32(s32 value); + void writeS64(s64 value); + void writeF32(f32 value); + void writeBit(const void* data, u32 bits); + void writeString(const SafeString& str, u32 size); + void writeMemBlock(const void* buffer, u32 size); + void writeComment(const SafeString& comment); + void writeLineComment(const SafeString& comment); + void writeDecorationText(const SafeString& text); void writeNullChar(); void flush(); private: - void writeF32BitImpl_(f32, u32, u32); - void writeF64BitImpl_(f64, u32, u32); + void writeF32BitImpl_(f32 value, u32 integerBits, u32 fractionalBits); + void writeF64BitImpl_(f64 value, u32 integerBits, u32 fractionalBits); }; } // namespace sead diff --git a/include/stream/seadStreamFormat.h b/include/stream/seadStreamFormat.h index 01826df16..3a9fbb348 100644 --- a/include/stream/seadStreamFormat.h +++ b/include/stream/seadStreamFormat.h @@ -41,4 +41,73 @@ class StreamFormat virtual void flush(StreamSrc*) = 0; virtual void rewind(StreamSrc*) = 0; }; + +class BinaryStreamFormat : public StreamFormat +{ +public: + u8 readU8(StreamSrc*, Endian::Types) override; + u16 readU16(StreamSrc*, Endian::Types) override; + u32 readU32(StreamSrc*, Endian::Types) override; + u64 readU64(StreamSrc*, Endian::Types) override; + s8 readS8(StreamSrc*, Endian::Types) override; + s16 readS16(StreamSrc*, Endian::Types) override; + s32 readS32(StreamSrc*, Endian::Types) override; + s64 readS64(StreamSrc*, Endian::Types) override; + f32 readF32(StreamSrc*, Endian::Types) override; + void readBit(StreamSrc*, void*, u32) override; + void readString(StreamSrc*, BufferedSafeString*, u32) override; + u32 readMemBlock(StreamSrc*, void*, u32) override; + void writeU8(StreamSrc*, Endian::Types, u8) override; + void writeU16(StreamSrc*, Endian::Types, u16) override; + void writeU32(StreamSrc*, Endian::Types, u32) override; + void writeU64(StreamSrc*, Endian::Types, u64) override; + void writeS8(StreamSrc*, Endian::Types, s8) override; + void writeS16(StreamSrc*, Endian::Types, s16) override; + void writeS32(StreamSrc*, Endian::Types, s32) override; + void writeS64(StreamSrc*, Endian::Types, s64) override; + void writeF32(StreamSrc*, Endian::Types, f32) override; + void writeBit(StreamSrc*, const void*, u32) override; + void writeString(StreamSrc*, const SafeString&, u32) override; + void writeMemBlock(StreamSrc*, const void*, u32) override; + void writeDecorationText(StreamSrc*, const SafeString&) override; + void writeNullChar(StreamSrc*) override; + void skip(StreamSrc*, u32) override; + void flush(StreamSrc*) override; + void rewind(StreamSrc*) override; +}; + +class TextStreamFormat : public StreamFormat +{ +public: + u8 readU8(StreamSrc*, Endian::Types) override; + u16 readU16(StreamSrc*, Endian::Types) override; + u32 readU32(StreamSrc*, Endian::Types) override; + u64 readU64(StreamSrc*, Endian::Types) override; + s8 readS8(StreamSrc*, Endian::Types) override; + s16 readS16(StreamSrc*, Endian::Types) override; + s32 readS32(StreamSrc*, Endian::Types) override; + s64 readS64(StreamSrc*, Endian::Types) override; + f32 readF32(StreamSrc*, Endian::Types) override; + void readBit(StreamSrc*, void*, u32) override; + void readString(StreamSrc*, BufferedSafeString*, u32) override; + u32 readMemBlock(StreamSrc*, void*, u32) override; + void writeU8(StreamSrc*, Endian::Types, u8) override; + void writeU16(StreamSrc*, Endian::Types, u16) override; + void writeU32(StreamSrc*, Endian::Types, u32) override; + void writeU64(StreamSrc*, Endian::Types, u64) override; + void writeS8(StreamSrc*, Endian::Types, s8) override; + void writeS16(StreamSrc*, Endian::Types, s16) override; + void writeS32(StreamSrc*, Endian::Types, s32) override; + void writeS64(StreamSrc*, Endian::Types, s64) override; + void writeF32(StreamSrc*, Endian::Types, f32) override; + void writeBit(StreamSrc*, const void*, u32) override; + void writeString(StreamSrc*, const SafeString&, u32) override; + void writeMemBlock(StreamSrc*, const void*, u32) override; + void writeDecorationText(StreamSrc*, const SafeString&) override; + void writeNullChar(StreamSrc*) override; + void skip(StreamSrc*, u32) override; + void flush(StreamSrc*) override; + void rewind(StreamSrc*) override; +}; + } // namespace sead diff --git a/include/stream/seadStreamSrc.h b/include/stream/seadStreamSrc.h index 699618fe0..c909f5ac7 100644 --- a/include/stream/seadStreamSrc.h +++ b/include/stream/seadStreamSrc.h @@ -13,5 +13,7 @@ class StreamSrc virtual void rewind() = 0; virtual bool isEOF() = 0; virtual bool flush() { return true; } + + virtual ~StreamSrc() = default; }; } // namespace sead diff --git a/modules/src/stream/seadRamStream.cpp b/modules/src/stream/seadRamStream.cpp new file mode 100644 index 000000000..980cec6da --- /dev/null +++ b/modules/src/stream/seadRamStream.cpp @@ -0,0 +1,101 @@ +#include "stream/seadRamStream.h" + +namespace sead +{ +RamStreamSrc::RamStreamSrc(void* buffer, u32 bufferSize) + : mBuffer(static_cast(buffer)), mBufferSize(bufferSize) +{ +} + +RamStreamSrc::~RamStreamSrc() = default; + +u32 RamStreamSrc::read(void* data, u32 size) +{ + if (mCurrentPos + size > mBufferSize) + { + size = mBufferSize - mCurrentPos; + } + + memcpy(data, mBuffer + mCurrentPos, size); + mCurrentPos += size; + return size; +} + +u32 RamStreamSrc::write(const void* data, u32 size) +{ + if (mCurrentPos + size > mBufferSize) + { + size = mBufferSize - mCurrentPos; + } + + memcpy(mBuffer + mCurrentPos, data, size); + mCurrentPos += size; + return size; +} + +u32 RamStreamSrc::skip(s32 offset) +{ + if (offset > 0 && mCurrentPos + offset > mBufferSize) + { + offset = mBufferSize - mCurrentPos; + } + + if (offset < 0 && mCurrentPos < static_cast(-offset)) + { + offset = -mCurrentPos; + } + + mCurrentPos += offset; + return offset; +} + +void RamStreamSrc::rewind() +{ + mCurrentPos = 0; +} + +bool RamStreamSrc::isEOF() +{ + return mCurrentPos >= mBufferSize; +} + +RamReadStream::RamReadStream(const void* buffer, u32 buffer_size, Stream::Modes mode) + : mSrc(const_cast(buffer), buffer_size) +{ + setSrc(&mSrc); + setMode(mode); +} + +RamReadStream::RamReadStream(const void* buffer, u32 buffer_size, StreamFormat* format) + : mSrc(const_cast(buffer), buffer_size) +{ + setSrc(&mSrc); + setUserFormat(format); +} + +RamReadStream::~RamReadStream() +{ + setSrc(nullptr); +} + +RamWriteStream::RamWriteStream(void* buffer, u32 buffer_size, Stream::Modes mode) + : mSrc(buffer, buffer_size) +{ + setSrc(&mSrc); + setMode(mode); +} + +RamWriteStream::RamWriteStream(void* buffer, u32 buffer_size, StreamFormat* format) + : mSrc(buffer, buffer_size) +{ + setSrc(&mSrc); + setUserFormat(format); +} + +RamWriteStream::~RamWriteStream() +{ + flush(); + setSrc(nullptr); +} + +} // namespace sead diff --git a/modules/src/stream/seadStream.cpp b/modules/src/stream/seadStream.cpp new file mode 100644 index 000000000..79a830e41 --- /dev/null +++ b/modules/src/stream/seadStream.cpp @@ -0,0 +1,288 @@ +#include "stream/seadStream.h" + +#include "stream/seadStreamFormat.h" +#include "stream/seadStreamSrc.h" + +namespace sead +{ +BinaryStreamFormat sBinaryStreamInstance; +TextStreamFormat sTextStreamInstance; + +StreamFormat* Stream::BASIC_STREAM_FORMAT[2]{ + &sBinaryStreamInstance, + &sTextStreamInstance, +}; + +Stream::Stream() = default; + +Stream::Stream(StreamSrc* src, StreamFormat* format) +{ + mSrc = src; + mFormat = format; +} + +void Stream::skip(u32 bytes) +{ + mFormat->skip(mSrc, bytes); +} + +void Stream::skip(u32 blockSize, u32 count) +{ + for (u32 i = 0; i < count; i++) + skip(blockSize); +} + +void Stream::rewind() +{ + mFormat->rewind(mSrc); +} + +bool Stream::isEOF() +{ + return mSrc->isEOF(); +} + +void Stream::setBinaryEndian(Endian::Types endian) +{ + mEndian = endian; +} + +void Stream::setMode(Modes mode) +{ + mFormat = BASIC_STREAM_FORMAT[(u32)mode]; +} + +void Stream::setUserFormat(StreamFormat* format) +{ + mFormat = format; +} + +u8 ReadStream::readU8() +{ + return mFormat->readU8(mSrc, mEndian); +} + +void ReadStream::readU8(u8& value) +{ + value = readU8(); +} + +u16 ReadStream::readU16() +{ + return mFormat->readU16(mSrc, mEndian); +} + +void ReadStream::readU16(u16& value) +{ + value = readU16(); +} + +u32 ReadStream::readU32() +{ + return mFormat->readU32(mSrc, mEndian); +} + +void ReadStream::readU32(u32& value) +{ + value = readU32(); +} + +u64 ReadStream::readU64() +{ + return mFormat->readU64(mSrc, mEndian); +} + +void ReadStream::readU64(u64& value) +{ + value = readU64(); +} + +s8 ReadStream::readS8() +{ + return mFormat->readS8(mSrc, mEndian); +} + +void ReadStream::readS8(s8& value) +{ + value = readS8(); +} + +s16 ReadStream::readS16() +{ + return mFormat->readS16(mSrc, mEndian); +} + +void ReadStream::readS16(s16& value) +{ + value = readS16(); +} + +s32 ReadStream::readS32() +{ + return mFormat->readS32(mSrc, mEndian); +} + +void ReadStream::readS32(s32& value) +{ + value = readS32(); +} + +s64 ReadStream::readS64() +{ + return mFormat->readS64(mSrc, mEndian); +} + +void ReadStream::readS64(s64& value) +{ + value = readS64(); +} + +f32 ReadStream::readF32() +{ + return mFormat->readF32(mSrc, mEndian); +} + +void ReadStream::readF32(f32& value) +{ + value = readF32(); +} + +void ReadStream::readBit(void* data, u32 bits) +{ + mFormat->readBit(mSrc, data, bits); +} + +void ReadStream::readString(BufferedSafeString* str, u32 size) +{ + mFormat->readString(mSrc, str, size); +} + +u32 ReadStream::readMemBlock(void* buffer, u32 size) +{ + return mFormat->readMemBlock(mSrc, buffer, size); +} + +f32 ReadStream::readF32BitImpl_(u32 integerBits, u32 fractionalBits) +{ + u32 rawValue = 0; + readBit(&rawValue, integerBits + fractionalBits); + rawValue = Endian::toHostU32(Endian::cLittle, rawValue); + + return static_cast(rawValue) / (1 << fractionalBits); +} + +f64 ReadStream::readF64BitImpl_(u32 integerBits, u32 fractionalBits) +{ + u64 rawValue = 0; + readBit(&rawValue, integerBits + fractionalBits); + rawValue = Endian::toHostU64(Endian::cLittle, rawValue); + + return static_cast(rawValue) / (1 << fractionalBits); +} + +void WriteStream::writeU8(u8 value) +{ + mFormat->writeU8(mSrc, mEndian, value); +} + +void WriteStream::writeU16(u16 value) +{ + mFormat->writeU16(mSrc, mEndian, value); +} + +void WriteStream::writeU32(u32 value) +{ + mFormat->writeU32(mSrc, mEndian, value); +} + +void WriteStream::writeU64(u64 value) +{ + mFormat->writeU64(mSrc, mEndian, value); +} + +void WriteStream::writeS8(s8 value) +{ + mFormat->writeS8(mSrc, mEndian, value); +} + +void WriteStream::writeS16(s16 value) +{ + mFormat->writeS16(mSrc, mEndian, value); +} + +void WriteStream::writeS32(s32 value) +{ + mFormat->writeS32(mSrc, mEndian, value); +} + +void WriteStream::writeS64(s64 value) +{ + mFormat->writeS64(mSrc, mEndian, value); +} + +void WriteStream::writeF32(f32 value) +{ + mFormat->writeF32(mSrc, mEndian, value); +} + +void WriteStream::writeBit(const void* data, u32 bits) +{ + mFormat->writeBit(mSrc, data, bits); +} + +void WriteStream::writeString(const SafeString& str, u32 size) +{ + mFormat->writeString(mSrc, str, size); +} + +void WriteStream::writeMemBlock(const void* buffer, u32 size) +{ + mFormat->writeMemBlock(mSrc, buffer, size); +} + +void WriteStream::writeComment(const SafeString& comment) +{ + mFormat->writeDecorationText(mSrc, "/* "); + mFormat->writeDecorationText(mSrc, comment); + mFormat->writeDecorationText(mSrc, " */"); +} + +void WriteStream::writeLineComment(const SafeString& comment) +{ + mFormat->writeDecorationText(mSrc, "// "); + mFormat->writeDecorationText(mSrc, comment); + mFormat->writeDecorationText(mSrc, "\n"); +} + +void WriteStream::writeDecorationText(const SafeString& text) +{ + mFormat->writeDecorationText(mSrc, text); +} + +void WriteStream::writeNullChar() +{ + mFormat->writeNullChar(mSrc); +} + +void WriteStream::flush() +{ + mFormat->flush(mSrc); + mSrc->flush(); +} + +void WriteStream::writeF32BitImpl_(f32 value, u32 integerBits, u32 fractionalBits) +{ + u32 rawValue = static_cast(value * (1 << fractionalBits) + 0.5f); + rawValue = Endian::fromHostU32(Endian::Types::cLittle, rawValue); + + writeBit(&rawValue, integerBits + fractionalBits); +} + +void WriteStream::writeF64BitImpl_(f64 value, u32 integerBits, u32 fractionalBits) +{ + u64 rawValue = static_cast(value * (1 << fractionalBits) + 0.5f); + rawValue = Endian::fromHostU64(Endian::Types::cLittle, rawValue); + + writeBit(&rawValue, integerBits + fractionalBits); +} +} // namespace sead