{-|
Description: Implementation of Nix's base32 encoding.
-}
module System.Nix.Base32 where

import qualified Data.ByteString        as BS
import qualified Data.Text              as T
import qualified Data.Vector            as V

-- | Encode a 'BS.ByteString' in Nix's base32 encoding
encode :: BS.ByteString -> T.Text
encode c = T.pack $ concatMap char32 [nChar - 1, nChar - 2 .. 0]
  where
    digits32 = V.fromList "0123456789abcdfghijklmnpqrsvwxyz"
    -- The base32 encoding is 8/5's as long as the base256 digest.  This `+ 1`
    -- `- 1` business is a bit odd, but has always been used in C++ since the
    -- base32 truncation was added in was first added in
    -- d58a11e019813902b6c4547ca61a127938b2cc20.
    nChar = fromIntegral $ ((BS.length c * 8 - 1) `div` 5) + 1

    char32 :: Integer -> [Char]
    char32 i = [digits32 V.! digitInd]
      where
        byte j   = BS.index c (fromIntegral j)
        fromIntegral' :: Num b => Integer -> b
        fromIntegral' = fromIntegral
        digitInd = fromIntegral' $
                   sum [fromIntegral (byte j) * (256^j)
                       | j <- [0 .. BS.length c - 1]]
                   `div` (32^i)
                   `mod` 32