-- | Common utility functions, used both in the client and the server. module Parry.Util( -- * Hexadecimal encoders and decoders. encode16,decode16,encode16l,decode16l ) where import qualified Data.ByteString.Lazy.Internal as ILB import qualified Data.ByteString.Internal as IB import qualified Data.ByteString as B import qualified Data.ByteString.Unsafe as UB import qualified Data.ByteString.Char8 as B8 import Foreign.Ptr import Foreign.Storable import Data.Bits import Data.Word -- | Encodes a strict bytestring to its hexadecimal representation. See 'decode16'. encode16 :: B.ByteString -> B.ByteString encode16 bytes= let { len=B.length bytes } in IB.unsafeCreate (len*2) $ \pp-> let { fill p0 i | i>=len=return () | otherwise=do { let { c=UB.unsafeIndex bytes i; c0=c`shiftR`4; c1=c.&.0xf }; poke p0 $ if c0<=9 then 48+c0 else 97+c0-10; poke (p0`plusPtr`1) $ if c1<=9 then 48+c1 else 97+c1-10; fill (p0`plusPtr`2) $ i+1 }} in fill pp 0 atomHex::Word8->Word8 atomHex c= if c<=(fromIntegral $ fromEnum '9') then c-(fromIntegral $ fromEnum '0') else c-(fromIntegral $ fromEnum 'a')+10 -- | Decodes a strict bytestring from its hexadecimal representation. See 'encode16'. decode16::B8.ByteString->B8.ByteString decode16 bytes= let { len=B.length bytes } in IB.unsafeCreate (len`quot`2) $ \pp-> let { fill p0 i | i>=len=return () | otherwise=do { let { c0=atomHex $ UB.unsafeIndex bytes i; c1=atomHex $ UB.unsafeIndex bytes (i+1) }; poke p0 $ (c0`shiftL`4) .|. c1; fill (p0`plusPtr`1) $ i+2 }} in fill pp 0 -- | Encodes a lazy bytestring to its hexadecimal representation. encode16l::ILB.ByteString->ILB.ByteString encode16l ILB.Empty=ILB.Empty encode16l (ILB.Chunk x xs)=ILB.Chunk (encode16 x) (encode16l xs) -- | Decodes a lazy bytestring from its hexadecimal representation. decode16l::ILB.ByteString->ILB.ByteString decode16l ILB.Empty=ILB.Empty decode16l (ILB.Chunk x xs)=ILB.Chunk (decode16 x) (decode16l xs)