{-# LANGUAGE OverloadedStrings #-}
module Binrep.Type.NullTerminated where
import Binrep
import Binrep.Get.Flatparse qualified as Flatparse
import FlatParse.Basic qualified as FP
import Refined
import Refined.Unsafe
import Data.Typeable ( typeRep )
import Data.ByteString qualified as B
import Data.Word ( Word8 )
data NullTerminate
type NullTerminated = Refined NullTerminate
instance NullCheck a => Predicate NullTerminate a where
validate :: Proxy NullTerminate -> a -> Maybe RefineException
validate Proxy NullTerminate
p a
a
| a -> Bool
forall a. NullCheck a => a -> Bool
hasNoNulls a
a = TypeRep -> Text -> Maybe RefineException
throwRefineOtherException (Proxy NullTerminate -> TypeRep
forall {k} (proxy :: k -> Type) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep Proxy NullTerminate
p) (Text -> Maybe RefineException) -> Text -> Maybe RefineException
forall a b. (a -> b) -> a -> b
$
Text
"null byte not permitted in null-terminated data"
| Bool
otherwise = Maybe RefineException
success
class NullCheck a where hasNoNulls :: a -> Bool
instance NullCheck B.ByteString where
{-# INLINE hasNoNulls #-}
hasNoNulls :: ByteString -> Bool
hasNoNulls = (Word8 -> Bool) -> ByteString -> Bool
B.any (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0x00)
instance BLen a => BLen (NullTerminated a) where
blen :: NullTerminated a -> Int
blen NullTerminated a
ra = Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ a -> Int
forall a. BLen a => a -> Int
blen (NullTerminated a -> a
forall {k} (p :: k) x. Refined p x -> x
unrefine NullTerminated a
ra)
{-# INLINE blen #-}
instance Put a => Put (NullTerminated a) where
{-# INLINE put #-}
put :: NullTerminated a -> Poke
put NullTerminated a
a = a -> Poke
forall a. Put a => a -> Poke
put (NullTerminated a -> a
forall {k} (p :: k) x. Refined p x -> x
unrefine NullTerminated a
a) Poke -> Poke -> Poke
forall a. Semigroup a => a -> a -> a
<> forall a. Put a => a -> Poke
put @Word8 Word8
0x00
instance Flatparse.Get (NullTerminated B.ByteString) where
{-# INLINE get #-}
get :: Getter (NullTerminated ByteString)
get = ByteString -> NullTerminated ByteString
forall {k} x (p :: k). x -> Refined p x
reallyUnsafeRefine (ByteString -> NullTerminated ByteString)
-> ParserT PureMode E ByteString
-> Getter (NullTerminated ByteString)
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> ParserT PureMode E ByteString
-> EBase -> ParserT PureMode E ByteString
forall a. Getter a -> EBase -> Getter a
Flatparse.getEBase ParserT PureMode E ByteString
forall (st :: ZeroBitType) e. ParserT st e ByteString
FP.anyCString (String -> EBase
EFailNamed String
"cstring")