{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE OverloadedStrings #-}
module Data.ByteString.Lazy.Base64
( encodeBase64
, encodeBase64'
, decodeBase64
, decodeBase64Lenient
, isBase64
, isValidBase64
) where
import Prelude hiding (all, elem)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Base64 as B64
import Data.ByteString.Base64.Internal.Utils (reChunkN)
import Data.ByteString.Lazy (elem, fromChunks, toChunks)
import Data.ByteString.Lazy.Internal (ByteString(..))
import Data.Either (isRight)
import qualified Data.Text as T
import qualified Data.Text.Lazy as TL
import qualified Data.Text.Lazy.Encoding as TL
encodeBase64 :: ByteString -> TL.Text
encodeBase64 = TL.decodeUtf8 . encodeBase64'
{-# INLINE encodeBase64 #-}
encodeBase64' :: ByteString -> ByteString
encodeBase64' = fromChunks
. fmap B64.encodeBase64'
. reChunkN 3
. toChunks
{-# INLINE encodeBase64' #-}
decodeBase64 :: ByteString -> Either T.Text ByteString
decodeBase64 = fmap (fromChunks . (:[]))
. B64.decodeBase64
. BS.concat
. toChunks
{-# INLINE decodeBase64 #-}
decodeBase64Lenient :: ByteString -> ByteString
decodeBase64Lenient = fromChunks
. fmap B64.decodeBase64Lenient
. reChunkN 4
. fmap (BS.filter (flip elem "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="))
. toChunks
{-# INLINE decodeBase64Lenient #-}
isBase64 :: ByteString -> Bool
isBase64 bs = isValidBase64 bs && isRight (decodeBase64 bs)
{-# INLINE isBase64 #-}
isValidBase64 :: ByteString -> Bool
isValidBase64 = go . toChunks
where
go [] = True
go [c] = B64.isValidBase64 c
go (c:cs) =
BS.all (flip elem "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") c
&& go cs
{-# INLINE isValidBase64 #-}