module Codec.Binary.QuotedPrintable
( EncIncData(..)
, EncIncRes(..)
, encodeInc
, encode
, DecIncData(..)
, DecIncRes(..)
, decodeInc
, decode
, chop
, unchop
) where
import Codec.Binary.Util
import Data.Char
import Data.Maybe
import Data.Word
encodeInc :: EncIncData -> EncIncRes String
encodeInc :: EncIncData -> EncIncRes String
encodeInc e :: EncIncData
e = EncIncData -> EncIncRes String
eI EncIncData
e
where
enc :: [Word8] -> String
enc [] = []
enc (o :: Word8
o:os :: [Word8]
os)
| Word8
o Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
< 33 Bool -> Bool -> Bool
|| Word8
o Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 61 Bool -> Bool -> Bool
|| Word8
o Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
> 126 = ('=' Char -> String -> String
forall a. a -> [a] -> [a]
: Word8 -> String
toHex Word8
o) String -> String -> String
forall a. [a] -> [a] -> [a]
++ [Word8] -> String
enc [Word8]
os
| Bool
otherwise = Int -> Char
chr (Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
o) Char -> String -> String
forall a. a -> [a] -> [a]
: [Word8] -> String
enc [Word8]
os
eI :: EncIncData -> EncIncRes String
eI EDone = String -> EncIncRes String
forall i. i -> EncIncRes i
EFinal []
eI (EChunk bs :: [Word8]
bs) = String -> (EncIncData -> EncIncRes String) -> EncIncRes String
forall i. i -> (EncIncData -> EncIncRes i) -> EncIncRes i
EPart ([Word8] -> String
enc [Word8]
bs) EncIncData -> EncIncRes String
encodeInc
encode :: [Word8] -> String
encode :: [Word8] -> String
encode = (EncIncData -> EncIncRes String) -> [Word8] -> String
forall a. (EncIncData -> EncIncRes [a]) -> [Word8] -> [a]
encoder EncIncData -> EncIncRes String
encodeInc
decodeInc :: DecIncData String -> DecIncRes String
decodeInc :: DecIncData String -> DecIncRes String
decodeInc d :: DecIncData String
d = String -> DecIncData String -> DecIncRes String
dI [] DecIncData String
d
where
dI :: String -> DecIncData String -> DecIncRes String
dI [] DDone = [Word8] -> String -> DecIncRes String
forall i. [Word8] -> i -> DecIncRes i
DFinal [] []
dI lo :: String
lo DDone = [Word8] -> String -> DecIncRes String
forall i. [Word8] -> i -> DecIncRes i
DFail [] String
lo
dI lo :: String
lo (DChunk s :: String
s) = [Word8] -> String -> DecIncRes String
doDec [] (String
lo String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
s)
where
doDec :: [Word8] -> String -> DecIncRes String
doDec acc :: [Word8]
acc [] = [Word8]
-> (DecIncData String -> DecIncRes String) -> DecIncRes String
forall i. [Word8] -> (DecIncData i -> DecIncRes i) -> DecIncRes i
DPart [Word8]
acc (String -> DecIncData String -> DecIncRes String
dI [])
doDec acc :: [Word8]
acc s' :: String
s'@('=':c0 :: Char
c0:c1 :: Char
c1:cs :: String
cs) = let
o :: Maybe Word8
o = String -> Maybe Word8
fromHex [Char
c0, Char
c1]
in if Maybe Word8 -> Bool
forall a. Maybe a -> Bool
isJust Maybe Word8
o
then [Word8] -> String -> DecIncRes String
doDec ([Word8]
acc [Word8] -> [Word8] -> [Word8]
forall a. [a] -> [a] -> [a]
++ [Maybe Word8 -> Word8
forall a. HasCallStack => Maybe a -> a
fromJust Maybe Word8
o]) String
cs
else [Word8] -> String -> DecIncRes String
forall i. [Word8] -> i -> DecIncRes i
DFail [Word8]
acc String
s'
doDec acc :: [Word8]
acc s' :: String
s'@(c :: Char
c:cs :: String
cs)
| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= '=' = [Word8] -> String -> DecIncRes String
doDec ([Word8]
acc [Word8] -> [Word8] -> [Word8]
forall a. [a] -> [a] -> [a]
++ [Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Word8) -> Int -> Word8
forall a b. (a -> b) -> a -> b
$ Char -> Int
ord Char
c]) String
cs
| Bool
otherwise = [Word8]
-> (DecIncData String -> DecIncRes String) -> DecIncRes String
forall i. [Word8] -> (DecIncData i -> DecIncRes i) -> DecIncRes i
DPart [Word8]
acc (String -> DecIncData String -> DecIncRes String
dI String
s')
decode :: String -> Maybe [Word8]
decode :: String -> Maybe [Word8]
decode = (DecIncData String -> DecIncRes String) -> String -> Maybe [Word8]
forall i. (DecIncData i -> DecIncRes i) -> i -> Maybe [Word8]
decoder DecIncData String -> DecIncRes String
decodeInc
chop :: Int
-> String
-> [String]
chop :: Int -> String -> [String]
chop n :: Int
n "" = []
chop n :: Int
n s :: String
s = let
n' :: Int
n' = Int -> Int -> Int
forall a. Ord a => a -> a -> a
max 3 (Int -> Int) -> Int -> Int
forall a b. (a -> b) -> a -> b
$ Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- 1
_c :: Int -> String -> String -> [String] -> [String]
_c i :: Int
i ts :: String
ts "" acc :: [String]
acc = String
ts String -> [String] -> [String]
forall a. a -> [a] -> [a]
: [String]
acc
_c i :: Int
i ts :: String
ts tss :: String
tss@('=' : tss' :: String
tss') acc :: [String]
acc
| Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ 2 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
n' = Int -> String -> String -> [String] -> [String]
_c (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ 1) ('=' Char -> String -> String
forall a. a -> [a] -> [a]
: String
ts) String
tss' [String]
acc
| Bool
otherwise = Int -> String -> String -> [String] -> [String]
_c 0 "" String
tss (('=' Char -> String -> String
forall a. a -> [a] -> [a]
: String
ts) String -> [String] -> [String]
forall a. a -> [a] -> [a]
: [String]
acc)
_c i :: Int
i ts :: String
ts tss :: String
tss@(c :: Char
c : tss' :: String
tss') acc :: [String]
acc
| Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
n' = Int -> String -> String -> [String] -> [String]
_c (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ 1) (Char
c Char -> String -> String
forall a. a -> [a] -> [a]
: String
ts) String
tss' [String]
acc
| Bool
otherwise = Int -> String -> String -> [String] -> [String]
_c 0 "" String
tss (('=' Char -> String -> String
forall a. a -> [a] -> [a]
: String
ts) String -> [String] -> [String]
forall a. a -> [a] -> [a]
: [String]
acc)
in (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map String -> String
forall a. [a] -> [a]
reverse ([String] -> [String])
-> ([String] -> [String]) -> [String] -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> [String]
forall a. [a] -> [a]
reverse ([String] -> [String]) -> [String] -> [String]
forall a b. (a -> b) -> a -> b
$ Int -> String -> String -> [String] -> [String]
_c 0 "" String
s []
unchop :: [String] -> String
unchop :: [String] -> String
unchop [] = ""
unchop (s :: String
s : ss :: [String]
ss) = let
dropLast :: Bool
dropLast = String -> Char
forall a. [a] -> a
last String
s Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== '='
len :: Int
len = String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
s
in if Bool
dropLast
then Int -> String -> String
forall a. Int -> [a] -> [a]
take (Int
len Int -> Int -> Int
forall a. Num a => a -> a -> a
- 1) String
s String -> String -> String
forall a. [a] -> [a] -> [a]
++ [String] -> String
unchop [String]
ss
else String
s String -> String -> String
forall a. [a] -> [a] -> [a]
++ [String] -> String
unchop [String]
ss