diff --git a/idiii.cabal b/idiii.cabal
--- a/idiii.cabal
+++ b/idiii.cabal
@@ -1,15 +1,16 @@
 Name:                idiii
-Version:             0.0
-Synopsis:            ID3v2 tag editing-suite
-Description:         ID3v2 tag editing-suite
+Version:             0.1
+Synopsis:            Reading and writing of ID3v2 tags
+Description:         Reading and writing of ID3v2 tags
 Category:            Text, Sound
 License:             BSD3
 License-file:        LICENSE
 Author:              laughedelic
-Maintainer:          laughedelic@gmail.com
-Build-Depends:       base < 5, polyparse, haskell98, bytestring, encoding, data-accessor, utf8-string, containers, MissingH
+Maintainer:          christopher.t.wagner@gmail.com
+Build-Depends:       base < 5, haskell98, bytestring, polyparse, text, data-accessor, utf8-string, containers, MissingH
 Build-Type:          Simple
 hs-source-dirs:      src
+extra-source-files:  LICENSE read-idiii.hs
 Exposed-modules:     ID3,
                      ID3.Simple,
 
@@ -34,4 +35,3 @@
                      ID3.ReadTag,
                      ID3.WriteTag
 ghc-options:         -Wall
-
diff --git a/read-idiii.hs b/read-idiii.hs
new file mode 100644
--- /dev/null
+++ b/read-idiii.hs
@@ -0,0 +1,18 @@
+module Main where
+
+import ID3
+import qualified Data.Map as Map
+import System (getArgs)
+
+main = do
+  args <- getArgs
+  let f = head args
+  maybeTag <- readTag f
+  case maybeTag of
+    Nothing -> putStrLn "File has no tag."
+    Just tag -> do
+      putStrLn $ "Here's the header: " ++ (show $ tagHeader tag)
+      putStrLn $ "Here are the frames: "
+      let lines = Map.elems $ Map.mapWithKey (\key val -> "  " ++ (show key) ++ ": " ++ (show $ frInfo_ val))
+                                             (tagFrames tag)
+      mapM_ putStrLn lines
diff --git a/src/ID3/Parser/ExtHeader.hs b/src/ID3/Parser/ExtHeader.hs
--- a/src/ID3/Parser/ExtHeader.hs
+++ b/src/ID3/Parser/ExtHeader.hs
@@ -14,12 +14,11 @@
 ----
 
 
-
 -- | Parses Extended Header as 'ID3ExtHeader' structure
 parseExtHeader :: TagParser ID3ExtHeader
 parseExtHeader = do
-    s    <- parseSize_ 4 `err` "ext header size"            -- Extended header size   4 * %0xxxxxxx
-    word8 0x01           `err` "ext header pre-flags"       -- Number of flag bytes       $01
+    s    <- parseSize 4 True `err` "ext header size"        -- Extended header size   4 * %0xxxxxxx
+    word8 0x01               `err` "ext header pre-flags"   -- Number of flag bytes       $01
     [b,c,d] <- parseFlags_ [2,3,4] `err` "ext header flags" -- Extended Flags             %0bcd0000
     bb <- if b then parseB else return False
     cc <- if c then parseC else return []
diff --git a/src/ID3/Parser/Frame.hs b/src/ID3/Parser/Frame.hs
--- a/src/ID3/Parser/Frame.hs
+++ b/src/ID3/Parser/Frame.hs
@@ -9,8 +9,10 @@
 import ID3.Parser.NativeFrames
 import ID3.Type.Frame
 import ID3.Type.Flags
+import ID3.Type.Header (unsynch)
 
 import Data.Accessor
+import Data.Either (rights)
 import Data.Map (Map)
 import qualified Data.Map as Map
 
@@ -20,39 +22,31 @@
 
 parseFrames :: TagParser ([FrameID], Map FrameID ID3Frame)
 parseFrames = do
-    frames <- many1 anyFrame
+    framesAndErrs <- many1 anyFrame
+    let frames = rights framesAndErrs
     let idList = map (\f -> f^.frHeader^.frID) frames
     return ( idList , Map.fromList (zip idList frames) )
 
 -- | Parses any Frame Header
