1*522e010bSKonstantin Komarov // SPDX-License-Identifier: GPL-2.0-or-later
2*522e010bSKonstantin Komarov /*
3*522e010bSKonstantin Komarov * xpress_decompress.c - A decompressor for the XPRESS compression format
4*522e010bSKonstantin Komarov * (Huffman variant), which can be used in "System Compressed" files. This is
5*522e010bSKonstantin Komarov * based on the code from wimlib.
6*522e010bSKonstantin Komarov *
7*522e010bSKonstantin Komarov * Copyright (C) 2015 Eric Biggers
8*522e010bSKonstantin Komarov */
9*522e010bSKonstantin Komarov
10*522e010bSKonstantin Komarov #include "decompress_common.h"
11*522e010bSKonstantin Komarov #include "lib.h"
12*522e010bSKonstantin Komarov
13*522e010bSKonstantin Komarov #define XPRESS_NUM_SYMBOLS 512
14*522e010bSKonstantin Komarov #define XPRESS_MAX_CODEWORD_LEN 15
15*522e010bSKonstantin Komarov #define XPRESS_MIN_MATCH_LEN 3
16*522e010bSKonstantin Komarov
17*522e010bSKonstantin Komarov /* This value is chosen for fast decompression. */
18*522e010bSKonstantin Komarov #define XPRESS_TABLEBITS 12
19*522e010bSKonstantin Komarov
20*522e010bSKonstantin Komarov /* Reusable heap-allocated memory for XPRESS decompression */
21*522e010bSKonstantin Komarov struct xpress_decompressor {
22*522e010bSKonstantin Komarov
23*522e010bSKonstantin Komarov /* The Huffman decoding table */
24*522e010bSKonstantin Komarov u16 decode_table[(1 << XPRESS_TABLEBITS) + 2 * XPRESS_NUM_SYMBOLS];
25*522e010bSKonstantin Komarov
26*522e010bSKonstantin Komarov /* An array that maps symbols to codeword lengths */
27*522e010bSKonstantin Komarov u8 lens[XPRESS_NUM_SYMBOLS];
28*522e010bSKonstantin Komarov
29*522e010bSKonstantin Komarov /* Temporary space for make_huffman_decode_table() */
30*522e010bSKonstantin Komarov u16 working_space[2 * (1 + XPRESS_MAX_CODEWORD_LEN) +
31*522e010bSKonstantin Komarov XPRESS_NUM_SYMBOLS];
32*522e010bSKonstantin Komarov };
33*522e010bSKonstantin Komarov
34*522e010bSKonstantin Komarov /*
35*522e010bSKonstantin Komarov * xpress_allocate_decompressor - Allocate an XPRESS decompressor
36*522e010bSKonstantin Komarov *
37*522e010bSKonstantin Komarov * Return the pointer to the decompressor on success, or return NULL and set
38*522e010bSKonstantin Komarov * errno on failure.
39*522e010bSKonstantin Komarov */
xpress_allocate_decompressor(void)40*522e010bSKonstantin Komarov struct xpress_decompressor *xpress_allocate_decompressor(void)
41*522e010bSKonstantin Komarov {
42*522e010bSKonstantin Komarov return kmalloc(sizeof(struct xpress_decompressor), GFP_NOFS);
43*522e010bSKonstantin Komarov }
44*522e010bSKonstantin Komarov
45*522e010bSKonstantin Komarov /*
46*522e010bSKonstantin Komarov * xpress_decompress - Decompress a buffer of XPRESS-compressed data
47*522e010bSKonstantin Komarov *
48*522e010bSKonstantin Komarov * @decompressor: A decompressor that was allocated with
49*522e010bSKonstantin Komarov * xpress_allocate_decompressor()
50*522e010bSKonstantin Komarov * @compressed_data: The buffer of data to decompress
51*522e010bSKonstantin Komarov * @compressed_size: Number of bytes of compressed data
52*522e010bSKonstantin Komarov * @uncompressed_data: The buffer in which to store the decompressed data
53*522e010bSKonstantin Komarov * @uncompressed_size: The number of bytes the data decompresses into
54*522e010bSKonstantin Komarov *
55*522e010bSKonstantin Komarov * Return 0 on success, or return -1 and set errno on failure.
56*522e010bSKonstantin Komarov */
xpress_decompress(struct xpress_decompressor * decompressor,const void * compressed_data,size_t compressed_size,void * uncompressed_data,size_t uncompressed_size)57*522e010bSKonstantin Komarov int xpress_decompress(struct xpress_decompressor *decompressor,
58*522e010bSKonstantin Komarov const void *compressed_data, size_t compressed_size,
59*522e010bSKonstantin Komarov void *uncompressed_data, size_t uncompressed_size)
60*522e010bSKonstantin Komarov {
61*522e010bSKonstantin Komarov struct xpress_decompressor *d = decompressor;
62*522e010bSKonstantin Komarov const u8 * const in_begin = compressed_data;
63*522e010bSKonstantin Komarov u8 * const out_begin = uncompressed_data;
64*522e010bSKonstantin Komarov u8 *out_next = out_begin;
65*522e010bSKonstantin Komarov u8 * const out_end = out_begin + uncompressed_size;
66*522e010bSKonstantin Komarov struct input_bitstream is;
67*522e010bSKonstantin Komarov u32 i;
68*522e010bSKonstantin Komarov
69*522e010bSKonstantin Komarov /* Read the Huffman codeword lengths. */
70*522e010bSKonstantin Komarov if (compressed_size < XPRESS_NUM_SYMBOLS / 2)
71*522e010bSKonstantin Komarov goto invalid;
72*522e010bSKonstantin Komarov for (i = 0; i < XPRESS_NUM_SYMBOLS / 2; i++) {
73*522e010bSKonstantin Komarov d->lens[i*2 + 0] = in_begin[i] & 0xF;
74*522e010bSKonstantin Komarov d->lens[i*2 + 1] = in_begin[i] >> 4;
75*522e010bSKonstantin Komarov }
76*522e010bSKonstantin Komarov
77*522e010bSKonstantin Komarov /* Build a decoding table for the Huffman code. */
78*522e010bSKonstantin Komarov if (make_huffman_decode_table(d->decode_table, XPRESS_NUM_SYMBOLS,
79*522e010bSKonstantin Komarov XPRESS_TABLEBITS, d->lens,
80*522e010bSKonstantin Komarov XPRESS_MAX_CODEWORD_LEN,
81*522e010bSKonstantin Komarov d->working_space))
82*522e010bSKonstantin Komarov goto invalid;
83*522e010bSKonstantin Komarov
84*522e010bSKonstantin Komarov /* Decode the matches and literals. */
85*522e010bSKonstantin Komarov
86*522e010bSKonstantin Komarov init_input_bitstream(&is, in_begin + XPRESS_NUM_SYMBOLS / 2,
87*522e010bSKonstantin Komarov compressed_size - XPRESS_NUM_SYMBOLS / 2);
88*522e010bSKonstantin Komarov
89*522e010bSKonstantin Komarov while (out_next != out_end) {
90*522e010bSKonstantin Komarov u32 sym;
91*522e010bSKonstantin Komarov u32 log2_offset;
92*522e010bSKonstantin Komarov u32 length;
93*522e010bSKonstantin Komarov u32 offset;
94*522e010bSKonstantin Komarov
95*522e010bSKonstantin Komarov sym = read_huffsym(&is, d->decode_table,
96*522e010bSKonstantin Komarov XPRESS_TABLEBITS, XPRESS_MAX_CODEWORD_LEN);
97*522e010bSKonstantin Komarov if (sym < 256) {
98*522e010bSKonstantin Komarov /* Literal */
99*522e010bSKonstantin Komarov *out_next++ = sym;
100*522e010bSKonstantin Komarov } else {
101*522e010bSKonstantin Komarov /* Match */
102*522e010bSKonstantin Komarov length = sym & 0xf;
103*522e010bSKonstantin Komarov log2_offset = (sym >> 4) & 0xf;
104*522e010bSKonstantin Komarov
105*522e010bSKonstantin Komarov bitstream_ensure_bits(&is, 16);
106*522e010bSKonstantin Komarov
107*522e010bSKonstantin Komarov offset = ((u32)1 << log2_offset) |
108*522e010bSKonstantin Komarov bitstream_pop_bits(&is, log2_offset);
109*522e010bSKonstantin Komarov
110*522e010bSKonstantin Komarov if (length == 0xf) {
111*522e010bSKonstantin Komarov length += bitstream_read_byte(&is);
112*522e010bSKonstantin Komarov if (length == 0xf + 0xff)
113*522e010bSKonstantin Komarov length = bitstream_read_u16(&is);
114*522e010bSKonstantin Komarov }
115*522e010bSKonstantin Komarov length += XPRESS_MIN_MATCH_LEN;
116*522e010bSKonstantin Komarov
117*522e010bSKonstantin Komarov if (offset > (size_t)(out_next - out_begin))
118*522e010bSKonstantin Komarov goto invalid;
119*522e010bSKonstantin Komarov
120*522e010bSKonstantin Komarov if (length > (size_t)(out_end - out_next))
121*522e010bSKonstantin Komarov goto invalid;
122*522e010bSKonstantin Komarov
123*522e010bSKonstantin Komarov out_next = lz_copy(out_next, length, offset, out_end,
124*522e010bSKonstantin Komarov XPRESS_MIN_MATCH_LEN);
125*522e010bSKonstantin Komarov }
126*522e010bSKonstantin Komarov }
127*522e010bSKonstantin Komarov return 0;
128*522e010bSKonstantin Komarov
129*522e010bSKonstantin Komarov invalid:
130*522e010bSKonstantin Komarov return -1;
131*522e010bSKonstantin Komarov }
132*522e010bSKonstantin Komarov
133*522e010bSKonstantin Komarov /*
134*522e010bSKonstantin Komarov * xpress_free_decompressor - Free an XPRESS decompressor
135*522e010bSKonstantin Komarov *
136*522e010bSKonstantin Komarov * @decompressor: A decompressor that was allocated with
137*522e010bSKonstantin Komarov * xpress_allocate_decompressor(), or NULL.
138*522e010bSKonstantin Komarov */
xpress_free_decompressor(struct xpress_decompressor * decompressor)139*522e010bSKonstantin Komarov void xpress_free_decompressor(struct xpress_decompressor *decompressor)
140*522e010bSKonstantin Komarov {
141*522e010bSKonstantin Komarov kfree(decompressor);
142*522e010bSKonstantin Komarov }
143