{-# LANGUAGE OverloadedStrings #-}
-- ASCIIArmor/Decode.hs: OpenPGP (RFC4880) ASCII armor implementation
-- Copyright © 2012-2018  Clint Adams
-- This software is released under the terms of the Expat license.
-- (See the LICENSE file).

module Codec.Encryption.OpenPGP.ASCIIArmor.Decode (
   parseArmor
 , decode
 , decodeLazy
) where

import Codec.Encryption.OpenPGP.ASCIIArmor.Types
import Codec.Encryption.OpenPGP.ASCIIArmor.Utils
import Control.Applicative (many, (<|>), (<$>), (<*), (<*>), (*>), optional)
import Data.Attoparsec.ByteString (Parser, many1, string, inClass, notInClass, satisfy, word8, (<?>))
import qualified Data.Attoparsec.ByteString as AS
import qualified Data.Attoparsec.ByteString.Lazy as AL
import Data.Attoparsec.ByteString.Char8 (isDigit_w8, anyChar)
import Data.Bits (shiftL)
import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as BL
import qualified Data.ByteString.Char8 as BC8
import qualified Data.ByteString.Base64 as Base64
import Data.Digest.CRC24 (crc24)
import Data.Binary.Get (Get, runGetOrFail, getWord8)
import Data.Functor (($>))
import Data.String (IsString, fromString)
import Data.Word (Word32)

decode :: IsString e => B.ByteString -> Either e [Armor]
decode :: ByteString -> Either e [Armor]
decode bs :: ByteString
bs = IResult ByteString [Armor] -> Either e [Armor]
forall a b. IsString a => IResult ByteString b -> Either a b
go (Parser [Armor] -> ByteString -> IResult ByteString [Armor]
forall a. Parser a -> ByteString -> Result a
AS.parse Parser [Armor]
parseArmors ByteString
bs)
    where
        go :: IResult ByteString b -> Either a b
go (AS.Fail _ _ e :: String
e) = a -> Either a b
forall a b. a -> Either a b
Left (String -> a
forall a. IsString a => String -> a
fromString String
e)
        go (AS.Partial cont :: ByteString -> IResult ByteString b
cont) = IResult ByteString b -> Either a b
go (ByteString -> IResult ByteString b
cont ByteString
B.empty)
        go (AS.Done _ r :: b
r) = b -> Either a b
forall a b. b -> Either a b
Right b
r

decodeLazy :: IsString e => BL.ByteString -> Either e [Armor]
decodeLazy :: ByteString -> Either e [Armor]
decodeLazy bs :: ByteString
bs = Result [Armor] -> Either e [Armor]
forall a b. IsString a => Result b -> Either a b
go (Parser [Armor] -> ByteString -> Result [Armor]
forall a. Parser a -> ByteString -> Result a
AL.parse Parser [Armor]
parseArmors ByteString
bs)
    where
        go :: Result b -> Either a b
go (AL.Fail _ _ e :: String
e) = a -> Either a b
forall a b. a -> Either a b
Left (String -> a
forall a. IsString a => String -> a
fromString String
e)
        go (AL.Done _ r :: b
r) = b -> Either a b
forall a b. b -> Either a b
Right b
r

parseArmors :: Parser [Armor]
parseArmors :: Parser [Armor]
parseArmors = Parser ByteString Armor -> Parser [Armor]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many Parser ByteString Armor
parseArmor

parseArmor :: Parser Armor
parseArmor :: Parser ByteString Armor
parseArmor = Parser ByteString Armor -> Parser ByteString Armor
forall a. Parser a -> Parser a
prefixed (Parser ByteString Armor
clearsigned Parser ByteString Armor
-> Parser ByteString Armor -> Parser ByteString Armor
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Parser ByteString Armor
armor) Parser ByteString Armor -> String -> Parser ByteString Armor
forall i a. Parser i a -> String -> Parser i a
<?> "armor"

clearsigned :: Parser Armor
clearsigned :: Parser ByteString Armor
clearsigned = do
    ByteString
_ <- ByteString -> Parser ByteString
string "-----BEGIN PGP SIGNED MESSAGE-----" Parser ByteString -> String -> Parser ByteString
forall i a. Parser i a -> String -> Parser i a
<?> "clearsign header"
    ByteString
_ <- Parser ByteString
lineEnding Parser ByteString -> String -> Parser ByteString
forall i a. Parser i a -> String -> Parser i a
<?> "line ending"
    [(String, String)]
headers <- Parser [(String, String)]
armorHeaders Parser [(String, String)] -> String -> Parser [(String, String)]
forall i a. Parser i a -> String -> Parser i a
<?> "clearsign headers"
    ByteString
_ <- Parser ByteString
blankishLine Parser ByteString -> String -> Parser ByteString
forall i a. Parser i a -> String -> Parser i a
<?> "blank line"
    ByteString
cleartext <- Parser ByteString
dashEscapedCleartext
    Armor
sig <- Parser ByteString Armor
armor
    Armor -> Parser ByteString Armor
forall (m :: * -> *) a. Monad m => a -> m a
return (Armor -> Parser ByteString Armor)
-> Armor -> Parser ByteString Armor
forall a b. (a -> b) -> a -> b
$ [(String, String)] -> ByteString -> Armor -> Armor
ClearSigned [(String, String)]
headers ByteString
cleartext Armor
sig

armor :: Parser Armor
armor :: Parser ByteString Armor
armor = do
    ArmorType
atype <- Parser ArmorType
beginLine Parser ArmorType -> String -> Parser ArmorType
forall i a. Parser i a -> String -> Parser i a
<?> "begin line"
    [(String, String)]
headers <- Parser [(String, String)]
armorHeaders Parser [(String, String)] -> String -> Parser [(String, String)]
forall i a. Parser i a -> String -> Parser i a
<?> "headers"
    ByteString
_ <- Parser ByteString
blankishLine Parser ByteString -> String -> Parser ByteString
forall i a. Parser i a -> String -> Parser i a
<?> "blank line"
    ByteString
payload <- Parser ByteString
base64Data Parser ByteString -> String -> Parser ByteString
forall i a. Parser i a -> String -> Parser i a
<?> "base64 data"
    ByteString
_ <- ArmorType -> Parser ByteString
endLine ArmorType
atype Parser ByteString -> String -> Parser ByteString
forall i a. Parser i a -> String -> Parser i a
<?> "end line"
    Armor -> Parser ByteString Armor
forall (m :: * -> *) a. Monad m => a -> m a
return (Armor -> Parser ByteString Armor)
-> Armor -> Parser ByteString Armor
forall a b. (a -> b) -> a -> b
$ ArmorType -> [(String, String)] -> ByteString -> Armor
Armor ArmorType
atype [(String, String)]
headers ByteString
payload

beginLine :: Parser ArmorType
beginLine :: Parser ArmorType
beginLine = do
    ByteString
_ <- ByteString -> Parser ByteString
string "-----BEGIN PGP " Parser ByteString -> String -> Parser ByteString
forall i a. Parser i a -> String -> Parser i a
<?> "leading minus-hyphens"
    ArmorType
atype <- Parser ArmorType
pubkey Parser ArmorType -> Parser ArmorType -> Parser ArmorType
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Parser ArmorType
privkey Parser ArmorType -> Parser ArmorType -> Parser ArmorType
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Parser ArmorType
parts Parser ArmorType -> Parser ArmorType -> Parser ArmorType
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Parser ArmorType
message Parser ArmorType -> Parser ArmorType -> Parser ArmorType
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Parser ArmorType
signature
    ByteString
_ <- ByteString -> Parser ByteString
string "-----" Parser ByteString -> String -> Parser ByteString
forall i a. Parser i a -> String -> Parser i a
<?> "trailing minus-hyphens"
    [Word8]
_ <- Parser ByteString Word8 -> Parser ByteString [Word8]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many ((Word8 -> Bool) -> Parser ByteString Word8
satisfy (String -> Word8 -> Bool
inClass " \t")) Parser ByteString [Word8] -> String -> Parser ByteString [Word8]
forall i a. Parser i a -> String -> Parser i a
<?> "whitespace"
    ByteString
_ <- Parser ByteString
lineEnding Parser ByteString -> String -> Parser ByteString
forall i a. Parser i a -> String -> Parser i a
<?> "line ending"
    ArmorType -> Parser ArmorType
forall (m :: * -> *) a. Monad m => a -> m a
return ArmorType
atype
    where
        message :: Parser ArmorType
message = ByteString -> Parser ByteString
string "MESSAGE" Parser ByteString -> ArmorType -> Parser ArmorType
forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> ArmorType
ArmorMessage
        pubkey :: Parser ArmorType
pubkey = ByteString -> Parser ByteString
string "PUBLIC KEY BLOCK" Parser ByteString -> ArmorType -> Parser ArmorType
forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> ArmorType
ArmorPublicKeyBlock
        privkey :: Parser ArmorType
privkey = ByteString -> Parser ByteString
string "PRIVATE KEY BLOCK" Parser ByteString -> ArmorType -> Parser ArmorType
forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> ArmorType
ArmorPrivateKeyBlock
        signature :: Parser ArmorType
signature = ByteString -> Parser ByteString
string "SIGNATURE" Parser ByteString -> ArmorType -> Parser ArmorType
forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> ArmorType
ArmorSignature
        parts :: Parser ArmorType
parts = ByteString -> Parser ByteString
string "MESSAGE, PART " Parser ByteString -> Parser ArmorType -> Parser ArmorType
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> (Parser ArmorType
partsdef Parser ArmorType -> Parser ArmorType -> Parser ArmorType
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Parser ArmorType
partsindef)
        partsdef :: Parser ArmorType
partsdef = do
            [Word8]
firstnum <- Parser ByteString [Word8]
num
            Word8
_ <- Word8 -> Parser ByteString Word8
word8 (Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Word8) -> (Char -> Int) -> Char -> Word8
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Int
forall a. Enum a => a -> Int
fromEnum (Char -> Word8) -> Char -> Word8
forall a b. (a -> b) -> a -> b
$ '/')
            [Word8]
