1 /**********************************************************************
2 Copyright(c) 2011-2016 Intel Corporation All rights reserved.
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in
11 the documentation and/or other materials provided with the
13 * Neither the name of Intel Corporation nor the names of its
14 contributors may be used to endorse or promote products derived
15 from this software without specific prior written permission.
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 **********************************************************************/
33 #include "igzip_lib.h"
34 #include "igzip_inflate_ref.h"
35 #include "crc_inflate.h"
42 # define TEST_SEED 0x1234
45 #define IBUF_SIZE (1024*1024)
47 #ifndef IGZIP_USE_GZIP_FORMAT
51 #define PAGE_SIZE 4*1024
53 #define str1 "Short test string"
54 #define str2 "one two three four five six seven eight nine ten eleven twelve " \
55 "thirteen fourteen fifteen sixteen"
57 #define TYPE0_HDR_SIZE 5 /* Size of a type 0 blocks header in bytes */
58 #define TYPE0_MAX_SIZE 65535 /* Max length of a type 0 block in bytes (excludes the header) */
61 /* Defines for the possible error conditions */
62 enum IGZIP_TEST_ERROR_CODES
{
68 COMPRESS_INCORRECT_STATE
,
69 COMPRESS_INPUT_STREAM_INTEGRITY_ERROR
,
70 COMPRESS_OUTPUT_STREAM_INTEGRITY_ERROR
,
71 COMPRESS_END_OF_STREAM_NOT_SET
,
72 COMPRESS_ALL_INPUT_FAIL
,
73 COMPRESS_OUT_BUFFER_OVERFLOW
,
74 COMPRESS_LOOP_COUNT_OVERFLOW
,
75 COMPRESS_GENERAL_ERROR
,
78 INFLATE_INVALID_BLOCK_HEADER
,
79 INFLATE_INVALID_SYMBOL
,
80 INFLATE_OUT_BUFFER_OVERFLOW
,
81 INFLATE_INVALID_NON_COMPRESSED_BLOCK_LENGTH
,
82 INFLATE_LEFTOVER_INPUT
,
83 INFLATE_INCORRECT_OUTPUT_SIZE
,
84 INFLATE_INVALID_LOOK_BACK_DISTANCE
,
86 INCORRECT_GZIP_TRAILER
,
87 INFLATE_GENERAL_ERROR
,
95 const int hdr_bytes
= 300;
98 const uint8_t gzip_hdr
[10] = {
99 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
103 const uint32_t gzip_hdr_bytes
= 10;
104 const uint32_t gzip_trl_bytes
= 8;
106 const int trl_bytes
= 8;
107 const int gzip_extra_bytes
= 18;
110 const int trl_bytes
= 0;
111 const int gzip_extra_bytes
= 0;
115 struct isal_hufftables
*hufftables
= NULL
;
117 #define HISTORY_SIZE 32*1024
121 /* Create random compressible data. This is achieved by randomly choosing a
122 * random character, or to repeat previous data in the stream for a random
123 * length and look back distance. The probability of a random character or a
124 * repeat being chosen is semi-randomly chosen by setting max_repeat_data to be
125 * differing values */
126 void create_rand_repeat_data(uint8_t * data
, int size
)
129 uint8_t *data_start
= data
;
130 uint32_t length
, distance
;
131 uint32_t max_repeat_data
= 256;
132 uint32_t power
= rand() % 32;
133 /* An array of the powers of 2 (except the final element which is 0) */
134 const uint32_t power_of_2_array
[] = {
135 0x00000001, 0x00000002, 0x00000004, 0x00000008,
136 0x00000010, 0x00000020, 0x00000040, 0x00000080,
137 0x00000100, 0x00000200, 0x00000400, 0x00000800,
138 0x00001000, 0x00002000, 0x00004000, 0x00008000,
139 0x00010000, 0x00020000, 0x00040000, 0x00080000,
140 0x00100000, 0x00200000, 0x00400000, 0x00800000,
141 0x01000000, 0x02000000, 0x04000000, 0x08000000,
142 0x10000000, 0x20000000, 0x40000000, 0x00000000
145 max_repeat_data
+= power_of_2_array
[power
];
151 next_data
= rand() % max_repeat_data
;
152 if (next_data
< 256) {
155 } else if (size
< 3) {
156 *data
++ = rand() % 256;
159 length
= (rand() % 256) + MIN_LENGTH
;
161 length
= (rand() % (size
- 2)) + MIN_LENGTH
;
163 distance
= (rand() % HISTORY_SIZE
) + MIN_DIST
;
164 if (distance
> data
- data_start
)
165 distance
= (rand() % (data
- data_start
)) + MIN_DIST
;
168 if (distance
<= length
) {
169 while (length
-- > 0) {
170 *data
= *(data
- distance
);
174 memcpy(data
, data
- distance
, length
);
179 void print_error(int error_code
)
181 switch (error_code
) {
185 printf("error: failed to allocate memory\n");
187 case FILE_READ_FAILED
:
188 printf("error: failed to read in file\n");
190 case COMPRESS_INCORRECT_STATE
:
191 printf("error: incorrect stream internal state\n");
193 case COMPRESS_INPUT_STREAM_INTEGRITY_ERROR
:
194 printf("error: inconsistent stream input buffer\n");
196 case COMPRESS_OUTPUT_STREAM_INTEGRITY_ERROR
:
197 printf("error: inconsistent stream output buffer\n");
199 case COMPRESS_END_OF_STREAM_NOT_SET
:
200 printf("error: end of stream not set\n");
202 case COMPRESS_ALL_INPUT_FAIL
:
203 printf("error: not all input data compressed\n");
205 case COMPRESS_OUT_BUFFER_OVERFLOW
:
206 printf("error: output buffer overflow while compressing data\n");
208 case COMPRESS_GENERAL_ERROR
:
209 printf("error: compression failed\n");
211 case INFLATE_END_OF_INPUT
:
212 printf("error: did not decompress all input\n");
214 case INFLATE_INVALID_BLOCK_HEADER
:
215 printf("error: invalid header\n");
217 case INFLATE_INVALID_SYMBOL
:
218 printf("error: invalid symbol found when decompressing input\n");
220 case INFLATE_OUT_BUFFER_OVERFLOW
:
221 printf("error: output buffer overflow while decompressing data\n");
223 case INFLATE_INVALID_NON_COMPRESSED_BLOCK_LENGTH
:
224 printf("error: invalid length bits in non-compressed block\n");
226 case INFLATE_GENERAL_ERROR
:
227 printf("error: decompression failed\n");
229 case INFLATE_LEFTOVER_INPUT
:
230 printf("error: the trailer of igzip output contains junk\n");
232 case INFLATE_INCORRECT_OUTPUT_SIZE
:
233 printf("error: incorrect amount of data was decompressed\n");
235 case INFLATE_INVALID_LOOK_BACK_DISTANCE
:
236 printf("error: invalid look back distance found while decompressing\n");
238 case INVALID_GZIP_HEADER
:
239 printf("error: incorrect gzip header found when inflating data\n");
241 case INCORRECT_GZIP_TRAILER
:
242 printf("error: incorrect gzip trailer found when inflating data\n");
244 case INVALID_FLUSH_ERROR
:
245 printf("error: invalid flush did not cause compression to error\n");
248 printf("error: decompressed data is not the same as the compressed data\n");
250 case OVERFLOW_TEST_ERROR
:
251 printf("error: overflow undetected\n");
254 printf("error: unknown error code\n");
258 void print_uint8_t(uint8_t * array
, uint64_t length
)
260 const int line_size
= 16;
263 printf("Length = %lu", length
);
264 for (i
= 0; i
< length
; i
++) {
265 if ((i
% line_size
) == 0)
266 printf("\n0x%08x\t", i
);
269 printf("0x%02x,", array
[i
]);
275 uint32_t check_gzip_header(uint8_t * z_buf
)
277 /* These values are defined in RFC 1952 page 4 */
278 const uint8_t ID1
= 0x1f, ID2
= 0x8b, CM
= 0x08, FLG
= 0;
281 /* Verify that the gzip header is the one used in hufftables_c.c */
282 for (i
= 0; i
< gzip_hdr_bytes
; i
++)
283 if (z_buf
[i
] != gzip_hdr
[i
])
284 ret
= INVALID_GZIP_HEADER
;
286 /* Verify that the gzip header is a valid gzip header */
288 ret
= INVALID_GZIP_HEADER
;
291 ret
= INVALID_GZIP_HEADER
;
293 /* Verfiy compression method is Deflate */
295 ret
= INVALID_GZIP_HEADER
;
297 /* The following comparison is specific to how gzip headers are written in igzip */
298 /* Verify no extra flags are set */
300 ret
= INVALID_GZIP_HEADER
;
302 /* The last 6 bytes in the gzip header do not contain any information
303 * important to decomrpessing the data */
308 uint32_t check_gzip_trl(struct inflate_state
* gstream
)
310 uint8_t *index
= NULL
;
311 uint32_t crc
, ret
= 0;
313 index
= gstream
->out_buffer
.next_out
- gstream
->out_buffer
.total_out
;
314 crc
= find_crc(index
, gstream
->out_buffer
.total_out
);
316 if (gstream
->out_buffer
.total_out
!= *(uint32_t *) (gstream
->in_buffer
.next_in
+ 4) ||
317 crc
!= *(uint32_t *) gstream
->in_buffer
.next_in
)
318 ret
= INCORRECT_GZIP_TRAILER
;
324 /* Inflate the compressed data and check that the decompressed data agrees with the input data */
325 int inflate_check(uint8_t * z_buf
, int z_size
, uint8_t * in_buf
, int in_size
)
327 /* Test inflate with reference inflate */
330 struct inflate_state gstream
;
331 uint32_t test_size
= in_size
;
332 uint8_t *test_buf
= NULL
;
336 assert(in_buf
!= NULL
);
337 test_buf
= malloc(test_size
);
339 if (test_buf
== NULL
)
340 return MALLOC_FAILED
;
342 if (test_buf
!= NULL
)
343 memset(test_buf
, 0xff, test_size
);
346 int gzip_hdr_result
, gzip_trl_result
;
348 gzip_hdr_result
= check_gzip_header(z_buf
);
349 z_buf
+= gzip_hdr_bytes
;
350 z_size
-= gzip_hdr_bytes
;
353 igzip_inflate_init(&gstream
, z_buf
, z_size
, test_buf
, test_size
);
354 ret
= igzip_inflate(&gstream
);
356 if (test_buf
!= NULL
)
357 mem_result
= memcmp(in_buf
, test_buf
, in_size
);
362 for (i
= 0; i
< in_size
; i
++) {
363 if (in_buf
[i
] != test_buf
[i
]) {
364 printf("First incorrect data at 0x%x of 0x%x, 0x%x != 0x%x\n",
365 i
, in_size
, in_buf
[i
], test_buf
[i
]);
372 gzip_trl_result
= check_gzip_trl(&gstream
);
373 gstream
.in_buffer
.avail_in
-= gzip_trl_bytes
;
374 gstream
.in_buffer
.next_in
+= gzip_trl_bytes
;
377 if (test_buf
!= NULL
)
384 return INFLATE_END_OF_INPUT
;
386 case INVALID_BLOCK_HEADER
:
387 return INFLATE_INVALID_BLOCK_HEADER
;
390 return INFLATE_INVALID_SYMBOL
;
392 case OUT_BUFFER_OVERFLOW
:
393 return INFLATE_OUT_BUFFER_OVERFLOW
;
395 case INVALID_NON_COMPRESSED_BLOCK_LENGTH
:
396 return INFLATE_INVALID_NON_COMPRESSED_BLOCK_LENGTH
;
398 case INVALID_LOOK_BACK_DISTANCE
:
399 return INFLATE_INVALID_LOOK_BACK_DISTANCE
;
402 return INFLATE_GENERAL_ERROR
;
406 if (gstream
.in_buffer
.avail_in
!= 0)
407 return INFLATE_LEFTOVER_INPUT
;
409 if (gstream
.out_buffer
.total_out
!= in_size
)
410 return INFLATE_INCORRECT_OUTPUT_SIZE
;
417 return INVALID_GZIP_HEADER
;
420 return INCORRECT_GZIP_TRAILER
;
426 /* Check if that the state of the data stream is consistent */
427 int stream_valid_check(struct isal_zstream
*stream
, uint8_t * in_buf
, uint32_t in_size
,
428 uint8_t * out_buf
, uint32_t out_size
, uint32_t in_processed
,
429 uint32_t out_processed
, uint32_t data_size
)
431 uint32_t total_in
, in_buffer_size
, total_out
, out_buffer_size
;
435 0) ? in_processed
: (in_processed
- in_size
) + (stream
->next_in
- in_buf
);
436 in_buffer_size
= (in_size
== 0) ? 0 : stream
->next_in
- in_buf
+ stream
->avail_in
;
438 /* Check for a consistent amount of data processed */
439 if (total_in
!= stream
->total_in
|| in_buffer_size
!= in_size
)
440 return COMPRESS_INPUT_STREAM_INTEGRITY_ERROR
;
443 (out_size
== 0) ? out_processed
: out_processed
+ (stream
->next_out
- out_buf
);
444 out_buffer_size
= (out_size
== 0) ? 0 : stream
->next_out
- out_buf
+ stream
->avail_out
;
446 /* Check for a consistent amount of data compressed */
447 if (total_out
!= stream
->total_out
|| out_buffer_size
!= out_size
) {
448 return COMPRESS_OUTPUT_STREAM_INTEGRITY_ERROR
;
454 /* Performs compression with checks to discover and verify the state of the
456 * stream: compress data structure which has been initialized to use
457 * in_buf and out_buf as the buffers
458 * data_size: size of all input data
459 * compressed_size: size of all available output buffers
460 * in_buf: next buffer of data to be compressed
461 * in_size: size of in_buf
462 * out_buf: next out put buffer where data is stored
463 * out_size: size of out_buf
464 * in_processed: the amount of input data which has been loaded into buffers
465 * to be compressed, this includes the data in in_buf
466 * out_processed: the amount of output data which has been compressed and stored,
467 * this does not include the data in the current out_buf
469 int isal_deflate_with_checks(struct isal_zstream
*stream
, uint32_t data_size
,
470 uint32_t compressed_size
, uint8_t * in_buf
, uint32_t in_size
,
471 uint32_t in_processed
, uint8_t * out_buf
, uint32_t out_size
,
472 uint32_t out_processed
)
474 int ret
, stream_check
;
475 struct isal_zstate
*state
= &stream
->internal_state
;
478 printf("Pre compression\n");
480 ("data_size = 0x%05x, in_processed = 0x%05x, in_size = 0x%05x, avail_in = 0x%05x, total_in = 0x%05x\n",
481 data_size
, in_processed
, in_size
, stream
->avail_in
, stream
->total_in
);
483 ("compressed_size = 0x%05x, out_processed = 0x%05x, out_size = 0x%05x, avail_out = 0x%05x, total_out = 0x%05x\n",
484 compressed_size
, out_processed
, out_size
, stream
->avail_out
, stream
->total_out
);
487 ret
= isal_deflate(stream
);
490 printf("Post compression\n");
492 ("data_size = 0x%05x, in_processed = 0x%05x, in_size = 0x%05x, avail_in = 0x%05x, total_in = 0x%05x\n",
493 data_size
, in_processed
, in_size
, stream
->avail_in
, stream
->total_in
);
495 ("compressed_size = 0x%05x, out_processed = 0x%05x, out_size = 0x%05x, avail_out = 0x%05x, total_out = 0x%05x\n",
496 compressed_size
, out_processed
, out_size
, stream
->avail_out
, stream
->total_out
);
500 /* Verify the stream is in a valid state */
501 stream_check
= stream_valid_check(stream
, in_buf
, in_size
, out_buf
, out_size
,
502 in_processed
, out_processed
, data_size
);
504 if (stream_check
!= 0)
507 if (ret
!= IGZIP_COMP_OK
)
508 return COMPRESS_GENERAL_ERROR
;
510 /* Check if the compression is completed */
511 if (state
->state
!= ZSTATE_END
)
512 if (compressed_size
- out_processed
- (out_size
- stream
->avail_out
) <= 0)
513 return COMPRESS_OUT_BUFFER_OVERFLOW
;
519 /* Compress the input data into the output buffer where the input buffer and
520 * output buffer are randomly segmented to test state information for the
522 int compress_multi_pass(uint8_t * data
, uint32_t data_size
, uint8_t * compressed_buf
,
523 uint32_t * compressed_size
, uint32_t flush_type
)
525 int ret
= IGZIP_COMP_OK
;
526 uint8_t *in_buf
= NULL
, *out_buf
= NULL
;
527 uint32_t in_size
= 0, out_size
= 0;
528 uint32_t in_processed
= 0, out_processed
= 0;
529 struct isal_zstream stream
;
530 struct isal_zstate
*state
= &stream
.internal_state
;
531 uint32_t loop_count
= 0;
534 printf("Starting Compress Multi Pass\n");
537 create_rand_repeat_data((uint8_t *) & stream
, sizeof(stream
));
539 isal_deflate_init(&stream
);
541 if (hufftables
!= NULL
)
542 stream
.hufftables
= hufftables
;
544 if (state
->state
!= ZSTATE_NEW_HDR
)
545 return COMPRESS_INCORRECT_STATE
;
547 stream
.flush
= flush_type
;
548 stream
.end_of_stream
= 0;
550 /* These are set here to allow the loop to run correctly */
552 stream
.avail_out
= 0;
557 /* Setup in buffer for next round of compression */
558 if (stream
.avail_in
== 0) {
559 if (flush_type
== NO_FLUSH
|| state
->state
== ZSTATE_NEW_HDR
) {
560 /* Randomly choose size of the next out buffer */
561 in_size
= rand() % (data_size
+ 1);
563 /* Limit size of buffer to be smaller than maximum */
564 if (in_size
>= data_size
- in_processed
) {
565 in_size
= data_size
- in_processed
;
566 stream
.end_of_stream
= 1;
570 if (in_buf
!= NULL
) {
575 in_buf
= malloc(in_size
);
576 if (in_buf
== NULL
) {
580 memcpy(in_buf
, data
+ in_processed
, in_size
);
581 in_processed
+= in_size
;
583 stream
.avail_in
= in_size
;
584 stream
.next_in
= in_buf
;
589 /* Setup out buffer for next round of compression */
590 if (stream
.avail_out
== 0) {
591 /* Save compressed data inot compressed_buf */
592 if (out_buf
!= NULL
) {
593 memcpy(compressed_buf
+ out_processed
, out_buf
,
594 out_size
- stream
.avail_out
);
595 out_processed
+= out_size
- stream
.avail_out
;
598 /* Randomly choose size of the next out buffer */
599 out_size
= rand() % (*compressed_size
+ 1);
601 /* Limit size of buffer to be smaller than maximum */
602 if (out_size
> *compressed_size
- out_processed
)
603 out_size
= *compressed_size
- out_processed
;
606 if (out_buf
!= NULL
) {
611 out_buf
= malloc(out_size
);
612 if (out_buf
== NULL
) {
617 stream
.avail_out
= out_size
;
618 stream
.next_out
= out_buf
;
623 isal_deflate_with_checks(&stream
, data_size
, *compressed_size
, in_buf
,
624 in_size
, in_processed
, out_buf
, out_size
,
628 if (ret
== COMPRESS_OUT_BUFFER_OVERFLOW
629 || ret
== COMPRESS_INCORRECT_STATE
)
630 memcpy(compressed_buf
+ out_processed
, out_buf
, out_size
);
634 /* Check if the compression is completed */
635 if (state
->state
== ZSTATE_END
) {
636 memcpy(compressed_buf
+ out_processed
, out_buf
, out_size
);
637 *compressed_size
= stream
.total_out
;
648 if (ret
== COMPRESS_OUT_BUFFER_OVERFLOW
&& flush_type
== SYNC_FLUSH
649 && loop_count
>= MAX_LOOPS
)
650 ret
= COMPRESS_LOOP_COUNT_OVERFLOW
;
656 /* Compress the input data into the outbuffer in one call to isal_deflate */
657 int compress_single_pass(uint8_t * data
, uint32_t data_size
, uint8_t * compressed_buf
,
658 uint32_t * compressed_size
, uint32_t flush_type
)
660 int ret
= IGZIP_COMP_OK
;
661 struct isal_zstream stream
;
662 struct isal_zstate
*state
= &stream
.internal_state
;
665 printf("Starting Compress Single Pass\n");
668 create_rand_repeat_data((uint8_t *) & stream
, sizeof(stream
));
670 isal_deflate_init(&stream
);
672 if (hufftables
!= NULL
)
673 stream
.hufftables
= hufftables
;
675 if (state
->state
!= ZSTATE_NEW_HDR
)
676 return COMPRESS_INCORRECT_STATE
;
678 stream
.flush
= flush_type
;
679 stream
.avail_in
= data_size
;
680 stream
.next_in
= data
;
681 stream
.avail_out
= *compressed_size
;
682 stream
.next_out
= compressed_buf
;
683 stream
.end_of_stream
= 1;
686 isal_deflate_with_checks(&stream
, data_size
, *compressed_size
, data
, data_size
,
687 data_size
, compressed_buf
, *compressed_size
, 0);
689 /* Check if the compression is completed */
690 if (state
->state
== ZSTATE_END
)
691 *compressed_size
= stream
.total_out
;
692 else if (flush_type
== SYNC_FLUSH
&& stream
.avail_out
< 16)
693 ret
= COMPRESS_OUT_BUFFER_OVERFLOW
;
699 /* Statelessly compress the input buffer into the output buffer */
700 int compress_stateless(uint8_t * data
, uint32_t data_size
, uint8_t * compressed_buf
,
701 uint32_t * compressed_size
)
703 int ret
= IGZIP_COMP_OK
;
704 struct isal_zstream stream
;
706 create_rand_repeat_data((uint8_t *) & stream
, sizeof(stream
));
708 isal_deflate_init(&stream
);
710 if (hufftables
!= NULL
)
711 stream
.hufftables
= hufftables
;
713 stream
.avail_in
= data_size
;
714 stream
.end_of_stream
= 1;
715 stream
.next_in
= data
;
716 stream
.flush
= NO_FLUSH
;
718 stream
.avail_out
= *compressed_size
;
719 stream
.next_out
= compressed_buf
;
721 ret
= isal_deflate_stateless(&stream
);
723 /* verify the stream */
724 if (stream
.next_in
- data
!= stream
.total_in
||
725 stream
.total_in
+ stream
.avail_in
!= data_size
)
726 return COMPRESS_INPUT_STREAM_INTEGRITY_ERROR
;
728 if (stream
.next_out
- compressed_buf
!= stream
.total_out
||
729 stream
.total_out
+ stream
.avail_out
!= *compressed_size
)
730 return COMPRESS_OUTPUT_STREAM_INTEGRITY_ERROR
;
732 if (ret
!= IGZIP_COMP_OK
) {
733 if (ret
== STATELESS_OVERFLOW
)
734 return COMPRESS_OUT_BUFFER_OVERFLOW
;
736 return COMPRESS_GENERAL_ERROR
;
739 if (!stream
.end_of_stream
) {
740 return COMPRESS_END_OF_STREAM_NOT_SET
;
743 if (stream
.avail_in
!= 0)
744 return COMPRESS_ALL_INPUT_FAIL
;
746 *compressed_size
= stream
.total_out
;
752 /* Compress the input data into the output buffer where the input buffer and
753 * is randomly segmented to test for independence of blocks in full flush
755 int compress_full_flush(uint8_t * data
, uint32_t data_size
, uint8_t * compressed_buf
,
756 uint32_t * compressed_size
)
758 int ret
= IGZIP_COMP_OK
;
759 uint8_t *in_buf
= NULL
, *out_buf
= compressed_buf
;
760 uint32_t in_size
= 0;
761 uint32_t in_processed
= 00;
762 struct isal_zstream stream
;
763 struct isal_zstate
*state
= &stream
.internal_state
;
764 uint32_t loop_count
= 0;
767 printf("Starting Compress Full Flush\n");
770 create_rand_repeat_data((uint8_t *) & stream
, sizeof(stream
));
772 isal_deflate_init(&stream
);
774 if (hufftables
!= NULL
)
775 stream
.hufftables
= hufftables
;
777 if (state
->state
!= ZSTATE_NEW_HDR
)
778 return COMPRESS_INCORRECT_STATE
;
780 stream
.flush
= FULL_FLUSH
;
781 stream
.end_of_stream
= 0;
782 stream
.avail_out
= *compressed_size
;
783 stream
.next_out
= compressed_buf
;
784 stream
.total_out
= 0;
789 /* Setup in buffer for next round of compression */
790 if (state
->state
== ZSTATE_NEW_HDR
) {
791 /* Randomly choose size of the next out buffer */
792 in_size
= rand() % (data_size
+ 1);
794 /* Limit size of buffer to be smaller than maximum */
795 if (in_size
>= data_size
- in_processed
) {
796 in_size
= data_size
- in_processed
;
797 stream
.end_of_stream
= 1;
800 stream
.avail_in
= in_size
;
803 if (in_buf
!= NULL
) {
808 in_buf
= malloc(in_size
);
809 if (in_buf
== NULL
) {
813 memcpy(in_buf
, data
+ in_processed
, in_size
);
814 in_processed
+= in_size
;
816 stream
.next_in
= in_buf
;
819 out_buf
= stream
.next_out
;
822 ret
= isal_deflate(&stream
);
827 /* Verify that blocks are independent */
828 if (state
->state
== ZSTATE_NEW_HDR
|| state
->state
== ZSTATE_END
) {
830 inflate_check(out_buf
, stream
.next_out
- out_buf
, in_buf
, in_size
);
832 if (ret
== INFLATE_INVALID_LOOK_BACK_DISTANCE
)
838 /* Check if the compression is completed */
839 if (state
->state
== ZSTATE_END
) {
840 *compressed_size
= stream
.total_out
;
849 if (ret
== COMPRESS_OUT_BUFFER_OVERFLOW
&& loop_count
>= MAX_LOOPS
)
850 ret
= COMPRESS_LOOP_COUNT_OVERFLOW
;
856 /*Compress the input buffer into the output buffer, but switch the flush type in
857 * the middle of the compression to test what happens*/
858 int compress_swap_flush(uint8_t * data
, uint32_t data_size
, uint8_t * compressed_buf
,
859 uint32_t * compressed_size
, uint32_t flush_type
)
861 int ret
= IGZIP_COMP_OK
;
862 struct isal_zstream stream
;
863 struct isal_zstate
*state
= &stream
.internal_state
;
864 uint32_t partial_size
;
867 printf("Starting Compress Swap Flush\n");
870 isal_deflate_init(&stream
);
872 if (hufftables
!= NULL
)
873 stream
.hufftables
= hufftables
;
875 if (state
->state
!= ZSTATE_NEW_HDR
)
876 return COMPRESS_INCORRECT_STATE
;
878 partial_size
= rand() % (data_size
+ 1);
880 stream
.flush
= flush_type
;
881 stream
.avail_in
= partial_size
;
882 stream
.next_in
= data
;
883 stream
.avail_out
= *compressed_size
;
884 stream
.next_out
= compressed_buf
;
885 stream
.end_of_stream
= 0;
888 isal_deflate_with_checks(&stream
, data_size
, *compressed_size
, data
, partial_size
,
889 partial_size
, compressed_buf
, *compressed_size
, 0);
894 flush_type
= rand() % 3;
896 stream
.flush
= flush_type
;
897 stream
.avail_in
= data_size
- partial_size
;
898 stream
.next_in
= data
+ partial_size
;
899 stream
.end_of_stream
= 1;
902 isal_deflate_with_checks(&stream
, data_size
, *compressed_size
, data
+ partial_size
,
903 data_size
- partial_size
, data_size
, compressed_buf
,
904 *compressed_size
, 0);
906 if (ret
== COMPRESS_GENERAL_ERROR
)
907 return INVALID_FLUSH_ERROR
;
909 *compressed_size
= stream
.total_out
;
914 /* Test deflate_stateless */
915 int test_compress_stateless(uint8_t * in_data
, uint32_t in_size
)
917 int ret
= IGZIP_COMP_OK
;
918 uint32_t z_size
, overflow
;
919 uint8_t *z_buf
= NULL
;
920 uint8_t *in_buf
= NULL
;
923 in_buf
= malloc(in_size
);
926 return MALLOC_FAILED
;
928 memcpy(in_buf
, in_data
, in_size
);
931 /* Test non-overflow case where a type 0 block is not written */
932 z_size
= 2 * in_size
+ hdr_bytes
+ trl_bytes
;
934 z_buf
= malloc(z_size
);
937 return MALLOC_FAILED
;
939 create_rand_repeat_data(z_buf
, z_size
);
941 ret
= compress_stateless(in_buf
, in_size
, z_buf
, &z_size
);
944 ret
= inflate_check(z_buf
, z_size
, in_buf
, in_size
);
948 printf("Compressed array: ");
949 print_uint8_t(z_buf
, z_size
);
952 print_uint8_t(in_buf
, in_size
);
963 /*Test non-overflow case where a type 0 block is possible to be written */
965 TYPE0_HDR_SIZE
* ((in_size
+ TYPE0_MAX_SIZE
- 1) / TYPE0_MAX_SIZE
) + in_size
+
968 if (z_size
== gzip_extra_bytes
)
969 z_size
+= TYPE0_HDR_SIZE
;
974 z_buf
= malloc(z_size
);
977 return MALLOC_FAILED
;
979 create_rand_repeat_data(z_buf
, z_size
);
981 ret
= compress_stateless(in_buf
, in_size
, z_buf
, &z_size
);
983 ret
= inflate_check(z_buf
, z_size
, in_buf
, in_size
);
986 printf("Compressed array: ");
987 print_uint8_t(z_buf
, z_size
);
990 print_uint8_t(in_buf
, in_size
);
998 /* Test random overflow case */
999 z_size
= rand() % z_size
;
1001 if (z_size
> in_size
)
1002 z_size
= rand() & in_size
;
1005 z_buf
= malloc(z_size
);
1008 return MALLOC_FAILED
;
1011 overflow
= compress_stateless(in_buf
, in_size
, z_buf
, &z_size
);
1013 if (overflow
!= COMPRESS_OUT_BUFFER_OVERFLOW
) {
1015 printf("overflow error = %d\n", overflow
);
1016 print_error(overflow
);
1017 if (overflow
== 0) {
1018 overflow
= inflate_check(z_buf
, z_size
, in_buf
, in_size
);
1019 printf("inflate ret = %d\n", overflow
);
1020 print_error(overflow
);
1022 printf("Compressed array: ");
1023 print_uint8_t(z_buf
, z_size
);
1026 print_uint8_t(in_buf
, in_size
);
1028 ret
= OVERFLOW_TEST_ERROR
;
1044 int test_compress(uint8_t * in_buf
, uint32_t in_size
, uint32_t flush_type
)
1046 int ret
= IGZIP_COMP_OK
, fin_ret
= IGZIP_COMP_OK
;
1047 uint32_t overflow
= 0;
1048 uint32_t z_size
, z_size_max
, z_compressed_size
;
1049 uint8_t *z_buf
= NULL
;
1051 /* Test a non overflow case */
1052 if (flush_type
== NO_FLUSH
)
1053 z_size_max
= 2 * in_size
+ hdr_bytes
+ trl_bytes
+ 2;
1054 else if (flush_type
== SYNC_FLUSH
|| flush_type
== FULL_FLUSH
)
1055 z_size_max
= 2 * in_size
+ MAX_LOOPS
* (hdr_bytes
+ trl_bytes
+ 5);
1057 printf("Invalid Flush Parameter\n");
1058 return COMPRESS_GENERAL_ERROR
;
1061 z_size
= z_size_max
;
1063 z_buf
= malloc(z_size
);
1064 if (z_buf
== NULL
) {
1065 print_error(MALLOC_FAILED
);
1066 return MALLOC_FAILED
;
1068 create_rand_repeat_data(z_buf
, z_size_max
);
1070 ret
= compress_single_pass(in_buf
, in_size
, z_buf
, &z_size
, flush_type
);
1073 ret
= inflate_check(z_buf
, z_size
, in_buf
, in_size
);
1077 printf("Compressed array: ");
1078 print_uint8_t(z_buf
, z_size
);
1081 print_uint8_t(in_buf
, in_size
);
1083 printf("Failed on compress single pass\n");
1089 z_compressed_size
= z_size
;
1090 z_size
= z_size_max
;
1091 create_rand_repeat_data(z_buf
, z_size_max
);
1093 ret
= compress_multi_pass(in_buf
, in_size
, z_buf
, &z_size
, flush_type
);
1096 ret
= inflate_check(z_buf
, z_size
, in_buf
, in_size
);
1100 printf("Compressed array: ");
1101 print_uint8_t(z_buf
, z_size
);
1104 print_uint8_t(in_buf
, in_size
);
1106 printf("Failed on compress multi pass\n");
1114 /* Test random overflow case */
1115 if (flush_type
== SYNC_FLUSH
&& z_compressed_size
> in_size
)
1116 z_compressed_size
= in_size
+ 1;
1118 z_size
= rand() % z_compressed_size
;
1119 create_rand_repeat_data(z_buf
, z_size_max
);
1121 overflow
= compress_single_pass(in_buf
, in_size
, z_buf
, &z_size
, flush_type
);
1123 if (overflow
!= COMPRESS_OUT_BUFFER_OVERFLOW
) {
1125 ret
= inflate_check(z_buf
, z_size
, in_buf
, in_size
);
1127 /* Rarely single pass overflow will compresses data
1128 * better than the initial run. This is to stop that
1129 * case from erroring. */
1130 if (overflow
!= 0 || ret
!= 0) {
1132 printf("overflow error = %d\n", overflow
);
1133 print_error(overflow
);
1134 printf("inflate ret = %d\n", ret
);
1135 print_error(overflow
);
1137 printf("Compressed array: ");
1138 print_uint8_t(z_buf
, z_size
);
1141 print_uint8_t(in_buf
, in_size
);
1143 printf("Failed on compress multi pass overflow\n");
1145 ret
= OVERFLOW_TEST_ERROR
;
1151 if (flush_type
== NO_FLUSH
) {
1152 create_rand_repeat_data(z_buf
, z_size_max
);
1154 overflow
= compress_multi_pass(in_buf
, in_size
, z_buf
, &z_size
, flush_type
);
1156 if (overflow
!= COMPRESS_OUT_BUFFER_OVERFLOW
) {
1158 ret
= inflate_check(z_buf
, z_size
, in_buf
, in_size
);
1160 /* Rarely multi pass overflow will compresses data
1161 * better than the initial run. This is to stop that
1162 * case from erroring */
1163 if (overflow
!= 0 || ret
!= 0) {
1165 printf("overflow error = %d\n", overflow
);
1166 print_error(overflow
);
1167 printf("inflate ret = %d\n", ret
);
1168 print_error(overflow
);
1170 printf("Compressed array: ");
1171 print_uint8_t(z_buf
, z_size
);
1174 print_uint8_t(in_buf
, in_size
);
1176 printf("Failed on compress multi pass overflow\n");
1178 ret
= OVERFLOW_TEST_ERROR
;
1189 /* Test swapping flush types in the middle of compression */
1190 int test_flush(uint8_t * in_buf
, uint32_t in_size
)
1192 int fin_ret
= IGZIP_COMP_OK
, ret
;
1193 uint32_t z_size
, flush_type
= 0;
1194 uint8_t *z_buf
= NULL
;
1196 z_size
= 2 * in_size
+ 2 * (hdr_bytes
+ trl_bytes
) + 8;
1198 z_buf
= malloc(z_size
);
1201 return MALLOC_FAILED
;
1203 create_rand_repeat_data(z_buf
, z_size
);
1205 while (flush_type
< 3)
1206 flush_type
= rand();
1208 /* Test invalid flush */
1209 ret
= compress_single_pass(in_buf
, in_size
, z_buf
, &z_size
, flush_type
);
1211 if (ret
== COMPRESS_GENERAL_ERROR
)
1214 printf("Failed when passing invalid flush parameter\n");
1215 ret
= INVALID_FLUSH_ERROR
;
1221 create_rand_repeat_data(z_buf
, z_size
);
1223 /* Test swapping flush type */
1224 ret
= compress_swap_flush(in_buf
, in_size
, z_buf
, &z_size
, rand() % 3);
1227 ret
= inflate_check(z_buf
, z_size
, in_buf
, in_size
);
1231 printf("Compressed array: ");
1232 print_uint8_t(z_buf
, z_size
);
1235 print_uint8_t(in_buf
, in_size
);
1237 printf("Failed on swapping flush type\n");
1247 /* Test there are no length distance pairs across full flushes */
1248 int test_full_flush(uint8_t * in_buf
, uint32_t in_size
)
1250 int ret
= IGZIP_COMP_OK
;
1252 uint8_t *z_buf
= NULL
;
1254 z_size
= 2 * in_size
+ MAX_LOOPS
* (hdr_bytes
+ trl_bytes
+ 5);
1256 z_buf
= malloc(z_size
);
1257 if (z_buf
== NULL
) {
1258 print_error(MALLOC_FAILED
);
1259 return MALLOC_FAILED
;
1262 create_rand_repeat_data(z_buf
, z_size
);
1264 ret
= compress_full_flush(in_buf
, in_size
, z_buf
, &z_size
);
1267 ret
= inflate_check(z_buf
, z_size
, in_buf
, in_size
);
1271 printf("Compressed array: ");
1272 print_uint8_t(z_buf
, z_size
);
1275 print_uint8_t(in_buf
, in_size
);
1277 printf("Failed on compress multi pass\n");
1286 int get_filesize(FILE * f
)
1290 curr
= ftell(f
); /* Save current position */
1291 fseek(f
, 0L, SEEK_END
);
1293 fseek(f
, curr
, SEEK_SET
); /* Restore position */
1297 /* Run multiple compression tests on data stored in a file */
1298 int test_compress_file(char *file_name
)
1300 int ret
= IGZIP_COMP_OK
;
1302 uint8_t *in_buf
= NULL
;
1303 FILE *in_file
= NULL
;
1305 in_file
= fopen(file_name
, "rb");
1307 return FILE_READ_FAILED
;
1309 in_size
= get_filesize(in_file
);
1311 in_buf
= malloc(in_size
);
1313 return MALLOC_FAILED
;
1314 fread(in_buf
, 1, in_size
, in_file
);
1317 ret
|= test_compress_stateless(in_buf
, in_size
);
1318 ret
|= test_compress(in_buf
, in_size
, NO_FLUSH
);
1319 ret
|= test_compress(in_buf
, in_size
, SYNC_FLUSH
);
1320 ret
|= test_compress(in_buf
, in_size
, FULL_FLUSH
);
1321 ret
|= test_flush(in_buf
, in_size
);
1324 printf("Failed on file %s\n", file_name
);
1332 int create_custom_hufftables(struct isal_hufftables
*hufftables_custom
, int argc
, char *argv
[])
1334 long int file_length
;
1335 uint8_t *stream
= NULL
;
1336 struct isal_huff_histogram histogram
;
1339 memset(&histogram
, 0, sizeof(histogram
));
1342 printf("Processing %s\n", argv
[argc
- 1]);
1343 file
= fopen(argv
[argc
- 1], "r");
1345 printf("Error opening file\n");
1348 fseek(file
, 0, SEEK_END
);
1349 file_length
= ftell(file
);
1350 fseek(file
, 0, SEEK_SET
);
1351 file_length
-= ftell(file
);
1353 if (file_length
> 0) {
1354 stream
= malloc(file_length
);
1355 if (stream
== NULL
) {
1356 printf("Failed to allocate memory to read in file\n");
1362 fread(stream
, 1, file_length
, file
);
1365 printf("Error occurred when reading file");
1371 /* Create a histogram of frequency of symbols found in stream to
1372 * generate the huffman tree.*/
1373 isal_update_histogram(stream
, file_length
, &histogram
);
1380 return isal_create_hufftables(hufftables_custom
, &histogram
);
1384 int main(int argc
, char *argv
[])
1386 int i
= 0, ret
= 0, fin_ret
= 0;
1387 uint32_t in_size
= 0, offset
= 0;
1389 struct isal_hufftables hufftables_custom
;
1392 setbuf(stdout
, NULL
);
1395 printf("Window Size: %d K\n", HIST_SIZE
);
1396 printf("Test Seed : %d\n", TEST_SEED
);
1397 printf("Randoms : %d\n", RANDOMS
);
1401 ret
= create_custom_hufftables(&hufftables_custom
, argc
, argv
);
1403 hufftables
= &hufftables_custom
;
1405 printf("Failed to generate custom hufftable");
1410 in_buf
= malloc(IBUF_SIZE
);
1411 memset(in_buf
, 0, IBUF_SIZE
);
1413 if (in_buf
== NULL
) {
1414 fprintf(stderr
, "Can't allocate in_buf memory\n");
1419 printf("igzip_rand_test files: ");
1421 for (i
= 1; i
< argc
; i
++) {
1422 ret
|= test_compress_file(argv
[i
]);
1427 printf("................");
1428 printf("%s\n", ret
? "Fail" : "Pass");
1432 printf("igzip_rand_test stateless: ");
1434 ret
= test_compress_stateless((uint8_t *) str1
, sizeof(str1
));
1438 ret
|= test_compress_stateless((uint8_t *) str2
, sizeof(str2
));
1442 for (i
= 0; i
< RANDOMS
; i
++) {
1443 in_size
= rand() % (IBUF_SIZE
+ 1);
1444 offset
= rand() % (IBUF_SIZE
+ 1 - in_size
);
1447 create_rand_repeat_data(in_buf
, in_size
);
1449 ret
|= test_compress_stateless(in_buf
, in_size
);
1453 if (i
% (RANDOMS
/ 16) == 0)
1460 for (i
= 0; i
< RANDOMS
/ 16; i
++) {
1461 create_rand_repeat_data(in_buf
, PAGE_SIZE
);
1462 ret
|= test_compress_stateless(in_buf
, PAGE_SIZE
); // good for efence
1467 printf("%s\n", ret
? "Fail" : "Pass");
1469 printf("igzip_rand_test NO_FLUSH: ");
1471 ret
= test_compress((uint8_t *) str1
, sizeof(str1
), NO_FLUSH
);
1475 ret
|= test_compress((uint8_t *) str2
, sizeof(str2
), NO_FLUSH
);
1479 for (i
= 0; i
< RANDOMS
; i
++) {
1480 in_size
= rand() % (IBUF_SIZE
+ 1);
1481 offset
= rand() % (IBUF_SIZE
+ 1 - in_size
);
1484 create_rand_repeat_data(in_buf
, in_size
);
1486 ret
|= test_compress(in_buf
, in_size
, NO_FLUSH
);
1490 if (i
% (RANDOMS
/ 16) == 0)
1498 printf("%s\n", ret
? "Fail" : "Pass");
1500 printf("igzip_rand_test SYNC_FLUSH: ");
1502 ret
= test_compress((uint8_t *) str1
, sizeof(str1
), SYNC_FLUSH
);
1506 ret
|= test_compress((uint8_t *) str2
, sizeof(str2
), SYNC_FLUSH
);
1510 for (i
= 0; i
< RANDOMS
; i
++) {
1511 in_size
= rand() % (IBUF_SIZE
+ 1);
1512 offset
= rand() % (IBUF_SIZE
+ 1 - in_size
);
1515 create_rand_repeat_data(in_buf
, in_size
);
1517 ret
|= test_compress(in_buf
, in_size
, SYNC_FLUSH
);
1521 if (i
% (RANDOMS
/ 16) == 0)
1529 printf("%s\n", ret
? "Fail" : "Pass");
1531 printf("igzip_rand_test FULL_FLUSH: ");
1533 ret
= test_compress((uint8_t *) str1
, sizeof(str1
), FULL_FLUSH
);
1537 ret
|= test_compress((uint8_t *) str2
, sizeof(str2
), FULL_FLUSH
);
1541 for (i
= 0; i
< RANDOMS
; i
++) {
1542 in_size
= rand() % (IBUF_SIZE
+ 1);
1543 offset
= rand() % (IBUF_SIZE
+ 1 - in_size
);
1546 create_rand_repeat_data(in_buf
, in_size
);
1548 ret
|= test_compress(in_buf
, in_size
, FULL_FLUSH
);
1552 if (i
% (RANDOMS
/ 16) == 0)
1559 for (i
= 0; i
< RANDOMS
/ 8; i
++) {
1560 in_size
= rand() % (IBUF_SIZE
+ 1);
1561 offset
= rand() % (IBUF_SIZE
+ 1 - in_size
);
1564 create_rand_repeat_data(in_buf
, in_size
);
1566 ret
|= test_full_flush(in_buf
, in_size
);
1577 printf("%s\n", ret
? "Fail" : "Pass");
1579 printf("igzip_rand_test Change Flush: ");
1581 ret
= test_flush((uint8_t *) str1
, sizeof(str1
));
1585 ret
|= test_flush((uint8_t *) str2
, sizeof(str2
));
1589 for (i
= 0; i
< RANDOMS
/ 4; i
++) {
1590 in_size
= rand() % (IBUF_SIZE
+ 1);
1591 offset
= rand() % (IBUF_SIZE
+ 1 - in_size
);
1594 create_rand_repeat_data(in_buf
, in_size
);
1596 ret
|= test_flush(in_buf
, in_size
);
1600 if (i
% ((RANDOMS
/ 4) / 16) == 0)
1608 printf("%s\n", ret
? "Fail" : "Pass");
1610 printf("igzip rand test finished: %s\n",
1611 fin_ret
? "Some tests failed" : "All tests passed");
1613 return fin_ret
!= IGZIP_COMP_OK
;