]>
glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/lzx.c
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 (at your option) 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
25 * This algorithm is derived jointly from the document "[MS-PATCH]:
26 * LZX DELTA Compression and Decompression", available from
28 * http://msdn.microsoft.com/en-us/library/cc483133.aspx
30 * and from the file lzx-decompress.c in the wimlib source code.
38 /** Base positions, indexed by position slot */
39 static unsigned int lzx_position_base
[LZX_POSITION_SLOTS
];
42 * Attempt to accumulate bits from LZX bitstream
45 * @v bits Number of bits to accumulate
46 * @v norm_value Accumulated value (normalised to 16 bits)
48 * Note that there may not be sufficient accumulated bits in the
49 * bitstream; callers must check that sufficient bits are available
50 * before using the value.
52 static int lzx_accumulate ( struct lzx
*lzx
, unsigned int bits
) {
53 const uint16_t *src16
;
55 /* Accumulate more bits if required */
56 if ( ( lzx
->bits
< bits
) &&
57 ( lzx
->input
.offset
< lzx
->input
.len
) ) {
58 src16
= (const uint16_t *)( ( char * ) lzx
->input
.data
+ lzx
->input
.offset
);
59 lzx
->input
.offset
+= sizeof ( *src16
);
60 lzx
->accumulator
|= ( *src16
<< ( 16 - lzx
->bits
) );
64 return ( lzx
->accumulator
>> 16 );
68 * Consume accumulated bits from LZX bitstream
71 * @v bits Number of bits to consume
72 * @ret rc Return status code
74 static int lzx_consume ( struct lzx
*lzx
, unsigned int bits
) {
76 /* Fail if insufficient bits are available */
77 if ( lzx
->bits
< bits
) {
78 DBG ( "LZX input overrun in %#zx/%#zx out %#zx)\n",
79 lzx
->input
.offset
, lzx
->input
.len
, lzx
->output
.offset
);
84 lzx
->accumulator
<<= bits
;
91 * Get bits from LZX bitstream
94 * @v bits Number of bits to fetch
95 * @ret value Value, or negative error
97 static int lzx_getbits ( struct lzx
*lzx
, unsigned int bits
) {
101 /* Accumulate more bits if required */
102 norm_value
= lzx_accumulate ( lzx
, bits
);
105 if ( ( rc
= lzx_consume ( lzx
, bits
) ) != 0 )
108 return ( norm_value
>> ( 16 - bits
) );
112 * Align LZX bitstream for byte access
114 * @v lzx Decompressor
115 * @v bits Minimum number of padding bits
116 * @ret rc Return status code
118 static int lzx_align ( struct lzx
*lzx
, unsigned int bits
) {
121 /* Get padding bits */
122 pad
= lzx_getbits ( lzx
, bits
);
126 /* Consume all accumulated bits */
127 lzx_consume ( lzx
, lzx
->bits
);
133 * Get bytes from LZX bitstream
135 * @v lzx Decompressor
136 * @v data Data buffer, or NULL
137 * @v len Length of data buffer
138 * @ret rc Return status code
140 static int lzx_getbytes ( struct lzx
*lzx
, void *data
, size_t len
) {
143 if ( ( lzx
->input
.offset
+ len
) > lzx
->input
.len
) {
144 DBG ( "LZX input overrun in %#zx/%#zx out %#zx)\n",
145 lzx
->input
.offset
, lzx
->input
.len
, lzx
->output
.offset
);
151 memcpy ( data
, ( lzx
->input
.data
+ lzx
->input
.offset
), len
);
152 lzx
->input
.offset
+= len
;
158 * Decode LZX Huffman-coded symbol
160 * @v lzx Decompressor
161 * @v alphabet Huffman alphabet
162 * @ret raw Raw symbol, or negative error
164 static int lzx_decode ( struct lzx
*lzx
, struct huffman_alphabet
*alphabet
) {
165 struct huffman_symbols
*sym
;
169 /* Accumulate sufficient bits */
170 huf
= lzx_accumulate ( lzx
, HUFFMAN_BITS
);
175 sym
= huffman_sym ( alphabet
, huf
);
178 if ( ( rc
= lzx_consume ( lzx
, huffman_len ( sym
) ) ) != 0 )
181 return huffman_raw ( sym
, huf
);
185 * Generate Huffman alphabet from raw length table
187 * @v lzx Decompressor
188 * @v count Number of symbols
189 * @v bits Length of each length (in bits)
190 * @v lengths Lengths table to fill in
191 * @v alphabet Huffman alphabet to fill in
192 * @ret rc Return status code
194 static int lzx_raw_alphabet ( struct lzx
*lzx
, unsigned int count
,
195 unsigned int bits
, uint8_t *lengths
,
196 struct huffman_alphabet
*alphabet
) {
202 for ( i
= 0 ; i
< count
; i
++ ) {
203 len
= lzx_getbits ( lzx
, bits
);
209 /* Generate Huffman alphabet */
210 if ( ( rc
= huffman_alphabet ( alphabet
, lengths
, count
) ) != 0 )
219 * @v lzx Decompressor
220 * @v count Number of symbols
221 * @v lengths Lengths table to fill in
222 * @ret rc Return status code
224 static int lzx_pretree ( struct lzx
*lzx
, unsigned int count
,
232 /* Generate pretree alphabet */
233 if ( ( rc
= lzx_raw_alphabet ( lzx
, LZX_PRETREE_CODES
,
234 LZX_PRETREE_BITS
, lzx
->pretree_lengths
,
235 &lzx
->pretree
) ) != 0 )
239 for ( i
= 0 ; i
< count
; i
++ ) {
243 /* Duplicate previous length */
244 lengths
[i
] = lengths
[ i
- 1 ];
250 code
= lzx_decode ( lzx
, &lzx
->pretree
);
256 length
= ( ( lengths
[i
] - code
+ 17 ) % 17 );
257 } else if ( code
== 17 ) {
259 dup
= lzx_getbits ( lzx
, 4 );
263 } else if ( code
== 18 ) {
265 dup
= lzx_getbits ( lzx
, 5 );
269 } else if ( code
== 19 ) {
271 dup
= lzx_getbits ( lzx
, 1 );
275 code
= lzx_decode ( lzx
, &lzx
->pretree
);
278 length
= ( ( lengths
[i
] - code
+ 17 ) % 17 );
280 DBG ( "Unrecognised pretree code %d\n", code
);
289 DBG ( "Pretree duplicate overrun\n" );
297 * Generate aligned offset Huffman alphabet
299 * @v lzx Decompressor
300 * @ret rc Return status code
302 static int lzx_alignoffset_alphabet ( struct lzx
*lzx
) {
305 /* Generate aligned offset alphabet */
306 if ( ( rc
= lzx_raw_alphabet ( lzx
, LZX_ALIGNOFFSET_CODES
,
307 LZX_ALIGNOFFSET_BITS
,
308 lzx
->alignoffset_lengths
,
309 &lzx
->alignoffset
) ) != 0 )
316 * Generate main Huffman alphabet
318 * @v lzx Decompressor
319 * @ret rc Return status code
321 static int lzx_main_alphabet ( struct lzx
*lzx
) {
324 /* Generate literal symbols pretree */
325 if ( ( rc
= lzx_pretree ( lzx
, LZX_MAIN_LIT_CODES
,
326 lzx
->main_lengths
.literals
) ) != 0 ) {
327 DBG ( "Could not construct main literal pretree\n" );
331 /* Generate remaining symbols pretree */
332 if ( ( rc
= lzx_pretree ( lzx
, ( LZX_MAIN_CODES
- LZX_MAIN_LIT_CODES
),
333 lzx
->main_lengths
.remainder
) ) != 0 ) {
334 DBG ( "Could not construct main remainder pretree\n" );
338 /* Generate Huffman alphabet */
339 if ( ( rc
= huffman_alphabet ( &lzx
->main
, lzx
->main_lengths
.literals
,
340 LZX_MAIN_CODES
) ) != 0 ) {
341 DBG ( "Could not generate main alphabet\n" );
349 * Generate length Huffman alphabet
351 * @v lzx Decompressor
352 * @ret rc Return status code
354 static int lzx_length_alphabet ( struct lzx
*lzx
) {
357 /* Generate pretree */
358 if ( ( rc
= lzx_pretree ( lzx
, LZX_LENGTH_CODES
,
359 lzx
->length_lengths
) ) != 0 ) {
360 DBG ( "Could not generate length pretree\n" );
364 /* Generate Huffman alphabet */
365 if ( ( rc
= huffman_alphabet ( &lzx
->length
, lzx
->length_lengths
,
366 LZX_LENGTH_CODES
) ) != 0 ) {
367 DBG ( "Could not generate length alphabet\n" );
375 * Process LZX block header
377 * @v lzx Decompressor
378 * @ret rc Return status code
380 static int lzx_block_header ( struct lzx
*lzx
) {
389 block_type
= lzx_getbits ( lzx
, LZX_BLOCK_TYPE_BITS
);
390 if ( block_type
< 0 )
392 lzx
->block_type
= block_type
;
394 /* Check block length */
395 default_len
= lzx_getbits ( lzx
, 1 );
396 if ( default_len
< 0 )
399 block_len
= LZX_DEFAULT_BLOCK_LEN
;
401 len_high
= lzx_getbits ( lzx
, 8 );
404 len_low
= lzx_getbits ( lzx
, 8 );
407 block_len
= ( ( len_high
<< 8 ) | len_low
);
409 lzx
->output
.threshold
= ( lzx
->output
.offset
+ block_len
);
411 /* Handle block type */
412 switch ( block_type
) {
413 case LZX_BLOCK_ALIGNOFFSET
:
414 /* Generated aligned offset alphabet */
415 if ( ( rc
= lzx_alignoffset_alphabet ( lzx
) ) != 0 )
418 case LZX_BLOCK_VERBATIM
:
419 /* Generate main alphabet */
420 if ( ( rc
= lzx_main_alphabet ( lzx
) ) != 0 )
422 /* Generate lengths alphabet */
423 if ( ( rc
= lzx_length_alphabet ( lzx
) ) != 0 )
426 case LZX_BLOCK_UNCOMPRESSED
:
427 /* Align input stream */
428 if ( ( rc
= lzx_align ( lzx
, 1 ) ) != 0 )
430 /* Read new repeated offsets */
431 if ( ( rc
= lzx_getbytes ( lzx
, &lzx
->repeated_offset
,
432 sizeof ( lzx
->repeated_offset
)))!=0)
436 DBG ( "Unrecognised block type %d\n", block_type
);
444 * Process uncompressed data
446 * @v lzx Decompressor
447 * @ret rc Return status code
449 static int lzx_uncompressed ( struct lzx
*lzx
) {
455 data
= ( lzx
->output
.data
?
456 ( lzx
->output
.data
+ lzx
->output
.offset
) : NULL
);
457 len
= ( lzx
->output
.threshold
- lzx
->output
.offset
);
458 if ( ( rc
= lzx_getbytes ( lzx
, data
, len
) ) != 0 )
461 /* Align input stream */
469 * Process an LZX token
471 * @v lzx Decompressor
472 * @ret rc Return status code
474 * Variable names are chosen to match the LZX specification
477 static int lzx_token ( struct lzx
*lzx
) {
478 unsigned int length_header
;
479 unsigned int position_slot
;
480 unsigned int offset_bits
;
490 /* Get maindata symelse*/
491 maindata
= lzx_decode ( lzx
, &lzx
->main
);
495 /* Check for literals */
496 if ( maindata
< LZX_MAIN_LIT_CODES
) {
497 if ( lzx
->output
.data
)
498 lzx
->output
.data
[lzx
->output
.offset
] = maindata
;
499 lzx
->output
.offset
++;
502 maindata
-= LZX_MAIN_LIT_CODES
;
504 /* Calculate the match length */
505 length_header
= ( maindata
& 7 );
506 if ( length_header
== 7 ) {
507 length
= lzx_decode ( lzx
, &lzx
->length
);
513 match_length
= ( length_header
+ 2 + length
);
515 /* Calculate the position slot */
516 position_slot
= ( maindata
>> 3 );
517 if ( position_slot
< LZX_REPEATED_OFFSETS
) {
519 /* Repeated offset */
520 match_offset
= lzx
->repeated_offset
[position_slot
];
521 lzx
->repeated_offset
[position_slot
] = lzx
->repeated_offset
[0];
522 lzx
->repeated_offset
[0] = match_offset
;
526 /* Non-repeated offset */
527 offset_bits
= lzx_footer_bits ( position_slot
);
528 if ( ( lzx
->block_type
== LZX_BLOCK_ALIGNOFFSET
) &&
529 ( offset_bits
>= 3 ) ) {
530 verbatim_bits
= lzx_getbits ( lzx
, ( offset_bits
- 3 ));
531 if ( verbatim_bits
< 0 )
532 return verbatim_bits
;
534 aligned_bits
= lzx_decode ( lzx
, &lzx
->alignoffset
);
535 if ( aligned_bits
< 0 )
538 verbatim_bits
= lzx_getbits ( lzx
, offset_bits
);
539 if ( verbatim_bits
< 0 )
540 return verbatim_bits
;
543 match_offset
= ( lzx_position_base
[position_slot
] +
544 verbatim_bits
+ aligned_bits
- 2 );
546 /* Update repeated offset list */
547 for ( i
= ( LZX_REPEATED_OFFSETS
- 1 ) ; i
> 0 ; i
-- )
548 lzx
->repeated_offset
[i
] = lzx
->repeated_offset
[ i
- 1 ];
549 lzx
->repeated_offset
[0] = match_offset
;
553 if ( match_offset
> lzx
->output
.offset
) {
554 DBG ( "LZX match underrun out 0x%x offset 0x%x len 0x%x\n",
555 lzx
->output
.offset
, match_offset
, match_length
);
558 if ( lzx
->output
.data
) {
559 copy
= &lzx
->output
.data
[lzx
->output
.offset
];
560 for ( i
= 0 ; i
< match_length
; i
++ )
561 copy
[i
] = copy
[ i
- match_offset
];
563 lzx
->output
.offset
+= match_length
;
569 * Translate E8 jump addresses
571 * @v lzx Decompressor
573 static void lzx_translate_jumps ( struct lzx
*lzx
) {
578 if ( lzx
->output
.offset
< 10 )
581 /* Scan for jump instructions */
582 for ( offset
= 0 ; offset
< ( lzx
->output
.offset
- 10 ) ; offset
++ ) {
584 /* Check for jump instruction */
585 if ( lzx
->output
.data
[offset
] != 0xe8 )
588 /* Translate jump target */
589 target
= ( ( int32_t * ) &lzx
->output
.data
[ offset
+ 1 ] );
590 if ( *target
>= 0 ) {
591 if ( *target
< LZX_WIM_MAGIC_FILESIZE
)
594 if ( *target
>= -( ( int32_t ) offset
) )
595 *target
+= LZX_WIM_MAGIC_FILESIZE
;
597 offset
+= sizeof ( *target
);
602 * Decompress LZX-compressed data
604 * @v data Compressed data
605 * @v len Length of compressed data
606 * @v buf Decompression buffer, or NULL
607 * @ret out_len Length of decompressed data, or negative error
609 ssize_t
lzx_decompress ( const void *data
, size_t len
, void *buf
) {
616 DBG ( "LZX cannot handle odd-length input data\n" );
620 /* Initialise global state, if required */
621 if ( ! lzx_position_base
[ LZX_POSITION_SLOTS
- 1 ] ) {
622 for ( i
= 1 ; i
< LZX_POSITION_SLOTS
; i
++ ) {
623 lzx_position_base
[i
] =
624 ( lzx_position_base
[i
-1] +
625 ( 1 << lzx_footer_bits ( i
- 1 ) ) );
629 /* Initialise decompressor */
630 memset ( &lzx
, 0, sizeof ( lzx
) );
631 lzx
.input
.data
= data
;
633 lzx
.output
.data
= buf
;
634 for ( i
= 0 ; i
< LZX_REPEATED_OFFSETS
; i
++ )
635 lzx
.repeated_offset
[i
] = 1;
638 while ( lzx
.input
.offset
< lzx
.input
.len
) {
640 /* Process block header */
641 if ( ( rc
= lzx_block_header ( &lzx
) ) != 0 )
644 /* Process block contents */
645 if ( lzx
.block_type
== LZX_BLOCK_UNCOMPRESSED
) {
647 /* Copy uncompressed data */
648 if ( ( rc
= lzx_uncompressed ( &lzx
) ) != 0 )
653 /* Process token stream */
654 while ( lzx
.output
.offset
< lzx
.output
.threshold
) {
655 if ( ( rc
= lzx_token ( &lzx
) ) != 0 )
661 /* Postprocess to undo E8 jump compression */
662 if ( lzx
.output
.data
)
663 lzx_translate_jumps ( &lzx
);
665 return lzx
.output
.offset
;