{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE OverloadedStrings #-}
module Data.ByteString.Base32.Internal.Head
( encodeBase32_
, encodeBase32NoPad_
, decodeBase32_
) where


import Data.ByteString.Internal
import Data.ByteString.Base32.Internal.Loop
import Data.ByteString.Base32.Internal.Tail
import Data.ByteString.Base32.Internal.Utils
import Data.Text (Text)

import Foreign.Ptr
import Foreign.ForeignPtr

import GHC.Exts
import GHC.ForeignPtr
import GHC.Word

import System.IO.Unsafe


-- | Head of the base32 encoding loop - marshal data, assemble loops
--
encodeBase32_ :: Addr# -> ByteString -> ByteString
encodeBase32_ !lut (PS !sfp !o !l) =
    unsafeDupablePerformIO $ do
      dfp <- mallocPlainForeignPtrBytes dlen
      withForeignPtr dfp $ \dptr ->
        withForeignPtr sfp $ \sptr -> do
          let !end = plusPtr sptr (l + o)
          innerLoop
            lut
            (castPtr dptr)
            (plusPtr sptr o)
            end
            (loopTail lut dfp dptr end)
  where
    !q = (l * 8) `quot` 5
    !r = (l * 8) `rem` 5
    !dlen = padCeilN 8 (q + if r == 0 then 0 else 1)

-- | Head of the unpadded base32 encoding loop - marshal data, assemble loops
--
encodeBase32NoPad_ :: Addr# -> ByteString -> ByteString
encodeBase32NoPad_ !lut (PS !sfp !o !l) =
    unsafeDupablePerformIO $ do
      !dfp <- mallocPlainForeignPtrBytes dlen
      withForeignPtr dfp $ \dptr ->
        withForeignPtr sfp $ \sptr -> do
          let !end = plusPtr sptr (l + o)
          innerLoop lut
            (castPtr dptr)
            (plusPtr sptr o)
            end
            (loopTailNoPad lut dfp dptr end)
  where
    !q = (l * 8) `quot` 5
    !r = (l * 8) `rem` 5
    !dlen = padCeilN 8 (q + if r == 0 then 0 else 1)

-- | Head of the base32 decoding loop - marshal data, assemble loops
--
decodeBase32_ :: Int -> ForeignPtr Word8 -> ByteString -> IO (Either Text ByteString)
decodeBase32_ !dlen !dtfp (PS !sfp !soff !slen) =
    withForeignPtr dtfp $ \(Ptr dtable) ->
    withForeignPtr sfp $ \sptr -> do
      dfp <- mallocPlainForeignPtrBytes dlen
      withForeignPtr dfp $ \dptr -> do
        let !end = plusPtr sptr (soff + slen)
        decodeLoop dtable dfp dptr (plusPtr sptr soff) end