Adding read file code
This commit is contained in:
@@ -32,7 +32,12 @@ consteval Type MaxValueOf()
|
|||||||
{
|
{
|
||||||
return std::numeric_limits<Type>::max();
|
return std::numeric_limits<Type>::max();
|
||||||
}
|
}
|
||||||
constexpr uint32 uint8Max = MaxValueOf<uint8>();
|
constexpr uint8 uint8Max = MaxValueOf<uint8>();
|
||||||
constexpr uint32 uint16Max = MaxValueOf<uint16>();
|
constexpr uint16 uint16Max = MaxValueOf<uint16>();
|
||||||
constexpr uint32 uint32Max = MaxValueOf<uint32>();
|
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);
|
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 ZeroStruct(structInstance) ZeroSize(sizeof(structInstance), &(structInstance))
|
||||||
#define ZeroArray(array) ZeroSize(sizeof((array)), (array))
|
#define ZeroArray(array) ZeroSize(sizeof((array)), (array))
|
||||||
#define ZeroDynArray(Count, Pointer) ZeroSize((Count) * sizeof((Pointer)[0]), Pointer)
|
#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);
|
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 (*Read)(NonNullPtr<IOStreamDataPayload> data, void* outBuffer, size_t size, NonNullPtr<IOStreamStatus> status);
|
||||||
size_t (*Write)(NonNullPtr<IOStreamDataPayload> data, const void* inBuffer, size_t size,
|
size_t (*Write)(NonNullPtr<IOStreamDataPayload> data, const void* inBuffer, size_t size, NonNullPtr<IOStreamStatus> status);
|
||||||
NonNullPtr<IOStreamStatus> status);
|
|
||||||
bool (*Flush)(NonNullPtr<IOStreamDataPayload> data, NonNullPtr<IOStreamStatus> status);
|
bool (*Flush)(NonNullPtr<IOStreamDataPayload> data, NonNullPtr<IOStreamStatus> status);
|
||||||
|
|
||||||
bool (*Close)(NonNullPtr<IOStreamDataPayload> data);
|
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 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 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
|
} // namespace Juliet
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <Core/HAL/IO/IOStream.h>
|
#include <Core/HAL/IO/IOStream.h>
|
||||||
#include <Core/HAL/IO/IOStream_Private.h>
|
#include <Core/HAL/IO/IOStream_Private.h>
|
||||||
#include <Core/Memory/Allocator.h>
|
#include <Core/Memory/Allocator.h>
|
||||||
|
#include <Core/Thread/Thread.h>
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
|
|
||||||
namespace Juliet
|
namespace Juliet
|
||||||
@@ -79,4 +80,146 @@ namespace Juliet
|
|||||||
}
|
}
|
||||||
return writtenBytes;
|
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
|
} // namespace Juliet
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ namespace Juliet::Internal
|
|||||||
{
|
{
|
||||||
HANDLE Handle;
|
HANDLE Handle;
|
||||||
void* Data;
|
void* Data;
|
||||||
|
size_t Size;
|
||||||
size_t SizeLeft;
|
size_t SizeLeft;
|
||||||
bool IsAppending;
|
bool IsAppending;
|
||||||
bool ShouldAutoClose;
|
bool ShouldAutoClose;
|
||||||
@@ -66,8 +67,71 @@ namespace Juliet::Internal
|
|||||||
return windowsOffset.QuadPart;
|
return windowsOffset.QuadPart;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t FileWrite(NonNullPtr<IOStreamDataPayload> payload, const void* inBuffer, size_t size,
|
size_t FileRead(NonNullPtr<IOStreamDataPayload> payload, void* outBuffer, size_t size, NonNullPtr<IOStreamStatus> status)
|
||||||
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());
|
auto win32Payload = static_cast<Win32IOStreamDataPayload*>(payload.Get());
|
||||||
DWORD bytes;
|
DWORD bytes;
|
||||||
@@ -137,17 +201,16 @@ namespace Juliet::Internal
|
|||||||
// Making sure the mode is valid
|
// Making sure the mode is valid
|
||||||
String modeView = mode;
|
String modeView = mode;
|
||||||
size_t modeLength = StringLength(modeView);
|
size_t modeLength = StringLength(modeView);
|
||||||
Assert(!ContainsChar(mode, 'b') && "Binary mode note supported");
|
|
||||||
Assert((modeLength <= 2) &&
|
Assert((modeLength <= 2) &&
|
||||||
"Mode should have at most 2 characters, one being either r,w or a and the other can only be +");
|
"Mode should have at most 2 characters, one being either r,w or a and the other can only be +");
|
||||||
if (modeLength == 1)
|
if (modeLength == 1)
|
||||||
{
|
{
|
||||||
Assert(modeView.Data[0] == 'r' || modeView.Data[0] == 'w' ||
|
Assert((modeView.Data[0] == 'r' || modeView.Data[0] == 'w' || modeView.Data[0] == 'a') &&
|
||||||
modeView.Data[0] == 'a' && "Invalid Mode. First char is not r,w or a");
|
"Invalid Mode. First char is not r,w or a");
|
||||||
}
|
}
|
||||||
else
|
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
|
#endif
|
||||||
|
|
||||||
@@ -192,6 +255,7 @@ namespace Juliet::Internal
|
|||||||
interface.Size = FileSize;
|
interface.Size = FileSize;
|
||||||
interface.Seek = FileSeek;
|
interface.Seek = FileSeek;
|
||||||
}
|
}
|
||||||
|
interface.Read = FileRead;
|
||||||
interface.Write = FileWrite;
|
interface.Write = FileWrite;
|
||||||
interface.Close = FileClose;
|
interface.Close = FileClose;
|
||||||
|
|
||||||
|
|||||||
@@ -44,10 +44,13 @@ void Compile()
|
|||||||
|
|
||||||
int main(int argc, char* argv[])
|
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, ":)");
|
size_t bytesRead = 0;
|
||||||
IOPrintf(stream, "%d%s", 1234, "Hello World!");
|
auto* data = LoadFile(ConstString("XF"),bytesRead );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user