-- |
-- Module      : Data.ASN1.BinaryEncoding.Writer
-- License     : BSD-style
-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
-- Stability   : experimental
-- Portability : unknown
--
-- Serialize events for streaming.
--
module Data.ASN1.BinaryEncoding.Writer
    ( toByteString
    , toLazyByteString
    ) where

import Data.ByteString (ByteString)
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as L
import Data.ASN1.Types.Lowlevel
import Data.ASN1.Serialize

-- | transform a list of ASN1 Events into a strict bytestring
toByteString :: [ASN1Event] -> ByteString
toByteString :: [ASN1Event] -> ByteString
toByteString = [ByteString] -> ByteString
B.concat ([ByteString] -> ByteString)
-> ([ASN1Event] -> [ByteString]) -> [ASN1Event] -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [ByteString]
L.toChunks (ByteString -> [ByteString])
-> ([ASN1Event] -> ByteString) -> [ASN1Event] -> [ByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ASN1Event] -> ByteString
toLazyByteString

-- | transform a list of ASN1 Events into a lazy bytestring
toLazyByteString :: [ASN1Event] -> L.ByteString
toLazyByteString :: [ASN1Event] -> ByteString
toLazyByteString [ASN1Event]
evs = [ByteString] -> ByteString
L.fromChunks ([ByteString] -> ByteString) -> [ByteString] -> ByteString
forall a b. (a -> b) -> a -> b
$ [Bool] -> [ASN1Event] -> [ByteString]
loop [] [ASN1Event]
evs
    where loop :: [Bool] -> [ASN1Event] -> [ByteString]
loop [Bool]
_ [] = []
          loop [Bool]
acc (x :: ASN1Event
x@(Header (ASN1Header ASN1Class
_ ASN1Tag
_ Bool
pc ASN1Length
len)):[ASN1Event]
xs) = ASN1Event -> ByteString
toBs ASN1Event
x ByteString -> [ByteString] -> [ByteString]
forall a. a -> [a] -> [a]
: [Bool] -> [ASN1Event] -> [ByteString]
loop (if Bool
pc then (ASN1Length
len ASN1Length -> ASN1Length -> Bool
forall a. Eq a => a -> a -> Bool
== ASN1Length
LenIndefinite)Bool -> [Bool] -> [Bool]
forall a. a -> [a] -> [a]
:[Bool]
acc else [Bool]
acc) [ASN1Event]
xs
          loop [Bool]
acc (ASN1Event
ConstructionEnd:[ASN1Event]
xs) = case [Bool]
acc of
                                              []        -> [Char] -> [ByteString]
forall a. HasCallStack => [Char] -> a
error [Char]
"malformed stream: end before construction"
                                              (Bool
True:[Bool]
r)  -> ASN1Event -> ByteString
toBs ASN1Event
ConstructionEnd ByteString -> [ByteString] -> [ByteString]
forall a. a -> [a] -> [a]
: [Bool] -> [ASN1Event] -> [ByteString]
loop [Bool]
r [ASN1Event]
xs
                                              (Bool
False:[Bool]
r) -> [Bool] -> [ASN1Event] -> [ByteString]
loop [Bool]
r [ASN1Event]
xs
          loop [Bool]
acc (ASN1Event
x:[ASN1Event]
xs) = ASN1Event -> ByteString
toBs ASN1Event
x ByteString -> [ByteString] -> [ByteString]
forall a. a -> [a] -> [a]
: [Bool] -> [ASN1Event] -> [ByteString]
loop [Bool]
acc [ASN1Event]
xs

          toBs :: ASN1Event -> ByteString
toBs (Header ASN1Header
hdr)      = ASN1Header -> ByteString
putHeader ASN1Header
hdr
          toBs (Primitive ByteString
bs)    = ByteString
bs
          toBs ASN1Event
ConstructionBegin = ByteString
B.empty
          toBs ASN1Event
ConstructionEnd   = ByteString
B.empty