-anyFrameHeader :: TagParser FrameHeader
+anyFrameHeader :: TagParser (Either String FrameHeader)
 anyFrameHeader = do
     i <- frameID       `err` "frame id"
     s <- frameSize     `err` "frame size"
-    f <- frameFlags    `err` "frame flags"
-    return $ initFrameHeader [frID^=i, frSize^=s, frFlags^=f]
+    if s > 500000
+      then return $ Left $ "Frame of type " ++ (show i) ++ " is too big!"
+      else do
+        f <- frameFlags    `err` "frame flags"
+        return $ Right $ initFrameHeader [frID^=i, frSize^=s, frFlags^=f]
 
 -- | Parses any Frame
-anyFrame :: TagParser ID3Frame
+anyFrame :: TagParser (Either String ID3Frame)
 anyFrame = do
-    h <- anyFrameHeader               `err` "frame header"
-    i <- frameInfo (h^.frID)          `err` "frame info"
-    return $ initID3Frame [frHeader^=h, frInfo^=i]
-
--- | Parses Frame Header with given id
-frameHeader :: FrameID -> TagParser FrameHeader
-frameHeader i = do
-    string i
-    s <- frameSize
-    f <- frameFlags
-    return $ initFrameHeader [frID^=i, frSize^=s, frFlags^=f]
-
--- | Parses Frame with given id
-parseFrame :: FrameID -> TagParser ID3Frame
-parseFrame id = do
-    h <- frameHeader id
-    i <- frameInfo   id
-    return $ initID3Frame [frHeader^=h, frInfo^=i]
+    hdr <- anyFrameHeader `err` "frame header"
+    case hdr of
+      Left e -> return $ Left e
+      Right h -> do
+        i <- frameInfo (h^.frID) `err` "frame info"
+        return $ Right $ initID3Frame [frHeader^=h, frInfo^=i]
 
 frameID :: TagParser FrameID
 frameID = do
@@ -61,7 +55,13 @@
     return $ C.unpack $ BS.pack name
 
 frameSize :: TagParser FrameSize
-frameSize = parseSize_ 4
+frameSize = do
+    version <- tagVersionGet
+    let (majorVersion, _) = version
+    flags <- flagsGet
+    let doDecoding = (majorVersion >= 4 || flags^.unsynch)
+    size <- parseSize 4 doDecoding
+    return size
 
 frameFlags = do
     s <- frameStatusFlags  `err` "status flags"
diff --git a/src/ID3/Parser/General.hs b/src/ID3/Parser/General.hs
--- a/src/ID3/Parser/General.hs
+++ b/src/ID3/Parser/General.hs
@@ -2,19 +2,23 @@
 module ID3.Parser.General where
 
 ----  IMPORTS
-import Text.ParserCombinators.Poly.State
+import Text.ParserCombinators.Poly.State (Parser, runParser, stGet, stUpdate, onFail, next,
+                                          satisfy, adjustErr, exactly)
 import ID3.Parser.UnSync
-import qualified Data.ByteString.Lazy as BS
-import qualified Data.ByteString.Lazy.Char8 as C
+import ID3.Type.Header (TagVersion, unsynch)
+import ID3.Type.Flags (Flags(..))
+--import qualified Data.ByteString.Lazy as BS
+--import qualified Data.ByteString.Lazy.Char8 as C
+import qualified Data.ByteString as BS
+import qualified Data.ByteString.Char8 as C
 import Data.Word (Word8)
 import Bits
 import Data.Accessor
-import Data.Encoding
-import Data.Encoding.ISO88591
-import Data.Encoding.UTF8
-import Data.Encoding.UTF16
+import qualified Data.Text as Text
+import Data.Text.Encoding (decodeASCII, decodeUtf16LE, decodeUtf16BE, decodeUtf8)
 import Data.ByteString.Lazy.UTF8 (toString)
 import Codec.Binary.UTF8.String as Codec
