1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 21:17:44 +00:00

LibGfx/TIFF: Ensure baseline tags presence before decoding

This allows us to reject invalid images before trying to decode them.
The spec requires more tag to be present[1] but as we don't use them for
decoding I don't see the point.

[1] - XResolution, YResolution and ResolutionUnit
This commit is contained in:
Lucas CHOLLET 2023-12-23 13:08:57 -05:00 committed by Andreas Kling
parent ec2b4c271f
commit a31b988473
2 changed files with 26 additions and 10 deletions

View file

@ -96,7 +96,7 @@ class ExtraSample(EnumWithExportName):
UnassociatedAlpha = 2
tag_fields = ['id', 'types', 'counts', 'default', 'name', 'associated_enum']
tag_fields = ['id', 'types', 'counts', 'default', 'name', 'associated_enum', 'is_required']
Tag = namedtuple(
'Tag',
@ -106,16 +106,17 @@ Tag = namedtuple(
# FIXME: Some tag have only a few allowed values, we should ensure that
known_tags: List[Tag] = [
Tag('256', [TIFFType.UnsignedShort, TIFFType.UnsignedLong], [1], None, "ImageWidth"),
Tag('257', [TIFFType.UnsignedShort, TIFFType.UnsignedLong], [1], None, "ImageHeight"),
Tag('258', [TIFFType.UnsignedShort], [], None, "BitsPerSample"),
Tag('259', [TIFFType.UnsignedShort], [1], None, "Compression", Compression),
Tag('262', [TIFFType.UnsignedShort], [1], None, "PhotometricInterpretation", PhotometricInterpretation),
Tag('273', [TIFFType.UnsignedShort, TIFFType.UnsignedLong], [], None, "StripOffsets"),
Tag('256', [TIFFType.UnsignedShort, TIFFType.UnsignedLong], [1], None, "ImageWidth", is_required=True),
Tag('257', [TIFFType.UnsignedShort, TIFFType.UnsignedLong], [1], None, "ImageHeight", is_required=True),
Tag('258', [TIFFType.UnsignedShort], [], None, "BitsPerSample", is_required=True),
Tag('259', [TIFFType.UnsignedShort], [1], None, "Compression", Compression, is_required=True),
Tag('262', [TIFFType.UnsignedShort], [1], None, "PhotometricInterpretation",
PhotometricInterpretation, is_required=True),
Tag('273', [TIFFType.UnsignedShort, TIFFType.UnsignedLong], [], None, "StripOffsets", is_required=True),
Tag('274', [TIFFType.UnsignedShort], [1], Orientation.Default, "Orientation", Orientation),
Tag('277', [TIFFType.UnsignedShort], [1], None, "SamplesPerPixel"),
Tag('278', [TIFFType.UnsignedShort, TIFFType.UnsignedLong], [1], None, "RowsPerStrip"),
Tag('279', [TIFFType.UnsignedShort, TIFFType.UnsignedLong], [], None, "StripByteCounts"),
Tag('277', [TIFFType.UnsignedShort], [1], None, "SamplesPerPixel", is_required=True),
Tag('278', [TIFFType.UnsignedShort, TIFFType.UnsignedLong], [1], None, "RowsPerStrip", is_required=True),
Tag('279', [TIFFType.UnsignedShort, TIFFType.UnsignedLong], [], None, "StripByteCounts", is_required=True),
Tag('282', [TIFFType.UnsignedRational], [], None, "XResolution"),
Tag('283', [TIFFType.UnsignedRational], [], None, "YResolution"),
Tag('284', [TIFFType.UnsignedShort], [], PlanarConfiguration.Chunky, "PlanarConfiguration", PlanarConfiguration),
@ -133,6 +134,8 @@ HANDLE_TAG_SIGNATURE_TEMPLATE = ("ErrorOr<void> {namespace}handle_tag(Metadata&
HANDLE_TAG_SIGNATURE = HANDLE_TAG_SIGNATURE_TEMPLATE.format(namespace="")
HANDLE_TAG_SIGNATURE_TIFF_NAMESPACE = HANDLE_TAG_SIGNATURE_TEMPLATE.format(namespace="TIFF::")
ENSURE_BASELINE_TAG_PRESENCE = "ErrorOr<void> ensure_baseline_tags_presence(Metadata const& metadata)"
LICENSE = R"""/*
* Copyright (c) 2023, Lucas Chollet <lucas.chollet@serenityos.org>
*
@ -352,6 +355,7 @@ using Value = Variant<ByteBuffer, String, u32, Rational<u32>, i32, Rational<i32>
{export_enum_to_string_converter([tag.associated_enum for tag in known_tags if tag.associated_enum] + [TIFFType])}
{HANDLE_TAG_SIGNATURE};
{ENSURE_BASELINE_TAG_PRESENCE};
}}
@ -434,6 +438,10 @@ def generate_tag_handler_file(tags: List[Tag]) -> str:
name_for_enum_tag_value(static_cast<{tag.associated_enum.export_name()}>(v.get<u32>()))));"""
for tag in tags if tag.associated_enum])
ensure_tag_presence = '\n'.join([fR""" if (!metadata.{pascal_case_to_snake_case(tag.name)}().has_value())
return Error::from_string_literal("Unable to decode image, missing required tag {tag.name}.");
""" for tag in filter(lambda tag: tag.is_required, known_tags)])
output = fR"""{LICENSE}
#include <AK/Debug.h>
@ -467,6 +475,13 @@ static String value_formatter(u32 tag_id, Value const& v) {{
return MUST(builder.to_string());
}}
{ENSURE_BASELINE_TAG_PRESENCE}
{{
{ensure_tag_presence}
return {{}};
}}
{HANDLE_TAG_SIGNATURE}
{{
switch (tag) {{