1f39cd3f7SHyunchul Lee // SPDX-License-Identifier: GPL-2.0-or-later 2f39cd3f7SHyunchul Lee /* 3f39cd3f7SHyunchul Lee * xpress_decompress.c - A decompressor for the XPRESS compression format 4f39cd3f7SHyunchul Lee * (Huffman variant), which can be used in "System Compressed" (WOF) files. 5f39cd3f7SHyunchul Lee * 6f39cd3f7SHyunchul Lee * This is a port of the upstream wimlib "xpress_decompress.c" which uses a 7f39cd3f7SHyunchul Lee * subtable-based Huffman decode table format. The decode table and the 8f39cd3f7SHyunchul Lee * codeword-length array share a union since the lengths are fully consumed 9f39cd3f7SHyunchul Lee * before the table is written. 10f39cd3f7SHyunchul Lee * 11f39cd3f7SHyunchul Lee * Copyright (C) 2012-2016 Eric Biggers 12f39cd3f7SHyunchul Lee */ 13f39cd3f7SHyunchul Lee 14f39cd3f7SHyunchul Lee #include <linux/array_size.h> 15f39cd3f7SHyunchul Lee 16f39cd3f7SHyunchul Lee #include "decompress_common.h" 17f39cd3f7SHyunchul Lee #include "lib.h" 18*7ddb3fefSHyunchul Lee #include "../ntfs_codec.h" 19f39cd3f7SHyunchul Lee 20f39cd3f7SHyunchul Lee #define XPRESS_NUM_CHARS 256 21f39cd3f7SHyunchul Lee #define XPRESS_NUM_SYMBOLS 512 22f39cd3f7SHyunchul Lee #define XPRESS_MAX_CODEWORD_LEN 15 23f39cd3f7SHyunchul Lee #define XPRESS_MIN_MATCH_LEN 3 24f39cd3f7SHyunchul Lee 25f39cd3f7SHyunchul Lee /* This value is chosen for fast decompression. */ 26f39cd3f7SHyunchul Lee #define XPRESS_TABLEBITS 11 27f39cd3f7SHyunchul Lee 28f39cd3f7SHyunchul Lee /* Reusable heap-allocated memory for XPRESS decompression. The decode table 29f39cd3f7SHyunchul Lee * and the codeword-length array alias each other in a union: all lengths are 30f39cd3f7SHyunchul Lee * consumed into the working space before any decode-table entry is written. 31f39cd3f7SHyunchul Lee */ 32f39cd3f7SHyunchul Lee struct xpress_decompressor { 33f39cd3f7SHyunchul Lee union { 34f39cd3f7SHyunchul Lee DECODE_TABLE(decode_table, XPRESS_NUM_SYMBOLS, XPRESS_TABLEBITS, 35f39cd3f7SHyunchul Lee XPRESS_MAX_CODEWORD_LEN); 36f39cd3f7SHyunchul Lee u8 lens[XPRESS_NUM_SYMBOLS]; 37f39cd3f7SHyunchul Lee }; 38f39cd3f7SHyunchul Lee DECODE_TABLE_WORKING_SPACE(working_space, XPRESS_NUM_SYMBOLS, 39f39cd3f7SHyunchul Lee XPRESS_MAX_CODEWORD_LEN); 40f39cd3f7SHyunchul Lee } __aligned(DECODE_TABLE_ALIGNMENT); 41f39cd3f7SHyunchul Lee 42f39cd3f7SHyunchul Lee int xpress_decompress(struct xpress_decompressor *d, 43f39cd3f7SHyunchul Lee const void *compressed_data, size_t compressed_size, 44f39cd3f7SHyunchul Lee void *uncompressed_data, size_t uncompressed_size) 45f39cd3f7SHyunchul Lee { 46f39cd3f7SHyunchul Lee const u8 *const in_begin = compressed_data; 47f39cd3f7SHyunchul Lee u8 *const out_begin = uncompressed_data; 48f39cd3f7SHyunchul Lee u8 *out_next = out_begin; 49f39cd3f7SHyunchul Lee u8 *const out_end = out_begin + uncompressed_size; 50f39cd3f7SHyunchul Lee struct input_bitstream is; 51f39cd3f7SHyunchul Lee u32 i; 52f39cd3f7SHyunchul Lee 53f39cd3f7SHyunchul Lee /* Read the Huffman codeword lengths (512 4-bit values packed into 256 54f39cd3f7SHyunchul Lee * bytes). 55f39cd3f7SHyunchul Lee */ 56f39cd3f7SHyunchul Lee if (compressed_size < XPRESS_NUM_SYMBOLS / 2) 57f39cd3f7SHyunchul Lee return -1; 58f39cd3f7SHyunchul Lee for (i = 0; i < XPRESS_NUM_SYMBOLS / 2; i++) { 59f39cd3f7SHyunchul Lee d->lens[2 * i + 0] = in_begin[i] & 0xf; 60f39cd3f7SHyunchul Lee d->lens[2 * i + 1] = in_begin[i] >> 4; 61f39cd3f7SHyunchul Lee } 62f39cd3f7SHyunchul Lee 63f39cd3f7SHyunchul Lee /* Build a decoding table for the Huffman code. */ 64f39cd3f7SHyunchul Lee if (make_huffman_decode_table(d->decode_table, XPRESS_NUM_SYMBOLS, 65f39cd3f7SHyunchul Lee XPRESS_TABLEBITS, d->lens, 66f39cd3f7SHyunchul Lee XPRESS_MAX_CODEWORD_LEN, 67f39cd3f7SHyunchul Lee d->working_space, 68f39cd3f7SHyunchul Lee ARRAY_SIZE(d->decode_table))) 69f39cd3f7SHyunchul Lee return -1; 70f39cd3f7SHyunchul Lee 71f39cd3f7SHyunchul Lee /* Decode the matches and literals. */ 72f39cd3f7SHyunchul Lee init_input_bitstream(&is, in_begin + XPRESS_NUM_SYMBOLS / 2, 73f39cd3f7SHyunchul Lee compressed_size - XPRESS_NUM_SYMBOLS / 2); 74f39cd3f7SHyunchul Lee 75f39cd3f7SHyunchul Lee while (out_next != out_end) { 76f39cd3f7SHyunchul Lee u32 sym; 77f39cd3f7SHyunchul Lee u32 log2_offset; 78f39cd3f7SHyunchul Lee u32 length; 79f39cd3f7SHyunchul Lee u32 offset; 80f39cd3f7SHyunchul Lee 81f39cd3f7SHyunchul Lee sym = read_huffsym(&is, d->decode_table, XPRESS_TABLEBITS, 82f39cd3f7SHyunchul Lee XPRESS_MAX_CODEWORD_LEN); 83f39cd3f7SHyunchul Lee if (sym < XPRESS_NUM_CHARS) { 84f39cd3f7SHyunchul Lee /* Literal */ 85f39cd3f7SHyunchul Lee *out_next++ = sym; 86f39cd3f7SHyunchul Lee } else { 87f39cd3f7SHyunchul Lee /* Match */ 88f39cd3f7SHyunchul Lee length = sym & 0xf; 89f39cd3f7SHyunchul Lee log2_offset = (sym >> 4) & 0xf; 90f39cd3f7SHyunchul Lee 91f39cd3f7SHyunchul Lee bitstream_ensure_bits(&is, 16); 92f39cd3f7SHyunchul Lee 93f39cd3f7SHyunchul Lee offset = ((u32)1 << log2_offset) | 94f39cd3f7SHyunchul Lee bitstream_pop_bits(&is, log2_offset); 95f39cd3f7SHyunchul Lee 96f39cd3f7SHyunchul Lee if (length == 0xf) { 97f39cd3f7SHyunchul Lee length += bitstream_read_byte(&is); 98f39cd3f7SHyunchul Lee if (length == 0xf + 0xff) 99f39cd3f7SHyunchul Lee length = bitstream_read_u16(&is); 100f39cd3f7SHyunchul Lee } 101f39cd3f7SHyunchul Lee length += XPRESS_MIN_MATCH_LEN; 102f39cd3f7SHyunchul Lee 103f39cd3f7SHyunchul Lee if (unlikely(lz_copy(length, offset, out_begin, out_next, 104f39cd3f7SHyunchul Lee out_end, XPRESS_MIN_MATCH_LEN))) 105f39cd3f7SHyunchul Lee return -1; 106f39cd3f7SHyunchul Lee 107f39cd3f7SHyunchul Lee out_next += length; 108f39cd3f7SHyunchul Lee } 109f39cd3f7SHyunchul Lee } 110f39cd3f7SHyunchul Lee return 0; 111f39cd3f7SHyunchul Lee } 112f39cd3f7SHyunchul Lee 113f39cd3f7SHyunchul Lee struct xpress_decompressor *xpress_allocate_decompressor(void) 114f39cd3f7SHyunchul Lee { 115f39cd3f7SHyunchul Lee return kmalloc_obj(struct xpress_decompressor, GFP_NOFS); 116f39cd3f7SHyunchul Lee } 117f39cd3f7SHyunchul Lee 118f39cd3f7SHyunchul Lee void xpress_free_decompressor(struct xpress_decompressor *d) 119f39cd3f7SHyunchul Lee { 120f39cd3f7SHyunchul Lee kfree(d); 121f39cd3f7SHyunchul Lee } 122*7ddb3fefSHyunchul Lee 123*7ddb3fefSHyunchul Lee static size_t xpress_scratch_size(u32 chunk_size) 124*7ddb3fefSHyunchul Lee { 125*7ddb3fefSHyunchul Lee return sizeof(struct xpress_decompressor); 126*7ddb3fefSHyunchul Lee } 127*7ddb3fefSHyunchul Lee 128*7ddb3fefSHyunchul Lee static int xpress_decompress_chunk(void *scratch, const void *src, 129*7ddb3fefSHyunchul Lee size_t src_len, void *dst, size_t dst_len, 130*7ddb3fefSHyunchul Lee u32 chunk_size) 131*7ddb3fefSHyunchul Lee { 132*7ddb3fefSHyunchul Lee return xpress_decompress(scratch, src, src_len, dst, dst_len); 133*7ddb3fefSHyunchul Lee } 134*7ddb3fefSHyunchul Lee 135*7ddb3fefSHyunchul Lee const struct ntfs_codec_ops ntfs_xpress4k_codec_ops = { 136*7ddb3fefSHyunchul Lee .id = NTFS_CODEC_XPRESS4K, 137*7ddb3fefSHyunchul Lee .name = "xpress4k", 138*7ddb3fefSHyunchul Lee .scratch_size = xpress_scratch_size, 139*7ddb3fefSHyunchul Lee .decompress_chunk = xpress_decompress_chunk, 140*7ddb3fefSHyunchul Lee }; 141*7ddb3fefSHyunchul Lee 142*7ddb3fefSHyunchul Lee const struct ntfs_codec_ops ntfs_xpress8k_codec_ops = { 143*7ddb3fefSHyunchul Lee .id = NTFS_CODEC_XPRESS8K, 144*7ddb3fefSHyunchul Lee .name = "xpress8k", 145*7ddb3fefSHyunchul Lee .scratch_size = xpress_scratch_size, 146*7ddb3fefSHyunchul Lee .decompress_chunk = xpress_decompress_chunk, 147*7ddb3fefSHyunchul Lee }; 148*7ddb3fefSHyunchul Lee 149*7ddb3fefSHyunchul Lee const struct ntfs_codec_ops ntfs_xpress16k_codec_ops = { 150*7ddb3fefSHyunchul Lee .id = NTFS_CODEC_XPRESS16K, 151*7ddb3fefSHyunchul Lee .name = "xpress16k", 152*7ddb3fefSHyunchul Lee .scratch_size = xpress_scratch_size, 153*7ddb3fefSHyunchul Lee .decompress_chunk = xpress_decompress_chunk, 154*7ddb3fefSHyunchul Lee }; 155