+import Control.Monad (when)
 ----
 
 ---,--------------------------------
@@ -22,26 +26,41 @@
 type Token = Word8
 
 -- | Parsers state
-data St = State { tagPos         :: Integer  -- ^ current position in tag
---              , headerFlags    :: [Bool]   -- ^
+data St = State { id3TagVersion  :: TagVersion
+                , headerFlags    :: Flags    -- ^ flags from tag's header
+                , tagPos         :: Integer  -- ^ current position in tag
 --              , frFlags        :: [Bool]}  -- ^ current frame flags
                 , curSize        :: Integer  -- ^ current frame size
-                , curEncoding    :: Integer  -- ^ current frame encoding
                 }
 
 instance Show St where
-    show st = show (tagPos st
-                   ,curSize st
-                   ,curEncoding st)
-initState = State 0 10 0
+    show st = show (tagPos st, curSize st)
+initState = State (4, 0) (Flags []) 0 10
 
+type CharEncoding = Integer
+
 type TagParser = Parser St Token
 
 run :: TagParser a -> [Word8] -> (Either String a, [Token])
 run p cont = (result, rest) where (result, _, rest) = runParser p initState cont
 
+
 ---,--------------------------------
+tagVersionGet :: TagParser TagVersion
+tagVersionGet = stGet >>= return . id3TagVersion
 
+tagVersionSet :: TagVersion -> TagParser ()
+tagVersionSet v = stUpdate (\st -> st {id3TagVersion = v})
+
+---,--------------------------------
+flagsGet :: TagParser Flags
+flagsGet = stGet >>= return . headerFlags
+
+flagsSet :: Flags -> TagParser ()
+flagsSet fs = stUpdate (\st -> st {headerFlags = fs})
+
+---,--------------------------------
+
 -- pos = accessor (stGet >>= return . tagPos) (stUpdate $ \p st -> st {tagPos = p} )
 
 -- | Returns 'tagPos' from 'St'.
@@ -78,21 +97,6 @@
 sizeInc      = sizeUpdate (\x -> x+1)
 
 ---,--------------------------------
--- | Returns 'curEncoding' from 'St'.
-encGet      :: TagParser Integer
-encGet      = stGet >>= return . curEncoding
--- | Updates 'curEncoding' with given function.
-encUpdate   :: (Integer -> Integer) -> TagParser ()
-encUpdate f = stUpdate ( \st -> st {curEncoding = f (curEncoding st)} )
--- | Sets 'curEncoding' with given value.
-encSet      :: Integer -> TagParser ()
-encSet e    = encUpdate (\_ -> e)
--- | Parses one byte and sets 'curEncoding'.
-encRead     :: TagParser Integer
-encRead     = anyWord8 >>= encSet . toInteger >> encGet
-
-
----,--------------------------------
 -- | Wrapper for /reiterative/ parsers.
 --   Mnemonic: @if 'curSize' > 0 then@ continue @else@ stop
 ifSize :: TagParser [a] -> TagParser [a]
@@ -197,46 +201,52 @@
     xs <- count' (n-1) (sep >> p)
     return (x:xs)
 
