iso_reader.h (5041B)
1 // SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com> 2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) 3 4 #pragma once 5 6 #include "common/types.h" 7 8 #include <memory> 9 #include <optional> 10 #include <string> 11 #include <vector> 12 13 class CDImage; 14 15 class Error; 16 17 class IsoReader 18 { 19 public: 20 enum : u32 21 { 22 SECTOR_SIZE = 2048 23 }; 24 25 #pragma pack(push, 1) 26 27 struct ISOVolumeDescriptorHeader 28 { 29 u8 type_code; 30 char standard_identifier[5]; 31 u8 version; 32 }; 33 static_assert(sizeof(ISOVolumeDescriptorHeader) == 7); 34 35 struct ISOBootRecord 36 { 37 ISOVolumeDescriptorHeader header; 38 char boot_system_identifier[32]; 39 char boot_identifier[32]; 40 u8 data[1977]; 41 }; 42 static_assert(sizeof(ISOBootRecord) == 2048); 43 44 struct ISOPVDDateTime 45 { 46 char year[4]; 47 char month[2]; 48 char day[2]; 49 char hour[2]; 50 char minute[2]; 51 char second[2]; 52 char milliseconds[2]; 53 s8 gmt_offset; 54 }; 55 static_assert(sizeof(ISOPVDDateTime) == 17); 56 57 struct ISOPrimaryVolumeDescriptor 58 { 59 ISOVolumeDescriptorHeader header; 60 u8 unused; 61 char system_identifier[32]; 62 char volume_identifier[32]; 63 char unused2[8]; 64 u32 total_sectors_le; 65 u32 total_sectors_be; 66 char unused3[32]; 67 u16 volume_set_size_le; 68 u16 volume_set_size_be; 69 u16 volume_sequence_number_le; 70 u16 volume_sequence_number_be; 71 u16 block_size_le; 72 u16 block_size_be; 73 u32 path_table_size_le; 74 u32 path_table_size_be; 75 u32 path_table_location_le; 76 u32 optional_path_table_location_le; 77 u32 path_table_location_be; 78 u32 optional_path_table_location_be; 79 u8 root_directory_entry[34]; 80 char volume_set_identifier[128]; 81 char publisher_identifier[128]; 82 char data_preparer_identifier[128]; 83 char application_identifier[128]; 84 char copyright_file_identifier[38]; 85 char abstract_file_identifier[36]; 86 char bibliographic_file_identifier[37]; 87 ISOPVDDateTime volume_creation_time; 88 ISOPVDDateTime volume_modification_time; 89 ISOPVDDateTime volume_expiration_time; 90 ISOPVDDateTime volume_effective_time; 91 u8 structure_version; 92 u8 unused4; 93 u8 application_used[512]; 94 u8 reserved[653]; 95 }; 96 static_assert(sizeof(ISOPrimaryVolumeDescriptor) == 2048); 97 98 struct ISODirectoryEntryDateTime 99 { 100 u8 years_since_1900; 101 u8 month; 102 u8 day; 103 u8 hour; 104 u8 minute; 105 u8 second; 106 s8 gmt_offset; 107 }; 108 109 enum ISODirectoryEntryFlags : u8 110 { 111 ISODirectoryEntryFlag_Hidden = (1 << 0), 112 ISODirectoryEntryFlag_Directory = (1 << 1), 113 ISODirectoryEntryFlag_AssociatedFile = (1 << 2), 114 ISODirectoryEntryFlag_ExtendedAttributePresent = (1 << 3), 115 ISODirectoryEntryFlag_OwnerGroupPermissions = (1 << 4), 116 ISODirectoryEntryFlag_MoreExtents = (1 << 7), 117 }; 118 119 struct ISODirectoryEntry 120 { 121 u8 entry_length; 122 u8 extended_attribute_length; 123 u32 location_le; 124 u32 location_be; 125 u32 length_le; 126 u32 length_be; 127 ISODirectoryEntryDateTime recoding_time; 128 ISODirectoryEntryFlags flags; 129 u8 interleaved_unit_size; 130 u8 interleaved_gap_size; 131 u16 sequence_le; 132 u16 sequence_be; 133 u8 filename_length; 134 135 ALWAYS_INLINE bool IsDirectory() const { return (flags & ISODirectoryEntryFlag_Directory); } 136 ALWAYS_INLINE u32 GetSizeInSectors() const { return (length_le + (SECTOR_SIZE - 1)) / SECTOR_SIZE; } 137 }; 138 139 #pragma pack(pop) 140 141 IsoReader(); 142 ~IsoReader(); 143 144 static std::string_view RemoveVersionIdentifierFromPath(std::string_view path); 145 146 ALWAYS_INLINE const CDImage* GetImage() const { return m_image; } 147 ALWAYS_INLINE u32 GetTrackNumber() const { return m_track_number; } 148 ALWAYS_INLINE u32 GetPVDLBA() const { return m_pvd_lba; } 149 ALWAYS_INLINE const ISOPrimaryVolumeDescriptor& GetPVD() const { return m_pvd; } 150 151 bool Open(CDImage* image, u32 track_number, Error* error = nullptr); 152 153 std::vector<std::string> GetFilesInDirectory(std::string_view path, Error* error = nullptr); 154 std::vector<std::pair<std::string, ISODirectoryEntry>> GetEntriesInDirectory(std::string_view path, 155 Error* error = nullptr); 156 157 std::optional<ISODirectoryEntry> LocateFile(std::string_view path, Error* error); 158 159 bool FileExists(std::string_view path, Error* error = nullptr); 160 bool DirectoryExists(std::string_view path, Error* error = nullptr); 161 bool ReadFile(std::string_view path, std::vector<u8>* data, Error* error = nullptr); 162 bool ReadFile(const ISODirectoryEntry& de, std::vector<u8>* data, Error* error = nullptr); 163 164 private: 165 static std::string_view GetDirectoryEntryFileName(const u8* sector, u32 de_sector_offset); 166 167 bool ReadSector(u8* buf, u32 lsn, Error* error); 168 bool ReadPVD(Error* error); 169 170 std::optional<ISODirectoryEntry> LocateFile(std::string_view path, u8* sector_buffer, u32 directory_record_lba, 171 u32 directory_record_size, Error* error); 172 173 CDImage* m_image; 174 u32 m_track_number; 175 176 ISOPrimaryVolumeDescriptor m_pvd = {}; 177 u32 m_pvd_lba = 0; 178 };