#!/bin/sh
# SPDX-License-Identifier: 0BSD

LC_ALL=C
export LC_ALL

# head -c is Issue 8 and OpenBSD does not have it
head -c 0 < /dev/null 2>/dev/null || head() { dd bs=1 count="$2" 2>/dev/null; }
command -v truncate > /dev/null   || truncate() { tr=$2; printf '\0' | dd bs=1 count=1 seek=$(( tr - 1 )) > "$3" 2>/dev/null; }
command -v base64 > /dev/null     || base64() { b64decode -r; }


EMPTYSUM='4294967295 0'  # cksum /dev/null

reqsum() {  # file cksum [label]
	sum="$(cksum < "$1")" || exit
	[ "$sum" = "$2" ] || {
		echo "$0: ${3-"$1"}: cksum $sum != $2" >&2
		exit 1
	}
}

expexit() {  # expecting comment
	ret=$?
	[ "$ret" -eq "${1-0}" ] || {
		echo "$0: $2: $ret != ${1-0}!" >&2
		ret=${ret#0}
		exit ${ret:-100}
	}
}

reqcompuncomp() {
	for src in file ${pipe-pipe}; do
		case $src in
			file)	           "$snappy" $tpfl $1 "$2" > "${tmpd}out$suff" 2>"${tmpd}err$suff" ;;
			pipe)	cat "$2" | "$snappy" $tpfl $1      > "${tmpd}out$suff" 2>"${tmpd}err$suff" ;;
		esac
		expexit "${exit-0}" "${4-"$2"}"

		grep -v ' -> ' "${tmpd}err$suff" > "${tmpd}errG$suff"
		[ -n "$error" ] && {
			mv "${tmpd}errG$suff" "${tmpd}err$suff"
			grep -v -e "$error" "${tmpd}err$suff" > "${tmpd}errG$suff"
		}
		[ -s "${tmpd}errG$suff" ] && {
			echo "$0: ${4-"$2"} $tpfl ${1:-  }: error output!" >&2
			cat "${tmpd}errG$suff" >&2
			exit 101
		}
		reqsum "${tmpd}out$suff" "$3" "${4-"$2"} ${1:-  } ${tp}compressed ($src)"
	done
	rm "${tmpd}out$suff"
}

reqcomp() {  # -f|'' file cksum [label]
	tp= tpfl= reqcompuncomp "$@"
}

requncomp() {  # -i|'' file cksum [label]
	tp=un tpfl=-d reqcompuncomp "$@"
}


trap 'rm -rf "$tmpd"' EXIT INT
tmpd="$(mktemp -d)/" || exit
snappy="${snappy-./snappy}"

LP64="$(od -tc -N5 -An "$snappy" | {
	read -r x7f e l f wide
	[ "$x7f$e$l$f" = '177ELF' ] || {
		echo "$0: $snappy not an ELF" >&2
		exit 102
	}
	case "$wide" in
		(001)	;;
		(002)	echo 1 ;;
		(*  )	echo "$0: $snappy ELF EI_CLASS=$wide != 00[12]" >&2; exit 102 ;;
	esac
})" || exit


truncate -s $(( 4 * 1024 * 1024 * 1024 - 1 )) "${tmpd}4G-1"
truncate -s $(( 4 * 1024 * 1024 * 1024     )) "${tmpd}4G"
truncate -s $(( 4 * 1024 * 1024 * 1024 + 1 )) "${tmpd}4G+1"

pipe=                                                                                 suff=0 reqcomp '' "${tmpd}4G-1" '1595709065 201457669' & slowpids="$slowpids $!"
if [ -n "$LP64" ]; then
pipe= exit=3 error=': sized 4294967296B >= 4GiB w/o -f: output stream may be broken!' suff=1 reqcomp '' "${tmpd}4G"   '3359713396 201457665' & slowpids="$slowpids $!"
pipe= exit=3 error=': sized 4294967297B >= 4GiB w/o -f: output stream may be broken!' suff=2 reqcomp '' "${tmpd}4G+1" '2636691535 201457667' & slowpids="$slowpids $!"
else
pipe= exit=2 error='Value too large for defined data type'                                   reqcomp '' "${tmpd}4G"   "$EMPTYSUM"  # EOVERFLOW
pipe= exit=2 error='Value too large for defined data type'                                   reqcomp '' "${tmpd}4G+1" "$EMPTYSUM"  # EOVERFLOW
unset pipe exit error  # OpenBSD
echo "$0: ILP32" >&2
fi
pipe=                                                                                 suff=3 reqcomp -f "${tmpd}4G-1" '3376615409 202178570' & slowpids="$slowpids $!"
pipe=                                                                                 suff=4 reqcomp -f "${tmpd}4G"   '1723315092 202178570' & slowpids="$slowpids $!"
pipe=                                                                                 suff=5 reqcomp -f "${tmpd}4G+1" '1639829730 202178579' & slowpids="$slowpids $!"