----,--------------------------------
--- | 'terminator' parses values termination symbol, according to current encoding ('curEncoding').
-terminator :: TagParser [Token]
-terminator = do
-    enc <- encGet
-    case enc of
-         0x01 -> word8s [00,00]     -- UTF-16
-         0x02 -> word8s [00,00]     -- UTF-16 BOM
-         _    -> word8s [00]        -- ISO-8859-1 or UTF-8
-
-encPack :: Integer -> [Token] -> String
-encPack 0x00 = toString . recode' ISO88591 UTF8 . BS.pack . filter (/=00)
-encPack 0x01 = toString . recode' UTF16 UTF8    . BS.pack . filter (/=00)
-encPack 0x02 = toString . recode' UTF16 UTF8    . BS.pack . filter (/=00)
-encPack _ = Codec.decode . filter (/=00)
-
-recode' from to = Data.Encoding.encodeLazyByteString to . Data.Encoding.decodeLazyByteString from
-
----,--------------------------------
--- | Parses a list of values (as [Token]) separated with termination symbol
-parseValues :: (Num n) => n -> TagParser [[Token]]
-parseValues n = countSepBy' n (many' nonNull) terminator
+encPack :: CharEncoding -> [Token] -> String
+encPack 0x00            s  = Text.unpack $ decodeASCII   $ BS.pack s
+encPack 0x01 (0xFF:0xFE:s) = Text.unpack $ decodeUtf16LE $ BS.pack s
+encPack 0x01 (0xFE:0xFF:s) = Text.unpack $ decodeUtf16BE $ BS.pack s
+encPack 0x02            s  = Text.unpack $ decodeUtf16BE $ BS.pack s
+encPack _               s  = Text.unpack $ decodeUtf8    $ BS.pack s
 
 -- | Parses one value (as [Token]) till termination symbol
-parseValue :: TagParser [Token]
-parseValue = nonNull `manyTill'` terminator
+parseUntilWord8Null :: TagParser [Token]
+parseUntilWord8Null = nonNull `manyTill'` (word8 0x00)
 
+parseUntilWord16Null :: TagParser [Token]
+parseUntilWord16Null = do
+  s <- sizeGet
+  when (s == 1) $ fail "Non-even number of bytes for UTF-16 string"
+  if s > 1
+    then do
+      byte1 <- anyWord8
+      byte2 <- anyWord8
+      if byte1 == 0x00 && byte2 == 0x00
+        then return []
+        else do
+          rest <- parseUntilWord16Null
+          return $ [byte1, byte2] ++ rest
+    else return []
+
 -- any byte except null
 nonNull = withSize $ satisfy (/=0x00) `adjustErr` (++"\nWTF: nonNull")
 
+-- | Parses a character-encoding "code", a one-byte value that should be 0, 1, 2, or 3
+parseEncoding :: TagParser CharEncoding
+parseEncoding = anyWord8 >>= (return . toInteger)
+
 -- | Parses one value and returns it as a 'String'
-parseString :: TagParser String
-parseString = do
-    e <- encGet
-    v <- parseValue
-    return $ encPack e v -- C.unpack . BS.pack
+parseString :: CharEncoding -> TagParser String
+parseString enc = do
+    v <- case enc of
+      0x01 -> parseUntilWord16Null -- UTF-16
+      0x02 -> parseUntilWord16Null -- UTF-16 BOM
+      _    -> parseUntilWord8Null  -- ISO-8859-1 or UTF-8
+    return $ encPack enc v
 
 -- | Parses one value and returns it as a 'Integer'
 parseNumber :: TagParser Integer
-parseNumber = parseValue >>= return . sum . (zipWith (*) (iterate (*10) 1)) . reverse . map toInteger
+parseNumber = parseUntilWord8Null >>= return . sum . (zipWith (*) (iterate (*10) 1)) .
+  reverse . map toInteger
 
 -- | Parses 3 bytes of language value (as a String) and returns a pair ("Language", value)
 parseLanguage :: TagParser String
@@ -244,13 +254,6 @@
     lang <- count' 3 anyWord8
     return $ encPack 0x03 lang
 
--- | Takes a list of keys and parses a list of values. Result is zip of these two lists.
-formValues :: [String] -> TagParser [(String, String)]
-formValues keys = do
-    enc  <- encGet
-    vals <- parseValues (length keys)
-    return $ zip keys $ map (encPack enc) vals
-
 --(<|>) = onFail
 
 ---,--------------------------------
@@ -298,12 +301,12 @@
 
 ---,--------------------------------
 type Size = Integer
--- | 'parseSize_ n' parses n bytes of synchronized size-value, and returns unsynchronized 'Integer' value.
-parseSize_ :: Integer -> TagParser Size
-parseSize_ n = do
+-- | 'parseSize n unsynchDecode' parses n bytes, doing decoding of "unsynchronized" data when unsynchDecode is True, and returns the represented 'Integer' value.
+parseSize :: Integer -> Bool -> TagParser Size
+parseSize n unsynchDecode = do
     s <- count n next
