LCOV - code coverage report
Current view: top level - lib/compression - lzxpress.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 0 150 0.0 %
Date: 2024-06-13 04:01:37 Functions: 0 2 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) Matthieu Suiche 2008
       3             :  *
       4             :  * All rights reserved.
       5             :  *
       6             :  * Redistribution and use in source and binary forms, with or without
       7             :  * modification, are permitted provided that the following conditions
       8             :  * are met:
       9             :  *
      10             :  * 1. Redistributions of source code must retain the above copyright
      11             :  *    notice, this list of conditions and the following disclaimer.
      12             :  *
      13             :  * 2. Redistributions in binary form must reproduce the above copyright
      14             :  *    notice, this list of conditions and the following disclaimer in the
      15             :  *    documentation and/or other materials provided with the distribution.
      16             :  *
      17             :  * 3. Neither the name of the author nor the names of its contributors
      18             :  *    may be used to endorse or promote products derived from this software
      19             :  *    without specific prior written permission.
      20             :  *
      21             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
      22             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      23             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      24             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
      25             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      26             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      27             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      28             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      29             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      30             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      31             :  * SUCH DAMAGE.
      32             :  *
      33             :  */
      34             : 
      35             : #include "replace.h"
      36             : #include "lzxpress.h"
      37             : #include "../lib/util/byteorder.h"
      38             : 
      39             : 
      40             : #define __CHECK_BYTES(__size, __index, __needed) do { \
      41             :         if (unlikely(__index >= __size)) { \
      42             :                 return -1; \
      43             :         } else { \
      44             :                 uint32_t __avail = __size - __index; \
      45             :                 if (unlikely(__needed > __avail)) { \
      46             :                         return -1; \
      47             :                 } \
      48             :         } \
      49             : } while(0)
      50             : 
      51             : #define CHECK_INPUT_BYTES(__needed) \
      52             :         __CHECK_BYTES(uncompressed_size, uncompressed_pos, __needed)
      53             : #define CHECK_OUTPUT_BYTES(__needed) \
      54             :         __CHECK_BYTES(max_compressed_size, compressed_pos, __needed)
      55             : 
      56           0 : ssize_t lzxpress_compress(const uint8_t *uncompressed,
      57             :                           uint32_t uncompressed_size,
      58             :                           uint8_t *compressed,
      59             :                           uint32_t max_compressed_size)
      60             : {
      61             :         /*
      62             :          * This is the algorithm in [MS-XCA] 2.3 "Plain LZ77 Compression".
      63             :          *
      64             :          * It avoids Huffman encoding by including literal bytes inline when a
      65             :          * match is not found. Every so often it includes a uint32 bit map
      66             :          * flagging which positions contain matches and which contain
      67             :          * literals. The encoding of matches is of variable size, depending on
      68             :          * the match length; they are always at least 16 bits long, and can
      69             :          * implicitly use unused half-bytes from earlier in the stream.
      70             :          */
      71             :         uint32_t uncompressed_pos, compressed_pos;
      72             :         uint32_t indic;
      73             :         uint32_t indic_pos;
      74             :         uint32_t indic_bit, nibble_index;
      75             : 
      76           0 :         if (!uncompressed_size) {
      77           0 :                 return 0;
      78             :         }
      79             : 
      80           0 :         uncompressed_pos = 0;
      81           0 :         compressed_pos = 0;
      82           0 :         indic = 0;
      83           0 :         CHECK_OUTPUT_BYTES(sizeof(uint32_t));
      84           0 :         PUSH_LE_U32(compressed, compressed_pos, 0);
      85           0 :         compressed_pos += sizeof(uint32_t);
      86           0 :         indic_pos = 0;
      87             : 
      88           0 :         indic_bit = 0;
      89           0 :         nibble_index = 0;
      90             : 
      91           0 :         while ((uncompressed_pos < uncompressed_size) &&
      92             :                (compressed_pos < max_compressed_size)) {
      93           0 :                 bool found = false;
      94             : 
      95           0 :                 uint32_t best_len = 2;
      96           0 :                 uint32_t best_offset = 0;
      97             : 
      98             :                 int32_t offset;
      99             : 
     100           0 :                 const uint32_t max_offset = MIN(0x2000, uncompressed_pos);
     101             :                 /* maximum len we can encode into metadata */
     102           0 :                 const uint32_t max_len = MIN(0xFFFF + 3, uncompressed_size - uncompressed_pos);
     103             : 
     104             :                 /* search for the longest match in the window for the lookahead buffer */
     105           0 :                 for (offset = 1; (uint32_t)offset <= max_offset; offset++) {
     106             :                         uint32_t len;
     107             : 
     108           0 :                         for (len = 0;
     109           0 :                              (len < max_len) && (uncompressed[uncompressed_pos + len] ==
     110           0 :                                                  uncompressed[uncompressed_pos + len - offset]);
     111           0 :                              len++);
     112             : 
     113             :                         /*
     114             :                          * We check if len is better than the value found before, including the
     115             :                          * sequence of identical bytes
     116             :                          */
     117           0 :                         if (len > best_len) {
     118           0 :                                 found = true;
     119           0 :                                 best_len = len;
     120           0 :                                 best_offset = offset;
     121           0 :                                 if (best_len == max_len) {
     122             :                                         /* We're not going to do better than this */
     123           0 :                                         break;
     124             :                                 }
     125             :                         }
     126             :                 }
     127             : 
     128           0 :                 if (!found) {
     129             :                         /*
     130             :                          * This is going to literal byte, which we flag by
     131             :                          * setting a bit in an indicator field somewhere
     132             :                          * earlier in the stream.
     133             :                          */
     134           0 :                         CHECK_INPUT_BYTES(sizeof(uint8_t));
     135           0 :                         CHECK_OUTPUT_BYTES(sizeof(uint8_t));
     136           0 :                         compressed[compressed_pos++] = uncompressed[uncompressed_pos++];
     137             : 
     138           0 :                         indic <<= 1;
     139           0 :                         indic_bit += 1;
     140             : 
     141           0 :                         if (indic_bit == 32) {
     142           0 :                                 PUSH_LE_U32(compressed, indic_pos, indic);
     143           0 :                                 indic_bit = 0;
     144           0 :                                 CHECK_OUTPUT_BYTES(sizeof(uint32_t));
     145           0 :                                 indic_pos = compressed_pos;
     146           0 :                                 compressed_pos += sizeof(uint32_t);
     147             :                         }
     148             :                 } else {
     149           0 :                         uint32_t match_len = best_len;
     150             : 
     151             :                         uint16_t metadata;
     152             : 
     153           0 :                         match_len -= 3;
     154           0 :                         best_offset -= 1;
     155             : 
     156             :                         /* Classical meta-data */
     157           0 :                         CHECK_OUTPUT_BYTES(sizeof(uint16_t));
     158           0 :                         metadata = (uint16_t)((best_offset << 3) | MIN(match_len, 7));
     159           0 :                         PUSH_LE_U16(compressed, compressed_pos, metadata);
     160           0 :                         compressed_pos += sizeof(uint16_t);
     161             : 
     162           0 :                         if (match_len >= 7) {
     163           0 :                                 match_len -= 7;
     164             : 
     165           0 :                                 if (!nibble_index) {
     166           0 :                                         nibble_index = compressed_pos;
     167             : 
     168           0 :                                         CHECK_OUTPUT_BYTES(sizeof(uint8_t));
     169           0 :                                         compressed[nibble_index] = MIN(match_len, 15);
     170           0 :                                         compressed_pos += sizeof(uint8_t);
     171             :                                 } else {
     172           0 :                                         compressed[nibble_index] |= MIN(match_len, 15) << 4;
     173           0 :                                         nibble_index = 0;
     174             :                                 }
     175             : 
     176           0 :                                 if (match_len >= 15) {
     177           0 :                                         match_len -= 15;
     178             : 
     179           0 :                                         CHECK_OUTPUT_BYTES(sizeof(uint8_t));
     180           0 :                                         compressed[compressed_pos] = MIN(match_len, 255);
     181           0 :                                         compressed_pos += sizeof(uint8_t);
     182             : 
     183           0 :                                         if (match_len >= 255) {
     184             :                                                 /* Additional match_len */
     185             : 
     186           0 :                                                 match_len += 7 + 15;
     187             : 
     188           0 :                                                 if (match_len < (1 << 16)) {
     189           0 :                                                         CHECK_OUTPUT_BYTES(sizeof(uint16_t));
     190           0 :                                                         PUSH_LE_U16(compressed, compressed_pos, match_len);
     191           0 :                                                         compressed_pos += sizeof(uint16_t);
     192             :                                                 } else {
     193           0 :                                                         CHECK_OUTPUT_BYTES(sizeof(uint16_t) + sizeof(uint32_t));
     194           0 :                                                         PUSH_LE_U16(compressed, compressed_pos, 0);
     195           0 :                                                         compressed_pos += sizeof(uint16_t);
     196             : 
     197           0 :                                                         PUSH_LE_U32(compressed, compressed_pos, match_len);
     198           0 :                                                         compressed_pos += sizeof(uint32_t);
     199             :                                                 }
     200             :                                         }
     201             :                                 }
     202             :                         }
     203             : 
     204           0 :                         indic = (indic << 1) | 1;
     205           0 :                         indic_bit += 1;
     206             : 
     207           0 :                         if (indic_bit == 32) {
     208           0 :                                 PUSH_LE_U32(compressed, indic_pos, indic);
     209           0 :                                 indic_bit = 0;
     210           0 :                                 CHECK_OUTPUT_BYTES(sizeof(uint32_t));
     211           0 :                                 indic_pos = compressed_pos;
     212           0 :                                 compressed_pos += sizeof(uint32_t);
     213             :                         }
     214             : 
     215           0 :                         uncompressed_pos += best_len;
     216             :                 }
     217             :         }
     218             : 
     219           0 :         if (indic_bit != 0) {
     220           0 :                 indic <<= 32 - indic_bit;
     221             :         }
     222           0 :         indic |= UINT32_MAX >> indic_bit;
     223           0 :         PUSH_LE_U32(compressed, indic_pos, indic);
     224             : 
     225           0 :         return compressed_pos;
     226             : }
     227             : 
     228           0 : ssize_t lzxpress_decompress(const uint8_t *input,
     229             :                             uint32_t input_size,
     230             :                             uint8_t *output,
     231             :                             uint32_t max_output_size)
     232             : {
     233             :         /*
     234             :          * This is the algorithm in [MS-XCA] 2.4 "Plain LZ77 Decompression
     235             :          * Algorithm Details".
     236             :          */
     237             :         uint32_t output_index, input_index;
     238             :         uint32_t indicator, indicator_bit;
     239             :         uint32_t nibble_index;
     240             : 
     241           0 :         if (input_size == 0) {
     242           0 :                 return 0;
     243             :         }
     244             : 
     245           0 :         output_index = 0;
     246           0 :         input_index = 0;
     247           0 :         indicator = 0;
     248           0 :         indicator_bit = 0;
     249           0 :         nibble_index = 0;
     250             : 
     251             : #undef CHECK_INPUT_BYTES
     252             : #define CHECK_INPUT_BYTES(__needed) \
     253             :         __CHECK_BYTES(input_size, input_index, __needed)
     254             : #undef CHECK_OUTPUT_BYTES
     255             : #define CHECK_OUTPUT_BYTES(__needed) \
     256             :         __CHECK_BYTES(max_output_size, output_index, __needed)
     257             : 
     258             :         do {
     259           0 :                 if (indicator_bit == 0) {
     260           0 :                         CHECK_INPUT_BYTES(sizeof(uint32_t));
     261           0 :                         indicator = PULL_LE_U32(input, input_index);
     262           0 :                         input_index += sizeof(uint32_t);
     263           0 :                         if (input_index == input_size) {
     264             :                                 /*
     265             :                                  * The compressor left room for indicator
     266             :                                  * flags for data that doesn't exist.
     267             :                                  */
     268           0 :                                 break;
     269             :                         }
     270           0 :                         indicator_bit = 32;
     271             :                 }
     272           0 :                 indicator_bit--;
     273             : 
     274             :                 /*
     275             :                  * check whether the bit specified by indicator_bit is set or not
     276             :                  * set in indicator. For example, if indicator_bit has value 4
     277             :                  * check whether the 4th bit of the value in indicator is set
     278             :                  */
     279           0 :                 if (((indicator >> indicator_bit) & 1) == 0) {
     280           0 :                         CHECK_INPUT_BYTES(sizeof(uint8_t));
     281           0 :                         CHECK_OUTPUT_BYTES(sizeof(uint8_t));
     282           0 :                         output[output_index] = input[input_index];
     283           0 :                         input_index += sizeof(uint8_t);
     284           0 :                         output_index += sizeof(uint8_t);
     285             :                 } else {
     286             :                         uint32_t length;
     287             :                         uint32_t offset;
     288             : 
     289           0 :                         CHECK_INPUT_BYTES(sizeof(uint16_t));
     290           0 :                         length = PULL_LE_U16(input, input_index);
     291           0 :                         input_index += sizeof(uint16_t);
     292           0 :                         offset = (length >> 3) + 1;
     293           0 :                         length &= 7;
     294             : 
     295           0 :                         if (length == 7) {
     296           0 :                                 if (nibble_index == 0) {
     297           0 :                                         CHECK_INPUT_BYTES(sizeof(uint8_t));
     298           0 :                                         nibble_index = input_index;
     299           0 :                                         length = input[input_index] & 0xf;
     300           0 :                                         input_index += sizeof(uint8_t);
     301             :                                 } else {
     302           0 :                                         length = input[nibble_index] >> 4;
     303           0 :                                         nibble_index = 0;
     304             :                                 }
     305             : 
     306           0 :                                 if (length == 15) {
     307           0 :                                         CHECK_INPUT_BYTES(sizeof(uint8_t));
     308           0 :                                         length = input[input_index];
     309           0 :                                         input_index += sizeof(uint8_t);
     310           0 :                                         if (length == 255) {
     311           0 :                                                 CHECK_INPUT_BYTES(sizeof(uint16_t));
     312           0 :                                                 length = PULL_LE_U16(input, input_index);
     313           0 :                                                 input_index += sizeof(uint16_t);
     314           0 :                                                 if (length == 0) {
     315           0 :                                                         CHECK_INPUT_BYTES(sizeof(uint32_t));
     316           0 :                                                         length = PULL_LE_U32(input, input_index);
     317           0 :                                                         input_index += sizeof(uint32_t);
     318             :                                                 }
     319             : 
     320           0 :                                                 if (length < (15 + 7)) {
     321           0 :                                                         return -1;
     322             :                                                 }
     323           0 :                                                 length -= (15 + 7);
     324             :                                         }
     325           0 :                                         length += 15;
     326             :                                 }
     327           0 :                                 length += 7;
     328             :                         }
     329           0 :                         length += 3;
     330             : 
     331           0 :                         if (length == 0) {
     332           0 :                                 return -1;
     333             :                         }
     334             : 
     335           0 :                         for (; length > 0; --length) {
     336           0 :                                 if (offset > output_index) {
     337           0 :                                         return -1;
     338             :                                 }
     339           0 :                                 CHECK_OUTPUT_BYTES(sizeof(uint8_t));
     340           0 :                                 output[output_index] = output[output_index - offset];
     341           0 :                                 output_index += sizeof(uint8_t);
     342             :                         }
     343             :                 }
     344           0 :         } while ((output_index < max_output_size) && (input_index < (input_size)));
     345             : 
     346           0 :         return output_index;
     347             : }

Generated by: LCOV version 1.13