std/vp8: decode to a placeholder gradient
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c index d4bd937..fa98f34 100644 --- a/release/c/wuffs-unsupported-snapshot.c +++ b/release/c/wuffs-unsupported-snapshot.c
@@ -14559,11 +14559,17 @@ // ---------------- Status Codes +extern const char wuffs_vp8__error__bad_header[]; +extern const char wuffs_vp8__error__truncated_input[]; +extern const char wuffs_vp8__error__unsupported_vp8_file[]; + // ---------------- Public Consts +#define WUFFS_VP8__DECODER_WORKBUF_LEN_MAX_INCL_WORST_CASE 0u + // ---------------- Struct Declarations -typedef struct wuffs_vp8__placeholder__struct wuffs_vp8__placeholder; +typedef struct wuffs_vp8__decoder__struct wuffs_vp8__decoder; #ifdef __cplusplus extern "C" { @@ -14578,14 +14584,14 @@ // Pass 0 (or some combination of WUFFS_INITIALIZE__XXX) for options. wuffs_base__status WUFFS_BASE__WARN_UNUSED_RESULT -wuffs_vp8__placeholder__initialize( - wuffs_vp8__placeholder* self, +wuffs_vp8__decoder__initialize( + wuffs_vp8__decoder* self, size_t sizeof_star_self, uint64_t wuffs_version, uint32_t options); size_t -sizeof__wuffs_vp8__placeholder(void); +sizeof__wuffs_vp8__decoder(void); // ---------------- Allocs @@ -14595,13 +14601,108 @@ // calling free on the returned pointer. That pointer is effectively a C++ // std::unique_ptr<T, wuffs_unique_ptr_deleter>. -wuffs_vp8__placeholder* -wuffs_vp8__placeholder__alloc(void); +wuffs_vp8__decoder* +wuffs_vp8__decoder__alloc(void); + +static inline wuffs_base__image_decoder* +wuffs_vp8__decoder__alloc_as__wuffs_base__image_decoder(void) { + return (wuffs_base__image_decoder*)(wuffs_vp8__decoder__alloc()); +} // ---------------- Upcasts +static inline wuffs_base__image_decoder* +wuffs_vp8__decoder__upcast_as__wuffs_base__image_decoder( + wuffs_vp8__decoder* p) { + return (wuffs_base__image_decoder*)p; +} + // ---------------- Public Function Prototypes +WUFFS_BASE__GENERATED_C_CODE +WUFFS_BASE__MAYBE_STATIC uint64_t +wuffs_vp8__decoder__get_quirk( + const wuffs_vp8__decoder* self, + uint32_t a_key); + +WUFFS_BASE__GENERATED_C_CODE +WUFFS_BASE__MAYBE_STATIC wuffs_base__status +wuffs_vp8__decoder__set_quirk( + wuffs_vp8__decoder* self, + uint32_t a_key, + uint64_t a_value); + +WUFFS_BASE__GENERATED_C_CODE +WUFFS_BASE__MAYBE_STATIC wuffs_base__status +wuffs_vp8__decoder__decode_image_config( + wuffs_vp8__decoder* self, + wuffs_base__image_config* a_dst, + wuffs_base__io_buffer* a_src); + +WUFFS_BASE__GENERATED_C_CODE +WUFFS_BASE__MAYBE_STATIC wuffs_base__status +wuffs_vp8__decoder__decode_frame_config( + wuffs_vp8__decoder* self, + wuffs_base__frame_config* a_dst, + wuffs_base__io_buffer* a_src); + +WUFFS_BASE__GENERATED_C_CODE +WUFFS_BASE__MAYBE_STATIC wuffs_base__status +wuffs_vp8__decoder__decode_frame( + wuffs_vp8__decoder* self, + wuffs_base__pixel_buffer* a_dst, + wuffs_base__io_buffer* a_src, + wuffs_base__pixel_blend a_blend, + wuffs_base__slice_u8 a_workbuf, + wuffs_base__decode_frame_options* a_opts); + +WUFFS_BASE__GENERATED_C_CODE +WUFFS_BASE__MAYBE_STATIC wuffs_base__rect_ie_u32 +wuffs_vp8__decoder__frame_dirty_rect( + const wuffs_vp8__decoder* self); + +WUFFS_BASE__GENERATED_C_CODE +WUFFS_BASE__MAYBE_STATIC uint32_t +wuffs_vp8__decoder__num_animation_loops( + const wuffs_vp8__decoder* self); + +WUFFS_BASE__GENERATED_C_CODE +WUFFS_BASE__MAYBE_STATIC uint64_t +wuffs_vp8__decoder__num_decoded_frame_configs( + const wuffs_vp8__decoder* self); + +WUFFS_BASE__GENERATED_C_CODE +WUFFS_BASE__MAYBE_STATIC uint64_t +wuffs_vp8__decoder__num_decoded_frames( + const wuffs_vp8__decoder* self); + +WUFFS_BASE__GENERATED_C_CODE +WUFFS_BASE__MAYBE_STATIC wuffs_base__status +wuffs_vp8__decoder__restart_frame( + wuffs_vp8__decoder* self, + uint64_t a_index, + uint64_t a_io_position); + +WUFFS_BASE__GENERATED_C_CODE +WUFFS_BASE__MAYBE_STATIC wuffs_base__empty_struct +wuffs_vp8__decoder__set_report_metadata( + wuffs_vp8__decoder* self, + uint32_t a_fourcc, + bool a_report); + +WUFFS_BASE__GENERATED_C_CODE +WUFFS_BASE__MAYBE_STATIC wuffs_base__status +wuffs_vp8__decoder__tell_me_more( + wuffs_vp8__decoder* self, + wuffs_base__io_buffer* a_dst, + wuffs_base__more_information* a_minfo, + wuffs_base__io_buffer* a_src); + +WUFFS_BASE__GENERATED_C_CODE +WUFFS_BASE__MAYBE_STATIC wuffs_base__range_ii_u64 +wuffs_vp8__decoder__workbuf_len( + const wuffs_vp8__decoder* self); + #ifdef __cplusplus } // extern "C" #endif @@ -14615,7 +14716,7 @@ #if defined(__cplusplus) || defined(WUFFS_IMPLEMENTATION) -struct wuffs_vp8__placeholder__struct { +struct wuffs_vp8__decoder__struct { // Do not access the private_impl's or private_data's fields directly. There // is no API/ABI compatibility or safety guarantee if you do so. Instead, use // the wuffs_foo__bar__baz functions. @@ -14626,20 +14727,46 @@ struct { uint32_t magic; uint32_t active_coroutine; + wuffs_base__vtable vtable_for__wuffs_base__image_decoder; wuffs_base__vtable null_vtable; - uint32_t f_placeholder; + uint32_t f_width; + uint32_t f_height; + uint8_t f_call_sequence; + uint64_t f_frame_config_io_position; + uint32_t f_dst_x; + uint32_t f_dst_y; + wuffs_base__pixel_swizzler f_swizzler; + + uint32_t p_decode_image_config; + uint32_t p_do_decode_image_config; + uint32_t p_decode_frame_config; + uint32_t p_do_decode_frame_config; + uint32_t p_decode_frame; + uint32_t p_do_decode_frame; } private_impl; + struct { + struct { + uint64_t scratch; + } s_do_decode_image_config; + } private_data; + #ifdef __cplusplus #if defined(WUFFS_BASE__HAVE_UNIQUE_PTR) - using unique_ptr = std::unique_ptr<wuffs_vp8__placeholder, wuffs_unique_ptr_deleter>; + using unique_ptr = std::unique_ptr<wuffs_vp8__decoder, wuffs_unique_ptr_deleter>; // On failure, the alloc_etc functions return nullptr. They don't throw. static inline unique_ptr alloc() { - return unique_ptr(wuffs_vp8__placeholder__alloc()); + return unique_ptr(wuffs_vp8__decoder__alloc()); + } + + static inline wuffs_base__image_decoder::unique_ptr + alloc_as__wuffs_base__image_decoder() { + return wuffs_base__image_decoder::unique_ptr( + wuffs_vp8__decoder__alloc_as__wuffs_base__image_decoder()); } #endif // defined(WUFFS_BASE__HAVE_UNIQUE_PTR) @@ -14655,10 +14782,10 @@ // WUFFS_IMPLEMENTATION is #define'd). In C++, we define a complete type in // order to provide convenience methods. These forward on "this", so that you // can write "bar->baz(etc)" instead of "wuffs_foo__bar__baz(bar, etc)". - wuffs_vp8__placeholder__struct() = delete; - wuffs_vp8__placeholder__struct(const wuffs_vp8__placeholder__struct&) = delete; - wuffs_vp8__placeholder__struct& operator=( - const wuffs_vp8__placeholder__struct&) = delete; + wuffs_vp8__decoder__struct() = delete; + wuffs_vp8__decoder__struct(const wuffs_vp8__decoder__struct&) = delete; + wuffs_vp8__decoder__struct& operator=( + const wuffs_vp8__decoder__struct&) = delete; #endif // defined(WUFFS_BASE__HAVE_EQ_DELETE) && !defined(WUFFS_IMPLEMENTATION) #if !defined(WUFFS_IMPLEMENTATION) @@ -14678,12 +14805,101 @@ size_t sizeof_star_self, uint64_t wuffs_version, uint32_t options) { - return wuffs_vp8__placeholder__initialize( + return wuffs_vp8__decoder__initialize( this, sizeof_star_self, wuffs_version, options); } + inline wuffs_base__image_decoder* + upcast_as__wuffs_base__image_decoder() { + return (wuffs_base__image_decoder*)this; + } + + inline uint64_t + get_quirk( + uint32_t a_key) const { + return wuffs_vp8__decoder__get_quirk(this, a_key); + } + + inline wuffs_base__status + set_quirk( + uint32_t a_key, + uint64_t a_value) { + return wuffs_vp8__decoder__set_quirk(this, a_key, a_value); + } + + inline wuffs_base__status + decode_image_config( + wuffs_base__image_config* a_dst, + wuffs_base__io_buffer* a_src) { + return wuffs_vp8__decoder__decode_image_config(this, a_dst, a_src); + } + + inline wuffs_base__status + decode_frame_config( + wuffs_base__frame_config* a_dst, + wuffs_base__io_buffer* a_src) { + return wuffs_vp8__decoder__decode_frame_config(this, a_dst, a_src); + } + + inline wuffs_base__status + decode_frame( + wuffs_base__pixel_buffer* a_dst, + wuffs_base__io_buffer* a_src, + wuffs_base__pixel_blend a_blend, + wuffs_base__slice_u8 a_workbuf, + wuffs_base__decode_frame_options* a_opts) { + return wuffs_vp8__decoder__decode_frame(this, a_dst, a_src, a_blend, a_workbuf, a_opts); + } + + inline wuffs_base__rect_ie_u32 + frame_dirty_rect() const { + return wuffs_vp8__decoder__frame_dirty_rect(this); + } + + inline uint32_t + num_animation_loops() const { + return wuffs_vp8__decoder__num_animation_loops(this); + } + + inline uint64_t + num_decoded_frame_configs() const { + return wuffs_vp8__decoder__num_decoded_frame_configs(this); + } + + inline uint64_t + num_decoded_frames() const { + return wuffs_vp8__decoder__num_decoded_frames(this); + } + + inline wuffs_base__status + restart_frame( + uint64_t a_index, + uint64_t a_io_position) { + return wuffs_vp8__decoder__restart_frame(this, a_index, a_io_position); + } + + inline wuffs_base__empty_struct + set_report_metadata( + uint32_t a_fourcc, + bool a_report) { + return wuffs_vp8__decoder__set_report_metadata(this, a_fourcc, a_report); + } + + inline wuffs_base__status + tell_me_more( + wuffs_base__io_buffer* a_dst, + wuffs_base__more_information* a_minfo, + wuffs_base__io_buffer* a_src) { + return wuffs_vp8__decoder__tell_me_more(this, a_dst, a_minfo, a_src); + } + + inline wuffs_base__range_ii_u64 + workbuf_len() const { + return wuffs_vp8__decoder__workbuf_len(this); + } + #endif // __cplusplus -}; // struct wuffs_vp8__placeholder__struct +}; // struct wuffs_vp8__decoder__struct #endif // defined(__cplusplus) || defined(WUFFS_IMPLEMENTATION) @@ -15234,6 +15450,7 @@ uint8_t f_call_sequence; uint8_t f_code_length_code_lengths[19]; bool f_sub_chunk_has_padding; + bool f_is_vp8_lossy; uint64_t f_frame_config_io_position; uint32_t f_riff_chunk_length; uint32_t f_sub_chunk_length; @@ -15276,6 +15493,7 @@ } private_impl; struct { + wuffs_vp8__decoder f_vp8; uint8_t f_palette[1024]; uint32_t f_color_cache[2048]; uint16_t f_codes[2328]; @@ -75876,19 +76094,89 @@ // ---------------- Status Codes Implementations +const char wuffs_vp8__error__bad_header[] = "#vp8: bad header"; +const char wuffs_vp8__error__truncated_input[] = "#vp8: truncated input"; +const char wuffs_vp8__error__unsupported_vp8_file[] = "#vp8: unsupported VP8 file"; + // ---------------- Private Consts // ---------------- Private Initializer Prototypes // ---------------- Private Function Prototypes +WUFFS_BASE__GENERATED_C_CODE +static wuffs_base__status +wuffs_vp8__decoder__do_decode_image_config( + wuffs_vp8__decoder* self, + wuffs_base__image_config* a_dst, + wuffs_base__io_buffer* a_src); + +WUFFS_BASE__GENERATED_C_CODE +static wuffs_base__status +wuffs_vp8__decoder__do_decode_frame_config( + wuffs_vp8__decoder* self, + wuffs_base__frame_config* a_dst, + wuffs_base__io_buffer* a_src); + +WUFFS_BASE__GENERATED_C_CODE +static wuffs_base__status +wuffs_vp8__decoder__do_decode_frame( + wuffs_vp8__decoder* self, + wuffs_base__pixel_buffer* a_dst, + wuffs_base__io_buffer* a_src, + wuffs_base__pixel_blend a_blend, + wuffs_base__slice_u8 a_workbuf, + wuffs_base__decode_frame_options* a_opts); + +WUFFS_BASE__GENERATED_C_CODE +static wuffs_base__status +wuffs_vp8__decoder__make_a_placeholder_gradient( + wuffs_vp8__decoder* self, + wuffs_base__pixel_buffer* a_dst); + // ---------------- VTables +const wuffs_base__image_decoder__func_ptrs +wuffs_vp8__decoder__func_ptrs_for__wuffs_base__image_decoder = { + (wuffs_base__status(*)(void*, + wuffs_base__pixel_buffer*, + wuffs_base__io_buffer*, + wuffs_base__pixel_blend, + wuffs_base__slice_u8, + wuffs_base__decode_frame_options*))(&wuffs_vp8__decoder__decode_frame), + (wuffs_base__status(*)(void*, + wuffs_base__frame_config*, + wuffs_base__io_buffer*))(&wuffs_vp8__decoder__decode_frame_config), + (wuffs_base__status(*)(void*, + wuffs_base__image_config*, + wuffs_base__io_buffer*))(&wuffs_vp8__decoder__decode_image_config), + (wuffs_base__rect_ie_u32(*)(const void*))(&wuffs_vp8__decoder__frame_dirty_rect), + (uint64_t(*)(const void*, + uint32_t))(&wuffs_vp8__decoder__get_quirk), + (uint32_t(*)(const void*))(&wuffs_vp8__decoder__num_animation_loops), + (uint64_t(*)(const void*))(&wuffs_vp8__decoder__num_decoded_frame_configs), + (uint64_t(*)(const void*))(&wuffs_vp8__decoder__num_decoded_frames), + (wuffs_base__status(*)(void*, + uint64_t, + uint64_t))(&wuffs_vp8__decoder__restart_frame), + (wuffs_base__status(*)(void*, + uint32_t, + uint64_t))(&wuffs_vp8__decoder__set_quirk), + (wuffs_base__empty_struct(*)(void*, + uint32_t, + bool))(&wuffs_vp8__decoder__set_report_metadata), + (wuffs_base__status(*)(void*, + wuffs_base__io_buffer*, + wuffs_base__more_information*, + wuffs_base__io_buffer*))(&wuffs_vp8__decoder__tell_me_more), + (wuffs_base__range_ii_u64(*)(const void*))(&wuffs_vp8__decoder__workbuf_len), +}; + // ---------------- Initializer Implementations wuffs_base__status WUFFS_BASE__WARN_UNUSED_RESULT -wuffs_vp8__placeholder__initialize( - wuffs_vp8__placeholder* self, +wuffs_vp8__decoder__initialize( + wuffs_vp8__decoder* self, size_t sizeof_star_self, uint64_t wuffs_version, uint32_t options){ @@ -75926,18 +76214,22 @@ } self->private_impl.magic = WUFFS_BASE__MAGIC; + self->private_impl.vtable_for__wuffs_base__image_decoder.vtable_name = + wuffs_base__image_decoder__vtable_name; + self->private_impl.vtable_for__wuffs_base__image_decoder.function_pointers = + (const void*)(&wuffs_vp8__decoder__func_ptrs_for__wuffs_base__image_decoder); return wuffs_base__make_status(NULL); } -wuffs_vp8__placeholder* -wuffs_vp8__placeholder__alloc(void) { - wuffs_vp8__placeholder* x = - (wuffs_vp8__placeholder*)(calloc(1, sizeof(wuffs_vp8__placeholder))); +wuffs_vp8__decoder* +wuffs_vp8__decoder__alloc(void) { + wuffs_vp8__decoder* x = + (wuffs_vp8__decoder*)(calloc(1, sizeof(wuffs_vp8__decoder))); if (!x) { return NULL; } - if (wuffs_vp8__placeholder__initialize( - x, sizeof(wuffs_vp8__placeholder), WUFFS_VERSION, WUFFS_INITIALIZE__ALREADY_ZEROED).repr) { + if (wuffs_vp8__decoder__initialize( + x, sizeof(wuffs_vp8__decoder), WUFFS_VERSION, WUFFS_INITIALIZE__ALREADY_ZEROED).repr) { free(x); return NULL; } @@ -75945,12 +76237,801 @@ } size_t -sizeof__wuffs_vp8__placeholder(void) { - return sizeof(wuffs_vp8__placeholder); +sizeof__wuffs_vp8__decoder(void) { + return sizeof(wuffs_vp8__decoder); } // ---------------- Function Implementations +// -------- func vp8.decoder.get_quirk + +WUFFS_BASE__GENERATED_C_CODE +WUFFS_BASE__MAYBE_STATIC uint64_t +wuffs_vp8__decoder__get_quirk( + const wuffs_vp8__decoder* self, + uint32_t a_key) { + if (!self) { + return 0; + } + if ((self->private_impl.magic != WUFFS_BASE__MAGIC) && + (self->private_impl.magic != WUFFS_BASE__DISABLED)) { + return 0; + } + + return 0u; +} + +// -------- func vp8.decoder.set_quirk + +WUFFS_BASE__GENERATED_C_CODE +WUFFS_BASE__MAYBE_STATIC wuffs_base__status +wuffs_vp8__decoder__set_quirk( + wuffs_vp8__decoder* self, + uint32_t a_key, + uint64_t a_value) { + if (!self) { + return wuffs_base__make_status(wuffs_base__error__bad_receiver); + } + if (self->private_impl.magic != WUFFS_BASE__MAGIC) { + return wuffs_base__make_status( + (self->private_impl.magic == WUFFS_BASE__DISABLED) + ? wuffs_base__error__disabled_by_previous_error + : wuffs_base__error__initialize_not_called); + } + + return wuffs_base__make_status(wuffs_base__error__unsupported_option); +} + +// -------- func vp8.decoder.decode_image_config + +WUFFS_BASE__GENERATED_C_CODE +WUFFS_BASE__MAYBE_STATIC wuffs_base__status +wuffs_vp8__decoder__decode_image_config( + wuffs_vp8__decoder* self, + wuffs_base__image_config* a_dst, + wuffs_base__io_buffer* a_src) { + if (!self) { + return wuffs_base__make_status(wuffs_base__error__bad_receiver); + } + if (self->private_impl.magic != WUFFS_BASE__MAGIC) { + return wuffs_base__make_status( + (self->private_impl.magic == WUFFS_BASE__DISABLED) + ? wuffs_base__error__disabled_by_previous_error + : wuffs_base__error__initialize_not_called); + } + if (!a_src) { + self->private_impl.magic = WUFFS_BASE__DISABLED; + return wuffs_base__make_status(wuffs_base__error__bad_argument); + } + if ((self->private_impl.active_coroutine != 0) && + (self->private_impl.active_coroutine != 1)) { + self->private_impl.magic = WUFFS_BASE__DISABLED; + return wuffs_base__make_status(wuffs_base__error__interleaved_coroutine_calls); + } + self->private_impl.active_coroutine = 0; + wuffs_base__status status = wuffs_base__make_status(NULL); + + wuffs_base__status v_status = wuffs_base__make_status(NULL); + + uint32_t coro_susp_point = self->private_impl.p_decode_image_config; + switch (coro_susp_point) { + WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0; + + while (true) { + { + wuffs_base__status t_0 = wuffs_vp8__decoder__do_decode_image_config(self, a_dst, a_src); + v_status = t_0; + } + if ((v_status.repr == wuffs_base__suspension__short_read) && (a_src && a_src->meta.closed)) { + status = wuffs_base__make_status(wuffs_vp8__error__truncated_input); + goto exit; + } + status = v_status; + WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(1); + } + + ok: + self->private_impl.p_decode_image_config = 0; + goto exit; + } + + goto suspend; + suspend: + self->private_impl.p_decode_image_config = wuffs_base__status__is_suspension(&status) ? coro_susp_point : 0; + self->private_impl.active_coroutine = wuffs_base__status__is_suspension(&status) ? 1 : 0; + + goto exit; + exit: + if (wuffs_base__status__is_error(&status)) { + self->private_impl.magic = WUFFS_BASE__DISABLED; + } + return status; +} + +// -------- func vp8.decoder.do_decode_image_config + +WUFFS_BASE__GENERATED_C_CODE +static wuffs_base__status +wuffs_vp8__decoder__do_decode_image_config( + wuffs_vp8__decoder* self, + wuffs_base__image_config* a_dst, + wuffs_base__io_buffer* a_src) { + wuffs_base__status status = wuffs_base__make_status(NULL); + + uint32_t v_c32 = 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; + const uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL; + if (a_src && a_src->data.ptr) { + io0_a_src = a_src->data.ptr; + io1_a_src = io0_a_src + a_src->meta.ri; + iop_a_src = io1_a_src; + io2_a_src = io0_a_src + a_src->meta.wi; + } + + uint32_t coro_susp_point = self->private_impl.p_do_decode_image_config; + switch (coro_susp_point) { + WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0; + + if (self->private_impl.f_call_sequence != 0u) { + status = wuffs_base__make_status(wuffs_base__error__bad_call_sequence); + goto exit; + } + { + WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1); + uint32_t t_0; + if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 3)) { + t_0 = ((uint32_t)(wuffs_base__peek_u24le__no_bounds_check(iop_a_src))); + iop_a_src += 3; + } else { + self->private_data.s_do_decode_image_config.scratch = 0; + WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2); + 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_do_decode_image_config.scratch; + uint32_t num_bits_0 = ((uint32_t)(*scratch >> 56)); + *scratch <<= 8; + *scratch >>= 8; + *scratch |= ((uint64_t)(*iop_a_src++)) << num_bits_0; + if (num_bits_0 == 16) { + t_0 = ((uint32_t)(*scratch)); + break; + } + num_bits_0 += 8u; + *scratch |= ((uint64_t)(num_bits_0)) << 56; + } + } + v_c32 = t_0; + } + if ((v_c32 & 1u) != 0u) { + status = wuffs_base__make_status(wuffs_vp8__error__unsupported_vp8_file); + goto exit; + } + { + WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3); + uint32_t t_1; + if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 3)) { + t_1 = ((uint32_t)(wuffs_base__peek_u24le__no_bounds_check(iop_a_src))); + iop_a_src += 3; + } else { + self->private_data.s_do_decode_image_config.scratch = 0; + WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4); + 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_do_decode_image_config.scratch; + uint32_t num_bits_1 = ((uint32_t)(*scratch >> 56)); + *scratch <<= 8; + *scratch >>= 8; + *scratch |= ((uint64_t)(*iop_a_src++)) << num_bits_1; + if (num_bits_1 == 16) { + t_1 = ((uint32_t)(*scratch)); + break; + } + num_bits_1 += 8u; + *scratch |= ((uint64_t)(num_bits_1)) << 56; + } + } + v_c32 = t_1; + } + if (v_c32 != 2752925u) { + status = wuffs_base__make_status(wuffs_vp8__error__bad_header); + goto exit; + } + { + WUFFS_BASE__COROUTINE_SUSPENSION_POINT(5); + 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_do_decode_image_config.scratch = 0; + WUFFS_BASE__COROUTINE_SUSPENSION_POINT(6); + 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_do_decode_image_config.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 += 8u; + *scratch |= ((uint64_t)(num_bits_2)) << 56; + } + } + v_c32 = t_2; + } + self->private_impl.f_width = (16383u & (v_c32 >> 0u)); + self->private_impl.f_height = (16383u & (v_c32 >> 16u)); + self->private_impl.f_frame_config_io_position = wuffs_base__u64__sat_add((a_src ? a_src->meta.pos : 0), ((uint64_t)(iop_a_src - io0_a_src))); + if (a_dst != NULL) { + wuffs_base__image_config__set( + a_dst, + 2415954056u, + 0u, + self->private_impl.f_width, + self->private_impl.f_height, + self->private_impl.f_frame_config_io_position, + false); + } + self->private_impl.f_call_sequence = 32u; + + goto ok; + ok: + self->private_impl.p_do_decode_image_config = 0; + goto exit; + } + + goto suspend; + suspend: + self->private_impl.p_do_decode_image_config = wuffs_base__status__is_suspension(&status) ? coro_susp_point : 0; + + goto exit; + exit: + if (a_src && a_src->data.ptr) { + a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr)); + } + + return status; +} + +// -------- func vp8.decoder.decode_frame_config + +WUFFS_BASE__GENERATED_C_CODE +WUFFS_BASE__MAYBE_STATIC wuffs_base__status +wuffs_vp8__decoder__decode_frame_config( + wuffs_vp8__decoder* self, + wuffs_base__frame_config* a_dst, + wuffs_base__io_buffer* a_src) { + if (!self) { + return wuffs_base__make_status(wuffs_base__error__bad_receiver); + } + if (self->private_impl.magic != WUFFS_BASE__MAGIC) { + return wuffs_base__make_status( + (self->private_impl.magic == WUFFS_BASE__DISABLED) + ? wuffs_base__error__disabled_by_previous_error + : wuffs_base__error__initialize_not_called); + } + if (!a_src) { + self->private_impl.magic = WUFFS_BASE__DISABLED; + return wuffs_base__make_status(wuffs_base__error__bad_argument); + } + if ((self->private_impl.active_coroutine != 0) && + (self->private_impl.active_coroutine != 2)) { + self->private_impl.magic = WUFFS_BASE__DISABLED; + return wuffs_base__make_status(wuffs_base__error__interleaved_coroutine_calls); + } + self->private_impl.active_coroutine = 0; + wuffs_base__status status = wuffs_base__make_status(NULL); + + wuffs_base__status v_status = wuffs_base__make_status(NULL); + + uint32_t coro_susp_point = self->private_impl.p_decode_frame_config; + switch (coro_susp_point) { + WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0; + + while (true) { + { + wuffs_base__status t_0 = wuffs_vp8__decoder__do_decode_frame_config(self, a_dst, a_src); + v_status = t_0; + } + if ((v_status.repr == wuffs_base__suspension__short_read) && (a_src && a_src->meta.closed)) { + status = wuffs_base__make_status(wuffs_vp8__error__truncated_input); + goto exit; + } + status = v_status; + WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(1); + } + + ok: + self->private_impl.p_decode_frame_config = 0; + goto exit; + } + + goto suspend; + suspend: + self->private_impl.p_decode_frame_config = wuffs_base__status__is_suspension(&status) ? coro_susp_point : 0; + self->private_impl.active_coroutine = wuffs_base__status__is_suspension(&status) ? 2 : 0; + + goto exit; + exit: + if (wuffs_base__status__is_error(&status)) { + self->private_impl.magic = WUFFS_BASE__DISABLED; + } + return status; +} + +// -------- func vp8.decoder.do_decode_frame_config + +WUFFS_BASE__GENERATED_C_CODE +static wuffs_base__status +wuffs_vp8__decoder__do_decode_frame_config( + wuffs_vp8__decoder* self, + wuffs_base__frame_config* a_dst, + wuffs_base__io_buffer* a_src) { + wuffs_base__status status = wuffs_base__make_status(NULL); + + 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; + const uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL; + if (a_src && a_src->data.ptr) { + io0_a_src = a_src->data.ptr; + io1_a_src = io0_a_src + a_src->meta.ri; + iop_a_src = io1_a_src; + io2_a_src = io0_a_src + a_src->meta.wi; + } + + uint32_t coro_susp_point = self->private_impl.p_do_decode_frame_config; + switch (coro_susp_point) { + WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0; + + if (self->private_impl.f_call_sequence == 32u) { + } else if (self->private_impl.f_call_sequence < 32u) { + if (a_src) { + a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr)); + } + WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1); + status = wuffs_vp8__decoder__do_decode_image_config(self, NULL, a_src); + if (a_src) { + iop_a_src = a_src->data.ptr + a_src->meta.ri; + } + if (status.repr) { + goto suspend; + } + } else if (self->private_impl.f_call_sequence == 40u) { + if (self->private_impl.f_frame_config_io_position != wuffs_base__u64__sat_add((a_src ? a_src->meta.pos : 0), ((uint64_t)(iop_a_src - io0_a_src)))) { + status = wuffs_base__make_status(wuffs_base__error__bad_restart); + goto exit; + } + } else if (self->private_impl.f_call_sequence == 64u) { + self->private_impl.f_call_sequence = 96u; + 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 (a_dst != NULL) { + wuffs_base__frame_config__set( + a_dst, + wuffs_base__utility__make_rect_ie_u32( + 0u, + 0u, + self->private_impl.f_width, + self->private_impl.f_height), + ((wuffs_base__flicks)(0u)), + 0u, + self->private_impl.f_frame_config_io_position, + 0u, + false, + false, + 0u); + } + self->private_impl.f_call_sequence = 64u; + + ok: + self->private_impl.p_do_decode_frame_config = 0; + goto exit; + } + + goto suspend; + suspend: + self->private_impl.p_do_decode_frame_config = wuffs_base__status__is_suspension(&status) ? coro_susp_point : 0; + + goto exit; + exit: + if (a_src && a_src->data.ptr) { + a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr)); + } + + return status; +} + +// -------- func vp8.decoder.decode_frame + +WUFFS_BASE__GENERATED_C_CODE +WUFFS_BASE__MAYBE_STATIC wuffs_base__status +wuffs_vp8__decoder__decode_frame( + wuffs_vp8__decoder* self, + wuffs_base__pixel_buffer* a_dst, + wuffs_base__io_buffer* a_src, + wuffs_base__pixel_blend a_blend, + wuffs_base__slice_u8 a_workbuf, + wuffs_base__decode_frame_options* a_opts) { + if (!self) { + return wuffs_base__make_status(wuffs_base__error__bad_receiver); + } + if (self->private_impl.magic != WUFFS_BASE__MAGIC) { + return wuffs_base__make_status( + (self->private_impl.magic == WUFFS_BASE__DISABLED) + ? wuffs_base__error__disabled_by_previous_error + : wuffs_base__error__initialize_not_called); + } + if (!a_dst || !a_src) { + self->private_impl.magic = WUFFS_BASE__DISABLED; + return wuffs_base__make_status(wuffs_base__error__bad_argument); + } + if ((self->private_impl.active_coroutine != 0) && + (self->private_impl.active_coroutine != 3)) { + self->private_impl.magic = WUFFS_BASE__DISABLED; + return wuffs_base__make_status(wuffs_base__error__interleaved_coroutine_calls); + } + self->private_impl.active_coroutine = 0; + wuffs_base__status status = wuffs_base__make_status(NULL); + + wuffs_base__status v_status = wuffs_base__make_status(NULL); + + uint32_t coro_susp_point = self->private_impl.p_decode_frame; + switch (coro_susp_point) { + WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0; + + while (true) { + { + wuffs_base__status t_0 = wuffs_vp8__decoder__do_decode_frame(self, + a_dst, + a_src, + a_blend, + a_workbuf, + a_opts); + v_status = t_0; + } + if ((v_status.repr == wuffs_base__suspension__short_read) && (a_src && a_src->meta.closed)) { + status = wuffs_base__make_status(wuffs_vp8__error__truncated_input); + goto exit; + } + status = v_status; + WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(1); + } + + ok: + self->private_impl.p_decode_frame = 0; + goto exit; + } + + goto suspend; + suspend: + self->private_impl.p_decode_frame = wuffs_base__status__is_suspension(&status) ? coro_susp_point : 0; + self->private_impl.active_coroutine = wuffs_base__status__is_suspension(&status) ? 3 : 0; + + goto exit; + exit: + if (wuffs_base__status__is_error(&status)) { + self->private_impl.magic = WUFFS_BASE__DISABLED; + } + return status; +} + +// -------- func vp8.decoder.do_decode_frame + +WUFFS_BASE__GENERATED_C_CODE +static wuffs_base__status +wuffs_vp8__decoder__do_decode_frame( + wuffs_vp8__decoder* self, + wuffs_base__pixel_buffer* a_dst, + wuffs_base__io_buffer* a_src, + wuffs_base__pixel_blend a_blend, + wuffs_base__slice_u8 a_workbuf, + wuffs_base__decode_frame_options* a_opts) { + wuffs_base__status status = wuffs_base__make_status(NULL); + + wuffs_base__status v_status = wuffs_base__make_status(NULL); + + uint32_t coro_susp_point = self->private_impl.p_do_decode_frame; + switch (coro_susp_point) { + WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0; + + if (self->private_impl.f_call_sequence == 64u) { + } else if (self->private_impl.f_call_sequence < 64u) { + WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1); + status = wuffs_vp8__decoder__do_decode_frame_config(self, NULL, a_src); + if (status.repr) { + goto suspend; + } + } else { + status = wuffs_base__make_status(wuffs_base__note__end_of_data); + goto ok; + } + self->private_impl.f_dst_x = 0u; + self->private_impl.f_dst_y = 0u; + v_status = wuffs_base__pixel_swizzler__prepare(&self->private_impl.f_swizzler, + wuffs_base__pixel_buffer__pixel_format(a_dst), + wuffs_base__pixel_buffer__palette(a_dst), + wuffs_base__utility__make_pixel_format(2415954056u), + wuffs_base__utility__empty_slice_u8(), + a_blend); + if ( ! wuffs_base__status__is_ok(&v_status)) { + status = v_status; + if (wuffs_base__status__is_error(&status)) { + goto exit; + } else if (wuffs_base__status__is_suspension(&status)) { + status = wuffs_base__make_status(wuffs_base__error__cannot_return_a_suspension); + goto exit; + } + goto ok; + } + v_status = wuffs_vp8__decoder__make_a_placeholder_gradient(self, a_dst); + if ( ! wuffs_base__status__is_ok(&v_status)) { + status = v_status; + if (wuffs_base__status__is_error(&status)) { + goto exit; + } else if (wuffs_base__status__is_suspension(&status)) { + status = wuffs_base__make_status(wuffs_base__error__cannot_return_a_suspension); + goto exit; + } + goto ok; + } + self->private_impl.f_call_sequence = 96u; + + ok: + self->private_impl.p_do_decode_frame = 0; + goto exit; + } + + goto suspend; + suspend: + self->private_impl.p_do_decode_frame = wuffs_base__status__is_suspension(&status) ? coro_susp_point : 0; + + goto exit; + exit: + return status; +} + +// -------- func vp8.decoder.make_a_placeholder_gradient + +WUFFS_BASE__GENERATED_C_CODE +static wuffs_base__status +wuffs_vp8__decoder__make_a_placeholder_gradient( + wuffs_vp8__decoder* self, + wuffs_base__pixel_buffer* a_dst) { + wuffs_base__pixel_format v_dst_pixfmt = {0}; + uint32_t v_dst_bits_per_pixel = 0; + uint32_t v_dst_bytes_per_pixel = 0; + uint64_t v_dst_bytes_per_row = 0; + wuffs_base__table_u8 v_tab = {0}; + wuffs_base__slice_u8 v_dst = {0}; + uint64_t v_i = 0; + uint8_t v_bgrx[4] = {0}; + + v_dst_pixfmt = wuffs_base__pixel_buffer__pixel_format(a_dst); + v_dst_bits_per_pixel = wuffs_base__pixel_format__bits_per_pixel(&v_dst_pixfmt); + if ((v_dst_bits_per_pixel & 7u) != 0u) { + return wuffs_base__make_status(wuffs_base__error__unsupported_option); + } + v_dst_bytes_per_pixel = (v_dst_bits_per_pixel / 8u); + v_dst_bytes_per_row = ((uint64_t)((self->private_impl.f_width * v_dst_bytes_per_pixel))); + v_tab = wuffs_base__pixel_buffer__plane(a_dst, 0u); + v_bgrx[0u] = 128u; + while (self->private_impl.f_dst_y < self->private_impl.f_height) { + v_bgrx[1u] = ((uint8_t)(self->private_impl.f_dst_y)); + self->private_impl.f_dst_x = 0u; + while (self->private_impl.f_dst_x < self->private_impl.f_width) { + v_bgrx[2u] = ((uint8_t)(self->private_impl.f_dst_x)); + v_dst = wuffs_private_impl__table_u8__row_u32(v_tab, self->private_impl.f_dst_y); + if (v_dst_bytes_per_row < ((uint64_t)(v_dst.len))) { + v_dst = wuffs_base__slice_u8__subslice_j(v_dst, v_dst_bytes_per_row); + } + v_i = (((uint64_t)(self->private_impl.f_dst_x)) * ((uint64_t)(v_dst_bytes_per_pixel))); + if (v_i < ((uint64_t)(v_dst.len))) { + wuffs_base__pixel_swizzler__swizzle_interleaved_from_slice(&self->private_impl.f_swizzler, wuffs_base__slice_u8__subslice_i(v_dst, v_i), wuffs_base__pixel_buffer__palette(a_dst), wuffs_base__make_slice_u8(v_bgrx, 4)); + } + self->private_impl.f_dst_x += 1u; + } + self->private_impl.f_dst_y += 1u; + } + return wuffs_base__make_status(NULL); +} + +// -------- func vp8.decoder.frame_dirty_rect + +WUFFS_BASE__GENERATED_C_CODE +WUFFS_BASE__MAYBE_STATIC wuffs_base__rect_ie_u32 +wuffs_vp8__decoder__frame_dirty_rect( + const wuffs_vp8__decoder* self) { + if (!self) { + return wuffs_base__utility__empty_rect_ie_u32(); + } + if ((self->private_impl.magic != WUFFS_BASE__MAGIC) && + (self->private_impl.magic != WUFFS_BASE__DISABLED)) { + return wuffs_base__utility__empty_rect_ie_u32(); + } + + return wuffs_base__utility__make_rect_ie_u32( + 0u, + 0u, + self->private_impl.f_width, + self->private_impl.f_height); +} + +// -------- func vp8.decoder.num_animation_loops + +WUFFS_BASE__GENERATED_C_CODE +WUFFS_BASE__MAYBE_STATIC uint32_t +wuffs_vp8__decoder__num_animation_loops( + const wuffs_vp8__decoder* self) { + if (!self) { + return 0; + } + if ((self->private_impl.magic != WUFFS_BASE__MAGIC) && + (self->private_impl.magic != WUFFS_BASE__DISABLED)) { + return 0; + } + + return 0u; +} + +// -------- func vp8.decoder.num_decoded_frame_configs + +WUFFS_BASE__GENERATED_C_CODE +WUFFS_BASE__MAYBE_STATIC uint64_t +wuffs_vp8__decoder__num_decoded_frame_configs( + const wuffs_vp8__decoder* self) { + if (!self) { + return 0; + } + if ((self->private_impl.magic != WUFFS_BASE__MAGIC) && + (self->private_impl.magic != WUFFS_BASE__DISABLED)) { + return 0; + } + + if (self->private_impl.f_call_sequence > 32u) { + return 1u; + } + return 0u; +} + +// -------- func vp8.decoder.num_decoded_frames + +WUFFS_BASE__GENERATED_C_CODE +WUFFS_BASE__MAYBE_STATIC uint64_t +wuffs_vp8__decoder__num_decoded_frames( + const wuffs_vp8__decoder* self) { + if (!self) { + return 0; + } + if ((self->private_impl.magic != WUFFS_BASE__MAGIC) && + (self->private_impl.magic != WUFFS_BASE__DISABLED)) { + return 0; + } + + if (self->private_impl.f_call_sequence > 64u) { + return 1u; + } + return 0u; +} + +// -------- func vp8.decoder.restart_frame + +WUFFS_BASE__GENERATED_C_CODE +WUFFS_BASE__MAYBE_STATIC wuffs_base__status +wuffs_vp8__decoder__restart_frame( + wuffs_vp8__decoder* self, + uint64_t a_index, + uint64_t a_io_position) { + if (!self) { + return wuffs_base__make_status(wuffs_base__error__bad_receiver); + } + if (self->private_impl.magic != WUFFS_BASE__MAGIC) { + return wuffs_base__make_status( + (self->private_impl.magic == WUFFS_BASE__DISABLED) + ? wuffs_base__error__disabled_by_previous_error + : wuffs_base__error__initialize_not_called); + } + + if (self->private_impl.f_call_sequence < 32u) { + return wuffs_base__make_status(wuffs_base__error__bad_call_sequence); + } + if ((a_index != 0u) || (a_io_position != self->private_impl.f_frame_config_io_position)) { + return wuffs_base__make_status(wuffs_base__error__bad_argument); + } + self->private_impl.f_call_sequence = 40u; + return wuffs_base__make_status(NULL); +} + +// -------- func vp8.decoder.set_report_metadata + +WUFFS_BASE__GENERATED_C_CODE +WUFFS_BASE__MAYBE_STATIC wuffs_base__empty_struct +wuffs_vp8__decoder__set_report_metadata( + wuffs_vp8__decoder* self, + uint32_t a_fourcc, + bool a_report) { + return wuffs_base__make_empty_struct(); +} + +// -------- func vp8.decoder.tell_me_more + +WUFFS_BASE__GENERATED_C_CODE +WUFFS_BASE__MAYBE_STATIC wuffs_base__status +wuffs_vp8__decoder__tell_me_more( + wuffs_vp8__decoder* self, + wuffs_base__io_buffer* a_dst, + wuffs_base__more_information* a_minfo, + wuffs_base__io_buffer* a_src) { + if (!self) { + return wuffs_base__make_status(wuffs_base__error__bad_receiver); + } + if (self->private_impl.magic != WUFFS_BASE__MAGIC) { + return wuffs_base__make_status( + (self->private_impl.magic == WUFFS_BASE__DISABLED) + ? wuffs_base__error__disabled_by_previous_error + : wuffs_base__error__initialize_not_called); + } + if (!a_dst || !a_src) { + self->private_impl.magic = WUFFS_BASE__DISABLED; + return wuffs_base__make_status(wuffs_base__error__bad_argument); + } + if ((self->private_impl.active_coroutine != 0) && + (self->private_impl.active_coroutine != 4)) { + self->private_impl.magic = WUFFS_BASE__DISABLED; + return wuffs_base__make_status(wuffs_base__error__interleaved_coroutine_calls); + } + self->private_impl.active_coroutine = 0; + wuffs_base__status status = wuffs_base__make_status(NULL); + + status = wuffs_base__make_status(wuffs_base__error__no_more_information); + goto exit; + + goto ok; + ok: + goto exit; + exit: + if (wuffs_base__status__is_error(&status)) { + self->private_impl.magic = WUFFS_BASE__DISABLED; + } + return status; +} + +// -------- func vp8.decoder.workbuf_len + +WUFFS_BASE__GENERATED_C_CODE +WUFFS_BASE__MAYBE_STATIC wuffs_base__range_ii_u64 +wuffs_vp8__decoder__workbuf_len( + const wuffs_vp8__decoder* self) { + if (!self) { + return wuffs_base__utility__empty_range_ii_u64(); + } + if ((self->private_impl.magic != WUFFS_BASE__MAGIC) && + (self->private_impl.magic != WUFFS_BASE__DISABLED)) { + return wuffs_base__utility__empty_range_ii_u64(); + } + + return wuffs_base__utility__make_range_ii_u64(0u, 0u); +} + #endif // !defined(WUFFS_CONFIG__MODULES) || defined(WUFFS_CONFIG__MODULE__VP8) #if !defined(WUFFS_CONFIG__MODULES) || defined(WUFFS_CONFIG__MODULE__WBMP) @@ -77060,6 +78141,7 @@ static wuffs_base__status wuffs_webp__decoder__do_decode_image_config_limited( wuffs_webp__decoder* self, + wuffs_base__image_config* a_dst, wuffs_base__io_buffer* a_src); WUFFS_BASE__GENERATED_C_CODE @@ -77204,6 +78286,13 @@ } } + { + wuffs_base__status z = wuffs_vp8__decoder__initialize( + &self->private_data.f_vp8, sizeof(self->private_data.f_vp8), WUFFS_VERSION, options); + if (z.repr) { + return z; + } + } self->private_impl.magic = WUFFS_BASE__MAGIC; self->private_impl.vtable_for__wuffs_base__image_decoder.vtable_name = wuffs_base__image_decoder__vtable_name; @@ -79200,7 +80289,7 @@ if (a_src) { a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr)); } - wuffs_base__status t_2 = wuffs_webp__decoder__do_decode_image_config_limited(self, a_src); + wuffs_base__status t_2 = wuffs_webp__decoder__do_decode_image_config_limited(self, a_dst, a_src); v_status = t_2; if (a_src) { iop_a_src = a_src->data.ptr + a_src->meta.ri; @@ -79232,7 +80321,7 @@ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(5); } self->private_impl.f_frame_config_io_position = wuffs_base__u64__sat_add((a_src ? a_src->meta.pos : 0), ((uint64_t)(iop_a_src - io0_a_src))); - if (a_dst != NULL) { + if ( ! self->private_impl.f_is_vp8_lossy && (a_dst != NULL)) { wuffs_base__image_config__set( a_dst, self->private_impl.f_pixfmt, @@ -79268,6 +80357,7 @@ static wuffs_base__status wuffs_webp__decoder__do_decode_image_config_limited( wuffs_webp__decoder* self, + wuffs_base__image_config* a_dst, wuffs_base__io_buffer* a_src) { wuffs_base__status status = wuffs_base__make_status(NULL); @@ -79353,90 +80443,8 @@ v_c32 = t_1; } if (v_c32 == 540561494u) { - status = wuffs_base__make_status(wuffs_webp__error__unsupported_webp_file); - goto exit; + self->private_impl.f_is_vp8_lossy = true; } else if (v_c32 == 1278758998u) { - { - WUFFS_BASE__COROUTINE_SUSPENSION_POINT(5); - 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_do_decode_image_config_limited.scratch = 0; - WUFFS_BASE__COROUTINE_SUSPENSION_POINT(6); - 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_do_decode_image_config_limited.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 += 8u; - *scratch |= ((uint64_t)(num_bits_2)) << 56; - } - } - self->private_impl.f_sub_chunk_length = t_2; - } - if (self->private_impl.f_sub_chunk_length < 4u) { - status = wuffs_base__make_status(wuffs_webp__error__bad_header); - goto exit; - } - self->private_impl.f_sub_chunk_has_padding = ((self->private_impl.f_sub_chunk_length & 1u) != 0u); - while (true) { - { - const bool o_0_closed_a_src = a_src->meta.closed; - const uint8_t* o_0_io2_a_src = io2_a_src; - wuffs_private_impl__io_reader__limit(&io2_a_src, iop_a_src, - ((uint64_t)(self->private_impl.f_sub_chunk_length))); - if (a_src) { - size_t n = ((size_t)(io2_a_src - a_src->data.ptr)); - a_src->meta.closed = a_src->meta.closed && (a_src->meta.wi <= n); - a_src->meta.wi = n; - } - v_r_mark = ((uint64_t)(iop_a_src - io0_a_src)); - { - if (a_src) { - a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr)); - } - wuffs_base__status t_3 = wuffs_webp__decoder__do_decode_image_config_limited_vp8l(self, a_src); - v_status = t_3; - if (a_src) { - iop_a_src = a_src->data.ptr + a_src->meta.ri; - } - } - wuffs_private_impl__u32__sat_sub_indirect(&self->private_impl.f_sub_chunk_length, ((uint32_t)(wuffs_private_impl__io__count_since(v_r_mark, ((uint64_t)(iop_a_src - io0_a_src)))))); - io2_a_src = o_0_io2_a_src; - if (a_src) { - a_src->meta.closed = o_0_closed_a_src; - a_src->meta.wi = ((size_t)(io2_a_src - a_src->data.ptr)); - } - } - if (wuffs_base__status__is_ok(&v_status)) { - break; - } else if ( ! wuffs_base__status__is_suspension(&v_status)) { - status = v_status; - if (wuffs_base__status__is_error(&status)) { - goto exit; - } else if (wuffs_base__status__is_suspension(&status)) { - status = wuffs_base__make_status(wuffs_base__error__cannot_return_a_suspension); - goto exit; - } - goto ok; - } else if ((v_status.repr == wuffs_base__suspension__short_read) && (self->private_impl.f_sub_chunk_length == 0u)) { - status = wuffs_base__make_status(wuffs_webp__error__short_chunk); - goto exit; - } - status = v_status; - WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(7); - } } else if (v_c32 == 1480085590u) { status = wuffs_base__make_status(wuffs_webp__error__unsupported_webp_file); goto exit; @@ -79444,6 +80452,100 @@ status = wuffs_base__make_status(wuffs_webp__error__bad_header); goto exit; } + { + WUFFS_BASE__COROUTINE_SUSPENSION_POINT(5); + 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_do_decode_image_config_limited.scratch = 0; + WUFFS_BASE__COROUTINE_SUSPENSION_POINT(6); + 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_do_decode_image_config_limited.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 += 8u; + *scratch |= ((uint64_t)(num_bits_2)) << 56; + } + } + self->private_impl.f_sub_chunk_length = t_2; + } + if (self->private_impl.f_sub_chunk_length < 4u) { + status = wuffs_base__make_status(wuffs_webp__error__bad_header); + goto exit; + } + self->private_impl.f_sub_chunk_has_padding = ((self->private_impl.f_sub_chunk_length & 1u) != 0u); + while (true) { + { + const bool o_0_closed_a_src = a_src->meta.closed; + const uint8_t* o_0_io2_a_src = io2_a_src; + wuffs_private_impl__io_reader__limit(&io2_a_src, iop_a_src, + ((uint64_t)(self->private_impl.f_sub_chunk_length))); + if (a_src) { + size_t n = ((size_t)(io2_a_src - a_src->data.ptr)); + a_src->meta.closed = a_src->meta.closed && (a_src->meta.wi <= n); + a_src->meta.wi = n; + } + v_r_mark = ((uint64_t)(iop_a_src - io0_a_src)); + if (self->private_impl.f_is_vp8_lossy) { + { + if (a_src) { + a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr)); + } + wuffs_base__status t_3 = wuffs_vp8__decoder__decode_image_config(&self->private_data.f_vp8, a_dst, a_src); + v_status = t_3; + if (a_src) { + iop_a_src = a_src->data.ptr + a_src->meta.ri; + } + } + } else { + { + if (a_src) { + a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr)); + } + wuffs_base__status t_4 = wuffs_webp__decoder__do_decode_image_config_limited_vp8l(self, a_src); + v_status = t_4; + if (a_src) { + iop_a_src = a_src->data.ptr + a_src->meta.ri; + } + } + } + wuffs_private_impl__u32__sat_sub_indirect(&self->private_impl.f_sub_chunk_length, ((uint32_t)(wuffs_private_impl__io__count_since(v_r_mark, ((uint64_t)(iop_a_src - io0_a_src)))))); + io2_a_src = o_0_io2_a_src; + if (a_src) { + a_src->meta.closed = o_0_closed_a_src; + a_src->meta.wi = ((size_t)(io2_a_src - a_src->data.ptr)); + } + } + if (wuffs_base__status__is_ok(&v_status)) { + break; + } else if ( ! wuffs_base__status__is_suspension(&v_status)) { + status = v_status; + if (wuffs_base__status__is_error(&status)) { + goto exit; + } else if (wuffs_base__status__is_suspension(&status)) { + status = wuffs_base__make_status(wuffs_base__error__cannot_return_a_suspension); + goto exit; + } + goto ok; + } else if ((v_status.repr == wuffs_base__suspension__short_read) && (self->private_impl.f_sub_chunk_length == 0u)) { + status = wuffs_base__make_status(wuffs_webp__error__short_chunk); + goto exit; + } + status = v_status; + WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(7); + } ok: self->private_impl.p_do_decode_image_config_limited = 0; @@ -79606,9 +80708,16 @@ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0; while (true) { - { - wuffs_base__status t_0 = wuffs_webp__decoder__do_decode_frame_config(self, a_dst, a_src); - v_status = t_0; + if (self->private_impl.f_is_vp8_lossy) { + { + wuffs_base__status t_0 = wuffs_vp8__decoder__decode_frame_config(&self->private_data.f_vp8, a_dst, a_src); + v_status = t_0; + } + } else { + { + wuffs_base__status t_1 = wuffs_webp__decoder__do_decode_frame_config(self, a_dst, a_src); + v_status = t_1; + } } if ((v_status.repr == wuffs_base__suspension__short_read) && (a_src && a_src->meta.closed)) { status = wuffs_base__make_status(wuffs_webp__error__truncated_input); @@ -79762,14 +80871,26 @@ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0; while (true) { - { - wuffs_base__status t_0 = wuffs_webp__decoder__do_decode_frame(self, - a_dst, - a_src, - a_blend, - a_workbuf, - a_opts); - v_status = t_0; + if (self->private_impl.f_is_vp8_lossy) { + { + wuffs_base__status t_0 = wuffs_vp8__decoder__decode_frame(&self->private_data.f_vp8, + a_dst, + a_src, + a_blend, + a_workbuf, + a_opts); + v_status = t_0; + } + } else { + { + wuffs_base__status t_1 = wuffs_webp__decoder__do_decode_frame(self, + a_dst, + a_src, + a_blend, + a_workbuf, + a_opts); + v_status = t_1; + } } if ((v_status.repr == wuffs_base__suspension__short_read) && (a_src && a_src->meta.closed)) { status = wuffs_base__make_status(wuffs_webp__error__truncated_input); @@ -80683,6 +81804,9 @@ return wuffs_base__utility__empty_rect_ie_u32(); } + if (self->private_impl.f_is_vp8_lossy) { + return wuffs_vp8__decoder__frame_dirty_rect(&self->private_data.f_vp8); + } return wuffs_base__utility__make_rect_ie_u32( 0u, 0u, @@ -80721,6 +81845,9 @@ return 0; } + if (self->private_impl.f_is_vp8_lossy) { + return wuffs_vp8__decoder__num_decoded_frame_configs(&self->private_data.f_vp8); + } if (self->private_impl.f_call_sequence > 32u) { return 1u; } @@ -80741,6 +81868,9 @@ return 0; } + if (self->private_impl.f_is_vp8_lossy) { + return wuffs_vp8__decoder__num_decoded_frames(&self->private_data.f_vp8); + } if (self->private_impl.f_call_sequence > 64u) { return 1u; } @@ -80765,6 +81895,12 @@ : wuffs_base__error__initialize_not_called); } + wuffs_base__status v_status = wuffs_base__make_status(NULL); + + if (self->private_impl.f_is_vp8_lossy) { + v_status = wuffs_vp8__decoder__restart_frame(&self->private_data.f_vp8, a_index, a_io_position); + return wuffs_private_impl__status__ensure_not_a_suspension(v_status); + } if (self->private_impl.f_call_sequence < 32u) { return wuffs_base__make_status(wuffs_base__error__bad_call_sequence); } @@ -80843,6 +81979,9 @@ return wuffs_base__utility__empty_range_ii_u64(); } + if (self->private_impl.f_is_vp8_lossy) { + return wuffs_vp8__decoder__workbuf_len(&self->private_data.f_vp8); + } return wuffs_base__utility__make_range_ii_u64(((uint64_t)(self->private_impl.f_workbuf_offset_for_transform[3u])), ((uint64_t)(self->private_impl.f_workbuf_offset_for_transform[3u]))); }
diff --git a/std/vp8/decode_vp8.wuffs b/std/vp8/decode_vp8.wuffs index 98b6cf1..27151c4 100644 --- a/std/vp8/decode_vp8.wuffs +++ b/std/vp8/decode_vp8.wuffs
@@ -8,17 +8,276 @@ // // SPDX-License-Identifier: Apache-2.0 OR MIT -// -------- +pub status "#bad header" +pub status "#truncated input" +pub status "#unsupported VP8 file" -// This code is a placeholder. std/webp depends on std/vp8 (a lossy image -// codec) even though, in the very short term, std/webp only implements the -// lossless VP8L format. In the medium term, though, std/webp will also support -// VP8 and the resultant code changes will be smaller and simpler if std/webp -// depends on std/vp8 right from the start. -// -// Also, a std/webm package does not exist yet, but might in the future. If it -// does, it will also depend on std/vp8 (but not std/webp). +pub const DECODER_WORKBUF_LEN_MAX_INCL_WORST_CASE : base.u64 = 0 -pub struct placeholder?( - placeholder : base.u32, +pub struct decoder? implements base.image_decoder( + width : base.u32[..= 0x3FFF], + height : base.u32[..= 0x3FFF], + + // The call sequence state machine is discussed in + // (/doc/std/image-decoders-call-sequence.md). + call_sequence : base.u8, + + frame_config_io_position : base.u64, + + dst_x : base.u32, + dst_y : base.u32, + + swizzler : base.pixel_swizzler, + util : base.utility, ) + +pub func decoder.get_quirk(key: base.u32) base.u64 { + return 0 +} + +pub func decoder.set_quirk!(key: base.u32, value: base.u64) base.status { + return base."#unsupported option" +} + +pub func decoder.decode_image_config?(dst: nptr base.image_config, src: base.io_reader) { + var status : base.status + + while true { + status =? this.do_decode_image_config?(dst: args.dst, src: args.src) + if (status == base."$short read") and args.src.is_closed() { + return "#truncated input" + } + yield? status + } +} + +pri func decoder.do_decode_image_config?(dst: nptr base.image_config, src: base.io_reader) { + var c32 : base.u32 + + if this.call_sequence <> 0x00 { + return base."#bad call sequence" + } + + c32 = args.src.read_u24le_as_u32?() + if (c32 & 0x01) <> 0 { + // TODO: support non-key frames. + return "#unsupported VP8 file" + } + + c32 = args.src.read_u24le_as_u32?() + if c32 <> '\x9D\x01\x2A'le { + return "#bad header" + } + + c32 = args.src.read_u32le?() + this.width = 0x3FFF & (c32 >> 0) + this.height = 0x3FFF & (c32 >> 16) + + this.frame_config_io_position = args.src.position() + + if args.dst <> nullptr { + args.dst.set!( + pixfmt: base.PIXEL_FORMAT__BGRX, + pixsub: 0, + width: this.width, + height: this.height, + first_frame_io_position: this.frame_config_io_position, + first_frame_is_opaque: false) + } + + this.call_sequence = 0x20 +} + +pub func decoder.decode_frame_config?(dst: nptr base.frame_config, src: base.io_reader) { + var status : base.status + + while true { + status =? this.do_decode_frame_config?(dst: args.dst, src: args.src) + if (status == base."$short read") and args.src.is_closed() { + return "#truncated input" + } + yield? status + } +} + +pri func decoder.do_decode_frame_config?(dst: nptr base.frame_config, src: base.io_reader) { + if this.call_sequence == 0x20 { + // No-op. + } else if this.call_sequence < 0x20 { + this.do_decode_image_config?(dst: nullptr, src: args.src) + } else if this.call_sequence == 0x28 { + if this.frame_config_io_position <> args.src.position() { + return base."#bad restart" + } + } else if this.call_sequence == 0x40 { + this.call_sequence = 0x60 + return base."@end of data" + } else { + return base."@end of data" + } + + if args.dst <> nullptr { + args.dst.set!(bounds: this.util.make_rect_ie_u32( + min_incl_x: 0, + min_incl_y: 0, + max_excl_x: this.width, + max_excl_y: this.height), + duration: 0, + index: 0, + io_position: this.frame_config_io_position, + disposal: 0, + opaque_within_bounds: false, + overwrite_instead_of_blend: false, + background_color: 0x0000_0000) + } + + this.call_sequence = 0x40 +} + +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) { + var status : base.status + + while true { + status =? this.do_decode_frame?(dst: args.dst, src: args.src, blend: args.blend, workbuf: args.workbuf, opts: args.opts) + if (status == base."$short read") and args.src.is_closed() { + return "#truncated input" + } + yield? status + } +} + +pri func decoder.do_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) { + var status : base.status + + if this.call_sequence == 0x40 { + // No-op. + } else if this.call_sequence < 0x40 { + this.do_decode_frame_config?(dst: nullptr, src: args.src) + } else { + return base."@end of data" + } + + this.dst_x = 0 + this.dst_y = 0 + + status = this.swizzler.prepare!( + dst_pixfmt: args.dst.pixel_format(), + dst_palette: args.dst.palette(), + src_pixfmt: this.util.make_pixel_format(repr: base.PIXEL_FORMAT__BGRX), + src_palette: this.util.empty_slice_u8(), + blend: args.blend) + if not status.is_ok() { + return status + } + + // TODO: actually decode the pixels. + status = this.make_a_placeholder_gradient!(dst: args.dst) + if not status.is_ok() { + return status + } + + this.call_sequence = 0x60 +} + +pri func decoder.make_a_placeholder_gradient!(dst: ptr base.pixel_buffer) base.status { + var dst_pixfmt : base.pixel_format + var dst_bits_per_pixel : base.u32[..= 256] + var dst_bytes_per_pixel : base.u32[..= 32] + var dst_bytes_per_row : base.u64 + var tab : table base.u8 + var dst : slice base.u8 + var i : base.u64 + var bgrx : array[4] base.u8 + + // TODO: the dst_pixfmt variable shouldn't be necessary. We should be able + // to chain the two calls: "args.dst.pixel_format().bits_per_pixel()". + dst_pixfmt = args.dst.pixel_format() + dst_bits_per_pixel = dst_pixfmt.bits_per_pixel() + if (dst_bits_per_pixel & 7) <> 0 { + return base."#unsupported option" + } + dst_bytes_per_pixel = dst_bits_per_pixel / 8 + dst_bytes_per_row = (this.width * dst_bytes_per_pixel) as base.u64 + tab = args.dst.plane(p: 0) + + bgrx[0] = 0x80 + + while this.dst_y < this.height { + assert this.dst_y < 0x3FFF via "a < b: a < c; c <= b"(c: this.height) + bgrx[1] = (this.dst_y & 0xFF) as base.u8 + + this.dst_x = 0 + while this.dst_x < this.width, + inv this.dst_y < 0x3FFF, + { + assert this.dst_x < 0x3FFF via "a < b: a < c; c <= b"(c: this.width) + bgrx[2] = (this.dst_x & 0xFF) as base.u8 + + dst = tab.row_u32(y: this.dst_y) + if dst_bytes_per_row < dst.length() { + dst = dst[.. dst_bytes_per_row] + } + i = (this.dst_x as base.u64) * (dst_bytes_per_pixel as base.u64) + if i < dst.length() { + this.swizzler.swizzle_interleaved_from_slice!( + dst: dst[i ..], + dst_palette: args.dst.palette(), + src: bgrx[.. 4]) + } + + this.dst_x += 1 + } + this.dst_y += 1 + } + + return ok +} + +pub func decoder.frame_dirty_rect() base.rect_ie_u32 { + return this.util.make_rect_ie_u32( + min_incl_x: 0, + min_incl_y: 0, + max_excl_x: this.width, + max_excl_y: this.height) +} + +pub func decoder.num_animation_loops() base.u32 { + return 0 +} + +pub func decoder.num_decoded_frame_configs() base.u64 { + if this.call_sequence > 0x20 { + return 1 + } + return 0 +} + +pub func decoder.num_decoded_frames() base.u64 { + if this.call_sequence > 0x40 { + return 1 + } + return 0 +} + +pub func decoder.restart_frame!(index: base.u64, io_position: base.u64) base.status { + if this.call_sequence < 0x20 { + return base."#bad call sequence" + } + if (args.index <> 0) or (args.io_position <> this.frame_config_io_position) { + return base."#bad argument" + } + this.call_sequence = 0x28 + return ok +} + +pub func decoder.set_report_metadata!(fourcc: base.u32, report: base.bool) { + // No-op. VP8 doesn't support metadata (but WEBP does). +} + +pub func decoder.tell_me_more?(dst: base.io_writer, minfo: nptr base.more_information, src: base.io_reader) { + return base."#no more information" +} + +pub func decoder.workbuf_len() base.range_ii_u64 { + return this.util.make_range_ii_u64(min_incl: 0, max_incl: 0) +}
diff --git a/std/webp/decode_webp.wuffs b/std/webp/decode_webp.wuffs index fa9d05e..4af5f01 100644 --- a/std/webp/decode_webp.wuffs +++ b/std/webp/decode_webp.wuffs
@@ -42,6 +42,8 @@ sub_chunk_has_padding : base.bool, + is_vp8_lossy : base.bool, + frame_config_io_position : base.u64, riff_chunk_length : base.u32, @@ -91,6 +93,8 @@ // apply_transform_color_indexing modifies the pixel buffer in-place. workbuf_offset_for_color_indexing : base.u32[..= 0x4000_0000], + vp8 : vp8.decoder, + swizzler : base.pixel_swizzler, util : base.utility, ) + ( @@ -178,7 +182,7 @@ while true { io_limit (io: args.src, limit: this.riff_chunk_length as base.u64) { r_mark = args.src.mark() - status =? this.do_decode_image_config_limited?(src: args.src) + status =? this.do_decode_image_config_limited?(dst: args.dst, src: args.src) this.riff_chunk_length ~sat-= (args.src.count_since(mark: r_mark) & 0xFFFF_FFFF) as base.u32 } @@ -195,7 +199,7 @@ this.frame_config_io_position = args.src.position() - if args.dst <> nullptr { + if (not this.is_vp8_lossy) and (args.dst <> nullptr) { args.dst.set!( pixfmt: this.pixfmt, pixsub: 0, @@ -208,7 +212,7 @@ this.call_sequence = 0x20 } -pri func decoder.do_decode_image_config_limited?(src: base.io_reader) { +pri func decoder.do_decode_image_config_limited?(dst: nptr base.image_config, src: base.io_reader) { var c32 : base.u32 var r_mark : base.u64 var status : base.status @@ -220,39 +224,42 @@ c32 = args.src.read_u32le?() if c32 == 'VP8 'le { - return "#unsupported WebP file" - + this.is_vp8_lossy = true } else if c32 == 'VP8L'le { - this.sub_chunk_length = args.src.read_u32le?() - if this.sub_chunk_length < 4 { - return "#bad header" - } - this.sub_chunk_has_padding = (this.sub_chunk_length & 1) <> 0 - - while true { - io_limit (io: args.src, limit: this.sub_chunk_length as base.u64) { - r_mark = args.src.mark() - status =? this.do_decode_image_config_limited_vp8l?(src: args.src) - this.sub_chunk_length ~sat-= - (args.src.count_since(mark: r_mark) & 0xFFFF_FFFF) as base.u32 - } - - if status.is_ok() { - break - } else if not status.is_suspension() { - return status - } else if (status == base."$short read") and (this.sub_chunk_length == 0) { - return "#short chunk" - } - yield? status - } - + // No-op. } else if c32 == 'VP8X'le { return "#unsupported WebP file" - } else { return "#bad header" } + + this.sub_chunk_length = args.src.read_u32le?() + if this.sub_chunk_length < 4 { + return "#bad header" + } + this.sub_chunk_has_padding = (this.sub_chunk_length & 1) <> 0 + + while true { + io_limit (io: args.src, limit: this.sub_chunk_length as base.u64) { + r_mark = args.src.mark() + if this.is_vp8_lossy { + status =? this.vp8.decode_image_config?(dst: args.dst, src: args.src) + } else { + status =? this.do_decode_image_config_limited_vp8l?(src: args.src) + } + this.sub_chunk_length ~sat-= + (args.src.count_since(mark: r_mark) & 0xFFFF_FFFF) as base.u32 + } + + if status.is_ok() { + break + } else if not status.is_suspension() { + return status + } else if (status == base."$short read") and (this.sub_chunk_length == 0) { + return "#short chunk" + } + yield? status + } } pri func decoder.do_decode_image_config_limited_vp8l?(src: base.io_reader) { @@ -288,7 +295,11 @@ var status : base.status while true { - status =? this.do_decode_frame_config?(dst: args.dst, src: args.src) + if this.is_vp8_lossy { + status =? this.vp8.decode_frame_config?(dst: args.dst, src: args.src) + } else { + status =? this.do_decode_frame_config?(dst: args.dst, src: args.src) + } if (status == base."$short read") and args.src.is_closed() { return "#truncated input" } @@ -334,7 +345,11 @@ var status : base.status while true { - status =? this.do_decode_frame?(dst: args.dst, src: args.src, blend: args.blend, workbuf: args.workbuf, opts: args.opts) + if this.is_vp8_lossy { + status =? this.vp8.decode_frame?(dst: args.dst, src: args.src, blend: args.blend, workbuf: args.workbuf, opts: args.opts) + } else { + status =? this.do_decode_frame?(dst: args.dst, src: args.src, blend: args.blend, workbuf: args.workbuf, opts: args.opts) + } if (status == base."$short read") and args.src.is_closed() { return "#truncated input" } @@ -810,6 +825,9 @@ } pub func decoder.frame_dirty_rect() base.rect_ie_u32 { + if this.is_vp8_lossy { + return this.vp8.frame_dirty_rect() + } return this.util.make_rect_ie_u32( min_incl_x: 0, min_incl_y: 0, @@ -822,6 +840,9 @@ } pub func decoder.num_decoded_frame_configs() base.u64 { + if this.is_vp8_lossy { + return this.vp8.num_decoded_frame_configs() + } if this.call_sequence > 0x20 { return 1 } @@ -829,6 +850,9 @@ } pub func decoder.num_decoded_frames() base.u64 { + if this.is_vp8_lossy { + return this.vp8.num_decoded_frames() + } if this.call_sequence > 0x40 { return 1 } @@ -836,6 +860,12 @@ } pub func decoder.restart_frame!(index: base.u64, io_position: base.u64) base.status { + var status : base.status + + if this.is_vp8_lossy { + status = this.vp8.restart_frame!(index: args.index, io_position: args.io_position) + return status + } if this.call_sequence < 0x20 { return base."#bad call sequence" } @@ -855,6 +885,9 @@ } pub func decoder.workbuf_len() base.range_ii_u64 { + if this.is_vp8_lossy { + return this.vp8.workbuf_len() + } return this.util.make_range_ii_u64( min_incl: this.workbuf_offset_for_transform[3] as base.u64, max_incl: this.workbuf_offset_for_transform[3] as base.u64)
diff --git a/test/3pdata/nia-checksums-of-blinksuite.txt b/test/3pdata/nia-checksums-of-blinksuite.txt index 45e9782..6b0a289 100644 --- a/test/3pdata/nia-checksums-of-blinksuite.txt +++ b/test/3pdata/nia-checksums-of-blinksuite.txt
@@ -91,6 +91,7 @@ OK. 1de5a906 test/3pdata/blinksuite/icc-v2-gbr.jpg OK. 0da5f37e test/3pdata/blinksuite/jpeg-height-exif-orientation.jpg OK. 4409dca6 test/3pdata/blinksuite/large-gif-checkerboard.gif +OK. 42c50963 test/3pdata/blinksuite/large.webp BAD 2f310e57 test/3pdata/blinksuite/missing-eoi.jpg OK. 72bbe2b6 test/3pdata/blinksuite/motion-jpeg-single-frame.jpg OK. 0268284a test/3pdata/blinksuite/mu.png @@ -169,7 +170,10 @@ OK. 1b1f5f96 test/3pdata/blinksuite/stripes-large.png OK. 6b85cdb9 test/3pdata/blinksuite/stripes-small.png OK. 16c2c0fe test/3pdata/blinksuite/test-load.jpg +OK. 2e88e913 test/3pdata/blinksuite/test.webp OK. 19d3a207 test/3pdata/blinksuite/test3.webp +OK. 60f368dc test/3pdata/blinksuite/truncated2.webp +OK. 194d8b64 test/3pdata/blinksuite/webp-color-no-profile-lossy.webp BAD ed67a9a5 test/3pdata/blinksuite/wrong-block-length.gif OK. 577c5c4c test/3pdata/blinksuite/ycbcr-420-fast-int-progressive.jpg OK. bf4cd8e2 test/3pdata/blinksuite/ycbcr-420-float-progressive.jpg
diff --git a/test/3pdata/nia-checksums-of-webpsuite.txt b/test/3pdata/nia-checksums-of-webpsuite.txt index f041710..a7a1b2a 100644 --- a/test/3pdata/nia-checksums-of-webpsuite.txt +++ b/test/3pdata/nia-checksums-of-webpsuite.txt
@@ -1,5 +1,7 @@ # Generated by script/print-nia-checksums.sh OK. ca4c0038 test/3pdata/webpsuite/bad_palette_index.webp +OK. 807f5a23 test/3pdata/webpsuite/bryce.webp +OK. 2ee5c270 test/3pdata/webpsuite/bug3.webp OK. 6fbda804 test/3pdata/webpsuite/color_cache_bits_11.webp BAD d338aed8 test/3pdata/webpsuite/dual_transform.webp OK. 1ef61f19 test/3pdata/webpsuite/grid.bmp @@ -47,9 +49,77 @@ BAD 62adeb37 test/3pdata/webpsuite/lossless_vec_2_7.webp OK. 6706e719 test/3pdata/webpsuite/lossless_vec_2_8.webp BAD 62adeb37 test/3pdata/webpsuite/lossless_vec_2_9.webp +OK. d1ed71a2 test/3pdata/webpsuite/lossy_extreme_probabilities.webp +OK. 2e88e913 test/3pdata/webpsuite/lossy_q0_f100.webp OK. 6957defa test/3pdata/webpsuite/near_lossless_75.webp OK. 7c80a001 test/3pdata/webpsuite/one_color_no_palette.webp OK. 6706e719 test/3pdata/webpsuite/peak.bmp OK. 315bbd77 test/3pdata/webpsuite/peak.pgm OK. 6706e719 test/3pdata/webpsuite/peak.png OK. 6706e719 test/3pdata/webpsuite/peak.ppm +OK. 69f5f4ec test/3pdata/webpsuite/segment01.webp +OK. 69f5f4ec test/3pdata/webpsuite/segment02.webp +OK. 69f5f4ec test/3pdata/webpsuite/segment03.webp +OK. 61e94e53 test/3pdata/webpsuite/small_13x1.webp +OK. 2d7e6391 test/3pdata/webpsuite/small_1x1.webp +OK. 7c595111 test/3pdata/webpsuite/small_1x13.webp +OK. 9240e9d0 test/3pdata/webpsuite/small_31x13.webp +OK. 2e88e913 test/3pdata/webpsuite/test-nostrong.webp +OK. 2e88e913 test/3pdata/webpsuite/test.webp +OK. 8b56f1b6 test/3pdata/webpsuite/very_short.webp +OK. c42a950e test/3pdata/webpsuite/vp80-00-comprehensive-001.webp +OK. c42a950e test/3pdata/webpsuite/vp80-00-comprehensive-002.webp +OK. c42a950e test/3pdata/webpsuite/vp80-00-comprehensive-003.webp +OK. c42a950e test/3pdata/webpsuite/vp80-00-comprehensive-004.webp +OK. c42a950e test/3pdata/webpsuite/vp80-00-comprehensive-005.webp +OK. e3e955c2 test/3pdata/webpsuite/vp80-00-comprehensive-006.webp +OK. c42a950e test/3pdata/webpsuite/vp80-00-comprehensive-007.webp +OK. 69cf2fa7 test/3pdata/webpsuite/vp80-00-comprehensive-008.webp +OK. c42a950e test/3pdata/webpsuite/vp80-00-comprehensive-009.webp +OK. 3796a852 test/3pdata/webpsuite/vp80-00-comprehensive-010.webp +OK. c42a950e test/3pdata/webpsuite/vp80-00-comprehensive-011.webp +OK. c42a950e test/3pdata/webpsuite/vp80-00-comprehensive-012.webp +OK. c42a950e test/3pdata/webpsuite/vp80-00-comprehensive-013.webp +OK. e3e955c2 test/3pdata/webpsuite/vp80-00-comprehensive-014.webp +OK. 3796a852 test/3pdata/webpsuite/vp80-00-comprehensive-015.webp +OK. c42a950e test/3pdata/webpsuite/vp80-00-comprehensive-016.webp +OK. c42a950e test/3pdata/webpsuite/vp80-00-comprehensive-017.webp +OK. c42a950e test/3pdata/webpsuite/vp80-01-intra-1400.webp +OK. 4937f445 test/3pdata/webpsuite/vp80-01-intra-1411.webp +OK. c42a950e test/3pdata/webpsuite/vp80-01-intra-1416.webp +OK. c42a950e test/3pdata/webpsuite/vp80-01-intra-1417.webp +OK. c42a950e test/3pdata/webpsuite/vp80-02-inter-1402.webp +OK. 4937f445 test/3pdata/webpsuite/vp80-02-inter-1412.webp +OK. 96b4ed67 test/3pdata/webpsuite/vp80-02-inter-1418.webp +OK. c42a950e test/3pdata/webpsuite/vp80-02-inter-1424.webp +OK. c42a950e test/3pdata/webpsuite/vp80-03-segmentation-1401.webp +OK. c42a950e test/3pdata/webpsuite/vp80-03-segmentation-1403.webp +OK. 1187f564 test/3pdata/webpsuite/vp80-03-segmentation-1407.webp +OK. 1187f564 test/3pdata/webpsuite/vp80-03-segmentation-1408.webp +OK. 1187f564 test/3pdata/webpsuite/vp80-03-segmentation-1409.webp +OK. 1187f564 test/3pdata/webpsuite/vp80-03-segmentation-1410.webp +OK. 4937f445 test/3pdata/webpsuite/vp80-03-segmentation-1413.webp +OK. 3796a852 test/3pdata/webpsuite/vp80-03-segmentation-1414.webp +OK. 3796a852 test/3pdata/webpsuite/vp80-03-segmentation-1415.webp +OK. c42a950e test/3pdata/webpsuite/vp80-03-segmentation-1425.webp +OK. 1187f564 test/3pdata/webpsuite/vp80-03-segmentation-1426.webp +OK. 1187f564 test/3pdata/webpsuite/vp80-03-segmentation-1427.webp +OK. 1187f564 test/3pdata/webpsuite/vp80-03-segmentation-1432.webp +OK. 1187f564 test/3pdata/webpsuite/vp80-03-segmentation-1435.webp +OK. 1187f564 test/3pdata/webpsuite/vp80-03-segmentation-1436.webp +OK. 1187f564 test/3pdata/webpsuite/vp80-03-segmentation-1437.webp +OK. 1187f564 test/3pdata/webpsuite/vp80-03-segmentation-1441.webp +OK. 1187f564 test/3pdata/webpsuite/vp80-03-segmentation-1442.webp +OK. c42a950e test/3pdata/webpsuite/vp80-04-partitions-1404.webp +OK. c42a950e test/3pdata/webpsuite/vp80-04-partitions-1405.webp +OK. c42a950e test/3pdata/webpsuite/vp80-04-partitions-1406.webp +OK. 1187f564 test/3pdata/webpsuite/vp80-05-sharpness-1428.webp +OK. 1187f564 test/3pdata/webpsuite/vp80-05-sharpness-1429.webp +OK. 1187f564 test/3pdata/webpsuite/vp80-05-sharpness-1430.webp +OK. 1187f564 test/3pdata/webpsuite/vp80-05-sharpness-1431.webp +OK. 1187f564 test/3pdata/webpsuite/vp80-05-sharpness-1433.webp +OK. 1187f564 test/3pdata/webpsuite/vp80-05-sharpness-1434.webp +OK. 1187f564 test/3pdata/webpsuite/vp80-05-sharpness-1438.webp +OK. 1187f564 test/3pdata/webpsuite/vp80-05-sharpness-1439.webp +OK. 1187f564 test/3pdata/webpsuite/vp80-05-sharpness-1440.webp +OK. 35ab76d3 test/3pdata/webpsuite/vp80-05-sharpness-1443.webp
diff --git a/test/c/std/webp.c b/test/c/std/webp.c index 9c528b1..23d3b19 100644 --- a/test/c/std/webp.c +++ b/test/c/std/webp.c
@@ -88,7 +88,7 @@ // -------- const char* // -test_wuffs_webp_decode_interface() { +test_wuffs_webp_decode_interface_lossless() { CHECK_FOCUS(__func__); wuffs_webp__decoder* dec = &g_webp_decoder; CHECK_STATUS("initialize", @@ -101,6 +101,19 @@ 0xFF022460); } +const char* // +test_wuffs_webp_decode_interface_lossy() { + CHECK_FOCUS(__func__); + wuffs_webp__decoder* dec = &g_webp_decoder; + CHECK_STATUS("initialize", + wuffs_webp__decoder__initialize( + dec, sizeof *dec, WUFFS_VERSION, + WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED)); + return do_test__wuffs_base__image_decoder( + wuffs_webp__decoder__upcast_as__wuffs_base__image_decoder(dec), + "test/data/bricks-color.lossy.webp", 0, SIZE_MAX, 160, 120, 0xFF9F7780); +} + // ---------------- Mimic Tests #ifdef WUFFS_MIMIC @@ -280,7 +293,8 @@ proc g_tests[] = { - test_wuffs_webp_decode_interface, + test_wuffs_webp_decode_interface_lossless, + test_wuffs_webp_decode_interface_lossy, #ifdef WUFFS_MIMIC