summaryrefslogtreecommitdiff
path: root/util/compress/libdeflate/programs/test_trailing_bytes.c
blob: 92609ff4663b2a85a8902f4f6beab898337dc7b9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/*
 * test_trailing_bytes.c
 *
 * Test that decompression correctly stops at the end of the first DEFLATE,
 * zlib, or gzip stream, and doesn't process any additional trailing bytes.
 */

#include "test_util.h"

static const struct {
	size_t (LIBDEFLATEAPI *compress)(
			struct libdeflate_compressor *compressor,
			const void *in, size_t in_nbytes,
			void *out, size_t out_nbytes_avail);
	enum libdeflate_result (LIBDEFLATEAPI *decompress)(
			struct libdeflate_decompressor *decompressor,
			const void *in, size_t in_nbytes,
			void *out, size_t out_nbytes_avail,
			size_t *actual_out_nbytes_ret);
	enum libdeflate_result (LIBDEFLATEAPI *decompress_ex)(
			struct libdeflate_decompressor *decompressor,
			const void *in, size_t in_nbytes,
			void *out, size_t out_nbytes_avail,
			size_t *actual_in_nbytes_ret,
			size_t *actual_out_nbytes_ret);
} codecs[] = {
	{
		.compress = libdeflate_deflate_compress,
		.decompress = libdeflate_deflate_decompress,
		.decompress_ex = libdeflate_deflate_decompress_ex,
	}, {
		.compress = libdeflate_zlib_compress,
		.decompress = libdeflate_zlib_decompress,
		.decompress_ex = libdeflate_zlib_decompress_ex,
	}, {
		.compress = libdeflate_gzip_compress,
		.decompress = libdeflate_gzip_decompress,
		.decompress_ex = libdeflate_gzip_decompress_ex,
	}
};

int
tmain(int argc, tchar *argv[])
{
	const size_t original_nbytes = 32768;
	const size_t compressed_nbytes_total = 32768;
	/*
	 * Don't use the full buffer for compressed data, because we want to
	 * test whether decompression can deal with additional trailing bytes.
	 *
	 * Note: we can't use a guarded buffer (i.e. a buffer where the byte
	 * after compressed_nbytes is unmapped) because the decompressor may
	 * read a few bytes beyond the end of the stream (but ultimately not
	 * actually use those bytes) as long as they are within the buffer.
	 */
	const size_t compressed_nbytes_avail = 30000;
	size_t i;
	u8 *original;
	u8 *compressed;
	u8 *decompressed;
	struct libdeflate_compressor *c;
	struct libdeflate_decompressor *d;
	size_t compressed_nbytes;
	enum libdeflate_result res;
	size_t actual_compressed_nbytes;
	size_t actual_decompressed_nbytes;

	begin_program(argv);

	ASSERT(compressed_nbytes_avail < compressed_nbytes_total);

	/* Prepare some dummy data to compress */
	original = xmalloc(original_nbytes);
	ASSERT(original != NULL);
	for (i = 0; i < original_nbytes; i++)
		original[i] = (i % 123) + (i % 1023);

	compressed = xmalloc(compressed_nbytes_total);
	ASSERT(compressed != NULL);
	memset(compressed, 0, compressed_nbytes_total);

	decompressed = xmalloc(original_nbytes);
	ASSERT(decompressed != NULL);

	c = libdeflate_alloc_compressor(6);
	ASSERT(c != NULL);

	d = libdeflate_alloc_decompressor();
	ASSERT(d != NULL);

	for (i = 0; i < ARRAY_LEN(codecs); i++) {
		compressed_nbytes = codecs[i].compress(c, original,
						       original_nbytes,
						       compressed,
						       compressed_nbytes_avail);
		ASSERT(compressed_nbytes > 0);
		ASSERT(compressed_nbytes <= compressed_nbytes_avail);

		/* Test decompress() of stream that fills the whole buffer */
		actual_decompressed_nbytes = 0;
		memset(decompressed, 0, original_nbytes);
		res = codecs[i].decompress(d, compressed, compressed_nbytes,
					   decompressed, original_nbytes,
					   &actual_decompressed_nbytes);
		ASSERT(res == LIBDEFLATE_SUCCESS);
		ASSERT(actual_decompressed_nbytes == original_nbytes);
		ASSERT(memcmp(decompressed, original, original_nbytes) == 0);

		/* Test decompress_ex() of stream that fills the whole buffer */
		actual_compressed_nbytes = actual_decompressed_nbytes = 0;
		memset(decompressed, 0, original_nbytes);
		res = codecs[i].decompress_ex(d, compressed, compressed_nbytes,
					      decompressed, original_nbytes,
					      &actual_compressed_nbytes,
					      &actual_decompressed_nbytes);
		ASSERT(res == LIBDEFLATE_SUCCESS);
		ASSERT(actual_compressed_nbytes == compressed_nbytes);
		ASSERT(actual_decompressed_nbytes == original_nbytes);
		ASSERT(memcmp(decompressed, original, original_nbytes) == 0);

		/* Test decompress() of stream with trailing bytes */
		actual_decompressed_nbytes = 0;
		memset(decompressed, 0, original_nbytes);
		res = codecs[i].decompress(d, compressed,
					   compressed_nbytes_total,
					   decompressed, original_nbytes,
					   &actual_decompressed_nbytes);
		ASSERT(res == LIBDEFLATE_SUCCESS);
		ASSERT(actual_decompressed_nbytes == original_nbytes);
		ASSERT(memcmp(decompressed, original, original_nbytes) == 0);

		/* Test decompress_ex() of stream with trailing bytes */
		actual_compressed_nbytes = actual_decompressed_nbytes = 0;
		memset(decompressed, 0, original_nbytes);
		res = codecs[i].decompress_ex(d, compressed,
					      compressed_nbytes_total,
					      decompressed, original_nbytes,
					      &actual_compressed_nbytes,
					      &actual_decompressed_nbytes);
		ASSERT(res == LIBDEFLATE_SUCCESS);
		ASSERT(actual_compressed_nbytes == compressed_nbytes);
		ASSERT(actual_decompressed_nbytes == original_nbytes);
		ASSERT(memcmp(decompressed, original, original_nbytes) == 0);
	}

	free(original);
	free(compressed);
	free(decompressed);
	libdeflate_free_compressor(c);
	libdeflate_free_decompressor(d);
	return 0;
}