packages feed

HCodecs 0.4.2 → 0.5

raw patch · 13 files changed

+1207/−1267 lines, 13 filesdep ~QuickCheckdep ~basePVP ok

version bump matches the API change (PVP)

Dependency ranges changed: QuickCheck, base

API changes (from Hackage documentation)

+ Codec.ByteString.Builder: append :: Builder -> Builder -> Builder
+ Codec.ByteString.Builder: data Builder
+ Codec.ByteString.Builder: empty :: Builder
+ Codec.ByteString.Builder: flush :: Builder
+ Codec.ByteString.Builder: fromByteString :: ByteString -> Builder
+ Codec.ByteString.Builder: fromLazyByteString :: ByteString -> Builder
+ Codec.ByteString.Builder: instance Monoid Builder
+ Codec.ByteString.Builder: putInt16be :: Int16 -> Builder
+ Codec.ByteString.Builder: putInt16le :: Int16 -> Builder
+ Codec.ByteString.Builder: putInt32be :: Int32 -> Builder
+ Codec.ByteString.Builder: putInt32le :: Int32 -> Builder
+ Codec.ByteString.Builder: putInt64be :: Int64 -> Builder
+ Codec.ByteString.Builder: putInt64le :: Int64 -> Builder
+ Codec.ByteString.Builder: putInt8 :: Int8 -> Builder
+ Codec.ByteString.Builder: putString :: String -> Builder
+ Codec.ByteString.Builder: putVarLenBe :: Word64 -> Builder
+ Codec.ByteString.Builder: putVarLenLe :: Word64 -> Builder
+ Codec.ByteString.Builder: putWord16be :: Word16 -> Builder
+ Codec.ByteString.Builder: putWord16host :: Word16 -> Builder
+ Codec.ByteString.Builder: putWord16le :: Word16 -> Builder
+ Codec.ByteString.Builder: putWord24be :: Word32 -> Builder
+ Codec.ByteString.Builder: putWord24le :: Word32 -> Builder
+ Codec.ByteString.Builder: putWord32be :: Word32 -> Builder
+ Codec.ByteString.Builder: putWord32host :: Word32 -> Builder
+ Codec.ByteString.Builder: putWord32le :: Word32 -> Builder
+ Codec.ByteString.Builder: putWord64be :: Word64 -> Builder
+ Codec.ByteString.Builder: putWord64host :: Word64 -> Builder
+ Codec.ByteString.Builder: putWord64le :: Word64 -> Builder
+ Codec.ByteString.Builder: putWord8 :: Word8 -> Builder
+ Codec.ByteString.Builder: putWordHost :: Word -> Builder
+ Codec.ByteString.Builder: singleton :: Word8 -> Builder
+ Codec.ByteString.Builder: toLazyByteString :: Builder -> ByteString
+ Codec.ByteString.Parser: bytesRead :: Parser Int64
+ Codec.ByteString.Parser: choice :: [Parser a] -> Parser a
+ Codec.ByteString.Parser: data Parser a
+ Codec.ByteString.Parser: expect :: (Show a, Eq a) => (a -> Bool) -> Parser a -> Parser a
+ Codec.ByteString.Parser: getByteString :: Int -> Parser ByteString
+ Codec.ByteString.Parser: getBytes :: Int -> Parser ByteString
+ Codec.ByteString.Parser: getInt16be :: Parser Int16
+ Codec.ByteString.Parser: getInt16le :: Parser Int16
+ Codec.ByteString.Parser: getInt32be :: Parser Int32
+ Codec.ByteString.Parser: getInt32le :: Parser Int32
+ Codec.ByteString.Parser: getInt64be :: Parser Int64
+ Codec.ByteString.Parser: getInt64le :: Parser Int64
+ Codec.ByteString.Parser: getInt8 :: Parser Int8
+ Codec.ByteString.Parser: getLazyByteString :: Int64 -> Parser ByteString
+ Codec.ByteString.Parser: getLazyByteStringNul :: Parser ByteString
+ Codec.ByteString.Parser: getRemainingLazyByteString :: Parser ByteString
+ Codec.ByteString.Parser: getString :: Int -> Parser String
+ Codec.ByteString.Parser: getStringNul :: Parser String
+ Codec.ByteString.Parser: getVarLenBe :: Parser Word64
+ Codec.ByteString.Parser: getVarLenLe :: Parser Word64
+ Codec.ByteString.Parser: getWord16be :: Parser Word16
+ Codec.ByteString.Parser: getWord16host :: Parser Word16
+ Codec.ByteString.Parser: getWord16le :: Parser Word16
+ Codec.ByteString.Parser: getWord24be :: Parser Word32
+ Codec.ByteString.Parser: getWord24le :: Parser Word32
+ Codec.ByteString.Parser: getWord32be :: Parser Word32
+ Codec.ByteString.Parser: getWord32host :: Parser Word32
+ Codec.ByteString.Parser: getWord32le :: Parser Word32
+ Codec.ByteString.Parser: getWord64be :: Parser Word64
+ Codec.ByteString.Parser: getWord64host :: Parser Word64
+ Codec.ByteString.Parser: getWord64le :: Parser Word64
+ Codec.ByteString.Parser: getWord8 :: Parser Word8
+ Codec.ByteString.Parser: getWordHost :: Parser Word
+ Codec.ByteString.Parser: instance Alternative Parser
+ Codec.ByteString.Parser: instance Applicative Parser
+ Codec.ByteString.Parser: instance Functor Parser
+ Codec.ByteString.Parser: instance Monad Parser
+ Codec.ByteString.Parser: instance MonadPlus Parser
+ Codec.ByteString.Parser: int16be :: Int16 -> Parser Int16
+ Codec.ByteString.Parser: int16le :: Int16 -> Parser Int16
+ Codec.ByteString.Parser: int32be :: Int32 -> Parser Int32
+ Codec.ByteString.Parser: int32le :: Int32 -> Parser Int32
+ Codec.ByteString.Parser: int64be :: Int64 -> Parser Int64
+ Codec.ByteString.Parser: int64le :: Int64 -> Parser Int64
+ Codec.ByteString.Parser: int8 :: Int8 -> Parser Int8
+ Codec.ByteString.Parser: isEmpty :: Parser Bool
+ Codec.ByteString.Parser: lookAhead :: Parser a -> Parser a
+ Codec.ByteString.Parser: lookAheadE :: Parser (Either a b) -> Parser (Either a b)
+ Codec.ByteString.Parser: lookAheadM :: Parser (Maybe a) -> Parser (Maybe a)
+ Codec.ByteString.Parser: remaining :: Parser Int64
+ Codec.ByteString.Parser: runParser :: Parser a -> ByteString -> Either String a
+ Codec.ByteString.Parser: runParserState :: Parser a -> ByteString -> Int64 -> Either String (a, ByteString, Int64)
+ Codec.ByteString.Parser: satisfy :: (Word8 -> Bool) -> Parser Word8
+ Codec.ByteString.Parser: skip :: Word64 -> Parser ()
+ Codec.ByteString.Parser: string :: String -> Parser String
+ Codec.ByteString.Parser: varLenBe :: Word64 -> Parser Word64
+ Codec.ByteString.Parser: varLenLe :: Word64 -> Parser Word64
+ Codec.ByteString.Parser: word16be :: Word16 -> Parser Word16
+ Codec.ByteString.Parser: word16host :: Word16 -> Parser Word16
+ Codec.ByteString.Parser: word16le :: Word16 -> Parser Word16
+ Codec.ByteString.Parser: word24be :: Word32 -> Parser Word32
+ Codec.ByteString.Parser: word24le :: Word32 -> Parser Word32
+ Codec.ByteString.Parser: word32be :: Word32 -> Parser Word32
+ Codec.ByteString.Parser: word32host :: Word32 -> Parser Word32
+ Codec.ByteString.Parser: word32le :: Word32 -> Parser Word32
+ Codec.ByteString.Parser: word64be :: Word64 -> Parser Word64
+ Codec.ByteString.Parser: word64host :: Word64 -> Parser Word64
+ Codec.ByteString.Parser: word64le :: Word64 -> Parser Word64
+ Codec.ByteString.Parser: word8 :: Word8 -> Parser Word8
+ Codec.ByteString.Parser: wordHost :: Word -> Parser Word

Files

