module VLQ
(encode
,decode)
where
import Data.Bits hiding (shift)
import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy as B
import Data.Int
import Data.List
import Data.Maybe
import Data.Word
import Prelude hiding ((>>))
baseShift :: Int
baseShift :: Int
baseShift = Int
5
base :: Int32
base :: Int32
base = Int32
1 Int32 -> Int -> Int32
<< Int
baseShift
baseMask :: Int32
baseMask :: Int32
baseMask = Int32
base Int32 -> Int32 -> Int32
forall a. Num a => a -> a -> a
- Int32
1
continuationBit :: Int32
continuationBit :: Int32
continuationBit = Int32
base
toVlqSigned :: Int32 -> Int32
toVlqSigned :: Int32 -> Int32
toVlqSigned Int32
value =
if Int32
value Int32 -> Int32 -> Bool
forall a. Ord a => a -> a -> Bool
< Int32
0
then ((-Int32
value) Int32 -> Int -> Int32
<< Int
1) Int32 -> Int32 -> Int32
forall a. Num a => a -> a -> a
+ Int32
1
else (Int32
value Int32 -> Int -> Int32
<< Int
1) Int32 -> Int32 -> Int32
forall a. Num a => a -> a -> a
+ Int32
0
fromVlgSigned :: Int32 -> Int32
fromVlgSigned :: Int32 -> Int32
fromVlgSigned Int32
value =
let value' :: Int32
value' = Int32
value Int32 -> Int -> Int32
>> Int
1
in if (Int32
value Int32 -> Int32 -> Int32
& Int32
1) Int32 -> Int32 -> Bool
forall a. Eq a => a -> a -> Bool
== Int32
1
then -Int32
value'
else Int32
value'
encode :: Int32 -> ByteString
encode :: Int32 -> ByteString
encode = (Word8 -> Word8) -> ByteString -> ByteString
B.map Word8 -> Word8
encodeBase64 (ByteString -> ByteString)
-> (Int32 -> ByteString) -> Int32 -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int32 -> ByteString
start where
start :: Int32 -> ByteString
start Int32
0 = Word8 -> ByteString
B.singleton ((Word8, Int32) -> Word8
forall a b. (a, b) -> a
fst (Int32 -> (Word8, Int32)
forall a. Num a => Int32 -> (a, Int32)
continue Int32
0))
start Int32
n = (Int32 -> Maybe (Word8, Int32)) -> Int32 -> ByteString
forall a. (a -> Maybe (Word8, a)) -> a -> ByteString
B.unfoldr Int32 -> Maybe (Word8, Int32)
forall a. Num a => Int32 -> Maybe (a, Int32)
go (Int32 -> ByteString) -> (Int32 -> Int32) -> Int32 -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int32 -> Int32
toVlqSigned (Int32 -> ByteString) -> Int32 -> ByteString
forall a b. (a -> b) -> a -> b
$ Int32
n
go :: Int32 -> Maybe (a, Int32)
go Int32
value
| Int32
value Int32 -> Int32 -> Bool
forall a. Ord a => a -> a -> Bool
<= Int32
0 = Maybe (a, Int32)
forall a. Maybe a
Nothing
| Bool
otherwise = (a, Int32) -> Maybe (a, Int32)
forall a. a -> Maybe a
Just (Int32 -> (a, Int32)
forall a. Num a => Int32 -> (a, Int32)
continue Int32
value)
continue :: Int32 -> (a, Int32)
continue Int32
value =
let digit :: Int32
digit = Int32
value Int32 -> Int32 -> Int32
& Int32
baseMask
value' :: Int32
value' = Int32
value Int32 -> Int -> Int32
>> Int
baseShift
digit' :: Int32
digit' = if Int32
value' Int32 -> Int32 -> Bool
forall a. Ord a => a -> a -> Bool
> Int32
0
then Int32
digit Int32 -> Int32 -> Int32
forall a. Bits a => a -> a -> a
.|. Int32
continuationBit
else Int32
digit
in (Int32 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int32
digit',Int32
value')
decode :: ByteString -> Int32
decode :: ByteString -> Int32
decode = Int32 -> Int32
fromVlgSigned (Int32 -> Int32) -> (ByteString -> Int32) -> ByteString -> Int32
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int32, Int) -> ByteString -> Int32
go (Int32
0,Int
0) (ByteString -> Int32)
-> (ByteString -> ByteString) -> ByteString -> Int32
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Word8 -> Word8) -> ByteString -> ByteString
B.map Word8 -> Word8
decodeBase64 where
go :: (Int32, Int) -> ByteString -> Int32
go (Int32
result,Int
shift) ByteString
bytes =
case ByteString -> Maybe (Word8, ByteString)
B.uncons ByteString
bytes of
Maybe (Word8, ByteString)
Nothing -> Int32
result
Just (Word8
c,ByteString
next) ->
let digit :: Int32
digit = Word8 -> Int32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
c
continuation :: Bool
continuation = (Int32
digit Int32 -> Int32 -> Int32
& Int32
continuationBit) Int32 -> Int32 -> Bool
forall a. Eq a => a -> a -> Bool
/= Int32
0
digit' :: Int32
digit' = Int32
digit Int32 -> Int32 -> Int32
& Int32
baseMask
result' :: Int32
result' = Int32
result Int32 -> Int32 -> Int32
forall a. Num a => a -> a -> a
+ (Int32
digit' Int32 -> Int -> Int32
<< Int
shift)
shift' :: Int
shift' = Int
shift Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
baseShift
in if Bool
continuation
then (Int32, Int) -> ByteString -> Int32
go (Int32
result',Int
shift') ByteString
next
else Int32
result'
base64Chars :: [Word8]
base64Chars :: [Word8]
base64Chars = (Char -> Word8) -> [Char] -> [Word8]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral(Int -> Word8) -> (Char -> Int) -> Char -> Word8
forall b c a. (b -> c) -> (a -> b) -> a -> c
.Char -> Int
forall a. Enum a => a -> Int
fromEnum) [Char]
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
encodeBase64 :: Word8 -> Word8
encodeBase64 :: Word8 -> Word8
encodeBase64 Word8
i = Word8 -> Maybe Word8 -> Word8
forall a. a -> Maybe a -> a
fromMaybe ([Char] -> Word8
forall a. HasCallStack => [Char] -> a
error [Char]
"Base 64 char must be between 0 and 63.")
(Word8 -> [(Word8, Word8)] -> Maybe Word8
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup Word8
i ([Word8] -> [Word8] -> [(Word8, Word8)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Word8
0..] [Word8]
base64Chars))
decodeBase64 :: Word8 -> Word8
decodeBase64 :: Word8 -> Word8
decodeBase64 Word8
i = Word8 -> (Int -> Word8) -> Maybe Int -> Word8
forall b a. b -> (a -> b) -> Maybe a -> b
maybe ([Char] -> Word8
forall a. HasCallStack => [Char] -> a
error [Char]
"Not a valid base 65 digit.") Int -> Word8
forall a. Enum a => Int -> a
toEnum
(Word8 -> [Word8] -> Maybe Int
forall a. Eq a => a -> [a] -> Maybe Int
elemIndex Word8
i [Word8]
base64Chars)
(<<) :: Int32 -> Int -> Int32
<< :: Int32 -> Int -> Int32
(<<) = Int32 -> Int -> Int32
forall a. Bits a => a -> Int -> a
shiftL
(>>) :: Int32 -> Int -> Int32
>> :: Int32 -> Int -> Int32
(>>) = Int32 -> Int -> Int32
forall a. Bits a => a -> Int -> a
shiftR
(&) :: Int32 -> Int32 -> Int32
& :: Int32 -> Int32 -> Int32
(&) = Int32 -> Int32 -> Int32
forall a. Bits a => a -> a -> a
(.&.)