secondnum <- Parser ByteString [Word8]
num
            ArmorType -> Parser ArmorType
forall (m :: * -> *) a. Monad m => a -> m a
return (ArmorType -> Parser ArmorType) -> ArmorType -> Parser ArmorType
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString -> ArmorType
ArmorSplitMessage ([Word8] -> ByteString
BL.pack [Word8]
firstnum) ([Word8] -> ByteString
BL.pack [Word8]
secondnum)
        partsindef :: Parser ArmorType
partsindef = ByteString -> ArmorType
ArmorSplitMessageIndefinite (ByteString -> ArmorType)
-> ([Word8] -> ByteString) -> [Word8] -> ArmorType
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Word8] -> ByteString
BL.pack ([Word8] -> ArmorType)
-> Parser ByteString [Word8] -> Parser ArmorType
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser ByteString [Word8]
num
        num :: Parser ByteString [Word8]
num = Parser ByteString Word8 -> Parser ByteString [Word8]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many1 ((Word8 -> Bool) -> Parser ByteString Word8
satisfy Word8 -> Bool
isDigit_w8) Parser ByteString [Word8] -> String -> Parser ByteString [Word8]
forall i a. Parser i a -> String -> Parser i a
<?> "number"

lineEnding :: Parser B.ByteString
lineEnding :: Parser ByteString
lineEnding = ByteString -> Parser ByteString
string "\n" Parser ByteString -> Parser ByteString -> Parser ByteString
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> ByteString -> Parser ByteString
string "\r\n"

