{-# LINE 1 "Data/GI/Base/BasicConversions.hsc" #-}
{-# LANGUAGE ScopedTypeVariables, ConstraintKinds, FlexibleContexts #-}
{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
module Data.GI.Base.BasicConversions
( gflagsToWord
, wordToGFlags
, packGList
, unpackGList
, packGSList
, unpackGSList
, packGArray
, unpackGArray
, unrefGArray
, packGPtrArray
, unpackGPtrArray
, unrefPtrArray
, packGByteArray
, unpackGByteArray
, unrefGByteArray
, packGHashTable
, unpackGHashTable
, unrefGHashTable
, packByteString
, packZeroTerminatedByteString
, unpackByteStringWithLength
, unpackZeroTerminatedByteString
, packFileNameArray
, packZeroTerminatedFileNameArray
, unpackZeroTerminatedFileNameArray
, unpackFileNameArrayWithLength
, packUTF8CArray
, packZeroTerminatedUTF8CArray
, unpackUTF8CArrayWithLength
, unpackZeroTerminatedUTF8CArray
, packStorableArray
, packZeroTerminatedStorableArray
, unpackStorableArrayWithLength
, unpackZeroTerminatedStorableArray
, packMapStorableArray
, packMapZeroTerminatedStorableArray
, unpackMapStorableArrayWithLength
, unpackMapZeroTerminatedStorableArray
, packPtrArray
, packZeroTerminatedPtrArray
, unpackPtrArrayWithLength
, unpackZeroTerminatedPtrArray
, packBlockArray
, unpackBlockArrayWithLength
, unpackBoxedArrayWithLength
, stringToCString
, cstringToString
, textToCString
, withTextCString
, cstringToText
, byteStringToCString
, cstringToByteString
, mapZeroTerminatedCArray
, mapCArrayWithLength
, mapGArray
, mapPtrArray
, mapGList
, mapGSList
) where
{-# LINE 70 "Data/GI/Base/BasicConversions.hsc" #-}
import Control.Exception.Base (bracket)
import Control.Monad (foldM)
import Data.ByteString (ByteString)
import qualified Data.ByteString as B
import qualified Data.ByteString.Internal as BI
import Data.Maybe (fromMaybe)
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Text.Foreign as TF
import Foreign.Ptr (Ptr, plusPtr, nullPtr, nullFunPtr, castPtr)
import Foreign.ForeignPtr (withForeignPtr)
import Foreign.Storable (Storable, peek, poke, sizeOf)
import Foreign.C.Types (CInt(..), CUInt(..), CSize(..), CChar(..))
import Foreign.C.String (CString, withCString, peekCString)
import Data.Word
import Data.Int (Int32)
import Data.Bits (Bits, (.|.), (.&.), shift)
import Data.GI.Base.BasicTypes
import Data.GI.Base.CallStack (HasCallStack)
import Data.GI.Base.GHashTable (GEqualFunc, GHashFunc)
import Data.GI.Base.ManagedPtr (copyBoxedPtr)
import Data.GI.Base.Utils (allocBytes, callocBytes, memcpy, freeMem,
checkUnexpectedReturnNULL)
gflagsToWord :: (Num b, IsGFlag a) => [a] -> b
gflagsToWord flags = fromIntegral (go flags)
where go (f:fs) = fromEnum f .|. go fs
go [] = 0
wordToGFlags :: (Storable a, Integral a, Bits a, IsGFlag b) => a -> [b]
wordToGFlags w = go 0
where
nbits = (sizeOf w)*8
go k
| k == nbits = []
| otherwise = if mask .&. w /= 0
then toEnum (fromIntegral mask) : go (k+1)
else go (k+1)
where mask = shift 1 k
foreign import ccall "g_list_prepend" g_list_prepend ::
Ptr (GList (Ptr a)) -> Ptr a -> IO (Ptr (GList (Ptr a)))
packGList :: [Ptr a] -> IO (Ptr (GList (Ptr a)))
packGList l = foldM g_list_prepend nullPtr $ reverse l
unpackGList :: Ptr (GList (Ptr a)) -> IO [Ptr a]
unpackGList gsl
| gsl == nullPtr = return []
| otherwise =
do x <- peek (castPtr gsl)
next <- peek (gsl `plusPtr` sizeOf x)
xs <- unpackGList next
return $ x : xs
foreign import ccall "g_slist_prepend" g_slist_prepend ::
Ptr (GSList (Ptr a)) -> Ptr a -> IO (Ptr (GSList (Ptr a)))
packGSList :: [Ptr a] -> IO (Ptr (GSList (Ptr a)))
packGSList l = foldM g_slist_prepend nullPtr $ reverse l
unpackGSList :: Ptr (GSList (Ptr a)) -> IO [Ptr a]
unpackGSList gsl = unpackGList (castPtr gsl)
foreign import ccall "g_array_new" g_array_new ::
CInt -> CInt -> CUInt -> IO (Ptr (GArray ()))
foreign import ccall "g_array_set_size" g_array_set_size ::
Ptr (GArray ()) -> CUInt -> IO (Ptr (GArray ()))
foreign import ccall "g_array_unref" unrefGArray ::
Ptr (GArray a) -> IO ()
packGArray :: forall a. Storable a => [a] -> IO (Ptr (GArray a))
packGArray elems = do
let elemsize = sizeOf (elems!!0)
array <- g_array_new 0 0 (fromIntegral elemsize)
_ <- g_array_set_size array (fromIntegral $ length elems)
dataPtr <- peek (castPtr array :: Ptr (Ptr a))
fill dataPtr elems
return $ castPtr array
where
fill :: Ptr a -> [a] -> IO ()
fill _ [] = return ()
fill ptr (x:xs) =
do poke ptr x
fill (ptr `plusPtr` (sizeOf x)) xs
unpackGArray :: forall a. Storable a => Ptr (GArray a) -> IO [a]
unpackGArray array = do
dataPtr <- peek (castPtr array :: Ptr (Ptr a))
nitems <- peek (array `plusPtr` sizeOf dataPtr)
go dataPtr nitems
where go :: Ptr a -> CUInt -> IO [a]
go _ 0 = return []
go ptr n = do
x <- peek ptr
(x:) <$> go (ptr `plusPtr` sizeOf x) (n-1)
foreign import ccall "g_ptr_array_new" g_ptr_array_new ::
IO (Ptr (GPtrArray ()))
foreign import ccall "g_ptr_array_set_size" g_ptr_array_set_size ::
Ptr (GPtrArray ()) -> CUInt -> IO (Ptr (GPtrArray ()))
foreign import ccall "g_ptr_array_unref" unrefPtrArray ::
Ptr (GPtrArray a) -> IO ()
packGPtrArray :: [Ptr a] -> IO (Ptr (GPtrArray (Ptr a)))
packGPtrArray elems = do
array <- g_ptr_array_new
_ <- g_ptr_array_set_size array (fromIntegral $ length elems)
dataPtr <- peek (castPtr array :: Ptr (Ptr (Ptr a)))
fill dataPtr elems
return $ castPtr array
where
fill :: Ptr (Ptr a) -> [Ptr a] -> IO ()
fill _ [] = return ()
fill ptr (x:xs) =
do poke ptr x
fill (ptr `plusPtr` (sizeOf x)) xs
unpackGPtrArray :: Ptr (GPtrArray (Ptr a)) -> IO [Ptr a]
unpackGPtrArray array = do
dataPtr <- peek (castPtr array :: Ptr (Ptr (Ptr a)))
nitems <- peek (array `plusPtr` sizeOf dataPtr)
go dataPtr nitems
where go :: Ptr (Ptr a) -> CUInt -> IO [Ptr a]
go _ 0 = return []
go ptr n = do
x <- peek ptr
(x:) <$> go (ptr `plusPtr` sizeOf x) (n-1)
foreign import ccall "g_byte_array_new" g_byte_array_new ::
IO (Ptr GByteArray)
foreign import ccall "g_byte_array_append" g_byte_array_append ::
Ptr GByteArray -> Ptr a -> CUInt -> IO (Ptr GByteArray)
foreign import ccall "g_byte_array_unref" unrefGByteArray ::
Ptr GByteArray -> IO ()
packGByteArray :: ByteString -> IO (Ptr GByteArray)
packGByteArray bs = do
array <- g_byte_array_new
let (ptr, offset, length) = BI.toForeignPtr bs
_ <- withForeignPtr ptr $ \dataPtr ->
g_byte_array_append array (dataPtr `plusPtr` offset)
(fromIntegral length)
return array
unpackGByteArray :: Ptr GByteArray -> IO ByteString
unpackGByteArray array = do
dataPtr <- peek (castPtr array :: Ptr (Ptr CChar))
length <- peek (array `plusPtr` (sizeOf dataPtr)) :: IO CUInt
B.packCStringLen (dataPtr, fromIntegral length)
foreign import ccall "g_hash_table_new_full" g_hash_table_new_full ::
GHashFunc a -> GEqualFunc a -> GDestroyNotify a -> GDestroyNotify b ->
IO (Ptr (GHashTable a b))
foreign import ccall "g_hash_table_insert" g_hash_table_insert ::
Ptr (GHashTable a b) -> PtrWrapped a -> PtrWrapped b -> IO Int32
{-# LINE 237 "Data/GI/Base/BasicConversions.hsc" #-}
packGHashTable :: GHashFunc a -> GEqualFunc a ->
Maybe (GDestroyNotify a) -> Maybe (GDestroyNotify b) ->
[(PtrWrapped a, PtrWrapped b)] -> IO (Ptr (GHashTable a b))
packGHashTable keyHash keyEqual keyDestroy elemDestroy pairs = do
let keyDPtr = fromMaybe nullFunPtr keyDestroy
elemDPtr = fromMaybe nullFunPtr elemDestroy
ht <- g_hash_table_new_full keyHash keyEqual keyDPtr elemDPtr
mapM_ (uncurry (g_hash_table_insert ht)) pairs
return ht
foreign import ccall "g_hash_table_get_keys" g_hash_table_get_keys ::
Ptr (GHashTable a b) -> IO (Ptr (GList (Ptr a)))
foreign import ccall "g_hash_table_lookup" g_hash_table_lookup ::
Ptr (GHashTable a b) -> PtrWrapped a -> IO (PtrWrapped b)
unpackGHashTable :: Ptr (GHashTable a b) -> IO [(PtrWrapped a, PtrWrapped b)]
unpackGHashTable ht = do
keysGList <- g_hash_table_get_keys ht
keys <- (map (PtrWrapped . castPtr)) <$> unpackGList keysGList
g_list_free keysGList
elems <- mapM (g_hash_table_lookup ht) keys
return (zip keys elems)
foreign import ccall "g_hash_table_unref" unrefGHashTable ::
Ptr (GHashTable a b) -> IO ()
packByteString :: ByteString -> IO (Ptr Word8)
packByteString bs = do
let (ptr, offset, length) = BI.toForeignPtr bs
mem <- allocBytes length
withForeignPtr ptr $ \dataPtr ->
memcpy mem (dataPtr `plusPtr` offset) (fromIntegral length)
return mem
packZeroTerminatedByteString :: ByteString -> IO (Ptr Word8)
packZeroTerminatedByteString bs = do
let (ptr, offset, length) = BI.toForeignPtr bs
mem <- allocBytes (length+1)
withForeignPtr ptr $ \dataPtr ->
memcpy mem (dataPtr `plusPtr` offset) (fromIntegral length)
poke (mem `plusPtr` (offset+length)) (0 :: Word8)
return mem
unpackByteStringWithLength :: Integral a => a -> Ptr Word8 -> IO ByteString
unpackByteStringWithLength length ptr =
B.packCStringLen (castPtr ptr, fromIntegral length)
unpackZeroTerminatedByteString :: Ptr Word8 -> IO ByteString
unpackZeroTerminatedByteString ptr =
B.packCString (castPtr ptr)
packStorableArray :: Storable a => [a] -> IO (Ptr a)
packStorableArray = packMapStorableArray id
packZeroTerminatedStorableArray :: (Num a, Storable a) => [a] -> IO (Ptr a)
packZeroTerminatedStorableArray = packMapZeroTerminatedStorableArray id
unpackStorableArrayWithLength :: (Integral a, Storable b) =>
a -> Ptr b -> IO [b]
unpackStorableArrayWithLength = unpackMapStorableArrayWithLength id
unpackZeroTerminatedStorableArray :: (Eq a, Num a, Storable a) =>
Ptr a -> IO [a]
unpackZeroTerminatedStorableArray = unpackMapZeroTerminatedStorableArray id
packMapStorableArray :: forall a b. Storable b => (a -> b) -> [a] -> IO (Ptr b)
packMapStorableArray fn items = do
let nitems = length items
mem <- allocBytes $ (sizeOf (undefined::b)) * nitems
fill mem (map fn items)
return mem
where fill :: Ptr b -> [b] -> IO ()
fill _ [] = return ()
fill ptr (x:xs) = do
poke ptr x
fill (ptr `plusPtr` sizeOf x) xs
packMapZeroTerminatedStorableArray :: forall a b. (Num b, Storable b) =>
(a -> b) -> [a] -> IO (Ptr b)
packMapZeroTerminatedStorableArray fn items = do
let nitems = length items
mem <- allocBytes $ (sizeOf (undefined::b)) * (nitems+1)
fill mem (map fn items)
return mem
where fill :: Ptr b -> [b] -> IO ()
fill ptr [] = poke ptr 0
fill ptr (x:xs) = do
poke ptr x
fill (ptr `plusPtr` sizeOf x) xs
unpackMapStorableArrayWithLength :: forall a b c. (Integral a, Storable b) =>
(b -> c) -> a -> Ptr b -> IO [c]
unpackMapStorableArrayWithLength fn n ptr = map fn <$> go (fromIntegral n) ptr
where go :: Int -> Ptr b -> IO [b]
go 0 _ = return []
go n ptr = do
x <- peek ptr
(x:) <$> go (n-1) (ptr `plusPtr` sizeOf x)
unpackMapZeroTerminatedStorableArray :: forall a b. (Eq a, Num a, Storable a) =>
(a -> b) -> Ptr a -> IO [b]
unpackMapZeroTerminatedStorableArray fn ptr = map fn <$> go ptr
where go :: Ptr a -> IO [a]
go ptr = do
x <- peek ptr
if x == 0
then return []
else (x:) <$> go (ptr `plusPtr` sizeOf x)
packUTF8CArray :: [Text] -> IO (Ptr CString)
packUTF8CArray items = do
let nitems = length items
mem <- allocBytes $ nitems * (sizeOf (nullPtr :: CString))
fill mem items
return mem
where fill :: Ptr CString -> [Text] -> IO ()
fill _ [] = return ()
fill ptr (x:xs) =
do cstring <- textToCString x
poke ptr cstring
fill (ptr `plusPtr` sizeOf cstring) xs
packZeroTerminatedUTF8CArray :: [Text] -> IO (Ptr CString)
packZeroTerminatedUTF8CArray items = do
let nitems = length items
mem <- allocBytes $ (sizeOf (nullPtr :: CString)) * (nitems+1)
fill mem items
return mem
where fill :: Ptr CString -> [Text] -> IO ()
fill ptr [] = poke ptr nullPtr
fill ptr (x:xs) = do cstring <- textToCString x
poke ptr cstring
fill (ptr `plusPtr` sizeOf cstring) xs
unpackZeroTerminatedUTF8CArray :: HasCallStack => Ptr CString -> IO [Text]
unpackZeroTerminatedUTF8CArray listPtr = go listPtr
where go :: Ptr CString -> IO [Text]
go ptr = do
cstring <- peek ptr
if cstring == nullPtr
then return []
else (:) <$> cstringToText cstring
<*> go (ptr `plusPtr` sizeOf cstring)
unpackUTF8CArrayWithLength :: (HasCallStack, Integral a) =>
a -> Ptr CString -> IO [Text]
unpackUTF8CArrayWithLength n ptr = go (fromIntegral n) ptr
where go :: Int -> Ptr CString -> IO [Text]
go 0 _ = return []
go n ptr = do
cstring <- peek ptr
(:) <$> cstringToText cstring
<*> go (n-1) (ptr `plusPtr` sizeOf cstring)
packFileNameArray :: [String] -> IO (Ptr CString)
packFileNameArray items = do
let nitems = length items
mem <- allocBytes $ nitems * (sizeOf (nullPtr :: CString))
fill mem items
return mem
where fill :: Ptr CString -> [String] -> IO ()
fill _ [] = return ()
fill ptr (x:xs) =
do cstring <- stringToCString x
poke ptr cstring
fill (ptr `plusPtr` sizeOf cstring) xs
packZeroTerminatedFileNameArray :: [String] -> IO (Ptr CString)
packZeroTerminatedFileNameArray items = do
let nitems = length items
mem <- allocBytes $ (sizeOf (nullPtr :: CString)) * (nitems+1)
fill mem items
return mem
where fill :: Ptr CString -> [String] -> IO ()
fill ptr [] = poke ptr nullPtr
fill ptr (x:xs) = do cstring <- stringToCString x
poke ptr cstring
fill (ptr `plusPtr` sizeOf cstring) xs
unpackZeroTerminatedFileNameArray :: HasCallStack => Ptr CString -> IO [String]
unpackZeroTerminatedFileNameArray listPtr = go listPtr
where go :: Ptr CString -> IO [String]
go ptr = do
cstring <- peek ptr
if cstring == nullPtr
then return []
else (:) <$> cstringToString cstring
<*> go (ptr `plusPtr` sizeOf cstring)
unpackFileNameArrayWithLength :: (HasCallStack, Integral a) =>
a -> Ptr CString -> IO [String]
unpackFileNameArrayWithLength n ptr = go (fromIntegral n) ptr
where go :: Int -> Ptr CString -> IO [String]
go 0 _ = return []
go n ptr = do
cstring <- peek ptr
(:) <$> cstringToString cstring
<*> go (n-1) (ptr `plusPtr` sizeOf cstring)
foreign import ccall "g_strdup" g_strdup :: CString -> IO CString
stringToCString :: String -> IO CString
stringToCString str = withCString str g_strdup
cstringToString :: HasCallStack => CString -> IO String
cstringToString cstr = do
checkUnexpectedReturnNULL (T.pack "cstringToString") cstr
peekCString cstr
foreign import ccall "g_strndup" g_strndup ::
CString -> Word64 -> IO CString
{-# LINE 456 "Data/GI/Base/BasicConversions.hsc" #-}
textToCString :: Text -> IO CString
textToCString str = TF.withCStringLen str $ \(cstr, len) ->
if cstr /= nullPtr
then g_strndup cstr (fromIntegral len)
else callocBytes 1
withTextCString :: Text -> (CString -> IO a) -> IO a
withTextCString text action = bracket (textToCString text) freeMem action
foreign import ccall "strlen" c_strlen ::
CString -> IO (CSize)
cstringToText :: HasCallStack => CString -> IO Text
cstringToText cstr = do
checkUnexpectedReturnNULL (T.pack "cstringToText") cstr
len <- c_strlen cstr
let cstrlen = (cstr, fromIntegral len)
TF.peekCStringLen cstrlen
byteStringToCString :: ByteString -> IO CString
byteStringToCString bs = B.useAsCString bs g_strdup
cstringToByteString :: HasCallStack => CString -> IO ByteString
cstringToByteString cstr = do
checkUnexpectedReturnNULL (T.pack "cstringToByteString") cstr
B.packCString cstr
packPtrArray :: [Ptr a] -> IO (Ptr (Ptr a))
packPtrArray items = do
let nitems = length items
mem <- allocBytes $ (sizeOf (nullPtr :: Ptr a)) * nitems
fill mem items
return mem
where fill :: Ptr (Ptr a) -> [Ptr a] -> IO ()
fill _ [] = return ()
fill ptr (x:xs) = do poke ptr x
fill (ptr `plusPtr` sizeOf x) xs
packZeroTerminatedPtrArray :: [Ptr a] -> IO (Ptr (Ptr a))
packZeroTerminatedPtrArray items = do
let nitems = length items
mem <- allocBytes $ (sizeOf (nullPtr :: Ptr a)) * (nitems+1)
fill mem items
return mem
where fill :: Ptr (Ptr a) -> [Ptr a] -> IO ()
fill ptr [] = poke ptr nullPtr
fill ptr (x:xs) = do poke ptr x
fill (ptr `plusPtr` sizeOf x) xs
unpackPtrArrayWithLength :: Integral a => a -> Ptr (Ptr b) -> IO [Ptr b]
unpackPtrArrayWithLength n ptr = go (fromIntegral n) ptr
where go :: Int -> Ptr (Ptr a) -> IO [Ptr a]
go 0 _ = return []
go n ptr = (:) <$> peek ptr
<*> go (n-1) (ptr `plusPtr` sizeOf (nullPtr :: Ptr a))
unpackZeroTerminatedPtrArray :: Ptr (Ptr a) -> IO [Ptr a]
unpackZeroTerminatedPtrArray ptr = go ptr
where go :: Ptr (Ptr a) -> IO [Ptr a]
go ptr = do
p <- peek ptr
if p == nullPtr
then return []
else (p:) <$> go (ptr `plusPtr` sizeOf p)
mapZeroTerminatedCArray :: (Ptr a -> IO b) -> Ptr (Ptr a) -> IO ()
mapZeroTerminatedCArray f dataPtr
| (dataPtr == nullPtr) = return ()
| otherwise =
do ptr <- peek dataPtr
if ptr == nullPtr
then return ()
else do
_ <- f ptr
mapZeroTerminatedCArray f (dataPtr `plusPtr` sizeOf ptr)
packBlockArray :: Int -> [Ptr a] -> IO (Ptr a)
packBlockArray size items = do
let nitems = length items
mem <- allocBytes $ size * nitems
fill mem items
return mem
where fill :: Ptr a -> [Ptr a] -> IO ()
fill _ [] = return ()
fill ptr (x:xs) = do memcpy ptr x size
fill (ptr `plusPtr` size) xs
foreign import ccall "g_memdup" g_memdup ::
Ptr a -> CUInt -> IO (Ptr a)
unpackBlockArrayWithLength :: Integral a => Int -> a -> Ptr b -> IO [Ptr b]
unpackBlockArrayWithLength size n ptr = go size (fromIntegral n) ptr
where go :: Int -> Int -> Ptr b -> IO [Ptr b]
go _ 0 _ = return []
go size n ptr = do
buf <- g_memdup ptr (fromIntegral size)
(buf :) <$> go size (n-1) (ptr `plusPtr` size)
unpackBoxedArrayWithLength :: forall a b. (Integral a, GBoxed b) =>
Int -> a -> Ptr b -> IO [Ptr b]
unpackBoxedArrayWithLength size n ptr = go size (fromIntegral n) ptr
where go :: Int -> Int -> Ptr b -> IO [Ptr b]
go _ 0 _ = return []
go size n ptr = do
buf <- copyBoxedPtr ptr
(buf :) <$> go size (n-1) (ptr `plusPtr` size)
mapCArrayWithLength :: (Storable a, Integral b) =>
b -> (a -> IO c) -> Ptr a -> IO ()
mapCArrayWithLength n f dataPtr
| (dataPtr == nullPtr) = return ()
| (n <= 0) = return ()
| otherwise =
do ptr <- peek dataPtr
_ <- f ptr
mapCArrayWithLength (n-1) f (dataPtr `plusPtr` sizeOf ptr)
mapGArray :: forall a b. Storable a => (a -> IO b) -> Ptr (GArray a) -> IO ()
mapGArray f array
| (array == nullPtr) = return ()
| otherwise =
do dataPtr <- peek (castPtr array :: Ptr (Ptr a))
nitems <- peek (array `plusPtr` sizeOf dataPtr)
go dataPtr nitems
where go :: Ptr a -> Int -> IO ()
go _ 0 = return ()
go ptr n = do
x <- peek ptr
_ <- f x
go (ptr `plusPtr` sizeOf x) (n-1)
mapPtrArray :: (Ptr a -> IO b) -> Ptr (GPtrArray (Ptr a)) -> IO ()
mapPtrArray f array = mapGArray f (castPtr array)
mapGList :: (Ptr a -> IO b) -> Ptr (GList (Ptr a)) -> IO ()
mapGList f glist
| (glist == nullPtr) = return ()
| otherwise =
do ptr <- peek (castPtr glist)
next <- peek (glist `plusPtr` sizeOf ptr)
_ <- f ptr
mapGList f next
mapGSList :: (Ptr a -> IO b) -> Ptr (GSList (Ptr a)) -> IO ()
mapGSList f gslist = mapGList f (castPtr gslist)