diff --git a/Userland/Libraries/LibGfx/ImageFormats/JBIG2Loader.cpp b/Userland/Libraries/LibGfx/ImageFormats/JBIG2Loader.cpp index 4a3fcbfc6c..135c90d076 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/JBIG2Loader.cpp +++ b/Userland/Libraries/LibGfx/ImageFormats/JBIG2Loader.cpp @@ -62,6 +62,11 @@ struct SegmentHeader { Optional data_length; }; +struct SegmentData { + SegmentHeader header; + ReadonlyBytes data; +}; + struct JBIG2LoadingContext { enum class State { NotDecoded = 0, @@ -74,6 +79,8 @@ struct JBIG2LoadingContext { IntSize size; Optional number_of_pages; + + Vector segments; }; static ErrorOr decode_jbig2_header(JBIG2LoadingContext& context) @@ -184,18 +191,45 @@ static ErrorOr decode_segment_headers(JBIG2LoadingContext& context) if (context.organization != Organization::Embedded) data = data.slice(sizeof(id_string) + sizeof(u8) + (context.number_of_pages.has_value() ? sizeof(u32) : 0)); FixedMemoryStream stream(data); + + Vector segment_datas; + auto store_and_skip_segment_data = [&](SegmentHeader const& segment_header) -> ErrorOr { + if (!segment_header.data_length.has_value()) + return Error::from_string_literal("JBIG2ImageDecoderPlugin: Can't handle segment without data length yet"); + + size_t start_offset = TRY(stream.tell()); + if (start_offset + segment_header.data_length.value() > data.size()) + return Error::from_string_literal("JBIG2ImageDecoderPlugin: Segment data length exceeds file size"); + ReadonlyBytes segment_data = data.slice(start_offset, segment_header.data_length.value()); + segment_datas.append(segment_data); + + TRY(stream.seek(segment_header.data_length.value(), SeekMode::FromCurrentPosition)); + return {}; + }; + + Vector segment_headers; while (!stream.is_eof()) { auto segment_header = TRY(decode_segment_header(stream)); - if (context.organization != Organization::RandomAccess) { - if (!segment_header.data_length.has_value()) - return Error::from_string_literal("JBIG2ImageDecoderPlugin: Can't handle non-random-access organization segment without data length yet"); - TRY(stream.seek(segment_header.data_length.value(), SeekMode::FromCurrentPosition)); - } + segment_headers.append(segment_header); + + if (context.organization != Organization::RandomAccess) + TRY(store_and_skip_segment_data(segment_header)); // Required per spec for files with RandomAccess organization. if (segment_header.type == SegmentType::EndOfFile) break; } + + if (context.organization == Organization::RandomAccess) { + for (auto const& segment_header : segment_headers) + TRY(store_and_skip_segment_data(segment_header)); + } + + if (segment_headers.size() != segment_datas.size()) + return Error::from_string_literal("JBIG2ImageDecoderPlugin: Segment headers and segment datas have different sizes"); + for (size_t i = 0; i < segment_headers.size(); ++i) + context.segments.append({ segment_headers[i], segment_datas[i] }); + return {}; }