11module Functora.Rfc2397
2- ( encode ,
2+ ( Media (.. ),
3+ Encoding (.. ),
4+ encode ,
35 decode ,
46 )
57where
68
79import qualified Data.ByteString.Base64 as B64
810import Functora.Prelude
11+ import qualified Network.URI as URI
912import qualified Network.URI.Encode as UE
1013import qualified Prelude
1114
12- data ENC = BASE64 | URL
13- deriving stock (Eq )
15+ data Media = Media
16+ { mediaMime :: String ,
17+ mediaBytes :: ByteString ,
18+ mediaEncoding :: Encoding
19+ }
20+ deriving stock (Eq , Ord , Show , Data , Generic )
1421
15- encode :: String -> ByteString -> String
16- encode mime bs =
22+ data Encoding = B64Encoding | UrlEncoding
23+ deriving stock (Eq , Ord , Show , Read , Data , Generic , Bounded , Enum )
24+
25+ encode :: Media -> String
26+ encode Media {mediaMime = mime, mediaBytes = bs, mediaEncoding = enc} =
1727 " data:"
1828 <> mime
19- <> " ;base64,"
20- <> either impureThrow id (decodeUtf8Strict $ B64. encode bs)
29+ <> ( case enc of
30+ B64Encoding -> " ;base64"
31+ UrlEncoding -> mempty
32+ )
33+ <> " ,"
34+ <> ( case enc of
35+ B64Encoding ->
36+ either impureThrow id
37+ . decodeUtf8Strict
38+ $ B64. encode bs
39+ UrlEncoding ->
40+ either impureThrow (UE. encodeWith URI. isAllowedInURI)
41+ $ decodeUtf8Strict bs
42+ )
2143
22- decode :: String -> Maybe ( String , ByteString )
44+ decode :: String -> Maybe Media
2345decode url =
2446 let (scheme, rest) = break (== ' :' ) url
2547 in case rest of
2648 ' :' : contents | scheme == " data" -> decodeContents contents
2749 _ -> Nothing
2850
29- decodeContents :: String -> Maybe ( String , ByteString )
51+ decodeContents :: String -> Maybe Media
3052decodeContents xs =
3153 let (prefix, restdata) = break (== ' ,' ) xs
3254 in case restdata of
3355 ' ,' : thedata -> decodePrefix prefix thedata
3456 _ -> Nothing
3557
36- decodePrefix :: String -> String -> Maybe ( String , ByteString )
58+ decodePrefix :: String -> String -> Maybe Media
3759decodePrefix prefix thedata =
3860 let fragments = breakList (== ' ;' ) prefix
3961 enc = case reverse fragments of
40- (" base64" : _) -> BASE64
41- _ -> URL
62+ (" base64" : _) -> B64Encoding
63+ _ -> UrlEncoding
4264 mediapart
43- | enc == BASE64 = Prelude. init fragments
65+ | enc == B64Encoding = Prelude. init fragments
4466 | otherwise = fragments
4567 in case mediapart of
4668 (xs : _) ->
@@ -49,14 +71,20 @@ decodePrefix prefix thedata =
4971 _ -> decodeData mediapart enc thedata
5072 _ -> decodeData [" text/plain" , " charset=US-ASCII" ] enc thedata
5173
52- decodeData :: [String ] -> ENC -> String -> Maybe (String , ByteString )
53- decodeData mediatype enc thedata =
54- Just
55- ( unparse mediatype,
56- case enc of
57- URL -> encodeUtf8 $ UE. decode thedata
58- BASE64 -> either Prelude. error id . B64. decode $ encodeUtf8 thedata
59- )
74+ decodeData :: [String ] -> Encoding -> String -> Maybe Media
75+ decodeData mediatype enc thedata = do
76+ bs <-
77+ case enc of
78+ UrlEncoding ->
79+ pure . encodeUtf8 $ UE. decode thedata
80+ B64Encoding ->
81+ either (const Nothing ) Just . B64. decode $ encodeUtf8 thedata
82+ pure
83+ Media
84+ { mediaMime = unparse mediatype,
85+ mediaBytes = bs,
86+ mediaEncoding = enc
87+ }
6088
6189breakList :: (x -> Bool ) -> [x ] -> [[x ]]
6290breakList p xs =
0 commit comments