{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE MagicHash #-}
#if __GLASGOW_HASKELL__ >= 702
{-# LANGUAGE Trustworthy #-}
#endif
module Data.ByteString.Base16
( encode
, decode
, decodeLenient
) where
import Data.ByteString (empty)
import Data.ByteString.Base16.Internal
import Data.ByteString.Internal
import Foreign.ForeignPtr
import Foreign.Ptr
import GHC.ForeignPtr
#if __GLASGOW_HASKELL__ >= 702
import System.IO.Unsafe (unsafeDupablePerformIO)
#else
import GHC.IO (unsafeDupablePerformIO)
#endif
encode :: ByteString -> ByteString
encode (PS sfp soff slen)
| slen > maxBound `div` 2 =
error "Data.ByteString.Base16.encode: input too long"
| otherwise = unsafeCreate (slen * 2) $ \dptr ->
withForeignPtr sfp $ \sptr ->
encodeLoop dptr
(sptr `plusPtr` soff)
(sptr `plusPtr` (soff + slen))
decode :: ByteString -> Either String ByteString
decode (PS sfp soff slen)
| slen == 0 = Right empty
| r /= 0 = Left "invalid bytestring size"
| otherwise = unsafeDupablePerformIO $ do
dfp <- mallocPlainForeignPtrBytes q
withForeignPtr dfp $ \dptr ->
withForeignPtr sfp $ \sptr ->
decodeLoop dfp dptr
(plusPtr sptr soff)
(plusPtr sptr (soff + slen))
where
!q = slen `quot` 2
!r = slen `rem` 2
decodeLenient :: ByteString -> ByteString
decodeLenient (PS !sfp !soff !slen)
| slen == 0 = empty
| otherwise = unsafeDupablePerformIO $ do
dfp <- mallocPlainForeignPtrBytes (q * 2)
withForeignPtr dfp $ \dptr ->
withForeignPtr sfp $ \sptr ->
lenientLoop dfp dptr
(plusPtr sptr soff)
(plusPtr sptr (soff + slen))
where
!q = slen `quot` 2