{-# LANGUAGE OverloadedStrings #-} -- | -- Module : Data.PEM.Parser -- License : BSD-style -- Maintainer : Vincent Hanquez -- Stability : experimental -- Portability : portable -- -- Parse PEM content. -- -- A PEM contains contains from one to many PEM sections. -- Each section contains an optional key-value pair header -- and a binary content encoded in base64. -- module Data.PEM.Parser ( pemParser , pemParseBS , pemParseLBS ) where import Control.Applicative import Data.Attoparsec import qualified Data.Attoparsec.Lazy as AttoLazy import Data.Attoparsec.Char8 (space) import Data.PEM.Types import Data.ByteString (ByteString) import qualified Data.ByteString.Char8 as BC import qualified Data.ByteString.Lazy as L import qualified Data.ByteString.Base64 as Base64 import Prelude hiding (takeWhile) import Data.Serialize.Builder import Data.Monoid -- | parser to get PEM sections pemParser :: Parser [PEM] pemParser = many contextSection where beginMarker = string "-----BEGIN " >> return () endMarker = string "-----END " >> return () skipLine = skipWhile (/= 0xa) >> space >> return () eatLine = takeWhile (/= 0xa) <* space contextSection = manyTill skipLine beginMarker *> section section = do -- begin marker has already been eaten by contextSection name <- takeWhile (/= 0x2d) <* (string "-----" *> space) l <- manyTill eatLine endMarker let content = toByteString $ mconcat $ map (fromByteString . Base64.decodeLenient) l return $ PEM { pemName = BC.unpack name, pemHeader = [], pemContent = content } -- | parse a PEM content using a strict bytestring pemParseBS :: ByteString -> Either String [PEM] pemParseBS = parseOnly pemParser -- | parse a PEM content using a dynamic bytestring pemParseLBS :: L.ByteString -> Either String [PEM] pemParseLBS = AttoLazy.eitherResult . AttoLazy.parse pemParser