blob: cdc22668e975e606e5a93bc5c642de07557a2f00 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
--------------------------------------------------------------------
-- |
-- Module : Codec.MIME.QuotedPrintable
-- Copyright : (c) 2006-2009, Galois, Inc.
-- License : BSD3
--
-- Maintainer: Sigbjorn Finne <sigbjorn.finne@gmail.com>
-- Stability : provisional
-- Portability:
--
-- To and from QP content encoding.
--
--------------------------------------------------------------------
module Codec.MIME.QuotedPrintable
( decode -- :: String -> String
, encode -- :: String -> String
) where
import Data.Char
-- | 'decode' incoming quoted-printable content, stripping
-- out soft line breaks and translating @=XY@ sequences
-- into their decoded byte\/octet. The output encoding\/representation
-- is still a String, not a sequence of bytes.
decode :: String -> String
decode "" = ""
decode ('=':'\r':'\n':xs) = decode xs -- soft line break.
decode ('=':x1:x2:xs)
| isHexDigit x1 && isHexDigit x2 =
chr (digitToInt x1 * 16 + digitToInt x2) : decode xs
decode ('=':xs) = '=':decode xs
-- make it explicit that we propagate other '=' occurrences.
decode (x1:xs) = x1:decode xs
-- | 'encode' converts a sequence of characeter _octets_ into
-- quoted-printable form; suitable for transmission in MIME
-- payloads. Note the stress on _octets_; it is assumed that
-- you have already converted Unicode into a <=8-bit encoding
-- (UTF-8, most likely.)
encode :: String -> String
encode xs = encodeLength 0 xs
-- | @encodeLength llen str@ is the worker function during encoding.
-- The extra argument @llen@ tracks the current column for the line
-- being processed. Soft line breaks are inserted if a line exceeds
-- a max length.
encodeLength :: Int -> String -> String
encodeLength _ "" = ""
encodeLength n (x:xs)
| n >= 72 = '=':'\r':'\n':encodeLength 0 (x:xs)
encodeLength _ ('=':xs)
= '=':'3':'D':encodeLength 0 xs
encodeLength n (x:xs)
| ox >= 0x100 = error ("QuotedPrintable.encode: encountered > 8 bit character: " ++ show (x,ox))
| n >= 72 = '=':'\r':'\n':encodeLength 0 (x:xs)
| ox >= 0x21 && ox <= 0x7e = x : encodeLength (n+1) xs
| ox == 0x09 || ox == 0x20 = x : encodeLength (n+1) xs
| otherwise = '=':showH (ox `div` 0x10): showH (ox `mod` 0x10):encodeLength (n+3) xs
where
ox = ord x
showH v
| v < 10 = chr (ord_0 + v)
| otherwise = chr (ord_A + (v-10))
ord_0 = ord '0'
ord_A = ord 'A'
|