aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--LICENSE21
-rw-r--r--README.md1
-rw-r--r--bitreader.go129
-rw-r--r--bitreader_test.go103
-rw-r--r--go.mod3
5 files changed, 257 insertions, 0 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..7ea74e1
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
1MIT License
2
3Copyright (c) 2022 Arda Serdar Pektezol
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in all
13copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21SOFTWARE. \ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..a493a1f
--- /dev/null
+++ b/README.md
@@ -0,0 +1 @@
# BitReader
diff --git a/bitreader.go b/bitreader.go
new file mode 100644
index 0000000..9d9a273
--- /dev/null
+++ b/bitreader.go
@@ -0,0 +1,129 @@
1package main
2
3import (
4 "fmt"
5 "math/bits"
6 "strconv"
7 "strings"
8)
9
10type ReaderType struct {
11 data []byte
12 base int
13 index int
14 lsb bool
15}
16
17func Reader(data []byte) *ReaderType {
18 return &ReaderType{
19 data: data,
20 base: 0,
21 index: 0,
22 lsb: false,
23 }
24}
25
26func ReaderLSB(data []byte) *ReaderType {
27 dataReversed := data
28 for index, byteValue := range data {
29 dataReversed[index] = bits.Reverse8(byteValue)
30 }
31 return &ReaderType{
32 data: dataReversed,
33 base: 0,
34 index: 0,
35 lsb: true,
36 }
37}
38
39func (reader *ReaderType) SkipBits(bits int) error {
40 if bits <= 0 {
41 return fmt.Errorf("SkipBits Error: Bits value %d lower or equals than 0.", bits)
42 }
43 for reader.index+bits > 7 {
44 reader.base++
45 reader.index = 0
46 bits -= 8
47 }
48 reader.index += bits
49 return nil
50}
51
52func (reader *ReaderType) ReadBits32(bits int) (int, error) {
53 if bits <= 0 {
54 return -1, fmt.Errorf("ReadBits Error: Bits value %d lower or equals than 0.", bits)
55 }
56 if bits > 32 {
57 return -1, fmt.Errorf("ReadBits Error: Bits value %d higher than 32.", bits)
58 }
59 err := reader.checkAvailableBits(bits)
60 if err != nil {
61 return -1, err
62 }
63 if reader.lsb {
64 var output string
65 // Go to last bit and read backwards from there
66 reader.base += bits / 8
67 reader.index += bits % 8
68 if reader.index > 7 {
69 reader.index -= 8
70 reader.base++
71 }
72 for i := 0; i < bits; i++ {
73 reader.index--
74 if reader.index < 0 {
75 reader.base--
76 reader.index = 7
77 }
78 binary := fmt.Sprintf("%08b", reader.data[reader.base])
79 binaryArr := strings.Split(binary, "")
80 output += binaryArr[reader.index]
81 }
82 // Return to last bit after reading
83 reader.base += bits / 8
84 reader.index += bits % 8
85 if reader.index > 7 {
86 reader.index -= 8
87 }
88 // Conversion of string binary to int
89 value, err := strconv.ParseUint(output, 2, 32)
90 if err != nil {
91 return -1, fmt.Errorf("%s", err)
92 }
93 return int(value), nil
94 } else {
95 var output string
96 for i := 0; i < bits; i++ {
97 binary := fmt.Sprintf("%08b", reader.data[reader.base])
98 binaryArr := strings.Split(binary, "")
99 output += binaryArr[reader.index]
100 reader.index++
101 if reader.index > 7 {
102 reader.base++
103 reader.index = 0
104 }
105 }
106 // Conversion of string binary to int
107 value, err := strconv.ParseUint(output, 2, 32)
108 if err != nil {
109 return -1, fmt.Errorf("%s", err)
110 }
111 return int(value), nil
112 }
113}
114
115func (reader *ReaderType) ReadBit() (bool, error) {
116 value, err := reader.ReadBits32(1)
117 if err != nil {
118 return false, fmt.Errorf("ReadBit Error: %s", err)
119 }
120 return value != 0, nil
121}
122
123func (reader *ReaderType) checkAvailableBits(bits int) error {
124 availableBits := (len(reader.data)-reader.base)*8 - reader.index
125 if availableBits < bits {
126 return fmt.Errorf("BitReaderOutOfBounds: Wanted to read %d bit(s) but only %d bit(s) is/are available.", bits, availableBits)
127 }
128 return nil
129}
diff --git a/bitreader_test.go b/bitreader_test.go
new file mode 100644
index 0000000..c29a3bd
--- /dev/null
+++ b/bitreader_test.go
@@ -0,0 +1,103 @@
1package main
2
3import (
4 "testing"
5)
6
7// 01110001, 00001101, 00000000, 00000000, 10100010, 00011011, 00000000, 00000000, 11001100
8var TestArray = [...]byte{113, 13, 0, 0, 162, 27, 0, 0, 204}
9
10func TestReadBit(t *testing.T) {
11 bitreader := Reader(TestArray[:])
12 expected := []bool{false, true, true, true}
13 for i := range expected {
14 value, err := bitreader.ReadBit()
15 if err != nil {
16 t.Fatal(err)
17 }
18 if value != expected[i] {
19 t.Fatalf("ReadBit FAIL for index %d: Expected %t, Got %t", i, expected[i], value)
20 }
21 }
22}
23
24func TestReadBitLSB(t *testing.T) {
25 bitreader := ReaderLSB(TestArray[:])
26 expected := []bool{true, false, false, false}
27 for i := range expected {
28 value, err := bitreader.ReadBit()
29 if err != nil {
30 t.Fatal(err)
31 }
32 if value != expected[i] {
33 t.Fatalf("ReadBitLSB FAIL for index %d: Expected %t, Got %t", i, expected[i], value)
34 }
35 }
36}
37
38func TestReadBits32(t *testing.T) {
39 bitreader := Reader(TestArray[:])
40 expected := []int{3793354753, 2288779267} // 11100010000110100000000000000001, 10001000011011000000000000000011
41 expectedBool := []bool{false, false}
42 for i := range expected {
43 bool, err := bitreader.ReadBit()
44 if bool != expectedBool[i] {
45 t.Fatalf("ReadBits32 ReadBit FAIL for index %d: Expected %t, Got %t", i, expectedBool[i], bool)
46 }
47 if err != nil {
48 t.Fatal(err)
49 }
50 value, err := bitreader.ReadBits32(32)
51 if err != nil {
52 t.Fatal(err)
53 }
54 if value != expected[i] {
55 t.Fatalf("ReadBits32 FAIL for index %d: Expected %d, Got %d", i, expected[i], value)
56 }
57 }
58}
59
60func TestReadBits32LSB(t *testing.T) {
61 bitreader := ReaderLSB(TestArray[:])
62 expected := []int{1720, 1768} // 11010111000, 11011101000
63 for i := range expected {
64 bitreader.ReadBit()
65 value, err := bitreader.ReadBits32(32)
66 if err != nil {
67 t.Fatal(err)
68 }
69 if value != expected[i] {
70 t.Fatalf("ReadBits32LSB FAIL for index %d: Expected %d, Got %d", i, expected[i], value)
71 }
72 }
73}
74
75func TestSkipBits(t *testing.T) {
76 bitreader := Reader(TestArray[:])
77 expected := []bool{true, true, false, true} //00001101
78 bitreader.SkipBits(12)
79 for i := range expected {
80 value, err := bitreader.ReadBit()
81 if err != nil {
82 t.Fatal(err)
83 }
84 if value != expected[i] {
85 t.Fatalf("SkipBits ReadBit FAIL for index %d: Expected %t, Got %t", i, expected[i], value)
86 }
87 }
88}
89
90func TestSkipBitsLSB(t *testing.T) {
91 bitreader := ReaderLSB(TestArray[:])
92 expected := []bool{false, false, false, false} //10110000
93 bitreader.SkipBits(12)
94 for i := range expected {
95 value, err := bitreader.ReadBit()
96 if err != nil {
97 t.Fatal(err)
98 }
99 if value != expected[i] {
100 t.Fatalf("SkipBits ReadBit FAIL for index %d: Expected %t, Got %t", i, expected[i], value)
101 }
102 }
103}
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..2caf20e
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,3 @@
1module github.com/bisaxa/bitreader
2
3go 1.19