blob: 4c717fd0de620643717434ac798a512488b3353e (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
#include "impl/file-browser-posix.hh"
#include <string>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
namespace nes::app::mac
{
file_browser_posix::file_browser_posix()
{
reopen_directory(path_.get_path());
}
file_browser_posix::~file_browser_posix()
{
if (it_) { closedir(it_); }
}
auto file_browser_posix::seek(u32 const pos) -> void
{
if (it_pos_ > pos)
{
reopen_directory(path_.get_path());
}
while (it_pos_ < pos)
{
if (!read_next(nullptr)) { break; }
}
}
auto file_browser_posix::read_next(item* out_item) -> bool
{
if (!it_) { return false; }
while (true)
{
errno = 0;
auto const entry = readdir(it_);
if (!entry)
{
if (errno) { perror("file_browser_posix: readdir"); }
return false;
}
auto const name = std::string_view{ entry->d_name };
if (name.length() > max_name_length) { continue; }
if (name[0] == '.') { continue; }
auto type = item_type::directory;
if (entry->d_type == DT_DIR) { type = item_type::directory; }
else if (entry->d_type == DT_REG) { type = item_type::file; }
else { continue; }
it_pos_ += 1;
if (out_item) { *out_item = item{ type, name }; }
return true;
}
}
auto file_browser_posix::navigate_up() -> status
{
auto new_path = path_;
if (auto const s = new_path.pop(); s != status::success) { return s; }
if (auto const s = reopen_directory(new_path.get_path()); s != status::success) { return s; }
path_ = new_path;
return status::success;
}
auto file_browser_posix::navigate(std::string_view const item) -> status
{
auto new_path = path_;
if (auto const s = new_path.push(item); s != status::success) { return s; }
if (auto const s = reopen_directory(new_path.get_path()); s != status::success) { return s; }
path_ = new_path;
return status::success;
}
auto file_browser_posix::load(std::string_view const item, span<u8> const buffer, u32* out_length) -> status
{
auto file_path = path_;
if (auto const s = file_path.push(item); s != status::success) { return s; }
auto const file_path_str = std::string{ file_path.get_path() };
auto const fd = open(file_path_str.c_str(), O_RDONLY);
if (fd == -1)
{
perror("file_browser_posix: open");
return status::error_system_error;
}
auto const res = read(fd, buffer.get_data(), buffer.get_length());
if (res < 0)
{
perror("file_browser_posix: read");
close(fd);
return status::error_system_error;
}
if (out_length) { *out_length = static_cast<u32>(res); }
auto remaining = char{};
if (read(fd, &remaining, 1) != 0)
{
// File was too long.
close(fd);
return status::error_invalid_ines_data;
}
close(fd);
return status::success;
}
auto file_browser_posix::reopen_directory(std::string_view const path) -> status
{
auto const path_str = std::string{ path };
auto const new_it = opendir(path_str.c_str());
if (!new_it)
{
perror("file_browser_posix: opendir");
return status::error_system_error;
}
if (it_) { closedir(it_); }
it_ = new_it;
it_pos_ = 0;
return status::success;
}
} // namespace nes::app::mac
|