armorHeaders :: Parser [(String, String)]
armorHeaders :: Parser [(String, String)]
armorHeaders = Parser ByteString (String, String) -> Parser [(String, String)]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many Parser ByteString (String, String)
armorHeader

armorHeader :: Parser (String, String)
armorHeader :: Parser ByteString (String, String)
armorHeader = do
    [Word8]
key <- Parser ByteString Word8 -> Parser ByteString [Word8]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many1 ((Word8 -> Bool) -> Parser ByteString Word8
satisfy (String -> Word8 -> Bool
inClass "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"))
    ByteString
_ <- ByteString -> Parser ByteString
string ": "
    [Word8]
val <- Parser ByteString Word8 -> Parser ByteString [Word8]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many1 ((Word8 -> Bool) -> Parser ByteString Word8
satisfy (String -> Word8 -> Bool
notInClass "\n\r"))
    ByteString
_ <- Parser ByteString
lineEnding
    (String, String) -> Parser ByteString (String, String)
forall (m :: * -> *) a. Monad m => a -> m a
return ([Word8] -> String
w8sToString [Word8]
key, [Word8] -> String
w8sToString [Word8]
val)
    where
        w8sToString :: [Word8] -> String
w8sToString = ByteString -> String
BC8.unpack (ByteString -> String)
-> ([Word8] -> ByteString) -> [Word8] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Word8] -> ByteString
B.pack

