github.com/bluenviron/mediacommon@v1.9.3/pkg/bits/read.go (about) 1 // Package bits contains functions to read/write bits from/to buffers. 2 package bits 3 4 import ( 5 "fmt" 6 ) 7 8 // HasSpace checks whether buffer has space for N bits. 9 func HasSpace(buf []byte, pos int, n int) error { 10 if n > ((len(buf) * 8) - pos) { 11 return fmt.Errorf("not enough bits") 12 } 13 return nil 14 } 15 16 // ReadBits reads N bits. 17 func ReadBits(buf []byte, pos *int, n int) (uint64, error) { 18 err := HasSpace(buf, *pos, n) 19 if err != nil { 20 return 0, err 21 } 22 23 return ReadBitsUnsafe(buf, pos, n), nil 24 } 25 26 // ReadBitsUnsafe reads N bits. 27 func ReadBitsUnsafe(buf []byte, pos *int, n int) uint64 { 28 v := uint64(0) 29 30 res := 8 - (*pos & 0x07) 31 if n < res { 32 v := uint64((buf[*pos>>0x03] >> (res - n)) & (1<<n - 1)) 33 *pos += n 34 return v 35 } 36 37 v = (v << res) | uint64(buf[*pos>>0x03]&(1<<res-1)) 38 *pos += res 39 n -= res 40 41 for n >= 8 { 42 v = (v << 8) | uint64(buf[*pos>>0x03]) 43 *pos += 8 44 n -= 8 45 } 46 47 if n > 0 { 48 v = (v << n) | uint64(buf[*pos>>0x03]>>(8-n)) 49 *pos += n 50 } 51 52 return v 53 } 54 55 // ReadGolombUnsigned reads an unsigned golomb-encoded value. 56 func ReadGolombUnsigned(buf []byte, pos *int) (uint32, error) { 57 buflen := len(buf) 58 leadingZeroBits := uint32(0) 59 60 for { 61 if (buflen*8 - *pos) == 0 { 62 return 0, fmt.Errorf("not enough bits") 63 } 64 65 b := (buf[*pos>>0x03] >> (7 - (*pos & 0x07))) & 0x01 66 *pos++ 67 if b != 0 { 68 break 69 } 70 71 leadingZeroBits++ 72 if leadingZeroBits > 32 { 73 return 0, fmt.Errorf("invalid value") 74 } 75 } 76 77 if (buflen*8 - *pos) < int(leadingZeroBits) { 78 return 0, fmt.Errorf("not enough bits") 79 } 80 81 codeNum := uint32(0) 82 83 for n := leadingZeroBits; n > 0; n-- { 84 b := (buf[*pos>>0x03] >> (7 - (*pos & 0x07))) & 0x01 85 *pos++ 86 codeNum |= uint32(b) << (n - 1) 87 } 88 89 codeNum = (1 << leadingZeroBits) - 1 + codeNum 90 91 return codeNum, nil 92 } 93 94 // ReadGolombSigned reads a signed golomb-encoded value. 95 func ReadGolombSigned(buf []byte, pos *int) (int32, error) { 96 v, err := ReadGolombUnsigned(buf, pos) 97 if err != nil { 98 return 0, err 99 } 100 101 vi := int32(v) 102 if (vi & 0x01) != 0 { 103 return (vi + 1) / 2, nil 104 } 105 return -vi / 2, nil 106 } 107 108 // ReadFlag reads a boolean flag. 109 func ReadFlag(buf []byte, pos *int) (bool, error) { 110 err := HasSpace(buf, *pos, 1) 111 if err != nil { 112 return false, err 113 } 114 115 return ReadFlagUnsafe(buf, pos), nil 116 } 117 118 // ReadFlagUnsafe reads a boolean flag. 119 func ReadFlagUnsafe(buf []byte, pos *int) bool { 120 b := (buf[*pos>>0x03] >> (7 - (*pos & 0x07))) & 0x01 121 *pos++ 122 return b == 1 123 }