Skip to content
This repository was archived by the owner on Apr 9, 2025. It is now read-only.

Commit ba7c829

Browse files
committed
iso: add supplementary volume support
1 parent 6a2f878 commit ba7c829

File tree

2 files changed

+136
-26
lines changed

2 files changed

+136
-26
lines changed

app/src/main/cpp/iso.cpp

Lines changed: 110 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,63 @@
22
#include "iso.hpp"
33
#include "Utilities/File.h"
44
#include "util/types.hpp"
5+
#include <bit>
56
#include <cctype>
7+
#include <codecvt>
68
#include <cstddef>
79
#include <cstdint>
810
#include <cstdio>
911
#include <ctime>
1012
#include <filesystem>
1113
#include <memory>
14+
#include <span>
15+
#include <string>
16+
17+
static std::string u16_ne_to_string(const char16_t *bytes, std::size_t count) {
18+
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
19+
return convert.to_bytes(bytes, bytes + count);
20+
}
21+
22+
static std::string u16_se_to_string(const char16_t *bytes, std::size_t count) {
23+
auto seBytes = (se_t<char16_t, true, alignof(char16_t)> *)bytes;
24+
25+
std::vector<char16_t> neBytes(count);
26+
for (std::size_t i = 0; i < count; ++i) {
27+
neBytes[i] = seBytes[i];
28+
}
29+
30+
return u16_ne_to_string(neBytes.data(), neBytes.size());
31+
}
32+
33+
static std::string u16_be_to_string(const char16_t *bytes, std::size_t count) {
34+
if constexpr (std::endian::native == std::endian::big) {
35+
return u16_ne_to_string(bytes, count);
36+
} else {
37+
return u16_se_to_string(bytes, count);
38+
}
39+
}
40+
41+
static std::string decodeString(std::string_view data,
42+
iso::StringEncoding encoding) {
43+
switch (encoding) {
44+
case iso::StringEncoding::ascii:
45+
break;
46+
47+
case iso::StringEncoding::utf16_be:
48+
return u16_be_to_string((char16_t *)data.data(), data.size() / 2);
49+
}
50+
51+
return std::string(data);
52+
}
1253