blankishLine ::  Parser B.ByteString
blankishLine :: Parser ByteString
blankishLine = Parser ByteString Word8 -> Parser ByteString [Word8]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many ((Word8 -> Bool) -> Parser ByteString Word8
satisfy (String -> Word8 -> Bool
inClass " \t")) Parser ByteString [Word8] -> Parser ByteString -> Parser ByteString
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser ByteString
lineEnding

endLine :: ArmorType -> Parser B.ByteString
endLine :: ArmorType -> Parser ByteString
endLine atype :: ArmorType
atype = do
    ByteString
_ <- ByteString -> Parser ByteString
string (ByteString -> Parser ByteString)
-> ByteString -> Parser ByteString
forall a b. (a -> b) -> a -> b
$ "-----END PGP " ByteString -> ByteString -> ByteString
`B.append` ArmorType -> ByteString
aType ArmorType
atype ByteString -> ByteString -> ByteString
`B.append` "-----"
    Parser ByteString
lineEnding

aType :: ArmorType -> B.ByteString
aType :: ArmorType -> ByteString
aType ArmorMessage = String -> ByteString
BC8.pack "MESSAGE"
aType ArmorPublicKeyBlock = String -> ByteString
BC8.pack "PUBLIC KEY BLOCK"
aType ArmorPrivateKeyBlock = String -> ByteString
BC8.pack "PRIVATE KEY BLOCK"
aType (ArmorSplitMessage x :: ByteString
x y :: ByteString
y) = String -> ByteString
BC8.pack "MESSAGE, PART " ByteString -> ByteString -> ByteString
`B.append` ByteString -> ByteString
l2s ByteString
x ByteString -> ByteString -> ByteString
`B.append` Char -> ByteString
BC8.singleton '/' ByteString -> ByteString -> ByteString
`B.append` ByteString -> ByteString
l2s ByteString
y
aType (ArmorSplitMessageIndefinite x :: ByteString
x) = String -> ByteString
BC8.pack "MESSAGE, PART " ByteString -> ByteString -> ByteString
`B.append` ByteString -> ByteString
l2s ByteString
x
aType ArmorSignature = String -> ByteString
BC8.pack "SIGNATURE"

l2s :: BL.ByteString -> B.ByteString
l2s :: ByteString -> ByteString
l2s = [ByteString] -> ByteString
B.concat ([ByteString] -> ByteString)
-> (ByteString -> [ByteString]) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [ByteString]
BL.toChunks

base64Data :: Parser ByteString
base64Data :: Parser ByteString
base64Data = do
    [ByteString]
