diff --git a/sherpa-onnx/csrc/file-utils.cc b/sherpa-onnx/csrc/file-utils.cc index b1802334ab..33cf83c3d0 100644 --- a/sherpa-onnx/csrc/file-utils.cc +++ b/sherpa-onnx/csrc/file-utils.cc @@ -13,6 +13,8 @@ #ifdef _WIN32 #include #else +#include +#include #include #include #endif @@ -20,9 +22,18 @@ #include "sherpa-onnx/csrc/macros.h" namespace sherpa_onnx { +std::wstring ToWideString(const std::string &s); +std::string ToString(const std::wstring &s); bool FileExists(const std::string &filename) { - return std::ifstream(filename).good(); +#ifdef _WIN32 + DWORD attributes = GetFileAttributesW(ToWideString(filename).c_str()); + + return attributes != INVALID_FILE_ATTRIBUTES && !(attributes & FILE_ATTRIBUTE_DIRECTORY); +#else + struct stat file_stat; + return stat(filename.c_str(), &file_stat) == 0 && S_ISREG(file_stat.st_mode); +#endif } void AssertFileExists(const std::string &filename) { @@ -33,20 +44,70 @@ void AssertFileExists(const std::string &filename) { } std::vector ReadFile(const std::string &filename) { - std::ifstream file(filename, std::ios::binary | std::ios::ate); - if (!file.is_open()) { + if (filename.empty()) { return {}; } - - std::streamsize size = file.tellg(); - file.seekg(0, std::ios::beg); - - std::vector buffer(size); - if (!file.read(buffer.data(), size)) { + try { +#ifdef _WIN32 + HANDLE hFile = CreateFileW( + ToWideString(filename).c_str(), + GENERIC_READ, + FILE_SHARE_READ, + nullptr, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + nullptr + ); + + if (hFile == INVALID_HANDLE_VALUE) { + return {}; + } + + std::unique_ptr file_guard( + hFile, CloseHandle); + + LARGE_INTEGER file_size; + if (!GetFileSizeEx(hFile, &file_size) || file_size.QuadPart > SIZE_MAX) { + return {}; + } + + std::vector buffer(static_cast(file_size.QuadPart)); + + DWORD bytes_read = 0; + bool read_success = ::ReadFile( + hFile, + buffer.data(), + static_cast(buffer.size()), + &bytes_read, + nullptr + ); + if (!read_success || bytes_read != buffer.size()) { + return {}; + } + + return buffer; +#else + std::ifstream file(filename, std::ios::binary | std::ios::ate); + if (!file.is_open()) { + return {}; + } + + std::streamsize size = file.tellg(); + if (size < 0) { + return {}; + } + file.seekg(0, std::ios::beg); + + std::vector buffer(static_cast(size)); + if (!file.read(buffer.data(), size)) { + return {}; + } + + return buffer; +#endif + } catch (const std::exception&) { return {}; } - - return buffer; } #if __ANDROID_API__ >= 9 @@ -119,33 +180,38 @@ std::string ResolveAbsolutePath(const std::string &path) { return path; } + try { #ifdef _WIN32 - // Check if path is already absolute (drive letter or UNC path) - if ((path.size() > 1 && path[1] == ':') || - (path.size() > 1 && path[0] == '\\' && path[1] == '\\')) { - return path; - } - - char buffer[MAX_PATH]; - if (GetFullPathNameA(path.c_str(), MAX_PATH, buffer, nullptr)) { - return std::string(buffer); - } - - return path; // fallback on failure - + std::wstring wide_path = ToWideString(path); + DWORD required_size = GetFullPathNameW(wide_path.c_str(), 0, nullptr, nullptr); + if (required_size == 0) { + return path; + } + + std::vector buffer(required_size); + DWORD actual_size = GetFullPathNameW( + wide_path.c_str(), + required_size, + buffer.data(), + nullptr + ); + + if (actual_size == 0 || actual_size >= required_size) { + return path; + } + + std::wstring resolved_wide(buffer.data(), actual_size); + return ToString(resolved_wide); #else - // POSIX: absolute paths start with '/' - if (path[0] == '/') { + char resolved_path[PATH_MAX]; + if (realpath(path.c_str(), resolved_path) == nullptr) { + return path; + } + return std::string(resolved_path); +#endif + } catch (const std::exception&) { return path; } - - char buffer[PATH_MAX]; - if (realpath(path.c_str(), buffer)) { - return std::string(buffer); - } - - return path; // fallback on failure -#endif } } // namespace sherpa_onnx