Adding read file code

This commit is contained in:
2025-03-07 23:04:30 -05:00
parent 5fd3fc75eb
commit f9f292b6d6
6 changed files with 240 additions and 14 deletions

View File

@@ -32,7 +32,12 @@ consteval Type MaxValueOf()
{
return std::numeric_limits<Type>::max();
}
constexpr uint32 uint8Max = MaxValueOf<uint8>();
constexpr uint32 uint16Max = MaxValueOf<uint16>();
constexpr uint8 uint8Max = MaxValueOf<uint8>();
constexpr uint16 uint16Max = MaxValueOf<uint16>();
constexpr uint32 uint32Max = MaxValueOf<uint32>();
constexpr uint32 uint64Max = MaxValueOf<uint64>();
constexpr uint64 uint64Max = MaxValueOf<uint64>();
constexpr int8 int8Max = MaxValueOf<int8>();
constexpr int16 int16Max = MaxValueOf<int16>();
constexpr int32 int32Max = MaxValueOf<int32>();
constexpr int64 int64Max = MaxValueOf<int64>();

View File

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

View File

@@ -41,8 +41,7 @@ namespace Juliet
int64 (*Seek)(NonNullPtr<IOStreamDataPayload> data, int64 offset, IOStreamSeekPivot pivot);
size_t (*Read)(NonNullPtr<IOStreamDataPayload> data, void* outBuffer, size_t size, NonNullPtr<IOStreamStatus> status);
size_t (*Write)(NonNullPtr<IOStreamDataPayload> data, const void* inBuffer, size_t size,
NonNullPtr<IOStreamStatus> status);
size_t (*Write)(NonNullPtr<IOStreamDataPayload> data, const void* inBuffer, size_t size, NonNullPtr<IOStreamStatus> status);
bool (*Flush)(NonNullPtr<IOStreamDataPayload> data, NonNullPtr<IOStreamStatus> status);
bool (*Close)(NonNullPtr<IOStreamDataPayload> data);
@@ -57,4 +56,14 @@ namespace Juliet
extern JULIET_API size_t IOPrintf(NonNullPtr<IOStream> stream, _Printf_format_string_ const char* format, ...);
extern JULIET_API size_t IOWrite(NonNullPtr<IOStream> stream, const void* ptr, size_t size);
extern JULIET_API size_t IORead(NonNullPtr<IOStream> stream, void* ptr, size_t size);
extern JULIET_API int64 IOSeek(NonNullPtr<IOStream> stream, int64 offset, IOStreamSeekPivot pivot);
extern JULIET_API int64 IOSize(NonNullPtr<IOStream> stream);
// TODO : Use memory arena because that Allocates
extern JULIET_API uint8* LoadFile(String filename, size_t& outByteRead);
extern JULIET_API uint8* LoadFile(NonNullPtr<IOStream> stream, size_t& outByteRead, bool closeStreamWhenDone);
extern JULIET_API bool IOClose(NonNullPtr<IOStream> stream);
} // namespace Juliet

View File

@@ -4,6 +4,7 @@
#include <Core/HAL/IO/IOStream.h>
#include <Core/HAL/IO/IOStream_Private.h>
#include <Core/Memory/Allocator.h>
#include <Core/Thread/Thread.h>
#include <cstdarg>
namespace Juliet
@@ -79,4 +80,146 @@ namespace Juliet
}
return writtenBytes;
}
size_t IORead(NonNullPtr<IOStream> 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<IOStream> 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<IOStream> 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<IOStream> 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<uint8*>(Malloc(static_cast<size_t>(size + 1)));
if (!data)
{
goto done;
}
while (true)
{
if (loadChunks)
{
if ((totalSize + kFileChunkSize) > size)
{
size = static_cast<int64>(totalSize + kFileChunkSize);
newData = static_cast<uint8*>(Realloc(data, static_cast<size_t>(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<IOStream> stream)
{
bool result = true;
if (stream->Interface.Close)
{
result = stream->Interface.Close(stream->Data);
}
Free(stream.Get());
return result;
}
} // namespace Juliet

View File

@@ -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<IOStreamDataPayload> payload, const void* inBuffer, size_t size,
NonNullPtr<IOStreamStatus> status)
size_t FileRead(NonNullPtr<IOStreamDataPayload> payload, void* outBuffer, size_t size, NonNullPtr<IOStreamStatus> status)
{
auto win32Payload = static_cast<Win32IOStreamDataPayload*>(payload.Get());
size_t totalNeed = size;
size_t totalRead = 0;
size_t sizeToReadAhead = 0;
if (win32Payload->SizeLeft > 0)
{
uint8* data = static_cast<uint8*>(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<uint8*>(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<size_t>(bytes));
MemCopy(outBuffer, win32Payload->Data, sizeToReadAhead);
win32Payload->Size = bytes;
win32Payload->SizeLeft = bytes - sizeToReadAhead;
totalRead += sizeToReadAhead;
}
else
{
if (!ReadFile(win32Payload->Handle, outBuffer, static_cast<DWORD>(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<IOStreamDataPayload> payload, const void* inBuffer, size_t size, NonNullPtr<IOStreamStatus> status)
{
auto win32Payload = static_cast<Win32IOStreamDataPayload*>(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;

View File

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