github.com/bodgit/sevenzip@v1.5.1/internal/bra/bcj.go (about) 1 package bra 2 3 import ( 4 "encoding/binary" 5 "io" 6 ) 7 8 const bcjLookAhead = 4 9 10 type bcj struct { 11 ip, state uint32 12 } 13 14 func (c *bcj) Size() int { return bcjLookAhead + 1 } 15 16 func test86MSByte(b byte) bool { 17 return (b+1)&0xfe == 0 18 } 19 20 //nolint:cyclop,funlen,gocognit 21 func (c *bcj) Convert(b []byte, encoding bool) int { 22 if len(b) < c.Size() { 23 return 0 24 } 25 26 var ( 27 pos int 28 mask = c.state & 7 29 ) 30 31 for { 32 p := pos 33 for ; p < len(b)-bcjLookAhead; p++ { 34 if b[p]&0xfe == 0xe8 { 35 break 36 } 37 } 38 39 d := p - pos 40 pos = p 41 42 if p >= len(b)-bcjLookAhead { 43 if d > 2 { 44 c.state = 0 45 } else { 46 c.state = mask >> d 47 } 48 49 c.ip += uint32(pos) 50 51 return pos 52 } 53 54 if d > 2 { 55 mask = 0 56 } else { 57 mask >>= d 58 if mask != 0 && (mask > 4 || mask == 3 || test86MSByte(b[p+int(mask>>1)+1])) { 59 mask = (mask >> 1) | 4 60 pos++ 61 62 continue 63 } 64 } 65 66 //nolint:nestif 67 if test86MSByte(b[p+4]) { 68 v := binary.LittleEndian.Uint32(b[p+1:]) 69 cur := c.ip + uint32(c.Size()+pos) 70 pos += c.Size() 71 72 if encoding { 73 v += cur 74 } else { 75 v -= cur 76 } 77 78 if mask != 0 { 79 sh := mask & 6 << 2 80 if test86MSByte(byte(v >> sh)) { 81 v ^= (uint32(0x100) << sh) - 1 82 if encoding { 83 v += cur 84 } else { 85 v -= cur 86 } 87 } 88 89 mask = 0 90 } 91 92 binary.LittleEndian.PutUint32(b[p+1:], v) 93 b[p+4] = 0 - b[p+4]&1 94 } else { 95 mask = (mask >> 1) | 4 96 pos++ 97 } 98 } 99 } 100 101 // NewBCJReader returns a new BCJ io.ReadCloser. 102 func NewBCJReader(_ []byte, _ uint64, readers []io.ReadCloser) (io.ReadCloser, error) { 103 return newReader(readers, new(bcj)) 104 }