From 4b01f2f15880152d9a28c9702a1c1b3b53c1ab2c Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Fri, 8 Mar 2024 20:02:30 -0500 Subject: [PATCH] LibGfx/JBIG2: Implement decode_extension() Only logs the data to dbgln(). All jb2 files in ghostpdl/tests start with this segment. --- .../LibGfx/ImageFormats/JBIG2Loader.cpp | 65 ++++++++++++++++++- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/Userland/Libraries/LibGfx/ImageFormats/JBIG2Loader.cpp b/Userland/Libraries/LibGfx/ImageFormats/JBIG2Loader.cpp index 4edd8a9757..0ab0a61aa8 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/JBIG2Loader.cpp +++ b/Userland/Libraries/LibGfx/ImageFormats/JBIG2Loader.cpp @@ -5,7 +5,9 @@ */ #include +#include #include +#include // Spec: ITU-T_T_88__08_2018.pdf in the zip file here: // https://www.itu.int/rec/T-REC-T.88-201808-I @@ -445,9 +447,68 @@ static ErrorOr decode_color_palette(JBIG2LoadingContext&, SegmentData cons return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot decode color palette yet"); } -static ErrorOr decode_extension(JBIG2LoadingContext&, SegmentData const&) +static ErrorOr decode_extension(JBIG2LoadingContext&, SegmentData const& segment) { - return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot decode extension yet"); + // 7.4.14 Extension segment syntax + FixedMemoryStream stream { segment.data }; + + enum ExtensionType { + SingleByteCodedComment = 0x20000000, + MultiByteCodedComment = 0x20000002, + }; + u32 type = TRY(stream.read_value>()); + + auto read_string = [&]() -> ErrorOr> { + Vector result; + do { + result.append(TRY(stream.read_value>())); + } while (result.last()); + result.take_last(); + return result; + }; + + switch (type) { + case SingleByteCodedComment: { + // 7.4.15.1 Single-byte coded comment + // Pairs of zero-terminated ISO/IEC 8859-1 (latin1) pairs, terminated by another \0. + while (true) { + auto first_bytes = TRY(read_string.template operator()()); + if (first_bytes.is_empty()) + break; + + auto second_bytes = TRY(read_string.template operator()()); + + auto first = TRY(TextCodec::decoder_for("ISO-8859-1"sv)->to_utf8(StringView { first_bytes })); + auto second = TRY(TextCodec::decoder_for("ISO-8859-1"sv)->to_utf8(StringView { second_bytes })); + dbgln("JBIG2ImageDecoderPlugin: key '{}', value '{}'", first, second); + } + if (!stream.is_eof()) + return Error::from_string_literal("JBIG2ImageDecoderPlugin: Trailing data after SingleByteCodedComment"); + return {}; + } + case MultiByteCodedComment: { + // 7.4.15.2 Multi-byte coded comment + // Pairs of (two-byte-)zero-terminated UCS-2 pairs, terminated by another \0\0. + while (true) { + auto first_ucs2 = TRY(read_string.template operator()()); + if (first_ucs2.is_empty()) + break; + + auto second_ucs2 = TRY(read_string.template operator()()); + + auto first = TRY(Utf16View(first_ucs2).to_utf8()); + auto second = TRY(Utf16View(second_ucs2).to_utf8()); + dbgln("JBIG2ImageDecoderPlugin: key '{}', value '{}'", first, second); + } + if (!stream.is_eof()) + return Error::from_string_literal("JBIG2ImageDecoderPlugin: Trailing data after MultiByteCodedComment"); + return {}; + } + } + + // FIXME: If bit 31 in `type` is not set, the extension isn't necessary, and we could ignore it. + dbgln("JBIG2ImageDecoderPlugin: Unknown extension type {:#x}", type); + return Error::from_string_literal("JBIG2ImageDecoderPlugin: Unknown extension type"); } static ErrorOr decode_data(JBIG2LoadingContext& context)