ktx-codec-0.0.2.1: src/Codec/Ktx2/DFD.hs
module Codec.Ktx2.DFD where
import Data.Binary (Binary(..))
import Data.Binary.Get (getWord32le, getByteString, isolate)
import Data.Binary.Put (putByteString, putWord32le)
import Data.Bits (shiftR, Bits ((.&.), shiftL, (.|.)))
import Data.ByteString (ByteString)
import Data.Vector (Vector)
import Data.Vector qualified as Vector
import Data.Word (Word32)
import GHC.Generics (Generic)
data DFD = DFD
{ dfdTotalSize :: Word32
, dfdBlocks :: Vector Block
}
deriving (Eq, Show, Generic)
instance Binary DFD where
get = do
dfdTotalSize <- getWord32le
dfdBlocks <- isolate (fromIntegral dfdTotalSize - 4) do
flip Vector.unfoldrM (dfdTotalSize - 4) \case
0 ->
pure Nothing
remaining | remaining < 0 ->
error "reading beyond end of block"
remaining -> do
block <- get
pure $ Just
( block
, remaining - descriptorBlockSize block
)
pure DFD{..}
put DFD{..} = do
putWord32le dfdTotalSize
Vector.mapM_ put dfdBlocks
data Block = Block
{ descriptorType :: Word32
, vendorId :: Word32
, descriptorBlockSize :: Word32
, versionNumber :: Word32
, body :: ByteString
}
deriving (Eq, Show, Generic)
instance Binary Block where
get = do
a <- getWord32le
let
descriptorType = shiftR a 17
vendorId = a .&. 0x0001FFFF
b <- getWord32le
let
descriptorBlockSize = shiftR b 16
versionNumber = b .&. 0x00007FFF
body <- getByteString $ fromIntegral descriptorBlockSize - 8
pure Block{..}
put Block{..} = do
putWord32le $ shiftL descriptorType 17 .|. vendorId
putWord32le $ shiftL descriptorBlockSize 16 .|. versionNumber
putByteString body