# A constant megabyte of uncompressible data but without shipping a constant megabyte of uncompressible data
# This is the minstd generator (m = 2^31−1, a = 48271, c = 0), seed chosen from date +%s at time of writing
# This could be a shell function but converting a number to bytes is too slow to be useful
{
	printf '%s\n' '#include <endian.h>'                    \
	              '#include <stdint.h>'                    \
	              '#include <stdio.h>'                     \
	              'int main() {'                           \
	              '	uint32_t seed = 1703786413, le;'       \
	              '	for(;;) {'                             \
	              '		seed = (48271 * seed) % 0x7FFFFFFF;' \
	              '		le   = htole32(seed);'               \
	              '		fwrite(&le, 1, sizeof(le), stdout);' \
	              '	}'                                     \
	              '}' | ${CC-cc} ${CPPFLAGS} ${CFLAGS} -O0 -xc - -o "${tmpd}genrand"
	"${tmpd}genrand" | head -c $(( 1024 * 1024 )) > "${tmpd}rand"
} & randpid=$!

# A constant megabyte of easily-compressible data but without shipping a constant megabyte of easily-compressible data
i=0; while [ $i -lt 1024 ]; do
	printf '%1023d\n' $i
	i=$(( i + 1 ))
done > "${tmpd}notrand"
reqsum "${tmpd}notrand" '1532305231 1048576'


[ -w /dev/full ] && {
	"$snappy" "${tmpd}notrand" > /dev/full 2>/dev/null
	expexit 2 '/dev/full'

	"$snappy" -f "${tmpd}notrand" > /dev/full 2>/dev/null
	expexit 2 '/dev/full'

	"$snappy" /ENOENT > /dev/full 2>/dev/null
	expexit 2 '/ENOENT'

	"$snappy" -d /ENOENT > /dev/full 2>/dev/null
	expexit 2 '-d /ENOENT'
} || echo "$0: no /dev/full" >&2



# $ echo data | ./snappy -f | hd
# 000000 ff 06 00 00 73 4e 61 50 70 59 01 09 00 00 eb 1b  >....sNaPpY......<
# 000010 fb 25 64 61 74 61 0a                             >.%data.<
# 000017
stream_identifier() {  # data
	data="${1-sNaPpY}"
	printf '\377'
	printf "\\$(printf %03o ${#data})"'\0\0'
	printf '%s' "$data"
}

uncompressed() {
	printf '\1'
	printf '\11\0\0' # 9
	printf '\353\33\373\45'
	printf 'data\n'
}

# $ echo data data data data data | ./snappy -f | hd
# 000000 ff 06 00 00 73 4e 61 50 70 59 00 10 00 00 c4 61  >....sNaPpY.....a<
# 000010 e6 61 19 10 64 61 74 61 20 4a 05 00 00 0a        >.a..data J....<
# 00001e
compressed() {
	printf '\0'
	printf '\20\0\0'
	printf '\304\141\346\141'
	compressed_data
}
compressed_data() {
	printf '\31\20data\40\112\5\0\0\n'
}

mangle_cksum() {
	head -c $(( 1 + 3 ))
	head -c 4 > /dev/null
	printf '\377\377\377\377'
	cat
}


stream_identifier > "${tmpd}tmp"
requncomp '' "${tmpd}tmp" "$EMPTYSUM"


{ stream_identifier; uncompressed; } > "${tmpd}tmp"
requncomp '' "${tmpd}tmp" "$(echo data | cksum)"


# 4.1. Stream identifier (chunk type 0xff)
{ stream_identifier; stream_identifier snoopy; uncompressed; } > "${tmpd}tmp"
exit=1 error=': stream identifier chunk: content snoopy != sNaPpY' requncomp '' "${tmpd}tmp" "$EMPTYSUM"
exit=1 error=': stream identifier chunk: content snoopy != sNaPpY' requncomp -i "${tmpd}tmp" "$(echo data | cksum)"

{ stream_identifier; stream_identifier short; uncompressed; } > "${tmpd}tmp"
exit=1 error='stream identifier chunk: length 5 != 6
: stream identifier chunk: content short != sNaPpY' requncomp '' "${tmpd}tmp" "$EMPTYSUM"
exit=1 error='stream identifier chunk: length 5 != 6
: stream identifier chunk: content short != sNaPpY' requncomp -i "${tmpd}tmp" "$(echo data | cksum)"
unset pipe exit error  # OpenBSD


