mirror of
https://github.com/google/wuffs.git
synced 2026-01-18 17:11:32 +01:00
Merge branch 'master' into fix-typos
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
462
example/imageviewer/imageviewer.c
Normal file
462
example/imageviewer/imageviewer.c
Normal 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)
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) ||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 //
|
||||
|
||||
@@ -15,3 +15,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
// ---------------- Images
|
||||
|
||||
// ---------------- Images (Utility)
|
||||
|
||||
#define wuffs_base__utility__make_pixel_format wuffs_base__make_pixel_format
|
||||
|
||||
@@ -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 //
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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" +
|
||||
""
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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) {
|
||||
|
||||
126
script/convert-png-to-wbmp.go
Normal file
126
script/convert-png-to-wbmp.go
Normal 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
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
269
std/wbmp/decode_wbmp.wuffs
Normal 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)
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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, //
|
||||
|
||||
1182
test/c/std/gif.c
1182
test/c/std/gif.c
File diff suppressed because it is too large
Load Diff
@@ -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, //
|
||||
|
||||
|
||||
122
test/c/std/lzw.c
122
test/c/std/lzw.c
@@ -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
198
test/c/std/wbmp.c
Normal 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);
|
||||
}
|
||||
@@ -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, //
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
|
||||
|
||||
BIN
test/data/bricks-nodither.wbmp
Normal file
BIN
test/data/bricks-nodither.wbmp
Normal file
Binary file not shown.
22
test/data/github-tags.json
Normal file
22
test/data/github-tags.json
Normal 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
BIN
test/data/hat.wbmp
Normal file
Binary file not shown.
BIN
test/data/muybridge-frame-000.wbmp
Normal file
BIN
test/data/muybridge-frame-000.wbmp
Normal file
Binary file not shown.
Reference in New Issue
Block a user