{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE CPP, NoImplicitPrelude #-}
{-# OPTIONS_GHC -funbox-strict-fields #-}
module GHC.IO.Encoding (
BufferCodec(..), TextEncoding(..), TextEncoder, TextDecoder, CodingProgress(..),
latin1, latin1_encode, latin1_decode,
utf8, utf8_bom,
utf16, utf16le, utf16be,
utf32, utf32le, utf32be,
initLocaleEncoding,
getLocaleEncoding, getFileSystemEncoding, getForeignEncoding,
setLocaleEncoding, setFileSystemEncoding, setForeignEncoding,
char8,
mkTextEncoding,
) where
import GHC.Base
import GHC.IO.Exception
import GHC.IO.Buffer
import GHC.IO.Encoding.Failure
import GHC.IO.Encoding.Types
#if !defined(mingw32_HOST_OS)
import qualified GHC.IO.Encoding.Iconv as Iconv
#else
import qualified GHC.IO.Encoding.CodePage as CodePage
import Text.Read (reads)
#endif
import qualified GHC.IO.Encoding.Latin1 as Latin1
import qualified GHC.IO.Encoding.UTF8 as UTF8
import qualified GHC.IO.Encoding.UTF16 as UTF16
import qualified GHC.IO.Encoding.UTF32 as UTF32
import GHC.Word
import Data.IORef
import Data.Char (toUpper)
import Data.List
import Data.Maybe
import System.IO.Unsafe (unsafePerformIO)
latin1 :: TextEncoding
latin1 = Latin1.latin1_checked
utf8 :: TextEncoding
utf8 = UTF8.utf8
utf8_bom :: TextEncoding
utf8_bom = UTF8.utf8_bom
utf16 :: TextEncoding
utf16 = UTF16.utf16
utf16le :: TextEncoding
utf16le = UTF16.utf16le
utf16be :: TextEncoding
utf16be = UTF16.utf16be
utf32 :: TextEncoding
utf32 = UTF32.utf32
utf32le :: TextEncoding
utf32le = UTF32.utf32le
utf32be :: TextEncoding
utf32be = UTF32.utf32be
getLocaleEncoding :: IO TextEncoding
getFileSystemEncoding :: IO TextEncoding
getForeignEncoding :: IO TextEncoding
setLocaleEncoding, setFileSystemEncoding, setForeignEncoding :: TextEncoding -> IO ()
(getLocaleEncoding, setLocaleEncoding) = mkGlobal initLocaleEncoding
(getFileSystemEncoding, setFileSystemEncoding) = mkGlobal initFileSystemEncoding
(getForeignEncoding, setForeignEncoding) = mkGlobal initForeignEncoding
mkGlobal :: a -> (IO a, a -> IO ())
mkGlobal x = unsafePerformIO $ do
x_ref <- newIORef x
return (readIORef x_ref, writeIORef x_ref)
initLocaleEncoding, initFileSystemEncoding, initForeignEncoding :: TextEncoding
#if !defined(mingw32_HOST_OS)
initLocaleEncoding = unsafePerformIO $ mkTextEncoding' ErrorOnCodingFailure Iconv.localeEncodingName
initFileSystemEncoding = unsafePerformIO $ mkTextEncoding' RoundtripFailure Iconv.localeEncodingName
initForeignEncoding = unsafePerformIO $ mkTextEncoding' IgnoreCodingFailure Iconv.localeEncodingName
#else
initLocaleEncoding = CodePage.localeEncoding
initFileSystemEncoding = CodePage.mkLocaleEncoding RoundtripFailure
initForeignEncoding = CodePage.mkLocaleEncoding IgnoreCodingFailure
#endif
char8 :: TextEncoding
char8 = Latin1.latin1
mkTextEncoding :: String -> IO TextEncoding
mkTextEncoding e = case mb_coding_failure_mode of
Nothing -> unknownEncodingErr e
Just cfm -> mkTextEncoding' cfm enc
where
(enc, suffix) = span (/= '/') e
mb_coding_failure_mode = case suffix of
"" -> Just ErrorOnCodingFailure
"//IGNORE" -> Just IgnoreCodingFailure
"//TRANSLIT" -> Just TransliterateCodingFailure
"//ROUNDTRIP" -> Just RoundtripFailure
_ -> Nothing
mkTextEncoding' :: CodingFailureMode -> String -> IO TextEncoding
mkTextEncoding' cfm enc = case [toUpper c | c <- enc, c /= '-'] of
"UTF8" -> return $ UTF8.mkUTF8 cfm
"UTF16" -> return $ UTF16.mkUTF16 cfm
"UTF16LE" -> return $ UTF16.mkUTF16le cfm
"UTF16BE" -> return $ UTF16.mkUTF16be cfm
"UTF32" -> return $ UTF32.mkUTF32 cfm
"UTF32LE" -> return $ UTF32.mkUTF32le cfm
"UTF32BE" -> return $ UTF32.mkUTF32be cfm
#if defined(mingw32_HOST_OS)
'C':'P':n | [(cp,"")] <- reads n -> return $ CodePage.mkCodePageEncoding cfm cp
_ -> unknownEncodingErr (enc ++ codingFailureModeSuffix cfm)
#else
_ -> Iconv.mkIconvEncoding cfm enc
#endif
latin1_encode :: CharBuffer -> Buffer Word8 -> IO (CharBuffer, Buffer Word8)
latin1_encode input output = fmap (\(_why,input',output') -> (input',output')) $ Latin1.latin1_encode input output
latin1_decode :: Buffer Word8 -> CharBuffer -> IO (Buffer Word8, CharBuffer)
latin1_decode input output = fmap (\(_why,input',output') -> (input',output')) $ Latin1.latin1_decode input output
unknownEncodingErr :: String -> IO a
unknownEncodingErr e = ioException (IOError Nothing NoSuchThing "mkTextEncoding"
("unknown encoding:" ++ e) Nothing Nothing)