From 1a75b90efc7c80aaa4cb4b11e79536675d029a76 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Mon, 26 Feb 2024 14:19:31 +0800 Subject: [PATCH] iso9660: basic directory traversal --- iso9660/byte_position.py | 119 ++++++++++++++++++++++++++ iso9660/csv_input.py | 1 + iso9660/directory_record.csv | 12 +++ iso9660/directory_record.hpp | 32 +++++++ iso9660/directory_record.ods | Bin 17744 -> 18198 bytes iso9660/generate.py | 1 + iso9660/primary_volume_descriptor.csv | 34 ++++++++ iso9660/primary_volume_descriptor.hpp | 76 ++++++++++++++++ iso9660/test.cpp | 66 ++++++++++++++ iso9660/uint_le_be.hpp | 37 ++++++++ 10 files changed, 378 insertions(+) create mode 100644 iso9660/byte_position.py create mode 120000 iso9660/csv_input.py create mode 100644 iso9660/directory_record.csv create mode 100644 iso9660/directory_record.hpp create mode 120000 iso9660/generate.py create mode 100644 iso9660/primary_volume_descriptor.csv create mode 100644 iso9660/primary_volume_descriptor.hpp create mode 100644 iso9660/test.cpp create mode 100644 iso9660/uint_le_be.hpp diff --git a/iso9660/byte_position.py b/iso9660/byte_position.py new file mode 100644 index 0000000..61fef12 --- /dev/null +++ b/iso9660/byte_position.py @@ -0,0 +1,119 @@ +import sys +from dataclasses import dataclass +from os.path import splitext + +from csv_input import read_input +from generate import renderer + +from pprint import pprint + +def parse_bp(s): + if ' to ' in s: + start0, end0 = s.split(' to ') + if '(' in end0 and ')' in end0 and 'LEN_' in end0: + end0 = int(start0) - 1 + start, end = int(start0), int(end0) + return start, end + else: + start, end = int(start0), int(end0) + assert start <= end, (start, end) + return start, end + else: + start = int(s) + return start, start + +def bp_range(start, end): + return set(range(start, end+1)) + +reserved = 0 +def sanitize_field_name(name): + global reserved + if name == "(Reserved for future standardization)" or name == "Unused field": + reserved += 1 + return f"_res{reserved}"; + if '(' in name: + assert 'LEN_' in name, name + name = name.split('(')[0].strip() + + name = name.lower().replace(' ', '_') + return name + +def sanitize_content_name(name): + if name == 'Numerical value': + return 'numerical_value' + else: + return 'bytes' + +@dataclass +class Field: + start: int + end: int + name: str + content: str + +def parse(rows): + seen_bps = set() + seen_names = set() + + for row in rows: + start, end = parse_bp(row['BP']) + _range = bp_range(start, end) + assert seen_bps.intersection(_range) == set(), row + seen_bps = seen_bps.union(_range) + field_name = sanitize_field_name(row["Field name"]) + assert field_name not in seen_names + seen_names.add(field_name) + content_name = sanitize_content_name(row["Content"]) + + yield Field( + start=start, + end=end, + name=field_name, + content=content_name + ) + +type_dict = { + 1: 'uint8_t', + 2: 'uint16_t', + 4: 'uint16_le_be', + 8: 'uint32_le_be', +} + +def header(): + yield "#pragma once" + yield "" + yield "#include " + yield "#include " + yield "" + yield '#include "uint_le_be.hpp"' + yield "" + +def render_fields(input_name, fields): + yield f"struct {input_name} {{" + for field in fields: + field_size = (field.end - field.start) + 1 + if field.content == 'numerical_value': + assert field_size in type_dict, field + type = type_dict[field_size] + yield f"const {type} {field.name};" + else: + if field_size == 1: + yield f"const uint8_t {field.name};" + elif field_size == 0: + yield f"const uint8_t {field.name}[];" + else: + yield f"const uint8_t {field.name}[{field_size}];" + yield "};" + + for field in fields: + yield f"static_assert((offsetof (struct {input_name}, {field.name})) == {field.start - 1});" + +if __name__ == "__main__": + input_file = sys.argv[1] + input_name, _ = splitext(input_file) + rows = read_input(input_file) + fields = list(parse(rows)) + render, out = renderer() + render(header()) + render(render_fields(input_name, fields)) + sys.stdout.write(out.getvalue()) diff --git a/iso9660/csv_input.py b/iso9660/csv_input.py new file mode 120000 index 0000000..3c0b97f --- /dev/null +++ b/iso9660/csv_input.py @@ -0,0 +1 @@ +../regs/gen/csv_input.py \ No newline at end of file diff --git a/iso9660/directory_record.csv b/iso9660/directory_record.csv new file mode 100644 index 0000000..0de1021 --- /dev/null +++ b/iso9660/directory_record.csv @@ -0,0 +1,12 @@ +"BP","Field name","Content" +1,"Length of directory record (LEN_DR)","Numerical value" +2,"Extended attribute record length","Numerical value" +"3 to 10","Location of extent","Numerical value" +"11 to 18","Data length","Numerical value" +"19 to 25","Recording date and time","Recording date and time" +26,"File flags","8 bits" +27,"File unit size","Numerical value" +28,"Interleave gap size","Numerical value" +"29 to 32","Volume sequence number","Numerical value" +33,"Length of file identifier (LEN_FI)","Numerical value" +"34 to (33 + LEN_FI)","File identifier","d-characters, d1-characters, separator 1, separator 2, (00) or (01) byte" diff --git a/iso9660/directory_record.hpp b/iso9660/directory_record.hpp new file mode 100644 index 0000000..63f2c7e --- /dev/null +++ b/iso9660/directory_record.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +#include "uint_le_be.hpp" + +struct directory_record { + const uint8_t length_of_directory_record; + const uint8_t extended_attribute_record_length; + const uint32_le_be location_of_extent; + const uint32_le_be data_length; + const uint8_t recording_date_and_time[7]; + const uint8_t file_flags; + const uint8_t file_unit_size; + const uint8_t interleave_gap_size; + const uint16_le_be volume_sequence_number; + const uint8_t length_of_file_identifier; + const uint8_t file_identifier[]; +}; + +static_assert((offsetof (struct directory_record, length_of_directory_ecord)) == 0); +static_assert((offsetof (struct directory_record, extended_attribute_record_length)) == 1); +static_assert((offsetof (struct directory_record, location_of_extent)) == 2); +static_assert((offsetof (struct directory_record, data_length)) == 10); +static_assert((offsetof (struct directory_record, recording_date_and_time)) == 18); +static_assert((offsetof (struct directory_record, file_flags)) == 25); +static_assert((offsetof (struct directory_record, file_unit_size)) == 26); +static_assert((offsetof (struct directory_record, interleave_gap_size)) == 27); +static_assert((offsetof (struct directory_record, volume_sequence_number)) == 28); +static_assert((offsetof (struct directory_record, length_of_file_identifier)) == 32); +static_assert((offsetof (struct directory_record, file_identifier)) == 33); diff --git a/iso9660/directory_record.ods b/iso9660/directory_record.ods index 9cf171e3ad9a4795e17810c8ebcfaed013db9c27..2332fc490f36f83d71508dc11435a1a1dd8072c8 100644 GIT binary patch delta 6025 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 Fe*jWP9wYz& delta 5523 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 diff --git a/iso9660/generate.py b/iso9660/generate.py new file mode 120000 index 0000000..7242ef6 --- /dev/null +++ b/iso9660/generate.py @@ -0,0 +1 @@ +../regs/gen/generate.py \ No newline at end of file diff --git a/iso9660/primary_volume_descriptor.csv b/iso9660/primary_volume_descriptor.csv new file mode 100644 index 0000000..91eb67b --- /dev/null +++ b/iso9660/primary_volume_descriptor.csv @@ -0,0 +1,34 @@ +"BP","Field name","Content" +"1","Volume descriptor type","Numerical value" +"2 to 6","Standard identifier","CD001" +"7","Volume descriptor version","Numerical value" +"8","Unused field","(00) byte" +"9 to 40","System identifier","a-characters" +"41 to 72","Volume identifier","d-characters" +"73 to 80","Unused field","(00) bytes" +"81 to 88","Volume space size","Numerical value" +"89 to 120","Unused field","(00) bytes" +"121 to 124","Volume set size","Numerical value" +"125 to 128","Volume sequence number","Numerical value" +"129 to 132","Logical block size","Numerical value" +"133 to 140","Path table size","Numerical value" +"141 to 144","Location of occurrence of type L path table","Numerical value" +"145 to 148","Location of optional occurence of type L path table","Numerical value" +"149 to 152","Location of occurence of type M path table","Numerical value" +"153 to 156","Location of optional occurence of type M path table","Numerical value" +"157 to 190","Directory record for root directory","34 bytes" +"191 to 318","Volume set identifier","d-characters" +"319 to 446","Publisher identifier","a-characters" +"447 to 574","Data preparer identifier","a-characters" +"575 to 702","Application identifier","a-characters" +"703 to 739","Copyright file identifier","d-characters, separator 1, separator 2" +"740 to 776","Abstract file identifier","d-characters, separator 1, separator 3" +"777 to 813","Bibliographic file identifier","d-characters, separator 1, separator 4" +"814 to 830","Volume creation date and time","Digit(s), numerical value" +"831 to 847","Volume modification date and time","Digit(s), numerical value" +"848 to 864","Volume expiration date and time","Digit(s), numerical value" +"865 to 881","Volume effective date and time","Digit(s), numerical value" +"882","File structure version","numerical value" +"883","(Reserved for future standardization)","(00) byte" +"884 to 1395","Application use","not specified" +"1396 to 2048","(Reserved for future standardization)","(00) bytes" diff --git a/iso9660/primary_volume_descriptor.hpp b/iso9660/primary_volume_descriptor.hpp new file mode 100644 index 0000000..6aa75d6 --- /dev/null +++ b/iso9660/primary_volume_descriptor.hpp @@ -0,0 +1,76 @@ +#pragma once + +#include +#include + +#include "uint_le_be.hpp" + +struct primary_volume_descriptor { + const uint8_t volume_descriptor_type; + const uint8_t standard_identifier[5]; + const uint8_t volume_descriptor_version; + const uint8_t _res1; + const uint8_t system_identifier[32]; + const uint8_t volume_identifier[32]; + const uint8_t _res2[8]; + const uint32_le_be volume_space_size; + const uint8_t _res3[32]; + const uint16_le_be volume_set_size; + const uint16_le_be volume_sequence_number; + const uint16_le_be logical_block_size; + const uint32_le_be path_table_size; + const uint16_le_be location_of_occurrence_of_type_l_path_table; + const uint16_le_be location_of_optional_occurence_of_type_l_path_table; + const uint16_le_be location_of_occurence_of_type_m_path_table; + const uint16_le_be location_of_optional_occurence_of_type_m_path_table; + const uint8_t directory_record_for_root_directory[34]; + const uint8_t volume_set_identifier[128]; + const uint8_t publisher_identifier[128]; + const uint8_t data_preparer_identifier[128]; + const uint8_t application_identifier[128]; + const uint8_t copyright_file_identifier[37]; + const uint8_t abstract_file_identifier[37]; + const uint8_t bibliographic_file_identifier[37]; + const uint8_t volume_creation_date_and_time[17]; + const uint8_t volume_modification_date_and_time[17]; + const uint8_t volume_expiration_date_and_time[17]; + const uint8_t volume_effective_date_and_time[17]; + const uint8_t file_structure_version; + const uint8_t _res4; + const uint8_t application_use[512]; + const uint8_t _res5[653]; +}; + +static_assert((offsetof (struct primary_volume_descriptor, volume_descriptor_type)) == 0); +static_assert((offsetof (struct primary_volume_descriptor, standard_identifier)) == 1); +static_assert((offsetof (struct primary_volume_descriptor, volume_descriptor_version)) == 6); +static_assert((offsetof (struct primary_volume_descriptor, _res1)) == 7); +static_assert((offsetof (struct primary_volume_descriptor, system_identifier)) == 8); +static_assert((offsetof (struct primary_volume_descriptor, volume_identifier)) == 40); +static_assert((offsetof (struct primary_volume_descriptor, _res2)) == 72); +static_assert((offsetof (struct primary_volume_descriptor, volume_space_size)) == 80); +static_assert((offsetof (struct primary_volume_descriptor, _res3)) == 88); +static_assert((offsetof (struct primary_volume_descriptor, volume_set_size)) == 120); +static_assert((offsetof (struct primary_volume_descriptor, volume_sequence_number)) == 124); +static_assert((offsetof (struct primary_volume_descriptor, logical_block_size)) == 128); +static_assert((offsetof (struct primary_volume_descriptor, path_table_size)) == 132); +static_assert((offsetof (struct primary_volume_descriptor, location_of_occurrence_of_type_l_path_table)) == 140); +static_assert((offsetof (struct primary_volume_descriptor, location_of_optional_occurence_of_type_l_path_table)) == 144); +static_assert((offsetof (struct primary_volume_descriptor, location_of_occurence_of_type_m_path_table)) == 148); +static_assert((offsetof (struct primary_volume_descriptor, location_of_optional_occurence_of_type_m_path_table)) == 152); +static_assert((offsetof (struct primary_volume_descriptor, directory_record_for_root_directory)) == 156); +static_assert((offsetof (struct primary_volume_descriptor, volume_set_identifier)) == 190); +static_assert((offsetof (struct primary_volume_descriptor, publisher_identifier)) == 318); +static_assert((offsetof (struct primary_volume_descriptor, data_preparer_identifier)) == 446); +static_assert((offsetof (struct primary_volume_descriptor, application_identifier)) == 574); +static_assert((offsetof (struct primary_volume_descriptor, copyright_file_identifier)) == 702); +static_assert((offsetof (struct primary_volume_descriptor, abstract_file_identifier)) == 739); +static_assert((offsetof (struct primary_volume_descriptor, bibliographic_file_identifier)) == 776); +static_assert((offsetof (struct primary_volume_descriptor, volume_creation_date_and_time)) == 813); +static_assert((offsetof (struct primary_volume_descriptor, volume_modification_date_and_time)) == 830); +static_assert((offsetof (struct primary_volume_descriptor, volume_expiration_date_and_time)) == 847); +static_assert((offsetof (struct primary_volume_descriptor, volume_effective_date_and_time)) == 864); +static_assert((offsetof (struct primary_volume_descriptor, file_structure_version)) == 881); +static_assert((offsetof (struct primary_volume_descriptor, _res4)) == 882); +static_assert((offsetof (struct primary_volume_descriptor, application_use)) == 883); +static_assert((offsetof (struct primary_volume_descriptor, _res5)) == 1395); diff --git a/iso9660/test.cpp b/iso9660/test.cpp new file mode 100644 index 0000000..1fdab1d --- /dev/null +++ b/iso9660/test.cpp @@ -0,0 +1,66 @@ +#include +#include +#include + +#include "primary_volume_descriptor.hpp" +#include "directory_record.hpp" + +void write_field(const uint8_t * s, const int len) +{ + for (int i = 0; i < len; i++) { + std::cout << s[i]; + } + std::cout << '\n'; +} + +int main() +{ + std::ifstream ifs("test.iso"); + std::string content( (std::istreambuf_iterator(ifs) ), + (std::istreambuf_iterator() ) ); + + const char * str = content.c_str(); + auto pvd = reinterpret_cast(&str[2048 * 16]); + + write_field(pvd->standard_identifier, 5); + + auto root_dr = reinterpret_cast(&pvd->directory_record_for_root_directory); + + std::cout << "root directory record:" << '\n'; + std::cout << root_dr->location_of_extent.get() << '\n'; + std::cout << root_dr->data_length.get() << '\n'; + + uint32_t offset = root_dr->location_of_extent.get() * 2048; + while (true) { + std::cout << "\n\n"; + std::cout << "directory entry offset: " << std::hex << offset << '\n'; + auto dr = reinterpret_cast(&str[offset]); + if (dr->length_of_directory_record == 0) + break; + + std::cout << "length_of_directory_record: "; + std::cout << std::dec << (int)dr->length_of_directory_record << '\n'; + std::cout << "length_of_file_identifier: "; + std::cout << (int)dr->length_of_file_identifier << '\n'; + std::cout << "file_identifier: "; + write_field(dr->file_identifier, dr->length_of_file_identifier); + std::cout << std::hex << "file_flags: " << (int)dr->file_flags << '\n'; + + if (dr->file_flags == 0) { + std::cout << "location_of_extent: " << dr->location_of_extent.get() << '\n'; + std::cout << "data_length: " << std::dec << dr->data_length.get() << '\n'; + + if (dr->file_identifier[0] != '1') { + const uint32_t extent = dr->location_of_extent.get() * 2048; + auto file = reinterpret_cast(&str[extent]); + std::cout << "---begin file content---\n"; + write_field(file, dr->data_length.get()); + std::cout << "---end file content---\n"; + } + } + + offset += dr->length_of_directory_record; + } + + return 0; +} diff --git a/iso9660/uint_le_be.hpp b/iso9660/uint_le_be.hpp new file mode 100644 index 0000000..1e6ded3 --- /dev/null +++ b/iso9660/uint_le_be.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include + +template +struct uint_le_be { + const uint8_t le[(sizeof (T))]; + const uint8_t be[(sizeof (T))]; + + T get() const { + union { + uint8_t u8[(sizeof (T))]; + T uint; + } value; + static_assert((sizeof (value)) == (sizeof (T))); + + if constexpr (std::endian::native == std::endian::little) { + for (uint32_t i = 0; i < (sizeof (T)); i++) { + value.u8[i] = le[i]; + } + return value.uint; + } else { + for (uint32_t i = 0; i < (sizeof (T)); i++) { + value.u8[i] = be[i]; + } + return value.uint; + } + } +}; + +using uint16_le_be = uint_le_be; +using uint32_le_be = uint_le_be; + +static_assert((sizeof (uint16_le_be)) == 4); +static_assert((sizeof (uint32_le_be)) == 8);