module Data.Attoparsec.ByteString.Base64
  ( isBase64Char
  , base64CharParser
  , takeNBase64Chars
  , takeMNBase64Chars
  ) where

import Data.Attoparsec.ByteString ( Parser, count, inClass, satisfy, (<?>) )
import Data.Attoparsec.ByteString.Extra ( takeWhileMN )
import Data.ByteString ( ByteString )
import qualified Data.ByteString as BS
import Data.Word ( Word8 )
import Prelude

-- | Determine whether a 'Word8' is a valid character in an unpadded base64
-- string.
isBase64Char :: Word8 -> Bool
isBase64Char :: Word8 -> Bool
isBase64Char = String -> Word8 -> Bool
inClass String
"a-zA-Z0-9+/"

-- | Parse a base64 character.
base64CharParser :: Parser Word8
base64CharParser :: Parser Word8
base64CharParser = (Word8 -> Bool) -> Parser Word8
satisfy Word8 -> Bool
isBase64Char Parser Word8 -> String -> Parser Word8
forall i a. Parser i a -> String -> Parser i a
<?> String
"base64 character"

-- | Consume exactly @n@ base64 characters.
takeNBase64Chars :: Word -> Parser ByteString
takeNBase64Chars :: Word -> Parser ByteString
takeNBase64Chars Word
n = [Word8] -> ByteString
BS.pack ([Word8] -> ByteString)
-> Parser ByteString [Word8] -> Parser ByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> Parser Word8 -> Parser ByteString [Word8]
forall (m :: * -> *) a. Monad m => Int -> m a -> m [a]
count (Word -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word
n) Parser Word8
base64CharParser

-- | Consume a base64 character string of length @m <= len <= n@.
takeMNBase64Chars ::
  -- | @m@.
  Word ->
  -- | @n@.
  Word ->
  Parser ByteString
takeMNBase64Chars :: Word -> Word -> Parser ByteString
takeMNBase64Chars Word
m Word
n = Word -> Word -> (Word8 -> Bool) -> Parser ByteString
takeWhileMN Word
m Word
n Word8 -> Bool
isBase64Char