ls <- Parser ByteString -> Parser ByteString [ByteString]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many1 Parser ByteString
base64Line
    ByteString
cksum <- Parser ByteString
checksumLine
    let payload :: ByteString
payload = [ByteString] -> ByteString
B.concat [ByteString]
ls
    let ourcksum :: Word32
ourcksum = ByteString -> Word32
crc24 ByteString
payload
    case Get Word32
-> ByteString
-> Either
     (ByteString, ByteOffset, String) (ByteString, ByteOffset, Word32)
forall a.
Get a
-> ByteString
-> Either
     (ByteString, ByteOffset, String) (ByteString, ByteOffset, a)
runGetOrFail Get Word32
d24 (ByteString -> ByteString
BL.fromStrict ByteString
cksum) of
        Left (_,_,err :: String
err) -> String -> Parser ByteString
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
err
        Right (_,_,theircksum :: Word32
theircksum) -> if Word32
theircksum Word32 -> Word32 -> Bool
forall a. Eq a => a -> a -> Bool
== Word32
ourcksum then ByteString -> Parser ByteString
forall (m :: * -> *) a. Monad m => a -> m a
return (ByteString -> ByteString
BL.fromStrict ByteString
payload) else String -> Parser ByteString
forall (m :: * -> *) a. MonadFail m => String -> m a
fail ("CRC24 mismatch: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ [Word8] -> String
forall a. Show a => a -> String
show (ByteString -> [Word8]
B.unpack ByteString
cksum) String -> String -> String
forall a. [a] -> [a] -> [a]
++ "/" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Word32 -> String
forall a. Show a => a -> String
show Word32
theircksum String -> String -> String
forall a. [a] -> [a] -> [a]
++ " vs. " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Word32 -> String
forall a. Show a => a -> String
show Word32
ourcksum)
    where
        base64Line :: Parser B.ByteString
        base64Line :: Parser ByteString
base64Line = do
                        [Word8]
b64 <- Parser ByteString Word8 -> Parser ByteString [Word8]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many1 ((Word8 -> Bool) -> Parser ByteString Word8
satisfy (String -> Word8 -> Bool
inClass "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"))
                        [Word8]
pad <- Parser ByteString Word8 -> Parser ByteString [Word8]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many (Word8 -> Parser ByteString Word8
word8 (Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Word8) -> (Char -> Int) -> Char -> Word8
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Int
forall a. Enum a => a -> Int
fromEnum (Char -> Word8) -> Char -> Word8
forall a b. (a -> b) -> a -> b
$ '='))
                        ByteString
_ <- Parser ByteString
lineEnding
                        let line :: ByteString
line = [Word8] -> ByteString
B.pack [Word8]
b64 ByteString -> ByteString -> ByteString
`B.append` [Word8] -> ByteString
B.pack [Word8]
pad
                        case ByteString -> Either String ByteString
Base64.decode ByteString
line of
                            Left err :: String
err -> String -> Parser ByteString
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
err
                            Right bs :: ByteString
bs -> ByteString -> Parser ByteString
forall (m :: * -> *) a. Monad m => a -> m a
return ByteString
bs
        checksumLine :: Parser B.ByteString
        checksumLine :: Parser ByteString
checksumLine = do
                        Word8
_ <- Word8 -> Parser ByteString Word8
word8 (Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Word8) -> (Char -> Int) -> Char -> Word8
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Int
forall a. Enum a => a -> Int
fromEnum (Char -> Word8) -> Char -> Word8
forall a b. (a -> b) -> a -> b
$ '=')
                        [Word8]
b64 <- Parser ByteString Word8 -> Parser ByteString [Word8]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many1 ((Word8 -> Bool) -> Parser ByteString Word8
satisfy (String -> Word8 -> Bool
inClass "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"))
                        ByteString
_ <- Parser ByteString
lineEnding
                        let line :: ByteString
line = [Word8] -> ByteString
B.pack [Word8]
b64
                        case ByteString -> Either String ByteString
