packages feed

idiii 0.0 → 0.1

raw patch · 13 files changed

+229/−175 lines, 13 filesdep +textdep −encodingnew-uploaderPVP ok

version bump matches the API change (PVP)

Dependencies added: text

Dependencies removed: encoding

API changes (from Hackage documentation)

- ID3.Parser.Frame: frameHeader :: FrameID -> TagParser FrameHeader
- ID3.Parser.Frame: parseFrame :: FrameID -> TagParser ID3Frame
- ID3.Parser.General: curEncoding :: St -> Integer
- ID3.Parser.General: encGet :: TagParser Integer
- ID3.Parser.General: encRead :: TagParser Integer
- ID3.Parser.General: encSet :: Integer -> TagParser ()
- ID3.Parser.General: encUpdate :: (Integer -> Integer) -> TagParser ()
- ID3.Parser.General: formValues :: [String] -> TagParser [(String, String)]
- ID3.Parser.General: parseSize_ :: Integer -> TagParser Size
- ID3.Parser.General: parseValue :: TagParser [Token]
- ID3.Parser.General: parseValues :: (Num n) => n -> TagParser [[Token]]
- ID3.Parser.General: terminator :: TagParser [Token]
- ID3.Parser.Tag: ID3Tag :: ID3Header -> Maybe ID3ExtHeader -> Map FrameID ID3Frame -> [FrameID] -> Integer -> ID3Tag
- ID3.Parser.Tag: data ID3Tag
- ID3.Parser.Tag: run :: TagParser a -> [Word8] -> (Either String a, [Token])
- ID3.Parser.Tag: tagExtHeader :: ID3Tag -> Maybe ID3ExtHeader
- ID3.Parser.Tag: tagFrames :: ID3Tag -> Map FrameID ID3Frame
- ID3.Parser.Tag: tagFramesOrder :: ID3Tag -> [FrameID]
- ID3.Parser.Tag: tagHeader :: ID3Tag -> ID3Header
- ID3.Parser.Tag: tagPadding :: ID3Tag -> Integer
+ ID3.Parser.General: flagsGet :: TagParser Flags
+ ID3.Parser.General: flagsSet :: Flags -> TagParser ()
+ ID3.Parser.General: headerFlags :: St -> Flags
+ ID3.Parser.General: id3TagVersion :: St -> TagVersion
+ ID3.Parser.General: parseEncoding :: TagParser CharEncoding
+ ID3.Parser.General: parseSize :: Integer -> Bool -> TagParser Size
+ ID3.Parser.General: parseUntilWord16Null :: TagParser [Token]
+ ID3.Parser.General: parseUntilWord8Null :: TagParser [Token]
+ ID3.Parser.General: tagVersionGet :: TagParser TagVersion
+ ID3.Parser.General: tagVersionSet :: TagVersion -> TagParser ()
+ ID3.Parser.General: type CharEncoding = Integer
+ ID3.Type.Flags: instance Show Flags
+ ID3.Type.FrameInfo: ownerId :: FrameInfo -> String
+ ID3.Type.FrameInfo: privateData :: FrameInfo -> [Word8]
+ ID3.Type.FrameInfo: tocData :: FrameInfo -> [Word8]
- ID3.Parser.Frame: anyFrame :: TagParser ID3Frame
+ ID3.Parser.Frame: anyFrame :: TagParser (Either String ID3Frame)
- ID3.Parser.Frame: anyFrameHeader :: TagParser FrameHeader
+ ID3.Parser.Frame: anyFrameHeader :: TagParser (Either String FrameHeader)
- ID3.Parser.General: State :: Integer -> Integer -> Integer -> St
+ ID3.Parser.General: State :: TagVersion -> Flags -> Integer -> Integer -> St
- ID3.Parser.General: count :: (Num n) => n -> TagParser a -> TagParser [a]
+ ID3.Parser.General: count :: Num n => n -> TagParser a -> TagParser [a]
- ID3.Parser.General: count' :: (Num n) => n -> TagParser a -> TagParser [a]
+ ID3.Parser.General: count' :: Num n => n -> TagParser a -> TagParser [a]
- ID3.Parser.General: countSepBy' :: (Num n) => n -> TagParser a -> TagParser sep -> TagParser [a]
+ ID3.Parser.General: countSepBy' :: Num n => n -> TagParser a -> TagParser sep -> TagParser [a]
- ID3.Parser.General: encPack :: Integer -> [Token] -> String
+ ID3.Parser.General: encPack :: CharEncoding -> [Token] -> String
- ID3.Parser.General: parseString :: TagParser String
+ ID3.Parser.General: parseString :: CharEncoding -> TagParser String
- ID3.Type.FrameInfo: MCDI :: FrameInfo
+ ID3.Type.FrameInfo: MCDI :: [Word8] -> FrameInfo
- ID3.Type.FrameInfo: PRIV :: FrameInfo
+ ID3.Type.FrameInfo: PRIV :: String -> [Word8] -> FrameInfo
- ID3.Type.Header: type TagVersion = [Word8]
+ ID3.Type.Header: type TagVersion = (Word8, Word8)
- ID3.Type.Unparse: size :: (HasSize a) => Accessor a Integer
+ ID3.Type.Unparse: size :: HasSize a => Accessor a Integer
- ID3.Type.Unparse: unparse :: (Parsed a) => a -> [Word8]
+ ID3.Type.Unparse: unparse :: Parsed a => a -> [Word8]
- ID3.Type.Unparse: updateSize :: (HasSize a) => a -> a
+ ID3.Type.Unparse: updateSize :: HasSize a => a -> a

Files

idiii.cabal view
@@ -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-
+ read-idiii.hs view
@@ -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
src/ID3/Parser/ExtHeader.hs view
@@ -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 []
src/ID3/Parser/Frame.hs view
@@ -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"
src/ID3/Parser/General.hs view
@@ -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 
src/ID3/Parser/Header.hs view
@@ -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) 
src/ID3/Parser/NativeFrames.hs view
@@ -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
src/ID3/Parser/Tag.hs view
@@ -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"
src/ID3/ReadTag.hs view
@@ -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
src/ID3/Type/Flags.hs view
@@ -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
src/ID3/Type/Frame.hs view
@@ -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 ""
src/ID3/Type/FrameInfo.hs view
@@ -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")
src/ID3/Type/Header.hs view
@@ -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/