example: add output-crc32-digest flag

This commit is contained in:
Nigel Tao
2024-02-15 13:40:09 +11:00
parent 6017c37232
commit 4e20ba6876
4 changed files with 108 additions and 39 deletions

View File

@@ -25,6 +25,7 @@ https://skia-review.googlesource.com/c/skia/+/290618
#include <errno.h>
#include <inttypes.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -150,6 +151,8 @@ union {
wuffs_wbmp__decoder wbmp;
} g_potential_decoders;
wuffs_crc32__ieee_hasher g_digest_hasher;
// ----
#define BYTES_PER_PIXEL 4
@@ -194,6 +197,7 @@ struct {
bool fail_if_unsandboxed;
bool first_frame_only;
bool output_crc32_digest;
bool output_netpbm;
} g_flags = {0};
@@ -227,7 +231,17 @@ parse_flags(int argc, char** argv) {
g_flags.first_frame_only = true;
continue;
}
if (!strcmp(arg, "output-crc32-digest")) {
if (g_flags.output_crc32_digest || g_flags.output_netpbm) {
return "main: multiple --output-etc flags";
}
g_flags.output_crc32_digest = true;
continue;
}
if (!strcmp(arg, "p") || !strcmp(arg, "output-netpbm")) {
if (g_flags.output_crc32_digest || g_flags.output_netpbm) {
return "main: multiple --output-etc flags";
}
g_flags.output_netpbm = true;
continue;
}
@@ -250,6 +264,18 @@ parse_flags(int argc, char** argv) {
static void //
ignore_return_value(int ignored) {}
ssize_t //
write_to_stdout(const void* ptr, size_t len) {
if (!g_flags.output_crc32_digest) {
return write(STDOUT_FD, ptr, len);
} else if (len > SSIZE_MAX) {
return -EFBIG;
}
wuffs_crc32__ieee_hasher__update(
&g_digest_hasher, wuffs_base__make_slice_u8((uint8_t*)ptr, len));
return (ssize_t)len;
}
const char* //
read_more_src() {
if (g_src.meta.closed) {
@@ -528,7 +554,7 @@ print_nix_header(uint32_t magic_u32le) {
wuffs_base__poke_u32le__no_bounds_check(data + 0x04, version1_bn4_u32le);
wuffs_base__poke_u32le__no_bounds_check(data + 0x08, g_width);
wuffs_base__poke_u32le__no_bounds_check(data + 0x0C, g_height);
ignore_return_value(write(STDOUT_FD, &data[0], 16));
ignore_return_value(write_to_stdout(&data[0], 16));
}
void //
@@ -536,14 +562,14 @@ print_netpbm_header() {
char data[256];
int n = snprintf(data, sizeof(data), "P%c\n%" PRIu32 " %" PRIu32 "\n255\n",
(g_pixfmt_is_gray ? '5' : '6'), g_width, g_height);
ignore_return_value(write(STDOUT_FD, &data[0], n));
ignore_return_value(write_to_stdout(&data[0], n));
}
void //
print_nia_duration(wuffs_base__flicks duration) {
uint8_t data[8];
wuffs_base__poke_u64le__no_bounds_check(data + 0x00, duration);
ignore_return_value(write(STDOUT_FD, &data[0], 8));
ignore_return_value(write_to_stdout(&data[0], 8));
}
void //
@@ -552,11 +578,11 @@ print_nie_frame() {
print_nix_header(0x45AFC36E); // "nïE" as a u32le.
wuffs_base__table_u8 tab = wuffs_base__pixel_buffer__plane(&g_pixbuf, 0);
if (tab.width == tab.stride) {
ignore_return_value(write(STDOUT_FD, tab.ptr, tab.width * tab.height));
ignore_return_value(write_to_stdout(tab.ptr, tab.width * tab.height));
} else {
for (size_t y = 0; y < tab.height; y++) {
ignore_return_value(
write(STDOUT_FD, tab.ptr + (y * tab.stride), tab.width));
write_to_stdout(tab.ptr + (y * tab.stride), tab.width));
}
}
}
@@ -576,13 +602,13 @@ print_netpbm_frame() {
data[o + 2] = row[x + 0];
o += o_increment;
if ((o + 3) > sizeof(data)) {
ignore_return_value(write(STDOUT_FD, &data[0], o));
ignore_return_value(write_to_stdout(&data[0], o));
o = 0;
}
}
}
if (o > 0) {
ignore_return_value(write(STDOUT_FD, &data[0], o));
ignore_return_value(write_to_stdout(&data[0], o));
o = 0;
}
}
@@ -592,7 +618,7 @@ print_nia_padding() {
if (g_width & g_height & 1) {
uint8_t data[4];
wuffs_base__poke_u32le__no_bounds_check(data + 0x00, 0);
ignore_return_value(write(STDOUT_FD, &data[0], 4));
ignore_return_value(write_to_stdout(&data[0], 4));
}
}
@@ -616,7 +642,7 @@ print_nia_footer() {
uint8_t data[8];
wuffs_base__poke_u32le__no_bounds_check(data + 0x00, n);
wuffs_base__poke_u32le__no_bounds_check(data + 0x04, 0x80000000);
ignore_return_value(write(STDOUT_FD, &data[0], 8));
ignore_return_value(write_to_stdout(&data[0], 8));
}
const char* //
@@ -761,6 +787,15 @@ main1(int argc, char** argv) {
return "main: unsandboxed";
}
if (g_flags.output_crc32_digest) {
wuffs_base__status status = wuffs_crc32__ieee_hasher__initialize(
&g_digest_hasher, sizeof g_digest_hasher, WUFFS_VERSION,
WUFFS_INITIALIZE__DEFAULT_OPTIONS);
if (status.repr) {
return wuffs_base__status__message(&status);
}
}
g_src.data.ptr = g_src_buffer_array;
g_src.data.len = SRC_BUFFER_ARRAY_SIZE;
@@ -809,6 +844,21 @@ compute_exit_code(const char* status_msg) {
return strstr(status_msg, "internal error:") ? 2 : 1;
}
void //
print_crc32_digest(bool bad) {
const char* hex = "0123456789abcdef";
uint32_t hash = wuffs_crc32__ieee_hasher__checksum_u32(&g_digest_hasher);
char buf[13];
memcpy(buf + 0, bad ? "BAD " : "OK. ", 4);
for (int i = 0; i < 8; i++) {
buf[4 + i] = hex[hash >> 28];
hash <<= 4;
}
buf[12] = '\n';
const int stdout_fd = 1;
ignore_return_value(write(stdout_fd, buf, 13));
}
int //
main(int argc, char** argv) {
#if !defined(ALLOW_GIGABYTES_OF_PIXEL_BUFFERS)
@@ -843,6 +893,9 @@ main(int argc, char** argv) {
#endif
int exit_code = compute_exit_code(main1(argc, argv));
if (g_flags.output_crc32_digest) {
print_crc32_digest(exit_code != 0);
}
#if defined(WUFFS_EXAMPLE_USE_SECCOMP)
// Call SYS_exit explicitly, instead of calling SYS_exit_group implicitly by

View File

@@ -112,6 +112,8 @@ union {
wuffs_zlib__decoder zlib;
} g_potential_decoders;
wuffs_crc32__ieee_hasher g_digest_hasher;
// ----
struct {
@@ -120,6 +122,7 @@ struct {
bool fail_if_unsandboxed;
bool ignore_checksum;
bool output_crc32_digest;
} g_flags = {0};
const char* //
@@ -150,6 +153,9 @@ parse_flags(int argc, char** argv) {
} else if (!strcmp(arg, "ignore-checksum")) {
g_flags.ignore_checksum = true;
continue;
} else if (!strcmp(arg, "output-crc32-digest")) {
g_flags.output_crc32_digest = true;
continue;
}
return "main: unrecognized flag argument";
@@ -280,6 +286,13 @@ main1(int argc, char** argv) {
const char* z = initialize_io_transformer(src.data.ptr[src.meta.ri]);
if (z) {
return z;
} else if (g_flags.output_crc32_digest) {
wuffs_base__status status = wuffs_crc32__ieee_hasher__initialize(
&g_digest_hasher, sizeof g_digest_hasher, WUFFS_VERSION,
WUFFS_INITIALIZE__DEFAULT_OPTIONS);
if (status.repr) {
return wuffs_base__status__message(&status);
}
}
}
@@ -290,10 +303,15 @@ main1(int argc, char** argv) {
sizeof(g_workbuf_array)));
if (dst.meta.ri < 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, g_dst_buffer_array + dst.meta.ri,
dst.meta.wi - dst.meta.ri));
if (g_flags.output_crc32_digest) {
wuffs_crc32__ieee_hasher__update(
&g_digest_hasher, wuffs_base__io_buffer__reader_slice(&dst));
} else {
// TODO: handle EINTR and other write errors; see "man 2 write".
const int stdout_fd = 1;
ignore_return_value(write(stdout_fd, g_dst_buffer_array + dst.meta.ri,
dst.meta.wi - dst.meta.ri));
}
dst.meta.ri = dst.meta.wi;
wuffs_base__optional_u63 hrl =
wuffs_base__io_transformer__dst_history_retain_length(
@@ -345,6 +363,21 @@ compute_exit_code(const char* status_msg) {
return strstr(status_msg, "internal error:") ? 2 : 1;
}
void //
print_crc32_digest(bool bad) {
const char* hex = "0123456789abcdef";
uint32_t hash = wuffs_crc32__ieee_hasher__checksum_u32(&g_digest_hasher);
char buf[13];
memcpy(buf + 0, bad ? "BAD " : "OK. ", 4);
for (int i = 0; i < 8; i++) {
buf[4 + i] = hex[hash >> 28];
hash <<= 4;
}
buf[12] = '\n';
const int stdout_fd = 1;
ignore_return_value(write(stdout_fd, buf, 13));
}
int //
main(int argc, char** argv) {
#if defined(WUFFS_EXAMPLE_USE_SECCOMP)
@@ -353,6 +386,9 @@ main(int argc, char** argv) {
#endif
int exit_code = compute_exit_code(main1(argc, argv));
if (g_flags.output_crc32_digest) {
print_crc32_digest(exit_code != 0);
}
#if defined(WUFFS_EXAMPLE_USE_SECCOMP)
// Call SYS_exit explicitly, instead of calling SYS_exit_group implicitly by

View File

@@ -39,19 +39,9 @@ fi
# ----
handle() {
# "Use $x for the exit code" is loosely based on
# https://stackoverflow.com/a/16530815
local x
local o=$(((((gen/bin/example-mzcat <$1 2>/dev/null; echo $? >&3) |\
gen/bin/example-crc32 >&4) 3>&1) | (read x; echo $x)) 4>&1)
local a=($o)
# ${a[0]} holds the exit code of gen/bin/example-etc.
# ${a[1]} holds the CRC-32 hash of gen/bin/example-etc's output.
if [ ${a[0]} == 0 ]; then
echo OK. ${a[1]} $1
elif [ ${a[1]} != "00000000" ]; then
echo BAD ${a[1]} $1
local c=$(gen/bin/example-mzcat --output-crc32-digest <$1 2>/dev/null)
if [ "$c" != "BAD 00000000" ]; then
echo $c $1
fi
}

View File

@@ -47,19 +47,9 @@ fi
# ----
handle() {
# "Use $x for the exit code" is loosely based on
# https://stackoverflow.com/a/16530815
local x
local o=$(((((gen/bin/example-convert-to-nia <$1 2>/dev/null; echo $? >&3) |\
gen/bin/example-crc32 >&4) 3>&1) | (read x; echo $x)) 4>&1)
local a=($o)
# ${a[0]} holds the exit code of gen/bin/example-etc.
# ${a[1]} holds the CRC-32 hash of gen/bin/example-etc's output.
if [ ${a[0]} == 0 ]; then
echo OK. ${a[1]} $1
elif [ ${a[1]} != "00000000" ]; then
echo BAD ${a[1]} $1
local c=$(gen/bin/example-convert-to-nia --output-crc32-digest <$1 2>/dev/null)
if [ "$c" != "BAD 00000000" ]; then
echo $c $1
fi
}