Add std/wbmp package
diff --git a/doc/changelog.md b/doc/changelog.md
index e18c76d..b68f050 100644
--- a/doc/changelog.md
+++ b/doc/changelog.md
@@ -3,6 +3,7 @@
 
 ## Work In Progress
 
+- Added `std/wbmp` package.
 - Renamed `decode_io_writer?` methods to `transform_io?`.
 - Added interfaces.
 - Renamed warnings to notes.
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index 2149bef..2fff95d 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -4121,6 +4121,134 @@
 
 // ---------------- Status Codes
 
+extern const char* wuffs_wbmp__error__bad_header;
+
+// ---------------- Public Consts
+
+// ---------------- Struct Declarations
+
+typedef struct wuffs_wbmp__decoder__struct wuffs_wbmp__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 initialize_flags.
+
+wuffs_base__status WUFFS_BASE__WARN_UNUSED_RESULT  //
+wuffs_wbmp__decoder__initialize(wuffs_wbmp__decoder* self,
+                                size_t sizeof_star_self,
+                                uint64_t wuffs_version,
+                                uint32_t initialize_flags);
+
+size_t  //
+sizeof__wuffs_wbmp__decoder();
+
+// ---------------- Upcasts
+
+// ---------------- Public Function Prototypes
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__status  //
+wuffs_wbmp__decoder__decode_image_config(wuffs_wbmp__decoder* self,
+                                         wuffs_base__image_config* a_dst,
+                                         wuffs_base__io_buffer* a_src);
+
+// ---------------- 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_wbmp__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 null_vtable;
+
+    uint32_t f_width;
+    uint32_t f_height;
+
+    uint32_t p_decode_image_config[1];
+  } private_impl;
+
+  struct {
+    struct {
+      uint32_t v_i;
+      uint32_t v_x32;
+    } s_decode_image_config[1];
+  } private_data;
+
+#ifdef __cplusplus
+#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_wbmp__decoder__struct() = delete;
+  wuffs_wbmp__decoder__struct(const wuffs_wbmp__decoder__struct&) = delete;
+  wuffs_wbmp__decoder__struct& operator=(const wuffs_wbmp__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 initialize_flags) {
+    return wuffs_wbmp__decoder__initialize(this, sizeof_star_self,
+                                           wuffs_version, initialize_flags);
+  }
+
+  inline wuffs_base__status  //
+  decode_image_config(wuffs_base__image_config* a_dst,
+                      wuffs_base__io_buffer* a_src) {
+    return wuffs_wbmp__decoder__decode_image_config(this, a_dst, a_src);
+  }
+
+#endif  // __cplusplus
+
+};  // struct wuffs_wbmp__decoder__struct
+
+#endif  // defined(__cplusplus) || defined(WUFFS_IMPLEMENTATION)
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// ---------------- Status Codes
+
 extern const char* wuffs_zlib__note__dictionary_required;
 extern const char* wuffs_zlib__error__bad_checksum;
 extern const char* wuffs_zlib__error__bad_compression_method;
@@ -12682,6 +12810,214 @@
 #endif  // !defined(WUFFS_CONFIG__MODULES) ||
         // defined(WUFFS_CONFIG__MODULE__GZIP)
 
