Update wuffs to match the version used by Skia
Change-Id: I4c98412464785f1175af68d6d7ae9f8b1038ace2
diff --git a/cmd/ractool/main.go b/cmd/ractool/main.go
new file mode 100644
index 0000000..c552ba3
--- /dev/null
+++ b/cmd/ractool/main.go
@@ -0,0 +1,148 @@
+// Copyright 2019 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.
+
+// ----------------
+
+// ractool manipulates Random Access Compression (RAC) files.
+package main
+
+import (
+ "bytes"
+ "errors"
+ "flag"
+ "fmt"
+ "io"
+ "os"
+
+ "github.com/google/wuffs/lib/raczlib"
+)
+
+// TODO: a flag to use a disk-backed (not memory-backed) TempFile.
+
+var (
+ decodeFlag = flag.Bool("decode", false, "whether to decode the input")
+ encodeFlag = flag.Bool("encode", false, "whether to encode the input")
+
+ codecFlag = flag.String("codec", "zlib", "when encoding, the compression codec")
+ cpagesizeFlag = flag.Uint64("cpagesize", 0, "when encoding, the page size (in CSpace)")
+ cchunksizeFlag = flag.Uint64("cchunksize", 0, "when encoding, the chunk size (in CSpace)")
+ dchunksizeFlag = flag.Uint64("dchunksize", 0, "when encoding, the chunk size (in DSpace)")
+ indexlocationFlag = flag.String("indexlocation", "start",
+ "when encoding, the index location, \"start\" or \"end\"")
+)
+
+const usageStr = `usage: ractool [flags] [input_filename]
+
+If no input_filename is given, stdin is used. Either way, output is written to
+stdout.
+
+The flags should include exactly one of -decode or -encode.
+
+Decoding is not yet implemented.
+
+When encoding, the input is partitioned into chunks and each chunk is
+compressed independently. You can specify the target chunk size in terms of
+either its compressed size or decompressed size. By default (if both
+-cchunksize and -dchunksize are zero), a 64KiB -cchunksize is used.
+
+You can also specify a -cpagesize, which is similar to but not exactly the same
+concept as alignment. If non-zero, padding is inserted into the output to
+minimize the number of pages that each chunk occupies. Look for "CPageSize" in
+the "package rac" documentation for more details.
+
+A RAC file consists of an index and the chunks. The index may be either at the
+start or at the end of the file. See the RAC specification for more details:
+
+https://github.com/google/wuffs/blob/master/doc/spec/rac-spec.md
+
+`
+
+func usage() {
+ fmt.Fprintf(os.Stderr, usageStr)
+ flag.PrintDefaults()
+}
+
+func main() {
+ if err := main1(); err != nil {
+ os.Stderr.WriteString(err.Error() + "\n")
+ os.Exit(1)
+ }
+}
+
+func main1() error {
+ flag.Usage = usage
+ flag.Parse()
+
+ r := io.Reader(os.Stdin)
+ switch flag.NArg() {
+ case 0:
+ // No-op.
+ case 1:
+ f, err := os.Open(flag.Arg(0))
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ r = f
+ default:
+ return errors.New("too many filenames; the maximum is one")
+ }
+
+ if *decodeFlag && !*encodeFlag {
+ return decode(r)
+ }
+ if *encodeFlag && !*decodeFlag {
+ return encode(r)
+ }
+ return errors.New("must specify exactly one of -decode or -encode")
+}
+
+func decode(r io.Reader) error {
+ return errors.New("TODO: implement a decoder")
+}
+
+func encode(r io.Reader) error {
+ indexLocation := raczlib.IndexLocation(0)
+ switch *indexlocationFlag {
+ case "start":
+ indexLocation = raczlib.IndexLocationAtStart
+ case "end":
+ indexLocation = raczlib.IndexLocationAtEnd
+ default:
+ return errors.New("invalid -indexlocation")
+ }
+
+ if (*cchunksizeFlag != 0) && (*dchunksizeFlag != 0) {
+ return errors.New("must specify none or one of -cchunksize or -dchunksize")
+ } else if (*cchunksizeFlag == 0) && (*dchunksizeFlag == 0) {
+ *cchunksizeFlag = 65536 // 64 KiB.
+ }
+
+ switch *codecFlag {
+ case "zlib":
+ w := &raczlib.Writer{
+ Writer: os.Stdout,
+ IndexLocation: indexLocation,
+ TempFile: &bytes.Buffer{},
+ CPageSize: *cpagesizeFlag,
+ CChunkSize: *cchunksizeFlag,
+ DChunkSize: *dchunksizeFlag,
+ }
+ if _, err := io.Copy(w, r); err != nil {
+ return err
+ }
+ return w.Close()
+ }
+ return errors.New("unsupported -codec")
+}
diff --git a/doc/changelog.md b/doc/changelog.md
index 205ad84..3d9501c 100644
--- a/doc/changelog.md
+++ b/doc/changelog.md
@@ -37,6 +37,7 @@
- Added a `reset` method.
- Added `peek_uxx`, `skip_fast` and `write_fast_uxx` methods.
- Renamed some `read_uxx` methods as `read_uxx_as_uyy`.
+- Report image metadata such as ICCP and XMP.
- Added I/O positions.
- Added extra fields (uninitialized internal buffers) to structs.
- Tweaked how marks and limits work.
@@ -68,4 +69,4 @@
---
-Updated on March 2019.
+Updated on April 2019.
diff --git a/doc/note/README.md b/doc/note/README.md
new file mode 100644
index 0000000..d1ec6fd
--- /dev/null
+++ b/doc/note/README.md
@@ -0,0 +1,2 @@
+This directory contains notes: short articles about various Wuffs concepts that
+aren't specific to any one file format or package.
diff --git a/doc/note/base38-and-fourcc.md b/doc/note/base38-and-fourcc.md
new file mode 100644
index 0000000..dc3c83f
--- /dev/null
+++ b/doc/note/base38-and-fourcc.md
@@ -0,0 +1,53 @@
+# Base38 and FourCC Codes
+
+Both of these encode a four-character string such as `"JPEG"` as a `uint32_t`
+value. Computers can compare two integer values faster than they can compare
+two arbitrary strings.
+
+Both schemes maintain ordering: if two four-character strings `s` and `t`
+satisfy `(s < t)`, and those strings have valid numerical encodings, then the
+numerical values also satisfy `(encoding(s) < encoding(t))`.
+
+
+## FourCC
+
+FourCC codes are not specific to Wuffs. For example, the AVI multimedia
+container format can hold various sub-formats, such as "H264" or "YV12",
+distinguished in the overall file format by their FourCC code.
+
+The FourCC encoding is the straightforward sequence of each character's ASCII
+encoding. The FourCC code for `"JPEG"` is `0x4A504547`, since `'J'` is `0x4A`,
+`'P'` is `0x50`, etc. This is essentially 8 bits for each character, 32 bits
+overall. The big-endian representation of this number is exactly the ASCII (and
+UTF-8) string `"JPEG"`.
+
+Other FourCC documentation sometimes use a little-endian convention, so that
+the `{0x4A, 0x50, 0x45, 0x47}` bytes on the wire for `"JPEG"` corresponds to
+the number `0x4745504A` (little-endian) instead of `0x4A504547` (big-endian).
+Wuffs uses the big-endian interpretation, as it maintains ordering.
+
+
+## Base38
+
+Base38 is a tighter encoding than FourCC, fitting four characters into 21 bits
+instead of 32 bits. This is achieved by using a smaller alphabet of 38 possible
+values (space, 0-9, ? or a-z), so that it cannot distinguish between e.g. an
+upper case 'X' and a lower case 'x'. There's also the happy coincidence that
+`38 ** 4` is slightly smaller than `2 ** 21`.
+
+The base38 encoding of `"JPEG"` is `0x122FF6`, which is `1191926`, which is
+`((21 * (38 ** 3)) + (27 * (38 ** 2)) + (16 * (38 ** 1)) + (18 * (38 ** 0)))`.
+
+Using only 21 bits means that we can use base38 values to partition the set of
+possible `uint32_t` values into file-format specific enumerations. Each package
+(i.e. Wuffs implementation of a specific file format) can define up to 1024
+different values in their own namespace, without conflicting with other
+packages (assuming that there aren't e.g. two `"JPEG"` Wuffs packages in the
+same library). The conventional `uint32_t` packing is:
+
+- Bit 31 is reserved (zero).
+- Bits 30 .. 10 are the base38 value, shifted by 10.
+- Bits 9 .. 0 are the enumeration value.
+
+For example, [quirk values](/doc/note/quirks.md) use this `((base38 << 10) |
+enumeration)` scheme.
diff --git a/doc/note/io-input-output.md b/doc/note/io-input-output.md
new file mode 100644
index 0000000..056ae43
--- /dev/null
+++ b/doc/note/io-input-output.md
@@ -0,0 +1,212 @@
+# I/O (Input / Output)
+
+Wuffs per se doesn't have the ability to read or write to files or network
+connections. Recall that Wuffs is a programming language for writing libraries,
+not applications, and that having fewer capabilities means that it's trivial to
+prove that you can't misuse a capability, even when given malicious input.
+
+Instead, the code that calls into Wuffs libraries is responsible for
+interfacing with e.g. the file system or the network system. An `io_buffer` is
+the mechanism for transferring data into and out of Wuffs libraries. For
+example, when decompressing gzip, there are two `io_buffer`'s: the caller fills
+a source buffer with e.g. the compressed file's contents and the callee (the
+Wuffs library) reads compressed bytes from that source buffer and writes
+decompressed bytes to a destination buffer.
+
+
+## I/O Buffers
+
+An `io_buffer` is a [slice](/doc/note/slices-and-tables.md) of bytes (the data,
+a `ptr` and `len`) with additional fields (the metadata): a read index (`ri`),
+a write index (`wi`), a position (`pos`) and whether or not it is `closed`.
+
+
+## Read Index and Write Index
+
+Writing to an `io_buffer`, e.g. copying from a file to a buffer, increments
+`wi`. The buffer is full for writing (no more can be written) when `wi` equals
+`len`. Writing does not have to fill a buffer before further processing.
+
+Reading from an `io_buffer`, e.g. copying from a buffer to a file, increments
+`ri`. The buffer is empty for reading (no more can be read) when `ri` equals
+`wi`. Reading does not have to empty a buffer before further processing.
+
+An invariant condition is that `((0 <= ri) and (ri <= wi) and (wi <= len))`.
+
+Having separate read and write indexes simplifies connecting a sequence of
+filters or processors with `io_buffer`'s, similar to connecting Unix processes
+with pipes. Each filter reads from the previous buffer and writes to the next
+buffer. Each buffer is written to by the previous filter and is read from by
+the next filter. There's no need to flip a buffer between reading and writing
+modes. Nonetheless, `io_buffer`'s are generally not thread-safe.
+
+Continuing the "decompressing gzip" example, the application would write to the
+source buffer by copying from e.g. `/dev/stdin`. The Wuffs library would read
+from the source buffer and write to the destination buffer. The application
+would read from the destination buffer by copying to e.g. `stdout`. Buffer
+space can be re-used, via compaction (see below), so that neither the source
+(`/dev/stdin`) or destination (`/dev/stdout`) data needs to be entirely in
+memory at any point.
+
+For example, an `io_buffer` of length 8 could have 4 bytes available to read
+and 1 byte available to write. If 1 byte was written, there would then be 5
+bytes available to read. Visually:
+
+```
+[.. .. .. .. .. .. .. ..]
+ |<- ri ->| | |
+ |<------- wi ------->| |
+ |<-------- len -------->|
+```
+
+
+## Position
+
+An `io_buffer` is a sliding window into a stream of bytes. Its position (`pos`)
+is the number of bytes in the stream prior to the first element of the slice.
+The total number of bytes read from and written to the stream are therefore
+`(pos + ri)` and `(pos + wi)`.
+
+While every slice element is in-memory, the stream's prior bytes do not
+necessarily have to be in-memory now, or have been in-memory in the past. It is
+valid to open a file, seek to the 1000'th byte and start copying from there to
+an `io_buffer`, provided that `pos` was also initialized to 1000.
+
+
+## Closed-ness
+
+The `closed` field indicates that no further writes are expected to the
+`io_buffer`. When copying from a file to a buffer, `closed` means that we have
+reached EOF (End Of File).
+
+For example, decoding a particular file format might, at some point, expect at
+least another 4 bytes of data, but only 3 are available to read. If `closed` is
+false, this isn't necessarily an error, since an `io_buffer` holds only a
+partial view of the underlying data stream, and more data might be forthcoming
+but not yet buffered. If `closed` is true, it is definitely an error.
+
+
+## Undoing Reads and Writes
+
+It is possible to decrement `ri` or `wi`, undoing previous reads or writes,
+provided that the invariant `((0 <= ri) and (ri <= wi) and (wi <= len))` holds.
+For example, it can be faster on 64 bit (8 byte) systems, if buffer space is
+available, to write 8 bytes and then undo 1 byte than to write exactly 7 bytes.
+
+The Wuffs compiler enforces that, during a Wuffs function, `ri` and `wi` will
+never be decremented (by an undo operation) to be less than the initial values
+at the time of the call. When considering a function as a 'black box', the two
+indexes can only travel forward, and it is up to the application code (not
+Wuffs library) code to rewind the indexes (e.g. by compaction).
+
+Even though `ri` can not drop below its initial value, Wuffs code can still
+read the contents of the slice before `ri` (in sub-slice notation,
+`data[0:ri]`) and it should still contain the `(pos + 0)`th, `(pos + 1)`th,
+etc. byte of the stream.
+
+The contents of the slice after `wi` (in sub-slice notation, `data[wi:len]`)
+are undefined, and code should not rely on its values. When passing an
+`io_buffer` into a function, that function is free to modify anything in
+`data[wi:len]`, for either value of `wi` before or after the function returns.
+
+
+## Compaction
+
+Compacting an `io_buffer` moves any written but unread bytes (those in
+`data[ri:wi]`) to the start of the buffer, and updates the metadata fields
+`ri`, `wi` and `pos`. Equivalently, it moves the sliding window that is the
+`io_buffer` as far forward as possible along the stream.
+
+This generally increases `(len - wi)`, the number of bytes available for
+writing, allowing for re-using the allocated buffer memory (the data slice).
+
+Suppose that the underlying data stream's `i`th byte has value `i`, and that we
+start with `ri`, `wi` and `pos` were `3`, `7` and `20`. Compaction will
+subtract 3 from the first two and add 3 to the last, so that the new `ri`, `wi`
+and `pos` are `0`, `4` and `23`. Note that `len`, `(pos + ri)` and `(pos + wi)`
+are all unchanged.
+
+Here are two equivalent visualizations of before and after compaction. The `xx`
+means a byte whose value is undefined (as it is at or past `wi`).
+
+The first visualization is where the slice is fixed and its contents (its view
+of the stream) moves relative to the slice:
+
+```
+Before:
+[20 21 22 23 24 25 26 xx]
+ |<- ri ->| | |
+ |<------- wi ------->| |
+ |<-------- len -------->|
+
+After:
+[23 24 25 26 xx xx xx xx]
+ || | |
+ |<-- wi --->| |
+ |<-------- len -------->|
+```
+
+The second visualization is where the stream (and its contents) is fixed and
+the slice (the sliding window) moves relative to the stream:
+
+```
+ pos+ri pos+wi
+ | |
+Before: [20 21 22 23 24 25 26 xx]
+Stream: ... 18 19 20 21 22 23 24 25 26 27 27 28 29 30 31 ...
+After: [23 24 25 26 xx xx xx xx]
+ | |
+ pos+ri pos+wi
+```
+
+
+## Seeking and I/O Positions
+
+Recall that Wuffs code has limited capabilities, and cannot seek in the
+underlying I/O data streams per se. When it needs to seek (e.g. when jumping
+between video frames), it will typically provide an "I/O position", a
+`uint64_t` value, via some package-specific API. The application (the caller of
+the Wuffs code) is then responsible for configuring an `io_buffer` whose
+`(pos + ri)` or `(pos + wi)` value, depending on whether we're reading or
+writing, is at that "I/O position".
+
+If the underlying file (or equivalent) isn't seekable, e.g. it's `/dev/stdin`
+instead of a regular file, then the request cannot be satisfied. The
+application should then decide whether that error is recoverable or fatal. This
+is the application's responsibility, not the library's, as the application
+usually has more context to make that decision.
+
+If that "I/O position" is already within the sliding window, it might not be
+necessary to seek in the underlying file, as it may be possible to e.g. simply
+decrement `ri` to reach a target `(pos + ri)`, for the reading case. Otherwise,
+the typical process is:
+
+1. Set `ri`, `wi` and `pos` to `0`, `0` and that "I/O position". This discards
+ any buffered data (but does not free the buffer's memory).
+2. Seek in the underlying file to that same "I/O position".
+3. Copy from the underlying file to the `io_buffer`, incrementing `wi`.
+
+Whether or not it was necessary to seek and copy from the underlying file, when
+calling back into the Wuffs library, it typically checks that the `io_buffer`'s
+`(pos + ri)` is now at the expected "I/O position".
+
+
+## I/O Reader and I/O Writer
+
+An `io_buffer` is the mechanism for transferring data between the application
+and the Wuffs library. Application code can manipulate an `io_buffer`'s fields
+as it wishes (but is responsible for maintaining the invariant condition).
+Wuffs library code places a further restriction that `io_buffer`s are used
+exclusively either for reading or for writing, as optimizing incremental access
+to an `io_buffer`'s data, while enforcing invariants, is simpler when only one
+of `ri` and `wi` can vary.
+
+Wuffs code therefore refers to either a `base.io_reader` or `base.io_writer`,
+both of which are essentially the same type (an `io_buffer`) with different
+methods. Wuffs code does not reference an `io_buffer` directly.
+
+
+## Binding
+
+TODO: discuss `io_bind`, which temporarily adapts a slice of bytes into an
+`io_buffer`.
diff --git a/doc/note/quirks.md b/doc/note/quirks.md
new file mode 100644
index 0000000..f919da3
--- /dev/null
+++ b/doc/note/quirks.md
@@ -0,0 +1,34 @@
+# Quirks
+
+Quirks are configuration options that let Wuffs more closely match other codec
+implementations.
+
+Some codecs and file formats are more tightly specified than others. When a
+spec doesn't fully dictate how to treat malformed files, different codec
+implementations have disagreed on whether to accept it (e.g. whether they
+follow Postel's Principle of "be liberal in what you accept") and if so, how to
+interpret it. Some implementations also raise those decisions to the
+application level, not the library level: "provide mechanism, not policy".
+
+For example, in an animated GIF image, the first frame might not fill out the
+entire image, and different implementations choose a different default color
+for the outside pixels: opaque black, transparent black, or something else.
+
+Wuffs, out of the box, makes particular choices (typically mimicking the de
+facto canonical implementation), but enabling various quirks result in
+different choices. In particular, quirks are useful in regression testing that
+Wuffs and another implementation produce the same output for the same input,
+even for malformed input.
+
+
+## Wuffs API
+
+Each quirk is assigned a `uint32_t` value, packed using the [base38 namespace
+convention](/doc/note/base38-and-fourcc.md). Decoders and encoders can have a
+`set_quirk_enabled!(quirk base.u32, enabled base.bool)` method whose first
+argument is this `uint32_t` value.
+
+For example, the base38 encoding of `"gif "` is `0xF8586`, so that the
+GIF-specific quirks have a `uint32_t` value of `((0xF8586 << 10) | n)`, for
+some small integer `n`. The generated `C` language file defines human-readable
+names for those constant values.
diff --git a/example/gifplayer/gifplayer.c b/example/gifplayer/gifplayer.c
index 74ff1be..703b968 100644
--- a/example/gifplayer/gifplayer.c
+++ b/example/gifplayer/gifplayer.c
@@ -130,6 +130,7 @@
const char* reset_color = "\x1B[0m";
bool color_flag = false;
+bool quirk_honor_background_color_flag = false;
const int stdout_fd = 1;
static inline uint32_t load_u32le(uint8_t* p) {
@@ -138,7 +139,8 @@
}
void restore_background(wuffs_base__pixel_buffer* pb,
- wuffs_base__rect_ie_u32 bounds) {
+ wuffs_base__rect_ie_u32 bounds,
+ wuffs_base__color_u32_argb_premul background_color) {
size_t width = wuffs_base__pixel_config__width(&pb->pixcfg);
size_t y;
for (y = bounds.min_incl_y; y < bounds.max_excl_y; y++) {
@@ -146,7 +148,7 @@
wuffs_base__color_u32_argb_premul* d =
curr_dst_buffer + (y * width) + bounds.min_incl_x;
for (x = bounds.min_incl_x; x < bounds.max_excl_x; x++) {
- *d++ = 0;
+ *d++ = background_color;
}
}
}
@@ -296,6 +298,11 @@
return status;
}
+ if (quirk_honor_background_color_flag) {
+ wuffs_gif__decoder__set_quirk_enabled(
+ &dec, wuffs_gif__quirk_honor_background_color, true);
+ }
+
wuffs_base__io_buffer src;
src.data.ptr = src_buffer;
src.data.len = src_len;
@@ -303,11 +310,10 @@
src.meta.ri = 0;
src.meta.pos = 0;
src.meta.closed = true;
- wuffs_base__io_reader src_reader = wuffs_base__io_buffer__reader(&src);
if (first_play) {
wuffs_base__image_config ic = {0};
- status = wuffs_gif__decoder__decode_image_config(&dec, &ic, src_reader);
+ status = wuffs_gif__decoder__decode_image_config(&dec, &ic, &src);
if (status) {
return status;
}
@@ -334,13 +340,12 @@
return status;
}
memset(pixbuf.ptr, 0, pixbuf.len);
- memset(curr_dst_buffer, 0, dst_len);
}
while (1) {
wuffs_base__frame_config fc = {0};
wuffs_base__status status =
- wuffs_gif__decoder__decode_frame_config(&dec, &fc, src_reader);
+ wuffs_gif__decoder__decode_frame_config(&dec, &fc, &src);
if (status) {
if (status == wuffs_base__warning__end_of_data) {
break;
@@ -348,6 +353,16 @@
return status;
}
+ if (wuffs_base__frame_config__index(&fc) == 0) {
+ wuffs_base__color_u32_argb_premul background_color =
+ wuffs_base__frame_config__background_color(&fc);
+ size_t i;
+ size_t n = dst_len / sizeof(wuffs_base__color_u32_argb_premul);
+ for (i = 0; i < n; i++) {
+ curr_dst_buffer[i] = background_color;
+ }
+ }
+
switch (wuffs_base__frame_config__disposal(&fc)) {
case WUFFS_BASE__ANIMATION_DISPOSAL__RESTORE_PREVIOUS: {
memcpy(prev_dst_buffer, curr_dst_buffer, dst_len);
@@ -355,8 +370,7 @@
}
}
- status =
- wuffs_gif__decoder__decode_frame(&dec, &pb, src_reader, workbuf, NULL);
+ status = wuffs_gif__decoder__decode_frame(&dec, &pb, &src, workbuf, NULL);
if (status) {
if (status == wuffs_base__warning__end_of_data) {
break;
@@ -370,7 +384,8 @@
switch (wuffs_base__frame_config__disposal(&fc)) {
case WUFFS_BASE__ANIMATION_DISPOSAL__RESTORE_BACKGROUND: {
- restore_background(&pb, wuffs_base__frame_config__bounds(&fc));
+ restore_background(&pb, wuffs_base__frame_config__bounds(&fc),
+ wuffs_base__frame_config__background_color(&fc));
break;
}
case WUFFS_BASE__ANIMATION_DISPOSAL__RESTORE_PREVIOUS: {
@@ -423,6 +438,9 @@
if (!strcmp(argv[i], "-color")) {
color_flag = true;
}
+ if (!strcmp(argv[i], "-quirk_honor_background_color")) {
+ quirk_honor_background_color_flag = true;
+ }
}
const char* status = read_stdin();
diff --git a/example/library/library.c b/example/library/library.c
index 8726ca3..f8e258a 100644
--- a/example/library/library.c
+++ b/example/library/library.c
@@ -93,9 +93,6 @@
src.meta.pos = 0;
src.meta.closed = true;
- wuffs_base__io_writer dst_writer = wuffs_base__io_buffer__writer(&dst);
- wuffs_base__io_reader src_reader = wuffs_base__io_buffer__reader(&src);
-
wuffs_gzip__decoder* dec =
(wuffs_gzip__decoder*)(calloc(sizeof__wuffs_gzip__decoder(), 1));
if (!dec) {
@@ -109,7 +106,7 @@
return status;
}
status = wuffs_gzip__decoder__decode_io_writer(
- dec, dst_writer, src_reader,
+ dec, &dst, &src,
wuffs_base__make_slice_u8(work_buffer, WORK_BUFFER_SIZE));
if (status) {
free(dec);
diff --git a/example/zcat/zcat.c b/example/zcat/zcat.c
index c2bf06a..20d7fe4 100644
--- a/example/zcat/zcat.c
+++ b/example/zcat/zcat.c
@@ -124,8 +124,7 @@
while (true) {
status = wuffs_gzip__decoder__decode_io_writer(
- &dec, wuffs_base__io_buffer__writer(&dst),
- wuffs_base__io_buffer__reader(&src),
+ &dec, &dst, &src,
wuffs_base__make_slice_u8(work_buffer, WORK_BUFFER_SIZE));
if (dst.meta.wi) {
diff --git a/fuzz/c/fuzzlib/fuzzlib.c b/fuzz/c/fuzzlib/fuzzlib.c
index 03050f9..a91e1e4 100644
--- a/fuzz/c/fuzzlib/fuzzlib.c
+++ b/fuzz/c/fuzzlib/fuzzlib.c
@@ -27,7 +27,7 @@
*intentional_segfault_ptr = 0;
}
-const char* fuzz(wuffs_base__io_reader src_reader, uint32_t hash);
+const char* fuzz(wuffs_base__io_buffer* src, uint32_t hash);
static const char* llvmFuzzerTestOneInput(const uint8_t* data, size_t size) {
// Hash input as per https://en.wikipedia.org/wiki/Jenkins_hash_function
@@ -55,7 +55,7 @@
}),
});
- const char* msg = fuzz(wuffs_base__io_buffer__reader(&src), hash);
+ const char* msg = fuzz(&src, hash);
if (msg && strstr(msg, "internal error:")) {
fprintf(stderr, "internal errors shouldn't occur: \"%s\"\n", msg);
intentional_segfault();
diff --git a/fuzz/c/std/gif_fuzzer.c b/fuzz/c/std/gif_fuzzer.c
index c3ce2fd..2858c1c 100644
--- a/fuzz/c/std/gif_fuzzer.c
+++ b/fuzz/c/std/gif_fuzzer.c
@@ -48,7 +48,7 @@
#include "../../../release/c/wuffs-unsupported-snapshot.c"
#include "../fuzzlib/fuzzlib.c"
-const char* fuzz(wuffs_base__io_reader src_reader, uint32_t hash) {
+const char* fuzz(wuffs_base__io_buffer* src, uint32_t hash) {
const char* ret = NULL;
wuffs_base__slice_u8 pixbuf = ((wuffs_base__slice_u8){});
wuffs_base__slice_u8 workbuf = ((wuffs_base__slice_u8){});
@@ -67,7 +67,7 @@
}
wuffs_base__image_config ic = ((wuffs_base__image_config){});
- status = wuffs_gif__decoder__decode_image_config(&dec, &ic, src_reader);
+ status = wuffs_gif__decoder__decode_image_config(&dec, &ic, src);
if (status) {
ret = status;
goto exit;
@@ -115,7 +115,7 @@
bool seen_ok = false;
while (true) {
wuffs_base__frame_config fc = ((wuffs_base__frame_config){});
- status = wuffs_gif__decoder__decode_frame_config(&dec, &fc, src_reader);
+ status = wuffs_gif__decoder__decode_frame_config(&dec, &fc, src);
if (status) {
if ((status != wuffs_base__warning__end_of_data) || !seen_ok) {
ret = status;
@@ -123,8 +123,7 @@
goto exit;
}
- status = wuffs_gif__decoder__decode_frame(&dec, &pb, src_reader, workbuf,
- NULL);
+ status = wuffs_gif__decoder__decode_frame(&dec, &pb, src, workbuf, NULL);
wuffs_base__rect_ie_u32 frame_rect =
wuffs_base__frame_config__bounds(&fc);
diff --git a/fuzz/c/std/zlib_fuzzer.c b/fuzz/c/std/zlib_fuzzer.c
index ffded01..b452582 100644
--- a/fuzz/c/std/zlib_fuzzer.c
+++ b/fuzz/c/std/zlib_fuzzer.c
@@ -60,7 +60,7 @@
uint8_t work_buffer[1];
#endif
-const char* fuzz(wuffs_base__io_reader src_reader, uint32_t hash) {
+const char* fuzz(wuffs_base__io_buffer* src, uint32_t hash) {
wuffs_zlib__decoder dec;
const char* status = wuffs_zlib__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION,
@@ -81,11 +81,10 @@
.len = DST_BUFFER_SIZE,
}),
});
- wuffs_base__io_writer dst_writer = wuffs_base__io_buffer__writer(&dst);
while (true) {
dst.meta.wi = 0;
- status = wuffs_zlib__decoder__decode_io_writer(&dec, dst_writer, src_reader,
+ status = wuffs_zlib__decoder__decode_io_writer(&dec, &dst, src,
((wuffs_base__slice_u8){
.ptr = work_buffer,
.len = WORK_BUFFER_SIZE,
diff --git a/go.mod b/go.mod
index 3279328..4ec9849 100644
--- a/go.mod
+++ b/go.mod
@@ -1,3 +1,3 @@
module github.com/google/wuffs
-go 1.13
+go 1.12
diff --git a/internal/cgen/base/core-public.h b/internal/cgen/base/core-public.h
index dc7e7fb..f642fb7 100644
--- a/internal/cgen/base/core-public.h
+++ b/internal/cgen/base/core-public.h
@@ -197,6 +197,12 @@
// --------
+// FourCC constants.
+
+// !! INSERT FourCCs.
+
+// --------
+
// Flicks are a unit of time. One flick (frame-tick) is 1 / 705_600_000 of a
// second. See https://github.com/OculusVR/Flicks
typedef int64_t wuffs_base__flicks;
diff --git a/internal/cgen/base/image-impl.c b/internal/cgen/base/image-impl.c
index 6674c4a..7f62677 100644
--- a/internal/cgen/base/image-impl.c
+++ b/internal/cgen/base/image-impl.c
@@ -29,6 +29,61 @@
}
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) {
+ if (dst_palette.len != 1024) {
+ return 0;
+ }
+ size_t dst_len3 = dst.len / 3;
+ size_t len = dst_len3 < src.len ? dst_len3 : src.len;
+ uint8_t* d = dst.ptr;
+ uint8_t* s = src.ptr;
+ size_t n = len;
+
+ // N is the loop unroll count.
+ const int N = 4;
+
+ // The comparison in the while condition is ">", not ">=", because with ">=",
+ // the last 4-byte store could write past the end of the dst slice.
+ //
+ // Each 4-byte store writes one too many bytes, but a subsequent store will
+ // overwrite that with the correct byte. There is always another store,
+ // whether a 4-byte store in this loop or a 1-byte store in the next loop.
+ while (n > N) {
+ wuffs_base__store_u32le(
+ d + (0 * 3),
+ wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[0]) * 4)));
+ wuffs_base__store_u32le(
+ d + (1 * 3),
+ wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[1]) * 4)));
+ wuffs_base__store_u32le(
+ d + (2 * 3),
+ wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[2]) * 4)));
+ wuffs_base__store_u32le(
+ d + (3 * 3),
+ wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[3]) * 4)));
+
+ s += 1 * N;
+ d += 3 * N;
+ n -= (size_t)(1 * N);
+ }
+
+ while (n >= 1) {
+ uint32_t color =
+ wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[0]) * 4));
+ d[0] = (uint8_t)(color >> 0);
+ d[1] = (uint8_t)(color >> 8);
+ d[2] = (uint8_t)(color >> 16);
+
+ s += 1 * 1;
+ d += 3 * 1;
+ n -= (size_t)(1 * 1);
+ }
+
+ 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) {
@@ -39,8 +94,9 @@
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;
+
+ // N is the loop unroll count.
const int N = 4;
while (n >= N) {
@@ -98,14 +154,14 @@
return len4 * 4;
}
-void //
+wuffs_base__status //
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) {
if (!p) {
- return;
+ return wuffs_base__error__bad_receiver;
}
// TODO: support many more formats.
@@ -125,6 +181,13 @@
}
func = wuffs_base__pixel_swizzler__copy_1_1;
break;
+ case WUFFS_BASE__PIXEL_FORMAT__BGR:
+ if (wuffs_base__slice_u8__copy_from_slice(dst_palette, src_palette) !=
+ 1024) {
+ break;
+ }
+ func = wuffs_base__pixel_swizzler__copy_3_1;
+ break;
case WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL:
case WUFFS_BASE__PIXEL_FORMAT__BGRA_PREMUL:
case WUFFS_BASE__PIXEL_FORMAT__BGRA_BINARY:
@@ -134,6 +197,13 @@
}
func = wuffs_base__pixel_swizzler__copy_4_1;
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;
+ break;
case WUFFS_BASE__PIXEL_FORMAT__RGBA_NONPREMUL:
case WUFFS_BASE__PIXEL_FORMAT__RGBA_PREMUL:
case WUFFS_BASE__PIXEL_FORMAT__RGBA_BINARY:
@@ -153,13 +223,15 @@
}
p->private_impl.func = func;
+ return func ? NULL : wuffs_base__error__unsupported_option;
}
uint64_t //
-wuffs_base__pixel_swizzler__swizzle_packed(wuffs_base__pixel_swizzler* p,
- wuffs_base__slice_u8 dst,
- wuffs_base__slice_u8 dst_palette,
- wuffs_base__slice_u8 src) {
+wuffs_base__pixel_swizzler__swizzle_interleaved(
+ const wuffs_base__pixel_swizzler* p,
+ wuffs_base__slice_u8 dst,
+ wuffs_base__slice_u8 dst_palette,
+ wuffs_base__slice_u8 src) {
if (p && p->private_impl.func) {
return (*(p->private_impl.func))(dst, dst_palette, src);
}
diff --git a/internal/cgen/base/image-public.h b/internal/cgen/base/image-public.h
index f452b3b..0a18365 100644
--- a/internal/cgen/base/image-public.h
+++ b/internal/cgen/base/image-public.h
@@ -33,9 +33,9 @@
// - bit 20 indicates big-endian/MSB-first (as opposed to little/LSB).
// - bit 19 indicates floating point (as opposed to integer).
// - bit 18 indicates palette-indexed. The number-of-planes (the next
-// field) will be zero, as the format is considered packed,
+// field) will be 0, as the format is considered interleaved,
// but the 8-bit N-BGRA color data is stored in plane 3.
-// - bits 17 .. 16 are the number of planes, minus 1. Zero means packed.
+// - bits 17 .. 16 are the number of planes, minus 1. Zero means interleaved.
// - bits 15 .. 12 encodes the number of bits (depth) in the 3rd channel.
// - bits 11 .. 8 encodes the number of bits (depth) in the 2nd channel.
// - bits 7 .. 4 encodes the number of bits (depth) in the 1st channel.
@@ -52,14 +52,14 @@
// channels: cyan, magenta, yellow, black).
//
// For direct formats with N > 1 channels, those channels can be laid out in
-// either 1 (packed) or N (planar) planes. For example, RGBA data is usually
-// packed, but YCbCr data is usually planar, due to chroma subsampling (for
-// details, see the wuffs_base__pixel_subsampling type).
+// either 1 (interleaved) or N (planar) planes. For example, RGBA data is
+// usually interleaved, but YCbCr data is usually planar, due to chroma
+// subsampling (for details, see the wuffs_base__pixel_subsampling type).
//
// For indexed formats, the palette (always 256 × 4 bytes) holds 8 bits per
// channel non-alpha-premultiplied BGRA color data. There is only 1 plane (for
-// the index), as the format is considered packed. Plane 0 holds the per-pixel
-// indices. Plane 3 is re-purposed to hold the per-index colors.
+// the index), as the format is considered interleaved. Plane 0 holds the
+// per-pixel indices. Plane 3 is re-purposed to hold the per-index colors.
//
// The color field is encoded in 3 bits:
// - 0 means A (Alpha).
@@ -73,8 +73,8 @@
//
// In Wuffs, channels are given in memory order (also known as byte order),
// regardless of endianness, since the C type for the pixel data is an array of
-// bytes, not an array of uint32_t. For example, packed BGRA with 8 bits per
-// channel means that the bytes in memory are always Blue, Green, Red then
+// bytes, not an array of uint32_t. For example, interleaved BGRA with 8 bits
+// per channel means that the bytes in memory are always Blue, Green, Red then
// Alpha. On big-endian systems, that is the uint32_t 0xBBGGRRAA. On
// little-endian, 0xAARRGGBB.
//
@@ -107,15 +107,15 @@
//
// For example, wuffs_base__pixel_format 0x5510BBBB is a natural format for
// decoding a PNG image - network byte order (also known as big-endian),
-// packed, non-premultiplied alpha - that happens to be 16-bit-depth truecolor
-// with alpha (RGBA). In memory order:
+// interleaved, non-premultiplied alpha - that happens to be 16-bit-depth
+// truecolor with alpha (RGBA). In memory order:
//
// ptr+0 ptr+1 ptr+2 ptr+3 ptr+4 ptr+5 ptr+6 ptr+7
// Rhi Rlo Ghi Glo Bhi Blo Ahi Alo
//
// For example, the value wuffs_base__pixel_format 0x40000565 means BGR with no
-// alpha or padding, 5/6/5 bits for blue/green/red, packed 2 bytes per pixel,
-// laid out LSB-first in memory order:
+// alpha or padding, 5/6/5 bits for blue/green/red, interleaved 2 bytes per
+// pixel, laid out LSB-first in memory order:
//
// ptr+0........... ptr+1...........
// MSB LSB MSB LSB
@@ -200,8 +200,8 @@
return f != 0;
}
-// wuffs_base__pixel_format__bits_per_pixel returns, for packed pixel formats,
-// the number of bits per pixel. It returns 0 for planar pixel formats.
+// 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) {
@@ -219,7 +219,7 @@
}
static inline bool //
-wuffs_base__pixel_format__is_packed(wuffs_base__pixel_format f) {
+wuffs_base__pixel_format__is_interleaved(wuffs_base__pixel_format f) {
return ((f >> 16) & 0x03) == 0;
}
@@ -245,7 +245,7 @@
// plane p. For a depth of 8 bits (1 byte), the p'th plane's sample starts at
// (planes[p].ptr + (j * planes[p].stride) + i).
//
-// For packed pixel formats, the mapping is trivial: i = x and j = y. For
+// For interleaved pixel formats, the mapping is trivial: i = x and j = y. For
// planar pixel formats, the mapping can differ due to chroma subsampling. For
// example, consider a three plane YCbCr pixel format with 4:2:2 subsampling.
// For the luma (Y) channel, there is one sample for every pixel, but for the
@@ -336,13 +336,13 @@
uint32_t width,
uint32_t height);
inline void invalidate();
- inline bool is_valid();
- inline wuffs_base__pixel_format pixel_format();
- inline wuffs_base__pixel_subsampling pixel_subsampling();
- inline wuffs_base__rect_ie_u32 bounds();
- inline uint32_t width();
- inline uint32_t height();
- inline uint64_t pixbuf_len();
+ inline bool is_valid() const;
+ inline wuffs_base__pixel_format pixel_format() const;
+ inline wuffs_base__pixel_subsampling pixel_subsampling() const;
+ inline wuffs_base__rect_ie_u32 bounds() const;
+ inline uint32_t width() const;
+ inline uint32_t height() const;
+ inline uint64_t pixbuf_len() const;
#endif // __cplusplus
} wuffs_base__pixel_config;
@@ -396,22 +396,22 @@
}
static inline bool //
-wuffs_base__pixel_config__is_valid(wuffs_base__pixel_config* c) {
+wuffs_base__pixel_config__is_valid(const wuffs_base__pixel_config* c) {
return c && c->private_impl.pixfmt;
}
static inline wuffs_base__pixel_format //
-wuffs_base__pixel_config__pixel_format(wuffs_base__pixel_config* c) {
+wuffs_base__pixel_config__pixel_format(const wuffs_base__pixel_config* c) {
return c ? c->private_impl.pixfmt : 0;
}
static inline wuffs_base__pixel_subsampling //
-wuffs_base__pixel_config__pixel_subsampling(wuffs_base__pixel_config* c) {
+wuffs_base__pixel_config__pixel_subsampling(const wuffs_base__pixel_config* c) {
return c ? c->private_impl.pixsub : 0;
}
static inline wuffs_base__rect_ie_u32 //
-wuffs_base__pixel_config__bounds(wuffs_base__pixel_config* c) {
+wuffs_base__pixel_config__bounds(const wuffs_base__pixel_config* c) {
if (c) {
wuffs_base__rect_ie_u32 ret;
ret.min_incl_x = 0;
@@ -430,20 +430,20 @@
}
static inline uint32_t //
-wuffs_base__pixel_config__width(wuffs_base__pixel_config* c) {
+wuffs_base__pixel_config__width(const wuffs_base__pixel_config* c) {
return c ? c->private_impl.width : 0;
}
static inline uint32_t //
-wuffs_base__pixel_config__height(wuffs_base__pixel_config* c) {
+wuffs_base__pixel_config__height(const wuffs_base__pixel_config* c) {
return c ? c->private_impl.height : 0;
}
-// TODO: this is the right API for planar (not packed) pixbufs? Should it allow
-// decoding into a color model different from the format's intrinsic one? For
-// example, decoding a JPEG image straight to RGBA instead of to YCbCr?
+// TODO: this is the right API for planar (not interleaved) pixbufs? Should it
+// allow decoding into a color model different from the format's intrinsic one?
+// For example, decoding a JPEG image straight to RGBA instead of to YCbCr?
static inline uint64_t //
-wuffs_base__pixel_config__pixbuf_len(wuffs_base__pixel_config* c) {
+wuffs_base__pixel_config__pixbuf_len(const wuffs_base__pixel_config* c) {
if (!c) {
return 0;
}
@@ -492,37 +492,37 @@
}
inline bool //
-wuffs_base__pixel_config::is_valid() {
+wuffs_base__pixel_config::is_valid() const {
return wuffs_base__pixel_config__is_valid(this);
}
inline wuffs_base__pixel_format //
-wuffs_base__pixel_config::pixel_format() {
+wuffs_base__pixel_config::pixel_format() const {
return wuffs_base__pixel_config__pixel_format(this);
}
inline wuffs_base__pixel_subsampling //
-wuffs_base__pixel_config::pixel_subsampling() {
+wuffs_base__pixel_config::pixel_subsampling() const {
return wuffs_base__pixel_config__pixel_subsampling(this);
}
inline wuffs_base__rect_ie_u32 //
-wuffs_base__pixel_config::bounds() {
+wuffs_base__pixel_config::bounds() const {
return wuffs_base__pixel_config__bounds(this);
}
inline uint32_t //
-wuffs_base__pixel_config::width() {
+wuffs_base__pixel_config::width() const {
return wuffs_base__pixel_config__width(this);
}
inline uint32_t //
-wuffs_base__pixel_config::height() {
+wuffs_base__pixel_config::height() const {
return wuffs_base__pixel_config__height(this);
}
inline uint64_t //
-wuffs_base__pixel_config::pixbuf_len() {
+wuffs_base__pixel_config::pixbuf_len() const {
return wuffs_base__pixel_config__pixbuf_len(this);
}
@@ -548,9 +548,9 @@
uint64_t first_frame_io_position,
bool first_frame_is_opaque);
inline void invalidate();
- inline bool is_valid();
- inline uint64_t first_frame_io_position();
- inline bool first_frame_is_opaque();
+ inline bool is_valid() const;
+ inline uint64_t first_frame_io_position() const;
+ inline bool first_frame_is_opaque() const;
#endif // __cplusplus
} wuffs_base__image_config;
@@ -607,17 +607,19 @@
}
static inline bool //
-wuffs_base__image_config__is_valid(wuffs_base__image_config* c) {
+wuffs_base__image_config__is_valid(const wuffs_base__image_config* c) {
return c && wuffs_base__pixel_config__is_valid(&(c->pixcfg));
}
static inline uint64_t //
-wuffs_base__image_config__first_frame_io_position(wuffs_base__image_config* c) {
+wuffs_base__image_config__first_frame_io_position(
+ const wuffs_base__image_config* c) {
return c ? c->private_impl.first_frame_io_position : 0;
}
static inline bool //
-wuffs_base__image_config__first_frame_is_opaque(wuffs_base__image_config* c) {
+wuffs_base__image_config__first_frame_is_opaque(
+ const wuffs_base__image_config* c) {
return c ? c->private_impl.first_frame_is_opaque : false;
}
@@ -640,17 +642,17 @@
}
inline bool //
-wuffs_base__image_config::is_valid() {
+wuffs_base__image_config::is_valid() const {
return wuffs_base__image_config__is_valid(this);
}
inline uint64_t //
-wuffs_base__image_config::first_frame_io_position() {
+wuffs_base__image_config::first_frame_io_position() const {
return wuffs_base__image_config__first_frame_io_position(this);
}
inline bool //
-wuffs_base__image_config::first_frame_is_opaque() {
+wuffs_base__image_config::first_frame_is_opaque() const {
return wuffs_base__image_config__first_frame_is_opaque(this);
}
@@ -706,6 +708,7 @@
uint64_t io_position;
wuffs_base__animation_blend blend;
wuffs_base__animation_disposal disposal;
+ wuffs_base__color_u32_argb_premul background_color;
} private_impl;
#ifdef __cplusplus
@@ -714,15 +717,17 @@
uint64_t index,
uint64_t io_position,
wuffs_base__animation_blend blend,
- wuffs_base__animation_disposal disposal);
- inline wuffs_base__rect_ie_u32 bounds();
- inline uint32_t width();
- inline uint32_t height();
- inline wuffs_base__flicks duration();
- inline uint64_t index();
- inline uint64_t io_position();
- inline wuffs_base__animation_blend blend();
- inline wuffs_base__animation_disposal disposal();
+ wuffs_base__animation_disposal disposal,
+ wuffs_base__color_u32_argb_premul background_color);
+ inline wuffs_base__rect_ie_u32 bounds() const;
+ inline uint32_t width() const;
+ inline uint32_t height() const;
+ 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 wuffs_base__color_u32_argb_premul background_color() const;
#endif // __cplusplus
} wuffs_base__frame_config;
@@ -740,13 +745,15 @@
}
static inline void //
-wuffs_base__frame_config__update(wuffs_base__frame_config* c,
- wuffs_base__rect_ie_u32 bounds,
- wuffs_base__flicks duration,
- uint64_t index,
- uint64_t io_position,
- wuffs_base__animation_blend blend,
- wuffs_base__animation_disposal disposal) {
+wuffs_base__frame_config__update(
+ wuffs_base__frame_config* c,
+ wuffs_base__rect_ie_u32 bounds,
+ wuffs_base__flicks duration,
+ uint64_t index,
+ uint64_t io_position,
+ wuffs_base__animation_blend blend,
+ wuffs_base__animation_disposal disposal,
+ wuffs_base__color_u32_argb_premul background_color) {
if (!c) {
return;
}
@@ -757,10 +764,11 @@
c->private_impl.io_position = io_position;
c->private_impl.blend = blend;
c->private_impl.disposal = disposal;
+ c->private_impl.background_color = background_color;
}
static inline wuffs_base__rect_ie_u32 //
-wuffs_base__frame_config__bounds(wuffs_base__frame_config* c) {
+wuffs_base__frame_config__bounds(const wuffs_base__frame_config* c) {
if (c) {
return c->private_impl.bounds;
}
@@ -774,103 +782,115 @@
}
static inline uint32_t //
-wuffs_base__frame_config__width(wuffs_base__frame_config* c) {
+wuffs_base__frame_config__width(const wuffs_base__frame_config* c) {
return c ? wuffs_base__rect_ie_u32__width(&c->private_impl.bounds) : 0;
}
static inline uint32_t //
-wuffs_base__frame_config__height(wuffs_base__frame_config* c) {
+wuffs_base__frame_config__height(const wuffs_base__frame_config* c) {
return c ? wuffs_base__rect_ie_u32__height(&c->private_impl.bounds) : 0;
}
// wuffs_base__frame_config__duration returns the amount of time to display
// this frame. Zero means to display forever - a still (non-animated) image.
static inline wuffs_base__flicks //
-wuffs_base__frame_config__duration(wuffs_base__frame_config* c) {
+wuffs_base__frame_config__duration(const wuffs_base__frame_config* c) {
return c ? c->private_impl.duration : 0;
}
// wuffs_base__frame_config__index returns the index of this frame. The first
// frame in an image has index 0, the second frame has index 1, and so on.
static inline uint64_t //
-wuffs_base__frame_config__index(wuffs_base__frame_config* c) {
+wuffs_base__frame_config__index(const wuffs_base__frame_config* c) {
return c ? c->private_impl.index : 0;
}
// wuffs_base__frame_config__io_position returns the I/O stream position before
// the frame config.
static inline uint64_t //
-wuffs_base__frame_config__io_position(wuffs_base__frame_config* c) {
+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(wuffs_base__frame_config* c) {
+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 //
-wuffs_base__frame_config__disposal(wuffs_base__frame_config* c) {
+wuffs_base__frame_config__disposal(const wuffs_base__frame_config* c) {
return c ? c->private_impl.disposal : 0;
}
+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;
+}
+
#ifdef __cplusplus
inline void //
-wuffs_base__frame_config::update(wuffs_base__rect_ie_u32 bounds,
- wuffs_base__flicks duration,
- uint64_t index,
- uint64_t io_position,
- wuffs_base__animation_blend blend,
- wuffs_base__animation_disposal disposal) {
+wuffs_base__frame_config::update(
+ wuffs_base__rect_ie_u32 bounds,
+ wuffs_base__flicks duration,
+ uint64_t index,
+ uint64_t io_position,
+ wuffs_base__animation_blend blend,
+ wuffs_base__animation_disposal disposal,
+ wuffs_base__color_u32_argb_premul background_color) {
wuffs_base__frame_config__update(this, bounds, duration, index, io_position,
- blend, disposal);
+ blend, disposal, background_color);
}
inline wuffs_base__rect_ie_u32 //
-wuffs_base__frame_config::bounds() {
+wuffs_base__frame_config::bounds() const {
return wuffs_base__frame_config__bounds(this);
}
inline uint32_t //
-wuffs_base__frame_config::width() {
+wuffs_base__frame_config::width() const {
return wuffs_base__frame_config__width(this);
}
inline uint32_t //
-wuffs_base__frame_config::height() {
+wuffs_base__frame_config::height() const {
return wuffs_base__frame_config__height(this);
}
inline wuffs_base__flicks //
-wuffs_base__frame_config::duration() {
+wuffs_base__frame_config::duration() const {
return wuffs_base__frame_config__duration(this);
}
inline uint64_t //
-wuffs_base__frame_config::index() {
+wuffs_base__frame_config::index() const {
return wuffs_base__frame_config__index(this);
}
inline uint64_t //
-wuffs_base__frame_config::io_position() {
+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() {
+wuffs_base__frame_config::blend() const {
return wuffs_base__frame_config__blend(this);
}
inline wuffs_base__animation_disposal //
-wuffs_base__frame_config::disposal() {
+wuffs_base__frame_config::disposal() const {
return wuffs_base__frame_config__disposal(this);
}
+inline wuffs_base__color_u32_argb_premul //
+wuffs_base__frame_config::background_color() const {
+ return wuffs_base__frame_config__background_color(this);
+}
+
#endif // __cplusplus
// --------
@@ -888,8 +908,10 @@
#ifdef __cplusplus
inline wuffs_base__status set_from_slice(wuffs_base__pixel_config* pixcfg,
wuffs_base__slice_u8 pixbuf_memory);
+ inline wuffs_base__status set_from_table(wuffs_base__pixel_config* pixcfg,
+ wuffs_base__table_u8 pixbuf_memory);
inline wuffs_base__slice_u8 palette();
- inline wuffs_base__pixel_format pixel_format();
+ inline wuffs_base__pixel_format pixel_format() const;
inline wuffs_base__table_u8 plane(uint32_t p);
#endif // __cplusplus
@@ -919,12 +941,13 @@
}
if (wuffs_base__pixel_format__is_planar(pixcfg->private_impl.pixfmt)) {
// TODO: support planar pixel formats, concious of pixel subsampling.
- return wuffs_base__error__bad_argument;
+ return wuffs_base__error__unsupported_option;
}
uint32_t bits_per_pixel =
wuffs_base__pixel_format__bits_per_pixel(pixcfg->private_impl.pixfmt);
if ((bits_per_pixel == 0) || ((bits_per_pixel % 8) != 0)) {
- return wuffs_base__error__bad_argument;
+ // TODO: support fraction-of-byte pixels, e.g. 1 bit per pixel?
+ return wuffs_base__error__unsupported_option;
}
uint64_t bytes_per_pixel = bits_per_pixel / 8;
@@ -970,6 +993,38 @@
return NULL;
}
+static inline wuffs_base__status //
+wuffs_base__pixel_buffer__set_from_table(wuffs_base__pixel_buffer* b,
+ wuffs_base__pixel_config* pixcfg,
+ wuffs_base__table_u8 pixbuf_memory) {
+ if (!b) {
+ return 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;
+ }
+ uint32_t bits_per_pixel =
+ 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;
+ }
+ uint64_t bytes_per_pixel = bits_per_pixel / 8;
+
+ uint64_t width_in_bytes =
+ ((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;
+ }
+
+ b->pixcfg = *pixcfg;
+ b->private_impl.planes[0] = pixbuf_memory;
+ return NULL;
+}
+
// wuffs_base__pixel_buffer__palette returns the palette color data. If
// non-empty, it will have length 1024.
static inline wuffs_base__slice_u8 //
@@ -986,7 +1041,7 @@
}
static inline wuffs_base__pixel_format //
-wuffs_base__pixel_buffer__pixel_format(wuffs_base__pixel_buffer* b) {
+wuffs_base__pixel_buffer__pixel_format(const wuffs_base__pixel_buffer* b) {
if (b) {
return b->pixcfg.private_impl.pixfmt;
}
@@ -1015,13 +1070,19 @@
return wuffs_base__pixel_buffer__set_from_slice(this, pixcfg, pixbuf_memory);
}
+inline wuffs_base__status //
+wuffs_base__pixel_buffer::set_from_table(wuffs_base__pixel_config* pixcfg,
+ wuffs_base__table_u8 pixbuf_memory) {
+ return wuffs_base__pixel_buffer__set_from_table(this, pixcfg, pixbuf_memory);
+}
+
inline wuffs_base__slice_u8 //
wuffs_base__pixel_buffer::palette() {
return wuffs_base__pixel_buffer__palette(this);
}
inline wuffs_base__pixel_format //
-wuffs_base__pixel_buffer::pixel_format() {
+wuffs_base__pixel_buffer::pixel_format() const {
return wuffs_base__pixel_buffer__pixel_format(this);
}
@@ -1063,20 +1124,18 @@
} private_impl;
#ifdef __cplusplus
- inline void 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);
- inline uint64_t swizzle_packed(wuffs_base__slice_u8 dst,
- wuffs_base__slice_u8 dst_palette,
- wuffs_base__slice_u8 src);
+ 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);
+ inline uint64_t swizzle_interleaved(wuffs_base__slice_u8 dst,
+ wuffs_base__slice_u8 dst_palette,
+ wuffs_base__slice_u8 src) const;
#endif // __cplusplus
} wuffs_base__pixel_swizzler;
-// TODO: should prepare (both the C and C++ methods) return a status?
-
-void //
+wuffs_base__status //
wuffs_base__pixel_swizzler__prepare(wuffs_base__pixel_swizzler* p,
wuffs_base__pixel_format dst_format,
wuffs_base__slice_u8 dst_palette,
@@ -1084,28 +1143,30 @@
wuffs_base__slice_u8 src_palette);
uint64_t //
-wuffs_base__pixel_swizzler__swizzle_packed(wuffs_base__pixel_swizzler* p,
- wuffs_base__slice_u8 dst,
- wuffs_base__slice_u8 dst_palette,
- wuffs_base__slice_u8 src);
+wuffs_base__pixel_swizzler__swizzle_interleaved(
+ const wuffs_base__pixel_swizzler* p,
+ wuffs_base__slice_u8 dst,
+ wuffs_base__slice_u8 dst_palette,
+ wuffs_base__slice_u8 src);
#ifdef __cplusplus
-inline void //
+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__pixel_swizzler__prepare(this, dst_format, dst_palette, src_format,
- src_palette);
+ return wuffs_base__pixel_swizzler__prepare(this, dst_format, dst_palette,
+ src_format, src_palette);
}
uint64_t //
-wuffs_base__pixel_swizzler::swizzle_packed(wuffs_base__slice_u8 dst,
- wuffs_base__slice_u8 dst_palette,
- wuffs_base__slice_u8 src) {
- return wuffs_base__pixel_swizzler__swizzle_packed(this, dst, dst_palette,
- src);
+wuffs_base__pixel_swizzler::swizzle_interleaved(
+ wuffs_base__slice_u8 dst,
+ wuffs_base__slice_u8 dst_palette,
+ wuffs_base__slice_u8 src) const {
+ return wuffs_base__pixel_swizzler__swizzle_interleaved(this, dst, dst_palette,
+ src);
}
#endif // __cplusplus
diff --git a/internal/cgen/base/io-private.h b/internal/cgen/base/io-private.h
index 088f3ce..fad529b 100644
--- a/internal/cgen/base/io-private.h
+++ b/internal/cgen/base/io-private.h
@@ -16,65 +16,52 @@
// ---------------- I/O
-static inline bool //
-wuffs_base__io_buffer__is_valid(wuffs_base__io_buffer buf) {
- return (buf.data.ptr || (buf.data.len == 0)) &&
- (buf.data.len >= buf.meta.wi) && (buf.meta.wi >= buf.meta.ri);
-}
-
-// TODO: wuffs_base__io_reader__is_eof is no longer used by Wuffs per se, but
-// it might be handy to programs that use Wuffs. Either delete it, or promote
-// it to the public API.
+// "Null" as in "/dev/null", not as in "nullptr".
//
-// If making this function public (i.e. moving it to base-header.h), it also
-// needs to allow NULL (i.e. implicit, callee-calculated) mark/limit.
+// TODO: ensure that this is zero-initialized.
+static wuffs_base__io_buffer wuffs_base__global__null_io_buffer;
-static inline bool //
-wuffs_base__io_reader__is_eof(wuffs_base__io_reader o) {
- wuffs_base__io_buffer* buf = o.private_impl.buf;
- return buf && buf->meta.closed &&
- (buf->data.ptr + buf->meta.wi == o.private_impl.limit);
+static inline wuffs_base__io_buffer* //
+wuffs_base__null_io_reader() {
+ return &wuffs_base__global__null_io_buffer;
}
-static inline bool //
-wuffs_base__io_reader__is_valid(wuffs_base__io_reader o) {
- wuffs_base__io_buffer* buf = o.private_impl.buf;
- // Note: if making this function public (i.e. moving it to base-header.h), it
- // also needs to allow NULL (i.e. implicit, callee-calculated) mark/limit.
- return buf ? ((buf->data.ptr <= o.private_impl.mark) &&
- (o.private_impl.mark <= o.private_impl.limit) &&
- (o.private_impl.limit <= buf->data.ptr + buf->data.len))
- : ((o.private_impl.mark == NULL) &&
- (o.private_impl.limit == NULL));
+static inline wuffs_base__io_buffer* //
+wuffs_base__null_io_writer() {
+ return &wuffs_base__global__null_io_buffer;
}
-static inline bool //
-wuffs_base__io_writer__is_valid(wuffs_base__io_writer o) {
- wuffs_base__io_buffer* buf = o.private_impl.buf;
- // Note: if making this function public (i.e. moving it to base-header.h), it
- // also needs to allow NULL (i.e. implicit, callee-calculated) mark/limit.
- return buf ? ((buf->data.ptr <= o.private_impl.mark) &&
- (o.private_impl.mark <= o.private_impl.limit) &&
- (o.private_impl.limit <= buf->data.ptr + buf->data.len))
- : ((o.private_impl.mark == NULL) &&
- (o.private_impl.limit == NULL));
+static inline uint64_t //
+wuffs_base__io__count_since(uint64_t mark, uint64_t index) {
+ if (index >= mark) {
+ return index - mark;
+ }
+ return 0;
+}
+
+static inline wuffs_base__slice_u8 //
+wuffs_base__io__since(uint64_t mark, uint64_t index, uint8_t* ptr) {
+ if (index >= mark) {
+ return wuffs_base__make_slice_u8(ptr + mark, index - mark);
+ }
+ return wuffs_base__make_slice_u8(NULL, 0);
}
static inline uint32_t //
wuffs_base__io_writer__copy_n_from_history(uint8_t** ptr_iop_w,
- uint8_t* io0_w,
uint8_t* io1_w,
+ uint8_t* io2_w,
uint32_t length,
uint32_t distance) {
if (!distance) {
return 0;
}
uint8_t* p = *ptr_iop_w;
- if ((size_t)(p - io0_w) < (size_t)(distance)) {
+ if ((size_t)(p - io1_w) < (size_t)(distance)) {
return 0;
}
uint8_t* q = p - distance;
- size_t n = (size_t)(io1_w - p);
+ size_t n = (size_t)(io2_w - p);
if ((size_t)(length) > n) {
length = (uint32_t)(n);
} else {
@@ -106,12 +93,12 @@
// wuffs_base__io_writer__copy_n_from_history function above, but has stronger
// pre-conditions. The caller needs to prove that:
// - distance > 0
-// - distance <= (*ptr_iop_w - io0_w)
-// - length <= (io1_w - *ptr_iop_w)
+// - 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* io0_w,
uint8_t* io1_w,
+ uint8_t* io2_w,
uint32_t length,
uint32_t distance) {
uint8_t* p = *ptr_iop_w;
@@ -131,18 +118,18 @@
static inline uint32_t //
wuffs_base__io_writer__copy_n_from_reader(uint8_t** ptr_iop_w,
- uint8_t* io1_w,
+ uint8_t* io2_w,
uint32_t length,
uint8_t** ptr_iop_r,
- uint8_t* io1_r) {
+ uint8_t* io2_r) {
uint8_t* iop_w = *ptr_iop_w;
size_t n = length;
- if (n > ((size_t)(io1_w - iop_w))) {
- n = (size_t)(io1_w - iop_w);
+ if (n > ((size_t)(io2_w - iop_w))) {
+ n = (size_t)(io2_w - iop_w);
}
uint8_t* iop_r = *ptr_iop_r;
- if (n > ((size_t)(io1_r - iop_r))) {
- n = (size_t)(io1_r - iop_r);
+ if (n > ((size_t)(io2_r - iop_r))) {
+ n = (size_t)(io2_r - iop_r);
}
if (n > 0) {
memmove(iop_w, iop_r, n);
@@ -154,12 +141,12 @@
static inline uint64_t //
wuffs_base__io_writer__copy_from_slice(uint8_t** ptr_iop_w,
- uint8_t* io1_w,
+ uint8_t* io2_w,
wuffs_base__slice_u8 src) {
uint8_t* iop_w = *ptr_iop_w;
size_t n = src.len;
- if (n > ((size_t)(io1_w - iop_w))) {
- n = (size_t)(io1_w - iop_w);
+ if (n > ((size_t)(io2_w - iop_w))) {
+ n = (size_t)(io2_w - iop_w);
}
if (n > 0) {
memmove(iop_w, src.ptr, n);
@@ -170,7 +157,7 @@
static inline uint32_t //
wuffs_base__io_writer__copy_n_from_slice(uint8_t** ptr_iop_w,
- uint8_t* io1_w,
+ uint8_t* io2_w,
uint32_t length,
wuffs_base__slice_u8 src) {
uint8_t* iop_w = *ptr_iop_w;
@@ -178,8 +165,8 @@
if (n > length) {
n = length;
}
- if (n > ((size_t)(io1_w - iop_w))) {
- n = (size_t)(io1_w - iop_w);
+ if (n > ((size_t)(io2_w - iop_w))) {
+ n = (size_t)(io2_w - iop_w);
}
if (n > 0) {
memmove(iop_w, src.ptr, n);
@@ -188,11 +175,12 @@
return (uint32_t)(n);
}
-static inline wuffs_base__empty_struct //
-wuffs_base__io_reader__set(wuffs_base__io_reader* o,
- wuffs_base__io_buffer* b,
+static inline wuffs_base__io_buffer* //
+wuffs_base__io_reader__set(wuffs_base__io_buffer* b,
uint8_t** ptr_iop_r,
+ uint8_t** ptr_io0_r,
uint8_t** ptr_io1_r,
+ uint8_t** ptr_io2_r,
wuffs_base__slice_u8 data) {
b->data = data;
b->meta.wi = data.len;
@@ -200,42 +188,17 @@
b->meta.pos = 0;
b->meta.closed = false;
- o->private_impl.buf = b;
- o->private_impl.mark = data.ptr;
- o->private_impl.limit = data.ptr + data.len;
*ptr_iop_r = data.ptr;
- *ptr_io1_r = data.ptr + data.len;
+ *ptr_io0_r = data.ptr;
+ *ptr_io1_r = data.ptr;
+ *ptr_io2_r = data.ptr + data.len;
- wuffs_base__empty_struct ret;
- ret.private_impl = 0;
- return ret;
-}
-
-static inline wuffs_base__empty_struct //
-wuffs_base__io_reader__set_limit(wuffs_base__io_reader* o,
- uint8_t* iop_r,
- uint64_t limit) {
- if (o && (((size_t)(o->private_impl.limit - iop_r)) > limit)) {
- o->private_impl.limit = iop_r + limit;
- }
-
- wuffs_base__empty_struct ret;
- ret.private_impl = 0;
- return ret;
-}
-
-static inline wuffs_base__empty_struct //
-wuffs_base__io_reader__set_mark(wuffs_base__io_reader* o, uint8_t* mark) {
- o->private_impl.mark = mark;
-
- wuffs_base__empty_struct ret;
- ret.private_impl = 0;
- return ret;
+ return b;
}
static inline wuffs_base__slice_u8 //
-wuffs_base__io_reader__take(uint8_t** ptr_iop_r, uint8_t* io1_r, uint64_t n) {
- if (n <= ((size_t)(io1_r - *ptr_iop_r))) {
+wuffs_base__io_reader__take(uint8_t** ptr_iop_r, uint8_t* io2_r, uint64_t n) {
+ if (n <= ((size_t)(io2_r - *ptr_iop_r))) {
uint8_t* p = *ptr_iop_r;
*ptr_iop_r += n;
return wuffs_base__make_slice_u8(p, n);
@@ -243,11 +206,12 @@
return wuffs_base__make_slice_u8(NULL, 0);
}
-static inline wuffs_base__empty_struct //
-wuffs_base__io_writer__set(wuffs_base__io_writer* o,
- wuffs_base__io_buffer* b,
+static inline wuffs_base__io_buffer* //
+wuffs_base__io_writer__set(wuffs_base__io_buffer* b,
uint8_t** ptr_iop_w,
+ uint8_t** ptr_io0_w,
uint8_t** ptr_io1_w,
+ uint8_t** ptr_io2_w,
wuffs_base__slice_u8 data) {
b->data = data;
b->meta.wi = 0;
@@ -255,24 +219,12 @@
b->meta.pos = 0;
b->meta.closed = false;
- o->private_impl.buf = b;
- o->private_impl.mark = data.ptr;
- o->private_impl.limit = data.ptr + data.len;
*ptr_iop_w = data.ptr;
- *ptr_io1_w = data.ptr + data.len;
+ *ptr_io0_w = data.ptr;
+ *ptr_io1_w = data.ptr;
+ *ptr_io2_w = data.ptr + data.len;
- wuffs_base__empty_struct ret;
- ret.private_impl = 0;
- return ret;
-}
-
-static inline wuffs_base__empty_struct //
-wuffs_base__io_writer__set_mark(wuffs_base__io_writer* o, uint8_t* mark) {
- o->private_impl.mark = mark;
-
- wuffs_base__empty_struct ret;
- ret.private_impl = 0;
- return ret;
+ return b;
}
// ---------------- I/O (Utility)
diff --git a/internal/cgen/base/io-public.h b/internal/cgen/base/io-public.h
index 6e9bb58..271c7f9 100644
--- a/internal/cgen/base/io-public.h
+++ b/internal/cgen/base/io-public.h
@@ -15,34 +15,8 @@
// limitations under the License.
// ---------------- I/O
-
-struct wuffs_base__io_buffer__struct;
-
-typedef struct {
- // Do not access the private_impl's fields directly. There is no API/ABI
- // compatibility or safety guarantee if you do so.
- struct {
- struct wuffs_base__io_buffer__struct* buf;
- // The bounds values are typically NULL, when created by the Wuffs public
- // API. NULL means that the callee substitutes the implicit bounds derived
- // from buf.
- uint8_t* mark;
- uint8_t* limit;
- } private_impl;
-} wuffs_base__io_reader;
-
-typedef struct {
- // Do not access the private_impl's fields directly. There is no API/ABI
- // compatibility or safety guarantee if you do so.
- struct {
- struct wuffs_base__io_buffer__struct* buf;
- // The bounds values are typically NULL, when created by the Wuffs public
- // API. NULL means that the callee substitutes the implicit bounds derived
- // from buf.
- uint8_t* mark;
- uint8_t* limit;
- } private_impl;
-} wuffs_base__io_writer;
+//
+// See (/doc/note/io-input-output.md).
// wuffs_base__io_buffer_meta is the metadata for a wuffs_base__io_buffer's
// data.
@@ -63,10 +37,12 @@
#ifdef __cplusplus
inline void compact();
- inline wuffs_base__io_reader reader();
- inline wuffs_base__io_writer writer();
- inline uint64_t reader_io_position();
- inline uint64_t writer_io_position();
+ inline wuffs_base__io_buffer__struct* reader(); // Deprecated.
+ inline wuffs_base__io_buffer__struct* writer(); // Deprecated.
+ inline uint64_t reader_available() const;
+ inline uint64_t reader_io_position() const;
+ inline uint64_t writer_available() const;
+ inline uint64_t writer_io_position() const;
#endif // __cplusplus
} wuffs_base__io_buffer;
@@ -115,24 +91,6 @@
return ret;
}
-static inline wuffs_base__io_reader //
-wuffs_base__null_io_reader() {
- wuffs_base__io_reader ret;
- ret.private_impl.buf = NULL;
- ret.private_impl.mark = NULL;
- ret.private_impl.limit = NULL;
- return ret;
-}
-
-static inline wuffs_base__io_writer //
-wuffs_base__null_io_writer() {
- wuffs_base__io_writer ret;
- ret.private_impl.buf = NULL;
- ret.private_impl.mark = NULL;
- ret.private_impl.limit = NULL;
- return ret;
-}
-
// wuffs_base__io_buffer__compact moves any written but unread bytes to the
// start of the buffer.
static inline void //
@@ -149,31 +107,23 @@
buf->meta.ri = 0;
}
-static inline wuffs_base__io_reader //
-wuffs_base__io_buffer__reader(wuffs_base__io_buffer* buf) {
- wuffs_base__io_reader ret;
- ret.private_impl.buf = buf;
- ret.private_impl.mark = NULL;
- ret.private_impl.limit = NULL;
- return ret;
-}
-
-static inline wuffs_base__io_writer //
-wuffs_base__io_buffer__writer(wuffs_base__io_buffer* buf) {
- wuffs_base__io_writer ret;
- ret.private_impl.buf = buf;
- ret.private_impl.mark = NULL;
- ret.private_impl.limit = NULL;
- return ret;
+static inline uint64_t //
+wuffs_base__io_buffer__reader_available(const wuffs_base__io_buffer* buf) {
+ return buf ? buf->meta.wi - buf->meta.ri : 0;
}
static inline uint64_t //
-wuffs_base__io_buffer__reader_io_position(wuffs_base__io_buffer* buf) {
+wuffs_base__io_buffer__reader_io_position(const wuffs_base__io_buffer* buf) {
return buf ? wuffs_base__u64__sat_add(buf->meta.pos, buf->meta.ri) : 0;
}
static inline uint64_t //
-wuffs_base__io_buffer__writer_io_position(wuffs_base__io_buffer* buf) {
+wuffs_base__io_buffer__writer_available(const wuffs_base__io_buffer* buf) {
+ return buf ? buf->data.len - buf->meta.wi : 0;
+}
+
+static inline uint64_t //
+wuffs_base__io_buffer__writer_io_position(const wuffs_base__io_buffer* buf) {
return buf ? wuffs_base__u64__sat_add(buf->meta.pos, buf->meta.wi) : 0;
}
@@ -184,23 +134,33 @@
wuffs_base__io_buffer__compact(this);
}
-inline wuffs_base__io_reader //
+inline wuffs_base__io_buffer* //
wuffs_base__io_buffer__struct::reader() {
- return wuffs_base__io_buffer__reader(this);
+ return this;
}
-inline wuffs_base__io_writer //
+inline wuffs_base__io_buffer* //
wuffs_base__io_buffer__struct::writer() {
- return wuffs_base__io_buffer__writer(this);
+ return this;
}
inline uint64_t //
-wuffs_base__io_buffer__struct::reader_io_position() {
+wuffs_base__io_buffer__struct::reader_available() const {
+ return wuffs_base__io_buffer__reader_available(this);
+}
+
+inline uint64_t //
+wuffs_base__io_buffer__struct::reader_io_position() const {
return wuffs_base__io_buffer__reader_io_position(this);
}
inline uint64_t //
-wuffs_base__io_buffer__struct::writer_io_position() {
+wuffs_base__io_buffer__struct::writer_available() const {
+ return wuffs_base__io_buffer__writer_available(this);
+}
+
+inline uint64_t //
+wuffs_base__io_buffer__struct::writer_io_position() const {
return wuffs_base__io_buffer__writer_io_position(this);
}
diff --git a/internal/cgen/base/range-public.h b/internal/cgen/base/range-public.h
index 69d6ecb..b6f6be7 100644
--- a/internal/cgen/base/range-public.h
+++ b/internal/cgen/base/range-public.h
@@ -52,14 +52,14 @@
uint32_t max_incl;
#ifdef __cplusplus
- inline bool is_empty();
- inline bool equals(wuffs_base__range_ii_u32__struct s);
+ inline bool is_empty() const;
+ inline bool equals(wuffs_base__range_ii_u32__struct s) const;
inline wuffs_base__range_ii_u32__struct intersect(
- wuffs_base__range_ii_u32__struct s);
+ wuffs_base__range_ii_u32__struct s) const;
inline wuffs_base__range_ii_u32__struct unite(
- wuffs_base__range_ii_u32__struct s);
- inline bool contains(uint32_t x);
- inline bool contains_range(wuffs_base__range_ii_u32__struct s);
+ wuffs_base__range_ii_u32__struct s) const;
+ inline bool contains(uint32_t x) const;
+ inline bool contains_range(wuffs_base__range_ii_u32__struct s) const;
#endif // __cplusplus
} wuffs_base__range_ii_u32;
@@ -73,12 +73,12 @@
}
static inline bool //
-wuffs_base__range_ii_u32__is_empty(wuffs_base__range_ii_u32* r) {
+wuffs_base__range_ii_u32__is_empty(const wuffs_base__range_ii_u32* r) {
return r->min_incl > r->max_incl;
}
static inline bool //
-wuffs_base__range_ii_u32__equals(wuffs_base__range_ii_u32* r,
+wuffs_base__range_ii_u32__equals(const wuffs_base__range_ii_u32* r,
wuffs_base__range_ii_u32 s) {
return (r->min_incl == s.min_incl && r->max_incl == s.max_incl) ||
(wuffs_base__range_ii_u32__is_empty(r) &&
@@ -86,7 +86,7 @@
}
static inline wuffs_base__range_ii_u32 //
-wuffs_base__range_ii_u32__intersect(wuffs_base__range_ii_u32* r,
+wuffs_base__range_ii_u32__intersect(const wuffs_base__range_ii_u32* r,
wuffs_base__range_ii_u32 s) {
wuffs_base__range_ii_u32 t;
t.min_incl = wuffs_base__u32__max(r->min_incl, s.min_incl);
@@ -95,7 +95,7 @@
}
static inline wuffs_base__range_ii_u32 //
-wuffs_base__range_ii_u32__unite(wuffs_base__range_ii_u32* r,
+wuffs_base__range_ii_u32__unite(const wuffs_base__range_ii_u32* r,
wuffs_base__range_ii_u32 s) {
if (wuffs_base__range_ii_u32__is_empty(r)) {
return s;
@@ -110,12 +110,13 @@
}
static inline bool //
-wuffs_base__range_ii_u32__contains(wuffs_base__range_ii_u32* r, uint32_t x) {
+wuffs_base__range_ii_u32__contains(const wuffs_base__range_ii_u32* r,
+ uint32_t x) {
return (r->min_incl <= x) && (x <= r->max_incl);
}
static inline bool //
-wuffs_base__range_ii_u32__contains_range(wuffs_base__range_ii_u32* r,
+wuffs_base__range_ii_u32__contains_range(const wuffs_base__range_ii_u32* r,
wuffs_base__range_ii_u32 s) {
return wuffs_base__range_ii_u32__equals(
&s, wuffs_base__range_ii_u32__intersect(r, s));
@@ -124,32 +125,32 @@
#ifdef __cplusplus
inline bool //
-wuffs_base__range_ii_u32::is_empty() {
+wuffs_base__range_ii_u32::is_empty() const {
return wuffs_base__range_ii_u32__is_empty(this);
}
inline bool //
-wuffs_base__range_ii_u32::equals(wuffs_base__range_ii_u32 s) {
+wuffs_base__range_ii_u32::equals(wuffs_base__range_ii_u32 s) const {
return wuffs_base__range_ii_u32__equals(this, s);
}
inline wuffs_base__range_ii_u32 //
-wuffs_base__range_ii_u32::intersect(wuffs_base__range_ii_u32 s) {
+wuffs_base__range_ii_u32::intersect(wuffs_base__range_ii_u32 s) const {
return wuffs_base__range_ii_u32__intersect(this, s);
}
inline wuffs_base__range_ii_u32 //
-wuffs_base__range_ii_u32::unite(wuffs_base__range_ii_u32 s) {
+wuffs_base__range_ii_u32::unite(wuffs_base__range_ii_u32 s) const {
return wuffs_base__range_ii_u32__unite(this, s);
}
inline bool //
-wuffs_base__range_ii_u32::contains(uint32_t x) {
+wuffs_base__range_ii_u32::contains(uint32_t x) const {
return wuffs_base__range_ii_u32__contains(this, x);
}
inline bool //
-wuffs_base__range_ii_u32::contains_range(wuffs_base__range_ii_u32 s) {
+wuffs_base__range_ii_u32::contains_range(wuffs_base__range_ii_u32 s) const {
return wuffs_base__range_ii_u32__contains_range(this, s);
}
@@ -162,15 +163,15 @@
uint32_t max_excl;
#ifdef __cplusplus
- inline bool is_empty();
- inline bool equals(wuffs_base__range_ie_u32__struct s);
+ inline bool is_empty() const;
+ inline bool equals(wuffs_base__range_ie_u32__struct s) const;
inline wuffs_base__range_ie_u32__struct intersect(
- wuffs_base__range_ie_u32__struct s);
+ wuffs_base__range_ie_u32__struct s) const;
inline wuffs_base__range_ie_u32__struct unite(
- wuffs_base__range_ie_u32__struct s);
- inline bool contains(uint32_t x);
- inline bool contains_range(wuffs_base__range_ie_u32__struct s);
- inline uint32_t length();
+ wuffs_base__range_ie_u32__struct s) const;
+ inline bool contains(uint32_t x) const;
+ inline bool contains_range(wuffs_base__range_ie_u32__struct s) const;
+ inline uint32_t length() const;
#endif // __cplusplus
} wuffs_base__range_ie_u32;
@@ -184,12 +185,12 @@
}
static inline bool //
-wuffs_base__range_ie_u32__is_empty(wuffs_base__range_ie_u32* r) {
+wuffs_base__range_ie_u32__is_empty(const wuffs_base__range_ie_u32* r) {
return r->min_incl >= r->max_excl;
}
static inline bool //
-wuffs_base__range_ie_u32__equals(wuffs_base__range_ie_u32* r,
+wuffs_base__range_ie_u32__equals(const wuffs_base__range_ie_u32* r,
wuffs_base__range_ie_u32 s) {
return (r->min_incl == s.min_incl && r->max_excl == s.max_excl) ||
(wuffs_base__range_ie_u32__is_empty(r) &&
@@ -197,7 +198,7 @@
}
static inline wuffs_base__range_ie_u32 //
-wuffs_base__range_ie_u32__intersect(wuffs_base__range_ie_u32* r,
+wuffs_base__range_ie_u32__intersect(const wuffs_base__range_ie_u32* r,
wuffs_base__range_ie_u32 s) {
wuffs_base__range_ie_u32 t;
t.min_incl = wuffs_base__u32__max(r->min_incl, s.min_incl);
@@ -206,7 +207,7 @@
}
static inline wuffs_base__range_ie_u32 //
-wuffs_base__range_ie_u32__unite(wuffs_base__range_ie_u32* r,
+wuffs_base__range_ie_u32__unite(const wuffs_base__range_ie_u32* r,
wuffs_base__range_ie_u32 s) {
if (wuffs_base__range_ie_u32__is_empty(r)) {
return s;
@@ -221,56 +222,57 @@
}
static inline bool //
-wuffs_base__range_ie_u32__contains(wuffs_base__range_ie_u32* r, uint32_t x) {
+wuffs_base__range_ie_u32__contains(const wuffs_base__range_ie_u32* r,
+ uint32_t x) {
return (r->min_incl <= x) && (x < r->max_excl);
}
static inline bool //
-wuffs_base__range_ie_u32__contains_range(wuffs_base__range_ie_u32* r,
+wuffs_base__range_ie_u32__contains_range(const wuffs_base__range_ie_u32* r,
wuffs_base__range_ie_u32 s) {
return wuffs_base__range_ie_u32__equals(
&s, wuffs_base__range_ie_u32__intersect(r, s));
}
static inline uint32_t //
-wuffs_base__range_ie_u32__length(wuffs_base__range_ie_u32* r) {
+wuffs_base__range_ie_u32__length(const wuffs_base__range_ie_u32* r) {
return wuffs_base__u32__sat_sub(r->max_excl, r->min_incl);
}
#ifdef __cplusplus
inline bool //
-wuffs_base__range_ie_u32::is_empty() {
+wuffs_base__range_ie_u32::is_empty() const {
return wuffs_base__range_ie_u32__is_empty(this);
}
inline bool //
-wuffs_base__range_ie_u32::equals(wuffs_base__range_ie_u32 s) {
+wuffs_base__range_ie_u32::equals(wuffs_base__range_ie_u32 s) const {
return wuffs_base__range_ie_u32__equals(this, s);
}
inline wuffs_base__range_ie_u32 //
-wuffs_base__range_ie_u32::intersect(wuffs_base__range_ie_u32 s) {
+wuffs_base__range_ie_u32::intersect(wuffs_base__range_ie_u32 s) const {
return wuffs_base__range_ie_u32__intersect(this, s);
}
inline wuffs_base__range_ie_u32 //
-wuffs_base__range_ie_u32::unite(wuffs_base__range_ie_u32 s) {
+wuffs_base__range_ie_u32::unite(wuffs_base__range_ie_u32 s) const {
return wuffs_base__range_ie_u32__unite(this, s);
}
inline bool //
-wuffs_base__range_ie_u32::contains(uint32_t x) {
+wuffs_base__range_ie_u32::contains(uint32_t x) const {
return wuffs_base__range_ie_u32__contains(this, x);
}
inline bool //
-wuffs_base__range_ie_u32::contains_range(wuffs_base__range_ie_u32 s) {
+wuffs_base__range_ie_u32::contains_range(wuffs_base__range_ie_u32 s) const {
return wuffs_base__range_ie_u32__contains_range(this, s);
}
inline uint32_t //
-wuffs_base__range_ie_u32::length() {
+wuffs_base__range_ie_u32::length() const {
return wuffs_base__range_ie_u32__length(this);
}
@@ -283,14 +285,14 @@
uint64_t max_incl;
#ifdef __cplusplus
- inline bool is_empty();
- inline bool equals(wuffs_base__range_ii_u64__struct s);
+ inline bool is_empty() const;
+ inline bool equals(wuffs_base__range_ii_u64__struct s) const;
inline wuffs_base__range_ii_u64__struct intersect(
- wuffs_base__range_ii_u64__struct s);
+ wuffs_base__range_ii_u64__struct s) const;
inline wuffs_base__range_ii_u64__struct unite(
- wuffs_base__range_ii_u64__struct s);
- inline bool contains(uint64_t x);
- inline bool contains_range(wuffs_base__range_ii_u64__struct s);
+ wuffs_base__range_ii_u64__struct s) const;
+ inline bool contains(uint64_t x) const;
+ inline bool contains_range(wuffs_base__range_ii_u64__struct s) const;
#endif // __cplusplus
} wuffs_base__range_ii_u64;
@@ -304,12 +306,12 @@
}
static inline bool //
-wuffs_base__range_ii_u64__is_empty(wuffs_base__range_ii_u64* r) {
+wuffs_base__range_ii_u64__is_empty(const wuffs_base__range_ii_u64* r) {
return r->min_incl > r->max_incl;
}
static inline bool //
-wuffs_base__range_ii_u64__equals(wuffs_base__range_ii_u64* r,
+wuffs_base__range_ii_u64__equals(const wuffs_base__range_ii_u64* r,
wuffs_base__range_ii_u64 s) {
return (r->min_incl == s.min_incl && r->max_incl == s.max_incl) ||
(wuffs_base__range_ii_u64__is_empty(r) &&
@@ -317,7 +319,7 @@
}
static inline wuffs_base__range_ii_u64 //
-wuffs_base__range_ii_u64__intersect(wuffs_base__range_ii_u64* r,
+wuffs_base__range_ii_u64__intersect(const wuffs_base__range_ii_u64* r,
wuffs_base__range_ii_u64 s) {
wuffs_base__range_ii_u64 t;
t.min_incl = wuffs_base__u64__max(r->min_incl, s.min_incl);
@@ -326,7 +328,7 @@
}
static inline wuffs_base__range_ii_u64 //
-wuffs_base__range_ii_u64__unite(wuffs_base__range_ii_u64* r,
+wuffs_base__range_ii_u64__unite(const wuffs_base__range_ii_u64* r,
wuffs_base__range_ii_u64 s) {
if (wuffs_base__range_ii_u64__is_empty(r)) {
return s;
@@ -341,12 +343,13 @@
}
static inline bool //
-wuffs_base__range_ii_u64__contains(wuffs_base__range_ii_u64* r, uint64_t x) {
+wuffs_base__range_ii_u64__contains(const wuffs_base__range_ii_u64* r,
+ uint64_t x) {
return (r->min_incl <= x) && (x <= r->max_incl);
}
static inline bool //
-wuffs_base__range_ii_u64__contains_range(wuffs_base__range_ii_u64* r,
+wuffs_base__range_ii_u64__contains_range(const wuffs_base__range_ii_u64* r,
wuffs_base__range_ii_u64 s) {
return wuffs_base__range_ii_u64__equals(
&s, wuffs_base__range_ii_u64__intersect(r, s));
@@ -355,32 +358,32 @@
#ifdef __cplusplus
inline bool //
-wuffs_base__range_ii_u64::is_empty() {
+wuffs_base__range_ii_u64::is_empty() const {
return wuffs_base__range_ii_u64__is_empty(this);
}
inline bool //
-wuffs_base__range_ii_u64::equals(wuffs_base__range_ii_u64 s) {
+wuffs_base__range_ii_u64::equals(wuffs_base__range_ii_u64 s) const {
return wuffs_base__range_ii_u64__equals(this, s);
}
inline wuffs_base__range_ii_u64 //
-wuffs_base__range_ii_u64::intersect(wuffs_base__range_ii_u64 s) {
+wuffs_base__range_ii_u64::intersect(wuffs_base__range_ii_u64 s) const {
return wuffs_base__range_ii_u64__intersect(this, s);
}
inline wuffs_base__range_ii_u64 //
-wuffs_base__range_ii_u64::unite(wuffs_base__range_ii_u64 s) {
+wuffs_base__range_ii_u64::unite(wuffs_base__range_ii_u64 s) const {
return wuffs_base__range_ii_u64__unite(this, s);
}
inline bool //
-wuffs_base__range_ii_u64::contains(uint64_t x) {
+wuffs_base__range_ii_u64::contains(uint64_t x) const {
return wuffs_base__range_ii_u64__contains(this, x);
}
inline bool //
-wuffs_base__range_ii_u64::contains_range(wuffs_base__range_ii_u64 s) {
+wuffs_base__range_ii_u64::contains_range(wuffs_base__range_ii_u64 s) const {
return wuffs_base__range_ii_u64__contains_range(this, s);
}
@@ -393,15 +396,15 @@
uint64_t max_excl;
#ifdef __cplusplus
- inline bool is_empty();
- inline bool equals(wuffs_base__range_ie_u64__struct s);
+ inline bool is_empty() const;
+ inline bool equals(wuffs_base__range_ie_u64__struct s) const;
inline wuffs_base__range_ie_u64__struct intersect(
- wuffs_base__range_ie_u64__struct s);
+ wuffs_base__range_ie_u64__struct s) const;
inline wuffs_base__range_ie_u64__struct unite(
- wuffs_base__range_ie_u64__struct s);
- inline bool contains(uint64_t x);
- inline bool contains_range(wuffs_base__range_ie_u64__struct s);
- inline uint64_t length();
+ wuffs_base__range_ie_u64__struct s) const;
+ inline bool contains(uint64_t x) const;
+ inline bool contains_range(wuffs_base__range_ie_u64__struct s) const;
+ inline uint64_t length() const;
#endif // __cplusplus
} wuffs_base__range_ie_u64;
@@ -415,12 +418,12 @@
}
static inline bool //
-wuffs_base__range_ie_u64__is_empty(wuffs_base__range_ie_u64* r) {
+wuffs_base__range_ie_u64__is_empty(const wuffs_base__range_ie_u64* r) {
return r->min_incl >= r->max_excl;
}
static inline bool //
-wuffs_base__range_ie_u64__equals(wuffs_base__range_ie_u64* r,
+wuffs_base__range_ie_u64__equals(const wuffs_base__range_ie_u64* r,
wuffs_base__range_ie_u64 s) {
return (r->min_incl == s.min_incl && r->max_excl == s.max_excl) ||
(wuffs_base__range_ie_u64__is_empty(r) &&
@@ -428,7 +431,7 @@
}
static inline wuffs_base__range_ie_u64 //
-wuffs_base__range_ie_u64__intersect(wuffs_base__range_ie_u64* r,
+wuffs_base__range_ie_u64__intersect(const wuffs_base__range_ie_u64* r,
wuffs_base__range_ie_u64 s) {
wuffs_base__range_ie_u64 t;
t.min_incl = wuffs_base__u64__max(r->min_incl, s.min_incl);
@@ -437,7 +440,7 @@
}
static inline wuffs_base__range_ie_u64 //
-wuffs_base__range_ie_u64__unite(wuffs_base__range_ie_u64* r,
+wuffs_base__range_ie_u64__unite(const wuffs_base__range_ie_u64* r,
wuffs_base__range_ie_u64 s) {
if (wuffs_base__range_ie_u64__is_empty(r)) {
return s;
@@ -452,56 +455,57 @@
}
static inline bool //
-wuffs_base__range_ie_u64__contains(wuffs_base__range_ie_u64* r, uint64_t x) {
+wuffs_base__range_ie_u64__contains(const wuffs_base__range_ie_u64* r,
+ uint64_t x) {
return (r->min_incl <= x) && (x < r->max_excl);
}
static inline bool //
-wuffs_base__range_ie_u64__contains_range(wuffs_base__range_ie_u64* r,
+wuffs_base__range_ie_u64__contains_range(const wuffs_base__range_ie_u64* r,
wuffs_base__range_ie_u64 s) {
return wuffs_base__range_ie_u64__equals(
&s, wuffs_base__range_ie_u64__intersect(r, s));
}
static inline uint64_t //
-wuffs_base__range_ie_u64__length(wuffs_base__range_ie_u64* r) {
+wuffs_base__range_ie_u64__length(const wuffs_base__range_ie_u64* r) {
return wuffs_base__u64__sat_sub(r->max_excl, r->min_incl);
}
#ifdef __cplusplus
inline bool //
-wuffs_base__range_ie_u64::is_empty() {
+wuffs_base__range_ie_u64::is_empty() const {
return wuffs_base__range_ie_u64__is_empty(this);
}
inline bool //
-wuffs_base__range_ie_u64::equals(wuffs_base__range_ie_u64 s) {
+wuffs_base__range_ie_u64::equals(wuffs_base__range_ie_u64 s) const {
return wuffs_base__range_ie_u64__equals(this, s);
}
inline wuffs_base__range_ie_u64 //
-wuffs_base__range_ie_u64::intersect(wuffs_base__range_ie_u64 s) {
+wuffs_base__range_ie_u64::intersect(wuffs_base__range_ie_u64 s) const {
return wuffs_base__range_ie_u64__intersect(this, s);
}
inline wuffs_base__range_ie_u64 //
-wuffs_base__range_ie_u64::unite(wuffs_base__range_ie_u64 s) {
+wuffs_base__range_ie_u64::unite(wuffs_base__range_ie_u64 s) const {
return wuffs_base__range_ie_u64__unite(this, s);
}
inline bool //
-wuffs_base__range_ie_u64::contains(uint64_t x) {
+wuffs_base__range_ie_u64::contains(uint64_t x) const {
return wuffs_base__range_ie_u64__contains(this, x);
}
inline bool //
-wuffs_base__range_ie_u64::contains_range(wuffs_base__range_ie_u64 s) {
+wuffs_base__range_ie_u64::contains_range(wuffs_base__range_ie_u64 s) const {
return wuffs_base__range_ie_u64__contains_range(this, s);
}
inline uint64_t //
-wuffs_base__range_ie_u64::length() {
+wuffs_base__range_ie_u64::length() const {
return wuffs_base__range_ie_u64__length(this);
}
@@ -525,14 +529,14 @@
uint32_t max_incl_y;
#ifdef __cplusplus
- inline bool is_empty();
- inline bool equals(wuffs_base__rect_ii_u32__struct s);
+ inline bool is_empty() const;
+ inline bool equals(wuffs_base__rect_ii_u32__struct s) const;
inline wuffs_base__rect_ii_u32__struct intersect(
- wuffs_base__rect_ii_u32__struct s);
+ wuffs_base__rect_ii_u32__struct s) const;
inline wuffs_base__rect_ii_u32__struct unite(
- wuffs_base__rect_ii_u32__struct s);
- inline bool contains(uint32_t x, uint32_t y);
- inline bool contains_rect(wuffs_base__rect_ii_u32__struct s);
+ wuffs_base__rect_ii_u32__struct s) const;
+ inline bool contains(uint32_t x, uint32_t y) const;
+ inline bool contains_rect(wuffs_base__rect_ii_u32__struct s) const;
#endif // __cplusplus
} wuffs_base__rect_ii_u32;
@@ -551,12 +555,12 @@
}
static inline bool //
-wuffs_base__rect_ii_u32__is_empty(wuffs_base__rect_ii_u32* r) {
+wuffs_base__rect_ii_u32__is_empty(const wuffs_base__rect_ii_u32* r) {
return (r->min_incl_x > r->max_incl_x) || (r->min_incl_y > r->max_incl_y);
}
static inline bool //
-wuffs_base__rect_ii_u32__equals(wuffs_base__rect_ii_u32* r,
+wuffs_base__rect_ii_u32__equals(const wuffs_base__rect_ii_u32* r,
wuffs_base__rect_ii_u32 s) {
return (r->min_incl_x == s.min_incl_x && r->min_incl_y == s.min_incl_y &&
r->max_incl_x == s.max_incl_x && r->max_incl_y == s.max_incl_y) ||
@@ -565,7 +569,7 @@
}
static inline wuffs_base__rect_ii_u32 //
-wuffs_base__rect_ii_u32__intersect(wuffs_base__rect_ii_u32* r,
+wuffs_base__rect_ii_u32__intersect(const wuffs_base__rect_ii_u32* r,
wuffs_base__rect_ii_u32 s) {
wuffs_base__rect_ii_u32 t;
t.min_incl_x = wuffs_base__u32__max(r->min_incl_x, s.min_incl_x);
@@ -576,7 +580,7 @@
}
static inline wuffs_base__rect_ii_u32 //
-wuffs_base__rect_ii_u32__unite(wuffs_base__rect_ii_u32* r,
+wuffs_base__rect_ii_u32__unite(const wuffs_base__rect_ii_u32* r,
wuffs_base__rect_ii_u32 s) {
if (wuffs_base__rect_ii_u32__is_empty(r)) {
return s;
@@ -593,7 +597,7 @@
}
static inline bool //
-wuffs_base__rect_ii_u32__contains(wuffs_base__rect_ii_u32* r,
+wuffs_base__rect_ii_u32__contains(const wuffs_base__rect_ii_u32* r,
uint32_t x,
uint32_t y) {
return (r->min_incl_x <= x) && (x <= r->max_incl_x) && (r->min_incl_y <= y) &&
@@ -601,7 +605,7 @@
}
static inline bool //
-wuffs_base__rect_ii_u32__contains_rect(wuffs_base__rect_ii_u32* r,
+wuffs_base__rect_ii_u32__contains_rect(const wuffs_base__rect_ii_u32* r,
wuffs_base__rect_ii_u32 s) {
return wuffs_base__rect_ii_u32__equals(
&s, wuffs_base__rect_ii_u32__intersect(r, s));
@@ -610,32 +614,32 @@
#ifdef __cplusplus
inline bool //
-wuffs_base__rect_ii_u32::is_empty() {
+wuffs_base__rect_ii_u32::is_empty() const {
return wuffs_base__rect_ii_u32__is_empty(this);
}
inline bool //
-wuffs_base__rect_ii_u32::equals(wuffs_base__rect_ii_u32 s) {
+wuffs_base__rect_ii_u32::equals(wuffs_base__rect_ii_u32 s) const {
return wuffs_base__rect_ii_u32__equals(this, s);
}
inline wuffs_base__rect_ii_u32 //
-wuffs_base__rect_ii_u32::intersect(wuffs_base__rect_ii_u32 s) {
+wuffs_base__rect_ii_u32::intersect(wuffs_base__rect_ii_u32 s) const {
return wuffs_base__rect_ii_u32__intersect(this, s);
}
inline wuffs_base__rect_ii_u32 //
-wuffs_base__rect_ii_u32::unite(wuffs_base__rect_ii_u32 s) {
+wuffs_base__rect_ii_u32::unite(wuffs_base__rect_ii_u32 s) const {
return wuffs_base__rect_ii_u32__unite(this, s);
}
inline bool //
-wuffs_base__rect_ii_u32::contains(uint32_t x, uint32_t y) {
+wuffs_base__rect_ii_u32::contains(uint32_t x, uint32_t y) const {
return wuffs_base__rect_ii_u32__contains(this, x, y);
}
inline bool //
-wuffs_base__rect_ii_u32::contains_rect(wuffs_base__rect_ii_u32 s) {
+wuffs_base__rect_ii_u32::contains_rect(wuffs_base__rect_ii_u32 s) const {
return wuffs_base__rect_ii_u32__contains_rect(this, s);
}
@@ -660,16 +664,16 @@
uint32_t max_excl_y;
#ifdef __cplusplus
- inline bool is_empty();
- inline bool equals(wuffs_base__rect_ie_u32__struct s);
+ inline bool is_empty() const;
+ inline bool equals(wuffs_base__rect_ie_u32__struct s) const;
inline wuffs_base__rect_ie_u32__struct intersect(
- wuffs_base__rect_ie_u32__struct s);
+ wuffs_base__rect_ie_u32__struct s) const;
inline wuffs_base__rect_ie_u32__struct unite(
- wuffs_base__rect_ie_u32__struct s);
- inline bool contains(uint32_t x, uint32_t y);
- inline bool contains_rect(wuffs_base__rect_ie_u32__struct s);
- inline uint32_t width();
- inline uint32_t height();
+ wuffs_base__rect_ie_u32__struct s) const;
+ inline bool contains(uint32_t x, uint32_t y) const;
+ inline bool contains_rect(wuffs_base__rect_ie_u32__struct s) const;
+ inline uint32_t width() const;
+ inline uint32_t height() const;
#endif // __cplusplus
} wuffs_base__rect_ie_u32;
@@ -688,12 +692,12 @@
}
static inline bool //
-wuffs_base__rect_ie_u32__is_empty(wuffs_base__rect_ie_u32* r) {
+wuffs_base__rect_ie_u32__is_empty(const wuffs_base__rect_ie_u32* r) {
return (r->min_incl_x >= r->max_excl_x) || (r->min_incl_y >= r->max_excl_y);
}
static inline bool //
-wuffs_base__rect_ie_u32__equals(wuffs_base__rect_ie_u32* r,
+wuffs_base__rect_ie_u32__equals(const wuffs_base__rect_ie_u32* r,
wuffs_base__rect_ie_u32 s) {
return (r->min_incl_x == s.min_incl_x && r->min_incl_y == s.min_incl_y &&
r->max_excl_x == s.max_excl_x && r->max_excl_y == s.max_excl_y) ||
@@ -702,7 +706,7 @@
}
static inline wuffs_base__rect_ie_u32 //
-wuffs_base__rect_ie_u32__intersect(wuffs_base__rect_ie_u32* r,
+wuffs_base__rect_ie_u32__intersect(const wuffs_base__rect_ie_u32* r,
wuffs_base__rect_ie_u32 s) {
wuffs_base__rect_ie_u32 t;
t.min_incl_x = wuffs_base__u32__max(r->min_incl_x, s.min_incl_x);
@@ -713,7 +717,7 @@
}
static inline wuffs_base__rect_ie_u32 //
-wuffs_base__rect_ie_u32__unite(wuffs_base__rect_ie_u32* r,
+wuffs_base__rect_ie_u32__unite(const wuffs_base__rect_ie_u32* r,
wuffs_base__rect_ie_u32 s) {
if (wuffs_base__rect_ie_u32__is_empty(r)) {
return s;
@@ -730,7 +734,7 @@
}
static inline bool //
-wuffs_base__rect_ie_u32__contains(wuffs_base__rect_ie_u32* r,
+wuffs_base__rect_ie_u32__contains(const wuffs_base__rect_ie_u32* r,
uint32_t x,
uint32_t y) {
return (r->min_incl_x <= x) && (x < r->max_excl_x) && (r->min_incl_y <= y) &&
@@ -738,61 +742,61 @@
}
static inline bool //
-wuffs_base__rect_ie_u32__contains_rect(wuffs_base__rect_ie_u32* r,
+wuffs_base__rect_ie_u32__contains_rect(const wuffs_base__rect_ie_u32* r,
wuffs_base__rect_ie_u32 s) {
return wuffs_base__rect_ie_u32__equals(
&s, wuffs_base__rect_ie_u32__intersect(r, s));
}
static inline uint32_t //
-wuffs_base__rect_ie_u32__width(wuffs_base__rect_ie_u32* r) {
+wuffs_base__rect_ie_u32__width(const wuffs_base__rect_ie_u32* r) {
return wuffs_base__u32__sat_sub(r->max_excl_x, r->min_incl_x);
}
static inline uint32_t //
-wuffs_base__rect_ie_u32__height(wuffs_base__rect_ie_u32* r) {
+wuffs_base__rect_ie_u32__height(const wuffs_base__rect_ie_u32* r) {
return wuffs_base__u32__sat_sub(r->max_excl_y, r->min_incl_y);
}
#ifdef __cplusplus
inline bool //
-wuffs_base__rect_ie_u32::is_empty() {
+wuffs_base__rect_ie_u32::is_empty() const {
return wuffs_base__rect_ie_u32__is_empty(this);
}
inline bool //
-wuffs_base__rect_ie_u32::equals(wuffs_base__rect_ie_u32 s) {
+wuffs_base__rect_ie_u32::equals(wuffs_base__rect_ie_u32 s) const {
return wuffs_base__rect_ie_u32__equals(this, s);
}
inline wuffs_base__rect_ie_u32 //
-wuffs_base__rect_ie_u32::intersect(wuffs_base__rect_ie_u32 s) {
+wuffs_base__rect_ie_u32::intersect(wuffs_base__rect_ie_u32 s) const {
return wuffs_base__rect_ie_u32__intersect(this, s);
}
inline wuffs_base__rect_ie_u32 //
-wuffs_base__rect_ie_u32::unite(wuffs_base__rect_ie_u32 s) {
+wuffs_base__rect_ie_u32::unite(wuffs_base__rect_ie_u32 s) const {
return wuffs_base__rect_ie_u32__unite(this, s);
}
inline bool //
-wuffs_base__rect_ie_u32::contains(uint32_t x, uint32_t y) {
+wuffs_base__rect_ie_u32::contains(uint32_t x, uint32_t y) const {
return wuffs_base__rect_ie_u32__contains(this, x, y);
}
inline bool //
-wuffs_base__rect_ie_u32::contains_rect(wuffs_base__rect_ie_u32 s) {
+wuffs_base__rect_ie_u32::contains_rect(wuffs_base__rect_ie_u32 s) const {
return wuffs_base__rect_ie_u32__contains_rect(this, s);
}
inline uint32_t //
-wuffs_base__rect_ie_u32::width() {
+wuffs_base__rect_ie_u32::width() const {
return wuffs_base__rect_ie_u32__width(this);
}
inline uint32_t //
-wuffs_base__rect_ie_u32::height() {
+wuffs_base__rect_ie_u32::height() const {
return wuffs_base__rect_ie_u32__height(this);
}
diff --git a/internal/cgen/builtin.go b/internal/cgen/builtin.go
index 636637e..1529d6b 100644
--- a/internal/cgen/builtin.go
+++ b/internal/cgen/builtin.go
@@ -102,75 +102,68 @@
func (g *gen) writeBuiltinIO(b *buffer, recv *a.Expr, method t.ID, args []*a.Node, depth uint32) error {
switch method {
case t.IDAvailable:
- p0, p1 := "", ""
+ p, q := "", ""
// TODO: don't hard-code these.
switch recv.Str(g.tm) {
case "args.dst":
- p0 = "io1_a_dst"
- p1 = "iop_a_dst"
+ p = "io2_a_dst"
+ q = "iop_a_dst"
case "args.src":
- p0 = "io1_a_src"
- p1 = "iop_a_src"
+ p = "io2_a_src"
+ q = "iop_a_src"
case "w":
- p0 = "io1_v_w"
- p1 = "iop_v_w"
+ p = "io2_v_w"
+ q = "iop_v_w"
}
- if p0 == "" {
+ if p == "" {
return fmt.Errorf(`TODO: cgen a "foo.available" expression`)
}
- b.printf("((uint64_t)(%s - %s))", p0, p1)
+ b.printf("((uint64_t)(%s - %s))", p, q)
return nil
-
- case t.IDSet:
- typ, v := "reader", "r"
- if len(args) == 1 {
- typ, v = "writer", "w"
- }
- b.printf("wuffs_base__io_%s__set(&v_%s, &u_%s, &iop_v_%s, &io1_v_%s,", typ, v, v, v, v)
- return g.writeArgs(b, args, depth)
-
}
return errNoSuchBuiltin
}
func (g *gen) writeBuiltinIOReader(b *buffer, recv *a.Expr, method t.ID, args []*a.Node, depth uint32) error {
// TODO: don't hard-code the recv being a_src.
+ prefix, name := aPrefix, "src"
+ if recv.Operator() == 0 {
+ prefix, name = vPrefix, recv.Ident().Str(g.tm)
+ }
+
switch method {
case t.IDUndoByte:
b.writes("(iop_a_src--, wuffs_base__make_empty_struct())")
return nil
case t.IDCanUndoByte:
- b.writes("(iop_a_src > io0_a_src)")
+ b.writes("(iop_a_src > io1_a_src)")
+ return nil
+
+ case t.IDCountSince:
+ b.printf("wuffs_base__io__count_since(")
+ if err := g.writeExpr(b, args[0].AsArg().Value(), depth); err != nil {
+ return err
+ }
+ b.printf(", ((uint64_t)(%s%s%s - %s%s%s)))", iopPrefix, prefix, name, io0Prefix, prefix, name)
+ return nil
+
+ case t.IDMark:
+ b.printf("((uint64_t)(%s%s%s - %s%s%s))", iopPrefix, prefix, name, io0Prefix, prefix, name)
return nil
case t.IDPosition:
- b.printf("(a_src.private_impl.buf ? wuffs_base__u64__sat_add(" +
- "a_src.private_impl.buf->meta.pos, ((uint64_t)(iop_a_src - a_src.private_impl.buf->data.ptr))) : 0)")
+ b.printf("(a_src ? wuffs_base__u64__sat_add(" +
+ "a_src->meta.pos, ((uint64_t)(iop_a_src - a_src->data.ptr))) : 0)")
return nil
- case t.IDSetLimit:
- b.printf("wuffs_base__io_reader__set_limit(&%ssrc, iop_a_src,", aPrefix)
- // TODO: update the iop variables?
- return g.writeArgs(b, args, depth)
-
- case t.IDSetMark:
- b.printf("wuffs_base__io_reader__set_mark(&%ssrc, iop_a_src)", aPrefix)
- return nil
-
- case t.IDSinceMark, t.IDSinceMarkLength:
- prefix, name := aPrefix, "src"
- if recv.Operator() == 0 {
- prefix, name = vPrefix, recv.Ident().Str(g.tm)
+ case t.IDSince:
+ b.printf("wuffs_base__io__since(")
+ if err := g.writeExpr(b, args[0].AsArg().Value(), depth); err != nil {
+ return err
}
-
- if method == t.IDSinceMark {
- b.printf("wuffs_base__make_slice_u8(%s%s.private_impl.mark, (size_t)(", prefix, name)
- }
- b.printf("iop_%s%s - %s%s.private_impl.mark", prefix, name, prefix, name)
- if method == t.IDSinceMark {
- b.writes("))")
- }
+ b.printf(", ((uint64_t)(%s%s%s - %s%s%s)), %s%s%s)",
+ iopPrefix, prefix, name, io0Prefix, prefix, name, io0Prefix, prefix, name)
return nil
case t.IDSkipFast:
@@ -186,7 +179,7 @@
return nil
case t.IDTake:
- b.printf("wuffs_base__io_reader__take(&iop_a_src, io1_a_src,")
+ b.printf("wuffs_base__io_reader__take(&iop_a_src, io2_a_src,")
return g.writeArgs(b, args, depth)
}
@@ -210,6 +203,11 @@
func (g *gen) writeBuiltinIOWriter(b *buffer, recv *a.Expr, method t.ID, args []*a.Node, depth uint32) error {
// TODO: don't hard-code the recv being a_dst or w.
+ prefix, name := aPrefix, "dst"
+ if recv.Operator() == 0 {
+ prefix, name = vPrefix, recv.Ident().Str(g.tm)
+ }
+
switch method {
case t.IDCopyNFromHistory, t.IDCopyNFromHistoryFast:
suffix := ""
@@ -217,7 +215,7 @@
suffix = "_fast"
}
b.printf("wuffs_base__io_writer__copy_n_from_history%s("+
- "&iop_a_dst, %sdst.private_impl.mark, io1_a_dst",
+ "&iop_a_dst, %sdst->data.ptr, io2_a_dst",
suffix, aPrefix)
for _, o := range args {
b.writeb(',')
@@ -229,48 +227,48 @@
return nil
case t.IDCopyNFromReader:
- b.printf("wuffs_base__io_writer__copy_n_from_reader(&iop_a_dst, io1_a_dst,")
+ b.printf("wuffs_base__io_writer__copy_n_from_reader(&iop_a_dst, io2_a_dst,")
if err := g.writeExpr(b, args[0].AsArg().Value(), depth); err != nil {
return err
}
// TODO: don't assume that the last argument is "args.src".
- b.printf(", &iop_a_src, io1_a_src)")
+ b.printf(", &iop_a_src, io2_a_src)")
return nil
case t.IDCopyFromSlice:
- b.printf("wuffs_base__io_writer__copy_from_slice(&iop_a_dst, io1_a_dst,")
+ b.printf("wuffs_base__io_writer__copy_from_slice(&iop_a_dst, io2_a_dst,")
return g.writeArgs(b, args, depth)
case t.IDCopyNFromSlice:
- b.printf("wuffs_base__io_writer__copy_n_from_slice(&iop_a_dst, io1_a_dst,")
+ b.printf("wuffs_base__io_writer__copy_n_from_slice(&iop_a_dst, io2_a_dst,")
return g.writeArgs(b, args, depth)
+ case t.IDCountSince:
+ b.printf("wuffs_base__io__count_since(")
+ if err := g.writeExpr(b, args[0].AsArg().Value(), depth); err != nil {
+ return err
+ }
+ b.printf(", ((uint64_t)(iop_a_dst - io0_a_dst)))")
+ return nil
+
+ case t.IDHistoryAvailable:
+ b.printf("((uint64_t)(iop_%s%s - %s%s->data.ptr))", prefix, name, prefix, name)
+ return nil
+
+ case t.IDMark:
+ b.printf("((uint64_t)(iop_a_dst - io0_a_dst))")
+ return nil
+
case t.IDPosition:
- b.printf("(a_dst.private_impl.buf ? wuffs_base__u64__sat_add(" +
- "a_dst.private_impl.buf->meta.pos, iop_a_dst - a_dst.private_impl.buf->data.ptr) : 0)")
+ b.printf("(a_dst ? wuffs_base__u64__sat_add(a_dst->meta.pos, iop_a_dst - a_dst->data.ptr) : 0)")
return nil
- case t.IDSetMark:
- // TODO: is a private_impl.mark the right representation? What
- // if the function is passed a (ptr io_writer) instead of a
- // (io_writer)? Do we still want to have that mark live outside of
- // the function scope?
- b.printf("wuffs_base__io_writer__set_mark(&%sdst, iop_a_dst)", aPrefix)
- return nil
-
- case t.IDSinceMark, t.IDSinceMarkLength:
- prefix, name := aPrefix, "dst"
- if recv.Operator() == 0 {
- prefix, name = vPrefix, recv.Ident().Str(g.tm)
+ case t.IDSince:
+ b.printf("wuffs_base__io__since(")
+ if err := g.writeExpr(b, args[0].AsArg().Value(), depth); err != nil {
+ return err
}
-
- if method == t.IDSinceMark {
- b.printf("wuffs_base__make_slice_u8(%s%s.private_impl.mark, (size_t)(", prefix, name)
- }
- b.printf("iop_%s%s - %s%s.private_impl.mark", prefix, name, prefix, name)
- if method == t.IDSinceMark {
- b.writes("))")
- }
+ b.printf(", ((uint64_t)(iop_a_dst - io0_a_dst)), io0_a_dst)")
return nil
}
@@ -401,25 +399,6 @@
return g.writeArgs(b, args, depth)
case t.IDLength:
- if recv.Operator() == t.IDOpenParen {
- if method := recv.LHS().AsExpr(); method.Operator() == t.IDDot && method.Ident() == t.IDSinceMark {
- if lhs := method.LHS().AsExpr(); lhs.MType().IsIOType() {
- b.writes("((uint64_t)(")
- if lhs.MType().QID()[1] == t.IDIOReader {
- if err := g.writeBuiltinIOReader(b, lhs, t.IDSinceMarkLength, nil, depth); err != nil {
- return err
- }
- } else {
- if err := g.writeBuiltinIOWriter(b, lhs, t.IDSinceMarkLength, nil, depth); err != nil {
- return err
- }
- }
- b.writes("))")
- return nil
- }
- }
- }
-
b.writes("((uint64_t)(")
if err := g.writeExpr(b, recv, depth); err != nil {
return err
@@ -579,7 +558,7 @@
temp := g.currFunk.tempW
g.currFunk.tempW++
- b.printf("if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {" +
+ b.printf("if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {" +
"status = wuffs_base__suspension__short_read; goto suspend; }")
// TODO: watch for passing an array type to writeCTypeName? In C, an
@@ -596,7 +575,7 @@
if err := g.writeCoroSuspPoint(b, false); err != nil {
return err
}
- b.printf("if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {" +
+ b.printf("if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {" +
"status = wuffs_base__suspension__short_read; goto suspend; }")
b.printf("iop_a_src++;\n")
return nil
@@ -617,9 +596,9 @@
return err
}
- b.printf("if (%s > ((uint64_t)(io1_a_src - iop_a_src))) {\n", scratchName)
- b.printf("%s -= ((uint64_t)(io1_a_src - iop_a_src));\n", scratchName)
- b.printf("iop_a_src = io1_a_src;\n")
+ b.printf("if (%s > ((uint64_t)(io2_a_src - iop_a_src))) {\n", scratchName)
+ 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.printf("iop_a_src += %s;\n", scratchName)
@@ -643,7 +622,7 @@
if err := g.writeCoroSuspPoint(b, false); err != nil {
return err
}
- b.writes("if (iop_a_dst == io1_a_dst) {\n" +
+ b.writes("if (iop_a_dst == io2_a_dst) {\n" +
"status = wuffs_base__suspension__short_write; goto suspend; }\n" +
"*iop_a_dst++ = ")
x := n.Args()[0].AsArg().Value()
@@ -681,7 +660,7 @@
scratchName := fmt.Sprintf("self->private_data.%s%s[0].scratch",
sPrefix, g.currFunk.astFunc.FuncName().Str(g.tm))
- b.printf("if (WUFFS_BASE__LIKELY(io1_a_src - iop_a_src >= %d)) {", xx/8)
+ b.printf("if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= %d)) {", xx/8)
b.printf("%s%d =", tPrefix, temp)
if xx != yy {
b.printf("((uint%d_t)(", yy)
@@ -699,7 +678,7 @@
}
b.printf("while (true) {")
- b.printf("if (WUFFS_BASE__UNLIKELY(iop_%s == io1_%s)) {"+
+ b.printf("if (WUFFS_BASE__UNLIKELY(iop_%s == io2_%s)) {"+
"status = wuffs_base__suspension__short_read; goto suspend; }",
preName, preName)
diff --git a/internal/cgen/cgen.go b/internal/cgen/cgen.go
index 52f9b3c..d5cb53b 100644
--- a/internal/cgen/cgen.go
+++ b/internal/cgen/cgen.go
@@ -68,27 +68,29 @@
// reading or writing the next byte (and advancing the stream) is essentially
// "etc = *iop_a_src++" or "*io_a_dst++ = etc".
//
-// The other two prefixes, giving names like io0_etc and io1_etc, are
+// The other two prefixes, giving names like io1_etc and io2_etc, are
// auxilliary pointers: lower and upper inclusive bounds. As an iop_etc pointer
-// advances, it cannot advance past io1_etc. In the rarer case that an iop_etc
-// pointer retreats, undoing a read or write, it cannot retreat past io0_etc.
+// advances, it cannot advance past io2_etc. In the rarer case that an iop_etc
+// pointer retreats, undoing a read or write, it cannot retreat past io1_etc.
+//
+// The iop_etc pointer can change over the lifetime of a function. The ioN_etc
+// pointers, for numeric N, cannot.
//
// At the start of a function, these pointers are initialized from an
-// io_buffer's fields (ptr, ri, wi, len), or possibly a limit field. For an
-// io_reader:
-// - io0_etc = ptr + ri
+// io_buffer's fields (ptr, ri, wi, len). For an io_reader:
+// - io0_etc = ptr
+// - io1_etc = ptr + ri
// - iop_etc = ptr + ri
-// - io1_etc = ptr + wi or limit
+// - io2_etc = ptr + wi
// and for an io_writer:
-// - io0_etc = ptr + wi
+// - io0_etc = ptr
+// - io1_etc = ptr + wi
// - iop_etc = ptr + wi
-// - io1_etc = ptr + len or limit
-//
-// TODO: discuss marks and limits, and how (if at all) auxilliary pointers can
-// change over a function's lifetime.
+// - io2_etc = ptr + len
const (
- io0Prefix = "io0_" // Lower bound.
- io1Prefix = "io1_" // Upper bound.
+ io0Prefix = "io0_" // Base.
+ io1Prefix = "io1_" // Lower bound.
+ io2Prefix = "io2_" // Upper bound.
iopPrefix = "iop_" // Pointer.
)
@@ -263,6 +265,19 @@
func insertBaseAllPublicH(buf *buffer) error {
if err := expandBangBangInsert(buf, baseCorePublicH, map[string]func(*buffer) error{
+ "// !! INSERT FourCCs.\n": func(b *buffer) error {
+ for _, z := range builtin.FourCCs {
+ b.printf("// %s.\n#define WUFFS_BASE__FOURCC__%s 0x%02X%02X%02X%02X\n\n",
+ z[1],
+ strings.ToUpper(strings.TrimSpace(z[0])),
+ z[0][0],
+ z[0][1],
+ z[0][2],
+ z[0][3],
+ )
+ }
+ return nil
+ },
"// !! INSERT wuffs_base__status names.\n": func(b *buffer) error {
for _, z := range builtin.Statuses {
msg, _ := t.Unescape(z)
diff --git a/internal/cgen/data.go b/internal/cgen/data.go
index 9b91b5e..09121da 100644
--- a/internal/cgen/data.go
+++ b/internal/cgen/data.go
@@ -24,11 +24,13 @@
""
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_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\n size_t n = len;\n const int N = 4;\n\n while (n >= N) {\n wuffs_base__store_u32le(\n d + (0 * 4),\n wuffs_base__load_u3" +
- "2le(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 uin" +
- "t8_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\nvoid //\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 if (!p) {\n return;\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__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__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__copy_4_1;\n break;\n d" +
- "efault:\n break;\n }\n break;\n\n default:\n break;\n }\n\n p->private_impl.func = func;\n}\n\nuint64_t //\nwuffs_base__pixel_swizzler__swizzle_packed(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__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" +
""
const baseCorePrivateH = "" +
@@ -71,6 +73,8 @@
"// --------\n\n// A status is either NULL (meaning OK) or a string message. That message is\n// human-readable, for programmers, but it is not for end users. It is not\n// localized, and does not contain additional contextual information such as a\n// source filename.\n//\n// Status strings are statically allocated and should never be free'd. They can\n// be compared by the == operator and not just by strcmp.\n//\n// Statuses come in four categories:\n// - OK: the request was completed, successfully.\n// - Warnings: the request was completed, unsuccessfully.\n// - Suspensions: the request was not completed, but can be re-tried.\n// - Errors: the request was not completed, permanently.\n//\n// When a function returns an incomplete status, a suspension means that that\n// function should be called again within a new context, such as after flushing\n// or re-filling an I/O buffer. An error means that an irrecoverable failure\n// state was reached.\ntypedef const char* wuffs_base__status;\n\n// !! INSERT wuffs_bas" +
"e__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" +
"" +
+ "// --------\n\n// FourCC constants.\n\n// !! INSERT FourCCs.\n\n" +
+ "" +
"// --------\n\n// Flicks are a unit of time. One flick (frame-tick) is 1 / 705_600_000 of a\n// second. See https://github.com/OculusVR/Flicks\ntypedef int64_t wuffs_base__flicks;\n\n#define WUFFS_BASE__FLICKS_PER_SECOND ((uint64_t)705600000)\n#define WUFFS_BASE__FLICKS_PER_MILLISECOND ((uint64_t)705600)\n\n" +
"" +
"// ---------------- Numeric Types\n\nstatic inline uint8_t //\nwuffs_base__u8__min(uint8_t x, uint8_t y) {\n return x < y ? x : y;\n}\n\nstatic inline uint8_t //\nwuffs_base__u8__max(uint8_t x, uint8_t y) {\n return x > y ? x : y;\n}\n\nstatic inline uint16_t //\nwuffs_base__u16__min(uint16_t x, uint16_t y) {\n return x < y ? x : y;\n}\n\nstatic inline uint16_t //\nwuffs_base__u16__max(uint16_t x, uint16_t y) {\n return x > y ? x : y;\n}\n\nstatic inline uint32_t //\nwuffs_base__u32__min(uint32_t x, uint32_t y) {\n return x < y ? x : y;\n}\n\nstatic inline uint32_t //\nwuffs_base__u32__max(uint32_t x, uint32_t y) {\n return x > y ? x : y;\n}\n\nstatic inline uint64_t //\nwuffs_base__u64__min(uint64_t x, uint64_t y) {\n return x < y ? x : y;\n}\n\nstatic inline uint64_t //\nwuffs_base__u64__max(uint64_t x, uint64_t y) {\n return x > y ? x : y;\n}\n\n" +
@@ -101,80 +105,81 @@
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. Its bits:\n// - bit 31 is reserved.\n// - bits 30 .. 28 encodes color (and channel order, in terms of memory).\n// - bit 27 is reserved.\n// - bits 26 .. 24 encodes transparency.\n// - bits 23 .. 21 are reserved.\n// - bit 20 indicates big-endian/MSB-first (as opposed to little/LSB).\n// - bit 19 indicates floating point (as opposed to integer).\n// - bit 18 indicates palette-indexed. The number-of-planes (the next\n// field) will be zero, as the format is considered packed,\n// but the 8-bit N-BGRA color data is stored in plane 3.\n// - bits 17 .. 16 are the number of planes, minus 1. Zero means packed.\n// - bits 15 .. 12 encodes the number of bits (depth) in the 3rd channel.\n// - bits 11 .. 8 encodes the number of bits (depth) in the 2nd channel.\n// - bits 7 .. 4 encodes the number of bits (depth) in the 1st channe" +
- "l.\n// - bits 3 .. 0 encodes the number of bits (depth) in the 0th channel.\n//\n// The bit fields of a wuffs_base__pixel_format are not independent. For\n// example, the number of planes should not be greater than the number of\n// channels. Similarly, bits 15..4 are unused (and should be zero) if bits\n// 31..24 (color and transparency) together imply only 1 channel (gray, no\n// alpha) and floating point samples should mean a bit depth of 16, 32 or 64.\n//\n// Formats hold between 1 and 4 channels. For example: Y (1 channel: gray), YA\n// (2 channels: gray and alpha), BGR (3 channels: blue, green, red) or CMYK (4\n// channels: cyan, magenta, yellow, black).\n//\n// For direct formats with N > 1 channels, those channels can be laid out in\n// either 1 (packed) or N (planar) planes. For example, RGBA data is usually\n// packed, but YCbCr data is usually planar, due to chroma subsampling (for\n// details, see the wuffs_base__pixel_subsampling type).\n//\n// For indexed formats, the palette (always 256 × 4 bytes) holds 8 bi" +
- "ts per\n// channel non-alpha-premultiplied BGRA color data. There is only 1 plane (for\n// the index), as the format is considered packed. Plane 0 holds the per-pixel\n// indices. Plane 3 is re-purposed to hold the per-index colors.\n//\n// The color field is encoded in 3 bits:\n// - 0 means A (Alpha).\n// - 1 means Y or YA (Gray, Alpha).\n// - 2 means YCbCr or YCbCrA (Luma, Chroma-blue, Chroma-red, Alpha).\n// - 3 means YCoCg or YCoCgA (Luma, Chroma-orange, Chroma-green, Alpha).\n// - 4 means BGR, BGRX or BGRA (Blue, Green, Red, X-padding or Alpha).\n// - 5 means RGB, RGBX or RGBA (Red, Green, Blue, X-padding or Alpha).\n// - 6 means CMY or CMYK (Cyan, Magenta, Yellow, Black).\n// - all other values are reserved.\n//\n// In Wuffs, channels are given in memory order (also known as byte order),\n// regardless of endianness, since the C type for the pixel data is an array of\n// bytes, not an array of uint32_t. For example, packed BGRA with 8 bits per\n// channel means th" +
- "at the bytes in memory are always Blue, Green, Red then\n// Alpha. On big-endian systems, that is the uint32_t 0xBBGGRRAA. On\n// little-endian, 0xAARRGGBB.\n//\n// When the color field (3 bits) encodes multiple options, the transparency\n// field (3 bits) distinguishes them:\n// - 0 means fully opaque, no extra channels\n// - 1 means fully opaque, one extra channel (X or K, padding or black).\n// - 5 means one extra alpha channel, other channels are non-premultiplied.\n// - 6 means one extra alpha channel, other channels are premultiplied.\n// - 7 means one extra alpha channel, binary alpha.\n// - all other values are reserved.\n//\n// Binary alpha means that if a color is not completely opaque, it is\n// completely transparent black. As a source pixel format, it can therefore be\n// treated as either non-premultiplied or premultiplied.\n//\n// The zero wuffs_base__pixel_format value is an invalid pixel format, as it is\n// invalid to combine the zero color (alpha only) with the zero transparency.\n//\n// Bit depth is" +
- " encoded in 4 bits:\n// - 0 means the channel or index is unused.\n// - x means a bit depth of x, for x in the range 1..8.\n// - 9 means a bit depth of 10.\n// - 10 means a bit depth of 12.\n// - 11 means a bit depth of 16.\n// - 12 means a bit depth of 24.\n// - 13 means a bit depth of 32.\n// - 14 means a bit depth of 48.\n// - 15 means a bit depth of 64.\n//\n// For example, wuffs_base__pixel_format 0x5510BBBB is a natural format for\n// decoding a PNG image - network byte order (also known as big-endian),\n// packed, non-premultiplied alpha - that happens to be 16-bit-depth truecolor\n// with alpha (RGBA). In memory order:\n//\n// ptr+0 ptr+1 ptr+2 ptr+3 ptr+4 ptr+5 ptr+6 ptr+7\n// Rhi Rlo Ghi Glo Bhi Blo Ahi Alo\n//\n// For example, the value wuffs_base__pixel_format 0x40000565 means BGR with no\n// alpha or padding, 5/6/5 bits for blue/green/red, packed 2 bytes per pixel,\n// laid out LSB-first in memory order:\n//\n// ptr+0........... ptr+1...........\n// MSB LSB MSB " +
- " LSB\n// G₂G₁G₀B₄B₃B₂B₁B₀ R₄R₃R₂R₁R₀G₅G₄G₃\n//\n// On little-endian systems (but not big-endian), this Wuffs pixel format value\n// (0x40000565) corresponds to the Cairo library's CAIRO_FORMAT_RGB16_565, the\n// SDL2 (Simple DirectMedia Layer 2) library's SDL_PIXELFORMAT_RGB565 and the\n// Skia library's kRGB_565_SkColorType. Note BGR in Wuffs versus RGB in the\n// other libraries.\n//\n// Regardless of endianness, this Wuffs pixel format value (0x40000565)\n// corresponds to the V4L2 (Video For Linux 2) library's V4L2_PIX_FMT_RGB565\n// and the Wayland-DRM library's WL_DRM_FORMAT_RGB565.\n//\n// Different software libraries name their pixel formats (and especially their\n// channel order) either according to memory layout or as bits of a native\n// integer type like uint32_t. The two conventions differ because of a system's\n// endianness. As mentioned earlier, Wuffs pixel formats are always in memory\n// order. More detail of other software libraries' naming conventions is in the\n// Pi" +
- "xel Format Guide at https://afrantzis.github.io/pixel-format-guide/\n//\n// Do not manipulate these 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 ((w" +
- "uffs_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 W" +
- "UFFS_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, for packed pixel formats,\n// the number of bits per pixel. It returns 0 for planar pixel 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_packed(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_BASE__PIXEL_FORMAT__INDEXED__INDEX_PLANE 0\n#define WUFFS_BASE__PIXEL_FORMAT__INDEXED__COLOR_PLANE 3\n\n" +
+ "// --------\n\n// wuffs_base__pixel_format encodes the format of the bytes that constitute an\n// image frame's pixel data. Its bits:\n// - bit 31 is reserved.\n// - bits 30 .. 28 encodes color (and channel order, in terms of memory).\n// - bit 27 is reserved.\n// - bits 26 .. 24 encodes transparency.\n// - bits 23 .. 21 are reserved.\n// - bit 20 indicates big-endian/MSB-first (as opposed to little/LSB).\n// - bit 19 indicates floating point (as opposed to integer).\n// - bit 18 indicates palette-indexed. The number-of-planes (the next\n// field) will be 0, as the format is considered interleaved,\n// but the 8-bit N-BGRA color data is stored in plane 3.\n// - bits 17 .. 16 are the number of planes, minus 1. Zero means interleaved.\n// - bits 15 .. 12 encodes the number of bits (depth) in the 3rd channel.\n// - bits 11 .. 8 encodes the number of bits (depth) in the 2nd channel.\n// - bits 7 .. 4 encodes the number of bits (depth) in the 1st" +
+ " channel.\n// - bits 3 .. 0 encodes the number of bits (depth) in the 0th channel.\n//\n// The bit fields of a wuffs_base__pixel_format are not independent. For\n// example, the number of planes should not be greater than the number of\n// channels. Similarly, bits 15..4 are unused (and should be zero) if bits\n// 31..24 (color and transparency) together imply only 1 channel (gray, no\n// alpha) and floating point samples should mean a bit depth of 16, 32 or 64.\n//\n// Formats hold between 1 and 4 channels. For example: Y (1 channel: gray), YA\n// (2 channels: gray and alpha), BGR (3 channels: blue, green, red) or CMYK (4\n// channels: cyan, magenta, yellow, black).\n//\n// For direct formats with N > 1 channels, those channels can be laid out in\n// either 1 (interleaved) or N (planar) planes. For example, RGBA data is\n// usually interleaved, but YCbCr data is usually planar, due to chroma\n// subsampling (for details, see the wuffs_base__pixel_subsampling type).\n//\n// For indexed formats, the palette (always 256 × 4 " +
+ "bytes) holds 8 bits per\n// channel non-alpha-premultiplied BGRA color data. There is only 1 plane (for\n// the index), as the format is considered interleaved. Plane 0 holds the\n// per-pixel indices. Plane 3 is re-purposed to hold the per-index colors.\n//\n// The color field is encoded in 3 bits:\n// - 0 means A (Alpha).\n// - 1 means Y or YA (Gray, Alpha).\n// - 2 means YCbCr or YCbCrA (Luma, Chroma-blue, Chroma-red, Alpha).\n// - 3 means YCoCg or YCoCgA (Luma, Chroma-orange, Chroma-green, Alpha).\n// - 4 means BGR, BGRX or BGRA (Blue, Green, Red, X-padding or Alpha).\n// - 5 means RGB, RGBX or RGBA (Red, Green, Blue, X-padding or Alpha).\n// - 6 means CMY or CMYK (Cyan, Magenta, Yellow, Black).\n// - all other values are reserved.\n//\n// In Wuffs, channels are given in memory order (also known as byte order),\n// regardless of endianness, since the C type for the pixel data is an array of\n// bytes, not an array of uint32_t. For example, interleaved BGRA with 8 b" +
+ "its\n// per channel means that the bytes in memory are always Blue, Green, Red then\n// Alpha. On big-endian systems, that is the uint32_t 0xBBGGRRAA. On\n// little-endian, 0xAARRGGBB.\n//\n// When the color field (3 bits) encodes multiple options, the transparency\n// field (3 bits) distinguishes them:\n// - 0 means fully opaque, no extra channels\n// - 1 means fully opaque, one extra channel (X or K, padding or black).\n// - 5 means one extra alpha channel, other channels are non-premultiplied.\n// - 6 means one extra alpha channel, other channels are premultiplied.\n// - 7 means one extra alpha channel, binary alpha.\n// - all other values are reserved.\n//\n// Binary alpha means that if a color is not completely opaque, it is\n// completely transparent black. As a source pixel format, it can therefore be\n// treated as either non-premultiplied or premultiplied.\n//\n// The zero wuffs_base__pixel_format value is an invalid pixel format, as it is\n// invalid to combine the zero color (alpha only) with the zero trans" +
+ "parency.\n//\n// Bit depth is encoded in 4 bits:\n// - 0 means the channel or index is unused.\n// - x means a bit depth of x, for x in the range 1..8.\n// - 9 means a bit depth of 10.\n// - 10 means a bit depth of 12.\n// - 11 means a bit depth of 16.\n// - 12 means a bit depth of 24.\n// - 13 means a bit depth of 32.\n// - 14 means a bit depth of 48.\n// - 15 means a bit depth of 64.\n//\n// For example, wuffs_base__pixel_format 0x5510BBBB is a natural format for\n// decoding a PNG image - network byte order (also known as big-endian),\n// interleaved, non-premultiplied alpha - that happens to be 16-bit-depth\n// truecolor with alpha (RGBA). In memory order:\n//\n// ptr+0 ptr+1 ptr+2 ptr+3 ptr+4 ptr+5 ptr+6 ptr+7\n// Rhi Rlo Ghi Glo Bhi Blo Ahi Alo\n//\n// For example, the value wuffs_base__pixel_format 0x40000565 means BGR with no\n// alpha or padding, 5/6/5 bits for blue/green/red, interleaved 2 bytes per\n// pixel, laid out LSB-first in memory order:\n//\n// ptr+0........... ptr+1...." +
+ ".......\n// MSB LSB MSB LSB\n// G₂G₁G₀B₄B₃B₂B₁B₀ R₄R₃R₂R₁R₀G₅G₄G₃\n//\n// On little-endian systems (but not big-endian), this Wuffs pixel format value\n// (0x40000565) corresponds to the Cairo library's CAIRO_FORMAT_RGB16_565, the\n// SDL2 (Simple DirectMedia Layer 2) library's SDL_PIXELFORMAT_RGB565 and the\n// Skia library's kRGB_565_SkColorType. Note BGR in Wuffs versus RGB in the\n// other libraries.\n//\n// Regardless of endianness, this Wuffs pixel format value (0x40000565)\n// corresponds to the V4L2 (Video For Linux 2) library's V4L2_PIX_FMT_RGB565\n// and the Wayland-DRM library's WL_DRM_FORMAT_RGB565.\n//\n// Different software libraries name their pixel formats (and especially their\n// channel order) either according to memory layout or as bits of a native\n// integer type like uint32_t. The two conventions differ because of a system's\n// endianness. As mentioned earlier, Wuffs pixel formats are always in memory\n// order. More detail of other software librarie" +
+ "s' naming conventions is in the\n// Pixel Format Guide at https://afrantzis.github.io/pixel-format-guide/\n//\n// Do not manipulate these 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__P" +
+ "IXEL_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 pixel 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_BASE__PIXEL_FORMAT__INDEXED__INDEX_PLANE 0\n#define WUFFS_BASE__PIXEL_FORMAT__INDEXED__COLOR_PLA" +
+ "NE 3\n\n" +
"" +
- "// --------\n\n// wuffs_base__pixel_subsampling encodes the mapping of pixel space coordinates\n// (x, y) to pixel buffer indices (i, j). That mapping can differ for each\n// plane p. For a depth of 8 bits (1 byte), the p'th plane's sample starts at\n// (planes[p].ptr + (j * planes[p].stride) + i).\n//\n// For packed pixel formats, the mapping is trivial: i = x and j = y. For\n// planar pixel formats, the mapping can differ due to chroma subsampling. For\n// example, consider a three plane YCbCr pixel format with 4:2:2 subsampling.\n// For the luma (Y) channel, there is one sample for every pixel, but for the\n// chroma (Cb, Cr) channels, there is one sample for every two pixels: pairs of\n// horizontally adjacent pixels form one macropixel, i = x / 2 and j == y. In\n// general, for a given p:\n// - i = (x + bias_x) >> shift_x.\n// - j = (y + bias_y) >> shift_y.\n// where biases and shifts are in the range 0..3 and 0..2 respectively.\n//\n// In general, the biases will be zero after decoding an image. However, making\n// a su" +
- "b-image may change the bias, since the (x, y) coordinates are relative\n// to the sub-image's top-left origin, but the backing pixel buffers were\n// created relative to the original image's origin.\n//\n// For each plane p, each of those four numbers (biases and shifts) are encoded\n// in two bits, which combine to form an 8 bit unsigned integer:\n//\n// e_p = (bias_x << 6) | (shift_x << 4) | (bias_y << 2) | (shift_y << 0)\n//\n// Those e_p values (e_0 for the first plane, e_1 for the second plane, etc)\n// combine to form a wuffs_base__pixel_subsampling value:\n//\n// pixsub = (e_3 << 24) | (e_2 << 16) | (e_1 << 8) | (e_0 << 0)\n//\n// Do not manipulate these 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__PI" +
- "XEL_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)0x202000)\n#define WUFFS_BASE__PIXEL_SUBSAMPLING__410 \\\n ((wuffs_base__pixel_subsampling)0x212100)\n\nstatic 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__shift_x(wuffs_base__pixel_subsampling s,\n uint32_t plane) {\n uint32_t shift = ((plane & 0x03) * 8) + 4;\n return (s >> shift) & 0x03;\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__shift_y(wuffs_base__pixel_subsampling s,\n uint32_t plane) {\n uint32_t shift = ((plane & 0x03) * 8) + 0;\n return (s >> shift) & 0x03;\n}\n\n" +
+ "// --------\n\n// wuffs_base__pixel_subsampling encodes the mapping of pixel space coordinates\n// (x, y) to pixel buffer indices (i, j). That mapping can differ for each\n// plane p. For a depth of 8 bits (1 byte), the p'th plane's sample starts at\n// (planes[p].ptr + (j * planes[p].stride) + i).\n//\n// For interleaved pixel formats, the mapping is trivial: i = x and j = y. For\n// planar pixel formats, the mapping can differ due to chroma subsampling. For\n// example, consider a three plane YCbCr pixel format with 4:2:2 subsampling.\n// For the luma (Y) channel, there is one sample for every pixel, but for the\n// chroma (Cb, Cr) channels, there is one sample for every two pixels: pairs of\n// horizontally adjacent pixels form one macropixel, i = x / 2 and j == y. In\n// general, for a given p:\n// - i = (x + bias_x) >> shift_x.\n// - j = (y + bias_y) >> shift_y.\n// where biases and shifts are in the range 0..3 and 0..2 respectively.\n//\n// In general, the biases will be zero after decoding an image. However, making\n//" +
+ " a sub-image may change the bias, since the (x, y) coordinates are relative\n// to the sub-image's top-left origin, but the backing pixel buffers were\n// created relative to the original image's origin.\n//\n// For each plane p, each of those four numbers (biases and shifts) are encoded\n// in two bits, which combine to form an 8 bit unsigned integer:\n//\n// e_p = (bias_x << 6) | (shift_x << 4) | (bias_y << 2) | (shift_y << 0)\n//\n// Those e_p values (e_0 for the first plane, e_1 for the second plane, etc)\n// combine to form a wuffs_base__pixel_subsampling value:\n//\n// pixsub = (e_3 << 24) | (e_2 << 16) | (e_1 << 8) | (e_0 << 0)\n//\n// Do not manipulate these 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_BAS" +
+ "E__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)0x202000)\n#define WUFFS_BASE__PIXEL_SUBSAMPLING__410 \\\n ((wuffs_base__pixel_subsampling)0x212100)\n\nstatic 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__shift_x(wuffs_base__pixel_subsampling s,\n uint32_t plane) {\n uint32_t shift = ((plane & 0x03) * 8) + 4;\n return (s >> shift) & 0x03;\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__shift_y(wuffs_base__pixel_subsampling s,\n uint32_t plane) {\n uint32_t shift = ((plane & 0x03) * 8) + 0;\n return (s >> shift) & 0x03;\n}\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();\n inline wuffs_base__pixel_format pixel_format();\n inline wuffs_base__pixel_subsampling pixel_subsampling();\n inline wuffs_base__rect_ie_u32 bounds();\n inline uint32_t width();\n inline uint32_t height();\n inline uint64_t pixbuf_len();\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 = 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_config__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(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(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(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(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(wuffs_base__pixel_config* c) {\n return c ? c->private_impl.width : 0;\n}\n\nstatic inline uint32_t //\nwuffs_base__pixel_config__height(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 packed) pixbufs? Should it allow\n// decoding into a color model different from the format's intrinsic one? For\n// example, decoding a JPEG image straight to RGBA instead of to YCbCr?\nstatic inline uint64_t //\nwuffs_base__pixel_config__pixbuf_len(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() {\n return wuffs_base__pixel_config__is_valid(this);\n}\n\ninline wuffs_base__pixel_format //\nwuffs_base__p" +
- "ixel_config::pixel_format() {\n return wuffs_base__pixel_config__pixel_format(this);\n}\n\ninline wuffs_base__pixel_subsampling //\nwuffs_base__pixel_config::pixel_subsampling() {\n return wuffs_base__pixel_config__pixel_subsampling(this);\n}\n\ninline wuffs_base__rect_ie_u32 //\nwuffs_base__pixel_config::bounds() {\n return wuffs_base__pixel_config__bounds(this);\n}\n\ninline uint32_t //\nwuffs_base__pixel_config::width() {\n return wuffs_base__pixel_config__width(this);\n}\n\ninline uint32_t //\nwuffs_base__pixel_config::height() {\n return wuffs_base__pixel_config__height(this);\n}\n\ninline uint64_t //\nwuffs_base__pixel_config::pixbuf_len() {\n return wuffs_base__pixel_config__pixbuf_len(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\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();\n inline uint64_t first_frame_io_position();\n inline bool first_frame_is_opaque();\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 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->pixcfg.private_impl.w" +
- "idth = 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(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(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(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(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() {\n return wuffs_base__image_config__is_valid(this);\n}\n\ninline uint64_t //\nwuffs_base__image_config::first_frame_io_position() {\n return wuffs_base__image_config__first_frame_io_position(this);\n}\n\ninline bool //\nwuffs_base__image_config::first_frame_is_opaque() {\n return wuffs_base__image_config__first_frame_is_opaque(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 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\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 } 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 inline wuffs_base__rect_ie_u32 bounds();\n inline uint32_t width();\n inline uint32_t height();\n inline wuffs_base__flicks duration();\n inline uint64_t index();\n inline uint64_t io_position();\n inline wuffs_base__animation_blend blend();\n inline wuffs_base__animation_disposal disposal();\n#endif // __cpluspl" +
- "us\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(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 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_po" +
- "sition;\n c->private_impl.blend = blend;\n c->private_impl.disposal = disposal;\n}\n\nstatic inline wuffs_base__rect_ie_u32 //\nwuffs_base__frame_config__bounds(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(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(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(wuffs_base__frame_config* c) {\n return c ? c->private_impl.duration : 0;\n}\n\n// wuffs_b" +
- "ase__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(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(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(wuffs_base__frame_config* c) {\n return c ? c->private_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__dispos" +
- "al(wuffs_base__frame_config* c) {\n return c ? c->private_impl.disposal : 0;\n}\n\n#ifdef __cplusplus\n\ninline void //\nwuffs_base__frame_config::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__frame_config__update(this, bounds, duration, index, io_position,\n blend, disposal);\n}\n\ninline wuffs_base__rect_ie_u32 //\nwuffs_base__frame_config::bounds() {\n return wuffs_base__frame_config__bounds(this);\n}\n\ninline uint32_t //\nwuffs_base__frame_config::width() {\n return wuffs_base__frame_config__width(this);\n}\n\ninline uint32_t //\nwuffs_base__frame_config::height() {\n return wuffs_base__frame_config__height(this);\n}\n\ninline wuffs_base__flicks //\nwuffs_base__frame_config::du" +
- "ration() {\n return wuffs_base__frame_config__duration(this);\n}\n\ninline uint64_t //\nwuffs_base__frame_config::index() {\n return wuffs_base__frame_config__index(this);\n}\n\ninline uint64_t //\nwuffs_base__frame_config::io_position() {\n return wuffs_base__frame_config__io_position(this);\n}\n\ninline wuffs_base__animation_blend //\nwuffs_base__frame_config::blend() {\n return wuffs_base__frame_config__blend(this);\n}\n\ninline wuffs_base__animation_disposal //\nwuffs_base__frame_config::disposal() {\n return wuffs_base__frame_config__disposal(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_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 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(wuffs_base__pixel_config* pixcfg,\n wuffs_base__slice_u8 pixbuf_memory);\n inline wuffs_base__slice_u8 palette();\n inline wuffs_base__pixel_format pixel_format();\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__null_table_u8();\n ret.private_impl.planes[1] = wuffs_base__null_table_u8();\n ret.private_impl.planes[2] = wuffs_base__null_tabl" +
- "e_u8();\n ret.private_impl.planes[3] = wuffs_base__null_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 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__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 return wuffs_base__error__bad_argument;\n }\n uint64_t bytes_per_pixel = bits_per_pixel / 8;\n\n uint8_t* ptr = pixbuf_memory.ptr;\n uint64_t len = pixbuf_memo" +
- "ry.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_pix" +
- "el;\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\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(wuffs_base__pixel_buffer* b) {\n i" +
- "f (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(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__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() {\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 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(wuffs_base__pixel_config* pixcfg,\n wuffs_base__slice_u8 pixbuf_memory);\n inline wuffs_base__status set_from_table(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.pri" +
+ "vate_impl.planes[0] = wuffs_base__null_table_u8();\n ret.private_impl.planes[1] = wuffs_base__null_table_u8();\n ret.private_impl.planes[2] = wuffs_base__null_table_u8();\n ret.private_impl.planes[3] = wuffs_base__null_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 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-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 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 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_b" +
+ "ase__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->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__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(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(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 void 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_packed(wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 dst_palette,\n wuffs_base__slice_u8 src);\n#endif // __cplusplus\n\n} wuffs_base__pixel_swizzler;\n\n// TODO: should prepare (both the C and C++ methods) return a status?\n\nvoid //\nwuffs_base__pixel_swizzler__prepare(wuffs_base__pixel_swi" +
- "zzler* 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_packed(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 void //\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_swizzler__prepare(this, dst_format, dst_palette, src_format,\n " +
- " src_palette);\n}\n\nuint64_t //\nwuffs_base__pixel_swizzler::swizzle_packed(wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 dst_palette,\n wuffs_base__slice_u8 src) {\n return wuffs_base__pixel_swizzler__swizzle_packed(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 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" +
""
const baseIOPrivateH = "" +
- "// ---------------- I/O\n\nstatic inline bool //\nwuffs_base__io_buffer__is_valid(wuffs_base__io_buffer buf) {\n return (buf.data.ptr || (buf.data.len == 0)) &&\n (buf.data.len >= buf.meta.wi) && (buf.meta.wi >= buf.meta.ri);\n}\n\n// TODO: wuffs_base__io_reader__is_eof is no longer used by Wuffs per se, but\n// it might be handy to programs that use Wuffs. Either delete it, or promote\n// it to the public API.\n//\n// If making this function public (i.e. moving it to base-header.h), it also\n// needs to allow NULL (i.e. implicit, callee-calculated) mark/limit.\n\nstatic inline bool //\nwuffs_base__io_reader__is_eof(wuffs_base__io_reader o) {\n wuffs_base__io_buffer* buf = o.private_impl.buf;\n return buf && buf->meta.closed &&\n (buf->data.ptr + buf->meta.wi == o.private_impl.limit);\n}\n\nstatic inline bool //\nwuffs_base__io_reader__is_valid(wuffs_base__io_reader o) {\n wuffs_base__io_buffer* buf = o.private_impl.buf;\n // Note: if making this function public (i.e. moving it to base-header.h), it\n // also " +
- "needs to allow NULL (i.e. implicit, callee-calculated) mark/limit.\n return buf ? ((buf->data.ptr <= o.private_impl.mark) &&\n (o.private_impl.mark <= o.private_impl.limit) &&\n (o.private_impl.limit <= buf->data.ptr + buf->data.len))\n : ((o.private_impl.mark == NULL) &&\n (o.private_impl.limit == NULL));\n}\n\nstatic inline bool //\nwuffs_base__io_writer__is_valid(wuffs_base__io_writer o) {\n wuffs_base__io_buffer* buf = o.private_impl.buf;\n // Note: if making this function public (i.e. moving it to base-header.h), it\n // also needs to allow NULL (i.e. implicit, callee-calculated) mark/limit.\n return buf ? ((buf->data.ptr <= o.private_impl.mark) &&\n (o.private_impl.mark <= o.private_impl.limit) &&\n (o.private_impl.limit <= buf->data.ptr + buf->data.len))\n : ((o.private_impl.mark == NULL) &&\n (o.private_impl.limit == NULL));\n}\n\nstatic inline uint32_t //\nwuffs_base__io_writer__copy_n_from_history(uin" +
- "t8_t** ptr_iop_w,\n uint8_t* io0_w,\n uint8_t* io1_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 - io0_w) < (size_t)(distance)) {\n return 0;\n }\n uint8_t* q = p - distance;\n size_t n = (size_t)(io1_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 - io0_w)\n// - length <= (io1_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* io0_w,\n uint8_t* io1_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* io1_w,\n uint32_t length,\n uint8_t** ptr_iop_r,\n uint8_t* io1_r) {\n uint8_t* iop_w = *ptr_iop_w;\n size_t n = length;\n if (n > ((size_t)(io1_w - iop_w))) {\n n = (size_t)(io1_w - iop_w);\n }\n uint8_t* iop_r = *ptr_iop_r;\n if (n > ((size_t)(io1_r - iop_r))) {\n n = (size_t)(io1_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* io1_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)(io1_w - iop_w))) {\n n = (size_t)(io1_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* io1_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)(io1_w - iop_w))) {\n n = (size_t)(io1_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__empty_struct //\nwuffs_base__io_reader__set(wuffs_base__io_reader* o,\n wuffs_base__io_buffer* b,\n uint8_t** ptr_iop_r,\n " +
- " uint8_t** ptr_io1_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 o->private_impl.buf = b;\n o->private_impl.mark = data.ptr;\n o->private_impl.limit = data.ptr + data.len;\n *ptr_iop_r = data.ptr;\n *ptr_io1_r = data.ptr + data.len;\n\n wuffs_base__empty_struct ret;\n ret.private_impl = 0;\n return ret;\n}\n\nstatic inline wuffs_base__empty_struct //\nwuffs_base__io_reader__set_limit(wuffs_base__io_reader* o,\n uint8_t* iop_r,\n uint64_t limit) {\n if (o && (((size_t)(o->private_impl.limit - iop_r)) > limit)) {\n o->private_impl.limit = iop_r + limit;\n }\n\n wuffs_base__empty_struct ret;\n ret.private_impl = 0;\n return ret;\n}\n\nstatic inline wuffs_base__empty_struct //\nwuffs_base__io_reader__set_mark(wuffs_base__io_reader* o, uint8_t* mark) {\n o->private_impl.mark = mark;\n\n wuffs_base__empty_struct ret;\n ret." +
- "private_impl = 0;\n return ret;\n}\n\nstatic inline wuffs_base__slice_u8 //\nwuffs_base__io_reader__take(uint8_t** ptr_iop_r, uint8_t* io1_r, uint64_t n) {\n if (n <= ((size_t)(io1_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__empty_struct //\nwuffs_base__io_writer__set(wuffs_base__io_writer* o,\n wuffs_base__io_buffer* b,\n uint8_t** ptr_iop_w,\n uint8_t** ptr_io1_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 o->private_impl.buf = b;\n o->private_impl.mark = data.ptr;\n o->private_impl.limit = data.ptr + data.len;\n *ptr_iop_w = data.ptr;\n *ptr_io1_w = data.ptr + data.len;\n\n wuffs_base__empty_struct ret;\n ret.private_impl = 0;\n return ret;\n}\n\nstatic inline wuffs_base__empty_str" +
- "uct //\nwuffs_base__io_writer__set_mark(wuffs_base__io_writer* o, uint8_t* mark) {\n o->private_impl.mark = mark;\n\n wuffs_base__empty_struct ret;\n ret.private_impl = 0;\n return ret;\n}\n\n" +
+ "// ---------------- I/O\n\n// \"Null\" as in \"/dev/null\", not as in \"nullptr\".\n//\n// TODO: ensure that this is zero-initialized.\nstatic wuffs_base__io_buffer wuffs_base__global__null_io_buffer;\n\nstatic inline wuffs_base__io_buffer* //\nwuffs_base__null_io_reader() {\n return &wuffs_base__global__null_io_buffer;\n}\n\nstatic inline wuffs_base__io_buffer* //\nwuffs_base__null_io_writer() {\n return &wuffs_base__global__null_io_buffer;\n}\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, poss" +
+ "ibly 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* 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 > ((s" +
+ "ize_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 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_ba" +
+ "se__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 = dat" +
+ "a.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__null_io_reader wuffs_base__null_io_reader\n#define wuffs_base__utility__null_io_writer wuffs_base__null_io_writer\n" +
""
const baseIOPublicH = "" +
- "// ---------------- I/O\n\nstruct wuffs_base__io_buffer__struct;\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 struct wuffs_base__io_buffer__struct* buf;\n // The bounds values are typically NULL, when created by the Wuffs public\n // API. NULL means that the callee substitutes the implicit bounds derived\n // from buf.\n uint8_t* mark;\n uint8_t* limit;\n } private_impl;\n} wuffs_base__io_reader;\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 struct wuffs_base__io_buffer__struct* buf;\n // The bounds values are typically NULL, when created by the Wuffs public\n // API. NULL means that the callee substitutes the implicit bounds derived\n // from buf.\n uint8_t* mark;\n uint8_t* limit;\n } private_impl;\n} wuffs_base__io_writer;\n\n// wuffs_base__io_buffer_meta is the met" +
- "adata for a wuffs_base__io_buffer's\n// data.\ntypedef struct {\n size_t wi; // Write index. Invariant: wi <= len.\n size_t ri; // Read index. Invariant: ri <= wi.\n uint64_t pos; // Position of the buffer start relative to the stream start.\n bool closed; // No further writes are expected.\n} wuffs_base__io_buffer_meta;\n\n// wuffs_base__io_buffer is a 1-dimensional buffer (a pointer and length) plus\n// additional metadata.\n//\n// A value with all fields zero is a valid, empty buffer.\ntypedef struct wuffs_base__io_buffer__struct {\n wuffs_base__slice_u8 data;\n wuffs_base__io_buffer_meta meta;\n\n#ifdef __cplusplus\n inline void compact();\n inline wuffs_base__io_reader reader();\n inline wuffs_base__io_writer writer();\n inline uint64_t reader_io_position();\n inline uint64_t writer_io_position();\n#endif // __cplusplus\n\n} wuffs_base__io_buffer;\n\nstatic inline wuffs_base__io_buffer //\nwuffs_base__make_io_buffer(wuffs_base__slice_u8 data,\n wuffs_base__io_buffer_meta meta) {\n w" +
- "uffs_base__io_buffer ret;\n ret.data = data;\n ret.meta = meta;\n return ret;\n}\n\nstatic inline wuffs_base__io_buffer_meta //\nwuffs_base__make_io_buffer_meta(size_t wi,\n size_t ri,\n uint64_t pos,\n bool closed) {\n wuffs_base__io_buffer_meta ret;\n ret.wi = wi;\n ret.ri = ri;\n ret.pos = pos;\n ret.closed = closed;\n return ret;\n}\n\nstatic inline wuffs_base__io_buffer //\nwuffs_base__null_io_buffer() {\n wuffs_base__io_buffer ret;\n ret.data.ptr = NULL;\n ret.data.len = 0;\n ret.meta.wi = 0;\n ret.meta.ri = 0;\n ret.meta.pos = 0;\n ret.meta.closed = false;\n return ret;\n}\n\nstatic inline wuffs_base__io_buffer_meta //\nwuffs_base__null_io_buffer_meta() {\n wuffs_base__io_buffer_meta ret;\n ret.wi = 0;\n ret.ri = 0;\n ret.pos = 0;\n ret.closed = false;\n return ret;\n}\n\nstatic inline wuffs_base__io_reader //\nwuffs_base__null_io_reader() {\n wuffs_base__io_reader ret;\n ret.private_impl.buf = NULL;\n ret.private_impl.mark =" +
- " NULL;\n ret.private_impl.limit = NULL;\n return ret;\n}\n\nstatic inline wuffs_base__io_writer //\nwuffs_base__null_io_writer() {\n wuffs_base__io_writer ret;\n ret.private_impl.buf = NULL;\n ret.private_impl.mark = NULL;\n ret.private_impl.limit = NULL;\n return ret;\n}\n\n// wuffs_base__io_buffer__compact moves any written but unread bytes to the\n// start of the buffer.\nstatic inline void //\nwuffs_base__io_buffer__compact(wuffs_base__io_buffer* buf) {\n if (!buf || (buf->meta.ri == 0)) {\n return;\n }\n buf->meta.pos = wuffs_base__u64__sat_add(buf->meta.pos, buf->meta.ri);\n size_t n = buf->meta.wi - buf->meta.ri;\n if (n != 0) {\n memmove(buf->data.ptr, buf->data.ptr + buf->meta.ri, n);\n }\n buf->meta.wi = n;\n buf->meta.ri = 0;\n}\n\nstatic inline wuffs_base__io_reader //\nwuffs_base__io_buffer__reader(wuffs_base__io_buffer* buf) {\n wuffs_base__io_reader ret;\n ret.private_impl.buf = buf;\n ret.private_impl.mark = NULL;\n ret.private_impl.limit = NULL;\n return ret;\n}\n\nstatic inline wuffs_base__io_writer " +
- "//\nwuffs_base__io_buffer__writer(wuffs_base__io_buffer* buf) {\n wuffs_base__io_writer ret;\n ret.private_impl.buf = buf;\n ret.private_impl.mark = NULL;\n ret.private_impl.limit = NULL;\n return ret;\n}\n\nstatic inline uint64_t //\nwuffs_base__io_buffer__reader_io_position(wuffs_base__io_buffer* buf) {\n return buf ? wuffs_base__u64__sat_add(buf->meta.pos, buf->meta.ri) : 0;\n}\n\nstatic inline uint64_t //\nwuffs_base__io_buffer__writer_io_position(wuffs_base__io_buffer* buf) {\n return buf ? wuffs_base__u64__sat_add(buf->meta.pos, buf->meta.wi) : 0;\n}\n\n#ifdef __cplusplus\n\ninline void //\nwuffs_base__io_buffer__struct::compact() {\n wuffs_base__io_buffer__compact(this);\n}\n\ninline wuffs_base__io_reader //\nwuffs_base__io_buffer__struct::reader() {\n return wuffs_base__io_buffer__reader(this);\n}\n\ninline wuffs_base__io_writer //\nwuffs_base__io_buffer__struct::writer() {\n return wuffs_base__io_buffer__writer(this);\n}\n\ninline uint64_t //\nwuffs_base__io_buffer__struct::reader_io_position() {\n return wuffs_base__io_" +
- "buffer__reader_io_position(this);\n}\n\ninline uint64_t //\nwuffs_base__io_buffer__struct::writer_io_position() {\n return wuffs_base__io_buffer__writer_io_position(this);\n}\n\n#endif // __cplusplus\n" +
+ "// ---------------- I/O\n//\n// See (/doc/note/io-input-output.md).\n\n// wuffs_base__io_buffer_meta is the metadata for a wuffs_base__io_buffer's\n// data.\ntypedef struct {\n size_t wi; // Write index. Invariant: wi <= len.\n size_t ri; // Read index. Invariant: ri <= wi.\n uint64_t pos; // Position of the buffer start relative to the stream start.\n bool closed; // No further writes are expected.\n} wuffs_base__io_buffer_meta;\n\n// wuffs_base__io_buffer is a 1-dimensional buffer (a pointer and length) plus\n// additional metadata.\n//\n// A value with all fields zero is a valid, empty buffer.\ntypedef struct wuffs_base__io_buffer__struct {\n wuffs_base__slice_u8 data;\n wuffs_base__io_buffer_meta meta;\n\n#ifdef __cplusplus\n inline void compact();\n inline wuffs_base__io_buffer__struct* reader(); // Deprecated.\n inline wuffs_base__io_buffer__struct* writer(); // Deprecated.\n inline uint64_t reader_available() const;\n inline uint64_t reader_io_position() const;\n inline uint64_t writer_available() const" +
+ ";\n inline uint64_t writer_io_position() const;\n#endif // __cplusplus\n\n} wuffs_base__io_buffer;\n\nstatic inline wuffs_base__io_buffer //\nwuffs_base__make_io_buffer(wuffs_base__slice_u8 data,\n wuffs_base__io_buffer_meta meta) {\n wuffs_base__io_buffer ret;\n ret.data = data;\n ret.meta = meta;\n return ret;\n}\n\nstatic inline wuffs_base__io_buffer_meta //\nwuffs_base__make_io_buffer_meta(size_t wi,\n size_t ri,\n uint64_t pos,\n bool closed) {\n wuffs_base__io_buffer_meta ret;\n ret.wi = wi;\n ret.ri = ri;\n ret.pos = pos;\n ret.closed = closed;\n return ret;\n}\n\nstatic inline wuffs_base__io_buffer //\nwuffs_base__null_io_buffer() {\n wuffs_base__io_buffer ret;\n ret.data.ptr = NULL;\n ret.data.len = 0;\n ret.meta.wi = 0;\n ret.meta.ri = 0;\n ret.meta.pos = 0;\n ret.meta.closed = false;\n return ret;\n}\n\nstatic inline wuffs_base__io_buffer_meta //\nwuffs_base__null_io_buffer_meta() {\n wuffs_base__i" +
+ "o_buffer_meta ret;\n ret.wi = 0;\n ret.ri = 0;\n ret.pos = 0;\n ret.closed = false;\n return ret;\n}\n\n// wuffs_base__io_buffer__compact moves any written but unread bytes to the\n// start of the buffer.\nstatic inline void //\nwuffs_base__io_buffer__compact(wuffs_base__io_buffer* buf) {\n if (!buf || (buf->meta.ri == 0)) {\n return;\n }\n buf->meta.pos = wuffs_base__u64__sat_add(buf->meta.pos, buf->meta.ri);\n size_t n = buf->meta.wi - buf->meta.ri;\n if (n != 0) {\n memmove(buf->data.ptr, buf->data.ptr + buf->meta.ri, n);\n }\n buf->meta.wi = n;\n buf->meta.ri = 0;\n}\n\nstatic inline uint64_t //\nwuffs_base__io_buffer__reader_available(const wuffs_base__io_buffer* buf) {\n return buf ? buf->meta.wi - buf->meta.ri : 0;\n}\n\nstatic inline uint64_t //\nwuffs_base__io_buffer__reader_io_position(const wuffs_base__io_buffer* buf) {\n return buf ? wuffs_base__u64__sat_add(buf->meta.pos, buf->meta.ri) : 0;\n}\n\nstatic inline uint64_t //\nwuffs_base__io_buffer__writer_available(const wuffs_base__io_buffer* buf) {\n return" +
+ " buf ? buf->data.len - buf->meta.wi : 0;\n}\n\nstatic inline uint64_t //\nwuffs_base__io_buffer__writer_io_position(const wuffs_base__io_buffer* buf) {\n return buf ? wuffs_base__u64__sat_add(buf->meta.pos, buf->meta.wi) : 0;\n}\n\n#ifdef __cplusplus\n\ninline void //\nwuffs_base__io_buffer__struct::compact() {\n wuffs_base__io_buffer__compact(this);\n}\n\ninline wuffs_base__io_buffer* //\nwuffs_base__io_buffer__struct::reader() {\n return this;\n}\n\ninline wuffs_base__io_buffer* //\nwuffs_base__io_buffer__struct::writer() {\n return this;\n}\n\ninline uint64_t //\nwuffs_base__io_buffer__struct::reader_available() const {\n return wuffs_base__io_buffer__reader_available(this);\n}\n\ninline uint64_t //\nwuffs_base__io_buffer__struct::reader_io_position() const {\n return wuffs_base__io_buffer__reader_io_position(this);\n}\n\ninline uint64_t //\nwuffs_base__io_buffer__struct::writer_available() const {\n return wuffs_base__io_buffer__writer_available(this);\n}\n\ninline uint64_t //\nwuffs_base__io_buffer__struct::writer_io_position() c" +
+ "onst {\n return wuffs_base__io_buffer__writer_io_position(this);\n}\n\n#endif // __cplusplus\n" +
""
const baseRangePrivateH = "" +
@@ -186,39 +191,39 @@
const baseRangePublicH = "" +
"// ---------------- Ranges and Rects\n\n// Ranges are either inclusive (\"range_ii\") or exclusive (\"range_ie\") on the\n// high end. Both the \"ii\" and \"ie\" flavors are useful in practice.\n//\n// The \"ei\" and \"ee\" flavors also exist in theory, but aren't widely used. In\n// Wuffs, the low end is always inclusive.\n//\n// The \"ii\" (closed interval) flavor is useful when refining e.g. \"the set of\n// all uint32_t values\" to a contiguous subset: \"uint32_t values in the closed\n// interval [M, N]\", for uint32_t values M and N. An unrefined type (in other\n// words, the set of all uint32_t values) is not representable in the \"ie\"\n// flavor because if N equals ((1<<32) - 1) then (N + 1) will overflow.\n//\n// On the other hand, the \"ie\" (half-open interval) flavor is recommended by\n// Dijkstra's \"Why numbering should start at zero\" at\n// http://www.cs.utexas.edu/users/EWD/ewd08xx/EWD831.PDF and a further\n// discussion of motivating rationale is at\n// https://www.quora.com/Why-are-Python-ranges-half-open-exclusive-instead-of-close" +
- "d-inclusive\n//\n// For example, with \"ie\", the number of elements in \"uint32_t values in the\n// half-open interval [M, N)\" is equal to max(0, N-M). Furthermore, that number\n// of elements (in one dimension, a length, in two dimensions, a width or\n// height) is itself representable as a uint32_t without overflow, again for\n// uint32_t values M and N. In the contrasting \"ii\" flavor, the length of the\n// closed interval [0, (1<<32) - 1] is 1<<32, which cannot be represented as a\n// uint32_t. In Wuffs, because of this potential overflow, the \"ie\" flavor has\n// length / width / height methods, but the \"ii\" flavor does not.\n//\n// It is valid for min > max (for range_ii) or for min >= max (for range_ie),\n// in which case the range is empty. There are multiple representations of an\n// empty range.\n\ntypedef struct wuffs_base__range_ii_u32__struct {\n uint32_t min_incl;\n uint32_t max_incl;\n\n#ifdef __cplusplus\n inline bool is_empty();\n inline bool equals(wuffs_base__range_ii_u32__struct s);\n inline wuffs_base__range_" +
- "ii_u32__struct intersect(\n wuffs_base__range_ii_u32__struct s);\n inline wuffs_base__range_ii_u32__struct unite(\n wuffs_base__range_ii_u32__struct s);\n inline bool contains(uint32_t x);\n inline bool contains_range(wuffs_base__range_ii_u32__struct s);\n#endif // __cplusplus\n\n} wuffs_base__range_ii_u32;\n\nstatic inline wuffs_base__range_ii_u32 //\nwuffs_base__make_range_ii_u32(uint32_t min_incl, uint32_t max_incl) {\n wuffs_base__range_ii_u32 ret;\n ret.min_incl = min_incl;\n ret.max_incl = max_incl;\n return ret;\n}\n\nstatic inline bool //\nwuffs_base__range_ii_u32__is_empty(wuffs_base__range_ii_u32* r) {\n return r->min_incl > r->max_incl;\n}\n\nstatic inline bool //\nwuffs_base__range_ii_u32__equals(wuffs_base__range_ii_u32* r,\n wuffs_base__range_ii_u32 s) {\n return (r->min_incl == s.min_incl && r->max_incl == s.max_incl) ||\n (wuffs_base__range_ii_u32__is_empty(r) &&\n wuffs_base__range_ii_u32__is_empty(&s));\n}\n\nstatic inline wuffs_base__range_ii_u32 //" +
- "\nwuffs_base__range_ii_u32__intersect(wuffs_base__range_ii_u32* r,\n wuffs_base__range_ii_u32 s) {\n wuffs_base__range_ii_u32 t;\n t.min_incl = wuffs_base__u32__max(r->min_incl, s.min_incl);\n t.max_incl = wuffs_base__u32__min(r->max_incl, s.max_incl);\n return t;\n}\n\nstatic inline wuffs_base__range_ii_u32 //\nwuffs_base__range_ii_u32__unite(wuffs_base__range_ii_u32* r,\n wuffs_base__range_ii_u32 s) {\n if (wuffs_base__range_ii_u32__is_empty(r)) {\n return s;\n }\n if (wuffs_base__range_ii_u32__is_empty(&s)) {\n return *r;\n }\n wuffs_base__range_ii_u32 t;\n t.min_incl = wuffs_base__u32__min(r->min_incl, s.min_incl);\n t.max_incl = wuffs_base__u32__max(r->max_incl, s.max_incl);\n return t;\n}\n\nstatic inline bool //\nwuffs_base__range_ii_u32__contains(wuffs_base__range_ii_u32* r, uint32_t x) {\n return (r->min_incl <= x) && (x <= r->max_incl);\n}\n\nstatic inline bool //\nwuffs_base__range_ii_u32__contains_range(wuffs_base__range_ii_u32* r,\n " +
- " wuffs_base__range_ii_u32 s) {\n return wuffs_base__range_ii_u32__equals(\n &s, wuffs_base__range_ii_u32__intersect(r, s));\n}\n\n#ifdef __cplusplus\n\ninline bool //\nwuffs_base__range_ii_u32::is_empty() {\n return wuffs_base__range_ii_u32__is_empty(this);\n}\n\ninline bool //\nwuffs_base__range_ii_u32::equals(wuffs_base__range_ii_u32 s) {\n return wuffs_base__range_ii_u32__equals(this, s);\n}\n\ninline wuffs_base__range_ii_u32 //\nwuffs_base__range_ii_u32::intersect(wuffs_base__range_ii_u32 s) {\n return wuffs_base__range_ii_u32__intersect(this, s);\n}\n\ninline wuffs_base__range_ii_u32 //\nwuffs_base__range_ii_u32::unite(wuffs_base__range_ii_u32 s) {\n return wuffs_base__range_ii_u32__unite(this, s);\n}\n\ninline bool //\nwuffs_base__range_ii_u32::contains(uint32_t x) {\n return wuffs_base__range_ii_u32__contains(this, x);\n}\n\ninline bool //\nwuffs_base__range_ii_u32::contains_range(wuffs_base__range_ii_u32 s) {\n return wuffs_base__range_ii_u32__contains_range(this, s);\n}\n\n#endif // __c" +
- "plusplus\n\n" +
+ "d-inclusive\n//\n// For example, with \"ie\", the number of elements in \"uint32_t values in the\n// half-open interval [M, N)\" is equal to max(0, N-M). Furthermore, that number\n// of elements (in one dimension, a length, in two dimensions, a width or\n// height) is itself representable as a uint32_t without overflow, again for\n// uint32_t values M and N. In the contrasting \"ii\" flavor, the length of the\n// closed interval [0, (1<<32) - 1] is 1<<32, which cannot be represented as a\n// uint32_t. In Wuffs, because of this potential overflow, the \"ie\" flavor has\n// length / width / height methods, but the \"ii\" flavor does not.\n//\n// It is valid for min > max (for range_ii) or for min >= max (for range_ie),\n// in which case the range is empty. There are multiple representations of an\n// empty range.\n\ntypedef struct wuffs_base__range_ii_u32__struct {\n uint32_t min_incl;\n uint32_t max_incl;\n\n#ifdef __cplusplus\n inline bool is_empty() const;\n inline bool equals(wuffs_base__range_ii_u32__struct s) const;\n inline wuffs_" +
+ "base__range_ii_u32__struct intersect(\n wuffs_base__range_ii_u32__struct s) const;\n inline wuffs_base__range_ii_u32__struct unite(\n wuffs_base__range_ii_u32__struct s) const;\n inline bool contains(uint32_t x) const;\n inline bool contains_range(wuffs_base__range_ii_u32__struct s) const;\n#endif // __cplusplus\n\n} wuffs_base__range_ii_u32;\n\nstatic inline wuffs_base__range_ii_u32 //\nwuffs_base__make_range_ii_u32(uint32_t min_incl, uint32_t max_incl) {\n wuffs_base__range_ii_u32 ret;\n ret.min_incl = min_incl;\n ret.max_incl = max_incl;\n return ret;\n}\n\nstatic inline bool //\nwuffs_base__range_ii_u32__is_empty(const wuffs_base__range_ii_u32* r) {\n return r->min_incl > r->max_incl;\n}\n\nstatic inline bool //\nwuffs_base__range_ii_u32__equals(const wuffs_base__range_ii_u32* r,\n wuffs_base__range_ii_u32 s) {\n return (r->min_incl == s.min_incl && r->max_incl == s.max_incl) ||\n (wuffs_base__range_ii_u32__is_empty(r) &&\n wuffs_base__range_ii_u32__is_empty(&s)" +
+ ");\n}\n\nstatic inline wuffs_base__range_ii_u32 //\nwuffs_base__range_ii_u32__intersect(const wuffs_base__range_ii_u32* r,\n wuffs_base__range_ii_u32 s) {\n wuffs_base__range_ii_u32 t;\n t.min_incl = wuffs_base__u32__max(r->min_incl, s.min_incl);\n t.max_incl = wuffs_base__u32__min(r->max_incl, s.max_incl);\n return t;\n}\n\nstatic inline wuffs_base__range_ii_u32 //\nwuffs_base__range_ii_u32__unite(const wuffs_base__range_ii_u32* r,\n wuffs_base__range_ii_u32 s) {\n if (wuffs_base__range_ii_u32__is_empty(r)) {\n return s;\n }\n if (wuffs_base__range_ii_u32__is_empty(&s)) {\n return *r;\n }\n wuffs_base__range_ii_u32 t;\n t.min_incl = wuffs_base__u32__min(r->min_incl, s.min_incl);\n t.max_incl = wuffs_base__u32__max(r->max_incl, s.max_incl);\n return t;\n}\n\nstatic inline bool //\nwuffs_base__range_ii_u32__contains(const wuffs_base__range_ii_u32* r,\n uint32_t x) {\n return (r->min_incl <= x) && (x <= r->max_incl);\n}\n\n" +
+ "static inline bool //\nwuffs_base__range_ii_u32__contains_range(const wuffs_base__range_ii_u32* r,\n wuffs_base__range_ii_u32 s) {\n return wuffs_base__range_ii_u32__equals(\n &s, wuffs_base__range_ii_u32__intersect(r, s));\n}\n\n#ifdef __cplusplus\n\ninline bool //\nwuffs_base__range_ii_u32::is_empty() const {\n return wuffs_base__range_ii_u32__is_empty(this);\n}\n\ninline bool //\nwuffs_base__range_ii_u32::equals(wuffs_base__range_ii_u32 s) const {\n return wuffs_base__range_ii_u32__equals(this, s);\n}\n\ninline wuffs_base__range_ii_u32 //\nwuffs_base__range_ii_u32::intersect(wuffs_base__range_ii_u32 s) const {\n return wuffs_base__range_ii_u32__intersect(this, s);\n}\n\ninline wuffs_base__range_ii_u32 //\nwuffs_base__range_ii_u32::unite(wuffs_base__range_ii_u32 s) const {\n return wuffs_base__range_ii_u32__unite(this, s);\n}\n\ninline bool //\nwuffs_base__range_ii_u32::contains(uint32_t x) const {\n return wuffs_base__range_ii_u32__contains(this, x);\n}\n\ninline bool //\nwuffs_base_" +
+ "_range_ii_u32::contains_range(wuffs_base__range_ii_u32 s) const {\n return wuffs_base__range_ii_u32__contains_range(this, s);\n}\n\n#endif // __cplusplus\n\n" +
"" +
- "// --------\n\ntypedef struct wuffs_base__range_ie_u32__struct {\n uint32_t min_incl;\n uint32_t max_excl;\n\n#ifdef __cplusplus\n inline bool is_empty();\n inline bool equals(wuffs_base__range_ie_u32__struct s);\n inline wuffs_base__range_ie_u32__struct intersect(\n wuffs_base__range_ie_u32__struct s);\n inline wuffs_base__range_ie_u32__struct unite(\n wuffs_base__range_ie_u32__struct s);\n inline bool contains(uint32_t x);\n inline bool contains_range(wuffs_base__range_ie_u32__struct s);\n inline uint32_t length();\n#endif // __cplusplus\n\n} wuffs_base__range_ie_u32;\n\nstatic inline wuffs_base__range_ie_u32 //\nwuffs_base__make_range_ie_u32(uint32_t min_incl, uint32_t max_excl) {\n wuffs_base__range_ie_u32 ret;\n ret.min_incl = min_incl;\n ret.max_excl = max_excl;\n return ret;\n}\n\nstatic inline bool //\nwuffs_base__range_ie_u32__is_empty(wuffs_base__range_ie_u32* r) {\n return r->min_incl >= r->max_excl;\n}\n\nstatic inline bool //\nwuffs_base__range_ie_u32__equals(wuffs_base__range_ie_u32* r,\n " +
- " wuffs_base__range_ie_u32 s) {\n return (r->min_incl == s.min_incl && r->max_excl == s.max_excl) ||\n (wuffs_base__range_ie_u32__is_empty(r) &&\n wuffs_base__range_ie_u32__is_empty(&s));\n}\n\nstatic inline wuffs_base__range_ie_u32 //\nwuffs_base__range_ie_u32__intersect(wuffs_base__range_ie_u32* r,\n wuffs_base__range_ie_u32 s) {\n wuffs_base__range_ie_u32 t;\n t.min_incl = wuffs_base__u32__max(r->min_incl, s.min_incl);\n t.max_excl = wuffs_base__u32__min(r->max_excl, s.max_excl);\n return t;\n}\n\nstatic inline wuffs_base__range_ie_u32 //\nwuffs_base__range_ie_u32__unite(wuffs_base__range_ie_u32* r,\n wuffs_base__range_ie_u32 s) {\n if (wuffs_base__range_ie_u32__is_empty(r)) {\n return s;\n }\n if (wuffs_base__range_ie_u32__is_empty(&s)) {\n return *r;\n }\n wuffs_base__range_ie_u32 t;\n t.min_incl = wuffs_base__u32__min(r->min_incl, s.min_incl);\n t.max_excl = wuffs_base__u32__max(r->max_excl, s.max_excl);\n retu" +
- "rn t;\n}\n\nstatic inline bool //\nwuffs_base__range_ie_u32__contains(wuffs_base__range_ie_u32* r, uint32_t x) {\n return (r->min_incl <= x) && (x < r->max_excl);\n}\n\nstatic inline bool //\nwuffs_base__range_ie_u32__contains_range(wuffs_base__range_ie_u32* r,\n wuffs_base__range_ie_u32 s) {\n return wuffs_base__range_ie_u32__equals(\n &s, wuffs_base__range_ie_u32__intersect(r, s));\n}\n\nstatic inline uint32_t //\nwuffs_base__range_ie_u32__length(wuffs_base__range_ie_u32* r) {\n return wuffs_base__u32__sat_sub(r->max_excl, r->min_incl);\n}\n\n#ifdef __cplusplus\n\ninline bool //\nwuffs_base__range_ie_u32::is_empty() {\n return wuffs_base__range_ie_u32__is_empty(this);\n}\n\ninline bool //\nwuffs_base__range_ie_u32::equals(wuffs_base__range_ie_u32 s) {\n return wuffs_base__range_ie_u32__equals(this, s);\n}\n\ninline wuffs_base__range_ie_u32 //\nwuffs_base__range_ie_u32::intersect(wuffs_base__range_ie_u32 s) {\n return wuffs_base__range_ie_u32__intersect(this, s);\n}\n\ninline wuffs_base__" +
- "range_ie_u32 //\nwuffs_base__range_ie_u32::unite(wuffs_base__range_ie_u32 s) {\n return wuffs_base__range_ie_u32__unite(this, s);\n}\n\ninline bool //\nwuffs_base__range_ie_u32::contains(uint32_t x) {\n return wuffs_base__range_ie_u32__contains(this, x);\n}\n\ninline bool //\nwuffs_base__range_ie_u32::contains_range(wuffs_base__range_ie_u32 s) {\n return wuffs_base__range_ie_u32__contains_range(this, s);\n}\n\ninline uint32_t //\nwuffs_base__range_ie_u32::length() {\n return wuffs_base__range_ie_u32__length(this);\n}\n\n#endif // __cplusplus\n\n" +
+ "// --------\n\ntypedef struct wuffs_base__range_ie_u32__struct {\n uint32_t min_incl;\n uint32_t max_excl;\n\n#ifdef __cplusplus\n inline bool is_empty() const;\n inline bool equals(wuffs_base__range_ie_u32__struct s) const;\n inline wuffs_base__range_ie_u32__struct intersect(\n wuffs_base__range_ie_u32__struct s) const;\n inline wuffs_base__range_ie_u32__struct unite(\n wuffs_base__range_ie_u32__struct s) const;\n inline bool contains(uint32_t x) const;\n inline bool contains_range(wuffs_base__range_ie_u32__struct s) const;\n inline uint32_t length() const;\n#endif // __cplusplus\n\n} wuffs_base__range_ie_u32;\n\nstatic inline wuffs_base__range_ie_u32 //\nwuffs_base__make_range_ie_u32(uint32_t min_incl, uint32_t max_excl) {\n wuffs_base__range_ie_u32 ret;\n ret.min_incl = min_incl;\n ret.max_excl = max_excl;\n return ret;\n}\n\nstatic inline bool //\nwuffs_base__range_ie_u32__is_empty(const wuffs_base__range_ie_u32* r) {\n return r->min_incl >= r->max_excl;\n}\n\nstatic inline bool //\nwuffs_base__range_ie_u32__eq" +
+ "uals(const wuffs_base__range_ie_u32* r,\n wuffs_base__range_ie_u32 s) {\n return (r->min_incl == s.min_incl && r->max_excl == s.max_excl) ||\n (wuffs_base__range_ie_u32__is_empty(r) &&\n wuffs_base__range_ie_u32__is_empty(&s));\n}\n\nstatic inline wuffs_base__range_ie_u32 //\nwuffs_base__range_ie_u32__intersect(const wuffs_base__range_ie_u32* r,\n wuffs_base__range_ie_u32 s) {\n wuffs_base__range_ie_u32 t;\n t.min_incl = wuffs_base__u32__max(r->min_incl, s.min_incl);\n t.max_excl = wuffs_base__u32__min(r->max_excl, s.max_excl);\n return t;\n}\n\nstatic inline wuffs_base__range_ie_u32 //\nwuffs_base__range_ie_u32__unite(const wuffs_base__range_ie_u32* r,\n wuffs_base__range_ie_u32 s) {\n if (wuffs_base__range_ie_u32__is_empty(r)) {\n return s;\n }\n if (wuffs_base__range_ie_u32__is_empty(&s)) {\n return *r;\n }\n wuffs_base__range_ie_u32 t;\n t.min_incl = wuffs_base__u32__min(r->min_incl, s.min_incl);\n " +
+ "t.max_excl = wuffs_base__u32__max(r->max_excl, s.max_excl);\n return t;\n}\n\nstatic inline bool //\nwuffs_base__range_ie_u32__contains(const wuffs_base__range_ie_u32* r,\n uint32_t x) {\n return (r->min_incl <= x) && (x < r->max_excl);\n}\n\nstatic inline bool //\nwuffs_base__range_ie_u32__contains_range(const wuffs_base__range_ie_u32* r,\n wuffs_base__range_ie_u32 s) {\n return wuffs_base__range_ie_u32__equals(\n &s, wuffs_base__range_ie_u32__intersect(r, s));\n}\n\nstatic inline uint32_t //\nwuffs_base__range_ie_u32__length(const wuffs_base__range_ie_u32* r) {\n return wuffs_base__u32__sat_sub(r->max_excl, r->min_incl);\n}\n\n#ifdef __cplusplus\n\ninline bool //\nwuffs_base__range_ie_u32::is_empty() const {\n return wuffs_base__range_ie_u32__is_empty(this);\n}\n\ninline bool //\nwuffs_base__range_ie_u32::equals(wuffs_base__range_ie_u32 s) const {\n return wuffs_base__range_ie_u32__equals(this, s);\n}\n\ninline wuffs_base__range_ie_u32 //\nwuffs_base__" +
+ "range_ie_u32::intersect(wuffs_base__range_ie_u32 s) const {\n return wuffs_base__range_ie_u32__intersect(this, s);\n}\n\ninline wuffs_base__range_ie_u32 //\nwuffs_base__range_ie_u32::unite(wuffs_base__range_ie_u32 s) const {\n return wuffs_base__range_ie_u32__unite(this, s);\n}\n\ninline bool //\nwuffs_base__range_ie_u32::contains(uint32_t x) const {\n return wuffs_base__range_ie_u32__contains(this, x);\n}\n\ninline bool //\nwuffs_base__range_ie_u32::contains_range(wuffs_base__range_ie_u32 s) const {\n return wuffs_base__range_ie_u32__contains_range(this, s);\n}\n\ninline uint32_t //\nwuffs_base__range_ie_u32::length() const {\n return wuffs_base__range_ie_u32__length(this);\n}\n\n#endif // __cplusplus\n\n" +
"" +
- "// --------\n\ntypedef struct wuffs_base__range_ii_u64__struct {\n uint64_t min_incl;\n uint64_t max_incl;\n\n#ifdef __cplusplus\n inline bool is_empty();\n inline bool equals(wuffs_base__range_ii_u64__struct s);\n inline wuffs_base__range_ii_u64__struct intersect(\n wuffs_base__range_ii_u64__struct s);\n inline wuffs_base__range_ii_u64__struct unite(\n wuffs_base__range_ii_u64__struct s);\n inline bool contains(uint64_t x);\n inline bool contains_range(wuffs_base__range_ii_u64__struct s);\n#endif // __cplusplus\n\n} wuffs_base__range_ii_u64;\n\nstatic inline wuffs_base__range_ii_u64 //\nwuffs_base__make_range_ii_u64(uint64_t min_incl, uint64_t max_incl) {\n wuffs_base__range_ii_u64 ret;\n ret.min_incl = min_incl;\n ret.max_incl = max_incl;\n return ret;\n}\n\nstatic inline bool //\nwuffs_base__range_ii_u64__is_empty(wuffs_base__range_ii_u64* r) {\n return r->min_incl > r->max_incl;\n}\n\nstatic inline bool //\nwuffs_base__range_ii_u64__equals(wuffs_base__range_ii_u64* r,\n wuffs_base" +
- "__range_ii_u64 s) {\n return (r->min_incl == s.min_incl && r->max_incl == s.max_incl) ||\n (wuffs_base__range_ii_u64__is_empty(r) &&\n wuffs_base__range_ii_u64__is_empty(&s));\n}\n\nstatic inline wuffs_base__range_ii_u64 //\nwuffs_base__range_ii_u64__intersect(wuffs_base__range_ii_u64* r,\n wuffs_base__range_ii_u64 s) {\n wuffs_base__range_ii_u64 t;\n t.min_incl = wuffs_base__u64__max(r->min_incl, s.min_incl);\n t.max_incl = wuffs_base__u64__min(r->max_incl, s.max_incl);\n return t;\n}\n\nstatic inline wuffs_base__range_ii_u64 //\nwuffs_base__range_ii_u64__unite(wuffs_base__range_ii_u64* r,\n wuffs_base__range_ii_u64 s) {\n if (wuffs_base__range_ii_u64__is_empty(r)) {\n return s;\n }\n if (wuffs_base__range_ii_u64__is_empty(&s)) {\n return *r;\n }\n wuffs_base__range_ii_u64 t;\n t.min_incl = wuffs_base__u64__min(r->min_incl, s.min_incl);\n t.max_incl = wuffs_base__u64__max(r->max_incl, s.max_incl);\n return t;\n}\n\nstatic inline bool " +
- "//\nwuffs_base__range_ii_u64__contains(wuffs_base__range_ii_u64* r, uint64_t x) {\n return (r->min_incl <= x) && (x <= r->max_incl);\n}\n\nstatic inline bool //\nwuffs_base__range_ii_u64__contains_range(wuffs_base__range_ii_u64* r,\n wuffs_base__range_ii_u64 s) {\n return wuffs_base__range_ii_u64__equals(\n &s, wuffs_base__range_ii_u64__intersect(r, s));\n}\n\n#ifdef __cplusplus\n\ninline bool //\nwuffs_base__range_ii_u64::is_empty() {\n return wuffs_base__range_ii_u64__is_empty(this);\n}\n\ninline bool //\nwuffs_base__range_ii_u64::equals(wuffs_base__range_ii_u64 s) {\n return wuffs_base__range_ii_u64__equals(this, s);\n}\n\ninline wuffs_base__range_ii_u64 //\nwuffs_base__range_ii_u64::intersect(wuffs_base__range_ii_u64 s) {\n return wuffs_base__range_ii_u64__intersect(this, s);\n}\n\ninline wuffs_base__range_ii_u64 //\nwuffs_base__range_ii_u64::unite(wuffs_base__range_ii_u64 s) {\n return wuffs_base__range_ii_u64__unite(this, s);\n}\n\ninline bool //\nwuffs_base__range_ii_u64::contains" +
- "(uint64_t x) {\n return wuffs_base__range_ii_u64__contains(this, x);\n}\n\ninline bool //\nwuffs_base__range_ii_u64::contains_range(wuffs_base__range_ii_u64 s) {\n return wuffs_base__range_ii_u64__contains_range(this, s);\n}\n\n#endif // __cplusplus\n\n" +
+ "// --------\n\ntypedef struct wuffs_base__range_ii_u64__struct {\n uint64_t min_incl;\n uint64_t max_incl;\n\n#ifdef __cplusplus\n inline bool is_empty() const;\n inline bool equals(wuffs_base__range_ii_u64__struct s) const;\n inline wuffs_base__range_ii_u64__struct intersect(\n wuffs_base__range_ii_u64__struct s) const;\n inline wuffs_base__range_ii_u64__struct unite(\n wuffs_base__range_ii_u64__struct s) const;\n inline bool contains(uint64_t x) const;\n inline bool contains_range(wuffs_base__range_ii_u64__struct s) const;\n#endif // __cplusplus\n\n} wuffs_base__range_ii_u64;\n\nstatic inline wuffs_base__range_ii_u64 //\nwuffs_base__make_range_ii_u64(uint64_t min_incl, uint64_t max_incl) {\n wuffs_base__range_ii_u64 ret;\n ret.min_incl = min_incl;\n ret.max_incl = max_incl;\n return ret;\n}\n\nstatic inline bool //\nwuffs_base__range_ii_u64__is_empty(const wuffs_base__range_ii_u64* r) {\n return r->min_incl > r->max_incl;\n}\n\nstatic inline bool //\nwuffs_base__range_ii_u64__equals(const wuffs_base__range_ii_u64" +
+ "* r,\n wuffs_base__range_ii_u64 s) {\n return (r->min_incl == s.min_incl && r->max_incl == s.max_incl) ||\n (wuffs_base__range_ii_u64__is_empty(r) &&\n wuffs_base__range_ii_u64__is_empty(&s));\n}\n\nstatic inline wuffs_base__range_ii_u64 //\nwuffs_base__range_ii_u64__intersect(const wuffs_base__range_ii_u64* r,\n wuffs_base__range_ii_u64 s) {\n wuffs_base__range_ii_u64 t;\n t.min_incl = wuffs_base__u64__max(r->min_incl, s.min_incl);\n t.max_incl = wuffs_base__u64__min(r->max_incl, s.max_incl);\n return t;\n}\n\nstatic inline wuffs_base__range_ii_u64 //\nwuffs_base__range_ii_u64__unite(const wuffs_base__range_ii_u64* r,\n wuffs_base__range_ii_u64 s) {\n if (wuffs_base__range_ii_u64__is_empty(r)) {\n return s;\n }\n if (wuffs_base__range_ii_u64__is_empty(&s)) {\n return *r;\n }\n wuffs_base__range_ii_u64 t;\n t.min_incl = wuffs_base__u64__min(r->min_incl, s.min_incl);\n t.max_incl = wuffs_base__u64__max(r" +
+ "->max_incl, s.max_incl);\n return t;\n}\n\nstatic inline bool //\nwuffs_base__range_ii_u64__contains(const wuffs_base__range_ii_u64* r,\n uint64_t x) {\n return (r->min_incl <= x) && (x <= r->max_incl);\n}\n\nstatic inline bool //\nwuffs_base__range_ii_u64__contains_range(const wuffs_base__range_ii_u64* r,\n wuffs_base__range_ii_u64 s) {\n return wuffs_base__range_ii_u64__equals(\n &s, wuffs_base__range_ii_u64__intersect(r, s));\n}\n\n#ifdef __cplusplus\n\ninline bool //\nwuffs_base__range_ii_u64::is_empty() const {\n return wuffs_base__range_ii_u64__is_empty(this);\n}\n\ninline bool //\nwuffs_base__range_ii_u64::equals(wuffs_base__range_ii_u64 s) const {\n return wuffs_base__range_ii_u64__equals(this, s);\n}\n\ninline wuffs_base__range_ii_u64 //\nwuffs_base__range_ii_u64::intersect(wuffs_base__range_ii_u64 s) const {\n return wuffs_base__range_ii_u64__intersect(this, s);\n}\n\ninline wuffs_base__range_ii_u64 //\nwuffs_base__range_ii_u64::unite(wuffs_bas" +
+ "e__range_ii_u64 s) const {\n return wuffs_base__range_ii_u64__unite(this, s);\n}\n\ninline bool //\nwuffs_base__range_ii_u64::contains(uint64_t x) const {\n return wuffs_base__range_ii_u64__contains(this, x);\n}\n\ninline bool //\nwuffs_base__range_ii_u64::contains_range(wuffs_base__range_ii_u64 s) const {\n return wuffs_base__range_ii_u64__contains_range(this, s);\n}\n\n#endif // __cplusplus\n\n" +
"" +
- "// --------\n\ntypedef struct wuffs_base__range_ie_u64__struct {\n uint64_t min_incl;\n uint64_t max_excl;\n\n#ifdef __cplusplus\n inline bool is_empty();\n inline bool equals(wuffs_base__range_ie_u64__struct s);\n inline wuffs_base__range_ie_u64__struct intersect(\n wuffs_base__range_ie_u64__struct s);\n inline wuffs_base__range_ie_u64__struct unite(\n wuffs_base__range_ie_u64__struct s);\n inline bool contains(uint64_t x);\n inline bool contains_range(wuffs_base__range_ie_u64__struct s);\n inline uint64_t length();\n#endif // __cplusplus\n\n} wuffs_base__range_ie_u64;\n\nstatic inline wuffs_base__range_ie_u64 //\nwuffs_base__make_range_ie_u64(uint64_t min_incl, uint64_t max_excl) {\n wuffs_base__range_ie_u64 ret;\n ret.min_incl = min_incl;\n ret.max_excl = max_excl;\n return ret;\n}\n\nstatic inline bool //\nwuffs_base__range_ie_u64__is_empty(wuffs_base__range_ie_u64* r) {\n return r->min_incl >= r->max_excl;\n}\n\nstatic inline bool //\nwuffs_base__range_ie_u64__equals(wuffs_base__range_ie_u64* r,\n " +
- " wuffs_base__range_ie_u64 s) {\n return (r->min_incl == s.min_incl && r->max_excl == s.max_excl) ||\n (wuffs_base__range_ie_u64__is_empty(r) &&\n wuffs_base__range_ie_u64__is_empty(&s));\n}\n\nstatic inline wuffs_base__range_ie_u64 //\nwuffs_base__range_ie_u64__intersect(wuffs_base__range_ie_u64* r,\n wuffs_base__range_ie_u64 s) {\n wuffs_base__range_ie_u64 t;\n t.min_incl = wuffs_base__u64__max(r->min_incl, s.min_incl);\n t.max_excl = wuffs_base__u64__min(r->max_excl, s.max_excl);\n return t;\n}\n\nstatic inline wuffs_base__range_ie_u64 //\nwuffs_base__range_ie_u64__unite(wuffs_base__range_ie_u64* r,\n wuffs_base__range_ie_u64 s) {\n if (wuffs_base__range_ie_u64__is_empty(r)) {\n return s;\n }\n if (wuffs_base__range_ie_u64__is_empty(&s)) {\n return *r;\n }\n wuffs_base__range_ie_u64 t;\n t.min_incl = wuffs_base__u64__min(r->min_incl, s.min_incl);\n t.max_excl = wuffs_base__u64__max(r->max_excl, s.max_excl);\n retu" +
- "rn t;\n}\n\nstatic inline bool //\nwuffs_base__range_ie_u64__contains(wuffs_base__range_ie_u64* r, uint64_t x) {\n return (r->min_incl <= x) && (x < r->max_excl);\n}\n\nstatic inline bool //\nwuffs_base__range_ie_u64__contains_range(wuffs_base__range_ie_u64* r,\n wuffs_base__range_ie_u64 s) {\n return wuffs_base__range_ie_u64__equals(\n &s, wuffs_base__range_ie_u64__intersect(r, s));\n}\n\nstatic inline uint64_t //\nwuffs_base__range_ie_u64__length(wuffs_base__range_ie_u64* r) {\n return wuffs_base__u64__sat_sub(r->max_excl, r->min_incl);\n}\n\n#ifdef __cplusplus\n\ninline bool //\nwuffs_base__range_ie_u64::is_empty() {\n return wuffs_base__range_ie_u64__is_empty(this);\n}\n\ninline bool //\nwuffs_base__range_ie_u64::equals(wuffs_base__range_ie_u64 s) {\n return wuffs_base__range_ie_u64__equals(this, s);\n}\n\ninline wuffs_base__range_ie_u64 //\nwuffs_base__range_ie_u64::intersect(wuffs_base__range_ie_u64 s) {\n return wuffs_base__range_ie_u64__intersect(this, s);\n}\n\ninline wuffs_base__" +
- "range_ie_u64 //\nwuffs_base__range_ie_u64::unite(wuffs_base__range_ie_u64 s) {\n return wuffs_base__range_ie_u64__unite(this, s);\n}\n\ninline bool //\nwuffs_base__range_ie_u64::contains(uint64_t x) {\n return wuffs_base__range_ie_u64__contains(this, x);\n}\n\ninline bool //\nwuffs_base__range_ie_u64::contains_range(wuffs_base__range_ie_u64 s) {\n return wuffs_base__range_ie_u64__contains_range(this, s);\n}\n\ninline uint64_t //\nwuffs_base__range_ie_u64::length() {\n return wuffs_base__range_ie_u64__length(this);\n}\n\n#endif // __cplusplus\n\n" +
+ "// --------\n\ntypedef struct wuffs_base__range_ie_u64__struct {\n uint64_t min_incl;\n uint64_t max_excl;\n\n#ifdef __cplusplus\n inline bool is_empty() const;\n inline bool equals(wuffs_base__range_ie_u64__struct s) const;\n inline wuffs_base__range_ie_u64__struct intersect(\n wuffs_base__range_ie_u64__struct s) const;\n inline wuffs_base__range_ie_u64__struct unite(\n wuffs_base__range_ie_u64__struct s) const;\n inline bool contains(uint64_t x) const;\n inline bool contains_range(wuffs_base__range_ie_u64__struct s) const;\n inline uint64_t length() const;\n#endif // __cplusplus\n\n} wuffs_base__range_ie_u64;\n\nstatic inline wuffs_base__range_ie_u64 //\nwuffs_base__make_range_ie_u64(uint64_t min_incl, uint64_t max_excl) {\n wuffs_base__range_ie_u64 ret;\n ret.min_incl = min_incl;\n ret.max_excl = max_excl;\n return ret;\n}\n\nstatic inline bool //\nwuffs_base__range_ie_u64__is_empty(const wuffs_base__range_ie_u64* r) {\n return r->min_incl >= r->max_excl;\n}\n\nstatic inline bool //\nwuffs_base__range_ie_u64__eq" +
+ "uals(const wuffs_base__range_ie_u64* r,\n wuffs_base__range_ie_u64 s) {\n return (r->min_incl == s.min_incl && r->max_excl == s.max_excl) ||\n (wuffs_base__range_ie_u64__is_empty(r) &&\n wuffs_base__range_ie_u64__is_empty(&s));\n}\n\nstatic inline wuffs_base__range_ie_u64 //\nwuffs_base__range_ie_u64__intersect(const wuffs_base__range_ie_u64* r,\n wuffs_base__range_ie_u64 s) {\n wuffs_base__range_ie_u64 t;\n t.min_incl = wuffs_base__u64__max(r->min_incl, s.min_incl);\n t.max_excl = wuffs_base__u64__min(r->max_excl, s.max_excl);\n return t;\n}\n\nstatic inline wuffs_base__range_ie_u64 //\nwuffs_base__range_ie_u64__unite(const wuffs_base__range_ie_u64* r,\n wuffs_base__range_ie_u64 s) {\n if (wuffs_base__range_ie_u64__is_empty(r)) {\n return s;\n }\n if (wuffs_base__range_ie_u64__is_empty(&s)) {\n return *r;\n }\n wuffs_base__range_ie_u64 t;\n t.min_incl = wuffs_base__u64__min(r->min_incl, s.min_incl);\n " +
+ "t.max_excl = wuffs_base__u64__max(r->max_excl, s.max_excl);\n return t;\n}\n\nstatic inline bool //\nwuffs_base__range_ie_u64__contains(const wuffs_base__range_ie_u64* r,\n uint64_t x) {\n return (r->min_incl <= x) && (x < r->max_excl);\n}\n\nstatic inline bool //\nwuffs_base__range_ie_u64__contains_range(const wuffs_base__range_ie_u64* r,\n wuffs_base__range_ie_u64 s) {\n return wuffs_base__range_ie_u64__equals(\n &s, wuffs_base__range_ie_u64__intersect(r, s));\n}\n\nstatic inline uint64_t //\nwuffs_base__range_ie_u64__length(const wuffs_base__range_ie_u64* r) {\n return wuffs_base__u64__sat_sub(r->max_excl, r->min_incl);\n}\n\n#ifdef __cplusplus\n\ninline bool //\nwuffs_base__range_ie_u64::is_empty() const {\n return wuffs_base__range_ie_u64__is_empty(this);\n}\n\ninline bool //\nwuffs_base__range_ie_u64::equals(wuffs_base__range_ie_u64 s) const {\n return wuffs_base__range_ie_u64__equals(this, s);\n}\n\ninline wuffs_base__range_ie_u64 //\nwuffs_base__" +
+ "range_ie_u64::intersect(wuffs_base__range_ie_u64 s) const {\n return wuffs_base__range_ie_u64__intersect(this, s);\n}\n\ninline wuffs_base__range_ie_u64 //\nwuffs_base__range_ie_u64::unite(wuffs_base__range_ie_u64 s) const {\n return wuffs_base__range_ie_u64__unite(this, s);\n}\n\ninline bool //\nwuffs_base__range_ie_u64::contains(uint64_t x) const {\n return wuffs_base__range_ie_u64__contains(this, x);\n}\n\ninline bool //\nwuffs_base__range_ie_u64::contains_range(wuffs_base__range_ie_u64 s) const {\n return wuffs_base__range_ie_u64__contains_range(this, s);\n}\n\ninline uint64_t //\nwuffs_base__range_ie_u64::length() const {\n return wuffs_base__range_ie_u64__length(this);\n}\n\n#endif // __cplusplus\n\n" +
"" +
- "// --------\n\n// wuffs_base__rect_ii_u32 is a rectangle (a 2-dimensional range) on the\n// integer grid. The \"ii\" means that the bounds are inclusive on the low end\n// and inclusive on the high end. It contains all points (x, y) such that\n// ((min_incl_x <= x) && (x <= max_incl_x)) and likewise for y.\n//\n// It is valid for min > max, in which case the rectangle is empty. There are\n// multiple representations of an empty rectangle.\n//\n// The X and Y axes increase right and down.\ntypedef struct wuffs_base__rect_ii_u32__struct {\n uint32_t min_incl_x;\n uint32_t min_incl_y;\n uint32_t max_incl_x;\n uint32_t max_incl_y;\n\n#ifdef __cplusplus\n inline bool is_empty();\n inline bool equals(wuffs_base__rect_ii_u32__struct s);\n inline wuffs_base__rect_ii_u32__struct intersect(\n wuffs_base__rect_ii_u32__struct s);\n inline wuffs_base__rect_ii_u32__struct unite(\n wuffs_base__rect_ii_u32__struct s);\n inline bool contains(uint32_t x, uint32_t y);\n inline bool contains_rect(wuffs_base__rect_ii_u32__struct s);\n#en" +
- "dif // __cplusplus\n\n} wuffs_base__rect_ii_u32;\n\nstatic inline wuffs_base__rect_ii_u32 //\nwuffs_base__make_rect_ii_u32(uint32_t min_incl_x,\n uint32_t min_incl_y,\n uint32_t max_incl_x,\n uint32_t max_incl_y) {\n wuffs_base__rect_ii_u32 ret;\n ret.min_incl_x = min_incl_x;\n ret.min_incl_y = min_incl_y;\n ret.max_incl_x = max_incl_x;\n ret.max_incl_y = max_incl_y;\n return ret;\n}\n\nstatic inline bool //\nwuffs_base__rect_ii_u32__is_empty(wuffs_base__rect_ii_u32* r) {\n return (r->min_incl_x > r->max_incl_x) || (r->min_incl_y > r->max_incl_y);\n}\n\nstatic inline bool //\nwuffs_base__rect_ii_u32__equals(wuffs_base__rect_ii_u32* r,\n wuffs_base__rect_ii_u32 s) {\n return (r->min_incl_x == s.min_incl_x && r->min_incl_y == s.min_incl_y &&\n r->max_incl_x == s.max_incl_x && r->max_incl_y == s.max_incl_y) ||\n (wuffs_base__rect_ii_u32__is_empty(r) &&\n wuffs_base__rect_ii_u32__is_empty(&" +
- "s));\n}\n\nstatic inline wuffs_base__rect_ii_u32 //\nwuffs_base__rect_ii_u32__intersect(wuffs_base__rect_ii_u32* r,\n wuffs_base__rect_ii_u32 s) {\n wuffs_base__rect_ii_u32 t;\n t.min_incl_x = wuffs_base__u32__max(r->min_incl_x, s.min_incl_x);\n t.min_incl_y = wuffs_base__u32__max(r->min_incl_y, s.min_incl_y);\n t.max_incl_x = wuffs_base__u32__min(r->max_incl_x, s.max_incl_x);\n t.max_incl_y = wuffs_base__u32__min(r->max_incl_y, s.max_incl_y);\n return t;\n}\n\nstatic inline wuffs_base__rect_ii_u32 //\nwuffs_base__rect_ii_u32__unite(wuffs_base__rect_ii_u32* r,\n wuffs_base__rect_ii_u32 s) {\n if (wuffs_base__rect_ii_u32__is_empty(r)) {\n return s;\n }\n if (wuffs_base__rect_ii_u32__is_empty(&s)) {\n return *r;\n }\n wuffs_base__rect_ii_u32 t;\n t.min_incl_x = wuffs_base__u32__min(r->min_incl_x, s.min_incl_x);\n t.min_incl_y = wuffs_base__u32__min(r->min_incl_y, s.min_incl_y);\n t.max_incl_x = wuffs_base__u32__max(r->max_incl_x, s.max_incl_x);\n t.max" +
- "_incl_y = wuffs_base__u32__max(r->max_incl_y, s.max_incl_y);\n return t;\n}\n\nstatic inline bool //\nwuffs_base__rect_ii_u32__contains(wuffs_base__rect_ii_u32* r,\n uint32_t x,\n uint32_t y) {\n return (r->min_incl_x <= x) && (x <= r->max_incl_x) && (r->min_incl_y <= y) &&\n (y <= r->max_incl_y);\n}\n\nstatic inline bool //\nwuffs_base__rect_ii_u32__contains_rect(wuffs_base__rect_ii_u32* r,\n wuffs_base__rect_ii_u32 s) {\n return wuffs_base__rect_ii_u32__equals(\n &s, wuffs_base__rect_ii_u32__intersect(r, s));\n}\n\n#ifdef __cplusplus\n\ninline bool //\nwuffs_base__rect_ii_u32::is_empty() {\n return wuffs_base__rect_ii_u32__is_empty(this);\n}\n\ninline bool //\nwuffs_base__rect_ii_u32::equals(wuffs_base__rect_ii_u32 s) {\n return wuffs_base__rect_ii_u32__equals(this, s);\n}\n\ninline wuffs_base__rect_ii_u32 //\nwuffs_base__rect_ii_u32::intersect(wuffs_base__rect_ii_u32 s) {\n return wuffs_base__rect_ii_u32__interse" +
- "ct(this, s);\n}\n\ninline wuffs_base__rect_ii_u32 //\nwuffs_base__rect_ii_u32::unite(wuffs_base__rect_ii_u32 s) {\n return wuffs_base__rect_ii_u32__unite(this, s);\n}\n\ninline bool //\nwuffs_base__rect_ii_u32::contains(uint32_t x, uint32_t y) {\n return wuffs_base__rect_ii_u32__contains(this, x, y);\n}\n\ninline bool //\nwuffs_base__rect_ii_u32::contains_rect(wuffs_base__rect_ii_u32 s) {\n return wuffs_base__rect_ii_u32__contains_rect(this, s);\n}\n\n#endif // __cplusplus\n\n" +
+ "// --------\n\n// wuffs_base__rect_ii_u32 is a rectangle (a 2-dimensional range) on the\n// integer grid. The \"ii\" means that the bounds are inclusive on the low end\n// and inclusive on the high end. It contains all points (x, y) such that\n// ((min_incl_x <= x) && (x <= max_incl_x)) and likewise for y.\n//\n// It is valid for min > max, in which case the rectangle is empty. There are\n// multiple representations of an empty rectangle.\n//\n// The X and Y axes increase right and down.\ntypedef struct wuffs_base__rect_ii_u32__struct {\n uint32_t min_incl_x;\n uint32_t min_incl_y;\n uint32_t max_incl_x;\n uint32_t max_incl_y;\n\n#ifdef __cplusplus\n inline bool is_empty() const;\n inline bool equals(wuffs_base__rect_ii_u32__struct s) const;\n inline wuffs_base__rect_ii_u32__struct intersect(\n wuffs_base__rect_ii_u32__struct s) const;\n inline wuffs_base__rect_ii_u32__struct unite(\n wuffs_base__rect_ii_u32__struct s) const;\n inline bool contains(uint32_t x, uint32_t y) const;\n inline bool contains_rect(wuffs_bas" +
+ "e__rect_ii_u32__struct s) const;\n#endif // __cplusplus\n\n} wuffs_base__rect_ii_u32;\n\nstatic inline wuffs_base__rect_ii_u32 //\nwuffs_base__make_rect_ii_u32(uint32_t min_incl_x,\n uint32_t min_incl_y,\n uint32_t max_incl_x,\n uint32_t max_incl_y) {\n wuffs_base__rect_ii_u32 ret;\n ret.min_incl_x = min_incl_x;\n ret.min_incl_y = min_incl_y;\n ret.max_incl_x = max_incl_x;\n ret.max_incl_y = max_incl_y;\n return ret;\n}\n\nstatic inline bool //\nwuffs_base__rect_ii_u32__is_empty(const wuffs_base__rect_ii_u32* r) {\n return (r->min_incl_x > r->max_incl_x) || (r->min_incl_y > r->max_incl_y);\n}\n\nstatic inline bool //\nwuffs_base__rect_ii_u32__equals(const wuffs_base__rect_ii_u32* r,\n wuffs_base__rect_ii_u32 s) {\n return (r->min_incl_x == s.min_incl_x && r->min_incl_y == s.min_incl_y &&\n r->max_incl_x == s.max_incl_x && r->max_incl_y == s.max_incl_y) ||\n (wuffs_base__rect_ii_u32__is_empty(r) " +
+ "&&\n wuffs_base__rect_ii_u32__is_empty(&s));\n}\n\nstatic inline wuffs_base__rect_ii_u32 //\nwuffs_base__rect_ii_u32__intersect(const wuffs_base__rect_ii_u32* r,\n wuffs_base__rect_ii_u32 s) {\n wuffs_base__rect_ii_u32 t;\n t.min_incl_x = wuffs_base__u32__max(r->min_incl_x, s.min_incl_x);\n t.min_incl_y = wuffs_base__u32__max(r->min_incl_y, s.min_incl_y);\n t.max_incl_x = wuffs_base__u32__min(r->max_incl_x, s.max_incl_x);\n t.max_incl_y = wuffs_base__u32__min(r->max_incl_y, s.max_incl_y);\n return t;\n}\n\nstatic inline wuffs_base__rect_ii_u32 //\nwuffs_base__rect_ii_u32__unite(const wuffs_base__rect_ii_u32* r,\n wuffs_base__rect_ii_u32 s) {\n if (wuffs_base__rect_ii_u32__is_empty(r)) {\n return s;\n }\n if (wuffs_base__rect_ii_u32__is_empty(&s)) {\n return *r;\n }\n wuffs_base__rect_ii_u32 t;\n t.min_incl_x = wuffs_base__u32__min(r->min_incl_x, s.min_incl_x);\n t.min_incl_y = wuffs_base__u32__min(r->min_incl_y, s.min_incl_y);\n t.max_incl_x " +
+ "= wuffs_base__u32__max(r->max_incl_x, s.max_incl_x);\n t.max_incl_y = wuffs_base__u32__max(r->max_incl_y, s.max_incl_y);\n return t;\n}\n\nstatic inline bool //\nwuffs_base__rect_ii_u32__contains(const wuffs_base__rect_ii_u32* r,\n uint32_t x,\n uint32_t y) {\n return (r->min_incl_x <= x) && (x <= r->max_incl_x) && (r->min_incl_y <= y) &&\n (y <= r->max_incl_y);\n}\n\nstatic inline bool //\nwuffs_base__rect_ii_u32__contains_rect(const wuffs_base__rect_ii_u32* r,\n wuffs_base__rect_ii_u32 s) {\n return wuffs_base__rect_ii_u32__equals(\n &s, wuffs_base__rect_ii_u32__intersect(r, s));\n}\n\n#ifdef __cplusplus\n\ninline bool //\nwuffs_base__rect_ii_u32::is_empty() const {\n return wuffs_base__rect_ii_u32__is_empty(this);\n}\n\ninline bool //\nwuffs_base__rect_ii_u32::equals(wuffs_base__rect_ii_u32 s) const {\n return wuffs_base__rect_ii_u32__equals(this, s);\n}\n\ninline wuffs_base__rect_ii_u32 //\nwuffs_base__rect_ii_u" +
+ "32::intersect(wuffs_base__rect_ii_u32 s) const {\n return wuffs_base__rect_ii_u32__intersect(this, s);\n}\n\ninline wuffs_base__rect_ii_u32 //\nwuffs_base__rect_ii_u32::unite(wuffs_base__rect_ii_u32 s) const {\n return wuffs_base__rect_ii_u32__unite(this, s);\n}\n\ninline bool //\nwuffs_base__rect_ii_u32::contains(uint32_t x, uint32_t y) const {\n return wuffs_base__rect_ii_u32__contains(this, x, y);\n}\n\ninline bool //\nwuffs_base__rect_ii_u32::contains_rect(wuffs_base__rect_ii_u32 s) const {\n return wuffs_base__rect_ii_u32__contains_rect(this, s);\n}\n\n#endif // __cplusplus\n\n" +
"" +
- "// --------\n\n// wuffs_base__rect_ie_u32 is a rectangle (a 2-dimensional range) on the\n// integer grid. The \"ie\" means that the bounds are inclusive on the low end\n// and exclusive on the high end. It contains all points (x, y) such that\n// ((min_incl_x <= x) && (x < max_excl_x)) and likewise for y.\n//\n// It is valid for min >= max, in which case the rectangle is empty. There are\n// multiple representations of an empty rectangle, including a value with all\n// fields zero.\n//\n// The X and Y axes increase right and down.\ntypedef struct wuffs_base__rect_ie_u32__struct {\n uint32_t min_incl_x;\n uint32_t min_incl_y;\n uint32_t max_excl_x;\n uint32_t max_excl_y;\n\n#ifdef __cplusplus\n inline bool is_empty();\n inline bool equals(wuffs_base__rect_ie_u32__struct s);\n inline wuffs_base__rect_ie_u32__struct intersect(\n wuffs_base__rect_ie_u32__struct s);\n inline wuffs_base__rect_ie_u32__struct unite(\n wuffs_base__rect_ie_u32__struct s);\n inline bool contains(uint32_t x, uint32_t y);\n inline bool contains_r" +
- "ect(wuffs_base__rect_ie_u32__struct s);\n inline uint32_t width();\n inline uint32_t height();\n#endif // __cplusplus\n\n} wuffs_base__rect_ie_u32;\n\nstatic inline wuffs_base__rect_ie_u32 //\nwuffs_base__make_rect_ie_u32(uint32_t min_incl_x,\n uint32_t min_incl_y,\n uint32_t max_excl_x,\n uint32_t max_excl_y) {\n wuffs_base__rect_ie_u32 ret;\n ret.min_incl_x = min_incl_x;\n ret.min_incl_y = min_incl_y;\n ret.max_excl_x = max_excl_x;\n ret.max_excl_y = max_excl_y;\n return ret;\n}\n\nstatic inline bool //\nwuffs_base__rect_ie_u32__is_empty(wuffs_base__rect_ie_u32* r) {\n return (r->min_incl_x >= r->max_excl_x) || (r->min_incl_y >= r->max_excl_y);\n}\n\nstatic inline bool //\nwuffs_base__rect_ie_u32__equals(wuffs_base__rect_ie_u32* r,\n wuffs_base__rect_ie_u32 s) {\n return (r->min_incl_x == s.min_incl_x && r->min_incl_y == s.min_incl_y &&\n r->max_excl_x == s.max_excl_x && r->max_excl_y == s.max_excl_y" +
- ") ||\n (wuffs_base__rect_ie_u32__is_empty(r) &&\n wuffs_base__rect_ie_u32__is_empty(&s));\n}\n\nstatic inline wuffs_base__rect_ie_u32 //\nwuffs_base__rect_ie_u32__intersect(wuffs_base__rect_ie_u32* r,\n wuffs_base__rect_ie_u32 s) {\n wuffs_base__rect_ie_u32 t;\n t.min_incl_x = wuffs_base__u32__max(r->min_incl_x, s.min_incl_x);\n t.min_incl_y = wuffs_base__u32__max(r->min_incl_y, s.min_incl_y);\n t.max_excl_x = wuffs_base__u32__min(r->max_excl_x, s.max_excl_x);\n t.max_excl_y = wuffs_base__u32__min(r->max_excl_y, s.max_excl_y);\n return t;\n}\n\nstatic inline wuffs_base__rect_ie_u32 //\nwuffs_base__rect_ie_u32__unite(wuffs_base__rect_ie_u32* r,\n wuffs_base__rect_ie_u32 s) {\n if (wuffs_base__rect_ie_u32__is_empty(r)) {\n return s;\n }\n if (wuffs_base__rect_ie_u32__is_empty(&s)) {\n return *r;\n }\n wuffs_base__rect_ie_u32 t;\n t.min_incl_x = wuffs_base__u32__min(r->min_incl_x, s.min_incl_x);\n t.min_incl_y = wuffs_base__u32__min(r->mi" +
- "n_incl_y, s.min_incl_y);\n t.max_excl_x = wuffs_base__u32__max(r->max_excl_x, s.max_excl_x);\n t.max_excl_y = wuffs_base__u32__max(r->max_excl_y, s.max_excl_y);\n return t;\n}\n\nstatic inline bool //\nwuffs_base__rect_ie_u32__contains(wuffs_base__rect_ie_u32* r,\n uint32_t x,\n uint32_t y) {\n return (r->min_incl_x <= x) && (x < r->max_excl_x) && (r->min_incl_y <= y) &&\n (y < r->max_excl_y);\n}\n\nstatic inline bool //\nwuffs_base__rect_ie_u32__contains_rect(wuffs_base__rect_ie_u32* r,\n wuffs_base__rect_ie_u32 s) {\n return wuffs_base__rect_ie_u32__equals(\n &s, wuffs_base__rect_ie_u32__intersect(r, s));\n}\n\nstatic inline uint32_t //\nwuffs_base__rect_ie_u32__width(wuffs_base__rect_ie_u32* r) {\n return wuffs_base__u32__sat_sub(r->max_excl_x, r->min_incl_x);\n}\n\nstatic inline uint32_t //\nwuffs_base__rect_ie_u32__height(wuffs_base__rect_ie_u32* r) {\n return wuffs_base__u32__sat_sub(r->max_excl_y, r->min" +
- "_incl_y);\n}\n\n#ifdef __cplusplus\n\ninline bool //\nwuffs_base__rect_ie_u32::is_empty() {\n return wuffs_base__rect_ie_u32__is_empty(this);\n}\n\ninline bool //\nwuffs_base__rect_ie_u32::equals(wuffs_base__rect_ie_u32 s) {\n return wuffs_base__rect_ie_u32__equals(this, s);\n}\n\ninline wuffs_base__rect_ie_u32 //\nwuffs_base__rect_ie_u32::intersect(wuffs_base__rect_ie_u32 s) {\n return wuffs_base__rect_ie_u32__intersect(this, s);\n}\n\ninline wuffs_base__rect_ie_u32 //\nwuffs_base__rect_ie_u32::unite(wuffs_base__rect_ie_u32 s) {\n return wuffs_base__rect_ie_u32__unite(this, s);\n}\n\ninline bool //\nwuffs_base__rect_ie_u32::contains(uint32_t x, uint32_t y) {\n return wuffs_base__rect_ie_u32__contains(this, x, y);\n}\n\ninline bool //\nwuffs_base__rect_ie_u32::contains_rect(wuffs_base__rect_ie_u32 s) {\n return wuffs_base__rect_ie_u32__contains_rect(this, s);\n}\n\ninline uint32_t //\nwuffs_base__rect_ie_u32::width() {\n return wuffs_base__rect_ie_u32__width(this);\n}\n\ninline uint32_t //\nwuffs_base__rect_ie_u32::height() {\n return" +
- " wuffs_base__rect_ie_u32__height(this);\n}\n\n#endif // __cplusplus\n" +
+ "// --------\n\n// wuffs_base__rect_ie_u32 is a rectangle (a 2-dimensional range) on the\n// integer grid. The \"ie\" means that the bounds are inclusive on the low end\n// and exclusive on the high end. It contains all points (x, y) such that\n// ((min_incl_x <= x) && (x < max_excl_x)) and likewise for y.\n//\n// It is valid for min >= max, in which case the rectangle is empty. There are\n// multiple representations of an empty rectangle, including a value with all\n// fields zero.\n//\n// The X and Y axes increase right and down.\ntypedef struct wuffs_base__rect_ie_u32__struct {\n uint32_t min_incl_x;\n uint32_t min_incl_y;\n uint32_t max_excl_x;\n uint32_t max_excl_y;\n\n#ifdef __cplusplus\n inline bool is_empty() const;\n inline bool equals(wuffs_base__rect_ie_u32__struct s) const;\n inline wuffs_base__rect_ie_u32__struct intersect(\n wuffs_base__rect_ie_u32__struct s) const;\n inline wuffs_base__rect_ie_u32__struct unite(\n wuffs_base__rect_ie_u32__struct s) const;\n inline bool contains(uint32_t x, uint32_t y) c" +
+ "onst;\n inline bool contains_rect(wuffs_base__rect_ie_u32__struct s) const;\n inline uint32_t width() const;\n inline uint32_t height() const;\n#endif // __cplusplus\n\n} wuffs_base__rect_ie_u32;\n\nstatic inline wuffs_base__rect_ie_u32 //\nwuffs_base__make_rect_ie_u32(uint32_t min_incl_x,\n uint32_t min_incl_y,\n uint32_t max_excl_x,\n uint32_t max_excl_y) {\n wuffs_base__rect_ie_u32 ret;\n ret.min_incl_x = min_incl_x;\n ret.min_incl_y = min_incl_y;\n ret.max_excl_x = max_excl_x;\n ret.max_excl_y = max_excl_y;\n return ret;\n}\n\nstatic inline bool //\nwuffs_base__rect_ie_u32__is_empty(const wuffs_base__rect_ie_u32* r) {\n return (r->min_incl_x >= r->max_excl_x) || (r->min_incl_y >= r->max_excl_y);\n}\n\nstatic inline bool //\nwuffs_base__rect_ie_u32__equals(const wuffs_base__rect_ie_u32* r,\n wuffs_base__rect_ie_u32 s) {\n return (r->min_incl_x == s.min_incl_x && r->min_incl_y == s.min_incl_y &&\n r-" +
+ ">max_excl_x == s.max_excl_x && r->max_excl_y == s.max_excl_y) ||\n (wuffs_base__rect_ie_u32__is_empty(r) &&\n wuffs_base__rect_ie_u32__is_empty(&s));\n}\n\nstatic inline wuffs_base__rect_ie_u32 //\nwuffs_base__rect_ie_u32__intersect(const wuffs_base__rect_ie_u32* r,\n wuffs_base__rect_ie_u32 s) {\n wuffs_base__rect_ie_u32 t;\n t.min_incl_x = wuffs_base__u32__max(r->min_incl_x, s.min_incl_x);\n t.min_incl_y = wuffs_base__u32__max(r->min_incl_y, s.min_incl_y);\n t.max_excl_x = wuffs_base__u32__min(r->max_excl_x, s.max_excl_x);\n t.max_excl_y = wuffs_base__u32__min(r->max_excl_y, s.max_excl_y);\n return t;\n}\n\nstatic inline wuffs_base__rect_ie_u32 //\nwuffs_base__rect_ie_u32__unite(const wuffs_base__rect_ie_u32* r,\n wuffs_base__rect_ie_u32 s) {\n if (wuffs_base__rect_ie_u32__is_empty(r)) {\n return s;\n }\n if (wuffs_base__rect_ie_u32__is_empty(&s)) {\n return *r;\n }\n wuffs_base__rect_ie_u32 t;\n t.min_incl_x = wuffs_base__u32__min(r" +
+ "->min_incl_x, s.min_incl_x);\n t.min_incl_y = wuffs_base__u32__min(r->min_incl_y, s.min_incl_y);\n t.max_excl_x = wuffs_base__u32__max(r->max_excl_x, s.max_excl_x);\n t.max_excl_y = wuffs_base__u32__max(r->max_excl_y, s.max_excl_y);\n return t;\n}\n\nstatic inline bool //\nwuffs_base__rect_ie_u32__contains(const wuffs_base__rect_ie_u32* r,\n uint32_t x,\n uint32_t y) {\n return (r->min_incl_x <= x) && (x < r->max_excl_x) && (r->min_incl_y <= y) &&\n (y < r->max_excl_y);\n}\n\nstatic inline bool //\nwuffs_base__rect_ie_u32__contains_rect(const wuffs_base__rect_ie_u32* r,\n wuffs_base__rect_ie_u32 s) {\n return wuffs_base__rect_ie_u32__equals(\n &s, wuffs_base__rect_ie_u32__intersect(r, s));\n}\n\nstatic inline uint32_t //\nwuffs_base__rect_ie_u32__width(const wuffs_base__rect_ie_u32* r) {\n return wuffs_base__u32__sat_sub(r->max_excl_x, r->min_incl_x);\n}\n\nstatic inline uint32_t //\nwuffs_base__rect_ie_u32__he" +
+ "ight(const wuffs_base__rect_ie_u32* r) {\n return wuffs_base__u32__sat_sub(r->max_excl_y, r->min_incl_y);\n}\n\n#ifdef __cplusplus\n\ninline bool //\nwuffs_base__rect_ie_u32::is_empty() const {\n return wuffs_base__rect_ie_u32__is_empty(this);\n}\n\ninline bool //\nwuffs_base__rect_ie_u32::equals(wuffs_base__rect_ie_u32 s) const {\n return wuffs_base__rect_ie_u32__equals(this, s);\n}\n\ninline wuffs_base__rect_ie_u32 //\nwuffs_base__rect_ie_u32::intersect(wuffs_base__rect_ie_u32 s) const {\n return wuffs_base__rect_ie_u32__intersect(this, s);\n}\n\ninline wuffs_base__rect_ie_u32 //\nwuffs_base__rect_ie_u32::unite(wuffs_base__rect_ie_u32 s) const {\n return wuffs_base__rect_ie_u32__unite(this, s);\n}\n\ninline bool //\nwuffs_base__rect_ie_u32::contains(uint32_t x, uint32_t y) const {\n return wuffs_base__rect_ie_u32__contains(this, x, y);\n}\n\ninline bool //\nwuffs_base__rect_ie_u32::contains_rect(wuffs_base__rect_ie_u32 s) const {\n return wuffs_base__rect_ie_u32__contains_rect(this, s);\n}\n\ninline uint32_t //\nwuffs_base__rect_" +
+ "ie_u32::width() const {\n return wuffs_base__rect_ie_u32__width(this);\n}\n\ninline uint32_t //\nwuffs_base__rect_ie_u32::height() const {\n return wuffs_base__rect_ie_u32__height(this);\n}\n\n#endif // __cplusplus\n" +
""
const baseCopyright = "" +
diff --git a/internal/cgen/expr.go b/internal/cgen/expr.go
index 3315531..4a326c8 100644
--- a/internal/cgen/expr.go
+++ b/internal/cgen/expr.go
@@ -461,8 +461,8 @@
t.IDU32: "uint32_t",
t.IDU64: "uint64_t",
t.IDBool: "bool",
- t.IDIOReader: "wuffs_base__io_reader",
- t.IDIOWriter: "wuffs_base__io_writer",
+ t.IDIOReader: "wuffs_base__io_buffer*",
+ t.IDIOWriter: "wuffs_base__io_buffer*",
}
const noSuchCOperator = " no_such_C_operator "
diff --git a/internal/cgen/func.go b/internal/cgen/func.go
index 1030f78..3f8daf5 100644
--- a/internal/cgen/func.go
+++ b/internal/cgen/func.go
@@ -368,10 +368,12 @@
b.writes("goto suspend;suspend:") // The goto avoids the "unused label" warning.
- b.printf("self->private_impl.%s%s[0] = coro_susp_point;\n",
+ b.printf("self->private_impl.%s%s[0] = "+
+ "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 = %d;\n", g.currFunk.coroID)
+ b.printf("self->private_impl.active_coroutine = "+
+ "wuffs_base__status__is_suspension(status) ? %d : 0;\n", g.currFunk.coroID)
}
if err := g.writeResumeSuspend(b, &g.currFunk, true); err != nil {
return err
@@ -418,13 +420,10 @@
for _, o := range n.In().Fields() {
o := o.AsField()
oTyp := o.XType()
- if oTyp.Decorator() != t.IDPtr && !oTyp.IsRefined() {
- // TODO: Also check elements, for array-typed arguments.
- continue
- }
+ // TODO: Also check elements, for array-typed arguments.
switch {
- case oTyp.Decorator() == t.IDPtr:
+ case oTyp.IsIOType() || (oTyp.Decorator() == t.IDPtr):
checks = append(checks, fmt.Sprintf("!%s%s", aPrefix, o.Name().Str(g.tm)))
case oTyp.IsRefined():
diff --git a/internal/cgen/resume.go b/internal/cgen/resume.go
index 09bf05c..1ade456 100644
--- a/internal/cgen/resume.go
+++ b/internal/cgen/resume.go
@@ -236,8 +236,14 @@
}
func (h *resumabilityHelper) doAssign(r resumabilities, n *a.Assign, depth uint32) error {
- if err := h.doExpr(r, n.RHS()); err != nil {
- return err
+ if n.Operator() == t.IDEqQuestion {
+ if err := h.doExpr1(r, n.RHS(), subExprFilterNone, 0); err != nil {
+ return err
+ }
+ } else {
+ if err := h.doExpr(r, n.RHS()); err != nil {
+ return err
+ }
}
if n.LHS() == nil {
@@ -302,12 +308,14 @@
}
return nil
}
+ panic("TODO: unreachable; delete")
processOnlySubExprs = true
case subExprFilterAfterCoroutine:
if n.Effect().Coroutine() {
return nil
}
+ panic("TODO: unreachable; delete")
}
}
diff --git a/internal/cgen/statement.go b/internal/cgen/statement.go
index 6fca3e8..7a57e9d 100644
--- a/internal/cgen/statement.go
+++ b/internal/cgen/statement.go
@@ -267,8 +267,8 @@
cTyp = "writer"
}
name := e.Ident().Str(g.tm)
- b.printf("wuffs_base__io_%s %s%d_%s%s = %s%s;\n",
- cTyp, oPrefix, ioBindNum, prefix, name, prefix, name)
+ b.printf("wuffs_base__io_buffer* %s%d_%s%s = %s%s;\n",
+ oPrefix, ioBindNum, prefix, name, prefix, name)
// TODO: save / restore all iop vars, not just for local IO vars? How
// does this work if the io_bind body advances these pointers, either
@@ -277,25 +277,24 @@
b.printf("uint8_t *%s%d_%s%s%s = %s%s%s;\n",
oPrefix, ioBindNum, iopPrefix, prefix, name, iopPrefix, prefix, name)
b.printf("uint8_t *%s%d_%s%s%s = %s%s%s;\n",
+ oPrefix, ioBindNum, io0Prefix, prefix, name, io0Prefix, prefix, name)
+ b.printf("uint8_t *%s%d_%s%s%s = %s%s%s;\n",
oPrefix, ioBindNum, io1Prefix, prefix, name, io1Prefix, prefix, name)
+ b.printf("uint8_t *%s%d_%s%s%s = %s%s%s;\n",
+ oPrefix, ioBindNum, io2Prefix, prefix, name, io2Prefix, prefix, name)
}
if n.Keyword() == t.IDIOBind {
- b.printf("wuffs_base__io_%s__set(&%s%s, &u_%s, &iop_%s%s, &io1_%s%s,",
- cTyp, prefix, name, name, prefix, name, prefix, name)
+ b.printf("%s%s = wuffs_base__io_%s__set(&%s%s, &%s%s%s, &%s%s%s, &%s%s%s, &%s%s%s,",
+ prefix, name, cTyp, uPrefix, name, iopPrefix, prefix, name,
+ io0Prefix, prefix, name, io1Prefix, prefix, name, io2Prefix, prefix, name)
if err := g.writeExpr(b, n.Arg1(), 0); err != nil {
return err
}
b.writes(");\n")
} else {
- // TODO: restrict (in the type checker or parser) that e is
- // args.foo?
- b.printf("wuffs_base__io_%s__set_limit(&%s%s, iop_%s%s,\n", cTyp, prefix, name, prefix, name)
- if err := g.writeExpr(b, n.Arg1(), 0); err != nil {
- return err
- }
- b.writes(");\n")
+ return fmt.Errorf("TODO: implement io_limit (or remove it from the parser)")
}
}
@@ -318,7 +317,11 @@
b.printf("%s%s%s = %s%d_%s%s%s;\n",
iopPrefix, prefix, name, oPrefix, ioBindNum, iopPrefix, prefix, name)
b.printf("%s%s%s = %s%d_%s%s%s;\n",
+ io0Prefix, prefix, name, oPrefix, ioBindNum, io0Prefix, prefix, name)
+ b.printf("%s%s%s = %s%d_%s%s%s;\n",
io1Prefix, prefix, name, oPrefix, ioBindNum, io1Prefix, prefix, name)
+ b.printf("%s%s%s = %s%d_%s%s%s;\n",
+ io2Prefix, prefix, name, oPrefix, ioBindNum, io2Prefix, prefix, name)
}
}
b.writes("}\n")
diff --git a/internal/cgen/var.go b/internal/cgen/var.go
index 5a2cb50..9263d1c 100644
--- a/internal/cgen/var.go
+++ b/internal/cgen/var.go
@@ -95,37 +95,33 @@
}
preName := prefix + name.Str(g.tm)
- i0, i1 := "meta.ri", "meta.wi"
+ i1, i2 := "meta.ri", "meta.wi"
if typ.QID()[1] == t.IDIOWriter {
- i0, i1 = "meta.wi", "data.len"
+ i1, i2 = "meta.wi", "data.len"
}
if header {
b.printf("uint8_t* %s%s = NULL;", iopPrefix, preName)
b.printf("uint8_t* %s%s WUFFS_BASE__POTENTIALLY_UNUSED = NULL;", io0Prefix, preName)
b.printf("uint8_t* %s%s WUFFS_BASE__POTENTIALLY_UNUSED = NULL;", io1Prefix, preName)
+ b.printf("uint8_t* %s%s WUFFS_BASE__POTENTIALLY_UNUSED = NULL;", io2Prefix, preName)
}
- b.printf("if (%s.private_impl.buf) {", preName)
-
- b.printf("%s%s = %s.private_impl.buf->data.ptr + %s.private_impl.buf->%s;",
- iopPrefix, preName, preName, preName, i0)
+ b.printf("if (%s) {", preName)
if header {
- b.printf("if (!%s.private_impl.mark) {", preName)
- b.printf("%s.private_impl.mark = %s%s;", preName, iopPrefix, preName)
- b.printf("%s.private_impl.limit = %s.private_impl.buf->data.ptr + %s.private_impl.buf->%s;",
- preName, preName, preName, i1)
- b.printf("}\n")
+ b.printf("%s%s = %s->data.ptr;", io0Prefix, preName, preName)
+ b.printf("%s%s = %s%s + %s->%s;", io1Prefix, preName, io0Prefix, preName, preName, i1)
+ b.printf("%s%s = %s%s;", iopPrefix, preName, io1Prefix, preName)
+ b.printf("%s%s = %s%s + %s->%s;", io2Prefix, preName, io0Prefix, preName, preName, i2)
if typ.QID()[1] == t.IDIOWriter {
- b.printf("if (%s.private_impl.buf->meta.closed) {", preName)
- b.printf("%s.private_impl.limit = %s%s;", preName, iopPrefix, preName)
+ b.printf("if (%s->meta.closed) {", preName)
+ b.printf("%s%s = %s%s;", io2Prefix, preName, iopPrefix, preName)
b.printf("}\n")
}
-
- b.printf("%s%s = %s.private_impl.mark;", io0Prefix, preName, preName)
- b.printf("%s%s = %s.private_impl.limit;", io1Prefix, preName, preName)
+ } else {
+ b.printf("%s%s = %s->data.ptr + %s->%s;", iopPrefix, preName, preName, preName, i1)
}
b.printf("}\n")
@@ -158,15 +154,13 @@
}
preName := prefix + name.Str(g.tm)
- i0 := "ri"
+ index := "ri"
if typ.QID()[1] == t.IDIOWriter {
- i0 = "wi"
+ index = "wi"
}
- b.printf("if (%s.private_impl.buf) {", preName)
- b.printf("%s.private_impl.buf->meta.%s = ((size_t)(%s%s - %s.private_impl.buf->data.ptr));",
- preName, i0, iopPrefix, preName, preName)
- b.printf("}\n")
+ b.printf("if (%s) { %s->meta.%s = ((size_t)(%s%s - %s->data.ptr)); }\n",
+ preName, preName, index, iopPrefix, preName, preName)
return nil
}
@@ -278,6 +272,11 @@
}
name := n.Name().Str(g.tm)
+
+ if typ.IsIOType() {
+ b.printf("wuffs_base__io_buffer %s%s = wuffs_base__null_io_buffer();\n", uPrefix, name)
+ }
+
if err := g.writeCTypeName(b, typ, vPrefix, name); err != nil {
return err
}
@@ -290,22 +289,16 @@
} else if typ.IsStatus() {
b.writes(" = NULL;\n")
} else if typ.IsIOType() {
- typName := "reader"
- if typ.QID()[1] == t.IDIOWriter {
- typName = "writer"
- }
- b.printf(" = wuffs_base__null_io_%s();\n", typName)
+ b.printf(" = &%s%s;\n", uPrefix, name)
} else {
b.writes(" = {0};\n")
}
if typ.IsIOType() {
- b.printf("wuffs_base__io_buffer %s%s WUFFS_BASE__POTENTIALLY_UNUSED = "+
- "wuffs_base__null_io_buffer();\n", uPrefix, name)
- preName := vPrefix + name
- // TODO: io0_etc variables?
- b.printf("uint8_t* %s%s WUFFS_BASE__POTENTIALLY_UNUSED = NULL;\n", iopPrefix, preName)
- b.printf("uint8_t* %s%s WUFFS_BASE__POTENTIALLY_UNUSED = NULL;\n", io1Prefix, preName)
+ b.printf("uint8_t* %s%s%s WUFFS_BASE__POTENTIALLY_UNUSED = NULL;\n", iopPrefix, vPrefix, name)
+ b.printf("uint8_t* %s%s%s WUFFS_BASE__POTENTIALLY_UNUSED = NULL;\n", io0Prefix, vPrefix, name)
+ b.printf("uint8_t* %s%s%s WUFFS_BASE__POTENTIALLY_UNUSED = NULL;\n", io1Prefix, vPrefix, name)
+ b.printf("uint8_t* %s%s%s WUFFS_BASE__POTENTIALLY_UNUSED = NULL;\n", io2Prefix, vPrefix, name)
}
}
return nil
diff --git a/internal/testcut/testcut.go b/internal/testcut/testcut.go
index ba2d0ca..f15b8a5 100644
--- a/internal/testcut/testcut.go
+++ b/internal/testcut/testcut.go
@@ -43,7 +43,7 @@
func Test(t *testing.T,
smallestValidMaxEncodedLen int,
- cut func([]byte, int) (int, int, error),
+ cut func(io.Writer, []byte, int) (int, int, error),
newReader func(io.Reader) (io.ReadCloser, error),
filenames []string) {
@@ -90,8 +90,9 @@
if maxEncodedLen < smallestValidMaxEncodedLen {
continue
}
+ w0 := &bytes.Buffer{}
encoded := clone(full)
- encLen, decLen, err := cut(encoded, maxEncodedLen)
+ encLen, decLen, err := cut(w0, encoded, maxEncodedLen)
if err != nil {
t.Errorf("f=%q, mEL=%d: cut: %v", filename, maxEncodedLen, err)
continue
@@ -107,13 +108,13 @@
continue
}
- w := &bytes.Buffer{}
+ w1 := &bytes.Buffer{}
r, err := newReader(bytes.NewReader(encoded[:encLen]))
if err != nil {
t.Errorf("f=%q, mEL=%d: newReader: %v", filename, maxEncodedLen, err)
continue
}
- if n, err := io.Copy(w, r); err != nil {
+ if n, err := io.Copy(w1, r); err != nil {
t.Errorf("f=%q, mEL=%d: io.Copy: %v", filename, maxEncodedLen, err)
continue
} else if n != int64(decLen) {
@@ -122,6 +123,11 @@
continue
}
+ if !bytes.Equal(w0.Bytes(), w1.Bytes()) {
+ t.Errorf("f=%q, mEL=%d: decoded bytes were not equal", filename, maxEncodedLen)
+ continue
+ }
+
if (maxEncodedLen == len(encoded)) && (int64(decLen) != fullDecodedLen) {
t.Errorf("f=%q, mEL=%d: full decode: got %d, want %d",
filename, maxEncodedLen, decLen, fullDecodedLen)
@@ -138,7 +144,7 @@
func Benchmark(b *testing.B,
smallestValidMaxEncodedLen int,
- cut func([]byte, int) (int, int, error),
+ cut func(io.Writer, []byte, int) (int, int, error),
newReader func(io.Reader) (io.ReadCloser, error),
filename string,
trimPrefix int,
@@ -168,7 +174,7 @@
continue
}
encoded := clone(full)
- if _, _, err := cut(encoded, maxEncodedLen); err != nil {
+ if _, _, err := cut(nil, encoded, maxEncodedLen); err != nil {
b.Fatalf("cut: %v", err)
}
if maxEncodedLen >= len(full) {
diff --git a/lang/builtin/builtin.go b/lang/builtin/builtin.go
index 47de929..919fe86 100644
--- a/lang/builtin/builtin.go
+++ b/lang/builtin/builtin.go
@@ -19,15 +19,22 @@
t "github.com/google/wuffs/lang/token"
)
+var FourCCs = [...][2]string{
+ {"ICCP", "International Color Consortium Profile"},
+ {"XMP ", "Extensible Metadata Platform"},
+}
+
var Statuses = [...]string{
// Warnings.
`"@end of data"`,
+ `"@metadata reported"`,
// Suspensions.
`"$short read"`,
`"$short write"`,
// Errors.
+ `"#bad I/O position"`,
`"#bad argument (length too short)"`,
`"#bad argument"`,
`"#bad call sequence"`,
@@ -42,6 +49,7 @@
`"#initialize not called"`,
`"#interleaved coroutine calls"`,
`"#not enough data"`,
+ `"#unsupported option"`,
`"#too much data"`,
}
@@ -209,11 +217,10 @@
"io_reader.peek_u64le() u64",
"io_reader.available() u64",
+ "io_reader.count_since(mark u64) u64",
+ "io_reader.mark() u64",
"io_reader.position() u64",
- "io_reader.set!(s slice u8, closed bool)", // TODO: remove, as it's no longer used?
- "io_reader.set_limit!(l u64)", // TODO: remove, as it's no longer used?
- "io_reader.set_mark!()",
- "io_reader.since_mark() slice u8",
+ "io_reader.since(mark u64) slice u8",
"io_reader.take!(n u64) slice u8",
"io_reader.skip?(n u32)",
@@ -264,11 +271,11 @@
"io_writer.write_fast_u64le!(x u64)",
"io_writer.available() u64",
+ "io_writer.count_since(mark u64) u64",
+ "io_writer.history_available() u64",
+ "io_writer.mark() u64",
"io_writer.position() u64",
- "io_writer.set!(s slice u8)", // TODO: remove, as it's no longer used?
- "io_writer.set_limit!(l u64)", // TODO: remove, as it's no longer used?
- "io_writer.set_mark!()",
- "io_writer.since_mark() slice u8",
+ "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",
@@ -300,7 +307,7 @@
"frame_config.io_position() u64",
"frame_config.update!(bounds rect_ie_u32, duration u64[..0x7FFFFFFFFFFFFFFF], " +
- "index u64, io_position u64, blend u8, disposal u8)",
+ "index u64, io_position u64, blend u8, disposal u8, background_color u32)",
// ---- image_config
@@ -315,8 +322,8 @@
// ---- pixel_swizzler
- "pixel_swizzler.prepare!(dst_pixfmt u32, dst_palette slice u8, src_pixfmt u32, src_palette slice u8)",
- "pixel_swizzler.swizzle_packed!(dst slice u8, dst_palette slice u8, src slice u8) u64",
+ "pixel_swizzler.prepare!(dst_pixfmt u32, dst_palette slice u8, src_pixfmt u32, src_palette slice u8) status",
+ "pixel_swizzler.swizzle_interleaved!(dst slice u8, dst_palette slice u8, src slice u8) u64",
}
// The "T1" and "T2" types here are placeholders for generic "slice T" or
diff --git a/lang/check/bounds.go b/lang/check/bounds.go
index a2d36ef..6e3c7d9 100644
--- a/lang/check/bounds.go
+++ b/lang/check/bounds.go
@@ -1113,10 +1113,10 @@
}
func (q *checker) canCopyNFromHistoryFast(recv *a.Expr, args []*a.Node) error {
- // As per cgen's base-private.h, there are three pre-conditions:
+ // As per cgen's io-private.h, there are three pre-conditions:
// - n <= this.available()
// - distance > 0
- // - distance <= this.since_mark().length()
+ // - distance <= this.history_available()
if len(args) != 2 {
return fmt.Errorf("check: internal error: inconsistent copy_n_from_history_fast arguments")
@@ -1174,7 +1174,7 @@
return fmt.Errorf("check: could not prove distance > 0")
}
- // Check "distance <= this.since_mark().length()".
+ // Check "distance <= this.history_available()".
check2:
for {
for _, x := range q.facts {
@@ -1192,22 +1192,18 @@
continue
}
- // Check that the RHS is "recv.since_mark().length()".
+ // Check that the RHS is "recv.history_available()".
y, method, yArgs := splitReceiverMethodArgs(x.RHS().AsExpr())
- if method != t.IDLength || len(yArgs) != 0 {
+ if method != t.IDHistoryAvailable || len(yArgs) != 0 {
continue
}
- z, method, zArgs := splitReceiverMethodArgs(y)
- if method != t.IDSinceMark || len(zArgs) != 0 {
- continue
- }
- if !z.Eq(recv) {
+ if !y.Eq(recv) {
continue
}
break check2
}
- return fmt.Errorf("check: could not prove distance <= %s.since_mark().length()", recv.Str(q.tm))
+ return fmt.Errorf("check: could not prove distance <= %s.history_available()", recv.Str(q.tm))
}
return nil
diff --git a/lang/token/list.go b/lang/token/list.go
index 85cb5c5..765ef80 100644
--- a/lang/token/list.go
+++ b/lang/token/list.go
@@ -459,15 +459,15 @@
IDDecodeFrameOptions = ID(0x158)
- IDCanUndoByte = ID(0x160)
- IDPosition = ID(0x161)
- IDSetLimit = ID(0x162)
- IDSetMark = ID(0x163)
- IDSinceMark = ID(0x164)
- IDSinceMarkLength = ID(0x165)
- IDSkip = ID(0x166)
- IDSkipFast = ID(0x167)
- IDTake = ID(0x168)
+ IDCanUndoByte = ID(0x160)
+ IDCountSince = ID(0x161)
+ IDHistoryAvailable = ID(0x162)
+ IDMark = ID(0x163)
+ IDPosition = ID(0x164)
+ IDSince = ID(0x165)
+ IDSkip = ID(0x166)
+ IDSkipFast = ID(0x167)
+ IDTake = ID(0x168)
IDCopyFromSlice = ID(0x170)
IDCopyNFromHistory = ID(0x171)
@@ -791,15 +791,15 @@
IDDecodeFrameOptions: "decode_frame_options",
- IDCanUndoByte: "can_undo_byte",
- IDPosition: "position",
- IDSetLimit: "set_limit",
- IDSetMark: "set_mark",
- IDSinceMark: "since_mark",
- IDSinceMarkLength: "since_mark_length",
- IDSkip: "skip",
- IDSkipFast: "skip_fast",
- IDTake: "take",
+ IDCanUndoByte: "can_undo_byte",
+ IDCountSince: "count_since",
+ IDHistoryAvailable: "history_available",
+ IDMark: "mark",
+ IDPosition: "position",
+ IDSince: "since",
+ IDSkip: "skip",
+ IDSkipFast: "skip_fast",
+ IDTake: "take",
IDCopyFromSlice: "copy_from_slice",
IDCopyNFromHistory: "copy_n_from_history",
diff --git a/lib/flatecut/flatecut.go b/lib/flatecut/flatecut.go
index cc4e7fc..0557168 100644
--- a/lib/flatecut/flatecut.go
+++ b/lib/flatecut/flatecut.go
@@ -23,14 +23,19 @@
package flatecut
import (
+ "bytes"
+ "compress/flate"
"errors"
+ "io"
)
var (
errMaxEncodedLenTooSmall = errors.New("flatecut: maxEncodedLen is too small")
- errInternalNoProgress = errors.New("flatecut: internal: no progress")
- errInternalSomeProgress = errors.New("flatecut: internal: some progress")
+ errInternalInconsistentDecodedLen = errors.New("flatecut: internal: inconsistent decodedLen")
+ errInternalNoProgress = errors.New("flatecut: internal: no progress")
+ errInternalReplaceWithSingleBlock = errors.New("flatecut: internal: replace with single block")
+ errInternalSomeProgress = errors.New("flatecut: internal: some progress")
errInvalidBadBlockLength = errors.New("flatecut: invalid input: bad block length")
errInvalidBadBlockType = errors.New("flatecut: invalid input: bad block type")
@@ -84,6 +89,13 @@
mostNegativeInt32 = -0x80000000
)
+func loadU64LE(b []byte) uint64 {
+ _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
+ uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
+
+}
+
type bitstream struct {
// bytes[index] is the next byte to load into the 'bits' field.
bytes []byte
@@ -91,7 +103,7 @@
// The low nBits bits of the 'bits' field hold the next bits (in LSB-first
// order).
- bits uint32
+ bits uint64
nBits uint32
}
@@ -100,13 +112,13 @@
if b.index >= len(b.bytes) {
return mostNegativeInt32
}
- b.bits |= uint32(b.bytes[b.index]) << b.nBits
+ b.bits |= uint64(b.bytes[b.index]) << b.nBits
b.nBits += 8
b.index++
}
mask := ((uint32(1)) << nBits) - 1
- ret := b.bits & mask
+ ret := uint32(b.bits) & mask
b.bits >>= nBits
b.nBits -= nBits
return int32(ret)
@@ -125,12 +137,15 @@
// which results in:
//
// huffman{
-// counts: []uint32{
+// counts: [maxCodeBits + 1]uint32{
// 2: 1, 3: 5, 4: 2,
// },
-// symbols: []int32{
+// symbols: [maxNumCodes]int32{
// 0: 'F', 1: 'A', 2: 'B', 3: 'C', 4: 'D', 5: 'E', 6: 'G', 7: 'H',
// },
+// lookUpTable: [256]uint32{
+// etc,
+// },
// }
//
// Continuing the example from the RFC, decoding "1110" from the bitstream will
@@ -138,9 +153,49 @@
type huffman struct {
counts [maxCodeBits + 1]uint32
symbols [maxNumCodes]int32
+
+ // lookUpTable holds cached results of the slowDecode method.
+ //
+ // The uint8 key is the next 8 bits of input.
+ //
+ // The uint32 value's low 16 bits are the symbol, the high 16 bits are the
+ // number of bits used to encode that symbol.
+ //
+ // Zero means that the entry is invalid. For example, the encoded symbol
+ // might be longer than 8 bits.
+ lookUpTable [256]uint32
}
func (h *huffman) decode(b *bitstream) int32 {
+ if b.nBits >= 8 {
+ // No-op.
+ } else if b.index < (len(b.bytes) - 8) {
+ // This is "Variant 4" of
+ // https://fgiesen.wordpress.com/2018/02/20/reading-bits-in-far-too-many-ways-part-2/
+ u := loadU64LE(b.bytes[b.index:])
+ b.bits |= u << b.nBits
+ b.index += int((63 - b.nBits) >> 3)
+ b.nBits |= 56
+ } else if b.index < len(b.bytes) {
+ b.bits |= uint64(b.bytes[b.index]) << b.nBits
+ b.nBits += 8
+ b.index++
+ } else {
+ goto slow
+ }
+
+ if x := h.lookUpTable[b.bits&0xFF]; x != 0 {
+ n := x >> 16
+ b.bits >>= n
+ b.nBits -= n
+ return int32(x & 0xFFFF)
+ }
+
+slow:
+ return h.slowDecode(b)
+}
+
+func (h *huffman) slowDecode(b *bitstream) int32 {
code := uint32(0) // The i bits from the bitstream.
first := uint32(0) // The first Huffman code of length i.
symIndex := uint32(0) // How many elements of h.symbols we've gone past.
@@ -154,12 +209,12 @@
if b.index >= len(b.bytes) {
return mostNegativeInt32
}
- b.bits = uint32(b.bytes[b.index])
+ b.bits = uint64(b.bytes[b.index])
b.nBits = 8
b.index++
}
- code |= b.bits & 1
+ code |= uint32(b.bits & 1)
b.bits >>= 1
b.nBits -= 1
@@ -199,7 +254,7 @@
for _, x := range lengths {
h.counts[x]++
}
- if h.counts[0] == uint32(len(lengths)) {
+ if h.counts[0] >= uint32(len(lengths)) {
return 0, 0, errInvalidBadHuffmanTree
}
@@ -230,7 +285,12 @@
}
}
if remaining != 0 {
- return 0, 0, errInvalidBadHuffmanTree
+ if ((h.counts[0] + 1) == uint32(len(lengths))) && (h.counts[1] == 1) {
+ // No-op. We allow a degenerate Huffman tree with only one code (of
+ // length 1 bit).
+ } else {
+ return 0, 0, errInvalidBadHuffmanTree
+ }
}
offsets := [maxCodeBits + 1]uint32{}
@@ -244,18 +304,68 @@
offsets[length]++
}
}
+ h.constructLookUpTable()
return endCodeBits, endCodeNBits, nil
}
-// cutEmpty sets encoding[:2] to contain valid DEFLATE-encoded data. Decoding
-// that data produces zero bytes.
-func cutEmpty(encoded []byte, maxEncodedLen int) (encodedLen int, decodedLen int, retErr error) {
+func (h *huffman) constructLookUpTable() {
+ b := bitstream{
+ bytes: []byte{0x00},
+ }
+ for i := range h.lookUpTable {
+ b.bytes[0] = uint8(i)
+ b.index = 0
+ b.bits = 0
+ b.nBits = 0
+ if x := h.slowDecode(&b); x >= 0 {
+ h.lookUpTable[i] = ((8 - b.nBits) << 16) | uint32(x)
+ } else {
+ h.lookUpTable[i] = 0
+ }
+ }
+}
+
+// cutSingleBlock is an implementation of Cut whose output consists of a single
+// DEFLATE block.
+//
+// If maxEncodedLen is sufficiently large, this will be a Stored block (i.e. a
+// header followed by literal bytes). Otherwise, it will set encoding[:2] so
+// that decoding produces zero bytes.
+//
+// A precondition is that maxEncodedLen >= SmallestValidMaxEncodedLen.
+func cutSingleBlock(encoded []byte, maxEncodedLen int) (encodedLen int, decodedLen int, retErr error) {
if maxEncodedLen < SmallestValidMaxEncodedLen {
panic("unreachable")
}
+
+ // Try re-encoding as a single Stored block: up to 0xFFFF literal bytes,
+ // with a 5 byte prefix.
+ if maxEncodedLen > 5 {
+ n := maxEncodedLen - 5
+ if n > 0xFFFF {
+ n = 0xFFFF
+ }
+
+ buf := make([]byte, n)
+ n, err := io.ReadFull(flate.NewReader(bytes.NewReader(encoded)), buf)
+ if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
+ return 0, 0, err
+ }
+
+ if n > 0 {
+ encoded[0] = 0x01 // finalBlock = true, blockType = 0 (Stored).
+ encoded[1] = uint8(n >> 0)
+ encoded[2] = uint8(n >> 8)
+ encoded[3] = ^encoded[1]
+ encoded[4] = ^encoded[2]
+ copy(encoded[5:], buf[:n])
+ return n + 5, n, nil
+ }
+ }
+
// Set encoded[:2] to hold:
// - 1 bit ...._...._...._...1 finalBlock = true.
- // - 2 bits ...._...._...._.01. blockType = 1 (static Huffman).
+ // - 2 bits ...._...._...._.01. blockType = 1 (Static Huffman).
// - 7 bits ...._..00_0000_0... litLenSymbol = 256 (end-of-block).
// - 6 bits 0000_00.._...._.... padding.
encoded[0] = 0x03
@@ -267,11 +377,16 @@
// DEFLATE-compressed data, assuming that encoded starts off containing valid
// DEFLATE-compressed data.
//
+// If a nil error is returned, then encodedLen <= maxEncodedLen will hold.
+//
// Decompressing that modified, shorter byte slice produces a prefix (of length
// decodedLen) of the decompression of the original, longer byte slice.
//
+// If w is non-nil, that prefix is also written to w. If a non-nil error is
+// returned, incomplete data might still be written to w.
+//
// It does not necessarily return the largest possible decodedLen.
-func Cut(encoded []byte, maxEncodedLen int) (encodedLen int, decodedLen int, retErr error) {
+func Cut(w io.Writer, encoded []byte, maxEncodedLen int) (encodedLen int, decodedLen int, retErr error) {
if maxEncodedLen < SmallestValidMaxEncodedLen {
return 0, 0, errMaxEncodedLenTooSmall
}
@@ -292,7 +407,28 @@
},
maxEncodedLen: maxEncodedLen,
}
- return c.cut()
+ encodedLen, decodedLen, err := c.cut()
+ if err != nil {
+ return 0, 0, err
+ }
+
+ if w != nil {
+ // TODO: writing to w directly, in cutter's doStored and doHuffman,
+ // might be faster than re-walking the bitstream with compress/flate.
+ r := flate.NewReader(bytes.NewReader(encoded[:encodedLen]))
+ if n, err := io.Copy(w, r); err != nil {
+ r.Close()
+ return 0, 0, err
+ } else if n != int64(decodedLen) {
+ r.Close()
+ return 0, 0, errInternalInconsistentDecodedLen
+ }
+ if err := r.Close(); err != nil {
+ return 0, 0, err
+ }
+ }
+
+ return encodedLen, decodedLen, nil
}
type cutter struct {
@@ -320,6 +456,10 @@
finalBlockIndex := c.bits.index
finalBlockNBits := c.bits.nBits
+ for finalBlockNBits >= 8 {
+ finalBlockIndex--
+ finalBlockNBits -= 8
+ }
blockType := c.bits.take(2)
if blockType < 0 {
@@ -331,13 +471,18 @@
case 0:
err = c.doStored()
case 1:
- err = c.doStaticHuffman()
+ err = c.doStaticHuffman(prevFinalBlockIndex < 0)
case 2:
- err = c.doDynamicHuffman()
+ err = c.doDynamicHuffman(prevFinalBlockIndex < 0)
case 3:
return 0, 0, errInvalidBadBlockType
}
+ for c.bits.nBits >= 8 {
+ c.bits.index--
+ c.bits.nBits -= 8
+ }
+
switch err {
case nil:
if finalBlock == 0 {
@@ -348,15 +493,15 @@
case errInternalNoProgress:
if prevFinalBlockIndex < 0 {
- return cutEmpty(c.bits.bytes, c.maxEncodedLen)
+ return cutSingleBlock(c.bits.bytes, c.maxEncodedLen)
}
// Un-read to just before the finalBlock bit.
c.bits.index = finalBlockIndex
c.bits.nBits = finalBlockNBits + 1
- if c.bits.nBits == 8 {
+ for c.bits.nBits >= 8 {
c.bits.index--
- c.bits.nBits = 0
+ c.bits.nBits -= 8
}
finalBlockIndex = prevFinalBlockIndex
@@ -370,6 +515,9 @@
mask := uint32(1) << n
c.bits.bytes[finalBlockIndex-1] |= uint8(mask)
+ case errInternalReplaceWithSingleBlock:
+ return cutSingleBlock(c.bits.bytes, c.maxEncodedLen)
+
default:
return 0, 0, err
@@ -387,9 +535,14 @@
}
func (c *cutter) doStored() error {
- if (c.maxEncodedLen - c.bits.index) < 4 {
+ for c.bits.nBits >= 8 {
+ c.bits.index--
+ c.bits.nBits -= 8
+ }
+ if (c.maxEncodedLen < c.bits.index) || ((c.maxEncodedLen - c.bits.index) < 4) {
return errInternalNoProgress
}
+
length := uint32(c.bits.bytes[c.bits.index+0]) | uint32(c.bits.bytes[c.bits.index+1])<<8
invLen := uint32(c.bits.bytes[c.bits.index+2]) | uint32(c.bits.bytes[c.bits.index+3])<<8
if length+invLen != 0xFFFF {
@@ -426,7 +579,7 @@
return errInternalSomeProgress
}
-func (c *cutter) doStaticHuffman() error {
+func (c *cutter) doStaticHuffman(isFirstBlock bool) error {
const (
numLCodes = 288
numDCodes = 32
@@ -451,10 +604,10 @@
lengths[i] = 5
}
- return c.doHuffman(lengths[:numLCodes], lengths[numLCodes:])
+ return c.doHuffman(isFirstBlock, lengths[:numLCodes], lengths[numLCodes:])
}
-func (c *cutter) doDynamicHuffman() error {
+func (c *cutter) doDynamicHuffman(isFirstBlock bool) error {
numLCodes := 257 + c.bits.take(5)
if numLCodes < 0 {
return errInvalidNotEnoughData
@@ -527,10 +680,10 @@
}
}
- return c.doHuffman(lengths[:numLCodes], lengths[numLCodes:])
+ return c.doHuffman(isFirstBlock, lengths[:numLCodes], lengths[numLCodes:])
}
-func (c *cutter) doHuffman(lLengths []uint32, dLengths []uint32) error {
+func (c *cutter) doHuffman(isFirstBlock bool, lLengths []uint32, dLengths []uint32) error {
err := error(nil)
if c.endCodeBits, c.endCodeNBits, err = c.lHuff.construct(lLengths); err != nil {
return err
@@ -542,6 +695,10 @@
return err
}
+ for c.bits.nBits >= 8 {
+ c.bits.index--
+ c.bits.nBits -= 8
+ }
if c.bits.index > c.maxEncodedLen {
return errInternalNoProgress
}
@@ -609,8 +766,25 @@
if checkpointIndex < 0 {
return errInternalNoProgress
}
+
+ // If we're the first block in the DEFLATE stream, check if we would be
+ // better off replacing the Huffman block with a Stored block.
+ if isFirstBlock && (c.maxEncodedLen > 5) {
+ n := c.maxEncodedLen - 5
+ if n > 0xFFFF {
+ n = 0xFFFF
+ }
+ if c.decodedLen < int32(n) {
+ return errInternalReplaceWithSingleBlock
+ }
+ }
+
c.bits.index = checkpointIndex
c.bits.nBits = checkpointNBits
+ for c.bits.nBits >= 8 {
+ c.bits.index--
+ c.bits.nBits -= 8
+ }
c.writeEndCode()
return errInternalSomeProgress
}
diff --git a/lib/flatecut/flatecut_test.go b/lib/flatecut/flatecut_test.go
index 7c649ca..5b0035e 100644
--- a/lib/flatecut/flatecut_test.go
+++ b/lib/flatecut/flatecut_test.go
@@ -15,8 +15,10 @@
package flatecut
import (
+ "bytes"
"compress/flate"
"io"
+ "io/ioutil"
"testing"
"github.com/google/wuffs/internal/testcut"
@@ -39,3 +41,191 @@
func newReader(r io.Reader) (io.ReadCloser, error) {
return flate.NewReader(r), nil
}
+
+func decodeFlate(src []byte) string {
+ dst, err := ioutil.ReadAll(flate.NewReader(bytes.NewReader(src)))
+ if err != nil {
+ return err.Error()
+ }
+ return string(dst)
+}
+
+func TestHuffmanDecode(t *testing.T) {
+ // This exercises the "ABCDEFGH" example from RFC 1951 section 3.2.2,
+ // discussed in the "type huffman" doc comment.
+
+ const src = "HEADFACE"
+ codes := []string{
+ 'A': " 010",
+ 'B': " 011",
+ 'C': " 100",
+ 'D': " 101",
+ 'E': " 110",
+ 'F': " 00",
+ 'G': "1110",
+ 'H': "1111",
+ }
+
+ encoded := []byte(nil)
+ encBits := uint32(0)
+ encNBits := uint32(0)
+ for _, s := range src {
+ for _, c := range codes[s] {
+ if c == ' ' {
+ continue
+ }
+
+ if c == '1' {
+ encBits |= 1 << encNBits
+ }
+ encNBits++
+
+ if encNBits == 8 {
+ encoded = append(encoded, uint8(encBits))
+ encBits = 0
+ encNBits = 0
+ }
+ }
+ }
+ if encNBits > 0 {
+ encoded = append(encoded, uint8(encBits))
+ }
+
+ h := huffman{
+ counts: [maxCodeBits + 1]uint32{
+ 2: 1, 3: 5, 4: 2,
+ },
+ symbols: [maxNumCodes]int32{
+ 0: 'F', 1: 'A', 2: 'B', 3: 'C', 4: 'D', 5: 'E', 6: 'G', 7: 'H',
+ },
+ }
+ h.constructLookUpTable()
+
+ b := &bitstream{
+ bytes: encoded,
+ }
+
+ decoded := []byte(nil)
+ for _ = range src {
+ c := h.decode(b)
+ if c < 0 {
+ decoded = append(decoded, '!')
+ break
+ }
+ decoded = append(decoded, uint8(c))
+ }
+
+ if got, want := string(decoded), src; got != want {
+ t.Fatalf("got %q, want %q", got, want)
+ }
+}
+
+// A DEFLATE encoding of the first 64 bytes of the AUTHORS file in the
+// repository root directory.
+//
+// The encoding uses a Dynamic Huffman block, but one whose H-D Huffman
+// distance tree is degenerate (there's a mapping for the "0" code but no
+// mapping for the "1" code) and unused.
+//
+// The first 25-30 bytes contain the encoded H-L and H-D Huffman trees. The
+// last 30-35 bytes contain the actual payload, encoded with H-L.
+//
+// The high 7 bits of the final byte is unused padding.
+const (
+ degenerateHuffmanDec = "# This is the official list of Wuffs authors for copyright purpo"
+ degenerateHuffmanEnc = "" +
+ "\x05\xc0\xc1\x09\xc5\x30\x0c\x03\xd0\x55\x04\x7f\xa5\x0f\x3d\x87" +
+ "\x50\xd5\x82\x80\x82\xed\x1c\xba\x7d\xdf\x0f\xff\x50\x41\x85\x8e" +
+ "\x1b\x26\x35\x35\x16\x96\xaa\x61\xe2\x3a\x64\x61\x9c\x0e\x67\x81" +
+ "\x4e\x4c\xef\x37\xf5\x44\x63\x9f\xdc\xfe\x00"
+)
+
+func TestReplaceHuffmanWithStored(t *testing.T) {
+ const dec = degenerateHuffmanDec
+ const enc = degenerateHuffmanEnc
+ if (len(dec) != 64) || (len(enc) != 59) {
+ panic("inconsistent const string lengths")
+ }
+ if got, want := decodeFlate([]byte(enc)), dec; got != want {
+ t.Fatalf("before Cut: got %q, want %q", got, want)
+ }
+
+ for i := 4; i <= 59; i += 5 {
+ b := []byte(enc)
+ encLen, decLen, err := Cut(nil, b, i)
+ if err != nil {
+ t.Errorf("i=%d: %v", i, err)
+ continue
+ }
+ if encLen < 1 {
+ t.Errorf("i=%d: encLen: got %d, want >= 1", i, encLen)
+ continue
+ } else if encLen > len(enc) {
+ t.Errorf("i=%d: encLen: got %d, want <= %d", i, encLen, len(enc))
+ continue
+ }
+ // If we can make some progress (decLen > 0), even if the input uses a
+ // Huffman block, one option is to re-encode to a single Stored block
+ // (for 5 bytes of overhead). It's single because len(dec) < 0xFFFF.
+ // Regardless of whether the cut form uses a Huffman or Stored block,
+ // we should be able to produce at least i-5 bytes of decoded output.
+ if (decLen > 0) && (i > 5) && (decLen < i-5) {
+ t.Errorf("i=%d: decLen: got %d, want >= %d", i, decLen, i-5)
+ continue
+ } else if decLen > len(dec) {
+ t.Errorf("i=%d: decLen: got %d, want <= %d", i, decLen, len(dec))
+ continue
+ }
+
+ if got, want := decodeFlate(b[:encLen]), dec[:decLen]; got != want {
+ t.Errorf("i=%d: after Cut: got %q, want %q", i, got, want)
+ continue
+ }
+
+ // Check that we are using a space-efficient block type.
+ {
+ got := (b[0] >> 1) & 3
+ want := uint8(0xFF)
+
+ switch i {
+ case 4:
+ want = 1 // Static Huffman, for a decLen of 0.
+ case 9:
+ want = 0 // Stored.
+ case 59:
+ want = 2 // Dynamic Huffman.
+ default:
+ continue
+ }
+
+ if got != want {
+ t.Errorf("i=%d: block type: got %d, want %d", i, got, want)
+ }
+ }
+ }
+}
+
+func TestDegenerateHuffmanUnused(t *testing.T) {
+ const dec = degenerateHuffmanDec
+ const enc = degenerateHuffmanEnc
+
+ // Cutting 1 byte off the end of the encoded form will lead to cutting n
+ // bytes off the decoded form. Coincidentally, n equals 1, even though each
+ // decoded byte (8 bits) is packed into smaller number of bits, as most of
+ // the final encoded byte's bits are unused padding.
+ const n = 1
+
+ b := []byte(enc)
+ encLen, decLen, err := Cut(nil, b, len(enc)-1)
+ if err != nil {
+ t.Fatalf("Cut: %v", err)
+ } else if encLen != len(enc)-1 {
+ t.Fatalf("encLen: got %d, want %d", encLen, len(enc)-1)
+ } else if decLen != len(dec)-n {
+ t.Fatalf("decLen: got %d, want %d", decLen, len(dec)-n)
+ }
+
+ if got, want := decodeFlate(b[:encLen]), dec[:decLen]; got != want {
+ t.Fatalf("after Cut: got %q, want %q", got, want)
+ }
+}
diff --git a/lib/rac/rac.go b/lib/rac/rac.go
index 905fb15..03b9ffb 100644
--- a/lib/rac/rac.go
+++ b/lib/rac/rac.go
@@ -26,7 +26,7 @@
package rac
const (
- // MaxCSize is the maximum RAC file size (in both CSpace and DSpace).
+ // MaxSize is the maximum RAC file size (in both CSpace and DSpace).
MaxSize = (1 << 48) - 1
// invalidCOffsetCLength is ((1 << 64) - 1).
diff --git a/lib/rac/writer.go b/lib/rac/writer.go
index 002365f..b699120 100644
--- a/lib/rac/writer.go
+++ b/lib/rac/writer.go
@@ -21,6 +21,13 @@
"sort"
)
+func btoi(b bool) int {
+ if b {
+ return 1
+ }
+ return 0
+}
+
func isZeroOrAPowerOf2(x uint64) bool {
return (x & (x - 1)) == 0
}
@@ -593,8 +600,18 @@
w.buffer[4] = uint8(checksum >> 0)
w.buffer[5] = uint8(checksum >> 8)
- _, err := w.w.Write(w.buffer[:size])
- return err
+ if _, err := w.w.Write(w.buffer[:size]); err != nil {
+ return err
+ }
+
+ for i, o := range n.children {
+ if len(o.children) != 0 {
+ if err := w.writeIndex(&n.children[i]); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
}
func calcCLength(primarySize int) uint64 {
@@ -640,37 +657,51 @@
}
resources := map[OptResource]bool{}
- arity := 0
for {
- i, j, newNodes := 0, 0, []node(nil)
+ i, j, arity, newNodes := 0, 0, 0, []node(nil)
for ; j < len(nodes); j++ {
o := &nodes[j]
- arity++
- if (o.secondary != 0) && !resources[o.secondary] {
- resources[o.secondary] = true
- arity++
- }
- if (o.tertiary != 0) && !resources[o.tertiary] {
- resources[o.tertiary] = true
- arity++
- }
+ new2 := (o.secondary != 0) && !resources[o.secondary]
+ new3 := (o.tertiary != 0) && !resources[o.tertiary]
+ arity += 1 + btoi(new2) + btoi(new3)
if arity <= 0xFF {
+ if new2 {
+ resources[o.secondary] = true
+ }
+ if new3 {
+ resources[o.tertiary] = true
+ }
continue
}
newNodes = append(newNodes, makeBranch(nodes[i:j], resources))
- i = j
- arity = 0
if len(resources) != 0 {
resources = map[OptResource]bool{}
}
+
+ i = j
+ arity = 1
+ if o.secondary != 0 {
+ resources[o.secondary] = true
+ arity++
+ }
+ if o.tertiary != 0 {
+ resources[o.tertiary] = true
+ arity++
+ }
}
if i == 0 {
return makeBranch(nodes, resources)
}
+
+ newNodes = append(newNodes, makeBranch(nodes[i:], resources))
+ if len(resources) != 0 {
+ resources = map[OptResource]bool{}
+ }
+
nodes, newNodes = newNodes, nil
}
}
diff --git a/lib/rac/writer_test.go b/lib/rac/writer_test.go
index 08982af..596c407 100644
--- a/lib/rac/writer_test.go
+++ b/lib/rac/writer_test.go
@@ -25,6 +25,10 @@
"testing"
)
+const bytesPerHexDumpLine = 79
+
+const fakeCodec = Codec(0xEE)
+
// Note that these exact bytes depends on the zlib encoder's algorithm, but
// there is more than one valid zlib encoding of any given input. This "compare
// to golden output" test is admittedly brittle, as the standard library's zlib
@@ -164,7 +168,6 @@
func testWriter(iloc IndexLocation, tempFile io.ReadWriter, cPageSize uint64, empty bool) error {
buf := &bytes.Buffer{}
- const fakeCodec = Codec(0xEE)
w := &Writer{
Writer: buf,
Codec: fakeCodec,
@@ -211,3 +214,127 @@
}
return nil
}
+
+func TestWriterMultiLevelIndex(t *testing.T) {
+ buf := &bytes.Buffer{}
+ w := &Writer{
+ Writer: buf,
+ Codec: fakeCodec,
+ IndexLocation: IndexLocationAtStart,
+ TempFile: &bytes.Buffer{},
+ }
+
+ // Write 260 chunks with 3 resources. With the current "func gather"
+ // algorithm, this results in a root node with two children, both of which
+ // are branch nodes. The first branch contains 252 chunks and refers to 3
+ // resources (so that its arity is 255). The second branch contains 8
+ // chunks and refers to 1 resource (so that its arity is 9).
+ xRes := OptResource(0)
+ yRes := OptResource(0)
+ zRes := OptResource(0)
+ for i := 0; i < 260; i++ {
+ secondary := OptResource(0)
+ tertiary := OptResource(0)
+
+ switch i {
+ case 3:
+ xRes, _ = w.AddResource([]byte("XX"))
+ yRes, _ = w.AddResource([]byte("YY"))
+ secondary = xRes
+ tertiary = yRes
+
+ case 4:
+ zRes, _ = w.AddResource([]byte("ZZ"))
+ secondary = yRes
+ tertiary = zRes
+
+ case 259:
+ secondary = yRes
+ }
+
+ primary := []byte(fmt.Sprintf("p%02x", i&0xFF))
+ _ = w.AddChunk(0x10000, primary, secondary, tertiary)
+ }
+
+ if err := w.Close(); err != nil {
+ t.Fatalf("Close: %v", err)
+ }
+
+ encoded := buf.Bytes()
+ if got, want := len(encoded), 0x13E2; got != want {
+ t.Fatalf("len(encoded): got 0x%X, want 0x%X", got, want)
+ }
+
+ got := hex.Dump(encoded)
+ got = "" +
+ got[0x000*bytesPerHexDumpLine:0x008*bytesPerHexDumpLine] +
+ "...\n" +
+ got[0x080*bytesPerHexDumpLine:0x088*bytesPerHexDumpLine] +
+ "...\n" +
+ got[0x100*bytesPerHexDumpLine:0x110*bytesPerHexDumpLine] +
+ "...\n" +
+ got[0x13C*bytesPerHexDumpLine:]
+
+ const want = "" +
+ "00000000 72 c3 63 02 a0 24 00 ff 00 00 fc 00 00 00 00 ff |r.c..$..........|\n" +
+ "00000010 00 00 04 01 00 00 00 ee 30 00 00 00 00 00 04 ff |........0.......|\n" +
+ "00000020 30 10 00 00 00 00 01 ff e2 13 00 00 00 00 01 02 |0...............|\n" +
+ "00000030 72 c3 63 ff 4c be 00 ff 00 00 00 00 00 00 00 ff |r.c.L...........|\n" +
+ "00000040 00 00 00 00 00 00 00 ff 00 00 00 00 00 00 00 ff |................|\n" +
+ "00000050 00 00 01 00 00 00 00 ff 00 00 02 00 00 00 00 ff |................|\n" +
+ "00000060 00 00 03 00 00 00 00 01 00 00 04 00 00 00 00 02 |................|\n" +
+ "00000070 00 00 05 00 00 00 00 ff 00 00 06 00 00 00 00 ff |................|\n" +
+ "...\n" +
+ "00000800 00 00 f7 00 00 00 00 ff 00 00 f8 00 00 00 00 ff |................|\n" +
+ "00000810 00 00 f9 00 00 00 00 ff 00 00 fa 00 00 00 00 ff |................|\n" +
+ "00000820 00 00 fb 00 00 00 00 ff 00 00 fc 00 00 00 00 ee |................|\n" +
+ "00000830 d9 10 00 00 00 00 01 ff db 10 00 00 00 00 01 ff |................|\n" +
+ "00000840 e0 10 00 00 00 00 01 ff d0 10 00 00 00 00 01 ff |................|\n" +
+ "00000850 d3 10 00 00 00 00 01 ff d6 10 00 00 00 00 01 ff |................|\n" +
+ "00000860 dd 10 00 00 00 00 01 00 e2 10 00 00 00 00 01 01 |................|\n" +
+ "00000870 e5 10 00 00 00 00 01 ff e8 10 00 00 00 00 01 ff |................|\n" +
+ "...\n" +
+ "00001000 bb 13 00 00 00 00 01 ff be 13 00 00 00 00 01 ff |................|\n" +
+ "00001010 c1 13 00 00 00 00 01 ff c4 13 00 00 00 00 01 ff |................|\n" +
+ "00001020 c7 13 00 00 00 00 01 ff e2 13 00 00 00 00 01 ff |................|\n" +
+ "00001030 72 c3 63 09 f0 09 00 ff 00 00 00 00 00 00 00 ff |r.c.............|\n" +
+ "00001040 00 00 01 00 00 00 00 ff 00 00 02 00 00 00 00 ff |................|\n" +
+ "00001050 00 00 03 00 00 00 00 ff 00 00 04 00 00 00 00 ff |................|\n" +
+ "00001060 00 00 05 00 00 00 00 ff 00 00 06 00 00 00 00 ff |................|\n" +
+ "00001070 00 00 07 00 00 00 00 ff 00 00 08 00 00 00 00 ee |................|\n" +
+ "00001080 db 10 00 00 00 00 01 ff ca 13 00 00 00 00 01 ff |................|\n" +
+ "00001090 cd 13 00 00 00 00 01 ff d0 13 00 00 00 00 01 ff |................|\n" +
+ "000010a0 d3 13 00 00 00 00 01 ff d6 13 00 00 00 00 01 ff |................|\n" +
+ "000010b0 d9 13 00 00 00 00 01 ff dc 13 00 00 00 00 01 ff |................|\n" +
+ "000010c0 df 13 00 00 00 00 01 00 e2 13 00 00 00 00 01 09 |................|\n" +
+ "000010d0 70 30 30 70 30 31 70 30 32 58 58 59 59 70 30 33 |p00p01p02XXYYp03|\n" +
+ "000010e0 5a 5a 70 30 34 70 30 35 70 30 36 70 30 37 70 30 |ZZp04p05p06p07p0|\n" +
+ "000010f0 38 70 30 39 70 30 61 70 30 62 70 30 63 70 30 64 |8p09p0ap0bp0cp0d|\n" +
+ "...\n" +
+ "000013c0 38 70 66 39 70 66 61 70 66 62 70 66 63 70 66 64 |8pf9pfapfbpfcpfd|\n" +
+ "000013d0 70 66 65 70 66 66 70 30 30 70 30 31 70 30 32 70 |pfepffp00p01p02p|\n" +
+ "000013e0 30 33 |03|\n"
+
+ if got != want {
+ t.Fatalf("\ngot:\n%s\nwant:\n%s", got, want)
+ }
+}
+
+func TestWriter1000Chunks(t *testing.T) {
+ w := &Writer{
+ Writer: ioutil.Discard,
+ Codec: fakeCodec,
+ }
+ data := make([]byte, 1)
+ res, _ := w.AddResource(data)
+ for i := 0; i < 1000; i++ {
+ if i == 2*255 {
+ _ = w.AddChunk(1, data, res, 0)
+ } else {
+ _ = w.AddChunk(1, data, 0, 0)
+ }
+ }
+ if err := w.Close(); err != nil {
+ t.Fatalf("Close: %v", err)
+ }
+}
diff --git a/lib/raczlib/raczlib.go b/lib/raczlib/raczlib.go
new file mode 100644
index 0000000..d41b8df
--- /dev/null
+++ b/lib/raczlib/raczlib.go
@@ -0,0 +1,41 @@
+// Copyright 2019 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.
+
+// ----------------
+
+// Package raczlib provides access to RAC (Random Access Compression) files
+// with the Zlib compression codec.
+//
+// The RAC specification is at
+// https://github.com/google/wuffs/blob/master/doc/spec/rac-spec.md
+package raczlib
+
+import (
+ "github.com/google/wuffs/lib/rac"
+)
+
+const (
+ // MaxSize is the maximum RAC file size (in both CSpace and DSpace).
+ MaxSize = rac.MaxSize
+)
+
+// IndexLocation is whether the index is at the start or end of the RAC file.
+//
+// See the RAC specification for further discussion.
+type IndexLocation = rac.IndexLocation
+
+const (
+ IndexLocationAtEnd = rac.IndexLocationAtEnd
+ IndexLocationAtStart = rac.IndexLocationAtStart
+)
diff --git a/lib/raczlib/writer.go b/lib/raczlib/writer.go
new file mode 100644
index 0000000..00c4815
--- /dev/null
+++ b/lib/raczlib/writer.go
@@ -0,0 +1,470 @@
+// Copyright 2019 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.
+
+package raczlib
+
+// TODO: API for shared dictionaries.
+
+import (
+ "bytes"
+ "compress/zlib"
+ "errors"
+ "io"
+
+ "github.com/google/wuffs/lib/rac"
+ "github.com/google/wuffs/lib/zlibcut"
+)
+
+const (
+ defaultDChunkSize = 65536 // 64 KiB.
+
+ maxCChunkSize = 1 << 30 // 1 GiB.
+ maxTargetDChunkSize = 1 << 31 // 2 GiB.
+)
+
+var (
+ errCChunkSizeIsTooSmall = errors.New("raczlib: CChunkSize is too small")
+ errInvalidWriter = errors.New("raczlib: invalid Writer")
+ errWriterIsClosed = errors.New("raczlib: Writer is closed")
+
+ errInternalShortCSize = errors.New("raczlib: internal error: short CSize")
+)
+
+func startingTargetDChunkSize(cChunkSize uint64) uint64 { return 2 * cChunkSize }
+
+// stripTrailingZeroes returns b shorn of any trailing '\x00' bytes. The RAC
+// file format will implicitly set any trailing zeroes.
+func stripTrailingZeroes(b []byte) []byte {
+ n := len(b)
+ for (n > 0) && (b[n-1] == 0) {
+ n--
+ }
+ return b[:n]
+}
+
+// writeBuffer is a sequence of bytes, split into two slices: prev[p:] and
+// curr. Together, they hold the tail (so far) of the stream of bytes given to
+// an io.Writer.
+//
+// Conceptually, it is the concatenation of those two slices, but the struct
+// holds two slices, not one, to minimize copying and memory allocation.
+//
+// The first slice, prev[p:], is those bytes from all previous Write calls that
+// have been copied to an internal buffer but not yet fully processed.
+//
+// The second slice, curr, is those bytes from the current Write call that have
+// not been processed.
+//
+// The underlying array that backs the prev slice is owned by the writeBuffer,
+// and is re-used to minimize memory allocations. The curr slice is a sub-slice
+// of the []byte passed to the Write method, and is owned by the caller, not by
+// the writeBuffer.
+//
+// As bytes are fully processed, prev[p:] shrinks (by incrementing "p += etc")
+// and after len(prev[p:]) hits zero, curr shrinks (by re-assigning "curr =
+// curr[etc:]"). The two mechanisms differ (e.g. there is a p int that offsets
+// prev but not a corresponding c int that offsets curr) because of the
+// difference in backing-array memory ownership, mentioned above.
+//
+// The intended usage is for an io.Writer's Write(data) method to first call
+// writeBuffer.extend(data), then a mixture of multiple writeBuffer.peek(n) and
+// writeBuffer.advance(n), and finally writeBuffer.compact(). Thus, before and
+// after every Write call, writeBuffer.curr is empty and writebuffer.p is 0.
+type writeBuffer struct {
+ prev []byte
+ curr []byte
+ p int
+}
+
+// extend extends b's view of an io.Writer's incoming byte stream.
+func (b *writeBuffer) extend(curr []byte) {
+ if len(b.curr) != 0 {
+ panic("inconsistent writeBuffer state")
+ }
+ b.curr = curr
+}
+
+// length returns the total number of bytes available in b's buffers.
+func (b *writeBuffer) length() uint64 {
+ return uint64(len(b.prev)-b.p) + uint64(len(b.curr))
+}
+
+// peek returns the next m bytes in b's buffers, where m is the minimum of n
+// and b.length().
+//
+// The bytes are returned in two slices, not a single contiguous slice, in
+// order to minimize copying and memory allocation.
+func (b *writeBuffer) peek(n uint64) ([]byte, []byte) {
+ available := uint64(len(b.prev) - b.p)
+ if n <= available {
+ return b.prev[b.p : b.p+int(n)], nil
+ }
+ n -= available
+ if n <= uint64(len(b.curr)) {
+ return b.prev[b.p:], b.curr[:n]
+ }
+ return b.prev[b.p:], b.curr
+}
+
+// advance consumes the next n bytes.
+func (b *writeBuffer) advance(n uint64) {
+ available := uint64(len(b.prev) - b.p)
+ if n <= available {
+ b.p += int(n)
+ return
+ }
+ n -= available
+ b.curr = b.curr[n:]
+ b.p = len(b.prev)
+}
+
+// compact moves and copies any unprocessed bytes in b.prev and b.curr to be at
+// the start of b.prev.
+func (b *writeBuffer) compact() {
+ // Move any remaining bytes in prev to the front.
+ n := copy(b.prev, b.prev[b.p:])
+ b.prev = b.prev[:n]
+ b.p = 0
+ // Move any remaining bytes in curr to prev.
+ b.prev = append(b.prev, b.curr...)
+ b.curr = nil
+}
+
+// Writer provides a relatively simple way to write a RAC file (with the Zlib
+// compression codec) - one that is created starting from nothing, as opposed
+// to incrementally modifying an existing RAC file.
+//
+// Other packages may provide a more flexible (and more complicated) way to
+// write or append to RAC files, but that is out of scope of this package.
+//
+// Do not modify its exported fields after calling any of its methods.
+//
+// Writer implements the io.Writer interface.
+type Writer struct {
+ // Writer is where the RAC-encoded data is written to.
+ //
+ // Nil is an invalid value.
+ Writer io.Writer
+
+ // IndexLocation is whether the index is at the start or end of the RAC
+ // file.
+ //
+ // See the RAC specification for further discussion.
+ //
+ // The zero value of this field is IndexLocationAtEnd: a one pass encoding.
+ IndexLocation IndexLocation
+
+ // TempFile is a temporary file to use for a two pass encoding. The field
+ // name says "file" but it need not be a real file, in the operating system
+ // sense.
+ //
+ // For IndexLocationAtEnd, this must be nil. For IndexLocationAtStart, this
+ // must be non-nil.
+ //
+ // It does not need to implement io.Seeker, if it supports separate read
+ // and write positions (e.g. it is a bytes.Buffer). If it does implement
+ // io.Seeker (e.g. it is an os.File), its current position will be noted
+ // (via SeekCurrent), then it will be written to (via the
+ // raczlib.Writer.Write method), then its position will be reset (via
+ // SeekSet), then it will be read from (via the raczlib.Writer.Close
+ // method).
+ //
+ // The raczlib.Writer does not call TempFile.Close even if that method
+ // exists (e.g. the TempFile is an os.File). In that case, closing the
+ // temporary file (and deleting it) after the raczlib.Writer is closed is
+ // the responsibility of the raczlib.Writer caller, not the raczlib.Writer
+ // itself.
+ TempFile io.ReadWriter
+
+ // CPageSize guides padding the output to minimize the number of pages that
+ // each chunk occupies (in what the RAC spec calls CSpace).
+ //
+ // It must either be zero (which means no padding is inserted) or a power
+ // of 2, and no larger than MaxSize.
+ //
+ // For example, suppose that CSpace is partitioned into 1024-byte pages,
+ // that 1000 bytes have already been written to the output, and the next
+ // chunk is 1500 bytes long.
+ //
+ // - With no padding (i.e. with CPageSize set to 0), this chunk will
+ // occupy the half-open range [1000, 2500) in CSpace, which straddles
+ // three 1024-byte pages: the page [0, 1024), the page [1024, 2048) and
+ // the page [2048, 3072). Call those pages p0, p1 and p2.
+ //
+ // - With padding (i.e. with CPageSize set to 1024), 24 bytes of zeroes
+ // are first inserted so that this chunk occupies the half-open range
+ // [1024, 2524) in CSpace, which straddles only two pages (p1 and p2).
+ //
+ // This concept is similar, but not identical, to alignment. Even with a
+ // non-zero CPageSize, chunk start offsets are not necessarily aligned to
+ // page boundaries. For example, suppose that the chunk size was only 1040
+ // bytes, not 1500 bytes. No padding will be inserted, as both [1000, 2040)
+ // and [1024, 2064) straddle two pages: either pages p0 and p1, or pages p1
+ // and p2.
+ //
+ // Nonetheless, if all chunks (or all but the final chunk) have a size
+ // equal to (or just under) a multiple of the page size, then in practice,
+ // each chunk's starting offset will be aligned to a page boundary.
+ CPageSize uint64
+
+ // CChunkSize is the compressed size (i.e. size in CSpace) of each chunk.
+ // The final chunk might be smaller than this.
+ //
+ // This field is ignored if DChunkSize is non-zero.
+ CChunkSize uint64
+
+ // DChunkSize is the uncompressed size (i.e. size in DSpace) of each chunk.
+ // The final chunk might be smaller than this.
+ //
+ // If both CChunkSize and DChunkSize are non-zero, DChunkSize takes
+ // precedence and CChunkSize is ignored.
+ //
+ // If both CChunkSize and DChunkSize are zero, a default DChunkSize value
+ // will be used.
+ DChunkSize uint64
+
+ // cChunkSize and dChunkSize are copies of CChunkSize and DChunkSize,
+ // validated during the initialize method. For example, if both CChunkSize
+ // and DChunkSize are zero, dChunkSize will be defaultDChunkSize.
+ cChunkSize uint64
+ dChunkSize uint64
+
+ // err is the first error encountered. It is sticky: once a non-nil error
+ // occurs, all public methods will return that error.
+ err error
+
+ racWriter rac.Writer
+ zlibWriter *zlib.Writer
+
+ compressed bytes.Buffer
+ uncompressed writeBuffer
+}
+
+func (w *Writer) initialize() error {
+ if w.err != nil {
+ return w.err
+ }
+ if w.racWriter.Writer != nil {
+ // We're already initialized.
+ return nil
+ }
+ if w.Writer == nil {
+ w.err = errInvalidWriter
+ return w.err
+ }
+
+ if w.DChunkSize > 0 {
+ w.dChunkSize = w.DChunkSize
+ } else if w.CChunkSize > 0 {
+ w.cChunkSize = w.CChunkSize
+ if w.cChunkSize > maxCChunkSize {
+ w.cChunkSize = maxCChunkSize
+ }
+ } else {
+ w.dChunkSize = defaultDChunkSize
+ }
+
+ w.racWriter.Writer = w.Writer
+ w.racWriter.Codec = rac.CodecZlib
+ w.racWriter.IndexLocation = w.IndexLocation
+ w.racWriter.TempFile = w.TempFile
+ w.racWriter.CPageSize = w.CPageSize
+
+ w.zlibWriter, w.err = zlib.NewWriterLevel(&w.compressed, zlib.BestCompression)
+ return w.err
+}
+
+func (w *Writer) compress(dBytes0 []byte, dBytes1 []byte) ([]byte, error) {
+ w.compressed.Reset()
+ w.zlibWriter.Reset(&w.compressed)
+ if len(dBytes0) > 0 {
+ if _, err := w.zlibWriter.Write(dBytes0); err != nil {
+ w.err = err
+ return nil, err
+ }
+ }
+ if len(dBytes1) > 0 {
+ if _, err := w.zlibWriter.Write(dBytes1); err != nil {
+ w.err = err
+ return nil, err
+ }
+ }
+ if err := w.zlibWriter.Close(); err != nil {
+ w.err = err
+ return nil, err
+ }
+ return w.compressed.Bytes(), nil
+}
+
+// Write implements io.Writer.
+func (w *Writer) Write(p []byte) (int, error) {
+ if err := w.initialize(); err != nil {
+ return 0, err
+ }
+ w.uncompressed.extend(p)
+ n, err := len(p), w.write(false)
+ w.uncompressed.compact()
+ if err != nil {
+ return 0, err
+ }
+ return n, nil
+}
+
+func (w *Writer) write(eof bool) error {
+ if w.dChunkSize > 0 {
+ return w.writeDChunks(eof)
+ }
+ return w.writeCChunks(eof)
+}
+
+func (w *Writer) writeDChunks(eof bool) error {
+ for {
+ peek0, peek1 := w.uncompressed.peek(w.dChunkSize)
+ dSize := uint64(len(peek0)) + uint64(len(peek1))
+ if dSize == 0 {
+ return nil
+ }
+ if !eof && (dSize < w.dChunkSize) {
+ return nil
+ }
+
+ peek1 = stripTrailingZeroes(peek1)
+ if len(peek1) == 0 {
+ peek0 = stripTrailingZeroes(peek0)
+ }
+ cBytes, err := w.compress(peek0, peek1)
+ if err != nil {
+ return err
+ }
+
+ if err := w.racWriter.AddChunk(dSize, cBytes, 0, 0); err != nil {
+ w.err = err
+ return err
+ }
+ w.uncompressed.advance(dSize)
+ }
+}
+
+func (w *Writer) writeCChunks(eof bool) error {
+ // Each outer loop iteration tries to write exactly one chunk.
+outer:
+ for {
+ // We don't know, a priori, how many w.uncompressed bytes are needed to
+ // produce a compressed chunk of size cChunkSize. We use a
+ // startingTargetDChunkSize that is a small multiple of cChunkSize, and
+ // keep doubling that until we build something at least as large as
+ // cChunkSize, then zlibcut it back to be exactly cChunkSize.
+ targetDChunkSize := uint64(maxTargetDChunkSize)
+ if !eof {
+ targetDChunkSize = startingTargetDChunkSize(w.cChunkSize)
+ }
+
+ if n := w.uncompressed.length(); n == 0 {
+ return nil
+ } else if !eof && (n < targetDChunkSize) {
+ return nil
+ }
+
+ // The inner loop keeps doubling the targetDChunkSize until it's big
+ // enough to produce at least cChunkSize bytes of compressed data.
+ for {
+ next := targetDChunkSize * 2
+ if next > maxTargetDChunkSize {
+ next = maxTargetDChunkSize
+ }
+ force := next <= targetDChunkSize
+
+ if err := w.tryCChunk(targetDChunkSize, force); err == nil {
+ continue outer
+ } else if err != errInternalShortCSize {
+ return err
+ }
+
+ if w.uncompressed.length() <= targetDChunkSize {
+ // Growing the targetDChunkSize isn't going to change anything.
+ return nil
+ }
+ targetDChunkSize = next
+ }
+ }
+}
+
+func (w *Writer) tryCChunk(targetDChunkSize uint64, force bool) error {
+ peek0, peek1 := w.uncompressed.peek(targetDChunkSize)
+ dSize := uint64(len(peek0)) + uint64(len(peek1))
+ cBytes, err := w.compress(peek0, peek1)
+ if err != nil {
+ return err
+ }
+
+ switch {
+ case uint64(len(cBytes)) < w.cChunkSize:
+ if !force {
+ return errInternalShortCSize
+ }
+ fallthrough
+ case uint64(len(cBytes)) == w.cChunkSize:
+ if err := w.racWriter.AddChunk(dSize, cBytes, 0, 0); err != nil {
+ w.err = err
+ return err
+ }
+ w.uncompressed.advance(dSize)
+ return nil
+ }
+
+ eLen, dLen, err := zlibcut.Cut(nil, cBytes, int(w.cChunkSize))
+ if err != nil {
+ w.err = err
+ return err
+ }
+ if dLen == 0 {
+ w.err = errCChunkSizeIsTooSmall
+ return w.err
+ }
+ if err := w.racWriter.AddChunk(uint64(dLen), cBytes[:eLen], 0, 0); err != nil {
+ w.err = err
+ return err
+ }
+ w.uncompressed.advance(uint64(dLen))
+ return nil
+}
+
+// Close writes the RAC index to w.Writer and marks that w accepts no further
+// method calls.
+//
+// For a one pass encoding, no further action is taken. For a two pass encoding
+// (i.e. IndexLocationAtStart), it then copies w.TempFile to w.Writer. Either
+// way, if this method returns nil error, the entirety of what was written to
+// w.Writer constitutes a valid RAC file.
+//
+// Closing the underlying w.Writer, w.TempFile or both is the responsibility of
+// the raczlib.Writer caller, not the raczlib.Writer itself.
+//
+// It is not necessary to call Close, e.g. if an earlier Write call returned a
+// non-nil error. Unlike an os.File, failing to call raczlib.Writer.Close will
+// not leak resources such as file descriptors.
+func (w *Writer) Close() error {
+ if err := w.initialize(); err != nil {
+ return err
+ }
+ if err := w.write(true); err != nil {
+ return err
+ }
+ if err := w.racWriter.Close(); err != nil {
+ w.err = err
+ return err
+ }
+ w.err = errWriterIsClosed
+ return nil
+}
diff --git a/lib/zlibcut/example_test.go b/lib/zlibcut/example_test.go
new file mode 100644
index 0000000..76f4f4f
--- /dev/null
+++ b/lib/zlibcut/example_test.go
@@ -0,0 +1,121 @@
+// Copyright 2019 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.
+
+package zlibcut_test
+
+import (
+ "bytes"
+ "compress/zlib"
+ "fmt"
+ "io/ioutil"
+ "strings"
+
+ "github.com/google/wuffs/lib/zlibcut"
+)
+
+func ExampleCut() {
+ const sonnet18 = "" +
+ "Shall I compare thee to a summer’s day?\n" +
+ "Thou art more lovely and more temperate.\n" +
+ "Rough winds do shake the darling buds of May,\n" +
+ "And summer’s lease hath all too short a date.\n" +
+ "Sometime too hot the eye of heaven shines,\n" +
+ "And often is his gold complexion dimmed;\n" +
+ "And every fair from fair sometime declines,\n" +
+ "By chance, or nature’s changing course, untrimmed;\n" +
+ "But thy eternal summer shall not fade,\n" +
+ "Nor lose possession of that fair thou ow’st,\n" +
+ "Nor shall death brag thou wand'rest in his shade,\n" +
+ "When in eternal lines to Time thou grow'st.\n" +
+ "So long as men can breathe, or eyes can see,\n" +
+ "So long lives this, and this gives life to thee.\n"
+
+ if n := len(sonnet18); n != 632 {
+ fmt.Printf("len(sonnet18): got %d, want 632", n)
+ return
+ }
+
+ // Compress the input text, sonnet18.
+ buffer := &bytes.Buffer{}
+ w := zlib.NewWriter(buffer)
+ w.Write([]byte(sonnet18))
+ w.Close()
+ compressed := buffer.Bytes()
+
+ // The exact length of the zlib-compressed form of sonnet18 depends on the
+ // compression algorithm used, which can change from version to version of
+ // the Go standard library. Nonetheless, for a 632 byte input, we expect
+ // the compressed form to be between 300 and 500 bytes.
+ if n := len(compressed); (n < 300) || (500 < n) {
+ fmt.Printf("len(compressed): got %d, want something in [300, 500]", n)
+ return
+ }
+
+ // Cut the 300-or-more bytes to be 200.
+ encodedLen, decodedLen, err := zlibcut.Cut(nil, compressed, 200)
+ if err != nil {
+ fmt.Printf("Cut: %v", err)
+ return
+ }
+
+ // The encodedLen should be equal to or just under the requested 200.
+ cut := compressed[:encodedLen]
+ if n := len(cut); (n < 190) || (200 < n) {
+ fmt.Printf("len(cut): got %d, want something in [190, 200]", n)
+ return
+ }
+
+ // At this point, a real program would write that cut slice somewhere. The
+ // rest of this example verifies that the cut data has the properties we
+ // expect, given the semantics of zlibcut.Cut.
+
+ // Uncompress the cut data. It should be a valid zlib-compressed stream, so
+ // no errors should be encountered.
+ r, err := zlib.NewReader(bytes.NewReader(cut))
+ if err != nil {
+ fmt.Printf("NewReader: %v", err)
+ return
+ }
+ uncompressed, err := ioutil.ReadAll(r)
+ if err != nil {
+ fmt.Printf("ReadAll: %v", err)
+ return
+ }
+ err = r.Close()
+ if err != nil {
+ fmt.Printf("Close: %v", err)
+ return
+ }
+
+ // The uncompressed form of the cut data should be a prefix (of length
+ // decodedLen) of the original input, sonnet18. Again, the exact length
+ // depends on the zlib compression algorithm, but uncompressing 200 or so
+ // bytes should give between 250 and 400 bytes.
+ if n := len(uncompressed); n != decodedLen {
+ fmt.Printf("len(uncompressed): got %d, want %d", n, decodedLen)
+ return
+ } else if (n < 250) || (400 < n) {
+ fmt.Printf("len(uncompressed): got %d, want something in [250, 400]", n)
+ return
+ } else if !strings.HasPrefix(sonnet18, string(uncompressed)) {
+ fmt.Printf("uncompressed was not a prefix of the original input")
+ return
+ }
+
+ // The first two lines of the sonnet take 83 bytes.
+ fmt.Println(string(uncompressed[:83]))
+ // Output:
+ // Shall I compare thee to a summer’s day?
+ // Thou art more lovely and more temperate.
+}
diff --git a/lib/zlibcut/zlibcut.go b/lib/zlibcut/zlibcut.go
index 4f7da1c..6554ea1 100644
--- a/lib/zlibcut/zlibcut.go
+++ b/lib/zlibcut/zlibcut.go
@@ -23,8 +23,6 @@
package zlibcut
import (
- "bytes"
- "compress/flate"
"errors"
"hash/adler32"
"io"
@@ -52,11 +50,16 @@
// zlib-compressed data, assuming that encoded starts off containing valid
// zlib-compressed data.
//
+// If a nil error is returned, then encodedLen <= maxEncodedLen will hold.
+//
// Decompressing that modified, shorter byte slice produces a prefix (of length
// decodedLen) of the decompression of the original, longer byte slice.
//
+// If w is non-nil, that prefix is also written to w. If a non-nil error is
+// returned, incomplete data might still be written to w.
+//
// It does not necessarily return the largest possible decodedLen.
-func Cut(encoded []byte, maxEncodedLen int) (encodedLen int, decodedLen int, retErr error) {
+func Cut(w io.Writer, encoded []byte, maxEncodedLen int) (encodedLen int, decodedLen int, retErr error) {
if len(encoded) < 2 {
return 0, 0, errInvalidNotEnoughData
}
@@ -85,7 +88,15 @@
return 0, 0, errMaxEncodedLenTooSmall
}
+ hasher := adler32.New()
+ if w == nil {
+ w = hasher
+ } else {
+ w = io.MultiWriter(w, hasher)
+ }
+
encodedLen, decodedLen, err := flatecut.Cut(
+ w,
encoded[payloadStart:len(encoded)-4],
maxEncodedLen-payloadStart-4,
)
@@ -93,15 +104,7 @@
return 0, 0, err
}
- w := adler32.New()
- r := bytes.NewReader(encoded[payloadStart : payloadStart+encodedLen])
- if n, err := io.Copy(w, flate.NewReader(r)); err != nil {
- return 0, 0, err
- } else if n != int64(decodedLen) {
- return 0, 0, errInternalInconsistentDecodedLen
- }
-
- hash := w.Sum32()
+ hash := hasher.Sum32()
hashBytes := encoded[payloadStart+encodedLen : payloadStart+encodedLen+4]
hashBytes[0] = uint8(hash >> 24)
hashBytes[1] = uint8(hash >> 16)
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index dc00a84..964d7dd 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -191,8 +191,10 @@
typedef const char* wuffs_base__status;
extern const char* wuffs_base__warning__end_of_data;
+extern const char* wuffs_base__warning__metadata_reported;
extern const char* wuffs_base__suspension__short_read;
extern const char* wuffs_base__suspension__short_write;
+extern const char* wuffs_base__error__bad_i_o_position;
extern const char* wuffs_base__error__bad_argument_length_too_short;
extern const char* wuffs_base__error__bad_argument;
extern const char* wuffs_base__error__bad_call_sequence;
@@ -207,6 +209,7 @@
extern const char* wuffs_base__error__initialize_not_called;
extern const char* wuffs_base__error__interleaved_coroutine_calls;
extern const char* wuffs_base__error__not_enough_data;
+extern const char* wuffs_base__error__unsupported_option;
extern const char* wuffs_base__error__too_much_data;
static inline bool //
@@ -236,6 +239,16 @@
// --------
+// FourCC constants.
+
+// International Color Consortium Profile.
+#define WUFFS_BASE__FOURCC__ICCP 0x49434350
+
+// Extensible Metadata Platform.
+#define WUFFS_BASE__FOURCC__XMP 0x584D5020
+
+// --------
+
// Flicks are a unit of time. One flick (frame-tick) is 1 / 705_600_000 of a
// second. See https://github.com/OculusVR/Flicks
typedef int64_t wuffs_base__flicks;
@@ -509,14 +522,14 @@
uint32_t max_incl;
#ifdef __cplusplus
- inline bool is_empty();
- inline bool equals(wuffs_base__range_ii_u32__struct s);
+ inline bool is_empty() const;
+ inline bool equals(wuffs_base__range_ii_u32__struct s) const;
inline wuffs_base__range_ii_u32__struct intersect(
- wuffs_base__range_ii_u32__struct s);
+ wuffs_base__range_ii_u32__struct s) const;
inline wuffs_base__range_ii_u32__struct unite(
- wuffs_base__range_ii_u32__struct s);
- inline bool contains(uint32_t x);
- inline bool contains_range(wuffs_base__range_ii_u32__struct s);
+ wuffs_base__range_ii_u32__struct s) const;
+ inline bool contains(uint32_t x) const;
+ inline bool contains_range(wuffs_base__range_ii_u32__struct s) const;
#endif // __cplusplus
} wuffs_base__range_ii_u32;
@@ -530,12 +543,12 @@
}
static inline bool //
-wuffs_base__range_ii_u32__is_empty(wuffs_base__range_ii_u32* r) {
+wuffs_base__range_ii_u32__is_empty(const wuffs_base__range_ii_u32* r) {
return r->min_incl > r->max_incl;
}
static inline bool //
-wuffs_base__range_ii_u32__equals(wuffs_base__range_ii_u32* r,
+wuffs_base__range_ii_u32__equals(const wuffs_base__range_ii_u32* r,
wuffs_base__range_ii_u32 s) {
return (r->min_incl == s.min_incl && r->max_incl == s.max_incl) ||
(wuffs_base__range_ii_u32__is_empty(r) &&
@@ -543,7 +556,7 @@
}
static inline wuffs_base__range_ii_u32 //
-wuffs_base__range_ii_u32__intersect(wuffs_base__range_ii_u32* r,
+wuffs_base__range_ii_u32__intersect(const wuffs_base__range_ii_u32* r,
wuffs_base__range_ii_u32 s) {
wuffs_base__range_ii_u32 t;
t.min_incl = wuffs_base__u32__max(r->min_incl, s.min_incl);
@@ -552,7 +565,7 @@
}
static inline wuffs_base__range_ii_u32 //
-wuffs_base__range_ii_u32__unite(wuffs_base__range_ii_u32* r,
+wuffs_base__range_ii_u32__unite(const wuffs_base__range_ii_u32* r,
wuffs_base__range_ii_u32 s) {
if (wuffs_base__range_ii_u32__is_empty(r)) {
return s;
@@ -567,12 +580,13 @@
}
static inline bool //
-wuffs_base__range_ii_u32__contains(wuffs_base__range_ii_u32* r, uint32_t x) {
+wuffs_base__range_ii_u32__contains(const wuffs_base__range_ii_u32* r,
+ uint32_t x) {
return (r->min_incl <= x) && (x <= r->max_incl);
}
static inline bool //
-wuffs_base__range_ii_u32__contains_range(wuffs_base__range_ii_u32* r,
+wuffs_base__range_ii_u32__contains_range(const wuffs_base__range_ii_u32* r,
wuffs_base__range_ii_u32 s) {
return wuffs_base__range_ii_u32__equals(
&s, wuffs_base__range_ii_u32__intersect(r, s));
@@ -581,32 +595,32 @@
#ifdef __cplusplus
inline bool //
-wuffs_base__range_ii_u32::is_empty() {
+wuffs_base__range_ii_u32::is_empty() const {
return wuffs_base__range_ii_u32__is_empty(this);
}
inline bool //
-wuffs_base__range_ii_u32::equals(wuffs_base__range_ii_u32 s) {
+wuffs_base__range_ii_u32::equals(wuffs_base__range_ii_u32 s) const {
return wuffs_base__range_ii_u32__equals(this, s);
}
inline wuffs_base__range_ii_u32 //
-wuffs_base__range_ii_u32::intersect(wuffs_base__range_ii_u32 s) {
+wuffs_base__range_ii_u32::intersect(wuffs_base__range_ii_u32 s) const {
return wuffs_base__range_ii_u32__intersect(this, s);
}
inline wuffs_base__range_ii_u32 //
-wuffs_base__range_ii_u32::unite(wuffs_base__range_ii_u32 s) {
+wuffs_base__range_ii_u32::unite(wuffs_base__range_ii_u32 s) const {
return wuffs_base__range_ii_u32__unite(this, s);
}
inline bool //
-wuffs_base__range_ii_u32::contains(uint32_t x) {
+wuffs_base__range_ii_u32::contains(uint32_t x) const {
return wuffs_base__range_ii_u32__contains(this, x);
}
inline bool //
-wuffs_base__range_ii_u32::contains_range(wuffs_base__range_ii_u32 s) {
+wuffs_base__range_ii_u32::contains_range(wuffs_base__range_ii_u32 s) const {
return wuffs_base__range_ii_u32__contains_range(this, s);
}
@@ -619,15 +633,15 @@
uint32_t max_excl;
#ifdef __cplusplus
- inline bool is_empty();
- inline bool equals(wuffs_base__range_ie_u32__struct s);
+ inline bool is_empty() const;
+ inline bool equals(wuffs_base__range_ie_u32__struct s) const;
inline wuffs_base__range_ie_u32__struct intersect(
- wuffs_base__range_ie_u32__struct s);
+ wuffs_base__range_ie_u32__struct s) const;
inline wuffs_base__range_ie_u32__struct unite(
- wuffs_base__range_ie_u32__struct s);
- inline bool contains(uint32_t x);
- inline bool contains_range(wuffs_base__range_ie_u32__struct s);
- inline uint32_t length();
+ wuffs_base__range_ie_u32__struct s) const;
+ inline bool contains(uint32_t x) const;
+ inline bool contains_range(wuffs_base__range_ie_u32__struct s) const;
+ inline uint32_t length() const;
#endif // __cplusplus
} wuffs_base__range_ie_u32;
@@ -641,12 +655,12 @@
}
static inline bool //
-wuffs_base__range_ie_u32__is_empty(wuffs_base__range_ie_u32* r) {
+wuffs_base__range_ie_u32__is_empty(const wuffs_base__range_ie_u32* r) {
return r->min_incl >= r->max_excl;
}
static inline bool //
-wuffs_base__range_ie_u32__equals(wuffs_base__range_ie_u32* r,
+wuffs_base__range_ie_u32__equals(const wuffs_base__range_ie_u32* r,
wuffs_base__range_ie_u32 s) {
return (r->min_incl == s.min_incl && r->max_excl == s.max_excl) ||
(wuffs_base__range_ie_u32__is_empty(r) &&
@@ -654,7 +668,7 @@
}
static inline wuffs_base__range_ie_u32 //
-wuffs_base__range_ie_u32__intersect(wuffs_base__range_ie_u32* r,
+wuffs_base__range_ie_u32__intersect(const wuffs_base__range_ie_u32* r,
wuffs_base__range_ie_u32 s) {
wuffs_base__range_ie_u32 t;
t.min_incl = wuffs_base__u32__max(r->min_incl, s.min_incl);
@@ -663,7 +677,7 @@
}
static inline wuffs_base__range_ie_u32 //
-wuffs_base__range_ie_u32__unite(wuffs_base__range_ie_u32* r,
+wuffs_base__range_ie_u32__unite(const wuffs_base__range_ie_u32* r,
wuffs_base__range_ie_u32 s) {
if (wuffs_base__range_ie_u32__is_empty(r)) {
return s;
@@ -678,56 +692,57 @@
}
static inline bool //
-wuffs_base__range_ie_u32__contains(wuffs_base__range_ie_u32* r, uint32_t x) {
+wuffs_base__range_ie_u32__contains(const wuffs_base__range_ie_u32* r,
+ uint32_t x) {
return (r->min_incl <= x) && (x < r->max_excl);
}
static inline bool //
-wuffs_base__range_ie_u32__contains_range(wuffs_base__range_ie_u32* r,
+wuffs_base__range_ie_u32__contains_range(const wuffs_base__range_ie_u32* r,
wuffs_base__range_ie_u32 s) {
return wuffs_base__range_ie_u32__equals(
&s, wuffs_base__range_ie_u32__intersect(r, s));
}
static inline uint32_t //
-wuffs_base__range_ie_u32__length(wuffs_base__range_ie_u32* r) {
+wuffs_base__range_ie_u32__length(const wuffs_base__range_ie_u32* r) {
return wuffs_base__u32__sat_sub(r->max_excl, r->min_incl);
}
#ifdef __cplusplus
inline bool //
-wuffs_base__range_ie_u32::is_empty() {
+wuffs_base__range_ie_u32::is_empty() const {
return wuffs_base__range_ie_u32__is_empty(this);
}
inline bool //
-wuffs_base__range_ie_u32::equals(wuffs_base__range_ie_u32 s) {
+wuffs_base__range_ie_u32::equals(wuffs_base__range_ie_u32 s) const {
return wuffs_base__range_ie_u32__equals(this, s);
}
inline wuffs_base__range_ie_u32 //
-wuffs_base__range_ie_u32::intersect(wuffs_base__range_ie_u32 s) {
+wuffs_base__range_ie_u32::intersect(wuffs_base__range_ie_u32 s) const {
return wuffs_base__range_ie_u32__intersect(this, s);
}
inline wuffs_base__range_ie_u32 //
-wuffs_base__range_ie_u32::unite(wuffs_base__range_ie_u32 s) {
+wuffs_base__range_ie_u32::unite(wuffs_base__range_ie_u32 s) const {
return wuffs_base__range_ie_u32__unite(this, s);
}
inline bool //
-wuffs_base__range_ie_u32::contains(uint32_t x) {
+wuffs_base__range_ie_u32::contains(uint32_t x) const {
return wuffs_base__range_ie_u32__contains(this, x);
}
inline bool //
-wuffs_base__range_ie_u32::contains_range(wuffs_base__range_ie_u32 s) {
+wuffs_base__range_ie_u32::contains_range(wuffs_base__range_ie_u32 s) const {
return wuffs_base__range_ie_u32__contains_range(this, s);
}
inline uint32_t //
-wuffs_base__range_ie_u32::length() {
+wuffs_base__range_ie_u32::length() const {
return wuffs_base__range_ie_u32__length(this);
}
@@ -740,14 +755,14 @@
uint64_t max_incl;
#ifdef __cplusplus
- inline bool is_empty();
- inline bool equals(wuffs_base__range_ii_u64__struct s);
+ inline bool is_empty() const;
+ inline bool equals(wuffs_base__range_ii_u64__struct s) const;
inline wuffs_base__range_ii_u64__struct intersect(
- wuffs_base__range_ii_u64__struct s);
+ wuffs_base__range_ii_u64__struct s) const;
inline wuffs_base__range_ii_u64__struct unite(
- wuffs_base__range_ii_u64__struct s);
- inline bool contains(uint64_t x);
- inline bool contains_range(wuffs_base__range_ii_u64__struct s);
+ wuffs_base__range_ii_u64__struct s) const;
+ inline bool contains(uint64_t x) const;
+ inline bool contains_range(wuffs_base__range_ii_u64__struct s) const;
#endif // __cplusplus
} wuffs_base__range_ii_u64;
@@ -761,12 +776,12 @@
}
static inline bool //
-wuffs_base__range_ii_u64__is_empty(wuffs_base__range_ii_u64* r) {
+wuffs_base__range_ii_u64__is_empty(const wuffs_base__range_ii_u64* r) {
return r->min_incl > r->max_incl;
}
static inline bool //
-wuffs_base__range_ii_u64__equals(wuffs_base__range_ii_u64* r,
+wuffs_base__range_ii_u64__equals(const wuffs_base__range_ii_u64* r,
wuffs_base__range_ii_u64 s) {
return (r->min_incl == s.min_incl && r->max_incl == s.max_incl) ||
(wuffs_base__range_ii_u64__is_empty(r) &&
@@ -774,7 +789,7 @@
}
static inline wuffs_base__range_ii_u64 //
-wuffs_base__range_ii_u64__intersect(wuffs_base__range_ii_u64* r,
+wuffs_base__range_ii_u64__intersect(const wuffs_base__range_ii_u64* r,
wuffs_base__range_ii_u64 s) {
wuffs_base__range_ii_u64 t;
t.min_incl = wuffs_base__u64__max(r->min_incl, s.min_incl);
@@ -783,7 +798,7 @@
}
static inline wuffs_base__range_ii_u64 //
-wuffs_base__range_ii_u64__unite(wuffs_base__range_ii_u64* r,
+wuffs_base__range_ii_u64__unite(const wuffs_base__range_ii_u64* r,
wuffs_base__range_ii_u64 s) {
if (wuffs_base__range_ii_u64__is_empty(r)) {
return s;
@@ -798,12 +813,13 @@
}
static inline bool //
-wuffs_base__range_ii_u64__contains(wuffs_base__range_ii_u64* r, uint64_t x) {
+wuffs_base__range_ii_u64__contains(const wuffs_base__range_ii_u64* r,
+ uint64_t x) {
return (r->min_incl <= x) && (x <= r->max_incl);
}
static inline bool //
-wuffs_base__range_ii_u64__contains_range(wuffs_base__range_ii_u64* r,
+wuffs_base__range_ii_u64__contains_range(const wuffs_base__range_ii_u64* r,
wuffs_base__range_ii_u64 s) {
return wuffs_base__range_ii_u64__equals(
&s, wuffs_base__range_ii_u64__intersect(r, s));
@@ -812,32 +828,32 @@
#ifdef __cplusplus
inline bool //
-wuffs_base__range_ii_u64::is_empty() {
+wuffs_base__range_ii_u64::is_empty() const {
return wuffs_base__range_ii_u64__is_empty(this);
}
inline bool //
-wuffs_base__range_ii_u64::equals(wuffs_base__range_ii_u64 s) {
+wuffs_base__range_ii_u64::equals(wuffs_base__range_ii_u64 s) const {
return wuffs_base__range_ii_u64__equals(this, s);
}
inline wuffs_base__range_ii_u64 //
-wuffs_base__range_ii_u64::intersect(wuffs_base__range_ii_u64 s) {
+wuffs_base__range_ii_u64::intersect(wuffs_base__range_ii_u64 s) const {
return wuffs_base__range_ii_u64__intersect(this, s);
}
inline wuffs_base__range_ii_u64 //
-wuffs_base__range_ii_u64::unite(wuffs_base__range_ii_u64 s) {
+wuffs_base__range_ii_u64::unite(wuffs_base__range_ii_u64 s) const {
return wuffs_base__range_ii_u64__unite(this, s);
}
inline bool //
-wuffs_base__range_ii_u64::contains(uint64_t x) {
+wuffs_base__range_ii_u64::contains(uint64_t x) const {
return wuffs_base__range_ii_u64__contains(this, x);
}
inline bool //
-wuffs_base__range_ii_u64::contains_range(wuffs_base__range_ii_u64 s) {
+wuffs_base__range_ii_u64::contains_range(wuffs_base__range_ii_u64 s) const {
return wuffs_base__range_ii_u64__contains_range(this, s);
}
@@ -850,15 +866,15 @@
uint64_t max_excl;
#ifdef __cplusplus
- inline bool is_empty();
- inline bool equals(wuffs_base__range_ie_u64__struct s);
+ inline bool is_empty() const;
+ inline bool equals(wuffs_base__range_ie_u64__struct s) const;
inline wuffs_base__range_ie_u64__struct intersect(
- wuffs_base__range_ie_u64__struct s);
+ wuffs_base__range_ie_u64__struct s) const;
inline wuffs_base__range_ie_u64__struct unite(
- wuffs_base__range_ie_u64__struct s);
- inline bool contains(uint64_t x);
- inline bool contains_range(wuffs_base__range_ie_u64__struct s);
- inline uint64_t length();
+ wuffs_base__range_ie_u64__struct s) const;
+ inline bool contains(uint64_t x) const;
+ inline bool contains_range(wuffs_base__range_ie_u64__struct s) const;
+ inline uint64_t length() const;
#endif // __cplusplus
} wuffs_base__range_ie_u64;
@@ -872,12 +888,12 @@
}
static inline bool //
-wuffs_base__range_ie_u64__is_empty(wuffs_base__range_ie_u64* r) {
+wuffs_base__range_ie_u64__is_empty(const wuffs_base__range_ie_u64* r) {
return r->min_incl >= r->max_excl;
}
static inline bool //
-wuffs_base__range_ie_u64__equals(wuffs_base__range_ie_u64* r,
+wuffs_base__range_ie_u64__equals(const wuffs_base__range_ie_u64* r,
wuffs_base__range_ie_u64 s) {
return (r->min_incl == s.min_incl && r->max_excl == s.max_excl) ||
(wuffs_base__range_ie_u64__is_empty(r) &&
@@ -885,7 +901,7 @@
}
static inline wuffs_base__range_ie_u64 //
-wuffs_base__range_ie_u64__intersect(wuffs_base__range_ie_u64* r,
+wuffs_base__range_ie_u64__intersect(const wuffs_base__range_ie_u64* r,
wuffs_base__range_ie_u64 s) {
wuffs_base__range_ie_u64 t;
t.min_incl = wuffs_base__u64__max(r->min_incl, s.min_incl);
@@ -894,7 +910,7 @@
}
static inline wuffs_base__range_ie_u64 //
-wuffs_base__range_ie_u64__unite(wuffs_base__range_ie_u64* r,
+wuffs_base__range_ie_u64__unite(const wuffs_base__range_ie_u64* r,
wuffs_base__range_ie_u64 s) {
if (wuffs_base__range_ie_u64__is_empty(r)) {
return s;
@@ -909,56 +925,57 @@
}
static inline bool //
-wuffs_base__range_ie_u64__contains(wuffs_base__range_ie_u64* r, uint64_t x) {
+wuffs_base__range_ie_u64__contains(const wuffs_base__range_ie_u64* r,
+ uint64_t x) {
return (r->min_incl <= x) && (x < r->max_excl);
}
static inline bool //
-wuffs_base__range_ie_u64__contains_range(wuffs_base__range_ie_u64* r,
+wuffs_base__range_ie_u64__contains_range(const wuffs_base__range_ie_u64* r,
wuffs_base__range_ie_u64 s) {
return wuffs_base__range_ie_u64__equals(
&s, wuffs_base__range_ie_u64__intersect(r, s));
}
static inline uint64_t //
-wuffs_base__range_ie_u64__length(wuffs_base__range_ie_u64* r) {
+wuffs_base__range_ie_u64__length(const wuffs_base__range_ie_u64* r) {
return wuffs_base__u64__sat_sub(r->max_excl, r->min_incl);
}
#ifdef __cplusplus
inline bool //
-wuffs_base__range_ie_u64::is_empty() {
+wuffs_base__range_ie_u64::is_empty() const {
return wuffs_base__range_ie_u64__is_empty(this);
}
inline bool //
-wuffs_base__range_ie_u64::equals(wuffs_base__range_ie_u64 s) {
+wuffs_base__range_ie_u64::equals(wuffs_base__range_ie_u64 s) const {
return wuffs_base__range_ie_u64__equals(this, s);
}
inline wuffs_base__range_ie_u64 //
-wuffs_base__range_ie_u64::intersect(wuffs_base__range_ie_u64 s) {
+wuffs_base__range_ie_u64::intersect(wuffs_base__range_ie_u64 s) const {
return wuffs_base__range_ie_u64__intersect(this, s);
}
inline wuffs_base__range_ie_u64 //
-wuffs_base__range_ie_u64::unite(wuffs_base__range_ie_u64 s) {
+wuffs_base__range_ie_u64::unite(wuffs_base__range_ie_u64 s) const {
return wuffs_base__range_ie_u64__unite(this, s);
}
inline bool //
-wuffs_base__range_ie_u64::contains(uint64_t x) {
+wuffs_base__range_ie_u64::contains(uint64_t x) const {
return wuffs_base__range_ie_u64__contains(this, x);
}
inline bool //
-wuffs_base__range_ie_u64::contains_range(wuffs_base__range_ie_u64 s) {
+wuffs_base__range_ie_u64::contains_range(wuffs_base__range_ie_u64 s) const {
return wuffs_base__range_ie_u64__contains_range(this, s);
}
inline uint64_t //
-wuffs_base__range_ie_u64::length() {
+wuffs_base__range_ie_u64::length() const {
return wuffs_base__range_ie_u64__length(this);
}
@@ -982,14 +999,14 @@
uint32_t max_incl_y;
#ifdef __cplusplus
- inline bool is_empty();
- inline bool equals(wuffs_base__rect_ii_u32__struct s);
+ inline bool is_empty() const;
+ inline bool equals(wuffs_base__rect_ii_u32__struct s) const;
inline wuffs_base__rect_ii_u32__struct intersect(
- wuffs_base__rect_ii_u32__struct s);
+ wuffs_base__rect_ii_u32__struct s) const;
inline wuffs_base__rect_ii_u32__struct unite(
- wuffs_base__rect_ii_u32__struct s);
- inline bool contains(uint32_t x, uint32_t y);
- inline bool contains_rect(wuffs_base__rect_ii_u32__struct s);
+ wuffs_base__rect_ii_u32__struct s) const;
+ inline bool contains(uint32_t x, uint32_t y) const;
+ inline bool contains_rect(wuffs_base__rect_ii_u32__struct s) const;
#endif // __cplusplus
} wuffs_base__rect_ii_u32;
@@ -1008,12 +1025,12 @@
}
static inline bool //
-wuffs_base__rect_ii_u32__is_empty(wuffs_base__rect_ii_u32* r) {
+wuffs_base__rect_ii_u32__is_empty(const wuffs_base__rect_ii_u32* r) {
return (r->min_incl_x > r->max_incl_x) || (r->min_incl_y > r->max_incl_y);
}
static inline bool //
-wuffs_base__rect_ii_u32__equals(wuffs_base__rect_ii_u32* r,
+wuffs_base__rect_ii_u32__equals(const wuffs_base__rect_ii_u32* r,
wuffs_base__rect_ii_u32 s) {
return (r->min_incl_x == s.min_incl_x && r->min_incl_y == s.min_incl_y &&
r->max_incl_x == s.max_incl_x && r->max_incl_y == s.max_incl_y) ||
@@ -1022,7 +1039,7 @@
}
static inline wuffs_base__rect_ii_u32 //
-wuffs_base__rect_ii_u32__intersect(wuffs_base__rect_ii_u32* r,
+wuffs_base__rect_ii_u32__intersect(const wuffs_base__rect_ii_u32* r,
wuffs_base__rect_ii_u32 s) {
wuffs_base__rect_ii_u32 t;
t.min_incl_x = wuffs_base__u32__max(r->min_incl_x, s.min_incl_x);
@@ -1033,7 +1050,7 @@
}
static inline wuffs_base__rect_ii_u32 //
-wuffs_base__rect_ii_u32__unite(wuffs_base__rect_ii_u32* r,
+wuffs_base__rect_ii_u32__unite(const wuffs_base__rect_ii_u32* r,
wuffs_base__rect_ii_u32 s) {
if (wuffs_base__rect_ii_u32__is_empty(r)) {
return s;
@@ -1050,7 +1067,7 @@
}
static inline bool //
-wuffs_base__rect_ii_u32__contains(wuffs_base__rect_ii_u32* r,
+wuffs_base__rect_ii_u32__contains(const wuffs_base__rect_ii_u32* r,
uint32_t x,
uint32_t y) {
return (r->min_incl_x <= x) && (x <= r->max_incl_x) && (r->min_incl_y <= y) &&
@@ -1058,7 +1075,7 @@
}
static inline bool //
-wuffs_base__rect_ii_u32__contains_rect(wuffs_base__rect_ii_u32* r,
+wuffs_base__rect_ii_u32__contains_rect(const wuffs_base__rect_ii_u32* r,
wuffs_base__rect_ii_u32 s) {
return wuffs_base__rect_ii_u32__equals(
&s, wuffs_base__rect_ii_u32__intersect(r, s));
@@ -1067,32 +1084,32 @@
#ifdef __cplusplus
inline bool //
-wuffs_base__rect_ii_u32::is_empty() {
+wuffs_base__rect_ii_u32::is_empty() const {
return wuffs_base__rect_ii_u32__is_empty(this);
}
inline bool //
-wuffs_base__rect_ii_u32::equals(wuffs_base__rect_ii_u32 s) {
+wuffs_base__rect_ii_u32::equals(wuffs_base__rect_ii_u32 s) const {
return wuffs_base__rect_ii_u32__equals(this, s);
}
inline wuffs_base__rect_ii_u32 //
-wuffs_base__rect_ii_u32::intersect(wuffs_base__rect_ii_u32 s) {
+wuffs_base__rect_ii_u32::intersect(wuffs_base__rect_ii_u32 s) const {
return wuffs_base__rect_ii_u32__intersect(this, s);
}
inline wuffs_base__rect_ii_u32 //
-wuffs_base__rect_ii_u32::unite(wuffs_base__rect_ii_u32 s) {
+wuffs_base__rect_ii_u32::unite(wuffs_base__rect_ii_u32 s) const {
return wuffs_base__rect_ii_u32__unite(this, s);
}
inline bool //
-wuffs_base__rect_ii_u32::contains(uint32_t x, uint32_t y) {
+wuffs_base__rect_ii_u32::contains(uint32_t x, uint32_t y) const {
return wuffs_base__rect_ii_u32__contains(this, x, y);
}
inline bool //
-wuffs_base__rect_ii_u32::contains_rect(wuffs_base__rect_ii_u32 s) {
+wuffs_base__rect_ii_u32::contains_rect(wuffs_base__rect_ii_u32 s) const {
return wuffs_base__rect_ii_u32__contains_rect(this, s);
}
@@ -1117,16 +1134,16 @@
uint32_t max_excl_y;
#ifdef __cplusplus
- inline bool is_empty();
- inline bool equals(wuffs_base__rect_ie_u32__struct s);
+ inline bool is_empty() const;
+ inline bool equals(wuffs_base__rect_ie_u32__struct s) const;
inline wuffs_base__rect_ie_u32__struct intersect(
- wuffs_base__rect_ie_u32__struct s);
+ wuffs_base__rect_ie_u32__struct s) const;
inline wuffs_base__rect_ie_u32__struct unite(
- wuffs_base__rect_ie_u32__struct s);
- inline bool contains(uint32_t x, uint32_t y);
- inline bool contains_rect(wuffs_base__rect_ie_u32__struct s);
- inline uint32_t width();
- inline uint32_t height();
+ wuffs_base__rect_ie_u32__struct s) const;
+ inline bool contains(uint32_t x, uint32_t y) const;
+ inline bool contains_rect(wuffs_base__rect_ie_u32__struct s) const;
+ inline uint32_t width() const;
+ inline uint32_t height() const;
#endif // __cplusplus
} wuffs_base__rect_ie_u32;
@@ -1145,12 +1162,12 @@
}
static inline bool //
-wuffs_base__rect_ie_u32__is_empty(wuffs_base__rect_ie_u32* r) {
+wuffs_base__rect_ie_u32__is_empty(const wuffs_base__rect_ie_u32* r) {
return (r->min_incl_x >= r->max_excl_x) || (r->min_incl_y >= r->max_excl_y);
}
static inline bool //
-wuffs_base__rect_ie_u32__equals(wuffs_base__rect_ie_u32* r,
+wuffs_base__rect_ie_u32__equals(const wuffs_base__rect_ie_u32* r,
wuffs_base__rect_ie_u32 s) {
return (r->min_incl_x == s.min_incl_x && r->min_incl_y == s.min_incl_y &&
r->max_excl_x == s.max_excl_x && r->max_excl_y == s.max_excl_y) ||
@@ -1159,7 +1176,7 @@
}
static inline wuffs_base__rect_ie_u32 //
-wuffs_base__rect_ie_u32__intersect(wuffs_base__rect_ie_u32* r,
+wuffs_base__rect_ie_u32__intersect(const wuffs_base__rect_ie_u32* r,
wuffs_base__rect_ie_u32 s) {
wuffs_base__rect_ie_u32 t;
t.min_incl_x = wuffs_base__u32__max(r->min_incl_x, s.min_incl_x);
@@ -1170,7 +1187,7 @@
}
static inline wuffs_base__rect_ie_u32 //
-wuffs_base__rect_ie_u32__unite(wuffs_base__rect_ie_u32* r,
+wuffs_base__rect_ie_u32__unite(const wuffs_base__rect_ie_u32* r,
wuffs_base__rect_ie_u32 s) {
if (wuffs_base__rect_ie_u32__is_empty(r)) {
return s;
@@ -1187,7 +1204,7 @@
}
static inline bool //
-wuffs_base__rect_ie_u32__contains(wuffs_base__rect_ie_u32* r,
+wuffs_base__rect_ie_u32__contains(const wuffs_base__rect_ie_u32* r,
uint32_t x,
uint32_t y) {
return (r->min_incl_x <= x) && (x < r->max_excl_x) && (r->min_incl_y <= y) &&
@@ -1195,95 +1212,69 @@
}
static inline bool //
-wuffs_base__rect_ie_u32__contains_rect(wuffs_base__rect_ie_u32* r,
+wuffs_base__rect_ie_u32__contains_rect(const wuffs_base__rect_ie_u32* r,
wuffs_base__rect_ie_u32 s) {
return wuffs_base__rect_ie_u32__equals(
&s, wuffs_base__rect_ie_u32__intersect(r, s));
}
static inline uint32_t //
-wuffs_base__rect_ie_u32__width(wuffs_base__rect_ie_u32* r) {
+wuffs_base__rect_ie_u32__width(const wuffs_base__rect_ie_u32* r) {
return wuffs_base__u32__sat_sub(r->max_excl_x, r->min_incl_x);
}
static inline uint32_t //
-wuffs_base__rect_ie_u32__height(wuffs_base__rect_ie_u32* r) {
+wuffs_base__rect_ie_u32__height(const wuffs_base__rect_ie_u32* r) {
return wuffs_base__u32__sat_sub(r->max_excl_y, r->min_incl_y);
}
#ifdef __cplusplus
inline bool //
-wuffs_base__rect_ie_u32::is_empty() {
+wuffs_base__rect_ie_u32::is_empty() const {
return wuffs_base__rect_ie_u32__is_empty(this);
}
inline bool //
-wuffs_base__rect_ie_u32::equals(wuffs_base__rect_ie_u32 s) {
+wuffs_base__rect_ie_u32::equals(wuffs_base__rect_ie_u32 s) const {
return wuffs_base__rect_ie_u32__equals(this, s);
}
inline wuffs_base__rect_ie_u32 //
-wuffs_base__rect_ie_u32::intersect(wuffs_base__rect_ie_u32 s) {
+wuffs_base__rect_ie_u32::intersect(wuffs_base__rect_ie_u32 s) const {
return wuffs_base__rect_ie_u32__intersect(this, s);
}
inline wuffs_base__rect_ie_u32 //
-wuffs_base__rect_ie_u32::unite(wuffs_base__rect_ie_u32 s) {
+wuffs_base__rect_ie_u32::unite(wuffs_base__rect_ie_u32 s) const {
return wuffs_base__rect_ie_u32__unite(this, s);
}
inline bool //
-wuffs_base__rect_ie_u32::contains(uint32_t x, uint32_t y) {
+wuffs_base__rect_ie_u32::contains(uint32_t x, uint32_t y) const {
return wuffs_base__rect_ie_u32__contains(this, x, y);
}
inline bool //
-wuffs_base__rect_ie_u32::contains_rect(wuffs_base__rect_ie_u32 s) {
+wuffs_base__rect_ie_u32::contains_rect(wuffs_base__rect_ie_u32 s) const {
return wuffs_base__rect_ie_u32__contains_rect(this, s);
}
inline uint32_t //
-wuffs_base__rect_ie_u32::width() {
+wuffs_base__rect_ie_u32::width() const {
return wuffs_base__rect_ie_u32__width(this);
}
inline uint32_t //
-wuffs_base__rect_ie_u32::height() {
+wuffs_base__rect_ie_u32::height() const {
return wuffs_base__rect_ie_u32__height(this);
}
#endif // __cplusplus
// ---------------- I/O
-
-struct wuffs_base__io_buffer__struct;
-
-typedef struct {
- // Do not access the private_impl's fields directly. There is no API/ABI
- // compatibility or safety guarantee if you do so.
- struct {
- struct wuffs_base__io_buffer__struct* buf;
- // The bounds values are typically NULL, when created by the Wuffs public
- // API. NULL means that the callee substitutes the implicit bounds derived
- // from buf.
- uint8_t* mark;
- uint8_t* limit;
- } private_impl;
-} wuffs_base__io_reader;
-
-typedef struct {
- // Do not access the private_impl's fields directly. There is no API/ABI
- // compatibility or safety guarantee if you do so.
- struct {
- struct wuffs_base__io_buffer__struct* buf;
- // The bounds values are typically NULL, when created by the Wuffs public
- // API. NULL means that the callee substitutes the implicit bounds derived
- // from buf.
- uint8_t* mark;
- uint8_t* limit;
- } private_impl;
-} wuffs_base__io_writer;
+//
+// See (/doc/note/io-input-output.md).
// wuffs_base__io_buffer_meta is the metadata for a wuffs_base__io_buffer's
// data.
@@ -1304,10 +1295,12 @@
#ifdef __cplusplus
inline void compact();
- inline wuffs_base__io_reader reader();
- inline wuffs_base__io_writer writer();
- inline uint64_t reader_io_position();
- inline uint64_t writer_io_position();
+ inline wuffs_base__io_buffer__struct* reader(); // Deprecated.
+ inline wuffs_base__io_buffer__struct* writer(); // Deprecated.
+ inline uint64_t reader_available() const;
+ inline uint64_t reader_io_position() const;
+ inline uint64_t writer_available() const;
+ inline uint64_t writer_io_position() const;
#endif // __cplusplus
} wuffs_base__io_buffer;
@@ -1356,24 +1349,6 @@
return ret;
}
-static inline wuffs_base__io_reader //
-wuffs_base__null_io_reader() {
- wuffs_base__io_reader ret;
- ret.private_impl.buf = NULL;
- ret.private_impl.mark = NULL;
- ret.private_impl.limit = NULL;
- return ret;
-}
-
-static inline wuffs_base__io_writer //
-wuffs_base__null_io_writer() {
- wuffs_base__io_writer ret;
- ret.private_impl.buf = NULL;
- ret.private_impl.mark = NULL;
- ret.private_impl.limit = NULL;
- return ret;
-}
-
// wuffs_base__io_buffer__compact moves any written but unread bytes to the
// start of the buffer.
static inline void //
@@ -1390,31 +1365,23 @@
buf->meta.ri = 0;
}
-static inline wuffs_base__io_reader //
-wuffs_base__io_buffer__reader(wuffs_base__io_buffer* buf) {
- wuffs_base__io_reader ret;
- ret.private_impl.buf = buf;
- ret.private_impl.mark = NULL;
- ret.private_impl.limit = NULL;
- return ret;
-}
-
-static inline wuffs_base__io_writer //
-wuffs_base__io_buffer__writer(wuffs_base__io_buffer* buf) {
- wuffs_base__io_writer ret;
- ret.private_impl.buf = buf;
- ret.private_impl.mark = NULL;
- ret.private_impl.limit = NULL;
- return ret;
+static inline uint64_t //
+wuffs_base__io_buffer__reader_available(const wuffs_base__io_buffer* buf) {
+ return buf ? buf->meta.wi - buf->meta.ri : 0;
}
static inline uint64_t //
-wuffs_base__io_buffer__reader_io_position(wuffs_base__io_buffer* buf) {
+wuffs_base__io_buffer__reader_io_position(const wuffs_base__io_buffer* buf) {
return buf ? wuffs_base__u64__sat_add(buf->meta.pos, buf->meta.ri) : 0;
}
static inline uint64_t //
-wuffs_base__io_buffer__writer_io_position(wuffs_base__io_buffer* buf) {
+wuffs_base__io_buffer__writer_available(const wuffs_base__io_buffer* buf) {
+ return buf ? buf->data.len - buf->meta.wi : 0;
+}
+
+static inline uint64_t //
+wuffs_base__io_buffer__writer_io_position(const wuffs_base__io_buffer* buf) {
return buf ? wuffs_base__u64__sat_add(buf->meta.pos, buf->meta.wi) : 0;
}
@@ -1425,23 +1392,33 @@
wuffs_base__io_buffer__compact(this);
}
-inline wuffs_base__io_reader //
+inline wuffs_base__io_buffer* //
wuffs_base__io_buffer__struct::reader() {
- return wuffs_base__io_buffer__reader(this);
+ return this;
}
-inline wuffs_base__io_writer //
+inline wuffs_base__io_buffer* //
wuffs_base__io_buffer__struct::writer() {
- return wuffs_base__io_buffer__writer(this);
+ return this;
}
inline uint64_t //
-wuffs_base__io_buffer__struct::reader_io_position() {
+wuffs_base__io_buffer__struct::reader_available() const {
+ return wuffs_base__io_buffer__reader_available(this);
+}
+
+inline uint64_t //
+wuffs_base__io_buffer__struct::reader_io_position() const {
return wuffs_base__io_buffer__reader_io_position(this);
}
inline uint64_t //
-wuffs_base__io_buffer__struct::writer_io_position() {
+wuffs_base__io_buffer__struct::writer_available() const {
+ return wuffs_base__io_buffer__writer_available(this);
+}
+
+inline uint64_t //
+wuffs_base__io_buffer__struct::writer_io_position() const {
return wuffs_base__io_buffer__writer_io_position(this);
}
@@ -1525,9 +1502,9 @@
// - bit 20 indicates big-endian/MSB-first (as opposed to little/LSB).
// - bit 19 indicates floating point (as opposed to integer).
// - bit 18 indicates palette-indexed. The number-of-planes (the next
-// field) will be zero, as the format is considered packed,
+// field) will be 0, as the format is considered interleaved,
// but the 8-bit N-BGRA color data is stored in plane 3.
-// - bits 17 .. 16 are the number of planes, minus 1. Zero means packed.
+// - bits 17 .. 16 are the number of planes, minus 1. Zero means interleaved.
// - bits 15 .. 12 encodes the number of bits (depth) in the 3rd channel.
// - bits 11 .. 8 encodes the number of bits (depth) in the 2nd channel.
// - bits 7 .. 4 encodes the number of bits (depth) in the 1st channel.
@@ -1544,14 +1521,14 @@
// channels: cyan, magenta, yellow, black).
//
// For direct formats with N > 1 channels, those channels can be laid out in
-// either 1 (packed) or N (planar) planes. For example, RGBA data is usually
-// packed, but YCbCr data is usually planar, due to chroma subsampling (for
-// details, see the wuffs_base__pixel_subsampling type).
+// either 1 (interleaved) or N (planar) planes. For example, RGBA data is
+// usually interleaved, but YCbCr data is usually planar, due to chroma
+// subsampling (for details, see the wuffs_base__pixel_subsampling type).
//
// For indexed formats, the palette (always 256 × 4 bytes) holds 8 bits per
// channel non-alpha-premultiplied BGRA color data. There is only 1 plane (for
-// the index), as the format is considered packed. Plane 0 holds the per-pixel
-// indices. Plane 3 is re-purposed to hold the per-index colors.
+// the index), as the format is considered interleaved. Plane 0 holds the
+// per-pixel indices. Plane 3 is re-purposed to hold the per-index colors.
//
// The color field is encoded in 3 bits:
// - 0 means A (Alpha).
@@ -1565,8 +1542,8 @@
//
// In Wuffs, channels are given in memory order (also known as byte order),
// regardless of endianness, since the C type for the pixel data is an array of
-// bytes, not an array of uint32_t. For example, packed BGRA with 8 bits per
-// channel means that the bytes in memory are always Blue, Green, Red then
+// bytes, not an array of uint32_t. For example, interleaved BGRA with 8 bits
+// per channel means that the bytes in memory are always Blue, Green, Red then
// Alpha. On big-endian systems, that is the uint32_t 0xBBGGRRAA. On
// little-endian, 0xAARRGGBB.
//
@@ -1599,15 +1576,15 @@
//
// For example, wuffs_base__pixel_format 0x5510BBBB is a natural format for
// decoding a PNG image - network byte order (also known as big-endian),
-// packed, non-premultiplied alpha - that happens to be 16-bit-depth truecolor
-// with alpha (RGBA). In memory order:
+// interleaved, non-premultiplied alpha - that happens to be 16-bit-depth
+// truecolor with alpha (RGBA). In memory order:
//
// ptr+0 ptr+1 ptr+2 ptr+3 ptr+4 ptr+5 ptr+6 ptr+7
// Rhi Rlo Ghi Glo Bhi Blo Ahi Alo
//
// For example, the value wuffs_base__pixel_format 0x40000565 means BGR with no
-// alpha or padding, 5/6/5 bits for blue/green/red, packed 2 bytes per pixel,
-// laid out LSB-first in memory order:
+// alpha or padding, 5/6/5 bits for blue/green/red, interleaved 2 bytes per
+// pixel, laid out LSB-first in memory order:
//
// ptr+0........... ptr+1...........
// MSB LSB MSB LSB
@@ -1692,8 +1669,8 @@
return f != 0;
}
-// wuffs_base__pixel_format__bits_per_pixel returns, for packed pixel formats,
-// the number of bits per pixel. It returns 0 for planar pixel formats.
+// 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) {
@@ -1711,7 +1688,7 @@
}
static inline bool //
-wuffs_base__pixel_format__is_packed(wuffs_base__pixel_format f) {
+wuffs_base__pixel_format__is_interleaved(wuffs_base__pixel_format f) {
return ((f >> 16) & 0x03) == 0;
}
@@ -1737,7 +1714,7 @@
// plane p. For a depth of 8 bits (1 byte), the p'th plane's sample starts at
// (planes[p].ptr + (j * planes[p].stride) + i).
//
-// For packed pixel formats, the mapping is trivial: i = x and j = y. For
+// For interleaved pixel formats, the mapping is trivial: i = x and j = y. For
// planar pixel formats, the mapping can differ due to chroma subsampling. For
// example, consider a three plane YCbCr pixel format with 4:2:2 subsampling.
// For the luma (Y) channel, there is one sample for every pixel, but for the
@@ -1828,13 +1805,13 @@
uint32_t width,
uint32_t height);
inline void invalidate();
- inline bool is_valid();
- inline wuffs_base__pixel_format pixel_format();
- inline wuffs_base__pixel_subsampling pixel_subsampling();
- inline wuffs_base__rect_ie_u32 bounds();
- inline uint32_t width();
- inline uint32_t height();
- inline uint64_t pixbuf_len();
+ inline bool is_valid() const;
+ inline wuffs_base__pixel_format pixel_format() const;
+ inline wuffs_base__pixel_subsampling pixel_subsampling() const;
+ inline wuffs_base__rect_ie_u32 bounds() const;
+ inline uint32_t width() const;
+ inline uint32_t height() const;
+ inline uint64_t pixbuf_len() const;
#endif // __cplusplus
} wuffs_base__pixel_config;
@@ -1888,22 +1865,22 @@
}
static inline bool //
-wuffs_base__pixel_config__is_valid(wuffs_base__pixel_config* c) {
+wuffs_base__pixel_config__is_valid(const wuffs_base__pixel_config* c) {
return c && c->private_impl.pixfmt;
}
static inline wuffs_base__pixel_format //
-wuffs_base__pixel_config__pixel_format(wuffs_base__pixel_config* c) {
+wuffs_base__pixel_config__pixel_format(const wuffs_base__pixel_config* c) {
return c ? c->private_impl.pixfmt : 0;
}
static inline wuffs_base__pixel_subsampling //
-wuffs_base__pixel_config__pixel_subsampling(wuffs_base__pixel_config* c) {
+wuffs_base__pixel_config__pixel_subsampling(const wuffs_base__pixel_config* c) {
return c ? c->private_impl.pixsub : 0;
}
static inline wuffs_base__rect_ie_u32 //
-wuffs_base__pixel_config__bounds(wuffs_base__pixel_config* c) {
+wuffs_base__pixel_config__bounds(const wuffs_base__pixel_config* c) {
if (c) {
wuffs_base__rect_ie_u32 ret;
ret.min_incl_x = 0;
@@ -1922,20 +1899,20 @@
}
static inline uint32_t //
-wuffs_base__pixel_config__width(wuffs_base__pixel_config* c) {
+wuffs_base__pixel_config__width(const wuffs_base__pixel_config* c) {
return c ? c->private_impl.width : 0;
}
static inline uint32_t //
-wuffs_base__pixel_config__height(wuffs_base__pixel_config* c) {
+wuffs_base__pixel_config__height(const wuffs_base__pixel_config* c) {
return c ? c->private_impl.height : 0;
}
-// TODO: this is the right API for planar (not packed) pixbufs? Should it allow
-// decoding into a color model different from the format's intrinsic one? For
-// example, decoding a JPEG image straight to RGBA instead of to YCbCr?
+// TODO: this is the right API for planar (not interleaved) pixbufs? Should it
+// allow decoding into a color model different from the format's intrinsic one?
+// For example, decoding a JPEG image straight to RGBA instead of to YCbCr?
static inline uint64_t //
-wuffs_base__pixel_config__pixbuf_len(wuffs_base__pixel_config* c) {
+wuffs_base__pixel_config__pixbuf_len(const wuffs_base__pixel_config* c) {
if (!c) {
return 0;
}
@@ -1984,37 +1961,37 @@
}
inline bool //
-wuffs_base__pixel_config::is_valid() {
+wuffs_base__pixel_config::is_valid() const {
return wuffs_base__pixel_config__is_valid(this);
}
inline wuffs_base__pixel_format //
-wuffs_base__pixel_config::pixel_format() {
+wuffs_base__pixel_config::pixel_format() const {
return wuffs_base__pixel_config__pixel_format(this);
}
inline wuffs_base__pixel_subsampling //
-wuffs_base__pixel_config::pixel_subsampling() {
+wuffs_base__pixel_config::pixel_subsampling() const {
return wuffs_base__pixel_config__pixel_subsampling(this);
}
inline wuffs_base__rect_ie_u32 //
-wuffs_base__pixel_config::bounds() {
+wuffs_base__pixel_config::bounds() const {
return wuffs_base__pixel_config__bounds(this);
}
inline uint32_t //
-wuffs_base__pixel_config::width() {
+wuffs_base__pixel_config::width() const {
return wuffs_base__pixel_config__width(this);
}
inline uint32_t //
-wuffs_base__pixel_config::height() {
+wuffs_base__pixel_config::height() const {
return wuffs_base__pixel_config__height(this);
}
inline uint64_t //
-wuffs_base__pixel_config::pixbuf_len() {
+wuffs_base__pixel_config::pixbuf_len() const {
return wuffs_base__pixel_config__pixbuf_len(this);
}
@@ -2040,9 +2017,9 @@
uint64_t first_frame_io_position,
bool first_frame_is_opaque);
inline void invalidate();
- inline bool is_valid();
- inline uint64_t first_frame_io_position();
- inline bool first_frame_is_opaque();
+ inline bool is_valid() const;
+ inline uint64_t first_frame_io_position() const;
+ inline bool first_frame_is_opaque() const;
#endif // __cplusplus
} wuffs_base__image_config;
@@ -2099,17 +2076,19 @@
}
static inline bool //
-wuffs_base__image_config__is_valid(wuffs_base__image_config* c) {
+wuffs_base__image_config__is_valid(const wuffs_base__image_config* c) {
return c && wuffs_base__pixel_config__is_valid(&(c->pixcfg));
}
static inline uint64_t //
-wuffs_base__image_config__first_frame_io_position(wuffs_base__image_config* c) {
+wuffs_base__image_config__first_frame_io_position(
+ const wuffs_base__image_config* c) {
return c ? c->private_impl.first_frame_io_position : 0;
}
static inline bool //
-wuffs_base__image_config__first_frame_is_opaque(wuffs_base__image_config* c) {
+wuffs_base__image_config__first_frame_is_opaque(
+ const wuffs_base__image_config* c) {
return c ? c->private_impl.first_frame_is_opaque : false;
}
@@ -2132,17 +2111,17 @@
}
inline bool //
-wuffs_base__image_config::is_valid() {
+wuffs_base__image_config::is_valid() const {
return wuffs_base__image_config__is_valid(this);
}
inline uint64_t //
-wuffs_base__image_config::first_frame_io_position() {
+wuffs_base__image_config::first_frame_io_position() const {
return wuffs_base__image_config__first_frame_io_position(this);
}
inline bool //
-wuffs_base__image_config::first_frame_is_opaque() {
+wuffs_base__image_config::first_frame_is_opaque() const {
return wuffs_base__image_config__first_frame_is_opaque(this);
}
@@ -2198,6 +2177,7 @@
uint64_t io_position;
wuffs_base__animation_blend blend;
wuffs_base__animation_disposal disposal;
+ wuffs_base__color_u32_argb_premul background_color;
} private_impl;
#ifdef __cplusplus
@@ -2206,15 +2186,17 @@
uint64_t index,
uint64_t io_position,
wuffs_base__animation_blend blend,
- wuffs_base__animation_disposal disposal);
- inline wuffs_base__rect_ie_u32 bounds();
- inline uint32_t width();
- inline uint32_t height();
- inline wuffs_base__flicks duration();
- inline uint64_t index();
- inline uint64_t io_position();
- inline wuffs_base__animation_blend blend();
- inline wuffs_base__animation_disposal disposal();
+ wuffs_base__animation_disposal disposal,
+ wuffs_base__color_u32_argb_premul background_color);
+ inline wuffs_base__rect_ie_u32 bounds() const;
+ inline uint32_t width() const;
+ inline uint32_t height() const;
+ 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 wuffs_base__color_u32_argb_premul background_color() const;
#endif // __cplusplus
} wuffs_base__frame_config;
@@ -2232,13 +2214,15 @@
}
static inline void //
-wuffs_base__frame_config__update(wuffs_base__frame_config* c,
- wuffs_base__rect_ie_u32 bounds,
- wuffs_base__flicks duration,
- uint64_t index,
- uint64_t io_position,
- wuffs_base__animation_blend blend,
- wuffs_base__animation_disposal disposal) {
+wuffs_base__frame_config__update(
+ wuffs_base__frame_config* c,
+ wuffs_base__rect_ie_u32 bounds,
+ wuffs_base__flicks duration,
+ uint64_t index,
+ uint64_t io_position,
+ wuffs_base__animation_blend blend,
+ wuffs_base__animation_disposal disposal,
+ wuffs_base__color_u32_argb_premul background_color) {
if (!c) {
return;
}
@@ -2249,10 +2233,11 @@
c->private_impl.io_position = io_position;
c->private_impl.blend = blend;
c->private_impl.disposal = disposal;
+ c->private_impl.background_color = background_color;
}
static inline wuffs_base__rect_ie_u32 //
-wuffs_base__frame_config__bounds(wuffs_base__frame_config* c) {
+wuffs_base__frame_config__bounds(const wuffs_base__frame_config* c) {
if (c) {
return c->private_impl.bounds;
}
@@ -2266,103 +2251,115 @@
}
static inline uint32_t //
-wuffs_base__frame_config__width(wuffs_base__frame_config* c) {
+wuffs_base__frame_config__width(const wuffs_base__frame_config* c) {
return c ? wuffs_base__rect_ie_u32__width(&c->private_impl.bounds) : 0;
}
static inline uint32_t //
-wuffs_base__frame_config__height(wuffs_base__frame_config* c) {
+wuffs_base__frame_config__height(const wuffs_base__frame_config* c) {
return c ? wuffs_base__rect_ie_u32__height(&c->private_impl.bounds) : 0;
}
// wuffs_base__frame_config__duration returns the amount of time to display
// this frame. Zero means to display forever - a still (non-animated) image.
static inline wuffs_base__flicks //
-wuffs_base__frame_config__duration(wuffs_base__frame_config* c) {
+wuffs_base__frame_config__duration(const wuffs_base__frame_config* c) {
return c ? c->private_impl.duration : 0;
}
// wuffs_base__frame_config__index returns the index of this frame. The first
// frame in an image has index 0, the second frame has index 1, and so on.
static inline uint64_t //
-wuffs_base__frame_config__index(wuffs_base__frame_config* c) {
+wuffs_base__frame_config__index(const wuffs_base__frame_config* c) {
return c ? c->private_impl.index : 0;
}
// wuffs_base__frame_config__io_position returns the I/O stream position before
// the frame config.
static inline uint64_t //
-wuffs_base__frame_config__io_position(wuffs_base__frame_config* c) {
+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(wuffs_base__frame_config* c) {
+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 //
-wuffs_base__frame_config__disposal(wuffs_base__frame_config* c) {
+wuffs_base__frame_config__disposal(const wuffs_base__frame_config* c) {
return c ? c->private_impl.disposal : 0;
}
+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;
+}
+
#ifdef __cplusplus
inline void //
-wuffs_base__frame_config::update(wuffs_base__rect_ie_u32 bounds,
- wuffs_base__flicks duration,
- uint64_t index,
- uint64_t io_position,
- wuffs_base__animation_blend blend,
- wuffs_base__animation_disposal disposal) {
+wuffs_base__frame_config::update(
+ wuffs_base__rect_ie_u32 bounds,
+ wuffs_base__flicks duration,
+ uint64_t index,
+ uint64_t io_position,
+ wuffs_base__animation_blend blend,
+ wuffs_base__animation_disposal disposal,
+ wuffs_base__color_u32_argb_premul background_color) {
wuffs_base__frame_config__update(this, bounds, duration, index, io_position,
- blend, disposal);
+ blend, disposal, background_color);
}
inline wuffs_base__rect_ie_u32 //
-wuffs_base__frame_config::bounds() {
+wuffs_base__frame_config::bounds() const {
return wuffs_base__frame_config__bounds(this);
}
inline uint32_t //
-wuffs_base__frame_config::width() {
+wuffs_base__frame_config::width() const {
return wuffs_base__frame_config__width(this);
}
inline uint32_t //
-wuffs_base__frame_config::height() {
+wuffs_base__frame_config::height() const {
return wuffs_base__frame_config__height(this);
}
inline wuffs_base__flicks //
-wuffs_base__frame_config::duration() {
+wuffs_base__frame_config::duration() const {
return wuffs_base__frame_config__duration(this);
}
inline uint64_t //
-wuffs_base__frame_config::index() {
+wuffs_base__frame_config::index() const {
return wuffs_base__frame_config__index(this);
}
inline uint64_t //
-wuffs_base__frame_config::io_position() {
+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() {
+wuffs_base__frame_config::blend() const {
return wuffs_base__frame_config__blend(this);
}
inline wuffs_base__animation_disposal //
-wuffs_base__frame_config::disposal() {
+wuffs_base__frame_config::disposal() const {
return wuffs_base__frame_config__disposal(this);
}
+inline wuffs_base__color_u32_argb_premul //
+wuffs_base__frame_config::background_color() const {
+ return wuffs_base__frame_config__background_color(this);
+}
+
#endif // __cplusplus
// --------
@@ -2380,8 +2377,10 @@
#ifdef __cplusplus
inline wuffs_base__status set_from_slice(wuffs_base__pixel_config* pixcfg,
wuffs_base__slice_u8 pixbuf_memory);
+ inline wuffs_base__status set_from_table(wuffs_base__pixel_config* pixcfg,
+ wuffs_base__table_u8 pixbuf_memory);
inline wuffs_base__slice_u8 palette();
- inline wuffs_base__pixel_format pixel_format();
+ inline wuffs_base__pixel_format pixel_format() const;
inline wuffs_base__table_u8 plane(uint32_t p);
#endif // __cplusplus
@@ -2411,12 +2410,13 @@
}
if (wuffs_base__pixel_format__is_planar(pixcfg->private_impl.pixfmt)) {
// TODO: support planar pixel formats, concious of pixel subsampling.
- return wuffs_base__error__bad_argument;
+ return wuffs_base__error__unsupported_option;
}
uint32_t bits_per_pixel =
wuffs_base__pixel_format__bits_per_pixel(pixcfg->private_impl.pixfmt);
if ((bits_per_pixel == 0) || ((bits_per_pixel % 8) != 0)) {
- return wuffs_base__error__bad_argument;
+ // TODO: support fraction-of-byte pixels, e.g. 1 bit per pixel?
+ return wuffs_base__error__unsupported_option;
}
uint64_t bytes_per_pixel = bits_per_pixel / 8;
@@ -2462,6 +2462,38 @@
return NULL;
}
+static inline wuffs_base__status //
+wuffs_base__pixel_buffer__set_from_table(wuffs_base__pixel_buffer* b,
+ wuffs_base__pixel_config* pixcfg,
+ wuffs_base__table_u8 pixbuf_memory) {
+ if (!b) {
+ return 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;
+ }
+ uint32_t bits_per_pixel =
+ 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;
+ }
+ uint64_t bytes_per_pixel = bits_per_pixel / 8;
+
+ uint64_t width_in_bytes =
+ ((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;
+ }
+
+ b->pixcfg = *pixcfg;
+ b->private_impl.planes[0] = pixbuf_memory;
+ return NULL;
+}
+
// wuffs_base__pixel_buffer__palette returns the palette color data. If
// non-empty, it will have length 1024.
static inline wuffs_base__slice_u8 //
@@ -2478,7 +2510,7 @@
}
static inline wuffs_base__pixel_format //
-wuffs_base__pixel_buffer__pixel_format(wuffs_base__pixel_buffer* b) {
+wuffs_base__pixel_buffer__pixel_format(const wuffs_base__pixel_buffer* b) {
if (b) {
return b->pixcfg.private_impl.pixfmt;
}
@@ -2507,13 +2539,19 @@
return wuffs_base__pixel_buffer__set_from_slice(this, pixcfg, pixbuf_memory);
}
+inline wuffs_base__status //
+wuffs_base__pixel_buffer::set_from_table(wuffs_base__pixel_config* pixcfg,
+ wuffs_base__table_u8 pixbuf_memory) {
+ return wuffs_base__pixel_buffer__set_from_table(this, pixcfg, pixbuf_memory);
+}
+
inline wuffs_base__slice_u8 //
wuffs_base__pixel_buffer::palette() {
return wuffs_base__pixel_buffer__palette(this);
}
inline wuffs_base__pixel_format //
-wuffs_base__pixel_buffer::pixel_format() {
+wuffs_base__pixel_buffer::pixel_format() const {
return wuffs_base__pixel_buffer__pixel_format(this);
}
@@ -2555,20 +2593,18 @@
} private_impl;
#ifdef __cplusplus
- inline void 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);
- inline uint64_t swizzle_packed(wuffs_base__slice_u8 dst,
- wuffs_base__slice_u8 dst_palette,
- wuffs_base__slice_u8 src);
+ 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);
+ inline uint64_t swizzle_interleaved(wuffs_base__slice_u8 dst,
+ wuffs_base__slice_u8 dst_palette,
+ wuffs_base__slice_u8 src) const;
#endif // __cplusplus
} wuffs_base__pixel_swizzler;
-// TODO: should prepare (both the C and C++ methods) return a status?
-
-void //
+wuffs_base__status //
wuffs_base__pixel_swizzler__prepare(wuffs_base__pixel_swizzler* p,
wuffs_base__pixel_format dst_format,
wuffs_base__slice_u8 dst_palette,
@@ -2576,28 +2612,30 @@
wuffs_base__slice_u8 src_palette);
uint64_t //
-wuffs_base__pixel_swizzler__swizzle_packed(wuffs_base__pixel_swizzler* p,
- wuffs_base__slice_u8 dst,
- wuffs_base__slice_u8 dst_palette,
- wuffs_base__slice_u8 src);
+wuffs_base__pixel_swizzler__swizzle_interleaved(
+ const wuffs_base__pixel_swizzler* p,
+ wuffs_base__slice_u8 dst,
+ wuffs_base__slice_u8 dst_palette,
+ wuffs_base__slice_u8 src);
#ifdef __cplusplus
-inline void //
+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__pixel_swizzler__prepare(this, dst_format, dst_palette, src_format,
- src_palette);
+ return wuffs_base__pixel_swizzler__prepare(this, dst_format, dst_palette,
+ src_format, src_palette);
}
uint64_t //
-wuffs_base__pixel_swizzler::swizzle_packed(wuffs_base__slice_u8 dst,
- wuffs_base__slice_u8 dst_palette,
- wuffs_base__slice_u8 src) {
- return wuffs_base__pixel_swizzler__swizzle_packed(this, dst, dst_palette,
- src);
+wuffs_base__pixel_swizzler::swizzle_interleaved(
+ wuffs_base__slice_u8 dst,
+ wuffs_base__slice_u8 dst_palette,
+ wuffs_base__slice_u8 src) const {
+ return wuffs_base__pixel_swizzler__swizzle_interleaved(this, dst, dst_palette,
+ src);
}
#endif // __cplusplus
@@ -2900,8 +2938,8 @@
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
wuffs_deflate__decoder__decode_io_writer(wuffs_deflate__decoder* self,
- wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src,
+ wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf);
// ---------------- Struct Definitions
@@ -3019,8 +3057,8 @@
}
inline wuffs_base__status //
- decode_io_writer(wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src,
+ decode_io_writer(wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf) {
return wuffs_deflate__decoder__decode_io_writer(this, a_dst, a_src,
a_workbuf);
@@ -3091,8 +3129,8 @@
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
wuffs_lzw__decoder__decode_io_writer(wuffs_lzw__decoder* self,
- wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src,
+ wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf);
WUFFS_BASE__MAYBE_STATIC wuffs_base__slice_u8 //
@@ -3189,8 +3227,8 @@
}
inline wuffs_base__status //
- decode_io_writer(wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src,
+ decode_io_writer(wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf) {
return wuffs_lzw__decoder__decode_io_writer(this, a_dst, a_src, a_workbuf);
}
@@ -3225,9 +3263,11 @@
extern const char* wuffs_gif__error__bad_block;
extern const char* wuffs_gif__error__bad_extension_label;
+extern const char* wuffs_gif__error__bad_frame_size;
extern const char* wuffs_gif__error__bad_graphic_control;
extern const char* wuffs_gif__error__bad_header;
extern const char* wuffs_gif__error__bad_literal_width;
+extern const char* wuffs_gif__error__bad_palette;
// ---------------- Public Consts
@@ -3237,6 +3277,49 @@
wuffs_gif__decoder_workbuf_len_max_incl_worst_case //
WUFFS_BASE__POTENTIALLY_UNUSED = 1;
+#define WUFFS_GIF__QUIRK_DELAY_NUM_DECODED_FRAMES 1041635328
+
+static const uint32_t //
+ wuffs_gif__quirk_delay_num_decoded_frames //
+ WUFFS_BASE__POTENTIALLY_UNUSED = 1041635328;
+
+#define WUFFS_GIF__QUIRK_FIRST_FRAME_LOCAL_PALETTE_MEANS_BLACK_BACKGROUND \
+ 1041635329
+
+static const uint32_t //
+ wuffs_gif__quirk_first_frame_local_palette_means_black_background //
+ WUFFS_BASE__POTENTIALLY_UNUSED = 1041635329;
+
+#define WUFFS_GIF__QUIRK_HONOR_BACKGROUND_COLOR 1041635330
+
+static const uint32_t //
+ wuffs_gif__quirk_honor_background_color //
+ WUFFS_BASE__POTENTIALLY_UNUSED = 1041635330;
+
+#define WUFFS_GIF__QUIRK_IGNORE_TOO_MUCH_PIXEL_DATA 1041635331
+
+static const uint32_t //
+ wuffs_gif__quirk_ignore_too_much_pixel_data //
+ WUFFS_BASE__POTENTIALLY_UNUSED = 1041635331;
+
+#define WUFFS_GIF__QUIRK_IMAGE_BOUNDS_ARE_STRICT 1041635332
+
+static const uint32_t //
+ wuffs_gif__quirk_image_bounds_are_strict //
+ WUFFS_BASE__POTENTIALLY_UNUSED = 1041635332;
+
+#define WUFFS_GIF__QUIRK_REJECT_EMPTY_FRAME 1041635333
+
+static const uint32_t //
+ wuffs_gif__quirk_reject_empty_frame //
+ WUFFS_BASE__POTENTIALLY_UNUSED = 1041635333;
+
+#define WUFFS_GIF__QUIRK_REJECT_EMPTY_PALETTE 1041635334
+
+static const uint32_t //
+ wuffs_gif__quirk_reject_empty_palette //
+ WUFFS_BASE__POTENTIALLY_UNUSED = 1041635334;
+
// ---------------- Struct Declarations
typedef struct wuffs_gif__decoder__struct wuffs_gif__decoder;
@@ -3260,10 +3343,30 @@
// ---------------- Public Function Prototypes
+WUFFS_BASE__MAYBE_STATIC wuffs_base__empty_struct //
+wuffs_gif__decoder__set_quirk_enabled(wuffs_gif__decoder* self,
+ uint32_t a_quirk,
+ bool a_enabled);
+
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
wuffs_gif__decoder__decode_image_config(wuffs_gif__decoder* self,
wuffs_base__image_config* a_dst,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_src);
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__empty_struct //
+wuffs_gif__decoder__set_report_metadata(wuffs_gif__decoder* self,
+ uint32_t a_fourcc,
+ bool a_report);
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
+wuffs_gif__decoder__ack_metadata_chunk(wuffs_gif__decoder* self,
+ wuffs_base__io_buffer* a_src);
+
+WUFFS_BASE__MAYBE_STATIC uint32_t //
+wuffs_gif__decoder__metadata_fourcc(const wuffs_gif__decoder* self);
+
+WUFFS_BASE__MAYBE_STATIC uint64_t //
+wuffs_gif__decoder__metadata_chunk_length(const wuffs_gif__decoder* self);
WUFFS_BASE__MAYBE_STATIC uint32_t //
wuffs_gif__decoder__num_animation_loops(const wuffs_gif__decoder* self);
@@ -3288,12 +3391,12 @@
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
wuffs_gif__decoder__decode_frame_config(wuffs_gif__decoder* self,
wuffs_base__frame_config* a_dst,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_src);
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
wuffs_gif__decoder__decode_frame(wuffs_gif__decoder* self,
wuffs_base__pixel_buffer* a_dst,
- wuffs_base__io_reader a_src,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf,
wuffs_base__decode_frame_options* a_opts);
@@ -3323,14 +3426,29 @@
uint32_t f_width;
uint32_t f_height;
uint8_t f_call_sequence;
+ bool f_ignore_metadata;
+ bool f_report_metadata_iccp;
+ bool f_report_metadata_xmp;
+ uint32_t f_metadata_fourcc_value;
+ uint64_t f_metadata_chunk_length_value;
+ uint64_t f_metadata_io_position;
+ bool f_quirk_enabled_delay_num_decoded_frames;
+ bool f_quirk_enabled_first_frame_local_palette_means_black_background;
+ bool f_quirk_enabled_honor_background_color;
+ bool f_quirk_enabled_ignore_too_much_pixel_data;
+ bool f_quirk_enabled_image_bounds_are_strict;
+ bool f_quirk_enabled_reject_empty_frame;
+ bool f_quirk_enabled_reject_empty_palette;
+ bool f_delayed_num_decoded_frames;
bool f_end_of_data;
bool f_restarted;
bool f_previous_lzw_decode_ended_abruptly;
- uint8_t f_which_palette;
+ bool f_has_global_palette;
uint8_t f_interlace;
bool f_seen_num_loops;
uint32_t f_num_loops;
- bool f_seen_graphic_control;
+ uint32_t f_background_color_u32_argb_premul;
+ uint32_t f_black_color_u32_argb_premul;
bool f_gc_has_transparent_index;
uint8_t f_gc_transparent_index;
uint8_t f_gc_disposal;
@@ -3350,6 +3468,7 @@
wuffs_base__pixel_swizzler f_swizzler;
uint32_t p_decode_image_config[1];
+ uint32_t p_ack_metadata_chunk[1];
uint32_t p_decode_frame_config[1];
uint32_t p_skip_frame[1];
uint32_t p_decode_frame[1];
@@ -3372,6 +3491,10 @@
wuffs_lzw__decoder f_lzw;
struct {
+ uint8_t v_blend;
+ uint32_t v_background_color;
+ } s_decode_frame_config[1];
+ struct {
uint64_t scratch;
} s_skip_frame[1];
struct {
@@ -3380,6 +3503,7 @@
} s_decode_header[1];
struct {
uint8_t v_flags;
+ uint8_t v_background_color_index;
uint32_t v_num_palette_entries;
uint32_t v_i;
uint64_t scratch;
@@ -3389,8 +3513,10 @@
} s_skip_blocks[1];
struct {
uint8_t v_block_size;
- bool v_not_animexts;
- bool v_not_netscape;
+ bool v_is_animexts;
+ bool v_is_netscape;
+ bool v_is_iccp;
+ bool v_is_xmp;
uint64_t scratch;
} s_decode_ae[1];
struct {
@@ -3400,6 +3526,7 @@
uint64_t scratch;
} s_decode_id_part0[1];
struct {
+ uint8_t v_which_palette;
uint32_t v_num_palette_entries;
uint32_t v_i;
uint64_t scratch;
@@ -3444,12 +3571,37 @@
initialize_flags);
}
+ inline wuffs_base__empty_struct //
+ set_quirk_enabled(uint32_t a_quirk, bool a_enabled) {
+ return wuffs_gif__decoder__set_quirk_enabled(this, a_quirk, a_enabled);
+ }
+
inline wuffs_base__status //
decode_image_config(wuffs_base__image_config* a_dst,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_src) {
return wuffs_gif__decoder__decode_image_config(this, a_dst, a_src);
}
+ inline wuffs_base__empty_struct //
+ set_report_metadata(uint32_t a_fourcc, bool a_report) {
+ return wuffs_gif__decoder__set_report_metadata(this, a_fourcc, a_report);
+ }
+
+ inline wuffs_base__status //
+ ack_metadata_chunk(wuffs_base__io_buffer* a_src) {
+ return wuffs_gif__decoder__ack_metadata_chunk(this, a_src);
+ }
+
+ inline uint32_t //
+ metadata_fourcc() const {
+ return wuffs_gif__decoder__metadata_fourcc(this);
+ }
+
+ inline uint64_t //
+ metadata_chunk_length() const {
+ return wuffs_gif__decoder__metadata_chunk_length(this);
+ }
+
inline uint32_t //
num_animation_loops() const {
return wuffs_gif__decoder__num_animation_loops(this);
@@ -3482,13 +3634,13 @@
inline wuffs_base__status //
decode_frame_config(wuffs_base__frame_config* a_dst,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_src) {
return wuffs_gif__decoder__decode_frame_config(this, a_dst, a_src);
}
inline wuffs_base__status //
decode_frame(wuffs_base__pixel_buffer* a_dst,
- wuffs_base__io_reader a_src,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf,
wuffs_base__decode_frame_options* a_opts) {
return wuffs_gif__decoder__decode_frame(this, a_dst, a_src, a_workbuf,
@@ -3562,8 +3714,8 @@
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
wuffs_gzip__decoder__decode_io_writer(wuffs_gzip__decoder* self,
- wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src,
+ wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf);
// ---------------- Struct Definitions
@@ -3650,8 +3802,8 @@
}
inline wuffs_base__status //
- decode_io_writer(wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src,
+ decode_io_writer(wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf) {
return wuffs_gzip__decoder__decode_io_writer(this, a_dst, a_src, a_workbuf);
}
@@ -3723,8 +3875,8 @@
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
wuffs_zlib__decoder__decode_io_writer(wuffs_zlib__decoder* self,
- wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src,
+ wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf);
// ---------------- Struct Definitions
@@ -3808,8 +3960,8 @@
}
inline wuffs_base__status //
- decode_io_writer(wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src,
+ decode_io_writer(wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf) {
return wuffs_zlib__decoder__decode_io_writer(this, a_dst, a_src, a_workbuf);
}
@@ -4304,65 +4456,52 @@
// ---------------- I/O
-static inline bool //
-wuffs_base__io_buffer__is_valid(wuffs_base__io_buffer buf) {
- return (buf.data.ptr || (buf.data.len == 0)) &&
- (buf.data.len >= buf.meta.wi) && (buf.meta.wi >= buf.meta.ri);
-}
-
-// TODO: wuffs_base__io_reader__is_eof is no longer used by Wuffs per se, but
-// it might be handy to programs that use Wuffs. Either delete it, or promote
-// it to the public API.
+// "Null" as in "/dev/null", not as in "nullptr".
//
-// If making this function public (i.e. moving it to base-header.h), it also
-// needs to allow NULL (i.e. implicit, callee-calculated) mark/limit.
+// TODO: ensure that this is zero-initialized.
+static wuffs_base__io_buffer wuffs_base__global__null_io_buffer;
-static inline bool //
-wuffs_base__io_reader__is_eof(wuffs_base__io_reader o) {
- wuffs_base__io_buffer* buf = o.private_impl.buf;
- return buf && buf->meta.closed &&
- (buf->data.ptr + buf->meta.wi == o.private_impl.limit);
+static inline wuffs_base__io_buffer* //
+wuffs_base__null_io_reader() {
+ return &wuffs_base__global__null_io_buffer;
}
-static inline bool //
-wuffs_base__io_reader__is_valid(wuffs_base__io_reader o) {
- wuffs_base__io_buffer* buf = o.private_impl.buf;
- // Note: if making this function public (i.e. moving it to base-header.h), it
- // also needs to allow NULL (i.e. implicit, callee-calculated) mark/limit.
- return buf ? ((buf->data.ptr <= o.private_impl.mark) &&
- (o.private_impl.mark <= o.private_impl.limit) &&
- (o.private_impl.limit <= buf->data.ptr + buf->data.len))
- : ((o.private_impl.mark == NULL) &&
- (o.private_impl.limit == NULL));
+static inline wuffs_base__io_buffer* //
+wuffs_base__null_io_writer() {
+ return &wuffs_base__global__null_io_buffer;
}
-static inline bool //
-wuffs_base__io_writer__is_valid(wuffs_base__io_writer o) {
- wuffs_base__io_buffer* buf = o.private_impl.buf;
- // Note: if making this function public (i.e. moving it to base-header.h), it
- // also needs to allow NULL (i.e. implicit, callee-calculated) mark/limit.
- return buf ? ((buf->data.ptr <= o.private_impl.mark) &&
- (o.private_impl.mark <= o.private_impl.limit) &&
- (o.private_impl.limit <= buf->data.ptr + buf->data.len))
- : ((o.private_impl.mark == NULL) &&
- (o.private_impl.limit == NULL));
+static inline uint64_t //
+wuffs_base__io__count_since(uint64_t mark, uint64_t index) {
+ if (index >= mark) {
+ return index - mark;
+ }
+ return 0;
+}
+
+static inline wuffs_base__slice_u8 //
+wuffs_base__io__since(uint64_t mark, uint64_t index, uint8_t* ptr) {
+ if (index >= mark) {
+ return wuffs_base__make_slice_u8(ptr + mark, index - mark);
+ }
+ return wuffs_base__make_slice_u8(NULL, 0);
}
static inline uint32_t //
wuffs_base__io_writer__copy_n_from_history(uint8_t** ptr_iop_w,
- uint8_t* io0_w,
uint8_t* io1_w,
+ uint8_t* io2_w,
uint32_t length,
uint32_t distance) {
if (!distance) {
return 0;
}
uint8_t* p = *ptr_iop_w;
- if ((size_t)(p - io0_w) < (size_t)(distance)) {
+ if ((size_t)(p - io1_w) < (size_t)(distance)) {
return 0;
}
uint8_t* q = p - distance;
- size_t n = (size_t)(io1_w - p);
+ size_t n = (size_t)(io2_w - p);
if ((size_t)(length) > n) {
length = (uint32_t)(n);
} else {
@@ -4394,12 +4533,12 @@
// wuffs_base__io_writer__copy_n_from_history function above, but has stronger
// pre-conditions. The caller needs to prove that:
// - distance > 0
-// - distance <= (*ptr_iop_w - io0_w)
-// - length <= (io1_w - *ptr_iop_w)
+// - 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* io0_w,
uint8_t* io1_w,
+ uint8_t* io2_w,
uint32_t length,
uint32_t distance) {
uint8_t* p = *ptr_iop_w;
@@ -4419,18 +4558,18 @@
static inline uint32_t //
wuffs_base__io_writer__copy_n_from_reader(uint8_t** ptr_iop_w,
- uint8_t* io1_w,
+ uint8_t* io2_w,
uint32_t length,
uint8_t** ptr_iop_r,
- uint8_t* io1_r) {
+ uint8_t* io2_r) {
uint8_t* iop_w = *ptr_iop_w;
size_t n = length;
- if (n > ((size_t)(io1_w - iop_w))) {
- n = (size_t)(io1_w - iop_w);
+ if (n > ((size_t)(io2_w - iop_w))) {
+ n = (size_t)(io2_w - iop_w);
}
uint8_t* iop_r = *ptr_iop_r;
- if (n > ((size_t)(io1_r - iop_r))) {
- n = (size_t)(io1_r - iop_r);
+ if (n > ((size_t)(io2_r - iop_r))) {
+ n = (size_t)(io2_r - iop_r);
}
if (n > 0) {
memmove(iop_w, iop_r, n);
@@ -4442,12 +4581,12 @@
static inline uint64_t //
wuffs_base__io_writer__copy_from_slice(uint8_t** ptr_iop_w,
- uint8_t* io1_w,
+ uint8_t* io2_w,
wuffs_base__slice_u8 src) {
uint8_t* iop_w = *ptr_iop_w;
size_t n = src.len;
- if (n > ((size_t)(io1_w - iop_w))) {
- n = (size_t)(io1_w - iop_w);
+ if (n > ((size_t)(io2_w - iop_w))) {
+ n = (size_t)(io2_w - iop_w);
}
if (n > 0) {
memmove(iop_w, src.ptr, n);
@@ -4458,7 +4597,7 @@
static inline uint32_t //
wuffs_base__io_writer__copy_n_from_slice(uint8_t** ptr_iop_w,
- uint8_t* io1_w,
+ uint8_t* io2_w,
uint32_t length,
wuffs_base__slice_u8 src) {
uint8_t* iop_w = *ptr_iop_w;
@@ -4466,8 +4605,8 @@
if (n > length) {
n = length;
}
- if (n > ((size_t)(io1_w - iop_w))) {
- n = (size_t)(io1_w - iop_w);
+ if (n > ((size_t)(io2_w - iop_w))) {
+ n = (size_t)(io2_w - iop_w);
}
if (n > 0) {
memmove(iop_w, src.ptr, n);
@@ -4476,11 +4615,12 @@
return (uint32_t)(n);
}
-static inline wuffs_base__empty_struct //
-wuffs_base__io_reader__set(wuffs_base__io_reader* o,
- wuffs_base__io_buffer* b,
+static inline wuffs_base__io_buffer* //
+wuffs_base__io_reader__set(wuffs_base__io_buffer* b,
uint8_t** ptr_iop_r,
+ uint8_t** ptr_io0_r,
uint8_t** ptr_io1_r,
+ uint8_t** ptr_io2_r,
wuffs_base__slice_u8 data) {
b->data = data;
b->meta.wi = data.len;
@@ -4488,42 +4628,17 @@
b->meta.pos = 0;
b->meta.closed = false;
- o->private_impl.buf = b;
- o->private_impl.mark = data.ptr;
- o->private_impl.limit = data.ptr + data.len;
*ptr_iop_r = data.ptr;
- *ptr_io1_r = data.ptr + data.len;
+ *ptr_io0_r = data.ptr;
+ *ptr_io1_r = data.ptr;
+ *ptr_io2_r = data.ptr + data.len;
- wuffs_base__empty_struct ret;
- ret.private_impl = 0;
- return ret;
-}
-
-static inline wuffs_base__empty_struct //
-wuffs_base__io_reader__set_limit(wuffs_base__io_reader* o,
- uint8_t* iop_r,
- uint64_t limit) {
- if (o && (((size_t)(o->private_impl.limit - iop_r)) > limit)) {
- o->private_impl.limit = iop_r + limit;
- }
-
- wuffs_base__empty_struct ret;
- ret.private_impl = 0;
- return ret;
-}
-
-static inline wuffs_base__empty_struct //
-wuffs_base__io_reader__set_mark(wuffs_base__io_reader* o, uint8_t* mark) {
- o->private_impl.mark = mark;
-
- wuffs_base__empty_struct ret;
- ret.private_impl = 0;
- return ret;
+ return b;
}
static inline wuffs_base__slice_u8 //
-wuffs_base__io_reader__take(uint8_t** ptr_iop_r, uint8_t* io1_r, uint64_t n) {
- if (n <= ((size_t)(io1_r - *ptr_iop_r))) {
+wuffs_base__io_reader__take(uint8_t** ptr_iop_r, uint8_t* io2_r, uint64_t n) {
+ if (n <= ((size_t)(io2_r - *ptr_iop_r))) {
uint8_t* p = *ptr_iop_r;
*ptr_iop_r += n;
return wuffs_base__make_slice_u8(p, n);
@@ -4531,11 +4646,12 @@
return wuffs_base__make_slice_u8(NULL, 0);
}
-static inline wuffs_base__empty_struct //
-wuffs_base__io_writer__set(wuffs_base__io_writer* o,
- wuffs_base__io_buffer* b,
+static inline wuffs_base__io_buffer* //
+wuffs_base__io_writer__set(wuffs_base__io_buffer* b,
uint8_t** ptr_iop_w,
+ uint8_t** ptr_io0_w,
uint8_t** ptr_io1_w,
+ uint8_t** ptr_io2_w,
wuffs_base__slice_u8 data) {
b->data = data;
b->meta.wi = 0;
@@ -4543,24 +4659,12 @@
b->meta.pos = 0;
b->meta.closed = false;
- o->private_impl.buf = b;
- o->private_impl.mark = data.ptr;
- o->private_impl.limit = data.ptr + data.len;
*ptr_iop_w = data.ptr;
- *ptr_io1_w = data.ptr + data.len;
+ *ptr_io0_w = data.ptr;
+ *ptr_io1_w = data.ptr;
+ *ptr_io2_w = data.ptr + data.len;
- wuffs_base__empty_struct ret;
- ret.private_impl = 0;
- return ret;
-}
-
-static inline wuffs_base__empty_struct //
-wuffs_base__io_writer__set_mark(wuffs_base__io_writer* o, uint8_t* mark) {
- o->private_impl.mark = mark;
-
- wuffs_base__empty_struct ret;
- ret.private_impl = 0;
- return ret;
+ return b;
}
// ---------------- I/O (Utility)
@@ -4618,8 +4722,10 @@
};
const char* wuffs_base__warning__end_of_data = "@base: end of data";
+const char* wuffs_base__warning__metadata_reported = "@base: metadata reported";
const char* wuffs_base__suspension__short_read = "$base: short read";
const char* wuffs_base__suspension__short_write = "$base: short write";
+const char* wuffs_base__error__bad_i_o_position = "#base: bad I/O position";
const char* wuffs_base__error__bad_argument_length_too_short =
"#base: bad argument (length too short)";
const char* wuffs_base__error__bad_argument = "#base: bad argument";
@@ -4641,6 +4747,7 @@
const char* wuffs_base__error__interleaved_coroutine_calls =
"#base: interleaved coroutine calls";
const char* wuffs_base__error__not_enough_data = "#base: not enough data";
+const char* wuffs_base__error__unsupported_option = "#base: unsupported option";
const char* wuffs_base__error__too_much_data = "#base: too much data";
// ---------------- Images
@@ -4658,6 +4765,61 @@
}
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) {
+ if (dst_palette.len != 1024) {
+ return 0;
+ }
+ size_t dst_len3 = dst.len / 3;
+ size_t len = dst_len3 < src.len ? dst_len3 : src.len;
+ uint8_t* d = dst.ptr;
+ uint8_t* s = src.ptr;
+ size_t n = len;
+
+ // N is the loop unroll count.
+ const int N = 4;
+
+ // The comparison in the while condition is ">", not ">=", because with ">=",
+ // the last 4-byte store could write past the end of the dst slice.
+ //
+ // Each 4-byte store writes one too many bytes, but a subsequent store will
+ // overwrite that with the correct byte. There is always another store,
+ // whether a 4-byte store in this loop or a 1-byte store in the next loop.
+ while (n > N) {
+ wuffs_base__store_u32le(
+ d + (0 * 3),
+ wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[0]) * 4)));
+ wuffs_base__store_u32le(
+ d + (1 * 3),
+ wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[1]) * 4)));
+ wuffs_base__store_u32le(
+ d + (2 * 3),
+ wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[2]) * 4)));
+ wuffs_base__store_u32le(
+ d + (3 * 3),
+ wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[3]) * 4)));
+
+ s += 1 * N;
+ d += 3 * N;
+ n -= (size_t)(1 * N);
+ }
+
+ while (n >= 1) {
+ uint32_t color =
+ wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[0]) * 4));
+ d[0] = (uint8_t)(color >> 0);
+ d[1] = (uint8_t)(color >> 8);
+ d[2] = (uint8_t)(color >> 16);
+
+ s += 1 * 1;
+ d += 3 * 1;
+ n -= (size_t)(1 * 1);
+ }
+
+ 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) {
@@ -4668,8 +4830,9 @@
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;
+
+ // N is the loop unroll count.
const int N = 4;
while (n >= N) {
@@ -4727,14 +4890,14 @@
return len4 * 4;
}
-void //
+wuffs_base__status //
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) {
if (!p) {
- return;
+ return wuffs_base__error__bad_receiver;
}
// TODO: support many more formats.
@@ -4754,6 +4917,13 @@
}
func = wuffs_base__pixel_swizzler__copy_1_1;
break;
+ case WUFFS_BASE__PIXEL_FORMAT__BGR:
+ if (wuffs_base__slice_u8__copy_from_slice(dst_palette, src_palette) !=
+ 1024) {
+ break;
+ }
+ func = wuffs_base__pixel_swizzler__copy_3_1;
+ break;
case WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL:
case WUFFS_BASE__PIXEL_FORMAT__BGRA_PREMUL:
case WUFFS_BASE__PIXEL_FORMAT__BGRA_BINARY:
@@ -4763,6 +4933,13 @@
}
func = wuffs_base__pixel_swizzler__copy_4_1;
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;
+ break;
case WUFFS_BASE__PIXEL_FORMAT__RGBA_NONPREMUL:
case WUFFS_BASE__PIXEL_FORMAT__RGBA_PREMUL:
case WUFFS_BASE__PIXEL_FORMAT__RGBA_BINARY:
@@ -4782,13 +4959,15 @@
}
p->private_impl.func = func;
+ return func ? NULL : wuffs_base__error__unsupported_option;
}
uint64_t //
-wuffs_base__pixel_swizzler__swizzle_packed(wuffs_base__pixel_swizzler* p,
- wuffs_base__slice_u8 dst,
- wuffs_base__slice_u8 dst_palette,
- wuffs_base__slice_u8 src) {
+wuffs_base__pixel_swizzler__swizzle_interleaved(
+ const wuffs_base__pixel_swizzler* p,
+ wuffs_base__slice_u8 dst,
+ wuffs_base__slice_u8 dst_palette,
+ wuffs_base__slice_u8 src) {
if (p && p->private_impl.func) {
return (*(p->private_impl.func))(dst, dst_palette, src);
}
@@ -6091,20 +6270,20 @@
static wuffs_base__status //
wuffs_deflate__decoder__decode_blocks(wuffs_deflate__decoder* self,
- wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src);
static wuffs_base__status //
wuffs_deflate__decoder__decode_uncompressed(wuffs_deflate__decoder* self,
- wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src);
static wuffs_base__status //
wuffs_deflate__decoder__init_fixed_huffman(wuffs_deflate__decoder* self);
static wuffs_base__status //
wuffs_deflate__decoder__init_dynamic_huffman(wuffs_deflate__decoder* self,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_src);
static wuffs_base__status //
wuffs_deflate__decoder__init_huff(wuffs_deflate__decoder* self,
@@ -6115,13 +6294,13 @@
static wuffs_base__status //
wuffs_deflate__decoder__decode_huffman_fast(wuffs_deflate__decoder* self,
- wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src);
static wuffs_base__status //
wuffs_deflate__decoder__decode_huffman_slow(wuffs_deflate__decoder* self,
- wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src);
// ---------------- Initializer Implementations
@@ -6196,8 +6375,8 @@
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
wuffs_deflate__decoder__decode_io_writer(wuffs_deflate__decoder* self,
- wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src,
+ wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf) {
if (!self) {
return wuffs_base__error__bad_receiver;
@@ -6207,6 +6386,10 @@
? wuffs_base__error__disabled_by_previous_error
: wuffs_base__error__initialize_not_called;
}
+ if (!a_dst || !a_src) {
+ self->private_impl.magic = WUFFS_BASE__DISABLED;
+ return wuffs_base__error__bad_argument;
+ }
if ((self->private_impl.active_coroutine != 0) &&
(self->private_impl.active_coroutine != 1)) {
self->private_impl.magic = WUFFS_BASE__DISABLED;
@@ -6215,6 +6398,7 @@
self->private_impl.active_coroutine = 0;
wuffs_base__status status = NULL;
+ uint64_t v_mark = 0;
wuffs_base__status v_status = NULL;
wuffs_base__slice_u8 v_written = {0};
uint64_t v_n_copied = 0;
@@ -6223,19 +6407,15 @@
uint8_t* iop_a_dst = NULL;
uint8_t* io0_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_dst.private_impl.buf) {
- iop_a_dst =
- a_dst.private_impl.buf->data.ptr + a_dst.private_impl.buf->meta.wi;
- if (!a_dst.private_impl.mark) {
- a_dst.private_impl.mark = iop_a_dst;
- a_dst.private_impl.limit =
- a_dst.private_impl.buf->data.ptr + a_dst.private_impl.buf->data.len;
+ uint8_t* io2_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_dst) {
+ io0_a_dst = a_dst->data.ptr;
+ io1_a_dst = io0_a_dst + a_dst->meta.wi;
+ iop_a_dst = io1_a_dst;
+ io2_a_dst = io0_a_dst + a_dst->data.len;
+ if (a_dst->meta.closed) {
+ io2_a_dst = iop_a_dst;
}
- if (a_dst.private_impl.buf->meta.closed) {
- a_dst.private_impl.limit = iop_a_dst;
- }
- io0_a_dst = a_dst.private_impl.mark;
- io1_a_dst = a_dst.private_impl.limit;
}
uint32_t coro_susp_point = self->private_impl.p_decode_io_writer[0];
@@ -6245,17 +6425,15 @@
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
while (true) {
- wuffs_base__io_writer__set_mark(&a_dst, iop_a_dst);
+ v_mark = ((uint64_t)(iop_a_dst - io0_a_dst));
{
- if (a_dst.private_impl.buf) {
- a_dst.private_impl.buf->meta.wi =
- ((size_t)(iop_a_dst - a_dst.private_impl.buf->data.ptr));
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
}
wuffs_base__status t_0 =
wuffs_deflate__decoder__decode_blocks(self, a_dst, a_src);
- if (a_dst.private_impl.buf) {
- iop_a_dst = a_dst.private_impl.buf->data.ptr +
- a_dst.private_impl.buf->meta.wi;
+ if (a_dst) {
+ iop_a_dst = a_dst->data.ptr + a_dst->meta.wi;
}
v_status = t_0;
}
@@ -6269,9 +6447,8 @@
}
goto ok;
}
- v_written = wuffs_base__make_slice_u8(
- a_dst.private_impl.mark,
- (size_t)(iop_a_dst - a_dst.private_impl.mark));
+ v_written = wuffs_base__io__since(
+ v_mark, ((uint64_t)(iop_a_dst - io0_a_dst)), io0_a_dst);
if (((uint64_t)(v_written.len)) >= 32768) {
v_written = wuffs_base__slice_u8__suffix(v_written, 32768);
wuffs_base__slice_u8__copy_from_slice(
@@ -6313,14 +6490,15 @@
goto suspend;
suspend:
- self->private_impl.p_decode_io_writer[0] = coro_susp_point;
- self->private_impl.active_coroutine = 1;
+ self->private_impl.p_decode_io_writer[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
+ self->private_impl.active_coroutine =
+ wuffs_base__status__is_suspension(status) ? 1 : 0;
goto exit;
exit:
- if (a_dst.private_impl.buf) {
- a_dst.private_impl.buf->meta.wi =
- ((size_t)(iop_a_dst - a_dst.private_impl.buf->data.ptr));
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
}
if (wuffs_base__status__is_error(status)) {
@@ -6333,8 +6511,8 @@
static wuffs_base__status //
wuffs_deflate__decoder__decode_blocks(wuffs_deflate__decoder* self,
- wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src) {
wuffs_base__status status = NULL;
uint32_t v_final = 0;
@@ -6345,16 +6523,12 @@
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_decode_blocks[0];
@@ -6369,7 +6543,7 @@
while (self->private_impl.f_n_bits < 3) {
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -6384,16 +6558,14 @@
self->private_impl.f_bits >>= 3;
self->private_impl.f_n_bits -= 3;
if (v_type == 0) {
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
status =
wuffs_deflate__decoder__decode_uncompressed(self, a_dst, a_src);
- if (a_src.private_impl.buf) {
- iop_a_src = a_src.private_impl.buf->data.ptr +
- a_src.private_impl.buf->meta.ri;
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
}
if (status) {
goto suspend;
@@ -6412,15 +6584,13 @@
goto ok;
}
} else if (v_type == 2) {
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
status = wuffs_deflate__decoder__init_dynamic_huffman(self, a_src);
- if (a_src.private_impl.buf) {
- iop_a_src = a_src.private_impl.buf->data.ptr +
- a_src.private_impl.buf->meta.ri;
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
}
if (status) {
goto suspend;
@@ -6431,15 +6601,13 @@
}
self->private_impl.f_end_of_block = false;
while (true) {
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
v_status =
wuffs_deflate__decoder__decode_huffman_fast(self, a_dst, a_src);
- if (a_src.private_impl.buf) {
- iop_a_src = a_src.private_impl.buf->data.ptr +
- a_src.private_impl.buf->meta.ri;
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
}
if (wuffs_base__status__is_error(v_status)) {
status = v_status;
@@ -6448,16 +6616,14 @@
if (self->private_impl.f_end_of_block) {
goto label_0_continue;
}
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
status =
wuffs_deflate__decoder__decode_huffman_slow(self, a_dst, a_src);
- if (a_src.private_impl.buf) {
- iop_a_src = a_src.private_impl.buf->data.ptr +
- a_src.private_impl.buf->meta.ri;
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
}
if (status) {
goto suspend;
@@ -6476,14 +6642,14 @@
goto suspend;
suspend:
- self->private_impl.p_decode_blocks[0] = coro_susp_point;
+ self->private_impl.p_decode_blocks[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
self->private_data.s_decode_blocks[0].v_final = v_final;
goto exit;
exit:
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return status;
@@ -6493,8 +6659,8 @@
static wuffs_base__status //
wuffs_deflate__decoder__decode_uncompressed(wuffs_deflate__decoder* self,
- wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src) {
wuffs_base__status status = NULL;
uint32_t v_length = 0;
@@ -6503,33 +6669,25 @@
uint8_t* iop_a_dst = NULL;
uint8_t* io0_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_dst.private_impl.buf) {
- iop_a_dst =
- a_dst.private_impl.buf->data.ptr + a_dst.private_impl.buf->meta.wi;
- if (!a_dst.private_impl.mark) {
- a_dst.private_impl.mark = iop_a_dst;
- a_dst.private_impl.limit =
- a_dst.private_impl.buf->data.ptr + a_dst.private_impl.buf->data.len;
+ uint8_t* io2_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_dst) {
+ io0_a_dst = a_dst->data.ptr;
+ io1_a_dst = io0_a_dst + a_dst->meta.wi;
+ iop_a_dst = io1_a_dst;
+ io2_a_dst = io0_a_dst + a_dst->data.len;
+ if (a_dst->meta.closed) {
+ io2_a_dst = iop_a_dst;
}
- if (a_dst.private_impl.buf->meta.closed) {
- a_dst.private_impl.limit = iop_a_dst;
- }
- io0_a_dst = a_dst.private_impl.mark;
- io1_a_dst = a_dst.private_impl.limit;
}
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_decode_uncompressed[0];
@@ -6550,14 +6708,14 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
uint32_t t_0;
- if (WUFFS_BASE__LIKELY(io1_a_src - iop_a_src >= 4)) {
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 4)) {
t_0 = wuffs_base__load_u32le(iop_a_src);
iop_a_src += 4;
} else {
self->private_data.s_decode_uncompressed[0].scratch = 0;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -6584,13 +6742,13 @@
v_length = ((v_length)&0xFFFF);
while (true) {
v_n_copied = wuffs_base__io_writer__copy_n_from_reader(
- &iop_a_dst, io1_a_dst, v_length, &iop_a_src, io1_a_src);
+ &iop_a_dst, io2_a_dst, v_length, &iop_a_src, io2_a_src);
if (v_length <= v_n_copied) {
status = NULL;
goto ok;
}
v_length -= v_n_copied;
- if (((uint64_t)(io1_a_dst - iop_a_dst)) == 0) {
+ if (((uint64_t)(io2_a_dst - iop_a_dst)) == 0) {
status = wuffs_base__suspension__short_write;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(3);
} else {
@@ -6607,18 +6765,17 @@
goto suspend;
suspend:
- self->private_impl.p_decode_uncompressed[0] = coro_susp_point;
+ self->private_impl.p_decode_uncompressed[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
self->private_data.s_decode_uncompressed[0].v_length = v_length;
goto exit;
exit:
- if (a_dst.private_impl.buf) {
- a_dst.private_impl.buf->meta.wi =
- ((size_t)(iop_a_dst - a_dst.private_impl.buf->data.ptr));
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
}
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return status;
@@ -6666,7 +6823,7 @@
static wuffs_base__status //
wuffs_deflate__decoder__init_dynamic_huffman(wuffs_deflate__decoder* self,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_src) {
wuffs_base__status status = NULL;
uint32_t v_bits = 0;
@@ -6690,16 +6847,12 @@
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_init_dynamic_huffman[0];
@@ -6725,7 +6878,7 @@
while (v_n_bits < 14) {
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -6755,7 +6908,7 @@
while (v_n_bits < 3) {
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -6794,7 +6947,7 @@
}
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -6843,7 +6996,7 @@
while (v_n_bits < v_n_extra_bits) {
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -6896,7 +7049,8 @@
goto suspend;
suspend:
- self->private_impl.p_init_dynamic_huffman[0] = coro_susp_point;
+ self->private_impl.p_init_dynamic_huffman[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
self->private_data.s_init_dynamic_huffman[0].v_bits = v_bits;
self->private_data.s_init_dynamic_huffman[0].v_n_bits = v_n_bits;
self->private_data.s_init_dynamic_huffman[0].v_n_lit = v_n_lit;
@@ -6911,9 +7065,8 @@
goto exit;
exit:
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return status;
@@ -7178,8 +7331,8 @@
static wuffs_base__status //
wuffs_deflate__decoder__decode_huffman_fast(wuffs_deflate__decoder* self,
- wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src) {
wuffs_base__status status = NULL;
uint32_t v_bits = 0;
@@ -7199,33 +7352,25 @@
uint8_t* iop_a_dst = NULL;
uint8_t* io0_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_dst.private_impl.buf) {
- iop_a_dst =
- a_dst.private_impl.buf->data.ptr + a_dst.private_impl.buf->meta.wi;
- if (!a_dst.private_impl.mark) {
- a_dst.private_impl.mark = iop_a_dst;
- a_dst.private_impl.limit =
- a_dst.private_impl.buf->data.ptr + a_dst.private_impl.buf->data.len;
+ uint8_t* io2_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_dst) {
+ io0_a_dst = a_dst->data.ptr;
+ io1_a_dst = io0_a_dst + a_dst->meta.wi;
+ iop_a_dst = io1_a_dst;
+ io2_a_dst = io0_a_dst + a_dst->data.len;
+ if (a_dst->meta.closed) {
+ io2_a_dst = iop_a_dst;
}
- if (a_dst.private_impl.buf->meta.closed) {
- a_dst.private_impl.limit = iop_a_dst;
- }
- io0_a_dst = a_dst.private_impl.mark;
- io1_a_dst = a_dst.private_impl.limit;
}
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
if ((self->private_impl.f_n_bits >= 8) ||
@@ -7238,8 +7383,8 @@
v_lmask = ((((uint32_t)(1)) << self->private_impl.f_n_huffs_bits[0]) - 1);
v_dmask = ((((uint32_t)(1)) << self->private_impl.f_n_huffs_bits[1]) - 1);
label_0_continue:;
- while ((((uint64_t)(io1_a_dst - iop_a_dst)) >= 258) &&
- (((uint64_t)(io1_a_src - iop_a_src)) >= 12)) {
+ while ((((uint64_t)(io2_a_dst - iop_a_dst)) >= 258) &&
+ (((uint64_t)(io2_a_src - iop_a_src)) >= 12)) {
if (v_n_bits < 15) {
v_bits |= (((uint32_t)(wuffs_base__load_u8be(iop_a_src))) << v_n_bits);
(iop_a_src += 1, wuffs_base__make_empty_struct());
@@ -7391,11 +7536,10 @@
v_n_copied = 0;
while (true) {
if (((uint64_t)((v_dist_minus_1 + 1))) >
- ((uint64_t)(iop_a_dst - a_dst.private_impl.mark))) {
+ ((uint64_t)(iop_a_dst - a_dst->data.ptr))) {
v_hlen = 0;
- v_hdist =
- ((uint32_t)((((uint64_t)((v_dist_minus_1 + 1))) -
- ((uint64_t)(iop_a_dst - a_dst.private_impl.mark)))));
+ v_hdist = ((uint32_t)((((uint64_t)((v_dist_minus_1 + 1))) -
+ ((uint64_t)(iop_a_dst - a_dst->data.ptr)))));
if (v_length > v_hdist) {
v_length -= v_hdist;
v_hlen = v_hdist;
@@ -7410,7 +7554,7 @@
v_hdist = (self->private_impl.f_history_index - v_hdist);
while (true) {
v_n_copied = wuffs_base__io_writer__copy_n_from_slice(
- &iop_a_dst, io1_a_dst, v_hlen,
+ &iop_a_dst, io2_a_dst, v_hlen,
wuffs_base__slice_u8__subslice_i(
wuffs_base__make_slice_u8(self->private_data.f_history,
32768),
@@ -7420,7 +7564,7 @@
}
v_hlen -= v_n_copied;
wuffs_base__io_writer__copy_n_from_slice(
- &iop_a_dst, io1_a_dst, v_hlen,
+ &iop_a_dst, io2_a_dst, v_hlen,
wuffs_base__make_slice_u8(self->private_data.f_history, 32768));
goto label_1_break;
}
@@ -7429,13 +7573,13 @@
goto label_0_continue;
}
if (((uint64_t)((v_dist_minus_1 + 1))) >
- ((uint64_t)(iop_a_dst - a_dst.private_impl.mark))) {
+ ((uint64_t)(iop_a_dst - a_dst->data.ptr))) {
status = wuffs_deflate__error__internal_error_inconsistent_distance;
goto exit;
}
}
wuffs_base__io_writer__copy_n_from_history_fast(
- &iop_a_dst, a_dst.private_impl.mark, io1_a_dst, v_length,
+ &iop_a_dst, a_dst->data.ptr, io2_a_dst, v_length,
(v_dist_minus_1 + 1));
goto label_2_break;
}
@@ -7444,7 +7588,7 @@
label_0_break:;
while (v_n_bits >= 8) {
v_n_bits -= 8;
- if (iop_a_src > io0_a_src) {
+ if (iop_a_src > io1_a_src) {
(iop_a_src--, wuffs_base__make_empty_struct());
} else {
status = wuffs_deflate__error__internal_error_inconsistent_i_o;
@@ -7460,13 +7604,11 @@
}
goto exit;
exit:
- if (a_dst.private_impl.buf) {
- a_dst.private_impl.buf->meta.wi =
- ((size_t)(iop_a_dst - a_dst.private_impl.buf->data.ptr));
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
}
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return status;
@@ -7476,8 +7618,8 @@
static wuffs_base__status //
wuffs_deflate__decoder__decode_huffman_slow(wuffs_deflate__decoder* self,
- wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src) {
wuffs_base__status status = NULL;
uint32_t v_bits = 0;
@@ -7503,33 +7645,25 @@
uint8_t* iop_a_dst = NULL;
uint8_t* io0_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_dst.private_impl.buf) {
- iop_a_dst =
- a_dst.private_impl.buf->data.ptr + a_dst.private_impl.buf->meta.wi;
- if (!a_dst.private_impl.mark) {
- a_dst.private_impl.mark = iop_a_dst;
- a_dst.private_impl.limit =
- a_dst.private_impl.buf->data.ptr + a_dst.private_impl.buf->data.len;
+ uint8_t* io2_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_dst) {
+ io0_a_dst = a_dst->data.ptr;
+ io1_a_dst = io0_a_dst + a_dst->meta.wi;
+ iop_a_dst = io1_a_dst;
+ io2_a_dst = io0_a_dst + a_dst->data.len;
+ if (a_dst->meta.closed) {
+ io2_a_dst = iop_a_dst;
}
- if (a_dst.private_impl.buf->meta.closed) {
- a_dst.private_impl.limit = iop_a_dst;
- }
- io0_a_dst = a_dst.private_impl.mark;
- io1_a_dst = a_dst.private_impl.limit;
}
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_decode_huffman_slow[0];
@@ -7573,7 +7707,7 @@
}
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -7586,7 +7720,7 @@
label_1_break:;
if ((v_table_entry >> 31) != 0) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
- if (iop_a_dst == io1_a_dst) {
+ if (iop_a_dst == io2_a_dst) {
status = wuffs_base__suspension__short_write;
goto suspend;
}
@@ -7611,7 +7745,7 @@
}
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -7624,7 +7758,7 @@
label_2_break:;
if ((v_table_entry >> 31) != 0) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
- if (iop_a_dst == io1_a_dst) {
+ if (iop_a_dst == io2_a_dst) {
status = wuffs_base__suspension__short_write;
goto suspend;
}
@@ -7660,7 +7794,7 @@
while (v_n_bits < v_table_entry_n_bits) {
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(5);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -7688,7 +7822,7 @@
}
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(6);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -7714,7 +7848,7 @@
}
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(7);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -7741,7 +7875,7 @@
while (v_n_bits < v_table_entry_n_bits) {
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(8);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -7760,10 +7894,9 @@
}
while (true) {
if (((uint64_t)((v_dist_minus_1 + 1))) >
- ((uint64_t)(iop_a_dst - a_dst.private_impl.mark))) {
- v_hdist =
- ((uint32_t)((((uint64_t)((v_dist_minus_1 + 1))) -
- ((uint64_t)(iop_a_dst - a_dst.private_impl.mark)))));
+ ((uint64_t)(iop_a_dst - a_dst->data.ptr))) {
+ v_hdist = ((uint32_t)((((uint64_t)((v_dist_minus_1 + 1))) -
+ ((uint64_t)(iop_a_dst - a_dst->data.ptr)))));
if (v_length > v_hdist) {
v_length -= v_hdist;
v_hlen = v_hdist;
@@ -7778,7 +7911,7 @@
v_hdist = (self->private_impl.f_history_index - v_hdist);
while (true) {
v_n_copied = wuffs_base__io_writer__copy_n_from_slice(
- &iop_a_dst, io1_a_dst, v_hlen,
+ &iop_a_dst, io2_a_dst, v_hlen,
wuffs_base__slice_u8__subslice_i(
wuffs_base__make_slice_u8(self->private_data.f_history,
32768),
@@ -7801,7 +7934,7 @@
if (v_hlen > 0) {
while (true) {
v_n_copied = wuffs_base__io_writer__copy_n_from_slice(
- &iop_a_dst, io1_a_dst, v_hlen,
+ &iop_a_dst, io2_a_dst, v_hlen,
wuffs_base__slice_u8__subslice_i(
wuffs_base__make_slice_u8(self->private_data.f_history,
32768),
@@ -7822,7 +7955,7 @@
}
}
v_n_copied = wuffs_base__io_writer__copy_n_from_history(
- &iop_a_dst, a_dst.private_impl.mark, io1_a_dst, v_length,
+ &iop_a_dst, a_dst->data.ptr, io2_a_dst, v_length,
(v_dist_minus_1 + 1));
if (v_length <= v_n_copied) {
v_length = 0;
@@ -7852,7 +7985,8 @@
goto suspend;
suspend:
- self->private_impl.p_decode_huffman_slow[0] = coro_susp_point;
+ self->private_impl.p_decode_huffman_slow[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
self->private_data.s_decode_huffman_slow[0].v_bits = v_bits;
self->private_data.s_decode_huffman_slow[0].v_n_bits = v_n_bits;
self->private_data.s_decode_huffman_slow[0].v_table_entry = v_table_entry;
@@ -7869,13 +8003,11 @@
goto exit;
exit:
- if (a_dst.private_impl.buf) {
- a_dst.private_impl.buf->meta.wi =
- ((size_t)(iop_a_dst - a_dst.private_impl.buf->data.ptr));
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
}
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return status;
@@ -7900,11 +8032,11 @@
static wuffs_base__empty_struct //
wuffs_lzw__decoder__read_from(wuffs_lzw__decoder* self,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_src);
static wuffs_base__status //
wuffs_lzw__decoder__write_to(wuffs_lzw__decoder* self,
- wuffs_base__io_writer a_dst);
+ wuffs_base__io_buffer* a_dst);
// ---------------- Initializer Implementations
@@ -7970,12 +8102,12 @@
if (self->private_impl.magic != WUFFS_BASE__MAGIC) {
return wuffs_base__make_empty_struct();
}
- if (a_lw < 2 || a_lw > 8) {
+ if (a_lw > 8) {
self->private_impl.magic = WUFFS_BASE__DISABLED;
return wuffs_base__make_empty_struct();
}
- self->private_impl.f_set_literal_width_arg = a_lw;
+ self->private_impl.f_set_literal_width_arg = (a_lw + 1);
return wuffs_base__make_empty_struct();
}
@@ -7998,8 +8130,8 @@
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
wuffs_lzw__decoder__decode_io_writer(wuffs_lzw__decoder* self,
- wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src,
+ wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf) {
if (!self) {
return wuffs_base__error__bad_receiver;
@@ -8009,6 +8141,10 @@
? wuffs_base__error__disabled_by_previous_error
: wuffs_base__error__initialize_not_called;
}
+ if (!a_dst || !a_src) {
+ self->private_impl.magic = WUFFS_BASE__DISABLED;
+ return wuffs_base__error__bad_argument;
+ }
if ((self->private_impl.active_coroutine != 0) &&
(self->private_impl.active_coroutine != 1)) {
self->private_impl.magic = WUFFS_BASE__DISABLED;
@@ -8026,9 +8162,9 @@
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
self->private_impl.f_literal_width = 8;
- if (self->private_impl.f_set_literal_width_arg >= 2) {
+ if (self->private_impl.f_set_literal_width_arg > 0) {
self->private_impl.f_literal_width =
- self->private_impl.f_set_literal_width_arg;
+ (self->private_impl.f_set_literal_width_arg - 1);
}
self->private_impl.f_clear_code =
(((uint32_t)(1)) << self->private_impl.f_literal_width);
@@ -8081,8 +8217,10 @@
goto suspend;
suspend:
- self->private_impl.p_decode_io_writer[0] = coro_susp_point;
- self->private_impl.active_coroutine = 1;
+ self->private_impl.p_decode_io_writer[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
+ self->private_impl.active_coroutine =
+ wuffs_base__status__is_suspension(status) ? 1 : 0;
goto exit;
exit:
@@ -8096,7 +8234,7 @@
static wuffs_base__empty_struct //
wuffs_lzw__decoder__read_from(wuffs_lzw__decoder* self,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_src) {
uint32_t v_clear_code = 0;
uint32_t v_end_code = 0;
uint32_t v_save_code = 0;
@@ -8116,16 +8254,12 @@
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
v_clear_code = self->private_impl.f_clear_code;
@@ -8138,11 +8272,11 @@
v_output_wi = self->private_impl.f_output_wi;
while (true) {
if (v_n_bits < v_width) {
- if (((uint64_t)(io1_a_src - iop_a_src)) >= 4) {
+ if (((uint64_t)(io2_a_src - iop_a_src)) >= 4) {
v_bits |= (wuffs_base__load_u32le(iop_a_src) << v_n_bits);
(iop_a_src += ((31 - v_n_bits) >> 3), wuffs_base__make_empty_struct());
v_n_bits |= 24;
- } else if (((uint64_t)(io1_a_src - iop_a_src)) <= 0) {
+ } else if (((uint64_t)(io2_a_src - iop_a_src)) <= 0) {
self->private_impl.f_read_from_return_value = 2;
goto label_0_break;
} else {
@@ -8150,7 +8284,7 @@
(iop_a_src += 1, wuffs_base__make_empty_struct());
v_n_bits += 8;
if (v_n_bits >= v_width) {
- } else if (((uint64_t)(io1_a_src - iop_a_src)) <= 0) {
+ } else if (((uint64_t)(io2_a_src - iop_a_src)) <= 0) {
self->private_impl.f_read_from_return_value = 2;
goto label_0_break;
} else {
@@ -8265,7 +8399,7 @@
if (self->private_impl.f_read_from_return_value != 2) {
while (v_n_bits >= 8) {
v_n_bits -= 8;
- if (iop_a_src > io0_a_src) {
+ if (iop_a_src > io1_a_src) {
(iop_a_src--, wuffs_base__make_empty_struct());
} else {
self->private_impl.f_read_from_return_value = 4;
@@ -8280,9 +8414,8 @@
self->private_impl.f_bits = v_bits;
self->private_impl.f_n_bits = v_n_bits;
self->private_impl.f_output_wi = v_output_wi;
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return wuffs_base__make_empty_struct();
@@ -8292,7 +8425,7 @@
static wuffs_base__status //
wuffs_lzw__decoder__write_to(wuffs_lzw__decoder* self,
- wuffs_base__io_writer a_dst) {
+ wuffs_base__io_buffer* a_dst) {
wuffs_base__status status = NULL;
wuffs_base__slice_u8 v_s = {0};
@@ -8301,19 +8434,15 @@
uint8_t* iop_a_dst = NULL;
uint8_t* io0_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_dst.private_impl.buf) {
- iop_a_dst =
- a_dst.private_impl.buf->data.ptr + a_dst.private_impl.buf->meta.wi;
- if (!a_dst.private_impl.mark) {
- a_dst.private_impl.mark = iop_a_dst;
- a_dst.private_impl.limit =
- a_dst.private_impl.buf->data.ptr + a_dst.private_impl.buf->data.len;
+ uint8_t* io2_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_dst) {
+ io0_a_dst = a_dst->data.ptr;
+ io1_a_dst = io0_a_dst + a_dst->meta.wi;
+ iop_a_dst = io1_a_dst;
+ io2_a_dst = io0_a_dst + a_dst->data.len;
+ if (a_dst->meta.closed) {
+ io2_a_dst = iop_a_dst;
}
- if (a_dst.private_impl.buf->meta.closed) {
- a_dst.private_impl.limit = iop_a_dst;
- }
- io0_a_dst = a_dst.private_impl.mark;
- io1_a_dst = a_dst.private_impl.limit;
}
uint32_t coro_susp_point = self->private_impl.p_write_to[0];
@@ -8330,7 +8459,7 @@
v_s = wuffs_base__slice_u8__subslice_ij(
wuffs_base__make_slice_u8(self->private_data.f_output, 8199),
self->private_impl.f_output_ri, self->private_impl.f_output_wi);
- v_n = wuffs_base__io_writer__copy_from_slice(&iop_a_dst, io1_a_dst, v_s);
+ v_n = wuffs_base__io_writer__copy_from_slice(&iop_a_dst, io2_a_dst, v_s);
if (v_n == ((uint64_t)(v_s.len))) {
self->private_impl.f_output_ri = 0;
self->private_impl.f_output_wi = 0;
@@ -8352,13 +8481,13 @@
goto suspend;
suspend:
- self->private_impl.p_write_to[0] = coro_susp_point;
+ self->private_impl.p_write_to[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
goto exit;
exit:
- if (a_dst.private_impl.buf) {
- a_dst.private_impl.buf->meta.wi =
- ((size_t)(iop_a_dst - a_dst.private_impl.buf->data.ptr));
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
}
return status;
@@ -8395,9 +8524,11 @@
const char* wuffs_gif__error__bad_block = "#gif: bad block";
const char* wuffs_gif__error__bad_extension_label = "#gif: bad extension label";
+const char* wuffs_gif__error__bad_frame_size = "#gif: bad frame size";
const char* wuffs_gif__error__bad_graphic_control = "#gif: bad graphic control";
const char* wuffs_gif__error__bad_header = "#gif: bad header";
const char* wuffs_gif__error__bad_literal_width = "#gif: bad literal width";
+const char* wuffs_gif__error__bad_palette = "#gif: bad palette";
const char* wuffs_gif__error__internal_error_inconsistent_ri_wi =
"#gif: internal error: inconsistent ri/wi";
@@ -8427,58 +8558,70 @@
78, 69, 84, 83, 67, 65, 80, 69, 50, 46, 48,
};
+static const uint8_t //
+ wuffs_gif__iccrgbg1012[11] //
+ WUFFS_BASE__POTENTIALLY_UNUSED = {
+ 73, 67, 67, 82, 71, 66, 71, 49, 48, 49, 50,
+};
+
+static const uint8_t //
+ wuffs_gif__xmpdataxmp[11] //
+ WUFFS_BASE__POTENTIALLY_UNUSED = {
+ 88, 77, 80, 32, 68, 97, 116, 97, 88, 77, 80,
+};
+
// ---------------- Private Initializer Prototypes
// ---------------- Private Function Prototypes
static wuffs_base__status //
wuffs_gif__decoder__skip_frame(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_src);
static wuffs_base__empty_struct //
wuffs_gif__decoder__reset_gc(wuffs_gif__decoder* self);
static wuffs_base__status //
wuffs_gif__decoder__decode_up_to_id_part1(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_src);
static wuffs_base__status //
wuffs_gif__decoder__decode_header(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_src);
static wuffs_base__status //
wuffs_gif__decoder__decode_lsd(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_src);
static wuffs_base__status //
wuffs_gif__decoder__decode_extension(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_src);
static wuffs_base__status //
wuffs_gif__decoder__skip_blocks(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_src);
static wuffs_base__status //
wuffs_gif__decoder__decode_ae(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_src);
static wuffs_base__status //
wuffs_gif__decoder__decode_gc(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_src);
static wuffs_base__status //
wuffs_gif__decoder__decode_id_part0(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_src);
static wuffs_base__status //
wuffs_gif__decoder__decode_id_part1(wuffs_gif__decoder* self,
wuffs_base__pixel_buffer* a_dst,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_src);
static wuffs_base__status //
wuffs_gif__decoder__decode_id_part2(wuffs_gif__decoder* self,
wuffs_base__pixel_buffer* a_dst,
- wuffs_base__io_reader a_src,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf);
static wuffs_base__status //
@@ -8548,12 +8691,47 @@
// ---------------- Function Implementations
+// -------- func gif.decoder.set_quirk_enabled
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__empty_struct //
+wuffs_gif__decoder__set_quirk_enabled(wuffs_gif__decoder* self,
+ uint32_t a_quirk,
+ bool a_enabled) {
+ if (!self) {
+ return wuffs_base__make_empty_struct();
+ }
+ if (self->private_impl.magic != WUFFS_BASE__MAGIC) {
+ return wuffs_base__make_empty_struct();
+ }
+
+ if (self->private_impl.f_call_sequence == 0) {
+ if (a_quirk == 1041635328) {
+ self->private_impl.f_quirk_enabled_delay_num_decoded_frames = a_enabled;
+ } else if (a_quirk == 1041635329) {
+ self->private_impl
+ .f_quirk_enabled_first_frame_local_palette_means_black_background =
+ a_enabled;
+ } else if (a_quirk == 1041635330) {
+ self->private_impl.f_quirk_enabled_honor_background_color = a_enabled;
+ } else if (a_quirk == 1041635331) {
+ self->private_impl.f_quirk_enabled_ignore_too_much_pixel_data = a_enabled;
+ } else if (a_quirk == 1041635332) {
+ self->private_impl.f_quirk_enabled_image_bounds_are_strict = a_enabled;
+ } else if (a_quirk == 1041635333) {
+ self->private_impl.f_quirk_enabled_reject_empty_frame = a_enabled;
+ } else if (a_quirk == 1041635334) {
+ self->private_impl.f_quirk_enabled_reject_empty_palette = a_enabled;
+ }
+ }
+ return wuffs_base__make_empty_struct();
+}
+
// -------- func gif.decoder.decode_image_config
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
wuffs_gif__decoder__decode_image_config(wuffs_gif__decoder* self,
wuffs_base__image_config* a_dst,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_src) {
if (!self) {
return wuffs_base__error__bad_receiver;
}
@@ -8562,6 +8740,10 @@
? wuffs_base__error__disabled_by_previous_error
: wuffs_base__error__initialize_not_called;
}
+ if (!a_src) {
+ self->private_impl.magic = WUFFS_BASE__DISABLED;
+ return wuffs_base__error__bad_argument;
+ }
if ((self->private_impl.active_coroutine != 0) &&
(self->private_impl.active_coroutine != 1)) {
self->private_impl.magic = WUFFS_BASE__DISABLED;
@@ -8578,38 +8760,47 @@
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
- if (self->private_impl.f_call_sequence >= 1) {
+ if (self->private_impl.f_call_sequence == 0) {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
+ status = wuffs_gif__decoder__decode_header(self, a_src);
+ if (status) {
+ goto suspend;
+ }
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
+ status = wuffs_gif__decoder__decode_lsd(self, a_src);
+ if (status) {
+ goto suspend;
+ }
+ } else if (self->private_impl.f_call_sequence != 2) {
status = wuffs_base__error__bad_call_sequence;
goto exit;
}
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
- status = wuffs_gif__decoder__decode_header(self, a_src);
- if (status) {
- goto suspend;
- }
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
- status = wuffs_gif__decoder__decode_lsd(self, a_src);
- if (status) {
- goto suspend;
- }
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
status = wuffs_gif__decoder__decode_up_to_id_part1(self, a_src);
if (status) {
goto suspend;
}
- v_ffio =
- (!self->private_impl.f_gc_has_transparent_index &&
- (self->private_impl.f_frame_rect_x0 == 0) &&
- (self->private_impl.f_frame_rect_y0 == 0) &&
- (self->private_impl.f_frame_rect_x1 == self->private_impl.f_width) &&
- (self->private_impl.f_frame_rect_y1 == self->private_impl.f_height));
+ v_ffio = !self->private_impl.f_gc_has_transparent_index;
+ if (!self->private_impl.f_quirk_enabled_honor_background_color) {
+ v_ffio =
+ (v_ffio && (self->private_impl.f_frame_rect_x0 == 0) &&
+ (self->private_impl.f_frame_rect_y0 == 0) &&
+ (self->private_impl.f_frame_rect_x1 == self->private_impl.f_width) &&
+ (self->private_impl.f_frame_rect_y1 == self->private_impl.f_height));
+ } else if (v_ffio) {
+ self->private_impl.f_black_color_u32_argb_premul = 4278190080;
+ }
+ if (self->private_impl.f_background_color_u32_argb_premul == 77) {
+ self->private_impl.f_background_color_u32_argb_premul =
+ self->private_impl.f_black_color_u32_argb_premul;
+ }
if (a_dst != NULL) {
wuffs_base__image_config__set(
a_dst, 1191444488, 0, self->private_impl.f_width,
self->private_impl.f_height,
self->private_impl.f_frame_config_io_position, v_ffio);
}
- self->private_impl.f_call_sequence = 1;
+ self->private_impl.f_call_sequence = 3;
goto ok;
ok:
@@ -8619,8 +8810,10 @@
goto suspend;
suspend:
- self->private_impl.p_decode_image_config[0] = coro_susp_point;
- self->private_impl.active_coroutine = 1;
+ self->private_impl.p_decode_image_config[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
+ self->private_impl.active_coroutine =
+ wuffs_base__status__is_suspension(status) ? 1 : 0;
goto exit;
exit:
@@ -8630,6 +8823,172 @@
return status;
}
+// -------- func gif.decoder.set_report_metadata
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__empty_struct //
+wuffs_gif__decoder__set_report_metadata(wuffs_gif__decoder* self,
+ uint32_t a_fourcc,
+ bool a_report) {
+ if (!self) {
+ return wuffs_base__make_empty_struct();
+ }
+ if (self->private_impl.magic != WUFFS_BASE__MAGIC) {
+ return wuffs_base__make_empty_struct();
+ }
+
+ if (a_fourcc == 1229144912) {
+ self->private_impl.f_report_metadata_iccp = a_report;
+ } else if (a_fourcc == 1481461792) {
+ self->private_impl.f_report_metadata_xmp = a_report;
+ }
+ return wuffs_base__make_empty_struct();
+}
+
+// -------- func gif.decoder.ack_metadata_chunk
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
+wuffs_gif__decoder__ack_metadata_chunk(wuffs_gif__decoder* self,
+ wuffs_base__io_buffer* a_src) {
+ if (!self) {
+ return wuffs_base__error__bad_receiver;
+ }
+ if (self->private_impl.magic != WUFFS_BASE__MAGIC) {
+ return (self->private_impl.magic == WUFFS_BASE__DISABLED)
+ ? wuffs_base__error__disabled_by_previous_error
+ : wuffs_base__error__initialize_not_called;
+ }
+ if (!a_src) {
+ self->private_impl.magic = WUFFS_BASE__DISABLED;
+ return wuffs_base__error__bad_argument;
+ }
+ if ((self->private_impl.active_coroutine != 0) &&
+ (self->private_impl.active_coroutine != 2)) {
+ self->private_impl.magic = WUFFS_BASE__DISABLED;
+ return wuffs_base__error__interleaved_coroutine_calls;
+ }
+ self->private_impl.active_coroutine = 0;
+ wuffs_base__status status = NULL;
+
+ uint8_t* iop_a_src = NULL;
+ uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
+ }
+
+ uint32_t coro_susp_point = self->private_impl.p_ack_metadata_chunk[0];
+ if (coro_susp_point) {
+ }
+ switch (coro_susp_point) {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
+
+ if (self->private_impl.f_call_sequence != 1) {
+ status = wuffs_base__error__bad_call_sequence;
+ goto exit;
+ }
+ if ((a_src ? wuffs_base__u64__sat_add(
+ a_src->meta.pos, ((uint64_t)(iop_a_src - a_src->data.ptr)))
+ : 0) != self->private_impl.f_metadata_io_position) {
+ status = wuffs_base__error__bad_i_o_position;
+ goto exit;
+ }
+ while (((uint64_t)(io2_a_src - iop_a_src)) <= 0) {
+ status = wuffs_base__suspension__short_read;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(1);
+ }
+ if (self->private_impl.f_metadata_fourcc_value == 1481461792) {
+ self->private_impl.f_metadata_chunk_length_value =
+ (((uint64_t)(wuffs_base__load_u8be(iop_a_src))) + 1);
+ if (self->private_impl.f_metadata_chunk_length_value > 1) {
+ self->private_impl.f_metadata_io_position = wuffs_base__u64__sat_add(
+ (a_src ? wuffs_base__u64__sat_add(
+ a_src->meta.pos,
+ ((uint64_t)(iop_a_src - a_src->data.ptr)))
+ : 0),
+ self->private_impl.f_metadata_chunk_length_value);
+ status = wuffs_base__warning__metadata_reported;
+ goto ok;
+ }
+ } else {
+ self->private_impl.f_metadata_chunk_length_value =
+ ((uint64_t)(wuffs_base__load_u8be(iop_a_src)));
+ if (self->private_impl.f_metadata_chunk_length_value > 0) {
+ (iop_a_src += 1, wuffs_base__make_empty_struct());
+ self->private_impl.f_metadata_io_position = wuffs_base__u64__sat_add(
+ (a_src ? wuffs_base__u64__sat_add(
+ a_src->meta.pos,
+ ((uint64_t)(iop_a_src - a_src->data.ptr)))
+ : 0),
+ self->private_impl.f_metadata_chunk_length_value);
+ status = wuffs_base__warning__metadata_reported;
+ goto ok;
+ }
+ }
+ (iop_a_src += 1, wuffs_base__make_empty_struct());
+ self->private_impl.f_call_sequence = 2;
+ self->private_impl.f_metadata_fourcc_value = 0;
+ self->private_impl.f_metadata_io_position = 0;
+ status = NULL;
+ goto ok;
+ goto ok;
+ ok:
+ self->private_impl.p_ack_metadata_chunk[0] = 0;
+ goto exit;
+ }
+
+ goto suspend;
+suspend:
+ self->private_impl.p_ack_metadata_chunk[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
+ self->private_impl.active_coroutine =
+ wuffs_base__status__is_suspension(status) ? 2 : 0;
+
+ goto exit;
+exit:
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+
+ if (wuffs_base__status__is_error(status)) {
+ self->private_impl.magic = WUFFS_BASE__DISABLED;
+ }
+ return status;
+}
+
+// -------- func gif.decoder.metadata_fourcc
+
+WUFFS_BASE__MAYBE_STATIC uint32_t //
+wuffs_gif__decoder__metadata_fourcc(const wuffs_gif__decoder* self) {
+ if (!self) {
+ return 0;
+ }
+ if ((self->private_impl.magic != WUFFS_BASE__MAGIC) &&
+ (self->private_impl.magic != WUFFS_BASE__DISABLED)) {
+ return 0;
+ }
+
+ return self->private_impl.f_metadata_fourcc_value;
+}
+
+// -------- func gif.decoder.metadata_chunk_length
+
+WUFFS_BASE__MAYBE_STATIC uint64_t //
+wuffs_gif__decoder__metadata_chunk_length(const wuffs_gif__decoder* self) {
+ if (!self) {
+ return 0;
+ }
+ if ((self->private_impl.magic != WUFFS_BASE__MAGIC) &&
+ (self->private_impl.magic != WUFFS_BASE__DISABLED)) {
+ return 0;
+ }
+
+ return self->private_impl.f_metadata_chunk_length_value;
+}
+
// -------- func gif.decoder.num_animation_loops
WUFFS_BASE__MAYBE_STATIC uint32_t //
@@ -8732,6 +9091,7 @@
if (self->private_impl.f_call_sequence == 0) {
return wuffs_base__error__bad_call_sequence;
}
+ self->private_impl.f_delayed_num_decoded_frames = false;
self->private_impl.f_end_of_data = false;
self->private_impl.f_restarted = true;
self->private_impl.f_frame_config_io_position = a_io_position;
@@ -8746,7 +9106,7 @@
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
wuffs_gif__decoder__decode_frame_config(wuffs_gif__decoder* self,
wuffs_base__frame_config* a_dst,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_src) {
if (!self) {
return wuffs_base__error__bad_receiver;
}
@@ -8755,8 +9115,12 @@
? wuffs_base__error__disabled_by_previous_error
: wuffs_base__error__initialize_not_called;
}
+ if (!a_src) {
+ self->private_impl.magic = WUFFS_BASE__DISABLED;
+ return wuffs_base__error__bad_argument;
+ }
if ((self->private_impl.active_coroutine != 0) &&
- (self->private_impl.active_coroutine != 2)) {
+ (self->private_impl.active_coroutine != 3)) {
self->private_impl.magic = WUFFS_BASE__DISABLED;
return wuffs_base__error__interleaved_coroutine_calls;
}
@@ -8764,32 +9128,67 @@
wuffs_base__status status = NULL;
uint8_t v_blend = 0;
+ uint32_t v_background_color = 0;
+ uint8_t v_flags = 0;
+
+ uint8_t* iop_a_src = NULL;
+ uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
+ }
uint32_t coro_susp_point = self->private_impl.p_decode_frame_config[0];
if (coro_susp_point) {
+ v_blend = self->private_data.s_decode_frame_config[0].v_blend;
+ v_background_color =
+ self->private_data.s_decode_frame_config[0].v_background_color;
}
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
+ self->private_impl.f_ignore_metadata = true;
(memset(&self->private_impl.f_dirty_y, 0, sizeof(wuffs_base__range_ie_u32)),
wuffs_base__make_empty_struct());
if (!self->private_impl.f_end_of_data) {
if (self->private_impl.f_call_sequence == 0) {
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
status = wuffs_gif__decoder__decode_image_config(self, NULL, a_src);
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
+ }
if (status) {
goto suspend;
}
- } else if (self->private_impl.f_call_sequence != 1) {
- if (self->private_impl.f_call_sequence == 2) {
+ } else if (self->private_impl.f_call_sequence != 3) {
+ if (self->private_impl.f_call_sequence == 4) {
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
status = wuffs_gif__decoder__skip_frame(self, a_src);
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
+ }
if (status) {
goto suspend;
}
}
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
status = wuffs_gif__decoder__decode_up_to_id_part1(self, a_src);
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
+ }
if (status) {
goto suspend;
}
@@ -8800,8 +9199,23 @@
goto ok;
}
v_blend = 0;
+ v_background_color = self->private_impl.f_black_color_u32_argb_premul;
if (!self->private_impl.f_gc_has_transparent_index) {
v_blend = 2;
+ v_background_color =
+ self->private_impl.f_background_color_u32_argb_premul;
+ if (self->private_impl
+ .f_quirk_enabled_first_frame_local_palette_means_black_background &&
+ (self->private_impl.f_num_decoded_frame_configs_value == 0)) {
+ while (((uint64_t)(io2_a_src - iop_a_src)) <= 0) {
+ status = wuffs_base__suspension__short_read;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(4);
+ }
+ v_flags = wuffs_base__load_u8be(iop_a_src);
+ if ((v_flags & 128) != 0) {
+ v_background_color = self->private_impl.f_black_color_u32_argb_premul;
+ }
+ }
}
if (a_dst != NULL) {
wuffs_base__frame_config__update(
@@ -8818,11 +9232,11 @@
((wuffs_base__flicks)(self->private_impl.f_gc_duration)),
self->private_impl.f_num_decoded_frame_configs_value,
self->private_impl.f_frame_config_io_position, v_blend,
- self->private_impl.f_gc_disposal);
+ self->private_impl.f_gc_disposal, v_background_color);
}
wuffs_base__u64__sat_add_indirect(
&self->private_impl.f_num_decoded_frame_configs_value, 1);
- self->private_impl.f_call_sequence = 2;
+ self->private_impl.f_call_sequence = 4;
goto ok;
ok:
@@ -8832,11 +9246,20 @@
goto suspend;
suspend:
- self->private_impl.p_decode_frame_config[0] = coro_susp_point;
- self->private_impl.active_coroutine = 2;
+ self->private_impl.p_decode_frame_config[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
+ self->private_impl.active_coroutine =
+ wuffs_base__status__is_suspension(status) ? 3 : 0;
+ self->private_data.s_decode_frame_config[0].v_blend = v_blend;
+ self->private_data.s_decode_frame_config[0].v_background_color =
+ v_background_color;
goto exit;
exit:
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+
if (wuffs_base__status__is_error(status)) {
self->private_impl.magic = WUFFS_BASE__DISABLED;
}
@@ -8847,24 +9270,21 @@
static wuffs_base__status //
wuffs_gif__decoder__skip_frame(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_src) {
wuffs_base__status status = NULL;
uint8_t v_flags = 0;
+ uint8_t v_lw = 0;
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_skip_frame[0];
@@ -8875,7 +9295,7 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -8887,36 +9307,45 @@
(((uint32_t)(3)) << (1 + (v_flags & 7)));
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
if (self->private_data.s_skip_frame[0].scratch >
- ((uint64_t)(io1_a_src - iop_a_src))) {
+ ((uint64_t)(io2_a_src - iop_a_src))) {
self->private_data.s_skip_frame[0].scratch -=
- ((uint64_t)(io1_a_src - iop_a_src));
- iop_a_src = io1_a_src;
+ ((uint64_t)(io2_a_src - iop_a_src));
+ iop_a_src = io2_a_src;
status = wuffs_base__suspension__short_read;
goto suspend;
}
iop_a_src += self->private_data.s_skip_frame[0].scratch;
}
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
- status = wuffs_base__suspension__short_read;
- goto suspend;
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+ status = wuffs_base__suspension__short_read;
+ goto suspend;
+ }
+ uint8_t t_1 = *iop_a_src++;
+ v_lw = t_1;
}
- iop_a_src++;
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (v_lw > 8) {
+ status = wuffs_gif__error__bad_literal_width;
+ goto exit;
+ }
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
status = wuffs_gif__decoder__skip_blocks(self, a_src);
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
}
if (status) {
goto suspend;
}
- wuffs_base__u64__sat_add_indirect(
- &self->private_impl.f_num_decoded_frames_value, 1);
+ if (self->private_impl.f_quirk_enabled_delay_num_decoded_frames) {
+ self->private_impl.f_delayed_num_decoded_frames = true;
+ } else {
+ wuffs_base__u64__sat_add_indirect(
+ &self->private_impl.f_num_decoded_frames_value, 1);
+ }
wuffs_gif__decoder__reset_gc(self);
goto ok;
@@ -8927,13 +9356,13 @@
goto suspend;
suspend:
- self->private_impl.p_skip_frame[0] = coro_susp_point;
+ self->private_impl.p_skip_frame[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
goto exit;
exit:
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return status;
@@ -8944,7 +9373,7 @@
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
wuffs_gif__decoder__decode_frame(wuffs_gif__decoder* self,
wuffs_base__pixel_buffer* a_dst,
- wuffs_base__io_reader a_src,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf,
wuffs_base__decode_frame_options* a_opts) {
if (!self) {
@@ -8955,12 +9384,12 @@
? wuffs_base__error__disabled_by_previous_error
: wuffs_base__error__initialize_not_called;
}
- if (!a_dst) {
+ if (!a_dst || !a_src) {
self->private_impl.magic = WUFFS_BASE__DISABLED;
return wuffs_base__error__bad_argument;
}
if ((self->private_impl.active_coroutine != 0) &&
- (self->private_impl.active_coroutine != 3)) {
+ (self->private_impl.active_coroutine != 4)) {
self->private_impl.magic = WUFFS_BASE__DISABLED;
return wuffs_base__error__interleaved_coroutine_calls;
}
@@ -8973,13 +9402,22 @@
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
- if (self->private_impl.f_call_sequence != 2) {
+ self->private_impl.f_ignore_metadata = true;
+ if (self->private_impl.f_call_sequence != 4) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
status = wuffs_gif__decoder__decode_frame_config(self, NULL, a_src);
if (status) {
goto suspend;
}
}
+ if (self->private_impl.f_quirk_enabled_reject_empty_frame &&
+ ((self->private_impl.f_frame_rect_x0 ==
+ self->private_impl.f_frame_rect_x1) ||
+ (self->private_impl.f_frame_rect_y0 ==
+ self->private_impl.f_frame_rect_y1))) {
+ status = wuffs_gif__error__bad_frame_size;
+ goto exit;
+ }
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
status = wuffs_gif__decoder__decode_id_part1(self, a_dst, a_src);
if (status) {
@@ -9002,8 +9440,10 @@
goto suspend;
suspend:
- self->private_impl.p_decode_frame[0] = coro_susp_point;
- self->private_impl.active_coroutine = 3;
+ self->private_impl.p_decode_frame[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
+ self->private_impl.active_coroutine =
+ wuffs_base__status__is_suspension(status) ? 4 : 0;
goto exit;
exit:
@@ -9017,8 +9457,7 @@
static wuffs_base__empty_struct //
wuffs_gif__decoder__reset_gc(wuffs_gif__decoder* self) {
- self->private_impl.f_call_sequence = 3;
- self->private_impl.f_seen_graphic_control = false;
+ self->private_impl.f_call_sequence = 5;
self->private_impl.f_gc_has_transparent_index = false;
self->private_impl.f_gc_transparent_index = 0;
self->private_impl.f_gc_disposal = 0;
@@ -9030,7 +9469,7 @@
static wuffs_base__status //
wuffs_gif__decoder__decode_up_to_id_part1(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_src) {
wuffs_base__status status = NULL;
uint8_t v_block_type = 0;
@@ -9038,16 +9477,12 @@
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_decode_up_to_id_part1[0];
@@ -9057,19 +9492,18 @@
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
if (!self->private_impl.f_restarted) {
- self->private_impl.f_frame_config_io_position =
- (a_src.private_impl.buf
- ? wuffs_base__u64__sat_add(
- a_src.private_impl.buf->meta.pos,
- ((uint64_t)(iop_a_src - a_src.private_impl.buf->data.ptr)))
- : 0);
+ if (self->private_impl.f_call_sequence != 2) {
+ self->private_impl.f_frame_config_io_position =
+ (a_src ? wuffs_base__u64__sat_add(
+ a_src->meta.pos,
+ ((uint64_t)(iop_a_src - a_src->data.ptr)))
+ : 0);
+ }
} else if (self->private_impl.f_frame_config_io_position !=
- (a_src.private_impl.buf
- ? wuffs_base__u64__sat_add(
- a_src.private_impl.buf->meta.pos,
- ((uint64_t)(iop_a_src -
- a_src.private_impl.buf->data.ptr)))
- : 0)) {
+ (a_src ? wuffs_base__u64__sat_add(
+ a_src->meta.pos,
+ ((uint64_t)(iop_a_src - a_src->data.ptr)))
+ : 0)) {
status = wuffs_base__error__bad_restart;
goto exit;
} else {
@@ -9078,7 +9512,7 @@
while (true) {
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -9086,35 +9520,41 @@
v_block_type = t_0;
}
if (v_block_type == 33) {
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
status = wuffs_gif__decoder__decode_extension(self, a_src);
- if (a_src.private_impl.buf) {
- iop_a_src = a_src.private_impl.buf->data.ptr +
- a_src.private_impl.buf->meta.ri;
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
}
if (status) {
goto suspend;
}
} else if (v_block_type == 44) {
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (self->private_impl.f_delayed_num_decoded_frames) {
+ self->private_impl.f_delayed_num_decoded_frames = false;
+ wuffs_base__u64__sat_add_indirect(
+ &self->private_impl.f_num_decoded_frames_value, 1);
+ }
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
status = wuffs_gif__decoder__decode_id_part0(self, a_src);
- if (a_src.private_impl.buf) {
- iop_a_src = a_src.private_impl.buf->data.ptr +
- a_src.private_impl.buf->meta.ri;
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
}
if (status) {
goto suspend;
}
goto label_0_break;
} else if (v_block_type == 59) {
+ if (self->private_impl.f_delayed_num_decoded_frames) {
+ self->private_impl.f_delayed_num_decoded_frames = false;
+ wuffs_base__u64__sat_add_indirect(
+ &self->private_impl.f_num_decoded_frames_value, 1);
+ }
self->private_impl.f_end_of_data = true;
goto label_0_break;
} else {
@@ -9132,13 +9572,13 @@
goto suspend;
suspend:
- self->private_impl.p_decode_up_to_id_part1[0] = coro_susp_point;
+ self->private_impl.p_decode_up_to_id_part1[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
goto exit;
exit:
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return status;
@@ -9148,7 +9588,7 @@
static wuffs_base__status //
wuffs_gif__decoder__decode_header(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_src) {
wuffs_base__status status = NULL;
uint8_t v_c[6] = {0};
@@ -9157,16 +9597,12 @@
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_decode_header[0];
@@ -9180,7 +9616,7 @@
while (v_i < 6) {
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -9203,15 +9639,15 @@
goto suspend;
suspend:
- self->private_impl.p_decode_header[0] = coro_susp_point;
+ self->private_impl.p_decode_header[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
memcpy(self->private_data.s_decode_header[0].v_c, v_c, sizeof(v_c));
self->private_data.s_decode_header[0].v_i = v_i;
goto exit;
exit:
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return status;
@@ -9221,32 +9657,32 @@
static wuffs_base__status //
wuffs_gif__decoder__decode_lsd(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_src) {
wuffs_base__status status = NULL;
uint8_t v_flags = 0;
+ uint8_t v_background_color_index = 0;
uint32_t v_num_palette_entries = 0;
uint32_t v_i = 0;
+ uint32_t v_j = 0;
uint32_t v_argb = 0;
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_decode_lsd[0];
if (coro_susp_point) {
v_flags = self->private_data.s_decode_lsd[0].v_flags;
+ v_background_color_index =
+ self->private_data.s_decode_lsd[0].v_background_color_index;
v_num_palette_entries =
self->private_data.s_decode_lsd[0].v_num_palette_entries;
v_i = self->private_data.s_decode_lsd[0].v_i;
@@ -9257,14 +9693,14 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
uint32_t t_0;
- if (WUFFS_BASE__LIKELY(io1_a_src - iop_a_src >= 2)) {
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 2)) {
t_0 = ((uint32_t)(wuffs_base__load_u16le(iop_a_src)));
iop_a_src += 2;
} else {
self->private_data.s_decode_lsd[0].scratch = 0;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -9286,14 +9722,14 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
uint32_t t_1;
- if (WUFFS_BASE__LIKELY(io1_a_src - iop_a_src >= 2)) {
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 2)) {
t_1 = ((uint32_t)(wuffs_base__load_u16le(iop_a_src)));
iop_a_src += 2;
} else {
self->private_data.s_decode_lsd[0].scratch = 0;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -9314,56 +9750,61 @@
}
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(5);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
uint8_t t_2 = *iop_a_src++;
v_flags = t_2;
}
- self->private_data.s_decode_lsd[0].scratch = 2;
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(6);
- if (self->private_data.s_decode_lsd[0].scratch >
- ((uint64_t)(io1_a_src - iop_a_src))) {
- self->private_data.s_decode_lsd[0].scratch -=
- ((uint64_t)(io1_a_src - iop_a_src));
- iop_a_src = io1_a_src;
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(6);
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+ status = wuffs_base__suspension__short_read;
+ goto suspend;
+ }
+ uint8_t t_3 = *iop_a_src++;
+ v_background_color_index = t_3;
+ }
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(7);
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
- iop_a_src += self->private_data.s_decode_lsd[0].scratch;
- if ((v_flags & 128) != 0) {
+ iop_a_src++;
+ v_i = 0;
+ self->private_impl.f_has_global_palette = ((v_flags & 128) != 0);
+ if (self->private_impl.f_has_global_palette) {
v_num_palette_entries = (((uint32_t)(1)) << (1 + (v_flags & 7)));
- v_i = 0;
while (v_i < v_num_palette_entries) {
{
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(7);
- uint32_t t_3;
- if (WUFFS_BASE__LIKELY(io1_a_src - iop_a_src >= 3)) {
- t_3 = ((uint32_t)(wuffs_base__load_u24be(iop_a_src)));
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(8);
+ uint32_t t_4;
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 3)) {
+ t_4 = ((uint32_t)(wuffs_base__load_u24be(iop_a_src)));
iop_a_src += 3;
} else {
self->private_data.s_decode_lsd[0].scratch = 0;
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(8);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(9);
while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
uint64_t* scratch = &self->private_data.s_decode_lsd[0].scratch;
- uint32_t num_bits_3 = ((uint32_t)(*scratch & 0xFF));
+ uint32_t num_bits_4 = ((uint32_t)(*scratch & 0xFF));
*scratch >>= 8;
*scratch <<= 8;
- *scratch |= ((uint64_t)(*iop_a_src++)) << (56 - num_bits_3);
- if (num_bits_3 == 16) {
- t_3 = ((uint32_t)(*scratch >> 40));
+ *scratch |= ((uint64_t)(*iop_a_src++)) << (56 - num_bits_4);
+ if (num_bits_4 == 16) {
+ t_4 = ((uint32_t)(*scratch >> 40));
break;
}
- num_bits_3 += 8;
- *scratch |= ((uint64_t)(num_bits_3));
+ num_bits_4 += 8;
+ *scratch |= ((uint64_t)(num_bits_4));
}
}
- v_argb = t_3;
+ v_argb = t_4;
}
v_argb |= 4278190080;
self->private_data.f_palettes[0][((4 * v_i) + 0)] =
@@ -9376,14 +9817,31 @@
((uint8_t)(((v_argb >> 24) & 255)));
v_i += 1;
}
- while (v_i < 256) {
- self->private_data.f_palettes[0][((4 * v_i) + 0)] = 0;
- self->private_data.f_palettes[0][((4 * v_i) + 1)] = 0;
- self->private_data.f_palettes[0][((4 * v_i) + 2)] = 0;
- self->private_data.f_palettes[0][((4 * v_i) + 3)] = 255;
- v_i += 1;
+ if (self->private_impl.f_quirk_enabled_honor_background_color) {
+ if ((v_background_color_index != 0) &&
+ (((uint32_t)(v_background_color_index)) < v_num_palette_entries)) {
+ v_j = (4 * ((uint32_t)(v_background_color_index)));
+ self->private_impl.f_background_color_u32_argb_premul =
+ ((((uint32_t)(self->private_data.f_palettes[0][(v_j + 0)]))
+ << 0) |
+ (((uint32_t)(self->private_data.f_palettes[0][(v_j + 1)]))
+ << 8) |
+ (((uint32_t)(self->private_data.f_palettes[0][(v_j + 2)]))
+ << 16) |
+ (((uint32_t)(self->private_data.f_palettes[0][(v_j + 3)]))
+ << 24));
+ } else {
+ self->private_impl.f_background_color_u32_argb_premul = 77;
+ }
}
}
+ while (v_i < 256) {
+ self->private_data.f_palettes[0][((4 * v_i) + 0)] = 0;
+ self->private_data.f_palettes[0][((4 * v_i) + 1)] = 0;
+ self->private_data.f_palettes[0][((4 * v_i) + 2)] = 0;
+ self->private_data.f_palettes[0][((4 * v_i) + 3)] = 255;
+ v_i += 1;
+ }
goto ok;
ok:
@@ -9393,17 +9851,19 @@
goto suspend;
suspend:
- self->private_impl.p_decode_lsd[0] = coro_susp_point;
+ self->private_impl.p_decode_lsd[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
self->private_data.s_decode_lsd[0].v_flags = v_flags;
+ self->private_data.s_decode_lsd[0].v_background_color_index =
+ v_background_color_index;
self->private_data.s_decode_lsd[0].v_num_palette_entries =
v_num_palette_entries;
self->private_data.s_decode_lsd[0].v_i = v_i;
goto exit;
exit:
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return status;
@@ -9413,7 +9873,7 @@
static wuffs_base__status //
wuffs_gif__decoder__decode_extension(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_src) {
wuffs_base__status status = NULL;
uint8_t v_label = 0;
@@ -9421,16 +9881,12 @@
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_decode_extension[0];
@@ -9441,7 +9897,7 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -9449,15 +9905,13 @@
v_label = t_0;
}
if (v_label == 249) {
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
status = wuffs_gif__decoder__decode_gc(self, a_src);
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
}
if (status) {
goto suspend;
@@ -9465,15 +9919,13 @@
status = NULL;
goto ok;
} else if (v_label == 255) {
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
status = wuffs_gif__decoder__decode_ae(self, a_src);
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
}
if (status) {
goto suspend;
@@ -9481,15 +9933,13 @@
status = NULL;
goto ok;
}
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
status = wuffs_gif__decoder__skip_blocks(self, a_src);
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
}
if (status) {
goto suspend;
@@ -9503,13 +9953,13 @@
goto suspend;
suspend:
- self->private_impl.p_decode_extension[0] = coro_susp_point;
+ self->private_impl.p_decode_extension[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
goto exit;
exit:
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return status;
@@ -9519,7 +9969,7 @@
static wuffs_base__status //
wuffs_gif__decoder__skip_blocks(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_src) {
wuffs_base__status status = NULL;
uint8_t v_block_size = 0;
@@ -9527,16 +9977,12 @@
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_skip_blocks[0];
@@ -9548,7 +9994,7 @@
while (true) {
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -9562,10 +10008,10 @@
self->private_data.s_skip_blocks[0].scratch = ((uint32_t)(v_block_size));
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
if (self->private_data.s_skip_blocks[0].scratch >
- ((uint64_t)(io1_a_src - iop_a_src))) {
+ ((uint64_t)(io2_a_src - iop_a_src))) {
self->private_data.s_skip_blocks[0].scratch -=
- ((uint64_t)(io1_a_src - iop_a_src));
- iop_a_src = io1_a_src;
+ ((uint64_t)(io2_a_src - iop_a_src));
+ iop_a_src = io2_a_src;
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -9580,13 +10026,13 @@
goto suspend;
suspend:
- self->private_impl.p_skip_blocks[0] = coro_susp_point;
+ self->private_impl.p_skip_blocks[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
goto exit;
exit:
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return status;
@@ -9596,34 +10042,34 @@
static wuffs_base__status //
wuffs_gif__decoder__decode_ae(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_src) {
wuffs_base__status status = NULL;
uint8_t v_c = 0;
uint8_t v_block_size = 0;
- bool v_not_animexts = false;
- bool v_not_netscape = false;
+ bool v_is_animexts = false;
+ bool v_is_netscape = false;
+ bool v_is_iccp = false;
+ bool v_is_xmp = false;
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_decode_ae[0];
if (coro_susp_point) {
v_block_size = self->private_data.s_decode_ae[0].v_block_size;
- v_not_animexts = self->private_data.s_decode_ae[0].v_not_animexts;
- v_not_netscape = self->private_data.s_decode_ae[0].v_not_netscape;
+ v_is_animexts = self->private_data.s_decode_ae[0].v_is_animexts;
+ v_is_netscape = self->private_data.s_decode_ae[0].v_is_netscape;
+ v_is_iccp = self->private_data.s_decode_ae[0].v_is_iccp;
+ v_is_xmp = self->private_data.s_decode_ae[0].v_is_xmp;
}
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
@@ -9631,7 +10077,7 @@
while (true) {
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -9646,33 +10092,38 @@
self->private_data.s_decode_ae[0].scratch = ((uint32_t)(v_block_size));
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
if (self->private_data.s_decode_ae[0].scratch >
- ((uint64_t)(io1_a_src - iop_a_src))) {
+ ((uint64_t)(io2_a_src - iop_a_src))) {
self->private_data.s_decode_ae[0].scratch -=
- ((uint64_t)(io1_a_src - iop_a_src));
- iop_a_src = io1_a_src;
+ ((uint64_t)(io2_a_src - iop_a_src));
+ iop_a_src = io2_a_src;
status = wuffs_base__suspension__short_read;
goto suspend;
}
iop_a_src += self->private_data.s_decode_ae[0].scratch;
goto label_0_break;
}
- v_not_animexts = false;
- v_not_netscape = false;
+ v_is_animexts = true;
+ v_is_netscape = true;
+ v_is_iccp = true;
+ v_is_xmp = true;
v_block_size = 0;
while (v_block_size < 11) {
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
uint8_t t_1 = *iop_a_src++;
v_c = t_1;
}
- v_not_animexts =
- (v_not_animexts || (v_c != wuffs_gif__animexts1dot0[v_block_size]));
- v_not_netscape =
- (v_not_netscape || (v_c != wuffs_gif__netscape2dot0[v_block_size]));
+ v_is_animexts =
+ (v_is_animexts && (v_c == wuffs_gif__animexts1dot0[v_block_size]));
+ v_is_netscape =
+ (v_is_netscape && (v_c == wuffs_gif__netscape2dot0[v_block_size]));
+ v_is_iccp =
+ (v_is_iccp && (v_c == wuffs_gif__iccrgbg1012[v_block_size]));
+ v_is_xmp = (v_is_xmp && (v_c == wuffs_gif__xmpdataxmp[v_block_size]));
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
@@ -9682,101 +10133,135 @@
#pragma GCC diagnostic pop
#endif
}
- if (v_not_animexts && v_not_netscape) {
- goto label_0_break;
- }
- {
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
- status = wuffs_base__suspension__short_read;
- goto suspend;
- }
- uint8_t t_2 = *iop_a_src++;
- v_block_size = t_2;
- }
- if (v_block_size != 3) {
- self->private_data.s_decode_ae[0].scratch = ((uint32_t)(v_block_size));
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(5);
- if (self->private_data.s_decode_ae[0].scratch >
- ((uint64_t)(io1_a_src - iop_a_src))) {
- self->private_data.s_decode_ae[0].scratch -=
- ((uint64_t)(io1_a_src - iop_a_src));
- iop_a_src = io1_a_src;
- status = wuffs_base__suspension__short_read;
- goto suspend;
- }
- iop_a_src += self->private_data.s_decode_ae[0].scratch;
- goto label_0_break;
- }
- {
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(6);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
- status = wuffs_base__suspension__short_read;
- goto suspend;
- }
- uint8_t t_3 = *iop_a_src++;
- v_c = t_3;
- }
- if (v_c != 1) {
- self->private_data.s_decode_ae[0].scratch = 2;
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(7);
- if (self->private_data.s_decode_ae[0].scratch >
- ((uint64_t)(io1_a_src - iop_a_src))) {
- self->private_data.s_decode_ae[0].scratch -=
- ((uint64_t)(io1_a_src - iop_a_src));
- iop_a_src = io1_a_src;
- status = wuffs_base__suspension__short_read;
- goto suspend;
- }
- iop_a_src += self->private_data.s_decode_ae[0].scratch;
- goto label_0_break;
- }
- {
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(8);
- uint32_t t_4;
- if (WUFFS_BASE__LIKELY(io1_a_src - iop_a_src >= 2)) {
- t_4 = ((uint32_t)(wuffs_base__load_u16le(iop_a_src)));
- iop_a_src += 2;
- } else {
- self->private_data.s_decode_ae[0].scratch = 0;
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(9);
- while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
- status = wuffs_base__suspension__short_read;
- goto suspend;
- }
- uint64_t* scratch = &self->private_data.s_decode_ae[0].scratch;
- uint32_t num_bits_4 = ((uint32_t)(*scratch >> 56));
- *scratch <<= 8;
- *scratch >>= 8;
- *scratch |= ((uint64_t)(*iop_a_src++)) << num_bits_4;
- if (num_bits_4 == 8) {
- t_4 = ((uint32_t)(*scratch));
- break;
- }
- num_bits_4 += 8;
- *scratch |= ((uint64_t)(num_bits_4)) << 56;
+ if (v_is_animexts || v_is_netscape) {
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+ status = wuffs_base__suspension__short_read;
+ goto suspend;
}
+ uint8_t t_2 = *iop_a_src++;
+ v_block_size = t_2;
}
- self->private_impl.f_num_loops = t_4;
- }
- self->private_impl.f_seen_num_loops = true;
- if ((0 < self->private_impl.f_num_loops) &&
- (self->private_impl.f_num_loops <= 65535)) {
- self->private_impl.f_num_loops += 1;
+ if (v_block_size != 3) {
+ self->private_data.s_decode_ae[0].scratch =
+ ((uint32_t)(v_block_size));
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(5);
+ if (self->private_data.s_decode_ae[0].scratch >
+ ((uint64_t)(io2_a_src - iop_a_src))) {
+ self->private_data.s_decode_ae[0].scratch -=
+ ((uint64_t)(io2_a_src - iop_a_src));
+ iop_a_src = io2_a_src;
+ status = wuffs_base__suspension__short_read;
+ goto suspend;
+ }
+ iop_a_src += self->private_data.s_decode_ae[0].scratch;
+ goto label_0_break;
+ }
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(6);
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+ status = wuffs_base__suspension__short_read;
+ goto suspend;
+ }
+ uint8_t t_3 = *iop_a_src++;
+ v_c = t_3;
+ }
+ if (v_c != 1) {
+ self->private_data.s_decode_ae[0].scratch = 2;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(7);
+ if (self->private_data.s_decode_ae[0].scratch >
+ ((uint64_t)(io2_a_src - iop_a_src))) {
+ self->private_data.s_decode_ae[0].scratch -=
+ ((uint64_t)(io2_a_src - iop_a_src));
+ iop_a_src = io2_a_src;
+ status = wuffs_base__suspension__short_read;
+ goto suspend;
+ }
+ iop_a_src += self->private_data.s_decode_ae[0].scratch;
+ goto label_0_break;
+ }
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(8);
+ uint32_t t_4;
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 2)) {
+ t_4 = ((uint32_t)(wuffs_base__load_u16le(iop_a_src)));
+ iop_a_src += 2;
+ } else {
+ self->private_data.s_decode_ae[0].scratch = 0;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(9);
+ while (true) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+ status = wuffs_base__suspension__short_read;
+ goto suspend;
+ }
+ uint64_t* scratch = &self->private_data.s_decode_ae[0].scratch;
+ uint32_t num_bits_4 = ((uint32_t)(*scratch >> 56));
+ *scratch <<= 8;
+ *scratch >>= 8;
+ *scratch |= ((uint64_t)(*iop_a_src++)) << num_bits_4;
+ if (num_bits_4 == 8) {
+ t_4 = ((uint32_t)(*scratch));
+ break;
+ }
+ num_bits_4 += 8;
+ *scratch |= ((uint64_t)(num_bits_4)) << 56;
+ }
+ }
+ self->private_impl.f_num_loops = t_4;
+ }
+ self->private_impl.f_seen_num_loops = true;
+ if ((0 < self->private_impl.f_num_loops) &&
+ (self->private_impl.f_num_loops <= 65535)) {
+ self->private_impl.f_num_loops += 1;
+ }
+ } else if (self->private_impl.f_ignore_metadata) {
+ } else if (v_is_iccp && self->private_impl.f_report_metadata_iccp) {
+ while (((uint64_t)(io2_a_src - iop_a_src)) <= 0) {
+ status = wuffs_base__suspension__short_read;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(10);
+ }
+ self->private_impl.f_metadata_chunk_length_value =
+ ((uint64_t)(wuffs_base__load_u8be(iop_a_src)));
+ (iop_a_src += 1, wuffs_base__make_empty_struct());
+ self->private_impl.f_metadata_fourcc_value = 1229144912;
+ self->private_impl.f_metadata_io_position = wuffs_base__u64__sat_add(
+ (a_src ? wuffs_base__u64__sat_add(
+ a_src->meta.pos,
+ ((uint64_t)(iop_a_src - a_src->data.ptr)))
+ : 0),
+ self->private_impl.f_metadata_chunk_length_value);
+ self->private_impl.f_call_sequence = 1;
+ status = wuffs_base__warning__metadata_reported;
+ goto ok;
+ } else if (v_is_xmp && self->private_impl.f_report_metadata_xmp) {
+ while (((uint64_t)(io2_a_src - iop_a_src)) <= 0) {
+ status = wuffs_base__suspension__short_read;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(11);
+ }
+ self->private_impl.f_metadata_chunk_length_value =
+ (((uint64_t)(wuffs_base__load_u8be(iop_a_src))) + 1);
+ self->private_impl.f_metadata_fourcc_value = 1481461792;
+ self->private_impl.f_metadata_io_position = wuffs_base__u64__sat_add(
+ (a_src ? wuffs_base__u64__sat_add(
+ a_src->meta.pos,
+ ((uint64_t)(iop_a_src - a_src->data.ptr)))
+ : 0),
+ self->private_impl.f_metadata_chunk_length_value);
+ self->private_impl.f_call_sequence = 1;
+ status = wuffs_base__warning__metadata_reported;
+ goto ok;
}
goto label_0_break;
}
label_0_break:;
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(10);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(12);
status = wuffs_gif__decoder__skip_blocks(self, a_src);
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
}
if (status) {
goto suspend;
@@ -9790,16 +10275,18 @@
goto suspend;
suspend:
- self->private_impl.p_decode_ae[0] = coro_susp_point;
+ self->private_impl.p_decode_ae[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
self->private_data.s_decode_ae[0].v_block_size = v_block_size;
- self->private_data.s_decode_ae[0].v_not_animexts = v_not_animexts;
- self->private_data.s_decode_ae[0].v_not_netscape = v_not_netscape;
+ self->private_data.s_decode_ae[0].v_is_animexts = v_is_animexts;
+ self->private_data.s_decode_ae[0].v_is_netscape = v_is_netscape;
+ self->private_data.s_decode_ae[0].v_is_iccp = v_is_iccp;
+ self->private_data.s_decode_ae[0].v_is_xmp = v_is_xmp;
goto exit;
exit:
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return status;
@@ -9809,7 +10296,7 @@
static wuffs_base__status //
wuffs_gif__decoder__decode_gc(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_src) {
wuffs_base__status status = NULL;
uint8_t v_c = 0;
@@ -9819,16 +10306,12 @@
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_decode_gc[0];
@@ -9837,13 +10320,9 @@
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
- if (self->private_impl.f_seen_graphic_control) {
- status = wuffs_gif__error__bad_graphic_control;
- goto exit;
- }
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -9856,7 +10335,7 @@
}
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -9875,14 +10354,14 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
uint16_t t_2;
- if (WUFFS_BASE__LIKELY(io1_a_src - iop_a_src >= 2)) {
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 2)) {
t_2 = wuffs_base__load_u16le(iop_a_src);
iop_a_src += 2;
} else {
self->private_data.s_decode_gc[0].scratch = 0;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -9905,7 +10384,7 @@
(((uint64_t)(v_gc_duration_centiseconds)) * 7056000);
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(5);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -9914,7 +10393,7 @@
}
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(6);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -9925,7 +10404,6 @@
status = wuffs_gif__error__bad_graphic_control;
goto exit;
}
- self->private_impl.f_seen_graphic_control = true;
goto ok;
ok:
@@ -9935,13 +10413,13 @@
goto suspend;
suspend:
- self->private_impl.p_decode_gc[0] = coro_susp_point;
+ self->private_impl.p_decode_gc[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
goto exit;
exit:
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return status;
@@ -9951,22 +10429,18 @@
static wuffs_base__status //
wuffs_gif__decoder__decode_id_part0(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_src) {
wuffs_base__status status = NULL;
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_decode_id_part0[0];
@@ -9978,14 +10452,14 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
uint32_t t_0;
- if (WUFFS_BASE__LIKELY(io1_a_src - iop_a_src >= 2)) {
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 2)) {
t_0 = ((uint32_t)(wuffs_base__load_u16le(iop_a_src)));
iop_a_src += 2;
} else {
self->private_data.s_decode_id_part0[0].scratch = 0;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -10007,14 +10481,14 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
uint32_t t_1;
- if (WUFFS_BASE__LIKELY(io1_a_src - iop_a_src >= 2)) {
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 2)) {
t_1 = ((uint32_t)(wuffs_base__load_u16le(iop_a_src)));
iop_a_src += 2;
} else {
self->private_data.s_decode_id_part0[0].scratch = 0;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -10036,14 +10510,14 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(5);
uint32_t t_2;
- if (WUFFS_BASE__LIKELY(io1_a_src - iop_a_src >= 2)) {
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 2)) {
t_2 = ((uint32_t)(wuffs_base__load_u16le(iop_a_src)));
iop_a_src += 2;
} else {
self->private_data.s_decode_id_part0[0].scratch = 0;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(6);
while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -10066,14 +10540,14 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(7);
uint32_t t_3;
- if (WUFFS_BASE__LIKELY(io1_a_src - iop_a_src >= 2)) {
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 2)) {
t_3 = ((uint32_t)(wuffs_base__load_u16le(iop_a_src)));
iop_a_src += 2;
} else {
self->private_data.s_decode_id_part0[0].scratch = 0;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(8);
while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -10095,7 +10569,8 @@
self->private_impl.f_frame_rect_y1 += self->private_impl.f_frame_rect_y0;
self->private_impl.f_dst_x = self->private_impl.f_frame_rect_x0;
self->private_impl.f_dst_y = self->private_impl.f_frame_rect_y0;
- if (self->private_impl.f_call_sequence == 0) {
+ if ((self->private_impl.f_call_sequence == 0) &&
+ !self->private_impl.f_quirk_enabled_image_bounds_are_strict) {
self->private_impl.f_width = wuffs_base__u32__max(
self->private_impl.f_width, self->private_impl.f_frame_rect_x1);
self->private_impl.f_height = wuffs_base__u32__max(
@@ -10110,13 +10585,13 @@
goto suspend;
suspend:
- self->private_impl.p_decode_id_part0[0] = coro_susp_point;
+ self->private_impl.p_decode_id_part0[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
goto exit;
exit:
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return status;
@@ -10127,33 +10602,32 @@
static wuffs_base__status //
wuffs_gif__decoder__decode_id_part1(wuffs_gif__decoder* self,
wuffs_base__pixel_buffer* a_dst,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_src) {
wuffs_base__status status = NULL;
uint8_t v_flags = 0;
+ uint8_t v_which_palette = 0;
uint32_t v_num_palette_entries = 0;
uint32_t v_i = 0;
uint32_t v_argb = 0;
wuffs_base__slice_u8 v_dst_palette = {0};
+ wuffs_base__status v_status = NULL;
uint8_t v_lw = 0;
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_decode_id_part1[0];
if (coro_susp_point) {
+ v_which_palette = self->private_data.s_decode_id_part1[0].v_which_palette;
v_num_palette_entries =
self->private_data.s_decode_id_part1[0].v_num_palette_entries;
v_i = self->private_data.s_decode_id_part1[0].v_i;
@@ -10163,7 +10637,7 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -10175,7 +10649,7 @@
} else {
self->private_impl.f_interlace = 0;
}
- self->private_impl.f_which_palette = 1;
+ v_which_palette = 1;
if ((v_flags & 128) != 0) {
v_num_palette_entries = (((uint32_t)(1)) << (1 + (v_flags & 7)));
v_i = 0;
@@ -10183,14 +10657,14 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
uint32_t t_1;
- if (WUFFS_BASE__LIKELY(io1_a_src - iop_a_src >= 3)) {
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 3)) {
t_1 = ((uint32_t)(wuffs_base__load_u24be(iop_a_src)));
iop_a_src += 3;
} else {
self->private_data.s_decode_id_part1[0].scratch = 0;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -10228,12 +10702,16 @@
self->private_data.f_palettes[1][((4 * v_i) + 3)] = 255;
v_i += 1;
}
+ } else if (self->private_impl.f_quirk_enabled_reject_empty_palette &&
+ !self->private_impl.f_has_global_palette) {
+ status = wuffs_gif__error__bad_palette;
+ goto exit;
} else if (self->private_impl.f_gc_has_transparent_index) {
wuffs_base__slice_u8__copy_from_slice(
wuffs_base__make_slice_u8(self->private_data.f_palettes[1], 1024),
wuffs_base__make_slice_u8(self->private_data.f_palettes[0], 1024));
} else {
- self->private_impl.f_which_palette = 0;
+ v_which_palette = 0;
}
if (self->private_impl.f_gc_has_transparent_index) {
self->private_data.f_palettes[1][(
@@ -10254,13 +10732,22 @@
v_dst_palette =
wuffs_base__make_slice_u8(self->private_data.f_dst_palette, 1024);
}
- wuffs_base__pixel_swizzler__prepare(
+ v_status = wuffs_base__pixel_swizzler__prepare(
&self->private_impl.f_swizzler,
wuffs_base__pixel_buffer__pixel_format(a_dst), v_dst_palette,
1191444488,
wuffs_base__make_slice_u8(
- self->private_data.f_palettes[self->private_impl.f_which_palette],
- 1024));
+ self->private_data.f_palettes[v_which_palette], 1024));
+ if (!wuffs_base__status__is_ok(v_status)) {
+ status = v_status;
+ if (wuffs_base__status__is_error(status)) {
+ goto exit;
+ } else if (wuffs_base__status__is_suspension(status)) {
+ status = wuffs_base__error__cannot_return_a_suspension;
+ goto exit;
+ }
+ goto ok;
+ }
if (self->private_impl.f_previous_lzw_decode_ended_abruptly) {
wuffs_base__ignore_status(wuffs_lzw__decoder__initialize(
&self->private_data.f_lzw, sizeof(wuffs_lzw__decoder), WUFFS_VERSION,
@@ -10268,14 +10755,14 @@
}
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
uint8_t t_2 = *iop_a_src++;
v_lw = t_2;
}
- if ((v_lw < 2) || (8 < v_lw)) {
+ if (v_lw > 8) {
status = wuffs_gif__error__bad_literal_width;
goto exit;
}
@@ -10291,16 +10778,17 @@
goto suspend;
suspend:
- self->private_impl.p_decode_id_part1[0] = coro_susp_point;
+ self->private_impl.p_decode_id_part1[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
+ self->private_data.s_decode_id_part1[0].v_which_palette = v_which_palette;
self->private_data.s_decode_id_part1[0].v_num_palette_entries =
v_num_palette_entries;
self->private_data.s_decode_id_part1[0].v_i = v_i;
goto exit;
exit:
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return status;
@@ -10311,7 +10799,7 @@
static wuffs_base__status //
wuffs_gif__decoder__decode_id_part2(wuffs_gif__decoder* self,
wuffs_base__pixel_buffer* a_dst,
- wuffs_base__io_reader a_src,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf) {
wuffs_base__status status = NULL;
@@ -10319,11 +10807,13 @@
bool v_need_block_size = false;
uint64_t v_n_compressed = 0;
wuffs_base__slice_u8 v_compressed = {0};
- wuffs_base__io_reader v_r = wuffs_base__null_io_reader();
- wuffs_base__io_buffer u_r WUFFS_BASE__POTENTIALLY_UNUSED =
- wuffs_base__null_io_buffer();
+ wuffs_base__io_buffer u_r = wuffs_base__null_io_buffer();
+ wuffs_base__io_buffer* v_r = &u_r;
uint8_t* iop_v_r WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ uint8_t* io0_v_r WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_v_r WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ uint8_t* io2_v_r WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ uint64_t v_mark = 0;
wuffs_base__status v_lzw_status = NULL;
wuffs_base__status v_copy_status = NULL;
wuffs_base__slice_u8 v_uncompressed = {0};
@@ -10331,16 +10821,12 @@
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_decode_id_part2[0];
@@ -10360,7 +10846,7 @@
v_need_block_size = false;
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -10371,7 +10857,7 @@
if (v_block_size == 0) {
goto label_0_break;
}
- while (((uint64_t)(io1_a_src - iop_a_src)) == 0) {
+ while (((uint64_t)(io2_a_src - iop_a_src)) == 0) {
status = wuffs_base__suspension__short_read;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(2);
}
@@ -10382,12 +10868,12 @@
}
while (self->private_impl.f_compressed_wi <= 3841) {
v_n_compressed = wuffs_base__u64__min(
- v_block_size, ((uint64_t)(io1_a_src - iop_a_src)));
+ v_block_size, ((uint64_t)(io2_a_src - iop_a_src)));
if (v_n_compressed <= 0) {
goto label_1_break;
}
v_compressed =
- wuffs_base__io_reader__take(&iop_a_src, io1_a_src, v_n_compressed);
+ wuffs_base__io_reader__take(&iop_a_src, io2_a_src, v_n_compressed);
wuffs_base__slice_u8__copy_from_slice(
wuffs_base__slice_u8__subslice_i(
wuffs_base__make_slice_u8(self->private_data.f_compressed,
@@ -10400,7 +10886,7 @@
if (v_block_size > 0) {
goto label_1_break;
}
- if (((uint64_t)(io1_a_src - iop_a_src)) <= 0) {
+ if (((uint64_t)(io2_a_src - iop_a_src)) <= 0) {
v_need_block_size = true;
goto label_1_break;
}
@@ -10421,16 +10907,19 @@
goto exit;
}
{
- wuffs_base__io_reader o_0_v_r = v_r;
+ wuffs_base__io_buffer* o_0_v_r = v_r;
uint8_t* o_0_iop_v_r = iop_v_r;
+ uint8_t* o_0_io0_v_r = io0_v_r;
uint8_t* o_0_io1_v_r = io1_v_r;
- wuffs_base__io_reader__set(
- &v_r, &u_r, &iop_v_r, &io1_v_r,
+ uint8_t* o_0_io2_v_r = io2_v_r;
+ v_r = wuffs_base__io_reader__set(
+ &u_r, &iop_v_r, &io0_v_r, &io1_v_r, &io2_v_r,
wuffs_base__slice_u8__subslice_ij(
wuffs_base__make_slice_u8(self->private_data.f_compressed,
4096),
self->private_impl.f_compressed_ri,
self->private_impl.f_compressed_wi));
+ v_mark = ((uint64_t)(iop_v_r - io0_v_r));
{
u_r.meta.ri = ((size_t)(iop_v_r - u_r.data.ptr));
wuffs_base__status t_1 = wuffs_lzw__decoder__decode_io_writer(
@@ -10442,10 +10931,13 @@
}
wuffs_base__u64__sat_add_indirect(
&self->private_impl.f_compressed_ri,
- ((uint64_t)(iop_v_r - v_r.private_impl.mark)));
+ wuffs_base__io__count_since(v_mark,
+ ((uint64_t)(iop_v_r - io0_v_r))));
v_r = o_0_v_r;
iop_v_r = o_0_iop_v_r;
+ io0_v_r = o_0_io0_v_r;
io1_v_r = o_0_io1_v_r;
+ io2_v_r = o_0_io2_v_r;
}
v_uncompressed = wuffs_lzw__decoder__flush(&self->private_data.f_lzw);
if (((uint64_t)(v_uncompressed.len)) > 0) {
@@ -10463,23 +10955,21 @@
((uint32_t)(v_block_size));
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
if (self->private_data.s_decode_id_part2[0].scratch >
- ((uint64_t)(io1_a_src - iop_a_src))) {
+ ((uint64_t)(io2_a_src - iop_a_src))) {
self->private_data.s_decode_id_part2[0].scratch -=
- ((uint64_t)(io1_a_src - iop_a_src));
- iop_a_src = io1_a_src;
+ ((uint64_t)(io2_a_src - iop_a_src));
+ iop_a_src = io2_a_src;
status = wuffs_base__suspension__short_read;
goto suspend;
}
iop_a_src += self->private_data.s_decode_id_part2[0].scratch;
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
status = wuffs_gif__decoder__skip_blocks(self, a_src);
- if (a_src.private_impl.buf) {
- iop_a_src = a_src.private_impl.buf->data.ptr +
- a_src.private_impl.buf->meta.ri;
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
}
if (status) {
goto suspend;
@@ -10521,16 +11011,16 @@
goto suspend;
suspend:
- self->private_impl.p_decode_id_part2[0] = coro_susp_point;
+ self->private_impl.p_decode_id_part2[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
self->private_data.s_decode_id_part2[0].v_block_size = v_block_size;
self->private_data.s_decode_id_part2[0].v_need_block_size = v_need_block_size;
self->private_data.s_decode_id_part2[0].v_lzw_status = v_lzw_status;
goto exit;
exit:
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return status;
@@ -10547,23 +11037,29 @@
uint64_t v_n = 0;
uint64_t v_src_ri = 0;
uint32_t v_bytes_per_pixel = 0;
- uint32_t v_pixfmt = 0;
+ uint32_t v_pixfmt_channels = 0;
wuffs_base__table_u8 v_tab = {0};
uint64_t v_i = 0;
uint64_t v_j = 0;
- v_bytes_per_pixel = 1;
- v_pixfmt = wuffs_base__pixel_buffer__pixel_format(a_pb);
- if ((v_pixfmt == 1157662856) || (v_pixfmt == 1426098312) ||
- (v_pixfmt == 1174440072) || (v_pixfmt == 1442875528) ||
- (v_pixfmt == 1191217288) || (v_pixfmt == 1459652744)) {
+ v_pixfmt_channels = (wuffs_base__pixel_buffer__pixel_format(a_pb) & 65535);
+ if (v_pixfmt_channels == 34952) {
v_bytes_per_pixel = 4;
+ } else if (v_pixfmt_channels == 2184) {
+ v_bytes_per_pixel = 3;
+ } else if (v_pixfmt_channels == 8) {
+ v_bytes_per_pixel = 1;
+ } else {
+ return wuffs_base__error__unsupported_option;
}
v_tab = wuffs_base__pixel_buffer__plane(a_pb, 0);
label_0_continue:;
while (v_src_ri < ((uint64_t)(a_src.len))) {
v_src = wuffs_base__slice_u8__subslice_i(a_src, v_src_ri);
if (self->private_impl.f_dst_y >= self->private_impl.f_frame_rect_y1) {
+ if (self->private_impl.f_quirk_enabled_ignore_too_much_pixel_data) {
+ return NULL;
+ }
return wuffs_base__error__too_much_data;
}
v_dst = wuffs_base__table_u8__row(v_tab, self->private_impl.f_dst_y);
@@ -10577,7 +11073,7 @@
} else {
v_dst = wuffs_base__slice_u8__subslice_i(v_dst, v_i);
}
- v_n = wuffs_base__pixel_swizzler__swizzle_packed(
+ v_n = wuffs_base__pixel_swizzler__swizzle_interleaved(
&self->private_impl.f_swizzler, v_dst,
wuffs_base__make_slice_u8(self->private_data.f_dst_palette, 1024),
v_src);
@@ -10778,8 +11274,8 @@
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
wuffs_gzip__decoder__decode_io_writer(wuffs_gzip__decoder* self,
- wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src,
+ wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf) {
if (!self) {
return wuffs_base__error__bad_receiver;
@@ -10789,6 +11285,10 @@
? wuffs_base__error__disabled_by_previous_error
: wuffs_base__error__initialize_not_called;
}
+ if (!a_dst || !a_src) {
+ self->private_impl.magic = WUFFS_BASE__DISABLED;
+ return wuffs_base__error__bad_argument;
+ }
if ((self->private_impl.active_coroutine != 0) &&
(self->private_impl.active_coroutine != 1)) {
self->private_impl.magic = WUFFS_BASE__DISABLED;
@@ -10800,6 +11300,7 @@
uint8_t v_c = 0;
uint8_t v_flags = 0;
uint16_t v_xlen = 0;
+ uint64_t v_mark = 0;
uint32_t v_checksum_got = 0;
uint32_t v_decoded_length_got = 0;
wuffs_base__status v_status = NULL;
@@ -10809,33 +11310,25 @@
uint8_t* iop_a_dst = NULL;
uint8_t* io0_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_dst.private_impl.buf) {
- iop_a_dst =
- a_dst.private_impl.buf->data.ptr + a_dst.private_impl.buf->meta.wi;
- if (!a_dst.private_impl.mark) {
- a_dst.private_impl.mark = iop_a_dst;
- a_dst.private_impl.limit =
- a_dst.private_impl.buf->data.ptr + a_dst.private_impl.buf->data.len;
+ uint8_t* io2_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_dst) {
+ io0_a_dst = a_dst->data.ptr;
+ io1_a_dst = io0_a_dst + a_dst->meta.wi;
+ iop_a_dst = io1_a_dst;
+ io2_a_dst = io0_a_dst + a_dst->data.len;
+ if (a_dst->meta.closed) {
+ io2_a_dst = iop_a_dst;
}
- if (a_dst.private_impl.buf->meta.closed) {
- a_dst.private_impl.limit = iop_a_dst;
- }
- io0_a_dst = a_dst.private_impl.mark;
- io1_a_dst = a_dst.private_impl.limit;
}
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_decode_io_writer[0];
@@ -10851,7 +11344,7 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -10864,7 +11357,7 @@
}
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -10877,7 +11370,7 @@
}
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -10890,7 +11383,7 @@
}
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -10900,10 +11393,10 @@
self->private_data.s_decode_io_writer[0].scratch = 6;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(5);
if (self->private_data.s_decode_io_writer[0].scratch >
- ((uint64_t)(io1_a_src - iop_a_src))) {
+ ((uint64_t)(io2_a_src - iop_a_src))) {
self->private_data.s_decode_io_writer[0].scratch -=
- ((uint64_t)(io1_a_src - iop_a_src));
- iop_a_src = io1_a_src;
+ ((uint64_t)(io2_a_src - iop_a_src));
+ iop_a_src = io2_a_src;
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -10912,14 +11405,14 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(6);
uint16_t t_4;
- if (WUFFS_BASE__LIKELY(io1_a_src - iop_a_src >= 2)) {
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 2)) {
t_4 = wuffs_base__load_u16le(iop_a_src);
iop_a_src += 2;
} else {
self->private_data.s_decode_io_writer[0].scratch = 0;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(7);
while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -10942,10 +11435,10 @@
self->private_data.s_decode_io_writer[0].scratch = ((uint32_t)(v_xlen));
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(8);
if (self->private_data.s_decode_io_writer[0].scratch >
- ((uint64_t)(io1_a_src - iop_a_src))) {
+ ((uint64_t)(io2_a_src - iop_a_src))) {
self->private_data.s_decode_io_writer[0].scratch -=
- ((uint64_t)(io1_a_src - iop_a_src));
- iop_a_src = io1_a_src;
+ ((uint64_t)(io2_a_src - iop_a_src));
+ iop_a_src = io2_a_src;
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -10955,7 +11448,7 @@
while (true) {
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(9);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -10972,7 +11465,7 @@
while (true) {
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(10);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -10989,10 +11482,10 @@
self->private_data.s_decode_io_writer[0].scratch = 2;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(11);
if (self->private_data.s_decode_io_writer[0].scratch >
- ((uint64_t)(io1_a_src - iop_a_src))) {
+ ((uint64_t)(io2_a_src - iop_a_src))) {
self->private_data.s_decode_io_writer[0].scratch -=
- ((uint64_t)(io1_a_src - iop_a_src));
- iop_a_src = io1_a_src;
+ ((uint64_t)(io2_a_src - iop_a_src));
+ iop_a_src = io2_a_src;
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -11003,36 +11496,33 @@
goto exit;
}
while (true) {
- wuffs_base__io_writer__set_mark(&a_dst, iop_a_dst);
+ v_mark = ((uint64_t)(iop_a_dst - io0_a_dst));
{
- if (a_dst.private_impl.buf) {
- a_dst.private_impl.buf->meta.wi =
- ((size_t)(iop_a_dst - a_dst.private_impl.buf->data.ptr));
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
}
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
wuffs_base__status t_7 = wuffs_deflate__decoder__decode_io_writer(
&self->private_data.f_flate, a_dst, a_src, a_workbuf);
- if (a_dst.private_impl.buf) {
- iop_a_dst = a_dst.private_impl.buf->data.ptr +
- a_dst.private_impl.buf->meta.wi;
+ if (a_dst) {
+ iop_a_dst = a_dst->data.ptr + a_dst->meta.wi;
}
- if (a_src.private_impl.buf) {
- iop_a_src = a_src.private_impl.buf->data.ptr +
- a_src.private_impl.buf->meta.ri;
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
}
v_status = t_7;
}
if (!self->private_impl.f_ignore_checksum) {
v_checksum_got = wuffs_crc32__ieee_hasher__update(
&self->private_data.f_checksum,
- wuffs_base__make_slice_u8(
- a_dst.private_impl.mark,
- (size_t)(iop_a_dst - a_dst.private_impl.mark)));
- v_decoded_length_got += ((uint32_t)(
- (((uint64_t)(iop_a_dst - a_dst.private_impl.mark)) & 4294967295)));
+ wuffs_base__io__since(v_mark, ((uint64_t)(iop_a_dst - io0_a_dst)),
+ io0_a_dst));
+ v_decoded_length_got +=
+ ((uint32_t)((wuffs_base__io__count_since(
+ v_mark, ((uint64_t)(iop_a_dst - io0_a_dst))) &
+ 4294967295)));
}
if (wuffs_base__status__is_ok(v_status)) {
goto label_2_break;
@@ -11044,14 +11534,14 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(13);
uint32_t t_8;
- if (WUFFS_BASE__LIKELY(io1_a_src - iop_a_src >= 4)) {
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 4)) {
t_8 = wuffs_base__load_u32le(iop_a_src);
iop_a_src += 4;
} else {
self->private_data.s_decode_io_writer[0].scratch = 0;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(14);
while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -11073,14 +11563,14 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(15);
uint32_t t_9;
- if (WUFFS_BASE__LIKELY(io1_a_src - iop_a_src >= 4)) {
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 4)) {
t_9 = wuffs_base__load_u32le(iop_a_src);
iop_a_src += 4;
} else {
self->private_data.s_decode_io_writer[0].scratch = 0;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(16);
while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -11114,8 +11604,10 @@
goto suspend;
suspend:
- self->private_impl.p_decode_io_writer[0] = coro_susp_point;
- self->private_impl.active_coroutine = 1;
+ self->private_impl.p_decode_io_writer[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
+ self->private_impl.active_coroutine =
+ wuffs_base__status__is_suspension(status) ? 1 : 0;
self->private_data.s_decode_io_writer[0].v_flags = v_flags;
self->private_data.s_decode_io_writer[0].v_checksum_got = v_checksum_got;
self->private_data.s_decode_io_writer[0].v_decoded_length_got =
@@ -11124,13 +11616,11 @@
goto exit;
exit:
- if (a_dst.private_impl.buf) {
- a_dst.private_impl.buf->meta.wi =
- ((size_t)(iop_a_dst - a_dst.private_impl.buf->data.ptr));
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
}
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
if (wuffs_base__status__is_error(status)) {
@@ -11265,8 +11755,8 @@
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
wuffs_zlib__decoder__decode_io_writer(wuffs_zlib__decoder* self,
- wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src,
+ wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf) {
if (!self) {
return wuffs_base__error__bad_receiver;
@@ -11276,6 +11766,10 @@
? wuffs_base__error__disabled_by_previous_error
: wuffs_base__error__initialize_not_called;
}
+ if (!a_dst || !a_src) {
+ self->private_impl.magic = WUFFS_BASE__DISABLED;
+ return wuffs_base__error__bad_argument;
+ }
if ((self->private_impl.active_coroutine != 0) &&
(self->private_impl.active_coroutine != 1)) {
self->private_impl.magic = WUFFS_BASE__DISABLED;
@@ -11288,37 +11782,30 @@
uint32_t v_checksum_got = 0;
wuffs_base__status v_status = NULL;
uint32_t v_checksum_want = 0;
+ uint64_t v_mark = 0;
uint8_t* iop_a_dst = NULL;
uint8_t* io0_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_dst.private_impl.buf) {
- iop_a_dst =
- a_dst.private_impl.buf->data.ptr + a_dst.private_impl.buf->meta.wi;
- if (!a_dst.private_impl.mark) {
- a_dst.private_impl.mark = iop_a_dst;
- a_dst.private_impl.limit =
- a_dst.private_impl.buf->data.ptr + a_dst.private_impl.buf->data.len;
+ uint8_t* io2_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_dst) {
+ io0_a_dst = a_dst->data.ptr;
+ io1_a_dst = io0_a_dst + a_dst->meta.wi;
+ iop_a_dst = io1_a_dst;
+ io2_a_dst = io0_a_dst + a_dst->data.len;
+ if (a_dst->meta.closed) {
+ io2_a_dst = iop_a_dst;
}
- if (a_dst.private_impl.buf->meta.closed) {
- a_dst.private_impl.limit = iop_a_dst;
- }
- io0_a_dst = a_dst.private_impl.mark;
- io1_a_dst = a_dst.private_impl.limit;
}
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_decode_io_writer[0];
@@ -11331,14 +11818,14 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
uint16_t t_0;
- if (WUFFS_BASE__LIKELY(io1_a_src - iop_a_src >= 2)) {
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 2)) {
t_0 = wuffs_base__load_u16be(iop_a_src);
iop_a_src += 2;
} else {
self->private_data.s_decode_io_writer[0].scratch = 0;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -11374,34 +11861,29 @@
goto exit;
}
while (true) {
- wuffs_base__io_writer__set_mark(&a_dst, iop_a_dst);
+ v_mark = ((uint64_t)(iop_a_dst - io0_a_dst));
{
- if (a_dst.private_impl.buf) {
- a_dst.private_impl.buf->meta.wi =
- ((size_t)(iop_a_dst - a_dst.private_impl.buf->data.ptr));
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
}
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
wuffs_base__status t_1 = wuffs_deflate__decoder__decode_io_writer(
&self->private_data.f_flate, a_dst, a_src, a_workbuf);
- if (a_dst.private_impl.buf) {
- iop_a_dst = a_dst.private_impl.buf->data.ptr +
- a_dst.private_impl.buf->meta.wi;
+ if (a_dst) {
+ iop_a_dst = a_dst->data.ptr + a_dst->meta.wi;
}
- if (a_src.private_impl.buf) {
- iop_a_src = a_src.private_impl.buf->data.ptr +
- a_src.private_impl.buf->meta.ri;
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
}
v_status = t_1;
}
if (!self->private_impl.f_ignore_checksum) {
v_checksum_got = wuffs_adler32__hasher__update(
&self->private_data.f_checksum,
- wuffs_base__make_slice_u8(
- a_dst.private_impl.mark,
- (size_t)(iop_a_dst - a_dst.private_impl.mark)));
+ wuffs_base__io__since(v_mark, ((uint64_t)(iop_a_dst - io0_a_dst)),
+ io0_a_dst));
}
if (wuffs_base__status__is_ok(v_status)) {
goto label_0_break;
@@ -11413,14 +11895,14 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
uint32_t t_2;
- if (WUFFS_BASE__LIKELY(io1_a_src - iop_a_src >= 4)) {
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 4)) {
t_2 = wuffs_base__load_u32be(iop_a_src);
iop_a_src += 4;
} else {
self->private_data.s_decode_io_writer[0].scratch = 0;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(5);
while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -11453,19 +11935,19 @@
goto suspend;
suspend:
- self->private_impl.p_decode_io_writer[0] = coro_susp_point;
- self->private_impl.active_coroutine = 1;
+ self->private_impl.p_decode_io_writer[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
+ self->private_impl.active_coroutine =
+ wuffs_base__status__is_suspension(status) ? 1 : 0;
self->private_data.s_decode_io_writer[0].v_checksum_got = v_checksum_got;
goto exit;
exit:
- if (a_dst.private_impl.buf) {
- a_dst.private_impl.buf->meta.wi =
- ((size_t)(iop_a_dst - a_dst.private_impl.buf->data.ptr));
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
}
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
if (wuffs_base__status__is_error(status)) {
diff --git a/release/c/wuffs-v0.2.c b/release/c/wuffs-v0.2.c
index 8ea6abd..2a0215b 100644
--- a/release/c/wuffs-v0.2.c
+++ b/release/c/wuffs-v0.2.c
@@ -60,15 +60,15 @@
// each major.minor branch, the commit count should increase monotonically.
//
// WUFFS_VERSION was overridden by "wuffs gen -version" based on revision
-// 6b9f658c593bb57851e3fac7df2e5f3949a4fac8 committed on 2019-04-07.
+// 3037f1e389b54f9721161cc92c9b00372254cafc committed on 2019-07-07.
#define WUFFS_VERSION ((uint64_t)0x0000000000020000)
#define WUFFS_VERSION_MAJOR ((uint64_t)0x00000000)
#define WUFFS_VERSION_MINOR ((uint64_t)0x0002)
#define WUFFS_VERSION_PATCH ((uint64_t)0x0000)
-#define WUFFS_VERSION_PRE_RELEASE_LABEL "alpha.36"
-#define WUFFS_VERSION_BUILD_METADATA_COMMIT_COUNT 1675
-#define WUFFS_VERSION_BUILD_METADATA_COMMIT_DATE 20190407
-#define WUFFS_VERSION_STRING "0.2.0-alpha.36+1675.20190407"
+#define WUFFS_VERSION_PRE_RELEASE_LABEL "alpha.44"
+#define WUFFS_VERSION_BUILD_METADATA_COMMIT_COUNT 1776
+#define WUFFS_VERSION_BUILD_METADATA_COMMIT_DATE 20190707
+#define WUFFS_VERSION_STRING "0.2.0-alpha.44+1776.20190707"
// Define WUFFS_CONFIG__STATIC_FUNCTIONS to make all of Wuffs' functions have
// static storage. The motivation is discussed in the "ALLOW STATIC
@@ -192,8 +192,10 @@
typedef const char* wuffs_base__status;
extern const char* wuffs_base__warning__end_of_data;
+extern const char* wuffs_base__warning__metadata_reported;
extern const char* wuffs_base__suspension__short_read;
extern const char* wuffs_base__suspension__short_write;
+extern const char* wuffs_base__error__bad_i_o_position;
extern const char* wuffs_base__error__bad_argument_length_too_short;
extern const char* wuffs_base__error__bad_argument;
extern const char* wuffs_base__error__bad_call_sequence;
@@ -208,6 +210,7 @@
extern const char* wuffs_base__error__initialize_not_called;
extern const char* wuffs_base__error__interleaved_coroutine_calls;
extern const char* wuffs_base__error__not_enough_data;
+extern const char* wuffs_base__error__unsupported_option;
extern const char* wuffs_base__error__too_much_data;
static inline bool //
@@ -237,6 +240,16 @@
// --------
+// FourCC constants.
+
+// International Color Consortium Profile.
+#define WUFFS_BASE__FOURCC__ICCP 0x49434350
+
+// Extensible Metadata Platform.
+#define WUFFS_BASE__FOURCC__XMP 0x584D5020
+
+// --------
+
// Flicks are a unit of time. One flick (frame-tick) is 1 / 705_600_000 of a
// second. See https://github.com/OculusVR/Flicks
typedef int64_t wuffs_base__flicks;
@@ -510,14 +523,14 @@
uint32_t max_incl;
#ifdef __cplusplus
- inline bool is_empty();
- inline bool equals(wuffs_base__range_ii_u32__struct s);
+ inline bool is_empty() const;
+ inline bool equals(wuffs_base__range_ii_u32__struct s) const;
inline wuffs_base__range_ii_u32__struct intersect(
- wuffs_base__range_ii_u32__struct s);
+ wuffs_base__range_ii_u32__struct s) const;
inline wuffs_base__range_ii_u32__struct unite(
- wuffs_base__range_ii_u32__struct s);
- inline bool contains(uint32_t x);
- inline bool contains_range(wuffs_base__range_ii_u32__struct s);
+ wuffs_base__range_ii_u32__struct s) const;
+ inline bool contains(uint32_t x) const;
+ inline bool contains_range(wuffs_base__range_ii_u32__struct s) const;
#endif // __cplusplus
} wuffs_base__range_ii_u32;
@@ -531,12 +544,12 @@
}
static inline bool //
-wuffs_base__range_ii_u32__is_empty(wuffs_base__range_ii_u32* r) {
+wuffs_base__range_ii_u32__is_empty(const wuffs_base__range_ii_u32* r) {
return r->min_incl > r->max_incl;
}
static inline bool //
-wuffs_base__range_ii_u32__equals(wuffs_base__range_ii_u32* r,
+wuffs_base__range_ii_u32__equals(const wuffs_base__range_ii_u32* r,
wuffs_base__range_ii_u32 s) {
return (r->min_incl == s.min_incl && r->max_incl == s.max_incl) ||
(wuffs_base__range_ii_u32__is_empty(r) &&
@@ -544,7 +557,7 @@
}
static inline wuffs_base__range_ii_u32 //
-wuffs_base__range_ii_u32__intersect(wuffs_base__range_ii_u32* r,
+wuffs_base__range_ii_u32__intersect(const wuffs_base__range_ii_u32* r,
wuffs_base__range_ii_u32 s) {
wuffs_base__range_ii_u32 t;
t.min_incl = wuffs_base__u32__max(r->min_incl, s.min_incl);
@@ -553,7 +566,7 @@
}
static inline wuffs_base__range_ii_u32 //
-wuffs_base__range_ii_u32__unite(wuffs_base__range_ii_u32* r,
+wuffs_base__range_ii_u32__unite(const wuffs_base__range_ii_u32* r,
wuffs_base__range_ii_u32 s) {
if (wuffs_base__range_ii_u32__is_empty(r)) {
return s;
@@ -568,12 +581,13 @@
}
static inline bool //
-wuffs_base__range_ii_u32__contains(wuffs_base__range_ii_u32* r, uint32_t x) {
+wuffs_base__range_ii_u32__contains(const wuffs_base__range_ii_u32* r,
+ uint32_t x) {
return (r->min_incl <= x) && (x <= r->max_incl);
}
static inline bool //
-wuffs_base__range_ii_u32__contains_range(wuffs_base__range_ii_u32* r,
+wuffs_base__range_ii_u32__contains_range(const wuffs_base__range_ii_u32* r,
wuffs_base__range_ii_u32 s) {
return wuffs_base__range_ii_u32__equals(
&s, wuffs_base__range_ii_u32__intersect(r, s));
@@ -582,32 +596,32 @@
#ifdef __cplusplus
inline bool //
-wuffs_base__range_ii_u32::is_empty() {
+wuffs_base__range_ii_u32::is_empty() const {
return wuffs_base__range_ii_u32__is_empty(this);
}
inline bool //
-wuffs_base__range_ii_u32::equals(wuffs_base__range_ii_u32 s) {
+wuffs_base__range_ii_u32::equals(wuffs_base__range_ii_u32 s) const {
return wuffs_base__range_ii_u32__equals(this, s);
}
inline wuffs_base__range_ii_u32 //
-wuffs_base__range_ii_u32::intersect(wuffs_base__range_ii_u32 s) {
+wuffs_base__range_ii_u32::intersect(wuffs_base__range_ii_u32 s) const {
return wuffs_base__range_ii_u32__intersect(this, s);
}
inline wuffs_base__range_ii_u32 //
-wuffs_base__range_ii_u32::unite(wuffs_base__range_ii_u32 s) {
+wuffs_base__range_ii_u32::unite(wuffs_base__range_ii_u32 s) const {
return wuffs_base__range_ii_u32__unite(this, s);
}
inline bool //
-wuffs_base__range_ii_u32::contains(uint32_t x) {
+wuffs_base__range_ii_u32::contains(uint32_t x) const {
return wuffs_base__range_ii_u32__contains(this, x);
}
inline bool //
-wuffs_base__range_ii_u32::contains_range(wuffs_base__range_ii_u32 s) {
+wuffs_base__range_ii_u32::contains_range(wuffs_base__range_ii_u32 s) const {
return wuffs_base__range_ii_u32__contains_range(this, s);
}
@@ -620,15 +634,15 @@
uint32_t max_excl;
#ifdef __cplusplus
- inline bool is_empty();
- inline bool equals(wuffs_base__range_ie_u32__struct s);
+ inline bool is_empty() const;
+ inline bool equals(wuffs_base__range_ie_u32__struct s) const;
inline wuffs_base__range_ie_u32__struct intersect(
- wuffs_base__range_ie_u32__struct s);
+ wuffs_base__range_ie_u32__struct s) const;
inline wuffs_base__range_ie_u32__struct unite(
- wuffs_base__range_ie_u32__struct s);
- inline bool contains(uint32_t x);
- inline bool contains_range(wuffs_base__range_ie_u32__struct s);
- inline uint32_t length();
+ wuffs_base__range_ie_u32__struct s) const;
+ inline bool contains(uint32_t x) const;
+ inline bool contains_range(wuffs_base__range_ie_u32__struct s) const;
+ inline uint32_t length() const;
#endif // __cplusplus
} wuffs_base__range_ie_u32;
@@ -642,12 +656,12 @@
}
static inline bool //
-wuffs_base__range_ie_u32__is_empty(wuffs_base__range_ie_u32* r) {
+wuffs_base__range_ie_u32__is_empty(const wuffs_base__range_ie_u32* r) {
return r->min_incl >= r->max_excl;
}
static inline bool //
-wuffs_base__range_ie_u32__equals(wuffs_base__range_ie_u32* r,
+wuffs_base__range_ie_u32__equals(const wuffs_base__range_ie_u32* r,
wuffs_base__range_ie_u32 s) {
return (r->min_incl == s.min_incl && r->max_excl == s.max_excl) ||
(wuffs_base__range_ie_u32__is_empty(r) &&
@@ -655,7 +669,7 @@
}
static inline wuffs_base__range_ie_u32 //
-wuffs_base__range_ie_u32__intersect(wuffs_base__range_ie_u32* r,
+wuffs_base__range_ie_u32__intersect(const wuffs_base__range_ie_u32* r,
wuffs_base__range_ie_u32 s) {
wuffs_base__range_ie_u32 t;
t.min_incl = wuffs_base__u32__max(r->min_incl, s.min_incl);
@@ -664,7 +678,7 @@
}
static inline wuffs_base__range_ie_u32 //
-wuffs_base__range_ie_u32__unite(wuffs_base__range_ie_u32* r,
+wuffs_base__range_ie_u32__unite(const wuffs_base__range_ie_u32* r,
wuffs_base__range_ie_u32 s) {
if (wuffs_base__range_ie_u32__is_empty(r)) {
return s;
@@ -679,56 +693,57 @@
}
static inline bool //
-wuffs_base__range_ie_u32__contains(wuffs_base__range_ie_u32* r, uint32_t x) {
+wuffs_base__range_ie_u32__contains(const wuffs_base__range_ie_u32* r,
+ uint32_t x) {
return (r->min_incl <= x) && (x < r->max_excl);
}
static inline bool //
-wuffs_base__range_ie_u32__contains_range(wuffs_base__range_ie_u32* r,
+wuffs_base__range_ie_u32__contains_range(const wuffs_base__range_ie_u32* r,
wuffs_base__range_ie_u32 s) {
return wuffs_base__range_ie_u32__equals(
&s, wuffs_base__range_ie_u32__intersect(r, s));
}
static inline uint32_t //
-wuffs_base__range_ie_u32__length(wuffs_base__range_ie_u32* r) {
+wuffs_base__range_ie_u32__length(const wuffs_base__range_ie_u32* r) {
return wuffs_base__u32__sat_sub(r->max_excl, r->min_incl);
}
#ifdef __cplusplus
inline bool //
-wuffs_base__range_ie_u32::is_empty() {
+wuffs_base__range_ie_u32::is_empty() const {
return wuffs_base__range_ie_u32__is_empty(this);
}
inline bool //
-wuffs_base__range_ie_u32::equals(wuffs_base__range_ie_u32 s) {
+wuffs_base__range_ie_u32::equals(wuffs_base__range_ie_u32 s) const {
return wuffs_base__range_ie_u32__equals(this, s);
}
inline wuffs_base__range_ie_u32 //
-wuffs_base__range_ie_u32::intersect(wuffs_base__range_ie_u32 s) {
+wuffs_base__range_ie_u32::intersect(wuffs_base__range_ie_u32 s) const {
return wuffs_base__range_ie_u32__intersect(this, s);
}
inline wuffs_base__range_ie_u32 //
-wuffs_base__range_ie_u32::unite(wuffs_base__range_ie_u32 s) {
+wuffs_base__range_ie_u32::unite(wuffs_base__range_ie_u32 s) const {
return wuffs_base__range_ie_u32__unite(this, s);
}
inline bool //
-wuffs_base__range_ie_u32::contains(uint32_t x) {
+wuffs_base__range_ie_u32::contains(uint32_t x) const {
return wuffs_base__range_ie_u32__contains(this, x);
}
inline bool //
-wuffs_base__range_ie_u32::contains_range(wuffs_base__range_ie_u32 s) {
+wuffs_base__range_ie_u32::contains_range(wuffs_base__range_ie_u32 s) const {
return wuffs_base__range_ie_u32__contains_range(this, s);
}
inline uint32_t //
-wuffs_base__range_ie_u32::length() {
+wuffs_base__range_ie_u32::length() const {
return wuffs_base__range_ie_u32__length(this);
}
@@ -741,14 +756,14 @@
uint64_t max_incl;
#ifdef __cplusplus
- inline bool is_empty();
- inline bool equals(wuffs_base__range_ii_u64__struct s);
+ inline bool is_empty() const;
+ inline bool equals(wuffs_base__range_ii_u64__struct s) const;
inline wuffs_base__range_ii_u64__struct intersect(
- wuffs_base__range_ii_u64__struct s);
+ wuffs_base__range_ii_u64__struct s) const;
inline wuffs_base__range_ii_u64__struct unite(
- wuffs_base__range_ii_u64__struct s);
- inline bool contains(uint64_t x);
- inline bool contains_range(wuffs_base__range_ii_u64__struct s);
+ wuffs_base__range_ii_u64__struct s) const;
+ inline bool contains(uint64_t x) const;
+ inline bool contains_range(wuffs_base__range_ii_u64__struct s) const;
#endif // __cplusplus
} wuffs_base__range_ii_u64;
@@ -762,12 +777,12 @@
}
static inline bool //
-wuffs_base__range_ii_u64__is_empty(wuffs_base__range_ii_u64* r) {
+wuffs_base__range_ii_u64__is_empty(const wuffs_base__range_ii_u64* r) {
return r->min_incl > r->max_incl;
}
static inline bool //
-wuffs_base__range_ii_u64__equals(wuffs_base__range_ii_u64* r,
+wuffs_base__range_ii_u64__equals(const wuffs_base__range_ii_u64* r,
wuffs_base__range_ii_u64 s) {
return (r->min_incl == s.min_incl && r->max_incl == s.max_incl) ||
(wuffs_base__range_ii_u64__is_empty(r) &&
@@ -775,7 +790,7 @@
}
static inline wuffs_base__range_ii_u64 //
-wuffs_base__range_ii_u64__intersect(wuffs_base__range_ii_u64* r,
+wuffs_base__range_ii_u64__intersect(const wuffs_base__range_ii_u64* r,
wuffs_base__range_ii_u64 s) {
wuffs_base__range_ii_u64 t;
t.min_incl = wuffs_base__u64__max(r->min_incl, s.min_incl);
@@ -784,7 +799,7 @@
}
static inline wuffs_base__range_ii_u64 //
-wuffs_base__range_ii_u64__unite(wuffs_base__range_ii_u64* r,
+wuffs_base__range_ii_u64__unite(const wuffs_base__range_ii_u64* r,
wuffs_base__range_ii_u64 s) {
if (wuffs_base__range_ii_u64__is_empty(r)) {
return s;
@@ -799,12 +814,13 @@
}
static inline bool //
-wuffs_base__range_ii_u64__contains(wuffs_base__range_ii_u64* r, uint64_t x) {
+wuffs_base__range_ii_u64__contains(const wuffs_base__range_ii_u64* r,
+ uint64_t x) {
return (r->min_incl <= x) && (x <= r->max_incl);
}
static inline bool //
-wuffs_base__range_ii_u64__contains_range(wuffs_base__range_ii_u64* r,
+wuffs_base__range_ii_u64__contains_range(const wuffs_base__range_ii_u64* r,
wuffs_base__range_ii_u64 s) {
return wuffs_base__range_ii_u64__equals(
&s, wuffs_base__range_ii_u64__intersect(r, s));
@@ -813,32 +829,32 @@
#ifdef __cplusplus
inline bool //
-wuffs_base__range_ii_u64::is_empty() {
+wuffs_base__range_ii_u64::is_empty() const {
return wuffs_base__range_ii_u64__is_empty(this);
}
inline bool //
-wuffs_base__range_ii_u64::equals(wuffs_base__range_ii_u64 s) {
+wuffs_base__range_ii_u64::equals(wuffs_base__range_ii_u64 s) const {
return wuffs_base__range_ii_u64__equals(this, s);
}
inline wuffs_base__range_ii_u64 //
-wuffs_base__range_ii_u64::intersect(wuffs_base__range_ii_u64 s) {
+wuffs_base__range_ii_u64::intersect(wuffs_base__range_ii_u64 s) const {
return wuffs_base__range_ii_u64__intersect(this, s);
}
inline wuffs_base__range_ii_u64 //
-wuffs_base__range_ii_u64::unite(wuffs_base__range_ii_u64 s) {
+wuffs_base__range_ii_u64::unite(wuffs_base__range_ii_u64 s) const {
return wuffs_base__range_ii_u64__unite(this, s);
}
inline bool //
-wuffs_base__range_ii_u64::contains(uint64_t x) {
+wuffs_base__range_ii_u64::contains(uint64_t x) const {
return wuffs_base__range_ii_u64__contains(this, x);
}
inline bool //
-wuffs_base__range_ii_u64::contains_range(wuffs_base__range_ii_u64 s) {
+wuffs_base__range_ii_u64::contains_range(wuffs_base__range_ii_u64 s) const {
return wuffs_base__range_ii_u64__contains_range(this, s);
}
@@ -851,15 +867,15 @@
uint64_t max_excl;
#ifdef __cplusplus
- inline bool is_empty();
- inline bool equals(wuffs_base__range_ie_u64__struct s);
+ inline bool is_empty() const;
+ inline bool equals(wuffs_base__range_ie_u64__struct s) const;
inline wuffs_base__range_ie_u64__struct intersect(
- wuffs_base__range_ie_u64__struct s);
+ wuffs_base__range_ie_u64__struct s) const;
inline wuffs_base__range_ie_u64__struct unite(
- wuffs_base__range_ie_u64__struct s);
- inline bool contains(uint64_t x);
- inline bool contains_range(wuffs_base__range_ie_u64__struct s);
- inline uint64_t length();
+ wuffs_base__range_ie_u64__struct s) const;
+ inline bool contains(uint64_t x) const;
+ inline bool contains_range(wuffs_base__range_ie_u64__struct s) const;
+ inline uint64_t length() const;
#endif // __cplusplus
} wuffs_base__range_ie_u64;
@@ -873,12 +889,12 @@
}
static inline bool //
-wuffs_base__range_ie_u64__is_empty(wuffs_base__range_ie_u64* r) {
+wuffs_base__range_ie_u64__is_empty(const wuffs_base__range_ie_u64* r) {
return r->min_incl >= r->max_excl;
}
static inline bool //
-wuffs_base__range_ie_u64__equals(wuffs_base__range_ie_u64* r,
+wuffs_base__range_ie_u64__equals(const wuffs_base__range_ie_u64* r,
wuffs_base__range_ie_u64 s) {
return (r->min_incl == s.min_incl && r->max_excl == s.max_excl) ||
(wuffs_base__range_ie_u64__is_empty(r) &&
@@ -886,7 +902,7 @@
}
static inline wuffs_base__range_ie_u64 //
-wuffs_base__range_ie_u64__intersect(wuffs_base__range_ie_u64* r,
+wuffs_base__range_ie_u64__intersect(const wuffs_base__range_ie_u64* r,
wuffs_base__range_ie_u64 s) {
wuffs_base__range_ie_u64 t;
t.min_incl = wuffs_base__u64__max(r->min_incl, s.min_incl);
@@ -895,7 +911,7 @@
}
static inline wuffs_base__range_ie_u64 //
-wuffs_base__range_ie_u64__unite(wuffs_base__range_ie_u64* r,
+wuffs_base__range_ie_u64__unite(const wuffs_base__range_ie_u64* r,
wuffs_base__range_ie_u64 s) {
if (wuffs_base__range_ie_u64__is_empty(r)) {
return s;
@@ -910,56 +926,57 @@
}
static inline bool //
-wuffs_base__range_ie_u64__contains(wuffs_base__range_ie_u64* r, uint64_t x) {
+wuffs_base__range_ie_u64__contains(const wuffs_base__range_ie_u64* r,
+ uint64_t x) {
return (r->min_incl <= x) && (x < r->max_excl);
}
static inline bool //
-wuffs_base__range_ie_u64__contains_range(wuffs_base__range_ie_u64* r,
+wuffs_base__range_ie_u64__contains_range(const wuffs_base__range_ie_u64* r,
wuffs_base__range_ie_u64 s) {
return wuffs_base__range_ie_u64__equals(
&s, wuffs_base__range_ie_u64__intersect(r, s));
}
static inline uint64_t //
-wuffs_base__range_ie_u64__length(wuffs_base__range_ie_u64* r) {
+wuffs_base__range_ie_u64__length(const wuffs_base__range_ie_u64* r) {
return wuffs_base__u64__sat_sub(r->max_excl, r->min_incl);
}
#ifdef __cplusplus
inline bool //
-wuffs_base__range_ie_u64::is_empty() {
+wuffs_base__range_ie_u64::is_empty() const {
return wuffs_base__range_ie_u64__is_empty(this);
}
inline bool //
-wuffs_base__range_ie_u64::equals(wuffs_base__range_ie_u64 s) {
+wuffs_base__range_ie_u64::equals(wuffs_base__range_ie_u64 s) const {
return wuffs_base__range_ie_u64__equals(this, s);
}
inline wuffs_base__range_ie_u64 //
-wuffs_base__range_ie_u64::intersect(wuffs_base__range_ie_u64 s) {
+wuffs_base__range_ie_u64::intersect(wuffs_base__range_ie_u64 s) const {
return wuffs_base__range_ie_u64__intersect(this, s);
}
inline wuffs_base__range_ie_u64 //
-wuffs_base__range_ie_u64::unite(wuffs_base__range_ie_u64 s) {
+wuffs_base__range_ie_u64::unite(wuffs_base__range_ie_u64 s) const {
return wuffs_base__range_ie_u64__unite(this, s);
}
inline bool //
-wuffs_base__range_ie_u64::contains(uint64_t x) {
+wuffs_base__range_ie_u64::contains(uint64_t x) const {
return wuffs_base__range_ie_u64__contains(this, x);
}
inline bool //
-wuffs_base__range_ie_u64::contains_range(wuffs_base__range_ie_u64 s) {
+wuffs_base__range_ie_u64::contains_range(wuffs_base__range_ie_u64 s) const {
return wuffs_base__range_ie_u64__contains_range(this, s);
}
inline uint64_t //
-wuffs_base__range_ie_u64::length() {
+wuffs_base__range_ie_u64::length() const {
return wuffs_base__range_ie_u64__length(this);
}
@@ -983,14 +1000,14 @@
uint32_t max_incl_y;
#ifdef __cplusplus
- inline bool is_empty();
- inline bool equals(wuffs_base__rect_ii_u32__struct s);
+ inline bool is_empty() const;
+ inline bool equals(wuffs_base__rect_ii_u32__struct s) const;
inline wuffs_base__rect_ii_u32__struct intersect(
- wuffs_base__rect_ii_u32__struct s);
+ wuffs_base__rect_ii_u32__struct s) const;
inline wuffs_base__rect_ii_u32__struct unite(
- wuffs_base__rect_ii_u32__struct s);
- inline bool contains(uint32_t x, uint32_t y);
- inline bool contains_rect(wuffs_base__rect_ii_u32__struct s);
+ wuffs_base__rect_ii_u32__struct s) const;
+ inline bool contains(uint32_t x, uint32_t y) const;
+ inline bool contains_rect(wuffs_base__rect_ii_u32__struct s) const;
#endif // __cplusplus
} wuffs_base__rect_ii_u32;
@@ -1009,12 +1026,12 @@
}
static inline bool //
-wuffs_base__rect_ii_u32__is_empty(wuffs_base__rect_ii_u32* r) {
+wuffs_base__rect_ii_u32__is_empty(const wuffs_base__rect_ii_u32* r) {
return (r->min_incl_x > r->max_incl_x) || (r->min_incl_y > r->max_incl_y);
}
static inline bool //
-wuffs_base__rect_ii_u32__equals(wuffs_base__rect_ii_u32* r,
+wuffs_base__rect_ii_u32__equals(const wuffs_base__rect_ii_u32* r,
wuffs_base__rect_ii_u32 s) {
return (r->min_incl_x == s.min_incl_x && r->min_incl_y == s.min_incl_y &&
r->max_incl_x == s.max_incl_x && r->max_incl_y == s.max_incl_y) ||
@@ -1023,7 +1040,7 @@
}
static inline wuffs_base__rect_ii_u32 //
-wuffs_base__rect_ii_u32__intersect(wuffs_base__rect_ii_u32* r,
+wuffs_base__rect_ii_u32__intersect(const wuffs_base__rect_ii_u32* r,
wuffs_base__rect_ii_u32 s) {
wuffs_base__rect_ii_u32 t;
t.min_incl_x = wuffs_base__u32__max(r->min_incl_x, s.min_incl_x);
@@ -1034,7 +1051,7 @@
}
static inline wuffs_base__rect_ii_u32 //
-wuffs_base__rect_ii_u32__unite(wuffs_base__rect_ii_u32* r,
+wuffs_base__rect_ii_u32__unite(const wuffs_base__rect_ii_u32* r,
wuffs_base__rect_ii_u32 s) {
if (wuffs_base__rect_ii_u32__is_empty(r)) {
return s;
@@ -1051,7 +1068,7 @@
}
static inline bool //
-wuffs_base__rect_ii_u32__contains(wuffs_base__rect_ii_u32* r,
+wuffs_base__rect_ii_u32__contains(const wuffs_base__rect_ii_u32* r,
uint32_t x,
uint32_t y) {
return (r->min_incl_x <= x) && (x <= r->max_incl_x) && (r->min_incl_y <= y) &&
@@ -1059,7 +1076,7 @@
}
static inline bool //
-wuffs_base__rect_ii_u32__contains_rect(wuffs_base__rect_ii_u32* r,
+wuffs_base__rect_ii_u32__contains_rect(const wuffs_base__rect_ii_u32* r,
wuffs_base__rect_ii_u32 s) {
return wuffs_base__rect_ii_u32__equals(
&s, wuffs_base__rect_ii_u32__intersect(r, s));
@@ -1068,32 +1085,32 @@
#ifdef __cplusplus
inline bool //
-wuffs_base__rect_ii_u32::is_empty() {
+wuffs_base__rect_ii_u32::is_empty() const {
return wuffs_base__rect_ii_u32__is_empty(this);
}
inline bool //
-wuffs_base__rect_ii_u32::equals(wuffs_base__rect_ii_u32 s) {
+wuffs_base__rect_ii_u32::equals(wuffs_base__rect_ii_u32 s) const {
return wuffs_base__rect_ii_u32__equals(this, s);
}
inline wuffs_base__rect_ii_u32 //
-wuffs_base__rect_ii_u32::intersect(wuffs_base__rect_ii_u32 s) {
+wuffs_base__rect_ii_u32::intersect(wuffs_base__rect_ii_u32 s) const {
return wuffs_base__rect_ii_u32__intersect(this, s);
}
inline wuffs_base__rect_ii_u32 //
-wuffs_base__rect_ii_u32::unite(wuffs_base__rect_ii_u32 s) {
+wuffs_base__rect_ii_u32::unite(wuffs_base__rect_ii_u32 s) const {
return wuffs_base__rect_ii_u32__unite(this, s);
}
inline bool //
-wuffs_base__rect_ii_u32::contains(uint32_t x, uint32_t y) {
+wuffs_base__rect_ii_u32::contains(uint32_t x, uint32_t y) const {
return wuffs_base__rect_ii_u32__contains(this, x, y);
}
inline bool //
-wuffs_base__rect_ii_u32::contains_rect(wuffs_base__rect_ii_u32 s) {
+wuffs_base__rect_ii_u32::contains_rect(wuffs_base__rect_ii_u32 s) const {
return wuffs_base__rect_ii_u32__contains_rect(this, s);
}
@@ -1118,16 +1135,16 @@
uint32_t max_excl_y;
#ifdef __cplusplus
- inline bool is_empty();
- inline bool equals(wuffs_base__rect_ie_u32__struct s);
+ inline bool is_empty() const;
+ inline bool equals(wuffs_base__rect_ie_u32__struct s) const;
inline wuffs_base__rect_ie_u32__struct intersect(
- wuffs_base__rect_ie_u32__struct s);
+ wuffs_base__rect_ie_u32__struct s) const;
inline wuffs_base__rect_ie_u32__struct unite(
- wuffs_base__rect_ie_u32__struct s);
- inline bool contains(uint32_t x, uint32_t y);
- inline bool contains_rect(wuffs_base__rect_ie_u32__struct s);
- inline uint32_t width();
- inline uint32_t height();
+ wuffs_base__rect_ie_u32__struct s) const;
+ inline bool contains(uint32_t x, uint32_t y) const;
+ inline bool contains_rect(wuffs_base__rect_ie_u32__struct s) const;
+ inline uint32_t width() const;
+ inline uint32_t height() const;
#endif // __cplusplus
} wuffs_base__rect_ie_u32;
@@ -1146,12 +1163,12 @@
}
static inline bool //
-wuffs_base__rect_ie_u32__is_empty(wuffs_base__rect_ie_u32* r) {
+wuffs_base__rect_ie_u32__is_empty(const wuffs_base__rect_ie_u32* r) {
return (r->min_incl_x >= r->max_excl_x) || (r->min_incl_y >= r->max_excl_y);
}
static inline bool //
-wuffs_base__rect_ie_u32__equals(wuffs_base__rect_ie_u32* r,
+wuffs_base__rect_ie_u32__equals(const wuffs_base__rect_ie_u32* r,
wuffs_base__rect_ie_u32 s) {
return (r->min_incl_x == s.min_incl_x && r->min_incl_y == s.min_incl_y &&
r->max_excl_x == s.max_excl_x && r->max_excl_y == s.max_excl_y) ||
@@ -1160,7 +1177,7 @@
}
static inline wuffs_base__rect_ie_u32 //
-wuffs_base__rect_ie_u32__intersect(wuffs_base__rect_ie_u32* r,
+wuffs_base__rect_ie_u32__intersect(const wuffs_base__rect_ie_u32* r,
wuffs_base__rect_ie_u32 s) {
wuffs_base__rect_ie_u32 t;
t.min_incl_x = wuffs_base__u32__max(r->min_incl_x, s.min_incl_x);
@@ -1171,7 +1188,7 @@
}
static inline wuffs_base__rect_ie_u32 //
-wuffs_base__rect_ie_u32__unite(wuffs_base__rect_ie_u32* r,
+wuffs_base__rect_ie_u32__unite(const wuffs_base__rect_ie_u32* r,
wuffs_base__rect_ie_u32 s) {
if (wuffs_base__rect_ie_u32__is_empty(r)) {
return s;
@@ -1188,7 +1205,7 @@
}
static inline bool //
-wuffs_base__rect_ie_u32__contains(wuffs_base__rect_ie_u32* r,
+wuffs_base__rect_ie_u32__contains(const wuffs_base__rect_ie_u32* r,
uint32_t x,
uint32_t y) {
return (r->min_incl_x <= x) && (x < r->max_excl_x) && (r->min_incl_y <= y) &&
@@ -1196,95 +1213,69 @@
}
static inline bool //
-wuffs_base__rect_ie_u32__contains_rect(wuffs_base__rect_ie_u32* r,
+wuffs_base__rect_ie_u32__contains_rect(const wuffs_base__rect_ie_u32* r,
wuffs_base__rect_ie_u32 s) {
return wuffs_base__rect_ie_u32__equals(
&s, wuffs_base__rect_ie_u32__intersect(r, s));
}
static inline uint32_t //
-wuffs_base__rect_ie_u32__width(wuffs_base__rect_ie_u32* r) {
+wuffs_base__rect_ie_u32__width(const wuffs_base__rect_ie_u32* r) {
return wuffs_base__u32__sat_sub(r->max_excl_x, r->min_incl_x);
}
static inline uint32_t //
-wuffs_base__rect_ie_u32__height(wuffs_base__rect_ie_u32* r) {
+wuffs_base__rect_ie_u32__height(const wuffs_base__rect_ie_u32* r) {
return wuffs_base__u32__sat_sub(r->max_excl_y, r->min_incl_y);
}
#ifdef __cplusplus
inline bool //
-wuffs_base__rect_ie_u32::is_empty() {
+wuffs_base__rect_ie_u32::is_empty() const {
return wuffs_base__rect_ie_u32__is_empty(this);
}
inline bool //
-wuffs_base__rect_ie_u32::equals(wuffs_base__rect_ie_u32 s) {
+wuffs_base__rect_ie_u32::equals(wuffs_base__rect_ie_u32 s) const {
return wuffs_base__rect_ie_u32__equals(this, s);
}
inline wuffs_base__rect_ie_u32 //
-wuffs_base__rect_ie_u32::intersect(wuffs_base__rect_ie_u32 s) {
+wuffs_base__rect_ie_u32::intersect(wuffs_base__rect_ie_u32 s) const {
return wuffs_base__rect_ie_u32__intersect(this, s);
}
inline wuffs_base__rect_ie_u32 //
-wuffs_base__rect_ie_u32::unite(wuffs_base__rect_ie_u32 s) {
+wuffs_base__rect_ie_u32::unite(wuffs_base__rect_ie_u32 s) const {
return wuffs_base__rect_ie_u32__unite(this, s);
}
inline bool //
-wuffs_base__rect_ie_u32::contains(uint32_t x, uint32_t y) {
+wuffs_base__rect_ie_u32::contains(uint32_t x, uint32_t y) const {
return wuffs_base__rect_ie_u32__contains(this, x, y);
}
inline bool //
-wuffs_base__rect_ie_u32::contains_rect(wuffs_base__rect_ie_u32 s) {
+wuffs_base__rect_ie_u32::contains_rect(wuffs_base__rect_ie_u32 s) const {
return wuffs_base__rect_ie_u32__contains_rect(this, s);
}
inline uint32_t //
-wuffs_base__rect_ie_u32::width() {
+wuffs_base__rect_ie_u32::width() const {
return wuffs_base__rect_ie_u32__width(this);
}
inline uint32_t //
-wuffs_base__rect_ie_u32::height() {
+wuffs_base__rect_ie_u32::height() const {
return wuffs_base__rect_ie_u32__height(this);
}
#endif // __cplusplus
// ---------------- I/O
-
-struct wuffs_base__io_buffer__struct;
-
-typedef struct {
- // Do not access the private_impl's fields directly. There is no API/ABI
- // compatibility or safety guarantee if you do so.
- struct {
- struct wuffs_base__io_buffer__struct* buf;
- // The bounds values are typically NULL, when created by the Wuffs public
- // API. NULL means that the callee substitutes the implicit bounds derived
- // from buf.
- uint8_t* mark;
- uint8_t* limit;
- } private_impl;
-} wuffs_base__io_reader;
-
-typedef struct {
- // Do not access the private_impl's fields directly. There is no API/ABI
- // compatibility or safety guarantee if you do so.
- struct {
- struct wuffs_base__io_buffer__struct* buf;
- // The bounds values are typically NULL, when created by the Wuffs public
- // API. NULL means that the callee substitutes the implicit bounds derived
- // from buf.
- uint8_t* mark;
- uint8_t* limit;
- } private_impl;
-} wuffs_base__io_writer;
+//
+// See (/doc/note/io-input-output.md).
// wuffs_base__io_buffer_meta is the metadata for a wuffs_base__io_buffer's
// data.
@@ -1305,10 +1296,12 @@
#ifdef __cplusplus
inline void compact();
- inline wuffs_base__io_reader reader();
- inline wuffs_base__io_writer writer();
- inline uint64_t reader_io_position();
- inline uint64_t writer_io_position();
+ inline wuffs_base__io_buffer__struct* reader(); // Deprecated.
+ inline wuffs_base__io_buffer__struct* writer(); // Deprecated.
+ inline uint64_t reader_available() const;
+ inline uint64_t reader_io_position() const;
+ inline uint64_t writer_available() const;
+ inline uint64_t writer_io_position() const;
#endif // __cplusplus
} wuffs_base__io_buffer;
@@ -1357,24 +1350,6 @@
return ret;
}
-static inline wuffs_base__io_reader //
-wuffs_base__null_io_reader() {
- wuffs_base__io_reader ret;
- ret.private_impl.buf = NULL;
- ret.private_impl.mark = NULL;
- ret.private_impl.limit = NULL;
- return ret;
-}
-
-static inline wuffs_base__io_writer //
-wuffs_base__null_io_writer() {
- wuffs_base__io_writer ret;
- ret.private_impl.buf = NULL;
- ret.private_impl.mark = NULL;
- ret.private_impl.limit = NULL;
- return ret;
-}
-
// wuffs_base__io_buffer__compact moves any written but unread bytes to the
// start of the buffer.
static inline void //
@@ -1391,31 +1366,23 @@
buf->meta.ri = 0;
}
-static inline wuffs_base__io_reader //
-wuffs_base__io_buffer__reader(wuffs_base__io_buffer* buf) {
- wuffs_base__io_reader ret;
- ret.private_impl.buf = buf;
- ret.private_impl.mark = NULL;
- ret.private_impl.limit = NULL;
- return ret;
-}
-
-static inline wuffs_base__io_writer //
-wuffs_base__io_buffer__writer(wuffs_base__io_buffer* buf) {
- wuffs_base__io_writer ret;
- ret.private_impl.buf = buf;
- ret.private_impl.mark = NULL;
- ret.private_impl.limit = NULL;
- return ret;
+static inline uint64_t //
+wuffs_base__io_buffer__reader_available(const wuffs_base__io_buffer* buf) {
+ return buf ? buf->meta.wi - buf->meta.ri : 0;
}
static inline uint64_t //
-wuffs_base__io_buffer__reader_io_position(wuffs_base__io_buffer* buf) {
+wuffs_base__io_buffer__reader_io_position(const wuffs_base__io_buffer* buf) {
return buf ? wuffs_base__u64__sat_add(buf->meta.pos, buf->meta.ri) : 0;
}
static inline uint64_t //
-wuffs_base__io_buffer__writer_io_position(wuffs_base__io_buffer* buf) {
+wuffs_base__io_buffer__writer_available(const wuffs_base__io_buffer* buf) {
+ return buf ? buf->data.len - buf->meta.wi : 0;
+}
+
+static inline uint64_t //
+wuffs_base__io_buffer__writer_io_position(const wuffs_base__io_buffer* buf) {
return buf ? wuffs_base__u64__sat_add(buf->meta.pos, buf->meta.wi) : 0;
}
@@ -1426,23 +1393,33 @@
wuffs_base__io_buffer__compact(this);
}
-inline wuffs_base__io_reader //
+inline wuffs_base__io_buffer* //
wuffs_base__io_buffer__struct::reader() {
- return wuffs_base__io_buffer__reader(this);
+ return this;
}
-inline wuffs_base__io_writer //
+inline wuffs_base__io_buffer* //
wuffs_base__io_buffer__struct::writer() {
- return wuffs_base__io_buffer__writer(this);
+ return this;
}
inline uint64_t //
-wuffs_base__io_buffer__struct::reader_io_position() {
+wuffs_base__io_buffer__struct::reader_available() const {
+ return wuffs_base__io_buffer__reader_available(this);
+}
+
+inline uint64_t //
+wuffs_base__io_buffer__struct::reader_io_position() const {
return wuffs_base__io_buffer__reader_io_position(this);
}
inline uint64_t //
-wuffs_base__io_buffer__struct::writer_io_position() {
+wuffs_base__io_buffer__struct::writer_available() const {
+ return wuffs_base__io_buffer__writer_available(this);
+}
+
+inline uint64_t //
+wuffs_base__io_buffer__struct::writer_io_position() const {
return wuffs_base__io_buffer__writer_io_position(this);
}
@@ -1526,9 +1503,9 @@
// - bit 20 indicates big-endian/MSB-first (as opposed to little/LSB).
// - bit 19 indicates floating point (as opposed to integer).
// - bit 18 indicates palette-indexed. The number-of-planes (the next
-// field) will be zero, as the format is considered packed,
+// field) will be 0, as the format is considered interleaved,
// but the 8-bit N-BGRA color data is stored in plane 3.
-// - bits 17 .. 16 are the number of planes, minus 1. Zero means packed.
+// - bits 17 .. 16 are the number of planes, minus 1. Zero means interleaved.
// - bits 15 .. 12 encodes the number of bits (depth) in the 3rd channel.
// - bits 11 .. 8 encodes the number of bits (depth) in the 2nd channel.
// - bits 7 .. 4 encodes the number of bits (depth) in the 1st channel.
@@ -1545,14 +1522,14 @@
// channels: cyan, magenta, yellow, black).
//
// For direct formats with N > 1 channels, those channels can be laid out in
-// either 1 (packed) or N (planar) planes. For example, RGBA data is usually
-// packed, but YCbCr data is usually planar, due to chroma subsampling (for
-// details, see the wuffs_base__pixel_subsampling type).
+// either 1 (interleaved) or N (planar) planes. For example, RGBA data is
+// usually interleaved, but YCbCr data is usually planar, due to chroma
+// subsampling (for details, see the wuffs_base__pixel_subsampling type).
//
// For indexed formats, the palette (always 256 × 4 bytes) holds 8 bits per
// channel non-alpha-premultiplied BGRA color data. There is only 1 plane (for
-// the index), as the format is considered packed. Plane 0 holds the per-pixel
-// indices. Plane 3 is re-purposed to hold the per-index colors.
+// the index), as the format is considered interleaved. Plane 0 holds the
+// per-pixel indices. Plane 3 is re-purposed to hold the per-index colors.
//
// The color field is encoded in 3 bits:
// - 0 means A (Alpha).
@@ -1566,8 +1543,8 @@
//
// In Wuffs, channels are given in memory order (also known as byte order),
// regardless of endianness, since the C type for the pixel data is an array of
-// bytes, not an array of uint32_t. For example, packed BGRA with 8 bits per
-// channel means that the bytes in memory are always Blue, Green, Red then
+// bytes, not an array of uint32_t. For example, interleaved BGRA with 8 bits
+// per channel means that the bytes in memory are always Blue, Green, Red then
// Alpha. On big-endian systems, that is the uint32_t 0xBBGGRRAA. On
// little-endian, 0xAARRGGBB.
//
@@ -1600,15 +1577,15 @@
//
// For example, wuffs_base__pixel_format 0x5510BBBB is a natural format for
// decoding a PNG image - network byte order (also known as big-endian),
-// packed, non-premultiplied alpha - that happens to be 16-bit-depth truecolor
-// with alpha (RGBA). In memory order:
+// interleaved, non-premultiplied alpha - that happens to be 16-bit-depth
+// truecolor with alpha (RGBA). In memory order:
//
// ptr+0 ptr+1 ptr+2 ptr+3 ptr+4 ptr+5 ptr+6 ptr+7
// Rhi Rlo Ghi Glo Bhi Blo Ahi Alo
//
// For example, the value wuffs_base__pixel_format 0x40000565 means BGR with no
-// alpha or padding, 5/6/5 bits for blue/green/red, packed 2 bytes per pixel,
-// laid out LSB-first in memory order:
+// alpha or padding, 5/6/5 bits for blue/green/red, interleaved 2 bytes per
+// pixel, laid out LSB-first in memory order:
//
// ptr+0........... ptr+1...........
// MSB LSB MSB LSB
@@ -1693,8 +1670,8 @@
return f != 0;
}
-// wuffs_base__pixel_format__bits_per_pixel returns, for packed pixel formats,
-// the number of bits per pixel. It returns 0 for planar pixel formats.
+// 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) {
@@ -1712,7 +1689,7 @@
}
static inline bool //
-wuffs_base__pixel_format__is_packed(wuffs_base__pixel_format f) {
+wuffs_base__pixel_format__is_interleaved(wuffs_base__pixel_format f) {
return ((f >> 16) & 0x03) == 0;
}
@@ -1738,7 +1715,7 @@
// plane p. For a depth of 8 bits (1 byte), the p'th plane's sample starts at
// (planes[p].ptr + (j * planes[p].stride) + i).
//
-// For packed pixel formats, the mapping is trivial: i = x and j = y. For
+// For interleaved pixel formats, the mapping is trivial: i = x and j = y. For
// planar pixel formats, the mapping can differ due to chroma subsampling. For
// example, consider a three plane YCbCr pixel format with 4:2:2 subsampling.
// For the luma (Y) channel, there is one sample for every pixel, but for the
@@ -1829,13 +1806,13 @@
uint32_t width,
uint32_t height);
inline void invalidate();
- inline bool is_valid();
- inline wuffs_base__pixel_format pixel_format();
- inline wuffs_base__pixel_subsampling pixel_subsampling();
- inline wuffs_base__rect_ie_u32 bounds();
- inline uint32_t width();
- inline uint32_t height();
- inline uint64_t pixbuf_len();
+ inline bool is_valid() const;
+ inline wuffs_base__pixel_format pixel_format() const;
+ inline wuffs_base__pixel_subsampling pixel_subsampling() const;
+ inline wuffs_base__rect_ie_u32 bounds() const;
+ inline uint32_t width() const;
+ inline uint32_t height() const;
+ inline uint64_t pixbuf_len() const;
#endif // __cplusplus
} wuffs_base__pixel_config;
@@ -1889,22 +1866,22 @@
}
static inline bool //
-wuffs_base__pixel_config__is_valid(wuffs_base__pixel_config* c) {
+wuffs_base__pixel_config__is_valid(const wuffs_base__pixel_config* c) {
return c && c->private_impl.pixfmt;
}
static inline wuffs_base__pixel_format //
-wuffs_base__pixel_config__pixel_format(wuffs_base__pixel_config* c) {
+wuffs_base__pixel_config__pixel_format(const wuffs_base__pixel_config* c) {
return c ? c->private_impl.pixfmt : 0;
}
static inline wuffs_base__pixel_subsampling //
-wuffs_base__pixel_config__pixel_subsampling(wuffs_base__pixel_config* c) {
+wuffs_base__pixel_config__pixel_subsampling(const wuffs_base__pixel_config* c) {
return c ? c->private_impl.pixsub : 0;
}
static inline wuffs_base__rect_ie_u32 //
-wuffs_base__pixel_config__bounds(wuffs_base__pixel_config* c) {
+wuffs_base__pixel_config__bounds(const wuffs_base__pixel_config* c) {
if (c) {
wuffs_base__rect_ie_u32 ret;
ret.min_incl_x = 0;
@@ -1923,20 +1900,20 @@
}
static inline uint32_t //
-wuffs_base__pixel_config__width(wuffs_base__pixel_config* c) {
+wuffs_base__pixel_config__width(const wuffs_base__pixel_config* c) {
return c ? c->private_impl.width : 0;
}
static inline uint32_t //
-wuffs_base__pixel_config__height(wuffs_base__pixel_config* c) {
+wuffs_base__pixel_config__height(const wuffs_base__pixel_config* c) {
return c ? c->private_impl.height : 0;
}
-// TODO: this is the right API for planar (not packed) pixbufs? Should it allow
-// decoding into a color model different from the format's intrinsic one? For
-// example, decoding a JPEG image straight to RGBA instead of to YCbCr?
+// TODO: this is the right API for planar (not interleaved) pixbufs? Should it
+// allow decoding into a color model different from the format's intrinsic one?
+// For example, decoding a JPEG image straight to RGBA instead of to YCbCr?
static inline uint64_t //
-wuffs_base__pixel_config__pixbuf_len(wuffs_base__pixel_config* c) {
+wuffs_base__pixel_config__pixbuf_len(const wuffs_base__pixel_config* c) {
if (!c) {
return 0;
}
@@ -1985,37 +1962,37 @@
}
inline bool //
-wuffs_base__pixel_config::is_valid() {
+wuffs_base__pixel_config::is_valid() const {
return wuffs_base__pixel_config__is_valid(this);
}
inline wuffs_base__pixel_format //
-wuffs_base__pixel_config::pixel_format() {
+wuffs_base__pixel_config::pixel_format() const {
return wuffs_base__pixel_config__pixel_format(this);
}
inline wuffs_base__pixel_subsampling //
-wuffs_base__pixel_config::pixel_subsampling() {
+wuffs_base__pixel_config::pixel_subsampling() const {
return wuffs_base__pixel_config__pixel_subsampling(this);
}
inline wuffs_base__rect_ie_u32 //
-wuffs_base__pixel_config::bounds() {
+wuffs_base__pixel_config::bounds() const {
return wuffs_base__pixel_config__bounds(this);
}
inline uint32_t //
-wuffs_base__pixel_config::width() {
+wuffs_base__pixel_config::width() const {
return wuffs_base__pixel_config__width(this);
}
inline uint32_t //
-wuffs_base__pixel_config::height() {
+wuffs_base__pixel_config::height() const {
return wuffs_base__pixel_config__height(this);
}
inline uint64_t //
-wuffs_base__pixel_config::pixbuf_len() {
+wuffs_base__pixel_config::pixbuf_len() const {
return wuffs_base__pixel_config__pixbuf_len(this);
}
@@ -2041,9 +2018,9 @@
uint64_t first_frame_io_position,
bool first_frame_is_opaque);
inline void invalidate();
- inline bool is_valid();
- inline uint64_t first_frame_io_position();
- inline bool first_frame_is_opaque();
+ inline bool is_valid() const;
+ inline uint64_t first_frame_io_position() const;
+ inline bool first_frame_is_opaque() const;
#endif // __cplusplus
} wuffs_base__image_config;
@@ -2100,17 +2077,19 @@
}
static inline bool //
-wuffs_base__image_config__is_valid(wuffs_base__image_config* c) {
+wuffs_base__image_config__is_valid(const wuffs_base__image_config* c) {
return c && wuffs_base__pixel_config__is_valid(&(c->pixcfg));
}
static inline uint64_t //
-wuffs_base__image_config__first_frame_io_position(wuffs_base__image_config* c) {
+wuffs_base__image_config__first_frame_io_position(
+ const wuffs_base__image_config* c) {
return c ? c->private_impl.first_frame_io_position : 0;
}
static inline bool //
-wuffs_base__image_config__first_frame_is_opaque(wuffs_base__image_config* c) {
+wuffs_base__image_config__first_frame_is_opaque(
+ const wuffs_base__image_config* c) {
return c ? c->private_impl.first_frame_is_opaque : false;
}
@@ -2133,17 +2112,17 @@
}
inline bool //
-wuffs_base__image_config::is_valid() {
+wuffs_base__image_config::is_valid() const {
return wuffs_base__image_config__is_valid(this);
}
inline uint64_t //
-wuffs_base__image_config::first_frame_io_position() {
+wuffs_base__image_config::first_frame_io_position() const {
return wuffs_base__image_config__first_frame_io_position(this);
}
inline bool //
-wuffs_base__image_config::first_frame_is_opaque() {
+wuffs_base__image_config::first_frame_is_opaque() const {
return wuffs_base__image_config__first_frame_is_opaque(this);
}
@@ -2199,6 +2178,7 @@
uint64_t io_position;
wuffs_base__animation_blend blend;
wuffs_base__animation_disposal disposal;
+ wuffs_base__color_u32_argb_premul background_color;
} private_impl;
#ifdef __cplusplus
@@ -2207,15 +2187,17 @@
uint64_t index,
uint64_t io_position,
wuffs_base__animation_blend blend,
- wuffs_base__animation_disposal disposal);
- inline wuffs_base__rect_ie_u32 bounds();
- inline uint32_t width();
- inline uint32_t height();
- inline wuffs_base__flicks duration();
- inline uint64_t index();
- inline uint64_t io_position();
- inline wuffs_base__animation_blend blend();
- inline wuffs_base__animation_disposal disposal();
+ wuffs_base__animation_disposal disposal,
+ wuffs_base__color_u32_argb_premul background_color);
+ inline wuffs_base__rect_ie_u32 bounds() const;
+ inline uint32_t width() const;
+ inline uint32_t height() const;
+ 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 wuffs_base__color_u32_argb_premul background_color() const;
#endif // __cplusplus
} wuffs_base__frame_config;
@@ -2233,13 +2215,15 @@
}
static inline void //
-wuffs_base__frame_config__update(wuffs_base__frame_config* c,
- wuffs_base__rect_ie_u32 bounds,
- wuffs_base__flicks duration,
- uint64_t index,
- uint64_t io_position,
- wuffs_base__animation_blend blend,
- wuffs_base__animation_disposal disposal) {
+wuffs_base__frame_config__update(
+ wuffs_base__frame_config* c,
+ wuffs_base__rect_ie_u32 bounds,
+ wuffs_base__flicks duration,
+ uint64_t index,
+ uint64_t io_position,
+ wuffs_base__animation_blend blend,
+ wuffs_base__animation_disposal disposal,
+ wuffs_base__color_u32_argb_premul background_color) {
if (!c) {
return;
}
@@ -2250,10 +2234,11 @@
c->private_impl.io_position = io_position;
c->private_impl.blend = blend;
c->private_impl.disposal = disposal;
+ c->private_impl.background_color = background_color;
}
static inline wuffs_base__rect_ie_u32 //
-wuffs_base__frame_config__bounds(wuffs_base__frame_config* c) {
+wuffs_base__frame_config__bounds(const wuffs_base__frame_config* c) {
if (c) {
return c->private_impl.bounds;
}
@@ -2267,103 +2252,115 @@
}
static inline uint32_t //
-wuffs_base__frame_config__width(wuffs_base__frame_config* c) {
+wuffs_base__frame_config__width(const wuffs_base__frame_config* c) {
return c ? wuffs_base__rect_ie_u32__width(&c->private_impl.bounds) : 0;
}
static inline uint32_t //
-wuffs_base__frame_config__height(wuffs_base__frame_config* c) {
+wuffs_base__frame_config__height(const wuffs_base__frame_config* c) {
return c ? wuffs_base__rect_ie_u32__height(&c->private_impl.bounds) : 0;
}
// wuffs_base__frame_config__duration returns the amount of time to display
// this frame. Zero means to display forever - a still (non-animated) image.
static inline wuffs_base__flicks //
-wuffs_base__frame_config__duration(wuffs_base__frame_config* c) {
+wuffs_base__frame_config__duration(const wuffs_base__frame_config* c) {
return c ? c->private_impl.duration : 0;
}
// wuffs_base__frame_config__index returns the index of this frame. The first
// frame in an image has index 0, the second frame has index 1, and so on.
static inline uint64_t //
-wuffs_base__frame_config__index(wuffs_base__frame_config* c) {
+wuffs_base__frame_config__index(const wuffs_base__frame_config* c) {
return c ? c->private_impl.index : 0;
}
// wuffs_base__frame_config__io_position returns the I/O stream position before
// the frame config.
static inline uint64_t //
-wuffs_base__frame_config__io_position(wuffs_base__frame_config* c) {
+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(wuffs_base__frame_config* c) {
+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 //
-wuffs_base__frame_config__disposal(wuffs_base__frame_config* c) {
+wuffs_base__frame_config__disposal(const wuffs_base__frame_config* c) {
return c ? c->private_impl.disposal : 0;
}
+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;
+}
+
#ifdef __cplusplus
inline void //
-wuffs_base__frame_config::update(wuffs_base__rect_ie_u32 bounds,
- wuffs_base__flicks duration,
- uint64_t index,
- uint64_t io_position,
- wuffs_base__animation_blend blend,
- wuffs_base__animation_disposal disposal) {
+wuffs_base__frame_config::update(
+ wuffs_base__rect_ie_u32 bounds,
+ wuffs_base__flicks duration,
+ uint64_t index,
+ uint64_t io_position,
+ wuffs_base__animation_blend blend,
+ wuffs_base__animation_disposal disposal,
+ wuffs_base__color_u32_argb_premul background_color) {
wuffs_base__frame_config__update(this, bounds, duration, index, io_position,
- blend, disposal);
+ blend, disposal, background_color);
}
inline wuffs_base__rect_ie_u32 //
-wuffs_base__frame_config::bounds() {
+wuffs_base__frame_config::bounds() const {
return wuffs_base__frame_config__bounds(this);
}
inline uint32_t //
-wuffs_base__frame_config::width() {
+wuffs_base__frame_config::width() const {
return wuffs_base__frame_config__width(this);
}
inline uint32_t //
-wuffs_base__frame_config::height() {
+wuffs_base__frame_config::height() const {
return wuffs_base__frame_config__height(this);
}
inline wuffs_base__flicks //
-wuffs_base__frame_config::duration() {
+wuffs_base__frame_config::duration() const {
return wuffs_base__frame_config__duration(this);
}
inline uint64_t //
-wuffs_base__frame_config::index() {
+wuffs_base__frame_config::index() const {
return wuffs_base__frame_config__index(this);
}
inline uint64_t //
-wuffs_base__frame_config::io_position() {
+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() {
+wuffs_base__frame_config::blend() const {
return wuffs_base__frame_config__blend(this);
}
inline wuffs_base__animation_disposal //
-wuffs_base__frame_config::disposal() {
+wuffs_base__frame_config::disposal() const {
return wuffs_base__frame_config__disposal(this);
}
+inline wuffs_base__color_u32_argb_premul //
+wuffs_base__frame_config::background_color() const {
+ return wuffs_base__frame_config__background_color(this);
+}
+
#endif // __cplusplus
// --------
@@ -2381,8 +2378,10 @@
#ifdef __cplusplus
inline wuffs_base__status set_from_slice(wuffs_base__pixel_config* pixcfg,
wuffs_base__slice_u8 pixbuf_memory);
+ inline wuffs_base__status set_from_table(wuffs_base__pixel_config* pixcfg,
+ wuffs_base__table_u8 pixbuf_memory);
inline wuffs_base__slice_u8 palette();
- inline wuffs_base__pixel_format pixel_format();
+ inline wuffs_base__pixel_format pixel_format() const;
inline wuffs_base__table_u8 plane(uint32_t p);
#endif // __cplusplus
@@ -2412,12 +2411,13 @@
}
if (wuffs_base__pixel_format__is_planar(pixcfg->private_impl.pixfmt)) {
// TODO: support planar pixel formats, concious of pixel subsampling.
- return wuffs_base__error__bad_argument;
+ return wuffs_base__error__unsupported_option;
}
uint32_t bits_per_pixel =
wuffs_base__pixel_format__bits_per_pixel(pixcfg->private_impl.pixfmt);
if ((bits_per_pixel == 0) || ((bits_per_pixel % 8) != 0)) {
- return wuffs_base__error__bad_argument;
+ // TODO: support fraction-of-byte pixels, e.g. 1 bit per pixel?
+ return wuffs_base__error__unsupported_option;
}
uint64_t bytes_per_pixel = bits_per_pixel / 8;
@@ -2463,6 +2463,38 @@
return NULL;
}
+static inline wuffs_base__status //
+wuffs_base__pixel_buffer__set_from_table(wuffs_base__pixel_buffer* b,
+ wuffs_base__pixel_config* pixcfg,
+ wuffs_base__table_u8 pixbuf_memory) {
+ if (!b) {
+ return 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;
+ }
+ uint32_t bits_per_pixel =
+ 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;
+ }
+ uint64_t bytes_per_pixel = bits_per_pixel / 8;
+
+ uint64_t width_in_bytes =
+ ((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;
+ }
+
+ b->pixcfg = *pixcfg;
+ b->private_impl.planes[0] = pixbuf_memory;
+ return NULL;
+}
+
// wuffs_base__pixel_buffer__palette returns the palette color data. If
// non-empty, it will have length 1024.
static inline wuffs_base__slice_u8 //
@@ -2479,7 +2511,7 @@
}
static inline wuffs_base__pixel_format //
-wuffs_base__pixel_buffer__pixel_format(wuffs_base__pixel_buffer* b) {
+wuffs_base__pixel_buffer__pixel_format(const wuffs_base__pixel_buffer* b) {
if (b) {
return b->pixcfg.private_impl.pixfmt;
}
@@ -2508,13 +2540,19 @@
return wuffs_base__pixel_buffer__set_from_slice(this, pixcfg, pixbuf_memory);
}
+inline wuffs_base__status //
+wuffs_base__pixel_buffer::set_from_table(wuffs_base__pixel_config* pixcfg,
+ wuffs_base__table_u8 pixbuf_memory) {
+ return wuffs_base__pixel_buffer__set_from_table(this, pixcfg, pixbuf_memory);
+}
+
inline wuffs_base__slice_u8 //
wuffs_base__pixel_buffer::palette() {
return wuffs_base__pixel_buffer__palette(this);
}
inline wuffs_base__pixel_format //
-wuffs_base__pixel_buffer::pixel_format() {
+wuffs_base__pixel_buffer::pixel_format() const {
return wuffs_base__pixel_buffer__pixel_format(this);
}
@@ -2556,20 +2594,18 @@
} private_impl;
#ifdef __cplusplus
- inline void 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);
- inline uint64_t swizzle_packed(wuffs_base__slice_u8 dst,
- wuffs_base__slice_u8 dst_palette,
- wuffs_base__slice_u8 src);
+ 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);
+ inline uint64_t swizzle_interleaved(wuffs_base__slice_u8 dst,
+ wuffs_base__slice_u8 dst_palette,
+ wuffs_base__slice_u8 src) const;
#endif // __cplusplus
} wuffs_base__pixel_swizzler;
-// TODO: should prepare (both the C and C++ methods) return a status?
-
-void //
+wuffs_base__status //
wuffs_base__pixel_swizzler__prepare(wuffs_base__pixel_swizzler* p,
wuffs_base__pixel_format dst_format,
wuffs_base__slice_u8 dst_palette,
@@ -2577,28 +2613,30 @@
wuffs_base__slice_u8 src_palette);
uint64_t //
-wuffs_base__pixel_swizzler__swizzle_packed(wuffs_base__pixel_swizzler* p,
- wuffs_base__slice_u8 dst,
- wuffs_base__slice_u8 dst_palette,
- wuffs_base__slice_u8 src);
+wuffs_base__pixel_swizzler__swizzle_interleaved(
+ const wuffs_base__pixel_swizzler* p,
+ wuffs_base__slice_u8 dst,
+ wuffs_base__slice_u8 dst_palette,
+ wuffs_base__slice_u8 src);
#ifdef __cplusplus
-inline void //
+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__pixel_swizzler__prepare(this, dst_format, dst_palette, src_format,
- src_palette);
+ return wuffs_base__pixel_swizzler__prepare(this, dst_format, dst_palette,
+ src_format, src_palette);
}
uint64_t //
-wuffs_base__pixel_swizzler::swizzle_packed(wuffs_base__slice_u8 dst,
- wuffs_base__slice_u8 dst_palette,
- wuffs_base__slice_u8 src) {
- return wuffs_base__pixel_swizzler__swizzle_packed(this, dst, dst_palette,
- src);
+wuffs_base__pixel_swizzler::swizzle_interleaved(
+ wuffs_base__slice_u8 dst,
+ wuffs_base__slice_u8 dst_palette,
+ wuffs_base__slice_u8 src) const {
+ return wuffs_base__pixel_swizzler__swizzle_interleaved(this, dst, dst_palette,
+ src);
}
#endif // __cplusplus
@@ -2901,8 +2939,8 @@
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
wuffs_deflate__decoder__decode_io_writer(wuffs_deflate__decoder* self,
- wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src,
+ wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf);
// ---------------- Struct Definitions
@@ -3020,8 +3058,8 @@
}
inline wuffs_base__status //
- decode_io_writer(wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src,
+ decode_io_writer(wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf) {
return wuffs_deflate__decoder__decode_io_writer(this, a_dst, a_src,
a_workbuf);
@@ -3092,8 +3130,8 @@
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
wuffs_lzw__decoder__decode_io_writer(wuffs_lzw__decoder* self,
- wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src,
+ wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf);
WUFFS_BASE__MAYBE_STATIC wuffs_base__slice_u8 //
@@ -3190,8 +3228,8 @@
}
inline wuffs_base__status //
- decode_io_writer(wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src,
+ decode_io_writer(wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf) {
return wuffs_lzw__decoder__decode_io_writer(this, a_dst, a_src, a_workbuf);
}
@@ -3226,9 +3264,11 @@
extern const char* wuffs_gif__error__bad_block;
extern const char* wuffs_gif__error__bad_extension_label;
+extern const char* wuffs_gif__error__bad_frame_size;
extern const char* wuffs_gif__error__bad_graphic_control;
extern const char* wuffs_gif__error__bad_header;
extern const char* wuffs_gif__error__bad_literal_width;
+extern const char* wuffs_gif__error__bad_palette;
// ---------------- Public Consts
@@ -3238,6 +3278,49 @@
wuffs_gif__decoder_workbuf_len_max_incl_worst_case //
WUFFS_BASE__POTENTIALLY_UNUSED = 1;
+#define WUFFS_GIF__QUIRK_DELAY_NUM_DECODED_FRAMES 1041635328
+
+static const uint32_t //
+ wuffs_gif__quirk_delay_num_decoded_frames //
+ WUFFS_BASE__POTENTIALLY_UNUSED = 1041635328;
+
+#define WUFFS_GIF__QUIRK_FIRST_FRAME_LOCAL_PALETTE_MEANS_BLACK_BACKGROUND \
+ 1041635329
+
+static const uint32_t //
+ wuffs_gif__quirk_first_frame_local_palette_means_black_background //
+ WUFFS_BASE__POTENTIALLY_UNUSED = 1041635329;
+
+#define WUFFS_GIF__QUIRK_HONOR_BACKGROUND_COLOR 1041635330
+
+static const uint32_t //
+ wuffs_gif__quirk_honor_background_color //
+ WUFFS_BASE__POTENTIALLY_UNUSED = 1041635330;
+
+#define WUFFS_GIF__QUIRK_IGNORE_TOO_MUCH_PIXEL_DATA 1041635331
+
+static const uint32_t //
+ wuffs_gif__quirk_ignore_too_much_pixel_data //
+ WUFFS_BASE__POTENTIALLY_UNUSED = 1041635331;
+
+#define WUFFS_GIF__QUIRK_IMAGE_BOUNDS_ARE_STRICT 1041635332
+
+static const uint32_t //
+ wuffs_gif__quirk_image_bounds_are_strict //
+ WUFFS_BASE__POTENTIALLY_UNUSED = 1041635332;
+
+#define WUFFS_GIF__QUIRK_REJECT_EMPTY_FRAME 1041635333
+
+static const uint32_t //
+ wuffs_gif__quirk_reject_empty_frame //
+ WUFFS_BASE__POTENTIALLY_UNUSED = 1041635333;
+
+#define WUFFS_GIF__QUIRK_REJECT_EMPTY_PALETTE 1041635334
+
+static const uint32_t //
+ wuffs_gif__quirk_reject_empty_palette //
+ WUFFS_BASE__POTENTIALLY_UNUSED = 1041635334;
+
// ---------------- Struct Declarations
typedef struct wuffs_gif__decoder__struct wuffs_gif__decoder;
@@ -3261,10 +3344,30 @@
// ---------------- Public Function Prototypes
+WUFFS_BASE__MAYBE_STATIC wuffs_base__empty_struct //
+wuffs_gif__decoder__set_quirk_enabled(wuffs_gif__decoder* self,
+ uint32_t a_quirk,
+ bool a_enabled);
+
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
wuffs_gif__decoder__decode_image_config(wuffs_gif__decoder* self,
wuffs_base__image_config* a_dst,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_src);
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__empty_struct //
+wuffs_gif__decoder__set_report_metadata(wuffs_gif__decoder* self,
+ uint32_t a_fourcc,
+ bool a_report);
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
+wuffs_gif__decoder__ack_metadata_chunk(wuffs_gif__decoder* self,
+ wuffs_base__io_buffer* a_src);
+
+WUFFS_BASE__MAYBE_STATIC uint32_t //
+wuffs_gif__decoder__metadata_fourcc(const wuffs_gif__decoder* self);
+
+WUFFS_BASE__MAYBE_STATIC uint64_t //
+wuffs_gif__decoder__metadata_chunk_length(const wuffs_gif__decoder* self);
WUFFS_BASE__MAYBE_STATIC uint32_t //
wuffs_gif__decoder__num_animation_loops(const wuffs_gif__decoder* self);
@@ -3289,12 +3392,12 @@
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
wuffs_gif__decoder__decode_frame_config(wuffs_gif__decoder* self,
wuffs_base__frame_config* a_dst,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_src);
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
wuffs_gif__decoder__decode_frame(wuffs_gif__decoder* self,
wuffs_base__pixel_buffer* a_dst,
- wuffs_base__io_reader a_src,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf,
wuffs_base__decode_frame_options* a_opts);
@@ -3324,14 +3427,29 @@
uint32_t f_width;
uint32_t f_height;
uint8_t f_call_sequence;
+ bool f_ignore_metadata;
+ bool f_report_metadata_iccp;
+ bool f_report_metadata_xmp;
+ uint32_t f_metadata_fourcc_value;
+ uint64_t f_metadata_chunk_length_value;
+ uint64_t f_metadata_io_position;
+ bool f_quirk_enabled_delay_num_decoded_frames;
+ bool f_quirk_enabled_first_frame_local_palette_means_black_background;
+ bool f_quirk_enabled_honor_background_color;
+ bool f_quirk_enabled_ignore_too_much_pixel_data;
+ bool f_quirk_enabled_image_bounds_are_strict;
+ bool f_quirk_enabled_reject_empty_frame;
+ bool f_quirk_enabled_reject_empty_palette;
+ bool f_delayed_num_decoded_frames;
bool f_end_of_data;
bool f_restarted;
bool f_previous_lzw_decode_ended_abruptly;
- uint8_t f_which_palette;
+ bool f_has_global_palette;
uint8_t f_interlace;
bool f_seen_num_loops;
uint32_t f_num_loops;
- bool f_seen_graphic_control;
+ uint32_t f_background_color_u32_argb_premul;
+ uint32_t f_black_color_u32_argb_premul;
bool f_gc_has_transparent_index;
uint8_t f_gc_transparent_index;
uint8_t f_gc_disposal;
@@ -3351,6 +3469,7 @@
wuffs_base__pixel_swizzler f_swizzler;
uint32_t p_decode_image_config[1];
+ uint32_t p_ack_metadata_chunk[1];
uint32_t p_decode_frame_config[1];
uint32_t p_skip_frame[1];
uint32_t p_decode_frame[1];
@@ -3373,6 +3492,10 @@
wuffs_lzw__decoder f_lzw;
struct {
+ uint8_t v_blend;
+ uint32_t v_background_color;
+ } s_decode_frame_config[1];
+ struct {
uint64_t scratch;
} s_skip_frame[1];
struct {
@@ -3381,6 +3504,7 @@
} s_decode_header[1];
struct {
uint8_t v_flags;
+ uint8_t v_background_color_index;
uint32_t v_num_palette_entries;
uint32_t v_i;
uint64_t scratch;
@@ -3390,8 +3514,10 @@
} s_skip_blocks[1];
struct {
uint8_t v_block_size;
- bool v_not_animexts;
- bool v_not_netscape;
+ bool v_is_animexts;
+ bool v_is_netscape;
+ bool v_is_iccp;
+ bool v_is_xmp;
uint64_t scratch;
} s_decode_ae[1];
struct {
@@ -3401,6 +3527,7 @@
uint64_t scratch;
} s_decode_id_part0[1];
struct {
+ uint8_t v_which_palette;
uint32_t v_num_palette_entries;
uint32_t v_i;
uint64_t scratch;
@@ -3445,12 +3572,37 @@
initialize_flags);
}
+ inline wuffs_base__empty_struct //
+ set_quirk_enabled(uint32_t a_quirk, bool a_enabled) {
+ return wuffs_gif__decoder__set_quirk_enabled(this, a_quirk, a_enabled);
+ }
+
inline wuffs_base__status //
decode_image_config(wuffs_base__image_config* a_dst,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_src) {
return wuffs_gif__decoder__decode_image_config(this, a_dst, a_src);
}
+ inline wuffs_base__empty_struct //
+ set_report_metadata(uint32_t a_fourcc, bool a_report) {
+ return wuffs_gif__decoder__set_report_metadata(this, a_fourcc, a_report);
+ }
+
+ inline wuffs_base__status //
+ ack_metadata_chunk(wuffs_base__io_buffer* a_src) {
+ return wuffs_gif__decoder__ack_metadata_chunk(this, a_src);
+ }
+
+ inline uint32_t //
+ metadata_fourcc() const {
+ return wuffs_gif__decoder__metadata_fourcc(this);
+ }
+
+ inline uint64_t //
+ metadata_chunk_length() const {
+ return wuffs_gif__decoder__metadata_chunk_length(this);
+ }
+
inline uint32_t //
num_animation_loops() const {
return wuffs_gif__decoder__num_animation_loops(this);
@@ -3483,13 +3635,13 @@
inline wuffs_base__status //
decode_frame_config(wuffs_base__frame_config* a_dst,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_src) {
return wuffs_gif__decoder__decode_frame_config(this, a_dst, a_src);
}
inline wuffs_base__status //
decode_frame(wuffs_base__pixel_buffer* a_dst,
- wuffs_base__io_reader a_src,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf,
wuffs_base__decode_frame_options* a_opts) {
return wuffs_gif__decoder__decode_frame(this, a_dst, a_src, a_workbuf,
@@ -3563,8 +3715,8 @@
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
wuffs_gzip__decoder__decode_io_writer(wuffs_gzip__decoder* self,
- wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src,
+ wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf);
// ---------------- Struct Definitions
@@ -3651,8 +3803,8 @@
}
inline wuffs_base__status //
- decode_io_writer(wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src,
+ decode_io_writer(wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf) {
return wuffs_gzip__decoder__decode_io_writer(this, a_dst, a_src, a_workbuf);
}
@@ -3724,8 +3876,8 @@
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
wuffs_zlib__decoder__decode_io_writer(wuffs_zlib__decoder* self,
- wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src,
+ wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf);
// ---------------- Struct Definitions
@@ -3809,8 +3961,8 @@
}
inline wuffs_base__status //
- decode_io_writer(wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src,
+ decode_io_writer(wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf) {
return wuffs_zlib__decoder__decode_io_writer(this, a_dst, a_src, a_workbuf);
}
@@ -4305,65 +4457,52 @@
// ---------------- I/O
-static inline bool //
-wuffs_base__io_buffer__is_valid(wuffs_base__io_buffer buf) {
- return (buf.data.ptr || (buf.data.len == 0)) &&
- (buf.data.len >= buf.meta.wi) && (buf.meta.wi >= buf.meta.ri);
-}
-
-// TODO: wuffs_base__io_reader__is_eof is no longer used by Wuffs per se, but
-// it might be handy to programs that use Wuffs. Either delete it, or promote
-// it to the public API.
+// "Null" as in "/dev/null", not as in "nullptr".
//
-// If making this function public (i.e. moving it to base-header.h), it also
-// needs to allow NULL (i.e. implicit, callee-calculated) mark/limit.
+// TODO: ensure that this is zero-initialized.
+static wuffs_base__io_buffer wuffs_base__global__null_io_buffer;
-static inline bool //
-wuffs_base__io_reader__is_eof(wuffs_base__io_reader o) {
- wuffs_base__io_buffer* buf = o.private_impl.buf;
- return buf && buf->meta.closed &&
- (buf->data.ptr + buf->meta.wi == o.private_impl.limit);
+static inline wuffs_base__io_buffer* //
+wuffs_base__null_io_reader() {
+ return &wuffs_base__global__null_io_buffer;
}
-static inline bool //
-wuffs_base__io_reader__is_valid(wuffs_base__io_reader o) {
- wuffs_base__io_buffer* buf = o.private_impl.buf;
- // Note: if making this function public (i.e. moving it to base-header.h), it
- // also needs to allow NULL (i.e. implicit, callee-calculated) mark/limit.
- return buf ? ((buf->data.ptr <= o.private_impl.mark) &&
- (o.private_impl.mark <= o.private_impl.limit) &&
- (o.private_impl.limit <= buf->data.ptr + buf->data.len))
- : ((o.private_impl.mark == NULL) &&
- (o.private_impl.limit == NULL));
+static inline wuffs_base__io_buffer* //
+wuffs_base__null_io_writer() {
+ return &wuffs_base__global__null_io_buffer;
}
-static inline bool //
-wuffs_base__io_writer__is_valid(wuffs_base__io_writer o) {
- wuffs_base__io_buffer* buf = o.private_impl.buf;
- // Note: if making this function public (i.e. moving it to base-header.h), it
- // also needs to allow NULL (i.e. implicit, callee-calculated) mark/limit.
- return buf ? ((buf->data.ptr <= o.private_impl.mark) &&
- (o.private_impl.mark <= o.private_impl.limit) &&
- (o.private_impl.limit <= buf->data.ptr + buf->data.len))
- : ((o.private_impl.mark == NULL) &&
- (o.private_impl.limit == NULL));
+static inline uint64_t //
+wuffs_base__io__count_since(uint64_t mark, uint64_t index) {
+ if (index >= mark) {
+ return index - mark;
+ }
+ return 0;
+}
+
+static inline wuffs_base__slice_u8 //
+wuffs_base__io__since(uint64_t mark, uint64_t index, uint8_t* ptr) {
+ if (index >= mark) {
+ return wuffs_base__make_slice_u8(ptr + mark, index - mark);
+ }
+ return wuffs_base__make_slice_u8(NULL, 0);
}
static inline uint32_t //
wuffs_base__io_writer__copy_n_from_history(uint8_t** ptr_iop_w,
- uint8_t* io0_w,
uint8_t* io1_w,
+ uint8_t* io2_w,
uint32_t length,
uint32_t distance) {
if (!distance) {
return 0;
}
uint8_t* p = *ptr_iop_w;
- if ((size_t)(p - io0_w) < (size_t)(distance)) {
+ if ((size_t)(p - io1_w) < (size_t)(distance)) {
return 0;
}
uint8_t* q = p - distance;
- size_t n = (size_t)(io1_w - p);
+ size_t n = (size_t)(io2_w - p);
if ((size_t)(length) > n) {
length = (uint32_t)(n);
} else {
@@ -4395,12 +4534,12 @@
// wuffs_base__io_writer__copy_n_from_history function above, but has stronger
// pre-conditions. The caller needs to prove that:
// - distance > 0
-// - distance <= (*ptr_iop_w - io0_w)
-// - length <= (io1_w - *ptr_iop_w)
+// - 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* io0_w,
uint8_t* io1_w,
+ uint8_t* io2_w,
uint32_t length,
uint32_t distance) {
uint8_t* p = *ptr_iop_w;
@@ -4420,18 +4559,18 @@
static inline uint32_t //
wuffs_base__io_writer__copy_n_from_reader(uint8_t** ptr_iop_w,
- uint8_t* io1_w,
+ uint8_t* io2_w,
uint32_t length,
uint8_t** ptr_iop_r,
- uint8_t* io1_r) {
+ uint8_t* io2_r) {
uint8_t* iop_w = *ptr_iop_w;
size_t n = length;
- if (n > ((size_t)(io1_w - iop_w))) {
- n = (size_t)(io1_w - iop_w);
+ if (n > ((size_t)(io2_w - iop_w))) {
+ n = (size_t)(io2_w - iop_w);
}
uint8_t* iop_r = *ptr_iop_r;
- if (n > ((size_t)(io1_r - iop_r))) {
- n = (size_t)(io1_r - iop_r);
+ if (n > ((size_t)(io2_r - iop_r))) {
+ n = (size_t)(io2_r - iop_r);
}
if (n > 0) {
memmove(iop_w, iop_r, n);
@@ -4443,12 +4582,12 @@
static inline uint64_t //
wuffs_base__io_writer__copy_from_slice(uint8_t** ptr_iop_w,
- uint8_t* io1_w,
+ uint8_t* io2_w,
wuffs_base__slice_u8 src) {
uint8_t* iop_w = *ptr_iop_w;
size_t n = src.len;
- if (n > ((size_t)(io1_w - iop_w))) {
- n = (size_t)(io1_w - iop_w);
+ if (n > ((size_t)(io2_w - iop_w))) {
+ n = (size_t)(io2_w - iop_w);
}
if (n > 0) {
memmove(iop_w, src.ptr, n);
@@ -4459,7 +4598,7 @@
static inline uint32_t //
wuffs_base__io_writer__copy_n_from_slice(uint8_t** ptr_iop_w,
- uint8_t* io1_w,
+ uint8_t* io2_w,
uint32_t length,
wuffs_base__slice_u8 src) {
uint8_t* iop_w = *ptr_iop_w;
@@ -4467,8 +4606,8 @@
if (n > length) {
n = length;
}
- if (n > ((size_t)(io1_w - iop_w))) {
- n = (size_t)(io1_w - iop_w);
+ if (n > ((size_t)(io2_w - iop_w))) {
+ n = (size_t)(io2_w - iop_w);
}
if (n > 0) {
memmove(iop_w, src.ptr, n);
@@ -4477,11 +4616,12 @@
return (uint32_t)(n);
}
-static inline wuffs_base__empty_struct //
-wuffs_base__io_reader__set(wuffs_base__io_reader* o,
- wuffs_base__io_buffer* b,
+static inline wuffs_base__io_buffer* //
+wuffs_base__io_reader__set(wuffs_base__io_buffer* b,
uint8_t** ptr_iop_r,
+ uint8_t** ptr_io0_r,
uint8_t** ptr_io1_r,
+ uint8_t** ptr_io2_r,
wuffs_base__slice_u8 data) {
b->data = data;
b->meta.wi = data.len;
@@ -4489,42 +4629,17 @@
b->meta.pos = 0;
b->meta.closed = false;
- o->private_impl.buf = b;
- o->private_impl.mark = data.ptr;
- o->private_impl.limit = data.ptr + data.len;
*ptr_iop_r = data.ptr;
- *ptr_io1_r = data.ptr + data.len;
+ *ptr_io0_r = data.ptr;
+ *ptr_io1_r = data.ptr;
+ *ptr_io2_r = data.ptr + data.len;
- wuffs_base__empty_struct ret;
- ret.private_impl = 0;
- return ret;
-}
-
-static inline wuffs_base__empty_struct //
-wuffs_base__io_reader__set_limit(wuffs_base__io_reader* o,
- uint8_t* iop_r,
- uint64_t limit) {
- if (o && (((size_t)(o->private_impl.limit - iop_r)) > limit)) {
- o->private_impl.limit = iop_r + limit;
- }
-
- wuffs_base__empty_struct ret;
- ret.private_impl = 0;
- return ret;
-}
-
-static inline wuffs_base__empty_struct //
-wuffs_base__io_reader__set_mark(wuffs_base__io_reader* o, uint8_t* mark) {
- o->private_impl.mark = mark;
-
- wuffs_base__empty_struct ret;
- ret.private_impl = 0;
- return ret;
+ return b;
}
static inline wuffs_base__slice_u8 //
-wuffs_base__io_reader__take(uint8_t** ptr_iop_r, uint8_t* io1_r, uint64_t n) {
- if (n <= ((size_t)(io1_r - *ptr_iop_r))) {
+wuffs_base__io_reader__take(uint8_t** ptr_iop_r, uint8_t* io2_r, uint64_t n) {
+ if (n <= ((size_t)(io2_r - *ptr_iop_r))) {
uint8_t* p = *ptr_iop_r;
*ptr_iop_r += n;
return wuffs_base__make_slice_u8(p, n);
@@ -4532,11 +4647,12 @@
return wuffs_base__make_slice_u8(NULL, 0);
}
-static inline wuffs_base__empty_struct //
-wuffs_base__io_writer__set(wuffs_base__io_writer* o,
- wuffs_base__io_buffer* b,
+static inline wuffs_base__io_buffer* //
+wuffs_base__io_writer__set(wuffs_base__io_buffer* b,
uint8_t** ptr_iop_w,
+ uint8_t** ptr_io0_w,
uint8_t** ptr_io1_w,
+ uint8_t** ptr_io2_w,
wuffs_base__slice_u8 data) {
b->data = data;
b->meta.wi = 0;
@@ -4544,24 +4660,12 @@
b->meta.pos = 0;
b->meta.closed = false;
- o->private_impl.buf = b;
- o->private_impl.mark = data.ptr;
- o->private_impl.limit = data.ptr + data.len;
*ptr_iop_w = data.ptr;
- *ptr_io1_w = data.ptr + data.len;
+ *ptr_io0_w = data.ptr;
+ *ptr_io1_w = data.ptr;
+ *ptr_io2_w = data.ptr + data.len;
- wuffs_base__empty_struct ret;
- ret.private_impl = 0;
- return ret;
-}
-
-static inline wuffs_base__empty_struct //
-wuffs_base__io_writer__set_mark(wuffs_base__io_writer* o, uint8_t* mark) {
- o->private_impl.mark = mark;
-
- wuffs_base__empty_struct ret;
- ret.private_impl = 0;
- return ret;
+ return b;
}
// ---------------- I/O (Utility)
@@ -4619,8 +4723,10 @@
};
const char* wuffs_base__warning__end_of_data = "@base: end of data";
+const char* wuffs_base__warning__metadata_reported = "@base: metadata reported";
const char* wuffs_base__suspension__short_read = "$base: short read";
const char* wuffs_base__suspension__short_write = "$base: short write";
+const char* wuffs_base__error__bad_i_o_position = "#base: bad I/O position";
const char* wuffs_base__error__bad_argument_length_too_short =
"#base: bad argument (length too short)";
const char* wuffs_base__error__bad_argument = "#base: bad argument";
@@ -4642,6 +4748,7 @@
const char* wuffs_base__error__interleaved_coroutine_calls =
"#base: interleaved coroutine calls";
const char* wuffs_base__error__not_enough_data = "#base: not enough data";
+const char* wuffs_base__error__unsupported_option = "#base: unsupported option";
const char* wuffs_base__error__too_much_data = "#base: too much data";
// ---------------- Images
@@ -4659,6 +4766,61 @@
}
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) {
+ if (dst_palette.len != 1024) {
+ return 0;
+ }
+ size_t dst_len3 = dst.len / 3;
+ size_t len = dst_len3 < src.len ? dst_len3 : src.len;
+ uint8_t* d = dst.ptr;
+ uint8_t* s = src.ptr;
+ size_t n = len;
+
+ // N is the loop unroll count.
+ const int N = 4;
+
+ // The comparison in the while condition is ">", not ">=", because with ">=",
+ // the last 4-byte store could write past the end of the dst slice.
+ //
+ // Each 4-byte store writes one too many bytes, but a subsequent store will
+ // overwrite that with the correct byte. There is always another store,
+ // whether a 4-byte store in this loop or a 1-byte store in the next loop.
+ while (n > N) {
+ wuffs_base__store_u32le(
+ d + (0 * 3),
+ wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[0]) * 4)));
+ wuffs_base__store_u32le(
+ d + (1 * 3),
+ wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[1]) * 4)));
+ wuffs_base__store_u32le(
+ d + (2 * 3),
+ wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[2]) * 4)));
+ wuffs_base__store_u32le(
+ d + (3 * 3),
+ wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[3]) * 4)));
+
+ s += 1 * N;
+ d += 3 * N;
+ n -= (size_t)(1 * N);
+ }
+
+ while (n >= 1) {
+ uint32_t color =
+ wuffs_base__load_u32le(dst_palette.ptr + ((uint32_t)(s[0]) * 4));
+ d[0] = (uint8_t)(color >> 0);
+ d[1] = (uint8_t)(color >> 8);
+ d[2] = (uint8_t)(color >> 16);
+
+ s += 1 * 1;
+ d += 3 * 1;
+ n -= (size_t)(1 * 1);
+ }
+
+ 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) {
@@ -4669,8 +4831,9 @@
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;
+
+ // N is the loop unroll count.
const int N = 4;
while (n >= N) {
@@ -4728,14 +4891,14 @@
return len4 * 4;
}
-void //
+wuffs_base__status //
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) {
if (!p) {
- return;
+ return wuffs_base__error__bad_receiver;
}
// TODO: support many more formats.
@@ -4755,6 +4918,13 @@
}
func = wuffs_base__pixel_swizzler__copy_1_1;
break;
+ case WUFFS_BASE__PIXEL_FORMAT__BGR:
+ if (wuffs_base__slice_u8__copy_from_slice(dst_palette, src_palette) !=
+ 1024) {
+ break;
+ }
+ func = wuffs_base__pixel_swizzler__copy_3_1;
+ break;
case WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL:
case WUFFS_BASE__PIXEL_FORMAT__BGRA_PREMUL:
case WUFFS_BASE__PIXEL_FORMAT__BGRA_BINARY:
@@ -4764,6 +4934,13 @@
}
func = wuffs_base__pixel_swizzler__copy_4_1;
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;
+ break;
case WUFFS_BASE__PIXEL_FORMAT__RGBA_NONPREMUL:
case WUFFS_BASE__PIXEL_FORMAT__RGBA_PREMUL:
case WUFFS_BASE__PIXEL_FORMAT__RGBA_BINARY:
@@ -4783,13 +4960,15 @@
}
p->private_impl.func = func;
+ return func ? NULL : wuffs_base__error__unsupported_option;
}
uint64_t //
-wuffs_base__pixel_swizzler__swizzle_packed(wuffs_base__pixel_swizzler* p,
- wuffs_base__slice_u8 dst,
- wuffs_base__slice_u8 dst_palette,
- wuffs_base__slice_u8 src) {
+wuffs_base__pixel_swizzler__swizzle_interleaved(
+ const wuffs_base__pixel_swizzler* p,
+ wuffs_base__slice_u8 dst,
+ wuffs_base__slice_u8 dst_palette,
+ wuffs_base__slice_u8 src) {
if (p && p->private_impl.func) {
return (*(p->private_impl.func))(dst, dst_palette, src);
}
@@ -6092,20 +6271,20 @@
static wuffs_base__status //
wuffs_deflate__decoder__decode_blocks(wuffs_deflate__decoder* self,
- wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src);
static wuffs_base__status //
wuffs_deflate__decoder__decode_uncompressed(wuffs_deflate__decoder* self,
- wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src);
static wuffs_base__status //
wuffs_deflate__decoder__init_fixed_huffman(wuffs_deflate__decoder* self);
static wuffs_base__status //
wuffs_deflate__decoder__init_dynamic_huffman(wuffs_deflate__decoder* self,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_src);
static wuffs_base__status //
wuffs_deflate__decoder__init_huff(wuffs_deflate__decoder* self,
@@ -6116,13 +6295,13 @@
static wuffs_base__status //
wuffs_deflate__decoder__decode_huffman_fast(wuffs_deflate__decoder* self,
- wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src);
static wuffs_base__status //
wuffs_deflate__decoder__decode_huffman_slow(wuffs_deflate__decoder* self,
- wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src);
// ---------------- Initializer Implementations
@@ -6197,8 +6376,8 @@
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
wuffs_deflate__decoder__decode_io_writer(wuffs_deflate__decoder* self,
- wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src,
+ wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf) {
if (!self) {
return wuffs_base__error__bad_receiver;
@@ -6208,6 +6387,10 @@
? wuffs_base__error__disabled_by_previous_error
: wuffs_base__error__initialize_not_called;
}
+ if (!a_dst || !a_src) {
+ self->private_impl.magic = WUFFS_BASE__DISABLED;
+ return wuffs_base__error__bad_argument;
+ }
if ((self->private_impl.active_coroutine != 0) &&
(self->private_impl.active_coroutine != 1)) {
self->private_impl.magic = WUFFS_BASE__DISABLED;
@@ -6216,6 +6399,7 @@
self->private_impl.active_coroutine = 0;
wuffs_base__status status = NULL;
+ uint64_t v_mark = 0;
wuffs_base__status v_status = NULL;
wuffs_base__slice_u8 v_written = {0};
uint64_t v_n_copied = 0;
@@ -6224,19 +6408,15 @@
uint8_t* iop_a_dst = NULL;
uint8_t* io0_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_dst.private_impl.buf) {
- iop_a_dst =
- a_dst.private_impl.buf->data.ptr + a_dst.private_impl.buf->meta.wi;
- if (!a_dst.private_impl.mark) {
- a_dst.private_impl.mark = iop_a_dst;
- a_dst.private_impl.limit =
- a_dst.private_impl.buf->data.ptr + a_dst.private_impl.buf->data.len;
+ uint8_t* io2_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_dst) {
+ io0_a_dst = a_dst->data.ptr;
+ io1_a_dst = io0_a_dst + a_dst->meta.wi;
+ iop_a_dst = io1_a_dst;
+ io2_a_dst = io0_a_dst + a_dst->data.len;
+ if (a_dst->meta.closed) {
+ io2_a_dst = iop_a_dst;
}
- if (a_dst.private_impl.buf->meta.closed) {
- a_dst.private_impl.limit = iop_a_dst;
- }
- io0_a_dst = a_dst.private_impl.mark;
- io1_a_dst = a_dst.private_impl.limit;
}
uint32_t coro_susp_point = self->private_impl.p_decode_io_writer[0];
@@ -6246,17 +6426,15 @@
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
while (true) {
- wuffs_base__io_writer__set_mark(&a_dst, iop_a_dst);
+ v_mark = ((uint64_t)(iop_a_dst - io0_a_dst));
{
- if (a_dst.private_impl.buf) {
- a_dst.private_impl.buf->meta.wi =
- ((size_t)(iop_a_dst - a_dst.private_impl.buf->data.ptr));
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
}
wuffs_base__status t_0 =
wuffs_deflate__decoder__decode_blocks(self, a_dst, a_src);
- if (a_dst.private_impl.buf) {
- iop_a_dst = a_dst.private_impl.buf->data.ptr +
- a_dst.private_impl.buf->meta.wi;
+ if (a_dst) {
+ iop_a_dst = a_dst->data.ptr + a_dst->meta.wi;
}
v_status = t_0;
}
@@ -6270,9 +6448,8 @@
}
goto ok;
}
- v_written = wuffs_base__make_slice_u8(
- a_dst.private_impl.mark,
- (size_t)(iop_a_dst - a_dst.private_impl.mark));
+ v_written = wuffs_base__io__since(
+ v_mark, ((uint64_t)(iop_a_dst - io0_a_dst)), io0_a_dst);
if (((uint64_t)(v_written.len)) >= 32768) {
v_written = wuffs_base__slice_u8__suffix(v_written, 32768);
wuffs_base__slice_u8__copy_from_slice(
@@ -6314,14 +6491,15 @@
goto suspend;
suspend:
- self->private_impl.p_decode_io_writer[0] = coro_susp_point;
- self->private_impl.active_coroutine = 1;
+ self->private_impl.p_decode_io_writer[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
+ self->private_impl.active_coroutine =
+ wuffs_base__status__is_suspension(status) ? 1 : 0;
goto exit;
exit:
- if (a_dst.private_impl.buf) {
- a_dst.private_impl.buf->meta.wi =
- ((size_t)(iop_a_dst - a_dst.private_impl.buf->data.ptr));
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
}
if (wuffs_base__status__is_error(status)) {
@@ -6334,8 +6512,8 @@
static wuffs_base__status //
wuffs_deflate__decoder__decode_blocks(wuffs_deflate__decoder* self,
- wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src) {
wuffs_base__status status = NULL;
uint32_t v_final = 0;
@@ -6346,16 +6524,12 @@
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_decode_blocks[0];
@@ -6370,7 +6544,7 @@
while (self->private_impl.f_n_bits < 3) {
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -6385,16 +6559,14 @@
self->private_impl.f_bits >>= 3;
self->private_impl.f_n_bits -= 3;
if (v_type == 0) {
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
status =
wuffs_deflate__decoder__decode_uncompressed(self, a_dst, a_src);
- if (a_src.private_impl.buf) {
- iop_a_src = a_src.private_impl.buf->data.ptr +
- a_src.private_impl.buf->meta.ri;
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
}
if (status) {
goto suspend;
@@ -6413,15 +6585,13 @@
goto ok;
}
} else if (v_type == 2) {
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
status = wuffs_deflate__decoder__init_dynamic_huffman(self, a_src);
- if (a_src.private_impl.buf) {
- iop_a_src = a_src.private_impl.buf->data.ptr +
- a_src.private_impl.buf->meta.ri;
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
}
if (status) {
goto suspend;
@@ -6432,15 +6602,13 @@
}
self->private_impl.f_end_of_block = false;
while (true) {
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
v_status =
wuffs_deflate__decoder__decode_huffman_fast(self, a_dst, a_src);
- if (a_src.private_impl.buf) {
- iop_a_src = a_src.private_impl.buf->data.ptr +
- a_src.private_impl.buf->meta.ri;
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
}
if (wuffs_base__status__is_error(v_status)) {
status = v_status;
@@ -6449,16 +6617,14 @@
if (self->private_impl.f_end_of_block) {
goto label_0_continue;
}
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
status =
wuffs_deflate__decoder__decode_huffman_slow(self, a_dst, a_src);
- if (a_src.private_impl.buf) {
- iop_a_src = a_src.private_impl.buf->data.ptr +
- a_src.private_impl.buf->meta.ri;
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
}
if (status) {
goto suspend;
@@ -6477,14 +6643,14 @@
goto suspend;
suspend:
- self->private_impl.p_decode_blocks[0] = coro_susp_point;
+ self->private_impl.p_decode_blocks[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
self->private_data.s_decode_blocks[0].v_final = v_final;
goto exit;
exit:
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return status;
@@ -6494,8 +6660,8 @@
static wuffs_base__status //
wuffs_deflate__decoder__decode_uncompressed(wuffs_deflate__decoder* self,
- wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src) {
wuffs_base__status status = NULL;
uint32_t v_length = 0;
@@ -6504,33 +6670,25 @@
uint8_t* iop_a_dst = NULL;
uint8_t* io0_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_dst.private_impl.buf) {
- iop_a_dst =
- a_dst.private_impl.buf->data.ptr + a_dst.private_impl.buf->meta.wi;
- if (!a_dst.private_impl.mark) {
- a_dst.private_impl.mark = iop_a_dst;
- a_dst.private_impl.limit =
- a_dst.private_impl.buf->data.ptr + a_dst.private_impl.buf->data.len;
+ uint8_t* io2_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_dst) {
+ io0_a_dst = a_dst->data.ptr;
+ io1_a_dst = io0_a_dst + a_dst->meta.wi;
+ iop_a_dst = io1_a_dst;
+ io2_a_dst = io0_a_dst + a_dst->data.len;
+ if (a_dst->meta.closed) {
+ io2_a_dst = iop_a_dst;
}
- if (a_dst.private_impl.buf->meta.closed) {
- a_dst.private_impl.limit = iop_a_dst;
- }
- io0_a_dst = a_dst.private_impl.mark;
- io1_a_dst = a_dst.private_impl.limit;
}
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_decode_uncompressed[0];
@@ -6551,14 +6709,14 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
uint32_t t_0;
- if (WUFFS_BASE__LIKELY(io1_a_src - iop_a_src >= 4)) {
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 4)) {
t_0 = wuffs_base__load_u32le(iop_a_src);
iop_a_src += 4;
} else {
self->private_data.s_decode_uncompressed[0].scratch = 0;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -6585,13 +6743,13 @@
v_length = ((v_length)&0xFFFF);
while (true) {
v_n_copied = wuffs_base__io_writer__copy_n_from_reader(
- &iop_a_dst, io1_a_dst, v_length, &iop_a_src, io1_a_src);
+ &iop_a_dst, io2_a_dst, v_length, &iop_a_src, io2_a_src);
if (v_length <= v_n_copied) {
status = NULL;
goto ok;
}
v_length -= v_n_copied;
- if (((uint64_t)(io1_a_dst - iop_a_dst)) == 0) {
+ if (((uint64_t)(io2_a_dst - iop_a_dst)) == 0) {
status = wuffs_base__suspension__short_write;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(3);
} else {
@@ -6608,18 +6766,17 @@
goto suspend;
suspend:
- self->private_impl.p_decode_uncompressed[0] = coro_susp_point;
+ self->private_impl.p_decode_uncompressed[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
self->private_data.s_decode_uncompressed[0].v_length = v_length;
goto exit;
exit:
- if (a_dst.private_impl.buf) {
- a_dst.private_impl.buf->meta.wi =
- ((size_t)(iop_a_dst - a_dst.private_impl.buf->data.ptr));
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
}
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return status;
@@ -6667,7 +6824,7 @@
static wuffs_base__status //
wuffs_deflate__decoder__init_dynamic_huffman(wuffs_deflate__decoder* self,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_src) {
wuffs_base__status status = NULL;
uint32_t v_bits = 0;
@@ -6691,16 +6848,12 @@
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_init_dynamic_huffman[0];
@@ -6726,7 +6879,7 @@
while (v_n_bits < 14) {
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -6756,7 +6909,7 @@
while (v_n_bits < 3) {
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -6795,7 +6948,7 @@
}
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -6844,7 +6997,7 @@
while (v_n_bits < v_n_extra_bits) {
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -6897,7 +7050,8 @@
goto suspend;
suspend:
- self->private_impl.p_init_dynamic_huffman[0] = coro_susp_point;
+ self->private_impl.p_init_dynamic_huffman[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
self->private_data.s_init_dynamic_huffman[0].v_bits = v_bits;
self->private_data.s_init_dynamic_huffman[0].v_n_bits = v_n_bits;
self->private_data.s_init_dynamic_huffman[0].v_n_lit = v_n_lit;
@@ -6912,9 +7066,8 @@
goto exit;
exit:
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return status;
@@ -7179,8 +7332,8 @@
static wuffs_base__status //
wuffs_deflate__decoder__decode_huffman_fast(wuffs_deflate__decoder* self,
- wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src) {
wuffs_base__status status = NULL;
uint32_t v_bits = 0;
@@ -7200,33 +7353,25 @@
uint8_t* iop_a_dst = NULL;
uint8_t* io0_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_dst.private_impl.buf) {
- iop_a_dst =
- a_dst.private_impl.buf->data.ptr + a_dst.private_impl.buf->meta.wi;
- if (!a_dst.private_impl.mark) {
- a_dst.private_impl.mark = iop_a_dst;
- a_dst.private_impl.limit =
- a_dst.private_impl.buf->data.ptr + a_dst.private_impl.buf->data.len;
+ uint8_t* io2_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_dst) {
+ io0_a_dst = a_dst->data.ptr;
+ io1_a_dst = io0_a_dst + a_dst->meta.wi;
+ iop_a_dst = io1_a_dst;
+ io2_a_dst = io0_a_dst + a_dst->data.len;
+ if (a_dst->meta.closed) {
+ io2_a_dst = iop_a_dst;
}
- if (a_dst.private_impl.buf->meta.closed) {
- a_dst.private_impl.limit = iop_a_dst;
- }
- io0_a_dst = a_dst.private_impl.mark;
- io1_a_dst = a_dst.private_impl.limit;
}
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
if ((self->private_impl.f_n_bits >= 8) ||
@@ -7239,8 +7384,8 @@
v_lmask = ((((uint32_t)(1)) << self->private_impl.f_n_huffs_bits[0]) - 1);
v_dmask = ((((uint32_t)(1)) << self->private_impl.f_n_huffs_bits[1]) - 1);
label_0_continue:;
- while ((((uint64_t)(io1_a_dst - iop_a_dst)) >= 258) &&
- (((uint64_t)(io1_a_src - iop_a_src)) >= 12)) {
+ while ((((uint64_t)(io2_a_dst - iop_a_dst)) >= 258) &&
+ (((uint64_t)(io2_a_src - iop_a_src)) >= 12)) {
if (v_n_bits < 15) {
v_bits |= (((uint32_t)(wuffs_base__load_u8be(iop_a_src))) << v_n_bits);
(iop_a_src += 1, wuffs_base__make_empty_struct());
@@ -7392,11 +7537,10 @@
v_n_copied = 0;
while (true) {
if (((uint64_t)((v_dist_minus_1 + 1))) >
- ((uint64_t)(iop_a_dst - a_dst.private_impl.mark))) {
+ ((uint64_t)(iop_a_dst - a_dst->data.ptr))) {
v_hlen = 0;
- v_hdist =
- ((uint32_t)((((uint64_t)((v_dist_minus_1 + 1))) -
- ((uint64_t)(iop_a_dst - a_dst.private_impl.mark)))));
+ v_hdist = ((uint32_t)((((uint64_t)((v_dist_minus_1 + 1))) -
+ ((uint64_t)(iop_a_dst - a_dst->data.ptr)))));
if (v_length > v_hdist) {
v_length -= v_hdist;
v_hlen = v_hdist;
@@ -7411,7 +7555,7 @@
v_hdist = (self->private_impl.f_history_index - v_hdist);
while (true) {
v_n_copied = wuffs_base__io_writer__copy_n_from_slice(
- &iop_a_dst, io1_a_dst, v_hlen,
+ &iop_a_dst, io2_a_dst, v_hlen,
wuffs_base__slice_u8__subslice_i(
wuffs_base__make_slice_u8(self->private_data.f_history,
32768),
@@ -7421,7 +7565,7 @@
}
v_hlen -= v_n_copied;
wuffs_base__io_writer__copy_n_from_slice(
- &iop_a_dst, io1_a_dst, v_hlen,
+ &iop_a_dst, io2_a_dst, v_hlen,
wuffs_base__make_slice_u8(self->private_data.f_history, 32768));
goto label_1_break;
}
@@ -7430,13 +7574,13 @@
goto label_0_continue;
}
if (((uint64_t)((v_dist_minus_1 + 1))) >
- ((uint64_t)(iop_a_dst - a_dst.private_impl.mark))) {
+ ((uint64_t)(iop_a_dst - a_dst->data.ptr))) {
status = wuffs_deflate__error__internal_error_inconsistent_distance;
goto exit;
}
}
wuffs_base__io_writer__copy_n_from_history_fast(
- &iop_a_dst, a_dst.private_impl.mark, io1_a_dst, v_length,
+ &iop_a_dst, a_dst->data.ptr, io2_a_dst, v_length,
(v_dist_minus_1 + 1));
goto label_2_break;
}
@@ -7445,7 +7589,7 @@
label_0_break:;
while (v_n_bits >= 8) {
v_n_bits -= 8;
- if (iop_a_src > io0_a_src) {
+ if (iop_a_src > io1_a_src) {
(iop_a_src--, wuffs_base__make_empty_struct());
} else {
status = wuffs_deflate__error__internal_error_inconsistent_i_o;
@@ -7461,13 +7605,11 @@
}
goto exit;
exit:
- if (a_dst.private_impl.buf) {
- a_dst.private_impl.buf->meta.wi =
- ((size_t)(iop_a_dst - a_dst.private_impl.buf->data.ptr));
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
}
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return status;
@@ -7477,8 +7619,8 @@
static wuffs_base__status //
wuffs_deflate__decoder__decode_huffman_slow(wuffs_deflate__decoder* self,
- wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src) {
wuffs_base__status status = NULL;
uint32_t v_bits = 0;
@@ -7504,33 +7646,25 @@
uint8_t* iop_a_dst = NULL;
uint8_t* io0_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_dst.private_impl.buf) {
- iop_a_dst =
- a_dst.private_impl.buf->data.ptr + a_dst.private_impl.buf->meta.wi;
- if (!a_dst.private_impl.mark) {
- a_dst.private_impl.mark = iop_a_dst;
- a_dst.private_impl.limit =
- a_dst.private_impl.buf->data.ptr + a_dst.private_impl.buf->data.len;
+ uint8_t* io2_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_dst) {
+ io0_a_dst = a_dst->data.ptr;
+ io1_a_dst = io0_a_dst + a_dst->meta.wi;
+ iop_a_dst = io1_a_dst;
+ io2_a_dst = io0_a_dst + a_dst->data.len;
+ if (a_dst->meta.closed) {
+ io2_a_dst = iop_a_dst;
}
- if (a_dst.private_impl.buf->meta.closed) {
- a_dst.private_impl.limit = iop_a_dst;
- }
- io0_a_dst = a_dst.private_impl.mark;
- io1_a_dst = a_dst.private_impl.limit;
}
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_decode_huffman_slow[0];
@@ -7574,7 +7708,7 @@
}
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -7587,7 +7721,7 @@
label_1_break:;
if ((v_table_entry >> 31) != 0) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
- if (iop_a_dst == io1_a_dst) {
+ if (iop_a_dst == io2_a_dst) {
status = wuffs_base__suspension__short_write;
goto suspend;
}
@@ -7612,7 +7746,7 @@
}
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -7625,7 +7759,7 @@
label_2_break:;
if ((v_table_entry >> 31) != 0) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
- if (iop_a_dst == io1_a_dst) {
+ if (iop_a_dst == io2_a_dst) {
status = wuffs_base__suspension__short_write;
goto suspend;
}
@@ -7661,7 +7795,7 @@
while (v_n_bits < v_table_entry_n_bits) {
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(5);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -7689,7 +7823,7 @@
}
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(6);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -7715,7 +7849,7 @@
}
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(7);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -7742,7 +7876,7 @@
while (v_n_bits < v_table_entry_n_bits) {
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(8);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -7761,10 +7895,9 @@
}
while (true) {
if (((uint64_t)((v_dist_minus_1 + 1))) >
- ((uint64_t)(iop_a_dst - a_dst.private_impl.mark))) {
- v_hdist =
- ((uint32_t)((((uint64_t)((v_dist_minus_1 + 1))) -
- ((uint64_t)(iop_a_dst - a_dst.private_impl.mark)))));
+ ((uint64_t)(iop_a_dst - a_dst->data.ptr))) {
+ v_hdist = ((uint32_t)((((uint64_t)((v_dist_minus_1 + 1))) -
+ ((uint64_t)(iop_a_dst - a_dst->data.ptr)))));
if (v_length > v_hdist) {
v_length -= v_hdist;
v_hlen = v_hdist;
@@ -7779,7 +7912,7 @@
v_hdist = (self->private_impl.f_history_index - v_hdist);
while (true) {
v_n_copied = wuffs_base__io_writer__copy_n_from_slice(
- &iop_a_dst, io1_a_dst, v_hlen,
+ &iop_a_dst, io2_a_dst, v_hlen,
wuffs_base__slice_u8__subslice_i(
wuffs_base__make_slice_u8(self->private_data.f_history,
32768),
@@ -7802,7 +7935,7 @@
if (v_hlen > 0) {
while (true) {
v_n_copied = wuffs_base__io_writer__copy_n_from_slice(
- &iop_a_dst, io1_a_dst, v_hlen,
+ &iop_a_dst, io2_a_dst, v_hlen,
wuffs_base__slice_u8__subslice_i(
wuffs_base__make_slice_u8(self->private_data.f_history,
32768),
@@ -7823,7 +7956,7 @@
}
}
v_n_copied = wuffs_base__io_writer__copy_n_from_history(
- &iop_a_dst, a_dst.private_impl.mark, io1_a_dst, v_length,
+ &iop_a_dst, a_dst->data.ptr, io2_a_dst, v_length,
(v_dist_minus_1 + 1));
if (v_length <= v_n_copied) {
v_length = 0;
@@ -7853,7 +7986,8 @@
goto suspend;
suspend:
- self->private_impl.p_decode_huffman_slow[0] = coro_susp_point;
+ self->private_impl.p_decode_huffman_slow[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
self->private_data.s_decode_huffman_slow[0].v_bits = v_bits;
self->private_data.s_decode_huffman_slow[0].v_n_bits = v_n_bits;
self->private_data.s_decode_huffman_slow[0].v_table_entry = v_table_entry;
@@ -7870,13 +8004,11 @@
goto exit;
exit:
- if (a_dst.private_impl.buf) {
- a_dst.private_impl.buf->meta.wi =
- ((size_t)(iop_a_dst - a_dst.private_impl.buf->data.ptr));
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
}
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return status;
@@ -7901,11 +8033,11 @@
static wuffs_base__empty_struct //
wuffs_lzw__decoder__read_from(wuffs_lzw__decoder* self,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_src);
static wuffs_base__status //
wuffs_lzw__decoder__write_to(wuffs_lzw__decoder* self,
- wuffs_base__io_writer a_dst);
+ wuffs_base__io_buffer* a_dst);
// ---------------- Initializer Implementations
@@ -7971,12 +8103,12 @@
if (self->private_impl.magic != WUFFS_BASE__MAGIC) {
return wuffs_base__make_empty_struct();
}
- if (a_lw < 2 || a_lw > 8) {
+ if (a_lw > 8) {
self->private_impl.magic = WUFFS_BASE__DISABLED;
return wuffs_base__make_empty_struct();
}
- self->private_impl.f_set_literal_width_arg = a_lw;
+ self->private_impl.f_set_literal_width_arg = (a_lw + 1);
return wuffs_base__make_empty_struct();
}
@@ -7999,8 +8131,8 @@
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
wuffs_lzw__decoder__decode_io_writer(wuffs_lzw__decoder* self,
- wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src,
+ wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf) {
if (!self) {
return wuffs_base__error__bad_receiver;
@@ -8010,6 +8142,10 @@
? wuffs_base__error__disabled_by_previous_error
: wuffs_base__error__initialize_not_called;
}
+ if (!a_dst || !a_src) {
+ self->private_impl.magic = WUFFS_BASE__DISABLED;
+ return wuffs_base__error__bad_argument;
+ }
if ((self->private_impl.active_coroutine != 0) &&
(self->private_impl.active_coroutine != 1)) {
self->private_impl.magic = WUFFS_BASE__DISABLED;
@@ -8027,9 +8163,9 @@
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
self->private_impl.f_literal_width = 8;
- if (self->private_impl.f_set_literal_width_arg >= 2) {
+ if (self->private_impl.f_set_literal_width_arg > 0) {
self->private_impl.f_literal_width =
- self->private_impl.f_set_literal_width_arg;
+ (self->private_impl.f_set_literal_width_arg - 1);
}
self->private_impl.f_clear_code =
(((uint32_t)(1)) << self->private_impl.f_literal_width);
@@ -8082,8 +8218,10 @@
goto suspend;
suspend:
- self->private_impl.p_decode_io_writer[0] = coro_susp_point;
- self->private_impl.active_coroutine = 1;
+ self->private_impl.p_decode_io_writer[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
+ self->private_impl.active_coroutine =
+ wuffs_base__status__is_suspension(status) ? 1 : 0;
goto exit;
exit:
@@ -8097,7 +8235,7 @@
static wuffs_base__empty_struct //
wuffs_lzw__decoder__read_from(wuffs_lzw__decoder* self,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_src) {
uint32_t v_clear_code = 0;
uint32_t v_end_code = 0;
uint32_t v_save_code = 0;
@@ -8117,16 +8255,12 @@
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
v_clear_code = self->private_impl.f_clear_code;
@@ -8139,11 +8273,11 @@
v_output_wi = self->private_impl.f_output_wi;
while (true) {
if (v_n_bits < v_width) {
- if (((uint64_t)(io1_a_src - iop_a_src)) >= 4) {
+ if (((uint64_t)(io2_a_src - iop_a_src)) >= 4) {
v_bits |= (wuffs_base__load_u32le(iop_a_src) << v_n_bits);
(iop_a_src += ((31 - v_n_bits) >> 3), wuffs_base__make_empty_struct());
v_n_bits |= 24;
- } else if (((uint64_t)(io1_a_src - iop_a_src)) <= 0) {
+ } else if (((uint64_t)(io2_a_src - iop_a_src)) <= 0) {
self->private_impl.f_read_from_return_value = 2;
goto label_0_break;
} else {
@@ -8151,7 +8285,7 @@
(iop_a_src += 1, wuffs_base__make_empty_struct());
v_n_bits += 8;
if (v_n_bits >= v_width) {
- } else if (((uint64_t)(io1_a_src - iop_a_src)) <= 0) {
+ } else if (((uint64_t)(io2_a_src - iop_a_src)) <= 0) {
self->private_impl.f_read_from_return_value = 2;
goto label_0_break;
} else {
@@ -8266,7 +8400,7 @@
if (self->private_impl.f_read_from_return_value != 2) {
while (v_n_bits >= 8) {
v_n_bits -= 8;
- if (iop_a_src > io0_a_src) {
+ if (iop_a_src > io1_a_src) {
(iop_a_src--, wuffs_base__make_empty_struct());
} else {
self->private_impl.f_read_from_return_value = 4;
@@ -8281,9 +8415,8 @@
self->private_impl.f_bits = v_bits;
self->private_impl.f_n_bits = v_n_bits;
self->private_impl.f_output_wi = v_output_wi;
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return wuffs_base__make_empty_struct();
@@ -8293,7 +8426,7 @@
static wuffs_base__status //
wuffs_lzw__decoder__write_to(wuffs_lzw__decoder* self,
- wuffs_base__io_writer a_dst) {
+ wuffs_base__io_buffer* a_dst) {
wuffs_base__status status = NULL;
wuffs_base__slice_u8 v_s = {0};
@@ -8302,19 +8435,15 @@
uint8_t* iop_a_dst = NULL;
uint8_t* io0_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_dst.private_impl.buf) {
- iop_a_dst =
- a_dst.private_impl.buf->data.ptr + a_dst.private_impl.buf->meta.wi;
- if (!a_dst.private_impl.mark) {
- a_dst.private_impl.mark = iop_a_dst;
- a_dst.private_impl.limit =
- a_dst.private_impl.buf->data.ptr + a_dst.private_impl.buf->data.len;
+ uint8_t* io2_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_dst) {
+ io0_a_dst = a_dst->data.ptr;
+ io1_a_dst = io0_a_dst + a_dst->meta.wi;
+ iop_a_dst = io1_a_dst;
+ io2_a_dst = io0_a_dst + a_dst->data.len;
+ if (a_dst->meta.closed) {
+ io2_a_dst = iop_a_dst;
}
- if (a_dst.private_impl.buf->meta.closed) {
- a_dst.private_impl.limit = iop_a_dst;
- }
- io0_a_dst = a_dst.private_impl.mark;
- io1_a_dst = a_dst.private_impl.limit;
}
uint32_t coro_susp_point = self->private_impl.p_write_to[0];
@@ -8331,7 +8460,7 @@
v_s = wuffs_base__slice_u8__subslice_ij(
wuffs_base__make_slice_u8(self->private_data.f_output, 8199),
self->private_impl.f_output_ri, self->private_impl.f_output_wi);
- v_n = wuffs_base__io_writer__copy_from_slice(&iop_a_dst, io1_a_dst, v_s);
+ v_n = wuffs_base__io_writer__copy_from_slice(&iop_a_dst, io2_a_dst, v_s);
if (v_n == ((uint64_t)(v_s.len))) {
self->private_impl.f_output_ri = 0;
self->private_impl.f_output_wi = 0;
@@ -8353,13 +8482,13 @@
goto suspend;
suspend:
- self->private_impl.p_write_to[0] = coro_susp_point;
+ self->private_impl.p_write_to[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
goto exit;
exit:
- if (a_dst.private_impl.buf) {
- a_dst.private_impl.buf->meta.wi =
- ((size_t)(iop_a_dst - a_dst.private_impl.buf->data.ptr));
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
}
return status;
@@ -8396,9 +8525,11 @@
const char* wuffs_gif__error__bad_block = "#gif: bad block";
const char* wuffs_gif__error__bad_extension_label = "#gif: bad extension label";
+const char* wuffs_gif__error__bad_frame_size = "#gif: bad frame size";
const char* wuffs_gif__error__bad_graphic_control = "#gif: bad graphic control";
const char* wuffs_gif__error__bad_header = "#gif: bad header";
const char* wuffs_gif__error__bad_literal_width = "#gif: bad literal width";
+const char* wuffs_gif__error__bad_palette = "#gif: bad palette";
const char* wuffs_gif__error__internal_error_inconsistent_ri_wi =
"#gif: internal error: inconsistent ri/wi";
@@ -8428,58 +8559,70 @@
78, 69, 84, 83, 67, 65, 80, 69, 50, 46, 48,
};
+static const uint8_t //
+ wuffs_gif__iccrgbg1012[11] //
+ WUFFS_BASE__POTENTIALLY_UNUSED = {
+ 73, 67, 67, 82, 71, 66, 71, 49, 48, 49, 50,
+};
+
+static const uint8_t //
+ wuffs_gif__xmpdataxmp[11] //
+ WUFFS_BASE__POTENTIALLY_UNUSED = {
+ 88, 77, 80, 32, 68, 97, 116, 97, 88, 77, 80,
+};
+
// ---------------- Private Initializer Prototypes
// ---------------- Private Function Prototypes
static wuffs_base__status //
wuffs_gif__decoder__skip_frame(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_src);
static wuffs_base__empty_struct //
wuffs_gif__decoder__reset_gc(wuffs_gif__decoder* self);
static wuffs_base__status //
wuffs_gif__decoder__decode_up_to_id_part1(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_src);
static wuffs_base__status //
wuffs_gif__decoder__decode_header(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_src);
static wuffs_base__status //
wuffs_gif__decoder__decode_lsd(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_src);
static wuffs_base__status //
wuffs_gif__decoder__decode_extension(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_src);
static wuffs_base__status //
wuffs_gif__decoder__skip_blocks(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_src);
static wuffs_base__status //
wuffs_gif__decoder__decode_ae(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_src);
static wuffs_base__status //
wuffs_gif__decoder__decode_gc(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_src);
static wuffs_base__status //
wuffs_gif__decoder__decode_id_part0(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_src);
static wuffs_base__status //
wuffs_gif__decoder__decode_id_part1(wuffs_gif__decoder* self,
wuffs_base__pixel_buffer* a_dst,
- wuffs_base__io_reader a_src);
+ wuffs_base__io_buffer* a_src);
static wuffs_base__status //
wuffs_gif__decoder__decode_id_part2(wuffs_gif__decoder* self,
wuffs_base__pixel_buffer* a_dst,
- wuffs_base__io_reader a_src,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf);
static wuffs_base__status //
@@ -8549,12 +8692,47 @@
// ---------------- Function Implementations
+// -------- func gif.decoder.set_quirk_enabled
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__empty_struct //
+wuffs_gif__decoder__set_quirk_enabled(wuffs_gif__decoder* self,
+ uint32_t a_quirk,
+ bool a_enabled) {
+ if (!self) {
+ return wuffs_base__make_empty_struct();
+ }
+ if (self->private_impl.magic != WUFFS_BASE__MAGIC) {
+ return wuffs_base__make_empty_struct();
+ }
+
+ if (self->private_impl.f_call_sequence == 0) {
+ if (a_quirk == 1041635328) {
+ self->private_impl.f_quirk_enabled_delay_num_decoded_frames = a_enabled;
+ } else if (a_quirk == 1041635329) {
+ self->private_impl
+ .f_quirk_enabled_first_frame_local_palette_means_black_background =
+ a_enabled;
+ } else if (a_quirk == 1041635330) {
+ self->private_impl.f_quirk_enabled_honor_background_color = a_enabled;
+ } else if (a_quirk == 1041635331) {
+ self->private_impl.f_quirk_enabled_ignore_too_much_pixel_data = a_enabled;
+ } else if (a_quirk == 1041635332) {
+ self->private_impl.f_quirk_enabled_image_bounds_are_strict = a_enabled;
+ } else if (a_quirk == 1041635333) {
+ self->private_impl.f_quirk_enabled_reject_empty_frame = a_enabled;
+ } else if (a_quirk == 1041635334) {
+ self->private_impl.f_quirk_enabled_reject_empty_palette = a_enabled;
+ }
+ }
+ return wuffs_base__make_empty_struct();
+}
+
// -------- func gif.decoder.decode_image_config
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
wuffs_gif__decoder__decode_image_config(wuffs_gif__decoder* self,
wuffs_base__image_config* a_dst,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_src) {
if (!self) {
return wuffs_base__error__bad_receiver;
}
@@ -8563,6 +8741,10 @@
? wuffs_base__error__disabled_by_previous_error
: wuffs_base__error__initialize_not_called;
}
+ if (!a_src) {
+ self->private_impl.magic = WUFFS_BASE__DISABLED;
+ return wuffs_base__error__bad_argument;
+ }
if ((self->private_impl.active_coroutine != 0) &&
(self->private_impl.active_coroutine != 1)) {
self->private_impl.magic = WUFFS_BASE__DISABLED;
@@ -8579,38 +8761,47 @@
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
- if (self->private_impl.f_call_sequence >= 1) {
+ if (self->private_impl.f_call_sequence == 0) {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
+ status = wuffs_gif__decoder__decode_header(self, a_src);
+ if (status) {
+ goto suspend;
+ }
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
+ status = wuffs_gif__decoder__decode_lsd(self, a_src);
+ if (status) {
+ goto suspend;
+ }
+ } else if (self->private_impl.f_call_sequence != 2) {
status = wuffs_base__error__bad_call_sequence;
goto exit;
}
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
- status = wuffs_gif__decoder__decode_header(self, a_src);
- if (status) {
- goto suspend;
- }
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
- status = wuffs_gif__decoder__decode_lsd(self, a_src);
- if (status) {
- goto suspend;
- }
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
status = wuffs_gif__decoder__decode_up_to_id_part1(self, a_src);
if (status) {
goto suspend;
}
- v_ffio =
- (!self->private_impl.f_gc_has_transparent_index &&
- (self->private_impl.f_frame_rect_x0 == 0) &&
- (self->private_impl.f_frame_rect_y0 == 0) &&
- (self->private_impl.f_frame_rect_x1 == self->private_impl.f_width) &&
- (self->private_impl.f_frame_rect_y1 == self->private_impl.f_height));
+ v_ffio = !self->private_impl.f_gc_has_transparent_index;
+ if (!self->private_impl.f_quirk_enabled_honor_background_color) {
+ v_ffio =
+ (v_ffio && (self->private_impl.f_frame_rect_x0 == 0) &&
+ (self->private_impl.f_frame_rect_y0 == 0) &&
+ (self->private_impl.f_frame_rect_x1 == self->private_impl.f_width) &&
+ (self->private_impl.f_frame_rect_y1 == self->private_impl.f_height));
+ } else if (v_ffio) {
+ self->private_impl.f_black_color_u32_argb_premul = 4278190080;
+ }
+ if (self->private_impl.f_background_color_u32_argb_premul == 77) {
+ self->private_impl.f_background_color_u32_argb_premul =
+ self->private_impl.f_black_color_u32_argb_premul;
+ }
if (a_dst != NULL) {
wuffs_base__image_config__set(
a_dst, 1191444488, 0, self->private_impl.f_width,
self->private_impl.f_height,
self->private_impl.f_frame_config_io_position, v_ffio);
}
- self->private_impl.f_call_sequence = 1;
+ self->private_impl.f_call_sequence = 3;
goto ok;
ok:
@@ -8620,8 +8811,10 @@
goto suspend;
suspend:
- self->private_impl.p_decode_image_config[0] = coro_susp_point;
- self->private_impl.active_coroutine = 1;
+ self->private_impl.p_decode_image_config[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
+ self->private_impl.active_coroutine =
+ wuffs_base__status__is_suspension(status) ? 1 : 0;
goto exit;
exit:
@@ -8631,6 +8824,172 @@
return status;
}
+// -------- func gif.decoder.set_report_metadata
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__empty_struct //
+wuffs_gif__decoder__set_report_metadata(wuffs_gif__decoder* self,
+ uint32_t a_fourcc,
+ bool a_report) {
+ if (!self) {
+ return wuffs_base__make_empty_struct();
+ }
+ if (self->private_impl.magic != WUFFS_BASE__MAGIC) {
+ return wuffs_base__make_empty_struct();
+ }
+
+ if (a_fourcc == 1229144912) {
+ self->private_impl.f_report_metadata_iccp = a_report;
+ } else if (a_fourcc == 1481461792) {
+ self->private_impl.f_report_metadata_xmp = a_report;
+ }
+ return wuffs_base__make_empty_struct();
+}
+
+// -------- func gif.decoder.ack_metadata_chunk
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
+wuffs_gif__decoder__ack_metadata_chunk(wuffs_gif__decoder* self,
+ wuffs_base__io_buffer* a_src) {
+ if (!self) {
+ return wuffs_base__error__bad_receiver;
+ }
+ if (self->private_impl.magic != WUFFS_BASE__MAGIC) {
+ return (self->private_impl.magic == WUFFS_BASE__DISABLED)
+ ? wuffs_base__error__disabled_by_previous_error
+ : wuffs_base__error__initialize_not_called;
+ }
+ if (!a_src) {
+ self->private_impl.magic = WUFFS_BASE__DISABLED;
+ return wuffs_base__error__bad_argument;
+ }
+ if ((self->private_impl.active_coroutine != 0) &&
+ (self->private_impl.active_coroutine != 2)) {
+ self->private_impl.magic = WUFFS_BASE__DISABLED;
+ return wuffs_base__error__interleaved_coroutine_calls;
+ }
+ self->private_impl.active_coroutine = 0;
+ wuffs_base__status status = NULL;
+
+ uint8_t* iop_a_src = NULL;
+ uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
+ }
+
+ uint32_t coro_susp_point = self->private_impl.p_ack_metadata_chunk[0];
+ if (coro_susp_point) {
+ }
+ switch (coro_susp_point) {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
+
+ if (self->private_impl.f_call_sequence != 1) {
+ status = wuffs_base__error__bad_call_sequence;
+ goto exit;
+ }
+ if ((a_src ? wuffs_base__u64__sat_add(
+ a_src->meta.pos, ((uint64_t)(iop_a_src - a_src->data.ptr)))
+ : 0) != self->private_impl.f_metadata_io_position) {
+ status = wuffs_base__error__bad_i_o_position;
+ goto exit;
+ }
+ while (((uint64_t)(io2_a_src - iop_a_src)) <= 0) {
+ status = wuffs_base__suspension__short_read;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(1);
+ }
+ if (self->private_impl.f_metadata_fourcc_value == 1481461792) {
+ self->private_impl.f_metadata_chunk_length_value =
+ (((uint64_t)(wuffs_base__load_u8be(iop_a_src))) + 1);
+ if (self->private_impl.f_metadata_chunk_length_value > 1) {
+ self->private_impl.f_metadata_io_position = wuffs_base__u64__sat_add(
+ (a_src ? wuffs_base__u64__sat_add(
+ a_src->meta.pos,
+ ((uint64_t)(iop_a_src - a_src->data.ptr)))
+ : 0),
+ self->private_impl.f_metadata_chunk_length_value);
+ status = wuffs_base__warning__metadata_reported;
+ goto ok;
+ }
+ } else {
+ self->private_impl.f_metadata_chunk_length_value =
+ ((uint64_t)(wuffs_base__load_u8be(iop_a_src)));
+ if (self->private_impl.f_metadata_chunk_length_value > 0) {
+ (iop_a_src += 1, wuffs_base__make_empty_struct());
+ self->private_impl.f_metadata_io_position = wuffs_base__u64__sat_add(
+ (a_src ? wuffs_base__u64__sat_add(
+ a_src->meta.pos,
+ ((uint64_t)(iop_a_src - a_src->data.ptr)))
+ : 0),
+ self->private_impl.f_metadata_chunk_length_value);
+ status = wuffs_base__warning__metadata_reported;
+ goto ok;
+ }
+ }
+ (iop_a_src += 1, wuffs_base__make_empty_struct());
+ self->private_impl.f_call_sequence = 2;
+ self->private_impl.f_metadata_fourcc_value = 0;
+ self->private_impl.f_metadata_io_position = 0;
+ status = NULL;
+ goto ok;
+ goto ok;
+ ok:
+ self->private_impl.p_ack_metadata_chunk[0] = 0;
+ goto exit;
+ }
+
+ goto suspend;
+suspend:
+ self->private_impl.p_ack_metadata_chunk[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
+ self->private_impl.active_coroutine =
+ wuffs_base__status__is_suspension(status) ? 2 : 0;
+
+ goto exit;
+exit:
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+
+ if (wuffs_base__status__is_error(status)) {
+ self->private_impl.magic = WUFFS_BASE__DISABLED;
+ }
+ return status;
+}
+
+// -------- func gif.decoder.metadata_fourcc
+
+WUFFS_BASE__MAYBE_STATIC uint32_t //
+wuffs_gif__decoder__metadata_fourcc(const wuffs_gif__decoder* self) {
+ if (!self) {
+ return 0;
+ }
+ if ((self->private_impl.magic != WUFFS_BASE__MAGIC) &&
+ (self->private_impl.magic != WUFFS_BASE__DISABLED)) {
+ return 0;
+ }
+
+ return self->private_impl.f_metadata_fourcc_value;
+}
+
+// -------- func gif.decoder.metadata_chunk_length
+
+WUFFS_BASE__MAYBE_STATIC uint64_t //
+wuffs_gif__decoder__metadata_chunk_length(const wuffs_gif__decoder* self) {
+ if (!self) {
+ return 0;
+ }
+ if ((self->private_impl.magic != WUFFS_BASE__MAGIC) &&
+ (self->private_impl.magic != WUFFS_BASE__DISABLED)) {
+ return 0;
+ }
+
+ return self->private_impl.f_metadata_chunk_length_value;
+}
+
// -------- func gif.decoder.num_animation_loops
WUFFS_BASE__MAYBE_STATIC uint32_t //
@@ -8733,6 +9092,7 @@
if (self->private_impl.f_call_sequence == 0) {
return wuffs_base__error__bad_call_sequence;
}
+ self->private_impl.f_delayed_num_decoded_frames = false;
self->private_impl.f_end_of_data = false;
self->private_impl.f_restarted = true;
self->private_impl.f_frame_config_io_position = a_io_position;
@@ -8747,7 +9107,7 @@
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
wuffs_gif__decoder__decode_frame_config(wuffs_gif__decoder* self,
wuffs_base__frame_config* a_dst,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_src) {
if (!self) {
return wuffs_base__error__bad_receiver;
}
@@ -8756,8 +9116,12 @@
? wuffs_base__error__disabled_by_previous_error
: wuffs_base__error__initialize_not_called;
}
+ if (!a_src) {
+ self->private_impl.magic = WUFFS_BASE__DISABLED;
+ return wuffs_base__error__bad_argument;
+ }
if ((self->private_impl.active_coroutine != 0) &&
- (self->private_impl.active_coroutine != 2)) {
+ (self->private_impl.active_coroutine != 3)) {
self->private_impl.magic = WUFFS_BASE__DISABLED;
return wuffs_base__error__interleaved_coroutine_calls;
}
@@ -8765,32 +9129,67 @@
wuffs_base__status status = NULL;
uint8_t v_blend = 0;
+ uint32_t v_background_color = 0;
+ uint8_t v_flags = 0;
+
+ uint8_t* iop_a_src = NULL;
+ uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
+ }
uint32_t coro_susp_point = self->private_impl.p_decode_frame_config[0];
if (coro_susp_point) {
+ v_blend = self->private_data.s_decode_frame_config[0].v_blend;
+ v_background_color =
+ self->private_data.s_decode_frame_config[0].v_background_color;
}
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
+ self->private_impl.f_ignore_metadata = true;
(memset(&self->private_impl.f_dirty_y, 0, sizeof(wuffs_base__range_ie_u32)),
wuffs_base__make_empty_struct());
if (!self->private_impl.f_end_of_data) {
if (self->private_impl.f_call_sequence == 0) {
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
status = wuffs_gif__decoder__decode_image_config(self, NULL, a_src);
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
+ }
if (status) {
goto suspend;
}
- } else if (self->private_impl.f_call_sequence != 1) {
- if (self->private_impl.f_call_sequence == 2) {
+ } else if (self->private_impl.f_call_sequence != 3) {
+ if (self->private_impl.f_call_sequence == 4) {
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
status = wuffs_gif__decoder__skip_frame(self, a_src);
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
+ }
if (status) {
goto suspend;
}
}
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
status = wuffs_gif__decoder__decode_up_to_id_part1(self, a_src);
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
+ }
if (status) {
goto suspend;
}
@@ -8801,8 +9200,23 @@
goto ok;
}
v_blend = 0;
+ v_background_color = self->private_impl.f_black_color_u32_argb_premul;
if (!self->private_impl.f_gc_has_transparent_index) {
v_blend = 2;
+ v_background_color =
+ self->private_impl.f_background_color_u32_argb_premul;
+ if (self->private_impl
+ .f_quirk_enabled_first_frame_local_palette_means_black_background &&
+ (self->private_impl.f_num_decoded_frame_configs_value == 0)) {
+ while (((uint64_t)(io2_a_src - iop_a_src)) <= 0) {
+ status = wuffs_base__suspension__short_read;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(4);
+ }
+ v_flags = wuffs_base__load_u8be(iop_a_src);
+ if ((v_flags & 128) != 0) {
+ v_background_color = self->private_impl.f_black_color_u32_argb_premul;
+ }
+ }
}
if (a_dst != NULL) {
wuffs_base__frame_config__update(
@@ -8819,11 +9233,11 @@
((wuffs_base__flicks)(self->private_impl.f_gc_duration)),
self->private_impl.f_num_decoded_frame_configs_value,
self->private_impl.f_frame_config_io_position, v_blend,
- self->private_impl.f_gc_disposal);
+ self->private_impl.f_gc_disposal, v_background_color);
}
wuffs_base__u64__sat_add_indirect(
&self->private_impl.f_num_decoded_frame_configs_value, 1);
- self->private_impl.f_call_sequence = 2;
+ self->private_impl.f_call_sequence = 4;
goto ok;
ok:
@@ -8833,11 +9247,20 @@
goto suspend;
suspend:
- self->private_impl.p_decode_frame_config[0] = coro_susp_point;
- self->private_impl.active_coroutine = 2;
+ self->private_impl.p_decode_frame_config[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
+ self->private_impl.active_coroutine =
+ wuffs_base__status__is_suspension(status) ? 3 : 0;
+ self->private_data.s_decode_frame_config[0].v_blend = v_blend;
+ self->private_data.s_decode_frame_config[0].v_background_color =
+ v_background_color;
goto exit;
exit:
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+
if (wuffs_base__status__is_error(status)) {
self->private_impl.magic = WUFFS_BASE__DISABLED;
}
@@ -8848,24 +9271,21 @@
static wuffs_base__status //
wuffs_gif__decoder__skip_frame(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_src) {
wuffs_base__status status = NULL;
uint8_t v_flags = 0;
+ uint8_t v_lw = 0;
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_skip_frame[0];
@@ -8876,7 +9296,7 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -8888,36 +9308,45 @@
(((uint32_t)(3)) << (1 + (v_flags & 7)));
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
if (self->private_data.s_skip_frame[0].scratch >
- ((uint64_t)(io1_a_src - iop_a_src))) {
+ ((uint64_t)(io2_a_src - iop_a_src))) {
self->private_data.s_skip_frame[0].scratch -=
- ((uint64_t)(io1_a_src - iop_a_src));
- iop_a_src = io1_a_src;
+ ((uint64_t)(io2_a_src - iop_a_src));
+ iop_a_src = io2_a_src;
status = wuffs_base__suspension__short_read;
goto suspend;
}
iop_a_src += self->private_data.s_skip_frame[0].scratch;
}
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
- status = wuffs_base__suspension__short_read;
- goto suspend;
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+ status = wuffs_base__suspension__short_read;
+ goto suspend;
+ }
+ uint8_t t_1 = *iop_a_src++;
+ v_lw = t_1;
}
- iop_a_src++;
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (v_lw > 8) {
+ status = wuffs_gif__error__bad_literal_width;
+ goto exit;
+ }
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
status = wuffs_gif__decoder__skip_blocks(self, a_src);
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
}
if (status) {
goto suspend;
}
- wuffs_base__u64__sat_add_indirect(
- &self->private_impl.f_num_decoded_frames_value, 1);
+ if (self->private_impl.f_quirk_enabled_delay_num_decoded_frames) {
+ self->private_impl.f_delayed_num_decoded_frames = true;
+ } else {
+ wuffs_base__u64__sat_add_indirect(
+ &self->private_impl.f_num_decoded_frames_value, 1);
+ }
wuffs_gif__decoder__reset_gc(self);
goto ok;
@@ -8928,13 +9357,13 @@
goto suspend;
suspend:
- self->private_impl.p_skip_frame[0] = coro_susp_point;
+ self->private_impl.p_skip_frame[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
goto exit;
exit:
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return status;
@@ -8945,7 +9374,7 @@
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
wuffs_gif__decoder__decode_frame(wuffs_gif__decoder* self,
wuffs_base__pixel_buffer* a_dst,
- wuffs_base__io_reader a_src,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf,
wuffs_base__decode_frame_options* a_opts) {
if (!self) {
@@ -8956,12 +9385,12 @@
? wuffs_base__error__disabled_by_previous_error
: wuffs_base__error__initialize_not_called;
}
- if (!a_dst) {
+ if (!a_dst || !a_src) {
self->private_impl.magic = WUFFS_BASE__DISABLED;
return wuffs_base__error__bad_argument;
}
if ((self->private_impl.active_coroutine != 0) &&
- (self->private_impl.active_coroutine != 3)) {
+ (self->private_impl.active_coroutine != 4)) {
self->private_impl.magic = WUFFS_BASE__DISABLED;
return wuffs_base__error__interleaved_coroutine_calls;
}
@@ -8974,13 +9403,22 @@
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
- if (self->private_impl.f_call_sequence != 2) {
+ self->private_impl.f_ignore_metadata = true;
+ if (self->private_impl.f_call_sequence != 4) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
status = wuffs_gif__decoder__decode_frame_config(self, NULL, a_src);
if (status) {
goto suspend;
}
}
+ if (self->private_impl.f_quirk_enabled_reject_empty_frame &&
+ ((self->private_impl.f_frame_rect_x0 ==
+ self->private_impl.f_frame_rect_x1) ||
+ (self->private_impl.f_frame_rect_y0 ==
+ self->private_impl.f_frame_rect_y1))) {
+ status = wuffs_gif__error__bad_frame_size;
+ goto exit;
+ }
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
status = wuffs_gif__decoder__decode_id_part1(self, a_dst, a_src);
if (status) {
@@ -9003,8 +9441,10 @@
goto suspend;
suspend:
- self->private_impl.p_decode_frame[0] = coro_susp_point;
- self->private_impl.active_coroutine = 3;
+ self->private_impl.p_decode_frame[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
+ self->private_impl.active_coroutine =
+ wuffs_base__status__is_suspension(status) ? 4 : 0;
goto exit;
exit:
@@ -9018,8 +9458,7 @@
static wuffs_base__empty_struct //
wuffs_gif__decoder__reset_gc(wuffs_gif__decoder* self) {
- self->private_impl.f_call_sequence = 3;
- self->private_impl.f_seen_graphic_control = false;
+ self->private_impl.f_call_sequence = 5;
self->private_impl.f_gc_has_transparent_index = false;
self->private_impl.f_gc_transparent_index = 0;
self->private_impl.f_gc_disposal = 0;
@@ -9031,7 +9470,7 @@
static wuffs_base__status //
wuffs_gif__decoder__decode_up_to_id_part1(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_src) {
wuffs_base__status status = NULL;
uint8_t v_block_type = 0;
@@ -9039,16 +9478,12 @@
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_decode_up_to_id_part1[0];
@@ -9058,19 +9493,18 @@
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
if (!self->private_impl.f_restarted) {
- self->private_impl.f_frame_config_io_position =
- (a_src.private_impl.buf
- ? wuffs_base__u64__sat_add(
- a_src.private_impl.buf->meta.pos,
- ((uint64_t)(iop_a_src - a_src.private_impl.buf->data.ptr)))
- : 0);
+ if (self->private_impl.f_call_sequence != 2) {
+ self->private_impl.f_frame_config_io_position =
+ (a_src ? wuffs_base__u64__sat_add(
+ a_src->meta.pos,
+ ((uint64_t)(iop_a_src - a_src->data.ptr)))
+ : 0);
+ }
} else if (self->private_impl.f_frame_config_io_position !=
- (a_src.private_impl.buf
- ? wuffs_base__u64__sat_add(
- a_src.private_impl.buf->meta.pos,
- ((uint64_t)(iop_a_src -
- a_src.private_impl.buf->data.ptr)))
- : 0)) {
+ (a_src ? wuffs_base__u64__sat_add(
+ a_src->meta.pos,
+ ((uint64_t)(iop_a_src - a_src->data.ptr)))
+ : 0)) {
status = wuffs_base__error__bad_restart;
goto exit;
} else {
@@ -9079,7 +9513,7 @@
while (true) {
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -9087,35 +9521,41 @@
v_block_type = t_0;
}
if (v_block_type == 33) {
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
status = wuffs_gif__decoder__decode_extension(self, a_src);
- if (a_src.private_impl.buf) {
- iop_a_src = a_src.private_impl.buf->data.ptr +
- a_src.private_impl.buf->meta.ri;
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
}
if (status) {
goto suspend;
}
} else if (v_block_type == 44) {
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (self->private_impl.f_delayed_num_decoded_frames) {
+ self->private_impl.f_delayed_num_decoded_frames = false;
+ wuffs_base__u64__sat_add_indirect(
+ &self->private_impl.f_num_decoded_frames_value, 1);
+ }
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
status = wuffs_gif__decoder__decode_id_part0(self, a_src);
- if (a_src.private_impl.buf) {
- iop_a_src = a_src.private_impl.buf->data.ptr +
- a_src.private_impl.buf->meta.ri;
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
}
if (status) {
goto suspend;
}
goto label_0_break;
} else if (v_block_type == 59) {
+ if (self->private_impl.f_delayed_num_decoded_frames) {
+ self->private_impl.f_delayed_num_decoded_frames = false;
+ wuffs_base__u64__sat_add_indirect(
+ &self->private_impl.f_num_decoded_frames_value, 1);
+ }
self->private_impl.f_end_of_data = true;
goto label_0_break;
} else {
@@ -9133,13 +9573,13 @@
goto suspend;
suspend:
- self->private_impl.p_decode_up_to_id_part1[0] = coro_susp_point;
+ self->private_impl.p_decode_up_to_id_part1[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
goto exit;
exit:
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return status;
@@ -9149,7 +9589,7 @@
static wuffs_base__status //
wuffs_gif__decoder__decode_header(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_src) {
wuffs_base__status status = NULL;
uint8_t v_c[6] = {0};
@@ -9158,16 +9598,12 @@
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_decode_header[0];
@@ -9181,7 +9617,7 @@
while (v_i < 6) {
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -9204,15 +9640,15 @@
goto suspend;
suspend:
- self->private_impl.p_decode_header[0] = coro_susp_point;
+ self->private_impl.p_decode_header[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
memcpy(self->private_data.s_decode_header[0].v_c, v_c, sizeof(v_c));
self->private_data.s_decode_header[0].v_i = v_i;
goto exit;
exit:
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return status;
@@ -9222,32 +9658,32 @@
static wuffs_base__status //
wuffs_gif__decoder__decode_lsd(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_src) {
wuffs_base__status status = NULL;
uint8_t v_flags = 0;
+ uint8_t v_background_color_index = 0;
uint32_t v_num_palette_entries = 0;
uint32_t v_i = 0;
+ uint32_t v_j = 0;
uint32_t v_argb = 0;
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_decode_lsd[0];
if (coro_susp_point) {
v_flags = self->private_data.s_decode_lsd[0].v_flags;
+ v_background_color_index =
+ self->private_data.s_decode_lsd[0].v_background_color_index;
v_num_palette_entries =
self->private_data.s_decode_lsd[0].v_num_palette_entries;
v_i = self->private_data.s_decode_lsd[0].v_i;
@@ -9258,14 +9694,14 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
uint32_t t_0;
- if (WUFFS_BASE__LIKELY(io1_a_src - iop_a_src >= 2)) {
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 2)) {
t_0 = ((uint32_t)(wuffs_base__load_u16le(iop_a_src)));
iop_a_src += 2;
} else {
self->private_data.s_decode_lsd[0].scratch = 0;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -9287,14 +9723,14 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
uint32_t t_1;
- if (WUFFS_BASE__LIKELY(io1_a_src - iop_a_src >= 2)) {
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 2)) {
t_1 = ((uint32_t)(wuffs_base__load_u16le(iop_a_src)));
iop_a_src += 2;
} else {
self->private_data.s_decode_lsd[0].scratch = 0;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -9315,56 +9751,61 @@
}
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(5);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
uint8_t t_2 = *iop_a_src++;
v_flags = t_2;
}
- self->private_data.s_decode_lsd[0].scratch = 2;
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(6);
- if (self->private_data.s_decode_lsd[0].scratch >
- ((uint64_t)(io1_a_src - iop_a_src))) {
- self->private_data.s_decode_lsd[0].scratch -=
- ((uint64_t)(io1_a_src - iop_a_src));
- iop_a_src = io1_a_src;
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(6);
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+ status = wuffs_base__suspension__short_read;
+ goto suspend;
+ }
+ uint8_t t_3 = *iop_a_src++;
+ v_background_color_index = t_3;
+ }
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(7);
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
- iop_a_src += self->private_data.s_decode_lsd[0].scratch;
- if ((v_flags & 128) != 0) {
+ iop_a_src++;
+ v_i = 0;
+ self->private_impl.f_has_global_palette = ((v_flags & 128) != 0);
+ if (self->private_impl.f_has_global_palette) {
v_num_palette_entries = (((uint32_t)(1)) << (1 + (v_flags & 7)));
- v_i = 0;
while (v_i < v_num_palette_entries) {
{
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(7);
- uint32_t t_3;
- if (WUFFS_BASE__LIKELY(io1_a_src - iop_a_src >= 3)) {
- t_3 = ((uint32_t)(wuffs_base__load_u24be(iop_a_src)));
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(8);
+ uint32_t t_4;
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 3)) {
+ t_4 = ((uint32_t)(wuffs_base__load_u24be(iop_a_src)));
iop_a_src += 3;
} else {
self->private_data.s_decode_lsd[0].scratch = 0;
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(8);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(9);
while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
uint64_t* scratch = &self->private_data.s_decode_lsd[0].scratch;
- uint32_t num_bits_3 = ((uint32_t)(*scratch & 0xFF));
+ uint32_t num_bits_4 = ((uint32_t)(*scratch & 0xFF));
*scratch >>= 8;
*scratch <<= 8;
- *scratch |= ((uint64_t)(*iop_a_src++)) << (56 - num_bits_3);
- if (num_bits_3 == 16) {
- t_3 = ((uint32_t)(*scratch >> 40));
+ *scratch |= ((uint64_t)(*iop_a_src++)) << (56 - num_bits_4);
+ if (num_bits_4 == 16) {
+ t_4 = ((uint32_t)(*scratch >> 40));
break;
}
- num_bits_3 += 8;
- *scratch |= ((uint64_t)(num_bits_3));
+ num_bits_4 += 8;
+ *scratch |= ((uint64_t)(num_bits_4));
}
}
- v_argb = t_3;
+ v_argb = t_4;
}
v_argb |= 4278190080;
self->private_data.f_palettes[0][((4 * v_i) + 0)] =
@@ -9377,14 +9818,31 @@
((uint8_t)(((v_argb >> 24) & 255)));
v_i += 1;
}
- while (v_i < 256) {
- self->private_data.f_palettes[0][((4 * v_i) + 0)] = 0;
- self->private_data.f_palettes[0][((4 * v_i) + 1)] = 0;
- self->private_data.f_palettes[0][((4 * v_i) + 2)] = 0;
- self->private_data.f_palettes[0][((4 * v_i) + 3)] = 255;
- v_i += 1;
+ if (self->private_impl.f_quirk_enabled_honor_background_color) {
+ if ((v_background_color_index != 0) &&
+ (((uint32_t)(v_background_color_index)) < v_num_palette_entries)) {
+ v_j = (4 * ((uint32_t)(v_background_color_index)));
+ self->private_impl.f_background_color_u32_argb_premul =
+ ((((uint32_t)(self->private_data.f_palettes[0][(v_j + 0)]))
+ << 0) |
+ (((uint32_t)(self->private_data.f_palettes[0][(v_j + 1)]))
+ << 8) |
+ (((uint32_t)(self->private_data.f_palettes[0][(v_j + 2)]))
+ << 16) |
+ (((uint32_t)(self->private_data.f_palettes[0][(v_j + 3)]))
+ << 24));
+ } else {
+ self->private_impl.f_background_color_u32_argb_premul = 77;
+ }
}
}
+ while (v_i < 256) {
+ self->private_data.f_palettes[0][((4 * v_i) + 0)] = 0;
+ self->private_data.f_palettes[0][((4 * v_i) + 1)] = 0;
+ self->private_data.f_palettes[0][((4 * v_i) + 2)] = 0;
+ self->private_data.f_palettes[0][((4 * v_i) + 3)] = 255;
+ v_i += 1;
+ }
goto ok;
ok:
@@ -9394,17 +9852,19 @@
goto suspend;
suspend:
- self->private_impl.p_decode_lsd[0] = coro_susp_point;
+ self->private_impl.p_decode_lsd[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
self->private_data.s_decode_lsd[0].v_flags = v_flags;
+ self->private_data.s_decode_lsd[0].v_background_color_index =
+ v_background_color_index;
self->private_data.s_decode_lsd[0].v_num_palette_entries =
v_num_palette_entries;
self->private_data.s_decode_lsd[0].v_i = v_i;
goto exit;
exit:
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return status;
@@ -9414,7 +9874,7 @@
static wuffs_base__status //
wuffs_gif__decoder__decode_extension(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_src) {
wuffs_base__status status = NULL;
uint8_t v_label = 0;
@@ -9422,16 +9882,12 @@
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_decode_extension[0];
@@ -9442,7 +9898,7 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -9450,15 +9906,13 @@
v_label = t_0;
}
if (v_label == 249) {
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
status = wuffs_gif__decoder__decode_gc(self, a_src);
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
}
if (status) {
goto suspend;
@@ -9466,15 +9920,13 @@
status = NULL;
goto ok;
} else if (v_label == 255) {
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
status = wuffs_gif__decoder__decode_ae(self, a_src);
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
}
if (status) {
goto suspend;
@@ -9482,15 +9934,13 @@
status = NULL;
goto ok;
}
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
status = wuffs_gif__decoder__skip_blocks(self, a_src);
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
}
if (status) {
goto suspend;
@@ -9504,13 +9954,13 @@
goto suspend;
suspend:
- self->private_impl.p_decode_extension[0] = coro_susp_point;
+ self->private_impl.p_decode_extension[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
goto exit;
exit:
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return status;
@@ -9520,7 +9970,7 @@
static wuffs_base__status //
wuffs_gif__decoder__skip_blocks(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_src) {
wuffs_base__status status = NULL;
uint8_t v_block_size = 0;
@@ -9528,16 +9978,12 @@
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_skip_blocks[0];
@@ -9549,7 +9995,7 @@
while (true) {
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -9563,10 +10009,10 @@
self->private_data.s_skip_blocks[0].scratch = ((uint32_t)(v_block_size));
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
if (self->private_data.s_skip_blocks[0].scratch >
- ((uint64_t)(io1_a_src - iop_a_src))) {
+ ((uint64_t)(io2_a_src - iop_a_src))) {
self->private_data.s_skip_blocks[0].scratch -=
- ((uint64_t)(io1_a_src - iop_a_src));
- iop_a_src = io1_a_src;
+ ((uint64_t)(io2_a_src - iop_a_src));
+ iop_a_src = io2_a_src;
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -9581,13 +10027,13 @@
goto suspend;
suspend:
- self->private_impl.p_skip_blocks[0] = coro_susp_point;
+ self->private_impl.p_skip_blocks[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
goto exit;
exit:
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return status;
@@ -9597,34 +10043,34 @@
static wuffs_base__status //
wuffs_gif__decoder__decode_ae(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_src) {
wuffs_base__status status = NULL;
uint8_t v_c = 0;
uint8_t v_block_size = 0;
- bool v_not_animexts = false;
- bool v_not_netscape = false;
+ bool v_is_animexts = false;
+ bool v_is_netscape = false;
+ bool v_is_iccp = false;
+ bool v_is_xmp = false;
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_decode_ae[0];
if (coro_susp_point) {
v_block_size = self->private_data.s_decode_ae[0].v_block_size;
- v_not_animexts = self->private_data.s_decode_ae[0].v_not_animexts;
- v_not_netscape = self->private_data.s_decode_ae[0].v_not_netscape;
+ v_is_animexts = self->private_data.s_decode_ae[0].v_is_animexts;
+ v_is_netscape = self->private_data.s_decode_ae[0].v_is_netscape;
+ v_is_iccp = self->private_data.s_decode_ae[0].v_is_iccp;
+ v_is_xmp = self->private_data.s_decode_ae[0].v_is_xmp;
}
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
@@ -9632,7 +10078,7 @@
while (true) {
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -9647,33 +10093,38 @@
self->private_data.s_decode_ae[0].scratch = ((uint32_t)(v_block_size));
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
if (self->private_data.s_decode_ae[0].scratch >
- ((uint64_t)(io1_a_src - iop_a_src))) {
+ ((uint64_t)(io2_a_src - iop_a_src))) {
self->private_data.s_decode_ae[0].scratch -=
- ((uint64_t)(io1_a_src - iop_a_src));
- iop_a_src = io1_a_src;
+ ((uint64_t)(io2_a_src - iop_a_src));
+ iop_a_src = io2_a_src;
status = wuffs_base__suspension__short_read;
goto suspend;
}
iop_a_src += self->private_data.s_decode_ae[0].scratch;
goto label_0_break;
}
- v_not_animexts = false;
- v_not_netscape = false;
+ v_is_animexts = true;
+ v_is_netscape = true;
+ v_is_iccp = true;
+ v_is_xmp = true;
v_block_size = 0;
while (v_block_size < 11) {
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
uint8_t t_1 = *iop_a_src++;
v_c = t_1;
}
- v_not_animexts =
- (v_not_animexts || (v_c != wuffs_gif__animexts1dot0[v_block_size]));
- v_not_netscape =
- (v_not_netscape || (v_c != wuffs_gif__netscape2dot0[v_block_size]));
+ v_is_animexts =
+ (v_is_animexts && (v_c == wuffs_gif__animexts1dot0[v_block_size]));
+ v_is_netscape =
+ (v_is_netscape && (v_c == wuffs_gif__netscape2dot0[v_block_size]));
+ v_is_iccp =
+ (v_is_iccp && (v_c == wuffs_gif__iccrgbg1012[v_block_size]));
+ v_is_xmp = (v_is_xmp && (v_c == wuffs_gif__xmpdataxmp[v_block_size]));
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
@@ -9683,101 +10134,135 @@
#pragma GCC diagnostic pop
#endif
}
- if (v_not_animexts && v_not_netscape) {
- goto label_0_break;
- }
- {
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
- status = wuffs_base__suspension__short_read;
- goto suspend;
- }
- uint8_t t_2 = *iop_a_src++;
- v_block_size = t_2;
- }
- if (v_block_size != 3) {
- self->private_data.s_decode_ae[0].scratch = ((uint32_t)(v_block_size));
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(5);
- if (self->private_data.s_decode_ae[0].scratch >
- ((uint64_t)(io1_a_src - iop_a_src))) {
- self->private_data.s_decode_ae[0].scratch -=
- ((uint64_t)(io1_a_src - iop_a_src));
- iop_a_src = io1_a_src;
- status = wuffs_base__suspension__short_read;
- goto suspend;
- }
- iop_a_src += self->private_data.s_decode_ae[0].scratch;
- goto label_0_break;
- }
- {
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(6);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
- status = wuffs_base__suspension__short_read;
- goto suspend;
- }
- uint8_t t_3 = *iop_a_src++;
- v_c = t_3;
- }
- if (v_c != 1) {
- self->private_data.s_decode_ae[0].scratch = 2;
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(7);
- if (self->private_data.s_decode_ae[0].scratch >
- ((uint64_t)(io1_a_src - iop_a_src))) {
- self->private_data.s_decode_ae[0].scratch -=
- ((uint64_t)(io1_a_src - iop_a_src));
- iop_a_src = io1_a_src;
- status = wuffs_base__suspension__short_read;
- goto suspend;
- }
- iop_a_src += self->private_data.s_decode_ae[0].scratch;
- goto label_0_break;
- }
- {
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(8);
- uint32_t t_4;
- if (WUFFS_BASE__LIKELY(io1_a_src - iop_a_src >= 2)) {
- t_4 = ((uint32_t)(wuffs_base__load_u16le(iop_a_src)));
- iop_a_src += 2;
- } else {
- self->private_data.s_decode_ae[0].scratch = 0;
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(9);
- while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
- status = wuffs_base__suspension__short_read;
- goto suspend;
- }
- uint64_t* scratch = &self->private_data.s_decode_ae[0].scratch;
- uint32_t num_bits_4 = ((uint32_t)(*scratch >> 56));
- *scratch <<= 8;
- *scratch >>= 8;
- *scratch |= ((uint64_t)(*iop_a_src++)) << num_bits_4;
- if (num_bits_4 == 8) {
- t_4 = ((uint32_t)(*scratch));
- break;
- }
- num_bits_4 += 8;
- *scratch |= ((uint64_t)(num_bits_4)) << 56;
+ if (v_is_animexts || v_is_netscape) {
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+ status = wuffs_base__suspension__short_read;
+ goto suspend;
}
+ uint8_t t_2 = *iop_a_src++;
+ v_block_size = t_2;
}
- self->private_impl.f_num_loops = t_4;
- }
- self->private_impl.f_seen_num_loops = true;
- if ((0 < self->private_impl.f_num_loops) &&
- (self->private_impl.f_num_loops <= 65535)) {
- self->private_impl.f_num_loops += 1;
+ if (v_block_size != 3) {
+ self->private_data.s_decode_ae[0].scratch =
+ ((uint32_t)(v_block_size));
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(5);
+ if (self->private_data.s_decode_ae[0].scratch >
+ ((uint64_t)(io2_a_src - iop_a_src))) {
+ self->private_data.s_decode_ae[0].scratch -=
+ ((uint64_t)(io2_a_src - iop_a_src));
+ iop_a_src = io2_a_src;
+ status = wuffs_base__suspension__short_read;
+ goto suspend;
+ }
+ iop_a_src += self->private_data.s_decode_ae[0].scratch;
+ goto label_0_break;
+ }
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(6);
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+ status = wuffs_base__suspension__short_read;
+ goto suspend;
+ }
+ uint8_t t_3 = *iop_a_src++;
+ v_c = t_3;
+ }
+ if (v_c != 1) {
+ self->private_data.s_decode_ae[0].scratch = 2;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(7);
+ if (self->private_data.s_decode_ae[0].scratch >
+ ((uint64_t)(io2_a_src - iop_a_src))) {
+ self->private_data.s_decode_ae[0].scratch -=
+ ((uint64_t)(io2_a_src - iop_a_src));
+ iop_a_src = io2_a_src;
+ status = wuffs_base__suspension__short_read;
+ goto suspend;
+ }
+ iop_a_src += self->private_data.s_decode_ae[0].scratch;
+ goto label_0_break;
+ }
+ {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(8);
+ uint32_t t_4;
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 2)) {
+ t_4 = ((uint32_t)(wuffs_base__load_u16le(iop_a_src)));
+ iop_a_src += 2;
+ } else {
+ self->private_data.s_decode_ae[0].scratch = 0;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(9);
+ while (true) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
+ status = wuffs_base__suspension__short_read;
+ goto suspend;
+ }
+ uint64_t* scratch = &self->private_data.s_decode_ae[0].scratch;
+ uint32_t num_bits_4 = ((uint32_t)(*scratch >> 56));
+ *scratch <<= 8;
+ *scratch >>= 8;
+ *scratch |= ((uint64_t)(*iop_a_src++)) << num_bits_4;
+ if (num_bits_4 == 8) {
+ t_4 = ((uint32_t)(*scratch));
+ break;
+ }
+ num_bits_4 += 8;
+ *scratch |= ((uint64_t)(num_bits_4)) << 56;
+ }
+ }
+ self->private_impl.f_num_loops = t_4;
+ }
+ self->private_impl.f_seen_num_loops = true;
+ if ((0 < self->private_impl.f_num_loops) &&
+ (self->private_impl.f_num_loops <= 65535)) {
+ self->private_impl.f_num_loops += 1;
+ }
+ } else if (self->private_impl.f_ignore_metadata) {
+ } else if (v_is_iccp && self->private_impl.f_report_metadata_iccp) {
+ while (((uint64_t)(io2_a_src - iop_a_src)) <= 0) {
+ status = wuffs_base__suspension__short_read;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(10);
+ }
+ self->private_impl.f_metadata_chunk_length_value =
+ ((uint64_t)(wuffs_base__load_u8be(iop_a_src)));
+ (iop_a_src += 1, wuffs_base__make_empty_struct());
+ self->private_impl.f_metadata_fourcc_value = 1229144912;
+ self->private_impl.f_metadata_io_position = wuffs_base__u64__sat_add(
+ (a_src ? wuffs_base__u64__sat_add(
+ a_src->meta.pos,
+ ((uint64_t)(iop_a_src - a_src->data.ptr)))
+ : 0),
+ self->private_impl.f_metadata_chunk_length_value);
+ self->private_impl.f_call_sequence = 1;
+ status = wuffs_base__warning__metadata_reported;
+ goto ok;
+ } else if (v_is_xmp && self->private_impl.f_report_metadata_xmp) {
+ while (((uint64_t)(io2_a_src - iop_a_src)) <= 0) {
+ status = wuffs_base__suspension__short_read;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(11);
+ }
+ self->private_impl.f_metadata_chunk_length_value =
+ (((uint64_t)(wuffs_base__load_u8be(iop_a_src))) + 1);
+ self->private_impl.f_metadata_fourcc_value = 1481461792;
+ self->private_impl.f_metadata_io_position = wuffs_base__u64__sat_add(
+ (a_src ? wuffs_base__u64__sat_add(
+ a_src->meta.pos,
+ ((uint64_t)(iop_a_src - a_src->data.ptr)))
+ : 0),
+ self->private_impl.f_metadata_chunk_length_value);
+ self->private_impl.f_call_sequence = 1;
+ status = wuffs_base__warning__metadata_reported;
+ goto ok;
}
goto label_0_break;
}
label_0_break:;
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT(10);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(12);
status = wuffs_gif__decoder__skip_blocks(self, a_src);
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
}
if (status) {
goto suspend;
@@ -9791,16 +10276,18 @@
goto suspend;
suspend:
- self->private_impl.p_decode_ae[0] = coro_susp_point;
+ self->private_impl.p_decode_ae[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
self->private_data.s_decode_ae[0].v_block_size = v_block_size;
- self->private_data.s_decode_ae[0].v_not_animexts = v_not_animexts;
- self->private_data.s_decode_ae[0].v_not_netscape = v_not_netscape;
+ self->private_data.s_decode_ae[0].v_is_animexts = v_is_animexts;
+ self->private_data.s_decode_ae[0].v_is_netscape = v_is_netscape;
+ self->private_data.s_decode_ae[0].v_is_iccp = v_is_iccp;
+ self->private_data.s_decode_ae[0].v_is_xmp = v_is_xmp;
goto exit;
exit:
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return status;
@@ -9810,7 +10297,7 @@
static wuffs_base__status //
wuffs_gif__decoder__decode_gc(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_src) {
wuffs_base__status status = NULL;
uint8_t v_c = 0;
@@ -9820,16 +10307,12 @@
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_decode_gc[0];
@@ -9838,13 +10321,9 @@
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
- if (self->private_impl.f_seen_graphic_control) {
- status = wuffs_gif__error__bad_graphic_control;
- goto exit;
- }
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -9857,7 +10336,7 @@
}
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -9876,14 +10355,14 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
uint16_t t_2;
- if (WUFFS_BASE__LIKELY(io1_a_src - iop_a_src >= 2)) {
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 2)) {
t_2 = wuffs_base__load_u16le(iop_a_src);
iop_a_src += 2;
} else {
self->private_data.s_decode_gc[0].scratch = 0;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -9906,7 +10385,7 @@
(((uint64_t)(v_gc_duration_centiseconds)) * 7056000);
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(5);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -9915,7 +10394,7 @@
}
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(6);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -9926,7 +10405,6 @@
status = wuffs_gif__error__bad_graphic_control;
goto exit;
}
- self->private_impl.f_seen_graphic_control = true;
goto ok;
ok:
@@ -9936,13 +10414,13 @@
goto suspend;
suspend:
- self->private_impl.p_decode_gc[0] = coro_susp_point;
+ self->private_impl.p_decode_gc[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
goto exit;
exit:
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return status;
@@ -9952,22 +10430,18 @@
static wuffs_base__status //
wuffs_gif__decoder__decode_id_part0(wuffs_gif__decoder* self,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_src) {
wuffs_base__status status = NULL;
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_decode_id_part0[0];
@@ -9979,14 +10453,14 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
uint32_t t_0;
- if (WUFFS_BASE__LIKELY(io1_a_src - iop_a_src >= 2)) {
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 2)) {
t_0 = ((uint32_t)(wuffs_base__load_u16le(iop_a_src)));
iop_a_src += 2;
} else {
self->private_data.s_decode_id_part0[0].scratch = 0;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -10008,14 +10482,14 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
uint32_t t_1;
- if (WUFFS_BASE__LIKELY(io1_a_src - iop_a_src >= 2)) {
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 2)) {
t_1 = ((uint32_t)(wuffs_base__load_u16le(iop_a_src)));
iop_a_src += 2;
} else {
self->private_data.s_decode_id_part0[0].scratch = 0;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -10037,14 +10511,14 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(5);
uint32_t t_2;
- if (WUFFS_BASE__LIKELY(io1_a_src - iop_a_src >= 2)) {
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 2)) {
t_2 = ((uint32_t)(wuffs_base__load_u16le(iop_a_src)));
iop_a_src += 2;
} else {
self->private_data.s_decode_id_part0[0].scratch = 0;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(6);
while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -10067,14 +10541,14 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(7);
uint32_t t_3;
- if (WUFFS_BASE__LIKELY(io1_a_src - iop_a_src >= 2)) {
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 2)) {
t_3 = ((uint32_t)(wuffs_base__load_u16le(iop_a_src)));
iop_a_src += 2;
} else {
self->private_data.s_decode_id_part0[0].scratch = 0;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(8);
while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -10096,7 +10570,8 @@
self->private_impl.f_frame_rect_y1 += self->private_impl.f_frame_rect_y0;
self->private_impl.f_dst_x = self->private_impl.f_frame_rect_x0;
self->private_impl.f_dst_y = self->private_impl.f_frame_rect_y0;
- if (self->private_impl.f_call_sequence == 0) {
+ if ((self->private_impl.f_call_sequence == 0) &&
+ !self->private_impl.f_quirk_enabled_image_bounds_are_strict) {
self->private_impl.f_width = wuffs_base__u32__max(
self->private_impl.f_width, self->private_impl.f_frame_rect_x1);
self->private_impl.f_height = wuffs_base__u32__max(
@@ -10111,13 +10586,13 @@
goto suspend;
suspend:
- self->private_impl.p_decode_id_part0[0] = coro_susp_point;
+ self->private_impl.p_decode_id_part0[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
goto exit;
exit:
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return status;
@@ -10128,33 +10603,32 @@
static wuffs_base__status //
wuffs_gif__decoder__decode_id_part1(wuffs_gif__decoder* self,
wuffs_base__pixel_buffer* a_dst,
- wuffs_base__io_reader a_src) {
+ wuffs_base__io_buffer* a_src) {
wuffs_base__status status = NULL;
uint8_t v_flags = 0;
+ uint8_t v_which_palette = 0;
uint32_t v_num_palette_entries = 0;
uint32_t v_i = 0;
uint32_t v_argb = 0;
wuffs_base__slice_u8 v_dst_palette = {0};
+ wuffs_base__status v_status = NULL;
uint8_t v_lw = 0;
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_decode_id_part1[0];
if (coro_susp_point) {
+ v_which_palette = self->private_data.s_decode_id_part1[0].v_which_palette;
v_num_palette_entries =
self->private_data.s_decode_id_part1[0].v_num_palette_entries;
v_i = self->private_data.s_decode_id_part1[0].v_i;
@@ -10164,7 +10638,7 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -10176,7 +10650,7 @@
} else {
self->private_impl.f_interlace = 0;
}
- self->private_impl.f_which_palette = 1;
+ v_which_palette = 1;
if ((v_flags & 128) != 0) {
v_num_palette_entries = (((uint32_t)(1)) << (1 + (v_flags & 7)));
v_i = 0;
@@ -10184,14 +10658,14 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
uint32_t t_1;
- if (WUFFS_BASE__LIKELY(io1_a_src - iop_a_src >= 3)) {
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 3)) {
t_1 = ((uint32_t)(wuffs_base__load_u24be(iop_a_src)));
iop_a_src += 3;
} else {
self->private_data.s_decode_id_part1[0].scratch = 0;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -10229,12 +10703,16 @@
self->private_data.f_palettes[1][((4 * v_i) + 3)] = 255;
v_i += 1;
}
+ } else if (self->private_impl.f_quirk_enabled_reject_empty_palette &&
+ !self->private_impl.f_has_global_palette) {
+ status = wuffs_gif__error__bad_palette;
+ goto exit;
} else if (self->private_impl.f_gc_has_transparent_index) {
wuffs_base__slice_u8__copy_from_slice(
wuffs_base__make_slice_u8(self->private_data.f_palettes[1], 1024),
wuffs_base__make_slice_u8(self->private_data.f_palettes[0], 1024));
} else {
- self->private_impl.f_which_palette = 0;
+ v_which_palette = 0;
}
if (self->private_impl.f_gc_has_transparent_index) {
self->private_data.f_palettes[1][(
@@ -10255,13 +10733,22 @@
v_dst_palette =
wuffs_base__make_slice_u8(self->private_data.f_dst_palette, 1024);
}
- wuffs_base__pixel_swizzler__prepare(
+ v_status = wuffs_base__pixel_swizzler__prepare(
&self->private_impl.f_swizzler,
wuffs_base__pixel_buffer__pixel_format(a_dst), v_dst_palette,
1191444488,
wuffs_base__make_slice_u8(
- self->private_data.f_palettes[self->private_impl.f_which_palette],
- 1024));
+ self->private_data.f_palettes[v_which_palette], 1024));
+ if (!wuffs_base__status__is_ok(v_status)) {
+ status = v_status;
+ if (wuffs_base__status__is_error(status)) {
+ goto exit;
+ } else if (wuffs_base__status__is_suspension(status)) {
+ status = wuffs_base__error__cannot_return_a_suspension;
+ goto exit;
+ }
+ goto ok;
+ }
if (self->private_impl.f_previous_lzw_decode_ended_abruptly) {
wuffs_base__ignore_status(wuffs_lzw__decoder__initialize(
&self->private_data.f_lzw, sizeof(wuffs_lzw__decoder), WUFFS_VERSION,
@@ -10269,14 +10756,14 @@
}
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
uint8_t t_2 = *iop_a_src++;
v_lw = t_2;
}
- if ((v_lw < 2) || (8 < v_lw)) {
+ if (v_lw > 8) {
status = wuffs_gif__error__bad_literal_width;
goto exit;
}
@@ -10292,16 +10779,17 @@
goto suspend;
suspend:
- self->private_impl.p_decode_id_part1[0] = coro_susp_point;
+ self->private_impl.p_decode_id_part1[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
+ self->private_data.s_decode_id_part1[0].v_which_palette = v_which_palette;
self->private_data.s_decode_id_part1[0].v_num_palette_entries =
v_num_palette_entries;
self->private_data.s_decode_id_part1[0].v_i = v_i;
goto exit;
exit:
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return status;
@@ -10312,7 +10800,7 @@
static wuffs_base__status //
wuffs_gif__decoder__decode_id_part2(wuffs_gif__decoder* self,
wuffs_base__pixel_buffer* a_dst,
- wuffs_base__io_reader a_src,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf) {
wuffs_base__status status = NULL;
@@ -10320,11 +10808,13 @@
bool v_need_block_size = false;
uint64_t v_n_compressed = 0;
wuffs_base__slice_u8 v_compressed = {0};
- wuffs_base__io_reader v_r = wuffs_base__null_io_reader();
- wuffs_base__io_buffer u_r WUFFS_BASE__POTENTIALLY_UNUSED =
- wuffs_base__null_io_buffer();
+ wuffs_base__io_buffer u_r = wuffs_base__null_io_buffer();
+ wuffs_base__io_buffer* v_r = &u_r;
uint8_t* iop_v_r WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ uint8_t* io0_v_r WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_v_r WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ uint8_t* io2_v_r WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ uint64_t v_mark = 0;
wuffs_base__status v_lzw_status = NULL;
wuffs_base__status v_copy_status = NULL;
wuffs_base__slice_u8 v_uncompressed = {0};
@@ -10332,16 +10822,12 @@
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_decode_id_part2[0];
@@ -10361,7 +10847,7 @@
v_need_block_size = false;
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -10372,7 +10858,7 @@
if (v_block_size == 0) {
goto label_0_break;
}
- while (((uint64_t)(io1_a_src - iop_a_src)) == 0) {
+ while (((uint64_t)(io2_a_src - iop_a_src)) == 0) {
status = wuffs_base__suspension__short_read;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(2);
}
@@ -10383,12 +10869,12 @@
}
while (self->private_impl.f_compressed_wi <= 3841) {
v_n_compressed = wuffs_base__u64__min(
- v_block_size, ((uint64_t)(io1_a_src - iop_a_src)));
+ v_block_size, ((uint64_t)(io2_a_src - iop_a_src)));
if (v_n_compressed <= 0) {
goto label_1_break;
}
v_compressed =
- wuffs_base__io_reader__take(&iop_a_src, io1_a_src, v_n_compressed);
+ wuffs_base__io_reader__take(&iop_a_src, io2_a_src, v_n_compressed);
wuffs_base__slice_u8__copy_from_slice(
wuffs_base__slice_u8__subslice_i(
wuffs_base__make_slice_u8(self->private_data.f_compressed,
@@ -10401,7 +10887,7 @@
if (v_block_size > 0) {
goto label_1_break;
}
- if (((uint64_t)(io1_a_src - iop_a_src)) <= 0) {
+ if (((uint64_t)(io2_a_src - iop_a_src)) <= 0) {
v_need_block_size = true;
goto label_1_break;
}
@@ -10422,16 +10908,19 @@
goto exit;
}
{
- wuffs_base__io_reader o_0_v_r = v_r;
+ wuffs_base__io_buffer* o_0_v_r = v_r;
uint8_t* o_0_iop_v_r = iop_v_r;
+ uint8_t* o_0_io0_v_r = io0_v_r;
uint8_t* o_0_io1_v_r = io1_v_r;
- wuffs_base__io_reader__set(
- &v_r, &u_r, &iop_v_r, &io1_v_r,
+ uint8_t* o_0_io2_v_r = io2_v_r;
+ v_r = wuffs_base__io_reader__set(
+ &u_r, &iop_v_r, &io0_v_r, &io1_v_r, &io2_v_r,
wuffs_base__slice_u8__subslice_ij(
wuffs_base__make_slice_u8(self->private_data.f_compressed,
4096),
self->private_impl.f_compressed_ri,
self->private_impl.f_compressed_wi));
+ v_mark = ((uint64_t)(iop_v_r - io0_v_r));
{
u_r.meta.ri = ((size_t)(iop_v_r - u_r.data.ptr));
wuffs_base__status t_1 = wuffs_lzw__decoder__decode_io_writer(
@@ -10443,10 +10932,13 @@
}
wuffs_base__u64__sat_add_indirect(
&self->private_impl.f_compressed_ri,
- ((uint64_t)(iop_v_r - v_r.private_impl.mark)));
+ wuffs_base__io__count_since(v_mark,
+ ((uint64_t)(iop_v_r - io0_v_r))));
v_r = o_0_v_r;
iop_v_r = o_0_iop_v_r;
+ io0_v_r = o_0_io0_v_r;
io1_v_r = o_0_io1_v_r;
+ io2_v_r = o_0_io2_v_r;
}
v_uncompressed = wuffs_lzw__decoder__flush(&self->private_data.f_lzw);
if (((uint64_t)(v_uncompressed.len)) > 0) {
@@ -10464,23 +10956,21 @@
((uint32_t)(v_block_size));
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
if (self->private_data.s_decode_id_part2[0].scratch >
- ((uint64_t)(io1_a_src - iop_a_src))) {
+ ((uint64_t)(io2_a_src - iop_a_src))) {
self->private_data.s_decode_id_part2[0].scratch -=
- ((uint64_t)(io1_a_src - iop_a_src));
- iop_a_src = io1_a_src;
+ ((uint64_t)(io2_a_src - iop_a_src));
+ iop_a_src = io2_a_src;
status = wuffs_base__suspension__short_read;
goto suspend;
}
iop_a_src += self->private_data.s_decode_id_part2[0].scratch;
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
status = wuffs_gif__decoder__skip_blocks(self, a_src);
- if (a_src.private_impl.buf) {
- iop_a_src = a_src.private_impl.buf->data.ptr +
- a_src.private_impl.buf->meta.ri;
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
}
if (status) {
goto suspend;
@@ -10522,16 +11012,16 @@
goto suspend;
suspend:
- self->private_impl.p_decode_id_part2[0] = coro_susp_point;
+ self->private_impl.p_decode_id_part2[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
self->private_data.s_decode_id_part2[0].v_block_size = v_block_size;
self->private_data.s_decode_id_part2[0].v_need_block_size = v_need_block_size;
self->private_data.s_decode_id_part2[0].v_lzw_status = v_lzw_status;
goto exit;
exit:
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
return status;
@@ -10548,23 +11038,29 @@
uint64_t v_n = 0;
uint64_t v_src_ri = 0;
uint32_t v_bytes_per_pixel = 0;
- uint32_t v_pixfmt = 0;
+ uint32_t v_pixfmt_channels = 0;
wuffs_base__table_u8 v_tab = {0};
uint64_t v_i = 0;
uint64_t v_j = 0;
- v_bytes_per_pixel = 1;
- v_pixfmt = wuffs_base__pixel_buffer__pixel_format(a_pb);
- if ((v_pixfmt == 1157662856) || (v_pixfmt == 1426098312) ||
- (v_pixfmt == 1174440072) || (v_pixfmt == 1442875528) ||
- (v_pixfmt == 1191217288) || (v_pixfmt == 1459652744)) {
+ v_pixfmt_channels = (wuffs_base__pixel_buffer__pixel_format(a_pb) & 65535);
+ if (v_pixfmt_channels == 34952) {
v_bytes_per_pixel = 4;
+ } else if (v_pixfmt_channels == 2184) {
+ v_bytes_per_pixel = 3;
+ } else if (v_pixfmt_channels == 8) {
+ v_bytes_per_pixel = 1;
+ } else {
+ return wuffs_base__error__unsupported_option;
}
v_tab = wuffs_base__pixel_buffer__plane(a_pb, 0);
label_0_continue:;
while (v_src_ri < ((uint64_t)(a_src.len))) {
v_src = wuffs_base__slice_u8__subslice_i(a_src, v_src_ri);
if (self->private_impl.f_dst_y >= self->private_impl.f_frame_rect_y1) {
+ if (self->private_impl.f_quirk_enabled_ignore_too_much_pixel_data) {
+ return NULL;
+ }
return wuffs_base__error__too_much_data;
}
v_dst = wuffs_base__table_u8__row(v_tab, self->private_impl.f_dst_y);
@@ -10578,7 +11074,7 @@
} else {
v_dst = wuffs_base__slice_u8__subslice_i(v_dst, v_i);
}
- v_n = wuffs_base__pixel_swizzler__swizzle_packed(
+ v_n = wuffs_base__pixel_swizzler__swizzle_interleaved(
&self->private_impl.f_swizzler, v_dst,
wuffs_base__make_slice_u8(self->private_data.f_dst_palette, 1024),
v_src);
@@ -10779,8 +11275,8 @@
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
wuffs_gzip__decoder__decode_io_writer(wuffs_gzip__decoder* self,
- wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src,
+ wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf) {
if (!self) {
return wuffs_base__error__bad_receiver;
@@ -10790,6 +11286,10 @@
? wuffs_base__error__disabled_by_previous_error
: wuffs_base__error__initialize_not_called;
}
+ if (!a_dst || !a_src) {
+ self->private_impl.magic = WUFFS_BASE__DISABLED;
+ return wuffs_base__error__bad_argument;
+ }
if ((self->private_impl.active_coroutine != 0) &&
(self->private_impl.active_coroutine != 1)) {
self->private_impl.magic = WUFFS_BASE__DISABLED;
@@ -10801,6 +11301,7 @@
uint8_t v_c = 0;
uint8_t v_flags = 0;
uint16_t v_xlen = 0;
+ uint64_t v_mark = 0;
uint32_t v_checksum_got = 0;
uint32_t v_decoded_length_got = 0;
wuffs_base__status v_status = NULL;
@@ -10810,33 +11311,25 @@
uint8_t* iop_a_dst = NULL;
uint8_t* io0_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_dst.private_impl.buf) {
- iop_a_dst =
- a_dst.private_impl.buf->data.ptr + a_dst.private_impl.buf->meta.wi;
- if (!a_dst.private_impl.mark) {
- a_dst.private_impl.mark = iop_a_dst;
- a_dst.private_impl.limit =
- a_dst.private_impl.buf->data.ptr + a_dst.private_impl.buf->data.len;
+ uint8_t* io2_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_dst) {
+ io0_a_dst = a_dst->data.ptr;
+ io1_a_dst = io0_a_dst + a_dst->meta.wi;
+ iop_a_dst = io1_a_dst;
+ io2_a_dst = io0_a_dst + a_dst->data.len;
+ if (a_dst->meta.closed) {
+ io2_a_dst = iop_a_dst;
}
- if (a_dst.private_impl.buf->meta.closed) {
- a_dst.private_impl.limit = iop_a_dst;
- }
- io0_a_dst = a_dst.private_impl.mark;
- io1_a_dst = a_dst.private_impl.limit;
}
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_decode_io_writer[0];
@@ -10852,7 +11345,7 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -10865,7 +11358,7 @@
}
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -10878,7 +11371,7 @@
}
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(3);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -10891,7 +11384,7 @@
}
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -10901,10 +11394,10 @@
self->private_data.s_decode_io_writer[0].scratch = 6;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(5);
if (self->private_data.s_decode_io_writer[0].scratch >
- ((uint64_t)(io1_a_src - iop_a_src))) {
+ ((uint64_t)(io2_a_src - iop_a_src))) {
self->private_data.s_decode_io_writer[0].scratch -=
- ((uint64_t)(io1_a_src - iop_a_src));
- iop_a_src = io1_a_src;
+ ((uint64_t)(io2_a_src - iop_a_src));
+ iop_a_src = io2_a_src;
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -10913,14 +11406,14 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(6);
uint16_t t_4;
- if (WUFFS_BASE__LIKELY(io1_a_src - iop_a_src >= 2)) {
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 2)) {
t_4 = wuffs_base__load_u16le(iop_a_src);
iop_a_src += 2;
} else {
self->private_data.s_decode_io_writer[0].scratch = 0;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(7);
while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -10943,10 +11436,10 @@
self->private_data.s_decode_io_writer[0].scratch = ((uint32_t)(v_xlen));
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(8);
if (self->private_data.s_decode_io_writer[0].scratch >
- ((uint64_t)(io1_a_src - iop_a_src))) {
+ ((uint64_t)(io2_a_src - iop_a_src))) {
self->private_data.s_decode_io_writer[0].scratch -=
- ((uint64_t)(io1_a_src - iop_a_src));
- iop_a_src = io1_a_src;
+ ((uint64_t)(io2_a_src - iop_a_src));
+ iop_a_src = io2_a_src;
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -10956,7 +11449,7 @@
while (true) {
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(9);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -10973,7 +11466,7 @@
while (true) {
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(10);
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -10990,10 +11483,10 @@
self->private_data.s_decode_io_writer[0].scratch = 2;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(11);
if (self->private_data.s_decode_io_writer[0].scratch >
- ((uint64_t)(io1_a_src - iop_a_src))) {
+ ((uint64_t)(io2_a_src - iop_a_src))) {
self->private_data.s_decode_io_writer[0].scratch -=
- ((uint64_t)(io1_a_src - iop_a_src));
- iop_a_src = io1_a_src;
+ ((uint64_t)(io2_a_src - iop_a_src));
+ iop_a_src = io2_a_src;
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -11004,36 +11497,33 @@
goto exit;
}
while (true) {
- wuffs_base__io_writer__set_mark(&a_dst, iop_a_dst);
+ v_mark = ((uint64_t)(iop_a_dst - io0_a_dst));
{
- if (a_dst.private_impl.buf) {
- a_dst.private_impl.buf->meta.wi =
- ((size_t)(iop_a_dst - a_dst.private_impl.buf->data.ptr));
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
}
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
wuffs_base__status t_7 = wuffs_deflate__decoder__decode_io_writer(
&self->private_data.f_flate, a_dst, a_src, a_workbuf);
- if (a_dst.private_impl.buf) {
- iop_a_dst = a_dst.private_impl.buf->data.ptr +
- a_dst.private_impl.buf->meta.wi;
+ if (a_dst) {
+ iop_a_dst = a_dst->data.ptr + a_dst->meta.wi;
}
- if (a_src.private_impl.buf) {
- iop_a_src = a_src.private_impl.buf->data.ptr +
- a_src.private_impl.buf->meta.ri;
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
}
v_status = t_7;
}
if (!self->private_impl.f_ignore_checksum) {
v_checksum_got = wuffs_crc32__ieee_hasher__update(
&self->private_data.f_checksum,
- wuffs_base__make_slice_u8(
- a_dst.private_impl.mark,
- (size_t)(iop_a_dst - a_dst.private_impl.mark)));
- v_decoded_length_got += ((uint32_t)(
- (((uint64_t)(iop_a_dst - a_dst.private_impl.mark)) & 4294967295)));
+ wuffs_base__io__since(v_mark, ((uint64_t)(iop_a_dst - io0_a_dst)),
+ io0_a_dst));
+ v_decoded_length_got +=
+ ((uint32_t)((wuffs_base__io__count_since(
+ v_mark, ((uint64_t)(iop_a_dst - io0_a_dst))) &
+ 4294967295)));
}
if (wuffs_base__status__is_ok(v_status)) {
goto label_2_break;
@@ -11045,14 +11535,14 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(13);
uint32_t t_8;
- if (WUFFS_BASE__LIKELY(io1_a_src - iop_a_src >= 4)) {
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 4)) {
t_8 = wuffs_base__load_u32le(iop_a_src);
iop_a_src += 4;
} else {
self->private_data.s_decode_io_writer[0].scratch = 0;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(14);
while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -11074,14 +11564,14 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(15);
uint32_t t_9;
- if (WUFFS_BASE__LIKELY(io1_a_src - iop_a_src >= 4)) {
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 4)) {
t_9 = wuffs_base__load_u32le(iop_a_src);
iop_a_src += 4;
} else {
self->private_data.s_decode_io_writer[0].scratch = 0;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(16);
while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -11115,8 +11605,10 @@
goto suspend;
suspend:
- self->private_impl.p_decode_io_writer[0] = coro_susp_point;
- self->private_impl.active_coroutine = 1;
+ self->private_impl.p_decode_io_writer[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
+ self->private_impl.active_coroutine =
+ wuffs_base__status__is_suspension(status) ? 1 : 0;
self->private_data.s_decode_io_writer[0].v_flags = v_flags;
self->private_data.s_decode_io_writer[0].v_checksum_got = v_checksum_got;
self->private_data.s_decode_io_writer[0].v_decoded_length_got =
@@ -11125,13 +11617,11 @@
goto exit;
exit:
- if (a_dst.private_impl.buf) {
- a_dst.private_impl.buf->meta.wi =
- ((size_t)(iop_a_dst - a_dst.private_impl.buf->data.ptr));
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
}
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
if (wuffs_base__status__is_error(status)) {
@@ -11266,8 +11756,8 @@
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
wuffs_zlib__decoder__decode_io_writer(wuffs_zlib__decoder* self,
- wuffs_base__io_writer a_dst,
- wuffs_base__io_reader a_src,
+ wuffs_base__io_buffer* a_dst,
+ wuffs_base__io_buffer* a_src,
wuffs_base__slice_u8 a_workbuf) {
if (!self) {
return wuffs_base__error__bad_receiver;
@@ -11277,6 +11767,10 @@
? wuffs_base__error__disabled_by_previous_error
: wuffs_base__error__initialize_not_called;
}
+ if (!a_dst || !a_src) {
+ self->private_impl.magic = WUFFS_BASE__DISABLED;
+ return wuffs_base__error__bad_argument;
+ }
if ((self->private_impl.active_coroutine != 0) &&
(self->private_impl.active_coroutine != 1)) {
self->private_impl.magic = WUFFS_BASE__DISABLED;
@@ -11289,37 +11783,30 @@
uint32_t v_checksum_got = 0;
wuffs_base__status v_status = NULL;
uint32_t v_checksum_want = 0;
+ uint64_t v_mark = 0;
uint8_t* iop_a_dst = NULL;
uint8_t* io0_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_dst.private_impl.buf) {
- iop_a_dst =
- a_dst.private_impl.buf->data.ptr + a_dst.private_impl.buf->meta.wi;
- if (!a_dst.private_impl.mark) {
- a_dst.private_impl.mark = iop_a_dst;
- a_dst.private_impl.limit =
- a_dst.private_impl.buf->data.ptr + a_dst.private_impl.buf->data.len;
+ uint8_t* io2_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_dst) {
+ io0_a_dst = a_dst->data.ptr;
+ io1_a_dst = io0_a_dst + a_dst->meta.wi;
+ iop_a_dst = io1_a_dst;
+ io2_a_dst = io0_a_dst + a_dst->data.len;
+ if (a_dst->meta.closed) {
+ io2_a_dst = iop_a_dst;
}
- if (a_dst.private_impl.buf->meta.closed) {
- a_dst.private_impl.limit = iop_a_dst;
- }
- io0_a_dst = a_dst.private_impl.mark;
- io1_a_dst = a_dst.private_impl.limit;
}
uint8_t* iop_a_src = NULL;
uint8_t* io0_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
uint8_t* io1_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
- if (a_src.private_impl.buf) {
- iop_a_src =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.ri;
- if (!a_src.private_impl.mark) {
- a_src.private_impl.mark = iop_a_src;
- a_src.private_impl.limit =
- a_src.private_impl.buf->data.ptr + a_src.private_impl.buf->meta.wi;
- }
- io0_a_src = a_src.private_impl.mark;
- io1_a_src = a_src.private_impl.limit;
+ uint8_t* io2_a_src WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ if (a_src) {
+ io0_a_src = a_src->data.ptr;
+ io1_a_src = io0_a_src + a_src->meta.ri;
+ iop_a_src = io1_a_src;
+ io2_a_src = io0_a_src + a_src->meta.wi;
}
uint32_t coro_susp_point = self->private_impl.p_decode_io_writer[0];
@@ -11332,14 +11819,14 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
uint16_t t_0;
- if (WUFFS_BASE__LIKELY(io1_a_src - iop_a_src >= 2)) {
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 2)) {
t_0 = wuffs_base__load_u16be(iop_a_src);
iop_a_src += 2;
} else {
self->private_data.s_decode_io_writer[0].scratch = 0;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(2);
while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -11375,34 +11862,29 @@
goto exit;
}
while (true) {
- wuffs_base__io_writer__set_mark(&a_dst, iop_a_dst);
+ v_mark = ((uint64_t)(iop_a_dst - io0_a_dst));
{
- if (a_dst.private_impl.buf) {
- a_dst.private_impl.buf->meta.wi =
- ((size_t)(iop_a_dst - a_dst.private_impl.buf->data.ptr));
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
}
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
wuffs_base__status t_1 = wuffs_deflate__decoder__decode_io_writer(
&self->private_data.f_flate, a_dst, a_src, a_workbuf);
- if (a_dst.private_impl.buf) {
- iop_a_dst = a_dst.private_impl.buf->data.ptr +
- a_dst.private_impl.buf->meta.wi;
+ if (a_dst) {
+ iop_a_dst = a_dst->data.ptr + a_dst->meta.wi;
}
- if (a_src.private_impl.buf) {
- iop_a_src = a_src.private_impl.buf->data.ptr +
- a_src.private_impl.buf->meta.ri;
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
}
v_status = t_1;
}
if (!self->private_impl.f_ignore_checksum) {
v_checksum_got = wuffs_adler32__hasher__update(
&self->private_data.f_checksum,
- wuffs_base__make_slice_u8(
- a_dst.private_impl.mark,
- (size_t)(iop_a_dst - a_dst.private_impl.mark)));
+ wuffs_base__io__since(v_mark, ((uint64_t)(iop_a_dst - io0_a_dst)),
+ io0_a_dst));
}
if (wuffs_base__status__is_ok(v_status)) {
goto label_0_break;
@@ -11414,14 +11896,14 @@
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(4);
uint32_t t_2;
- if (WUFFS_BASE__LIKELY(io1_a_src - iop_a_src >= 4)) {
+ if (WUFFS_BASE__LIKELY(io2_a_src - iop_a_src >= 4)) {
t_2 = wuffs_base__load_u32be(iop_a_src);
iop_a_src += 4;
} else {
self->private_data.s_decode_io_writer[0].scratch = 0;
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(5);
while (true) {
- if (WUFFS_BASE__UNLIKELY(iop_a_src == io1_a_src)) {
+ if (WUFFS_BASE__UNLIKELY(iop_a_src == io2_a_src)) {
status = wuffs_base__suspension__short_read;
goto suspend;
}
@@ -11454,19 +11936,19 @@
goto suspend;
suspend:
- self->private_impl.p_decode_io_writer[0] = coro_susp_point;
- self->private_impl.active_coroutine = 1;
+ self->private_impl.p_decode_io_writer[0] =
+ wuffs_base__status__is_suspension(status) ? coro_susp_point : 0;
+ self->private_impl.active_coroutine =
+ wuffs_base__status__is_suspension(status) ? 1 : 0;
self->private_data.s_decode_io_writer[0].v_checksum_got = v_checksum_got;
goto exit;
exit:
- if (a_dst.private_impl.buf) {
- a_dst.private_impl.buf->meta.wi =
- ((size_t)(iop_a_dst - a_dst.private_impl.buf->data.ptr));
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
}
- if (a_src.private_impl.buf) {
- a_src.private_impl.buf->meta.ri =
- ((size_t)(iop_a_src - a_src.private_impl.buf->data.ptr));
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
if (wuffs_base__status__is_error(status)) {
diff --git a/script/make-artificial.go b/script/make-artificial.go
index d436b99..23d37bb 100644
--- a/script/make-artificial.go
+++ b/script/make-artificial.go
@@ -118,6 +118,15 @@
}
}
+ if state == nil {
+ return fmt.Errorf("no 'make' line")
+ } else {
+ state, err = state("")
+ if err != nil {
+ return err
+ }
+ }
+
_, err = os.Stdout.Write(out)
return err
}
@@ -224,22 +233,189 @@
formats["deflate"] = stateDeflate
}
+var deflateCodeOrder = [19]uint32{
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15,
+}
+
+type deflateHuffmanTable map[uint32]string
+
var deflateGlobals struct {
bncData []byte
stream deflateBitStream
+
+ // Dynamic Huffman state.
+ numLCodes uint32
+ numDCodes uint32
+ numCLCodeLengths uint32
+ whichHuffman uint32
+ // 0=Unused, 1=CodeLength, 2=Length/Literal, 3=Distance.
+ huffmans [4]deflateHuffmanTable
+}
+
+func deflateGlobalsClearDynamicHuffmanState() {
+ deflateGlobals.numLCodes = 0
+ deflateGlobals.numDCodes = 0
+ deflateGlobals.numCLCodeLengths = 0
+ deflateGlobals.whichHuffman = 0
+ deflateGlobals.huffmans = [4]deflateHuffmanTable{}
+}
+
+func deflateGlobalsWriteDynamicHuffmanTables() error {
+ g := &deflateGlobals
+ if (g.numLCodes < 257) || (257+31 < g.numLCodes) {
+ return fmt.Errorf("bad numLCodes: %d", g.numLCodes)
+ }
+ g.stream.writeBits(g.numLCodes-257, 5)
+ if (g.numDCodes < 1) || (1+31 < g.numDCodes) {
+ return fmt.Errorf("bad numDCodes: %d", g.numDCodes)
+ }
+ g.stream.writeBits(g.numDCodes-1, 5)
+ if (g.numCLCodeLengths < 4) || (4+15 < g.numCLCodeLengths) {
+ return fmt.Errorf("bad numCLCodeLengths: %d", g.numCLCodeLengths)
+ }
+ g.stream.writeBits(g.numCLCodeLengths-4, 4)
+
+ // Write the Huffman table for CodeLength.
+ {
+ for i := uint32(0); i < g.numCLCodeLengths; i++ {
+ n := len(g.huffmans[1][deflateCodeOrder[i]])
+ g.stream.writeBits(uint32(n), 3)
+ }
+ for i := g.numCLCodeLengths; i < uint32(len(deflateCodeOrder)); i++ {
+ n := len(g.huffmans[1][deflateCodeOrder[i]])
+ if n > 0 {
+ return fmt.Errorf("short numCLCodeLengths: %d", g.numCLCodeLengths)
+ }
+ }
+ }
+
+ // Write the Huffman tables for Length/Literal and Distance.
+ {
+ numZeroes := uint32(0)
+ for i := uint32(0); i < g.numLCodes+g.numDCodes; i++ {
+ s := ""
+ if i < g.numLCodes {
+ s = g.huffmans[2][i]
+ } else {
+ s = g.huffmans[3][i-g.numLCodes]
+ }
+ if s == "" {
+ numZeroes++
+ continue
+ }
+
+ if err := deflateGlobalsWriteDynamicHuffmanZeroes(numZeroes); err != nil {
+ return err
+ }
+ numZeroes = 0
+
+ deflateGlobalsWriteDynamicHuffmanBits(g.huffmans[1][uint32(len(s))])
+ }
+ if err := deflateGlobalsWriteDynamicHuffmanZeroes(numZeroes); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func deflateGlobalsWriteDynamicHuffmanZeroes(numZeroes uint32) error {
+ g := &deflateGlobals
+ if numZeroes == 0 {
+ return nil
+ }
+
+ if s := g.huffmans[1][18]; s != "" {
+ for numZeroes >= 11 {
+ extra := numZeroes - 11
+ if extra > 127 {
+ extra = 127
+ }
+ deflateGlobalsWriteDynamicHuffmanBits(s)
+ g.stream.writeBits(extra, 7)
+ numZeroes -= 11 + extra
+ }
+ }
+
+ if s := g.huffmans[1][17]; s != "" {
+ for numZeroes >= 3 {
+ extra := numZeroes - 3
+ if extra > 7 {
+ extra = 7
+ }
+ deflateGlobalsWriteDynamicHuffmanBits(s)
+ g.stream.writeBits(extra, 3)
+ numZeroes -= 3 + extra
+ }
+ }
+
+ if s := g.huffmans[1][0]; s != "" {
+ for ; numZeroes > 0; numZeroes-- {
+ deflateGlobalsWriteDynamicHuffmanBits(s)
+ }
+ }
+
+ if numZeroes > 0 {
+ return fmt.Errorf("could not write a run of zero-valued code lengths")
+ }
+ return nil
+}
+
+func deflateGlobalsWriteDynamicHuffmanBits(s string) {
+ g := &deflateGlobals
+ for i := 0; i < len(s); i++ {
+ g.stream.writeBits(uint32(s[i]&1), 1)
+ }
+}
+
+func parseDeflateWhichHuffman(s string) (num uint32, remaining string, ok bool) {
+ if i := strings.IndexByte(s, ' '); i >= 0 {
+ s, remaining = s[:i], s[i+1:]
+ for len(remaining) > 0 && remaining[0] == ' ' {
+ remaining = remaining[1:]
+ }
+ }
+
+ switch s {
+ case "CodeLength":
+ return 1, remaining, true
+ case "Length/Literal":
+ return 2, remaining, true
+ case "Distance":
+ return 3, remaining, true
+ }
+ return 0, "", false
}
func stateDeflate(line string) (stateFunc, error) {
g := &deflateGlobals
const (
- cmdBNC = "blockNoCompression "
+ cmdB = "bytes "
+ cmdBDH = "blockDynamicHuffman "
cmdBFH = "blockFixedHuffman "
+ cmdBNC = "blockNoCompression "
)
bits := uint32(0)
s := ""
retState := stateFunc(nil)
switch {
+ case line == "":
+ g.stream.flush()
+ return stateDeflate, nil
+
+ case strings.HasPrefix(line, cmdB):
+ s := line[len(cmdB):]
+ for s != "" {
+ x, ok := uint32(0), false
+ x, s, ok = parseHex(s)
+ if !ok {
+ return nil, fmt.Errorf("bad stateDeflate command: %q", line)
+ }
+ out = append(out, uint8(x))
+ }
+ return stateDeflate, nil
+
case strings.HasPrefix(line, cmdBNC):
s = line[len(cmdBNC):]
retState = stateDeflateNoCompression
@@ -248,6 +424,10 @@
s = line[len(cmdBFH):]
retState = stateDeflateFixedHuffman
bits |= 1 << 1
+ case strings.HasPrefix(line, cmdBDH):
+ s = line[len(cmdBDH):]
+ retState = stateDeflateDynamicHuffman
+ bits |= 2 << 1
default:
return nil, fmt.Errorf("bad stateDeflate command: %q", line)
}
@@ -291,7 +471,6 @@
func stateDeflateFixedHuffman(line string) (stateFunc, error) {
g := &deflateGlobals
if line == "}" {
- g.stream.flush()
return stateDeflate, nil
}
@@ -301,16 +480,15 @@
}
if lit, ok := deflateParseLiteral(line); ok {
- // TODO: support "\xAB" escape codes in the script?
for i := 0; i < len(lit); i++ {
- g.stream.writeLCode(uint32(lit[i]))
+ g.stream.writeFixedHuffmanLCode(uint32(lit[i]))
}
return stateDeflateFixedHuffman, nil
}
if line == "len 3 distCode 31" {
lCode, lExtra, lNExtra := deflateEncodeLength(3)
- g.stream.writeLCode(lCode)
+ g.stream.writeFixedHuffmanLCode(lCode)
g.stream.writeBits(lExtra, lNExtra)
dCode, dExtra, dNExtra := uint32(31), uint32(0), uint32(0)
g.stream.writeBits(reverse(dCode, 5), 5)
@@ -320,7 +498,7 @@
if l, d, ok := deflateParseLenDist(line); ok {
lCode, lExtra, lNExtra := deflateEncodeLength(l)
- g.stream.writeLCode(lCode)
+ g.stream.writeFixedHuffmanLCode(lCode)
g.stream.writeBits(lExtra, lNExtra)
dCode, dExtra, dNExtra := deflateEncodeDistance(d)
g.stream.writeBits(reverse(dCode, 5), 5)
@@ -331,6 +509,120 @@
return nil, fmt.Errorf("bad stateDeflateFixedHuffman command: %q", line)
}
+func stateDeflateDynamicHuffman(line string) (stateFunc, error) {
+ g := &deflateGlobals
+ const (
+ cmdH = "huffman "
+ cmdNCLCL = "numCLCodeLengths "
+ cmdNDC = "numDCodes "
+ cmdNLC = "numLCodes "
+ )
+ switch {
+ case line == "}":
+ deflateGlobalsClearDynamicHuffmanState()
+ return stateDeflate, nil
+
+ case strings.HasPrefix(line, cmdH):
+ s := line[len(cmdH):]
+ n, s, ok := parseDeflateWhichHuffman(s)
+ if !ok {
+ break
+ }
+ g.whichHuffman = n
+ return stateDeflateDynamicHuffmanHuffman, nil
+
+ case strings.HasPrefix(line, cmdNLC):
+ s := line[len(cmdNLC):]
+ n, s, ok := parseNum(s)
+ if !ok {
+ break
+ }
+ g.numLCodes = n
+ return stateDeflateDynamicHuffman, nil
+
+ case strings.HasPrefix(line, cmdNDC):
+ s := line[len(cmdNDC):]
+ n, s, ok := parseNum(s)
+ if !ok {
+ break
+ }
+ g.numDCodes = n
+ return stateDeflateDynamicHuffman, nil
+
+ case strings.HasPrefix(line, cmdNCLCL):
+ s := line[len(cmdNCLCL):]
+ n, s, ok := parseNum(s)
+ if !ok {
+ break
+ }
+ g.numCLCodeLengths = n
+ return stateDeflateDynamicHuffman, nil
+ }
+
+ if lit, ok := deflateParseLiteral(line); ok {
+ for i := 0; i < len(lit); i++ {
+ s := g.huffmans[2][uint32(lit[i])]
+ if s == "" {
+ return nil, fmt.Errorf("no code for literal %q (%d)", lit[i:i+1], lit[i])
+ }
+ deflateGlobalsWriteDynamicHuffmanBits(s)
+ }
+ return stateDeflateDynamicHuffman, nil
+ } else if line == "endOfBlock" {
+ s := g.huffmans[2][256]
+ if s == "" {
+ return nil, fmt.Errorf("no code for end-of-block (256)")
+ }
+ deflateGlobalsWriteDynamicHuffmanBits(s)
+ return stateDeflateDynamicHuffman, nil
+ }
+
+ return nil, fmt.Errorf("bad stateDeflateDynamicHuffman command: %q", line)
+}
+
+func stateDeflateDynamicHuffmanHuffman(line string) (stateFunc, error) {
+ g := &deflateGlobals
+outer:
+ switch {
+ case line == "}":
+ g.whichHuffman = 0
+
+ // If we have all three Huffman tables, write them.
+ for i := 1; ; i++ {
+ if i == 4 {
+ if err := deflateGlobalsWriteDynamicHuffmanTables(); err != nil {
+ return nil, err
+ }
+ break
+ }
+ if g.huffmans[i] == nil {
+ break
+ }
+ }
+
+ return stateDeflateDynamicHuffman, nil
+
+ default:
+ s := line
+ n, s, ok := parseNum(s)
+ if !ok || s == "" {
+ break
+ }
+ for i := 0; i < len(s); i++ {
+ if c := s[i]; c != '0' && c != '1' {
+ break outer
+ }
+ }
+ if g.huffmans[g.whichHuffman] == nil {
+ g.huffmans[g.whichHuffman] = deflateHuffmanTable{}
+ }
+ g.huffmans[g.whichHuffman][n] = s
+ return stateDeflateDynamicHuffmanHuffman, nil
+ }
+
+ return nil, fmt.Errorf("bad stateDeflateDynamicHuffmanHuffman command: %q", line)
+}
+
type deflateBitStream struct {
bits uint32
nBits uint32 // Always within [0, 7].
@@ -355,7 +647,7 @@
out = append(out, b...)
}
-func (z *deflateBitStream) writeLCode(lCode uint32) {
+func (z *deflateBitStream) writeFixedHuffmanLCode(lCode uint32) {
switch {
case lCode < 144: // 0b._0011_0000 through 0b._1011_1111
lCode += 0x030
@@ -459,6 +751,7 @@
}
func deflateParseLiteral(s string) (lit string, ok bool) {
+ // TODO: support "\xAB" escape codes in the script?
const (
prefix = `literal "`
suffix = `"`
@@ -499,8 +792,9 @@
}
var gifGlobals struct {
- imageWidth uint32
- imageHeight uint32
+ imageWidth uint32
+ imageHeight uint32
+ imageBackgroundColorIndex uint32
frameLeft uint32
frameTop uint32
@@ -508,16 +802,23 @@
frameHeight uint32
globalPalette [][4]uint8
+ localPalette [][4]uint8
}
func stateGif(line string) (stateFunc, error) {
const (
+ cmdB = "bytes "
+ cmdGC = "graphicControl "
cmdL = "lzw "
cmdLC = "loopCount "
)
outer:
switch {
+ case line == "":
+ return stateGif, nil
+
case line == "frame {":
+ gifGlobals.localPalette = nil
out = append(out, 0x2C)
return stateGifFrame, nil
@@ -532,6 +833,60 @@
out = append(out, 0x3B)
return stateGif, nil
+ case strings.HasPrefix(line, cmdB):
+ s := line[len(cmdB):]
+ for s != "" {
+ x, ok := uint32(0), false
+ x, s, ok = parseHex(s)
+ if !ok {
+ break outer
+ }
+ out = append(out, uint8(x))
+ }
+ return stateGif, nil
+
+ case strings.HasPrefix(line, cmdGC):
+ s := line[len(cmdGC):]
+
+ flags := uint8(0)
+ if i := strings.IndexByte(s, ' '); i < 0 {
+ break
+ } else {
+ switch s[:i] {
+ case "animationDisposalNone":
+ flags |= 0x00
+ case "animationDisposalRestoreBackground":
+ flags |= 0x08
+ case "animationDisposalRestorePrevious":
+ flags |= 0x0C
+ default:
+ break outer
+ }
+ s = s[i+1:]
+ }
+
+ if !strings.HasSuffix(s, "ms") {
+ break
+ }
+ s = s[:len(s)-2]
+ duration, s, ok := parseNum(s)
+ if !ok || s != "" {
+ break
+ }
+ duration /= 10 // GIF's unit of time is 10ms.
+
+ transparentIndex := uint8(0)
+
+ out = append(out,
+ 0x21, 0xF9, 0x04,
+ flags,
+ uint8(duration>>0),
+ uint8(duration>>8),
+ transparentIndex,
+ 0x00,
+ )
+ return stateGif, nil
+
case strings.HasPrefix(line, cmdL):
s := line[len(cmdL):]
litWidth, s, ok := parseNum(s)
@@ -611,7 +966,7 @@
} else {
out = append(out, 0x80|uint8(n-1))
}
- out = append(out, 0x00) // TODO: background index.
+ out = append(out, uint8(g.imageBackgroundColorIndex))
out = append(out, 0x00)
for _, x := range g.globalPalette {
out = append(out, x[0], x[1], x[2])
@@ -620,10 +975,18 @@
}
const (
+ cmdBCI = "backgroundColorIndex "
cmdIWH = "imageWidthHeight "
cmdP = "palette {"
)
switch {
+ case strings.HasPrefix(line, cmdBCI):
+ s := line[len(cmdBCI):]
+ if i, _, ok := parseNum(s); ok {
+ g.imageBackgroundColorIndex = i
+ }
+ return stateGifImage, nil
+
case strings.HasPrefix(line, cmdIWH):
s := line[len(cmdIWH):]
if w, s, ok := parseNum(s); ok {
@@ -648,12 +1011,22 @@
out = appendU16LE(out, uint16(g.frameTop))
out = appendU16LE(out, uint16(g.frameWidth))
out = appendU16LE(out, uint16(g.frameHeight))
- out = append(out, 0x00) // TODO: flags.
+ if g.localPalette == nil {
+ out = append(out, 0x00)
+ } else if n := log2(uint32(len(g.localPalette))); n < 2 || 8 < n {
+ return nil, fmt.Errorf("bad len(g.localPalette): %d", len(g.localPalette))
+ } else {
+ out = append(out, 0x80|uint8(n-1))
+ }
+ for _, x := range g.localPalette {
+ out = append(out, x[0], x[1], x[2])
+ }
return stateGif, nil
}
const (
cmdFLTWH = "frameLeftTopWidthHeight "
+ cmdP = "palette {"
)
switch {
case strings.HasPrefix(line, cmdFLTWH):
@@ -671,6 +1044,9 @@
}
}
}
+
+ case strings.HasPrefix(line, cmdP):
+ return stateGifFramePalette, nil
}
return nil, fmt.Errorf("bad stateGifFrame command: %q", line)
@@ -695,3 +1071,23 @@
return nil, fmt.Errorf("bad stateGifImagePalette command: %q", line)
}
+
+func stateGifFramePalette(line string) (stateFunc, error) {
+ g := &gifGlobals
+ if line == "}" {
+ return stateGifFrame, nil
+ }
+
+ s := line
+ if rgb0, s, ok := parseHex(s); ok {
+ if rgb1, s, ok := parseHex(s); ok {
+ if rgb2, _, ok := parseHex(s); ok {
+ g.localPalette = append(g.localPalette,
+ [4]uint8{uint8(rgb0), uint8(rgb1), uint8(rgb2), 0xFF})
+ return stateGifFramePalette, nil
+ }
+ }
+ }
+
+ return nil, fmt.Errorf("bad stateGifFramePalette command: %q", line)
+}
diff --git a/std/deflate/decode_deflate.wuffs b/std/deflate/decode_deflate.wuffs
index a91e9b7..89117ab 100644
--- a/std/deflate/decode_deflate.wuffs
+++ b/std/deflate/decode_deflate.wuffs
@@ -139,21 +139,22 @@
}
pub func decoder.decode_io_writer?(dst base.io_writer, src base.io_reader, workbuf slice base.u8) {
+ var mark base.u64
var status base.status
var written slice base.u8
var n_copied base.u64
var already_full base.u32[..0x8000]
while true {
- args.dst.set_mark!()
+ mark = args.dst.mark()
status =? this.decode_blocks?(dst:args.dst, src:args.src)
if not status.is_suspension() {
return status
}
- // TODO: should "since_mark" be "since_mark!", as the return value lets
- // you modify the state of args.dst, so future mutations (via the
- // slice) can change the veracity of any args.dst assertions?
- written = args.dst.since_mark()
+ // TODO: should "since" be "since!", as the return value lets you
+ // modify the state of args.dst, so future mutations (via the slice)
+ // can change the veracity of any args.dst assertions?
+ written = args.dst.since(mark:mark)
// Append written, the decoded output, to the history ringbuffer.
if written.length() >= 0x8000 {
// If written is longer than the ringbuffer, we can ignore the
diff --git a/std/deflate/decode_huffman_fast.wuffs b/std/deflate/decode_huffman_fast.wuffs
index d98af1c..6fa3c5f 100644
--- a/std/deflate/decode_huffman_fast.wuffs
+++ b/std/deflate/decode_huffman_fast.wuffs
@@ -292,12 +292,12 @@
pre args.dst.available() >= 258,
{
// Copy from this.history.
- if ((dist_minus_1 + 1) as base.u64) > args.dst.since_mark().length() {
+ if ((dist_minus_1 + 1) as base.u64) > args.dst.history_available() {
// Set (hlen, hdist) to be the length-distance pair to copy
// from this.history, and (length, distance) to be the
// remaining length-distance pair to copy from args.dst.
hlen = 0
- hdist = (((dist_minus_1 + 1) as base.u64) - args.dst.since_mark().length()) as base.u32
+ hdist = (((dist_minus_1 + 1) as base.u64) - args.dst.history_available()) as base.u32
if length > hdist {
assert hdist < length via "a < b: b > a"()
assert hdist < 0x8000 via "a < b: a < c; c <= b"(c:length)
@@ -345,12 +345,12 @@
continue:loop
}
- if ((dist_minus_1 + 1) as base.u64) > args.dst.since_mark().length() {
+ if ((dist_minus_1 + 1) as base.u64) > args.dst.history_available() {
return "#internal error: inconsistent distance"
}
}
// Once again, redundant but explicit assertions.
- assert ((dist_minus_1 + 1) as base.u64) <= args.dst.since_mark().length()
+ assert ((dist_minus_1 + 1) as base.u64) <= args.dst.history_available()
assert args.dst.available() >= 258
// We can therefore prove:
diff --git a/std/deflate/decode_huffman_slow.wuffs b/std/deflate/decode_huffman_slow.wuffs
index 2fb085f..2c66e9d 100644
--- a/std/deflate/decode_huffman_slow.wuffs
+++ b/std/deflate/decode_huffman_slow.wuffs
@@ -203,11 +203,11 @@
while true {
// Copy from this.history.
- if ((dist_minus_1 + 1) as base.u64) > args.dst.since_mark().length() {
+ if ((dist_minus_1 + 1) as base.u64) > args.dst.history_available() {
// Set (hlen, hdist) to be the length-distance pair to copy
// from this.history, and (length, distance) to be the
// remaining length-distance pair to copy from args.dst.
- hdist = (((dist_minus_1 + 1) as base.u64) - args.dst.since_mark().length()) as base.u32
+ hdist = (((dist_minus_1 + 1) as base.u64) - args.dst.history_available()) as base.u32
if length > hdist {
assert hdist < length via "a < b: b > a"()
assert hdist < 0x8000 via "a < b: a < c; c <= b"(c:length)
diff --git a/std/gif/decode_gif.wuffs b/std/gif/decode_gif.wuffs
index 38b8271..203f3e0 100644
--- a/std/gif/decode_gif.wuffs
+++ b/std/gif/decode_gif.wuffs
@@ -16,9 +16,11 @@
pub status "#bad block"
pub status "#bad extension label"
+pub status "#bad frame size"
pub status "#bad graphic control"
pub status "#bad header"
pub status "#bad literal width"
+pub status "#bad palette"
pri status "#internal error: inconsistent ri/wi"
@@ -27,6 +29,80 @@
// need a per-pixel-row workbuf.
pub const decoder_workbuf_len_max_incl_worst_case base.u64 = 1
+// --------
+
+// Quirks are discussed in (/doc/note/quirks.md).
+//
+// The base38 encoding of "gif " is 0xF8586.
+
+// When this quirk is enabled, when skipping over frames, the number of frames
+// visited isn't incremented when the last byte of the N'th frame is seen.
+// Instead, it is incremented when the first byte of the N+1'th frame's header
+// is seen. There may be zero or more GIF extensions between the N'th frame's
+// payload and the N+1'th frame's header.
+//
+// For a well-formed GIF, this won't have much effect. For a malformed GIF,
+// this can affect the number of valid frames, if there is an error detected in
+// the extensions between one frame's payload and the next frame's header.
+//
+// Some other GIF decoders don't register the N'th frame as complete until they
+// see the N+1'th frame's header (or the end-of-animation terminator), so that
+// e.g. the API for visiting the N'th frame can also return whether it's the
+// final frame. Enabling this quirk allows for matching that behavior.
+pub const quirk_delay_num_decoded_frames base.u32 = (0xF8586 << 10) | 0
+
+// When this quirk is enabled, the background color of the first frame is set
+// to black whenever that first frame has a local (frame-specific) palette.
+// That black can be either opaque black or transparent black, depending on
+// whether or not that first frame is opaque: whether that local palette
+// contains a transparent color.
+//
+// This has no effect unless quirk_honor_background_color is also enabled.
+//
+// There isn't really much of a rationale for this, other than it matches the
+// behavior of another GIF implementation.
+pub const quirk_first_frame_local_palette_means_black_background base.u32 = (0xF8586 << 10) | 1
+
+// When this quirk is enabled, the background color is taken from the GIF
+// instead of always being transparent black. If the background color index in
+// the GIF header is non-zero but less than the global palette's size, the
+// global background color is that global palette's entry. Otherwise, it is
+// opaque black. A frame's background color is transparent if the frame palette
+// contains a transparent color. Otherwise, it is the global background color.
+// Note that different frames can have different background colors.
+//
+// Specifically, if the initial frame bounds is smaller than the image bounds,
+// those pixels outside the initial frame bounds are assumed to start as that
+// frame background color. The frame background color should also be used when
+// processing WUFFS_BASE__ANIMATION_DISPOSAL__RESTORE_BACKGROUND. In both
+// cases, the caller of Wuffs, not Wuffs itself, is responsible for filling the
+// pixel buffer with that color.
+pub const quirk_honor_background_color base.u32 = (0xF8586 << 10) | 2
+
+// When this quirk is enabled, silently ignore e.g. a frame that reports a
+// width and height of 6 pixels each, followed by 50 pixel values. In that
+// case, we process the first 36 pixel values and discard the excess 14.
+pub const quirk_ignore_too_much_pixel_data base.u32 = (0xF8586 << 10) | 3
+
+// When this quirk is enabled, if the initial frame bounds extends beyond the
+// image bounds, then the image bounds stay unchanged. By default (with this
+// quirk disabled), the image bounds are adjusted to always contain the first
+// frame's bounds (but not necessarily subsequent frame's bounds).
+//
+// For more discussion, see
+// https://github.com/google/wuffs/blob/master/test/data/artificial/gif-frame-out-of-bounds.gif.make-artificial.txt
+pub const quirk_image_bounds_are_strict base.u32 = (0xF8586 << 10) | 4
+
+// When this quirk is enabled, a frame with zero width or height is rejected
+// during decode_frame (but accepted during decode_frame_config).
+pub const quirk_reject_empty_frame base.u32 = (0xF8586 << 10) | 5
+
+// When this quirk is enabled, a frame with no explicit palette is rejected,
+// instead of implicitly having a palette with every entry being opaque black.
+pub const quirk_reject_empty_palette base.u32 = (0xF8586 << 10) | 6
+
+// --------
+
// See the spec appendix E "Interlaced Images" on page 29. The first element
// represents either that the frame was non-interlaced, or that all interlace
// stages are complete. Otherwise, the four interlace stages are elements 4, 3,
@@ -49,37 +125,62 @@
// Call sequence states:
// - 0: initial state.
- // - 1: image config decoded, including the first frame's bounds, but not
+ // - 1: metadata reported; image config decode is in progress.
+ // - 2: metadata finished; image config decode is in progress.
+ // - 3: image config decoded, including the first frame's bounds, but not
// the first frame's pixels.
- // - 2: frame config decoded.
- // - 3: frame decoded.
+ // - 4: frame config decoded.
+ // - 5: frame decoded.
//
// State transitions:
//
- // - 0 -> 1: via IC
- // - 0 -> 2: via FC with implicit IC
- // - 0 -> 3: via F with implicit IC and FC
+ // - 0 -> 1: via IC (metadata reported)
+ // - 0 -> 3: via IC (metadata not reported)
+ // - 0 -> 4: via FC with implicit IC
+ // - 0 -> 5: via F with implicit IC and FC
//
- // - 1 -> 2: via FC
- // - 1 -> 3: via F with implicit FC
+ // - 1 -> 2: via AMC
//
- // - 2 -> 2: via FC with implicit F
- // - 2 -> 3: via F
+ // - 2 -> 1: via IC (metadata reported)
+ // - 2 -> 3: via IC (metadata not reported)
//
- // - 3 -> 2: via FC
- // - 3 -> 3: via F with implicit FC
+ // - 3 -> 4: via FC
+ // - 3 -> 5: via F with implicit FC
+ //
+ // - 4 -> 4: via FC with implicit F
+ // - 4 -> 5: via F
+ //
+ // - 5 -> 4: via FC
+ // - 5 -> 5: via F with implicit FC
//
// Where:
- // - F is decode_frame, implicit means skip_frame
- // - FC is decode_frame_config, implicit means nullptr args.dst
- // - IC is decode_image_config, implicit means nullptr args.dst
+ // - AMC is ack_metadata_chunk
+ // - F is decode_frame, implicit means skip_frame
+ // - FC is decode_frame_config, implicit means nullptr args.dst
+ // - IC is decode_image_config, implicit means nullptr args.dst
call_sequence base.u8,
+ ignore_metadata base.bool,
+ report_metadata_iccp base.bool,
+ report_metadata_xmp base.bool,
+ metadata_fourcc_value base.u32,
+ metadata_chunk_length_value base.u64,
+ metadata_io_position base.u64,
+
+ quirk_enabled_delay_num_decoded_frames base.bool,
+ quirk_enabled_first_frame_local_palette_means_black_background base.bool,
+ quirk_enabled_honor_background_color base.bool,
+ quirk_enabled_ignore_too_much_pixel_data base.bool,
+ quirk_enabled_image_bounds_are_strict base.bool,
+ quirk_enabled_reject_empty_frame base.bool,
+ quirk_enabled_reject_empty_palette base.bool,
+
+ delayed_num_decoded_frames base.bool,
end_of_data base.bool,
restarted base.bool,
previous_lzw_decode_ended_abruptly base.bool,
- which_palette base.u8[..1],
+ has_global_palette base.bool,
// interlace indexes the interlace_start and interlace_delta arrays.
interlace base.u8[..4],
@@ -89,7 +190,9 @@
seen_num_loops base.bool,
num_loops base.u32,
- seen_graphic_control base.bool,
+ background_color_u32_argb_premul base.u32,
+ black_color_u32_argb_premul base.u32,
+
gc_has_transparent_index base.bool,
gc_transparent_index base.u8,
gc_disposal base.u8,
@@ -127,24 +230,55 @@
lzw lzw.decoder,
)
+pub func decoder.set_quirk_enabled!(quirk base.u32, enabled base.bool) {
+ if this.call_sequence == 0 {
+ if args.quirk == quirk_delay_num_decoded_frames {
+ this.quirk_enabled_delay_num_decoded_frames = args.enabled
+ } else if args.quirk == quirk_first_frame_local_palette_means_black_background {
+ this.quirk_enabled_first_frame_local_palette_means_black_background = args.enabled
+ } else if args.quirk == quirk_honor_background_color {
+ this.quirk_enabled_honor_background_color = args.enabled
+ } else if args.quirk == quirk_ignore_too_much_pixel_data {
+ this.quirk_enabled_ignore_too_much_pixel_data = args.enabled
+ } else if args.quirk == quirk_image_bounds_are_strict {
+ this.quirk_enabled_image_bounds_are_strict = args.enabled
+ } else if args.quirk == quirk_reject_empty_frame {
+ this.quirk_enabled_reject_empty_frame = args.enabled
+ } else if args.quirk == quirk_reject_empty_palette {
+ this.quirk_enabled_reject_empty_palette = args.enabled
+ }
+ }
+}
+
pub func decoder.decode_image_config?(dst nptr base.image_config, src base.io_reader) {
var ffio base.bool
- if this.call_sequence >= 1 {
+ if this.call_sequence == 0 {
+ this.decode_header?(src:args.src)
+ this.decode_lsd?(src:args.src)
+ } else if this.call_sequence <> 2 {
return base."#bad call sequence"
}
- this.decode_header?(src:args.src)
- this.decode_lsd?(src:args.src)
this.decode_up_to_id_part1?(src:args.src)
// TODO: if this.end_of_data, return an error and/or set dst to zero?
- ffio = (not this.gc_has_transparent_index) and
- (this.frame_rect_x0 == 0) and
- (this.frame_rect_y0 == 0) and
- (this.frame_rect_x1 == this.width) and
- (this.frame_rect_y1 == this.height)
+ ffio = not this.gc_has_transparent_index
+ if not this.quirk_enabled_honor_background_color {
+ ffio = ffio and
+ (this.frame_rect_x0 == 0) and
+ (this.frame_rect_y0 == 0) and
+ (this.frame_rect_x1 == this.width) and
+ (this.frame_rect_y1 == this.height)
+ } else if ffio {
+ // Use opaque black, not transparent black.
+ this.black_color_u32_argb_premul = 0xFF000000
+ }
+
+ if this.background_color_u32_argb_premul == 77 {
+ this.background_color_u32_argb_premul = this.black_color_u32_argb_premul
+ }
if args.dst <> nullptr {
// TODO: a Wuffs (not just C) name for the
@@ -158,7 +292,60 @@
first_frame_is_opaque:ffio)
}
- this.call_sequence = 1
+ this.call_sequence = 3
+}
+
+pub func decoder.set_report_metadata!(fourcc base.u32, report base.bool) {
+ if args.fourcc == 0x49434350 { // "ICCP"
+ this.report_metadata_iccp = args.report
+ } else if args.fourcc == 0x584D5020 { // "XMP "
+ this.report_metadata_xmp = args.report
+ }
+}
+
+pub func decoder.ack_metadata_chunk?(src base.io_reader) {
+ if this.call_sequence <> 1 {
+ return base."#bad call sequence"
+ }
+ if args.src.position() <> this.metadata_io_position {
+ return base."#bad I/O position"
+ }
+ while args.src.available() <= 0,
+ post args.src.available() > 0,
+ {
+ yield? base."$short read"
+ }
+
+ if this.metadata_fourcc_value == 0x584D5020 { // "XMP "
+ // The +1 is because XMP metadata's encoding includes each block's leading
+ // byte (the block size) as part of the metadata passed to the caller.
+ this.metadata_chunk_length_value = args.src.peek_u8_as_u64() + 1
+ if this.metadata_chunk_length_value > 1 {
+ this.metadata_io_position = args.src.position() ~sat+ this.metadata_chunk_length_value
+ return base."@metadata reported"
+ }
+ } else {
+ this.metadata_chunk_length_value = args.src.peek_u8_as_u64()
+ if this.metadata_chunk_length_value > 0 {
+ args.src.skip_fast!(actual:1, worst_case:1)
+ this.metadata_io_position = args.src.position() ~sat+ this.metadata_chunk_length_value
+ return base."@metadata reported"
+ }
+ }
+
+ args.src.skip_fast!(actual:1, worst_case:1)
+ this.call_sequence = 2
+ this.metadata_fourcc_value = 0
+ this.metadata_io_position = 0
+ return ok
+}
+
+pub func decoder.metadata_fourcc() base.u32 {
+ return this.metadata_fourcc_value
+}
+
+pub func decoder.metadata_chunk_length() base.u64 {
+ return this.metadata_chunk_length_value
}
pub func decoder.num_animation_loops() base.u32 {
@@ -200,6 +387,7 @@
if this.call_sequence == 0 {
return base."#bad call sequence"
}
+ this.delayed_num_decoded_frames = false
this.end_of_data = false
this.restarted = true
this.frame_config_io_position = args.io_position
@@ -210,15 +398,18 @@
}
pub func decoder.decode_frame_config?(dst nptr base.frame_config, src base.io_reader) {
- var blend base.u8
+ var blend base.u8
+ var background_color base.u32
+ var flags base.u8
+ this.ignore_metadata = true
this.dirty_y.reset!()
if not this.end_of_data {
if this.call_sequence == 0 {
this.decode_image_config?(dst:nullptr, src:args.src)
- } else if this.call_sequence <> 1 {
- if this.call_sequence == 2 {
+ } else if this.call_sequence <> 3 {
+ if this.call_sequence == 4 {
this.skip_frame?(src:args.src)
}
this.decode_up_to_id_part1?(src:args.src)
@@ -232,8 +423,26 @@
}
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
+ // palette, its background color is black.
+ if this.quirk_enabled_first_frame_local_palette_means_black_background and
+ (this.num_decoded_frame_configs_value == 0) {
+
+ while args.src.available() <= 0,
+ post args.src.available() > 0,
+ {
+ yield? base."$short read"
+ }
+ flags = args.src.peek_u8()
+ if (flags & 0x80) <> 0 {
+ background_color = this.black_color_u32_argb_premul
+ }
+ }
}
if args.dst <> nullptr {
@@ -246,35 +455,51 @@
index:this.num_decoded_frame_configs_value,
io_position:this.frame_config_io_position,
blend:blend,
- disposal:this.gc_disposal)
+ disposal:this.gc_disposal,
+ background_color:background_color)
}
this.num_decoded_frame_configs_value ~sat+= 1
- this.call_sequence = 2
+ this.call_sequence = 4
}
pri func decoder.skip_frame?(src base.io_reader) {
var flags base.u8
+ var lw base.u8
// 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)))
}
- // Skip the literal width.
- args.src.skip?(n:1)
+
+ // Process the LZW literal width.
+ lw = args.src.read_u8?()
+ if lw > 8 {
+ return "#bad literal width"
+ }
+
// Skip the blocks of LZW-compressed data.
this.skip_blocks?(src:args.src)
- this.num_decoded_frames_value ~sat+= 1
+ if this.quirk_enabled_delay_num_decoded_frames {
+ this.delayed_num_decoded_frames = true
+ } else {
+ this.num_decoded_frames_value ~sat+= 1
+ }
this.reset_gc!()
}
// 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) {
- if this.call_sequence <> 2 {
+ this.ignore_metadata = true
+ if this.call_sequence <> 4 {
this.decode_frame_config?(dst:nullptr, src:args.src)
}
+ if this.quirk_enabled_reject_empty_frame and
+ ((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_part2?(dst:args.dst, src:args.src, workbuf:args.workbuf)
@@ -283,10 +508,9 @@
}
pri func decoder.reset_gc!() {
- this.call_sequence = 3
+ this.call_sequence = 5
// The Image Descriptor is mandatory, but the Graphic Control extension is
// optional. Reset the GC related fields for the next decode_frame call.
- this.seen_graphic_control = false
this.gc_has_transparent_index = false
this.gc_transparent_index = 0
this.gc_disposal = 0
@@ -297,7 +521,9 @@
var block_type base.u8
if not this.restarted {
- this.frame_config_io_position = args.src.position()
+ if this.call_sequence <> 2 {
+ this.frame_config_io_position = args.src.position()
+ }
} else if this.frame_config_io_position <> args.src.position() {
return base."#bad restart"
} else {
@@ -309,9 +535,17 @@
if block_type == 0x21 { // The spec calls 0x21 the "Extension Introducer".
this.decode_extension?(src:args.src)
} else if block_type == 0x2C { // The spec calls 0x2C the "Image Separator".
+ if this.delayed_num_decoded_frames {
+ this.delayed_num_decoded_frames = false
+ this.num_decoded_frames_value ~sat+= 1
+ }
this.decode_id_part0?(src:args.src)
break
} else if block_type == 0x3B { // The spec calls 0x3B the "Trailer".
+ if this.delayed_num_decoded_frames {
+ this.delayed_num_decoded_frames = false
+ this.num_decoded_frames_value ~sat+= 1
+ }
this.end_of_data = true
break
} else {
@@ -341,21 +575,25 @@
//
// See the spec section 18 "Logical Screen Descriptor" on page 8.
pri func decoder.decode_lsd?(src base.io_reader) {
- var flags base.u8
- var num_palette_entries base.u32[..256]
- var i base.u32
- var argb base.u32
+ var flags base.u8
+ var background_color_index base.u8
+ var num_palette_entries base.u32[..256]
+ var i base.u32
+ var j base.u32[..1020]
+ var argb base.u32
this.width = args.src.read_u16le_as_u32?()
this.height = args.src.read_u16le_as_u32?()
flags = args.src.read_u8?()
- // Ignore the Background Color Index and Pixel Aspect Ratio bytes.
- args.src.skip?(n:2)
+ background_color_index = args.src.read_u8?()
+ // Ignore the Pixel Aspect Ratio byte.
+ args.src.skip?(n:1)
// Read the optional Global Color Table.
- if (flags & 0x80) <> 0 {
+ i = 0
+ this.has_global_palette = (flags & 0x80) <> 0
+ if this.has_global_palette {
num_palette_entries = (1 as base.u32) << (1 + (flags & 0x07))
- i = 0
while i < num_palette_entries {
assert i < 256 via "a < b: a < c; c <= b"(c:num_palette_entries)
// Convert from RGB (in memory order) to ARGB (in native u32 order)
@@ -368,15 +606,35 @@
this.palettes[0][(4 * i) + 3] = ((argb >> 24) & 0xFF) as base.u8
i += 1
}
- // Set the remaining palette entries to opaque black.
- while i < 256 {
- this.palettes[0][(4 * i) + 0] = 0x00
- this.palettes[0][(4 * i) + 1] = 0x00
- this.palettes[0][(4 * i) + 2] = 0x00
- this.palettes[0][(4 * i) + 3] = 0xFF
- i += 1
+
+ if this.quirk_enabled_honor_background_color {
+ if (background_color_index <> 0) and
+ ((background_color_index as base.u32) < num_palette_entries) {
+
+ j = 4 * (background_color_index as base.u32)
+ this.background_color_u32_argb_premul =
+ ((this.palettes[0][j + 0] as base.u32) << 0) |
+ ((this.palettes[0][j + 1] as base.u32) << 8) |
+ ((this.palettes[0][j + 2] as base.u32) << 16) |
+ ((this.palettes[0][j + 3] as base.u32) << 24)
+ } else {
+ // The background color is either opaque black or transparent
+ // black. We set it to an arbitrary nonsense value (77) for
+ // now, and set it to its real value later, once we know
+ // whether the first frame is opaque (the ffio value).
+ this.background_color_u32_argb_premul = 77
+ }
}
}
+
+ // Set the remaining palette entries to opaque black.
+ while i < 256 {
+ this.palettes[0][(4 * i) + 0] = 0x00
+ this.palettes[0][(4 * i) + 1] = 0x00
+ this.palettes[0][(4 * i) + 2] = 0x00
+ this.palettes[0][(4 * i) + 3] = 0xFF
+ i += 1
+ }
}
// decode_extension reads an extension. The Extension Introducer byte has
@@ -425,12 +683,24 @@
0x4E, 0x45, 0x54, 0x53, 0x43, 0x41, 0x50, 0x45, 0x32, 0x2E, 0x30,
]
+// iccrgbg1012 is "ICCRGBG1012" as bytes.
+pri const iccrgbg1012 array[11] base.u8 = [
+ 0x49, 0x43, 0x43, 0x52, 0x47, 0x42, 0x47, 0x31, 0x30, 0x31, 0x32,
+]
+
+// xmpdataxmp is "XMP DataXMP" as bytes.
+pri const xmpdataxmp array[11] base.u8 = [
+ 0x58, 0x4D, 0x50, 0x20, 0x44, 0x61, 0x74, 0x61, 0x58, 0x4D, 0x50,
+]
+
// decode_ae reads an Application Extension.
pri func decoder.decode_ae?(src base.io_reader) {
- var c base.u8
- var block_size base.u8
- var not_animexts base.bool
- var not_netscape base.bool
+ var c base.u8
+ var block_size base.u8
+ var is_animexts base.bool
+ var is_netscape base.bool
+ var is_iccp base.bool
+ var is_xmp base.bool
// This "while true" always executes exactly once, as it ends with a
// "break", but using "break"s throughout simplifies the control flow.
@@ -440,54 +710,90 @@
return ok
}
- // Look only for an 11 byte "ANIMEXTS1.0" or "NETSCAPE2.0" extension,
- // as per:
+ // Look only for an 11 byte "ANIMEXTS1.0", "NETSCAPE2.0" or other
+ // extension, as per:
// - http://www.vurdalakov.net/misc/gif/animexts-looping-application-extension
// - http://www.vurdalakov.net/misc/gif/netscape-looping-application-extension
+ //
+ // Other extensions include XMP metadata.
if block_size <> 11 {
args.src.skip?(n:block_size as base.u32)
break
}
- not_animexts = false
- not_netscape = false
+ is_animexts = true
+ is_netscape = true
+ is_iccp = true
+ is_xmp = true
block_size = 0 // Re-purpose the block_size variable as a counter.
while block_size < 11 {
c = args.src.read_u8?()
- not_animexts = not_animexts or (c <> animexts1dot0[block_size])
- not_netscape = not_netscape or (c <> netscape2dot0[block_size])
+ is_animexts = is_animexts and (c == animexts1dot0[block_size])
+ is_netscape = is_netscape and (c == netscape2dot0[block_size])
+ is_iccp = is_iccp and (c == iccrgbg1012[block_size])
+ is_xmp = is_xmp and (c == xmpdataxmp[block_size])
block_size += 1
}
- if not_animexts and not_netscape {
- break
- }
- // Those 11 bytes should be followed by 0x03, 0x01 and then the loop
- // count.
- block_size = args.src.read_u8?()
- if block_size <> 3 {
- args.src.skip?(n:block_size as base.u32)
- break
- }
- c = args.src.read_u8?()
- if c <> 0x01 {
- args.src.skip?(n:2)
- break
- }
- this.num_loops = args.src.read_u16le_as_u32?()
- this.seen_num_loops = true
+ if is_animexts or is_netscape {
+ // Those 11 bytes should be followed by 0x03, 0x01 and then the loop
+ // count.
+ block_size = args.src.read_u8?()
+ if block_size <> 3 {
+ args.src.skip?(n:block_size as base.u32)
+ break
+ }
+ c = args.src.read_u8?()
+ if c <> 0x01 {
+ args.src.skip?(n:2)
+ break
+ }
+ this.num_loops = args.src.read_u16le_as_u32?()
+ this.seen_num_loops = true
- // A loop count of N, in the wire format, actually means "repeat N
- // times after the first play", if N is positive. A zero N means to
- // loop forever. Playing the frames exactly once is denoted by the
- // *absence* of this NETSCAPE2.0 application extension.
- //
- // For example, if there are four frames: A, B, C, D, and N is 2, then
- // each frame is actually played N+1 or 3 times: ABCDABCDABCD.
- //
- // Thus, we increment N if it is positive. The comparison against
- // 0xFFFF will never fail, but is necessary for the overflow checker.
- if (0 < this.num_loops) and (this.num_loops <= 0xFFFF) {
- this.num_loops += 1
+ // A loop count of N, in the wire format, actually means "repeat N
+ // times after the first play", if N is positive. A zero N means to
+ // loop forever. Playing the frames exactly once is denoted by the
+ // *absence* of this NETSCAPE2.0 application extension.
+ //
+ // For example, if there are four frames: A, B, C, D, and N is 2, then
+ // each frame is actually played N+1 or 3 times: ABCDABCDABCD.
+ //
+ // Thus, we increment N if it is positive. The comparison against
+ // 0xFFFF will never fail, but is necessary for the overflow checker.
+ if (0 < this.num_loops) and (this.num_loops <= 0xFFFF) {
+ this.num_loops += 1
+ }
+
+ } else if this.ignore_metadata {
+ // No-op.
+
+ } else if is_iccp and this.report_metadata_iccp {
+ while args.src.available() <= 0,
+ post args.src.available() > 0,
+ {
+ yield? base."$short read"
+ }
+ this.metadata_chunk_length_value = args.src.peek_u8_as_u64()
+ args.src.skip_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
+ return base."@metadata reported"
+
+ } else if is_xmp and this.report_metadata_xmp {
+ while args.src.available() <= 0,
+ post args.src.available() > 0,
+ {
+ yield? base."$short read"
+ }
+ // The +1 is because XMP metadata's encoding includes each block's
+ // leading byte (the block size) as part of the metadata passed to
+ // the caller.
+ this.metadata_chunk_length_value = args.src.peek_u8_as_u64() + 1
+ this.metadata_fourcc_value = 0x584D5020 // "XMP "
+ this.metadata_io_position = args.src.position() ~sat+ this.metadata_chunk_length_value
+ this.call_sequence = 1
+ return base."@metadata reported"
}
break
@@ -501,9 +807,6 @@
var flags base.u8
var gc_duration_centiseconds base.u16
- if this.seen_graphic_control {
- return "#bad graphic control"
- }
c = args.src.read_u8?()
if c <> 4 {
return "#bad graphic control"
@@ -539,7 +842,6 @@
if c <> 0 {
return "#bad graphic control"
}
- this.seen_graphic_control = true
}
// decode_id_partX reads an Image Descriptor. The Image Separator byte has
@@ -569,7 +871,7 @@
// and the bottom right extent of the first frame. See
// test/data/artificial/gif-frame-out-of-bounds.gif.make-artificial.txt for
// more discussion.
- if this.call_sequence == 0 {
+ if (this.call_sequence == 0) and (not this.quirk_enabled_image_bounds_are_strict) {
this.width = this.width.max(x:this.frame_rect_x1)
this.height = this.height.max(x:this.frame_rect_y1)
}
@@ -577,10 +879,12 @@
pri func decoder.decode_id_part1?(dst ptr base.pixel_buffer, src base.io_reader) {
var flags base.u8
+ var which_palette base.u8[..1]
var num_palette_entries base.u32[..256]
var i base.u32
var argb base.u32
var dst_palette slice base.u8
+ var status base.status
var lw base.u8
flags = args.src.read_u8?()
@@ -591,7 +895,7 @@
}
// Read the optional Local Color Table.
- this.which_palette = 1
+ which_palette = 1
if (flags & 0x80) <> 0 {
num_palette_entries = (1 as base.u32) << (1 + (flags & 0x07))
i = 0
@@ -615,10 +919,12 @@
this.palettes[1][(4 * i) + 3] = 0xFF
i += 1
}
+ } else if this.quirk_enabled_reject_empty_palette and (not this.has_global_palette) {
+ return "#bad palette"
} else if this.gc_has_transparent_index {
this.palettes[1][:].copy_from_slice!(s:this.palettes[0][:])
} else {
- this.which_palette = 0
+ which_palette = 0
}
// Set the gc_transparent_index palette entry to transparent black.
@@ -636,11 +942,14 @@
// TODO: a Wuffs (not just C) name for the
// WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_BINARY magic pixfmt constant.
- this.swizzler.prepare!(
+ status = this.swizzler.prepare!(
dst_pixfmt:args.dst.pixel_format(),
dst_palette:dst_palette,
src_pixfmt:0x47040008,
- src_palette:this.palettes[this.which_palette][:])
+ src_palette:this.palettes[which_palette][:])
+ if not status.is_ok() {
+ return status
+ }
// Other GIF implementations accept GIF files that aren't completely spec
// compliant. For example, the test/data/gifplayer-muybridge.gif file
@@ -661,8 +970,11 @@
this.lzw.reset!()
}
+ // Process the LZW literal width. The spec says that "images which have one
+ // color bit must be indicated as having a code size [i.e. literal width]
+ // of 2", but in practice, some encoders use a literal width of 1 or 0.
lw = args.src.read_u8?()
- if (lw < 2) or (8 < lw) {
+ if lw > 8 {
return "#bad literal width"
}
this.lzw.set_literal_width!(lw:lw as base.u32)
@@ -676,6 +988,7 @@
var n_compressed base.u64
var compressed slice base.u8
var r base.io_reader
+ var mark base.u64
var lzw_status base.status
var copy_status base.status
var uncompressed slice base.u8
@@ -726,9 +1039,10 @@
return "#internal error: inconsistent ri/wi"
}
io_bind (io:r, data:this.compressed[this.compressed_ri:this.compressed_wi]) {
+ mark = r.mark()
lzw_status =? this.lzw.decode_io_writer?(
dst:this.util.null_io_writer(), src:r, workbuf:this.util.null_slice_u8())
- this.compressed_ri ~sat+= r.since_mark().length()
+ this.compressed_ri ~sat+= r.count_since(mark:mark)
}
uncompressed = this.lzw.flush!()
@@ -769,25 +1083,28 @@
}
pri func decoder.copy_to_image_buffer!(pb ptr base.pixel_buffer, src slice base.u8) base.status {
- // TODO: don't assume a packed pixel format.
+ // TODO: don't assume an interleaved pixel format.
var dst slice base.u8
var src slice base.u8
var n base.u64
var src_ri base.u64
var bytes_per_pixel base.u32[..64]
- var pixfmt base.u32
+ var pixfmt_channels base.u32
var tab table base.u8
var i base.u64
var j base.u64
// TODO: a Wuffs (not just C) name for the WUFFS_BASE__PIXEL_FORMAT__ETC
// magic pixfmt constants. Also, support more formats.
- bytes_per_pixel = 1
- pixfmt = args.pb.pixel_format()
- if (pixfmt == 0x45008888) or (pixfmt == 0x55008888) or
- (pixfmt == 0x46008888) or (pixfmt == 0x56008888) or
- (pixfmt == 0x47008888) or (pixfmt == 0x57008888) {
+ pixfmt_channels = args.pb.pixel_format() & 0xFFFF
+ if (pixfmt_channels == 0x8888) {
bytes_per_pixel = 4
+ } else if (pixfmt_channels == 0x0888) {
+ bytes_per_pixel = 3
+ } else if (pixfmt_channels == 0x0008) {
+ bytes_per_pixel = 1
+ } else {
+ return base."#unsupported option"
}
tab = args.pb.plane(p:0)
@@ -795,6 +1112,9 @@
src = args.src[src_ri:]
if this.dst_y >= this.frame_rect_y1 {
+ if this.quirk_enabled_ignore_too_much_pixel_data {
+ return ok
+ }
return base."#too much data"
}
@@ -810,7 +1130,8 @@
} else {
dst = dst[i:]
}
- n = this.swizzler.swizzle_packed!(dst:dst, dst_palette:this.dst_palette[:], src:src)
+ n = this.swizzler.swizzle_interleaved!(
+ dst:dst, dst_palette:this.dst_palette[:], src:src)
src_ri ~sat+= n
this.dst_x ~sat+= (n & 0xFFFFFFFF) as base.u32
diff --git a/std/gzip/decode_gzip.wuffs b/std/gzip/decode_gzip.wuffs
index 297b191..49a7cb6 100644
--- a/std/gzip/decode_gzip.wuffs
+++ b/std/gzip/decode_gzip.wuffs
@@ -46,6 +46,7 @@
var c base.u8
var flags base.u8
var xlen base.u16
+ var mark base.u64
var checksum_got base.u32
var decoded_length_got base.u32
var status base.status
@@ -111,11 +112,11 @@
// Decode and checksum the DEFLATE-encoded payload.
while true {
- args.dst.set_mark!()
+ mark = args.dst.mark()
status =? this.flate.decode_io_writer?(dst:args.dst, src:args.src, workbuf:args.workbuf)
if not this.ignore_checksum {
- checksum_got = this.checksum.update!(x:args.dst.since_mark())
- decoded_length_got ~mod+= ((args.dst.since_mark().length() & 0xFFFFFFFF) as base.u32)
+ checksum_got = this.checksum.update!(x:args.dst.since(mark:mark))
+ decoded_length_got ~mod+= ((args.dst.count_since(mark:mark) & 0xFFFFFFFF) as base.u32)
}
if status.is_ok() {
break
diff --git a/std/lzw/decode_lzw.wuffs b/std/lzw/decode_lzw.wuffs
index 7f3698c..5f02e99 100644
--- a/std/lzw/decode_lzw.wuffs
+++ b/std/lzw/decode_lzw.wuffs
@@ -27,11 +27,11 @@
pub const decoder_workbuf_len_max_incl_worst_case base.u64 = 0
pub struct decoder?(
- // set_literal_width_arg is the saved argument passed to set_literal_width.
- // This field is copied to the literal_width field at the start of
- // decode_io_writer. During that method, calling set_literal_width will
- // change set_literal_width_arg but not literal_width.
- set_literal_width_arg base.u32[..8],
+ // 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
+ // will change set_literal_width_arg but not literal_width.
+ set_literal_width_arg base.u32[..9],
// read_from state that does not change during a decode call.
literal_width base.u32[..8],
@@ -69,8 +69,8 @@
output array[8192 + 7] base.u8,
)
-pub func decoder.set_literal_width!(lw base.u32[2..8]) {
- this.set_literal_width_arg = args.lw
+pub func decoder.set_literal_width!(lw base.u32[..8]) {
+ this.set_literal_width_arg = args.lw + 1
}
pub func decoder.workbuf_len() base.range_ii_u64 {
@@ -82,8 +82,8 @@
// Initialize read_from state.
this.literal_width = 8
- if this.set_literal_width_arg >= 2 {
- this.literal_width = this.set_literal_width_arg
+ if this.set_literal_width_arg > 0 {
+ this.literal_width = this.set_literal_width_arg - 1
}
this.clear_code = (1 as base.u32) << this.literal_width
this.end_code = this.clear_code + 1
diff --git a/std/zlib/decode_zlib.wuffs b/std/zlib/decode_zlib.wuffs
index b7b5817..fcf6c65 100644
--- a/std/zlib/decode_zlib.wuffs
+++ b/std/zlib/decode_zlib.wuffs
@@ -49,6 +49,7 @@
var checksum_got base.u32
var status base.status
var checksum_want base.u32
+ var mark base.u64
x = args.src.read_u16be?()
if ((x >> 8) & 0x0F) <> 0x08 {
@@ -66,10 +67,10 @@
// Decode and checksum the DEFLATE-encoded payload.
while true {
- args.dst.set_mark!()
+ mark = args.dst.mark()
status =? this.flate.decode_io_writer?(dst:args.dst, src:args.src, workbuf:args.workbuf)
if not this.ignore_checksum {
- checksum_got = this.checksum.update!(x:args.dst.since_mark())
+ checksum_got = this.checksum.update!(x:args.dst.since(mark:mark))
}
if status.is_ok() {
break
diff --git a/test/c/mimiclib/deflate-gzip-zlib.c b/test/c/mimiclib/deflate-gzip-zlib.c
index 9b9c0c3..4c3a740 100644
--- a/test/c/mimiclib/deflate-gzip-zlib.c
+++ b/test/c/mimiclib/deflate-gzip-zlib.c
@@ -42,7 +42,7 @@
uint64_t wlimit,
uint64_t rlimit,
bool deflate_instead_of_zlib) {
- if (wlimit || rlimit) {
+ if ((wlimit < UINT64_MAX) || (rlimit < UINT64_MAX)) {
// Supporting this would probably mean using tinfl_decompress instead of
// the simpler tinfl_decompress_mem_to_mem function.
return "unsupported I/O limit";
@@ -99,7 +99,7 @@
size_t len = src->meta.wi - src->meta.ri;
if (len > 0x7FFFFFFF) {
return "src length is too large";
- } else if ((len > rlimit) && (rlimit > 0)) {
+ } else if (len > rlimit) {
len = rlimit;
}
global_mimiclib_deflate_unused_u32 =
@@ -120,7 +120,7 @@
size_t len = src->meta.wi - src->meta.ri;
if (len > 0x7FFFFFFF) {
return "src length is too large";
- } else if ((len > rlimit) && (rlimit > 0)) {
+ } else if (len > rlimit) {
len = rlimit;
}
global_mimiclib_deflate_unused_u32 =
@@ -178,14 +178,14 @@
while (true) {
z.next_in = src->data.ptr + src->meta.ri;
z.avail_in = src->meta.wi - src->meta.ri;
- if ((z.avail_in > rlimit) && (rlimit > 0)) {
+ if (z.avail_in > rlimit) {
z.avail_in = rlimit;
}
uInt initial_avail_in = z.avail_in;
z.next_out = dst->data.ptr + dst->meta.wi;
z.avail_out = dst->data.len - dst->meta.wi;
- if ((z.avail_out > wlimit) && (wlimit > 0)) {
+ if (z.avail_out > wlimit) {
z.avail_out = wlimit;
}
uInt initial_avail_out = z.avail_out;
diff --git a/test/c/std/adler32.c b/test/c/std/adler32.c
index 9e509a9..b48a707 100644
--- a/test/c/std/adler32.c
+++ b/test/c/std/adler32.c
@@ -253,7 +253,7 @@
return do_bench_io_buffers(
wuffs_bench_adler32,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED, tc_src,
- &adler32_midsummer_gt, 0, 0, 1500);
+ &adler32_midsummer_gt, UINT64_MAX, UINT64_MAX, 1500);
}
const char* bench_wuffs_adler32_100k() {
@@ -261,7 +261,7 @@
return do_bench_io_buffers(
wuffs_bench_adler32,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED, tc_src,
- &adler32_pi_gt, 0, 0, 150);
+ &adler32_pi_gt, UINT64_MAX, UINT64_MAX, 150);
}
// ---------------- Mimic Benches
@@ -271,13 +271,14 @@
const char* bench_mimic_adler32_10k() {
CHECK_FOCUS(__func__);
return do_bench_io_buffers(mimic_bench_adler32, 0, tc_src,
- &adler32_midsummer_gt, 0, 0, 1500);
+ &adler32_midsummer_gt, UINT64_MAX, UINT64_MAX,
+ 1500);
}
const char* bench_mimic_adler32_100k() {
CHECK_FOCUS(__func__);
- return do_bench_io_buffers(mimic_bench_adler32, 0, tc_src, &adler32_pi_gt, 0,
- 0, 150);
+ return do_bench_io_buffers(mimic_bench_adler32, 0, tc_src, &adler32_pi_gt,
+ UINT64_MAX, UINT64_MAX, 150);
}
#endif // WUFFS_MIMIC
diff --git a/test/c/std/crc32.c b/test/c/std/crc32.c
index b2c395d..33322c0 100644
--- a/test/c/std/crc32.c
+++ b/test/c/std/crc32.c
@@ -288,7 +288,7 @@
return do_bench_io_buffers(
wuffs_bench_crc32_ieee,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED, tc_src,
- &crc32_midsummer_gt, 0, 0, 1500);
+ &crc32_midsummer_gt, UINT64_MAX, UINT64_MAX, 1500);
}
const char* bench_wuffs_crc32_ieee_100k() {
@@ -296,7 +296,7 @@
return do_bench_io_buffers(
wuffs_bench_crc32_ieee,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED, tc_src,
- &crc32_pi_gt, 0, 0, 150);
+ &crc32_pi_gt, UINT64_MAX, UINT64_MAX, 150);
}
// ---------------- Mimic Benches
@@ -306,13 +306,13 @@
const char* bench_mimic_crc32_ieee_10k() {
CHECK_FOCUS(__func__);
return do_bench_io_buffers(mimic_bench_crc32_ieee, 0, tc_src,
- &crc32_midsummer_gt, 0, 0, 1500);
+ &crc32_midsummer_gt, UINT64_MAX, UINT64_MAX, 1500);
}
const char* bench_mimic_crc32_ieee_100k() {
CHECK_FOCUS(__func__);
- return do_bench_io_buffers(mimic_bench_crc32_ieee, 0, tc_src, &crc32_pi_gt, 0,
- 0, 150);
+ return do_bench_io_buffers(mimic_bench_crc32_ieee, 0, tc_src, &crc32_pi_gt,
+ UINT64_MAX, UINT64_MAX, 150);
}
#endif // WUFFS_MIMIC
diff --git a/test/c/std/deflate.c b/test/c/std/deflate.c
index b011709..c7ac8e9 100644
--- a/test/c/std/deflate.c
+++ b/test/c/std/deflate.c
@@ -148,20 +148,19 @@
}
while (true) {
- wuffs_base__io_writer dst_writer = wuffs_base__io_buffer__writer(dst);
- if (wlimit) {
- set_writer_limit(&dst_writer, wlimit);
- }
- wuffs_base__io_reader src_reader = wuffs_base__io_buffer__reader(src);
- if (rlimit) {
- set_reader_limit(&src_reader, rlimit);
- }
+ 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(
- &dec, dst_writer, src_reader, global_work_slice);
+ &dec, &limited_dst, &limited_src, global_work_slice);
- if ((wlimit && (status == wuffs_base__suspension__short_write)) ||
- (rlimit && (status == wuffs_base__suspension__short_read))) {
+ dst->meta.wi += limited_dst.meta.wi;
+ src->meta.ri += limited_src.meta.ri;
+
+ if (((wlimit < UINT64_MAX) &&
+ (status == wuffs_base__suspension__short_write)) ||
+ ((rlimit < UINT64_MAX) &&
+ (status == wuffs_base__suspension__short_read))) {
continue;
}
return status;
@@ -170,25 +169,29 @@
const char* test_wuffs_deflate_decode_256_bytes() {
CHECK_FOCUS(__func__);
- return do_test_io_buffers(wuffs_deflate_decode, &deflate_256_bytes_gt, 0, 0);
+ return do_test_io_buffers(wuffs_deflate_decode, &deflate_256_bytes_gt,
+ UINT64_MAX, UINT64_MAX);
}
const char* test_wuffs_deflate_decode_deflate_backref_crosses_blocks() {
CHECK_FOCUS(__func__);
return do_test_io_buffers(wuffs_deflate_decode,
- &deflate_deflate_backref_crosses_blocks_gt, 0, 0);
+ &deflate_deflate_backref_crosses_blocks_gt,
+ UINT64_MAX, UINT64_MAX);
}
const char* test_wuffs_deflate_decode_deflate_distance_32768() {
CHECK_FOCUS(__func__);
return do_test_io_buffers(wuffs_deflate_decode,
- &deflate_deflate_distance_32768_gt, 0, 0);
+ &deflate_deflate_distance_32768_gt, UINT64_MAX,
+ UINT64_MAX);
}
const char* test_wuffs_deflate_decode_deflate_distance_code_31() {
CHECK_FOCUS(__func__);
- const char* got = do_test_io_buffers(
- wuffs_deflate_decode, &deflate_deflate_distance_code_31_gt, 0, 0);
+ const char* got = do_test_io_buffers(wuffs_deflate_decode,
+ &deflate_deflate_distance_code_31_gt,
+ UINT64_MAX, UINT64_MAX);
if (got != wuffs_deflate__error__bad_huffman_code) {
RETURN_FAIL("got \"%s\", want \"%s\"", got,
wuffs_deflate__error__bad_huffman_code);
@@ -198,22 +201,26 @@
const char* test_wuffs_deflate_decode_midsummer() {
CHECK_FOCUS(__func__);
- return do_test_io_buffers(wuffs_deflate_decode, &deflate_midsummer_gt, 0, 0);
+ return do_test_io_buffers(wuffs_deflate_decode, &deflate_midsummer_gt,
+ UINT64_MAX, UINT64_MAX);
}
const char* test_wuffs_deflate_decode_pi_just_one_read() {
CHECK_FOCUS(__func__);
- return do_test_io_buffers(wuffs_deflate_decode, &deflate_pi_gt, 0, 0);
+ return do_test_io_buffers(wuffs_deflate_decode, &deflate_pi_gt, UINT64_MAX,
+ UINT64_MAX);
}
const char* test_wuffs_deflate_decode_pi_many_big_reads() {
CHECK_FOCUS(__func__);
- return do_test_io_buffers(wuffs_deflate_decode, &deflate_pi_gt, 0, 4096);
+ return do_test_io_buffers(wuffs_deflate_decode, &deflate_pi_gt, UINT64_MAX,
+ 4096);
}
const char* test_wuffs_deflate_decode_pi_many_medium_reads() {
CHECK_FOCUS(__func__);
- return do_test_io_buffers(wuffs_deflate_decode, &deflate_pi_gt, 0, 599);
+ return do_test_io_buffers(wuffs_deflate_decode, &deflate_pi_gt, UINT64_MAX,
+ 599);
}
const char* test_wuffs_deflate_decode_pi_many_small_writes_reads() {
@@ -223,13 +230,14 @@
const char* test_wuffs_deflate_decode_romeo() {
CHECK_FOCUS(__func__);
- return do_test_io_buffers(wuffs_deflate_decode, &deflate_romeo_gt, 0, 0);
+ return do_test_io_buffers(wuffs_deflate_decode, &deflate_romeo_gt, UINT64_MAX,
+ UINT64_MAX);
}
const char* test_wuffs_deflate_decode_romeo_fixed() {
CHECK_FOCUS(__func__);
- return do_test_io_buffers(wuffs_deflate_decode, &deflate_romeo_fixed_gt, 0,
- 0);
+ return do_test_io_buffers(wuffs_deflate_decode, &deflate_romeo_fixed_gt,
+ UINT64_MAX, UINT64_MAX);
}
const char* test_wuffs_deflate_decode_split_src() {
@@ -256,9 +264,6 @@
return status;
}
- wuffs_base__io_writer dst_writer = wuffs_base__io_buffer__writer(&got);
- wuffs_base__io_reader src_reader = wuffs_base__io_buffer__reader(&src);
-
int i;
for (i = 1; i < 32; i++) {
size_t split = gt->src_offset0 + i;
@@ -279,13 +284,13 @@
src.meta.ri = gt->src_offset0;
src.meta.wi = split;
const char* z0 = wuffs_deflate__decoder__decode_io_writer(
- &dec, dst_writer, src_reader, global_work_slice);
+ &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(
- &dec, dst_writer, src_reader, global_work_slice);
+ &dec, &got, &src, global_work_slice);
if (z0 != wuffs_base__suspension__short_read) {
RETURN_FAIL("i=%d: z0: got \"%s\", want \"%s\"", i, z0,
@@ -312,22 +317,20 @@
wuffs_base__io_buffer* got,
wuffs_deflate__decoder* dec,
uint32_t starting_history_index,
- uint64_t limit,
+ uint64_t wlimit,
const char* want_z) {
src->meta.ri = gt->src_offset0;
src->meta.wi = gt->src_offset1;
got->meta.ri = 0;
got->meta.wi = 0;
- wuffs_base__io_writer dst_writer = wuffs_base__io_buffer__writer(got);
- wuffs_base__io_reader src_reader = wuffs_base__io_buffer__reader(src);
+ wuffs_base__io_buffer limited_got = make_limited_writer(*got, wlimit);
dec->private_impl.f_history_index = starting_history_index;
- set_writer_limit(&dst_writer, limit);
-
const char* got_z = wuffs_deflate__decoder__decode_io_writer(
- dec, dst_writer, src_reader, global_work_slice);
+ dec, &limited_got, src, global_work_slice);
+ got->meta.wi += limited_got.meta.wi;
if (got_z != want_z) {
RETURN_FAIL("i=%d: starting_history_index=0x%04" PRIX32
": decode status: got \"%s\", want \"%s\"",
@@ -624,25 +627,29 @@
const char* test_mimic_deflate_decode_256_bytes() {
CHECK_FOCUS(__func__);
- return do_test_io_buffers(mimic_deflate_decode, &deflate_256_bytes_gt, 0, 0);
+ return do_test_io_buffers(mimic_deflate_decode, &deflate_256_bytes_gt,
+ UINT64_MAX, UINT64_MAX);
}
const char* test_mimic_deflate_decode_deflate_backref_crosses_blocks() {
CHECK_FOCUS(__func__);
return do_test_io_buffers(mimic_deflate_decode,
- &deflate_deflate_backref_crosses_blocks_gt, 0, 0);
+ &deflate_deflate_backref_crosses_blocks_gt,
+ UINT64_MAX, UINT64_MAX);
}
const char* test_mimic_deflate_decode_deflate_distance_32768() {
CHECK_FOCUS(__func__);
return do_test_io_buffers(mimic_deflate_decode,
- &deflate_deflate_distance_32768_gt, 0, 0);
+ &deflate_deflate_distance_32768_gt, UINT64_MAX,
+ UINT64_MAX);
}
const char* test_mimic_deflate_decode_deflate_distance_code_31() {
CHECK_FOCUS(__func__);
- const char* got = do_test_io_buffers(
- mimic_deflate_decode, &deflate_deflate_distance_code_31_gt, 0, 0);
+ const char* got = do_test_io_buffers(mimic_deflate_decode,
+ &deflate_deflate_distance_code_31_gt,
+ UINT64_MAX, UINT64_MAX);
const char* want = "inflate failed (data error)";
if ((got != want) && ((got == NULL) || (want == NULL) || strcmp(got, want))) {
RETURN_FAIL("got \"%s\", want \"%s\"", got, want);
@@ -652,28 +659,32 @@
const char* test_mimic_deflate_decode_midsummer() {
CHECK_FOCUS(__func__);
- return do_test_io_buffers(mimic_deflate_decode, &deflate_midsummer_gt, 0, 0);
+ return do_test_io_buffers(mimic_deflate_decode, &deflate_midsummer_gt,
+ UINT64_MAX, UINT64_MAX);
}
const char* test_mimic_deflate_decode_pi_just_one_read() {
CHECK_FOCUS(__func__);
- return do_test_io_buffers(mimic_deflate_decode, &deflate_pi_gt, 0, 0);
+ return do_test_io_buffers(mimic_deflate_decode, &deflate_pi_gt, UINT64_MAX,
+ UINT64_MAX);
}
const char* test_mimic_deflate_decode_pi_many_big_reads() {
CHECK_FOCUS(__func__);
- return do_test_io_buffers(mimic_deflate_decode, &deflate_pi_gt, 0, 4096);
+ return do_test_io_buffers(mimic_deflate_decode, &deflate_pi_gt, UINT64_MAX,
+ 4096);
}
const char* test_mimic_deflate_decode_romeo() {
CHECK_FOCUS(__func__);
- return do_test_io_buffers(mimic_deflate_decode, &deflate_romeo_gt, 0, 0);
+ return do_test_io_buffers(mimic_deflate_decode, &deflate_romeo_gt, UINT64_MAX,
+ UINT64_MAX);
}
const char* test_mimic_deflate_decode_romeo_fixed() {
CHECK_FOCUS(__func__);
- return do_test_io_buffers(mimic_deflate_decode, &deflate_romeo_fixed_gt, 0,
- 0);
+ return do_test_io_buffers(mimic_deflate_decode, &deflate_romeo_fixed_gt,
+ UINT64_MAX, UINT64_MAX);
}
#endif // WUFFS_MIMIC
@@ -684,7 +695,7 @@
CHECK_FOCUS(__func__);
return do_bench_io_buffers(wuffs_deflate_decode,
WUFFS_INITIALIZE__DEFAULT_OPTIONS, tc_dst,
- &deflate_romeo_gt, 0, 0, 2000);
+ &deflate_romeo_gt, UINT64_MAX, UINT64_MAX, 2000);
}
const char* bench_wuffs_deflate_decode_1k_part_init() {
@@ -692,14 +703,14 @@
return do_bench_io_buffers(
wuffs_deflate_decode,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED, tc_dst,
- &deflate_romeo_gt, 0, 0, 2000);
+ &deflate_romeo_gt, UINT64_MAX, UINT64_MAX, 2000);
}
const char* bench_wuffs_deflate_decode_10k_full_init() {
CHECK_FOCUS(__func__);
- return do_bench_io_buffers(wuffs_deflate_decode,
- WUFFS_INITIALIZE__DEFAULT_OPTIONS, tc_dst,
- &deflate_midsummer_gt, 0, 0, 300);
+ return do_bench_io_buffers(
+ wuffs_deflate_decode, WUFFS_INITIALIZE__DEFAULT_OPTIONS, tc_dst,
+ &deflate_midsummer_gt, UINT64_MAX, UINT64_MAX, 300);
}
const char* bench_wuffs_deflate_decode_10k_part_init() {
@@ -707,7 +718,7 @@
return do_bench_io_buffers(
wuffs_deflate_decode,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED, tc_dst,
- &deflate_midsummer_gt, 0, 0, 300);
+ &deflate_midsummer_gt, UINT64_MAX, UINT64_MAX, 300);
}
const char* bench_wuffs_deflate_decode_100k_just_one_read() {
@@ -715,7 +726,7 @@
return do_bench_io_buffers(
wuffs_deflate_decode,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED, tc_dst,
- &deflate_pi_gt, 0, 0, 30);
+ &deflate_pi_gt, UINT64_MAX, UINT64_MAX, 30);
}
const char* bench_wuffs_deflate_decode_100k_many_big_reads() {
@@ -723,7 +734,7 @@
return do_bench_io_buffers(
wuffs_deflate_decode,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED, tc_dst,
- &deflate_pi_gt, 0, 4096, 30);
+ &deflate_pi_gt, UINT64_MAX, 4096, 30);
}
// ---------------- Mimic Benches
@@ -733,25 +744,26 @@
const char* bench_mimic_deflate_decode_1k() {
CHECK_FOCUS(__func__);
return do_bench_io_buffers(mimic_deflate_decode, 0, tc_dst, &deflate_romeo_gt,
- 0, 0, 2000);
+ UINT64_MAX, UINT64_MAX, 2000);
}
const char* bench_mimic_deflate_decode_10k() {
CHECK_FOCUS(__func__);
return do_bench_io_buffers(mimic_deflate_decode, 0, tc_dst,
- &deflate_midsummer_gt, 0, 0, 300);
+ &deflate_midsummer_gt, UINT64_MAX, UINT64_MAX,
+ 300);
}
const char* bench_mimic_deflate_decode_100k_just_one_read() {
CHECK_FOCUS(__func__);
- return do_bench_io_buffers(mimic_deflate_decode, 0, tc_dst, &deflate_pi_gt, 0,
- 0, 30);
+ return do_bench_io_buffers(mimic_deflate_decode, 0, tc_dst, &deflate_pi_gt,
+ UINT64_MAX, UINT64_MAX, 30);
}
const char* bench_mimic_deflate_decode_100k_many_big_reads() {
CHECK_FOCUS(__func__);
- return do_bench_io_buffers(mimic_deflate_decode, 0, tc_dst, &deflate_pi_gt, 0,
- 4096, 30);
+ return do_bench_io_buffers(mimic_deflate_decode, 0, tc_dst, &deflate_pi_gt,
+ UINT64_MAX, 4096, 30);
}
#endif // WUFFS_MIMIC
diff --git a/test/c/std/gif.c b/test/c/std/gif.c
index 6ed3277..ceae7c6 100644
--- a/test/c/std/gif.c
+++ b/test/c/std/gif.c
@@ -73,8 +73,7 @@
const char* test_basic_bad_receiver() {
CHECK_FOCUS(__func__);
wuffs_base__image_config ic = ((wuffs_base__image_config){});
- wuffs_base__io_reader src = ((wuffs_base__io_reader){});
- const char* status = wuffs_gif__decoder__decode_image_config(NULL, &ic, src);
+ const char* status = wuffs_gif__decoder__decode_image_config(NULL, &ic, NULL);
if (status != wuffs_base__error__bad_receiver) {
RETURN_FAIL("decode_image_config: got \"%s\", want \"%s\"", status,
wuffs_base__error__bad_receiver);
@@ -112,8 +111,7 @@
CHECK_FOCUS(__func__);
wuffs_gif__decoder dec = ((wuffs_gif__decoder){});
wuffs_base__image_config ic = ((wuffs_base__image_config){});
- wuffs_base__io_reader src = ((wuffs_base__io_reader){});
- const char* status = wuffs_gif__decoder__decode_image_config(&dec, &ic, src);
+ const char* status = wuffs_gif__decoder__decode_image_config(&dec, &ic, NULL);
if (status != wuffs_base__error__initialize_not_called) {
RETURN_FAIL("decode_image_config: got \"%s\", want \"%s\"", status,
wuffs_base__error__initialize_not_called);
@@ -205,8 +203,7 @@
wuffs_base__image_config ic = ((wuffs_base__image_config){});
wuffs_base__frame_config fc = ((wuffs_base__frame_config){});
- wuffs_base__io_reader src_reader = wuffs_base__io_buffer__reader(src);
- status = wuffs_gif__decoder__decode_image_config(&dec, &ic, src_reader);
+ status = wuffs_gif__decoder__decode_image_config(&dec, &ic, src);
if (status) {
return status;
}
@@ -224,15 +221,15 @@
}
while (true) {
- status = wuffs_gif__decoder__decode_frame_config(&dec, &fc, src_reader);
+ status = wuffs_gif__decoder__decode_frame_config(&dec, &fc, src);
if (status == wuffs_base__warning__end_of_data) {
break;
} else if (status) {
return status;
}
- status = wuffs_gif__decoder__decode_frame(&dec, &pb, src_reader,
- global_work_slice, NULL);
+ status = wuffs_gif__decoder__decode_frame(&dec, &pb, src, global_work_slice,
+ NULL);
if (status) {
return status;
}
@@ -276,8 +273,7 @@
{
wuffs_base__image_config ic = ((wuffs_base__image_config){});
- wuffs_base__io_reader src_reader = wuffs_base__io_buffer__reader(&src);
- status = wuffs_gif__decoder__decode_image_config(&dec, &ic, src_reader);
+ status = wuffs_gif__decoder__decode_image_config(&dec, &ic, &src);
if (status) {
RETURN_FAIL("decode_image_config: got \"%s\"", status);
}
@@ -324,13 +320,11 @@
int num_iters = 0;
while (true) {
num_iters++;
- wuffs_base__io_reader src_reader = wuffs_base__io_buffer__reader(&src);
- if (rlimit) {
- set_reader_limit(&src_reader, rlimit);
- }
+ wuffs_base__io_buffer limited_src = make_limited_reader(src, rlimit);
size_t old_ri = src.meta.ri;
- status = wuffs_gif__decoder__decode_frame_config(&dec, &fc, src_reader);
+ status = wuffs_gif__decoder__decode_frame_config(&dec, &fc, &limited_src);
+ src.meta.ri += limited_src.meta.ri;
if (!status) {
break;
@@ -350,14 +344,12 @@
while (true) {
num_iters++;
- wuffs_base__io_reader src_reader = wuffs_base__io_buffer__reader(&src);
- if (rlimit) {
- set_reader_limit(&src_reader, rlimit);
- }
+ wuffs_base__io_buffer limited_src = make_limited_reader(src, rlimit);
size_t old_ri = src.meta.ri;
const char* status = wuffs_gif__decoder__decode_frame(
- &dec, &pb, src_reader, global_work_slice, NULL);
+ &dec, &pb, &limited_src, global_work_slice, NULL);
+ src.meta.ri += limited_src.meta.ri;
if (!status) {
break;
@@ -381,7 +373,7 @@
return status;
}
- if (rlimit) {
+ if (rlimit < UINT64_MAX) {
if (num_iters <= 2) {
RETURN_FAIL("num_iters: got %d, want > 2", num_iters);
}
@@ -432,15 +424,49 @@
if (ind_want.meta.wi > (expanded_want.data.len / 4)) {
RETURN_FAIL("indexes are too long to expand into the work buffer");
}
- size_t i;
- for (i = 0; i < ind_want.meta.wi; i++) {
- uint8_t index = ind_want.data.ptr[i];
- expanded_want.data.ptr[4 * i + 0] = pal_want_array[4 * index + 0];
- expanded_want.data.ptr[4 * i + 1] = pal_want_array[4 * index + 1];
- expanded_want.data.ptr[4 * i + 2] = pal_want_array[4 * index + 2];
- expanded_want.data.ptr[4 * i + 3] = pal_want_array[4 * index + 3];
+
+ if (dst_pixfmt == WUFFS_BASE__PIXEL_FORMAT__BGR) {
+ size_t i;
+ for (i = 0; i < ind_want.meta.wi; i++) {
+ uint8_t index = ind_want.data.ptr[i];
+ expanded_want.data.ptr[3 * i + 0] = pal_want_array[4 * index + 0];
+ expanded_want.data.ptr[3 * i + 1] = pal_want_array[4 * index + 1];
+ expanded_want.data.ptr[3 * i + 2] = pal_want_array[4 * index + 2];
+ }
+ expanded_want.meta.wi = 3 * ind_want.meta.wi;
+ } else if (dst_pixfmt == WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL) {
+ size_t i;
+ for (i = 0; i < ind_want.meta.wi; i++) {
+ uint8_t index = ind_want.data.ptr[i];
+ expanded_want.data.ptr[4 * i + 0] = pal_want_array[4 * index + 0];
+ expanded_want.data.ptr[4 * i + 1] = pal_want_array[4 * index + 1];
+ expanded_want.data.ptr[4 * i + 2] = pal_want_array[4 * index + 2];
+ expanded_want.data.ptr[4 * i + 3] = pal_want_array[4 * index + 3];
+ }
+ expanded_want.meta.wi = 4 * ind_want.meta.wi;
+ } else if (dst_pixfmt == WUFFS_BASE__PIXEL_FORMAT__RGB) {
+ size_t i;
+ for (i = 0; i < ind_want.meta.wi; i++) {
+ uint8_t index = ind_want.data.ptr[i];
+ expanded_want.data.ptr[3 * i + 0] = pal_want_array[4 * index + 2];
+ expanded_want.data.ptr[3 * i + 1] = pal_want_array[4 * index + 1];
+ expanded_want.data.ptr[3 * i + 2] = pal_want_array[4 * index + 0];
+ }
+ expanded_want.meta.wi = 3 * ind_want.meta.wi;
+ } else if (dst_pixfmt == WUFFS_BASE__PIXEL_FORMAT__RGBA_NONPREMUL) {
+ size_t i;
+ for (i = 0; i < ind_want.meta.wi; i++) {
+ uint8_t index = ind_want.data.ptr[i];
+ expanded_want.data.ptr[4 * i + 0] = pal_want_array[4 * index + 2];
+ expanded_want.data.ptr[4 * i + 1] = pal_want_array[4 * index + 1];
+ expanded_want.data.ptr[4 * i + 2] = pal_want_array[4 * index + 0];
+ expanded_want.data.ptr[4 * i + 3] = pal_want_array[4 * index + 3];
+ }
+ expanded_want.meta.wi = 4 * ind_want.meta.wi;
+ } else {
+ return "unsupported pixel format";
}
- expanded_want.meta.wi = 4 * ind_want.meta.wi;
+
status = check_io_buffers_equal("pixels ", &got, &expanded_want);
if (status) {
return status;
@@ -451,8 +477,7 @@
if (src.meta.ri == src.meta.wi) {
RETURN_FAIL("decode_frame returned \"ok\" but src was exhausted");
}
- wuffs_base__io_reader src_reader = wuffs_base__io_buffer__reader(&src);
- status = wuffs_gif__decoder__decode_frame(&dec, &pb, src_reader,
+ status = wuffs_gif__decoder__decode_frame(&dec, &pb, &src,
global_work_slice, NULL);
if (status != wuffs_base__warning__end_of_data) {
RETURN_FAIL("decode_frame: got \"%s\", want \"%s\"", status,
@@ -468,6 +493,7 @@
}
const char* do_test_wuffs_gif_decode_expecting(wuffs_base__io_buffer src,
+ uint32_t quirk,
const char* want_status,
bool want_dirty_rect_is_empty) {
wuffs_gif__decoder dec;
@@ -477,11 +503,13 @@
if (status) {
RETURN_FAIL("initialize: \"%s\"", status);
}
+ if (quirk) {
+ wuffs_gif__decoder__set_quirk_enabled(&dec, quirk, true);
+ }
wuffs_base__image_config ic = ((wuffs_base__image_config){});
- wuffs_base__io_reader src_reader = wuffs_base__io_buffer__reader(&src);
- status = wuffs_gif__decoder__decode_image_config(&dec, &ic, src_reader);
+ status = wuffs_gif__decoder__decode_image_config(&dec, &ic, &src);
if (status) {
RETURN_FAIL("decode_image_config: got \"%s\"", status);
}
@@ -493,8 +521,8 @@
RETURN_FAIL("set_from_slice: \"%s\"", status);
}
- status = wuffs_gif__decoder__decode_frame(&dec, &pb, src_reader,
- global_work_slice, NULL);
+ status = wuffs_gif__decoder__decode_frame(&dec, &pb, &src, global_work_slice,
+ NULL);
if (status != want_status) {
RETURN_FAIL("decode_frame: got \"%s\", want \"%s\"", status, want_status);
}
@@ -530,10 +558,9 @@
}
{
- wuffs_base__io_reader src_reader = wuffs_base__io_buffer__reader(&src);
- set_reader_limit(&src_reader, 700);
-
- status = wuffs_gif__decoder__decode_frame_config(&dec, NULL, src_reader);
+ wuffs_base__io_buffer limited_src = make_limited_reader(src, 700);
+ status = wuffs_gif__decoder__decode_frame_config(&dec, NULL, &limited_src);
+ src.meta.ri += limited_src.meta.ri;
if (status != wuffs_base__suspension__short_read) {
RETURN_FAIL("decode_frame_config: got \"%s\", want \"%s\"", status,
wuffs_base__suspension__short_read);
@@ -545,9 +572,7 @@
// wuffs_base__error__interleaved_coroutine_calls.
{
- wuffs_base__io_reader src_reader = wuffs_base__io_buffer__reader(&src);
-
- status = wuffs_gif__decoder__decode_image_config(&dec, NULL, src_reader);
+ status = wuffs_gif__decoder__decode_image_config(&dec, NULL, &src);
if (status != wuffs_base__error__interleaved_coroutine_calls) {
RETURN_FAIL("decode_image_config: got \"%s\", want \"%s\"", status,
wuffs_base__error__interleaved_coroutine_calls);
@@ -577,14 +602,12 @@
RETURN_FAIL("initialize: \"%s\"", status);
}
- wuffs_base__io_reader src_reader = wuffs_base__io_buffer__reader(&src);
-
- status = wuffs_gif__decoder__decode_image_config(&dec, NULL, src_reader);
+ status = wuffs_gif__decoder__decode_image_config(&dec, NULL, &src);
if (status) {
RETURN_FAIL("decode_image_config: got \"%s\"", status);
}
- status = wuffs_gif__decoder__decode_image_config(&dec, NULL, src_reader);
+ status = wuffs_gif__decoder__decode_image_config(&dec, NULL, &src);
if (status != wuffs_base__error__bad_call_sequence) {
RETURN_FAIL("decode_image_config: got \"%s\", want \"%s\"", status,
wuffs_base__error__bad_call_sequence);
@@ -615,9 +638,8 @@
}
wuffs_base__image_config ic = ((wuffs_base__image_config){});
- wuffs_base__io_reader src_reader = wuffs_base__io_buffer__reader(&src);
- status = wuffs_gif__decoder__decode_image_config(&dec, &ic, src_reader);
+ status = wuffs_gif__decoder__decode_image_config(&dec, &ic, &src);
if (status) {
RETURN_FAIL("decode_image_config: got \"%s\"", status);
}
@@ -638,7 +660,7 @@
uint32_t i;
for (i = 0; i < want_num_frames; i++) {
wuffs_base__frame_config fc = ((wuffs_base__frame_config){});
- status = wuffs_gif__decoder__decode_frame_config(&dec, &fc, src_reader);
+ status = wuffs_gif__decoder__decode_frame_config(&dec, &fc, &src);
if (status) {
RETURN_FAIL("decode_frame_config #%" PRIu32 ": got \"%s\"", i, status);
}
@@ -656,7 +678,7 @@
}
}
- status = wuffs_gif__decoder__decode_frame(&dec, &pb, src_reader,
+ status = wuffs_gif__decoder__decode_frame(&dec, &pb, &src,
global_work_slice, NULL);
if (status) {
RETURN_FAIL("decode_frame #%" PRIu32 ": got \"%s\"", i, status);
@@ -673,7 +695,7 @@
// There should be no more frames, no matter how many times we call
// decode_frame.
for (i = 0; i < 3; i++) {
- status = wuffs_gif__decoder__decode_frame(&dec, &pb, src_reader,
+ status = wuffs_gif__decoder__decode_frame(&dec, &pb, &src,
global_work_slice, NULL);
if (status != wuffs_base__warning__end_of_data) {
RETURN_FAIL("decode_frame: got \"%s\", want \"%s\"", status,
@@ -720,6 +742,212 @@
want_frame_config_bounds);
}
+const char* test_wuffs_gif_decode_delay_num_frames_decoded() {
+ CHECK_FOCUS(__func__);
+ wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
+ .data = global_src_slice,
+ });
+ const char* status = read_file(&src, "test/data/animated-red-blue.gif");
+ if (status) {
+ return status;
+ }
+ if (src.meta.wi < 1) {
+ return "src file is too short";
+ }
+
+ // A GIF image should end with the 0x3B Trailer byte.
+ if (src.data.ptr[src.meta.wi - 1] != 0x3B) {
+ RETURN_FAIL("final byte: got 0x%02X, want 0x%02X",
+ src.data.ptr[src.meta.wi - 1], 0x3B);
+ }
+ // Replace that final byte with something invalid: neither 0x21 (Extension
+ // Introducer), 0x2C (Image Separator) or 0x3B (Trailer).
+ src.data.ptr[src.meta.wi - 1] = 0x99;
+
+ int q;
+ for (q = 0; q < 2; q++) {
+ src.meta.ri = 0;
+
+ wuffs_gif__decoder dec;
+ status = wuffs_gif__decoder__initialize(
+ &dec, sizeof dec, WUFFS_VERSION,
+ WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED);
+ if (status) {
+ RETURN_FAIL("q=%d: initialize: \"%s\"", q, status);
+ }
+ wuffs_gif__decoder__set_quirk_enabled(
+ &dec, wuffs_gif__quirk_delay_num_decoded_frames, q);
+
+ while (true) {
+ status = wuffs_gif__decoder__decode_frame_config(&dec, NULL, &src);
+ if (status) {
+ break;
+ }
+ }
+
+ uint64_t got = wuffs_gif__decoder__num_decoded_frames(&dec);
+ uint64_t want = q ? 3 : 4;
+ if (got != want) {
+ RETURN_FAIL("q=%d: num_decoded_frames: got %" PRIu64 ", want %" PRIu64, q,
+ got, want);
+ }
+ }
+ return NULL;
+}
+
+const char* test_wuffs_gif_decode_empty_palette() {
+ CHECK_FOCUS(__func__);
+ wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
+ .data = global_src_slice,
+ });
+ const char* status =
+ read_file(&src, "test/data/artificial/gif-empty-palette.gif");
+ if (status) {
+ return status;
+ }
+ int q;
+ for (q = 0; q < 2; q++) {
+ src.meta.ri = 0;
+
+ wuffs_gif__decoder dec;
+ status = wuffs_gif__decoder__initialize(
+ &dec, sizeof dec, WUFFS_VERSION,
+ WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED);
+ if (status) {
+ RETURN_FAIL("q=%d: initialize: \"%s\"", q, status);
+ }
+ wuffs_gif__decoder__set_quirk_enabled(
+ &dec, wuffs_gif__quirk_reject_empty_palette, q);
+
+ wuffs_base__image_config ic = ((wuffs_base__image_config){});
+ status = wuffs_gif__decoder__decode_image_config(&dec, &ic, &src);
+ if (status) {
+ RETURN_FAIL("q=%d: decode_image_config: \"%s\"", q, status);
+ }
+
+ wuffs_base__pixel_buffer pb = ((wuffs_base__pixel_buffer){});
+ status = wuffs_base__pixel_buffer__set_from_slice(&pb, &ic.pixcfg,
+ global_pixel_slice);
+ if (status) {
+ RETURN_FAIL("q=%d: set_from_slice: \"%s\"", q, status);
+ }
+
+ int i;
+ for (i = 0; i < 2; i++) {
+ status = wuffs_gif__decoder__decode_frame(&dec, &pb, &src,
+ global_work_slice, NULL);
+ if ((q == 1) && (i == 1)) {
+ if (status != wuffs_gif__error__bad_palette) {
+ RETURN_FAIL("q=%d: i=%d: decode_frame: got \"%s\", want \"%s\"", q, i,
+ status, wuffs_gif__error__bad_palette);
+ }
+ break;
+ }
+ if (status) {
+ RETURN_FAIL("q=%d: i=%d: decode_frame: \"%s\"", q, i, status);
+ }
+
+ wuffs_base__slice_u8 pal = wuffs_base__pixel_buffer__palette(&pb);
+ if (pal.len < 4) {
+ RETURN_FAIL("q=%d: i=%d: palette length: got %d, want >= 4", q, i,
+ (int)(pal.len));
+ }
+ uint8_t* p = pal.ptr;
+ int blue = i ? 0x00 : 0xFF;
+ if ((p[0] != blue) || (p[1] != 0x00) || (p[2] != 0x00) ||
+ (p[3] != 0xFF)) {
+ RETURN_FAIL(
+ "q=%d: i=%d: palette[0] BGRA: got (0x%02X, 0x%02X, 0x%02X, "
+ "0x%02X), want (0x%02X, 0x00, 0x00, 0xFF)",
+ q, i, (int)(p[0]), (int)(p[1]), (int)(p[2]), (int)(p[3]), blue);
+ }
+ }
+ }
+ return NULL;
+}
+
+const char* test_wuffs_gif_decode_background_color() {
+ CHECK_FOCUS(__func__);
+ wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
+ .data = global_src_slice,
+ });
+ const char* status =
+ read_file(&src, "test/data/artificial/gif-background-color.gif");
+ if (status) {
+ return status;
+ }
+ int q;
+ for (q = 0; q < 2; q++) {
+ src.meta.ri = 0;
+
+ wuffs_gif__decoder dec;
+ status = wuffs_gif__decoder__initialize(
+ &dec, sizeof dec, WUFFS_VERSION,
+ WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED);
+ if (status) {
+ RETURN_FAIL("q=%d: initialize: \"%s\"", q, status);
+ }
+ wuffs_gif__decoder__set_quirk_enabled(
+ &dec, wuffs_gif__quirk_honor_background_color, q);
+
+ wuffs_base__frame_config fc = ((wuffs_base__frame_config){});
+ status = wuffs_gif__decoder__decode_frame_config(&dec, &fc, &src);
+ if (status) {
+ RETURN_FAIL("q=%d: decode_frame_config: \"%s\"", q, status);
+ }
+
+ wuffs_base__color_u32_argb_premul got =
+ wuffs_base__frame_config__background_color(&fc);
+ wuffs_base__color_u32_argb_premul want = q ? 0xFF80C3C3 : 0x00000000;
+
+ if (got != want) {
+ RETURN_FAIL("q=%d: got 0x%08" PRIX32 ", want 0x%08" PRIX32, q, got, want);
+ }
+ }
+ return NULL;
+}
+
+const char* test_wuffs_gif_decode_first_frame_is_opaque() {
+ CHECK_FOCUS(__func__);
+ wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
+ .data = global_src_slice,
+ });
+ const char* status =
+ read_file(&src, "test/data/artificial/gif-frame-out-of-bounds.gif");
+ if (status) {
+ return status;
+ }
+ int q;
+ for (q = 0; q < 2; q++) {
+ src.meta.ri = 0;
+
+ wuffs_gif__decoder dec;
+ status = wuffs_gif__decoder__initialize(
+ &dec, sizeof dec, WUFFS_VERSION,
+ WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED);
+ if (status) {
+ RETURN_FAIL("q=%d: initialize: \"%s\"", q, status);
+ }
+ wuffs_gif__decoder__set_quirk_enabled(
+ &dec, wuffs_gif__quirk_honor_background_color, q);
+
+ wuffs_base__image_config ic = ((wuffs_base__image_config){});
+ status = wuffs_gif__decoder__decode_image_config(&dec, &ic, &src);
+ if (status) {
+ RETURN_FAIL("q=%d: decode_image_config: \"%s\"", q, status);
+ }
+
+ bool got = wuffs_base__image_config__first_frame_is_opaque(&ic);
+ bool want = q;
+
+ if (got != want) {
+ RETURN_FAIL("q=%d: got %s, want %s", q, got ? "true" : "false",
+ want ? "true" : "false");
+ }
+ }
+ return NULL;
+}
+
const char* test_wuffs_gif_decode_frame_out_of_bounds() {
CHECK_FOCUS(__func__);
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
@@ -731,144 +959,242 @@
return status;
}
- wuffs_gif__decoder dec;
- status = wuffs_gif__decoder__initialize(
- &dec, sizeof dec, WUFFS_VERSION,
- WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED);
- if (status) {
- RETURN_FAIL("initialize: \"%s\"", status);
- }
- wuffs_base__image_config ic = ((wuffs_base__image_config){});
- wuffs_base__io_reader src_reader = wuffs_base__io_buffer__reader(&src);
- status = wuffs_gif__decoder__decode_image_config(&dec, &ic, src_reader);
- if (status) {
- RETURN_FAIL("decode_image_config: \"%s\"", status);
- }
+ int q;
+ for (q = 0; q < 2; q++) {
+ src.meta.ri = 0;
- // The nominal width and height for the overall image is 2×2, but its first
- // frame extends those bounds to 4×2. See
- // test/data/artificial/gif-frame-out-of-bounds.gif.make-artificial.txt for
- // more discussion.
+ wuffs_gif__decoder dec;
+ status = wuffs_gif__decoder__initialize(
+ &dec, sizeof dec, WUFFS_VERSION,
+ WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED);
+ if (status) {
+ RETURN_FAIL("q=%d: initialize: \"%s\"", q, status);
+ }
+ wuffs_gif__decoder__set_quirk_enabled(
+ &dec, wuffs_gif__quirk_image_bounds_are_strict, q);
- const uint32_t width = 4;
- const uint32_t height = 2;
-
- if (wuffs_base__pixel_config__width(&ic.pixcfg) != width) {
- RETURN_FAIL("width: got %" PRIu32 ", want %" PRIu32,
- wuffs_base__pixel_config__width(&ic.pixcfg), width);
- }
- if (wuffs_base__pixel_config__height(&ic.pixcfg) != height) {
- RETURN_FAIL("height: got %" PRIu32 ", want %" PRIu32,
- wuffs_base__pixel_config__height(&ic.pixcfg), height);
- }
-
- wuffs_base__pixel_buffer pb = ((wuffs_base__pixel_buffer){});
- status = wuffs_base__pixel_buffer__set_from_slice(&pb, &ic.pixcfg,
- global_pixel_slice);
- if (status) {
- RETURN_FAIL("set_from_slice: \"%s\"", status);
- }
-
- // See test/data/artificial/gif-frame-out-of-bounds.gif.make-artificial.txt
- // for the want_frame_config_bounds and want_pixel_indexes source.
-
- wuffs_base__rect_ie_u32 want_frame_config_bounds[4] = {
- make_rect_ie_u32(1, 0, 4, 1),
- make_rect_ie_u32(0, 1, 2, 2),
- make_rect_ie_u32(0, 2, 1, 2),
- make_rect_ie_u32(2, 0, 4, 2),
- };
-
- const char* want_pixel_indexes[4] = {
- ".123....",
- "....89..",
- "........",
- "..45..89",
- };
-
- uint32_t i;
- for (i = 0; true; i++) {
- wuffs_base__frame_config fc = ((wuffs_base__frame_config){});
- {
- status = wuffs_gif__decoder__decode_frame_config(&dec, &fc, src_reader);
- if (i == WUFFS_TESTLIB_ARRAY_SIZE(want_frame_config_bounds)) {
- if (status != wuffs_base__warning__end_of_data) {
- RETURN_FAIL("decode_frame_config #%" PRIu32 ": got \"%s\"", i,
- status);
- }
- break;
- }
- if (status) {
- RETURN_FAIL("decode_frame_config #%" PRIu32 ": got \"%s\"", i, status);
- }
-
- wuffs_base__rect_ie_u32 got = wuffs_base__frame_config__bounds(&fc);
- wuffs_base__rect_ie_u32 want = want_frame_config_bounds[i];
- if (!wuffs_base__rect_ie_u32__equals(&got, want)) {
- RETURN_FAIL("decode_frame_config #%" PRIu32 ": bounds: got (%" PRIu32
- ", %" PRIu32 ")-(%" PRIu32 ", %" PRIu32 "), want (%" PRIu32
- ", %" PRIu32 ")-(%" PRIu32 ", %" PRIu32 ")",
- i, got.min_incl_x, got.min_incl_y, got.max_excl_x,
- got.max_excl_y, want.min_incl_x, want.min_incl_y,
- want.max_excl_x, want.max_excl_y);
- }
+ wuffs_base__image_config ic = ((wuffs_base__image_config){});
+ status = wuffs_gif__decoder__decode_image_config(&dec, &ic, &src);
+ if (status) {
+ RETURN_FAIL("q=%d: decode_image_config: \"%s\"", q, status);
}
- {
- wuffs_base__table_u8 p = wuffs_base__pixel_buffer__plane(&pb, 0);
- uint32_t y, x;
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x++) {
- p.ptr[(y * p.stride) + x] = 0;
+ // The nominal width and height for the overall image is 2×2, but its first
+ // frame extends those bounds to 4×2. See
+ // test/data/artificial/gif-frame-out-of-bounds.gif.make-artificial.txt for
+ // more discussion.
+
+ const uint32_t width = q ? 2 : 4;
+ const uint32_t height = 2;
+
+ if (wuffs_base__pixel_config__width(&ic.pixcfg) != width) {
+ RETURN_FAIL("q=%d: width: got %" PRIu32 ", want %" PRIu32, q,
+ wuffs_base__pixel_config__width(&ic.pixcfg), width);
+ }
+ if (wuffs_base__pixel_config__height(&ic.pixcfg) != height) {
+ RETURN_FAIL("q=%d: height: got %" PRIu32 ", want %" PRIu32, q,
+ wuffs_base__pixel_config__height(&ic.pixcfg), height);
+ }
+
+ wuffs_base__pixel_buffer pb = ((wuffs_base__pixel_buffer){});
+ status = wuffs_base__pixel_buffer__set_from_slice(&pb, &ic.pixcfg,
+ global_pixel_slice);
+ if (status) {
+ RETURN_FAIL("q=%d: set_from_slice: \"%s\"", q, status);
+ }
+
+ // See test/data/artificial/gif-frame-out-of-bounds.gif.make-artificial.txt
+ // for the want_frame_config_bounds and want_pixel_indexes source.
+
+ wuffs_base__rect_ie_u32 want_frame_config_bounds[4] = {
+ q ? make_rect_ie_u32(1, 0, 2, 1) : make_rect_ie_u32(1, 0, 4, 1),
+ q ? make_rect_ie_u32(0, 1, 2, 2) : make_rect_ie_u32(0, 1, 2, 2),
+ q ? make_rect_ie_u32(0, 2, 1, 2) : make_rect_ie_u32(0, 2, 1, 2),
+ q ? make_rect_ie_u32(2, 0, 2, 2) : make_rect_ie_u32(2, 0, 4, 2),
+ };
+
+ const char* want_pixel_indexes[4] = {
+ q ? ".1.." : ".123....",
+ q ? "..89" : "....89..",
+ q ? "...." : "........",
+ q ? "...." : "..45..89",
+ };
+
+ uint32_t i;
+ for (i = 0; true; i++) {
+ wuffs_base__frame_config fc = ((wuffs_base__frame_config){});
+ {
+ status = wuffs_gif__decoder__decode_frame_config(&dec, &fc, &src);
+ if (i == WUFFS_TESTLIB_ARRAY_SIZE(want_frame_config_bounds)) {
+ if (status != wuffs_base__warning__end_of_data) {
+ RETURN_FAIL("q=%d: decode_frame_config #%" PRIu32 ": got \"%s\"", q,
+ i, status);
+ }
+ break;
+ }
+ if (status) {
+ RETURN_FAIL("q=%d: decode_frame_config #%" PRIu32 ": got \"%s\"", q,
+ i, status);
+ }
+
+ wuffs_base__rect_ie_u32 got = wuffs_base__frame_config__bounds(&fc);
+ wuffs_base__rect_ie_u32 want = want_frame_config_bounds[i];
+ if (!wuffs_base__rect_ie_u32__equals(&got, want)) {
+ RETURN_FAIL("q=%d: decode_frame_config #%" PRIu32
+ ": bounds: got (%" PRIu32 ", %" PRIu32 ")-(%" PRIu32
+ ", %" PRIu32 "), want (%" PRIu32 ", %" PRIu32
+ ")-(%" PRIu32 ", %" PRIu32 ")",
+ q, i, got.min_incl_x, got.min_incl_y, got.max_excl_x,
+ got.max_excl_y, want.min_incl_x, want.min_incl_y,
+ want.max_excl_x, want.max_excl_y);
}
}
- status = wuffs_gif__decoder__decode_frame(&dec, &pb, src_reader,
- global_work_slice, NULL);
- if (status) {
- RETURN_FAIL("decode_frame #%" PRIu32 ": got \"%s\"", i, status);
- }
-
- wuffs_base__rect_ie_u32 frame_rect =
- wuffs_base__frame_config__bounds(&fc);
- wuffs_base__rect_ie_u32 dirty_rect =
- wuffs_gif__decoder__frame_dirty_rect(&dec);
- if (!wuffs_base__rect_ie_u32__contains_rect(&frame_rect, dirty_rect)) {
- RETURN_FAIL("internal error: frame_rect does not contain dirty_rect");
- }
-
- char got[(width * height) + 1];
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x++) {
- uint8_t index = 0x0F & p.ptr[(y * p.stride) + x];
- got[(y * width) + x] = index ? ('0' + index) : '.';
+ {
+ wuffs_base__table_u8 p = wuffs_base__pixel_buffer__plane(&pb, 0);
+ uint32_t y, x;
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ p.ptr[(y * p.stride) + x] = 0;
+ }
}
- }
- got[width * height] = 0;
- const char* want = want_pixel_indexes[i];
- if (memcmp(got, want, width * height)) {
- RETURN_FAIL("decode_frame #%" PRIu32 ": got \"%s\", want \"%s\"", i,
- got, want);
+ status = wuffs_gif__decoder__decode_frame(&dec, &pb, &src,
+ global_work_slice, NULL);
+ if (status) {
+ RETURN_FAIL("q=%d: decode_frame #%" PRIu32 ": got \"%s\"", q, i,
+ status);
+ }
+
+ wuffs_base__rect_ie_u32 frame_rect =
+ wuffs_base__frame_config__bounds(&fc);
+ wuffs_base__rect_ie_u32 dirty_rect =
+ wuffs_gif__decoder__frame_dirty_rect(&dec);
+ if (!wuffs_base__rect_ie_u32__contains_rect(&frame_rect, dirty_rect)) {
+ RETURN_FAIL(
+ "q=%d: internal error: frame_rect does not contain dirty_rect",
+ q);
+ }
+
+ char got[(width * height) + 1];
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ uint8_t index = 0x0F & p.ptr[(y * p.stride) + x];
+ got[(y * width) + x] = index ? ('0' + index) : '.';
+ }
+ }
+ got[width * height] = 0;
+
+ const char* want = want_pixel_indexes[i];
+ if (memcmp(got, want, width * height)) {
+ RETURN_FAIL("q=%d: decode_frame #%" PRIu32
+ ": got \"%s\", want \"%s\"",
+ q, i, got, want);
+ }
}
}
}
return NULL;
}
-const char* test_wuffs_gif_decode_bgra_nonpremul() {
+const char* test_wuffs_gif_decode_zero_width_frame() {
+ CHECK_FOCUS(__func__);
+ wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
+ .data = global_src_slice,
+ });
+ const char* status =
+ read_file(&src, "test/data/artificial/gif-zero-width-frame.gif");
+ if (status) {
+ return status;
+ }
+ int q;
+ for (q = 0; q < 3; q++) {
+ src.meta.ri = 0;
+
+ wuffs_gif__decoder dec;
+ status = wuffs_gif__decoder__initialize(
+ &dec, sizeof dec, WUFFS_VERSION,
+ WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED);
+ if (status) {
+ RETURN_FAIL("q=%d: initialize: \"%s\"", q, status);
+ }
+
+ const char* want = NULL;
+ switch (q) {
+ case 0:
+ want = wuffs_base__error__too_much_data;
+ break;
+ case 1:
+ want = NULL;
+ wuffs_gif__decoder__set_quirk_enabled(
+ &dec, wuffs_gif__quirk_ignore_too_much_pixel_data, true);
+ break;
+ case 2:
+ want = wuffs_gif__error__bad_frame_size;
+ wuffs_gif__decoder__set_quirk_enabled(
+ &dec, wuffs_gif__quirk_reject_empty_frame, true);
+ break;
+ }
+
+ wuffs_base__image_config ic = ((wuffs_base__image_config){});
+ status = wuffs_gif__decoder__decode_image_config(&dec, &ic, &src);
+ if (status) {
+ RETURN_FAIL("q=%d: decode_image_config: \"%s\"", q, status);
+ }
+
+ wuffs_base__pixel_buffer pb = ((wuffs_base__pixel_buffer){});
+ status = wuffs_base__pixel_buffer__set_from_slice(&pb, &ic.pixcfg,
+ global_pixel_slice);
+ if (status) {
+ RETURN_FAIL("q=%d: set_from_slice: \"%s\"", q, status);
+ }
+
+ const char* got = wuffs_gif__decoder__decode_frame(&dec, &pb, &src,
+ global_work_slice, NULL);
+ if (got != want) {
+ RETURN_FAIL("q=%d: decode_frame: got \"%s\", want \"%s\"", q, got, want);
+ }
+ }
+ return NULL;
+}
+
+const char* test_wuffs_gif_decode_pixfmt_bgr() {
CHECK_FOCUS(__func__);
return do_test_wuffs_gif_decode("test/data/bricks-dither.gif",
"test/data/bricks-dither.palette",
- "test/data/bricks-dither.indexes", 0,
+ "test/data/bricks-dither.indexes", UINT64_MAX,
+ WUFFS_BASE__PIXEL_FORMAT__BGR);
+}
+
+const char* test_wuffs_gif_decode_pixfmt_bgra_nonpremul() {
+ CHECK_FOCUS(__func__);
+ return do_test_wuffs_gif_decode("test/data/bricks-dither.gif",
+ "test/data/bricks-dither.palette",
+ "test/data/bricks-dither.indexes", UINT64_MAX,
WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL);
}
+const char* test_wuffs_gif_decode_pixfmt_rgb() {
+ CHECK_FOCUS(__func__);
+ return do_test_wuffs_gif_decode("test/data/bricks-dither.gif",
+ "test/data/bricks-dither.palette",
+ "test/data/bricks-dither.indexes", UINT64_MAX,
+ WUFFS_BASE__PIXEL_FORMAT__RGB);
+}
+
+const char* test_wuffs_gif_decode_pixfmt_rgba_nonpremul() {
+ CHECK_FOCUS(__func__);
+ return do_test_wuffs_gif_decode("test/data/bricks-dither.gif",
+ "test/data/bricks-dither.palette",
+ "test/data/bricks-dither.indexes", UINT64_MAX,
+ WUFFS_BASE__PIXEL_FORMAT__RGBA_NONPREMUL);
+}
+
const char* test_wuffs_gif_decode_input_is_a_gif_just_one_read() {
CHECK_FOCUS(__func__);
return do_test_wuffs_gif_decode(
"test/data/bricks-dither.gif", "test/data/bricks-dither.palette",
- "test/data/bricks-dither.indexes", 0,
+ "test/data/bricks-dither.indexes", UINT64_MAX,
WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_BINARY);
}
@@ -920,9 +1246,8 @@
RETURN_FAIL("initialize: \"%s\"", status);
}
wuffs_base__image_config ic = ((wuffs_base__image_config){});
- wuffs_base__io_reader src_reader = wuffs_base__io_buffer__reader(&src);
- status = wuffs_gif__decoder__decode_image_config(&dec, &ic, src_reader);
+ status = wuffs_gif__decoder__decode_image_config(&dec, &ic, &src);
if (status != wuffs_gif__error__bad_header) {
RETURN_FAIL("decode_image_config: got \"%s\", want \"%s\"", status,
wuffs_gif__error__bad_header);
@@ -930,6 +1255,163 @@
return NULL;
}
+const char* test_wuffs_gif_decode_metadata() {
+ CHECK_FOCUS(__func__);
+
+ wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
+ .data = global_src_slice,
+ });
+
+ const char* status = read_file(&src, "test/data/artificial/gif-metadata.gif");
+ if (status) {
+ return status;
+ }
+
+ int iccp;
+ for (iccp = 0; iccp < 2; iccp++) {
+ int xmp;
+ for (xmp = 0; xmp < 2; xmp++) {
+ bool seen_iccp = false;
+ bool seen_xmp = false;
+
+ wuffs_gif__decoder dec;
+ status = wuffs_gif__decoder__initialize(
+ &dec, sizeof dec, WUFFS_VERSION,
+ WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED);
+ if (status) {
+ RETURN_FAIL("initialize: \"%s\"", status);
+ }
+
+ if (iccp) {
+ wuffs_gif__decoder__set_report_metadata(&dec, WUFFS_BASE__FOURCC__ICCP,
+ true);
+ }
+ if (xmp) {
+ wuffs_gif__decoder__set_report_metadata(&dec, WUFFS_BASE__FOURCC__XMP,
+ true);
+ }
+
+ wuffs_base__image_config ic = ((wuffs_base__image_config){});
+ src.meta.ri = 0;
+
+ while (true) {
+ status = wuffs_gif__decoder__decode_image_config(&dec, &ic, &src);
+ if (!status) {
+ break;
+ } else if (status != wuffs_base__warning__metadata_reported) {
+ RETURN_FAIL(
+ "decode_image_config (iccp=%d, xmp=%d): got \"%s\", want \"%s\"",
+ iccp, xmp, status, wuffs_base__warning__metadata_reported);
+ }
+
+ const char* want = "";
+ char got_buffer[100];
+ int got_length = 0;
+ uint32_t got_fourcc = wuffs_gif__decoder__metadata_fourcc(&dec);
+
+ switch (wuffs_gif__decoder__metadata_fourcc(&dec)) {
+ case WUFFS_BASE__FOURCC__ICCP:
+ want = "\x16\x26\x36\x46\x56\x76\x86\x96";
+ seen_iccp = true;
+ break;
+ case WUFFS_BASE__FOURCC__XMP:
+ want = "\x05\x17\x27\x37\x47\x57\x03\x77\x87\x97";
+ seen_xmp = true;
+ break;
+ default:
+ RETURN_FAIL(
+ "metadata_fourcc (iccp=%d, xmp=%d): unexpected FourCC "
+ "0x%08" PRIX32,
+ iccp, xmp, got_fourcc);
+ }
+
+ while (true) {
+ uint64_t n = wuffs_gif__decoder__metadata_chunk_length(&dec);
+ if ((n > 100) || (n + got_length > 100)) {
+ RETURN_FAIL(
+ "metadata_chunk_length (iccp=%d, xmp=%d): too much "
+ "metadata (vs buffer size)",
+ iccp, xmp);
+ }
+ if (n > wuffs_base__io_buffer__reader_available(&src)) {
+ RETURN_FAIL(
+ "metadata_chunk_length (iccp=%d, xmp=%d): too much "
+ "metadata (vs available)",
+ iccp, xmp);
+ }
+ memcpy(got_buffer + got_length, src.data.ptr + src.meta.ri, n);
+ got_length += n;
+ src.meta.ri += n;
+
+ status = wuffs_gif__decoder__ack_metadata_chunk(&dec, &src);
+ if (!status) {
+ break;
+ } else if (status != wuffs_base__warning__metadata_reported) {
+ RETURN_FAIL(
+ "ack_metadata_chunk (iccp=%d, xmp=%d): got \"%s\", want \"%s\"",
+ iccp, xmp, status, wuffs_base__warning__metadata_reported);
+ }
+ }
+
+ int want_length = strlen(want);
+ if ((got_length != want_length) ||
+ strncmp(got_buffer, want, want_length)) {
+ RETURN_FAIL("metadata (iccp=%d, xmp=%d): fourcc=0x%08" PRIX32
+ ": values differed",
+ iccp, xmp, got_fourcc);
+ }
+ }
+
+ if (iccp != seen_iccp) {
+ RETURN_FAIL("seen_iccp (iccp=%d, xmp=%d): got %d, want %d", iccp, xmp,
+ seen_iccp, iccp);
+ }
+
+ if (xmp != seen_xmp) {
+ RETURN_FAIL("seen_xmp (iccp=%d, xmp=%d): got %d, want %d", iccp, xmp,
+ seen_xmp, xmp);
+ }
+
+ {
+ uint64_t got = wuffs_base__image_config__first_frame_io_position(&ic);
+ uint64_t want = 25;
+ if (got != want) {
+ RETURN_FAIL("first_frame_io_position: got %" PRIu64 ", want %" PRIu64,
+ got, want);
+ }
+ }
+
+ {
+ uint32_t got = wuffs_gif__decoder__num_animation_loops(&dec);
+ uint32_t want = 2001;
+ if (got != want) {
+ RETURN_FAIL("num_animation_loops: got %" PRIu32 ", want %" PRIu32,
+ got, want);
+ }
+ }
+
+ {
+ wuffs_base__frame_config fc = ((wuffs_base__frame_config){});
+ status = wuffs_gif__decoder__decode_frame_config(&dec, &fc, &src);
+ if (status) {
+ RETURN_FAIL("decode_frame_config (iccp=%d, xmp=%d): %s", iccp, xmp,
+ status);
+ }
+ uint32_t got = wuffs_base__frame_config__width(&fc);
+ uint32_t want = 1;
+ if (got != want) {
+ RETURN_FAIL(
+ "decode_frame_config (iccp=%d, xmp=%d): width: got %" PRIu32
+ ", want %" PRIu32,
+ iccp, xmp, got, want);
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
const char* test_wuffs_gif_decode_missing_two_src_bytes() {
CHECK_FOCUS(__func__);
@@ -949,7 +1431,40 @@
src.meta.wi -= 2;
return do_test_wuffs_gif_decode_expecting(
- src, wuffs_base__suspension__short_read, false);
+ src, 0, wuffs_base__suspension__short_read, false);
+}
+
+const char* test_wuffs_gif_decode_multiple_graphic_controls() {
+ CHECK_FOCUS(__func__);
+ wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
+ .data = global_src_slice,
+ });
+ const char* status =
+ read_file(&src, "test/data/artificial/gif-multiple-graphic-controls.gif");
+ if (status) {
+ return status;
+ }
+
+ wuffs_gif__decoder dec;
+ status = wuffs_gif__decoder__initialize(
+ &dec, sizeof dec, WUFFS_VERSION,
+ WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED);
+ if (status) {
+ RETURN_FAIL("initialize: \"%s\"", status);
+ }
+ wuffs_base__frame_config fc = ((wuffs_base__frame_config){});
+ status = wuffs_gif__decoder__decode_frame_config(&dec, &fc, &src);
+ if (status) {
+ RETURN_FAIL("decode_frame_config: \"%s\"", status);
+ }
+
+ int got = wuffs_base__frame_config__duration(&fc) /
+ WUFFS_BASE__FLICKS_PER_MILLISECOND;
+ int want = 300;
+ if (got != want) {
+ RETURN_FAIL("duration: got %d, want %d", got, want);
+ }
+ return NULL;
}
const char* test_wuffs_gif_decode_multiple_loop_counts() {
@@ -971,8 +1486,7 @@
RETURN_FAIL("initialize: \"%s\"", status);
}
wuffs_base__image_config ic = ((wuffs_base__image_config){});
- wuffs_base__io_reader src_reader = wuffs_base__io_buffer__reader(&src);
- status = wuffs_gif__decoder__decode_image_config(&dec, &ic, src_reader);
+ status = wuffs_gif__decoder__decode_image_config(&dec, &ic, &src);
if (status) {
RETURN_FAIL("decode_image_config: \"%s\"", status);
}
@@ -987,7 +1501,7 @@
uint32_t i;
for (i = 0; true; i++) {
{
- status = wuffs_gif__decoder__decode_frame_config(&dec, NULL, src_reader);
+ status = wuffs_gif__decoder__decode_frame_config(&dec, NULL, &src);
if (i == WUFFS_TESTLIB_ARRAY_SIZE(want_num_animation_loops)) {
if (status != wuffs_base__warning__end_of_data) {
RETURN_FAIL("decode_frame_config #%" PRIu32 ": got \"%s\"", i,
@@ -1033,7 +1547,7 @@
}
return do_test_wuffs_gif_decode_expecting(
- src, wuffs_base__error__not_enough_data, true);
+ src, 0, wuffs_base__error__not_enough_data, true);
}
const char* test_wuffs_gif_decode_pixel_data_not_enough() {
@@ -1050,10 +1564,10 @@
}
return do_test_wuffs_gif_decode_expecting(
- src, wuffs_base__error__not_enough_data, false);
+ src, 0, wuffs_base__error__not_enough_data, false);
}
-const char* test_wuffs_gif_decode_pixel_data_too_much() {
+const char* test_wuffs_gif_decode_pixel_data_too_much_sans_quirk() {
CHECK_FOCUS(__func__);
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
@@ -1067,7 +1581,24 @@
}
return do_test_wuffs_gif_decode_expecting(
- src, wuffs_base__error__too_much_data, false);
+ src, 0, wuffs_base__error__too_much_data, false);
+}
+
+const char* test_wuffs_gif_decode_pixel_data_too_much_with_quirk() {
+ CHECK_FOCUS(__func__);
+
+ wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
+ .data = global_src_slice,
+ });
+
+ const char* status =
+ read_file(&src, "test/data/artificial/gif-pixel-data-too-much.gif");
+ if (status) {
+ return status;
+ }
+
+ return do_test_wuffs_gif_decode_expecting(
+ src, wuffs_gif__quirk_ignore_too_much_pixel_data, NULL, false);
}
const char* test_wuffs_gif_frame_dirty_rect() {
@@ -1091,8 +1622,7 @@
}
wuffs_base__image_config ic = ((wuffs_base__image_config){});
- status = wuffs_gif__decoder__decode_image_config(
- &dec, &ic, wuffs_base__io_buffer__reader(&src));
+ status = wuffs_gif__decoder__decode_image_config(&dec, &ic, &src);
if (status) {
RETURN_FAIL("decode_image_config: \"%s\"", status);
}
@@ -1113,10 +1643,11 @@
int i = 0;
while (true) {
- wuffs_base__io_reader src_reader = wuffs_base__io_buffer__reader(&src);
- set_reader_limit(&src_reader, 1);
- status = wuffs_gif__decoder__decode_frame(&dec, &pb, src_reader,
+ wuffs_base__io_buffer limited_src = make_limited_reader(src, 1);
+
+ status = wuffs_gif__decoder__decode_frame(&dec, &pb, &limited_src,
global_work_slice, NULL);
+ src.meta.ri += limited_src.meta.ri;
wuffs_base__rect_ie_u32 r = wuffs_gif__decoder__frame_dirty_rect(&dec);
if ((i < WUFFS_TESTLIB_ARRAY_SIZE(wants)) && (wants[i] == r.max_excl_y)) {
@@ -1154,12 +1685,11 @@
if (status) {
RETURN_FAIL("initialize: \"%s\"", status);
}
- wuffs_base__io_reader src_reader = wuffs_base__io_buffer__reader(&src);
wuffs_base__pixel_buffer pb = ((wuffs_base__pixel_buffer){});
if (!frame_config) {
wuffs_base__image_config ic = ((wuffs_base__image_config){});
- status = wuffs_gif__decoder__decode_image_config(&dec, &ic, src_reader);
+ status = wuffs_gif__decoder__decode_image_config(&dec, &ic, &src);
if (status) {
RETURN_FAIL("decode_image_config: \"%s\"", status);
}
@@ -1189,9 +1719,9 @@
const char* status = NULL;
if (frame_config) {
- status = wuffs_gif__decoder__decode_frame_config(&dec, NULL, src_reader);
+ status = wuffs_gif__decoder__decode_frame_config(&dec, NULL, &src);
} else {
- status = wuffs_gif__decoder__decode_frame(&dec, &pb, src_reader,
+ status = wuffs_gif__decoder__decode_frame(&dec, &pb, &src,
global_work_slice, NULL);
}
@@ -1237,8 +1767,6 @@
RETURN_FAIL("initialize: \"%s\"", status);
}
- wuffs_base__io_reader src_reader = wuffs_base__io_buffer__reader(&src);
-
if (chunked) {
if (src.meta.wi < 50) {
RETURN_FAIL("src is too short");
@@ -1248,7 +1776,7 @@
src.meta.wi = 30;
src.meta.closed = false;
- status = wuffs_gif__decoder__decode_image_config(&dec, NULL, src_reader);
+ status = wuffs_gif__decoder__decode_image_config(&dec, NULL, &src);
if (status != wuffs_base__suspension__short_read) {
RETURN_FAIL("decode_image_config (chunked): \"%s\"", status);
}
@@ -1265,7 +1793,7 @@
}
}
- status = wuffs_gif__decoder__decode_image_config(&dec, NULL, src_reader);
+ status = wuffs_gif__decoder__decode_image_config(&dec, NULL, &src);
if (status) {
RETURN_FAIL("decode_image_config: \"%s\"", status);
}
@@ -1276,7 +1804,7 @@
int i;
for (i = 0; i < 4; i++) {
fcs[i] = ((wuffs_base__frame_config){});
- status = wuffs_gif__decoder__decode_frame_config(&dec, &fcs[i], src_reader);
+ status = wuffs_gif__decoder__decode_frame_config(&dec, &fcs[i], &src);
if (status) {
RETURN_FAIL("decode_frame_config #%d: \"%s\"", i, status);
}
@@ -1321,7 +1849,7 @@
}
}
- status = wuffs_gif__decoder__decode_frame_config(&dec, NULL, src_reader);
+ status = wuffs_gif__decoder__decode_frame_config(&dec, NULL, &src);
if (status != wuffs_base__warning__end_of_data) {
RETURN_FAIL("decode_frame_config EOD: \"%s\"", status);
}
@@ -1345,7 +1873,7 @@
int j;
for (j = i; j < 4; j++) {
wuffs_base__frame_config fc = ((wuffs_base__frame_config){});
- status = wuffs_gif__decoder__decode_frame_config(&dec, &fc, src_reader);
+ status = wuffs_gif__decoder__decode_frame_config(&dec, &fc, &src);
if (status) {
RETURN_FAIL("decode_frame_config #%d, #%d: \"%s\"", i, j, status);
}
@@ -1365,7 +1893,7 @@
}
}
- status = wuffs_gif__decoder__decode_frame_config(&dec, NULL, src_reader);
+ status = wuffs_gif__decoder__decode_frame_config(&dec, NULL, &src);
if (status != wuffs_base__warning__end_of_data) {
RETURN_FAIL("decode_frame_config EOD #%d: \"%s\"", i, status);
}
@@ -1704,18 +2232,29 @@
test_wuffs_gif_decode_animated_big, //
test_wuffs_gif_decode_animated_medium, //
test_wuffs_gif_decode_animated_small, //
- test_wuffs_gif_decode_bgra_nonpremul, //
+ test_wuffs_gif_decode_background_color, //
+ test_wuffs_gif_decode_delay_num_frames_decoded, //
+ test_wuffs_gif_decode_empty_palette, //
+ test_wuffs_gif_decode_first_frame_is_opaque, //
test_wuffs_gif_decode_frame_out_of_bounds, //
test_wuffs_gif_decode_input_is_a_gif_just_one_read, //
test_wuffs_gif_decode_input_is_a_gif_many_big_reads, //
test_wuffs_gif_decode_input_is_a_gif_many_medium_reads, //
test_wuffs_gif_decode_input_is_a_gif_many_small_reads, //
test_wuffs_gif_decode_input_is_a_png, //
+ test_wuffs_gif_decode_metadata, //
test_wuffs_gif_decode_missing_two_src_bytes, //
+ test_wuffs_gif_decode_multiple_graphic_controls, //
test_wuffs_gif_decode_multiple_loop_counts, //
test_wuffs_gif_decode_pixel_data_none, //
test_wuffs_gif_decode_pixel_data_not_enough, //
- test_wuffs_gif_decode_pixel_data_too_much, //
+ test_wuffs_gif_decode_pixel_data_too_much_sans_quirk, //
+ test_wuffs_gif_decode_pixel_data_too_much_with_quirk, //
+ test_wuffs_gif_decode_pixfmt_bgr, //
+ test_wuffs_gif_decode_pixfmt_bgra_nonpremul, //
+ test_wuffs_gif_decode_pixfmt_rgb, //
+ test_wuffs_gif_decode_pixfmt_rgba_nonpremul, //
+ test_wuffs_gif_decode_zero_width_frame, //
test_wuffs_gif_frame_dirty_rect, //
test_wuffs_gif_num_decoded_frame_configs, //
test_wuffs_gif_num_decoded_frames, //
diff --git a/test/c/std/gzip.c b/test/c/std/gzip.c
index 830d605..89e14c8 100644
--- a/test/c/std/gzip.c
+++ b/test/c/std/gzip.c
@@ -96,20 +96,19 @@
}
while (true) {
- wuffs_base__io_writer dst_writer = wuffs_base__io_buffer__writer(dst);
- if (wlimit) {
- set_writer_limit(&dst_writer, wlimit);
- }
- wuffs_base__io_reader src_reader = wuffs_base__io_buffer__reader(src);
- if (rlimit) {
- set_reader_limit(&src_reader, rlimit);
- }
+ 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(&dec, dst_writer, src_reader,
- global_work_slice);
+ status = wuffs_gzip__decoder__decode_io_writer(
+ &dec, &limited_dst, &limited_src, global_work_slice);
- if ((wlimit && (status == wuffs_base__suspension__short_write)) ||
- (rlimit && (status == wuffs_base__suspension__short_read))) {
+ dst->meta.wi += limited_dst.meta.wi;
+ src->meta.ri += limited_src.meta.ri;
+
+ if (((wlimit < UINT64_MAX) &&
+ (status == wuffs_base__suspension__short_write)) ||
+ ((rlimit < UINT64_MAX) &&
+ (status == wuffs_base__suspension__short_read))) {
continue;
}
return status;
@@ -138,7 +137,7 @@
src.data.ptr[src.meta.wi - 1 - (bad_checksum & 7)] ^= 1;
}
- int end_limit;
+ 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(
@@ -149,14 +148,13 @@
}
wuffs_gzip__decoder__set_ignore_checksum(&dec, ignore_checksum);
got.meta.wi = 0;
- wuffs_base__io_writer got_writer = wuffs_base__io_buffer__writer(&got);
src.meta.ri = 0;
// Decode the src data in 1 or 2 chunks, depending on whether end_limit is
// or isn't zero.
int i;
for (i = 0; i < 2; i++) {
- wuffs_base__io_reader src_reader = wuffs_base__io_buffer__reader(&src);
+ uint64_t rlimit = UINT64_MAX;
const char* want_z = NULL;
if (i == 0) {
if (end_limit == 0) {
@@ -165,7 +163,7 @@
if (src.meta.wi < end_limit) {
RETURN_FAIL("end_limit=%d: not enough source data", end_limit);
}
- set_reader_limit(&src_reader, src.meta.wi - (uint64_t)(end_limit));
+ rlimit = src.meta.wi - (uint64_t)(end_limit);
want_z = wuffs_base__suspension__short_read;
} else {
want_z = (bad_checksum && !ignore_checksum)
@@ -173,8 +171,10 @@
: NULL;
}
+ wuffs_base__io_buffer limited_src = make_limited_reader(src, rlimit);
const char* got_z = wuffs_gzip__decoder__decode_io_writer(
- &dec, got_writer, src_reader, global_work_slice);
+ &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);
@@ -206,12 +206,14 @@
const char* test_wuffs_gzip_decode_midsummer() {
CHECK_FOCUS(__func__);
- return do_test_io_buffers(wuffs_gzip_decode, &gzip_midsummer_gt, 0, 0);
+ return do_test_io_buffers(wuffs_gzip_decode, &gzip_midsummer_gt, UINT64_MAX,
+ UINT64_MAX);
}
const char* test_wuffs_gzip_decode_pi() {
CHECK_FOCUS(__func__);
- return do_test_io_buffers(wuffs_gzip_decode, &gzip_pi_gt, 0, 0);
+ return do_test_io_buffers(wuffs_gzip_decode, &gzip_pi_gt, UINT64_MAX,
+ UINT64_MAX);
}
// ---------------- Mimic Tests
@@ -220,12 +222,14 @@
const char* test_mimic_gzip_decode_midsummer() {
CHECK_FOCUS(__func__);
- return do_test_io_buffers(mimic_gzip_decode, &gzip_midsummer_gt, 0, 0);
+ return do_test_io_buffers(mimic_gzip_decode, &gzip_midsummer_gt, UINT64_MAX,
+ UINT64_MAX);
}
const char* test_mimic_gzip_decode_pi() {
CHECK_FOCUS(__func__);
- return do_test_io_buffers(mimic_gzip_decode, &gzip_pi_gt, 0, 0);
+ return do_test_io_buffers(mimic_gzip_decode, &gzip_pi_gt, UINT64_MAX,
+ UINT64_MAX);
}
#endif // WUFFS_MIMIC
@@ -236,14 +240,14 @@
CHECK_FOCUS(__func__);
return do_bench_io_buffers(
wuffs_gzip_decode, WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED,
- tc_dst, &gzip_midsummer_gt, 0, 0, 300);
+ tc_dst, &gzip_midsummer_gt, UINT64_MAX, UINT64_MAX, 300);
}
const char* bench_wuffs_gzip_decode_100k() {
CHECK_FOCUS(__func__);
return do_bench_io_buffers(
wuffs_gzip_decode, WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED,
- tc_dst, &gzip_pi_gt, 0, 0, 30);
+ tc_dst, &gzip_pi_gt, UINT64_MAX, UINT64_MAX, 30);
}
// ---------------- Mimic Benches
@@ -253,13 +257,13 @@
const char* bench_mimic_gzip_decode_10k() {
CHECK_FOCUS(__func__);
return do_bench_io_buffers(mimic_gzip_decode, 0, tc_dst, &gzip_midsummer_gt,
- 0, 0, 300);
+ UINT64_MAX, UINT64_MAX, 300);
}
const char* bench_mimic_gzip_decode_100k() {
CHECK_FOCUS(__func__);
- return do_bench_io_buffers(mimic_gzip_decode, 0, tc_dst, &gzip_pi_gt, 0, 0,
- 30);
+ return do_bench_io_buffers(mimic_gzip_decode, 0, tc_dst, &gzip_pi_gt,
+ UINT64_MAX, UINT64_MAX, 30);
}
#endif // WUFFS_MIMIC
diff --git a/test/c/std/lzw.c b/test/c/std/lzw.c
index 6b800a7..f156e8e 100644
--- a/test/c/std/lzw.c
+++ b/test/c/std/lzw.c
@@ -118,19 +118,15 @@
int num_iters = 0;
while (true) {
num_iters++;
- wuffs_base__io_writer got_writer = wuffs_base__io_buffer__writer(&got);
- if (wlimit) {
- set_writer_limit(&got_writer, wlimit);
- }
- wuffs_base__io_reader src_reader = wuffs_base__io_buffer__reader(&src);
- if (rlimit) {
- set_reader_limit(&src_reader, rlimit);
- }
+ wuffs_base__io_buffer limited_got = make_limited_writer(got, wlimit);
+ wuffs_base__io_buffer limited_src = make_limited_reader(src, rlimit);
size_t old_wi = got.meta.wi;
size_t old_ri = src.meta.ri;
- status = wuffs_lzw__decoder__decode_io_writer(&dec, got_writer, src_reader,
- global_work_slice);
+ status = wuffs_lzw__decoder__decode_io_writer(
+ &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 (src.meta.ri != src.meta.wi) {
RETURN_FAIL("decode returned \"ok\" but src was not exhausted");
@@ -155,7 +151,7 @@
}
}
- if (wlimit || rlimit) {
+ if ((wlimit < UINT64_MAX) || (rlimit < UINT64_MAX)) {
if (num_iters <= 1) {
RETURN_FAIL("num_iters: got %d, want > 1", num_iters);
}
@@ -172,21 +168,21 @@
CHECK_FOCUS(__func__);
return do_test_wuffs_lzw_decode("test/data/bricks-dither.indexes.giflzw",
14923, "test/data/bricks-dither.indexes",
- 19200, 0, 0);
+ 19200, UINT64_MAX, UINT64_MAX);
}
const char* test_wuffs_lzw_decode_bricks_nodither() {
CHECK_FOCUS(__func__);
return do_test_wuffs_lzw_decode("test/data/bricks-nodither.indexes.giflzw",
13382, "test/data/bricks-nodither.indexes",
- 19200, 0, 0);
+ 19200, UINT64_MAX, UINT64_MAX);
}
const char* test_wuffs_lzw_decode_many_big_reads() {
CHECK_FOCUS(__func__);
return do_test_wuffs_lzw_decode("test/data/bricks-gray.indexes.giflzw", 14731,
- "test/data/bricks-gray.indexes", 19200, 0,
- 4096);
+ "test/data/bricks-gray.indexes", 19200,
+ UINT64_MAX, 4096);
}
const char* test_wuffs_lzw_decode_many_small_writes_reads() {
@@ -199,7 +195,8 @@
const char* test_wuffs_lzw_decode_pi() {
CHECK_FOCUS(__func__);
return do_test_wuffs_lzw_decode("test/data/pi.txt.giflzw", 50550,
- "test/data/pi.txt", 100003, 0, 0);
+ "test/data/pi.txt", 100003, UINT64_MAX,
+ UINT64_MAX);
}
const char* test_wuffs_lzw_decode_output_bad() {
@@ -234,9 +231,8 @@
}
wuffs_lzw__decoder__set_literal_width(&dec, 7);
- status = wuffs_lzw__decoder__decode_io_writer(
- &dec, wuffs_base__io_buffer__writer(&got),
- wuffs_base__io_buffer__reader(&src), global_work_slice);
+ 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);
}
@@ -279,9 +275,8 @@
}
wuffs_lzw__decoder__set_literal_width(&dec, 8);
- status = wuffs_lzw__decoder__decode_io_writer(
- &dec, wuffs_base__io_buffer__writer(&got),
- wuffs_base__io_buffer__reader(&src), global_work_slice);
+ status =
+ wuffs_lzw__decoder__decode_io_writer(&dec, &got, &src, global_work_slice);
if (status) {
RETURN_FAIL("decode: \"%s\"", status);
}
@@ -295,6 +290,93 @@
return NULL;
}
+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);
+ }
+ 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);
+ }
+
+ return check_io_buffers_equal("", &got, &want);
+}
+
+// A zero literal width isn't very practical: the output bytes can only be 0x00
+// and it isn't possible to encode the empty string, as the End code requires
+// two bits but the first non-Clear code after a Clear code has only one bit,
+// so it must be the literal 0x00. Nonetheless, the giflib C library accepts a
+// zero literal width (it only rejects literal widths above 8), so we do too.
+const char* test_wuffs_lzw_decode_width_0() {
+ CHECK_FOCUS(__func__);
+
+ // 0b...._...._...._...1 0x001 Clear code.
+ // 0b...._...._...._..0. 0x000 Literal "0".
+ // 0b...._...._...._11.. 0x011 Back-ref "00"
+ // 0b...._...._.100_.... 0x100 Back-ref "000".
+ // 0b...._..00_0..._.... 0x000 Literal "0".
+ // 0b...0_10.._...._.... 0x010 End code.
+ wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
+ .data = global_src_slice,
+ });
+ src.meta.wi = 2;
+ src.data.ptr[0] = 0x4D;
+ src.data.ptr[1] = 0x08;
+
+ wuffs_base__io_buffer want = ((wuffs_base__io_buffer){
+ .data = global_want_slice,
+ });
+ want.meta.wi = 7;
+ want.data.ptr[0] = 0x00;
+ want.data.ptr[1] = 0x00;
+ want.data.ptr[2] = 0x00;
+ want.data.ptr[3] = 0x00;
+ want.data.ptr[4] = 0x00;
+ want.data.ptr[5] = 0x00;
+ want.data.ptr[6] = 0x00;
+
+ return do_test_wuffs_lzw_decode_width(0, src, want);
+}
+
+const char* test_wuffs_lzw_decode_width_1() {
+ CHECK_FOCUS(__func__);
+
+ // 0b...._...._...._..10 0x010 Clear code.
+ // 0b...._...._...._00.. 0x000 Literal "0".
+ // 0b...._...._.001_.... 0x001 Literal "1".
+ // 0b...._..10_0..._.... 0x100 Back-ref "01".
+ // 0b...0_11.._...._.... 0x011 End code.
+ wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
+ .data = global_src_slice,
+ });
+ src.meta.wi = 2;
+ src.data.ptr[0] = 0x12;
+ src.data.ptr[1] = 0x0E;
+
+ wuffs_base__io_buffer want = ((wuffs_base__io_buffer){
+ .data = global_want_slice,
+ });
+ want.meta.wi = 4;
+ want.data.ptr[0] = 0x00;
+ want.data.ptr[1] = 0x01;
+ want.data.ptr[2] = 0x00;
+ want.data.ptr[3] = 0x01;
+
+ return do_test_wuffs_lzw_decode_width(1, src, want);
+}
+
// ---------------- LZW Benches
const char* do_bench_wuffs_lzw_decode(const char* filename,
@@ -305,8 +387,6 @@
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
.data = global_src_slice,
});
- wuffs_base__io_writer got_writer = wuffs_base__io_buffer__writer(&got);
- wuffs_base__io_reader src_reader = wuffs_base__io_buffer__reader(&src);
const char* status = read_file(&src, filename);
if (status) {
@@ -335,7 +415,7 @@
if (status) {
RETURN_FAIL("initialize: \"%s\"", status);
}
- status = wuffs_lzw__decoder__decode_io_writer(&dec, got_writer, src_reader,
+ status = wuffs_lzw__decoder__decode_io_writer(&dec, &got, &src,
global_work_slice);
if (status) {
RETURN_FAIL("decode: \"%s\"", status);
@@ -368,6 +448,8 @@
test_wuffs_lzw_decode_output_bad, //
test_wuffs_lzw_decode_output_empty, //
test_wuffs_lzw_decode_pi, //
+ test_wuffs_lzw_decode_width_0, //
+ test_wuffs_lzw_decode_width_1, //
NULL,
};
diff --git a/test/c/std/zlib.c b/test/c/std/zlib.c
index 726d4a4..93fa7b2 100644
--- a/test/c/std/zlib.c
+++ b/test/c/std/zlib.c
@@ -96,20 +96,19 @@
}
while (true) {
- wuffs_base__io_writer dst_writer = wuffs_base__io_buffer__writer(dst);
- if (wlimit) {
- set_writer_limit(&dst_writer, wlimit);
- }
- wuffs_base__io_reader src_reader = wuffs_base__io_buffer__reader(src);
- if (rlimit) {
- set_reader_limit(&src_reader, rlimit);
- }
+ 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(&dec, dst_writer, src_reader,
- global_work_slice);
+ status = wuffs_zlib__decoder__decode_io_writer(
+ &dec, &limited_dst, &limited_src, global_work_slice);
- if ((wlimit && (status == wuffs_base__suspension__short_write)) ||
- (rlimit && (status == wuffs_base__suspension__short_read))) {
+ dst->meta.wi += limited_dst.meta.wi;
+ src->meta.ri += limited_src.meta.ri;
+
+ if (((wlimit < UINT64_MAX) &&
+ (status == wuffs_base__suspension__short_write)) ||
+ ((rlimit < UINT64_MAX) &&
+ (status == wuffs_base__suspension__short_read))) {
continue;
}
return status;
@@ -137,7 +136,7 @@
src.data.ptr[src.meta.wi - 1 - (bad_checksum & 3)] ^= 1;
}
- int end_limit;
+ 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(
@@ -148,14 +147,13 @@
}
wuffs_zlib__decoder__set_ignore_checksum(&dec, ignore_checksum);
got.meta.wi = 0;
- wuffs_base__io_writer got_writer = wuffs_base__io_buffer__writer(&got);
src.meta.ri = 0;
// Decode the src data in 1 or 2 chunks, depending on whether end_limit is
// or isn't zero.
int i;
for (i = 0; i < 2; i++) {
- wuffs_base__io_reader src_reader = wuffs_base__io_buffer__reader(&src);
+ uint64_t rlimit = UINT64_MAX;
const char* want_z = NULL;
if (i == 0) {
if (end_limit == 0) {
@@ -164,7 +162,7 @@
if (src.meta.wi < end_limit) {
RETURN_FAIL("end_limit=%d: not enough source data", end_limit);
}
- set_reader_limit(&src_reader, src.meta.wi - (uint64_t)(end_limit));
+ rlimit = src.meta.wi - (uint64_t)(end_limit);
want_z = wuffs_base__suspension__short_read;
} else {
want_z = (bad_checksum && !ignore_checksum)
@@ -172,8 +170,11 @@
: NULL;
}
+ wuffs_base__io_buffer limited_src = make_limited_reader(src, rlimit);
+
const char* got_z = wuffs_zlib__decoder__decode_io_writer(
- &dec, got_writer, src_reader, global_work_slice);
+ &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);
@@ -205,12 +206,14 @@
const char* test_wuffs_zlib_decode_midsummer() {
CHECK_FOCUS(__func__);
- return do_test_io_buffers(wuffs_zlib_decode, &zlib_midsummer_gt, 0, 0);
+ return do_test_io_buffers(wuffs_zlib_decode, &zlib_midsummer_gt, UINT64_MAX,
+ UINT64_MAX);
}
const char* test_wuffs_zlib_decode_pi() {
CHECK_FOCUS(__func__);
- return do_test_io_buffers(wuffs_zlib_decode, &zlib_pi_gt, 0, 0);
+ return do_test_io_buffers(wuffs_zlib_decode, &zlib_pi_gt, UINT64_MAX,
+ UINT64_MAX);
}
// ---------------- Mimic Tests
@@ -219,12 +222,14 @@
const char* test_mimic_zlib_decode_midsummer() {
CHECK_FOCUS(__func__);
- return do_test_io_buffers(mimic_zlib_decode, &zlib_midsummer_gt, 0, 0);
+ return do_test_io_buffers(mimic_zlib_decode, &zlib_midsummer_gt, UINT64_MAX,
+ UINT64_MAX);
}
const char* test_mimic_zlib_decode_pi() {
CHECK_FOCUS(__func__);
- return do_test_io_buffers(mimic_zlib_decode, &zlib_pi_gt, 0, 0);
+ return do_test_io_buffers(mimic_zlib_decode, &zlib_pi_gt, UINT64_MAX,
+ UINT64_MAX);
}
#endif // WUFFS_MIMIC
@@ -235,14 +240,14 @@
CHECK_FOCUS(__func__);
return do_bench_io_buffers(
wuffs_zlib_decode, WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED,
- tc_dst, &zlib_midsummer_gt, 0, 0, 300);
+ tc_dst, &zlib_midsummer_gt, UINT64_MAX, UINT64_MAX, 300);
}
const char* bench_wuffs_zlib_decode_100k() {
CHECK_FOCUS(__func__);
return do_bench_io_buffers(
wuffs_zlib_decode, WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED,
- tc_dst, &zlib_pi_gt, 0, 0, 30);
+ tc_dst, &zlib_pi_gt, UINT64_MAX, UINT64_MAX, 30);
}
// ---------------- Mimic Benches
@@ -252,13 +257,13 @@
const char* bench_mimic_zlib_decode_10k() {
CHECK_FOCUS(__func__);
return do_bench_io_buffers(mimic_zlib_decode, 0, tc_dst, &zlib_midsummer_gt,
- 0, 0, 300);
+ UINT64_MAX, UINT64_MAX, 300);
}
const char* bench_mimic_zlib_decode_100k() {
CHECK_FOCUS(__func__);
- return do_bench_io_buffers(mimic_zlib_decode, 0, tc_dst, &zlib_pi_gt, 0, 0,
- 30);
+ return do_bench_io_buffers(mimic_zlib_decode, 0, tc_dst, &zlib_pi_gt,
+ UINT64_MAX, UINT64_MAX, 30);
}
#endif // WUFFS_MIMIC
diff --git a/test/c/testlib/testlib.c b/test/c/testlib/testlib.c
index a6b17d3..30a8389 100644
--- a/test/c/testlib/testlib.c
+++ b/test/c/testlib/testlib.c
@@ -366,32 +366,40 @@
return ret;
}
-void set_reader_limit(wuffs_base__io_reader* o, uint64_t limit) {
- if (o && o->private_impl.buf) {
- uint8_t* p = o->private_impl.buf->data.ptr + o->private_impl.buf->meta.ri;
- uint8_t* q = o->private_impl.buf->data.ptr + o->private_impl.buf->meta.wi;
- if (!o->private_impl.mark) {
- o->private_impl.mark = p;
- o->private_impl.limit = q;
- }
- if ((o->private_impl.limit - p) > limit) {
- o->private_impl.limit = p + limit;
- }
+wuffs_base__io_buffer make_limited_reader(wuffs_base__io_buffer b,
+ uint64_t limit) {
+ uint64_t n = b.meta.wi - b.meta.ri;
+ bool closed = b.meta.closed;
+ if (n > limit) {
+ n = limit;
+ closed = false;
}
+
+ wuffs_base__io_buffer ret;
+ ret.data.ptr = b.data.ptr + b.meta.ri;
+ ret.data.len = n;
+ ret.meta.wi = n;
+ ret.meta.ri = 0;
+ ret.meta.pos = wuffs_base__u64__sat_add(b.meta.pos, b.meta.ri);
+ ret.meta.closed = closed;
+ return ret;
}
-void set_writer_limit(wuffs_base__io_writer* o, uint64_t limit) {
- if (o && o->private_impl.buf) {
- uint8_t* p = o->private_impl.buf->data.ptr + o->private_impl.buf->meta.wi;
- uint8_t* q = o->private_impl.buf->data.ptr + o->private_impl.buf->data.len;
- if (!o->private_impl.mark) {
- o->private_impl.mark = p;
- o->private_impl.limit = q;
- }
- if ((o->private_impl.limit - p) > limit) {
- o->private_impl.limit = p + limit;
- }
+wuffs_base__io_buffer make_limited_writer(wuffs_base__io_buffer b,
+ uint64_t limit) {
+ uint64_t n = b.data.len - b.meta.wi;
+ if (n > limit) {
+ n = limit;
}
+
+ wuffs_base__io_buffer ret;
+ ret.data.ptr = b.data.ptr + b.meta.wi;
+ ret.data.len = n;
+ ret.meta.wi = 0;
+ ret.meta.ri = 0;
+ ret.meta.pos = wuffs_base__u64__sat_add(b.meta.pos, b.meta.wi);
+ ret.meta.closed = b.meta.closed;
+ return ret;
}
// TODO: we shouldn't need to pass the rect. Instead, pass a subset pixbuf.
diff --git a/test/data/artificial/deflate-degenerate-huffman-unused.deflate b/test/data/artificial/deflate-degenerate-huffman-unused.deflate
new file mode 100644
index 0000000..4751683
--- /dev/null
+++ b/test/data/artificial/deflate-degenerate-huffman-unused.deflate
Binary files differ
diff --git a/test/data/artificial/deflate-degenerate-huffman-unused.deflate.commentary.txt b/test/data/artificial/deflate-degenerate-huffman-unused.deflate.commentary.txt
new file mode 100644
index 0000000..52698b3
--- /dev/null
+++ b/test/data/artificial/deflate-degenerate-huffman-unused.deflate.commentary.txt
@@ -0,0 +1,66 @@
+Running deflate-degenerate-huffman-unused.deflate through script/print-bits.go
+and adding commentary:
+
+ offset xoffset ASCII hex binary
+ 000000 0x0000 . 0x05 0b_...._.101 Dynamic Huffman block, final
+ 000000 0x0000 . 0x04 0b_0000_0... NumLCodes: 257
+ 000001 0x0001 . 0xC0 0b_...0_0000 NumDCodes: 1
+ 000001 0x0001 . 0xC0 0b_110._.... NumCLCodeLengths: 18
+ 000002 0x0002 ! 0x21 0b_...._...1
+
+Decode the H-CL Huffman table (NumCLCodeLengths = 18). Recall the peculiar
+code_order: 16, 17, 18, 0, 8, ..., 2, 14, 1, 15:
+
+ 000002 0x0002 ! 0x21 0b_0010_000. CLCodeLengths: 18 x 3 bits
+ 000003 0x0003 . 0x01 0b_0000_0001 CLCLs[ 1] is 2
+ 000004 0x0004 . 0x00 0b_0000_0000 CLCLs[ 2] is 2
+ 000005 0x0005 . 0x00 0b_0000_0000 CLCLs[17] is 2
+ 000006 0x0006 . 0x00 0b_0000_0000 CLCLs[18] is 2
+ 000007 0x0007 . 0x80 0b_1000_0000
+ 000008 0x0008 . 0xA0 0b_.010_0000
+
+The H-CL Huffman table is:
+"00" -> CodeLength=1
+"01" -> CodeLength=2
+"10" -> CodeLength=17 which means a block of ( 3 + 3_extra_bits) zeroes
+"11" -> CodeLength=18 which means a block of (11 + 7_extra_bits) zeroes
+
+Decode the H-L Huffman table (NumLCodes = 257):
+
+ 000008 0x0008 . 0xA0 0b_1..._.... "11" is CL=18: 11+7extra
+ 000009 0x0009 . 0xB7 0b_...._...1
+ 000009 0x0009 . 0xB7 0b_1011_011. 7extra=91: 102 zeroes
+ 000010 0x000A V 0x56 0b_...._..10 "01" is CL= 2 (102='f')
+ 000010 0x000A V 0x56 0b_...._01.. "10" is CL=17: 3+3extra
+ 000010 0x000A V 0x56 0b_.101_.... 3extra=5: 8 zeroes
+ 000010 0x000A V 0x56 0b_0..._.... "00" is CL= 1 (111='o')
+ 000011 0x000B . 0xFE 0b_...._...0
+ 000011 0x000B . 0xFE 0b_...._.11. "11" is CL=18: 11+7extra
+ 000011 0x000B . 0xFE 0b_1111_1... 7extra=127: 138 zeroes
+ 000012 0x000C 7 0x37 0b_...._..11
+ 000012 0x000C 7 0x37 0b_...._01.. "10" is CL=17: 3+3extra
+ 000012 0x000C 7 0x37 0b_.011_.... 3extra=3: 6 zeroes
+ 000012 0x000C 7 0x37 0b_0..._.... "01" is CL=2 (256=EOB)
+ 000013 0x000D . 0x89 0b_...._...1
+
+The H-L Huffman table is:
+"0" -> 'o'
+"10" -> 'f'
+"11" -> EOB
+
+Decode the H-D Huffman table (NumDCodes = 1):
+
+ 000013 0x000D . 0x89 0b_...._.00. "00" is CL= 1 (DCode 0)
+
+The H-D Huffman table is:
+"0" -> 0
+This table is incomplete: there is no entry starting with a "1" bit. It is
+therefore degenerate, but not used below.
+
+Apply H-L and H-D.
+
+ 000013 0x000D . 0x89 0b_...0_1... lcode: 102 literal 'f'
+ 000013 0x000D . 0x89 0b_..0._.... lcode: 111 literal 'o'
+ 000013 0x000D . 0x89 0b_.0.._.... lcode: 111 literal 'o'
+ 000013 0x000D . 0x89 0b_1..._.... lcode: 256 end of block
+ 000014 0x000E . 0x01 0b_...._...1
diff --git a/test/data/artificial/deflate-degenerate-huffman-unused.deflate.make-artificial.txt b/test/data/artificial/deflate-degenerate-huffman-unused.deflate.make-artificial.txt
new file mode 100644
index 0000000..ba90dd8
--- /dev/null
+++ b/test/data/artificial/deflate-degenerate-huffman-unused.deflate.make-artificial.txt
@@ -0,0 +1,31 @@
+# Feed this file to script/make-artificial.go
+
+make deflate
+
+blockDynamicHuffman (final) {
+ numLCodes 257
+ numDCodes 1
+ numCLCodeLengths 18
+
+ huffman CodeLength {
+ 1 00
+ 2 01
+ 17 10
+ 18 11
+ }
+
+ huffman Length/Literal {
+ # 102='f', 111='o', 256=EOB
+ 111 0
+ 102 10
+ 256 11
+ }
+
+ huffman Distance {
+ # Incomplete. There is no key/value pair whose value starts with "1".
+ 0 0
+ }
+
+ literal "foo"
+ endOfBlock
+}
diff --git a/test/data/artificial/deflate-distance-32768.deflate.commentary.txt b/test/data/artificial/deflate-distance-32768.deflate.commentary.txt
index 84a30b2..fb5d94e 100644
--- a/test/data/artificial/deflate-distance-32768.deflate.commentary.txt
+++ b/test/data/artificial/deflate-distance-32768.deflate.commentary.txt
@@ -18,7 +18,7 @@
000019 0x0013 . 0xE9 0b_...._...1
000019 0x0013 . 0xE9 0b_..10_100. dcode: 5 base: 7
000019 0x0013 . 0xE9 0b_.1.._.... extra: 1 distance: 8
- etc
+ etc
000236 0x00EC . 0xE9 0b_1..._.... lcode: 284 base: 227
000237 0x00ED . 0x91 0b_.001_0001
000237 0x00ED . 0x91 0b_1..._.... extra: 17 length: 244
diff --git a/test/data/artificial/gif-background-color.gif b/test/data/artificial/gif-background-color.gif
new file mode 100644
index 0000000..d25e59e
--- /dev/null
+++ b/test/data/artificial/gif-background-color.gif
Binary files differ
diff --git a/test/data/artificial/gif-background-color.gif.make-artificial.txt b/test/data/artificial/gif-background-color.gif.make-artificial.txt
new file mode 100644
index 0000000..10c4c38
--- /dev/null
+++ b/test/data/artificial/gif-background-color.gif.make-artificial.txt
@@ -0,0 +1,34 @@
+# Feed this file to script/make-artificial.go
+
+make gif
+
+header
+
+image {
+ imageWidthHeight 4 1
+ backgroundColorIndex 3
+ palette {
+ 0x80 0x00 0x00
+ 0x80 0x00 0xC1
+ 0x80 0xC2 0x00
+ 0x80 0xC3 0xC3
+ }
+}
+
+loopCount 1
+
+graphicControl animationDisposalRestoreBackground 100ms
+
+frame {
+ frameLeftTopWidthHeight 0 0 2 1
+}
+lzw 2 0x00 0x01
+
+graphicControl animationDisposalRestoreBackground 200ms
+
+frame {
+ frameLeftTopWidthHeight 2 0 1 1
+}
+lzw 2 0x02
+
+trailer
diff --git a/test/data/artificial/gif-empty-palette.gif b/test/data/artificial/gif-empty-palette.gif
new file mode 100644
index 0000000..b26bd84
--- /dev/null
+++ b/test/data/artificial/gif-empty-palette.gif
Binary files differ
diff --git a/test/data/artificial/gif-empty-palette.gif.make-artificial.txt b/test/data/artificial/gif-empty-palette.gif.make-artificial.txt
new file mode 100644
index 0000000..bc114a6
--- /dev/null
+++ b/test/data/artificial/gif-empty-palette.gif.make-artificial.txt
@@ -0,0 +1,33 @@
+# Feed this file to script/make-artificial.go
+
+# This GIF image has two frames. There is no global palette, and only the first
+# frame has a local palette.
+#
+# Wuffs implicitly gives the second frame an all-opaque-black palette by
+# default. Wuffs can be configured to reject it instead, by enabling a 'quirk'.
+
+make gif
+
+header
+
+image {
+ imageWidthHeight 1 1
+}
+
+frame {
+ frameLeftTopWidthHeight 0 0 1 1
+ palette {
+ 0x00 0x00 0xFF
+ 0x11 0x00 0xFF
+ 0x22 0x00 0xFF
+ 0x33 0x00 0xFF
+ }
+}
+lzw 2 0x00
+
+frame {
+ frameLeftTopWidthHeight 0 0 1 1
+}
+lzw 2 0x00
+
+trailer
diff --git a/test/data/artificial/gif-frame-out-of-bounds.gif.make-artificial.txt b/test/data/artificial/gif-frame-out-of-bounds.gif.make-artificial.txt
index 20ce402..da7111c 100644
--- a/test/data/artificial/gif-frame-out-of-bounds.gif.make-artificial.txt
+++ b/test/data/artificial/gif-frame-out-of-bounds.gif.make-artificial.txt
@@ -47,7 +47,8 @@
# - giflib enforces no particular policy. It provides image and frame bounds
# as encoded in the file and leaves it up to the caller how to respond.
#
-# Wuffs chooses policy 4, the same as Chromium.
+# Wuffs chooses policy 4 by default, the same as Chromium. Wuffs can be
+# configured to choose policy 1, by enabling a 'quirk'.
make gif
diff --git a/test/data/artificial/gif-metadata.gif b/test/data/artificial/gif-metadata.gif
new file mode 100644
index 0000000..8d01384
--- /dev/null
+++ b/test/data/artificial/gif-metadata.gif
Binary files differ
diff --git a/test/data/artificial/gif-metadata.gif.make-artificial.txt b/test/data/artificial/gif-metadata.gif.make-artificial.txt
new file mode 100644
index 0000000..197f857
--- /dev/null
+++ b/test/data/artificial/gif-metadata.gif.make-artificial.txt
@@ -0,0 +1,54 @@
+# Feed this file to script/make-artificial.go
+
+make gif
+
+header
+
+image {
+ imageWidthHeight 2 2
+ palette {
+ 0x00 0x00 0xFF
+ 0x11 0x00 0xFF
+ 0x22 0x00 0xFF
+ 0x33 0x00 0xFF
+ }
+}
+
+# ICCP metadata.
+#
+# Extension (Application Extension), 11 bytes for AI and AAC.
+bytes 0x21 0xFF 0x0B
+# Application Identifier "ICCRGBG1".
+bytes 0x49 0x43 0x43 0x52 0x47 0x42 0x47 0x31
+# Application Authentication Code "012".
+bytes 0x30 0x31 0x32
+# A block of arbitrary data.
+bytes 0x05 0x16 0x26 0x36 0x46 0x56
+# Another block of arbitrary data.
+bytes 0x03 0x76 0x86 0x96
+# Block Terminator.
+bytes 0x00
+
+# XMP metadata.
+#
+# Extension (Application Extension), 11 bytes for AI and AAC.
+bytes 0x21 0xFF 0x0B
+# Application Identifier "XMP Data".
+bytes 0x58 0x4D 0x50 0x20 0x44 0x61 0x74 0x61
+# Application Authentication Code "XMP".
+bytes 0x58 0x4D 0x50
+# A block of arbitrary data.
+bytes 0x05 0x17 0x27 0x37 0x47 0x57
+# Another block of arbitrary data.
+bytes 0x03 0x77 0x87 0x97
+# Block Terminator.
+bytes 0x00
+
+loopCount 2000
+
+frame {
+ frameLeftTopWidthHeight 1 0 1 1
+}
+lzw 4 0x01
+
+trailer
diff --git a/test/data/artificial/gif-multiple-graphic-controls.gif b/test/data/artificial/gif-multiple-graphic-controls.gif
new file mode 100644
index 0000000..ca49790
--- /dev/null
+++ b/test/data/artificial/gif-multiple-graphic-controls.gif
Binary files differ
diff --git a/test/data/artificial/gif-multiple-graphic-controls.gif.make-artificial.txt b/test/data/artificial/gif-multiple-graphic-controls.gif.make-artificial.txt
new file mode 100644
index 0000000..cd36eed
--- /dev/null
+++ b/test/data/artificial/gif-multiple-graphic-controls.gif.make-artificial.txt
@@ -0,0 +1,31 @@
+# Feed this file to script/make-artificial.go
+
+# This GIF image contains multiple "Graphic Control Extensions" for a frame.
+#
+# The GIF89a specification says that "at most one Graphic Control Extension may
+# precede a graphic rendering block", but in practice, some encoders emit more
+# than one, and decoders ignore all but the last one.
+
+make gif
+
+header
+
+image {
+ imageWidthHeight 1 1
+ palette {
+ 0x00 0x00 0xFF
+ 0x11 0x00 0xFF
+ 0x22 0x00 0xFF
+ 0x33 0x00 0xFF
+ }
+}
+
+graphicControl animationDisposalNone 200ms
+graphicControl animationDisposalNone 300ms
+
+frame {
+ frameLeftTopWidthHeight 0 0 1 1
+}
+lzw 2 0x00
+
+trailer
diff --git a/test/data/artificial/gif-multiple-loop-counts.gif.make-artificial.txt b/test/data/artificial/gif-multiple-loop-counts.gif.make-artificial.txt
index 4ed6cf2..75b9647 100644
--- a/test/data/artificial/gif-multiple-loop-counts.gif.make-artificial.txt
+++ b/test/data/artificial/gif-multiple-loop-counts.gif.make-artificial.txt
@@ -1,5 +1,30 @@
# Feed this file to script/make-artificial.go
+# This GIF image contains multiple "loop count" entries.
+#
+# The GIF89a specification doesn't discuss loop counts: it is an extension to
+# the format. Neither the official spec nor unofficial documents (e.g.
+# http://www.vurdalakov.net/misc/gif/netscape-looping-application-extension)
+# state how to interpret having more than one of them: whether to accept the
+# first, accept the last, reject the overall animated image as invalid, etc.
+# Different spec-compliant decoders can choose different policies.
+#
+# Wuffs reports the most recent loop count seen, which may change over the
+# course of stepping through the frames. Programs that use Wuffs may enforce
+# their own policy (e.g. accept first, accept last, etc.) on top of that.
+#
+# Note also that the loop count as written in the GIF file format has "excludes"
+# semantics: it is the number of times to repeat the animation excluding the
+# initial play-through (and 0 means to loop forever). An "excludes" loop count
+# of 3 means to play each animation frame 4 times. An absent loop count means to
+# play each animation frame exactly once.
+#
+# Wuffs' API provides "includes" semantics, across all of its supported
+# animation file formats. An "includes" loop count of 3 means to play each
+# animation frame 3 times. There is no absent option. Wuffs' numbers and GIF's
+# numbers will generally differ by 1 (other than the absent case, and both
+# using 0 to mean forever).
+
make gif
header
diff --git a/test/data/artificial/gif-zero-width-frame.gif b/test/data/artificial/gif-zero-width-frame.gif
new file mode 100644
index 0000000..b88b4b4
--- /dev/null
+++ b/test/data/artificial/gif-zero-width-frame.gif
Binary files differ
diff --git a/test/data/artificial/gif-zero-width-frame.gif.make-artificial.txt b/test/data/artificial/gif-zero-width-frame.gif.make-artificial.txt
new file mode 100644
index 0000000..a7d16b5
--- /dev/null
+++ b/test/data/artificial/gif-zero-width-frame.gif.make-artificial.txt
@@ -0,0 +1,23 @@
+# Feed this file to script/make-artificial.go
+
+make gif
+
+header
+
+image {
+ imageWidthHeight 2 2
+ palette {
+ 0x00 0x00 0xFF
+ 0x11 0x00 0xFF
+ 0x22 0x00 0xFF
+ 0x33 0x00 0xFF
+ }
+}
+
+frame {
+ frameLeftTopWidthHeight 0 0 0 0
+}
+# The frame is 0 pixels, but we supply 1.
+lzw 2 0x00
+
+trailer