* entagged-sharp: Lots of changes! Removed Tag/GenericTag/AbstractTag abstraction, there is now just Tag. Removed *TagField and *Tag abstraction, now just using strings and the plain Tag class in the most part. All readers updated for the new model. Fixed some minor reader bugs/omissions which means the tests now pass in full. Index: tests/EntaggedTest.cs =================================================================== --- tests/EntaggedTest.cs (revision 48552) +++ tests/EntaggedTest.cs (working copy) @@ -74,7 +74,6 @@ } } - [TestFixture] public class TestMpc { private AudioFileWrapper afw; Index: src/Tag.cs =================================================================== --- src/Tag.cs (revision 48552) +++ src/Tag.cs (working copy) @@ -33,6 +33,7 @@ * */ +using System; using System.Collections; using System.Text; using Entagged.Audioformats.Util; @@ -70,187 +71,149 @@ { get { return DEFAULT_GENRES; } } - } - //////////////////////////////////////////////////////// - // - // Tag: Defines the core-interface for a Tag in - // an audio file. - // - /////////////////////////////////////////////////////// + public static string Get(int i) + { + if (i > TagGenres.Genres.Length - 1) + return "Unknown"; + return DEFAULT_GENRES[i]; + } - public interface Tag : IEnumerable { - - void Add(TagField field); + public static string Get(byte b) + { + return Get((int)b & 0xff); + } + } - void AddAlbum(string s); - void AddArtist(string s); - void AddComment(string s); - void AddGenre(string s); - void AddTitle(string s); - void AddTrack(string s); - void AddTrackCount(string s); - void AddYear(string s); - - IList Get(string id); - - - IList Genre { - get; - } - IList Title { - get; - } - IList Track { - get; - } - IList TrackCount { - get; - } - IList Year { - get; - } - IList Album { - get; - } - IList Artist { - get; - } - IList Comment { - get; - } - - bool HasCommonFields { - get; - } - bool HasField(string id); - bool IsEmpty { - get; - } - - void Set(TagField field); - - void SetAlbum(string s); - void SetArtist(string s); - void SetComment(string s); - void SetGenre(string s); - void SetTitle(string s); - void SetTrack(string s); - void SetYear(string s); - - bool SetEncoding(string enc); + public enum CommonField { + Artist, + Album, + Comment, + Genre, + Title, + Track, + TrackCount, + Year, } //////////////////////////////////////////////////////// // - // AbstractTag: Defines basic operations on a Tag + // Tag: Defines basic operations on a Tag // /////////////////////////////////////////////////////// - public abstract class AbstractTag : Tag, IEnumerable { + public class Tag : IEnumerable { protected Hashtable fields = new Hashtable(); - protected int commonNumber = 0; - + private Hashtable common_field_lookup = new Hashtable(); + + protected void AddCommonFieldMapping (CommonField field_id, string internal_name) + { + if (internal_name == null) + return; + + common_field_lookup[internal_name.ToLower()] = field_id; + } + public IList Title { - get { return Get(TitleId); } + get { return Get(CommonField.Title); } } public IList Album { - get { return Get(AlbumId); } + get { return Get(CommonField.Album); } } public IList Artist { - get { return Get(ArtistId); } + get { return Get(CommonField.Artist); } } public IList Genre { - get { return Get(GenreId); } + get { return Get(CommonField.Genre); } } public IList Track { - get { return Get(TrackId); } + get { return Get(CommonField.Track); } } public IList TrackCount { - get { return Get(TrackCountId); } + get { return Get(CommonField.TrackCount); } } public IList Year { - get { return Get(YearId); } + get { return Get(CommonField.Year); } } public IList Comment { - get { return Get(CommentId); } + get { return Get(CommonField.Comment); } } - public void SetTitle(string s) { - Set (CreateTitleField (s)); + Set (CommonField.Title, s); } public void SetAlbum(string s) { - Set (CreateAlbumField (s)); + Set (CommonField.Album, s); } public void SetArtist(string s) { - Set (CreateArtistField (s)); + Set (CommonField.Artist, s); } public void SetGenre(string s) { - Set (CreateGenreField (s)); + Set (CommonField.Genre, s); } public void SetTrack(string s) { - Set (CreateTrackField (s)); + Set (CommonField.Track, s); } public void SetTrackCount(string s) { - Set (CreateTrackCountField (s)); + Set (CommonField.TrackCount, s); } public void SetYear(string s) { - Set (CreateYearField (s)); + Set (CommonField.Year, s); } public void SetComment(string s) { - Set( CreateCommentField (s)); + Set (CommonField.Comment, s); } - + public void AddTitle(string s) { - Add (CreateTitleField (s)); + Add (CommonField.Title, s); } - public void AddAlbum(string s) { - Add( CreateAlbumField (s)); + Add(CommonField.Album, s); } public void AddArtist(string s) { - Add (CreateArtistField (s)); + Add (CommonField.Artist, s); } public void AddGenre(string s) { - Add (CreateGenreField (s)); + Add (CommonField.Genre, s); } public void AddTrack(string s) { - Add (CreateTrackField (s)); + Add (CommonField.Track, s); } + public void AddTrackCount(string s) { - Add (CreateTrackCountField (s)); + Add (CommonField.TrackCount, s); } + public void AddYear(string s) { - Add (CreateYearField (s)); + Add (CommonField.Year, s); } public void AddComment(string s) { - Add (CreateCommentField (s)); + Add (CommonField.Comment, s); } public bool HasField(string id) @@ -261,10 +224,6 @@ { get { return fields.Count == 0; } } - public bool HasCommonFields - { - get { return commonNumber != 0; } - } private class FieldsEnumerator : IEnumerator { @@ -320,270 +279,104 @@ return new FieldsEnumerator( fields.GetEnumerator() ); } - public IList Get (string id) + public IList Get(string id) { - IList list = fields[id] as IList; + IList list = fields[id.ToLower()] as IList; if(list == null) return new ArrayList(); return list; } - public void Set (TagField field) + + public IList Get(CommonField id) { - if(field == null) + return Get(id.ToString()); + } + + public void Set(string id, string content) + { + if (id == null || content == null) return; + + id = id.ToLower(); - //If an empty field is passed, we delete all the previous ones - if(field.IsEmpty) { - object removed = fields[field.Id]; - fields.Remove(field.Id); - - if(removed != null && field.IsCommon) - commonNumber--; + // If there is already an existing field with same id + // we update the first element + IList list = fields[id] as IList; + if(list != null && list.Count > 0) { + list [0] = content; return; } - //If there is already an existing field with same id - //and both are TextFields, we update the first element - IList l = fields[field.Id] as IList; - if(l != null) { - TagField f = l[0] as TagField; - f.CopyContent(field); - return; - } - - //Else we put the new field in the fields. - l = new ArrayList(); - l.Add(field); - fields[field.Id] = l; - if(field.IsCommon) - commonNumber++; + // Else we put the new field in the fields. + list = new ArrayList(); + list.Add(content); + fields[id] = list; } - public void Add(TagField field) + public void Set(CommonField id, string content) { - if(field == null || field.IsEmpty) + Set(id.ToString(), content); + } + + private void DoAdd(string id, string content) + { + if (content == null) return; + + id = id.ToLower(); + + // The 'raw' lists + IList list = fields[id] as IList; - IList list = fields[field.Id] as IList; - - //There was no previous item - if(list == null) { + // There was no previous item + if (list == null) { list = new ArrayList(); - list.Add(field); - fields[field.Id] = list; - if(field.IsCommon) - commonNumber++; + fields[id] = list; } - else { - //We append to existing list - list.Add(field); - } + + list.Add(content); } - - public override string ToString() + + public void Add(string id, string content, bool checkcommon) { - StringBuilder sb = new StringBuilder(); - sb.Append("Tag content:\n"); - foreach(TagField field in this) { - sb.Append("\t"); - sb.Append(field.Id); - sb.Append(" : "); - sb.Append(field.ToString()); - sb.Append("\n"); + DoAdd(id, content); + + if (checkcommon) { + object field = common_field_lookup[id.ToLower()]; + if (field != null) + DoAdd (((CommonField)field).ToString().ToLower(), content); } - return sb.ToString().Substring(0,sb.Length-1); } - public bool SetEncoding(string enc) { - if(!IsAllowedEncoding(enc)) { - return false; - } - - foreach(TagField field in this) { - if(field is TagTextField) { - (field as TagTextField).Encoding = enc; - } - } - - return true; - } - //-------------------------------- - protected abstract string ArtistId { - get; + public void Add(string id, string content) + { + Add(id, content, true); } - protected abstract string AlbumId { - get; - } - protected abstract string TitleId { - get; - } - protected abstract string TrackId { - get; - } - protected abstract string TrackCountId { - get; - } - protected abstract string YearId { - get; - } - protected abstract string CommentId { - get; - } - protected abstract string GenreId { - get; - } - - protected abstract TagField CreateArtistField(string content); - protected abstract TagField CreateAlbumField(string content); - protected abstract TagField CreateTitleField(string content); - protected abstract TagField CreateTrackField(string content); - protected abstract TagField CreateTrackCountField(string content); - protected abstract TagField CreateYearField(string content); - protected abstract TagField CreateCommentField(string content); - protected abstract TagField CreateGenreField(string content); - - protected abstract bool IsAllowedEncoding(string enc); - //--------------------------------------- - } - //////////////////////////////////////////////////////// - // - // GenericTag: Defines a basic mapping of Tags between - // different audio file formats - // - /////////////////////////////////////////////////////// - - public class GenericTag : AbstractTag { - private static string[] keys = + public void Add(CommonField id, string content) { - "ARTIST", - "ALBUM", - "TITLE", - "TRACK", - "YEAR", - "GENRE", - "COMMENT", - "TRACKCOUNT", - }; - - public static int ARTIST = 0; - public static int ALBUM = 1; - public static int TITLE = 2; - public static int TRACK = 3; - public static int YEAR = 4; - public static int GENRE = 5; - public static int COMMENT = 6; - public static int TRACKCOUNT = 7; - - protected override string ArtistId { - get { return keys[ARTIST]; } + Add(id.ToString(), content, false); } - protected override string AlbumId { - get { return keys[ALBUM]; } - } - protected override string TitleId { - get { return keys[TITLE]; } - } - protected override string TrackId { - get { return keys[TRACK]; } - } - protected override string TrackCountId { - get { return keys[TRACKCOUNT]; } - } - protected override string YearId { - get { return keys[YEAR]; } - } - protected override string CommentId { - get { return keys[COMMENT]; } - } - protected override string GenreId { - get { return keys[GENRE]; } - } - - protected override TagField CreateArtistField(string content) { - return new GenericTagTextField(keys[ARTIST], content); - } - protected override TagField CreateAlbumField(string content) { - return new GenericTagTextField(keys[ALBUM], content); - } - protected override TagField CreateTitleField(string content) { - return new GenericTagTextField(keys[TITLE], content); - } - protected override TagField CreateTrackField(string content) { - return new GenericTagTextField(keys[TRACK], content); - } - protected override TagField CreateTrackCountField(string content) { - return new GenericTagTextField(keys[TRACKCOUNT], content); - } - protected override TagField CreateYearField(string content) { - return new GenericTagTextField(keys[YEAR], content); - } - protected override TagField CreateCommentField(string content) { - return new GenericTagTextField(keys[COMMENT], content); - } - protected override TagField CreateGenreField(string content) { - return new GenericTagTextField(keys[GENRE], content); - } - - protected override bool IsAllowedEncoding(string enc) { - return true; - } - - private class GenericTagTextField : TagTextField { - - private string id; - private string content; - - public GenericTagTextField(string id, string content) { - this.id = id; - this.content = content; - } - - public string Content { - get { return this.content; } - set { this.content = value; } - } - public string Encoding { - get { return "ISO-8859-1"; } - set { /* Not allowed */} - } - - public string Id { - get { return id; } - } - - public byte[] RawContent { - /* FIXME: What to do here ? not supported */ - get { return new byte[] {}; } - } - - public bool IsBinary { - get { return false; } - set { /* Not Supported */ } - } - - public bool IsCommon { - get { return true; } - } - - public bool IsEmpty { - get { return content == ""; } - } - - public override string ToString() - { - return Id + " : " + Content; - } - - public void CopyContent(TagField field) - { - if(field is TagTextField) { - this.content = (field as TagTextField).Content; + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("Tag content:\n"); + foreach(DictionaryEntry entry in fields) { + string id = (string) entry.Key; + IList list = (IList) entry.Value; + foreach (string content in list) { + sb.Append("\t"); + sb.Append(id); + sb.Append(" : "); + sb.Append(content); + sb.Append("\n"); } } + return sb.ToString().Substring(0,sb.Length-1); } } + } Index: src/M4a/M4aTag.cs =================================================================== --- src/M4a/M4aTag.cs (revision 48552) +++ src/M4a/M4aTag.cs (working copy) @@ -1,126 +0,0 @@ -/*************************************************************************** - * Copyright 2005 Novell, Inc. - * Aaron Bockover - ****************************************************************************/ - -/* THIS FILE IS LICENSED UNDER THE MIT LICENSE AS OUTLINED IMMEDIATELY BELOW: - * - * 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. - */ - -using System; - -using Entagged.Audioformats.Util; -using Entagged.Audioformats.M4a.Util; - -namespace Entagged.Audioformats.M4a -{ - public class M4aTag : AbstractTag - { - protected override TagField CreateAlbumField(string content) - { - return new M4aTagField(AlbumId, content); - } - - protected override TagField CreateArtistField(string content) - { - return new M4aTagField(ArtistId, content); - } - - protected override TagField CreateCommentField(string content) - { - return new M4aTagField(CommentId, content); - } - - protected override TagField CreateGenreField(string content) - { - return new M4aTagField(GenreId, content); - } - - protected override TagField CreateTitleField(string content) - { - return new M4aTagField(TitleId, content); - } - - protected override TagField CreateTrackField(string content) - { - return new M4aTagField(TrackId, content); - } - - protected override TagField CreateTrackCountField(string content) - { - return new M4aTagField(TrackCountId, content); - } - - protected override TagField CreateYearField(string content) - { - return new M4aTagField(YearId, content); - } - - protected override string AlbumId - { - get { return "ALBUM"; } - } - - protected override string ArtistId - { - get { return "ARTIST"; } - } - - protected override string CommentId - { - get { return "COMMENTS"; } - } - - protected override string GenreId - { - get { return "GENRE"; } - } - - protected override string TitleId - { - get { return "TITLE"; } - } - - protected override string TrackId - { - get { return "TRACKNUMBER"; } - } - - protected override string TrackCountId - { - get { return "EntaggedTrackCount"; } - } - - protected override string YearId - { - get { return "YEAR"; } - } - - protected override bool IsAllowedEncoding(string enc) - { - return enc == "UTF-8"; - } - - public override string ToString() - { - return "M4A " + base.ToString(); - } - } -} Index: src/M4a/Util/M4aTagReader.cs =================================================================== --- src/M4a/Util/M4aTagReader.cs (revision 48552) +++ src/M4a/Util/M4aTagReader.cs (working copy) @@ -38,9 +38,9 @@ public class M4aTagReader { private BinaryReader br; - private M4aTag tag; + private Tag tag; private EncodingInfo ei; - + public Tag ReadTags(Stream raf) { Read(raf); @@ -55,12 +55,12 @@ public void Read (Stream raf) { - tag = new M4aTag(); + tag = new Tag(); ei = new EncodingInfo(); br = new BinaryReader(raf); Parse(); } - + private void Parse() { byte[] buffer = new byte[4]; @@ -118,12 +118,10 @@ data[1 + (i * 2)], data[0 + (i * 2)] }, 0); switch(dataatom) { case DataAtoms.GNRE: - tag.Add(new M4aTagField("GENRE", - GENRE_MAP[intvals[0]])); + tag.AddGenre(GENRE_MAP[intvals[0]]); break; case DataAtoms.TRKN: - tag.Add(new M4aTagField("TRACKNUMBER", - Convert.ToString(intvals[1]))); + tag.AddTrack(Convert.ToString(intvals[1])); break; default: Console.WriteLine("DataAtom: {0}", dataatom); @@ -132,32 +130,28 @@ break; } case 1: { + CommonField field = 0; switch(dataatom) { case DataAtoms.GEN: - tag.Add(new M4aTagField("GENRE", - Encoding.Default.GetString(data))); + field = CommonField.Genre; break; case DataAtoms.NAM: - tag.Add(new M4aTagField("TITLE", - Encoding.Default.GetString(data))); + field = CommonField.Title; break; case DataAtoms.ART: - tag.Add(new M4aTagField("ARTIST", - Encoding.Default.GetString(data))); + field = CommonField.Artist; break; case DataAtoms.ALB: - tag.Add(new M4aTagField("ALBUM", - Encoding.Default.GetString(data))); + field = CommonField.Album; break; case DataAtoms.DAY: - tag.Add(new M4aTagField("YEAR", - Encoding.Default.GetString(data))); + field = CommonField.Year; break; case DataAtoms.CMT: - tag.Add(new M4aTagField("COMMENT", - Encoding.Default.GetString(data))); + field = CommonField.Comment; break; } + tag.Add(field, Encoding.Default.GetString(data)); break; } case 2: { // other byte data Index: src/M4a/Util/M4aTagField.cs =================================================================== --- src/M4a/Util/M4aTagField.cs (revision 48552) +++ src/M4a/Util/M4aTagField.cs (working copy) @@ -1,117 +0,0 @@ -/*************************************************************************** - * Copyright 2005 Novell, Inc. - * Aaron Bockover - ****************************************************************************/ - -/* THIS FILE IS LICENSED UNDER THE MIT LICENSE AS OUTLINED IMMEDIATELY BELOW: - * - * 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. - */ - -using System; - -using Entagged.Audioformats.Util; - -namespace Entagged.Audioformats.M4a.Util -{ - public class M4aTagField : TagTextField - { - private bool common; - private string content; - private string id; - - public M4aTagField(string fieldId, string fieldContent) - { - id = fieldId.ToUpper(); - content = fieldContent; - } - - public void CopyContent(TagField field) - { - if(field is TagTextField) - content = (field as TagTextField).Content; - } - - public string Content - { - get { - return content; - } - - set { - content = value; - } - } - - public string Encoding - { - get { - return "UTF-8"; - } - - set { - /* NA */ - } - } - - public string Id - { - get { - return id; - } - } - - public byte[] RawContent - { - get { - return null; - } - } - - public bool IsBinary - { - get { - return false; - } - - set { - /* NA */ - } - } - - public bool IsCommon - { - get { - return common; - } - } - - public bool IsEmpty - { - get { - return content.Equals(string.Empty); - } - } - - public override string ToString() - { - return Content; - } - } -} Index: src/Mp3/Id3Tag.cs =================================================================== --- src/Mp3/Id3Tag.cs (revision 48552) +++ src/Mp3/Id3Tag.cs (working copy) @@ -36,98 +36,20 @@ namespace Entagged.Audioformats.Mp3 { - public class Id3v1Tag : GenericTag { - public static string[] Genres { - get { return TagGenres.Genres; } - } - - protected override bool IsAllowedEncoding(string enc) { - return enc == "ISO-8859-1"; - } - - public string TranslateGenre( byte b) { - int i = b & 0xFF; - - if ( i == 255 || i > Genres.Length - 1 ) - return ""; - return Genres[i]; - } - - public override string ToString() { - return "Id3v1 "+base.ToString(); - } - } - - public class Id3v2Tag : AbstractTag { + public class Id3Tag : Tag { public static string DEFAULT_ENCODING = "UTF-16"; public static byte ID3V22 = 0; public static byte ID3V23 = 1; - private bool hasV1; - - protected override string ArtistId { - get { return "TPE1"; } + public Id3Tag() + { + AddCommonFieldMapping(CommonField.Artist, "TPE1"); + AddCommonFieldMapping(CommonField.Album, "TALB"); + AddCommonFieldMapping(CommonField.Title, "TIT2"); + AddCommonFieldMapping(CommonField.Track, "TRCK"); + AddCommonFieldMapping(CommonField.Year, "TYER"); + AddCommonFieldMapping(CommonField.Genre, "TCON"); } - protected override string AlbumId { - get { return "TALB"; } - } - protected override string TitleId { - get { return "TIT2"; } - } - protected override string TrackId { - get { return "TRCK"; } - } - protected override string TrackCountId { - get { return "EntaggedTrackCount"; } - } - protected override string YearId { - get { return "TYER"; } - } - protected override string CommentId { - get { return "COMM"; } - } - protected override string GenreId { - get { return "TCON"; } - } - - protected override TagField CreateArtistField(string content) { - return new TextId3Frame(ArtistId, content); - } - protected override TagField CreateAlbumField(string content) { - return new TextId3Frame(AlbumId, content); - } - protected override TagField CreateTitleField(string content) { - return new TextId3Frame(TitleId, content); - } - protected override TagField CreateTrackField(string content) { - return new TextId3Frame(TrackId, content); - } - protected override TagField CreateTrackCountField(string content) { - return new TextId3Frame(TrackCountId, content); - } - protected override TagField CreateYearField(string content) { - return new TextId3Frame(YearId, content); - } - protected override TagField CreateCommentField(string content) { - return new CommId3Frame(content); - } - protected override TagField CreateGenreField(string content) { - return new TextId3Frame(GenreId, content); - } - - protected override bool IsAllowedEncoding(string enc) { - return enc == "ISO-8859-1" || - enc == "UTF-16"; - } - - public bool HasId3v1 { - get { return hasV1; } - set { this.hasV1 = value; } - } - - public override string ToString() { - return "Id3v2 "+base.ToString(); - } } } Index: src/Mp3/Mp3FileReader.cs =================================================================== --- src/Mp3/Mp3FileReader.cs (revision 48552) +++ src/Mp3/Mp3FileReader.cs (working copy) @@ -54,28 +54,12 @@ } protected override Tag GetTag( Stream raf ) { - string error = ""; - Id3v2Tag v2 = null; - Id3v1Tag v1 = null; - - try { - v2 = idv2tr.Read(raf); - } catch(CannotReadException e) { - v2 = null; - error += "("+e.Message+")"; - } - - try { - v1 = idv1tr.Read(raf); - } catch(CannotReadException e) { - v1 = null; - error += "("+e.Message+")"; - } + Id3Tag tag = new Id3Tag(); - if (v2 != null && v1 != null) - v2.HasId3v1 = true; + idv2tr.Read(tag, raf); + idv1tr.Read(tag, raf); - return Utils.CombineTags(v2, v1); + return tag; } } } Index: src/Mp3/Util/Id3v1TagReader.cs =================================================================== --- src/Mp3/Util/Id3v1TagReader.cs (revision 48552) +++ src/Mp3/Util/Id3v1TagReader.cs (working copy) @@ -31,68 +31,58 @@ */ using System.IO; +using System.Text; using Entagged.Audioformats.Exceptions; namespace Entagged.Audioformats.Mp3.Util { public class Id3v1TagReader { - public Id3v1Tag Read( Stream mp3Stream ) + public bool Read(Id3Tag tag, Stream mp3Stream) { - Id3v1Tag tag = new Id3v1Tag(); //Check wether the file contains an Id3v1 tag-------------------------------- mp3Stream.Seek( -128 , SeekOrigin.End); byte[] b = new byte[3]; mp3Stream.Read( b, 0, 3 ); mp3Stream.Seek(0, SeekOrigin.Begin); - string tagS = new string(System.Text.Encoding.ASCII.GetChars( b )); - if(tagS != "TAG"){ - throw new CannotReadException("There is no Id3v1 Tag in this file"); - } + string tagS = Encoding.ASCII.GetString(b); + if(tagS != "TAG") + return false; mp3Stream.Seek( - 128 + 3, SeekOrigin.End ); //Parse the tag -)------------------------------------------------ - string songName = Read(mp3Stream, 30); + tag.AddTitle(Read(mp3Stream, 30)); + tag.AddArtist(Read(mp3Stream, 30)); + tag.AddAlbum(Read(mp3Stream, 30)); //------------------------------------------------ - string artist = Read(mp3Stream, 30); - //------------------------------------------------ - string album = Read(mp3Stream, 30); - //------------------------------------------------ - string year = Read(mp3Stream, 4); - //------------------------------------------------ - string comment = Read(mp3Stream, 30); - //------------------------------------------------ - string trackNumber = ""; - + tag.AddYear(Read(mp3Stream, 4)); + tag.AddComment(Read(mp3Stream, 30)); + + string trackNumber; mp3Stream.Seek(- 2, SeekOrigin.Current); b = new byte[2]; mp3Stream.Read(b, 0, 2); - if ( b[0] == 0 ) { - trackNumber = b[1].ToString (); - } - //------------------------------------------------ + if (b[0] == 0) + tag.AddTrack(b[1].ToString()); + byte genreByte = (byte) mp3Stream.ReadByte(); mp3Stream.Seek(0, SeekOrigin.Begin); + tag.AddGenre(TagGenres.Get(genreByte)); - tag.SetTitle( songName ); - tag.SetArtist( artist ); - tag.SetAlbum( album ); - tag.SetYear( year ); - tag.SetComment( comment ); - tag.SetTrack( trackNumber ); - tag.SetGenre( tag.TranslateGenre(genreByte) ); - - - return tag; + return true; } private string Read(Stream mp3Stream, int length) { byte[] b = new byte[length]; mp3Stream.Read( b, 0, b.Length ); - string ret = new string(System.Text.Encoding.GetEncoding("ISO-8859-1").GetChars( b )).Trim(); - - return ret.Split('\0')[0]; + string ret = Encoding.GetEncoding("ISO-8859-1").GetString(b).Trim(); + + int pos = ret.IndexOf('\0'); + if (pos != -1) + ret = ret.Substring(0, pos); + + return ret; } } } Index: src/Mp3/Util/Id3v2TagReader.cs =================================================================== --- src/Mp3/Util/Id3v2TagReader.cs (revision 48552) +++ src/Mp3/Util/Id3v2TagReader.cs (working copy) @@ -30,7 +30,9 @@ * */ +using System; using System.IO; +using System.Text; using Entagged.Audioformats.Util; using Entagged.Audioformats.Exceptions; @@ -42,20 +44,18 @@ Id3v23TagReader v23 = new Id3v23TagReader(); - public Id3v2Tag Read(Stream mp3Stream) + public bool Read(Id3Tag tag, Stream mp3Stream) { - Id3v2Tag tag; - byte[] b = new byte[3]; mp3Stream.Read(b, 0, b.Length); mp3Stream.Seek(0, SeekOrigin.Begin); - string ID3 = new string(System.Text.Encoding.ASCII.GetChars(b)); + string ID3 = Encoding.ASCII.GetString(b); - if (ID3 != "ID3") { - throw new CannotReadException("Not an ID3 tag"); - } + if (ID3 != "ID3") + return false; + //Begins tag parsing --------------------------------------------- mp3Stream.Seek(3, SeekOrigin.Begin); //---------------------------------------------------------------------------- @@ -82,57 +82,38 @@ bb = synchronizer.synchronize(bb); } - if(versionHigh == "2") { - tag = v23.Read(bb, ID3Flags, Id3v2Tag.ID3V22); - } - else if(versionHigh == "3") { - tag = v23.Read(bb, ID3Flags, Id3v2Tag.ID3V23); - } - else if(versionHigh == "4") { - throw new CannotReadException("ID3v2 tag version "+ versionID3 + " not supported !"); - } - else { - throw new CannotReadException("ID3v2 tag version "+ versionID3 + " not supported !"); - } + if (versionHigh == "2") + v23.Read(tag, bb, ID3Flags, Id3Tag.ID3V22); + else if (versionHigh == "3") + v23.Read(tag, bb, ID3Flags, Id3Tag.ID3V23); + else + return false; - return tag; + return true; } private bool[] ProcessID3Flags(byte b) { - bool[] flags; + bool[] flags = new bool[] { false, false, false, false }; + if (b == 0) + return flags; - if (b != 0) { - flags = new bool[4]; + // Synchronisation + if ((b & 128) == 128) + flags[0] = true; + + // Extended header + if ((b & 64) == 64) + flags[1] = true; + + // Experimental indicator + if ((b & 32) == 32) + flags[2] = true; - int flag = b & 128; + // Footer present + if ((b & 16) == 16) + flags[3] = true; - if (flag == 128) - flags[0] = true; - else - flags[0] = false; //unsynchronisation - flag = b & 64; - if (flag == 64) - flags[1] = true; - else - flags[1] = false; //Extended Header - flag = b & 32; - if (flag == 32) - flags[2] = true; - else - flags[2] = false; //Experimental Indicator - flag = b & 16; - if (flag == 16) - flags[3] = true; - else - flags[3] = false; //Footer Present - } else { - flags = new bool[4]; - flags[0] = false; - flags[1] = false; - flags[2] = false; - flags[3] = false; - } return flags; } Index: src/Mp3/Util/Id3frames/TextId3Frame.cs =================================================================== --- src/Mp3/Util/Id3frames/TextId3Frame.cs (revision 48552) +++ src/Mp3/Util/Id3frames/TextId3Frame.cs (working copy) @@ -31,11 +31,12 @@ */ using System; +using System.Text; using Entagged.Audioformats.Util; using Entagged.Audioformats.Mp3; namespace Entagged.Audioformats.Mp3.Util.Id3Frames { - public class TextId3Frame : Id3Frame, TagTextField { + public class TextId3Frame : Id3Frame { protected string content; protected byte encoding; @@ -50,26 +51,14 @@ public TextId3Frame(string id, string content) { this.id = id; - CheckCommon(); this.content = content; - Encoding = Id3v2Tag.DEFAULT_ENCODING; + Encoding = Id3Tag.DEFAULT_ENCODING; } public TextId3Frame(string id, byte[] rawContent, byte version) : base(rawContent, version) { this.id = id; - CheckCommon(); } - private void CheckCommon() { - this.common = id == "TIT2" || - id == "TALB" || - id == "TPE1" || - id == "TCON" || - id == "TRCK" || - id == "TYER" || - id == "COMM"; - } - public string Encoding { get { if(encoding == 0) @@ -122,7 +111,7 @@ this.encoding = raw[flags.Length]; if(this.encoding != 0 && this.encoding != 1) this.encoding = 0; - + this.content = GetString(raw, flags.Length+1, raw.Length-flags.Length-1, Encoding); this.content = this.content.Split('\0')[0]; Index: src/Mp3/Util/Id3frames/CommId3Frame.cs =================================================================== --- src/Mp3/Util/Id3frames/CommId3Frame.cs (revision 48552) +++ src/Mp3/Util/Id3frames/CommId3Frame.cs (working copy) @@ -36,7 +36,7 @@ using Entagged.Audioformats.Mp3; namespace Entagged.Audioformats.Mp3.Util.Id3Frames { - public class CommId3Frame : TextId3Frame, TagTextField { + public class CommId3Frame : TextId3Frame { private string shortDesc; private string lang; @@ -64,7 +64,7 @@ { this.encoding = raw[flags.Length]; - this.lang = new string(System.Text.Encoding.GetEncoding("ISO-8859-1").GetChars(raw, flags.Length+1, 3)); + this.lang = System.Text.Encoding.GetEncoding("ISO-8859-1").GetString(raw, flags.Length+1, 3); this.shortDesc = GetString(raw, flags.Length+4, raw.Length - flags.Length - 4, Encoding); Index: src/Mp3/Util/Id3frames/Id3Frame.cs =================================================================== --- src/Mp3/Util/Id3frames/Id3Frame.cs (revision 48552) +++ src/Mp3/Util/Id3frames/Id3Frame.cs (working copy) @@ -31,23 +31,24 @@ */ using System; +using System.Text; using Entagged.Audioformats.Util; using Entagged.Audioformats.Mp3; namespace Entagged.Audioformats.Mp3.Util.Id3Frames { - public abstract class Id3Frame : TagField { + public abstract class Id3Frame { protected byte[] flags; protected byte version; public Id3Frame() { - this.version = Id3v2Tag.ID3V23; + this.version = Id3Tag.ID3V23; CreateDefaultFlags(); } public Id3Frame(byte[] raw, byte version) { byte[] rawNew; - if(version == Id3v2Tag.ID3V23) { + if(version == Id3Tag.ID3V23) { byte size = 2; if((raw[1]&0x80) == 0x80) { @@ -127,9 +128,9 @@ } protected byte[] IdBytes { - get { return System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(Id); } + get { return Encoding.GetEncoding("ISO-8859-1").GetBytes(Id); } } - + protected byte[] GetSize(int size) { byte[] b = new byte[4]; b[0] = (byte)( ( size >> 24 ) & 0xFF ); @@ -140,9 +141,9 @@ } protected string GetString(byte[]b, int offset, int length, string encoding) { - return new string(System.Text.Encoding.GetEncoding(encoding).GetChars(b, offset, length)); + return Encoding.GetEncoding(encoding).GetString(b, offset, length); } - + protected byte[] GetBytes(string s, string encoding) { return System.Text.Encoding.GetEncoding(encoding).GetBytes(s); } Index: src/Mp3/Util/Id3v23TagReader.cs =================================================================== --- src/Mp3/Util/Id3v23TagReader.cs (revision 48552) +++ src/Mp3/Util/Id3v23TagReader.cs (working copy) @@ -33,7 +33,9 @@ * */ +using System; using System.Collections; +using System.Text; using Entagged.Audioformats.Util; using Entagged.Audioformats.Mp3.Util.Id3Frames; @@ -46,66 +48,97 @@ InitConversionTable(); } - public Id3v2Tag Read(ByteBuffer data, bool[] ID3Flags, byte version) + public void Read(Id3Tag tag, ByteBuffer data, bool[] ID3Flags, byte version) { int tagSize = data.Limit; byte[] b; - Id3v2Tag tag = new Id3v2Tag(); //---------------------------------------------------------------------------- //Traitement en cas d'Header Etendu==true (A COMPLETER) - if (version == Id3v2Tag.ID3V23 && ID3Flags[1]) + if (version == Id3Tag.ID3V23 && ID3Flags[1]) ProcessExtendedHeader(data); //---------------------------------------------------------------------------- //Extraction des champs de texte - int specSize = (version == Id3v2Tag.ID3V22) ? 3 : 4; + int specSize = (version == Id3Tag.ID3V22) ? 3 : 4; for (int a = 0; a < tagSize; a++) { - //Nom de la Frame + // Frame name b = new byte[specSize]; if(data.Remaining <= specSize) break; - + data.Get(b); - - string field = new string(System.Text.Encoding.ASCII.GetChars(b)); + string field = Encoding.ASCII.GetString(b); if (b[0] == 0) break; - + //La longueur du texte contenu dans la Frame int frameSize = ReadInteger(data, version); - if ((frameSize > data.Remaining) || frameSize <= 0){ - //ignore empty frames + // Ignore empty frames + if ((frameSize > data.Remaining) || frameSize <= 0) break; - } - - b = new byte[ frameSize + ((version == Id3v2Tag.ID3V23) ? 2 : 0) ]; + + //string field = Encoding.ASCII.GetString(b); + if (field == "" || field.Length < 4 || field[0] != 'T' || field[1] == 'X') + continue; + + b = new byte[ frameSize + ((version == Id3Tag.ID3V23) ? 2 : 0) ]; data.Get(b); - - if( "" != field) { - Id3Frame f = CreateId3Frame(field, b, version); + + if(version == Id3Tag.ID3V22) + field = ConvertFromId3v22(field); + + // FIXME: We only deal with text/comment frames right now + if (field == "COMM") { + TextId3Frame f = new CommId3Frame(b, version); + tag.AddComment(f.Content); + } else if (field[0] == 'T' && field[1] != 'X') { + TextId3Frame f = new TextId3Frame(field, b, version); switch (field) { - case "TRCK": - if (!(f is TextId3Frame)) - break; + case "TCON": // genre + tag.AddGenre(TranslateGenre(f.Content)); + break; + + case "TRCK": // track number string num, count; - Utils.SplitTrackNumber(((TextId3Frame)f).Content, out num, out count); + Utils.SplitTrackNumber(f.Content, out num, out count); if (num != null) - tag.Add(new TextId3Frame(field, num)); + tag.AddTrack(num); if (count != null) - tag.Add(new TextId3Frame("EntaggedTrackCount", count)); + tag.AddTrackCount(count); break; default: - tag.Add(f); + tag.Add(field, f.Content); break; } } } - - return tag; } - + + private string TranslateGenre(string content) + { + if (content == null || content.Length == 0) + return null; + + // Written as "Name" ? + if (content[0] != '(') + return content; + + int pos = content.IndexOf(')'); + if (pos == -1) + return content; + + // Written as "(id)" ? + if (pos == content.Length - 1) { + int num = Convert.ToInt32(content.Substring(1, content.Length - 2)); + return TagGenres.Get(num); + } + + // Written as "(id)Name" ? + return content.Substring(pos + 1); + } + private void InitConversionTable() { @@ -155,28 +188,6 @@ this.conversion[v22[i]] = v23[i]; } - private Id3Frame CreateId3Frame(string field, byte[] data, byte version) - { - if(version == Id3v2Tag.ID3V22) - field = ConvertFromId3v22(field); - - if("" == field) - return null; - - //Text frames - if (field.StartsWith("T") && !field.StartsWith("TX")) { - return new TextId3Frame(field, data, version); - } - //Comment - else if (field.StartsWith("COMM")) - return new CommId3Frame(data, version); - else if (field.StartsWith("APIC")) - return new ApicId3Frame(data, version); - //Any other frame - else - return new GenericId3Frame(field, data, version); - } - private string ConvertFromId3v22(string field) { string s = this.conversion[field] as string; @@ -193,7 +204,7 @@ //TODO Verify that we have an syncsfe int byte[] exthead = new byte [4]; data.Get(exthead); - int extsize = ReadInteger(data, Id3v2Tag.ID3V23); + int extsize = ReadInteger(data, Id3Tag.ID3V23); // The extended header size includes those first four bytes. data.Position = data.Position + extsize; return extsize; @@ -203,7 +214,7 @@ { int value = 0; - if(version == Id3v2Tag.ID3V23) + if(version == Id3Tag.ID3V23) value += (bb.Get()& 0xFF) << 24; value += (bb.Get()& 0xFF) << 16; value += (bb.Get()& 0xFF) << 8; Index: src/AudioFile.cs =================================================================== --- src/AudioFile.cs (revision 48552) +++ src/AudioFile.cs (working copy) @@ -52,7 +52,7 @@ public AudioFile(EncodingInfo info) { this.info = info; - this.tag = new GenericTag(); + this.tag = new Tag(); } public int Bitrate { @@ -84,7 +84,7 @@ } public Tag Tag { - get { return (tag == null) ? new GenericTag() : tag; } + get { return (tag == null) ? new Tag() : tag; } } public EncodingInfo EncodingInfo Index: src/Ape/ApeTag.cs =================================================================== --- src/Ape/ApeTag.cs (revision 48552) +++ src/Ape/ApeTag.cs (working copy) @@ -1,98 +0,0 @@ -/*************************************************************************** - * Copyright 2005 Raphaël Slinckx - ****************************************************************************/ - -/* THIS FILE IS LICENSED UNDER THE MIT LICENSE AS OUTLINED IMMEDIATELY BELOW: - * - * 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. - */ - -/* - * $Log: ApeTag.cs,v $ - * Revision 1.3 2005/02/08 12:54:42 kikidonk - * Added cvs log and header - * - */ - -using System.IO; -using Entagged.Audioformats.Util; -using Entagged.Audioformats.Ape.Util; - -namespace Entagged.Audioformats.Ape { - public class ApeTag : AbstractTag { - - protected override string ArtistId { - get { return "Artist"; } - } - protected override string AlbumId { - get { return "Album"; } - } - protected override string TitleId { - get { return "Title"; } - } - protected override string TrackId { - get { return "Track"; } - } - protected override string TrackCountId { - get { return "EntaggedTrackCount"; } - } - protected override string YearId { - get { return "Year"; } - } - protected override string CommentId { - get { return "Comment"; } - } - protected override string GenreId { - get { return "Genre"; } - } - - protected override TagField CreateArtistField(string content) { - return new ApeTagTextField(ArtistId, content); - } - protected override TagField CreateAlbumField(string content) { - return new ApeTagTextField(AlbumId, content); - } - protected override TagField CreateTitleField(string content) { - return new ApeTagTextField(TitleId, content); - } - protected override TagField CreateTrackField(string content) { - return new ApeTagTextField(TrackId, content); - } - protected override TagField CreateTrackCountField(string content) { - return new ApeTagTextField(TrackCountId, content); - } - protected override TagField CreateYearField(string content) { - return new ApeTagTextField(YearId, content); - } - protected override TagField CreateCommentField(string content) { - return new ApeTagTextField(CommentId, content); - } - protected override TagField CreateGenreField(string content) { - return new ApeTagTextField(GenreId, content); - } - - protected override bool IsAllowedEncoding(string enc) { - return enc == "UTF-8"; - } - - public override string ToString() { - return "APE "+base.ToString(); - } - } -} Index: src/Ape/Util/ApeTagReader.cs =================================================================== --- src/Ape/Util/ApeTagReader.cs (revision 48552) +++ src/Ape/Util/ApeTagReader.cs (working copy) @@ -40,7 +40,7 @@ public Tag Read(Stream apeStream) { - ApeTag tag = new ApeTag(); + Tag tag = new Tag(); //Check wether the file contains an APE tag-------------------------------- apeStream.Seek( apeStream.Length - 32 , SeekOrigin.Begin); @@ -108,24 +108,24 @@ b = new byte[contentLength]; apeStream.Read( b , 0, b .Length); if(!binary) { - string content = new string(Encoding.UTF8.GetChars(b)); + string content = Encoding.UTF8.GetString(b); switch (field) { case "Track": string num, count; Utils.SplitTrackNumber(content, out num, out count); if (num != null) - tag.Add(new ApeTagTextField(field, num)); + tag.AddTrack(num); if (count != null) - tag.Add(new ApeTagTextField("EntaggedTrackCount", count)); + tag.AddTrackCount(count); break; default: - tag.Add(new ApeTagTextField(field, content)); + tag.Add(field, content); break; } - } else - tag.Add(new ApeTagBinaryField(field, b)); + } //else FIXME + // tag.Add(new ApeTagBinaryField(field, b)); } return tag; Index: src/Ape/Util/ApeTagField.cs =================================================================== --- src/Ape/Util/ApeTagField.cs (revision 48552) +++ src/Ape/Util/ApeTagField.cs (working copy) @@ -1,93 +0,0 @@ -/*************************************************************************** - * Copyright 2005 Raphaël Slinckx - ****************************************************************************/ - -/* THIS FILE IS LICENSED UNDER THE MIT LICENSE AS OUTLINED IMMEDIATELY BELOW: - * - * 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. - */ - -/* - * $Log: ApeTagField.cs,v $ - * Revision 1.3 2005/02/08 12:54:41 kikidonk - * Added cvs log and header - * - */ - -using Entagged.Audioformats.Util; - -namespace Entagged.Audioformats.Ape.Util { - public abstract class ApeTagField : TagField { - - private string id; - private bool binary; - - public ApeTagField(string id, bool binary) { - this.id = id; - this.binary = binary; - } - - public string Id { - get { return this.id; } - } - - public bool IsBinary { - get { return binary; } - set { this.binary = value; } - } - - public bool IsCommon { - get { - return id == "Title" || - id == "Album" || - id == "Artist" || - id == "Genre" || - id == "Track" || - id == "Year" || - id == "Comment"; - } - } - - protected void Copy(byte[] src, byte[] dst, int dstOffset) { - for(int i = 0; i> 24 ); - b[2] = (byte) ( ( size & 0x00FF0000 ) >> 16 ); - b[1] = (byte) ( ( size & 0x0000FF00 ) >> 8 ); - b[0] = (byte) ( size & 0x000000FF ); - return b; - } - - protected byte[] GetBytes(string s, string encoding) { - return System.Text.Encoding.GetEncoding(encoding).GetBytes(s); - } - - public abstract bool IsEmpty { - get; - } - public abstract void CopyContent(TagField field); - public abstract byte[] RawContent { - get; - } - } -} Index: src/Ape/Util/ApeTagTextField.cs =================================================================== --- src/Ape/Util/ApeTagTextField.cs (revision 48552) +++ src/Ape/Util/ApeTagTextField.cs (working copy) @@ -1,96 +0,0 @@ -/*************************************************************************** - * Copyright 2005 Raphaël Slinckx - ****************************************************************************/ - -/* THIS FILE IS LICENSED UNDER THE MIT LICENSE AS OUTLINED IMMEDIATELY BELOW: - * - * 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. - */ - -/* - * $Log: ApeTagTextField.cs,v $ - * Revision 1.3 2005/02/08 12:54:41 kikidonk - * Added cvs log and header - * - */ - -using Entagged.Audioformats.Util; - -namespace Entagged.Audioformats.Ape.Util { - public class ApeTagTextField : ApeTagField, TagTextField { - - private string content; - - public ApeTagTextField(string id, string content) : base(id, false) { - this.content = content; - } - - public override bool IsEmpty { - get { return this.content == ""; } - } - - public override string ToString() { - return this.content; - } - - public override void CopyContent(TagField field) { - if(field is ApeTagTextField) { - this.content = (field as ApeTagTextField).Content; - } - } - - public string Content { - get { return this.content; } - set { this.content = value; } - } - - public string Encoding { - get { return "UTF-8"; } - set { /* NA */ } - } - - public override byte[] RawContent - { - get { - byte[] idBytes = GetBytes(Id, "ISO-8859-1"); - byte[] contentBytes = GetBytes(content, Encoding); - byte[] buf = new byte[4 + 4 + idBytes.Length + 1 + contentBytes.Length]; - byte[] flags = {0x00,0x00,0x00,0x00}; - - int offset = 0; - Copy(GetSize(contentBytes.Length), buf, offset); - offset += 4; - - Copy(flags, buf, offset); - offset += 4; - - Copy(idBytes, buf, offset); - offset += idBytes.Length; - - buf[offset] = 0; - offset += 1; - - Copy(contentBytes, buf, offset); - offset += contentBytes.Length; - - return buf; - } - } - } -} Index: src/AudioFileWrapper.cs =================================================================== --- src/AudioFileWrapper.cs (revision 48552) +++ src/AudioFileWrapper.cs (working copy) @@ -107,73 +107,55 @@ public string[] Genres { - get { - return Utils.FieldListToStringArray(Tag.Genre); - } + get { return Utils.FieldListToStringArray(Tag.Genre); } } public string[] Titles { - get { - return Utils.FieldListToStringArray(Tag.Title); - } + get { return Utils.FieldListToStringArray(Tag.Title); } } public int[] TrackNumbers { - get { - return Utils.FieldListToIntArray(Tag.Track); - } + get { return Utils.FieldListToIntArray(Tag.Track); } } public int[] TrackCounts { - get { - return Utils.FieldListToIntArray(Tag.TrackCount); - } + get { return Utils.FieldListToIntArray(Tag.TrackCount); } } public int[] Years { - get { - return Utils.FieldListToIntArray(Tag.Year); - } + get { return Utils.FieldListToIntArray(Tag.Year); } } public string[] Albums { - get { - return Utils.FieldListToStringArray(Tag.Album); - } + get { return Utils.FieldListToStringArray(Tag.Album); } } public string[] Artists { - get { - return Utils.FieldListToStringArray(Tag.Artist); - } + get { return Utils.FieldListToStringArray(Tag.Artist); } } public string[] Comments { - get { - return Utils.FieldListToStringArray(Tag.Comment); - } + get { return Utils.FieldListToStringArray(Tag.Comment); } } public string Genre { get { - return Tag.Genre.Count > 0 ? - ((TagTextField)Tag.Genre[0]).Content : null; + return Tag.Genre.Count > 0 ? Tag.Genre[0] as string : null; } } public string Title { get { - return Tag.Title.Count > 0 ? - ((TagTextField)Tag.Title[0]).Content : null; + return Tag.Title.Count > 0 ? Tag.Title[0] as string : null; } } @@ -181,7 +163,7 @@ { get { try { - return Convert.ToInt32(((TagTextField)Tag.Track[0]).Content); + return Convert.ToInt32(Tag.Track[0] as string); } catch(Exception) { return 0; } @@ -192,7 +174,7 @@ { get { try { - return Convert.ToInt32(((TagTextField)Tag.TrackCount[0]).Content); + return Convert.ToInt32(Tag.TrackCount[0] as string); } catch(Exception) { return 0; } @@ -203,7 +185,7 @@ { get { try { - return Convert.ToInt32(((TagTextField)Tag.Year[0]).Content); + return Convert.ToInt32(Tag.Year[0] as string); } catch(Exception) { return 0; } @@ -213,53 +195,42 @@ public string Album { get { - return Tag.Album.Count > 0 ? - ((TagTextField)Tag.Album[0]).Content : null; + return Tag.Album.Count > 0 ? Tag.Album[0] as string : null; } } public string Artist { get { - return Tag.Artist.Count > 0 ? - ((TagTextField)Tag.Artist[0]).Content : null; + return Tag.Artist.Count > 0 ? Tag.Artist[0] as string : null; } } public string Comment { get { - return Tag.Comment.Count > 0 ? - ((TagTextField)Tag.Comment[0]).Content : null; + return Tag.Comment.Count > 0 ? Tag.Comment[0] as string : null; } } public Tag Tag { - get { - return afb.Tag; - } + get { return afb.Tag; } } public string Filename { - get { - return filename; - } + get { return filename; } } public string MimeType { - get { - return mimetype; - } + get { return mimetype; } } public EncodingInfo EncodingInfo { - get { - return afb.EncodingInfo; - } + get { return afb.EncodingInfo; } } public override string ToString() Index: src/Makefile.am =================================================================== --- src/Makefile.am (revision 48552) +++ src/Makefile.am (working copy) @@ -5,66 +5,75 @@ entaggedsharpdir=$(pkglibdir) entaggedsharp_SCRIPTS=$(ASSEMBLY) -ASSEMBLY_SOURCES = \ - $(srcdir)/AssemblyInfo.cs \ - $(srcdir)/Ape/ApeTag.cs \ +APE_CSFILES = \ $(srcdir)/Ape/MonkeyFileReader.cs \ - $(srcdir)/Ape/Util/ApeTagBinaryField.cs \ - $(srcdir)/Ape/Util/ApeTagField.cs \ $(srcdir)/Ape/Util/ApeTagReader.cs \ - $(srcdir)/Ape/Util/ApeTagTextField.cs \ $(srcdir)/Ape/Util/MonkeyDescriptor.cs \ $(srcdir)/Ape/Util/MonkeyHeader.cs \ $(srcdir)/Ape/Util/MonkeyInfoReader.cs \ $(srcdir)/Ape/Util/WavFormatHeader.cs \ - $(srcdir)/Ape/Util/WavRIFFHeader.cs \ - $(srcdir)/Exceptions/CannotReadException.cs \ + $(srcdir)/Ape/Util/WavRIFFHeader.cs + +FLAC_CSFILES = \ $(srcdir)/Flac/FlacFileReader.cs \ $(srcdir)/Flac/Util/FlacInfoReader.cs \ $(srcdir)/Flac/Util/FlacTagReader.cs \ $(srcdir)/Flac/Util/MetadataBlockDataStreamInfo.cs \ - $(srcdir)/Flac/Util/MetadataBlockHeader.cs \ - $(srcdir)/Util/AudioFileReader.cs \ - $(srcdir)/Util/ByteBuffer.cs \ - $(srcdir)/Util/CustomAttributes.cs \ - $(srcdir)/Util/TagField.cs \ - $(srcdir)/Util/Utils.cs \ + $(srcdir)/Flac/Util/MetadataBlockHeader.cs + +OGG_CSFILES = \ + $(srcdir)/Ogg/OggFileReader.cs \ + $(srcdir)/Ogg/OggTag.cs \ + $(srcdir)/Ogg/Util/OggTagReader.cs \ + $(srcdir)/Ogg/Util/VorbisTagReader.cs \ + $(srcdir)/Ogg/Util/OggInfoReader.cs \ + $(srcdir)/Ogg/Util/OggPageHeader.cs \ + $(srcdir)/Ogg/Util/VorbisCodecHeader.cs + +MPC_CSFILES = \ + $(srcdir)/Mpc/MpcFileReader.cs \ + $(srcdir)/Mpc/Util/MpcHeader.cs \ + $(srcdir)/Mpc/Util/MpcInfoReader.cs + +MP3_CSFILES = \ $(srcdir)/Mp3/Id3Tag.cs \ $(srcdir)/Mp3/Mp3FileReader.cs \ $(srcdir)/Mp3/Util/Id3frames/CommId3Frame.cs \ - $(srcdir)/Mp3/Util/Id3frames/GenericId3Frame.cs \ $(srcdir)/Mp3/Util/Id3frames/Id3Frame.cs \ $(srcdir)/Mp3/Util/Id3frames/TextId3Frame.cs \ - $(srcdir)/Mp3/Util/Id3frames/ApicId3Frame.cs \ - $(srcdir)/Mp3/Util/Id3v1TagReader.cs \ $(srcdir)/Mp3/Util/Id3v23TagReader.cs \ $(srcdir)/Mp3/Util/Id3v2TagReader.cs \ $(srcdir)/Mp3/Util/Id3v2TagSynchronizer.cs \ + $(srcdir)/Mp3/Util/Mp3InfoReader.cs \ + $(srcdir)/Mp3/Util/Id3v1TagReader.cs \ $(srcdir)/Mp3/Util/LameMPEGFrame.cs \ - $(srcdir)/Mp3/Util/Mp3InfoReader.cs \ $(srcdir)/Mp3/Util/MPEGFrame.cs \ - $(srcdir)/Mp3/Util/XingMPEGFrame.cs \ - $(srcdir)/Mpc/MpcFileReader.cs \ - $(srcdir)/Mpc/Util/MpcHeader.cs \ - $(srcdir)/Mpc/Util/MpcInfoReader.cs \ - $(srcdir)/Ogg/OggFileReader.cs \ - $(srcdir)/Ogg/OggTag.cs \ - $(srcdir)/Ogg/Util/OggInfoReader.cs \ - $(srcdir)/Ogg/Util/OggPageHeader.cs \ - $(srcdir)/Ogg/Util/OggTagField.cs \ - $(srcdir)/Ogg/Util/OggTagReader.cs \ - $(srcdir)/Ogg/Util/VorbisCodecHeader.cs \ - $(srcdir)/Ogg/Util/VorbisTagReader.cs \ + $(srcdir)/Mp3/Util/XingMPEGFrame.cs + +M4A_CSFILES = \ $(srcdir)/M4a/M4aFileReader.cs \ - $(srcdir)/M4a/M4aTag.cs \ $(srcdir)/M4a/Util/M4aInfoReader.cs \ - $(srcdir)/M4a/Util/M4aTagField.cs \ - $(srcdir)/M4a/Util/M4aTagReader.cs \ - $(srcdir)/Tag.cs \ + $(srcdir)/M4a/Util/M4aTagReader.cs + +ASSEMBLY_SOURCES = \ + $(srcdir)/AssemblyInfo.cs \ + $(srcdir)/Exceptions/CannotReadException.cs \ + $(srcdir)/Util/AudioFileReader.cs \ + $(srcdir)/Util/ByteBuffer.cs \ + $(srcdir)/Util/CustomAttributes.cs \ + $(srcdir)/Util/TagField.cs \ + $(srcdir)/Util/Utils.cs \ $(srcdir)/AudioFile.cs \ $(srcdir)/AudioFileIO.cs \ + $(srcdir)/AudioFileWrapper.cs \ $(srcdir)/EncodingInfo.cs \ - $(srcdir)/AudioFileWrapper.cs + $(srcdir)/Tag.cs \ + $(APE_CSFILES) \ + $(FLAC_CSFILES) \ + $(OGG_CSFILES) \ + $(MPC_CSFILES) \ + $(MP3_CSFILES) \ + $(M4a_CSFILES) all: $(ASSEMBLY) Index: src/Ogg/OggTag.cs =================================================================== --- src/Ogg/OggTag.cs (revision 48552) +++ src/Ogg/OggTag.cs (working copy) @@ -30,101 +30,30 @@ * */ +using System.Text; using Entagged.Audioformats.Util; using Entagged.Audioformats.Ogg.Util; namespace Entagged.Audioformats.Ogg { - public class OggTag : AbstractTag { + public class OggTag : Tag { - private string vendor = ""; - //This is the vendor string that will be written if no other is supplied - public const string DEFAULT_VENDOR = "Entagged - The Musical Box"; + public OggTag() + { + AddCommonFieldMapping(CommonField.Comment, "DESCRIPTION"); + AddCommonFieldMapping(CommonField.Track, "TRACKNUMBER"); + AddCommonFieldMapping(CommonField.TrackCount, "TRACKTOTAL"); + AddCommonFieldMapping(CommonField.Year, "DATE"); + } - protected override TagField CreateAlbumField(string content) { - return new OggTagField(AlbumId, content); - } - - protected override TagField CreateArtistField(string content) { - return new OggTagField(ArtistId, content); - } - - protected override TagField CreateCommentField(string content) { - return new OggTagField(CommentId, content); - } - - protected override TagField CreateGenreField(string content) { - return new OggTagField(GenreId, content); - } - - protected override TagField CreateTitleField(string content) { - return new OggTagField(TitleId, content); - } - - protected override TagField CreateTrackField(string content) { - return new OggTagField(TrackId, content); - } - - protected override TagField CreateTrackCountField(string content) { - return new OggTagField(TrackCountId, content); - } - - protected override TagField CreateYearField(string content) { - return new OggTagField(YearId, content); - } - - protected override string AlbumId { - get { return "ALBUM"; } - } - - protected override string ArtistId { - get { return "ARTIST"; } - } - - protected override string CommentId { - get { return "DESCRIPTION"; } - } - - protected override string GenreId { - get { return "GENRE"; } - } - - protected override string TitleId { - get { return "TITLE"; } - } - - protected override string TrackId { - get { return "TRACKNUMBER"; } - } - - protected override string TrackCountId { - get { return "TRACKTOTAL"; } + public void AddOggField(byte [] raw) + { + string field = new string(Encoding.UTF8.GetChars(raw)); + string[] splitField = field.Split('='); + if (splitField.Length > 1) + Add(splitField[0], splitField[1]); + else if (field.IndexOf('=') == -1) + Add("ERRONEOUS", field); } - protected override string YearId { - get { return "DATE"; } - } - - public string Vendor { - get { - if( this.vendor.Trim() != "" ) - return vendor; - - return DEFAULT_VENDOR; - } - set { - if(value == null) - this.vendor = ""; - else - this.vendor = value; - } - } - - protected override bool IsAllowedEncoding(string enc) { - return enc == "UTF-8"; - } - - public override string ToString() { - return "OGG " + base.ToString(); - } } } Index: src/Ogg/Util/OggTagReader.cs =================================================================== --- src/Ogg/Util/OggTagReader.cs (revision 48552) +++ src/Ogg/Util/OggTagReader.cs (working copy) @@ -31,6 +31,7 @@ */ using System.IO; +using System.Text; using Entagged.Audioformats.Util; namespace Entagged.Audioformats.Ogg.Util { @@ -45,8 +46,7 @@ int vendorstringLength = Utils.GetNumber( b, 0, 3); b = new byte[vendorstringLength]; oggStream.Read( b , 0, b .Length); - - tag.Vendor = new string( System.Text.Encoding.UTF8.GetChars(b) ); + tag.Add("vendor", new string(Encoding.UTF8.GetChars(b))); b = new byte[4]; oggStream.Read( b , 0, b .Length); @@ -56,11 +56,10 @@ b = new byte[4]; oggStream.Read( b , 0, b .Length); int commentLength = Utils.GetNumber( b, 0, 3); + b = new byte[commentLength]; oggStream.Read( b , 0, b .Length); - - OggTagField field = new OggTagField(b); - tag.Add(field); + tag.AddOggField(b); } return tag; Index: src/Ogg/Util/OggTagField.cs =================================================================== --- src/Ogg/Util/OggTagField.cs (revision 48552) +++ src/Ogg/Util/OggTagField.cs (working copy) @@ -1,154 +0,0 @@ -/*************************************************************************** - * Copyright 2005 Raphaël Slinckx - ****************************************************************************/ - -/* THIS FILE IS LICENSED UNDER THE MIT LICENSE AS OUTLINED IMMEDIATELY BELOW: - * - * 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. - */ - -/* - * $Log: OggTagField.cs,v $ - * Revision 1.3 2005/02/08 12:54:40 kikidonk - * Added cvs log and header - * - */ - -using Entagged.Audioformats.Util; - -namespace Entagged.Audioformats.Ogg.Util { - public class OggTagField : TagTextField { - - private bool common; - - private string content; - - private string id; - - public OggTagField(byte[] raw) - { - string field = new string(System.Text.Encoding.UTF8.GetChars(raw)); - string[] splitField = field.Split('='); - if (splitField.Length > 1) { - this.id = splitField[0].ToUpper(); - this.content = splitField[1]; - } else { - //Either we have "XXXXXXX" without "=" - //Or we have "XXXXXX=" with nothing after the "=" - int i = field.IndexOf("="); - if(i != -1) { - this.id = field.Substring(0, i+1); - this.content = ""; - } - else { - //Beware that ogg ID, must be capitalized and contain no space.. - this.id = "ERRONEOUS"; - this.content = field; - } - } - - CheckCommon(); - } - - public OggTagField(string fieldId, string fieldContent) { - this.id = fieldId.ToUpper(); - this.content = fieldContent; - CheckCommon(); - } - - private void CheckCommon() { - this.common = id == "TITLE" || id == "ALBUM" - || id == "ARTIST" || id == "GENRE" - || id == "TRACKNUMBER" || id == "DATE" - || id == "DESCRIPTION" || id == "COMMENT" - || id == "TRACK"; - } - - protected void Copy(byte[] src, byte[] dst, int dstOffset) { - for (int i = 0; i < src.Length; i++) - dst[i + dstOffset] = src[i]; - } - - public void CopyContent(TagField field) { - if (field is TagTextField) - this.content = (field as TagTextField).Content; - } - - protected byte[] GetBytes(string s, string encoding) { - return System.Text.Encoding.GetEncoding(encoding).GetBytes(s); - } - - public string Content { - get { return content; } - set { this.content = value; } - } - - public string Encoding { - get { return "UTF-8"; } - set { /* NA */ } - } - - public string Id { - get { return this.id; } - } - - public byte[] RawContent { - get { - byte[] size = new byte[4]; - byte[] idBytes = System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(this.id); - byte[] contentBytes = GetBytes(this.content, "UTF-8"); - byte[] b = new byte[4 + idBytes.Length + 1 + contentBytes.Length]; - - int length = idBytes.Length + 1 + contentBytes.Length; - size[3] = (byte) ((length & 0xFF000000) >> 24); - size[2] = (byte) ((length & 0x00FF0000) >> 16); - size[1] = (byte) ((length & 0x0000FF00) >> 8); - size[0] = (byte) (length & 0x000000FF); - - int offset = 0; - Copy(size, b, offset); - offset += 4; - Copy(idBytes, b, offset); - offset += idBytes.Length; - b[offset] = (byte) 0x3D; - offset++;// "=" - Copy(contentBytes, b, offset); - - return b; - } - } - - public bool IsBinary { - get { return false; } - set { /* NA */ } - } - - public bool IsCommon { - get { return common; } - } - - public bool IsEmpty { - get { return this.content == ""; } - } - - public override string ToString() { - return Content; - } - } -} Index: src/Util/Utils.cs =================================================================== --- src/Util/Utils.cs (revision 48552) +++ src/Util/Utils.cs (working copy) @@ -72,8 +72,8 @@ { string[] ret = new string[taglist.Count]; int i = 0; - foreach (TagTextField field in taglist) - ret[i++] = field.Content; + foreach (string field in taglist) + ret[i++] = field; return ret; } @@ -81,14 +81,14 @@ { int[] ret = new int[taglist.Count]; int i = 0; - foreach (TagTextField field in taglist) - ret[i++] = Convert.ToInt32(field.Content); + foreach (string field in taglist) + ret[i++] = Convert.ToInt32(field); return ret; } public static Tag CombineTags(params Tag[] tags) { - Tag ret = new GenericTag(); + Tag ret = new Tag(); foreach (Tag tag in tags) { if (tag == null) Index: ChangeLog =================================================================== --- ChangeLog (revision 48552) +++ ChangeLog (working copy) @@ -1,3 +1,12 @@ +2005-08-19 Daniel Drake + + * entagged-sharp: Lots of changes! + Removed Tag/GenericTag/AbstractTag abstraction, there is now just Tag. + Removed *TagField and *Tag abstraction, now just using strings and the + plain Tag class in the most part. All readers updated for the new model. + Fixed some minor reader bugs/omissions which means the tests now pass in + full. + 2005-08-18 Aaron Bockover * configure.ac: Entagged 0.1.4