{-# LANGUAGE BangPatterns #-} {-# LANGUAGE MagicHash #-} module Codec.Compression.Zlib.Adler32 ( AdlerState, initialAdlerState, advanceAdler, advanceAdlerBlock, finalizeAdler, ) where import Data.Bits (shiftL, (.|.)) import qualified Data.ByteString as S import GHC.Exts (Word#, plusWord#, remWord#) import GHC.Word (Word32 (..), Word8 (..)) data AdlerState = AdlerState {_adlerA :: Word#, _adlerB :: Word#} initialAdlerState :: AdlerState initialAdlerState = AdlerState 1## 0## advanceAdler :: AdlerState -> Word8 -> AdlerState advanceAdler (AdlerState a b) (W8# v) = AdlerState a' b' where a' = (a `plusWord#` v) `remWord#` 65521## b' = (b `plusWord#` a') `remWord#` 65521## {-# INLINE advanceAdler #-} advanceNoMod :: AdlerState -> Word8 -> AdlerState advanceNoMod (AdlerState a b) (W8# v) = AdlerState a' b' where a' = a `plusWord#` v b' = b `plusWord#` a' {-# INLINE advanceNoMod #-} -- The block must be less than 5552 bytes long in this case advanceAdlerLimited :: AdlerState -> S.ByteString -> AdlerState advanceAdlerLimited !state !bl = AdlerState stateA' stateB' where !(AdlerState stateA stateB) = S.foldl' advanceNoMod state bl stateA' = stateA `remWord#` 65521## stateB' = stateB `remWord#` 65521## advanceAdlerBlock :: AdlerState -> S.ByteString -> AdlerState advanceAdlerBlock !state !bl | S.length bl == 0 = state | S.length bl == 1 = advanceAdler state (S.head bl) | S.length bl < 5552 = advanceAdlerLimited state bl | otherwise = advanceAdlerBlock (advanceAdlerBlock state first5551) rest where (!first5551, !rest) = S.splitAt 5551 bl finalizeAdler :: AdlerState -> Word32 finalizeAdler (AdlerState a b) = high .|. low where high = (W32# b) `shiftL` 16 low = W32# a