diff --git a/Userland/Libraries/LibArchive/TarStream.h b/Userland/Libraries/LibArchive/TarStream.h index d0764faa4d8..5ffa04991ed 100644 --- a/Userland/Libraries/LibArchive/TarStream.h +++ b/Userland/Libraries/LibArchive/TarStream.h @@ -40,6 +40,9 @@ public: const TarFileHeader& header() const { return m_header; } TarFileStream file_contents(); + template F> + ErrorOr for_each_extended_header(F func); + private: TarFileHeader m_header; InputStream& m_stream; @@ -64,4 +67,51 @@ private: friend class TarFileStream; }; +template F> +inline ErrorOr TarInputStream::for_each_extended_header(F func) +{ + VERIFY(header().content_is_like_extended_header()); + + Archive::TarFileStream file_stream = file_contents(); + + ByteBuffer file_contents_buffer = TRY(ByteBuffer::create_zeroed(header().size())); + VERIFY(file_stream.read(file_contents_buffer) == header().size()); + + StringView file_contents { file_contents_buffer }; + + while (!file_contents.is_empty()) { + // Split off the length (until the first space). + Optional length_end_index = file_contents.find(' '); + if (!length_end_index.has_value()) + return Error::from_string_literal("Malformed extended header: No length found."); + Optional length = file_contents.substring_view(0, length_end_index.value()).to_uint(); + if (!length.has_value()) + return Error::from_string_literal("Malformed extended header: Could not parse length."); + unsigned int remaining_length = length.value(); + + remaining_length -= length_end_index.value() + 1; + file_contents = file_contents.substring_view(length_end_index.value() + 1); + + // Extract the header. + StringView header = file_contents.substring_view(0, remaining_length - 1); + file_contents = file_contents.substring_view(remaining_length - 1); + + // Ensure that the header ends at the expected location. + if (file_contents.length() < 1 || !file_contents.starts_with('\n')) + return Error::from_string_literal("Malformed extended header: Header does not end at expected location."); + file_contents = file_contents.substring_view(1); + + // Find the delimiting '='. + Optional header_delimiter_index = header.find('='); + if (!header_delimiter_index.has_value()) + return Error::from_string_literal("Malformed extended header: Header does not have a delimiter."); + StringView key = header.substring_view(0, header_delimiter_index.value()); + StringView value = header.substring_view(header_delimiter_index.value() + 1); + + func(key, value); + } + + return {}; +} + }