-    let size = unSynchronise s
     posUpdate (+n)
+    let size = if unsynchDecode then unSynchronise s else wordsToInteger s
     sizeSet size
     return size
 
diff --git a/src/ID3/Parser/Header.hs b/src/ID3/Parser/Header.hs
--- a/src/ID3/Parser/Header.hs
+++ b/src/ID3/Parser/Header.hs
@@ -28,12 +28,14 @@
 parseHeader_ = do
     v <- parseVersion         `err` "tag version"
     f <- parseFlags           `err` "tag flags"
-    s <- parseSize            `err` "tag size"
+    s <- parseTagSize         `err` "tag size"
     return $ initID3Header [tagVersion^=v, tagFlags^=f, tagSize^=s]
-    -- i.e. return ([major version, revision number], [a, b, c, d], size)
 
 parseVersion :: TagParser TagVersion
-parseVersion = count 2 anyWord8
+parseVersion = do
+    v1 <- anyWord8
+    v2 <- anyWord8
+    return $ (v1, v2)
 
 parseFlags :: TagParser TagFlags
 parseFlags = do
@@ -41,8 +43,8 @@
     return $ mkFlags [1..4] fs
     -- i.e. %abcd0000
 
-parseSize :: TagParser TagSize
-parseSize = parseSize_ 4
+parseTagSize :: TagParser TagSize
+parseTagSize = parseSize 4 True
 
 {- | /ID3v2 FOOTER/ (optional)
 
diff --git a/src/ID3/Parser/NativeFrames.hs b/src/ID3/Parser/NativeFrames.hs
--- a/src/ID3/Parser/NativeFrames.hs
+++ b/src/ID3/Parser/NativeFrames.hs
@@ -58,9 +58,9 @@
 
 textInfo :: String -> TagParser FrameInfo
 textInfo _ = do
-    enc  <- encRead
-    info <- parseString
-    return $ Text enc info --(name,  [("Information", encPack enc info)])
+    enc <- parseEncoding
+    info <- parseString enc
+    return $ Text enc info
 
 ---- {--    4.3.   URL link frames
 
@@ -79,9 +79,8 @@
  --  URL              <text string>
 
 urlInfo name = do
-    --info <- formValues ["URL"]
-    url <- parseString
-    return $ URL url --(name,  info)
+    url <- parseString 0
+    return $ URL url
 
 
 ---- {--    4.2.1.   Identification frames
@@ -483,7 +482,7 @@
 ---- --}
 
 frameInfo "TCMP" = do
-    encRead
+    parseEncoding -- XXX: Is the encoding really not used here??
     f <- parseNumber
     return $ TCMP (f == 1)
 
@@ -501,10 +500,10 @@
  --  Value             <text string according to encoding>
 
 frameInfo "TXXX" = do
-    enc   <- encRead
-    descr <- parseString
-    value <- parseString
-    return $ TXXX enc descr value -- (name,  info)
+    enc <- parseEncoding
+    descr <- parseString enc
+    value <- parseString enc
+    return $ TXXX enc descr value
 
 ---- --} }}}
 
@@ -570,14 +569,14 @@
  --  URL               <text string>
 
 frameInfo "WXXX" = do
-    enc   <- encRead
-    descr <- parseString
-    url   <- parseString
-    return $ WXXX enc descr url-- (name,  info)
+    enc   <- parseEncoding
+    descr <- parseString enc
+    url   <- parseString 0 -- URLs are always encoded in ISO-8859-1 (I think)
+    return $ WXXX enc descr url
 
 ---- --} }}}
 