+#if !defined(WUFFS_CONFIG__MODULES) || defined(WUFFS_CONFIG__MODULE__WBMP)
+
+// ---------------- Status Codes Implementations
+
+const char* wuffs_wbmp__error__bad_header = "#wbmp: bad header";
+
+// ---------------- Private Consts
+
+// ---------------- Private Initializer Prototypes
+
+// ---------------- Private Function Prototypes
+
+// ---------------- VTables
+
+// ---------------- Initializer Implementations
+
+wuffs_base__status WUFFS_BASE__WARN_UNUSED_RESULT  //
+wuffs_wbmp__decoder__initialize(wuffs_wbmp__decoder* self,
+                                size_t sizeof_star_self,
+                                uint64_t wuffs_version,
+                                uint32_t initialize_flags) {
+  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 ((initialize_flags & 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 ((initialize_flags &
+         WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED) == 0) {
+      memset(self, 0, sizeof(*self));
+      initialize_flags |= WUFFS_INITIALIZE__ALREADY_ZEROED;
+    } else {
+      memset(&(self->private_impl), 0, sizeof(self->private_impl));
+    }
+  }
+
+  self->private_impl.magic = WUFFS_BASE__MAGIC;
+  return wuffs_base__make_status(NULL);
+}
+
+size_t  //
+sizeof__wuffs_wbmp__decoder() {
+  return sizeof(wuffs_wbmp__decoder);
+}
+
+// ---------------- Function Implementations
+
+// -------- func wbmp.decoder.decode_image_config
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__status  //
+wuffs_wbmp__decoder__decode_image_config(wuffs_wbmp__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);
+
+  uint8_t v_c = 0;
+  uint32_t v_i = 0;
+  uint32_t v_x32 = 0;
+  uint64_t v_x64 = 0;
+
+  uint8_t* iop_a_src = NULL;
+  uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+  uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+  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];
+  if (coro_susp_point) {
+    v_i = self->private_data.s_decode_image_config[0].v_i;
+    v_x32 = self->private_data.s_decode_image_config[0].v_x32;
+  }
+  switch (coro_susp_point) {
+    WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
+
+    v_i = 0;
+    while (v_i < 2) {
+      {
+        WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
+        if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+          status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+          goto suspend;
+        }
+        uint8_t t_0 = *iop_a_src++;
+        v_c = t_0;
+      }
+      if (v_c != 0) {
+        status = wuffs_base__make_status(wuffs_wbmp__error__bad_header);
+        goto exit;
+      }
+      v_i += 1;
+    }
+    v_i = 0;
+    while (v_i < 2) {
+      v_x32 = 0;
+      while (true) {
+        {
+          WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
+          if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+            status =
+                wuffs_base__make_status(wuffs_base__suspension__short_read);
+            goto suspend;
+          }
+          uint8_t t_1 = *iop_a_src++;
+          v_c = t_1;
+        }
+        v_x32 |= ((uint32_t)((v_c & 127)));
+        if ((v_c >> 7) == 0) {
+          goto label_0_break;
+        }
+        v_x64 = (((uint64_t)(v_x32)) << 7);
+        if (v_x64 > 4294967295) {
+          status = wuffs_base__make_status(wuffs_wbmp__error__bad_header);
+          goto exit;
+        }
+        v_x32 = ((uint32_t)(v_x64));
+      }
+    label_0_break:;
+      if (v_i == 0) {
+        self->private_impl.f_width = v_x32;
+      } else {
+        self->private_impl.f_height = v_x32;
+      }
+      v_i += 1;
+    }
+    if (a_dst != NULL) {
+      wuffs_base__image_config__set(
+          a_dst, 1191444488, 0, self->private_impl.f_width,
+          self->private_impl.f_height,
+          wuffs_base__u64__sat_add(a_src->meta.pos,
+                                   ((uint64_t)(iop_a_src - io0_a_src))),
+          true);
+    }
+
+    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;
+  self->private_data.s_decode_image_config[0].v_i = v_i;
+  self->private_data.s_decode_image_config[0].v_x32 = v_x32;
+
+  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;
+}
+
+#endif  // !defined(WUFFS_CONFIG__MODULES) ||
+        // defined(WUFFS_CONFIG__MODULE__WBMP)
+
 #if !defined(WUFFS_CONFIG__MODULES) || defined(WUFFS_CONFIG__MODULE__ZLIB)
 
 // ---------------- Status Codes Implementations
