{-# 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 ([ByteString] -> ByteString) -> [ByteString] -> ByteString
forall a b. (a -> b) -> a -> b
$ ([ByteString
begin,ByteString
header][ByteString] -> [ByteString] -> [ByteString]
forall a. [a] -> [a] -> [a]
++[ByteString]
section[ByteString] -> [ByteString] -> [ByteString]
forall 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 = (ByteString -> ByteString) -> [ByteString] -> [ByteString]
forall a b. (a -> b) -> [a] -> [b]
map ByteString -> ByteString
forall bin. ByteArrayAccess bin => bin -> ByteString
encodeLine ([ByteString] -> [ByteString]) -> [ByteString] -> [ByteString]
forall a b. (a -> b) -> a -> b
$ ByteString -> [ByteString]
splitChunks (ByteString -> [ByteString]) -> ByteString -> [ByteString]
forall a b. (a -> b) -> a -> b
$ PEM -> ByteString
pemContent PEM
pem
          header :: ByteString
          header :: ByteString
header  = if [(String, ByteString)] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([(String, ByteString)] -> Bool) -> [(String, ByteString)] -> Bool
forall a b. (a -> b) -> a -> b
$ PEM -> [(String, ByteString)]
pemHeader PEM
pem
                        then ByteString
B.empty
                        else [ByteString] -> ByteString
B.concat ((((String, ByteString) -> [ByteString])
-> [(String, ByteString)] -> [ByteString]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (String, ByteString) -> [ByteString]
toHeader (PEM -> [(String, ByteString)]
pemHeader PEM
pem)) [ByteString] -> [ByteString] -> [ByteString]
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 (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ PEM -> String
pemName PEM
pem
          encodeLine :: bin -> ByteString
encodeLine bin
l = Base -> bin -> ByteString
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 Int -> Int -> Bool
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 ByteString -> [ByteString] -> [ByteString]
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 ([ByteString] -> ByteString)
-> (PEM -> [ByteString]) -> PEM -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [ByteString]
L.toChunks (ByteString -> [ByteString])
-> (PEM -> ByteString) -> PEM -> [ByteString]
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