packages feed

casa-reoc-0.1.0.0: src/ReOC/Render/Base64.hs

{-# OPTIONS_GHC -Wall #-}

-- | Base64, for images embedded in Flat ODF text.
module ReOC.Render.Base64 (
  base64,
) where

import Data.Bits (shiftL, shiftR, (.&.), (.|.))
import Data.ByteString (ByteString)
import qualified Data.ByteString as ByteString
import Data.Text (Text)
import qualified Data.Text as Text
import Data.Word (Word8)

{- $setup
>>> import qualified Data.ByteString.Char8 as Char8
-}

{- | The base64 encoding of bytes (RFC 4648), with padding.

>>> base64 (Char8.pack "Man")
"TWFu"

>>> base64 (Char8.pack "Ma")
"TWE="

>>> base64 (Char8.pack "M")
"TQ=="
-}
base64 :: ByteString -> Text
base64 =
  Text.pack . go . ByteString.unpack
 where
  go (a : b : c : rest) =
    quad a b c <> go rest
  go [a, b] =
    take 3 (quad a b 0) <> "="
  go [a] =
    take 2 (quad a 0 0) <> "=="
  go [] =
    []
  quad :: Word8 -> Word8 -> Word8 -> String
  quad a b c =
    let n = (fromIntegral a `shiftL` 16) .|. (fromIntegral b `shiftL` 8) .|. fromIntegral c :: Int
     in map (\k -> alphabet !! ((n `shiftR` k) .&. 63)) [18, 12, 6, 0]
  alphabet =
    ['A' .. 'Z'] <> ['a' .. 'z'] <> ['0' .. '9'] <> "+/"