1
1
import Foundation
2
2
3
- enum BinError : Error {
4
- case outOfBounds
5
- case notString
6
- }
7
-
8
3
public struct Binary {
4
+ /// Stores a reading cursor in bits.
5
+ /// All methods starting with `read` will increment the value of `bitCursor`.
9
6
private var bitCursor : Int
7
+
8
+ /// Stores the binary content.
10
9
var bytesStore : [ UInt8 ]
11
- private let byteSize = 8
12
10
11
+ /// Constant with number of bits in a byte (8)
12
+ private let byteSize = UInt8 . bitWidth
13
+
14
+ /// Initialize a new `Binary`.
13
15
public init ( bytes: [ UInt8 ] ) {
14
16
self . bitCursor = 0
15
17
self . bytesStore = bytes
@@ -36,17 +38,30 @@ public struct Binary {
36
38
return bitCursor + ( bytes * byteSize)
37
39
}
38
40
41
+ /// Increments the `bitCursor`-value by the given `bits`.
42
+ private mutating func incrementCursorBy( bits: Int ) {
43
+ bitCursor = incrementedCursorBy ( bits: bits)
44
+ }
45
+
46
+ /// Increments the `bitCursor`-value by the given `bytes`.
47
+ private mutating func incrementCursorBy( bytes: Int ) {
48
+ bitCursor = incrementedCursorBy ( bytes: bytes)
49
+ }
50
+
39
51
/// Sets the reading cursor back to its initial value.
40
52
public mutating func resetCursor( ) {
41
53
self . bitCursor = 0
42
54
}
43
55
44
- // MARK: - Bit
56
+ // MARK: - Get
57
+
58
+ /// All `get` methods give access to binary data at any given
59
+ /// location — without incrementing the internal cursor.
45
60
46
- /// Returns the binary value `0` or `1` of the given position.
61
+ /// Returns an `UInt8` with the value of 0 or 1 of the given position.
47
62
public func getBit( index: Int ) throws -> UInt8 {
48
63
guard ( 0 ..< ( bytesStore. count) ) . contains ( index / byteSize) else {
49
- throw BinError . outOfBounds
64
+ throw BinaryError . outOfBounds
50
65
}
51
66
let byteCursor = index / byteSize
52
67
let bitindex = 7 - ( index % byteSize)
@@ -56,79 +71,114 @@ public struct Binary {
56
71
/// Returns the `Int`-value of the given range.
57
72
public mutating func getBits( range: Range < Int > ) throws -> Int {
58
73
guard ( 0 ... ( bytesStore. count * byteSize) ) . contains ( range. endIndex) else {
59
- throw BinError . outOfBounds
74
+ throw BinaryError . outOfBounds
60
75
}
61
76
return try range. reversed ( ) . enumerated ( ) . reduce ( 0 ) {
62
77
$0 + Int( try getBit ( index: $1. element) << $1. offset)
63
78
}
64
79
}
65
80
66
- /// Returns the binary value `0` or `1` of the given position and
67
- /// increments the reading cursor by one bit.
68
- public mutating func readBit( ) throws -> UInt8 {
69
- defer { bitCursor = incrementedCursorBy ( bits: 1 ) }
70
- return try getBit ( index: bitCursor)
71
- }
72
-
73
- /// Returns the `Int`-value of the next n-bits (`quantitiy`)
74
- /// and increments the reading cursor by n-bits.
75
- public mutating func readBits( quantitiy: Int ) throws -> Int {
76
- guard ( 0 ... ( bytesStore. count * byteSize) ) . contains ( bitCursor + quantitiy) else {
77
- throw BinError . outOfBounds
78
- }
79
- defer { bitCursor = incrementedCursorBy ( bits: quantitiy) }
80
- return try ( bitCursor..< ( bitCursor + quantitiy) ) . reversed ( ) . enumerated ( ) . reduce ( 0 ) {
81
- $0 + Int( try getBit ( index: $1. element) << $1. offset)
82
- }
83
- }
84
-
85
- // MARK: - Byte
86
-
87
81
/// Returns the `UInt8`-value of the given `index`.
88
82
public func getByte( index: Int ) throws -> UInt8 {
89
83
/// Check if `index` is within bounds of `bytes`
90
84
guard ( 0 ..< ( bytesStore. count) ) . contains ( index) else {
91
- throw BinError . outOfBounds
85
+ throw BinaryError . outOfBounds
92
86
}
93
87
return bytesStore [ index]
94
88
}
95
89
96
90
/// Returns an `[UInt8]` of the given `range`.
97
91
public func getBytes( range: Range < Int > ) throws -> [ UInt8 ] {
98
92
guard ( 0 ... ( bytesStore. count) ) . contains ( range. endIndex) else {
99
- throw BinError . outOfBounds
93
+ throw BinaryError . outOfBounds
100
94
}
101
95
return Array ( bytesStore [ range] )
102
96
}
103
97
104
- /// Returns the `UInt8`-value of the next byte and increments the reading cursor.
98
+ // MARK: - Read
99
+
100
+ /// All `read*` methods return the next requested binary data
101
+ /// and increment an internal cursor (or reading offset) to
102
+ /// the end of the requested data, so the
103
+ /// next `read*`-method can continue from there.
104
+
105
+ /// Returns an `UInt8` with the value of 0 or 1 of the given
106
+ /// position and increments the reading cursor by one bit.
107
+ public mutating func readBit( ) throws -> UInt8 {
108
+ let result = try getBit ( index: bitCursor)
109
+ incrementCursorBy ( bits: 1 )
110
+ return result
111
+ }
112
+
113
+ /// Returns the `Int`-value of the next n-bits (`quantitiy`)
114
+ /// and increments the reading cursor by n-bits.
115
+ public mutating func readBits( quantitiy: Int ) throws -> Int {
116
+ guard ( 0 ... ( bytesStore. count * byteSize) ) . contains ( bitCursor + quantitiy) else {
117
+ throw BinaryError . outOfBounds
118
+ }
119
+ let result = try ( bitCursor..< ( bitCursor + quantitiy) ) . reversed ( ) . enumerated ( ) . reduce ( 0 ) {
120
+ $0 + Int( try getBit ( index: $1. element) << $1. offset)
121
+ }
122
+ incrementCursorBy ( bits: quantitiy)
123
+ return result
124
+ }
125
+
126
+ /// Returns the `UInt8`-value of the next byte and
127
+ /// increments the reading cursor by 1 byte.
105
128
public mutating func readByte( ) throws -> UInt8 {
106
129
let result = try getByte ( index: bitCursor / byteSize)
107
- bitCursor = incrementedCursorBy ( bytes: 1 )
130
+ incrementCursorBy ( bytes: 1 )
108
131
return result
109
132
}
110
133
111
- /// Returns an `[UInt8]` of the next n-bytes (`quantitiy`) and
134
+ /// Returns a `[UInt8]` of the next n-bytes (`quantitiy`) and
112
135
/// increments the reading cursor by n-bytes.
113
136
public mutating func readBytes( quantitiy: Int ) throws -> [ UInt8 ] {
114
137
let byteCursor = bitCursor / byteSize
115
- defer { bitCursor = incrementedCursorBy ( bytes: quantitiy) }
138
+ incrementCursorBy ( bytes: quantitiy)
116
139
return try getBytes ( range: byteCursor..< ( byteCursor + quantitiy) )
117
140
}
118
141
119
- // MARK: - String
142
+ /// Returns a `String` of the next n-bytes (`quantitiy`) and
143
+ /// increments the reading cursor by n-bytes.
120
144
public mutating func readString( quantitiyOfBytes quantitiy: Int , encoding: String . Encoding = . utf8) throws -> String {
121
145
guard let result = String ( bytes: try self . readBytes ( quantitiy: quantitiy) , encoding: encoding) else {
122
- throw BinError . notString
146
+ throw BinaryError . notString
123
147
}
124
148
return result
125
149
}
126
150
127
- public mutating func getCharacter( ) throws -> Character {
151
+ /// Returns the next byte as `Character` and
152
+ /// increments the reading cursor by 1 byte.
153
+ public mutating func readCharacter( ) throws -> Character {
128
154
return Character ( UnicodeScalar ( try readByte ( ) ) )
129
155
}
130
156
157
+ /// Returns the `Bool`-value of the next bit and
158
+ /// increments the reading cursor by 1 bit.
131
159
public mutating func readBool( ) throws -> Bool {
132
160
return try readBit ( ) == 1
133
161
}
162
+
163
+ /// Returns the `UInt8`-value of the next 4 bit and
164
+ /// increments the reading cursor by 4 bits.
165
+ public mutating func readNibble( ) throws -> UInt8 {
166
+ return UInt8 ( try readBits ( quantitiy: 4 ) )
167
+ }
168
+
169
+ // MARK: - Find
170
+
171
+ /// Returns indices of given `[UInt8]`.
172
+ func indices( of sequence: [ UInt8 ] ) -> [ Int ] {
173
+ let size = sequence. count
174
+ return bytesStore. indices. dropLast ( size - 1 ) . filter {
175
+ bytesStore [ $0..< ( $0 + size) ] . elementsEqual ( sequence)
176
+ }
177
+ }
178
+
179
+ /// Returns indices of given `String`.
180
+ func indices( of string: String ) -> [ Int ] {
181
+ let sequence = [ UInt8] ( string. utf8)
182
+ return indices ( of: sequence)
183
+ }
134
184
}
0 commit comments