Adding read file code
This commit is contained in:
@@ -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>();
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user