aboutsummaryrefslogtreecommitdiff
path: root/src/bitreader.nim
diff options
context:
space:
mode:
Diffstat (limited to 'src/bitreader.nim')
-rw-r--r--src/bitreader.nim52
1 files changed, 18 insertions, 34 deletions
diff --git a/src/bitreader.nim b/src/bitreader.nim
index 757c1b3..7afb13d 100644
--- a/src/bitreader.nim
+++ b/src/bitreader.nim
@@ -17,49 +17,33 @@
17import streams 17import streams
18import integers 18import integers
19 19
20# Stream functions
21
22proc newEIO(msg: string): ref IOError =
23 new(result)
24 result.msg = msg
25
26proc read[T](s: Stream, t: typedesc[T]): T =
27 if readData(s, addr(result), sizeof(T)) != sizeof(T):
28 raise newEIO("cannot read from stream")
29
30proc peek[T](s: Stream, t: typedesc[T]): T =
31 if peekData(s, addr(result), sizeof(T)) != sizeof(T):
32 raise newEIO("cannot read from stream")
33
34# BitReader
35
36type BitReader* = ref object 20type BitReader* = ref object
37 stream: Stream 21 stream: Stream
38 bitOffset: int 22 bitOffset: int
23 overflowBuffer: uint8
39 24
40proc bitReader*(stream: Stream): BitReader = 25proc bitReader*(stream: Stream): BitReader =
41 BitReader(stream: stream, bitOffset: 0) 26 BitReader(stream: stream, bitOffset: 0, overflowBuffer: 0)
42 27
43proc atEnd*(bitReader: BitReader): bool = 28proc atEnd*(bitReader: BitReader): bool =
44 bitReader.stream.atEnd() 29 bitReader.bitOffset == 0 and bitReader.stream.atEnd()
45 30
46proc readBits*[T: SomeUnsignedInt](bitReader: BitReader, bits: int, to: typedesc[T]): T = 31proc readBits*[T: SomeUnsignedInt](bitReader: BitReader, bits: int, to: typedesc[T]): T =
47 let targetBitLength = sizeof(T) * wordBitLength 32 if bits < 0 or bits > sizeof(T) * wordBitLength: raise newException(RangeError, "invalid bit length")
48 if bits < 0 or bits > targetBitLength: 33 if bits == 0: return 0
49 raise newException(RangeError, "invalid bit length") 34 var bitsRead = 0
50 elif bits == 0: 35 if bitReader.bitOffset > 0:
51 result = 0 36 let bitsFromBuffer = min(bits, wordBitLength - bitReader.bitOffset)
52 elif bits < targetBitLength - bitReader.bitOffset: 37 result = (bitReader.overflowBuffer shr bitReader.bitOffset).leastSignificantBits(bitsFromBuffer)
53 result = bitReader.stream.peek(T) shl (targetBitLength - bits - bitReader.bitOffset) shr (targetBitLength - bits) 38 bitReader.bitOffset = (bitReader.bitOffset + bitsFromBuffer) mod wordBitLength
54 elif bits == targetBitLength - bitReader.bitOffset: 39 bitsRead += bitsFromBuffer
55 result = bitReader.stream.read(T) shl (targetBitLength - bits - bitReader.bitOffset) shr (targetBitLength - bits) 40 while bits - bitsRead >= wordBitLength:
56 else: 41 result = result or (bitReader.stream.readUint8().T shl bitsRead)
57 let rightBits = targetBitLength - bitReader.bitOffset 42 bitsRead += wordBitLength
58 let leftBits = bits - rightBits 43 if bits - bitsRead > 0:
59 let right = bitReader.stream.read(T) shr bitReader.bitOffset 44 bitReader.overflowBuffer = bitReader.stream.readUint8()
60 let left = bitReader.stream.peek(T) shl (targetBitLength - leftBits) shr (targetBitLength - bits) 45 bitReader.bitOffset = bits - bitsRead
61 result = left or right 46 result = result or (bitReader.overflowBuffer.leastSignificantBits(bitReader.bitOffset).T shl bitsRead)
62 bitReader.bitOffset = (bitReader.bitOffset + bits) mod wordBitLength
63 47
64proc readBool*(bitReader: BitReader): bool = 48proc readBool*(bitReader: BitReader): bool =
65 bitReader.readBits(1, uint8) != 0 49 bitReader.readBits(1, uint8) != 0