LibGfx/JBIG2: Store location of segment data bodies

They're in different places for Sequential/Embedded (right after
the header) and RandomAccess (which has all headers first, followed
by all data bits next).

We don't do anything with the data yet, but now everything's in
place to actually process segment data.
This commit is contained in:
Nico Weber 2024-03-03 21:14:07 -05:00 committed by Andreas Kling
parent 953f6c5d9b
commit 379ef45688
Notes: sideshowbarker 2024-07-17 05:02:35 +09:00

View file

@ -62,6 +62,11 @@ struct SegmentHeader {
Optional<u32> data_length;
};
struct SegmentData {
SegmentHeader header;
ReadonlyBytes data;
};
struct JBIG2LoadingContext {
enum class State {
NotDecoded = 0,
@ -74,6 +79,8 @@ struct JBIG2LoadingContext {
IntSize size;
Optional<u32> number_of_pages;
Vector<SegmentData> segments;
};
static ErrorOr<void> decode_jbig2_header(JBIG2LoadingContext& context)
@ -184,18 +191,45 @@ static ErrorOr<void> 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<ReadonlyBytes> segment_datas;
auto store_and_skip_segment_data = [&](SegmentHeader const& segment_header) -> ErrorOr<void> {
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<SegmentHeader> 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 {};
}