public void TestTitle () { Id3v2.Tag tag = new Id3v2.Tag (); for (byte version = 2; version <= 4; version ++) { tag.Version = version; TagTestWithSave (ref tag, delegate (Id3v2.Tag t, string m) { Assert.IsTrue (t.IsEmpty, "Initial (IsEmpty): " + m); Assert.IsNull (t.Title, "Initial (Null): " + m); }); tag.Title = val_sing; TagTestWithSave (ref tag, delegate (Id3v2.Tag t, string m) { Assert.IsFalse (t.IsEmpty, "Value Set (!IsEmpty): " + m); Assert.AreEqual (val_sing, t.Title, "Value Set (!Null): " + m); }); tag.Title = string.Empty; TagTestWithSave (ref tag, delegate (Id3v2.Tag t, string m) { Assert.IsTrue (t.IsEmpty, "Value Cleared (IsEmpty): " + m); Assert.IsNull (t.Title, "Value Cleared (Null): " + m); }); } }
public TagLib.Tag AddTag(TagTypes type, TagLib.Tag copy) { TagLib.Tag tag = null; if (type == TagTypes.Id3v1) { tag = new TagLib.Id3v1.Tag(); } else if (type == TagTypes.Id3v2) { Id3v2.Tag tag32 = new Id3v2.Tag(); tag32.Version = 4; tag32.Flags |= Id3v2.HeaderFlags.FooterPresent; tag = tag32; } else if (type == TagTypes.Ape) { tag = new TagLib.Ape.Tag(); } if (tag != null) { if (copy != null) { copy.CopyTo(tag, true); } if (type == TagTypes.Id3v1) { AddTag(tag); } else { InsertTag(0, tag); } } return(tag); }
public override void RemoveTags(TagTypes types) { if (types == TagLib.TagTypes.Id3v2 || types == TagLib.TagTypes.AllTags) { tag = null; } }
/// <summary> /// Reads a tag starting at a specified position and moves the /// cursor to its start position. /// </summary> /// <param name="start"> /// A <see cref="long" /> value reference specifying at what /// position the potential tag starts. If a tag is found, /// this value will be updated to the position at which the /// found tag ends. /// </param> /// <returns> /// A <see cref="TagLibSharp.Tag" /> object representing the tag /// found at the specified position, or <see langword="null" /// /> if no tag was found. /// </returns> private TagLibSharp.Tag ReadTag(ref long start) { long end = start; TagTypes type = ReadTagInfo(ref end); TagLibSharp.Tag tag = null; try { switch (type) { case TagTypes.Ape: tag = new Ape.Tag(file, start); break; case TagTypes.Id3v2: tag = new Id3v2.Tag(file, start); break; } } catch (CorruptFileException e) { Console.Error.WriteLine("taglib-sharp caught exception creating tag: {0}", e); } start = end; return(tag); }
/// <summary> /// Adds a tag of a specified type to the current instance, /// optionally copying values from an existing type. /// </summary> /// <param name="type"> /// A <see cref="TagTypes" /> value specifying the type of /// tag to add to the current instance. At the time of this /// writing, this is limited to <see cref="TagTypes.Ape" /> /// and <see cref="TagTypes.Id3v2" />. /// </param> /// <param name="copy"> /// A <see cref="TagLibSharp.Tag" /> to copy values from using /// <see cref="TagLibSharp.Tag.CopyTo" />, or <see /// langword="null" /> if no tag is to be copied. /// </param> /// <returns> /// The <see cref="TagLibSharp.Tag" /> object added to the current /// instance, or <see langword="null" /> if it couldn't be /// created. /// </returns> /// <remarks> /// ID3v2 tags are added at the end of the current instance, /// while other tags are added to the beginning. /// </remarks> public TagLibSharp.Tag AddTag(TagTypes type, TagLibSharp.Tag copy) { TagLibSharp.Tag tag = null; if (type == TagTypes.Id3v2) { tag = new Id3v2.Tag(); } else if (type == TagTypes.Ape) { tag = new Ape.Tag(); (tag as Ape.Tag).HeaderPresent = true; } if (tag != null) { if (copy != null) { copy.CopyTo(tag, true); } AddTag(tag); } return(tag); }
public void TestAlbumArtists () { Id3v2.Tag tag = new Id3v2.Tag (); for (byte version = 2; version <= 4; version ++) { tag.Version = version; TagTestWithSave (ref tag, delegate (Id3v2.Tag t, string m) { Assert.IsTrue (t.IsEmpty, "Initial (IsEmpty): " + m); Assert.AreEqual (0, t.AlbumArtists.Length, "Initial (Zero): " + m); }); tag.AlbumArtists = val_mult; TagTestWithSave (ref tag, delegate (Id3v2.Tag t, string m) { Assert.IsFalse (t.IsEmpty, "Value Set (!IsEmpty): " + m); Assert.AreEqual (val_mult.Length, t.AlbumArtists.Length, "Value Set: " + m); for (int i = 0; i < val_mult.Length; i ++) { Assert.AreEqual (val_mult [i], t.AlbumArtists [i], "Value Set: " + m); } }); tag.AlbumArtists = new string [0]; TagTestWithSave (ref tag, delegate (Id3v2.Tag t, string m) { Assert.IsTrue (t.IsEmpty, "Value Cleared (IsEmpty): " + m); Assert.AreEqual (0, t.AlbumArtists.Length, "Value Cleared (Zero): " + m); }); } }
/// <summary> /// Reads a tag ending at a specified position and moves the /// cursor to its start position. /// </summary> /// <param name="end"> /// A <see cref="long" /> value reference specifying at what /// position the potential tag ends at. If a tag is found, /// this value will be updated to the position at which the /// found tag starts. /// </param> /// <returns> /// A <see cref="TagLibSharp.Tag" /> object representing the tag /// found at the specified position, or <see langword="null" /// /> if no tag was found. /// </returns> private TagLibSharp.Tag ReadTag(ref long end) { long start = end; TagTypes type = ReadTagInfo(ref start); TagLibSharp.Tag tag = null; try { switch (type) { case TagTypes.Ape: tag = new Ape.Tag(file, end - Footer.Size); break; case TagTypes.Id3v2: tag = new Id3v2.Tag(file, start); break; case TagTypes.Id3v1: tag = new Id3v1.Tag(file, start); break; } end = start; } catch (CorruptFileException) { } return(tag); }
/// <summary> /// Reads the contents of the current instance determining /// the size of the dsf data, the area the tagging is in, /// and optionally reading in the tags and media properties. /// </summary> /// <param name="read_tags"> /// If <see langword="true" />, any tags found will be read /// into the current instance. /// </param> /// <param name="style"> /// A <see cref="ReadStyle"/> value specifying how the media /// data is to be read into the current instance. /// </param> /// <param name="dsf_size"> /// A <see cref="uint"/> value reference to be filled with /// the size of the RIFF data as read from the file. /// </param> /// <param name="tag_start"> /// A <see cref="long" /> value reference to be filled with /// the absolute seek position at which the tagging data /// starts. /// </param> /// <param name="tag_end"> /// A <see cref="long" /> value reference to be filled with /// the absolute seek position at which the tagging data /// ends. /// </param> /// <exception cref="CorruptFileException"> /// The file does not begin with <see cref="FileIdentifier" /// />. /// </exception> private void Read(bool read_tags, ReadStyle style, out uint dsf_size, out long tag_start, out long tag_end) { Seek(0); if (ReadBlock(4) != FileIdentifier) { throw new CorruptFileException( "File does not begin with DSF identifier"); } Seek(12); dsf_size = ReadBlock(8).ToUInt(false); tag_start = (long)ReadBlock(8).ToULong(false); tag_end = -1; // Get the properties of the file if (header_block == null && style != ReadStyle.None) { long fmt_chunk_pos = Find(FormatIdentifier, 0); if (fmt_chunk_pos == -1) { throw new CorruptFileException( "No Format chunk available in DSF file."); } Seek(fmt_chunk_pos); header_block = ReadBlock((int)StreamHeader.Size); StreamHeader header = new StreamHeader(header_block, dsf_size); properties = new Properties(TimeSpan.Zero, header); } // Now position to the ID3 chunk, which we read before if (tag_start > 0) { Seek(tag_start); if (ReadBlock(3) == ID3Identifier) { if (read_tags && tag == null) { tag = new Id3v2.Tag(this, tag_start, style); } // Get the length of the tag out of the ID3 chunk Seek(tag_start + 6); uint tag_size = SynchData.ToUInt(ReadBlock(4)) + 10; InvariantStartPosition = tag_start; tag_end = InvariantEndPosition = tag_start + tag_size; } } }
private void Read(bool read_tags, ReadStyle style, out uint aiff_size, out long tag_start, out long tag_end) { Seek(0); if (ReadBlock(4) != FileIdentifier) { throw new CorruptFileException("File does not begin with AIFF identifier"); } aiff_size = ReadBlock(4).ToUInt(true); tag_start = -1; tag_end = -1; if (header_block == null && style != ReadStyle.None) { long common_chunk_pos = Find(CommIdentifier, 0); if (common_chunk_pos == -1) { throw new CorruptFileException("No Common chunk available in AIFF file."); } Seek(common_chunk_pos); header_block = ReadBlock((int)StreamHeader.Size); StreamHeader header = new StreamHeader(header_block, aiff_size); properties = new Properties(TimeSpan.Zero, header); } long id3_chunk_pos = -1; long sound_chunk_pos = Find(SoundIdentifier, 0, ID3Identifier); if (sound_chunk_pos == -1) { id3_chunk_pos = Find(ID3Identifier, 0); } sound_chunk_pos = Find(SoundIdentifier, 0); if (sound_chunk_pos == -1) { throw new CorruptFileException("No Sound chunk available in AIFF file."); } Seek(sound_chunk_pos + 4); ulong sound_chunk_length = ReadBlock(4).ToULong(true); long start_search_pos = (long)sound_chunk_length + sound_chunk_pos + 4; if (id3_chunk_pos == -1) { id3_chunk_pos = Find(ID3Identifier, start_search_pos); } if (id3_chunk_pos > -1) { if (read_tags && tag == null) { tag = new Id3v2.Tag(this, id3_chunk_pos + 8); } Seek(id3_chunk_pos + 4); uint tag_size = ReadBlock(4).ToUInt(true) + 8; tag_start = InvariantStartPosition = id3_chunk_pos; tag_end = InvariantEndPosition = tag_start + tag_size; } }
/// <summary> /// Gets a tag of a specified type from the current instance, /// optionally creating a new tag if possible. /// </summary> /// <param name="type"> /// A <see cref="TagLib.TagTypes" /> value indicating the /// type of tag to read. /// </param> /// <param name="create"> /// A <see cref="bool" /> value specifying whether or not to /// try and create the tag if one is not found. /// </param> /// <returns> /// A <see cref="Tag" /> object containing the tag that was /// found in or added to the current instance. If no /// matching tag was found and none was created, <see /// langword="null" /> is returned. /// </returns> public override TagLib.Tag GetTag(TagTypes type, bool create) { TagLib.Tag tag = null; switch (type) { case TagTypes.Id3v2: if (id32_tag == null && create) { id32_tag = new Id3v2.Tag(); id32_tag.Version = 4; id32_tag.Flags |= Id3v2.HeaderFlags .FooterPresent; this.tag.CopyTo(id32_tag, true); } tag = id32_tag; break; case TagTypes.RiffInfo: if (info_tag == null && create) { info_tag = new InfoTag(); this.tag.CopyTo(info_tag, true); } tag = info_tag; break; case TagTypes.MovieId: if (mid_tag == null && create) { mid_tag = new MovieIdTag(); this.tag.CopyTo(mid_tag, true); } tag = mid_tag; break; case TagTypes.DivX: if (divx_tag == null && create) { divx_tag = new DivXTag(); this.tag.CopyTo(divx_tag, true); } tag = divx_tag; break; } this.tag.SetTags(id32_tag, info_tag, mid_tag, divx_tag); return(tag); }
public override TagLib.Tag GetTag(TagTypes type, bool create) { TagLib.Tag id32_tag = null; switch (type) { case TagTypes.Id3v2: if (tag == null && create) { tag = new Id3v2.Tag(); tag.Version = 2; } id32_tag = tag; break; } return(id32_tag); }
public override void RemoveTags(TagTypes types) { if ((types & TagLib.TagTypes.Id3v2) != TagLib.TagTypes.None) { id32_tag = null; } if ((types & TagLib.TagTypes.RiffInfo) != TagLib.TagTypes.None) { info_tag = null; } if ((types & TagLib.TagTypes.MovieId) != TagLib.TagTypes.None) { mid_tag = null; } if ((types & TagLib.TagTypes.DivX) != TagLib.TagTypes.None) { divx_tag = null; } tag.SetTags(id32_tag, info_tag, mid_tag, divx_tag); }
/// <summary> /// Gets a tag of a specified type from the current instance, /// optionally creating a new tag if possible. /// </summary> /// <param name="type"> /// A <see cref="TagLib.TagTypes" /> value indicating the /// type of tag to read. /// </param> /// <param name="create"> /// A <see cref="bool" /> value specifying whether or not to /// try and create the tag if one is not found. /// </param> /// <returns> /// A <see cref="Tag" /> object containing the tag that was /// found in or added to the current instance. If no /// matching tag was found and none was created, <see /// langword="null" /> is returned. /// </returns> public override TagLib.Tag GetTag(TagTypes type, bool create) { TagLib.Tag id32_tag = null; switch (type) { case TagTypes.Id3v2: if (tag == null && create) { tag = new Id3v2.Tag(); tag.Version = 2; } id32_tag = tag; break; } return id32_tag; }
private void Read(bool read_tags, ReadStyle style, out uint riff_size, out long tag_start, out long tag_end) { Seek(0); if (ReadBlock(4) != FileIdentifier) { throw new CorruptFileException("File does not begin with RIFF identifier"); } riff_size = ReadBlock(4).ToUInt(false); ByteVector stream_format = ReadBlock(4); tag_start = -1; tag_end = -1; long position = 12; long length = Length; TimeSpan duration = TimeSpan.Zero; ICodec[] codecs = new ICodec [0]; do { bool tag_found = false; Seek(position); string fourcc = ReadBlock(4).ToString(StringType.UTF8); uint size = ReadBlock(4).ToUInt(false); switch (fourcc) { case "fmt ": if (stream_format == "WAVE" && style != ReadStyle.None) { Seek(position + 8); codecs = new ICodec [] { new WaveFormatEx(ReadBlock(18), 0) }; } break; case "data": if (stream_format == "WAVE") { if (style != ReadStyle.None && codecs.Length == 1 && codecs [0] is WaveFormatEx) { duration += TimeSpan.FromSeconds((double)size / (double)((WaveFormatEx)codecs [0]).AverageBytesPerSecond); } InvariantStartPosition = position; InvariantEndPosition = position + size; } break; case "LIST": { switch (ReadBlock(4).ToString(StringType.UTF8)) { case "hdrl": if (stream_format == "AVI " && style != ReadStyle.None) { AviHeaderList header_list = new AviHeaderList(this, position + 12, (int)(size - 4)); duration = header_list.Header.Duration; codecs = header_list.Codecs; } break; case "INFO": { if (read_tags && info_tag == null) { info_tag = new InfoTag(this, position + 12, (int)(size - 4)); } tag_found = true; break; } case "MID ": if (read_tags && mid_tag == null) { mid_tag = new MovieIdTag(this, position + 12, (int)(size - 4)); } tag_found = true; break; case "movi": if (stream_format == "AVI ") { InvariantStartPosition = position; InvariantEndPosition = position + size; } break; } break; } case "ID32": if (read_tags && id32_tag == null) { id32_tag = new Id3v2.Tag(this, position + 8); } tag_found = true; break; case "IDVX": if (read_tags && divx_tag == null) { divx_tag = new DivXTag(this, position + 8); } tag_found = true; break; case "JUNK": if (tag_end == position) { tag_end = position + 8 + size; } break; } if (tag_found) { if (tag_start == -1) { tag_start = position; tag_end = position + 8 + size; } else if (tag_end == position) { tag_end = position + 8 + size; } } position += 8 + size; }while (position + 8 < length); if (style != ReadStyle.None) { if (codecs.Length == 0) { throw new UnsupportedFormatException("Unsupported RIFF type."); } properties = new Properties(duration, codecs); } if (read_tags) { tag.SetTags(id32_tag, info_tag, mid_tag, divx_tag); } }
private void Read (bool read_tags, ReadStyle style, out uint riff_size, out long tag_start, out long tag_end) { Seek (0); if (ReadBlock (4) != FileIdentifier) throw new CorruptFileException ("File does not begin with RIFF identifier"); riff_size = ReadBlock (4).ToUInt (false); ByteVector stream_format = ReadBlock (4); tag_start = -1; tag_end = -1; long position = 12; long length = Length; TimeSpan duration = TimeSpan.Zero; ICodec[] codecs = new ICodec [0]; do { bool tag_found = false; Seek (position); string fourcc = ReadBlock (4).ToString (StringType.UTF8); uint size = ReadBlock (4).ToUInt (false); switch (fourcc) { case "fmt ": if (stream_format == "WAVE" && style != ReadStyle.None) { Seek (position + 8); codecs = new ICodec [] {new WaveFormatEx (ReadBlock (18), 0)}; } break; case "data": if (stream_format == "WAVE") { if (style != ReadStyle.None && codecs.Length == 1 && codecs [0] is WaveFormatEx) duration += TimeSpan.FromSeconds ((double) size / (double) ((WaveFormatEx) codecs [0]).AverageBytesPerSecond); InvariantStartPosition = position; InvariantEndPosition = position + size; } break; case "LIST": { switch (ReadBlock (4).ToString (StringType.UTF8)) { case "hdrl": if (stream_format == "AVI " && style != ReadStyle.None) { AviHeaderList header_list = new AviHeaderList (this, position + 12, (int) (size - 4)); duration = header_list.Header.Duration; codecs = header_list.Codecs; } break; case "INFO": { if (read_tags && info_tag == null) info_tag = new InfoTag (this, position + 12, (int) (size - 4)); tag_found = true; break; } case "MID ": if (read_tags && mid_tag == null) mid_tag = new MovieIdTag (this, position + 12, (int) (size - 4)); tag_found = true; break; case "movi": if (stream_format == "AVI ") { InvariantStartPosition = position; InvariantEndPosition = position + size; } break; } break; } case "ID32": if (read_tags && id32_tag == null) id32_tag = new Id3v2.Tag (this, position + 8); tag_found = true; break; case "IDVX": if (read_tags && divx_tag == null) divx_tag = new DivXTag (this, position + 8); tag_found = true; break; case "JUNK": if (tag_end == position) tag_end = position + 8 + size; break; } if (tag_found) { if (tag_start == -1) { tag_start = position; tag_end = position + 8 + size; } else if (tag_end == position) tag_end = position + 8 + size; } position += 8 + size; } while (position + 8 < length); if (style != ReadStyle.None) { if (codecs.Length == 0) throw new UnsupportedFormatException ("Unsupported RIFF type."); properties = new Properties (duration, codecs); } if (read_tags) tag.SetTags (id32_tag, info_tag, mid_tag, divx_tag); }
/// <summary> /// Reads the contents of the current instance determining /// the size of the dsf data, the area the tagging is in, /// and optionally reading in the tags and media properties. /// </summary> /// <param name="read_tags"> /// If <see langword="true" />, any tags found will be read /// into the current instance. /// </param> /// <param name="style"> /// A <see cref="ReadStyle"/> value specifying how the media /// data is to be read into the current instance. /// </param> /// <param name="dsf_size"> /// A <see cref="uint"/> value reference to be filled with /// the size of the RIFF data as read from the file. /// </param> /// <param name="tag_start"> /// A <see cref="long" /> value reference to be filled with /// the absolute seek position at which the tagging data /// starts. /// </param> /// <param name="tag_end"> /// A <see cref="long" /> value reference to be filled with /// the absolute seek position at which the tagging data /// ends. /// </param> /// <exception cref="CorruptFileException"> /// The file does not begin with <see cref="FileIdentifier" /// />. /// </exception> private void Read(bool read_tags, ReadStyle style, out uint dsf_size, out long tag_start, out long tag_end) { Seek(0); if (ReadBlock(4) != FileIdentifier) throw new CorruptFileException( "File does not begin with DSF identifier"); Seek(12); dsf_size = ReadBlock(8).ToUInt(false); tag_start = (long)ReadBlock(8).ToULong(false); tag_end = -1; // Get the properties of the file if (header_block == null && style != ReadStyle.None) { long fmt_chunk_pos = Find(FormatIdentifier, 0); if (fmt_chunk_pos == -1) { throw new CorruptFileException( "No Format chunk available in DSF file."); } Seek(fmt_chunk_pos); header_block = ReadBlock((int) StreamHeader.Size); StreamHeader header = new StreamHeader(header_block, dsf_size); properties = new Properties(TimeSpan.Zero, header); } // Now position to the ID3 chunk, which we read before if (tag_start > 0) { Seek(tag_start); if (ReadBlock(3) == ID3Identifier) { if (read_tags && tag == null) { tag = new Id3v2.Tag(this, tag_start); } // Get the length of the tag out of the ID3 chunk Seek(tag_start + 6); uint tag_size = SynchData.ToUInt(ReadBlock(4)) + 10; InvariantStartPosition = tag_start; tag_end = InvariantEndPosition = tag_start + tag_size; } } }
public void TestPictures () { Id3v2.Tag tag = new Id3v2.Tag (); Picture [] pictures = new Picture [] { new Picture ("../examples/covers/sample_a.png"), new Picture ("../examples/covers/sample_a.jpg"), new Picture ("../examples/covers/sample_b.png"), new Picture ("../examples/covers/sample_b.jpg"), new Picture ("../examples/covers/sample_c.png"), new Picture ("../examples/covers/sample_c.jpg") }; for (int i = 0; i < 6; i ++) pictures [i].Type = (PictureType) (i * 2); pictures [3].Description = val_sing; for (byte version = 2; version <= 4; version ++) { tag.Version = version; TagTestWithSave (ref tag, delegate (Id3v2.Tag t, string m) { Assert.IsTrue (t.IsEmpty, "Initial (IsEmpty): " + m); Assert.AreEqual (0, t.Pictures.Length, "Initial (Zero): " + m); }); tag.Pictures = pictures; TagTestWithSave (ref tag, delegate (Id3v2.Tag t, string m) { Assert.IsFalse (t.IsEmpty, "Value Set (!IsEmpty): " + m); Assert.AreEqual (pictures.Length, t.Pictures.Length, "Value Set: " + m); for (int i = 0; i < pictures.Length; i ++) { string msg = "Value " + i + "Set: " + m; Assert.AreEqual (pictures [i].Data, t.Pictures [i].Data, msg); Assert.AreEqual (pictures [i].Type, t.Pictures [i].Type, msg); Assert.AreEqual (pictures [i].Description, t.Pictures [i].Description, msg); Assert.AreEqual (pictures [i].MimeType, t.Pictures [i].MimeType, msg); } }); tag.Pictures = new Picture [0]; TagTestWithSave (ref tag, delegate (Id3v2.Tag t, string m) { Assert.IsTrue (t.IsEmpty, "Value Cleared (IsEmpty): " + m); Assert.AreEqual (0, t.Pictures.Length, "Value Cleared (Zero): " + m); }); } }
/// <summary> /// Removes a set of tag types from the current instance. /// </summary> /// <param name="types"> /// A bitwise combined <see cref="TagLib.TagTypes" /> value /// containing tag types to be removed from the file. /// </param> /// <remarks> /// In order to remove all tags from a file, pass <see /// cref="TagTypes.AllTags" /> as <paramref name="types" />. /// </remarks> public override void RemoveTags(TagTypes types) { if ((types & TagLib.TagTypes.Id3v2) != TagLib.TagTypes.None) id32_tag = null; if ((types & TagLib.TagTypes.RiffInfo) != TagLib.TagTypes.None) info_tag = null; if ((types & TagLib.TagTypes.MovieId) != TagLib.TagTypes.None) mid_tag = null; if ((types & TagLib.TagTypes.DivX) != TagLib.TagTypes.None) divx_tag = null; tag.SetTags (id32_tag, info_tag, mid_tag, divx_tag); }
/// <summary> /// Reads the contents of the current instance determining /// the size of the riff data, the area the tagging is in, /// and optionally reading in the tags and media properties. /// </summary> /// <param name="read_tags"> /// If <see langword="true" />, any tags found will be read /// into the current instance. /// </param> /// <param name="style"> /// A <see cref="ReadStyle"/> value specifying how the media /// data is to be read into the current instance. /// </param> /// <param name="aiff_size"> /// A <see cref="uint"/> value reference to be filled with /// the size of the RIFF data as read from the file. /// </param> /// <param name="tag_start"> /// A <see cref="long" /> value reference to be filled with /// the absolute seek position at which the tagging data /// starts. /// </param> /// <param name="tag_end"> /// A <see cref="long" /> value reference to be filled with /// the absolute seek position at which the tagging data /// ends. /// </param> /// <exception cref="CorruptFileException"> /// The file does not begin with <see cref="FileIdentifier" /// />. /// </exception> private void Read(bool read_tags, ReadStyle style, out uint aiff_size, out long tag_start, out long tag_end) { Seek(0); if (ReadBlock(4) != FileIdentifier) { throw new CorruptFileException( "File does not begin with AIFF identifier"); } aiff_size = ReadBlock(4).ToUInt(true); tag_start = -1; tag_end = -1; // Get the properties of the file if (header_block == null && style != ReadStyle.None) { long common_chunk_pos = Find(CommIdentifier, 0); if (common_chunk_pos == -1) { throw new CorruptFileException( "No Common chunk available in AIFF file."); } Seek(common_chunk_pos); header_block = ReadBlock((int)StreamHeader.Size); StreamHeader header = new StreamHeader(header_block, aiff_size); properties = new Properties(TimeSpan.Zero, header); } // Now we search for the ID3 chunk. // Normally it appears after the Sound data chunk. But as the order of // chunks is free, it might be the case that the ID3 chunk appears before // the sound data chunk. // So we search first for the Sound data chunk and see, if an ID3 chunk appears before long id3_chunk_pos = -1; long sound_chunk_pos = Find(SoundIdentifier, 0, ID3Identifier); if (sound_chunk_pos == -1) { // The ID3 chunk appears before the Sound chunk id3_chunk_pos = Find(ID3Identifier, 0); } // Now let's look for the Sound chunk again // Since a previous return value of -1 does mean, that the ID3 chunk was found first sound_chunk_pos = Find(SoundIdentifier, 0); if (sound_chunk_pos == -1) { throw new CorruptFileException( "No Sound chunk available in AIFF file."); } // Get the length of the Sound chunk and use this as a start value to look for the ID3 chunk Seek(sound_chunk_pos + 4); ulong sound_chunk_length = ReadBlock(4).ToULong(true); long start_search_pos = (long)sound_chunk_length + sound_chunk_pos + 4; if (id3_chunk_pos == -1) { id3_chunk_pos = Find(ID3Identifier, start_search_pos); } if (id3_chunk_pos > -1) { if (read_tags && tag == null) { tag = new Id3v2.Tag(this, id3_chunk_pos + 8); } // Get the length of the tag out of the ID3 chunk Seek(id3_chunk_pos + 4); uint tag_size = ReadBlock(4).ToUInt(true) + 8; tag_start = InvariantStartPosition = id3_chunk_pos; tag_end = InvariantEndPosition = tag_start + tag_size; } }
/// <summary> /// Reads the contents of the current instance determining /// the size of the riff data, the area the tagging is in, /// and optionally reading in the tags and media properties. /// </summary> /// <param name="read_tags"> /// If <see langword="true" />, any tags found will be read /// into the current instance. /// </param> /// <param name="style"> /// A <see cref="ReadStyle"/> value specifying how the media /// data is to be read into the current instance. /// </param> /// <param name="aiff_size"> /// A <see cref="uint"/> value reference to be filled with /// the size of the RIFF data as read from the file. /// </param> /// <param name="tag_start"> /// A <see cref="long" /> value reference to be filled with /// the absolute seek position at which the tagging data /// starts. /// </param> /// <param name="tag_end"> /// A <see cref="long" /> value reference to be filled with /// the absolute seek position at which the tagging data /// ends. /// </param> /// <exception cref="CorruptFileException"> /// The file does not begin with <see cref="FileIdentifier" /// />. /// </exception> private void Read(bool read_tags, ReadStyle style, out uint aiff_size, out long tag_start, out long tag_end) { Seek(0); if (ReadBlock(4) != FileIdentifier) { throw new CorruptFileException( "File does not begin with AIFF identifier"); } aiff_size = ReadBlock(4).ToUInt(true); tag_start = -1; tag_end = -1; // Check formType if (ReadBlock(4) != AIFFFormType) { throw new CorruptFileException( "File form type is not AIFF"); } long formBlockChunksPosition = Tell; // Get the properties of the file if (header_block == null && style != ReadStyle.None) { long common_chunk_pos = FindChunk(CommIdentifier, formBlockChunksPosition); if (common_chunk_pos == -1) { throw new CorruptFileException( "No Common chunk available in AIFF file."); } Seek(common_chunk_pos); header_block = ReadBlock((int)StreamHeader.Size); StreamHeader header = new StreamHeader(header_block, aiff_size); properties = new Properties(TimeSpan.Zero, header); } // Search for the ID3 chunk long id3_chunk_pos = FindChunk(ID3Identifier, formBlockChunksPosition); // Search for the sound chunk long sound_chunk_pos = FindChunk(SoundIdentifier, formBlockChunksPosition); // Ensure there is a sound chunk for the file to be valid if (sound_chunk_pos == -1) { throw new CorruptFileException( "No Sound chunk available in AIFF file."); } // Get the length of the Sound chunk and use this as a start value to look for the ID3 chunk Seek(sound_chunk_pos + 4); // Read the id3 chunk if (id3_chunk_pos > -1) { if (read_tags && tag == null) { tag = new Id3v2.Tag(this, id3_chunk_pos + 8); } // Get the length of the tag out of the ID3 chunk Seek(id3_chunk_pos + 4); uint tag_size = ReadBlock(4).ToUInt(true) + 8; tag_start = InvariantStartPosition = id3_chunk_pos; tag_end = InvariantEndPosition = tag_start + tag_size; } }
/// <summary> /// Reads the contents of the current instance determining /// the size of the riff data, the area the tagging is in, /// and optionally reading in the tags and media properties. /// </summary> /// <param name="read_tags"> /// If <see langword="true" />, any tags found will be read /// into the current instance. /// </param> /// <param name="style"> /// A <see cref="ReadStyle"/> value specifying how the media /// data is to be read into the current instance. /// </param> /// <param name="riff_size"> /// A <see cref="uint"/> value reference to be filled with /// the size of the RIFF data as read from the file. /// </param> /// <param name="tag_start"> /// A <see cref="long" /> value reference to be filled with /// the absolute seek position at which the tagging data /// starts. /// </param> /// <param name="tag_end"> /// A <see cref="long" /> value reference to be filled with /// the absolute seek position at which the tagging data /// ends. /// </param> /// <exception cref="CorruptFileException"> /// The file does not begin with <see cref="FileIdentifier" /// />. /// </exception> private void Read(bool read_tags, ReadStyle style, out uint riff_size, out long tag_start, out long tag_end) { Seek(0); if (ReadBlock(4) != FileIdentifier) { throw new CorruptFileException( "File does not begin with RIFF identifier"); } riff_size = ReadBlock(4).ToUInt(false); ByteVector stream_format = ReadBlock(4); tag_start = -1; tag_end = -1; long position = 12; long length = Length; uint size = 0; TimeSpan duration = TimeSpan.Zero; ICodec [] codecs = new ICodec [0]; // Read until there are less than 8 bytes to read. do { bool tag_found = false; Seek(position); string fourcc = ReadBlock(4).ToString(StringType.UTF8); size = ReadBlock(4).ToUInt(false); switch (fourcc) { // "fmt " is used by Wave files to hold the // WaveFormatEx structure. case "fmt ": if (style == ReadStyle.None || stream_format != "WAVE") { break; } Seek(position + 8); codecs = new ICodec [] { new WaveFormatEx(ReadBlock(18), 0) }; break; // "data" contains the audio data for wave // files. It's contents represent the invariant // portion of the file and is used to determine // the duration of a file. It should always // appear after "fmt ". case "data": if (stream_format != "WAVE") { break; } InvariantStartPosition = position; InvariantEndPosition = position + size; if (style == ReadStyle.None || codecs.Length != 1 || !(codecs [0] is WaveFormatEx)) { break; } duration += TimeSpan.FromSeconds( (double)size / (double) ((WaveFormatEx)codecs [0]) .AverageBytesPerSecond); break; // Lists are used to store a variety of data // collections. Read the type and act on it. case "LIST": { switch (ReadBlock(4).ToString(StringType.UTF8)) { // "hdlr" is used by AVI files to hold // a media header and BitmapInfoHeader // and WaveFormatEx structures. case "hdrl": if (style == ReadStyle.None || stream_format != "AVI ") { continue; } AviHeaderList header_list = new AviHeaderList(this, position + 12, (int)(size - 4)); duration = header_list.Header.Duration; codecs = header_list.Codecs; break; // "INFO" is a tagging format handled by // the InfoTag class. case "INFO": if (read_tags && info_tag == null) { info_tag = new InfoTag( this, position + 12, (int)(size - 4)); } tag_found = true; break; // "MID " is a tagging format handled by // the MovieIdTag class. case "MID ": if (read_tags && mid_tag == null) { mid_tag = new MovieIdTag( this, position + 12, (int)(size - 4)); } tag_found = true; break; // "movi" contains the media data for // and AVI and its contents represent // the invariant portion of the file. case "movi": if (stream_format != "AVI ") { break; } InvariantStartPosition = position; InvariantEndPosition = position + size; break; } break; } // "ID32" is a custom box for this format that // contains an ID3v2 tag. case "ID32": if (read_tags && id32_tag == null) { id32_tag = new Id3v2.Tag(this, position + 8); } tag_found = true; break; // "IDVX" is used by DivX and holds an ID3v1- // style tag. case "IDVX": if (read_tags && divx_tag == null) { divx_tag = new DivXTag(this, position + 8); } tag_found = true; break; // "JUNK" is a padding element that could be // associated with tag data. case "JUNK": if (tag_end == position) { tag_end = position + 8 + size; } break; } // Determine the region of the file that // contains tags. if (tag_found) { if (tag_start == -1) { tag_start = position; tag_end = position + 8 + size; } else if (tag_end == position) { tag_end = position + 8 + size; } } // Move to the next item. } while ((position += 8 + size) + 8 < length); // If we're reading properties, and one were found, // throw an exception. Otherwise, create the Properties // object. if (style != ReadStyle.None) { if (codecs.Length == 0) { throw new UnsupportedFormatException( "Unsupported RIFF type."); } properties = new Properties(duration, codecs); } // If we're reading tags, update the combined tag. if (read_tags) { tag.SetTags(id32_tag, info_tag, mid_tag, divx_tag); } }
public void TestBeatsPerMinute () { Id3v2.Tag tag = new Id3v2.Tag (); for (byte version = 2; version <= 4; version ++) { tag.Version = version; TagTestWithSave (ref tag, delegate (Id3v2.Tag t, string m) { Assert.IsTrue (t.IsEmpty, "Initial (IsEmpty): " + m); Assert.AreEqual (0, tag.BeatsPerMinute, "Initial (Zero): " + m); }); tag.BeatsPerMinute = 199; TagTestWithSave (ref tag, delegate (Id3v2.Tag t, string m) { Assert.IsFalse (t.IsEmpty, "Value Set (!IsEmpty): " + m); Assert.AreEqual (199, tag.BeatsPerMinute, "Value Set: " + m); }); tag.BeatsPerMinute = 0; TagTestWithSave (ref tag, delegate (Id3v2.Tag t, string m) { Assert.IsTrue (t.IsEmpty, "Value Cleared (IsEmpty): " + m); Assert.AreEqual (0, t.BeatsPerMinute, "Value Cleared (Zero): " + m); }); } }
public void TestCopyTo () { Id3v2.Tag tag1 = new Id3v2.Tag (); Id3v2.Tag tag2 = new Id3v2.Tag (); UserTextInformationFrame frame1 = UserTextInformationFrame.Get (tag1, "FOOBAR", true); UserTextInformationFrame frame2 = UserTextInformationFrame.Get (tag2, "FOOBAR", true); frame1.Text = new string [] {"1"}; frame2.Text = new string [] {"2"}; Assert.AreEqual ("2", UserTextInformationFrame.Get (tag2, "FOOBAR", false).Text [0], "Not yet copied."); tag1.CopyTo (tag2, false); Assert.AreEqual ("2", UserTextInformationFrame.Get (tag2, "FOOBAR", false).Text [0], "overwrite=false"); tag1.CopyTo (tag2, true); Assert.AreEqual ("1", UserTextInformationFrame.Get (tag2, "FOOBAR", false).Text [0], "overwrite=true"); UserTextInformationFrame.Get (tag2, "FOOBAR", false).Text = new string [] {"3"}; Assert.AreEqual ("1", UserTextInformationFrame.Get (tag1, "FOOBAR", false).Text [0], "Deep copy."); }
public void TestClear () { Id3v2.Tag tag = new Id3v2.Tag (); tag.Title = "A"; tag.Performers = new string [] {"B"}; tag.AlbumArtists = new string [] {"C"}; tag.Composers = new string [] {"D"}; tag.Album = "E"; tag.Comment = "F"; tag.Genres = new string [] {"Blues"}; tag.Year = 123; tag.Track = 234; tag.TrackCount = 234; tag.Disc = 234; tag.DiscCount = 234; tag.Lyrics = "G"; tag.Grouping = "H"; tag.BeatsPerMinute = 234; tag.Conductor = "I"; tag.Copyright = "J"; tag.Pictures = new Picture [] {new Picture ("../examples/covers/sample_a.png")}; Assert.IsFalse (tag.IsEmpty, "Should be full."); tag.Clear (); Assert.IsNull (tag.Title, "Title"); Assert.AreEqual (0, tag.Performers.Length, "Performers"); Assert.AreEqual (0, tag.AlbumArtists.Length, "AlbumArtists"); Assert.AreEqual (0, tag.Composers.Length, "Composers"); Assert.IsNull (tag.Album, "Album"); Assert.IsNull (tag.Comment, "Comment"); Assert.AreEqual (0, tag.Genres.Length, "Genres"); Assert.AreEqual (0, tag.Year, "Year"); Assert.AreEqual (0, tag.Track, "Track"); Assert.AreEqual (0, tag.TrackCount, "TrackCount"); Assert.AreEqual (0, tag.Disc, "Disc"); Assert.AreEqual (0, tag.DiscCount, "DiscCount"); Assert.IsNull (tag.Lyrics, "Lyrics"); Assert.IsNull (tag.Comment, "Comment"); Assert.AreEqual (0, tag.BeatsPerMinute, "BeatsPerMinute"); Assert.IsNull (tag.Conductor, "Conductor"); Assert.IsNull (tag.Copyright, "Copyright"); Assert.AreEqual (0, tag.Pictures.Length, "Pictures"); Assert.IsTrue (tag.IsEmpty, "Should be empty."); }
/// <summary> /// Removes a set of tag types from the current instance. /// </summary> /// <param name="types"> /// A bitwise combined <see cref="TagLib.TagTypes" /> value /// containing tag types to be removed from the file. /// </param> /// <remarks> /// In order to remove all tags from a file, pass <see /// cref="TagTypes.AllTags" /> as <paramref name="types" />. /// </remarks> public override void RemoveTags(TagTypes types) { if (types == TagLib.TagTypes.Id3v2 || types == TagLib.TagTypes.AllTags) { tag = null; } }
/// <summary> /// Reads the contents of the current instance determining /// the size of the riff data, the area the tagging is in, /// and optionally reading in the tags and media properties. /// </summary> /// <param name="read_tags"> /// If <see langword="true" />, any tags found will be read /// into the current instance. /// </param> /// <param name="style"> /// A <see cref="ReadStyle"/> value specifying how the media /// data is to be read into the current instance. /// </param> /// <param name="aiff_size"> /// A <see cref="uint"/> value reference to be filled with /// the size of the RIFF data as read from the file. /// </param> /// <param name="tag_start"> /// A <see cref="long" /> value reference to be filled with /// the absolute seek position at which the tagging data /// starts. /// </param> /// <param name="tag_end"> /// A <see cref="long" /> value reference to be filled with /// the absolute seek position at which the tagging data /// ends. /// </param> /// <exception cref="CorruptFileException"> /// The file does not begin with <see cref="FileIdentifier" /// />. /// </exception> private void Read(bool read_tags, ReadStyle style, out uint aiff_size, out long tag_start, out long tag_end) { Seek(0); if (ReadBlock(4) != FileIdentifier) throw new CorruptFileException( "File does not begin with AIFF identifier"); aiff_size = ReadBlock(4).ToUInt(true); tag_start = -1; tag_end = -1; // Get the properties of the file if (header_block == null && style != ReadStyle.None) { long common_chunk_pos = Find(CommIdentifier, 0); if (common_chunk_pos == -1) { throw new CorruptFileException( "No Common chunk available in AIFF file."); } Seek(common_chunk_pos); header_block = ReadBlock((int) StreamHeader.Size); StreamHeader header = new StreamHeader(header_block, aiff_size); properties = new Properties(TimeSpan.Zero, header); } // Now we search for the ID3 chunk. // Normally it appears after the Sound data chunk. But as the order of // chunks is free, it might be the case that the ID3 chunk appears before // the sound data chunk. // So we search first for the Sound data chunk and see, if an ID3 chunk appears before long id3_chunk_pos = -1; long sound_chunk_pos = Find(SoundIdentifier, 0, ID3Identifier); if (sound_chunk_pos == -1) { // The ID3 chunk appears before the Sound chunk id3_chunk_pos = Find(ID3Identifier, 0); } // Now let's look for the Sound chunk again // Since a previous return value of -1 does mean, that the ID3 chunk was found first sound_chunk_pos = Find(SoundIdentifier, 0); if (sound_chunk_pos == -1) { throw new CorruptFileException( "No Sound chunk available in AIFF file."); } // Get the length of the Sound chunk and use this as a start value to look for the ID3 chunk Seek(sound_chunk_pos + 4); ulong sound_chunk_length = ReadBlock(4).ToULong(true); long start_search_pos = (long) sound_chunk_length + sound_chunk_pos + 4; if (id3_chunk_pos == -1) { id3_chunk_pos = Find(ID3Identifier, start_search_pos); } if (id3_chunk_pos > -1) { if (read_tags && tag == null) { tag = new Id3v2.Tag(this, id3_chunk_pos + 8); } // Get the length of the tag out of the ID3 chunk Seek(id3_chunk_pos + 4); uint tag_size = ReadBlock(4).ToUInt(true) + 8; tag_start = InvariantStartPosition = id3_chunk_pos; tag_end = InvariantEndPosition = tag_start + tag_size; } }
/// <summary> /// Adds a tag of a specified type to the current instance, /// optionally copying values from an existing type. /// </summary> /// <param name="type"> /// A <see cref="TagTypes" /> value specifying the type of /// tag to add to the current instance. At the time of this /// writing, this is limited to <see cref="TagTypes.Ape" />, /// <see cref="TagTypes.Id3v1" />, and <see /// cref="TagTypes.Id3v2" />. /// </param> /// <param name="copy"> /// A <see cref="TagLib.Tag" /> to copy values from using /// <see cref="TagLib.Tag.CopyTo" />, or <see /// langword="null" /> if no tag is to be copied. /// </param> /// <returns> /// The <see cref="TagLib.Tag" /> object added to the current /// instance, or <see langword="null" /> if it couldn't be /// created. /// </returns> /// <remarks> /// ID3v2 tags are added at the end of the current instance, /// while other tags are added to the beginning. /// </remarks> public TagLib.Tag AddTag(TagTypes type, TagLib.Tag copy) { TagLib.Tag tag = null; if (type == TagTypes.Id3v1) { tag = new TagLib.Id3v1.Tag (); } else if (type == TagTypes.Id3v2) { Id3v2.Tag tag32 = new Id3v2.Tag (); tag32.Version = 4; tag32.Flags |= Id3v2.HeaderFlags.FooterPresent; tag = tag32; } else if (type == TagTypes.Ape) { tag = new TagLib.Ape.Tag (); } if (tag != null) { if (copy != null) copy.CopyTo (tag, true); if (type == TagTypes.Id3v1) AddTag (tag); else InsertTag (0, tag); } return tag; }
/// <summary> /// Gets a tag of a specified type from the current instance, /// optionally creating a new tag if possible. /// </summary> /// <param name="type"> /// A <see cref="TagLib.TagTypes" /> value indicating the /// type of tag to read. /// </param> /// <param name="create"> /// A <see cref="bool" /> value specifying whether or not to /// try and create the tag if one is not found. /// </param> /// <returns> /// A <see cref="Tag" /> object containing the tag that was /// found in or added to the current instance. If no /// matching tag was found and none was created, <see /// langword="null" /> is returned. /// </returns> public override TagLib.Tag GetTag(TagTypes type, bool create) { TagLib.Tag tag = null; switch (type) { case TagTypes.Id3v2: if (id32_tag == null && create) { id32_tag = new Id3v2.Tag (); id32_tag.Version = 4; id32_tag.Flags |= Id3v2.HeaderFlags .FooterPresent; this.tag.CopyTo (id32_tag, true); } tag = id32_tag; break; case TagTypes.RiffInfo: if (info_tag == null && create) { info_tag = new InfoTag (); this.tag.CopyTo (info_tag, true); } tag = info_tag; break; case TagTypes.MovieId: if (mid_tag == null && create) { mid_tag = new MovieIdTag (); this.tag.CopyTo (mid_tag, true); } tag = mid_tag; break; case TagTypes.DivX: if (divx_tag == null && create) { divx_tag = new DivXTag (); this.tag.CopyTo (divx_tag, true); } tag = divx_tag; break; } this.tag.SetTags (id32_tag, info_tag, mid_tag, divx_tag); return tag; }
private void TagTestWithSave (ref Id3v2.Tag tag, TagTestFunc testFunc) { testFunc (tag, "Before Save"); for (byte version = 2; version <= 4; version ++) { tag.Version = version; tag = new Id3v2.Tag (tag.Render ()); testFunc (tag, "After Save, Version: " + version); tag = tag.Clone (); testFunc (tag, "After Clone, Version: " + version); Id3v2.Tag tmp = new Id3v2.Tag (); tag.CopyTo (tmp, true); tag = tmp; testFunc (tag, "After CopyTo(true), Version: " + version); tmp = new Id3v2.Tag (); tag.CopyTo (tmp, false); tag = tmp; testFunc (tag, "After CopyTo(false), Version: " + version); } }
/// <summary> /// Reads the contents of the current instance determining /// the size of the riff data, the area the tagging is in, /// and optionally reading in the tags and media properties. /// </summary> /// <param name="read_tags"> /// If <see langword="true" />, any tags found will be read /// into the current instance. /// </param> /// <param name="style"> /// A <see cref="ReadStyle"/> value specifying how the media /// data is to be read into the current instance. /// </param> /// <param name="riff_size"> /// A <see cref="uint"/> value reference to be filled with /// the size of the RIFF data as read from the file. /// </param> /// <param name="tag_start"> /// A <see cref="long" /> value reference to be filled with /// the absolute seek position at which the tagging data /// starts. /// </param> /// <param name="tag_end"> /// A <see cref="long" /> value reference to be filled with /// the absolute seek position at which the tagging data /// ends. /// </param> /// <exception cref="CorruptFileException"> /// The file does not begin with <see cref="FileIdentifier" /// />. /// </exception> private void Read(bool read_tags, ReadStyle style, out uint riff_size, out long tag_start, out long tag_end) { Seek (0); if (ReadBlock (4) != FileIdentifier) throw new CorruptFileException ( "File does not begin with RIFF identifier"); riff_size = ReadBlock (4).ToUInt (false); ByteVector stream_format = ReadBlock (4); tag_start = -1; tag_end = -1; long position = 12; long length = Length; uint size = 0; TimeSpan duration = TimeSpan.Zero; ICodec [] codecs = new ICodec [0]; // Read until there are less than 8 bytes to read. do { bool tag_found = false; Seek (position); string fourcc = ReadBlock (4).ToString (StringType.UTF8); size = ReadBlock (4).ToUInt (false); switch (fourcc) { // "fmt " is used by Wave files to hold the // WaveFormatEx structure. case "fmt ": if (style == ReadStyle.None || stream_format != "WAVE") break; Seek (position + 8); codecs = new ICodec [] { new WaveFormatEx (ReadBlock (18), 0) }; break; // "data" contains the audio data for wave // files. It's contents represent the invariant // portion of the file and is used to determine // the duration of a file. It should always // appear after "fmt ". case "data": if (stream_format != "WAVE") break; InvariantStartPosition = position; InvariantEndPosition = position + size; if (style == ReadStyle.None || codecs.Length != 1 || !(codecs [0] is WaveFormatEx)) break; duration += TimeSpan.FromSeconds ( (double) size / (double) ((WaveFormatEx) codecs [0]) .AverageBytesPerSecond); break; // Lists are used to store a variety of data // collections. Read the type and act on it. case "LIST": { switch (ReadBlock (4).ToString (StringType.UTF8)) { // "hdlr" is used by AVI files to hold // a media header and BitmapInfoHeader // and WaveFormatEx structures. case "hdrl": if (style == ReadStyle.None || stream_format != "AVI ") continue; AviHeaderList header_list = new AviHeaderList (this, position + 12, (int) (size - 4)); duration = header_list.Header.Duration; codecs = header_list.Codecs; break; // "INFO" is a tagging format handled by // the InfoTag class. case "INFO": if (read_tags && info_tag == null) info_tag = new InfoTag ( this, position + 12, (int) (size - 4)); tag_found = true; break; // "MID " is a tagging format handled by // the MovieIdTag class. case "MID ": if (read_tags && mid_tag == null) mid_tag = new MovieIdTag ( this, position + 12, (int) (size - 4)); tag_found = true; break; // "movi" contains the media data for // and AVI and its contents represent // the invariant portion of the file. case "movi": if (stream_format != "AVI ") break; InvariantStartPosition = position; InvariantEndPosition = position + size; break; } break; } // "ID32" is a custom box for this format that // contains an ID3v2 tag. case "ID32": if (read_tags && id32_tag == null) id32_tag = new Id3v2.Tag (this, position + 8); tag_found = true; break; // "IDVX" is used by DivX and holds an ID3v1- // style tag. case "IDVX": if (read_tags && divx_tag == null) divx_tag = new DivXTag (this, position + 8); tag_found = true; break; // "JUNK" is a padding element that could be // associated with tag data. case "JUNK": if (tag_end == position) tag_end = position + 8 + size; break; } // Determine the region of the file that // contains tags. if (tag_found) { if (tag_start == -1) { tag_start = position; tag_end = position + 8 + size; } else if (tag_end == position) { tag_end = position + 8 + size; } } // Move to the next item. } while ((position += 8 + size) + 8 < length); // If we're reading properties, and one were found, // throw an exception. Otherwise, create the Properties // object. if (style != ReadStyle.None) { if (codecs.Length == 0) throw new UnsupportedFormatException ( "Unsupported RIFF type."); properties = new Properties (duration, codecs); } // If we're reading tags, update the combined tag. if (read_tags) tag.SetTags (id32_tag, info_tag, mid_tag, divx_tag); }
public void TestIsCompilation () { Id3v2.Tag tag = new Id3v2.Tag (); for (byte version = 2; version <= 4; version ++) { tag.Version = version; TagTestWithSave (ref tag, delegate (Id3v2.Tag t, string m) { Assert.IsTrue (t.IsEmpty, "Initial (IsEmpty): " + m); Assert.IsFalse (t.IsCompilation, "Initial (False): " + m); }); tag.IsCompilation = true; TagTestWithSave (ref tag, delegate (Id3v2.Tag t, string m) { Assert.IsFalse (t.IsEmpty, "Value Set (!IsEmpty): " + m); Assert.IsTrue (t.IsCompilation, "Value Set (True): " + m); }); tag.IsCompilation = false; TagTestWithSave (ref tag, delegate (Id3v2.Tag t, string m) { Assert.IsTrue (t.IsEmpty, "Value Cleared (IsEmpty): " + m); Assert.IsFalse (t.IsCompilation, "Value Cleared (False): " + m); }); } }