import Data.Map (Map)
import qualified Data.Map as M
import Data.Monoid.Unicode
+import Data.Sequence (Seq, ViewL(..))
import qualified Data.Sequence as S
import Data.Sequence.Unicode hiding ((∅))
import Data.Text (Text)
import qualified Data.Text as T
+import qualified Data.Text.ICU.Convert as TC
import Data.Text.Encoding
import Data.Traversable
import Data.Word
return (name, sect, isEncoded)
initialEncodedValue ∷ Parser (CIAscii, BS.ByteString)
-initialEncodedValue = do charset ← metadata
- _ ← char '\''
- _ ← metadata -- Ignore the language tag
- _ ← char '\''
- payload ← encodedPayload
- return (charset, payload)
+initialEncodedValue
+ = do charset ← metadata
+ _ ← char '\''
+ _ ← metadata -- Ignore the language tag
+ _ ← char '\''
+ payload ← encodedPayload
+ if charset ≡ "" then
+ -- NOTE: I'm not sure this is the right thing, but RFC
+ -- 2231 doesn't tell us what should we do when the
+ -- charset is omitted.
+ return ("US-ASCII", payload)
+ else
+ return (charset, payload)
where
metadata ∷ Parser CIAscii
metadata = (A.toCIAscii ∘ A.unsafeFromByteString) <$>
])
decodeSections ∷ ∀m. Monad m ⇒ Map Integer ExtendedParam → m Text
-decodeSections = flip (flip go 0) (∅)
+decodeSections = (decodeSeq =≪) ∘ flip (flip toSeq 0) (∅)
where
- go ∷ Map Integer ExtendedParam → Integer → S.Seq Text → m Text
- go m expectedSect chunks
+ toSeq ∷ Map Integer ExtendedParam
+ → Integer
+ → Seq ExtendedParam
+ → m (Seq ExtendedParam)
+ toSeq m expectedSect sects
= case M.minViewWithKey m of
Nothing
- → return $ T.concat $ toList chunks
+ → return sects
Just ((sect, p), m')
| sect ≡ expectedSect
- → error "FIXME"
+ → toSeq m' (expectedSect + 1) (sects ⊳ p)
| otherwise
→ fail (concat [ "Missing section "
, show $ section p
, A.toString $ A.fromCIAscii $ epName p
, "'"
])
+
+ decodeSeq ∷ Seq ExtendedParam → m Text
+ decodeSeq sects
+ = case S.viewl sects of
+ EmptyL
+ → fail "decodeSeq: internal error: empty seq"
+ InitialEncodedParam {..} :< xs
+ → do conv ← openConv epCharset
+ let t = TC.toUnicode conv epPayload
+ decodeSeq' (Just conv) xs $ S.singleton t
+ ContinuedEncodedParam {..} :< _
+ → fail "decodeSeq: internal error: ContinuedEncodedParam at section 0"
+ AsciiParam {..} :< xs
+ → let t = A.toText apPayload
+ in
+ decodeSeq' Nothing xs $ S.singleton t
+
+ decodeSeq' ∷ Maybe (TC.Converter)
+ → Seq ExtendedParam
+ → Seq Text
+ → m Text
+ decodeSeq' convM sects chunks
+ = case S.viewl sects of
+ EmptyL
+ → return $ T.concat $ toList chunks
+ InitialEncodedParam {..} :< _
+ → fail "decodeSeq': internal error: InitialEncodedParam at section > 0"
+ ContinuedEncodedParam {..} :< xs
+ → case convM of
+ Just conv
+ → let t = TC.toUnicode conv epPayload
+ in
+ decodeSeq' convM xs $ chunks ⊳ t
+ Nothing
+ → fail (concat [ "Section "
+ , show epSection
+ , " for parameter '"
+ , A.toString $ A.fromCIAscii epName
+ , "' is encoded but its section 0 is not"
+ ])
+ AsciiParam {..} :< xs
+ → let t = A.toText apPayload
+ in
+ decodeSeq' convM xs $ chunks ⊳ t
+
+ openConv ∷ CIAscii → m TC.Converter
+ openConv charset
+ = fail "FIXME"