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  }