1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
|
{-# LANGUAGE OverloadedStrings #-}
-- |
-- Module : Data.ByteString.Base16.Lazy
-- Copyright : (c) 2011 MailRank, Inc.
--
-- License : BSD
-- Maintainer : bos@serpentine.com
-- Stability : experimental
-- Portability : GHC
--
-- Fast and efficient encoding and decoding of base16-encoded strings.
module Data.ByteString.Base16.Lazy
(
encode
, decode
) where
import Data.Word (Word8)
import qualified Data.ByteString.Base16 as B16
import qualified Data.ByteString as B
import qualified Data.ByteString.Unsafe as B
import Data.ByteString.Lazy.Internal
-- | Encode a string into base16 form. The result will always be a
-- multiple of 2 bytes in length.
--
-- Example:
--
-- > encode "foo" == "666f6f"
encode :: ByteString -> ByteString
encode (Chunk c cs) = Chunk (B16.encode c) (encode cs)
encode Empty = Empty
-- | Decode a string from base16 form. The first element of the
-- returned tuple contains the decoded data. The second element starts
-- at the first invalid base16 sequence in the original string.
--
-- This function operates as lazily as possible over the input chunks.
-- The only instance in which it is non-lazy is if an odd-length chunk
-- ends with a byte that is valid base16.
--
-- Examples:
--
-- > decode "666f6f" == ("foo", "")
-- > decode "66quux" == ("f", "quux")
-- > decode "666quux" == ("f", "6quux")
decode :: ByteString -> (ByteString, ByteString)
decode = foldrChunks go (Empty, Empty)
where go c ~(y,z)
| len == 0 = (chunk h y, z)
| len == 1 && isHex (B.unsafeHead t) =
case z of
Chunk a as | isHex (B.unsafeHead a)
-> let (q,_) = B16.decode (t `B.snoc` B.unsafeHead a)
in (chunk h (chunk q y), chunk (B.unsafeTail a) as)
_ -> (chunk h y, chunk t z)
| otherwise = (chunk h y, chunk t z)
where (h,t) = B16.decode c
len = B.length t
isHex :: Word8 -> Bool
isHex w = (w >= 48 && w <= 57) || (w >= 97 && w <= 102) || (w >= 65 && w <= 70)
|