diff --git a/Data/Riff.hs b/Data/Riff.hs
new file mode 100644
--- /dev/null
+++ b/Data/Riff.hs
@@ -0,0 +1,30 @@
+{-|
+Description : Convenience module that brings together both the parsing and assebling of Riff files.
+Copyright   : (c) Robert Massaioli, 2014
+License     : MIT
+Maintainer  : robertmassaioli@gmail.com
+Stability   : experimental
+
+This module was made as a convinience, it's purpose is to aid the manipulation of RIFF files such 
+that you can both parse them and asseble them. If you wish to just parse or assemble Riff files 
+then you may be better off just importing Data.Riff.Parse or Data.Riff.Assemble respectively.
+-}
+module Data.Riff ( 
+   -- * RIFF File Data Representaion
+   RiffFile(..),
+   RiffChunkSize, 
+   RiffFileType(..), 
+   RiffChunk(..), 
+   RiffId, 
+   RiffData, 
+   ParseError,
+   -- * Reading (parsing) RIFF Files
+   withRiffFile,
+   parseRiffData,
+   assembleRiffFile,
+   assembleRiffFileStream
+   ) where
+
+import Data.Riff.RiffData
+import Data.Riff.Parse
+import Data.Riff.Assemble
diff --git a/Data/Riff/Assemble.hs b/Data/Riff/Assemble.hs
new file mode 100644
--- /dev/null
+++ b/Data/Riff/Assemble.hs
@@ -0,0 +1,105 @@
+{-|
+Description : The module that allows the assembly of a RIFF / RIFX file.
+Copyright   : (c) Robert Massaioli, 2014
+License     : MIT
+Maintainer  : robertmassaioli@gmail.com
+Stability   : experimental
+
+This module allows the assembly of RIFF files in pure Haskell. You can create a RIFF file in 
+pure Haskell starting with a RiffFile and building it up until you are ready to write it out 
+to a ByteString or Disk. For example, this is how you might construct a RIFF file to be written
+out:
+
+> import Data.Riff
+>
+> riffFile = RiffFile RIFF "EXPL" children
+> 
+> children = 
+>    [ RiffChunkChild "fst " [1..11]
+>    , RiffChunkChild "snd " [11..100]
+>    ]
+>
+> main = assembleRiffFile "example.riff" riffFile
+
+As you can see it is a very simple API that lets you write out data into Riff Files. Have a play 
+around with with the examples until you can see how it works and fits together.
+-}
+module Data.Riff.Assemble 
+   ( assembleRiffFile
+   , assembleRiffFileStream
+   ) where
+
+import Data.Riff.RiffData
+import Data.Riff.Operations
+import qualified Data.ByteString.Lazy as BL
+import System.IO (withBinaryFile, IOMode(..))
+import Control.Monad (when)
+
+import Data.Binary.Put
+import Data.Char (ord)
+
+-- | Given a file path and a RiffFile representation this will allow you to safely write
+-- out a RiffFile to disk. This allows you to save anything that you like in a RiffFile.
+-- Just remember that the maximum file size of a RiffFile is bounded by the maximum size
+-- of a 32bit integer. The behaviour of this function, should you give it too much data,
+-- is undefined.
+assembleRiffFile 
+   :: FilePath -- ^ The location on the filesystem to save the RiffFile.
+   -> RiffFile -- ^ The in-memory representation of a RiffFile to be saved.
+   -> IO ()    -- ^ Writing to disk is an IO operatin and we return no results.
+assembleRiffFile filePath riffFile = withBinaryFile filePath WriteMode $ \h -> 
+   BL.hPut h (assembleRiffFileStream riffFile)
+
+-- | Assembles a RiffFile into it's representation in a Lazy ByteString. 
+assembleRiffFileStream 
+   :: RiffFile       -- ^ The RIFF file to be written out. 
+   -> BL.ByteString  -- ^ The resultant stream of bytes representing the file.
+assembleRiffFileStream = runPut . writeRiffFile
+
+writeRiffFile :: RiffFile -> Put
+writeRiffFile riffFile = do
+   printHeader . riffFileType $ riffFile -- Do not need safeId, chosen to be correrct
+   putSize context . calculateFileLength $ riffFile
+   putString . safeId . riffFileFormatType $ riffFile
+   sequence_ $ fmap (writeRiffChunk context) (riffFileChildren riffFile)
+   where
+      context = getContext . riffFileType $ riffFile
+   -- TODO do we need to word align the end of a riff file?
+
+getContext :: RiffFileType -> AssemblyContext
+getContext RIFF = AssemblyContext putWord32le
+getContext RIFX = AssemblyContext putWord32be
+
+data AssemblyContext = AssemblyContext
+   { putSize :: RiffChunkSize -> Put
+   }
+
+writeRiffChunk :: AssemblyContext -> RiffChunk -> Put
+writeRiffChunk context chunk@(RiffChunkChild _ _) = do
+   putString . safeId . riffChunkId $ chunk
+   let chunkSize = calculateChunkLength chunk
+   putSize context chunkSize
+   sequence_ $ fmap putWord8 (riffData chunk)
+   maybeFillBlank chunkSize
+writeRiffChunk context chunk@(RiffChunkParent _ _) = do
+   putString "LIST" -- Do not need to pass through safeId, chosen to be correct
+   let chunkSize = calculateChunkLength chunk
+   putSize context chunkSize
+   putString . safeId . riffFormTypeInfo $ chunk
+   sequence_ $ fmap (writeRiffChunk context) (riffChunkChildren chunk)
+   maybeFillBlank chunkSize
+
+maybeFillBlank :: RiffChunkSize -> Put
+maybeFillBlank chunkSize = when (chunkSize `mod` 2 == 1) putBlankByte
+
+putBlankByte = putWord8 0
+
+printHeader :: RiffFileType -> Put
+printHeader RIFF = putString "RIFF"
+printHeader RIFX = putString "RIFX"
+
+putString :: String -> Put
+putString = sequence_ . fmap (putWord8 . fromIntegral . ord)
+
+safeId :: RiffId -> RiffId
+safeId input = take 4 $ input ++ repeat ' '
diff --git a/Data/Riff/InternalUtil.hs b/Data/Riff/InternalUtil.hs
new file mode 100644
--- /dev/null
+++ b/Data/Riff/InternalUtil.hs
@@ -0,0 +1,8 @@
+module Data.Riff.InternalUtil where
+
+import Data.Riff.RiffData
+
+padToWord :: RiffChunkSize -> RiffChunkSize
+padToWord x = if x `mod` 2 == 0
+   then x
+   else x + 1
diff --git a/Data/Riff/Operations.hs b/Data/Riff/Operations.hs
new file mode 100644
--- /dev/null
+++ b/Data/Riff/Operations.hs
@@ -0,0 +1,47 @@
+{-|
+Description : The module provides common operations to perform on RIFF files.
+Copyright   : (c) Robert Massaioli, 2014
+License     : MIT
+Maintainer  : robertmassaioli@gmail.com
+Stability   : experimental
+
+This module provides some common operations that you might like to perform on RIFF files. This is 
+by no means an exhaustive list but you may find it useful. This is meant to be a collection of 
+common methods to make your development time shorter.
+-}
+module Data.Riff.Operations 
+   ( calculateFileLength
+   , calculateChunkLength
+   , trueFileSize
+   ) where
+
+import Data.Riff.RiffData
+import Data.Riff.InternalUtil
+
+-- | This function calculates the size of the RIFF file if it was written out to disk.
+trueFileSize 
+   :: RiffFile -- ^ The RIFF file that needs its size calculated.
+   -> Integer  -- ^ The size of the RIFF file if it was written to disk.
+trueFileSize riffFile = 8 + fromIntegral (calculateFileLength riffFile)
+
+-- | Calculates the size that should be in the ChunkSize location of the RiffFile when it
+-- has been written out to disk. If you want to get the true file size of a Riff file once
+-- it has been written out to disk then you need to use the trueFileSize function.
+calculateFileLength 
+   :: RiffFile       -- The RIFF file whose data size we want to calculate.
+   -> RiffChunkSize  -- The RiffChunkSize that should be placed in the initial ChunkSize slot.
+calculateFileLength (RiffFile _ _ children) = 
+   idLength + childHeaderLength children + childrenLength children
+
+-- | Calculates the size of this chunk such that you could place that size in the
+-- ChunkSize section of that chunk in a RIFF file that you wrote to disk.
+calculateChunkLength 
+   :: RiffChunk      -- ^ The RIFF chunk whose size should be calculated.
+   -> RiffChunkSize  -- ^ The size of the data portion of that chunk no disk.
+calculateChunkLength (RiffChunkChild _ chunkData) = fromIntegral $ length chunkData
+calculateChunkLength (RiffChunkParent _ children) = 
+   idLength + childHeaderLength children + childrenLength children
+
+idLength = 4
+childHeaderLength children = fromIntegral (8 * length children)
+childrenLength = sum . fmap (padToWord . calculateChunkLength)
diff --git a/Data/Riff/Parse.hs b/Data/Riff/Parse.hs
new file mode 100644
--- /dev/null
+++ b/Data/Riff/Parse.hs
@@ -0,0 +1,141 @@
+{-|
+Description : The module that allows parsing of a RIFF / RIFX file.
+Copyright   : (c) Robert Massaioli, 2014
+License     : MIT
+Maintainer  : robertmassaioli@gmail.com
+Stability   : experimental
+
+This module allows the parsing of RIFF files in pure Haskell. You can parse a RIFF file using the 
+methods provided in this module. For example, if you wanted to parse a RIFF file and print it out
+then you could:
+
+> main = withRiffFile "path/to/file.riff" print
+
+And that will print the RIFF file, in gory details, to the screen.
+-}
+module Data.Riff.Parse
+   ( withRiffFile
+   , parseRiffData
+   ) where
+
+import Data.Riff.RiffData
+import Data.Riff.InternalUtil
+
+import Control.Monad (when, replicateM)
+import Control.Monad.Trans.Either (EitherT(..), left, right)
+import Control.Monad.Trans.Class
+import Data.Binary.Get
+import qualified Data.ByteString.Lazy as BL
+import Data.Char (chr)
+import Data.Word (Word8)
+import GHC.IO.IOMode (IOMode(..))
+import System.IO (withBinaryFile)
+
+-- | Given a FilePath you can provide a function that will be given either a ParseError or
+-- an actual RiffFile to process. It is important to note that you should do all of the
+-- processing of the RiffFile in the provided action because the file will be closed at
+-- the end of this function.
+withRiffFile :: FilePath                              -- ^ The file that will be read.
+             -> (Either ParseError RiffFile -> IO ()) -- ^ An action to perform on the potentialy 
+                                                      -- parsed file
+             -> IO ()                                 -- ^ The resultant IO action.
+withRiffFile filePath action = withBinaryFile filePath ReadMode $ \h -> do
+   riffData <- fmap parseRiffData (BL.hGetContents h)
+   action riffData
+
+-- | You can parse a raw ByteString and try and convert it into a RiffFile. This will give
+-- a best attempt at parsing the data and, if success is not possible, will give you a
+-- ParseError.
+parseRiffData :: BL.ByteString               -- A lazy bytestring for input.
+              -> Either ParseError RiffFile  -- The result of our attempted parse.
+parseRiffData input =
+   case runGetOrFail (runEitherT getRiffStart) input of
+      Left (_, offset, error) -> Left (offset, error)
+      Right (_, _, result) -> result
+
+data ParseContext = ParseContext
+   { getSize :: Get RiffChunkSize
+   }
+
+getRiffStart :: EitherT ParseError Get RiffFile
+getRiffStart = do
+   id <- lift getIdentifier
+   (context, fileType) <- case id of
+      "RIFF" -> right (leContext, RIFF)
+      "RIFX" -> right (beContext, RIFX)
+      _ -> do
+         read <- lift bytesRead 
+         left (read, "RIFF file not allowed to start with chunk id: '" ++ id ++ "'. Must start with either RIFF or RIFX")
+   size <- lift . getSize $ context
+   riffType <- lift getIdentifier
+   contents <- parseChunkList context (size - 4)
+   return RiffFile
+      { riffFileType = fileType
+      , riffFileFormatType = riffType
+      , riffFileChildren = contents
+      }
+   where
+      leContext = ParseContext getWord32le
+      beContext = ParseContext getWord32be
+
+parseChunkList :: ParseContext -> RiffChunkSize -> EitherT ParseError Get [RiffChunk]
+parseChunkList _        0         = return []
+parseChunkList context  totalSize = do
+   (nextChunk, dataSize) <- getRiffChunk context
+   -- No matter what type of chunk it is tehre will be 8 bytes taken up by the id and size
+   let chunkSize = 8 + padToWord dataSize
+   if totalSize <= chunkSize
+      then return [nextChunk]
+      else do
+         following <- parseChunkList context (totalSize - chunkSize)
+         return $ nextChunk : following
+
+getRiffChunk :: ParseContext -> EitherT ParseError Get (RiffChunk, RiffChunkSize)
+getRiffChunk context = do
+   id <- lift getIdentifier
+   size <- lift . getSize $ context
+   if id == "LIST"
+      then do
+         guardListSize id size
+         formType <- lift getIdentifier
+         -- Minus 4 because of the formType before that is part of the size
+         children <- parseChunkList context (size - 4)
+         lift $ skipToWordBoundary size
+         return (RiffChunkParent
+            { riffFormTypeInfo = formType
+            , riffChunkChildren = children
+            }, size)
+      else do
+         -- TODO do we need to consider byte boundaries here?
+         riffData <- lift $ getNWords (fromIntegral size)
+         lift $ skipToWordBoundary size
+         return (RiffChunkChild
+            { riffChunkId = id
+            , riffData = riffData
+            }, size)
+   where
+      guardListSize id size = when (size < 4) $ do
+         read <- lift bytesRead
+         left (read, message id size)
+         where
+            message id size = 
+               "List Chunk Id '" ++ id 
+               ++ "' had chunk size " ++ show size 
+               ++ " which is less than 4 and invalid."
+
+skipToWordBoundary :: RiffChunkSize -> Get ()
+skipToWordBoundary size = do
+   empty <- isEmpty
+   when (not empty && size `mod` 2 == 1) $ skip 1
+
+getNWords :: Int -> Get [Word8]
+getNWords n = replicateM n getWord8
+
+getNChars :: Int -> Get String
+getNChars = fmap (fmap byteToChar) . getNWords 
+
+-- Parsing bytes
+byteToChar :: Word8 -> Char
+byteToChar = chr . fromIntegral
+
+getIdentifier = getNChars 4
diff --git a/Data/Riff/RiffData.hs b/Data/Riff/RiffData.hs
new file mode 100644
--- /dev/null
+++ b/Data/Riff/RiffData.hs
@@ -0,0 +1,61 @@
+-- | This module is responsible for all of the datatypes that are required around the codebase.
+module Data.Riff.RiffData where
+
+import Data.Word (Word8, Word32)
+import Data.Binary.Get (ByteOffset)
+
+-- | The data in a riff file is just a collection of bytes.
+type RiffData = Word8
+
+-- | A Riff file is made up exclusively of Riff Chunks and each chunk, as the second piece
+-- of data in the chunk, contains it's size. The size never includes the first 8 bytes of
+-- the chunk, which are the Chunk Id and the Chunk Size but, in the case of a nested
+-- chunk, it does include the four bytes of the Chunk FormType Id.
+--
+-- According to the specification a chunk size must be represented by four bytes of data.
+-- This means that the maximum number of bytes that can be present in a RIFF file is:
+--
+-- > 2 ^ 32 + 8 = 4294967304 bytes or ~4GB 
+-- 
+-- If your raw data is larger than that then this file format cannot support it.
+type RiffChunkSize = Word32
+
+-- | A RiffId is just a four character string (FourCC). It is usually (but by no means
+-- always) chosen to be something that is human readable when converted to ASCII. 
+type RiffId = String
+
+-- | Represents an error in the parsing of a Riff File. It contains the location in the
+-- file that we read up to and a message of what went wrong.
+type ParseError = (ByteOffset, String)
+
+-- | This is our representation of a RIFF file. These files all have a
+-- format type and are composed by one or more nestable data Chunks which we represent
+-- with a RiffChunk.
+data RiffFile = RiffFile 
+   { riffFileType :: RiffFileType      -- ^ The type of RIFF file.
+   , riffFileFormatType :: RiffId      -- ^ An ID representing the type of data contained within.
+   , riffFileChildren :: [RiffChunk]   -- ^ The chunks that make up the file.
+   }
+   deriving (Eq, Show)
+
+-- | There are only two different types of RIFF file: RIFF and RIFX and the difference is
+-- in the way that data is encoded inside them.
+data RiffFileType 
+   = RIFF -- ^ This is the most common type of RIFF file and is in little endian format.
+   | RIFX -- ^ This is a rare riff format that uses big endian encoding (otherwise known as
+          -- Motorolla byte order)
+   deriving(Eq, Show)
+
+-- | A RiffFile is just an alias for a RiffChunk. A RiffFile is merely a nested collection
+-- of RiffChunks where the first element must be a list of chunks with the ID RIFF or
+-- RIFX. 
+data RiffChunk 
+   = RiffChunkChild
+      { riffChunkId :: RiffId
+      , riffData :: [RiffData]
+      }
+   | RiffChunkParent
+      { riffFormTypeInfo :: RiffId
+      , riffChunkChildren :: [RiffChunk]
+      }
+   deriving (Eq, Show)
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Robert Massaioli <robertmassaioli@gmail.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/README.markdown b/README.markdown
new file mode 100644
--- /dev/null
+++ b/README.markdown
@@ -0,0 +1,49 @@
+# RIFF for Haskell
+
+[RIFF][2] has been around for a long time and I thought that now would be a
+good time to write a library for it in Haskell. This library supports reading most RIFF
+files. Example file formats (taken from Wikipedia and elsewhere) that use RIFF as the 
+container layer include:
+
+ - WAV (Windows audio)
+ - AVI (Windows audiovisual)
+ - RMI (Windows "RIFF MIDIfile")
+ - CDR (CorelDRAW vector graphics file)
+ - ANI (Animated Windows cursors)
+ - DLS (Downloadable Sounds)
+ - WebP (An image format developed by Google)
+ - XMA (Microsoft Xbox 360 console audio format based on WMA Pro)
+
+And there are many more. You can even come up with your own data that can be contained
+inside RIFF.
+
+## Building the Code
+
+To build the code:
+
+    $ cabal sandbox init
+    $ cabal install
+
+And that is all that there is to it.
+
+## Bundled Executables
+
+I have written a few simple programs just so that I could test out the code that I have written:
+
+    $ cabal run riff-structure # prints out the internal structure of a RIFF file
+    $ cabal run riff-convert # lets you convert files to and from RIFF and RIFX formats
+    $ cabal run riff-identity # the identity over RIFF files, useful for testing
+
+Feel free to use any of these executables to have a play with the RIFF file format, or better yet,
+write some code using this library and let me know about it.
+
+## Example Data
+
+You can find example data all over the internet. Any WAVE file is a RIFF file for example.
+Here is a list of example data that you may be able to download:
+
+ - [John Loomis Examples][1]
+
+
+ [1]: http://www.johnloomis.org/cpe102/asgn/asgn1/riff.zip
+ [2]: http://en.wikipedia.org/wiki/Resource_Interchange_File_Format
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/riff.cabal b/riff.cabal
new file mode 100644
--- /dev/null
+++ b/riff.cabal
@@ -0,0 +1,110 @@
+-- Initial riff.cabal generated by cabal init.  For further documentation, 
+-- see http://haskell.org/cabal/users-guide/
+
+-- The name of the package.
+name:                riff
+
+-- The package version.  See the Haskell package versioning policy (PVP) 
+-- for standards guiding when and how versions should be incremented.
+-- http://www.haskell.org/haskellwiki/Package_versioning_policy
+-- PVP summary:      +-+------- breaking API changes
+--                   | | +----- non-breaking API additions
+--                   | | | +--- code changes with no API change
+version:             0.1.0.0
+
+-- A short (one-line) description of the package.
+synopsis:            RIFF parser for Haskell
+
+-- A longer description of the package.
+description:         This library provides a RIFF parser for Haskell for easy manipulation
+                     of common file formats like WAVE and RIFF container AVI files.
+
+stability:           experimental
+
+homepage:            https://bitbucket.org/robertmassaioli/riff/overview
+
+bug-reports:         http://bitbucket.org/robertmassaioli/riff/issues
+
+-- The license under which the package is released.
+license:             MIT
+
+-- The file containing the license text.
+license-file:        LICENSE
+
+-- The package author(s).
+author:              Robert Massaioli
+
+-- An email address to which users can send suggestions, bug reports, and 
+-- patches.
+maintainer:          robertmassaioli@gmail.com
+
+-- A copyright notice.
+copyright:           (c) 2014 Robert Massaioli         
+
+category:            Data
+
+build-type:          Simple
+
+-- Extra files to be distributed with the package, such as examples or a 
+-- README.
+extra-source-files:  LICENSE, README.markdown
+
+-- Constraint on the version of Cabal needed to build this package.
+cabal-version:       >=1.10
+
+-- The source repository that this comes from.
+source-repository head
+  type: git
+  location: git://bitbucket.org/robertmassaioli/riff.git
+
+library
+  -- Modules exported by the library.
+  exposed-modules:     Data.Riff
+                       , Data.Riff.Operations
+  
+  -- Modules included in this library but not exported.
+  other-modules:       Data.Riff.InternalUtil
+                       , Data.Riff.RiffData
+                       , Data.Riff.Parse
+                       , Data.Riff.Assemble
+  
+  -- LANGUAGE extensions used by modules in this package.
+  -- other-extensions:    
+  
+  -- Other library packages from which modules are imported.
+  build-depends:       base >=4.5 && <5.0
+                       , binary >=0.7 && <0.8
+                       , bytestring >=0.9 && <1.0
+                       , either >=4.1 && <4.2
+                       , transformers >=0.3.0 && <0.3.1
+  
+  -- Directories containing source files.
+  -- hs-source-dirs:      
+  
+  -- Base language which the package is written in.
+  default-language:    Haskell2010
+
+  ghc-options: -W
+  
+
+executable riff-structure
+  hs-source-dirs: src
+  main-is:        riff-structure.hs
+  build-depends:       base >=4.5 && <5.0
+                       , riff
+  default-language:    Haskell2010
+
+executable riff-identity
+  hs-source-dirs: src
+  main-is:        riff-identity.hs
+  build-depends:       base >=4.5 && <5.0
+                       , riff
+  default-language:    Haskell2010
+
+executable riff-convert
+  hs-source-dirs: src
+  main-is:        riff-convert.hs
+  build-depends:       base >=4.5 && <5.0
+                       , filepath >=1.3 && <1.4
+                       , riff
+  default-language:    Haskell2010
diff --git a/src/riff-convert.hs b/src/riff-convert.hs
new file mode 100644
--- /dev/null
+++ b/src/riff-convert.hs
@@ -0,0 +1,46 @@
+module Main where
+
+import System.Console.GetOpt
+import System.Environment (getArgs)
+import System.FilePath (splitExtension)
+import Data.Riff
+
+data Flag
+   = Help
+   | ToRifx
+   deriving(Eq, Show)
+
+options :: [OptDescr Flag]
+options = 
+   [ Option "h" ["help"] (NoArg Help) "prints this help message"
+   , Option "x" ["rifx"] (NoArg ToRifx) "converts to the RIFX format. Converts to RIFF otherwise."
+   ]
+
+main = do
+   args <- getArgs
+   let (flags, extras, _) = getOpt Permute options args
+   handleFlags flags extras
+   
+handleFlags :: [Flag] -> [String] -> IO ()
+handleFlags flags files = do
+   if Help `elem` flags
+      then putStrLn $ usageInfo "riff-convert" options
+      else sequence_ $ fmap (convert toRifx) files
+   where
+      toRifx = ToRifx `elem` flags
+
+convert :: Bool -> FilePath -> IO ()
+convert toRifx filePath = do
+   putStr $ "> Reading " ++ filePath ++ "..."
+   withRiffFile filePath $ \result -> case result of
+      Left (pos, error) -> putStrLn $ error ++ " (Offset: " ++ show pos ++ ")"
+      Right riffFile -> do
+         putStr "converting..."
+         assembleRiffFile newFilename $ convertRep riffFile
+         putStrLn "[DONE]"
+   where
+      newFilename = filename ++ ".converted" ++ ext
+      (filename, ext) = splitExtension filePath
+
+      convertRep riffFile = riffFile { riffFileType = riffFT } 
+      riffFT = if toRifx then RIFX else RIFF
diff --git a/src/riff-identity.hs b/src/riff-identity.hs
new file mode 100644
--- /dev/null
+++ b/src/riff-identity.hs
@@ -0,0 +1,21 @@
+module Main where
+
+import Data.Riff
+
+import System.Environment (getArgs)
+
+main = do
+   args <- getArgs
+   case args of
+      [] -> putStrLn "You need to give this a riff file!"
+      xs -> do
+         putStrLn "Parsing and reassembling RIFF files:"
+         sequence_ $ fmap reassembleFile xs
+         putStrLn "Finished reassembling RIFF files."
+
+reassembleFile :: FilePath -> IO ()
+reassembleFile filePath = do
+   putStr $ "> " ++ filePath ++ " ..."
+   withRiffFile filePath $ \e -> case e of
+      Left (_, error) -> putStrLn "[FAILED]" >> putStrLn error
+      Right riffFile -> assembleRiffFile (filePath ++ ".clone") riffFile >> putStrLn "[Done]"
diff --git a/src/riff-structure.hs b/src/riff-structure.hs
new file mode 100644
--- /dev/null
+++ b/src/riff-structure.hs
@@ -0,0 +1,80 @@
+module Main where
+
+import Data.Riff
+import Data.Riff.Operations
+
+import System.Environment (getArgs)
+import Data.List (intersperse)
+import Control.Monad (when)
+import Data.Char (chr)
+
+main = do
+   args <- getArgs
+   case args of
+      [] -> error "No filename provided to scan. Please give me a file."
+      xs -> sequence_ . intersperse putNewline $ fmap processFile xs
+
+processFile :: String -> IO ()
+processFile filePath = do
+   putStr "File: "
+   print filePath
+   withRiffFile filePath $ \potential -> case potential of
+      Left (offset, error) -> putStrLn $ error ++ " (Offset: " ++ show offset ++ ")"
+      Right riffFile -> printRiffFile startContext riffFile
+
+data PrintContext = PrintContext
+   { indentation :: Int
+   , printValue :: Bool
+   }
+   deriving (Show)
+
+startContext :: PrintContext
+startContext = PrintContext 0 False
+
+printRiffFile :: PrintContext -> RiffFile -> IO ()
+printRiffFile context file@(RiffFile riffType formatType children) = do
+   printWithIndent context (typeName riffType)
+   putStrLn $ " (" ++ formatType ++ ") [" ++ showFileLength file ++ "]"
+   mapM_ (printRiffChunk nextContext) children
+   where
+      nextContext = PrintContext
+         { indentation = 1 + indentation context
+         , printValue = False
+         }
+
+      typeName RIFF = "RIFF"
+      typeName RIFX = "RIFX"
+
+printRiffChunk :: PrintContext -> RiffChunk -> IO ()
+printRiffChunk context chunk@(RiffChunkChild id value) = do
+   printWithIndent context id
+   putStr $ " [" ++ showLength chunk ++ "]"
+   when (printValue context) $ do
+      putStr ": "
+      inQuotes (putStr . fmap (chr . fromIntegral) $ takeWhile (/= 0) value)
+   putNewline
+printRiffChunk context chunk@(RiffChunkParent typeName children) = do
+   printWithIndent context "LIST"
+   putStrLn $ " (" ++ typeName ++ ") [" ++ showLength chunk ++ "]"
+   mapM_ (printRiffChunk nextContext) children
+   where
+      nextContext = PrintContext
+         { indentation = 1 + indentation context
+         , printValue = typeName == "INFO"
+         }
+
+showFileLength = show . calculateFileLength
+showLength = show . calculateChunkLength
+
+inQuotes :: IO () -> IO ()
+inQuotes action = do
+   putChar '"'
+   action
+   putChar '"'
+
+printWithIndent :: PrintContext -> String -> IO ()
+printWithIndent context value = do
+   putStr . concat . take (indentation context) $ repeat "   "
+   putStr value
+
+putNewline = putStrLn ""