diff --git a/std/wbmp/decode_wbmp.wuffs b/std/wbmp/decode_wbmp.wuffs
new file mode 100644
index 0000000..293b5b6
--- /dev/null
+++ b/std/wbmp/decode_wbmp.wuffs
@@ -0,0 +1,77 @@
+// 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 struct decoder?(
+	width  : base.u32,
+	height : base.u32,
+)
+
+pub func decoder.decode_image_config?(dst: nptr base.image_config, src: base.io_reader) {
+	var c   : base.u8
+	var i   : base.u32
+	var x32 : base.u32
+	var x64 : base.u64
+
+	// TypeField, FixHeaderField.
+	i = 0
+	while i < 2 {
+		c = args.src.read_u8?()
+		if c <> 0 {
+			return "#bad header"
+		}
+		i += 1
+	}
+
+	// Width, height.
+	i = 0
+	while i < 2 {
+		x32 = 0
+
+		while true,
+			inv i < 2,
+		{
+			c = args.src.read_u8?()
+			x32 |= (c & 0x7F) as base.u32
+			if (c >> 7) == 0 {
+				break
+			}
+			x64 = (x32 as base.u64) << 7
+			if x64 > 0xFFFFFFFF {
+				return "#bad header"
+			}
+			x32 = x64 as base.u32
+		}
+
+		if i == 0 {
+			this.width = x32
+		} else {
+			this.height = x32
+		}
+		i += 1
+	}
+
+	if args.dst <> nullptr {
+		// TODO: a Wuffs (not just C) name for the
+		// WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_BINARY magic pixfmt constant.
+		args.dst.set!(
+			pixfmt: 0x47040008,
+			pixsub: 0,
+			width: this.width,
+			height: this.height,
+			first_frame_io_position: args.src.position(),
+			first_frame_is_opaque: true)
+	}
+}
diff --git a/test/c/std/wbmp.c b/test/c/std/wbmp.c
new file mode 100644
index 0000000..8946b29
--- /dev/null
+++ b/test/c/std/wbmp.c
@@ -0,0 +1,155 @@
+// 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 wbmp.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__WBMP
+
+// 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
+
+// ---------------- WBMP Tests
+
+const char* test_wuffs_wbmp_decode_image_config() {
+  CHECK_FOCUS(__func__);
+  wuffs_wbmp__decoder dec;
+  CHECK_STATUS("initialize",
+               wuffs_wbmp__decoder__initialize(
+                   &dec, sizeof dec, WUFFS_VERSION,
+                   WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
+
+  wuffs_base__image_config ic = ((wuffs_base__image_config){});
+  wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
+      .data = global_src_slice,
+  });
+  CHECK_STRING(read_file(&src, "test/data/muybridge-frame-000.wbmp"));
+  CHECK_STATUS("decode_image_config",
+               wuffs_wbmp__decoder__decode_image_config(&dec, &ic, &src));
+
+  uint32_t got_width = wuffs_base__pixel_config__width(&ic.pixcfg);
+  uint32_t want_width = 30;
+  if (got_width != want_width) {
+    RETURN_FAIL("width: got %" PRIu32 ", want %" PRIu32, got_width, want_width);
+  }
+  uint32_t got_height = wuffs_base__pixel_config__height(&ic.pixcfg);
+  uint32_t want_height = 20;
+  if (got_height != want_height) {
+    RETURN_FAIL("height: got %" PRIu32 ", want %" PRIu32, got_height,
+                want_height);
+  }
+  return NULL;
+}
+
+  // ---------------- Mimic Tests
+
+#ifdef WUFFS_MIMIC
+
+  // No mimic tests.
+
+#endif  // WUFFS_MIMIC
+
+  // ---------------- WBMP Benches
+
+  // No WBMP benches.
+
+  // ---------------- Mimic Benches
+
+#ifdef WUFFS_MIMIC
+
+  // No mimic benches.
+
+#endif  // WUFFS_MIMIC
+
+// ---------------- Manifest
+
+// The empty comments forces clang-format to place one element per line.
+proc tests[] = {
+
+    test_wuffs_wbmp_decode_image_config,  //
+
+#ifdef WUFFS_MIMIC
+
+// No mimic tests.
+
+#endif  // WUFFS_MIMIC
+
+    NULL,
+};
+
+// The empty comments forces clang-format to place one element per line.
+proc benches[] = {
+
+// No WBMP benches.
+
+#ifdef WUFFS_MIMIC
+
+// No mimic benches.
+
+#endif  // WUFFS_MIMIC
+
+    NULL,
+};
+
+int main(int argc, char** argv) {
+  proc_package_name = "std/wbmp";
+  return test_main(argc, argv, tests, benches);
+}