/// <summary>Initializes a new instance of the <see cref="ID3v2Frame" /> class.</summary> /// <param name="header">The header.</param> /// <param name="reader">The reader.</param> /// <exception cref="ArgumentNullException">Header.</exception> /// <exception cref="NotSupportedException"></exception> public ID3v2Frame(ID3v2Header header, DataFrameReader reader) { if (reader == null) { throw new ArgumentNullException("Reader"); } m_Header = new ID3v2FrameHeader(header, reader); // prepare content (has to be decoded, decrypted, decompressed, ... m_Content = reader.Read(m_Header.HeaderSize, m_Header.ContentSize); switch (header.Version) { case 2: /*nothing to do, raw plain content data*/ break; case 3: ParseVersion3(reader); break; case 4: ParseVersion4(reader); break; default: throw new NotSupportedException(string.Format("ID3v2.{0} is not supported!", header.Version)); } // copy raw data and remove from reader m_Data = reader.GetBuffer(m_Header.HeaderSize + m_Header.ContentSize); }
/// <summary>Initializes a new instance of the <see cref="ID3v2Frame" /> class.</summary> /// <param name="header">The header.</param> /// <param name="data">The data.</param> public ID3v2Frame(ID3v2Header header, byte[] data) { m_Header = new ID3v2FrameHeader(header, data); if (m_Header.ContentSize + m_Header.HeaderSize != data.Length) { throw new ArgumentOutOfRangeException("data", $"Invalid size of data! Expected {m_Header.ContentSize + m_Header.HeaderSize} bytes, got {data.Length}!"); } m_Data = data; m_Content = new byte[m_Header.ContentSize]; Array.Copy(m_Data, m_Header.HeaderSize, m_Content, 0, m_Header.ContentSize); }
/// <summary>Gets the size of the header.</summary> /// <param name="header">The header.</param> /// <returns></returns> /// <exception cref="NotSupportedException"></exception> public static int GetHeaderSize(ID3v2Header header) { switch (header.Version) { case 2: return(6); case 3: case 4: return(10); default: throw new NotSupportedException(string.Format("Unsupported ID3v2 Version {0}", header.Version)); } }
/// <summary>Creates the specified header.</summary> /// <param name="header">The header.</param> /// <param name="id">The identifier.</param> /// <param name="flags">The flags.</param> /// <param name="contentSize">Size of the frame content.</param> /// <returns></returns> /// <exception cref="NotSupportedException"></exception> public static ID3v2FrameHeader Create(ID3v2Header header, string id, ID3v2FrameFlags flags, int contentSize) { switch (header.Version) { case 2: return(CreateVersion2(header, id, contentSize)); case 3: return(CreateVersion3(header, id, flags, contentSize)); case 4: return(CreateVersion4(header, id, flags, contentSize)); default: throw new NotSupportedException(string.Format("Unsupported ID3v2 Version {0}", header.Version)); } }
/// <summary>Initializes a new instance of the <see cref="ID3v2FrameHeader"/> class.</summary> /// <param name="header">The header.</param> /// <param name="reader">The reader.</param> /// <exception cref="NotSupportedException"></exception> public ID3v2FrameHeader(ID3v2Header header, DataFrameReader reader) { TagHeader = header; switch (header.Version) { case 2: ParseVersion2(reader.Read(0, 6)); break; case 3: ParseVersion3(reader.Read(0, 10)); break; case 4: ParseVersion4(reader.Read(0, 10)); break; default: throw new NotSupportedException(string.Format("Unsupported ID3v2 Version {0}", header.Version)); } }
/// <summary>Initializes a new instance of the <see cref="ID3v2FrameHeader"/> class.</summary> /// <param name="header">The header.</param> /// <param name="data">The data.</param> /// <exception cref="NotSupportedException"></exception> public ID3v2FrameHeader(ID3v2Header header, byte[] data) { m_Data = data; TagHeader = header; switch (header.Version) { case 2: ParseVersion2(data); break; case 3: ParseVersion3(data); break; case 4: ParseVersion4(data); break; default: throw new NotSupportedException(string.Format("Unsupported ID3v2 Version {0}", header.Version)); } }
/// <summary>Selects the best encoding for the given text.</summary> /// <param name="header">The header.</param> /// <param name="text">The text.</param> /// <returns></returns> /// <exception cref="NotSupportedException"></exception> /// <exception cref="NotImplementedException"></exception> internal static ID3v2EncodingType Select(ID3v2Header header, string text) { if (CanUseISO(text)) { return(ID3v2EncodingType.ISO88591); } else { switch (header.Version) { case 3: return(ID3v2EncodingType.Unicode); case 4: return(ID3v2EncodingType.Unicode); default: throw new NotSupportedException(); } } }
/// <summary>Creates a version2 header.</summary> /// <param name="header">The header.</param> /// <param name="id">The identifier.</param> /// <param name="contentSize">Size of the frame content.</param> /// <returns></returns> /// <exception cref="ArgumentException">Invalid identifier!.</exception> /// <exception cref="ArgumentOutOfRangeException"></exception> public static ID3v2FrameHeader CreateVersion2(ID3v2Header header, string id, int contentSize) { if (id.Length != 3) { throw new ArgumentException("Invalid identifier!", nameof(id)); } byte[] data = ASCII.GetBytes(id + " "); for (int i = 5; i >= 3; i--) { data[i] = (byte)(contentSize & 0xFF); contentSize >>= 8; } if (contentSize > 0) { throw new ArgumentOutOfRangeException(nameof(contentSize)); } return(new ID3v2FrameHeader(header, data)); }
/// <summary> /// Reads the header (check <see cref="State"/> before usage). /// </summary> /// <returns></returns> public ID3v2Header ReadHeader(out byte[] tagData) { if (State != ID3v2ReaderState.ReadHeader) { throw new InvalidOperationException(string.Format("Cannot read header at state {0}", State)); } var header = new ID3v2Header(); if (!header.Parse(m_Reader)) { tagData = null; return(null); } m_BodyBytes = header.BodySize; if ((header.Flags & ID3v2HeaderFlags.Footer) != 0) { m_BodyBytes -= 10; } State++; if (header.Version < 2) { tagData = null; return(null); } tagData = m_Reader.GetBuffer(header.HeaderSize + header.BodySize); var bodyData = tagData.GetRange(header.HeaderSize); // need to unsync whole tag? if ((header.Flags & ID3v2HeaderFlags.Unsynchronisation) != 0) { bodyData = ID3v2DeUnsync.Buffer(bodyData); m_BodyBytes = bodyData.Length; } // update reader (use cached data) m_Header = header; m_Reader = new DataFrameReader(bodyData); return(header); }
/// <summary>Retrieves the tag as byte array.</summary> /// <returns></returns> public byte[] ToArray() { var buffer = new FifoBuffer(); ID3v2HeaderFlags flags = ID3v2HeaderFlags.None; /* we do not like extended headers so we won't write them * if (m_ExtendedHeader != null) * { * buffer.Enqueue(m_ExtendedHeader.Data); * flags |= ID3v2HeaderFlags.ExtendedHeader; * } */ foreach (ID3v2Frame frame in frames) { buffer.Enqueue(frame.RawData); } int bodySize = buffer.Length; // no one likes footers so we won't write them var header = new ID3v2Header(Header.Version, Header.Revision, flags, bodySize); buffer.Prepend(header.Data); return(buffer.ToArray()); }
/// <summary>Creates a version3 header.</summary> /// <param name="header">The header.</param> /// <param name="id">The identifier.</param> /// <param name="flags">The flags.</param> /// <param name="contentSize">Size of the frame content.</param> /// <returns></returns> /// <exception cref="ArgumentException">Invalid identifier!.</exception> /// <exception cref="ArgumentOutOfRangeException"></exception> public static ID3v2FrameHeader CreateVersion3(ID3v2Header header, string id, ID3v2FrameFlags flags, int contentSize) { if (id.Length != 4) { throw new ArgumentException("Invalid identifier!", nameof(id)); } var data = ASCII.GetBytes(id + " "); var f = (ushort)flags.ToID3v2d3Flags(); data[9] = (byte)(f & 0xFF); data[8] = (byte)(f >> 8); for (var i = 7; i >= 4; i--) { data[i] = (byte)(contentSize & 0xFF); contentSize >>= 8; } if (contentSize > 0) { throw new ArgumentOutOfRangeException(nameof(contentSize)); } return(new ID3v2FrameHeader(header, data)); }
/// <summary> /// Creates a new empty instance. /// </summary> /// <param name="header"></param> public ID3v2ExtendedHeader(ID3v2Header header) { m_Header = header ?? throw new ArgumentNullException("Header"); }