iPXE
deflate_test.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
3  *
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.
8  *
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.
13  *
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
17  * 02110-1301, USA.
18  *
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.
22  */
23 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 
26 /** @file
27  *
28  * DEFLATE tests
29  *
30  */
31 
32 /* Forcibly enable assertions */
33 #undef NDEBUG
34 
35 #include <stdint.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <ipxe/deflate.h>
39 #include <ipxe/test.h>
40 
41 /** A DEFLATE test */
42 struct deflate_test {
43  /** Compression format */
45  /** Compressed data */
46  const void *compressed;
47  /** Length of compressed data */
49  /** Expected uncompressed data */
50  const void *expected;
51  /** Length of expected uncompressed data */
52  size_t expected_len;
53 };
54 
55 /** A DEFLATE fragment list */
57  /** Fragment lengths */
58  size_t len[8];
59 };
60 
61 /** Define inline data */
62 #define DATA(...) { __VA_ARGS__ }
63 
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 = { \
69  .format = FORMAT, \
70  .compressed = name ## _compressed, \
71  .compressed_len = sizeof ( name ## _compressed ), \
72  .expected = name ## _expected, \
73  .expected_len = sizeof ( name ## _expected ), \
74  };
75 
76 /* Empty file, no compression */
77 DEFLATE ( empty_literal, DEFLATE_RAW,
78  DATA ( 0x01, 0x00, 0x00, 0xff, 0xff ), DATA() );
79 
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 ) );
84 
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 ) );
90 
91 /* Empty file */
92 DEFLATE ( empty, DEFLATE_RAW, DATA ( 0x03, 0x00 ), DATA() );
93 
94 /* "Hello world" */
95 DEFLATE ( hello_world, DEFLATE_RAW,
96  DATA ( 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca,
97  0x49, 0x01, 0x00 ),
98  DATA ( 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c,
99  0x64 ) );
100 
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 ) );
107 
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 ) );
122 
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,
134  0x6e ) );
135 
136 /* "ZLIB Compressed Data Format Specification" fragment list */
138  { { -1UL, } },
139  { { 0, 1, 5, -1UL, } },
140  { { 0, 0, 1, 0, 0, 1, -1UL } },
141  { { 10, 8, 4, 7, 11, -1UL } },
142  { { 45, -1UL } },
143  { { 48, -1UL } },
144 };
145 
146 /**
147  * Report DEFLATE test result
148  *
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
154  */
155 static void deflate_okx ( struct deflate *deflate,
156  struct deflate_test *test,
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;
163  size_t offset = 0;
164  size_t remaining = test->compressed_len;
165  unsigned int i;
166 
167  /* Initialise decompressor */
168  deflate_init ( deflate, test->format );
169 
170  /* Initialise output chunk */
171  deflate_chunk_init ( &out, virt_to_user ( data ), 0, sizeof ( data ) );
172 
173  /* Process input (in fragments, if applicable) */
174  for ( i = 0 ; i < ( sizeof ( frags->len ) /
175  sizeof ( frags->len[0] ) ) ; i++ ) {
176 
177  /* Initialise input chunk */
178  if ( frags )
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 ) );
184 
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 );
189 
190  /* Move to next fragment */
191  offset = in.offset;
192  remaining -= frag_len;
193  if ( ! remaining )
194  break;
195 
196  /* Check that decompression has not terminated early */
197  okx ( ! deflate_finished ( deflate ), file, line );
198  }
199 
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,
205  file, line );
206 }
207 #define deflate_ok( deflate, test, frags ) \
208  deflate_okx ( deflate, test, frags, __FILE__, __LINE__ )
209 
210 /**
211  * Perform DEFLATE self-test
212  *
213  */
214 static void deflate_test_exec ( void ) {
215  struct deflate *deflate;
216  unsigned int i;
217 
218  /* Allocate shared structure */
219  deflate = malloc ( sizeof ( *deflate ) );
220  ok ( deflate != NULL );
221 
222  /* Perform self-tests */
223  if ( deflate ) {
224 
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 );
234 
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] );
239  }
240  }
241 
242  /* Free shared structure */
243  free ( deflate );
244 }
245 
246 /** DEFLATE self-test */
248  .name = "deflate",
249  .exec = deflate_test_exec,
250 };
int deflate_inflate(struct deflate *deflate, struct deflate_chunk *in, struct deflate_chunk *out)
Inflate compressed data.
Definition: deflate.c:492
__be32 in[4]
Definition: CIB_PRM.h:35
Self-test infrastructure.
const char * name
Test set name.
Definition: test.h:17
A self-test set.
Definition: test.h:15
__be32 out[4]
Definition: CIB_PRM.h:36
#define DEFLATE(name, FORMAT, COMPRESSED, EXPECTED)
Define a DEFLATE test.
Definition: deflate_test.c:65
struct velocity_frag frags[7]
Definition: velocity.h:14
A chunk of data.
Definition: deflate.h:241
void deflate_init(struct deflate *deflate, enum deflate_format format)
Initialise decompressor.
Definition: deflate.c:999
#define okx(success, file, line)
Report test result.
Definition: test.h:44
static int deflate_finished(struct deflate *deflate)
Check if decompression has finished.
Definition: deflate.h:273
static userptr_t size_t offset
Offset of the first segment within the content.
Definition: deflate.h:259
ZLIB header and footer.
Definition: deflate.h:21
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:54
deflate_format
Compression formats.
Definition: deflate.h:17
unsigned char uint8_t
Definition: stdint.h:10
void * malloc(size_t size)
Allocate memory.
Definition: malloc.c:583
const void * expected
Expected uncompressed data.
Definition: deflate_test.c:50
#define DATA(...)
Define inline data.
Definition: deflate_test.c:62
#define deflate_ok(deflate, test, frags)
Definition: deflate_test.c:207
const void * compressed
Compressed data.
Definition: deflate_test.c:46
Raw DEFLATE data (no header or footer)
Definition: deflate.h:19
static void deflate_okx(struct deflate *deflate, struct deflate_test *test, struct deflate_test_fragments *frags, const char *file, unsigned int line)
Report DEFLATE test result.
Definition: deflate_test.c:155
userptr_t virt_to_user(volatile const void *addr)
Convert virtual address to user pointer.
enum deflate_format format
Compression format.
Definition: deflate_test.c:44
uint8_t data[48]
Additional event data.
Definition: ena.h:22
size_t len[8]
Fragment lengths.
Definition: deflate_test.c:58
A DEFLATE fragment list.
Definition: deflate_test.c:56
DEFLATE decompression algorithm.
static struct deflate_test_fragments zlib_fragments[]
Definition: deflate_test.c:137
A DEFLATE test.
Definition: deflate_test.c:42
static void deflate_test_exec(void)
Perform DEFLATE self-test.
Definition: deflate_test.c:214
struct self_test deflate_test __self_test
DEFLATE self-test.
Definition: deflate_test.c:247
#define ok(success)
Definition: test.h:46
size_t expected_len
Length of expected uncompressed data.
Definition: deflate_test.c:52
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition: string.c:114
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
size_t compressed_len
Length of compressed data.
Definition: deflate_test.c:48
String functions.
static int test
Definition: epic100.c:73
Decompressor.
Definition: deflate.h:156