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