1717#include < string>
1818
1919#ifdef _WIN32
20- # ifndef WIN32_LEAN_AND_MEAN
21- # define WIN32_LEAN_AND_MEAN
22- # endif
23- # include < windows.h>
20+ // Avoid <windows.h> entirely — MinGW C++17+ std::byte conflicts with
21+ // rpcndr.h byte typedef. Use POSIX-compat _open/_read/_lseeki64 instead.
22+ # include < io.h>
23+ # include < fcntl.h>
24+ # include < sys/stat.h>
25+ # include < mutex>
2426#else
2527# include < fcntl.h>
2628# include < unistd.h>
@@ -33,35 +35,22 @@ namespace streampress {
3335// / Platform-agnostic random-access file reader.
3436// / Supports positional reads without moving any file cursor.
3537// / Thread-safe for concurrent pread() calls on POSIX platforms.
38+ // / On Windows, uses a mutex to serialise _lseeki64 + _read.
3639class FileReader {
3740public:
3841 explicit FileReader (const std::string& path) {
3942#ifdef _WIN32
40- // Convert UTF-8 path to wide string
41- int wlen = MultiByteToWideChar (CP_UTF8, 0 , path.c_str (), -1 , nullptr , 0 );
42- if (wlen <= 0 )
43- throw std::runtime_error (" Cannot convert path to wide string: " + path);
44- std::wstring wpath (wlen, L' \0 ' );
45- MultiByteToWideChar (CP_UTF8, 0 , path.c_str (), -1 , &wpath[0 ], wlen);
46-
47- hFile_ = CreateFileW (
48- wpath.c_str (),
49- GENERIC_READ,
50- FILE_SHARE_READ,
51- nullptr ,
52- OPEN_EXISTING,
53- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
54- nullptr );
55- if (hFile_ == INVALID_HANDLE_VALUE)
43+ fd_ = _open (path.c_str (), _O_RDONLY | _O_BINARY);
44+ if (fd_ < 0 )
5645 throw std::runtime_error (" Cannot open file: " + path);
57-
58- LARGE_INTEGER li;
59- if (!GetFileSizeEx (hFile_, &li)) {
60- CloseHandle (hFile_);
61- hFile_ = INVALID_HANDLE_VALUE;
46+ __int64 sz = _lseeki64 (fd_, 0 , SEEK_END);
47+ if (sz < 0 ) {
48+ _close (fd_);
49+ fd_ = -1 ;
6250 throw std::runtime_error (" Cannot get file size: " + path);
6351 }
64- file_size_ = static_cast <uint64_t >(li.QuadPart );
52+ file_size_ = static_cast <uint64_t >(sz);
53+ _lseeki64 (fd_, 0 , SEEK_SET);
6554#else
6655 fd_ = ::open (path.c_str (), O_RDONLY);
6756 if (fd_ < 0 )
@@ -86,31 +75,18 @@ class FileReader {
8675 // Movable
8776 FileReader (FileReader&& other) noexcept
8877 : file_size_(other.file_size_)
89- #ifdef _WIN32
90- , hFile_(other.hFile_)
91- #else
9278 , fd_(other.fd_)
93- #endif
9479 {
9580 other.file_size_ = 0 ;
96- #ifdef _WIN32
97- other.hFile_ = INVALID_HANDLE_VALUE;
98- #else
9981 other.fd_ = -1 ;
100- #endif
10182 }
10283
10384 FileReader& operator =(FileReader&& other) noexcept {
10485 if (this != &other) {
10586 close ();
10687 file_size_ = other.file_size_ ;
107- #ifdef _WIN32
108- hFile_ = other.hFile_ ;
109- other.hFile_ = INVALID_HANDLE_VALUE;
110- #else
11188 fd_ = other.fd_ ;
11289 other.fd_ = -1 ;
113- #endif
11490 other.file_size_ = 0 ;
11591 }
11692 return *this ;
@@ -121,13 +97,13 @@ class FileReader {
12197 size_t pread (uint64_t offset, void * buf, size_t size) const {
12298 if (size == 0 ) return 0 ;
12399#ifdef _WIN32
124- OVERLAPPED ov = {} ;
125- ov. Offset = static_cast <DWORD >(offset & 0xFFFFFFFF );
126- ov. OffsetHigh = static_cast <DWORD>( offset >> 32 );
127- DWORD bytes_read = 0 ;
128- if (! ReadFile (hFile_, buf, static_cast <DWORD>(size), &bytes_read, &ov) )
129- throw std::runtime_error (" ReadFile failed at offset " + std::to_string (offset));
130- return static_cast <size_t >(bytes_read );
100+ std::lock_guard<std::mutex> lock (mtx_) ;
101+ if ( _lseeki64 (fd_, static_cast <__int64 >(offset), SEEK_SET) < 0 )
102+ throw std::runtime_error ( " _lseeki64 failed at offset " + std::to_string (offset) );
103+ int n = _read (fd_, buf, static_cast < unsigned int >(size)) ;
104+ if (n < 0 )
105+ throw std::runtime_error (" _read failed at offset " + std::to_string (offset));
106+ return static_cast <size_t >(n );
131107#else
132108 ssize_t n = ::pread (fd_, buf, size, static_cast <off_t >(offset));
133109 if (n < 0 )
@@ -139,19 +115,13 @@ class FileReader {
139115
140116 uint64_t file_size () const { return file_size_; }
141117
142- bool is_open () const {
143- #ifdef _WIN32
144- return hFile_ != INVALID_HANDLE_VALUE;
145- #else
146- return fd_ >= 0 ;
147- #endif
148- }
118+ bool is_open () const { return fd_ >= 0 ; }
149119
150120 void close () {
151121#ifdef _WIN32
152- if (hFile_ != INVALID_HANDLE_VALUE ) {
153- CloseHandle (hFile_ );
154- hFile_ = INVALID_HANDLE_VALUE ;
122+ if (fd_ >= 0 ) {
123+ _close (fd_ );
124+ fd_ = - 1 ;
155125 }
156126#else
157127 if (fd_ >= 0 ) {
@@ -163,10 +133,9 @@ class FileReader {
163133
164134private:
165135 uint64_t file_size_ = 0 ;
166- #ifdef _WIN32
167- HANDLE hFile_ = INVALID_HANDLE_VALUE;
168- #else
169136 int fd_ = -1 ;
137+ #ifdef _WIN32
138+ mutable std::mutex mtx_;
170139#endif
171140};
172141
0 commit comments