15#if defined(_GNU_SOURCE) || defined(_DEFAULT_SOURCE) || defined(_BSD_SOURCE) || defined(_SVID_SOURCE)
17 if(munmap(mapping_handle, content.
file_size) == -1) {
26 if(file_descriptor != -1) {
27 close(file_descriptor);
31file::file(
file&& other)
noexcept {
32 file_descriptor = other.file_descriptor;
33#if defined(_GNU_SOURCE) || defined(_DEFAULT_SOURCE) || defined(_BSD_SOURCE) || defined(_SVID_SOURCE)
34 mapping_handle = other.mapping_handle;
36 file_buffer = other.file_buffer;
38 content = other.content;
39 absolute_path = std::move(other.absolute_path);
41 other.file_descriptor = -1;
42#if defined(_GNU_SOURCE) || defined(_DEFAULT_SOURCE) || defined(_BSD_SOURCE) || defined(_SVID_SOURCE)
43 other.mapping_handle =
nullptr;
45 other.file_buffer =
nullptr;
49 file_descriptor = other.file_descriptor;
50#if defined(_GNU_SOURCE) || defined(_DEFAULT_SOURCE) || defined(_BSD_SOURCE) || defined(_SVID_SOURCE)
51 mapping_handle = other.mapping_handle;
53 file_buffer = other.file_buffer;
55 content = other.content;
56 absolute_path = std::move(other.absolute_path);
58 other.file_descriptor = -1;
59#if defined(_GNU_SOURCE) || defined(_DEFAULT_SOURCE) || defined(_BSD_SOURCE) || defined(_SVID_SOURCE)
60 other.mapping_handle =
nullptr;
62 other.file_buffer =
nullptr;
67 file_descriptor = open(full_path.c_str(), O_RDONLY | O_NONBLOCK);
68 if(file_descriptor != -1) {
69 absolute_path = full_path;
71 if(fstat(file_descriptor, &sb) != -1) {
73#if _POSIX_C_SOURCE >= 200112L
74 posix_fadvise(file_descriptor, 0,
static_cast<off_t
>(content.
file_size), POSIX_FADV_WILLNEED);
76#if defined(_GNU_SOURCE) || defined(_DEFAULT_SOURCE) || defined(_BSD_SOURCE) || defined(_SVID_SOURCE)
77 mapping_handle = mmap(0, content.
file_size, PROT_READ, MAP_PRIVATE, file_descriptor, 0);
78 if(mapping_handle == MAP_FAILED) {
81 content.
data =
static_cast<char*
>(mapping_handle);
84 read(file_descriptor, file_buffer, content.
file_size);
85 content.
data =
static_cast<char*
>(file_buffer);
90file::file(
int file_descriptor,
native_string const& full_path) : file_descriptor(file_descriptor) {
91 absolute_path = full_path;
93 if(fstat(file_descriptor, &sb) != -1) {
95#if defined(_GNU_SOURCE) || defined(_DEFAULT_SOURCE) || defined(_BSD_SOURCE) || defined(_SVID_SOURCE)
96 mapping_handle = mmap(0, content.
file_size, PROT_READ, MAP_PRIVATE, file_descriptor, 0);
97 if(mapping_handle == MAP_FAILED) {
100 content.
data =
static_cast<char*
>(mapping_handle);
103 read(file_descriptor, file_buffer, content.
file_size);
104 content.
data =
static_cast<char*
>(file_buffer);
110 std::optional<file> result(
file{f.absolute_path});
111 if(!result->content.data) {
112 result = std::optional<file>{};
118 fs.ordered_roots.clear();
119 fs.ignored_paths.clear();
123 fs.ordered_roots.emplace_back(root_path);
127 char module_name[1024];
129 if((path_used = readlink(
"/proc/self/exe", module_name,
sizeof(module_name) - 1)) != -1) {
130 while(path_used >= 0 && module_name[path_used] !=
'/') {
131 module_name[path_used] =
'\0';
136 snprintf(tmpbuf,
sizeof(tmpbuf),
"/proc/%u/exe",
unsigned(
getpid()));
137 if((path_used = readlink(tmpbuf, module_name,
sizeof(module_name) - 1)) != -1) {
138 while(path_used >= 0 && module_name[path_used] !=
'/') {
139 module_name[path_used] =
'\0';
157 for(
auto const& str : fs.ordered_roots) {
158 result +=
NATIVE(
";") + str;
161 for(
auto const& replace_path : fs.ignored_paths) {
162 result += replace_path +
NATIVE(
";");
169 auto break_position = std::find(data.data(), data.data() + data.length(),
NATIVE(
'?'));
172 auto position = data.data() + 1;
173 auto end = break_position;
174 while(position < end) {
175 auto next_semicolon = std::find(position, end,
NATIVE(
';'));
176 fs.ordered_roots.emplace_back(position, next_semicolon);
177 position = next_semicolon + 1;
182 auto position = break_position + 1;
183 auto end = data.data() + data.length();
184 while(position < end) {
185 auto next_semicolon = std::find(position, end,
NATIVE(
';'));
186 fs.ignored_paths.emplace_back(position, next_semicolon);
187 position = next_semicolon + 1;
194 for(
auto c = str; *c != 0; ++c) {
195 if(int32_t(*c) > 127 || int32_t(*c) < 0)
203 std::vector<unopened_file> accumulated_results;
204 if(dir.parent_system) {
205 for(
size_t i = dir.parent_system->ordered_roots.size(); i-- > 0;) {
206 auto const appended_path = dir.parent_system->ordered_roots[i] + dir.relative_path;
211 DIR* d = opendir(appended_path.c_str());
213 struct dirent* dir_ent =
nullptr;
214 while((dir_ent = readdir(d)) !=
nullptr) {
216 if(dir_ent->d_type != DT_REG)
220 if(extension && extension[0] != 0) {
221 char* dot = strrchr(dir_ent->d_name,
'.');
222 if(!dot || dot == dir_ent->d_name)
224 if(strcmp(dot, extension))
231 auto search_result = std::find_if(accumulated_results.begin(), accumulated_results.end(),
232 [n = dir_ent->d_name](
auto const& f) { return f.file_name.compare(n) == 0; });
233 if(search_result == accumulated_results.end()) {
234 accumulated_results.emplace_back(
235 dir.parent_system->ordered_roots[i] + dir.relative_path +
NATIVE(
"/") + dir_ent->d_name, dir_ent->d_name);
242 auto const appended_path = dir.relative_path;
243 DIR* d = opendir(appended_path.c_str());
245 struct dirent* dir_ent =
nullptr;
246 while((dir_ent = readdir(d)) !=
nullptr) {
248 if(dir_ent->d_type != DT_REG)
252 if(extension && extension[0] != 0) {
253 char* dot = strrchr(dir_ent->d_name,
'.');
254 if(!dot || dot == dir_ent->d_name)
256 if(strcmp(dot, extension))
263 accumulated_results.emplace_back(dir.relative_path +
NATIVE(
"/") + dir_ent->d_name, dir_ent->d_name);
269 return std::lexicographical_compare(std::begin(a.file_name), std::end(a.file_name), std::begin(b.file_name),
270 std::end(b.file_name),
271 [](native_char const& char1, native_char const& char2) { return tolower(char1) < tolower(char2); });
273 return accumulated_results;
276 std::vector<directory> accumulated_results;
277 if(dir.parent_system) {
278 for(
size_t i = dir.parent_system->ordered_roots.size(); i-- > 0;) {
279 auto const appended_path = dir.parent_system->ordered_roots[i] + dir.relative_path;
283 DIR* d = opendir(appended_path.c_str());
285 struct dirent* dir_ent =
nullptr;
286 while((dir_ent = readdir(d)) !=
nullptr) {
288 if(dir_ent->d_type != DT_DIR)
291 if(impl::contains_non_ascii(dir_ent->d_name))
295 if(dir_ent->d_name[0] !=
NATIVE(
'.')) {
296 auto search_result = std::find_if(accumulated_results.begin(), accumulated_results.end(),
297 [&rel_name](
auto const& s) { return s.relative_path.compare(rel_name) == 0; });
298 if(search_result == accumulated_results.end()) {
299 accumulated_results.emplace_back(dir.parent_system, rel_name);
307 auto const appended_path = dir.relative_path;
308 DIR* d = opendir(appended_path.c_str());
310 struct dirent* dir_ent =
nullptr;
311 while((dir_ent = readdir(d)) !=
nullptr) {
313 if(dir_ent->d_type != DT_DIR)
316 if(impl::contains_non_ascii(dir_ent->d_name))
320 if(dir_ent->d_name[0] !=
NATIVE(
'.')) {
321 accumulated_results.emplace_back(
nullptr, rel_name);
327 std::sort(accumulated_results.begin(), accumulated_results.end(), [](
directory const& a,
directory const& b) {
328 return std::lexicographical_compare(std::begin(a.relative_path), std::end(a.relative_path), std::begin(b.relative_path),
329 std::end(b.relative_path),
330 [](native_char const& char1, native_char const& char2) { return tolower(char1) < tolower(char2); });
333 return accumulated_results;
341 if(dir.parent_system) {
342 for(
size_t i = dir.parent_system->ordered_roots.size(); i-- > 0;) {
343 native_string dir_path = dir.parent_system->ordered_roots[i] + dir.relative_path;
348 int file_descriptor = open(full_path.c_str(), O_RDONLY | O_NONBLOCK);
349 if(file_descriptor != -1) {
350 return std::optional<file>(
file(file_descriptor, full_path));
355 int file_descriptor = open(full_path.c_str(), O_RDONLY | O_NONBLOCK);
356 if(file_descriptor != -1) {
357 return std::optional<file>(
file(file_descriptor, full_path));
360 return std::optional<file>{};
364 if(dir.parent_system) {
365 for(
size_t i = dir.parent_system->ordered_roots.size(); i-- > 0;) {
370 struct stat stat_buf;
371 int result = stat(full_path.c_str(), &stat_buf);
372 if(result != -1 && S_ISREG(stat_buf.st_mode)) {
373 return std::optional<unopened_file>(
unopened_file(full_path, file_name));
378 struct stat stat_buf;
379 int result = stat(full_path.c_str(), &stat_buf);
380 if(result != -1 && S_ISREG(stat_buf.st_mode)) {
381 return std::optional<unopened_file>(
unopened_file(full_path, file_name));
384 return std::optional<unopened_file>{};
388 fs.ignored_paths.emplace_back(replaced_path);
392 return fs.ordered_roots;
396 for(
auto const& replace_path : fs.ignored_paths) {
397 if(path.starts_with(replace_path))
404 return f.absolute_path;
412 return f.absolute_path;
416 return dir.relative_path;
420 if(dir.parent_system)
425 mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
426 int file_handle = open(full_path.c_str(), O_RDWR | O_CREAT | O_TRUNC, mode);
427 if(file_handle != -1) {
429 int64_t size_remaining = file_size;
431 written = write(file_handle, file_data,
size_t(size_remaining));
432 file_data += written;
433 size_remaining -= written;
434 }
while(written >= 0 && size_remaining > 0);
446 char current_path[FILENAME_MAX];
447 mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
449 strcpy(current_path, path.c_str());
451 for(
char* p = strchr(current_path + 1,
'/'); p; p = strchr(p + 1,
'/')) {
453 int status = mkdir(current_path, mode);
512 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,
char16_t> converter;
513 for(
auto ch : data_in) {
523 return std::string(str);
527 return std::string(str);
532 res.reserve(data_in.size());
533 for(
uint32_t i = 0; i < data_in.size(); ++i) {
534 if(data_in[i] ==
'\\') {
536 if(i + 1 < data_in.size() && data_in[i + 1] ==
'\\')
547 res.reserve(path.size());
548 for(
size_t i = 0; i < path.size(); i++) {
549 res += path[i] ==
'\\' ?
'/' : path[i];
void operator=(file const &other)=delete
bool contains_non_ascii(native_char const *str)
std::vector< unopened_file > list_files(directory const &dir, native_char const *extension)
void add_root(file_system &fs, native_string_view root_path)
void reset(file_system &fs)
native_string win1250_to_native(std::string_view data_in)
void add_relative_root(file_system &fs, native_string_view root_path)
std::vector< directory > list_subdirectories(directory const &dir)
directory open_directory(directory const &dir, native_string_view directory_name)
void add_ignore_path(file_system &fs, native_string_view replaced_path)
native_string utf8_to_native(std::string_view data_in)
native_string extract_state(file_system const &fs)
void make_directories(native_string const &path)
directory get_root(file_system const &fs)
void restore_state(file_system &fs, native_string_view data)
void write_file(directory const &dir, native_string_view file_name, char const *file_data, uint32_t file_size)
directory get_or_create_oos_directory()
std::vector< native_string > list_roots(file_system const &fs)
directory get_or_create_templates_directory()
std::string remove_double_backslashes(std::string_view data_in)
directory get_or_create_settings_directory()
native_string get_full_name(directory const &f)
native_string correct_slashes(native_string_view path)
directory get_or_create_save_game_directory()
std::optional< file > open_file(directory const &dir, native_string_view file_name)
directory get_or_create_root_documents()
directory get_or_create_data_dumps_directory()
bool is_ignored_path(file_system const &fs, native_string_view path)
std::optional< unopened_file > peek_file(directory const &dir, native_string_view file_name)
std::string native_to_utf8(native_string_view data_in)
file_contents view_contents(file const &f)
native_string get_file_name(unopened_file const &f)
directory get_or_create_scenario_directory()
char16_t win1250toUTF16(char in)
std::string_view native_string_view
std::string native_string