/* * Copyright (c) 2021, sin-ack * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include namespace Kernel { namespace ISO { // The implemented spec here is ECMA 119, available at: // https://www.ecma-international.org/wp-content/uploads/ECMA-119_4th_edition_june_2019.pdf template struct [[gnu::packed]] LittleAndBigEndian { T little; T big; }; // 8.4.26.1 Date and Time Format struct [[gnu::packed]] AsciiDateAndTime { // All of these fields are ASCII digits. :^) u8 year[4]; u8 month[2]; u8 day[2]; u8 hour[2]; u8 minute[2]; u8 second[2]; u8 hundredths_of_second[2]; // From OSDev wiki: // Time zone offset from GMT in 15 minute intervals, starting at // interval -48 (west) and running up to interval 52 (east). So value 0 // indicates interval -48 which equals GMT-12 hours, and value 100 // indicates interval 52 which equals GMT+13 hours. u8 timezone_offset; }; static_assert(sizeof(AsciiDateAndTime) == 17); // 9.1.5 Recording Date and Time (BP 19 to 25) struct [[gnu::packed]] NumericalDateAndTime { u8 years_since_1900; u8 month; u8 day; u8 hour; u8 minute; u8 second; // Same format as AsciiDateAndTime. u8 timezone_offset; }; static_assert(sizeof(NumericalDateAndTime) == 7); // --- Path Table --- // 9.4 Format of a Path Table Record struct [[gnu::packed]] PathTableRecord { u8 directory_identifier_length; u8 extended_attribute_record_length; u32 extent_location; u16 parent_directory_number; u8 directory_identifier[]; }; static_assert(sizeof(PathTableRecord) == 8); // --- Extended Attribute Record --- // 9.5.3 Permissions enum class ExtendedPermissions : u16 { SystemGroupReadable = 1 << 0, SystemGroupExecutable = 1 << 2, UserReadable = 1 << 4, UserExecutable = 1 << 6, GroupReadable = 1 << 8, GroupExecutable = 1 << 10, OtherReadable = 1 << 12, OtherExecutable = 1 << 14, }; AK_ENUM_BITWISE_OPERATORS(ExtendedPermissions); // 9.5.8 Record Format enum class RecordFormat : u8 { NotSpecified = 0, FixedLengthRecords = 1, LittleEndianVariableRecords = 2, BigEndianVariableRecords = 3, // 4-127 are reserved for future standardization. // 128-255 are reserved for system use. }; // 9.5.9 Record Attributes enum class RecordAttributes : u8 { // This value means the record is stored like: \n123456\r. LfCrDelimited = 0, FortranVerticalSpacing = 1, ContainsControlInformation = 2, // 3-255 are reserved for future standardization. }; // 9.5 Format of an Extended Attribute Record struct [[gnu::packed]] ExtendedAttributeRecord { LittleAndBigEndian owner_identification; LittleAndBigEndian group_identification; ExtendedPermissions permissions; AsciiDateAndTime file_creation_date_and_time; AsciiDateAndTime file_modification_date_and_time; AsciiDateAndTime file_expiration_date_and_time; AsciiDateAndTime file_effective_date_and_time; RecordFormat record_format; u8 record_attributes; LittleAndBigEndian record_length; u8 system_identifier[32]; u8 system_use[64]; u8 extended_attribute_record_version; u8 escape_sequence_length; u8 reserved[64]; LittleAndBigEndian application_use_length; // NOTE: Application use is immediately followed by escape sequences (no // padding). u8 application_use_and_escape_sequences[]; }; static_assert(sizeof(ExtendedAttributeRecord) == 250); // --- Files and Directories --- // 9.1.6 File Flags enum class FileFlags : u8 { Hidden = 1 << 0, // The "existence" flag Directory = 1 << 1, AssociatedFile = 1 << 2, Record = 1 << 3, Protection = 1 << 4, // 5 and 6 are reserved. MultiExtent = 1 << 7, }; AK_ENUM_BITWISE_OPERATORS(FileFlags); struct [[gnu::packed]] DirectoryRecordHeader { u8 length; u8 extended_attribute_record_length; LittleAndBigEndian extent_location; LittleAndBigEndian data_length; NumericalDateAndTime recording_date_and_time; FileFlags file_flags; u8 file_unit_size; u8 interleave_gap_size; LittleAndBigEndian volume_sequence_number; u8 file_identifier_length; // NOTE: The file identifier itself is of variable length, so it and the // fields following it are not included in this struct. Instead, they are: // // 34 to (33+file_identifier_length) - file identifier // 1 byte of padding, if file_identifier_length is even // // The remaining bytes are system use (ISO9660 extensions). }; static_assert(sizeof(DirectoryRecordHeader) == 33); // --- Volume Descriptors --- enum class VolumeDescriptorType : u8 { BootRecord = 0, PrimaryVolumeDescriptor = 1, SupplementaryOrEnhancedVolumeDescriptor = 2, VolumePartitionDescriptor = 3, // 4-254 are reserved. VolumeDescriptorSetTerminator = 255, }; // 8.1 Format of a Volume Descriptor struct [[gnu::packed]] VolumeDescriptorHeader { VolumeDescriptorType type; // NOTE: Contains exactly "CD001". u8 identifier[5]; u8 version; }; static_assert(sizeof(VolumeDescriptorHeader) == 7); // 8.2 Boot Record struct [[gnu::packed]] BootRecord { VolumeDescriptorHeader header; u8 boot_system_identifier[32]; u8 boot_identifier[32]; u8 boot_system_use[1977]; }; static_assert(sizeof(BootRecord) == 2048); // 8.3 Volume Descriptor Set Terminator struct [[gnu::packed]] VolumeDescriptorSetTerminator { VolumeDescriptorHeader header; u8 zeros[2041]; }; static_assert(sizeof(VolumeDescriptorSetTerminator) == 2048); // 8.4 Primary Volume Descriptor struct [[gnu::packed]] PrimaryVolumeDescriptor { VolumeDescriptorHeader header; u8 unused1; u8 system_identifier[32]; u8 volume_identifier[32]; u64 unused2; LittleAndBigEndian volume_space_size; u8 unused3[32]; LittleAndBigEndian volume_set_size; LittleAndBigEndian volume_sequence_number; LittleAndBigEndian logical_block_size; LittleAndBigEndian path_table_size; u32 l_path_table_occurrence_location; u32 l_path_table_optional_occurrence_location; u32 m_path_table_occurrence_location; u32 m_path_table_optional_occurrence_location; DirectoryRecordHeader root_directory_record_header; u8 root_directory_identifier; // Exactly 0x00. u8 volume_set_identifier[128]; u8 publisher_identifier[128]; u8 data_preparer_identifier[128]; u8 application_identifier[128]; u8 copyright_file_identifier[37]; u8 abstract_file_identifier[37]; u8 bibliographic_file_identifier[37]; AsciiDateAndTime volume_creation_date_and_time; AsciiDateAndTime volume_modification_date_and_time; AsciiDateAndTime volume_expiration_date_and_time; AsciiDateAndTime volume_effective_date_and_time; u8 file_structure_version; // Always 0x01. u8 unused4; u8 application_use[512]; u8 reserved[653]; }; static_assert(sizeof(PrimaryVolumeDescriptor) == 2048); // 8.6 Volume Partition Descriptor struct [[gnu::packed]] VolumePartitionDescriptor { VolumeDescriptorHeader header; u8 unused; u8 system_identifier[32]; u8 volume_partition_identifier[32]; LittleAndBigEndian volume_partition_location; LittleAndBigEndian volume_partition_size; u8 system_use[1960]; }; static_assert(sizeof(VolumePartitionDescriptor) == 2048); } }