11import Foundation
22
3- enum BinError : Error {
4- case outOfBounds
5- case notString
6- }
7-
83public struct Binary {
4+ /// Stores a reading cursor in bits.
5+ /// All methods starting with `read` will increment the value of `bitCursor`.
96 private var bitCursor : Int
7+
8+ /// Stores the binary content.
109 var bytesStore : [ UInt8 ]
11- private let byteSize = 8
1210
11+ /// Constant with number of bits in a byte (8)
12+ private let byteSize = UInt8 . bitWidth
13+
14+ /// Initialize a new `Binary`.
1315 public init ( bytes: [ UInt8 ] ) {
1416 self . bitCursor = 0
1517 self . bytesStore = bytes
@@ -36,17 +38,30 @@ public struct Binary {
3638 return bitCursor + ( bytes * byteSize)
3739 }
3840
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+
3951 /// Sets the reading cursor back to its initial value.
4052 public mutating func resetCursor( ) {
4153 self . bitCursor = 0
4254 }
4355
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.
4560
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.
4762 public func getBit( index: Int ) throws -> UInt8 {
4863 guard ( 0 ..< ( bytesStore. count) ) . contains ( index / byteSize) else {
49- throw BinError . outOfBounds
64+ throw BinaryError . outOfBounds
5065 }
5166 let byteCursor = index / byteSize
5267 let bitindex = 7 - ( index % byteSize)
@@ -56,79 +71,114 @@ public struct Binary {
5671 /// Returns the `Int`-value of the given range.
5772 public mutating func getBits( range: Range < Int > ) throws -> Int {
5873 guard ( 0 ... ( bytesStore. count * byteSize) ) . contains ( range. endIndex) else {
59- throw BinError . outOfBounds
74+ throw BinaryError . outOfBounds
6075 }
6176 return try range. reversed ( ) . enumerated ( ) . reduce ( 0 ) {
6277 $0 + Int( try getBit ( index: $1. element) << $1. offset)
6378 }
6479 }
6580
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-
8781 /// Returns the `UInt8`-value of the given `index`.
8882 public func getByte( index: Int ) throws -> UInt8 {
8983 /// Check if `index` is within bounds of `bytes`
9084 guard ( 0 ..< ( bytesStore. count) ) . contains ( index) else {
91- throw BinError . outOfBounds
85+ throw BinaryError . outOfBounds
9286 }
9387 return bytesStore [ index]
9488 }
9589
9690 /// Returns an `[UInt8]` of the given `range`.
9791 public func getBytes( range: Range < Int > ) throws -> [ UInt8 ] {
9892 guard ( 0 ... ( bytesStore. count) ) . contains ( range. endIndex) else {
99- throw BinError . outOfBounds
93+ throw BinaryError . outOfBounds
10094 }
10195 return Array ( bytesStore [ range] )
10296 }
10397
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.
105128 public mutating func readByte( ) throws -> UInt8 {
106129 let result = try getByte ( index: bitCursor / byteSize)
107- bitCursor = incrementedCursorBy ( bytes: 1 )
130+ incrementCursorBy ( bytes: 1 )
108131 return result
109132 }
110133
111- /// Returns an `[UInt8]` of the next n-bytes (`quantitiy`) and
134+ /// Returns a `[UInt8]` of the next n-bytes (`quantitiy`) and
112135 /// increments the reading cursor by n-bytes.
113136 public mutating func readBytes( quantitiy: Int ) throws -> [ UInt8 ] {
114137 let byteCursor = bitCursor / byteSize
115- defer { bitCursor = incrementedCursorBy ( bytes: quantitiy) }
138+ incrementCursorBy ( bytes: quantitiy)
116139 return try getBytes ( range: byteCursor..< ( byteCursor + quantitiy) )
117140 }
118141
119- // MARK: - String
142+ /// Returns a `String` of the next n-bytes (`quantitiy`) and
143+ /// increments the reading cursor by n-bytes.
120144 public mutating func readString( quantitiyOfBytes quantitiy: Int , encoding: String . Encoding = . utf8) throws -> String {
121145 guard let result = String ( bytes: try self . readBytes ( quantitiy: quantitiy) , encoding: encoding) else {
122- throw BinError . notString
146+ throw BinaryError . notString
123147 }
124148 return result
125149 }
126150
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 {
128154 return Character ( UnicodeScalar ( try readByte ( ) ) )
129155 }
130156
157+ /// Returns the `Bool`-value of the next bit and
158+ /// increments the reading cursor by 1 bit.
131159 public mutating func readBool( ) throws -> Bool {
132160 return try readBit ( ) == 1
133161 }
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+ }
134184}
0 commit comments