aboutsummaryrefslogtreecommitdiff
path: root/bitreader.go
diff options
context:
space:
mode:
authorArda Serdar Pektezol <1669855+BiSaXa@users.noreply.github.com>2022-09-11 10:08:36 +0300
committerGitHub <noreply@github.com>2022-09-11 10:08:36 +0300
commit3afa6d7edf32164e884a247a5a9937ecdaed4f64 (patch)
tree6265637c712678b1e16f4be07326d20dab6dfc0d /bitreader.go
parentMerge pull request #1 from BiSaXa/pull-req-templates (diff)
parentadded go doc (diff)
downloadbitreader-1.1.0.tar.gz
bitreader-1.1.0.tar.bz2
bitreader-1.1.0.zip
Merge pull request #2 from BiSaXa/devv1.1.0
Merge dev branch onto main
Diffstat (limited to 'bitreader.go')
-rw-r--r--bitreader.go281
1 files changed, 189 insertions, 92 deletions
diff --git a/bitreader.go b/bitreader.go
index 06374b8..3fbc221 100644
--- a/bitreader.go
+++ b/bitreader.go
@@ -1,51 +1,146 @@
1// BitReader is a simple bit reader with big/little-endian support for golang.
2// It can read stream data from an io.Reader; can read from os.File and a byte array with bytes.NewReader(array).
3// Uses bitwise operations for v2.
4// Supports reading up to 64 bits at one time.
5// Includes wrapper functions for most used data types.
6// Error checking on all but wrapper functions.
7// Thanks to github.com/mlugg for the big help!
1package bitreader 8package bitreader
2 9
3import ( 10import (
4 "fmt" 11 "fmt"
5 "math/bits" 12 "io"
6 "strconv" 13 "math"
7 "strings"
8) 14)
9 15
16// ReaderType is the main structure of our Reader.
17// Whenever index == 0, we need to read a new byte from stream into curByte
10type ReaderType struct { 18type ReaderType struct {
11 data []byte // Reader data from a byte array 19 stream io.Reader // The underlying stream we're reading bytes from
12 base int // Current reader byte location 20 index uint8 // The current index into the byte [0-7]
13 index int // Current reader index 21 curByte byte // The byte we're currently reading from
14 le bool // Little endian or big endian? 22 le bool // Whether to read in little-endian order
15} 23}
16 24
17func Reader(data []byte, le bool) *ReaderType { 25// Reader is the main constructor that creates the ReaderType object
18 dataClone := data 26// with stream data and little-endian state.
19 if le { 27func Reader(stream io.Reader, le bool) *ReaderType {
20 for index, byteValue := range data {
21 dataClone[index] = bits.Reverse8(byteValue)
22 }
23 }
24 return &ReaderType{ 28 return &ReaderType{
25 data: dataClone, 29 stream: stream,
26 base: 0, 30 index: 0,
27 index: 0, 31 curByte: 0, // Initial value doesn't matter, it'll be read as soon as we try to read any bits
28 le: le, 32 le: le,
29 } 33 }
30} 34}
31 35
32func (reader *ReaderType) SkipBits(bits int) error { 36// TryReadBool is a wrapper function that gets the state of 1-bit,
33 if bits <= 0 { 37// returns true if 1, false if 0. Panics on error.
34 return fmt.Errorf("SkipBits Error: Bits value %d lower or equals than 0.", bits) 38func (reader *ReaderType) TryReadBool() bool {
39 flag, err := reader.ReadBool()
40 if err != nil {
41 panic(err)
42 }
43 return flag
44}
45
46// TryReadInt1 is a wrapper function that returns the value of 1-bit.
47// Returns type uint8. Panics on error.
48func (reader *ReaderType) TryReadInt1() uint8 {
49 value, err := reader.ReadBits(1)
50 if err != nil {
51 panic(err)
52 }
53 return uint8(value)
54}
55
56// TryReadInt8 is a wrapper function that returns the value of 8-bits.
57// Returns uint8. Panics on error.
58func (reader *ReaderType) TryReadInt8() uint8 {
59 value, err := reader.ReadBits(8)
60 if err != nil {
61 panic(err)
62 }
63 return uint8(value)
64}
65
66// TryReadInt16 is a wrapper function that returns the value of 16-bits.
67// Returns uint16. Panics on error.
68func (reader *ReaderType) TryReadInt16() uint16 {
69 value, err := reader.ReadBits(16)
70 if err != nil {
71 panic(err)
72 }
73 return uint16(value)
74}
75
76// TryReadInt32 is a wrapper function that returns the value of 32-bits.
77// Returns uint32. Panics on error.
78func (reader *ReaderType) TryReadInt32() uint32 {
79 value, err := reader.ReadBits(32)
80 if err != nil {
81 panic(err)
82 }
83 return uint32(value)
84}
85
86// TryReadInt64 is a wrapper function that returns the value of 64-bits.
87// Returns uint64. Panics on error.
88func (reader *ReaderType) TryReadInt64() uint64 {
89 value, err := reader.ReadBits(64)
90 if err != nil {
91 panic(err)
92 }
93 return value
94}
95
96// TryReadFloat32 is a wrapper function that returns the value of 32-bits.
97// Returns float32. Panics on error.
98func (reader *ReaderType) TryReadFloat32() float32 {
99 value, err := reader.ReadBits(32)
100 if err != nil {
101 panic(err)
102 }
103 return math.Float32frombits(uint32(value))
104}
105
106// TryReadFloat64 is a wrapper function that returns the value of 64-bits.
107// Returns float64. Panics on error.
108func (reader *ReaderType) TryReadFloat64() float64 {
109 value, err := reader.ReadBits(64)
110 if err != nil {
111 panic(err)
35 } 112 }
36 err := reader.checkAvailableBits(bits) 113 return math.Float64frombits(value)
114}
115
116// SkipBits is a function that increases Reader index
117// based on given input bits number. Returns an error
118// if there are no remaining bits.
119func (reader *ReaderType) SkipBits(bits int) error {
120 // Read as many raw bytes as we can
121 bytes := bits / 8
122 buf := make([]byte, bytes)
123 _, err := reader.stream.Read(buf)
37 if err != nil { 124 if err != nil {
38 return err 125 return err
39 } 126 }
40 for reader.index+bits > 7 { 127 // The final read byte should be the new current byte
41 reader.base++ 128 if bytes > 0 {
42 reader.index = 0 129 reader.curByte = buf[bytes-1]
43 bits -= 8 130 }
131 // Read the extra bits
132 for i := bytes * 8; i < bits; i++ {
133 _, err := reader.readBit()
134 if err != nil {
135 return err
136 }
44 } 137 }
45 reader.index += bits
46 return nil 138 return nil
47} 139}
48 140
141// SkipBytes is a function that increases Reader index
142// based on given input bytes number. Returns an error
143// if there are no remaining bits.
49func (reader *ReaderType) SkipBytes(bytes int) error { 144func (reader *ReaderType) SkipBytes(bytes int) error {
50 err := reader.SkipBits(bytes * 8) 145 err := reader.SkipBits(bytes * 8)
51 if err != nil { 146 if err != nil {
@@ -54,81 +149,83 @@ func (reader *ReaderType) SkipBytes(bytes int) error {
54 return nil 149 return nil
55} 150}
56 151
57func (reader *ReaderType) ReadBits(bits int) (int, error) { 152// ReadBits is a function that reads the specified amount of bits
58 if bits <= 0 { 153// specified in the parameter and returns the value, error
59 return -1, fmt.Errorf("ReadBits Error: Bits value %d lower or equals than 0.", bits) 154// based on the output. It can read up to 64 bits. Returns the read
60 } 155// value in type uint64.
61 if bits > 64 { 156//
62 return -1, fmt.Errorf("ReadBits Error: Bits value %d higher than 64.", bits) 157// Returns an error if there are no remaining bits.
158func (reader *ReaderType) ReadBits(bits int) (uint64, error) {
159 if bits < 1 || bits > 64 {
160 return 0, fmt.Errorf("ReadBits(bits) ERROR: Bits number should be between 1 and 64.")
63 } 161 }
64 err := reader.checkAvailableBits(bits) 162 var val uint64
65 if err != nil { 163 for i := 0; i < bits; i++ {
66 return -1, err 164 bit, err := reader.readBit()
67 }
68 if reader.le {
69 var output string
70 // Go to last bit and read backwards from there
71 reader.base += bits / 8
72 reader.index += bits % 8
73 if reader.index > 7 {
74 reader.index -= 8
75 reader.base++
76 }
77 for i := 0; i < bits; i++ {
78 reader.index--
79 if reader.index < 0 {
80 reader.base--
81 reader.index = 7
82 }
83 binary := fmt.Sprintf("%08b", reader.data[reader.base])
84 binaryArr := strings.Split(binary, "")
85 output += binaryArr[reader.index]
86 }
87 // Return to last bit after reading
88 reader.base += bits / 8
89 reader.index += bits % 8
90 if reader.index > 7 {
91 reader.index -= 8
92 }
93 // Conversion of string binary to int
94 value, err := strconv.ParseUint(output, 2, 64)
95 if err != nil { 165 if err != nil {
96 return -1, fmt.Errorf("%s", err) 166 return 0, err
97 }
98 return int(value), nil
99 } else {
100 var output string
101 for i := 0; i < bits; i++ {
102 binary := fmt.Sprintf("%08b", reader.data[reader.base])
103 binaryArr := strings.Split(binary, "")
104 output += binaryArr[reader.index]
105 reader.index++
106 if reader.index > 7 {
107 reader.base++
108 reader.index = 0
109 }
110 } 167 }
111 // Conversion of string binary to int 168
112 value, err := strconv.ParseUint(output, 2, 64) 169 if reader.le {
113 if err != nil { 170 val |= uint64(bit) << i
114 return -1, fmt.Errorf("%s", err) 171 } else {
172 val |= uint64(bit) << (bits - 1 - i)
115 } 173 }
116 return int(value), nil
117 } 174 }
175 return val, nil
118} 176}
119 177
120func (reader *ReaderType) ReadBit() (bool, error) { 178// ReadBytes is a function that reads the specified amount of bytes
121 value, err := reader.ReadBits(1) 179// specified in the parameter and returns the value, error
180// based on the output. It can read up to 8 bytes. Returns the read
181// value in type uint64.
182//
183// Returns an error if there are no remaining bits.
184func (reader *ReaderType) ReadBytes(bytes int) (uint64, error) {
185 if bytes < 1 || bytes > 8 {
186 return 0, fmt.Errorf("ReadBytes(bytes) ERROR: Bytes number should be between 1 and 8.")
187 }
188 value, err := reader.ReadBits(bytes * 8)
122 if err != nil { 189 if err != nil {
123 return false, fmt.Errorf("ReadBit Error: %s", err) 190 return 0, err
124 } 191 }
125 return value != 0, nil 192 return value, nil
126} 193}
127 194
128func (reader *ReaderType) checkAvailableBits(bits int) error { 195// ReadBool is a function that reads one bit and returns the state, error
129 availableBits := (len(reader.data)-reader.base)*8 - reader.index 196// based on the output. Returns the read value in a bool format.
130 if availableBits < bits { 197//
131 return fmt.Errorf("BitReaderOutOfBounds: Wanted to read/skip %d bit(s) but only %d bit(s) is/are available.", bits, availableBits) 198// Returns an error if there are no remaining bits.
199func (reader *ReaderType) ReadBool() (bool, error) {
200 val, err := reader.readBit()
201 if err != nil {
202 return false, err
203 }
204 return val == 1, nil
205}
206
207// readBit is a private function that reads a single bit from the stream.
208// This is the main function that makes us read stream data.
209func (reader *ReaderType) readBit() (uint8, error) {
210 if reader.index == 0 {
211 // Read a byte from stream into curByte
212 buf := make([]byte, 1)
213 _, err := reader.stream.Read(buf)
214 if err != nil {
215 return 0, err
216 }
217 reader.curByte = buf[0]
218 }
219 var val bool
220 if reader.le {
221 val = (reader.curByte & (1 << reader.index)) != 0
222 } else {
223 val = (reader.curByte & (1 << (7 - reader.index))) != 0
224 }
225 reader.index = (reader.index + 1) % 8
226 if val {
227 return 1, nil
228 } else {
229 return 0, nil
132 } 230 }
133 return nil
134} 231}