pem-0.1.0: Data/PEM/Parser.hs
{-# LANGUAGE OverloadedStrings #-}
-- |
-- Module : Data.PEM.Parser
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- 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