Merge branch 'master' into fix-typos

This commit is contained in:
Nigel Tao
2020-01-17 13:38:12 +11:00
committed by GitHub
69 changed files with 7033 additions and 2807 deletions

View File

@@ -70,6 +70,12 @@ wuffs test -skipgen -mimic
wuffs bench -skipgen -mimic -reps=1 -iterscale=1
./build-example.sh
LICENSE_CRC32=$(gen/bin/example-crc32 < LICENSE)
if [ "$LICENSE_CRC32" != "1ea3b7b0" ]; then
echo "LICENSE crc32 mismatch"
exit 1
fi
./build-fuzz.sh
for f in gen/bin/fuzz-*; do
echo "Running $f"

View File

@@ -43,6 +43,10 @@ for f in $sources; do
echo "Building gen/bin/example-$f"
# example/crc32 is unusual in that it's C++, not C.
$CXX -O3 example/$f/*.cc -o gen/bin/example-$f
elif [ $f = imageviewer ]; then
# example/imageviewer is unusual in that needs additional libraries.
echo "Building gen/bin/example-$f"
$CC -O3 example/$f/*.c -lxcb -lxcb-image -o gen/bin/example-$f
elif [ $f = library ]; then
# example/library is unusual in that it uses separately compiled libraries
# (built by "wuffs genlib", e.g. by running build-all.sh) instead of

View File

@@ -314,11 +314,20 @@ func (h *genHelper) genWuffs(dirname string, qualifiedFilenames []string) error
if !n.Public() {
continue
}
classy := ""
fmt.Fprintf(out, "pub struct %s", n.QID().Str(&h.tm))
if n.Classy() {
classy = "?"
fmt.Fprintf(out, "?")
}
fmt.Fprintf(out, "pub struct %s%s()\n", n.QID().Str(&h.tm), classy)
if imps := n.Implements(); len(imps) > 0 {
fmt.Fprintf(out, " implements ")
for i, imp := range imps {
if i > 0 {
fmt.Fprintf(out, ", ")
}
fmt.Fprintf(out, "%s", imp.AsTypeExpr().Str(&h.tm))
}
}
fmt.Fprintf(out, "()\n")
}
}
}

View File

@@ -1,6 +1,18 @@
# Changelog
## Work In Progress
- Added `std/wbmp` package.
- Renamed `decode_io_writer?` methods to `transform_io?`.
- Added interfaces.
- Renamed warnings to notes.
- Made `wuffs_base__pixel_format` a struct.
- Made `wuffs_base__pixel_subsampling` a struct.
- Made `wuffs_base__status` a struct.
- Removed `wuffs_base__frame_config__blend`.
## 2019-12-19 version 0.2.0
The headline feature is that the GIF decoder is now of production quality.
@@ -96,4 +108,4 @@ Wuffs version 0.1.
---
Updated on December 2019.
Updated on January 2020.

View File

@@ -5,7 +5,7 @@ involving [I/O](/doc/note/io-input-output.md) - return a status value. There
are four categories:
- OK: the request was completed, successfully.
- Warnings: the request was completed, unsuccessfully.
- Notes: the request was completed, unsuccessfully.
- Suspensions: the request was not completed, but can be re-tried.
- Errors: the request was not completed, permanently.
@@ -18,12 +18,12 @@ When a method returns a suspension, the suspended
again. However, calling any other public coroutine method, while already
suspended, will lead to an `"#interleaved coroutine calls"` error.
Otherwise, the call was complete. 'Warning' or 'unsuccessful' doesn't
Otherwise, the call was complete. 'Unsuccessful' (i.e. a note) doesn't
necessarily mean 'bad' or something to avoid, only that something occurred
other than the typical outcome. For example, when decoding an animated image,
without knowing the number of frames beforehand, a call to "decode the next
frame" could return OK, if there was a next frame, or an `"@end of data"`
warning, if there wasn't.
frame" could return OK, if there was a next frame, or an `"@end of data"` note,
if there wasn't.
## Statuses are Strings
@@ -60,17 +60,17 @@ information such as a source filename.
The first byte of the string message gives the category. For example, `"#bad
receiver"` is an error and `"$short read"` is a suspension:
- `'@'` means a warning.
- `'@'` means a note.
- `'$'` means a suspension.
- `'#'` means an error.
## C Implementation
In terms of C implementation, a status value is just its string message: a
`const char *`, with `ok` being the null pointer. That C string is statically
allocated and should never be `free`d. Status values can be compared by the
`==` operator and not just by `strcmp`.
In terms of C implementation, a status' `repr` (representation) is just its
string message: a `const char *`, with `ok` being the null pointer. That C
string is statically allocated and should never be `free`d. Status `repr`s can
be compared by the `==` operator and not just by `strcmp`.
The C string's contents has the Wuffs package name inserted by the Wuffs
compiler, just after that first byte. For example, the `std/deflate` package

View File

@@ -11,20 +11,20 @@ categories:
The general pattern is that a package `foo` (e.g. `jpeg`, `png`) contains a
struct `bar` (e.g. `hasher`, `decoder`, etc) that implements a
package-independent interface. For example, every compression decoder struct
would have a `decode_io_writer` method. In C, this would be invoked as
would have a `transform_io` method. In C, this would be invoked as
```
// Allocate and initialize the struct.
wuffs_foo__decoder* dec = etc;
// Do the work. Error checking is not shown, for brevity.
const char* status = wuffs_foo__decoder__decode_io_writer(dec, etc);
const char* status = wuffs_foo__decoder__transform_io(dec, etc);
```
When that C library is used as C++, that last line can be shortened:
```
const char* status = dec->decode_io_writer(etc);
const char* status = dec->transform_io(etc);
```
See also the [glossary](/doc/glossary.md), as well as the notes on:

View File

@@ -2,10 +2,8 @@
Compression decoders read from one input stream (an `io_reader` called `src`)
and write to an output stream (an `io_writer` called `dst`). Wuffs'
implementations have one key method: `decode_io_writer`, named after the
operation (decoding) and the type of the destination (an
[`io_writer`](/doc/note/io-input-output.md)). It incrementally decompresses the
source data.
implementations have one key method: `transform_io`. It incrementally
decompresses the source data.
This method is a [coroutine](/doc/note/coroutines.md), and does not require
either all of the input or all of the output to fit in a single contiguous

View File

@@ -31,7 +31,7 @@ wuffs_base__pixel_buffer pb = etc;
while (true) {
wuffs_base__frame_config fc;
status = wuffs_gif__decoder__decode_frame_config(dec, &fc, &src);
if (status == wuffs_base__warning__end_of_data) {
if (status == wuffs_base__note__end_of_data) {
break;
}
// Ditto re error checking.

View File

@@ -59,8 +59,8 @@ uint8_t src_buffer[SRC_BUFFER_SIZE];
int main(int argc, char** argv) {
wuffs_crc32__ieee_hasher h;
wuffs_base__status status = h.initialize(sizeof h, WUFFS_VERSION, 0);
if (status) {
fprintf(stderr, "%s\n", wuffs_base__status__message(status));
if (!status.is_ok()) {
fprintf(stderr, "%s\n", status.message());
return 1;
}

View File

@@ -273,8 +273,8 @@ const char* try_allocate(wuffs_gif__decoder* dec,
}
const char* allocate(wuffs_gif__decoder* dec, wuffs_base__image_config* ic) {
const char* status = try_allocate(dec, ic);
if (status) {
const char* status_msg = try_allocate(dec, ic);
if (status_msg) {
free(printbuf.ptr);
printbuf = wuffs_base__make_slice_u8(NULL, 0);
free(workbuf.ptr);
@@ -287,15 +287,15 @@ const char* allocate(wuffs_gif__decoder* dec, wuffs_base__image_config* ic) {
curr_dst_buffer = NULL;
dst_len = 0;
}
return status;
return status_msg;
}
const char* play() {
wuffs_gif__decoder dec;
wuffs_base__status status =
wuffs_gif__decoder__initialize(&dec, sizeof dec, WUFFS_VERSION, 0);
if (status) {
return wuffs_base__status__message(status);
if (!wuffs_base__status__is_ok(&status)) {
return wuffs_base__status__message(&status);
}
if (quirk_honor_background_color_flag) {
@@ -314,8 +314,8 @@ const char* play() {
if (first_play) {
wuffs_base__image_config ic = {0};
status = wuffs_gif__decoder__decode_image_config(&dec, &ic, &src);
if (status) {
return wuffs_base__status__message(status);
if (!wuffs_base__status__is_ok(&status)) {
return wuffs_base__status__message(&status);
}
if (!wuffs_base__image_config__is_valid(&ic)) {
return "invalid image configuration";
@@ -336,8 +336,8 @@ const char* play() {
return msg;
}
status = wuffs_base__pixel_buffer__set_from_slice(&pb, &ic.pixcfg, pixbuf);
if (status) {
return wuffs_base__status__message(status);
if (!wuffs_base__status__is_ok(&status)) {
return wuffs_base__status__message(&status);
}
memset(pixbuf.ptr, 0, pixbuf.len);
}
@@ -346,11 +346,11 @@ const char* play() {
wuffs_base__frame_config fc = {0};
wuffs_base__status status =
wuffs_gif__decoder__decode_frame_config(&dec, &fc, &src);
if (status) {
if (status == wuffs_base__warning__end_of_data) {
if (!wuffs_base__status__is_ok(&status)) {
if (status.repr == wuffs_base__note__end_of_data) {
break;
}
return wuffs_base__status__message(status);
return wuffs_base__status__message(&status);
}
if (wuffs_base__frame_config__index(&fc) == 0) {
@@ -370,9 +370,9 @@ const char* play() {
}
}
wuffs_base__status decode_frame_status =
wuffs_gif__decoder__decode_frame(&dec, &pb, &src, workbuf, NULL);
if (decode_frame_status == wuffs_base__warning__end_of_data) {
wuffs_base__status decode_frame_status = wuffs_gif__decoder__decode_frame(
&dec, &pb, &src, WUFFS_BASE__PIXEL_BLEND__SRC, workbuf, NULL);
if (decode_frame_status.repr == wuffs_base__note__end_of_data) {
break;
}
@@ -422,8 +422,8 @@ const char* play() {
// TODO: should a zero duration mean to show this frame forever?
if (decode_frame_status) {
return wuffs_base__status__message(decode_frame_status);
if (!wuffs_base__status__is_ok(&decode_frame_status)) {
return wuffs_base__status__message(&decode_frame_status);
}
}
@@ -446,16 +446,16 @@ int main(int argc, char** argv) {
}
}
const char* status = read_stdin();
if (status) {
fprintf(stderr, "%s\n", status);
const char* status_msg = read_stdin();
if (status_msg) {
fprintf(stderr, "%s\n", status_msg);
return 1;
}
while (true) {
status = play();
if (status) {
fprintf(stderr, "%s\n", status);
status_msg = play();
if (status_msg) {
fprintf(stderr, "%s\n", status_msg);
return 1;
}
if (num_loops_remaining == 0) {

View File

@@ -0,0 +1,462 @@
// 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.
// ----------------
/*
imageviewer is a simple GUI program for viewing images. On Linux, GUI means
X11. To run:
$CC imageviewer.c -lxcb -lxcb-image && \
./a.out ../../test/data/bricks-*.gif; rm -f a.out
for a C compiler $CC, such as clang or gcc.
The Space and BackSpace keys cycle through the files, if more than one was
given as command line arguments. If none were given, the program reads from
stdin.
The Return key is equivalent to the Space key.
The Escape key quits.
*/
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
// 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__GIF
#define WUFFS_CONFIG__MODULE__LZW
#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"
// X11 limits its image dimensions to uint16_t.
#define MAX_DIMENSION 65535
#define SRC_BUFFER_SIZE (64 * 1024)
// Global variable names start with a "g_" prefix.
FILE* g_file = NULL;
const char* g_filename = NULL;
uint32_t g_width = 0;
uint32_t g_height = 0;
wuffs_base__slice_u8 g_workbuf_slice = {0};
wuffs_base__slice_u8 g_pixbuf_slice = {0};
wuffs_base__pixel_buffer g_pixbuf = {0};
uint8_t g_src_buffer[SRC_BUFFER_SIZE] = {0};
wuffs_base__io_buffer g_src = {0};
wuffs_base__image_config g_image_config = {0};
wuffs_base__image_decoder* g_image_decoder = NULL;
union {
wuffs_gif__decoder gif;
wuffs_wbmp__decoder wbmp;
} g_potential_decoders;
bool read_more_src() {
if (g_src.meta.closed) {
printf("%s: unexpected end of file\n", g_filename);
return false;
}
wuffs_base__io_buffer__compact(&g_src);
g_src.meta.wi += fread(g_src.data.ptr + g_src.meta.wi, sizeof(uint8_t),
g_src.data.len - g_src.meta.wi, g_file);
if (feof(g_file)) {
g_src.meta.closed = true;
} else if (ferror(g_file)) {
printf("%s: read error\n", g_filename);
return false;
}
return true;
}
bool load_image_type() {
while (g_src.meta.wi == 0) {
if (!read_more_src()) {
return false;
}
}
wuffs_base__status status;
switch (g_src_buffer[0]) {
case '\x00':
status = wuffs_wbmp__decoder__initialize(
&g_potential_decoders.wbmp, sizeof g_potential_decoders.wbmp,
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_wbmp__decoder__upcast_as__wuffs_base__image_decoder(
&g_potential_decoders.wbmp);
break;
case 'G':
status = wuffs_gif__decoder__initialize(
&g_potential_decoders.gif, sizeof g_potential_decoders.gif,
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_gif__decoder__upcast_as__wuffs_base__image_decoder(
&g_potential_decoders.gif);
break;
default:
printf("%s: unrecognized file format\n", g_filename);
return false;
}
return true;
}
bool load_image_config() {
// Decode the wuffs_base__image_config.
while (true) {
wuffs_base__status status = wuffs_base__image_decoder__decode_image_config(
g_image_decoder, &g_image_config, &g_src);
if (status.repr == NULL) {
break;
} else if (status.repr != wuffs_base__suspension__short_read) {
printf("%s: %s\n", g_filename, wuffs_base__status__message(&status));
return false;
}
if (!read_more_src()) {
return false;
}
}
// Read the dimensions.
uint32_t w = wuffs_base__pixel_config__width(&g_image_config.pixcfg);
uint32_t h = wuffs_base__pixel_config__height(&g_image_config.pixcfg);
if ((w > MAX_DIMENSION) || (h > MAX_DIMENSION)) {
printf("%s: image is too large\n", g_filename);
return false;
}
g_width = w;
g_height = h;
// Override the image's native pixel format to be BGRA_PREMUL.
wuffs_base__pixel_config__set(&g_image_config.pixcfg,
WUFFS_BASE__PIXEL_FORMAT__BGRA_PREMUL,
WUFFS_BASE__PIXEL_SUBSAMPLING__NONE, w, h);
// Allocate the work buffer memory.
uint64_t workbuf_len =
wuffs_base__image_decoder__workbuf_len(g_image_decoder).max_incl;
if (workbuf_len > SIZE_MAX) {
printf("%s: out of memory\n", g_filename);
return false;
}
if (workbuf_len > 0) {
void* p = malloc(workbuf_len);
if (!p) {
printf("%s: out of memory\n", g_filename);
return false;
}
g_workbuf_slice.ptr = p;
g_workbuf_slice.len = workbuf_len;
}
// Allocate the pixel buffer memory.
uint64_t num_pixels = ((uint64_t)w) * ((uint64_t)h);
if (num_pixels > (SIZE_MAX / sizeof(wuffs_base__color_u32_argb_premul))) {
printf("%s: image is too large\n", g_filename);
return false;
}
size_t n = num_pixels * sizeof(wuffs_base__color_u32_argb_premul);
void* p = calloc(n, 1);
if (!p) {
printf("%s: out of memory\n", g_filename);
return false;
}
g_pixbuf_slice.ptr = p;
g_pixbuf_slice.len = n;
// Configure the wuffs_base__pixel_buffer struct.
wuffs_base__status status = wuffs_base__pixel_buffer__set_from_slice(
&g_pixbuf, &g_image_config.pixcfg, g_pixbuf_slice);
if (!wuffs_base__status__is_ok(&status)) {
printf("%s: %s\n", g_filename, wuffs_base__status__message(&status));
return false;
}
return true;
}
// This function always returns true. If we get this far, we still display a
// partial image, even if we encounter an error.
bool load_image_frame() {
while (true) {
wuffs_base__status status = wuffs_base__image_decoder__decode_frame(
g_image_decoder, &g_pixbuf, &g_src, WUFFS_BASE__PIXEL_BLEND__SRC,
g_workbuf_slice, NULL);
if (status.repr == NULL) {
break;
} else if (status.repr != wuffs_base__suspension__short_read) {
printf("%s: %s\n", g_filename, wuffs_base__status__message(&status));
return true;
}
if (!read_more_src()) {
return true;
}
}
uint32_t w = wuffs_base__pixel_config__width(&g_image_config.pixcfg);
uint32_t h = wuffs_base__pixel_config__height(&g_image_config.pixcfg);
printf("%s: ok (%" PRIu32 " x %" PRIu32 ")\n", g_filename, w, h);
return true;
}
bool load_image(const char* filename) {
if (g_workbuf_slice.ptr != NULL) {
free(g_workbuf_slice.ptr);
g_workbuf_slice.ptr = NULL;
g_workbuf_slice.len = 0;
}
if (g_pixbuf_slice.ptr != NULL) {
free(g_pixbuf_slice.ptr);
g_pixbuf_slice.ptr = NULL;
g_pixbuf_slice.len = 0;
}
g_width = 0;
g_height = 0;
g_src.data.ptr = g_src_buffer;
g_src.data.len = SRC_BUFFER_SIZE;
g_src.meta.wi = 0;
g_src.meta.ri = 0;
g_src.meta.pos = 0;
g_src.meta.closed = false;
g_image_config = wuffs_base__null_image_config();
g_image_decoder = NULL;
g_file = stdin;
g_filename = "<stdin>";
if (filename) {
FILE* f = fopen(filename, "r");
if (f == NULL) {
printf("%s: could not open file\n", filename);
return false;
}
g_file = f;
g_filename = filename;
}
bool ret = load_image_type() && load_image_config() && load_image_frame();
if (filename) {
fclose(g_file);
g_file = NULL;
}
return ret;
}
// ---------------------------------------------------------------------
#if defined(__linux__)
#define SUPPORTED_OPERATING_SYSTEM
#include <xcb/xcb.h>
#include <xcb/xcb_image.h>
#define XK_BackSpace 0xFF08
#define XK_Escape 0xFF1B
#define XK_Return 0xFF0D
xcb_atom_t g_atom_net_wm_name = XCB_NONE;
xcb_atom_t g_atom_utf8_string = XCB_NONE;
xcb_atom_t g_atom_wm_protocols = XCB_NONE;
xcb_atom_t g_atom_wm_delete_window = XCB_NONE;
xcb_pixmap_t g_pixmap = XCB_NONE;
xcb_keysym_t* g_keysyms = NULL;
xcb_get_keyboard_mapping_reply_t* g_keyboard_mapping = NULL;
void init_keymap(xcb_connection_t* c, const xcb_setup_t* z) {
xcb_get_keyboard_mapping_cookie_t cookie = xcb_get_keyboard_mapping(
c, z->min_keycode, z->max_keycode - z->min_keycode + 1);
g_keyboard_mapping = xcb_get_keyboard_mapping_reply(c, cookie, NULL);
g_keysyms = (xcb_keysym_t*)(g_keyboard_mapping + 1);
}
xcb_window_t make_window(xcb_connection_t* c, xcb_screen_t* s) {
xcb_window_t w = xcb_generate_id(c);
uint32_t value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
uint32_t value_list[2];
value_list[0] = s->black_pixel;
value_list[1] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_KEY_PRESS;
xcb_create_window(c, 0, w, s->root, 0, 0, 1024, 768, 0,
XCB_WINDOW_CLASS_INPUT_OUTPUT, s->root_visual, value_mask,
value_list);
xcb_change_property(c, XCB_PROP_MODE_REPLACE, w, g_atom_net_wm_name,
g_atom_utf8_string, 8, 12, "Image Viewer");
xcb_change_property(c, XCB_PROP_MODE_REPLACE, w, g_atom_wm_protocols,
XCB_ATOM_ATOM, 32, 1, &g_atom_wm_delete_window);
xcb_map_window(c, w);
return w;
}
bool load(xcb_connection_t* c,
xcb_screen_t* s,
xcb_window_t w,
xcb_gcontext_t g,
const char* filename) {
if (g_pixmap != XCB_NONE) {
xcb_free_pixmap(c, g_pixmap);
}
if (!load_image(filename)) {
return false;
}
xcb_create_pixmap(c, s->root_depth, g_pixmap, w, g_width, g_height);
xcb_image_t* image = xcb_image_create_native(
c, g_width, g_height, XCB_IMAGE_FORMAT_Z_PIXMAP, s->root_depth, NULL,
g_pixbuf_slice.len, g_pixbuf_slice.ptr);
xcb_image_put(c, g_pixmap, g, image, 0, 0, 0);
xcb_image_destroy(image);
return true;
}
int main(int argc, char** argv) {
xcb_connection_t* c = xcb_connect(NULL, NULL);
const xcb_setup_t* z = xcb_get_setup(c);
xcb_screen_t* s = xcb_setup_roots_iterator(z).data;
{
xcb_intern_atom_cookie_t cookie0 =
xcb_intern_atom(c, 1, 12, "_NET_WM_NAME");
xcb_intern_atom_cookie_t cookie1 = xcb_intern_atom(c, 1, 11, "UTF8_STRING");
xcb_intern_atom_cookie_t cookie2 =
xcb_intern_atom(c, 1, 12, "WM_PROTOCOLS");
xcb_intern_atom_cookie_t cookie3 =
xcb_intern_atom(c, 1, 16, "WM_DELETE_WINDOW");
xcb_intern_atom_reply_t* reply0 = xcb_intern_atom_reply(c, cookie0, NULL);
xcb_intern_atom_reply_t* reply1 = xcb_intern_atom_reply(c, cookie1, NULL);
xcb_intern_atom_reply_t* reply2 = xcb_intern_atom_reply(c, cookie2, NULL);
xcb_intern_atom_reply_t* reply3 = xcb_intern_atom_reply(c, cookie3, NULL);
g_atom_net_wm_name = reply0->atom;
g_atom_utf8_string = reply1->atom;
g_atom_wm_protocols = reply2->atom;
g_atom_wm_delete_window = reply3->atom;
free(reply0);
free(reply1);
free(reply2);
free(reply3);
}
xcb_window_t w = make_window(c, s);
xcb_gcontext_t g = xcb_generate_id(c);
xcb_create_gc(c, g, w, 0, NULL);
init_keymap(c, z);
xcb_flush(c);
g_pixmap = xcb_generate_id(c);
bool loaded = load(c, s, w, g, (argc > 1) ? argv[1] : NULL);
int arg = 1;
while (true) {
xcb_generic_event_t* event = xcb_wait_for_event(c);
switch (event->response_type & 0x7F) {
case XCB_EXPOSE: {
if (loaded) {
xcb_copy_area(c, g_pixmap, w, g, 0, 0, 0, 0, g_width, g_height);
xcb_flush(c);
}
break;
}
case XCB_KEY_PRESS: {
xcb_key_press_event_t* e = (xcb_key_press_event_t*)event;
uint32_t i = e->detail;
if ((z->min_keycode <= i) && (i <= z->max_keycode)) {
i = g_keysyms[(i - z->min_keycode) *
g_keyboard_mapping->keysyms_per_keycode];
switch (i) {
case XK_Escape:
return 0;
case ' ':
case XK_BackSpace:
case XK_Return:
if (argc <= 2) {
break;
}
arg += (i != XK_BackSpace) ? +1 : -1;
if (arg == 0) {
arg = argc - 1;
} else if (arg == argc) {
arg = 1;
}
loaded = load(c, s, w, g, argv[arg]);
xcb_clear_area(c, 1, w, 0, 0, 0xFFFF, 0xFFFF);
xcb_flush(c);
break;
}
}
break;
}
case XCB_CLIENT_MESSAGE: {
xcb_client_message_event_t* e = (xcb_client_message_event_t*)event;
if (e->data.data32[0] == g_atom_wm_delete_window) {
return 0;
}
break;
}
}
free(event);
}
return 0;
}
#endif // defined(__linux__)
// ---------------------------------------------------------------------
#if !defined(SUPPORTED_OPERATING_SYSTEM)
int main(int argc, char** argv) {
printf("unsupported operating system\n");
return 1;
}
#endif // !defined(SUPPORTED_OPERATING_SYSTEM)

View File

@@ -101,16 +101,16 @@ static const char* decode() {
wuffs_base__status status = wuffs_gzip__decoder__initialize(
dec, sizeof__wuffs_gzip__decoder(), WUFFS_VERSION,
WUFFS_INITIALIZE__ALREADY_ZEROED);
if (status) {
if (!wuffs_base__status__is_ok(&status)) {
free(dec);
return wuffs_base__status__message(status);
return wuffs_base__status__message(&status);
}
status = wuffs_gzip__decoder__decode_io_writer(
status = wuffs_gzip__decoder__transform_io(
dec, &dst, &src,
wuffs_base__make_slice_u8(work_buffer, WORK_BUFFER_SIZE));
if (status) {
if (!wuffs_base__status__is_ok(&status)) {
free(dec);
return wuffs_base__status__message(status);
return wuffs_base__status__message(&status);
}
fwrite(dst.data.ptr, sizeof(uint8_t), dst.meta.wi, stdout);
free(dec);
@@ -118,9 +118,9 @@ static const char* decode() {
}
int main(int argc, char** argv) {
const char* status = decode();
if (status) {
fprintf(stderr, "%s\n", status);
const char* status_msg = decode();
if (status_msg) {
fprintf(stderr, "%s\n", status_msg);
return 1;
}
return 0;

View File

@@ -87,8 +87,8 @@ static const char* decode() {
wuffs_gzip__decoder dec;
wuffs_base__status status =
wuffs_gzip__decoder__initialize(&dec, sizeof dec, WUFFS_VERSION, 0);
if (status) {
return wuffs_base__status__message(status);
if (!wuffs_base__status__is_ok(&status)) {
return wuffs_base__status__message(&status);
}
wuffs_base__io_buffer dst;
@@ -123,7 +123,7 @@ static const char* decode() {
}
while (true) {
status = wuffs_gzip__decoder__decode_io_writer(
status = wuffs_gzip__decoder__transform_io(
&dec, &dst, &src,
wuffs_base__make_slice_u8(work_buffer, WORK_BUFFER_SIZE));
@@ -135,13 +135,13 @@ static const char* decode() {
wuffs_base__io_buffer__compact(&dst);
}
if (status == wuffs_base__suspension__short_read) {
if (status.repr == wuffs_base__suspension__short_read) {
break;
}
if (status == wuffs_base__suspension__short_write) {
if (status.repr == wuffs_base__suspension__short_write) {
continue;
}
return wuffs_base__status__message(status);
return wuffs_base__status__message(&status);
}
wuffs_base__io_buffer__compact(&src);
@@ -163,8 +163,8 @@ int main(int argc, char** argv) {
prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT);
#endif
const char* status = decode();
int status_code = status ? fail(status) : 0;
const char* status_msg = decode();
int status_code = status_msg ? fail(status_msg) : 0;
#if defined(WUFFS_EXAMPLE_USE_SECCOMP)
// Call SYS_exit explicitly instead of SYS_exit_group implicitly.

View File

@@ -57,19 +57,19 @@ const char* fuzz(wuffs_base__io_buffer* src, uint32_t hash) {
// variable initialization" warnings.
{
wuffs_gif__decoder dec;
const char* status = wuffs_gif__decoder__initialize(
wuffs_base__status status = wuffs_gif__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION,
(hash & 1) ? WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED
: 0);
if (status) {
ret = status;
if (!wuffs_base__status__is_ok(&status)) {
ret = wuffs_base__status__message(&status);
goto exit;
}
wuffs_base__image_config ic = ((wuffs_base__image_config){});
status = wuffs_gif__decoder__decode_image_config(&dec, &ic, src);
if (status) {
ret = status;
if (!wuffs_base__status__is_ok(&status)) {
ret = wuffs_base__status__message(&status);
goto exit;
}
if (!wuffs_base__image_config__is_valid(&ic)) {
@@ -107,8 +107,8 @@ const char* fuzz(wuffs_base__io_buffer* src, uint32_t hash) {
wuffs_base__pixel_buffer pb = ((wuffs_base__pixel_buffer){});
status = wuffs_base__pixel_buffer__set_from_slice(&pb, &ic.pixcfg, pixbuf);
if (status) {
ret = status;
if (!wuffs_base__status__is_ok(&status)) {
ret = wuffs_base__status__message(&status);
goto exit;
}
@@ -116,14 +116,15 @@ const char* fuzz(wuffs_base__io_buffer* src, uint32_t hash) {
while (true) {
wuffs_base__frame_config fc = ((wuffs_base__frame_config){});
status = wuffs_gif__decoder__decode_frame_config(&dec, &fc, src);
if (status) {
if ((status != wuffs_base__warning__end_of_data) || !seen_ok) {
ret = status;
if (!wuffs_base__status__is_ok(&status)) {
if ((status.repr != wuffs_base__note__end_of_data) || !seen_ok) {
ret = wuffs_base__status__message(&status);
}
goto exit;
}
status = wuffs_gif__decoder__decode_frame(&dec, &pb, src, workbuf, NULL);
status = wuffs_gif__decoder__decode_frame(
&dec, &pb, src, WUFFS_BASE__PIXEL_BLEND__SRC, workbuf, NULL);
wuffs_base__rect_ie_u32 frame_rect =
wuffs_base__frame_config__bounds(&fc);
@@ -134,9 +135,9 @@ const char* fuzz(wuffs_base__io_buffer* src, uint32_t hash) {
goto exit;
}
if (status) {
if ((status != wuffs_base__warning__end_of_data) || !seen_ok) {
ret = status;
if (!wuffs_base__status__is_ok(&status)) {
if ((status.repr != wuffs_base__note__end_of_data) || !seen_ok) {
ret = wuffs_base__status__message(&status);
}
goto exit;
}

View File

@@ -62,11 +62,11 @@ uint8_t work_buffer[1];
const char* fuzz(wuffs_base__io_buffer* src, uint32_t hash) {
wuffs_zlib__decoder dec;
const char* status = wuffs_zlib__decoder__initialize(
wuffs_base__status status = wuffs_zlib__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION,
(hash & 1) ? WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED : 0);
if (status) {
return status;
if (!wuffs_base__status__is_ok(&status)) {
return wuffs_base__status__message(&status);
}
// Ignore the checksum for 99.99%-ish of all input. When fuzzers generate
@@ -84,19 +84,18 @@ const char* fuzz(wuffs_base__io_buffer* src, uint32_t hash) {
while (true) {
dst.meta.wi = 0;
status = wuffs_zlib__decoder__decode_io_writer(&dec, &dst, src,
((wuffs_base__slice_u8){
.ptr = work_buffer,
.len = WORK_BUFFER_SIZE,
}));
if (status != wuffs_base__suspension__short_write) {
status = wuffs_zlib__decoder__transform_io(&dec, &dst, src,
((wuffs_base__slice_u8){
.ptr = work_buffer,
.len = WORK_BUFFER_SIZE,
}));
if (status.repr != wuffs_base__suspension__short_write) {
break;
}
if (dst.meta.wi == 0) {
fprintf(stderr,
"wuffs_zlib__decoder__decode_io_writer made no progress\n");
fprintf(stderr, "wuffs_zlib__decoder__transform_io made no progress\n");
intentional_segfault();
}
}
return status;
return wuffs_base__status__message(&status);
}

View File

@@ -47,8 +47,8 @@ uint32_t parse(char* p, size_t n) {
status = wuffs_demo__parser__initialize(parser, sizeof__wuffs_demo__parser(),
WUFFS_VERSION, 0);
if (!wuffs_base__status__is_ok(status)) {
printf("initialize: %s\n", wuffs_base__status__message(status));
if (!wuffs_base__status__is_ok(&status)) {
printf("initialize: %s\n", wuffs_base__status__message(&status));
free(parser);
return 0;
}
@@ -62,8 +62,8 @@ uint32_t parse(char* p, size_t n) {
iobuf.meta.closed = true;
status = wuffs_demo__parser__parse(parser, &iobuf);
if (!wuffs_base__status__is_ok(status)) {
printf("parse: %s\n", wuffs_base__status__message(status));
if (!wuffs_base__status__is_ok(&status)) {
printf("parse: %s\n", wuffs_base__status__message(&status));
free(parser);
return 0;
}

View File

@@ -42,6 +42,10 @@ extern "C" {
// !! INSERT base/all-public.h.
// !! INSERT InterfaceDeclarations.
// ----------------
#ifdef __cplusplus
} // extern "C"
#endif
@@ -112,6 +116,8 @@ const uint64_t wuffs_base__low_bits_mask__u64[65] = {
// !! INSERT wuffs_base__status strings.
// !! INSERT InterfaceDefinitions.
// !! INSERT base/image-impl.c.
#endif // !defined(WUFFS_CONFIG__MODULES) ||

View File

@@ -55,9 +55,9 @@ wuffs_base__ignore_status(wuffs_base__status z) {
case n:;
#define WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(n) \
if (!status) { \
if (!status.repr) { \
goto ok; \
} else if (*status != '$') { \
} else if (*status.repr != '$') { \
goto exit; \
} \
coro_susp_point = n; \
@@ -417,6 +417,6 @@ wuffs_base__table_u8__row(wuffs_base__table_u8 t, uint32_t y) {
return wuffs_base__make_slice_u8(NULL, 0);
}
// ---------------- Slices and Tables (Utility)
// ---------------- Slices and Tables (Utility)
#define wuffs_base__utility__empty_slice_u8 wuffs_base__empty_slice_u8

View File

@@ -14,14 +14,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// Wuffs assumes that:
// - converting a uint32_t to a size_t will never overflow.
// - converting a size_t to a uint64_t will never overflow.
#ifdef __WORDSIZE
#if (__WORDSIZE != 32) && (__WORDSIZE != 64)
#error "Wuffs requires a word size of either 32 or 64 bits"
#endif
#endif
// ---------------- Fundamentals
// WUFFS_VERSION is the major.minor.patch version, as per https://semver.org/,
// as a uint64_t. The major number is the high 32 bits. The minor number is the
@@ -57,6 +50,17 @@
#define WUFFS_BASE__MAYBE_STATIC
#endif
// --------
// Wuffs assumes that:
// - converting a uint32_t to a size_t will never overflow.
// - converting a size_t to a uint64_t will never overflow.
#ifdef __WORDSIZE
#if (__WORDSIZE != 32) && (__WORDSIZE != 64)
#error "Wuffs requires a word size of either 32 or 64 bits"
#endif
#endif
#if defined(__clang__)
#define WUFFS_BASE__POTENTIALLY_UNUSED_FIELD __attribute__((unused))
#else
@@ -132,49 +136,107 @@ typedef struct {
uint8_t private_impl;
} wuffs_base__utility;
typedef struct {
const char* vtable_name;
const void* function_pointers;
} wuffs_base__vtable;
// --------
// See https://github.com/google/wuffs/blob/master/doc/note/statuses.md
typedef const char* wuffs_base__status;
typedef struct {
const char* repr;
#ifdef __cplusplus
inline bool is_complete() const;
inline bool is_error() const;
inline bool is_note() const;
inline bool is_ok() const;
inline bool is_suspension() const;
inline const char* message() const;
#endif // __cplusplus
} wuffs_base__status;
// !! INSERT wuffs_base__status names.
static inline bool //
wuffs_base__status__is_complete(wuffs_base__status z) {
return (z == NULL) || ((*z != '$') && (*z != '#'));
static inline wuffs_base__status //
wuffs_base__make_status(const char* repr) {
wuffs_base__status z;
z.repr = repr;
return z;
}
static inline bool //
wuffs_base__status__is_error(wuffs_base__status z) {
return z && (*z == '#');
wuffs_base__status__is_complete(const wuffs_base__status* z) {
return (z->repr == NULL) || ((*z->repr != '$') && (*z->repr != '#'));
}
static inline bool //
wuffs_base__status__is_ok(wuffs_base__status z) {
return z == NULL;
wuffs_base__status__is_error(const wuffs_base__status* z) {
return z->repr && (*z->repr == '#');
}
static inline bool //
wuffs_base__status__is_suspension(wuffs_base__status z) {
return z && (*z == '$');
wuffs_base__status__is_note(const wuffs_base__status* z) {
return z->repr && (*z->repr != '$') && (*z->repr != '#');
}
static inline bool //
wuffs_base__status__is_warning(wuffs_base__status z) {
return z && (*z != '$') && (*z != '#');
wuffs_base__status__is_ok(const wuffs_base__status* z) {
return z->repr == NULL;
}
static inline bool //
wuffs_base__status__is_suspension(const wuffs_base__status* z) {
return z->repr && (*z->repr == '$');
}
// wuffs_base__status__message strips the leading '$', '#' or '@'.
static inline const char* //
wuffs_base__status__message(wuffs_base__status z) {
if (z) {
if ((*z == '$') || (*z == '#') || (*z == '@')) {
return z + 1;
wuffs_base__status__message(const wuffs_base__status* z) {
if (z->repr) {
if ((*z->repr == '$') || (*z->repr == '#') || (*z->repr == '@')) {
return z->repr + 1;
}
}
return z;
return z->repr;
}
#ifdef __cplusplus
inline bool //
wuffs_base__status::is_complete() const {
return wuffs_base__status__is_complete(this);
}
inline bool //
wuffs_base__status::is_error() const {
return wuffs_base__status__is_error(this);
}
inline bool //
wuffs_base__status::is_note() const {
return wuffs_base__status__is_note(this);
}
inline bool //
wuffs_base__status::is_ok() const {
return wuffs_base__status__is_ok(this);
}
inline bool //
wuffs_base__status::is_suspension() const {
return wuffs_base__status__is_suspension(this);
}
inline const char* //
wuffs_base__status::message() const {
return wuffs_base__status__message(this);
}
#endif // __cplusplus
// --------
// FourCC constants.

View File

@@ -29,9 +29,9 @@ wuffs_base__pixel_swizzler__copy_1_1(wuffs_base__slice_u8 dst,
}
static uint64_t //
wuffs_base__pixel_swizzler__copy_3_1(wuffs_base__slice_u8 dst,
wuffs_base__slice_u8 dst_palette,
wuffs_base__slice_u8 src) {
wuffs_base__pixel_swizzler__xxx_index(wuffs_base__slice_u8 dst,
wuffs_base__slice_u8 dst_palette,
wuffs_base__slice_u8 src) {
if (dst_palette.len != 1024) {
return 0;
}
@@ -83,10 +83,11 @@ wuffs_base__pixel_swizzler__copy_3_1(wuffs_base__slice_u8 dst,
return len;
}
static uint64_t //
wuffs_base__pixel_swizzler__copy_4_1(wuffs_base__slice_u8 dst,
wuffs_base__slice_u8 dst_palette,
wuffs_base__slice_u8 src) {
wuffs_base__pixel_swizzler__xxxx_index(wuffs_base__slice_u8 dst,
wuffs_base__slice_u8 dst_palette,
wuffs_base__slice_u8 src) {
if (dst_palette.len != 1024) {
return 0;
}
@@ -131,6 +132,30 @@ wuffs_base__pixel_swizzler__copy_4_1(wuffs_base__slice_u8 dst,
return len;
}
static uint64_t //
wuffs_base__pixel_swizzler__xxxx_y(wuffs_base__slice_u8 dst,
wuffs_base__slice_u8 dst_palette,
wuffs_base__slice_u8 src) {
size_t dst_len4 = dst.len / 4;
size_t len = dst_len4 < src.len ? dst_len4 : src.len;
uint8_t* d = dst.ptr;
uint8_t* s = src.ptr;
size_t n = len;
// TODO: unroll.
while (n >= 1) {
wuffs_base__store_u32le(d + (0 * 4),
0xFF000000 | (0x010101 * (uint32_t)s[0]));
s += 1 * 1;
d += 4 * 1;
n -= (size_t)(1 * 1);
}
return len;
}
static uint64_t //
wuffs_base__pixel_swizzler__swap_rgbx_bgrx(wuffs_base__slice_u8 dst,
wuffs_base__slice_u8 src) {
@@ -159,9 +184,10 @@ wuffs_base__pixel_swizzler__prepare(wuffs_base__pixel_swizzler* p,
wuffs_base__pixel_format dst_format,
wuffs_base__slice_u8 dst_palette,
wuffs_base__pixel_format src_format,
wuffs_base__slice_u8 src_palette) {
wuffs_base__slice_u8 src_palette,
wuffs_base__pixel_blend blend) {
if (!p) {
return wuffs_base__error__bad_receiver;
return wuffs_base__make_status(wuffs_base__error__bad_receiver);
}
// TODO: support many more formats.
@@ -169,9 +195,30 @@ wuffs_base__pixel_swizzler__prepare(wuffs_base__pixel_swizzler* p,
uint64_t (*func)(wuffs_base__slice_u8 dst, wuffs_base__slice_u8 dst_palette,
wuffs_base__slice_u8 src) = NULL;
switch (src_format) {
switch (src_format.repr) {
case WUFFS_BASE__PIXEL_FORMAT__Y:
switch (dst_format.repr) {
case WUFFS_BASE__PIXEL_FORMAT__BGR:
case WUFFS_BASE__PIXEL_FORMAT__RGB:
// TODO.
break;
case WUFFS_BASE__PIXEL_FORMAT__BGRX:
case WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL:
case WUFFS_BASE__PIXEL_FORMAT__BGRA_PREMUL:
case WUFFS_BASE__PIXEL_FORMAT__BGRA_BINARY:
case WUFFS_BASE__PIXEL_FORMAT__RGBX:
case WUFFS_BASE__PIXEL_FORMAT__RGBA_NONPREMUL:
case WUFFS_BASE__PIXEL_FORMAT__RGBA_PREMUL:
case WUFFS_BASE__PIXEL_FORMAT__RGBA_BINARY:
func = wuffs_base__pixel_swizzler__xxxx_y;
break;
default:
break;
}
break;
case WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_BINARY:
switch (dst_format) {
switch (dst_format.repr) {
case WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_NONPREMUL:
case WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_PREMUL:
case WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_BINARY:
@@ -186,7 +233,7 @@ wuffs_base__pixel_swizzler__prepare(wuffs_base__pixel_swizzler* p,
1024) {
break;
}
func = wuffs_base__pixel_swizzler__copy_3_1;
func = wuffs_base__pixel_swizzler__xxx_index;
break;
case WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL:
case WUFFS_BASE__PIXEL_FORMAT__BGRA_PREMUL:
@@ -195,14 +242,14 @@ wuffs_base__pixel_swizzler__prepare(wuffs_base__pixel_swizzler* p,
1024) {
break;
}
func = wuffs_base__pixel_swizzler__copy_4_1;
func = wuffs_base__pixel_swizzler__xxxx_index;
break;
case WUFFS_BASE__PIXEL_FORMAT__RGB:
if (wuffs_base__pixel_swizzler__swap_rgbx_bgrx(dst_palette,
src_palette) != 1024) {
break;
}
func = wuffs_base__pixel_swizzler__copy_3_1;
func = wuffs_base__pixel_swizzler__xxx_index;
break;
case WUFFS_BASE__PIXEL_FORMAT__RGBA_NONPREMUL:
case WUFFS_BASE__PIXEL_FORMAT__RGBA_PREMUL:
@@ -211,7 +258,7 @@ wuffs_base__pixel_swizzler__prepare(wuffs_base__pixel_swizzler* p,
src_palette) != 1024) {
break;
}
func = wuffs_base__pixel_swizzler__copy_4_1;
func = wuffs_base__pixel_swizzler__xxxx_index;
break;
default:
break;
@@ -223,7 +270,8 @@ wuffs_base__pixel_swizzler__prepare(wuffs_base__pixel_swizzler* p,
}
p->private_impl.func = func;
return func ? NULL : wuffs_base__error__unsupported_option;
return wuffs_base__make_status(func ? NULL
: wuffs_base__error__unsupported_option);
}
uint64_t //

View File

@@ -15,3 +15,7 @@
// limitations under the License.
// ---------------- Images
// ---------------- Images (Utility)
#define wuffs_base__utility__make_pixel_format wuffs_base__make_pixel_format

View File

@@ -23,6 +23,17 @@ typedef uint32_t wuffs_base__color_u32_argb_premul;
// --------
typedef uint8_t wuffs_base__pixel_blend;
// wuffs_base__pixel_blend encodes how to blend source and destination pixels,
// accounting for transparency. It encompasses the Porter-Duff compositing
// operators as well as the other blending modes defined by PDF.
//
// TODO: implement the other modes.
#define WUFFS_BASE__PIXEL_BLEND__SRC ((wuffs_base__pixel_blend)0)
// --------
// wuffs_base__pixel_format encodes the format of the bytes that constitute an
// image frame's pixel data.
//
@@ -30,97 +41,103 @@ typedef uint32_t wuffs_base__color_u32_argb_premul;
//
// Do not manipulate its bits directly; they are private implementation
// details. Use methods such as wuffs_base__pixel_format__num_planes instead.
typedef uint32_t wuffs_base__pixel_format;
typedef struct {
uint32_t repr;
// Common 8-bit-depth pixel formats. This list is not exhaustive; not all valid
// wuffs_base__pixel_format values are present.
#ifdef __cplusplus
inline bool is_valid() const;
inline uint32_t bits_per_pixel() const;
inline bool is_indexed() const;
inline bool is_interleaved() const;
inline bool is_planar() const;
inline uint32_t num_planes() const;
#endif // __cplusplus
#define WUFFS_BASE__PIXEL_FORMAT__INVALID ((wuffs_base__pixel_format)0x00000000)
} wuffs_base__pixel_format;
#define WUFFS_BASE__PIXEL_FORMAT__A ((wuffs_base__pixel_format)0x02000008)
static inline wuffs_base__pixel_format //
wuffs_base__make_pixel_format(uint32_t repr) {
wuffs_base__pixel_format f;
f.repr = repr;
return f;
}
#define WUFFS_BASE__PIXEL_FORMAT__Y ((wuffs_base__pixel_format)0x10000008)
#define WUFFS_BASE__PIXEL_FORMAT__YA_NONPREMUL \
((wuffs_base__pixel_format)0x15000008)
#define WUFFS_BASE__PIXEL_FORMAT__YA_PREMUL \
((wuffs_base__pixel_format)0x16000008)
// Common 8-bit-depth pixel formats. This list is not exhaustive; not all
// valid wuffs_base__pixel_format values are present.
#define WUFFS_BASE__PIXEL_FORMAT__YCBCR ((wuffs_base__pixel_format)0x20020888)
#define WUFFS_BASE__PIXEL_FORMAT__YCBCRK ((wuffs_base__pixel_format)0x21038888)
#define WUFFS_BASE__PIXEL_FORMAT__YCBCRA_NONPREMUL \
((wuffs_base__pixel_format)0x25038888)
#define WUFFS_BASE__PIXEL_FORMAT__INVALID 0x00000000
#define WUFFS_BASE__PIXEL_FORMAT__YCOCG ((wuffs_base__pixel_format)0x30020888)
#define WUFFS_BASE__PIXEL_FORMAT__YCOCGK ((wuffs_base__pixel_format)0x31038888)
#define WUFFS_BASE__PIXEL_FORMAT__YCOCGA_NONPREMUL \
((wuffs_base__pixel_format)0x35038888)
#define WUFFS_BASE__PIXEL_FORMAT__A 0x02000008
#define WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_NONPREMUL \
((wuffs_base__pixel_format)0x45040008)
#define WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_PREMUL \
((wuffs_base__pixel_format)0x46040008)
#define WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_BINARY \
((wuffs_base__pixel_format)0x47040008)
#define WUFFS_BASE__PIXEL_FORMAT__Y 0x10000008
#define WUFFS_BASE__PIXEL_FORMAT__YA_NONPREMUL 0x15000008
#define WUFFS_BASE__PIXEL_FORMAT__YA_PREMUL 0x16000008
#define WUFFS_BASE__PIXEL_FORMAT__BGR ((wuffs_base__pixel_format)0x40000888)
#define WUFFS_BASE__PIXEL_FORMAT__BGRX ((wuffs_base__pixel_format)0x41008888)
#define WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL \
((wuffs_base__pixel_format)0x45008888)
#define WUFFS_BASE__PIXEL_FORMAT__BGRA_PREMUL \
((wuffs_base__pixel_format)0x46008888)
#define WUFFS_BASE__PIXEL_FORMAT__BGRA_BINARY \
((wuffs_base__pixel_format)0x47008888)
#define WUFFS_BASE__PIXEL_FORMAT__YCBCR 0x20020888
#define WUFFS_BASE__PIXEL_FORMAT__YCBCRK 0x21038888
#define WUFFS_BASE__PIXEL_FORMAT__YCBCRA_NONPREMUL 0x25038888
#define WUFFS_BASE__PIXEL_FORMAT__RGB ((wuffs_base__pixel_format)0x50000888)
#define WUFFS_BASE__PIXEL_FORMAT__RGBX ((wuffs_base__pixel_format)0x51008888)
#define WUFFS_BASE__PIXEL_FORMAT__RGBA_NONPREMUL \
((wuffs_base__pixel_format)0x55008888)
#define WUFFS_BASE__PIXEL_FORMAT__RGBA_PREMUL \
((wuffs_base__pixel_format)0x56008888)
#define WUFFS_BASE__PIXEL_FORMAT__RGBA_BINARY \
((wuffs_base__pixel_format)0x57008888)
#define WUFFS_BASE__PIXEL_FORMAT__YCOCG 0x30020888
#define WUFFS_BASE__PIXEL_FORMAT__YCOCGK 0x31038888
#define WUFFS_BASE__PIXEL_FORMAT__YCOCGA_NONPREMUL 0x35038888
#define WUFFS_BASE__PIXEL_FORMAT__CMY ((wuffs_base__pixel_format)0x60020888)
#define WUFFS_BASE__PIXEL_FORMAT__CMYK ((wuffs_base__pixel_format)0x61038888)
#define WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_NONPREMUL 0x45040008
#define WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_PREMUL 0x46040008
#define WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_BINARY 0x47040008
#define WUFFS_BASE__PIXEL_FORMAT__BGR 0x40000888
#define WUFFS_BASE__PIXEL_FORMAT__BGRX 0x41008888
#define WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL 0x45008888
#define WUFFS_BASE__PIXEL_FORMAT__BGRA_PREMUL 0x46008888
#define WUFFS_BASE__PIXEL_FORMAT__BGRA_BINARY 0x47008888
#define WUFFS_BASE__PIXEL_FORMAT__RGB 0x50000888
#define WUFFS_BASE__PIXEL_FORMAT__RGBX 0x51008888
#define WUFFS_BASE__PIXEL_FORMAT__RGBA_NONPREMUL 0x55008888
#define WUFFS_BASE__PIXEL_FORMAT__RGBA_PREMUL 0x56008888
#define WUFFS_BASE__PIXEL_FORMAT__RGBA_BINARY 0x57008888
#define WUFFS_BASE__PIXEL_FORMAT__CMY 0x60020888
#define WUFFS_BASE__PIXEL_FORMAT__CMYK 0x61038888
extern const uint32_t wuffs_base__pixel_format__bits_per_channel[16];
static inline bool //
wuffs_base__pixel_format__is_valid(wuffs_base__pixel_format f) {
return f != 0;
wuffs_base__pixel_format__is_valid(const wuffs_base__pixel_format* f) {
return f->repr != 0;
}
// wuffs_base__pixel_format__bits_per_pixel returns the number of bits per
// pixel for interleaved pixel formats, and returns 0 for planar pixel formats.
static inline uint32_t //
wuffs_base__pixel_format__bits_per_pixel(wuffs_base__pixel_format f) {
if (((f >> 16) & 0x03) != 0) {
wuffs_base__pixel_format__bits_per_pixel(const wuffs_base__pixel_format* f) {
if (((f->repr >> 16) & 0x03) != 0) {
return 0;
}
return wuffs_base__pixel_format__bits_per_channel[0x0F & (f >> 0)] +
wuffs_base__pixel_format__bits_per_channel[0x0F & (f >> 4)] +
wuffs_base__pixel_format__bits_per_channel[0x0F & (f >> 8)] +
wuffs_base__pixel_format__bits_per_channel[0x0F & (f >> 12)];
return wuffs_base__pixel_format__bits_per_channel[0x0F & (f->repr >> 0)] +
wuffs_base__pixel_format__bits_per_channel[0x0F & (f->repr >> 4)] +
wuffs_base__pixel_format__bits_per_channel[0x0F & (f->repr >> 8)] +
wuffs_base__pixel_format__bits_per_channel[0x0F & (f->repr >> 12)];
}
static inline bool //
wuffs_base__pixel_format__is_indexed(wuffs_base__pixel_format f) {
return (f >> 18) & 0x01;
wuffs_base__pixel_format__is_indexed(const wuffs_base__pixel_format* f) {
return (f->repr >> 18) & 0x01;
}
static inline bool //
wuffs_base__pixel_format__is_interleaved(wuffs_base__pixel_format f) {
return ((f >> 16) & 0x03) == 0;
wuffs_base__pixel_format__is_interleaved(const wuffs_base__pixel_format* f) {
return ((f->repr >> 16) & 0x03) == 0;
}
static inline bool //
wuffs_base__pixel_format__is_planar(wuffs_base__pixel_format f) {
return ((f >> 16) & 0x03) != 0;
wuffs_base__pixel_format__is_planar(const wuffs_base__pixel_format* f) {
return ((f->repr >> 16) & 0x03) != 0;
}
static inline uint32_t //
wuffs_base__pixel_format__num_planes(wuffs_base__pixel_format f) {
return ((f >> 16) & 0x03) + 1;
wuffs_base__pixel_format__num_planes(const wuffs_base__pixel_format* f) {
return ((f->repr >> 16) & 0x03) + 1;
}
#define WUFFS_BASE__PIXEL_FORMAT__NUM_PLANES_MAX 4
@@ -128,6 +145,40 @@ wuffs_base__pixel_format__num_planes(wuffs_base__pixel_format f) {
#define WUFFS_BASE__PIXEL_FORMAT__INDEXED__INDEX_PLANE 0
#define WUFFS_BASE__PIXEL_FORMAT__INDEXED__COLOR_PLANE 3
#ifdef __cplusplus
inline bool //
wuffs_base__pixel_format::is_valid() const {
return wuffs_base__pixel_format__is_valid(this);
}
inline uint32_t //
wuffs_base__pixel_format::bits_per_pixel() const {
return wuffs_base__pixel_format__bits_per_pixel(this);
}
inline bool //
wuffs_base__pixel_format::is_indexed() const {
return wuffs_base__pixel_format__is_indexed(this);
}
inline bool //
wuffs_base__pixel_format::is_interleaved() const {
return wuffs_base__pixel_format__is_interleaved(this);
}
inline bool //
wuffs_base__pixel_format::is_planar() const {
return wuffs_base__pixel_format__is_planar(this);
}
inline uint32_t //
wuffs_base__pixel_format::num_planes() const {
return wuffs_base__pixel_format__num_planes(this);
}
#endif // __cplusplus
// --------
// wuffs_base__pixel_subsampling encodes whether sample values cover one pixel
@@ -137,51 +188,88 @@ wuffs_base__pixel_format__num_planes(wuffs_base__pixel_format f) {
//
// Do not manipulate its bits directly; they are private implementation
// details. Use methods such as wuffs_base__pixel_subsampling__bias_x instead.
typedef uint32_t wuffs_base__pixel_subsampling;
typedef struct {
uint32_t repr;
#define WUFFS_BASE__PIXEL_SUBSAMPLING__NONE ((wuffs_base__pixel_subsampling)0)
#ifdef __cplusplus
inline uint32_t bias_x(uint32_t plane) const;
inline uint32_t denominator_x(uint32_t plane) const;
inline uint32_t bias_y(uint32_t plane) const;
inline uint32_t denominator_y(uint32_t plane) const;
#endif // __cplusplus
#define WUFFS_BASE__PIXEL_SUBSAMPLING__444 \
((wuffs_base__pixel_subsampling)0x000000)
#define WUFFS_BASE__PIXEL_SUBSAMPLING__440 \
((wuffs_base__pixel_subsampling)0x010100)
#define WUFFS_BASE__PIXEL_SUBSAMPLING__422 \
((wuffs_base__pixel_subsampling)0x101000)
#define WUFFS_BASE__PIXEL_SUBSAMPLING__420 \
((wuffs_base__pixel_subsampling)0x111100)
#define WUFFS_BASE__PIXEL_SUBSAMPLING__411 \
((wuffs_base__pixel_subsampling)0x303000)
#define WUFFS_BASE__PIXEL_SUBSAMPLING__410 \
((wuffs_base__pixel_subsampling)0x313100)
} wuffs_base__pixel_subsampling;
static inline wuffs_base__pixel_subsampling //
wuffs_base__make_pixel_subsampling(uint32_t repr) {
wuffs_base__pixel_subsampling s;
s.repr = repr;
return s;
}
#define WUFFS_BASE__PIXEL_SUBSAMPLING__NONE 0x00000000
#define WUFFS_BASE__PIXEL_SUBSAMPLING__444 0x000000
#define WUFFS_BASE__PIXEL_SUBSAMPLING__440 0x010100
#define WUFFS_BASE__PIXEL_SUBSAMPLING__422 0x101000
#define WUFFS_BASE__PIXEL_SUBSAMPLING__420 0x111100
#define WUFFS_BASE__PIXEL_SUBSAMPLING__411 0x303000
#define WUFFS_BASE__PIXEL_SUBSAMPLING__410 0x313100
static inline uint32_t //
wuffs_base__pixel_subsampling__bias_x(wuffs_base__pixel_subsampling s,
wuffs_base__pixel_subsampling__bias_x(const wuffs_base__pixel_subsampling* s,
uint32_t plane) {
uint32_t shift = ((plane & 0x03) * 8) + 6;
return (s >> shift) & 0x03;
return (s->repr >> shift) & 0x03;
}
static inline uint32_t //
wuffs_base__pixel_subsampling__denominator_x(wuffs_base__pixel_subsampling s,
uint32_t plane) {
wuffs_base__pixel_subsampling__denominator_x(
const wuffs_base__pixel_subsampling* s,
uint32_t plane) {
uint32_t shift = ((plane & 0x03) * 8) + 4;
return ((s >> shift) & 0x03) + 1;
return ((s->repr >> shift) & 0x03) + 1;
}
static inline uint32_t //
wuffs_base__pixel_subsampling__bias_y(wuffs_base__pixel_subsampling s,
wuffs_base__pixel_subsampling__bias_y(const wuffs_base__pixel_subsampling* s,
uint32_t plane) {
uint32_t shift = ((plane & 0x03) * 8) + 2;
return (s >> shift) & 0x03;
return (s->repr >> shift) & 0x03;
}
static inline uint32_t //
wuffs_base__pixel_subsampling__denominator_y(wuffs_base__pixel_subsampling s,
uint32_t plane) {
wuffs_base__pixel_subsampling__denominator_y(
const wuffs_base__pixel_subsampling* s,
uint32_t plane) {
uint32_t shift = ((plane & 0x03) * 8) + 0;
return ((s >> shift) & 0x03) + 1;
return ((s->repr >> shift) & 0x03) + 1;
}
#ifdef __cplusplus
inline uint32_t //
wuffs_base__pixel_subsampling::bias_x(uint32_t plane) const {
return wuffs_base__pixel_subsampling__bias_x(this, plane);
}
inline uint32_t //
wuffs_base__pixel_subsampling::denominator_x(uint32_t plane) const {
return wuffs_base__pixel_subsampling__denominator_x(this, plane);
}
inline uint32_t //
wuffs_base__pixel_subsampling::bias_y(uint32_t plane) const {
return wuffs_base__pixel_subsampling__bias_y(this, plane);
}
inline uint32_t //
wuffs_base__pixel_subsampling::denominator_y(uint32_t plane) const {
return wuffs_base__pixel_subsampling__denominator_y(this, plane);
}
#endif // __cplusplus
// --------
typedef struct {
@@ -195,8 +283,8 @@ typedef struct {
} private_impl;
#ifdef __cplusplus
inline void set(wuffs_base__pixel_format pixfmt,
wuffs_base__pixel_subsampling pixsub,
inline void set(uint32_t pixfmt_repr,
uint32_t pixsub_repr,
uint32_t width,
uint32_t height);
inline void invalidate();
@@ -214,8 +302,8 @@ typedef struct {
static inline wuffs_base__pixel_config //
wuffs_base__null_pixel_config() {
wuffs_base__pixel_config ret;
ret.private_impl.pixfmt = 0;
ret.private_impl.pixsub = 0;
ret.private_impl.pixfmt.repr = 0;
ret.private_impl.pixsub.repr = 0;
ret.private_impl.width = 0;
ret.private_impl.height = 0;
return ret;
@@ -224,27 +312,27 @@ wuffs_base__null_pixel_config() {
// TODO: Should this function return bool? An error type?
static inline void //
wuffs_base__pixel_config__set(wuffs_base__pixel_config* c,
wuffs_base__pixel_format pixfmt,
wuffs_base__pixel_subsampling pixsub,
uint32_t pixfmt_repr,
uint32_t pixsub_repr,
uint32_t width,
uint32_t height) {
if (!c) {
return;
}
if (pixfmt) {
if (pixfmt_repr) {
uint64_t wh = ((uint64_t)width) * ((uint64_t)height);
// TODO: handle things other than 1 byte per pixel.
if (wh <= ((uint64_t)SIZE_MAX)) {
c->private_impl.pixfmt = pixfmt;
c->private_impl.pixsub = pixsub;
c->private_impl.pixfmt.repr = pixfmt_repr;
c->private_impl.pixsub.repr = pixsub_repr;
c->private_impl.width = width;
c->private_impl.height = height;
return;
}
}
c->private_impl.pixfmt = 0;
c->private_impl.pixsub = 0;
c->private_impl.pixfmt.repr = 0;
c->private_impl.pixsub.repr = 0;
c->private_impl.width = 0;
c->private_impl.height = 0;
}
@@ -252,8 +340,8 @@ wuffs_base__pixel_config__set(wuffs_base__pixel_config* c,
static inline void //
wuffs_base__pixel_config__invalidate(wuffs_base__pixel_config* c) {
if (c) {
c->private_impl.pixfmt = 0;
c->private_impl.pixsub = 0;
c->private_impl.pixfmt.repr = 0;
c->private_impl.pixsub.repr = 0;
c->private_impl.width = 0;
c->private_impl.height = 0;
}
@@ -261,17 +349,17 @@ wuffs_base__pixel_config__invalidate(wuffs_base__pixel_config* c) {
static inline bool //
wuffs_base__pixel_config__is_valid(const wuffs_base__pixel_config* c) {
return c && c->private_impl.pixfmt;
return c && c->private_impl.pixfmt.repr;
}
static inline wuffs_base__pixel_format //
wuffs_base__pixel_config__pixel_format(const wuffs_base__pixel_config* c) {
return c ? c->private_impl.pixfmt : 0;
return c ? c->private_impl.pixfmt : wuffs_base__make_pixel_format(0);
}
static inline wuffs_base__pixel_subsampling //
wuffs_base__pixel_config__pixel_subsampling(const wuffs_base__pixel_config* c) {
return c ? c->private_impl.pixsub : 0;
return c ? c->private_impl.pixsub : wuffs_base__make_pixel_subsampling(0);
}
static inline wuffs_base__rect_ie_u32 //
@@ -311,12 +399,12 @@ wuffs_base__pixel_config__pixbuf_len(const wuffs_base__pixel_config* c) {
if (!c) {
return 0;
}
if (wuffs_base__pixel_format__is_planar(c->private_impl.pixfmt)) {
if (wuffs_base__pixel_format__is_planar(&c->private_impl.pixfmt)) {
// TODO: support planar pixel formats, concious of pixel subsampling.
return 0;
}
uint32_t bits_per_pixel =
wuffs_base__pixel_format__bits_per_pixel(c->private_impl.pixfmt);
wuffs_base__pixel_format__bits_per_pixel(&c->private_impl.pixfmt);
if ((bits_per_pixel == 0) || ((bits_per_pixel % 8) != 0)) {
// TODO: support fraction-of-byte pixels, e.g. 1 bit per pixel?
return 0;
@@ -330,7 +418,7 @@ wuffs_base__pixel_config__pixbuf_len(const wuffs_base__pixel_config* c) {
}
n *= bytes_per_pixel;
if (wuffs_base__pixel_format__is_indexed(c->private_impl.pixfmt)) {
if (wuffs_base__pixel_format__is_indexed(&c->private_impl.pixfmt)) {
if (n > (UINT64_MAX - 1024)) {
return 0;
}
@@ -343,11 +431,11 @@ wuffs_base__pixel_config__pixbuf_len(const wuffs_base__pixel_config* c) {
#ifdef __cplusplus
inline void //
wuffs_base__pixel_config::set(wuffs_base__pixel_format pixfmt,
wuffs_base__pixel_subsampling pixsub,
wuffs_base__pixel_config::set(uint32_t pixfmt_repr,
uint32_t pixsub_repr,
uint32_t width,
uint32_t height) {
wuffs_base__pixel_config__set(this, pixfmt, pixsub, width, height);
wuffs_base__pixel_config__set(this, pixfmt_repr, pixsub_repr, width, height);
}
inline void //
@@ -405,8 +493,8 @@ typedef struct {
} private_impl;
#ifdef __cplusplus
inline void set(wuffs_base__pixel_format pixfmt,
wuffs_base__pixel_subsampling pixsub,
inline void set(uint32_t pixfmt_repr,
uint32_t pixsub_repr,
uint32_t width,
uint32_t height,
uint64_t first_frame_io_position,
@@ -431,8 +519,8 @@ wuffs_base__null_image_config() {
// TODO: Should this function return bool? An error type?
static inline void //
wuffs_base__image_config__set(wuffs_base__image_config* c,
wuffs_base__pixel_format pixfmt,
wuffs_base__pixel_subsampling pixsub,
uint32_t pixfmt_repr,
uint32_t pixsub_repr,
uint32_t width,
uint32_t height,
uint64_t first_frame_io_position,
@@ -440,9 +528,9 @@ wuffs_base__image_config__set(wuffs_base__image_config* c,
if (!c) {
return;
}
if (wuffs_base__pixel_format__is_valid(pixfmt)) {
c->pixcfg.private_impl.pixfmt = pixfmt;
c->pixcfg.private_impl.pixsub = pixsub;
if (pixfmt_repr) {
c->pixcfg.private_impl.pixfmt.repr = pixfmt_repr;
c->pixcfg.private_impl.pixsub.repr = pixsub_repr;
c->pixcfg.private_impl.width = width;
c->pixcfg.private_impl.height = height;
c->private_impl.first_frame_io_position = first_frame_io_position;
@@ -450,8 +538,8 @@ wuffs_base__image_config__set(wuffs_base__image_config* c,
return;
}
c->pixcfg.private_impl.pixfmt = 0;
c->pixcfg.private_impl.pixsub = 0;
c->pixcfg.private_impl.pixfmt.repr = 0;
c->pixcfg.private_impl.pixsub.repr = 0;
c->pixcfg.private_impl.width = 0;
c->pixcfg.private_impl.height = 0;
c->private_impl.first_frame_io_position = 0;
@@ -461,8 +549,8 @@ wuffs_base__image_config__set(wuffs_base__image_config* c,
static inline void //
wuffs_base__image_config__invalidate(wuffs_base__image_config* c) {
if (c) {
c->pixcfg.private_impl.pixfmt = 0;
c->pixcfg.private_impl.pixsub = 0;
c->pixcfg.private_impl.pixfmt.repr = 0;
c->pixcfg.private_impl.pixsub.repr = 0;
c->pixcfg.private_impl.width = 0;
c->pixcfg.private_impl.height = 0;
c->private_impl.first_frame_io_position = 0;
@@ -490,13 +578,13 @@ wuffs_base__image_config__first_frame_is_opaque(
#ifdef __cplusplus
inline void //
wuffs_base__image_config::set(wuffs_base__pixel_format pixfmt,
wuffs_base__pixel_subsampling pixsub,
wuffs_base__image_config::set(uint32_t pixfmt_repr,
uint32_t pixsub_repr,
uint32_t width,
uint32_t height,
uint64_t first_frame_io_position,
bool first_frame_is_opaque) {
wuffs_base__image_config__set(this, pixfmt, pixsub, width, height,
wuffs_base__image_config__set(this, pixfmt_repr, pixsub_repr, width, height,
first_frame_io_position, first_frame_is_opaque);
}
@@ -524,6 +612,8 @@ wuffs_base__image_config::first_frame_is_opaque() const {
// --------
// Deprecated: use wuffs_base__pixel_blend instead.
//
// wuffs_base__animation_blend encodes, for an animated image, how to blend the
// transparent pixels of this frame with the existing canvas. In Porter-Duff
// compositing operator terminology:
@@ -570,8 +660,9 @@ typedef struct {
wuffs_base__flicks duration;
uint64_t index;
uint64_t io_position;
wuffs_base__animation_blend blend;
wuffs_base__animation_disposal disposal;
bool opaque_within_bounds;
bool overwrite_instead_of_blend;
wuffs_base__color_u32_argb_premul background_color;
} private_impl;
@@ -580,8 +671,9 @@ typedef struct {
wuffs_base__flicks duration,
uint64_t index,
uint64_t io_position,
wuffs_base__animation_blend blend,
wuffs_base__animation_disposal disposal,
bool opaque_within_bounds,
bool overwrite_instead_of_blend,
wuffs_base__color_u32_argb_premul background_color);
inline wuffs_base__rect_ie_u32 bounds() const;
inline uint32_t width() const;
@@ -589,8 +681,9 @@ typedef struct {
inline wuffs_base__flicks duration() const;
inline uint64_t index() const;
inline uint64_t io_position() const;
inline wuffs_base__animation_blend blend() const;
inline wuffs_base__animation_disposal disposal() const;
inline bool opaque_within_bounds() const;
inline bool overwrite_instead_of_blend() const;
inline wuffs_base__color_u32_argb_premul background_color() const;
#endif // __cplusplus
@@ -603,8 +696,9 @@ wuffs_base__null_frame_config() {
ret.private_impl.duration = 0;
ret.private_impl.index = 0;
ret.private_impl.io_position = 0;
ret.private_impl.blend = 0;
ret.private_impl.disposal = 0;
ret.private_impl.opaque_within_bounds = false;
ret.private_impl.overwrite_instead_of_blend = false;
return ret;
}
@@ -615,8 +709,9 @@ wuffs_base__frame_config__update(
wuffs_base__flicks duration,
uint64_t index,
uint64_t io_position,
wuffs_base__animation_blend blend,
wuffs_base__animation_disposal disposal,
bool opaque_within_bounds,
bool overwrite_instead_of_blend,
wuffs_base__color_u32_argb_premul background_color) {
if (!c) {
return;
@@ -626,8 +721,9 @@ wuffs_base__frame_config__update(
c->private_impl.duration = duration;
c->private_impl.index = index;
c->private_impl.io_position = io_position;
c->private_impl.blend = blend;
c->private_impl.disposal = disposal;
c->private_impl.opaque_within_bounds = opaque_within_bounds;
c->private_impl.overwrite_instead_of_blend = overwrite_instead_of_blend;
c->private_impl.background_color = background_color;
}
@@ -676,13 +772,6 @@ wuffs_base__frame_config__io_position(const wuffs_base__frame_config* c) {
return c ? c->private_impl.io_position : 0;
}
// wuffs_base__frame_config__blend returns, for an animated image, how to blend
// the transparent pixels of this frame with the existing canvas.
static inline wuffs_base__animation_blend //
wuffs_base__frame_config__blend(const wuffs_base__frame_config* c) {
return c ? c->private_impl.blend : 0;
}
// wuffs_base__frame_config__disposal returns, for an animated image, how to
// dispose of this frame after displaying it.
static inline wuffs_base__animation_disposal //
@@ -690,6 +779,37 @@ wuffs_base__frame_config__disposal(const wuffs_base__frame_config* c) {
return c ? c->private_impl.disposal : 0;
}
// wuffs_base__frame_config__opaque_within_bounds returns whether all pixels
// within the frame's bounds are fully opaque. It makes no claim about pixels
// outside the frame bounds but still inside the overall image. The two
// bounding rectangles can differ for animated images.
//
// Its semantics are conservative. It is valid for a fully opaque frame to have
// this value be false: a false negative.
//
// If true, drawing the frame with WUFFS_BASE__PIXEL_BLEND__SRC and
// WUFFS_BASE__PIXEL_BLEND__SRC_OVER should be equivalent, in terms of
// resultant pixels, but the former may be faster.
static inline bool //
wuffs_base__frame_config__opaque_within_bounds(
const wuffs_base__frame_config* c) {
return c && c->private_impl.opaque_within_bounds;
}
// wuffs_base__frame_config__overwrite_instead_of_blend returns, for an
// animated image, whether to ignore the previous image state (within the frame
// bounds) when drawing this incremental frame. Equivalently, whether to use
// WUFFS_BASE__PIXEL_BLEND__SRC instead of WUFFS_BASE__PIXEL_BLEND__SRC_OVER.
//
// The WebP spec (https://developers.google.com/speed/webp/docs/riff_container)
// calls this the "Blending method" bit. WebP's "Do not blend" corresponds to
// Wuffs' "overwrite_instead_of_blend".
static inline bool //
wuffs_base__frame_config__overwrite_instead_of_blend(
const wuffs_base__frame_config* c) {
return c && c->private_impl.overwrite_instead_of_blend;
}
static inline wuffs_base__color_u32_argb_premul //
wuffs_base__frame_config__background_color(const wuffs_base__frame_config* c) {
return c ? c->private_impl.background_color : 0;
@@ -703,11 +823,13 @@ wuffs_base__frame_config::update(
wuffs_base__flicks duration,
uint64_t index,
uint64_t io_position,
wuffs_base__animation_blend blend,
wuffs_base__animation_disposal disposal,
bool opaque_within_bounds,
bool overwrite_instead_of_blend,
wuffs_base__color_u32_argb_premul background_color) {
wuffs_base__frame_config__update(this, bounds, duration, index, io_position,
blend, disposal, background_color);
wuffs_base__frame_config__update(
this, bounds, duration, index, io_position, disposal,
opaque_within_bounds, overwrite_instead_of_blend, background_color);
}
inline wuffs_base__rect_ie_u32 //
@@ -740,16 +862,21 @@ wuffs_base__frame_config::io_position() const {
return wuffs_base__frame_config__io_position(this);
}
inline wuffs_base__animation_blend //
wuffs_base__frame_config::blend() const {
return wuffs_base__frame_config__blend(this);
}
inline wuffs_base__animation_disposal //
wuffs_base__frame_config::disposal() const {
return wuffs_base__frame_config__disposal(this);
}
inline bool //
wuffs_base__frame_config::opaque_within_bounds() const {
return wuffs_base__frame_config__opaque_within_bounds(this);
}
inline bool //
wuffs_base__frame_config::overwrite_instead_of_blend() const {
return wuffs_base__frame_config__overwrite_instead_of_blend(this);
}
inline wuffs_base__color_u32_argb_premul //
wuffs_base__frame_config::background_color() const {
return wuffs_base__frame_config__background_color(this);
@@ -799,33 +926,34 @@ wuffs_base__pixel_buffer__set_from_slice(wuffs_base__pixel_buffer* b,
const wuffs_base__pixel_config* pixcfg,
wuffs_base__slice_u8 pixbuf_memory) {
if (!b) {
return wuffs_base__error__bad_receiver;
return wuffs_base__make_status(wuffs_base__error__bad_receiver);
}
memset(b, 0, sizeof(*b));
if (!pixcfg) {
return wuffs_base__error__bad_argument;
return wuffs_base__make_status(wuffs_base__error__bad_argument);
}
if (wuffs_base__pixel_format__is_planar(pixcfg->private_impl.pixfmt)) {
if (wuffs_base__pixel_format__is_planar(&pixcfg->private_impl.pixfmt)) {
// TODO: support planar pixel formats, concious of pixel subsampling.
return wuffs_base__error__unsupported_option;
return wuffs_base__make_status(wuffs_base__error__unsupported_option);
}
uint32_t bits_per_pixel =
wuffs_base__pixel_format__bits_per_pixel(pixcfg->private_impl.pixfmt);
wuffs_base__pixel_format__bits_per_pixel(&pixcfg->private_impl.pixfmt);
if ((bits_per_pixel == 0) || ((bits_per_pixel % 8) != 0)) {
// TODO: support fraction-of-byte pixels, e.g. 1 bit per pixel?
return wuffs_base__error__unsupported_option;
return wuffs_base__make_status(wuffs_base__error__unsupported_option);
}
uint64_t bytes_per_pixel = bits_per_pixel / 8;
uint8_t* ptr = pixbuf_memory.ptr;
uint64_t len = pixbuf_memory.len;
if (wuffs_base__pixel_format__is_indexed(pixcfg->private_impl.pixfmt)) {
if (wuffs_base__pixel_format__is_indexed(&pixcfg->private_impl.pixfmt)) {
// Split a 1024 byte chunk (256 palette entries × 4 bytes per entry) from
// the start of pixbuf_memory. We split from the start, not the end, so
// that the both chunks' pointers have the same alignment as the original
// pointer, up to an alignment of 1024.
if (len < 1024) {
return wuffs_base__error__bad_argument_length_too_short;
return wuffs_base__make_status(
wuffs_base__error__bad_argument_length_too_short);
}
wuffs_base__table_u8* tab =
&b->private_impl.planes[WUFFS_BASE__PIXEL_FORMAT__INDEXED__COLOR_PLANE];
@@ -842,12 +970,13 @@ wuffs_base__pixel_buffer__set_from_slice(wuffs_base__pixel_buffer* b,
size_t width = (size_t)(pixcfg->private_impl.width);
if ((wh > (UINT64_MAX / bytes_per_pixel)) ||
(width > (SIZE_MAX / bytes_per_pixel))) {
return wuffs_base__error__bad_argument;
return wuffs_base__make_status(wuffs_base__error__bad_argument);
}
wh *= bytes_per_pixel;
width *= bytes_per_pixel;
if (wh > len) {
return wuffs_base__error__bad_argument_length_too_short;
return wuffs_base__make_status(
wuffs_base__error__bad_argument_length_too_short);
}
b->pixcfg = *pixcfg;
@@ -856,7 +985,7 @@ wuffs_base__pixel_buffer__set_from_slice(wuffs_base__pixel_buffer* b,
tab->width = width;
tab->height = pixcfg->private_impl.height;
tab->stride = width;
return NULL;
return wuffs_base__make_status(NULL);
}
static inline wuffs_base__status //
@@ -864,18 +993,18 @@ wuffs_base__pixel_buffer__set_from_table(wuffs_base__pixel_buffer* b,
const wuffs_base__pixel_config* pixcfg,
wuffs_base__table_u8 pixbuf_memory) {
if (!b) {
return wuffs_base__error__bad_receiver;
return wuffs_base__make_status(wuffs_base__error__bad_receiver);
}
memset(b, 0, sizeof(*b));
if (!pixcfg ||
wuffs_base__pixel_format__is_planar(pixcfg->private_impl.pixfmt)) {
return wuffs_base__error__bad_argument;
wuffs_base__pixel_format__is_planar(&pixcfg->private_impl.pixfmt)) {
return wuffs_base__make_status(wuffs_base__error__bad_argument);
}
uint32_t bits_per_pixel =
wuffs_base__pixel_format__bits_per_pixel(pixcfg->private_impl.pixfmt);
wuffs_base__pixel_format__bits_per_pixel(&pixcfg->private_impl.pixfmt);
if ((bits_per_pixel == 0) || ((bits_per_pixel % 8) != 0)) {
// TODO: support fraction-of-byte pixels, e.g. 1 bit per pixel?
return wuffs_base__error__unsupported_option;
return wuffs_base__make_status(wuffs_base__error__unsupported_option);
}
uint64_t bytes_per_pixel = bits_per_pixel / 8;
@@ -883,12 +1012,12 @@ wuffs_base__pixel_buffer__set_from_table(wuffs_base__pixel_buffer* b,
((uint64_t)pixcfg->private_impl.width) * bytes_per_pixel;
if ((width_in_bytes > pixbuf_memory.width) ||
(pixcfg->private_impl.height > pixbuf_memory.height)) {
return wuffs_base__error__bad_argument;
return wuffs_base__make_status(wuffs_base__error__bad_argument);
}
b->pixcfg = *pixcfg;
b->private_impl.planes[0] = pixbuf_memory;
return NULL;
return wuffs_base__make_status(NULL);
}
// wuffs_base__pixel_buffer__palette returns the palette color data. If
@@ -896,7 +1025,7 @@ wuffs_base__pixel_buffer__set_from_table(wuffs_base__pixel_buffer* b,
static inline wuffs_base__slice_u8 //
wuffs_base__pixel_buffer__palette(wuffs_base__pixel_buffer* b) {
if (b &&
wuffs_base__pixel_format__is_indexed(b->pixcfg.private_impl.pixfmt)) {
wuffs_base__pixel_format__is_indexed(&b->pixcfg.private_impl.pixfmt)) {
wuffs_base__table_u8* tab =
&b->private_impl.planes[WUFFS_BASE__PIXEL_FORMAT__INDEXED__COLOR_PLANE];
if ((tab->width == 1024) && (tab->height == 1)) {
@@ -911,7 +1040,7 @@ wuffs_base__pixel_buffer__pixel_format(const wuffs_base__pixel_buffer* b) {
if (b) {
return b->pixcfg.private_impl.pixfmt;
}
return WUFFS_BASE__PIXEL_FORMAT__INVALID;
return wuffs_base__make_pixel_format(WUFFS_BASE__PIXEL_FORMAT__INVALID);
}
static inline wuffs_base__table_u8 //
@@ -993,7 +1122,8 @@ typedef struct {
inline wuffs_base__status prepare(wuffs_base__pixel_format dst_format,
wuffs_base__slice_u8 dst_palette,
wuffs_base__pixel_format src_format,
wuffs_base__slice_u8 src_palette);
wuffs_base__slice_u8 src_palette,
wuffs_base__pixel_blend blend);
inline uint64_t swizzle_interleaved(wuffs_base__slice_u8 dst,
wuffs_base__slice_u8 dst_palette,
wuffs_base__slice_u8 src) const;
@@ -1006,7 +1136,8 @@ wuffs_base__pixel_swizzler__prepare(wuffs_base__pixel_swizzler* p,
wuffs_base__pixel_format dst_format,
wuffs_base__slice_u8 dst_palette,
wuffs_base__pixel_format src_format,
wuffs_base__slice_u8 src_palette);
wuffs_base__slice_u8 src_palette,
wuffs_base__pixel_blend blend);
uint64_t //
wuffs_base__pixel_swizzler__swizzle_interleaved(
@@ -1021,9 +1152,10 @@ inline wuffs_base__status //
wuffs_base__pixel_swizzler::prepare(wuffs_base__pixel_format dst_format,
wuffs_base__slice_u8 dst_palette,
wuffs_base__pixel_format src_format,
wuffs_base__slice_u8 src_palette) {
wuffs_base__slice_u8 src_palette,
wuffs_base__pixel_blend blend) {
return wuffs_base__pixel_swizzler__prepare(this, dst_format, dst_palette,
src_format, src_palette);
src_format, src_palette, blend);
}
uint64_t //

View File

@@ -33,11 +33,11 @@ wuffs_base__io__since(uint64_t mark, uint64_t index, uint8_t* ptr) {
}
static inline uint32_t //
wuffs_base__io_writer__copy_n_from_history(uint8_t** ptr_iop_w,
uint8_t* io1_w,
uint8_t* io2_w,
uint32_t length,
uint32_t distance) {
wuffs_base__io_writer__copy_n32_from_history(uint8_t** ptr_iop_w,
uint8_t* io1_w,
uint8_t* io2_w,
uint32_t length,
uint32_t distance) {
if (!distance) {
return 0;
}
@@ -55,12 +55,13 @@ wuffs_base__io_writer__copy_n_from_history(uint8_t** ptr_iop_w,
// TODO: unrolling by 3 seems best for the std/deflate benchmarks, but that
// is mostly because 3 is the minimum length for the deflate format. This
// function implementation shouldn't overfit to that one format. Perhaps the
// copy_n_from_history Wuffs method should also take an unroll hint argument,
// and the cgen can look if that argument is the constant expression '3'.
// copy_n32_from_history Wuffs method should also take an unroll hint
// argument, and the cgen can look if that argument is the constant
// expression '3'.
//
// See also wuffs_base__io_writer__copy_n_from_history_fast below.
// See also wuffs_base__io_writer__copy_n32_from_history_fast below.
//
// Alternatively, or additionally, have a sloppy_copy_n_from_history method
// Alternatively, or additionally, have a sloppy_copy_n32_from_history method
// that copies 8 bytes at a time, possibly writing more than length bytes?
for (; n >= 3; n -= 3) {
*p++ = *q++;
@@ -74,18 +75,18 @@ wuffs_base__io_writer__copy_n_from_history(uint8_t** ptr_iop_w,
return length;
}
// wuffs_base__io_writer__copy_n_from_history_fast is like the
// wuffs_base__io_writer__copy_n_from_history function above, but has stronger
// pre-conditions. The caller needs to prove that:
// wuffs_base__io_writer__copy_n32_from_history_fast is like the
// wuffs_base__io_writer__copy_n32_from_history function above, but has
// stronger pre-conditions. The caller needs to prove that:
// - distance > 0
// - distance <= (*ptr_iop_w - io1_w)
// - length <= (io2_w - *ptr_iop_w)
static inline uint32_t //
wuffs_base__io_writer__copy_n_from_history_fast(uint8_t** ptr_iop_w,
uint8_t* io1_w,
uint8_t* io2_w,
uint32_t length,
uint32_t distance) {
wuffs_base__io_writer__copy_n32_from_history_fast(uint8_t** ptr_iop_w,
uint8_t* io1_w,
uint8_t* io2_w,
uint32_t length,
uint32_t distance) {
uint8_t* p = *ptr_iop_w;
uint8_t* q = p - distance;
uint32_t n = length;
@@ -102,11 +103,11 @@ wuffs_base__io_writer__copy_n_from_history_fast(uint8_t** ptr_iop_w,
}
static inline uint32_t //
wuffs_base__io_writer__copy_n_from_reader(uint8_t** ptr_iop_w,
uint8_t* io2_w,
uint32_t length,
uint8_t** ptr_iop_r,
uint8_t* io2_r) {
wuffs_base__io_writer__copy_n32_from_reader(uint8_t** ptr_iop_w,
uint8_t* io2_w,
uint32_t length,
uint8_t** ptr_iop_r,
uint8_t* io2_r) {
uint8_t* iop_w = *ptr_iop_w;
size_t n = length;
if (n > ((size_t)(io2_w - iop_w))) {
@@ -141,10 +142,10 @@ wuffs_base__io_writer__copy_from_slice(uint8_t** ptr_iop_w,
}
static inline uint32_t //
wuffs_base__io_writer__copy_n_from_slice(uint8_t** ptr_iop_w,
uint8_t* io2_w,
uint32_t length,
wuffs_base__slice_u8 src) {
wuffs_base__io_writer__copy_n32_from_slice(uint8_t** ptr_iop_w,
uint8_t* io2_w,
uint32_t length,
wuffs_base__slice_u8 src) {
uint8_t* iop_w = *ptr_iop_w;
size_t n = src.len;
if (n > length) {

View File

@@ -176,7 +176,7 @@ func (g *gen) writeBuiltinIOReader(b *buffer, recv *a.Expr, method t.ID, args []
iopPrefix, name, io0Prefix, name, io0Prefix, name)
return nil
case t.IDSkipFast:
case t.IDSkip32Fast:
// Generate a two part expression using the comma operator: "(pointer
// increment, return_empty_struct call)". The final part is a function
// call (to a static inline function) instead of a struct literal, to
@@ -218,12 +218,12 @@ func (g *gen) writeBuiltinIOWriter(b *buffer, recv *a.Expr, method t.ID, args []
}
switch method {
case t.IDCopyNFromHistory, t.IDCopyNFromHistoryFast:
case t.IDCopyN32FromHistory, t.IDCopyN32FromHistoryFast:
suffix := ""
if method == t.IDCopyNFromHistoryFast {
if method == t.IDCopyN32FromHistoryFast {
suffix = "_fast"
}
b.printf("wuffs_base__io_writer__copy_n_from_history%s(&%s%s, %s%s, %s%s",
b.printf("wuffs_base__io_writer__copy_n32_from_history%s(&%s%s, %s%s, %s%s",
suffix, iopPrefix, name, io0Prefix, name, io2Prefix, name)
for _, o := range args {
b.writeb(',')
@@ -234,13 +234,13 @@ func (g *gen) writeBuiltinIOWriter(b *buffer, recv *a.Expr, method t.ID, args []
b.writeb(')')
return nil
case t.IDCopyNFromReader:
case t.IDCopyN32FromReader:
readerName, err := g.ioRecvName(args[1].AsArg().Value())
if err != nil {
return err
}
b.printf("wuffs_base__io_writer__copy_n_from_reader(&%s%s, %s%s,",
b.printf("wuffs_base__io_writer__copy_n32_from_reader(&%s%s, %s%s,",
iopPrefix, name, io2Prefix, name)
if err := g.writeExpr(b, args[0].AsArg().Value(), depth); err != nil {
return err
@@ -253,8 +253,8 @@ func (g *gen) writeBuiltinIOWriter(b *buffer, recv *a.Expr, method t.ID, args []
iopPrefix, name, io2Prefix, name)
return g.writeArgs(b, args, depth)
case t.IDCopyNFromSlice:
b.printf("wuffs_base__io_writer__copy_n_from_slice(&%s%s, %s%s,",
case t.IDCopyN32FromSlice:
b.printf("wuffs_base__io_writer__copy_n32_from_slice(&%s%s, %s%s,",
iopPrefix, name, io2Prefix, name)
return g.writeArgs(b, args, depth)
@@ -573,7 +573,7 @@ func (g *gen) writeBuiltinQuestionCall(b *buffer, n *a.Expr, depth uint32) error
g.currFunk.tempW++
b.printf("if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {" +
"status = wuffs_base__suspension__short_read; goto suspend; }")
"status = wuffs_base__make_status(wuffs_base__suspension__short_read); goto suspend; }")
// TODO: watch for passing an array type to writeCTypeName? In C, an
// array type can decay into a pointer.
@@ -583,14 +583,14 @@ func (g *gen) writeBuiltinQuestionCall(b *buffer, n *a.Expr, depth uint32) error
b.printf(" = *iop_a_src++;\n")
return nil
case t.IDSkip:
case t.IDSkip, t.IDSkip32:
x := n.Args()[0].AsArg().Value()
if cv := x.ConstValue(); cv != nil && cv.Cmp(one) == 0 {
if err := g.writeCoroSuspPoint(b, false); err != nil {
return err
}
b.printf("if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {" +
"status = wuffs_base__suspension__short_read; goto suspend; }")
"status = wuffs_base__make_status(wuffs_base__suspension__short_read); goto suspend; }")
b.printf("iop_a_src++;\n")
return nil
}
@@ -614,7 +614,7 @@ func (g *gen) writeBuiltinQuestionCall(b *buffer, n *a.Expr, depth uint32) error
b.printf("%s -= ((uint64_t)(io2_a_src - iop_a_src));\n", scratchName)
b.printf("iop_a_src = io2_a_src;\n")
b.writes("status = wuffs_base__suspension__short_read; goto suspend; }\n")
b.writes("status = wuffs_base__make_status(wuffs_base__suspension__short_read); goto suspend; }\n")
b.printf("iop_a_src += %s;\n", scratchName)
return nil
}
@@ -637,7 +637,7 @@ func (g *gen) writeBuiltinQuestionCall(b *buffer, n *a.Expr, depth uint32) error
return err
}
b.writes("if (iop_a_dst == io2_a_dst) {\n" +
"status = wuffs_base__suspension__short_write; goto suspend; }\n" +
"status = wuffs_base__make_status(wuffs_base__suspension__short_write); goto suspend; }\n" +
"*iop_a_dst++ = ")
x := n.Args()[0].AsArg().Value()
if err := g.writeExpr(b, x, depth); err != nil {
@@ -693,7 +693,7 @@ func (g *gen) writeReadUxxAsUyy(b *buffer, n *a.Expr, preName string, xx uint8,
b.printf("while (true) {")
b.printf("if (WUFFS_BASE__UNLIKELY(iop_%s == io2_%s)) {"+
"status = wuffs_base__suspension__short_read; goto suspend; }",
"status = wuffs_base__make_status(wuffs_base__suspension__short_read); goto suspend; }",
preName, preName)
b.printf("uint64_t *scratch = &%s;", scratchName)

View File

@@ -28,7 +28,6 @@ import (
"strings"
"github.com/google/wuffs/lang/builtin"
"github.com/google/wuffs/lang/check"
"github.com/google/wuffs/lang/generate"
cf "github.com/google/wuffs/cmd/commonflags"
@@ -105,7 +104,7 @@ func Do(args []string) error {
cformatterFlag := flags.String("cformatter", cf.CformatterDefault, cf.CformatterUsage)
genlinenumFlag := flags.Bool("genlinenum", cf.GenlinenumDefault, cf.GenlinenumUsage)
return generate.Do(&flags, args, func(pkgName string, tm *t.Map, c *check.Checker, files []*a.File) ([]byte, error) {
return generate.Do(&flags, args, func(pkgName string, tm *t.Map, files []*a.File) ([]byte, error) {
if !cf.IsAlphaNumericIsh(*cformatterFlag) {
return nil, fmt.Errorf("bad -cformatter flag value %q", *cformatterFlag)
}
@@ -117,17 +116,19 @@ func Do(args []string) error {
}
buf := make(buffer, 0, 128*1024)
if err := expandBangBangInsert(&buf, baseAllImplC, map[string]func(*buffer) error{
"// !! INSERT base/all-private.h.\n": insertBaseAllPrivateH,
"// !! INSERT base/all-public.h.\n": insertBaseAllPublicH,
"// !! INSERT base/copyright\n": insertBaseCopyright,
"// !! INSERT base/image-impl.c.\n": insertBaseImageImplC,
"// !! INSERT InterfaceDeclarations.\n": insertInterfaceDeclarations,
"// !! INSERT InterfaceDefinitions.\n": insertInterfaceDefinitions,
"// !! INSERT base/all-private.h.\n": insertBaseAllPrivateH,
"// !! INSERT base/all-public.h.\n": insertBaseAllPublicH,
"// !! INSERT base/copyright\n": insertBaseCopyright,
"// !! INSERT base/image-impl.c.\n": insertBaseImageImplC,
"// !! INSERT wuffs_base__status strings.\n": func(b *buffer) error {
for _, z := range builtin.Statuses {
msg, _ := t.Unescape(z)
if msg == "" {
continue
}
pre := "warning"
pre := "note"
if msg[0] == '$' {
pre = "suspension"
} else if msg[0] == '#' {
@@ -148,7 +149,6 @@ func Do(args []string) error {
pkgPrefix: "wuffs_" + pkgName + "__",
pkgName: pkgName,
tm: tm,
checker: c,
files: files,
genlinenum: *genlinenumFlag,
}
@@ -195,12 +195,12 @@ func statusMsgIsError(msg string) bool {
return (len(msg) != 0) && (msg[0] == '#')
}
func statusMsgIsSuspension(msg string) bool {
return (len(msg) != 0) && (msg[0] == '$')
func statusMsgIsNote(msg string) bool {
return (len(msg) == 0) || (msg[0] != '$' && msg[0] != '#')
}
func statusMsgIsWarning(msg string) bool {
return (len(msg) == 0) || (msg[0] != '$' && msg[0] != '#')
func statusMsgIsSuspension(msg string) bool {
return (len(msg) != 0) && (msg[0] == '$')
}
type buffer []byte
@@ -284,7 +284,7 @@ func insertBaseAllPublicH(buf *buffer) error {
if msg == "" {
return fmt.Errorf("bad built-in status %q", z)
}
pre := "warning"
pre := "note"
if statusMsgIsError(msg) {
pre = "error"
} else if statusMsgIsSuspension(msg) {
@@ -322,13 +322,166 @@ func insertBaseImageImplC(buf *buffer) error {
return nil
}
func insertInterfaceDeclarations(buf *buffer) error {
if err := parseBuiltInInterfaceMethods(); err != nil {
return err
}
g := &gen{
pkgPrefix: "wuffs_base__",
pkgName: "base",
tm: &builtInTokenMap,
}
buf.writes("// ---------------- Interface Declarations.\n\n")
for i, n := range builtin.Interfaces {
if i > 0 {
buf.writes("// --------\n\n")
}
qid := t.QID{t.IDBase, builtInTokenMap.ByName(n)}
buf.printf("extern const char* wuffs_base__%s__vtable_name;\n\n", n)
buf.writes("typedef struct {\n\n")
for _, f := range builtInInterfaceMethods[qid] {
if err := g.writeFuncSignature(buf, f, wfsCFuncPtrField); err != nil {
return err
}
buf.writes(";\n")
}
buf.printf("} wuffs_base__%s__func_ptrs;\n\n", n)
buf.printf("typedef struct wuffs_base__%s__struct wuffs_base__%s;\n\n", n, n)
for _, f := range builtInInterfaceMethods[qid] {
if err := g.writeFuncSignature(buf, f, wfsCDecl); err != nil {
return err
}
buf.writes(";\n\n")
}
buf.writes("#if defined(__cplusplus) || defined(WUFFS_IMPLEMENTATION)\n\n")
buf.printf("struct wuffs_base__%s__struct {", n)
buf.writes("struct {\n")
buf.writes("uint32_t magic;\n")
buf.writes("uint32_t active_coroutine;\n")
buf.writes("wuffs_base__vtable first_vtable;\n")
buf.writes("} private_impl;\n\n")
buf.writes("\n#ifdef __cplusplus\n\n")
for _, f := range builtInInterfaceMethods[qid] {
if err := g.writeFuncSignature(buf, f, wfsCppDecl); err != nil {
return err
}
buf.writes("{ return ")
buf.writes(g.funcCName(f))
buf.writes("(this")
for _, o := range f.In().Fields() {
buf.writeb(',')
buf.writes(aPrefix)
buf.writes(o.AsField().Name().Str(g.tm))
}
buf.writes(");}\n\n")
}
buf.writes("#endif // __cplusplus\n\n")
buf.printf("}; // struct wuffs_base__%s__struct\n\n", n)
buf.writes("#endif // defined(__cplusplus) || defined(WUFFS_IMPLEMENTATION)\n\n")
}
return nil
}
func insertInterfaceDefinitions(buf *buffer) error {
if err := parseBuiltInInterfaceMethods(); err != nil {
return err
}
g := &gen{
pkgPrefix: "wuffs_base__",
pkgName: "base",
tm: &builtInTokenMap,
}
buf.writes("// ---------------- Interface Definitions.\n\n")
for i, n := range builtin.Interfaces {
if i > 0 {
buf.writes("// --------\n\n")
}
qid := t.QID{t.IDBase, builtInTokenMap.ByName(n)}
buf.printf("const char* wuffs_base__%s__vtable_name = "+
"\"{vtable}wuffs_base__%s\";\n\n", n, n)
for _, f := range builtInInterfaceMethods[qid] {
returnsStatus := f.Effect().Coroutine() ||
((f.Out() != nil) && f.Out().IsStatus())
if err := g.writeFuncSignature(buf, f, wfsCDecl); err != nil {
return err
}
buf.writes("{\n")
if err := writeFuncImplSelfMagicCheck(buf, g.tm, f); err != nil {
return err
}
buf.writes("\nconst wuffs_base__vtable* v = &self->private_impl.first_vtable;\n")
buf.writes("int i;\n")
buf.printf("for (i = 0; i < %d; i++) {\n", a.MaxImplements)
buf.printf("if (v->vtable_name == wuffs_base__%s__vtable_name) {\n", n)
buf.printf("const wuffs_base__%s__func_ptrs* func_ptrs = "+
"(const wuffs_base__%s__func_ptrs*)(v->function_pointers);\n", n, n)
buf.printf("return (*func_ptrs->%s)(self", f.FuncName().Str(g.tm))
for _, o := range f.In().Fields() {
buf.writeb(',')
buf.writes(aPrefix)
buf.writes(o.AsField().Name().Str(g.tm))
}
buf.writes(");\n")
buf.writes("} else if (v->vtable_name == NULL) {\n")
buf.writes("break;\n")
buf.writes("}\n")
buf.writes("v++;\n")
buf.writes("}\n\n")
buf.writes("return ")
if returnsStatus {
buf.writes("wuffs_base__make_status(wuffs_base__error__bad_vtable)")
} else if err := writeOutParamZeroValue(buf, g.tm, f.Out()); err != nil {
return err
}
buf.writes(";\n}\n\n")
}
}
return nil
}
var (
builtInTokenMap = t.Map{}
builtInInterfaceMethods = map[t.QID][]*a.Func{}
)
func parseBuiltInInterfaceMethods() error {
if len(builtInInterfaceMethods) != 0 {
return nil
}
return builtin.ParseFuncs(&builtInTokenMap, builtin.InterfaceFuncs, func(f *a.Func) error {
qid := f.Receiver()
builtInInterfaceMethods[qid] = append(builtInInterfaceMethods[qid], f)
return nil
})
}
type gen struct {
pkgPrefix string // e.g. "wuffs_jpeg__"
pkgName string // e.g. "jpeg"
tm *t.Map
checker *check.Checker
files []*a.File
tm *t.Map
files []*a.File
// genlinenum is whether to print "// foo.wuffs:123" comments in the
// generated C code. This can be useful for debugging, although it is not
@@ -431,6 +584,11 @@ func (g *gen) generate() ([]byte, error) {
return *b, nil
}
var (
wiStartImpl = []byte("\n// WUFFS C HEADER ENDS HERE.\n#ifdef WUFFS_IMPLEMENTATION\n\n")
wiEnd = []byte("\n#endif // WUFFS_IMPLEMENTATION\n\n")
)
func (g *gen) genIncludes(b *buffer) error {
b.writes("#if defined(WUFFS_IMPLEMENTATION) && !defined(WUFFS_CONFIG__MODULES)\n")
b.writes("#define WUFFS_CONFIG__MODULES\n")
@@ -507,6 +665,20 @@ func (g *gen) genHeader(b *buffer) error {
}
}
b.writes("// ---------------- Upcasts\n\n")
for _, n := range g.structList {
structName := n.QID().Str(g.tm)
for _, impl := range n.Implements() {
iQID := impl.AsTypeExpr().QID()
iName := fmt.Sprintf("wuffs_%s__%s", iQID[0].Str(g.tm), iQID[1].Str(g.tm))
b.printf("static inline %s* //\n", iName)
b.printf("%s%s__upcast_as__%s(%s%s* p){\n",
g.pkgPrefix, structName, iName, g.pkgPrefix, structName)
b.printf("return (%s*)p;\n", iName)
b.printf("}\n\n")
}
}
b.writes("// ---------------- Public Function Prototypes\n\n")
if err := g.forEachFunc(b, pubOnly, (*gen).writeFuncPrototype); err != nil {
return err
@@ -564,6 +736,13 @@ func (g *gen) genImpl(b *buffer) error {
return err
}
b.writes("// ---------------- VTables\n\n")
for _, n := range g.structList {
if err := g.writeVTableImpl(b, n); err != nil {
return err
}
}
b.writes("// ---------------- Initializer Implementations\n\n")
for _, n := range g.structList {
if err := g.writeInitializerImpl(b, n); err != nil {
@@ -688,7 +867,7 @@ func (g *gen) gatherStatuses(b *buffer, n *a.Status) error {
}
func (g *gen) addStatus(qid t.QID, msg string, public bool) error {
category := "warning__"
category := "note__"
if msg[0] == '$' {
category = "suspension__"
} else if msg[0] == '#' {
@@ -762,6 +941,12 @@ func (g *gen) writeStructPrivateImpl(b *buffer, n *a.Struct) error {
if n.Classy() {
b.writes("uint32_t magic;\n")
b.writes("uint32_t active_coroutine;\n")
for _, impl := range n.Implements() {
qid := impl.AsTypeExpr().QID()
b.printf("wuffs_base__vtable vtable_for__wuffs_%s__%s;\n",
qid[0].Str(g.tm), qid[1].Str(g.tm))
}
b.writes("wuffs_base__vtable null_vtable;\n")
b.writes("\n")
}
@@ -866,30 +1051,10 @@ func (g *gen) writeStruct(b *buffer, n *a.Struct) error {
fullStructName := g.pkgPrefix + structName + "__struct"
b.printf("struct %s {\n", fullStructName)
b.writex(wiStart)
if err := g.writeStructPrivateImpl(b, n); err != nil {
return err
}
b.writex(wiElse)
b.writes("// When WUFFS_IMPLEMENTATION is not defined, this placeholder private_impl is\n")
b.writes("// large enough to discourage trying to allocate one on the stack. The sizeof\n")
b.writes("// the real private_impl (and the sizeof the real outermost wuffs_foo__bar\n")
b.writes("// struct) is not part of the public, stable, memory-safe API. Call\n")
b.writes("// wuffs_foo__bar__baz methods (which all take a \"this\"-like pointer as their\n")
b.writes("// first argument) instead of fiddling with bar.private_impl.qux fields.\n")
b.writes("//\n")
b.writes("// Even when WUFFS_IMPLEMENTATION is not defined, the outermost struct still\n")
b.writes("// defines C++ convenience methods. These methods forward on \"this\", so that\n")
b.writes("// you can write \"bar->baz(etc)\" instead of \"wuffs_foo__bar__baz(bar, etc)\".\n")
b.writes("private:\n")
b.writes("union {\n")
b.writes("uint32_t align_as_per_magic_field;\n")
b.writes("uint8_t placeholder[1073741824]; // 1 GiB.\n")
b.writes("} private_impl WUFFS_BASE__POTENTIALLY_UNUSED_FIELD;\n\n")
b.writes("public:\n")
b.writex(wiEnd)
if n.AsNode().AsRaw().Flags()&a.FlagsPublic != 0 {
if err := g.writeCppMethods(b, n); err != nil {
return err
@@ -903,7 +1068,34 @@ func (g *gen) writeStruct(b *buffer, n *a.Struct) error {
func (g *gen) writeCppMethods(b *buffer, n *a.Struct) error {
structName := n.QID().Str(g.tm)
fullStructName := g.pkgPrefix + structName + "__struct"
b.writes("#ifdef __cplusplus\n\n")
b.writes("#ifdef __cplusplus\n")
b.writes("#if (__cplusplus >= 201103L) && !defined(WUFFS_IMPLEMENTATION)\n")
b.writes("// Disallow constructing or copying an object via standard C++ mechanisms,\n")
b.writes("// e.g. the \"new\" operator, as this struct is intentionally opaque. Its total\n")
b.writes("// size and field layout is not part of the public, stable, memory-safe API.\n")
b.writes("// Use malloc or memcpy and the sizeof__wuffs_foo__bar function instead, and\n")
b.writes("// call wuffs_foo__bar__baz methods (which all take a \"this\"-like pointer as\n")
b.writes("// their first argument) rather than tweaking bar.private_impl.qux fields.\n")
b.writes("//\n")
b.writes("// In C, we can just leave wuffs_foo__bar as an incomplete type (unless\n")
b.writes("// WUFFS_IMPLEMENTATION is #define'd). In C++, we define a complete type in\n")
b.writes("// order to provide convenience methods. These forward on \"this\", so that you\n")
b.writes("// can write \"bar->baz(etc)\" instead of \"wuffs_foo__bar__baz(bar, etc)\".\n")
b.printf("%s() = delete;\n", fullStructName)
b.printf("%s(const %s&) = delete;\n", fullStructName, fullStructName)
b.printf("%s& operator=(const %s&) = delete;\n", fullStructName, fullStructName)
b.writes("\n")
b.writes("// As above, the size of the struct is not part of the public API, and unless\n")
b.writes("// WUFFS_IMPLEMENTATION is #define'd, this struct type T should be heap\n")
b.writes("// allocated, not stack allocated. Its size is not intended to be known at\n")
b.writes("// compile time, but it is unfortunately divulged as a side effect of\n")
b.writes("// defining C++ convenience methods. Use \"sizeof__T()\", calling the function,\n")
b.writes("// instead of \"sizeof T\", invoking the operator. To make the two values\n")
b.writes("// different, so that passing the latter will be rejected by the initialize\n")
b.writes("// function, we add an arbitrary amount of dead weight.\n")
b.writes("uint8_t dead_weight[123000000]; // 123 MB.\n")
b.writes("#endif // (__cplusplus >= 201103L) && !defined(WUFFS_IMPLEMENTATION)\n\n")
// The empty // comment makes clang-format place the function name
// at the start of a line.
@@ -912,6 +1104,15 @@ func (g *gen) writeCppMethods(b *buffer, n *a.Struct) error {
b.printf("return %s%s__initialize(this, sizeof_star_self, wuffs_version, initialize_flags);\n}\n\n",
g.pkgPrefix, structName)
for _, impl := range n.Implements() {
iQID := impl.AsTypeExpr().QID()
iName := fmt.Sprintf("wuffs_%s__%s", iQID[0].Str(g.tm), iQID[1].Str(g.tm))
b.printf("inline %s* //\n", iName)
b.printf("upcast_as__%s(){\n", iName)
b.printf("return (%s*)this;\n", iName)
b.printf("}\n\n")
}
structID := n.QID()[1]
for _, file := range g.files {
for _, tld := range file.TopLevelDecls() {
@@ -924,7 +1125,7 @@ func (g *gen) writeCppMethods(b *buffer, n *a.Struct) error {
continue
}
if err := g.writeFuncSignature(b, f, cppInsideStruct); err != nil {
if err := g.writeFuncSignature(b, f, wfsCppDecl); err != nil {
return err
}
b.writes("{ return ")
@@ -939,22 +1140,48 @@ func (g *gen) writeCppMethods(b *buffer, n *a.Struct) error {
}
}
b.writes("#if (__cplusplus >= 201103L) && !defined(WUFFS_IMPLEMENTATION)\n")
b.writes("// Disallow copy and assign.\n")
b.printf("%s(const %s&) = delete;\n", fullStructName, fullStructName)
b.printf("%s& operator=(const %s&) = delete;\n", fullStructName, fullStructName)
b.writes("#endif // (__cplusplus >= 201103L) && !defined(WUFFS_IMPLEMENTATION)\n\n")
b.writes("#endif // __cplusplus\n\n")
return nil
}
var (
wiStartImpl = []byte("\n// WUFFS C HEADER ENDS HERE.\n#ifdef WUFFS_IMPLEMENTATION\n\n")
wiStart = []byte("\n#ifdef WUFFS_IMPLEMENTATION\n\n")
wiElse = []byte("\n#else // WUFFS_IMPLEMENTATION\n\n")
wiEnd = []byte("\n#endif // WUFFS_IMPLEMENTATION\n\n")
)
func (g *gen) writeVTableImpl(b *buffer, n *a.Struct) error {
impls := n.Implements()
if len(impls) == 0 {
return nil
}
if err := parseBuiltInInterfaceMethods(); err != nil {
return err
}
nQID := n.QID()
for _, impl := range impls {
iQID := impl.AsTypeExpr().QID()
b.printf("const wuffs_%s__%s__func_ptrs %s%s__func_ptrs_for__wuffs_%s__%s = {",
iQID[0].Str(g.tm), iQID[1].Str(g.tm),
g.pkgPrefix, nQID[1].Str(g.tm),
iQID[0].Str(g.tm), iQID[1].Str(g.tm),
)
// Note the two t.Map values: g.tm and builtInTokenMap.
altQID := t.QID{
builtInTokenMap.ByName(iQID[0].Str(g.tm)),
builtInTokenMap.ByName(iQID[1].Str(g.tm)),
}
for _, f := range builtInInterfaceMethods[altQID] {
b.writeb('(')
if err := g.writeFuncSignature(b, f, wfsCFuncPtrType); err != nil {
return err
}
b.printf(")(&%s%s__%s),\n",
g.pkgPrefix, nQID[1].Str(g.tm),
f.FuncName().Str(&builtInTokenMap),
)
}
b.writes("};\n\n")
}
return nil
}
func (g *gen) writeInitializerSignature(b *buffer, n *a.Struct, public bool) error {
structName := n.QID().Str(g.tm)
@@ -995,14 +1222,14 @@ func (g *gen) writeInitializerImpl(b *buffer, n *a.Struct) error {
return err
}
b.writes("{\n")
b.writes("if (!self) { return wuffs_base__error__bad_receiver; }\n")
b.writes("if (!self) { return wuffs_base__make_status(wuffs_base__error__bad_receiver); }\n")
b.writes("if (sizeof(*self) != sizeof_star_self) {\n")
b.writes(" return wuffs_base__error__bad_sizeof_receiver;\n")
b.writes(" return wuffs_base__make_status(wuffs_base__error__bad_sizeof_receiver);\n")
b.writes("}\n")
b.writes("if (((wuffs_version >> 32) != WUFFS_VERSION_MAJOR) || " +
"(((wuffs_version >> 16) & 0xFFFF) > WUFFS_VERSION_MINOR)) {\n")
b.writes(" return wuffs_base__error__bad_wuffs_version;\n")
b.writes(" return wuffs_base__make_status(wuffs_base__error__bad_wuffs_version);\n")
b.writes("}\n\n")
b.writes("if ((initialize_flags & WUFFS_INITIALIZE__ALREADY_ZEROED) != 0) {\n")
@@ -1013,7 +1240,7 @@ func (g *gen) writeInitializerImpl(b *buffer, n *a.Struct) error {
b.writes(" #pragma GCC diagnostic ignored \"-Wmaybe-uninitialized\"\n")
b.writes(" #endif\n")
b.writes(" if (self->private_impl.magic != 0) {\n")
b.writes(" return wuffs_base__error__initialize_falsely_claimed_already_zeroed;\n")
b.writes(" return wuffs_base__make_status(wuffs_base__error__initialize_falsely_claimed_already_zeroed);\n")
b.writes(" }\n")
b.writes(" #if !defined(__clang__) && defined(__GNUC__)\n")
b.writes(" #pragma GCC diagnostic pop\n")
@@ -1053,12 +1280,21 @@ func (g *gen) writeInitializerImpl(b *buffer, n *a.Struct) error {
b.printf("wuffs_base__status z = %s%s__initialize("+
"&self->private_data.%s%s, sizeof(self->private_data.%s%s), WUFFS_VERSION, initialize_flags);\n",
prefix, qid[1].Str(g.tm), fPrefix, f.Name().Str(g.tm), fPrefix, f.Name().Str(g.tm))
b.printf("if (z) { return z; }\n")
b.printf("if (z.repr) { return z; }\n")
b.printf("}\n")
}
b.writes("self->private_impl.magic = WUFFS_BASE__MAGIC;\n")
b.writes("return NULL;\n")
for _, impl := range n.Implements() {
qid := impl.AsTypeExpr().QID()
iName := fmt.Sprintf("wuffs_%s__%s", qid[0].Str(g.tm), qid[1].Str(g.tm))
b.printf("self->private_impl.vtable_for__%s.vtable_name = "+
"%s__vtable_name;\n", iName, iName)
b.printf("self->private_impl.vtable_for__%s.function_pointers = "+
"(const void*)(&%s%s__func_ptrs_for__%s);\n",
iName, g.pkgPrefix, n.QID().Str(g.tm), iName)
}
b.writes("return wuffs_base__make_status(NULL);\n")
b.writes("}\n\n")
if n.Public() {

View File

@@ -17,25 +17,29 @@
package cgen
const baseAllImplC = "" +
"#ifndef WUFFS_INCLUDE_GUARD__BASE\n#define WUFFS_INCLUDE_GUARD__BASE\n\n#if defined(WUFFS_IMPLEMENTATION) && !defined(WUFFS_CONFIG__MODULES)\n#define WUFFS_CONFIG__MODULES\n#define WUFFS_CONFIG__MODULE__BASE\n#endif\n\n// !! WUFFS MONOLITHIC RELEASE DISCARDS EVERYTHING ABOVE.\n\n// !! INSERT base/copyright\n\n#include <stdbool.h>\n#include <stdint.h>\n#include <string.h>\n\n// GCC does not warn for unused *static inline* functions, but clang does.\n#ifdef __clang__\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wunused-function\"\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// !! INSERT base/all-public.h.\n\n#ifdef __cplusplus\n} // extern \"C\"\n#endif\n\n#ifdef __clang__\n#pragma clang diagnostic pop\n#endif\n\n// WUFFS C HEADER ENDS HERE.\n#ifdef WUFFS_IMPLEMENTATION\n\n// GCC does not warn for unused *static inline* functions, but clang does.\n#ifdef __clang__\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wunused-function\"\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// !! INSERT base/all-privat" +
"e.h.\n\n#if !defined(WUFFS_CONFIG__MODULES) || defined(WUFFS_CONFIG__MODULE__BASE)\n\nconst uint8_t wuffs_base__low_bits_mask__u8[9] = {\n 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF,\n};\n\nconst uint16_t wuffs_base__low_bits_mask__u16[17] = {\n 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF,\n 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF,\n};\n\nconst uint32_t wuffs_base__low_bits_mask__u32[33] = {\n 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000F, 0x0000001F,\n 0x0000003F, 0x0000007F, 0x000000FF, 0x000001FF, 0x000003FF, 0x000007FF,\n 0x00000FFF, 0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF, 0x0001FFFF,\n 0x0003FFFF, 0x0007FFFF, 0x000FFFFF, 0x001FFFFF, 0x003FFFFF, 0x007FFFFF,\n 0x00FFFFFF, 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF, 0x1FFFFFFF,\n 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF,\n};\n\nconst uint64_t wuffs_base__low_bits_mask__u64[65] = {\n 0x0000000000000000, 0x0000000000000001, 0x0000000000000003,\n 0x0000000000000007, 0x00000" +
"0000000000F, 0x000000000000001F,\n 0x000000000000003F, 0x000000000000007F, 0x00000000000000FF,\n 0x00000000000001FF, 0x00000000000003FF, 0x00000000000007FF,\n 0x0000000000000FFF, 0x0000000000001FFF, 0x0000000000003FFF,\n 0x0000000000007FFF, 0x000000000000FFFF, 0x000000000001FFFF,\n 0x000000000003FFFF, 0x000000000007FFFF, 0x00000000000FFFFF,\n 0x00000000001FFFFF, 0x00000000003FFFFF, 0x00000000007FFFFF,\n 0x0000000000FFFFFF, 0x0000000001FFFFFF, 0x0000000003FFFFFF,\n 0x0000000007FFFFFF, 0x000000000FFFFFFF, 0x000000001FFFFFFF,\n 0x000000003FFFFFFF, 0x000000007FFFFFFF, 0x00000000FFFFFFFF,\n 0x00000001FFFFFFFF, 0x00000003FFFFFFFF, 0x00000007FFFFFFFF,\n 0x0000000FFFFFFFFF, 0x0000001FFFFFFFFF, 0x0000003FFFFFFFFF,\n 0x0000007FFFFFFFFF, 0x000000FFFFFFFFFF, 0x000001FFFFFFFFFF,\n 0x000003FFFFFFFFFF, 0x000007FFFFFFFFFF, 0x00000FFFFFFFFFFF,\n 0x00001FFFFFFFFFFF, 0x00003FFFFFFFFFFF, 0x00007FFFFFFFFFFF,\n 0x0000FFFFFFFFFFFF, 0x0001FFFFFFFFFFFF, 0x0003FFFFFFFFFFFF,\n 0x0007FFFFFFFFFFFF, 0x000FF" +
"FFFFFFFFFFF, 0x001FFFFFFFFFFFFF,\n 0x003FFFFFFFFFFFFF, 0x007FFFFFFFFFFFFF, 0x00FFFFFFFFFFFFFF,\n 0x01FFFFFFFFFFFFFF, 0x03FFFFFFFFFFFFFF, 0x07FFFFFFFFFFFFFF,\n 0x0FFFFFFFFFFFFFFF, 0x1FFFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFFF,\n 0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF,\n};\n\n// !! INSERT wuffs_base__status strings.\n\n// !! INSERT base/image-impl.c.\n\n#endif // !defined(WUFFS_CONFIG__MODULES) ||\n // defined(WUFFS_CONFIG__MODULE__BASE)\n\n#ifdef __cplusplus\n} // extern \"C\"\n#endif\n\n#ifdef __clang__\n#pragma clang diagnostic pop\n#endif\n\n#endif // WUFFS_IMPLEMENTATION\n\n// !! WUFFS MONOLITHIC RELEASE DISCARDS EVERYTHING BELOW.\n\n#endif // WUFFS_INCLUDE_GUARD__BASE\n" +
"#ifndef WUFFS_INCLUDE_GUARD__BASE\n#define WUFFS_INCLUDE_GUARD__BASE\n\n#if defined(WUFFS_IMPLEMENTATION) && !defined(WUFFS_CONFIG__MODULES)\n#define WUFFS_CONFIG__MODULES\n#define WUFFS_CONFIG__MODULE__BASE\n#endif\n\n// !! WUFFS MONOLITHIC RELEASE DISCARDS EVERYTHING ABOVE.\n\n// !! INSERT base/copyright\n\n#include <stdbool.h>\n#include <stdint.h>\n#include <string.h>\n\n// GCC does not warn for unused *static inline* functions, but clang does.\n#ifdef __clang__\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wunused-function\"\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// !! INSERT base/all-public.h.\n\n// !! INSERT InterfaceDeclarations.\n\n" +
"" +
"// ----------------\n\n#ifdef __cplusplus\n} // extern \"C\"\n#endif\n\n#ifdef __clang__\n#pragma clang diagnostic pop\n#endif\n\n// WUFFS C HEADER ENDS HERE.\n#ifdef WUFFS_IMPLEMENTATION\n\n// GCC does not warn for unused *static inline* functions, but clang does.\n#ifdef __clang__\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wunused-function\"\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// !! INSERT base/all-private.h.\n\n#if !defined(WUFFS_CONFIG__MODULES) || defined(WUFFS_CONFIG__MODULE__BASE)\n\nconst uint8_t wuffs_base__low_bits_mask__u8[9] = {\n 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF,\n};\n\nconst uint16_t wuffs_base__low_bits_mask__u16[17] = {\n 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF,\n 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF,\n};\n\nconst uint32_t wuffs_base__low_bits_mask__u32[33] = {\n 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000F, 0x0000001F,\n 0x0000003F, 0x0000007F, 0x000000FF, 0x000001FF, 0x000003FF, 0x000" +
"007FF,\n 0x00000FFF, 0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF, 0x0001FFFF,\n 0x0003FFFF, 0x0007FFFF, 0x000FFFFF, 0x001FFFFF, 0x003FFFFF, 0x007FFFFF,\n 0x00FFFFFF, 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF, 0x1FFFFFFF,\n 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF,\n};\n\nconst uint64_t wuffs_base__low_bits_mask__u64[65] = {\n 0x0000000000000000, 0x0000000000000001, 0x0000000000000003,\n 0x0000000000000007, 0x000000000000000F, 0x000000000000001F,\n 0x000000000000003F, 0x000000000000007F, 0x00000000000000FF,\n 0x00000000000001FF, 0x00000000000003FF, 0x00000000000007FF,\n 0x0000000000000FFF, 0x0000000000001FFF, 0x0000000000003FFF,\n 0x0000000000007FFF, 0x000000000000FFFF, 0x000000000001FFFF,\n 0x000000000003FFFF, 0x000000000007FFFF, 0x00000000000FFFFF,\n 0x00000000001FFFFF, 0x00000000003FFFFF, 0x00000000007FFFFF,\n 0x0000000000FFFFFF, 0x0000000001FFFFFF, 0x0000000003FFFFFF,\n 0x0000000007FFFFFF, 0x000000000FFFFFFF, 0x000000001FFFFFFF,\n 0x000000003FFFFFFF, 0x000000007FFFFFFF, 0x00000" +
"000FFFFFFFF,\n 0x00000001FFFFFFFF, 0x00000003FFFFFFFF, 0x00000007FFFFFFFF,\n 0x0000000FFFFFFFFF, 0x0000001FFFFFFFFF, 0x0000003FFFFFFFFF,\n 0x0000007FFFFFFFFF, 0x000000FFFFFFFFFF, 0x000001FFFFFFFFFF,\n 0x000003FFFFFFFFFF, 0x000007FFFFFFFFFF, 0x00000FFFFFFFFFFF,\n 0x00001FFFFFFFFFFF, 0x00003FFFFFFFFFFF, 0x00007FFFFFFFFFFF,\n 0x0000FFFFFFFFFFFF, 0x0001FFFFFFFFFFFF, 0x0003FFFFFFFFFFFF,\n 0x0007FFFFFFFFFFFF, 0x000FFFFFFFFFFFFF, 0x001FFFFFFFFFFFFF,\n 0x003FFFFFFFFFFFFF, 0x007FFFFFFFFFFFFF, 0x00FFFFFFFFFFFFFF,\n 0x01FFFFFFFFFFFFFF, 0x03FFFFFFFFFFFFFF, 0x07FFFFFFFFFFFFFF,\n 0x0FFFFFFFFFFFFFFF, 0x1FFFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFFF,\n 0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF,\n};\n\n// !! INSERT wuffs_base__status strings.\n\n// !! INSERT InterfaceDefinitions.\n\n// !! INSERT base/image-impl.c.\n\n#endif // !defined(WUFFS_CONFIG__MODULES) ||\n // defined(WUFFS_CONFIG__MODULE__BASE)\n\n#ifdef __cplusplus\n} // extern \"C\"\n#endif\n\n#ifdef __clang__\n#pragma clang diagnostic pop\n#endif\n\n#endif // WUFFS_IMP" +
"LEMENTATION\n\n// !! WUFFS MONOLITHIC RELEASE DISCARDS EVERYTHING BELOW.\n\n#endif // WUFFS_INCLUDE_GUARD__BASE\n" +
""
const baseImageImplC = "" +
"// ---------------- Images\n\nconst uint32_t wuffs_base__pixel_format__bits_per_channel[16] = {\n 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,\n 0x08, 0x0A, 0x0C, 0x10, 0x18, 0x20, 0x30, 0x40,\n};\n\nstatic uint64_t //\nwuffs_base__pixel_swizzler__copy_1_1(wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 dst_palette,\n wuffs_base__slice_u8 src) {\n return wuffs_base__slice_u8__copy_from_slice(dst, src);\n}\n\nstatic uint64_t //\nwuffs_base__pixel_swizzler__copy_3_1(wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 dst_palette,\n wuffs_base__slice_u8 src) {\n if (dst_palette.len != 1024) {\n return 0;\n }\n size_t dst_len3 = dst.len / 3;\n size_t len = dst_len3 < src.len ? dst_len3 : src.len;\n uint8_t* d = dst.ptr;\n uint8_t* s = src.ptr;\n size_t n = len;\n\n // N is the loop unroll count.\n const int N = 4;\n\n // The comparison in the while condition is \">\", not \">=\", be" +
"cause with \">=\",\n // the last 4-byte store could write past the end of the dst slice.\n //\n // Each 4-byte store writes one too many bytes, but a subsequent store will\n // overwrite that with the correct byte. There is always another store,\n // whether a 4-byte store in this loop or a 1-byte store in the next loop.\n while (n > N) {\n wuffs_base__store_u32le(\n d + (0 * 3),\n wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[0]) * 4)));\n wuffs_base__store_u32le(\n d + (1 * 3),\n wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[1]) * 4)));\n wuffs_base__store_u32le(\n d + (2 * 3),\n wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[2]) * 4)));\n wuffs_base__store_u32le(\n d + (3 * 3),\n wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[3]) * 4)));\n\n s += 1 * N;\n d += 3 * N;\n n -= (size_t)(1 * N);\n }\n\n while (n >= 1) {\n uint32_t color =\n wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[0]) * 4));\n d[0" +
"] = (uint8_t)(color >> 0);\n d[1] = (uint8_t)(color >> 8);\n d[2] = (uint8_t)(color >> 16);\n\n s += 1 * 1;\n d += 3 * 1;\n n -= (size_t)(1 * 1);\n }\n\n return len;\n}\nstatic uint64_t //\nwuffs_base__pixel_swizzler__copy_4_1(wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 dst_palette,\n wuffs_base__slice_u8 src) {\n if (dst_palette.len != 1024) {\n return 0;\n }\n size_t dst_len4 = dst.len / 4;\n size_t len = dst_len4 < src.len ? dst_len4 : src.len;\n uint8_t* d = dst.ptr;\n uint8_t* s = src.ptr;\n size_t n = len;\n\n // N is the loop unroll count.\n const int N = 4;\n\n while (n >= N) {\n wuffs_base__store_u32le(\n d + (0 * 4),\n wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[0]) * 4)));\n wuffs_base__store_u32le(\n d + (1 * 4),\n wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[1]) * 4)));\n wuffs_base__store_u32le(\n d + (2 * 4),\n wuffs_base__load_u32le(dst_palette.ptr + (" +
"(uint32_t)(s[2]) * 4)));\n wuffs_base__store_u32le(\n d + (3 * 4),\n wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[3]) * 4)));\n\n s += 1 * N;\n d += 4 * N;\n n -= (size_t)(1 * N);\n }\n\n while (n >= 1) {\n wuffs_base__store_u32le(\n d + (0 * 4),\n wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[0]) * 4)));\n\n s += 1 * 1;\n d += 4 * 1;\n n -= (size_t)(1 * 1);\n }\n\n return len;\n}\n\nstatic uint64_t //\nwuffs_base__pixel_swizzler__swap_rgbx_bgrx(wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 src) {\n size_t len4 = (dst.len < src.len ? dst.len : src.len) / 4;\n uint8_t* d = dst.ptr;\n uint8_t* s = src.ptr;\n\n size_t n = len4;\n while (n--) {\n uint8_t b0 = s[0];\n uint8_t b1 = s[1];\n uint8_t b2 = s[2];\n uint8_t b3 = s[3];\n d[0] = b2;\n d[1] = b1;\n d[2] = b0;\n d[3] = b3;\n s += 4;\n d += 4;\n }\n return len4 * 4;\n}\n\nwuffs_base__status //\nwuffs_base__pixel_swizzler__prepare(wuffs_base__pixel_s" +
"wizzler* p,\n wuffs_base__pixel_format dst_format,\n wuffs_base__slice_u8 dst_palette,\n wuffs_base__pixel_format src_format,\n wuffs_base__slice_u8 src_palette) {\n if (!p) {\n return wuffs_base__error__bad_receiver;\n }\n\n // TODO: support many more formats.\n\n uint64_t (*func)(wuffs_base__slice_u8 dst, wuffs_base__slice_u8 dst_palette,\n wuffs_base__slice_u8 src) = NULL;\n\n switch (src_format) {\n case WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_BINARY:\n switch (dst_format) {\n case WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_NONPREMUL:\n case WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_PREMUL:\n case WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_BINARY:\n if (wuffs_base__slice_u8__copy_from_slice(dst_palette, src_palette) !=\n 1024) {\n break;\n }\n func = wuffs_base__pixel_swizzler__copy_1_1;\n " +
" break;\n case WUFFS_BASE__PIXEL_FORMAT__BGR:\n if (wuffs_base__slice_u8__copy_from_slice(dst_palette, src_palette) !=\n 1024) {\n break;\n }\n func = wuffs_base__pixel_swizzler__copy_3_1;\n break;\n case WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL:\n case WUFFS_BASE__PIXEL_FORMAT__BGRA_PREMUL:\n case WUFFS_BASE__PIXEL_FORMAT__BGRA_BINARY:\n if (wuffs_base__slice_u8__copy_from_slice(dst_palette, src_palette) !=\n 1024) {\n break;\n }\n func = wuffs_base__pixel_swizzler__copy_4_1;\n break;\n case WUFFS_BASE__PIXEL_FORMAT__RGB:\n if (wuffs_base__pixel_swizzler__swap_rgbx_bgrx(dst_palette,\n src_palette) != 1024) {\n break;\n }\n func = wuffs_base__pixel_swizzler__copy_3_1;\n break;\n case WUFFS_BASE__PIXEL_FORMAT__RGBA_NONPREMUL:\n case WUFFS_BASE__PIXEL_FORMAT__RGBA_PR" +
"EMUL:\n case WUFFS_BASE__PIXEL_FORMAT__RGBA_BINARY:\n if (wuffs_base__pixel_swizzler__swap_rgbx_bgrx(dst_palette,\n src_palette) != 1024) {\n break;\n }\n func = wuffs_base__pixel_swizzler__copy_4_1;\n break;\n default:\n break;\n }\n break;\n\n default:\n break;\n }\n\n p->private_impl.func = func;\n return func ? NULL : wuffs_base__error__unsupported_option;\n}\n\nuint64_t //\nwuffs_base__pixel_swizzler__swizzle_interleaved(\n const wuffs_base__pixel_swizzler* p,\n wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 dst_palette,\n wuffs_base__slice_u8 src) {\n if (p && p->private_impl.func) {\n return (*(p->private_impl.func))(dst, dst_palette, src);\n }\n return 0;\n}\n" +
"// ---------------- Images\n\nconst uint32_t wuffs_base__pixel_format__bits_per_channel[16] = {\n 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,\n 0x08, 0x0A, 0x0C, 0x10, 0x18, 0x20, 0x30, 0x40,\n};\n\nstatic uint64_t //\nwuffs_base__pixel_swizzler__copy_1_1(wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 dst_palette,\n wuffs_base__slice_u8 src) {\n return wuffs_base__slice_u8__copy_from_slice(dst, src);\n}\n\nstatic uint64_t //\nwuffs_base__pixel_swizzler__xxx_index(wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 dst_palette,\n wuffs_base__slice_u8 src) {\n if (dst_palette.len != 1024) {\n return 0;\n }\n size_t dst_len3 = dst.len / 3;\n size_t len = dst_len3 < src.len ? dst_len3 : src.len;\n uint8_t* d = dst.ptr;\n uint8_t* s = src.ptr;\n size_t n = len;\n\n // N is the loop unroll count.\n const int N = 4;\n\n // The comparison in the while condition is \">\", not \">=\"," +
" because with \">=\",\n // the last 4-byte store could write past the end of the dst slice.\n //\n // Each 4-byte store writes one too many bytes, but a subsequent store will\n // overwrite that with the correct byte. There is always another store,\n // whether a 4-byte store in this loop or a 1-byte store in the next loop.\n while (n > N) {\n wuffs_base__store_u32le(\n d + (0 * 3),\n wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[0]) * 4)));\n wuffs_base__store_u32le(\n d + (1 * 3),\n wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[1]) * 4)));\n wuffs_base__store_u32le(\n d + (2 * 3),\n wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[2]) * 4)));\n wuffs_base__store_u32le(\n d + (3 * 3),\n wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[3]) * 4)));\n\n s += 1 * N;\n d += 3 * N;\n n -= (size_t)(1 * N);\n }\n\n while (n >= 1) {\n uint32_t color =\n wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[0]) * 4));\n " +
"d[0] = (uint8_t)(color >> 0);\n d[1] = (uint8_t)(color >> 8);\n d[2] = (uint8_t)(color >> 16);\n\n s += 1 * 1;\n d += 3 * 1;\n n -= (size_t)(1 * 1);\n }\n\n return len;\n}\n\nstatic uint64_t //\nwuffs_base__pixel_swizzler__xxxx_index(wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 dst_palette,\n wuffs_base__slice_u8 src) {\n if (dst_palette.len != 1024) {\n return 0;\n }\n size_t dst_len4 = dst.len / 4;\n size_t len = dst_len4 < src.len ? dst_len4 : src.len;\n uint8_t* d = dst.ptr;\n uint8_t* s = src.ptr;\n size_t n = len;\n\n // N is the loop unroll count.\n const int N = 4;\n\n while (n >= N) {\n wuffs_base__store_u32le(\n d + (0 * 4),\n wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[0]) * 4)));\n wuffs_base__store_u32le(\n d + (1 * 4),\n wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[1]) * 4)));\n wuffs_base__store_u32le(\n d + (2 * 4),\n wuffs_base__load_u32le(dst_palet" +
"te.ptr + ((uint32_t)(s[2]) * 4)));\n wuffs_base__store_u32le(\n d + (3 * 4),\n wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[3]) * 4)));\n\n s += 1 * N;\n d += 4 * N;\n n -= (size_t)(1 * N);\n }\n\n while (n >= 1) {\n wuffs_base__store_u32le(\n d + (0 * 4),\n wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[0]) * 4)));\n\n s += 1 * 1;\n d += 4 * 1;\n n -= (size_t)(1 * 1);\n }\n\n return len;\n}\n\nstatic uint64_t //\nwuffs_base__pixel_swizzler__xxxx_y(wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 dst_palette,\n wuffs_base__slice_u8 src) {\n size_t dst_len4 = dst.len / 4;\n size_t len = dst_len4 < src.len ? dst_len4 : src.len;\n uint8_t* d = dst.ptr;\n uint8_t* s = src.ptr;\n size_t n = len;\n\n // TODO: unroll.\n\n while (n >= 1) {\n wuffs_base__store_u32le(d + (0 * 4),\n 0xFF000000 | (0x010101 * (uint32_t)s[0]));\n\n s += 1 * 1;\n d += 4 * 1;\n n -= (size_t)(1 * " +
"1);\n }\n\n return len;\n}\n\nstatic uint64_t //\nwuffs_base__pixel_swizzler__swap_rgbx_bgrx(wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 src) {\n size_t len4 = (dst.len < src.len ? dst.len : src.len) / 4;\n uint8_t* d = dst.ptr;\n uint8_t* s = src.ptr;\n\n size_t n = len4;\n while (n--) {\n uint8_t b0 = s[0];\n uint8_t b1 = s[1];\n uint8_t b2 = s[2];\n uint8_t b3 = s[3];\n d[0] = b2;\n d[1] = b1;\n d[2] = b0;\n d[3] = b3;\n s += 4;\n d += 4;\n }\n return len4 * 4;\n}\n\nwuffs_base__status //\nwuffs_base__pixel_swizzler__prepare(wuffs_base__pixel_swizzler* p,\n wuffs_base__pixel_format dst_format,\n wuffs_base__slice_u8 dst_palette,\n wuffs_base__pixel_format src_format,\n wuffs_base__slice_u8 src_palette,\n wuffs_base__pixel_blend blend) {\n if (!p) {\n return wuffs_base__make_status" +
"(wuffs_base__error__bad_receiver);\n }\n\n // TODO: support many more formats.\n\n uint64_t (*func)(wuffs_base__slice_u8 dst, wuffs_base__slice_u8 dst_palette,\n wuffs_base__slice_u8 src) = NULL;\n\n switch (src_format.repr) {\n case WUFFS_BASE__PIXEL_FORMAT__Y:\n switch (dst_format.repr) {\n case WUFFS_BASE__PIXEL_FORMAT__BGR:\n case WUFFS_BASE__PIXEL_FORMAT__RGB:\n // TODO.\n break;\n case WUFFS_BASE__PIXEL_FORMAT__BGRX:\n case WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL:\n case WUFFS_BASE__PIXEL_FORMAT__BGRA_PREMUL:\n case WUFFS_BASE__PIXEL_FORMAT__BGRA_BINARY:\n case WUFFS_BASE__PIXEL_FORMAT__RGBX:\n case WUFFS_BASE__PIXEL_FORMAT__RGBA_NONPREMUL:\n case WUFFS_BASE__PIXEL_FORMAT__RGBA_PREMUL:\n case WUFFS_BASE__PIXEL_FORMAT__RGBA_BINARY:\n func = wuffs_base__pixel_swizzler__xxxx_y;\n break;\n default:\n break;\n }\n break;\n\n case WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_BINAR" +
"Y:\n switch (dst_format.repr) {\n case WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_NONPREMUL:\n case WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_PREMUL:\n case WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_BINARY:\n if (wuffs_base__slice_u8__copy_from_slice(dst_palette, src_palette) !=\n 1024) {\n break;\n }\n func = wuffs_base__pixel_swizzler__copy_1_1;\n break;\n case WUFFS_BASE__PIXEL_FORMAT__BGR:\n if (wuffs_base__slice_u8__copy_from_slice(dst_palette, src_palette) !=\n 1024) {\n break;\n }\n func = wuffs_base__pixel_swizzler__xxx_index;\n break;\n case WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL:\n case WUFFS_BASE__PIXEL_FORMAT__BGRA_PREMUL:\n case WUFFS_BASE__PIXEL_FORMAT__BGRA_BINARY:\n if (wuffs_base__slice_u8__copy_from_slice(dst_palette, src_palette) !=\n 1024) {\n break;\n }\n func = wuffs_base__pixel_swizzler__xxxx_in" +
"dex;\n break;\n case WUFFS_BASE__PIXEL_FORMAT__RGB:\n if (wuffs_base__pixel_swizzler__swap_rgbx_bgrx(dst_palette,\n src_palette) != 1024) {\n break;\n }\n func = wuffs_base__pixel_swizzler__xxx_index;\n break;\n case WUFFS_BASE__PIXEL_FORMAT__RGBA_NONPREMUL:\n case WUFFS_BASE__PIXEL_FORMAT__RGBA_PREMUL:\n case WUFFS_BASE__PIXEL_FORMAT__RGBA_BINARY:\n if (wuffs_base__pixel_swizzler__swap_rgbx_bgrx(dst_palette,\n src_palette) != 1024) {\n break;\n }\n func = wuffs_base__pixel_swizzler__xxxx_index;\n break;\n default:\n break;\n }\n break;\n\n default:\n break;\n }\n\n p->private_impl.func = func;\n return wuffs_base__make_status(func ? NULL\n : wuffs_base__error__unsupported_option);\n}\n\nuint64_t //\nwuffs_base__pixel_swizzler__s" +
"wizzle_interleaved(\n const wuffs_base__pixel_swizzler* p,\n wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 dst_palette,\n wuffs_base__slice_u8 src) {\n if (p && p->private_impl.func) {\n return (*(p->private_impl.func))(dst, dst_palette, src);\n }\n return 0;\n}\n" +
""
const baseCorePrivateH = "" +
"static inline wuffs_base__empty_struct //\nwuffs_base__ignore_status(wuffs_base__status z) {\n return wuffs_base__make_empty_struct();\n}\n\n// WUFFS_BASE__MAGIC is a magic number to check that initializers are called.\n// It's not foolproof, given C doesn't automatically zero memory before use,\n// but it should catch 99.99% of cases.\n//\n// Its (non-zero) value is arbitrary, based on md5sum(\"wuffs\").\n#define WUFFS_BASE__MAGIC ((uint32_t)0x3CCB6C71)\n\n// WUFFS_BASE__DISABLED is a magic number to indicate that a non-recoverable\n// error was previously encountered.\n//\n// Its (non-zero) value is arbitrary, based on md5sum(\"disabled\").\n#define WUFFS_BASE__DISABLED ((uint32_t)0x075AE3D2)\n\n// Denote intentional fallthroughs for -Wimplicit-fallthrough.\n//\n// The order matters here. Clang also defines \"__GNUC__\".\n#if defined(__clang__) && defined(__cplusplus) && (__cplusplus >= 201103L)\n#define WUFFS_BASE__FALLTHROUGH [[clang::fallthrough]]\n#elif !defined(__clang__) && defined(__GNUC__) && (__GNUC__ >= 7)\n#define WUFFS_BAS" +
"E__FALLTHROUGH __attribute__((fallthrough))\n#else\n#define WUFFS_BASE__FALLTHROUGH\n#endif\n\n// Use switch cases for coroutine suspension points, similar to the technique\n// in https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html\n//\n// We use trivial macros instead of an explicit assignment and case statement\n// so that clang-format doesn't get confused by the unusual \"case\"s.\n#define WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0 case 0:;\n#define WUFFS_BASE__COROUTINE_SUSPENSION_POINT(n) \\\n coro_susp_point = n; \\\n WUFFS_BASE__FALLTHROUGH; \\\n case n:;\n\n#define WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(n) \\\n if (!status) { \\\n goto ok; \\\n } else if (*status != '$') { \\\n goto exit; \\\n } \\\n coro_susp_point" +
"E__FALLTHROUGH __attribute__((fallthrough))\n#else\n#define WUFFS_BASE__FALLTHROUGH\n#endif\n\n// Use switch cases for coroutine suspension points, similar to the technique\n// in https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html\n//\n// We use trivial macros instead of an explicit assignment and case statement\n// so that clang-format doesn't get confused by the unusual \"case\"s.\n#define WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0 case 0:;\n#define WUFFS_BASE__COROUTINE_SUSPENSION_POINT(n) \\\n coro_susp_point = n; \\\n WUFFS_BASE__FALLTHROUGH; \\\n case n:;\n\n#define WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(n) \\\n if (!status.repr) { \\\n goto ok; \\\n } else if (*status.repr != '$') { \\\n goto exit; \\\n } \\\n coro_susp_point" +
" = n; \\\n goto suspend; \\\n case n:;\n\n// Clang also defines \"__GNUC__\".\n#if defined(__GNUC__)\n#define WUFFS_BASE__LIKELY(expr) (__builtin_expect(!!(expr), 1))\n#define WUFFS_BASE__UNLIKELY(expr) (__builtin_expect(!!(expr), 0))\n#else\n#define WUFFS_BASE__LIKELY(expr) (expr)\n#define WUFFS_BASE__UNLIKELY(expr) (expr)\n#endif\n\n// The helpers below are functions, instead of macros, because their arguments\n// can be an expression that we shouldn't evaluate more than once.\n//\n// They are static, so that linking multiple wuffs .o files won't complain about\n// duplicate function definitions.\n//\n// They are explicitly marked inline, even if modern compilers don't use the\n// inline attribute to guide optimizations such as inlining, to avoid the\n// -Wunused-function warning, and we like to compile with -Wall -Werror.\n\n" +
"" +
"// ---------------- Numeric Types\n\nstatic inline uint8_t //\nwuffs_base__load_u8be(uint8_t* p) {\n return p[0];\n}\n\nstatic inline uint16_t //\nwuffs_base__load_u16be(uint8_t* p) {\n return (uint16_t)(((uint16_t)(p[0]) << 8) | ((uint16_t)(p[1]) << 0));\n}\n\nstatic inline uint16_t //\nwuffs_base__load_u16le(uint8_t* p) {\n return (uint16_t)(((uint16_t)(p[0]) << 0) | ((uint16_t)(p[1]) << 8));\n}\n\nstatic inline uint32_t //\nwuffs_base__load_u24be(uint8_t* p) {\n return ((uint32_t)(p[0]) << 16) | ((uint32_t)(p[1]) << 8) |\n ((uint32_t)(p[2]) << 0);\n}\n\nstatic inline uint32_t //\nwuffs_base__load_u24le(uint8_t* p) {\n return ((uint32_t)(p[0]) << 0) | ((uint32_t)(p[1]) << 8) |\n ((uint32_t)(p[2]) << 16);\n}\n\nstatic inline uint32_t //\nwuffs_base__load_u32be(uint8_t* p) {\n return ((uint32_t)(p[0]) << 24) | ((uint32_t)(p[1]) << 16) |\n ((uint32_t)(p[2]) << 8) | ((uint32_t)(p[3]) << 0);\n}\n\nstatic inline uint32_t //\nwuffs_base__load_u32le(uint8_t* p) {\n return ((uint32_t)(p[0]) << 0) | ((uint32_t)(p[1]" +
@@ -55,21 +59,24 @@ const baseCorePrivateH = "" +
"// ---------------- Slices and Tables\n\n// wuffs_base__slice_u8__prefix returns up to the first up_to bytes of s.\nstatic inline wuffs_base__slice_u8 //\nwuffs_base__slice_u8__prefix(wuffs_base__slice_u8 s, uint64_t up_to) {\n if ((uint64_t)(s.len) > up_to) {\n s.len = up_to;\n }\n return s;\n}\n\n// wuffs_base__slice_u8__suffix returns up to the last up_to bytes of s.\nstatic inline wuffs_base__slice_u8 //\nwuffs_base__slice_u8__suffix(wuffs_base__slice_u8 s, uint64_t up_to) {\n if ((uint64_t)(s.len) > up_to) {\n s.ptr += (uint64_t)(s.len) - up_to;\n s.len = up_to;\n }\n return s;\n}\n\n// wuffs_base__slice_u8__copy_from_slice calls memmove(dst.ptr, src.ptr, len)\n// where len is the minimum of dst.len and src.len.\n//\n// Passing a wuffs_base__slice_u8 with all fields NULL or zero (a valid, empty\n// slice) is valid and results in a no-op.\nstatic inline uint64_t //\nwuffs_base__slice_u8__copy_from_slice(wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 src) {\n size_t len = dst.l" +
"en < src.len ? dst.len : src.len;\n if (len > 0) {\n memmove(dst.ptr, src.ptr, len);\n }\n return len;\n}\n\n" +
"" +
"// --------\n\nstatic inline wuffs_base__slice_u8 //\nwuffs_base__table_u8__row(wuffs_base__table_u8 t, uint32_t y) {\n if (y < t.height) {\n return wuffs_base__make_slice_u8(t.ptr + (t.stride * y), t.width);\n }\n return wuffs_base__make_slice_u8(NULL, 0);\n}\n\n" +
"// --------\n\nstatic inline wuffs_base__slice_u8 //\nwuffs_base__table_u8__row(wuffs_base__table_u8 t, uint32_t y) {\n if (y < t.height) {\n return wuffs_base__make_slice_u8(t.ptr + (t.stride * y), t.width);\n }\n return wuffs_base__make_slice_u8(NULL, 0);\n}\n\n " +
"" +
"// ---------------- Slices and Tables (Utility)\n\n#define wuffs_base__utility__empty_slice_u8 wuffs_base__empty_slice_u8\n" +
""
const baseCorePublicH = "" +
"// Wuffs assumes that:\n// - converting a uint32_t to a size_t will never overflow.\n// - converting a size_t to a uint64_t will never overflow.\n#ifdef __WORDSIZE\n#if (__WORDSIZE != 32) && (__WORDSIZE != 64)\n#error \"Wuffs requires a word size of either 32 or 64 bits\"\n#endif\n#endif\n\n// WUFFS_VERSION is the major.minor.patch version, as per https://semver.org/,\n// as a uint64_t. The major number is the high 32 bits. The minor number is the\n// middle 16 bits. The patch number is the low 16 bits. The pre-release label\n// and build metadata are part of the string representation (such as\n// \"1.2.3-beta+456.20181231\") but not the uint64_t representation.\n//\n// WUFFS_VERSION_PRE_RELEASE_LABEL (such as \"\", \"beta\" or \"rc.1\") being\n// non-empty denotes a developer preview, not a release version, and has no\n// backwards or forwards compatibility guarantees.\n//\n// WUFFS_VERSION_BUILD_METADATA_XXX, if non-zero, are the number of commits and\n// the last commit date in the repository used to build this library. Within\n// eac" +
"h major.minor branch, the commit count should increase monotonically.\n//\n// !! Some code generation programs can override WUFFS_VERSION.\n#define WUFFS_VERSION ((uint64_t)0)\n#define WUFFS_VERSION_MAJOR ((uint64_t)0)\n#define WUFFS_VERSION_MINOR ((uint64_t)0)\n#define WUFFS_VERSION_PATCH ((uint64_t)0)\n#define WUFFS_VERSION_PRE_RELEASE_LABEL \"work.in.progress\"\n#define WUFFS_VERSION_BUILD_METADATA_COMMIT_COUNT 0\n#define WUFFS_VERSION_BUILD_METADATA_COMMIT_DATE 0\n#define WUFFS_VERSION_STRING \"0.0.0+0.00000000\"\n\n// Define WUFFS_CONFIG__STATIC_FUNCTIONS to make all of Wuffs' functions have\n// static storage. The motivation is discussed in the \"ALLOW STATIC\n// IMPLEMENTATION\" section of\n// https://raw.githubusercontent.com/nothings/stb/master/docs/stb_howto.txt\n#ifdef WUFFS_CONFIG__STATIC_FUNCTIONS\n#define WUFFS_BASE__MAYBE_STATIC static\n#else\n#define WUFFS_BASE__MAYBE_STATIC\n#endif\n\n#if defined(__clang__)\n#define WUFFS_BASE__POTENTIALLY_UNUSED_FIELD __attribute__((unused))\n#else\n#define WUFFS_BASE__POTENTIALLY_UNUSED_" +
"FIELD\n#endif\n\n// Clang also defines \"__GNUC__\".\n#if defined(__GNUC__)\n#define WUFFS_BASE__POTENTIALLY_UNUSED __attribute__((unused))\n#define WUFFS_BASE__WARN_UNUSED_RESULT __attribute__((warn_unused_result))\n#else\n#define WUFFS_BASE__POTENTIALLY_UNUSED\n#define WUFFS_BASE__WARN_UNUSED_RESULT\n#endif\n\n// Flags for wuffs_foo__bar__initialize functions.\n\n#define WUFFS_INITIALIZE__DEFAULT_OPTIONS ((uint32_t)0x00000000)\n\n// WUFFS_INITIALIZE__ALREADY_ZEROED means that the \"self\" receiver struct value\n// has already been set to all zeroes.\n#define WUFFS_INITIALIZE__ALREADY_ZEROED ((uint32_t)0x00000001)\n\n// WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED means that, absent\n// WUFFS_INITIALIZE__ALREADY_ZEROED, only some of the \"self\" receiver struct\n// value will be set to all zeroes. Internal buffers, which tend to be a large\n// proportion of the struct's size, will be left uninitialized. Internal means\n// that the buffer is contained by the receiver struct, as opposed to being\n// passed as a separately allocate" +
"d \"work buffer\".\n//\n// For more detail, see:\n// https://github.com/google/wuffs/blob/master/doc/note/initialization.md\n#define WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED \\\n ((uint32_t)0x00000002)\n\n" +
"// ---------------- Fundamentals\n\n// WUFFS_VERSION is the major.minor.patch version, as per https://semver.org/,\n// as a uint64_t. The major number is the high 32 bits. The minor number is the\n// middle 16 bits. The patch number is the low 16 bits. The pre-release label\n// and build metadata are part of the string representation (such as\n// \"1.2.3-beta+456.20181231\") but not the uint64_t representation.\n//\n// WUFFS_VERSION_PRE_RELEASE_LABEL (such as \"\", \"beta\" or \"rc.1\") being\n// non-empty denotes a developer preview, not a release version, and has no\n// backwards or forwards compatibility guarantees.\n//\n// WUFFS_VERSION_BUILD_METADATA_XXX, if non-zero, are the number of commits and\n// the last commit date in the repository used to build this library. Within\n// each major.minor branch, the commit count should increase monotonically.\n//\n// !! Some code generation programs can override WUFFS_VERSION.\n#define WUFFS_VERSION ((uint64_t)0)\n#define WUFFS_VERSION_MAJOR ((uint64_t)0)\n#define WUFFS_VERSION_MINOR ((uint" +
"64_t)0)\n#define WUFFS_VERSION_PATCH ((uint64_t)0)\n#define WUFFS_VERSION_PRE_RELEASE_LABEL \"work.in.progress\"\n#define WUFFS_VERSION_BUILD_METADATA_COMMIT_COUNT 0\n#define WUFFS_VERSION_BUILD_METADATA_COMMIT_DATE 0\n#define WUFFS_VERSION_STRING \"0.0.0+0.00000000\"\n\n// Define WUFFS_CONFIG__STATIC_FUNCTIONS to make all of Wuffs' functions have\n// static storage. The motivation is discussed in the \"ALLOW STATIC\n// IMPLEMENTATION\" section of\n// https://raw.githubusercontent.com/nothings/stb/master/docs/stb_howto.txt\n#ifdef WUFFS_CONFIG__STATIC_FUNCTIONS\n#define WUFFS_BASE__MAYBE_STATIC static\n#else\n#define WUFFS_BASE__MAYBE_STATIC\n#endif\n\n" +
"" +
"// --------\n\n// Wuffs assumes that:\n// - converting a uint32_t to a size_t will never overflow.\n// - converting a size_t to a uint64_t will never overflow.\n#ifdef __WORDSIZE\n#if (__WORDSIZE != 32) && (__WORDSIZE != 64)\n#error \"Wuffs requires a word size of either 32 or 64 bits\"\n#endif\n#endif\n\n#if defined(__clang__)\n#define WUFFS_BASE__POTENTIALLY_UNUSED_FIELD __attribute__((unused))\n#else\n#define WUFFS_BASE__POTENTIALLY_UNUSED_FIELD\n#endif\n\n// Clang also defines \"__GNUC__\".\n#if defined(__GNUC__)\n#define WUFFS_BASE__POTENTIALLY_UNUSED __attribute__((unused))\n#define WUFFS_BASE__WARN_UNUSED_RESULT __attribute__((warn_unused_result))\n#else\n#define WUFFS_BASE__POTENTIALLY_UNUSED\n#define WUFFS_BASE__WARN_UNUSED_RESULT\n#endif\n\n// Flags for wuffs_foo__bar__initialize functions.\n\n#define WUFFS_INITIALIZE__DEFAULT_OPTIONS ((uint32_t)0x00000000)\n\n// WUFFS_INITIALIZE__ALREADY_ZEROED means that the \"self\" receiver struct value\n// has already been set to all zeroes.\n#define WUFFS_INITIALIZE__ALREADY_ZEROED ((uint32_t)0x" +
"00000001)\n\n// WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED means that, absent\n// WUFFS_INITIALIZE__ALREADY_ZEROED, only some of the \"self\" receiver struct\n// value will be set to all zeroes. Internal buffers, which tend to be a large\n// proportion of the struct's size, will be left uninitialized. Internal means\n// that the buffer is contained by the receiver struct, as opposed to being\n// passed as a separately allocated \"work buffer\".\n//\n// For more detail, see:\n// https://github.com/google/wuffs/blob/master/doc/note/initialization.md\n#define WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED \\\n ((uint32_t)0x00000002)\n\n" +
"" +
"// --------\n\n// wuffs_base__empty_struct is used when a Wuffs function returns an empty\n// struct. In C, if a function f returns void, you can't say \"x = f()\", but in\n// Wuffs, if a function g returns empty, you can say \"y = g()\".\ntypedef struct {\n // private_impl is a placeholder field. It isn't explicitly used, except that\n // without it, the sizeof a struct with no fields can differ across C/C++\n // compilers, and it is undefined behavior in C99. For example, gcc says that\n // the sizeof an empty struct is 0, and g++ says that it is 1. This leads to\n // ABI incompatibility if a Wuffs .c file is processed by one compiler and\n // its .h file with another compiler.\n //\n // Instead, we explicitly insert an otherwise unused field, so that the\n // sizeof this struct is always 1.\n uint8_t private_impl;\n} wuffs_base__empty_struct;\n\nstatic inline wuffs_base__empty_struct //\nwuffs_base__make_empty_struct() {\n wuffs_base__empty_struct ret;\n ret.private_impl = 0;\n return ret;\n}\n\n// wuffs_base__utility is" +
" a placeholder receiver type. It enables what Java\n// calls static methods, as opposed to regular methods.\ntypedef struct {\n // private_impl is a placeholder field. It isn't explicitly used, except that\n // without it, the sizeof a struct with no fields can differ across C/C++\n // compilers, and it is undefined behavior in C99. For example, gcc says that\n // the sizeof an empty struct is 0, and g++ says that it is 1. This leads to\n // ABI incompatibility if a Wuffs .c file is processed by one compiler and\n // its .h file with another compiler.\n //\n // Instead, we explicitly insert an otherwise unused field, so that the\n // sizeof this struct is always 1.\n uint8_t private_impl;\n} wuffs_base__utility;\n\n" +
" a placeholder receiver type. It enables what Java\n// calls static methods, as opposed to regular methods.\ntypedef struct {\n // private_impl is a placeholder field. It isn't explicitly used, except that\n // without it, the sizeof a struct with no fields can differ across C/C++\n // compilers, and it is undefined behavior in C99. For example, gcc says that\n // the sizeof an empty struct is 0, and g++ says that it is 1. This leads to\n // ABI incompatibility if a Wuffs .c file is processed by one compiler and\n // its .h file with another compiler.\n //\n // Instead, we explicitly insert an otherwise unused field, so that the\n // sizeof this struct is always 1.\n uint8_t private_impl;\n} wuffs_base__utility;\n\ntypedef struct {\n const char* vtable_name;\n const void* function_pointers;\n} wuffs_base__vtable;\n\n" +
"" +
"// --------\n\n// See https://github.com/google/wuffs/blob/master/doc/note/statuses.md\ntypedef const char* wuffs_base__status;\n\n// !! INSERT wuffs_base__status names.\n\nstatic inline bool //\nwuffs_base__status__is_complete(wuffs_base__status z) {\n return (z == NULL) || ((*z != '$') && (*z != '#'));\n}\n\nstatic inline bool //\nwuffs_base__status__is_error(wuffs_base__status z) {\n return z && (*z == '#');\n}\n\nstatic inline bool //\nwuffs_base__status__is_ok(wuffs_base__status z) {\n return z == NULL;\n}\n\nstatic inline bool //\nwuffs_base__status__is_suspension(wuffs_base__status z) {\n return z && (*z == '$');\n}\n\nstatic inline bool //\nwuffs_base__status__is_warning(wuffs_base__status z) {\n return z && (*z != '$') && (*z != '#');\n}\n\n// wuffs_base__status__message strips the leading '$', '#' or '@'.\nstatic inline const char* //\nwuffs_base__status__message(wuffs_base__status z) {\n if (z) {\n if ((*z == '$') || (*z == '#') || (*z == '@')) {\n return z + 1;\n }\n }\n return z;\n}\n\n" +
"// --------\n\n// See https://github.com/google/wuffs/blob/master/doc/note/statuses.md\ntypedef struct {\n const char* repr;\n\n#ifdef __cplusplus\n inline bool is_complete() const;\n inline bool is_error() const;\n inline bool is_note() const;\n inline bool is_ok() const;\n inline bool is_suspension() const;\n inline const char* message() const;\n#endif // __cplusplus\n\n} wuffs_base__status;\n\n// !! INSERT wuffs_base__status names.\n\nstatic inline wuffs_base__status //\nwuffs_base__make_status(const char* repr) {\n wuffs_base__status z;\n z.repr = repr;\n return z;\n}\n\nstatic inline bool //\nwuffs_base__status__is_complete(const wuffs_base__status* z) {\n return (z->repr == NULL) || ((*z->repr != '$') && (*z->repr != '#'));\n}\n\nstatic inline bool //\nwuffs_base__status__is_error(const wuffs_base__status* z) {\n return z->repr && (*z->repr == '#');\n}\n\nstatic inline bool //\nwuffs_base__status__is_note(const wuffs_base__status* z) {\n return z->repr && (*z->repr != '$') && (*z->repr != '#');\n}\n\nstatic inline bool //\nwu" +
"ffs_base__status__is_ok(const wuffs_base__status* z) {\n return z->repr == NULL;\n}\n\nstatic inline bool //\nwuffs_base__status__is_suspension(const wuffs_base__status* z) {\n return z->repr && (*z->repr == '$');\n}\n\n// wuffs_base__status__message strips the leading '$', '#' or '@'.\nstatic inline const char* //\nwuffs_base__status__message(const wuffs_base__status* z) {\n if (z->repr) {\n if ((*z->repr == '$') || (*z->repr == '#') || (*z->repr == '@')) {\n return z->repr + 1;\n }\n }\n return z->repr;\n}\n\n#ifdef __cplusplus\n\ninline bool //\nwuffs_base__status::is_complete() const {\n return wuffs_base__status__is_complete(this);\n}\n\ninline bool //\nwuffs_base__status::is_error() const {\n return wuffs_base__status__is_error(this);\n}\n\ninline bool //\nwuffs_base__status::is_note() const {\n return wuffs_base__status__is_note(this);\n}\n\ninline bool //\nwuffs_base__status::is_ok() const {\n return wuffs_base__status__is_ok(this);\n}\n\ninline bool //\nwuffs_base__status::is_suspension() const {\n return wuffs_base" +
"__status__is_suspension(this);\n}\n\ninline const char* //\nwuffs_base__status::message() const {\n return wuffs_base__status__message(this);\n}\n\n#endif // __cplusplus\n\n" +
"" +
"// --------\n\n// FourCC constants.\n\n// !! INSERT FourCCs.\n\n" +
"" +
@@ -97,68 +104,74 @@ const baseMemoryPublicH = "" +
""
const baseImagePrivateH = "" +
"// ---------------- Images\n" +
"// ---------------- Images\n\n" +
"" +
"// ---------------- Images (Utility)\n\n#define wuffs_base__utility__make_pixel_format wuffs_base__make_pixel_format\n" +
""
const baseImagePublicH = "" +
"// ---------------- Images\n\n// wuffs_base__color_u32_argb_premul is an 8 bit per channel premultiplied\n// Alpha, Red, Green, Blue color, as a uint32_t value. It is in word order, not\n// byte order: its value is always 0xAARRGGBB, regardless of endianness.\ntypedef uint32_t wuffs_base__color_u32_argb_premul;\n\n" +
"" +
"// --------\n\n// wuffs_base__pixel_format encodes the format of the bytes that constitute an\n// image frame's pixel data.\n//\n// See https://github.com/google/wuffs/blob/master/doc/note/pixel-formats.md\n//\n// Do not manipulate its bits directly; they are private implementation\n// details. Use methods such as wuffs_base__pixel_format__num_planes instead.\ntypedef uint32_t wuffs_base__pixel_format;\n\n// Common 8-bit-depth pixel formats. This list is not exhaustive; not all valid\n// wuffs_base__pixel_format values are present.\n\n#define WUFFS_BASE__PIXEL_FORMAT__INVALID ((wuffs_base__pixel_format)0x00000000)\n\n#define WUFFS_BASE__PIXEL_FORMAT__A ((wuffs_base__pixel_format)0x02000008)\n\n#define WUFFS_BASE__PIXEL_FORMAT__Y ((wuffs_base__pixel_format)0x10000008)\n#define WUFFS_BASE__PIXEL_FORMAT__YA_NONPREMUL \\\n ((wuffs_base__pixel_format)0x15000008)\n#define WUFFS_BASE__PIXEL_FORMAT__YA_PREMUL \\\n ((wuffs_base__pixel_format)0x16000008)\n\n#define WUFFS_BASE__PIXEL_FORMAT__YCBCR ((wuffs_base__pixel_format)0x20020888)\n#define" +
" WUFFS_BASE__PIXEL_FORMAT__YCBCRK ((wuffs_base__pixel_format)0x21038888)\n#define WUFFS_BASE__PIXEL_FORMAT__YCBCRA_NONPREMUL \\\n ((wuffs_base__pixel_format)0x25038888)\n\n#define WUFFS_BASE__PIXEL_FORMAT__YCOCG ((wuffs_base__pixel_format)0x30020888)\n#define WUFFS_BASE__PIXEL_FORMAT__YCOCGK ((wuffs_base__pixel_format)0x31038888)\n#define WUFFS_BASE__PIXEL_FORMAT__YCOCGA_NONPREMUL \\\n ((wuffs_base__pixel_format)0x35038888)\n\n#define WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_NONPREMUL \\\n ((wuffs_base__pixel_format)0x45040008)\n#define WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_PREMUL \\\n ((wuffs_base__pixel_format)0x46040008)\n#define WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_BINARY \\\n ((wuffs_base__pixel_format)0x47040008)\n\n#define WUFFS_BASE__PIXEL_FORMAT__BGR ((wuffs_base__pixel_format)0x40000888)\n#define WUFFS_BASE__PIXEL_FORMAT__BGRX ((wuffs_base__pixel_format)0x41008888)\n#define WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL \\\n ((wuffs_base__pixel_format)0x45008888)\n#define WUFFS_BASE__PIXEL_FORMAT__BGRA_PREMUL \\\n ((wuffs" +
"_base__pixel_format)0x46008888)\n#define WUFFS_BASE__PIXEL_FORMAT__BGRA_BINARY \\\n ((wuffs_base__pixel_format)0x47008888)\n\n#define WUFFS_BASE__PIXEL_FORMAT__RGB ((wuffs_base__pixel_format)0x50000888)\n#define WUFFS_BASE__PIXEL_FORMAT__RGBX ((wuffs_base__pixel_format)0x51008888)\n#define WUFFS_BASE__PIXEL_FORMAT__RGBA_NONPREMUL \\\n ((wuffs_base__pixel_format)0x55008888)\n#define WUFFS_BASE__PIXEL_FORMAT__RGBA_PREMUL \\\n ((wuffs_base__pixel_format)0x56008888)\n#define WUFFS_BASE__PIXEL_FORMAT__RGBA_BINARY \\\n ((wuffs_base__pixel_format)0x57008888)\n\n#define WUFFS_BASE__PIXEL_FORMAT__CMY ((wuffs_base__pixel_format)0x60020888)\n#define WUFFS_BASE__PIXEL_FORMAT__CMYK ((wuffs_base__pixel_format)0x61038888)\n\nextern const uint32_t wuffs_base__pixel_format__bits_per_channel[16];\n\nstatic inline bool //\nwuffs_base__pixel_format__is_valid(wuffs_base__pixel_format f) {\n return f != 0;\n}\n\n// wuffs_base__pixel_format__bits_per_pixel returns the number of bits per\n// pixel for interleaved pixel formats, and returns 0 for planar p" +
"ixel formats.\nstatic inline uint32_t //\nwuffs_base__pixel_format__bits_per_pixel(wuffs_base__pixel_format f) {\n if (((f >> 16) & 0x03) != 0) {\n return 0;\n }\n return wuffs_base__pixel_format__bits_per_channel[0x0F & (f >> 0)] +\n wuffs_base__pixel_format__bits_per_channel[0x0F & (f >> 4)] +\n wuffs_base__pixel_format__bits_per_channel[0x0F & (f >> 8)] +\n wuffs_base__pixel_format__bits_per_channel[0x0F & (f >> 12)];\n}\n\nstatic inline bool //\nwuffs_base__pixel_format__is_indexed(wuffs_base__pixel_format f) {\n return (f >> 18) & 0x01;\n}\n\nstatic inline bool //\nwuffs_base__pixel_format__is_interleaved(wuffs_base__pixel_format f) {\n return ((f >> 16) & 0x03) == 0;\n}\n\nstatic inline bool //\nwuffs_base__pixel_format__is_planar(wuffs_base__pixel_format f) {\n return ((f >> 16) & 0x03) != 0;\n}\n\nstatic inline uint32_t //\nwuffs_base__pixel_format__num_planes(wuffs_base__pixel_format f) {\n return ((f >> 16) & 0x03) + 1;\n}\n\n#define WUFFS_BASE__PIXEL_FORMAT__NUM_PLANES_MAX 4\n\n#define WUFFS_B" +
"ASE__PIXEL_FORMAT__INDEXED__INDEX_PLANE 0\n#define WUFFS_BASE__PIXEL_FORMAT__INDEXED__COLOR_PLANE 3\n\n" +
"// --------\n\ntypedef uint8_t wuffs_base__pixel_blend;\n\n// wuffs_base__pixel_blend encodes how to blend source and destination pixels,\n// accounting for transparency. It encompasses the Porter-Duff compositing\n// operators as well as the other blending modes defined by PDF.\n//\n// TODO: implement the other modes.\n#define WUFFS_BASE__PIXEL_BLEND__SRC ((wuffs_base__pixel_blend)0)\n\n" +
"" +
"// --------\n\n// wuffs_base__pixel_subsampling encodes whether sample values cover one pixel\n// or cover multiple pixels.\n//\n// See https://github.com/google/wuffs/blob/master/doc/note/pixel-subsampling.md\n//\n// Do not manipulate its bits directly; they are private implementation\n// details. Use methods such as wuffs_base__pixel_subsampling__bias_x instead.\ntypedef uint32_t wuffs_base__pixel_subsampling;\n\n#define WUFFS_BASE__PIXEL_SUBSAMPLING__NONE ((wuffs_base__pixel_subsampling)0)\n\n#define WUFFS_BASE__PIXEL_SUBSAMPLING__444 \\\n ((wuffs_base__pixel_subsampling)0x000000)\n#define WUFFS_BASE__PIXEL_SUBSAMPLING__440 \\\n ((wuffs_base__pixel_subsampling)0x010100)\n#define WUFFS_BASE__PIXEL_SUBSAMPLING__422 \\\n ((wuffs_base__pixel_subsampling)0x101000)\n#define WUFFS_BASE__PIXEL_SUBSAMPLING__420 \\\n ((wuffs_base__pixel_subsampling)0x111100)\n#define WUFFS_BASE__PIXEL_SUBSAMPLING__411 \\\n ((wuffs_base__pixel_subsampling)0x303000)\n#define WUFFS_BASE__PIXEL_SUBSAMPLING__410 \\\n ((wuffs_base__pixel_subsampling)0x313100)\n\ns" +
"tatic inline uint32_t //\nwuffs_base__pixel_subsampling__bias_x(wuffs_base__pixel_subsampling s,\n uint32_t plane) {\n uint32_t shift = ((plane & 0x03) * 8) + 6;\n return (s >> shift) & 0x03;\n}\n\nstatic inline uint32_t //\nwuffs_base__pixel_subsampling__denominator_x(wuffs_base__pixel_subsampling s,\n uint32_t plane) {\n uint32_t shift = ((plane & 0x03) * 8) + 4;\n return ((s >> shift) & 0x03) + 1;\n}\n\nstatic inline uint32_t //\nwuffs_base__pixel_subsampling__bias_y(wuffs_base__pixel_subsampling s,\n uint32_t plane) {\n uint32_t shift = ((plane & 0x03) * 8) + 2;\n return (s >> shift) & 0x03;\n}\n\nstatic inline uint32_t //\nwuffs_base__pixel_subsampling__denominator_y(wuffs_base__pixel_subsampling s,\n uint32_t plane) {\n uint32_t shift = ((plane & 0x03) * 8) + 0;\n return ((s >> shift) & 0x03) + 1;\n}\n\n" +
"// --------\n\n// wuffs_base__pixel_format encodes the format of the bytes that constitute an\n// image frame's pixel data.\n//\n// See https://github.com/google/wuffs/blob/master/doc/note/pixel-formats.md\n//\n// Do not manipulate its bits directly; they are private implementation\n// details. Use methods such as wuffs_base__pixel_format__num_planes instead.\ntypedef struct {\n uint32_t repr;\n\n#ifdef __cplusplus\n inline bool is_valid() const;\n inline uint32_t bits_per_pixel() const;\n inline bool is_indexed() const;\n inline bool is_interleaved() const;\n inline bool is_planar() const;\n inline uint32_t num_planes() const;\n#endif // __cplusplus\n\n} wuffs_base__pixel_format;\n\nstatic inline wuffs_base__pixel_format //\nwuffs_base__make_pixel_format(uint32_t repr) {\n wuffs_base__pixel_format f;\n f.repr = repr;\n return f;\n}\n\n // Common 8-bit-depth pixel formats. This list is not exhaustive; not all\n // valid wuffs_base__pixel_format values are present.\n\n#define WUFFS_BASE__PIXEL_FORMAT__INVALID 0x00000000\n\n#define" +
" WUFFS_BASE__PIXEL_FORMAT__A 0x02000008\n\n#define WUFFS_BASE__PIXEL_FORMAT__Y 0x10000008\n#define WUFFS_BASE__PIXEL_FORMAT__YA_NONPREMUL 0x15000008\n#define WUFFS_BASE__PIXEL_FORMAT__YA_PREMUL 0x16000008\n\n#define WUFFS_BASE__PIXEL_FORMAT__YCBCR 0x20020888\n#define WUFFS_BASE__PIXEL_FORMAT__YCBCRK 0x21038888\n#define WUFFS_BASE__PIXEL_FORMAT__YCBCRA_NONPREMUL 0x25038888\n\n#define WUFFS_BASE__PIXEL_FORMAT__YCOCG 0x30020888\n#define WUFFS_BASE__PIXEL_FORMAT__YCOCGK 0x31038888\n#define WUFFS_BASE__PIXEL_FORMAT__YCOCGA_NONPREMUL 0x35038888\n\n#define WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_NONPREMUL 0x45040008\n#define WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_PREMUL 0x46040008\n#define WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_BINARY 0x47040008\n\n#define WUFFS_BASE__PIXEL_FORMAT__BGR 0x40000888\n#define WUFFS_BASE__PIXEL_FORMAT__BGRX 0x41008888\n#define WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL 0x45008888\n#define WUFFS_BASE__PIXEL_FORMAT__BGRA_PREMUL 0x46008888\n#define WUFFS_BASE__PIXEL_FORMAT__BGRA_BINARY 0x47008888\n\n#define WUFFS_" +
"BASE__PIXEL_FORMAT__RGB 0x50000888\n#define WUFFS_BASE__PIXEL_FORMAT__RGBX 0x51008888\n#define WUFFS_BASE__PIXEL_FORMAT__RGBA_NONPREMUL 0x55008888\n#define WUFFS_BASE__PIXEL_FORMAT__RGBA_PREMUL 0x56008888\n#define WUFFS_BASE__PIXEL_FORMAT__RGBA_BINARY 0x57008888\n\n#define WUFFS_BASE__PIXEL_FORMAT__CMY 0x60020888\n#define WUFFS_BASE__PIXEL_FORMAT__CMYK 0x61038888\n\nextern const uint32_t wuffs_base__pixel_format__bits_per_channel[16];\n\nstatic inline bool //\nwuffs_base__pixel_format__is_valid(const wuffs_base__pixel_format* f) {\n return f->repr != 0;\n}\n\n// wuffs_base__pixel_format__bits_per_pixel returns the number of bits per\n// pixel for interleaved pixel formats, and returns 0 for planar pixel formats.\nstatic inline uint32_t //\nwuffs_base__pixel_format__bits_per_pixel(const wuffs_base__pixel_format* f) {\n if (((f->repr >> 16) & 0x03) != 0) {\n return 0;\n }\n return wuffs_base__pixel_format__bits_per_channel[0x0F & (f->repr >> 0)] +\n wuffs_base__pixel_format__bits_per_channel[0x0F & (f->repr >> 4)] +\n " +
" wuffs_base__pixel_format__bits_per_channel[0x0F & (f->repr >> 8)] +\n wuffs_base__pixel_format__bits_per_channel[0x0F & (f->repr >> 12)];\n}\n\nstatic inline bool //\nwuffs_base__pixel_format__is_indexed(const wuffs_base__pixel_format* f) {\n return (f->repr >> 18) & 0x01;\n}\n\nstatic inline bool //\nwuffs_base__pixel_format__is_interleaved(const wuffs_base__pixel_format* f) {\n return ((f->repr >> 16) & 0x03) == 0;\n}\n\nstatic inline bool //\nwuffs_base__pixel_format__is_planar(const wuffs_base__pixel_format* f) {\n return ((f->repr >> 16) & 0x03) != 0;\n}\n\nstatic inline uint32_t //\nwuffs_base__pixel_format__num_planes(const wuffs_base__pixel_format* f) {\n return ((f->repr >> 16) & 0x03) + 1;\n}\n\n#define WUFFS_BASE__PIXEL_FORMAT__NUM_PLANES_MAX 4\n\n#define WUFFS_BASE__PIXEL_FORMAT__INDEXED__INDEX_PLANE 0\n#define WUFFS_BASE__PIXEL_FORMAT__INDEXED__COLOR_PLANE 3\n\n#ifdef __cplusplus\n\ninline bool //\nwuffs_base__pixel_format::is_valid() const {\n return wuffs_base__pixel_format__is_valid(this);\n}\n\ninline " +
"uint32_t //\nwuffs_base__pixel_format::bits_per_pixel() const {\n return wuffs_base__pixel_format__bits_per_pixel(this);\n}\n\ninline bool //\nwuffs_base__pixel_format::is_indexed() const {\n return wuffs_base__pixel_format__is_indexed(this);\n}\n\ninline bool //\nwuffs_base__pixel_format::is_interleaved() const {\n return wuffs_base__pixel_format__is_interleaved(this);\n}\n\ninline bool //\nwuffs_base__pixel_format::is_planar() const {\n return wuffs_base__pixel_format__is_planar(this);\n}\n\ninline uint32_t //\nwuffs_base__pixel_format::num_planes() const {\n return wuffs_base__pixel_format__num_planes(this);\n}\n\n#endif // __cplusplus\n\n" +
"" +
"// --------\n\ntypedef struct {\n // Do not access the private_impl's fields directly. There is no API/ABI\n // compatibility or safety guarantee if you do so.\n struct {\n wuffs_base__pixel_format pixfmt;\n wuffs_base__pixel_subsampling pixsub;\n uint32_t width;\n uint32_t height;\n } private_impl;\n\n#ifdef __cplusplus\n inline void set(wuffs_base__pixel_format pixfmt,\n wuffs_base__pixel_subsampling pixsub,\n uint32_t width,\n uint32_t height);\n inline void invalidate();\n inline bool is_valid() const;\n inline wuffs_base__pixel_format pixel_format() const;\n inline wuffs_base__pixel_subsampling pixel_subsampling() const;\n inline wuffs_base__rect_ie_u32 bounds() const;\n inline uint32_t width() const;\n inline uint32_t height() const;\n inline uint64_t pixbuf_len() const;\n#endif // __cplusplus\n\n} wuffs_base__pixel_config;\n\nstatic inline wuffs_base__pixel_config //\nwuffs_base__null_pixel_config() {\n wuffs_base__pixel_config ret;\n ret.private_impl.pix" +
"fmt = 0;\n ret.private_impl.pixsub = 0;\n ret.private_impl.width = 0;\n ret.private_impl.height = 0;\n return ret;\n}\n\n// TODO: Should this function return bool? An error type?\nstatic inline void //\nwuffs_base__pixel_config__set(wuffs_base__pixel_config* c,\n wuffs_base__pixel_format pixfmt,\n wuffs_base__pixel_subsampling pixsub,\n uint32_t width,\n uint32_t height) {\n if (!c) {\n return;\n }\n if (pixfmt) {\n uint64_t wh = ((uint64_t)width) * ((uint64_t)height);\n // TODO: handle things other than 1 byte per pixel.\n if (wh <= ((uint64_t)SIZE_MAX)) {\n c->private_impl.pixfmt = pixfmt;\n c->private_impl.pixsub = pixsub;\n c->private_impl.width = width;\n c->private_impl.height = height;\n return;\n }\n }\n\n c->private_impl.pixfmt = 0;\n c->private_impl.pixsub = 0;\n c->private_impl.width = 0;\n c->private_impl.height = 0;\n}\n\nstatic inline void //\nwuffs_base__pixel_co" +
"nfig__invalidate(wuffs_base__pixel_config* c) {\n if (c) {\n c->private_impl.pixfmt = 0;\n c->private_impl.pixsub = 0;\n c->private_impl.width = 0;\n c->private_impl.height = 0;\n }\n}\n\nstatic inline bool //\nwuffs_base__pixel_config__is_valid(const wuffs_base__pixel_config* c) {\n return c && c->private_impl.pixfmt;\n}\n\nstatic inline wuffs_base__pixel_format //\nwuffs_base__pixel_config__pixel_format(const wuffs_base__pixel_config* c) {\n return c ? c->private_impl.pixfmt : 0;\n}\n\nstatic inline wuffs_base__pixel_subsampling //\nwuffs_base__pixel_config__pixel_subsampling(const wuffs_base__pixel_config* c) {\n return c ? c->private_impl.pixsub : 0;\n}\n\nstatic inline wuffs_base__rect_ie_u32 //\nwuffs_base__pixel_config__bounds(const wuffs_base__pixel_config* c) {\n if (c) {\n wuffs_base__rect_ie_u32 ret;\n ret.min_incl_x = 0;\n ret.min_incl_y = 0;\n ret.max_excl_x = c->private_impl.width;\n ret.max_excl_y = c->private_impl.height;\n return ret;\n }\n\n wuffs_base__rect_ie_u32 ret;\n ret.min_incl" +
"_x = 0;\n ret.min_incl_y = 0;\n ret.max_excl_x = 0;\n ret.max_excl_y = 0;\n return ret;\n}\n\nstatic inline uint32_t //\nwuffs_base__pixel_config__width(const wuffs_base__pixel_config* c) {\n return c ? c->private_impl.width : 0;\n}\n\nstatic inline uint32_t //\nwuffs_base__pixel_config__height(const wuffs_base__pixel_config* c) {\n return c ? c->private_impl.height : 0;\n}\n\n// TODO: this is the right API for planar (not interleaved) pixbufs? Should it\n// allow decoding into a color model different from the format's intrinsic one?\n// For example, decoding a JPEG image straight to RGBA instead of to YCbCr?\nstatic inline uint64_t //\nwuffs_base__pixel_config__pixbuf_len(const wuffs_base__pixel_config* c) {\n if (!c) {\n return 0;\n }\n if (wuffs_base__pixel_format__is_planar(c->private_impl.pixfmt)) {\n // TODO: support planar pixel formats, concious of pixel subsampling.\n return 0;\n }\n uint32_t bits_per_pixel =\n wuffs_base__pixel_format__bits_per_pixel(c->private_impl.pixfmt);\n if ((bits_per_pixel == 0" +
") || ((bits_per_pixel % 8) != 0)) {\n // TODO: support fraction-of-byte pixels, e.g. 1 bit per pixel?\n return 0;\n }\n uint64_t bytes_per_pixel = bits_per_pixel / 8;\n\n uint64_t n =\n ((uint64_t)c->private_impl.width) * ((uint64_t)c->private_impl.height);\n if (n > (UINT64_MAX / bytes_per_pixel)) {\n return 0;\n }\n n *= bytes_per_pixel;\n\n if (wuffs_base__pixel_format__is_indexed(c->private_impl.pixfmt)) {\n if (n > (UINT64_MAX - 1024)) {\n return 0;\n }\n n += 1024;\n }\n\n return n;\n}\n\n#ifdef __cplusplus\n\ninline void //\nwuffs_base__pixel_config::set(wuffs_base__pixel_format pixfmt,\n wuffs_base__pixel_subsampling pixsub,\n uint32_t width,\n uint32_t height) {\n wuffs_base__pixel_config__set(this, pixfmt, pixsub, width, height);\n}\n\ninline void //\nwuffs_base__pixel_config::invalidate() {\n wuffs_base__pixel_config__invalidate(this);\n}\n\ninline bool //\nwuffs_base__pixel_config::is_valid() const {\n return" +
" wuffs_base__pixel_config__is_valid(this);\n}\n\ninline wuffs_base__pixel_format //\nwuffs_base__pixel_config::pixel_format() const {\n return wuffs_base__pixel_config__pixel_format(this);\n}\n\ninline wuffs_base__pixel_subsampling //\nwuffs_base__pixel_config::pixel_subsampling() const {\n return wuffs_base__pixel_config__pixel_subsampling(this);\n}\n\ninline wuffs_base__rect_ie_u32 //\nwuffs_base__pixel_config::bounds() const {\n return wuffs_base__pixel_config__bounds(this);\n}\n\ninline uint32_t //\nwuffs_base__pixel_config::width() const {\n return wuffs_base__pixel_config__width(this);\n}\n\ninline uint32_t //\nwuffs_base__pixel_config::height() const {\n return wuffs_base__pixel_config__height(this);\n}\n\ninline uint64_t //\nwuffs_base__pixel_config::pixbuf_len() const {\n return wuffs_base__pixel_config__pixbuf_len(this);\n}\n\n#endif // __cplusplus\n\n" +
"// --------\n\n// wuffs_base__pixel_subsampling encodes whether sample values cover one pixel\n// or cover multiple pixels.\n//\n// See https://github.com/google/wuffs/blob/master/doc/note/pixel-subsampling.md\n//\n// Do not manipulate its bits directly; they are private implementation\n// details. Use methods such as wuffs_base__pixel_subsampling__bias_x instead.\ntypedef struct {\n uint32_t repr;\n\n#ifdef __cplusplus\n inline uint32_t bias_x(uint32_t plane) const;\n inline uint32_t denominator_x(uint32_t plane) const;\n inline uint32_t bias_y(uint32_t plane) const;\n inline uint32_t denominator_y(uint32_t plane) const;\n#endif // __cplusplus\n\n} wuffs_base__pixel_subsampling;\n\nstatic inline wuffs_base__pixel_subsampling //\nwuffs_base__make_pixel_subsampling(uint32_t repr) {\n wuffs_base__pixel_subsampling s;\n s.repr = repr;\n return s;\n}\n\n#define WUFFS_BASE__PIXEL_SUBSAMPLING__NONE 0x00000000\n\n#define WUFFS_BASE__PIXEL_SUBSAMPLING__444 0x000000\n#define WUFFS_BASE__PIXEL_SUBSAMPLING__440 0x010100\n#define WUFFS_BASE__" +
"PIXEL_SUBSAMPLING__422 0x101000\n#define WUFFS_BASE__PIXEL_SUBSAMPLING__420 0x111100\n#define WUFFS_BASE__PIXEL_SUBSAMPLING__411 0x303000\n#define WUFFS_BASE__PIXEL_SUBSAMPLING__410 0x313100\n\nstatic inline uint32_t //\nwuffs_base__pixel_subsampling__bias_x(const wuffs_base__pixel_subsampling* s,\n uint32_t plane) {\n uint32_t shift = ((plane & 0x03) * 8) + 6;\n return (s->repr >> shift) & 0x03;\n}\n\nstatic inline uint32_t //\nwuffs_base__pixel_subsampling__denominator_x(\n const wuffs_base__pixel_subsampling* s,\n uint32_t plane) {\n uint32_t shift = ((plane & 0x03) * 8) + 4;\n return ((s->repr >> shift) & 0x03) + 1;\n}\n\nstatic inline uint32_t //\nwuffs_base__pixel_subsampling__bias_y(const wuffs_base__pixel_subsampling* s,\n uint32_t plane) {\n uint32_t shift = ((plane & 0x03) * 8) + 2;\n return (s->repr >> shift) & 0x03;\n}\n\nstatic inline uint32_t //\nwuffs_base__pixel_subsampling__denominator_y(\n const wuffs_base__pixel_subsampling* s," +
"\n uint32_t plane) {\n uint32_t shift = ((plane & 0x03) * 8) + 0;\n return ((s->repr >> shift) & 0x03) + 1;\n}\n\n#ifdef __cplusplus\n\ninline uint32_t //\nwuffs_base__pixel_subsampling::bias_x(uint32_t plane) const {\n return wuffs_base__pixel_subsampling__bias_x(this, plane);\n}\n\ninline uint32_t //\nwuffs_base__pixel_subsampling::denominator_x(uint32_t plane) const {\n return wuffs_base__pixel_subsampling__denominator_x(this, plane);\n}\n\ninline uint32_t //\nwuffs_base__pixel_subsampling::bias_y(uint32_t plane) const {\n return wuffs_base__pixel_subsampling__bias_y(this, plane);\n}\n\ninline uint32_t //\nwuffs_base__pixel_subsampling::denominator_y(uint32_t plane) const {\n return wuffs_base__pixel_subsampling__denominator_y(this, plane);\n}\n\n#endif // __cplusplus\n\n" +
"" +
"// --------\n\ntypedef struct {\n wuffs_base__pixel_config pixcfg;\n\n // Do not access the private_impl's fields directly. There is no API/ABI\n // compatibility or safety guarantee if you do so.\n struct {\n uint64_t first_frame_io_position;\n bool first_frame_is_opaque;\n } private_impl;\n\n#ifdef __cplusplus\n inline void set(wuffs_base__pixel_format pixfmt,\n wuffs_base__pixel_subsampling pixsub,\n uint32_t width,\n uint32_t height,\n uint64_t first_frame_io_position,\n bool first_frame_is_opaque);\n inline void invalidate();\n inline bool is_valid() const;\n inline uint64_t first_frame_io_position() const;\n inline bool first_frame_is_opaque() const;\n#endif // __cplusplus\n\n} wuffs_base__image_config;\n\nstatic inline wuffs_base__image_config //\nwuffs_base__null_image_config() {\n wuffs_base__image_config ret;\n ret.pixcfg = wuffs_base__null_pixel_config();\n ret.private_impl.first_frame_io_position = 0;\n ret.private_impl.fir" +
"st_frame_is_opaque = false;\n return ret;\n}\n\n// TODO: Should this function return bool? An error type?\nstatic inline void //\nwuffs_base__image_config__set(wuffs_base__image_config* c,\n wuffs_base__pixel_format pixfmt,\n wuffs_base__pixel_subsampling pixsub,\n uint32_t width,\n uint32_t height,\n uint64_t first_frame_io_position,\n bool first_frame_is_opaque) {\n if (!c) {\n return;\n }\n if (wuffs_base__pixel_format__is_valid(pixfmt)) {\n c->pixcfg.private_impl.pixfmt = pixfmt;\n c->pixcfg.private_impl.pixsub = pixsub;\n c->pixcfg.private_impl.width = width;\n c->pixcfg.private_impl.height = height;\n c->private_impl.first_frame_io_position = first_frame_io_position;\n c->private_impl.first_frame_is_opaque = first_frame_is_opaque;\n return;\n }\n\n c->pixcfg.private_impl.pixfmt = 0;\n c->pixcfg.private_impl.pixsub = 0;\n c->pix" +
"cfg.private_impl.width = 0;\n c->pixcfg.private_impl.height = 0;\n c->private_impl.first_frame_io_position = 0;\n c->private_impl.first_frame_is_opaque = 0;\n}\n\nstatic inline void //\nwuffs_base__image_config__invalidate(wuffs_base__image_config* c) {\n if (c) {\n c->pixcfg.private_impl.pixfmt = 0;\n c->pixcfg.private_impl.pixsub = 0;\n c->pixcfg.private_impl.width = 0;\n c->pixcfg.private_impl.height = 0;\n c->private_impl.first_frame_io_position = 0;\n c->private_impl.first_frame_is_opaque = 0;\n }\n}\n\nstatic inline bool //\nwuffs_base__image_config__is_valid(const wuffs_base__image_config* c) {\n return c && wuffs_base__pixel_config__is_valid(&(c->pixcfg));\n}\n\nstatic inline uint64_t //\nwuffs_base__image_config__first_frame_io_position(\n const wuffs_base__image_config* c) {\n return c ? c->private_impl.first_frame_io_position : 0;\n}\n\nstatic inline bool //\nwuffs_base__image_config__first_frame_is_opaque(\n const wuffs_base__image_config* c) {\n return c ? c->private_impl.first_frame_is_opaqu" +
"e : false;\n}\n\n#ifdef __cplusplus\n\ninline void //\nwuffs_base__image_config::set(wuffs_base__pixel_format pixfmt,\n wuffs_base__pixel_subsampling pixsub,\n uint32_t width,\n uint32_t height,\n uint64_t first_frame_io_position,\n bool first_frame_is_opaque) {\n wuffs_base__image_config__set(this, pixfmt, pixsub, width, height,\n first_frame_io_position, first_frame_is_opaque);\n}\n\ninline void //\nwuffs_base__image_config::invalidate() {\n wuffs_base__image_config__invalidate(this);\n}\n\ninline bool //\nwuffs_base__image_config::is_valid() const {\n return wuffs_base__image_config__is_valid(this);\n}\n\ninline uint64_t //\nwuffs_base__image_config::first_frame_io_position() const {\n return wuffs_base__image_config__first_frame_io_position(this);\n}\n\ninline bool //\nwuffs_base__image_config::first_frame_is_opaque() const {\n return wuffs_base__image_co" +
"nfig__first_frame_is_opaque(this);\n}\n\n#endif // __cplusplus\n\n" +
"// --------\n\ntypedef struct {\n // Do not access the private_impl's fields directly. There is no API/ABI\n // compatibility or safety guarantee if you do so.\n struct {\n wuffs_base__pixel_format pixfmt;\n wuffs_base__pixel_subsampling pixsub;\n uint32_t width;\n uint32_t height;\n } private_impl;\n\n#ifdef __cplusplus\n inline void set(uint32_t pixfmt_repr,\n uint32_t pixsub_repr,\n uint32_t width,\n uint32_t height);\n inline void invalidate();\n inline bool is_valid() const;\n inline wuffs_base__pixel_format pixel_format() const;\n inline wuffs_base__pixel_subsampling pixel_subsampling() const;\n inline wuffs_base__rect_ie_u32 bounds() const;\n inline uint32_t width() const;\n inline uint32_t height() const;\n inline uint64_t pixbuf_len() const;\n#endif // __cplusplus\n\n} wuffs_base__pixel_config;\n\nstatic inline wuffs_base__pixel_config //\nwuffs_base__null_pixel_config() {\n wuffs_base__pixel_config ret;\n ret.private_impl.pixfmt.repr = 0;\n ret.private" +
"_impl.pixsub.repr = 0;\n ret.private_impl.width = 0;\n ret.private_impl.height = 0;\n return ret;\n}\n\n// TODO: Should this function return bool? An error type?\nstatic inline void //\nwuffs_base__pixel_config__set(wuffs_base__pixel_config* c,\n uint32_t pixfmt_repr,\n uint32_t pixsub_repr,\n uint32_t width,\n uint32_t height) {\n if (!c) {\n return;\n }\n if (pixfmt_repr) {\n uint64_t wh = ((uint64_t)width) * ((uint64_t)height);\n // TODO: handle things other than 1 byte per pixel.\n if (wh <= ((uint64_t)SIZE_MAX)) {\n c->private_impl.pixfmt.repr = pixfmt_repr;\n c->private_impl.pixsub.repr = pixsub_repr;\n c->private_impl.width = width;\n c->private_impl.height = height;\n return;\n }\n }\n\n c->private_impl.pixfmt.repr = 0;\n c->private_impl.pixsub.repr = 0;\n c->private_impl.width = 0;\n c->private_impl.height = 0;\n}\n\nstatic inline void //\nwuffs_base__pixel_config__inv" +
"alidate(wuffs_base__pixel_config* c) {\n if (c) {\n c->private_impl.pixfmt.repr = 0;\n c->private_impl.pixsub.repr = 0;\n c->private_impl.width = 0;\n c->private_impl.height = 0;\n }\n}\n\nstatic inline bool //\nwuffs_base__pixel_config__is_valid(const wuffs_base__pixel_config* c) {\n return c && c->private_impl.pixfmt.repr;\n}\n\nstatic inline wuffs_base__pixel_format //\nwuffs_base__pixel_config__pixel_format(const wuffs_base__pixel_config* c) {\n return c ? c->private_impl.pixfmt : wuffs_base__make_pixel_format(0);\n}\n\nstatic inline wuffs_base__pixel_subsampling //\nwuffs_base__pixel_config__pixel_subsampling(const wuffs_base__pixel_config* c) {\n return c ? c->private_impl.pixsub : wuffs_base__make_pixel_subsampling(0);\n}\n\nstatic inline wuffs_base__rect_ie_u32 //\nwuffs_base__pixel_config__bounds(const wuffs_base__pixel_config* c) {\n if (c) {\n wuffs_base__rect_ie_u32 ret;\n ret.min_incl_x = 0;\n ret.min_incl_y = 0;\n ret.max_excl_x = c->private_impl.width;\n ret.max_excl_y = c->private_impl.h" +
"eight;\n return ret;\n }\n\n wuffs_base__rect_ie_u32 ret;\n ret.min_incl_x = 0;\n ret.min_incl_y = 0;\n ret.max_excl_x = 0;\n ret.max_excl_y = 0;\n return ret;\n}\n\nstatic inline uint32_t //\nwuffs_base__pixel_config__width(const wuffs_base__pixel_config* c) {\n return c ? c->private_impl.width : 0;\n}\n\nstatic inline uint32_t //\nwuffs_base__pixel_config__height(const wuffs_base__pixel_config* c) {\n return c ? c->private_impl.height : 0;\n}\n\n// TODO: this is the right API for planar (not interleaved) pixbufs? Should it\n// allow decoding into a color model different from the format's intrinsic one?\n// For example, decoding a JPEG image straight to RGBA instead of to YCbCr?\nstatic inline uint64_t //\nwuffs_base__pixel_config__pixbuf_len(const wuffs_base__pixel_config* c) {\n if (!c) {\n return 0;\n }\n if (wuffs_base__pixel_format__is_planar(&c->private_impl.pixfmt)) {\n // TODO: support planar pixel formats, concious of pixel subsampling.\n return 0;\n }\n uint32_t bits_per_pixel =\n wuffs_base__pixel_" +
"format__bits_per_pixel(&c->private_impl.pixfmt);\n if ((bits_per_pixel == 0) || ((bits_per_pixel % 8) != 0)) {\n // TODO: support fraction-of-byte pixels, e.g. 1 bit per pixel?\n return 0;\n }\n uint64_t bytes_per_pixel = bits_per_pixel / 8;\n\n uint64_t n =\n ((uint64_t)c->private_impl.width) * ((uint64_t)c->private_impl.height);\n if (n > (UINT64_MAX / bytes_per_pixel)) {\n return 0;\n }\n n *= bytes_per_pixel;\n\n if (wuffs_base__pixel_format__is_indexed(&c->private_impl.pixfmt)) {\n if (n > (UINT64_MAX - 1024)) {\n return 0;\n }\n n += 1024;\n }\n\n return n;\n}\n\n#ifdef __cplusplus\n\ninline void //\nwuffs_base__pixel_config::set(uint32_t pixfmt_repr,\n uint32_t pixsub_repr,\n uint32_t width,\n uint32_t height) {\n wuffs_base__pixel_config__set(this, pixfmt_repr, pixsub_repr, width, height);\n}\n\ninline void //\nwuffs_base__pixel_config::invalidate() {\n wuffs_base__pixel_config__invalidate(this);\n}\n\ninline boo" +
"l //\nwuffs_base__pixel_config::is_valid() const {\n return wuffs_base__pixel_config__is_valid(this);\n}\n\ninline wuffs_base__pixel_format //\nwuffs_base__pixel_config::pixel_format() const {\n return wuffs_base__pixel_config__pixel_format(this);\n}\n\ninline wuffs_base__pixel_subsampling //\nwuffs_base__pixel_config::pixel_subsampling() const {\n return wuffs_base__pixel_config__pixel_subsampling(this);\n}\n\ninline wuffs_base__rect_ie_u32 //\nwuffs_base__pixel_config::bounds() const {\n return wuffs_base__pixel_config__bounds(this);\n}\n\ninline uint32_t //\nwuffs_base__pixel_config::width() const {\n return wuffs_base__pixel_config__width(this);\n}\n\ninline uint32_t //\nwuffs_base__pixel_config::height() const {\n return wuffs_base__pixel_config__height(this);\n}\n\ninline uint64_t //\nwuffs_base__pixel_config::pixbuf_len() const {\n return wuffs_base__pixel_config__pixbuf_len(this);\n}\n\n#endif // __cplusplus\n\n" +
"" +
"// --------\n\n// wuffs_base__animation_blend encodes, for an animated image, how to blend the\n// transparent pixels of this frame with the existing canvas. In Porter-Duff\n// compositing operator terminology:\n// - 0 means the frame may be transparent, and should be blended \"src over\n// dst\", also known as just \"over\".\n// - 1 means the frame may be transparent, and should be blended \"src\".\n// - 2 means the frame is completely opaque, so that \"src over dst\" and \"src\"\n// are equivalent.\n//\n// These semantics are conservative. It is valid for a completely opaque frame\n// to have a blend value other than 2.\ntypedef uint8_t wuffs_base__animation_blend;\n\n#define WUFFS_BASE__ANIMATION_BLEND__SRC_OVER_DST \\\n ((wuffs_base__animation_blend)0)\n#define WUFFS_BASE__ANIMATION_BLEND__SRC ((wuffs_base__animation_blend)1)\n#define WUFFS_BASE__ANIMATION_BLEND__OPAQUE ((wuffs_base__animation_blend)2)\n\n" +
"// --------\n\ntypedef struct {\n wuffs_base__pixel_config pixcfg;\n\n // Do not access the private_impl's fields directly. There is no API/ABI\n // compatibility or safety guarantee if you do so.\n struct {\n uint64_t first_frame_io_position;\n bool first_frame_is_opaque;\n } private_impl;\n\n#ifdef __cplusplus\n inline void set(uint32_t pixfmt_repr,\n uint32_t pixsub_repr,\n uint32_t width,\n uint32_t height,\n uint64_t first_frame_io_position,\n bool first_frame_is_opaque);\n inline void invalidate();\n inline bool is_valid() const;\n inline uint64_t first_frame_io_position() const;\n inline bool first_frame_is_opaque() const;\n#endif // __cplusplus\n\n} wuffs_base__image_config;\n\nstatic inline wuffs_base__image_config //\nwuffs_base__null_image_config() {\n wuffs_base__image_config ret;\n ret.pixcfg = wuffs_base__null_pixel_config();\n ret.private_impl.first_frame_io_position = 0;\n ret.private_impl.first_frame_is_opaque = false;" +
"\n return ret;\n}\n\n// TODO: Should this function return bool? An error type?\nstatic inline void //\nwuffs_base__image_config__set(wuffs_base__image_config* c,\n uint32_t pixfmt_repr,\n uint32_t pixsub_repr,\n uint32_t width,\n uint32_t height,\n uint64_t first_frame_io_position,\n bool first_frame_is_opaque) {\n if (!c) {\n return;\n }\n if (pixfmt_repr) {\n c->pixcfg.private_impl.pixfmt.repr = pixfmt_repr;\n c->pixcfg.private_impl.pixsub.repr = pixsub_repr;\n c->pixcfg.private_impl.width = width;\n c->pixcfg.private_impl.height = height;\n c->private_impl.first_frame_io_position = first_frame_io_position;\n c->private_impl.first_frame_is_opaque = first_frame_is_opaque;\n return;\n }\n\n c->pixcfg.private_impl.pixfmt.repr = 0;\n c->pixcfg.private_impl.pixsub.repr = 0;\n c->pixcfg.private_impl.width = 0;\n c->pixcfg.private_impl.he" +
"ight = 0;\n c->private_impl.first_frame_io_position = 0;\n c->private_impl.first_frame_is_opaque = 0;\n}\n\nstatic inline void //\nwuffs_base__image_config__invalidate(wuffs_base__image_config* c) {\n if (c) {\n c->pixcfg.private_impl.pixfmt.repr = 0;\n c->pixcfg.private_impl.pixsub.repr = 0;\n c->pixcfg.private_impl.width = 0;\n c->pixcfg.private_impl.height = 0;\n c->private_impl.first_frame_io_position = 0;\n c->private_impl.first_frame_is_opaque = 0;\n }\n}\n\nstatic inline bool //\nwuffs_base__image_config__is_valid(const wuffs_base__image_config* c) {\n return c && wuffs_base__pixel_config__is_valid(&(c->pixcfg));\n}\n\nstatic inline uint64_t //\nwuffs_base__image_config__first_frame_io_position(\n const wuffs_base__image_config* c) {\n return c ? c->private_impl.first_frame_io_position : 0;\n}\n\nstatic inline bool //\nwuffs_base__image_config__first_frame_is_opaque(\n const wuffs_base__image_config* c) {\n return c ? c->private_impl.first_frame_is_opaque : false;\n}\n\n#ifdef __cplusplus\n\ninline void" +
" //\nwuffs_base__image_config::set(uint32_t pixfmt_repr,\n uint32_t pixsub_repr,\n uint32_t width,\n uint32_t height,\n uint64_t first_frame_io_position,\n bool first_frame_is_opaque) {\n wuffs_base__image_config__set(this, pixfmt_repr, pixsub_repr, width, height,\n first_frame_io_position, first_frame_is_opaque);\n}\n\ninline void //\nwuffs_base__image_config::invalidate() {\n wuffs_base__image_config__invalidate(this);\n}\n\ninline bool //\nwuffs_base__image_config::is_valid() const {\n return wuffs_base__image_config__is_valid(this);\n}\n\ninline uint64_t //\nwuffs_base__image_config::first_frame_io_position() const {\n return wuffs_base__image_config__first_frame_io_position(this);\n}\n\ninline bool //\nwuffs_base__image_config::first_frame_is_opaque() const {\n return wuffs_base__image_config__first_frame_is_opaque(this);\n}\n\n#endif // __cplusplus\n\n" +
"" +
"// --------\n\n// Deprecated: use wuffs_base__pixel_blend instead.\n//\n// wuffs_base__animation_blend encodes, for an animated image, how to blend the\n// transparent pixels of this frame with the existing canvas. In Porter-Duff\n// compositing operator terminology:\n// - 0 means the frame may be transparent, and should be blended \"src over\n// dst\", also known as just \"over\".\n// - 1 means the frame may be transparent, and should be blended \"src\".\n// - 2 means the frame is completely opaque, so that \"src over dst\" and \"src\"\n// are equivalent.\n//\n// These semantics are conservative. It is valid for a completely opaque frame\n// to have a blend value other than 2.\ntypedef uint8_t wuffs_base__animation_blend;\n\n#define WUFFS_BASE__ANIMATION_BLEND__SRC_OVER_DST \\\n ((wuffs_base__animation_blend)0)\n#define WUFFS_BASE__ANIMATION_BLEND__SRC ((wuffs_base__animation_blend)1)\n#define WUFFS_BASE__ANIMATION_BLEND__OPAQUE ((wuffs_base__animation_blend)2)\n\n" +
"" +
"// --------\n\n// wuffs_base__animation_disposal encodes, for an animated image, how to\n// dispose of a frame after displaying it:\n// - None means to draw the next frame on top of this one.\n// - Restore Background means to clear the frame's dirty rectangle to \"the\n// background color\" (in practice, this means transparent black) before\n// drawing the next frame.\n// - Restore Previous means to undo the current frame, so that the next frame\n// is drawn on top of the previous one.\ntypedef uint8_t wuffs_base__animation_disposal;\n\n#define WUFFS_BASE__ANIMATION_DISPOSAL__NONE ((wuffs_base__animation_disposal)0)\n#define WUFFS_BASE__ANIMATION_DISPOSAL__RESTORE_BACKGROUND \\\n ((wuffs_base__animation_disposal)1)\n#define WUFFS_BASE__ANIMATION_DISPOSAL__RESTORE_PREVIOUS \\\n ((wuffs_base__animation_disposal)2)\n\n" +
"" +
"// --------\n\ntypedef struct {\n // Do not access the private_impl's fields directly. There is no API/ABI\n // compatibility or safety guarantee if you do so.\n struct {\n wuffs_base__rect_ie_u32 bounds;\n wuffs_base__flicks duration;\n uint64_t index;\n uint64_t io_position;\n wuffs_base__animation_blend blend;\n wuffs_base__animation_disposal disposal;\n wuffs_base__color_u32_argb_premul background_color;\n } private_impl;\n\n#ifdef __cplusplus\n inline void update(wuffs_base__rect_ie_u32 bounds,\n wuffs_base__flicks duration,\n uint64_t index,\n uint64_t io_position,\n wuffs_base__animation_blend blend,\n wuffs_base__animation_disposal disposal,\n wuffs_base__color_u32_argb_premul background_color);\n inline wuffs_base__rect_ie_u32 bounds() const;\n inline uint32_t width() const;\n inline uint32_t height() const;\n inline wuffs_base__flicks duration() const;\n inline uint64_t index()" +
" const;\n inline uint64_t io_position() const;\n inline wuffs_base__animation_blend blend() const;\n inline wuffs_base__animation_disposal disposal() const;\n inline wuffs_base__color_u32_argb_premul background_color() const;\n#endif // __cplusplus\n\n} wuffs_base__frame_config;\n\nstatic inline wuffs_base__frame_config //\nwuffs_base__null_frame_config() {\n wuffs_base__frame_config ret;\n ret.private_impl.bounds = wuffs_base__make_rect_ie_u32(0, 0, 0, 0);\n ret.private_impl.duration = 0;\n ret.private_impl.index = 0;\n ret.private_impl.io_position = 0;\n ret.private_impl.blend = 0;\n ret.private_impl.disposal = 0;\n return ret;\n}\n\nstatic inline void //\nwuffs_base__frame_config__update(\n wuffs_base__frame_config* c,\n wuffs_base__rect_ie_u32 bounds,\n wuffs_base__flicks duration,\n uint64_t index,\n uint64_t io_position,\n wuffs_base__animation_blend blend,\n wuffs_base__animation_disposal disposal,\n wuffs_base__color_u32_argb_premul background_color) {\n if (!c) {\n return;\n }\n\n c->privat" +
"e_impl.bounds = bounds;\n c->private_impl.duration = duration;\n c->private_impl.index = index;\n c->private_impl.io_position = io_position;\n c->private_impl.blend = blend;\n c->private_impl.disposal = disposal;\n c->private_impl.background_color = background_color;\n}\n\nstatic inline wuffs_base__rect_ie_u32 //\nwuffs_base__frame_config__bounds(const wuffs_base__frame_config* c) {\n if (c) {\n return c->private_impl.bounds;\n }\n\n wuffs_base__rect_ie_u32 ret;\n ret.min_incl_x = 0;\n ret.min_incl_y = 0;\n ret.max_excl_x = 0;\n ret.max_excl_y = 0;\n return ret;\n}\n\nstatic inline uint32_t //\nwuffs_base__frame_config__width(const wuffs_base__frame_config* c) {\n return c ? wuffs_base__rect_ie_u32__width(&c->private_impl.bounds) : 0;\n}\n\nstatic inline uint32_t //\nwuffs_base__frame_config__height(const wuffs_base__frame_config* c) {\n return c ? wuffs_base__rect_ie_u32__height(&c->private_impl.bounds) : 0;\n}\n\n// wuffs_base__frame_config__duration returns the amount of time to display\n// this frame. Zero means to d" +
"isplay forever - a still (non-animated) image.\nstatic inline wuffs_base__flicks //\nwuffs_base__frame_config__duration(const wuffs_base__frame_config* c) {\n return c ? c->private_impl.duration : 0;\n}\n\n// wuffs_base__frame_config__index returns the index of this frame. The first\n// frame in an image has index 0, the second frame has index 1, and so on.\nstatic inline uint64_t //\nwuffs_base__frame_config__index(const wuffs_base__frame_config* c) {\n return c ? c->private_impl.index : 0;\n}\n\n// wuffs_base__frame_config__io_position returns the I/O stream position before\n// the frame config.\nstatic inline uint64_t //\nwuffs_base__frame_config__io_position(const wuffs_base__frame_config* c) {\n return c ? c->private_impl.io_position : 0;\n}\n\n// wuffs_base__frame_config__blend returns, for an animated image, how to blend\n// the transparent pixels of this frame with the existing canvas.\nstatic inline wuffs_base__animation_blend //\nwuffs_base__frame_config__blend(const wuffs_base__frame_config* c) {\n return c ? c->p" +
"rivate_impl.blend : 0;\n}\n\n// wuffs_base__frame_config__disposal returns, for an animated image, how to\n// dispose of this frame after displaying it.\nstatic inline wuffs_base__animation_disposal //\nwuffs_base__frame_config__disposal(const wuffs_base__frame_config* c) {\n return c ? c->private_impl.disposal : 0;\n}\n\nstatic inline wuffs_base__color_u32_argb_premul //\nwuffs_base__frame_config__background_color(const wuffs_base__frame_config* c) {\n return c ? c->private_impl.background_color : 0;\n}\n\n#ifdef __cplusplus\n\ninline void //\nwuffs_base__frame_config::update(\n wuffs_base__rect_ie_u32 bounds,\n wuffs_base__flicks duration,\n uint64_t index,\n uint64_t io_position,\n wuffs_base__animation_blend blend,\n wuffs_base__animation_disposal disposal,\n wuffs_base__color_u32_argb_premul background_color) {\n wuffs_base__frame_config__update(this, bounds, duration, index, io_position,\n blend, disposal, background_color);\n}\n\ninline wuffs_base__rect_ie_u32 //\nwuffs_b" +
"ase__frame_config::bounds() const {\n return wuffs_base__frame_config__bounds(this);\n}\n\ninline uint32_t //\nwuffs_base__frame_config::width() const {\n return wuffs_base__frame_config__width(this);\n}\n\ninline uint32_t //\nwuffs_base__frame_config::height() const {\n return wuffs_base__frame_config__height(this);\n}\n\ninline wuffs_base__flicks //\nwuffs_base__frame_config::duration() const {\n return wuffs_base__frame_config__duration(this);\n}\n\ninline uint64_t //\nwuffs_base__frame_config::index() const {\n return wuffs_base__frame_config__index(this);\n}\n\ninline uint64_t //\nwuffs_base__frame_config::io_position() const {\n return wuffs_base__frame_config__io_position(this);\n}\n\ninline wuffs_base__animation_blend //\nwuffs_base__frame_config::blend() const {\n return wuffs_base__frame_config__blend(this);\n}\n\ninline wuffs_base__animation_disposal //\nwuffs_base__frame_config::disposal() const {\n return wuffs_base__frame_config__disposal(this);\n}\n\ninline wuffs_base__color_u32_argb_premul //\nwuffs_base__frame_confi" +
"g::background_color() const {\n return wuffs_base__frame_config__background_color(this);\n}\n\n#endif // __cplusplus\n\n" +
"// --------\n\ntypedef struct {\n // Do not access the private_impl's fields directly. There is no API/ABI\n // compatibility or safety guarantee if you do so.\n struct {\n wuffs_base__rect_ie_u32 bounds;\n wuffs_base__flicks duration;\n uint64_t index;\n uint64_t io_position;\n wuffs_base__animation_disposal disposal;\n bool opaque_within_bounds;\n bool overwrite_instead_of_blend;\n wuffs_base__color_u32_argb_premul background_color;\n } private_impl;\n\n#ifdef __cplusplus\n inline void update(wuffs_base__rect_ie_u32 bounds,\n wuffs_base__flicks duration,\n uint64_t index,\n uint64_t io_position,\n wuffs_base__animation_disposal disposal,\n bool opaque_within_bounds,\n bool overwrite_instead_of_blend,\n wuffs_base__color_u32_argb_premul background_color);\n inline wuffs_base__rect_ie_u32 bounds() const;\n inline uint32_t width() const;\n inline uint32_t height() con" +
"st;\n inline wuffs_base__flicks duration() const;\n inline uint64_t index() const;\n inline uint64_t io_position() const;\n inline wuffs_base__animation_disposal disposal() const;\n inline bool opaque_within_bounds() const;\n inline bool overwrite_instead_of_blend() const;\n inline wuffs_base__color_u32_argb_premul background_color() const;\n#endif // __cplusplus\n\n} wuffs_base__frame_config;\n\nstatic inline wuffs_base__frame_config //\nwuffs_base__null_frame_config() {\n wuffs_base__frame_config ret;\n ret.private_impl.bounds = wuffs_base__make_rect_ie_u32(0, 0, 0, 0);\n ret.private_impl.duration = 0;\n ret.private_impl.index = 0;\n ret.private_impl.io_position = 0;\n ret.private_impl.disposal = 0;\n ret.private_impl.opaque_within_bounds = false;\n ret.private_impl.overwrite_instead_of_blend = false;\n return ret;\n}\n\nstatic inline void //\nwuffs_base__frame_config__update(\n wuffs_base__frame_config* c,\n wuffs_base__rect_ie_u32 bounds,\n wuffs_base__flicks duration,\n uint64_t index,\n uint64_t io_p" +
"osition,\n wuffs_base__animation_disposal disposal,\n bool opaque_within_bounds,\n bool overwrite_instead_of_blend,\n wuffs_base__color_u32_argb_premul background_color) {\n if (!c) {\n return;\n }\n\n c->private_impl.bounds = bounds;\n c->private_impl.duration = duration;\n c->private_impl.index = index;\n c->private_impl.io_position = io_position;\n c->private_impl.disposal = disposal;\n c->private_impl.opaque_within_bounds = opaque_within_bounds;\n c->private_impl.overwrite_instead_of_blend = overwrite_instead_of_blend;\n c->private_impl.background_color = background_color;\n}\n\nstatic inline wuffs_base__rect_ie_u32 //\nwuffs_base__frame_config__bounds(const wuffs_base__frame_config* c) {\n if (c) {\n return c->private_impl.bounds;\n }\n\n wuffs_base__rect_ie_u32 ret;\n ret.min_incl_x = 0;\n ret.min_incl_y = 0;\n ret.max_excl_x = 0;\n ret.max_excl_y = 0;\n return ret;\n}\n\nstatic inline uint32_t //\nwuffs_base__frame_config__width(const wuffs_base__frame_config* c) {\n return c ? wuffs_base__rect_ie_" +
"u32__width(&c->private_impl.bounds) : 0;\n}\n\nstatic inline uint32_t //\nwuffs_base__frame_config__height(const wuffs_base__frame_config* c) {\n return c ? wuffs_base__rect_ie_u32__height(&c->private_impl.bounds) : 0;\n}\n\n// wuffs_base__frame_config__duration returns the amount of time to display\n// this frame. Zero means to display forever - a still (non-animated) image.\nstatic inline wuffs_base__flicks //\nwuffs_base__frame_config__duration(const wuffs_base__frame_config* c) {\n return c ? c->private_impl.duration : 0;\n}\n\n// wuffs_base__frame_config__index returns the index of this frame. The first\n// frame in an image has index 0, the second frame has index 1, and so on.\nstatic inline uint64_t //\nwuffs_base__frame_config__index(const wuffs_base__frame_config* c) {\n return c ? c->private_impl.index : 0;\n}\n\n// wuffs_base__frame_config__io_position returns the I/O stream position before\n// the frame config.\nstatic inline uint64_t //\nwuffs_base__frame_config__io_position(const wuffs_base__frame_config* c) {\n " +
"return c ? c->private_impl.io_position : 0;\n}\n\n// wuffs_base__frame_config__disposal returns, for an animated image, how to\n// dispose of this frame after displaying it.\nstatic inline wuffs_base__animation_disposal //\nwuffs_base__frame_config__disposal(const wuffs_base__frame_config* c) {\n return c ? c->private_impl.disposal : 0;\n}\n\n// wuffs_base__frame_config__opaque_within_bounds returns whether all pixels\n// within the frame's bounds are fully opaque. It makes no claim about pixels\n// outside the frame bounds but still inside the overall image. The two\n// bounding rectangles can differ for animated images.\n//\n// Its semantics are conservative. It is valid for a fully opaque frame to have\n// this value be false: a false negative.\n//\n// If true, drawing the frame with WUFFS_BASE__PIXEL_BLEND__SRC and\n// WUFFS_BASE__PIXEL_BLEND__SRC_OVER should be equivalent, in terms of\n// resultant pixels, but the former may be faster.\nstatic inline bool //\nwuffs_base__frame_config__opaque_within_bounds(\n const wuffs_" +
"base__frame_config* c) {\n return c && c->private_impl.opaque_within_bounds;\n}\n\n// wuffs_base__frame_config__overwrite_instead_of_blend returns, for an\n// animated image, whether to ignore the previous image state (within the frame\n// bounds) when drawing this incremental frame. Equivalently, whether to use\n// WUFFS_BASE__PIXEL_BLEND__SRC instead of WUFFS_BASE__PIXEL_BLEND__SRC_OVER.\n//\n// The WebP spec (https://developers.google.com/speed/webp/docs/riff_container)\n// calls this the \"Blending method\" bit. WebP's \"Do not blend\" corresponds to\n// Wuffs' \"overwrite_instead_of_blend\".\nstatic inline bool //\nwuffs_base__frame_config__overwrite_instead_of_blend(\n const wuffs_base__frame_config* c) {\n return c && c->private_impl.overwrite_instead_of_blend;\n}\n\nstatic inline wuffs_base__color_u32_argb_premul //\nwuffs_base__frame_config__background_color(const wuffs_base__frame_config* c) {\n return c ? c->private_impl.background_color : 0;\n}\n\n#ifdef __cplusplus\n\ninline void //\nwuffs_base__frame_config::update(\n " +
" wuffs_base__rect_ie_u32 bounds,\n wuffs_base__flicks duration,\n uint64_t index,\n uint64_t io_position,\n wuffs_base__animation_disposal disposal,\n bool opaque_within_bounds,\n bool overwrite_instead_of_blend,\n wuffs_base__color_u32_argb_premul background_color) {\n wuffs_base__frame_config__update(\n this, bounds, duration, index, io_position, disposal,\n opaque_within_bounds, overwrite_instead_of_blend, background_color);\n}\n\ninline wuffs_base__rect_ie_u32 //\nwuffs_base__frame_config::bounds() const {\n return wuffs_base__frame_config__bounds(this);\n}\n\ninline uint32_t //\nwuffs_base__frame_config::width() const {\n return wuffs_base__frame_config__width(this);\n}\n\ninline uint32_t //\nwuffs_base__frame_config::height() const {\n return wuffs_base__frame_config__height(this);\n}\n\ninline wuffs_base__flicks //\nwuffs_base__frame_config::duration() const {\n return wuffs_base__frame_config__duration(this);\n}\n\ninline uint64_t //\nwuffs_base__frame_config::index() const {\n return wuffs_b" +
"ase__frame_config__index(this);\n}\n\ninline uint64_t //\nwuffs_base__frame_config::io_position() const {\n return wuffs_base__frame_config__io_position(this);\n}\n\ninline wuffs_base__animation_disposal //\nwuffs_base__frame_config::disposal() const {\n return wuffs_base__frame_config__disposal(this);\n}\n\ninline bool //\nwuffs_base__frame_config::opaque_within_bounds() const {\n return wuffs_base__frame_config__opaque_within_bounds(this);\n}\n\ninline bool //\nwuffs_base__frame_config::overwrite_instead_of_blend() const {\n return wuffs_base__frame_config__overwrite_instead_of_blend(this);\n}\n\ninline wuffs_base__color_u32_argb_premul //\nwuffs_base__frame_config::background_color() const {\n return wuffs_base__frame_config__background_color(this);\n}\n\n#endif // __cplusplus\n\n" +
"" +
"// --------\n\ntypedef struct {\n wuffs_base__pixel_config pixcfg;\n\n // Do not access the private_impl's fields directly. There is no API/ABI\n // compatibility or safety guarantee if you do so.\n struct {\n wuffs_base__table_u8 planes[WUFFS_BASE__PIXEL_FORMAT__NUM_PLANES_MAX];\n // TODO: color spaces.\n } private_impl;\n\n#ifdef __cplusplus\n inline wuffs_base__status set_from_slice(\n const wuffs_base__pixel_config* pixcfg,\n wuffs_base__slice_u8 pixbuf_memory);\n inline wuffs_base__status set_from_table(\n const wuffs_base__pixel_config* pixcfg,\n wuffs_base__table_u8 pixbuf_memory);\n inline wuffs_base__slice_u8 palette();\n inline wuffs_base__pixel_format pixel_format() const;\n inline wuffs_base__table_u8 plane(uint32_t p);\n#endif // __cplusplus\n\n} wuffs_base__pixel_buffer;\n\nstatic inline wuffs_base__pixel_buffer //\nwuffs_base__null_pixel_buffer() {\n wuffs_base__pixel_buffer ret;\n ret.pixcfg = wuffs_base__null_pixel_config();\n ret.private_impl.planes[0] = wuffs_base__empty_table_u8" +
"();\n ret.private_impl.planes[1] = wuffs_base__empty_table_u8();\n ret.private_impl.planes[2] = wuffs_base__empty_table_u8();\n ret.private_impl.planes[3] = wuffs_base__empty_table_u8();\n return ret;\n}\n\nstatic inline wuffs_base__status //\nwuffs_base__pixel_buffer__set_from_slice(wuffs_base__pixel_buffer* b,\n const wuffs_base__pixel_config* pixcfg,\n wuffs_base__slice_u8 pixbuf_memory) {\n if (!b) {\n return wuffs_base__error__bad_receiver;\n }\n memset(b, 0, sizeof(*b));\n if (!pixcfg) {\n return wuffs_base__error__bad_argument;\n }\n if (wuffs_base__pixel_format__is_planar(pixcfg->private_impl.pixfmt)) {\n // TODO: support planar pixel formats, concious of pixel subsampling.\n return wuffs_base__error__unsupported_option;\n }\n uint32_t bits_per_pixel =\n wuffs_base__pixel_format__bits_per_pixel(pixcfg->private_impl.pixfmt);\n if ((bits_per_pixel == 0) || ((bits_per_pixel % 8) != 0)) {\n // TODO: support fraction-o" +
"f-byte pixels, e.g. 1 bit per pixel?\n return wuffs_base__error__unsupported_option;\n }\n uint64_t bytes_per_pixel = bits_per_pixel / 8;\n\n uint8_t* ptr = pixbuf_memory.ptr;\n uint64_t len = pixbuf_memory.len;\n if (wuffs_base__pixel_format__is_indexed(pixcfg->private_impl.pixfmt)) {\n // Split a 1024 byte chunk (256 palette entries × 4 bytes per entry) from\n // the start of pixbuf_memory. We split from the start, not the end, so\n // that the both chunks' pointers have the same alignment as the original\n // pointer, up to an alignment of 1024.\n if (len < 1024) {\n return wuffs_base__error__bad_argument_length_too_short;\n }\n wuffs_base__table_u8* tab =\n &b->private_impl.planes[WUFFS_BASE__PIXEL_FORMAT__INDEXED__COLOR_PLANE];\n tab->ptr = ptr;\n tab->width = 1024;\n tab->height = 1;\n tab->stride = 1024;\n ptr += 1024;\n len -= 1024;\n }\n\n uint64_t wh = ((uint64_t)pixcfg->private_impl.width) *\n ((uint64_t)pixcfg->private_impl.height);\n size_t width" +
" = (size_t)(pixcfg->private_impl.width);\n if ((wh > (UINT64_MAX / bytes_per_pixel)) ||\n (width > (SIZE_MAX / bytes_per_pixel))) {\n return wuffs_base__error__bad_argument;\n }\n wh *= bytes_per_pixel;\n width *= bytes_per_pixel;\n if (wh > len) {\n return wuffs_base__error__bad_argument_length_too_short;\n }\n\n b->pixcfg = *pixcfg;\n wuffs_base__table_u8* tab = &b->private_impl.planes[0];\n tab->ptr = ptr;\n tab->width = width;\n tab->height = pixcfg->private_impl.height;\n tab->stride = width;\n return NULL;\n}\n\nstatic inline wuffs_base__status //\nwuffs_base__pixel_buffer__set_from_table(wuffs_base__pixel_buffer* b,\n const wuffs_base__pixel_config* pixcfg,\n wuffs_base__table_u8 pixbuf_memory) {\n if (!b) {\n return wuffs_base__error__bad_receiver;\n }\n memset(b, 0, sizeof(*b));\n if (!pixcfg ||\n wuffs_base__pixel_format__is_planar(pixcfg->private_impl.pixfmt)) {\n return wuffs_base__error__bad_argument;\n }\n " +
"uint32_t bits_per_pixel =\n wuffs_base__pixel_format__bits_per_pixel(pixcfg->private_impl.pixfmt);\n if ((bits_per_pixel == 0) || ((bits_per_pixel % 8) != 0)) {\n // TODO: support fraction-of-byte pixels, e.g. 1 bit per pixel?\n return wuffs_base__error__unsupported_option;\n }\n uint64_t bytes_per_pixel = bits_per_pixel / 8;\n\n uint64_t width_in_bytes =\n ((uint64_t)pixcfg->private_impl.width) * bytes_per_pixel;\n if ((width_in_bytes > pixbuf_memory.width) ||\n (pixcfg->private_impl.height > pixbuf_memory.height)) {\n return wuffs_base__error__bad_argument;\n }\n\n b->pixcfg = *pixcfg;\n b->private_impl.planes[0] = pixbuf_memory;\n return NULL;\n}\n\n// wuffs_base__pixel_buffer__palette returns the palette color data. If\n// non-empty, it will have length 1024.\nstatic inline wuffs_base__slice_u8 //\nwuffs_base__pixel_buffer__palette(wuffs_base__pixel_buffer* b) {\n if (b &&\n wuffs_base__pixel_format__is_indexed(b->pixcfg.private_impl.pixfmt)) {\n wuffs_base__table_u8* tab =\n &b->pr" +
"ivate_impl.planes[WUFFS_BASE__PIXEL_FORMAT__INDEXED__COLOR_PLANE];\n if ((tab->width == 1024) && (tab->height == 1)) {\n return wuffs_base__make_slice_u8(tab->ptr, 1024);\n }\n }\n return wuffs_base__make_slice_u8(NULL, 0);\n}\n\nstatic inline wuffs_base__pixel_format //\nwuffs_base__pixel_buffer__pixel_format(const wuffs_base__pixel_buffer* b) {\n if (b) {\n return b->pixcfg.private_impl.pixfmt;\n }\n return WUFFS_BASE__PIXEL_FORMAT__INVALID;\n}\n\nstatic inline wuffs_base__table_u8 //\nwuffs_base__pixel_buffer__plane(wuffs_base__pixel_buffer* b, uint32_t p) {\n if (b && (p < WUFFS_BASE__PIXEL_FORMAT__NUM_PLANES_MAX)) {\n return b->private_impl.planes[p];\n }\n\n wuffs_base__table_u8 ret;\n ret.ptr = NULL;\n ret.width = 0;\n ret.height = 0;\n ret.stride = 0;\n return ret;\n}\n\n#ifdef __cplusplus\n\ninline wuffs_base__status //\nwuffs_base__pixel_buffer::set_from_slice(const wuffs_base__pixel_config* pixcfg,\n wuffs_base__slice_u8 pixbuf_memory) {\n return wuffs_base__p" +
"ixel_buffer__set_from_slice(this, pixcfg, pixbuf_memory);\n}\n\ninline wuffs_base__status //\nwuffs_base__pixel_buffer::set_from_table(const wuffs_base__pixel_config* pixcfg,\n wuffs_base__table_u8 pixbuf_memory) {\n return wuffs_base__pixel_buffer__set_from_table(this, pixcfg, pixbuf_memory);\n}\n\ninline wuffs_base__slice_u8 //\nwuffs_base__pixel_buffer::palette() {\n return wuffs_base__pixel_buffer__palette(this);\n}\n\ninline wuffs_base__pixel_format //\nwuffs_base__pixel_buffer::pixel_format() const {\n return wuffs_base__pixel_buffer__pixel_format(this);\n}\n\ninline wuffs_base__table_u8 //\nwuffs_base__pixel_buffer::plane(uint32_t p) {\n return wuffs_base__pixel_buffer__plane(this, p);\n}\n\n#endif // __cplusplus\n\n" +
"();\n ret.private_impl.planes[1] = wuffs_base__empty_table_u8();\n ret.private_impl.planes[2] = wuffs_base__empty_table_u8();\n ret.private_impl.planes[3] = wuffs_base__empty_table_u8();\n return ret;\n}\n\nstatic inline wuffs_base__status //\nwuffs_base__pixel_buffer__set_from_slice(wuffs_base__pixel_buffer* b,\n const wuffs_base__pixel_config* pixcfg,\n wuffs_base__slice_u8 pixbuf_memory) {\n if (!b) {\n return wuffs_base__make_status(wuffs_base__error__bad_receiver);\n }\n memset(b, 0, sizeof(*b));\n if (!pixcfg) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n if (wuffs_base__pixel_format__is_planar(&pixcfg->private_impl.pixfmt)) {\n // TODO: support planar pixel formats, concious of pixel subsampling.\n return wuffs_base__make_status(wuffs_base__error__unsupported_option);\n }\n uint32_t bits_per_pixel =\n wuffs_base__pixel_format__bits_per_pixel(&pixcfg->private_impl.pixfmt);\n if ((bits_per_" +
"pixel == 0) || ((bits_per_pixel % 8) != 0)) {\n // TODO: support fraction-of-byte pixels, e.g. 1 bit per pixel?\n return wuffs_base__make_status(wuffs_base__error__unsupported_option);\n }\n uint64_t bytes_per_pixel = bits_per_pixel / 8;\n\n uint8_t* ptr = pixbuf_memory.ptr;\n uint64_t len = pixbuf_memory.len;\n if (wuffs_base__pixel_format__is_indexed(&pixcfg->private_impl.pixfmt)) {\n // Split a 1024 byte chunk (256 palette entries × 4 bytes per entry) from\n // the start of pixbuf_memory. We split from the start, not the end, so\n // that the both chunks' pointers have the same alignment as the original\n // pointer, up to an alignment of 1024.\n if (len < 1024) {\n return wuffs_base__make_status(\n wuffs_base__error__bad_argument_length_too_short);\n }\n wuffs_base__table_u8* tab =\n &b->private_impl.planes[WUFFS_BASE__PIXEL_FORMAT__INDEXED__COLOR_PLANE];\n tab->ptr = ptr;\n tab->width = 1024;\n tab->height = 1;\n tab->stride = 1024;\n ptr += 1024;\n len -= " +
"1024;\n }\n\n uint64_t wh = ((uint64_t)pixcfg->private_impl.width) *\n ((uint64_t)pixcfg->private_impl.height);\n size_t width = (size_t)(pixcfg->private_impl.width);\n if ((wh > (UINT64_MAX / bytes_per_pixel)) ||\n (width > (SIZE_MAX / bytes_per_pixel))) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n wh *= bytes_per_pixel;\n width *= bytes_per_pixel;\n if (wh > len) {\n return wuffs_base__make_status(\n wuffs_base__error__bad_argument_length_too_short);\n }\n\n b->pixcfg = *pixcfg;\n wuffs_base__table_u8* tab = &b->private_impl.planes[0];\n tab->ptr = ptr;\n tab->width = width;\n tab->height = pixcfg->private_impl.height;\n tab->stride = width;\n return wuffs_base__make_status(NULL);\n}\n\nstatic inline wuffs_base__status //\nwuffs_base__pixel_buffer__set_from_table(wuffs_base__pixel_buffer* b,\n const wuffs_base__pixel_config* pixcfg,\n wuffs_base__table_u8 pixbuf_memory) {\n if (" +
"!b) {\n return wuffs_base__make_status(wuffs_base__error__bad_receiver);\n }\n memset(b, 0, sizeof(*b));\n if (!pixcfg ||\n wuffs_base__pixel_format__is_planar(&pixcfg->private_impl.pixfmt)) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n uint32_t bits_per_pixel =\n wuffs_base__pixel_format__bits_per_pixel(&pixcfg->private_impl.pixfmt);\n if ((bits_per_pixel == 0) || ((bits_per_pixel % 8) != 0)) {\n // TODO: support fraction-of-byte pixels, e.g. 1 bit per pixel?\n return wuffs_base__make_status(wuffs_base__error__unsupported_option);\n }\n uint64_t bytes_per_pixel = bits_per_pixel / 8;\n\n uint64_t width_in_bytes =\n ((uint64_t)pixcfg->private_impl.width) * bytes_per_pixel;\n if ((width_in_bytes > pixbuf_memory.width) ||\n (pixcfg->private_impl.height > pixbuf_memory.height)) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n\n b->pixcfg = *pixcfg;\n b->private_impl.planes[0] = pixbuf_memory;\n return wuffs_base__make_status(NULL);\n}\n\n" +
"// wuffs_base__pixel_buffer__palette returns the palette color data. If\n// non-empty, it will have length 1024.\nstatic inline wuffs_base__slice_u8 //\nwuffs_base__pixel_buffer__palette(wuffs_base__pixel_buffer* b) {\n if (b &&\n wuffs_base__pixel_format__is_indexed(&b->pixcfg.private_impl.pixfmt)) {\n wuffs_base__table_u8* tab =\n &b->private_impl.planes[WUFFS_BASE__PIXEL_FORMAT__INDEXED__COLOR_PLANE];\n if ((tab->width == 1024) && (tab->height == 1)) {\n return wuffs_base__make_slice_u8(tab->ptr, 1024);\n }\n }\n return wuffs_base__make_slice_u8(NULL, 0);\n}\n\nstatic inline wuffs_base__pixel_format //\nwuffs_base__pixel_buffer__pixel_format(const wuffs_base__pixel_buffer* b) {\n if (b) {\n return b->pixcfg.private_impl.pixfmt;\n }\n return wuffs_base__make_pixel_format(WUFFS_BASE__PIXEL_FORMAT__INVALID);\n}\n\nstatic inline wuffs_base__table_u8 //\nwuffs_base__pixel_buffer__plane(wuffs_base__pixel_buffer* b, uint32_t p) {\n if (b && (p < WUFFS_BASE__PIXEL_FORMAT__NUM_PLANES_MAX)) {\n retur" +
"n b->private_impl.planes[p];\n }\n\n wuffs_base__table_u8 ret;\n ret.ptr = NULL;\n ret.width = 0;\n ret.height = 0;\n ret.stride = 0;\n return ret;\n}\n\n#ifdef __cplusplus\n\ninline wuffs_base__status //\nwuffs_base__pixel_buffer::set_from_slice(const wuffs_base__pixel_config* pixcfg,\n wuffs_base__slice_u8 pixbuf_memory) {\n return wuffs_base__pixel_buffer__set_from_slice(this, pixcfg, pixbuf_memory);\n}\n\ninline wuffs_base__status //\nwuffs_base__pixel_buffer::set_from_table(const wuffs_base__pixel_config* pixcfg,\n wuffs_base__table_u8 pixbuf_memory) {\n return wuffs_base__pixel_buffer__set_from_table(this, pixcfg, pixbuf_memory);\n}\n\ninline wuffs_base__slice_u8 //\nwuffs_base__pixel_buffer::palette() {\n return wuffs_base__pixel_buffer__palette(this);\n}\n\ninline wuffs_base__pixel_format //\nwuffs_base__pixel_buffer::pixel_format() const {\n return wuffs_base__pixel_buffer__pixel_format(this);\n}\n\ninline wuffs_base__table_u8 //\nwuffs_base" +
"__pixel_buffer::plane(uint32_t p) {\n return wuffs_base__pixel_buffer__plane(this, p);\n}\n\n#endif // __cplusplus\n\n" +
"" +
"// --------\n\ntypedef struct {\n // Do not access the private_impl's fields directly. There is no API/ABI\n // compatibility or safety guarantee if you do so.\n struct {\n uint8_t TODO;\n } private_impl;\n\n#ifdef __cplusplus\n#endif // __cplusplus\n\n} wuffs_base__decode_frame_options;\n\n#ifdef __cplusplus\n\n#endif // __cplusplus\n\n" +
"" +
"// --------\n\ntypedef struct {\n // Do not access the private_impl's fields directly. There is no API/ABI\n // compatibility or safety guarantee if you do so.\n struct {\n // TODO: should the func type take restrict pointers?\n uint64_t (*func)(wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 dst_palette,\n wuffs_base__slice_u8 src);\n } private_impl;\n\n#ifdef __cplusplus\n inline wuffs_base__status prepare(wuffs_base__pixel_format dst_format,\n wuffs_base__slice_u8 dst_palette,\n wuffs_base__pixel_format src_format,\n wuffs_base__slice_u8 src_palette);\n inline uint64_t swizzle_interleaved(wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 dst_palette,\n wuffs_base__slice_u8 src) const;\n#endif // __cplusplus\n\n} wuffs_base__pixel_swizzler;\n\nwuffs_base__status //\nwuffs_base__pixel_swizzler__prepare(w" +
"uffs_base__pixel_swizzler* p,\n wuffs_base__pixel_format dst_format,\n wuffs_base__slice_u8 dst_palette,\n wuffs_base__pixel_format src_format,\n wuffs_base__slice_u8 src_palette);\n\nuint64_t //\nwuffs_base__pixel_swizzler__swizzle_interleaved(\n const wuffs_base__pixel_swizzler* p,\n wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 dst_palette,\n wuffs_base__slice_u8 src);\n\n#ifdef __cplusplus\n\ninline wuffs_base__status //\nwuffs_base__pixel_swizzler::prepare(wuffs_base__pixel_format dst_format,\n wuffs_base__slice_u8 dst_palette,\n wuffs_base__pixel_format src_format,\n wuffs_base__slice_u8 src_palette) {\n return wuffs_base__pixel_swizzler__prepare(this, dst_format, dst_palette,\n src_format, src_palette);\n}\n\nuint64_t //\nwu" +
"ffs_base__pixel_swizzler::swizzle_interleaved(\n wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 dst_palette,\n wuffs_base__slice_u8 src) const {\n return wuffs_base__pixel_swizzler__swizzle_interleaved(this, dst, dst_palette,\n src);\n}\n\n#endif // __cplusplus\n" +
"// --------\n\ntypedef struct {\n // Do not access the private_impl's fields directly. There is no API/ABI\n // compatibility or safety guarantee if you do so.\n struct {\n // TODO: should the func type take restrict pointers?\n uint64_t (*func)(wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 dst_palette,\n wuffs_base__slice_u8 src);\n } private_impl;\n\n#ifdef __cplusplus\n inline wuffs_base__status prepare(wuffs_base__pixel_format dst_format,\n wuffs_base__slice_u8 dst_palette,\n wuffs_base__pixel_format src_format,\n wuffs_base__slice_u8 src_palette,\n wuffs_base__pixel_blend blend);\n inline uint64_t swizzle_interleaved(wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 dst_palette,\n wuffs_base__slice_u8 src) const;\n#endif // __cplusplus\n\n} wuffs_base__pixel_swiz" +
"zler;\n\nwuffs_base__status //\nwuffs_base__pixel_swizzler__prepare(wuffs_base__pixel_swizzler* p,\n wuffs_base__pixel_format dst_format,\n wuffs_base__slice_u8 dst_palette,\n wuffs_base__pixel_format src_format,\n wuffs_base__slice_u8 src_palette,\n wuffs_base__pixel_blend blend);\n\nuint64_t //\nwuffs_base__pixel_swizzler__swizzle_interleaved(\n const wuffs_base__pixel_swizzler* p,\n wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 dst_palette,\n wuffs_base__slice_u8 src);\n\n#ifdef __cplusplus\n\ninline wuffs_base__status //\nwuffs_base__pixel_swizzler::prepare(wuffs_base__pixel_format dst_format,\n wuffs_base__slice_u8 dst_palette,\n wuffs_base__pixel_format src_format,\n wuffs_base__slice_u8 src_palette,\n " +
" wuffs_base__pixel_blend blend) {\n return wuffs_base__pixel_swizzler__prepare(this, dst_format, dst_palette,\n src_format, src_palette, blend);\n}\n\nuint64_t //\nwuffs_base__pixel_swizzler::swizzle_interleaved(\n wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 dst_palette,\n wuffs_base__slice_u8 src) const {\n return wuffs_base__pixel_swizzler__swizzle_interleaved(this, dst, dst_palette,\n src);\n}\n\n#endif // __cplusplus\n" +
""
const baseIOPrivateH = "" +
"// ---------------- I/O\n\nstatic inline uint64_t //\nwuffs_base__io__count_since(uint64_t mark, uint64_t index) {\n if (index >= mark) {\n return index - mark;\n }\n return 0;\n}\n\nstatic inline wuffs_base__slice_u8 //\nwuffs_base__io__since(uint64_t mark, uint64_t index, uint8_t* ptr) {\n if (index >= mark) {\n return wuffs_base__make_slice_u8(ptr + mark, index - mark);\n }\n return wuffs_base__make_slice_u8(NULL, 0);\n}\n\nstatic inline uint32_t //\nwuffs_base__io_writer__copy_n_from_history(uint8_t** ptr_iop_w,\n uint8_t* io1_w,\n uint8_t* io2_w,\n uint32_t length,\n uint32_t distance) {\n if (!distance) {\n return 0;\n }\n uint8_t* p = *ptr_iop_w;\n if ((size_t)(p - io1_w) < (size_t)(distance)) {\n return 0;\n }\n uint8_t* q = p - distance;\n size_t n = (size_t)(io2_w - p);\n if ((size_t)(length) > n) {\n length = (uint32_t)(n);\n } else {\n" +
" n = (size_t)(length);\n }\n // TODO: unrolling by 3 seems best for the std/deflate benchmarks, but that\n // is mostly because 3 is the minimum length for the deflate format. This\n // function implementation shouldn't overfit to that one format. Perhaps the\n // copy_n_from_history Wuffs method should also take an unroll hint argument,\n // and the cgen can look if that argument is the constant expression '3'.\n //\n // See also wuffs_base__io_writer__copy_n_from_history_fast below.\n //\n // Alternatively, or additionally, have a sloppy_copy_n_from_history method\n // that copies 8 bytes at a time, possibly writing more than length bytes?\n for (; n >= 3; n -= 3) {\n *p++ = *q++;\n *p++ = *q++;\n *p++ = *q++;\n }\n for (; n; n--) {\n *p++ = *q++;\n }\n *ptr_iop_w = p;\n return length;\n}\n\n// wuffs_base__io_writer__copy_n_from_history_fast is like the\n// wuffs_base__io_writer__copy_n_from_history function above, but has stronger\n// pre-conditions. The caller needs to prove that:\n// - distance > " +
"0\n// - distance <= (*ptr_iop_w - io1_w)\n// - length <= (io2_w - *ptr_iop_w)\nstatic inline uint32_t //\nwuffs_base__io_writer__copy_n_from_history_fast(uint8_t** ptr_iop_w,\n uint8_t* io1_w,\n uint8_t* io2_w,\n uint32_t length,\n uint32_t distance) {\n uint8_t* p = *ptr_iop_w;\n uint8_t* q = p - distance;\n uint32_t n = length;\n for (; n >= 3; n -= 3) {\n *p++ = *q++;\n *p++ = *q++;\n *p++ = *q++;\n }\n for (; n; n--) {\n *p++ = *q++;\n }\n *ptr_iop_w = p;\n return length;\n}\n\nstatic inline uint32_t //\nwuffs_base__io_writer__copy_n_from_reader(uint8_t** ptr_iop_w,\n uint8_t* io2_w,\n uint32_t length,\n uint8_t** ptr_iop_r,\n uint8_t* io2_r) {\n uint8_t* i" +
"op_w = *ptr_iop_w;\n size_t n = length;\n if (n > ((size_t)(io2_w - iop_w))) {\n n = (size_t)(io2_w - iop_w);\n }\n uint8_t* iop_r = *ptr_iop_r;\n if (n > ((size_t)(io2_r - iop_r))) {\n n = (size_t)(io2_r - iop_r);\n }\n if (n > 0) {\n memmove(iop_w, iop_r, n);\n *ptr_iop_w += n;\n *ptr_iop_r += n;\n }\n return (uint32_t)(n);\n}\n\nstatic inline uint64_t //\nwuffs_base__io_writer__copy_from_slice(uint8_t** ptr_iop_w,\n uint8_t* io2_w,\n wuffs_base__slice_u8 src) {\n uint8_t* iop_w = *ptr_iop_w;\n size_t n = src.len;\n if (n > ((size_t)(io2_w - iop_w))) {\n n = (size_t)(io2_w - iop_w);\n }\n if (n > 0) {\n memmove(iop_w, src.ptr, n);\n *ptr_iop_w += n;\n }\n return (uint64_t)(n);\n}\n\nstatic inline uint32_t //\nwuffs_base__io_writer__copy_n_from_slice(uint8_t** ptr_iop_w,\n uint8_t* io2_w,\n uint32_t length,\n w" +
"uffs_base__slice_u8 src) {\n uint8_t* iop_w = *ptr_iop_w;\n size_t n = src.len;\n if (n > length) {\n n = length;\n }\n if (n > ((size_t)(io2_w - iop_w))) {\n n = (size_t)(io2_w - iop_w);\n }\n if (n > 0) {\n memmove(iop_w, src.ptr, n);\n *ptr_iop_w += n;\n }\n return (uint32_t)(n);\n}\n\nstatic inline wuffs_base__io_buffer* //\nwuffs_base__io_reader__set(wuffs_base__io_buffer* b,\n uint8_t** ptr_iop_r,\n uint8_t** ptr_io0_r,\n uint8_t** ptr_io1_r,\n uint8_t** ptr_io2_r,\n wuffs_base__slice_u8 data) {\n b->data = data;\n b->meta.wi = data.len;\n b->meta.ri = 0;\n b->meta.pos = 0;\n b->meta.closed = false;\n\n *ptr_iop_r = data.ptr;\n *ptr_io0_r = data.ptr;\n *ptr_io1_r = data.ptr;\n *ptr_io2_r = data.ptr + data.len;\n\n return b;\n}\n\nstatic inline wuffs_base__slice_u8 //\nwuffs_base__io_reader__take(uint8_t** ptr_iop_r, uint8_t* io2_r, uint64_t n) {\n if (n <= ((size_t)(io2_r - *ptr_i" +
"op_r))) {\n uint8_t* p = *ptr_iop_r;\n *ptr_iop_r += n;\n return wuffs_base__make_slice_u8(p, n);\n }\n return wuffs_base__make_slice_u8(NULL, 0);\n}\n\nstatic inline wuffs_base__io_buffer* //\nwuffs_base__io_writer__set(wuffs_base__io_buffer* b,\n uint8_t** ptr_iop_w,\n uint8_t** ptr_io0_w,\n uint8_t** ptr_io1_w,\n uint8_t** ptr_io2_w,\n wuffs_base__slice_u8 data) {\n b->data = data;\n b->meta.wi = 0;\n b->meta.ri = 0;\n b->meta.pos = 0;\n b->meta.closed = false;\n\n *ptr_iop_w = data.ptr;\n *ptr_io0_w = data.ptr;\n *ptr_io1_w = data.ptr;\n *ptr_io2_w = data.ptr + data.len;\n\n return b;\n}\n\n" +
"// ---------------- I/O\n\nstatic inline uint64_t //\nwuffs_base__io__count_since(uint64_t mark, uint64_t index) {\n if (index >= mark) {\n return index - mark;\n }\n return 0;\n}\n\nstatic inline wuffs_base__slice_u8 //\nwuffs_base__io__since(uint64_t mark, uint64_t index, uint8_t* ptr) {\n if (index >= mark) {\n return wuffs_base__make_slice_u8(ptr + mark, index - mark);\n }\n return wuffs_base__make_slice_u8(NULL, 0);\n}\n\nstatic inline uint32_t //\nwuffs_base__io_writer__copy_n32_from_history(uint8_t** ptr_iop_w,\n uint8_t* io1_w,\n uint8_t* io2_w,\n uint32_t length,\n uint32_t distance) {\n if (!distance) {\n return 0;\n }\n uint8_t* p = *ptr_iop_w;\n if ((size_t)(p - io1_w) < (size_t)(distance)) {\n return 0;\n }\n uint8_t* q = p - distance;\n size_t n = (size_t)(io2_w - p);\n if ((size_t)(length) > n) {\n length = (uint32_t)(n);\n " +
" } else {\n n = (size_t)(length);\n }\n // TODO: unrolling by 3 seems best for the std/deflate benchmarks, but that\n // is mostly because 3 is the minimum length for the deflate format. This\n // function implementation shouldn't overfit to that one format. Perhaps the\n // copy_n32_from_history Wuffs method should also take an unroll hint\n // argument, and the cgen can look if that argument is the constant\n // expression '3'.\n //\n // See also wuffs_base__io_writer__copy_n32_from_history_fast below.\n //\n // Alternatively, or additionally, have a sloppy_copy_n32_from_history method\n // that copies 8 bytes at a time, possibly writing more than length bytes?\n for (; n >= 3; n -= 3) {\n *p++ = *q++;\n *p++ = *q++;\n *p++ = *q++;\n }\n for (; n; n--) {\n *p++ = *q++;\n }\n *ptr_iop_w = p;\n return length;\n}\n\n// wuffs_base__io_writer__copy_n32_from_history_fast is like the\n// wuffs_base__io_writer__copy_n32_from_history function above, but has\n// stronger pre-conditions. The caller needs to prove" +
" that:\n// - distance > 0\n// - distance <= (*ptr_iop_w - io1_w)\n// - length <= (io2_w - *ptr_iop_w)\nstatic inline uint32_t //\nwuffs_base__io_writer__copy_n32_from_history_fast(uint8_t** ptr_iop_w,\n uint8_t* io1_w,\n uint8_t* io2_w,\n uint32_t length,\n uint32_t distance) {\n uint8_t* p = *ptr_iop_w;\n uint8_t* q = p - distance;\n uint32_t n = length;\n for (; n >= 3; n -= 3) {\n *p++ = *q++;\n *p++ = *q++;\n *p++ = *q++;\n }\n for (; n; n--) {\n *p++ = *q++;\n }\n *ptr_iop_w = p;\n return length;\n}\n\nstatic inline uint32_t //\nwuffs_base__io_writer__copy_n32_from_reader(uint8_t** ptr_iop_w,\n uint8_t* io2_w,\n uint32_t length,\n uint8_t** ptr_iop_r,\n " +
" uint8_t* io2_r) {\n uint8_t* iop_w = *ptr_iop_w;\n size_t n = length;\n if (n > ((size_t)(io2_w - iop_w))) {\n n = (size_t)(io2_w - iop_w);\n }\n uint8_t* iop_r = *ptr_iop_r;\n if (n > ((size_t)(io2_r - iop_r))) {\n n = (size_t)(io2_r - iop_r);\n }\n if (n > 0) {\n memmove(iop_w, iop_r, n);\n *ptr_iop_w += n;\n *ptr_iop_r += n;\n }\n return (uint32_t)(n);\n}\n\nstatic inline uint64_t //\nwuffs_base__io_writer__copy_from_slice(uint8_t** ptr_iop_w,\n uint8_t* io2_w,\n wuffs_base__slice_u8 src) {\n uint8_t* iop_w = *ptr_iop_w;\n size_t n = src.len;\n if (n > ((size_t)(io2_w - iop_w))) {\n n = (size_t)(io2_w - iop_w);\n }\n if (n > 0) {\n memmove(iop_w, src.ptr, n);\n *ptr_iop_w += n;\n }\n return (uint64_t)(n);\n}\n\nstatic inline uint32_t //\nwuffs_base__io_writer__copy_n32_from_slice(uint8_t** ptr_iop_w,\n uint8_t* io2_w,\n uint32_t" +
" length,\n wuffs_base__slice_u8 src) {\n uint8_t* iop_w = *ptr_iop_w;\n size_t n = src.len;\n if (n > length) {\n n = length;\n }\n if (n > ((size_t)(io2_w - iop_w))) {\n n = (size_t)(io2_w - iop_w);\n }\n if (n > 0) {\n memmove(iop_w, src.ptr, n);\n *ptr_iop_w += n;\n }\n return (uint32_t)(n);\n}\n\nstatic inline wuffs_base__io_buffer* //\nwuffs_base__io_reader__set(wuffs_base__io_buffer* b,\n uint8_t** ptr_iop_r,\n uint8_t** ptr_io0_r,\n uint8_t** ptr_io1_r,\n uint8_t** ptr_io2_r,\n wuffs_base__slice_u8 data) {\n b->data = data;\n b->meta.wi = data.len;\n b->meta.ri = 0;\n b->meta.pos = 0;\n b->meta.closed = false;\n\n *ptr_iop_r = data.ptr;\n *ptr_io0_r = data.ptr;\n *ptr_io1_r = data.ptr;\n *ptr_io2_r = data.ptr + data.len;\n\n return b;\n}\n\nstatic inline wuffs_base__slice_u8 //\nwuffs_base__io_reader__take(uint8_t** ptr_iop_r, uint8_t* io2" +
"_r, uint64_t n) {\n if (n <= ((size_t)(io2_r - *ptr_iop_r))) {\n uint8_t* p = *ptr_iop_r;\n *ptr_iop_r += n;\n return wuffs_base__make_slice_u8(p, n);\n }\n return wuffs_base__make_slice_u8(NULL, 0);\n}\n\nstatic inline wuffs_base__io_buffer* //\nwuffs_base__io_writer__set(wuffs_base__io_buffer* b,\n uint8_t** ptr_iop_w,\n uint8_t** ptr_io0_w,\n uint8_t** ptr_io1_w,\n uint8_t** ptr_io2_w,\n wuffs_base__slice_u8 data) {\n b->data = data;\n b->meta.wi = 0;\n b->meta.ri = 0;\n b->meta.pos = 0;\n b->meta.closed = false;\n\n *ptr_iop_w = data.ptr;\n *ptr_io0_w = data.ptr;\n *ptr_io1_w = data.ptr;\n *ptr_io2_w = data.ptr + data.len;\n\n return b;\n}\n\n" +
"" +
"// ---------------- I/O (Utility)\n\n#define wuffs_base__utility__empty_io_reader wuffs_base__empty_io_reader\n#define wuffs_base__utility__empty_io_writer wuffs_base__empty_io_writer\n" +
""

View File

@@ -30,8 +30,10 @@ func (g *gen) writeExpr(b *buffer, n *a.Expr, depth uint32) error {
if cv := n.ConstValue(); cv != nil {
if typ := n.MType(); typ.IsNumTypeOrIdeal() {
b.writes(cv.String())
} else if typ.IsNullptr() || typ.IsStatus() {
} else if typ.IsNullptr() {
b.writes("NULL")
} else if typ.IsStatus() {
b.writes("wuffs_base__make_status(NULL)")
} else if cv.Cmp(zero) == 0 {
b.writes("false")
} else if cv.Cmp(one) == 0 {
@@ -70,7 +72,9 @@ func (g *gen) writeExprOther(b *buffer, n *a.Expr, depth uint32) error {
} else if ident.IsStrLiteral(g.tm) {
if z := g.statusMap[n.StatusQID()]; z.cName != "" {
b.writes("wuffs_base__make_status(")
b.writes(z.cName)
b.writes(")")
} else {
return fmt.Errorf("unrecognized status %s", n.StatusQID().Str(g.tm))
}
@@ -272,14 +276,24 @@ func (g *gen) writeExprBinaryOp(b *buffer, n *a.Expr, depth uint32) error {
if err := g.writeExpr(b, n.LHS().AsExpr(), depth); err != nil {
return err
}
if g.hasRepr(n.LHS().AsExpr()) {
b.writes(".repr")
}
b.writes(opName)
if err := g.writeExpr(b, n.RHS().AsExpr(), depth); err != nil {
return err
}
if g.hasRepr(n.RHS().AsExpr()) {
b.writes(".repr")
}
b.writeb(')')
return nil
}
func (g *gen) hasRepr(n *a.Expr) bool {
return n.MType().IsStatus()
}
func (g *gen) writeExprAs(b *buffer, lhs *a.Expr, rhs *a.TypeExpr, depth uint32) error {
b.writes("((")
// TODO: watch for passing an array type to writeCTypeName? In C, an array
@@ -321,8 +335,6 @@ func (g *gen) writeExprUserDefinedCall(b *buffer, n *a.Expr, depth uint32) error
recvTyp, addr := recv.MType(), "&"
if p := recvTyp.Decorator(); p == t.IDNptr || p == t.IDPtr {
recvTyp, addr = recvTyp.Inner(), ""
} else if recvTyp.IsStatus() {
addr = ""
}
if recvTyp.Decorator() != 0 {
return fmt.Errorf("cannot generate user-defined method call %q for receiver type %q",
@@ -351,9 +363,11 @@ func (g *gen) writeCTypeName(b *buffer, n *a.TypeExpr, varNamePrefix string, var
o := n.Inner()
if o.Decorator() == 0 && o.QID() == (t.QID{t.IDBase, t.IDU8}) && !o.IsRefined() {
b.writes("wuffs_base__slice_u8")
b.writeb(' ')
b.writes(varNamePrefix)
b.writes(varName)
if varNamePrefix != "" {
b.writeb(' ')
b.writes(varNamePrefix)
b.writes(varName)
}
return nil
}
return fmt.Errorf("cannot convert Wuffs type %q to C", n.Str(g.tm))
@@ -362,9 +376,11 @@ func (g *gen) writeCTypeName(b *buffer, n *a.TypeExpr, varNamePrefix string, var
o := n.Inner()
if o.Decorator() == 0 && o.QID() == (t.QID{t.IDBase, t.IDU8}) && !o.IsRefined() {
b.writes("wuffs_base__table_u8")
b.writeb(' ')
b.writes(varNamePrefix)
b.writes(varName)
if varNamePrefix != "" {
b.writeb(' ')
b.writes(varNamePrefix)
b.writes(varName)
}
return nil
}
return fmt.Errorf("cannot convert Wuffs type %q to C", n.Str(g.tm))
@@ -408,9 +424,11 @@ func (g *gen) writeCTypeName(b *buffer, n *a.TypeExpr, varNamePrefix string, var
b.writeb('*')
}
b.writeb(' ')
b.writes(varNamePrefix)
b.writes(varName)
if varNamePrefix != "" {
b.writeb(' ')
b.writes(varNamePrefix)
b.writes(varName)
}
x = n
for ; x != nil && x.IsArrayType(); x = x.Inner() {

View File

@@ -67,25 +67,33 @@ func (g *gen) funcCName(n *a.Func) string {
// TODO: this isn't right if r[0] != 0, i.e. the receiver is from a
// used package. There might be similar cases elsewhere in this
// package.
return g.pkgPrefix + r.Str(g.tm) + "__" + n.FuncName().Str(g.tm)
return g.pkgPrefix + r[1].Str(g.tm) + "__" + n.FuncName().Str(g.tm)
}
return g.pkgPrefix + n.FuncName().Str(g.tm)
}
// C++ related function signature constants.
// writeFunctionSignature modes.
const (
cppNone = 0 // Not C++, just plain C.
cppInsideStruct = 1
cppOutsideStruct = 2
wfsCDecl = 0
wfsCppDecl = 1
wfsCFuncPtrField = 2
wfsCFuncPtrType = 3
)
func (g *gen) writeFuncSignature(b *buffer, n *a.Func, cpp uint32) error {
if cpp != cppNone {
func (g *gen) writeFuncSignature(b *buffer, n *a.Func, wfs uint32) error {
switch wfs {
case wfsCDecl:
if n.Public() {
b.writes("WUFFS_BASE__MAYBE_STATIC ")
} else {
b.writes("static ")
}
case wfsCppDecl:
b.writes("inline ")
} else if n.Public() {
b.writes("WUFFS_BASE__MAYBE_STATIC ")
} else {
b.writes("static ")
case wfsCFuncPtrField, wfsCFuncPtrType:
// No-op.
}
// TODO: write n's return values.
@@ -100,30 +108,41 @@ func (g *gen) writeFuncSignature(b *buffer, n *a.Func, cpp uint32) error {
// The empty // comment makes clang-format place the function name at the
// start of a line.
b.writes("//\n")
switch cpp {
case cppNone:
b.writes(g.funcCName(n))
case cppInsideStruct:
b.writes(n.FuncName().Str(g.tm))
case cppOutsideStruct:
b.writes(g.pkgPrefix)
b.writes(n.Receiver().Str(g.tm))
b.writes("::")
b.writes(n.FuncName().Str(g.tm))
if (wfs != wfsCFuncPtrField) && (wfs != wfsCFuncPtrType) {
b.writes("//\n")
}
b.writeb('(')
comma := false
if cpp == cppNone {
switch wfs {
case wfsCDecl:
b.writes(g.funcCName(n))
b.writeb('(')
if r := n.Receiver(); !r.IsZero() {
if n.Effect().Pure() {
b.writes("const ")
}
b.printf("%s%s *self", g.pkgPrefix, r.Str(g.tm))
b.printf("%s%s *self", g.pkgPrefix, r[1].Str(g.tm))
comma = true
}
case wfsCppDecl:
b.writes(n.FuncName().Str(g.tm))
b.writeb('(')
case wfsCFuncPtrField, wfsCFuncPtrType:
b.writes("(*")
if wfs == wfsCFuncPtrField {
b.writes(n.FuncName().Str(g.tm))
}
b.writes(")(")
if n.Effect().Pure() {
b.writes("const ")
}
b.writes("void*")
if wfs == wfsCFuncPtrField {
b.writes(" self")
}
comma = true
}
for _, o := range n.In().Fields() {
@@ -132,20 +151,24 @@ func (g *gen) writeFuncSignature(b *buffer, n *a.Func, cpp uint32) error {
}
comma = true
o := o.AsField()
if err := g.writeCTypeName(b, o.XType(), aPrefix, o.Name().Str(g.tm)); err != nil {
varNamePrefix, varName := "", ""
if wfs != wfsCFuncPtrType {
varNamePrefix, varName = aPrefix, o.Name().Str(g.tm)
}
if err := g.writeCTypeName(b, o.XType(), varNamePrefix, varName); err != nil {
return err
}
}
b.printf(")")
if cpp != cppNone && !n.Receiver().IsZero() && n.Effect().Pure() {
if (wfs == wfsCppDecl) && !n.Receiver().IsZero() && n.Effect().Pure() {
b.writes(" const ")
}
return nil
}
func (g *gen) writeFuncPrototype(b *buffer, n *a.Func) error {
if err := g.writeFuncSignature(b, n, cppNone); err != nil {
if err := g.writeFuncSignature(b, n, wfsCDecl); err != nil {
return err
}
b.writes(";\n\n")
@@ -156,7 +179,7 @@ func (g *gen) writeFuncImpl(b *buffer, n *a.Func) error {
k := g.funks[n.QQID()]
b.printf("// -------- func %s.%s\n\n", g.pkgName, n.QQID().Str(g.tm))
if err := g.writeFuncSignature(b, n, cppNone); err != nil {
if err := g.writeFuncSignature(b, n, wfsCDecl); err != nil {
return err
}
b.writes("{\n")
@@ -194,15 +217,16 @@ func (g *gen) gatherFuncImpl(_ *buffer, n *a.Func) error {
}
g.findDerivedVars()
if err := g.writeFuncImplBody(&g.currFunk.bBody); err != nil {
return err
}
if err := g.writeFuncImplPrologue(&g.currFunk.bPrologue); err != nil {
return err
}
if err := g.writeFuncImplBodyResume(&g.currFunk.bBodyResume); err != nil {
return err
}
if err := g.writeFuncImplBody(&g.currFunk.bBody); err != nil {
return err
}
if err := g.writeFuncImplBodySuspend(&g.currFunk.bBodySuspend); err != nil {
return err
}
@@ -217,7 +241,7 @@ func (g *gen) gatherFuncImpl(_ *buffer, n *a.Func) error {
return nil
}
func (g *gen) writeOutParamZeroValue(b *buffer, typ *a.TypeExpr) error {
func writeOutParamZeroValue(b *buffer, tm *t.Map, typ *a.TypeExpr) error {
if typ == nil {
b.writes("wuffs_base__make_empty_struct()")
return nil
@@ -251,38 +275,47 @@ func (g *gen) writeOutParamZeroValue(b *buffer, typ *a.TypeExpr) error {
return nil
}
}
return fmt.Errorf("internal error: cannot write the zero value of type %q", typ.Str(g.tm))
return fmt.Errorf("internal error: cannot write the zero value of type %q", typ.Str(tm))
}
func writeFuncImplSelfMagicCheck(b *buffer, tm *t.Map, f *a.Func) error {
returnsStatus := f.Effect().Coroutine() ||
((f.Out() != nil) && f.Out().IsStatus())
b.writes("if (!self) { return ")
if returnsStatus {
b.writes("wuffs_base__make_status(wuffs_base__error__bad_receiver)")
} else if err := writeOutParamZeroValue(b, tm, f.Out()); err != nil {
return err
}
b.writes(";}")
if f.Effect().Pure() {
b.writes("if ((self->private_impl.magic != WUFFS_BASE__MAGIC) &&")
b.writes(" (self->private_impl.magic != WUFFS_BASE__DISABLED)) {")
} else {
b.writes("if (self->private_impl.magic != WUFFS_BASE__MAGIC) {")
}
b.writes("return ")
if returnsStatus {
b.writes("wuffs_base__make_status(" +
"(self->private_impl.magic == WUFFS_BASE__DISABLED) " +
"? wuffs_base__error__disabled_by_previous_error " +
": wuffs_base__error__initialize_not_called)")
} else if err := writeOutParamZeroValue(b, tm, f.Out()); err != nil {
return err
}
b.writes(";}\n")
return nil
}
func (g *gen) writeFuncImplPrologue(b *buffer) error {
// Check the initialized/disabled state and the "self" arg.
if g.currFunk.astFunc.Public() && !g.currFunk.astFunc.Receiver().IsZero() {
out := g.currFunk.astFunc.Out()
b.writes("if (!self) { return ")
if g.currFunk.returnsStatus {
b.writes("wuffs_base__error__bad_receiver")
} else if err := g.writeOutParamZeroValue(b, out); err != nil {
if err := writeFuncImplSelfMagicCheck(b, g.tm, g.currFunk.astFunc); err != nil {
return err
}
b.writes(";}")
if g.currFunk.astFunc.Effect().Pure() {
b.writes("if ((self->private_impl.magic != WUFFS_BASE__MAGIC) &&")
b.writes(" (self->private_impl.magic != WUFFS_BASE__DISABLED)) {")
} else {
b.writes("if (self->private_impl.magic != WUFFS_BASE__MAGIC) {")
}
b.writes("return ")
if g.currFunk.returnsStatus {
b.writes("(self->private_impl.magic == WUFFS_BASE__DISABLED) " +
"? wuffs_base__error__disabled_by_previous_error " +
": wuffs_base__error__initialize_not_called")
} else if err := g.writeOutParamZeroValue(b, out); err != nil {
return err
}
b.writes(";}\n")
}
// For public functions, check (at runtime) the other args for bounds and
@@ -298,7 +331,7 @@ func (g *gen) writeFuncImplPrologue(b *buffer) error {
b.printf("if ((self->private_impl.active_coroutine != 0) && "+
"(self->private_impl.active_coroutine != %d)) {\n", g.currFunk.coroID)
b.writes("self->private_impl.magic = WUFFS_BASE__DISABLED;\n")
b.writes("return wuffs_base__error__interleaved_coroutine_calls;\n")
b.writes("return wuffs_base__make_status(wuffs_base__error__interleaved_coroutine_calls);\n")
b.writes("}\n")
b.writes("self->private_impl.active_coroutine = 0;\n")
}
@@ -307,7 +340,7 @@ func (g *gen) writeFuncImplPrologue(b *buffer) error {
if g.currFunk.astFunc.Effect().Coroutine() ||
(g.currFunk.returnsStatus && (len(g.currFunk.derivedVars) > 0)) {
// TODO: rename the "status" variable to "ret"?
b.printf("wuffs_base__status status = NULL;\n")
b.printf("wuffs_base__status status = wuffs_base__make_status(NULL);\n")
}
b.writes("\n")
@@ -330,7 +363,7 @@ func (g *gen) writeFuncImplPrologue(b *buffer) error {
}
func (g *gen) writeFuncImplBodyResume(b *buffer) error {
if g.currFunk.astFunc.Effect().Coroutine() {
if g.currFunk.coroSuspPoint > 0 {
// TODO: don't hard-code [0], and allow recursive coroutines.
b.printf("uint32_t coro_susp_point = self->private_impl.%s%s[0];\n",
pPrefix, g.currFunk.astFunc.FuncName().Str(g.tm))
@@ -358,7 +391,7 @@ func (g *gen) writeFuncImplBody(b *buffer) error {
}
func (g *gen) writeFuncImplBodySuspend(b *buffer) error {
if g.currFunk.astFunc.Effect().Coroutine() {
if g.currFunk.coroSuspPoint > 0 {
// We've reached the end of the function body. Reset the coroutine
// suspension point so that the next call to this function starts at
// the top.
@@ -370,16 +403,19 @@ func (g *gen) writeFuncImplBodySuspend(b *buffer) error {
b.writes("goto suspend;suspend:") // The goto avoids the "unused label" warning.
b.printf("self->private_impl.%s%s[0] = "+
"wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;\n",
"wuffs_base__status__is_suspension(&status) ? coro_susp_point : 0;\n",
pPrefix, g.currFunk.astFunc.FuncName().Str(g.tm))
if g.currFunk.astFunc.Public() {
b.printf("self->private_impl.active_coroutine = "+
"wuffs_base__status__is_suspension(status) ? %d : 0;\n", g.currFunk.coroID)
"wuffs_base__status__is_suspension(&status) ? %d : 0;\n", g.currFunk.coroID)
}
if err := g.writeResumeSuspend(b, &g.currFunk, true); err != nil {
return err
}
b.writes("\n")
} else if g.currFunk.astFunc.Effect().Coroutine() {
b.writes("\ngoto ok;ok:") // The goto avoids the "unused label" warning.
}
return nil
}
@@ -405,7 +441,7 @@ func (g *gen) writeFuncImplEpilogue(b *buffer) error {
(g.currFunk.returnsStatus && (len(g.currFunk.derivedVars) > 0)) {
if g.currFunk.astFunc.Public() {
b.writes("if (wuffs_base__status__is_error(status)) { " +
b.writes("if (wuffs_base__status__is_error(&status)) { " +
"self->private_impl.magic = WUFFS_BASE__DISABLED; }\n")
}
b.writes("return status;\n")
@@ -473,7 +509,7 @@ func (g *gen) writeFuncImplArgChecks(b *buffer, n *a.Func) error {
b.writes(") {")
b.writes("self->private_impl.magic = WUFFS_BASE__DISABLED;\n")
if g.currFunk.astFunc.Effect().Coroutine() {
b.writes("return wuffs_base__error__bad_argument;\n\n")
b.writes("return wuffs_base__make_status(wuffs_base__error__bad_argument);\n\n")
} else {
// TODO: don't assume that the return type is empty.
b.printf("return wuffs_base__make_empty_struct();\n")

View File

@@ -162,7 +162,7 @@ func (g *gen) writeStatementAssign0(b *buffer, op t.ID, lhs *a.Expr, rhs *a.Expr
}
if op != t.IDEqQuestion && rhs.Effect().Coroutine() {
b.writes("if (status) { goto suspend; }\n")
b.writes("if (status.repr) { goto suspend; }\n")
}
}
@@ -435,15 +435,15 @@ func (g *gen) writeStatementRet(b *buffer, n *a.Ret, depth uint32) error {
if g.currFunk.astFunc.Effect().Coroutine() ||
(g.currFunk.returnsStatus && (len(g.currFunk.derivedVars) > 0)) {
isOK := false
isComplete := false
b.writes("status = ")
if retExpr.Operator() == 0 && retExpr.Ident() == t.IDOk {
b.writes("NULL")
isOK = true
b.writes("wuffs_base__make_status(NULL)")
isComplete = true
} else {
if retExpr.Ident().IsStrLiteral(g.tm) {
msg, _ := t.Unescape(retExpr.Ident().Str(g.tm))
isOK = statusMsgIsWarning(msg)
isComplete = statusMsgIsNote(msg)
}
if err := g.writeExpr(
b, retExpr, depth); err != nil {
@@ -458,15 +458,15 @@ func (g *gen) writeStatementRet(b *buffer, n *a.Ret, depth uint32) error {
if n.RetsError() {
b.writes("goto exit;")
} else if isOK {
} else if isComplete {
g.currFunk.hasGotoOK = true
b.writes("goto ok;")
} else {
g.currFunk.hasGotoOK = true
// TODO: the "goto exit"s can be "goto ok".
b.writes("if (wuffs_base__status__is_error(status)) { goto exit; }" +
"else if (wuffs_base__status__is_suspension(status)) { " +
"status = wuffs_base__error__cannot_return_a_suspension; goto exit; } goto ok;")
b.writes("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;")
}
return nil
}

View File

@@ -287,7 +287,7 @@ func (g *gen) writeVars(b *buffer, f *funk, inStructDecl bool) error {
} else if typ.IsBool() {
b.writes(" = false;\n")
} else if typ.IsStatus() {
b.writes(" = NULL;\n")
b.writes(" = wuffs_base__make_status(NULL);\n")
} else if typ.IsIOType() {
b.printf(" = &%s%s;\n", uPrefix, name)
} else {

View File

@@ -887,33 +887,40 @@ func NewConst(flags Flags, filename string, line uint32, name t.ID, xType *TypeE
}
}
// Struct is "struct ID2(List0)" or "struct ID2?(List0)":
// MaxImplements is an advisory limit for the number of interfaces a Struct can
// implement.
const MaxImplements = 63
// Struct is "struct ID2? implements List0 (List1)":
// - FlagsPublic is "pub" vs "pri"
// - FlagsClassy is "ID2" vs "ID2?"
// - ID1: <0|pkg> (set by calling SetPackage)
// - ID2: name
// - List0: <Field> fields
// - List0: <TypeExpr> implements
// - List1: <Field> fields
//
// The question mark indicates a classy struct - one that supports methods,
// especially coroutines.
type Struct Node
func (n *Struct) AsNode() *Node { return (*Node)(n) }
func (n *Struct) Classy() bool { return n.flags&FlagsClassy != 0 }
func (n *Struct) Public() bool { return n.flags&FlagsPublic != 0 }
func (n *Struct) Filename() string { return n.filename }
func (n *Struct) Line() uint32 { return n.line }
func (n *Struct) QID() t.QID { return t.QID{n.id1, n.id2} }
func (n *Struct) Fields() []*Node { return n.list0 }
func (n *Struct) AsNode() *Node { return (*Node)(n) }
func (n *Struct) Classy() bool { return n.flags&FlagsClassy != 0 }
func (n *Struct) Public() bool { return n.flags&FlagsPublic != 0 }
func (n *Struct) Filename() string { return n.filename }
func (n *Struct) Line() uint32 { return n.line }
func (n *Struct) QID() t.QID { return t.QID{n.id1, n.id2} }
func (n *Struct) Implements() []*Node { return n.list0 }
func (n *Struct) Fields() []*Node { return n.list1 }
func NewStruct(flags Flags, filename string, line uint32, name t.ID, fields []*Node) *Struct {
func NewStruct(flags Flags, filename string, line uint32, name t.ID, implements []*Node, fields []*Node) *Struct {
return &Struct{
kind: KStruct,
flags: flags,
filename: filename,
line: line,
id2: name,
list0: fields,
list0: implements,
list1: fields,
}
}

View File

@@ -16,6 +16,12 @@
package builtin
import (
"fmt"
"strings"
"github.com/google/wuffs/lang/parse"
a "github.com/google/wuffs/lang/ast"
t "github.com/google/wuffs/lang/token"
)
@@ -25,7 +31,7 @@ var FourCCs = [...][2]string{
}
var Statuses = [...]string{
// Warnings.
// Notes.
`"@end of data"`,
`"@metadata reported"`,
@@ -41,6 +47,7 @@ var Statuses = [...]string{
`"#bad receiver"`,
`"#bad restart"`,
`"#bad sizeof receiver"`,
`"#bad vtable"`,
`"#bad workbuf length"`,
`"#bad wuffs version"`,
`"#cannot return a suspension"`,
@@ -80,8 +87,10 @@ var Types = []string{
"frame_config",
"image_config",
"pixel_blend",
"pixel_buffer",
"pixel_config",
"pixel_format",
"pixel_swizzler",
"decode_frame_options",
@@ -113,6 +122,7 @@ var Funcs = []string{
"utility.empty_io_reader() io_reader",
"utility.empty_io_writer() io_writer",
"utility.empty_slice_u8() slice u8",
"utility.make_pixel_format(repr: u32) pixel_format",
"utility.make_range_ii_u32(min_incl: u32, max_incl: u32) range_ii_u32",
"utility.make_range_ie_u32(min_incl: u32, max_excl: u32) range_ie_u32",
"utility.make_range_ii_u64(min_incl: u64, max_incl: u64) range_ii_u64",
@@ -225,13 +235,14 @@ var Funcs = []string{
"io_reader.since(mark: u64) slice u8",
"io_reader.take!(n: u64) slice u8",
"io_reader.skip?(n: u32)",
"io_reader.skip?(n: u64)",
"io_reader.skip32?(n: u32)",
// TODO: this should have explicit pre-conditions "actual <= worst_case"
// and "worst_case <= available()". As an implementation restriction, we
// also require that worst_case has a constant value. For now, that's all
// implicitly checked (i.e. hard coded).
"io_reader.skip_fast!(actual: u32, worst_case: u32)",
"io_reader.skip32_fast!(actual: u32, worst_case: u32)",
// ---- io_writer
@@ -280,24 +291,24 @@ var Funcs = []string{
"io_writer.since(mark: u64) slice u8",
"io_writer.copy_from_slice!(s: slice u8) u64",
"io_writer.copy_n_from_history!(n: u32, distance: u32) u32",
"io_writer.copy_n_from_reader!(n: u32, r: io_reader) u32",
"io_writer.copy_n_from_slice!(n: u32, s: slice u8) u32",
"io_writer.copy_n32_from_history!(n: u32, distance: u32) u32",
"io_writer.copy_n32_from_reader!(n: u32, r: io_reader) u32",
"io_writer.copy_n32_from_slice!(n: u32, s: slice u8) u32",
// TODO: this should have explicit pre-conditions:
// - n <= this.available()
// - distance > 0
// - distance <= this.since_mark().length()
// For now, that's all implicitly checked (i.e. hard coded).
"io_writer.copy_n_from_history_fast!(n: u32, distance: u32) u32",
"io_writer.copy_n32_from_history_fast!(n: u32, distance: u32) u32",
// ---- status
// TODO: should we add is_complete?
"status.is_error() bool",
"status.is_note() bool",
"status.is_ok() bool",
"status.is_suspension() bool",
"status.is_warning() bool",
// ---- frame_config
// Duration's upper bound is the maximum possible i64 value.
@@ -308,51 +319,149 @@ var Funcs = []string{
"frame_config.index() u64",
"frame_config.io_position() u64",
"frame_config.update!(bounds: rect_ie_u32, duration: u64[..= 0x7FFFFFFFFFFFFFFF], " +
"index: u64, io_position: u64, blend: u8, disposal: u8, background_color: u32)",
"frame_config.update!(bounds: rect_ie_u32, duration: u64[..= 0x7FFFFFFFFFFFFFFF]," +
"index: u64, io_position: u64, disposal: u8, opaque_within_bounds: bool," +
"overwrite_instead_of_blend: bool, background_color: u32)",
// ---- image_config
"image_config.set!(pixfmt: u32, pixsub: u32, width: u32, height: u32, " +
"image_config.set!(pixfmt: u32, pixsub: u32, width: u32, height: u32," +
"first_frame_io_position: u64, first_frame_is_opaque: bool)",
// ---- pixel_buffer
"pixel_buffer.palette() slice u8",
"pixel_buffer.pixel_format() u32",
"pixel_buffer.pixel_format() pixel_format",
"pixel_buffer.plane(p: u32[..= 3]) table u8",
// ---- pixel_format
"pixel_format.bits_per_pixel() u32",
// ---- pixel_swizzler
"pixel_swizzler.prepare!(" +
"dst_pixfmt: u32, dst_palette: slice u8, src_pixfmt: u32, src_palette: slice u8) status",
"dst_pixfmt: pixel_format, dst_palette: slice u8," +
"src_pixfmt: pixel_format, src_palette: slice u8, blend: pixel_blend) status",
"pixel_swizzler.swizzle_interleaved!(" +
"dst: slice u8, dst_palette: slice u8, src: slice u8) u64",
}
var Interfaces = []string{
"hasher_u32",
"image_decoder",
"io_transformer",
}
var InterfacesMap = map[string]bool{
"hasher_u32": true,
"image_decoder": true,
"io_transformer": true,
}
var InterfaceFuncs = []string{
// ---- hasher_u32
"hasher_u32.update_u32!(x: slice u8) u32",
// ---- image_decoder
"image_decoder.ack_metadata_chunk?(src: io_reader)",
"image_decoder.decode_frame?(" +
"dst: ptr pixel_buffer, src: io_reader, blend: pixel_blend," +
"workbuf: slice u8, opts: nptr decode_frame_options)",
"image_decoder.decode_frame_config?(dst: nptr frame_config, src: io_reader)",
"image_decoder.decode_image_config?(dst: nptr image_config, src: io_reader)",
"image_decoder.frame_dirty_rect() rect_ie_u32",
"image_decoder.metadata_chunk_length() u64",
"image_decoder.metadata_fourcc() u32",
"image_decoder.num_animation_loops() u32",
"image_decoder.num_decoded_frame_configs() u64",
"image_decoder.num_decoded_frames() u64",
"image_decoder.restart_frame!(index: u64, io_position: u64) status",
"image_decoder.set_report_metadata!(fourcc: u32, report: bool)",
"image_decoder.workbuf_len() range_ii_u64",
// ---- io_transformer
"io_transformer.transform_io?(dst: io_writer, src: io_reader, workbuf: slice u8)",
"io_transformer.workbuf_len() range_ii_u64",
}
// The "T1" and "T2" types here are placeholders for generic "slice T" or
// "table T" types. After tokenizing (but before parsing) these XxxFunc strings
// (e.g. in the lang/check package), replace "T1" and "T2" with "†" or "‡"
// daggers, to avoid collision with a user-defined "T1" or "T2" type.
const (
GenericOldName1 = t.IDT1
GenericOldName2 = t.IDT2
GenericNewName1 = t.IDDagger1
GenericNewName2 = t.IDDagger2
genericOldName1 = t.IDT1
genericOldName2 = t.IDT2
genericNewName1 = t.IDDagger1
genericNewName2 = t.IDDagger2
)
var SliceFuncs = []string{
"T1.copy_from_slice!(s: T1) u64",
"T1.length() u64",
"T1.prefix(up_to: u64) T1",
"T1.suffix(up_to: u64) T1",
"GENERIC T1.copy_from_slice!(s: T1) u64",
"GENERIC T1.length() u64",
"GENERIC T1.prefix(up_to: u64) T1",
"GENERIC T1.suffix(up_to: u64) T1",
}
var TableFuncs = []string{
"T2.height() u64",
"T2.stride() u64",
"T2.width() u64",
"GENERIC T2.height() u64",
"GENERIC T2.stride() u64",
"GENERIC T2.width() u64",
"T2.row(y: u32) T1",
"GENERIC T2.row(y: u32) T1",
}
func ParseFuncs(tm *t.Map, ss []string, callback func(*a.Func) error) error {
const GENERIC = "GENERIC "
buf := []byte(nil)
for _, s := range ss {
generic := strings.HasPrefix(s, GENERIC)
if generic {
s = s[len(GENERIC):]
}
buf = buf[:0]
buf = append(buf, "pub func "...)
buf = append(buf, s...)
buf = append(buf, "{}\n"...)
const filename = "builtin.wuffs"
tokens, _, err := t.Tokenize(tm, filename, buf)
if err != nil {
return fmt.Errorf("parsing %q: could not tokenize built-in funcs: %v", s, err)
}
if generic {
for i := range tokens {
if id := tokens[i].ID; id == genericOldName1 {
tokens[i].ID = genericNewName1
} else if id == genericOldName2 {
tokens[i].ID = genericNewName2
}
}
}
file, err := parse.Parse(tm, filename, tokens, &parse.Options{
AllowBuiltInNames: true,
})
if err != nil {
return fmt.Errorf("parsing %q: could not parse built-in funcs: %v", s, err)
}
tlds := file.TopLevelDecls()
if len(tlds) != 1 || tlds[0].Kind() != a.KFunc {
return fmt.Errorf("parsing %q: got %d top level decls, want %d", s, len(tlds), 1)
}
f := tlds[0].AsFunc()
f.AsNode().AsRaw().SetPackage(tm, t.IDBase)
if callback != nil {
if err := callback(f); err != nil {
return err
}
}
}
return nil
}

View File

@@ -1045,12 +1045,12 @@ func (q *checker) bcheckExprCallSpecialCases(n *a.Expr, depth uint32) (bounds, e
return bounds{}, err
}
} else if method == t.IDCopyNFromHistoryFast {
if err := q.canCopyNFromHistoryFast(recv, n.Args()); err != nil {
} else if method == t.IDCopyN32FromHistoryFast {
if err := q.canCopyN32FromHistoryFast(recv, n.Args()); err != nil {
return bounds{}, err
}
} else if method == t.IDSkipFast {
} else if method == t.IDSkip32Fast {
args := n.Args()
if len(args) != 2 {
return bounds{}, fmt.Errorf("check: internal error: bad skip_fast arguments")
@@ -1112,7 +1112,7 @@ func (q *checker) canUndoByte(recv *a.Expr) error {
return fmt.Errorf("check: could not prove %s.can_undo_byte()", recv.Str(q.tm))
}
func (q *checker) canCopyNFromHistoryFast(recv *a.Expr, args []*a.Node) error {
func (q *checker) canCopyN32FromHistoryFast(recv *a.Expr, args []*a.Node) error {
// As per cgen's io-private.h, there are three pre-conditions:
// - n <= this.available()
// - distance > 0

View File

@@ -20,6 +20,7 @@ import (
"errors"
"fmt"
"path"
"sort"
"github.com/google/wuffs/lang/builtin"
"github.com/google/wuffs/lang/parse"
@@ -83,29 +84,48 @@ func Check(tm *t.Map, files []*a.File, resolveUse func(usePath string) ([]byte,
}
}
c := &Checker{
tm: tm,
resolveUse: resolveUse,
reasonMap: rMap,
consts: map[t.QID]*a.Const{},
funcs: map[t.QQID]*a.Func{},
localVars: map[t.QQID]typeMap{},
statuses: map[t.QID]*a.Status{},
structs: map[t.QID]*a.Struct{},
tm: tm,
resolveUse: resolveUse,
reasonMap: rMap,
consts: map[t.QID]*a.Const{},
funcs: map[t.QQID]*a.Func{},
localVars: map[t.QQID]typeMap{},
statuses: map[t.QID]*a.Status{},
structs: map[t.QID]*a.Struct{},
useBaseNames: map[t.ID]struct{}{},
builtInSliceFuncs: map[t.QQID]*a.Func{},
builtInTableFuncs: map[t.QQID]*a.Func{},
builtInInterfaces: map[t.QID][]t.QQID{},
builtInInterfaceFuncs: map[t.QQID]*a.Func{},
unseenInterfaceImpls: map[t.QQID]*a.Func{},
}
_, err := c.parseBuiltInFuncs(builtin.Funcs, false)
if err != nil {
if err := c.parseBuiltInFuncs(nil, builtin.Funcs); err != nil {
return nil, err
}
c.builtInSliceFuncs, err = c.parseBuiltInFuncs(builtin.SliceFuncs, true)
if err != nil {
if err := c.parseBuiltInFuncs(c.builtInSliceFuncs, builtin.SliceFuncs); err != nil {
return nil, err
}
c.builtInTableFuncs, err = c.parseBuiltInFuncs(builtin.TableFuncs, true)
if err != nil {
if err := c.parseBuiltInFuncs(c.builtInTableFuncs, builtin.TableFuncs); err != nil {
return nil, err
}
if err := c.parseBuiltInFuncs(c.builtInInterfaceFuncs, builtin.InterfaceFuncs); err != nil {
return nil, err
}
for qqid := range c.builtInInterfaceFuncs {
qid := t.QID{qqid[0], qqid[1]}
c.builtInInterfaces[qid] = append(c.builtInInterfaces[qid], qqid)
}
for _, qqids := range c.builtInInterfaces {
sort.Slice(qqids, func(i int, j int) bool {
return qqids[i].LessThan(qqids[j])
})
}
for _, z := range builtin.Statuses {
id, err := tm.Insert(z)
@@ -150,7 +170,9 @@ var phases = [...]struct {
{a.KStruct, (*Checker).checkStructFields},
{a.KFunc, (*Checker).checkFuncSignature},
{a.KFunc, (*Checker).checkFuncContract},
{a.KFunc, (*Checker).checkFuncImplements},
{a.KFunc, (*Checker).checkFuncBody},
{a.KInvalid, (*Checker).checkInterfacesSatisfied},
{a.KStruct, (*Checker).checkFieldMethodCollisions},
{a.KInvalid, (*Checker).checkAllTypeChecked},
// TODO: check consts, funcs, structs and uses for name collisions.
@@ -177,7 +199,12 @@ type Checker struct {
builtInSliceFuncs map[t.QQID]*a.Func
builtInTableFuncs map[t.QQID]*a.Func
unsortedStructs []*a.Struct
builtInInterfaces map[t.QID][]t.QQID
builtInInterfaceFuncs map[t.QQID]*a.Func
unseenInterfaceImpls map[t.QQID]*a.Func
unsortedStructs []*a.Struct
}
func (c *Checker) checkUse(node *a.Node) error {
@@ -327,7 +354,7 @@ func (c *Checker) checkConstElement(n *a.Expr, nb bounds, nLists int) error {
return nil
}
if cv := n.ConstValue(); cv == nil || cv.Cmp(nb[0]) < 0 || cv.Cmp(nb[1]) > 0 {
return fmt.Errorf("invalid const value %q not within %v", n.Str(c.tm), nb)
return fmt.Errorf("check: invalid const value %q not within %v", n.Str(c.tm), nb)
}
return nil
}
@@ -348,8 +375,37 @@ func (c *Checker) checkStructDecl(node *a.Node) error {
c.unsortedStructs = append(c.unsortedStructs, n)
setPlaceholderMBoundsMType(n.AsNode())
// Add entries to c.unseenInterfaceImpls that later stages remove, checking
// that the concrete type (in this package) actually implements the
// interfaces that it claims to.
for _, o := range n.Implements() {
// For example, qid and ifaceType could be "<>.hasher" (i.e. defined in
// this package, not the base package) and "base.hasher_u32".
//
// The "<>" denotes an empty element of a t.QID or t.QQID.
o := o.AsTypeExpr()
ifaceType := o.QID()
if (o.Decorator() != 0) || (ifaceType[0] != t.IDBase) ||
!builtin.InterfacesMap[ifaceType[1].Str(c.tm)] {
return fmt.Errorf("check: invalid interface type %q", o.Str(c.tm))
}
o.AsNode().SetMBounds(bounds{zero, zero})
o.AsNode().SetMType(typeExprTypeExpr)
if qid[0] != 0 {
continue
}
for _, ifaceFunc := range c.builtInInterfaces[ifaceType] {
// Continuing the example, ifaceFunc could be
// "base.hasher_u32.update_u32".
c.unseenInterfaceImpls[t.QQID{qid[0], qid[1], ifaceFunc[2]}] =
c.builtInInterfaceFuncs[ifaceFunc]
}
}
// A struct declaration implies a reset method.
in := a.NewStruct(0, n.Filename(), n.Line(), t.IDArgs, nil)
in := a.NewStruct(0, n.Filename(), n.Line(), t.IDArgs, nil, nil)
f := a.NewFunc(a.EffectImpure.AsFlags(), n.Filename(), n.Line(), qid[1], t.IDReset, in, nil, nil, nil)
if qid[0] != 0 {
f.AsNode().AsRaw().SetPackage(c.tm, qid[0])
@@ -529,6 +585,37 @@ func (c *Checker) checkFuncContract(node *a.Node) error {
return nil
}
func (c *Checker) checkFuncImplements(node *a.Node) error {
n := node.AsFunc()
o := c.unseenInterfaceImpls[n.QQID()]
if o == nil {
return nil
}
if (n.Effect() != o.Effect()) || !n.Out().Eq(o.Out()) {
return nil
}
// Check that the args (the implicit In types) match.
nArgs := n.In().Fields()
oArgs := o.In().Fields()
if len(nArgs) != len(oArgs) {
return nil
}
for i := range nArgs {
na := nArgs[i].AsField()
oa := oArgs[i].AsField()
if na.Name() != oa.Name() || !na.XType().Eq(oa.XType()) {
return nil
}
}
// TODO: check that n.Asserts() matches o.Asserts().
delete(c.unseenInterfaceImpls, n.QQID())
return nil
}
func (c *Checker) checkFuncBody(node *a.Node) error {
n := node.AsFunc()
if len(n.Body()) == 0 {
@@ -577,6 +664,30 @@ func (c *Checker) checkFuncBody(node *a.Node) error {
return nil
}
func (c *Checker) checkInterfacesSatisfied(node *a.Node) error {
if len(c.unseenInterfaceImpls) == 0 {
return nil
}
// Pick the largest t.QQID key, despite randomized map iteration order, for
// deterministic error messages. The zero-valued t.QQID is LessThan any
// non-zero value.
method, iface := t.QQID{}, t.QID{}
for qqid, f := range c.unseenInterfaceImpls {
if method.LessThan(qqid) {
fqqid := f.QQID()
method, iface = qqid, t.QID{fqqid[0], fqqid[1]}
}
}
// For example, at the end of the loop above, method and iface could be
// "<>.hasher.update_u32" and "base.hasher_u32".
//
// The "<>" denotes an empty element of a t.QID or t.QQID.
return fmt.Errorf("check: %q does not implement %q: no matching %q method",
method[1].Str(c.tm), iface.Str(c.tm), method[2].Str(c.tm))
}
func (c *Checker) checkFieldMethodCollisions(node *a.Node) error {
n := node.AsStruct()
for _, o := range n.Fields() {

View File

@@ -18,7 +18,6 @@ import (
"fmt"
"github.com/google/wuffs/lang/builtin"
"github.com/google/wuffs/lang/parse"
a "github.com/google/wuffs/lang/ast"
t "github.com/google/wuffs/lang/token"
@@ -61,8 +60,10 @@ var (
typeExprFrameConfig = a.NewTypeExpr(0, t.IDBase, t.IDFrameConfig, nil, nil, nil)
typeExprImageConfig = a.NewTypeExpr(0, t.IDBase, t.IDImageConfig, nil, nil, nil)
typeExprPixelBlend = a.NewTypeExpr(0, t.IDBase, t.IDPixelBlend, nil, nil, nil)
typeExprPixelBuffer = a.NewTypeExpr(0, t.IDBase, t.IDPixelBuffer, nil, nil, nil)
typeExprPixelConfig = a.NewTypeExpr(0, t.IDBase, t.IDPixelConfig, nil, nil, nil)
typeExprPixelFormat = a.NewTypeExpr(0, t.IDBase, t.IDPixelFormat, nil, nil, nil)
typeExprPixelSwizzler = a.NewTypeExpr(0, t.IDBase, t.IDPixelSwizzler, nil, nil, nil)
typeExprDecodeFrameOptions = a.NewTypeExpr(0, t.IDBase, t.IDDecodeFrameOptions, nil, nil, nil)
@@ -102,62 +103,25 @@ var builtInTypeMap = typeMap{
t.IDFrameConfig: typeExprFrameConfig,
t.IDImageConfig: typeExprImageConfig,
t.IDPixelBlend: typeExprPixelBlend,
t.IDPixelBuffer: typeExprPixelBuffer,
t.IDPixelConfig: typeExprPixelConfig,
t.IDPixelFormat: typeExprPixelFormat,
t.IDPixelSwizzler: typeExprPixelSwizzler,
t.IDDecodeFrameOptions: typeExprDecodeFrameOptions,
}
func (c *Checker) parseBuiltInFuncs(ss []string, generic bool) (map[t.QQID]*a.Func, error) {
m := map[t.QQID]*a.Func(nil)
if generic {
m = map[t.QQID]*a.Func{}
}
buf := []byte(nil)
for _, s := range ss {
buf = buf[:0]
buf = append(buf, "pub func "...)
buf = append(buf, s...)
buf = append(buf, "{}\n"...)
const filename = "builtin.wuffs"
tokens, _, err := t.Tokenize(c.tm, filename, buf)
if err != nil {
return nil, fmt.Errorf("check: parsing %q: could not tokenize built-in funcs: %v", s, err)
}
if generic {
for i := range tokens {
if tokens[i].ID == builtin.GenericOldName1 {
tokens[i].ID = builtin.GenericNewName1
} else if tokens[i].ID == builtin.GenericOldName2 {
tokens[i].ID = builtin.GenericNewName2
}
}
}
file, err := parse.Parse(c.tm, filename, tokens, &parse.Options{
AllowBuiltInNames: true,
})
if err != nil {
return nil, fmt.Errorf("check: parsing %q: could not parse built-in funcs: %v", s, err)
}
tlds := file.TopLevelDecls()
if len(tlds) != 1 || tlds[0].Kind() != a.KFunc {
return nil, fmt.Errorf("check: parsing %q: got %d top level decls, want %d", s, len(tlds), 1)
}
f := tlds[0].AsFunc()
f.AsNode().AsRaw().SetPackage(c.tm, t.IDBase)
func (c *Checker) parseBuiltInFuncs(m map[t.QQID]*a.Func, ss []string) error {
return builtin.ParseFuncs(c.tm, ss, func(f *a.Func) error {
if err := c.checkFuncSignature(f.AsNode()); err != nil {
return nil, err
return err
}
if m != nil {
m[f.QQID()] = f
}
}
return m, nil
return nil
})
}
func (c *Checker) resolveFunc(typ *a.TypeExpr) (*a.Func, error) {

View File

@@ -30,7 +30,7 @@ import (
t "github.com/google/wuffs/lang/token"
)
type Generator func(packageName string, tm *t.Map, c *check.Checker, files []*a.File) ([]byte, error)
type Generator func(packageName string, tm *t.Map, files []*a.File) ([]byte, error)
func Do(flags *flag.FlagSet, args []string, g Generator) error {
packageName := flags.String("package_name", "", "the package name of the Wuffs input code")
@@ -41,7 +41,7 @@ func Do(flags *flag.FlagSet, args []string, g Generator) error {
if *packageName == "base" && len(flags.Args()) == 0 {
var err error
out, err = g("base", nil, nil, nil)
out, err = g("base", nil, nil)
if err != nil {
return err
}
@@ -58,12 +58,11 @@ func Do(flags *flag.FlagSet, args []string, g Generator) error {
return err
}
c, err := check.Check(tm, files, resolveUse)
if err != nil {
if _, err := check.Check(tm, files, resolveUse); err != nil {
return err
}
out, err = g(pkgName, tm, c, files)
out, err = g(pkgName, tm, files)
if err != nil {
return err
}

View File

@@ -217,7 +217,7 @@ func (p *parser) parseTopLevelDecl() (*a.Node, error) {
}
p.src = p.src[1:]
p.funcEffect = 0
in := a.NewStruct(0, p.filename, line, t.IDArgs, argFields)
in := a.NewStruct(0, p.filename, line, t.IDArgs, nil, argFields)
return a.NewFunc(flags, p.filename, line, id0, id1, in, out, asserts, body).AsNode(), nil
case t.IDStatus:
@@ -255,6 +255,19 @@ func (p *parser) parseTopLevelDecl() (*a.Node, error) {
flags |= a.FlagsClassy
p.src = p.src[1:]
}
implements := []*a.Node(nil)
if p.peek1() == t.IDImplements {
p.src = p.src[1:]
implements, err = p.parseList(t.IDOpenParen, (*parser).parseQualifiedIdentNode)
if err != nil {
return nil, err
}
if len(implements) > a.MaxImplements {
return nil, fmt.Errorf(`parse: too many implements listed at %s:%d`, p.filename, p.line())
}
}
fields, err := p.parseList(t.IDCloseParen, (*parser).parseFieldNode)
if err != nil {
return nil, err
@@ -271,12 +284,20 @@ func (p *parser) parseTopLevelDecl() (*a.Node, error) {
return nil, fmt.Errorf(`parse: expected (implicit) ";", got %q at %s:%d`, got, p.filename, p.line())
}
p.src = p.src[1:]
return a.NewStruct(flags, p.filename, line, name, fields).AsNode(), nil
return a.NewStruct(flags, p.filename, line, name, implements, fields).AsNode(), nil
}
}
return nil, fmt.Errorf(`parse: unrecognized top level declaration at %s:%d`, p.filename, line)
}
func (p *parser) parseQualifiedIdentNode() (*a.Node, error) {
pkg, name, err := p.parseQualifiedIdent()
if err != nil {
return nil, err
}
return a.NewTypeExpr(0, pkg, name, nil, nil, nil).AsNode(), nil
}
// parseQualifiedIdent parses "foo.bar" or "bar".
func (p *parser) parseQualifiedIdent() (t.ID, t.ID, error) {
x, err := p.parseIdent()

View File

@@ -147,7 +147,7 @@ func Render(w io.Writer, tm *t.Map, src []t.Token, comments []string) (err error
if prevID == t.IDEq || (prevID != 0 && !prevIsTightRight && !tok.ID.IsTightLeft()) {
// The "(" token's tight-left-ness is context dependent. For
// "f(x)", the "(" is tight-left. For "a * (b + c)", it is not.
if tok.ID != t.IDOpenParen || !isCloseIdentStrLiteral(tm, prevID) {
if tok.ID != t.IDOpenParen || !isCloseIdentStrLiteralQuestion(tm, prevID) {
buf = append(buf, ' ')
}
}
@@ -164,8 +164,6 @@ func Render(w io.Writer, tm *t.Map, src []t.Token, comments []string) (err error
return errors.New("render: too many \"}\" tokens")
}
indent--
} else if (tok.ID == t.IDQuestion) && (prevID == t.IDYield) {
buf = append(buf, ' ')
}
prevIsTightRight = tok.ID.IsTightRight()
@@ -248,8 +246,8 @@ func isCloseIdentLiteral(tm *t.Map, x t.ID) bool {
return x.IsClose() || x.IsIdent(tm) || x.IsLiteral(tm)
}
func isCloseIdentStrLiteral(tm *t.Map, x t.ID) bool {
return x.IsClose() || x.IsIdent(tm) || x.IsStrLiteral(tm)
func isCloseIdentStrLiteralQuestion(tm *t.Map, x t.ID) bool {
return x.IsClose() || x.IsIdent(tm) || x.IsStrLiteral(tm) || (x == t.IDQuestion)
}
func measureVarNameLength(tm *t.Map, lineTokens []t.Token, remaining []t.Token) uint32 {

View File

@@ -149,6 +149,13 @@ type QID [2]ID
func (x QID) IsZero() bool { return x == QID{} }
func (x QID) LessThan(y QID) bool {
if x[0] != y[0] {
return x[0] < y[0]
}
return x[1] < y[1]
}
// Str returns a string form of x.
func (x QID) Str(m *Map) string {
if x[0] != 0 {
@@ -162,6 +169,16 @@ type QQID [3]ID
func (x QQID) IsZero() bool { return x == QQID{} }
func (x QQID) LessThan(y QQID) bool {
if x[0] != y[0] {
return x[0] < y[0]
}
if x[1] != y[1] {
return x[1] < y[1]
}
return x[2] < y[2]
}
// Str returns a string form of x.
func (x QQID) Str(m *Map) string {
if x[0] != 0 {
@@ -344,28 +361,29 @@ const (
minKeyword = 0xA0
maxKeyword = 0xBF
IDAssert = ID(0xA0)
IDBreak = ID(0xA1)
IDConst = ID(0xA2)
IDContinue = ID(0xA3)
IDElse = ID(0xA4)
IDFunc = ID(0xA5)
IDIOBind = ID(0xA6)
IDIOLimit = ID(0xA7)
IDIf = ID(0xA8)
IDInv = ID(0xA9)
IDIterate = ID(0xAA)
IDPost = ID(0xAB)
IDPre = ID(0xAC)
IDPri = ID(0xAD)
IDPub = ID(0xAE)
IDReturn = ID(0xAF)
IDStruct = ID(0xB0)
IDUse = ID(0xB1)
IDVar = ID(0xB2)
IDVia = ID(0xB3)
IDWhile = ID(0xB4)
IDYield = ID(0xB5)
IDAssert = ID(0xA0)
IDBreak = ID(0xA1)
IDConst = ID(0xA2)
IDContinue = ID(0xA3)
IDElse = ID(0xA4)
IDFunc = ID(0xA5)
IDIOBind = ID(0xA6)
IDIOLimit = ID(0xA7)
IDIf = ID(0xA8)
IDImplements = ID(0xA9)
IDInv = ID(0xAA)
IDIterate = ID(0xAB)
IDPost = ID(0xAC)
IDPre = ID(0xAD)
IDPri = ID(0xAE)
IDPub = ID(0xAF)
IDReturn = ID(0xB0)
IDStruct = ID(0xB1)
IDUse = ID(0xB2)
IDVar = ID(0xB3)
IDVia = ID(0xB4)
IDWhile = ID(0xB5)
IDYield = ID(0xB6)
)
const (
@@ -460,9 +478,11 @@ const (
IDFrameConfig = ID(0x150)
IDImageConfig = ID(0x151)
IDPixelBuffer = ID(0x152)
IDPixelConfig = ID(0x153)
IDPixelSwizzler = ID(0x154)
IDPixelBlend = ID(0x152)
IDPixelBuffer = ID(0x153)
IDPixelConfig = ID(0x154)
IDPixelFormat = ID(0x155)
IDPixelSwizzler = ID(0x156)
IDDecodeFrameOptions = ID(0x158)
@@ -473,14 +493,15 @@ const (
IDPosition = ID(0x164)
IDSince = ID(0x165)
IDSkip = ID(0x166)
IDSkipFast = ID(0x167)
IDTake = ID(0x168)
IDSkip32 = ID(0x167)
IDSkip32Fast = ID(0x168)
IDTake = ID(0x169)
IDCopyFromSlice = ID(0x170)
IDCopyNFromHistory = ID(0x171)
IDCopyNFromHistoryFast = ID(0x172)
IDCopyNFromReader = ID(0x173)
IDCopyNFromSlice = ID(0x174)
IDCopyFromSlice = ID(0x170)
IDCopyN32FromHistory = ID(0x171)
IDCopyN32FromHistoryFast = ID(0x172)
IDCopyN32FromReader = ID(0x173)
IDCopyN32FromSlice = ID(0x174)
// -------- 0x180 block.
@@ -686,28 +707,29 @@ var builtInsByID = [nBuiltInIDs]string{
IDNot: "not",
IDAssert: "assert",
IDBreak: "break",
IDConst: "const",
IDContinue: "continue",
IDElse: "else",
IDFunc: "func",
IDIOBind: "io_bind",
IDIOLimit: "io_limit",
IDIf: "if",
IDInv: "inv",
IDIterate: "iterate",
IDPost: "post",
IDPre: "pre",
IDPri: "pri",
IDPub: "pub",
IDReturn: "return",
IDStruct: "struct",
IDUse: "use",
IDVar: "var",
IDVia: "via",
IDWhile: "while",
IDYield: "yield",
IDAssert: "assert",
IDBreak: "break",
IDConst: "const",
IDContinue: "continue",
IDElse: "else",
IDFunc: "func",
IDIOBind: "io_bind",
IDIOLimit: "io_limit",
IDIf: "if",
IDImplements: "implements",
IDInv: "inv",
IDIterate: "iterate",
IDPost: "post",
IDPre: "pre",
IDPri: "pri",
IDPub: "pub",
IDReturn: "return",
IDStruct: "struct",
IDUse: "use",
IDVar: "var",
IDVia: "via",
IDWhile: "while",
IDYield: "yield",
IDArray: "array",
IDNptr: "nptr",
@@ -799,8 +821,10 @@ var builtInsByID = [nBuiltInIDs]string{
IDFrameConfig: "frame_config",
IDImageConfig: "image_config",
IDPixelBlend: "pixel_blend",
IDPixelBuffer: "pixel_buffer",
IDPixelConfig: "pixel_config",
IDPixelFormat: "pixel_format",
IDPixelSwizzler: "pixel_swizzler",
IDDecodeFrameOptions: "decode_frame_options",
@@ -812,14 +836,15 @@ var builtInsByID = [nBuiltInIDs]string{
IDPosition: "position",
IDSince: "since",
IDSkip: "skip",
IDSkipFast: "skip_fast",
IDSkip32: "skip32",
IDSkip32Fast: "skip32_fast",
IDTake: "take",
IDCopyFromSlice: "copy_from_slice",
IDCopyNFromHistory: "copy_n_from_history",
IDCopyNFromHistoryFast: "copy_n_from_history_fast",
IDCopyNFromReader: "copy_n_from_reader",
IDCopyNFromSlice: "copy_n_from_slice",
IDCopyFromSlice: "copy_from_slice",
IDCopyN32FromHistory: "copy_n32_from_history",
IDCopyN32FromHistoryFast: "copy_n32_from_history_fast",
IDCopyN32FromReader: "copy_n32_from_reader",
IDCopyN32FromSlice: "copy_n32_from_slice",
// -------- 0x180 block.
@@ -1205,7 +1230,6 @@ var isTightRight = [...]bool{
IDOpenParen: true,
IDOpenBracket: true,
IDDot: true,
IDExclam: true,
IDQuestion: true,
IDDot: true,
IDExclam: true,
}

View File

@@ -346,6 +346,12 @@ func (c *WriterRecycler) Close() error {
return nil
}
func minDstLenForBlockMaxLen() uint64 {
return uint64(C.cgolz4_compress_min_dst_len(C.uint32_t(blockMaxLen)))
}
const writerBufLen = 2*blockMaxLen + 16
// Writer compresses to the lz4 format.
//
// Compressed bytes may be buffered and not sent to the underlying io.Writer
@@ -353,7 +359,7 @@ func (c *WriterRecycler) Close() error {
//
// The zero value is not usable until Reset is called.
type Writer struct {
buf [2 * blockMaxLen]byte
buf [writerBufLen]byte
j uint32
w io.Writer
begun bool

View File

@@ -89,3 +89,9 @@ func TestRoundTrip(tt *testing.T) {
}
}
}
func TestWriterBufIsLargeEnough(tt *testing.T) {
if m := minDstLenForBlockMaxLen(); writerBufLen < m {
tt.Fatalf("writerBufLen: got %d, want >= %d", writerBufLen, m)
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -227,10 +227,10 @@ const char* process_png_chunks(uint8_t* p, size_t n) {
const char* decode_once(bool frag_dst, bool frag_idat) {
wuffs_zlib__decoder dec;
const char* status =
wuffs_base__status status =
wuffs_zlib__decoder__initialize(&dec, sizeof dec, WUFFS_VERSION, 0);
if (status) {
return status;
if (!wuffs_base__status__is_ok(&status)) {
return wuffs_base__status__message(&status);
}
wuffs_base__io_buffer dst = ((wuffs_base__io_buffer){
@@ -251,8 +251,6 @@ const char* decode_once(bool frag_dst, bool frag_idat) {
.closed = true,
}),
});
wuffs_base__io_writer dst_writer = wuffs_base__io_buffer__writer(&dst);
wuffs_base__io_reader idat_reader = wuffs_base__io_buffer__reader(&idat);
uint32_t i = 0; // Number of dst fragments processed, if frag_dst.
if (frag_dst) {
@@ -266,30 +264,29 @@ const char* decode_once(bool frag_dst, bool frag_idat) {
}
while (true) {
status =
wuffs_zlib__decoder__decode_io_writer(&dec, dst_writer, idat_reader,
((wuffs_base__slice_u8){
.ptr = work_buffer,
.len = WORK_BUFFER_SIZE,
}));
status = wuffs_zlib__decoder__transform_io(&dec, &dst, &idat,
((wuffs_base__slice_u8){
.ptr = work_buffer,
.len = WORK_BUFFER_SIZE,
}));
if (!status) {
if (wuffs_base__status__is_ok(&status)) {
break;
}
if ((status == wuffs_base__suspension__short_write) && frag_dst &&
if ((status.repr == wuffs_base__suspension__short_write) && frag_dst &&
(i < height - 1)) {
i++;
dst.data.len = bytes_per_row * (i + 1);
continue;
}
if ((status == wuffs_base__suspension__short_read) && frag_idat &&
if ((status.repr == wuffs_base__suspension__short_read) && frag_idat &&
(j < num_idat_chunks - 1)) {
j++;
idat.meta.wi = idat_splits[j + 1];
idat.meta.closed = (num_idat_chunks == j + 1);
continue;
}
return status;
return wuffs_base__status__message(&status);
}
if (dst.meta.wi != bytes_per_frame) {

View File

@@ -0,0 +1,126 @@
// 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.
// +build ignore
package main
// convert-png-to-wbmp.go decodes PNG from stdin and encodes WBMP Type 0 to
// stdout.
//
// WBMP (Wireless Bitmap) is described in Section 6 and Appendix A of
// http://www.wapforum.org/what/technical/SPEC-WAESpec-19990524.pdf
//
// Usage: go run convert-png-to-wbmp.go < foo.png > foo.wbmp
import (
"bufio"
"errors"
"image"
"image/draw"
"image/png"
"os"
)
func main() {
if err := main1(); err != nil {
os.Stderr.WriteString(err.Error() + "\n")
os.Exit(1)
}
}
func main1() error {
src, err := png.Decode(os.Stdin)
if err != nil {
return err
}
b := src.Bounds()
dst := image.NewGray(b)
draw.Draw(dst, b, src, b.Min, draw.Src)
w := bufio.NewWriter(os.Stdout)
defer w.Flush()
// TypeField, FixHeaderField.
w.WriteString("\x00\x00")
// Width, height.
if err := writeMultiByteInteger(w, b.Dx()); err != nil {
return err
}
if err := writeMultiByteInteger(w, b.Dy()); err != nil {
return err
}
// Rows.
for y := b.Min.Y; y < b.Max.Y; y++ {
i := dst.PixOffset(b.Min.X, y)
j := dst.PixOffset(b.Max.X, y)
if err := writeRow(w, dst.Pix[i:j]); err != nil {
return err
}
}
return nil
}
func writeMultiByteInteger(w *bufio.Writer, x int) error {
if x < 0 {
return errors.New("cannot encode negative integer")
}
n := 1
for z := x; z > 0x7F; n, z = n+1, z>>7 {
}
for i := n - 1; i >= 0; i-- {
c := (x >> uint(7*i)) & 0x7F
if i > 0 {
c |= 0x80
}
if err := w.WriteByte(byte(c)); err != nil {
return err
}
}
return nil
}
func writeRow(w *bufio.Writer, row []byte) error {
// Pack as many complete groups of 8 pixels as we can.
n := len(row) / 8
for i := 0; i < n; i++ {
row8 := row[i*8 : i*8+8]
c := ((row8[0] & 0x80) >> 0) |
((row8[1] & 0x80) >> 1) |
((row8[2] & 0x80) >> 2) |
((row8[3] & 0x80) >> 3) |
((row8[4] & 0x80) >> 4) |
((row8[5] & 0x80) >> 5) |
((row8[6] & 0x80) >> 6) |
((row8[7] & 0x80) >> 7)
if err := w.WriteByte(c); err != nil {
return err
}
}
row = row[8*n:]
// Pack up to 7 remaining pixels.
if len(row) > 0 {
c := byte(0)
for i, x := range row {
c |= (x & 0x80) >> uint(i)
}
if err := w.WriteByte(c); err != nil {
return err
}
}
return nil
}

View File

@@ -115,7 +115,17 @@ extern const char*
#ifdef MAKE_THIS_FILE_COMPILABLE_STANDALONE
typedef const char* wuffs_base__status;
typedef struct {
const char* repr;
} wuffs_base__status;
static inline wuffs_base__status //
wuffs_base__make_status(const char* repr) {
wuffs_base__status z;
z.repr = repr;
return z;
}
typedef struct {
uint8_t* ptr;
size_t len;
@@ -159,7 +169,7 @@ static wuffs_base__status wuffs_deflate__decoder__decode_huffman_fast(
wuffs_deflate__decoder* self,
wuffs_base__io_buffer* a_dst,
wuffs_base__io_buffer* a_src) {
return NULL;
return wuffs_base__make_status(NULL);
}
#endif // MAKE_THIS_FILE_COMPILABLE_STANDALONE
@@ -222,9 +232,9 @@ wuffs_base__status c_wuffs_deflate__decoder__decode_huffman_fast(
(void)(wuffs_deflate__decoder__decode_huffman_fast);
if (!a_dst || !a_src) {
return wuffs_base__error__bad_argument;
return wuffs_base__make_status(wuffs_base__error__bad_argument);
}
wuffs_base__status status = NULL;
wuffs_base__status status = wuffs_base__make_status(NULL);
// Load contextual state. Prepare to check that pdst and psrc remain within
// a_dst's and a_src's bounds.
@@ -232,7 +242,7 @@ wuffs_base__status c_wuffs_deflate__decoder__decode_huffman_fast(
uint8_t* pdst = a_dst->data.ptr + a_dst->meta.wi;
uint8_t* qdst = a_dst->data.ptr + a_dst->data.len;
if ((qdst - pdst) < 258) {
return NULL;
return wuffs_base__make_status(NULL);
} else {
qdst -= 258;
}
@@ -240,7 +250,7 @@ wuffs_base__status c_wuffs_deflate__decoder__decode_huffman_fast(
uint8_t* psrc = a_src->data.ptr + a_src->meta.ri;
uint8_t* qsrc = a_src->data.ptr + a_src->meta.wi;
if ((qsrc - psrc) < 12) {
return NULL;
return wuffs_base__make_status(NULL);
} else {
qsrc -= 12;
}
@@ -309,8 +319,8 @@ outer_loop:
goto end;
}
if ((table_entry >> 24) != 0x10) {
status =
wuffs_deflate__error__internal_error_inconsistent_huffman_decoder_state;
status = wuffs_base__make_status(
wuffs_deflate__error__internal_error_inconsistent_huffman_decoder_state);
goto end;
}
uint32_t top = (table_entry >> 8) & 0xFFFF;
@@ -356,8 +366,8 @@ outer_loop:
break;
}
if ((table_entry >> 24) != 0x10) {
status =
wuffs_deflate__error__internal_error_inconsistent_huffman_decoder_state;
status = wuffs_base__make_status(
wuffs_deflate__error__internal_error_inconsistent_huffman_decoder_state);
goto end;
}
uint32_t top = (table_entry >> 8) & 0xFFFF;
@@ -399,7 +409,7 @@ outer_loop:
length = 0;
}
if (self->private_impl.f_history_index < hdist) {
status = wuffs_deflate__error__bad_distance;
status = wuffs_base__make_status(wuffs_deflate__error__bad_distance);
goto end;
}
@@ -423,7 +433,8 @@ outer_loop:
}
if ((ptrdiff_t)(dist_minus_1 + 1) > (pdst - pdst_mark)) {
status = wuffs_deflate__error__internal_error_inconsistent_distance;
status = wuffs_base__make_status(
wuffs_deflate__error__internal_error_inconsistent_distance);
goto end;
}
}

View File

@@ -13,7 +13,7 @@
// limitations under the License.
// TODO: drop the '?' but still generate wuffs_adler32__hasher__initialize?
pub struct hasher?(
pub struct hasher? implements base.hasher_u32(
state : base.u32,
started : base.bool,
)

View File

@@ -13,7 +13,7 @@
// limitations under the License.
// TODO: drop the '?' but still generate wuffs_crc32__ieee_hasher__initialize?
pub struct ieee_hasher?(
pub struct ieee_hasher? implements base.hasher_u32(
state : base.u32,
)

View File

@@ -65,7 +65,7 @@ pri const dcode_magic_numbers array[32] base.u32 = [
pri const huffs_table_size base.u32 = 1024
pri const huffs_table_mask base.u32 = 1023
pub struct decoder?(
pub struct decoder? implements base.io_transformer(
// These fields yield src's bits in Least Significant Bits order.
bits : base.u32,
n_bits : base.u32,
@@ -186,7 +186,7 @@ pub func decoder.workbuf_len() base.range_ii_u64 {
max_incl: decoder_workbuf_len_max_incl_worst_case)
}
pub func decoder.decode_io_writer?(dst: base.io_writer, src: base.io_reader, workbuf: slice base.u8) {
pub func decoder.transform_io?(dst: base.io_writer, src: base.io_reader, workbuf: slice base.u8) {
var mark : base.u64
var status : base.status
@@ -281,7 +281,7 @@ pri func decoder.decode_uncompressed?(dst: base.io_writer, src: base.io_reader)
}
length = length.low_bits(n: 16)
while true {
n_copied = args.dst.copy_n_from_reader!(n: length, r: args.src)
n_copied = args.dst.copy_n32_from_reader!(n: length, r: args.src)
if length <= n_copied {
return ok
}

View File

@@ -76,10 +76,10 @@ pri func decoder.decode_huffman_fast!(dst: base.io_writer, src: base.io_reader)
if n_bits < 15 {
assert n_bits >= 0 // TODO: this shouldn't be necessary.
bits |= args.src.peek_u8_as_u32() << n_bits
args.src.skip_fast!(actual: 1, worst_case: 1)
args.src.skip32_fast!(actual: 1, worst_case: 1)
n_bits += 8
bits |= args.src.peek_u8_as_u32() << n_bits
args.src.skip_fast!(actual: 1, worst_case: 1)
args.src.skip32_fast!(actual: 1, worst_case: 1)
n_bits += 8
assert n_bits >= 15
} else {
@@ -115,10 +115,10 @@ pri func decoder.decode_huffman_fast!(dst: base.io_writer, src: base.io_reader)
if n_bits < 15 {
assert n_bits >= 0 // TODO: this shouldn't be necessary.
bits |= args.src.peek_u8_as_u32() << n_bits
args.src.skip_fast!(actual: 1, worst_case: 1)
args.src.skip32_fast!(actual: 1, worst_case: 1)
n_bits += 8
bits |= args.src.peek_u8_as_u32() << n_bits
args.src.skip_fast!(actual: 1, worst_case: 1)
args.src.skip32_fast!(actual: 1, worst_case: 1)
n_bits += 8
assert n_bits >= 15
} else {
@@ -173,10 +173,10 @@ pri func decoder.decode_huffman_fast!(dst: base.io_writer, src: base.io_reader)
if n_bits < 15 {
assert n_bits >= 0 // TODO: this shouldn't be necessary.
bits |= args.src.peek_u8_as_u32() << n_bits
args.src.skip_fast!(actual: 1, worst_case: 1)
args.src.skip32_fast!(actual: 1, worst_case: 1)
n_bits += 8
bits |= args.src.peek_u8_as_u32() << n_bits
args.src.skip_fast!(actual: 1, worst_case: 1)
args.src.skip32_fast!(actual: 1, worst_case: 1)
n_bits += 8
assert n_bits >= 15
} else {
@@ -200,10 +200,10 @@ pri func decoder.decode_huffman_fast!(dst: base.io_writer, src: base.io_reader)
if n_bits < 15 {
assert n_bits >= 0 // TODO: this shouldn't be necessary.
bits |= args.src.peek_u8_as_u32() << n_bits
args.src.skip_fast!(actual: 1, worst_case: 1)
args.src.skip32_fast!(actual: 1, worst_case: 1)
n_bits += 8
bits |= args.src.peek_u8_as_u32() << n_bits
args.src.skip_fast!(actual: 1, worst_case: 1)
args.src.skip32_fast!(actual: 1, worst_case: 1)
n_bits += 8
assert n_bits >= 15
} else {
@@ -225,10 +225,10 @@ pri func decoder.decode_huffman_fast!(dst: base.io_writer, src: base.io_reader)
if n_bits < 15 {
assert n_bits >= 0 // TODO: this shouldn't be necessary.
bits |= args.src.peek_u8_as_u32() << n_bits
args.src.skip_fast!(actual: 1, worst_case: 1)
args.src.skip32_fast!(actual: 1, worst_case: 1)
n_bits += 8
bits |= args.src.peek_u8_as_u32() << n_bits
args.src.skip_fast!(actual: 1, worst_case: 1)
args.src.skip32_fast!(actual: 1, worst_case: 1)
n_bits += 8
assert n_bits >= 15
} else {
@@ -269,10 +269,10 @@ pri func decoder.decode_huffman_fast!(dst: base.io_writer, src: base.io_reader)
assert n_bits < 15 via "a < b: a < c; c <= b"(c: table_entry_n_bits)
assert n_bits >= 0 // TODO: this shouldn't be necessary.
bits |= args.src.peek_u8_as_u32() << n_bits
args.src.skip_fast!(actual: 1, worst_case: 1)
args.src.skip32_fast!(actual: 1, worst_case: 1)
n_bits += 8
bits |= args.src.peek_u8_as_u32() << n_bits
args.src.skip_fast!(actual: 1, worst_case: 1)
args.src.skip32_fast!(actual: 1, worst_case: 1)
n_bits += 8
assert table_entry_n_bits <= n_bits via "a <= b: a <= c; c <= b"(c: 16)
assert n_bits >= table_entry_n_bits via "a >= b: b <= a"()
@@ -330,13 +330,13 @@ pri func decoder.decode_huffman_fast!(dst: base.io_writer, src: base.io_reader)
// TODO: copy_from_slice32 should probably update the
// "args.dst.available() >= 258" fact. It should certainly
// invalidate any fact that was "<=" instead of ">=".
n_copied = args.dst.copy_n_from_slice!(
n_copied = args.dst.copy_n32_from_slice!(
n: hlen, s: this.history[hdist & 0x7FFF ..])
if hlen <= n_copied {
break
}
hlen -= n_copied
args.dst.copy_n_from_slice!(n: hlen, s: this.history[..])
args.dst.copy_n32_from_slice!(n: hlen, s: this.history[..])
break
}
@@ -359,7 +359,7 @@ pri func decoder.decode_huffman_fast!(dst: base.io_writer, src: base.io_reader)
assert (length as base.u64) <= args.dst.available() via "a <= b: a <= c; c <= b"(c: 258)
// Copy from args.dst.
args.dst.copy_n_from_history_fast!(n: length, distance: (dist_minus_1 + 1))
args.dst.copy_n32_from_history_fast!(n: length, distance: (dist_minus_1 + 1))
break
}
}

View File

@@ -226,7 +226,7 @@ pri func decoder.decode_huffman_slow?(dst: base.io_writer, src: base.io_reader)
// Copy from hdist to the end of this.history.
while true {
n_copied = args.dst.copy_n_from_slice!(
n_copied = args.dst.copy_n32_from_slice!(
n: hlen, s: this.history[hdist & 0x7FFF ..])
if hlen <= n_copied {
hlen = 0
@@ -245,7 +245,7 @@ pri func decoder.decode_huffman_slow?(dst: base.io_writer, src: base.io_reader)
// Copy from the start of this.history, if we wrapped around.
if hlen > 0 {
while true {
n_copied = args.dst.copy_n_from_slice!(
n_copied = args.dst.copy_n32_from_slice!(
n: hlen, s: this.history[hdist & 0x7FFF ..])
if hlen <= n_copied {
hlen = 0
@@ -264,7 +264,7 @@ pri func decoder.decode_huffman_slow?(dst: base.io_writer, src: base.io_reader)
}
// Copy from args.dst.
n_copied = args.dst.copy_n_from_history!(n: length, distance: (dist_minus_1 + 1))
n_copied = args.dst.copy_n32_from_history!(n: length, distance: (dist_minus_1 + 1))
if length <= n_copied {
length = 0
break

View File

@@ -46,7 +46,7 @@ pri const interlace_start array[5] base.u32 = [0xFFFFFFFF, 1, 2, 4, 0]
pri const interlace_delta array[5] base.u8 = [1, 2, 4, 8, 8]
pri const interlace_count array[5] base.u8 = [0, 1, 2, 4, 8]
pub struct decoder?(
pub struct decoder? implements base.image_decoder(
width : base.u32,
height : base.u32,
@@ -253,7 +253,7 @@ pub func decoder.ack_metadata_chunk?(src: base.io_reader) {
// metadata passed to the caller.
this.metadata_chunk_length_value += 1
} else {
args.src.skip_fast!(actual: 1, worst_case: 1)
args.src.skip32_fast!(actual: 1, worst_case: 1)
}
this.metadata_io_position =
args.src.position() ~sat+ this.metadata_chunk_length_value
@@ -261,7 +261,7 @@ pub func decoder.ack_metadata_chunk?(src: base.io_reader) {
}
// Consume the '\x00' that means a zero-length block.
args.src.skip_fast!(actual: 1, worst_case: 1)
args.src.skip32_fast!(actual: 1, worst_case: 1)
}
this.call_sequence = 2
@@ -324,7 +324,6 @@ pub func decoder.restart_frame!(index: base.u64, io_position: base.u64) base.sta
}
pub func decoder.decode_frame_config?(dst: nptr base.frame_config, src: base.io_reader) {
var blend : base.u8
var background_color : base.u32
var flags : base.u8
@@ -348,10 +347,8 @@ pub func decoder.decode_frame_config?(dst: nptr base.frame_config, src: base.io_
return base."@end of data"
}
blend = 0
background_color = this.black_color_u32_argb_premul
if not this.gc_has_transparent_index {
blend = 2 // 2 is WUFFS_BASE__ANIMATION_BLEND__OPAQUE.
background_color = this.background_color_u32_argb_premul
// If the quirk is enabled and the first frame has a local color
@@ -385,8 +382,9 @@ pub func decoder.decode_frame_config?(dst: nptr base.frame_config, src: base.io_
duration: this.gc_duration,
index: this.num_decoded_frame_configs_value,
io_position: this.frame_config_io_position,
blend: blend,
disposal: this.gc_disposal,
opaque_within_bounds: not this.gc_has_transparent_index,
overwrite_instead_of_blend: false,
background_color: background_color)
}
@@ -401,7 +399,7 @@ pri func decoder.skip_frame?(src: base.io_reader) {
// Skip the optional Local Color Table, 3 bytes (RGB) per entry.
flags = args.src.read_u8?()
if (flags & 0x80) <> 0 {
args.src.skip?(n: (3 as base.u32) << (1 + (flags & 0x07)))
args.src.skip32?(n: (3 as base.u32) << (1 + (flags & 0x07)))
}
// Process the LZW literal width.
@@ -422,7 +420,7 @@ pri func decoder.skip_frame?(src: base.io_reader) {
}
// TODO: honor args.opts.
pub func decoder.decode_frame?(dst: ptr base.pixel_buffer, src: base.io_reader, workbuf: slice base.u8, opts: nptr base.decode_frame_options) {
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) {
this.ignore_metadata = true
if this.call_sequence <> 4 {
this.decode_frame_config?(dst: nullptr, src: args.src)
@@ -431,7 +429,7 @@ pub func decoder.decode_frame?(dst: ptr base.pixel_buffer, src: base.io_reader,
((this.frame_rect_x0 == this.frame_rect_x1) or (this.frame_rect_y0 == this.frame_rect_y1)) {
return "#bad frame size"
}
this.decode_id_part1?(dst: args.dst, src: args.src)
this.decode_id_part1?(dst: args.dst, src: args.src, blend: args.blend)
this.decode_id_part2?(dst: args.dst, src: args.src, workbuf: args.workbuf)
this.num_decoded_frames_value ~sat+= 1
@@ -518,7 +516,7 @@ pri func decoder.decode_lsd?(src: base.io_reader) {
flags = args.src.read_u8?()
background_color_index = args.src.read_u8?()
// Ignore the Pixel Aspect Ratio byte.
args.src.skip?(n: 1)
args.src.skip32?(n: 1)
// Read the optional Global Color Table.
i = 0
@@ -600,7 +598,7 @@ pri func decoder.skip_blocks?(src: base.io_reader) {
if block_size == 0 {
return ok
}
args.src.skip?(n: block_size as base.u32)
args.src.skip32?(n: block_size as base.u32)
}
}
@@ -648,7 +646,7 @@ pri func decoder.decode_ae?(src: base.io_reader) {
//
// Other extensions include XMP metadata.
if block_size <> 11 {
args.src.skip?(n: block_size as base.u32)
args.src.skip32?(n: block_size as base.u32)
break
}
is_animexts = true
@@ -670,12 +668,12 @@ pri func decoder.decode_ae?(src: base.io_reader) {
// count.
block_size = args.src.read_u8?()
if block_size <> 3 {
args.src.skip?(n: block_size as base.u32)
args.src.skip32?(n: block_size as base.u32)
break
}
c = args.src.read_u8?()
if c <> 0x01 {
args.src.skip?(n: 2)
args.src.skip32?(n: 2)
break
}
this.num_loops = args.src.read_u16le_as_u32?()
@@ -705,7 +703,7 @@ pri func decoder.decode_ae?(src: base.io_reader) {
yield? base."$short read"
}
this.metadata_chunk_length_value = args.src.peek_u8_as_u64()
args.src.skip_fast!(actual: 1, worst_case: 1)
args.src.skip32_fast!(actual: 1, worst_case: 1)
this.metadata_fourcc_value = 0x49434350 // "ICCP"
this.metadata_io_position = args.src.position() ~sat+ this.metadata_chunk_length_value
this.call_sequence = 1
@@ -724,7 +722,7 @@ pri func decoder.decode_ae?(src: base.io_reader) {
// metadata passed to the caller.
this.metadata_chunk_length_value += 1
} else {
args.src.skip_fast!(actual: 1, worst_case: 1)
args.src.skip32_fast!(actual: 1, worst_case: 1)
}
this.metadata_fourcc_value = 0x584D5020 // "XMP "
this.metadata_io_position = args.src.position() ~sat+ this.metadata_chunk_length_value
@@ -813,7 +811,7 @@ pri func decoder.decode_id_part0?(src: base.io_reader) {
}
}
pri func decoder.decode_id_part1?(dst: ptr base.pixel_buffer, src: base.io_reader) {
pri func decoder.decode_id_part1?(dst: ptr base.pixel_buffer, src: base.io_reader, blend: base.pixel_blend) {
var flags : base.u8
var which_palette : base.u8[..= 1]
var num_palette_entries : base.u32[..= 256]
@@ -881,8 +879,9 @@ pri func decoder.decode_id_part1?(dst: ptr base.pixel_buffer, src: base.io_reade
status = this.swizzler.prepare!(
dst_pixfmt: args.dst.pixel_format(),
dst_palette: dst_palette,
src_pixfmt: 0x47040008,
src_palette: this.palettes[which_palette][..])
src_pixfmt: this.util.make_pixel_format(repr: 0x47040008),
src_palette: this.palettes[which_palette][..],
blend: args.blend)
if not status.is_ok() {
return status
}
@@ -963,7 +962,7 @@ pri func decoder.decode_id_part2?(dst: ptr base.pixel_buffer, src: base.io_reade
break
}
block_size = args.src.peek_u8_as_u64()
args.src.skip_fast!(actual: 1, worst_case: 1)
args.src.skip32_fast!(actual: 1, worst_case: 1)
}
if decoder_workbuf_len_max_incl_worst_case > args.workbuf.length() {
@@ -976,7 +975,7 @@ pri func decoder.decode_id_part2?(dst: ptr base.pixel_buffer, src: base.io_reade
}
io_bind (io: r, data: this.compressed[this.compressed_ri .. this.compressed_wi]) {
mark = r.mark()
lzw_status =? this.lzw.decode_io_writer?(
lzw_status =? this.lzw.transform_io?(
dst: this.util.empty_io_writer(), src: r, workbuf: this.util.empty_slice_u8())
this.compressed_ri ~sat+= r.count_since(mark: mark)
}
@@ -994,7 +993,7 @@ pri func decoder.decode_id_part2?(dst: ptr base.pixel_buffer, src: base.io_reade
// Skip any trailing blocks.
if need_block_size or (block_size > 0) {
args.src.skip?(n: block_size as base.u32)
args.src.skip32?(n: block_size as base.u32)
this.skip_blocks?(src: args.src)
}
@@ -1025,8 +1024,9 @@ pri func decoder.copy_to_image_buffer!(pb: ptr base.pixel_buffer, src: slice bas
var width_in_bytes : base.u64
var n : base.u64
var src_ri : base.u64
var pixfmt : base.pixel_format
var bytes_per_pixel : base.u32[..= 64]
var pixfmt_channels : base.u32
var bits_per_pixel : base.u32
var tab : table base.u8
var i : base.u64
var j : base.u64
@@ -1037,12 +1037,16 @@ pri func decoder.copy_to_image_buffer!(pb: ptr base.pixel_buffer, src: slice bas
// TODO: a Wuffs (not just C) name for the WUFFS_BASE__PIXEL_FORMAT__ETC
// magic pixfmt constants. Also, support more formats.
pixfmt_channels = args.pb.pixel_format() & 0xFFFF
if (pixfmt_channels == 0x8888) {
//
// TODO: the pixfmt variable shouldn't be necessary. We should be able to
// chain the two calls: "args.pb.pixel_format().bits_per_pixel()".
pixfmt = args.pb.pixel_format()
bits_per_pixel = pixfmt.bits_per_pixel()
if (bits_per_pixel == 32) {
bytes_per_pixel = 4
} else if (pixfmt_channels == 0x0888) {
} else if (bits_per_pixel == 24) {
bytes_per_pixel = 3
} else if (pixfmt_channels == 0x0008) {
} else if (bits_per_pixel == 8) {
bytes_per_pixel = 1
} else {
return base."#unsupported option"

View File

@@ -23,7 +23,7 @@ pub status "#bad header"
// TODO: reference deflate.decoder_workbuf_len_max_incl_worst_case.
pub const decoder_workbuf_len_max_incl_worst_case base.u64 = 1
pub struct decoder?(
pub struct decoder? implements base.io_transformer(
ignore_checksum : base.bool,
checksum : crc32.ieee_hasher,
@@ -42,7 +42,7 @@ pub func decoder.workbuf_len() base.range_ii_u64 {
max_incl: decoder_workbuf_len_max_incl_worst_case)
}
pub func decoder.decode_io_writer?(dst: base.io_writer, src: base.io_reader, workbuf: slice base.u8) {
pub func decoder.transform_io?(dst: base.io_writer, src: base.io_reader, workbuf: slice base.u8) {
var c : base.u8
var flags : base.u8
var xlen : base.u16
@@ -68,12 +68,12 @@ pub func decoder.decode_io_writer?(dst: base.io_writer, src: base.io_reader, wor
}
flags = args.src.read_u8?()
// TODO: API for returning the header's MTIME field.
args.src.skip?(n: 6)
args.src.skip32?(n: 6)
// Handle FEXTRA.
if (flags & 0x04) <> 0 {
xlen = args.src.read_u16le?()
args.src.skip?(n: xlen as base.u32)
args.src.skip32?(n: xlen as base.u32)
}
// Handle FNAME.
@@ -102,7 +102,7 @@ pub func decoder.decode_io_writer?(dst: base.io_writer, src: base.io_reader, wor
// Handle FHCRC.
if (flags & 0x02) <> 0 {
args.src.skip?(n: 2)
args.src.skip32?(n: 2)
}
// Reserved flags bits must be zero.
@@ -113,7 +113,7 @@ pub func decoder.decode_io_writer?(dst: base.io_writer, src: base.io_reader, wor
// Decode and checksum the DEFLATE-encoded payload.
while true {
mark = args.dst.mark()
status =? this.flate.decode_io_writer?(dst: args.dst, src: args.src, workbuf: args.workbuf)
status =? this.flate.transform_io?(dst: args.dst, src: args.src, workbuf: args.workbuf)
if not this.ignore_checksum {
checksum_got = this.checksum.update_u32!(x: args.dst.since(mark: mark))
decoded_length_got ~mod+= ((args.dst.count_since(mark: mark) & 0xFFFFFFFF) as base.u32)

View File

@@ -26,10 +26,10 @@ pri status "#internal error: inconsistent I/O"
// - 3056a84 Roll back 3 recent lzw.decoder.suffixes commits
pub const decoder_workbuf_len_max_incl_worst_case base.u64 = 0
pub struct decoder?(
pub struct decoder? implements base.io_transformer(
// set_literal_width_arg is 1 plus the saved argument passed to
// set_literal_width. This is assigned to the literal_width field at the
// start of decode_io_writer. During that method, calling set_literal_width
// start of transform_io. During that method, calling set_literal_width
// will change set_literal_width_arg but not literal_width.
set_literal_width_arg : base.u32[..= 9],
@@ -77,7 +77,7 @@ pub func decoder.workbuf_len() base.range_ii_u64 {
return this.util.make_range_ii_u64(min_incl: 0, max_incl: 0)
}
pub func decoder.decode_io_writer?(dst: base.io_writer, src: base.io_reader, workbuf: slice base.u8) {
pub func decoder.transform_io?(dst: base.io_writer, src: base.io_reader, workbuf: slice base.u8) {
var i : base.u32[..= 8191]
// Initialize read_from state.
@@ -159,7 +159,7 @@ pri func decoder.read_from!(src: base.io_reader) {
// Read 4 bytes, using the "Variant 4" technique of
// https://fgiesen.wordpress.com/2018/02/20/reading-bits-in-far-too-many-ways-part-2/
bits |= args.src.peek_u32le() ~mod<< n_bits
args.src.skip_fast!(actual: (31 - n_bits) >> 3, worst_case: 3)
args.src.skip32_fast!(actual: (31 - n_bits) >> 3, worst_case: 3)
n_bits |= 24
assert width <= n_bits via "a <= b: a <= c; c <= b"(c: 12)
assert n_bits >= width via "a >= b: b <= a"()
@@ -168,7 +168,7 @@ pri func decoder.read_from!(src: base.io_reader) {
break
} else {
bits |= args.src.peek_u8_as_u32() << n_bits
args.src.skip_fast!(actual: 1, worst_case: 1)
args.src.skip32_fast!(actual: 1, worst_case: 1)
n_bits += 8
if n_bits >= width {
// No-op.
@@ -177,7 +177,7 @@ pri func decoder.read_from!(src: base.io_reader) {
break
} else {
bits |= args.src.peek_u8_as_u32() << n_bits
args.src.skip_fast!(actual: 1, worst_case: 1)
args.src.skip32_fast!(actual: 1, worst_case: 1)
n_bits += 8
assert width <= n_bits via "a <= b: a <= c; c <= b"(c: 12)
assert n_bits >= width via "a >= b: b <= a"()

269
std/wbmp/decode_wbmp.wuffs Normal file
View File

@@ -0,0 +1,269 @@
// 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 const decoder_workbuf_len_max_incl_worst_case base.u64 = 0
pub struct decoder? implements base.image_decoder(
width : base.u32,
height : base.u32,
call_sequence : base.u8,
frame_config_io_position : base.u64,
swizzler : base.pixel_swizzler,
util : base.utility,
)
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
if this.call_sequence <> 0 {
return base."#bad call sequence"
}
// 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
}
this.frame_config_io_position = args.src.position()
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: this.frame_config_io_position,
first_frame_is_opaque: true)
}
this.call_sequence = 1
}
pub func decoder.decode_frame_config?(dst: nptr base.frame_config, src: base.io_reader) {
if this.call_sequence < 1 {
this.decode_image_config?(dst: nullptr, src: args.src)
} else if this.call_sequence == 1 {
// No-op.
} else if this.call_sequence == 2 {
this.skip_frame?(src: args.src)
return base."@end of data"
} else {
return base."@end of data"
}
if args.dst <> nullptr {
args.dst.update!(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: true,
overwrite_instead_of_blend: false,
background_color: 0xFF000000)
}
this.call_sequence = 2
}
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
var dst_x : base.u32
var dst_y : base.u32
var tab : table base.u8
var dst : slice base.u8
var src : array[1] base.u8
var c : base.u8
if this.call_sequence < 2 {
this.decode_frame_config?(dst: nullptr, src: args.src)
} else if this.call_sequence == 2 {
// No-op.
} else {
return base."@end of data"
}
// TODO: a Wuffs (not just C) name for the
// WUFFS_BASE__PIXEL_FORMAT__Y magic pixfmt constant.
status = this.swizzler.prepare!(
dst_pixfmt: args.dst.pixel_format(),
dst_palette: args.dst.palette(),
src_pixfmt: this.util.make_pixel_format(repr: 0x10000008),
src_palette: this.util.empty_slice_u8(),
blend: args.blend)
if not status.is_ok() {
return status
}
// TODO: be more efficient than reading one byte at a time.
if this.width > 0 {
tab = args.dst.plane(p: 0)
while dst_y < this.height {
assert dst_y < 0xFFFFFFFF via "a < b: a < c; c <= b"(c: this.height)
dst = tab.row(y: dst_y)
dst_x = 0
while dst_x < this.width,
inv dst_y < 0xFFFFFFFF,
{
assert dst_x < 0xFFFFFFFF via "a < b: a < c; c <= b"(c: this.width)
if (dst_x & 7) == 0 {
c = args.src.read_u8?()
}
if (c & 0x80) == 0 {
src[0] = 0x00
} else {
src[0] = 0xFF
}
// TODO: this should just be "c ~mod<<= 1", but that generates:
//
// error: conversion to uint8_t {aka unsigned char} from
// int may alter its value [-Werror=conversion]
// v_c <<= 1;
c = (((c as base.u32) << 1) & 0xFF) as base.u8
this.swizzler.swizzle_interleaved!(
dst: dst, dst_palette: this.util.empty_slice_u8(), src: src[..])
if dst.length() >= 4 {
dst = dst[4 ..]
}
dst_x += 1
}
dst_y += 1
}
}
this.call_sequence = 3
}
pri func decoder.skip_frame?(src: base.io_reader) {
var bytes_per_row : base.u64[..= 0x20000000]
var total_bytes : base.u64
bytes_per_row = ((this.width as base.u64) + 7) / 8
total_bytes = bytes_per_row * (this.height as base.u64)
args.src.skip?(n: total_bytes)
this.call_sequence = 3
}
pub func decoder.ack_metadata_chunk?(src: base.io_reader) {
// TODO: this final line shouldn't be necessary, here and in some other
// std/*/*.wuffs functions.
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.metadata_chunk_length() base.u64 {
return 0
}
pub func decoder.metadata_fourcc() base.u32 {
return 0
}
pub func decoder.num_animation_loops() base.u32 {
return 0
}
pub func decoder.num_decoded_frame_configs() base.u64 {
if this.call_sequence > 1 {
return 1
}
return 0
}
pub func decoder.num_decoded_frames() base.u64 {
if this.call_sequence > 2 {
return 1
}
return 0
}
pub func decoder.restart_frame!(index: base.u64, io_position: base.u64) base.status {
if this.call_sequence == 0 {
return base."#bad call sequence"
}
if args.index <> 0 {
return base."#bad argument"
}
this.call_sequence = 1
this.frame_config_io_position = args.io_position
return ok
}
pub func decoder.set_report_metadata!(fourcc: base.u32, report: base.bool) {
// No-op. WBMP doesn't support metadata.
}
pub func decoder.workbuf_len() base.range_ii_u64 {
return this.util.make_range_ii_u64(min_incl: 0, max_incl: 0)
}

View File

@@ -26,7 +26,7 @@ pub status "#incorrect dictionary"
// TODO: reference deflate.decoder_workbuf_len_max_incl_worst_case.
pub const decoder_workbuf_len_max_incl_worst_case base.u64 = 1
pub struct decoder?(
pub struct decoder? implements base.io_transformer(
bad_call_sequence : base.bool,
header_complete : base.bool,
@@ -69,7 +69,7 @@ pub func decoder.workbuf_len() base.range_ii_u64 {
max_incl: decoder_workbuf_len_max_incl_worst_case)
}
pub func decoder.decode_io_writer?(dst: base.io_writer, src: base.io_reader, workbuf: slice base.u8) {
pub func decoder.transform_io?(dst: base.io_writer, src: base.io_reader, workbuf: slice base.u8) {
var x : base.u16
var checksum_got : base.u32
var status : base.status
@@ -109,7 +109,7 @@ pub func decoder.decode_io_writer?(dst: base.io_writer, src: base.io_reader, wor
// Decode and checksum the DEFLATE-encoded payload.
while true {
mark = args.dst.mark()
status =? this.flate.decode_io_writer?(dst: args.dst, src: args.src, workbuf: args.workbuf)
status =? this.flate.transform_io?(dst: args.dst, src: args.src, workbuf: args.workbuf)
if not this.ignore_checksum {
checksum_got = this.checksum.update_u32!(x: args.dst.since(mark: mark))
}

View File

@@ -79,6 +79,18 @@ golden_test adler32_pi_gt = {
// ---------------- Adler32 Tests
const char* test_wuffs_adler32_interface() {
CHECK_FOCUS(__func__);
wuffs_adler32__hasher h;
CHECK_STATUS("initialize",
wuffs_adler32__hasher__initialize(
&h, sizeof h, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
return do_test__wuffs_base__hasher_u32(
wuffs_adler32__hasher__upcast_as__wuffs_base__hasher_u32(&h),
"test/data/hat.lossy.webp", 0, SIZE_MAX, 0xF1BB258D);
}
const char* test_wuffs_adler32_golden() {
CHECK_FOCUS(__func__);
@@ -122,20 +134,15 @@ const char* test_wuffs_adler32_golden() {
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
.data = global_src_slice,
});
const char* status = read_file(&src, test_cases[i].filename);
if (status) {
return status;
}
CHECK_STRING(read_file(&src, test_cases[i].filename));
int j;
for (j = 0; j < 2; j++) {
wuffs_adler32__hasher checksum;
status = wuffs_adler32__hasher__initialize(
&checksum, sizeof checksum, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED);
if (status) {
RETURN_FAIL("initialize: \"%s\"", status);
}
CHECK_STATUS("initialize",
wuffs_adler32__hasher__initialize(
&checksum, sizeof checksum, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
uint32_t got = 0;
size_t num_fragments = 0;
@@ -201,12 +208,10 @@ const char* test_wuffs_adler32_pi() {
int i;
for (i = 0; i < 100; i++) {
wuffs_adler32__hasher checksum;
const char* status = wuffs_adler32__hasher__initialize(
&checksum, sizeof checksum, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED);
if (status) {
RETURN_FAIL("initialize: \"%s\"", status);
}
CHECK_STATUS("initialize",
wuffs_adler32__hasher__initialize(
&checksum, sizeof checksum, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
uint32_t got = wuffs_adler32__hasher__update_u32(
&checksum, ((wuffs_base__slice_u8){
.ptr = (uint8_t*)(digits),
@@ -234,11 +239,9 @@ const char* wuffs_bench_adler32(wuffs_base__io_buffer* dst,
len = wuffs_base__u64__min(len, rlimit);
}
wuffs_adler32__hasher checksum;
const char* status = wuffs_adler32__hasher__initialize(
&checksum, sizeof checksum, WUFFS_VERSION, wuffs_initialize_flags);
if (status) {
return status;
}
CHECK_STATUS("initialize", wuffs_adler32__hasher__initialize(
&checksum, sizeof checksum, WUFFS_VERSION,
wuffs_initialize_flags));
global_wuffs_adler32_unused_u32 = wuffs_adler32__hasher__update_u32(
&checksum, ((wuffs_base__slice_u8){
.ptr = src->data.ptr + src->meta.ri,
@@ -291,8 +294,9 @@ const char* bench_mimic_adler32_100k() {
// The empty comments forces clang-format to place one element per line.
proc tests[] = {
test_wuffs_adler32_golden, //
test_wuffs_adler32_pi, //
test_wuffs_adler32_golden, //
test_wuffs_adler32_interface, //
test_wuffs_adler32_pi, //
NULL,
};

View File

@@ -79,6 +79,18 @@ golden_test crc32_pi_gt = {
// ---------------- CRC32 Tests
const char* test_wuffs_crc32_ieee_interface() {
CHECK_FOCUS(__func__);
wuffs_crc32__ieee_hasher h;
CHECK_STATUS("initialize",
wuffs_crc32__ieee_hasher__initialize(
&h, sizeof h, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
return do_test__wuffs_base__hasher_u32(
wuffs_crc32__ieee_hasher__upcast_as__wuffs_base__hasher_u32(&h),
"test/data/hat.lossy.webp", 0, SIZE_MAX, 0x89F53B4E);
}
const char* test_wuffs_crc32_ieee_golden() {
CHECK_FOCUS(__func__);
@@ -122,20 +134,15 @@ const char* test_wuffs_crc32_ieee_golden() {
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
.data = global_src_slice,
});
const char* status = read_file(&src, test_cases[i].filename);
if (status) {
return status;
}
CHECK_STRING(read_file(&src, test_cases[i].filename));
int j;
for (j = 0; j < 2; j++) {
wuffs_crc32__ieee_hasher checksum;
status = wuffs_crc32__ieee_hasher__initialize(
&checksum, sizeof checksum, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED);
if (status) {
RETURN_FAIL("initialize: \"%s\"", status);
}
CHECK_STATUS("initialize",
wuffs_crc32__ieee_hasher__initialize(
&checksum, sizeof checksum, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
uint32_t got = 0;
size_t num_fragments = 0;
@@ -222,12 +229,10 @@ const char* do_test_xxxxx_crc32_ieee_pi(bool mimic) {
} else {
wuffs_crc32__ieee_hasher checksum;
const char* status = wuffs_crc32__ieee_hasher__initialize(
&checksum, sizeof checksum, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED);
if (status) {
RETURN_FAIL("initialize: \"%s\"", status);
}
CHECK_STATUS("initialize",
wuffs_crc32__ieee_hasher__initialize(
&checksum, sizeof checksum, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
got = wuffs_crc32__ieee_hasher__update_u32(&checksum, data);
}
@@ -269,11 +274,9 @@ const char* wuffs_bench_crc32_ieee(wuffs_base__io_buffer* dst,
len = wuffs_base__u64__min(len, rlimit);
}
wuffs_crc32__ieee_hasher checksum;
const char* status = wuffs_crc32__ieee_hasher__initialize(
&checksum, sizeof checksum, WUFFS_VERSION, wuffs_initialize_flags);
if (status) {
return status;
}
CHECK_STATUS("initialize", wuffs_crc32__ieee_hasher__initialize(
&checksum, sizeof checksum, WUFFS_VERSION,
wuffs_initialize_flags));
global_wuffs_crc32_unused_u32 = wuffs_crc32__ieee_hasher__update_u32(
&checksum, ((wuffs_base__slice_u8){
.ptr = src->data.ptr + src->meta.ri,
@@ -325,8 +328,9 @@ const char* bench_mimic_crc32_ieee_100k() {
// The empty comments forces clang-format to place one element per line.
proc tests[] = {
test_wuffs_crc32_ieee_golden, //
test_wuffs_crc32_ieee_pi, //
test_wuffs_crc32_ieee_golden, //
test_wuffs_crc32_ieee_interface, //
test_wuffs_crc32_ieee_pi, //
#ifdef WUFFS_MIMIC

View File

@@ -155,35 +155,45 @@ golden_test deflate_romeo_fixed_gt = {
// ---------------- Deflate Tests
const char* test_wuffs_deflate_decode_interface() {
CHECK_FOCUS(__func__);
wuffs_deflate__decoder dec;
CHECK_STATUS("initialize",
wuffs_deflate__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
return do_test__wuffs_base__io_transformer(
wuffs_deflate__decoder__upcast_as__wuffs_base__io_transformer(&dec),
"test/data/romeo.txt.deflate", 0, SIZE_MAX, 942, 0x0A);
}
const char* wuffs_deflate_decode(wuffs_base__io_buffer* dst,
wuffs_base__io_buffer* src,
uint32_t wuffs_initialize_flags,
uint64_t wlimit,
uint64_t rlimit) {
wuffs_deflate__decoder dec;
const char* status = wuffs_deflate__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION, wuffs_initialize_flags);
if (status) {
RETURN_FAIL("initialize: \"%s\"", status);
}
CHECK_STATUS("initialize",
wuffs_deflate__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION, wuffs_initialize_flags));
while (true) {
wuffs_base__io_buffer limited_dst = make_limited_writer(*dst, wlimit);
wuffs_base__io_buffer limited_src = make_limited_reader(*src, rlimit);
status = wuffs_deflate__decoder__decode_io_writer(
wuffs_base__status status = wuffs_deflate__decoder__transform_io(
&dec, &limited_dst, &limited_src, global_work_slice);
dst->meta.wi += limited_dst.meta.wi;
src->meta.ri += limited_src.meta.ri;
if (((wlimit < UINT64_MAX) &&
(status == wuffs_base__suspension__short_write)) ||
(status.repr == wuffs_base__suspension__short_write)) ||
((rlimit < UINT64_MAX) &&
(status == wuffs_base__suspension__short_read))) {
(status.repr == wuffs_base__suspension__short_read))) {
continue;
}
return status;
return status.repr;
}
}
@@ -230,12 +240,9 @@ const char* test_wuffs_deflate_decode_deflate_huffman_primlen_9() {
CHECK_FOCUS(__func__);
// First, treat this like any other compare-to-golden test.
const char* status = do_test_io_buffers(wuffs_deflate_decode,
&deflate_deflate_huffman_primlen_9_gt,
UINT64_MAX, UINT64_MAX);
if (status) {
return status;
}
CHECK_STRING(do_test_io_buffers(wuffs_deflate_decode,
&deflate_deflate_huffman_primlen_9_gt,
UINT64_MAX, UINT64_MAX));
// Second, check that the decoder's huffman table sizes match those predicted
// by the script/print-deflate-huff-table-size.go program.
@@ -247,22 +254,14 @@ const char* test_wuffs_deflate_decode_deflate_huffman_primlen_9() {
});
golden_test* gt = &deflate_deflate_huffman_primlen_9_gt;
status = read_file(&src, gt->src_filename);
if (status) {
return status;
}
CHECK_STRING(read_file(&src, gt->src_filename));
wuffs_deflate__decoder dec;
status = wuffs_deflate__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION, WUFFS_INITIALIZE__DEFAULT_OPTIONS);
if (status) {
RETURN_FAIL("initialize: \"%s\"", status);
}
status = wuffs_deflate__decoder__decode_io_writer(&dec, &got, &src,
global_work_slice);
if (status) {
RETURN_FAIL("decode_io_writer: \"%s\"", status);
}
CHECK_STATUS("initialize", wuffs_deflate__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__DEFAULT_OPTIONS));
CHECK_STATUS("transform_io", wuffs_deflate__decoder__transform_io(
&dec, &got, &src, global_work_slice));
int i;
for (i = 0; i < 2; i++) {
@@ -337,16 +336,9 @@ const char* test_wuffs_deflate_decode_split_src() {
.data = global_want_slice,
});
const char* status;
golden_test* gt = &deflate_256_bytes_gt;
status = read_file(&src, gt->src_filename);
if (status) {
return status;
}
status = read_file(&want, gt->want_filename);
if (status) {
return status;
}
CHECK_STRING(read_file(&src, gt->src_filename));
CHECK_STRING(read_file(&want, gt->want_filename));
int i;
for (i = 1; i < 32; i++) {
@@ -357,40 +349,35 @@ const char* test_wuffs_deflate_decode_split_src() {
got.meta.wi = 0;
wuffs_deflate__decoder dec;
status = wuffs_deflate__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED);
if (status) {
RETURN_FAIL("initialize: \"%s\"", status);
}
CHECK_STATUS("initialize",
wuffs_deflate__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
src.meta.closed = false;
src.meta.ri = gt->src_offset0;
src.meta.wi = split;
const char* z0 = wuffs_deflate__decoder__decode_io_writer(
wuffs_base__status z0 = wuffs_deflate__decoder__transform_io(
&dec, &got, &src, global_work_slice);
src.meta.closed = true;
src.meta.ri = split;
src.meta.wi = gt->src_offset1;
const char* z1 = wuffs_deflate__decoder__decode_io_writer(
wuffs_base__status z1 = wuffs_deflate__decoder__transform_io(
&dec, &got, &src, global_work_slice);
if (z0 != wuffs_base__suspension__short_read) {
RETURN_FAIL("i=%d: z0: got \"%s\", want \"%s\"", i, z0,
if (z0.repr != wuffs_base__suspension__short_read) {
RETURN_FAIL("i=%d: z0: got \"%s\", want \"%s\"", i, z0.repr,
wuffs_base__suspension__short_read);
}
if (z1) {
RETURN_FAIL("i=%d: z1: got \"%s\"", i, z1);
if (z1.repr) {
RETURN_FAIL("i=%d: z1: got \"%s\"", i, z1.repr);
}
char prefix[64];
snprintf(prefix, 64, "i=%d: ", i);
status = check_io_buffers_equal(prefix, &got, &want);
if (status) {
return status;
}
CHECK_STRING(check_io_buffers_equal(prefix, &got, &want));
}
return NULL;
}
@@ -412,13 +399,13 @@ const char* do_test_wuffs_deflate_history(int i,
dec->private_impl.f_history_index = starting_history_index;
const char* got_z = wuffs_deflate__decoder__decode_io_writer(
wuffs_base__status got_z = wuffs_deflate__decoder__transform_io(
dec, &limited_got, src, global_work_slice);
got->meta.wi += limited_got.meta.wi;
if (got_z != want_z) {
if (got_z.repr != want_z) {
RETURN_FAIL("i=%d: starting_history_index=0x%04" PRIX32
": decode status: got \"%s\", want \"%s\"",
i, starting_history_index, got_z, want_z);
": decode: got \"%s\", want \"%s\"",
i, starting_history_index, got_z.repr, want_z);
}
return NULL;
}
@@ -436,34 +423,22 @@ const char* test_wuffs_deflate_history_full() {
.data = global_want_slice,
});
const char* status;
golden_test* gt = &deflate_pi_gt;
status = read_file(&src, gt->src_filename);
if (status) {
return status;
}
status = read_file(&want, gt->want_filename);
if (status) {
return status;
}
CHECK_STRING(read_file(&src, gt->src_filename));
CHECK_STRING(read_file(&want, gt->want_filename));
const int full_history_size = 0x8000;
int i;
for (i = -2; i <= +2; i++) {
wuffs_deflate__decoder dec;
status = wuffs_deflate__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED);
if (status) {
RETURN_FAIL("initialize: \"%s\"", status);
}
CHECK_STATUS("initialize",
wuffs_deflate__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
status = do_test_wuffs_deflate_history(
CHECK_STRING(do_test_wuffs_deflate_history(
i, gt, &src, &got, &dec, 0, want.meta.wi + i,
i >= 0 ? NULL : wuffs_base__suspension__short_write);
if (status) {
return status;
}
i >= 0 ? NULL : wuffs_base__suspension__short_write));
uint32_t want_history_index = i >= 0 ? 0 : full_history_size;
if (dec.private_impl.f_history_index != want_history_index) {
@@ -492,10 +467,7 @@ const char* test_wuffs_deflate_history_full() {
});
history_want.meta.wi = full_history_size;
status = check_io_buffers_equal("", &history_got, &history_want);
if (status) {
return status;
}
CHECK_STRING(check_io_buffers_equal("", &history_got, &history_want));
}
return NULL;
}
@@ -511,10 +483,7 @@ const char* test_wuffs_deflate_history_partial() {
});
golden_test* gt = &deflate_pi_gt;
const char* status = read_file(&src, gt->src_filename);
if (status) {
return status;
}
CHECK_STRING(read_file(&src, gt->src_filename));
uint32_t starting_history_indexes[] = {
0x0000, 0x0001, 0x1234, 0x7FFB, 0x7FFC, 0x7FFD, 0x7FFE, 0x7FFF,
@@ -532,19 +501,14 @@ const char* test_wuffs_deflate_history_partial() {
wuffs_deflate__decoder dec;
memset(&(dec.private_data.f_history), 0,
sizeof(dec.private_data.f_history));
status = wuffs_deflate__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED);
if (status) {
RETURN_FAIL("initialize: \"%s\"", status);
}
CHECK_STATUS("initialize",
wuffs_deflate__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
status = do_test_wuffs_deflate_history(
CHECK_STRING(do_test_wuffs_deflate_history(
i, gt, &src, &got, &dec, starting_history_index, fragment_length,
wuffs_base__suspension__short_write);
if (status) {
return status;
}
wuffs_base__suspension__short_write));
bool got_full = dec.private_impl.f_history_index >= 0x8000;
uint32_t got_history_index = dec.private_impl.f_history_index & 0x7FFF;
@@ -620,12 +584,10 @@ const char* test_wuffs_deflate_table_redirect() {
// 2nd is the key in the second level table (variable bits).
wuffs_deflate__decoder dec;
const char* status = wuffs_deflate__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED);
if (status) {
RETURN_FAIL("initialize: \"%s\"", status);
}
CHECK_STATUS("initialize",
wuffs_deflate__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
memset(&(dec.private_data.f_huffs), 0, sizeof(dec.private_data.f_huffs));
int i;
@@ -645,10 +607,8 @@ const char* test_wuffs_deflate_table_redirect() {
dec.private_data.f_code_lengths[n++] = 13;
dec.private_data.f_code_lengths[n++] = 13;
status = wuffs_deflate__decoder__init_huff(&dec, 0, 0, n, 257);
if (status) {
RETURN_FAIL("init_huff: \"%s\"", status);
}
CHECK_STATUS("init_huff",
wuffs_deflate__decoder__init_huff(&dec, 0, 0, n, 257));
// There is one 1st-level table (9 bits), and three 2nd-level tables (3, 3
// and 4 bits). f_huffs[0]'s elements should be non-zero for those tables and
@@ -877,6 +837,7 @@ proc tests[] = {
test_wuffs_deflate_decode_deflate_distance_32768, //
test_wuffs_deflate_decode_deflate_distance_code_31, //
test_wuffs_deflate_decode_deflate_huffman_primlen_9, //
test_wuffs_deflate_decode_interface, //
test_wuffs_deflate_decode_midsummer, //
test_wuffs_deflate_decode_pi_just_one_read, //
test_wuffs_deflate_decode_pi_many_big_reads, //

File diff suppressed because it is too large Load Diff

View File

@@ -83,35 +83,45 @@ golden_test gzip_pi_gt = {
// ---------------- Gzip Tests
const char* test_wuffs_gzip_decode_interface() {
CHECK_FOCUS(__func__);
wuffs_gzip__decoder dec;
CHECK_STATUS("initialize",
wuffs_gzip__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
return do_test__wuffs_base__io_transformer(
wuffs_gzip__decoder__upcast_as__wuffs_base__io_transformer(&dec),
"test/data/romeo.txt.gz", 0, SIZE_MAX, 942, 0x0A);
}
const char* wuffs_gzip_decode(wuffs_base__io_buffer* dst,
wuffs_base__io_buffer* src,
uint32_t wuffs_initialize_flags,
uint64_t wlimit,
uint64_t rlimit) {
wuffs_gzip__decoder dec;
const char* status = wuffs_gzip__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION, wuffs_initialize_flags);
if (status) {
return status;
}
CHECK_STATUS("initialize",
wuffs_gzip__decoder__initialize(&dec, sizeof dec, WUFFS_VERSION,
wuffs_initialize_flags));
while (true) {
wuffs_base__io_buffer limited_dst = make_limited_writer(*dst, wlimit);
wuffs_base__io_buffer limited_src = make_limited_reader(*src, rlimit);
status = wuffs_gzip__decoder__decode_io_writer(
wuffs_base__status status = wuffs_gzip__decoder__transform_io(
&dec, &limited_dst, &limited_src, global_work_slice);
dst->meta.wi += limited_dst.meta.wi;
src->meta.ri += limited_src.meta.ri;
if (((wlimit < UINT64_MAX) &&
(status == wuffs_base__suspension__short_write)) ||
(status.repr == wuffs_base__suspension__short_write)) ||
((rlimit < UINT64_MAX) &&
(status == wuffs_base__suspension__short_read))) {
(status.repr == wuffs_base__suspension__short_read))) {
continue;
}
return status;
return status.repr;
}
}
@@ -124,10 +134,7 @@ const char* do_test_wuffs_gzip_checksum(bool ignore_checksum,
.data = global_src_slice,
});
const char* status = read_file(&src, gzip_midsummer_gt.src_filename);
if (status) {
return status;
}
CHECK_STRING(read_file(&src, gzip_midsummer_gt.src_filename));
// Flip a bit in the gzip checksum, which is in the last 8 bytes of the file.
if (src.meta.wi < 8) {
@@ -140,12 +147,10 @@ const char* do_test_wuffs_gzip_checksum(bool ignore_checksum,
int end_limit; // The rlimit, relative to the end of the data.
for (end_limit = 0; end_limit < 10; end_limit++) {
wuffs_gzip__decoder dec;
status = wuffs_gzip__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED);
if (status) {
RETURN_FAIL("initialize: \"%s\"", status);
}
CHECK_STATUS("initialize",
wuffs_gzip__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
wuffs_gzip__decoder__set_ignore_checksum(&dec, ignore_checksum);
got.meta.wi = 0;
src.meta.ri = 0;
@@ -172,12 +177,12 @@ const char* do_test_wuffs_gzip_checksum(bool ignore_checksum,
}
wuffs_base__io_buffer limited_src = make_limited_reader(src, rlimit);
const char* got_z = wuffs_gzip__decoder__decode_io_writer(
wuffs_base__status got_z = wuffs_gzip__decoder__transform_io(
&dec, &got, &limited_src, global_work_slice);
src.meta.ri += limited_src.meta.ri;
if (got_z != want_z) {
RETURN_FAIL("end_limit=%d: got \"%s\", want \"%s\"", end_limit, got_z,
want_z);
if (got_z.repr != want_z) {
RETURN_FAIL("end_limit=%d: got \"%s\", want \"%s\"", end_limit,
got_z.repr, want_z);
}
}
}
@@ -280,6 +285,7 @@ proc tests[] = {
test_wuffs_gzip_checksum_verify_bad0, //
test_wuffs_gzip_checksum_verify_bad7, //
test_wuffs_gzip_checksum_verify_good, //
test_wuffs_gzip_decode_interface, //
test_wuffs_gzip_decode_midsummer, //
test_wuffs_gzip_decode_pi, //

View File

@@ -66,6 +66,18 @@ the first "./a.out" with "./a.out -bench". Combine these changes with the
// ---------------- LZW Tests
const char* test_wuffs_lzw_decode_interface() {
CHECK_FOCUS(__func__);
wuffs_lzw__decoder dec;
CHECK_STATUS("initialize",
wuffs_lzw__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
return do_test__wuffs_base__io_transformer(
wuffs_lzw__decoder__upcast_as__wuffs_base__io_transformer(&dec),
"test/data/bricks-nodither.indexes.giflzw", 1, SIZE_MAX, 19200, 0x4F);
}
const char* do_test_wuffs_lzw_decode(const char* src_filename,
uint64_t src_size,
const char* want_filename,
@@ -82,10 +94,7 @@ const char* do_test_wuffs_lzw_decode(const char* src_filename,
.data = global_src_slice,
});
const char* status = read_file(&src, src_filename);
if (status) {
return status;
}
CHECK_STRING(read_file(&src, src_filename));
if (src.meta.wi != src_size) {
RETURN_FAIL("src size: got %d, want %d", (int)(src.meta.wi),
(int)(src_size));
@@ -98,22 +107,17 @@ const char* do_test_wuffs_lzw_decode(const char* src_filename,
}
src.meta.ri++;
status = read_file(&want, want_filename);
if (status) {
return status;
}
CHECK_STRING(read_file(&want, want_filename));
if (want.meta.wi != want_size) {
RETURN_FAIL("want size: got %d, want %d", (int)(want.meta.wi),
(int)(want_size));
}
wuffs_lzw__decoder dec;
status = wuffs_lzw__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED);
if (status) {
RETURN_FAIL("initialize: \"%s\"", status);
}
CHECK_STATUS("initialize",
wuffs_lzw__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
wuffs_lzw__decoder__set_literal_width(&dec, literal_width);
int num_iters = 0;
while (true) {
@@ -123,20 +127,20 @@ const char* do_test_wuffs_lzw_decode(const char* src_filename,
size_t old_wi = got.meta.wi;
size_t old_ri = src.meta.ri;
status = wuffs_lzw__decoder__decode_io_writer(
wuffs_base__status status = wuffs_lzw__decoder__transform_io(
&dec, &limited_got, &limited_src, global_work_slice);
got.meta.wi += limited_got.meta.wi;
src.meta.ri += limited_src.meta.ri;
if (!status) {
if (wuffs_base__status__is_ok(&status)) {
if (src.meta.ri != src.meta.wi) {
RETURN_FAIL("decode returned \"ok\" but src was not exhausted");
RETURN_FAIL("transform_io returned \"ok\" but src was not exhausted");
}
break;
}
if ((status != wuffs_base__suspension__short_read) &&
(status != wuffs_base__suspension__short_write)) {
RETURN_FAIL("decode: got \"%s\", want \"%s\" or \"%s\"", status,
wuffs_base__suspension__short_read,
if ((status.repr != wuffs_base__suspension__short_read) &&
(status.repr != wuffs_base__suspension__short_write)) {
RETURN_FAIL("transform_io: got \"%s\", want \"%s\" or \"%s\"",
status.repr, wuffs_base__suspension__short_read,
wuffs_base__suspension__short_write);
}
@@ -223,18 +227,17 @@ const char* test_wuffs_lzw_decode_output_bad() {
src.data.ptr[3] = 0xFF;
wuffs_lzw__decoder dec;
const char* status = wuffs_lzw__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED);
if (status) {
RETURN_FAIL("initialize: \"%s\"", status);
}
CHECK_STATUS("initialize",
wuffs_lzw__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
wuffs_lzw__decoder__set_literal_width(&dec, 7);
status =
wuffs_lzw__decoder__decode_io_writer(&dec, &got, &src, global_work_slice);
if (status != wuffs_lzw__error__bad_code) {
RETURN_FAIL("decode: \"%s\"", status);
wuffs_base__status status =
wuffs_lzw__decoder__transform_io(&dec, &got, &src, global_work_slice);
if (status.repr != wuffs_lzw__error__bad_code) {
RETURN_FAIL("transform_io: got \"%s\", want \"%s\"", status.repr,
wuffs_lzw__error__bad_code);
}
if (got.meta.wi != 3) {
@@ -267,19 +270,14 @@ const char* test_wuffs_lzw_decode_output_empty() {
src.data.ptr[1] = 0x01;
wuffs_lzw__decoder dec;
const char* status = wuffs_lzw__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED);
if (status) {
RETURN_FAIL("initialize: \"%s\"", status);
}
CHECK_STATUS("initialize",
wuffs_lzw__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
wuffs_lzw__decoder__set_literal_width(&dec, 8);
status =
wuffs_lzw__decoder__decode_io_writer(&dec, &got, &src, global_work_slice);
if (status) {
RETURN_FAIL("decode: \"%s\"", status);
}
CHECK_STATUS("transform_io", wuffs_lzw__decoder__transform_io(
&dec, &got, &src, global_work_slice));
if (got.meta.wi != 0) {
RETURN_FAIL("got.meta.wi: got %d, want 0", (int)(got.meta.wi));
@@ -294,22 +292,17 @@ const char* do_test_wuffs_lzw_decode_width(uint32_t width,
wuffs_base__io_buffer src,
wuffs_base__io_buffer want) {
wuffs_lzw__decoder dec;
const char* status = wuffs_lzw__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED);
if (status) {
RETURN_FAIL("initialize: \"%s\"", status);
}
CHECK_STATUS("initialize",
wuffs_lzw__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
wuffs_lzw__decoder__set_literal_width(&dec, width);
wuffs_base__io_buffer got = ((wuffs_base__io_buffer){
.data = global_got_slice,
});
status =
wuffs_lzw__decoder__decode_io_writer(&dec, &got, &src, global_work_slice);
if (status) {
RETURN_FAIL("decode: \"%s\"", status);
}
CHECK_STATUS("transform_io", wuffs_lzw__decoder__transform_io(
&dec, &got, &src, global_work_slice));
return check_io_buffers_equal("", &got, &want);
}
@@ -388,10 +381,7 @@ const char* do_bench_wuffs_lzw_decode(const char* filename,
.data = global_src_slice,
});
const char* status = read_file(&src, filename);
if (status) {
return status;
}
CHECK_STRING(read_file(&src, filename));
if (src.meta.wi <= 0) {
RETURN_FAIL("src size: got %d, want > 0", (int)(src.meta.wi));
}
@@ -409,17 +399,12 @@ const char* do_bench_wuffs_lzw_decode(const char* filename,
got.meta.wi = 0;
src.meta.ri = 1; // Skip the literal width.
wuffs_lzw__decoder dec;
status = wuffs_lzw__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED);
if (status) {
RETURN_FAIL("initialize: \"%s\"", status);
}
status = wuffs_lzw__decoder__decode_io_writer(&dec, &got, &src,
global_work_slice);
if (status) {
RETURN_FAIL("decode: \"%s\"", status);
}
CHECK_STATUS("initialize",
wuffs_lzw__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
CHECK_STATUS("transform_io", wuffs_lzw__decoder__transform_io(
&dec, &got, &src, global_work_slice));
n_bytes += got.meta.wi;
}
bench_finish(iters, n_bytes);
@@ -443,6 +428,7 @@ proc tests[] = {
test_wuffs_lzw_decode_bricks_dither, //
test_wuffs_lzw_decode_bricks_nodither, //
test_wuffs_lzw_decode_interface, //
test_wuffs_lzw_decode_many_big_reads, //
test_wuffs_lzw_decode_many_small_writes_reads, //
test_wuffs_lzw_decode_output_bad, //

198
test/c/std/wbmp.c Normal file
View File

@@ -0,0 +1,198 @@
// 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_interface() {
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));
return do_test__wuffs_base__image_decoder(
wuffs_wbmp__decoder__upcast_as__wuffs_base__image_decoder(&dec),
"test/data/muybridge-frame-000.wbmp", 0, SIZE_MAX, 30, 20, 0xFFFFFFFF);
}
const char* test_wuffs_wbmp_decode_frame_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__frame_config fc = ((wuffs_base__frame_config){});
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
.data = global_src_slice,
});
CHECK_STRING(read_file(&src, "test/data/hat.wbmp"));
CHECK_STATUS("decode_frame_config #0",
wuffs_wbmp__decoder__decode_frame_config(&dec, &fc, &src));
wuffs_base__status status =
wuffs_wbmp__decoder__decode_frame_config(&dec, &fc, &src);
if (status.repr != wuffs_base__note__end_of_data) {
RETURN_FAIL("decode_frame_config #1: got \"%s\", want \"%s\"", status.repr,
wuffs_base__note__end_of_data);
}
if (src.meta.ri != src.meta.wi) {
RETURN_FAIL("at end of data: ri (%zu) doesn't equal wi (%zu)", src.meta.ri,
src.meta.wi);
}
return NULL;
}
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/bricks-nodither.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 = 160;
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 = 120;
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_frame_config, //
test_wuffs_wbmp_decode_image_config, //
test_wuffs_wbmp_decode_interface, //
#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);
}

View File

@@ -94,35 +94,45 @@ const size_t zlib_sheep_want_len = 11;
// ---------------- Zlib Tests
const char* test_wuffs_zlib_decode_interface() {
CHECK_FOCUS(__func__);
wuffs_zlib__decoder dec;
CHECK_STATUS("initialize",
wuffs_zlib__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
return do_test__wuffs_base__io_transformer(
wuffs_zlib__decoder__upcast_as__wuffs_base__io_transformer(&dec),
"test/data/romeo.txt.zlib", 0, SIZE_MAX, 942, 0x0A);
}
const char* wuffs_zlib_decode(wuffs_base__io_buffer* dst,
wuffs_base__io_buffer* src,
uint32_t wuffs_initialize_flags,
uint64_t wlimit,
uint64_t rlimit) {
wuffs_zlib__decoder dec;
const char* status = wuffs_zlib__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION, wuffs_initialize_flags);
if (status) {
return status;
}
CHECK_STATUS("initialize",
wuffs_zlib__decoder__initialize(&dec, sizeof dec, WUFFS_VERSION,
wuffs_initialize_flags));
while (true) {
wuffs_base__io_buffer limited_dst = make_limited_writer(*dst, wlimit);
wuffs_base__io_buffer limited_src = make_limited_reader(*src, rlimit);
status = wuffs_zlib__decoder__decode_io_writer(
wuffs_base__status status = wuffs_zlib__decoder__transform_io(
&dec, &limited_dst, &limited_src, global_work_slice);
dst->meta.wi += limited_dst.meta.wi;
src->meta.ri += limited_src.meta.ri;
if (((wlimit < UINT64_MAX) &&
(status == wuffs_base__suspension__short_write)) ||
(status.repr == wuffs_base__suspension__short_write)) ||
((rlimit < UINT64_MAX) &&
(status == wuffs_base__suspension__short_read))) {
(status.repr == wuffs_base__suspension__short_read))) {
continue;
}
return status;
return status.repr;
}
}
@@ -135,10 +145,7 @@ const char* do_test_wuffs_zlib_checksum(bool ignore_checksum,
.data = global_src_slice,
});
const char* status = read_file(&src, zlib_midsummer_gt.src_filename);
if (status) {
return status;
}
CHECK_STRING(read_file(&src, zlib_midsummer_gt.src_filename));
// Flip a bit in the zlib checksum, which is in the last 4 bytes of the file.
if (src.meta.wi < 4) {
RETURN_FAIL("source file was too short");
@@ -150,12 +157,10 @@ const char* do_test_wuffs_zlib_checksum(bool ignore_checksum,
int end_limit; // The rlimit, relative to the end of the data.
for (end_limit = 0; end_limit < 10; end_limit++) {
wuffs_zlib__decoder dec;
status = wuffs_zlib__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED);
if (status) {
RETURN_FAIL("initialize: \"%s\"", status);
}
CHECK_STATUS("initialize",
wuffs_zlib__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
wuffs_zlib__decoder__set_ignore_checksum(&dec, ignore_checksum);
got.meta.wi = 0;
src.meta.ri = 0;
@@ -183,12 +188,12 @@ const char* do_test_wuffs_zlib_checksum(bool ignore_checksum,
wuffs_base__io_buffer limited_src = make_limited_reader(src, rlimit);
const char* got_z = wuffs_zlib__decoder__decode_io_writer(
wuffs_base__status got_z = wuffs_zlib__decoder__transform_io(
&dec, &got, &limited_src, global_work_slice);
src.meta.ri += limited_src.meta.ri;
if (got_z != want_z) {
RETURN_FAIL("end_limit=%d: got \"%s\", want \"%s\"", end_limit, got_z,
want_z);
if (got_z.repr != want_z) {
RETURN_FAIL("end_limit=%d: got \"%s\", want \"%s\"", end_limit,
got_z.repr, want_z);
}
}
}
@@ -236,20 +241,18 @@ const char* test_wuffs_zlib_decode_sheep() {
make_io_buffer_from_string(zlib_sheep_src_ptr, zlib_sheep_src_len);
wuffs_zlib__decoder dec;
const char* status = wuffs_zlib__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION, WUFFS_INITIALIZE__DEFAULT_OPTIONS);
if (status) {
RETURN_FAIL("initialize: %s", status);
}
CHECK_STATUS("initialize", wuffs_zlib__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__DEFAULT_OPTIONS));
int i;
for (i = 0; i < 3; i++) {
status = wuffs_zlib__decoder__decode_io_writer(&dec, &got, &src,
global_work_slice);
wuffs_base__status status =
wuffs_zlib__decoder__transform_io(&dec, &got, &src, global_work_slice);
if (status != wuffs_zlib__warning__dictionary_required) {
RETURN_FAIL("decode_io_writer (before dict): got \"%s\", want \"%s\"",
status, wuffs_zlib__warning__dictionary_required);
if (status.repr != wuffs_zlib__note__dictionary_required) {
RETURN_FAIL("transform_io (before dict): got \"%s\", want \"%s\"",
status.repr, wuffs_zlib__note__dictionary_required);
}
uint32_t dict_id_got = wuffs_zlib__decoder__dictionary_id(&dec);
@@ -266,11 +269,9 @@ const char* test_wuffs_zlib_decode_sheep() {
.len = zlib_sheep_dict_len,
}));
status = wuffs_zlib__decoder__decode_io_writer(&dec, &got, &src,
global_work_slice);
if (status) {
RETURN_FAIL("decode_io_writer (after dict): %s", status);
}
CHECK_STATUS(
"transform_io (after dict)",
wuffs_zlib__decoder__transform_io(&dec, &got, &src, global_work_slice));
wuffs_base__io_buffer want =
make_io_buffer_from_string(zlib_sheep_want_ptr, zlib_sheep_want_len);
@@ -358,6 +359,7 @@ proc tests[] = {
test_wuffs_zlib_checksum_verify_bad0, //
test_wuffs_zlib_checksum_verify_bad3, //
test_wuffs_zlib_checksum_verify_good, //
test_wuffs_zlib_decode_interface, //
test_wuffs_zlib_decode_midsummer, //
test_wuffs_zlib_decode_pi, //
test_wuffs_zlib_decode_sheep, //

View File

@@ -30,30 +30,34 @@ uint8_t global_work_array[BUFFER_SIZE];
uint8_t global_src_array[BUFFER_SIZE];
uint8_t global_pixel_array[BUFFER_SIZE];
wuffs_base__slice_u8 global_got_slice = ((wuffs_base__slice_u8){
.ptr = global_got_array,
.len = BUFFER_SIZE,
});
wuffs_base__slice_u8 global_got_slice;
wuffs_base__slice_u8 global_want_slice;
wuffs_base__slice_u8 global_work_slice;
wuffs_base__slice_u8 global_src_slice;
wuffs_base__slice_u8 global_pixel_slice;
wuffs_base__slice_u8 global_want_slice = ((wuffs_base__slice_u8){
.ptr = global_want_array,
.len = BUFFER_SIZE,
});
wuffs_base__slice_u8 global_work_slice = ((wuffs_base__slice_u8){
.ptr = global_work_array,
.len = BUFFER_SIZE,
});
wuffs_base__slice_u8 global_src_slice = ((wuffs_base__slice_u8){
.ptr = global_src_array,
.len = BUFFER_SIZE,
});
wuffs_base__slice_u8 global_pixel_slice = ((wuffs_base__slice_u8){
.ptr = global_pixel_array,
.len = BUFFER_SIZE,
});
void wuffs_testlib__initialize_global_xxx_slices() {
global_got_slice = ((wuffs_base__slice_u8){
.ptr = global_got_array,
.len = BUFFER_SIZE,
});
global_want_slice = ((wuffs_base__slice_u8){
.ptr = global_want_array,
.len = BUFFER_SIZE,
});
global_work_slice = ((wuffs_base__slice_u8){
.ptr = global_work_array,
.len = BUFFER_SIZE,
});
global_src_slice = ((wuffs_base__slice_u8){
.ptr = global_src_array,
.len = BUFFER_SIZE,
});
global_pixel_slice = ((wuffs_base__slice_u8){
.ptr = global_pixel_array,
.len = BUFFER_SIZE,
});
}
char fail_msg[65536] = {0};
@@ -61,9 +65,26 @@ char fail_msg[65536] = {0};
return (snprintf(fail_msg, sizeof(fail_msg), ##__VA_ARGS__) >= 0) \
? fail_msg \
: "unknown failure (snprintf-related)"
#define INCR_FAIL(msg, ...) \
msg += snprintf(msg, sizeof(fail_msg) - (msg - fail_msg), ##__VA_ARGS__)
#define CHECK_STATUS(prefix, status) \
do { \
wuffs_base__status z = status; \
if (z.repr) { \
RETURN_FAIL("%s: \"%s\"", prefix, z.repr); \
} \
} while (0)
#define CHECK_STRING(string) \
do { \
const char* z = string; \
if (z) { \
return z; \
} \
} while (0)
int tests_run = 0;
uint64_t iterscale = 100;
@@ -243,6 +264,7 @@ const char* chdir_to_the_wuffs_root_directory() {
typedef const char* (*proc)();
int test_main(int argc, char** argv, proc* tests, proc* benches) {
wuffs_testlib__initialize_global_xxx_slices();
const char* status = chdir_to_the_wuffs_root_directory();
if (status) {
fprintf(stderr, "%s\n", status);
@@ -426,12 +448,12 @@ const char* copy_to_io_buffer_from_pixel_buffer(wuffs_base__io_buffer* dst,
wuffs_base__pixel_format pixfmt =
wuffs_base__pixel_config__pixel_format(&src->pixcfg);
if (wuffs_base__pixel_format__is_planar(pixfmt)) {
if (wuffs_base__pixel_format__is_planar(&pixfmt)) {
// If we want to support planar pixel buffers, in the future, be concious
// of pixel subsampling.
return "copy_to_io_buffer_from_pixel_buffer: cannot copy from planar src";
}
uint32_t bits_per_pixel = wuffs_base__pixel_format__bits_per_pixel(pixfmt);
uint32_t bits_per_pixel = wuffs_base__pixel_format__bits_per_pixel(&pixfmt);
if (bits_per_pixel == 0) {
return "copy_to_io_buffer_from_pixel_buffer: invalid bits_per_pixel";
} else if ((bits_per_pixel % 8) != 0) {
@@ -518,6 +540,23 @@ const char* read_file(wuffs_base__io_buffer* dst, const char* path) {
return NULL;
}
const char* read_file_fragment(wuffs_base__io_buffer* dst,
const char* path,
size_t ri_min,
size_t wi_max) {
CHECK_STRING(read_file(dst, path));
if (dst->meta.ri < ri_min) {
dst->meta.ri = ri_min;
}
if (dst->meta.wi > wi_max) {
dst->meta.wi = wi_max;
}
if (dst->meta.ri > dst->meta.wi) {
RETURN_FAIL("read_file_fragment(\"%s\"): ri > wi", path);
}
return NULL;
}
char* hex_dump(char* msg, wuffs_base__io_buffer* buf, size_t i) {
if (!msg || !buf) {
RETURN_FAIL("hex_dump: NULL argument");
@@ -723,4 +762,119 @@ const char* do_test_io_buffers(const char* (*codec_func)(wuffs_base__io_buffer*,
tc_neither, gt, wlimit, rlimit, 1, false);
}
// --------
const char* do_test__wuffs_base__hasher_u32(wuffs_base__hasher_u32* b,
const char* src_filename,
size_t src_ri,
size_t src_wi,
uint32_t want) {
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
.data = global_src_slice,
});
CHECK_STRING(read_file_fragment(&src, src_filename, src_ri, src_wi));
uint32_t got = wuffs_base__hasher_u32__update_u32(
b, ((wuffs_base__slice_u8){
.ptr = (uint8_t*)(src.data.ptr + src.meta.ri),
.len = (size_t)(src.meta.wi - src.meta.ri),
}));
if (got != want) {
RETURN_FAIL("got 0x%08" PRIX32 ", want 0x%08" PRIX32, got, want);
}
return NULL;
}
const char* do_test__wuffs_base__image_decoder(
wuffs_base__image_decoder* b,
const char* src_filename,
size_t src_ri,
size_t src_wi,
uint32_t want_width,
uint32_t want_height,
wuffs_base__color_u32_argb_premul want_final_pixel) {
if ((want_width > 16384) || (want_height > 16384) ||
((want_width * want_height * 4) > BUFFER_SIZE)) {
return "want dimensions are too large";
}
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_fragment(&src, src_filename, src_ri, src_wi));
CHECK_STATUS("decode_image_config",
wuffs_base__image_decoder__decode_image_config(b, &ic, &src));
uint32_t got_width = wuffs_base__pixel_config__width(&ic.pixcfg);
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);
if (got_height != want_height) {
RETURN_FAIL("height: got %" PRIu32 ", want %" PRIu32, got_height,
want_height);
}
wuffs_base__pixel_config__set(
&ic.pixcfg, WUFFS_BASE__PIXEL_FORMAT__BGRA_PREMUL,
WUFFS_BASE__PIXEL_SUBSAMPLING__NONE, want_width, want_height);
wuffs_base__pixel_buffer pb = ((wuffs_base__pixel_buffer){});
CHECK_STATUS("set_from_slice", wuffs_base__pixel_buffer__set_from_slice(
&pb, &ic.pixcfg, global_pixel_slice));
CHECK_STATUS("decode_frame", wuffs_base__image_decoder__decode_frame(
b, &pb, &src, WUFFS_BASE__PIXEL_BLEND__SRC,
global_work_slice, NULL));
uint64_t n = wuffs_base__pixel_config__pixbuf_len(&ic.pixcfg);
if (n < 4) {
RETURN_FAIL("pixbuf_len too small");
} else if (n > BUFFER_SIZE) {
RETURN_FAIL("pixbuf_len too large");
}
wuffs_base__color_u32_argb_premul got_final_pixel =
wuffs_base__load_u32le(&global_pixel_array[n - 4]);
if (got_final_pixel != want_final_pixel) {
RETURN_FAIL("final pixel: got 0x%08" PRIX32 ", want 0x%08" PRIX32,
got_final_pixel, want_final_pixel);
}
return NULL;
}
const char* do_test__wuffs_base__io_transformer(wuffs_base__io_transformer* b,
const char* src_filename,
size_t src_ri,
size_t src_wi,
size_t want_wi,
uint8_t want_final_byte) {
if (want_wi > BUFFER_SIZE) {
return "want_wi is too large";
}
wuffs_base__range_ii_u64 workbuf_len =
wuffs_base__io_transformer__workbuf_len(b);
if (workbuf_len.min_incl > workbuf_len.max_incl) {
return "inconsistent workbuf_len";
}
if (workbuf_len.max_incl > BUFFER_SIZE) {
return "workbuf_len is too large";
}
wuffs_base__io_buffer got = ((wuffs_base__io_buffer){
.data = global_got_slice,
});
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
.data = global_src_slice,
});
CHECK_STRING(read_file_fragment(&src, src_filename, src_ri, src_wi));
CHECK_STATUS("transform_io", wuffs_base__io_transformer__transform_io(
b, &got, &src, global_work_slice));
if (got.meta.wi != want_wi) {
RETURN_FAIL("dst wi: got %zu, want %zu", got.meta.wi, want_wi);
}
if ((want_wi > 0) && (got.data.ptr[want_wi - 1] != want_final_byte)) {
RETURN_FAIL("final byte: got 0x%02X, want 0x%02X",
got.data.ptr[want_wi - 1], want_final_byte);
}
return NULL;
}
#endif // WUFFS_INCLUDE_GUARD

View File

@@ -6,8 +6,9 @@ were generated by script/extract-palette-indexes.go
The \*.jpeg files are usually the canonical versions of the test/data images,
and other versions (\*.bmp, \*.gif, \*.png, \*.tiff) were generated by
ImageMagick's convert command line tool. The \*.webp versions were generated by
the cwebp command line tool.
ImageMagick's convert command line tool. The \*.wbmp versions were generated by
the `script/convert-png-to-wbmp.go` command line tool. The \*.webp versions
were generated by the cwebp command line tool.

Binary file not shown.

View File

@@ -0,0 +1,22 @@
[
{
"name": "v0.2.0",
"zipball_url": "https://api.github.com/repos/google/wuffs/zipball/v0.2.0",
"tarball_url": "https://api.github.com/repos/google/wuffs/tarball/v0.2.0",
"commit": {
"sha": "fb600fe3ce5e161936849148aa4d3ad82dfc5743",
"url": "https://api.github.com/repos/google/wuffs/commits/fb600fe3ce5e161936849148aa4d3ad82dfc5743"
},
"node_id": "MDM6UmVmMTEwNDgyMjY3OnYwLjIuMA=="
},
{
"name": "v0.1.0",
"zipball_url": "https://api.github.com/repos/google/wuffs/zipball/v0.1.0",
"tarball_url": "https://api.github.com/repos/google/wuffs/tarball/v0.1.0",
"commit": {
"sha": "f604194ba4d7f9721105b6ec328422b5f98fe8bd",
"url": "https://api.github.com/repos/google/wuffs/commits/f604194ba4d7f9721105b6ec328422b5f98fe8bd"
},
"node_id": "MDM6UmVmMTEwNDgyMjY3OnYwLjEuMA=="
}
]

BIN
test/data/hat.wbmp Normal file

Binary file not shown.

Binary file not shown.