11module Functora.Rfc2397
2- ( Media (.. ),
3- Encoding (.. ),
2+ ( Rfc2397 (.. ),
3+ Rfc2397Encoding (.. ),
44 encodeRfc2397 ,
55 decodeRfc2397 ,
66 )
@@ -12,92 +12,96 @@ import qualified Network.URI as URI
1212import qualified Network.URI.Encode as UE
1313import qualified Prelude
1414
15- data Media = Media
16- { mediaMime :: String ,
17- mediaBytes :: ByteString ,
18- mediaEncoding :: Encoding
15+ data Rfc2397 = Rfc2397
16+ { rfc2397Mime :: Unicode ,
17+ rfc2397Bytes :: ByteString ,
18+ rfc2397Encoding :: Rfc2397Encoding
1919 }
2020 deriving stock (Eq , Ord , Show , Data , Generic )
2121
22- instance Binary Media
22+ instance Binary Rfc2397
2323
24- data Encoding = B64Encoding | UrlEncoding
24+ data Rfc2397Encoding
25+ = Rfc2397EncodingB64
26+ | Rfc2397EncodingUrl
2527 deriving stock (Eq , Ord , Show , Read , Data , Generic , Bounded , Enum )
2628
27- instance Binary Encoding
29+ instance Binary Rfc2397Encoding
2830
29- encodeRfc2397 :: Media -> String
30- encodeRfc2397 Media {mediaMime = mime, mediaBytes = bs, mediaEncoding = enc} =
31- " data:"
32- <> mime
33- <> ( case enc of
34- B64Encoding -> " ;base64"
35- UrlEncoding -> mempty
36- )
37- <> " ,"
38- <> ( case enc of
39- B64Encoding ->
40- either impureThrow id
41- . decodeUtf8Strict
42- $ B64. encode bs
43- UrlEncoding ->
44- either impureThrow (UE. encodeWith URI. isAllowedInURI)
45- $ decodeUtf8Strict bs
46- )
31+ encodeRfc2397 :: Rfc2397 -> Unicode
32+ encodeRfc2397
33+ Rfc2397
34+ { rfc2397Mime = mime,
35+ rfc2397Bytes = bs,
36+ rfc2397Encoding = enc
37+ } =
38+ " data:"
39+ <> mime
40+ <> ( case enc of
41+ Rfc2397EncodingB64 -> " ;base64"
42+ Rfc2397EncodingUrl -> mempty
43+ )
44+ <> " ,"
45+ <> ( case enc of
46+ Rfc2397EncodingB64 ->
47+ either impureThrow id
48+ . decodeUtf8Strict
49+ $ B64. encode bs
50+ Rfc2397EncodingUrl ->
51+ either
52+ impureThrow
53+ ( from @ String @ Unicode
54+ . UE. encodeWith URI. isAllowedInURI
55+ )
56+ $ decodeUtf8Strict bs
57+ )
4758
48- decodeRfc2397 :: String -> Maybe Media
49- decodeRfc2397 url =
50- let (scheme, rest) = break (== ' :' ) url
51- in case rest of
52- ' :' : contents | scheme == " data" -> decodeContents contents
53- _ -> Nothing
59+ decodeRfc2397 :: Unicode -> Maybe Rfc2397
60+ decodeRfc2397 xs =
61+ case break (== ' :' ) xs of
62+ (" data" , rhs) | not (null rhs) -> decodeContents $ drop 1 rhs
63+ _ -> Nothing
5464
55- decodeContents :: String -> Maybe Media
65+ decodeContents :: Unicode -> Maybe Rfc2397
5666decodeContents xs =
57- let (prefix, restdata) = break (== ' ,' ) xs
58- in case restdata of
59- ' ,' : thedata -> decodePrefix prefix thedata
60- _ -> Nothing
67+ case break (== ' ,' ) xs of
68+ (lhs, rhs) | not (null rhs) -> decodePrefix lhs $ drop 1 rhs
69+ _ -> Nothing
6170
62- decodePrefix :: String -> String -> Maybe Media
71+ decodePrefix :: Unicode -> Unicode -> Maybe Rfc2397
6372decodePrefix prefix thedata =
64- let fragments = breakList (== ' ;' ) prefix
65- enc = case reverse fragments of
66- (" base64" : _) -> B64Encoding
67- _ -> UrlEncoding
68- mediapart
69- | enc == B64Encoding = Prelude. init fragments
70- | otherwise = fragments
71- in case mediapart of
72- (xs : _) ->
73- case break (== ' /' ) xs of
74- (_, [] ) -> decodeData (" text/plain" : mediapart) enc thedata
75- _ -> decodeData mediapart enc thedata
76- _ -> decodeData [" text/plain" , " charset=US-ASCII" ] enc thedata
73+ case mediapart of
74+ [] -> decodeData [" text/plain" , " charset=US-ASCII" ] enc thedata
75+ (xs : _) ->
76+ case break (== ' /' ) xs of
77+ (_, [] ) -> decodeData (" text/plain" : mediapart) enc thedata
78+ _ -> decodeData mediapart enc thedata
79+ where
80+ fragments = breakList (== ' ;' ) prefix
81+ enc = case reverse fragments of
82+ (" base64" : _) -> Rfc2397EncodingB64
83+ _ -> Rfc2397EncodingUrl
84+ mediapart
85+ | enc == Rfc2397EncodingB64 = Prelude. init fragments
86+ | otherwise = fragments
7787
78- decodeData :: [String ] -> Encoding -> String -> Maybe Media
88+ decodeData :: [Unicode ] -> Rfc2397Encoding -> Unicode -> Maybe Rfc2397
7989decodeData mediatype enc thedata = do
8090 bs <-
8191 case enc of
82- UrlEncoding ->
83- pure . encodeUtf8 $ UE. decode thedata
84- B64Encoding ->
92+ Rfc2397EncodingUrl ->
93+ pure . encodeUtf8 . UE. decode $ from @ Unicode @ String thedata
94+ Rfc2397EncodingB64 ->
8595 either (const Nothing ) Just . B64. decode $ encodeUtf8 thedata
8696 pure
87- Media
88- { mediaMime = unparse mediatype,
89- mediaBytes = bs,
90- mediaEncoding = enc
97+ Rfc2397
98+ { rfc2397Mime = intercalate " ; " mediatype,
99+ rfc2397Bytes = bs,
100+ rfc2397Encoding = enc
91101 }
92102
93- breakList :: (x -> Bool ) -> [x ] -> [[x ]]
94- breakList p xs =
95- let (pre, post) = break p xs
96- in case post of
97- [] -> [pre]
98- _ : ys -> pre : breakList p ys
99-
100- unparse :: [String ] -> String
101- unparse [] = " "
102- unparse [xs] = xs
103- unparse (xs : xss) = xs ++ ' ;' : unparse xss
103+ breakList :: (Char -> Bool ) -> Unicode -> [Unicode ]
104+ breakList f xs =
105+ case break f xs of
106+ (lhs, rhs) | null rhs -> [lhs]
107+ (lhs, rhs) -> lhs : breakList f (drop 1 rhs)
0 commit comments