/// <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); }
bool ParseVersion3(DataFrameReader reader) { if (!reader.EnsureBuffer(4)) { return false; } // calc size byte[] sizeBytes = reader.Read(0, 4); int size = 0; for (int i = 0; i < 4; i++) { size = (size << 8) | sizeBytes[i]; } size += 4; // get data if (!reader.EnsureBuffer(size)) { return false; } m_Data = reader.GetBuffer(size); // get flags m_Flags = ID3v2ExtendedHeaderFlags.FromID3v23(m_Data); return true; }
/// <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); }
bool ParseVersion4(DataFrameReader reader) { if (!reader.EnsureBuffer(4)) { return false; } // calc size int size = ID3v2DeUnsync.Int32(reader.Read(0, 4), 0); // get data if (!reader.EnsureBuffer(size)) { return false; } m_Data = reader.GetBuffer(size); // get flags m_Flags = ID3v2ExtendedHeaderFlags.FromID3v24(m_Data); return true; }
/// <summary> /// uses the <see cref="Search"/> class to find the next id3 / mp3 frame start at the buffer. /// </summary> /// <returns>Returns the search result.</returns> Search FindFrame() { // initialize the search and run it at the buffer var search = new Search(); while (true) { // fill the buffer if (!m_Reader.EnsureBuffer(1024) && (m_Reader.Available < 4)) { if (m_Reader.Available == 0) { return(null); } // end of stream var buffer = m_Reader.GetBuffer(m_Reader.Available); InvalidData(buffer); return(null); } // run the search { if (m_Reader.Contains(search)) { return(search); } // nothing found, enqueue invalid data... var buffer = m_Reader.GetBuffer(m_Reader.Available - 2); InvalidData(buffer); // .. and start new search search = new Search(); } } }