diff --git a/src/io-util.cc b/src/io-util.cc index 4f9e2681..47019217 100644 --- a/src/io-util.cc +++ b/src/io-util.cc @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache 2.0 // Copyright 2022 - 2023, Syoyo Fujita. // Copyright 2023 - Present, Light Transport Entertainment Inc. -// +// #include #include @@ -17,14 +17,13 @@ #define WIN32_LEAN_AND_MEAN #endif -#include // include API for expanding a file path #include +#include // include API for expanding a file path #ifndef TINYUSDZ_MMAP_SUPPORTED #define TINYUSDZ_MMAP_SUPPORTED (1) #endif - #ifdef _MSC_VER #undef NOMINMAX #endif @@ -52,16 +51,14 @@ #else // Assume Posix -#include - -#include #include +#include +#include #ifndef TINYUSDZ_MMAP_SUPPORTED #define TINYUSDZ_MMAP_SUPPORTED (1) #endif - #endif #endif // _WIN32 @@ -96,41 +93,46 @@ namespace { // from llama.cpp ---- // MIT license std::string GetErrorMessageWin32(DWORD error_code) { - std::string ret; - LPSTR lpMsgBuf = NULL; - DWORD bufLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&lpMsgBuf, 0, NULL); - if (!bufLen) { - ret = "Win32 error code: " + std::to_string(error_code); - } else { - ret = lpMsgBuf; - LocalFree(lpMsgBuf); - } + std::string ret; + LPSTR lpMsgBuf = NULL; + DWORD bufLen = FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR)&lpMsgBuf, 0, NULL); + if (!bufLen) { + ret = "Win32 error code: " + std::to_string(error_code); + } else { + ret = lpMsgBuf; + LocalFree(lpMsgBuf); + } - return ret; + return ret; } static std::string llama_format_win_err(DWORD err) { - LPSTR buf; - size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buf, 0, NULL); - if (!size) { - return "FormatMessageA failed"; - } - std::string ret(buf, size); - LocalFree(buf); - return ret; + LPSTR buf; + size_t size = FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buf, 0, + NULL); + if (!size) { + return "FormatMessageA failed"; + } + std::string ret(buf, size); + LocalFree(buf); + return ret; } // ---- -} +} // namespace #endif #ifdef TINYUSDZ_ANDROID_LOAD_FROM_ASSETS AAssetManager *asset_manager = nullptr; #endif - bool IsMMapSupported() { #if TINYUSDZ_MMAP_SUPPORTED return true; @@ -139,12 +141,22 @@ bool IsMMapSupported() { #endif } -bool MMapFile(const std::string &filepath, MMapFileHandle *handle, bool writable, std::string *err) { +bool MMapFile(const std::string &filepath, MMapFileHandle *handle, + bool writable, std::string *err) { + + if (!FileExists(filepath, /* userdata */nullptr)) { + if (err) { + (*err) += "File not found: " + filepath + "\n"; + } + return false; + } #if TINYUSDZ_MMAP_SUPPORTED #if defined(_WIN32) - //int fd = open(filepath.c_str(), writable ? O_RDWR : O_RDONLY); - HANDLE hFile = CreateFile(filepath.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); + // int fd = open(filepath.c_str(), writable ? O_RDWR : O_RDONLY); + HANDLE hFile = + CreateFile(filepath.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); if (hFile == INVALID_HANDLE_VALUE) { if (err) { (*err) += "Failed to open file."; @@ -157,90 +169,115 @@ bool MMapFile(const std::string &filepath, MMapFileHandle *handle, bool writable LARGE_INTEGER sz{}; if (!GetFileSizeEx(hFile, &sz)) { if (err) { - (*err) += "GetFileSizeEx failed: " + llama_format_win_err(GetLastError()); + (*err) += + "GetFileSizeEx failed: " + llama_format_win_err(GetLastError()); } return false; } size = sz.QuadPart; } - - HANDLE hMapping = CreateFileMapping(hFile, nullptr, writable ? PAGE_READWRITE : PAGE_READONLY, 0, 0, nullptr); - if (hMapping == nullptr) { - if (err) { - (*err) += "CreateFileMapping failed: " + llama_format_win_err(GetLastError()); - } - return false; - } - void *addr = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0); - DWORD lastError = GetLastError(); - CloseHandle(hMapping); - if (!addr) { + + HANDLE hMapping = CreateFileMapping( + hFile, nullptr, writable ? PAGE_READWRITE : PAGE_READONLY, 0, 0, nullptr); + if (hMapping == nullptr) { + if (err) { + (*err) += + "CreateFileMapping failed: " + llama_format_win_err(GetLastError()); + } + return false; + } + void *addr = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0); + DWORD lastError = GetLastError(); + CloseHandle(hMapping); + if (!addr) { + if (err) { + (*err) += "MapViewOfFile failed: " + llama_format_win_err(lastError); + } + return false; + } + + size_t prefetch = 0; // TODO + if (prefetch > 0) { +#if _WIN32_WINNT >= 0x602 + // PrefetchVirtualMemory is only present on Windows 8 and above, so we + // dynamically load it + BOOL(WINAPI * pPrefetchVirtualMemory) + (HANDLE, ULONG_PTR, PWIN32_MEMORY_RANGE_ENTRY, ULONG); + HMODULE hKernel32 = GetModuleHandleW(L"kernel32.dll"); + + // may fail on pre-Windows 8 systems + pPrefetchVirtualMemory = reinterpret_cast( + GetProcAddress(hKernel32, "PrefetchVirtualMemory")); + + if (pPrefetchVirtualMemory) { + // advise the kernel to preload the mapped memory + WIN32_MEMORY_RANGE_ENTRY range; + range.VirtualAddress = addr; + range.NumberOfBytes = static_cast((std::min)(size, prefetch)); + if (!pPrefetchVirtualMemory(GetCurrentProcess(), 1, &range, 0)) { + // warn if (err) { - (*err) += "MapViewOfFile failed: " + llama_format_win_err(lastError); + (*err) += "warning: PrefetchVirtualMemory failed: " + + llama_format_win_err(GetLastError()); } - return false; } + } +#else + throw std::runtime_error("PrefetchVirtualMemory unavailable"); + if (err) { + (*err) += "PrefetchVirtualMemory unavailable"; + } + return false; +#endif + } - size_t prefetch = 0; // TODO - if (prefetch > 0) { - #if _WIN32_WINNT >= 0x602 - // PrefetchVirtualMemory is only present on Windows 8 and above, so we dynamically load it - BOOL (WINAPI *pPrefetchVirtualMemory) (HANDLE, ULONG_PTR, PWIN32_MEMORY_RANGE_ENTRY, ULONG); - HMODULE hKernel32 = GetModuleHandleW(L"kernel32.dll"); - - // may fail on pre-Windows 8 systems - pPrefetchVirtualMemory = reinterpret_cast (GetProcAddress(hKernel32, "PrefetchVirtualMemory")); - - if (pPrefetchVirtualMemory) { - // advise the kernel to preload the mapped memory - WIN32_MEMORY_RANGE_ENTRY range; - range.VirtualAddress = addr; - range.NumberOfBytes = static_cast( (std::min)(size, prefetch) ); - if (!pPrefetchVirtualMemory(GetCurrentProcess(), 1, &range, 0)) { - // warn - if (err) { - (*err) += "warning: PrefetchVirtualMemory failed: " + llama_format_win_err(GetLastError()); - } - } - } - #else - throw std::runtime_error("PrefetchVirtualMemory unavailable"); - if (err) { - (*err) += "PrefetchVirtualMemory unavailable"; - } - return false; - #endif - } - - handle->addr = reinterpret_cast(addr); - handle->size = size; - handle->writable = writable; - handle->filename = filepath; + handle->addr = reinterpret_cast(addr); + handle->size = size; + handle->writable = writable; + handle->filename = filepath; return true; - -#else // !WIN32 + +#else // !WIN32 // assume posix FILE *fp = fopen(filepath.c_str(), writable ? "rw" : "r"); + if (!fp) { + if (err) { + (*err) += "fopen failed."; + } + return false; + } + int ret = std::fseek(fp, 0, SEEK_END); if (ret != 0) { + if (err) { + (*err) += "Failed to fseek."; + } fclose(fp); return false; - } + } size_t size = size_t(std::ftell(fp)); std::fseek(fp, 0, SEEK_SET); if (size == 0) { + if (err) { + (*err) += "File size is zero."; + } return false; } - + int fd = fileno(fp); - - int flags = MAP_PRIVATE; // delayed access - void *addr = mmap(nullptr, size, writable ? PROT_READ|PROT_WRITE : PROT_READ, flags, fd, 0); + + int flags = MAP_PRIVATE; // delayed access + void *addr = + mmap(nullptr, size, writable ? PROT_READ | PROT_WRITE : PROT_READ, flags, + fd, 0); if (addr == MAP_FAILED) { + if (err) { + (*err) += "mmap failed."; + } return false; } @@ -251,11 +288,12 @@ bool MMapFile(const std::string &filepath, MMapFileHandle *handle, bool writable close(fd); return true; -#endif // !WIN32 -#else // !TINYUSDZ_MMAP_SUPPORTED +#endif // !WIN32 +#else // !TINYUSDZ_MMAP_SUPPORTED (void)filepath; (void)handle; (void)writable; + (void)err; return false; #endif } @@ -266,7 +304,8 @@ bool UnmapFile(const MMapFileHandle &handle, std::string *err) { if (handle.addr && handle.size) { if (!UnmapViewOfFile(handle.addr)) { if (err) { - (*err) += "warning: UnmapViewOfFile failed: " + llama_format_win_err(GetLastError()); + (*err) += "warning: UnmapViewOfFile failed: " + + llama_format_win_err(GetLastError()); } // May ok for now return true; @@ -274,22 +313,26 @@ bool UnmapFile(const MMapFileHandle &handle, std::string *err) { } return false; -#else // !WIN32 +#else // !WIN32 if (handle.addr && handle.size) { - int ret = munmap(reinterpret_cast(handle.addr), handle.size); + int ret = munmap(reinterpret_cast(handle.addr), handle.size); + if (!ret) { + if (err) { + (*err) += "warning: munmap failed."; + } + } // ignore return code for now - (void)ret; return true; } return false; #endif -#else // !TINYUSDZ_MMAP_SUPPORTED +#else // !TINYUSDZ_MMAP_SUPPORTED (void)handle; + (void)err; return false; #endif } - std::string ExpandFilePath(const std::string &_filepath, void *) { std::string filepath = _filepath; if (filepath.size() > 2048) { @@ -396,10 +439,10 @@ bool ReadWholeFile(std::vector *out, std::string *err, size_t size = size_t(len); if (size >= filesize_max) { - (*err) += "File size exceeds filesize_max : " + filepath + - " (filesize_max " + std::to_string(filesize_max) + ")"; + (*err) += "File size exceeds filesize_max : " + filepath + + " (filesize_max " + std::to_string(filesize_max) + ")"; - return false; + return false; } out->resize(size); @@ -443,7 +486,9 @@ bool ReadWholeFile(std::vector *out, std::string *err, (void)buf; if (!f) { if (err) { - (*err) += "File read error. Maybe empty file or invalid file : " + filepath + "\n"; + (*err) += + "File read error. Maybe empty file or invalid file : " + filepath + + "\n"; } return false; } @@ -569,12 +614,13 @@ bool ReadFileHeader(std::vector *out, std::string *err, (void)buf; if (!f) { if (err) { - (*err) += "File read error. Maybe empty file or invalid file : " + filepath + "\n"; + (*err) += + "File read error. Maybe empty file or invalid file : " + filepath + + "\n"; } return false; } - f.seekg(0, f.end); size_t sz = static_cast(f.tellg()); f.seekg(0, f.beg);