diff --git a/Juliet/include/Core/Common/CoreTypes.h b/Juliet/include/Core/Common/CoreTypes.h index 85d34de..a8e3034 100644 --- a/Juliet/include/Core/Common/CoreTypes.h +++ b/Juliet/include/Core/Common/CoreTypes.h @@ -32,7 +32,12 @@ consteval Type MaxValueOf() { return std::numeric_limits::max(); } -constexpr uint32 uint8Max = MaxValueOf(); -constexpr uint32 uint16Max = MaxValueOf(); +constexpr uint8 uint8Max = MaxValueOf(); +constexpr uint16 uint16Max = MaxValueOf(); constexpr uint32 uint32Max = MaxValueOf(); -constexpr uint32 uint64Max = MaxValueOf(); +constexpr uint64 uint64Max = MaxValueOf(); + +constexpr int8 int8Max = MaxValueOf(); +constexpr int16 int16Max = MaxValueOf(); +constexpr int32 int32Max = MaxValueOf(); +constexpr int64 int64Max = MaxValueOf(); diff --git a/Juliet/include/Core/Common/CoreUtils.h b/Juliet/include/Core/Common/CoreUtils.h index f88dfca..e03efc4 100644 --- a/Juliet/include/Core/Common/CoreUtils.h +++ b/Juliet/include/Core/Common/CoreUtils.h @@ -24,6 +24,8 @@ namespace Juliet extern void JULIET_API JulietAssert(const char* expression); +#define DEFER(cleanup) for (bool done_ = 0; !done_; (cleanup), done_ = 1) + #define ZeroStruct(structInstance) ZeroSize(sizeof(structInstance), &(structInstance)) #define ZeroArray(array) ZeroSize(sizeof((array)), (array)) #define ZeroDynArray(Count, Pointer) ZeroSize((Count) * sizeof((Pointer)[0]), Pointer) diff --git a/Juliet/include/Core/HAL/IO/IOStream.h b/Juliet/include/Core/HAL/IO/IOStream.h index 844702c..a022deb 100644 --- a/Juliet/include/Core/HAL/IO/IOStream.h +++ b/Juliet/include/Core/HAL/IO/IOStream.h @@ -41,8 +41,7 @@ namespace Juliet int64 (*Seek)(NonNullPtr data, int64 offset, IOStreamSeekPivot pivot); size_t (*Read)(NonNullPtr data, void* outBuffer, size_t size, NonNullPtr status); - size_t (*Write)(NonNullPtr data, const void* inBuffer, size_t size, - NonNullPtr status); + size_t (*Write)(NonNullPtr data, const void* inBuffer, size_t size, NonNullPtr status); bool (*Flush)(NonNullPtr data, NonNullPtr status); bool (*Close)(NonNullPtr data); @@ -57,4 +56,14 @@ namespace Juliet extern JULIET_API size_t IOPrintf(NonNullPtr stream, _Printf_format_string_ const char* format, ...); extern JULIET_API size_t IOWrite(NonNullPtr stream, const void* ptr, size_t size); + extern JULIET_API size_t IORead(NonNullPtr stream, void* ptr, size_t size); + extern JULIET_API int64 IOSeek(NonNullPtr stream, int64 offset, IOStreamSeekPivot pivot); + + extern JULIET_API int64 IOSize(NonNullPtr stream); + + // TODO : Use memory arena because that Allocates + extern JULIET_API uint8* LoadFile(String filename, size_t& outByteRead); + extern JULIET_API uint8* LoadFile(NonNullPtr stream, size_t& outByteRead, bool closeStreamWhenDone); + + extern JULIET_API bool IOClose(NonNullPtr stream); } // namespace Juliet diff --git a/Juliet/src/Core/HAL/IO/IOStream.cpp b/Juliet/src/Core/HAL/IO/IOStream.cpp index 3be114b..d48f32f 100644 --- a/Juliet/src/Core/HAL/IO/IOStream.cpp +++ b/Juliet/src/Core/HAL/IO/IOStream.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include namespace Juliet @@ -79,4 +80,146 @@ namespace Juliet } return writtenBytes; } + + size_t IORead(NonNullPtr stream, void* ptr, size_t size) + { + if (!stream->Interface.Read) + { + Log(LogLevel::Error, LogCategory::Core, "Trying to read a writeonly IOStream"); + stream->Status = IOStreamStatus::WriteOnly; + return 0; + } + + stream->Status = IOStreamStatus::Ready; + if (size == 0) + { + return 0; + } + size_t bytes = stream->Interface.Read(stream->Data, ptr, size, &stream->Status); + if (bytes == 0 && stream->Status == IOStreamStatus::Ready) + { + // TODO: Detect error and do this stream->Status = IOStreamStatus::Error; + stream->Status = IOStreamStatus::EndOfFile; + } + return bytes; + } + + int64 IOSeek(NonNullPtr stream, int64 offset, IOStreamSeekPivot pivot) + { + if (!stream->Interface.Seek) + { + Log(LogLevel::Error, LogCategory::Core, "IOSeek: Stream interface cannot Seek"); + return -1; + } + return stream->Interface.Seek(stream->Data, offset, pivot); + } + + int64 IOSize(NonNullPtr stream) + { + if (!stream->Interface.Size) + { + int64 pos = IOSeek(stream, 0, IOStreamSeekPivot::Current); + if (pos < 0) + { + return -1; + } + int64 size = IOSeek(stream, 0, IOStreamSeekPivot::End); + + IOSeek(stream, pos, IOStreamSeekPivot::Begin); + return size; + } + return stream->Interface.Size(stream->Data); + } + + uint8* LoadFile(String filename, size_t& outByteRead) + { + IOStream* stream = IOFromFile(filename, ConstString("rb")); + if (!stream) + { + outByteRead = 0; + return nullptr; + } + return LoadFile(stream, outByteRead, true); + } + + uint8* LoadFile(NonNullPtr stream, size_t& outByteRead, bool closeStreamWhenDone) + { + constexpr size_t kFileChunkSize = 1024; + uint8* data = nullptr; + uint8* newData = nullptr; + size_t totalSize = 0; + + // Try reading the size from the stream, if failing we'll try to read it chunk by chunk + bool loadChunks = false; + int64 size = IOSize(stream); + if (size < 0) + { + size = kFileChunkSize; + loadChunks = true; + } + data = static_cast(Malloc(static_cast(size + 1))); + if (!data) + { + goto done; + } + + while (true) + { + if (loadChunks) + { + if ((totalSize + kFileChunkSize) > size) + { + size = static_cast(totalSize + kFileChunkSize); + newData = static_cast(Realloc(data, static_cast(size + 1))); + if (!newData) + { + Free(data); + data = nullptr; + goto done; + } + data = newData; + } + } + + size_t sizeRead = IORead(stream, data + totalSize, (size - totalSize)); + if (sizeRead > 0) + { + totalSize += sizeRead; + continue; + } + if (stream->Status == IOStreamStatus::NotReady) + { + // Wait for the stream to be ready + wait_ms(1); + continue; + } + + // The stream status will remain set for the caller to check + break; + } + + // Adding null terminator + data[totalSize] = '\0'; + + done: + outByteRead = totalSize; + + if (closeStreamWhenDone) + { + IOClose(stream); + } + return data; + } + + bool IOClose(NonNullPtr stream) + { + bool result = true; + if (stream->Interface.Close) + { + result = stream->Interface.Close(stream->Data); + } + Free(stream.Get()); + return result; + } + } // namespace Juliet diff --git a/Juliet/src/Core/HAL/IO/Win32/Win32IOStream.cpp b/Juliet/src/Core/HAL/IO/Win32/Win32IOStream.cpp index 68895b1..b149be4 100644 --- a/Juliet/src/Core/HAL/IO/Win32/Win32IOStream.cpp +++ b/Juliet/src/Core/HAL/IO/Win32/Win32IOStream.cpp @@ -14,6 +14,7 @@ namespace Juliet::Internal { HANDLE Handle; void* Data; + size_t Size; size_t SizeLeft; bool IsAppending; bool ShouldAutoClose; @@ -66,8 +67,71 @@ namespace Juliet::Internal return windowsOffset.QuadPart; } - size_t FileWrite(NonNullPtr payload, const void* inBuffer, size_t size, - NonNullPtr status) + size_t FileRead(NonNullPtr payload, void* outBuffer, size_t size, NonNullPtr status) + { + auto win32Payload = static_cast(payload.Get()); + size_t totalNeed = size; + size_t totalRead = 0; + size_t sizeToReadAhead = 0; + if (win32Payload->SizeLeft > 0) + { + uint8* data = static_cast(win32Payload->Data) + win32Payload->Size - win32Payload->SizeLeft; + sizeToReadAhead = Min(totalNeed, win32Payload->SizeLeft); + MemCopy(outBuffer, data, sizeToReadAhead); + win32Payload->SizeLeft -= sizeToReadAhead; + + if (sizeToReadAhead == totalNeed) + { + return size; + } + outBuffer = static_cast(outBuffer) + sizeToReadAhead; + totalNeed -= sizeToReadAhead; + totalRead += sizeToReadAhead; + } + + DWORD bytes = 0; + if (totalNeed < kFileReadBufferSize) + { + if (!ReadFile(win32Payload->Handle, win32Payload->Data, kFileReadBufferSize, &bytes, nullptr)) + { + switch (DWORD error = GetLastError()) + { + case ERROR_BROKEN_PIPE: + case ERROR_HANDLE_EOF: break; + case ERROR_NO_DATA: *status = IOStreamStatus::NotReady; break; + default: + Log(LogLevel::Error, LogCategory::Core, "IoStream:Win32 Read: Error reading from data stream: %d", error); + break; + } + return 0; + } + sizeToReadAhead = Min(totalNeed, static_cast(bytes)); + MemCopy(outBuffer, win32Payload->Data, sizeToReadAhead); + win32Payload->Size = bytes; + win32Payload->SizeLeft = bytes - sizeToReadAhead; + totalRead += sizeToReadAhead; + } + else + { + if (!ReadFile(win32Payload->Handle, outBuffer, static_cast(totalNeed), &bytes, nullptr)) + { + switch (DWORD error = GetLastError()) + { + case ERROR_BROKEN_PIPE: + case ERROR_HANDLE_EOF: break; + case ERROR_NO_DATA: *status = IOStreamStatus::NotReady; break; + default: + Log(LogLevel::Error, LogCategory::Core, "IoStream:Win32 Read: Error reading from data stream: %d", error); + break; + } + return 0; + } + totalRead += bytes; + } + return totalRead; + } + + size_t FileWrite(NonNullPtr payload, const void* inBuffer, size_t size, NonNullPtr status) { auto win32Payload = static_cast(payload.Get()); DWORD bytes; @@ -137,17 +201,16 @@ namespace Juliet::Internal // Making sure the mode is valid String modeView = mode; size_t modeLength = StringLength(modeView); - Assert(!ContainsChar(mode, 'b') && "Binary mode note supported"); Assert((modeLength <= 2) && "Mode should have at most 2 characters, one being either r,w or a and the other can only be +"); if (modeLength == 1) { - Assert(modeView.Data[0] == 'r' || modeView.Data[0] == 'w' || - modeView.Data[0] == 'a' && "Invalid Mode. First char is not r,w or a"); + Assert((modeView.Data[0] == 'r' || modeView.Data[0] == 'w' || modeView.Data[0] == 'a') && + "Invalid Mode. First char is not r,w or a"); } else { - Assert(modeView.Data[1] == '+' && "Invalid Mode. Second char is not +"); + Assert((modeView.Data[1] == '+' || modeView.Data[1] == 'b') && "Invalid Mode. Second char is not +"); } #endif @@ -192,6 +255,7 @@ namespace Juliet::Internal interface.Size = FileSize; interface.Seek = FileSeek; } + interface.Read = FileRead; interface.Write = FileWrite; interface.Close = FileClose; diff --git a/JulietShaderCompiler/main.cpp b/JulietShaderCompiler/main.cpp index 3ca9569..b6b4885 100644 --- a/JulietShaderCompiler/main.cpp +++ b/JulietShaderCompiler/main.cpp @@ -44,10 +44,13 @@ void Compile() int main(int argc, char* argv[]) { - auto* stream = IOFromFile(ConstString("XF"), ConstString("w")); + // auto* stream = IOFromFile(ConstString("XF"), ConstString("w")); + // + // IOPrintf(stream, ":)"); + // IOPrintf(stream, "%d%s", 1234, "Hello World!"); - IOPrintf(stream, ":)"); - IOPrintf(stream, "%d%s", 1234, "Hello World!"); + size_t bytesRead = 0; + auto* data = LoadFile(ConstString("XF"),bytesRead ); return 0; }