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
1354bool 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
42103fs::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 }
0 commit comments