Files
FlaxEngine/Source/Engine/Serialization/FileReadStream.cpp

168 lines
4.0 KiB
C++

// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
#include "FileReadStream.h"
#include "Engine/Core/Log.h"
#include "Engine/Platform/File.h"
#define USE_FILE_POS (1)
FileReadStream* FileReadStream::Open(const StringView& path)
{
const auto file = File::Open(path, FileMode::OpenExisting, FileAccess::Read, FileShare::Read);
if (file == nullptr)
{
LOG(Warning, "Cannot open file '{0}'", path);
return nullptr;
}
return New<FileReadStream>(file);
}
void FileReadStream::Unlink()
{
_file = nullptr;
}
FileReadStream::FileReadStream(File* file)
: _file(file)
, _virtualPosInBuffer(0)
, _bufferSize(0)
#if USE_FILE_POS
, _filePosition(file->GetPosition())
#else
, _filePosition(0)
#endif
{
}
FileReadStream::~FileReadStream()
{
// Ensure to be file closed and deleted
if (_file)
Delete(_file);
}
void FileReadStream::Flush()
{
// Check if need to flush
/*if (_virtualPosInBuffer > 0)
{
// Update buffer
uint32 bytesRead;
_hasError |= _file->Read(_buffer, FILESTREAM_BUFFER_SIZE, &bytesRead) != 0;
_virtualPosInBuffer = 0;
}*/
}
void FileReadStream::Close()
{
if (_file)
{
_file->Close();
}
}
uint32 FileReadStream::GetLength()
{
return _file->GetSize();
}
uint32 FileReadStream::GetPosition()
{
#if USE_FILE_POS
return _filePosition - _bufferSize + _virtualPosInBuffer;
#else
return _file->GetPosition() - _bufferSize + _virtualPosInBuffer;
#endif
}
void FileReadStream::SetPosition(uint32 seek)
{
#if USE_FILE_POS
// Skip if position won't change
if (GetPosition() == seek)
{
return;
}
// Try to seek with virtual position
uint32 bufferStartPos = _filePosition - _bufferSize;
if (seek >= GetPosition() && seek < _filePosition)
{
_virtualPosInBuffer = seek - bufferStartPos;
return;
}
#endif
// Seek
_file->SetPosition(seek);
_filePosition = _file->GetPosition();
// Update buffer
_hasError |= _file->Read(_buffer, FILESTREAM_BUFFER_SIZE, &_bufferSize) != 0;
#if USE_FILE_POS
_filePosition += _bufferSize;
#endif
_virtualPosInBuffer = 0;
}
void FileReadStream::ReadBytes(void* data, uint32 bytes)
{
// Skip if nothing to read
if (bytes == 0)
{
return;
}
// Ensure to flush the buffer if it's empty
if (_bufferSize == 0)
{
CHECK(_virtualPosInBuffer == 0);
_hasError |= _file->Read(_buffer, FILESTREAM_BUFFER_SIZE, &_bufferSize) != 0;
#if USE_FILE_POS
_filePosition += _bufferSize;
#endif
}
// Check if buffer has enough data for this read
const uint32 bufferBytesLeft = static_cast<uint32>(_bufferSize - _virtualPosInBuffer);
if (bytes <= bufferBytesLeft)
{
Platform::MemoryCopy(data, _buffer + _virtualPosInBuffer, bytes);
_virtualPosInBuffer += bytes;
}
else
{
// Flush already buffered bytes and read more it the buffer (reduce amount of flushes)
if (_virtualPosInBuffer > 0)
{
Platform::MemoryCopy(data, _buffer + _virtualPosInBuffer, bufferBytesLeft);
data = (byte*)data + bufferBytesLeft;
bytes -= bufferBytesLeft;
_virtualPosInBuffer = 0;
_hasError |= _file->Read(_buffer, FILESTREAM_BUFFER_SIZE, &_bufferSize) != 0;
#if USE_FILE_POS
_filePosition += _bufferSize;
#endif
}
// Read as much as can using whole buffer
while (bytes >= FILESTREAM_BUFFER_SIZE)
{
Platform::MemoryCopy(data, _buffer, FILESTREAM_BUFFER_SIZE);
data = (byte*)data + FILESTREAM_BUFFER_SIZE;
bytes -= FILESTREAM_BUFFER_SIZE;
_hasError |= _file->Read(_buffer, FILESTREAM_BUFFER_SIZE, &_bufferSize) != 0;
#if USE_FILE_POS
_filePosition += _bufferSize;
#endif
}
// Read the rest of the buffer but without flushing its data
if (bytes > 0)
{
Platform::MemoryCopy(data, _buffer, bytes);
_virtualPosInBuffer = bytes;
}
}
}