{-# LANGUAGE OverloadedStrings #-}
-- |
-- Module      : Data.PEM.Writer
-- License     : BSD-style
-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
-- Stability   : experimental
-- Portability : portable
--
module Data.PEM.Writer
    ( pemWriteLBS
    , pemWriteBS
    ) where

import Data.PEM.Types
import Data.ByteString (ByteString)
import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as BC
import qualified Data.ByteString.Lazy as L
import           Data.ByteArray.Encoding (Base(Base64), convertToBase)

-- | write a PEM structure to a builder
pemWrite :: PEM -> L.ByteString
pemWrite :: PEM -> ByteString
pemWrite PEM
pem = [ByteString] -> ByteString
L.fromChunks forall a b. (a -> b) -> a -> b
$ ([ByteString
begin,ByteString
header]forall a. [a] -> [a] -> [a]
++[ByteString]
sectionforall a. [a] -> [a] -> [a]
++[ByteString
end])
    where begin :: ByteString
begin   = [ByteString] -> ByteString
B.concat [ByteString
"-----BEGIN ", ByteString
sectionName, ByteString
"-----\n"]
          end :: ByteString
end     = [ByteString] -> ByteString
B.concat [ByteString
"-----END ", ByteString
sectionName, ByteString
"-----\n" ]
          section :: [ByteString]
          section :: [ByteString]
section = forall a b. (a -> b) -> [a] -> [b]
map forall {bin}. ByteArrayAccess bin => bin -> ByteString
encodeLine forall a b. (a -> b) -> a -> b
$ ByteString -> [ByteString]
splitChunks forall a b. (a -> b) -> a -> b
$ PEM -> ByteString
pemContent PEM
pem
          header :: ByteString
          header :: ByteString
header  = if forall (t :: * -> *) a. Foldable t => t a -> Bool
null forall a b. (a -> b) -> a -> b
$ PEM -> [(String, ByteString)]
pemHeader PEM
pem
                        then ByteString
B.empty
                        else [ByteString] -> ByteString
B.concat ((forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (String, ByteString) -> [ByteString]
toHeader (PEM -> [(String, ByteString)]
pemHeader PEM
pem)) forall a. [a] -> [a] -> [a]
++ [ByteString
"\n"])
          toHeader :: (String, ByteString) -> [ByteString]
          toHeader :: (String, ByteString) -> [ByteString]
toHeader (String
k,ByteString
v) = [ String -> ByteString
BC.pack String
k, ByteString
":", ByteString
v, ByteString
"\n" ]
          -- expect only ASCII. need to find a type to represent it.
          sectionName :: ByteString
sectionName = String -> ByteString
BC.pack forall a b. (a -> b) -> a -> b
$ PEM -> String
pemName PEM
pem
          encodeLine :: bin -> ByteString
encodeLine bin
l = forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
Base -> bin -> bout
convertToBase Base
Base64 bin
l ByteString -> ByteString -> ByteString
`B.append` ByteString
"\n"

          splitChunks :: ByteString -> [ByteString]
splitChunks ByteString
b
                  | ByteString -> Int
B.length ByteString
b forall a. Ord a => a -> a -> Bool
> Int
48 = let (ByteString
x,ByteString
y) = Int -> ByteString -> (ByteString, ByteString)
B.splitAt Int
48 ByteString
b in ByteString
x forall a. a -> [a] -> [a]
: ByteString -> [ByteString]
splitChunks ByteString
y
                  | Bool
otherwise       = [ByteString
b]

-- | convert a PEM structure to a bytestring
pemWriteBS :: PEM -> ByteString
pemWriteBS :: PEM -> ByteString
pemWriteBS = [ByteString] -> ByteString
B.concat forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [ByteString]
L.toChunks forall b c a. (b -> c) -> (a -> b) -> a -> c
. PEM -> ByteString
pemWrite

-- | convert a PEM structure to a lazy bytestring
pemWriteLBS :: PEM -> L.ByteString
pemWriteLBS :: PEM -> ByteString
pemWriteLBS = PEM -> ByteString
pemWrite