protected internal UniqueFileIdentifierFrame (ByteVector data, int offset, FrameHeader header, byte version) : base(header) { SetData (data, offset, version, false); }
protected internal GeneralEncapsulatedObjectFrame (ByteVector data, int offset, FrameHeader header, byte version) : base(header) { SetData (data, offset, version, false); }
protected Frame(ByteVector data, byte version) { if (data == null) { throw new ArgumentNullException("data"); } if (data.Count < ((version >= 3) ? 4 : 3)) { throw new ArgumentException("Data contains an incomplete identifier.", "data"); } this.header = new FrameHeader(data, version); }
/// <summary> /// Constructs and initializes a new instance of <see /// cref="UserUrlLinkFrame" /> by reading its raw /// data in a specified ID3v2 version. /// </summary> /// <param name="data"> /// A <see cref="ByteVector" /> object containing the raw /// representation of the new frame. /// </param> /// <param name="offset"> /// A <see cref="int" /> indicating at what offset in /// <paramref name="data" /> the frame actually begins. /// </param> /// <param name="header"> /// A <see cref="FrameHeader" /> containing the header of the /// frame found at <paramref name="offset" /> in the data. /// </param> /// <param name="version"> /// A <see cref="byte" /> indicating the ID3v2 version the /// raw frame is encoded in. /// </param> protected internal UserUrlLinkFrame(ByteVector data, int offset, FrameHeader header , byte version) : base(data, offset, header, version) { }
/// <summary> /// Constructs and initializes a new instance of <see /// cref="TermsOfUseFrame" /> by reading its raw data in a /// specified ID3v2 version. /// </summary> /// <param name="data"> /// A <see cref="ByteVector" /> object containing the raw /// representation of the new frame. /// </param> /// <param name="offset"> /// A <see cref="int" /> indicating at what offset in /// <paramref name="data" /> the frame actually begins. /// </param> /// <param name="header"> /// A <see cref="FrameHeader" /> containing the header of the /// frame found at <paramref name="offset" /> in the data. /// </param> /// <param name="version"> /// A <see cref="byte" /> indicating the ID3v2 version the /// raw frame is encoded in. /// </param> protected internal TermsOfUseFrame (ByteVector data, int offset, FrameHeader header, byte version) : base (header) { SetData (data, offset, version, false); }
protected internal MusicCdIdentifierFrame(ByteVector data, int offset, FrameHeader header, byte version) : base(header) { SetData(data, offset, version, false); }
protected internal PopularimeterFrame(ByteVector data, int offset, FrameHeader header, byte version) : base(header) { this.user = string.Empty; base.SetData(data, offset, version, false); }
/// <summary> /// Creates a <see cref="Frame" /> object by reading it from /// raw ID3v2 frame data. /// </summary> /// <param name="data"> /// A <see cref="ByteVector" /> object containing a raw ID3v2 /// frame. /// </param> /// <param name="offset"> /// A <see cref="int" /> value reference specifying at what /// index in <paramref name="data" /> at which the frame /// begins. After reading, it contains the offset of the next /// frame to be read. /// </param> /// <param name="version"> /// A <see cref="byte" /> value specifying the ID3v2 version /// the frame in <paramref name="data"/> is encoded in. /// </param> /// <param name="alreadyUnsynched"> /// A <see cref="bool" /> value specifying whether the entire /// tag has already been unsynchronized. /// </param> /// <returns> /// A <see cref="Frame" /> object read from the data, or <see /// langword="null" /> if none is found. /// </returns> /// <exception cref="System.NotImplementedException"> /// The frame contained in the raw data could not be /// converted to ID3v2 or uses encryption or compression. /// </exception> public static Frame CreateFrame(ByteVector data, ref int offset, byte version, bool alreadyUnsynched) { int position = offset; FrameHeader header = new FrameHeader(data.Mid(position, (int)FrameHeader.Size(version)), version); offset += (int)(header.FrameSize + FrameHeader.Size( version)); if (header.FrameId == null) { throw new System.NotImplementedException(); } foreach (byte b in header.FrameId) { char c = (char)b; if ((c < 'A' || c > 'Z') && (c < '0' || c > '9')) { return(null); } } if (alreadyUnsynched) { // Mark the frame as not Unsynchronozed because the entire // tag has already been Unsynchronized header.Flags &= ~FrameFlags.Unsynchronisation; } // Windows Media Player may create zero byte frames. // Just send them off as unknown and delete them. if (header.FrameSize == 0) { header.Flags |= FrameFlags.TagAlterPreservation; return(new UnknownFrame(data, position, header, version)); } // TODO: Support Compression. if ((header.Flags & FrameFlags.Compression) != 0) { throw new System.NotImplementedException(); } // TODO: Support Encryption. if ((header.Flags & FrameFlags.Encryption) != 0) { throw new System.NotImplementedException(); } foreach (FrameCreator creator in frame_creators) { Frame frame = creator(data, position, header, version); if (frame != null) { return(frame); } } // This is where things get necissarily nasty. Here we // determine which Frame subclass (or if none is found // simply an Frame) based on the frame ID. Since there // are a lot of possibilities, that means a lot of if // blocks. // Text Identification (frames 4.2) if (header.FrameId == FrameType.TXXX) { return(new UserTextInformationFrame(data, position, header, version)); } if (header.FrameId [0] == (byte)'T') { return(new TextInformationFrame(data, position, header, version)); } // Unique File Identifier (frames 4.1) if (header.FrameId == FrameType.UFID) { return(new UniqueFileIdentifierFrame(data, position, header, version)); } // Music CD Identifier (frames 4.5) if (header.FrameId == FrameType.MCDI) { return(new MusicCdIdentifierFrame(data, position, header, version)); } // Unsynchronized Lyrics (frames 4.8) if (header.FrameId == FrameType.USLT) { return(new UnsynchronisedLyricsFrame(data, position, header, version)); } // Synchronized Lyrics (frames 4.9) if (header.FrameId == FrameType.SYLT) { return(new SynchronisedLyricsFrame(data, position, header, version)); } // Comments (frames 4.10) if (header.FrameId == FrameType.COMM) { return(new CommentsFrame(data, position, header, version)); } // Relative Volume Adjustment (frames 4.11) if (header.FrameId == FrameType.RVA2) { return(new RelativeVolumeFrame(data, position, header, version)); } // Attached Picture (frames 4.14) if (header.FrameId == FrameType.APIC) { return(new AttachedPictureFrame(data, position, header, version)); } // General Encapsulated Object (frames 4.15) if (header.FrameId == FrameType.GEOB) { return(new GeneralEncapsulatedObjectFrame(data, position, header, version)); } // Play Count (frames 4.16) if (header.FrameId == FrameType.PCNT) { return(new PlayCountFrame(data, position, header, version)); } // Play Count (frames 4.17) if (header.FrameId == FrameType.POPM) { return(new PopularimeterFrame(data, position, header, version)); } // Terms of Use (frames 4.22) if (header.FrameId == FrameType.USER) { return(new TermsOfUseFrame(data, position, header, version)); } // Private (frames 4.27) if (header.FrameId == FrameType.PRIV) { return(new PrivateFrame(data, position, header, version)); } // Url Link (frames 4.3.1) if (header.FrameId[0] == (byte)'W') { return(new UrlLinkFrame(data, position, header, version)); } return(new UnknownFrame(data, position, header, version)); }
/// <summary> /// Constructs and initializes a new instance of <see /// cref="UnsynchronisedLyricsFrame" /> by reading its raw /// data in a specified ID3v2 version. /// </summary> /// <param name="data"> /// A <see cref="ByteVector" /> object containing the raw /// representation of the new frame. /// </param> /// <param name="offset"> /// A <see cref="int" /> indicating at what offset in /// <paramref name="data" /> the frame actually begins. /// </param> /// <param name="header"> /// A <see cref="FrameHeader" /> containing the header of the /// frame found at <paramref name="offset" /> in the data. /// </param> /// <param name="version"> /// A <see cref="byte" /> indicating the ID3v2 version the /// raw frame is encoded in. /// </param> protected internal UnsynchronisedLyricsFrame (ByteVector data, int offset, FrameHeader header, byte version) : base(header) { SetData (data, offset, version, false); }
protected internal UserTextInformationFrame(ByteVector data, int offset, FrameHeader header, byte version) : base(data, offset, header, version) { }
/// <summary> /// Constructs and initializes a new instance of <see /// cref="RelativeVolumeFrame" /> by reading its raw data in /// a specified ID3v2 version. /// </summary> /// <param name="data"> /// A <see cref="ByteVector" /> object containing the raw /// representation of the new frame. /// </param> /// <param name="offset"> /// A <see cref="int" /> indicating at what offset in /// <paramref name="data" /> the frame actually begins. /// </param> /// <param name="header"> /// A <see cref="FrameHeader" /> containing the header of the /// frame found at <paramref name="offset" /> in the data. /// </param> /// <param name="version"> /// A <see cref="byte" /> indicating the ID3v2 version the /// raw frame is encoded in. /// </param> protected internal RelativeVolumeFrame(ByteVector data, int offset, FrameHeader header, byte version) : base(header) { SetData(data, offset, version, false); }
/// <summary> /// Creates a <see cref="Frame" /> object by reading it from /// raw ID3v2 frame data. /// </summary> /// <param name="data"> /// A <see cref="ByteVector" /> object containing a raw ID3v2 /// frame. /// </param> /// <param name="file"> /// A <see cref="File"/> object containing /// abstraction of the file to read. /// Ignored if <paramref name="data"/> is not null. /// </param> /// <param name="offset"> /// A <see cref="int" /> value reference specifying at what /// index in <paramref name="file" />, or in /// <paramref name="data" /> if not null, /// at which the frame begins. After reading, it contains /// the offset of the next frame to be read. /// </param> /// <param name="version"> /// A <see cref="byte" /> value specifying the ID3v2 version /// the frame in <paramref name="data"/> is encoded in. /// </param> /// <param name="alreadyUnsynched"> /// A <see cref="bool" /> value specifying whether the entire /// tag has already been unsynchronized. /// </param> /// <returns> /// A <see cref="Frame" /> object read from the data, or <see /// langword="null" /> if none is found. /// </returns> /// <exception cref="System.NotImplementedException"> /// The frame contained in the raw data could not be /// converted to ID3v2 or uses encryption or compression. /// </exception> public static Frame CreateFrame(ByteVector data, File file, ref int offset, byte version, bool alreadyUnsynched) { int position = 0; if (data == null) { file.Seek(offset); data = file.ReadBlock((int)FrameHeader.Size(version)); } else { file = null; position = offset; } // If the next data is position is 0, assume // that we've hit the padding portion of the // frame data. if (data[position] == 0) { return(null); } FrameHeader header = new FrameHeader(data.Mid(position, (int)FrameHeader.Size(version)), version); int fileposition = offset + (int)FrameHeader.Size(version); offset += (int)(header.FrameSize + FrameHeader.Size(version)); if (header.FrameId == null) { throw new System.NotImplementedException(); } foreach (byte b in header.FrameId) { char c = (char)b; if ((c < 'A' || c > 'Z') && (c < '0' || c > '9')) { return(null); } } if (alreadyUnsynched) { // Mark the frame as not Unsynchronozed because the entire // tag has already been Unsynchronized header.Flags &= ~FrameFlags.Unsynchronisation; } // Windows Media Player may create zero byte frames. // Just send them off as unknown and delete them. if (header.FrameSize == 0) { header.Flags |= FrameFlags.TagAlterPreservation; return(new UnknownFrame(data, position, header, version)); } // TODO: Support Compression. if ((header.Flags & FrameFlags.Compression) != 0) { throw new System.NotImplementedException(); } // TODO: Support Encryption. if ((header.Flags & FrameFlags.Encryption) != 0) { throw new System.NotImplementedException(); } foreach (FrameCreator creator in frame_creators) { Frame frame = creator(data, position, header, version); if (frame != null) { return(frame); } } // This is where things get necessarily nasty. Here we // determine which Frame subclass (or if none is found // simply an Frame) based on the frame ID. Since there // are a lot of possibilities, that means a lot of if // blocks. // Lazy objects loading handling if (file != null) { // Attached Picture (frames 4.14) // General Encapsulated Object (frames 4.15) if (header.FrameId == FrameType.APIC || header.FrameId == FrameType.GEOB) { return(new AttachmentFrame(file.FileAbstraction, fileposition, offset - fileposition, header, version)); } // Read remaining part of the frame for the non lazy Frames file.Seek(fileposition); data.Add(file.ReadBlock(offset - fileposition)); } // Text Identification (frames 4.2) if (header.FrameId == FrameType.TXXX) { return(new UserTextInformationFrame(data, position, header, version)); } if (header.FrameId[0] == (byte)'T') { return(new TextInformationFrame(data, position, header, version)); } // Involved People List (frames 4.4 in 2.3. in 2.4 this is a TIPL frame) if (header.FrameId == FrameType.IPLS) { return(new TextInformationFrame(data, position, header, version)); } // Unique File Identifier (frames 4.1) if (header.FrameId == FrameType.UFID) { return(new UniqueFileIdentifierFrame(data, position, header, version)); } // Music CD Identifier (frames 4.5) if (header.FrameId == FrameType.MCDI) { return(new MusicCdIdentifierFrame(data, position, header, version)); } // Unsynchronized Lyrics (frames 4.8) if (header.FrameId == FrameType.USLT) { return(new UnsynchronisedLyricsFrame(data, position, header, version)); } // Synchronized Lyrics (frames 4.9) if (header.FrameId == FrameType.SYLT) { return(new SynchronisedLyricsFrame(data, position, header, version)); } // Comments (frames 4.10) if (header.FrameId == FrameType.COMM) { return(new CommentsFrame(data, position, header, version)); } // Relative Volume Adjustment (frames 4.11) if (header.FrameId == FrameType.RVA2) { return(new RelativeVolumeFrame(data, position, header, version)); } // Attached Picture (frames 4.14) // General Encapsulated Object (frames 4.15) if (header.FrameId == FrameType.APIC || header.FrameId == FrameType.GEOB) { return(new AttachmentFrame(data, position, header, version)); } // Play Count (frames 4.16) if (header.FrameId == FrameType.PCNT) { return(new PlayCountFrame(data, position, header, version)); } // Play Count (frames 4.17) if (header.FrameId == FrameType.POPM) { return(new PopularimeterFrame(data, position, header, version)); } // Terms of Use (frames 4.22) if (header.FrameId == FrameType.USER) { return(new TermsOfUseFrame(data, position, header, version)); } // Private (frames 4.27) if (header.FrameId == FrameType.PRIV) { return(new PrivateFrame(data, position, header, version)); } // Url Link (frames 4.3.1) if (header.FrameId[0] == (byte)'W') { return(new UrlLinkFrame(data, position, header, version)); } // Event timing codes (frames 4.6) if (header.FrameId == FrameType.ETCO) { return(new EventTimeCodesFrame(data, position, header, version)); } return(new UnknownFrame(data, position, header, version)); }
protected void Parse(ByteVector data) { if (data == null) { throw new ArgumentNullException("data"); } bool fullTagUnsynch = (header.MajorVersion < 4) && ((header.Flags & HeaderFlags.Unsynchronisation) != 0); if (fullTagUnsynch) { SynchData.ResynchByteVector(data); } int frame_data_position = 0; int frame_data_length = data.Count; if ((header.Flags & HeaderFlags.ExtendedHeader) != 0) { extended_header = new ExtendedHeader(data, header.MajorVersion); if (extended_header.Size <= data.Count) { frame_data_position += (int)extended_header.Size; frame_data_length -= (int)extended_header.Size; } } TextInformationFrame tdrc = null; TextInformationFrame tyer = null; TextInformationFrame tdat = null; TextInformationFrame time = null; while (frame_data_position < frame_data_length - FrameHeader.Size(header.MajorVersion)) { if (data[frame_data_position] == 0) { break; } Frame frame = null; try { frame = FrameFactory.CreateFrame(data, ref frame_data_position, header.MajorVersion, fullTagUnsynch); } catch (NotImplementedException) { continue; } catch (CorruptFileException) { continue; } if (frame == null) { break; } if (frame.Size == 0) { continue; } AddFrame(frame); if (header.MajorVersion == 4) { continue; } if (tdrc == null && frame.FrameId.Equals(FrameType.TDRC)) { tdrc = frame as TextInformationFrame; } else if (tyer == null && frame.FrameId.Equals(FrameType.TYER)) { tyer = frame as TextInformationFrame; } else if (tdat == null && frame.FrameId.Equals(FrameType.TDAT)) { tdat = frame as TextInformationFrame; } else if (time == null && frame.FrameId.Equals(FrameType.TIME)) { time = frame as TextInformationFrame; } } if (tdrc == null || tdat == null || tdrc.ToString().Length > 4) { return; } string year = tdrc.ToString(); if (year.Length != 4) { return; } StringBuilder tdrc_text = new StringBuilder(); tdrc_text.Append(year); if (tdat != null) { string tdat_text = tdat.ToString(); if (tdat_text.Length == 4) { tdrc_text.Append("-").Append(tdat_text, 0, 2).Append("-").Append(tdat_text, 2, 2); if (time != null) { string time_text = time.ToString(); if (time_text.Length == 4) { tdrc_text.Append("T").Append(time_text, 0, 2).Append(":").Append(time_text, 2, 2); } RemoveFrames(FrameType.TIME); } } RemoveFrames(FrameType.TDAT); } tdrc.Text = new string[] { tdrc_text.ToString() }; }
protected internal RelativeVolumeFrame(ByteVector data, int offset, FrameHeader header, byte version) : base(header) { this.channels = new ChannelData[9]; base.SetData(data, offset, version, false); }
public static Frame CreateFrame(ByteVector data, ref int offset, byte version, bool alreadyUnsynched) { int startIndex = offset; FrameHeader header = new FrameHeader(data.Mid(startIndex, (int) FrameHeader.Size(version)), version); offset = (int) (offset + (header.FrameSize + FrameHeader.Size(version))); if (header.FrameId == null) { throw new NotImplementedException(); } IEnumerator<byte> enumerator = header.FrameId.GetEnumerator(); try { while (enumerator.MoveNext()) { byte current = enumerator.Current; char ch = (char) current; if (((ch < 'A') || (ch > 'Z')) && ((ch < '1') || (ch > '9'))) { return null; } } } finally { if (enumerator == null) { } enumerator.Dispose(); } if (alreadyUnsynched) { header.Flags = (FrameFlags) ((ushort) (((int) header.Flags) & 0xfffd)); } if (header.FrameSize == 0) { header.Flags = (FrameFlags) ((ushort) (header.Flags | (FrameFlags.None | FrameFlags.TagAlterPreservation))); return new UnknownFrame(data, startIndex, header, version); } if (((ushort) (header.Flags & FrameFlags.Compression)) != 0) { throw new NotImplementedException(); } if (((ushort) (header.Flags & FrameFlags.Encryption)) != 0) { throw new NotImplementedException(); } foreach (FrameCreator creator in frame_creators) { Frame frame = creator(data, startIndex, header, version); if (frame != null) { return frame; } } if (header.FrameId == FrameType.TXXX) { return new UserTextInformationFrame(data, startIndex, header, version); } if (header.FrameId[0] == 0x54) { return new TextInformationFrame(data, startIndex, header, version); } if (header.FrameId == FrameType.UFID) { return new UniqueFileIdentifierFrame(data, startIndex, header, version); } if (header.FrameId == FrameType.MCDI) { return new MusicCdIdentifierFrame(data, startIndex, header, version); } if (header.FrameId == FrameType.USLT) { return new UnsynchronisedLyricsFrame(data, startIndex, header, version); } if (header.FrameId == FrameType.SYLT) { return new SynchronisedLyricsFrame(data, startIndex, header, version); } if (header.FrameId == FrameType.COMM) { return new CommentsFrame(data, startIndex, header, version); } if (header.FrameId == FrameType.RVA2) { return new RelativeVolumeFrame(data, startIndex, header, version); } if (header.FrameId == FrameType.APIC) { return new AttachedPictureFrame(data, startIndex, header, version); } if (header.FrameId == FrameType.GEOB) { return new GeneralEncapsulatedObjectFrame(data, startIndex, header, version); } if (header.FrameId == FrameType.PCNT) { return new PlayCountFrame(data, startIndex, header, version); } if (header.FrameId == FrameType.POPM) { return new PopularimeterFrame(data, startIndex, header, version); } if (header.FrameId == FrameType.USER) { return new TermsOfUseFrame(data, startIndex, header, version); } if (header.FrameId == FrameType.PRIV) { return new PrivateFrame(data, startIndex, header, version); } return new UnknownFrame(data, startIndex, header, version); }
protected internal AttachedPictureFrame(ByteVector data, int offset, FrameHeader header, byte version) : base(header) { this.text_encoding = TagLib.Id3v2.Tag.DefaultEncoding; base.SetData(data, offset, version, false); }
protected internal PopularimeterFrame(ByteVector data, int offset, FrameHeader header, byte version) : base(header) { SetData(data, offset, version, false); }
protected internal AttachedPictureFrame(ByteVector data, int offset, FrameHeader header, byte version) : base(data, offset, header, version) { }
/// <summary> /// Constructs and initializes a new instance of <see /// cref="Frame" /> with a specified header. /// </summary> /// <param name="header"> /// A <see cref="FrameHeader" /> value containing the header /// to use for the new instance. /// </param> protected Frame(FrameHeader header) { this.header = header; }
/// <summary> /// Constructs and initializes a new instance of <see /// cref="AttachmentFrame" /> by reading its raw data /// in a specified ID3v2 version. /// </summary> /// <param name="data"> /// A <see cref="ByteVector" /> object containing the raw /// representation of the new frame. /// </param> /// <param name="offset"> /// A <see cref="int" /> indicating at what offset in /// <paramref name="data" /> the frame actually begins. /// </param> /// <param name="header"> /// A <see cref="FrameHeader" /> containing the header of the /// frame found at <paramref name="offset" /> in the data. /// </param> /// <param name="version"> /// A <see cref="byte" /> indicating the ID3v2 version the /// raw frame is encoded in. /// </param> protected internal AttachmentFrame(ByteVector data, int offset, FrameHeader header, byte version) : base(header) { SetData(data, offset, version, false); }
protected internal UnsynchronisedLyricsFrame(ByteVector data, int offset, FrameHeader header, byte version) : base(header) { SetData(data, offset, version, false); }
protected internal TextInformationFrame(ByteVector data, int offset, FrameHeader header, byte version) : base(header) { this.encoding = TagLib.Id3v2.Tag.DefaultEncoding; this.text_fields = new string[0]; base.SetData(data, offset, version, false); }
protected internal TextInformationFrame(ByteVector data, int offset, FrameHeader header, byte version) : base(header) { SetData(data, offset, version, false); }
protected internal GeneralEncapsulatedObjectFrame(ByteVector data, int offset, FrameHeader header, byte version) : base(header) { this.encoding = TagLib.Id3v2.Tag.DefaultEncoding; base.SetData(data, offset, version, false); }
protected internal SynchronisedLyricsFrame(ByteVector data, int offset, FrameHeader header, byte version) : base(header) { this.encoding = TagLib.Id3v2.Tag.DefaultEncoding; this.text = new SynchedText[0]; base.SetData(data, offset, version, false); }
/// <summary> /// Extracts the field data from the raw data portion of an /// ID3v2 frame. /// </summary> /// <param name="frameData"> /// A <see cref="ByteVector" /> object containing fraw frame /// data. /// </param> /// <param name="offset"> /// A <see cref="int" /> value containing the index at which /// the data is contained. /// </param> /// <param name="version"> /// A <see cref="byte" /> value containing the ID3v2 version /// of the data. /// </param> /// <returns> /// A <see cref="ByteVector" /> object containing the /// extracted field data. /// </returns> /// <remarks> /// This method is necessary for extracting extra data /// prepended to the frame such as the grouping ID. /// </remarks> /// <exception cref="ArgumentNullException"> /// <paramref name="frameData" /> is <see langword="null" />. /// </exception> protected ByteVector FieldData(ByteVector frameData, int offset, byte version) { if (frameData == null) { throw new ArgumentNullException(nameof(frameData)); } int data_offset = offset + (int)FrameHeader.Size(version); int data_length = (int)Size; if ((Flags & (FrameFlags.Compression | FrameFlags.DataLengthIndicator)) != 0) { data_offset += 4; data_length -= 4; } if ((Flags & FrameFlags.GroupingIdentity) != 0) { if (frameData.Count >= data_offset) { throw new CorruptFileException("Frame data incomplete."); } group_id = frameData[data_offset++]; data_length--; } if ((Flags & FrameFlags.Encryption) != 0) { if (frameData.Count >= data_offset) { throw new CorruptFileException("Frame data incomplete."); } encryption_id = frameData[data_offset++]; data_length--; } data_length = Math.Min(data_length, frameData.Count - data_offset); if (data_length < 0) { throw new CorruptFileException("Frame size less than zero."); } ByteVector data = frameData.Mid(data_offset, data_length); if ((Flags & FrameFlags.Unsynchronisation) != 0) { int before_length = data.Count; SynchData.ResynchByteVector(data); data_length -= (data.Count - before_length); } // FIXME: Implement encryption. if ((Flags & FrameFlags.Encryption) != 0) { throw new NotImplementedException(); } // FIXME: Implement compression. if ((Flags & FrameFlags.Compression) != 0) { throw new NotImplementedException(); } /* * if(d->header->compression()) { * ByteVector data(frameDataLength); * uLongf uLongTmp = frameDataLength; * ::uncompress((Bytef *) data.data(), * (uLongf *) &uLongTmp, * (Bytef *) frameData.data() + frameDataOffset, * size()); * return data; * } */ return(data); }
/// <summary> /// Constructs and initializes a new instance of <see /// cref="EventTimeCodesFrame" /> by reading its raw data /// in a specified ID3v2 version. /// </summary> /// <param name="frameHeader"> /// A <see cref="FrameHeader" /> containing the header of the frame /// </param> public EventTimeCodesFrame(FrameHeader frameHeader) : base(frameHeader) { }
protected internal UserTextInformationFrame (ByteVector data, int offset, FrameHeader header, byte version) : base (data, offset, header, version) { }
/// <summary> /// Constructs and initializes a new instance of <see /// cref="EventTimeCodesFrame" /> by reading its raw data /// in a specified ID3v2 version. /// </summary> /// <param name="data"> /// A <see cref="ByteVector" /> object containing the raw /// representation of the new frame. /// </param> /// <param name="offset"> /// A <see cref="int" /> indicating at what offset in /// <paramref name="data" /> the frame actually begins. /// </param> /// <param name="header"> /// A <see cref="FrameHeader" /> containing the header of the /// frame found at <paramref name="offset" /> in the data. /// </param> /// <param name="version"> /// A <see cref="byte" /> indicating the ID3v2 version the /// raw frame is encoded in. /// </param> public EventTimeCodesFrame(ByteVector data, int offset, FrameHeader header, byte version) : base(header) { SetData(data, offset, version, false); }
/// <summary> /// Constructs and initializes a new instance of <see /// cref="RelativeVolumeFrame" /> by reading its raw data in /// a specified ID3v2 version. /// </summary> /// <param name="data"> /// A <see cref="ByteVector" /> object containing the raw /// representation of the new frame. /// </param> /// <param name="offset"> /// A <see cref="int" /> indicating at what offset in /// <paramref name="data" /> the frame actually begins. /// </param> /// <param name="header"> /// A <see cref="FrameHeader" /> containing the header of the /// frame found at <paramref name="offset" /> in the data. /// </param> /// <param name="version"> /// A <see cref="byte" /> indicating the ID3v2 version the /// raw frame is encoded in. /// </param> protected internal RelativeVolumeFrame(ByteVector data, int offset, FrameHeader header, byte version) : base(header) { SetData (data, offset, version, false); }
/// <summary> /// Constructs and initializes a new instance of <see /// cref="AttachedPictureFrame" /> by reading its raw data /// in a specified ID3v2 version. /// </summary> /// <param name="data"> /// A <see cref="ByteVector" /> object containing the raw /// representation of the new frame. /// </param> /// <param name="offset"> /// A <see cref="int" /> indicating at what offset in /// <paramref name="data" /> the frame actually begins. /// </param> /// <param name="header"> /// A <see cref="FrameHeader" /> containing the header of the /// frame found at <paramref name="offset" /> in the data. /// </param> /// <param name="version"> /// A <see cref="byte" /> indicating the ID3v2 version the /// raw frame is encoded in. /// </param> protected internal AttachedPictureFrame(ByteVector data, int offset, FrameHeader header, byte version) : base(header) { SetData (data, offset, version, false); }
/// <summary> /// Creates a <see cref="Frame" /> object by reading it from /// raw ID3v2 frame data. /// </summary> /// <param name="data"> /// A <see cref="ByteVector" /> object containing a raw ID3v2 /// frame. /// </param> /// <param name="offset"> /// A <see cref="int" /> value reference specifying at what /// index in <paramref name="data" /> at which the frame /// begins. After reading, it contains the offset of the next /// frame to be read. /// </param> /// <param name="version"> /// A <see cref="byte" /> value specifying the ID3v2 version /// the frame in <paramref name="data"/> is encoded in. /// </param> /// <param name="alreadyUnsynched"> /// A <see cref="bool" /> value specifying whether the entire /// tag has already been unsynchronized. /// </param> /// <returns> /// A <see cref="Frame" /> object read from the data, or <see /// langword="null" /> if none is found. /// </returns> /// <exception cref="System.NotImplementedException"> /// The frame contained in the raw data could not be /// converted to ID3v2 or uses encryption or compression. /// </exception> public static Frame CreateFrame(ByteVector data, ref int offset, byte version, bool alreadyUnsynched) { int position = offset; FrameHeader header = new FrameHeader (data.Mid (position, (int) FrameHeader.Size (version)), version); offset += (int) (header.FrameSize + FrameHeader.Size ( version)); if (header.FrameId == null) throw new System.NotImplementedException (); foreach (byte b in header.FrameId) { char c = (char) b; if ((c < 'A' || c > 'Z') && (c < '1' || c > '9')) return null; } if (alreadyUnsynched) { // Mark the frame as not Unsynchronozed because the entire // tag has already been Unsynchronized header.Flags &= ~FrameFlags.Unsynchronisation; } // Windows Media Player may create zero byte frames. // Just send them off as unknown and delete them. if (header.FrameSize == 0) { header.Flags |= FrameFlags.TagAlterPreservation; return new UnknownFrame (data, position, header, version); } // TODO: Support Compression. if ((header.Flags & FrameFlags.Compression) != 0) throw new System.NotImplementedException (); // TODO: Support Encryption. if ((header.Flags & FrameFlags.Encryption) != 0) throw new System.NotImplementedException (); foreach (FrameCreator creator in frame_creators) { Frame frame = creator (data, position, header, version); if (frame != null) return frame; } // This is where things get necissarily nasty. Here we // determine which Frame subclass (or if none is found // simply an Frame) based on the frame ID. Since there // are a lot of possibilities, that means a lot of if // blocks. // Text Identification (frames 4.2) if (header.FrameId == FrameType.TXXX) return new UserTextInformationFrame (data, position, header, version); if (header.FrameId [0] == (byte) 'T') return new TextInformationFrame (data, position, header, version); // Involved People List (frames 4.4 in 2.3. in 2.4 this is a TIPL frame) if (header.FrameId == FrameType.IPLS) return new TextInformationFrame(data, position, header, version); // Unique File Identifier (frames 4.1) if (header.FrameId == FrameType.UFID) return new UniqueFileIdentifierFrame (data, position, header, version); // Music CD Identifier (frames 4.5) if (header.FrameId == FrameType.MCDI) return new MusicCdIdentifierFrame (data, position, header, version); // Unsynchronized Lyrics (frames 4.8) if (header.FrameId == FrameType.USLT) return new UnsynchronisedLyricsFrame (data, position, header, version); // Synchronized Lyrics (frames 4.9) if (header.FrameId == FrameType.SYLT) return new SynchronisedLyricsFrame (data, position, header, version); // Comments (frames 4.10) if (header.FrameId == FrameType.COMM) return new CommentsFrame (data, position, header, version); // Relative Volume Adjustment (frames 4.11) if (header.FrameId == FrameType.RVA2) return new RelativeVolumeFrame (data, position, header, version); // Attached Picture (frames 4.14) if (header.FrameId == FrameType.APIC) return new AttachedPictureFrame (data, position, header, version); // General Encapsulated Object (frames 4.15) if(header.FrameId == FrameType.GEOB) return new GeneralEncapsulatedObjectFrame (data, position, header, version); // Play Count (frames 4.16) if(header.FrameId == FrameType.PCNT) return new PlayCountFrame (data, position, header, version); // Play Count (frames 4.17) if(header.FrameId == FrameType.POPM) return new PopularimeterFrame (data, position, header, version); // Terms of Use (frames 4.22) if(header.FrameId == FrameType.USER) return new TermsOfUseFrame (data, position, header, version); // Private (frames 4.27) if (header.FrameId == FrameType.PRIV) return new PrivateFrame (data, position, header, version); // Url Link (frames 4.3.1) if (header.FrameId[0] == (byte)'W') return new UrlLinkFrame(data, position, header, version); return new UnknownFrame (data, position, header, version); }
protected ByteVector FieldData(ByteVector frameData, int offset, byte version) { if (frameData == null) { throw new ArgumentNullException("frameData"); } int data_offset = offset + (int)FrameHeader.Size(version); int data_length = (int)Size; /*int uncompressed_data_length;*/ if ((Flags & (FrameFlags.Compression | FrameFlags.DataLengthIndicator)) != 0) { /*uncompressed_data_length = (int) frame_data.Mid (data_offset, 4).ToUInt () + 4;*/ data_offset += 4; data_offset -= 4; } if ((Flags & FrameFlags.GroupingIdentity) != 0) { group_id = frameData [data_offset++]; data_length--; } if ((Flags & FrameFlags.Encryption) != 0) { encryption_id = frameData [data_offset++]; data_length--; } if (data_length > frameData.Count - data_offset) { throw new CorruptFileException("Frame size exceeds bounds."); } if (data_length < 0) { throw new CorruptFileException("Frame size less than zero."); } ByteVector data = frameData.Mid(data_offset, data_length); if ((Flags & FrameFlags.Unsychronisation) != 0) { SynchData.ResynchByteVector(data); } // FIXME: Implement encryption. if ((Flags & FrameFlags.Encryption) != 0) { throw new NotImplementedException(); } // FIXME: Implement compression. if ((Flags & FrameFlags.Compression) != 0) { throw new NotImplementedException(); } /* * if(d->header->compression()) { * ByteVector data(frameDataLength); * uLongf uLongTmp = frameDataLength; * ::uncompress((Bytef *) data.data(), * (uLongf *) &uLongTmp, * (Bytef *) frameData.data() + frameDataOffset, * size()); * return data; * } */ return(data); }
/// <summary> /// Load the picture data from the file, /// if not done yet. /// </summary> public void Load() { // Already loaded ? if (file == null) { return; } // Load the picture from the stream Stream stream = null; ByteVector data = null; try { if (stream_size == 0) { data = new ByteVector(); } else if (stream_size > 0) { stream = file.ReadStream; stream.Seek(stream_offset, SeekOrigin.Begin); int count = 0, read = 0, needed = (int)stream_size; byte[] buffer = new byte[needed]; do { count = stream.Read(buffer, read, needed); read += count; needed -= count; } while (needed > 0 && count != 0); data = new ByteVector(buffer, read); } else { stream = file.ReadStream; stream.Seek(stream_offset, SeekOrigin.Begin); data = ByteVector.FromStream(stream); } } finally { // Free the resources if (stream != null && file != null) { file.CloseStream(stream); } file = null; } // Decode the raw data if required, by using FieldData raw_data = FieldData(data, -(int)FrameHeader.Size(raw_version), raw_version); // Get the actual data ParseRawData(); }
protected internal GeneralEncapsulatedObjectFrame(ByteVector data, int offset, FrameHeader header, byte version) : base(header) { SetData(data, offset, version, false); }
protected internal MusicCdIdentifierFrame(ByteVector data, int offset, FrameHeader header, byte version) : base(header) { base.SetData(data, offset, version, false); }
protected internal UserUrlLinkFrame(ByteVector data, int offset, FrameHeader header, byte version) : base(data, offset, header, version) { }
public static Frame CreateFrame(ByteVector data, ref int offset, byte version, bool alreadyUnsynched) { int position = offset; FrameHeader header = new FrameHeader(data.Mid(position, (int)FrameHeader.Size(version)), version); offset += (int)(header.FrameSize + FrameHeader.Size(version)); if (header.FrameId == null) { throw new System.NotImplementedException(); } foreach (byte b in header.FrameId) { char c = (char)b; if ((c < 'A' || c > 'Z') && (c < '0' || c > '9')) { return(null); } } if (alreadyUnsynched) { header.Flags &= ~FrameFlags.Unsynchronisation; } if (header.FrameSize == 0) { header.Flags |= FrameFlags.TagAlterPreservation; return(new UnknownFrame(data, position, header, version)); } if ((header.Flags & FrameFlags.Compression) != 0) { throw new System.NotImplementedException(); } if ((header.Flags & FrameFlags.Encryption) != 0) { throw new System.NotImplementedException(); } foreach (FrameCreator creator in frame_creators) { Frame frame = creator(data, position, header, version); if (frame != null) { return(frame); } } if (header.FrameId == FrameType.TXXX) { return(new UserTextInformationFrame(data, position, header, version)); } if (header.FrameId[0] == (byte)'T') { return(new TextInformationFrame(data, position, header, version)); } if (header.FrameId == FrameType.UFID) { return(new UniqueFileIdentifierFrame(data, position, header, version)); } if (header.FrameId == FrameType.MCDI) { return(new MusicCdIdentifierFrame(data, position, header, version)); } if (header.FrameId == FrameType.USLT) { return(new UnsynchronisedLyricsFrame(data, position, header, version)); } if (header.FrameId == FrameType.SYLT) { return(new SynchronisedLyricsFrame(data, position, header, version)); } if (header.FrameId == FrameType.COMM) { return(new CommentsFrame(data, position, header, version)); } if (header.FrameId == FrameType.RVA2) { return(new RelativeVolumeFrame(data, position, header, version)); } if (header.FrameId == FrameType.APIC) { return(new AttachedPictureFrame(data, position, header, version)); } if (header.FrameId == FrameType.GEOB) { return(new GeneralEncapsulatedObjectFrame(data, position, header, version)); } if (header.FrameId == FrameType.PCNT) { return(new PlayCountFrame(data, position, header, version)); } if (header.FrameId == FrameType.POPM) { return(new PopularimeterFrame(data, position, header, version)); } if (header.FrameId == FrameType.USER) { return(new TermsOfUseFrame(data, position, header, version)); } if (header.FrameId == FrameType.PRIV) { return(new PrivateFrame(data, position, header, version)); } if (header.FrameId[0] == (byte)'W') { return(new UrlLinkFrame(data, position, header, version)); } return(new UnknownFrame(data, position, header, version)); }
protected internal GeneralEncapsulatedObjectFrame(ByteVector data, int offset, FrameHeader header, byte version) : base(data, offset, header, version) { Type = PictureType.NotAPicture; }
/// <summary> /// Populates the current instance by reading the raw frame /// from disk, optionally reading the header. /// </summary> /// <param name="data"> /// A <see cref="ByteVector" /> object containing the raw /// ID3v2 frame. /// </param> /// <param name="offset"> /// A <see cref="int" /> value containing the offset in /// <paramref name="data" /> at which the frame begins. /// </param> /// <param name="version"> /// A <see cref="byte" /> value containing the ID3v2 version /// of the raw frame contained in <paramref name="data" />. /// </param> /// <param name="readHeader"> /// A <see cref="bool" /> value indicating whether or not to /// read the header into current instance. /// </param> protected void SetData(ByteVector data, int offset, byte version, bool readHeader) { if (readHeader) header = new FrameHeader (data, version); ParseFields (FieldData (data, offset, version), version); }
/// <summary> /// Constructs a new instance of <see /// cref="AttachmentFrame" /> from a file. /// The content will be lazily loaded. /// </summary> /// <param name="abstraction"> /// A <see cref="File.IFileAbstraction"/> object containing /// abstraction of the file to read. /// </param> /// <param name="offset"> /// The position in bytes where the picture is located in the /// <see cref="File.IFileAbstraction"/>. /// </param> /// <param name="size"> /// The size in bytes of the picture in the /// <see cref="File.IFileAbstraction"/> (-1 : read all). /// </param> /// <exception cref="ArgumentNullException"> /// <paramref name="abstraction" /> is <see langword="null" /// />. /// </exception> /// <param name="header"> /// A <see cref="FrameHeader" /> containing the header of the /// frame found at <paramref name="offset" /> in the data. /// </param> /// <param name="version"> /// A <see cref="byte" /> indicating the ID3v2 version the /// raw frame is encoded in. /// </param> public AttachmentFrame(File.IFileAbstraction abstraction, long offset, long size, FrameHeader header, byte version) : base(header) { if (abstraction == null) { throw new ArgumentNullException(nameof(abstraction)); } file = abstraction; stream_offset = offset; stream_size = size; raw_version = version; }
protected internal PlayCountFrame(ByteVector data, int offset, FrameHeader header, byte version) : base(header) { base.SetData(data, offset, version, false); }
/// <summary> /// Constructs and initializes a new instance of <see /// cref="PopularimeterFrame" /> by reading its raw data in a /// specified ID3v2 version. /// </summary> /// <param name="data"> /// A <see cref="ByteVector" /> object containing the raw /// representation of the new frame. /// </param> /// <param name="offset"> /// A <see cref="int" /> indicating at what offset in /// <paramref name="data" /> the frame actually begins. /// </param> /// <param name="header"> /// A <see cref="FrameHeader" /> containing the header of the /// frame found at <paramref name="offset" /> in the data. /// </param> /// <param name="version"> /// A <see cref="byte" /> indicating the ID3v2 version the /// raw frame is encoded in. /// </param> protected internal PopularimeterFrame (ByteVector data, int offset, FrameHeader header, byte version) : base (header) { SetData (data, offset, version, false); }
protected internal TermsOfUseFrame(ByteVector data, int offset, FrameHeader header, byte version) : base(header) { this.encoding = TagLib.Id3v2.Tag.DefaultEncoding; base.SetData(data, offset, version, false); }