module Data.Text.ICU.Convert
(
Converter
, open
, fromUnicode
, toUnicode
, getName
, usesFallback
, isAmbiguous
, getDefaultName
, setDefaultName
, compareNames
, aliases
, converterNames
, standardNames
) where
import Data.ByteString.Internal (ByteString, createAndTrim)
import Data.ByteString.Unsafe (unsafeUseAsCStringLen)
import Data.Int (Int32)
import Data.Text (Text)
import Data.Text.Foreign (fromPtr, lengthWord16, useAsPtr)
import Data.Text.ICU.Convert.Internal
import Data.Text.ICU.Error.Internal (UErrorCode, handleError)
import Data.Word (Word16)
import Foreign.C.String (CString, peekCString, withCString)
import Foreign.C.Types (CInt(..))
import Foreign.ForeignPtr (newForeignPtr)
import Foreign.Marshal.Array (allocaArray)
import Foreign.Ptr (FunPtr, Ptr, castPtr)
import System.IO.Unsafe (unsafePerformIO)
import Data.Text.ICU.Internal (UBool, UChar, asBool, asOrdering, withName)
compareNames :: String -> String -> Ordering
compareNames a b =
unsafePerformIO . withCString a $ \aptr ->
fmap asOrdering . withCString b $ ucnv_compareNames aptr
open :: String
-> Maybe Bool
-> IO Converter
open name mf = do
c <- fmap Converter . newForeignPtr ucnv_close =<< withName name (handleError . ucnv_open)
case mf of
Just f -> withConverter c $ \p -> ucnv_setFallback p . fromIntegral . fromEnum $ f
_ -> return ()
return c
fromUnicode :: Converter -> Text -> ByteString
fromUnicode cnv t =
unsafePerformIO . useAsPtr t $ \tptr tlen ->
withConverter cnv $ \cptr -> do
let capacity = fromIntegral . max_bytes_for_string cptr . fromIntegral $
lengthWord16 t
createAndTrim (fromIntegral capacity) $ \sptr ->
fmap fromIntegral . handleError $
ucnv_fromUChars cptr (castPtr sptr) capacity tptr (fromIntegral tlen)
toUnicode :: Converter -> ByteString -> Text
toUnicode cnv bs =
unsafePerformIO . unsafeUseAsCStringLen bs $ \(sptr, slen) ->
withConverter cnv $ \cptr -> do
let capacity = slen * 2
allocaArray capacity $ \tptr ->
fromPtr tptr =<< (fmap fromIntegral . handleError $
ucnv_toUChars cptr tptr (fromIntegral capacity) sptr
(fromIntegral slen))
usesFallback :: Converter -> Bool
usesFallback cnv = unsafePerformIO $
asBool `fmap` withConverter cnv ucnv_usesFallback
getDefaultName :: IO String
getDefaultName = peekCString =<< ucnv_getDefaultName
isAmbiguous :: Converter -> Bool
isAmbiguous cnv = asBool . unsafePerformIO $ withConverter cnv ucnv_isAmbiguous
setDefaultName :: String -> IO ()
setDefaultName s = withCString s $ ucnv_setDefaultName
converterNames :: [String]
converterNames = unsafePerformIO $
mapM ((peekCString =<<) . ucnv_getAvailableName) [0..ucnv_countAvailable1]
standardNames :: [String]
standardNames = filter (not . null) . unsafePerformIO $
mapM ((peekCString =<<) . handleError . ucnv_getStandard) [0..ucnv_countStandards1]
aliases :: String -> [String]
aliases name = unsafePerformIO . withCString name $ \ptr -> do
count <- handleError $ ucnv_countAliases ptr
if count == 0
then return []
else mapM ((peekCString =<<) . handleError . ucnv_getAlias ptr) [0..count1]
foreign import ccall unsafe "hs_text_icu.h __hs_ucnv_open" ucnv_open
:: CString -> Ptr UErrorCode -> IO (Ptr UConverter)
foreign import ccall unsafe "hs_text_icu.h &__hs_ucnv_close" ucnv_close
:: FunPtr (Ptr UConverter -> IO ())
foreign import ccall unsafe "__get_max_bytes_for_string" max_bytes_for_string
:: Ptr UConverter -> CInt -> CInt
foreign import ccall unsafe "hs_text_icu.h __hs_ucnv_toUChars" ucnv_toUChars
:: Ptr UConverter -> Ptr UChar -> Int32 -> CString -> Int32
-> Ptr UErrorCode -> IO Int32
foreign import ccall unsafe "hs_text_icu.h __hs_ucnv_fromUChars" ucnv_fromUChars
:: Ptr UConverter -> CString -> Int32 -> Ptr UChar -> Int32
-> Ptr UErrorCode -> IO Int32
foreign import ccall unsafe "hs_text_icu.h __hs_ucnv_compareNames" ucnv_compareNames
:: CString -> CString -> IO CInt
foreign import ccall unsafe "hs_text_icu.h __hs_ucnv_getDefaultName" ucnv_getDefaultName
:: IO CString
foreign import ccall unsafe "hs_text_icu.h __hs_ucnv_setDefaultName" ucnv_setDefaultName
:: CString -> IO ()
foreign import ccall unsafe "hs_text_icu.h __hs_ucnv_countAvailable" ucnv_countAvailable
:: Int32
foreign import ccall unsafe "hs_text_icu.h __hs_ucnv_getAvailableName" ucnv_getAvailableName
:: Int32 -> IO CString
foreign import ccall unsafe "hs_text_icu.h __hs_ucnv_countAliases" ucnv_countAliases
:: CString -> Ptr UErrorCode -> IO Word16
foreign import ccall unsafe "hs_text_icu.h __hs_ucnv_getAlias" ucnv_getAlias
:: CString -> Word16 -> Ptr UErrorCode -> IO CString
foreign import ccall unsafe "hs_text_icu.h __hs_ucnv_countStandards" ucnv_countStandards
:: Word16
foreign import ccall unsafe "hs_text_icu.h __hs_ucnv_getStandard" ucnv_getStandard
:: Word16 -> Ptr UErrorCode -> IO CString
foreign import ccall unsafe "hs_text_icu.h __hs_ucnv_usesFallback" ucnv_usesFallback
:: Ptr UConverter -> IO UBool
foreign import ccall unsafe "hs_text_icu.h __hs_ucnv_setFallback" ucnv_setFallback
:: Ptr UConverter -> UBool -> IO ()
foreign import ccall unsafe "hs_text_icu.h __hs_ucnv_isAmbiguous" ucnv_isAmbiguous
:: Ptr UConverter -> IO UBool