Base64.decode ByteString
line of
                            Left err :: String
err -> String -> Parser ByteString
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
err
                            Right bs :: ByteString
bs -> ByteString -> Parser ByteString
forall (m :: * -> *) a. Monad m => a -> m a
return ByteString
bs


d24 :: Get Word32
d24 :: Get Word32
d24 = do
    Word8
a <- Get Word8
getWord8
    Word8
b <- Get Word8
getWord8
    Word8
c <- Get Word8
getWord8
    Word32 -> Get Word32
forall (m :: * -> *) a. Monad m => a -> m a
return (Word32 -> Get Word32) -> Word32 -> Get Word32
forall a b. (a -> b) -> a -> b
$ Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
shiftL (Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
a :: Word32) 16 Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
+ Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
shiftL (Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
b :: Word32) 8 Word32 -> Word32 -> Word32
forall a. Num a => a -> a -> a
+ (Word8 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
c :: Word32)

prefixed :: Parser a -> Parser a
prefixed :: Parser a -> Parser a
prefixed end :: Parser a
end = Parser a
end Parser a -> Parser a -> Parser a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Parser Char
anyChar Parser Char -> Parser a -> Parser a
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser a -> Parser a
forall a. Parser a -> Parser a
prefixed Parser a
end

dashEscapedCleartext :: Parser ByteString
dashEscapedCleartext :: Parser ByteString
dashEscapedCleartext = do
    [ByteString]
ls <- Parser ByteString -> Parser ByteString [ByteString]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many1 ((Parser ByteString
deLine Parser ByteString -> Parser ByteString -> Parser ByteString
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Parser ByteString
unescapedLine) Parser ByteString -> Parser ByteString -> Parser ByteString
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Parser ByteString
lineEnding)
    ByteString -> Parser ByteString
forall (m :: * -> *) a. Monad m => a -> m a
return (ByteString -> Parser ByteString)
-> (ByteString -> ByteString) -> ByteString -> Parser ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
BL.fromStrict (ByteString -> Parser ByteString)
-> ByteString -> Parser ByteString
forall a b. (a -> b) -> a -> b
$ [ByteString] -> ByteString
crlfUnlines [ByteString]
ls
    where
        deLine :: Parser B.ByteString
        deLine :: Parser ByteString
deLine = [Word8] -> ByteString
B.pack ([Word8] -> ByteString)
-> Parser ByteString [Word8] -> Parser ByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (ByteString -> Parser ByteString
string "- " Parser ByteString
-> Parser ByteString [Word8] -> Parser ByteString [Word8]
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser ByteString Word8 -> Parser ByteString [Word8]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many ((Word8 -> Bool) -> Parser ByteString Word8
satisfy (String -> Word8 -> Bool
notInClass "\n\r")))
        unescapedLine :: Parser B.ByteString
        unescapedLine :: Parser ByteString
unescapedLine = ByteString
-> ([Word8] -> ByteString) -> Maybe [Word8] -> ByteString
forall b a. b -> (a -> b) -> Maybe a -> b
maybe ByteString
B.empty [Word8] -> ByteString
B.pack (Maybe [Word8] -> ByteString)
-> Parser ByteString (Maybe [Word8]) -> Parser ByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser ByteString [Word8] -> Parser ByteString (Maybe [Word8])
forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional ((:) (Word8 -> [Word8] -> [Word8])
-> Parser ByteString Word8
-> Parser ByteString ([Word8] -> [Word8])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Word8 -> Bool) -> Parser ByteString Word8
satisfy (String -> Word8 -> Bool
notInClass "-\n\r") Parser ByteString ([Word8] -> [Word8])
-> Parser ByteString [Word8] -> Parser ByteString [Word8]
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser ByteString Word8 -> Parser ByteString [Word8]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many ((Word8 -> Bool) -> Parser ByteString Word8
satisfy (String -> Word8 -> Bool
notInClass "\n\r")))