----- {--    TODO: 4.4.   Music CD identifier 
+---- {--    4.4.   Music CD identifier 
 
 --  This frame is intended for music that comes from a CD, so that the CD
 --  can be identified in databases such as the CDDB [CDDB]. The frame
@@ -593,6 +592,12 @@
 
  --  <Header for 'Music CD identifier', ID: "MCDI">
  --  CD TOC                <binary data>
+
+frameInfo "MCDI" = do
+    sz <- sizeGet
+    tocData <- many' anyWord8
+    return $ MCDI tocData
+
 ---- --}
 
 ---- {--    TODO: 4.5.   Event timing codes 
@@ -750,11 +755,11 @@
  --  Lyrics/text          <full text string according to encoding>
 
 frameInfo "USLT" = do
-    enc   <- encRead
+    enc   <- parseEncoding
     lang  <- parseLanguage
-    descr <- parseString
-    text  <- parseString
-    return $ USLT enc lang descr text-- ("Unsynchronised lyrics: "++name,  lang:info )
+    descr <- parseString enc
+    text  <- parseString enc
+    return $ USLT enc lang descr text
 
 ---- --}
 
@@ -850,12 +855,12 @@
  --  The actual text        <full text string according to encoding>
 
 frameInfo "COMM" = do
-    enc   <- encRead
+    enc   <- parseEncoding
     lang  <- parseLanguage
-    descr <- parseString
-    text  <- parseString
-    many' terminator                    -- ???!!!!
-    return $ COMM enc lang descr text-- ("Comment: "++name,  lang:info )
+    descr <- parseString enc
+    text  <- parseString enc
+    --many' terminator                    -- ???!!!!
+    return $ COMM enc lang descr text
 
 ---- --}
 
@@ -998,12 +1003,12 @@
  --  Picture data       <binary data>
 
 frameInfo "APIC" = do
-    enc     <- encRead
-    mime    <- parseString
+    enc     <- parseEncoding
+    mime    <- parseString 0 -- mimetype always encoded in ISO-8859-1
     picType <- anyWord8
-    descr   <- parseString
+    descr   <- parseString enc
     picData <- many' anyWord8
-    return $ APIC enc mime picType descr picData -- ("Attached picture",  [])
+    return $ APIC enc mime picType descr picData
 
 --  Picture type:  $00  Other
               --  $01  32x32 pixels 'file icon' (PNG only)
@@ -1089,11 +1094,11 @@
  --  Counter         $xx xx xx xx (xx ...)
 
 frameInfo "POPM" = do
-    encSet 0x00
-    mail <- parseString
+    --encSet 0x00
+    mail <- parseString 0
     rate <- anyWord8
     cnt <- many' anyWord8
-    return $ POPM mail (toInteger rate) (wordsToInteger cnt)-- ("Popularimeter: "++email,  [("Rating", pack [rating]), ("Counter", pack counter)])
+    return $ POPM mail (toInteger rate) (wordsToInteger cnt)
 
 ---- --}
 
@@ -1355,7 +1360,7 @@
  --  Group dependent data  <binary data>
 ---- --}
 
