Let std/png report metadata after the first frame
Fixes #58
diff --git a/internal/cgen/auxiliary/image.cc b/internal/cgen/auxiliary/image.cc
index 1c58016..f46ea9b 100644
--- a/internal/cgen/auxiliary/image.cc
+++ b/internal/cgen/auxiliary/image.cc
@@ -310,6 +310,7 @@
wuffs_base__image_config image_config = wuffs_base__null_image_config();
sync_io::DynIOBuffer raw_metadata_buf(max_incl_metadata_length);
uint64_t start_pos = io_buf.reader_position();
+ bool interested_in_metadata_after_the_frame = false;
bool redirected = false;
int32_t fourcc = 0;
redirect:
@@ -384,6 +385,7 @@
image_decoder->set_report_metadata(WUFFS_BASE__FOURCC__CHRM, true);
}
if (flags & DecodeImageArgFlags::REPORT_METADATA_EXIF) {
+ interested_in_metadata_after_the_frame = true;
image_decoder->set_report_metadata(WUFFS_BASE__FOURCC__EXIF, true);
}
if (flags & DecodeImageArgFlags::REPORT_METADATA_GAMA) {
@@ -393,12 +395,14 @@
image_decoder->set_report_metadata(WUFFS_BASE__FOURCC__ICCP, true);
}
if (flags & DecodeImageArgFlags::REPORT_METADATA_KVP) {
+ interested_in_metadata_after_the_frame = true;
image_decoder->set_report_metadata(WUFFS_BASE__FOURCC__KVP, true);
}
if (flags & DecodeImageArgFlags::REPORT_METADATA_SRGB) {
image_decoder->set_report_metadata(WUFFS_BASE__FOURCC__SRGB, true);
}
if (flags & DecodeImageArgFlags::REPORT_METADATA_XMP) {
+ interested_in_metadata_after_the_frame = true;
image_decoder->set_report_metadata(WUFFS_BASE__FOURCC__XMP, true);
}
}
@@ -433,7 +437,9 @@
}
}
} while (false);
- raw_metadata_buf.drop();
+ if (!interested_in_metadata_after_the_frame) {
+ raw_metadata_buf.drop();
+ }
// Select the pixel format.
uint32_t w = image_config.pixcfg.width();
@@ -494,6 +500,12 @@
image_decoder->decode_frame_config(&frame_config, &io_buf);
if (id_dfc_status.repr == nullptr) {
break;
+ } else if (id_dfc_status.repr == wuffs_base__note__metadata_reported) {
+ std::string error_message = DecodeImageHandleMetadata(
+ image_decoder, callbacks, input, io_buf, raw_metadata_buf);
+ if (!error_message.empty()) {
+ return DecodeImageResult(std::move(error_message));
+ }
} else if (id_dfc_status.repr != wuffs_base__suspension__short_read) {
return DecodeImageResult(id_dfc_status.message());
} else if (io_buf.meta.closed) {
@@ -535,6 +547,35 @@
}
}
}
+
+ // Decode any metadata after the frame.
+ if (interested_in_metadata_after_the_frame) {
+ while (true) {
+ wuffs_base__status id_dfc_status =
+ image_decoder->decode_frame_config(NULL, &io_buf);
+ if (id_dfc_status.repr == wuffs_base__note__end_of_data) {
+ break;
+ } else if (id_dfc_status.repr == nullptr) {
+ continue;
+ } else if (id_dfc_status.repr == wuffs_base__note__metadata_reported) {
+ std::string error_message = DecodeImageHandleMetadata(
+ image_decoder, callbacks, input, io_buf, raw_metadata_buf);
+ if (!error_message.empty()) {
+ return DecodeImageResult(std::move(error_message));
+ }
+ } else if (id_dfc_status.repr != wuffs_base__suspension__short_read) {
+ return DecodeImageResult(id_dfc_status.message());
+ } else if (io_buf.meta.closed) {
+ return DecodeImageResult(DecodeImage_UnexpectedEndOfFile);
+ } else {
+ std::string error_message = input.CopyIn(&io_buf);
+ if (!error_message.empty()) {
+ return DecodeImageResult(std::move(error_message));
+ }
+ }
+ }
+ }
+
return DecodeImageResult(std::move(alloc_pixbuf_result.mem_owner),
pixel_buffer, std::move(message));
}
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index a34439e..2f0b4ee 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -37915,7 +37915,8 @@
static wuffs_base__status
wuffs_png__decoder__decode_other_chunk(
wuffs_png__decoder* self,
- wuffs_base__io_buffer* a_src);
+ wuffs_base__io_buffer* a_src,
+ bool a_framy);
static wuffs_base__status
wuffs_png__decoder__decode_actl(
@@ -39772,7 +39773,7 @@
if (a_src) {
a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
- wuffs_base__status t_4 = wuffs_png__decoder__decode_other_chunk(self, a_src);
+ wuffs_base__status t_4 = wuffs_png__decoder__decode_other_chunk(self, a_src, false);
v_status = t_4;
if (a_src) {
iop_a_src = a_src->data.ptr + a_src->meta.ri;
@@ -40234,7 +40235,8 @@
static wuffs_base__status
wuffs_png__decoder__decode_other_chunk(
wuffs_png__decoder* self,
- wuffs_base__io_buffer* a_src) {
+ wuffs_base__io_buffer* a_src,
+ bool a_framy) {
wuffs_base__status status = wuffs_base__make_status(NULL);
const uint8_t* iop_a_src = NULL;
@@ -40252,7 +40254,7 @@
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
- if (self->private_impl.f_chunk_type == 1163152464) {
+ if ((self->private_impl.f_chunk_type == 1163152464) && ! a_framy) {
if (self->private_impl.f_seen_plte) {
status = wuffs_base__make_status(wuffs_png__error__bad_chunk);
goto exit;
@@ -40279,43 +40281,8 @@
status = wuffs_base__make_status(wuffs_png__error__bad_chunk);
goto exit;
}
- } else if (self->private_impl.f_chunk_type == 1280598881) {
- if (self->private_impl.f_seen_actl) {
- status = wuffs_base__make_status(wuffs_png__error__bad_chunk);
- goto exit;
- }
- if (a_src) {
- a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
- }
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
- status = wuffs_png__decoder__decode_actl(self, a_src);
- if (a_src) {
- iop_a_src = a_src->data.ptr + a_src->meta.ri;
- }
- if (status.repr) {
- goto suspend;
- }
- self->private_impl.f_seen_actl = true;
- } else if (self->private_impl.f_chunk_type == 1297238115) {
- if (self->private_impl.f_report_metadata_chrm) {
- if (self->private_impl.f_seen_chrm) {
- status = wuffs_base__make_status(wuffs_png__error__bad_chunk);
- goto exit;
- }
- if (a_src) {
- a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
- }
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
- status = wuffs_png__decoder__decode_chrm(self, a_src);
- if (a_src) {
- iop_a_src = a_src->data.ptr + a_src->meta.ri;
- }
- if (status.repr) {
- goto suspend;
- }
- self->private_impl.f_seen_chrm = true;
- }
- } else if (self->private_impl.f_chunk_type == 1716082789) {
+ }
+ if (self->private_impl.f_chunk_type == 1716082789) {
if (self->private_impl.f_report_metadata_exif) {
if (self->private_impl.f_seen_exif) {
status = wuffs_base__make_status(wuffs_png__error__bad_chunk);
@@ -40324,7 +40291,7 @@
if (a_src) {
a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
status = wuffs_png__decoder__decode_exif(self, a_src);
if (a_src) {
iop_a_src = a_src->data.ptr + a_src->meta.ri;
@@ -40334,97 +40301,6 @@
}
self->private_impl.f_seen_exif = true;
}
- } else if (self->private_impl.f_chunk_type == 1280598886) {
- if (self->private_impl.f_seen_fctl) {
- status = wuffs_base__make_status(wuffs_png__error__bad_chunk);
- goto exit;
- }
- if (a_src) {
- a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
- }
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(5);
- status = wuffs_png__decoder__decode_fctl(self, a_src);
- if (a_src) {
- iop_a_src = a_src->data.ptr + a_src->meta.ri;
- }
- if (status.repr) {
- goto suspend;
- }
- self->private_impl.f_seen_fctl = true;
- } else if (self->private_impl.f_chunk_type == 1095582055) {
- if (self->private_impl.f_report_metadata_gama) {
- if (self->private_impl.f_seen_gama) {
- status = wuffs_base__make_status(wuffs_png__error__bad_chunk);
- goto exit;
- }
- if (a_src) {
- a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
- }
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(6);
- status = wuffs_png__decoder__decode_gama(self, a_src);
- if (a_src) {
- iop_a_src = a_src->data.ptr + a_src->meta.ri;
- }
- if (status.repr) {
- goto suspend;
- }
- self->private_impl.f_seen_gama = true;
- }
- } else if (self->private_impl.f_chunk_type == 1346585449) {
- if (self->private_impl.f_report_metadata_iccp) {
- if (self->private_impl.f_seen_iccp) {
- status = wuffs_base__make_status(wuffs_png__error__bad_chunk);
- goto exit;
- }
- if (a_src) {
- a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
- }
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(7);
- status = wuffs_png__decoder__decode_iccp(self, a_src);
- if (a_src) {
- iop_a_src = a_src->data.ptr + a_src->meta.ri;
- }
- if (status.repr) {
- goto suspend;
- }
- self->private_impl.f_seen_iccp = true;
- }
- } else if (self->private_impl.f_chunk_type == 1111970419) {
- if (self->private_impl.f_report_metadata_srgb) {
- if (self->private_impl.f_seen_srgb) {
- status = wuffs_base__make_status(wuffs_png__error__bad_chunk);
- goto exit;
- }
- if (a_src) {
- a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
- }
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(8);
- status = wuffs_png__decoder__decode_srgb(self, a_src);
- if (a_src) {
- iop_a_src = a_src->data.ptr + a_src->meta.ri;
- }
- if (status.repr) {
- goto suspend;
- }
- self->private_impl.f_seen_srgb = true;
- }
- } else if (self->private_impl.f_chunk_type == 1397641844) {
- if (self->private_impl.f_seen_trns || (self->private_impl.f_color_type > 3) || ((self->private_impl.f_color_type == 3) && ! self->private_impl.f_seen_plte)) {
- status = wuffs_base__make_status(wuffs_png__error__bad_chunk);
- goto exit;
- }
- if (a_src) {
- a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
- }
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(9);
- status = wuffs_png__decoder__decode_trns(self, a_src);
- if (a_src) {
- iop_a_src = a_src->data.ptr + a_src->meta.ri;
- }
- if (status.repr) {
- goto suspend;
- }
- self->private_impl.f_seen_trns = true;
} else if ((self->private_impl.f_chunk_type == 1951945833) || (self->private_impl.f_chunk_type == 1951942004) || (self->private_impl.f_chunk_type == 1951945850)) {
if (self->private_impl.f_report_metadata_kvp) {
self->private_impl.f_metadata_flavor = 4;
@@ -40433,6 +40309,135 @@
self->private_impl.f_metadata_y = 0;
self->private_impl.f_metadata_z = 0;
}
+ } else if ( ! a_framy) {
+ if (self->private_impl.f_chunk_type == 1280598881) {
+ if (self->private_impl.f_seen_actl) {
+ status = wuffs_base__make_status(wuffs_png__error__bad_chunk);
+ goto exit;
+ }
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
+ status = wuffs_png__decoder__decode_actl(self, a_src);
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
+ }
+ if (status.repr) {
+ goto suspend;
+ }
+ self->private_impl.f_seen_actl = true;
+ } else if (self->private_impl.f_chunk_type == 1297238115) {
+ if (self->private_impl.f_report_metadata_chrm) {
+ if (self->private_impl.f_seen_chrm) {
+ status = wuffs_base__make_status(wuffs_png__error__bad_chunk);
+ goto exit;
+ }
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
+ status = wuffs_png__decoder__decode_chrm(self, a_src);
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
+ }
+ if (status.repr) {
+ goto suspend;
+ }
+ self->private_impl.f_seen_chrm = true;
+ }
+ } else if (self->private_impl.f_chunk_type == 1280598886) {
+ if (self->private_impl.f_seen_fctl) {
+ status = wuffs_base__make_status(wuffs_png__error__bad_chunk);
+ goto exit;
+ }
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(5);
+ status = wuffs_png__decoder__decode_fctl(self, a_src);
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
+ }
+ if (status.repr) {
+ goto suspend;
+ }
+ self->private_impl.f_seen_fctl = true;
+ } else if (self->private_impl.f_chunk_type == 1095582055) {
+ if (self->private_impl.f_report_metadata_gama) {
+ if (self->private_impl.f_seen_gama) {
+ status = wuffs_base__make_status(wuffs_png__error__bad_chunk);
+ goto exit;
+ }
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(6);
+ status = wuffs_png__decoder__decode_gama(self, a_src);
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
+ }
+ if (status.repr) {
+ goto suspend;
+ }
+ self->private_impl.f_seen_gama = true;
+ }
+ } else if (self->private_impl.f_chunk_type == 1346585449) {
+ if (self->private_impl.f_report_metadata_iccp) {
+ if (self->private_impl.f_seen_iccp) {
+ status = wuffs_base__make_status(wuffs_png__error__bad_chunk);
+ goto exit;
+ }
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(7);
+ status = wuffs_png__decoder__decode_iccp(self, a_src);
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
+ }
+ if (status.repr) {
+ goto suspend;
+ }
+ self->private_impl.f_seen_iccp = true;
+ }
+ } else if (self->private_impl.f_chunk_type == 1111970419) {
+ if (self->private_impl.f_report_metadata_srgb) {
+ if (self->private_impl.f_seen_srgb) {
+ status = wuffs_base__make_status(wuffs_png__error__bad_chunk);
+ goto exit;
+ }
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(8);
+ status = wuffs_png__decoder__decode_srgb(self, a_src);
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
+ }
+ if (status.repr) {
+ goto suspend;
+ }
+ self->private_impl.f_seen_srgb = true;
+ }
+ } else if (self->private_impl.f_chunk_type == 1397641844) {
+ if (self->private_impl.f_seen_trns || (self->private_impl.f_color_type > 3) || ((self->private_impl.f_color_type == 3) && ! self->private_impl.f_seen_plte)) {
+ status = wuffs_base__make_status(wuffs_png__error__bad_chunk);
+ goto exit;
+ }
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(9);
+ status = wuffs_png__decoder__decode_trns(self, a_src);
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
+ }
+ if (status.repr) {
+ goto suspend;
+ }
+ self->private_impl.f_seen_trns = true;
+ }
}
if (self->private_impl.f_metadata_fourcc == 0) {
self->private_data.s_decode_other_chunk[0].scratch = self->private_impl.f_chunk_length;
@@ -41800,6 +41805,8 @@
self->private_impl.active_coroutine = 0;
wuffs_base__status status = wuffs_base__make_status(NULL);
+ uint32_t v_checksum_have = 0;
+
const uint8_t* iop_a_src = NULL;
const uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
const uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
@@ -41848,14 +41855,15 @@
if (status.repr) {
goto suspend;
}
- if (self->private_impl.f_call_sequence >= 96) {
- status = wuffs_base__make_status(wuffs_base__note__end_of_data);
- goto ok;
- }
} else {
status = wuffs_base__make_status(wuffs_base__note__end_of_data);
goto ok;
}
+ if (self->private_impl.f_metadata_fourcc != 0) {
+ self->private_impl.f_call_sequence = 48;
+ status = wuffs_base__make_status(wuffs_base__note__metadata_reported);
+ goto ok;
+ }
if (self->private_impl.f_num_decoded_frame_configs_value == 0) {
self->private_impl.f_frame_rect_x0 = self->private_impl.f_first_rect_x0;
self->private_impl.f_frame_rect_y0 = self->private_impl.f_first_rect_y0;
@@ -41925,7 +41933,48 @@
}
self->private_impl.f_chunk_type = t_1;
}
- if (self->private_impl.f_chunk_type == 1413571686) {
+ if (self->private_impl.f_chunk_type == 1145980233) {
+ if (self->private_impl.f_chunk_length != 0) {
+ status = wuffs_base__make_status(wuffs_png__error__bad_chunk);
+ goto exit;
+ }
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(7);
+ uint32_t t_2;
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 4)) {
+ t_2 = wuffs_base__peek_u32le__no_bounds_check(iop_a_src);
+ iop_a_src += 4;
+ } else {
+ self->private_data.s_decode_frame_config[0].scratch = 0;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(8);
+ while (true) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ goto suspend;
+ }
+ uint64_t* scratch = &self->private_data.s_decode_frame_config[0].scratch;
+ uint32_t num_bits_2 = ((uint32_t)(*scratch >> 56));
+ *scratch <<= 8;
+ *scratch >>= 8;
+ *scratch |= ((uint64_t)(*iop_a_src++)) << num_bits_2;
+ if (num_bits_2 == 24) {
+ t_2 = ((uint32_t)(*scratch));
+ break;
+ }
+ num_bits_2 += 8;
+ *scratch |= ((uint64_t)(num_bits_2)) << 56;
+ }
+ }
+ v_checksum_have = t_2;
+ }
+ if ( ! self->private_impl.f_ignore_checksum && (v_checksum_have != 2187346606)) {
+ status = wuffs_base__make_status(wuffs_png__error__bad_checksum);
+ goto exit;
+ }
+ self->private_impl.f_call_sequence = 96;
+ status = wuffs_base__make_status(wuffs_base__note__end_of_data);
+ goto ok;
+ } else if (self->private_impl.f_chunk_type == 1413571686) {
status = wuffs_base__make_status(wuffs_png__error__bad_chunk);
goto exit;
} else if (self->private_impl.f_chunk_type == 1280598886) {
@@ -41933,7 +41982,7 @@
if (a_src) {
a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(7);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(9);
status = wuffs_png__decoder__decode_fctl(self, a_src);
if (a_src) {
iop_a_src = a_src->data.ptr + a_src->meta.ri;
@@ -41942,7 +41991,7 @@
goto suspend;
}
self->private_data.s_decode_frame_config[0].scratch = 4;
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(8);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(10);
if (self->private_data.s_decode_frame_config[0].scratch > ((uint64_t)(io2_a_src - iop_a_src))) {
self->private_data.s_decode_frame_config[0].scratch -= ((uint64_t)(io2_a_src - iop_a_src));
iop_a_src = io2_a_src;
@@ -41952,8 +42001,24 @@
iop_a_src += self->private_data.s_decode_frame_config[0].scratch;
goto label__0__break;
}
- self->private_data.s_decode_frame_config[0].scratch = (((uint64_t)(self->private_impl.f_chunk_length)) + 4);
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(9);
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(11);
+ status = wuffs_png__decoder__decode_other_chunk(self, a_src, true);
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
+ }
+ if (status.repr) {
+ goto suspend;
+ }
+ if (self->private_impl.f_metadata_fourcc != 0) {
+ self->private_impl.f_call_sequence = 48;
+ status = wuffs_base__make_status(wuffs_base__note__metadata_reported);
+ goto ok;
+ }
+ self->private_data.s_decode_frame_config[0].scratch = 4;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(12);
if (self->private_data.s_decode_frame_config[0].scratch > ((uint64_t)(io2_a_src - iop_a_src))) {
self->private_data.s_decode_frame_config[0].scratch -= ((uint64_t)(io2_a_src - iop_a_src));
iop_a_src = io2_a_src;
@@ -42138,11 +42203,7 @@
}
label__0__break:;
wuffs_base__u32__sat_add_indirect(&self->private_impl.f_num_decoded_frames_value, 1);
- if (self->private_impl.f_num_decoded_frames_value < self->private_impl.f_num_animation_frames_value) {
- self->private_impl.f_call_sequence = 32;
- } else {
- self->private_impl.f_call_sequence = 96;
- }
+ self->private_impl.f_call_sequence = 32;
ok:
self->private_impl.p_skip_frame[0] = 0;
@@ -42411,11 +42472,7 @@
}
label__2__break:;
wuffs_base__u32__sat_add_indirect(&self->private_impl.f_num_decoded_frames_value, 1);
- if (self->private_impl.f_num_decoded_frames_value < self->private_impl.f_num_animation_frames_value) {
- self->private_impl.f_call_sequence = 32;
- } else {
- self->private_impl.f_call_sequence = 96;
- }
+ self->private_impl.f_call_sequence = 32;
ok:
self->private_impl.p_decode_frame[0] = 0;
@@ -46746,6 +46803,7 @@
wuffs_base__image_config image_config = wuffs_base__null_image_config();
sync_io::DynIOBuffer raw_metadata_buf(max_incl_metadata_length);
uint64_t start_pos = io_buf.reader_position();
+ bool interested_in_metadata_after_the_frame = false;
bool redirected = false;
int32_t fourcc = 0;
redirect:
@@ -46820,6 +46878,7 @@
image_decoder->set_report_metadata(WUFFS_BASE__FOURCC__CHRM, true);
}
if (flags & DecodeImageArgFlags::REPORT_METADATA_EXIF) {
+ interested_in_metadata_after_the_frame = true;
image_decoder->set_report_metadata(WUFFS_BASE__FOURCC__EXIF, true);
}
if (flags & DecodeImageArgFlags::REPORT_METADATA_GAMA) {
@@ -46829,12 +46888,14 @@
image_decoder->set_report_metadata(WUFFS_BASE__FOURCC__ICCP, true);
}
if (flags & DecodeImageArgFlags::REPORT_METADATA_KVP) {
+ interested_in_metadata_after_the_frame = true;
image_decoder->set_report_metadata(WUFFS_BASE__FOURCC__KVP, true);
}
if (flags & DecodeImageArgFlags::REPORT_METADATA_SRGB) {
image_decoder->set_report_metadata(WUFFS_BASE__FOURCC__SRGB, true);
}
if (flags & DecodeImageArgFlags::REPORT_METADATA_XMP) {
+ interested_in_metadata_after_the_frame = true;
image_decoder->set_report_metadata(WUFFS_BASE__FOURCC__XMP, true);
}
}
@@ -46869,7 +46930,9 @@
}
}
} while (false);
- raw_metadata_buf.drop();
+ if (!interested_in_metadata_after_the_frame) {
+ raw_metadata_buf.drop();
+ }
// Select the pixel format.
uint32_t w = image_config.pixcfg.width();
@@ -46930,6 +46993,12 @@
image_decoder->decode_frame_config(&frame_config, &io_buf);
if (id_dfc_status.repr == nullptr) {
break;
+ } else if (id_dfc_status.repr == wuffs_base__note__metadata_reported) {
+ std::string error_message = DecodeImageHandleMetadata(
+ image_decoder, callbacks, input, io_buf, raw_metadata_buf);
+ if (!error_message.empty()) {
+ return DecodeImageResult(std::move(error_message));
+ }
} else if (id_dfc_status.repr != wuffs_base__suspension__short_read) {
return DecodeImageResult(id_dfc_status.message());
} else if (io_buf.meta.closed) {
@@ -46971,6 +47040,35 @@
}
}
}
+
+ // Decode any metadata after the frame.
+ if (interested_in_metadata_after_the_frame) {
+ while (true) {
+ wuffs_base__status id_dfc_status =
+ image_decoder->decode_frame_config(NULL, &io_buf);
+ if (id_dfc_status.repr == wuffs_base__note__end_of_data) {
+ break;
+ } else if (id_dfc_status.repr == nullptr) {
+ continue;
+ } else if (id_dfc_status.repr == wuffs_base__note__metadata_reported) {
+ std::string error_message = DecodeImageHandleMetadata(
+ image_decoder, callbacks, input, io_buf, raw_metadata_buf);
+ if (!error_message.empty()) {
+ return DecodeImageResult(std::move(error_message));
+ }
+ } else if (id_dfc_status.repr != wuffs_base__suspension__short_read) {
+ return DecodeImageResult(id_dfc_status.message());
+ } else if (io_buf.meta.closed) {
+ return DecodeImageResult(DecodeImage_UnexpectedEndOfFile);
+ } else {
+ std::string error_message = input.CopyIn(&io_buf);
+ if (!error_message.empty()) {
+ return DecodeImageResult(std::move(error_message));
+ }
+ }
+ }
+ }
+
return DecodeImageResult(std::move(alloc_pixbuf_result.mem_owner),
pixel_buffer, std::move(message));
}
diff --git a/std/png/decode_png.wuffs b/std/png/decode_png.wuffs
index 62e0e62..a1e37a0 100644
--- a/std/png/decode_png.wuffs
+++ b/std/png/decode_png.wuffs
@@ -24,8 +24,8 @@
// pass_bytes_per_row doesn't include the 1 byte for the per-row filter.
pass_bytes_per_row : base.u64[..= 0x07FF_FFF8],
- workbuf_wi : base.u64,
- workbuf_hist_pos_base : base.u64,
+ workbuf_wi : base.u64,
+ workbuf_hist_pos_base : base.u64,
// The inclusive upper bound, DECODER_WORKBUF_LEN_MAX_INCL_WORST_CASE, is
// derived from the width and height upper bounds at up to 8 bytes per
@@ -264,7 +264,7 @@
while true {
mark = args.src.mark()
- status =? this.decode_other_chunk?(src: args.src)
+ status =? this.decode_other_chunk?(src: args.src, framy: false)
if (not this.ignore_checksum) and ((this.chunk_type & ANCILLARY_BIT) == 0) {
checksum_have = this.crc32.update_u32!(x: args.src.since(mark: mark))
}
@@ -510,8 +510,11 @@
}
}
-pri func decoder.decode_other_chunk?(src: base.io_reader) {
- if this.chunk_type == 'PLTE'le {
+// framy is:
+// - false when coming from decode_image_config.
+// - true when coming from decode_frame_config.
+pri func decoder.decode_other_chunk?(src: base.io_reader, framy: base.bool) {
+ if (this.chunk_type == 'PLTE'le) and (not args.framy) {
if this.seen_plte {
return "#bad chunk"
} else if this.color_type == 3 {
@@ -530,24 +533,9 @@
if this.chunk_type <> 'IDAT'le {
return "#bad chunk"
}
+ }
- } else if this.chunk_type == 'acTL'le {
- if this.seen_actl {
- return "#bad chunk"
- }
- this.decode_actl?(src: args.src)
- this.seen_actl = true
-
- } else if this.chunk_type == 'cHRM'le {
- if this.report_metadata_chrm {
- if this.seen_chrm {
- return "#bad chunk"
- }
- this.decode_chrm?(src: args.src)
- this.seen_chrm = true
- }
-
- } else if this.chunk_type == 'eXIf'le {
+ if this.chunk_type == 'eXIf'le {
if this.report_metadata_exif {
if this.seen_exif {
return "#bad chunk"
@@ -556,48 +544,6 @@
this.seen_exif = true
}
- } else if this.chunk_type == 'fcTL'le {
- if this.seen_fctl {
- return "#bad chunk"
- }
- this.decode_fctl?(src: args.src)
- this.seen_fctl = true
-
- } else if this.chunk_type == 'gAMA'le {
- if this.report_metadata_gama {
- if this.seen_gama {
- return "#bad chunk"
- }
- this.decode_gama?(src: args.src)
- this.seen_gama = true
- }
-
- } else if this.chunk_type == 'iCCP'le {
- if this.report_metadata_iccp {
- if this.seen_iccp {
- return "#bad chunk"
- }
- this.decode_iccp?(src: args.src)
- this.seen_iccp = true
- }
-
- } else if this.chunk_type == 'sRGB'le {
- if this.report_metadata_srgb {
- if this.seen_srgb {
- return "#bad chunk"
- }
- this.decode_srgb?(src: args.src)
- this.seen_srgb = true
- }
-
- } else if this.chunk_type == 'tRNS'le {
- if this.seen_trns or (this.color_type > 3) or
- ((this.color_type == 3) and (not this.seen_plte)) {
- return "#bad chunk"
- }
- this.decode_trns?(src: args.src)
- this.seen_trns = true
-
} else if (this.chunk_type == 'iTXt'le) or
(this.chunk_type == 'tEXt'le) or
(this.chunk_type == 'zTXt'le) {
@@ -608,6 +554,66 @@
this.metadata_y = 0
this.metadata_z = 0
}
+
+ } else if not args.framy {
+ if this.chunk_type == 'acTL'le {
+ if this.seen_actl {
+ return "#bad chunk"
+ }
+ this.decode_actl?(src: args.src)
+ this.seen_actl = true
+
+ } else if this.chunk_type == 'cHRM'le {
+ if this.report_metadata_chrm {
+ if this.seen_chrm {
+ return "#bad chunk"
+ }
+ this.decode_chrm?(src: args.src)
+ this.seen_chrm = true
+ }
+
+ } else if this.chunk_type == 'fcTL'le {
+ if this.seen_fctl {
+ return "#bad chunk"
+ }
+ this.decode_fctl?(src: args.src)
+ this.seen_fctl = true
+
+ } else if this.chunk_type == 'gAMA'le {
+ if this.report_metadata_gama {
+ if this.seen_gama {
+ return "#bad chunk"
+ }
+ this.decode_gama?(src: args.src)
+ this.seen_gama = true
+ }
+
+ } else if this.chunk_type == 'iCCP'le {
+ if this.report_metadata_iccp {
+ if this.seen_iccp {
+ return "#bad chunk"
+ }
+ this.decode_iccp?(src: args.src)
+ this.seen_iccp = true
+ }
+
+ } else if this.chunk_type == 'sRGB'le {
+ if this.report_metadata_srgb {
+ if this.seen_srgb {
+ return "#bad chunk"
+ }
+ this.decode_srgb?(src: args.src)
+ this.seen_srgb = true
+ }
+
+ } else if this.chunk_type == 'tRNS'le {
+ if this.seen_trns or (this.color_type > 3) or
+ ((this.color_type == 3) and (not this.seen_plte)) {
+ return "#bad chunk"
+ }
+ this.decode_trns?(src: args.src)
+ this.seen_trns = true
+ }
}
if this.metadata_fourcc == 0 {
@@ -928,6 +934,8 @@
}
pub func decoder.decode_frame_config?(dst: nptr base.frame_config, src: base.io_reader) {
+ var checksum_have : base.u32
+
if (this.call_sequence & 0x10) <> 0 {
return base."#bad call sequence"
} else if this.call_sequence == 0x20 {
@@ -940,13 +948,15 @@
}
} else if this.call_sequence == 0x40 {
this.skip_frame?(src: args.src)
- if this.call_sequence >= 0x60 {
- return base."@end of data"
- }
} else {
return base."@end of data"
}
+ if this.metadata_fourcc <> 0 {
+ this.call_sequence = 0x30
+ return base."@metadata reported"
+ }
+
if this.num_decoded_frame_configs_value == 0 {
this.frame_rect_x0 = this.first_rect_x0
this.frame_rect_y0 = this.first_rect_y0
@@ -958,11 +968,21 @@
this.frame_overwrite_instead_of_blend = this.first_overwrite_instead_of_blend
} else {
- // Decode the next fcTL chunk.
+ // Decode the next IEND or fcTL chunk.
while true {
this.chunk_length = args.src.read_u32be?()
this.chunk_type = args.src.read_u32le?()
- if this.chunk_type == 'fdAT'le {
+ if this.chunk_type == 'IEND'le {
+ if this.chunk_length <> 0 {
+ return "#bad chunk"
+ }
+ checksum_have = args.src.read_u32le?()
+ if (not this.ignore_checksum) and (checksum_have <> 0x8260_42AE) {
+ return "#bad checksum"
+ }
+ this.call_sequence = 0x60
+ return base."@end of data"
+ } else if this.chunk_type == 'fdAT'le {
return "#bad chunk"
} else if this.chunk_type == 'fcTL'le {
this.frame_config_io_position = args.src.position() ~mod- 8
@@ -970,7 +990,13 @@
args.src.skip?(n: 4) // Skip the checksum.
break
}
- args.src.skip?(n: (this.chunk_length as base.u64) + 4) // +4 for the checksum.
+
+ this.decode_other_chunk?(src: args.src, framy: true)
+ if this.metadata_fourcc <> 0 {
+ this.call_sequence = 0x30
+ return base."@metadata reported"
+ }
+ args.src.skip_u32?(n: 4) // Skip the checksum.
this.chunk_length = 0
} endwhile
}
@@ -1061,11 +1087,7 @@
} endwhile
this.num_decoded_frames_value ~sat+= 1
- if this.num_decoded_frames_value < this.num_animation_frames_value {
- this.call_sequence = 0x20
- } else {
- this.call_sequence = 0x60
- }
+ this.call_sequence = 0x20
}
pub func decoder.decode_frame?(dst: ptr base.pixel_buffer, src: base.io_reader, blend: base.pixel_blend, workbuf: slice base.u8, opts: nptr base.decode_frame_options) {
@@ -1207,11 +1229,7 @@
} endwhile
this.num_decoded_frames_value ~sat+= 1
- if this.num_decoded_frames_value < this.num_animation_frames_value {
- this.call_sequence = 0x20
- } else {
- this.call_sequence = 0x60
- }
+ this.call_sequence = 0x20
}
pri func decoder.decode_pass?(src: base.io_reader, workbuf: slice base.u8) {
diff --git a/test/c/std/png.c b/test/c/std/png.c
index c77cb90..23eaafb 100644
--- a/test/c/std/png.c
+++ b/test/c/std/png.c
@@ -810,6 +810,8 @@
"U-значение", //
"Z-Këy", //
"Z-значение", //
+ "After", //
+ "Frame", //
};
wuffs_png__decoder dec;
@@ -819,14 +821,15 @@
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
wuffs_png__decoder__set_report_metadata(&dec, WUFFS_BASE__FOURCC__KVP, true);
- wuffs_base__image_config ic = ((wuffs_base__image_config){});
wuffs_base__more_information minfo = wuffs_base__empty_more_information();
size_t i = 0;
- for (;; i++) {
+ while (true) {
wuffs_base__status status =
- wuffs_png__decoder__decode_image_config(&dec, &ic, &src);
+ wuffs_png__decoder__decode_frame_config(&dec, NULL, &src);
if (wuffs_base__status__is_ok(&status)) {
+ continue;
+ } else if (status.repr == wuffs_base__note__end_of_data) {
break;
} else if (status.repr != wuffs_base__note__metadata_reported) {
RETURN_FAIL("decode_image_config i=%zu: %s", i, status.repr);
@@ -865,6 +868,7 @@
}
}
CHECK_STRING(check_io_buffers_equal("", &have, &want));
+ i++;
}
if (i != WUFFS_TESTLIB_ARRAY_SIZE(wants)) {
diff --git a/test/data/artificial-png/key-value-pairs.png b/test/data/artificial-png/key-value-pairs.png
index 906fb0e..4b04cfc 100644
--- a/test/data/artificial-png/key-value-pairs.png
+++ b/test/data/artificial-png/key-value-pairs.png
Binary files differ
diff --git a/test/data/artificial-png/key-value-pairs.png.make-artificial.txt b/test/data/artificial-png/key-value-pairs.png.make-artificial.txt
index 95b35fc..7090747 100644
--- a/test/data/artificial-png/key-value-pairs.png.make-artificial.txt
+++ b/test/data/artificial-png/key-value-pairs.png.make-artificial.txt
@@ -95,5 +95,15 @@
}
}
+# Basic key-value pair, after the frame (after all of the IDATs).
+tEXt {
+ raw {
+ # "After\x00".
+ 0x41 0x66 0x74 0x65 0x72 0x00
+ # "Frame".
+ 0x46 0x72 0x61 0x6D 0x65
+ }
+}
+
IEND {
}