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 . 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