2 * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
32 /* Forcibly enable assertions */
38 #include <ipxe/deflate.h>
39 #include <ipxe/test.h>
43 /** Compression format */
44 enum deflate_format format;
45 /** Compressed data */
46 const void *compressed;
47 /** Length of compressed data */
48 size_t compressed_len;
49 /** Expected uncompressed data */
51 /** Length of expected uncompressed data */
55 /** A DEFLATE fragment list */
56 struct deflate_test_fragments {
57 /** Fragment lengths */
61 /** Define inline data */
62 #define DATA(...) { __VA_ARGS__ }
64 /** Define a DEFLATE test */
65 #define DEFLATE( name, FORMAT, COMPRESSED, EXPECTED ) \
66 static const uint8_t name ## _compressed[] = COMPRESSED; \
67 static const uint8_t name ## _expected[] = EXPECTED; \
68 static struct deflate_test name = { \
70 .compressed = name ## _compressed, \
71 .compressed_len = sizeof ( name ## _compressed ), \
72 .expected = name ## _expected, \
73 .expected_len = sizeof ( name ## _expected ), \
76 /* Empty file, no compression */
77 DEFLATE ( empty_literal, DEFLATE_RAW,
78 DATA ( 0x01, 0x00, 0x00, 0xff, 0xff ), DATA() );
80 /* "iPXE" string, no compression */
81 DEFLATE ( literal, DEFLATE_RAW,
82 DATA ( 0x01, 0x04, 0x00, 0xfb, 0xff, 0x69, 0x50, 0x58, 0x45 ),
83 DATA ( 0x69, 0x50, 0x58, 0x45 ) );
85 /* "iPXE" string, no compression, split into two literals */
86 DEFLATE ( split_literal, DEFLATE_RAW,
87 DATA ( 0x00, 0x02, 0x00, 0xfd, 0xff, 0x69, 0x50, 0x01, 0x02, 0x00,
88 0xfd, 0xff, 0x58, 0x45 ),
89 DATA ( 0x69, 0x50, 0x58, 0x45 ) );
92 DEFLATE ( empty, DEFLATE_RAW, DATA ( 0x03, 0x00 ), DATA() );
95 DEFLATE ( hello_world, DEFLATE_RAW,
96 DATA ( 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca,
98 DATA ( 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c,
101 /* "Hello hello world" */
102 DEFLATE ( hello_hello_world, DEFLATE_RAW,
103 DATA ( 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0xc8, 0x00, 0x93, 0xe5,
104 0xf9, 0x45, 0x39, 0x29, 0x00 ),
105 DATA ( 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x68, 0x65, 0x6c, 0x6c,
106 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64 ) );
108 /* "This specification defines a lossless compressed data format" */
109 DEFLATE ( rfc_sentence, DEFLATE_RAW,
110 DATA ( 0x0d, 0xc6, 0xdb, 0x09, 0x00, 0x21, 0x0c, 0x04, 0xc0, 0x56,
111 0xb6, 0x28, 0x1b, 0x08, 0x79, 0x70, 0x01, 0x35, 0xe2, 0xa6,
112 0x7f, 0xce, 0xf9, 0x9a, 0xf1, 0x25, 0xc1, 0xe3, 0x9a, 0x91,
113 0x2a, 0x9d, 0xb5, 0x61, 0x1e, 0xb9, 0x9d, 0x10, 0xcc, 0x22,
114 0xa7, 0x93, 0xd0, 0x5a, 0xe7, 0xbe, 0xb8, 0xc1, 0xa4, 0x05,
115 0x51, 0x77, 0x49, 0xff ),
116 DATA ( 0x54, 0x68, 0x69, 0x73, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69,
117 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x64,
118 0x65, 0x66, 0x69, 0x6e, 0x65, 0x73, 0x20, 0x61, 0x20, 0x6c,
119 0x6f, 0x73, 0x73, 0x6c, 0x65, 0x73, 0x73, 0x20, 0x63, 0x6f,
120 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x64,
121 0x61, 0x74, 0x61, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74 ) );
123 /* "ZLIB Compressed Data Format Specification" */
124 DEFLATE ( zlib, DEFLATE_ZLIB,
125 DATA ( 0x78, 0x01, 0x8b, 0xf2, 0xf1, 0x74, 0x52, 0x70, 0xce, 0xcf,
126 0x2d, 0x28, 0x4a, 0x2d, 0x2e, 0x4e, 0x4d, 0x51, 0x70, 0x49,
127 0x2c, 0x49, 0x54, 0x70, 0xcb, 0x2f, 0xca, 0x4d, 0x2c, 0x51,
128 0x08, 0x2e, 0x48, 0x4d, 0xce, 0x4c, 0xcb, 0x4c, 0x4e, 0x2c,
129 0xc9, 0xcc, 0xcf, 0x03, 0x00, 0x2c, 0x0e, 0x0e, 0xeb ),
130 DATA ( 0x5a, 0x4c, 0x49, 0x42, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x72,
131 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x44, 0x61, 0x74, 0x61,
132 0x20, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x20, 0x53, 0x70,
133 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
136 /* "ZLIB Compressed Data Format Specification" fragment list */
137 static struct deflate_test_fragments zlib_fragments[] = {
139 { { 0, 1, 5, -1UL, } },
140 { { 0, 0, 1, 0, 0, 1, -1UL } },
141 { { 10, 8, 4, 7, 11, -1UL } },
147 * Report DEFLATE test result
149 * @v deflate Decompressor
150 * @v test Deflate test
151 * @v frags Fragment list, or NULL
152 * @v file Test code file
153 * @v line Test code line
155 static void deflate_okx ( struct deflate *deflate,
156 struct deflate_test *test,
157 struct deflate_test_fragments *frags,
158 const char *file, unsigned int line ) {
159 uint8_t data[ test->expected_len ];
160 struct deflate_chunk in;
161 struct deflate_chunk out;
162 size_t frag_len = -1UL;
164 size_t remaining = test->compressed_len;
167 /* Initialise decompressor */
168 deflate_init ( deflate, test->format );
170 /* Initialise output chunk */
171 deflate_chunk_init ( &out, virt_to_user ( data ), 0, sizeof ( data ) );
173 /* Process input (in fragments, if applicable) */
174 for ( i = 0 ; i < ( sizeof ( frags->len ) /
175 sizeof ( frags->len[0] ) ) ; i++ ) {
177 /* Initialise input chunk */
179 frag_len = frags->len[i];
180 if ( frag_len > remaining )
181 frag_len = remaining;
182 deflate_chunk_init ( &in, virt_to_user ( test->compressed ),
183 offset, ( offset + frag_len ) );
185 /* Decompress this fragment */
186 okx ( deflate_inflate ( deflate, &in, &out ) == 0, file, line );
187 okx ( in.len == ( offset + frag_len ), file, line );
188 okx ( in.offset == in.len, file, line );
190 /* Move to next fragment */
192 remaining -= frag_len;
196 /* Check that decompression has not terminated early */
197 okx ( ! deflate_finished ( deflate ), file, line );
200 /* Check decompression has terminated as expected */
201 okx ( deflate_finished ( deflate ), file, line );
202 okx ( offset == test->compressed_len, file, line );
203 okx ( out.offset == test->expected_len, file, line );
204 okx ( memcmp ( data, test->expected, test->expected_len ) == 0,
207 #define deflate_ok( deflate, test, frags ) \
208 deflate_okx ( deflate, test, frags, __FILE__, __LINE__ )
211 * Perform DEFLATE self-test
214 static void deflate_test_exec ( void ) {
215 struct deflate *deflate;
218 /* Allocate shared structure */
219 deflate = malloc ( sizeof ( *deflate ) );
220 ok ( deflate != NULL );
222 /* Perform self-tests */
225 /* Test as a single pass */
226 deflate_ok ( deflate, &empty_literal, NULL );
227 deflate_ok ( deflate, &literal, NULL );
228 deflate_ok ( deflate, &split_literal, NULL );
229 deflate_ok ( deflate, &empty, NULL );
230 deflate_ok ( deflate, &hello_world, NULL );
231 deflate_ok ( deflate, &hello_hello_world, NULL );
232 deflate_ok ( deflate, &rfc_sentence, NULL );
233 deflate_ok ( deflate, &zlib, NULL );
235 /* Test fragmentation */
236 for ( i = 0 ; i < ( sizeof ( zlib_fragments ) /
237 sizeof ( zlib_fragments[0] ) ) ; i++ ) {
238 deflate_ok ( deflate, &zlib, &zlib_fragments[i] );
242 /* Free shared structure */
246 /** DEFLATE self-test */
247 struct self_test deflate_test __self_test = {
249 .exec = deflate_test_exec,