File: Lazy.hs

package info (click to toggle)
haskell-base16-bytestring 0.1.1.4-2
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 68 kB
  • sloc: haskell: 142; makefile: 2
file content (64 lines) | stat: -rw-r--r-- 2,070 bytes parent folder | download | duplicates (4)
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)