----- {--    TODO: 4.27.   Private frame
+---- {--    4.27.   Private frame
 
 --  This frame is used to contain information from a software producer
 --  that its program uses and does not fit into the other frames. The
@@ -1370,6 +1375,12 @@
  --  <Header for 'Private frame', ID: "PRIV">
  --  Owner identifier      <text string> $00
  --  The private data      <binary data>
+
+frameInfo "PRIV" = do
+    ownerId <- parseString 0
+    privateData <- many' anyWord8
+    return $ PRIV ownerId privateData
+
 ---- --}
 
 ---- {--    TODO: 4.28.   Signature frame
@@ -1447,6 +1458,35 @@
  --  Oi = (Fi/2^b)*L    (rounded up to the nearest integer)
 ---- --}
 
+{------------------------------------------------------------------------
+ - Legacy ID3v2.3 Frames
+ - The following frames are not officially supported in ID3v2.4, but we
+ - will at least support reading it in, both because we want to support 
+ - reading of ID3v2.3 tags and because some MP3/ID3 encoders seem to
+ - illegally include the frames in ID3v2.4 tags.
+ ------------------------------------------------------------------------}
+
+--  TYER
+--  The 'Year' frame is a numeric string with a year of the recording.
+--  
+frameInfo "TYER" = textInfo "Year"
+
+--  TYER
+--  The 'Date' frame is a numeric string in the DDMM format containing
+--  the date for the recording.
+--  This frame, like 'TYER', is also not formally supported in ID3v2.4.
+frameInfo "TDAT" = textInfo "Date"
+
+--  TSIZ
+--  The 'Size' frame contains the size of the audiofile in bytes,
+--  excluding the ID3v2 tag, represented as a numeric string.
+frameInfo "TSIZ" = textInfo "Size of file (in bytes) excluding ID3v2 tag"
+
+{------------------------------------------------------------------------}
+
+-- XXX: This default implementation of frameInfo does not work correctly
+--      for some reason...  All frames coming after the unidentified frame
+--      will fail to be read.
 frameInfo _ = do
-    cont <- parseString
+    cont <- parseString 0
     return $ Unknown cont
diff --git a/src/ID3/Parser/Tag.hs b/src/ID3/Parser/Tag.hs
--- a/src/ID3/Parser/Tag.hs
+++ b/src/ID3/Parser/Tag.hs
@@ -1,13 +1,4 @@
-module ID3.Parser.Tag
-    (
-    -- * Tag type
-      ID3Tag(..)
-    -- * Tag parser
-    , run
-    , parseTag
-    , parseTag_
-    )
-where
+module ID3.Parser.Tag (parseTag, parseTag_) where
 
 {--  IMPORTS -}
 import Data.Accessor
@@ -27,6 +18,8 @@
 
 parseTag_ :: ID3Header -> TagParser ID3Tag
 parseTag_ h = do
+    tagVersionSet (h^.tagVersion)
+    flagsSet (h^.tagFlags)
     ext <- if (h^.tagFlags^.extended)
              then parseExtHeader >>= return . Just
              else return Nothing                                `err` "ext header"
diff --git a/src/ID3/ReadTag.hs b/src/ID3/ReadTag.hs
--- a/src/ID3/ReadTag.hs
+++ b/src/ID3/ReadTag.hs
@@ -1,11 +1,10 @@
-module ID3.ReadTag
-( hReadTag
-, readTag
-) where
+module ID3.ReadTag (hReadTag, readTag) where
 
 import Data.Accessor
+import ID3.Parser (run)
 import ID3.Parser.Tag
 import ID3.Parser.Header
+import ID3.Type (ID3Tag)
 import ID3.Type.Header
 import System.IO
 import System.IO.Binary
diff --git a/src/ID3/Type/Flags.hs b/src/ID3/Type/Flags.hs
--- a/src/ID3/Type/Flags.hs
+++ b/src/ID3/Type/Flags.hs
@@ -7,7 +7,7 @@
 import Data.Word (Word8)
 import ID3.Type.Unparse
 
-data Flags = Flags [Bool]   deriving Eq
+data Flags = Flags [Bool] deriving (Eq, Show)
 
 emptyFlags   :: Flags
 emptyFlags    = Flags $ replicate 8 False
diff --git a/src/ID3/Type/Frame.hs b/src/ID3/Type/Frame.hs
--- a/src/ID3/Type/Frame.hs
+++ b/src/ID3/Type/Frame.hs
@@ -289,10 +289,11 @@
     where inf = case id of
             "UFID" -> UFID "" ""
             "TXXX" -> TXXX 03 "" ""
+            "TCMP" -> TCMP False
             ('T':_)-> Text 03 ""
             "WXXX" -> WXXX 03 "" ""
             ('W':_)-> URL  ""
-            --MCDI -- TODO
+            "MCDI" -> MCDI []
             --ETCO -- { format :: Integer
                 -- , events :: [Event]} -- TODO
             --MLLT -- TODO
@@ -316,8 +317,7 @@
             --COMR -- TODO
             --ENCR -- TODO
             --GRID -- TODO
-            --PRIV -- TODO
+            "PRIV" -> PRIV "" []
             --SIGN -- TODO
             --ASPI -- TODO
-            "TCMP" -> TCMP False
             _      -> Unknown ""
diff --git a/src/ID3/Type/FrameInfo.hs b/src/ID3/Type/FrameInfo.hs
--- a/src/ID3/Type/FrameInfo.hs
+++ b/src/ID3/Type/FrameInfo.hs
@@ -17,7 +17,7 @@
                | WXXX { enc   :: Integer
                       , descr :: String
                       , url   :: String }
-               | MCDI -- TODO
+               | MCDI { tocData :: [Word8] }
                | ETCO -- { format :: Integer
                       -- , events :: [Event]} -- TODO
                | MLLT -- TODO
@@ -59,7 +59,8 @@
                | COMR -- TODO
                | ENCR -- TODO
                | GRID -- TODO
-               | PRIV -- TODO
+               | PRIV { ownerId     :: String
+                      , privateData :: [Word8] }
                | SIGN -- TODO
                | ASPI -- TODO
 
@@ -81,7 +82,7 @@
                TXXX enc descr text -> (fromInteger enc) : (encode descr) ++ [0x00] ++ (encode text)
                URL  url            ->  encode url
                WXXX enc descr url  -> (fromInteger enc) : (encode descr) ++ [0x00] ++ (encode url)
-               --MCDI -- TODO
+               MCDI tocData        -> tocData
                --ETCO -- { format :: Integer
                     -- , events :: [Event]} -- TODO
                --MLLT -- TODO
@@ -105,7 +106,7 @@
                --COMR -- TODO
                --ENCR -- TODO
                --GRID -- TODO
-               --PRIV -- TODO
+               PRIV ownerId privateData -> (encode ownerId) ++ privateData
                --SIGN -- TODO
                --ASPI -- TODO
                TCMP isPart -> 0x03 : (encode $ if isPart then "1" else "0")
diff --git a/src/ID3/Type/Header.hs b/src/ID3/Type/Header.hs
--- a/src/ID3/Type/Header.hs
+++ b/src/ID3/Type/Header.hs
@@ -28,12 +28,12 @@
    five or higher it should simply ignore the whole tag.
 -}
 data ID3Header = ID3Header
