sandbox
Loading...
Searching...
No Matches
native_file.hpp
1// SPDX-License-Identifier: MIT
2#ifndef LIBSBX_FILESYSTEM_NATIVE_FILE_HPP_
3#define LIBSBX_FILESYSTEM_NATIVE_FILE_HPP_
4
5#include <cstdio>
6#include <mutex>
7#include <vector>
8#include <span>
9#include <string>
10#include <system_error>
11#include <algorithm>
12
13#include <libsbx/utility/lockable.hpp>
14
15#include <libsbx/filesystem/file_base.hpp>
16#include <libsbx/filesystem/file_info.hpp>
17
18namespace sbx::filesystem {
19
20template<typename Lockable>
21class basic_native_file final : public file_base {
22
23public:
24
25 using handle_type = std::FILE*;
26 using lockable_type = Lockable;
27
28 explicit basic_native_file(const file_info& info)
29 : _info{info} { }
30
31 basic_native_file(const file_info& info, handle_type stream)
32 : _info{info},
33 _file{stream} { }
34
35 ~basic_native_file() override {
36 close();
37 }
38
39 [[nodiscard]] auto info() const -> const file_info& override {
40 auto lock = std::scoped_lock{_mutex};
41
42 return _info;
43 }
44
45 [[nodiscard]] auto size() const -> std::uint64_t override {
46 auto lock = std::scoped_lock{_mutex};
47
48 if (!_file) {
49 return 0;
50 }
51
52 auto ec = std::error_code{};
53 auto size = std::filesystem::file_size(_info.native_path(), ec);
54
55 return ec ? 0 : static_cast<std::uint64_t>(size);
56 }
57
58 [[nodiscard]] auto is_read_only() const -> bool override {
59 auto lock = std::scoped_lock{_mutex};
60
61 return !file_base::mode_has_flag(_mode, mode::write);
62 }
63
64 [[nodiscard]]
65 auto open(mode mode) -> bool override {
66 auto lock = std::scoped_lock{_mutex};
67
68 if (!file_base::is_mode_valid(mode)) {
69 return false;
70 }
71
72 if (_file && _mode == mode) {
73 std::fseek(_file, 0, SEEK_SET);
74 return true;
75 }
76
77 _mode = mode;
78
79 const auto is_read = file_base::mode_has_flag(mode, mode::read);
80 const auto is_write = file_base::mode_has_flag(mode, mode::write);
81 const auto is_append = file_base::mode_has_flag(mode, mode::append);
82 const auto is_truncate = file_base::mode_has_flag(mode, mode::truncate);
83
84 auto mode_string = std::string{};
85
86 if (is_read && !is_write) {
87 mode_string = "rb";
88 } else if (is_write && !is_read) {
89 mode_string = is_append ? "ab" : (is_truncate ? "wb" : "r+b");
90 } else if (is_read && is_write) {
91 mode_string = is_append ? "a+b" : (is_truncate ? "w+b" : "r+b");
92 } else {
93 mode_string = "rb";
94 }
95
96 _file = std::fopen(_info.native_path().c_str(), mode_string.c_str());
97
98 return _file != nullptr;
99 }
100
101 auto close() -> void override {
102 auto lock = std::scoped_lock{_mutex};
103
104 if (_file) {
105 std::fclose(_file);
106 _file = nullptr;
107 _mode = mode::read;
108 }
109 }
110
111 [[nodiscard]] auto is_open() const -> bool override {
112 auto lock = std::scoped_lock{_mutex};
113
114 return _file != nullptr;
115 }
116
117 auto seek(std::uint64_t offset, origin origin) -> std::uint64_t override {
118 auto lock = std::scoped_lock{_mutex};
119
120 if (!_file) {
121 return 0;
122 }
123
124 auto whence = SEEK_SET;
125
126 switch (origin) {
127 case origin::begin: {
128 whence = SEEK_SET;
129 break;
130 }
131 case origin::end: {
132 whence = SEEK_END;
133 break;
134 }
135 case origin::set: {
136 whence = SEEK_CUR;
137 break;
138 }
139 }
140
141 if (std::fseek(_file, static_cast<long>(offset), whence) != 0) {
142 return 0;
143 }
144
145 const auto position = std::ftell(_file);
146
147 return (position != -1L) ? static_cast<std::uint64_t>(position) : 0;
148 }
149
150 [[nodiscard]] auto tell() const -> std::uint64_t override {
151 auto lock = std::scoped_lock{_mutex};
152
153 if (!_file) {
154 return 0;
155 }
156
157 const auto position = std::ftell(_file);
158
159 return (position != -1L) ? static_cast<std::uint64_t>(position) : 0;
160 }
161
162 auto read(std::span<std::uint8_t> buffer) -> std::uint64_t override {
163 auto lock = std::scoped_lock{_mutex};
164
165 if (!_file || !file_base::mode_has_flag(_mode, mode::read)) {
166 return 0;
167 }
168
169 const auto read_count = std::fread(buffer.data(), 1, buffer.size(), _file);
170
171 return static_cast<std::uint64_t>(read_count);
172 }
173
174 auto read(std::vector<std::uint8_t>& buffer, std::uint64_t size) -> std::uint64_t override {
175 buffer.resize(size);
176 return read(std::span<std::uint8_t>{buffer});
177 }
178
179 auto write(std::span<const std::uint8_t> buffer) -> std::uint64_t override {
180 auto lock = std::scoped_lock{_mutex};
181
182 if (!_file || !file_base::mode_has_flag(_mode, mode::write)) {
183 return 0;
184 }
185
186 if (buffer.empty()) {
187 return 0;
188 }
189
190 const auto written = std::fwrite(buffer.data(), 1, buffer.size(), _file);
191
192 return static_cast<std::uint64_t>(written);
193 }
194
195 auto write(const std::vector<std::uint8_t>& buffer) -> std::uint64_t override {
196 return write(std::span<const std::uint8_t>{buffer});
197 }
198
199private:
200
201 mutable lockable_type _mutex;
202
203 file_info _info;
204 handle_type _file = nullptr;
205 mode _mode = mode::read;
206
207}; // class basic_native_file
208
211
213
214} // namespace sbx::filesystem
215
216#endif // LIBSBX_FILESYSTEM_NATIVE_FILE_HPP_
Definition: native_file.hpp:21
Definition: file_base.hpp:15
Definition: file_info.hpp:10