1354
bool iso_fs::initialize() {
1455
constexpr std::size_t primaryVolumeDescOffset = 16;
1556
ensure(m_dev->block_size() >= sizeof(iso::VolumeHeader));
1657
std::vector<std::byte> block(m_dev->block_size());
1758

59+
std::optional<iso::PrimaryVolumeDescriptor> primaryVolume;
60+
std::optional<iso::PrimaryVolumeDescriptor> supplementaryVolume;
61+
1862
for (std::size_t i = 0; i < 256; ++i) {
1963
if (m_dev->read(primaryVolumeDescOffset + i, block.data(), 1) != 1) {
2064
break;
@@ -26,17 +70,34 @@ bool iso_fs::initialize() {
2670
break;
2771
}
2872

29-
if (header->type != 1 ||
30-
std::memcmp(header->standard_id, "CD001", 5) != 0) {
73+
if (std::memcmp(header->standard_id, "CD001", 5) != 0) {
3174
continue;
3275
}
3376

34-
auto pvd = reinterpret_cast<iso::PrimaryVolumeDescriptor *>(block.data());
35-
m_root_dir = pvd->root;
36-
return true;
77+
if (header->type == 1) {
78+
primaryVolume =
79+
*reinterpret_cast<iso::PrimaryVolumeDescriptor *>(block.data());
80+
continue;
81+
}
82+
83+
if (header->type == 2) {
84+
std::printf("found supplementary volume\n");
85+
supplementaryVolume =
86+
*reinterpret_cast<iso::PrimaryVolumeDescriptor *>(block.data());
87+
continue;
88+
}
89+
}
90+
91+
if (!primaryVolume) {
92+
return false;
3793
}
3894

39-
return false;
95+
auto &pvd = supplementaryVolume ? *supplementaryVolume : *primaryVolume;
96+
m_encoding = supplementaryVolume ? iso::StringEncoding::utf16_be
97+
: iso::StringEncoding::ascii;
98+
m_root_dir = pvd.root;
99+
100+
return true;
40101
}
41102

42103
fs::file iso_fs::open(const std::filesystem::path &path, fs::open_mode mode) {
@@ -160,18 +221,19 @@ iso_fs::read_dir(const iso::DirEntry &entry) {
160221
}
161222

162223
auto block_size = m_dev->block_size();
163-
auto total_block_count = 1;
224+
auto total_block_count = (entry.length.value() + block_size - 1) / block_size;
225+
auto total_buffer_block_count = std::min<std::size_t>(total_block_count, 10);
164226

165-
std::vector<std::byte> buffer(total_block_count * block_size);
227+
std::vector<std::byte> buffer(total_buffer_block_count * block_size);
166228
auto first_block = entry.lba.value();
167229

168230
std::vector<iso::DirEntry> isoEntries;
169231
std::vector<std::string> names;
170232

171-
for (std::size_t block = first_block,
172-
end = first_block + entry.length.value() / block_size;
233+
for (std::size_t block = first_block, end = first_block + total_block_count;
173234
block < end;) {
174-
auto block_count = m_dev->read(block, buffer.data(), total_block_count);
235+
auto block_count =
236+
m_dev->read(block, buffer.data(), total_buffer_block_count);
175237
block += block_count;
176238

177239
std::size_t buffer_offset = 0;
@@ -181,33 +243,60 @@ iso_fs::read_dir(const iso::DirEntry &entry) {
181243
while (buffer_offset < buffer_size) {
182244
auto item = reinterpret_cast<const iso::DirEntry *>(buffer.data() +
183245
buffer_offset);
184-
185-
buffer_offset += item->entry_length;
186-
187-
if (item->entry_length < sizeof(iso::DirEntry)) {
246+
if (item->entry_length == 0) {
188247
buffer_offset += block_size;
189248
buffer_offset &= ~(block_size - 1);
190249
continue;
191250
}
192251

252+
auto filename_end =
253+
sizeof(iso::DirEntry) +
254+
((item->filename_length + 1) & ~static_cast<std::size_t>(1));
255+
256+
if (item->entry_length < filename_end) {
257+
buffer_offset += item->entry_length;
258+
continue;
259+
}
260+
261+
auto susp_area = std::span(buffer.data() + buffer_offset + filename_end,
262+
item->entry_length - filename_end);
263+
struct [[gnu::packed]] SuspHeader {
264+
char signature[2];
265+
u8 length;
266+
u8 version;
267+
};
268+
269+
if (susp_area.size() > sizeof(SuspHeader)) {
270+
auto susp_header = reinterpret_cast<SuspHeader *>(susp_area.data());
271+
272+
// TODO: extensions support
273+
}
274+
275+
buffer_offset += item->entry_length;
276+
193277
if (item->filename_length == 0 ||
194278
item->filename_length + sizeof(iso::DirEntry) > item->entry_length) {
195279
continue;
196280
}
197281

198-
auto filename = std::string_view(reinterpret_cast<const char *>(item + 1),
199-
item->filename_length);
282+
auto filename =
283+
item->filename_length > 1
284+
? decodeString({reinterpret_cast<const char *>(item + 1),
285+
item->filename_length},
286+
m_encoding)
287+
: std::string{};
200288

201-
if (filename.length() == 1) {
289+
if (item->filename_length == 1) {
290+
char c = *reinterpret_cast<const char *>(item + 1);
202291
// can be special name
203-
if (filename[0] == 0) {
292+
if (c == 0) {
204293
filename = ".";
205-
} else if (filename[0] == 1) {
294+
} else if (c == 1) {
206295
filename = "..";
207296
}
208297
}
209298

210-
filename = filename.substr(0, filename.find_first_of(";\0\n"));
299+
filename = filename.substr(0, filename.find(';'));
211300
if (filename.empty()) {
212301
continue;
213302
}

app/src/main/cpp/iso.hpp

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -126,11 +126,11 @@ struct PrimaryVolumeDescriptor {
126126
le_be_pair<u16> volume_set_size;
127127
le_be_pair<u16> vol_seq_num;
128128
le_be_pair<u16> block_size;
129-
le_be_pair<u32> patch_table_size;
130-
le_t<u32> patch_table_block_le;
131-
le_t<u32> ext_patch_table_block_le;
132-
le_t<u32> patch_table_block_be;
133-
le_t<u32> ext_patch_table_block_be;
129+
le_be_pair<u32> path_table_size;
130+
le_t<u32> path_table_block_le;
131+
le_t<u32> ext_path_table_block_le;
132+
be_t<u32> path_table_block_be;
133+
be_t<u32> ext_path_table_block_be;
134134
DirEntry root;
135135
u8 pad3;
136136
uint8_t volume_set_id[128];
@@ -147,6 +147,26 @@ struct PrimaryVolumeDescriptor {
147147
uint8_t version;
148148
uint8_t pad4;
149149
uint8_t app_used[512];
150+
151+
u32 path_table_block() const {
152+
if constexpr (std::endian::native == std::endian::little) {
153+
return path_table_block_le;
154+
} else {
155+
return path_table_block_be;
156+
}
157+
}
158+
};
159+
160+
struct PathTableEntryHeader {
161+
u8 name_length;
162+
u8 ext_attr_length;
163+
le_t<u32> location;
164+
le_t<u16> parent_id;
165+
};
166+
167+
enum class StringEncoding {
168+
ascii,
169+
utf16_be,
150170
};
151171

152172
#pragma pack(pop)
@@ -155,6 +175,7 @@ struct PrimaryVolumeDescriptor {
155175
class iso_fs final : public fs_provider {
156176
std::unique_ptr<block_dev> m_dev;
157177
iso::DirEntry m_root_dir;
178+
iso::StringEncoding m_encoding = iso::StringEncoding::ascii;
158179

159180
public:
160181
iso_fs() = default;

0 commit comments

Comments
 (0)