-- XXX Write tests -- Defined in RFC 2047 -- We assume we have US-ASCII characters. module Codec.Binary.EncodingQ.String ( encode, decode) where import Codec.MIME.String.Internal.Utils import Data.Bits import Data.Char -- len is the maximum length the encoded text in a single block is -- allowed to be encode :: Int -> String -> [String] encode _ "" = [] encode len xs = enc len 0 id id xs -- The Int is the number of characters on this line so far -- 76 is the maximum we can have no one line, and 3 is the most -- generated for 1 input char (but we also need space for a trailing -- '=' for a soft line break). enc :: Int -> Int -- Length stuff -> ([String] -> [String]) -> (String -> String) -- accumulators -> String -- input -> [String] enc _ _ acc_list acc_string "" = acc_list [acc_string ""] enc len so_far acc_list acc_string (c:cs) = if so_far' > len then enc len new_len (acc_list . (acc_string "" :)) id cs else enc len new_len acc_list (acc_string . (encoded ++)) cs where encoded = if isAsciiPrint c && (c /= ' ') && (c /= '?') then [c] else ['=', x1, x2] new_len = length encoded so_far' = so_far + new_len o = ord c x1 = toUpper $ intToDigit (o `shiftR` 4) x2 = toUpper $ intToDigit (o .&. 0xF) decode :: String -> String decode ('=':c1:c2:cs) | isAsciiHexDigit c1 && isAsciiHexDigit c2 = chr ((digitToInt c1 `shiftL` 4) + digitToInt c2):decode cs decode ('_':cs) = ' ':decode cs decode (c:cs) = c:decode cs decode "" = ""