/*** Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: FileStream.Win32.cpp Date: 2021-6-12 Author: Reece ***/ #include #include "FS.hpp" #include "FileStream.Win32.hpp" #if !defined(_AURUNTIME_GENERICFILESTREAM) namespace Aurora::IO::FS { static const AuUInt64 kFileCopyBlock = 0x4000; // 16KiB WinFileStream::~WinFileStream() { Close(); } void WinFileStream::Init(HANDLE handle) { handle_ = handle; } AuUInt64 WinFileStream::GetOffset() { LARGE_INTEGER distance {}; LARGE_INTEGER pos {}; if (handle_ == INVALID_HANDLE_VALUE) { SysPushErrorUninitialized(); return 0; } if (SetFilePointerEx(handle_, distance, &pos, FILE_CURRENT) == INVALID_SET_FILE_POINTER) { LogWarn("SetFilePointerEx IO Error: 0x%x", GetLastError()); SysPushErrorIO(); return 0; } return pos.QuadPart; } bool WinFileStream::SetOffset(AuUInt64 offset) { LARGE_INTEGER distance {}; LARGE_INTEGER pos {}; if (handle_ == INVALID_HANDLE_VALUE) { SysPushErrorUninitialized(); return false; } distance.QuadPart = offset; if (SetFilePointerEx(handle_, distance, &pos, FILE_CURRENT) == INVALID_SET_FILE_POINTER) { LogWarn("SetFilePointerEx IO Error: 0x%x", GetLastError()); SysPushErrorIO(); return false; } return true; } AuUInt64 WinFileStream::GetLength() { LARGE_INTEGER length; if (!GetFileSizeEx(handle_, &length)) { SysPushErrorIO(); return 0; } return length.QuadPart; } AuUInt64 WinFileStream::Read(void *in, AuUInt64 length) { if (handle_ == INVALID_HANDLE_VALUE) { SysPushErrorUninitialized(); return 0; } AuUInt64 offset {0}; while (length) { DWORD read; int blockSize = std::min(kFileCopyBlock, length); if (!::ReadFile(handle_, &reinterpret_cast(in)[offset], blockSize, &read, NULL)) { LogWarn("ReadFile IO Error: 0x%x", GetLastError()); SysPushErrorIO(); goto out; } #if 0 if (read != blockSize) { goto out; } #endif offset += read; length -= read; } out: if (handle_ != INVALID_HANDLE_VALUE) CloseHandle(handle_); return offset; } AuUInt64 WinFileStream::Write(const void *out, AuUInt64 length) { if (handle_ == INVALID_HANDLE_VALUE) { SysPushErrorUninitialized(); return 0; } AuUInt64 offset {0}; while (length) { DWORD written; int blockSize = std::min(kFileCopyBlock, length); if (!::WriteFile(handle_, &reinterpret_cast(out)[offset], blockSize, &written, NULL)) { LogWarn("WriteFileEx IO Error: 0x%x", GetLastError()); SysPushErrorIO(); return offset; } if (written != blockSize) { SysPushErrorIO(); return offset; } offset += written; length -= written; } return offset; } void WinFileStream::Close() { HANDLE handle; if ((handle = std::exchange(handle_, INVALID_HANDLE_VALUE)) != INVALID_HANDLE_VALUE) { CloseHandle(handle); } } void WinFileStream::Flush() { FlushFileBuffers(handle_); } static IFileStream *OpenNew(const AuString &path, bool read) { auto pathex = NormalizePathRet(path); auto win32Path = Locale::ConvertFromUTF8(pathex); HANDLE fileHandle; if (read) { fileHandle = CreateFileW(win32Path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); } else { CreateDirectories(pathex, true); fileHandle = CreateFileW(win32Path.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); } if (fileHandle == INVALID_HANDLE_VALUE) { LogWarn("Missing file: {}", path); SysPushErrorIO("Missing file: {}", path); return nullptr; } auto stream = _new WinFileStream(); if (!stream) { CloseHandle(fileHandle); return nullptr; } stream->Init(fileHandle); return stream; } AUKN_SYM IFileStream *OpenReadNew(const AuString &path) { return OpenNew(path, true); } AUKN_SYM void OpenReadRelease(IFileStream * that) { SafeDelete(that); } AUKN_SYM IFileStream *OpenWriteNew(const AuString &path) { return OpenNew(path, false); } AUKN_SYM void OpenWriteRelease(IFileStream * that) { SafeDelete(that); } } #endif