    {-# LANGUAGE ForeignFunctionInterface, CPP #-}
    -- |
    -- Module      : Data.Text.ICU.Convert
    -- Copyright   : (c) 2009, 2010 Bryan O'Sullivan
    --
    -- License     : BSD-style
    -- Maintainer  : bos@serpentine.com
    -- Stability   : experimental
    -- Portability : GHC
    --
    -- Character set conversion functions for Unicode, implemented as
    -- bindings to the International Components for Unicode (ICU)
    -- libraries.
    module Data.Text.ICU.Convert
        (
        -- * Character set conversion
          Converter
        -- ** Basic functions
        , open
        , fromUnicode
        , toUnicode
        -- ** Converter metadata
        , getName
        , usesFallback
        , isAmbiguous
        -- * Functions for controlling global behavior
        , getDefaultName
        , setDefaultName
        -- * Miscellaneous functions
        , compareNames
        , aliases
        -- * Metadata
        , 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, useAsPtr)
    #if !MIN_VERSION_text(2,0,0)
    import Data.Text.ICU.Internal (UChar)
    #endif
    import Data.Text.ICU.Internal (lengthWord)
    import Data.Text.ICU.Convert.Internal
    import Data.Text.ICU.Error.Internal (UErrorCode, handleError)
    import Data.Word (Word8, Word16)
    import Foreign.C.String (CString, peekCString, withCString)
    import Foreign.C.Types (CInt(..))
    import Foreign.Marshal.Array (allocaArray)
    import Foreign.Ptr (FunPtr, Ptr)
    import System.IO.Unsafe (unsafePerformIO)
    import Data.Text.ICU.Internal (UBool, asBool, asOrdering, withName, newICUPtr)

    -- | Do a fuzzy compare of two converter/alias names.  The comparison
    -- is case-insensitive, ignores leading zeroes if they are not
    -- followed by further digits, and ignores all but letters and digits.
    -- Thus the strings @\"UTF-8\"@, @\"utf_8\"@, @\"u*T\@f08\"@ and
    -- @\"Utf 8\"@ are exactly equivalent.  See section 1.4, Charset Alias
    -- Matching in Unicode Technical Standard #22 at
    -- <http://www.unicode.org/reports/tr22/>
    compareNames :: String -> String -> Ordering
    compareNames :: String -> String -> Ordering
    compareNames String
    a String
    b =
      IO Ordering -> Ordering
    forall a. IO a -> a
    unsafePerformIO (IO Ordering -> Ordering)
    -> ((CString -> IO Ordering) -> IO Ordering)
    -> (CString -> IO Ordering)
    -> Ordering
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> (CString -> IO Ordering) -> IO Ordering
    forall a. String -> (CString -> IO a) -> IO a
    withCString String
    a ((CString -> IO Ordering) -> Ordering)
    -> (CString -> IO Ordering) -> Ordering
    forall a b. (a -> b) -> a -> b
    $ \CString
    aptr ->
        (CInt -> Ordering) -> IO CInt -> IO Ordering
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap CInt -> Ordering
    forall a. Integral a => a -> Ordering
    asOrdering (IO CInt -> IO Ordering)
    -> ((CString -> IO CInt) -> IO CInt)
    -> (CString -> IO CInt)
    -> IO Ordering
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> (CString -> IO CInt) -> IO CInt
    forall a. String -> (CString -> IO a) -> IO a
    withCString String
    b ((CString -> IO CInt) -> IO Ordering)
    -> (CString -> IO CInt) -> IO Ordering
    forall a b. (a -> b) -> a -> b
    $ CString -> CString -> IO CInt
    ucnv_compareNames CString
    aptr

    -- | Create a 'Converter' with the name of a coded character set
    -- specified as a string.  The actual name will be resolved with the
    -- alias file using a case-insensitive string comparison that ignores
    -- leading zeroes and all non-alphanumeric characters.  E.g., the
    -- names @\"UTF8\"@, @\"utf-8\"@, @\"u*T\@f08\"@ and @\"Utf 8\"@ are
    -- all equivalent (see also 'compareNames').  If an empty string is
    -- passed for the converter name, it will create one with the
    -- 'getDefaultName' return value.
    --
    -- A converter name may contain options like a locale specification to
    -- control the specific behavior of the newly instantiated converter.
    -- The meaning of the options depends on the particular converter.  If
    -- an option is not defined for or recognized by a given converter,
    -- then it is ignored.
    --
    -- Options are appended to the converter name string, with a comma
    -- between the name and the first option and also between adjacent
    -- options.
    --
    -- If the alias is ambiguous, then the preferred converter is used.
    --
    -- The conversion behavior and names can vary between platforms. ICU
    -- may convert some characters differently from other
    -- platforms. Details on this topic are in the ICU User's Guide at
    -- <http://icu-project.org/userguide/conversion.html>. Aliases
    -- starting with a @\"cp\"@ prefix have no specific meaning other than
    -- its an alias starting with the letters @\"cp\"@. Please do not
    -- associate any meaning to these aliases.
    open :: String                  -- ^ Name of the converter to use.
         -> Maybe Bool              -- ^ Whether to use fallback mappings
                                    -- (see 'usesFallback' for details).
         -> IO Converter
    open :: String -> Maybe Bool -> IO Converter
    open String
    name Maybe Bool
    mf = do
      c <- (ForeignPtr UConverter -> Converter)
    -> FinalizerPtr UConverter -> IO (Ptr UConverter) -> IO Converter
    forall a i.
    (ForeignPtr a -> i) -> FinalizerPtr a -> IO (Ptr a) -> IO i
    newICUPtr ForeignPtr UConverter -> Converter
    Converter FinalizerPtr UConverter
    ucnv_close (IO (Ptr UConverter) -> IO Converter)
    -> IO (Ptr UConverter) -> IO Converter
    forall a b. (a -> b) -> a -> b
    $ String -> (CString -> IO (Ptr UConverter)) -> IO (Ptr UConverter)
    forall a. String -> (CString -> IO a) -> IO a
    withName String
    name ((Ptr CInt -> IO (Ptr UConverter)) -> IO (Ptr UConverter)
    forall a. (Ptr CInt -> IO a) -> IO a
    handleError ((Ptr CInt -> IO (Ptr UConverter)) -> IO (Ptr UConverter))
    -> (CString -> Ptr CInt -> IO (Ptr UConverter))
    -> CString
    -> IO (Ptr UConverter)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . CString -> Ptr CInt -> IO (Ptr UConverter)
    ucnv_open)
      case mf of
        Just Bool
    f -> Converter -> (Ptr UConverter -> IO ()) -> IO ()
    forall a. Converter -> (Ptr UConverter -> IO a) -> IO a
    withConverter Converter
    c ((Ptr UConverter -> IO ()) -> IO ())
    -> (Ptr UConverter -> IO ()) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \Ptr UConverter
    p -> Ptr UConverter -> UBool -> IO ()
    ucnv_setFallback Ptr UConverter
    p (UBool -> IO ()) -> (Bool -> UBool) -> Bool -> IO ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Int -> UBool
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Int -> UBool) -> (Bool -> Int) -> Bool -> UBool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Bool -> Int
    forall a. Enum a => a -> Int
    fromEnum (Bool -> IO ()) -> Bool -> IO ()
    forall a b. (a -> b) -> a -> b
    $ Bool
    f
        Maybe Bool
    _ -> () -> IO ()
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()
      return c

    -- | Encode a Unicode string into a code page string using the given converter.
    fromUnicode :: Converter -> Text -> ByteString
    fromUnicode :: Converter -> Text -> ByteString
    fromUnicode Converter
    cnv Text
    t =
      IO ByteString -> ByteString
    forall a. IO a -> a
    unsafePerformIO (IO ByteString -> ByteString)
    -> ((Ptr Word8 -> I8 -> IO ByteString) -> IO ByteString)
    -> (Ptr Word8 -> I8 -> IO ByteString)
    -> ByteString
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> (Ptr Word8 -> I8 -> IO ByteString) -> IO ByteString
    forall a. Text -> (Ptr Word8 -> I8 -> IO a) -> IO a
    useAsPtr Text
    t ((Ptr Word8 -> I8 -> IO ByteString) -> ByteString)
    -> (Ptr Word8 -> I8 -> IO ByteString) -> ByteString
    forall a b. (a -> b) -> a -> b
    $ \Ptr Word8
    tptr I8
    tlen ->
        Converter -> (Ptr UConverter -> IO ByteString) -> IO ByteString
    forall a. Converter -> (Ptr UConverter -> IO a) -> IO a
    withConverter Converter
    cnv ((Ptr UConverter -> IO ByteString) -> IO ByteString)
    -> (Ptr UConverter -> IO ByteString) -> IO ByteString
    forall a b. (a -> b) -> a -> b
    $ \Ptr UConverter
    cptr -> do
          let capacity :: Int32
    capacity = CInt -> Int32
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (CInt -> Int32) -> (Int -> CInt) -> Int -> Int32
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Ptr UConverter -> CInt -> CInt
    ucnv_max_bytes_for_string Ptr UConverter
    cptr (CInt -> CInt) -> (Int -> CInt) -> Int -> CInt
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Int -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Int -> Int32) -> Int -> Int32
    forall a b. (a -> b) -> a -> b
    $
                         Text -> Int
    lengthWord Text
    t
          Int -> (Ptr Word8 -> IO Int) -> IO ByteString
    createAndTrim (Int32 -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int32
    capacity) ((Ptr Word8 -> IO Int) -> IO ByteString)
    -> (Ptr Word8 -> IO Int) -> IO ByteString
    forall a b. (a -> b) -> a -> b
    $ \Ptr Word8
    sptr ->
            (Int32 -> Int) -> IO Int32 -> IO Int
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap Int32 -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (IO Int32 -> IO Int)
    -> ((Ptr CInt -> IO Int32) -> IO Int32)
    -> (Ptr CInt -> IO Int32)
    -> IO Int
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Ptr CInt -> IO Int32) -> IO Int32
    forall a. (Ptr CInt -> IO a) -> IO a
    handleError ((Ptr CInt -> IO Int32) -> IO Int)
    -> (Ptr CInt -> IO Int32) -> IO Int
    forall a b. (a -> b) -> a -> b
    $
    #if MIN_VERSION_text(2,0,0)
               Ptr UConverter
    -> Ptr Word8 -> Int32 -> Ptr Word8 -> Int32 -> Ptr CInt -> IO Int32
    ucnv_fromAlgorithmic_UTF8
    #else
               ucnv_fromUChars
    #endif
               Ptr UConverter
    cptr Ptr Word8
    sptr Int32
    capacity Ptr Word8
    tptr (I8 -> Int32
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral I8
    tlen)

    -- | Decode an encoded string into a Unicode string using the given converter.
    toUnicode :: Converter -> ByteString -> Text
    toUnicode :: Converter -> ByteString -> Text
    toUnicode Converter
    cnv ByteString
    bs =
      IO Text -> Text
    forall a. IO a -> a
    unsafePerformIO (IO Text -> Text)
    -> ((CStringLen -> IO Text) -> IO Text)
    -> (CStringLen -> IO Text)
    -> Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ByteString -> (CStringLen -> IO Text) -> IO Text
    forall a. ByteString -> (CStringLen -> IO a) -> IO a
    unsafeUseAsCStringLen ByteString
    bs ((CStringLen -> IO Text) -> Text)
    -> (CStringLen -> IO Text) -> Text
    forall a b. (a -> b) -> a -> b
    $ \(CString
    sptr, Int
    slen) ->
        Converter -> (Ptr UConverter -> IO Text) -> IO Text
    forall a. Converter -> (Ptr UConverter -> IO a) -> IO a
    withConverter Converter
    cnv ((Ptr UConverter -> IO Text) -> IO Text)
    -> (Ptr UConverter -> IO Text) -> IO Text
    forall a b. (a -> b) -> a -> b
    $ \Ptr UConverter
    cptr -> do
          let (Int
    capacity, Ptr UConverter
    -> Ptr Word8 -> Int32 -> CString -> Int32 -> Ptr CInt -> IO Int32
    conv) =
    #if MIN_VERSION_text(2,0,0)
                  (Int
    slen Int -> Int -> Int
    forall a. Num a => a -> a -> a
    * Int
    4, Ptr UConverter
    -> Ptr Word8 -> Int32 -> CString -> Int32 -> Ptr CInt -> IO Int32
    ucnv_toAlgorithmic_UTF8)
    #else
                  (slen * 2, ucnv_toUChars)
    #endif
          Int -> (Ptr Word8 -> IO Text) -> IO Text
    forall a b. Storable a => Int -> (Ptr a -> IO b) -> IO b
    allocaArray Int
    capacity ((Ptr Word8 -> IO Text) -> IO Text)
    -> (Ptr Word8 -> IO Text) -> IO Text
    forall a b. (a -> b) -> a -> b
    $ \Ptr Word8
    tptr ->
            Ptr Word8 -> I8 -> IO Text
    fromPtr Ptr Word8
    tptr (I8 -> IO Text) -> IO I8 -> IO Text
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< ((Int32 -> I8) -> IO Int32 -> IO I8
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap Int32 -> I8
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (IO Int32 -> IO I8)
    -> ((Ptr CInt -> IO Int32) -> IO Int32)
    -> (Ptr CInt -> IO Int32)
    -> IO I8
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Ptr CInt -> IO Int32) -> IO Int32
    forall a. (Ptr CInt -> IO a) -> IO a
    handleError ((Ptr CInt -> IO Int32) -> IO I8)
    -> (Ptr CInt -> IO Int32) -> IO I8
    forall a b. (a -> b) -> a -> b
    $
                              Ptr UConverter
    -> Ptr Word8 -> Int32 -> CString -> Int32 -> Ptr CInt -> IO Int32
    conv Ptr UConverter
    cptr Ptr Word8
    tptr (Int -> Int32
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    capacity) CString
    sptr
                                            (Int -> Int32
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    slen))

    -- | Determines whether the converter uses fallback mappings or not.
    -- This flag has restrictions.  Regardless of this flag, the converter
    -- will always use fallbacks from Unicode Private Use codepoints, as
    -- well as reverse fallbacks (to Unicode).  For details see \".ucm
    -- File Format\" in the Conversion Data chapter of the ICU User Guide:
    -- <http://www.icu-project.org/userguide/conversion-data.html#ucmformat>
    usesFallback :: Converter -> Bool
    usesFallback :: Converter -> Bool
    usesFallback Converter
    cnv = IO Bool -> Bool
    forall a. IO a -> a
    unsafePerformIO (IO Bool -> Bool) -> IO Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $
                       UBool -> Bool
    forall a. Integral a => a -> Bool
    asBool (UBool -> Bool) -> IO UBool -> IO Bool
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    `fmap` Converter -> (Ptr UConverter -> IO UBool) -> IO UBool
    forall a. Converter -> (Ptr UConverter -> IO a) -> IO a
    withConverter Converter
    cnv Ptr UConverter -> IO UBool
    ucnv_usesFallback

    -- | Returns the current default converter name. If you want to 'open'
    -- a default converter, you do not need to use this function.  It is
    -- faster to pass the empty string to 'open' the default converter.
    getDefaultName :: IO String
    getDefaultName :: IO String
    getDefaultName = CString -> IO String
    peekCString (CString -> IO String) -> IO CString -> IO String
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< IO CString
    ucnv_getDefaultName

    -- | Indicates whether the converter contains ambiguous mappings of
    -- the same character or not.
    isAmbiguous :: Converter -> Bool
    isAmbiguous :: Converter -> Bool
    isAmbiguous Converter
    cnv = UBool -> Bool
    forall a. Integral a => a -> Bool
    asBool (UBool -> Bool) -> (IO UBool -> UBool) -> IO UBool -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . IO UBool -> UBool
    forall a. IO a -> a
    unsafePerformIO (IO UBool -> Bool) -> IO UBool -> Bool
    forall a b. (a -> b) -> a -> b
    $ Converter -> (Ptr UConverter -> IO UBool) -> IO UBool
    forall a. Converter -> (Ptr UConverter -> IO a) -> IO a
    withConverter Converter
    cnv Ptr UConverter -> IO UBool
    ucnv_isAmbiguous

    -- | Sets the current default converter name. If this function needs
    -- to be called, it should be called during application
    -- initialization. Most of the time, the results from 'getDefaultName'
    -- or 'open' with an empty string argument is sufficient for your
    -- application.
    --
    -- /Note/: this function is not thread safe. /Do not/ call this
    -- function when /any/ ICU function is being used from more than one
    -- thread!
    setDefaultName :: String -> IO ()
    setDefaultName :: String -> IO ()
    setDefaultName String
    s = String -> (CString -> IO ()) -> IO ()
    forall a. String -> (CString -> IO a) -> IO a
    withCString String
    s ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ CString -> IO ()
    ucnv_setDefaultName

    -- | A list of the canonical names of all available converters.
    converterNames :: [String]
    {-# NOINLINE converterNames #-}
    converterNames :: [String]
    converterNames = IO [String] -> [String]
    forall a. IO a -> a
    unsafePerformIO (IO [String] -> [String]) -> IO [String] -> [String]
    forall a b. (a -> b) -> a -> b
    $
      (Int32 -> IO String) -> [Int32] -> IO [String]
    forall (t :: * -> *) (m :: * -> *) a b.
    (Traversable t, Monad m) =>
    (a -> m b) -> t a -> m (t b)
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
    mapM ((CString -> IO String
    peekCString (CString -> IO String) -> IO CString -> IO String
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<<) (IO CString -> IO String)
    -> (Int32 -> IO CString) -> Int32 -> IO String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Int32 -> IO CString
    ucnv_getAvailableName) [Int32
    0..Int32
    ucnv_countAvailableInt32 -> Int32 -> Int32
    forall a. Num a => a -> a -> a
    -Int32
    1]

    -- | The list of supported standard names.
    standardNames :: [String]
    {-# NOINLINE standardNames #-}
    standardNames :: [String]
    standardNames = (String -> Bool) -> [String] -> [String]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (Bool -> Bool
    not (Bool -> Bool) -> (String -> Bool) -> String -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null) ([String] -> [String])
    -> (IO [String] -> [String]) -> IO [String] -> [String]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . IO [String] -> [String]
    forall a. IO a -> a
    unsafePerformIO (IO [String] -> [String]) -> IO [String] -> [String]
    forall a b. (a -> b) -> a -> b
    $
      (Word16 -> IO String) -> [Word16] -> IO [String]
    forall (t :: * -> *) (m :: * -> *) a b.
    (Traversable t, Monad m) =>
    (a -> m b) -> t a -> m (t b)
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
    mapM ((CString -> IO String
    peekCString (CString -> IO String) -> IO CString -> IO String
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<<) (IO CString -> IO String)
    -> (Word16 -> IO CString) -> Word16 -> IO String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Ptr CInt -> IO CString) -> IO CString
    forall a. (Ptr CInt -> IO a) -> IO a
    handleError ((Ptr CInt -> IO CString) -> IO CString)
    -> (Word16 -> Ptr CInt -> IO CString) -> Word16 -> IO CString
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Word16 -> Ptr CInt -> IO CString
    ucnv_getStandard) [Word16
    0..Word16
    ucnv_countStandardsWord16 -> Word16 -> Word16
    forall a. Num a => a -> a -> a
    -Word16
    1]

    -- | Return the aliases for a given converter or alias name.
    aliases :: String -> [String]
    aliases :: String -> [String]
    aliases String
    name = IO [String] -> [String]
    forall a. IO a -> a
    unsafePerformIO (IO [String] -> [String])
    -> ((CString -> IO [String]) -> IO [String])
    -> (CString -> IO [String])
    -> [String]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> (CString -> IO [String]) -> IO [String]
    forall a. String -> (CString -> IO a) -> IO a
    withCString String
    name ((CString -> IO [String]) -> [String])
    -> (CString -> IO [String]) -> [String]
    forall a b. (a -> b) -> a -> b
    $ \CString
    ptr -> do
      count <- (Ptr CInt -> IO Word16) -> IO Word16
    forall a. (Ptr CInt -> IO a) -> IO a
    handleError ((Ptr CInt -> IO Word16) -> IO Word16)
    -> (Ptr CInt -> IO Word16) -> IO Word16
    forall a b. (a -> b) -> a -> b
    $ CString -> Ptr CInt -> IO Word16
    ucnv_countAliases CString
    ptr
      if count == 0
        then return []
        else mapM ((peekCString =<<) . handleError . ucnv_getAlias ptr) [0..count-1]

    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 "__hs_ucnv_get_max_bytes_for_string" ucnv_max_bytes_for_string
        :: Ptr UConverter -> CInt -> CInt

    #if MIN_VERSION_text(2,0,0)

    foreign import ccall unsafe "hs_text_icu.h __hs_ucnv_toAlgorithmic_UTF8" ucnv_toAlgorithmic_UTF8
        :: Ptr UConverter -> Ptr Word8 -> Int32 -> CString -> Int32
        -> Ptr UErrorCode -> IO Int32

    foreign import ccall unsafe "hs_text_icu.h __hs_ucnv_fromAlgorithmic_UTF8" ucnv_fromAlgorithmic_UTF8
        :: Ptr UConverter -> Ptr Word8 -> Int32 -> Ptr Word8 -> Int32
        -> Ptr UErrorCode -> IO Int32

    #else

    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 -> Ptr Word8 -> Int32 -> Ptr UChar -> Int32
        -> Ptr UErrorCode -> IO Int32

    #endif

    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