{-# OPTIONS_HADDOCK prune #-}
{-# LANGUAGE BangPatterns #-}

-- |
-- Module: Data.ByteString.Base32
-- Copyright: (c) 2024 Jared Tobin
-- License: MIT
-- Maintainer: Jared Tobin <jared@ppad.tech>
--
-- Unpadded base32 encoding & decoding using the bech32 character set.

module Data.ByteString.Base32 (
    -- * base32 encoding and decoding
    encode
  , decode
  ) where

import qualified Data.Bits as B
import Data.Bits ((.&.), (.|.))
import qualified Data.ByteString as BS
import Data.ByteString.Base32.Internal (enc_tab, dec_tab)
import qualified Data.ByteString.Internal as BI
import Data.Word (Word8)
import Foreign.ForeignPtr (withForeignPtr)
import Foreign.Ptr (Ptr, plusPtr)
import Foreign.Storable (peekElemOff, pokeElemOff)
import System.IO.Unsafe (unsafeDupablePerformIO)

fi :: (Num a, Integral b) => b -> a
fi :: forall a b. (Num a, Integral b) => b -> a
fi = b -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral
{-# INLINE fi #-}

-- | Encode a base256-encoded 'ByteString' as a base32-encoded
--   'ByteString', using the bech32 character set.
--
--   >>> encode "jtobin was here!"
--   "df6x7cnfdcs8wctnyp5x2un9yy"
encode
  :: BS.ByteString -- ^ base256-encoded bytestring
  -> BS.ByteString -- ^ base32-encoded bytestring
encode :: ByteString -> ByteString
encode (BI.PS ForeignPtr Word8
sfp Int
soff Int
l) = case ByteString
enc_tab of
  BI.PS ForeignPtr Word8
tfp Int
toff Int
_ ->
    let !outlen :: Int
outlen = (Int
l Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
8 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
4) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`quot` Int
5
    in  Int -> (Ptr Word8 -> IO ()) -> ByteString
BI.unsafeCreate Int
outlen ((Ptr Word8 -> IO ()) -> ByteString)
-> (Ptr Word8 -> IO ()) -> ByteString
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
dst ->
          ForeignPtr Word8 -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr Word8
sfp ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
sp0 ->
          ForeignPtr Word8 -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr Word8
tfp ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
tp0 -> do
            let !sp :: Ptr Word8
sp = Ptr Word8
sp0 Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
soff :: Ptr Word8
                !tp :: Ptr Word8
tp = Ptr Word8
tp0 Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
toff :: Ptr Word8
            Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Int -> Int -> Int -> IO ()
encode_loop Ptr Word8
sp Ptr Word8
tp Ptr Word8
dst Int
l Int
0 Int
0

encode_loop
  :: Ptr Word8 -> Ptr Word8 -> Ptr Word8
  -> Int -> Int -> Int -> IO ()
encode_loop :: Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Int -> Int -> Int -> IO ()
encode_loop !Ptr Word8
sp !Ptr Word8
tp !Ptr Word8
dst !Int
len !Int
i !Int
j
  | Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
5 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
len = do
      a <- Ptr Word8 -> Int -> IO Word8
forall a. Storable a => Ptr a -> Int -> IO a
peekElemOff Ptr Word8
sp Int
i
      b <- peekElemOff sp (i + 1)
      c <- peekElemOff sp (i + 2)
      d <- peekElemOff sp (i + 3)
      e <- peekElemOff sp (i + 4)
      let !w0 = (Word8
a Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
3) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
          !w1 = (Word8
a Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
2 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
b Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
6) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
          !w2 = (Word8
b Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
1) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
          !w3 = (Word8
b Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
4 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
c Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
4) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
          !w4 = (Word8
c Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
1 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
d Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
7) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
          !w5 = (Word8
d Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
2) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
          !w6 = (Word8
d Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
3 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
e Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
5) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
          !w7 = Word8
e Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
      peekElemOff tp (fi w0) >>= pokeElemOff dst j
      peekElemOff tp (fi w1) >>= pokeElemOff dst (j + 1)
      peekElemOff tp (fi w2) >>= pokeElemOff dst (j + 2)
      peekElemOff tp (fi w3) >>= pokeElemOff dst (j + 3)
      peekElemOff tp (fi w4) >>= pokeElemOff dst (j + 4)
      peekElemOff tp (fi w5) >>= pokeElemOff dst (j + 5)
      peekElemOff tp (fi w6) >>= pokeElemOff dst (j + 6)
      peekElemOff tp (fi w7) >>= pokeElemOff dst (j + 7)
      encode_loop sp tp dst len (i + 5) (j + 8)
  | Bool
otherwise = Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Int -> Int -> Int -> IO ()
encode_tail Ptr Word8
sp Ptr Word8
tp Ptr Word8
dst Int
len Int
i Int
j

encode_tail
  :: Ptr Word8 -> Ptr Word8 -> Ptr Word8
  -> Int -> Int -> Int -> IO ()
encode_tail :: Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Int -> Int -> Int -> IO ()
encode_tail !Ptr Word8
sp !Ptr Word8
tp !Ptr Word8
dst !Int
len !Int
i !Int
j = case Int
len Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
i of
  Int
0 -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
  Int
1 -> do
    a <- Ptr Word8 -> Int -> IO Word8
forall a. Storable a => Ptr a -> Int -> IO a
peekElemOff Ptr Word8
sp Int
i
    let !w0 = (Word8
a Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
3) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
        !w1 = (Word8
a Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
2) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
    peekElemOff tp (fi w0) >>= pokeElemOff dst j
    peekElemOff tp (fi w1) >>= pokeElemOff dst (j + 1)
  Int
2 -> do
    a <- Ptr Word8 -> Int -> IO Word8
forall a. Storable a => Ptr a -> Int -> IO a
peekElemOff Ptr Word8
sp Int
i
    b <- peekElemOff sp (i + 1)
    let !w0 = (Word8
a Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
3) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
        !w1 = (Word8
a Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
2 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
b Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
6) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
        !w2 = (Word8
b Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
1) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
        !w3 = (Word8
b Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
4) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
    peekElemOff tp (fi w0) >>= pokeElemOff dst j
    peekElemOff tp (fi w1) >>= pokeElemOff dst (j + 1)
    peekElemOff tp (fi w2) >>= pokeElemOff dst (j + 2)
    peekElemOff tp (fi w3) >>= pokeElemOff dst (j + 3)
  Int
3 -> do
    a <- Ptr Word8 -> Int -> IO Word8
forall a. Storable a => Ptr a -> Int -> IO a
peekElemOff Ptr Word8
sp Int
i
    b <- peekElemOff sp (i + 1)
    c <- peekElemOff sp (i + 2)
    let !w0 = (Word8
a Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
3) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
        !w1 = (Word8
a Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
2 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
b Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
6) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
        !w2 = (Word8
b Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
1) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
        !w3 = (Word8
b Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
4 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
c Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
4) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
        !w4 = (Word8
c Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
1) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
    peekElemOff tp (fi w0) >>= pokeElemOff dst j
    peekElemOff tp (fi w1) >>= pokeElemOff dst (j + 1)
    peekElemOff tp (fi w2) >>= pokeElemOff dst (j + 2)
    peekElemOff tp (fi w3) >>= pokeElemOff dst (j + 3)
    peekElemOff tp (fi w4) >>= pokeElemOff dst (j + 4)
  Int
4 -> do
    a <- Ptr Word8 -> Int -> IO Word8
forall a. Storable a => Ptr a -> Int -> IO a
peekElemOff Ptr Word8
sp Int
i
    b <- peekElemOff sp (i + 1)
    c <- peekElemOff sp (i + 2)
    d <- peekElemOff sp (i + 3)
    let !w0 = (Word8
a Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
3) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
        !w1 = (Word8
a Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
2 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
b Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
6) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
        !w2 = (Word8
b Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
1) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
        !w3 = (Word8
b Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
4 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
c Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
4) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
        !w4 = (Word8
c Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
1 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
d Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
7) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
        !w5 = (Word8
d Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
2) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
        !w6 = (Word8
d Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
3) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
    peekElemOff tp (fi w0) >>= pokeElemOff dst j
    peekElemOff tp (fi w1) >>= pokeElemOff dst (j + 1)
    peekElemOff tp (fi w2) >>= pokeElemOff dst (j + 2)
    peekElemOff tp (fi w3) >>= pokeElemOff dst (j + 3)
    peekElemOff tp (fi w4) >>= pokeElemOff dst (j + 4)
    peekElemOff tp (fi w5) >>= pokeElemOff dst (j + 5)
    peekElemOff tp (fi w6) >>= pokeElemOff dst (j + 6)
  Int
_ -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()  -- impossible: 0 <= len - i < 5

-- | Decode a 'ByteString', encoded as base32 using the bech32 character
--   set, to a base256-encoded 'ByteString'.
--
--   >>> decode "df6x7cnfdcs8wctnyp5x2un9yy"
--   Just "jtobin was here!"
--   >>> decode "dfOx7cnfdcs8wctnyp5x2un9yy" -- s/6/O (non-bech32 character)
--   Nothing
decode
  :: BS.ByteString        -- ^ base32-encoded bytestring
  -> Maybe BS.ByteString  -- ^ base256-encoded bytestring
decode :: ByteString -> Maybe ByteString
decode (BI.PS ForeignPtr Word8
sfp Int
soff Int
l) = case Int
l Int -> Int -> Int
forall a. Integral a => a -> a -> a
`rem` Int
8 of
  Int
1 -> Maybe ByteString
forall a. Maybe a
Nothing
  Int
3 -> Maybe ByteString
forall a. Maybe a
Nothing
  Int
6 -> Maybe ByteString
forall a. Maybe a
Nothing
  Int
_ -> case ByteString
dec_tab of
    BI.PS ForeignPtr Word8
tfp Int
toff Int
_ -> IO (Maybe ByteString) -> Maybe ByteString
forall a. IO a -> a
unsafeDupablePerformIO (IO (Maybe ByteString) -> Maybe ByteString)
-> IO (Maybe ByteString) -> Maybe ByteString
forall a b. (a -> b) -> a -> b
$ do
      let !n :: Int
n = (Int
l Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
5) Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
3
      fp <- Int -> IO (ForeignPtr Word8)
forall a. Int -> IO (ForeignPtr a)
BI.mallocByteString Int
n
      ok <- withForeignPtr fp  $ \Ptr Word8
dst ->
            ForeignPtr Word8 -> (Ptr Word8 -> IO Bool) -> IO Bool
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr Word8
sfp ((Ptr Word8 -> IO Bool) -> IO Bool)
-> (Ptr Word8 -> IO Bool) -> IO Bool
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
sp0 ->
            ForeignPtr Word8 -> (Ptr Word8 -> IO Bool) -> IO Bool
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr Word8
tfp ((Ptr Word8 -> IO Bool) -> IO Bool)
-> (Ptr Word8 -> IO Bool) -> IO Bool
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
tp0 -> do
              let !sp :: Ptr Word8
sp = Ptr Word8
sp0 Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
soff :: Ptr Word8
                  !tp :: Ptr Word8
tp = Ptr Word8
tp0 Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
toff :: Ptr Word8
              Ptr Word8
-> Ptr Word8 -> Ptr Word8 -> Int -> Int -> Int -> Word8 -> IO Bool
decode_loop Ptr Word8
sp Ptr Word8
tp Ptr Word8
dst Int
l Int
0 Int
0 Word8
0
      pure $! if ok then Just (BI.PS fp 0 n) else Nothing

decode_loop
  :: Ptr Word8 -> Ptr Word8 -> Ptr Word8
  -> Int -> Int -> Int -> Word8 -> IO Bool
decode_loop :: Ptr Word8
-> Ptr Word8 -> Ptr Word8 -> Int -> Int -> Int -> Word8 -> IO Bool
decode_loop !Ptr Word8
sp !Ptr Word8
tp !Ptr Word8
dst !Int
len !Int
i !Int
j !Word8
acc
  | Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
8 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
len = do
      c0 <- Ptr Word8 -> Int -> IO Word8
forall a. Storable a => Ptr a -> Int -> IO a
peekElemOff Ptr Word8
sp Int
i
      c1 <- peekElemOff sp (i + 1)
      c2 <- peekElemOff sp (i + 2)
      c3 <- peekElemOff sp (i + 3)
      c4 <- peekElemOff sp (i + 4)
      c5 <- peekElemOff sp (i + 5)
      c6 <- peekElemOff sp (i + 6)
      c7 <- peekElemOff sp (i + 7)
      n0 <- peekElemOff tp (fi c0)
      n1 <- peekElemOff tp (fi c1)
      n2 <- peekElemOff tp (fi c2)
      n3 <- peekElemOff tp (fi c3)
      n4 <- peekElemOff tp (fi c4)
      n5 <- peekElemOff tp (fi c5)
      n6 <- peekElemOff tp (fi c6)
      n7 <- peekElemOff tp (fi c7)
      let !v0 = Word8
n0 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
          !v1 = Word8
n1 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
          !v2 = Word8
n2 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
          !v3 = Word8
n3 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
          !v4 = Word8
n4 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
          !v5 = Word8
n5 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
          !v6 = Word8
n6 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
          !v7 = Word8
n7 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
          !b0 = (Word8
v0 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
3) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. (Word8
v1 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
2)
          !b1 = (Word8
v1 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
6) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. (Word8
v2 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
1) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|.
                (Word8
v3 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
4)
          !b2 = (Word8
v3 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
4) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. (Word8
v4 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
1)
          !b3 = (Word8
v4 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
7) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. (Word8
v5 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
2) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|.
                (Word8
v6 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
3)
          !b4 = (Word8
v6 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
5) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
v7
      pokeElemOff dst j       b0
      pokeElemOff dst (j + 1) b1
      pokeElemOff dst (j + 2) b2
      pokeElemOff dst (j + 3) b3
      pokeElemOff dst (j + 4) b4
      decode_loop sp tp dst len (i + 8) (j + 5)
        (acc .|. n0 .|. n1 .|. n2 .|. n3 .|. n4 .|. n5 .|. n6 .|. n7)
  | Bool
otherwise = Ptr Word8
-> Ptr Word8 -> Ptr Word8 -> Int -> Int -> Int -> Word8 -> IO Bool
decode_tail Ptr Word8
sp Ptr Word8
tp Ptr Word8
dst Int
len Int
i Int
j Word8
acc

decode_tail
  :: Ptr Word8 -> Ptr Word8 -> Ptr Word8
  -> Int -> Int -> Int -> Word8 -> IO Bool
decode_tail :: Ptr Word8
-> Ptr Word8 -> Ptr Word8 -> Int -> Int -> Int -> Word8 -> IO Bool
decode_tail !Ptr Word8
sp !Ptr Word8
tp !Ptr Word8
dst !Int
len !Int
i !Int
j !Word8
acc = case Int
len Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
i of
  Int
0 -> Bool -> IO Bool
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Bool -> IO Bool) -> Bool -> IO Bool
forall a b. (a -> b) -> a -> b
$! Word8
acc Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x40 Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
0
  Int
2 -> do
    c0 <- Ptr Word8 -> Int -> IO Word8
forall a. Storable a => Ptr a -> Int -> IO a
peekElemOff Ptr Word8
sp Int
i
    c1 <- peekElemOff sp (i + 1)
    n0 <- peekElemOff tp (fi c0)
    n1 <- peekElemOff tp (fi c1)
    let !v0 = Word8
n0 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
        !v1 = Word8
n1 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
        !b0 = (Word8
v0 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
3) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. (Word8
v1 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
2)
        -- canonical-form check: bits dropped from v1 must be zero
        !slack = Word8
v1 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
6
    pokeElemOff dst j b0
    pure $! (acc .|. n0 .|. n1) .&. 0x40 == 0 && slack == 0
  Int
4 -> do
    c0 <- Ptr Word8 -> Int -> IO Word8
forall a. Storable a => Ptr a -> Int -> IO a
peekElemOff Ptr Word8
sp Int
i
    c1 <- peekElemOff sp (i + 1)
    c2 <- peekElemOff sp (i + 2)
    c3 <- peekElemOff sp (i + 3)
    n0 <- peekElemOff tp (fi c0)
    n1 <- peekElemOff tp (fi c1)
    n2 <- peekElemOff tp (fi c2)
    n3 <- peekElemOff tp (fi c3)
    let !v0 = Word8
n0 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
        !v1 = Word8
n1 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
        !v2 = Word8
n2 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
        !v3 = Word8
n3 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
        !b0 = (Word8
v0 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
3) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. (Word8
v1 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
2)
        !b1 = (Word8
v1 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
6) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. (Word8
v2 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
1) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|.
              (Word8
v3 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
4)
        !slack = Word8
v3 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
4
    pokeElemOff dst j       b0
    pokeElemOff dst (j + 1) b1
    pure $! (acc .|. n0 .|. n1 .|. n2 .|. n3) .&. 0x40 == 0
         && slack == 0
  Int
5 -> do
    c0 <- Ptr Word8 -> Int -> IO Word8
forall a. Storable a => Ptr a -> Int -> IO a
peekElemOff Ptr Word8
sp Int
i
    c1 <- peekElemOff sp (i + 1)
    c2 <- peekElemOff sp (i + 2)
    c3 <- peekElemOff sp (i + 3)
    c4 <- peekElemOff sp (i + 4)
    n0 <- peekElemOff tp (fi c0)
    n1 <- peekElemOff tp (fi c1)
    n2 <- peekElemOff tp (fi c2)
    n3 <- peekElemOff tp (fi c3)
    n4 <- peekElemOff tp (fi c4)
    let !v0 = Word8
n0 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
        !v1 = Word8
n1 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
        !v2 = Word8
n2 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
        !v3 = Word8
n3 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
        !v4 = Word8
n4 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
        !b0 = (Word8
v0 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
3) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. (Word8
v1 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
2)
        !b1 = (Word8
v1 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
6) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. (Word8
v2 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
1) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|.
              (Word8
v3 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
4)
        !b2 = (Word8
v3 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
4) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. (Word8
v4 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
1)
        !slack = Word8
v4 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
7
    pokeElemOff dst j       b0
    pokeElemOff dst (j + 1) b1
    pokeElemOff dst (j + 2) b2
    pure $! (acc .|. n0 .|. n1 .|. n2 .|. n3 .|. n4) .&. 0x40 == 0
         && slack == 0
  Int
7 -> do
    c0 <- Ptr Word8 -> Int -> IO Word8
forall a. Storable a => Ptr a -> Int -> IO a
peekElemOff Ptr Word8
sp Int
i
    c1 <- peekElemOff sp (i + 1)
    c2 <- peekElemOff sp (i + 2)
    c3 <- peekElemOff sp (i + 3)
    c4 <- peekElemOff sp (i + 4)
    c5 <- peekElemOff sp (i + 5)
    c6 <- peekElemOff sp (i + 6)
    n0 <- peekElemOff tp (fi c0)
    n1 <- peekElemOff tp (fi c1)
    n2 <- peekElemOff tp (fi c2)
    n3 <- peekElemOff tp (fi c3)
    n4 <- peekElemOff tp (fi c4)
    n5 <- peekElemOff tp (fi c5)
    n6 <- peekElemOff tp (fi c6)
    let !v0 = Word8
n0 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
        !v1 = Word8
n1 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
        !v2 = Word8
n2 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
        !v3 = Word8
n3 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
        !v4 = Word8
n4 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
        !v5 = Word8
n5 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
        !v6 = Word8
n6 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x1f
        !b0 = (Word8
v0 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
3) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. (Word8
v1 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
2)
        !b1 = (Word8
v1 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
6) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. (Word8
v2 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
1) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|.
              (Word8
v3 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
4)
        !b2 = (Word8
v3 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
4) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. (Word8
v4 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
1)
        !b3 = (Word8
v4 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
7) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. (Word8
v5 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
2) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|.
              (Word8
v6 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftR` Int
3)
        !slack = Word8
v6 Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`B.shiftL` Int
5
    pokeElemOff dst j       b0
    pokeElemOff dst (j + 1) b1
    pokeElemOff dst (j + 2) b2
    pokeElemOff dst (j + 3) b3
    pure $!
         (acc .|. n0 .|. n1 .|. n2 .|. n3 .|. n4 .|. n5 .|. n6)
         .&. 0x40 == 0
         && slack == 0
  Int
_ -> Bool -> IO Bool
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
False -- impossible: tail-length guard already rejected