|
| 1 | +{-| |
| 2 | +Description: Implementation of Nix's base32 encoding. |
| 3 | +-} |
| 4 | +module System.Nix.Base32 where |
| 5 | + |
| 6 | +import qualified Data.ByteString as BS |
| 7 | +import qualified Data.Text as T |
| 8 | +import qualified Data.Vector as V |
| 9 | + |
| 10 | +-- | Encode a 'BS.ByteString' in Nix's base32 encoding |
| 11 | +encode :: BS.ByteString -> T.Text |
| 12 | +encode c = T.pack $ map char32 [nChar - 1, nChar - 2 .. 0] |
| 13 | + where |
| 14 | + digits32 = V.fromList "0123456789abcdfghijklmnpqrsvwxyz" |
| 15 | + -- Each base32 character gives us 5 bits of information, while |
| 16 | + -- each byte gives is 8. Because 'div' rounds down, we need to add |
| 17 | + -- one extra character to the result, and because of that extra 1 |
| 18 | + -- we need to subtract one from the number of bits in the |
| 19 | + -- bytestring to cover for the case where the number of bits is |
| 20 | + -- already a factor of 5. Thus, the + 1 outside of the 'div' and |
| 21 | + -- the - 1 inside of it. |
| 22 | + nChar = fromIntegral $ ((BS.length c * 8 - 1) `div` 5) + 1 |
| 23 | + |
| 24 | + byte = BS.index c . fromIntegral |
| 25 | + |
| 26 | + -- May need to switch to a more efficient calculation at some |
| 27 | + -- point. |
| 28 | + bAsInteger :: Integer |
| 29 | + bAsInteger = sum [fromIntegral (byte j) * (256 ^ j) |
| 30 | + | j <- [0 .. BS.length c - 1] |
| 31 | + ] |
| 32 | + |
| 33 | + char32 :: Integer -> Char |
| 34 | + char32 i = digits32 V.! digitInd |
| 35 | + where |
| 36 | + digitInd = fromIntegral $ |
| 37 | + bAsInteger |
| 38 | + `div` (32^i) |
| 39 | + `mod` 32 |
0 commit comments