Add std/nie
diff --git a/doc/changelog.md b/doc/changelog.md
index 0b6f1a2..0728955 100644
--- a/doc/changelog.md
+++ b/doc/changelog.md
@@ -21,6 +21,7 @@
- Added `std/cbor`.
- Added `std/gif.config_decoder`.
- Added `std/json`.
+- Added `std/nie`.
- Added `std/wbmp`.
- Added `tell_me_more?` mechanism.
- Added alloc functions.
diff --git a/example/imageviewer/imageviewer.c b/example/imageviewer/imageviewer.c
index 85ad6a5..116cb1c 100644
--- a/example/imageviewer/imageviewer.c
+++ b/example/imageviewer/imageviewer.c
@@ -56,6 +56,7 @@
#define WUFFS_CONFIG__MODULE__BMP
#define WUFFS_CONFIG__MODULE__GIF
#define WUFFS_CONFIG__MODULE__LZW
+#define WUFFS_CONFIG__MODULE__NIE
#define WUFFS_CONFIG__MODULE__WBMP
// If building this program in an environment that doesn't easily accommodate
@@ -92,6 +93,7 @@
union {
wuffs_bmp__decoder bmp;
wuffs_gif__decoder gif;
+ wuffs_nie__decoder nie;
wuffs_wbmp__decoder wbmp;
} g_potential_decoders;
@@ -162,6 +164,19 @@
&g_potential_decoders.gif);
break;
+ case 'n':
+ status = wuffs_nie__decoder__initialize(
+ &g_potential_decoders.nie, sizeof g_potential_decoders.nie,
+ WUFFS_VERSION, WUFFS_INITIALIZE__DEFAULT_OPTIONS);
+ if (!wuffs_base__status__is_ok(&status)) {
+ printf("%s: %s\n", g_filename, wuffs_base__status__message(&status));
+ return false;
+ }
+ g_image_decoder =
+ wuffs_nie__decoder__upcast_as__wuffs_base__image_decoder(
+ &g_potential_decoders.nie);
+ break;
+
default:
printf("%s: unrecognized file format\n", g_filename);
return false;
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index c393fa5..7822c48 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -7630,6 +7630,322 @@
// ---------------- Status Codes
+extern const char wuffs_nie__error__bad_header[];
+extern const char wuffs_nie__error__unsupported_nie_file[];
+
+// ---------------- Public Consts
+
+#define WUFFS_NIE__DECODER_WORKBUF_LEN_MAX_INCL_WORST_CASE 0
+
+// ---------------- Struct Declarations
+
+typedef struct wuffs_nie__decoder__struct wuffs_nie__decoder;
+
+// ---------------- Public Initializer Prototypes
+
+// For any given "wuffs_foo__bar* self", "wuffs_foo__bar__initialize(self,
+// etc)" should be called before any other "wuffs_foo__bar__xxx(self, etc)".
+//
+// Pass sizeof(*self) and WUFFS_VERSION for sizeof_star_self and wuffs_version.
+// Pass 0 (or some combination of WUFFS_INITIALIZE__XXX) for options.
+
+wuffs_base__status WUFFS_BASE__WARN_UNUSED_RESULT
+wuffs_nie__decoder__initialize(
+ wuffs_nie__decoder* self,
+ size_t sizeof_star_self,
+ uint64_t wuffs_version,
+ uint32_t options);
+
+size_t
+sizeof__wuffs_nie__decoder();
+
+// ---------------- Allocs
+
+// These functions allocate and initialize Wuffs structs. They return NULL if
+// memory allocation fails. If they return non-NULL, there is no need to call
+// wuffs_foo__bar__initialize, but the caller is responsible for eventually
+// calling free on the returned pointer. That pointer is effectively a C++
+// std::unique_ptr<T, decltype(&free)>.
+
+wuffs_nie__decoder*
+wuffs_nie__decoder__alloc();
+
+static inline wuffs_base__image_decoder*
+wuffs_nie__decoder__alloc_as__wuffs_base__image_decoder() {
+ return (wuffs_base__image_decoder*)(wuffs_nie__decoder__alloc());
+}
+
+// ---------------- Upcasts
+
+static inline wuffs_base__image_decoder*
+wuffs_nie__decoder__upcast_as__wuffs_base__image_decoder(
+ wuffs_nie__decoder* p) {
+ return (wuffs_base__image_decoder*)p;
+}
+
+// ---------------- Public Function Prototypes
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__empty_struct
+wuffs_nie__decoder__set_quirk_enabled(
+ wuffs_nie__decoder* self,
+ uint32_t a_quirk,
+ bool a_enabled);
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__status
+wuffs_nie__decoder__decode_image_config(
+ wuffs_nie__decoder* self,
+ wuffs_base__image_config* a_dst,
+ wuffs_base__io_buffer* a_src);
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__status
+wuffs_nie__decoder__decode_frame_config(
+ wuffs_nie__decoder* self,
+ wuffs_base__frame_config* a_dst,
+ wuffs_base__io_buffer* a_src);
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__status
+wuffs_nie__decoder__decode_frame(
+ wuffs_nie__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__MAYBE_STATIC wuffs_base__rect_ie_u32
+wuffs_nie__decoder__frame_dirty_rect(
+ const wuffs_nie__decoder* self);
+
+WUFFS_BASE__MAYBE_STATIC uint32_t
+wuffs_nie__decoder__num_animation_loops(
+ const wuffs_nie__decoder* self);
+
+WUFFS_BASE__MAYBE_STATIC uint64_t
+wuffs_nie__decoder__num_decoded_frame_configs(
+ const wuffs_nie__decoder* self);
+
+WUFFS_BASE__MAYBE_STATIC uint64_t
+wuffs_nie__decoder__num_decoded_frames(
+ const wuffs_nie__decoder* self);
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__status
+wuffs_nie__decoder__restart_frame(
+ wuffs_nie__decoder* self,
+ uint64_t a_index,
+ uint64_t a_io_position);
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__empty_struct
+wuffs_nie__decoder__set_report_metadata(
+ wuffs_nie__decoder* self,
+ uint32_t a_fourcc,
+ bool a_report);
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__status
+wuffs_nie__decoder__tell_me_more(
+ wuffs_nie__decoder* self,
+ wuffs_base__io_buffer* a_dst,
+ wuffs_base__more_information* a_minfo,
+ wuffs_base__io_buffer* a_src);
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__range_ii_u64
+wuffs_nie__decoder__workbuf_len(
+ const wuffs_nie__decoder* self);
+
+// ---------------- Struct Definitions
+
+// These structs' fields, and the sizeof them, are private implementation
+// details that aren't guaranteed to be stable across Wuffs versions.
+//
+// See https://en.wikipedia.org/wiki/Opaque_pointer#C
+
+#if defined(__cplusplus) || defined(WUFFS_IMPLEMENTATION)
+
+struct wuffs_nie__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.
+ //
+ // It is a struct, not a struct*, so that the outermost wuffs_foo__bar struct
+ // can be stack allocated when WUFFS_IMPLEMENTATION is defined.
+
+ 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_pixfmt;
+ uint32_t f_width;
+ uint32_t f_height;
+ uint8_t f_call_sequence;
+ uint32_t f_dst_x;
+ uint32_t f_dst_y;
+ wuffs_base__pixel_swizzler f_swizzler;
+
+ uint32_t p_decode_image_config[1];
+ uint32_t p_decode_frame_config[1];
+ uint32_t p_decode_frame[1];
+ } private_impl;
+
+ struct {
+ struct {
+ uint64_t scratch;
+ } s_decode_image_config[1];
+ } private_data;
+
+#ifdef __cplusplus
+#if (__cplusplus >= 201103L)
+ using unique_ptr = std::unique_ptr<wuffs_nie__decoder, decltype(&free)>;
+
+ // On failure, the alloc_etc functions return nullptr. They don't throw.
+
+ static inline unique_ptr
+ alloc() {
+ return unique_ptr(wuffs_nie__decoder__alloc(), &free);
+ }
+
+ static inline wuffs_base__image_decoder::unique_ptr
+ alloc_as__wuffs_base__image_decoder() {
+ return wuffs_base__image_decoder::unique_ptr(
+ wuffs_nie__decoder__alloc_as__wuffs_base__image_decoder(), &free);
+ }
+#endif // (__cplusplus >= 201103L)
+
+#if (__cplusplus >= 201103L) && !defined(WUFFS_IMPLEMENTATION)
+ // Disallow constructing or copying an object via standard C++ mechanisms,
+ // e.g. the "new" operator, as this struct is intentionally opaque. Its total
+ // size and field layout is not part of the public, stable, memory-safe API.
+ // Use malloc or memcpy and the sizeof__wuffs_foo__bar function instead, and
+ // call wuffs_foo__bar__baz methods (which all take a "this"-like pointer as
+ // their first argument) rather than tweaking bar.private_impl.qux fields.
+ //
+ // In C, we can just leave wuffs_foo__bar as an incomplete type (unless
+ // 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_nie__decoder__struct() = delete;
+ wuffs_nie__decoder__struct(const wuffs_nie__decoder__struct&) = delete;
+ wuffs_nie__decoder__struct& operator=(
+ const wuffs_nie__decoder__struct&) = delete;
+
+ // As above, the size of the struct is not part of the public API, and unless
+ // WUFFS_IMPLEMENTATION is #define'd, this struct type T should be heap
+ // allocated, not stack allocated. Its size is not intended to be known at
+ // compile time, but it is unfortunately divulged as a side effect of
+ // defining C++ convenience methods. Use "sizeof__T()", calling the function,
+ // instead of "sizeof T", invoking the operator. To make the two values
+ // different, so that passing the latter will be rejected by the initialize
+ // function, we add an arbitrary amount of dead weight.
+ uint8_t dead_weight[123000000]; // 123 MB.
+#endif // (__cplusplus >= 201103L) && !defined(WUFFS_IMPLEMENTATION)
+
+ inline wuffs_base__status WUFFS_BASE__WARN_UNUSED_RESULT
+ initialize(
+ size_t sizeof_star_self,
+ uint64_t wuffs_version,
+ uint32_t options) {
+ return wuffs_nie__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 wuffs_base__empty_struct
+ set_quirk_enabled(
+ uint32_t a_quirk,
+ bool a_enabled) {
+ return wuffs_nie__decoder__set_quirk_enabled(this, a_quirk, a_enabled);
+ }
+
+ inline wuffs_base__status
+ decode_image_config(
+ wuffs_base__image_config* a_dst,
+ wuffs_base__io_buffer* a_src) {
+ return wuffs_nie__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_nie__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_nie__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_nie__decoder__frame_dirty_rect(this);
+ }
+
+ inline uint32_t
+ num_animation_loops() const {
+ return wuffs_nie__decoder__num_animation_loops(this);
+ }
+
+ inline uint64_t
+ num_decoded_frame_configs() const {
+ return wuffs_nie__decoder__num_decoded_frame_configs(this);
+ }
+
+ inline uint64_t
+ num_decoded_frames() const {
+ return wuffs_nie__decoder__num_decoded_frames(this);
+ }
+
+ inline wuffs_base__status
+ restart_frame(
+ uint64_t a_index,
+ uint64_t a_io_position) {
+ return wuffs_nie__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_nie__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_nie__decoder__tell_me_more(this, a_dst, a_minfo, a_src);
+ }
+
+ inline wuffs_base__range_ii_u64
+ workbuf_len() const {
+ return wuffs_nie__decoder__workbuf_len(this);
+ }
+
+#endif // __cplusplus
+}; // struct wuffs_nie__decoder__struct
+
+#endif // defined(__cplusplus) || defined(WUFFS_IMPLEMENTATION)
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// ---------------- Status Codes
+
extern const char wuffs_wbmp__error__bad_header[];
// ---------------- Public Consts
@@ -27842,6 +28158,845 @@
#endif // !defined(WUFFS_CONFIG__MODULES) || defined(WUFFS_CONFIG__MODULE__JSON)
+#if !defined(WUFFS_CONFIG__MODULES) || defined(WUFFS_CONFIG__MODULE__NIE)
+
+// ---------------- Status Codes Implementations
+
+const char wuffs_nie__error__bad_header[] = "#nie: bad header";
+const char wuffs_nie__error__unsupported_nie_file[] = "#nie: unsupported NIE file";
+const char wuffs_nie__note__internal_note_short_read[] = "@nie: internal note: short read";
+
+// ---------------- Private Consts
+
+// ---------------- Private Initializer Prototypes
+
+// ---------------- Private Function Prototypes
+
+static wuffs_base__status
+wuffs_nie__decoder__swizzle(
+ wuffs_nie__decoder* self,
+ wuffs_base__pixel_buffer* a_dst,
+ wuffs_base__io_buffer* a_src);
+
+// ---------------- VTables
+
+const wuffs_base__image_decoder__func_ptrs
+wuffs_nie__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_nie__decoder__decode_frame),
+ (wuffs_base__status(*)(void*,
+ wuffs_base__frame_config*,
+ wuffs_base__io_buffer*))(&wuffs_nie__decoder__decode_frame_config),
+ (wuffs_base__status(*)(void*,
+ wuffs_base__image_config*,
+ wuffs_base__io_buffer*))(&wuffs_nie__decoder__decode_image_config),
+ (wuffs_base__rect_ie_u32(*)(const void*))(&wuffs_nie__decoder__frame_dirty_rect),
+ (uint32_t(*)(const void*))(&wuffs_nie__decoder__num_animation_loops),
+ (uint64_t(*)(const void*))(&wuffs_nie__decoder__num_decoded_frame_configs),
+ (uint64_t(*)(const void*))(&wuffs_nie__decoder__num_decoded_frames),
+ (wuffs_base__status(*)(void*,
+ uint64_t,
+ uint64_t))(&wuffs_nie__decoder__restart_frame),
+ (wuffs_base__empty_struct(*)(void*,
+ uint32_t,
+ bool))(&wuffs_nie__decoder__set_quirk_enabled),
+ (wuffs_base__empty_struct(*)(void*,
+ uint32_t,
+ bool))(&wuffs_nie__decoder__set_report_metadata),
+ (wuffs_base__status(*)(void*,
+ wuffs_base__io_buffer*,
+ wuffs_base__more_information*,
+ wuffs_base__io_buffer*))(&wuffs_nie__decoder__tell_me_more),
+ (wuffs_base__range_ii_u64(*)(const void*))(&wuffs_nie__decoder__workbuf_len),
+};
+
+// ---------------- Initializer Implementations
+
+wuffs_base__status WUFFS_BASE__WARN_UNUSED_RESULT
+wuffs_nie__decoder__initialize(
+ wuffs_nie__decoder* self,
+ size_t sizeof_star_self,
+ uint64_t wuffs_version,
+ uint32_t options){
+ if (!self) {
+ return wuffs_base__make_status(wuffs_base__error__bad_receiver);
+ }
+ if (sizeof(*self) != sizeof_star_self) {
+ return wuffs_base__make_status(wuffs_base__error__bad_sizeof_receiver);
+ }
+ if (((wuffs_version >> 32) != WUFFS_VERSION_MAJOR) ||
+ (((wuffs_version >> 16) & 0xFFFF) > WUFFS_VERSION_MINOR)) {
+ return wuffs_base__make_status(wuffs_base__error__bad_wuffs_version);
+ }
+
+ if ((options & WUFFS_INITIALIZE__ALREADY_ZEROED) != 0) {
+ // The whole point of this if-check is to detect an uninitialized *self.
+ // We disable the warning on GCC. Clang-5.0 does not have this warning.
+#if !defined(__clang__) && defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#endif
+ if (self->private_impl.magic != 0) {
+ return wuffs_base__make_status(wuffs_base__error__initialize_falsely_claimed_already_zeroed);
+ }
+#if !defined(__clang__) && defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
+ } else {
+ if ((options & WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED) == 0) {
+ memset(self, 0, sizeof(*self));
+ options |= WUFFS_INITIALIZE__ALREADY_ZEROED;
+ } else {
+ memset(&(self->private_impl), 0, sizeof(self->private_impl));
+ }
+ }
+
+ 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_nie__decoder__func_ptrs_for__wuffs_base__image_decoder);
+ return wuffs_base__make_status(NULL);
+}
+
+wuffs_nie__decoder*
+wuffs_nie__decoder__alloc() {
+ wuffs_nie__decoder* x =
+ (wuffs_nie__decoder*)(calloc(sizeof(wuffs_nie__decoder), 1));
+ if (!x) {
+ return NULL;
+ }
+ if (wuffs_nie__decoder__initialize(
+ x, sizeof(wuffs_nie__decoder), WUFFS_VERSION, WUFFS_INITIALIZE__ALREADY_ZEROED).repr) {
+ free(x);
+ return NULL;
+ }
+ return x;
+}
+
+size_t
+sizeof__wuffs_nie__decoder() {
+ return sizeof(wuffs_nie__decoder);
+}
+
+// ---------------- Function Implementations
+
+// -------- func nie.decoder.set_quirk_enabled
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__empty_struct
+wuffs_nie__decoder__set_quirk_enabled(
+ wuffs_nie__decoder* self,
+ uint32_t a_quirk,
+ bool a_enabled) {
+ return wuffs_base__make_empty_struct();
+}
+
+// -------- func nie.decoder.decode_image_config
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__status
+wuffs_nie__decoder__decode_image_config(
+ wuffs_nie__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);
+
+ uint32_t v_a = 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) {
+ 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_decode_image_config[0];
+ switch (coro_susp_point) {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
+
+ if (self->private_impl.f_call_sequence != 0) {
+ 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 >= 4)) {
+ t_0 = wuffs_base__load_u32le__no_bounds_check(iop_a_src);
+ iop_a_src += 4;
+ } else {
+ self->private_data.s_decode_image_config[0].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_decode_image_config[0].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 == 24) {
+ t_0 = ((uint32_t)(*scratch));
+ break;
+ }
+ num_bits_0 += 8;
+ *scratch |= ((uint64_t)(num_bits_0)) << 56;
+ }
+ }
+ v_a = t_0;
+ }
+ if (v_a != 1169146734) {
+ status = wuffs_base__make_status(wuffs_nie__error__bad_header);
+ goto exit;
+ }
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
+ uint32_t t_1;
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 4)) {
+ t_1 = wuffs_base__load_u32le__no_bounds_check(iop_a_src);
+ iop_a_src += 4;
+ } else {
+ self->private_data.s_decode_image_config[0].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_decode_image_config[0].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 == 24) {
+ t_1 = ((uint32_t)(*scratch));
+ break;
+ }
+ num_bits_1 += 8;
+ *scratch |= ((uint64_t)(num_bits_1)) << 56;
+ }
+ }
+ v_a = t_1;
+ }
+ if ((v_a & 255) != 255) {
+ status = wuffs_base__make_status(wuffs_nie__error__bad_header);
+ goto exit;
+ }
+ v_a >>= 8;
+ if (v_a == 3436130) {
+ self->private_impl.f_pixfmt = 2164295816;
+ } else if (v_a == 3698274) {
+ self->private_impl.f_pixfmt = 2164308923;
+ } else if (v_a == 3436642) {
+ status = wuffs_base__make_status(wuffs_nie__error__unsupported_nie_file);
+ goto exit;
+ } else if (v_a == 3698786) {
+ status = wuffs_base__make_status(wuffs_nie__error__unsupported_nie_file);
+ goto exit;
+ } else {
+ status = wuffs_base__make_status(wuffs_nie__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__load_u32le__no_bounds_check(iop_a_src);
+ iop_a_src += 4;
+ } else {
+ self->private_data.s_decode_image_config[0].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_decode_image_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_a = t_2;
+ }
+ if (v_a >= 2147483648) {
+ status = wuffs_base__make_status(wuffs_nie__error__bad_header);
+ goto exit;
+ }
+ self->private_impl.f_width = v_a;
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(7);
+ uint32_t t_3;
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 4)) {
+ t_3 = wuffs_base__load_u32le__no_bounds_check(iop_a_src);
+ iop_a_src += 4;
+ } else {
+ self->private_data.s_decode_image_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_image_config[0].scratch;
+ uint32_t num_bits_3 = ((uint32_t)(*scratch >> 56));
+ *scratch <<= 8;
+ *scratch >>= 8;
+ *scratch |= ((uint64_t)(*iop_a_src++)) << num_bits_3;
+ if (num_bits_3 == 24) {
+ t_3 = ((uint32_t)(*scratch));
+ break;
+ }
+ num_bits_3 += 8;
+ *scratch |= ((uint64_t)(num_bits_3)) << 56;
+ }
+ }
+ v_a = t_3;
+ }
+ if (v_a >= 2147483648) {
+ status = wuffs_base__make_status(wuffs_nie__error__bad_header);
+ goto exit;
+ }
+ self->private_impl.f_height = v_a;
+ if (a_dst != NULL) {
+ wuffs_base__image_config__set(
+ a_dst,
+ self->private_impl.f_pixfmt,
+ 0,
+ self->private_impl.f_width,
+ self->private_impl.f_height,
+ 16,
+ false);
+ }
+ self->private_impl.f_call_sequence = 3;
+
+ goto ok;
+ ok:
+ self->private_impl.p_decode_image_config[0] = 0;
+ goto exit;
+ }
+
+ goto suspend;
+ suspend:
+ self->private_impl.p_decode_image_config[0] = 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 (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+
+ if (wuffs_base__status__is_error(&status)) {
+ self->private_impl.magic = WUFFS_BASE__DISABLED;
+ }
+ return status;
+}
+
+// -------- func nie.decoder.decode_frame_config
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__status
+wuffs_nie__decoder__decode_frame_config(
+ wuffs_nie__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);
+
+ 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) {
+ 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_decode_frame_config[0];
+ switch (coro_susp_point) {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
+
+ if (self->private_impl.f_call_sequence < 3) {
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
+ status = wuffs_nie__decoder__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 == 3) {
+ if (16 != wuffs_base__u64__sat_add(a_src->meta.pos, ((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 == 4) {
+ self->private_impl.f_call_sequence = 255;
+ 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(
+ 0,
+ 0,
+ self->private_impl.f_width,
+ self->private_impl.f_height),
+ ((wuffs_base__flicks)(0)),
+ 0,
+ 16,
+ 0,
+ false,
+ false,
+ 0);
+ }
+ self->private_impl.f_call_sequence = 4;
+
+ goto ok;
+ ok:
+ self->private_impl.p_decode_frame_config[0] = 0;
+ goto exit;
+ }
+
+ goto suspend;
+ suspend:
+ self->private_impl.p_decode_frame_config[0] = 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 (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+
+ if (wuffs_base__status__is_error(&status)) {
+ self->private_impl.magic = WUFFS_BASE__DISABLED;
+ }
+ return status;
+}
+
+// -------- func nie.decoder.decode_frame
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__status
+wuffs_nie__decoder__decode_frame(
+ wuffs_nie__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[0];
+ switch (coro_susp_point) {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
+
+ if (self->private_impl.f_call_sequence < 4) {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
+ status = wuffs_nie__decoder__decode_frame_config(self, NULL, a_src);
+ if (status.repr) {
+ goto suspend;
+ }
+ } else if (self->private_impl.f_call_sequence == 4) {
+ } else {
+ status = wuffs_base__make_status(wuffs_base__note__end_of_data);
+ goto ok;
+ }
+ self->private_impl.f_dst_x = 0;
+ self->private_impl.f_dst_y = 0;
+ 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(self->private_impl.f_pixfmt),
+ 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;
+ }
+ while (true) {
+ v_status = wuffs_nie__decoder__swizzle(self, a_dst, a_src);
+ if (wuffs_base__status__is_ok(&v_status)) {
+ goto label__0__break;
+ } else if (v_status.repr != wuffs_nie__note__internal_note_short_read) {
+ 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;
+ }
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(2);
+ }
+ label__0__break:;
+ self->private_impl.f_call_sequence = 255;
+
+ goto ok;
+ ok:
+ self->private_impl.p_decode_frame[0] = 0;
+ goto exit;
+ }
+
+ goto suspend;
+ suspend:
+ self->private_impl.p_decode_frame[0] = 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 nie.decoder.swizzle
+
+static wuffs_base__status
+wuffs_nie__decoder__swizzle(
+ wuffs_nie__decoder* self,
+ wuffs_base__pixel_buffer* a_dst,
+ wuffs_base__io_buffer* a_src) {
+ wuffs_base__status status = wuffs_base__make_status(NULL);
+
+ wuffs_base__pixel_format v_dst_pixfmt = {0};
+ uint32_t v_dst_bits_per_pixel = 0;
+ uint64_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;
+ uint64_t v_n = 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) {
+ 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;
+ }
+
+ 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 & 7) != 0) {
+ status = wuffs_base__make_status(wuffs_base__error__unsupported_option);
+ goto exit;
+ }
+ v_dst_bytes_per_pixel = ((uint64_t)((v_dst_bits_per_pixel / 8)));
+ 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, 0);
+ if (((uint64_t)(io2_a_src - iop_a_src)) <= 0) {
+ }
+ label__0__continue:;
+ while (true) {
+ if (self->private_impl.f_dst_x == self->private_impl.f_width) {
+ self->private_impl.f_dst_x = 0;
+ self->private_impl.f_dst_y += 1;
+ if (self->private_impl.f_dst_y >= self->private_impl.f_height) {
+ goto label__0__break;
+ }
+ }
+ v_dst = wuffs_base__table_u8__row(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)) * v_dst_bytes_per_pixel);
+ if (v_i >= ((uint64_t)(v_dst.len))) {
+ goto label__0__continue;
+ }
+ v_n = wuffs_base__pixel_swizzler__swizzle_interleaved_from_reader(
+ &self->private_impl.f_swizzler,
+ wuffs_base__slice_u8__subslice_i(v_dst, v_i),
+ wuffs_base__pixel_buffer__palette(a_dst),
+ &iop_a_src,
+ io2_a_src);
+ if (v_n == 0) {
+ status = wuffs_base__make_status(wuffs_nie__note__internal_note_short_read);
+ goto ok;
+ }
+ wuffs_base__u32__sat_add_indirect(&self->private_impl.f_dst_x, ((uint32_t)((v_n & 4294967295))));
+ }
+ label__0__break:;
+ status = wuffs_base__make_status(NULL);
+ goto ok;
+
+ goto ok;
+ ok:
+ goto exit;
+ exit:
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+
+ return status;
+}
+
+// -------- func nie.decoder.frame_dirty_rect
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__rect_ie_u32
+wuffs_nie__decoder__frame_dirty_rect(
+ const wuffs_nie__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(
+ 0,
+ 0,
+ self->private_impl.f_width,
+ self->private_impl.f_height);
+}
+
+// -------- func nie.decoder.num_animation_loops
+
+WUFFS_BASE__MAYBE_STATIC uint32_t
+wuffs_nie__decoder__num_animation_loops(
+ const wuffs_nie__decoder* self) {
+ if (!self) {
+ return 0;
+ }
+ if ((self->private_impl.magic != WUFFS_BASE__MAGIC) &&
+ (self->private_impl.magic != WUFFS_BASE__DISABLED)) {
+ return 0;
+ }
+
+ return 0;
+}
+
+// -------- func nie.decoder.num_decoded_frame_configs
+
+WUFFS_BASE__MAYBE_STATIC uint64_t
+wuffs_nie__decoder__num_decoded_frame_configs(
+ const wuffs_nie__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 > 3) {
+ return 1;
+ }
+ return 0;
+}
+
+// -------- func nie.decoder.num_decoded_frames
+
+WUFFS_BASE__MAYBE_STATIC uint64_t
+wuffs_nie__decoder__num_decoded_frames(
+ const wuffs_nie__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 > 4) {
+ return 1;
+ }
+ return 0;
+}
+
+// -------- func nie.decoder.restart_frame
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__status
+wuffs_nie__decoder__restart_frame(
+ wuffs_nie__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 < 3) {
+ return wuffs_base__make_status(wuffs_base__error__bad_call_sequence);
+ }
+ if ((a_index != 0) || (a_io_position != 16)) {
+ return wuffs_base__make_status(wuffs_base__error__bad_argument);
+ }
+ self->private_impl.f_call_sequence = 3;
+ return wuffs_base__make_status(NULL);
+}
+
+// -------- func nie.decoder.set_report_metadata
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__empty_struct
+wuffs_nie__decoder__set_report_metadata(
+ wuffs_nie__decoder* self,
+ uint32_t a_fourcc,
+ bool a_report) {
+ return wuffs_base__make_empty_struct();
+}
+
+// -------- func nie.decoder.tell_me_more
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__status
+wuffs_nie__decoder__tell_me_more(
+ wuffs_nie__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 nie.decoder.workbuf_len
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__range_ii_u64
+wuffs_nie__decoder__workbuf_len(
+ const wuffs_nie__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(0, 0);
+}
+
+#endif // !defined(WUFFS_CONFIG__MODULES) || defined(WUFFS_CONFIG__MODULE__NIE)
+
#if !defined(WUFFS_CONFIG__MODULES) || defined(WUFFS_CONFIG__MODULE__WBMP)
// ---------------- Status Codes Implementations
diff --git a/std/nie/decode_nie.wuffs b/std/nie/decode_nie.wuffs
new file mode 100644
index 0000000..99ad7fe
--- /dev/null
+++ b/std/nie/decode_nie.wuffs
@@ -0,0 +1,293 @@
+// Copyright 2020 The Wuffs Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+pub status "#bad header"
+pub status "#unsupported NIE file"
+
+pri status "@internal note: short read"
+
+pub const DECODER_WORKBUF_LEN_MAX_INCL_WORST_CASE : base.u64 = 0
+
+pub struct decoder? implements base.image_decoder(
+ pixfmt : base.u32,
+ width : base.u32[..= 0x7FFF_FFFF],
+ height : base.u32[..= 0x7FFF_FFFF],
+
+ // Call sequence states:
+ // - 0x00: initial state.
+ // - 0x03: image config decoded.
+ // - 0x04: frame config decoded.
+ // - 0xFF: end-of-data, usually after (the non-animated) frame decoded.
+ //
+ // State transitions:
+ //
+ // - 0x00 -> 0x03: via DIC
+ // - 0x00 -> 0x04: via DFC with implicit DIC
+ // - 0x00 -> 0xFF: via DF with implicit DIC and DFC
+ //
+ // - 0x03 -> 0x04: via DFC
+ // - 0x03 -> 0xFF: via DF with implicit DFC
+ //
+ // - 0x04 -> 0xFF: via DFC
+ // - 0x04 -> 0xFF: via DF
+ //
+ // - ???? -> 0x03: via RF for ???? > 0x00
+ //
+ // Where:
+ // - DF is decode_frame
+ // - DFC is decode_frame_config, implicit means nullptr args.dst
+ // - DIC is decode_image_config, implicit means nullptr args.dst
+ // - RF is restart_frame
+ call_sequence : base.u8,
+
+ dst_x : base.u32,
+ dst_y : base.u32,
+
+ swizzler : base.pixel_swizzler,
+ util : base.utility,
+)(
+)
+
+pub func decoder.set_quirk_enabled!(quirk: base.u32, enabled: base.bool) {
+}
+
+pub func decoder.decode_image_config?(dst: nptr base.image_config, src: base.io_reader) {
+ var a : base.u32
+
+ if this.call_sequence <> 0 {
+ return base."#bad call sequence"
+ }
+
+ a = args.src.read_u32le?()
+ if a <> 'nïE'le {
+ return "#bad header"
+ }
+
+ a = args.src.read_u32le?()
+ if (a & 0xFF) <> 0xFF {
+ return "#bad header"
+ }
+ a >>= 8
+ if a == 'bn4'le {
+ this.pixfmt = base.PIXEL_FORMAT__BGRA_NONPREMUL
+ } else if a == 'bn8'le {
+ this.pixfmt = base.PIXEL_FORMAT__BGRA_NONPREMUL_4X16LE
+ } else if a == 'bp4'le {
+ return "#unsupported NIE file"
+ } else if a == 'bp8'le {
+ return "#unsupported NIE file"
+ } else {
+ return "#bad header"
+ }
+
+ a = args.src.read_u32le?()
+ if a >= 0x8000_0000 {
+ return "#bad header"
+ }
+ this.width = a
+
+ a = args.src.read_u32le?()
+ if a >= 0x8000_0000 {
+ return "#bad header"
+ }
+ this.height = a
+
+ if args.dst <> nullptr {
+ args.dst.set!(
+ pixfmt: this.pixfmt,
+ pixsub: 0,
+ width: this.width,
+ height: this.height,
+ first_frame_io_position: 16,
+ first_frame_is_opaque: false)
+ }
+
+ this.call_sequence = 3
+}
+
+pub func decoder.decode_frame_config?(dst: nptr base.frame_config, src: base.io_reader) {
+ if this.call_sequence < 3 {
+ this.decode_image_config?(dst: nullptr, src: args.src)
+ } else if this.call_sequence == 3 {
+ if 16 <> args.src.position() {
+ return base."#bad restart"
+ }
+ } else if this.call_sequence == 4 {
+ this.call_sequence = 0xFF
+ 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: 16,
+ disposal: 0,
+ opaque_within_bounds: false,
+ overwrite_instead_of_blend: false,
+ background_color: 0x0000_0000)
+ }
+
+ this.call_sequence = 4
+}
+
+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
+
+ if this.call_sequence < 4 {
+ this.decode_frame_config?(dst: nullptr, src: args.src)
+ } else if this.call_sequence == 4 {
+ // No-op.
+ } 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: this.pixfmt),
+ src_palette: this.util.empty_slice_u8(),
+ blend: args.blend)
+ if not status.is_ok() {
+ return status
+ }
+
+ while true {
+ status = this.swizzle!(dst: args.dst, src: args.src)
+ if status.is_ok() {
+ break
+ } else if status <> "@internal note: short read" {
+ return status
+ }
+ yield? base."$short read"
+ } endwhile
+
+ this.call_sequence = 0xFF
+}
+
+pri func decoder.swizzle!(dst: ptr base.pixel_buffer, src: base.io_reader) base.status {
+ var dst_pixfmt : base.pixel_format
+ var dst_bits_per_pixel : base.u32[..= 256]
+ var dst_bytes_per_pixel : base.u64[..= 32]
+ var dst_bytes_per_row : base.u64
+ var tab : table base.u8
+ var dst : slice base.u8
+ var i : base.u64
+ var n : base.u64
+
+ // 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) as base.u64
+ dst_bytes_per_row = (this.width as base.u64) * dst_bytes_per_pixel
+ tab = args.dst.plane(p: 0)
+
+ // TODO: this hack (to generate derived variables for args.src) shouldn't
+ // be necessary.
+ if args.src.length() <= 0 {
+ }
+
+ while true {
+ if this.dst_x == this.width {
+ this.dst_x = 0
+ this.dst_y ~mod+= 1
+ if this.dst_y >= this.height {
+ break
+ }
+ }
+
+ dst = tab.row(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
+ if i >= dst.length() {
+ // TODO: advance args.src if the dst pixel_buffer bounds is
+ // smaller than this NIE's image bounds?
+ continue
+ }
+ n = this.swizzler.swizzle_interleaved_from_reader!(
+ dst: dst[i ..],
+ dst_palette: args.dst.palette(),
+ src: args.src)
+ if n == 0 {
+ return "@internal note: short read"
+ }
+ this.dst_x ~sat+= (n & 0xFFFF_FFFF) as base.u32
+ } endwhile
+
+ 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 > 3 {
+ return 1
+ }
+ return 0
+}
+
+pub func decoder.num_decoded_frames() base.u64 {
+ if this.call_sequence > 4 {
+ return 1
+ }
+ return 0
+}
+
+pub func decoder.restart_frame!(index: base.u64, io_position: base.u64) base.status {
+ if this.call_sequence < 3 {
+ return base."#bad call sequence"
+ }
+ if (args.index <> 0) or (args.io_position <> 16) {
+ return base."#bad argument"
+ }
+ this.call_sequence = 3
+ return ok
+}
+
+pub func decoder.set_report_metadata!(fourcc: base.u32, report: base.bool) {
+ // No-op. NIE doesn't support metadata.
+}
+
+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/test/c/std/nie.c b/test/c/std/nie.c
new file mode 100644
index 0000000..3b37c6a
--- /dev/null
+++ b/test/c/std/nie.c
@@ -0,0 +1,164 @@
+// Copyright 2020 The Wuffs Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// ----------------
+
+/*
+This test program is typically run indirectly, by the "wuffs test" or "wuffs
+bench" commands. These commands take an optional "-mimic" flag to check that
+Wuffs' output mimics (i.e. exactly matches) other libraries' output, such as
+giflib for GIF, libpng for PNG, etc.
+
+To manually run this test:
+
+for CC in clang gcc; do
+ $CC -std=c99 -Wall -Werror nie.c && ./a.out
+ rm -f a.out
+done
+
+Each edition should print "PASS", amongst other information, and exit(0).
+
+Add the "wuffs mimic cflags" (everything after the colon below) to the C
+compiler flags (after the .c file) to run the mimic tests.
+
+To manually run the benchmarks, replace "-Wall -Werror" with "-O3" and replace
+the first "./a.out" with "./a.out -bench". Combine these changes with the
+"wuffs mimic cflags" to run the mimic benchmarks.
+*/
+
+// !! wuffs mimic cflags: -DWUFFS_MIMIC
+
+// Wuffs ships as a "single file C library" or "header file library" as per
+// https://github.com/nothings/stb/blob/master/docs/stb_howto.txt
+//
+// To use that single file as a "foo.c"-like implementation, instead of a
+// "foo.h"-like header, #define WUFFS_IMPLEMENTATION before #include'ing or
+// compiling it.
+#define WUFFS_IMPLEMENTATION
+
+// Defining the WUFFS_CONFIG__MODULE* macros are optional, but it lets users of
+// release/c/etc.c whitelist which parts of Wuffs to build. That file contains
+// the entire Wuffs standard library, implementing a variety of codecs and file
+// formats. Without this macro definition, an optimizing compiler or linker may
+// very well discard Wuffs code for unused codecs, but listing the Wuffs
+// modules we use makes that process explicit. Preprocessing means that such
+// code simply isn't compiled.
+#define WUFFS_CONFIG__MODULES
+#define WUFFS_CONFIG__MODULE__BASE
+#define WUFFS_CONFIG__MODULE__NIE
+
+// If building this program in an environment that doesn't easily accommodate
+// relative includes, you can use the script/inline-c-relative-includes.go
+// program to generate a stand-alone C file.
+#include "../../../release/c/wuffs-unsupported-snapshot.c"
+#include "../testlib/testlib.c"
+#ifdef WUFFS_MIMIC
+// No mimic library.
+#endif
+
+// --------
+
+const char* //
+test_wuffs_nie_decode_interface() {
+ CHECK_FOCUS(__func__);
+ wuffs_nie__decoder dec;
+ CHECK_STATUS("initialize",
+ wuffs_nie__decoder__initialize(
+ &dec, sizeof dec, WUFFS_VERSION,
+ WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
+ return do_test__wuffs_base__image_decoder(
+ wuffs_nie__decoder__upcast_as__wuffs_base__image_decoder(&dec),
+ "test/data/hippopotamus.nie", 0, SIZE_MAX, 36, 28, 0xFFF5F5F5);
+}
+
+const char* //
+test_wuffs_nie_decode_frame_config() {
+ CHECK_FOCUS(__func__);
+ wuffs_nie__decoder dec;
+ CHECK_STATUS("initialize",
+ wuffs_nie__decoder__initialize(
+ &dec, sizeof dec, WUFFS_VERSION,
+ WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
+
+ wuffs_base__frame_config fc = ((wuffs_base__frame_config){});
+ wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
+ .data = g_src_slice_u8,
+ });
+ CHECK_STRING(read_file(&src, "test/data/crude-flag.nie"));
+ CHECK_STATUS("decode_frame_config #0",
+ wuffs_nie__decoder__decode_frame_config(&dec, &fc, &src));
+
+ wuffs_base__status status =
+ wuffs_nie__decoder__decode_frame_config(&dec, &fc, &src);
+ if (status.repr != wuffs_base__note__end_of_data) {
+ RETURN_FAIL("decode_frame_config #1: have \"%s\", want \"%s\"", status.repr,
+ wuffs_base__note__end_of_data);
+ }
+ return NULL;
+}
+
+// ---------------- Mimic Tests
+
+#ifdef WUFFS_MIMIC
+
+// No mimic tests.
+
+#endif // WUFFS_MIMIC
+
+// ---------------- NIE Benches
+
+// No NIE benches.
+
+// ---------------- Mimic Benches
+
+#ifdef WUFFS_MIMIC
+
+// No mimic benches.
+
+#endif // WUFFS_MIMIC
+
+// ---------------- Manifest
+
+proc g_tests[] = {
+
+ test_wuffs_nie_decode_frame_config,
+ test_wuffs_nie_decode_interface,
+
+#ifdef WUFFS_MIMIC
+
+// No mimic tests.
+
+#endif // WUFFS_MIMIC
+
+ NULL,
+};
+
+proc g_benches[] = {
+
+// No NIE benches.
+
+#ifdef WUFFS_MIMIC
+
+// No mimic benches.
+
+#endif // WUFFS_MIMIC
+
+ NULL,
+};
+
+int //
+main(int argc, char** argv) {
+ g_proc_package_name = "std/nie";
+ return test_main(argc, argv, g_tests, g_benches);
+}