    {-# LANGUAGE CPP #-}
    #if __GLASGOW_HASKELL__ >= 702
    {-# LANGUAGE Trustworthy #-}
    #endif

    -- |
    -- Module      : Data.ByteString.Base64.Lazy
    -- Copyright   : (c) 2012 Ian Lynagh
    --
    -- License     : BSD-style
    -- Maintainer  : Emily Pillmore <emilypi@cohomolo.gy>,
    --               Herbert Valerio Riedel <hvr@gnu.org>,
    --               Mikhail Glushenkov <mikhail.glushenkov@gmail.com>
    -- Stability   : experimental
    -- Portability : GHC
    --
    -- Fast and efficient encoding and decoding of base64-encoded
    -- lazy bytestrings.
    --
    -- @since 1.0.0.0
    module Data.ByteString.Base64.Lazy
        (
          encode
        , decode
        , decodeLenient
        ) where

    import Data.ByteString.Base64.Internal
    import qualified Data.ByteString.Base64     as B64
    import qualified Data.ByteString            as S
    import qualified Data.ByteString.Lazy       as L
    import qualified Data.ByteString.Lazy.Char8 as LC
    import Data.Char

    -- | Encode a string into base64 form.  The result will always be a
    -- multiple of 4 bytes in length.
    encode :: L.ByteString -> L.ByteString
    encode :: ByteString -> ByteString
    encode = [StrictByteString] -> ByteString
    L.fromChunks ([StrictByteString] -> ByteString)
    -> (ByteString -> [StrictByteString]) -> ByteString -> ByteString
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (StrictByteString -> StrictByteString)
    -> [StrictByteString] -> [StrictByteString]
    forall a b. (a -> b) -> [a] -> [b]
    map StrictByteString -> StrictByteString
    B64.encode ([StrictByteString] -> [StrictByteString])
    -> (ByteString -> [StrictByteString])
    -> ByteString
    -> [StrictByteString]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Int -> [StrictByteString] -> [StrictByteString]
    reChunkIn Int
    3 ([StrictByteString] -> [StrictByteString])
    -> (ByteString -> [StrictByteString])
    -> ByteString
    -> [StrictByteString]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ByteString -> [StrictByteString]
    L.toChunks

    -- | Decode a base64-encoded string.  This function strictly follows
    -- the specification in
    -- <http://tools.ietf.org/rfc/rfc4648 RFC 4648>.
    decode :: L.ByteString -> Either String L.ByteString
    decode :: ByteString -> Either String ByteString
    decode ByteString
    b = -- Returning an Either type means that the entire result will
               -- need to be in memory at once anyway, so we may as well
               -- keep it simple and just convert to and from a strict byte
               -- string
               -- TODO: Use L.{fromStrict,toStrict} once we can rely on
               -- a new enough bytestring
               case StrictByteString -> Either String StrictByteString
    B64.decode (StrictByteString -> Either String StrictByteString)
    -> StrictByteString -> Either String StrictByteString
    forall a b. (a -> b) -> a -> b
    $ [StrictByteString] -> StrictByteString
    S.concat ([StrictByteString] -> StrictByteString)
    -> [StrictByteString] -> StrictByteString
    forall a b. (a -> b) -> a -> b
    $ ByteString -> [StrictByteString]
    L.toChunks ByteString
    b of
               Left String
    err -> String -> Either String ByteString
    forall a b. a -> Either a b
    Left String
    err
               Right StrictByteString
    b' -> ByteString -> Either String ByteString
    forall a b. b -> Either a b
    Right (ByteString -> Either String ByteString)
    -> ByteString -> Either String ByteString
    forall a b. (a -> b) -> a -> b
    $ [StrictByteString] -> ByteString
    L.fromChunks [StrictByteString
    b']

    -- | Decode a base64-encoded string.  This function is lenient in
    -- following the specification from
    -- <http://tools.ietf.org/rfc/rfc4648 RFC 4648>, and will not generate
    -- parse errors no matter how poor its input.
    decodeLenient :: L.ByteString -> L.ByteString
    decodeLenient :: ByteString -> ByteString
    decodeLenient = [StrictByteString] -> ByteString
    L.fromChunks ([StrictByteString] -> ByteString)
    -> (ByteString -> [StrictByteString]) -> ByteString -> ByteString
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (StrictByteString -> StrictByteString)
    -> [StrictByteString] -> [StrictByteString]
    forall a b. (a -> b) -> [a] -> [b]
    map StrictByteString -> StrictByteString
    B64.decodeLenient ([StrictByteString] -> [StrictByteString])
    -> (ByteString -> [StrictByteString])
    -> ByteString
    -> [StrictByteString]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Int -> [StrictByteString] -> [StrictByteString]
    reChunkIn Int
    4 ([StrictByteString] -> [StrictByteString])
    -> (ByteString -> [StrictByteString])
    -> ByteString
    -> [StrictByteString]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ByteString -> [StrictByteString]
    L.toChunks
                  (ByteString -> [StrictByteString])
    -> (ByteString -> ByteString) -> ByteString -> [StrictByteString]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Char -> Bool) -> ByteString -> ByteString
    LC.filter Char -> Bool
    goodChar
        where -- We filter out and '=' padding here, but B64.decodeLenient
              -- handles that
              goodChar :: Char -> Bool
    goodChar Char
    c = Char -> Bool
    isDigit Char
    c Bool -> Bool -> Bool
    || Char -> Bool
    isAsciiUpper Char
    c Bool -> Bool -> Bool
    || Char -> Bool
    isAsciiLower Char
    c
                                     Bool -> Bool -> Bool
    || Char
    c Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    == Char
    '+' Bool -> Bool -> Bool
    || Char
    c Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    == Char
    '/'