Merge pull request #27 from Leo-Neat/master
Add CIFuzz
diff --git a/doc/changelog.md b/doc/changelog.md
index c6190d6..b6a3061 100644
--- a/doc/changelog.md
+++ b/doc/changelog.md
@@ -16,6 +16,7 @@
- Added `WUFFS_BASE__PIXEL_FORMAT__BGR_565`.
- Added interfaces.
- Added preprocessor.
+- Added single-quoted strings.
- Added tokens.
- Changed `gif.decoder_workbuf_len_max_incl_worst_case` from 1 to 0.
- Made `wuffs_base__pixel_format` a struct.
diff --git a/doc/note/auto-formatting.md b/doc/note/auto-formatting.md
index f6eee02..ad9470a 100644
--- a/doc/note/auto-formatting.md
+++ b/doc/note/auto-formatting.md
@@ -4,3 +4,15 @@
- `C` code is formatted by `clang-format-5.0 -style=Chromium`.
- `Go` code is formatted by `gofmt`.
- `Wuffs` code is formatted by [`wuffsfmt`](/cmd/wuffsfmt).
+
+Some C code has empty `//` line-comments, which look superfluous at first, but
+force clang-format to break the line. This ensures one element per line (in a
+long list) or having a function's name (not just its type) start a line. For
+example, `grep ^wuffs_base__utf_8_ release/c/wuffs-unsupported-snapshot.c` (and
+note the `^`) gives you a rough overview of Wuffs' UTF-8 related functions,
+because of the forced line breaks:
+
+```
+size_t //
+wuffs_base__utf_8__encode(wuffs_base__slice_u8 dst, uint32_t code_point);
+```
diff --git a/doc/wuffs-the-language.md b/doc/wuffs-the-language.md
index 54c7cb3..1c081b4 100644
--- a/doc/wuffs-the-language.md
+++ b/doc/wuffs-the-language.md
@@ -22,9 +22,6 @@
- [Iterate loops](/doc/note/iterate-loops.md).
- Public vs private API is marked with the `pub` and `pri` keywords. Visibility
boundaries are at the package level, unlike C++ or Java's type level.
-- No string type, only [slices](/doc/note/slices-arrays-and-tables.md) of
- `base.u8`. Literals like `"#bad checksum"` are actually
- [statuses](/doc/note/statuses.md).
- No variable shadowing. All local variables must be declared before any other
statements in a function body.
- Like Go, semi-colons can be omitted. Similarly, the `()` parentheses around
@@ -88,6 +85,34 @@
The `as` operator, e.g. `x as T`, converts an expression `x` to the type `T`.
+## Strings
+
+There is no string type. There are [arrays and
+slices](/doc/note/slices-arrays-and-tables.md) of bytes (`base.u8`s), but bear
+in mind that Wuffs code cannot [allocate or free
+memory](/doc/note/memory-safety.md).
+
+Double-quoted literals like `"#bad checksum"` are actually
+[statuses](/doc/note/statuses.md), [axiom names](/doc/note/assertions.md) or a
+`use "std/foo"` package name.
+
+Single-quoted literals are actually numerical constants. For example, `'A'` and
+`'\t'` are equivalent to `0x41` and `0x09`. These literals are not restricted
+to a single ASCII byte or even a single Unicode code point, and can decode to
+multiple bytes when finished with a `be` or `le` endianness suffix. For
+example, `'\x01\x02'be` is equivalent to `0x0102`. Similarly, `'\u0394?'le`
+(which can also be written `'Δ?'le`) is equivalent to `0x3F94CE`, because the
+UTF-8 encodings of U+0394 GREEK CAPITAL LETTER DELTA and U+003F QUESTION MARK
+(the ASCII `?`) is `(0xCE, 0x94)` and `(0x3F)`.
+
+Double-quoted literals cannot contain backslashes, as they'd be an unnecessary
+complication. Single-quoted literals can contain backslash-escapes, as they are
+often compared with arbitrary binary data. For example, where other programming
+languages would check if JPEG data starts with the magic _string_ `"\xFF\xD8"`,
+Wuffs would check if its opening 2 bytes, read as a little-endian `base.u16`,
+is a _number_ that equals `'\xFF\xD8'le`.
+
+
## Introductory Example
A simple Wuffs the Language program, unrelated to Wuffs the Library, is
diff --git a/example/crc32/crc32.cc b/example/crc32/crc32.cc
index dd4089a..49f4a09 100644
--- a/example/crc32/crc32.cc
+++ b/example/crc32/crc32.cc
@@ -54,7 +54,7 @@
#define SRC_BUFFER_ARRAY_SIZE (32 * 1024)
#endif
-uint8_t src_buffer_array[SRC_BUFFER_ARRAY_SIZE];
+uint8_t g_src_buffer_array[SRC_BUFFER_ARRAY_SIZE];
int //
main(int argc, char** argv) {
@@ -66,10 +66,10 @@
}
while (true) {
- size_t n =
- fread(src_buffer_array, sizeof(uint8_t), SRC_BUFFER_ARRAY_SIZE, stdin);
+ size_t n = fread(g_src_buffer_array, sizeof(uint8_t), SRC_BUFFER_ARRAY_SIZE,
+ stdin);
uint32_t checksum =
- h.update_u32(wuffs_base__make_slice_u8(src_buffer_array, n));
+ h.update_u32(wuffs_base__make_slice_u8(g_src_buffer_array, n));
if (feof(stdin)) {
printf("%08" PRIx32 "\n", checksum);
return 0;
diff --git a/example/gifplayer/gifplayer.c b/example/gifplayer/gifplayer.c
index 01f599c..0ad7154 100644
--- a/example/gifplayer/gifplayer.c
+++ b/example/gifplayer/gifplayer.c
@@ -41,16 +41,16 @@
#include <unistd.h>
#define WUFFS_EXAMPLE_USE_TIMERS
-bool started = false;
-struct timespec start_time = {0};
+bool g_started = false;
+struct timespec g_start_time = {0};
int64_t //
micros_since_start(struct timespec* now) {
- if (!started) {
+ if (!g_started) {
return 0;
}
- int64_t nanos = (int64_t)(now->tv_sec - start_time.tv_sec) * 1000000000 +
- (int64_t)(now->tv_nsec - start_time.tv_nsec);
+ int64_t nanos = (int64_t)(now->tv_sec - g_start_time.tv_sec) * 1000000000 +
+ (int64_t)(now->tv_nsec - g_start_time.tv_nsec);
if (nanos < 0) {
return 0;
}
@@ -109,29 +109,29 @@
#define MAX_DIMENSION (4096)
#endif
-uint8_t src_buffer_array[SRC_BUFFER_ARRAY_SIZE] = {0};
-size_t src_len = 0;
+uint8_t g_src_buffer_array[SRC_BUFFER_ARRAY_SIZE] = {0};
+size_t g_src_len = 0;
-uint8_t* curr_dst_buffer = NULL;
-uint8_t* prev_dst_buffer = NULL;
-size_t dst_len; // Length in bytes.
+uint8_t* g_curr_dst_buffer = NULL;
+uint8_t* g_prev_dst_buffer = NULL;
+size_t g_dst_len; // Length in bytes.
-wuffs_base__slice_u8 workbuf = {0};
-wuffs_base__slice_u8 printbuf = {0};
+wuffs_base__slice_u8 g_workbuf = {0};
+wuffs_base__slice_u8 g_printbuf = {0};
-bool first_play = true;
-uint32_t num_loops_remaining = 0;
-wuffs_base__image_config ic = {0};
-wuffs_base__pixel_buffer pb = {0};
+bool g_first_play = true;
+uint32_t g_num_loops_remaining = 0;
+wuffs_base__image_config g_ic = {0};
+wuffs_base__pixel_buffer g_pb = {0};
-wuffs_base__flicks cumulative_delay_micros = 0;
+wuffs_base__flicks g_cumulative_delay_micros = 0;
const char* //
read_stdin() {
- while (src_len < SRC_BUFFER_ARRAY_SIZE) {
- size_t n = fread(src_buffer_array + src_len, sizeof(uint8_t),
- SRC_BUFFER_ARRAY_SIZE - src_len, stdin);
- src_len += n;
+ while (g_src_len < SRC_BUFFER_ARRAY_SIZE) {
+ size_t n = fread(g_src_buffer_array + g_src_len, sizeof(uint8_t),
+ SRC_BUFFER_ARRAY_SIZE - g_src_len, stdin);
+ g_src_len += n;
if (feof(stdin)) {
return NULL;
} else if (ferror(stdin)) {
@@ -149,7 +149,7 @@
bool color;
bool quirk_honor_background_color;
-} flags = {0};
+} g_flags = {0};
const char* //
parse_flags(int argc, char** argv) {
@@ -174,19 +174,19 @@
}
if (!strcmp(arg, "c") || !strcmp(arg, "color")) {
- flags.color = true;
+ g_flags.color = true;
continue;
}
if (!strcmp(arg, "quirk_honor_background_color")) {
- flags.quirk_honor_background_color = true;
+ g_flags.quirk_honor_background_color = true;
continue;
}
return "main: unrecognized flag argument";
}
- flags.remaining_argc = argc - c;
- flags.remaining_argv = argv + c;
+ g_flags.remaining_argc = argc - c;
+ g_flags.remaining_argv = argv + c;
return NULL;
}
@@ -198,7 +198,7 @@
// "\xE2\x96\x88" of "█", U+2588 FULL BLOCK.
#define BYTES_PER_COLOR_PIXEL 32
-const char* reset_color = "\x1B[0m";
+const char* g_reset_color = "\x1B[0m";
void //
restore_background(wuffs_base__pixel_buffer* pb,
@@ -208,7 +208,7 @@
size_t y;
for (y = bounds.min_incl_y; y < bounds.max_excl_y; y++) {
size_t x;
- uint8_t* d = curr_dst_buffer + (y * width4) + (bounds.min_incl_x * 4);
+ uint8_t* d = g_curr_dst_buffer + (y * width4) + (bounds.min_incl_x * 4);
for (x = bounds.min_incl_x; x < bounds.max_excl_x; x++) {
wuffs_base__store_u32le__no_bounds_check(d, background_color);
d += sizeof(wuffs_base__color_u32_argb_premul);
@@ -221,8 +221,8 @@
uint32_t width = wuffs_base__pixel_config__width(&pb->pixcfg);
uint32_t height = wuffs_base__pixel_config__height(&pb->pixcfg);
- uint8_t* d = curr_dst_buffer;
- uint8_t* p = printbuf.ptr;
+ uint8_t* d = g_curr_dst_buffer;
+ uint8_t* p = g_printbuf.ptr;
*p++ = '\n';
uint32_t y;
for (y = 0; y < height; y++) {
@@ -242,7 +242,7 @@
}
*p++ = '\n';
}
- return p - printbuf.ptr;
+ return p - g_printbuf.ptr;
}
size_t //
@@ -250,10 +250,10 @@
uint32_t width = wuffs_base__pixel_config__width(&pb->pixcfg);
uint32_t height = wuffs_base__pixel_config__height(&pb->pixcfg);
- uint8_t* d = curr_dst_buffer;
- uint8_t* p = printbuf.ptr;
+ uint8_t* d = g_curr_dst_buffer;
+ uint8_t* p = g_printbuf.ptr;
*p++ = '\n';
- p += sprintf((char*)p, "%s", reset_color);
+ p += sprintf((char*)p, "%s", g_reset_color);
uint32_t y;
for (y = 0; y < height; y++) {
uint32_t x;
@@ -270,50 +270,50 @@
}
*p++ = '\n';
}
- p += sprintf((char*)p, "%s", reset_color);
- return p - printbuf.ptr;
+ p += sprintf((char*)p, "%s", g_reset_color);
+ return p - g_printbuf.ptr;
}
// ----
const char* //
try_allocate(wuffs_gif__decoder* dec) {
- uint32_t width = wuffs_base__pixel_config__width(&ic.pixcfg);
- uint32_t height = wuffs_base__pixel_config__height(&ic.pixcfg);
+ uint32_t width = wuffs_base__pixel_config__width(&g_ic.pixcfg);
+ uint32_t height = wuffs_base__pixel_config__height(&g_ic.pixcfg);
uint64_t num_pixels = ((uint64_t)width) * ((uint64_t)height);
if (num_pixels > (SIZE_MAX / sizeof(wuffs_base__color_u32_argb_premul))) {
return "could not allocate dst buffer";
}
- dst_len = num_pixels * sizeof(wuffs_base__color_u32_argb_premul);
- curr_dst_buffer = (uint8_t*)calloc(dst_len, 1);
- if (!curr_dst_buffer) {
+ g_dst_len = num_pixels * sizeof(wuffs_base__color_u32_argb_premul);
+ g_curr_dst_buffer = (uint8_t*)calloc(g_dst_len, 1);
+ if (!g_curr_dst_buffer) {
return "could not allocate curr-dst buffer";
}
- prev_dst_buffer = (uint8_t*)malloc(dst_len);
- if (!prev_dst_buffer) {
+ g_prev_dst_buffer = (uint8_t*)malloc(g_dst_len);
+ if (!g_prev_dst_buffer) {
return "could not allocate prev-dst buffer";
}
uint64_t workbuf_len_max_incl = wuffs_gif__decoder__workbuf_len(dec).max_incl;
if (workbuf_len_max_incl > 0) {
- workbuf = wuffs_base__malloc_slice_u8(
+ g_workbuf = wuffs_base__malloc_slice_u8(
malloc, wuffs_gif__decoder__workbuf_len(dec).max_incl);
- if (!workbuf.ptr) {
+ if (!g_workbuf.ptr) {
return "could not allocate work buffer";
}
} else {
- workbuf = wuffs_base__make_slice_u8(NULL, 0);
+ g_workbuf = wuffs_base__make_slice_u8(NULL, 0);
}
uint64_t plen = 1 + ((uint64_t)(width) + 1) * (uint64_t)(height);
- uint64_t bytes_per_print_pixel = flags.color ? BYTES_PER_COLOR_PIXEL : 1;
+ uint64_t bytes_per_print_pixel = g_flags.color ? BYTES_PER_COLOR_PIXEL : 1;
if (plen <= ((uint64_t)SIZE_MAX) / bytes_per_print_pixel) {
- printbuf =
+ g_printbuf =
wuffs_base__malloc_slice_u8(malloc, plen * bytes_per_print_pixel);
}
- if (!printbuf.ptr) {
+ if (!g_printbuf.ptr) {
return "could not allocate print buffer";
}
@@ -324,15 +324,15 @@
allocate(wuffs_gif__decoder* dec) {
const char* status_msg = try_allocate(dec);
if (status_msg) {
- free(printbuf.ptr);
- printbuf = wuffs_base__make_slice_u8(NULL, 0);
- free(workbuf.ptr);
- workbuf = wuffs_base__make_slice_u8(NULL, 0);
- free(prev_dst_buffer);
- prev_dst_buffer = NULL;
- free(curr_dst_buffer);
- curr_dst_buffer = NULL;
- dst_len = 0;
+ free(g_printbuf.ptr);
+ g_printbuf = wuffs_base__make_slice_u8(NULL, 0);
+ free(g_workbuf.ptr);
+ g_workbuf = wuffs_base__make_slice_u8(NULL, 0);
+ free(g_prev_dst_buffer);
+ g_prev_dst_buffer = NULL;
+ free(g_curr_dst_buffer);
+ g_curr_dst_buffer = NULL;
+ g_dst_len = 0;
}
return status_msg;
}
@@ -346,36 +346,36 @@
return wuffs_base__status__message(&status);
}
- if (flags.quirk_honor_background_color) {
+ if (g_flags.quirk_honor_background_color) {
wuffs_gif__decoder__set_quirk_enabled(
&dec, WUFFS_GIF__QUIRK_HONOR_BACKGROUND_COLOR, true);
}
wuffs_base__io_buffer src;
- src.data.ptr = src_buffer_array;
- src.data.len = src_len;
- src.meta.wi = src_len;
+ src.data.ptr = &g_src_buffer_array[0];
+ src.data.len = g_src_len;
+ src.meta.wi = g_src_len;
src.meta.ri = 0;
src.meta.pos = 0;
src.meta.closed = true;
- if (first_play) {
- status = wuffs_gif__decoder__decode_image_config(&dec, &ic, &src);
+ if (g_first_play) {
+ status = wuffs_gif__decoder__decode_image_config(&dec, &g_ic, &src);
if (!wuffs_base__status__is_ok(&status)) {
return wuffs_base__status__message(&status);
}
- if (!wuffs_base__image_config__is_valid(&ic)) {
+ if (!wuffs_base__image_config__is_valid(&g_ic)) {
return "invalid image configuration";
}
- uint32_t width = wuffs_base__pixel_config__width(&ic.pixcfg);
- uint32_t height = wuffs_base__pixel_config__height(&ic.pixcfg);
+ uint32_t width = wuffs_base__pixel_config__width(&g_ic.pixcfg);
+ uint32_t height = wuffs_base__pixel_config__height(&g_ic.pixcfg);
if ((width > MAX_DIMENSION) || (height > MAX_DIMENSION)) {
return "image dimensions are too large";
}
// Override the source's indexed pixel format to be non-indexed.
wuffs_base__pixel_config__set(
- &ic.pixcfg, WUFFS_BASE__PIXEL_FORMAT__BGRA_PREMUL,
+ &g_ic.pixcfg, WUFFS_BASE__PIXEL_FORMAT__BGRA_PREMUL,
WUFFS_BASE__PIXEL_SUBSAMPLING__NONE, width, height);
const char* msg = allocate(&dec);
@@ -383,7 +383,8 @@
return msg;
}
status = wuffs_base__pixel_buffer__set_from_slice(
- &pb, &ic.pixcfg, wuffs_base__make_slice_u8(curr_dst_buffer, dst_len));
+ &g_pb, &g_ic.pixcfg,
+ wuffs_base__make_slice_u8(g_curr_dst_buffer, g_dst_len));
if (!wuffs_base__status__is_ok(&status)) {
return wuffs_base__status__message(&status);
}
@@ -404,8 +405,8 @@
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);
- uint8_t* p = curr_dst_buffer;
+ size_t n = g_dst_len / sizeof(wuffs_base__color_u32_argb_premul);
+ uint8_t* p = g_curr_dst_buffer;
for (i = 0; i < n; i++) {
wuffs_base__store_u32le__no_bounds_check(p, background_color);
p += sizeof(wuffs_base__color_u32_argb_premul);
@@ -414,33 +415,33 @@
switch (wuffs_base__frame_config__disposal(&fc)) {
case WUFFS_BASE__ANIMATION_DISPOSAL__RESTORE_PREVIOUS: {
- memcpy(prev_dst_buffer, curr_dst_buffer, dst_len);
+ memcpy(g_prev_dst_buffer, g_curr_dst_buffer, g_dst_len);
break;
}
}
wuffs_base__status decode_frame_status = wuffs_gif__decoder__decode_frame(
- &dec, &pb, &src, WUFFS_BASE__PIXEL_BLEND__SRC_OVER, workbuf, NULL);
+ &dec, &g_pb, &src, WUFFS_BASE__PIXEL_BLEND__SRC_OVER, g_workbuf, NULL);
if (decode_frame_status.repr == wuffs_base__note__end_of_data) {
break;
}
- size_t n = flags.color ? print_color_art(&pb) : print_ascii_art(&pb);
+ size_t n = g_flags.color ? print_color_art(&g_pb) : print_ascii_art(&g_pb);
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(&g_pb, wuffs_base__frame_config__bounds(&fc),
wuffs_base__frame_config__background_color(&fc));
break;
}
case WUFFS_BASE__ANIMATION_DISPOSAL__RESTORE_PREVIOUS: {
- uint8_t* swap = curr_dst_buffer;
- curr_dst_buffer = prev_dst_buffer;
- prev_dst_buffer = swap;
+ uint8_t* swap = g_curr_dst_buffer;
+ g_curr_dst_buffer = g_prev_dst_buffer;
+ g_prev_dst_buffer = swap;
wuffs_base__status status = wuffs_base__pixel_buffer__set_from_slice(
- &pb, &ic.pixcfg,
- wuffs_base__make_slice_u8(curr_dst_buffer, dst_len));
+ &g_pb, &g_ic.pixcfg,
+ wuffs_base__make_slice_u8(g_curr_dst_buffer, g_dst_len));
if (!wuffs_base__status__is_ok(&status)) {
return wuffs_base__status__message(&status);
}
@@ -449,28 +450,28 @@
}
#if defined(WUFFS_EXAMPLE_USE_TIMERS)
- if (started) {
+ if (g_started) {
struct timespec now;
if (clock_gettime(CLOCK_MONOTONIC, &now)) {
return strerror(errno);
}
int64_t elapsed_micros = micros_since_start(&now);
- if (cumulative_delay_micros > elapsed_micros) {
- usleep(cumulative_delay_micros - elapsed_micros);
+ if (g_cumulative_delay_micros > elapsed_micros) {
+ usleep(g_cumulative_delay_micros - elapsed_micros);
}
} else {
- if (clock_gettime(CLOCK_MONOTONIC, &start_time)) {
+ if (clock_gettime(CLOCK_MONOTONIC, &g_start_time)) {
return strerror(errno);
}
- started = true;
+ g_started = true;
}
#endif
- fwrite(printbuf.ptr, sizeof(uint8_t), n, stdout);
+ fwrite(g_printbuf.ptr, sizeof(uint8_t), n, stdout);
fflush(stdout);
- cumulative_delay_micros +=
+ g_cumulative_delay_micros +=
(1000 * wuffs_base__frame_config__duration(&fc)) /
WUFFS_BASE__FLICKS_PER_MILLISECOND;
@@ -481,9 +482,9 @@
}
}
- if (first_play) {
- first_play = false;
- num_loops_remaining = wuffs_gif__decoder__num_animation_loops(&dec);
+ if (g_first_play) {
+ g_first_play = false;
+ g_num_loops_remaining = wuffs_gif__decoder__num_animation_loops(&dec);
}
return NULL;
@@ -492,17 +493,17 @@
const char* //
main1(int argc, char** argv) {
TRY(parse_flags(argc, argv));
- if (flags.remaining_argc > 0) {
+ if (g_flags.remaining_argc > 0) {
return "main: bad argument: use \"program < input\", not \"program input\"";
}
TRY(read_stdin());
while (true) {
TRY(play());
- if (num_loops_remaining == 0) {
+ if (g_num_loops_remaining == 0) {
continue;
}
- num_loops_remaining--;
- if (num_loops_remaining == 0) {
+ g_num_loops_remaining--;
+ if (g_num_loops_remaining == 0) {
break;
}
}
diff --git a/example/imageviewer/imageviewer.c b/example/imageviewer/imageviewer.c
index 4b5fe4d..1447cee 100644
--- a/example/imageviewer/imageviewer.c
+++ b/example/imageviewer/imageviewer.c
@@ -69,8 +69,6 @@
#define NUM_BACKGROUND_COLORS 3
#define SRC_BUFFER_ARRAY_SIZE (64 * 1024)
-// Global variable names start with a "g_" prefix.
-
wuffs_base__color_u32_argb_premul g_background_colors[NUM_BACKGROUND_COLORS] = {
0xFF000000,
0xFFFFFFFF,
diff --git a/example/jsonfindptrs/jsonfindptrs.cc b/example/jsonfindptrs/jsonfindptrs.cc
index e2ead12..325661e 100644
--- a/example/jsonfindptrs/jsonfindptrs.cc
+++ b/example/jsonfindptrs/jsonfindptrs.cc
@@ -18,7 +18,7 @@
jsonfindptrs reads UTF-8 JSON from stdin and writes every node's JSON Pointer
(RFC 6901) to stdout.
-See the "const char* usage" string below for details.
+See the "const char* g_usage" string below for details.
----
@@ -97,7 +97,7 @@
} \
} while (false)
-static const char* usage =
+static const char* g_usage =
"Usage: jsonfindptrs -flags input.json\n"
"\n"
"Flags:\n"
@@ -177,11 +177,11 @@
uint32_t max_output_depth;
bool strict_json_pointer_syntax;
-} flags = {0};
+} g_flags = {0};
std::string //
parse_flags(int argc, char** argv) {
- flags.max_output_depth = 0xFFFFFFFF;
+ g_flags.max_output_depth = 0xFFFFFFFF;
int c = (argc > 0) ? 1 : 0; // Skip argv[0], the program name.
for (; c < argc; c++) {
@@ -204,7 +204,7 @@
}
if (!strcmp(arg, "o") || !strcmp(arg, "max-output-depth")) {
- flags.max_output_depth = 1;
+ g_flags.max_output_depth = 1;
continue;
} else if (!strncmp(arg, "o=", 2) ||
!strncmp(arg, "max-output-depth=", 16)) {
@@ -213,26 +213,29 @@
wuffs_base__result_u64 u = wuffs_base__parse_number_u64(
wuffs_base__make_slice_u8((uint8_t*)arg, strlen(arg)));
if (wuffs_base__status__is_ok(&u.status) && (u.value <= 0xFFFFFFFF)) {
- flags.max_output_depth = (uint32_t)(u.value);
+ g_flags.max_output_depth = (uint32_t)(u.value);
continue;
}
- return usage;
+ return g_usage;
}
if (!strcmp(arg, "s") || !strcmp(arg, "strict-json-pointer-syntax")) {
- flags.strict_json_pointer_syntax = true;
+ g_flags.strict_json_pointer_syntax = true;
continue;
}
- return usage;
+ return g_usage;
}
- flags.remaining_argc = argc - c;
- flags.remaining_argv = argv + c;
+ g_flags.remaining_argc = argc - c;
+ g_flags.remaining_argv = argv + c;
return "";
}
// ----
+#define WORK_BUFFER_ARRAY_SIZE \
+ WUFFS_JSON__DECODER_WORKBUF_LEN_MAX_INCL_WORST_CASE
+
#ifndef SRC_BUFFER_ARRAY_SIZE
#define SRC_BUFFER_ARRAY_SIZE (4 * 1024)
#endif
@@ -272,6 +275,13 @@
m_curr_token_end_src_index(0) {
m_status =
m_dec.initialize(sizeof__wuffs_json__decoder(), WUFFS_VERSION, 0);
+
+ // Uncomment these lines to enable the WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_X
+ // option, discussed in a separate comment.
+ //
+ // if (m_status.is_ok()) {
+ // m_dec.set_quirk_enabled(WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_X, true);
+ // }
}
Result peek() { return peek_or_next(false); }
@@ -298,7 +308,10 @@
return Result(m_status.message());
}
- m_status = m_dec.decode_tokens(&m_tok, &m_src);
+ m_status =
+ m_dec.decode_tokens(&m_tok, &m_src,
+ wuffs_base__make_slice_u8(
+ m_work_buffer_array, WORK_BUFFER_ARRAY_SIZE));
}
wuffs_base__token t = m_tok.data.ptr[m_tok.meta.ri];
@@ -348,6 +361,12 @@
wuffs_base__token m_tok_array[TOKEN_BUFFER_ARRAY_SIZE];
uint8_t m_src_array[SRC_BUFFER_ARRAY_SIZE];
+#if WORK_BUFFER_ARRAY_SIZE > 0
+ uint8_t m_work_buffer_array[WORK_BUFFER_ARRAY_SIZE];
+#else
+ // Not all C/C++ compilers support 0-length arrays.
+ uint8_t m_work_buffer_array[1];
+#endif
wuffs_json__decoder m_dec;
};
@@ -584,11 +603,43 @@
case WUFFS_BASE__TOKEN__VBC__STRING: {
if (vbd & WUFFS_BASE__TOKEN__VBD__STRING__CONVERT_0_DST_1_SRC_DROP) {
// No-op.
+
} else if (vbd &
WUFFS_BASE__TOKEN__VBD__STRING__CONVERT_1_DST_1_SRC_COPY) {
const char* ptr = // Convert from (uint8_t*).
static_cast<const char*>(static_cast<void*>(tsr.src_data.ptr));
jt.value.s.append(ptr, tsr.src_data.len);
+
+ } else if (
+ vbd &
+ WUFFS_BASE__TOKEN__VBD__STRING__CONVERT_1_DST_4_SRC_BACKSLASH_X) {
+ // We shouldn't get here unless we enable the
+ // WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_X option. The jsonfindptrs
+ // program doesn't enable that by default, but if you're copy/pasting
+ // this JsonThing code and your program does enable that option,
+ // here's how to handle it.
+ wuffs_base__slice_u8 encoded = tsr.src_data;
+ if (encoded.len & 3) {
+ return Result(
+ "main: internal error: \\x token length not a multiple of 4",
+ JsonThing());
+ }
+ while (encoded.len) {
+ uint8_t decoded[64];
+ size_t len = wuffs_base__hexadecimal__decode4(
+ wuffs_base__make_slice_u8(&decoded[0], 64), encoded);
+ if ((len > 64) || ((len * 4) > encoded.len)) {
+ return Result(
+ "main: internal error: inconsistent hexadecimal decoding",
+ JsonThing());
+ }
+ const char* ptr = // Convert from (uint8_t*).
+ static_cast<const char*>(static_cast<void*>(&decoded[0]));
+ jt.value.s.append(ptr, len);
+ encoded.ptr += len * 4;
+ encoded.len -= len * 4;
+ }
+
} else {
return Result(
"main: internal error: unexpected string-token conversion",
@@ -647,13 +698,13 @@
e += "~1";
break;
case '\n':
- if (flags.strict_json_pointer_syntax) {
+ if (g_flags.strict_json_pointer_syntax) {
return "";
}
e += "~n";
break;
case '\r':
- if (flags.strict_json_pointer_syntax) {
+ if (g_flags.strict_json_pointer_syntax) {
return "";
}
e += "~r";
@@ -669,7 +720,7 @@
std::string //
print_json_pointers(JsonThing& jt, std::string s, uint32_t depth) {
std::cout << s << std::endl;
- if (depth++ >= flags.max_output_depth) {
+ if (depth++ >= g_flags.max_output_depth) {
return "";
}
@@ -701,10 +752,10 @@
TRY(parse_flags(argc, argv));
int input_file_descriptor = 0; // A 0 default means stdin.
- if (flags.remaining_argc > 1) {
- return usage;
- } else if (flags.remaining_argc == 1) {
- const char* arg = flags.remaining_argv[0];
+ if (g_flags.remaining_argc > 1) {
+ return g_usage;
+ } else if (g_flags.remaining_argc == 1) {
+ const char* arg = g_flags.remaining_argv[0];
input_file_descriptor = open(arg, O_RDONLY);
if (input_file_descriptor < 0) {
return std::string("main: cannot read ") + arg + ": " + strerror(errno);
diff --git a/example/jsonptr/jsonptr.cc b/example/jsonptr/jsonptr.cc
index dad552d..9fd764f 100644
--- a/example/jsonptr/jsonptr.cc
+++ b/example/jsonptr/jsonptr.cc
@@ -19,7 +19,7 @@
(RFC 6901) query syntax. It reads UTF-8 JSON from stdin and writes
canonicalized, formatted UTF-8 JSON to stdout.
-See the "const char* usage" string below for details.
+See the "const char* g_usage" string below for details.
----
@@ -34,8 +34,8 @@
use-after-frees.
The core JSON implementation is also written in the Wuffs programming language
-(and then transpiled to C/C++), which is memory-safe but also guards against
-integer arithmetic overflows.
+(and then transpiled to C/C++), which is memory-safe (e.g. array indexing is
+bounds-checked) but also guards against integer arithmetic overflows.
For defense in depth, on Linux, this program also self-imposes a
SECCOMP_MODE_STRICT sandbox before reading (or otherwise processing) its input
@@ -60,7 +60,7 @@
This program uses Wuffs' JSON decoder at a relatively low level, processing the
decoder's token-stream output individually. The core loop, in pseudo-code, is
"for_each_token { handle_token(etc); }", where the handle_token function
-changes global state (e.g. the `depth` and `context` variables) and prints
+changes global state (e.g. the `g_depth` and `g_ctx` variables) and prints
output text based on that state and the token's source text. Notably,
handle_token is not recursive, even though JSON values can nest.
@@ -140,9 +140,9 @@
} \
} while (false)
-static const char* eod = "main: end of data";
+static const char* g_eod = "main: end of data";
-static const char* usage =
+static const char* g_usage =
"Usage: jsonptr -flags input.json\n"
"\n"
"Flags:\n"
@@ -232,9 +232,20 @@
// ----
-bool sandboxed = false;
+// Wuffs allows either statically or dynamically allocated work buffers. This
+// program exercises static allocation.
+#define WORK_BUFFER_ARRAY_SIZE \
+ WUFFS_JSON__DECODER_WORKBUF_LEN_MAX_INCL_WORST_CASE
+#if WORK_BUFFER_ARRAY_SIZE > 0
+uint8_t g_work_buffer_array[WORK_BUFFER_ARRAY_SIZE];
+#else
+// Not all C/C++ compilers support 0-length arrays.
+uint8_t g_work_buffer_array[1];
+#endif
-int input_file_descriptor = 0; // A 0 default means stdin.
+bool g_sandboxed = false;
+
+int g_input_file_descriptor = 0; // A 0 default means stdin.
#define MAX_INDENT 8
#define INDENT_SPACES_STRING " "
@@ -250,19 +261,20 @@
#define TOKEN_BUFFER_ARRAY_SIZE (4 * 1024)
#endif
-uint8_t dst_array[DST_BUFFER_ARRAY_SIZE];
-uint8_t src_array[SRC_BUFFER_ARRAY_SIZE];
-wuffs_base__token tok_array[TOKEN_BUFFER_ARRAY_SIZE];
+uint8_t g_dst_array[DST_BUFFER_ARRAY_SIZE];
+uint8_t g_src_array[SRC_BUFFER_ARRAY_SIZE];
+wuffs_base__token g_tok_array[TOKEN_BUFFER_ARRAY_SIZE];
-wuffs_base__io_buffer dst;
-wuffs_base__io_buffer src;
-wuffs_base__token_buffer tok;
+wuffs_base__io_buffer g_dst;
+wuffs_base__io_buffer g_src;
+wuffs_base__token_buffer g_tok;
-// curr_token_end_src_index is the src.data.ptr index of the end of the current
-// token. An invariant is that (curr_token_end_src_index <= src.meta.ri).
-size_t curr_token_end_src_index;
+// g_curr_token_end_src_index is the g_src.data.ptr index of the end of the
+// current token. An invariant is that (g_curr_token_end_src_index <=
+// g_src.meta.ri).
+size_t g_curr_token_end_src_index;
-uint32_t depth;
+uint32_t g_depth;
enum class context {
none,
@@ -271,18 +283,18 @@
in_dict_after_brace,
in_dict_after_key,
in_dict_after_value,
-} ctx;
+} g_ctx;
bool //
in_dict_before_key() {
- return (ctx == context::in_dict_after_brace) ||
- (ctx == context::in_dict_after_value);
+ return (g_ctx == context::in_dict_after_brace) ||
+ (g_ctx == context::in_dict_after_value);
}
-uint32_t suppress_write_dst;
-bool wrote_to_dst;
+uint32_t g_suppress_write_dst;
+bool g_wrote_to_dst;
-wuffs_json__decoder dec;
+wuffs_json__decoder g_dec;
// ----
@@ -531,7 +543,7 @@
}
return !previous_was_tilde;
}
-} query;
+} g_query;
// ----
@@ -546,12 +558,12 @@
char* query_c_string;
bool strict_json_pointer_syntax;
bool tabs;
-} flags = {0};
+} g_flags = {0};
const char* //
parse_flags(int argc, char** argv) {
- flags.indent = 4;
- flags.max_output_depth = 0xFFFFFFFF;
+ g_flags.indent = 4;
+ g_flags.max_output_depth = 0xFFFFFFFF;
int c = (argc > 0) ? 1 : 0; // Skip argv[0], the program name.
for (; c < argc; c++) {
@@ -574,24 +586,24 @@
}
if (!strcmp(arg, "c") || !strcmp(arg, "compact-output")) {
- flags.compact_output = true;
+ g_flags.compact_output = true;
continue;
}
if (!strcmp(arg, "fail-if-unsandboxed")) {
- flags.fail_if_unsandboxed = true;
+ g_flags.fail_if_unsandboxed = true;
continue;
}
if (!strncmp(arg, "i=", 2) || !strncmp(arg, "indent=", 7)) {
while (*arg++ != '=') {
}
if (('0' <= arg[0]) && (arg[0] <= '8') && (arg[1] == '\x00')) {
- flags.indent = arg[0] - '0';
+ g_flags.indent = arg[0] - '0';
continue;
}
- return usage;
+ return g_usage;
}
if (!strcmp(arg, "o") || !strcmp(arg, "max-output-depth")) {
- flags.max_output_depth = 1;
+ g_flags.max_output_depth = 1;
continue;
} else if (!strncmp(arg, "o=", 2) ||
!strncmp(arg, "max-output-depth=", 16)) {
@@ -600,78 +612,87 @@
wuffs_base__result_u64 u = wuffs_base__parse_number_u64(
wuffs_base__make_slice_u8((uint8_t*)arg, strlen(arg)));
if (wuffs_base__status__is_ok(&u.status) && (u.value <= 0xFFFFFFFF)) {
- flags.max_output_depth = (uint32_t)(u.value);
+ g_flags.max_output_depth = (uint32_t)(u.value);
continue;
}
- return usage;
+ return g_usage;
}
if (!strncmp(arg, "q=", 2) || !strncmp(arg, "query=", 6)) {
while (*arg++ != '=') {
}
- flags.query_c_string = arg;
+ g_flags.query_c_string = arg;
continue;
}
if (!strcmp(arg, "s") || !strcmp(arg, "strict-json-pointer-syntax")) {
- flags.strict_json_pointer_syntax = true;
+ g_flags.strict_json_pointer_syntax = true;
continue;
}
if (!strcmp(arg, "t") || !strcmp(arg, "tabs")) {
- flags.tabs = true;
+ g_flags.tabs = true;
continue;
}
- return usage;
+ return g_usage;
}
- if (flags.query_c_string &&
- !Query::validate(flags.query_c_string, strlen(flags.query_c_string),
- flags.strict_json_pointer_syntax)) {
+ if (g_flags.query_c_string &&
+ !Query::validate(g_flags.query_c_string, strlen(g_flags.query_c_string),
+ g_flags.strict_json_pointer_syntax)) {
return "main: bad JSON Pointer (RFC 6901) syntax for the -query=STR flag";
}
- flags.remaining_argc = argc - c;
- flags.remaining_argv = argv + c;
+ g_flags.remaining_argc = argc - c;
+ g_flags.remaining_argv = argv + c;
return nullptr;
}
const char* //
initialize_globals(int argc, char** argv) {
- dst = wuffs_base__make_io_buffer(
- wuffs_base__make_slice_u8(dst_array, DST_BUFFER_ARRAY_SIZE),
+ g_dst = wuffs_base__make_io_buffer(
+ wuffs_base__make_slice_u8(g_dst_array, DST_BUFFER_ARRAY_SIZE),
wuffs_base__empty_io_buffer_meta());
- src = wuffs_base__make_io_buffer(
- wuffs_base__make_slice_u8(src_array, SRC_BUFFER_ARRAY_SIZE),
+ g_src = wuffs_base__make_io_buffer(
+ wuffs_base__make_slice_u8(g_src_array, SRC_BUFFER_ARRAY_SIZE),
wuffs_base__empty_io_buffer_meta());
- tok = wuffs_base__make_token_buffer(
- wuffs_base__make_slice_token(tok_array, TOKEN_BUFFER_ARRAY_SIZE),
+ g_tok = wuffs_base__make_token_buffer(
+ wuffs_base__make_slice_token(g_tok_array, TOKEN_BUFFER_ARRAY_SIZE),
wuffs_base__empty_token_buffer_meta());
- curr_token_end_src_index = 0;
+ g_curr_token_end_src_index = 0;
- depth = 0;
+ g_depth = 0;
- ctx = context::none;
+ g_ctx = context::none;
TRY(parse_flags(argc, argv));
- if (flags.fail_if_unsandboxed && !sandboxed) {
+ if (g_flags.fail_if_unsandboxed && !g_sandboxed) {
return "main: unsandboxed";
}
const int stdin_fd = 0;
- if (flags.remaining_argc > ((input_file_descriptor != stdin_fd) ? 1 : 0)) {
- return usage;
+ if (g_flags.remaining_argc >
+ ((g_input_file_descriptor != stdin_fd) ? 1 : 0)) {
+ return g_usage;
}
- query.reset(flags.query_c_string);
+ g_query.reset(g_flags.query_c_string);
// If the query is non-empty, suprress writing to stdout until we've
// completed the query.
- suppress_write_dst = query.next_fragment() ? 1 : 0;
- wrote_to_dst = false;
+ g_suppress_write_dst = g_query.next_fragment() ? 1 : 0;
+ g_wrote_to_dst = false;
- return dec.initialize(sizeof__wuffs_json__decoder(), WUFFS_VERSION, 0)
- .message();
+ TRY(g_dec.initialize(sizeof__wuffs_json__decoder(), WUFFS_VERSION, 0)
+ .message());
+
+ // Consume an optional whitespace trailer. This isn't part of the JSON spec,
+ // but it works better with line oriented Unix tools (such as "echo 123 |
+ // jsonptr" where it's "echo", not "echo -n") or hand-edited JSON files which
+ // can accidentally contain trailing whitespace.
+ g_dec.set_quirk_enabled(WUFFS_JSON__QUIRK_ALLOW_TRAILING_NEW_LINE, true);
+
+ return nullptr;
}
// ----
@@ -682,19 +703,19 @@
const char* //
read_src() {
- if (src.meta.closed) {
+ if (g_src.meta.closed) {
return "main: internal error: read requested on a closed source";
}
- src.compact();
- if (src.meta.wi >= src.data.len) {
- return "main: src buffer is full";
+ g_src.compact();
+ if (g_src.meta.wi >= g_src.data.len) {
+ return "main: g_src buffer is full";
}
while (true) {
- ssize_t n = read(input_file_descriptor, src.data.ptr + src.meta.wi,
- src.data.len - src.meta.wi);
+ ssize_t n = read(g_input_file_descriptor, g_src.data.ptr + g_src.meta.wi,
+ g_src.data.len - g_src.meta.wi);
if (n >= 0) {
- src.meta.wi += n;
- src.meta.closed = n == 0;
+ g_src.meta.wi += n;
+ g_src.meta.closed = n == 0;
break;
} else if (errno != EINTR) {
return strerror(errno);
@@ -706,49 +727,49 @@
const char* //
flush_dst() {
while (true) {
- size_t n = dst.meta.wi - dst.meta.ri;
+ size_t n = g_dst.meta.wi - g_dst.meta.ri;
if (n == 0) {
break;
}
const int stdout_fd = 1;
- ssize_t i = write(stdout_fd, dst.data.ptr + dst.meta.ri, n);
+ ssize_t i = write(stdout_fd, g_dst.data.ptr + g_dst.meta.ri, n);
if (i >= 0) {
- dst.meta.ri += i;
+ g_dst.meta.ri += i;
} else if (errno != EINTR) {
return strerror(errno);
}
}
- dst.compact();
+ g_dst.compact();
return nullptr;
}
const char* //
write_dst(const void* s, size_t n) {
- if (suppress_write_dst > 0) {
+ if (g_suppress_write_dst > 0) {
return nullptr;
}
const uint8_t* p = static_cast<const uint8_t*>(s);
while (n > 0) {
- size_t i = dst.writer_available();
+ size_t i = g_dst.writer_available();
if (i == 0) {
const char* z = flush_dst();
if (z) {
return z;
}
- i = dst.writer_available();
+ i = g_dst.writer_available();
if (i == 0) {
- return "main: dst buffer is full";
+ return "main: g_dst buffer is full";
}
}
if (i > n) {
i = n;
}
- memcpy(dst.data.ptr + dst.meta.wi, p, i);
- dst.meta.wi += i;
+ memcpy(g_dst.data.ptr + g_dst.meta.wi, p, i);
+ g_dst.meta.wi += i;
p += i;
n -= i;
- wrote_to_dst = true;
+ g_wrote_to_dst = true;
}
return nullptr;
}
@@ -822,16 +843,16 @@
// Handle ']' or '}'.
if ((vbc == WUFFS_BASE__TOKEN__VBC__STRUCTURE) &&
(vbd & WUFFS_BASE__TOKEN__VBD__STRUCTURE__POP)) {
- if (query.is_at(depth)) {
+ if (g_query.is_at(g_depth)) {
return "main: no match for query";
}
- if (depth <= 0) {
- return "main: internal error: inconsistent depth";
+ if (g_depth <= 0) {
+ return "main: internal error: inconsistent g_depth";
}
- depth--;
+ g_depth--;
- if (query.matched_all() && (depth >= flags.max_output_depth)) {
- suppress_write_dst--;
+ if (g_query.matched_all() && (g_depth >= g_flags.max_output_depth)) {
+ g_suppress_write_dst--;
// '…' is U+2026 HORIZONTAL ELLIPSIS, which is 3 UTF-8 bytes.
TRY(write_dst((vbd & WUFFS_BASE__TOKEN__VBD__STRUCTURE__FROM_LIST)
? "\"[…]\""
@@ -839,12 +860,14 @@
7));
} else {
// Write preceding whitespace.
- if ((ctx != context::in_list_after_bracket) &&
- (ctx != context::in_dict_after_brace) && !flags.compact_output) {
+ if ((g_ctx != context::in_list_after_bracket) &&
+ (g_ctx != context::in_dict_after_brace) &&
+ !g_flags.compact_output) {
TRY(write_dst("\n", 1));
- for (uint32_t i = 0; i < depth; i++) {
- TRY(write_dst(flags.tabs ? INDENT_TAB_STRING : INDENT_SPACES_STRING,
- flags.tabs ? 1 : flags.indent));
+ for (uint32_t i = 0; i < g_depth; i++) {
+ TRY(write_dst(
+ g_flags.tabs ? INDENT_TAB_STRING : INDENT_SPACES_STRING,
+ g_flags.tabs ? 1 : g_flags.indent));
}
}
@@ -853,40 +876,41 @@
1));
}
- ctx = (vbd & WUFFS_BASE__TOKEN__VBD__STRUCTURE__TO_LIST)
- ? context::in_list_after_value
- : context::in_dict_after_key;
+ g_ctx = (vbd & WUFFS_BASE__TOKEN__VBD__STRUCTURE__TO_LIST)
+ ? context::in_list_after_value
+ : context::in_dict_after_key;
goto after_value;
}
// Write preceding whitespace and punctuation, if it wasn't ']', '}' or a
// continuation of a multi-token chain.
if (!t.link_prev()) {
- if (ctx == context::in_dict_after_key) {
- TRY(write_dst(": ", flags.compact_output ? 1 : 2));
- } else if (ctx != context::none) {
- if ((ctx != context::in_list_after_bracket) &&
- (ctx != context::in_dict_after_brace)) {
+ if (g_ctx == context::in_dict_after_key) {
+ TRY(write_dst(": ", g_flags.compact_output ? 1 : 2));
+ } else if (g_ctx != context::none) {
+ if ((g_ctx != context::in_list_after_bracket) &&
+ (g_ctx != context::in_dict_after_brace)) {
TRY(write_dst(",", 1));
}
- if (!flags.compact_output) {
+ if (!g_flags.compact_output) {
TRY(write_dst("\n", 1));
- for (size_t i = 0; i < depth; i++) {
- TRY(write_dst(flags.tabs ? INDENT_TAB_STRING : INDENT_SPACES_STRING,
- flags.tabs ? 1 : flags.indent));
+ for (size_t i = 0; i < g_depth; i++) {
+ TRY(write_dst(
+ g_flags.tabs ? INDENT_TAB_STRING : INDENT_SPACES_STRING,
+ g_flags.tabs ? 1 : g_flags.indent));
}
}
}
bool query_matched_fragment = false;
- if (query.is_at(depth)) {
- switch (ctx) {
+ if (g_query.is_at(g_depth)) {
+ switch (g_ctx) {
case context::in_list_after_bracket:
case context::in_list_after_value:
- query_matched_fragment = query.tick();
+ query_matched_fragment = g_query.tick();
break;
case context::in_dict_after_key:
- query_matched_fragment = query.matched_fragment();
+ query_matched_fragment = g_query.matched_fragment();
break;
default:
break;
@@ -894,20 +918,20 @@
}
if (!query_matched_fragment) {
// No-op.
- } else if (!query.next_fragment()) {
+ } else if (!g_query.next_fragment()) {
// There is no next fragment. We have matched the complete query, and
// the upcoming JSON value is the result of that query.
//
- // Un-suppress writing to stdout and reset the ctx and depth as if we
- // were about to decode a top-level value. This makes any subsequent
- // indentation be relative to this point, and we will return eod after
- // the upcoming JSON value is complete.
- if (suppress_write_dst != 1) {
- return "main: internal error: inconsistent suppress_write_dst";
+ // Un-suppress writing to stdout and reset the g_ctx and g_depth as if
+ // we were about to decode a top-level value. This makes any subsequent
+ // indentation be relative to this point, and we will return g_eod
+ // after the upcoming JSON value is complete.
+ if (g_suppress_write_dst != 1) {
+ return "main: internal error: inconsistent g_suppress_write_dst";
}
- suppress_write_dst = 0;
- ctx = context::none;
- depth = 0;
+ g_suppress_write_dst = 0;
+ g_ctx = context::none;
+ g_depth = 0;
} else if ((vbc != WUFFS_BASE__TOKEN__VBC__STRUCTURE) ||
!(vbd & WUFFS_BASE__TOKEN__VBD__STRUCTURE__PUSH)) {
// The query has moved on to the next fragment but the upcoming JSON
@@ -920,32 +944,33 @@
// value: string (a chain of raw or escaped parts), literal or number.
switch (vbc) {
case WUFFS_BASE__TOKEN__VBC__STRUCTURE:
- if (query.matched_all() && (depth >= flags.max_output_depth)) {
- suppress_write_dst++;
+ if (g_query.matched_all() && (g_depth >= g_flags.max_output_depth)) {
+ g_suppress_write_dst++;
} else {
TRY(write_dst(
(vbd & WUFFS_BASE__TOKEN__VBD__STRUCTURE__TO_LIST) ? "[" : "{",
1));
}
- depth++;
- ctx = (vbd & WUFFS_BASE__TOKEN__VBD__STRUCTURE__TO_LIST)
- ? context::in_list_after_bracket
- : context::in_dict_after_brace;
+ g_depth++;
+ g_ctx = (vbd & WUFFS_BASE__TOKEN__VBD__STRUCTURE__TO_LIST)
+ ? context::in_list_after_bracket
+ : context::in_dict_after_brace;
return nullptr;
case WUFFS_BASE__TOKEN__VBC__STRING:
if (!t.link_prev()) {
TRY(write_dst("\"", 1));
- query.restart_fragment(in_dict_before_key() && query.is_at(depth));
+ g_query.restart_fragment(in_dict_before_key() &&
+ g_query.is_at(g_depth));
}
if (vbd & WUFFS_BASE__TOKEN__VBD__STRING__CONVERT_0_DST_1_SRC_DROP) {
// No-op.
} else if (vbd &
WUFFS_BASE__TOKEN__VBD__STRING__CONVERT_1_DST_1_SRC_COPY) {
- uint8_t* ptr = src.data.ptr + curr_token_end_src_index - len;
+ uint8_t* ptr = g_src.data.ptr + g_curr_token_end_src_index - len;
TRY(write_dst(ptr, len));
- query.incremental_match_slice(ptr, len);
+ g_query.incremental_match_slice(ptr, len);
} else {
return "main: internal error: unexpected string-token conversion";
}
@@ -961,12 +986,12 @@
return "main: internal error: unexpected unlinked token";
}
TRY(handle_unicode_code_point(vbd));
- query.incremental_match_code_point(vbd);
+ g_query.incremental_match_code_point(vbd);
return nullptr;
case WUFFS_BASE__TOKEN__VBC__LITERAL:
case WUFFS_BASE__TOKEN__VBC__NUMBER:
- TRY(write_dst(src.data.ptr + curr_token_end_src_index - len, len));
+ TRY(write_dst(g_src.data.ptr + g_curr_token_end_src_index - len, len));
goto after_value;
}
@@ -978,21 +1003,21 @@
// simple value). Empty parent containers are no longer empty. If the parent
// container is a "{...}" object, toggle between keys and values.
after_value:
- if (depth == 0) {
- return eod;
+ if (g_depth == 0) {
+ return g_eod;
}
- switch (ctx) {
+ switch (g_ctx) {
case context::in_list_after_bracket:
- ctx = context::in_list_after_value;
+ g_ctx = context::in_list_after_value;
break;
case context::in_dict_after_brace:
- ctx = context::in_dict_after_key;
+ g_ctx = context::in_dict_after_key;
break;
case context::in_dict_after_key:
- ctx = context::in_dict_after_value;
+ g_ctx = context::in_dict_after_value;
break;
case context::in_dict_after_value:
- ctx = context::in_dict_after_key;
+ g_ctx = context::in_dict_after_key;
break;
default:
break;
@@ -1005,15 +1030,17 @@
TRY(initialize_globals(argc, argv));
while (true) {
- wuffs_base__status status = dec.decode_tokens(&tok, &src);
+ wuffs_base__status status = g_dec.decode_tokens(
+ &g_tok, &g_src,
+ wuffs_base__make_slice_u8(g_work_buffer_array, WORK_BUFFER_ARRAY_SIZE));
- while (tok.meta.ri < tok.meta.wi) {
- wuffs_base__token t = tok.data.ptr[tok.meta.ri++];
+ while (g_tok.meta.ri < g_tok.meta.wi) {
+ wuffs_base__token t = g_tok.data.ptr[g_tok.meta.ri++];
uint64_t n = t.length();
- if ((src.meta.ri - curr_token_end_src_index) < n) {
- return "main: internal error: inconsistent src indexes";
+ if ((g_src.meta.ri - g_curr_token_end_src_index) < n) {
+ return "main: internal error: inconsistent g_src indexes";
}
- curr_token_end_src_index += n;
+ g_curr_token_end_src_index += n;
// Skip filler tokens (e.g. whitespace).
if (t.value() == 0) {
@@ -1023,7 +1050,7 @@
const char* z = handle_token(t);
if (z == nullptr) {
continue;
- } else if (z == eod) {
+ } else if (z == g_eod) {
goto end_of_data;
}
return z;
@@ -1032,63 +1059,39 @@
if (status.repr == nullptr) {
return "main: internal error: unexpected end of token stream";
} else if (status.repr == wuffs_base__suspension__short_read) {
- if (curr_token_end_src_index != src.meta.ri) {
- return "main: internal error: inconsistent src indexes";
+ if (g_curr_token_end_src_index != g_src.meta.ri) {
+ return "main: internal error: inconsistent g_src indexes";
}
TRY(read_src());
- curr_token_end_src_index = src.meta.ri;
+ g_curr_token_end_src_index = g_src.meta.ri;
} else if (status.repr == wuffs_base__suspension__short_write) {
- tok.compact();
+ g_tok.compact();
} else {
return status.message();
}
}
end_of_data:
- // With a non-empty query, don't try to consume trailing whitespace or
+ // With a non-empty g_query, don't try to consume trailing whitespace or
// confirm that we've processed all the tokens.
- if (flags.query_c_string && *flags.query_c_string) {
+ if (g_flags.query_c_string && *g_flags.query_c_string) {
return nullptr;
}
- // Consume an optional whitespace trailer. This isn't part of the JSON spec,
- // but it works better with line oriented Unix tools (such as "echo 123 |
- // jsonptr" where it's "echo", not "echo -n") or hand-edited JSON files which
- // can accidentally contain trailing whitespace.
- //
- // A whitespace trailer is zero or more ' ' and then zero or one '\n'.
- while (true) {
- if (src.meta.ri < src.meta.wi) {
- uint8_t c = src.data.ptr[src.meta.ri];
- if (c == ' ') {
- src.meta.ri++;
- continue;
- } else if (c == '\n') {
- src.meta.ri++;
- break;
- }
- // The "exhausted the input" check below will fail.
- break;
- } else if (src.meta.closed) {
- break;
- }
- TRY(read_src());
- }
-
// Check that we've exhausted the input.
- if ((src.meta.ri == src.meta.wi) && !src.meta.closed) {
+ if ((g_src.meta.ri == g_src.meta.wi) && !g_src.meta.closed) {
TRY(read_src());
}
- if ((src.meta.ri < src.meta.wi) || !src.meta.closed) {
+ if ((g_src.meta.ri < g_src.meta.wi) || !g_src.meta.closed) {
return "main: valid JSON followed by further (unexpected) data";
}
// Check that we've used all of the decoded tokens, other than trailing
- // filler tokens. For example, a bare `"foo"` string is valid JSON, but even
- // without a trailing '\n', the Wuffs JSON parser emits a filler token for
- // the final '\"'.
- for (; tok.meta.ri < tok.meta.wi; tok.meta.ri++) {
- if (tok.data.ptr[tok.meta.ri].value_base_category() !=
+ // filler tokens. For example, "true\n" is valid JSON (and fully consumed
+ // with WUFFS_JSON__QUIRK_ALLOW_TRAILING_NEW_LINE enabled) with a trailing
+ // filler token for the "\n".
+ for (; g_tok.meta.ri < g_tok.meta.wi; g_tok.meta.ri++) {
+ if (g_tok.data.ptr[g_tok.meta.ri].value_base_category() !=
WUFFS_BASE__TOKEN__VBC__FILLER) {
return "main: internal error: decoded OK but unprocessed tokens remain";
}
@@ -1103,7 +1106,7 @@
return 0;
}
size_t n;
- if (status_msg == usage) {
+ if (status_msg == g_usage) {
n = strlen(status_msg);
} else {
n = strnlen(status_msg, 2047);
@@ -1144,8 +1147,8 @@
dash_dash = (arg[1] == '-') && (arg[2] == '\x00');
continue;
}
- input_file_descriptor = open(arg, O_RDONLY);
- if (input_file_descriptor < 0) {
+ g_input_file_descriptor = open(arg, O_RDONLY);
+ if (g_input_file_descriptor < 0) {
fprintf(stderr, "%s: %s\n", arg, strerror(errno));
return 1;
}
@@ -1155,11 +1158,11 @@
#if defined(WUFFS_EXAMPLE_USE_SECCOMP)
prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT);
- sandboxed = true;
+ g_sandboxed = true;
#endif
const char* z = main1(argc, argv);
- if (wrote_to_dst) {
+ if (g_wrote_to_dst) {
const char* z1 = write_dst("\n", 1);
const char* z2 = flush_dst();
z = z ? z : (z1 ? z1 : z2);
diff --git a/example/library/library.c b/example/library/library.c
index e6162d1..78cab0f 100644
--- a/example/library/library.c
+++ b/example/library/library.c
@@ -48,7 +48,7 @@
#ifndef DST_BUFFER_ARRAY_SIZE
#define DST_BUFFER_ARRAY_SIZE 1024
#endif
-uint8_t dst_buffer_array[DST_BUFFER_ARRAY_SIZE];
+uint8_t g_dst_buffer_array[DST_BUFFER_ARRAY_SIZE];
// src_ptr and src_len hold a gzip-encoded "Hello Wuffs."
//
@@ -59,28 +59,28 @@
//
// Passing --no-name to the gzip command line also means to skip the timestamp,
// which means that its output is deterministic.
-uint8_t src_ptr[] = {
+uint8_t g_src_ptr[] = {
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // 00..07
0x00, 0x03, 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, // 08..0F
0x08, 0x2f, 0x4d, 0x4b, 0x2b, 0xd6, 0xe3, 0x02, // 10..17
0x00, 0x3c, 0x84, 0x75, 0xbb, 0x0d, 0x00, 0x00, // 18..1F
0x00, // 20..20
};
-size_t src_len = 0x21;
+size_t g_src_len = 0x21;
#define WORK_BUFFER_ARRAY_SIZE \
WUFFS_GZIP__DECODER_WORKBUF_LEN_MAX_INCL_WORST_CASE
#if WORK_BUFFER_ARRAY_SIZE > 0
-uint8_t work_buffer_array[WORK_BUFFER_ARRAY_SIZE];
+uint8_t g_work_buffer_array[WORK_BUFFER_ARRAY_SIZE];
#else
// Not all C/C++ compilers support 0-length arrays.
-uint8_t work_buffer_array[1];
+uint8_t g_work_buffer_array[1];
#endif
static const char* //
decode() {
wuffs_base__io_buffer dst;
- dst.data.ptr = dst_buffer_array;
+ dst.data.ptr = g_dst_buffer_array;
dst.data.len = DST_BUFFER_ARRAY_SIZE;
dst.meta.wi = 0;
dst.meta.ri = 0;
@@ -88,9 +88,9 @@
dst.meta.closed = false;
wuffs_base__io_buffer src;
- src.data.ptr = src_ptr;
- src.data.len = src_len;
- src.meta.wi = src_len;
+ src.data.ptr = g_src_ptr;
+ src.data.len = g_src_len;
+ src.meta.wi = g_src_len;
src.meta.ri = 0;
src.meta.pos = 0;
src.meta.closed = true;
@@ -109,7 +109,7 @@
}
status = wuffs_gzip__decoder__transform_io(
dec, &dst, &src,
- wuffs_base__make_slice_u8(work_buffer_array, WORK_BUFFER_ARRAY_SIZE));
+ wuffs_base__make_slice_u8(g_work_buffer_array, WORK_BUFFER_ARRAY_SIZE));
if (!wuffs_base__status__is_ok(&status)) {
free(dec);
return wuffs_base__status__message(&status);
diff --git a/example/zcat/zcat.c b/example/zcat/zcat.c
index 07f9679..d1cefba 100644
--- a/example/zcat/zcat.c
+++ b/example/zcat/zcat.c
@@ -72,25 +72,25 @@
#define WORK_BUFFER_ARRAY_SIZE \
WUFFS_GZIP__DECODER_WORKBUF_LEN_MAX_INCL_WORST_CASE
-uint8_t dst_buffer_array[DST_BUFFER_ARRAY_SIZE];
-uint8_t src_buffer_array[SRC_BUFFER_ARRAY_SIZE];
+uint8_t g_dst_buffer_array[DST_BUFFER_ARRAY_SIZE];
+uint8_t g_src_buffer_array[SRC_BUFFER_ARRAY_SIZE];
#if WORK_BUFFER_ARRAY_SIZE > 0
-uint8_t work_buffer_array[WORK_BUFFER_ARRAY_SIZE];
+uint8_t g_work_buffer_array[WORK_BUFFER_ARRAY_SIZE];
#else
// Not all C/C++ compilers support 0-length arrays.
-uint8_t work_buffer_array[1];
+uint8_t g_work_buffer_array[1];
#endif
// ----
-static bool sandboxed = false;
+static bool g_sandboxed = false;
struct {
int remaining_argc;
char** remaining_argv;
bool fail_if_unsandboxed;
-} flags = {0};
+} g_flags = {0};
const char* //
parse_flags(int argc, char** argv) {
@@ -115,15 +115,15 @@
}
if (!strcmp(arg, "fail-if-unsandboxed")) {
- flags.fail_if_unsandboxed = true;
+ g_flags.fail_if_unsandboxed = true;
continue;
}
return "main: unrecognized flag argument";
}
- flags.remaining_argc = argc - c;
- flags.remaining_argv = argv + c;
+ g_flags.remaining_argc = argc - c;
+ g_flags.remaining_argv = argv + c;
return NULL;
}
@@ -139,7 +139,7 @@
if (z) {
return z;
}
- if (flags.fail_if_unsandboxed && !sandboxed) {
+ if (g_flags.fail_if_unsandboxed && !g_sandboxed) {
return "main: unsandboxed";
}
@@ -151,7 +151,7 @@
}
wuffs_base__io_buffer dst;
- dst.data.ptr = dst_buffer_array;
+ dst.data.ptr = g_dst_buffer_array;
dst.data.len = DST_BUFFER_ARRAY_SIZE;
dst.meta.wi = 0;
dst.meta.ri = 0;
@@ -159,7 +159,7 @@
dst.meta.closed = false;
wuffs_base__io_buffer src;
- src.data.ptr = src_buffer_array;
+ src.data.ptr = g_src_buffer_array;
src.data.len = SRC_BUFFER_ARRAY_SIZE;
src.meta.wi = 0;
src.meta.ri = 0;
@@ -184,12 +184,13 @@
while (true) {
status = wuffs_gzip__decoder__transform_io(
&dec, &dst, &src,
- wuffs_base__make_slice_u8(work_buffer_array, WORK_BUFFER_ARRAY_SIZE));
+ wuffs_base__make_slice_u8(g_work_buffer_array,
+ WORK_BUFFER_ARRAY_SIZE));
if (dst.meta.wi) {
// TODO: handle EINTR and other write errors; see "man 2 write".
const int stdout_fd = 1;
- ignore_return_value(write(stdout_fd, dst_buffer_array, dst.meta.wi));
+ ignore_return_value(write(stdout_fd, g_dst_buffer_array, dst.meta.wi));
dst.meta.ri = dst.meta.wi;
wuffs_base__io_buffer__compact(&dst);
}
@@ -241,7 +242,7 @@
main(int argc, char** argv) {
#if defined(WUFFS_EXAMPLE_USE_SECCOMP)
prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT);
- sandboxed = true;
+ g_sandboxed = true;
#endif
int exit_code = compute_exit_code(main1(argc, argv));
diff --git a/fuzz/c/fuzzlib/fuzzlib.c b/fuzz/c/fuzzlib/fuzzlib.c
index 35b7273..29f9a4a 100644
--- a/fuzz/c/fuzzlib/fuzzlib.c
+++ b/fuzz/c/fuzzlib/fuzzlib.c
@@ -21,11 +21,10 @@
#error "Wuffs' .h files need to be included before this file"
#endif
-volatile int* intentional_segfault_ptr = NULL;
-
void //
intentional_segfault() {
- *intentional_segfault_ptr = 0;
+ static volatile int* ptr = NULL;
+ *ptr = 0;
}
const char* //
@@ -119,7 +118,7 @@
char** remaining_argv;
bool color;
-} flags = {0};
+} g_flags = {0};
const char* //
parse_flags(int argc, char** argv) {
@@ -144,28 +143,28 @@
}
if (!strcmp(arg, "c") || !strcmp(arg, "color")) {
- flags.color = true;
+ g_flags.color = true;
continue;
}
return "main: unrecognized flag argument";
}
- flags.remaining_argc = argc - c;
- flags.remaining_argv = argv + c;
+ g_flags.remaining_argc = argc - c;
+ g_flags.remaining_argv = argv + c;
return NULL;
}
-static int num_files_processed;
+static int g_num_files_processed;
static struct {
char buf[PATH_MAX];
size_t len;
-} relative_cwd;
+} g_relative_cwd;
void //
errorf(const char* msg) {
- if (flags.color) {
+ if (g_flags.color) {
printf("\e[31m%s\e[0m\n", msg);
} else {
printf("%s\n", msg);
@@ -242,7 +241,7 @@
const char* msg = llvmFuzzerTestOneInput((const uint8_t*)(data), size);
if (msg) {
errorf(msg);
- } else if (flags.color) {
+ } else if (g_flags.color) {
printf("\e[32mok\e[0m\n");
} else {
printf("ok\n");
@@ -261,12 +260,12 @@
static int //
visit(char* filename) {
- num_files_processed++;
+ g_num_files_processed++;
if (!filename || (filename[0] == '\x00')) {
fprintf(stderr, "FAIL: invalid filename\n");
return 1;
}
- int n = printf("- %s%s", relative_cwd.buf, filename);
+ int n = printf("- %s%s", g_relative_cwd.buf, filename);
printf("%*s", (60 > n) ? (60 - n) : 1, "");
fflush(stdout);
@@ -290,7 +289,7 @@
return 0;
}
- size_t old_len = relative_cwd.len;
+ size_t old_len = g_relative_cwd.len;
size_t filename_len = strlen(filename);
size_t new_len = old_len + strlen(filename);
bool slash = filename[filename_len - 1] != '/';
@@ -302,25 +301,25 @@
fprintf(stderr, "FAIL: path is too long\n");
return 1;
}
- memcpy(relative_cwd.buf + old_len, filename, filename_len);
+ memcpy(g_relative_cwd.buf + old_len, filename, filename_len);
if (slash) {
- relative_cwd.buf[new_len - 1] = '/';
+ g_relative_cwd.buf[new_len - 1] = '/';
}
- relative_cwd.buf[new_len] = '\x00';
- relative_cwd.len = new_len;
+ g_relative_cwd.buf[new_len] = '\x00';
+ g_relative_cwd.len = new_len;
int v = visit_dir(fd);
- relative_cwd.buf[old_len] = '\x00';
- relative_cwd.len = old_len;
+ g_relative_cwd.buf[old_len] = '\x00';
+ g_relative_cwd.len = old_len;
return v;
}
int //
main(int argc, char** argv) {
- num_files_processed = 0;
- relative_cwd.len = 0;
+ g_num_files_processed = 0;
+ g_relative_cwd.len = 0;
const char* z = parse_flags(argc, argv);
if (z) {
@@ -328,14 +327,14 @@
return 1;
}
int i;
- for (i = 0; i < flags.remaining_argc; i++) {
- int v = visit(flags.remaining_argv[i]);
+ for (i = 0; i < g_flags.remaining_argc; i++) {
+ int v = visit(g_flags.remaining_argv[i]);
if (v) {
return v;
}
}
- printf("PASS: %d files processed\n", num_files_processed);
+ printf("PASS: %d files processed\n", g_num_files_processed);
return 0;
}
diff --git a/fuzz/c/std/json_fuzzer.c b/fuzz/c/std/json_fuzzer.c
index e8b99b0..3e76676 100644
--- a/fuzz/c/std/json_fuzzer.c
+++ b/fuzz/c/std/json_fuzzer.c
@@ -62,6 +62,17 @@
#define TOK_BUFFER_ARRAY_SIZE 4096
#define STACK_SIZE (WUFFS_JSON__DECODER_DEPTH_MAX_INCL + 1)
+// Wuffs allows either statically or dynamically allocated work buffers. This
+// program exercises static allocation.
+#define WORK_BUFFER_ARRAY_SIZE \
+ WUFFS_JSON__DECODER_WORKBUF_LEN_MAX_INCL_WORST_CASE
+#if WORK_BUFFER_ARRAY_SIZE > 0
+uint8_t g_work_buffer_array[WORK_BUFFER_ARRAY_SIZE];
+#else
+// Not all C/C++ compilers support 0-length arrays.
+uint8_t g_work_buffer_array[1];
+#endif
+
// Each stack element is 1 byte. The low 7 bits denote the container:
// - 0x01 means no container: we are at the top level.
// - 0x02 means a [] list.
@@ -201,19 +212,63 @@
return NULL;
}
+uint64_t //
+buffer_limit(uint32_t hash_6_bits, uint64_t min, uint64_t max) {
+ uint64_t n;
+ if (hash_6_bits < 0x20) {
+ n = min + hash_6_bits;
+ } else {
+ n = max - (0x3F - hash_6_bits);
+ }
+ if (n < min) {
+ return min;
+ } else if (n > max) {
+ return max;
+ }
+ return n;
+}
+
+void set_quirks(wuffs_json__decoder* dec, uint32_t hash_12_bits) {
+ uint32_t quirks[] = {
+ WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_A,
+ WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_CAPITAL_U,
+ WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_E,
+ WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_QUESTION_MARK,
+ WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_SINGLE_QUOTE,
+ WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_V,
+ WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_X,
+ WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_ZERO,
+ WUFFS_JSON__QUIRK_ALLOW_COMMENT_BLOCK,
+ WUFFS_JSON__QUIRK_ALLOW_COMMENT_LINE,
+ WUFFS_JSON__QUIRK_ALLOW_EXTRA_COMMA,
+ WUFFS_JSON__QUIRK_ALLOW_INF_NAN_NUMBERS,
+ WUFFS_JSON__QUIRK_ALLOW_LEADING_ASCII_RECORD_SEPARATOR,
+ WUFFS_JSON__QUIRK_ALLOW_LEADING_UNICODE_BYTE_ORDER_MARK,
+ WUFFS_JSON__QUIRK_ALLOW_TRAILING_NEW_LINE,
+ WUFFS_JSON__QUIRK_REPLACE_INVALID_UNICODE,
+ 0,
+ };
+
+ uint32_t i;
+ for (i = 0; quirks[i]; i++) {
+ uint32_t bit = 1 << (i % 12);
+ if (hash_12_bits & bit) {
+ wuffs_json__decoder__set_quirk_enabled(dec, quirks[i], true);
+ }
+ }
+}
+
const char* //
fuzz_complex(wuffs_base__io_buffer* full_src, uint32_t hash_24_bits) {
- uint64_t tok_limit = hash_24_bits & 0x0FFF; // 4095, or ((1 << 12) - 1).
- if (tok_limit < WUFFS_JSON__DECODER_DST_TOKEN_BUFFER_LENGTH_MIN_INCL) {
- tok_limit = WUFFS_JSON__DECODER_DST_TOKEN_BUFFER_LENGTH_MIN_INCL;
- }
- hash_24_bits >>= 12;
+ uint64_t tok_limit = buffer_limit(
+ hash_24_bits & 0x3F, WUFFS_JSON__DECODER_DST_TOKEN_BUFFER_LENGTH_MIN_INCL,
+ TOK_BUFFER_ARRAY_SIZE);
+ uint32_t hash_18_bits = hash_24_bits >> 6;
- uint64_t src_limit = hash_24_bits & 0x0FFF; // 4095, or ((1 << 12) - 1).
- if (src_limit < WUFFS_JSON__DECODER_SRC_IO_BUFFER_LENGTH_MIN_INCL) {
- src_limit = WUFFS_JSON__DECODER_SRC_IO_BUFFER_LENGTH_MIN_INCL;
- }
- hash_24_bits >>= 12;
+ uint64_t src_limit =
+ buffer_limit(hash_18_bits & 0x3F,
+ WUFFS_JSON__DECODER_SRC_IO_BUFFER_LENGTH_MIN_INCL, 4096);
+ uint32_t hash_12_bits = hash_18_bits >> 6;
// ----
@@ -224,6 +279,7 @@
if (!wuffs_base__status__is_ok(&status)) {
return wuffs_base__status__message(&status);
}
+ set_quirks(&dec, hash_12_bits);
wuffs_base__token tok_array[TOK_BUFFER_ARRAY_SIZE];
wuffs_base__token_buffer tok = ((wuffs_base__token_buffer){
@@ -252,7 +308,9 @@
size_t old_src_ri = src.meta.ri;
size_t ti = old_src_ri;
- status = wuffs_json__decoder__decode_tokens(&dec, &tok, &src);
+ status = wuffs_json__decoder__decode_tokens(
+ &dec, &tok, &src,
+ wuffs_base__make_slice_u8(g_work_buffer_array, WORK_BUFFER_ARRAY_SIZE));
if ((tok.data.len < tok.meta.wi) || //
(tok.meta.wi < tok.meta.ri) || //
(tok.meta.ri != old_tok_ri)) {
@@ -341,7 +399,9 @@
});
while (true) {
- status = wuffs_json__decoder__decode_tokens(&dec, &tok, full_src);
+ status = wuffs_json__decoder__decode_tokens(
+ &dec, &tok, full_src,
+ wuffs_base__make_slice_u8(g_work_buffer_array, WORK_BUFFER_ARRAY_SIZE));
if (status.repr == NULL) {
break;
diff --git a/fuzz/c/std/zlib_fuzzer.c b/fuzz/c/std/zlib_fuzzer.c
index 4835c6e..2571b65 100644
--- a/fuzz/c/std/zlib_fuzzer.c
+++ b/fuzz/c/std/zlib_fuzzer.c
@@ -68,10 +68,10 @@
#define WORK_BUFFER_ARRAY_SIZE \
WUFFS_ZLIB__DECODER_WORKBUF_LEN_MAX_INCL_WORST_CASE
#if WORK_BUFFER_ARRAY_SIZE > 0
-uint8_t work_buffer_array[WORK_BUFFER_ARRAY_SIZE];
+uint8_t g_work_buffer_array[WORK_BUFFER_ARRAY_SIZE];
#else
// Not all C/C++ compilers support 0-length arrays.
-uint8_t work_buffer_array[1];
+uint8_t g_work_buffer_array[1];
#endif
const char* //
@@ -99,12 +99,9 @@
while (true) {
dst.meta.wi = 0;
- status =
- wuffs_zlib__decoder__transform_io(&dec, &dst, src,
- ((wuffs_base__slice_u8){
- .ptr = work_buffer_array,
- .len = WORK_BUFFER_ARRAY_SIZE,
- }));
+ status = wuffs_zlib__decoder__transform_io(
+ &dec, &dst, src,
+ wuffs_base__make_slice_u8(g_work_buffer_array, WORK_BUFFER_ARRAY_SIZE));
if (status.repr != wuffs_base__suspension__short_write) {
break;
}
diff --git a/internal/cgen/base/core-public.h b/internal/cgen/base/core-public.h
index accb01a..92ac663 100644
--- a/internal/cgen/base/core-public.h
+++ b/internal/cgen/base/core-public.h
@@ -383,6 +383,80 @@
return res;
}
+// --------
+
+typedef struct {
+ uint64_t hi;
+ uint64_t lo;
+} wuffs_base__multiply_u64__output;
+
+// wuffs_base__multiply_u64 returns x*y as a 128-bit value.
+//
+// The maximum inclusive output hi_lo is 0xFFFFFFFFFFFFFFFE_0000000000000001.
+static inline wuffs_base__multiply_u64__output //
+wuffs_base__multiply_u64(uint64_t x, uint64_t y) {
+ uint64_t x0 = x & 0xFFFFFFFF;
+ uint64_t x1 = x >> 32;
+ uint64_t y0 = y & 0xFFFFFFFF;
+ uint64_t y1 = y >> 32;
+ uint64_t w0 = x0 * y0;
+ uint64_t t = (x1 * y0) + (w0 >> 32);
+ uint64_t w1 = t & 0xFFFFFFFF;
+ uint64_t w2 = t >> 32;
+ w1 += x0 * y1;
+ wuffs_base__multiply_u64__output o;
+ o.hi = (x1 * y1) + w2 + (w1 >> 32);
+ o.lo = x * y;
+ return o;
+}
+
+ // --------
+
+#if defined(__GNUC__) && (__SIZEOF_LONG__ == 8)
+
+static inline uint32_t //
+wuffs_base__count_leading_zeroes_u64(uint64_t u) {
+ return u ? ((uint32_t)(__builtin_clzl(u))) : 64u;
+}
+
+#else
+
+static inline uint32_t //
+wuffs_base__count_leading_zeroes_u64(uint64_t u) {
+ if (u == 0) {
+ return 64;
+ }
+
+ uint32_t n = 0;
+ if ((u >> 32) == 0) {
+ n |= 32;
+ u <<= 32;
+ }
+ if ((u >> 48) == 0) {
+ n |= 16;
+ u <<= 16;
+ }
+ if ((u >> 56) == 0) {
+ n |= 8;
+ u <<= 8;
+ }
+ if ((u >> 60) == 0) {
+ n |= 4;
+ u <<= 4;
+ }
+ if ((u >> 62) == 0) {
+ n |= 2;
+ u <<= 2;
+ }
+ if ((u >> 63) == 0) {
+ n |= 1;
+ u <<= 1;
+ }
+ return n;
+}
+
+#endif // defined(__GNUC__) && (__SIZEOF_LONG__ == 8)
+
// --------
#define wuffs_base__load_u8be__no_bounds_check \
diff --git a/internal/cgen/base/io-public.h b/internal/cgen/base/io-public.h
index d28761d..7b535cd 100644
--- a/internal/cgen/base/io-public.h
+++ b/internal/cgen/base/io-public.h
@@ -36,6 +36,7 @@
wuffs_base__io_buffer_meta meta;
#ifdef __cplusplus
+ inline bool is_valid() const;
inline void compact();
inline uint64_t reader_available() const;
inline uint64_t reader_io_position() const;
@@ -68,6 +69,30 @@
}
static inline wuffs_base__io_buffer //
+wuffs_base__make_io_buffer_reader(wuffs_base__slice_u8 s, bool closed) {
+ wuffs_base__io_buffer ret;
+ ret.data.ptr = s.ptr;
+ ret.data.len = s.len;
+ ret.meta.wi = s.len;
+ ret.meta.ri = 0;
+ ret.meta.pos = 0;
+ ret.meta.closed = closed;
+ return ret;
+}
+
+static inline wuffs_base__io_buffer //
+wuffs_base__make_io_buffer_writer(wuffs_base__slice_u8 s) {
+ wuffs_base__io_buffer ret;
+ ret.data.ptr = s.ptr;
+ ret.data.len = s.len;
+ ret.meta.wi = 0;
+ ret.meta.ri = 0;
+ ret.meta.pos = 0;
+ ret.meta.closed = false;
+ return ret;
+}
+
+static inline wuffs_base__io_buffer //
wuffs_base__empty_io_buffer() {
wuffs_base__io_buffer ret;
ret.data.ptr = NULL;
@@ -89,6 +114,18 @@
return ret;
}
+static inline bool //
+wuffs_base__io_buffer__is_valid(const wuffs_base__io_buffer* buf) {
+ if (buf) {
+ if (buf->data.ptr) {
+ return (buf->meta.ri <= buf->meta.wi) && (buf->meta.wi <= buf->data.len);
+ } else {
+ return (buf->meta.ri == 0) && (buf->meta.wi == 0) && (buf->data.len == 0);
+ }
+ }
+ return false;
+}
+
// wuffs_base__io_buffer__compact moves any written but unread bytes to the
// start of the buffer.
static inline void //
@@ -127,6 +164,11 @@
#ifdef __cplusplus
+inline bool //
+wuffs_base__io_buffer::is_valid() const {
+ return wuffs_base__io_buffer__is_valid(this);
+}
+
inline void //
wuffs_base__io_buffer::compact() {
wuffs_base__io_buffer__compact(this);
diff --git a/internal/cgen/base/strconv-impl.c b/internal/cgen/base/strconv-impl.c
index 1d4dbef..06710a1 100644
--- a/internal/cgen/base/strconv-impl.c
+++ b/internal/cgen/base/strconv-impl.c
@@ -312,6 +312,9 @@
// fixed precision floating point decimal number, augmented with ±infinity
// values, but it cannot represent NaN (Not a Number).
//
+// "High precision" means that the mantissa holds 500 decimal digits. 500 is
+// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION.
+//
// An HPD isn't for general purpose arithmetic, only for conversions to and
// from IEEE 754 double-precision floating point, where the largest and
// smallest positive, finite values are approximately 1.8e+308 and 4.9e-324.
@@ -331,7 +334,7 @@
// For example, if num_digits is 3 and digits is "\x07\x08\x09":
// - A decimal_point of -2 means ".00789"
// - A decimal_point of -1 means ".0789"
-// - A decimal_point of -0 means ".789"
+// - A decimal_point of +0 means ".789"
// - A decimal_point of +1 means "7.89"
// - A decimal_point of +2 means "78.9"
// - A decimal_point of +3 means "789."
@@ -861,6 +864,438 @@
// --------
+// The wuffs_base__private_implementation__etc_powers_of_10 tables were printed
+// by script/print-mpb-powers-of-10.go. That script has an optional -comments
+// flag, whose output is not copied here, which prints further detail.
+//
+// These tables are used in
+// wuffs_base__private_implementation__medium_prec_bin__assign_from_hpd.
+
+// wuffs_base__private_implementation__big_powers_of_10 contains approximations
+// to the powers of 10, ranging from 1e-348 to 1e+340, with the exponent
+// stepping by 8: -348, -340, -332, ..., -12, -4, +4, +12, ..., +340. Each step
+// consists of three uint32_t elements. There are 87 triples, 87 * 3 = 261.
+//
+// For example, the third approximation, for 1e-332, consists of the uint32_t
+// triple (0x3055AC76, 0x8B16FB20, 0xFFFFFB72). The first two of that triple
+// are a little-endian uint64_t value: 0x8B16FB203055AC76. The last one is an
+// int32_t value: -1166. Together, they represent the approximation:
+// 1e-332 ≈ 0x8B16FB203055AC76 * (2 ** -1166)
+// Similarly, the (0x00000000, 0x9C400000, 0xFFFFFFCE) uint32_t triple means:
+// 1e+4 ≈ 0x9C40000000000000 * (2 ** -50) // This approx'n is exact.
+// Similarly, the (0xD4C4FB27, 0xED63A231, 0x000000A2) uint32_t triple means:
+// 1e+68 ≈ 0xED63A231D4C4FB27 * (2 ** 162)
+static const uint32_t
+ wuffs_base__private_implementation__big_powers_of_10[261] = {
+ 0x081C0288, 0xFA8FD5A0, 0xFFFFFB3C, 0xA23EBF76, 0xBAAEE17F, 0xFFFFFB57,
+ 0x3055AC76, 0x8B16FB20, 0xFFFFFB72, 0x5DCE35EA, 0xCF42894A, 0xFFFFFB8C,
+ 0x55653B2D, 0x9A6BB0AA, 0xFFFFFBA7, 0x3D1A45DF, 0xE61ACF03, 0xFFFFFBC1,
+ 0xC79AC6CA, 0xAB70FE17, 0xFFFFFBDC, 0xBEBCDC4F, 0xFF77B1FC, 0xFFFFFBF6,
+ 0x416BD60C, 0xBE5691EF, 0xFFFFFC11, 0x907FFC3C, 0x8DD01FAD, 0xFFFFFC2C,
+ 0x31559A83, 0xD3515C28, 0xFFFFFC46, 0xADA6C9B5, 0x9D71AC8F, 0xFFFFFC61,
+ 0x23EE8BCB, 0xEA9C2277, 0xFFFFFC7B, 0x4078536D, 0xAECC4991, 0xFFFFFC96,
+ 0x5DB6CE57, 0x823C1279, 0xFFFFFCB1, 0x4DFB5637, 0xC2109436, 0xFFFFFCCB,
+ 0x3848984F, 0x9096EA6F, 0xFFFFFCE6, 0x25823AC7, 0xD77485CB, 0xFFFFFD00,
+ 0x97BF97F4, 0xA086CFCD, 0xFFFFFD1B, 0x172AACE5, 0xEF340A98, 0xFFFFFD35,
+ 0x2A35B28E, 0xB23867FB, 0xFFFFFD50, 0xD2C63F3B, 0x84C8D4DF, 0xFFFFFD6B,
+ 0x1AD3CDBA, 0xC5DD4427, 0xFFFFFD85, 0xBB25C996, 0x936B9FCE, 0xFFFFFDA0,
+ 0x7D62A584, 0xDBAC6C24, 0xFFFFFDBA, 0x0D5FDAF6, 0xA3AB6658, 0xFFFFFDD5,
+ 0xDEC3F126, 0xF3E2F893, 0xFFFFFDEF, 0xAAFF80B8, 0xB5B5ADA8, 0xFFFFFE0A,
+ 0x6C7C4A8B, 0x87625F05, 0xFFFFFE25, 0x34C13053, 0xC9BCFF60, 0xFFFFFE3F,
+ 0x91BA2655, 0x964E858C, 0xFFFFFE5A, 0x70297EBD, 0xDFF97724, 0xFFFFFE74,
+ 0xB8E5B88F, 0xA6DFBD9F, 0xFFFFFE8F, 0x88747D94, 0xF8A95FCF, 0xFFFFFEA9,
+ 0x8FA89BCF, 0xB9447093, 0xFFFFFEC4, 0xBF0F156B, 0x8A08F0F8, 0xFFFFFEDF,
+ 0x653131B6, 0xCDB02555, 0xFFFFFEF9, 0xD07B7FAC, 0x993FE2C6, 0xFFFFFF14,
+ 0x2A2B3B06, 0xE45C10C4, 0xFFFFFF2E, 0x697392D3, 0xAA242499, 0xFFFFFF49,
+ 0x8300CA0E, 0xFD87B5F2, 0xFFFFFF63, 0x92111AEB, 0xBCE50864, 0xFFFFFF7E,
+ 0x6F5088CC, 0x8CBCCC09, 0xFFFFFF99, 0xE219652C, 0xD1B71758, 0xFFFFFFB3,
+ 0x00000000, 0x9C400000, 0xFFFFFFCE, 0x00000000, 0xE8D4A510, 0xFFFFFFE8,
+ 0xAC620000, 0xAD78EBC5, 0x00000003, 0xF8940984, 0x813F3978, 0x0000001E,
+ 0xC90715B3, 0xC097CE7B, 0x00000038, 0x7BEA5C70, 0x8F7E32CE, 0x00000053,
+ 0xABE98068, 0xD5D238A4, 0x0000006D, 0x179A2245, 0x9F4F2726, 0x00000088,
+ 0xD4C4FB27, 0xED63A231, 0x000000A2, 0x8CC8ADA8, 0xB0DE6538, 0x000000BD,
+ 0x1AAB65DB, 0x83C7088E, 0x000000D8, 0x42711D9A, 0xC45D1DF9, 0x000000F2,
+ 0xA61BE758, 0x924D692C, 0x0000010D, 0x1A708DEA, 0xDA01EE64, 0x00000127,
+ 0x9AEF774A, 0xA26DA399, 0x00000142, 0xB47D6B85, 0xF209787B, 0x0000015C,
+ 0x79DD1877, 0xB454E4A1, 0x00000177, 0x5B9BC5C2, 0x865B8692, 0x00000192,
+ 0xC8965D3D, 0xC83553C5, 0x000001AC, 0xFA97A0B3, 0x952AB45C, 0x000001C7,
+ 0x99A05FE3, 0xDE469FBD, 0x000001E1, 0xDB398C25, 0xA59BC234, 0x000001FC,
+ 0xA3989F5C, 0xF6C69A72, 0x00000216, 0x54E9BECE, 0xB7DCBF53, 0x00000231,
+ 0xF22241E2, 0x88FCF317, 0x0000024C, 0xD35C78A5, 0xCC20CE9B, 0x00000266,
+ 0x7B2153DF, 0x98165AF3, 0x00000281, 0x971F303A, 0xE2A0B5DC, 0x0000029B,
+ 0x5CE3B396, 0xA8D9D153, 0x000002B6, 0xA4A7443C, 0xFB9B7CD9, 0x000002D0,
+ 0xA7A44410, 0xBB764C4C, 0x000002EB, 0xB6409C1A, 0x8BAB8EEF, 0x00000306,
+ 0xA657842C, 0xD01FEF10, 0x00000320, 0xE9913129, 0x9B10A4E5, 0x0000033B,
+ 0xA19C0C9D, 0xE7109BFB, 0x00000355, 0x623BF429, 0xAC2820D9, 0x00000370,
+ 0x7AA7CF85, 0x80444B5E, 0x0000038B, 0x03ACDD2D, 0xBF21E440, 0x000003A5,
+ 0x5E44FF8F, 0x8E679C2F, 0x000003C0, 0x9C8CB841, 0xD433179D, 0x000003DA,
+ 0xB4E31BA9, 0x9E19DB92, 0x000003F5, 0xBADF77D9, 0xEB96BF6E, 0x0000040F,
+ 0x9BF0EE6B, 0xAF87023B, 0x0000042A,
+};
+
+// wuffs_base__private_implementation__small_powers_of_10 contains
+// approximations to the powers of 10, ranging from 1e+0 to 1e+7, with the
+// exponent stepping by 1. Each step consists of three uint32_t elements.
+//
+// For example, the third approximation, for 1e+2, consists of the uint32_t
+// triple (0x00000000, 0xC8000000, 0xFFFFFFC7). The first two of that triple
+// are a little-endian uint64_t value: 0xC800000000000000. The last one is an
+// int32_t value: -57. Together, they represent the approximation:
+// 1e+2 ≈ 0xC800000000000000 * (2 ** -57) // This approx'n is exact.
+// Similarly, the (0x00000000, 0x9C400000, 0xFFFFFFCE) uint32_t triple means:
+// 1e+4 ≈ 0x9C40000000000000 * (2 ** -50) // This approx'n is exact.
+static const uint32_t
+ wuffs_base__private_implementation__small_powers_of_10[24] = {
+ 0x00000000, 0x80000000, 0xFFFFFFC1, 0x00000000, 0xA0000000, 0xFFFFFFC4,
+ 0x00000000, 0xC8000000, 0xFFFFFFC7, 0x00000000, 0xFA000000, 0xFFFFFFCA,
+ 0x00000000, 0x9C400000, 0xFFFFFFCE, 0x00000000, 0xC3500000, 0xFFFFFFD1,
+ 0x00000000, 0xF4240000, 0xFFFFFFD4, 0x00000000, 0x98968000, 0xFFFFFFD8,
+};
+
+// wuffs_base__private_implementation__f64_powers_of_10 holds powers of 10 that
+// can be exactly represented by a float64 (what C calls a double).
+static const double wuffs_base__private_implementation__f64_powers_of_10[23] = {
+ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11,
+ 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22,
+};
+
+// --------
+
+// wuffs_base__private_implementation__medium_prec_bin (abbreviated as MPB) is
+// a fixed precision floating point binary number. Unlike IEEE 754 Floating
+// Point, it cannot represent infinity or NaN (Not a Number).
+//
+// "Medium precision" means that the mantissa holds 64 binary digits, a little
+// more than "double precision", and sizeof(MPB) > sizeof(double). 64 is
+// obviously the number of bits in a uint64_t.
+//
+// An MPB isn't for general purpose arithmetic, only for conversions to and
+// from IEEE 754 double-precision floating point.
+//
+// There is no implicit mantissa bit. The mantissa field is zero if and only if
+// the overall floating point value is ±0. An MPB is normalized if the mantissa
+// is zero or its high bit (the 1<<63 bit) is set.
+//
+// There is no negative bit. An MPB can only represent non-negative numbers.
+//
+// The "all fields are zero" value is valid, and represents the number +0.
+//
+// This is the "Do It Yourself Floating Point" data structure from Loitsch,
+// "Printing Floating-Point Numbers Quickly and Accurately with Integers"
+// (https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf).
+//
+// Florian Loitsch is also the primary contributor to
+// https://github.com/google/double-conversion
+typedef struct {
+ uint64_t mantissa;
+ int32_t exp2;
+} wuffs_base__private_implementation__medium_prec_bin;
+
+static uint32_t //
+wuffs_base__private_implementation__medium_prec_bin__normalize(
+ wuffs_base__private_implementation__medium_prec_bin* m) {
+ if (m->mantissa == 0) {
+ return 0;
+ }
+ uint32_t shift = wuffs_base__count_leading_zeroes_u64(m->mantissa);
+ m->mantissa <<= shift;
+ m->exp2 -= (int32_t)shift;
+ return shift;
+}
+
+// wuffs_base__private_implementation__medium_prec_bin__mul_pow_10 sets m to be
+// (m * pow), where pow comes from an etc_powers_of_10 triple starting at p.
+//
+// The result is rounded, but not necessarily normalized.
+//
+// Preconditions:
+// - m is non-NULL.
+// - m->mantissa is non-zero.
+// - m->mantissa's high bit is set (i.e. m is normalized).
+//
+// The etc_powers_of_10 triple is already normalized.
+static void //
+wuffs_base__private_implementation__medium_prec_bin__mul_pow_10(
+ wuffs_base__private_implementation__medium_prec_bin* m,
+ const uint32_t* p) {
+ uint64_t p_mantissa = ((uint64_t)p[0]) | (((uint64_t)p[1]) << 32);
+ int32_t p_exp2 = (int32_t)p[2];
+
+ wuffs_base__multiply_u64__output o =
+ wuffs_base__multiply_u64(m->mantissa, p_mantissa);
+ // Round the mantissa up. It cannot overflow because the maximum possible
+ // value of o.hi is 0xFFFFFFFFFFFFFFFE.
+ m->mantissa = o.hi + (o.lo >> 63);
+ m->exp2 = m->exp2 + p_exp2 + 64;
+}
+
+// wuffs_base__private_implementation__medium_prec_bin__as_f64 converts m to a
+// double (what C calls a double-precision float64).
+//
+// Preconditions:
+// - m is non-NULL.
+// - m->mantissa is non-zero.
+// - m->mantissa's high bit is set (i.e. m is normalized).
+static double //
+wuffs_base__private_implementation__medium_prec_bin__as_f64(
+ const wuffs_base__private_implementation__medium_prec_bin* m,
+ bool negative) {
+ uint64_t mantissa64 = m->mantissa;
+ // An mpb's mantissa has the implicit (binary) decimal point at the right
+ // hand end of the mantissa's explicit digits. A double-precision's mantissa
+ // has that decimal point near the left hand end. There's also an explicit
+ // versus implicit leading 1 bit (binary digit). Together, the difference in
+ // semantics corresponds to adding 63.
+ int32_t exp2 = m->exp2 + 63;
+
+ // Ensure that exp2 is at least -1022, the minimum double-precision exponent
+ // for normal (as opposed to subnormal) numbers.
+ if (-1022 > exp2) {
+ uint32_t n = (uint32_t)(-1022 - exp2);
+ mantissa64 >>= n;
+ exp2 += (int32_t)n;
+ }
+
+ // Extract the (1 + 52) bits from the 64-bit mantissa64. 52 is the number of
+ // explicit mantissa bits in a double-precision f64.
+ //
+ // Before, we have 64 bits and due to normalization, the high bit 'H' is 1.
+ // 63 55 47 etc 15 7
+ // H210_9876_5432_1098_7654_etc_etc_etc_5432_1098_7654_3210
+ // ++++_++++_++++_++++_++++_etc_etc_etc_++++_+..._...._.... Kept bits.
+ // ...._...._...H_2109_8765_etc_etc_etc_6543_2109_8765_4321 After shifting.
+ // After, we have 53 bits (and bit #52 is this 'H' bit).
+ uint64_t mantissa53 = mantissa64 >> 11;
+
+ // Round up if the old bit #10 (the highest bit dropped by shifting) was set.
+ // We also fix any overflow from rounding up.
+ if (mantissa64 & 1024) {
+ mantissa53++;
+ if ((mantissa53 >> 53) != 0) {
+ mantissa53 >>= 1;
+ exp2++;
+ }
+ }
+
+ // Handle double-precision infinity (a nominal exponent of 1024) and
+ // subnormals (an exponent of -1023 and no implicit mantissa bit, bit #52).
+ if (exp2 >= 1024) {
+ mantissa53 = 0;
+ exp2 = 1024;
+ } else if ((mantissa53 >> 52) == 0) {
+ exp2 = -1023;
+ }
+
+ // Pack the bits and return.
+ const int32_t f64_bias = -1023;
+ uint64_t exp2_bits =
+ (uint64_t)((exp2 - f64_bias) & 0x07FF); // (1 << 11) - 1.
+ uint64_t bits = (mantissa53 & 0x000FFFFFFFFFFFFF) | // (1 << 52) - 1.
+ (exp2_bits << 52) | //
+ (negative ? 0x8000000000000000 : 0); // (1 << 63).
+ return wuffs_base__ieee_754_bit_representation__to_f64(bits);
+}
+
+// wuffs_base__private_implementation__medium_prec_bin__parse_number_f64
+// converts from an HPD to a double, using an MPB as scratch space. It returns
+// a NULL status.repr if there is no ambiguity in the truncation or rounding to
+// a float64 (an IEEE 754 double-precision floating point value).
+//
+// It may modify m even if it returns a non-NULL status.repr.
+static wuffs_base__result_f64 //
+wuffs_base__private_implementation__medium_prec_bin__parse_number_f64(
+ wuffs_base__private_implementation__medium_prec_bin* m,
+ const wuffs_base__private_implementation__high_prec_dec* h,
+ bool skip_fast_path_for_tests) {
+ do {
+ // m->mantissa is a uint64_t, which is an integer approximation to a
+ // rational value - h's underlying digits after m's normalization. This
+ // error is an upper bound on the difference between the approximate and
+ // actual value.
+ //
+ // The DiyFpStrtod function in https://github.com/google/double-conversion
+ // uses a finer grain (1/8th of the ULP, Unit in the Last Place) when
+ // tracking error. This implementation is coarser (1 ULP) but simpler.
+ //
+ // It is an error in the "numerical approximation" sense, not in the
+ // typical programming sense (as in "bad input" or "a result type").
+ uint64_t error = 0;
+
+ // Convert up to 19 decimal digits (in h->digits) to 64 binary digits (in
+ // m->mantissa): (1e19 < (1<<64)) and ((1<<64) < 1e20). If we have more
+ // than 19 digits, we're truncating (with error).
+ uint32_t i;
+ uint32_t i_end = h->num_digits;
+ if (i_end > 19) {
+ i_end = 19;
+ error = 1;
+ }
+ uint64_t mantissa = 0;
+ for (i = 0; i < i_end; i++) {
+ mantissa = (10 * mantissa) + h->digits[i];
+ }
+ m->mantissa = mantissa;
+ m->exp2 = 0;
+
+ // Check that exp10 lies in the (big_powers_of_10 + small_powers_of_10)
+ // range, -348 ..= +347, stepping big_powers_of_10 by 8 (which is 87
+ // triples) and small_powers_of_10 by 1 (which is 8 triples).
+ int32_t exp10 = h->decimal_point - ((int32_t)(i_end));
+ if (exp10 < -348) {
+ goto fail;
+ }
+ uint32_t bpo10 = ((uint32_t)(exp10 + 348)) / 8;
+ uint32_t spo10 = ((uint32_t)(exp10 + 348)) % 8;
+ if (bpo10 >= 87) {
+ goto fail;
+ }
+
+ // Try a fast path, if float64 math would be exact.
+ //
+ // 15 is such that 1e15 can be losslessly represented in a float64
+ // mantissa: (1e15 < (1<<53)) and ((1<<53) < 1e16).
+ //
+ // 22 is the maximum valid index for the
+ // wuffs_base__private_implementation__f64_powers_of_10 array.
+ do {
+ if (skip_fast_path_for_tests || ((mantissa >> 52) != 0)) {
+ break;
+ }
+ double d = (double)mantissa;
+
+ if (exp10 == 0) {
+ wuffs_base__result_f64 ret;
+ ret.status.repr = NULL;
+ ret.value = h->negative ? -d : +d;
+ return ret;
+
+ } else if (exp10 > 0) {
+ if (exp10 > 22) {
+ if (exp10 > (15 + 22)) {
+ break;
+ }
+ // If exp10 is in the range 23 ..= 37, try moving a few of the zeroes
+ // from the exponent to the mantissa. If we're still under 1e15, we
+ // haven't truncated any mantissa bits.
+ if (exp10 > 22) {
+ d *= wuffs_base__private_implementation__f64_powers_of_10[exp10 -
+ 22];
+ exp10 = 22;
+ if (d >= 1e15) {
+ break;
+ }
+ }
+ }
+ d *= wuffs_base__private_implementation__f64_powers_of_10[exp10];
+ wuffs_base__result_f64 ret;
+ ret.status.repr = NULL;
+ ret.value = h->negative ? -d : +d;
+ return ret;
+
+ } else { // "if (exp10 < 0)" is effectively "if (true)" here.
+ if (exp10 < -22) {
+ break;
+ }
+ d /= wuffs_base__private_implementation__f64_powers_of_10[-exp10];
+ wuffs_base__result_f64 ret;
+ ret.status.repr = NULL;
+ ret.value = h->negative ? -d : +d;
+ return ret;
+ }
+ } while (0);
+
+ // Normalize (and scale the error).
+ error <<= wuffs_base__private_implementation__medium_prec_bin__normalize(m);
+
+ // Multiplying two MPB values nominally multiplies two mantissas, call them
+ // A and B, which are integer approximations to the precise values (A+a)
+ // and (B+b) for some error terms a and b.
+ //
+ // MPB multiplication calculates (((A+a) * (B+b)) >> 64) to be ((A*B) >>
+ // 64). Shifting (truncating) and rounding introduces further error. The
+ // difference between the calculated result:
+ // ((A*B ) >> 64)
+ // and the true result:
+ // ((A*B + A*b + a*B + a*b) >> 64) + rounding_error
+ // is:
+ // (( A*b + a*B + a*b) >> 64) + rounding_error
+ // which can be re-grouped as:
+ // ((A*b) >> 64) + ((a*(B+b)) >> 64) + rounding_error
+ //
+ // Now, let A and a be "m->mantissa" and "error", and B and b be the
+ // pre-calculated power of 10. A and B are both less than (1 << 64), a is
+ // the "error" local variable and b is less than 1.
+ //
+ // An upper bound (in absolute value) on ((A*b) >> 64) is therefore 1.
+ //
+ // An upper bound on ((a*(B+b)) >> 64) is a, also known as error.
+ //
+ // Finally, the rounding_error is at most 1.
+ //
+ // In total, calling mpb__mul_pow_10 will raise the worst-case error by 2.
+ // The subsequent re-normalization can multiply that by a further factor.
+
+ // Multiply by small_powers_of_10[etc].
+ wuffs_base__private_implementation__medium_prec_bin__mul_pow_10(
+ m, &wuffs_base__private_implementation__small_powers_of_10[3 * spo10]);
+ error += 2;
+ error <<= wuffs_base__private_implementation__medium_prec_bin__normalize(m);
+
+ // Multiply by big_powers_of_10[etc].
+ wuffs_base__private_implementation__medium_prec_bin__mul_pow_10(
+ m, &wuffs_base__private_implementation__big_powers_of_10[3 * bpo10]);
+ error += 2;
+ error <<= wuffs_base__private_implementation__medium_prec_bin__normalize(m);
+
+ // We have a good approximation of h, but we still have to check whether
+ // the error is small enough. Equivalently, whether the number of surplus
+ // mantissa bits (the bits dropped when going from m's 64 mantissa bits to
+ // the smaller number of double-precision mantissa bits) would always round
+ // up or down, even when perturbed by ±error. We start at 11 surplus bits
+ // (m has 64, double-precision has 1+52), but it can be higher for
+ // subnormals.
+ //
+ // In many cases, the error is small enough and we return true.
+ const int32_t f64_bias = -1023;
+ int32_t subnormal_exp2 = f64_bias - 63;
+ uint32_t surplus_bits = 11;
+ if (subnormal_exp2 >= m->exp2) {
+ surplus_bits += 1 + ((uint32_t)(subnormal_exp2 - m->exp2));
+ }
+
+ uint64_t surplus_mask =
+ (((uint64_t)1) << surplus_bits) - 1; // e.g. 0x07FF.
+ uint64_t surplus = m->mantissa & surplus_mask;
+ uint64_t halfway = ((uint64_t)1) << (surplus_bits - 1); // e.g. 0x0400.
+
+ // Do the final calculation in *signed* arithmetic.
+ int64_t i_surplus = (int64_t)surplus;
+ int64_t i_halfway = (int64_t)halfway;
+ int64_t i_error = (int64_t)error;
+
+ if ((i_surplus > (i_halfway - i_error)) &&
+ (i_surplus < (i_halfway + i_error))) {
+ goto fail;
+ }
+
+ wuffs_base__result_f64 ret;
+ ret.status.repr = NULL;
+ ret.value = wuffs_base__private_implementation__medium_prec_bin__as_f64(
+ m, h->negative);
+ return ret;
+ } while (0);
+
+fail:
+ do {
+ wuffs_base__result_f64 ret;
+ ret.status.repr = "#base: mpb__parse_number_f64 failed";
+ ret.value = 0;
+ return ret;
+ } while (0);
+}
+
+// --------
+
wuffs_base__result_f64 //
wuffs_base__parse_number_f64_special(wuffs_base__slice_u8 s,
const char* fallback_status_repr) {
@@ -964,6 +1399,7 @@
wuffs_base__result_f64 //
wuffs_base__parse_number_f64(wuffs_base__slice_u8 s) {
+ wuffs_base__private_implementation__medium_prec_bin m;
wuffs_base__private_implementation__high_prec_dec h;
do {
@@ -990,10 +1426,17 @@
goto infinity;
}
+ wuffs_base__result_f64 mpb_result =
+ wuffs_base__private_implementation__medium_prec_bin__parse_number_f64(
+ &m, &h, false);
+ if (mpb_result.status.repr == NULL) {
+ return mpb_result;
+ }
+
// Scale by powers of 2 until we're in the range [½ .. 1], which gives us
// our exponent (in base-2). First we shift right, possibly a little too
// far, ending with a value certainly below 1 and possibly below ½...
- const int32_t bias = -1023;
+ const int32_t f64_bias = -1023;
int32_t exp2 = 0;
while (h.decimal_point > 0) {
uint32_t n = (uint32_t)(+h.decimal_point);
@@ -1037,9 +1480,9 @@
// We're in the range [½ .. 1] but f64 uses [1 .. 2].
exp2--;
- // The minimum normal exponent is (bias + 1).
- while ((bias + 1) > exp2) {
- uint32_t n = (uint32_t)((bias + 1) - exp2);
+ // The minimum normal exponent is (f64_bias + 1).
+ while ((f64_bias + 1) > exp2) {
+ uint32_t n = (uint32_t)((f64_bias + 1) - exp2);
if (n > WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL) {
n = WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL;
}
@@ -1048,7 +1491,7 @@
}
// Check for overflow.
- if ((exp2 - bias) >= 0x07FF) { // (1 << 11) - 1.
+ if ((exp2 - f64_bias) >= 0x07FF) { // (1 << 11) - 1.
goto infinity;
}
@@ -1061,21 +1504,22 @@
if ((man2 >> 53) != 0) {
man2 >>= 1;
exp2++;
- if ((exp2 - bias) >= 0x07FF) { // (1 << 11) - 1.
+ if ((exp2 - f64_bias) >= 0x07FF) { // (1 << 11) - 1.
goto infinity;
}
}
// Handle subnormal numbers.
if ((man2 >> 52) == 0) {
- exp2 = bias;
+ exp2 = f64_bias;
}
// Pack the bits and return.
- uint64_t exp2_bits = (uint64_t)((exp2 - bias) & 0x07FF); // (1 << 11) - 1.
- uint64_t bits = (man2 & 0x000FFFFFFFFFFFFF) | // (1 << 52) - 1.
- (exp2_bits << 52) | //
- (h.negative ? 0x8000000000000000 : 0); // (1 << 63).
+ uint64_t exp2_bits =
+ (uint64_t)((exp2 - f64_bias) & 0x07FF); // (1 << 11) - 1.
+ uint64_t bits = (man2 & 0x000FFFFFFFFFFFFF) | // (1 << 52) - 1.
+ (exp2_bits << 52) | //
+ (h.negative ? 0x8000000000000000 : 0); // (1 << 63).
wuffs_base__result_f64 ret;
ret.status.repr = NULL;
@@ -1104,6 +1548,46 @@
} while (0);
}
+// ---------------- Hexadecimal
+
+size_t //
+wuffs_base__hexadecimal__decode2(wuffs_base__slice_u8 dst,
+ wuffs_base__slice_u8 src) {
+ size_t src_len2 = src.len / 2;
+ size_t len = dst.len < src_len2 ? dst.len : src_len2;
+ uint8_t* d = dst.ptr;
+ uint8_t* s = src.ptr;
+ size_t n = len;
+
+ while (n--) {
+ *d = (uint8_t)((wuffs_base__parse_number__hexadecimal_digits[s[0]] << 4) |
+ (wuffs_base__parse_number__hexadecimal_digits[s[1]] & 0x0F));
+ d += 1;
+ s += 2;
+ }
+
+ return len;
+}
+
+size_t //
+wuffs_base__hexadecimal__decode4(wuffs_base__slice_u8 dst,
+ wuffs_base__slice_u8 src) {
+ size_t src_len4 = src.len / 4;
+ size_t len = dst.len < src_len4 ? dst.len : src_len4;
+ uint8_t* d = dst.ptr;
+ uint8_t* s = src.ptr;
+ size_t n = len;
+
+ while (n--) {
+ *d = (uint8_t)((wuffs_base__parse_number__hexadecimal_digits[s[2]] << 4) |
+ (wuffs_base__parse_number__hexadecimal_digits[s[3]] & 0x0F));
+ d += 1;
+ s += 4;
+ }
+
+ return len;
+}
+
// ---------------- Unicode and UTF-8
size_t //
diff --git a/internal/cgen/base/strconv-public.h b/internal/cgen/base/strconv-public.h
index 65c60ec..c6f7ad6 100644
--- a/internal/cgen/base/strconv-public.h
+++ b/internal/cgen/base/strconv-public.h
@@ -120,7 +120,35 @@
return f;
}
- // ---------------- Unicode and UTF-8
+// ---------------- Hexadecimal
+
+// wuffs_base__hexadecimal__decode2 converts "6A6b" to "jk", where e.g. 'j' is
+// U+006A. There are 2 source bytes for every destination byte.
+//
+// It returns the number of dst bytes written: the minimum of dst.len and
+// (src.len / 2). Excess source bytes are ignored.
+//
+// It assumes that the src bytes are two hexadecimal digits (0-9, A-F, a-f),
+// repeated. It may write nonsense bytes if not, although it will not read or
+// write out of bounds.
+size_t //
+wuffs_base__hexadecimal__decode2(wuffs_base__slice_u8 dst,
+ wuffs_base__slice_u8 src);
+
+// wuffs_base__hexadecimal__decode4 converts "\\x6A\\x6b" to "jk", where e.g.
+// 'j' is U+006A. There are 4 source bytes for every destination byte.
+//
+// It returns the number of dst bytes written: the minimum of dst.len and
+// (src.len / 4). Excess source bytes are ignored.
+//
+// It assumes that the src bytes are two ignored bytes and then two hexadecimal
+// digits (0-9, A-F, a-f), repeated. It may write nonsense bytes if not,
+// although it will not read or write out of bounds.
+size_t //
+wuffs_base__hexadecimal__decode4(wuffs_base__slice_u8 dst,
+ wuffs_base__slice_u8 src);
+
+// ---------------- Unicode and UTF-8
#define WUFFS_BASE__UNICODE_CODE_POINT__MIN_INCL 0x00000000
#define WUFFS_BASE__UNICODE_CODE_POINT__MAX_INCL 0x0010FFFF
diff --git a/internal/cgen/base/token-public.h b/internal/cgen/base/token-public.h
index 31f02e7..1c4c7c2 100644
--- a/internal/cgen/base/token-public.h
+++ b/internal/cgen/base/token-public.h
@@ -180,6 +180,11 @@
#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_SIGNED 0x00002
#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_UNSIGNED 0x00004
+#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_NEG_INF 0x00010
+#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_POS_INF 0x00020
+#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_NEG_NAN 0x00040
+#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_POS_NAN 0x00080
+
// The number 300 might be represented as "\x01\x2C", "\x2C\x01\x00\x00" or
// "300", which are big-endian, little-endian or text. For binary formats, the
// token length discriminates e.g. u16 little-endian vs u32 little-endian.
@@ -311,6 +316,7 @@
wuffs_base__token_buffer_meta meta;
#ifdef __cplusplus
+ inline bool is_valid() const;
inline void compact();
inline uint64_t reader_available() const;
inline uint64_t reader_token_position() const;
@@ -343,6 +349,30 @@
}
static inline wuffs_base__token_buffer //
+wuffs_base__make_token_buffer_reader(wuffs_base__slice_token s, bool closed) {
+ wuffs_base__token_buffer ret;
+ ret.data.ptr = s.ptr;
+ ret.data.len = s.len;
+ ret.meta.wi = s.len;
+ ret.meta.ri = 0;
+ ret.meta.pos = 0;
+ ret.meta.closed = closed;
+ return ret;
+}
+
+static inline wuffs_base__token_buffer //
+wuffs_base__make_token_buffer_writer(wuffs_base__slice_token s) {
+ wuffs_base__token_buffer ret;
+ ret.data.ptr = s.ptr;
+ ret.data.len = s.len;
+ ret.meta.wi = 0;
+ ret.meta.ri = 0;
+ ret.meta.pos = 0;
+ ret.meta.closed = false;
+ return ret;
+}
+
+static inline wuffs_base__token_buffer //
wuffs_base__empty_token_buffer() {
wuffs_base__token_buffer ret;
ret.data.ptr = NULL;
@@ -364,6 +394,18 @@
return ret;
}
+static inline bool //
+wuffs_base__token_buffer__is_valid(const wuffs_base__token_buffer* buf) {
+ if (buf) {
+ if (buf->data.ptr) {
+ return (buf->meta.ri <= buf->meta.wi) && (buf->meta.wi <= buf->data.len);
+ } else {
+ return (buf->meta.ri == 0) && (buf->meta.wi == 0) && (buf->data.len == 0);
+ }
+ }
+ return false;
+}
+
// wuffs_base__token_buffer__compact moves any written but unread tokens to the
// start of the buffer.
static inline void //
@@ -407,6 +449,11 @@
#ifdef __cplusplus
+inline bool //
+wuffs_base__token_buffer::is_valid() const {
+ return wuffs_base__token_buffer__is_valid(this);
+}
+
inline void //
wuffs_base__token_buffer::compact() {
wuffs_base__token_buffer__compact(this);
diff --git a/internal/cgen/builtin.go b/internal/cgen/builtin.go
index a6676fc..06cc079 100644
--- a/internal/cgen/builtin.go
+++ b/internal/cgen/builtin.go
@@ -177,6 +177,14 @@
b.writeb(')')
return nil
+ case t.IDPeekU64LEAt:
+ b.printf("wuffs_base__load_u64le__no_bounds_check(%s%s + ", iopPrefix, name)
+ if err := g.writeExpr(b, args[0].AsArg().Value(), depth); err != nil {
+ return err
+ }
+ b.writeb(')')
+ return nil
+
case t.IDPosition:
b.printf("wuffs_base__u64__sat_add(%s->meta.pos, ((uint64_t)(%s%s - %s%s)))",
name, iopPrefix, name, io0Prefix, name)
@@ -711,12 +719,28 @@
scratchName := fmt.Sprintf("self->private_data.%s%s[0].scratch",
sPrefix, g.currFunk.astFunc.FuncName().Str(g.tm))
+ args := n.Args()
b.printf("%s = (((uint64_t)(", scratchName)
- if err := g.writeExpr(b, n.Args()[0].AsArg().Value(), depth); err != nil {
+ if cv := args[0].AsArg().Value().ConstValue(); (cv == nil) || (cv.Sign() != 0) {
+ if err := g.writeExpr(b, args[0].AsArg().Value(), depth); err != nil {
+ return err
+ }
+ b.writes(")) << WUFFS_BASE__TOKEN__VALUE_MAJOR__SHIFT) | (((uint64_t)(")
+ }
+
+ if err := g.writeExpr(b, args[1].AsArg().Value(), depth); err != nil {
return err
}
- b.writes(")) << WUFFS_BASE__TOKEN__VLL__SHIFT) | (((uint64_t)(")
- if err := g.writeExpr(b, n.Args()[1].AsArg().Value(), depth); err != nil {
+ b.writes(")) << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) | (((uint64_t)(")
+
+ if cv := args[2].AsArg().Value().ConstValue(); (cv == nil) || (cv.Sign() != 0) {
+ if err := g.writeExpr(b, args[2].AsArg().Value(), depth); err != nil {
+ return err
+ }
+ b.writes(")) << WUFFS_BASE__TOKEN__LINK__SHIFT) | (((uint64_t)(")
+ }
+
+ if err := g.writeExpr(b, args[3].AsArg().Value(), depth); err != nil {
return err
}
b.writes(")) << WUFFS_BASE__TOKEN__LENGTH__SHIFT);\n")
diff --git a/internal/cgen/data.go b/internal/cgen/data.go
index 9d9a653..437a056 100644
--- a/internal/cgen/data.go
+++ b/internal/cgen/data.go
@@ -79,14 +79,14 @@
"wuffs_base__parse_number__hexadecimal_digits[*p++];\n if (v == 0) {\n goto fail_bad_argument;\n }\n v &= 0x0F;\n\n for (; p < q; p++) {\n if (*p == '_') {\n continue;\n }\n uint8_t digit = wuffs_base__parse_number__hexadecimal_digits[*p];\n if (digit == 0) {\n goto fail_bad_argument;\n }\n digit &= 0x0F;\n if ((v >> 60) != 0) {\n goto fail_out_of_bounds;\n }\n v = (v << 4) | ((uint64_t)(digit));\n }\n\n wuffs_base__result_u64 ret;\n ret.status.repr = NULL;\n ret.value = v;\n return ret;\n } while (0);\n\nok_zero:\n do {\n wuffs_base__result_u64 ret;\n ret.status.repr = NULL;\n ret.value = 0;\n return ret;\n } while (0);\n\nfail_bad_argument:\n do {\n wuffs_base__result_u64 ret;\n ret.status.repr = wuffs_base__error__bad_argument;\n ret.value = 0;\n return ret;\n } while (0);\n\nfail_out_of_bounds:\n do {\n wuffs_base__result_u64 ret;\n ret.status.repr = wuffs_base__error__out_of_bounds;\n ret.value = 0;\n return ret;\n " +
" } while (0);\n}\n\n " +
"" +
- "// ---------------- IEEE 754 Floating Point\n\n#define WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE 1023\n#define WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION 500\n\n// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL is the largest N\n// such that ((10 << N) < (1 << 64)).\n#define WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL 60\n\n// wuffs_base__private_implementation__high_prec_dec (abbreviated as HPD) is a\n// fixed precision floating point decimal number, augmented with ±infinity\n// values, but it cannot represent NaN (Not a Number).\n//\n// An HPD isn't for general purpose arithmetic, only for conversions to and\n// from IEEE 754 double-precision floating point, where the largest and\n// smallest positive, finite values are approximately 1.8e+308 and 4.9e-324.\n// HPD exponents above +1023 mean infinity, below -1023 mean zero. The ±1023\n// bounds are further away from zero than ±(324 + 500), where 500 and 1023 is\n// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRE" +
- "CISION and\n// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE.\n//\n// digits[.. num_digits] are the number's digits in big-endian order. The\n// uint8_t values are in the range [0 ..= 9], not ['0' ..= '9'], where e.g. '7'\n// is the ASCII value 0x37.\n//\n// decimal_point is the index (within digits) of the decimal point. It may be\n// negative or be larger than num_digits, in which case the explicit digits are\n// padded with implicit zeroes.\n//\n// For example, if num_digits is 3 and digits is \"\\x07\\x08\\x09\":\n// - A decimal_point of -2 means \".00789\"\n// - A decimal_point of -1 means \".0789\"\n// - A decimal_point of -0 means \".789\"\n// - A decimal_point of +1 means \"7.89\"\n// - A decimal_point of +2 means \"78.9\"\n// - A decimal_point of +3 means \"789.\"\n// - A decimal_point of +4 means \"7890.\"\n// - A decimal_point of +5 means \"78900.\"\n//\n// As above, a decimal_point higher than +1023 means that the overall value is\n// infinity, lower than -1023 means zero.\n//\n// negative is a sign bit. An HP" +
- "D can distinguish positive and negative zero.\n//\n// truncated is whether there are more than\n// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION digits, and at\n// least one of those extra digits are non-zero. The existence of long-tail\n// digits can affect rounding.\n//\n// The \"all fields are zero\" value is valid, and represents the number +0.\ntypedef struct {\n uint32_t num_digits;\n int32_t decimal_point;\n bool negative;\n bool truncated;\n uint8_t digits[WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION];\n} wuffs_base__private_implementation__high_prec_dec;\n\n// wuffs_base__private_implementation__high_prec_dec__trim trims trailing\n// zeroes from the h->digits[.. h->num_digits] slice. They have no benefit,\n// since we explicitly track h->decimal_point.\n//\n// Preconditions:\n// - h is non-NULL.\nstatic inline void //\nwuffs_base__private_implementation__high_prec_dec__trim(\n wuffs_base__private_implementation__high_prec_dec* h) {\n while ((h->num_digits > 0) && (h->digits[h->num_digits - 1" +
- "] == 0)) {\n h->num_digits--;\n }\n}\n\nstatic wuffs_base__status //\nwuffs_base__private_implementation__high_prec_dec__parse(\n wuffs_base__private_implementation__high_prec_dec* h,\n wuffs_base__slice_u8 s) {\n if (!h) {\n return wuffs_base__make_status(wuffs_base__error__bad_receiver);\n }\n h->num_digits = 0;\n h->decimal_point = 0;\n h->negative = false;\n h->truncated = false;\n\n uint8_t* p = s.ptr;\n uint8_t* q = s.ptr + s.len;\n\n for (; (p < q) && (*p == '_'); p++) {\n }\n if (p >= q) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n\n // Parse sign.\n do {\n if (*p == '+') {\n p++;\n } else if (*p == '-') {\n h->negative = true;\n p++;\n } else {\n break;\n }\n for (; (p < q) && (*p == '_'); p++) {\n }\n } while (0);\n\n // Parse digits.\n uint32_t nd = 0;\n int32_t dp = 0;\n bool saw_digits = false;\n bool saw_non_zero_digits = false;\n bool saw_dot = false;\n for (; p < q; p++) {\n if (*p == '_') {\n // No-op.\n\n } else if ((*p == '" +
- ".') || (*p == ',')) {\n // As per https://en.wikipedia.org/wiki/Decimal_separator, both '.' or\n // ',' are commonly used. We just parse either, regardless of LOCALE.\n if (saw_dot) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n saw_dot = true;\n dp = (int32_t)nd;\n\n } else if ('0' == *p) {\n if (!saw_dot && !saw_non_zero_digits && saw_digits) {\n // We don't allow unnecessary leading zeroes: \"000123\" or \"0644\".\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n saw_digits = true;\n if (nd == 0) {\n // Track leading zeroes implicitly.\n dp--;\n } else if (nd <\n WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION) {\n h->digits[nd++] = 0;\n } else {\n // Long-tail zeroes are ignored.\n }\n\n } else if (('0' < *p) && (*p <= '9')) {\n if (!saw_dot && !saw_non_zero_digits && saw_digits) {\n // We don't allow unnecessary leading zeroes: \"" +
- "000123\" or \"0644\".\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n saw_digits = true;\n saw_non_zero_digits = true;\n if (nd < WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION) {\n h->digits[nd++] = (uint8_t)(*p - '0');\n } else {\n // Long-tail non-zeroes set the truncated bit.\n h->truncated = true;\n }\n\n } else {\n break;\n }\n }\n\n if (!saw_digits) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n if (!saw_dot) {\n dp = (int32_t)nd;\n }\n\n // Parse exponent.\n if ((p < q) && ((*p == 'E') || (*p == 'e'))) {\n p++;\n for (; (p < q) && (*p == '_'); p++) {\n }\n if (p >= q) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n\n int32_t exp_sign = +1;\n if (*p == '+') {\n p++;\n } else if (*p == '-') {\n exp_sign = -1;\n p++;\n }\n\n int32_t exp = 0;\n const int32_t exp_large =\n WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_P" +
- "OINT__RANGE +\n WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION;\n bool saw_exp_digits = false;\n for (; p < q; p++) {\n if (*p == '_') {\n // No-op.\n } else if (('0' <= *p) && (*p <= '9')) {\n saw_exp_digits = true;\n if (exp < exp_large) {\n exp = (10 * exp) + ((int32_t)(*p - '0'));\n }\n } else {\n break;\n }\n }\n if (!saw_exp_digits) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n dp += exp_sign * exp;\n }\n\n // Finish.\n if (p != q) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n h->num_digits = nd;\n if (nd == 0) {\n h->decimal_point = 0;\n } else if (dp <\n -WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) {\n h->decimal_point =\n -WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE - 1;\n } else if (dp >\n +WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) {\n h->decimal_point =\n +WU" +
- "FFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE + 1;\n } else {\n h->decimal_point = dp;\n }\n wuffs_base__private_implementation__high_prec_dec__trim(h);\n return wuffs_base__make_status(NULL);\n}\n\n" +
+ "// ---------------- IEEE 754 Floating Point\n\n#define WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE 1023\n#define WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION 500\n\n// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL is the largest N\n// such that ((10 << N) < (1 << 64)).\n#define WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL 60\n\n// wuffs_base__private_implementation__high_prec_dec (abbreviated as HPD) is a\n// fixed precision floating point decimal number, augmented with ±infinity\n// values, but it cannot represent NaN (Not a Number).\n//\n// \"High precision\" means that the mantissa holds 500 decimal digits. 500 is\n// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION.\n//\n// An HPD isn't for general purpose arithmetic, only for conversions to and\n// from IEEE 754 double-precision floating point, where the largest and\n// smallest positive, finite values are approximately 1.8e+308 and 4.9e-324.\n// HPD exponents above +1023 mean infinity, below -1023 mean zero. Th" +
+ "e ±1023\n// bounds are further away from zero than ±(324 + 500), where 500 and 1023 is\n// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION and\n// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE.\n//\n// digits[.. num_digits] are the number's digits in big-endian order. The\n// uint8_t values are in the range [0 ..= 9], not ['0' ..= '9'], where e.g. '7'\n// is the ASCII value 0x37.\n//\n// decimal_point is the index (within digits) of the decimal point. It may be\n// negative or be larger than num_digits, in which case the explicit digits are\n// padded with implicit zeroes.\n//\n// For example, if num_digits is 3 and digits is \"\\x07\\x08\\x09\":\n// - A decimal_point of -2 means \".00789\"\n// - A decimal_point of -1 means \".0789\"\n// - A decimal_point of +0 means \".789\"\n// - A decimal_point of +1 means \"7.89\"\n// - A decimal_point of +2 means \"78.9\"\n// - A decimal_point of +3 means \"789.\"\n// - A decimal_point of +4 means \"7890.\"\n// - A decimal_point of +5 means \"78900.\"\n//\n// As above, a" +
+ " decimal_point higher than +1023 means that the overall value is\n// infinity, lower than -1023 means zero.\n//\n// negative is a sign bit. An HPD can distinguish positive and negative zero.\n//\n// truncated is whether there are more than\n// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION digits, and at\n// least one of those extra digits are non-zero. The existence of long-tail\n// digits can affect rounding.\n//\n// The \"all fields are zero\" value is valid, and represents the number +0.\ntypedef struct {\n uint32_t num_digits;\n int32_t decimal_point;\n bool negative;\n bool truncated;\n uint8_t digits[WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION];\n} wuffs_base__private_implementation__high_prec_dec;\n\n// wuffs_base__private_implementation__high_prec_dec__trim trims trailing\n// zeroes from the h->digits[.. h->num_digits] slice. They have no benefit,\n// since we explicitly track h->decimal_point.\n//\n// Preconditions:\n// - h is non-NULL.\nstatic inline void //\nwuffs_base__private_implementation_" +
+ "_high_prec_dec__trim(\n wuffs_base__private_implementation__high_prec_dec* h) {\n while ((h->num_digits > 0) && (h->digits[h->num_digits - 1] == 0)) {\n h->num_digits--;\n }\n}\n\nstatic wuffs_base__status //\nwuffs_base__private_implementation__high_prec_dec__parse(\n wuffs_base__private_implementation__high_prec_dec* h,\n wuffs_base__slice_u8 s) {\n if (!h) {\n return wuffs_base__make_status(wuffs_base__error__bad_receiver);\n }\n h->num_digits = 0;\n h->decimal_point = 0;\n h->negative = false;\n h->truncated = false;\n\n uint8_t* p = s.ptr;\n uint8_t* q = s.ptr + s.len;\n\n for (; (p < q) && (*p == '_'); p++) {\n }\n if (p >= q) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n\n // Parse sign.\n do {\n if (*p == '+') {\n p++;\n } else if (*p == '-') {\n h->negative = true;\n p++;\n } else {\n break;\n }\n for (; (p < q) && (*p == '_'); p++) {\n }\n } while (0);\n\n // Parse digits.\n uint32_t nd = 0;\n int32_t dp = 0;\n bool saw_digits = false;\n " +
+ "bool saw_non_zero_digits = false;\n bool saw_dot = false;\n for (; p < q; p++) {\n if (*p == '_') {\n // No-op.\n\n } else if ((*p == '.') || (*p == ',')) {\n // As per https://en.wikipedia.org/wiki/Decimal_separator, both '.' or\n // ',' are commonly used. We just parse either, regardless of LOCALE.\n if (saw_dot) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n saw_dot = true;\n dp = (int32_t)nd;\n\n } else if ('0' == *p) {\n if (!saw_dot && !saw_non_zero_digits && saw_digits) {\n // We don't allow unnecessary leading zeroes: \"000123\" or \"0644\".\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n saw_digits = true;\n if (nd == 0) {\n // Track leading zeroes implicitly.\n dp--;\n } else if (nd <\n WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION) {\n h->digits[nd++] = 0;\n } else {\n // Long-tail zeroes are ignored.\n }\n\n } else if (('" +
+ "0' < *p) && (*p <= '9')) {\n if (!saw_dot && !saw_non_zero_digits && saw_digits) {\n // We don't allow unnecessary leading zeroes: \"000123\" or \"0644\".\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n saw_digits = true;\n saw_non_zero_digits = true;\n if (nd < WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION) {\n h->digits[nd++] = (uint8_t)(*p - '0');\n } else {\n // Long-tail non-zeroes set the truncated bit.\n h->truncated = true;\n }\n\n } else {\n break;\n }\n }\n\n if (!saw_digits) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n if (!saw_dot) {\n dp = (int32_t)nd;\n }\n\n // Parse exponent.\n if ((p < q) && ((*p == 'E') || (*p == 'e'))) {\n p++;\n for (; (p < q) && (*p == '_'); p++) {\n }\n if (p >= q) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n\n int32_t exp_sign = +1;\n if (*p == '+') {\n p++;\n } else if (*p == '-') {\n " +
+ "exp_sign = -1;\n p++;\n }\n\n int32_t exp = 0;\n const int32_t exp_large =\n WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE +\n WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION;\n bool saw_exp_digits = false;\n for (; p < q; p++) {\n if (*p == '_') {\n // No-op.\n } else if (('0' <= *p) && (*p <= '9')) {\n saw_exp_digits = true;\n if (exp < exp_large) {\n exp = (10 * exp) + ((int32_t)(*p - '0'));\n }\n } else {\n break;\n }\n }\n if (!saw_exp_digits) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n dp += exp_sign * exp;\n }\n\n // Finish.\n if (p != q) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n h->num_digits = nd;\n if (nd == 0) {\n h->decimal_point = 0;\n } else if (dp <\n -WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) {\n h->decimal_point =\n -WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__" +
+ "RANGE - 1;\n } else if (dp >\n +WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) {\n h->decimal_point =\n +WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE + 1;\n } else {\n h->decimal_point = dp;\n }\n wuffs_base__private_implementation__high_prec_dec__trim(h);\n return wuffs_base__make_status(NULL);\n}\n\n" +
"" +
"// --------\n\n// The etc__hpd_left_shift and etc__powers_of_5 tables were printed by\n// script/print-hpd-left-shift.go. That script has an optional -comments flag,\n// whose output is not copied here, which prints further detail.\n//\n// These tables are used in\n// wuffs_base__private_implementation__high_prec_dec__lshift_num_new_digits.\n\n// wuffs_base__private_implementation__hpd_left_shift[i] encodes the number of\n// new digits created after multiplying a positive integer by (1 << i): the\n// additional length in the decimal representation. For example, shifting \"234\"\n// by 3 (equivalent to multiplying by 8) will produce \"1872\". Going from a\n// 3-length string to a 4-length string means that 1 new digit was added (and\n// existing digits may have changed).\n//\n// Shifting by i can add either N or N-1 new digits, depending on whether the\n// original positive integer compares >= or < to the i'th power of 5 (as 10\n// equals 2 * 5). Comparison is lexicographic, not numerical.\n//\n// For example, shifting by 4 (i.e. mul" +
"tiplying by 16) can add 1 or 2 new\n// digits, depending on a lexicographic comparison to (5 ** 4), i.e. \"625\":\n// - (\"1\" << 4) is \"16\", which adds 1 new digit.\n// - (\"5678\" << 4) is \"90848\", which adds 1 new digit.\n// - (\"624\" << 4) is \"9984\", which adds 1 new digit.\n// - (\"62498\" << 4) is \"999968\", which adds 1 new digit.\n// - (\"625\" << 4) is \"10000\", which adds 2 new digits.\n// - (\"625001\" << 4) is \"10000016\", which adds 2 new digits.\n// - (\"7008\" << 4) is \"112128\", which adds 2 new digits.\n// - (\"99\" << 4) is \"1584\", which adds 2 new digits.\n//\n// Thus, when i is 4, N is 2 and (5 ** i) is \"625\". This etc__hpd_left_shift\n// array encodes this as:\n// - etc__hpd_left_shift[4] is 0x1006 = (2 << 11) | 0x0006.\n// - etc__hpd_left_shift[5] is 0x1009 = (? << 11) | 0x0009.\n// where the ? isn't relevant for i == 4.\n//\n// The high 5 bits of etc__hpd_left_shift[i] is N, the higher of the two\n// possible number of new digits. The low 11 bits are an offset into the\n//" +
@@ -105,14 +105,39 @@
" 0;\n\n // Pick up enough leading digits to cover the first shift.\n while ((n >> shift) == 0) {\n if (rx < h->num_digits) {\n // Read a digit.\n n = (10 * n) + h->digits[rx++];\n } else if (n == 0) {\n // h's number used to be zero and remains zero.\n return;\n } else {\n // Read sufficient implicit trailing zeroes.\n while ((n >> shift) == 0) {\n n = 10 * n;\n rx++;\n }\n break;\n }\n }\n h->decimal_point -= ((int32_t)(rx - 1));\n if (h->decimal_point <\n -WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) {\n // After the shift, h's number is effectively zero.\n h->num_digits = 0;\n h->decimal_point = 0;\n h->negative = false;\n h->truncated = false;\n return;\n }\n\n // Repeat: pick up a digit, put down a digit, left to right.\n uint64_t mask = (((uint64_t)(1)) << shift) - 1;\n while (rx < h->num_digits) {\n uint8_t new_digit = ((uint8_t)(n >> shift));\n n = (10 * (n & mask)) + h->digits[rx++];\n h->digits[wx++] = new_digi" +
"t;\n }\n\n // Put down trailing digits, left to right.\n while (n > 0) {\n uint8_t new_digit = ((uint8_t)(n >> shift));\n n = 10 * (n & mask);\n if (wx < WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION) {\n h->digits[wx++] = new_digit;\n } else if (new_digit > 0) {\n h->truncated = true;\n }\n }\n\n // Finish.\n h->num_digits = wx;\n wuffs_base__private_implementation__high_prec_dec__trim(h);\n}\n\n" +
"" +
+ "// --------\n\n// The wuffs_base__private_implementation__etc_powers_of_10 tables were printed\n// by script/print-mpb-powers-of-10.go. That script has an optional -comments\n// flag, whose output is not copied here, which prints further detail.\n//\n// These tables are used in\n// wuffs_base__private_implementation__medium_prec_bin__assign_from_hpd.\n\n// wuffs_base__private_implementation__big_powers_of_10 contains approximations\n// to the powers of 10, ranging from 1e-348 to 1e+340, with the exponent\n// stepping by 8: -348, -340, -332, ..., -12, -4, +4, +12, ..., +340. Each step\n// consists of three uint32_t elements. There are 87 triples, 87 * 3 = 261.\n//\n// For example, the third approximation, for 1e-332, consists of the uint32_t\n// triple (0x3055AC76, 0x8B16FB20, 0xFFFFFB72). The first two of that triple\n// are a little-endian uint64_t value: 0x8B16FB203055AC76. The last one is an\n// int32_t value: -1166. Together, they represent the approximation:\n// 1e-332 ≈ 0x8B16FB203055AC76 * (2 ** -1166)\n// Similarly," +
+ " the (0x00000000, 0x9C400000, 0xFFFFFFCE) uint32_t triple means:\n// 1e+4 ≈ 0x9C40000000000000 * (2 ** -50) // This approx'n is exact.\n// Similarly, the (0xD4C4FB27, 0xED63A231, 0x000000A2) uint32_t triple means:\n// 1e+68 ≈ 0xED63A231D4C4FB27 * (2 ** 162)\nstatic const uint32_t\n wuffs_base__private_implementation__big_powers_of_10[261] = {\n 0x081C0288, 0xFA8FD5A0, 0xFFFFFB3C, 0xA23EBF76, 0xBAAEE17F, 0xFFFFFB57,\n 0x3055AC76, 0x8B16FB20, 0xFFFFFB72, 0x5DCE35EA, 0xCF42894A, 0xFFFFFB8C,\n 0x55653B2D, 0x9A6BB0AA, 0xFFFFFBA7, 0x3D1A45DF, 0xE61ACF03, 0xFFFFFBC1,\n 0xC79AC6CA, 0xAB70FE17, 0xFFFFFBDC, 0xBEBCDC4F, 0xFF77B1FC, 0xFFFFFBF6,\n 0x416BD60C, 0xBE5691EF, 0xFFFFFC11, 0x907FFC3C, 0x8DD01FAD, 0xFFFFFC2C,\n 0x31559A83, 0xD3515C28, 0xFFFFFC46, 0xADA6C9B5, 0x9D71AC8F, 0xFFFFFC61,\n 0x23EE8BCB, 0xEA9C2277, 0xFFFFFC7B, 0x4078536D, 0xAECC4991, 0xFFFFFC96,\n 0x5DB6CE57, 0x823C1279, 0xFFFFFCB1, 0x4DFB5637, 0xC2109436, 0xFFFFFCCB,\n 0x3848984F, 0x909" +
+ "6EA6F, 0xFFFFFCE6, 0x25823AC7, 0xD77485CB, 0xFFFFFD00,\n 0x97BF97F4, 0xA086CFCD, 0xFFFFFD1B, 0x172AACE5, 0xEF340A98, 0xFFFFFD35,\n 0x2A35B28E, 0xB23867FB, 0xFFFFFD50, 0xD2C63F3B, 0x84C8D4DF, 0xFFFFFD6B,\n 0x1AD3CDBA, 0xC5DD4427, 0xFFFFFD85, 0xBB25C996, 0x936B9FCE, 0xFFFFFDA0,\n 0x7D62A584, 0xDBAC6C24, 0xFFFFFDBA, 0x0D5FDAF6, 0xA3AB6658, 0xFFFFFDD5,\n 0xDEC3F126, 0xF3E2F893, 0xFFFFFDEF, 0xAAFF80B8, 0xB5B5ADA8, 0xFFFFFE0A,\n 0x6C7C4A8B, 0x87625F05, 0xFFFFFE25, 0x34C13053, 0xC9BCFF60, 0xFFFFFE3F,\n 0x91BA2655, 0x964E858C, 0xFFFFFE5A, 0x70297EBD, 0xDFF97724, 0xFFFFFE74,\n 0xB8E5B88F, 0xA6DFBD9F, 0xFFFFFE8F, 0x88747D94, 0xF8A95FCF, 0xFFFFFEA9,\n 0x8FA89BCF, 0xB9447093, 0xFFFFFEC4, 0xBF0F156B, 0x8A08F0F8, 0xFFFFFEDF,\n 0x653131B6, 0xCDB02555, 0xFFFFFEF9, 0xD07B7FAC, 0x993FE2C6, 0xFFFFFF14,\n 0x2A2B3B06, 0xE45C10C4, 0xFFFFFF2E, 0x697392D3, 0xAA242499, 0xFFFFFF49,\n 0x8300CA0E, 0xFD87B5F2, 0xFFFFFF63, 0x92111AEB, 0xBCE50864, 0xFFFFFF7E,\n 0" +
+ "x6F5088CC, 0x8CBCCC09, 0xFFFFFF99, 0xE219652C, 0xD1B71758, 0xFFFFFFB3,\n 0x00000000, 0x9C400000, 0xFFFFFFCE, 0x00000000, 0xE8D4A510, 0xFFFFFFE8,\n 0xAC620000, 0xAD78EBC5, 0x00000003, 0xF8940984, 0x813F3978, 0x0000001E,\n 0xC90715B3, 0xC097CE7B, 0x00000038, 0x7BEA5C70, 0x8F7E32CE, 0x00000053,\n 0xABE98068, 0xD5D238A4, 0x0000006D, 0x179A2245, 0x9F4F2726, 0x00000088,\n 0xD4C4FB27, 0xED63A231, 0x000000A2, 0x8CC8ADA8, 0xB0DE6538, 0x000000BD,\n 0x1AAB65DB, 0x83C7088E, 0x000000D8, 0x42711D9A, 0xC45D1DF9, 0x000000F2,\n 0xA61BE758, 0x924D692C, 0x0000010D, 0x1A708DEA, 0xDA01EE64, 0x00000127,\n 0x9AEF774A, 0xA26DA399, 0x00000142, 0xB47D6B85, 0xF209787B, 0x0000015C,\n 0x79DD1877, 0xB454E4A1, 0x00000177, 0x5B9BC5C2, 0x865B8692, 0x00000192,\n 0xC8965D3D, 0xC83553C5, 0x000001AC, 0xFA97A0B3, 0x952AB45C, 0x000001C7,\n 0x99A05FE3, 0xDE469FBD, 0x000001E1, 0xDB398C25, 0xA59BC234, 0x000001FC,\n 0xA3989F5C, 0xF6C69A72, 0x00000216, 0x54E9BECE, 0xB7DCBF53, 0x000" +
+ "00231,\n 0xF22241E2, 0x88FCF317, 0x0000024C, 0xD35C78A5, 0xCC20CE9B, 0x00000266,\n 0x7B2153DF, 0x98165AF3, 0x00000281, 0x971F303A, 0xE2A0B5DC, 0x0000029B,\n 0x5CE3B396, 0xA8D9D153, 0x000002B6, 0xA4A7443C, 0xFB9B7CD9, 0x000002D0,\n 0xA7A44410, 0xBB764C4C, 0x000002EB, 0xB6409C1A, 0x8BAB8EEF, 0x00000306,\n 0xA657842C, 0xD01FEF10, 0x00000320, 0xE9913129, 0x9B10A4E5, 0x0000033B,\n 0xA19C0C9D, 0xE7109BFB, 0x00000355, 0x623BF429, 0xAC2820D9, 0x00000370,\n 0x7AA7CF85, 0x80444B5E, 0x0000038B, 0x03ACDD2D, 0xBF21E440, 0x000003A5,\n 0x5E44FF8F, 0x8E679C2F, 0x000003C0, 0x9C8CB841, 0xD433179D, 0x000003DA,\n 0xB4E31BA9, 0x9E19DB92, 0x000003F5, 0xBADF77D9, 0xEB96BF6E, 0x0000040F,\n 0x9BF0EE6B, 0xAF87023B, 0x0000042A,\n};\n\n// wuffs_base__private_implementation__small_powers_of_10 contains\n// approximations to the powers of 10, ranging from 1e+0 to 1e+7, with the\n// exponent stepping by 1. Each step consists of three uint32_t elements.\n//\n// For example, the third appr" +
+ "oximation, for 1e+2, consists of the uint32_t\n// triple (0x00000000, 0xC8000000, 0xFFFFFFC7). The first two of that triple\n// are a little-endian uint64_t value: 0xC800000000000000. The last one is an\n// int32_t value: -57. Together, they represent the approximation:\n// 1e+2 ≈ 0xC800000000000000 * (2 ** -57) // This approx'n is exact.\n// Similarly, the (0x00000000, 0x9C400000, 0xFFFFFFCE) uint32_t triple means:\n// 1e+4 ≈ 0x9C40000000000000 * (2 ** -50) // This approx'n is exact.\nstatic const uint32_t\n wuffs_base__private_implementation__small_powers_of_10[24] = {\n 0x00000000, 0x80000000, 0xFFFFFFC1, 0x00000000, 0xA0000000, 0xFFFFFFC4,\n 0x00000000, 0xC8000000, 0xFFFFFFC7, 0x00000000, 0xFA000000, 0xFFFFFFCA,\n 0x00000000, 0x9C400000, 0xFFFFFFCE, 0x00000000, 0xC3500000, 0xFFFFFFD1,\n 0x00000000, 0xF4240000, 0xFFFFFFD4, 0x00000000, 0x98968000, 0xFFFFFFD8,\n};\n\n// wuffs_base__private_implementation__f64_powers_of_10 holds powers of 10 that\n// can be exactly represented" +
+ " by a float64 (what C calls a double).\nstatic const double wuffs_base__private_implementation__f64_powers_of_10[23] = {\n 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11,\n 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22,\n};\n\n" +
+ "" +
+ "// --------\n\n// wuffs_base__private_implementation__medium_prec_bin (abbreviated as MPB) is\n// a fixed precision floating point binary number. Unlike IEEE 754 Floating\n// Point, it cannot represent infinity or NaN (Not a Number).\n//\n// \"Medium precision\" means that the mantissa holds 64 binary digits, a little\n// more than \"double precision\", and sizeof(MPB) > sizeof(double). 64 is\n// obviously the number of bits in a uint64_t.\n//\n// An MPB isn't for general purpose arithmetic, only for conversions to and\n// from IEEE 754 double-precision floating point.\n//\n// There is no implicit mantissa bit. The mantissa field is zero if and only if\n// the overall floating point value is ±0. An MPB is normalized if the mantissa\n// is zero or its high bit (the 1<<63 bit) is set.\n//\n// There is no negative bit. An MPB can only represent non-negative numbers.\n//\n// The \"all fields are zero\" value is valid, and represents the number +0.\n//\n// This is the \"Do It Yourself Floating Point\" data structure from Loitsch,\n// \"Printin" +
+ "g Floating-Point Numbers Quickly and Accurately with Integers\"\n// (https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf).\n//\n// Florian Loitsch is also the primary contributor to\n// https://github.com/google/double-conversion\ntypedef struct {\n uint64_t mantissa;\n int32_t exp2;\n} wuffs_base__private_implementation__medium_prec_bin;\n\nstatic uint32_t //\nwuffs_base__private_implementation__medium_prec_bin__normalize(\n wuffs_base__private_implementation__medium_prec_bin* m) {\n if (m->mantissa == 0) {\n return 0;\n }\n uint32_t shift = wuffs_base__count_leading_zeroes_u64(m->mantissa);\n m->mantissa <<= shift;\n m->exp2 -= (int32_t)shift;\n return shift;\n}\n\n// wuffs_base__private_implementation__medium_prec_bin__mul_pow_10 sets m to be\n// (m * pow), where pow comes from an etc_powers_of_10 triple starting at p.\n//\n// The result is rounded, but not necessarily normalized.\n//\n// Preconditions:\n// - m is non-NULL.\n// - m->mantissa is non-zero.\n// - m->mantissa's high bit is set (i.e. m is " +
+ "normalized).\n//\n// The etc_powers_of_10 triple is already normalized.\nstatic void //\nwuffs_base__private_implementation__medium_prec_bin__mul_pow_10(\n wuffs_base__private_implementation__medium_prec_bin* m,\n const uint32_t* p) {\n uint64_t p_mantissa = ((uint64_t)p[0]) | (((uint64_t)p[1]) << 32);\n int32_t p_exp2 = (int32_t)p[2];\n\n wuffs_base__multiply_u64__output o =\n wuffs_base__multiply_u64(m->mantissa, p_mantissa);\n // Round the mantissa up. It cannot overflow because the maximum possible\n // value of o.hi is 0xFFFFFFFFFFFFFFFE.\n m->mantissa = o.hi + (o.lo >> 63);\n m->exp2 = m->exp2 + p_exp2 + 64;\n}\n\n// wuffs_base__private_implementation__medium_prec_bin__as_f64 converts m to a\n// double (what C calls a double-precision float64).\n//\n// Preconditions:\n// - m is non-NULL.\n// - m->mantissa is non-zero.\n// - m->mantissa's high bit is set (i.e. m is normalized).\nstatic double //\nwuffs_base__private_implementation__medium_prec_bin__as_f64(\n const wuffs_base__private_implementation__mediu" +
+ "m_prec_bin* m,\n bool negative) {\n uint64_t mantissa64 = m->mantissa;\n // An mpb's mantissa has the implicit (binary) decimal point at the right\n // hand end of the mantissa's explicit digits. A double-precision's mantissa\n // has that decimal point near the left hand end. There's also an explicit\n // versus implicit leading 1 bit (binary digit). Together, the difference in\n // semantics corresponds to adding 63.\n int32_t exp2 = m->exp2 + 63;\n\n // Ensure that exp2 is at least -1022, the minimum double-precision exponent\n // for normal (as opposed to subnormal) numbers.\n if (-1022 > exp2) {\n uint32_t n = (uint32_t)(-1022 - exp2);\n mantissa64 >>= n;\n exp2 += (int32_t)n;\n }\n\n // Extract the (1 + 52) bits from the 64-bit mantissa64. 52 is the number of\n // explicit mantissa bits in a double-precision f64.\n //\n // Before, we have 64 bits and due to normalization, the high bit 'H' is 1.\n // 63 55 47 etc 15 7\n // H210_9876_5432_1098_7654_etc_etc_etc_5432_109" +
+ "8_7654_3210\n // ++++_++++_++++_++++_++++_etc_etc_etc_++++_+..._...._.... Kept bits.\n // ...._...._...H_2109_8765_etc_etc_etc_6543_2109_8765_4321 After shifting.\n // After, we have 53 bits (and bit #52 is this 'H' bit).\n uint64_t mantissa53 = mantissa64 >> 11;\n\n // Round up if the old bit #10 (the highest bit dropped by shifting) was set.\n // We also fix any overflow from rounding up.\n if (mantissa64 & 1024) {\n mantissa53++;\n if ((mantissa53 >> 53) != 0) {\n mantissa53 >>= 1;\n exp2++;\n }\n }\n\n // Handle double-precision infinity (a nominal exponent of 1024) and\n // subnormals (an exponent of -1023 and no implicit mantissa bit, bit #52).\n if (exp2 >= 1024) {\n mantissa53 = 0;\n exp2 = 1024;\n } else if ((mantissa53 >> 52) == 0) {\n exp2 = -1023;\n }\n\n // Pack the bits and return.\n const int32_t f64_bias = -1023;\n uint64_t exp2_bits =\n (uint64_t)((exp2 - f64_bias) & 0x07FF); // (1 << 11) - 1.\n uint64_t bits = (mantissa53 & 0x000FFFFFFFFFFFFF) | // (1 << 52" +
+ ") - 1.\n (exp2_bits << 52) | //\n (negative ? 0x8000000000000000 : 0); // (1 << 63).\n return wuffs_base__ieee_754_bit_representation__to_f64(bits);\n}\n\n// wuffs_base__private_implementation__medium_prec_bin__parse_number_f64\n// converts from an HPD to a double, using an MPB as scratch space. It returns\n// a NULL status.repr if there is no ambiguity in the truncation or rounding to\n// a float64 (an IEEE 754 double-precision floating point value).\n//\n// It may modify m even if it returns a non-NULL status.repr.\nstatic wuffs_base__result_f64 //\nwuffs_base__private_implementation__medium_prec_bin__parse_number_f64(\n wuffs_base__private_implementation__medium_prec_bin* m,\n const wuffs_base__private_implementation__high_prec_dec* h,\n bool skip_fast_path_for_tests) {\n do {\n // m->mantissa is a uint64_t, which is an integer approximation to a\n // rational value - h's underlying digits after m's normalization. This\n // error is an upper bound on th" +
+ "e difference between the approximate and\n // actual value.\n //\n // The DiyFpStrtod function in https://github.com/google/double-conversion\n // uses a finer grain (1/8th of the ULP, Unit in the Last Place) when\n // tracking error. This implementation is coarser (1 ULP) but simpler.\n //\n // It is an error in the \"numerical approximation\" sense, not in the\n // typical programming sense (as in \"bad input\" or \"a result type\").\n uint64_t error = 0;\n\n // Convert up to 19 decimal digits (in h->digits) to 64 binary digits (in\n // m->mantissa): (1e19 < (1<<64)) and ((1<<64) < 1e20). If we have more\n // than 19 digits, we're truncating (with error).\n uint32_t i;\n uint32_t i_end = h->num_digits;\n if (i_end > 19) {\n i_end = 19;\n error = 1;\n }\n uint64_t mantissa = 0;\n for (i = 0; i < i_end; i++) {\n mantissa = (10 * mantissa) + h->digits[i];\n }\n m->mantissa = mantissa;\n m->exp2 = 0;\n\n // Check that exp10 lies in the (big_powers_of_10 + small_po" +
+ "wers_of_10)\n // range, -348 ..= +347, stepping big_powers_of_10 by 8 (which is 87\n // triples) and small_powers_of_10 by 1 (which is 8 triples).\n int32_t exp10 = h->decimal_point - ((int32_t)(i_end));\n if (exp10 < -348) {\n goto fail;\n }\n uint32_t bpo10 = ((uint32_t)(exp10 + 348)) / 8;\n uint32_t spo10 = ((uint32_t)(exp10 + 348)) % 8;\n if (bpo10 >= 87) {\n goto fail;\n }\n\n // Try a fast path, if float64 math would be exact.\n //\n // 15 is such that 1e15 can be losslessly represented in a float64\n // mantissa: (1e15 < (1<<53)) and ((1<<53) < 1e16).\n //\n // 22 is the maximum valid index for the\n // wuffs_base__private_implementation__f64_powers_of_10 array.\n do {\n if (skip_fast_path_for_tests || ((mantissa >> 52) != 0)) {\n break;\n }\n double d = (double)mantissa;\n\n if (exp10 == 0) {\n wuffs_base__result_f64 ret;\n ret.status.repr = NULL;\n ret.value = h->negative ? -d : +d;\n return ret;\n\n } else if (e" +
+ "xp10 > 0) {\n if (exp10 > 22) {\n if (exp10 > (15 + 22)) {\n break;\n }\n // If exp10 is in the range 23 ..= 37, try moving a few of the zeroes\n // from the exponent to the mantissa. If we're still under 1e15, we\n // haven't truncated any mantissa bits.\n if (exp10 > 22) {\n d *= wuffs_base__private_implementation__f64_powers_of_10[exp10 -\n 22];\n exp10 = 22;\n if (d >= 1e15) {\n break;\n }\n }\n }\n d *= wuffs_base__private_implementation__f64_powers_of_10[exp10];\n wuffs_base__result_f64 ret;\n ret.status.repr = NULL;\n ret.value = h->negative ? -d : +d;\n return ret;\n\n } else { // \"if (exp10 < 0)\" is effectively \"if (true)\" here.\n if (exp10 < -22) {\n break;\n }\n d /= wuffs_base__private_implementation__f64_powers_of_10[-exp10];\n wuffs_bas" +
+ "e__result_f64 ret;\n ret.status.repr = NULL;\n ret.value = h->negative ? -d : +d;\n return ret;\n }\n } while (0);\n\n // Normalize (and scale the error).\n error <<= wuffs_base__private_implementation__medium_prec_bin__normalize(m);\n\n // Multiplying two MPB values nominally multiplies two mantissas, call them\n // A and B, which are integer approximations to the precise values (A+a)\n // and (B+b) for some error terms a and b.\n //\n // MPB multiplication calculates (((A+a) * (B+b)) >> 64) to be ((A*B) >>\n // 64). Shifting (truncating) and rounding introduces further error. The\n // difference between the calculated result:\n // ((A*B ) >> 64)\n // and the true result:\n // ((A*B + A*b + a*B + a*b) >> 64) + rounding_error\n // is:\n // (( A*b + a*B + a*b) >> 64) + rounding_error\n // which can be re-grouped as:\n // ((A*b) >> 64) + ((a*(B+b)) >> 64) + rounding_error\n //\n // Now, let A and a be \"m->mantissa\" and \"erro" +
+ "r\", and B and b be the\n // pre-calculated power of 10. A and B are both less than (1 << 64), a is\n // the \"error\" local variable and b is less than 1.\n //\n // An upper bound (in absolute value) on ((A*b) >> 64) is therefore 1.\n //\n // An upper bound on ((a*(B+b)) >> 64) is a, also known as error.\n //\n // Finally, the rounding_error is at most 1.\n //\n // In total, calling mpb__mul_pow_10 will raise the worst-case error by 2.\n // The subsequent re-normalization can multiply that by a further factor.\n\n // Multiply by small_powers_of_10[etc].\n wuffs_base__private_implementation__medium_prec_bin__mul_pow_10(\n m, &wuffs_base__private_implementation__small_powers_of_10[3 * spo10]);\n error += 2;\n error <<= wuffs_base__private_implementation__medium_prec_bin__normalize(m);\n\n // Multiply by big_powers_of_10[etc].\n wuffs_base__private_implementation__medium_prec_bin__mul_pow_10(\n m, &wuffs_base__private_implementation__big_powers_of_10[3 * bpo10]);\n err" +
+ "or += 2;\n error <<= wuffs_base__private_implementation__medium_prec_bin__normalize(m);\n\n // We have a good approximation of h, but we still have to check whether\n // the error is small enough. Equivalently, whether the number of surplus\n // mantissa bits (the bits dropped when going from m's 64 mantissa bits to\n // the smaller number of double-precision mantissa bits) would always round\n // up or down, even when perturbed by ±error. We start at 11 surplus bits\n // (m has 64, double-precision has 1+52), but it can be higher for\n // subnormals.\n //\n // In many cases, the error is small enough and we return true.\n const int32_t f64_bias = -1023;\n int32_t subnormal_exp2 = f64_bias - 63;\n uint32_t surplus_bits = 11;\n if (subnormal_exp2 >= m->exp2) {\n surplus_bits += 1 + ((uint32_t)(subnormal_exp2 - m->exp2));\n }\n\n uint64_t surplus_mask =\n (((uint64_t)1) << surplus_bits) - 1; // e.g. 0x07FF.\n uint64_t surplus = m->mantissa & surplus_mask;\n uint64_t" +
+ " halfway = ((uint64_t)1) << (surplus_bits - 1); // e.g. 0x0400.\n\n // Do the final calculation in *signed* arithmetic.\n int64_t i_surplus = (int64_t)surplus;\n int64_t i_halfway = (int64_t)halfway;\n int64_t i_error = (int64_t)error;\n\n if ((i_surplus > (i_halfway - i_error)) &&\n (i_surplus < (i_halfway + i_error))) {\n goto fail;\n }\n\n wuffs_base__result_f64 ret;\n ret.status.repr = NULL;\n ret.value = wuffs_base__private_implementation__medium_prec_bin__as_f64(\n m, h->negative);\n return ret;\n } while (0);\n\nfail:\n do {\n wuffs_base__result_f64 ret;\n ret.status.repr = \"#base: mpb__parse_number_f64 failed\";\n ret.value = 0;\n return ret;\n } while (0);\n}\n\n" +
+ "" +
"// --------\n\nwuffs_base__result_f64 //\nwuffs_base__parse_number_f64_special(wuffs_base__slice_u8 s,\n const char* fallback_status_repr) {\n do {\n uint8_t* p = s.ptr;\n uint8_t* q = s.ptr + s.len;\n\n for (; (p < q) && (*p == '_'); p++) {\n }\n if (p >= q) {\n goto fallback;\n }\n\n // Parse sign.\n bool negative = false;\n do {\n if (*p == '+') {\n p++;\n } else if (*p == '-') {\n negative = true;\n p++;\n } else {\n break;\n }\n for (; (p < q) && (*p == '_'); p++) {\n }\n } while (0);\n if (p >= q) {\n goto fallback;\n }\n\n bool nan = false;\n switch (p[0]) {\n case 'I':\n case 'i':\n if (((q - p) < 3) || //\n ((p[1] != 'N') && (p[1] != 'n')) || //\n ((p[2] != 'F') && (p[2] != 'f'))) {\n goto fallback;\n }\n p += 3;\n\n if ((p >= q) || (*p == '_')) {\n break;\n } else if (((q - p) < 5) || " +
" //\n ((p[0] != 'I') && (p[0] != 'i')) || //\n ((p[1] != 'N') && (p[1] != 'n')) || //\n ((p[2] != 'I') && (p[2] != 'i')) || //\n ((p[3] != 'T') && (p[3] != 't')) || //\n ((p[4] != 'Y') && (p[4] != 'y'))) {\n goto fallback;\n }\n p += 5;\n\n if ((p >= q) || (*p == '_')) {\n break;\n }\n goto fallback;\n\n case 'N':\n case 'n':\n if (((q - p) < 3) || //\n ((p[1] != 'A') && (p[1] != 'a')) || //\n ((p[2] != 'N') && (p[2] != 'n'))) {\n goto fallback;\n }\n p += 3;\n\n if ((p >= q) || (*p == '_')) {\n nan = true;\n break;\n }\n goto fallback;\n\n default:\n goto fallback;\n }\n\n // Finish.\n for (; (p < q) && (*p == '_'); p++) {\n }\n if (p != q) {\n goto fallback;\n }\n wuffs_base__result_f64 ret;\n ret.status.repr = NULL;\n ret.value = w" +
- "uffs_base__ieee_754_bit_representation__to_f64(\n (nan ? 0x7FFFFFFFFFFFFFFF : 0x7FF0000000000000) |\n (negative ? 0x8000000000000000 : 0));\n return ret;\n } while (0);\n\nfallback:\n do {\n wuffs_base__result_f64 ret;\n ret.status.repr = fallback_status_repr;\n ret.value = 0;\n return ret;\n } while (0);\n}\n\nwuffs_base__result_f64 //\nwuffs_base__parse_number_f64(wuffs_base__slice_u8 s) {\n wuffs_base__private_implementation__high_prec_dec h;\n\n do {\n // powers converts decimal powers of 10 to binary powers of 2. For example,\n // (10000 >> 13) is 1. It stops before the elements exceed 60, also known\n // as WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL.\n static const uint32_t num_powers = 19;\n static const uint8_t powers[19] = {\n 0, 3, 6, 9, 13, 16, 19, 23, 26, 29, //\n 33, 36, 39, 43, 46, 49, 53, 56, 59, //\n };\n\n wuffs_base__status status =\n wuffs_base__private_implementation__high_prec_dec__parse(&h, s);\n if (status.repr) {\n" +
- " return wuffs_base__parse_number_f64_special(s, status.repr);\n }\n\n // Handle zero and obvious extremes. The largest and smallest positive\n // finite f64 values are approximately 1.8e+308 and 4.9e-324.\n if ((h.num_digits == 0) || (h.decimal_point < -326)) {\n goto zero;\n } else if (h.decimal_point > 310) {\n goto infinity;\n }\n\n // Scale by powers of 2 until we're in the range [½ .. 1], which gives us\n // our exponent (in base-2). First we shift right, possibly a little too\n // far, ending with a value certainly below 1 and possibly below ½...\n const int32_t bias = -1023;\n int32_t exp2 = 0;\n while (h.decimal_point > 0) {\n uint32_t n = (uint32_t)(+h.decimal_point);\n uint32_t shift =\n (n < num_powers)\n ? powers[n]\n : WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL;\n\n wuffs_base__private_implementation__high_prec_dec__small_rshift(&h,\n sh" +
- "ift);\n if (h.decimal_point <\n -WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) {\n goto zero;\n }\n exp2 += (int32_t)shift;\n }\n // ...then we shift left, putting us in [½ .. 1].\n while (h.decimal_point <= 0) {\n uint32_t shift;\n if (h.decimal_point == 0) {\n if (h.digits[0] >= 5) {\n break;\n }\n shift = (h.digits[0] <= 2) ? 2 : 1;\n } else {\n uint32_t n = (uint32_t)(-h.decimal_point);\n shift = (n < num_powers)\n ? powers[n]\n : WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL;\n }\n\n wuffs_base__private_implementation__high_prec_dec__small_lshift(&h,\n shift);\n if (h.decimal_point >\n +WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) {\n goto infinity;\n }\n exp2 -= (int32_t)shift;\n }\n\n // We're in the range [½ .. 1] but f64 uses [1 .. 2]." +
- "\n exp2--;\n\n // The minimum normal exponent is (bias + 1).\n while ((bias + 1) > exp2) {\n uint32_t n = (uint32_t)((bias + 1) - exp2);\n if (n > WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL) {\n n = WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL;\n }\n wuffs_base__private_implementation__high_prec_dec__small_rshift(&h, n);\n exp2 += (int32_t)n;\n }\n\n // Check for overflow.\n if ((exp2 - bias) >= 0x07FF) { // (1 << 11) - 1.\n goto infinity;\n }\n\n // Extract 53 bits for the mantissa (in base-2).\n wuffs_base__private_implementation__high_prec_dec__small_lshift(&h, 53);\n uint64_t man2 =\n wuffs_base__private_implementation__high_prec_dec__rounded_integer(&h);\n\n // Rounding might have added one bit. If so, shift and re-check overflow.\n if ((man2 >> 53) != 0) {\n man2 >>= 1;\n exp2++;\n if ((exp2 - bias) >= 0x07FF) { // (1 << 11) - 1.\n goto infinity;\n }\n }\n\n // Handle subnormal numbers.\n if ((" +
- "man2 >> 52) == 0) {\n exp2 = bias;\n }\n\n // Pack the bits and return.\n uint64_t exp2_bits = (uint64_t)((exp2 - bias) & 0x07FF); // (1 << 11) - 1.\n uint64_t bits = (man2 & 0x000FFFFFFFFFFFFF) | // (1 << 52) - 1.\n (exp2_bits << 52) | //\n (h.negative ? 0x8000000000000000 : 0); // (1 << 63).\n\n wuffs_base__result_f64 ret;\n ret.status.repr = NULL;\n ret.value = wuffs_base__ieee_754_bit_representation__to_f64(bits);\n return ret;\n } while (0);\n\nzero:\n do {\n uint64_t bits = h.negative ? 0x8000000000000000 : 0;\n\n wuffs_base__result_f64 ret;\n ret.status.repr = NULL;\n ret.value = wuffs_base__ieee_754_bit_representation__to_f64(bits);\n return ret;\n } while (0);\n\ninfinity:\n do {\n uint64_t bits = h.negative ? 0xFFF0000000000000 : 0x7FF0000000000000;\n\n wuffs_base__result_f64 ret;\n ret.status.repr = NULL;\n ret.value = wuffs_base__ieee_754_bit_representation__to_f64(bits);\n return ret;\n } whi" +
- "le (0);\n}\n\n" +
+ "uffs_base__ieee_754_bit_representation__to_f64(\n (nan ? 0x7FFFFFFFFFFFFFFF : 0x7FF0000000000000) |\n (negative ? 0x8000000000000000 : 0));\n return ret;\n } while (0);\n\nfallback:\n do {\n wuffs_base__result_f64 ret;\n ret.status.repr = fallback_status_repr;\n ret.value = 0;\n return ret;\n } while (0);\n}\n\nwuffs_base__result_f64 //\nwuffs_base__parse_number_f64(wuffs_base__slice_u8 s) {\n wuffs_base__private_implementation__medium_prec_bin m;\n wuffs_base__private_implementation__high_prec_dec h;\n\n do {\n // powers converts decimal powers of 10 to binary powers of 2. For example,\n // (10000 >> 13) is 1. It stops before the elements exceed 60, also known\n // as WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL.\n static const uint32_t num_powers = 19;\n static const uint8_t powers[19] = {\n 0, 3, 6, 9, 13, 16, 19, 23, 26, 29, //\n 33, 36, 39, 43, 46, 49, 53, 56, 59, //\n };\n\n wuffs_base__status status =\n wuffs_base__private_implementat" +
+ "ion__high_prec_dec__parse(&h, s);\n if (status.repr) {\n return wuffs_base__parse_number_f64_special(s, status.repr);\n }\n\n // Handle zero and obvious extremes. The largest and smallest positive\n // finite f64 values are approximately 1.8e+308 and 4.9e-324.\n if ((h.num_digits == 0) || (h.decimal_point < -326)) {\n goto zero;\n } else if (h.decimal_point > 310) {\n goto infinity;\n }\n\n wuffs_base__result_f64 mpb_result =\n wuffs_base__private_implementation__medium_prec_bin__parse_number_f64(\n &m, &h, false);\n if (mpb_result.status.repr == NULL) {\n return mpb_result;\n }\n\n // Scale by powers of 2 until we're in the range [½ .. 1], which gives us\n // our exponent (in base-2). First we shift right, possibly a little too\n // far, ending with a value certainly below 1 and possibly below ½...\n const int32_t f64_bias = -1023;\n int32_t exp2 = 0;\n while (h.decimal_point > 0) {\n uint32_t n = (uint32_t)(+h.decimal_point);\n uint32_t " +
+ "shift =\n (n < num_powers)\n ? powers[n]\n : WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL;\n\n wuffs_base__private_implementation__high_prec_dec__small_rshift(&h,\n shift);\n if (h.decimal_point <\n -WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) {\n goto zero;\n }\n exp2 += (int32_t)shift;\n }\n // ...then we shift left, putting us in [½ .. 1].\n while (h.decimal_point <= 0) {\n uint32_t shift;\n if (h.decimal_point == 0) {\n if (h.digits[0] >= 5) {\n break;\n }\n shift = (h.digits[0] <= 2) ? 2 : 1;\n } else {\n uint32_t n = (uint32_t)(-h.decimal_point);\n shift = (n < num_powers)\n ? powers[n]\n : WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL;\n }\n\n wuffs_base__private_implementation__high_prec_dec__small_lshift(&h,\n " +
+ " shift);\n if (h.decimal_point >\n +WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) {\n goto infinity;\n }\n exp2 -= (int32_t)shift;\n }\n\n // We're in the range [½ .. 1] but f64 uses [1 .. 2].\n exp2--;\n\n // The minimum normal exponent is (f64_bias + 1).\n while ((f64_bias + 1) > exp2) {\n uint32_t n = (uint32_t)((f64_bias + 1) - exp2);\n if (n > WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL) {\n n = WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL;\n }\n wuffs_base__private_implementation__high_prec_dec__small_rshift(&h, n);\n exp2 += (int32_t)n;\n }\n\n // Check for overflow.\n if ((exp2 - f64_bias) >= 0x07FF) { // (1 << 11) - 1.\n goto infinity;\n }\n\n // Extract 53 bits for the mantissa (in base-2).\n wuffs_base__private_implementation__high_prec_dec__small_lshift(&h, 53);\n uint64_t man2 =\n wuffs_base__private_implementation__high_prec_dec_" +
+ "_rounded_integer(&h);\n\n // Rounding might have added one bit. If so, shift and re-check overflow.\n if ((man2 >> 53) != 0) {\n man2 >>= 1;\n exp2++;\n if ((exp2 - f64_bias) >= 0x07FF) { // (1 << 11) - 1.\n goto infinity;\n }\n }\n\n // Handle subnormal numbers.\n if ((man2 >> 52) == 0) {\n exp2 = f64_bias;\n }\n\n // Pack the bits and return.\n uint64_t exp2_bits =\n (uint64_t)((exp2 - f64_bias) & 0x07FF); // (1 << 11) - 1.\n uint64_t bits = (man2 & 0x000FFFFFFFFFFFFF) | // (1 << 52) - 1.\n (exp2_bits << 52) | //\n (h.negative ? 0x8000000000000000 : 0); // (1 << 63).\n\n wuffs_base__result_f64 ret;\n ret.status.repr = NULL;\n ret.value = wuffs_base__ieee_754_bit_representation__to_f64(bits);\n return ret;\n } while (0);\n\nzero:\n do {\n uint64_t bits = h.negative ? 0x8000000000000000 : 0;\n\n wuffs_base__result_f64 ret;\n ret.status.repr = NULL;\n ret.value = wuffs_base" +
+ "__ieee_754_bit_representation__to_f64(bits);\n return ret;\n } while (0);\n\ninfinity:\n do {\n uint64_t bits = h.negative ? 0xFFF0000000000000 : 0x7FF0000000000000;\n\n wuffs_base__result_f64 ret;\n ret.status.repr = NULL;\n ret.value = wuffs_base__ieee_754_bit_representation__to_f64(bits);\n return ret;\n } while (0);\n}\n\n" +
+ "" +
+ "// ---------------- Hexadecimal\n\nsize_t //\nwuffs_base__hexadecimal__decode2(wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 src) {\n size_t src_len2 = src.len / 2;\n size_t len = dst.len < src_len2 ? dst.len : src_len2;\n uint8_t* d = dst.ptr;\n uint8_t* s = src.ptr;\n size_t n = len;\n\n while (n--) {\n *d = (uint8_t)((wuffs_base__parse_number__hexadecimal_digits[s[0]] << 4) |\n (wuffs_base__parse_number__hexadecimal_digits[s[1]] & 0x0F));\n d += 1;\n s += 2;\n }\n\n return len;\n}\n\nsize_t //\nwuffs_base__hexadecimal__decode4(wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 src) {\n size_t src_len4 = src.len / 4;\n size_t len = dst.len < src_len4 ? dst.len : src_len4;\n uint8_t* d = dst.ptr;\n uint8_t* s = src.ptr;\n size_t n = len;\n\n while (n--) {\n *d = (uint8_t)((wuffs_base__parse_number__hexadecimal_digits[s[2]] << 4) |\n (wuffs_base__parse_number__hexadecimal_digits[s[3]] & 0x0F));\n d += 1;\n s +" +
+ "= 4;\n }\n\n return len;\n}\n\n" +
"" +
"// ---------------- Unicode and UTF-8\n\nsize_t //\nwuffs_base__utf_8__encode(wuffs_base__slice_u8 dst, uint32_t code_point) {\n if (code_point <= 0x7F) {\n if (dst.len >= 1) {\n dst.ptr[0] = (uint8_t)(code_point);\n return 1;\n }\n\n } else if (code_point <= 0x07FF) {\n if (dst.len >= 2) {\n dst.ptr[0] = (uint8_t)(0xC0 | ((code_point >> 6)));\n dst.ptr[1] = (uint8_t)(0x80 | ((code_point >> 0) & 0x3F));\n return 2;\n }\n\n } else if (code_point <= 0xFFFF) {\n if ((dst.len >= 3) && ((code_point < 0xD800) || (0xDFFF < code_point))) {\n dst.ptr[0] = (uint8_t)(0xE0 | ((code_point >> 12)));\n dst.ptr[1] = (uint8_t)(0x80 | ((code_point >> 6) & 0x3F));\n dst.ptr[2] = (uint8_t)(0x80 | ((code_point >> 0) & 0x3F));\n return 3;\n }\n\n } else if (code_point <= 0x10FFFF) {\n if (dst.len >= 4) {\n dst.ptr[0] = (uint8_t)(0xF0 | ((code_point >> 18)));\n dst.ptr[1] = (uint8_t)(0x80 | ((code_point >> 12) & 0x3F));\n dst.ptr[2] = (uint8_t)(0x80 | ((code_point >> 6) & 0x3" +
"F));\n dst.ptr[3] = (uint8_t)(0x80 | ((code_point >> 0) & 0x3F));\n return 4;\n }\n }\n\n return 0;\n}\n\n// wuffs_base__utf_8__byte_length_minus_1 is the byte length (minus 1) of a\n// UTF-8 encoded code point, based on the encoding's initial byte.\n// - 0x00 is 1-byte UTF-8 (ASCII).\n// - 0x01 is the start of 2-byte UTF-8.\n// - 0x02 is the start of 3-byte UTF-8.\n// - 0x03 is the start of 4-byte UTF-8.\n// - 0x40 is a UTF-8 tail byte.\n// - 0x80 is invalid UTF-8.\n//\n// RFC 3629 (UTF-8) gives this grammar for valid UTF-8:\n// UTF8-1 = %x00-7F\n// UTF8-2 = %xC2-DF UTF8-tail\n// UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) /\n// %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail )\n// UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) /\n// %xF4 %x80-8F 2( UTF8-tail )\n// UTF8-tail = %x80-BF\nstatic const uint8_t wuffs_base__utf_8__byte_length_minus_1[256] = {\n // 0 1 2 3 4 5 6 7\n // 8 9" +
@@ -164,7 +189,11 @@
"\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" +
"" +
"// --------\n\n// Saturating arithmetic (sat_add, sat_sub) branchless bit-twiddling algorithms\n// are per https://locklessinc.com/articles/sat_arithmetic/\n//\n// It is important that the underlying types are unsigned integers, as signed\n// integer arithmetic overflow is undefined behavior in C.\n\nstatic inline uint8_t //\nwuffs_base__u8__sat_add(uint8_t x, uint8_t y) {\n uint8_t res = (uint8_t)(x + y);\n res |= (uint8_t)(-(res < x));\n return res;\n}\n\nstatic inline uint8_t //\nwuffs_base__u8__sat_sub(uint8_t x, uint8_t y) {\n uint8_t res = (uint8_t)(x - y);\n res &= (uint8_t)(-(res <= x));\n return res;\n}\n\nstatic inline uint16_t //\nwuffs_base__u16__sat_add(uint16_t x, uint16_t y) {\n uint16_t res = (uint16_t)(x + y);\n res |= (uint16_t)(-(res < x));\n return res;\n}\n\nstatic inline uint16_t //\nwuffs_base__u16__sat_sub(uint16_t x, uint16_t y) {\n uint16_t res = (uint16_t)(x - y);\n res &= (uint16_t)(-(res <= x));\n return res;\n}\n\nstatic inline uint32_t //\nwuffs_base__u32__sat_add(uint32_t x, uint32_t y) {\n uint32" +
- "_t res = (uint32_t)(x + y);\n res |= (uint32_t)(-(res < x));\n return res;\n}\n\nstatic inline uint32_t //\nwuffs_base__u32__sat_sub(uint32_t x, uint32_t y) {\n uint32_t res = (uint32_t)(x - y);\n res &= (uint32_t)(-(res <= x));\n return res;\n}\n\nstatic inline uint64_t //\nwuffs_base__u64__sat_add(uint64_t x, uint64_t y) {\n uint64_t res = (uint64_t)(x + y);\n res |= (uint64_t)(-(res < x));\n return res;\n}\n\nstatic inline uint64_t //\nwuffs_base__u64__sat_sub(uint64_t x, uint64_t y) {\n uint64_t res = (uint64_t)(x - y);\n res &= (uint64_t)(-(res <= x));\n return res;\n}\n\n " +
+ "_t res = (uint32_t)(x + y);\n res |= (uint32_t)(-(res < x));\n return res;\n}\n\nstatic inline uint32_t //\nwuffs_base__u32__sat_sub(uint32_t x, uint32_t y) {\n uint32_t res = (uint32_t)(x - y);\n res &= (uint32_t)(-(res <= x));\n return res;\n}\n\nstatic inline uint64_t //\nwuffs_base__u64__sat_add(uint64_t x, uint64_t y) {\n uint64_t res = (uint64_t)(x + y);\n res |= (uint64_t)(-(res < x));\n return res;\n}\n\nstatic inline uint64_t //\nwuffs_base__u64__sat_sub(uint64_t x, uint64_t y) {\n uint64_t res = (uint64_t)(x - y);\n res &= (uint64_t)(-(res <= x));\n return res;\n}\n\n" +
+ "" +
+ "// --------\n\ntypedef struct {\n uint64_t hi;\n uint64_t lo;\n} wuffs_base__multiply_u64__output;\n\n// wuffs_base__multiply_u64 returns x*y as a 128-bit value.\n//\n// The maximum inclusive output hi_lo is 0xFFFFFFFFFFFFFFFE_0000000000000001.\nstatic inline wuffs_base__multiply_u64__output //\nwuffs_base__multiply_u64(uint64_t x, uint64_t y) {\n uint64_t x0 = x & 0xFFFFFFFF;\n uint64_t x1 = x >> 32;\n uint64_t y0 = y & 0xFFFFFFFF;\n uint64_t y1 = y >> 32;\n uint64_t w0 = x0 * y0;\n uint64_t t = (x1 * y0) + (w0 >> 32);\n uint64_t w1 = t & 0xFFFFFFFF;\n uint64_t w2 = t >> 32;\n w1 += x0 * y1;\n wuffs_base__multiply_u64__output o;\n o.hi = (x1 * y1) + w2 + (w1 >> 32);\n o.lo = x * y;\n return o;\n}\n\n " +
+ "" +
+ "// --------\n\n#if defined(__GNUC__) && (__SIZEOF_LONG__ == 8)\n\nstatic inline uint32_t //\nwuffs_base__count_leading_zeroes_u64(uint64_t u) {\n return u ? ((uint32_t)(__builtin_clzl(u))) : 64u;\n}\n\n#else\n\nstatic inline uint32_t //\nwuffs_base__count_leading_zeroes_u64(uint64_t u) {\n if (u == 0) {\n return 64;\n }\n\n uint32_t n = 0;\n if ((u >> 32) == 0) {\n n |= 32;\n u <<= 32;\n }\n if ((u >> 48) == 0) {\n n |= 16;\n u <<= 16;\n }\n if ((u >> 56) == 0) {\n n |= 8;\n u <<= 8;\n }\n if ((u >> 60) == 0) {\n n |= 4;\n u <<= 4;\n }\n if ((u >> 62) == 0) {\n n |= 2;\n u <<= 2;\n }\n if ((u >> 63) == 0) {\n n |= 1;\n u <<= 1;\n }\n return n;\n}\n\n#endif // defined(__GNUC__) && (__SIZEOF_LONG__ == 8)\n\n " +
"" +
"// --------\n\n#define wuffs_base__load_u8be__no_bounds_check \\\n wuffs_base__load_u8__no_bounds_check\n#define wuffs_base__load_u8le__no_bounds_check \\\n wuffs_base__load_u8__no_bounds_check\n\nstatic inline uint8_t //\nwuffs_base__load_u8__no_bounds_check(uint8_t* p) {\n return p[0];\n}\n\nstatic inline uint16_t //\nwuffs_base__load_u16be__no_bounds_check(uint8_t* p) {\n return (uint16_t)(((uint16_t)(p[0]) << 8) | ((uint16_t)(p[1]) << 0));\n}\n\nstatic inline uint16_t //\nwuffs_base__load_u16le__no_bounds_check(uint8_t* p) {\n return (uint16_t)(((uint16_t)(p[0]) << 0) | ((uint16_t)(p[1]) << 8));\n}\n\nstatic inline uint32_t //\nwuffs_base__load_u24be__no_bounds_check(uint8_t* p) {\n return ((uint32_t)(p[0]) << 16) | ((uint32_t)(p[1]) << 8) |\n ((uint32_t)(p[2]) << 0);\n}\n\nstatic inline uint32_t //\nwuffs_base__load_u24le__no_bounds_check(uint8_t* p) {\n return ((uint32_t)(p[0]) << 0) | ((uint32_t)(p[1]) << 8) |\n ((uint32_t)(p[2]) << 16);\n}\n\nstatic inline uint32_t //\nwuffs_base__load_u32be__no_bounds_check(" +
"uint8_t* p) {\n return ((uint32_t)(p[0]) << 24) | ((uint32_t)(p[1]) << 16) |\n ((uint32_t)(p[2]) << 8) | ((uint32_t)(p[3]) << 0);\n}\n\nstatic inline uint32_t //\nwuffs_base__load_u32le__no_bounds_check(uint8_t* p) {\n return ((uint32_t)(p[0]) << 0) | ((uint32_t)(p[1]) << 8) |\n ((uint32_t)(p[2]) << 16) | ((uint32_t)(p[3]) << 24);\n}\n\nstatic inline uint64_t //\nwuffs_base__load_u40be__no_bounds_check(uint8_t* p) {\n return ((uint64_t)(p[0]) << 32) | ((uint64_t)(p[1]) << 24) |\n ((uint64_t)(p[2]) << 16) | ((uint64_t)(p[3]) << 8) |\n ((uint64_t)(p[4]) << 0);\n}\n\nstatic inline uint64_t //\nwuffs_base__load_u40le__no_bounds_check(uint8_t* p) {\n return ((uint64_t)(p[0]) << 0) | ((uint64_t)(p[1]) << 8) |\n ((uint64_t)(p[2]) << 16) | ((uint64_t)(p[3]) << 24) |\n ((uint64_t)(p[4]) << 32);\n}\n\nstatic inline uint64_t //\nwuffs_base__load_u48be__no_bounds_check(uint8_t* p) {\n return ((uint64_t)(p[0]) << 40) | ((uint64_t)(p[1]) << 32) |\n ((uint64_t)(p[2]) << 24) | ((uint64_t)" +
@@ -268,10 +297,11 @@
""
const baseIOPublicH = "" +
- "// ---------------- 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 {\n wuffs_base__slice_u8 data;\n wuffs_base__io_buffer_meta meta;\n\n#ifdef __cplusplus\n inline void compact();\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_buff" +
- "er(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__empty_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__empty_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\n// wuffs_base__io_buffer__compact moves any written but unr" +
- "ead 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 bu" +
- "f ? wuffs_base__u64__sat_add(buf->meta.pos, buf->meta.wi) : 0;\n}\n\n#ifdef __cplusplus\n\ninline void //\nwuffs_base__io_buffer::compact() {\n wuffs_base__io_buffer__compact(this);\n}\n\ninline uint64_t //\nwuffs_base__io_buffer::reader_available() const {\n return wuffs_base__io_buffer__reader_available(this);\n}\n\ninline uint64_t //\nwuffs_base__io_buffer::reader_io_position() const {\n return wuffs_base__io_buffer__reader_io_position(this);\n}\n\ninline uint64_t //\nwuffs_base__io_buffer::writer_available() const {\n return wuffs_base__io_buffer__writer_available(this);\n}\n\ninline uint64_t //\nwuffs_base__io_buffer::writer_io_position() const {\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 {\n wuffs_base__slice_u8 data;\n wuffs_base__io_buffer_meta meta;\n\n#ifdef __cplusplus\n inline bool is_valid() const;\n inline void compact();\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_buf" +
+ "fer //\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__make_io_buffer_reader(wuffs_base__slice_u8 s, bool closed) {\n wuffs_base__io_buffer ret;\n ret.data.ptr = s.ptr;\n ret.data.len = s.len;\n ret.meta.wi = s.len;\n ret.meta.ri = 0;\n ret.meta.pos = 0;\n ret.meta.closed = closed;\n return ret;\n}\n\nstatic inline wuffs_base__io_buffer //\nwuffs_base__make_io_buffer_writer(wuffs_base__slice_u8 s) {\n wuffs_base__io_buffer ret;\n ret.data.ptr = s.ptr;\n ret.data.len = s.le" +
+ "n;\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 //\nwuffs_base__empty_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__empty_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 bool //\nwuffs_base__io_buffer__is_valid(const wuffs_base__io_buffer* buf) {\n if (buf) {\n if (buf->data.ptr) {\n return (buf->meta.ri <= buf->meta.wi) && (buf->meta.wi <= buf->data.len);\n } else {\n return (buf->meta.ri == 0) && (buf->meta.wi == 0) && (buf->data.len == 0);\n }\n }\n return false;\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_buffe" +
+ "r__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 bool //\nwuffs_base__io_buffer::is_valid() const {\n return wuffs_base__io_buffer__is_valid(this);\n}\n\ninline void //\nwuffs_base__io_buffer::compact() {\n wuffs_base__io_buffer__compact(this);\n}\n\ninline uint64_t //\nwuffs_base__io_buffer::reader_available() const {\n return wuffs_base__io_buffer__reader_available(this);\n}\n\ninline uint64_t //\nwuffs_base__io_buffer::reader_io_position() const {\n return wuffs_base__io_buffer__reader_io_position(this);\n}\n\ninline uint64_t //\nwuffs_base__io_buffer::writer_available() const {\n return wuffs_base__io_buffer__writer_available(this);\n}\n\ninline uint64_t //\nwuffs_base__io_buffer::writer_io_position() const {\n return wuffs_base__io_buffer__writer_io_position(this);\n}\n\n#endif // __cplusplus\n" +
""
const baseRangePrivateH = "" +
@@ -328,7 +358,10 @@
"" +
"// ---------------- IEEE 754 Floating Point\n\n// wuffs_base__parse_number_f64 parses the floating point number in s. For\n// example, if s contains the bytes \"1.5\" then it will return the double 1.5.\n//\n// It returns an error if s does not contain a floating point number.\n//\n// It does not necessarily return an error if the conversion is lossy, e.g. if\n// s is \"0.3\", which double-precision floating point cannot represent exactly.\n//\n// Similarly, the returned value may be infinite (and no error returned) even\n// if s was not \"inf\", when the input is nominally finite but sufficiently\n// larger than DBL_MAX, about 1.8e+308.\n//\n// It is similar to the C standard library's strtod function, but:\n// - Errors are returned in-band (in a result type), not out-of-band (errno).\n// - It takes a slice (a pointer and length), not a NUL-terminated C string.\n// - It does not take an optional endptr argument. It does not allow a partial\n// parse: it returns an error unless all of s is consumed.\n// - It does not allow whi" +
"tespace, leading or otherwise.\n// - It does not allow unnecessary leading zeroes (\"0\" is valid and its sole\n// zero is necessary). All of \"00\", \"0644\" and \"00.7\" are invalid.\n// - It is not affected by i18n / l10n settings such as environment variables.\n// - Conversely, it always accepts either ',' or '.' as a decimal separator.\n// In particular, \"3,141,592\" is always invalid but \"3,141\" is always valid\n// (and approximately π). The caller is responsible for e.g. previously\n// rejecting or filtering s if it contains a comma, if that is unacceptable\n// to the caller. For example, JSON numbers always use a dot '.' and never a\n// comma ',', regardless of the LOCALE environment variable.\n// - It does allow arbitrary underscores. For example, \"_3.141_592\" would\n// successfully parse, again approximately π.\n// - It does allow \"inf\", \"+Infinity\" and \"-NAN\", case insensitive, but it\n// does not permit \"nan\" to be followed by an integer mantissa.\n// - It does not allow hexadecimal float" +
- "ing point numbers.\nwuffs_base__result_f64 //\nwuffs_base__parse_number_f64(wuffs_base__slice_u8 s);\n\n// wuffs_base__ieee_754_bit_representation__etc converts between a double\n// precision numerical value and its IEEE 754 64-bit representation (1 sign\n// bit, 11 exponent bits, 52 explicit significand bits).\n//\n// For example, it converts between:\n// - +1.0 and 0x3FF0_0000_0000_0000.\n// - +5.5 and 0x4016_0000_0000_0000.\n// - -inf and 0xFFF0_0000_0000_0000.\n//\n// See https://en.wikipedia.org/wiki/Double-precision_floating-point_format\n\nstatic inline uint64_t //\nwuffs_base__ieee_754_bit_representation__from_f64(double f) {\n uint64_t u = 0;\n if (sizeof(uint64_t) == sizeof(double)) {\n memcpy(&u, &f, sizeof(uint64_t));\n }\n return u;\n}\n\nstatic inline double //\nwuffs_base__ieee_754_bit_representation__to_f64(uint64_t u) {\n double f = 0;\n if (sizeof(uint64_t) == sizeof(double)) {\n memcpy(&f, &u, sizeof(uint64_t));\n }\n return f;\n}\n\n " +
+ "ing point numbers.\nwuffs_base__result_f64 //\nwuffs_base__parse_number_f64(wuffs_base__slice_u8 s);\n\n// wuffs_base__ieee_754_bit_representation__etc converts between a double\n// precision numerical value and its IEEE 754 64-bit representation (1 sign\n// bit, 11 exponent bits, 52 explicit significand bits).\n//\n// For example, it converts between:\n// - +1.0 and 0x3FF0_0000_0000_0000.\n// - +5.5 and 0x4016_0000_0000_0000.\n// - -inf and 0xFFF0_0000_0000_0000.\n//\n// See https://en.wikipedia.org/wiki/Double-precision_floating-point_format\n\nstatic inline uint64_t //\nwuffs_base__ieee_754_bit_representation__from_f64(double f) {\n uint64_t u = 0;\n if (sizeof(uint64_t) == sizeof(double)) {\n memcpy(&u, &f, sizeof(uint64_t));\n }\n return u;\n}\n\nstatic inline double //\nwuffs_base__ieee_754_bit_representation__to_f64(uint64_t u) {\n double f = 0;\n if (sizeof(uint64_t) == sizeof(double)) {\n memcpy(&f, &u, sizeof(uint64_t));\n }\n return f;\n}\n\n" +
+ "" +
+ "// ---------------- Hexadecimal\n\n// wuffs_base__hexadecimal__decode2 converts \"6A6b\" to \"jk\", where e.g. 'j' is\n// U+006A. There are 2 source bytes for every destination byte.\n//\n// It returns the number of dst bytes written: the minimum of dst.len and\n// (src.len / 2). Excess source bytes are ignored.\n//\n// It assumes that the src bytes are two hexadecimal digits (0-9, A-F, a-f),\n// repeated. It may write nonsense bytes if not, although it will not read or\n// write out of bounds.\nsize_t //\nwuffs_base__hexadecimal__decode2(wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 src);\n\n// wuffs_base__hexadecimal__decode4 converts \"\\\\x6A\\\\x6b\" to \"jk\", where e.g.\n// 'j' is U+006A. There are 4 source bytes for every destination byte.\n//\n// It returns the number of dst bytes written: the minimum of dst.len and\n// (src.len / 4). Excess source bytes are ignored.\n//\n// It assumes that the src bytes are two ignored bytes and then two hexadecimal\n// digits (0-9, A-F, a-f), repeated. It may wri" +
+ "te nonsense bytes if not,\n// although it will not read or write out of bounds.\nsize_t //\nwuffs_base__hexadecimal__decode4(wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 src);\n\n" +
"" +
"// ---------------- Unicode and UTF-8\n\n#define WUFFS_BASE__UNICODE_CODE_POINT__MIN_INCL 0x00000000\n#define WUFFS_BASE__UNICODE_CODE_POINT__MAX_INCL 0x0010FFFF\n\n#define WUFFS_BASE__UNICODE_REPLACEMENT_CHARACTER 0x0000FFFD\n\n#define WUFFS_BASE__UNICODE_SURROGATE__MIN_INCL 0x0000D800\n#define WUFFS_BASE__UNICODE_SURROGATE__MAX_INCL 0x0000DFFF\n\n#define WUFFS_BASE__ASCII__MIN_INCL 0x00\n#define WUFFS_BASE__ASCII__MAX_INCL 0x7F\n\n#define WUFFS_BASE__UTF_8__BYTE_LENGTH__MIN_INCL 1\n#define WUFFS_BASE__UTF_8__BYTE_LENGTH__MAX_INCL 4\n\n#define WUFFS_BASE__UTF_8__BYTE_LENGTH_1__CODE_POINT__MIN_INCL 0x00000000\n#define WUFFS_BASE__UTF_8__BYTE_LENGTH_1__CODE_POINT__MAX_INCL 0x0000007F\n#define WUFFS_BASE__UTF_8__BYTE_LENGTH_2__CODE_POINT__MIN_INCL 0x00000080\n#define WUFFS_BASE__UTF_8__BYTE_LENGTH_2__CODE_POINT__MAX_INCL 0x000007FF\n#define WUFFS_BASE__UTF_8__BYTE_LENGTH_3__CODE_POINT__MIN_INCL 0x00000800\n#define WUFFS_BASE__UTF_8__BYTE_LENGTH_3__CODE_POINT__MAX_INCL 0x0000FFFF\n#define WUFFS_BASE__UTF_8__BYTE_LENGTH_4__CODE_POINT_" +
"_MIN_INCL 0x00010000\n#define WUFFS_BASE__UTF_8__BYTE_LENGTH_4__CODE_POINT__MAX_INCL 0x0010FFFF\n\n" +
@@ -365,8 +398,8 @@
"" +
"// --------\n\n#define WUFFS_BASE__TOKEN__VBD__LITERAL__UNDEFINED 0x00001\n#define WUFFS_BASE__TOKEN__VBD__LITERAL__NULL 0x00002\n#define WUFFS_BASE__TOKEN__VBD__LITERAL__FALSE 0x00004\n#define WUFFS_BASE__TOKEN__VBD__LITERAL__TRUE 0x00008\n\n " +
"" +
- "// --------\n\n// For a source string of \"123\" or \"0x9A\", it is valid for a tokenizer to\n// return any one of:\n// - WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_FLOATING_POINT.\n// - WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_SIGNED.\n// - WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_UNSIGNED.\n//\n// For a source string of \"+123\" or \"-0x9A\", only the first two are valid.\n//\n// For a source string of \"123.\", only the first one is valid.\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_FLOATING_POINT 0x00001\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_SIGNED 0x00002\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_UNSIGNED 0x00004\n\n// The number 300 might be represented as \"\\x01\\x2C\", \"\\x2C\\x01\\x00\\x00\" or\n// \"300\", which are big-endian, little-endian or text. For binary formats, the\n// token length discriminates e.g. u16 little-endian vs u32 little-endian.\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_BINARY_BIG_ENDIAN 0x00100\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_BINARY_LITTLE_END" +
- "IAN 0x00200\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_TEXT 0x00400\n\n" +
+ "// --------\n\n// For a source string of \"123\" or \"0x9A\", it is valid for a tokenizer to\n// return any one of:\n// - WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_FLOATING_POINT.\n// - WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_SIGNED.\n// - WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_UNSIGNED.\n//\n// For a source string of \"+123\" or \"-0x9A\", only the first two are valid.\n//\n// For a source string of \"123.\", only the first one is valid.\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_FLOATING_POINT 0x00001\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_SIGNED 0x00002\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_UNSIGNED 0x00004\n\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_NEG_INF 0x00010\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_POS_INF 0x00020\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_NEG_NAN 0x00040\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_POS_NAN 0x00080\n\n// The number 300 might be represented as \"\\x01\\x2C\", \"\\x2C\\x01\\x00\\x00\" or\n// \"300\", which are big-endian, li" +
+ "ttle-endian or text. For binary formats, the\n// token length discriminates e.g. u16 little-endian vs u32 little-endian.\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_BINARY_BIG_ENDIAN 0x00100\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_BINARY_LITTLE_ENDIAN 0x00200\n#define WUFFS_BASE__TOKEN__VBD__NUMBER__FORMAT_TEXT 0x00400\n\n" +
"" +
"// --------\n\nstatic inline uint64_t //\nwuffs_base__token__value(const wuffs_base__token* t) {\n return (t->repr >> WUFFS_BASE__TOKEN__VALUE__SHIFT) &\n WUFFS_BASE__TOKEN__VALUE__MASK;\n}\n\nstatic inline uint64_t //\nwuffs_base__token__value_major(const wuffs_base__token* t) {\n return (t->repr >> WUFFS_BASE__TOKEN__VALUE_MAJOR__SHIFT) &\n WUFFS_BASE__TOKEN__VALUE_MAJOR__MASK;\n}\n\nstatic inline uint64_t //\nwuffs_base__token__value_minor(const wuffs_base__token* t) {\n return (t->repr >> WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) &\n WUFFS_BASE__TOKEN__VALUE_MINOR__MASK;\n}\n\nstatic inline uint64_t //\nwuffs_base__token__value_base_category(const wuffs_base__token* t) {\n return (t->repr >> WUFFS_BASE__TOKEN__VALUE_BASE_CATEGORY__SHIFT) &\n WUFFS_BASE__TOKEN__VALUE_BASE_CATEGORY__MASK;\n}\n\nstatic inline uint64_t //\nwuffs_base__token__value_base_detail(const wuffs_base__token* t) {\n return (t->repr >> WUFFS_BASE__TOKEN__VALUE_BASE_DETAIL__SHIFT) &\n WUFFS_BASE__TOKEN__VALUE_BASE_DETA" +
"IL__MASK;\n}\n\nstatic inline bool //\nwuffs_base__token__link_prev(const wuffs_base__token* t) {\n return t->repr & WUFFS_BASE__TOKEN__LINK_PREV;\n}\n\nstatic inline bool //\nwuffs_base__token__link_next(const wuffs_base__token* t) {\n return t->repr & WUFFS_BASE__TOKEN__LINK_NEXT;\n}\n\nstatic inline uint64_t //\nwuffs_base__token__length(const wuffs_base__token* t) {\n return (t->repr >> WUFFS_BASE__TOKEN__LENGTH__SHIFT) &\n WUFFS_BASE__TOKEN__LENGTH__MASK;\n}\n\n#ifdef __cplusplus\n\ninline uint64_t //\nwuffs_base__token::value() const {\n return wuffs_base__token__value(this);\n}\n\ninline uint64_t //\nwuffs_base__token::value_major() const {\n return wuffs_base__token__value_major(this);\n}\n\ninline uint64_t //\nwuffs_base__token::value_minor() const {\n return wuffs_base__token__value_minor(this);\n}\n\ninline uint64_t //\nwuffs_base__token::value_base_category() const {\n return wuffs_base__token__value_base_category(this);\n}\n\ninline uint64_t //\nwuffs_base__token::value_base_detail() const {\n return wuffs_base__to" +
@@ -374,10 +407,11 @@
"" +
"// --------\n\ntypedef WUFFS_BASE__SLICE(wuffs_base__token) wuffs_base__slice_token;\n\nstatic inline wuffs_base__slice_token //\nwuffs_base__make_slice_token(wuffs_base__token* ptr, size_t len) {\n wuffs_base__slice_token ret;\n ret.ptr = ptr;\n ret.len = len;\n return ret;\n}\n\n" +
"" +
- "// --------\n\n// wuffs_base__token_buffer_meta is the metadata for a\n// wuffs_base__token_buffer's 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__token_buffer_meta;\n\n// wuffs_base__token_buffer is a 1-dimensional buffer (a pointer and length)\n// plus additional metadata.\n//\n// A value with all fields zero is a valid, empty buffer.\ntypedef struct {\n wuffs_base__slice_token data;\n wuffs_base__token_buffer_meta meta;\n\n#ifdef __cplusplus\n inline void compact();\n inline uint64_t reader_available() const;\n inline uint64_t reader_token_position() const;\n inline uint64_t writer_available() const;\n inline uint64_t writer_token_position() const;\n#endif // __cplusplus\n\n} wuffs_base__token_buffer;\n\nstatic inline wuffs_base__token_buffer //\nwuffs_base__make_token_buffer(wuffs_base__slice_" +
- "token data,\n wuffs_base__token_buffer_meta meta) {\n wuffs_base__token_buffer ret;\n ret.data = data;\n ret.meta = meta;\n return ret;\n}\n\nstatic inline wuffs_base__token_buffer_meta //\nwuffs_base__make_token_buffer_meta(size_t wi,\n size_t ri,\n uint64_t pos,\n bool closed) {\n wuffs_base__token_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__token_buffer //\nwuffs_base__empty_token_buffer() {\n wuffs_base__token_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__token_buffer_meta //\nwuffs_base__empty_token_buffer_meta() {\n wuffs_base__token_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__token_buffer__com" +
- "pact moves any written but unread tokens to the\n// start of the buffer.\nstatic inline void //\nwuffs_base__token_buffer__compact(wuffs_base__token_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 * sizeof(wuffs_base__token));\n }\n buf->meta.wi = n;\n buf->meta.ri = 0;\n}\n\nstatic inline uint64_t //\nwuffs_base__token_buffer__reader_available(\n const wuffs_base__token_buffer* buf) {\n return buf ? buf->meta.wi - buf->meta.ri : 0;\n}\n\nstatic inline uint64_t //\nwuffs_base__token_buffer__reader_token_position(\n const wuffs_base__token_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__token_buffer__writer_available(\n const wuffs_base__token_buffer* buf) {\n return buf ? buf->data.len - buf->meta.wi : 0;\n}\n\nsta" +
- "tic inline uint64_t //\nwuffs_base__token_buffer__writer_token_position(\n const wuffs_base__token_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__token_buffer::compact() {\n wuffs_base__token_buffer__compact(this);\n}\n\ninline uint64_t //\nwuffs_base__token_buffer::reader_available() const {\n return wuffs_base__token_buffer__reader_available(this);\n}\n\ninline uint64_t //\nwuffs_base__token_buffer::reader_token_position() const {\n return wuffs_base__token_buffer__reader_token_position(this);\n}\n\ninline uint64_t //\nwuffs_base__token_buffer::writer_available() const {\n return wuffs_base__token_buffer__writer_available(this);\n}\n\ninline uint64_t //\nwuffs_base__token_buffer::writer_token_position() const {\n return wuffs_base__token_buffer__writer_token_position(this);\n}\n\n#endif // __cplusplus\n" +
+ "// --------\n\n// wuffs_base__token_buffer_meta is the metadata for a\n// wuffs_base__token_buffer's 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__token_buffer_meta;\n\n// wuffs_base__token_buffer is a 1-dimensional buffer (a pointer and length)\n// plus additional metadata.\n//\n// A value with all fields zero is a valid, empty buffer.\ntypedef struct {\n wuffs_base__slice_token data;\n wuffs_base__token_buffer_meta meta;\n\n#ifdef __cplusplus\n inline bool is_valid() const;\n inline void compact();\n inline uint64_t reader_available() const;\n inline uint64_t reader_token_position() const;\n inline uint64_t writer_available() const;\n inline uint64_t writer_token_position() const;\n#endif // __cplusplus\n\n} wuffs_base__token_buffer;\n\nstatic inline wuffs_base__token_buffer //\nwuffs_base__make" +
+ "_token_buffer(wuffs_base__slice_token data,\n wuffs_base__token_buffer_meta meta) {\n wuffs_base__token_buffer ret;\n ret.data = data;\n ret.meta = meta;\n return ret;\n}\n\nstatic inline wuffs_base__token_buffer_meta //\nwuffs_base__make_token_buffer_meta(size_t wi,\n size_t ri,\n uint64_t pos,\n bool closed) {\n wuffs_base__token_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__token_buffer //\nwuffs_base__make_token_buffer_reader(wuffs_base__slice_token s, bool closed) {\n wuffs_base__token_buffer ret;\n ret.data.ptr = s.ptr;\n ret.data.len = s.len;\n ret.meta.wi = s.len;\n ret.meta.ri = 0;\n ret.meta.pos = 0;\n ret.meta.closed = closed;\n return ret;\n}\n\nstatic inline wuffs_base__token_buffer //\nwuffs_base__make_token_buffer_writer(wuffs_base__slice_token s) {\n wuffs_base__token_buffer ret;\n ret.data.p" +
+ "tr = s.ptr;\n ret.data.len = s.len;\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__token_buffer //\nwuffs_base__empty_token_buffer() {\n wuffs_base__token_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__token_buffer_meta //\nwuffs_base__empty_token_buffer_meta() {\n wuffs_base__token_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 bool //\nwuffs_base__token_buffer__is_valid(const wuffs_base__token_buffer* buf) {\n if (buf) {\n if (buf->data.ptr) {\n return (buf->meta.ri <= buf->meta.wi) && (buf->meta.wi <= buf->data.len);\n } else {\n return (buf->meta.ri == 0) && (buf->meta.wi == 0) && (buf->data.len == 0);\n }\n }\n return false;\n}\n\n// wuffs_base__token_buffer__compact moves any written but unread tokens to the\n// sta" +
+ "rt of the buffer.\nstatic inline void //\nwuffs_base__token_buffer__compact(wuffs_base__token_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 * sizeof(wuffs_base__token));\n }\n buf->meta.wi = n;\n buf->meta.ri = 0;\n}\n\nstatic inline uint64_t //\nwuffs_base__token_buffer__reader_available(\n const wuffs_base__token_buffer* buf) {\n return buf ? buf->meta.wi - buf->meta.ri : 0;\n}\n\nstatic inline uint64_t //\nwuffs_base__token_buffer__reader_token_position(\n const wuffs_base__token_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__token_buffer__writer_available(\n const wuffs_base__token_buffer* buf) {\n return buf ? buf->data.len - buf->meta.wi : 0;\n}\n\nstatic inline uint64_t //\nwuffs_base__token_buffer__writ" +
+ "er_token_position(\n const wuffs_base__token_buffer* buf) {\n return buf ? wuffs_base__u64__sat_add(buf->meta.pos, buf->meta.wi) : 0;\n}\n\n#ifdef __cplusplus\n\ninline bool //\nwuffs_base__token_buffer::is_valid() const {\n return wuffs_base__token_buffer__is_valid(this);\n}\n\ninline void //\nwuffs_base__token_buffer::compact() {\n wuffs_base__token_buffer__compact(this);\n}\n\ninline uint64_t //\nwuffs_base__token_buffer::reader_available() const {\n return wuffs_base__token_buffer__reader_available(this);\n}\n\ninline uint64_t //\nwuffs_base__token_buffer::reader_token_position() const {\n return wuffs_base__token_buffer__reader_token_position(this);\n}\n\ninline uint64_t //\nwuffs_base__token_buffer::writer_available() const {\n return wuffs_base__token_buffer__writer_available(this);\n}\n\ninline uint64_t //\nwuffs_base__token_buffer::writer_token_position() const {\n return wuffs_base__token_buffer__writer_token_position(this);\n}\n\n#endif // __cplusplus\n" +
""
const baseCopyright = "" +
diff --git a/internal/cgen/expr.go b/internal/cgen/expr.go
index 7c2874d..3dd3898 100644
--- a/internal/cgen/expr.go
+++ b/internal/cgen/expr.go
@@ -70,7 +70,7 @@
b.writes("false")
}
- } else if ident.IsStrLiteral(g.tm) {
+ } else if ident.IsDQStrLiteral(g.tm) {
if z := g.statusMap[n.StatusQID()]; z.cName != "" {
b.writes("wuffs_base__make_status(")
b.writes(z.cName)
diff --git a/internal/cgen/func.go b/internal/cgen/func.go
index 13df2ca..1d5bd58 100644
--- a/internal/cgen/func.go
+++ b/internal/cgen/func.go
@@ -374,11 +374,17 @@
// TODO: don't hard-code [0], and allow recursive coroutines.
b.printf("uint32_t coro_susp_point = self->private_impl.%s%s[0];\n",
pPrefix, g.currFunk.astFunc.FuncName().Str(g.tm))
- b.printf("if (coro_susp_point) {\n")
- if err := g.writeResumeSuspend(b, &g.currFunk, false); err != nil {
+
+ resumeBuffer := buffer{}
+ if err := g.writeResumeSuspend(&resumeBuffer, &g.currFunk, false); err != nil {
return err
}
- b.writes("}\n")
+ if len(resumeBuffer) > 0 {
+ b.writes("if (coro_susp_point) {\n")
+ b.writex(resumeBuffer)
+ b.writes("}\n")
+ }
+
// Generate a coroutine switch similiar to the technique in
// https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
//
diff --git a/internal/cgen/statement.go b/internal/cgen/statement.go
index b141b64..fd19ad3 100644
--- a/internal/cgen/statement.go
+++ b/internal/cgen/statement.go
@@ -441,7 +441,7 @@
b.writes("wuffs_base__make_status(NULL)")
isComplete = true
} else {
- if retExpr.Ident().IsStrLiteral(g.tm) {
+ if retExpr.Ident().IsDQStrLiteral(g.tm) {
msg, _ := t.Unescape(retExpr.Ident().Str(g.tm))
isComplete = statusMsgIsNote(msg)
}
diff --git a/lang/ast/ast.go b/lang/ast/ast.go
index 7779f6e..03ee9ce 100644
--- a/lang/ast/ast.go
+++ b/lang/ast/ast.go
@@ -236,6 +236,13 @@
return nil
}
+func dropExprCachedMBounds(n *Node) error {
+ if n.kind == KExpr {
+ n.mBounds = interval.IntRange{nil, nil}
+ }
+ return nil
+}
+
type Loop interface {
AsNode() *Node
HasBreak() bool
@@ -379,7 +386,7 @@
// Assert is "assert RHS via ID2(args)", "pre etc", "inv etc" or "post etc":
// - ID0: <IDAssert|IDPre|IDInv|IDPost>
-// - ID2: <string literal> reason
+// - ID2: <"-string literal> reason
// - RHS: <Expr>
// - List0: <Arg> reason arguments
type Assert Node
@@ -390,6 +397,8 @@
func (n *Assert) Condition() *Expr { return n.rhs.AsExpr() }
func (n *Assert) Args() []*Node { return n.list0 }
+func (n *Assert) DropExprCachedMBounds() error { return n.AsNode().Walk(dropExprCachedMBounds) }
+
func NewAssert(keyword t.ID, condition *Expr, reason t.ID, args []*Node) *Assert {
return &Assert{
kind: KAssert,
@@ -539,7 +548,7 @@
}
}
-// While is "while.ID1 MHS, List1 { List2 }":
+// While is "while.ID1 MHS, List1 { List2 } endwhile.ID1":
// - FlagsHasBreak is the while has an explicit break
// - FlagsHasContinue is the while has an explicit continue
// - ID1: <0|label>
@@ -948,7 +957,7 @@
}
// Use is "use ID2":
-// - ID2: <string literal> package path
+// - ID2: <"-string literal> package path
type Use Node
func (n *Use) AsNode() *Node { return (*Node)(n) }
diff --git a/lang/builtin/builtin.go b/lang/builtin/builtin.go
index 2ec2221..06ca6e8 100644
--- a/lang/builtin/builtin.go
+++ b/lang/builtin/builtin.go
@@ -248,6 +248,11 @@
"io_reader.peek_u64be() u64",
"io_reader.peek_u64le() u64",
+ // As an implementation restriction, we require that offset has a constant
+ // value. The (0x1_0000 - sizeof(u64)) limit is arbitrary, but high enough
+ // in practice.
+ "io_reader.peek_u64le_at(offset: u32[..= 0xFFF8]) u64",
+
"io_reader.available() u64",
"io_reader.count_since(mark: u64) u64",
"io_reader.is_closed() bool",
@@ -417,7 +422,8 @@
// ---- token_decoder
- "token_decoder.decode_tokens?(dst: token_writer, src: io_reader)",
+ "token_decoder.decode_tokens?(dst: token_writer, src: io_reader, workbuf: slice u8)",
+ "token_decoder.workbuf_len() range_ii_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 2bdfa85..48ce697 100644
--- a/lang/check/bounds.go
+++ b/lang/check/bounds.go
@@ -357,6 +357,10 @@
}
func (q *checker) bcheckAssert(n *a.Assert) error {
+ if err := n.DropExprCachedMBounds(); err != nil {
+ return err
+ }
+
condition := n.Condition()
if _, err := q.bcheckExpr(condition, 0); err != nil {
return err
@@ -1068,10 +1072,22 @@
} else if err != nil {
return bounds{}, err
}
- advance, update = worstCase.ConstValue(), true
- if advance == nil {
+ if worstCase.ConstValue() == nil {
return bounds{}, fmt.Errorf("check: skip_fast worst_case is not a constant value")
}
+ advance, update = worstCase.ConstValue(), true
+
+ } else if method == t.IDPeekU64LEAt {
+ args := n.Args()
+ if len(args) != 1 {
+ return bounds{}, fmt.Errorf("check: internal error: bad peek_u64le_at arguments")
+ }
+ offset := args[0].AsArg().Value()
+ if offset.ConstValue() == nil {
+ return bounds{}, fmt.Errorf("check: peek_u64le_at offset is not a constant value")
+ }
+ advance, update = big.NewInt(8), false
+ advance.Add(advance, offset.ConstValue())
} else if method >= t.IDPeekU8 {
if m := method - t.IDPeekU8; m < t.ID(len(ioMethodAdvances)) {
diff --git a/lang/check/type.go b/lang/check/type.go
index 50da53a..7a0da26 100644
--- a/lang/check/type.go
+++ b/lang/check/type.go
@@ -364,7 +364,28 @@
n.SetMType(typeExprIdeal)
return nil
- } else if id1.IsStrLiteral(q.tm) {
+ } else if id1.IsSQStrLiteral(q.tm) {
+ s := id1.Str(q.tm)
+ unescaped, ok := t.Unescape(id1.Str(q.tm))
+ if !ok {
+ return fmt.Errorf("check: invalid '-string literal %q", s)
+ }
+
+ z := big.NewInt(0)
+ i, iEnd, iDelta := 0, len(unescaped), +1 // Big-endian.
+ if (len(s) > 2) && (s[len(s)-2] == 'l') {
+ i, iEnd, iDelta = len(unescaped)-1, -1, -1 // Little-endian.
+ }
+ for ; i != iEnd; i += iDelta {
+ z.Lsh(z, 8)
+ z.Or(z, big.NewInt(int64(unescaped[i])))
+ }
+
+ n.SetConstValue(z)
+ n.SetMType(typeExprIdeal)
+ return nil
+
+ } else if id1.IsDQStrLiteral(q.tm) {
if _, ok := q.c.statuses[n.StatusQID()]; !ok {
return fmt.Errorf("check: unrecognized status %s", n.StatusQID().Str(q.tm))
}
diff --git a/lang/parse/parse.go b/lang/parse/parse.go
index ab54a69..3a931cb 100644
--- a/lang/parse/parse.go
+++ b/lang/parse/parse.go
@@ -113,9 +113,9 @@
case t.IDUse:
p.src = p.src[1:]
path := p.peek1()
- if !path.IsStrLiteral(p.tm) {
+ if !path.IsDQStrLiteral(p.tm) {
got := p.tm.ByID(path)
- return nil, fmt.Errorf(`parse: expected string literal, got %q at %s:%d`, got, p.filename, p.line())
+ return nil, fmt.Errorf(`parse: expected "-string literal, got %q at %s:%d`, got, p.filename, p.line())
}
p.src = p.src[1:]
if x := p.peek1(); x != t.IDSemicolon {
@@ -224,9 +224,9 @@
p.src = p.src[1:]
message := p.peek1()
- if !message.IsStrLiteral(p.tm) {
+ if !message.IsDQStrLiteral(p.tm) {
got := p.tm.ByID(message)
- return nil, fmt.Errorf(`parse: expected string literal, got %q at %s:%d`, got, p.filename, p.line())
+ return nil, fmt.Errorf(`parse: expected "-string literal, got %q at %s:%d`, got, p.filename, p.line())
}
if s, _ := t.Unescape(p.tm.ByID(message)); !isStatusMessage(s) {
return nil, fmt.Errorf(`parse: status message %q does not start with `+
@@ -604,9 +604,9 @@
if p.peek1() == t.IDVia {
p.src = p.src[1:]
reason = p.peek1()
- if !reason.IsStrLiteral(p.tm) {
+ if !reason.IsDQStrLiteral(p.tm) {
got := p.tm.ByID(reason)
- return nil, fmt.Errorf(`parse: expected string literal, got %q at %s:%d`, got, p.filename, p.line())
+ return nil, fmt.Errorf(`parse: expected "-string literal, got %q at %s:%d`, got, p.filename, p.line())
}
p.src = p.src[1:]
args, err = p.parseList(t.IDCloseParen, (*parser).parseArgNode)
@@ -649,14 +649,16 @@
return false
}
p.src = p.src[1:]
- if p.peek1() != t.IDDot {
- return false
+ if label != 0 {
+ if p.peek1() != t.IDDot {
+ return false
+ }
+ p.src = p.src[1:]
+ if p.peek1() != label {
+ return false
+ }
+ p.src = p.src[1:]
}
- p.src = p.src[1:]
- if p.peek1() != label {
- return false
- }
- p.src = p.src[1:]
return true
}
@@ -737,9 +739,13 @@
if err != nil {
return nil, err
}
- if (label != 0) && !p.parseEndwhile(label) {
- return nil, fmt.Errorf(`parse: expected endwhile.%s at %s:%d`,
- label.Str(p.tm), p.filename, p.line())
+ if !p.parseEndwhile(label) {
+ dotLabel := ""
+ if label != 0 {
+ dotLabel = "." + label.Str(p.tm)
+ }
+ return nil, fmt.Errorf(`parse: expected endwhile%s at %s:%d`,
+ dotLabel, p.filename, p.line())
}
return a.NewWhile(label, condition, asserts, body).AsNode(), nil
}
@@ -1254,11 +1260,11 @@
p.src = p.src[1:]
if x := p.peek1(); x.IsLiteral(p.tm) {
- if x.IsNumLiteral(p.tm) {
- return nil, fmt.Errorf(`parse: dot followed by numeric literal at %s:%d`, p.filename, p.line())
+ if !x.IsDQStrLiteral(p.tm) {
+ return nil, fmt.Errorf(`parse: dot followed by non-"-string literal at %s:%d`, p.filename, p.line())
}
if !first {
- return nil, fmt.Errorf(`parse: string literal %s has too many package qualifiers at %s:%d`,
+ return nil, fmt.Errorf(`parse: "-string literal %s has too many package qualifiers at %s:%d`,
x.Str(p.tm), p.filename, p.line())
}
p.src = p.src[1:]
diff --git a/lang/render/render.go b/lang/render/render.go
index a42ec18..2efa21b 100644
--- a/lang/render/render.go
+++ b/lang/render/render.go
@@ -291,7 +291,8 @@
}
func isCloseIdentStrLiteralQuestion(tm *t.Map, x t.ID) bool {
- return x.IsClose() || x.IsIdent(tm) || x.IsStrLiteral(tm) || (x == t.IDQuestion)
+ return x.IsClose() || x.IsIdent(tm) || x.IsDQStrLiteral(tm) ||
+ x.IsSQStrLiteral(tm) || (x == t.IDQuestion)
}
func measureVarNameLength(tm *t.Map, lineTokens []t.Token, remaining []t.Token) uint32 {
diff --git a/lang/token/list.go b/lang/token/list.go
index ea2e069..d585c60 100644
--- a/lang/token/list.go
+++ b/lang/token/list.go
@@ -81,7 +81,8 @@
return false
}
-func (x ID) IsStrLiteral(m *Map) bool {
+// IsDQStrLiteral returns whether x is a double-quote string literal.
+func (x ID) IsDQStrLiteral(m *Map) bool {
if x < nBuiltInIDs {
return false
} else if s := m.ByID(x); s != "" {
@@ -90,6 +91,16 @@
return false
}
+// IsSQStrLiteral returns whether x is a single-quote string literal.
+func (x ID) IsSQStrLiteral(m *Map) bool {
+ if x < nBuiltInIDs {
+ return false
+ } else if s := m.ByID(x); s != "" {
+ return s[0] == '\''
+ }
+ return false
+}
+
func (x ID) IsIdent(m *Map) bool {
if x < nBuiltInIDs {
return minBuiltInIdent <= x && x <= maxBuiltInIdent
@@ -544,6 +555,8 @@
// --------
+ IDPeekU64LEAt = ID(0x1A0)
+
IDPeekU8 = ID(0x1A1)
IDPeekU16BE = ID(0x1A2)
@@ -899,6 +912,8 @@
// --------
+ IDPeekU64LEAt: "peek_u64le_at",
+
IDPeekU8: "peek_u8",
IDPeekU16BE: "peek_u16be",
diff --git a/lang/token/token.go b/lang/token/token.go
index b46e4dc..0d821e9 100644
--- a/lang/token/token.go
+++ b/lang/token/token.go
@@ -17,6 +17,7 @@
import (
"errors"
"fmt"
+ "unicode/utf8"
)
const (
@@ -25,11 +26,115 @@
maxTokenSize = 1023
)
+var backslashes = [256]byte{
+ '"': 0x22 | 0x80,
+ '\'': 0x27 | 0x80,
+ '/': 0x2F | 0x80,
+ '0': 0x00 | 0x80,
+ '?': 0x3F | 0x80,
+ '\\': 0x5C | 0x80,
+ 'a': 0x07 | 0x80,
+ 'b': 0x08 | 0x80,
+ 'e': 0x1B | 0x80,
+ 'f': 0x0C | 0x80,
+ 'n': 0x0A | 0x80,
+ 'r': 0x0D | 0x80,
+ 't': 0x09 | 0x80,
+ 'v': 0x0B | 0x80,
+}
+
func Unescape(s string) (unescaped string, ok bool) {
- if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' {
+ if len(s) < 2 {
return "", false
}
- return s[1 : len(s)-1], true
+ switch s[0] {
+ case '"':
+ if s[len(s)-1] == '"' {
+ s = s[1 : len(s)-1]
+ } else {
+ return "", false
+ }
+ case '\'':
+ if s[len(s)-1] == '\'' {
+ s = s[1 : len(s)-1]
+ } else if (len(s) >= 4) && (s[len(s)-3] == '\'') &&
+ ((s[len(s)-2] == 'b') || (s[len(s)-2] == 'l')) &&
+ (s[len(s)-1] == 'e') { // "be" or "le" suffix.
+ s = s[1 : len(s)-3]
+ } else {
+ return "", false
+ }
+ default:
+ return "", false
+ }
+
+ for i := 0; ; i++ {
+ if i == len(s) {
+ // There were no backslashes.
+ return s, true
+ }
+ if s[i] == '\\' {
+ break
+ }
+ }
+
+ // There were backslashes.
+ b := make([]byte, 0, len(s))
+ for i := 0; i < len(s); {
+ if s[i] != '\\' {
+ b = append(b, s[i])
+ i += 1
+ continue
+ } else if i >= (len(s) - 1) {
+ // No-op.
+ } else if x := backslashes[s[i+1]]; x != 0 {
+ b = append(b, x&0x7F)
+ i += 2
+ continue
+ } else if (s[i+1] == 'x') && (i < (len(s) - 3)) {
+ u0 := unhex(s[i+2])
+ u1 := unhex(s[i+3])
+ u := (u0 << 4) | u1
+ if 0 <= u {
+ b = append(b, uint8(u))
+ i += 4
+ continue
+ }
+ } else if (s[i+1] == 'u') && (i < (len(s) - 5)) {
+ u0 := unhex(s[i+2])
+ u1 := unhex(s[i+3])
+ u2 := unhex(s[i+4])
+ u3 := unhex(s[i+5])
+ u := (u0 << 12) | (u1 << 8) | (u2 << 4) | u3
+ if (u >= 0) && utf8.ValidRune(u) {
+ e := [utf8.UTFMax]byte{}
+ n := utf8.EncodeRune(e[:], u)
+ b = append(b, e[:n]...)
+ i += 6
+ continue
+ }
+ } else if (s[i+1] == 'U') && (i < (len(s) - 9)) {
+ u0 := unhex(s[i+2])
+ u1 := unhex(s[i+3])
+ u2 := unhex(s[i+4])
+ u3 := unhex(s[i+5])
+ u4 := unhex(s[i+6])
+ u5 := unhex(s[i+7])
+ u6 := unhex(s[i+8])
+ u7 := unhex(s[i+9])
+ u := (u0 << 28) | (u1 << 24) | (u2 << 20) | (u3 << 16) |
+ (u4 << 12) | (u5 << 8) | (u6 << 4) | u7
+ if (u >= 0) && utf8.ValidRune(u) {
+ e := [utf8.UTFMax]byte{}
+ n := utf8.EncodeRune(e[:], u)
+ b = append(b, e[:n]...)
+ i += 10
+ continue
+ }
+ }
+ return "", false
+ }
+ return string(b), true
}
type Map struct {
@@ -81,6 +186,18 @@
return ""
}
+func unhex(c byte) int32 {
+ switch {
+ case 'A' <= c && c <= 'F':
+ return int32(c) - ('A' - 10)
+ case 'a' <= c && c <= 'f':
+ return int32(c) - ('a' - 10)
+ case '0' <= c && c <= '9':
+ return int32(c) - '0'
+ }
+ return -1
+}
+
func alpha(c byte) bool {
return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') || (c == '_')
}
@@ -150,32 +267,45 @@
continue
}
- // TODO: recognize escapes such as `\t`, `\"` and `\\`. For now, we
- // assume that strings don't contain control bytes or backslashes.
- // Neither should be necessary to parse `use "foo/bar"` lines.
- if c == '"' {
+ if (c == '"') || (c == '\'') {
+ quote := c
j := i + 1
- for ; j < len(src); j++ {
+ for j < len(src) {
c = src[j]
- if c == '"' {
- j++
+ j++
+ if c == quote {
break
- }
- if c == '\\' {
- return nil, nil, fmt.Errorf("token: backslash in string at %s:%d", filename, line)
- }
- if c == '\n' {
- return nil, nil, fmt.Errorf("token: expected final '\"' in string at %s:%d", filename, line)
- }
- if c < ' ' {
+ } else if c == '\\' {
+ if quote == '"' {
+ return nil, nil, fmt.Errorf("token: backslash in \"-string at %s:%d", filename, line)
+ }
+ } else if c == '\n' {
+ return nil, nil, fmt.Errorf("token: expected final %c in string at %s:%d", quote, filename, line)
+ } else if c < ' ' {
return nil, nil, fmt.Errorf("token: control character in string at %s:%d", filename, line)
}
- // The -1 is because we still haven't seen the final '"'.
- if j-i == maxTokenSize-1 {
- return nil, nil, fmt.Errorf("token: string too long at %s:%d", filename, line)
+ }
+
+ hasEndian := (quote == '\'') && (j < (len(src) - 2)) &&
+ ((src[j] == 'b') || (src[j] == 'l')) &&
+ (src[j+1] == 'e')
+ if hasEndian {
+ j += 2
+ }
+
+ if j-i > maxTokenSize {
+ return nil, nil, fmt.Errorf("token: string too long at %s:%d", filename, line)
+ }
+ s := string(src[i:j])
+ if quote == '\'' {
+ if unescaped, ok := Unescape(s); !ok {
+ return nil, nil, fmt.Errorf("token: invalid '-string at %s:%d", filename, line)
+ } else if (len(unescaped) > 1) && !hasEndian {
+ return nil, nil, fmt.Errorf("token: multi-byte '-string needs be or le suffix at %s:%d", filename, line)
}
}
- id, err := m.Insert(string(src[i:j]))
+
+ id, err := m.Insert(s)
if err != nil {
return nil, nil, err
}
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index c7559dd..e139fb5 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -433,6 +433,80 @@
return res;
}
+// --------
+
+typedef struct {
+ uint64_t hi;
+ uint64_t lo;
+} wuffs_base__multiply_u64__output;
+
+// wuffs_base__multiply_u64 returns x*y as a 128-bit value.
+//
+// The maximum inclusive output hi_lo is 0xFFFFFFFFFFFFFFFE_0000000000000001.
+static inline wuffs_base__multiply_u64__output //
+wuffs_base__multiply_u64(uint64_t x, uint64_t y) {
+ uint64_t x0 = x & 0xFFFFFFFF;
+ uint64_t x1 = x >> 32;
+ uint64_t y0 = y & 0xFFFFFFFF;
+ uint64_t y1 = y >> 32;
+ uint64_t w0 = x0 * y0;
+ uint64_t t = (x1 * y0) + (w0 >> 32);
+ uint64_t w1 = t & 0xFFFFFFFF;
+ uint64_t w2 = t >> 32;
+ w1 += x0 * y1;
+ wuffs_base__multiply_u64__output o;
+ o.hi = (x1 * y1) + w2 + (w1 >> 32);
+ o.lo = x * y;
+ return o;
+}
+
+ // --------
+
+#if defined(__GNUC__) && (__SIZEOF_LONG__ == 8)
+
+static inline uint32_t //
+wuffs_base__count_leading_zeroes_u64(uint64_t u) {
+ return u ? ((uint32_t)(__builtin_clzl(u))) : 64u;
+}
+
+#else
+
+static inline uint32_t //
+wuffs_base__count_leading_zeroes_u64(uint64_t u) {
+ if (u == 0) {
+ return 64;
+ }
+
+ uint32_t n = 0;
+ if ((u >> 32) == 0) {
+ n |= 32;
+ u <<= 32;
+ }
+ if ((u >> 48) == 0) {
+ n |= 16;
+ u <<= 16;
+ }
+ if ((u >> 56) == 0) {
+ n |= 8;
+ u <<= 8;
+ }
+ if ((u >> 60) == 0) {
+ n |= 4;
+ u <<= 4;
+ }
+ if ((u >> 62) == 0) {
+ n |= 2;
+ u <<= 2;
+ }
+ if ((u >> 63) == 0) {
+ n |= 1;
+ u <<= 1;
+ }
+ return n;
+}
+
+#endif // defined(__GNUC__) && (__SIZEOF_LONG__ == 8)
+
// --------
#define wuffs_base__load_u8be__no_bounds_check \
@@ -1613,6 +1687,7 @@
wuffs_base__io_buffer_meta meta;
#ifdef __cplusplus
+ inline bool is_valid() const;
inline void compact();
inline uint64_t reader_available() const;
inline uint64_t reader_io_position() const;
@@ -1645,6 +1720,30 @@
}
static inline wuffs_base__io_buffer //
+wuffs_base__make_io_buffer_reader(wuffs_base__slice_u8 s, bool closed) {
+ wuffs_base__io_buffer ret;
+ ret.data.ptr = s.ptr;
+ ret.data.len = s.len;
+ ret.meta.wi = s.len;
+ ret.meta.ri = 0;
+ ret.meta.pos = 0;
+ ret.meta.closed = closed;
+ return ret;
+}
+
+static inline wuffs_base__io_buffer //
+wuffs_base__make_io_buffer_writer(wuffs_base__slice_u8 s) {
+ wuffs_base__io_buffer ret;
+ ret.data.ptr = s.ptr;
+ ret.data.len = s.len;
+ ret.meta.wi = 0;
+ ret.meta.ri = 0;
+ ret.meta.pos = 0;
+ ret.meta.closed = false;
+ return ret;
+}
+
+static inline wuffs_base__io_buffer //
wuffs_base__empty_io_buffer() {
wuffs_base__io_buffer ret;
ret.data.ptr = NULL;
@@ -1666,6 +1765,18 @@
return ret;
}
+static inline bool //
+wuffs_base__io_buffer__is_valid(const wuffs_base__io_buffer* buf) {
+ if (buf) {
+ if (buf->data.ptr) {
+ return (buf->meta.ri <= buf->meta.wi) && (buf->meta.wi <= buf->data.len);
+ } else {
+ return (buf->meta.ri == 0) && (buf->meta.wi == 0) && (buf->data.len == 0);
+ }
+ }
+ return false;
+}
+
// wuffs_base__io_buffer__compact moves any written but unread bytes to the
// start of the buffer.
static inline void //
@@ -1704,6 +1815,11 @@
#ifdef __cplusplus
+inline bool //
+wuffs_base__io_buffer::is_valid() const {
+ return wuffs_base__io_buffer__is_valid(this);
+}
+
inline void //
wuffs_base__io_buffer::compact() {
wuffs_base__io_buffer__compact(this);
@@ -1897,6 +2013,11 @@
#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_SIGNED 0x00002
#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_INTEGER_UNSIGNED 0x00004
+#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_NEG_INF 0x00010
+#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_POS_INF 0x00020
+#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_NEG_NAN 0x00040
+#define WUFFS_BASE__TOKEN__VBD__NUMBER__CONTENT_POS_NAN 0x00080
+
// The number 300 might be represented as "\x01\x2C", "\x2C\x01\x00\x00" or
// "300", which are big-endian, little-endian or text. For binary formats, the
// token length discriminates e.g. u16 little-endian vs u32 little-endian.
@@ -2028,6 +2149,7 @@
wuffs_base__token_buffer_meta meta;
#ifdef __cplusplus
+ inline bool is_valid() const;
inline void compact();
inline uint64_t reader_available() const;
inline uint64_t reader_token_position() const;
@@ -2060,6 +2182,30 @@
}
static inline wuffs_base__token_buffer //
+wuffs_base__make_token_buffer_reader(wuffs_base__slice_token s, bool closed) {
+ wuffs_base__token_buffer ret;
+ ret.data.ptr = s.ptr;
+ ret.data.len = s.len;
+ ret.meta.wi = s.len;
+ ret.meta.ri = 0;
+ ret.meta.pos = 0;
+ ret.meta.closed = closed;
+ return ret;
+}
+
+static inline wuffs_base__token_buffer //
+wuffs_base__make_token_buffer_writer(wuffs_base__slice_token s) {
+ wuffs_base__token_buffer ret;
+ ret.data.ptr = s.ptr;
+ ret.data.len = s.len;
+ ret.meta.wi = 0;
+ ret.meta.ri = 0;
+ ret.meta.pos = 0;
+ ret.meta.closed = false;
+ return ret;
+}
+
+static inline wuffs_base__token_buffer //
wuffs_base__empty_token_buffer() {
wuffs_base__token_buffer ret;
ret.data.ptr = NULL;
@@ -2081,6 +2227,18 @@
return ret;
}
+static inline bool //
+wuffs_base__token_buffer__is_valid(const wuffs_base__token_buffer* buf) {
+ if (buf) {
+ if (buf->data.ptr) {
+ return (buf->meta.ri <= buf->meta.wi) && (buf->meta.wi <= buf->data.len);
+ } else {
+ return (buf->meta.ri == 0) && (buf->meta.wi == 0) && (buf->data.len == 0);
+ }
+ }
+ return false;
+}
+
// wuffs_base__token_buffer__compact moves any written but unread tokens to the
// start of the buffer.
static inline void //
@@ -2124,6 +2282,11 @@
#ifdef __cplusplus
+inline bool //
+wuffs_base__token_buffer::is_valid() const {
+ return wuffs_base__token_buffer__is_valid(this);
+}
+
inline void //
wuffs_base__token_buffer::compact() {
wuffs_base__token_buffer__compact(this);
@@ -3507,7 +3670,35 @@
return f;
}
- // ---------------- Unicode and UTF-8
+// ---------------- Hexadecimal
+
+// wuffs_base__hexadecimal__decode2 converts "6A6b" to "jk", where e.g. 'j' is
+// U+006A. There are 2 source bytes for every destination byte.
+//
+// It returns the number of dst bytes written: the minimum of dst.len and
+// (src.len / 2). Excess source bytes are ignored.
+//
+// It assumes that the src bytes are two hexadecimal digits (0-9, A-F, a-f),
+// repeated. It may write nonsense bytes if not, although it will not read or
+// write out of bounds.
+size_t //
+wuffs_base__hexadecimal__decode2(wuffs_base__slice_u8 dst,
+ wuffs_base__slice_u8 src);
+
+// wuffs_base__hexadecimal__decode4 converts "\\x6A\\x6b" to "jk", where e.g.
+// 'j' is U+006A. There are 4 source bytes for every destination byte.
+//
+// It returns the number of dst bytes written: the minimum of dst.len and
+// (src.len / 4). Excess source bytes are ignored.
+//
+// It assumes that the src bytes are two ignored bytes and then two hexadecimal
+// digits (0-9, A-F, a-f), repeated. It may write nonsense bytes if not,
+// although it will not read or write out of bounds.
+size_t //
+wuffs_base__hexadecimal__decode4(wuffs_base__slice_u8 dst,
+ wuffs_base__slice_u8 src);
+
+// ---------------- Unicode and UTF-8
#define WUFFS_BASE__UNICODE_CODE_POINT__MIN_INCL 0x00000000
#define WUFFS_BASE__UNICODE_CODE_POINT__MAX_INCL 0x0010FFFF
@@ -3922,7 +4113,9 @@
typedef struct {
wuffs_base__status (*decode_tokens)(void* self,
wuffs_base__token_buffer* a_dst,
- wuffs_base__io_buffer* a_src);
+ wuffs_base__io_buffer* a_src,
+ wuffs_base__slice_u8 a_workbuf);
+ wuffs_base__range_ii_u64 (*workbuf_len)(const void* self);
} wuffs_base__token_decoder__func_ptrs;
typedef struct wuffs_base__token_decoder__struct wuffs_base__token_decoder;
@@ -3930,7 +4123,11 @@
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
wuffs_base__token_decoder__decode_tokens(wuffs_base__token_decoder* self,
wuffs_base__token_buffer* a_dst,
- wuffs_base__io_buffer* a_src);
+ wuffs_base__io_buffer* a_src,
+ wuffs_base__slice_u8 a_workbuf);
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__range_ii_u64 //
+wuffs_base__token_decoder__workbuf_len(const wuffs_base__token_decoder* self);
#if defined(__cplusplus) || defined(WUFFS_IMPLEMENTATION)
@@ -3944,8 +4141,16 @@
#ifdef __cplusplus
inline wuffs_base__status //
- decode_tokens(wuffs_base__token_buffer* a_dst, wuffs_base__io_buffer* a_src) {
- return wuffs_base__token_decoder__decode_tokens(this, a_dst, a_src);
+ decode_tokens(wuffs_base__token_buffer* a_dst,
+ wuffs_base__io_buffer* a_src,
+ wuffs_base__slice_u8 a_workbuf) {
+ return wuffs_base__token_decoder__decode_tokens(this, a_dst, a_src,
+ a_workbuf);
+ }
+
+ inline wuffs_base__range_ii_u64 //
+ workbuf_len() const {
+ return wuffs_base__token_decoder__workbuf_len(this);
}
#endif // __cplusplus
@@ -5791,6 +5996,8 @@
// ---------------- Public Consts
+#define WUFFS_JSON__DECODER_WORKBUF_LEN_MAX_INCL_WORST_CASE 0
+
#define WUFFS_JSON__DECODER_DEPTH_MAX_INCL 1024
#define WUFFS_JSON__DECODER_DST_TOKEN_BUFFER_LENGTH_MIN_INCL 1
@@ -5817,7 +6024,7 @@
#define WUFFS_JSON__QUIRK_ALLOW_COMMENT_LINE 1225364489
-#define WUFFS_JSON__QUIRK_ALLOW_FINAL_COMMA 1225364490
+#define WUFFS_JSON__QUIRK_ALLOW_EXTRA_COMMA 1225364490
#define WUFFS_JSON__QUIRK_ALLOW_INF_NAN_NUMBERS 1225364491
@@ -5827,7 +6034,7 @@
#define WUFFS_JSON__QUIRK_ALLOW_TRAILING_NEW_LINE 1225364494
-#define WUFFS_JSON__QUIRK_REPLACE_INVALID_UTF_8 1225364495
+#define WUFFS_JSON__QUIRK_REPLACE_INVALID_UNICODE 1225364495
// ---------------- Struct Declarations
@@ -5860,10 +6067,19 @@
// ---------------- Public Function Prototypes
+WUFFS_BASE__MAYBE_STATIC wuffs_base__empty_struct //
+wuffs_json__decoder__set_quirk_enabled(wuffs_json__decoder* self,
+ uint32_t a_quirk,
+ bool a_enabled);
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__range_ii_u64 //
+wuffs_json__decoder__workbuf_len(const wuffs_json__decoder* self);
+
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
wuffs_json__decoder__decode_tokens(wuffs_json__decoder* self,
wuffs_base__token_buffer* a_dst,
- wuffs_base__io_buffer* a_src);
+ wuffs_base__io_buffer* a_src,
+ wuffs_base__slice_u8 a_workbuf);
// ---------------- Struct Definitions
@@ -5888,7 +6104,26 @@
wuffs_base__vtable vtable_for__wuffs_base__token_decoder;
wuffs_base__vtable null_vtable;
+ bool f_quirk_enabled_allow_backslash_etc[8];
+ bool f_quirk_enabled_allow_backslash_capital_u;
+ bool f_quirk_enabled_allow_backslash_x;
+ bool f_quirk_enabled_allow_comment_block;
+ bool f_quirk_enabled_allow_comment_line;
+ bool f_quirk_enabled_allow_extra_comma;
+ bool f_quirk_enabled_allow_inf_nan_numbers;
+ bool f_quirk_enabled_allow_leading_ascii_record_separator;
+ bool f_quirk_enabled_allow_leading_unicode_byte_order_mark;
+ bool f_quirk_enabled_allow_trailing_new_line;
+ bool f_quirk_enabled_replace_invalid_unicode;
+ bool f_allow_leading_ars;
+ bool f_allow_leading_ubom;
+ bool f_end_of_data;
+
uint32_t p_decode_tokens[1];
+ uint32_t p_decode_leading[1];
+ uint32_t p_decode_comment[1];
+ uint32_t p_decode_inf_nan[1];
+ uint32_t p_decode_trailing_new_line[1];
} private_impl;
struct {
@@ -5899,6 +6134,12 @@
uint32_t v_expect;
uint32_t v_expect_after_value;
} s_decode_tokens[1];
+ struct {
+ uint32_t v_link_prev;
+ } s_decode_comment[1];
+ struct {
+ uint32_t v_neg;
+ } s_decode_inf_nan[1];
} private_data;
#ifdef __cplusplus
@@ -5943,9 +6184,21 @@
return (wuffs_base__token_decoder*)this;
}
+ inline wuffs_base__empty_struct //
+ set_quirk_enabled(uint32_t a_quirk, bool a_enabled) {
+ return wuffs_json__decoder__set_quirk_enabled(this, a_quirk, a_enabled);
+ }
+
+ inline wuffs_base__range_ii_u64 //
+ workbuf_len() const {
+ return wuffs_json__decoder__workbuf_len(this);
+ }
+
inline wuffs_base__status //
- decode_tokens(wuffs_base__token_buffer* a_dst, wuffs_base__io_buffer* a_src) {
- return wuffs_json__decoder__decode_tokens(this, a_dst, a_src);
+ decode_tokens(wuffs_base__token_buffer* a_dst,
+ wuffs_base__io_buffer* a_src,
+ wuffs_base__slice_u8 a_workbuf) {
+ return wuffs_json__decoder__decode_tokens(this, a_dst, a_src, a_workbuf);
}
#endif // __cplusplus
@@ -7468,7 +7721,8 @@
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
wuffs_base__token_decoder__decode_tokens(wuffs_base__token_decoder* self,
wuffs_base__token_buffer* a_dst,
- wuffs_base__io_buffer* a_src) {
+ wuffs_base__io_buffer* a_src,
+ wuffs_base__slice_u8 a_workbuf) {
if (!self) {
return wuffs_base__make_status(wuffs_base__error__bad_receiver);
}
@@ -7485,7 +7739,7 @@
if (v->vtable_name == wuffs_base__token_decoder__vtable_name) {
const wuffs_base__token_decoder__func_ptrs* func_ptrs =
(const wuffs_base__token_decoder__func_ptrs*)(v->function_pointers);
- return (*func_ptrs->decode_tokens)(self, a_dst, a_src);
+ return (*func_ptrs->decode_tokens)(self, a_dst, a_src, a_workbuf);
} else if (v->vtable_name == NULL) {
break;
}
@@ -7495,6 +7749,32 @@
return wuffs_base__make_status(wuffs_base__error__bad_vtable);
}
+WUFFS_BASE__MAYBE_STATIC wuffs_base__range_ii_u64 //
+wuffs_base__token_decoder__workbuf_len(const wuffs_base__token_decoder* self) {
+ if (!self) {
+ return wuffs_base__utility__empty_range_ii_u64();
+ }
+ if ((self->private_impl.magic != WUFFS_BASE__MAGIC) &&
+ (self->private_impl.magic != WUFFS_BASE__DISABLED)) {
+ return wuffs_base__utility__empty_range_ii_u64();
+ }
+
+ const wuffs_base__vtable* v = &self->private_impl.first_vtable;
+ int i;
+ for (i = 0; i < 63; i++) {
+ if (v->vtable_name == wuffs_base__token_decoder__vtable_name) {
+ const wuffs_base__token_decoder__func_ptrs* func_ptrs =
+ (const wuffs_base__token_decoder__func_ptrs*)(v->function_pointers);
+ return (*func_ptrs->workbuf_len)(self);
+ } else if (v->vtable_name == NULL) {
+ break;
+ }
+ v++;
+ }
+
+ return wuffs_base__utility__empty_range_ii_u64();
+}
+
// ---------------- Images
const uint32_t wuffs_base__pixel_format__bits_per_channel[16] = {
@@ -8739,6 +9019,9 @@
// fixed precision floating point decimal number, augmented with ±infinity
// values, but it cannot represent NaN (Not a Number).
//
+// "High precision" means that the mantissa holds 500 decimal digits. 500 is
+// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION.
+//
// An HPD isn't for general purpose arithmetic, only for conversions to and
// from IEEE 754 double-precision floating point, where the largest and
// smallest positive, finite values are approximately 1.8e+308 and 4.9e-324.
@@ -8758,7 +9041,7 @@
// For example, if num_digits is 3 and digits is "\x07\x08\x09":
// - A decimal_point of -2 means ".00789"
// - A decimal_point of -1 means ".0789"
-// - A decimal_point of -0 means ".789"
+// - A decimal_point of +0 means ".789"
// - A decimal_point of +1 means "7.89"
// - A decimal_point of +2 means "78.9"
// - A decimal_point of +3 means "789."
@@ -9288,6 +9571,438 @@
// --------
+// The wuffs_base__private_implementation__etc_powers_of_10 tables were printed
+// by script/print-mpb-powers-of-10.go. That script has an optional -comments
+// flag, whose output is not copied here, which prints further detail.
+//
+// These tables are used in
+// wuffs_base__private_implementation__medium_prec_bin__assign_from_hpd.
+
+// wuffs_base__private_implementation__big_powers_of_10 contains approximations
+// to the powers of 10, ranging from 1e-348 to 1e+340, with the exponent
+// stepping by 8: -348, -340, -332, ..., -12, -4, +4, +12, ..., +340. Each step
+// consists of three uint32_t elements. There are 87 triples, 87 * 3 = 261.
+//
+// For example, the third approximation, for 1e-332, consists of the uint32_t
+// triple (0x3055AC76, 0x8B16FB20, 0xFFFFFB72). The first two of that triple
+// are a little-endian uint64_t value: 0x8B16FB203055AC76. The last one is an
+// int32_t value: -1166. Together, they represent the approximation:
+// 1e-332 ≈ 0x8B16FB203055AC76 * (2 ** -1166)
+// Similarly, the (0x00000000, 0x9C400000, 0xFFFFFFCE) uint32_t triple means:
+// 1e+4 ≈ 0x9C40000000000000 * (2 ** -50) // This approx'n is exact.
+// Similarly, the (0xD4C4FB27, 0xED63A231, 0x000000A2) uint32_t triple means:
+// 1e+68 ≈ 0xED63A231D4C4FB27 * (2 ** 162)
+static const uint32_t
+ wuffs_base__private_implementation__big_powers_of_10[261] = {
+ 0x081C0288, 0xFA8FD5A0, 0xFFFFFB3C, 0xA23EBF76, 0xBAAEE17F, 0xFFFFFB57,
+ 0x3055AC76, 0x8B16FB20, 0xFFFFFB72, 0x5DCE35EA, 0xCF42894A, 0xFFFFFB8C,
+ 0x55653B2D, 0x9A6BB0AA, 0xFFFFFBA7, 0x3D1A45DF, 0xE61ACF03, 0xFFFFFBC1,
+ 0xC79AC6CA, 0xAB70FE17, 0xFFFFFBDC, 0xBEBCDC4F, 0xFF77B1FC, 0xFFFFFBF6,
+ 0x416BD60C, 0xBE5691EF, 0xFFFFFC11, 0x907FFC3C, 0x8DD01FAD, 0xFFFFFC2C,
+ 0x31559A83, 0xD3515C28, 0xFFFFFC46, 0xADA6C9B5, 0x9D71AC8F, 0xFFFFFC61,
+ 0x23EE8BCB, 0xEA9C2277, 0xFFFFFC7B, 0x4078536D, 0xAECC4991, 0xFFFFFC96,
+ 0x5DB6CE57, 0x823C1279, 0xFFFFFCB1, 0x4DFB5637, 0xC2109436, 0xFFFFFCCB,
+ 0x3848984F, 0x9096EA6F, 0xFFFFFCE6, 0x25823AC7, 0xD77485CB, 0xFFFFFD00,
+ 0x97BF97F4, 0xA086CFCD, 0xFFFFFD1B, 0x172AACE5, 0xEF340A98, 0xFFFFFD35,
+ 0x2A35B28E, 0xB23867FB, 0xFFFFFD50, 0xD2C63F3B, 0x84C8D4DF, 0xFFFFFD6B,
+ 0x1AD3CDBA, 0xC5DD4427, 0xFFFFFD85, 0xBB25C996, 0x936B9FCE, 0xFFFFFDA0,
+ 0x7D62A584, 0xDBAC6C24, 0xFFFFFDBA, 0x0D5FDAF6, 0xA3AB6658, 0xFFFFFDD5,
+ 0xDEC3F126, 0xF3E2F893, 0xFFFFFDEF, 0xAAFF80B8, 0xB5B5ADA8, 0xFFFFFE0A,
+ 0x6C7C4A8B, 0x87625F05, 0xFFFFFE25, 0x34C13053, 0xC9BCFF60, 0xFFFFFE3F,
+ 0x91BA2655, 0x964E858C, 0xFFFFFE5A, 0x70297EBD, 0xDFF97724, 0xFFFFFE74,
+ 0xB8E5B88F, 0xA6DFBD9F, 0xFFFFFE8F, 0x88747D94, 0xF8A95FCF, 0xFFFFFEA9,
+ 0x8FA89BCF, 0xB9447093, 0xFFFFFEC4, 0xBF0F156B, 0x8A08F0F8, 0xFFFFFEDF,
+ 0x653131B6, 0xCDB02555, 0xFFFFFEF9, 0xD07B7FAC, 0x993FE2C6, 0xFFFFFF14,
+ 0x2A2B3B06, 0xE45C10C4, 0xFFFFFF2E, 0x697392D3, 0xAA242499, 0xFFFFFF49,
+ 0x8300CA0E, 0xFD87B5F2, 0xFFFFFF63, 0x92111AEB, 0xBCE50864, 0xFFFFFF7E,
+ 0x6F5088CC, 0x8CBCCC09, 0xFFFFFF99, 0xE219652C, 0xD1B71758, 0xFFFFFFB3,
+ 0x00000000, 0x9C400000, 0xFFFFFFCE, 0x00000000, 0xE8D4A510, 0xFFFFFFE8,
+ 0xAC620000, 0xAD78EBC5, 0x00000003, 0xF8940984, 0x813F3978, 0x0000001E,
+ 0xC90715B3, 0xC097CE7B, 0x00000038, 0x7BEA5C70, 0x8F7E32CE, 0x00000053,
+ 0xABE98068, 0xD5D238A4, 0x0000006D, 0x179A2245, 0x9F4F2726, 0x00000088,
+ 0xD4C4FB27, 0xED63A231, 0x000000A2, 0x8CC8ADA8, 0xB0DE6538, 0x000000BD,
+ 0x1AAB65DB, 0x83C7088E, 0x000000D8, 0x42711D9A, 0xC45D1DF9, 0x000000F2,
+ 0xA61BE758, 0x924D692C, 0x0000010D, 0x1A708DEA, 0xDA01EE64, 0x00000127,
+ 0x9AEF774A, 0xA26DA399, 0x00000142, 0xB47D6B85, 0xF209787B, 0x0000015C,
+ 0x79DD1877, 0xB454E4A1, 0x00000177, 0x5B9BC5C2, 0x865B8692, 0x00000192,
+ 0xC8965D3D, 0xC83553C5, 0x000001AC, 0xFA97A0B3, 0x952AB45C, 0x000001C7,
+ 0x99A05FE3, 0xDE469FBD, 0x000001E1, 0xDB398C25, 0xA59BC234, 0x000001FC,
+ 0xA3989F5C, 0xF6C69A72, 0x00000216, 0x54E9BECE, 0xB7DCBF53, 0x00000231,
+ 0xF22241E2, 0x88FCF317, 0x0000024C, 0xD35C78A5, 0xCC20CE9B, 0x00000266,
+ 0x7B2153DF, 0x98165AF3, 0x00000281, 0x971F303A, 0xE2A0B5DC, 0x0000029B,
+ 0x5CE3B396, 0xA8D9D153, 0x000002B6, 0xA4A7443C, 0xFB9B7CD9, 0x000002D0,
+ 0xA7A44410, 0xBB764C4C, 0x000002EB, 0xB6409C1A, 0x8BAB8EEF, 0x00000306,
+ 0xA657842C, 0xD01FEF10, 0x00000320, 0xE9913129, 0x9B10A4E5, 0x0000033B,
+ 0xA19C0C9D, 0xE7109BFB, 0x00000355, 0x623BF429, 0xAC2820D9, 0x00000370,
+ 0x7AA7CF85, 0x80444B5E, 0x0000038B, 0x03ACDD2D, 0xBF21E440, 0x000003A5,
+ 0x5E44FF8F, 0x8E679C2F, 0x000003C0, 0x9C8CB841, 0xD433179D, 0x000003DA,
+ 0xB4E31BA9, 0x9E19DB92, 0x000003F5, 0xBADF77D9, 0xEB96BF6E, 0x0000040F,
+ 0x9BF0EE6B, 0xAF87023B, 0x0000042A,
+};
+
+// wuffs_base__private_implementation__small_powers_of_10 contains
+// approximations to the powers of 10, ranging from 1e+0 to 1e+7, with the
+// exponent stepping by 1. Each step consists of three uint32_t elements.
+//
+// For example, the third approximation, for 1e+2, consists of the uint32_t
+// triple (0x00000000, 0xC8000000, 0xFFFFFFC7). The first two of that triple
+// are a little-endian uint64_t value: 0xC800000000000000. The last one is an
+// int32_t value: -57. Together, they represent the approximation:
+// 1e+2 ≈ 0xC800000000000000 * (2 ** -57) // This approx'n is exact.
+// Similarly, the (0x00000000, 0x9C400000, 0xFFFFFFCE) uint32_t triple means:
+// 1e+4 ≈ 0x9C40000000000000 * (2 ** -50) // This approx'n is exact.
+static const uint32_t
+ wuffs_base__private_implementation__small_powers_of_10[24] = {
+ 0x00000000, 0x80000000, 0xFFFFFFC1, 0x00000000, 0xA0000000, 0xFFFFFFC4,
+ 0x00000000, 0xC8000000, 0xFFFFFFC7, 0x00000000, 0xFA000000, 0xFFFFFFCA,
+ 0x00000000, 0x9C400000, 0xFFFFFFCE, 0x00000000, 0xC3500000, 0xFFFFFFD1,
+ 0x00000000, 0xF4240000, 0xFFFFFFD4, 0x00000000, 0x98968000, 0xFFFFFFD8,
+};
+
+// wuffs_base__private_implementation__f64_powers_of_10 holds powers of 10 that
+// can be exactly represented by a float64 (what C calls a double).
+static const double wuffs_base__private_implementation__f64_powers_of_10[23] = {
+ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11,
+ 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22,
+};
+
+// --------
+
+// wuffs_base__private_implementation__medium_prec_bin (abbreviated as MPB) is
+// a fixed precision floating point binary number. Unlike IEEE 754 Floating
+// Point, it cannot represent infinity or NaN (Not a Number).
+//
+// "Medium precision" means that the mantissa holds 64 binary digits, a little
+// more than "double precision", and sizeof(MPB) > sizeof(double). 64 is
+// obviously the number of bits in a uint64_t.
+//
+// An MPB isn't for general purpose arithmetic, only for conversions to and
+// from IEEE 754 double-precision floating point.
+//
+// There is no implicit mantissa bit. The mantissa field is zero if and only if
+// the overall floating point value is ±0. An MPB is normalized if the mantissa
+// is zero or its high bit (the 1<<63 bit) is set.
+//
+// There is no negative bit. An MPB can only represent non-negative numbers.
+//
+// The "all fields are zero" value is valid, and represents the number +0.
+//
+// This is the "Do It Yourself Floating Point" data structure from Loitsch,
+// "Printing Floating-Point Numbers Quickly and Accurately with Integers"
+// (https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf).
+//
+// Florian Loitsch is also the primary contributor to
+// https://github.com/google/double-conversion
+typedef struct {
+ uint64_t mantissa;
+ int32_t exp2;
+} wuffs_base__private_implementation__medium_prec_bin;
+
+static uint32_t //
+wuffs_base__private_implementation__medium_prec_bin__normalize(
+ wuffs_base__private_implementation__medium_prec_bin* m) {
+ if (m->mantissa == 0) {
+ return 0;
+ }
+ uint32_t shift = wuffs_base__count_leading_zeroes_u64(m->mantissa);
+ m->mantissa <<= shift;
+ m->exp2 -= (int32_t)shift;
+ return shift;
+}
+
+// wuffs_base__private_implementation__medium_prec_bin__mul_pow_10 sets m to be
+// (m * pow), where pow comes from an etc_powers_of_10 triple starting at p.
+//
+// The result is rounded, but not necessarily normalized.
+//
+// Preconditions:
+// - m is non-NULL.
+// - m->mantissa is non-zero.
+// - m->mantissa's high bit is set (i.e. m is normalized).
+//
+// The etc_powers_of_10 triple is already normalized.
+static void //
+wuffs_base__private_implementation__medium_prec_bin__mul_pow_10(
+ wuffs_base__private_implementation__medium_prec_bin* m,
+ const uint32_t* p) {
+ uint64_t p_mantissa = ((uint64_t)p[0]) | (((uint64_t)p[1]) << 32);
+ int32_t p_exp2 = (int32_t)p[2];
+
+ wuffs_base__multiply_u64__output o =
+ wuffs_base__multiply_u64(m->mantissa, p_mantissa);
+ // Round the mantissa up. It cannot overflow because the maximum possible
+ // value of o.hi is 0xFFFFFFFFFFFFFFFE.
+ m->mantissa = o.hi + (o.lo >> 63);
+ m->exp2 = m->exp2 + p_exp2 + 64;
+}
+
+// wuffs_base__private_implementation__medium_prec_bin__as_f64 converts m to a
+// double (what C calls a double-precision float64).
+//
+// Preconditions:
+// - m is non-NULL.
+// - m->mantissa is non-zero.
+// - m->mantissa's high bit is set (i.e. m is normalized).
+static double //
+wuffs_base__private_implementation__medium_prec_bin__as_f64(
+ const wuffs_base__private_implementation__medium_prec_bin* m,
+ bool negative) {
+ uint64_t mantissa64 = m->mantissa;
+ // An mpb's mantissa has the implicit (binary) decimal point at the right
+ // hand end of the mantissa's explicit digits. A double-precision's mantissa
+ // has that decimal point near the left hand end. There's also an explicit
+ // versus implicit leading 1 bit (binary digit). Together, the difference in
+ // semantics corresponds to adding 63.
+ int32_t exp2 = m->exp2 + 63;
+
+ // Ensure that exp2 is at least -1022, the minimum double-precision exponent
+ // for normal (as opposed to subnormal) numbers.
+ if (-1022 > exp2) {
+ uint32_t n = (uint32_t)(-1022 - exp2);
+ mantissa64 >>= n;
+ exp2 += (int32_t)n;
+ }
+
+ // Extract the (1 + 52) bits from the 64-bit mantissa64. 52 is the number of
+ // explicit mantissa bits in a double-precision f64.
+ //
+ // Before, we have 64 bits and due to normalization, the high bit 'H' is 1.
+ // 63 55 47 etc 15 7
+ // H210_9876_5432_1098_7654_etc_etc_etc_5432_1098_7654_3210
+ // ++++_++++_++++_++++_++++_etc_etc_etc_++++_+..._...._.... Kept bits.
+ // ...._...._...H_2109_8765_etc_etc_etc_6543_2109_8765_4321 After shifting.
+ // After, we have 53 bits (and bit #52 is this 'H' bit).
+ uint64_t mantissa53 = mantissa64 >> 11;
+
+ // Round up if the old bit #10 (the highest bit dropped by shifting) was set.
+ // We also fix any overflow from rounding up.
+ if (mantissa64 & 1024) {
+ mantissa53++;
+ if ((mantissa53 >> 53) != 0) {
+ mantissa53 >>= 1;
+ exp2++;
+ }
+ }
+
+ // Handle double-precision infinity (a nominal exponent of 1024) and
+ // subnormals (an exponent of -1023 and no implicit mantissa bit, bit #52).
+ if (exp2 >= 1024) {
+ mantissa53 = 0;
+ exp2 = 1024;
+ } else if ((mantissa53 >> 52) == 0) {
+ exp2 = -1023;
+ }
+
+ // Pack the bits and return.
+ const int32_t f64_bias = -1023;
+ uint64_t exp2_bits =
+ (uint64_t)((exp2 - f64_bias) & 0x07FF); // (1 << 11) - 1.
+ uint64_t bits = (mantissa53 & 0x000FFFFFFFFFFFFF) | // (1 << 52) - 1.
+ (exp2_bits << 52) | //
+ (negative ? 0x8000000000000000 : 0); // (1 << 63).
+ return wuffs_base__ieee_754_bit_representation__to_f64(bits);
+}
+
+// wuffs_base__private_implementation__medium_prec_bin__parse_number_f64
+// converts from an HPD to a double, using an MPB as scratch space. It returns
+// a NULL status.repr if there is no ambiguity in the truncation or rounding to
+// a float64 (an IEEE 754 double-precision floating point value).
+//
+// It may modify m even if it returns a non-NULL status.repr.
+static wuffs_base__result_f64 //
+wuffs_base__private_implementation__medium_prec_bin__parse_number_f64(
+ wuffs_base__private_implementation__medium_prec_bin* m,
+ const wuffs_base__private_implementation__high_prec_dec* h,
+ bool skip_fast_path_for_tests) {
+ do {
+ // m->mantissa is a uint64_t, which is an integer approximation to a
+ // rational value - h's underlying digits after m's normalization. This
+ // error is an upper bound on the difference between the approximate and
+ // actual value.
+ //
+ // The DiyFpStrtod function in https://github.com/google/double-conversion
+ // uses a finer grain (1/8th of the ULP, Unit in the Last Place) when
+ // tracking error. This implementation is coarser (1 ULP) but simpler.
+ //
+ // It is an error in the "numerical approximation" sense, not in the
+ // typical programming sense (as in "bad input" or "a result type").
+ uint64_t error = 0;
+
+ // Convert up to 19 decimal digits (in h->digits) to 64 binary digits (in
+ // m->mantissa): (1e19 < (1<<64)) and ((1<<64) < 1e20). If we have more
+ // than 19 digits, we're truncating (with error).
+ uint32_t i;
+ uint32_t i_end = h->num_digits;
+ if (i_end > 19) {
+ i_end = 19;
+ error = 1;
+ }
+ uint64_t mantissa = 0;
+ for (i = 0; i < i_end; i++) {
+ mantissa = (10 * mantissa) + h->digits[i];
+ }
+ m->mantissa = mantissa;
+ m->exp2 = 0;
+
+ // Check that exp10 lies in the (big_powers_of_10 + small_powers_of_10)
+ // range, -348 ..= +347, stepping big_powers_of_10 by 8 (which is 87
+ // triples) and small_powers_of_10 by 1 (which is 8 triples).
+ int32_t exp10 = h->decimal_point - ((int32_t)(i_end));
+ if (exp10 < -348) {
+ goto fail;
+ }
+ uint32_t bpo10 = ((uint32_t)(exp10 + 348)) / 8;
+ uint32_t spo10 = ((uint32_t)(exp10 + 348)) % 8;
+ if (bpo10 >= 87) {
+ goto fail;
+ }
+
+ // Try a fast path, if float64 math would be exact.
+ //
+ // 15 is such that 1e15 can be losslessly represented in a float64
+ // mantissa: (1e15 < (1<<53)) and ((1<<53) < 1e16).
+ //
+ // 22 is the maximum valid index for the
+ // wuffs_base__private_implementation__f64_powers_of_10 array.
+ do {
+ if (skip_fast_path_for_tests || ((mantissa >> 52) != 0)) {
+ break;
+ }
+ double d = (double)mantissa;
+
+ if (exp10 == 0) {
+ wuffs_base__result_f64 ret;
+ ret.status.repr = NULL;
+ ret.value = h->negative ? -d : +d;
+ return ret;
+
+ } else if (exp10 > 0) {
+ if (exp10 > 22) {
+ if (exp10 > (15 + 22)) {
+ break;
+ }
+ // If exp10 is in the range 23 ..= 37, try moving a few of the zeroes
+ // from the exponent to the mantissa. If we're still under 1e15, we
+ // haven't truncated any mantissa bits.
+ if (exp10 > 22) {
+ d *= wuffs_base__private_implementation__f64_powers_of_10[exp10 -
+ 22];
+ exp10 = 22;
+ if (d >= 1e15) {
+ break;
+ }
+ }
+ }
+ d *= wuffs_base__private_implementation__f64_powers_of_10[exp10];
+ wuffs_base__result_f64 ret;
+ ret.status.repr = NULL;
+ ret.value = h->negative ? -d : +d;
+ return ret;
+
+ } else { // "if (exp10 < 0)" is effectively "if (true)" here.
+ if (exp10 < -22) {
+ break;
+ }
+ d /= wuffs_base__private_implementation__f64_powers_of_10[-exp10];
+ wuffs_base__result_f64 ret;
+ ret.status.repr = NULL;
+ ret.value = h->negative ? -d : +d;
+ return ret;
+ }
+ } while (0);
+
+ // Normalize (and scale the error).
+ error <<= wuffs_base__private_implementation__medium_prec_bin__normalize(m);
+
+ // Multiplying two MPB values nominally multiplies two mantissas, call them
+ // A and B, which are integer approximations to the precise values (A+a)
+ // and (B+b) for some error terms a and b.
+ //
+ // MPB multiplication calculates (((A+a) * (B+b)) >> 64) to be ((A*B) >>
+ // 64). Shifting (truncating) and rounding introduces further error. The
+ // difference between the calculated result:
+ // ((A*B ) >> 64)
+ // and the true result:
+ // ((A*B + A*b + a*B + a*b) >> 64) + rounding_error
+ // is:
+ // (( A*b + a*B + a*b) >> 64) + rounding_error
+ // which can be re-grouped as:
+ // ((A*b) >> 64) + ((a*(B+b)) >> 64) + rounding_error
+ //
+ // Now, let A and a be "m->mantissa" and "error", and B and b be the
+ // pre-calculated power of 10. A and B are both less than (1 << 64), a is
+ // the "error" local variable and b is less than 1.
+ //
+ // An upper bound (in absolute value) on ((A*b) >> 64) is therefore 1.
+ //
+ // An upper bound on ((a*(B+b)) >> 64) is a, also known as error.
+ //
+ // Finally, the rounding_error is at most 1.
+ //
+ // In total, calling mpb__mul_pow_10 will raise the worst-case error by 2.
+ // The subsequent re-normalization can multiply that by a further factor.
+
+ // Multiply by small_powers_of_10[etc].
+ wuffs_base__private_implementation__medium_prec_bin__mul_pow_10(
+ m, &wuffs_base__private_implementation__small_powers_of_10[3 * spo10]);
+ error += 2;
+ error <<= wuffs_base__private_implementation__medium_prec_bin__normalize(m);
+
+ // Multiply by big_powers_of_10[etc].
+ wuffs_base__private_implementation__medium_prec_bin__mul_pow_10(
+ m, &wuffs_base__private_implementation__big_powers_of_10[3 * bpo10]);
+ error += 2;
+ error <<= wuffs_base__private_implementation__medium_prec_bin__normalize(m);
+
+ // We have a good approximation of h, but we still have to check whether
+ // the error is small enough. Equivalently, whether the number of surplus
+ // mantissa bits (the bits dropped when going from m's 64 mantissa bits to
+ // the smaller number of double-precision mantissa bits) would always round
+ // up or down, even when perturbed by ±error. We start at 11 surplus bits
+ // (m has 64, double-precision has 1+52), but it can be higher for
+ // subnormals.
+ //
+ // In many cases, the error is small enough and we return true.
+ const int32_t f64_bias = -1023;
+ int32_t subnormal_exp2 = f64_bias - 63;
+ uint32_t surplus_bits = 11;
+ if (subnormal_exp2 >= m->exp2) {
+ surplus_bits += 1 + ((uint32_t)(subnormal_exp2 - m->exp2));
+ }
+
+ uint64_t surplus_mask =
+ (((uint64_t)1) << surplus_bits) - 1; // e.g. 0x07FF.
+ uint64_t surplus = m->mantissa & surplus_mask;
+ uint64_t halfway = ((uint64_t)1) << (surplus_bits - 1); // e.g. 0x0400.
+
+ // Do the final calculation in *signed* arithmetic.
+ int64_t i_surplus = (int64_t)surplus;
+ int64_t i_halfway = (int64_t)halfway;
+ int64_t i_error = (int64_t)error;
+
+ if ((i_surplus > (i_halfway - i_error)) &&
+ (i_surplus < (i_halfway + i_error))) {
+ goto fail;
+ }
+
+ wuffs_base__result_f64 ret;
+ ret.status.repr = NULL;
+ ret.value = wuffs_base__private_implementation__medium_prec_bin__as_f64(
+ m, h->negative);
+ return ret;
+ } while (0);
+
+fail:
+ do {
+ wuffs_base__result_f64 ret;
+ ret.status.repr = "#base: mpb__parse_number_f64 failed";
+ ret.value = 0;
+ return ret;
+ } while (0);
+}
+
+// --------
+
wuffs_base__result_f64 //
wuffs_base__parse_number_f64_special(wuffs_base__slice_u8 s,
const char* fallback_status_repr) {
@@ -9391,6 +10106,7 @@
wuffs_base__result_f64 //
wuffs_base__parse_number_f64(wuffs_base__slice_u8 s) {
+ wuffs_base__private_implementation__medium_prec_bin m;
wuffs_base__private_implementation__high_prec_dec h;
do {
@@ -9417,10 +10133,17 @@
goto infinity;
}
+ wuffs_base__result_f64 mpb_result =
+ wuffs_base__private_implementation__medium_prec_bin__parse_number_f64(
+ &m, &h, false);
+ if (mpb_result.status.repr == NULL) {
+ return mpb_result;
+ }
+
// Scale by powers of 2 until we're in the range [½ .. 1], which gives us
// our exponent (in base-2). First we shift right, possibly a little too
// far, ending with a value certainly below 1 and possibly below ½...
- const int32_t bias = -1023;
+ const int32_t f64_bias = -1023;
int32_t exp2 = 0;
while (h.decimal_point > 0) {
uint32_t n = (uint32_t)(+h.decimal_point);
@@ -9464,9 +10187,9 @@
// We're in the range [½ .. 1] but f64 uses [1 .. 2].
exp2--;
- // The minimum normal exponent is (bias + 1).
- while ((bias + 1) > exp2) {
- uint32_t n = (uint32_t)((bias + 1) - exp2);
+ // The minimum normal exponent is (f64_bias + 1).
+ while ((f64_bias + 1) > exp2) {
+ uint32_t n = (uint32_t)((f64_bias + 1) - exp2);
if (n > WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL) {
n = WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL;
}
@@ -9475,7 +10198,7 @@
}
// Check for overflow.
- if ((exp2 - bias) >= 0x07FF) { // (1 << 11) - 1.
+ if ((exp2 - f64_bias) >= 0x07FF) { // (1 << 11) - 1.
goto infinity;
}
@@ -9488,21 +10211,22 @@
if ((man2 >> 53) != 0) {
man2 >>= 1;
exp2++;
- if ((exp2 - bias) >= 0x07FF) { // (1 << 11) - 1.
+ if ((exp2 - f64_bias) >= 0x07FF) { // (1 << 11) - 1.
goto infinity;
}
}
// Handle subnormal numbers.
if ((man2 >> 52) == 0) {
- exp2 = bias;
+ exp2 = f64_bias;
}
// Pack the bits and return.
- uint64_t exp2_bits = (uint64_t)((exp2 - bias) & 0x07FF); // (1 << 11) - 1.
- uint64_t bits = (man2 & 0x000FFFFFFFFFFFFF) | // (1 << 52) - 1.
- (exp2_bits << 52) | //
- (h.negative ? 0x8000000000000000 : 0); // (1 << 63).
+ uint64_t exp2_bits =
+ (uint64_t)((exp2 - f64_bias) & 0x07FF); // (1 << 11) - 1.
+ uint64_t bits = (man2 & 0x000FFFFFFFFFFFFF) | // (1 << 52) - 1.
+ (exp2_bits << 52) | //
+ (h.negative ? 0x8000000000000000 : 0); // (1 << 63).
wuffs_base__result_f64 ret;
ret.status.repr = NULL;
@@ -9531,6 +10255,46 @@
} while (0);
}
+// ---------------- Hexadecimal
+
+size_t //
+wuffs_base__hexadecimal__decode2(wuffs_base__slice_u8 dst,
+ wuffs_base__slice_u8 src) {
+ size_t src_len2 = src.len / 2;
+ size_t len = dst.len < src_len2 ? dst.len : src_len2;
+ uint8_t* d = dst.ptr;
+ uint8_t* s = src.ptr;
+ size_t n = len;
+
+ while (n--) {
+ *d = (uint8_t)((wuffs_base__parse_number__hexadecimal_digits[s[0]] << 4) |
+ (wuffs_base__parse_number__hexadecimal_digits[s[1]] & 0x0F));
+ d += 1;
+ s += 2;
+ }
+
+ return len;
+}
+
+size_t //
+wuffs_base__hexadecimal__decode4(wuffs_base__slice_u8 dst,
+ wuffs_base__slice_u8 src) {
+ size_t src_len4 = src.len / 4;
+ size_t len = dst.len < src_len4 ? dst.len : src_len4;
+ uint8_t* d = dst.ptr;
+ uint8_t* s = src.ptr;
+ size_t n = len;
+
+ while (n--) {
+ *d = (uint8_t)((wuffs_base__parse_number__hexadecimal_digits[s[2]] << 4) |
+ (wuffs_base__parse_number__hexadecimal_digits[s[3]] & 0x0F));
+ d += 1;
+ s += 4;
+ }
+
+ return len;
+}
+
// ---------------- Unicode and UTF-8
size_t //
@@ -10611,8 +11375,6 @@
}
uint32_t coro_susp_point = self->private_impl.p_decode_frame_config[0];
- if (coro_susp_point) {
- }
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
@@ -11011,8 +11773,6 @@
}
uint32_t coro_susp_point = self->private_impl.p_skip_frame[0];
- if (coro_susp_point) {
- }
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
@@ -12628,8 +13388,6 @@
}
uint32_t coro_susp_point = self->private_impl.p_transform_io[0];
- if (coro_susp_point) {
- }
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
@@ -14429,8 +15187,6 @@
uint32_t v_i = 0;
uint32_t coro_susp_point = self->private_impl.p_transform_io[0];
- if (coro_susp_point) {
- }
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
@@ -14724,8 +15480,6 @@
}
uint32_t coro_susp_point = self->private_impl.p_write_to[0];
- if (coro_susp_point) {
- }
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
@@ -15214,8 +15968,6 @@
bool v_ffio = false;
uint32_t coro_susp_point = self->private_impl.p_decode_image_config[0];
- if (coro_susp_point) {
- }
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
@@ -15342,8 +16094,6 @@
}
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;
@@ -15737,8 +16487,6 @@
}
uint32_t coro_susp_point = self->private_impl.p_skip_frame[0];
- if (coro_susp_point) {
- }
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
@@ -15895,8 +16643,6 @@
}
uint32_t coro_susp_point = self->private_impl.p_decode_up_to_id_part1[0];
- if (coro_susp_point) {
- }
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
@@ -16299,8 +17045,6 @@
}
uint32_t coro_susp_point = self->private_impl.p_decode_extension[0];
- if (coro_susp_point) {
- }
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
@@ -16395,8 +17139,6 @@
}
uint32_t coro_susp_point = self->private_impl.p_skip_blocks[0];
- if (coro_susp_point) {
- }
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
@@ -16509,7 +17251,7 @@
goto suspend;
}
iop_a_src += self->private_data.s_decode_ae[0].scratch;
- goto label__0__break;
+ goto label__goto_done__break;
}
v_is_animexts = true;
v_is_netscape = true;
@@ -16568,7 +17310,7 @@
goto suspend;
}
iop_a_src += self->private_data.s_decode_ae[0].scratch;
- goto label__0__break;
+ goto label__goto_done__break;
}
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(6);
@@ -16593,7 +17335,7 @@
goto suspend;
}
iop_a_src += self->private_data.s_decode_ae[0].scratch;
- goto label__0__break;
+ goto label__goto_done__break;
}
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(8);
@@ -16669,9 +17411,9 @@
status = wuffs_base__make_status(wuffs_base__note__metadata_reported);
goto ok;
}
- goto label__0__break;
+ goto label__goto_done__break;
}
- label__0__break:;
+ label__goto_done__break:;
if (a_src) {
a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
@@ -16732,8 +17474,6 @@
}
uint32_t coro_susp_point = self->private_impl.p_decode_gc[0];
- if (coro_susp_point) {
- }
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
@@ -16862,8 +17602,6 @@
}
uint32_t coro_susp_point = self->private_impl.p_decode_id_part0[0];
- if (coro_susp_point) {
- }
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
@@ -17083,8 +17821,6 @@
bool v_ffio = false;
uint32_t coro_susp_point = self->private_impl.p_decode_image_config[0];
- if (coro_susp_point) {
- }
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
@@ -17211,8 +17947,6 @@
}
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;
@@ -17608,8 +18342,6 @@
}
uint32_t coro_susp_point = self->private_impl.p_skip_frame[0];
- if (coro_susp_point) {
- }
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
@@ -17720,8 +18452,6 @@
wuffs_base__status status = wuffs_base__make_status(NULL);
uint32_t coro_susp_point = self->private_impl.p_decode_frame[0];
- if (coro_susp_point) {
- }
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
@@ -17809,8 +18539,6 @@
}
uint32_t coro_susp_point = self->private_impl.p_decode_up_to_id_part1[0];
- if (coro_susp_point) {
- }
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
@@ -18213,8 +18941,6 @@
}
uint32_t coro_susp_point = self->private_impl.p_decode_extension[0];
- if (coro_susp_point) {
- }
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
@@ -18309,8 +19035,6 @@
}
uint32_t coro_susp_point = self->private_impl.p_skip_blocks[0];
- if (coro_susp_point) {
- }
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
@@ -18423,7 +19147,7 @@
goto suspend;
}
iop_a_src += self->private_data.s_decode_ae[0].scratch;
- goto label__0__break;
+ goto label__goto_done__break;
}
v_is_animexts = true;
v_is_netscape = true;
@@ -18482,7 +19206,7 @@
goto suspend;
}
iop_a_src += self->private_data.s_decode_ae[0].scratch;
- goto label__0__break;
+ goto label__goto_done__break;
}
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(6);
@@ -18507,7 +19231,7 @@
goto suspend;
}
iop_a_src += self->private_data.s_decode_ae[0].scratch;
- goto label__0__break;
+ goto label__goto_done__break;
}
{
WUFFS_BASE__COROUTINE_SUSPENSION_POINT(8);
@@ -18583,9 +19307,9 @@
status = wuffs_base__make_status(wuffs_base__note__metadata_reported);
goto ok;
}
- goto label__0__break;
+ goto label__goto_done__break;
}
- label__0__break:;
+ label__goto_done__break:;
if (a_src) {
a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
}
@@ -18646,8 +19370,6 @@
}
uint32_t coro_susp_point = self->private_impl.p_decode_gc[0];
- if (coro_susp_point) {
- }
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
@@ -18776,8 +19498,6 @@
}
uint32_t coro_susp_point = self->private_impl.p_decode_id_part0[0];
- if (coro_susp_point) {
- }
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
@@ -20063,11 +20783,11 @@
WUFFS_BASE__POTENTIALLY_UNUSED = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 162, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 175, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 4, 0, 0, 0, 0, 0, 0, 0, 175, 6, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 0,
- 0, 0, 0, 136, 0, 0, 0, 140, 0, 0, 0, 0, 0, 0, 0, 138, 0, 0, 0,
- 141, 0, 137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 136, 0, 0, 2, 140, 0, 0, 0, 0, 0, 0, 0, 138, 0, 0, 0,
+ 141, 0, 137, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -20077,6 +20797,12 @@
0, 0, 0, 0, 0, 0, 0, 0, 0,
};
+static const uint8_t //
+ wuffs_json__lut_quirky_backslashes[8] //
+ WUFFS_BASE__POTENTIALLY_UNUSED = {
+ 0, 7, 27, 63, 39, 11, 0, 0,
+};
+
static const uint8_t //
wuffs_json__lut_chars[256] //
WUFFS_BASE__POTENTIALLY_UNUSED = {
@@ -20106,10 +20832,10 @@
WUFFS_BASE__POTENTIALLY_UNUSED = {
15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 15, 15, 0, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 1, 15,
- 15, 15, 15, 15, 15, 15, 15, 15, 2, 4, 15, 15, 4, 4, 4, 4, 4, 4,
+ 15, 15, 15, 15, 15, 15, 15, 11, 2, 4, 15, 12, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 3, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 7, 15, 8, 15, 15, 15, 15, 15, 15, 15, 15, 9, 15, 15, 15, 15, 15,
+ 15, 11, 15, 15, 15, 15, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 7, 15, 8, 15, 15, 15, 15, 15, 15, 15, 15, 9, 15, 15, 11, 15, 15,
15, 15, 11, 15, 15, 15, 15, 15, 10, 15, 15, 15, 15, 15, 15, 5, 15, 6,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
@@ -20176,14 +20902,37 @@
wuffs_base__io_buffer* a_src,
uint32_t a_n);
+static wuffs_base__status //
+wuffs_json__decoder__decode_leading(wuffs_json__decoder* self,
+ wuffs_base__token_buffer* a_dst,
+ wuffs_base__io_buffer* a_src);
+
+static wuffs_base__status //
+wuffs_json__decoder__decode_comment(wuffs_json__decoder* self,
+ wuffs_base__token_buffer* a_dst,
+ wuffs_base__io_buffer* a_src);
+
+static wuffs_base__status //
+wuffs_json__decoder__decode_inf_nan(wuffs_json__decoder* self,
+ wuffs_base__token_buffer* a_dst,
+ wuffs_base__io_buffer* a_src);
+
+static wuffs_base__status //
+wuffs_json__decoder__decode_trailing_new_line(wuffs_json__decoder* self,
+ wuffs_base__token_buffer* a_dst,
+ wuffs_base__io_buffer* a_src);
+
// ---------------- VTables
const wuffs_base__token_decoder__func_ptrs
wuffs_json__decoder__func_ptrs_for__wuffs_base__token_decoder = {
(wuffs_base__status(*)(void*,
wuffs_base__token_buffer*,
- wuffs_base__io_buffer*))(
+ wuffs_base__io_buffer*,
+ wuffs_base__slice_u8))(
&wuffs_json__decoder__decode_tokens),
+ (wuffs_base__range_ii_u64(*)(const void*))(
+ &wuffs_json__decoder__workbuf_len),
};
// ---------------- Initializer Implementations
@@ -20243,12 +20992,79 @@
// ---------------- Function Implementations
+// -------- func json.decoder.set_quirk_enabled
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__empty_struct //
+wuffs_json__decoder__set_quirk_enabled(wuffs_json__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 (a_quirk == 1225364480) {
+ self->private_impl.f_quirk_enabled_allow_backslash_etc[1] = a_enabled;
+ } else if (a_quirk == 1225364481) {
+ self->private_impl.f_quirk_enabled_allow_backslash_capital_u = a_enabled;
+ } else if (a_quirk == 1225364482) {
+ self->private_impl.f_quirk_enabled_allow_backslash_etc[2] = a_enabled;
+ } else if (a_quirk == 1225364483) {
+ self->private_impl.f_quirk_enabled_allow_backslash_etc[3] = a_enabled;
+ } else if (a_quirk == 1225364484) {
+ self->private_impl.f_quirk_enabled_allow_backslash_etc[4] = a_enabled;
+ } else if (a_quirk == 1225364485) {
+ self->private_impl.f_quirk_enabled_allow_backslash_etc[5] = a_enabled;
+ } else if (a_quirk == 1225364486) {
+ self->private_impl.f_quirk_enabled_allow_backslash_x = a_enabled;
+ } else if (a_quirk == 1225364487) {
+ self->private_impl.f_quirk_enabled_allow_backslash_etc[6] = a_enabled;
+ } else if (a_quirk == 1225364488) {
+ self->private_impl.f_quirk_enabled_allow_comment_block = a_enabled;
+ } else if (a_quirk == 1225364489) {
+ self->private_impl.f_quirk_enabled_allow_comment_line = a_enabled;
+ } else if (a_quirk == 1225364490) {
+ self->private_impl.f_quirk_enabled_allow_extra_comma = a_enabled;
+ } else if (a_quirk == 1225364491) {
+ self->private_impl.f_quirk_enabled_allow_inf_nan_numbers = a_enabled;
+ } else if (a_quirk == 1225364492) {
+ self->private_impl.f_quirk_enabled_allow_leading_ascii_record_separator =
+ a_enabled;
+ } else if (a_quirk == 1225364493) {
+ self->private_impl.f_quirk_enabled_allow_leading_unicode_byte_order_mark =
+ a_enabled;
+ } else if (a_quirk == 1225364494) {
+ self->private_impl.f_quirk_enabled_allow_trailing_new_line = a_enabled;
+ } else if (a_quirk == 1225364495) {
+ self->private_impl.f_quirk_enabled_replace_invalid_unicode = a_enabled;
+ }
+ return wuffs_base__make_empty_struct();
+}
+
+// -------- func json.decoder.workbuf_len
+
+WUFFS_BASE__MAYBE_STATIC wuffs_base__range_ii_u64 //
+wuffs_json__decoder__workbuf_len(const wuffs_json__decoder* self) {
+ if (!self) {
+ return wuffs_base__utility__empty_range_ii_u64();
+ }
+ if ((self->private_impl.magic != WUFFS_BASE__MAGIC) &&
+ (self->private_impl.magic != WUFFS_BASE__DISABLED)) {
+ return wuffs_base__utility__empty_range_ii_u64();
+ }
+
+ return wuffs_base__utility__empty_range_ii_u64();
+}
+
// -------- func json.decoder.decode_tokens
WUFFS_BASE__MAYBE_STATIC wuffs_base__status //
wuffs_json__decoder__decode_tokens(wuffs_json__decoder* self,
wuffs_base__token_buffer* a_dst,
- wuffs_base__io_buffer* a_src) {
+ wuffs_base__io_buffer* a_src,
+ wuffs_base__slice_u8 a_workbuf) {
if (!self) {
return wuffs_base__make_status(wuffs_base__error__bad_receiver);
}
@@ -20280,17 +21096,22 @@
uint32_t v_stack_byte = 0;
uint32_t v_stack_bit = 0;
uint32_t v_match = 0;
- uint32_t v_c_by_4 = 0;
+ uint32_t v_c4 = 0;
uint8_t v_c = 0;
uint8_t v_backslash = 0;
uint8_t v_char = 0;
uint8_t v_class = 0;
uint32_t v_multi_byte_utf8 = 0;
+ uint32_t v_backslash_x_length = 0;
+ uint8_t v_backslash_x_ok = 0;
+ uint32_t v_backslash_x_string = 0;
uint8_t v_uni4_ok = 0;
uint64_t v_uni4_string = 0;
uint32_t v_uni4_value = 0;
uint32_t v_uni4_high_surrogate = 0;
- uint32_t v_uni4_rollback = 0;
+ uint8_t v_uni8_ok = 0;
+ uint64_t v_uni8_string = 0;
+ uint32_t v_uni8_value = 0;
uint32_t v_expect = 0;
uint32_t v_expect_after_value = 0;
@@ -20328,13 +21149,39 @@
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
- v_expect = 3762;
+ while (self->private_impl.f_end_of_data) {
+ status = wuffs_base__make_status(wuffs_base__note__end_of_data);
+ goto ok;
+ }
+ if (self->private_impl
+ .f_quirk_enabled_allow_leading_ascii_record_separator ||
+ self->private_impl
+ .f_quirk_enabled_allow_leading_unicode_byte_order_mark) {
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
+ }
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(1);
+ status = wuffs_json__decoder__decode_leading(self, a_dst, a_src);
+ if (a_dst) {
+ iop_a_dst = a_dst->data.ptr + a_dst->meta.wi;
+ }
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
+ }
+ if (status.repr) {
+ goto suspend;
+ }
+ }
+ v_expect = 7858;
label__outer__continue:;
while (true) {
while (true) {
if (((uint64_t)(io2_a_dst - iop_a_dst)) <= 0) {
status = wuffs_base__make_status(wuffs_base__suspension__short_write);
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(1);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(2);
goto label__outer__continue;
}
v_whitespace_length = 0;
@@ -20355,7 +21202,7 @@
}
status =
wuffs_base__make_status(wuffs_base__suspension__short_read);
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(2);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(3);
v_whitespace_length = 0;
goto label__outer__continue;
}
@@ -20400,7 +21247,7 @@
if (((uint64_t)(io2_a_dst - iop_a_dst)) <= 0) {
status =
wuffs_base__make_status(wuffs_base__suspension__short_write);
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(3);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(4);
goto label__string_loop_outer__continue;
}
v_string_length = 0;
@@ -20423,16 +21270,16 @@
}
status =
wuffs_base__make_status(wuffs_base__suspension__short_read);
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(4);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(5);
v_string_length = 0;
goto label__string_loop_outer__continue;
}
while (((uint64_t)(io2_a_src - iop_a_src)) > 4) {
- v_c_by_4 = wuffs_base__load_u32le__no_bounds_check(iop_a_src);
- if (0 != (wuffs_json__lut_chars[(255 & (v_c_by_4 >> 0))] |
- wuffs_json__lut_chars[(255 & (v_c_by_4 >> 8))] |
- wuffs_json__lut_chars[(255 & (v_c_by_4 >> 16))] |
- wuffs_json__lut_chars[(255 & (v_c_by_4 >> 24))])) {
+ v_c4 = wuffs_base__load_u32le__no_bounds_check(iop_a_src);
+ if (0 != (wuffs_json__lut_chars[(255 & (v_c4 >> 0))] |
+ wuffs_json__lut_chars[(255 & (v_c4 >> 8))] |
+ wuffs_json__lut_chars[(255 & (v_c4 >> 16))] |
+ wuffs_json__lut_chars[(255 & (v_c4 >> 24))])) {
goto label__0__break;
}
(iop_a_src += 4, wuffs_base__make_empty_struct());
@@ -20497,7 +21344,7 @@
}
status = wuffs_base__make_status(
wuffs_base__suspension__short_read);
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(5);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(6);
v_string_length = 0;
v_char = 0;
goto label__string_loop_outer__continue;
@@ -20505,7 +21352,7 @@
v_c = ((uint8_t)(
(wuffs_base__load_u16le__no_bounds_check(iop_a_src) >> 8)));
v_backslash = wuffs_json__lut_backslashes[v_c];
- if (v_backslash > 0) {
+ if ((v_backslash & 128) != 0) {
(iop_a_src += 2, wuffs_base__make_empty_struct());
*iop_a_dst++ = wuffs_base__make_token(
(((uint64_t)(
@@ -20514,6 +21361,20 @@
(((uint64_t)(3)) << WUFFS_BASE__TOKEN__LINK__SHIFT) |
(((uint64_t)(2)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
goto label__string_loop_outer__continue;
+ } else if (v_backslash != 0) {
+ if (self->private_impl.f_quirk_enabled_allow_backslash_etc[(
+ v_backslash & 7)]) {
+ (iop_a_src += 2, wuffs_base__make_empty_struct());
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)(
+ (6291456 |
+ ((uint32_t)(wuffs_json__lut_quirky_backslashes[(
+ v_backslash & 7)])))))
+ << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)(3)) << WUFFS_BASE__TOKEN__LINK__SHIFT) |
+ (((uint64_t)(2)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ goto label__string_loop_outer__continue;
+ }
} else if (v_c == 117) {
if (((uint64_t)(io2_a_src - iop_a_src)) < 6) {
if (a_src && a_src->meta.closed) {
@@ -20523,7 +21384,7 @@
}
status = wuffs_base__make_status(
wuffs_base__suspension__short_read);
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(6);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(7);
v_string_length = 0;
v_char = 0;
goto label__string_loop_outer__continue;
@@ -20563,22 +21424,33 @@
} else {
if (((uint64_t)(io2_a_src - iop_a_src)) < 12) {
if (a_src && a_src->meta.closed) {
+ if (self->private_impl
+ .f_quirk_enabled_replace_invalid_unicode) {
+ (iop_a_src += 6, wuffs_base__make_empty_struct());
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)(6356989))
+ << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)(3))
+ << WUFFS_BASE__TOKEN__LINK__SHIFT) |
+ (((uint64_t)(6))
+ << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ goto label__string_loop_outer__continue;
+ }
status = wuffs_base__make_status(
wuffs_json__error__bad_backslash_escape);
goto exit;
}
status = wuffs_base__make_status(
wuffs_base__suspension__short_read);
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(7);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(8);
v_string_length = 0;
v_uni4_value = 0;
v_char = 0;
goto label__string_loop_outer__continue;
}
- (iop_a_src += 4, wuffs_base__make_empty_struct());
- v_uni4_string =
- (wuffs_base__load_u64le__no_bounds_check(iop_a_src) >>
- 16);
+ v_uni4_string = (wuffs_base__load_u64le__no_bounds_check(
+ iop_a_src + 4) >>
+ 16);
if (((255 & (v_uni4_string >> 0)) != 92) ||
((255 & (v_uni4_string >> 8)) != 117)) {
v_uni4_high_surrogate = 0;
@@ -20610,7 +21482,7 @@
if ((v_uni4_ok != 0) && (56320 <= v_uni4_value) &&
(v_uni4_value <= 57343)) {
v_uni4_value -= 56320;
- (iop_a_src += 8, wuffs_base__make_empty_struct());
+ (iop_a_src += 12, wuffs_base__make_empty_struct());
*iop_a_dst++ = wuffs_base__make_token(
(((uint64_t)((6291456 | v_uni4_high_surrogate |
v_uni4_value)))
@@ -20619,20 +21491,144 @@
(((uint64_t)(12))
<< WUFFS_BASE__TOKEN__LENGTH__SHIFT));
goto label__string_loop_outer__continue;
- } else {
- v_uni4_rollback = 4;
- while (v_uni4_rollback > 0) {
- v_uni4_rollback -= 1;
- if (iop_a_src > io1_a_src) {
- (iop_a_src--, wuffs_base__make_empty_struct());
- } else {
- status = wuffs_base__make_status(
- wuffs_json__error__internal_error_inconsistent_i_o);
- goto exit;
- }
- }
}
}
+ if (self->private_impl
+ .f_quirk_enabled_replace_invalid_unicode) {
+ if (((uint64_t)(io2_a_src - iop_a_src)) < 6) {
+ status = wuffs_base__make_status(
+ wuffs_json__error__internal_error_inconsistent_i_o);
+ goto exit;
+ }
+ (iop_a_src += 6, wuffs_base__make_empty_struct());
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)(6356989))
+ << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)(3)) << WUFFS_BASE__TOKEN__LINK__SHIFT) |
+ (((uint64_t)(6)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ goto label__string_loop_outer__continue;
+ }
+ } else if ((v_c == 85) &&
+ self->private_impl
+ .f_quirk_enabled_allow_backslash_capital_u) {
+ if (((uint64_t)(io2_a_src - iop_a_src)) < 10) {
+ if (a_src && a_src->meta.closed) {
+ status = wuffs_base__make_status(
+ wuffs_json__error__bad_backslash_escape);
+ goto exit;
+ }
+ status = wuffs_base__make_status(
+ wuffs_base__suspension__short_read);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(9);
+ v_string_length = 0;
+ v_char = 0;
+ goto label__string_loop_outer__continue;
+ }
+ v_uni8_string =
+ wuffs_base__load_u64le__no_bounds_check(iop_a_src + 2);
+ v_uni8_value = 0;
+ v_uni8_ok = 128;
+ v_c = wuffs_json__lut_hexadecimal_digits[(
+ 255 & (v_uni8_string >> 0))];
+ v_uni8_ok &= v_c;
+ v_uni8_value |= (((uint32_t)((v_c & 15))) << 28);
+ v_c = wuffs_json__lut_hexadecimal_digits[(
+ 255 & (v_uni8_string >> 8))];
+ v_uni8_ok &= v_c;
+ v_uni8_value |= (((uint32_t)((v_c & 15))) << 24);
+ v_c = wuffs_json__lut_hexadecimal_digits[(
+ 255 & (v_uni8_string >> 16))];
+ v_uni8_ok &= v_c;
+ v_uni8_value |= (((uint32_t)((v_c & 15))) << 20);
+ v_c = wuffs_json__lut_hexadecimal_digits[(
+ 255 & (v_uni8_string >> 24))];
+ v_uni8_ok &= v_c;
+ v_uni8_value |= (((uint32_t)((v_c & 15))) << 16);
+ v_c = wuffs_json__lut_hexadecimal_digits[(
+ 255 & (v_uni8_string >> 32))];
+ v_uni8_ok &= v_c;
+ v_uni8_value |= (((uint32_t)((v_c & 15))) << 12);
+ v_c = wuffs_json__lut_hexadecimal_digits[(
+ 255 & (v_uni8_string >> 40))];
+ v_uni8_ok &= v_c;
+ v_uni8_value |= (((uint32_t)((v_c & 15))) << 8);
+ v_c = wuffs_json__lut_hexadecimal_digits[(
+ 255 & (v_uni8_string >> 48))];
+ v_uni8_ok &= v_c;
+ v_uni8_value |= (((uint32_t)((v_c & 15))) << 4);
+ v_c = wuffs_json__lut_hexadecimal_digits[(
+ 255 & (v_uni8_string >> 56))];
+ v_uni8_ok &= v_c;
+ v_uni8_value |= (((uint32_t)((v_c & 15))) << 0);
+ if (v_uni8_ok == 0) {
+ } else if ((v_uni8_value < 55296) ||
+ ((57343 < v_uni8_value) &&
+ (v_uni8_value <= 1114111))) {
+ (iop_a_src += 10, wuffs_base__make_empty_struct());
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)((6291456 | (v_uni8_value & 2097151))))
+ << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)(3)) << WUFFS_BASE__TOKEN__LINK__SHIFT) |
+ (((uint64_t)(10)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ goto label__string_loop_outer__continue;
+ } else if (self->private_impl
+ .f_quirk_enabled_replace_invalid_unicode) {
+ (iop_a_src += 10, wuffs_base__make_empty_struct());
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)(6356989))
+ << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)(3)) << WUFFS_BASE__TOKEN__LINK__SHIFT) |
+ (((uint64_t)(10)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ goto label__string_loop_outer__continue;
+ }
+ } else if ((v_c == 120) &&
+ self->private_impl
+ .f_quirk_enabled_allow_backslash_x) {
+ if (((uint64_t)(io2_a_src - iop_a_src)) < 4) {
+ if (a_src && a_src->meta.closed) {
+ status = wuffs_base__make_status(
+ wuffs_json__error__bad_backslash_escape);
+ goto exit;
+ }
+ status = wuffs_base__make_status(
+ wuffs_base__suspension__short_read);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(10);
+ v_string_length = 0;
+ v_char = 0;
+ goto label__string_loop_outer__continue;
+ }
+ v_backslash_x_length = 0;
+ while ((v_backslash_x_length <= 65531) &&
+ (((uint64_t)(io2_a_src - iop_a_src)) >= 4)) {
+ v_backslash_x_string =
+ wuffs_base__load_u32le__no_bounds_check(iop_a_src);
+ v_backslash_x_ok = 128;
+ v_c = wuffs_json__lut_hexadecimal_digits[(
+ 255 & (v_backslash_x_string >> 16))];
+ v_backslash_x_ok &= v_c;
+ v_c = wuffs_json__lut_hexadecimal_digits[(
+ 255 & (v_backslash_x_string >> 24))];
+ v_backslash_x_ok &= v_c;
+ if ((v_backslash_x_ok == 0) ||
+ ((v_backslash_x_string & 65535) != 30812)) {
+ goto label__1__break;
+ }
+ (iop_a_src += 4, wuffs_base__make_empty_struct());
+ v_backslash_x_length += 4;
+ }
+ label__1__break:;
+ if (v_backslash_x_length == 0) {
+ status = wuffs_base__make_status(
+ wuffs_json__error__bad_backslash_escape);
+ goto exit;
+ }
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)(4194432))
+ << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)(3)) << WUFFS_BASE__TOKEN__LINK__SHIFT) |
+ (((uint64_t)(v_backslash_x_length))
+ << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ goto label__string_loop_outer__continue;
}
status = wuffs_base__make_status(
wuffs_json__error__bad_backslash_escape);
@@ -20647,15 +21643,29 @@
(((uint64_t)(v_string_length))
<< WUFFS_BASE__TOKEN__LENGTH__SHIFT));
v_string_length = 0;
+ if (((uint64_t)(io2_a_dst - iop_a_dst)) <= 0) {
+ goto label__string_loop_outer__continue;
+ }
}
if (a_src && a_src->meta.closed) {
+ if (self->private_impl
+ .f_quirk_enabled_replace_invalid_unicode) {
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)(6356989))
+ << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)(3)) << WUFFS_BASE__TOKEN__LINK__SHIFT) |
+ (((uint64_t)(1))
+ << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ (iop_a_src += 1, wuffs_base__make_empty_struct());
+ goto label__string_loop_outer__continue;
+ }
status =
wuffs_base__make_status(wuffs_json__error__bad_utf_8);
goto exit;
}
status = wuffs_base__make_status(
wuffs_base__suspension__short_read);
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(8);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(11);
v_string_length = 0;
v_char = 0;
goto label__string_loop_outer__continue;
@@ -20689,15 +21699,29 @@
(((uint64_t)(v_string_length))
<< WUFFS_BASE__TOKEN__LENGTH__SHIFT));
v_string_length = 0;
+ if (((uint64_t)(io2_a_dst - iop_a_dst)) <= 0) {
+ goto label__string_loop_outer__continue;
+ }
}
if (a_src && a_src->meta.closed) {
+ if (self->private_impl
+ .f_quirk_enabled_replace_invalid_unicode) {
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)(6356989))
+ << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)(3)) << WUFFS_BASE__TOKEN__LINK__SHIFT) |
+ (((uint64_t)(1))
+ << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ (iop_a_src += 1, wuffs_base__make_empty_struct());
+ goto label__string_loop_outer__continue;
+ }
status =
wuffs_base__make_status(wuffs_json__error__bad_utf_8);
goto exit;
}
status = wuffs_base__make_status(
wuffs_base__suspension__short_read);
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(9);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(12);
v_string_length = 0;
v_char = 0;
goto label__string_loop_outer__continue;
@@ -20736,15 +21760,29 @@
(((uint64_t)(v_string_length))
<< WUFFS_BASE__TOKEN__LENGTH__SHIFT));
v_string_length = 0;
+ if (((uint64_t)(io2_a_dst - iop_a_dst)) <= 0) {
+ goto label__string_loop_outer__continue;
+ }
}
if (a_src && a_src->meta.closed) {
+ if (self->private_impl
+ .f_quirk_enabled_replace_invalid_unicode) {
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)(6356989))
+ << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)(3)) << WUFFS_BASE__TOKEN__LINK__SHIFT) |
+ (((uint64_t)(1))
+ << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ (iop_a_src += 1, wuffs_base__make_empty_struct());
+ goto label__string_loop_outer__continue;
+ }
status =
wuffs_base__make_status(wuffs_json__error__bad_utf_8);
goto exit;
}
status = wuffs_base__make_status(
wuffs_base__suspension__short_read);
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(10);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(13);
v_string_length = 0;
v_char = 0;
goto label__string_loop_outer__continue;
@@ -20782,18 +21820,30 @@
(((uint64_t)(v_string_length))
<< WUFFS_BASE__TOKEN__LENGTH__SHIFT));
v_string_length = 0;
+ if (((uint64_t)(io2_a_dst - iop_a_dst)) <= 0) {
+ goto label__string_loop_outer__continue;
+ }
}
if (v_char == 128) {
status = wuffs_base__make_status(
wuffs_json__error__bad_c0_control_code);
goto exit;
}
+ if (self->private_impl.f_quirk_enabled_replace_invalid_unicode) {
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)(6356989))
+ << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)(3)) << WUFFS_BASE__TOKEN__LINK__SHIFT) |
+ (((uint64_t)(1)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ (iop_a_src += 1, wuffs_base__make_empty_struct());
+ goto label__string_loop_outer__continue;
+ }
status = wuffs_base__make_status(wuffs_json__error__bad_utf_8);
goto exit;
}
}
label__string_loop_outer__break:;
- label__1__continue:;
+ label__2__continue:;
while (true) {
if (((uint64_t)(io2_a_src - iop_a_src)) <= 0) {
if (a_src && a_src->meta.closed) {
@@ -20802,14 +21852,14 @@
}
status =
wuffs_base__make_status(wuffs_base__suspension__short_read);
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(11);
- goto label__1__continue;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(14);
+ goto label__2__continue;
}
if (((uint64_t)(io2_a_dst - iop_a_dst)) <= 0) {
status =
wuffs_base__make_status(wuffs_base__suspension__short_write);
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(12);
- goto label__1__continue;
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(15);
+ goto label__2__continue;
}
(iop_a_src += 1, wuffs_base__make_empty_struct());
*iop_a_dst++ = wuffs_base__make_token(
@@ -20817,11 +21867,11 @@
<< WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
(((uint64_t)(2)) << WUFFS_BASE__TOKEN__LINK__SHIFT) |
(((uint64_t)(1)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
- goto label__1__break;
+ goto label__2__break;
}
- label__1__break:;
+ label__2__break:;
if (0 == (v_expect & 16)) {
- v_expect = 8;
+ v_expect = 4104;
goto label__outer__continue;
}
goto label__goto_parsed_a_leaf_value__break;
@@ -20831,9 +21881,17 @@
(((uint64_t)(0)) << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
(((uint64_t)(1)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
if (0 == (v_expect & 256)) {
- v_expect = 2;
+ if (self->private_impl.f_quirk_enabled_allow_extra_comma) {
+ v_expect = 4162;
+ } else {
+ v_expect = 4098;
+ }
} else {
- v_expect = 3762;
+ if (self->private_impl.f_quirk_enabled_allow_extra_comma) {
+ v_expect = 8114;
+ } else {
+ v_expect = 7858;
+ }
}
goto label__outer__continue;
} else if (v_class == 3) {
@@ -20841,7 +21899,7 @@
*iop_a_dst++ = wuffs_base__make_token(
(((uint64_t)(0)) << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
(((uint64_t)(1)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
- v_expect = 3762;
+ v_expect = 7858;
goto label__outer__continue;
} else if (v_class == 4) {
while (true) {
@@ -20864,7 +21922,7 @@
<< WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
(((uint64_t)(v_number_length))
<< WUFFS_BASE__TOKEN__LENGTH__SHIFT));
- goto label__2__break;
+ goto label__3__break;
}
while (v_number_length > 0) {
v_number_length -= 1;
@@ -20877,6 +21935,27 @@
}
}
if (v_number_status == 1) {
+ if (self->private_impl.f_quirk_enabled_allow_inf_nan_numbers) {
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
+ }
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(16);
+ status =
+ wuffs_json__decoder__decode_inf_nan(self, a_dst, a_src);
+ if (a_dst) {
+ iop_a_dst = a_dst->data.ptr + a_dst->meta.wi;
+ }
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
+ }
+ if (status.repr) {
+ goto suspend;
+ }
+ goto label__3__break;
+ }
status = wuffs_base__make_status(wuffs_json__error__bad_input);
goto exit;
} else if (v_number_status == 2) {
@@ -20886,15 +21965,15 @@
} else {
status =
wuffs_base__make_status(wuffs_base__suspension__short_read);
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(13);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(17);
while (((uint64_t)(io2_a_dst - iop_a_dst)) <= 0) {
status = wuffs_base__make_status(
wuffs_base__suspension__short_write);
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(14);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(18);
}
}
}
- label__2__break:;
+ label__3__break:;
goto label__goto_parsed_a_leaf_value__break;
} else if (v_class == 5) {
v_vminor = 2113553;
@@ -20919,8 +21998,8 @@
(((uint64_t)(v_vminor))
<< WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
(((uint64_t)(1)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
- v_expect = 66;
- v_expect_after_value = 68;
+ v_expect = 4162;
+ v_expect_after_value = 4164;
goto label__outer__continue;
} else if (v_class == 6) {
(iop_a_src += 1, wuffs_base__make_empty_struct());
@@ -20940,15 +22019,15 @@
(((uint64_t)(2105410))
<< WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
(((uint64_t)(1)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
- v_expect = 260;
- v_expect_after_value = 260;
+ v_expect = 4356;
+ v_expect_after_value = 4356;
} else {
*iop_a_dst++ = wuffs_base__make_token(
(((uint64_t)(2113602))
<< WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
(((uint64_t)(1)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
- v_expect = 68;
- v_expect_after_value = 68;
+ v_expect = 4164;
+ v_expect_after_value = 4164;
}
goto label__outer__continue;
} else if (v_class == 7) {
@@ -20974,8 +22053,8 @@
(((uint64_t)(v_vminor))
<< WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
(((uint64_t)(1)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
- v_expect = 4018;
- v_expect_after_value = 260;
+ v_expect = 8114;
+ v_expect_after_value = 4356;
goto label__outer__continue;
} else if (v_class == 8) {
(iop_a_src += 1, wuffs_base__make_empty_struct());
@@ -20995,15 +22074,15 @@
(((uint64_t)(2105378))
<< WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
(((uint64_t)(1)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
- v_expect = 260;
- v_expect_after_value = 260;
+ v_expect = 4356;
+ v_expect_after_value = 4356;
} else {
*iop_a_dst++ = wuffs_base__make_token(
(((uint64_t)(2113570))
<< WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
(((uint64_t)(1)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
- v_expect = 68;
- v_expect_after_value = 68;
+ v_expect = 4164;
+ v_expect_after_value = 4164;
}
goto label__outer__continue;
} else if (v_class == 9) {
@@ -21024,7 +22103,7 @@
} else if (v_match == 1) {
status =
wuffs_base__make_status(wuffs_base__suspension__short_read);
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(15);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(19);
goto label__outer__continue;
}
} else if (v_class == 10) {
@@ -21045,7 +22124,7 @@
} else if (v_match == 1) {
status =
wuffs_base__make_status(wuffs_base__suspension__short_read);
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(16);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(20);
goto label__outer__continue;
}
} else if (v_class == 11) {
@@ -21066,7 +22145,49 @@
} else if (v_match == 1) {
status =
wuffs_base__make_status(wuffs_base__suspension__short_read);
- WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(17);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(21);
+ goto label__outer__continue;
+ }
+ if (self->private_impl.f_quirk_enabled_allow_inf_nan_numbers) {
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
+ }
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(22);
+ status = wuffs_json__decoder__decode_inf_nan(self, a_dst, a_src);
+ if (a_dst) {
+ iop_a_dst = a_dst->data.ptr + a_dst->meta.wi;
+ }
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
+ }
+ if (status.repr) {
+ goto suspend;
+ }
+ goto label__goto_parsed_a_leaf_value__break;
+ }
+ } else if (v_class == 12) {
+ if (self->private_impl.f_quirk_enabled_allow_comment_block ||
+ self->private_impl.f_quirk_enabled_allow_comment_line) {
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
+ }
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(23);
+ status = wuffs_json__decoder__decode_comment(self, a_dst, a_src);
+ if (a_dst) {
+ iop_a_dst = a_dst->data.ptr + a_dst->meta.wi;
+ }
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
+ }
+ if (status.repr) {
+ goto suspend;
+ }
goto label__outer__continue;
}
}
@@ -21080,6 +22201,27 @@
v_expect = v_expect_after_value;
}
label__outer__break:;
+ if (self->private_impl.f_quirk_enabled_allow_trailing_new_line) {
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
+ }
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT(24);
+ status =
+ wuffs_json__decoder__decode_trailing_new_line(self, a_dst, a_src);
+ if (a_dst) {
+ iop_a_dst = a_dst->data.ptr + a_dst->meta.wi;
+ }
+ if (a_src) {
+ iop_a_src = a_src->data.ptr + a_src->meta.ri;
+ }
+ if (status.repr) {
+ goto suspend;
+ }
+ }
+ self->private_impl.f_end_of_data = true;
goto ok;
ok:
@@ -21296,6 +22438,607 @@
return v_n;
}
+// -------- func json.decoder.decode_leading
+
+static wuffs_base__status //
+wuffs_json__decoder__decode_leading(wuffs_json__decoder* self,
+ wuffs_base__token_buffer* a_dst,
+ wuffs_base__io_buffer* a_src) {
+ wuffs_base__status status = wuffs_base__make_status(NULL);
+
+ uint8_t v_c = 0;
+ uint32_t v_u = 0;
+
+ wuffs_base__token* iop_a_dst = NULL;
+ wuffs_base__token* io0_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ wuffs_base__token* io1_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ wuffs_base__token* 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;
+ }
+ }
+ 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_leading[0];
+ switch (coro_susp_point) {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
+
+ self->private_impl.f_allow_leading_ars =
+ self->private_impl.f_quirk_enabled_allow_leading_ascii_record_separator;
+ self->private_impl.f_allow_leading_ubom =
+ self->private_impl
+ .f_quirk_enabled_allow_leading_unicode_byte_order_mark;
+ label__0__continue:;
+ while (self->private_impl.f_allow_leading_ars ||
+ self->private_impl.f_allow_leading_ubom) {
+ if (((uint64_t)(io2_a_dst - iop_a_dst)) <= 0) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_write);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(1);
+ goto label__0__continue;
+ }
+ if (((uint64_t)(io2_a_src - iop_a_src)) <= 0) {
+ if (a_src && a_src->meta.closed) {
+ goto label__0__break;
+ }
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(2);
+ goto label__0__continue;
+ }
+ v_c = wuffs_base__load_u8be__no_bounds_check(iop_a_src);
+ if ((v_c == 30) && self->private_impl.f_allow_leading_ars) {
+ self->private_impl.f_allow_leading_ars = false;
+ (iop_a_src += 1, wuffs_base__make_empty_struct());
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)(0)) << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)(1)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ goto label__0__continue;
+ } else if ((v_c == 239) && self->private_impl.f_allow_leading_ubom) {
+ if (((uint64_t)(io2_a_src - iop_a_src)) < 3) {
+ if (a_src && a_src->meta.closed) {
+ goto label__0__break;
+ }
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(3);
+ goto label__0__continue;
+ }
+ v_u = ((uint32_t)(wuffs_base__load_u24le__no_bounds_check(iop_a_src)));
+ if (v_u == 12565487) {
+ self->private_impl.f_allow_leading_ubom = false;
+ (iop_a_src += 3, wuffs_base__make_empty_struct());
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)(0)) << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)(3)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ goto label__0__continue;
+ }
+ }
+ goto label__0__break;
+ }
+ label__0__break:;
+
+ goto ok;
+ ok:
+ self->private_impl.p_decode_leading[0] = 0;
+ goto exit;
+ }
+
+ goto suspend;
+suspend:
+ self->private_impl.p_decode_leading[0] =
+ wuffs_base__status__is_suspension(&status) ? coro_susp_point : 0;
+
+ goto exit;
+exit:
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
+ }
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+
+ return status;
+}
+
+// -------- func json.decoder.decode_comment
+
+static wuffs_base__status //
+wuffs_json__decoder__decode_comment(wuffs_json__decoder* self,
+ wuffs_base__token_buffer* a_dst,
+ wuffs_base__io_buffer* a_src) {
+ wuffs_base__status status = wuffs_base__make_status(NULL);
+
+ uint8_t v_c = 0;
+ uint16_t v_c2 = 0;
+ uint32_t v_link_prev = 0;
+ uint32_t v_length = 0;
+
+ wuffs_base__token* iop_a_dst = NULL;
+ wuffs_base__token* io0_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ wuffs_base__token* io1_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ wuffs_base__token* 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;
+ }
+ }
+ 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_comment[0];
+ if (coro_susp_point) {
+ v_link_prev = self->private_data.s_decode_comment[0].v_link_prev;
+ }
+ switch (coro_susp_point) {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
+
+ label__0__continue:;
+ while ((((uint64_t)(io2_a_dst - iop_a_dst)) <= 0) ||
+ (((uint64_t)(io2_a_src - iop_a_src)) <= 1)) {
+ if (((uint64_t)(io2_a_dst - iop_a_dst)) <= 0) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_write);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(1);
+ goto label__0__continue;
+ }
+ if (a_src && a_src->meta.closed) {
+ status = wuffs_base__make_status(wuffs_json__error__bad_input);
+ goto exit;
+ }
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(2);
+ }
+ v_c2 = wuffs_base__load_u16le__no_bounds_check(iop_a_src);
+ if ((v_c2 == 10799) &&
+ self->private_impl.f_quirk_enabled_allow_comment_block) {
+ (iop_a_src += 2, wuffs_base__make_empty_struct());
+ v_length = 2;
+ label__comment_block__continue:;
+ while (true) {
+ if (((uint64_t)(io2_a_dst - iop_a_dst)) <= 0) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_write);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(3);
+ v_length = 0;
+ goto label__comment_block__continue;
+ }
+ while (true) {
+ if (((uint64_t)(io2_a_src - iop_a_src)) <= 1) {
+ if (v_length > 0) {
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)(2)) << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)((1 | v_link_prev)))
+ << WUFFS_BASE__TOKEN__LINK__SHIFT) |
+ (((uint64_t)(v_length)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ v_link_prev = 2;
+ }
+ if (a_src && a_src->meta.closed) {
+ status = wuffs_base__make_status(wuffs_json__error__bad_input);
+ goto exit;
+ }
+ status =
+ wuffs_base__make_status(wuffs_base__suspension__short_read);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(4);
+ v_length = 0;
+ goto label__comment_block__continue;
+ }
+ v_c2 = wuffs_base__load_u16le__no_bounds_check(iop_a_src);
+ if (v_c2 == 12074) {
+ (iop_a_src += 2, wuffs_base__make_empty_struct());
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)(2)) << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)(v_link_prev)) << WUFFS_BASE__TOKEN__LINK__SHIFT) |
+ (((uint64_t)((v_length + 2)))
+ << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ status = wuffs_base__make_status(NULL);
+ goto ok;
+ }
+ (iop_a_src += 1, wuffs_base__make_empty_struct());
+ if (v_length >= 65533) {
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)(2)) << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)((1 | v_link_prev)))
+ << WUFFS_BASE__TOKEN__LINK__SHIFT) |
+ (((uint64_t)((v_length + 1)))
+ << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ v_length = 0;
+ v_link_prev = 2;
+ goto label__comment_block__continue;
+ }
+ v_length += 1;
+ }
+ }
+ } else if ((v_c2 == 12079) &&
+ self->private_impl.f_quirk_enabled_allow_comment_line) {
+ (iop_a_src += 2, wuffs_base__make_empty_struct());
+ v_length = 2;
+ label__comment_line__continue:;
+ while (true) {
+ if (((uint64_t)(io2_a_dst - iop_a_dst)) <= 0) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_write);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(5);
+ v_length = 0;
+ goto label__comment_line__continue;
+ }
+ while (true) {
+ if (((uint64_t)(io2_a_src - iop_a_src)) <= 0) {
+ if (v_length > 0) {
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)(1)) << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)((1 | v_link_prev)))
+ << WUFFS_BASE__TOKEN__LINK__SHIFT) |
+ (((uint64_t)(v_length)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ v_link_prev = 2;
+ }
+ if (a_src && a_src->meta.closed) {
+ status = wuffs_base__make_status(wuffs_json__error__bad_input);
+ goto exit;
+ }
+ status =
+ wuffs_base__make_status(wuffs_base__suspension__short_read);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(6);
+ v_length = 0;
+ goto label__comment_line__continue;
+ }
+ v_c = wuffs_base__load_u8be__no_bounds_check(iop_a_src);
+ if (v_c == 10) {
+ (iop_a_src += 1, wuffs_base__make_empty_struct());
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)(1)) << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)(v_link_prev)) << WUFFS_BASE__TOKEN__LINK__SHIFT) |
+ (((uint64_t)((v_length + 1)))
+ << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ status = wuffs_base__make_status(NULL);
+ goto ok;
+ }
+ (iop_a_src += 1, wuffs_base__make_empty_struct());
+ if (v_length >= 65533) {
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)(1)) << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)((1 | v_link_prev)))
+ << WUFFS_BASE__TOKEN__LINK__SHIFT) |
+ (((uint64_t)((v_length + 1)))
+ << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ v_length = 0;
+ v_link_prev = 2;
+ goto label__comment_line__continue;
+ }
+ v_length += 1;
+ }
+ }
+ }
+ status = wuffs_base__make_status(wuffs_json__error__bad_input);
+ goto exit;
+ goto ok;
+ ok:
+ self->private_impl.p_decode_comment[0] = 0;
+ goto exit;
+ }
+
+ goto suspend;
+suspend:
+ self->private_impl.p_decode_comment[0] =
+ wuffs_base__status__is_suspension(&status) ? coro_susp_point : 0;
+ self->private_data.s_decode_comment[0].v_link_prev = v_link_prev;
+
+ goto exit;
+exit:
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
+ }
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+
+ return status;
+}
+
+// -------- func json.decoder.decode_inf_nan
+
+static wuffs_base__status //
+wuffs_json__decoder__decode_inf_nan(wuffs_json__decoder* self,
+ wuffs_base__token_buffer* a_dst,
+ wuffs_base__io_buffer* a_src) {
+ wuffs_base__status status = wuffs_base__make_status(NULL);
+
+ uint32_t v_c4 = 0;
+ uint32_t v_neg = 0;
+
+ wuffs_base__token* iop_a_dst = NULL;
+ wuffs_base__token* io0_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ wuffs_base__token* io1_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ wuffs_base__token* 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;
+ }
+ }
+ 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_inf_nan[0];
+ if (coro_susp_point) {
+ v_neg = self->private_data.s_decode_inf_nan[0].v_neg;
+ }
+ switch (coro_susp_point) {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
+
+ label__0__continue:;
+ while (true) {
+ if (((uint64_t)(io2_a_dst - iop_a_dst)) <= 0) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_write);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(1);
+ goto label__0__continue;
+ }
+ if (((uint64_t)(io2_a_src - iop_a_src)) <= 2) {
+ if (a_src && a_src->meta.closed) {
+ status = wuffs_base__make_status(wuffs_json__error__bad_input);
+ goto exit;
+ }
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(2);
+ goto label__0__continue;
+ }
+ v_c4 = ((uint32_t)(wuffs_base__load_u24le__no_bounds_check(iop_a_src)));
+ if ((v_c4 | 2105376) == 6712937) {
+ if (((uint64_t)(io2_a_src - iop_a_src)) > 7) {
+ if ((wuffs_base__load_u64le__no_bounds_check(iop_a_src) |
+ 2314885530818453536) == 8751735898823356009) {
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)(10485792))
+ << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)(8)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ (iop_a_src += 8, wuffs_base__make_empty_struct());
+ status = wuffs_base__make_status(NULL);
+ goto ok;
+ }
+ } else if (!(a_src && a_src->meta.closed)) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(3);
+ goto label__0__continue;
+ }
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)(10485792)) << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)(3)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ (iop_a_src += 3, wuffs_base__make_empty_struct());
+ status = wuffs_base__make_status(NULL);
+ goto ok;
+ } else if ((v_c4 | 2105376) == 7233902) {
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)(10485888)) << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)(3)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ (iop_a_src += 3, wuffs_base__make_empty_struct());
+ status = wuffs_base__make_status(NULL);
+ goto ok;
+ } else if ((v_c4 & 255) == 43) {
+ v_neg = 0;
+ } else if ((v_c4 & 255) == 45) {
+ v_neg = 1;
+ } else {
+ status = wuffs_base__make_status(wuffs_json__error__bad_input);
+ goto exit;
+ }
+ if (((uint64_t)(io2_a_src - iop_a_src)) <= 3) {
+ if (a_src && a_src->meta.closed) {
+ status = wuffs_base__make_status(wuffs_json__error__bad_input);
+ goto exit;
+ }
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(4);
+ goto label__0__continue;
+ }
+ v_c4 = (wuffs_base__load_u32le__no_bounds_check(iop_a_src) >> 8);
+ if ((v_c4 | 2105376) == 6712937) {
+ if (((uint64_t)(io2_a_src - iop_a_src)) > 8) {
+ if ((wuffs_base__load_u64le__no_bounds_check(iop_a_src + 1) |
+ 2314885530818453536) == 8751735898823356009) {
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)((10485760 | (((uint32_t)(32)) >> v_neg))))
+ << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)(9)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ (iop_a_src += 9, wuffs_base__make_empty_struct());
+ status = wuffs_base__make_status(NULL);
+ goto ok;
+ }
+ } else if (!(a_src && a_src->meta.closed)) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(5);
+ goto label__0__continue;
+ }
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)((10485760 | (((uint32_t)(32)) >> v_neg))))
+ << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)(4)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ (iop_a_src += 4, wuffs_base__make_empty_struct());
+ status = wuffs_base__make_status(NULL);
+ goto ok;
+ } else if ((v_c4 | 2105376) == 7233902) {
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)((10485760 | (((uint32_t)(128)) >> v_neg))))
+ << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)(4)) << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ (iop_a_src += 4, wuffs_base__make_empty_struct());
+ status = wuffs_base__make_status(NULL);
+ goto ok;
+ }
+ status = wuffs_base__make_status(wuffs_json__error__bad_input);
+ goto exit;
+ }
+
+ goto ok;
+ ok:
+ self->private_impl.p_decode_inf_nan[0] = 0;
+ goto exit;
+ }
+
+ goto suspend;
+suspend:
+ self->private_impl.p_decode_inf_nan[0] =
+ wuffs_base__status__is_suspension(&status) ? coro_susp_point : 0;
+ self->private_data.s_decode_inf_nan[0].v_neg = v_neg;
+
+ goto exit;
+exit:
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
+ }
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+
+ return status;
+}
+
+// -------- func json.decoder.decode_trailing_new_line
+
+static wuffs_base__status //
+wuffs_json__decoder__decode_trailing_new_line(wuffs_json__decoder* self,
+ wuffs_base__token_buffer* a_dst,
+ wuffs_base__io_buffer* a_src) {
+ wuffs_base__status status = wuffs_base__make_status(NULL);
+
+ uint8_t v_c = 0;
+ uint32_t v_whitespace_length = 0;
+
+ wuffs_base__token* iop_a_dst = NULL;
+ wuffs_base__token* io0_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ wuffs_base__token* io1_a_dst WUFFS_BASE__POTENTIALLY_UNUSED = NULL;
+ wuffs_base__token* 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;
+ }
+ }
+ 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_trailing_new_line[0];
+ switch (coro_susp_point) {
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
+
+ label__outer__continue:;
+ while (true) {
+ if (((uint64_t)(io2_a_dst - iop_a_dst)) <= 0) {
+ status = wuffs_base__make_status(wuffs_base__suspension__short_write);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(1);
+ v_whitespace_length = 0;
+ goto label__outer__continue;
+ }
+ while (true) {
+ if (((uint64_t)(io2_a_src - iop_a_src)) <= 0) {
+ if (v_whitespace_length > 0) {
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)(0)) << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)(v_whitespace_length))
+ << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ v_whitespace_length = 0;
+ }
+ if (a_src && a_src->meta.closed) {
+ goto label__outer__break;
+ }
+ status = wuffs_base__make_status(wuffs_base__suspension__short_read);
+ WUFFS_BASE__COROUTINE_SUSPENSION_POINT_MAYBE_SUSPEND(2);
+ v_whitespace_length = 0;
+ goto label__outer__continue;
+ }
+ v_c = wuffs_base__load_u8be__no_bounds_check(iop_a_src);
+ if (wuffs_json__lut_classes[v_c] != 0) {
+ if (v_whitespace_length > 0) {
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)(0)) << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)(v_whitespace_length))
+ << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ v_whitespace_length = 0;
+ }
+ status = wuffs_base__make_status(wuffs_json__error__bad_input);
+ goto exit;
+ }
+ (iop_a_src += 1, wuffs_base__make_empty_struct());
+ if ((v_whitespace_length >= 65534) || (v_c == 10)) {
+ *iop_a_dst++ = wuffs_base__make_token(
+ (((uint64_t)(0)) << WUFFS_BASE__TOKEN__VALUE_MINOR__SHIFT) |
+ (((uint64_t)((v_whitespace_length + 1)))
+ << WUFFS_BASE__TOKEN__LENGTH__SHIFT));
+ v_whitespace_length = 0;
+ if (v_c == 10) {
+ goto label__outer__break;
+ }
+ goto label__outer__continue;
+ }
+ v_whitespace_length += 1;
+ }
+ }
+ label__outer__break:;
+
+ goto ok;
+ ok:
+ self->private_impl.p_decode_trailing_new_line[0] = 0;
+ goto exit;
+ }
+
+ goto suspend;
+suspend:
+ self->private_impl.p_decode_trailing_new_line[0] =
+ wuffs_base__status__is_suspension(&status) ? coro_susp_point : 0;
+
+ goto exit;
+exit:
+ if (a_dst) {
+ a_dst->meta.wi = ((size_t)(iop_a_dst - a_dst->data.ptr));
+ }
+ if (a_src) {
+ a_src->meta.ri = ((size_t)(iop_a_src - a_src->data.ptr));
+ }
+
+ return status;
+}
+
#endif // !defined(WUFFS_CONFIG__MODULES) ||
// defined(WUFFS_CONFIG__MODULE__JSON)
@@ -21592,8 +23335,6 @@
}
uint32_t coro_susp_point = self->private_impl.p_decode_frame_config[0];
- if (coro_susp_point) {
- }
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
@@ -21853,8 +23594,6 @@
}
uint32_t coro_susp_point = self->private_impl.p_skip_frame[0];
- if (coro_susp_point) {
- }
switch (coro_susp_point) {
WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
diff --git a/script/adler32-standalone.c b/script/adler32-standalone.c
index 6726083..805b212 100644
--- a/script/adler32-standalone.c
+++ b/script/adler32-standalone.c
@@ -40,17 +40,17 @@
// The order matters here. Clang also defines "__GNUC__".
#if defined(__clang__)
-const char* cc = "clang";
-const char* cc_version = __clang_version__;
+const char* g_cc = "clang";
+const char* g_cc_version = __clang_version__;
#elif defined(__GNUC__)
-const char* cc = "gcc";
-const char* cc_version = __VERSION__;
+const char* g_cc = "gcc";
+const char* g_cc_version = __VERSION__;
#elif defined(_MSC_VER)
-const char* cc = "cl";
-const char* cc_version = "???";
+const char* g_cc = "cl";
+const char* g_cc_version = "???";
#else
-const char* cc = "cc";
-const char* cc_version = "???";
+const char* g_cc = "cc";
+const char* g_cc_version = "???";
#endif
struct {
@@ -58,7 +58,7 @@
char** remaining_argv;
bool no_check;
-} flags = {0};
+} g_flags = {0};
const char* //
parse_flags(int argc, char** argv) {
@@ -83,15 +83,15 @@
}
if (!strcmp(arg, "no-check")) {
- flags.no_check = true;
+ g_flags.no_check = true;
continue;
}
return "main: unrecognized flag argument";
}
- flags.remaining_argc = argc - c;
- flags.remaining_argv = argv + c;
+ g_flags.remaining_argc = argc - c;
+ g_flags.remaining_argv = argv + c;
return NULL;
}
@@ -156,7 +156,7 @@
return (s2 << 16) | s1;
}
-uint8_t buffer[BUFFER_SIZE] = {0};
+uint8_t g_buffer[BUFFER_SIZE] = {0};
int //
main(int argc, char** argv) {
@@ -178,8 +178,8 @@
int i;
int num_bad = 0;
for (i = 0; i < num_reps; i++) {
- uint32_t actual_hash = calculate_hash(buffer, BUFFER_SIZE);
- if (!flags.no_check && (actual_hash != expected_hash_of_1mib_of_zeroes)) {
+ uint32_t actual_hash = calculate_hash(g_buffer, BUFFER_SIZE);
+ if (!g_flags.no_check && (actual_hash != expected_hash_of_1mib_of_zeroes)) {
num_bad++;
}
}
@@ -198,6 +198,6 @@
int64_t denom = micros * ONE_MIBIBYTE;
int64_t mib_per_s = denom ? numer / denom : 0;
- printf("%8d MiB/s, %s %s\n", (int)mib_per_s, cc, cc_version);
+ printf("%8d MiB/s, %s %s\n", (int)mib_per_s, g_cc, g_cc_version);
return 0;
}
diff --git a/script/bench-c-deflate-fragmentation.c b/script/bench-c-deflate-fragmentation.c
index be6f7aa..37b7c1e 100644
--- a/script/bench-c-deflate-fragmentation.c
+++ b/script/bench-c-deflate-fragmentation.c
@@ -75,17 +75,17 @@
// The order matters here. Clang also defines "__GNUC__".
#if defined(__clang__)
-const char* cc = "clang";
-const char* cc_version = __clang_version__;
+const char* g_cc = "clang";
+const char* g_cc_version = __clang_version__;
#elif defined(__GNUC__)
-const char* cc = "gcc";
-const char* cc_version = __VERSION__;
+const char* g_cc = "gcc";
+const char* g_cc_version = __VERSION__;
#elif defined(_MSC_VER)
-const char* cc = "cl";
-const char* cc_version = "???";
+const char* g_cc = "cl";
+const char* g_cc_version = "???";
#else
-const char* cc = "cc";
-const char* cc_version = "???";
+const char* g_cc = "cc";
+const char* g_cc_version = "???";
#endif
static inline uint32_t //
@@ -103,39 +103,40 @@
#define MAX_DIMENSION (16384)
#define MAX_IDAT_CHUNKS (1024)
-uint8_t dst_buffer_array[DST_BUFFER_ARRAY_SIZE] = {0};
-size_t dst_len = 0;
-uint8_t src_buffer_array[SRC_BUFFER_ARRAY_SIZE] = {0};
-size_t src_len = 0;
-uint8_t idat_buffer_array[SRC_BUFFER_ARRAY_SIZE] = {0};
+uint8_t g_dst_buffer_array[DST_BUFFER_ARRAY_SIZE] = {0};
+size_t g_dst_len = 0;
+uint8_t g_src_buffer_array[SRC_BUFFER_ARRAY_SIZE] = {0};
+size_t g_src_len = 0;
+uint8_t g_idat_buffer_array[SRC_BUFFER_ARRAY_SIZE] = {0};
// The n'th IDAT chunk data (where n is a zero-based count) is in
-// idat_buffer_array[i:j], where i = idat_splits[n+0] and j = idat_splits[n+1].
-size_t idat_splits[MAX_IDAT_CHUNKS + 1] = {0};
-uint32_t num_idat_chunks = 0;
+// g_idat_buffer_array[i:j], where i = g_idat_splits[n+0] and j =
+// g_idat_splits[n+1].
+size_t g_idat_splits[MAX_IDAT_CHUNKS + 1] = {0};
+uint32_t g_num_idat_chunks = 0;
#define WORK_BUFFER_ARRAY_SIZE \
WUFFS_ZLIB__DECODER_WORKBUF_LEN_MAX_INCL_WORST_CASE
#if WORK_BUFFER_ARRAY_SIZE > 0
-uint8_t work_buffer_array[WORK_BUFFER_ARRAY_SIZE];
+uint8_t g_work_buffer_array[WORK_BUFFER_ARRAY_SIZE];
#else
// Not all C/C++ compilers support 0-length arrays.
-uint8_t work_buffer_array[1];
+uint8_t g_work_buffer_array[1];
#endif
-uint32_t width = 0;
-uint32_t height = 0;
-uint64_t bytes_per_pixel = 0;
-uint64_t bytes_per_row = 0;
-uint64_t bytes_per_frame = 0;
+uint32_t g_width = 0;
+uint32_t g_height = 0;
+uint64_t g_bytes_per_pixel = 0;
+uint64_t g_bytes_per_row = 0;
+uint64_t g_bytes_per_frame = 0;
const char* //
read_stdin() {
- while (src_len < SRC_BUFFER_ARRAY_SIZE) {
+ while (g_src_len < SRC_BUFFER_ARRAY_SIZE) {
const int stdin_fd = 0;
- ssize_t n = read(stdin_fd, src_buffer_array + src_len,
- SRC_BUFFER_ARRAY_SIZE - src_len);
+ ssize_t n = read(stdin_fd, g_src_buffer_array + g_src_len,
+ SRC_BUFFER_ARRAY_SIZE - g_src_len);
if (n > 0) {
- src_len += n;
+ g_src_len += n;
} else if (n == 0) {
return NULL;
} else if (errno == EINTR) {
@@ -168,36 +169,36 @@
if (chunk_len != 13) {
return "invalid PNG IDAT chunk";
}
- width = load_u32be(p + 0);
- height = load_u32be(p + 4);
- if ((width == 0) || (height == 0)) {
+ g_width = load_u32be(p + 0);
+ g_height = load_u32be(p + 4);
+ if ((g_width == 0) || (g_height == 0)) {
return "image dimensions are too small";
}
- if ((width > MAX_DIMENSION) || (height > MAX_DIMENSION)) {
+ if ((g_width > MAX_DIMENSION) || (g_height > MAX_DIMENSION)) {
return "image dimensions are too large";
}
if (p[8] != 8) {
return "unsupported PNG bit depth";
}
- if (bytes_per_pixel != 0) {
+ if (g_bytes_per_pixel != 0) {
return "duplicate PNG IHDR chunk";
}
// Process the color type, as per the PNG spec table 11.1.
switch (p[9]) {
case 0:
- bytes_per_pixel = 1;
+ g_bytes_per_pixel = 1;
break;
case 2:
- bytes_per_pixel = 3;
+ g_bytes_per_pixel = 3;
break;
case 3:
- bytes_per_pixel = 1;
+ g_bytes_per_pixel = 1;
break;
case 4:
- bytes_per_pixel = 2;
+ g_bytes_per_pixel = 2;
break;
case 6:
- bytes_per_pixel = 4;
+ g_bytes_per_pixel = 4;
break;
default:
return "unsupported PNG color type";
@@ -208,13 +209,14 @@
break;
case 0x49444154: // "IDAT"
- if (num_idat_chunks == MAX_IDAT_CHUNKS - 1) {
+ if (g_num_idat_chunks == MAX_IDAT_CHUNKS - 1) {
return "too many IDAT chunks";
}
- memcpy(idat_buffer_array + idat_splits[num_idat_chunks], p, chunk_len);
- idat_splits[num_idat_chunks + 1] =
- idat_splits[num_idat_chunks] + chunk_len;
- num_idat_chunks++;
+ memcpy(g_idat_buffer_array + g_idat_splits[g_num_idat_chunks], p,
+ chunk_len);
+ g_idat_splits[g_num_idat_chunks + 1] =
+ g_idat_splits[g_num_idat_chunks] + chunk_len;
+ g_num_idat_chunks++;
break;
}
p += chunk_len;
@@ -241,17 +243,17 @@
wuffs_base__io_buffer dst = ((wuffs_base__io_buffer){
.data = ((wuffs_base__slice_u8){
- .ptr = dst_buffer_array,
- .len = bytes_per_frame,
+ .ptr = g_dst_buffer_array,
+ .len = g_bytes_per_frame,
}),
});
wuffs_base__io_buffer idat = ((wuffs_base__io_buffer){
.data = ((wuffs_base__slice_u8){
- .ptr = idat_buffer_array,
+ .ptr = g_idat_buffer_array,
.len = SRC_BUFFER_ARRAY_SIZE,
}),
.meta = ((wuffs_base__io_buffer_meta){
- .wi = idat_splits[num_idat_chunks],
+ .wi = g_idat_splits[g_num_idat_chunks],
.ri = 0,
.pos = 0,
.closed = true,
@@ -260,20 +262,20 @@
uint32_t i = 0; // Number of dst fragments processed, if frag_dst.
if (frag_dst) {
- dst.data.len = bytes_per_row;
+ dst.data.len = g_bytes_per_row;
}
uint32_t j = 0; // Number of IDAT fragments processed, if frag_idat.
if (frag_idat) {
- idat.meta.wi = idat_splits[1];
- idat.meta.closed = (num_idat_chunks == 1);
+ idat.meta.wi = g_idat_splits[1];
+ idat.meta.closed = (g_num_idat_chunks == 1);
}
while (true) {
status =
wuffs_zlib__decoder__transform_io(&dec, &dst, &idat,
((wuffs_base__slice_u8){
- .ptr = work_buffer_array,
+ .ptr = g_work_buffer_array,
.len = WORK_BUFFER_ARRAY_SIZE,
}));
@@ -281,22 +283,22 @@
break;
}
if ((status.repr == wuffs_base__suspension__short_write) && frag_dst &&
- (i < height - 1)) {
+ (i < g_height - 1)) {
i++;
- dst.data.len = bytes_per_row * (i + 1);
+ dst.data.len = g_bytes_per_row * (i + 1);
continue;
}
if ((status.repr == wuffs_base__suspension__short_read) && frag_idat &&
- (j < num_idat_chunks - 1)) {
+ (j < g_num_idat_chunks - 1)) {
j++;
- idat.meta.wi = idat_splits[j + 1];
- idat.meta.closed = (num_idat_chunks == j + 1);
+ idat.meta.wi = g_idat_splits[j + 1];
+ idat.meta.closed = (g_num_idat_chunks == j + 1);
continue;
}
return wuffs_base__status__message(&status);
}
- if (dst.meta.wi != bytes_per_frame) {
+ if (dst.meta.wi != g_bytes_per_frame) {
return "unexpected number of bytes decoded";
}
return NULL;
@@ -305,11 +307,11 @@
const char* //
decode(bool frag_dst, bool frag_idat) {
int reps;
- if (bytes_per_frame < 100000) {
+ if (g_bytes_per_frame < 100000) {
reps = 1000;
- } else if (bytes_per_frame < 1000000) {
+ } else if (g_bytes_per_frame < 1000000) {
reps = 100;
- } else if (bytes_per_frame < 10000000) {
+ } else if (g_bytes_per_frame < 10000000) {
reps = 10;
} else {
reps = 1;
@@ -339,7 +341,7 @@
printf("Benchmark%sDst%sIDAT/%s\t%8d\t%8" PRIu64 " ns/op\n",
frag_dst ? "Frag" : "Full", //
frag_idat ? "Frag" : "Full", //
- cc, reps, nanos / reps);
+ g_cc, reps, nanos / reps);
return NULL;
}
@@ -358,28 +360,28 @@
if (msg) {
return fail(msg);
}
- if ((src_len < 8) ||
- strncmp((const char*)(src_buffer_array), "\x89PNG\x0D\x0A\x1A\x0A", 8)) {
+ if ((g_src_len < 8) || strncmp((const char*)(g_src_buffer_array),
+ "\x89PNG\x0D\x0A\x1A\x0A", 8)) {
return fail("invalid PNG");
}
- msg = process_png_chunks(src_buffer_array + 8, src_len - 8);
+ msg = process_png_chunks(g_src_buffer_array + 8, g_src_len - 8);
if (msg) {
return fail(msg);
}
- if (bytes_per_pixel == 0) {
+ if (g_bytes_per_pixel == 0) {
return fail("missing PNG IHDR chunk");
}
- if (num_idat_chunks == 0) {
+ if (g_num_idat_chunks == 0) {
return fail("missing PNG IDAT chunk");
}
// The +1 here is for the per-row filter byte.
- bytes_per_row = (uint64_t)width * bytes_per_pixel + 1;
- bytes_per_frame = (uint64_t)height * bytes_per_row;
- if (bytes_per_frame > DST_BUFFER_ARRAY_SIZE) {
+ g_bytes_per_row = (uint64_t)g_width * g_bytes_per_pixel + 1;
+ g_bytes_per_frame = (uint64_t)g_height * g_bytes_per_row;
+ if (g_bytes_per_frame > DST_BUFFER_ARRAY_SIZE) {
return fail("decompressed data is too large");
}
- printf("# %s version %s\n#\n", cc, cc_version);
+ printf("# %s version %s\n#\n", g_cc, g_cc_version);
printf(
"# The output format, including the \"Benchmark\" prefixes, is "
"compatible with the\n"
diff --git a/script/print-hpd-left-shift.go b/script/print-hpd-left-shift.go
index 47141bd..09b175a 100644
--- a/script/print-hpd-left-shift.go
+++ b/script/print-hpd-left-shift.go
@@ -27,6 +27,7 @@
"fmt"
"math"
"math/big"
+ "os"
)
var (
@@ -48,6 +49,13 @@
}
func main() {
+ if err := main1(); err != nil {
+ os.Stderr.WriteString(err.Error() + "\n")
+ os.Exit(1)
+ }
+}
+
+func main1() error {
flag.Parse()
const WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL = 60
@@ -111,4 +119,5 @@
fmt.Printf(" // offset=0x%04X\n", len(data)&^15)
}
fmt.Printf("};\n")
+ return nil
}
diff --git a/script/print-json-token-debug-format.c b/script/print-json-token-debug-format.c
index 7d4827f..e140e45 100644
--- a/script/print-json-token-debug-format.c
+++ b/script/print-json-token-debug-format.c
@@ -84,6 +84,17 @@
// program to generate a stand-alone C++ file.
#include "../release/c/wuffs-unsupported-snapshot.c"
+// Wuffs allows either statically or dynamically allocated work buffers. This
+// program exercises static allocation.
+#define WORK_BUFFER_ARRAY_SIZE \
+ WUFFS_JSON__DECODER_WORKBUF_LEN_MAX_INCL_WORST_CASE
+#if WORK_BUFFER_ARRAY_SIZE > 0
+uint8_t g_work_buffer_array[WORK_BUFFER_ARRAY_SIZE];
+#else
+// Not all C/C++ compilers support 0-length arrays.
+uint8_t g_work_buffer_array[1];
+#endif
+
#ifndef SRC_BUFFER_ARRAY_SIZE
#define SRC_BUFFER_ARRAY_SIZE (64 * 1024 * 1024)
#endif
@@ -91,14 +102,14 @@
#define TOKEN_BUFFER_ARRAY_SIZE (128 * 1024)
#endif
-uint8_t src_buffer_array[SRC_BUFFER_ARRAY_SIZE];
-wuffs_base__token tok_buffer_array[TOKEN_BUFFER_ARRAY_SIZE];
+uint8_t g_src_buffer_array[SRC_BUFFER_ARRAY_SIZE];
+wuffs_base__token g_tok_buffer_array[TOKEN_BUFFER_ARRAY_SIZE];
-wuffs_base__io_buffer src;
-wuffs_base__token_buffer tok;
+wuffs_base__io_buffer g_src;
+wuffs_base__token_buffer g_tok;
-wuffs_json__decoder dec;
-wuffs_base__status dec_status;
+wuffs_json__decoder g_dec;
+wuffs_base__status g_dec_status;
#define TRY(error_msg) \
do { \
@@ -114,18 +125,18 @@
const char* //
read_src() {
- if (src.meta.closed) {
+ if (g_src.meta.closed) {
return "main: internal error: read requested on a closed source";
}
- wuffs_base__io_buffer__compact(&src);
- if (src.meta.wi >= src.data.len) {
- return "main: src buffer is full";
+ wuffs_base__io_buffer__compact(&g_src);
+ if (g_src.meta.wi >= g_src.data.len) {
+ return "main: g_src buffer is full";
}
- size_t n = fread(src.data.ptr + src.meta.wi, sizeof(uint8_t),
- src.data.len - src.meta.wi, stdin);
- src.meta.wi += n;
- src.meta.closed = feof(stdin);
- if ((n == 0) && !src.meta.closed) {
+ size_t n = fread(g_src.data.ptr + g_src.meta.wi, sizeof(uint8_t),
+ g_src.data.len - g_src.meta.wi, stdin);
+ g_src.meta.wi += n;
+ g_src.meta.closed = feof(stdin);
+ if ((n == 0) && !g_src.meta.closed) {
return "main: read error";
}
return NULL;
@@ -139,7 +150,8 @@
bool all_tokens;
bool human_readable;
-} flags = {0};
+ bool quirks;
+} g_flags = {0};
const char* //
parse_flags(int argc, char** argv) {
@@ -164,23 +176,27 @@
}
if (!strcmp(arg, "a") || !strcmp(arg, "all-tokens")) {
- flags.all_tokens = true;
+ g_flags.all_tokens = true;
continue;
}
if (!strcmp(arg, "h") || !strcmp(arg, "human-readable")) {
- flags.human_readable = true;
+ g_flags.human_readable = true;
+ continue;
+ }
+ if (!strcmp(arg, "q") || !strcmp(arg, "quirks")) {
+ g_flags.quirks = true;
continue;
}
return "main: unrecognized flag argument";
}
- flags.remaining_argc = argc - c;
- flags.remaining_argv = argv + c;
+ g_flags.remaining_argc = argc - c;
+ g_flags.remaining_argv = argv + c;
return NULL;
}
-const char* vbc_names[8] = {
+const char* g_vbc_names[8] = {
"0:Filler..........", //
"1:Structure.......", //
"2:String..........", //
@@ -191,7 +207,7 @@
"7:Reserved........", //
};
-const int base38_decode[38] = {
+const int g_base38_decode[38] = {
' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '?', //
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', //
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', //
@@ -200,34 +216,61 @@
const char* //
main1(int argc, char** argv) {
TRY(parse_flags(argc, argv));
- if (flags.remaining_argc > 0) {
+ if (g_flags.remaining_argc > 0) {
return "main: bad argument: use \"program < input\", not \"program input\"";
}
- src = wuffs_base__make_io_buffer(
- wuffs_base__make_slice_u8(src_buffer_array, SRC_BUFFER_ARRAY_SIZE),
+ g_src = wuffs_base__make_io_buffer(
+ wuffs_base__make_slice_u8(g_src_buffer_array, SRC_BUFFER_ARRAY_SIZE),
wuffs_base__empty_io_buffer_meta());
- tok = wuffs_base__make_token_buffer(
- wuffs_base__make_slice_token(tok_buffer_array, TOKEN_BUFFER_ARRAY_SIZE),
+ g_tok = wuffs_base__make_token_buffer(
+ wuffs_base__make_slice_token(g_tok_buffer_array, TOKEN_BUFFER_ARRAY_SIZE),
wuffs_base__empty_token_buffer_meta());
wuffs_base__status init_status = wuffs_json__decoder__initialize(
- &dec, sizeof__wuffs_json__decoder(), WUFFS_VERSION, 0);
+ &g_dec, sizeof__wuffs_json__decoder(), WUFFS_VERSION, 0);
if (!wuffs_base__status__is_ok(&init_status)) {
return wuffs_base__status__message(&init_status);
}
+ if (g_flags.quirks) {
+ uint32_t quirks[] = {
+ WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_A,
+ WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_CAPITAL_U,
+ WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_E,
+ WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_QUESTION_MARK,
+ WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_SINGLE_QUOTE,
+ WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_V,
+ WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_X,
+ WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_ZERO,
+ WUFFS_JSON__QUIRK_ALLOW_COMMENT_BLOCK,
+ WUFFS_JSON__QUIRK_ALLOW_COMMENT_LINE,
+ WUFFS_JSON__QUIRK_ALLOW_EXTRA_COMMA,
+ WUFFS_JSON__QUIRK_ALLOW_INF_NAN_NUMBERS,
+ WUFFS_JSON__QUIRK_ALLOW_LEADING_ASCII_RECORD_SEPARATOR,
+ WUFFS_JSON__QUIRK_ALLOW_LEADING_UNICODE_BYTE_ORDER_MARK,
+ WUFFS_JSON__QUIRK_ALLOW_TRAILING_NEW_LINE,
+ WUFFS_JSON__QUIRK_REPLACE_INVALID_UNICODE,
+ 0,
+ };
+ uint32_t i;
+ for (i = 0; quirks[i]; i++) {
+ wuffs_json__decoder__set_quirk_enabled(&g_dec, quirks[i], true);
+ }
+ }
+
uint64_t pos = 0;
while (true) {
- wuffs_base__status status =
- wuffs_json__decoder__decode_tokens(&dec, &tok, &src);
+ wuffs_base__status status = wuffs_json__decoder__decode_tokens(
+ &g_dec, &g_tok, &g_src,
+ wuffs_base__make_slice_u8(g_work_buffer_array, WORK_BUFFER_ARRAY_SIZE));
- while (tok.meta.ri < tok.meta.wi) {
- wuffs_base__token* t = &tok.data.ptr[tok.meta.ri++];
+ while (g_tok.meta.ri < g_tok.meta.wi) {
+ wuffs_base__token* t = &g_tok.data.ptr[g_tok.meta.ri++];
uint16_t len = wuffs_base__token__length(t);
- if (flags.all_tokens || (wuffs_base__token__value(t) != 0)) {
+ if (g_flags.all_tokens || (wuffs_base__token__value(t) != 0)) {
uint8_t lp = wuffs_base__token__link_prev(t) ? 1 : 0;
uint8_t ln = wuffs_base__token__link_next(t) ? 1 : 0;
uint32_t vmajor = wuffs_base__token__value_major(t);
@@ -235,7 +278,7 @@
uint8_t vbc = wuffs_base__token__value_base_category(t);
uint32_t vbd = wuffs_base__token__value_base_detail(t);
- if (flags.human_readable) {
+ if (g_flags.human_readable) {
printf("pos=0x%08" PRIX32 " len=0x%04" PRIX16 " link=0b%d%d ",
(uint32_t)(pos), len, (int)(lp), (int)(ln));
@@ -250,10 +293,10 @@
uint32_t m3 = m;
printf("vmajor=0x%06" PRIX32 ":%c%c%c%c vminor=0x%06" PRIX32 "\n",
- vmajor, base38_decode[m0], base38_decode[m1],
- base38_decode[m2], base38_decode[m3], vminor);
+ vmajor, g_base38_decode[m0], g_base38_decode[m1],
+ g_base38_decode[m2], g_base38_decode[m3], vminor);
} else {
- printf("vbc=%s. vbd=0x%06" PRIX32 "\n", vbc_names[vbc & 7], vbd);
+ printf("vbc=%s. vbd=0x%06" PRIX32 "\n", g_vbc_names[vbc & 7], vbd);
}
} else {
@@ -285,7 +328,7 @@
} else if (status.repr == wuffs_base__suspension__short_read) {
TRY(read_src());
} else if (status.repr == wuffs_base__suspension__short_write) {
- wuffs_base__token_buffer__compact(&tok);
+ wuffs_base__token_buffer__compact(&g_tok);
} else {
return wuffs_base__status__message(&status);
}
diff --git a/script/print-lzw-example.go b/script/print-lzw-example.go
index ab09d6a..0d588ee 100644
--- a/script/print-lzw-example.go
+++ b/script/print-lzw-example.go
@@ -33,6 +33,7 @@
import (
"fmt"
+ "os"
)
const (
@@ -74,6 +75,13 @@
}
func main() {
+ if err := main1(); err != nil {
+ os.Stderr.WriteString(err.Error() + "\n")
+ os.Exit(1)
+ }
+}
+
+func main1() error {
n, s, q := new(naive), new(suf1), new(sufQ)
decode(n)
decode(s)
@@ -109,6 +117,7 @@
fmt.Println()
key++
}
+ return nil
}
type implementation interface {
diff --git a/script/print-mpb-powers-of-10.go b/script/print-mpb-powers-of-10.go
new file mode 100644
index 0000000..6a55fe5
--- /dev/null
+++ b/script/print-mpb-powers-of-10.go
@@ -0,0 +1,113 @@
+// Copyright 2020 The Wuffs Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// +build ignore
+
+package main
+
+// print-mpb-powers-of-10.go prints the
+// wuffs_base__private_implementation__medium_prec_bin__powers_of_10 tables.
+//
+// Usage: go run print-mpb-powers-of-10.go -comments
+
+import (
+ "flag"
+ "fmt"
+ "math/big"
+ "os"
+)
+
+var (
+ comments = flag.Bool("comments", false, "whether to print comments")
+)
+
+func main() {
+ if err := main1(); err != nil {
+ os.Stderr.WriteString(err.Error() + "\n")
+ os.Exit(1)
+ }
+}
+
+func main1() error {
+ flag.Parse()
+
+ const bigCount = 1 + ((+340 - -348) / 8)
+ fmt.Printf("static const uint32_t "+
+ "wuffs_base__private_implementation__big_powers_of_10[%d] = {\n", 3*bigCount)
+ for e := -348; e <= +340; e += 8 {
+ if err := do(e); err != nil {
+ return err
+ }
+ }
+ fmt.Printf("};\n\n")
+
+ fmt.Printf("static const uint32_t " +
+ "wuffs_base__private_implementation__small_powers_of_10[24] = {\n")
+ for e := 0; e <= 7; e += 1 {
+ if err := do(e); err != nil {
+ return err
+ }
+ }
+ fmt.Printf("};\n")
+
+ return nil
+}
+
+var (
+ one = big.NewInt(1)
+ ten = big.NewInt(10)
+ two64 = big.NewInt(0).Lsh(one, 64)
+)
+
+// N is large enough so that (1<<N) is bigger than 1e348.
+const N = 2048
+
+func do(e int) error {
+ z := big.NewInt(0).Lsh(one, N)
+ if e >= 0 {
+ exp := big.NewInt(0).Exp(ten, big.NewInt(int64(+e)), nil)
+ z.Mul(z, exp)
+ } else {
+ exp := big.NewInt(0).Exp(ten, big.NewInt(int64(-e)), nil)
+ z.Div(z, exp)
+ }
+
+ roundUp := false
+ n := int32(-N)
+ for z.Cmp(two64) >= 0 {
+ roundUp = z.Bit(0) > 0
+ z.Rsh(z, 1)
+ n++
+ }
+ if roundUp {
+ z.Add(z, one)
+ }
+ hex := fmt.Sprintf("%X", z)
+ if len(hex) != 16 {
+ return fmt.Errorf("invalid hexadecimal representation %q", hex)
+ }
+
+ fmt.Printf(" 0x%s, 0x%s, 0x%08X,", hex[8:], hex[:8], uint32(n))
+ if *comments {
+ fmt.Printf(" // 1e%-04d ≈ (0x%s ", e, hex)
+ if n >= 0 {
+ fmt.Printf("<< %4d)", +n)
+ } else {
+ fmt.Printf(">> %4d)", -n)
+ }
+ }
+
+ fmt.Println()
+ return nil
+}
diff --git a/std/adler32/common_adler32.wuffs b/std/adler32/common_adler32.wuffs
index b336617..9c18fe0 100644
--- a/std/adler32/common_adler32.wuffs
+++ b/std/adler32/common_adler32.wuffs
@@ -51,7 +51,7 @@
s2 %= 65521
args.x = remaining
- }
+ } endwhile
this.state = ((s2 & 0xFFFF) << 16) | (s1 & 0xFFFF)
return this.state
diff --git a/std/bmp/decode_bmp.wuffs b/std/bmp/decode_bmp.wuffs
index 032f798..e0f6658 100644
--- a/std/bmp/decode_bmp.wuffs
+++ b/std/bmp/decode_bmp.wuffs
@@ -70,7 +70,7 @@
// Read the BITMAPFILEHEADER (14 bytes).
magic = args.src.read_u16le_as_u32?()
- if magic <> 0x4D42 { // "BM" little-endian.
+ if magic <> 'BM'le {
return "#bad header"
}
@@ -277,7 +277,7 @@
} else {
return status
}
- }
+ } endwhile
}
this.call_sequence = 3
@@ -314,7 +314,7 @@
}
this.pending_pad -= 1
args.src = args.src[1 ..]
- }
+ } endwhile
// Handle the case where the I/O suspension occurred in the middle of a
// source pixel.
@@ -327,7 +327,7 @@
this.stash[this.num_stashed] = args.src[0]
this.num_stashed += 1
args.src = args.src[1 ..]
- }
+ } endwhile
// Write the single pixel.
dst = tab.row(y: this.dst_y)
@@ -393,10 +393,10 @@
this.stash[this.num_stashed] = args.src[0]
this.num_stashed += 1
args.src = args.src[1 ..]
- }
+ } endwhile
return base."$short read"
}
- }
+ } endwhile
return ok
}
diff --git a/std/deflate/decode_deflate.wuffs b/std/deflate/decode_deflate.wuffs
index 97ffe6d..d99ee6d 100644
--- a/std/deflate/decode_deflate.wuffs
+++ b/std/deflate/decode_deflate.wuffs
@@ -211,7 +211,7 @@
// can change the veracity of any args.dst assertions?
this.add_history!(hist: args.dst.since(mark: mark))
yield? status
- }
+ } endwhile
}
pri func decoder.decode_blocks?(dst: base.io_writer, src: base.io_reader) {
@@ -227,7 +227,7 @@
b0 = args.src.read_u8_as_u32?()
this.bits |= b0 << this.n_bits
this.n_bits += 8
- }
+ } endwhile
final = this.bits & 0x01
type = (this.bits >> 1) & 0x03
this.bits >>= 3
@@ -266,7 +266,7 @@
if this.end_of_block {
continue.outer
}
- }
+ } endwhile
} endwhile.outer
}
@@ -301,7 +301,7 @@
} else {
yield? base."$short read"
}
- }
+ } endwhile
}
// init_fixed_huffman initializes this.huffs as per the RFC section 3.2.6.
@@ -312,23 +312,23 @@
while i < 144 {
this.code_lengths[i] = 8
i += 1
- }
+ } endwhile
while i < 256 {
this.code_lengths[i] = 9
i += 1
- }
+ } endwhile
while i < 280 {
this.code_lengths[i] = 7
i += 1
- }
+ } endwhile
while i < 288 {
this.code_lengths[i] = 8
i += 1
- }
+ } endwhile
while i < 320 {
this.code_lengths[i] = 5
i += 1
- }
+ } endwhile
status = this.init_huff!(which: 0, n_codes0: 0, n_codes1: 288, base_symbol: 257)
if status.is_error() {
@@ -369,7 +369,7 @@
b0 = args.src.read_u8_as_u32?()
bits |= b0 << n_bits
n_bits += 8
- }
+ } endwhile
n_lit = bits.low_bits(n: 5) + 257
if n_lit > 286 {
return "#bad literal/length code count"
@@ -394,17 +394,17 @@
b1 = args.src.read_u8_as_u32?()
bits |= b1 << n_bits
n_bits += 8
- }
+ } endwhile
assert i < 19 via "a < b: a < c; c <= b"(c: n_clen)
this.code_lengths[code_order[i]] = (bits & 0x07) as base.u8
bits >>= 3
n_bits -= 3
i += 1
- }
+ } endwhile
while i < 19 {
this.code_lengths[code_order[i]] = 0
i += 1
- }
+ } endwhile
status = this.init_huff!(which: 0, n_codes0: 0, n_codes1: 19, base_symbol: 0xFFF)
if status.is_error() {
return status
@@ -431,7 +431,7 @@
b2 = args.src.read_u8_as_u32?()
bits |= b2 << n_bits
n_bits += 8
- }
+ } endwhile
// For H-CL, there should be no redirections and all symbols should be
// literals.
if (table_entry >> 24) <> 0x80 {
@@ -480,7 +480,7 @@
b3 = args.src.read_u8_as_u32?()
bits |= b3 << n_bits
n_bits += 8
- }
+ } endwhile
rep_count += bits.low_bits(n: n_extra_bits)
bits >>= n_extra_bits
n_bits -= n_extra_bits
@@ -494,8 +494,8 @@
this.code_lengths[i] = rep_symbol
i += 1
rep_count -= 1
- }
- }
+ } endwhile
+ } endwhile
if i <> (n_lit + n_dist) {
return "#bad Huffman code length count"
@@ -588,7 +588,7 @@
}
counts[this.code_lengths[i] & 15] += 1
i += 1
- }
+ } endwhile
if ((counts[0] as base.u32) + args.n_codes0) == args.n_codes1 {
return "#no Huffman codes"
}
@@ -607,7 +607,7 @@
}
remaining -= counts[i] as base.u32
i += 1
- }
+ } endwhile
if remaining <> 0 {
// As a special case, allow a degenerate H-D Huffman table, with only
// one 1-bit code, for the smallest possible distance.
@@ -648,7 +648,7 @@
// bounds checking can handle it.
n_symbols = n_symbols + count
i += 1
- }
+ } endwhile
if n_symbols > 288 {
return "#internal error: inconsistent Huffman decoder state"
}
@@ -688,7 +688,7 @@
offsets[this.code_lengths[i] & 15] += 1
}
i += 1
- }
+ } endwhile
// Calculate min_cl and max_cl.
//
@@ -706,7 +706,7 @@
return "#bad Huffman minimum code length"
}
min_cl += 1
- }
+ } endwhile
max_cl = 15
while true,
inv n_symbols <= 288,
@@ -718,7 +718,7 @@
return "#no Huffman codes"
}
max_cl -= 1
- }
+ } endwhile
if max_cl <= 9 {
this.n_huffs_bits[args.which] = max_cl
} else {
@@ -806,7 +806,7 @@
}
remaining <<= 1
j += 1
- }
+ } endwhile
if (j <= 9) or (15 < j) {
return "#internal error: inconsistent Huffman decoder state"
}
@@ -867,7 +867,7 @@
}
assert (top + ((high_bits | reversed_key) & 511)) < 1024 via "a < b: a < c; c <= b"(c: huffs_table_size)
this.huffs[args.which][top + ((high_bits | reversed_key) & 511)] = value
- }
+ } endwhile
i += 1
if i >= n_symbols {
@@ -878,6 +878,6 @@
if code >= (1 << 15) {
return "#internal error: inconsistent Huffman decoder state"
}
- }
+ } endwhile
return ok
}
diff --git a/std/deflate/decode_huffman_fast.wuffs b/std/deflate/decode_huffman_fast.wuffs
index a803456..c9f7e0a 100644
--- a/std/deflate/decode_huffman_fast.wuffs
+++ b/std/deflate/decode_huffman_fast.wuffs
@@ -341,7 +341,7 @@
// Copy from args.dst.
args.dst.copy_n32_from_history_fast!(n: length, distance: (dist_minus_1 + 1))
break
- }
+ } endwhile
} endwhile.loop
// Ensure n_bits < 8 by rewindng args.src, if we loaded too many of its
@@ -363,7 +363,7 @@
} else {
return "#internal error: inconsistent I/O"
}
- }
+ } endwhile
this.bits = bits & (((1 as base.u32) << n_bits) - 1)
this.n_bits = n_bits
diff --git a/std/deflate/decode_huffman_slow.wuffs b/std/deflate/decode_huffman_slow.wuffs
index 934964e..1166fd5 100644
--- a/std/deflate/decode_huffman_slow.wuffs
+++ b/std/deflate/decode_huffman_slow.wuffs
@@ -62,7 +62,7 @@
b0 = args.src.read_u8_as_u32?()
bits |= b0 << n_bits
n_bits += 8
- }
+ } endwhile
if (table_entry >> 31) <> 0 {
// Literal.
@@ -90,7 +90,7 @@
b1 = args.src.read_u8_as_u32?()
bits |= b1 << n_bits
n_bits += 8
- }
+ } endwhile
if (table_entry >> 31) <> 0 {
// Literal.
@@ -130,7 +130,7 @@
b2 = args.src.read_u8_as_u32?()
bits |= b2 << n_bits
n_bits += 8
- }
+ } endwhile
// The "+ 253" is the same as "- 3", after the "& 0xFF", but the
// plus form won't require an underflow check.
length = ((length + 253 + bits.low_bits(n: table_entry_n_bits)) & 0xFF) + 3
@@ -151,7 +151,7 @@
b3 = args.src.read_u8_as_u32?()
bits |= b3 << n_bits
n_bits += 8
- }
+ } endwhile
// Check for a redirect.
if (table_entry >> 28) == 1 {
redir_top = (table_entry >> 8) & 0xFFFF
@@ -168,7 +168,7 @@
b4 = args.src.read_u8_as_u32?()
bits |= b4 << n_bits
n_bits += 8
- }
+ } endwhile
}
// For H-D, all symbols should be base_number + extra_bits.
@@ -195,7 +195,7 @@
b5 = args.src.read_u8_as_u32?()
bits |= b5 << n_bits
n_bits += 8
- }
+ } endwhile
dist_minus_1 = (dist_minus_1 + bits.low_bits(n: table_entry_n_bits)) & 0x7FFF
bits >>= table_entry_n_bits
n_bits -= table_entry_n_bits
@@ -241,7 +241,7 @@
}
}
yield? base."$short write"
- }
+ } endwhile
// Copy from the start of this.history, if we wrapped around.
if hlen > 0 {
while true {
@@ -254,7 +254,7 @@
hlen -= n_copied
hdist ~mod+= n_copied
yield? base."$short write"
- }
+ } endwhile
}
if length == 0 {
@@ -271,7 +271,7 @@
}
length -= n_copied
yield? base."$short write"
- }
+ } endwhile
} endwhile.loop
// TODO: "assert n_bits < 8"? What about (bits >> n_bits)?
diff --git a/std/gif/decode_config.wuffs b/std/gif/decode_config.wuffs
index 235bdf8..f86ec9c 100644
--- a/std/gif/decode_config.wuffs
+++ b/std/gif/decode_config.wuffs
@@ -180,9 +180,9 @@
}
pub func config_decoder.set_report_metadata!(fourcc: base.u32, report: base.bool) {
- if args.fourcc == 0x4943_4350 { // "ICCP"
+ if args.fourcc == 'ICCP'be {
this.report_metadata_iccp = args.report
- } else if args.fourcc == 0x584D_5020 { // "XMP "
+ } else if args.fourcc == 'XMP 'be {
this.report_metadata_xmp = args.report
}
}
@@ -200,11 +200,11 @@
post args.src.available() > 0,
{
yield? base."$short read"
- }
+ } endwhile
this.metadata_chunk_length_value = args.src.peek_u8_as_u64()
if this.metadata_chunk_length_value > 0 {
- if this.metadata_fourcc_value == 0x584D_5020 { // "XMP "
+ if this.metadata_fourcc_value == 'XMP 'be {
// 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.
@@ -308,7 +308,7 @@
post args.src.available() > 0,
{
yield? base."$short read"
- }
+ } endwhile
flags = args.src.peek_u8()
if (flags & 0x80) <> 0 {
background_color = this.black_color_u32_argb_premul
@@ -413,7 +413,7 @@
} else {
return "#bad block"
}
- }
+ } endwhile
}
// decode_header reads either "GIF87a" or "GIF89a".
@@ -426,9 +426,9 @@
while i < 6 {
c[i] = args.src.read_u8?()
i += 1
- }
- if (c[0] <> 0x47) or (c[1] <> 0x49) or (c[2] <> 0x46) or (c[3] <> 0x38) or
- ((c[4] <> 0x37) and (c[4] <> 0x39)) or (c[5] <> 0x61) {
+ } endwhile
+ if (c[0] <> 'G') or (c[1] <> 'I') or (c[2] <> 'F') or (c[3] <> '8') or
+ ((c[4] <> '7') and (c[4] <> '9')) or (c[5] <> 'a') {
return "#bad header"
}
}
@@ -467,7 +467,7 @@
this.palettes[0][(4 * i) + 2] = ((argb >> 16) & 0xFF) as base.u8
this.palettes[0][(4 * i) + 3] = ((argb >> 24) & 0xFF) as base.u8
i += 1
- }
+ } endwhile
if this.quirk_enabled_honor_background_color {
if (background_color_index <> 0) and
@@ -496,7 +496,7 @@
this.palettes[0][(4 * i) + 2] = 0x00
this.palettes[0][(4 * i) + 3] = 0xFF
i += 1
- }
+ } endwhile
}
// decode_extension reads an extension. The Extension Introducer byte has
@@ -532,7 +532,7 @@
return ok
}
args.src.skip32?(n: block_size as base.u32)
- }
+ } endwhile
}
// decode_ae reads an Application Extension.
@@ -544,9 +544,7 @@
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.
- while true {
+ while.goto_done true {
block_size = args.src.read_u8?()
if block_size == 0 {
return ok
@@ -560,7 +558,7 @@
// Other extensions include XMP metadata.
if block_size <> 11 {
args.src.skip32?(n: block_size as base.u32)
- break
+ break.goto_done
}
is_animexts = true
is_netscape = true
@@ -574,7 +572,7 @@
is_iccp = is_iccp and (c == iccrgbg1012[block_size])
is_xmp = is_xmp and (c == xmpdataxmp[block_size])
block_size += 1
- }
+ } endwhile
if is_animexts or is_netscape {
// Those 11 bytes should be followed by 0x03, 0x01 and then the loop
@@ -582,12 +580,12 @@
block_size = args.src.read_u8?()
if block_size <> 3 {
args.src.skip32?(n: block_size as base.u32)
- break
+ break.goto_done
}
c = args.src.read_u8?()
if c <> 0x01 {
args.src.skip32?(n: 2)
- break
+ break.goto_done
}
this.num_loops = args.src.read_u16le_as_u32?()
this.seen_num_loops = true
@@ -614,10 +612,10 @@
post args.src.available() > 0,
{
yield? base."$short read"
- }
+ } endwhile
this.metadata_chunk_length_value = args.src.peek_u8_as_u64()
args.src.skip32_fast!(actual: 1, worst_case: 1)
- this.metadata_fourcc_value = 0x4943_4350 // "ICCP"
+ this.metadata_fourcc_value = 'ICCP'be
this.metadata_io_position = args.src.position() ~sat+ this.metadata_chunk_length_value
this.call_sequence = 1
return base."@metadata reported"
@@ -627,7 +625,7 @@
post args.src.available() > 0,
{
yield? base."$short read"
- }
+ } endwhile
this.metadata_chunk_length_value = args.src.peek_u8_as_u64()
if this.metadata_chunk_length_value > 0 {
// The +1 is because XMP metadata's encoding includes each
@@ -637,14 +635,14 @@
} else {
args.src.skip32_fast!(actual: 1, worst_case: 1)
}
- this.metadata_fourcc_value = 0x584D_5020 // "XMP "
+ this.metadata_fourcc_value = 'XMP 'be
this.metadata_io_position = args.src.position() ~sat+ this.metadata_chunk_length_value
this.call_sequence = 1
return base."@metadata reported"
}
- break
- }
+ break.goto_done
+ } endwhile.goto_done
this.skip_blocks?(src: args.src)
}
diff --git a/std/gif/decode_gif.wuffs b/std/gif/decode_gif.wuffs
index 4f98771..0d56bda 100644
--- a/std/gif/decode_gif.wuffs
+++ b/std/gif/decode_gif.wuffs
@@ -219,9 +219,9 @@
}
pub func decoder.set_report_metadata!(fourcc: base.u32, report: base.bool) {
- if args.fourcc == 0x4943_4350 { // "ICCP"
+ if args.fourcc == 'ICCP'be {
this.report_metadata_iccp = args.report
- } else if args.fourcc == 0x584D_5020 { // "XMP "
+ } else if args.fourcc == 'XMP 'be {
this.report_metadata_xmp = args.report
}
}
@@ -239,11 +239,11 @@
post args.src.available() > 0,
{
yield? base."$short read"
- }
+ } endwhile
this.metadata_chunk_length_value = args.src.peek_u8_as_u64()
if this.metadata_chunk_length_value > 0 {
- if this.metadata_fourcc_value == 0x584D_5020 { // "XMP "
+ if this.metadata_fourcc_value == 'XMP 'be {
// 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.
@@ -367,7 +367,7 @@
post args.src.available() > 0,
{
yield? base."$short read"
- }
+ } endwhile
flags = args.src.peek_u8()
if (flags & 0x80) <> 0 {
background_color = this.black_color_u32_argb_premul
@@ -488,7 +488,7 @@
} else {
return "#bad block"
}
- }
+ } endwhile
}
// decode_header reads either "GIF87a" or "GIF89a".
@@ -501,9 +501,9 @@
while i < 6 {
c[i] = args.src.read_u8?()
i += 1
- }
- if (c[0] <> 0x47) or (c[1] <> 0x49) or (c[2] <> 0x46) or (c[3] <> 0x38) or
- ((c[4] <> 0x37) and (c[4] <> 0x39)) or (c[5] <> 0x61) {
+ } endwhile
+ if (c[0] <> 'G') or (c[1] <> 'I') or (c[2] <> 'F') or (c[3] <> '8') or
+ ((c[4] <> '7') and (c[4] <> '9')) or (c[5] <> 'a') {
return "#bad header"
}
}
@@ -542,7 +542,7 @@
this.palettes[0][(4 * i) + 2] = ((argb >> 16) & 0xFF) as base.u8
this.palettes[0][(4 * i) + 3] = ((argb >> 24) & 0xFF) as base.u8
i += 1
- }
+ } endwhile
if this.quirk_enabled_honor_background_color {
if (background_color_index <> 0) and
@@ -571,7 +571,7 @@
this.palettes[0][(4 * i) + 2] = 0x00
this.palettes[0][(4 * i) + 3] = 0xFF
i += 1
- }
+ } endwhile
}
// decode_extension reads an extension. The Extension Introducer byte has
@@ -607,7 +607,7 @@
return ok
}
args.src.skip32?(n: block_size as base.u32)
- }
+ } endwhile
}
// decode_ae reads an Application Extension.
@@ -619,9 +619,7 @@
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.
- while true {
+ while.goto_done true {
block_size = args.src.read_u8?()
if block_size == 0 {
return ok
@@ -635,7 +633,7 @@
// Other extensions include XMP metadata.
if block_size <> 11 {
args.src.skip32?(n: block_size as base.u32)
- break
+ break.goto_done
}
is_animexts = true
is_netscape = true
@@ -649,7 +647,7 @@
is_iccp = is_iccp and (c == iccrgbg1012[block_size])
is_xmp = is_xmp and (c == xmpdataxmp[block_size])
block_size += 1
- }
+ } endwhile
if is_animexts or is_netscape {
// Those 11 bytes should be followed by 0x03, 0x01 and then the loop
@@ -657,12 +655,12 @@
block_size = args.src.read_u8?()
if block_size <> 3 {
args.src.skip32?(n: block_size as base.u32)
- break
+ break.goto_done
}
c = args.src.read_u8?()
if c <> 0x01 {
args.src.skip32?(n: 2)
- break
+ break.goto_done
}
this.num_loops = args.src.read_u16le_as_u32?()
this.seen_num_loops = true
@@ -689,10 +687,10 @@
post args.src.available() > 0,
{
yield? base."$short read"
- }
+ } endwhile
this.metadata_chunk_length_value = args.src.peek_u8_as_u64()
args.src.skip32_fast!(actual: 1, worst_case: 1)
- this.metadata_fourcc_value = 0x4943_4350 // "ICCP"
+ this.metadata_fourcc_value = 'ICCP'be
this.metadata_io_position = args.src.position() ~sat+ this.metadata_chunk_length_value
this.call_sequence = 1
return base."@metadata reported"
@@ -702,7 +700,7 @@
post args.src.available() > 0,
{
yield? base."$short read"
- }
+ } endwhile
this.metadata_chunk_length_value = args.src.peek_u8_as_u64()
if this.metadata_chunk_length_value > 0 {
// The +1 is because XMP metadata's encoding includes each
@@ -712,14 +710,14 @@
} else {
args.src.skip32_fast!(actual: 1, worst_case: 1)
}
- this.metadata_fourcc_value = 0x584D_5020 // "XMP "
+ this.metadata_fourcc_value = 'XMP 'be
this.metadata_io_position = args.src.position() ~sat+ this.metadata_chunk_length_value
this.call_sequence = 1
return base."@metadata reported"
}
- break
- }
+ break.goto_done
+ } endwhile.goto_done
this.skip_blocks?(src: args.src)
}
@@ -836,7 +834,7 @@
this.palettes[1][(4 * i) + 2] = ((argb >> 16) & 0xFF) as base.u8
this.palettes[1][(4 * i) + 3] = ((argb >> 24) & 0xFF) as base.u8
i += 1
- }
+ } endwhile
// Set the remaining palette entries to opaque black.
while i < 256 {
this.palettes[1][(4 * i) + 0] = 0x00
@@ -844,7 +842,7 @@
this.palettes[1][(4 * i) + 2] = 0x00
this.palettes[1][(4 * i) + 3] = 0xFF
i += 1
- }
+ } endwhile
} else if this.quirk_enabled_reject_empty_palette and (not this.has_global_palette) {
return "#bad palette"
} else if this.gc_has_transparent_index {
@@ -931,7 +929,7 @@
}
while args.src.available() == 0 {
yield? base."$short read"
- }
+ } endwhile
if this.compressed_ri == this.compressed_wi {
this.compressed_ri = 0
@@ -955,7 +953,7 @@
}
block_size = args.src.peek_u8_as_u64()
args.src.skip32_fast!(actual: 1, worst_case: 1)
- }
+ } endwhile
while.inner true {
if (this.compressed_ri > this.compressed_wi) or (this.compressed_wi > 4096) {
@@ -1098,7 +1096,7 @@
replicate_dst = tab.row(y: replicate_y0)
replicate_dst.copy_from_slice!(s: replicate_src)
replicate_y0 += 1
- }
+ } endwhile
this.dirty_max_excl_y = this.dirty_max_excl_y.max(a: replicate_y1)
}
@@ -1106,7 +1104,7 @@
while (this.interlace > 0) and (this.dst_y >= this.frame_rect_y1) {
this.interlace -= 1
this.dst_y = this.frame_rect_y0 ~sat+ interlace_start[this.interlace]
- }
+ } endwhile
continue
}
@@ -1132,7 +1130,7 @@
while (this.interlace > 0) and (this.dst_y >= this.frame_rect_y1) {
this.interlace -= 1
this.dst_y = this.frame_rect_y0 ~sat+ interlace_start[this.interlace]
- }
+ } endwhile
continue
}
@@ -1140,7 +1138,7 @@
return "#internal error: inconsistent ri/wi"
}
break
- }
+ } endwhile
return ok
}
//#DONE PREPROC900
diff --git a/std/gzip/decode_gzip.wuffs b/std/gzip/decode_gzip.wuffs
index c5dfb76..0664003 100644
--- a/std/gzip/decode_gzip.wuffs
+++ b/std/gzip/decode_gzip.wuffs
@@ -87,7 +87,7 @@
if c == 0 {
break
}
- }
+ } endwhile
}
// Handle FCOMMENT.
@@ -97,7 +97,7 @@
if c == 0 {
break
}
- }
+ } endwhile
}
// Handle FHCRC.
@@ -122,7 +122,7 @@
break
}
yield? status
- }
+ } endwhile
checksum_want = args.src.read_u32le?()
decoded_length_want = args.src.read_u32le?()
if (not this.ignore_checksum) and
diff --git a/std/json/common_consts.wuffs b/std/json/common_consts.wuffs
index 553768d..10c7efe 100644
--- a/std/json/common_consts.wuffs
+++ b/std/json/common_consts.wuffs
@@ -21,6 +21,8 @@
pri status "#internal error: inconsistent I/O"
+pub const decoder_workbuf_len_max_incl_worst_case base.u64 = 0
+
// decoder_depth_max_incl is the maximum supported recursion depth: how deeply
// nested [] arrays and {} objects can be.
//
@@ -56,6 +58,24 @@
// Look-Up Tables (LUTs).
+// lut_backslashes[i] helps decode "\i", for various 'i's.
+//
+// If the element's 0x80 bit is set then "\i" is unconditionally a valid
+// single-output-byte backslash-escape. The low 7 bits are the unescaped value.
+// For example, lut_backslashes['n'] is (0x80 | 0x0A), because "\n" is U+000A.
+//
+// If the element is non-zero (but the 0x80 bit is not set) then "\i"'s
+// validity depends on the relevant quirk. The element's value is an enum:
+// - 1: "\a", U+0007, quirk_allow_backslash_a.
+// - 2: "\e", U+001B, quirk_allow_backslash_e.
+// - 3: "\?", U+003F, quirk_allow_backslash_question_mark.
+// - 4: "\'", U+0027, quirk_allow_backslash_single_quote.
+// - 5: "\v", U+000B, quirk_allow_backslash_v.
+// - 6: "\0", U+0000, quirk_allow_backslash_zero.
+// The U+1234 values are held in lut_quirky_backslashes, below.
+//
+// If the element is zero then "\i" is invalid, or it is a special case, the
+// start of "\x12", "\u1234" or "\U12345678".
pri const lut_backslashes array[256] base.u8 = [
// 0 1 2 3 4 5 6 7
// 8 9 A B C D E F
@@ -63,18 +83,18 @@
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x08 ..= 0x0F.
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x10 ..= 0x17.
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x18 ..= 0x1F.
- 0x00, 0x00, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x20 ..= 0x27. '"'.
+ 0x00, 0x00, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x04, // 0x20 ..= 0x27. '"', '\''.
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAF, // 0x28 ..= 0x2F. '/'.
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x30 ..= 0x37.
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x38 ..= 0x3F.
+ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x30 ..= 0x37. '0'.
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, // 0x38 ..= 0x3F. '?'
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x40 ..= 0x47.
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x48 ..= 0x4F.
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x50 ..= 0x57.
0x00, 0x00, 0x00, 0x00, 0xDC, 0x00, 0x00, 0x00, // 0x58 ..= 0x5F. '\\'.
- 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x8C, 0x00, // 0x60 ..= 0x67. 'b', 'f'.
+ 0x00, 0x01, 0x88, 0x00, 0x00, 0x02, 0x8C, 0x00, // 0x60 ..= 0x67. 'a', 'b', 'e', 'f'.
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x00, // 0x68 ..= 0x6F. 'n'.
- 0x00, 0x00, 0x8D, 0x00, 0x89, 0x00, 0x00, 0x00, // 0x70 ..= 0x77. 'r', 't'.
+ 0x00, 0x00, 0x8D, 0x00, 0x89, 0x00, 0x05, 0x00, // 0x70 ..= 0x77. 'r', 't', 'v'.
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x78 ..= 0x7F.
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x80 ..= 0x87.
@@ -98,6 +118,13 @@
// 8 9 A B C D E F
]
+// lut_quirky_backslashes is discussed in the lut_backslashes comment. The
+// first and last elements (indexes 0 and 7) are not used, but 8 is a round
+// power of 2, so enforcing index-in-bounds is a simple "&7" operation.
+pri const lut_quirky_backslashes array[8] base.u8 = [
+ 0x00, 0x07, 0x1B, 0x3F, 0x27, 0x0B, 0x00, 0x00,
+]
+
// lut_chars helps decode bytes within a string:
// - 0x00 is 1-byte UTF-8 (ASCII) but not '"', '\\' or a C0 control code.
// - 0x01 is '"'.
@@ -171,8 +198,8 @@
// - 0x08 (bitmask 0x0100) is CLASS_CLOSE_SQUARE_BRACKET.
// - 0x09 (bitmask 0x0200) is CLASS_FALSE.
// - 0x0A (bitmask 0x0400) is CLASS_TRUE.
-// - 0x0B (bitmask 0x0800) is CLASS_NULL.
-// - 0x0C (bitmask 0x1000) is reserved.
+// - 0x0B (bitmask 0x0800) is CLASS_NULL_NAN_INF.
+// - 0x0C (bitmask 0x1000) is CLASS_COMMENT.
// - 0x0D (bitmask 0x2000) is reserved.
// - 0x0E (bitmask 0x4000) is reserved.
// - 0x0F (bitmask 0x8000) is CLASS_BAD_INPUT.
@@ -180,26 +207,29 @@
// The bitmasks are used by the "expect" variable: what the next character
// class can be.
//
-// - 0x0002 is EXPECT_STRING.
-// - 0x0EB0 is EXPECT_NON_STRING_VALUE.
-// - 0x0004 is EXPECT_COMMA.
-// - 0x0008 is EXPECT_COLON.
-// - 0x0040 is EXPECT_CLOSE_CURLY_BRACE.
-// - 0x0100 is EXPECT_CLOSE_SQUARE_BRACKET.
+// - 0x1002 is EXPECT_STRING.
+// - 0x1EB0 is EXPECT_NON_STRING_VALUE.
+// - 0x1004 is EXPECT_COMMA.
+// - 0x1008 is EXPECT_COLON.
+// - 0x1040 is EXPECT_CLOSE_CURLY_BRACE.
+// - 0x1100 is EXPECT_CLOSE_SQUARE_BRACKET.
//
// Bitwise or'ing these together gives 0x0FFE. Whitespace is never expected, as
// it is handled separately.
//
-// EXPECT_VALUE is also defined to be 0x0EB2, equivalent to (EXPECT_STRING |
+// EXPECT_VALUE is also defined to be 0x1EB2, equivalent to (EXPECT_STRING |
// EXPECT_NON_STRING_VALUE).
//
-// EXPECT_NUMBER is also defined to be 0x0010. Testing for EXPECT_NUMBER's
+// EXPECT_NUMBER is also defined to be 0x1010. Testing for EXPECT_NUMBER's
// presence is equivalent to testing for EXPECT_NON_STRING_VALUE.
//
// "Non-string value" includes literals (false, true, null), numbers, arrays
// and objects.
//
// "String value" includes "this" and "th\u0061t".
+//
+// Comments are always expected. Whether the relevant quirks are enabled are
+// checked elsewhere.
pri const lut_classes array[256] base.u8[..= 0x0F] = [
// 0 1 2 3 4 5 6 7
// 8 9 A B C D E F
@@ -208,16 +238,16 @@
0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, // 0x10 ..= 0x17.
0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, // 0x18 ..= 0x1F.
0x00, 0x0F, 0x01, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, // 0x20 ..= 0x27. ' ', '"'.
- 0x0F, 0x0F, 0x0F, 0x0F, 0x02, 0x04, 0x0F, 0x0F, // 0x28 ..= 0x2F. ',', '-'.
+ 0x0F, 0x0F, 0x0F, 0x0B, 0x02, 0x04, 0x0F, 0x0C, // 0x28 ..= 0x2F. '+', ',', '-', '/'.
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, // 0x30 ..= 0x37. '0'-'7'.
0x04, 0x04, 0x03, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, // 0x38 ..= 0x3F. '8'-'9', ':'.
0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, // 0x40 ..= 0x47.
- 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, // 0x48 ..= 0x4F.
+ 0x0F, 0x0B, 0x0F, 0x0F, 0x0F, 0x0F, 0x0B, 0x0F, // 0x48 ..= 0x4F. 'I', 'N'.
0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, // 0x50 ..= 0x57.
0x0F, 0x0F, 0x0F, 0x07, 0x0F, 0x08, 0x0F, 0x0F, // 0x58 ..= 0x5F. '[', ']'.
0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x09, 0x0F, // 0x60 ..= 0x67. 'f'.
- 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0B, 0x0F, // 0x68 ..= 0x6F. 'n'.
+ 0x0F, 0x0B, 0x0F, 0x0F, 0x0F, 0x0F, 0x0B, 0x0F, // 0x68 ..= 0x6F. 'i', 'n'.
0x0F, 0x0F, 0x0F, 0x0F, 0x0A, 0x0F, 0x0F, 0x0F, // 0x70 ..= 0x77. 't'.
0x0F, 0x0F, 0x0F, 0x05, 0x0F, 0x06, 0x0F, 0x0F, // 0x78 ..= 0x7F. '{', '}'.
diff --git a/std/json/decode_json.wuffs b/std/json/decode_json.wuffs
index 36aa2db..f2465fd 100644
--- a/std/json/decode_json.wuffs
+++ b/std/json/decode_json.wuffs
@@ -13,6 +13,27 @@
// limitations under the License.
pub struct decoder? implements base.token_decoder(
+ // quirk_enabled_allow_backslash_etc, an 8-element array, is indexed by the
+ // same enum as lut_quirky_backslashes.
+ quirk_enabled_allow_backslash_etc : array[8] base.bool,
+
+ quirk_enabled_allow_backslash_capital_u : base.bool,
+ quirk_enabled_allow_backslash_x : base.bool,
+ quirk_enabled_allow_comment_block : base.bool,
+ quirk_enabled_allow_comment_line : base.bool,
+ quirk_enabled_allow_extra_comma : base.bool,
+ quirk_enabled_allow_inf_nan_numbers : base.bool,
+ quirk_enabled_allow_leading_ascii_record_separator : base.bool,
+ quirk_enabled_allow_leading_unicode_byte_order_mark : base.bool,
+ quirk_enabled_allow_trailing_new_line : base.bool,
+ quirk_enabled_replace_invalid_unicode : base.bool,
+
+ allow_leading_ars : base.bool,
+ allow_leading_ubom : base.bool,
+
+ end_of_data : base.bool,
+
+ util : base.utility,
)(
// stack is conceptually an array of bits, implemented as an array of u32.
// The N'th bit being 0 or 1 means that we're in an array or object, where
@@ -45,7 +66,47 @@
stack : array[1024 / 32] base.u32,
)
-pub func decoder.decode_tokens?(dst: base.token_writer, src: base.io_reader) {
+pub func decoder.set_quirk_enabled!(quirk: base.u32, enabled: base.bool) {
+ if args.quirk == quirk_allow_backslash_a {
+ this.quirk_enabled_allow_backslash_etc[1] = args.enabled
+ } else if args.quirk == quirk_allow_backslash_capital_u {
+ this.quirk_enabled_allow_backslash_capital_u = args.enabled
+ } else if args.quirk == quirk_allow_backslash_e {
+ this.quirk_enabled_allow_backslash_etc[2] = args.enabled
+ } else if args.quirk == quirk_allow_backslash_question_mark {
+ this.quirk_enabled_allow_backslash_etc[3] = args.enabled
+ } else if args.quirk == quirk_allow_backslash_single_quote {
+ this.quirk_enabled_allow_backslash_etc[4] = args.enabled
+ } else if args.quirk == quirk_allow_backslash_v {
+ this.quirk_enabled_allow_backslash_etc[5] = args.enabled
+ } else if args.quirk == quirk_allow_backslash_x {
+ this.quirk_enabled_allow_backslash_x = args.enabled
+ } else if args.quirk == quirk_allow_backslash_zero {
+ this.quirk_enabled_allow_backslash_etc[6] = args.enabled
+ } else if args.quirk == quirk_allow_comment_block {
+ this.quirk_enabled_allow_comment_block = args.enabled
+ } else if args.quirk == quirk_allow_comment_line {
+ this.quirk_enabled_allow_comment_line = args.enabled
+ } else if args.quirk == quirk_allow_extra_comma {
+ this.quirk_enabled_allow_extra_comma = args.enabled
+ } else if args.quirk == quirk_allow_inf_nan_numbers {
+ this.quirk_enabled_allow_inf_nan_numbers = args.enabled
+ } else if args.quirk == quirk_allow_leading_ascii_record_separator {
+ this.quirk_enabled_allow_leading_ascii_record_separator = args.enabled
+ } else if args.quirk == quirk_allow_leading_unicode_byte_order_mark {
+ this.quirk_enabled_allow_leading_unicode_byte_order_mark = args.enabled
+ } else if args.quirk == quirk_allow_trailing_new_line {
+ this.quirk_enabled_allow_trailing_new_line = args.enabled
+ } else if args.quirk == quirk_replace_invalid_unicode {
+ this.quirk_enabled_replace_invalid_unicode = args.enabled
+ }
+}
+
+pub func decoder.workbuf_len() base.range_ii_u64 {
+ return this.util.empty_range_ii_u64()
+}
+
+pub func decoder.decode_tokens?(dst: base.token_writer, src: base.io_reader, workbuf: slice base.u8) {
var vminor : base.u32[..= 0xFF_FFFF]
var number_length : base.u32[..= 0x3FF]
var number_status : base.u32[..= 0x3]
@@ -55,18 +116,25 @@
var stack_byte : base.u32[..= (1024 / 32) - 1]
var stack_bit : base.u32[..= 31]
var match : base.u32[..= 2]
- var c_by_4 : base.u32
+ var c4 : base.u32
var c : base.u8
var backslash : base.u8
var char : base.u8
var class : base.u8[..= 0x0F]
var multi_byte_utf8 : base.u32
+ var backslash_x_length : base.u32[..= 0xFFFF]
+ var backslash_x_ok : base.u8
+ var backslash_x_string : base.u32
+
var uni4_ok : base.u8
var uni4_string : base.u64
var uni4_value : base.u32[..= 0xFFFF]
var uni4_high_surrogate : base.u32[..= 0x10_FC00]
- var uni4_rollback : base.u32
+
+ var uni8_ok : base.u8
+ var uni8_string : base.u64
+ var uni8_value : base.u32[..= 0xFFFF_FFFF]
// expect is a bitmask of what the next character class can be.
//
@@ -77,7 +145,16 @@
var expect : base.u32
var expect_after_value : base.u32
- expect = 0x0EB2 // EXPECT_VALUE
+ while this.end_of_data {
+ return base."@end of data"
+ } endwhile
+
+ if this.quirk_enabled_allow_leading_ascii_record_separator or
+ this.quirk_enabled_allow_leading_unicode_byte_order_mark {
+ this.decode_leading?(dst: args.dst, src: args.src)
+ }
+
+ expect = 0x1EB2 // EXPECT_VALUE
while.outer true {
while.goto_parsed_a_leaf_value true {
@@ -197,11 +274,11 @@
inv args.dst.available() > 0,
inv args.src.available() > 0,
{
- c_by_4 = args.src.peek_u32le()
- if 0x00 <> (lut_chars[0xFF & (c_by_4 >> 0)] |
- lut_chars[0xFF & (c_by_4 >> 8)] |
- lut_chars[0xFF & (c_by_4 >> 16)] |
- lut_chars[0xFF & (c_by_4 >> 24)]) {
+ c4 = args.src.peek_u32le()
+ if 0x00 <> (lut_chars[0xFF & (c4 >> 0)] |
+ lut_chars[0xFF & (c4 >> 8)] |
+ lut_chars[0xFF & (c4 >> 16)] |
+ lut_chars[0xFF & (c4 >> 24)]) {
break
}
args.src.skip32_fast!(actual: 4, worst_case: 4)
@@ -215,7 +292,7 @@
continue.string_loop_outer
}
string_length += 4
- }
+ } endwhile
c = args.src.peek_u8()
char = lut_chars[c]
@@ -270,7 +347,7 @@
}
c = (args.src.peek_u16le() >> 8) as base.u8
backslash = lut_backslashes[c]
- if backslash > 0 {
+ if (backslash & 0x80) <> 0 {
args.src.skip32_fast!(actual: 2, worst_case: 2)
args.dst.write_fast_token!(
value_major: 0,
@@ -279,7 +356,18 @@
length: 2)
continue.string_loop_outer
- } else if c == 0x75 { // 0x75 is 'u'.
+ } else if backslash <> 0 {
+ if this.quirk_enabled_allow_backslash_etc[backslash & 7] {
+ args.src.skip32_fast!(actual: 2, worst_case: 2)
+ args.dst.write_fast_token!(
+ value_major: 0,
+ value_minor: 0x60_0000 | (lut_quirky_backslashes[backslash & 7] as base.u32),
+ link: 0x3,
+ length: 2)
+ continue.string_loop_outer
+ }
+
+ } else if c == 'u' {
// -------- BEGIN backslash-u.
if args.src.available() < 6 {
if args.src.is_closed() {
@@ -331,9 +419,19 @@
// High surrogate, which needs to be
// followed by a "\\u1234" low surrogate.
// We've already peeked 6 bytes for the
- // high surrogate. We need another 6.
+ // high surrogate. We need 12 in total:
+ // another 8 bytes at an offset of 4.
if args.src.available() < 12 {
if args.src.is_closed() {
+ if this.quirk_enabled_replace_invalid_unicode {
+ args.src.skip32_fast!(actual: 6, worst_case: 6)
+ args.dst.write_fast_token!(
+ value_major: 0,
+ value_minor: 0x60_FFFD,
+ link: 0x3,
+ length: 6)
+ continue.string_loop_outer
+ }
return "#bad backslash-escape"
}
yield? base."$short read"
@@ -342,16 +440,11 @@
char = 0
continue.string_loop_outer
}
-
- // Roll forward 4 bytes, so that calling
- // peek_u64le will pick up the last 8.
- args.src.skip32_fast!(actual: 4, worst_case: 4)
-
- uni4_string = args.src.peek_u64le() >> 16
+ uni4_string = args.src.peek_u64le_at(offset: 4) >> 16
// Look for the low surrogate's "\\u".
- if ((0xFF & (uni4_string >> 0)) <> 0x5C) or
- ((0xFF & (uni4_string >> 8)) <> 0x75) {
+ if ((0xFF & (uni4_string >> 0)) <> '\\') or
+ ((0xFF & (uni4_string >> 8)) <> 'u') {
uni4_high_surrogate = 0
uni4_value = 0
uni4_ok = 0
@@ -381,30 +474,142 @@
// Emit a single token for the surrogate pair.
uni4_value -= 0xDC00
- args.src.skip32_fast!(actual: 8, worst_case: 8)
+ args.src.skip32_fast!(actual: 12, worst_case: 12)
args.dst.write_fast_token!(
value_major: 0,
value_minor: 0x60_0000 | uni4_high_surrogate | uni4_value,
link: 0x3,
length: 12)
continue.string_loop_outer
-
- } else {
- // Roll back the 4 bytes, then fall
- // through to "#invalid
- // backslash-escape".
- uni4_rollback = 4
- while uni4_rollback > 0 {
- uni4_rollback -= 1
- if args.src.can_undo_byte() {
- args.src.undo_byte!()
- } else {
- return "#internal error: inconsistent I/O"
- }
- }
}
}
+
+ if this.quirk_enabled_replace_invalid_unicode {
+ if args.src.available() < 6 {
+ return "#internal error: inconsistent I/O"
+ }
+ args.src.skip32_fast!(actual: 6, worst_case: 6)
+ args.dst.write_fast_token!(
+ value_major: 0,
+ value_minor: 0x60_FFFD,
+ link: 0x3,
+ length: 6)
+ continue.string_loop_outer
+ }
// -------- END backslash-u.
+
+ } else if (c == 'U') and
+ this.quirk_enabled_allow_backslash_capital_u {
+ // -------- BEGIN backslash-capital-u.
+ if args.src.available() < 10 {
+ if args.src.is_closed() {
+ return "#bad backslash-escape"
+ }
+ yield? base."$short read"
+ string_length = 0
+ char = 0
+ continue.string_loop_outer
+ }
+ uni8_string = args.src.peek_u64le_at(offset: 2)
+ uni8_value = 0
+ uni8_ok = 0x80
+
+ c = lut_hexadecimal_digits[0xFF & (uni8_string >> 0)]
+ uni8_ok &= c
+ uni8_value |= ((c & 0x0F) as base.u32) << 28
+ c = lut_hexadecimal_digits[0xFF & (uni8_string >> 8)]
+ uni8_ok &= c
+ uni8_value |= ((c & 0x0F) as base.u32) << 24
+ c = lut_hexadecimal_digits[0xFF & (uni8_string >> 16)]
+ uni8_ok &= c
+ uni8_value |= ((c & 0x0F) as base.u32) << 20
+ c = lut_hexadecimal_digits[0xFF & (uni8_string >> 24)]
+ uni8_ok &= c
+ uni8_value |= ((c & 0x0F) as base.u32) << 16
+ c = lut_hexadecimal_digits[0xFF & (uni8_string >> 32)]
+ uni8_ok &= c
+ uni8_value |= ((c & 0x0F) as base.u32) << 12
+ c = lut_hexadecimal_digits[0xFF & (uni8_string >> 40)]
+ uni8_ok &= c
+ uni8_value |= ((c & 0x0F) as base.u32) << 8
+ c = lut_hexadecimal_digits[0xFF & (uni8_string >> 48)]
+ uni8_ok &= c
+ uni8_value |= ((c & 0x0F) as base.u32) << 4
+ c = lut_hexadecimal_digits[0xFF & (uni8_string >> 56)]
+ uni8_ok &= c
+ uni8_value |= ((c & 0x0F) as base.u32) << 0
+
+ if uni8_ok == 0 {
+ // It wasn't 8 hexadecimal digits. No-op
+ // (and fall through to "#bad
+ // backslash-escape").
+
+ } else if (uni8_value < 0xD800) or (
+ (0xDFFF < uni8_value) and (uni8_value <= 0x10_FFFF)) {
+ // Not a Unicode surrogate. We're good.
+ args.src.skip32_fast!(actual: 10, worst_case: 10)
+ args.dst.write_fast_token!(
+ value_major: 0,
+ value_minor: 0x60_0000 | (uni8_value & 0x1F_FFFF),
+ link: 0x3,
+ length: 10)
+ continue.string_loop_outer
+ } else if this.quirk_enabled_replace_invalid_unicode {
+ args.src.skip32_fast!(actual: 10, worst_case: 10)
+ args.dst.write_fast_token!(
+ value_major: 0,
+ value_minor: 0x60_FFFD,
+ link: 0x3,
+ length: 10)
+ continue.string_loop_outer
+ }
+ // -------- END backslash-capital-u.
+
+ } else if (c == 'x') and
+ this.quirk_enabled_allow_backslash_x {
+ // -------- BEGIN backslash-x
+ if args.src.available() < 4 {
+ if args.src.is_closed() {
+ return "#bad backslash-escape"
+ }
+ yield? base."$short read"
+ string_length = 0
+ char = 0
+ continue.string_loop_outer
+ }
+
+ backslash_x_length = 0
+ while (backslash_x_length <= 0xFFFB) and (args.src.available() >= 4),
+ inv args.dst.available() > 0,
+ {
+ backslash_x_string = args.src.peek_u32le()
+ backslash_x_ok = 0x80
+
+ c = lut_hexadecimal_digits[0xFF & (backslash_x_string >> 16)]
+ backslash_x_ok &= c
+ c = lut_hexadecimal_digits[0xFF & (backslash_x_string >> 24)]
+ backslash_x_ok &= c
+
+ if (backslash_x_ok == 0) or
+ ((backslash_x_string & 0xFFFF) <> 0x785C) {
+ // It wasn't "\\x34", for some
+ // hexadecimal digits "34".
+ break
+ }
+ args.src.skip32_fast!(actual: 4, worst_case: 4)
+ backslash_x_length += 4
+ } endwhile
+
+ if backslash_x_length == 0 {
+ return "#bad backslash-escape"
+ }
+ args.dst.write_fast_token!(
+ value_major: 0,
+ value_minor: 0x40_0080,
+ link: 0x3,
+ length: backslash_x_length)
+ continue.string_loop_outer
+ // -------- END backslash-x
}
return "#bad backslash-escape"
@@ -418,8 +623,20 @@
link: 0x3,
length: string_length)
string_length = 0
+ if args.dst.available() <= 0 {
+ continue.string_loop_outer
+ }
}
if args.src.is_closed() {
+ if this.quirk_enabled_replace_invalid_unicode {
+ args.dst.write_fast_token!(
+ value_major: 0,
+ value_minor: 0x60_FFFD,
+ link: 0x3,
+ length: 1)
+ args.src.skip32_fast!(actual: 1, worst_case: 1)
+ continue.string_loop_outer
+ }
return "#bad UTF-8"
}
yield? base."$short read"
@@ -454,8 +671,20 @@
link: 0x3,
length: string_length)
string_length = 0
+ if args.dst.available() <= 0 {
+ continue.string_loop_outer
+ }
}
if args.src.is_closed() {
+ if this.quirk_enabled_replace_invalid_unicode {
+ args.dst.write_fast_token!(
+ value_major: 0,
+ value_minor: 0x60_FFFD,
+ link: 0x3,
+ length: 1)
+ args.src.skip32_fast!(actual: 1, worst_case: 1)
+ continue.string_loop_outer
+ }
return "#bad UTF-8"
}
yield? base."$short read"
@@ -495,8 +724,20 @@
link: 0x3,
length: string_length)
string_length = 0
+ if args.dst.available() <= 0 {
+ continue.string_loop_outer
+ }
}
if args.src.is_closed() {
+ if this.quirk_enabled_replace_invalid_unicode {
+ args.dst.write_fast_token!(
+ value_major: 0,
+ value_minor: 0x60_FFFD,
+ link: 0x3,
+ length: 1)
+ args.src.skip32_fast!(actual: 1, worst_case: 1)
+ continue.string_loop_outer
+ }
return "#bad UTF-8"
}
yield? base."$short read"
@@ -534,10 +775,22 @@
link: 0x3,
length: string_length)
string_length = 0
+ if args.dst.available() <= 0 {
+ continue.string_loop_outer
+ }
}
if char == 0x80 {
return "#bad C0 control code"
}
+ if this.quirk_enabled_replace_invalid_unicode {
+ args.dst.write_fast_token!(
+ value_major: 0,
+ value_minor: 0x60_FFFD,
+ link: 0x3,
+ length: 1)
+ args.src.skip32_fast!(actual: 1, worst_case: 1)
+ continue.string_loop_outer
+ }
return "#bad UTF-8"
} endwhile.string_loop_inner
} endwhile.string_loop_outer
@@ -562,13 +815,13 @@
link: 0x2,
length: 1)
break
- }
+ } endwhile
// As above, expect must have contained EXPECT_STRING. If it
// didn't also contain EXPECT_NUMBER then we were parsing an
// object key and the next token should be ':'.
- if 0 == (expect & 0x0010) { // 0x0010 is EXPECT_NUMBER.
- expect = 0x0008 // 0x0008 is EXPECT_COLON.
+ if 0 == (expect & 0x0010) { // 0x0010 is (1 << CLASS_NUMBER).
+ expect = 0x1008 // 0x1008 is EXPECT_COLON.
continue.outer
}
break.goto_parsed_a_leaf_value
@@ -584,10 +837,18 @@
length: 1)
// What's valid after a comma depends on whether or not we're
// in an array or an object.
- if 0 == (expect & 0x0100) { // 0x0100 is EXPECT_CLOSE_SQUARE_BRACKET
- expect = 0x0002 // 0x0002 is EXPECT_STRING.
+ if 0 == (expect & 0x0100) { // 0x0100 is (1 << CLASS_CLOSE_SQUARE_BRACKET).
+ if this.quirk_enabled_allow_extra_comma {
+ expect = 0x1042 // 0x1042 is EXPECT_STRING | EXPECT_CLOSE_CURLY_BRACE.
+ } else {
+ expect = 0x1002 // 0x1002 is EXPECT_STRING.
+ }
} else {
- expect = 0x0EB2 // 0x0EB2 is EXPECT_VALUE.
+ if this.quirk_enabled_allow_extra_comma {
+ expect = 0x1FB2 // 0x0FB2 is EXPECT_VALUE | EXPECT_CLOSE_SQUARE_BRACKET.
+ } else {
+ expect = 0x1EB2 // 0x0EB2 is EXPECT_VALUE.
+ }
}
continue.outer
@@ -599,7 +860,7 @@
value_minor: 0,
link: 0x0,
length: 1)
- expect = 0x0EB2 // 0x0EB2 is EXPECT_VALUE.
+ expect = 0x1EB2 // 0x1EB2 is EXPECT_VALUE.
continue.outer
} else if class == 0x04 { // 0x04 is CLASS_NUMBER.
@@ -630,9 +891,13 @@
} else {
return "#internal error: inconsistent I/O"
}
- }
+ } endwhile
if number_status == 1 {
+ if this.quirk_enabled_allow_inf_nan_numbers {
+ this.decode_inf_nan?(dst: args.dst, src: args.src)
+ break
+ }
return "#bad input"
} else if number_status == 2 {
return "#unsupported number length"
@@ -642,9 +907,9 @@
post args.dst.available() > 0,
{
yield? base."$short write"
- }
+ } endwhile
}
- }
+ } endwhile
break.goto_parsed_a_leaf_value
// -------- END parse numbers.
@@ -652,7 +917,7 @@
vminor = 0x20_4011
if depth == 0 {
// No-op.
- } else if 0 <> (expect_after_value & 0x0040) { // 0x0040 is EXPECT_CLOSE_CURLY_BRACE.
+ } else if 0 <> (expect_after_value & 0x0040) { // 0x0040 is (1 << CLASS_CLOSE_CURLY_BRACE).
vminor = 0x20_4041
} else {
vminor = 0x20_4021
@@ -671,8 +936,8 @@
value_minor: vminor,
link: 0x0,
length: 1)
- expect = 0x0042 // 0x0042 is (EXPECT_CLOSE_CURLY_BRACE | EXPECT_STRING).
- expect_after_value = 0x0044 // 0x0044 is (EXPECT_CURLY_CLOSE_BRACE | EXPECT_COMMA).
+ expect = 0x1042 // 0x1042 is (EXPECT_CLOSE_CURLY_BRACE | EXPECT_STRING).
+ expect_after_value = 0x1044 // 0x1044 is (EXPECT_CURLY_CLOSE_BRACE | EXPECT_COMMA).
continue.outer
} else if class == 0x06 { // 0x06 is CLASS_CLOSE_CURLY_BRACE.
@@ -694,18 +959,18 @@
value_minor: 0x20_2042,
link: 0x0,
length: 1)
- // 0x0104 is (EXPECT_SQUARE_CLOSE_BRACKET | EXPECT_COMMA).
- expect = 0x0104
- expect_after_value = 0x0104
+ // 0x1104 is (EXPECT_SQUARE_CLOSE_BRACKET | EXPECT_COMMA).
+ expect = 0x1104
+ expect_after_value = 0x1104
} else {
args.dst.write_fast_token!(
value_major: 0,
value_minor: 0x20_4042,
link: 0x0,
length: 1)
- // 0x0044 is (EXPECT_CURLY_CLOSE_BRACE | EXPECT_COMMA).
- expect = 0x0044
- expect_after_value = 0x0044
+ // 0x1044 is (EXPECT_CURLY_CLOSE_BRACE | EXPECT_COMMA).
+ expect = 0x1044
+ expect_after_value = 0x1044
}
continue.outer
@@ -713,7 +978,7 @@
vminor = 0x20_2011
if depth == 0 {
// No-op.
- } else if 0 <> (expect_after_value & 0x0040) { // 0x0040 is EXPECT_CLOSE_CURLY_BRACE.
+ } else if 0 <> (expect_after_value & 0x0040) { // 0x0040 is (1 << CLASS_CLOSE_CURLY_BRACE).
vminor = 0x20_2041
} else {
vminor = 0x20_2021
@@ -732,8 +997,8 @@
value_minor: vminor,
link: 0x0,
length: 1)
- expect = 0x0FB2 // 0x0FB2 is (EXPECT_CLOSE_SQUARE_BRACKET | EXPECT_VALUE).
- expect_after_value = 0x0104 // 0x0104 is (EXPECT_CLOSE_SQUARE_BRACKET | EXPECT_COMMA).
+ expect = 0x1FB2 // 0x1FB2 is (EXPECT_CLOSE_SQUARE_BRACKET | EXPECT_VALUE).
+ expect_after_value = 0x1104 // 0x1104 is (EXPECT_CLOSE_SQUARE_BRACKET | EXPECT_COMMA).
continue.outer
} else if class == 0x08 { // 0x08 is CLASS_CLOSE_SQUARE_BRACKET.
@@ -755,23 +1020,23 @@
value_minor: 0x20_2022,
link: 0x0,
length: 1)
- // 0x0104 is (EXPECT_CLOSE_SQUARE_BRACKET | EXPECT_COMMA).
- expect = 0x0104
- expect_after_value = 0x0104
+ // 0x1104 is (EXPECT_CLOSE_SQUARE_BRACKET | EXPECT_COMMA).
+ expect = 0x1104
+ expect_after_value = 0x1104
} else {
args.dst.write_fast_token!(
value_major: 0,
value_minor: 0x20_4022,
link: 0x0,
length: 1)
- // 0x0044 is (EXPECT_CLOSE_CURLY_BRACE | EXPECT_COMMA).
- expect = 0x0044
- expect_after_value = 0x0044
+ // 0x1044 is (EXPECT_CLOSE_CURLY_BRACE | EXPECT_COMMA).
+ expect = 0x1044
+ expect_after_value = 0x1044
}
continue.outer
} else if class == 0x09 { // 0x09 is CLASS_FALSE.
- match = args.src.match7(a: 0x6573_6C61_6605) // 5 bytes "false".
+ match = args.src.match7(a: '\x05false'le)
if match == 0 {
args.dst.write_fast_token!(
value_major: 0,
@@ -789,7 +1054,7 @@
}
} else if class == 0x0A { // 0x0A is CLASS_TRUE.
- match = args.src.match7(a: 0x65_7572_7404) // 4 bytes "true".
+ match = args.src.match7(a: '\x04true'le)
if match == 0 {
args.dst.write_fast_token!(
value_major: 0,
@@ -806,8 +1071,8 @@
continue.outer
}
- } else if class == 0x0B { // 0x0B is CLASS_NULL.
- match = args.src.match7(a: 0x6C_6C75_6E04) // 4 bytes "null".
+ } else if class == 0x0B { // 0x0B is CLASS_NULL_NAN_INF.
+ match = args.src.match7(a: '\x04null'le)
if match == 0 {
args.dst.write_fast_token!(
value_major: 0,
@@ -823,6 +1088,17 @@
yield? base."$short read"
continue.outer
}
+
+ if this.quirk_enabled_allow_inf_nan_numbers {
+ this.decode_inf_nan?(dst: args.dst, src: args.src)
+ break.goto_parsed_a_leaf_value
+ }
+
+ } else if class == 0x0C { // 0x0C is CLASS_COMMENT.
+ if this.quirk_enabled_allow_comment_block or this.quirk_enabled_allow_comment_line {
+ this.decode_comment?(dst: args.dst, src: args.src)
+ continue.outer
+ }
}
return "#bad input"
@@ -835,6 +1111,12 @@
}
expect = expect_after_value
} endwhile.outer
+
+ if this.quirk_enabled_allow_trailing_new_line {
+ this.decode_trailing_new_line?(dst: args.dst, src: args.src)
+ }
+
+ this.end_of_data = true
}
pri func decoder.decode_number!(src: base.io_reader) base.u32[..= 0x3FF] {
@@ -855,7 +1137,7 @@
c = args.src.peek_u8()
// Scan the optional minus sign.
- if c <> 0x2D { // 0x2D is '-'.
+ if c <> '-' {
assert args.src.available() > 0
assert n <= 1
} else {
@@ -877,7 +1159,7 @@
}
// Scan the opening digits.
- if c == 0x30 { // 0x30 is '0'.
+ if c == '0' {
n += 1
args.src.skip32_fast!(actual: 1, worst_case: 1)
assert n <= 99
@@ -899,7 +1181,7 @@
c = args.src.peek_u8()
// Scan the optional fraction.
- if c <> 0x2E { // 0x2E is '.'.
+ if c <> '.' {
assert args.src.available() > 0
assert n <= 99
} else {
@@ -930,7 +1212,7 @@
}
// Scan the optional 'E' or 'e'.
- if (c <> 0x45) and (c <> 0x65) { // 0x45 and 0x65 are 'E' and 'e'.
+ if (c <> 'E') and (c <> 'e') {
break.goto_done
}
if n >= 99 {
@@ -953,7 +1235,7 @@
c = args.src.peek_u8()
// Scan the optional '+' or '-'.
- if (c <> 0x2B) and (c <> 0x2D) { // 0x2B and 0x2D are '+' and '-'.
+ if (c <> '+') and (c <> '-') {
assert n <= 99
} else {
if n >= 99 {
@@ -1004,9 +1286,353 @@
}
n += 1
args.src.skip32_fast!(actual: 1, worst_case: 1)
- }
+ } endwhile
if n == args.n {
n |= 0x100
}
return n
}
+
+pri func decoder.decode_leading?(dst: base.token_writer, src: base.io_reader) {
+ var c : base.u8
+ var u : base.u32
+
+ this.allow_leading_ars = this.quirk_enabled_allow_leading_ascii_record_separator
+ this.allow_leading_ubom = this.quirk_enabled_allow_leading_unicode_byte_order_mark
+ while this.allow_leading_ars or this.allow_leading_ubom {
+ if args.dst.available() <= 0 {
+ yield? base."$short write"
+ continue
+ }
+ if args.src.available() <= 0 {
+ if args.src.is_closed() {
+ break
+ }
+ yield? base."$short read"
+ continue
+ }
+ c = args.src.peek_u8()
+ if (c == 0x1E) and this.allow_leading_ars {
+ this.allow_leading_ars = false
+ args.src.skip32_fast!(actual: 1, worst_case: 1)
+ args.dst.write_fast_token!(
+ value_major: 0, value_minor: 0, link: 0x0, length: 1)
+ continue
+ } else if (c == 0xEF) and this.allow_leading_ubom {
+ if args.src.available() < 3 {
+ if args.src.is_closed() {
+ break
+ }
+ yield? base."$short read"
+ continue
+ }
+ u = args.src.peek_u24le_as_u32()
+ if u == 0xBF_BBEF {
+ this.allow_leading_ubom = false
+ args.src.skip32_fast!(actual: 3, worst_case: 3)
+ args.dst.write_fast_token!(
+ value_major: 0, value_minor: 0, link: 0x0, length: 3)
+ continue
+ }
+ }
+ break
+ } endwhile
+}
+
+pri func decoder.decode_comment?(dst: base.token_writer, src: base.io_reader) {
+ var c : base.u8
+ var c2 : base.u16
+ var link_prev : base.u32[..= 0x2]
+ var length : base.u32[..= 0xFFFD]
+
+ while (args.dst.available() <= 0) or (args.src.available() <= 1),
+ post args.dst.available() > 0,
+ post args.src.available() > 1,
+ {
+ if args.dst.available() <= 0 {
+ yield? base."$short write"
+ continue
+ }
+ if args.src.is_closed() {
+ return "#bad input"
+ }
+ yield? base."$short read"
+ } endwhile
+ c2 = args.src.peek_u16le()
+
+ if (c2 == '/*'le) and this.quirk_enabled_allow_comment_block {
+ args.src.skip32_fast!(actual: 2, worst_case: 2)
+ length = 2
+
+ while.comment_block true {
+ if args.dst.available() <= 0 {
+ yield? base."$short write"
+ length = 0
+ continue.comment_block
+ }
+
+ while true,
+ pre args.dst.available() > 0,
+ {
+ if args.src.available() <= 1 {
+ if length > 0 {
+ args.dst.write_fast_token!(
+ value_major: 0,
+ value_minor: 0x2,
+ link: 0x1 | link_prev,
+ length: length)
+ link_prev = 0x2
+ }
+ if args.src.is_closed() {
+ return "#bad input"
+ }
+ yield? base."$short read"
+ length = 0
+ continue.comment_block
+ }
+
+ c2 = args.src.peek_u16le()
+ if c2 == '*/'le {
+ args.src.skip32_fast!(actual: 2, worst_case: 2)
+ args.dst.write_fast_token!(
+ value_major: 0,
+ value_minor: 0x2,
+ link: link_prev,
+ length: length + 2)
+ return ok
+ }
+
+ args.src.skip32_fast!(actual: 1, worst_case: 1)
+ if length >= 0xFFFD {
+ args.dst.write_fast_token!(
+ value_major: 0,
+ value_minor: 0x2,
+ link: 0x1 | link_prev,
+ length: length + 1)
+ length = 0
+ link_prev = 0x2
+ continue.comment_block
+ }
+ length += 1
+ } endwhile
+ } endwhile.comment_block
+
+ } else if (c2 == '//'le) and this.quirk_enabled_allow_comment_line {
+ args.src.skip32_fast!(actual: 2, worst_case: 2)
+ length = 2
+
+ while.comment_line true {
+ if args.dst.available() <= 0 {
+ yield? base."$short write"
+ length = 0
+ continue.comment_line
+ }
+
+ while true,
+ pre args.dst.available() > 0,
+ {
+ if args.src.available() <= 0 {
+ if length > 0 {
+ args.dst.write_fast_token!(
+ value_major: 0,
+ value_minor: 0x1,
+ link: 0x1 | link_prev,
+ length: length)
+ link_prev = 0x2
+ }
+ if args.src.is_closed() {
+ return "#bad input"
+ }
+ yield? base."$short read"
+ length = 0
+ continue.comment_line
+ }
+
+ c = args.src.peek_u8()
+ if c == '\n' {
+ args.src.skip32_fast!(actual: 1, worst_case: 1)
+ args.dst.write_fast_token!(
+ value_major: 0,
+ value_minor: 0x1,
+ link: link_prev,
+ length: length + 1)
+ return ok
+ }
+
+ args.src.skip32_fast!(actual: 1, worst_case: 1)
+ if length >= 0xFFFD {
+ args.dst.write_fast_token!(
+ value_major: 0,
+ value_minor: 0x1,
+ link: 0x1 | link_prev,
+ length: length + 1)
+ length = 0
+ link_prev = 0x2
+ continue.comment_line
+ }
+ length += 1
+ } endwhile
+ } endwhile.comment_line
+ }
+
+ return "#bad input"
+}
+
+pri func decoder.decode_inf_nan?(dst: base.token_writer, src: base.io_reader) {
+ var c4 : base.u32
+ var neg : base.u32[..= 1]
+
+ while true {
+ if args.dst.available() <= 0 {
+ yield? base."$short write"
+ continue
+ }
+ if args.src.available() <= 2 {
+ if args.src.is_closed() {
+ return "#bad input"
+ }
+ yield? base."$short read"
+ continue
+ }
+
+ // Bitwise or'ing with 0x20 converts upper case ASCII to lower case.
+
+ c4 = args.src.peek_u24le_as_u32()
+ if (c4 | 0x20_2020) == 'inf'le {
+ if args.src.available() > 7 {
+ if (args.src.peek_u64le() | 0x2020_2020_2020_2020) == 'infinity'le {
+ args.dst.write_fast_token!(
+ value_major: 0,
+ value_minor: 0xA0_0020,
+ link: 0x0,
+ length: 8)
+ args.src.skip32_fast!(actual: 8, worst_case: 8)
+ return ok
+ }
+ } else if not args.src.is_closed() {
+ yield? base."$short read"
+ continue
+ }
+ args.dst.write_fast_token!(
+ value_major: 0,
+ value_minor: 0xA0_0020,
+ link: 0x0,
+ length: 3)
+ args.src.skip32_fast!(actual: 3, worst_case: 3)
+ return ok
+
+ } else if (c4 | 0x20_2020) == 'nan'le {
+ args.dst.write_fast_token!(
+ value_major: 0,
+ value_minor: 0xA0_0080,
+ link: 0x0,
+ length: 3)
+ args.src.skip32_fast!(actual: 3, worst_case: 3)
+ return ok
+ } else if (c4 & 0xFF) == '+' {
+ neg = 0
+ } else if (c4 & 0xFF) == '-' {
+ neg = 1
+ } else {
+ return "#bad input"
+ }
+
+ if args.src.available() <= 3 {
+ if args.src.is_closed() {
+ return "#bad input"
+ }
+ yield? base."$short read"
+ continue
+ }
+
+ c4 = args.src.peek_u32le() >> 8
+ if (c4 | 0x20_2020) == 'inf'le {
+ if args.src.available() > 8 {
+ if (args.src.peek_u64le_at(offset: 1) | 0x2020_2020_2020_2020) == 'infinity'le {
+ args.dst.write_fast_token!(
+ value_major: 0,
+ value_minor: 0xA0_0000 | ((0x20 as base.u32) >> neg),
+ link: 0x0,
+ length: 9)
+ args.src.skip32_fast!(actual: 9, worst_case: 9)
+ return ok
+ }
+ } else if not args.src.is_closed() {
+ yield? base."$short read"
+ continue
+ }
+ args.dst.write_fast_token!(
+ value_major: 0,
+ value_minor: 0xA0_0000 | ((0x20 as base.u32) >> neg),
+ link: 0x0,
+ length: 4)
+ args.src.skip32_fast!(actual: 4, worst_case: 4)
+ return ok
+
+ } else if (c4 | 0x20_2020) == 'nan'le {
+ args.dst.write_fast_token!(
+ value_major: 0,
+ value_minor: 0xA0_0000 | ((0x80 as base.u32) >> neg),
+ link: 0x0,
+ length: 4)
+ args.src.skip32_fast!(actual: 4, worst_case: 4)
+ return ok
+ }
+
+ return "#bad input"
+ } endwhile
+}
+
+pri func decoder.decode_trailing_new_line?(dst: base.token_writer, src: base.io_reader) {
+ var c : base.u8
+ var whitespace_length : base.u32[..= 0xFFFE]
+
+ while.outer true {
+ if args.dst.available() <= 0 {
+ yield? base."$short write"
+ whitespace_length = 0
+ continue.outer
+ }
+
+ while.inner true,
+ pre args.dst.available() > 0,
+ {
+ if args.src.available() <= 0 {
+ if whitespace_length > 0 {
+ args.dst.write_fast_token!(
+ value_major: 0, value_minor: 0, link: 0x0, length: whitespace_length)
+ whitespace_length = 0
+ }
+ if args.src.is_closed() {
+ break.outer
+ }
+ yield? base."$short read"
+ whitespace_length = 0
+ continue.outer
+ }
+
+ c = args.src.peek_u8()
+ if lut_classes[c] <> 0x00 { // 0x00 is CLASS_WHITESPACE.
+ if whitespace_length > 0 {
+ args.dst.write_fast_token!(
+ value_major: 0, value_minor: 0, link: 0x0, length: whitespace_length)
+ whitespace_length = 0
+ }
+ return "#bad input"
+ }
+
+ args.src.skip32_fast!(actual: 1, worst_case: 1)
+ if (whitespace_length >= 0xFFFE) or (c == '\n') {
+ args.dst.write_fast_token!(
+ value_major: 0, value_minor: 0, link: 0x0, length: whitespace_length + 1)
+ whitespace_length = 0
+ if c == '\n' {
+ break.outer
+ }
+ continue.outer
+ }
+ whitespace_length += 1
+ } endwhile.inner
+ } endwhile.outer
+
+}
diff --git a/std/json/decode_quirks.wuffs b/std/json/decode_quirks.wuffs
index c354505..e8eee13 100644
--- a/std/json/decode_quirks.wuffs
+++ b/std/json/decode_quirks.wuffs
@@ -28,6 +28,8 @@
// When this quirk is enabled, e.g. "abc\U0001F4A9z" is accepted as a JSON
// string, equivalent to "abc\uD83D\uDCA9z", containing the U+0001F4A9 PILE OF
// POO Unicode code point. There are exactly 8 encoded bytes after each "\U".
+//
+// This quirk can combine with quirk_replace_invalid_unicode.
pub const quirk_allow_backslash_capital_u base.u32 = 0x4909_9400 | 0x01
// When this quirk is enabled, e.g. "abc\ez" is accepted as a JSON string,
@@ -51,7 +53,9 @@
// decoding to 5 bytes: 0x61, 0x62, 0x63, 0xEF and 0x7A. There are exactly 2
// encoded bytes after each "\x".
//
-// Decoded strings are byte strings, no longer guaranteed to be valid UTF-8.
+// Decoded strings are byte strings, no longer guaranteed to be valid UTF-8 and
+// even if the overall byte string is valid UTF-8, tokens are also no longer
+// guaranteed to split on UTF-8 boundaries.
//
// "\x", "\x9", "\x9$" and "\X99" are all still rejected.
pub const quirk_allow_backslash_x base.u32 = 0x4909_9400 | 0x06
@@ -64,18 +68,23 @@
// anywhere whitespace would be, although see the quirk_allow_trailing_new_line
// comment for additional interaction when combining multiple quirks.
//
-// They produce WUFFS_BASE__TOKEN__VBD__FILLER__COMMENT_BLOCK tokens.
+// They produce WUFFS_BASE__TOKEN__VBD__FILLER__COMMENT_BLOCK tokens. The token
+// chain's source bytes includes the starting "/*" and the ending "*/".
pub const quirk_allow_comment_block base.u32 = 0x4909_9400 | 0x08
// When this quirk is enabled, "// C/C++ style line comments\n" are accepted
// anywhere whitespace would be, although see the quirk_allow_trailing_new_line
// comment for additional interaction when combining multiple quirks.
//
-// A line comment may omit the trailing '\n' if there is no input afterwards
-// (i.e. the line comment ends with the end-of-file), but note the
-// quirk_allow_trailing_new_line interaction already mentioned.
+// A line comment may not omit the ending "\n", even if there is no input
+// afterwards (i.e. the prospective line comment ends with the end-of-file).
//
-// They produce WUFFS_BASE__TOKEN__VBD__FILLER__COMMENT_LINE tokens.
+// They produce WUFFS_BASE__TOKEN__VBD__FILLER__COMMENT_LINE tokens. The token
+// chain's source bytes includes the starting "//" and the ending "\n".
+//
+// Even if the line comments are on consecutive lines, each line comment is a
+// separate token chain. There may be whitespace tokens between one line
+// comment's ending "\n" and the next one's starting "//".
pub const quirk_allow_comment_line base.u32 = 0x4909_9400 | 0x09
// When this quirk is enabled, there may be a comma after the final array
@@ -85,7 +94,7 @@
//
// For example, `[1,]`, `[1,2,3,]` and `{"k":"v",}` all become acceptable, but
// `[,]`, `{,}` and `{"k",:"v"}` are still rejected.
-pub const quirk_allow_final_comma base.u32 = 0x4909_9400 | 0x0A
+pub const quirk_allow_extra_comma base.u32 = 0x4909_9400 | 0x0A
// When this quirk is enabled, "inf", "Infinity", "NAN" and their
// case-insensitive variants, optionally preceded immediately by "-" or "+",
@@ -149,10 +158,16 @@
// When this quirk is enabled, invalid UTF-8 inside a JSON string is accepted.
// Each byte of invalid UTF-8 is equivalent to "\uFFFD", the Unicode
-// Replacement Character. Invalid UTF-8 outside a JSON string remains an error.
+// Replacement Character. The UTF-8 encoding of U+FFFD is "\xEF\xBF\xBD".
+//
+// Invalid UTF-8 outside a JSON string remains an error.
//
// Similarly, for backslash-u escapes featuring incorrectly paired Unicode
// surrogates, each backslash-u 6-byte unit is replaced. For example,
// "abc\uDC00z" and "ijk\uD800\uDBFFz" are equivalent to "abc\uFFFDz" and
// "ijk\uFFFD\uFFFDz".
-pub const quirk_replace_invalid_utf_8 base.u32 = 0x4909_9400 | 0x0F
+//
+// When combined with quirk_allow_backslash_capital_u, a "\U12345678" 10-byte
+// unit that is an invalid Unicode code point (i.e. in the range U+D800 ..=
+// U+DFFF or above U+10FFFF) is similarly replaced with U+FFFD.
+pub const quirk_replace_invalid_unicode base.u32 = 0x4909_9400 | 0x0F
diff --git a/std/lzw/decode_lzw.wuffs b/std/lzw/decode_lzw.wuffs
index 58317b4..4ec5d3d 100644
--- a/std/lzw/decode_lzw.wuffs
+++ b/std/lzw/decode_lzw.wuffs
@@ -100,7 +100,7 @@
this.lm1s[i] = 0
this.suffixes[i][0] = i as base.u8
i += 1
- }
+ } endwhile
while true {
this.read_from!(src: args.src)
@@ -120,7 +120,7 @@
} else {
return "#internal error: inconsistent I/O"
}
- }
+ } endwhile
}
pri func decoder.read_from!(src: base.io_reader) {
@@ -265,7 +265,7 @@
// in practice, but is necessary for the overflow checker.
o = (o ~mod- 8) & 8191
c = this.prefixes[c] as base.u32
- }
+ } endwhile
first_byte = this.suffixes[c][0]
if code == save_code {
@@ -306,7 +306,7 @@
this.read_from_return_value = 1
break
}
- }
+ } endwhile
// Rewind args.src, if we're not in "$short read" and we've read too many
// bits.
@@ -319,7 +319,7 @@
this.read_from_return_value = 4
break
}
- }
+ } endwhile
}
this.save_code = save_code
@@ -347,7 +347,7 @@
}
this.output_ri = (this.output_ri ~mod+ ((n & 0xFFFF_FFFF) as base.u32)) & 8191
yield? base."$short write"
- }
+ } endwhile
}
pub func decoder.flush!() slice base.u8 {
diff --git a/std/wbmp/decode_wbmp.wuffs b/std/wbmp/decode_wbmp.wuffs
index 683d0d8..cef9c53 100644
--- a/std/wbmp/decode_wbmp.wuffs
+++ b/std/wbmp/decode_wbmp.wuffs
@@ -46,7 +46,7 @@
return "#bad header"
}
i += 1
- }
+ } endwhile
// Width, height.
i = 0
@@ -66,7 +66,7 @@
return "#bad header"
}
x32 = x64 as base.u32
- }
+ } endwhile
if i == 0 {
this.width = x32
@@ -74,7 +74,7 @@
this.height = x32
}
i += 1
- }
+ } endwhile
this.frame_config_io_position = args.src.position()
@@ -190,9 +190,9 @@
}
dst_x += 1
- }
+ } endwhile
dst_y += 1
- }
+ } endwhile
}
this.call_sequence = 3
diff --git a/std/zlib/decode_zlib.wuffs b/std/zlib/decode_zlib.wuffs
index 4e9d8d7..9db5ff1 100644
--- a/std/zlib/decode_zlib.wuffs
+++ b/std/zlib/decode_zlib.wuffs
@@ -117,7 +117,7 @@
break
}
yield? status
- }
+ } endwhile
checksum_want = args.src.read_u32be?()
if (not this.ignore_checksum) and (checksum_got <> checksum_want) {
return "#bad checksum"
diff --git a/test/c/std/adler32.c b/test/c/std/adler32.c
index 767f948..69485ac 100644
--- a/test/c/std/adler32.c
+++ b/test/c/std/adler32.c
@@ -69,12 +69,12 @@
// ---------------- Golden Tests
-golden_test adler32_midsummer_gt = {
- .src_filename = "test/data/midsummer.txt", //
+golden_test g_adler32_midsummer_gt = {
+ .src_filename = "test/data/midsummer.txt",
};
-golden_test adler32_pi_gt = {
- .src_filename = "test/data/pi.txt", //
+golden_test g_adler32_pi_gt = {
+ .src_filename = "test/data/pi.txt",
};
// ---------------- Adler32 Tests
@@ -134,7 +134,7 @@
int tc;
for (tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) {
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(read_file(&src, test_cases[tc].filename));
@@ -230,7 +230,7 @@
// ---------------- Adler32 Benches
-uint32_t global_wuffs_adler32_unused_u32;
+uint32_t g_wuffs_adler32_unused_u32;
const char* //
wuffs_bench_adler32(wuffs_base__io_buffer* dst,
@@ -246,7 +246,7 @@
CHECK_STATUS("initialize", wuffs_adler32__hasher__initialize(
&checksum, sizeof checksum, WUFFS_VERSION,
wuffs_initialize_flags));
- global_wuffs_adler32_unused_u32 = wuffs_adler32__hasher__update_u32(
+ g_wuffs_adler32_unused_u32 = wuffs_adler32__hasher__update_u32(
&checksum, ((wuffs_base__slice_u8){
.ptr = src->data.ptr + src->meta.ri,
.len = len,
@@ -261,7 +261,7 @@
return do_bench_io_buffers(
wuffs_bench_adler32,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED, tcounter_src,
- &adler32_midsummer_gt, UINT64_MAX, UINT64_MAX, 1500);
+ &g_adler32_midsummer_gt, UINT64_MAX, UINT64_MAX, 1500);
}
const char* //
@@ -270,7 +270,7 @@
return do_bench_io_buffers(
wuffs_bench_adler32,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED, tcounter_src,
- &adler32_pi_gt, UINT64_MAX, UINT64_MAX, 150);
+ &g_adler32_pi_gt, UINT64_MAX, UINT64_MAX, 150);
}
// ---------------- Mimic Benches
@@ -281,7 +281,7 @@
bench_mimic_adler32_10k() {
CHECK_FOCUS(__func__);
return do_bench_io_buffers(mimic_bench_adler32, 0, tcounter_src,
- &adler32_midsummer_gt, UINT64_MAX, UINT64_MAX,
+ &g_adler32_midsummer_gt, UINT64_MAX, UINT64_MAX,
1500);
}
@@ -289,7 +289,7 @@
bench_mimic_adler32_100k() {
CHECK_FOCUS(__func__);
return do_bench_io_buffers(mimic_bench_adler32, 0, tcounter_src,
- &adler32_pi_gt, UINT64_MAX, UINT64_MAX, 150);
+ &g_adler32_pi_gt, UINT64_MAX, UINT64_MAX, 150);
}
#endif // WUFFS_MIMIC
@@ -299,26 +299,24 @@
// Note that the adler32 mimic tests and benches don't work with
// WUFFS_MIMICLIB_USE_MINIZ_INSTEAD_OF_ZLIB.
-// The empty comments forces clang-format to place one element per line.
-proc tests[] = {
+proc g_tests[] = {
- test_wuffs_adler32_golden, //
- test_wuffs_adler32_interface, //
- test_wuffs_adler32_pi, //
+ test_wuffs_adler32_golden,
+ test_wuffs_adler32_interface,
+ test_wuffs_adler32_pi,
NULL,
};
-// The empty comments forces clang-format to place one element per line.
-proc benches[] = {
+proc g_benches[] = {
- bench_wuffs_adler32_10k, //
- bench_wuffs_adler32_100k, //
+ bench_wuffs_adler32_10k,
+ bench_wuffs_adler32_100k,
#ifdef WUFFS_MIMIC
- bench_mimic_adler32_10k, //
- bench_mimic_adler32_100k, //
+ bench_mimic_adler32_10k,
+ bench_mimic_adler32_100k,
#endif // WUFFS_MIMIC
@@ -327,6 +325,6 @@
int //
main(int argc, char** argv) {
- proc_package_name = "std/adler32";
- return test_main(argc, argv, tests, benches);
+ g_proc_package_name = "std/adler32";
+ return test_main(argc, argv, g_tests, g_benches);
}
diff --git a/test/c/std/bmp.c b/test/c/std/bmp.c
index 6f90c25..bb6a6e9 100644
--- a/test/c/std/bmp.c
+++ b/test/c/std/bmp.c
@@ -69,7 +69,7 @@
// ---------------- BMP Tests
-const char* //
+const char* //
test_wuffs_bmp_decode_interface() {
CHECK_FOCUS(__func__);
wuffs_bmp__decoder dec;
@@ -82,7 +82,7 @@
"test/data/hippopotamus.bmp", 0, SIZE_MAX, 36, 28, 0xFFF5F5F5);
}
-const char* //
+const char* //
test_wuffs_bmp_decode_frame_config() {
CHECK_FOCUS(__func__);
wuffs_bmp__decoder dec;
@@ -93,7 +93,7 @@
wuffs_base__frame_config fc = ((wuffs_base__frame_config){});
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(read_file(&src, "test/data/hat.bmp"));
CHECK_STATUS("decode_frame_config #0",
@@ -134,11 +134,10 @@
// ---------------- Manifest
-// The empty comments forces clang-format to place one element per line.
-proc tests[] = {
+proc g_tests[] = {
- test_wuffs_bmp_decode_frame_config, //
- test_wuffs_bmp_decode_interface, //
+ test_wuffs_bmp_decode_frame_config,
+ test_wuffs_bmp_decode_interface,
#ifdef WUFFS_MIMIC
@@ -149,8 +148,7 @@
NULL,
};
-// The empty comments forces clang-format to place one element per line.
-proc benches[] = {
+proc g_benches[] = {
// No BMP benches.
@@ -163,8 +161,8 @@
NULL,
};
-int //
+int //
main(int argc, char** argv) {
- proc_package_name = "std/bmp";
- return test_main(argc, argv, tests, benches);
+ g_proc_package_name = "std/bmp";
+ return test_main(argc, argv, g_tests, g_benches);
}
diff --git a/test/c/std/crc32.c b/test/c/std/crc32.c
index 2a4be10..1d60def 100644
--- a/test/c/std/crc32.c
+++ b/test/c/std/crc32.c
@@ -69,12 +69,12 @@
// ---------------- Golden Tests
-golden_test crc32_midsummer_gt = {
- .src_filename = "test/data/midsummer.txt", //
+golden_test g_crc32_midsummer_gt = {
+ .src_filename = "test/data/midsummer.txt",
};
-golden_test crc32_pi_gt = {
- .src_filename = "test/data/pi.txt", //
+golden_test g_crc32_pi_gt = {
+ .src_filename = "test/data/pi.txt",
};
// ---------------- CRC32 Tests
@@ -134,7 +134,7 @@
int tc;
for (tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) {
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(read_file(&src, test_cases[tc].filename));
@@ -267,7 +267,7 @@
// ---------------- CRC32 Benches
-uint32_t global_wuffs_crc32_unused_u32;
+uint32_t g_wuffs_crc32_unused_u32;
const char* //
wuffs_bench_crc32_ieee(wuffs_base__io_buffer* dst,
@@ -283,7 +283,7 @@
CHECK_STATUS("initialize", wuffs_crc32__ieee_hasher__initialize(
&checksum, sizeof checksum, WUFFS_VERSION,
wuffs_initialize_flags));
- global_wuffs_crc32_unused_u32 = wuffs_crc32__ieee_hasher__update_u32(
+ g_wuffs_crc32_unused_u32 = wuffs_crc32__ieee_hasher__update_u32(
&checksum, ((wuffs_base__slice_u8){
.ptr = src->data.ptr + src->meta.ri,
.len = len,
@@ -298,7 +298,7 @@
return do_bench_io_buffers(
wuffs_bench_crc32_ieee,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED, tcounter_src,
- &crc32_midsummer_gt, UINT64_MAX, UINT64_MAX, 1500);
+ &g_crc32_midsummer_gt, UINT64_MAX, UINT64_MAX, 1500);
}
const char* //
@@ -307,7 +307,7 @@
return do_bench_io_buffers(
wuffs_bench_crc32_ieee,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED, tcounter_src,
- &crc32_pi_gt, UINT64_MAX, UINT64_MAX, 150);
+ &g_crc32_pi_gt, UINT64_MAX, UINT64_MAX, 150);
}
// ---------------- Mimic Benches
@@ -318,14 +318,15 @@
bench_mimic_crc32_ieee_10k() {
CHECK_FOCUS(__func__);
return do_bench_io_buffers(mimic_bench_crc32_ieee, 0, tcounter_src,
- &crc32_midsummer_gt, UINT64_MAX, UINT64_MAX, 1500);
+ &g_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, tcounter_src,
- &crc32_pi_gt, UINT64_MAX, UINT64_MAX, 150);
+ &g_crc32_pi_gt, UINT64_MAX, UINT64_MAX, 150);
}
#endif // WUFFS_MIMIC
@@ -335,32 +336,30 @@
// Note that the crc32 mimic tests and benches don't work with
// WUFFS_MIMICLIB_USE_MINIZ_INSTEAD_OF_ZLIB.
-// The empty comments forces clang-format to place one element per line.
-proc tests[] = {
+proc g_tests[] = {
- test_wuffs_crc32_ieee_golden, //
- test_wuffs_crc32_ieee_interface, //
- test_wuffs_crc32_ieee_pi, //
+ test_wuffs_crc32_ieee_golden,
+ test_wuffs_crc32_ieee_interface,
+ test_wuffs_crc32_ieee_pi,
#ifdef WUFFS_MIMIC
- test_mimic_crc32_ieee_pi, //
+ test_mimic_crc32_ieee_pi,
#endif // WUFFS_MIMIC
NULL,
};
-// The empty comments forces clang-format to place one element per line.
-proc benches[] = {
+proc g_benches[] = {
- bench_wuffs_crc32_ieee_10k, //
- bench_wuffs_crc32_ieee_100k, //
+ bench_wuffs_crc32_ieee_10k,
+ bench_wuffs_crc32_ieee_100k,
#ifdef WUFFS_MIMIC
- bench_mimic_crc32_ieee_10k, //
- bench_mimic_crc32_ieee_100k, //
+ bench_mimic_crc32_ieee_10k,
+ bench_mimic_crc32_ieee_100k,
#endif // WUFFS_MIMIC
@@ -369,6 +368,6 @@
int //
main(int argc, char** argv) {
- proc_package_name = "std/crc32";
- return test_main(argc, argv, tests, benches);
+ g_proc_package_name = "std/crc32";
+ return test_main(argc, argv, g_tests, g_benches);
}
diff --git a/test/c/std/deflate.c b/test/c/std/deflate.c
index 2aaa430..e9e9530 100644
--- a/test/c/std/deflate.c
+++ b/test/c/std/deflate.c
@@ -72,17 +72,15 @@
// The src_offset0 and src_offset1 magic numbers come from:
//
// go run script/extract-flate-offsets.go test/data/*.gz
-//
-// The empty comments forces clang-format to place one element per line.
-golden_test deflate_256_bytes_gt = {
- .want_filename = "test/data/artificial/256.bytes", //
- .src_filename = "test/data/artificial/256.bytes.gz", //
- .src_offset0 = 20, //
- .src_offset1 = 281, //
+golden_test g_deflate_256_bytes_gt = {
+ .want_filename = "test/data/artificial/256.bytes",
+ .src_filename = "test/data/artificial/256.bytes.gz",
+ .src_offset0 = 20,
+ .src_offset1 = 281,
};
-golden_test deflate_deflate_backref_crosses_blocks_gt = {
+golden_test g_deflate_deflate_backref_crosses_blocks_gt = {
.want_filename =
"test/data/artificial/"
"deflate-backref-crosses-blocks.deflate.decompressed",
@@ -91,7 +89,7 @@
"deflate-backref-crosses-blocks.deflate",
};
-golden_test deflate_deflate_degenerate_huffman_unused_gt = {
+golden_test g_deflate_deflate_degenerate_huffman_unused_gt = {
.want_filename =
"test/data/artificial/"
"deflate-degenerate-huffman-unused.deflate.decompressed",
@@ -100,7 +98,7 @@
"deflate-degenerate-huffman-unused.deflate",
};
-golden_test deflate_deflate_distance_32768_gt = {
+golden_test g_deflate_deflate_distance_32768_gt = {
.want_filename =
"test/data/artificial/"
"deflate-distance-32768.deflate.decompressed",
@@ -109,7 +107,7 @@
"deflate-distance-32768.deflate",
};
-golden_test deflate_deflate_distance_code_31_gt = {
+golden_test g_deflate_deflate_distance_code_31_gt = {
.want_filename =
"test/data/artificial/"
"qdeflate-distance-code-31.deflate.decompressed",
@@ -118,7 +116,7 @@
"deflate-distance-code-31.deflate",
};
-golden_test deflate_deflate_huffman_primlen_9_gt = {
+golden_test g_deflate_deflate_huffman_primlen_9_gt = {
.want_filename =
"test/data/artificial/"
"deflate-huffman-primlen-9.deflate.decompressed",
@@ -127,30 +125,30 @@
"deflate-huffman-primlen-9.deflate",
};
-golden_test deflate_midsummer_gt = {
- .want_filename = "test/data/midsummer.txt", //
- .src_filename = "test/data/midsummer.txt.gz", //
- .src_offset0 = 24, //
- .src_offset1 = 5166, //
+golden_test g_deflate_midsummer_gt = {
+ .want_filename = "test/data/midsummer.txt",
+ .src_filename = "test/data/midsummer.txt.gz",
+ .src_offset0 = 24,
+ .src_offset1 = 5166,
};
-golden_test deflate_pi_gt = {
- .want_filename = "test/data/pi.txt", //
- .src_filename = "test/data/pi.txt.gz", //
- .src_offset0 = 17, //
- .src_offset1 = 48335, //
+golden_test g_deflate_pi_gt = {
+ .want_filename = "test/data/pi.txt",
+ .src_filename = "test/data/pi.txt.gz",
+ .src_offset0 = 17,
+ .src_offset1 = 48335,
};
-golden_test deflate_romeo_gt = {
- .want_filename = "test/data/romeo.txt", //
- .src_filename = "test/data/romeo.txt.gz", //
- .src_offset0 = 20, //
- .src_offset1 = 550, //
+golden_test g_deflate_romeo_gt = {
+ .want_filename = "test/data/romeo.txt",
+ .src_filename = "test/data/romeo.txt.gz",
+ .src_offset0 = 20,
+ .src_offset1 = 550,
};
-golden_test deflate_romeo_fixed_gt = {
- .want_filename = "test/data/romeo.txt", //
- .src_filename = "test/data/romeo.txt.fixed-huff.deflate", //
+golden_test g_deflate_romeo_fixed_gt = {
+ .want_filename = "test/data/romeo.txt",
+ .src_filename = "test/data/romeo.txt.fixed-huff.deflate",
};
// ---------------- Deflate Tests
@@ -184,7 +182,7 @@
wuffs_base__io_buffer limited_src = make_limited_reader(*src, rlimit);
wuffs_base__status status = wuffs_deflate__decoder__transform_io(
- &dec, &limited_dst, &limited_src, global_work_slice);
+ &dec, &limited_dst, &limited_src, g_work_slice_u8);
dst->meta.wi += limited_dst.meta.wi;
src->meta.ri += limited_src.meta.ri;
@@ -202,7 +200,7 @@
const char* //
test_wuffs_deflate_decode_256_bytes() {
CHECK_FOCUS(__func__);
- return do_test_io_buffers(wuffs_deflate_decode, &deflate_256_bytes_gt,
+ return do_test_io_buffers(wuffs_deflate_decode, &g_deflate_256_bytes_gt,
UINT64_MAX, UINT64_MAX);
}
@@ -210,7 +208,7 @@
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,
+ &g_deflate_deflate_backref_crosses_blocks_gt,
UINT64_MAX, UINT64_MAX);
}
@@ -218,7 +216,7 @@
test_wuffs_deflate_decode_deflate_degenerate_huffman_unused() {
CHECK_FOCUS(__func__);
return do_test_io_buffers(wuffs_deflate_decode,
- &deflate_deflate_degenerate_huffman_unused_gt,
+ &g_deflate_deflate_degenerate_huffman_unused_gt,
UINT64_MAX, UINT64_MAX);
}
@@ -226,7 +224,7 @@
test_wuffs_deflate_decode_deflate_distance_32768() {
CHECK_FOCUS(__func__);
return do_test_io_buffers(wuffs_deflate_decode,
- &deflate_deflate_distance_32768_gt, UINT64_MAX,
+ &g_deflate_deflate_distance_32768_gt, UINT64_MAX,
UINT64_MAX);
}
@@ -234,7 +232,7 @@
test_wuffs_deflate_decode_deflate_distance_code_31() {
CHECK_FOCUS(__func__);
const char* have = do_test_io_buffers(wuffs_deflate_decode,
- &deflate_deflate_distance_code_31_gt,
+ &g_deflate_deflate_distance_code_31_gt,
UINT64_MAX, UINT64_MAX);
if (have != wuffs_deflate__error__bad_huffman_code) {
RETURN_FAIL("have \"%s\", want \"%s\"", have,
@@ -249,19 +247,19 @@
// First, treat this like any other compare-to-golden test.
CHECK_STRING(do_test_io_buffers(wuffs_deflate_decode,
- &deflate_deflate_huffman_primlen_9_gt,
+ &g_deflate_deflate_huffman_primlen_9_gt,
UINT64_MAX, UINT64_MAX));
// Second, check that the decoder's huffman table sizes match those predicted
// by the script/print-deflate-huff-table-size.go program.
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
wuffs_base__io_buffer have = ((wuffs_base__io_buffer){
- .data = global_have_slice,
+ .data = g_have_slice_u8,
});
- golden_test* gt = &deflate_deflate_huffman_primlen_9_gt;
+ golden_test* gt = &g_deflate_deflate_huffman_primlen_9_gt;
CHECK_STRING(read_file(&src, gt->src_filename));
wuffs_deflate__decoder dec;
@@ -269,7 +267,7 @@
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__DEFAULT_OPTIONS));
CHECK_STATUS("transform_io", wuffs_deflate__decoder__transform_io(
- &dec, &have, &src, global_work_slice));
+ &dec, &have, &src, g_work_slice_u8));
int i;
for (i = 0; i < 2; i++) {
@@ -293,48 +291,48 @@
const char* //
test_wuffs_deflate_decode_midsummer() {
CHECK_FOCUS(__func__);
- return do_test_io_buffers(wuffs_deflate_decode, &deflate_midsummer_gt,
+ return do_test_io_buffers(wuffs_deflate_decode, &g_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, UINT64_MAX,
+ return do_test_io_buffers(wuffs_deflate_decode, &g_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, UINT64_MAX,
+ return do_test_io_buffers(wuffs_deflate_decode, &g_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, UINT64_MAX,
+ return do_test_io_buffers(wuffs_deflate_decode, &g_deflate_pi_gt, UINT64_MAX,
599);
}
const char* //
test_wuffs_deflate_decode_pi_many_small_writes_reads() {
CHECK_FOCUS(__func__);
- return do_test_io_buffers(wuffs_deflate_decode, &deflate_pi_gt, 59, 61);
+ return do_test_io_buffers(wuffs_deflate_decode, &g_deflate_pi_gt, 59, 61);
}
const char* //
test_wuffs_deflate_decode_romeo() {
CHECK_FOCUS(__func__);
- return do_test_io_buffers(wuffs_deflate_decode, &deflate_romeo_gt, UINT64_MAX,
- UINT64_MAX);
+ return do_test_io_buffers(wuffs_deflate_decode, &g_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,
+ return do_test_io_buffers(wuffs_deflate_decode, &g_deflate_romeo_fixed_gt,
UINT64_MAX, UINT64_MAX);
}
@@ -343,16 +341,16 @@
CHECK_FOCUS(__func__);
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
wuffs_base__io_buffer have = ((wuffs_base__io_buffer){
- .data = global_have_slice,
+ .data = g_have_slice_u8,
});
wuffs_base__io_buffer want = ((wuffs_base__io_buffer){
- .data = global_want_slice,
+ .data = g_want_slice_u8,
});
- golden_test* gt = &deflate_256_bytes_gt;
+ golden_test* gt = &g_deflate_256_bytes_gt;
CHECK_STRING(read_file(&src, gt->src_filename));
CHECK_STRING(read_file(&want, gt->want_filename));
@@ -374,13 +372,13 @@
src.meta.ri = gt->src_offset0;
src.meta.wi = split;
wuffs_base__status z0 = wuffs_deflate__decoder__transform_io(
- &dec, &have, &src, global_work_slice);
+ &dec, &have, &src, g_work_slice_u8);
src.meta.closed = true;
src.meta.ri = split;
src.meta.wi = gt->src_offset1;
wuffs_base__status z1 = wuffs_deflate__decoder__transform_io(
- &dec, &have, &src, global_work_slice);
+ &dec, &have, &src, g_work_slice_u8);
if (z0.repr != wuffs_base__suspension__short_read) {
RETURN_FAIL("i=%d: z0: have \"%s\", want \"%s\"", i, z0.repr,
@@ -417,7 +415,7 @@
dec->private_impl.f_history_index = starting_history_index;
wuffs_base__status have_z = wuffs_deflate__decoder__transform_io(
- dec, &limited_have, src, global_work_slice);
+ dec, &limited_have, src, g_work_slice_u8);
have->meta.wi += limited_have.meta.wi;
if (have_z.repr != want_z) {
RETURN_FAIL("i=%d: starting_history_index=0x%04" PRIX32
@@ -456,16 +454,16 @@
CHECK_FOCUS(__func__);
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
wuffs_base__io_buffer have = ((wuffs_base__io_buffer){
- .data = global_have_slice,
+ .data = g_have_slice_u8,
});
wuffs_base__io_buffer want = ((wuffs_base__io_buffer){
- .data = global_want_slice,
+ .data = g_want_slice_u8,
});
- golden_test* gt = &deflate_pi_gt;
+ golden_test* gt = &g_deflate_pi_gt;
CHECK_STRING(read_file(&src, gt->src_filename));
CHECK_STRING(read_file(&want, gt->want_filename));
@@ -503,7 +501,7 @@
}
wuffs_base__io_buffer history_want = ((wuffs_base__io_buffer){
.data = ((wuffs_base__slice_u8){
- .ptr = global_want_array + want.meta.wi - (full_history_size - i),
+ .ptr = g_want_array_u8 + want.meta.wi - (full_history_size - i),
.len = full_history_size,
}),
});
@@ -519,13 +517,13 @@
CHECK_FOCUS(__func__);
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
wuffs_base__io_buffer have = ((wuffs_base__io_buffer){
- .data = global_have_slice,
+ .data = g_have_slice_u8,
});
- golden_test* gt = &deflate_pi_gt;
+ golden_test* gt = &g_deflate_pi_gt;
CHECK_STRING(read_file(&src, gt->src_filename));
uint32_t starting_history_indexes[] = {
@@ -717,7 +715,7 @@
const char* //
test_mimic_deflate_decode_256_bytes() {
CHECK_FOCUS(__func__);
- return do_test_io_buffers(mimic_deflate_decode, &deflate_256_bytes_gt,
+ return do_test_io_buffers(mimic_deflate_decode, &g_deflate_256_bytes_gt,
UINT64_MAX, UINT64_MAX);
}
@@ -725,7 +723,7 @@
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,
+ &g_deflate_deflate_backref_crosses_blocks_gt,
UINT64_MAX, UINT64_MAX);
}
@@ -733,7 +731,7 @@
test_mimic_deflate_decode_deflate_degenerate_huffman_unused() {
CHECK_FOCUS(__func__);
return do_test_io_buffers(mimic_deflate_decode,
- &deflate_deflate_degenerate_huffman_unused_gt,
+ &g_deflate_deflate_degenerate_huffman_unused_gt,
UINT64_MAX, UINT64_MAX);
}
@@ -741,7 +739,7 @@
test_mimic_deflate_decode_deflate_distance_32768() {
CHECK_FOCUS(__func__);
return do_test_io_buffers(mimic_deflate_decode,
- &deflate_deflate_distance_32768_gt, UINT64_MAX,
+ &g_deflate_deflate_distance_32768_gt, UINT64_MAX,
UINT64_MAX);
}
@@ -749,7 +747,7 @@
test_mimic_deflate_decode_deflate_distance_code_31() {
CHECK_FOCUS(__func__);
const char* have = do_test_io_buffers(mimic_deflate_decode,
- &deflate_deflate_distance_code_31_gt,
+ &g_deflate_deflate_distance_code_31_gt,
UINT64_MAX, UINT64_MAX);
const char* want = "inflate failed (data error)";
if ((have != want) &&
@@ -763,42 +761,42 @@
test_mimic_deflate_decode_deflate_huffman_primlen_9() {
CHECK_FOCUS(__func__);
return do_test_io_buffers(mimic_deflate_decode,
- &deflate_deflate_huffman_primlen_9_gt, UINT64_MAX,
+ &g_deflate_deflate_huffman_primlen_9_gt, UINT64_MAX,
UINT64_MAX);
}
const char* //
test_mimic_deflate_decode_midsummer() {
CHECK_FOCUS(__func__);
- return do_test_io_buffers(mimic_deflate_decode, &deflate_midsummer_gt,
+ return do_test_io_buffers(mimic_deflate_decode, &g_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, UINT64_MAX,
+ return do_test_io_buffers(mimic_deflate_decode, &g_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, UINT64_MAX,
+ return do_test_io_buffers(mimic_deflate_decode, &g_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, UINT64_MAX,
- UINT64_MAX);
+ return do_test_io_buffers(mimic_deflate_decode, &g_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,
+ return do_test_io_buffers(mimic_deflate_decode, &g_deflate_romeo_fixed_gt,
UINT64_MAX, UINT64_MAX);
}
@@ -811,7 +809,7 @@
CHECK_FOCUS(__func__);
return do_bench_io_buffers(wuffs_deflate_decode,
WUFFS_INITIALIZE__DEFAULT_OPTIONS, tcounter_dst,
- &deflate_romeo_gt, UINT64_MAX, UINT64_MAX, 2000);
+ &g_deflate_romeo_gt, UINT64_MAX, UINT64_MAX, 2000);
}
const char* //
@@ -820,7 +818,7 @@
return do_bench_io_buffers(
wuffs_deflate_decode,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED, tcounter_dst,
- &deflate_romeo_gt, UINT64_MAX, UINT64_MAX, 2000);
+ &g_deflate_romeo_gt, UINT64_MAX, UINT64_MAX, 2000);
}
const char* //
@@ -828,7 +826,7 @@
CHECK_FOCUS(__func__);
return do_bench_io_buffers(
wuffs_deflate_decode, WUFFS_INITIALIZE__DEFAULT_OPTIONS, tcounter_dst,
- &deflate_midsummer_gt, UINT64_MAX, UINT64_MAX, 300);
+ &g_deflate_midsummer_gt, UINT64_MAX, UINT64_MAX, 300);
}
const char* //
@@ -837,7 +835,7 @@
return do_bench_io_buffers(
wuffs_deflate_decode,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED, tcounter_dst,
- &deflate_midsummer_gt, UINT64_MAX, UINT64_MAX, 300);
+ &g_deflate_midsummer_gt, UINT64_MAX, UINT64_MAX, 300);
}
const char* //
@@ -846,7 +844,7 @@
return do_bench_io_buffers(
wuffs_deflate_decode,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED, tcounter_dst,
- &deflate_pi_gt, UINT64_MAX, UINT64_MAX, 30);
+ &g_deflate_pi_gt, UINT64_MAX, UINT64_MAX, 30);
}
const char* //
@@ -855,7 +853,7 @@
return do_bench_io_buffers(
wuffs_deflate_decode,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED, tcounter_dst,
- &deflate_pi_gt, UINT64_MAX, 4096, 30);
+ &g_deflate_pi_gt, UINT64_MAX, 4096, 30);
}
// ---------------- Mimic Benches
@@ -866,14 +864,14 @@
bench_mimic_deflate_decode_1k() {
CHECK_FOCUS(__func__);
return do_bench_io_buffers(mimic_deflate_decode, 0, tcounter_dst,
- &deflate_romeo_gt, UINT64_MAX, UINT64_MAX, 2000);
+ &g_deflate_romeo_gt, UINT64_MAX, UINT64_MAX, 2000);
}
const char* //
bench_mimic_deflate_decode_10k() {
CHECK_FOCUS(__func__);
return do_bench_io_buffers(mimic_deflate_decode, 0, tcounter_dst,
- &deflate_midsummer_gt, UINT64_MAX, UINT64_MAX,
+ &g_deflate_midsummer_gt, UINT64_MAX, UINT64_MAX,
300);
}
@@ -881,77 +879,75 @@
bench_mimic_deflate_decode_100k_just_one_read() {
CHECK_FOCUS(__func__);
return do_bench_io_buffers(mimic_deflate_decode, 0, tcounter_dst,
- &deflate_pi_gt, UINT64_MAX, UINT64_MAX, 30);
+ &g_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, tcounter_dst,
- &deflate_pi_gt, UINT64_MAX, 4096, 30);
+ &g_deflate_pi_gt, UINT64_MAX, 4096, 30);
}
#endif // WUFFS_MIMIC
// ---------------- Manifest
-// The empty comments forces clang-format to place one element per line.
-proc tests[] = {
+proc g_tests[] = {
- test_wuffs_deflate_decode_256_bytes, //
- test_wuffs_deflate_decode_deflate_backref_crosses_blocks, //
- test_wuffs_deflate_decode_deflate_degenerate_huffman_unused, //
- test_wuffs_deflate_decode_deflate_distance_32768, //
- test_wuffs_deflate_decode_deflate_distance_code_31, //
- test_wuffs_deflate_decode_deflate_huffman_primlen_9, //
- test_wuffs_deflate_decode_interface, //
- test_wuffs_deflate_decode_midsummer, //
- test_wuffs_deflate_decode_pi_just_one_read, //
- test_wuffs_deflate_decode_pi_many_big_reads, //
- test_wuffs_deflate_decode_pi_many_medium_reads, //
- test_wuffs_deflate_decode_pi_many_small_writes_reads, //
- test_wuffs_deflate_decode_romeo, //
- test_wuffs_deflate_decode_romeo_fixed, //
- test_wuffs_deflate_decode_split_src, //
- test_wuffs_deflate_history_full, //
- test_wuffs_deflate_history_partial, //
- test_wuffs_deflate_table_redirect, //
+ test_wuffs_deflate_decode_256_bytes,
+ test_wuffs_deflate_decode_deflate_backref_crosses_blocks,
+ test_wuffs_deflate_decode_deflate_degenerate_huffman_unused,
+ test_wuffs_deflate_decode_deflate_distance_32768,
+ test_wuffs_deflate_decode_deflate_distance_code_31,
+ test_wuffs_deflate_decode_deflate_huffman_primlen_9,
+ test_wuffs_deflate_decode_interface,
+ test_wuffs_deflate_decode_midsummer,
+ test_wuffs_deflate_decode_pi_just_one_read,
+ test_wuffs_deflate_decode_pi_many_big_reads,
+ test_wuffs_deflate_decode_pi_many_medium_reads,
+ test_wuffs_deflate_decode_pi_many_small_writes_reads,
+ test_wuffs_deflate_decode_romeo,
+ test_wuffs_deflate_decode_romeo_fixed,
+ test_wuffs_deflate_decode_split_src,
+ test_wuffs_deflate_history_full,
+ test_wuffs_deflate_history_partial,
+ test_wuffs_deflate_table_redirect,
#ifdef WUFFS_MIMIC
- test_mimic_deflate_decode_256_bytes, //
- test_mimic_deflate_decode_deflate_backref_crosses_blocks, //
- test_mimic_deflate_decode_deflate_degenerate_huffman_unused, //
- test_mimic_deflate_decode_deflate_distance_32768, //
- test_mimic_deflate_decode_deflate_distance_code_31, //
- test_mimic_deflate_decode_deflate_huffman_primlen_9, //
- test_mimic_deflate_decode_midsummer, //
- test_mimic_deflate_decode_pi_just_one_read, //
- test_mimic_deflate_decode_pi_many_big_reads, //
- test_mimic_deflate_decode_romeo, //
- test_mimic_deflate_decode_romeo_fixed, //
+ test_mimic_deflate_decode_256_bytes,
+ test_mimic_deflate_decode_deflate_backref_crosses_blocks,
+ test_mimic_deflate_decode_deflate_degenerate_huffman_unused,
+ test_mimic_deflate_decode_deflate_distance_32768,
+ test_mimic_deflate_decode_deflate_distance_code_31,
+ test_mimic_deflate_decode_deflate_huffman_primlen_9,
+ test_mimic_deflate_decode_midsummer,
+ test_mimic_deflate_decode_pi_just_one_read,
+ test_mimic_deflate_decode_pi_many_big_reads,
+ test_mimic_deflate_decode_romeo,
+ test_mimic_deflate_decode_romeo_fixed,
#endif // WUFFS_MIMIC
NULL,
};
-// The empty comments forces clang-format to place one element per line.
-proc benches[] = {
+proc g_benches[] = {
- bench_wuffs_deflate_decode_1k_full_init, //
- bench_wuffs_deflate_decode_1k_part_init, //
- bench_wuffs_deflate_decode_10k_full_init, //
- bench_wuffs_deflate_decode_10k_part_init, //
- bench_wuffs_deflate_decode_100k_just_one_read, //
- bench_wuffs_deflate_decode_100k_many_big_reads, //
+ bench_wuffs_deflate_decode_1k_full_init,
+ bench_wuffs_deflate_decode_1k_part_init,
+ bench_wuffs_deflate_decode_10k_full_init,
+ bench_wuffs_deflate_decode_10k_part_init,
+ bench_wuffs_deflate_decode_100k_just_one_read,
+ bench_wuffs_deflate_decode_100k_many_big_reads,
#ifdef WUFFS_MIMIC
- bench_mimic_deflate_decode_1k, //
- bench_mimic_deflate_decode_10k, //
- bench_mimic_deflate_decode_100k_just_one_read, //
- bench_mimic_deflate_decode_100k_many_big_reads, //
+ bench_mimic_deflate_decode_1k,
+ bench_mimic_deflate_decode_10k,
+ bench_mimic_deflate_decode_100k_just_one_read,
+ bench_mimic_deflate_decode_100k_many_big_reads,
#endif // WUFFS_MIMIC
@@ -960,6 +956,6 @@
int //
main(int argc, char** argv) {
- proc_package_name = "std/deflate";
- return test_main(argc, argv, tests, benches);
+ g_proc_package_name = "std/deflate";
+ return test_main(argc, argv, g_tests, g_benches);
}
diff --git a/test/c/std/gif.c b/test/c/std/gif.c
index 7b365e1..65911c4 100644
--- a/test/c/std/gif.c
+++ b/test/c/std/gif.c
@@ -217,7 +217,7 @@
wuffs_base__pixel_buffer pb = ((wuffs_base__pixel_buffer){});
CHECK_STATUS("set_from_slice", wuffs_base__pixel_buffer__set_from_slice(
- &pb, &ic.pixcfg, global_pixel_slice));
+ &pb, &ic.pixcfg, g_pixel_slice_u8));
while (true) {
wuffs_base__status status =
@@ -230,7 +230,7 @@
CHECK_STATUS("decode_frame",
wuffs_gif__decoder__decode_frame(&dec, &pb, src,
WUFFS_BASE__PIXEL_BLEND__SRC,
- global_work_slice, NULL));
+ g_work_slice_u8, NULL));
CHECK_STRING(copy_to_io_buffer_from_pixel_buffer(
dst, &pb, wuffs_base__frame_config__bounds(&fc)));
@@ -245,10 +245,10 @@
uint64_t rlimit,
wuffs_base__pixel_format dst_pixfmt) {
wuffs_base__io_buffer have = ((wuffs_base__io_buffer){
- .data = global_have_slice,
+ .data = g_have_slice_u8,
});
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(read_file(&src, filename));
@@ -290,7 +290,7 @@
120);
CHECK_STATUS("set_from_slice", wuffs_base__pixel_buffer__set_from_slice(
- &pb, &ic.pixcfg, global_pixel_slice));
+ &pb, &ic.pixcfg, g_pixel_slice_u8));
uint32_t have = wuffs_gif__decoder__num_animation_loops(&dec);
if (have != 1) {
@@ -330,8 +330,8 @@
size_t old_ri = src.meta.ri;
wuffs_base__status status = wuffs_gif__decoder__decode_frame(
- &dec, &pb, &limited_src, WUFFS_BASE__PIXEL_BLEND__SRC,
- global_work_slice, NULL);
+ &dec, &pb, &limited_src, WUFFS_BASE__PIXEL_BLEND__SRC, g_work_slice_u8,
+ NULL);
src.meta.ri += limited_src.meta.ri;
if (wuffs_base__status__is_ok(&status)) {
@@ -380,14 +380,14 @@
}
wuffs_base__io_buffer ind_want = ((wuffs_base__io_buffer){
- .data = global_want_slice,
+ .data = g_want_slice_u8,
});
CHECK_STRING(read_file(&ind_want, indexes_filename));
if (dst_pixfmt.repr == WUFFS_BASE__PIXEL_FORMAT__INDEXED__BGRA_BINARY) {
CHECK_STRING(check_io_buffers_equal("indexes ", &have, &ind_want));
} else {
wuffs_base__io_buffer expanded_want = ((wuffs_base__io_buffer){
- .data = global_work_slice,
+ .data = g_work_slice_u8,
});
if (ind_want.meta.wi > (expanded_want.data.len / 4)) {
RETURN_FAIL("indexes are too long to expand into the work buffer");
@@ -455,7 +455,7 @@
RETURN_FAIL("decode_frame returned \"ok\" but src was exhausted");
}
wuffs_base__status status = wuffs_gif__decoder__decode_frame(
- &dec, &pb, &src, WUFFS_BASE__PIXEL_BLEND__SRC, global_work_slice, NULL);
+ &dec, &pb, &src, WUFFS_BASE__PIXEL_BLEND__SRC, g_work_slice_u8, NULL);
if (status.repr != wuffs_base__note__end_of_data) {
RETURN_FAIL("decode_frame: have \"%s\", want \"%s\"", status.repr,
wuffs_base__note__end_of_data);
@@ -489,10 +489,10 @@
wuffs_base__pixel_buffer pb = ((wuffs_base__pixel_buffer){});
CHECK_STATUS("set_from_slice", wuffs_base__pixel_buffer__set_from_slice(
- &pb, &ic.pixcfg, global_pixel_slice));
+ &pb, &ic.pixcfg, g_pixel_slice_u8));
wuffs_base__status status = wuffs_gif__decoder__decode_frame(
- &dec, &pb, &src, WUFFS_BASE__PIXEL_BLEND__SRC, global_work_slice, NULL);
+ &dec, &pb, &src, WUFFS_BASE__PIXEL_BLEND__SRC, g_work_slice_u8, NULL);
if (status.repr != want_status) {
RETURN_FAIL("decode_frame: have \"%s\", want \"%s\"", status.repr,
want_status);
@@ -512,7 +512,7 @@
test_wuffs_gif_call_interleaved() {
CHECK_FOCUS(__func__);
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(read_file(&src, "test/data/bricks-dither.gif"));
@@ -553,7 +553,7 @@
test_wuffs_gif_call_sequence() {
CHECK_FOCUS(__func__);
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(read_file(&src, "test/data/bricks-dither.gif"));
@@ -582,7 +582,7 @@
uint32_t want_num_frames,
wuffs_base__rect_ie_u32* want_frame_config_bounds) {
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(read_file(&src, filename));
@@ -605,7 +605,7 @@
wuffs_base__pixel_buffer pb = ((wuffs_base__pixel_buffer){});
CHECK_STATUS("set_from_slice", wuffs_base__pixel_buffer__set_from_slice(
- &pb, &ic.pixcfg, global_pixel_slice));
+ &pb, &ic.pixcfg, g_pixel_slice_u8));
uint32_t i;
for (i = 0; i < want_num_frames; i++) {
@@ -630,7 +630,7 @@
}
status = wuffs_gif__decoder__decode_frame(
- &dec, &pb, &src, WUFFS_BASE__PIXEL_BLEND__SRC, global_work_slice, NULL);
+ &dec, &pb, &src, WUFFS_BASE__PIXEL_BLEND__SRC, g_work_slice_u8, NULL);
if (!wuffs_base__status__is_ok(&status)) {
RETURN_FAIL("decode_frame #%" PRIu32 ": \"%s\"", i, status.repr);
}
@@ -647,7 +647,7 @@
// decode_frame.
for (i = 0; i < 3; i++) {
wuffs_base__status status = wuffs_gif__decoder__decode_frame(
- &dec, &pb, &src, WUFFS_BASE__PIXEL_BLEND__SRC, global_work_slice, NULL);
+ &dec, &pb, &src, WUFFS_BASE__PIXEL_BLEND__SRC, g_work_slice_u8, NULL);
if (status.repr != wuffs_base__note__end_of_data) {
RETURN_FAIL("decode_frame: have \"%s\", want \"%s\"", status.repr,
wuffs_base__note__end_of_data);
@@ -700,7 +700,7 @@
test_wuffs_gif_decode_delay_num_frames_decoded() {
CHECK_FOCUS(__func__);
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(read_file(&src, "test/data/animated-red-blue.gif"));
if (src.meta.wi < 1) {
@@ -750,7 +750,7 @@
test_wuffs_gif_decode_empty_palette() {
CHECK_FOCUS(__func__);
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(read_file(&src, "test/data/artificial/gif-empty-palette.gif"));
int q;
@@ -774,16 +774,15 @@
wuffs_base__pixel_buffer pb = ((wuffs_base__pixel_buffer){});
status = wuffs_base__pixel_buffer__set_from_slice(&pb, &ic.pixcfg,
- global_pixel_slice);
+ g_pixel_slice_u8);
if (!wuffs_base__status__is_ok(&status)) {
RETURN_FAIL("q=%d: set_from_slice: \"%s\"", q, status.repr);
}
int i;
for (i = 0; i < 2; i++) {
- status = wuffs_gif__decoder__decode_frame(&dec, &pb, &src,
- WUFFS_BASE__PIXEL_BLEND__SRC,
- global_work_slice, NULL);
+ status = wuffs_gif__decoder__decode_frame(
+ &dec, &pb, &src, WUFFS_BASE__PIXEL_BLEND__SRC, g_work_slice_u8, NULL);
if ((q == 1) && (i == 1)) {
if (status.repr != wuffs_gif__error__bad_palette) {
RETURN_FAIL("q=%d: i=%d: decode_frame: have \"%s\", want \"%s\"", q,
@@ -818,7 +817,7 @@
test_wuffs_gif_decode_background_color() {
CHECK_FOCUS(__func__);
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(
read_file(&src, "test/data/artificial/gif-background-color.gif"));
@@ -857,7 +856,7 @@
test_wuffs_gif_decode_first_frame_is_opaque() {
CHECK_FOCUS(__func__);
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(
read_file(&src, "test/data/artificial/gif-frame-out-of-bounds.gif"));
@@ -895,7 +894,7 @@
test_wuffs_gif_decode_frame_out_of_bounds() {
CHECK_FOCUS(__func__);
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(
read_file(&src, "test/data/artificial/gif-frame-out-of-bounds.gif"));
@@ -941,7 +940,7 @@
wuffs_base__pixel_config__pixel_subsampling(&ic.pixcfg).repr, 5, 5);
wuffs_base__pixel_buffer pb = ((wuffs_base__pixel_buffer){});
status = wuffs_base__pixel_buffer__set_from_slice(&pb, &five_by_five,
- global_pixel_slice);
+ g_pixel_slice_u8);
if (!wuffs_base__status__is_ok(&status)) {
RETURN_FAIL("q=%d: set_from_slice: \"%s\"", q, status.repr);
}
@@ -1010,7 +1009,7 @@
status = wuffs_gif__decoder__decode_frame(&dec, &pb, &src,
WUFFS_BASE__PIXEL_BLEND__SRC,
- global_work_slice, NULL);
+ g_work_slice_u8, NULL);
if (!wuffs_base__status__is_ok(&status)) {
RETURN_FAIL("q=%d: decode_frame #%" PRIu32 ": \"%s\"", q, i,
status.repr);
@@ -1065,7 +1064,7 @@
test_wuffs_gif_decode_zero_width_frame() {
CHECK_FOCUS(__func__);
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(
read_file(&src, "test/data/artificial/gif-zero-width-frame.gif"));
@@ -1105,13 +1104,13 @@
wuffs_base__pixel_buffer pb = ((wuffs_base__pixel_buffer){});
status = wuffs_base__pixel_buffer__set_from_slice(&pb, &ic.pixcfg,
- global_pixel_slice);
+ g_pixel_slice_u8);
if (!wuffs_base__status__is_ok(&status)) {
RETURN_FAIL("q=%d: set_from_slice: \"%s\"", q, status.repr);
}
wuffs_base__status have = wuffs_gif__decoder__decode_frame(
- &dec, &pb, &src, WUFFS_BASE__PIXEL_BLEND__SRC, global_work_slice, NULL);
+ &dec, &pb, &src, WUFFS_BASE__PIXEL_BLEND__SRC, g_work_slice_u8, NULL);
if (have.repr != want) {
RETURN_FAIL("q=%d: decode_frame: have \"%s\", want \"%s\"", q, have.repr,
want);
@@ -1213,7 +1212,7 @@
test_wuffs_gif_decode_input_is_a_png() {
CHECK_FOCUS(__func__);
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(read_file(&src, "test/data/bricks-dither.png"));
@@ -1237,7 +1236,7 @@
test_wuffs_gif_decode_interlaced_truncated() {
CHECK_FOCUS(__func__);
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(
read_file(&src, "test/data/hippopotamus.interlaced.truncated.gif"));
@@ -1269,7 +1268,7 @@
wuffs_base__pixel_buffer pb = ((wuffs_base__pixel_buffer){});
CHECK_STATUS("set_from_slice", wuffs_base__pixel_buffer__set_from_slice(
- &pb, &ic.pixcfg, global_pixel_slice));
+ &pb, &ic.pixcfg, g_pixel_slice_u8));
uint8_t* pixel_ptr = wuffs_base__pixel_buffer__plane(&pb, 0).ptr;
memset(pixel_ptr, 0xEE, num_pixel_indexes);
@@ -1279,7 +1278,7 @@
}
wuffs_base__status status = wuffs_gif__decoder__decode_frame(
- &dec, &pb, &src, WUFFS_BASE__PIXEL_BLEND__SRC, global_work_slice, NULL);
+ &dec, &pb, &src, WUFFS_BASE__PIXEL_BLEND__SRC, g_work_slice_u8, NULL);
if (status.repr != wuffs_base__suspension__short_read) {
RETURN_FAIL("decode_frame: have \"%s\", want \"%s\"", status.repr,
wuffs_base__suspension__short_read);
@@ -1300,9 +1299,10 @@
return NULL;
}
-const char* do_test_wuffs_gif_decode_metadata(bool full) {
+const char* //
+do_test_wuffs_gif_decode_metadata(bool full) {
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(
read_file(&src, full ? "test/data/artificial/gif-metadata-full.gif"
@@ -1472,7 +1472,7 @@
test_wuffs_gif_decode_missing_two_src_bytes() {
CHECK_FOCUS(__func__);
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(read_file(&src, "test/data/pjw-thumbnail.gif"));
@@ -1490,7 +1490,7 @@
test_wuffs_gif_decode_multiple_graphic_controls() {
CHECK_FOCUS(__func__);
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(read_file(
&src, "test/data/artificial/gif-multiple-graphic-controls.gif"));
@@ -1517,7 +1517,7 @@
test_wuffs_gif_decode_multiple_loop_counts() {
CHECK_FOCUS(__func__);
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(
read_file(&src, "test/data/artificial/gif-multiple-loop-counts.gif"));
@@ -1579,7 +1579,7 @@
test_wuffs_gif_decode_pixel_data_none() {
CHECK_FOCUS(__func__);
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(read_file(&src, "test/data/artificial/gif-pixel-data-none.gif"));
@@ -1591,7 +1591,7 @@
test_wuffs_gif_decode_pixel_data_not_enough() {
CHECK_FOCUS(__func__);
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(
read_file(&src, "test/data/artificial/gif-pixel-data-not-enough.gif"));
@@ -1604,7 +1604,7 @@
test_wuffs_gif_decode_pixel_data_too_much_sans_quirk() {
CHECK_FOCUS(__func__);
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(
read_file(&src, "test/data/artificial/gif-pixel-data-too-much.gif"));
@@ -1617,7 +1617,7 @@
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,
+ .data = g_src_slice_u8,
});
CHECK_STRING(
read_file(&src, "test/data/artificial/gif-pixel-data-too-much.gif"));
@@ -1630,7 +1630,7 @@
test_wuffs_gif_frame_dirty_rect() {
CHECK_FOCUS(__func__);
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(read_file(&src, "test/data/hippopotamus.interlaced.gif"));
@@ -1646,7 +1646,7 @@
wuffs_base__pixel_buffer pb = ((wuffs_base__pixel_buffer){});
CHECK_STATUS("set_from_slice", wuffs_base__pixel_buffer__set_from_slice(
- &pb, &ic.pixcfg, global_pixel_slice));
+ &pb, &ic.pixcfg, g_pixel_slice_u8));
// The hippopotamus.interlaced.gif image is 28 pixels high. As we decode rows
// of pixels, interlacing means that we decode rows 0, 8, 16, 24, 4, 12, 20,
@@ -1661,8 +1661,8 @@
wuffs_base__io_buffer limited_src = make_limited_reader(src, 1);
wuffs_base__status status = wuffs_gif__decoder__decode_frame(
- &dec, &pb, &limited_src, WUFFS_BASE__PIXEL_BLEND__SRC,
- global_work_slice, NULL);
+ &dec, &pb, &limited_src, WUFFS_BASE__PIXEL_BLEND__SRC, g_work_slice_u8,
+ NULL);
src.meta.ri += limited_src.meta.ri;
wuffs_base__rect_ie_u32 r = wuffs_gif__decoder__frame_dirty_rect(&dec);
@@ -1685,9 +1685,10 @@
return NULL;
}
-const char* do_test_wuffs_gif_num_decoded(bool frame_config) {
+const char* //
+do_test_wuffs_gif_num_decoded(bool frame_config) {
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(read_file(&src, "test/data/animated-red-blue.gif"));
@@ -1704,7 +1705,7 @@
wuffs_gif__decoder__decode_image_config(&dec, &ic, &src));
CHECK_STATUS("set_from_slice", wuffs_base__pixel_buffer__set_from_slice(
- &pb, &ic.pixcfg, global_pixel_slice));
+ &pb, &ic.pixcfg, g_pixel_slice_u8));
}
const char* method = frame_config ? "decode_frame_config" : "decode_frame";
@@ -1728,9 +1729,8 @@
if (frame_config) {
status = wuffs_gif__decoder__decode_frame_config(&dec, NULL, &src);
} else {
- status = wuffs_gif__decoder__decode_frame(&dec, &pb, &src,
- WUFFS_BASE__PIXEL_BLEND__SRC,
- global_work_slice, NULL);
+ status = wuffs_gif__decoder__decode_frame(
+ &dec, &pb, &src, WUFFS_BASE__PIXEL_BLEND__SRC, g_work_slice_u8, NULL);
}
if (wuffs_base__status__is_ok(&status)) {
@@ -1761,9 +1761,10 @@
return do_test_wuffs_gif_num_decoded(false);
}
-const char* do_test_wuffs_gif_io_position(bool chunked) {
+const char* //
+do_test_wuffs_gif_io_position(bool chunked) {
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(read_file(&src, "test/data/animated-red-blue.gif"));
@@ -1929,7 +1930,7 @@
test_wuffs_gif_small_frame_interlaced() {
CHECK_FOCUS(__func__);
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(
read_file(&src, "test/data/artificial/gif-small-frame-interlaced.gif"));
@@ -1954,7 +1955,7 @@
wuffs_base__pixel_buffer pb = ((wuffs_base__pixel_buffer){});
CHECK_STATUS("set_from_slice", wuffs_base__pixel_buffer__set_from_slice(
- &pb, &ic.pixcfg, global_pixel_slice));
+ &pb, &ic.pixcfg, g_pixel_slice_u8));
wuffs_base__frame_config fc;
CHECK_STATUS("decode_frame_config",
@@ -1969,7 +1970,7 @@
CHECK_STATUS("decode_frame",
wuffs_gif__decoder__decode_frame(&dec, &pb, &src,
WUFFS_BASE__PIXEL_BLEND__SRC,
- global_work_slice, NULL));
+ g_work_slice_u8, NULL));
wuffs_base__rect_ie_u32 dr = wuffs_gif__decoder__frame_dirty_rect(&dec);
if (dr.max_excl_y != 3) {
@@ -1999,15 +2000,16 @@
#ifdef WUFFS_MIMIC
-const char* do_test_mimic_gif_decode(const char* filename) {
+const char* //
+do_test_mimic_gif_decode(const char* filename) {
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(read_file(&src, filename));
src.meta.ri = 0;
wuffs_base__io_buffer have = ((wuffs_base__io_buffer){
- .data = global_have_slice,
+ .data = g_have_slice_u8,
});
CHECK_STRING(
wuffs_gif_decode(&have, 0,
@@ -2017,7 +2019,7 @@
src.meta.ri = 0;
wuffs_base__io_buffer want = ((wuffs_base__io_buffer){
- .data = global_want_slice,
+ .data = g_want_slice_u8,
});
CHECK_STRING(
mimic_gif_decode(&want, 0,
@@ -2125,17 +2127,17 @@
wuffs_base__pixel_format pixfmt,
uint64_t iters_unscaled) {
wuffs_base__io_buffer have = ((wuffs_base__io_buffer){
- .data = global_have_slice,
+ .data = g_have_slice_u8,
});
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(read_file(&src, filename));
bench_start();
uint64_t n_bytes = 0;
uint64_t i;
- uint64_t iters = iters_unscaled * flags.iterscale;
+ uint64_t iters = iters_unscaled * g_flags.iterscale;
for (i = 0; i < iters; i++) {
have.meta.wi = 0;
src.meta.ri = 0;
@@ -2354,106 +2356,104 @@
// ---------------- Manifest
-// The empty comments forces clang-format to place one element per line.
-proc tests[] = {
+proc g_tests[] = {
// These basic tests are really testing the Wuffs compiler. They aren't
// specific to the std/gif code, but putting them here is as good as any
// other place.
- test_basic_bad_receiver, //
- test_basic_bad_sizeof_receiver, //
- test_basic_bad_wuffs_version, //
- test_basic_initialize_not_called, //
- test_basic_status_is_error, //
- test_basic_sub_struct_initializer, //
+ test_basic_bad_receiver,
+ test_basic_bad_sizeof_receiver,
+ test_basic_bad_wuffs_version,
+ test_basic_initialize_not_called,
+ test_basic_status_is_error,
+ test_basic_sub_struct_initializer,
- test_wuffs_gif_call_interleaved, //
- test_wuffs_gif_call_sequence, //
- test_wuffs_gif_decode_animated_big, //
- test_wuffs_gif_decode_animated_medium, //
- test_wuffs_gif_decode_animated_small, //
- 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_interface_image_config_decoder, //
- test_wuffs_gif_decode_interface_image_decoder, //
- test_wuffs_gif_decode_interlaced_truncated, //
- test_wuffs_gif_decode_metadata_empty, //
- test_wuffs_gif_decode_metadata_full, //
- 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_sans_quirk, //
- test_wuffs_gif_decode_pixel_data_too_much_with_quirk, //
- test_wuffs_gif_decode_pixfmt_bgr, //
- test_wuffs_gif_decode_pixfmt_bgr_565, //
- 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, //
- test_wuffs_gif_io_position_one_chunk, //
- test_wuffs_gif_io_position_two_chunks, //
- test_wuffs_gif_small_frame_interlaced, //
- test_wuffs_gif_sizeof, //
+ test_wuffs_gif_call_interleaved,
+ test_wuffs_gif_call_sequence,
+ test_wuffs_gif_decode_animated_big,
+ test_wuffs_gif_decode_animated_medium,
+ test_wuffs_gif_decode_animated_small,
+ 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_interface_image_config_decoder,
+ test_wuffs_gif_decode_interface_image_decoder,
+ test_wuffs_gif_decode_interlaced_truncated,
+ test_wuffs_gif_decode_metadata_empty,
+ test_wuffs_gif_decode_metadata_full,
+ 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_sans_quirk,
+ test_wuffs_gif_decode_pixel_data_too_much_with_quirk,
+ test_wuffs_gif_decode_pixfmt_bgr,
+ test_wuffs_gif_decode_pixfmt_bgr_565,
+ 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,
+ test_wuffs_gif_io_position_one_chunk,
+ test_wuffs_gif_io_position_two_chunks,
+ test_wuffs_gif_small_frame_interlaced,
+ test_wuffs_gif_sizeof,
#ifdef WUFFS_MIMIC
- test_mimic_gif_decode_animated_small, //
- test_mimic_gif_decode_bricks_dither, //
- test_mimic_gif_decode_bricks_gray, //
- test_mimic_gif_decode_bricks_nodither, //
- test_mimic_gif_decode_gifplayer_muybridge, //
- test_mimic_gif_decode_harvesters, //
- test_mimic_gif_decode_hat, //
- test_mimic_gif_decode_hibiscus_primitive, //
- test_mimic_gif_decode_hibiscus_regular, //
- test_mimic_gif_decode_hippopotamus_interlaced, //
- test_mimic_gif_decode_hippopotamus_regular, //
- test_mimic_gif_decode_muybridge, //
- test_mimic_gif_decode_pjw_thumbnail, //
+ test_mimic_gif_decode_animated_small,
+ test_mimic_gif_decode_bricks_dither,
+ test_mimic_gif_decode_bricks_gray,
+ test_mimic_gif_decode_bricks_nodither,
+ test_mimic_gif_decode_gifplayer_muybridge,
+ test_mimic_gif_decode_harvesters,
+ test_mimic_gif_decode_hat,
+ test_mimic_gif_decode_hibiscus_primitive,
+ test_mimic_gif_decode_hibiscus_regular,
+ test_mimic_gif_decode_hippopotamus_interlaced,
+ test_mimic_gif_decode_hippopotamus_regular,
+ test_mimic_gif_decode_muybridge,
+ test_mimic_gif_decode_pjw_thumbnail,
#endif // WUFFS_MIMIC
NULL,
};
-// The empty comments forces clang-format to place one element per line.
-proc benches[] = {
+proc g_benches[] = {
- bench_wuffs_gif_decode_1k_bw, //
- bench_wuffs_gif_decode_1k_color_full_init, //
- bench_wuffs_gif_decode_1k_color_part_init, //
- bench_wuffs_gif_decode_10k_bgra, //
- bench_wuffs_gif_decode_10k_indexed, //
- bench_wuffs_gif_decode_20k, //
- bench_wuffs_gif_decode_100k_artificial, //
- bench_wuffs_gif_decode_100k_realistic, //
- bench_wuffs_gif_decode_1000k_full_init, //
- bench_wuffs_gif_decode_1000k_part_init, //
- bench_wuffs_gif_decode_anim_screencap, //
+ bench_wuffs_gif_decode_1k_bw,
+ bench_wuffs_gif_decode_1k_color_full_init,
+ bench_wuffs_gif_decode_1k_color_part_init,
+ bench_wuffs_gif_decode_10k_bgra,
+ bench_wuffs_gif_decode_10k_indexed,
+ bench_wuffs_gif_decode_20k,
+ bench_wuffs_gif_decode_100k_artificial,
+ bench_wuffs_gif_decode_100k_realistic,
+ bench_wuffs_gif_decode_1000k_full_init,
+ bench_wuffs_gif_decode_1000k_part_init,
+ bench_wuffs_gif_decode_anim_screencap,
#ifdef WUFFS_MIMIC
- bench_mimic_gif_decode_1k_bw, //
- bench_mimic_gif_decode_1k_color, //
- bench_mimic_gif_decode_10k_indexed, //
- bench_mimic_gif_decode_20k, //
- bench_mimic_gif_decode_100k_artificial, //
- bench_mimic_gif_decode_100k_realistic, //
- bench_mimic_gif_decode_1000k, //
- bench_mimic_gif_decode_anim_screencap, //
+ bench_mimic_gif_decode_1k_bw,
+ bench_mimic_gif_decode_1k_color,
+ bench_mimic_gif_decode_10k_indexed,
+ bench_mimic_gif_decode_20k,
+ bench_mimic_gif_decode_100k_artificial,
+ bench_mimic_gif_decode_100k_realistic,
+ bench_mimic_gif_decode_1000k,
+ bench_mimic_gif_decode_anim_screencap,
#endif // WUFFS_MIMIC
@@ -2462,6 +2462,6 @@
int //
main(int argc, char** argv) {
- proc_package_name = "std/gif";
- return test_main(argc, argv, tests, benches);
+ g_proc_package_name = "std/gif";
+ return test_main(argc, argv, g_tests, g_benches);
}
diff --git a/test/c/std/gzip.c b/test/c/std/gzip.c
index 5be741f..9a7318d 100644
--- a/test/c/std/gzip.c
+++ b/test/c/std/gzip.c
@@ -71,14 +71,14 @@
// ---------------- Golden Tests
-golden_test gzip_midsummer_gt = {
- .want_filename = "test/data/midsummer.txt", //
- .src_filename = "test/data/midsummer.txt.gz", //
+golden_test g_gzip_midsummer_gt = {
+ .want_filename = "test/data/midsummer.txt",
+ .src_filename = "test/data/midsummer.txt.gz",
};
-golden_test gzip_pi_gt = {
- .want_filename = "test/data/pi.txt", //
- .src_filename = "test/data/pi.txt.gz", //
+golden_test g_gzip_pi_gt = {
+ .want_filename = "test/data/pi.txt",
+ .src_filename = "test/data/pi.txt.gz",
};
// ---------------- Gzip Tests
@@ -112,7 +112,7 @@
wuffs_base__io_buffer limited_src = make_limited_reader(*src, rlimit);
wuffs_base__status status = wuffs_gzip__decoder__transform_io(
- &dec, &limited_dst, &limited_src, global_work_slice);
+ &dec, &limited_dst, &limited_src, g_work_slice_u8);
dst->meta.wi += limited_dst.meta.wi;
src->meta.ri += limited_src.meta.ri;
@@ -130,13 +130,13 @@
const char* //
do_test_wuffs_gzip_checksum(bool ignore_checksum, uint32_t bad_checksum) {
wuffs_base__io_buffer have = ((wuffs_base__io_buffer){
- .data = global_have_slice,
+ .data = g_have_slice_u8,
});
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
- CHECK_STRING(read_file(&src, gzip_midsummer_gt.src_filename));
+ CHECK_STRING(read_file(&src, g_gzip_midsummer_gt.src_filename));
// Flip a bit in the gzip checksum, which is in the last 8 bytes of the file.
if (src.meta.wi < 8) {
@@ -180,7 +180,7 @@
wuffs_base__io_buffer limited_src = make_limited_reader(src, rlimit);
wuffs_base__status have_z = wuffs_gzip__decoder__transform_io(
- &dec, &have, &limited_src, global_work_slice);
+ &dec, &have, &limited_src, g_work_slice_u8);
src.meta.ri += limited_src.meta.ri;
if (have_z.repr != want_z) {
RETURN_FAIL("end_limit=%d: have \"%s\", want \"%s\"", end_limit,
@@ -218,14 +218,14 @@
const char* //
test_wuffs_gzip_decode_midsummer() {
CHECK_FOCUS(__func__);
- return do_test_io_buffers(wuffs_gzip_decode, &gzip_midsummer_gt, UINT64_MAX,
+ return do_test_io_buffers(wuffs_gzip_decode, &g_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, UINT64_MAX,
+ return do_test_io_buffers(wuffs_gzip_decode, &g_gzip_pi_gt, UINT64_MAX,
UINT64_MAX);
}
@@ -236,14 +236,14 @@
const char* //
test_mimic_gzip_decode_midsummer() {
CHECK_FOCUS(__func__);
- return do_test_io_buffers(mimic_gzip_decode, &gzip_midsummer_gt, UINT64_MAX,
+ return do_test_io_buffers(mimic_gzip_decode, &g_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, UINT64_MAX,
+ return do_test_io_buffers(mimic_gzip_decode, &g_gzip_pi_gt, UINT64_MAX,
UINT64_MAX);
}
@@ -256,7 +256,7 @@
CHECK_FOCUS(__func__);
return do_bench_io_buffers(
wuffs_gzip_decode, WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED,
- tcounter_dst, &gzip_midsummer_gt, UINT64_MAX, UINT64_MAX, 300);
+ tcounter_dst, &g_gzip_midsummer_gt, UINT64_MAX, UINT64_MAX, 300);
}
const char* //
@@ -264,7 +264,7 @@
CHECK_FOCUS(__func__);
return do_bench_io_buffers(
wuffs_gzip_decode, WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED,
- tcounter_dst, &gzip_pi_gt, UINT64_MAX, UINT64_MAX, 30);
+ tcounter_dst, &g_gzip_pi_gt, UINT64_MAX, UINT64_MAX, 30);
}
// ---------------- Mimic Benches
@@ -275,13 +275,13 @@
bench_mimic_gzip_decode_10k() {
CHECK_FOCUS(__func__);
return do_bench_io_buffers(mimic_gzip_decode, 0, tcounter_dst,
- &gzip_midsummer_gt, UINT64_MAX, UINT64_MAX, 300);
+ &g_gzip_midsummer_gt, UINT64_MAX, UINT64_MAX, 300);
}
const char* //
bench_mimic_gzip_decode_100k() {
CHECK_FOCUS(__func__);
- return do_bench_io_buffers(mimic_gzip_decode, 0, tcounter_dst, &gzip_pi_gt,
+ return do_bench_io_buffers(mimic_gzip_decode, 0, tcounter_dst, &g_gzip_pi_gt,
UINT64_MAX, UINT64_MAX, 30);
}
@@ -292,37 +292,35 @@
// Note that the gzip mimic tests and benches don't work with
// WUFFS_MIMICLIB_USE_MINIZ_INSTEAD_OF_ZLIB.
-// The empty comments forces clang-format to place one element per line.
-proc tests[] = {
+proc g_tests[] = {
- test_wuffs_gzip_checksum_ignore, //
- test_wuffs_gzip_checksum_verify_bad0, //
- test_wuffs_gzip_checksum_verify_bad7, //
- test_wuffs_gzip_checksum_verify_good, //
- test_wuffs_gzip_decode_interface, //
- test_wuffs_gzip_decode_midsummer, //
- test_wuffs_gzip_decode_pi, //
+ test_wuffs_gzip_checksum_ignore,
+ test_wuffs_gzip_checksum_verify_bad0,
+ test_wuffs_gzip_checksum_verify_bad7,
+ test_wuffs_gzip_checksum_verify_good,
+ test_wuffs_gzip_decode_interface,
+ test_wuffs_gzip_decode_midsummer,
+ test_wuffs_gzip_decode_pi,
#ifdef WUFFS_MIMIC
- test_mimic_gzip_decode_midsummer, //
- test_mimic_gzip_decode_pi, //
+ test_mimic_gzip_decode_midsummer,
+ test_mimic_gzip_decode_pi,
#endif // WUFFS_MIMIC
NULL,
};
-// The empty comments forces clang-format to place one element per line.
-proc benches[] = {
+proc g_benches[] = {
- bench_wuffs_gzip_decode_10k, //
- bench_wuffs_gzip_decode_100k, //
+ bench_wuffs_gzip_decode_10k,
+ bench_wuffs_gzip_decode_100k,
#ifdef WUFFS_MIMIC
- bench_mimic_gzip_decode_10k, //
- bench_mimic_gzip_decode_100k, //
+ bench_mimic_gzip_decode_10k,
+ bench_mimic_gzip_decode_100k,
#endif // WUFFS_MIMIC
@@ -331,6 +329,6 @@
int //
main(int argc, char** argv) {
- proc_package_name = "std/gzip";
- return test_main(argc, argv, tests, benches);
+ g_proc_package_name = "std/gzip";
+ return test_main(argc, argv, g_tests, g_benches);
}
diff --git a/test/c/std/json.c b/test/c/std/json.c
index ae52f56..5352664 100644
--- a/test/c/std/json.c
+++ b/test/c/std/json.c
@@ -67,6 +67,77 @@
// No mimic library.
#endif
+// ---------------- Numeric Types Tests
+
+const char* //
+test_wuffs_core_count_leading_zeroes_u64() {
+ CHECK_FOCUS(__func__);
+
+ struct {
+ uint64_t num;
+ uint32_t want;
+ } test_cases[] = {
+ {.num = 0x0000000000000000, .want = 64},
+ {.num = 0x0000000000000001, .want = 63},
+ {.num = 0x0000000000008001, .want = 48},
+ {.num = 0x0000000040302010, .want = 33},
+ {.num = 0x0123456789ABCDEF, .want = 7},
+ {.num = 0x8000000000000001, .want = 0},
+ {.num = 0xFFFFFFFFFFFFFFFF, .want = 0},
+ };
+
+ int tc;
+ for (tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) {
+ uint32_t have = wuffs_base__count_leading_zeroes_u64(test_cases[tc].num);
+ if (have != test_cases[tc].want) {
+ RETURN_FAIL("0x%" PRIX64 ": have %" PRIu32 ", want %" PRIu32,
+ test_cases[tc].num, have, test_cases[tc].want);
+ }
+ }
+
+ return NULL;
+}
+
+const char* //
+test_wuffs_core_multiply_u64() {
+ CHECK_FOCUS(__func__);
+
+ struct {
+ uint64_t x;
+ uint64_t y;
+ uint64_t want_hi;
+ uint64_t want_lo;
+ } test_cases[] = {
+ {.x = 0x0000000000005678,
+ .y = 0x0000000000001001,
+ .want_hi = 0x0000000000000000,
+ .want_lo = 0x000000000567D678},
+ {.x = 0x00000000DEADBEEF,
+ .y = 0x000000BEEEEEEEEF,
+ .want_hi = 0x00000000000000A6,
+ .want_lo = 0x14C912411FE97321},
+ {.x = 0x0123456789ABCDEF,
+ .y = 0x8080707066554321,
+ .want_hi = 0x009234D666DAD50F,
+ .want_lo = 0x89B3DE09506618CF},
+ };
+
+ int tc;
+ for (tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) {
+ wuffs_base__multiply_u64__output have =
+ wuffs_base__multiply_u64(test_cases[tc].x, test_cases[tc].y);
+ if ((have.hi != test_cases[tc].want_hi) ||
+ (have.lo != test_cases[tc].want_lo)) {
+ RETURN_FAIL("0x%" PRIX64 " * 0x%" PRIX64 ": have (0x%" PRIX64
+ ", 0x%" PRIX64 "), want (0x%" PRIX64 ", 0x%" PRIX64 ")",
+ test_cases[tc].x, test_cases[tc].y, have.hi, have.lo,
+ test_cases[tc].want_hi, test_cases[tc].want_lo);
+ }
+ }
+
+ return NULL;
+}
+
// ---------------- String Conversions Tests
// wuffs_base__private_implementation__high_prec_dec__to_debug_string converts
@@ -217,39 +288,39 @@
uint64_t want;
const char* str;
} test_cases[] = {
- {.want = 4, .str = "-3.9"}, //
- {.want = 3, .str = "-3.14159"}, //
- {.want = 0, .str = "+0"}, //
- {.want = 0, .str = "0.0000000009"}, //
- {.want = 0, .str = "0.1"}, //
- {.want = 1, .str = "0.9"}, //
- {.want = 12, .str = "1234e-2"}, //
- {.want = 57, .str = "5678e-2"}, //
- {.want = 60, .str = "60.0"}, //
- {.want = 60, .str = "60.4999"}, //
- {.want = 60, .str = "60.5"}, //
- {.want = 60, .str = "60.5000"}, //
- {.want = 61, .str = "60.5001"}, //
- {.want = 61, .str = "60.6"}, //
- {.want = 61, .str = "61.0"}, //
- {.want = 61, .str = "61.4999"}, //
- {.want = 62, .str = "61.5"}, //
- {.want = 62, .str = "61.5000"}, //
- {.want = 62, .str = "61.5001"}, //
- {.want = 62, .str = "61.6"}, //
- {.want = 62, .str = "62.0"}, //
- {.want = 62, .str = "62.4999"}, //
- {.want = 62, .str = "62.5"}, //
- {.want = 62, .str = "62.5000"}, //
- {.want = 63, .str = "62.5001"}, //
- {.want = 63, .str = "62.6"}, //
- {.want = 1000, .str = "999.999"}, //
- {.want = 4560000, .str = "456e+4"}, //
+ {.want = 4, .str = "-3.9"},
+ {.want = 3, .str = "-3.14159"},
+ {.want = 0, .str = "+0"},
+ {.want = 0, .str = "0.0000000009"},
+ {.want = 0, .str = "0.1"},
+ {.want = 1, .str = "0.9"},
+ {.want = 12, .str = "1234e-2"},
+ {.want = 57, .str = "5678e-2"},
+ {.want = 60, .str = "60.0"},
+ {.want = 60, .str = "60.4999"},
+ {.want = 60, .str = "60.5"},
+ {.want = 60, .str = "60.5000"},
+ {.want = 61, .str = "60.5001"},
+ {.want = 61, .str = "60.6"},
+ {.want = 61, .str = "61.0"},
+ {.want = 61, .str = "61.4999"},
+ {.want = 62, .str = "61.5"},
+ {.want = 62, .str = "61.5000"},
+ {.want = 62, .str = "61.5001"},
+ {.want = 62, .str = "61.6"},
+ {.want = 62, .str = "62.0"},
+ {.want = 62, .str = "62.4999"},
+ {.want = 62, .str = "62.5"},
+ {.want = 62, .str = "62.5000"},
+ {.want = 63, .str = "62.5001"},
+ {.want = 63, .str = "62.6"},
+ {.want = 1000, .str = "999.999"},
+ {.want = 4560000, .str = "456e+4"},
// With round-to-even, ½ rounds to 0 but "a tiny bit more than ½" rounds
// to 1, even if the HPD struct truncates that "1" digit.
- {.want = 0, .str = "0.5"}, //
- {.want = 1, // 50 '0's per row.
+ {.want = 0, .str = "0.5"},
+ {.want = 1, // 50 '0's per row.
.str = "0.500000000000000000000000000000000000000000000000"
"00000000000000000000000000000000000000000000000000"
"00000000000000000000000000000000000000000000000000"
@@ -262,14 +333,14 @@
"00000000000000000000000000000000000000000000000000"
"00000000000000000000000000000000000000000000000000"
"00000000000000000000000000000000000000000000000000"
- "00000000000000000000000000000000000000000000000001"}, //
+ "00000000000000000000000000000000000000000000000001"},
// Inputs with exactly 18 decimal digits before the decimal point.
- {.want = 123456789012345679, .str = "123456789012345678.9"}, //
- {.want = 1000000000000000000, .str = "999999999999999999.9"}, //
+ {.want = 123456789012345679, .str = "123456789012345678.9"},
+ {.want = 1000000000000000000, .str = "999999999999999999.9"},
// Inputs with exactly 19 decimal digits before the decimal point.
- {.want = UINT64_MAX, .str = "1234567890123456789"}, //
+ {.want = UINT64_MAX, .str = "1234567890123456789"},
};
int tc;
@@ -300,21 +371,21 @@
int32_t shift; // -ve means left shift, +ve means right shift.
const char* want;
} test_cases[] = {
- {.str = "0", .shift = +2, .want = "+0"}, //
- {.str = "1", .shift = +3, .want = "+.125"}, //
- {.str = "12e3", .shift = +5, .want = "+375."}, //
- {.str = "-0.007", .shift = +8, .want = "-.00002734375"}, //
+ {.str = "0", .shift = +2, .want = "+0"},
+ {.str = "1", .shift = +3, .want = "+.125"},
+ {.str = "12e3", .shift = +5, .want = "+375."},
+ {.str = "-0.007", .shift = +8, .want = "-.00002734375"},
{.str = "3.14159E+26",
.shift = +60,
- .want = "+272489496.244698869986677891574800014495849609375"}, //
+ .want = "+272489496.244698869986677891574800014495849609375"},
- {.str = "0", .shift = -2, .want = "+0"}, //
- {.str = ".125", .shift = -3, .want = "+1."}, //
- {.str = "3750e-1", .shift = -5, .want = "+12000."}, //
- {.str = "-2.734375e-5", .shift = -8, .want = "-.007"}, //
+ {.str = "0", .shift = -2, .want = "+0"},
+ {.str = ".125", .shift = -3, .want = "+1."},
+ {.str = "3750e-1", .shift = -5, .want = "+12000."},
+ {.str = "-2.734375e-5", .shift = -8, .want = "-.007"},
{.str = "+272489496.244698869986677891574800014495849609375",
.shift = -60,
- .want = "+314159000000000000000000000."}, //
+ .want = "+314159000000000000000000000."},
};
int tc;
@@ -349,6 +420,184 @@
}
const char* //
+test_strconv_mpb_assign_from_hpd() {
+ CHECK_FOCUS(__func__);
+
+ struct {
+ const char* str;
+ int32_t decimal_point;
+ uint64_t want_mantissa;
+ int32_t want_exp2;
+ double want_f64;
+ } test_cases[] = {
+
+ // (0x818995CE7AA0E1B2 * (2 ** -1136)) is roughly 1e-323
+ //
+ // 1e-323 is roughly twice 4.94066e-324, the minimum subnormal positive
+ // double-precision floating point number.
+ {.str = "1",
+ .decimal_point = -322,
+ .want_mantissa = 0x818995CE7AA0E1B2,
+ .want_exp2 = -1136,
+ .want_f64 = 1e-323},
+
+ // (0xD1B71758E219652C * (2 ** -77)) is roughly .0001
+ {.str = "1",
+ .decimal_point = -3,
+ .want_mantissa = 0xD1B71758E219652C,
+ .want_exp2 = -77,
+ .want_f64 = .0001},
+
+ // (0xCCCCCCCCCCCCCCCD * (2 ** -67)) is roughly .1
+ {.str = "1",
+ .decimal_point = +0,
+ .want_mantissa = 0xCCCCCCCCCCCCCCCD,
+ .want_exp2 = -67,
+ .want_f64 = .1},
+
+ // (0x8000000000000000 * (2 ** -63)) is 1.
+ {.str = "1",
+ .decimal_point = +1,
+ .want_mantissa = 0x8000000000000000,
+ .want_exp2 = -63,
+ .want_f64 = 1},
+
+ // (0xA000000000000000 * (2 ** -60)) is 10.
+ {.str = "1",
+ .decimal_point = +2,
+ .want_mantissa = 0xA000000000000000,
+ .want_exp2 = -60,
+ .want_f64 = 10},
+
+ // (0xC9F2C9CD04674EDE * (2 ** +36)) is roughly 1e30.
+ {.str = "1",
+ .decimal_point = +31,
+ .want_mantissa = 0xC9F2C9CD04674EDE,
+ .want_exp2 = +36,
+ .want_f64 = 1e30},
+
+ // (0xDE81E40A034BCF50 * (2 ** +966)) is roughly 1e310.
+ //
+ // 1e310 is almost 50 times larger than DBL_MAX (roughly 1.8e308), so it
+ // should be converted to +infinity.
+ {.str = "1",
+ .decimal_point = +311,
+ .want_mantissa = 0xDE81E40A034BCF50,
+ .want_exp2 = +966,
+ .want_f64 = (1.0 / 0.0)},
+
+ // (0x9A40000000000000 * (2 ** -53)) is 1234.
+ {.str = "1234",
+ .decimal_point = +4,
+ .want_mantissa = 0x9A40000000000000,
+ .want_exp2 = -53,
+ .want_f64 = 1234},
+
+ // (0xC90FCF80DC33721E * (2 ** -62)) is roughly 3.14159
+ {.str = "314159",
+ .decimal_point = +1,
+ .want_mantissa = 0xC90FCF80DC33721E,
+ .want_exp2 = -62,
+ .want_f64 = 3.14159},
+ };
+
+ int tc;
+ for (tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) {
+ wuffs_base__private_implementation__high_prec_dec hpd;
+
+ // Initialize hpd.
+ uint32_t i;
+ for (i = 0; test_cases[tc].str[i]; i++) {
+ hpd.digits[i] = test_cases[tc].str[i] - '0';
+ }
+ hpd.num_digits = i;
+ hpd.decimal_point = test_cases[tc].decimal_point;
+ hpd.negative = false;
+ hpd.truncated = false;
+
+ static const bool skip_fast_path_for_tests = true;
+ wuffs_base__private_implementation__medium_prec_bin mpb;
+ wuffs_base__private_implementation__medium_prec_bin__parse_number_f64(
+ &mpb, &hpd, skip_fast_path_for_tests);
+
+ uint64_t have_mantissa = mpb.mantissa;
+ if (have_mantissa != test_cases[tc].want_mantissa) {
+ RETURN_FAIL("%s@%d: mantissa: have 0x%" PRIX64 ", want 0x%" PRIX64,
+ test_cases[tc].str, test_cases[tc].decimal_point,
+ have_mantissa, test_cases[tc].want_mantissa);
+ }
+
+ int32_t have_exp2 = mpb.exp2;
+ if (have_exp2 != test_cases[tc].want_exp2) {
+ RETURN_FAIL("%s@%d: exp2: have %" PRId32 ", want %" PRId32,
+ test_cases[tc].str, test_cases[tc].decimal_point, have_exp2,
+ test_cases[tc].want_exp2);
+ }
+
+ double have_f64 =
+ wuffs_base__private_implementation__medium_prec_bin__as_f64(&mpb,
+ false);
+ if (have_f64 != test_cases[tc].want_f64) {
+ RETURN_FAIL("%s@%d: f64: have %g, want %g", test_cases[tc].str,
+ test_cases[tc].decimal_point, have_f64,
+ test_cases[tc].want_f64);
+ }
+ }
+ return NULL;
+}
+
+// ----------------
+
+const char* //
+test_strconv_hexadecimal() {
+ CHECK_FOCUS(__func__);
+
+ {
+ const char* str = "6A6b7"; // The "7" should be ignored.
+ wuffs_base__slice_u8 dst = g_have_slice_u8;
+ wuffs_base__slice_u8 src =
+ wuffs_base__make_slice_u8((void*)str, strlen(str));
+ size_t have = wuffs_base__hexadecimal__decode2(dst, src);
+ if (have != 2) {
+ RETURN_FAIL("decode2: have %zu, want 2", have);
+ }
+ if (g_have_array_u8[0] != 0x6A) {
+ RETURN_FAIL("decode2: dst[0]: have 0x%02X, want 0x6A",
+ (int)(g_have_array_u8[0]));
+ }
+ if (g_have_array_u8[1] != 0x6B) {
+ RETURN_FAIL("decode2: dst[1]: have 0x%02X, want 0x6B",
+ (int)(g_have_array_u8[1]));
+ }
+ }
+
+ {
+ const char* str = "\\xa9\\x00\\xFe";
+ wuffs_base__slice_u8 dst = g_have_slice_u8;
+ wuffs_base__slice_u8 src =
+ wuffs_base__make_slice_u8((void*)str, strlen(str));
+ size_t have = wuffs_base__hexadecimal__decode4(dst, src);
+ if (have != 3) {
+ RETURN_FAIL("decode4: have %zu, want 3", have);
+ }
+ if (g_have_array_u8[0] != 0xA9) {
+ RETURN_FAIL("decode4: dst[0]: have 0x%02X, want 0xA9",
+ (int)(g_have_array_u8[0]));
+ }
+ if (g_have_array_u8[1] != 0x00) {
+ RETURN_FAIL("decode4: dst[1]: have 0x%02X, want 0x00",
+ (int)(g_have_array_u8[1]));
+ }
+ if (g_have_array_u8[2] != 0xFE) {
+ RETURN_FAIL("decode4: dst[2]: have 0x%02X, want 0xFE",
+ (int)(g_have_array_u8[2]));
+ }
+ }
+
+ return NULL;
+}
+
+const char* //
test_strconv_parse_number_f64() {
CHECK_FOCUS(__func__);
@@ -361,6 +610,7 @@
{.want = 0x0000000000000000, .str = "+0.0"},
{.want = 0x0000000000000000, .str = "0"},
{.want = 0x0000000000000000, .str = "0e0"},
+ {.want = 0x0000000000000000, .str = "1e-332"},
{.want = 0x0000000000000001, .str = "4.9406564584124654e-324"},
{.want = 0x000FFFFFFFFFFFFF, .str = "2.2250738585072009E-308"},
{.want = 0x0010000000000000, .str = "2.2250738585072014E-308"},
@@ -382,7 +632,10 @@
{.want = 0x3FF0000000000002, .str = "1.0000000000000004"},
{.want = 0x3FF4000000000000, .str = "1.25"},
{.want = 0x3FF8000000000000, .str = "+1.5"},
- {.want = 0x4000000000000000, .str = "2"},
+ {.want = 0x4008000000000000, .str = "3"},
+ {.want = 0x400921F9F01B866E, .str = "3.14159"},
+ {.want = 0x400921FB54442D11, .str = "3.14159265358979"},
+ {.want = 0x400921FB54442D18, .str = "3.141592653589793"},
{.want = 0x400921FB54442D18, .str = "3.141592653589793238462643383279"},
{.want = 0x400C000000000000, .str = "3.5"},
{.want = 0x4014000000000000, .str = "5"},
@@ -395,6 +648,7 @@
{.want = 0x4038000000000000, .str = "24"},
{.want = 0x4038000000000000, .str = "2400_00000_00000.00000_e-_1_2"},
{.want = 0x40FE240C9FCB0C02, .str = "123456.789012"},
+ {.want = 0x4202A05F20000000, .str = "1e10"},
{.want = 0x4330000000000000, .str = "4503599627370496"}, // 1 << 52.
{.want = 0x4330000000000000, .str = "4503599627370496.5"},
{.want = 0x4330000000000001, .str = "4503599627370497"},
@@ -406,10 +660,13 @@
{.want = 0x4340000000000002, .str = "9007199254740995"},
{.want = 0x4340000000000002, .str = "9007199254740996"},
{.want = 0x4340000000000002, .str = "9_007__199_254__740_996"},
+ {.want = 0x4415AF1D78B58C40, .str = "1e20"},
+ {.want = 0x46293E5939A08CEA, .str = "1e30"},
{.want = 0x54B249AD2594C37D, .str = "+1E+100"},
{.want = 0x54B249AD2594C37D, .str = "+_1_E_+_1_0_0_"},
{.want = 0x7FEFFFFFFFFFFFFF, .str = "1.7976931348623157e308"},
{.want = 0x7FF0000000000000, .str = "1.8e308"},
+ {.want = 0x7FF0000000000000, .str = "1e+316"},
{.want = 0x7FF0000000000000, .str = "1e999"},
{.want = 0x7FF0000000000000, .str = "__InFinity__"},
{.want = 0x7FF0000000000000, .str = "inf"},
@@ -712,26 +969,31 @@
// ---------------- Golden Tests
-golden_test json_australian_abc_gt = {
- .want_filename = "test/data/australian-abc-local-stations.tokens", //
- .src_filename = "test/data/australian-abc-local-stations.json", //
+golden_test g_json_australian_abc_gt = {
+ .want_filename = "test/data/australian-abc-local-stations.tokens",
+ .src_filename = "test/data/australian-abc-local-stations.json",
};
-golden_test json_file_sizes_gt = {
- .src_filename = "test/data/file-sizes.json", //
+golden_test g_json_file_sizes_gt = {
+ .src_filename = "test/data/file-sizes.json",
};
-golden_test json_github_tags_gt = {
- .src_filename = "test/data/github-tags.json", //
+golden_test g_json_github_tags_gt = {
+ .src_filename = "test/data/github-tags.json",
};
-golden_test json_json_things_unformatted_gt = {
- .want_filename = "test/data/json-things.unformatted.tokens", //
- .src_filename = "test/data/json-things.unformatted.json", //
+golden_test g_json_json_things_unformatted_gt = {
+ .want_filename = "test/data/json-things.unformatted.tokens",
+ .src_filename = "test/data/json-things.unformatted.json",
};
-golden_test json_nobel_prizes_gt = {
- .src_filename = "test/data/nobel-prizes.json", //
+golden_test g_json_json_quirks_gt = {
+ .want_filename = "test/data/json-quirks.tokens",
+ .src_filename = "test/data/json-quirks.json",
+};
+
+golden_test g_json_nobel_prizes_gt = {
+ .src_filename = "test/data/nobel-prizes.json",
};
// ---------------- JSON Tests
@@ -748,7 +1010,7 @@
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
CHECK_STRING(do_test__wuffs_base__token_decoder(
wuffs_json__decoder__upcast_as__wuffs_base__token_decoder(&dec),
- &json_json_things_unformatted_gt));
+ &g_json_json_things_unformatted_gt));
}
{
@@ -759,7 +1021,42 @@
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
CHECK_STRING(do_test__wuffs_base__token_decoder(
wuffs_json__decoder__upcast_as__wuffs_base__token_decoder(&dec),
- &json_australian_abc_gt));
+ &g_json_australian_abc_gt));
+ }
+
+ {
+ uint32_t quirks[] = {
+ WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_A,
+ WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_CAPITAL_U,
+ WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_E,
+ WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_QUESTION_MARK,
+ WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_SINGLE_QUOTE,
+ WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_V,
+ WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_X,
+ WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_ZERO,
+ WUFFS_JSON__QUIRK_ALLOW_COMMENT_BLOCK,
+ WUFFS_JSON__QUIRK_ALLOW_COMMENT_LINE,
+ WUFFS_JSON__QUIRK_ALLOW_EXTRA_COMMA,
+ WUFFS_JSON__QUIRK_ALLOW_INF_NAN_NUMBERS,
+ WUFFS_JSON__QUIRK_ALLOW_LEADING_ASCII_RECORD_SEPARATOR,
+ WUFFS_JSON__QUIRK_ALLOW_LEADING_UNICODE_BYTE_ORDER_MARK,
+ WUFFS_JSON__QUIRK_ALLOW_TRAILING_NEW_LINE,
+ WUFFS_JSON__QUIRK_REPLACE_INVALID_UNICODE,
+ 0,
+ };
+
+ wuffs_json__decoder dec;
+ CHECK_STATUS("initialize",
+ wuffs_json__decoder__initialize(
+ &dec, sizeof dec, WUFFS_VERSION,
+ WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
+ uint32_t i;
+ for (i = 0; quirks[i]; i++) {
+ wuffs_json__decoder__set_quirk_enabled(&dec, quirks[i], true);
+ }
+ CHECK_STRING(do_test__wuffs_base__token_decoder(
+ wuffs_json__decoder__upcast_as__wuffs_base__token_decoder(&dec),
+ &g_json_json_quirks_gt));
}
return NULL;
@@ -781,8 +1078,8 @@
make_limited_token_writer(*tok, wlimit);
wuffs_base__io_buffer limited_src = make_limited_reader(*src, rlimit);
- wuffs_base__status status =
- wuffs_json__decoder__decode_tokens(&dec, &limited_tok, &limited_src);
+ wuffs_base__status status = wuffs_json__decoder__decode_tokens(
+ &dec, &limited_tok, &limited_src, g_work_slice_u8);
tok->meta.wi += limited_tok.meta.wi;
src->meta.ri += limited_src.meta.ri;
@@ -798,6 +1095,45 @@
}
const char* //
+test_wuffs_json_decode_end_of_data() {
+ CHECK_FOCUS(__func__);
+
+ int i;
+ for (i = 0; i < 2; i++) {
+ uint8_t* src_ptr = (uint8_t*)("123null89");
+ size_t src_len = i ? 3 : 9;
+
+ wuffs_json__decoder dec;
+ CHECK_STATUS("initialize",
+ wuffs_json__decoder__initialize(
+ &dec, sizeof dec, WUFFS_VERSION,
+ WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
+
+ wuffs_base__token_buffer tok =
+ wuffs_base__make_token_buffer_writer(g_have_slice_token);
+ wuffs_base__io_buffer src = wuffs_base__make_io_buffer_reader(
+ wuffs_base__make_slice_u8(src_ptr, src_len), true);
+ CHECK_STATUS("decode_tokens", wuffs_json__decoder__decode_tokens(
+ &dec, &tok, &src, g_work_slice_u8));
+ if (src.meta.ri != 3) {
+ RETURN_FAIL("src.meta.ri: have %zu, want 3", src.meta.ri);
+ }
+
+ const char* have =
+ wuffs_json__decoder__decode_tokens(&dec, &tok, &src, g_work_slice_u8)
+ .repr;
+ if (have != wuffs_base__note__end_of_data) {
+ RETURN_FAIL("decode_tokens: have \"%s\", want \"%s\"", have,
+ wuffs_base__note__end_of_data);
+ }
+ if (src.meta.ri != 3) {
+ RETURN_FAIL("src.meta.ri: have %zu, want 3", src.meta.ri);
+ }
+ }
+ return NULL;
+}
+
+const char* //
test_wuffs_json_decode_long_numbers() {
CHECK_FOCUS(__func__);
@@ -816,30 +1152,30 @@
bool valid;
const char* suffix;
} test_cases[] = {
- {.valid = true, .suffix = ""}, //
- {.valid = true, .suffix = " "}, //
- {.valid = fals, .suffix = "."}, //
- {.valid = fals, .suffix = ". "}, //
- {.valid = fals, .suffix = "E"}, //
- {.valid = fals, .suffix = "E "}, //
- {.valid = fals, .suffix = "E-"}, //
- {.valid = fals, .suffix = "E- "}, //
- {.valid = true, .suffix = "e2"}, //
- {.valid = true, .suffix = "e2 "}, //
- {.valid = true, .suffix = "e+34"}, //
- {.valid = true, .suffix = "e+34 "}, //
- {.valid = true, .suffix = ".2"}, //
- {.valid = true, .suffix = ".2 "}, //
- {.valid = fals, .suffix = ".2e"}, //
- {.valid = fals, .suffix = ".2e "}, //
- {.valid = fals, .suffix = ".2e+"}, //
- {.valid = fals, .suffix = ".2e+ "}, //
- {.valid = true, .suffix = ".2e4"}, //
- {.valid = true, .suffix = ".2e4 "}, //
- {.valid = true, .suffix = ".2E+5"}, //
- {.valid = true, .suffix = ".2E+5 "}, //
- {.valid = true, .suffix = ".2e-5678"}, //
- {.valid = true, .suffix = ".2e-5678 "}, //
+ {.valid = true, .suffix = ""},
+ {.valid = true, .suffix = " "},
+ {.valid = fals, .suffix = "."},
+ {.valid = fals, .suffix = ". "},
+ {.valid = fals, .suffix = "E"},
+ {.valid = fals, .suffix = "E "},
+ {.valid = fals, .suffix = "E-"},
+ {.valid = fals, .suffix = "E- "},
+ {.valid = true, .suffix = "e2"},
+ {.valid = true, .suffix = "e2 "},
+ {.valid = true, .suffix = "e+34"},
+ {.valid = true, .suffix = "e+34 "},
+ {.valid = true, .suffix = ".2"},
+ {.valid = true, .suffix = ".2 "},
+ {.valid = fals, .suffix = ".2e"},
+ {.valid = fals, .suffix = ".2e "},
+ {.valid = fals, .suffix = ".2e+"},
+ {.valid = fals, .suffix = ".2e+ "},
+ {.valid = true, .suffix = ".2e4"},
+ {.valid = true, .suffix = ".2e4 "},
+ {.valid = true, .suffix = ".2E+5"},
+ {.valid = true, .suffix = ".2E+5 "},
+ {.valid = true, .suffix = ".2e-5678"},
+ {.valid = true, .suffix = ".2e-5678 "},
};
// src_array holds the overall test string. 119 is arbitrary but long enough.
@@ -885,18 +1221,13 @@
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
- wuffs_base__token_buffer tok = ((wuffs_base__token_buffer){
- .data = global_have_token_slice,
- });
-
- wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = src_data,
- .meta = wuffs_base__make_io_buffer_meta(src_data.len, 0, 0,
- closed != 0),
- });
-
- const char* have =
- wuffs_json__decoder__decode_tokens(&dec, &tok, &src).repr;
+ wuffs_base__token_buffer tok =
+ wuffs_base__make_token_buffer_writer(g_have_slice_token);
+ wuffs_base__io_buffer src =
+ wuffs_base__make_io_buffer_reader(src_data, closed != 0);
+ const char* have = wuffs_json__decoder__decode_tokens(&dec, &tok, &src,
+ g_work_slice_u8)
+ .repr;
size_t total_length = 0;
while (tok.meta.ri < tok.meta.wi) {
@@ -1020,7 +1351,7 @@
// mark, where prefix and suffix are the number of 'p's and 's's and
// test_cases[tc] is the "MIDDLE".
wuffs_base__slice_u8 src_data = ((wuffs_base__slice_u8){
- .ptr = global_src_array,
+ .ptr = &g_src_array_u8[0],
.len = 1 + prefix + n + suffix,
});
if (src_data.len > IO_BUFFER_ARRAY_SIZE) {
@@ -1036,17 +1367,11 @@
CHECK_STATUS("initialize", wuffs_json__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION, 0));
- wuffs_base__token_buffer tok = ((wuffs_base__token_buffer){
- .data = global_have_token_slice,
- });
-
- wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = src_data,
- .meta = wuffs_base__make_io_buffer_meta(src_data.len, 0, 0,
- closed != 0),
- });
-
- wuffs_json__decoder__decode_tokens(&dec, &tok, &src);
+ wuffs_base__token_buffer tok =
+ wuffs_base__make_token_buffer_writer(g_have_slice_token);
+ wuffs_base__io_buffer src =
+ wuffs_base__make_io_buffer_reader(src_data, closed != 0);
+ wuffs_json__decoder__decode_tokens(&dec, &tok, &src, g_work_slice_u8);
size_t have = 0;
while (tok.meta.ri < tok.meta.wi) {
@@ -1080,6 +1405,694 @@
}
const char* //
+test_wuffs_json_decode_quirk_allow_backslash_etc() {
+ CHECK_FOCUS(__func__);
+
+ struct {
+ uint32_t want;
+ const char* str;
+ uint32_t quirk;
+ } test_cases[] = {
+ {
+ .want = 0x07,
+ .str = "\"\\a\"",
+ .quirk = WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_A,
+ },
+ {
+ .want = 0x0001F4A9,
+ .str = "\"\\U0001F4A9\"",
+ .quirk = WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_CAPITAL_U,
+ },
+ {
+ .want = 0x1B,
+ .str = "\"\\e\"",
+ .quirk = WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_E,
+ },
+ {
+ .want = 0x3F,
+ .str = "\"\\?\"",
+ .quirk = WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_QUESTION_MARK,
+ },
+ {
+ .want = 0x27,
+ .str = "\"\\'\"",
+ .quirk = WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_SINGLE_QUOTE,
+ },
+ {
+ .want = 0x0B,
+ .str = "\"\\v\"",
+ .quirk = WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_V,
+ },
+ {
+ .want = 0x00,
+ .str = "\"\\0\"",
+ .quirk = WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_ZERO,
+ },
+ };
+
+ int tc;
+ for (tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) {
+ int q;
+ for (q = 0; q < 2; q++) {
+ wuffs_json__decoder dec;
+ CHECK_STATUS("initialize", wuffs_json__decoder__initialize(
+ &dec, sizeof dec, WUFFS_VERSION,
+ WUFFS_INITIALIZE__DEFAULT_OPTIONS));
+ wuffs_json__decoder__set_quirk_enabled(&dec, test_cases[tc].quirk, q);
+
+ wuffs_base__token_buffer tok =
+ wuffs_base__make_token_buffer_writer(g_have_slice_token);
+ wuffs_base__io_buffer src = wuffs_base__make_io_buffer_reader(
+ wuffs_base__make_slice_u8((void*)(test_cases[tc].str),
+ strlen(test_cases[tc].str)),
+ true);
+
+ const char* have_status_repr =
+ wuffs_json__decoder__decode_tokens(&dec, &tok, &src, g_work_slice_u8)
+ .repr;
+ const char* want_status_repr =
+ q ? NULL : wuffs_json__error__bad_backslash_escape;
+ if (have_status_repr != want_status_repr) {
+ RETURN_FAIL("tc=%d, q=%d: decode_tokens: have \"%s\", want \"%s\"", tc,
+ q, have_status_repr, want_status_repr);
+ }
+ if (want_status_repr != NULL) {
+ continue;
+ }
+
+ uint32_t have = 0;
+ while (tok.meta.ri < tok.meta.wi) {
+ wuffs_base__token* t = &tok.data.ptr[tok.meta.ri++];
+ uint64_t vbc = wuffs_base__token__value_base_category(t);
+ uint64_t vbd = wuffs_base__token__value_base_detail(t);
+ if (vbc == WUFFS_BASE__TOKEN__VBC__UNICODE_CODE_POINT) {
+ have = vbd;
+ break;
+ }
+ }
+ if (have != test_cases[tc].want) {
+ RETURN_FAIL("tc=%d, q=%d: Unicode code point: have U+%04" PRIX32
+ ", want U+%04" PRIX32,
+ tc, q, have, test_cases[tc].want);
+ }
+ }
+ }
+ return NULL;
+}
+
+const char* //
+test_wuffs_json_decode_quirk_allow_backslash_x() {
+ CHECK_FOCUS(__func__);
+
+ struct {
+ uint64_t want_bytes;
+ const char* want_status_repr;
+ const char* str;
+ } test_cases[] = {
+ {.want_bytes = 0x12789A,
+ .want_status_repr = NULL,
+ .str = "\"\\x12\\u3456\\x78\\x9A\""},
+ {.want_bytes = 0x00,
+ .want_status_repr = wuffs_json__error__bad_backslash_escape,
+ .str = "\"a\\X6A\""},
+ {.want_bytes = 0x6A6B,
+ .want_status_repr = NULL,
+ .str = "\"a\\x6A\\x6bz\""},
+ {.want_bytes = 0x6A,
+ .want_status_repr = wuffs_json__error__bad_backslash_escape,
+ .str = "\"a\\x6A\\x6yz\""},
+ {.want_bytes = 0x00,
+ .want_status_repr = wuffs_json__error__bad_backslash_escape,
+ .str = "\"a\\x\""},
+ };
+
+ int tc;
+ for (tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) {
+ wuffs_json__decoder dec;
+ CHECK_STATUS("initialize", wuffs_json__decoder__initialize(
+ &dec, sizeof dec, WUFFS_VERSION,
+ WUFFS_INITIALIZE__DEFAULT_OPTIONS));
+ wuffs_json__decoder__set_quirk_enabled(
+ &dec, WUFFS_JSON__QUIRK_ALLOW_BACKSLASH_X, true);
+
+ wuffs_base__token_buffer tok =
+ wuffs_base__make_token_buffer_writer(g_have_slice_token);
+ wuffs_base__slice_u8 src_slice = wuffs_base__make_slice_u8(
+ (void*)(test_cases[tc].str), strlen(test_cases[tc].str));
+ wuffs_base__io_buffer src =
+ wuffs_base__make_io_buffer_reader(src_slice, true);
+ const char* have_status_repr =
+ wuffs_json__decoder__decode_tokens(&dec, &tok, &src, g_work_slice_u8)
+ .repr;
+ if (have_status_repr != test_cases[tc].want_status_repr) {
+ RETURN_FAIL("tc=%d: decode_tokens: have \"%s\", want \"%s\"", tc,
+ have_status_repr, test_cases[tc].want_status_repr);
+ }
+
+ uint64_t src_index = 0;
+ uint64_t have_bytes = 0;
+ while (tok.meta.ri < tok.meta.wi) {
+ wuffs_base__token* t = &tok.data.ptr[tok.meta.ri++];
+ uint64_t vbc = wuffs_base__token__value_base_category(t);
+ uint64_t vbd = wuffs_base__token__value_base_detail(t);
+ uint64_t token_length = wuffs_base__token__length(t);
+ if ((vbc == WUFFS_BASE__TOKEN__VBC__STRING) &&
+ (vbd ==
+ WUFFS_BASE__TOKEN__VBD__STRING__CONVERT_1_DST_4_SRC_BACKSLASH_X)) {
+ uint8_t b[8] = {0};
+ size_t n = wuffs_base__hexadecimal__decode4(
+ wuffs_base__make_slice_u8(&b[0], 8),
+ wuffs_base__make_slice_u8(src_slice.ptr + src_index, token_length));
+ size_t i = 0;
+ for (; i < n; i++) {
+ have_bytes <<= 8;
+ have_bytes |= b[i];
+ }
+ }
+
+ src_index += token_length;
+ }
+ if (have_bytes != test_cases[tc].want_bytes) {
+ RETURN_FAIL("tc=%d: have U+%08" PRIX64 ", want U+%08" PRIX64, tc,
+ have_bytes, test_cases[tc].want_bytes);
+ }
+ }
+
+ return NULL;
+}
+
+const char* //
+test_wuffs_json_decode_quirk_allow_extra_comma() {
+ CHECK_FOCUS(__func__);
+
+ struct {
+ // want has 2 bytes, one for each possible q:
+ // - q&1 sets WUFFS_JSON__QUIRK_ALLOW_EXTRA_COMMA.
+ // An 'X', '+' or '-' means that decoding should succeed (and consume the
+ // entire input), succeed (without consuming the entire input) or fail.
+ const char* want;
+ const char* str;
+ } test_cases[] = {
+ {.want = "-X", .str = "[0,]"},
+ {.want = "-X", .str = "[[], {},{\"k\":\"v\",\n}\n,\n]"},
+ {.want = "--", .str = "[,]"},
+ {.want = "--", .str = "{,}"},
+ };
+
+ int tc;
+ for (tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) {
+ int q;
+ for (q = 0; q < 2; q++) {
+ wuffs_json__decoder dec;
+ CHECK_STATUS("initialize", wuffs_json__decoder__initialize(
+ &dec, sizeof dec, WUFFS_VERSION,
+ WUFFS_INITIALIZE__DEFAULT_OPTIONS));
+ wuffs_json__decoder__set_quirk_enabled(
+ &dec, WUFFS_JSON__QUIRK_ALLOW_EXTRA_COMMA, q & 1);
+
+ wuffs_base__token_buffer tok =
+ wuffs_base__make_token_buffer_writer(g_have_slice_token);
+ wuffs_base__io_buffer src = wuffs_base__make_io_buffer_reader(
+ wuffs_base__make_slice_u8((void*)(test_cases[tc].str),
+ strlen(test_cases[tc].str)),
+ true);
+ const char* have =
+ wuffs_json__decoder__decode_tokens(&dec, &tok, &src, g_work_slice_u8)
+ .repr;
+ const char* want =
+ (test_cases[tc].want[q] != '-') ? NULL : wuffs_json__error__bad_input;
+ if (have != want) {
+ RETURN_FAIL("tc=%d, q=%d: decode_tokens: have \"%s\", want \"%s\"", tc,
+ q, have, want);
+ }
+
+ size_t total_length = 0;
+ while (tok.meta.ri < tok.meta.wi) {
+ total_length += wuffs_base__token__length(&tok.data.ptr[tok.meta.ri++]);
+ }
+ if (total_length != src.meta.ri) {
+ RETURN_FAIL("tc=%d, q=%d: total_length: have %zu, want %zu", tc, q,
+ total_length, src.meta.ri);
+ }
+ if (test_cases[tc].want[q] == 'X') {
+ if (total_length != src.data.len) {
+ RETURN_FAIL("tc=%d, q=%d: total_length: have %zu, want %zu", tc, q,
+ total_length, src.data.len);
+ }
+ } else if (test_cases[tc].want[q] == '+') {
+ if (total_length >= src.data.len) {
+ RETURN_FAIL("tc=%d, q=%d: total_length: have %zu, want < %zu", tc, q,
+ total_length, src.data.len);
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+const char* //
+test_wuffs_json_decode_quirk_allow_inf_nan_numbers() {
+ CHECK_FOCUS(__func__);
+
+ struct {
+ // want has 2 bytes, one for each possible q:
+ // - q&1 sets WUFFS_JSON__QUIRK_ALLOW_INF_NAN_NUMBERS.
+ // An 'X', '+' or '-' means that decoding should succeed (and consume the
+ // entire input), succeed (without consuming the entire input) or fail.
+ const char* want;
+ const char* str;
+ } test_cases[] = {
+ {.want = "-X", .str = "InFiniTy"},
+ {.want = "-X", .str = "[+inf, -infinity, +nan,-NaN,NAN]"},
+ {.want = "-X", .str = "inf"},
+ {.want = "-+", .str = "infinit"},
+ {.want = "-+", .str = "infiQity"},
+ {.want = "-+", .str = "nana"},
+ {.want = "--", .str = "+-inf"},
+ {.want = "--", .str = "-+inf"},
+ {.want = "--", .str = "[infinit,"},
+ {.want = "--", .str = "[infiQity,"},
+ {.want = "--", .str = "[nana,"},
+ {.want = "--", .str = "∞"},
+ };
+
+ int tc;
+ for (tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) {
+ int q;
+ for (q = 0; q < 2; q++) {
+ wuffs_json__decoder dec;
+ CHECK_STATUS("initialize", wuffs_json__decoder__initialize(
+ &dec, sizeof dec, WUFFS_VERSION,
+ WUFFS_INITIALIZE__DEFAULT_OPTIONS));
+ wuffs_json__decoder__set_quirk_enabled(
+ &dec, WUFFS_JSON__QUIRK_ALLOW_INF_NAN_NUMBERS, q & 1);
+
+ wuffs_base__token_buffer tok =
+ wuffs_base__make_token_buffer_writer(g_have_slice_token);
+ wuffs_base__io_buffer src = wuffs_base__make_io_buffer_reader(
+ wuffs_base__make_slice_u8((void*)(test_cases[tc].str),
+ strlen(test_cases[tc].str)),
+ true);
+ const char* have =
+ wuffs_json__decoder__decode_tokens(&dec, &tok, &src, g_work_slice_u8)
+ .repr;
+ const char* want =
+ (test_cases[tc].want[q] != '-') ? NULL : wuffs_json__error__bad_input;
+ if (have != want) {
+ RETURN_FAIL("tc=%d, q=%d: decode_tokens: have \"%s\", want \"%s\"", tc,
+ q, have, want);
+ }
+
+ size_t total_length = 0;
+ while (tok.meta.ri < tok.meta.wi) {
+ total_length += wuffs_base__token__length(&tok.data.ptr[tok.meta.ri++]);
+ }
+ if (total_length != src.meta.ri) {
+ RETURN_FAIL("tc=%d, q=%d: total_length: have %zu, want %zu", tc, q,
+ total_length, src.meta.ri);
+ }
+ if (test_cases[tc].want[q] == 'X') {
+ if (total_length != src.data.len) {
+ RETURN_FAIL("tc=%d, q=%d: total_length: have %zu, want %zu", tc, q,
+ total_length, src.data.len);
+ }
+ } else if (test_cases[tc].want[q] == '+') {
+ if (total_length >= src.data.len) {
+ RETURN_FAIL("tc=%d, q=%d: total_length: have %zu, want < %zu", tc, q,
+ total_length, src.data.len);
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+const char* //
+test_wuffs_json_decode_quirk_allow_comment_etc() {
+ CHECK_FOCUS(__func__);
+
+ struct {
+ // want has 4 bytes, one for each possible q:
+ // - q&1 sets WUFFS_JSON__QUIRK_ALLOW_COMMENT_BLOCK.
+ // - q&2 sets WUFFS_JSON__QUIRK_ALLOW_COMMENT_LINE.
+ // An 'X', '+' or '-' means that decoding should succeed (and consume the
+ // entire input), succeed (without consuming the entire input) or fail.
+ const char* want;
+ const char* str;
+ } test_cases[] = {
+ {.want = "-X-X", .str = "[ /*com*/ 0]"},
+ {.want = "--XX", .str = "//l\n //m\n0"},
+ {.want = "---X", .str = "[ 0, /*com*/ 1 //l\n\n]"},
+ {.want = "----", .str = "/*/0"}, // Not a valid slash-star comment.
+ {.want = "----", .str = "[4/5]"}, // Lone slash.
+ };
+
+ int tc;
+ for (tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) {
+ int q;
+ for (q = 0; q < 4; q++) {
+ wuffs_json__decoder dec;
+ CHECK_STATUS("initialize", wuffs_json__decoder__initialize(
+ &dec, sizeof dec, WUFFS_VERSION,
+ WUFFS_INITIALIZE__DEFAULT_OPTIONS));
+ wuffs_json__decoder__set_quirk_enabled(
+ &dec, WUFFS_JSON__QUIRK_ALLOW_COMMENT_BLOCK, q & 1);
+ wuffs_json__decoder__set_quirk_enabled(
+ &dec, WUFFS_JSON__QUIRK_ALLOW_COMMENT_LINE, q & 2);
+
+ wuffs_base__token_buffer tok =
+ wuffs_base__make_token_buffer_writer(g_have_slice_token);
+ wuffs_base__io_buffer src = wuffs_base__make_io_buffer_reader(
+ wuffs_base__make_slice_u8((void*)(test_cases[tc].str),
+ strlen(test_cases[tc].str)),
+ true);
+ const char* have =
+ wuffs_json__decoder__decode_tokens(&dec, &tok, &src, g_work_slice_u8)
+ .repr;
+ const char* want =
+ (test_cases[tc].want[q] != '-') ? NULL : wuffs_json__error__bad_input;
+ if (have != want) {
+ RETURN_FAIL("tc=%d, q=%d: decode_tokens: have \"%s\", want \"%s\"", tc,
+ q, have, want);
+ }
+
+ size_t total_length = 0;
+ while (tok.meta.ri < tok.meta.wi) {
+ total_length += wuffs_base__token__length(&tok.data.ptr[tok.meta.ri++]);
+ }
+ if (total_length != src.meta.ri) {
+ RETURN_FAIL("tc=%d, q=%d: total_length: have %zu, want %zu", tc, q,
+ total_length, src.meta.ri);
+ }
+ if (test_cases[tc].want[q] == 'X') {
+ if (total_length != src.data.len) {
+ RETURN_FAIL("tc=%d, q=%d: total_length: have %zu, want %zu", tc, q,
+ total_length, src.data.len);
+ }
+ } else if (test_cases[tc].want[q] == '+') {
+ if (total_length >= src.data.len) {
+ RETURN_FAIL("tc=%d, q=%d: total_length: have %zu, want < %zu", tc, q,
+ total_length, src.data.len);
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+const char* //
+test_wuffs_json_decode_quirk_allow_leading_etc() {
+ CHECK_FOCUS(__func__);
+
+ struct {
+ // want has 4 bytes, one for each possible q:
+ // - q&1 sets WUFFS_JSON__QUIRK_ALLOW_LEADING_ASCII_RECORD_SEPARATOR.
+ // - q&2 sets WUFFS_JSON__QUIRK_ALLOW_LEADING_UNICODE_BYTE_ORDER_MARK.
+ // An 'X', '+' or '-' means that decoding should succeed (and consume the
+ // entire input), succeed (without consuming the entire input) or fail.
+ const char* want;
+ const char* str;
+ } test_cases[] = {
+ {.want = "-X-X", .str = "\x1Etrue"},
+ {.want = "--XX", .str = "\xEF\xBB\xBFtrue"},
+ {.want = "---X", .str = "\x1E\xEF\xBB\xBFtrue"},
+ {.want = "---X", .str = "\xEF\xBB\xBF\x1Etrue"},
+ {.want = "----", .str = " \x1Etrue"},
+ {.want = "----", .str = "\x1E \xEF\xBB\xBFtrue"},
+ {.want = "----", .str = "\x1E\x1Etrue"},
+ {.want = "----", .str = "\xEF\xBB"},
+ {.want = "----", .str = "\xEF\xBB\xBF"},
+ {.want = "----", .str = "\xEF\xBB\xBF$"},
+ {.want = "----", .str = "\xEFtrue"},
+ };
+
+ int tc;
+ for (tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) {
+ int q;
+ for (q = 0; q < 4; q++) {
+ wuffs_json__decoder dec;
+ CHECK_STATUS("initialize", wuffs_json__decoder__initialize(
+ &dec, sizeof dec, WUFFS_VERSION,
+ WUFFS_INITIALIZE__DEFAULT_OPTIONS));
+ wuffs_json__decoder__set_quirk_enabled(
+ &dec, WUFFS_JSON__QUIRK_ALLOW_LEADING_ASCII_RECORD_SEPARATOR, q & 1);
+ wuffs_json__decoder__set_quirk_enabled(
+ &dec, WUFFS_JSON__QUIRK_ALLOW_LEADING_UNICODE_BYTE_ORDER_MARK, q & 2);
+
+ wuffs_base__token_buffer tok =
+ wuffs_base__make_token_buffer_writer(g_have_slice_token);
+ wuffs_base__io_buffer src = wuffs_base__make_io_buffer_reader(
+ wuffs_base__make_slice_u8((void*)(test_cases[tc].str),
+ strlen(test_cases[tc].str)),
+ true);
+ const char* have =
+ wuffs_json__decoder__decode_tokens(&dec, &tok, &src, g_work_slice_u8)
+ .repr;
+ const char* want =
+ (test_cases[tc].want[q] != '-') ? NULL : wuffs_json__error__bad_input;
+ if (have != want) {
+ RETURN_FAIL("tc=%d, q=%d: decode_tokens: have \"%s\", want \"%s\"", tc,
+ q, have, want);
+ }
+
+ size_t total_length = 0;
+ while (tok.meta.ri < tok.meta.wi) {
+ total_length += wuffs_base__token__length(&tok.data.ptr[tok.meta.ri++]);
+ }
+ if (total_length != src.meta.ri) {
+ RETURN_FAIL("tc=%d, q=%d: total_length: have %zu, want %zu", tc, q,
+ total_length, src.meta.ri);
+ }
+ if (test_cases[tc].want[q] == 'X') {
+ if (total_length != src.data.len) {
+ RETURN_FAIL("tc=%d, q=%d: total_length: have %zu, want %zu", tc, q,
+ total_length, src.data.len);
+ }
+ } else if (test_cases[tc].want[q] == '+') {
+ if (total_length >= src.data.len) {
+ RETURN_FAIL("tc=%d, q=%d: total_length: have %zu, want < %zu", tc, q,
+ total_length, src.data.len);
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+const char* //
+test_wuffs_json_decode_quirk_allow_trailing_etc() {
+ CHECK_FOCUS(__func__);
+
+ struct {
+ // want has 2 bytes, one for each possible q:
+ // - q&1 sets WUFFS_JSON__QUIRK_ALLOW_TRAILING_NEW_LINE.
+ // An 'X', '+' or '-' means that decoding should succeed (and consume the
+ // entire input), succeed (without consuming the entire input) or fail.
+ const char* want;
+ const char* str;
+ } test_cases[] = {
+ {.want = "++", .str = "0 \n "}, //
+ {.want = "++", .str = "0 \n\n"}, //
+ {.want = "++", .str = "0\n\n"}, //
+ {.want = "+-", .str = "0 true \n"}, //
+ {.want = "+-", .str = "007"}, //
+ {.want = "+-", .str = "007\n"}, //
+ {.want = "+-", .str = "0true "}, //
+ {.want = "+-", .str = "0true"}, //
+ {.want = "+X", .str = "0 "}, //
+ {.want = "+X", .str = "0 \n"}, //
+ {.want = "+X", .str = "0\n"}, //
+ {.want = "+X", .str = "0\t\r\n"}, //
+ {.want = "--", .str = "\n"}, //
+ {.want = "XX", .str = "0"}, //
+ };
+
+ int tc;
+ for (tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) {
+ int q;
+ for (q = 0; q < 2; q++) {
+ wuffs_json__decoder dec;
+ CHECK_STATUS("initialize", wuffs_json__decoder__initialize(
+ &dec, sizeof dec, WUFFS_VERSION,
+ WUFFS_INITIALIZE__DEFAULT_OPTIONS));
+ wuffs_json__decoder__set_quirk_enabled(
+ &dec, WUFFS_JSON__QUIRK_ALLOW_TRAILING_NEW_LINE, q & 1);
+
+ wuffs_base__token_buffer tok =
+ wuffs_base__make_token_buffer_writer(g_have_slice_token);
+ wuffs_base__io_buffer src = wuffs_base__make_io_buffer_reader(
+ wuffs_base__make_slice_u8((void*)(test_cases[tc].str),
+ strlen(test_cases[tc].str)),
+ true);
+ const char* have =
+ wuffs_json__decoder__decode_tokens(&dec, &tok, &src, g_work_slice_u8)
+ .repr;
+ const char* want =
+ (test_cases[tc].want[q] != '-') ? NULL : wuffs_json__error__bad_input;
+ if (have != want) {
+ RETURN_FAIL("tc=%d, q=%d: decode_tokens: have \"%s\", want \"%s\"", tc,
+ q, have, want);
+ }
+
+ size_t total_length = 0;
+ while (tok.meta.ri < tok.meta.wi) {
+ total_length += wuffs_base__token__length(&tok.data.ptr[tok.meta.ri++]);
+ }
+ if (total_length != src.meta.ri) {
+ RETURN_FAIL("tc=%d, q=%d: total_length: have %zu, want %zu", tc, q,
+ total_length, src.meta.ri);
+ }
+ if (test_cases[tc].want[q] == 'X') {
+ if (total_length != src.data.len) {
+ RETURN_FAIL("tc=%d, q=%d: total_length: have %zu, want %zu", tc, q,
+ total_length, src.data.len);
+ }
+ } else if (test_cases[tc].want[q] == '+') {
+ if (total_length >= src.data.len) {
+ RETURN_FAIL("tc=%d, q=%d: total_length: have %zu, want < %zu", tc, q,
+ total_length, src.data.len);
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+const char* //
+test_wuffs_json_decode_quirk_replace_invalid_unicode() {
+ CHECK_FOCUS(__func__);
+
+ // Decoding str should produce want, with invalid UTF-8 replaced by "?". A
+ // proper JSON decoder (with the quirk enabled) would replace with
+ // "\xEF\xBF\xBD", the UTF-8 encoding of U+FFFD, but using "?" leads to
+ // clearer, shorter test cases.
+ struct {
+ const char* want;
+ const char* str;
+ } test_cases[] = {
+ // Valid UTF-8.
+ {.want = "abc", .str = "\"abc\""},
+ {.want = "del\xCE\x94ta", .str = "\"del\\u0394ta\""},
+ {.want = "del\xCE\x94ta", .str = "\"del\xCE\x94ta\""},
+
+ // Invalid UTF-8: right byte lengths, wrong bytes.
+ {.want = "1byte?yz", .str = "\"1byte\xFFyz\""},
+ {.want = "2byte??yz", .str = "\"2byte\xCE\xFFyz\""},
+ {.want = "3byte???yz", .str = "\"3byte\xE2\x98\xFFyz\""},
+ {.want = "4byte????yz", .str = "\"4byte\xF0\x9F\x92\xFFyz\""},
+
+ // Invalid UTF-8: wrong byte lengths.
+ {.want = "?", .str = "\"\xCE\""},
+ {.want = "?g", .str = "\"\xCEg\""},
+ {.want = "?gh", .str = "\"\xCEgh\""},
+ {.want = "j?", .str = "\"j\xE2\""},
+ {.want = "j?l", .str = "\"j\xE2l\""},
+ {.want = "j?lm", .str = "\"j\xE2lm\""},
+ {.want = "?", .str = "\"\xF0\""},
+ {.want = "?r", .str = "\"\xF0r\""},
+ {.want = "?rs", .str = "\"\xF0rs\""},
+
+ // U+DC00 (as an unpaired surrogate) is either 1 or 3 '?'s depending on
+ // whether it's backslash-u or backslash-x.
+ {.want = "a?z", .str = "\"a\\uDC00z\""},
+ {.want = "a?zzzzzz", .str = "\"a\\uDC00zzzzzz\""},
+ {.want = "a???z", .str = "\"a\xED\xB0\x80z\""},
+ {.want = "a???zzzzzz", .str = "\"a\xED\xB0\x80zzzzzz\""},
+
+ // 1 or 2 unpaired surrogates each become '?'s, but for 3 surrogates
+ // where consecutive surrogates make a valid pair, there's only 1 '?'.
+ {.want = "a?z", .str = "\"a\\uD800z\""},
+ {.want = "a??z", .str = "\"a\\uD800\\uDBFFz\""},
+ {.want = "a?\xF4\x8F\xBF\xBFz", .str = "\"a\\uD800\\uDBFF\\uDFFFz\""},
+ {.want = "a\xF0\x90\x80\x80?z", .str = "\"a\\uD800\\uDC00\\uDFFFz\""},
+ };
+
+ int tc;
+ for (tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) {
+ wuffs_json__decoder dec;
+ CHECK_STATUS("initialize", wuffs_json__decoder__initialize(
+ &dec, sizeof dec, WUFFS_VERSION,
+ WUFFS_INITIALIZE__DEFAULT_OPTIONS));
+ wuffs_json__decoder__set_quirk_enabled(
+ &dec, WUFFS_JSON__QUIRK_REPLACE_INVALID_UNICODE, true);
+
+ wuffs_base__io_buffer have =
+ wuffs_base__make_io_buffer_writer(g_have_slice_u8);
+ wuffs_base__token_buffer tok =
+ wuffs_base__make_token_buffer_writer(g_have_slice_token);
+ wuffs_base__io_buffer src = wuffs_base__make_io_buffer_reader(
+ wuffs_base__make_slice_u8((void*)(test_cases[tc].str),
+ strlen(test_cases[tc].str)),
+ true);
+ CHECK_STATUS("decode_tokens", wuffs_json__decoder__decode_tokens(
+ &dec, &tok, &src, g_work_slice_u8));
+
+ uint64_t src_index = 0;
+ while (tok.meta.ri < tok.meta.wi) {
+ wuffs_base__token* t = &tok.data.ptr[tok.meta.ri++];
+ uint64_t vbc = wuffs_base__token__value_base_category(t);
+ uint64_t vbd = wuffs_base__token__value_base_detail(t);
+ uint64_t token_length = wuffs_base__token__length(t);
+
+ if (vbc == WUFFS_BASE__TOKEN__VBC__UNICODE_CODE_POINT) {
+ uint8_t u[WUFFS_BASE__UTF_8__BYTE_LENGTH__MAX_INCL];
+ size_t n = wuffs_base__utf_8__encode(
+ wuffs_base__make_slice_u8(&u[0],
+ WUFFS_BASE__UTF_8__BYTE_LENGTH__MAX_INCL),
+ vbd);
+ if (vbd == 0xFFFD) {
+ u[0] = '?';
+ n = 1;
+ }
+ if ((have.data.len - have.meta.wi) < n) {
+ RETURN_FAIL("tc=%d: token too long", tc);
+ }
+ memcpy(&have.data.ptr[have.meta.wi], &u[0], n);
+ have.meta.wi += n;
+
+ } else if (vbc == WUFFS_BASE__TOKEN__VBC__STRING) {
+ if (vbd & WUFFS_BASE__TOKEN__VBD__STRING__CONVERT_0_DST_1_SRC_DROP) {
+ // No-op.
+ } else if (vbd &
+ WUFFS_BASE__TOKEN__VBD__STRING__CONVERT_1_DST_1_SRC_COPY) {
+ if ((have.data.len - have.meta.wi) < token_length) {
+ RETURN_FAIL("tc=%d: token too long", tc);
+ }
+ memcpy(&have.data.ptr[have.meta.wi], &test_cases[tc].str[src_index],
+ token_length);
+ have.meta.wi += token_length;
+ } else {
+ RETURN_FAIL("tc=%d: unexpected string-token conversion", tc);
+ }
+
+ } else {
+ RETURN_FAIL("tc=%d: unexpected token", tc);
+ }
+
+ src_index += token_length;
+ }
+
+ if (src_index != src.meta.ri) {
+ RETURN_FAIL("tc=%d: src_index: have %zu, want %zu", tc, src_index,
+ src.meta.ri);
+ }
+
+ if (have.meta.wi >= have.data.len) {
+ RETURN_FAIL("tc=%d: too many have bytes", tc);
+ }
+ have.data.ptr[have.meta.wi] = '\x00';
+ size_t len = strlen(test_cases[tc].want);
+ if ((len != have.meta.wi) ||
+ (memcmp(have.data.ptr, test_cases[tc].want, len) != 0)) {
+ RETURN_FAIL("tc=%d: have \"%s\", want \"%s\"", tc, have.data.ptr,
+ test_cases[tc].want);
+ }
+ }
+
+ return NULL;
+}
+
+const char* //
test_wuffs_json_decode_unicode4_escapes() {
CHECK_FOCUS(__func__);
@@ -1139,16 +2152,13 @@
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
- wuffs_base__token_buffer tok = ((wuffs_base__token_buffer){
- .data = global_have_token_slice,
- });
- size_t n = strlen(test_cases[tc].str);
- wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = wuffs_base__make_slice_u8((void*)(test_cases[tc].str), n),
- .meta = wuffs_base__make_io_buffer_meta(n, 0, 0, true),
- });
-
- wuffs_json__decoder__decode_tokens(&dec, &tok, &src);
+ wuffs_base__token_buffer tok =
+ wuffs_base__make_token_buffer_writer(g_have_slice_token);
+ wuffs_base__io_buffer src = wuffs_base__make_io_buffer_reader(
+ wuffs_base__make_slice_u8((void*)(test_cases[tc].str),
+ strlen(test_cases[tc].str)),
+ true);
+ wuffs_json__decoder__decode_tokens(&dec, &tok, &src, g_work_slice_u8);
uint32_t have = fail;
uint64_t total_length = 0;
@@ -1231,21 +2241,17 @@
int closed;
for (closed = 0; closed < 2; closed++) {
- wuffs_base__token_buffer tok = ((wuffs_base__token_buffer){
- .data = global_have_token_slice,
- });
- wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = src_data,
- .meta =
- wuffs_base__make_io_buffer_meta(src_data.len, 0, 0, closed != 0),
- });
+ wuffs_base__token_buffer tok =
+ wuffs_base__make_token_buffer_writer(g_have_slice_token);
+ wuffs_base__io_buffer src =
+ wuffs_base__make_io_buffer_reader(src_data, closed != 0);
CHECK_STATUS("initialize",
wuffs_json__decoder__initialize(
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
wuffs_base__status have =
- wuffs_json__decoder__decode_tokens(&dec, &tok, &src);
+ wuffs_json__decoder__decode_tokens(&dec, &tok, &src, g_work_slice_u8);
const char* want =
(i > WUFFS_JSON__DECODER_NUMBER_LENGTH_MAX_INCL)
? wuffs_json__error__unsupported_number_length
@@ -1338,17 +2344,14 @@
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
- wuffs_base__token_buffer tok = ((wuffs_base__token_buffer){
- .data = global_have_token_slice,
- });
- size_t n = strlen(test_cases[tc].str);
- wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = wuffs_base__make_slice_u8((void*)(test_cases[tc].str), n),
- .meta = wuffs_base__make_io_buffer_meta(n, 0, 0, true),
- });
-
+ wuffs_base__token_buffer tok =
+ wuffs_base__make_token_buffer_writer(g_have_slice_token);
+ wuffs_base__io_buffer src = wuffs_base__make_io_buffer_reader(
+ wuffs_base__make_slice_u8((void*)(test_cases[tc].str),
+ strlen(test_cases[tc].str)),
+ true);
wuffs_base__status have_status =
- wuffs_json__decoder__decode_tokens(&dec, &tok, &src);
+ wuffs_json__decoder__decode_tokens(&dec, &tok, &src, g_work_slice_u8);
uint64_t total_length = 0;
size_t i;
@@ -1380,6 +2383,50 @@
#endif // WUFFS_MIMIC
+// ---------------- String Conversions Benches
+
+const char* //
+do_bench_strconv_parse_number_f64(const char* str, uint64_t iters_unscaled) {
+ wuffs_base__slice_u8 s = wuffs_base__make_slice_u8((void*)str, strlen(str));
+
+ bench_start();
+ uint64_t i;
+ uint64_t iters = iters_unscaled * g_flags.iterscale;
+ for (i = 0; i < iters; i++) {
+ CHECK_STATUS("", wuffs_base__parse_number_f64(s).status);
+ }
+ bench_finish(iters, 0);
+
+ return NULL;
+}
+
+const char* //
+bench_strconv_parse_number_f64_1_lsh53_add0() {
+ CHECK_FOCUS(__func__);
+ // 9007_199254_740992 is 0x20_0000_0000_0000, aka ((1<<53) + 0).
+ return do_bench_strconv_parse_number_f64("9007199254740992", 1000);
+}
+
+const char* //
+bench_strconv_parse_number_f64_1_lsh53_add1() {
+ CHECK_FOCUS(__func__);
+ // 9007_199254_740993 is 0x20_0000_0000_0001, aka ((1<<53) + 1).
+ return do_bench_strconv_parse_number_f64("9007199254740993", 1000);
+}
+
+const char* //
+bench_strconv_parse_number_f64_pi_long() {
+ CHECK_FOCUS(__func__);
+ return do_bench_strconv_parse_number_f64("3.141592653589793238462643383279",
+ 1000);
+}
+
+const char* //
+bench_strconv_parse_number_f64_pi_short() {
+ CHECK_FOCUS(__func__);
+ return do_bench_strconv_parse_number_f64("3.14159", 1000);
+}
+
// ---------------- JSON Benches
const char* //
@@ -1387,7 +2434,7 @@
CHECK_FOCUS(__func__);
return do_bench_token_decoder(
wuffs_json_decode, WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED,
- tcounter_src, &json_github_tags_gt, UINT64_MAX, UINT64_MAX, 10000);
+ tcounter_src, &g_json_github_tags_gt, UINT64_MAX, UINT64_MAX, 10000);
}
const char* //
@@ -1395,7 +2442,7 @@
CHECK_FOCUS(__func__);
return do_bench_token_decoder(
wuffs_json_decode, WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED,
- tcounter_src, &json_file_sizes_gt, UINT64_MAX, UINT64_MAX, 300);
+ tcounter_src, &g_json_file_sizes_gt, UINT64_MAX, UINT64_MAX, 300);
}
const char* //
@@ -1403,7 +2450,7 @@
CHECK_FOCUS(__func__);
return do_bench_token_decoder(
wuffs_json_decode, WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED,
- tcounter_src, &json_australian_abc_gt, UINT64_MAX, UINT64_MAX, 250);
+ tcounter_src, &g_json_australian_abc_gt, UINT64_MAX, UINT64_MAX, 250);
}
const char* //
@@ -1411,7 +2458,7 @@
CHECK_FOCUS(__func__);
return do_bench_token_decoder(
wuffs_json_decode, WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED,
- tcounter_src, &json_nobel_prizes_gt, UINT64_MAX, UINT64_MAX, 25);
+ tcounter_src, &g_json_nobel_prizes_gt, UINT64_MAX, UINT64_MAX, 25);
}
// ---------------- Mimic Benches
@@ -1424,25 +2471,37 @@
// ---------------- Manifest
-// The empty comments forces clang-format to place one element per line.
-proc tests[] = {
+proc g_tests[] = {
- // These strconv tests are really testing the Wuffs base library. They
- // aren't specific to the std/json code, but putting them here is as good
- // as any other place.
- test_strconv_hpd_rounded_integer, //
- test_strconv_hpd_shift, //
- test_strconv_parse_number_f64, //
- test_strconv_parse_number_i64, //
- test_strconv_parse_number_u64, //
- test_strconv_utf_8_next, //
+ // These core and strconv tests are really testing the Wuffs base library.
+ // They aren't specific to the std/json code, but putting them here is as
+ // good as any other place.
+ test_wuffs_core_count_leading_zeroes_u64,
+ test_wuffs_core_multiply_u64,
+ test_strconv_hexadecimal,
+ test_strconv_hpd_rounded_integer,
+ test_strconv_hpd_shift,
+ test_strconv_mpb_assign_from_hpd,
+ test_strconv_parse_number_f64,
+ test_strconv_parse_number_i64,
+ test_strconv_parse_number_u64,
+ test_strconv_utf_8_next,
- test_wuffs_json_decode_interface, //
- test_wuffs_json_decode_long_numbers, //
- test_wuffs_json_decode_prior_valid_utf_8, //
- test_wuffs_json_decode_src_io_buffer_length, //
- test_wuffs_json_decode_string, //
- test_wuffs_json_decode_unicode4_escapes, //
+ test_wuffs_json_decode_end_of_data,
+ test_wuffs_json_decode_interface,
+ test_wuffs_json_decode_long_numbers,
+ test_wuffs_json_decode_prior_valid_utf_8,
+ test_wuffs_json_decode_quirk_allow_backslash_etc,
+ test_wuffs_json_decode_quirk_allow_backslash_x,
+ test_wuffs_json_decode_quirk_allow_comment_etc,
+ test_wuffs_json_decode_quirk_allow_extra_comma,
+ test_wuffs_json_decode_quirk_allow_inf_nan_numbers,
+ test_wuffs_json_decode_quirk_allow_leading_etc,
+ test_wuffs_json_decode_quirk_allow_trailing_etc,
+ test_wuffs_json_decode_quirk_replace_invalid_unicode,
+ test_wuffs_json_decode_src_io_buffer_length,
+ test_wuffs_json_decode_string,
+ test_wuffs_json_decode_unicode4_escapes,
#ifdef WUFFS_MIMIC
@@ -1453,13 +2512,17 @@
NULL,
};
-// The empty comments forces clang-format to place one element per line.
-proc benches[] = {
+proc g_benches[] = {
- bench_wuffs_json_decode_1k, //
- bench_wuffs_json_decode_21k_formatted, //
- bench_wuffs_json_decode_26k_compact, //
- bench_wuffs_json_decode_217k_stringy, //
+ bench_strconv_parse_number_f64_1_lsh53_add0,
+ bench_strconv_parse_number_f64_1_lsh53_add1,
+ bench_strconv_parse_number_f64_pi_long,
+ bench_strconv_parse_number_f64_pi_short,
+
+ bench_wuffs_json_decode_1k,
+ bench_wuffs_json_decode_21k_formatted,
+ bench_wuffs_json_decode_26k_compact,
+ bench_wuffs_json_decode_217k_stringy,
#ifdef WUFFS_MIMIC
@@ -1472,6 +2535,6 @@
int //
main(int argc, char** argv) {
- proc_package_name = "std/json";
- return test_main(argc, argv, tests, benches);
+ g_proc_package_name = "std/json";
+ return test_main(argc, argv, g_tests, g_benches);
}
diff --git a/test/c/std/lzw.c b/test/c/std/lzw.c
index afad397..53df1b8 100644
--- a/test/c/std/lzw.c
+++ b/test/c/std/lzw.c
@@ -87,13 +87,13 @@
uint64_t wlimit,
uint64_t rlimit) {
wuffs_base__io_buffer have = ((wuffs_base__io_buffer){
- .data = global_have_slice,
+ .data = g_have_slice_u8,
});
wuffs_base__io_buffer want = ((wuffs_base__io_buffer){
- .data = global_want_slice,
+ .data = g_want_slice_u8,
});
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(read_file(&src, src_filename));
@@ -130,7 +130,7 @@
size_t old_ri = src.meta.ri;
wuffs_base__status status = wuffs_lzw__decoder__transform_io(
- &dec, &limited_have, &limited_src, global_work_slice);
+ &dec, &limited_have, &limited_src, g_work_slice_u8);
have.meta.wi += limited_have.meta.wi;
src.meta.ri += limited_src.meta.ri;
if (wuffs_base__status__is_ok(&status)) {
@@ -215,10 +215,10 @@
CHECK_FOCUS(__func__);
wuffs_base__io_buffer have = ((wuffs_base__io_buffer){
- .data = global_have_slice,
+ .data = g_have_slice_u8,
});
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
// Set up src to be 20 bytes long, starting with three 8-bit literal codes
@@ -242,7 +242,7 @@
wuffs_lzw__decoder__set_literal_width(&dec, 7);
wuffs_base__status status =
- wuffs_lzw__decoder__transform_io(&dec, &have, &src, global_work_slice);
+ wuffs_lzw__decoder__transform_io(&dec, &have, &src, g_work_slice_u8);
if (status.repr != wuffs_lzw__error__bad_code) {
RETURN_FAIL("transform_io: have \"%s\", want \"%s\"", status.repr,
wuffs_lzw__error__bad_code);
@@ -262,10 +262,10 @@
CHECK_FOCUS(__func__);
wuffs_base__io_buffer have = ((wuffs_base__io_buffer){
- .data = global_have_slice,
+ .data = g_have_slice_u8,
});
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
// Set up src to be 20 bytes long, starting with the 9-bit end code 0x101.
@@ -286,7 +286,7 @@
wuffs_lzw__decoder__set_literal_width(&dec, 8);
CHECK_STATUS("transform_io", wuffs_lzw__decoder__transform_io(
- &dec, &have, &src, global_work_slice));
+ &dec, &have, &src, g_work_slice_u8));
if (have.meta.wi != 0) {
RETURN_FAIL("have.meta.wi: have %d, want 0", (int)(have.meta.wi));
@@ -309,10 +309,10 @@
wuffs_lzw__decoder__set_literal_width(&dec, width);
wuffs_base__io_buffer have = ((wuffs_base__io_buffer){
- .data = global_have_slice,
+ .data = g_have_slice_u8,
});
CHECK_STATUS("transform_io", wuffs_lzw__decoder__transform_io(
- &dec, &have, &src, global_work_slice));
+ &dec, &have, &src, g_work_slice_u8));
return check_io_buffers_equal("", &have, &want);
}
@@ -333,14 +333,14 @@
// 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,
+ .data = g_src_slice_u8,
});
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,
+ .data = g_want_slice_u8,
});
want.meta.wi = 7;
want.data.ptr[0] = 0x00;
@@ -364,14 +364,14 @@
// 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,
+ .data = g_src_slice_u8,
});
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,
+ .data = g_want_slice_u8,
});
want.meta.wi = 4;
want.data.ptr[0] = 0x00;
@@ -387,10 +387,10 @@
const char* //
do_bench_wuffs_lzw_decode(const char* filename, uint64_t iters_unscaled) {
wuffs_base__io_buffer have = ((wuffs_base__io_buffer){
- .data = global_have_slice,
+ .data = g_have_slice_u8,
});
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(read_file(&src, filename));
@@ -406,7 +406,7 @@
bench_start();
uint64_t n_bytes = 0;
uint64_t i;
- uint64_t iters = iters_unscaled * flags.iterscale;
+ uint64_t iters = iters_unscaled * g_flags.iterscale;
for (i = 0; i < iters; i++) {
have.meta.wi = 0;
src.meta.ri = 1; // Skip the literal width.
@@ -416,7 +416,7 @@
&dec, sizeof dec, WUFFS_VERSION,
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
CHECK_STATUS("transform_io", wuffs_lzw__decoder__transform_io(
- &dec, &have, &src, global_work_slice));
+ &dec, &have, &src, g_work_slice_u8));
n_bytes += have.meta.wi;
}
bench_finish(iters, n_bytes);
@@ -437,34 +437,32 @@
// ---------------- Manifest
-// The empty comments forces clang-format to place one element per line.
-proc tests[] = {
+proc g_tests[] = {
- test_wuffs_lzw_decode_bricks_dither, //
- test_wuffs_lzw_decode_bricks_nodither, //
- test_wuffs_lzw_decode_interface, //
- test_wuffs_lzw_decode_many_big_reads, //
- test_wuffs_lzw_decode_many_small_writes_reads, //
- test_wuffs_lzw_decode_output_bad, //
- test_wuffs_lzw_decode_output_empty, //
- test_wuffs_lzw_decode_pi, //
- test_wuffs_lzw_decode_width_0, //
- test_wuffs_lzw_decode_width_1, //
+ test_wuffs_lzw_decode_bricks_dither,
+ test_wuffs_lzw_decode_bricks_nodither,
+ test_wuffs_lzw_decode_interface,
+ test_wuffs_lzw_decode_many_big_reads,
+ test_wuffs_lzw_decode_many_small_writes_reads,
+ test_wuffs_lzw_decode_output_bad,
+ test_wuffs_lzw_decode_output_empty,
+ test_wuffs_lzw_decode_pi,
+ test_wuffs_lzw_decode_width_0,
+ test_wuffs_lzw_decode_width_1,
NULL,
};
-// The empty comments forces clang-format to place one element per line.
-proc benches[] = {
+proc g_benches[] = {
- bench_wuffs_lzw_decode_20k, //
- bench_wuffs_lzw_decode_100k, //
+ bench_wuffs_lzw_decode_20k,
+ bench_wuffs_lzw_decode_100k,
NULL,
};
int //
main(int argc, char** argv) {
- proc_package_name = "std/lzw";
- return test_main(argc, argv, tests, benches);
+ g_proc_package_name = "std/lzw";
+ return test_main(argc, argv, g_tests, g_benches);
}
diff --git a/test/c/std/wbmp.c b/test/c/std/wbmp.c
index f7b718e..1678943 100644
--- a/test/c/std/wbmp.c
+++ b/test/c/std/wbmp.c
@@ -93,7 +93,7 @@
wuffs_base__frame_config fc = ((wuffs_base__frame_config){});
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(read_file(&src, "test/data/hat.wbmp"));
CHECK_STATUS("decode_frame_config #0",
@@ -123,7 +123,7 @@
wuffs_base__image_config ic = ((wuffs_base__image_config){});
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(read_file(&src, "test/data/bricks-nodither.wbmp"));
CHECK_STATUS("decode_image_config",
@@ -166,12 +166,11 @@
// ---------------- Manifest
-// The empty comments forces clang-format to place one element per line.
-proc tests[] = {
+proc g_tests[] = {
- test_wuffs_wbmp_decode_frame_config, //
- test_wuffs_wbmp_decode_image_config, //
- test_wuffs_wbmp_decode_interface, //
+ test_wuffs_wbmp_decode_frame_config,
+ test_wuffs_wbmp_decode_image_config,
+ test_wuffs_wbmp_decode_interface,
#ifdef WUFFS_MIMIC
@@ -182,8 +181,7 @@
NULL,
};
-// The empty comments forces clang-format to place one element per line.
-proc benches[] = {
+proc g_benches[] = {
// No WBMP benches.
@@ -198,6 +196,6 @@
int //
main(int argc, char** argv) {
- proc_package_name = "std/wbmp";
- return test_main(argc, argv, tests, benches);
+ g_proc_package_name = "std/wbmp";
+ return test_main(argc, argv, g_tests, g_benches);
}
diff --git a/test/c/std/zlib.c b/test/c/std/zlib.c
index 1721f4d..19ed404 100644
--- a/test/c/std/zlib.c
+++ b/test/c/std/zlib.c
@@ -71,26 +71,26 @@
// ---------------- Golden Tests
-golden_test zlib_midsummer_gt = {
- .want_filename = "test/data/midsummer.txt", //
- .src_filename = "test/data/midsummer.txt.zlib", //
+golden_test g_zlib_midsummer_gt = {
+ .want_filename = "test/data/midsummer.txt",
+ .src_filename = "test/data/midsummer.txt.zlib",
};
-golden_test zlib_pi_gt = {
- .want_filename = "test/data/pi.txt", //
- .src_filename = "test/data/pi.txt.zlib", //
+golden_test g_zlib_pi_gt = {
+ .want_filename = "test/data/pi.txt",
+ .src_filename = "test/data/pi.txt.zlib",
};
// This dictionary-using zlib-encoded data comes from
// https://play.golang.org/p/Jh9Wyp6PLID, also mentioned in the RAC spec.
-const char* zlib_sheep_src_ptr =
+const char* g_zlib_sheep_src_ptr =
"\x78\xf9\x0b\xe0\x02\x6e\x0a\x29\xcf\x87\x31\x01\x01\x00\x00\xff\xff\x18"
"\x0c\x03\xa8";
-const size_t zlib_sheep_src_len = 21;
-const char* zlib_sheep_dict_ptr = " sheep.\n";
-const size_t zlib_sheep_dict_len = 8;
-const char* zlib_sheep_want_ptr = "Two sheep.\n";
-const size_t zlib_sheep_want_len = 11;
+const size_t g_zlib_sheep_src_len = 21;
+const char* g_zlib_sheep_dict_ptr = " sheep.\n";
+const size_t g_zlib_sheep_dict_len = 8;
+const char* g_zlib_sheep_want_ptr = "Two sheep.\n";
+const size_t g_zlib_sheep_want_len = 11;
// ---------------- Zlib Tests
@@ -123,7 +123,7 @@
wuffs_base__io_buffer limited_src = make_limited_reader(*src, rlimit);
wuffs_base__status status = wuffs_zlib__decoder__transform_io(
- &dec, &limited_dst, &limited_src, global_work_slice);
+ &dec, &limited_dst, &limited_src, g_work_slice_u8);
dst->meta.wi += limited_dst.meta.wi;
src->meta.ri += limited_src.meta.ri;
@@ -141,13 +141,13 @@
const char* //
do_test_wuffs_zlib_checksum(bool ignore_checksum, uint32_t bad_checksum) {
wuffs_base__io_buffer have = ((wuffs_base__io_buffer){
- .data = global_have_slice,
+ .data = g_have_slice_u8,
});
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
- CHECK_STRING(read_file(&src, zlib_midsummer_gt.src_filename));
+ CHECK_STRING(read_file(&src, g_zlib_midsummer_gt.src_filename));
// Flip a bit in the zlib checksum, which is in the last 4 bytes of the file.
if (src.meta.wi < 4) {
RETURN_FAIL("source file was too short");
@@ -191,7 +191,7 @@
wuffs_base__io_buffer limited_src = make_limited_reader(src, rlimit);
wuffs_base__status have_z = wuffs_zlib__decoder__transform_io(
- &dec, &have, &limited_src, global_work_slice);
+ &dec, &have, &limited_src, g_work_slice_u8);
src.meta.ri += limited_src.meta.ri;
if (have_z.repr != want_z) {
RETURN_FAIL("end_limit=%d: have \"%s\", want \"%s\"", end_limit,
@@ -229,14 +229,14 @@
const char* //
test_wuffs_zlib_decode_midsummer() {
CHECK_FOCUS(__func__);
- return do_test_io_buffers(wuffs_zlib_decode, &zlib_midsummer_gt, UINT64_MAX,
+ return do_test_io_buffers(wuffs_zlib_decode, &g_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, UINT64_MAX,
+ return do_test_io_buffers(wuffs_zlib_decode, &g_zlib_pi_gt, UINT64_MAX,
UINT64_MAX);
}
@@ -244,10 +244,10 @@
test_wuffs_zlib_decode_sheep() {
CHECK_FOCUS(__func__);
wuffs_base__io_buffer have = ((wuffs_base__io_buffer){
- .data = global_have_slice,
+ .data = g_have_slice_u8,
});
wuffs_base__io_buffer src =
- make_io_buffer_from_string(zlib_sheep_src_ptr, zlib_sheep_src_len);
+ make_io_buffer_from_string(g_zlib_sheep_src_ptr, g_zlib_sheep_src_len);
wuffs_zlib__decoder dec;
CHECK_STATUS("initialize", wuffs_zlib__decoder__initialize(
@@ -257,7 +257,7 @@
int i;
for (i = 0; i < 3; i++) {
wuffs_base__status status =
- wuffs_zlib__decoder__transform_io(&dec, &have, &src, global_work_slice);
+ wuffs_zlib__decoder__transform_io(&dec, &have, &src, g_work_slice_u8);
if (status.repr != wuffs_zlib__note__dictionary_required) {
RETURN_FAIL("transform_io (before dict): have \"%s\", want \"%s\"",
@@ -274,16 +274,16 @@
wuffs_zlib__decoder__add_dictionary(
&dec, ((wuffs_base__slice_u8){
- .ptr = ((uint8_t*)(zlib_sheep_dict_ptr)),
- .len = zlib_sheep_dict_len,
+ .ptr = ((uint8_t*)(g_zlib_sheep_dict_ptr)),
+ .len = g_zlib_sheep_dict_len,
}));
CHECK_STATUS(
"transform_io (after dict)",
- wuffs_zlib__decoder__transform_io(&dec, &have, &src, global_work_slice));
+ wuffs_zlib__decoder__transform_io(&dec, &have, &src, g_work_slice_u8));
wuffs_base__io_buffer want =
- make_io_buffer_from_string(zlib_sheep_want_ptr, zlib_sheep_want_len);
+ make_io_buffer_from_string(g_zlib_sheep_want_ptr, g_zlib_sheep_want_len);
return check_io_buffers_equal("", &have, &want);
}
@@ -294,14 +294,14 @@
const char* //
test_mimic_zlib_decode_midsummer() {
CHECK_FOCUS(__func__);
- return do_test_io_buffers(mimic_zlib_decode, &zlib_midsummer_gt, UINT64_MAX,
+ return do_test_io_buffers(mimic_zlib_decode, &g_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, UINT64_MAX,
+ return do_test_io_buffers(mimic_zlib_decode, &g_zlib_pi_gt, UINT64_MAX,
UINT64_MAX);
}
@@ -309,20 +309,20 @@
test_mimic_zlib_decode_sheep() {
CHECK_FOCUS(__func__);
wuffs_base__io_buffer have = ((wuffs_base__io_buffer){
- .data = global_have_slice,
+ .data = g_have_slice_u8,
});
wuffs_base__io_buffer src =
- make_io_buffer_from_string(zlib_sheep_src_ptr, zlib_sheep_src_len);
+ make_io_buffer_from_string(g_zlib_sheep_src_ptr, g_zlib_sheep_src_len);
wuffs_base__slice_u8 dict = ((wuffs_base__slice_u8){
- .ptr = ((uint8_t*)(zlib_sheep_dict_ptr)),
- .len = zlib_sheep_dict_len,
+ .ptr = ((uint8_t*)(g_zlib_sheep_dict_ptr)),
+ .len = g_zlib_sheep_dict_len,
});
const char* status = mimic_zlib_decode_with_dictionary(&have, &src, dict);
if (status) {
return status;
}
wuffs_base__io_buffer want =
- make_io_buffer_from_string(zlib_sheep_want_ptr, zlib_sheep_want_len);
+ make_io_buffer_from_string(g_zlib_sheep_want_ptr, g_zlib_sheep_want_len);
return check_io_buffers_equal("", &have, &want);
}
@@ -335,7 +335,7 @@
CHECK_FOCUS(__func__);
return do_bench_io_buffers(
wuffs_zlib_decode, WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED,
- tcounter_dst, &zlib_midsummer_gt, UINT64_MAX, UINT64_MAX, 300);
+ tcounter_dst, &g_zlib_midsummer_gt, UINT64_MAX, UINT64_MAX, 300);
}
const char* //
@@ -343,7 +343,7 @@
CHECK_FOCUS(__func__);
return do_bench_io_buffers(
wuffs_zlib_decode, WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED,
- tcounter_dst, &zlib_pi_gt, UINT64_MAX, UINT64_MAX, 30);
+ tcounter_dst, &g_zlib_pi_gt, UINT64_MAX, UINT64_MAX, 30);
}
// ---------------- Mimic Benches
@@ -354,13 +354,13 @@
bench_mimic_zlib_decode_10k() {
CHECK_FOCUS(__func__);
return do_bench_io_buffers(mimic_zlib_decode, 0, tcounter_dst,
- &zlib_midsummer_gt, UINT64_MAX, UINT64_MAX, 300);
+ &g_zlib_midsummer_gt, UINT64_MAX, UINT64_MAX, 300);
}
const char* //
bench_mimic_zlib_decode_100k() {
CHECK_FOCUS(__func__);
- return do_bench_io_buffers(mimic_zlib_decode, 0, tcounter_dst, &zlib_pi_gt,
+ return do_bench_io_buffers(mimic_zlib_decode, 0, tcounter_dst, &g_zlib_pi_gt,
UINT64_MAX, UINT64_MAX, 30);
}
@@ -368,39 +368,37 @@
// ---------------- Manifest
-// The empty comments forces clang-format to place one element per line.
-proc tests[] = {
+proc g_tests[] = {
- test_wuffs_zlib_checksum_ignore, //
- test_wuffs_zlib_checksum_verify_bad0, //
- test_wuffs_zlib_checksum_verify_bad3, //
- test_wuffs_zlib_checksum_verify_good, //
- test_wuffs_zlib_decode_interface, //
- test_wuffs_zlib_decode_midsummer, //
- test_wuffs_zlib_decode_pi, //
- test_wuffs_zlib_decode_sheep, //
+ test_wuffs_zlib_checksum_ignore,
+ test_wuffs_zlib_checksum_verify_bad0,
+ test_wuffs_zlib_checksum_verify_bad3,
+ test_wuffs_zlib_checksum_verify_good,
+ test_wuffs_zlib_decode_interface,
+ test_wuffs_zlib_decode_midsummer,
+ test_wuffs_zlib_decode_pi,
+ test_wuffs_zlib_decode_sheep,
#ifdef WUFFS_MIMIC
- test_mimic_zlib_decode_midsummer, //
- test_mimic_zlib_decode_pi, //
- test_mimic_zlib_decode_sheep, //
+ test_mimic_zlib_decode_midsummer,
+ test_mimic_zlib_decode_pi,
+ test_mimic_zlib_decode_sheep,
#endif // WUFFS_MIMIC
NULL,
};
-// The empty comments forces clang-format to place one element per line.
-proc benches[] = {
+proc g_benches[] = {
- bench_wuffs_zlib_decode_10k, //
- bench_wuffs_zlib_decode_100k, //
+ bench_wuffs_zlib_decode_10k,
+ bench_wuffs_zlib_decode_100k,
#ifdef WUFFS_MIMIC
- bench_mimic_zlib_decode_10k, //
- bench_mimic_zlib_decode_100k, //
+ bench_mimic_zlib_decode_10k,
+ bench_mimic_zlib_decode_100k,
#endif // WUFFS_MIMIC
@@ -409,6 +407,6 @@
int //
main(int argc, char** argv) {
- proc_package_name = "std/zlib";
- return test_main(argc, argv, tests, benches);
+ g_proc_package_name = "std/zlib";
+ return test_main(argc, argv, g_tests, g_benches);
}
diff --git a/test/c/testlib/testlib.c b/test/c/testlib/testlib.c
index 7a4ac1a..a815cfc 100644
--- a/test/c/testlib/testlib.c
+++ b/test/c/testlib/testlib.c
@@ -26,67 +26,68 @@
#define WUFFS_TESTLIB_ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
-uint8_t global_have_array[IO_BUFFER_ARRAY_SIZE];
-uint8_t global_want_array[IO_BUFFER_ARRAY_SIZE];
-uint8_t global_work_array[IO_BUFFER_ARRAY_SIZE];
-uint8_t global_src_array[IO_BUFFER_ARRAY_SIZE];
+uint8_t g_have_array_u8[IO_BUFFER_ARRAY_SIZE];
+uint8_t g_want_array_u8[IO_BUFFER_ARRAY_SIZE];
+uint8_t g_work_array_u8[IO_BUFFER_ARRAY_SIZE];
+uint8_t g_src_array_u8[IO_BUFFER_ARRAY_SIZE];
-uint8_t global_pixel_array[PIXEL_BUFFER_ARRAY_SIZE];
+uint8_t g_pixel_array_u8[PIXEL_BUFFER_ARRAY_SIZE];
-wuffs_base__token global_have_token_array[TOKEN_BUFFER_ARRAY_SIZE];
-wuffs_base__token global_want_token_array[TOKEN_BUFFER_ARRAY_SIZE];
+wuffs_base__token g_have_array_token[TOKEN_BUFFER_ARRAY_SIZE];
+wuffs_base__token g_want_array_token[TOKEN_BUFFER_ARRAY_SIZE];
-wuffs_base__slice_u8 global_have_slice;
-wuffs_base__slice_u8 global_want_slice;
-wuffs_base__slice_u8 global_work_slice;
-wuffs_base__slice_u8 global_src_slice;
+wuffs_base__slice_u8 g_have_slice_u8;
+wuffs_base__slice_u8 g_want_slice_u8;
+wuffs_base__slice_u8 g_work_slice_u8;
+wuffs_base__slice_u8 g_src_slice_u8;
-wuffs_base__slice_u8 global_pixel_slice;
+wuffs_base__slice_u8 g_pixel_slice_u8;
-wuffs_base__slice_token global_have_token_slice;
-wuffs_base__slice_token global_want_token_slice;
+wuffs_base__slice_token g_have_slice_token;
+wuffs_base__slice_token g_want_slice_token;
-void wuffs_testlib__initialize_global_xxx_slices() {
- global_have_slice = ((wuffs_base__slice_u8){
- .ptr = global_have_array,
+void //
+wuffs_testlib__initialize_global_xxx_slices() {
+ g_have_slice_u8 = ((wuffs_base__slice_u8){
+ .ptr = g_have_array_u8,
.len = IO_BUFFER_ARRAY_SIZE,
});
- global_want_slice = ((wuffs_base__slice_u8){
- .ptr = global_want_array,
+ g_want_slice_u8 = ((wuffs_base__slice_u8){
+ .ptr = g_want_array_u8,
.len = IO_BUFFER_ARRAY_SIZE,
});
- global_work_slice = ((wuffs_base__slice_u8){
- .ptr = global_work_array,
+ g_work_slice_u8 = ((wuffs_base__slice_u8){
+ .ptr = g_work_array_u8,
.len = IO_BUFFER_ARRAY_SIZE,
});
- global_src_slice = ((wuffs_base__slice_u8){
- .ptr = global_src_array,
+ g_src_slice_u8 = ((wuffs_base__slice_u8){
+ .ptr = g_src_array_u8,
.len = IO_BUFFER_ARRAY_SIZE,
});
- global_pixel_slice = ((wuffs_base__slice_u8){
- .ptr = global_pixel_array,
+ g_pixel_slice_u8 = ((wuffs_base__slice_u8){
+ .ptr = g_pixel_array_u8,
.len = PIXEL_BUFFER_ARRAY_SIZE,
});
- global_have_token_slice = ((wuffs_base__slice_token){
- .ptr = global_have_token_array,
+ g_have_slice_token = ((wuffs_base__slice_token){
+ .ptr = g_have_array_token,
.len = TOKEN_BUFFER_ARRAY_SIZE,
});
- global_want_token_slice = ((wuffs_base__slice_token){
- .ptr = global_want_token_array,
+ g_want_slice_token = ((wuffs_base__slice_token){
+ .ptr = g_want_array_token,
.len = TOKEN_BUFFER_ARRAY_SIZE,
});
}
-char fail_msg[65536] = {0};
+char g_fail_msg[65536] = {0};
-#define RETURN_FAIL(...) \
- return (snprintf(fail_msg, sizeof(fail_msg), ##__VA_ARGS__) >= 0) \
- ? fail_msg \
+#define RETURN_FAIL(...) \
+ return (snprintf(g_fail_msg, sizeof(g_fail_msg), ##__VA_ARGS__) >= 0) \
+ ? g_fail_msg \
: "unknown failure (snprintf-related)"
#define INCR_FAIL(msg, ...) \
- msg += snprintf(msg, sizeof(fail_msg) - (msg - fail_msg), ##__VA_ARGS__)
+ msg += snprintf(msg, sizeof(g_fail_msg) - (msg - g_fail_msg), ##__VA_ARGS__)
#define CHECK_STATUS(prefix, status) \
do { \
@@ -104,7 +105,7 @@
} \
} while (0)
-int tests_run = 0;
+int g_tests_run = 0;
struct {
int remaining_argc;
@@ -114,12 +115,12 @@
const char* focus;
uint64_t iterscale;
int reps;
-} flags = {0};
+} g_flags = {0};
const char* //
parse_flags(int argc, char** argv) {
- flags.iterscale = 100;
- flags.reps = 5;
+ g_flags.iterscale = 100;
+ g_flags.reps = 5;
int c = (argc > 0) ? 1 : 0; // Skip argv[0], the program name.
for (; c < argc; c++) {
@@ -142,12 +143,12 @@
}
if (!strcmp(arg, "bench")) {
- flags.bench = true;
+ g_flags.bench = true;
continue;
}
if (!strncmp(arg, "focus=", 6)) {
- flags.focus = arg + 6;
+ g_flags.focus = arg + 6;
continue;
}
@@ -164,7 +165,7 @@
if ((n < 0) || (1000000 < n)) {
return "out-of-range -iterscale=N value";
}
- flags.iterscale = n;
+ g_flags.iterscale = n;
continue;
}
@@ -181,36 +182,36 @@
if ((n < 0) || (1000000 < n)) {
return "out-of-range -reps=N value";
}
- flags.reps = n;
+ g_flags.reps = n;
continue;
}
return "unrecognized flag argument";
}
- flags.remaining_argc = argc - c;
- flags.remaining_argv = argv + c;
+ g_flags.remaining_argc = argc - c;
+ g_flags.remaining_argv = argv + c;
return NULL;
}
-const char* proc_package_name = "unknown_package_name";
-const char* proc_func_name = "unknown_func_name";
-bool in_focus = false;
+const char* g_proc_package_name = "unknown_package_name";
+const char* g_proc_func_name = "unknown_func_name";
+bool g_in_focus = false;
-#define CHECK_FOCUS(func_name) \
- proc_func_name = func_name; \
- in_focus = check_focus(); \
- if (!in_focus) { \
- return NULL; \
+#define CHECK_FOCUS(func_name) \
+ g_proc_func_name = func_name; \
+ g_in_focus = check_focus(); \
+ if (!g_in_focus) { \
+ return NULL; \
}
bool //
check_focus() {
- const char* p = flags.focus;
+ const char* p = g_flags.focus;
if (!p || !*p) {
return true;
}
- size_t n = strlen(proc_func_name);
+ size_t n = strlen(g_proc_func_name);
// On each iteration of the loop, set p and q so that p (inclusive) and q
// (exclusive) bracket the interesting fragment of the comma-separated
@@ -246,18 +247,18 @@
p += 9;
}
- // See if proc_func_name (with or without a "test_" or "bench_" prefix)
+ // See if g_proc_func_name (with or without a "test_" or "bench_" prefix)
// starts with the [p, q) string.
- if ((n >= q - p) && !strncmp(proc_func_name, p, q - p)) {
+ if ((n >= q - p) && !strncmp(g_proc_func_name, p, q - p)) {
return true;
}
const char* unprefixed_proc_func_name = NULL;
size_t unprefixed_n = 0;
- if ((n >= q - p) && !strncmp(proc_func_name, "test_", 5)) {
- unprefixed_proc_func_name = proc_func_name + 5;
+ if ((n >= q - p) && !strncmp(g_proc_func_name, "test_", 5)) {
+ unprefixed_proc_func_name = g_proc_func_name + 5;
unprefixed_n = n - 5;
- } else if ((n >= q - p) && !strncmp(proc_func_name, "bench_", 6)) {
- unprefixed_proc_func_name = proc_func_name + 6;
+ } else if ((n >= q - p) && !strncmp(g_proc_func_name, "bench_", 6)) {
+ unprefixed_proc_func_name = g_proc_func_name + 6;
unprefixed_n = n - 6;
}
if (unprefixed_proc_func_name && (unprefixed_n >= q - p) &&
@@ -280,17 +281,17 @@
// The order matters here. Clang also defines "__GNUC__".
#if defined(__clang__)
-const char* cc = "clang" WUFFS_TESTLIB_QUOTE(__clang_major__);
-const char* cc_version = __clang_version__;
+const char* g_cc = "clang" WUFFS_TESTLIB_QUOTE(__clang_major__);
+const char* g_cc_version = __clang_version__;
#elif defined(__GNUC__)
-const char* cc = "gcc" WUFFS_TESTLIB_QUOTE(__GNUC__);
-const char* cc_version = __VERSION__;
+const char* g_cc = "gcc" WUFFS_TESTLIB_QUOTE(__GNUC__);
+const char* g_cc_version = __VERSION__;
#elif defined(_MSC_VER)
-const char* cc = "cl";
-const char* cc_version = "???";
+const char* g_cc = "cl";
+const char* g_cc_version = "???";
#else
-const char* cc = "cc";
-const char* cc_version = "???";
+const char* g_cc = "cc";
+const char* g_cc_version = "???";
#endif
typedef struct {
@@ -300,12 +301,12 @@
size_t src_offset1;
} golden_test;
-bool bench_warm_up;
-struct timeval bench_start_tv;
+bool g_bench_warm_up;
+struct timeval g_bench_start_tv;
void //
bench_start() {
- gettimeofday(&bench_start_tv, NULL);
+ gettimeofday(&g_bench_start_tv, NULL);
}
void //
@@ -313,28 +314,28 @@
struct timeval bench_finish_tv;
gettimeofday(&bench_finish_tv, NULL);
int64_t micros =
- (int64_t)(bench_finish_tv.tv_sec - bench_start_tv.tv_sec) * 1000000 +
- (int64_t)(bench_finish_tv.tv_usec - bench_start_tv.tv_usec);
+ (int64_t)(bench_finish_tv.tv_sec - g_bench_start_tv.tv_sec) * 1000000 +
+ (int64_t)(bench_finish_tv.tv_usec - g_bench_start_tv.tv_usec);
uint64_t nanos = 1;
if (micros > 0) {
nanos = (uint64_t)(micros)*1000;
}
uint64_t kb_per_s = n_bytes * 1000000 / nanos;
- const char* name = proc_func_name;
+ const char* name = g_proc_func_name;
if ((strlen(name) >= 6) && !strncmp(name, "bench_", 6)) {
name += 6;
}
- if (bench_warm_up) {
+ if (g_bench_warm_up) {
printf("# (warm up) %s/%s\t%8" PRIu64 ".%06" PRIu64 " seconds\n", //
- name, cc, nanos / 1000000000, (nanos % 1000000000) / 1000);
+ name, g_cc, nanos / 1000000000, (nanos % 1000000000) / 1000);
} else if (!n_bytes) {
printf("Benchmark%s/%s\t%8" PRIu64 "\t%8" PRIu64 " ns/op\n", //
- name, cc, iters, nanos / iters);
+ name, g_cc, iters, nanos / iters);
} else {
printf("Benchmark%s/%s\t%8" PRIu64 "\t%8" PRIu64
- " ns/op\t%8d.%03d MB/s\n", //
- name, cc, iters, nanos / iters, //
+ " ns/op\t%8d.%03d MB/s\n", //
+ name, g_cc, iters, nanos / iters, //
(int)(kb_per_s / 1000), (int)(kb_per_s % 1000));
}
// Flush stdout so that "wuffs bench | tee etc" still prints its numbers as
@@ -384,17 +385,18 @@
fprintf(stderr, "%s\n", status);
return 1;
}
- if (flags.remaining_argc > 0) {
+ if (g_flags.remaining_argc > 0) {
fprintf(stderr, "unexpected (non-flag) argument\n");
return 1;
}
int reps = 1;
proc* procs = tests;
- if (flags.bench) {
- reps = flags.reps + 1; // +1 for the warm up run.
+ if (g_flags.bench) {
+ reps = g_flags.reps + 1; // +1 for the warm up run.
procs = benches;
- printf("# %s\n# %s version %s\n#\n", proc_package_name, cc, cc_version);
+ printf("# %s\n# %s version %s\n#\n", g_proc_package_name, g_cc,
+ g_cc_version);
printf(
"# The output format, including the \"Benchmark\" prefixes, is "
"compatible with the\n"
@@ -405,33 +407,34 @@
int i;
for (i = 0; i < reps; i++) {
- bench_warm_up = i == 0;
+ g_bench_warm_up = i == 0;
proc* p;
for (p = procs; *p; p++) {
- proc_func_name = "unknown_func_name";
- fail_msg[0] = 0;
- in_focus = false;
+ g_proc_func_name = "unknown_func_name";
+ g_fail_msg[0] = 0;
+ g_in_focus = false;
const char* status = (*p)();
- if (!in_focus) {
+ if (!g_in_focus) {
continue;
}
if (status) {
- printf("%-16s%-8sFAIL %s: %s\n", proc_package_name, cc, proc_func_name,
- status);
+ printf("%-16s%-8sFAIL %s: %s\n", g_proc_package_name, g_cc,
+ g_proc_func_name, status);
return 1;
}
if (i == 0) {
- tests_run++;
+ g_tests_run++;
}
}
if (i != 0) {
continue;
}
- if (flags.bench) {
+ if (g_flags.bench) {
printf("# %d benchmarks, 1+%d reps per benchmark, iterscale=%d\n",
- tests_run, flags.reps, (int)(flags.iterscale));
+ g_tests_run, g_flags.reps, (int)(g_flags.iterscale));
} else {
- printf("%-16s%-8sPASS (%d tests)\n", proc_package_name, cc, tests_run);
+ printf("%-16s%-8sPASS (%d tests)\n", g_proc_package_name, g_cc,
+ g_tests_run);
}
}
return 0;
@@ -693,7 +696,7 @@
if (!have || !want) {
RETURN_FAIL("%sio_buffers_equal: NULL argument", prefix);
}
- char* msg = fail_msg;
+ char* msg = g_fail_msg;
size_t i;
size_t n = have->meta.wi < want->meta.wi ? have->meta.wi : want->meta.wi;
for (i = 0; i < n; i++) {
@@ -713,7 +716,7 @@
msg = hex_dump(msg, have, i);
INCR_FAIL(msg, "excerpts of have (above) versus want (below):\n");
msg = hex_dump(msg, want, i);
- return fail_msg;
+ return g_fail_msg;
}
// throughput_counter is whether to count dst or src bytes, or neither, when
@@ -748,13 +751,13 @@
}
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
wuffs_base__io_buffer have = ((wuffs_base__io_buffer){
- .data = global_have_slice,
+ .data = g_have_slice_u8,
});
wuffs_base__io_buffer want = ((wuffs_base__io_buffer){
- .data = global_want_slice,
+ .data = g_want_slice_u8,
});
if (!gt->src_filename) {
@@ -837,10 +840,10 @@
}
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
wuffs_base__token_buffer have = ((wuffs_base__token_buffer){
- .data = global_have_token_slice,
+ .data = g_have_slice_token,
});
if (!gt->src_filename) {
@@ -905,7 +908,7 @@
uint64_t rlimit,
uint64_t iters_unscaled) {
return proc_io_buffers(codec_func, wuffs_initialize_flags, tcounter, gt,
- wlimit, rlimit, iters_unscaled * flags.iterscale,
+ wlimit, rlimit, iters_unscaled * g_flags.iterscale,
true);
}
@@ -922,7 +925,7 @@
uint64_t rlimit,
uint64_t iters_unscaled) {
return proc_token_decoder(codec_func, wuffs_initialize_flags, tcounter, gt,
- wlimit, rlimit, iters_unscaled * flags.iterscale,
+ wlimit, rlimit, iters_unscaled * g_flags.iterscale,
true);
}
@@ -949,7 +952,7 @@
size_t src_wi,
uint32_t want) {
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(read_file_fragment(&src, src_filename, src_ri, src_wi));
uint32_t have = wuffs_base__hasher_u32__update_u32(
@@ -970,7 +973,7 @@
size_t src_wi,
uint64_t want_num_frames) {
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(read_file_fragment(&src, src_filename, src_ri, src_wi));
@@ -1008,7 +1011,7 @@
wuffs_base__image_config ic = ((wuffs_base__image_config){});
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(read_file_fragment(&src, src_filename, src_ri, src_wi));
CHECK_STATUS("decode_image_config",
@@ -1030,10 +1033,10 @@
wuffs_base__pixel_buffer pb = ((wuffs_base__pixel_buffer){});
CHECK_STATUS("set_from_slice", wuffs_base__pixel_buffer__set_from_slice(
- &pb, &ic.pixcfg, global_pixel_slice));
+ &pb, &ic.pixcfg, g_pixel_slice_u8));
CHECK_STATUS("decode_frame", wuffs_base__image_decoder__decode_frame(
b, &pb, &src, WUFFS_BASE__PIXEL_BLEND__SRC,
- global_work_slice, NULL));
+ g_work_slice_u8, NULL));
uint64_t n = wuffs_base__pixel_config__pixbuf_len(&ic.pixcfg);
if (n < 4) {
@@ -1042,7 +1045,7 @@
RETURN_FAIL("pixbuf_len too large");
} else {
wuffs_base__color_u32_argb_premul have_final_pixel =
- wuffs_base__load_u32le__no_bounds_check(&global_pixel_array[n - 4]);
+ wuffs_base__load_u32le__no_bounds_check(&g_pixel_array_u8[n - 4]);
if (have_final_pixel != want_final_pixel) {
RETURN_FAIL("final pixel: have 0x%08" PRIX32 ", want 0x%08" PRIX32,
have_final_pixel, want_final_pixel);
@@ -1081,14 +1084,14 @@
}
wuffs_base__io_buffer have = ((wuffs_base__io_buffer){
- .data = global_have_slice,
+ .data = g_have_slice_u8,
});
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
CHECK_STRING(read_file_fragment(&src, src_filename, src_ri, src_wi));
CHECK_STATUS("transform_io", wuffs_base__io_transformer__transform_io(
- b, &have, &src, global_work_slice));
+ b, &have, &src, g_work_slice_u8));
if (have.meta.wi != want_wi) {
RETURN_FAIL("dst wi: have %zu, want %zu", have.meta.wi, want_wi);
}
@@ -1104,16 +1107,16 @@
do_test__wuffs_base__token_decoder(wuffs_base__token_decoder* b,
golden_test* gt) {
wuffs_base__io_buffer have = ((wuffs_base__io_buffer){
- .data = global_have_slice,
+ .data = g_have_slice_u8,
});
wuffs_base__io_buffer want = ((wuffs_base__io_buffer){
- .data = global_want_slice,
+ .data = g_want_slice_u8,
});
wuffs_base__token_buffer tok = ((wuffs_base__token_buffer){
- .data = global_have_token_slice,
+ .data = g_have_slice_token,
});
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
- .data = global_src_slice,
+ .data = g_src_slice_u8,
});
if (gt->src_filename) {
@@ -1124,8 +1127,8 @@
src.meta.closed = true;
}
- CHECK_STATUS("decode_tokens",
- wuffs_base__token_decoder__decode_tokens(b, &tok, &src));
+ CHECK_STATUS("decode_tokens", wuffs_base__token_decoder__decode_tokens(
+ b, &tok, &src, g_work_slice_u8));
uint64_t pos = 0;
while (tok.meta.ri < tok.meta.wi) {
diff --git a/test/data/json-quirks.json b/test/data/json-quirks.json
new file mode 100644
index 0000000..5d3a877
--- /dev/null
+++ b/test/data/json-quirks.json
@@ -0,0 +1,16 @@
+[
+ 123,
+ nan,
+ +INFINITY,
+ "escaped \a\b\e\f\n\r\t\v\0\'\"\?\\\/ things",
+ {
+ "ABC\u0394E": // U+00000394 GREEK CAPITAL LETTER DELTA.
+ "mno\U0001F4A9q", /* U+0001F4A9 PILE OF POO. */
+ /* And now for some
+ * invalid Unicode. */
+ "ABC\uD800E": // Unpaired surrogate.
+ "mno\U12345678q", // Out of range.
+ },
+ "w\x58\x59z",
+ "invÿlid UTF-8",
+]
diff --git a/test/data/json-quirks.tokens b/test/data/json-quirks.tokens
new file mode 100644
index 0000000..d8feab9
--- /dev/null
+++ b/test/data/json-quirks.tokens
Binary files differ