github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/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 }