# 4.2. Compressed data (chunk type 0x00)
{ stream_identifier; compressed; } > "${tmpd}tmp"
requncomp '' "${tmpd}tmp" "$(echo data data data data data | cksum)"
requncomp -i "${tmpd}tmp" "$(echo data data data data data | cksum)"

compressed_data > "${tmpd}tmp"
requncomp '' "${tmpd}tmp" "$(echo data data data data data | cksum)"
requncomp -i "${tmpd}tmp" "$(echo data data data data data | cksum)"

{ stream_identifier; { printf '\0'; printf '\5\0\0'; printf '\330\352\202\242'; printf '\377'; } } > "${tmpd}tmp"
exit=1 error=': compressed block of length 1: invalid data' requncomp '' "${tmpd}tmp" "$EMPTYSUM"
exit=1 error=': compressed block of length 1: invalid data
: compressed block of length 1: expecting 127 bytes, got 0' requncomp -i "${tmpd}tmp" "$EMPTYSUM"

printf '\377' > "${tmpd}tmp"
exit=1 error=': compressed block of length 1: invalid data' requncomp '' "${tmpd}tmp" "$EMPTYSUM"
exit=1 error=': compressed block of length 1: invalid data
: compressed block of length 1: expecting 127 bytes, got 0' requncomp -i "${tmpd}tmp" "$EMPTYSUM"
unset pipe exit error  # OpenBSD


# 4.3. Uncompressed data (chunk type 0x01)
: nothing


# 4.4. Padding (chunk type 0xfe)
{ stream_identifier; { printf '\376'; printf '\5\0\0'; echo skip; } } > "${tmpd}tmp"
requncomp '' "${tmpd}tmp" "$EMPTYSUM"
requncomp -i "${tmpd}tmp" "$EMPTYSUM"


# 4.6. Reserved skippable chunks (chunk types 0x80-0xfd)
{ stream_identifier; { printf '\375'; printf '\5\0\0'; echo skip; }; { printf '\200'; printf '\5\0\0'; echo skip; } } > "${tmpd}tmp"
requncomp '' "${tmpd}tmp" "$EMPTYSUM"
requncomp -i "${tmpd}tmp" "$EMPTYSUM"


# 4.5. Reserved unskippable chunks (chunk types 0x02-0x7f)
{ stream_identifier; { printf '\2'; printf '\5\0\0'; echo need; }; { printf '\177'; printf '\5\0\0'; echo need; }; uncompressed; } > "${tmpd}tmp"
exit=1 error=': chunk of length 5: unknown type 0x02' requncomp '' "${tmpd}tmp" "$EMPTYSUM"
exit=1 error=': chunk of length 5: unknown type 0x02
: chunk of length 5: unknown type 0x7F' requncomp -i "${tmpd}tmp" "$(echo data | cksum)"


# Broken checksum
{ stream_identifier; uncompressed | mangle_cksum; uncompressed; } > "${tmpd}tmp"
exit=1 error=': chunk of length 9: checksum 0x25FB1BEB != 0xFFFFFFFF' requncomp '' "${tmpd}tmp" "$(echo data | cksum)"
exit=1 error=': chunk of length 9: checksum 0x25FB1BEB != 0xFFFFFFFF' requncomp -i "${tmpd}tmp" "$({ echo data; echo data; } | cksum)"

{ stream_identifier; compressed   | mangle_cksum; uncompressed; } > "${tmpd}tmp"
exit=1 error=': chunk of length 16: checksum 0x61E661C4 != 0xFFFFFFFF' requncomp '' "${tmpd}tmp" "$(echo data data data data data | cksum)"
exit=1 error=': chunk of length 16: checksum 0x61E661C4 != 0xFFFFFFFF' requncomp -i "${tmpd}tmp" "$({ echo data data data data data; echo data; } | cksum)"

{ stream_identifier; uncompressed | mangle_cksum; compressed | mangle_cksum; uncompressed; } > "${tmpd}tmp"
exit=1 error=': chunk of length 9: checksum 0x25FB1BEB != 0xFFFFFFFF' requncomp '' "${tmpd}tmp" "$(echo data | cksum)"
exit=1 error=': chunk of length 9: checksum 0x25FB1BEB != 0xFFFFFFFF
: chunk of length 16: checksum 0x61E661C4 != 0xFFFFFFFF' requncomp -i "${tmpd}tmp" "$({ echo data; echo data data data data data; echo data; } | cksum)"
unset pipe exit error  # OpenBSD


wait $randpid
reqsum "${tmpd}rand" '3325647168 1048576'

cat "${tmpd}notrand" "${tmpd}rand" > "${tmpd}both"
reqsum "${tmpd}both" '2787934995 2097152'