-                    { tagVersion_ :: TagVersion     -- ^ id3v2 version: @[major version, revision number]@
-                    , tagFlags_   :: TagFlags       -- ^ header flags as Bool values
-                    , tagSize_    :: TagSize        -- ^ full size of tag
-                    }   deriving Eq
+  { tagVersion_ :: TagVersion     -- ^ id3v2 version: @[major version, revision number]@
+  , tagFlags_   :: TagFlags       -- ^ header flags as Bool values
+  , tagSize_    :: TagSize        -- ^ full size of tag
+  }   deriving Eq
 
-emptyID3Header = ID3Header [4,0] emptyFlags 0
+emptyID3Header = ID3Header (4, 0) emptyFlags 0
 initID3Header  = flip compose emptyID3Header
 
 tagVersion = accessor tagVersion_ (\v h -> h {tagVersion_ = v})
@@ -44,18 +44,17 @@
     show header = "ID3v2"++"."++(show v1)++"."++(show v2)++"\n"++
                                 (showTagFlags $ header^.tagFlags)++
                   "Tag size: "++(show $ header^.tagSize   )++" bytes\n"
-                  where (v1:v2:_) = header^.tagVersion
+                  where (v1, v2) = header^.tagVersion
 
 instance Parsed ID3Header where
-    unparse h = (unparse $ Str "ID3"    ) ++
-                (          h^.tagVersion) ++
-                (unparse $ h^.tagFlags  ) ++
-                (unparse $ h^.tagSize   )
+    unparse h = (unparse $ Str "ID3") ++ [v1, v2] ++
+                (unparse $ h^.tagFlags) ++ (unparse $ h^.tagSize)
+      where (v1, v2) = h^.tagVersion
 
 {- | id3v2 version
     @major version . revision number@
 -}
-type TagVersion = [Word8]
+type TagVersion = (Word8, Word8)
 
 
 {- | /MEANING OF FLAGS/
