diff --git a/CMakeLists.txt b/CMakeLists.txt index 59f52697..edbe2783 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,13 +66,11 @@ add_library(sead OBJECT include/filedevice/seadArchiveFileDevice.h include/filedevice/seadFileDevice.h include/filedevice/seadFileDeviceMgr.h - include/filedevice/seadFileDeviceStreamSrc.h include/filedevice/seadMainFileDevice.h include/filedevice/seadPath.h modules/src/filedevice/seadArchiveFileDevice.cpp modules/src/filedevice/seadFileDevice.cpp modules/src/filedevice/seadFileDeviceMgr.cpp - modules/src/filedevice/seadFileDeviceStreamSrc.cpp modules/src/filedevice/seadMainFileDevice.cpp modules/src/filedevice/seadPath.cpp @@ -218,10 +216,13 @@ add_library(sead OBJECT modules/src/resource/seadSZSDecompressor.cpp include/stream/seadBufferStream.h + include/stream/seadFileDeviceStream.h include/stream/seadRamStream.h include/stream/seadStream.h include/stream/seadStreamFormat.h include/stream/seadStreamSrc.h + modules/src/stream/seadBufferStream.cpp + modules/src/stream/seadFileDeviceStream.cpp modules/src/stream/seadRamStream.cpp modules/src/stream/seadStream.cpp modules/src/stream/seadStreamFormat.cpp diff --git a/include/prim/seadPtrUtil.h b/include/prim/seadPtrUtil.h index 95ab58a7..2c43c34d 100644 --- a/include/prim/seadPtrUtil.h +++ b/include/prim/seadPtrUtil.h @@ -34,6 +34,12 @@ class PtrUtil return reinterpret_cast(result); } + static void* align(const void* ptr, u64 n) + { + const uintptr_t result = (uintptr_t(ptr) + n - 1) & ~(n - 1); + return reinterpret_cast(result); + } + static void* addOffset(const void* ptr, intptr_t offset) { return reinterpret_cast(uintptr_t(ptr) + offset); diff --git a/include/resource/seadResource.h b/include/resource/seadResource.h index 2493cebe..fc2e4e02 100644 --- a/include/resource/seadResource.h +++ b/include/resource/seadResource.h @@ -12,6 +12,8 @@ namespace sead { +class ReadStream; + class Resource { public: @@ -30,10 +32,6 @@ class DirectResource : public Resource ~DirectResource() override; virtual s32 getLoadDataAlignment() const { return 4; } - virtual void doCreate_([[maybe_unused]] u8* buffer, [[maybe_unused]] u32 bufferSize, - [[maybe_unused]] Heap* heap) - { - } void create(u8* buffer, u32 bufferSize, u32 allocSize, bool allocated, Heap* heap); @@ -44,12 +42,32 @@ class DirectResource : public Resource static constexpr size_t cLoadDataAlignment = 4; protected: + virtual void doCreate_([[maybe_unused]] u8* buffer, [[maybe_unused]] u32 bufferSize, + [[maybe_unused]] Heap* heap) + { + } u8* mRawData = 0; u32 mRawSize = 0; u32 mBufferSize = 0; BitFlag32 mSettingFlag; }; +class IndirectResource : public Resource +{ + SEAD_RTTI_OVERRIDE(IndirectResource, Resource) + +public: + IndirectResource(); + + void create(sead::ReadStream* stream, u32 size, sead::Heap* heap); + +protected: + virtual void doCreate_([[maybe_unused]] ReadStream* stream, [[maybe_unused]] u32 size, + [[maybe_unused]] Heap* heap) + { + } +}; + class ResourceFactory : public TListNode, public IDisposer { SEAD_RTTI_BASE(ResourceFactory) @@ -100,6 +118,21 @@ class DirectResourceFactory : public DirectResourceFactoryBase } }; +class IndirectResourceFactoryBase : public ResourceFactory +{ + SEAD_RTTI_OVERRIDE(IndirectResourceFactoryBase, ResourceFactory) +public: + IndirectResourceFactoryBase() : ResourceFactory() {} + + ~IndirectResourceFactoryBase() override {} + + Resource* create(const ResourceMgr::CreateArg& createArg) override; + Resource* tryCreate(const ResourceMgr::LoadArg& loadArg) override; + Resource* tryCreateWithDecomp(const ResourceMgr::LoadArg& loadArg, + Decompressor* decompressor) override; + virtual IndirectResource* newResource_(Heap* heap, s32 alignment) = 0; +}; + } // namespace sead #endif // SEAD_RESOURCE_H_ diff --git a/include/stream/seadBufferStream.h b/include/stream/seadBufferStream.h index 72019d47..c99404c4 100644 --- a/include/stream/seadBufferStream.h +++ b/include/stream/seadBufferStream.h @@ -16,14 +16,13 @@ class BufferReadStreamSrc : public StreamSrc u32 skip(s32 offset) override; void rewind() override; bool isEOF() override; - bool flush() override; private: StreamSrc* mSrc; - u8* mBuffer; + void* mBuffer; u32 mBufferSize; - u32 mCurrentSize; - u32 mCurrentPos; + u32 mCurrentSize = 0; + u32 mCurrentPos = 0; }; class BufferReadStream : public ReadStream @@ -46,14 +45,14 @@ class BufferWriteStreamSrc : public StreamSrc u32 write(const void* data, u32 size) override; u32 skip(s32 offset) override; void rewind() override; - bool isEOF() override { return false; } + bool isEOF() override { return mSrc->isEOF(); } bool flush() override; private: StreamSrc* mSrc; - u8* mBuffer; - u32 mBufferSize; - u32 mCurrentPos; + void* mBuffer; + u32 mBufferSize = 0; + u32 mCurrentPos = 0; }; class BufferWriteStream : public WriteStream diff --git a/include/filedevice/seadFileDeviceStreamSrc.h b/include/stream/seadFileDeviceStream.h similarity index 61% rename from include/filedevice/seadFileDeviceStreamSrc.h rename to include/stream/seadFileDeviceStream.h index 0557796b..7350ebf1 100644 --- a/include/filedevice/seadFileDeviceStreamSrc.h +++ b/include/stream/seadFileDeviceStream.h @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -34,6 +35,7 @@ class FileDeviceStreamSrc : public StreamSrc class FileDeviceWriteStream : public WriteStream { +public: FileDeviceWriteStream(Stream::Modes mode); FileDeviceWriteStream(StreamFormat* format); FileDeviceWriteStream(FileHandle* fileHandle, Stream::Modes mode); @@ -42,12 +44,15 @@ class FileDeviceWriteStream : public WriteStream void setFileHandle(sead::FileHandle* fileHandle); + FileDeviceStreamSrc* getSrc() { return &src; } + private: FileDeviceStreamSrc src; }; class FileDeviceReadStream : public ReadStream { +public: FileDeviceReadStream(Stream::Modes mode); FileDeviceReadStream(StreamFormat* format); FileDeviceReadStream(FileHandle* fileHandle, Stream::Modes mode); @@ -56,8 +61,35 @@ class FileDeviceReadStream : public ReadStream void setFileHandle(sead::FileHandle* fileHandle); + FileDeviceStreamSrc* getSrc() { return &src; } + private: FileDeviceStreamSrc src; }; +class BufferFileDeviceWriteStream : public FileDeviceWriteStream +{ +public: + BufferFileDeviceWriteStream(Stream::Modes mode); + BufferFileDeviceWriteStream(StreamFormat* format); + BufferFileDeviceWriteStream(FileHandle* fileHandle, Stream::Modes mode); + BufferFileDeviceWriteStream(FileHandle* fileHandle, StreamFormat* format); + +private: + BufferWriteStreamSrc mBufferSrc; + u8 mBuffer[0x120]; // NOTE: 0x100 + 0x20 bytes for alignment +}; + +class BufferFileDeviceReadStream : public FileDeviceReadStream +{ +public: + BufferFileDeviceReadStream(Stream::Modes mode); + BufferFileDeviceReadStream(StreamFormat* format); + BufferFileDeviceReadStream(FileHandle* fileHandle, Stream::Modes mode); + BufferFileDeviceReadStream(FileHandle* fileHandle, StreamFormat* format); + +private: + BufferReadStreamSrc mBufferSrc; + u8 mBuffer[0x120]; // NOTE: 0x100 + 0x20 bytes for alignment +}; } // namespace sead diff --git a/include/stream/seadStream.h b/include/stream/seadStream.h index df69589c..d3391c7b 100644 --- a/include/stream/seadStream.h +++ b/include/stream/seadStream.h @@ -32,6 +32,10 @@ class Stream void setMode(Modes mode); void setUserFormat(StreamFormat* format); + Endian::Types getBinaryEndian() const { return mEndian; } + StreamFormat* getUserFormat() const { return mFormat; } + StreamSrc* getSrc() const { return mSrc; } + protected: static StreamFormat* BASIC_STREAM_FORMAT[2]; diff --git a/modules/src/resource/seadResource.cpp b/modules/src/resource/seadResource.cpp index 3c9a246e..29806131 100644 --- a/modules/src/resource/seadResource.cpp +++ b/modules/src/resource/seadResource.cpp @@ -1,7 +1,10 @@ +#include + #include #include #include -#include +#include +#include namespace sead { @@ -34,6 +37,13 @@ void DirectResource::create(u8* buffer, u32 bufferSize, u32 allocSize, bool allo doCreate_(buffer, bufferSize, heap); } +IndirectResource::IndirectResource() = default; + +void IndirectResource::create(sead::ReadStream* stream, u32 size, sead::Heap* heap) +{ + doCreate_(stream, size, heap); +} + ResourceFactory::~ResourceFactory() { auto* mgr = ResourceMgr::instance(); @@ -90,15 +100,15 @@ Resource* DirectResourceFactoryBase::tryCreate(const ResourceMgr::LoadArg& loadA fileLoadArg.alignment = Mathi::sign(loadArg.instance_alignment) * resource->getLoadDataAlignment(); - if (loadArg.device != NULL) + if (loadArg.device != nullptr) data = loadArg.device->tryLoad(fileLoadArg); else data = FileDeviceMgr::instance()->tryLoad(fileLoadArg); - if (data == NULL) + if (data == nullptr) { delete resource; - return NULL; + return nullptr; } resource->create(data, fileLoadArg.read_size, fileLoadArg.roundup_size, fileLoadArg.need_unload, @@ -110,8 +120,8 @@ Resource* DirectResourceFactoryBase::tryCreateWithDecomp(const ResourceMgr::Load Decompressor* decompressor) { DirectResource* resource = newResource_(loadArg.instance_heap, loadArg.instance_alignment); - if (resource == NULL) - return NULL; + if (resource == nullptr) + return nullptr; u32 outSize = 0; u32 outAllocSize = 0; @@ -130,4 +140,76 @@ Resource* DirectResourceFactoryBase::tryCreateWithDecomp(const ResourceMgr::Load return resource; } +Resource* IndirectResourceFactoryBase::create(const ResourceMgr::CreateArg& createArg) +{ + IndirectResource* resource = newResource_(createArg.heap, createArg.alignment); + if (resource == nullptr) + return nullptr; + + RamReadStream stream(createArg.buffer, createArg.file_size, Stream::Modes::Binary); + resource->create(&stream, createArg.file_size, createArg.heap); + + return resource; +} + +Resource* IndirectResourceFactoryBase::tryCreate(const ResourceMgr::LoadArg& loadArg) +{ + IndirectResource* resource = newResource_(loadArg.instance_heap, loadArg.instance_alignment); + if (resource == nullptr) + return nullptr; + + FileHandle handle; + + bool isOpen; + if (loadArg.device) + isOpen = + loadArg.device->tryOpen(&handle, loadArg.path, FileDevice::cFileOpenFlag_ReadOnly, 0); + else + isOpen = FileDeviceMgr::instance()->tryOpen(&handle, loadArg.path, + FileDevice::cFileOpenFlag_ReadOnly, 0); + if (!isOpen) + { + delete resource; + return nullptr; + } + + BufferFileDeviceReadStream stream(&handle, Stream::Modes::Binary); + resource->create(&stream, handle.getFileSize(), loadArg.instance_heap); + + if (!handle.tryClose()) + { + delete resource; + return nullptr; + } + + return resource; +} + +Resource* IndirectResourceFactoryBase::tryCreateWithDecomp(const ResourceMgr::LoadArg& loadArg, + Decompressor* decompressor) +{ + IndirectResource* resource = newResource_(loadArg.instance_heap, loadArg.instance_alignment); + if (resource == nullptr) + return nullptr; + + u32 outSize = 0; + u32 outAllocSize = 0; + bool outAllocated = false; + + u8* data = decompressor->tryDecompFromDevice(loadArg, resource, &outSize, &outAllocSize, + &outAllocated); + + if (!data) + { + delete resource; + return nullptr; + } + + RamReadStream stream(data, outSize, Stream::Modes::Binary); + resource->create(&stream, outSize, loadArg.instance_heap); + delete[] data; + + return resource; +} + } // namespace sead diff --git a/modules/src/stream/seadBufferStream.cpp b/modules/src/stream/seadBufferStream.cpp new file mode 100644 index 00000000..206bfe7a --- /dev/null +++ b/modules/src/stream/seadBufferStream.cpp @@ -0,0 +1,151 @@ +#include "stream/seadBufferStream.h" + +#include "math/seadMathCalcCommon.h" + +namespace sead +{ +BufferReadStreamSrc::BufferReadStreamSrc(StreamSrc* src, void* buffer, u32 buffer_size) + : mSrc(src), mBuffer(buffer), mBufferSize(buffer_size) +{ +} + +BufferReadStreamSrc::~BufferReadStreamSrc() = default; + +// NOTE: cannot take negative `offset`, but expects `mSrc->skip(X)` to work with negatives +u32 BufferReadStreamSrc::read(void* data, u32 size) +{ + u32 totalBytesRead = 0; + while (true) + { + if (mCurrentPos < mCurrentSize) + { + u32 readSize = sead::Mathu::clampMax(size - totalBytesRead, mCurrentSize - mCurrentPos); + + memcpy((u8*)data + totalBytesRead, (u8*)mBuffer + mCurrentPos, readSize); + totalBytesRead += readSize; + mCurrentPos += readSize; + } + + if (size <= totalBytesRead) + break; + + mCurrentSize = mSrc->read(mBuffer, mBufferSize); + mCurrentPos = 0; + + if (mCurrentSize == 0) + break; + } + return totalBytesRead; +} + +u32 BufferReadStreamSrc::write([[maybe_unused]] const void* data, [[maybe_unused]] u32 size) +{ + return 0; +} + +u32 BufferReadStreamSrc::skip(s32 offset) +{ + s32 remainingBytes = mCurrentSize - mCurrentPos; + + if (remainingBytes >= offset) + { + mCurrentPos += offset; + return offset; + } + + mCurrentSize = 0; + mCurrentPos = 0; + return mSrc->skip(offset - remainingBytes) + remainingBytes; +} + +void BufferReadStreamSrc::rewind() +{ + mSrc->rewind(); + mCurrentSize = 0; + mCurrentPos = 0; +} + +bool BufferReadStreamSrc::isEOF() +{ + return mSrc->isEOF() && mCurrentPos >= mCurrentSize; +} + +BufferReadStream::BufferReadStream(ReadStream* stream, const void* buffer, u32 buffer_size) + : mSrc(stream->getSrc(), const_cast(buffer), buffer_size) +{ + setSrc(&mSrc); + setUserFormat(stream->getUserFormat()); + setBinaryEndian(stream->getBinaryEndian()); +} + +BufferReadStream::~BufferReadStream() +{ + setSrc(nullptr); +} + +BufferWriteStreamSrc::BufferWriteStreamSrc(StreamSrc* src, void* buffer, u32 buffer_size) + : mSrc(src), mBuffer(buffer), mBufferSize(buffer_size) +{ +} + +BufferWriteStreamSrc::~BufferWriteStreamSrc() = default; + +u32 BufferWriteStreamSrc::read([[maybe_unused]] void* data, [[maybe_unused]] u32 size) +{ + return 0; +} + +u32 BufferWriteStreamSrc::write(const void* data, u32 size) +{ + u32 totalBytesWritten = 0; + do + { + if (mCurrentPos >= mBufferSize) + continue; + + u32 writeSize = sead::Mathu::min(mBufferSize - mCurrentPos, size - totalBytesWritten); + + memcpy((u8*)mBuffer + mCurrentPos, (u8*)data + totalBytesWritten, writeSize); + totalBytesWritten += writeSize; + mCurrentPos += writeSize; + } while (totalBytesWritten < size && flush()); + + return totalBytesWritten; +} + +u32 BufferWriteStreamSrc::skip([[maybe_unused]] s32 offset) +{ + return 0; +} + +void BufferWriteStreamSrc::rewind() +{ + flush(); + mSrc->rewind(); +} + +bool BufferWriteStreamSrc::flush() +{ + if (mCurrentPos == 0) + return true; + + bool success = mSrc->write(mBuffer, mCurrentPos) >= mCurrentPos; + mCurrentPos = 0; + return success; +} + +BufferWriteStream::BufferWriteStream(WriteStream* stream, void* buffer, u32 buffer_size) + : mSrc(stream->getSrc(), buffer, buffer_size) +{ + setSrc(&mSrc); + setUserFormat(stream->getUserFormat()); + setBinaryEndian(stream->getBinaryEndian()); +} + +BufferWriteStream::~BufferWriteStream() +{ + flush(); + setSrc(nullptr); +} + +} // namespace sead diff --git a/modules/src/filedevice/seadFileDeviceStreamSrc.cpp b/modules/src/stream/seadFileDeviceStream.cpp similarity index 60% rename from modules/src/filedevice/seadFileDeviceStreamSrc.cpp rename to modules/src/stream/seadFileDeviceStream.cpp index 512763eb..3a4b9af8 100644 --- a/modules/src/filedevice/seadFileDeviceStreamSrc.cpp +++ b/modules/src/stream/seadFileDeviceStream.cpp @@ -1,4 +1,4 @@ -#include +#include namespace sead { @@ -133,4 +133,58 @@ void FileDeviceReadStream::setFileHandle(sead::FileHandle* fileHandle) src.setFileHandle(fileHandle); } + +BufferFileDeviceWriteStream::BufferFileDeviceWriteStream(Stream::Modes mode) + : FileDeviceWriteStream(mode), mBufferSrc(getSrc(), PtrUtil::align(mBuffer, 0x20), 0x100) +{ + setSrc(&mBufferSrc); +} + +BufferFileDeviceWriteStream::BufferFileDeviceWriteStream(StreamFormat* format) + : FileDeviceWriteStream(format), mBufferSrc(getSrc(), PtrUtil::align(mBuffer, 0x20), 0x100) +{ + setSrc(&mBufferSrc); +} + +BufferFileDeviceWriteStream::BufferFileDeviceWriteStream(FileHandle* fileHandle, Stream::Modes mode) + : FileDeviceWriteStream(fileHandle, mode), + mBufferSrc(getSrc(), PtrUtil::align(mBuffer, 0x20), 0x100) +{ + setSrc(&mBufferSrc); +} + +BufferFileDeviceWriteStream::BufferFileDeviceWriteStream(FileHandle* fileHandle, + StreamFormat* format) + : FileDeviceWriteStream(fileHandle, format), + mBufferSrc(getSrc(), PtrUtil::align(mBuffer, 0x20), 0x100) +{ + setSrc(&mBufferSrc); +} + +BufferFileDeviceReadStream::BufferFileDeviceReadStream(Stream::Modes mode) + : FileDeviceReadStream(mode), mBufferSrc(getSrc(), PtrUtil::align(mBuffer, 0x20), 0x100) +{ + setSrc(&mBufferSrc); +} + +BufferFileDeviceReadStream::BufferFileDeviceReadStream(StreamFormat* format) + : FileDeviceReadStream(format), mBufferSrc(getSrc(), PtrUtil::align(mBuffer, 0x20), 0x100) +{ + setSrc(&mBufferSrc); +} + +BufferFileDeviceReadStream::BufferFileDeviceReadStream(FileHandle* fileHandle, Stream::Modes mode) + : FileDeviceReadStream(fileHandle, mode), + mBufferSrc(getSrc(), PtrUtil::align(mBuffer, 0x20), 0x100) +{ + setSrc(&mBufferSrc); +} + +BufferFileDeviceReadStream::BufferFileDeviceReadStream(FileHandle* fileHandle, StreamFormat* format) + : FileDeviceReadStream(fileHandle, format), + mBufferSrc(getSrc(), PtrUtil::align(mBuffer, 0x20), 0x100) +{ + setSrc(&mBufferSrc); +} + } // namespace sead