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
20 FILE_LICENCE ( GPL2_OR_LATER );
28 /* Forcibly enable assertions */
34 #include <ipxe/deflate.h>
35 #include <ipxe/test.h>
39 /** Compression format */
40 enum deflate_format format;
41 /** Compressed data */
42 const void *compressed;
43 /** Length of compressed data */
44 size_t compressed_len;
45 /** Expected uncompressed data */
47 /** Length of expected uncompressed data */
51 /** A DEFLATE fragment list */
52 struct deflate_test_fragments {
53 /** Fragment lengths */
57 /** Define inline data */
58 #define DATA(...) { __VA_ARGS__ }
60 /** Define a DEFLATE test */
61 #define DEFLATE( name, FORMAT, COMPRESSED, EXPECTED ) \
62 static const uint8_t name ## _compressed[] = COMPRESSED; \
63 static const uint8_t name ## _expected[] = EXPECTED; \
64 static struct deflate_test name = { \
66 .compressed = name ## _compressed, \
67 .compressed_len = sizeof ( name ## _compressed ), \
68 .expected = name ## _expected, \
69 .expected_len = sizeof ( name ## _expected ), \
72 /* Empty file, no compression */
73 DEFLATE ( empty_literal, DEFLATE_RAW,
74 DATA ( 0x01, 0x00, 0x00, 0xff, 0xff ), DATA() );
76 /* "iPXE" string, no compression */
77 DEFLATE ( literal, DEFLATE_RAW,
78 DATA ( 0x01, 0x04, 0x00, 0xfb, 0xff, 0x69, 0x50, 0x58, 0x45 ),
79 DATA ( 0x69, 0x50, 0x58, 0x45 ) );
81 /* "iPXE" string, no compression, split into two literals */
82 DEFLATE ( split_literal, DEFLATE_RAW,
83 DATA ( 0x00, 0x02, 0x00, 0xfd, 0xff, 0x69, 0x50, 0x01, 0x02, 0x00,
84 0xfd, 0xff, 0x58, 0x45 ),
85 DATA ( 0x69, 0x50, 0x58, 0x45 ) );
88 DEFLATE ( empty, DEFLATE_RAW, DATA ( 0x03, 0x00 ), DATA() );
91 DEFLATE ( hello_world, DEFLATE_RAW,
92 DATA ( 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca,
94 DATA ( 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c,
97 /* "Hello hello world" */
98 DEFLATE ( hello_hello_world, DEFLATE_RAW,
99 DATA ( 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0xc8, 0x00, 0x93, 0xe5,
100 0xf9, 0x45, 0x39, 0x29, 0x00 ),
101 DATA ( 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x68, 0x65, 0x6c, 0x6c,
102 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64 ) );
104 /* "This specification defines a lossless compressed data format" */
105 DEFLATE ( rfc_sentence, DEFLATE_RAW,
106 DATA ( 0x0d, 0xc6, 0xdb, 0x09, 0x00, 0x21, 0x0c, 0x04, 0xc0, 0x56,
107 0xb6, 0x28, 0x1b, 0x08, 0x79, 0x70, 0x01, 0x35, 0xe2, 0xa6,
108 0x7f, 0xce, 0xf9, 0x9a, 0xf1, 0x25, 0xc1, 0xe3, 0x9a, 0x91,
109 0x2a, 0x9d, 0xb5, 0x61, 0x1e, 0xb9, 0x9d, 0x10, 0xcc, 0x22,
110 0xa7, 0x93, 0xd0, 0x5a, 0xe7, 0xbe, 0xb8, 0xc1, 0xa4, 0x05,
111 0x51, 0x77, 0x49, 0xff ),
112 DATA ( 0x54, 0x68, 0x69, 0x73, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69,
113 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x64,
114 0x65, 0x66, 0x69, 0x6e, 0x65, 0x73, 0x20, 0x61, 0x20, 0x6c,
115 0x6f, 0x73, 0x73, 0x6c, 0x65, 0x73, 0x73, 0x20, 0x63, 0x6f,
116 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x64,
117 0x61, 0x74, 0x61, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74 ) );
119 /* "ZLIB Compressed Data Format Specification" */
120 DEFLATE ( zlib, DEFLATE_ZLIB,
121 DATA ( 0x78, 0x01, 0x8b, 0xf2, 0xf1, 0x74, 0x52, 0x70, 0xce, 0xcf,
122 0x2d, 0x28, 0x4a, 0x2d, 0x2e, 0x4e, 0x4d, 0x51, 0x70, 0x49,
123 0x2c, 0x49, 0x54, 0x70, 0xcb, 0x2f, 0xca, 0x4d, 0x2c, 0x51,
124 0x08, 0x2e, 0x48, 0x4d, 0xce, 0x4c, 0xcb, 0x4c, 0x4e, 0x2c,
125 0xc9, 0xcc, 0xcf, 0x03, 0x00, 0x2c, 0x0e, 0x0e, 0xeb ),
126 DATA ( 0x5a, 0x4c, 0x49, 0x42, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x72,
127 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x44, 0x61, 0x74, 0x61,
128 0x20, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x20, 0x53, 0x70,
129 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
132 /* "ZLIB Compressed Data Format Specification" fragment list */
133 static struct deflate_test_fragments zlib_fragments[] = {
135 { { 0, 1, 5, -1UL, } },
136 { { 0, 0, 1, 0, 0, 1, -1UL } },
137 { { 10, 8, 4, 7, 11, -1UL } },
143 * Report DEFLATE test result
145 * @v deflate Decompressor
146 * @v test Deflate test
147 * @v frags Fragment list, or NULL
148 * @v file Test code file
149 * @v line Test code line
151 static void deflate_okx ( struct deflate *deflate,
152 struct deflate_test *test,
153 struct deflate_test_fragments *frags,
154 const char *file, unsigned int line ) {
155 uint8_t data[ test->expected_len ];
156 struct deflate_chunk in;
157 struct deflate_chunk out;
158 size_t frag_len = -1UL;
160 size_t remaining = test->compressed_len;
163 /* Initialise decompressor */
164 deflate_init ( deflate, test->format );
166 /* Initialise output chunk */
167 deflate_chunk_init ( &out, virt_to_user ( data ), 0, sizeof ( data ) );
169 /* Process input (in fragments, if applicable) */
170 for ( i = 0 ; i < ( sizeof ( frags->len ) /
171 sizeof ( frags->len[0] ) ) ; i++ ) {
173 /* Initialise input chunk */
175 frag_len = frags->len[i];
176 if ( frag_len > remaining )
177 frag_len = remaining;
178 deflate_chunk_init ( &in, virt_to_user ( test->compressed ),
179 offset, ( offset + frag_len ) );
181 /* Decompress this fragment */
182 okx ( deflate_inflate ( deflate, &in, &out ) == 0, file, line );
183 okx ( in.len == ( offset + frag_len ), file, line );
184 okx ( in.offset == in.len, file, line );
186 /* Move to next fragment */
188 remaining -= frag_len;
192 /* Check that decompression has not terminated early */
193 okx ( ! deflate_finished ( deflate ), file, line );
196 /* Check decompression has terminated as expected */
197 okx ( deflate_finished ( deflate ), file, line );
198 okx ( offset == test->compressed_len, file, line );
199 okx ( out.offset == test->expected_len, file, line );
200 okx ( memcmp ( data, test->expected, test->expected_len ) == 0,
203 #define deflate_ok( deflate, test, frags ) \
204 deflate_okx ( deflate, test, frags, __FILE__, __LINE__ )
207 * Perform DEFLATE self-test
210 static void deflate_test_exec ( void ) {
211 struct deflate *deflate;
214 /* Allocate shared structure */
215 deflate = malloc ( sizeof ( *deflate ) );
216 ok ( deflate != NULL );
218 /* Perform self-tests */
221 /* Test as a single pass */
222 deflate_ok ( deflate, &empty_literal, NULL );
223 deflate_ok ( deflate, &literal, NULL );
224 deflate_ok ( deflate, &split_literal, NULL );
225 deflate_ok ( deflate, &empty, NULL );
226 deflate_ok ( deflate, &hello_world, NULL );
227 deflate_ok ( deflate, &hello_hello_world, NULL );
228 deflate_ok ( deflate, &rfc_sentence, NULL );
229 deflate_ok ( deflate, &zlib, NULL );
231 /* Test fragmentation */
232 for ( i = 0 ; i < ( sizeof ( zlib_fragments ) /
233 sizeof ( zlib_fragments[0] ) ) ; i++ ) {
234 deflate_ok ( deflate, &zlib, &zlib_fragments[i] );
238 /* Free shared structure */
242 /** DEFLATE self-test */
243 struct self_test deflate_test __self_test = {
245 .exec = deflate_test_exec,