xpress_decompress.c 3.9 KB

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