base-encoding 0.1.0.0 → 0.3.0.0
raw patch · 11 files changed
Files
- ChangeLog.md +25/−0
- Setup.hs +0/−2
- base-encoding.cabal +24/−14
- src/Codec/Base16.hs +2/−57
- src/Codec/Base32.hs +269/−0
- src/Codec/Base32/Impl.hs +251/−0
- src/Codec/Base32Hex.hs +269/−0
- src/Codec/Base64.hs +0/−47
- src/Codec/Base64Url.hs +17/−65
- src/Codec/Base64Url/Unpadded.hs +278/−0
- src/Internal.hs +11/−0
+ ChangeLog.md view
@@ -0,0 +1,25 @@+See also http://pvp.haskell.org/faq++# 0.3.0.0++* Semantic change: Switch to `base64-bytestring-1.2.1` which provides+ even stricter Base64 decoding semantics regarding padding; switch to+ `base16-bytestring-1.0.1` which results in changed error messages.++* Add support for encoding/decoding to/from padded `base32` &+ `base32hex`.++----++# 0.2.0.0++* Semantic change: Switch to `base64-bytestring-0.2.0` which+ provides stricter Base64 decoding semantics regarding padding.++* Add support for encoding/decoding to/from unpadded `base64url`.++----++# 0.1.0.0++* First version. Released on an unsuspecting world.
− Setup.hs
@@ -1,2 +0,0 @@-import Distribution.Simple-main = defaultMain
base-encoding.cabal view
@@ -1,15 +1,14 @@-cabal-version: 1.12+cabal-version: 2.2 name: base-encoding-version: 0.1.0.0+version: 0.3.0.0 -synopsis: Binary-to-text encodings (e.g. base64)-license: BSD3+synopsis: RFC4648 Binary-to-text encodings (e.g. base64)+license: BSD-3-Clause license-file: LICENSE author: Herbert Valerio Riedel bug-reports: https://github.com/hvr/base-encoding/issues maintainer: hvr@gnu.org-category: Text-build-type: Simple+category: Codec, Text description: This package provides a simple and convenient API to encode and decode binary data in the popular binary-to-text \"base\" encoding@@ -17,10 +16,16 @@ . Currently, the following encodings are supported: .- - base16 (RFC4648)- - base64 (RFC4648)- - base64url (RFC4648)+ - (unpadded) @base16@ (RFC4648)+ - (padded) @base32@ (RFC4648)+ - (padded) @base32hex@ (RFC4648)+ - (padded) @base64@ (RFC4648)+ - padded @base64url@ (RFC4648)+ - unpadded @base64url@ (RFC4648)+ . +extra-source-files: ChangeLog.md+ source-repository head type: git location: https://github.com/hvr/base-encoding@@ -30,11 +35,15 @@ exposed-modules: Codec.Base16+ Codec.Base32+ Codec.Base32Hex Codec.Base64 Codec.Base64Url+ Codec.Base64Url.Unpadded other-modules: Internal+ Codec.Base32.Impl default-language: Haskell2010 other-extensions: CPP MultiParamTypeClasses@@ -45,11 +54,12 @@ ghc-options: -fno-warn-trustworthy-safe build-depends:- base >=4.3 && <4.12- , base16-bytestring >=0.1.1.6 && <0.2- , base64-bytestring >=1.0.0.1 && <1.1+ , base >=4.3 && <4.15+ , base16-bytestring ^>=1.0.1+ , base64-bytestring ^>=1.2.1 - , bytestring >=0.9.1 && <0.11- , text >=1.2.3 && <1.3+ , bytestring ^>=0.9.1 || ^>= 0.10.0+ , bytestring-builder ^>=0.10.8.2+ , text ^>=1.2.3 ghc-options: -Wall
src/Codec/Base16.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE CPP #-} {-# LANGUAGE MultiParamTypeClasses #-} -- | This module provides access to the \"base16\" binary-to-text encoding as defined by [RFC 4648](https://tools.ietf.org/html/rfc4648).@@ -33,15 +32,9 @@ import qualified Data.ByteString.Base16.Lazy as B16.L import qualified Data.ByteString as BS-#if MIN_VERSION_bytestring(0,10,2) import qualified Data.ByteString.Builder as BB-#elif MIN_VERSION_bytestring(0,10,0)-import qualified Data.ByteString.Lazy.Builder as BB-#endif import qualified Data.ByteString.Lazy as BS.L-#if MIN_VERSION_bytestring(0,10,4) import qualified Data.ByteString.Short as SBS-#endif import qualified Data.Text as T (Text) import qualified Data.Text.Encoding as T (decodeLatin1, encodeUtf8)@@ -55,18 +48,10 @@ -- primitives decodeBs2Bs :: BS.ByteString -> Either String BS.ByteString-decodeBs2Bs txt- | BS.null rest = Right $! b- | otherwise = Left ("invalid base16 encoding near offset " ++ show (2 * BS.length b))- where- (b,rest) = B16.decode txt+decodeBs2Bs = B16.decode decodeBsL2BsL :: BS.L.ByteString -> Either String BS.L.ByteString-decodeBsL2BsL txt- | BS.L.null rest = Right $! b- | otherwise = Left ("invalid base16 encoding near offset " ++ show (2 * BS.L.length b))- where- (b,rest) = B16.L.decode txt+decodeBsL2BsL = B16.L.decode encodeBs2Bs :: BS.ByteString -> BS.ByteString encodeBs2Bs = B16.encode@@ -99,15 +84,11 @@ instance Encode BS.L.ByteString BS.ByteString where encode = bsToStrict . encode -#if MIN_VERSION_bytestring(0,10,0) instance Encode BS.L.ByteString BB.Builder where encode = BB.lazyByteString . encode-#endif -#if MIN_VERSION_bytestring(0,10,4) instance Encode BS.L.ByteString SBS.ShortByteString where encode = SBS.toShort . encode-#endif instance Encode BS.L.ByteString T.Text where encode = T.decodeLatin1 . encode@@ -127,15 +108,11 @@ instance Encode BS.ByteString BS.L.ByteString where encode = bsFromStrict . encode -#if MIN_VERSION_bytestring(0,10,0) instance Encode BS.ByteString BB.Builder where encode = BB.byteString . encode-#endif -#if MIN_VERSION_bytestring(0,10,4) instance Encode BS.ByteString SBS.ShortByteString where encode = SBS.toShort . encode-#endif instance Encode BS.ByteString T.Text where encode = T.decodeLatin1 . encode@@ -148,7 +125,6 @@ ---- short BS -> * -#if MIN_VERSION_bytestring(0,10,4) instance Encode SBS.ShortByteString SBS.ShortByteString where encode = SBS.toShort . encode . SBS.fromShort @@ -169,16 +145,12 @@ instance Encode SBS.ShortByteString TB.Builder where encode = TB.fromText . encode-#endif ---- BB -> * -#if MIN_VERSION_bytestring(0,10,4) instance Encode BB.Builder SBS.ShortByteString where encode = encode . BB.toLazyByteString-#endif -#if MIN_VERSION_bytestring(0,10,0) instance Encode BB.Builder BB.Builder where encode = encode . BB.toLazyByteString @@ -196,7 +168,6 @@ instance Encode BB.Builder TB.Builder where encode = TB.fromLazyText . encode-#endif ------------------------------------------------------------------------------ @@ -207,15 +178,11 @@ instance Decode BS.ByteString BS.L.ByteString where decode = fmap bsFromStrict . decode -#if MIN_VERSION_bytestring(0,10,4) instance Decode BS.ByteString SBS.ShortByteString where decode = fmap SBS.toShort . decode-#endif -#if MIN_VERSION_bytestring(0,10,0) instance Decode BS.ByteString BB.Builder where decode = fmap BB.byteString . decode-#endif ---- @@ -226,19 +193,14 @@ instance Decode BS.L.ByteString BS.ByteString where decode = fmap bsToStrict . decode -#if MIN_VERSION_bytestring(0,10,4) instance Decode BS.L.ByteString SBS.ShortByteString where decode = fmap SBS.toShort . decode-#endif -#if MIN_VERSION_bytestring(0,10,0) instance Decode BS.L.ByteString BB.Builder where decode = fmap BB.byteString . decode-#endif ---- -#if MIN_VERSION_bytestring(0,10,4) instance Decode SBS.ShortByteString SBS.ShortByteString where decode = fmap SBS.toShort . decode . SBS.fromShort @@ -250,16 +212,12 @@ instance Decode SBS.ShortByteString BB.Builder where decode = decode . SBS.fromShort-#endif ---- -#if MIN_VERSION_bytestring(0,10,4) instance Decode BB.Builder SBS.ShortByteString where decode = decode . BB.toLazyByteString-#endif -#if MIN_VERSION_bytestring(0,10,0) instance Decode BB.Builder BS.L.ByteString where decode = decode . BB.toLazyByteString @@ -268,7 +226,6 @@ instance Decode BB.Builder BB.Builder where decode = decode . BB.toLazyByteString-#endif ---- @@ -278,15 +235,11 @@ instance Decode T.Text BS.L.ByteString where decode = decode . T.encodeUtf8 -#if MIN_VERSION_bytestring(0,10,4) instance Decode T.Text SBS.ShortByteString where decode = decode . T.encodeUtf8-#endif -#if MIN_VERSION_bytestring(0,10,0) instance Decode T.Text BB.Builder where decode = decode . T.encodeUtf8-#endif ---- @@ -296,15 +249,11 @@ instance Decode T.L.Text BS.L.ByteString where decode = decode . T.L.encodeUtf8 -#if MIN_VERSION_bytestring(0,10,4) instance Decode T.L.Text SBS.ShortByteString where decode = decode . T.L.encodeUtf8-#endif -#if MIN_VERSION_bytestring(0,10,0) instance Decode T.L.Text BB.Builder where decode = decode . T.L.encodeUtf8-#endif ---- @@ -314,12 +263,8 @@ instance Decode TB.Builder BS.L.ByteString where decode = decode . TB.toLazyText -#if MIN_VERSION_bytestring(0,10,4) instance Decode TB.Builder SBS.ShortByteString where decode = decode . TB.toLazyText-#endif -#if MIN_VERSION_bytestring(0,10,0) instance Decode TB.Builder BB.Builder where decode = decode . TB.toLazyText-#endif
+ src/Codec/Base32.hs view
@@ -0,0 +1,269 @@+{-# LANGUAGE MultiParamTypeClasses #-}++-- | This module provides access to the \"base32\" binary-to-text encoding as defined by [RFC 4648](https://tools.ietf.org/html/rfc4648).+--+-- This module is intended to be imported @qualified@, e.g.+--+-- > import qualified Codec.Base32 as B32+--+-- If you want to explictly specify which 'Encode' and 'Decode' typeclass instance is used, you can use plain Haskell2010 type-signature annotations, e.g.+--+-- >>> (B32.encode :: ByteString -> Text) "\x00\x00"+-- "AAAA===="+--+-- >>> (B32.decode :: Text -> Either String ShortByteString) "GQ5DEMA="+-- Right "4:20"+--+-- Alternatively, starting with GHC 8.0.1, you can also use the [TypeApplications language extension](https://downloads.haskell.org/~ghc/8.4.1/docs/html/users_guide/glasgow_exts.html#ghc-flag--XTypeApplications):+--+-- >>> B32.encode @ShortByteString @Text "\xFF\239"+-- "77XQ===="+--+-- >>> B32.decode @Text @ShortByteString "77XQ===="+-- Right "\255\239"+--+-- @since 0.3.0.0+module Codec.Base32+ ( Encode(encode)+ , Decode(decode)+ ) where++import qualified Codec.Base32.Impl as Impl++import qualified Data.ByteString as BS+import qualified Data.ByteString.Builder as BB+import qualified Data.ByteString.Lazy as BS.L+import qualified Data.ByteString.Short as SBS++import qualified Data.Text as T (Text)+import qualified Data.Text.Encoding as T (decodeLatin1, encodeUtf8)+import qualified Data.Text.Lazy as T.L (Text, fromStrict)+import qualified Data.Text.Lazy.Builder as TB (Builder, fromLazyText,+ fromText, toLazyText)+import qualified Data.Text.Lazy.Encoding as T.L (decodeLatin1, encodeUtf8)++import Internal++-- primitives++decodeBs2Bs :: BS.ByteString -> Either String BS.ByteString+decodeBs2Bs = Impl.decodeBs2Bs Impl.Fmt'base32++decodeBsL2BsL :: BS.L.ByteString -> Either String BS.L.ByteString+decodeBsL2BsL = Impl.decodeBsL2BsL Impl.Fmt'base32++encodeBs2Bs :: BS.ByteString -> BS.ByteString+encodeBs2Bs = Impl.encodeBs2Bs Impl.Fmt'base32++encodeBsL2BsL :: BS.L.ByteString -> BS.L.ByteString+encodeBsL2BsL = Impl.encodeBsL2BsL Impl.Fmt'base32++----------------------------------------------------------------------------+-- exposed API++-- | Typeclass representing types for which a binary-to-text @base32@ encoding is defined+class Encode bin txt where+ -- | Encode binary data using @base32@ text encoding+ encode :: bin -> txt++-- | Typeclass representing types for which a text-to-binary @base32@ decoding is defined+class Decode txt bin where+ -- | Decode binary data encoded textually as @base32@+ decode :: txt -> Either String bin++----------------------------------------------------------------------------+-- instance matrix++---- lazy BS -> *++-- PRIMITIVE+instance Encode BS.L.ByteString BS.L.ByteString where+ encode = encodeBsL2BsL++instance Encode BS.L.ByteString BS.ByteString where+ encode = bsToStrict . encode++instance Encode BS.L.ByteString BB.Builder where+ encode = BB.lazyByteString . encode++instance Encode BS.L.ByteString SBS.ShortByteString where+ encode = SBS.toShort . encode++instance Encode BS.L.ByteString T.Text where+ encode = T.decodeLatin1 . encode++instance Encode BS.L.ByteString T.L.Text where+ encode = T.L.decodeLatin1 . encode++instance Encode BS.L.ByteString TB.Builder where+ encode = TB.fromLazyText . encode++---- strict BS -> *++-- PRIMITIVE+instance Encode BS.ByteString BS.ByteString where+ encode = encodeBs2Bs++instance Encode BS.ByteString BS.L.ByteString where+ encode = bsFromStrict . encode++instance Encode BS.ByteString BB.Builder where+ encode = BB.byteString . encode++instance Encode BS.ByteString SBS.ShortByteString where+ encode = SBS.toShort . encode++instance Encode BS.ByteString T.Text where+ encode = T.decodeLatin1 . encode++instance Encode BS.ByteString T.L.Text where+ encode = T.L.fromStrict . T.decodeLatin1 . encode++instance Encode BS.ByteString TB.Builder where+ encode = TB.fromText . encode++---- short BS -> *++instance Encode SBS.ShortByteString SBS.ShortByteString where+ encode = SBS.toShort . encode . SBS.fromShort++instance Encode SBS.ShortByteString BS.ByteString where+ encode = encode . SBS.fromShort++instance Encode SBS.ShortByteString BS.L.ByteString where+ encode = encode . SBS.fromShort++instance Encode SBS.ShortByteString BB.Builder where+ encode = encode . SBS.fromShort++instance Encode SBS.ShortByteString T.Text where+ encode = T.decodeLatin1 . encode++instance Encode SBS.ShortByteString T.L.Text where+ encode = T.L.fromStrict . T.decodeLatin1 . encode++instance Encode SBS.ShortByteString TB.Builder where+ encode = TB.fromText . encode++---- BB -> *++instance Encode BB.Builder SBS.ShortByteString where+ encode = encode . BB.toLazyByteString++instance Encode BB.Builder BB.Builder where+ encode = encode . BB.toLazyByteString++instance Encode BB.Builder BS.ByteString where+ encode = encode . BB.toLazyByteString++instance Encode BB.Builder BS.L.ByteString where+ encode = encode . BB.toLazyByteString++instance Encode BB.Builder T.Text where+ encode = T.decodeLatin1 . encode++instance Encode BB.Builder T.L.Text where+ encode = T.L.decodeLatin1 . encode++instance Encode BB.Builder TB.Builder where+ encode = TB.fromLazyText . encode++------------------------------------------------------------------------------++-- PRIMITIVE+instance Decode BS.ByteString BS.ByteString where+ decode = decodeBs2Bs++instance Decode BS.ByteString BS.L.ByteString where+ decode = fmap bsFromStrict . decode++instance Decode BS.ByteString SBS.ShortByteString where+ decode = fmap SBS.toShort . decode++instance Decode BS.ByteString BB.Builder where+ decode = fmap BB.byteString . decode++----++-- PRIMITIVE+instance Decode BS.L.ByteString BS.L.ByteString where+ decode = decodeBsL2BsL++instance Decode BS.L.ByteString BS.ByteString where+ decode = fmap bsToStrict . decode++instance Decode BS.L.ByteString SBS.ShortByteString where+ decode = fmap SBS.toShort . decode++instance Decode BS.L.ByteString BB.Builder where+ decode = fmap BB.byteString . decode++----++instance Decode SBS.ShortByteString SBS.ShortByteString where+ decode = fmap SBS.toShort . decode . SBS.fromShort++instance Decode SBS.ShortByteString BS.ByteString where+ decode = decode . SBS.fromShort++instance Decode SBS.ShortByteString BS.L.ByteString where+ decode = decode . SBS.fromShort++instance Decode SBS.ShortByteString BB.Builder where+ decode = decode . SBS.fromShort++----++instance Decode BB.Builder SBS.ShortByteString where+ decode = decode . BB.toLazyByteString++instance Decode BB.Builder BS.L.ByteString where+ decode = decode . BB.toLazyByteString++instance Decode BB.Builder BS.ByteString where+ decode = decode . BB.toLazyByteString++instance Decode BB.Builder BB.Builder where+ decode = decode . BB.toLazyByteString++----++instance Decode T.Text BS.ByteString where+ decode = decode . T.encodeUtf8++instance Decode T.Text BS.L.ByteString where+ decode = decode . T.encodeUtf8++instance Decode T.Text SBS.ShortByteString where+ decode = decode . T.encodeUtf8++instance Decode T.Text BB.Builder where+ decode = decode . T.encodeUtf8++----++instance Decode T.L.Text BS.ByteString where+ decode = decode . T.L.encodeUtf8++instance Decode T.L.Text BS.L.ByteString where+ decode = decode . T.L.encodeUtf8++instance Decode T.L.Text SBS.ShortByteString where+ decode = decode . T.L.encodeUtf8++instance Decode T.L.Text BB.Builder where+ decode = decode . T.L.encodeUtf8++----++instance Decode TB.Builder BS.ByteString where+ decode = decode . TB.toLazyText++instance Decode TB.Builder BS.L.ByteString where+ decode = decode . TB.toLazyText++instance Decode TB.Builder SBS.ShortByteString where+ decode = decode . TB.toLazyText++instance Decode TB.Builder BB.Builder where+ decode = decode . TB.toLazyText
+ src/Codec/Base32/Impl.hs view
@@ -0,0 +1,251 @@+{-# LANGUAGE BangPatterns #-}++-- simple unoptimized implementation of base32(hex)+module Codec.Base32.Impl+ ( decodeBs2Bs+ , decodeBsL2BsL+ , encodeBs2Bs+ , encodeBsL2BsL+ , Fmt(..)+ ) where++import qualified Data.ByteString as BS+import qualified Data.ByteString.Builder as BB+import qualified Data.ByteString.Char8 as BS.C+import qualified Data.ByteString.Lazy as BS.L++import Control.Monad+import Data.Bits+import Data.Word++import Internal++-- exported primitives++data Fmt = Fmt'base32 | Fmt'base32hex++{-# INLINE decodeBs2Bs #-}+decodeBs2Bs :: Fmt -> BS.ByteString -> Either String BS.ByteString+decodeBs2Bs !fmt bs0 = case runDecode fmt bs0 of+ DR'Final chunk -> pure $! bsToStrict $ BB.toLazyByteString chunk+ DR'Error ofs err -> Left $ showDecErr ofs err+ DR'Partial chunk0 cont -> case cont mempty of+ DR'Final chunk1 -> pure $! bsToStrict $ BB.toLazyByteString (chunk0<>chunk1) -- chunk1 ought to be empty -- TODO: maybe refactor internal API+ DR'Partial _ _ -> error "decodeBs2Bs: the impossible just happened" -- broken invariant+ DR'Error ofs err -> Left $ showDecErr ofs err++{-# INLINE decodeBsL2BsL #-}+decodeBsL2BsL :: Fmt -> BS.L.ByteString -> Either String BS.L.ByteString+decodeBsL2BsL !fmt bs0 = go mempty (runDecode fmt) (filter (not . BS.null) $ BS.L.toChunks bs0)+ where+ go acc runDec (c:cs) = case runDec c of+ DR'Final _ -> error "impossible"+ DR'Error ofs err -> Left $! showDecErr ofs err -- TODO+ DR'Partial chunk cont -> go (acc <> chunk) cont cs++ go acc runDec [] = case runDec mempty of+ DR'Final chunk -> pure $! BB.toLazyByteString (acc <> chunk)+ DR'Partial _ _ -> error "decodeBsL2BsL: the impossible just happened" -- broken invariant+ DR'Error ofs err -> Left $ showDecErr ofs err++encodeBs2Bs :: Fmt -> BS.ByteString -> BS.ByteString+encodeBs2Bs !fmt = BS.C.pack . slowEnc fmt True . BS.unpack++encodeBsL2BsL :: Fmt -> BS.L.ByteString -> BS.L.ByteString+encodeBsL2BsL !fmt = BS.L.fromChunks . go mempty . BS.L.toChunks+ where+ go rest [] = encodeBs2Bs fmt rest : []+ go rest (c:cs)+ | rclen < 5 = go rc cs -- shortcut+ | otherwise = encodeBs2Bs fmt c' : go rest' cs+ where+ rlen = BS.length rest+ clen = BS.length c+ rc = rest <> c -- TODO: avoid copying large chunks of data+ rclen = rlen + clen+ rlen' = rclen `rem` 5+ (c',rest') = BS.splitAt (rclen - rlen') rc++----------------------------------------------------------------------------+-- encoding++-- | Relatively slow streaming base32 encoder+slowEnc :: Fmt -> Bool -> [Word8] -> [Char]+slowEnc !fmt doPad = go0+ where+ go0 [] = []+ go0 (x:xs) = sym hi : go1 lo xs+ where -- 5|3+ (hi,lo) = x `quotRem` 0x08++ go1 rest [] = sym (rest * 0x04) : pad "======"+ go1 rest (x:xs) = sym (rest * 0x04 + hi) : sym mid : go2 lo xs+ where -- 2|5|1+ (hi,tmp) = x `quotRem` 0x40+ (mid,lo) = tmp `quotRem` 0x02++ go2 rest [] = sym (rest * 0x10) : pad "===="+ go2 rest (x:xs) = sym (rest * 0x10 + hi) : go3 lo xs+ where -- 4|4+ (hi,lo) = x `quotRem` 0x10++ go3 rest [] = sym (rest * 0x02) : pad "==="+ go3 rest (x:xs) = sym (rest * 0x02 + hi) : sym mid : go4 lo xs+ where -- 1|5|2+ (hi,tmp) = x `quotRem` 0x80+ (mid,lo) = tmp `quotRem` 0x04++ go4 rest [] = sym (rest * 0x08) : pad "="+ go4 rest (x:xs) = sym (rest * 0x08 + hi) : sym lo : go0 xs+ where -- 3|5+ (hi,lo) = x `quotRem` 0x20++ pad x | doPad = x+ | otherwise = []++ sym = case fmt of+ Fmt'base32 -> sym0+ Fmt'base32hex -> symx++ -- plain base32 alphabet+ sym0 :: Word8 -> Char+ sym0 w+ | w < 26 = toEnum (fromIntegral w + 0x41)+ | w < 32 = toEnum (fromIntegral w + 24)+ | otherwise = undefined -- sym (w `rem` 32)++ -- base32hex alphabet+ symx :: Word8 -> Char+ symx w+ | w < 10 = toEnum (fromIntegral w + 0x30)+ | w < 32 = toEnum (fromIntegral w + 55)+ | otherwise = undefined -- sym (w `rem` 32)++----------------------------------------------------------------------------+-- decoding++-- internal abstraction+data DecodeRes = DR'Final !BB.Builder -- only emitted on empty EOF-signalling input+ | DR'Partial !BB.Builder (BS.ByteString -> DecodeRes)+ | DR'Error !Word DecodeError++instance Show DecodeRes where+ show (DR'Final x) = "DR'Final " ++ show (BB.toLazyByteString x)+ show (DR'Partial x _) = "DR'Partial " ++ show (BB.toLazyByteString x) ++ " <cont>"+ show (DR'Error ofs err) = "DR'Err " ++ show ofs ++ " " ++ show err++data DecodeError = Error'IncompleteInput+ | Error'InvalidChar+ | Error'InvalidPad+ deriving Show++showDecErr :: Word -> DecodeError -> String+showDecErr ofs Error'InvalidPad = "Base32-encoded data has invalid padding at offset: " ++ show ofs+showDecErr ofs Error'IncompleteInput = "Base32-encoded data ended prematurely at offset: " ++ show ofs+showDecErr ofs Error'InvalidChar = "Base32-encoded data has invalid character at offset: " ++ show ofs++runDecode :: Fmt -> BS.ByteString -> DecodeRes+runDecode !fmt = go 0 mempty+ where+ -- invariants:+ -- len(buf0) < 8++ go ofs0 buf0 buf1+ | doflush, BS.null buf0 = DR'Final mempty+ | doflush = case decodePaddedChunk fmt buf0 of+ Left (ofs,err) -> DR'Error (ofs0+ofs) err+ Right (out,rest)+ | BS.null rest -> DR'Final out -- actually not possible for padded input+ | otherwise -> error "runDecode: the impossible just happened" -- because buf0 invariant+ | buf01len < 8 = DR'Partial mempty (go ofs0 buf01)+ | otherwise = case decodeChunks fmt buf01 of+ Left (ofs,err) -> DR'Error (ofs0+ofs) err+ Right (chunks,rest) -> DR'Partial chunks (go (ofs0 + fromIntegral (buf01len - BS.length rest)) rest)+ where+ -- TODO: consider avoiding copying all of buf1 and instead copy only the prefix needed to+ -- complete buf0 into a full chunk+ buf01 = buf0 <> buf1+ buf01len = BS.length buf01++ doflush = BS.null buf1++-- | Iterate over multiple chunks; calls 'decodeChunk' repeatedly+--+-- The remaining ByteString is guaranteed to be smaller than 8 octets+decodeChunks :: Fmt -> BS.ByteString -> Either (Word,DecodeError) (BB.Builder,BS.ByteString)+decodeChunks !fmt = go 0 mempty+ where+ go !ofs0 bb0 bs0+ | BS.null bs0 = pure (bb0,mempty)+ | otherwise = case decodePaddedChunk fmt bs0 of+ Left (_, Error'IncompleteInput) -> pure (bb0,bs0)+ Left (ofs1,err) -> Left (ofs0+ofs1, err)+ Right (chunk, rest) -> go (ofs0+8) (bb0 <> chunk) rest++-- | Tries do decode a single 40bit base32 chunk (encoded as eight case-insensitive ASCII chars)+--+-- NB: An empty input leads to an incomplete input error result, as this function will either decode exactly a single+-- chunk or report an error+decodePaddedChunk :: Fmt -> BS.ByteString -> Either (Word,DecodeError) (BB.Builder,BS.ByteString)+decodePaddedChunk !fmt bs0+ | bs0len < 8 = Left (fromIntegral $ bs0len, Error'IncompleteInput)+ | otherwise = do+ let (digs,padding) = BS.break (== 0x3d) $ BS.take 8 bs0++ let vlen = fromIntegral $ BS.length digs+ vals <- forM (zip [0..] (BS.C.unpack digs)) $+ \(i,c) -> maybe (Left (i,Error'InvalidChar)) pure $ desym c++ olen <- case vlen of+ 0 -> Left (0, Error'InvalidPad)+ 1 -> Left (1, Error'InvalidPad)+ 2 -> pure 1+ 3 -> Left (3, Error'InvalidPad)+ 4 -> pure 2+ 5 -> pure 3+ 6 -> Left (6, Error'InvalidPad)+ 7 -> pure 4+ 8 -> pure 5+ _ -> undefined++ -- check padding trailer has no garbage+ forM_ (zip [vlen ..] (BS.unpack padding)) $+ \(i,c) -> unless (c == 0x3d) $ Left (i, Error'InvalidPad)++ -- bit shuffle 8*5bit into 5*8bit+ let buf64 = sum $ zipWith shiftL (map fromIntegral vals) [35, 30 .. 0]+ buf8 = map (fromIntegral . shiftR (buf64 :: Word64)) [32, 24 .. 0]++ -- check last 5bit digit didn't have unused bits set+ unless (all (== 0) $ drop olen buf8) $ do+ Left (fromIntegral vlen - 1, Error'InvalidPad)++ pure $ (BB.byteString $ BS.pack $ take olen buf8, BS.drop 8 bs0)+ where+ bs0len = BS.length bs0++ desym = case fmt of+ Fmt'base32 -> desym0+ Fmt'base32hex -> desymx++ -- plain base32 alphabet (case-insens)+ desym0 :: Char -> Maybe Word8+ desym0 c0 = case fromEnum c0 of+ c | c < 0x32 -> Nothing+ | c < 0x38 -> Just $! fromIntegral (c - 24)+ | c < 0x41 -> Nothing+ | c < 0x5b -> Just $! fromIntegral (c - 0x41)+ | c < 0x61 -> Nothing+ | c < 0x7b -> Just $! fromIntegral (c - 0x61)+ | otherwise -> Nothing++ -- base32hex alphabet (case-insens)+ desymx :: Char -> Maybe Word8+ desymx c0 = case fromEnum c0 of+ c | c < 0x30 -> Nothing+ | c < 0x3a -> Just $! fromIntegral (c - 0x30)+ | c < 0x41 -> Nothing+ | c < 0x57 -> Just $! fromIntegral (c - 55)+ | c < 0x61 -> Nothing+ | c < 0x77 -> Just $! fromIntegral (c - 87)+ | otherwise -> Nothing
+ src/Codec/Base32Hex.hs view
@@ -0,0 +1,269 @@+{-# LANGUAGE MultiParamTypeClasses #-}++-- | This module provides access to the \"base32hex\" binary-to-text encoding as defined by [RFC 4648](https://tools.ietf.org/html/rfc4648).+--+-- This module is intended to be imported @qualified@, e.g.+--+-- > import qualified Codec.Base32Hex as B32+--+-- If you want to explictly specify which 'Encode' and 'Decode' typeclass instance is used, you can use plain Haskell2010 type-signature annotations, e.g.+--+-- >>> (B32.encode :: ByteString -> Text) "\x00\x00"+-- "0000===="+--+-- >>> (B32.decode :: Text -> Either String ShortByteString) "6GT34C0="+-- Right "4:20"+--+-- Alternatively, starting with GHC 8.0.1, you can also use the [TypeApplications language extension](https://downloads.haskell.org/~ghc/8.4.1/docs/html/users_guide/glasgow_exts.html#ghc-flag--XTypeApplications):+--+-- >>> B32.encode @ShortByteString @Text "\xFF\239"+-- "VVNG===="+--+-- >>> B32.decode @Text @ShortByteString "VVNG===="+-- Right "\255\239"+--+-- @since 0.3.0.0+module Codec.Base32Hex+ ( Encode(encode)+ , Decode(decode)+ ) where++import qualified Codec.Base32.Impl as Impl++import qualified Data.ByteString as BS+import qualified Data.ByteString.Builder as BB+import qualified Data.ByteString.Lazy as BS.L+import qualified Data.ByteString.Short as SBS++import qualified Data.Text as T (Text)+import qualified Data.Text.Encoding as T (decodeLatin1, encodeUtf8)+import qualified Data.Text.Lazy as T.L (Text, fromStrict)+import qualified Data.Text.Lazy.Builder as TB (Builder, fromLazyText,+ fromText, toLazyText)+import qualified Data.Text.Lazy.Encoding as T.L (decodeLatin1, encodeUtf8)++import Internal++-- primitives++decodeBs2Bs :: BS.ByteString -> Either String BS.ByteString+decodeBs2Bs = Impl.decodeBs2Bs Impl.Fmt'base32hex++decodeBsL2BsL :: BS.L.ByteString -> Either String BS.L.ByteString+decodeBsL2BsL = Impl.decodeBsL2BsL Impl.Fmt'base32hex++encodeBs2Bs :: BS.ByteString -> BS.ByteString+encodeBs2Bs = Impl.encodeBs2Bs Impl.Fmt'base32hex++encodeBsL2BsL :: BS.L.ByteString -> BS.L.ByteString+encodeBsL2BsL = Impl.encodeBsL2BsL Impl.Fmt'base32hex++----------------------------------------------------------------------------+-- exposed API++-- | Typeclass representing types for which a binary-to-text @base32hex@ encoding is defined+class Encode bin txt where+ -- | Encode binary data using @base32hex@ text encoding+ encode :: bin -> txt++-- | Typeclass representing types for which a text-to-binary @base32hex@ decoding is defined+class Decode txt bin where+ -- | Decode binary data encoded textually as @base32hex@+ decode :: txt -> Either String bin++----------------------------------------------------------------------------+-- instance matrix++---- lazy BS -> *++-- PRIMITIVE+instance Encode BS.L.ByteString BS.L.ByteString where+ encode = encodeBsL2BsL++instance Encode BS.L.ByteString BS.ByteString where+ encode = bsToStrict . encode++instance Encode BS.L.ByteString BB.Builder where+ encode = BB.lazyByteString . encode++instance Encode BS.L.ByteString SBS.ShortByteString where+ encode = SBS.toShort . encode++instance Encode BS.L.ByteString T.Text where+ encode = T.decodeLatin1 . encode++instance Encode BS.L.ByteString T.L.Text where+ encode = T.L.decodeLatin1 . encode++instance Encode BS.L.ByteString TB.Builder where+ encode = TB.fromLazyText . encode++---- strict BS -> *++-- PRIMITIVE+instance Encode BS.ByteString BS.ByteString where+ encode = encodeBs2Bs++instance Encode BS.ByteString BS.L.ByteString where+ encode = bsFromStrict . encode++instance Encode BS.ByteString BB.Builder where+ encode = BB.byteString . encode++instance Encode BS.ByteString SBS.ShortByteString where+ encode = SBS.toShort . encode++instance Encode BS.ByteString T.Text where+ encode = T.decodeLatin1 . encode++instance Encode BS.ByteString T.L.Text where+ encode = T.L.fromStrict . T.decodeLatin1 . encode++instance Encode BS.ByteString TB.Builder where+ encode = TB.fromText . encode++---- short BS -> *++instance Encode SBS.ShortByteString SBS.ShortByteString where+ encode = SBS.toShort . encode . SBS.fromShort++instance Encode SBS.ShortByteString BS.ByteString where+ encode = encode . SBS.fromShort++instance Encode SBS.ShortByteString BS.L.ByteString where+ encode = encode . SBS.fromShort++instance Encode SBS.ShortByteString BB.Builder where+ encode = encode . SBS.fromShort++instance Encode SBS.ShortByteString T.Text where+ encode = T.decodeLatin1 . encode++instance Encode SBS.ShortByteString T.L.Text where+ encode = T.L.fromStrict . T.decodeLatin1 . encode++instance Encode SBS.ShortByteString TB.Builder where+ encode = TB.fromText . encode++---- BB -> *++instance Encode BB.Builder SBS.ShortByteString where+ encode = encode . BB.toLazyByteString++instance Encode BB.Builder BB.Builder where+ encode = encode . BB.toLazyByteString++instance Encode BB.Builder BS.ByteString where+ encode = encode . BB.toLazyByteString++instance Encode BB.Builder BS.L.ByteString where+ encode = encode . BB.toLazyByteString++instance Encode BB.Builder T.Text where+ encode = T.decodeLatin1 . encode++instance Encode BB.Builder T.L.Text where+ encode = T.L.decodeLatin1 . encode++instance Encode BB.Builder TB.Builder where+ encode = TB.fromLazyText . encode++------------------------------------------------------------------------------++-- PRIMITIVE+instance Decode BS.ByteString BS.ByteString where+ decode = decodeBs2Bs++instance Decode BS.ByteString BS.L.ByteString where+ decode = fmap bsFromStrict . decode++instance Decode BS.ByteString SBS.ShortByteString where+ decode = fmap SBS.toShort . decode++instance Decode BS.ByteString BB.Builder where+ decode = fmap BB.byteString . decode++----++-- PRIMITIVE+instance Decode BS.L.ByteString BS.L.ByteString where+ decode = decodeBsL2BsL++instance Decode BS.L.ByteString BS.ByteString where+ decode = fmap bsToStrict . decode++instance Decode BS.L.ByteString SBS.ShortByteString where+ decode = fmap SBS.toShort . decode++instance Decode BS.L.ByteString BB.Builder where+ decode = fmap BB.byteString . decode++----++instance Decode SBS.ShortByteString SBS.ShortByteString where+ decode = fmap SBS.toShort . decode . SBS.fromShort++instance Decode SBS.ShortByteString BS.ByteString where+ decode = decode . SBS.fromShort++instance Decode SBS.ShortByteString BS.L.ByteString where+ decode = decode . SBS.fromShort++instance Decode SBS.ShortByteString BB.Builder where+ decode = decode . SBS.fromShort++----++instance Decode BB.Builder SBS.ShortByteString where+ decode = decode . BB.toLazyByteString++instance Decode BB.Builder BS.L.ByteString where+ decode = decode . BB.toLazyByteString++instance Decode BB.Builder BS.ByteString where+ decode = decode . BB.toLazyByteString++instance Decode BB.Builder BB.Builder where+ decode = decode . BB.toLazyByteString++----++instance Decode T.Text BS.ByteString where+ decode = decode . T.encodeUtf8++instance Decode T.Text BS.L.ByteString where+ decode = decode . T.encodeUtf8++instance Decode T.Text SBS.ShortByteString where+ decode = decode . T.encodeUtf8++instance Decode T.Text BB.Builder where+ decode = decode . T.encodeUtf8++----++instance Decode T.L.Text BS.ByteString where+ decode = decode . T.L.encodeUtf8++instance Decode T.L.Text BS.L.ByteString where+ decode = decode . T.L.encodeUtf8++instance Decode T.L.Text SBS.ShortByteString where+ decode = decode . T.L.encodeUtf8++instance Decode T.L.Text BB.Builder where+ decode = decode . T.L.encodeUtf8++----++instance Decode TB.Builder BS.ByteString where+ decode = decode . TB.toLazyText++instance Decode TB.Builder BS.L.ByteString where+ decode = decode . TB.toLazyText++instance Decode TB.Builder SBS.ShortByteString where+ decode = decode . TB.toLazyText++instance Decode TB.Builder BB.Builder where+ decode = decode . TB.toLazyText
src/Codec/Base64.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE CPP #-} {-# LANGUAGE MultiParamTypeClasses #-} -- | This module provides access to the \"base64\" binary-to-text encoding as defined by [RFC 4648](https://tools.ietf.org/html/rfc4648).@@ -33,15 +32,9 @@ import qualified Data.ByteString.Base64.Lazy as B64.L import qualified Data.ByteString as BS-#if MIN_VERSION_bytestring(0,10,2) import qualified Data.ByteString.Builder as BB-#elif MIN_VERSION_bytestring(0,10,0)-import qualified Data.ByteString.Lazy.Builder as BB-#endif import qualified Data.ByteString.Lazy as BS.L-#if MIN_VERSION_bytestring(0,10,4) import qualified Data.ByteString.Short as SBS-#endif import qualified Data.Text as T (Text) import qualified Data.Text.Encoding as T (decodeLatin1, encodeUtf8)@@ -91,15 +84,11 @@ instance Encode BS.L.ByteString BS.ByteString where encode = bsToStrict . encode -#if MIN_VERSION_bytestring(0,10,0) instance Encode BS.L.ByteString BB.Builder where encode = BB.lazyByteString . encode-#endif -#if MIN_VERSION_bytestring(0,10,4) instance Encode BS.L.ByteString SBS.ShortByteString where encode = SBS.toShort . encode-#endif instance Encode BS.L.ByteString T.Text where encode = T.decodeLatin1 . encode@@ -119,15 +108,11 @@ instance Encode BS.ByteString BS.L.ByteString where encode = bsFromStrict . encode -#if MIN_VERSION_bytestring(0,10,0) instance Encode BS.ByteString BB.Builder where encode = BB.byteString . encode-#endif -#if MIN_VERSION_bytestring(0,10,4) instance Encode BS.ByteString SBS.ShortByteString where encode = SBS.toShort . encode-#endif instance Encode BS.ByteString T.Text where encode = T.decodeLatin1 . encode@@ -140,7 +125,6 @@ ---- short BS -> * -#if MIN_VERSION_bytestring(0,10,4) instance Encode SBS.ShortByteString SBS.ShortByteString where encode = SBS.toShort . encode . SBS.fromShort @@ -161,16 +145,12 @@ instance Encode SBS.ShortByteString TB.Builder where encode = TB.fromText . encode-#endif ---- BB -> * -#if MIN_VERSION_bytestring(0,10,4) instance Encode BB.Builder SBS.ShortByteString where encode = encode . BB.toLazyByteString-#endif -#if MIN_VERSION_bytestring(0,10,0) instance Encode BB.Builder BB.Builder where encode = encode . BB.toLazyByteString @@ -188,7 +168,6 @@ instance Encode BB.Builder TB.Builder where encode = TB.fromLazyText . encode-#endif ------------------------------------------------------------------------------ @@ -199,15 +178,11 @@ instance Decode BS.ByteString BS.L.ByteString where decode = fmap bsFromStrict . decode -#if MIN_VERSION_bytestring(0,10,4) instance Decode BS.ByteString SBS.ShortByteString where decode = fmap SBS.toShort . decode-#endif -#if MIN_VERSION_bytestring(0,10,0) instance Decode BS.ByteString BB.Builder where decode = fmap BB.byteString . decode-#endif ---- @@ -218,19 +193,14 @@ instance Decode BS.L.ByteString BS.ByteString where decode = fmap bsToStrict . decode -#if MIN_VERSION_bytestring(0,10,4) instance Decode BS.L.ByteString SBS.ShortByteString where decode = fmap SBS.toShort . decode-#endif -#if MIN_VERSION_bytestring(0,10,0) instance Decode BS.L.ByteString BB.Builder where decode = fmap BB.byteString . decode-#endif ---- -#if MIN_VERSION_bytestring(0,10,4) instance Decode SBS.ShortByteString SBS.ShortByteString where decode = fmap SBS.toShort . decode . SBS.fromShort @@ -242,16 +212,12 @@ instance Decode SBS.ShortByteString BB.Builder where decode = decode . SBS.fromShort-#endif ---- -#if MIN_VERSION_bytestring(0,10,4) instance Decode BB.Builder SBS.ShortByteString where decode = decode . BB.toLazyByteString-#endif -#if MIN_VERSION_bytestring(0,10,0) instance Decode BB.Builder BS.L.ByteString where decode = decode . BB.toLazyByteString @@ -260,7 +226,6 @@ instance Decode BB.Builder BB.Builder where decode = decode . BB.toLazyByteString-#endif ---- @@ -270,15 +235,11 @@ instance Decode T.Text BS.L.ByteString where decode = decode . T.encodeUtf8 -#if MIN_VERSION_bytestring(0,10,4) instance Decode T.Text SBS.ShortByteString where decode = decode . T.encodeUtf8-#endif -#if MIN_VERSION_bytestring(0,10,0) instance Decode T.Text BB.Builder where decode = decode . T.encodeUtf8-#endif ---- @@ -288,15 +249,11 @@ instance Decode T.L.Text BS.L.ByteString where decode = decode . T.L.encodeUtf8 -#if MIN_VERSION_bytestring(0,10,4) instance Decode T.L.Text SBS.ShortByteString where decode = decode . T.L.encodeUtf8-#endif -#if MIN_VERSION_bytestring(0,10,0) instance Decode T.L.Text BB.Builder where decode = decode . T.L.encodeUtf8-#endif ---- @@ -306,12 +263,8 @@ instance Decode TB.Builder BS.L.ByteString where decode = decode . TB.toLazyText -#if MIN_VERSION_bytestring(0,10,4) instance Decode TB.Builder SBS.ShortByteString where decode = decode . TB.toLazyText-#endif -#if MIN_VERSION_bytestring(0,10,0) instance Decode TB.Builder BB.Builder where decode = decode . TB.toLazyText-#endif
src/Codec/Base64Url.hs view
@@ -1,7 +1,6 @@-{-# LANGUAGE CPP #-} {-# LANGUAGE MultiParamTypeClasses #-} --- | This module provides access to the \"base64url\" binary-to-text encoding as defined by [RFC 4648](https://tools.ietf.org/html/rfc4648).+-- | This module provides access to the /padded/ \"base64url\" binary-to-text encoding as defined by [RFC 4648](https://tools.ietf.org/html/rfc4648). See also "Codec.Base64Url.Unpadded" for the /unpadded/ encoding variant. -- -- This module is intended to be imported @qualified@, e.g. --@@ -32,34 +31,27 @@ import qualified Data.ByteString.Base64.URL as B64 import qualified Data.ByteString.Base64.URL.Lazy as B64.L -import qualified Data.ByteString as BS-#if MIN_VERSION_bytestring(0,10,2)-import qualified Data.ByteString.Builder as BB-#elif MIN_VERSION_bytestring(0,10,0)-import qualified Data.ByteString.Lazy.Builder as BB-#endif-import qualified Data.ByteString.Lazy as BS.L-#if MIN_VERSION_bytestring(0,10,4)-import qualified Data.ByteString.Short as SBS-#endif+import qualified Data.ByteString as BS+import qualified Data.ByteString.Builder as BB+import qualified Data.ByteString.Lazy as BS.L+import qualified Data.ByteString.Short as SBS -import qualified Data.Text as T (Text)-import qualified Data.Text.Encoding as T (decodeLatin1, encodeUtf8)-import qualified Data.Text.Lazy as T.L (Text, fromStrict)-import qualified Data.Text.Lazy.Builder as TB (Builder, fromLazyText,- fromText, toLazyText)-import qualified Data.Text.Lazy.Encoding as T.L (decodeLatin1,- encodeUtf8)+import qualified Data.Text as T (Text)+import qualified Data.Text.Encoding as T (decodeLatin1, encodeUtf8)+import qualified Data.Text.Lazy as T.L (Text, fromStrict)+import qualified Data.Text.Lazy.Builder as TB (Builder, fromLazyText,+ fromText, toLazyText)+import qualified Data.Text.Lazy.Encoding as T.L (decodeLatin1, encodeUtf8) import Internal -- primitives decodeBs2Bs :: BS.ByteString -> Either String BS.ByteString-decodeBs2Bs = B64.decode+decodeBs2Bs = B64.decodePadded decodeBsL2BsL :: BS.L.ByteString -> Either String BS.L.ByteString-decodeBsL2BsL = B64.L.decode+decodeBsL2BsL = B64.L.decodePadded encodeBs2Bs :: BS.ByteString -> BS.ByteString encodeBs2Bs = B64.encode@@ -70,14 +62,14 @@ ---------------------------------------------------------------------------- -- exposed API --- | Typeclass representing types for which a binary-to-text @base64url@ encoding is defined+-- | Typeclass representing types for which a binary-to-text /padded/ @base64url@ encoding is defined class Encode bin txt where- -- | Encode binary data using @base64url@ text encoding+ -- | Encode binary data using /padded/ @base64url@ text encoding encode :: bin -> txt --- | Typeclass representing types for which a text-to-binary @base64url@ decoding is defined+-- | Typeclass representing types for which a text-to-binary /padded/ @base64url@ decoding is defined class Decode txt bin where- -- | Decode binary data encoded textually as @base64url@+ -- | Decode binary data encoded textually as /padded/ @base64url@ decode :: txt -> Either String bin ----------------------------------------------------------------------------@@ -92,15 +84,11 @@ instance Encode BS.L.ByteString BS.ByteString where encode = bsToStrict . encode -#if MIN_VERSION_bytestring(0,10,0) instance Encode BS.L.ByteString BB.Builder where encode = BB.lazyByteString . encode-#endif -#if MIN_VERSION_bytestring(0,10,4) instance Encode BS.L.ByteString SBS.ShortByteString where encode = SBS.toShort . encode-#endif instance Encode BS.L.ByteString T.Text where encode = T.decodeLatin1 . encode@@ -120,15 +108,11 @@ instance Encode BS.ByteString BS.L.ByteString where encode = bsFromStrict . encode -#if MIN_VERSION_bytestring(0,10,0) instance Encode BS.ByteString BB.Builder where encode = BB.byteString . encode-#endif -#if MIN_VERSION_bytestring(0,10,4) instance Encode BS.ByteString SBS.ShortByteString where encode = SBS.toShort . encode-#endif instance Encode BS.ByteString T.Text where encode = T.decodeLatin1 . encode@@ -141,7 +125,6 @@ ---- short BS -> * -#if MIN_VERSION_bytestring(0,10,4) instance Encode SBS.ShortByteString SBS.ShortByteString where encode = SBS.toShort . encode . SBS.fromShort @@ -162,16 +145,12 @@ instance Encode SBS.ShortByteString TB.Builder where encode = TB.fromText . encode-#endif ---- BB -> * -#if MIN_VERSION_bytestring(0,10,4) instance Encode BB.Builder SBS.ShortByteString where encode = encode . BB.toLazyByteString-#endif -#if MIN_VERSION_bytestring(0,10,0) instance Encode BB.Builder BB.Builder where encode = encode . BB.toLazyByteString @@ -189,7 +168,6 @@ instance Encode BB.Builder TB.Builder where encode = TB.fromLazyText . encode-#endif ------------------------------------------------------------------------------ @@ -200,15 +178,11 @@ instance Decode BS.ByteString BS.L.ByteString where decode = fmap bsFromStrict . decode -#if MIN_VERSION_bytestring(0,10,4) instance Decode BS.ByteString SBS.ShortByteString where decode = fmap SBS.toShort . decode-#endif -#if MIN_VERSION_bytestring(0,10,0) instance Decode BS.ByteString BB.Builder where decode = fmap BB.byteString . decode-#endif ---- @@ -219,19 +193,14 @@ instance Decode BS.L.ByteString BS.ByteString where decode = fmap bsToStrict . decode -#if MIN_VERSION_bytestring(0,10,4) instance Decode BS.L.ByteString SBS.ShortByteString where decode = fmap SBS.toShort . decode-#endif -#if MIN_VERSION_bytestring(0,10,0) instance Decode BS.L.ByteString BB.Builder where decode = fmap BB.byteString . decode-#endif ---- -#if MIN_VERSION_bytestring(0,10,4) instance Decode SBS.ShortByteString SBS.ShortByteString where decode = fmap SBS.toShort . decode . SBS.fromShort @@ -243,16 +212,12 @@ instance Decode SBS.ShortByteString BB.Builder where decode = decode . SBS.fromShort-#endif ---- -#if MIN_VERSION_bytestring(0,10,4) instance Decode BB.Builder SBS.ShortByteString where decode = decode . BB.toLazyByteString-#endif -#if MIN_VERSION_bytestring(0,10,0) instance Decode BB.Builder BS.L.ByteString where decode = decode . BB.toLazyByteString @@ -261,7 +226,6 @@ instance Decode BB.Builder BB.Builder where decode = decode . BB.toLazyByteString-#endif ---- @@ -271,15 +235,11 @@ instance Decode T.Text BS.L.ByteString where decode = decode . T.encodeUtf8 -#if MIN_VERSION_bytestring(0,10,4) instance Decode T.Text SBS.ShortByteString where decode = decode . T.encodeUtf8-#endif -#if MIN_VERSION_bytestring(0,10,0) instance Decode T.Text BB.Builder where decode = decode . T.encodeUtf8-#endif ---- @@ -289,15 +249,11 @@ instance Decode T.L.Text BS.L.ByteString where decode = decode . T.L.encodeUtf8 -#if MIN_VERSION_bytestring(0,10,4) instance Decode T.L.Text SBS.ShortByteString where decode = decode . T.L.encodeUtf8-#endif -#if MIN_VERSION_bytestring(0,10,0) instance Decode T.L.Text BB.Builder where decode = decode . T.L.encodeUtf8-#endif ---- @@ -307,12 +263,8 @@ instance Decode TB.Builder BS.L.ByteString where decode = decode . TB.toLazyText -#if MIN_VERSION_bytestring(0,10,4) instance Decode TB.Builder SBS.ShortByteString where decode = decode . TB.toLazyText-#endif -#if MIN_VERSION_bytestring(0,10,0) instance Decode TB.Builder BB.Builder where decode = decode . TB.toLazyText-#endif
+ src/Codec/Base64Url/Unpadded.hs view
@@ -0,0 +1,278 @@+{-# LANGUAGE MultiParamTypeClasses #-}++-- | This module provides access to the /unpadded/ \"base64url\" binary-to-text encoding as defined by [RFC 4648](https://tools.ietf.org/html/rfc4648). See also "Codec.Base64Url" for the /padded/ encoding variant.+--+-- This module is intended to be imported @qualified@, e.g.+--+-- > import qualified Codec.Base64Url.Unpadded as B64+--+-- If you want to explictly specify which 'Encode' and 'Decode' typeclass instance is used, you can use plain Haskell2010 type-signature annotations, e.g.+--+-- >>> (B64.encode :: ByteString -> Text) "\x00\x00"+-- "AAA"+--+-- >>> (B64.decode :: Text -> Either String ShortByteString) "NDoyMA"+-- Right "4:20"+--+-- Alternatively, starting with GHC 8.0.1, you can also use the [TypeApplications language extension](https://downloads.haskell.org/~ghc/8.4.1/docs/html/users_guide/glasgow_exts.html#ghc-flag--XTypeApplications):+--+-- >>> B64.encode @ShortByteString @Text "\xFF\239"+-- "_-8"+--+-- >>> B64.decode @Text @ShortByteString "_-8"+-- Right "\255\239"+--+-- @since 0.2.0.0+module Codec.Base64Url.Unpadded+ ( Encode(encode)+ , Decode(decode)+ ) where++import qualified Data.ByteString.Base64.URL as B64+import qualified Data.ByteString.Base64.URL.Lazy as B64.L++import qualified Data.ByteString as BS+import qualified Data.ByteString.Builder as BB+import qualified Data.ByteString.Lazy as BS.L+import qualified Data.ByteString.Short as SBS++import qualified Data.Text as T (Text)+import qualified Data.Text.Encoding as T (decodeLatin1, encodeUtf8)+import qualified Data.Text.Lazy as T.L (Text, fromStrict)+import qualified Data.Text.Lazy.Builder as TB (Builder, fromLazyText,+ fromText, toLazyText)+import qualified Data.Text.Lazy.Encoding as T.L (decodeLatin1, encodeUtf8)++import Internal++-- primitives++decodeBs2Bs :: BS.ByteString -> Either String BS.ByteString+decodeBs2Bs = B64.decodeUnpadded++decodeBsL2BsL :: BS.L.ByteString -> Either String BS.L.ByteString+decodeBsL2BsL = B64.L.decodeUnpadded++encodeBs2Bs :: BS.ByteString -> BS.ByteString+encodeBs2Bs = B64.encodeUnpadded++encodeBsL2BsL :: BS.L.ByteString -> BS.L.ByteString+encodeBsL2BsL = B64.L.encodeUnpadded++----------------------------------------------------------------------------+-- exposed API++-- | Typeclass representing types for which a binary-to-text /unpadded/ @base64url@ encoding is defined+--+-- @since 0.2.0.0+class Encode bin txt where+ -- | Encode binary data using /unpadded/ @base64url@ text encoding+ --+ -- @since 0.2.0.0+ encode :: bin -> txt++-- | Typeclass representing types for which a text-to-binary /unpadded/ @base64url@ decoding is defined+--+-- @since 0.2.0.0+class Decode txt bin where+ -- | Decode binary data encoded textually as /unpadded/ @base64url@+ --+ -- @since 0.2.0.0+ decode :: txt -> Either String bin++----------------------------------------------------------------------------+-- instance matrix++---- lazy BS -> *++-- PRIMITIVE+instance Encode BS.L.ByteString BS.L.ByteString where+ encode = encodeBsL2BsL++instance Encode BS.L.ByteString BS.ByteString where+ encode = bsToStrict . encode++instance Encode BS.L.ByteString BB.Builder where+ encode = BB.lazyByteString . encode++instance Encode BS.L.ByteString SBS.ShortByteString where+ encode = SBS.toShort . encode++instance Encode BS.L.ByteString T.Text where+ encode = T.decodeLatin1 . encode++instance Encode BS.L.ByteString T.L.Text where+ encode = T.L.decodeLatin1 . encode++instance Encode BS.L.ByteString TB.Builder where+ encode = TB.fromLazyText . encode++---- strict BS -> *++-- PRIMITIVE+instance Encode BS.ByteString BS.ByteString where+ encode = encodeBs2Bs++instance Encode BS.ByteString BS.L.ByteString where+ encode = bsFromStrict . encode++instance Encode BS.ByteString BB.Builder where+ encode = BB.byteString . encode++instance Encode BS.ByteString SBS.ShortByteString where+ encode = SBS.toShort . encode++instance Encode BS.ByteString T.Text where+ encode = T.decodeLatin1 . encode++instance Encode BS.ByteString T.L.Text where+ encode = T.L.fromStrict . T.decodeLatin1 . encode++instance Encode BS.ByteString TB.Builder where+ encode = TB.fromText . encode++---- short BS -> *++instance Encode SBS.ShortByteString SBS.ShortByteString where+ encode = SBS.toShort . encode . SBS.fromShort++instance Encode SBS.ShortByteString BS.ByteString where+ encode = encode . SBS.fromShort++instance Encode SBS.ShortByteString BS.L.ByteString where+ encode = encode . SBS.fromShort++instance Encode SBS.ShortByteString BB.Builder where+ encode = encode . SBS.fromShort++instance Encode SBS.ShortByteString T.Text where+ encode = T.decodeLatin1 . encode++instance Encode SBS.ShortByteString T.L.Text where+ encode = T.L.fromStrict . T.decodeLatin1 . encode++instance Encode SBS.ShortByteString TB.Builder where+ encode = TB.fromText . encode++---- BB -> *++instance Encode BB.Builder SBS.ShortByteString where+ encode = encode . BB.toLazyByteString++instance Encode BB.Builder BB.Builder where+ encode = encode . BB.toLazyByteString++instance Encode BB.Builder BS.ByteString where+ encode = encode . BB.toLazyByteString++instance Encode BB.Builder BS.L.ByteString where+ encode = encode . BB.toLazyByteString++instance Encode BB.Builder T.Text where+ encode = T.decodeLatin1 . encode++instance Encode BB.Builder T.L.Text where+ encode = T.L.decodeLatin1 . encode++instance Encode BB.Builder TB.Builder where+ encode = TB.fromLazyText . encode++------------------------------------------------------------------------------++-- PRIMITIVE+instance Decode BS.ByteString BS.ByteString where+ decode = decodeBs2Bs++instance Decode BS.ByteString BS.L.ByteString where+ decode = fmap bsFromStrict . decode++instance Decode BS.ByteString SBS.ShortByteString where+ decode = fmap SBS.toShort . decode++instance Decode BS.ByteString BB.Builder where+ decode = fmap BB.byteString . decode++----++-- PRIMITIVE+instance Decode BS.L.ByteString BS.L.ByteString where+ decode = decodeBsL2BsL++instance Decode BS.L.ByteString BS.ByteString where+ decode = fmap bsToStrict . decode++instance Decode BS.L.ByteString SBS.ShortByteString where+ decode = fmap SBS.toShort . decode++instance Decode BS.L.ByteString BB.Builder where+ decode = fmap BB.byteString . decode++----++instance Decode SBS.ShortByteString SBS.ShortByteString where+ decode = fmap SBS.toShort . decode . SBS.fromShort++instance Decode SBS.ShortByteString BS.ByteString where+ decode = decode . SBS.fromShort++instance Decode SBS.ShortByteString BS.L.ByteString where+ decode = decode . SBS.fromShort++instance Decode SBS.ShortByteString BB.Builder where+ decode = decode . SBS.fromShort++----++instance Decode BB.Builder SBS.ShortByteString where+ decode = decode . BB.toLazyByteString++instance Decode BB.Builder BS.L.ByteString where+ decode = decode . BB.toLazyByteString++instance Decode BB.Builder BS.ByteString where+ decode = decode . BB.toLazyByteString++instance Decode BB.Builder BB.Builder where+ decode = decode . BB.toLazyByteString++----++instance Decode T.Text BS.ByteString where+ decode = decode . T.encodeUtf8++instance Decode T.Text BS.L.ByteString where+ decode = decode . T.encodeUtf8++instance Decode T.Text SBS.ShortByteString where+ decode = decode . T.encodeUtf8++instance Decode T.Text BB.Builder where+ decode = decode . T.encodeUtf8++----++instance Decode T.L.Text BS.ByteString where+ decode = decode . T.L.encodeUtf8++instance Decode T.L.Text BS.L.ByteString where+ decode = decode . T.L.encodeUtf8++instance Decode T.L.Text SBS.ShortByteString where+ decode = decode . T.L.encodeUtf8++instance Decode T.L.Text BB.Builder where+ decode = decode . T.L.encodeUtf8++----++instance Decode TB.Builder BS.ByteString where+ decode = decode . TB.toLazyText++instance Decode TB.Builder BS.L.ByteString where+ decode = decode . TB.toLazyText++instance Decode TB.Builder SBS.ShortByteString where+ decode = decode . TB.toLazyText++instance Decode TB.Builder BB.Builder where+ decode = decode . TB.toLazyText
src/Internal.hs view
@@ -4,14 +4,25 @@ ( bsToStrict , bsFromStrict , (<$>)+ , pure+ , Data.Monoid.mempty+ , (<>) ) where #if !MIN_VERSION_base(4,8,0) import Control.Applicative #endif +import Data.Monoid import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as BS.L++#if !MIN_VERSION_base(4,5,0)+(<>) :: Monoid a => a -> a -> a+(<>) = mappend++infixr 6 <>+#endif {-# INLINE bsToStrict #-} bsToStrict :: BS.L.ByteString -> BS.ByteString