module Codec.Archive.SAPCAR.BitStream
( BitStream
, makeStream
, getBits
, consume
, getAndConsume
, Codec.Archive.SAPCAR.BitStream.isEmpty
, getRest
) where
import Control.Monad.State.Strict
import Data.Bits
import Data.ByteString
import Data.ByteString.Char8
import Data.Char
import Debug.Trace
data BitStream = BitStreamy
{ bytes :: !ByteString
, number :: !Int
, offset :: !Int
} deriving (Show)
makeStream :: ByteString -> BitStream
makeStream theBytes = BitStreamy
{ bytes=theBytes
, number=0
, offset=0 }
getBits_ :: BitStream -> Int -> (BitStream, Int)
getBits_ stream numBits =
if numBits > offset stream
then getBits_ newStream numBits
else (consumedStream, bits)
where
newStream = stream { number=number stream .|. byte `shiftL` offset stream,
offset=offset stream + 8,
bytes=Data.ByteString.Char8.tail $ bytes stream }
byte = ord . Data.ByteString.Char8.head $ bytes stream
consumedStream = stream
newNumber = if numBits == 32
then 0
else number stream `shiftR` numBits
bits = number stream .&. ((1 `shiftL` numBits) 1)
getBits :: Int -> State BitStream Int
getBits 0 = return 0
getBits numBits = do
stream <- get
let (newstream, result) = getBits_ stream numBits
put newstream
return result
consume_ :: BitStream -> Int -> BitStream
consume_ stream numBits =
stream { offset=offset stream numBits,
number=if numBits == 32
then 0
else number stream `shiftR` numBits }
consume :: Int -> State BitStream ()
consume numBits = do
stream <- get
put $ consume_ stream numBits
getAndConsume_ :: BitStream -> Int -> (BitStream, Int)
getAndConsume_ stream numBits = (newStream, bits)
where
(stream', bits) = getBits_ stream numBits
newStream = consume_ stream' numBits
getAndConsume :: Int -> State BitStream Int
getAndConsume 0 = return 0
getAndConsume numBits = do
stream <- get
let (newstream, bits) = getAndConsume_ stream numBits
put newstream
return bits
isEmpty :: State BitStream Bool
isEmpty = (== empty) . bytes <$> get
getRest :: State BitStream BitStream
getRest = get