1+ //
2+ // This file is part of The Pivot framework.
3+ // Written by Gabriel Dos Reis.
4+ // See LICENSE for copright and license notices.
5+ //
6+
7+ #ifdef _WIN32
8+ # include < windows.h>
9+ #else
10+ # include < sys/stat.h>
11+ # include < sys/mman.h>
12+ # include < fcntl.h>
13+ # include < unistd.h>
14+ #endif
15+
16+ #include < ipr/input>
17+
18+ namespace ipr ::input {
19+ #ifdef _WIN32
20+ // Helper type for automatically closing a handle on scope exit.
21+ struct SystemHandle {
22+ SystemHandle (HANDLE h) : handle{h} { }
23+ bool valid () const { return handle != INVALID_HANDLE_VALUE; }
24+ auto get_handle () const { return handle; }
25+ ~SystemHandle ()
26+ {
27+ if (valid ())
28+ CloseHandle (handle);
29+ }
30+ private:
31+ HANDLE handle;
32+ };
33+ #endif
34+
35+ SourceFile::SourceFile (const SystemPath& path)
36+ {
37+ #ifdef _WIN32
38+ // FIXME: Handle the situation of large files in a 32-bit program.
39+ static_assert (sizeof (LARGE_INTEGER) == sizeof (std::size_t ));
40+
41+ SystemHandle file = CreateFileW (path.c_str (), GENERIC_READ, 0 , nullptr ,
42+ OPEN_EXISTING,
43+ FILE_ATTRIBUTE_NORMAL, nullptr );
44+ if (not file.valid ())
45+ throw AccessError{ path, GetLastError () };
46+ LARGE_INTEGER s { };
47+ if (not GetFileSizeEx (file.get_handle (), &s))
48+ throw AccessError{ path, GetLastError () };
49+ if (s.QuadPart )
50+ return ;
51+ SystemHandle mapping = CreateFileMapping (file.get_handle (), nullptr , PAGE_READONLY, 0 , 0 , nullptr );
52+ if (mapping.get_handle () == nullptr )
53+ throw FileMappingError{ path, GetLastError () };
54+ auto start = MapViewOfFile (mapping.get_handle (), FILE_MAP_READ, 0 , 0 , 0 );
55+ view = { reinterpret_cast <const std::byte*>(start), static_cast <View::size_type>(s.QuadPart ) };
56+ #else
57+ struct stat s { };
58+ errno = 0 ;
59+ if (stat (path.c_str (), &s) < 0 )
60+ throw AccessError{ path, errno };
61+ else if (not S_ISREG (s.st_mode ))
62+ throw RegularFileError{ path };
63+
64+ // Don't labor too hard with empty files.
65+ if (s.st_size == 0 )
66+ return ;
67+
68+ auto fd = open (path.c_str (), O_RDONLY);
69+ if (fd < 0 )
70+ throw AccessError{ path, errno };
71+ auto start = mmap (nullptr , s.st_size , PROT_READ, MAP_PRIVATE, fd, 0 );
72+ close (fd);
73+ if (start == MAP_FAILED)
74+ throw FileMappingError{ path };
75+ view = { reinterpret_cast <std::byte*>(start), static_cast <View::size_type>(s.st_size ) };
76+ #endif
77+ }
78+
79+ SourceFile::SourceFile (SourceFile&& src) : view{src.view }
80+ {
81+ src.view = { };
82+ }
83+
84+ SourceFile::~SourceFile ()
85+ {
86+ if (not view.empty ())
87+ {
88+ #ifdef _WIN32
89+ UnmapViewOfFile (view.data ());
90+ #else
91+ munmap (const_cast <std::byte*>(view.data ()), view.size ());
92+ #endif
93+ }
94+ }
95+ }
0 commit comments