module Binrep.Example.Tar where

import Binrep
import Binrep.Generic
import Binrep.Type.NullPadded
import Binrep.Type.AsciiNat

import GHC.Generics ( Generic )

import Data.Word ( Word8 )

import GHC.TypeNats

import Data.ByteString qualified as B

import FlatParse.Basic qualified as FP

type BS = B.ByteString

-- | The naturals in tars are sized octal ASCII digit strings that end with a
--   null byte (and may start with leading ASCII zeroes). The size includes the
--   terminating null, so you get @n-1@ digits. What a farce.
--
-- Don't use this constructor directly! The size must be checked to ensure it
-- fits.
newtype TarNat n = TarNat { forall {k} (n :: k). TarNat n -> AsciiNat 8
getTarNat :: AsciiNat 8 }
    deriving stock (forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall k (n :: k) x. Rep (TarNat n) x -> TarNat n
forall k (n :: k) x. TarNat n -> Rep (TarNat n) x
$cto :: forall k (n :: k) x. Rep (TarNat n) x -> TarNat n
$cfrom :: forall k (n :: k) x. TarNat n -> Rep (TarNat n) x
Generic, Int -> TarNat n -> ShowS
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall k (n :: k). Int -> TarNat n -> ShowS
forall k (n :: k). [TarNat n] -> ShowS
forall k (n :: k). TarNat n -> String
showList :: [TarNat n] -> ShowS
$cshowList :: forall k (n :: k). [TarNat n] -> ShowS
show :: TarNat n -> String
$cshow :: forall k (n :: k). TarNat n -> String
showsPrec :: Int -> TarNat n -> ShowS
$cshowsPrec :: forall k (n :: k). Int -> TarNat n -> ShowS
Show, TarNat n -> TarNat n -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall k (n :: k). TarNat n -> TarNat n -> Bool
/= :: TarNat n -> TarNat n -> Bool
$c/= :: forall k (n :: k). TarNat n -> TarNat n -> Bool
== :: TarNat n -> TarNat n -> Bool
$c== :: forall k (n :: k). TarNat n -> TarNat n -> Bool
Eq)

instance KnownNat n => BLen (TarNat n) where
    type CBLen (TarNat n) = n

-- | No need to check for underflow etc. as TarNat guarantees good sizing.
instance KnownNat n => Put (TarNat n) where
    put :: TarNat n -> Builder
put (TarNat AsciiNat 8
an) = forall a. Put a => a -> Builder
put ByteString
pfxNulls forall a. Semigroup a => a -> a -> a
<> forall a. Put a => a -> Builder
put AsciiNat 8
an forall a. Semigroup a => a -> a -> a
<> forall a. Put a => a -> Builder
put @Word8 Word8
0x00
      where
        pfxNulls :: ByteString
pfxNulls = Int -> Word8 -> ByteString
B.replicate (forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
pfxNullCount) Word8
0x30
        pfxNullCount :: Int
pfxNullCount = Int
n forall a. Num a => a -> a -> a
- forall a. BLen a => a -> Int
blen AsciiNat 8
an forall a. Num a => a -> a -> a
- Int
1
        n :: Int
n = forall (n :: Nat). KnownNat n => Int
typeNatToBLen @n

instance KnownNat n => Get (TarNat n) where
    get :: Getter (TarNat n)
get = do
        AsciiNat 8
an <- forall e a. Int -> Parser e a -> Parser e a
FP.isolate (forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
n forall a. Num a => a -> a -> a
- Int
1)) forall a. Get a => Getter a
get
        forall a. Get a => Getter a
get @Word8 forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
          Word8
0x00 -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall {k} (n :: k). AsciiNat 8 -> TarNat n
TarNat AsciiNat 8
an
          Word8
w    -> forall a. EBase -> Getter a
eBase forall a b. (a -> b) -> a -> b
$ Word8 -> Word8 -> EBase
EExpectedByte Word8
0x00 Word8
w
      where
        n :: Int
n = forall (n :: Nat). KnownNat n => Int
typeNatToBLen @n

-- Partial header
data Tar = Tar
  { Tar -> NullPadded 100 ByteString
tarFileName :: NullPadded 100 BS
  , Tar -> TarNat 8
tarFileMode :: TarNat 8
  , Tar -> TarNat 8
tarFileUIDOwner :: TarNat 8
  , Tar -> TarNat 8
tarFileUIDGroup :: TarNat 8
  , Tar -> TarNat 12
tarFileFileSize :: TarNat 12
  , Tar -> TarNat 12
tarFileLastMod :: TarNat 12
  } deriving stock (forall x. Rep Tar x -> Tar
forall x. Tar -> Rep Tar x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Tar x -> Tar
$cfrom :: forall x. Tar -> Rep Tar x
Generic, Int -> Tar -> ShowS
[Tar] -> ShowS
Tar -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Tar] -> ShowS
$cshowList :: [Tar] -> ShowS
show :: Tar -> String
$cshow :: Tar -> String
showsPrec :: Int -> Tar -> ShowS
$cshowsPrec :: Int -> Tar -> ShowS
Show, Tar -> Tar -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Tar -> Tar -> Bool
$c/= :: Tar -> Tar -> Bool
== :: Tar -> Tar -> Bool
$c== :: Tar -> Tar -> Bool
Eq)

instance BLen Tar where blen :: Tar -> Int
blen = forall a w. (Generic a, GBLen (Rep a), BLen w) => Cfg w -> a -> Int
blenGeneric Cfg Void
cNoSum
instance Put  Tar where put :: Tar -> Builder
put  = forall a w.
(Generic a, GPut (Rep a), Put w) =>
Cfg w -> a -> Builder
putGeneric  Cfg Void
cNoSum
instance Get  Tar where get :: Getter Tar
get  = forall a w. (Generic a, GGetD (Rep a), Get w) => Cfg w -> Getter a
getGeneric  Cfg Void
cNoSum