-- |
-- module: Data.Text.Encoding.Locale
-- copyright: © kudah 2013
-- license: BSD3
--
-- maintainer: kudahkukarek@gmail.com
-- stability: experimental
-- portability: GHC-only
--
-- This module provides functions to encode and decode 'Data.Text.Lazy.Text'
-- to/from 'Data.ByteString.Lazy.ByteString' using 'System.IO.TextEncoding'
--
-- For performance, Text\'s native decode\* functions are used if the conditions
-- are right (LF NewlineMode and UTF encoding).
{-# LANGUAGE CPP #-}
#ifdef TRUSTWORTHY
{-# LANGUAGE Trustworthy #-}
#endif
module Data.Text.Lazy.Encoding.Locale
(decodeLocale
,encodeLocale
,decodeLocale'
,encodeLocale'
,decodeFromHandle
,encodeFromHandle
) where
import Import (getLocale'
,whenJust'
,hGetEncAndNlMode')
import qualified Data.ByteString.Lazy as L
import qualified Data.Text.Lazy as TL
import qualified Data.Text.Lazy.IO as TLIO
import qualified Data.Text.Lazy.Encoding as TLE
import System.IO
import Data.ByteString.Handle
import qualified Data.List as L
import Data.Maybe
handleDecoder :: Maybe TextEncoding -> Maybe NewlineMode -> L.ByteString -> IO TL.Text
handleDecoder menc mnlmode = \bs -> do
h <- readHandle False bs
whenJust' menc $ hSetEncoding h
whenJust' mnlmode $ hSetNewlineMode h
TLIO.hGetContents h
handleEncoder :: Maybe TextEncoding -> Maybe NewlineMode -> TL.Text -> IO L.ByteString
handleEncoder menc mnlmode = \t -> do
(res, ()) <- writeHandle False $ \h -> do
whenJust' menc $ hSetEncoding h
whenJust' mnlmode $ hSetNewlineMode h
TLIO.hPutStr h t
return res
chooseDecoder :: Maybe TextEncoding -> Maybe NewlineMode -> L.ByteString -> IO TL.Text
chooseDecoder menc mnlmode = \bs -> do
if inputNL nlmode == LF
-- decode* functions won't convert line ends
then do
enc <- maybe getLocale' return menc
case L.stripPrefix "UTF-" (show enc) of
Just s ->
case s of
"8" -> return (TLE.decodeUtf8 bs)
('1':'6':x:'E':_)
| 'L' == x -> return (TLE.decodeUtf16LE bs)
| 'B' == x -> return (TLE.decodeUtf16BE bs)
('3':'2':x:'E':_)
| 'L' == x -> return (TLE.decodeUtf32LE bs)
| 'B' == x -> return (TLE.decodeUtf32BE bs)
_ -> fallback bs
_ -> fallback bs
else
fallback bs
where
nlmode = fromMaybe nativeNewlineMode mnlmode
fallback = handleDecoder menc mnlmode
chooseEncoder :: Maybe TextEncoding -> Maybe NewlineMode -> TL.Text -> IO L.ByteString
chooseEncoder menc mnlmode = \bs ->
if outputNL nlmode == LF
-- encode* functions won't convert line ends
then do
enc <- maybe getLocale' return menc
case L.stripPrefix "UTF-" (show enc) of
Just s ->
case s of
"8" -> return (TLE.encodeUtf8 bs)
('1':'6':x:'E':_)
| 'L' == x -> return (TLE.encodeUtf16LE bs)
| 'B' == x -> return (TLE.encodeUtf16BE bs)
('3':'2':x:'E':_)
| 'L' == x -> return (TLE.encodeUtf32LE bs)
| 'B' == x -> return (TLE.encodeUtf32BE bs)
_ -> fallback bs
_ -> fallback bs
else
fallback bs
where
nlmode = fromMaybe nativeNewlineMode mnlmode
fallback = handleEncoder menc mnlmode
-- | Decode 'L.ByteString' to 'TL.Text' using current locale
decodeLocale :: L.ByteString -> IO TL.Text
decodeLocale = chooseDecoder Nothing Nothing
-- | Encode 'TL.Text' to 'L.ByteString' using current locale
encodeLocale :: TL.Text -> IO L.ByteString
encodeLocale = chooseEncoder Nothing Nothing
-- | Decode 'L.ByteString' to 'TL.Text' using supplied 'TextEncoding' and 'NewlineMode'
decodeLocale' :: TextEncoding -> NewlineMode -> L.ByteString -> IO TL.Text
decodeLocale' enc nlmode = chooseDecoder (Just enc) (Just nlmode)
-- | Encode 'TL.Text' to 'L.ByteString' using supplied 'TextEncoding' and 'NewlineMode'
encodeLocale' :: TextEncoding -> NewlineMode -> TL.Text -> IO L.ByteString
encodeLocale' enc nlmode = chooseEncoder (Just enc) (Just nlmode)
-- | Decode 'L.ByteString' to 'TL.Text' using 'Handle's 'TextEncoding' and 'NewlineMode'
decodeFromHandle :: Handle -> L.ByteString -> IO TL.Text
decodeFromHandle h bs = do
(enc, nlmode) <- hGetEncAndNlMode' h
decodeLocale' enc nlmode bs
-- | Encode 'TL.Text' to 'L.ByteString' using 'Handle's 'TextEncoding' and 'NewlineMode'
encodeFromHandle :: Handle -> TL.Text -> IO L.ByteString
encodeFromHandle h t = do
(enc, nlmode) <- hGetEncAndNlMode' h
encodeLocale' enc nlmode t