-- | -- Module : Codec.Binary.Url -- Copyright : (c) 2009 Magnus Therning -- License : BSD3 -- -- URL encoding, sometimes referred to as URI encoding or percent encoding. -- Implemented based on RFC 3986 (). -- -- Further documentation and information can be found at -- . module Codec.Binary.Url ( EncIncData(..) , EncIncRes(..) , encodeInc , encode , DecIncData , DecIncRes , decodeInc , decode , chop , unchop ) where import Codec.Binary.Util import qualified Data.Map as M import Data.Char(ord) import Data.Word(Word8) import Data.Maybe(isJust, fromJust) -- {{{1 enc/dec map _unreservedChars = zip [65..90] "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ++ zip [97..122] "abcdefghijklmnopqrstuvwxyz" ++ zip [48..57] "0123456789" ++ [(45, '-'), (95, '_'), (46, '.'), (126, '~')] encodeMap :: M.Map Word8 Char encodeMap = M.fromList _unreservedChars decodeMap :: M.Map Char Word8 decodeMap = M.fromList [(b, a) | (a, b) <- _unreservedChars] -- {{{1 encode -- | Incremental decoder function. encodeInc :: EncIncData -> EncIncRes String encodeInc e = eI e where enc [] = [] enc (o : os) = case (M.lookup o encodeMap) of Just c -> c : enc os Nothing -> ('%' : toHex o) ++ enc os eI EDone = EFinal [] eI (EChunk bs) = EPart (enc bs) encodeInc -- | Encode data. encode :: [Word8] -> String encode = encoder encodeInc -- {{{1 decode -- | Incremental decoder function. decodeInc :: DecIncData String -> DecIncRes String decodeInc d = dI [] d where dI [] DDone = DFinal [] [] dI lo DDone = DFail [] lo dI lo (DChunk s) = doDec [] (lo ++ s) where doDec acc [] = DPart acc (dI []) doDec acc s'@('%':c0:c1:cs) = let o = fromHex [c0, c1] in if isJust o then doDec (acc ++ [fromJust o]) cs else DFail acc s' doDec acc s'@(c:cs) | c /= '%' = doDec (acc ++ [fromIntegral $ ord c]) cs | otherwise = DPart acc (dI s') -- | Decode data. decode :: String -> Maybe [Word8] decode = decoder decodeInc -- {{{1 chop -- | Chop up a string in parts. chop :: Int -- ^ length of individual lines -> String -> [String] chop n = let _n = max 1 n _chop [] = [] _chop cs = take _n cs : _chop (drop _n cs) in _chop -- {{{1 unchop -- | Concatenate the strings into one long string unchop :: [String] -> String unchop = foldr (++) ""