HCodecs.cabal view
@@ -1,5 +1,5 @@ name: HCodecs-version: 0.4.2+version: 0.5 cabal-Version: >= 1.8 license: BSD3 license-file: LICENSE@@ -24,20 +24,20 @@ library   hs-source-dirs: src   ghc-options: -O3 -Wall-  build-depends: base < 5, bytestring, random, array >= 0.4, QuickCheck < 2+  build-depends: base < 5, bytestring, random, array >= 0.4, QuickCheck >= 2.0   exposed-modules:     Codec.Midi     Codec.Wav     Codec.SoundFont+    Codec.ByteString.Parser+    Codec.ByteString.Builder     Data.Audio   other-modules:-    Internal.ByteString.Parser-    Internal.ByteString.Builder-    Internal.Arbitrary+    Codec.Internal.Arbitrary  test-suite tests   type: exitcode-stdio-1.0   hs-source-dirs: src   ghc-options: -O3 -Wall-  build-depends: base < 5, bytestring, random, array >= 0.4, QuickCheck < 2-  main-is: Internal/TestSuite.hs+  build-depends: base < 5, bytestring, random, array >= 0.4, QuickCheck >= 2.0+  main-is: Codec/Internal/TestSuite.hs
+ src/Codec/ByteString/Builder.hs view
@@ -0,0 +1,392 @@+-----------------------------------------------------------------------------+-- |+-- Module      : Data.ByteString.Builder+-- Copyright   : Lennart Kolmodin, Ross Paterson, George Giorgidze+-- License     : BSD3+--+-- Maintainer  : George Giorgidze <http://cs.nott.ac.uk/~ggg/>+-- Stability   : experimental+-- Portability : Portable+--+-- Efficient construction of lazy bytestrings.+--+-----------------------------------------------------------------------------+module Codec.ByteString.Builder (++    -- * The Builder type+      Builder+    , toLazyByteString++    -- * Constructing Builders+    , empty+    , singleton+    , putWord8+    , putInt8+    , append+    , fromByteString        -- :: S.ByteString -> Builder+    , fromLazyByteString    -- :: L.ByteString -> Builder+    , putString++    -- * Flushing the buffer state+    , flush++    -- * Derived Builders+    -- ** Big-endian writes+    , putWord16be           -- :: Word16 -> Builder+    , putWord24be           -- :: Word32 -> Builder+    , putWord32be           -- :: Word32 -> Builder+    , putWord64be           -- :: Word64 -> Builder++    , putInt16be           -- :: Int16 -> Builder+    , putInt32be           -- :: Int32 -> Builder+    , putInt64be           -- :: Int64 -> Builder++    -- ** Little-endian writes+    , putWord16le           -- :: Word16 -> Builder+    , putWord24le           -- :: Word32 -> Builder+    , putWord32le           -- :: Word32 -> Builder+    , putWord64le           -- :: Word64 -> Builder++    , putInt16le           -- :: Int16 -> Builder+    , putInt32le           -- :: Int32 -> Builder+    , putInt64le           -- :: Int64 -> Builder++    -- ** Host-endian, unaligned writes+    , putWordHost           -- :: Word -> Builder+    , putWord16host         -- :: Word16 -> Builder+    , putWord32host         -- :: Word32 -> Builder+    , putWord64host         -- :: Word64 -> Builder+    -- Variable length numbers+    , putVarLenBe+    , putVarLenLe++  ) where+++import qualified Data.ByteString.Internal as S+import qualified Data.ByteString          as S+import qualified Data.ByteString.Lazy     as L++import Foreign.Storable         (Storable, poke, sizeOf)+import Foreign.Ptr              (Ptr, plusPtr)+import Foreign.ForeignPtr       (ForeignPtr, withForeignPtr)+import System.IO.Unsafe         (unsafePerformIO)+import Data.ByteString.Internal (inlinePerformIO,c2w)++import Data.Bits+import Data.Word+import Data.Int+import Data.Monoid++------------------------------------------------------------------------++-- | A 'Builder' is an efficient way to build lazy 'L.ByteString's.+-- There are several functions for constructing 'Builder's, but only one+-- to inspect them: to extract any data, you have to turn them into lazy+-- 'L.ByteString's using 'toLazyByteString'.+--+-- Internally, a 'Builder' constructs a lazy 'L.Bytestring' by filling byte+-- arrays piece by piece.  As each buffer is filled, it is \'popped\'+-- off, to become a new chunk of the resulting lazy 'L.ByteString'.+-- All this is hidden from the user of the 'Builder'.++newtype Builder = Builder {+        -- Invariant (from Data.ByteString.Lazy):+        --      The lists include no null ByteStrings.+        runBuilder :: (Buffer -> [S.ByteString]) -> Buffer -> [S.ByteString]+    }++instance Monoid Builder where+    mempty  = empty+    mappend = append++------------------------------------------------------------------------++-- | /O(1)./ The empty Builder, satisfying+--+--  * @'toLazyByteString' 'empty' = 'L.empty'@+--+empty :: Builder+empty = Builder id++-- | /O(1)./ A Builder taking a single byte, satisfying+--+--  * @'toLazyByteString' ('singleton' b) = 'L.singleton' b@+--+singleton :: Word8 -> Builder+singleton = writeN 1 . flip poke++putWord8 :: Word8 -> Builder+putWord8 = singleton+------------------------------------------------------------------------++-- | /O(1)./ The concatenation of two Builders, an associative operation+-- with identity 'empty', satisfying+--+--  * @'toLazyByteString' ('append' x y) = 'L.append' ('toLazyByteString' x) ('toLazyByteString' y)@+--+append :: Builder -> Builder -> Builder+append (Builder f) (Builder g) = Builder (f . g)++-- | /O(1)./ A Builder taking a 'S.ByteString', satisfying+--+--  * @'toLazyByteString' ('fromByteString' bs) = 'L.fromChunks' [bs]@+--+fromByteString :: S.ByteString -> Builder+fromByteString bs+  | S.null bs = empty+  | otherwise = flush `append` mapBuilder (bs :)++-- | /O(1)./ A Builder taking a lazy 'L.ByteString', satisfying+--+--  * @'toLazyByteString' ('fromLazyByteString' bs) = bs@+--+fromLazyByteString :: L.ByteString -> Builder+fromLazyByteString bss = flush `append` mapBuilder (L.toChunks bss ++)++putString :: String -> Builder+putString = fromLazyByteString . L.pack . map c2w++------------------------------------------------------------------------++-- Our internal buffer type+data Buffer = Buffer {-# UNPACK #-} !(ForeignPtr Word8)+                     {-# UNPACK #-} !Int                -- offset+                     {-# UNPACK #-} !Int                -- used bytes+                     {-# UNPACK #-} !Int                -- length left++------------------------------------------------------------------------++-- | /O(n)./ Extract a lazy 'L.ByteString' from a 'Builder'.+-- The construction work takes place if and when the relevant part of+-- the lazy 'L.ByteString' is demanded.+--+toLazyByteString :: Builder -> L.ByteString+toLazyByteString m = L.fromChunks $ unsafePerformIO $ do+    buf <- newBuffer defaultSize+    return (runBuilder (m `append` flush) (const []) buf)++-- | /O(1)./ Pop the 'S.ByteString' we have constructed so far, if any,+-- yielding a new chunk in the result lazy 'L.ByteString'.+flush :: Builder+flush = Builder $ \ k buf@(Buffer p o u l) ->+    if u == 0+      then k buf+      else S.PS p o u : k (Buffer p (o+u) 0 l)++------------------------------------------------------------------------++--+-- copied from Data.ByteString.Lazy+--+defaultSize :: Int+defaultSize = 32 * k - overhead+    where k = 1024+          overhead = 2 * sizeOf (undefined :: Int)++------------------------------------------------------------------------++-- | Sequence an IO operation on the buffer+unsafeLiftIO :: (Buffer -> IO Buffer) -> Builder+unsafeLiftIO f =  Builder $ \ k buf -> inlinePerformIO $ do+    buf' <- f buf+    return (k buf')++-- | Get the size of the buffer+withSize :: (Int -> Builder) -> Builder+withSize f = Builder $ \ k buf@(Buffer _ _ _ l) ->+    runBuilder (f l) k buf++-- | Map the resulting list of bytestrings.+mapBuilder :: ([S.ByteString] -> [S.ByteString]) -> Builder+mapBuilder f = Builder (f .)++------------------------------------------------------------------------++-- | Ensure that there are at least @n@ many bytes available.+ensureFree :: Int -> Builder+ensureFree n = n `seq` withSize $ \ l ->+    if n <= l then empty else+        flush `append` unsafeLiftIO (const (newBuffer (max n defaultSize)))++-- | Ensure that @n@ many bytes are available, and then use @f@ to write some+-- bytes into the memory.+writeN :: Int -> (Ptr Word8 -> IO ()) -> Builder+writeN n f = ensureFree n `append` unsafeLiftIO (writeNBuffer n f)++writeNBuffer :: Int -> (Ptr Word8 -> IO ()) -> Buffer -> IO Buffer+writeNBuffer n f (Buffer fp o u l) = do+    withForeignPtr fp (\p -> f (p `plusPtr` (o+u)))+    return (Buffer fp o (u+n) (l-n))++newBuffer :: Int -> IO Buffer+newBuffer size = do+    fp <- S.mallocByteString size+    return $! Buffer fp 0 0 size++------------------------------------------------------------------------+-- Aligned, host order writes of storable values++-- | Ensure that @n@ many bytes are available, and then use @f@ to write some+-- storable values into the memory.+writeNbytes :: Storable a => Int -> (Ptr a -> IO ()) -> Builder+writeNbytes n f = ensureFree n `append` unsafeLiftIO (writeNBufferBytes n f)++writeNBufferBytes :: Storable a => Int -> (Ptr a -> IO ()) -> Buffer -> IO Buffer+writeNBufferBytes n f (Buffer fp o u l) = do+    withForeignPtr fp (\p -> f (p `plusPtr` (o+u)))+    return (Buffer fp o (u+n) (l-n))++------------------------------------------------------------------------++--+-- We rely on the fromIntegral to do the right masking for us.+-- The inlining here is critical, and can be worth 4x performance+--++-- | Write a Word16 in big endian format+putWord16be :: Word16 -> Builder+putWord16be w = writeN 2 $ \p -> do+    poke p               (fromIntegral (shiftR w 8) :: Word8)+    poke (p `plusPtr` 1) (fromIntegral (w)              :: Word8)++-- | Write a Word16 in little endian format+putWord16le :: Word16 -> Builder+putWord16le w = writeN 2 $ \p -> do+    poke p               (fromIntegral (w)              :: Word8)+    poke (p `plusPtr` 1) (fromIntegral (shiftR w 8) :: Word8)++-- putWord16le w16 = writeN 2 (\p -> poke (castPtr p) w16)++-- | Write a 24 bit number in big endian format represented as Word32+putWord24be :: Word32 -> Builder+putWord24be w = writeN 3 $ \p -> do+    poke p               (fromIntegral (shiftR w 16) :: Word8)+    poke (p `plusPtr` 1) (fromIntegral (shiftR w 8) :: Word8)+    poke (p `plusPtr` 2) (fromIntegral (w) :: Word8)++-- | Write a 24 bit number in little endian format represented as Word32+putWord24le :: Word32 -> Builder+putWord24le w = writeN 3 $ \p -> do+    poke p               (fromIntegral (w)           :: Word8)+    poke (p `plusPtr` 1) (fromIntegral (shiftR w  8) :: Word8)+    poke (p `plusPtr` 2) (fromIntegral (shiftR w 16) :: Word8)++-- | Write a Word32 in big endian format+putWord32be :: Word32 -> Builder+putWord32be w = writeN 4 $ \p -> do+    poke p               (fromIntegral (shiftR w 24) :: Word8)+    poke (p `plusPtr` 1) (fromIntegral (shiftR w 16) :: Word8)+    poke (p `plusPtr` 2) (fromIntegral (shiftR w  8) :: Word8)+    poke (p `plusPtr` 3) (fromIntegral (w)           :: Word8)++--+-- a data type to tag Put/Check. writes construct these which are then+-- inlined and flattened. matching Checks will be more robust with rules.+--++-- | Write a Word32 in little endian format+putWord32le :: Word32 -> Builder+putWord32le w = writeN 4 $ \p -> do+    poke p               (fromIntegral (w)               :: Word8)+    poke (p `plusPtr` 1) (fromIntegral (shiftR w  8) :: Word8)+    poke (p `plusPtr` 2) (fromIntegral (shiftR w 16) :: Word8)+    poke (p `plusPtr` 3) (fromIntegral (shiftR w 24) :: Word8)++-- on a little endian machine:+-- putWord32le w32 = writeN 4 (\p -> poke (castPtr p) w32)++-- | Write a Word64 in big endian format+putWord64be :: Word64 -> Builder+putWord64be w = writeN 8 $ \p -> do+    poke p               (fromIntegral (shiftR w 56) :: Word8)+    poke (p `plusPtr` 1) (fromIntegral (shiftR w 48) :: Word8)+    poke (p `plusPtr` 2) (fromIntegral (shiftR w 40) :: Word8)+    poke (p `plusPtr` 3) (fromIntegral (shiftR w 32) :: Word8)+    poke (p `plusPtr` 4) (fromIntegral (shiftR w 24) :: Word8)+    poke (p `plusPtr` 5) (fromIntegral (shiftR w 16) :: Word8)+    poke (p `plusPtr` 6) (fromIntegral (shiftR w  8) :: Word8)+    poke (p `plusPtr` 7) (fromIntegral (w)               :: Word8)++-- | Write a Word64 in little endian format+putWord64le :: Word64 -> Builder+putWord64le w = writeN 8 $ \p -> do+    poke p               (fromIntegral (w)               :: Word8)+    poke (p `plusPtr` 1) (fromIntegral (shiftR w  8) :: Word8)+    poke (p `plusPtr` 2) (fromIntegral (shiftR w 16) :: Word8)+    poke (p `plusPtr` 3) (fromIntegral (shiftR w 24) :: Word8)+    poke (p `plusPtr` 4) (fromIntegral (shiftR w 32) :: Word8)+    poke (p `plusPtr` 5) (fromIntegral (shiftR w 40) :: Word8)+    poke (p `plusPtr` 6) (fromIntegral (shiftR w 48) :: Word8)+    poke (p `plusPtr` 7) (fromIntegral (shiftR w 56) :: Word8)++-- on a little endian machine:+-- putWord64le w64 = writeN 8 (\p -> poke (castPtr p) w64)++-----------------------------------------------------------------------++putInt8 :: Int8 -> Builder+putInt8 = putWord8 . fromIntegral++putInt16le :: Int16 -> Builder+putInt16le = putWord16le . fromIntegral++putInt16be :: Int16 -> Builder+putInt16be = putWord16be . fromIntegral++putInt32le :: Int32 -> Builder+putInt32le = putWord32le . fromIntegral++putInt32be :: Int32 -> Builder+putInt32be = putWord32be . fromIntegral++putInt64le :: Int64 -> Builder+putInt64le = putWord64le . fromIntegral++putInt64be :: Int64 -> Builder+putInt64be = putWord64be . fromIntegral++------------------------------------------------------------------------+-- Unaligned, word size ops++-- | /O(1)./ A Builder taking a single native machine word. The word is+-- written in host order, host endian form, for the machine you're on.+-- On a 64 bit machine the Word is an 8 byte value, on a 32 bit machine,+-- 4 bytes. Values written this way are not portable to+-- different endian or word sized machines, without conversion.+--+putWordHost :: Word -> Builder+putWordHost w = writeNbytes (sizeOf (undefined :: Word)) (\p -> poke p w)++-- | Write a Word16 in native host order and host endianness.+-- 2 bytes will be written, unaligned.+putWord16host :: Word16 -> Builder+putWord16host w16 = writeNbytes (sizeOf (undefined :: Word16)) (\p -> poke p w16)++-- | Write a Word32 in native host order and host endianness.+-- 4 bytes will be written, unaligned.+putWord32host :: Word32 -> Builder+putWord32host w32 = writeNbytes (sizeOf (undefined :: Word32)) (\p -> poke p w32)++-- | Write a Word64 in native host order.+-- On a 32 bit machine we write two host order Word32s, in big endian form.+-- 8 bytes will be written, unaligned.+putWord64host :: Word64 -> Builder+putWord64host w = writeNbytes (sizeOf (undefined :: Word64)) (\p -> poke p w)++------------------------------------------------------------------------++putVarLenBe :: Word64 -> Builder+putVarLenBe w = varLenAux2 $ reverse $ varLenAux1 w+  +putVarLenLe :: Word64 -> Builder+putVarLenLe w = varLenAux2 $ varLenAux1 w+  +varLenAux1 :: Word64 -> [Word8]+varLenAux1 0 = []+varLenAux1 w = (fromIntegral $ w .&. 0x7F) : (varLenAux1 $ shiftR w 7)++varLenAux2 :: [Word8] -> Builder+varLenAux2  [] = putWord8 0+varLenAux2  [w] = putWord8 w+varLenAux2 (w : ws) = putWord8 (setBit w 7) `append` varLenAux2 ws
+ src/Codec/ByteString/Parser.hs view
@@ -0,0 +1,593 @@+-----------------------------------------------------------------------------+-- |+-- Module      : Data.ByteString.Parser+-- Copyright   : Lennart Kolmodin, George Giorgidze+-- License     : BSD3+--+-- Maintainer  : George Giorgidze <http://cs.nott.ac.uk/~ggg/>+-- Stability   : experimental+-- Portability : Portable+--+-- A monad for efficiently building structures from+-- encoded lazy ByteStrings.+--+-----------------------------------------------------------------------------++module Codec.ByteString.Parser (++    -- * The Parser type+      Parser+    , runParser+    , runParserState++    -- * Parsing+    , choice+    , expect+    , skip+    , lookAhead+    , lookAheadM+    , lookAheadE++    -- * Utility+    , bytesRead+    , getBytes+    , remaining+    , isEmpty++    -- * Parsing particular types+    , satisfy+    , getString+    , getStringNul+    , string+    , getWord8+    , getInt8+    , word8+    , int8++    -- ** ByteStrings+    , getByteString+    , getLazyByteString+    , getLazyByteStringNul+    , getRemainingLazyByteString++    -- ** Big-endian reads+    , getWord16be+    , word16be+    , getWord24be+    , word24be+    , getWord32be+    , word32be+    , getWord64be+    , word64be++    , getInt16be+    , int16be+    , getInt32be+    , int32be+    , getInt64be+    , int64be++    -- ** Little-endian reads+    , getWord16le+    , word16le+    , getWord24le+    , word24le+    , getWord32le+    , word32le+    , getWord64le+    , word64le++    , getInt16le+    , int16le+    , getInt32le+    , int32le+    , getInt64le+    , int64le++    -- ** Host-endian, unaligned reads+    , getWordHost+    , wordHost+    , getWord16host+    , word16host+    , getWord32host+    , word32host+    , getWord64host+    , word64host++    -- Variable length reads+    , getVarLenBe+    , varLenBe+    , getVarLenLe+    , varLenLe+  ) where++import qualified Data.ByteString               as B+import qualified Data.ByteString.Lazy          as L+import qualified Data.ByteString.Internal      as B+import qualified Data.ByteString.Lazy.Internal as L++import Foreign.Storable        (Storable, peek, sizeOf)+import Foreign.Ptr             (plusPtr, castPtr)+import Foreign.ForeignPtr      (withForeignPtr)+import Control.Monad.ST        (runST)+import Control.Monad.ST.Unsafe (unsafeInterleaveST)++import Control.Monad+import Control.Applicative+import Data.STRef+import Data.Word+import Data.Int+import Data.Bits+import Data.Maybe++-- | The parse state+data S = S {-# UNPACK #-} !B.ByteString  -- current chunk+           L.ByteString                  -- the rest of the input+           {-# UNPACK #-} !Int64         -- bytes read++-- | The Get monad is just a State monad carrying around the input ByteString+newtype Parser a = Parser { unParser :: S -> Either String (a, S) }++instance Functor Parser where+    fmap f m = Parser $ \s -> case unParser m s of+      Left e -> Left e+      Right (a, s') -> Right (f a, s')+    +instance Monad Parser where+    return a  = Parser (\s -> Right (a, s))+    m >>= k   = Parser $ \s -> case (unParser m) s of+      Left e -> Left e+      Right (a, s') -> (unParser (k a)) s'+    fail  err  = Parser $ \(S _ _ bytes) ->+        Left (err ++ ". Failed reading at byte position " ++ show bytes)+instance MonadPlus Parser where+  mzero = Parser $ \_ -> Left []+  mplus p1 p2 = Parser $ \s -> case (unParser p1 s) of+    Left e1 -> case (unParser p2 s) of+      Left e2 -> Left (e1 ++ "\n" ++ e2)+      ok -> ok+    ok -> ok++instance Applicative Parser where+  pure  = return+  (<*>) = ap+  +instance Alternative Parser where+  empty = mzero+  (<|>) = mplus++------------------------------------------------------------------------++get :: Parser S+get   = Parser $ \s -> Right (s, s)++put :: S -> Parser ()+put s = Parser $ \_ -> Right ((), s)++------------------------------------------------------------------------++initState :: L.ByteString -> S+initState xs = mkState xs 0++mkState :: L.ByteString -> Int64 -> S+mkState l = case l of+    L.Empty      -> S B.empty L.empty+    L.Chunk x xs -> S x xs++-- | Run the Get monad applies a 'get'-based parser on the input ByteString+runParser :: Parser a -> L.ByteString -> Either String a+runParser m str = case unParser m (initState str) of+  Left e -> Left e+  Right (a, _) -> Right a++-- | Run the Get monad applies a 'get'-based parser on the input+-- ByteString. Additional to the result of get it returns the number of+-- consumed bytes and the rest of the input.+runParserState :: Parser a -> L.ByteString -> Int64 -> Either String (a, L.ByteString, Int64)+runParserState m str off =+    case unParser m (mkState str off) of+      Left e -> Left e+      Right (a, ~(S s ss newOff)) -> Right (a, s `bsJoin` ss, newOff)++------------------------------------------------------------------------++choice :: [Parser a] -> Parser a+choice = foldl (<|>) mzero++-- | Skip ahead @n@ bytes. Fails if fewer than @n@ bytes are available.+skip :: Word64 -> Parser ()+skip n = readN (fromIntegral n) (const ())++-- | Run @ga@, but return without consuming its input.+-- Fails if @ga@ fails.+lookAhead :: Parser a -> Parser a+lookAhead ga = do+    s <- get+    a <- ga+    put s+    return a++-- | Like 'lookAhead', but consume the input if @gma@ returns 'Just _'.+-- Fails if @gma@ fails.+lookAheadM :: Parser (Maybe a) -> Parser (Maybe a)+lookAheadM gma = do+    s <- get+    ma <- gma+    when (isNothing ma) $ put s+    return ma++-- | Like 'lookAhead', but consume the input if @gea@ returns 'Right _'.+-- Fails if @gea@ fails.+lookAheadE :: Parser (Either a b) -> Parser (Either a b)+lookAheadE gea = do+    s <- get+    ea <- gea+    case ea of+        Left _ -> put s+        _      -> return ()+    return ea++expect :: (Show a, Eq a) => (a -> Bool) -> Parser a -> Parser a+expect f p = do+  v <- p+  when (not $ f v) $ fail $ show v ++ " was not expected."+  return v++getString :: Int -> Parser String+getString l = do+  bs <- getLazyByteString (fromIntegral l)+  return $! map B.w2c (L.unpack bs)++getStringNul :: Parser String+getStringNul = do+  bs <- getLazyByteStringNul+  return $! map B.w2c (L.unpack bs)++string :: String -> Parser String+string s = expect (s ==) (getString $ length s)++-- Utility++-- | Get the total number of bytes read to this point.+bytesRead :: Parser Int64+bytesRead = do+    S _ _ b <- get+    return b++-- | Get the number of remaining unparsed bytes.+-- Useful for checking whether all input has been consumed.+-- Note that this forces the rest of the input.+remaining :: Parser Int64+remaining = do+    S s ss _ <- get+    return $! (fromIntegral (B.length s) + L.length ss)++-- | Test whether all input has been consumed,+-- i.e. there are no remaining unparsed bytes.+isEmpty :: Parser Bool+isEmpty = do+    S s ss _ <- get+    return $! (B.null s && L.null ss)++------------------------------------------------------------------------+-- Utility with ByteStrings++-- | An efficient 'get' method for strict ByteStrings. Fails if fewer+-- than @n@ bytes are left in the input.+getByteString :: Int -> Parser B.ByteString+getByteString n = readN n id++-- | An efficient 'get' method for lazy ByteStrings. Does not fail if fewer than+-- @n@ bytes are left in the input.+getLazyByteString :: Int64 -> Parser L.ByteString+getLazyByteString n = do+    S s ss bytes <- get+    let big = s `bsJoin` ss+    case splitAtST n big of+      (consume, rest) -> do put $ mkState rest (bytes + n)+                            return consume++-- | Get a lazy ByteString that is terminated with a NUL byte. Fails+-- if it reaches the end of input without hitting a NUL.+getLazyByteStringNul :: Parser L.ByteString+getLazyByteStringNul = do+    S s ss bytes <- get+    let big = s `bsJoin` ss+        (consume, t) = L.break (== 0) big+        (h, rest) = L.splitAt 1 t+    when (L.null h) $ fail "too few bytes"+    put $ mkState rest (bytes + L.length consume + 1)+    return consume++-- | Get the remaining bytes as a lazy ByteString+getRemainingLazyByteString :: Parser L.ByteString+getRemainingLazyByteString = do+    S s ss _ <- get+    return $! (s `bsJoin` ss)++------------------------------------------------------------------------+-- Helpers++-- | Pull @n@ bytes from the input, as a strict ByteString.+getBytes :: Int -> Parser B.ByteString+getBytes n = do+    S s ss bytes <- get+    if n <= B.length s+        then do let (consume,rest) = B.splitAt n s+                put $! S rest ss (bytes + fromIntegral n)+                return $! consume+        else+              case L.splitAt (fromIntegral n) (s `bsJoin` ss) of+                (consuming, rest) ->+                    do let now = B.concat . L.toChunks $ consuming+                       put $! mkState rest (bytes + fromIntegral n)+                       -- forces the next chunk before this one is returned+                       when (B.length now < n) $ fail "too few bytes"+                       return now++bsJoin :: B.ByteString -> L.ByteString -> L.ByteString+bsJoin bb lb+    | B.null bb = lb+    | otherwise = L.Chunk bb lb++-- | Split a ByteString. If the first result is consumed before the --+-- second, this runs in constant heap space.+--+-- You must force the returned tuple for that to work, e.g.+--+-- > case splitAtST n xs of+-- >    (ys,zs) -> consume ys ... consume zs+--+splitAtST :: Int64 -> L.ByteString -> (L.ByteString, L.ByteString)+splitAtST i ps | i <= 0 = (L.empty, ps)+splitAtST i ps          = runST (+     do r  <- newSTRef undefined+        xs <- first r i ps+        ys <- unsafeInterleaveST (readSTRef r)+        return (xs, ys))++  where+        first r 0 xs@(L.Chunk _ _) = writeSTRef r xs    >> return L.Empty+        first r _ L.Empty          = writeSTRef r L.Empty >> return L.Empty++        first r n (L.Chunk x xs)+          | n < l     = do writeSTRef r (L.Chunk (B.drop (fromIntegral n) x) xs)+                           return $! L.Chunk (B.take (fromIntegral n) x) L.Empty+          | otherwise = do writeSTRef r (L.drop (n - l) xs)+                           liftM (L.Chunk x) $ unsafeInterleaveST (first r (n - l) xs)++         where l = fromIntegral (B.length x)++-- Pull n bytes from the input, and apply a parser to those bytes,+-- yielding a value. If less than @n@ bytes are available, fail with an+-- error. This wraps @getBytes@.+readN :: Int -> (B.ByteString -> a) -> Parser a+readN n f = fmap f $ getBytes n+++------------------------------------------------------------------------+-- Primtives++-- helper, get a raw Ptr onto a strict ByteString copied out of the+-- underlying lazy byteString. So many indirections from the raw parser+-- state that my head hurts...++getPtr :: Storable a => Int -> Parser a+getPtr n = do+    (fp,o,_) <- readN n B.toForeignPtr+    return . B.inlinePerformIO $ withForeignPtr fp $ \p -> peek (castPtr $ p `plusPtr` o)++------------------------------------------------------------------------++satisfy :: (Word8 -> Bool) -> Parser Word8+satisfy f = do+  w <- getWord8+  guard (f w)+  return w++-- | Read a Word8 from the monad state+getWord8 :: Parser Word8+getWord8 = getPtr (sizeOf (undefined :: Word8))++word8 :: Word8 -> Parser Word8+word8 w = expect (w ==) getWord8++-- | Read a Word16 in big endian format+getWord16be :: Parser Word16+getWord16be = do+    s <- readN 2 id+    return $! (fromIntegral (s `B.index` 0) `shiftL` 8) .|.+              (fromIntegral (s `B.index` 1))++word16be :: Word16 -> Parser Word16+word16be w = expect (w ==) getWord16be++-- | Read a Word16 in little endian format+getWord16le :: Parser Word16+getWord16le = do+    s <- readN 2 id+    return $! (fromIntegral (s `B.index` 1) `shiftL` 8) .|.+              (fromIntegral (s `B.index` 0) )++word16le :: Word16 -> Parser Word16+word16le w = expect (w ==) getWord16le++-- | Read a 24 bit word into Word32 in big endian format+getWord24be :: Parser Word32+getWord24be = do+    s <- readN 3 id+    return $! (fromIntegral (s `B.index` 0) `shiftL` 16) .|.+              (fromIntegral (s `B.index` 1) `shiftL`  8) .|.+              (fromIntegral (s `B.index` 2) )++word24be :: Word32 -> Parser Word32+word24be w = expect (w ==) getWord24be++getWord24le :: Parser Word32+getWord24le = do+    s <- readN 3 id+    return $! (fromIntegral (s `B.index` 2) `shiftL` 16) .|.+              (fromIntegral (s `B.index` 1) `shiftL`  8) .|.+              (fromIntegral (s `B.index` 0) )++word24le :: Word32 -> Parser Word32+word24le w = expect (w ==) getWord24le++-- | Read a Word32 in big endian format+getWord32be :: Parser Word32+getWord32be = do+    s <- readN 4 id+    return $! (fromIntegral (s `B.index` 0) `shiftL` 24) .|.+              (fromIntegral (s `B.index` 1) `shiftL` 16) .|.+              (fromIntegral (s `B.index` 2) `shiftL`  8) .|.+              (fromIntegral (s `B.index` 3) )++word32be :: Word32 -> Parser Word32+word32be w = expect (w ==) getWord32be++-- | Read a Word32 in little endian format+getWord32le :: Parser Word32+getWord32le = do+    s <- readN 4 id+    return $! (fromIntegral (s `B.index` 3) `shiftL` 24) .|.+              (fromIntegral (s `B.index` 2) `shiftL` 16) .|.+              (fromIntegral (s `B.index` 1) `shiftL`  8) .|.+              (fromIntegral (s `B.index` 0) )++word32le :: Word32 -> Parser Word32+word32le w = expect (w ==) getWord32le+++-- | Read a Word64 in big endian format+getWord64be :: Parser Word64+getWord64be = do+    s <- readN 8 id+    return $! (fromIntegral (s `B.index` 0) `shiftL` 56) .|.+              (fromIntegral (s `B.index` 1) `shiftL` 48) .|.+              (fromIntegral (s `B.index` 2) `shiftL` 40) .|.+              (fromIntegral (s `B.index` 3) `shiftL` 32) .|.+              (fromIntegral (s `B.index` 4) `shiftL` 24) .|.+              (fromIntegral (s `B.index` 5) `shiftL` 16) .|.+              (fromIntegral (s `B.index` 6) `shiftL`  8) .|.+              (fromIntegral (s `B.index` 7) )++word64be :: Word64 -> Parser Word64+word64be w = expect (w ==) getWord64be++-- | Read a Word64 in little endian format+getWord64le :: Parser Word64+getWord64le = do+    s <- readN 8 id+    return $! (fromIntegral (s `B.index` 7) `shiftL` 56) .|.+              (fromIntegral (s `B.index` 6) `shiftL` 48) .|.+              (fromIntegral (s `B.index` 5) `shiftL` 40) .|.+              (fromIntegral (s `B.index` 4) `shiftL` 32) .|.+              (fromIntegral (s `B.index` 3) `shiftL` 24) .|.+              (fromIntegral (s `B.index` 2) `shiftL` 16) .|.+              (fromIntegral (s `B.index` 1) `shiftL`  8) .|.+              (fromIntegral (s `B.index` 0) )++word64le :: Word64 -> Parser Word64+word64le w = expect (w ==) getWord64le+------------------------------------------------------------------------+getInt8 :: Parser Int8+getInt8 = getWord8 >>= return . fromIntegral++int8 :: Int8 -> Parser Int8+int8 i = expect (i ==) getInt8++getInt16le :: Parser Int16+getInt16le = getWord16le >>= return . fromIntegral++int16le :: Int16 -> Parser Int16+int16le i = expect (i ==) getInt16le++getInt16be :: Parser Int16+getInt16be = getWord16be >>= return . fromIntegral++int16be :: Int16 -> Parser Int16+int16be i = expect (i ==) getInt16be++getInt32le :: Parser Int32+getInt32le = getWord32le >>= return . fromIntegral++int32le :: Int32 -> Parser Int32+int32le i = expect (i ==) getInt32le++getInt32be :: Parser Int32+getInt32be = getWord32be >>= return . fromIntegral++int32be :: Int32 -> Parser Int32+int32be i = expect (i ==) getInt32be++getInt64le :: Parser Int64+getInt64le = getWord64le >>= return . fromIntegral++int64le :: Int64 -> Parser Int64+int64le i = expect (i ==) getInt64le++getInt64be :: Parser Int64+getInt64be = getWord64be >>= return . fromIntegral++int64be :: Int64 -> Parser Int64+int64be i = expect (i ==) getInt64be++------------------------------------------------------------------------+-- Host-endian reads++-- | /O(1)./ Read a single native machine word. The word is read in+-- host order, host endian form, for the machine you're on. On a 64 bit+-- machine the Word is an 8 byte value, on a 32 bit machine, 4 bytes.+getWordHost :: Parser Word+getWordHost = getPtr (sizeOf (undefined :: Word))++wordHost :: Word -> Parser Word+wordHost w = expect (w ==) getWordHost++-- | /O(1)./ Read a 2 byte Word16 in native host order and host endianness.+getWord16host :: Parser Word16+getWord16host = getPtr (sizeOf (undefined :: Word16))++word16host :: Word16 -> Parser Word16+word16host w = expect (w ==) getWord16host++-- | /O(1)./ Read a Word32 in native host order and host endianness.+getWord32host :: Parser Word32+getWord32host = getPtr  (sizeOf (undefined :: Word32))++word32host :: Word32 -> Parser Word32+word32host w = expect (w ==) getWord32host++-- | /O(1)./ Read a Word64 in native host order and host endianess.+getWord64host   :: Parser Word64+getWord64host = getPtr  (sizeOf (undefined :: Word64))++word64host :: Word64 -> Parser Word64+word64host w = expect (w ==) getWord64host++-- Variable length numbers++getVarLenBe :: Parser Word64+getVarLenBe = f 0+  where+  f :: Word64 -> Parser Word64+  f acc =  do+    w <- getWord8 >>= return . fromIntegral+    if testBit w 7+      then f      $! (shiftL acc 7) .|. (clearBit w 7)+      else return $! (shiftL acc 7) .|. w++varLenBe :: Word64 -> Parser Word64+varLenBe a = expect (a ==) getVarLenBe++getVarLenLe :: Parser Word64+getVarLenLe = do+  w <- getWord8 >>= return . fromIntegral+  if testBit w 7+    then do+      w' <- getVarLenLe+      return $! (clearBit w 7) .|. (shiftL w' 7)+    else return $! w++varLenLe :: Word64 -> Parser Word64+varLenLe a = expect (a ==) getVarLenLe
+ src/Codec/Internal/Arbitrary.hs view
@@ -0,0 +1,52 @@+-----------------------------------------------------------------------------+-- |+-- Module      : Data.Arbitrary+-- Copyright   : George Giorgidze+-- License     : BSD3+--+-- Maintainer  : George Giorgidze <http://cs.nott.ac.uk/~ggg/>+-- Stability   : Experimental+-- Portability : Portable+--+-- Additional instances of the 'Arbitrary' type class defined in 'Test.QuickCheck'.+-- Some portions of code were copied from the test suite of 'binary' package.+--+-----------------------------------------------------------------------------++{-# LANGUAGE FlexibleContexts #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Codec.Internal.Arbitrary (+    arrayGen+  , stringNulGen+  ) where++import qualified Data.ByteString      as B+import qualified Data.ByteString.Lazy as L++import Test.QuickCheck+import Data.Array.IArray+import Data.List+import Data.Word+import Data.Char++instance Arbitrary L.ByteString where+  arbitrary = arbitrary >>= return . L.fromChunks . filter (not. B.null)++instance Arbitrary B.ByteString where+  arbitrary = B.pack `fmap` arbitrary+  +instance (Arbitrary e, Num i, IArray Array e, Ix i) =>  Arbitrary (Array i e) where+  arbitrary = do+    n <- choose (1, 128)+    arrayGen n++arrayGen :: (Arbitrary e, Num i, IArray a e, Ix i) => Word -> Gen (a i e)+arrayGen 0 = error "Array with 0 elements can not be defined"+arrayGen n = do+  es <- vector (fromIntegral n)+  return $! listArray (0 , fromIntegral $ n - 1) es+  +stringNulGen :: Word -> Gen String+stringNulGen n = do+  sequence $ genericReplicate n $ choose (1,255) >>= return . chr
+ src/Codec/Internal/TestSuite.hs view
@@ -0,0 +1,117 @@+module Main (main) where++import qualified Codec.Wav as Wav+import qualified Codec.SoundFont as SF+import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as L++import Test.QuickCheck (quickCheck, (==>))++import Data.Audio+import Codec.Midi+import Codec.ByteString.Parser+import Codec.ByteString.Builder++import Data.Int+import Data.Word+import Data.Bits+import Data.Monoid+import Debug.Trace++roundTrip :: (Eq a, Show a) => (a -> Builder) -> Parser a -> a -> Bool+roundTrip b p a = if Right a == ea'+  then True+  else trace (unlines $ [show ea']) $ False+  where ea' = runParser p bs+        bs = toLazyByteString $ b a++testAudio :: IO ()+testAudio = do+  putStrLn "TESTING Inctances of Audible"+  quickCheck (prop_audible :: Word8 -> Bool)+  quickCheck (prop_audible :: Word16 -> Bool)+  quickCheck (prop_audible :: Word32 -> Bool)+  -- quickCheck (prop_audible :: Word64 -> Bool)+  quickCheck (prop_audible :: Int8 -> Bool)+  quickCheck (prop_audible :: Int16 -> Bool)+  quickCheck (prop_audible :: Int32 -> Bool)+  -- quickCheck (prop_audible :: Int64 -> Bool)++  -- These two tests are commented, because they fail+  -- Reason for that is the fact that Double is not abble to accomodate+  -- 64 bit numbers in full precision+  where+  prop_audible :: (Eq a, Audible a) => a -> Bool+  prop_audible a = (a ==  fromSample s) && (s >= -1.0) && (s <= 1.0)+    where s = toSample a++testMidi :: IO ()+testMidi =  do+  putStrLn "TESTING PARSING AND BUILDING of Midi"++  quickCheck $ roundTrip buildMessage (parseMessage Nothing)+  quickCheck $ roundTrip buildMidi parseMidi+  quickCheck $ \trk -> trk == fromAbsTime (toAbsTime trk :: Track Ticks)+  quickCheck $ \trk td -> trk == fromRealTime td (toRealTime td trk)++  quickCheck $ \m -> (not $ null $ tracks m) ==>+                       let (Midi SingleTrack _ trks) = toSingleTrack m+                       in  length (concat $ tracks m) - length (concat trks) == length (tracks m) - 1++testWav :: IO ()+testWav =  do+  putStrLn "TESTING PARSING AND BUILDING of Wav"+  quickCheck $ roundTrip (Wav.buildWav :: Audio Word8 -> Builder) Wav.parseWav+  quickCheck $ roundTrip (Wav.buildWav :: Audio Int16 -> Builder) Wav.parseWav+  quickCheck $ roundTrip (Wav.buildWav :: Audio Int32 -> Builder) Wav.parseWav++testSoundFont :: IO ()+testSoundFont =  do+  putStrLn "TESTING PARSING AND BUILDING of SoundFont"+  quickCheck $ roundTrip SF.buildSoundFont SF.parseSoundFont++testParserBuilder :: IO ()+testParserBuilder = do+  putStrLn "TESTING PARSING AND BUILDING OF NUMERICAL TYPES"++  quickCheck $ roundTrip putWord8 getWord8+  quickCheck $ roundTrip putWord16be getWord16be+  quickCheck $ roundTrip putWord16le getWord16le+  quickCheck $ \w -> roundTrip putWord24be getWord24be (w .&. 0xFFFFFF)+  quickCheck $ \w -> roundTrip putWord24le getWord24le (w .&. 0xFFFFFF)+  quickCheck $ roundTrip putWord32be getWord32be+  quickCheck $ roundTrip putWord32le getWord32le+  quickCheck $ roundTrip putWord64be getWord64be+  quickCheck $ roundTrip putWord64le getWord64le++  quickCheck $ roundTrip putInt8 getInt8+  quickCheck $ roundTrip putInt16be getInt16be+  quickCheck $ roundTrip putInt16le getInt16le+  quickCheck $ roundTrip putInt32be getInt32be+  quickCheck $ roundTrip putInt32le getInt32le+  quickCheck $ roundTrip putInt64be getInt64be+  quickCheck $ roundTrip putInt64le getInt64le++  quickCheck $ roundTrip putWordHost getWordHost+  quickCheck $ roundTrip putWord16host getWord16host+  quickCheck $ roundTrip putWord32host getWord32host+  quickCheck $ roundTrip putWord64host getWord64host++  quickCheck $ roundTrip putVarLenBe getVarLenBe+  quickCheck $ roundTrip putVarLenLe getVarLenLe++  putStrLn "TESTING PARSING AND BUILDING OF String and ByteString"++  quickCheck $ \s1 s2 -> roundTrip (\s -> putString s `mappend` putString s2) (getString $ length s1) s1+  quickCheck $ \s1 s2 -> roundTrip (\s -> fromByteString s `mappend` fromByteString s2) (getByteString $ B.length s1) s1+  quickCheck $ \s1 s2 -> roundTrip (\s -> fromLazyByteString s `mappend` fromLazyByteString s2) (getLazyByteString $  L.length s1) s1+  quickCheck $ \bs -> roundTrip fromLazyByteString getRemainingLazyByteString bs+++main :: IO ()+main = do+  testAudio+  testParserBuilder+  testMidi+  testWav+  testSoundFont
src/Codec/Midi.hs view
@@ -3,7 +3,7 @@ -- Module      : Codec.Midi -- Copyright   : George Giorgidze -- License     : BSD3--- +-- -- Maintainer  : George Giorgidze <http://cs.nott.ac.uk/~ggg/> -- Stability   : Experimental -- Portability : Portable@@ -12,7 +12,7 @@ -- ----------------------------------------------------------------------------- -module Codec.Midi +module Codec.Midi   (     Midi (..)   , FileType (..)@@ -29,7 +29,7 @@   , Preset   , Bank   , PitchWheel-  , Tempo +  , Tempo      , isNoteOff   , isNoteOn@@ -62,21 +62,22 @@   )    where -import Internal.ByteString.Parser-import Internal.ByteString.Builder-import Internal.Arbitrary ()+import qualified Data.ByteString.Lazy as L +import Test.QuickCheck (Arbitrary, arbitrary, choose, oneof)++import Codec.ByteString.Parser+import Codec.ByteString.Builder+import Codec.Internal.Arbitrary ()+ import Data.Word-import qualified Data.ByteString.Lazy as L import Data.Bits import Data.Maybe import Data.List import Data.Monoid import Control.Applicative import Control.Monad-import Test.QuickCheck - data Midi = Midi {     fileType :: FileType   , timeDiv :: TimeDiv@@ -95,15 +96,13 @@         trks <- arbitrary >>= return . map fAux         return $! Midi ft td trks     where-    fAux = (++ [(0,TrackEnd)]) . map (\(dt,m) -> (abs dt,m)) . removeTrackEnds -  coarbitrary = undefined+    fAux = (++ [(0,TrackEnd)]) . map (\(dt,m) -> (abs dt,m)) . removeTrackEnds  data FileType = SingleTrack | MultiTrack | MultiPattern   deriving (Eq, Show)  instance Arbitrary FileType where   arbitrary = oneof [return SingleTrack , return MultiTrack , return MultiPattern]-  coarbitrary = undefined    type Track a = [(a,Message)] @@ -117,7 +116,6 @@   arbitrary = oneof [       choose (1,2 ^ (15 :: Int) - 1) >>= return . TicksPerBeat     , two (choose (1,127)) >>= \(w1,w2) -> return $! TicksPerSecond w1 w2]-  coarbitrary = undefined  type Ticks = Int -- 0 - (2^28 - 1) type Time = Double@@ -129,7 +127,7 @@ type Preset = Int	-- 0 - 127 type Bank = Int type PitchWheel = Int	-- 0 - (2^14 - 1)-type Tempo = Int -- microseconds per beat  1 - (2^24 - 1) +type Tempo = Int -- microseconds per beat  1 - (2^24 - 1)  data Message = -- Channel Messages@@ -141,7 +139,7 @@   ChannelPressure { channel :: !Channel, pressure :: !Pressure } |   PitchWheel      { channel :: !Channel, pitchWheel :: !PitchWheel } | -- Meta Messages-  SequenceNumber !Int | -- 0 - (2^16 - 1) +  SequenceNumber !Int | -- 0 - (2^16 - 1)   Text !String |   Copyright !String |   TrackName !String |@@ -172,7 +170,7 @@       , two (choose (0,127))  >>= \(w2,w3) -> return $! KeyPressure c w2 w3       , two (choose (0,127))  >>= \(w2,w3) -> return $! ControlChange c w2 w3       , choose (0,127)        >>= \w2      -> return $! ProgramChange c w2-      , choose (0,127)        >>= \w2      -> return $! ChannelPressure c w2 +      , choose (0,127)        >>= \w2      -> return $! ChannelPressure c w2       , do p <- choose (0,2 ^ (14 :: Int) - 1)            return $! PitchWheel c p       -- Meta Messages@@ -207,7 +205,6 @@       , do w <- oneof [return 0xF0, return 0xF7]            bs <- arbitrary            return $! Sysex w bs]-  coarbitrary = undefined  isNoteOff :: Message -> Bool isNoteOff (NoteOff {}) = True@@ -295,19 +292,19 @@ toAbsTime trk = zip ts' ms   where   (ts,ms) = unzip trk-  (_,ts') = mapAccumL (\acc t -> let t' = acc + t in (t',t')) 0 ts +  (_,ts') = mapAccumL (\acc t -> let t' = acc + t in (t',t')) 0 ts    fromAbsTime :: (Num a) => Track a -> Track a-fromAbsTime trk = zip ts' ms +fromAbsTime trk = zip ts' ms   where   (ts,ms) = unzip trk-  (_,ts') = mapAccumL (\acc t -> (t,t - acc)) 0 ts +  (_,ts') = mapAccumL (\acc t -> (t,t - acc)) 0 ts  toRealTime :: TimeDiv -> Track Ticks -> Track Time toRealTime (TicksPerBeat tpb) trk = trk'   where   (_,trk') = mapAccumL f (div 60000000 120) trk -- default tempo 120 beats per minute-  formula dt tempo = +  formula dt tempo =     (fromIntegral dt / fromIntegral tpb) * (fromIntegral tempo) * (1.0E-6)   f :: Tempo -> (Ticks,Message) -> (Tempo, (Time,Message))   f _ (dt, TempoChange tempo) = (tempo, (formula dt tempo, TempoChange tempo))@@ -320,7 +317,7 @@ fromRealTime (TicksPerBeat tpb) trk = trk'   where   (_,trk') = mapAccumL f (div 60000000 120) trk -- default tempo 120 beats per minute-  formula dt tempo = round $ +  formula dt tempo = round $     (dt * fromIntegral tpb) / (fromIntegral tempo * 1.0E-6)   f :: Tempo -> (Time,Message) -> (Tempo, (Ticks,Message))   f _ (dt, TempoChange tempo) = (tempo, (formula dt tempo, TempoChange tempo))@@ -329,7 +326,7 @@   where   f (dt,msg) = (round $ dt * fromIntegral fps * fromIntegral tpf, msg) --- MIDI import +-- MIDI import importFile :: FilePath -> IO (Either String Midi) importFile f = do   bs <- L.readFile f@@ -338,7 +335,7 @@ exportFile :: FilePath -> Midi ->  IO () exportFile f m = do   let bs = toLazyByteString $ buildMidi m-  L.writeFile f bs +  L.writeFile f bs  -- All numeric values are stored in big-endian format @@ -371,7 +368,7 @@     putString "MThd"   , putWord32be 6   , case fileType m of-      SingleTrack -> putWord16be 0 +      SingleTrack -> putWord16be 0       MultiTrack -> putWord16be 1       MultiPattern -> putWord16be 2   , putWord16be (fromIntegral $ length $ tracks m)@@ -385,7 +382,7 @@ parseTrack :: Parser (Track Ticks) parseTrack = do   _ <- string "MTrk"-  _ <- getWord32be -- trackSize +  _ <- getWord32be -- trackSize   track' <- parseMessages Nothing   return track'  @@ -395,12 +392,12 @@   , putWord32be $ fromIntegral $ L.length bs   , fromLazyByteString bs]   where-  f (dt,msg) = (putVarLenBe $ fromIntegral dt) `append` buildMessage msg +  f (dt,msg) = (putVarLenBe $ fromIntegral dt) `append` buildMessage msg   bs = toLazyByteString $ mconcat (map f trk)  parseMessages :: Maybe Message -> Parser (Track Ticks) parseMessages mPreMsg = do-  dt <- getVarLenBe >>= return . fromIntegral +  dt <- getVarLenBe >>= return . fromIntegral   msg <- parseMessage mPreMsg   if (isTrackEnd msg)     then return [(dt,msg)]@@ -539,7 +536,7 @@   case msg of     SequenceNumber i -> mconcat       [putWord8 0x00, putVarLenBe 2, putWord16be $ fromIntegral $ i]-    Text s -> mconcat +    Text s -> mconcat       [putWord8 0x01, putVarLenBe (fromIntegral $ length s), putString s]     Copyright s -> mconcat       [putWord8 0x02, putVarLenBe (fromIntegral $ length s), putString s]@@ -579,7 +576,7 @@         putWord8 (fromIntegral w)       , putVarLenBe (fromIntegral $ L.length bs)       , fromLazyByteString bs]-    _ -> mempty  +    _ -> mempty  parseSequenceNumber :: Parser Message parseSequenceNumber = do@@ -675,7 +672,7 @@ parseSMPTEOffset = do   _ <- word8 0x54   _ <- varLenBe 5-  bs <- getLazyByteString 5 +  bs <- getLazyByteString 5   let [n1,n2,n3,n4,n5] = map fromIntegral (L.unpack bs)   return $! SMPTEOffset n1 n2 n3 n4 n5 @@ -715,3 +712,6 @@           , putVarLenBe $ fromIntegral $ L.length bs           , fromLazyByteString bs] buildSysexMessage _ = mempty++two :: Applicative f => f a -> f (a,a)+two a = pure ((,)) <*> a <*> a
src/Codec/SoundFont.hs view
@@ -37,9 +37,9 @@   , buildPdta   )  where -import Internal.ByteString.Parser-import Internal.ByteString.Builder-import Internal.Arbitrary+import Codec.ByteString.Parser+import Codec.ByteString.Builder+import Codec.Internal.Arbitrary import qualified Data.Audio as Audio  import Data.Word@@ -65,7 +65,6 @@   arbitrary = do     f1 <- arbitrary; f2 <- arbitrary; f3 <- arbitrary;     return $! SoundFont f1 f2 f3-  coarbitrary = undefined  -- instance Show SoundFont where --   show sf = (show $ length $ elems $ sampleData sf) ++ "\n" ++ (show $ length $ show $ articulation sf) ++ "\n"@@ -90,13 +89,15 @@  instance Arbitrary Info where   arbitrary = oneof [-      do (w1,w2) <- two $ choose (minBound :: Word16, maxBound);+      do w1 <- choose (minBound :: Word16, maxBound)+         w2 <- choose (minBound :: Word16, maxBound)          return $ Version (fromIntegral w1) (fromIntegral w2);     , do l <- choose (0,255); s <- genStringNul l; return  $ TargetSoundEngine s     , do l <- choose (0,255); s <- genStringNul l; return  $ BankName s     , do l <- choose (0,255); s <- genStringNul l; return  $ RomName s-    , do (w1,w2) <- two $ choose (minBound :: Word16, maxBound);-         return $ RomVersion (fromIntegral w1) (fromIntegral w2);+    , do w1 <- choose (minBound :: Word16, maxBound)+         w2 <- choose (minBound :: Word16, maxBound)+         return $ RomVersion (fromIntegral w1) (fromIntegral w2)     , do l <- choose (0,255); s <- genStringNul l; return  $ CreationDate s     , do l <- choose (0,255); s <- genStringNul l; return  $ Authors s     , do l <- choose (0,255); s <- genStringNul l; return  $ IntendedProduct s@@ -108,7 +109,6 @@     where     genStringNul :: Int -> Gen String      genStringNul l = sequence $ replicate l $ fmap w2c $ choose (1,255)-  coarbitrary = undefined  data Sdta = Sdta {     smpl :: Audio.SampleData Int16@@ -124,7 +124,6 @@       , do sm24' <- arrayGen sn            return $! Sdta smpl1 (Just sm24')       ]-  coarbitrary = undefined  data Pdta = Pdta {     phdrs :: Array Word Phdr@@ -144,7 +143,6 @@     f5 <- arbitrary; f6 <- arbitrary; f7 <- arbitrary; f8 <- arbitrary;     f9 <- arbitrary;     return $! Pdta f1 f2 f3 f4 f5 f6 f7 f8 f9-  coarbitrary = undefined  data Phdr = Phdr {     presetName :: String@@ -175,7 +173,6 @@       , genre = fromIntegral $ genre'       , morphology = fromIntegral $ morphology'       }-  coarbitrary = undefined  data Bag = Bag {     genNdx :: Word@@ -189,7 +186,6 @@     return $! Bag {         genNdx = fromIntegral genNdx'       , modNdx = fromIntegral modNdx'}-  coarbitrary = undefined  data Mod = Mod {     srcOper :: Word@@ -213,7 +209,6 @@       , amtSrcOper = fromIntegral amtSrcOper'       , transOper = fromIntegral transOper'       }-  coarbitrary = undefined  data Generator =   -- Oscillator@@ -375,7 +370,6 @@       , RootKey w            , ReservedGen i' i]-  coarbitrary = undefined  isSampleIndex :: Generator -> Bool isSampleIndex g = case g of@@ -400,7 +394,6 @@     return $! Inst {         instName = instName'       , instBagNdx = fromIntegral $ instBagNdx'}-  coarbitrary = undefined  data Shdr = Shdr {     sampleName :: String@@ -440,7 +433,6 @@       , sampleLink = fromIntegral sampleLink'       , sampleType = fromIntegral sampleType'       }-  coarbitrary = undefined  ---- SoundFont import 
src/Codec/Wav.hs view
@@ -23,8 +23,8 @@   ) where  import Data.Audio-import Internal.ByteString.Parser-import Internal.ByteString.Builder+import Codec.ByteString.Parser+import Codec.ByteString.Builder  import Data.Word import Data.Int
src/Data/Audio.hs view
@@ -33,9 +33,9 @@ import Data.Array.IO     (MArray, IOUArray, newArray_, writeArray) import Data.Array.Unsafe (unsafeFreeze, unsafeThaw) -import Internal.Arbitrary-import Internal.ByteString.Parser-import Internal.ByteString.Builder+import Codec.Internal.Arbitrary+import Codec.ByteString.Parser+import Codec.ByteString.Builder  import Test.QuickCheck import System.IO.Unsafe@@ -74,11 +74,10 @@ instance (Arbitrary a, IArray UArray a) => Arbitrary (Audio a) where   arbitrary = do     sr <- choose (1, 44100 * 8)-    cn <- choose (1, 64)-    sn <- choose (1, 1024) >>= return . (fromIntegral cn *)+    cn <- choose (1, 8)+    sn <- choose (1, 128) >>= return . (fromIntegral cn *)     sd <- arrayGen sn     return (Audio sr cn sd)-  coarbitrary = undefined  sampleNumber :: (IArray UArray a) => SampleData a -> Int sampleNumber sd = (snd (bounds sd)) + 1@@ -144,4 +143,3 @@  instance Arbitrary SampleMode where   arbitrary = oneof [return NoLoop, return ContLoop, return PressLoop]-  coarbitrary = undefined
− src/Internal/Arbitrary.hs
@@ -1,101 +0,0 @@--------------------------------------------------------------------------------- |--- Module      : Data.Arbitrary--- Copyright   : George Giorgidze--- License     : BSD3------ Maintainer  : George Giorgidze <http://cs.nott.ac.uk/~ggg/>--- Stability   : Experimental--- Portability : Portable------ Additional instances of the 'Arbitrary' type class defined in 'Test.QuickCheck'.--- Some portions of code were copied from the test suite of 'binary' package.-----------------------------------------------------------------------------------{-# LANGUAGE FlexibleContexts #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}--module Internal.Arbitrary (-    arrayGen-  , stringNulGen-  ) where---import Test.QuickCheck--import qualified Data.ByteString as B-import qualified Data.ByteString.Lazy as L--import Data.Word-import Data.Int-import Data.Char--import Data.List-import Data.Array.IArray--import System.Random ()--instance Arbitrary Word8 where-    arbitrary       = choose (minBound, maxBound)-    coarbitrary     = undefined--instance Arbitrary Word16 where-    arbitrary       = choose (minBound, maxBound)-    coarbitrary     = undefined--instance Arbitrary Word32 where-    arbitrary       = choose (minBound, maxBound)-    coarbitrary     = undefined--instance Arbitrary Word64 where-    arbitrary       = choose (minBound, maxBound)-    coarbitrary     = undefined--instance Arbitrary Int8 where-    arbitrary       = choose (minBound, maxBound)-    coarbitrary     = undefined--instance Arbitrary Int16 where-    arbitrary       = choose (minBound, maxBound)-    coarbitrary     = undefined--instance Arbitrary Int32 where-    arbitrary       = choose (minBound, maxBound)-    coarbitrary     = undefined--instance Arbitrary Int64 where-    arbitrary       = choose (minBound, maxBound)-    coarbitrary     = undefined--instance Arbitrary Word where-    arbitrary       = choose (minBound, maxBound)-    coarbitrary     = undefined--instance Arbitrary Char where-    arbitrary = choose (0, 255) >>= return . toEnum-    coarbitrary = undefined--instance Arbitrary L.ByteString where-    arbitrary     = arbitrary >>= return . L.fromChunks . filter (not. B.null)-    coarbitrary s = coarbitrary (L.unpack s)--instance Arbitrary B.ByteString where-  arbitrary = B.pack `fmap` arbitrary-  coarbitrary s = coarbitrary (B.unpack s)-  -instance (Arbitrary e, Num i, IArray Array e, Ix i) =>  Arbitrary (Array i e) where-  arbitrary = do-    n <- choose (1, 128)-    arrayGen n-  coarbitrary = undefined--arrayGen :: (Arbitrary e, Num i, IArray a e, Ix i) => Word -> Gen (a i e)-arrayGen 0 = error "Array with 0 elements can not be defined"-arrayGen n = do-  es <- vector (fromIntegral n)-  return $! listArray (0 , fromIntegral $ n - 1) es-  -stringNulGen :: Word -> Gen String-stringNulGen n = do-  sequence $ genericReplicate n $ choose (1,255) >>= return . chr
− src/Internal/ByteString/Builder.hs
@@ -1,392 +0,0 @@--------------------------------------------------------------------------------- |--- Module      : Data.ByteString.Builder--- Copyright   : Lennart Kolmodin, Ross Paterson, George Giorgidze--- License     : BSD3------ Maintainer  : George Giorgidze <http://cs.nott.ac.uk/~ggg/>--- Stability   : experimental--- Portability : Portable------ Efficient construction of lazy bytestrings.----------------------------------------------------------------------------------module Internal.ByteString.Builder (--    -- * The Builder type-      Builder-    , toLazyByteString--    -- * Constructing Builders-    , empty-    , singleton-    , putWord8-    , putInt8-    , append-    , fromByteString        -- :: S.ByteString -> Builder-    , fromLazyByteString    -- :: L.ByteString -> Builder-    , putString--    -- * Flushing the buffer state-    , flush--    -- * Derived Builders-    -- ** Big-endian writes-    , putWord16be           -- :: Word16 -> Builder-    , putWord24be           -- :: Word32 -> Builder-    , putWord32be           -- :: Word32 -> Builder-    , putWord64be           -- :: Word64 -> Builder--    , putInt16be           -- :: Int16 -> Builder-    , putInt32be           -- :: Int32 -> Builder-    , putInt64be           -- :: Int64 -> Builder--    -- ** Little-endian writes-    , putWord16le           -- :: Word16 -> Builder-    , putWord24le           -- :: Word32 -> Builder-    , putWord32le           -- :: Word32 -> Builder-    , putWord64le           -- :: Word64 -> Builder--    , putInt16le           -- :: Int16 -> Builder-    , putInt32le           -- :: Int32 -> Builder-    , putInt64le           -- :: Int64 -> Builder--    -- ** Host-endian, unaligned writes-    , putWordHost           -- :: Word -> Builder-    , putWord16host         -- :: Word16 -> Builder-    , putWord32host         -- :: Word32 -> Builder-    , putWord64host         -- :: Word64 -> Builder-    -- Variable length numbers-    , putVarLenBe-    , putVarLenLe--  ) where---import qualified Data.ByteString.Internal as S-import qualified Data.ByteString          as S-import qualified Data.ByteString.Lazy     as L--import Foreign.Storable         (Storable, poke, sizeOf)-import Foreign.Ptr              (Ptr, plusPtr)-import Foreign.ForeignPtr       (ForeignPtr, withForeignPtr)-import System.IO.Unsafe         (unsafePerformIO)-import Data.ByteString.Internal (inlinePerformIO,c2w)--import Data.Bits-import Data.Word-import Data.Int-import Data.Monoid------------------------------------------------------------------------------ | A 'Builder' is an efficient way to build lazy 'L.ByteString's.--- There are several functions for constructing 'Builder's, but only one--- to inspect them: to extract any data, you have to turn them into lazy--- 'L.ByteString's using 'toLazyByteString'.------ Internally, a 'Builder' constructs a lazy 'L.Bytestring' by filling byte--- arrays piece by piece.  As each buffer is filled, it is \'popped\'--- off, to become a new chunk of the resulting lazy 'L.ByteString'.--- All this is hidden from the user of the 'Builder'.--newtype Builder = Builder {-        -- Invariant (from Data.ByteString.Lazy):-        --      The lists include no null ByteStrings.-        runBuilder :: (Buffer -> [S.ByteString]) -> Buffer -> [S.ByteString]-    }--instance Monoid Builder where-    mempty  = empty-    mappend = append------------------------------------------------------------------------------ | /O(1)./ The empty Builder, satisfying------  * @'toLazyByteString' 'empty' = 'L.empty'@----empty :: Builder-empty = Builder id---- | /O(1)./ A Builder taking a single byte, satisfying------  * @'toLazyByteString' ('singleton' b) = 'L.singleton' b@----singleton :: Word8 -> Builder-singleton = writeN 1 . flip poke--putWord8 :: Word8 -> Builder-putWord8 = singleton----------------------------------------------------------------------------- | /O(1)./ The concatenation of two Builders, an associative operation--- with identity 'empty', satisfying------  * @'toLazyByteString' ('append' x y) = 'L.append' ('toLazyByteString' x) ('toLazyByteString' y)@----append :: Builder -> Builder -> Builder-append (Builder f) (Builder g) = Builder (f . g)---- | /O(1)./ A Builder taking a 'S.ByteString', satisfying------  * @'toLazyByteString' ('fromByteString' bs) = 'L.fromChunks' [bs]@----fromByteString :: S.ByteString -> Builder-fromByteString bs-  | S.null bs = empty-  | otherwise = flush `append` mapBuilder (bs :)---- | /O(1)./ A Builder taking a lazy 'L.ByteString', satisfying------  * @'toLazyByteString' ('fromLazyByteString' bs) = bs@----fromLazyByteString :: L.ByteString -> Builder-fromLazyByteString bss = flush `append` mapBuilder (L.toChunks bss ++)--putString :: String -> Builder-putString = fromLazyByteString . L.pack . map c2w------------------------------------------------------------------------------ Our internal buffer type-data Buffer = Buffer {-# UNPACK #-} !(ForeignPtr Word8)-                     {-# UNPACK #-} !Int                -- offset-                     {-# UNPACK #-} !Int                -- used bytes-                     {-# UNPACK #-} !Int                -- length left------------------------------------------------------------------------------ | /O(n)./ Extract a lazy 'L.ByteString' from a 'Builder'.--- The construction work takes place if and when the relevant part of--- the lazy 'L.ByteString' is demanded.----toLazyByteString :: Builder -> L.ByteString-toLazyByteString m = L.fromChunks $ unsafePerformIO $ do-    buf <- newBuffer defaultSize-    return (runBuilder (m `append` flush) (const []) buf)---- | /O(1)./ Pop the 'S.ByteString' we have constructed so far, if any,--- yielding a new chunk in the result lazy 'L.ByteString'.-flush :: Builder-flush = Builder $ \ k buf@(Buffer p o u l) ->-    if u == 0-      then k buf-      else S.PS p o u : k (Buffer p (o+u) 0 l)--------------------------------------------------------------------------------- copied from Data.ByteString.Lazy----defaultSize :: Int-defaultSize = 32 * k - overhead-    where k = 1024-          overhead = 2 * sizeOf (undefined :: Int)------------------------------------------------------------------------------ | Sequence an IO operation on the buffer-unsafeLiftIO :: (Buffer -> IO Buffer) -> Builder-unsafeLiftIO f =  Builder $ \ k buf -> inlinePerformIO $ do-    buf' <- f buf-    return (k buf')---- | Get the size of the buffer-withSize :: (Int -> Builder) -> Builder-withSize f = Builder $ \ k buf@(Buffer _ _ _ l) ->-    runBuilder (f l) k buf---- | Map the resulting list of bytestrings.-mapBuilder :: ([S.ByteString] -> [S.ByteString]) -> Builder-mapBuilder f = Builder (f .)------------------------------------------------------------------------------ | Ensure that there are at least @n@ many bytes available.-ensureFree :: Int -> Builder-ensureFree n = n `seq` withSize $ \ l ->-    if n <= l then empty else-        flush `append` unsafeLiftIO (const (newBuffer (max n defaultSize)))---- | Ensure that @n@ many bytes are available, and then use @f@ to write some--- bytes into the memory.-writeN :: Int -> (Ptr Word8 -> IO ()) -> Builder-writeN n f = ensureFree n `append` unsafeLiftIO (writeNBuffer n f)--writeNBuffer :: Int -> (Ptr Word8 -> IO ()) -> Buffer -> IO Buffer-writeNBuffer n f (Buffer fp o u l) = do-    withForeignPtr fp (\p -> f (p `plusPtr` (o+u)))-    return (Buffer fp o (u+n) (l-n))--newBuffer :: Int -> IO Buffer-newBuffer size = do-    fp <- S.mallocByteString size-    return $! Buffer fp 0 0 size----------------------------------------------------------------------------- Aligned, host order writes of storable values---- | Ensure that @n@ many bytes are available, and then use @f@ to write some--- storable values into the memory.-writeNbytes :: Storable a => Int -> (Ptr a -> IO ()) -> Builder-writeNbytes n f = ensureFree n `append` unsafeLiftIO (writeNBufferBytes n f)--writeNBufferBytes :: Storable a => Int -> (Ptr a -> IO ()) -> Buffer -> IO Buffer-writeNBufferBytes n f (Buffer fp o u l) = do-    withForeignPtr fp (\p -> f (p `plusPtr` (o+u)))-    return (Buffer fp o (u+n) (l-n))--------------------------------------------------------------------------------- We rely on the fromIntegral to do the right masking for us.--- The inlining here is critical, and can be worth 4x performance------- | Write a Word16 in big endian format-putWord16be :: Word16 -> Builder-putWord16be w = writeN 2 $ \p -> do-    poke p               (fromIntegral (shiftR w 8) :: Word8)-    poke (p `plusPtr` 1) (fromIntegral (w)              :: Word8)---- | Write a Word16 in little endian format-putWord16le :: Word16 -> Builder-putWord16le w = writeN 2 $ \p -> do-    poke p               (fromIntegral (w)              :: Word8)-    poke (p `plusPtr` 1) (fromIntegral (shiftR w 8) :: Word8)---- putWord16le w16 = writeN 2 (\p -> poke (castPtr p) w16)---- | Write a 24 bit number in big endian format represented as Word32-putWord24be :: Word32 -> Builder-putWord24be w = writeN 3 $ \p -> do-    poke p               (fromIntegral (shiftR w 16) :: Word8)-    poke (p `plusPtr` 1) (fromIntegral (shiftR w 8) :: Word8)-    poke (p `plusPtr` 2) (fromIntegral (w) :: Word8)---- | Write a 24 bit number in little endian format represented as Word32-putWord24le :: Word32 -> Builder-putWord24le w = writeN 3 $ \p -> do-    poke p               (fromIntegral (w)           :: Word8)-    poke (p `plusPtr` 1) (fromIntegral (shiftR w  8) :: Word8)-    poke (p `plusPtr` 2) (fromIntegral (shiftR w 16) :: Word8)---- | Write a Word32 in big endian format-putWord32be :: Word32 -> Builder-putWord32be w = writeN 4 $ \p -> do-    poke p               (fromIntegral (shiftR w 24) :: Word8)-    poke (p `plusPtr` 1) (fromIntegral (shiftR w 16) :: Word8)-    poke (p `plusPtr` 2) (fromIntegral (shiftR w  8) :: Word8)-    poke (p `plusPtr` 3) (fromIntegral (w)           :: Word8)------- a data type to tag Put/Check. writes construct these which are then--- inlined and flattened. matching Checks will be more robust with rules.------- | Write a Word32 in little endian format-putWord32le :: Word32 -> Builder-putWord32le w = writeN 4 $ \p -> do-    poke p               (fromIntegral (w)               :: Word8)-    poke (p `plusPtr` 1) (fromIntegral (shiftR w  8) :: Word8)-    poke (p `plusPtr` 2) (fromIntegral (shiftR w 16) :: Word8)-    poke (p `plusPtr` 3) (fromIntegral (shiftR w 24) :: Word8)---- on a little endian machine:--- putWord32le w32 = writeN 4 (\p -> poke (castPtr p) w32)---- | Write a Word64 in big endian format-putWord64be :: Word64 -> Builder-putWord64be w = writeN 8 $ \p -> do-    poke p               (fromIntegral (shiftR w 56) :: Word8)-    poke (p `plusPtr` 1) (fromIntegral (shiftR w 48) :: Word8)-    poke (p `plusPtr` 2) (fromIntegral (shiftR w 40) :: Word8)-    poke (p `plusPtr` 3) (fromIntegral (shiftR w 32) :: Word8)-    poke (p `plusPtr` 4) (fromIntegral (shiftR w 24) :: Word8)-    poke (p `plusPtr` 5) (fromIntegral (shiftR w 16) :: Word8)-    poke (p `plusPtr` 6) (fromIntegral (shiftR w  8) :: Word8)-    poke (p `plusPtr` 7) (fromIntegral (w)               :: Word8)---- | Write a Word64 in little endian format-putWord64le :: Word64 -> Builder-putWord64le w = writeN 8 $ \p -> do-    poke p               (fromIntegral (w)               :: Word8)-    poke (p `plusPtr` 1) (fromIntegral (shiftR w  8) :: Word8)-    poke (p `plusPtr` 2) (fromIntegral (shiftR w 16) :: Word8)-    poke (p `plusPtr` 3) (fromIntegral (shiftR w 24) :: Word8)-    poke (p `plusPtr` 4) (fromIntegral (shiftR w 32) :: Word8)-    poke (p `plusPtr` 5) (fromIntegral (shiftR w 40) :: Word8)-    poke (p `plusPtr` 6) (fromIntegral (shiftR w 48) :: Word8)-    poke (p `plusPtr` 7) (fromIntegral (shiftR w 56) :: Word8)---- on a little endian machine:--- putWord64le w64 = writeN 8 (\p -> poke (castPtr p) w64)---------------------------------------------------------------------------putInt8 :: Int8 -> Builder-putInt8 = putWord8 . fromIntegral--putInt16le :: Int16 -> Builder-putInt16le = putWord16le . fromIntegral--putInt16be :: Int16 -> Builder-putInt16be = putWord16be . fromIntegral--putInt32le :: Int32 -> Builder-putInt32le = putWord32le . fromIntegral--putInt32be :: Int32 -> Builder-putInt32be = putWord32be . fromIntegral--putInt64le :: Int64 -> Builder-putInt64le = putWord64le . fromIntegral--putInt64be :: Int64 -> Builder-putInt64be = putWord64be . fromIntegral----------------------------------------------------------------------------- Unaligned, word size ops---- | /O(1)./ A Builder taking a single native machine word. The word is--- written in host order, host endian form, for the machine you're on.--- On a 64 bit machine the Word is an 8 byte value, on a 32 bit machine,--- 4 bytes. Values written this way are not portable to--- different endian or word sized machines, without conversion.----putWordHost :: Word -> Builder-putWordHost w = writeNbytes (sizeOf (undefined :: Word)) (\p -> poke p w)---- | Write a Word16 in native host order and host endianness.--- 2 bytes will be written, unaligned.-putWord16host :: Word16 -> Builder-putWord16host w16 = writeNbytes (sizeOf (undefined :: Word16)) (\p -> poke p w16)---- | Write a Word32 in native host order and host endianness.--- 4 bytes will be written, unaligned.-putWord32host :: Word32 -> Builder-putWord32host w32 = writeNbytes (sizeOf (undefined :: Word32)) (\p -> poke p w32)---- | Write a Word64 in native host order.--- On a 32 bit machine we write two host order Word32s, in big endian form.--- 8 bytes will be written, unaligned.-putWord64host :: Word64 -> Builder-putWord64host w = writeNbytes (sizeOf (undefined :: Word64)) (\p -> poke p w)----------------------------------------------------------------------------putVarLenBe :: Word64 -> Builder-putVarLenBe w = varLenAux2 $ reverse $ varLenAux1 w-  -putVarLenLe :: Word64 -> Builder-putVarLenLe w = varLenAux2 $ varLenAux1 w-  -varLenAux1 :: Word64 -> [Word8]-varLenAux1 0 = []-varLenAux1 w = (fromIntegral $ w .&. 0x7F) : (varLenAux1 $ shiftR w 7)--varLenAux2 :: [Word8] -> Builder-varLenAux2  [] = putWord8 0-varLenAux2  [w] = putWord8 w-varLenAux2 (w : ws) = putWord8 (setBit w 7) `append` varLenAux2 ws
− src/Internal/ByteString/Parser.hs
@@ -1,593 +0,0 @@--------------------------------------------------------------------------------- |--- Module      : Data.ByteString.Parser--- Copyright   : Lennart Kolmodin, George Giorgidze--- License     : BSD3------ Maintainer  : George Giorgidze <http://cs.nott.ac.uk/~ggg/>--- Stability   : experimental--- Portability : Portable------ A monad for efficiently building structures from--- encoded lazy ByteStrings.-----------------------------------------------------------------------------------module Internal.ByteString.Parser (--    -- * The Parser type-      Parser-    , runParser-    , runParserState--    -- * Parsing-    , choice-    , expect-    , skip-    , lookAhead-    , lookAheadM-    , lookAheadE--    -- * Utility-    , bytesRead-    , getBytes-    , remaining-    , isEmpty--    -- * Parsing particular types-    , satisfy-    , getString-    , getStringNul-    , string-    , getWord8-    , getInt8-    , word8-    , int8--    -- ** ByteStrings-    , getByteString-    , getLazyByteString-    , getLazyByteStringNul-    , getRemainingLazyByteString--    -- ** Big-endian reads-    , getWord16be-    , word16be-    , getWord24be-    , word24be-    , getWord32be-    , word32be-    , getWord64be-    , word64be--    , getInt16be-    , int16be-    , getInt32be-    , int32be-    , getInt64be-    , int64be--    -- ** Little-endian reads-    , getWord16le-    , word16le-    , getWord24le-    , word24le-    , getWord32le-    , word32le-    , getWord64le-    , word64le--    , getInt16le-    , int16le-    , getInt32le-    , int32le-    , getInt64le-    , int64le--    -- ** Host-endian, unaligned reads-    , getWordHost-    , wordHost-    , getWord16host-    , word16host-    , getWord32host-    , word32host-    , getWord64host-    , word64host--    -- Variable length reads-    , getVarLenBe-    , varLenBe-    , getVarLenLe-    , varLenLe-  ) where--import qualified Data.ByteString               as B-import qualified Data.ByteString.Lazy          as L-import qualified Data.ByteString.Internal      as B-import qualified Data.ByteString.Lazy.Internal as L--import Foreign.Storable        (Storable, peek, sizeOf)-import Foreign.Ptr             (plusPtr, castPtr)-import Foreign.ForeignPtr      (withForeignPtr)-import Control.Monad.ST        (runST)-import Control.Monad.ST.Unsafe (unsafeInterleaveST)--import Control.Monad-import Control.Applicative-import Data.STRef-import Data.Word-import Data.Int-import Data.Bits-import Data.Maybe---- | The parse state-data S = S {-# UNPACK #-} !B.ByteString  -- current chunk-           L.ByteString                  -- the rest of the input-           {-# UNPACK #-} !Int64         -- bytes read---- | The Get monad is just a State monad carrying around the input ByteString-newtype Parser a = Parser { unParser :: S -> Either String (a, S) }--instance Functor Parser where-    fmap f m = Parser $ \s -> case unParser m s of-      Left e -> Left e-      Right (a, s') -> Right (f a, s')-    -instance Monad Parser where-    return a  = Parser (\s -> Right (a, s))-    m >>= k   = Parser $ \s -> case (unParser m) s of-      Left e -> Left e-      Right (a, s') -> (unParser (k a)) s'-    fail  err  = Parser $ \(S _ _ bytes) ->-        Left (err ++ ". Failed reading at byte position " ++ show bytes)-instance MonadPlus Parser where-  mzero = Parser $ \_ -> Left []-  mplus p1 p2 = Parser $ \s -> case (unParser p1 s) of-    Left e1 -> case (unParser p2 s) of-      Left e2 -> Left (e1 ++ "\n" ++ e2)-      ok -> ok-    ok -> ok--instance Applicative Parser where-  pure  = return-  (<*>) = ap-  -instance Alternative Parser where-  empty = mzero-  (<|>) = mplus----------------------------------------------------------------------------get :: Parser S-get   = Parser $ \s -> Right (s, s)--put :: S -> Parser ()-put s = Parser $ \_ -> Right ((), s)----------------------------------------------------------------------------initState :: L.ByteString -> S-initState xs = mkState xs 0--mkState :: L.ByteString -> Int64 -> S-mkState l = case l of-    L.Empty      -> S B.empty L.empty-    L.Chunk x xs -> S x xs---- | Run the Get monad applies a 'get'-based parser on the input ByteString-runParser :: Parser a -> L.ByteString -> Either String a-runParser m str = case unParser m (initState str) of-  Left e -> Left e-  Right (a, _) -> Right a---- | Run the Get monad applies a 'get'-based parser on the input--- ByteString. Additional to the result of get it returns the number of--- consumed bytes and the rest of the input.-runParserState :: Parser a -> L.ByteString -> Int64 -> Either String (a, L.ByteString, Int64)-runParserState m str off =-    case unParser m (mkState str off) of-      Left e -> Left e-      Right (a, ~(S s ss newOff)) -> Right (a, s `bsJoin` ss, newOff)----------------------------------------------------------------------------choice :: [Parser a] -> Parser a-choice = foldl (<|>) mzero---- | Skip ahead @n@ bytes. Fails if fewer than @n@ bytes are available.-skip :: Word64 -> Parser ()-skip n = readN (fromIntegral n) (const ())---- | Run @ga@, but return without consuming its input.--- Fails if @ga@ fails.-lookAhead :: Parser a -> Parser a-lookAhead ga = do-    s <- get-    a <- ga-    put s-    return a---- | Like 'lookAhead', but consume the input if @gma@ returns 'Just _'.--- Fails if @gma@ fails.-lookAheadM :: Parser (Maybe a) -> Parser (Maybe a)-lookAheadM gma = do-    s <- get-    ma <- gma-    when (isNothing ma) $ put s-    return ma---- | Like 'lookAhead', but consume the input if @gea@ returns 'Right _'.--- Fails if @gea@ fails.-lookAheadE :: Parser (Either a b) -> Parser (Either a b)-lookAheadE gea = do-    s <- get-    ea <- gea-    case ea of-        Left _ -> put s-        _      -> return ()-    return ea--expect :: (Show a, Eq a) => (a -> Bool) -> Parser a -> Parser a-expect f p = do-  v <- p-  when (not $ f v) $ fail $ show v ++ " was not expected."-  return v--getString :: Int -> Parser String-getString l = do-  bs <- getLazyByteString (fromIntegral l)-  return $! map B.w2c (L.unpack bs)--getStringNul :: Parser String-getStringNul = do-  bs <- getLazyByteStringNul-  return $! map B.w2c (L.unpack bs)--string :: String -> Parser String-string s = expect (s ==) (getString $ length s)---- Utility---- | Get the total number of bytes read to this point.-bytesRead :: Parser Int64-bytesRead = do-    S _ _ b <- get-    return b---- | Get the number of remaining unparsed bytes.--- Useful for checking whether all input has been consumed.--- Note that this forces the rest of the input.-remaining :: Parser Int64-remaining = do-    S s ss _ <- get-    return $! (fromIntegral (B.length s) + L.length ss)---- | Test whether all input has been consumed,--- i.e. there are no remaining unparsed bytes.-isEmpty :: Parser Bool-isEmpty = do-    S s ss _ <- get-    return $! (B.null s && L.null ss)----------------------------------------------------------------------------- Utility with ByteStrings---- | An efficient 'get' method for strict ByteStrings. Fails if fewer--- than @n@ bytes are left in the input.-getByteString :: Int -> Parser B.ByteString-getByteString n = readN n id---- | An efficient 'get' method for lazy ByteStrings. Does not fail if fewer than--- @n@ bytes are left in the input.-getLazyByteString :: Int64 -> Parser L.ByteString-getLazyByteString n = do-    S s ss bytes <- get-    let big = s `bsJoin` ss-    case splitAtST n big of-      (consume, rest) -> do put $ mkState rest (bytes + n)-                            return consume---- | Get a lazy ByteString that is terminated with a NUL byte. Fails--- if it reaches the end of input without hitting a NUL.-getLazyByteStringNul :: Parser L.ByteString-getLazyByteStringNul = do-    S s ss bytes <- get-    let big = s `bsJoin` ss-        (consume, t) = L.break (== 0) big-        (h, rest) = L.splitAt 1 t-    when (L.null h) $ fail "too few bytes"-    put $ mkState rest (bytes + L.length consume + 1)-    return consume---- | Get the remaining bytes as a lazy ByteString-getRemainingLazyByteString :: Parser L.ByteString-getRemainingLazyByteString = do-    S s ss _ <- get-    return $! (s `bsJoin` ss)----------------------------------------------------------------------------- Helpers---- | Pull @n@ bytes from the input, as a strict ByteString.-getBytes :: Int -> Parser B.ByteString-getBytes n = do-    S s ss bytes <- get-    if n <= B.length s-        then do let (consume,rest) = B.splitAt n s-                put $! S rest ss (bytes + fromIntegral n)-                return $! consume-        else-              case L.splitAt (fromIntegral n) (s `bsJoin` ss) of-                (consuming, rest) ->-                    do let now = B.concat . L.toChunks $ consuming-                       put $! mkState rest (bytes + fromIntegral n)-                       -- forces the next chunk before this one is returned-                       when (B.length now < n) $ fail "too few bytes"-                       return now--bsJoin :: B.ByteString -> L.ByteString -> L.ByteString-bsJoin bb lb-    | B.null bb = lb-    | otherwise = L.Chunk bb lb---- | Split a ByteString. If the first result is consumed before the ----- second, this runs in constant heap space.------ You must force the returned tuple for that to work, e.g.------ > case splitAtST n xs of--- >    (ys,zs) -> consume ys ... consume zs----splitAtST :: Int64 -> L.ByteString -> (L.ByteString, L.ByteString)-splitAtST i ps | i <= 0 = (L.empty, ps)-splitAtST i ps          = runST (-     do r  <- newSTRef undefined-        xs <- first r i ps-        ys <- unsafeInterleaveST (readSTRef r)-        return (xs, ys))--  where-        first r 0 xs@(L.Chunk _ _) = writeSTRef r xs    >> return L.Empty-        first r _ L.Empty          = writeSTRef r L.Empty >> return L.Empty--        first r n (L.Chunk x xs)-          | n < l     = do writeSTRef r (L.Chunk (B.drop (fromIntegral n) x) xs)-                           return $! L.Chunk (B.take (fromIntegral n) x) L.Empty-          | otherwise = do writeSTRef r (L.drop (n - l) xs)-                           liftM (L.Chunk x) $ unsafeInterleaveST (first r (n - l) xs)--         where l = fromIntegral (B.length x)---- Pull n bytes from the input, and apply a parser to those bytes,--- yielding a value. If less than @n@ bytes are available, fail with an--- error. This wraps @getBytes@.-readN :: Int -> (B.ByteString -> a) -> Parser a-readN n f = fmap f $ getBytes n------------------------------------------------------------------------------ Primtives---- helper, get a raw Ptr onto a strict ByteString copied out of the--- underlying lazy byteString. So many indirections from the raw parser--- state that my head hurts...--getPtr :: Storable a => Int -> Parser a-getPtr n = do-    (fp,o,_) <- readN n B.toForeignPtr-    return . B.inlinePerformIO $ withForeignPtr fp $ \p -> peek (castPtr $ p `plusPtr` o)----------------------------------------------------------------------------satisfy :: (Word8 -> Bool) -> Parser Word8-satisfy f = do-  w <- getWord8-  guard (f w)-  return w---- | Read a Word8 from the monad state-getWord8 :: Parser Word8-getWord8 = getPtr (sizeOf (undefined :: Word8))--word8 :: Word8 -> Parser Word8-word8 w = expect (w ==) getWord8---- | Read a Word16 in big endian format-getWord16be :: Parser Word16-getWord16be = do-    s <- readN 2 id-    return $! (fromIntegral (s `B.index` 0) `shiftL` 8) .|.-              (fromIntegral (s `B.index` 1))--word16be :: Word16 -> Parser Word16-word16be w = expect (w ==) getWord16be---- | Read a Word16 in little endian format-getWord16le :: Parser Word16-getWord16le = do-    s <- readN 2 id-    return $! (fromIntegral (s `B.index` 1) `shiftL` 8) .|.-              (fromIntegral (s `B.index` 0) )--word16le :: Word16 -> Parser Word16-word16le w = expect (w ==) getWord16le---- | Read a 24 bit word into Word32 in big endian format-getWord24be :: Parser Word32-getWord24be = do-    s <- readN 3 id-    return $! (fromIntegral (s `B.index` 0) `shiftL` 16) .|.-              (fromIntegral (s `B.index` 1) `shiftL`  8) .|.-              (fromIntegral (s `B.index` 2) )--word24be :: Word32 -> Parser Word32-word24be w = expect (w ==) getWord24be--getWord24le :: Parser Word32-getWord24le = do-    s <- readN 3 id-    return $! (fromIntegral (s `B.index` 2) `shiftL` 16) .|.-              (fromIntegral (s `B.index` 1) `shiftL`  8) .|.-              (fromIntegral (s `B.index` 0) )--word24le :: Word32 -> Parser Word32-word24le w = expect (w ==) getWord24le---- | Read a Word32 in big endian format-getWord32be :: Parser Word32-getWord32be = do-    s <- readN 4 id-    return $! (fromIntegral (s `B.index` 0) `shiftL` 24) .|.-              (fromIntegral (s `B.index` 1) `shiftL` 16) .|.-              (fromIntegral (s `B.index` 2) `shiftL`  8) .|.-              (fromIntegral (s `B.index` 3) )--word32be :: Word32 -> Parser Word32-word32be w = expect (w ==) getWord32be---- | Read a Word32 in little endian format-getWord32le :: Parser Word32-getWord32le = do-    s <- readN 4 id-    return $! (fromIntegral (s `B.index` 3) `shiftL` 24) .|.-              (fromIntegral (s `B.index` 2) `shiftL` 16) .|.-              (fromIntegral (s `B.index` 1) `shiftL`  8) .|.-              (fromIntegral (s `B.index` 0) )--word32le :: Word32 -> Parser Word32-word32le w = expect (w ==) getWord32le----- | Read a Word64 in big endian format-getWord64be :: Parser Word64-getWord64be = do-    s <- readN 8 id-    return $! (fromIntegral (s `B.index` 0) `shiftL` 56) .|.-              (fromIntegral (s `B.index` 1) `shiftL` 48) .|.-              (fromIntegral (s `B.index` 2) `shiftL` 40) .|.-              (fromIntegral (s `B.index` 3) `shiftL` 32) .|.-              (fromIntegral (s `B.index` 4) `shiftL` 24) .|.-              (fromIntegral (s `B.index` 5) `shiftL` 16) .|.-              (fromIntegral (s `B.index` 6) `shiftL`  8) .|.-              (fromIntegral (s `B.index` 7) )--word64be :: Word64 -> Parser Word64-word64be w = expect (w ==) getWord64be---- | Read a Word64 in little endian format-getWord64le :: Parser Word64-getWord64le = do-    s <- readN 8 id-    return $! (fromIntegral (s `B.index` 7) `shiftL` 56) .|.-              (fromIntegral (s `B.index` 6) `shiftL` 48) .|.-              (fromIntegral (s `B.index` 5) `shiftL` 40) .|.-              (fromIntegral (s `B.index` 4) `shiftL` 32) .|.-              (fromIntegral (s `B.index` 3) `shiftL` 24) .|.-              (fromIntegral (s `B.index` 2) `shiftL` 16) .|.-              (fromIntegral (s `B.index` 1) `shiftL`  8) .|.-              (fromIntegral (s `B.index` 0) )--word64le :: Word64 -> Parser Word64-word64le w = expect (w ==) getWord64le--------------------------------------------------------------------------getInt8 :: Parser Int8-getInt8 = getWord8 >>= return . fromIntegral--int8 :: Int8 -> Parser Int8-int8 i = expect (i ==) getInt8--getInt16le :: Parser Int16-getInt16le = getWord16le >>= return . fromIntegral--int16le :: Int16 -> Parser Int16-int16le i = expect (i ==) getInt16le--getInt16be :: Parser Int16-getInt16be = getWord16be >>= return . fromIntegral--int16be :: Int16 -> Parser Int16-int16be i = expect (i ==) getInt16be--getInt32le :: Parser Int32-getInt32le = getWord32le >>= return . fromIntegral--int32le :: Int32 -> Parser Int32-int32le i = expect (i ==) getInt32le--getInt32be :: Parser Int32-getInt32be = getWord32be >>= return . fromIntegral--int32be :: Int32 -> Parser Int32-int32be i = expect (i ==) getInt32be--getInt64le :: Parser Int64-getInt64le = getWord64le >>= return . fromIntegral--int64le :: Int64 -> Parser Int64-int64le i = expect (i ==) getInt64le--getInt64be :: Parser Int64-getInt64be = getWord64be >>= return . fromIntegral--int64be :: Int64 -> Parser Int64-int64be i = expect (i ==) getInt64be----------------------------------------------------------------------------- Host-endian reads---- | /O(1)./ Read a single native machine word. The word is read in--- host order, host endian form, for the machine you're on. On a 64 bit--- machine the Word is an 8 byte value, on a 32 bit machine, 4 bytes.-getWordHost :: Parser Word-getWordHost = getPtr (sizeOf (undefined :: Word))--wordHost :: Word -> Parser Word-wordHost w = expect (w ==) getWordHost---- | /O(1)./ Read a 2 byte Word16 in native host order and host endianness.-getWord16host :: Parser Word16-getWord16host = getPtr (sizeOf (undefined :: Word16))--word16host :: Word16 -> Parser Word16-word16host w = expect (w ==) getWord16host---- | /O(1)./ Read a Word32 in native host order and host endianness.-getWord32host :: Parser Word32-getWord32host = getPtr  (sizeOf (undefined :: Word32))--word32host :: Word32 -> Parser Word32-word32host w = expect (w ==) getWord32host---- | /O(1)./ Read a Word64 in native host order and host endianess.-getWord64host   :: Parser Word64-getWord64host = getPtr  (sizeOf (undefined :: Word64))--word64host :: Word64 -> Parser Word64-word64host w = expect (w ==) getWord64host---- Variable length numbers--getVarLenBe :: Parser Word64-getVarLenBe = f 0-  where-  f :: Word64 -> Parser Word64-  f acc =  do-    w <- getWord8 >>= return . fromIntegral-    if testBit w 7-      then f      $! (shiftL acc 7) .|. (clearBit w 7)-      else return $! (shiftL acc 7) .|. w--varLenBe :: Word64 -> Parser Word64-varLenBe a = expect (a ==) getVarLenBe--getVarLenLe :: Parser Word64-getVarLenLe = do-  w <- getWord8 >>= return . fromIntegral-  if testBit w 7-    then do-      w' <- getVarLenLe-      return $! (clearBit w 7) .|. (shiftL w' 7)-    else return $! w--varLenLe :: Word64 -> Parser Word64-varLenLe a = expect (a ==) getVarLenLe
− src/Internal/TestSuite.hs
@@ -1,118 +0,0 @@-module Main (main) where--import Codec.Midi-import qualified Codec.Wav as Wav-import qualified Codec.SoundFont as SF-import Data.Audio--import Internal.ByteString.Parser-import Internal.ByteString.Builder--import Test.QuickCheck-import Data.Int-import Data.Word-import Data.Bits--import qualified Data.ByteString as B-import qualified Data.ByteString.Lazy as L--import Data.Monoid-import Debug.Trace--roundTrip :: (Eq a, Show a) => (a -> Builder) -> Parser a -> a -> Bool-roundTrip b p a = if Right a == ea'-  then True-  else trace (unlines $ [show ea']) $ False-  where ea' = runParser p bs-        bs = toLazyByteString $ b a--testAudio :: IO ()-testAudio = do-  putStrLn "TESTING Inctances of Audible"-  test (prop_audible :: Word8 -> Bool)-  test (prop_audible :: Word16 -> Bool)-  test (prop_audible :: Word32 -> Bool)-  -- test (prop_audible :: Word64 -> Bool)-  test (prop_audible :: Int8 -> Bool)-  test (prop_audible :: Int16 -> Bool)-  test (prop_audible :: Int32 -> Bool)-  -- test (prop_audible :: Int64 -> Bool)--  -- These two tests are commented, because they fail-  -- Reason for that is the fact that Double is not abble to accomodate-  -- 64 bit numbers in full precision-  where-  prop_audible :: (Eq a, Audible a) => a -> Bool-  prop_audible a = (a ==  fromSample s) && (s >= -1.0) && (s <= 1.0)-    where s = toSample a--testMidi :: IO ()-testMidi =  do-  putStrLn "TESTING PARSING AND BUILDING of Midi"--  test $ roundTrip buildMessage (parseMessage Nothing)-  test $ roundTrip buildMidi parseMidi-  test $ \trk -> trk == fromAbsTime (toAbsTime trk :: Track Ticks)-  test $ \trk td -> trk == fromRealTime td (toRealTime td trk)--  test $ \m -> (not $ null $ tracks m) ==>-               let (Midi SingleTrack _ trks) = toSingleTrack m-               in   length (concat $ tracks m) - length (concat trks) == length (tracks m) - 1--testWav :: IO ()-testWav =  do-  putStrLn "TESTING PARSING AND BUILDING of Wav"-  test $ roundTrip (Wav.buildWav :: Audio Word8 -> Builder) Wav.parseWav-  test $ roundTrip (Wav.buildWav :: Audio Int16 -> Builder) Wav.parseWav-  test $ roundTrip (Wav.buildWav :: Audio Int32 -> Builder) Wav.parseWav--testSoundFont :: IO ()-testSoundFont =  do-  putStrLn "TESTING PARSING AND BUILDING of SoundFont"-  test $ roundTrip SF.buildSoundFont SF.parseSoundFont--testParserBuilder :: IO ()-testParserBuilder = do-  putStrLn "TESTING PARSING AND BUILDING OF NUMERICAL TYPES"--  test $ roundTrip putWord8 getWord8-  test $ roundTrip putWord16be getWord16be-  test $ roundTrip putWord16le getWord16le-  test $ \w -> roundTrip putWord24be getWord24be (w .&. 0xFFFFFF)-  test $ \w -> roundTrip putWord24le getWord24le (w .&. 0xFFFFFF)-  test $ roundTrip putWord32be getWord32be-  test $ roundTrip putWord32le getWord32le-  test $ roundTrip putWord64be getWord64be-  test $ roundTrip putWord64le getWord64le--  test $ roundTrip putInt8 getInt8-  test $ roundTrip putInt16be getInt16be-  test $ roundTrip putInt16le getInt16le-  test $ roundTrip putInt32be getInt32be-  test $ roundTrip putInt32le getInt32le-  test $ roundTrip putInt64be getInt64be-  test $ roundTrip putInt64le getInt64le--  test $ roundTrip putWordHost getWordHost-  test $ roundTrip putWord16host getWord16host-  test $ roundTrip putWord32host getWord32host-  test $ roundTrip putWord64host getWord64host--  test $ roundTrip putVarLenBe getVarLenBe-  test $ roundTrip putVarLenLe getVarLenLe--  putStrLn "TESTING PARSING AND BUILDING OF String and ByteString"--  test $ \s1 s2 -> roundTrip (\s -> putString s `mappend` putString s2) (getString $ length s1) s1-  test $ \s1 s2 -> roundTrip (\s -> fromByteString s `mappend` fromByteString s2) (getByteString $ B.length s1) s1-  test $ \s1 s2 -> roundTrip (\s -> fromLazyByteString s `mappend` fromLazyByteString s2) (getLazyByteString $  L.length s1) s1-  test $ \bs -> roundTrip fromLazyByteString getRemainingLazyByteString bs---main :: IO ()-main = do-  testAudio-  testParserBuilder-  testMidi-  testWav-  testSoundFont