reqcomp '' "${tmpd}rand"    '3602555776 1048627'
reqcomp '' "${tmpd}notrand" '1720161590 51441'
reqcomp '' "${tmpd}both"    '2176093359 1100066'
reqcomp -f "${tmpd}rand"    '1464354933 1048714'
reqcomp -f "${tmpd}notrand" '4240805396 51624'
reqcomp -f "${tmpd}both"    '2083221021 1100328'


# Sought input
{ echo pref; stream_identifier; compressed; } > "${tmpd}tmp"
{ head -c 5; "$snappy" -d  2>/dev/null || exit; } < "${tmpd}tmp" > "${tmpd}head-d"
{ head -c 5; "$snappy" -di 2>/dev/null || exit; } < "${tmpd}tmp" > "${tmpd}head-di"
reqsum "${tmpd}head-d"  "$(printf '%s\n' pref 'data data data data data' | cksum)"
reqsum "${tmpd}head-di" "$(printf '%s\n' pref 'data data data data data' | cksum)"

{ head -c $(( 1024 * 1024 )) > /dev/null; "$snappy"    2>/dev/null || exit; } < "${tmpd}both" > "${tmpd}rand.comp"
{ head -c $(( 1024 * 1024 )) > /dev/null; "$snappy" -f 2>/dev/null || exit; } < "${tmpd}both" > "${tmpd}rand.comp-f"
reqsum "${tmpd}rand.comp"   '3602555776 1048627'  # same as rand
reqsum "${tmpd}rand.comp-f" '1464354933 1048714'  # same as rand


# Wikipedia (old)
# 0000000: ca02 f042 5769 6b69 7065 6469 6120 6973  ...BWikipedia is
# 0000010: 2061 2066 7265 652c 2077 6562 2d62 6173   a free, web-bas
# 0000020: 6564 2c20 636f 6c6c 6162 6f72 6174 6976  ed, collaborativ
# 0000030: 652c 206d 756c 7469 6c69 6e67 7561 6c20  e, multilingual
# 0000040: 656e 6379 636c 6f09 3ff0 1470 726f 6a65  encyclo.?..proje
# 0000050: 6374 2e00 0000 0000 0000 0000 0000 0000  ct.
WIKIRAW='Wikipedia is a free, web-based, collaborative, multilingual encyclopedia project.'
echo ygLwQldpa2lwZWRpYSBpcyBhIGZyZWUsIHdlYi1iYXNlZCwgY29sbGFib3JhdGl2ZSwgbXVsdGlsaW5ndWFsIGVuY3ljbG8JP/AUcHJvamVjdC4AAAAAAAAAAAAAAAAA | base64 -d > "${tmpd}wiki.old.sn"
reqsum "${tmpd}wiki.old.sn" '1128299641 96'

exit=1 error='compressed block of length 96: expecting 330 bytes, got 94' requncomp '' "${tmpd}wiki.old.sn" "$(printf '%s\0\0\0\0\0\0\0\0\0\0\0\0\0' "$WIKIRAW" | cksum)"
exit=1 error='compressed block of length 96: expecting 330 bytes, got 94' requncomp -i "${tmpd}wiki.old.sn" "$(printf '%s\0\0\0\0\0\0\0\0\0\0\0\0\0' "$WIKIRAW" | cksum)"
unset pipe exit error  # OpenBSD

# Wikipedia (new)
# https://en.wikipedia.org/w/index.php?title=Snappy_(compression)&oldid=1192681788
# 000000 51 f0 42 57 69 6b 69 70 65 64 69 61 20 69 73 20  >Q.BWikipedia is <
# 000010 61 20 66 72 65 65 2c 20 77 65 62 2d 62 61 73 65  >a free, web-base<
# 000020 64 2c 20 63 6f 6c 6c 61 62 6f 72 61 74 69 76 65  >d, collaborative<
# 000030 2c 20 6d 75 6c 74 69 6c 69 6e 67 75 61 6c 20 65  >, multilingual e<
# 000040 6e 63 79 63 6c 6f 09 3f 1c 70 72 6f 6a 65 63 74  >ncyclo.?.project<
# 000050 2e                                               >.<
echo UfBCV2lraXBlZGlhIGlzIGEgZnJlZSwgd2ViLWJhc2VkLCBjb2xsYWJvcmF0aXZlLCBtdWx0aWxpbmd1YWwgZW5jeWNsbwk/HHByb2plY3Qu | base64 -d > "${tmpd}wiki.new.sn"
reqsum "${tmpd}wiki.new.sn" '2867047585 81'

requncomp '' "${tmpd}wiki.new.sn" "$(printf '%s' "$WIKIRAW" | cksum)"
requncomp -i "${tmpd}wiki.new.sn" "$(printf '%s' "$WIKIRAW" | cksum)"


for i in $slowpids; do
	wait $i || exit
done
