github.com/neatio-net/neatio@v1.7.3-0.20231114194659-f4d7a2226baa/utilities/common/bitutil/compress.go (about)

     1  package bitutil
     2  
     3  import "errors"
     4  
     5  var (
     6  	errMissingData = errors.New("missing bytes on input")
     7  
     8  	errUnreferencedData = errors.New("extra bytes on input")
     9  
    10  	errExceededTarget = errors.New("target data size exceeded")
    11  
    12  	errZeroContent = errors.New("zero byte in input content")
    13  )
    14  
    15  func CompressBytes(data []byte) []byte {
    16  	if out := bitsetEncodeBytes(data); len(out) < len(data) {
    17  		return out
    18  	}
    19  	cpy := make([]byte, len(data))
    20  	copy(cpy, data)
    21  	return cpy
    22  }
    23  
    24  func bitsetEncodeBytes(data []byte) []byte {
    25  
    26  	if len(data) == 0 {
    27  		return nil
    28  	}
    29  
    30  	if len(data) == 1 {
    31  		if data[0] == 0 {
    32  			return nil
    33  		}
    34  		return data
    35  	}
    36  
    37  	nonZeroBitset := make([]byte, (len(data)+7)/8)
    38  	nonZeroBytes := make([]byte, 0, len(data))
    39  
    40  	for i, b := range data {
    41  		if b != 0 {
    42  			nonZeroBytes = append(nonZeroBytes, b)
    43  			nonZeroBitset[i/8] |= 1 << byte(7-i%8)
    44  		}
    45  	}
    46  	if len(nonZeroBytes) == 0 {
    47  		return nil
    48  	}
    49  	return append(bitsetEncodeBytes(nonZeroBitset), nonZeroBytes...)
    50  }
    51  
    52  func DecompressBytes(data []byte, target int) ([]byte, error) {
    53  	if len(data) > target {
    54  		return nil, errExceededTarget
    55  	}
    56  	if len(data) == target {
    57  		cpy := make([]byte, len(data))
    58  		copy(cpy, data)
    59  		return cpy, nil
    60  	}
    61  	return bitsetDecodeBytes(data, target)
    62  }
    63  
    64  func bitsetDecodeBytes(data []byte, target int) ([]byte, error) {
    65  	out, size, err := bitsetDecodePartialBytes(data, target)
    66  	if err != nil {
    67  		return nil, err
    68  	}
    69  	if size != len(data) {
    70  		return nil, errUnreferencedData
    71  	}
    72  	return out, nil
    73  }
    74  
    75  func bitsetDecodePartialBytes(data []byte, target int) ([]byte, int, error) {
    76  
    77  	if target == 0 {
    78  		return nil, 0, nil
    79  	}
    80  
    81  	decomp := make([]byte, target)
    82  	if len(data) == 0 {
    83  		return decomp, 0, nil
    84  	}
    85  	if target == 1 {
    86  		decomp[0] = data[0]
    87  		if data[0] != 0 {
    88  			return decomp, 1, nil
    89  		}
    90  		return decomp, 0, nil
    91  	}
    92  
    93  	nonZeroBitset, ptr, err := bitsetDecodePartialBytes(data, (target+7)/8)
    94  	if err != nil {
    95  		return nil, ptr, err
    96  	}
    97  	for i := 0; i < 8*len(nonZeroBitset); i++ {
    98  		if nonZeroBitset[i/8]&(1<<byte(7-i%8)) != 0 {
    99  
   100  			if ptr >= len(data) {
   101  				return nil, 0, errMissingData
   102  			}
   103  			if i >= len(decomp) {
   104  				return nil, 0, errExceededTarget
   105  			}
   106  
   107  			if data[ptr] == 0 {
   108  				return nil, 0, errZeroContent
   109  			}
   110  			decomp[i] = data[ptr]
   111  			ptr++
   112  		}
   113  	}
   114  	return decomp, ptr, nil
   115  }