xref: /openbmc/u-boot/test/compression.c (revision 7ca6f363)
1 /*
2  * Copyright (c) 2013, The Chromium Authors
3  *
4  * SPDX-License-Identifier:	GPL-2.0+
5  */
6 
7 #define DEBUG
8 
9 #include <common.h>
10 #include <command.h>
11 #include <malloc.h>
12 
13 #include <u-boot/zlib.h>
14 #include <bzlib.h>
15 
16 #include <lzma/LzmaTypes.h>
17 #include <lzma/LzmaDec.h>
18 #include <lzma/LzmaTools.h>
19 
20 #include <linux/lzo.h>
21 
22 static const char plain[] =
23 	"I am a highly compressable bit of text.\n"
24 	"I am a highly compressable bit of text.\n"
25 	"I am a highly compressable bit of text.\n"
26 	"There are many like me, but this one is mine.\n"
27 	"If I were any shorter, there wouldn't be much sense in\n"
28 	"compressing me in the first place. At least with lzo, anyway,\n"
29 	"which appears to behave poorly in the face of short text\n"
30 	"messages.\n";
31 
32 /* bzip2 -c /tmp/plain.txt > /tmp/plain.bz2 */
33 static const char bzip2_compressed[] =
34 	"\x42\x5a\x68\x39\x31\x41\x59\x26\x53\x59\xe5\x63\xdd\x09\x00\x00"
35 	"\x28\x57\x80\x00\x10\x40\x85\x20\x20\x04\x00\x3f\xef\xdf\xf0\x30"
36 	"\x00\xd6\xd0\x34\x91\x89\xa6\xf5\x4d\x19\x1a\x19\x0d\x02\x34\xd4"
37 	"\xc9\x00\x34\x34\x00\x02\x48\x41\x35\x4f\xd4\xc6\x88\xd3\x50\x3d"
38 	"\x4f\x51\x82\x4f\x88\xc3\x0d\x05\x62\x4f\x91\xa3\x52\x1b\xd0\x52"
39 	"\x41\x4a\xa3\x98\xc2\x6b\xca\xa3\x82\xa5\xac\x8b\x15\x99\x68\xad"
40 	"\xdf\x29\xd6\xf1\xf7\x5a\x10\xcd\x8c\x26\x61\x94\x95\xfe\x9e\x16"
41 	"\x18\x28\x69\xd4\x23\x64\xcc\x2b\xe5\xe8\x5f\x00\xa4\x70\x26\x2c"
42 	"\xee\xbd\x59\x6d\x6a\xec\xfc\x31\xda\x59\x0a\x14\x2a\x60\x1c\xf0"
43 	"\x04\x86\x73\x9a\xc5\x5b\x87\x3f\x5b\x4c\x93\xe6\xb5\x35\x0d\xa6"
44 	"\xb1\x2e\x62\x7b\xab\x67\xe7\x99\x2a\x14\x5e\x9f\x64\xcb\x96\xf4"
45 	"\x0d\x65\xd4\x39\xe6\x8b\x7e\xea\x1c\x03\x69\x97\x83\x58\x91\x96"
46 	"\xe1\xf0\x9d\xa4\x15\x8b\xb8\xc6\x93\xdc\x3d\xd9\x3c\x22\x55\xef"
47 	"\xfb\xbb\x2a\xd3\x87\xa2\x8b\x04\xd9\x19\xf8\xe2\xfd\x4f\xdb\x1a"
48 	"\x07\xc8\x60\xa3\x3f\xf8\xbb\x92\x29\xc2\x84\x87\x2b\x1e\xe8\x48";
49 static const unsigned long bzip2_compressed_size = 240;
50 
51 /* lzma -z -c /tmp/plain.txt > /tmp/plain.lzma */
52 static const char lzma_compressed[] =
53 	"\x5d\x00\x00\x80\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x24\x88"
54 	"\x08\x26\xd8\x41\xff\x99\xc8\xcf\x66\x3d\x80\xac\xba\x17\xf1\xc8"
55 	"\xb9\xdf\x49\x37\xb1\x68\xa0\x2a\xdd\x63\xd1\xa7\xa3\x66\xf8\x15"
56 	"\xef\xa6\x67\x8a\x14\x18\x80\xcb\xc7\xb1\xcb\x84\x6a\xb2\x51\x16"
57 	"\xa1\x45\xa0\xd6\x3e\x55\x44\x8a\x5c\xa0\x7c\xe5\xa8\xbd\x04\x57"
58 	"\x8f\x24\xfd\xb9\x34\x50\x83\x2f\xf3\x46\x3e\xb9\xb0\x00\x1a\xf5"
59 	"\xd3\x86\x7e\x8f\x77\xd1\x5d\x0e\x7c\xe1\xac\xde\xf8\x65\x1f\x4d"
60 	"\xce\x7f\xa7\x3d\xaa\xcf\x26\xa7\x58\x69\x1e\x4c\xea\x68\x8a\xe5"
61 	"\x89\xd1\xdc\x4d\xc7\xe0\x07\x42\xbf\x0c\x9d\x06\xd7\x51\xa2\x0b"
62 	"\x7c\x83\x35\xe1\x85\xdf\xee\xfb\xa3\xee\x2f\x47\x5f\x8b\x70\x2b"
63 	"\xe1\x37\xf3\x16\xf6\x27\x54\x8a\x33\x72\x49\xea\x53\x7d\x60\x0b"
64 	"\x21\x90\x66\xe7\x9e\x56\x61\x5d\xd8\xdc\x59\xf0\xac\x2f\xd6\x49"
65 	"\x6b\x85\x40\x08\x1f\xdf\x26\x25\x3b\x72\x44\xb0\xb8\x21\x2f\xb3"
66 	"\xd7\x9b\x24\x30\x78\x26\x44\x07\xc3\x33\xd1\x4d\x03\x1b\xe1\xff"
67 	"\xfd\xf5\x50\x8d\xca";
68 static const unsigned long lzma_compressed_size = 229;
69 
70 /* lzop -c /tmp/plain.txt > /tmp/plain.lzo */
71 static const char lzo_compressed[] =
72 	"\x89\x4c\x5a\x4f\x00\x0d\x0a\x1a\x0a\x10\x30\x20\x60\x09\x40\x01"
73 	"\x05\x03\x00\x00\x09\x00\x00\x81\xb4\x52\x09\x54\xf1\x00\x00\x00"
74 	"\x00\x09\x70\x6c\x61\x69\x6e\x2e\x74\x78\x74\x65\xb1\x07\x9c\x00"
75 	"\x00\x01\x5e\x00\x00\x01\x0f\xc3\xc7\x7a\xe0\x00\x16\x49\x20\x61"
76 	"\x6d\x20\x61\x20\x68\x69\x67\x68\x6c\x79\x20\x63\x6f\x6d\x70\x72"
77 	"\x65\x73\x73\x61\x62\x6c\x65\x20\x62\x69\x74\x20\x6f\x66\x20\x74"
78 	"\x65\x78\x74\x2e\x0a\x20\x2f\x9c\x00\x00\x22\x54\x68\x65\x72\x65"
79 	"\x20\x61\x72\x65\x20\x6d\x61\x6e\x79\x20\x6c\x69\x6b\x65\x20\x6d"
80 	"\x65\x2c\x20\x62\x75\x74\x20\x74\x68\x69\x73\x20\x6f\x6e\x65\x20"
81 	"\x69\x73\x20\x6d\x69\x6e\x65\x2e\x0a\x49\x66\x20\x49\x20\x77\x84"
82 	"\x06\x0a\x6e\x79\x20\x73\x68\x6f\x72\x74\x65\x72\x2c\x20\x74\x90"
83 	"\x08\x00\x08\x77\x6f\x75\x6c\x64\x6e\x27\x74\x20\x62\x65\x20\x6d"
84 	"\x75\x63\x68\x20\x73\x65\x6e\x73\x65\x20\x69\x6e\x0a\xf8\x19\x02"
85 	"\x69\x6e\x67\x20\x6d\x64\x02\x64\x06\x00\x5a\x20\x66\x69\x72\x73"
86 	"\x74\x20\x70\x6c\x61\x63\x65\x2e\x20\x41\x74\x20\x6c\x65\x61\x73"
87 	"\x74\x20\x77\x69\x74\x68\x20\x6c\x7a\x6f\x2c\x20\x61\x6e\x79\x77"
88 	"\x61\x79\x2c\x0a\x77\x68\x69\x63\x68\x20\x61\x70\x70\x65\x61\x72"
89 	"\x73\x20\x74\x6f\x20\x62\x65\x68\x61\x76\x65\x20\x70\x6f\x6f\x72"
90 	"\x6c\x79\x20\x69\x6e\x20\x74\x68\x65\x20\x66\x61\x63\x65\x20\x6f"
91 	"\x66\x20\x73\x68\x6f\x72\x74\x20\x74\x65\x78\x74\x0a\x6d\x65\x73"
92 	"\x73\x61\x67\x65\x73\x2e\x0a\x11\x00\x00\x00\x00\x00\x00";
93 static const unsigned long lzo_compressed_size = 334;
94 
95 
96 #define TEST_BUFFER_SIZE	512
97 
98 typedef int (*mutate_func)(void *, unsigned long, void *, unsigned long,
99 			   unsigned long *);
100 
101 static int compress_using_gzip(void *in, unsigned long in_size,
102 			       void *out, unsigned long out_max,
103 			       unsigned long *out_size)
104 {
105 	int ret;
106 	unsigned long inout_size = out_max;
107 
108 	ret = gzip(out, &inout_size, in, in_size);
109 	if (out_size)
110 		*out_size = inout_size;
111 
112 	return ret;
113 }
114 
115 static int uncompress_using_gzip(void *in, unsigned long in_size,
116 				 void *out, unsigned long out_max,
117 				 unsigned long *out_size)
118 {
119 	int ret;
120 	unsigned long inout_size = in_size;
121 
122 	ret = gunzip(out, out_max, in, &inout_size);
123 	if (out_size)
124 		*out_size = inout_size;
125 
126 	return ret;
127 }
128 
129 static int compress_using_bzip2(void *in, unsigned long in_size,
130 				void *out, unsigned long out_max,
131 				unsigned long *out_size)
132 {
133 	/* There is no bzip2 compression in u-boot, so fake it. */
134 	assert(in_size == strlen(plain));
135 	assert(memcmp(plain, in, in_size) == 0);
136 
137 	if (bzip2_compressed_size > out_max)
138 		return -1;
139 
140 	memcpy(out, bzip2_compressed, bzip2_compressed_size);
141 	if (out_size)
142 		*out_size = bzip2_compressed_size;
143 
144 	return 0;
145 }
146 
147 static int uncompress_using_bzip2(void *in, unsigned long in_size,
148 				  void *out, unsigned long out_max,
149 				  unsigned long *out_size)
150 {
151 	int ret;
152 	unsigned int inout_size = out_max;
153 
154 	ret = BZ2_bzBuffToBuffDecompress(out, &inout_size, in, in_size,
155 			CONFIG_SYS_MALLOC_LEN < (4096 * 1024), 0);
156 	if (out_size)
157 		*out_size = inout_size;
158 
159 	return (ret != BZ_OK);
160 }
161 
162 static int compress_using_lzma(void *in, unsigned long in_size,
163 			       void *out, unsigned long out_max,
164 			       unsigned long *out_size)
165 {
166 	/* There is no lzma compression in u-boot, so fake it. */
167 	assert(in_size == strlen(plain));
168 	assert(memcmp(plain, in, in_size) == 0);
169 
170 	if (lzma_compressed_size > out_max)
171 		return -1;
172 
173 	memcpy(out, lzma_compressed, lzma_compressed_size);
174 	if (out_size)
175 		*out_size = lzma_compressed_size;
176 
177 	return 0;
178 }
179 
180 static int uncompress_using_lzma(void *in, unsigned long in_size,
181 				 void *out, unsigned long out_max,
182 				 unsigned long *out_size)
183 {
184 	int ret;
185 	SizeT inout_size = out_max;
186 
187 	ret = lzmaBuffToBuffDecompress(out, &inout_size, in, in_size);
188 	if (out_size)
189 		*out_size = inout_size;
190 
191 	return (ret != SZ_OK);
192 }
193 
194 static int compress_using_lzo(void *in, unsigned long in_size,
195 			      void *out, unsigned long out_max,
196 			      unsigned long *out_size)
197 {
198 	/* There is no lzo compression in u-boot, so fake it. */
199 	assert(in_size == strlen(plain));
200 	assert(memcmp(plain, in, in_size) == 0);
201 
202 	if (lzo_compressed_size > out_max)
203 		return -1;
204 
205 	memcpy(out, lzo_compressed, lzo_compressed_size);
206 	if (out_size)
207 		*out_size = lzo_compressed_size;
208 
209 	return 0;
210 }
211 
212 static int uncompress_using_lzo(void *in, unsigned long in_size,
213 				void *out, unsigned long out_max,
214 				unsigned long *out_size)
215 {
216 	int ret;
217 	size_t input_size = in_size;
218 	size_t output_size = out_max;
219 
220 	ret = lzop_decompress(in, input_size, out, &output_size);
221 	if (out_size)
222 		*out_size = output_size;
223 
224 	return (ret != LZO_E_OK);
225 }
226 
227 #define errcheck(statement) if (!(statement)) { \
228 	fprintf(stderr, "\tFailed: %s\n", #statement); \
229 	ret = 1; \
230 	goto out; \
231 }
232 
233 static int run_test(char *name, mutate_func compress, mutate_func uncompress)
234 {
235 	ulong orig_size, compressed_size, uncompressed_size;
236 	void *orig_buf;
237 	void *compressed_buf = NULL;
238 	void *uncompressed_buf = NULL;
239 	void *compare_buf = NULL;
240 	int ret;
241 
242 	printf(" testing %s ...\n", name);
243 
244 	orig_buf = (void *)plain;
245 	orig_size = strlen(orig_buf); /* Trailing NULL not included. */
246 	errcheck(orig_size > 0);
247 
248 	compressed_size = uncompressed_size = TEST_BUFFER_SIZE;
249 	compressed_buf = malloc(compressed_size);
250 	errcheck(compressed_buf != NULL);
251 	uncompressed_buf = malloc(uncompressed_size);
252 	errcheck(uncompressed_buf != NULL);
253 	compare_buf = malloc(uncompressed_size);
254 	errcheck(compare_buf != NULL);
255 
256 	/* Compress works as expected. */
257 	printf("\torig_size:%lu\n", orig_size);
258 	memset(compressed_buf, 'A', TEST_BUFFER_SIZE);
259 	errcheck(compress(orig_buf, orig_size,
260 			compressed_buf, compressed_size,
261 			&compressed_size) == 0);
262 	printf("\tcompressed_size:%lu\n", compressed_size);
263 	errcheck(compressed_size > 0);
264 	errcheck(compressed_size < orig_size);
265 	errcheck(((char *)compressed_buf)[compressed_size-1] != 'A');
266 	errcheck(((char *)compressed_buf)[compressed_size] == 'A');
267 
268 	/* Uncompresses with space remaining. */
269 	errcheck(uncompress(compressed_buf, compressed_size,
270 			  uncompressed_buf, uncompressed_size,
271 			  &uncompressed_size) == 0);
272 	printf("\tuncompressed_size:%lu\n", uncompressed_size);
273 	errcheck(uncompressed_size == orig_size);
274 	errcheck(memcmp(orig_buf, uncompressed_buf, orig_size) == 0);
275 
276 	/* Uncompresses with exactly the right size output buffer. */
277 	memset(uncompressed_buf, 'A', TEST_BUFFER_SIZE);
278 	errcheck(uncompress(compressed_buf, compressed_size,
279 			  uncompressed_buf, orig_size,
280 			  &uncompressed_size) == 0);
281 	errcheck(uncompressed_size == orig_size);
282 	errcheck(memcmp(orig_buf, uncompressed_buf, orig_size) == 0);
283 	errcheck(((char *)uncompressed_buf)[orig_size] == 'A');
284 
285 	/* Make sure compression does not over-run. */
286 	memset(compare_buf, 'A', TEST_BUFFER_SIZE);
287 	ret = compress(orig_buf, orig_size,
288 		       compare_buf, compressed_size - 1,
289 		       NULL);
290 	errcheck(((char *)compare_buf)[compressed_size] == 'A');
291 	errcheck(ret != 0);
292 	printf("\tcompress does not overrun\n");
293 
294 	/* Make sure decompression does not over-run. */
295 	memset(compare_buf, 'A', TEST_BUFFER_SIZE);
296 	ret = uncompress(compressed_buf, compressed_size,
297 			 compare_buf, uncompressed_size - 1,
298 			 NULL);
299 	errcheck(((char *)compare_buf)[uncompressed_size - 1] == 'A');
300 	errcheck(ret != 0);
301 	printf("\tuncompress does not overrun\n");
302 
303 	/* Got here, everything is fine. */
304 	ret = 0;
305 
306 out:
307 	printf(" %s: %s\n", name, ret == 0 ? "ok" : "FAILED");
308 
309 	free(compare_buf);
310 	free(uncompressed_buf);
311 	free(compressed_buf);
312 
313 	return ret;
314 }
315 
316 
317 static int do_test_compression(cmd_tbl_t *cmdtp, int flag, int argc,
318 			       char * const argv[])
319 {
320 	int err = 0;
321 
322 	err += run_test("gzip", compress_using_gzip, uncompress_using_gzip);
323 	err += run_test("bzip2", compress_using_bzip2, uncompress_using_bzip2);
324 	err += run_test("lzma", compress_using_lzma, uncompress_using_lzma);
325 	err += run_test("lzo", compress_using_lzo, uncompress_using_lzo);
326 
327 	printf("test_compression %s\n", err == 0 ? "ok" : "FAILED");
328 
329 	return err;
330 }
331 
332 U_BOOT_CMD(
333 	test_compression,	5,	1,	do_test_compression,
334 	"Basic test of compressors: gzip bzip2 lzma lzo", ""
335 );
336