cpu-0.1.0: System/Endian.hs
{-# LANGUAGE CPP, ForeignFunctionInterface #-}
-- |
-- Module : System.Endian
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : experimental
-- Portability : unknown
--
module System.Endian
( Endianness(..)
, getSystemEndianness
-- little endian to and from cpu
, fromLE32
, fromLE64
, toLE32
, toLE64
-- big endian to and from cpu
, fromBE32
, fromBE64
, toBE32
, toBE64
) where
import Foreign.Marshal.Alloc
import Foreign.Storable
import Foreign.Ptr
import Foreign.C.Types
import System.IO.Unsafe (unsafePerformIO)
import Data.Word
-- | represent the CPU endianness
--
-- Big endian system stores bytes with the MSB as the first byte.
-- Little endian system stores bytes with the LSB as the first byte.
--
-- middle endian is purposely avoided.
data Endianness = LittleEndian
| BigEndian
deriving (Show,Eq)
-- | return the system endianness
getSystemEndianness :: Endianness
getSystemEndianness = unsafePerformIO $ alloca $ \p ->
poke p cst >> peek (castPtr p) >>= return . check
where cst :: Word32
cst = 0x01000000
check :: Word8 -> Endianness
check x
| x == 0x01 = BigEndian
| otherwise = LittleEndian
-- | Convert from a big endian 64 bit value to the cpu endianness
fromBE64 :: Word64 -> Word64
fromBE64 = if getSystemEndianness == BigEndian then id else swap64
-- | Convert from a little endian 64 bit value to the cpu endianness
fromLE64 :: Word64 -> Word64
fromLE64 = if getSystemEndianness == LittleEndian then id else swap64
-- | Convert from a big endian 32 bit value to the cpu endianness
fromBE32 :: Word32 -> Word32
fromBE32 = if getSystemEndianness == BigEndian then id else swap32
-- | Convert from a little endian 32 bit value to the cpu endianness
fromLE32 :: Word32 -> Word32
fromLE32 = if getSystemEndianness == LittleEndian then id else swap32
-- | Convert a 64 bit value in cpu endianess to big endian
toBE64 :: Word64 -> Word64
toBE64 = fromBE64
-- | Convert a 64 bit value in cpu endianess to little endian
toLE64 :: Word64 -> Word64
toLE64 = fromLE64
-- | Convert a 32 bit value in cpu endianess to big endian
toBE32 :: Word32 -> Word32
toBE32 = fromBE32
-- | Convert a 32 bit value in cpu endianess to little endian
toLE32 :: Word32 -> Word32
toLE32 = fromLE32
-- | Transform a 32 bit value bytes from a.b.c.d to d.c.b.a
{-# INLINE swap32 #-}
swap32 :: Word32 -> Word32
swap32 = fromIntegral . c_swap32 . fromIntegral
-- | Transform a 64 bit value bytes from a.b.c.d.e.f.g.h to h.g.f.e.d.c.b.a
{-# INLINE swap64 #-}
swap64 :: Word64 -> Word64
swap64 = fromIntegral . c_swap64 . fromIntegral
foreign import ccall safe "bitfn_swap32" c_swap32 :: CUInt -> CUInt
foreign import ccall safe "bitfn_swap64" c_swap64 :: CULLong -> CULLong