github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/common/bitutil/compress.go (about) 1 2 //此源码被清华学神尹成大魔王专业翻译分析并修改 3 //尹成QQ77025077 4 //尹成微信18510341407 5 //尹成所在QQ群721929980 6 //尹成邮箱 yinc13@mails.tsinghua.edu.cn 7 //尹成毕业于清华大学,微软区块链领域全球最有价值专家 8 //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620 9 //版权所有2017 Go Ethereum作者 10 //此文件是Go以太坊库的一部分。 11 // 12 //Go-Ethereum库是免费软件:您可以重新分发它和/或修改 13 //根据GNU发布的较低通用公共许可证的条款 14 //自由软件基金会,或者许可证的第3版,或者 15 //(由您选择)任何更高版本。 16 // 17 //Go以太坊图书馆的发行目的是希望它会有用, 18 //但没有任何保证;甚至没有 19 //适销性或特定用途的适用性。见 20 //GNU较低的通用公共许可证,了解更多详细信息。 21 // 22 //你应该收到一份GNU较低级别的公共许可证副本 23 //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。 24 25 package bitutil 26 27 import "errors" 28 29 var ( 30 //如果引用的字节 31 // 32 errMissingData = errors.New("missing bytes on input") 33 34 //如果没有使用所有字节,则从解压返回errunreferenceddata。 35 //在对输入数据进行解压缩之后。 36 errUnreferencedData = errors.New("extra bytes on input") 37 38 //如果位集头具有 39 //定义的比特数多于可用的目标缓冲区空间数。 40 errExceededTarget = errors.New("target data size exceeded") 41 42 //如果中引用了数据字节,则从解压缩返回errZeroContent。 43 //位集头实际上是一个零字节。 44 errZeroContent = errors.New("zero byte in input content") 45 ) 46 47 //由compressBytes和compressBytes实现的压缩算法是 48 //针对包含大量零字节的稀疏输入数据进行了优化。减压 49 //需要解压数据长度的知识。 50 // 51 //压缩工程如下: 52 // 53 //如果数据只包含零, 54 //compressbytes(data)==nil 55 //否则,如果len(data)<=1, 56 //compressBytes(data)==数据 57 //否则: 58 //compressbytes(data)==附加(compressbytes(nonzerobitset(data)),nonzerobytes(data)…) 59 //哪里 60 //非零位集(data)是一个带有len(data)位(msb first)的位向量: 61 //非零位集(数据)[I/8]&&(1<(7-I%8))!=0,如果数据[i]!= 0 62 //len(非零位集(数据))==(len(数据)+7)/8 63 //非零字节(数据)包含相同顺序的非零字节数据 64 65 //compressBytes根据稀疏位集压缩输入字节片 66 //表示算法。如果结果大于原始输入,则不 67 // 68 func CompressBytes(data []byte) []byte { 69 if out := bitsetEncodeBytes(data); len(out) < len(data) { 70 return out 71 } 72 cpy := make([]byte, len(data)) 73 copy(cpy, data) 74 return cpy 75 } 76 77 //bitsetEncodeBytes根据稀疏数据压缩输入字节片 78 // 79 func bitsetEncodeBytes(data []byte) []byte { 80 //空切片压缩为零 81 if len(data) == 0 { 82 return nil 83 } 84 //单字节片压缩为零或保留单字节 85 if len(data) == 1 { 86 if data[0] == 0 { 87 return nil 88 } 89 return data 90 } 91 //计算集合字节的位集,并收集非零字节 92 nonZeroBitset := make([]byte, (len(data)+7)/8) 93 nonZeroBytes := make([]byte, 0, len(data)) 94 95 for i, b := range data { 96 if b != 0 { 97 nonZeroBytes = append(nonZeroBytes, b) 98 nonZeroBitset[i/8] |= 1 << byte(7-i%8) 99 } 100 } 101 if len(nonZeroBytes) == 0 { 102 return nil 103 } 104 return append(bitsetEncodeBytes(nonZeroBitset), nonZeroBytes...) 105 } 106 107 //解压缩字节用已知的目标大小解压缩数据。如果输入数据 108 //匹配目标的大小,这意味着在第一个压缩过程中没有进行压缩 109 //地点。 110 func DecompressBytes(data []byte, target int) ([]byte, error) { 111 if len(data) > target { 112 return nil, errExceededTarget 113 } 114 if len(data) == target { 115 cpy := make([]byte, len(data)) 116 copy(cpy, data) 117 return cpy, nil 118 } 119 return bitsetDecodeBytes(data, target) 120 } 121 122 //bitsetdecodebytes用已知的目标大小解压缩数据。 123 func bitsetDecodeBytes(data []byte, target int) ([]byte, error) { 124 out, size, err := bitsetDecodePartialBytes(data, target) 125 if err != nil { 126 return nil, err 127 } 128 if size != len(data) { 129 return nil, errUnreferencedData 130 } 131 return out, nil 132 } 133 134 //BitsetDecodePartialBytes以已知的目标大小解压缩数据,但确实如此 135 //不强制使用所有输入字节。除了减压 136 //输出,函数返回相应的压缩输入数据的长度 137 //因为输入片可能更长。 138 func bitsetDecodePartialBytes(data []byte, target int) ([]byte, int, error) { 139 //健全性检查0个目标以避免无限递归 140 if target == 0 { 141 return nil, 0, nil 142 } 143 //处理零和单字节角情况 144 decomp := make([]byte, target) 145 if len(data) == 0 { 146 return decomp, 0, nil 147 } 148 if target == 1 { 149 decomp[0] = data[0] //复制以避免引用输入切片 150 if data[0] != 0 { 151 return decomp, 1, nil 152 } 153 return decomp, 0, nil 154 } 155 //解压集合字节的位集并分配非零字节 156 nonZeroBitset, ptr, err := bitsetDecodePartialBytes(data, (target+7)/8) 157 if err != nil { 158 return nil, ptr, err 159 } 160 for i := 0; i < 8*len(nonZeroBitset); i++ { 161 if nonZeroBitset[i/8]&(1<<byte(7-i%8)) != 0 { 162 //确保我们有足够的数据插入正确的插槽 163 if ptr >= len(data) { 164 return nil, 0, errMissingData 165 } 166 if i >= len(decomp) { 167 return nil, 0, errExceededTarget 168 } 169 //确保数据有效并推入插槽 170 if data[ptr] == 0 { 171 return nil, 0, errZeroContent 172 } 173 decomp[i] = data[ptr] 174 ptr++ 175 } 176 } 177 return decomp, ptr, nil 178 }