module Data.MIME.Boundary
(
Boundary
, unBoundary
, makeBoundary
) where
import Control.Monad (replicateM)
import qualified Data.ByteString as B
import qualified Data.ByteString.Internal as B
import Data.ByteString.Char8 as C8
import System.Random.Stateful
newtype Boundary = Boundary B.ByteString
deriving (Boundary -> Boundary -> Bool
(Boundary -> Boundary -> Bool)
-> (Boundary -> Boundary -> Bool) -> Eq Boundary
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Boundary -> Boundary -> Bool
$c/= :: Boundary -> Boundary -> Bool
== :: Boundary -> Boundary -> Bool
$c== :: Boundary -> Boundary -> Bool
Eq, Int -> Boundary -> ShowS
[Boundary] -> ShowS
Boundary -> String
(Int -> Boundary -> ShowS)
-> (Boundary -> String) -> ([Boundary] -> ShowS) -> Show Boundary
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Boundary] -> ShowS
$cshowList :: [Boundary] -> ShowS
show :: Boundary -> String
$cshow :: Boundary -> String
showsPrec :: Int -> Boundary -> ShowS
$cshowsPrec :: Int -> Boundary -> ShowS
Show)
unBoundary :: Boundary -> B.ByteString
unBoundary :: Boundary -> ByteString
unBoundary (Boundary ByteString
s) = ByteString
s
makeBoundary :: B.ByteString -> Either B.ByteString Boundary
makeBoundary :: ByteString -> Either ByteString Boundary
makeBoundary ByteString
s
| ByteString -> Bool
B.null ByteString
s = ByteString -> Either ByteString Boundary
forall a b. a -> Either a b
Left ByteString
s
| ByteString -> Int
B.length ByteString
s Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
70 = ByteString -> Either ByteString Boundary
forall a b. a -> Either a b
Left ByteString
s
| (Word8 -> Bool) -> ByteString -> Bool
B.any (Bool -> Bool
not (Bool -> Bool) -> (Word8 -> Bool) -> Word8 -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word8 -> Bool
forall a. (Ord a, Num a) => a -> Bool
validBchar) ByteString
s = ByteString -> Either ByteString Boundary
forall a b. a -> Either a b
Left ByteString
s
| ByteString -> Word8
B.last ByteString
s Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0x20 = ByteString -> Either ByteString Boundary
forall a b. a -> Either a b
Left ByteString
s
| Bool
otherwise = Boundary -> Either ByteString Boundary
forall a b. b -> Either a b
Right (Boundary -> Either ByteString Boundary)
-> Boundary -> Either ByteString Boundary
forall a b. (a -> b) -> a -> b
$ ByteString -> Boundary
Boundary ByteString
s
where
validBchar :: a -> Bool
validBchar a
c =
a
c a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
0x2c Bool -> Bool -> Bool
&& a
c a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
0x3a
Bool -> Bool -> Bool
|| a
c a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
0x41 Bool -> Bool -> Bool
&& a
c a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
0x5a
Bool -> Bool -> Bool
|| a
c a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
0x61 Bool -> Bool -> Bool
&& a
c a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
0x7a
Bool -> Bool -> Bool
|| a
c a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
0x27 Bool -> Bool -> Bool
&& a
c a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
0x29
Bool -> Bool -> Bool
|| a
c a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
0x2b
Bool -> Bool -> Bool
|| a
c a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
0x5f
Bool -> Bool -> Bool
|| a
c a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
0x3d
Bool -> Bool -> Bool
|| a
c a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
0x3f
Bool -> Bool -> Bool
|| a
c a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
0x20
genBoundary :: (StatefulGen g m) => g -> m Boundary
genBoundary :: g -> m Boundary
genBoundary g
g = do
let
blen :: Int
blen = Int
64
bchars :: ByteString
bchars = String -> ByteString
C8.pack (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ [Char
'0'..Char
'9'] String -> ShowS
forall a. Semigroup a => a -> a -> a
<> [Char
'a'..Char
'z'] String -> ShowS
forall a. Semigroup a => a -> a -> a
<> [Char
'A'..Char
'Z'] String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
"'()+_,-./:=?"
[Word8]
chars <-
Int -> m Word8 -> m [Word8]
forall (m :: * -> *) a. Applicative m => Int -> m a -> m [a]
replicateM Int
blen (m Word8 -> m [Word8]) -> m Word8 -> m [Word8]
forall a b. (a -> b) -> a -> b
$ ByteString -> Int -> Word8
B.index ByteString
bchars (Int -> Word8) -> m Int -> m Word8
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Int, Int) -> g -> m Int
forall a g (m :: * -> *).
(UniformRange a, StatefulGen g m) =>
(a, a) -> g -> m a
uniformRM (Int
0, ByteString -> Int
B.length ByteString
bchars Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) g
g
Boundary -> m Boundary
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Boundary -> m Boundary)
-> (ByteString -> Boundary) -> ByteString -> m Boundary
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Boundary
Boundary (ByteString -> m Boundary) -> ByteString -> m Boundary
forall a b. (a -> b) -> a -> b
$ Int -> [Word8] -> ByteString
B.unsafePackLenBytes Int
blen [Word8]
chars
instance Uniform Boundary where
uniformM :: g -> m Boundary
uniformM = g -> m Boundary
forall g (m :: * -> *). StatefulGen g m => g -> m Boundary
genBoundary