/// <summary> /// fill from tag /// </summary> /// <param name="idx"></param> public override void Fill() { TagV2Ext tag = new TagV2Ext(v2); UnknownFrame unk_frame = tag.GetUnknownFrame("IPLS"); if (unk_frame != null) { InvolvedPeopleFrame frame = new InvolvedPeopleFrame(unk_frame); string[] people = frame.Person; string[] functions = frame.Function; int len = people.Length; for (int i = 0; i < len; ++i) { ListViewItem item = new ListViewItem(people[i]); item.SubItems.Add(functions[i]); personList.Items.Add(item); } if (personList.Items.Count > 0) { ListViewItem item = personList.Items[0]; txtName.Text = item.Text; txtFunction.Text = item.SubItems[1].Text; } } }
public InvolvedPeopleFrame(UnknownFrame frame) { this.frame = frame; strings = this.frame.Data.ToStrings(TagLib.StringType.UTF8, 1); int len = (int)(strings.Length / 2); int total_len = strings.Length; persons = new string[len]; functions = new string[len]; for (int i = 0; i < len; i++) { int idx = (int)(i * 2); persons[i] = strings[idx]; functions[i] = strings[idx + 1]; } }
/// <summary> /// get text frame from id /// </summary> /// <param name="code">the frame id</param> /// <param name="create">if true creates the frame</param> /// <returns></returns> public UnknownFrame GetUnknownFrame(string code, bool create) { foreach (TagLib.Id3v2.UnknownFrame frame in ((TagLib.Id3v2.Tag)tag).GetFrames <TagLib.Id3v2.UnknownFrame>(code)) { return(frame); } UnknownFrame new_frame = null; if (create) { new_frame = new UnknownFrame(code); tag.AddFrame(new_frame); } return(new_frame); }
/// <summary> /// set text frame from id /// </summary> /// <param name="text"></param> public void SetText(string code, string text) { if (text != null) { if (code.StartsWith("T")) { TextInformationFrame frame = GetTextFrame(code, true); // add frame if (frame == null) { frame = new TextInformationFrame(code); tag.AddFrame(frame); } if (frame.Text.Length < 2) // one or zero { frame.Text = new string[1] { text }; } else // more than one { // add to front string[] strs = new string[frame.Text.Length]; strs[0] = text; Array.Copy(frame.Text, 1, strs, 1, frame.Text.Length - 1); } } else if (code.StartsWith("W")) { UnknownFrame frame = GetUnknownFrame(code); if (frame != null) { byte[] byts = UTF8Encoding.UTF8.GetBytes(text); frame.Data = new TagLib.ByteVector(byts); frame.Data.Add((byte)0); } } } }
/// <summary> /// get text from id /// </summary> /// <param name="code">the frame ifd</param> /// <returns></returns> public string GetText(string code) { if (code.StartsWith("T")) { TextInformationFrame frame = GetTextFrame(code); if (frame != null && frame.Text.Length > 0) { return(frame.Text[0]); } } else if (code.StartsWith("W")) { UnknownFrame frame = GetUnknownFrame(code); if (frame != null) { // todo //string[] strs = frame.Data.ToStrings( TagLib.StringType.UTF8 ); // gets the first frame return(frame.Data.ToString(TagLib.StringType.UTF8, 0, frame.Data.Count - 1)); } } return(string.Empty); }
/// <summary> /// Reads the raw data from a specified stream. /// </summary> /// <param name="stream">The stream to read from.</param> public void Read(Stream stream) { // Check for 'ID3' marker byte[] identifier = stream.Read(3); if (!(identifier[0] == 0x49 && identifier[1] == 0x44 && identifier[2] == 0x33)) { return; } // Read the header _id3v2Header = new ID3v2Header(stream, false); TagReadingInfo tagReadingInfo = new TagReadingInfo(_id3v2Header.TagVersion); if (_id3v2Header.UsesUnsynchronization) { tagReadingInfo.TagVersionOptions = TagVersionOptions.Unsynchronized; } else { tagReadingInfo.TagVersionOptions = TagVersionOptions.None; } if (_id3v2Header.HasExtendedHeader) { _id3v2ExtendedHeader = new ID3v2ExtendedHeader(tagReadingInfo, stream); } int frameIDSize = (tagReadingInfo.TagVersion == ID3v2TagVersion.ID3v22 ? 3 : 4); int bytesRead; int readUntil; #region <<< ID3v2.4 - Guess if syncsafe frame size was used or not >>> if (_id3v2Header.TagVersion == ID3v2TagVersion.ID3v24) { bool isID3v24SyncSafe = true; bytesRead = 0; readUntil = _id3v2Header.TagSize - _id3v2ExtendedHeader.SizeIncludingSizeBytes - frameIDSize; long initialPosition = stream.Position; while (bytesRead < readUntil) { byte[] frameIDBytes = stream.Read(frameIDSize); // TODO: Noticed some tags contain 0x00 'E' 'N' as a FrameID. Frame is well structured // and other frames follow. I believe the below (keep reading+looking) will cover this issue. // If character is not a letter or number, padding reached, audio began, // or otherwise the frame is not readable if (frameIDBytes[0] < 0x30 || frameIDBytes[0] > 0x5A || frameIDBytes[1] < 0x30 || frameIDBytes[1] > 0x5A || frameIDBytes[2] < 0x30 || frameIDBytes[2] > 0x5A || frameIDBytes[3] < 0x30 || frameIDBytes[3] > 0x5A) { // TODO: Try to keep reading and look for a valid frame if (frameIDBytes[0] != 0 && frameIDBytes[0] != 0xFF) { /*String msg = String.Format("Out of range FrameID - 0x{0:X}|0x{1:X}|0x{2:X}|0x{3:X}", * tmpFrameIDBytes[0], tmpFrameIDBytes[1], tmpFrameIDBytes[2], * tmpFrameIDBytes[3]); * Trace.WriteLine(msg);*/ } break; } int frameSize = stream.ReadInt32(); if (frameSize > 0xFF) { if ((frameSize & 0x80) == 0x80) { isID3v24SyncSafe = false; break; } if ((frameSize & 0x8000) == 0x8000) { isID3v24SyncSafe = false; break; } if ((frameSize & 0x800000) == 0x800000) { isID3v24SyncSafe = false; break; } if (bytesRead + frameSize + 10 == _id3v2Header.TagSize) { // Could give a false positive, but relatively unlikely (famous last words, huh?) isID3v24SyncSafe = false; break; } else { stream.Seek(-4, SeekOrigin.Current); // go back to read sync-safe version int syncSafeFrameSize = ID3v2Utils.ReadInt32SyncSafe(stream); long currentPosition = stream.Position; bool isValidAtSyncSafe = true; bool isValidAtNonSyncSafe = true; // TODO - if it's the last frame and there is padding, both would indicate false // Use the one that returns some padding bytes opposed to bytes with non-zero values (could be frame data) // If non sync-safe reads past the end of the tag, then it's sync safe // Testing non-sync safe since it will always be bigger than the sync safe integer if (currentPosition + frameSize + 2 >= readUntil) { isID3v24SyncSafe = true; break; } // Test non-sync safe stream.Seek(currentPosition + frameSize + 2, SeekOrigin.Begin); frameIDBytes = stream.Read(frameIDSize); if (frameIDBytes[0] < 0x30 || frameIDBytes[0] > 0x5A || frameIDBytes[1] < 0x30 || frameIDBytes[1] > 0x5A || frameIDBytes[2] < 0x30 || frameIDBytes[2] > 0x5A || frameIDBytes[3] < 0x30 || frameIDBytes[3] > 0x5A) { isValidAtNonSyncSafe = false; } // Test sync-safe stream.Seek(currentPosition + syncSafeFrameSize + 2, SeekOrigin.Begin); frameIDBytes = stream.Read(frameIDSize); if (frameIDBytes[0] < 0x30 || frameIDBytes[0] > 0x5A || frameIDBytes[1] < 0x30 || frameIDBytes[1] > 0x5A || frameIDBytes[2] < 0x30 || frameIDBytes[2] > 0x5A || frameIDBytes[3] < 0x30 || frameIDBytes[3] > 0x5A) { isValidAtSyncSafe = false; } // if they're equal, we'll just have to go with syncsafe, since that's the spec if (isValidAtNonSyncSafe != isValidAtSyncSafe) { isID3v24SyncSafe = isValidAtSyncSafe; } break; } } stream.Seek(frameSize + 2, SeekOrigin.Current); bytesRead += frameSize + 10; } stream.Position = initialPosition; if (isID3v24SyncSafe == false) { tagReadingInfo.TagVersionOptions |= TagVersionOptions.UseNonSyncSafeFrameSizeID3v24; } } else if (_id3v2Header.TagVersion == ID3v2TagVersion.ID3v22) { bool isID3v22CorrectSize = true; bytesRead = 0; readUntil = _id3v2Header.TagSize - _id3v2ExtendedHeader.SizeIncludingSizeBytes - frameIDSize; long initialPosition = stream.Position; stream.Read(frameIDSize); UnknownFrame unknownFrame = new UnknownFrame(null, tagReadingInfo, stream); bytesRead += unknownFrame.FrameHeader.FrameSizeTotal; if (bytesRead < readUntil) { byte[] frameIDBytes = stream.Read(frameIDSize); // TODO: Noticed some tags contain 0x00 'E' 'N' as a FrameID. Frame is well structured // and other frames follow. I believe the below (keep reading+looking) will cover this issue. // If character is not a letter or number, padding reached, audio began, // or otherwise the frame is not readable if (frameIDBytes[0] < 0x30 || frameIDBytes[0] > 0x5A) { if (frameIDBytes[1] >= 0x30 && frameIDBytes[1] <= 0x5A && frameIDBytes[2] >= 0x30 && frameIDBytes[2] <= 0x5A) { Trace.WriteLine("ID3v2.2 frame size off by 1 byte"); isID3v22CorrectSize = false; } } } stream.Position = initialPosition; if (isID3v22CorrectSize == false) { tagReadingInfo.TagVersionOptions |= TagVersionOptions.AddOneByteToSize; } } #endregion <<< ID3v2.4 - Guess if syncsafe frame size was used or not >>> readUntil = _id3v2Header.TagSize - _id3v2ExtendedHeader.SizeIncludingSizeBytes - frameIDSize; Read(stream, _id3v2Header.TagVersion, tagReadingInfo, readUntil, frameIDSize); }
public void ReadStream(Stream stream) { if (Utils.ReadString(EncodingType.ISO88591, stream, 3) == "ID3") { int num2; int num3; this.m_ID3v2Header = new ID3v2Header(stream, false); TagReadingInfo info1 = new TagReadingInfo(this.m_ID3v2Header.TagVersion); if (this.m_ID3v2Header.UsesUnsynchronization) { info1.TagVersionOptions = TagVersionOptions.Unsynchronized; } else { info1.TagVersionOptions = TagVersionOptions.None; } if (this.m_ID3v2Header.HasExtendedHeader) { this.m_ID3v2ExtendedHeader = new ID3v2ExtendedHeader(info1, stream); } int num1 = (info1.TagVersion == ID3v2TagVersion.ID3v22) ? 3 : 4; if (this.m_ID3v2Header.TagVersion != ID3v2TagVersion.ID3v24) { if (this.m_ID3v2Header.TagVersion == ID3v2TagVersion.ID3v22) { bool flag4 = true; num2 = 0; num3 = (this.m_ID3v2Header.TagSize - this.m_ID3v2ExtendedHeader.SizeIncludingSizeBytes) - num1; long num8 = stream.Position; Utils.Read(stream, num1); UnknownFrame frame1 = new UnknownFrame(null, info1, stream); num2 += frame1.FrameHeader.FrameSizeTotal; if (num2 < num3) { byte[] buffer2 = Utils.Read(stream, num1); if (((buffer2[0] < 0x30) || (buffer2[0] > 90)) && (((buffer2[1] >= 0x30) && (buffer2[1] <= 90)) && ((buffer2[2] >= 0x30) && (buffer2[2] <= 90)))) { Trace.WriteLine("ID3v2.2 frame size off by 1 byte"); flag4 = false; } } stream.Position = num8; if (!flag4) { info1.TagVersionOptions |= TagVersionOptions.AddOneByteToSize; } } } else { bool flag1 = true; num2 = 0; num3 = (this.m_ID3v2Header.TagSize - this.m_ID3v2ExtendedHeader.SizeIncludingSizeBytes) - num1; long num4 = stream.Position; while (num2 < num3) { byte[] buffer1 = Utils.Read(stream, num1); if ((((buffer1[0] < 0x30) || (buffer1[0] > 90)) || ((buffer1[1] < 0x30) || (buffer1[1] > 90))) || (((buffer1[2] < 0x30) || (buffer1[2] > 90)) || ((buffer1[3] < 0x30) || (buffer1[3] > 90)))) { if ((buffer1[0] != 0) && (buffer1[0] != 0xff)) { } break; } int num5 = Utils.ReadInt32(stream); if (num5 > 0xff) { if ((num5 & 0x80) == 0x80) { flag1 = false; break; } if ((num5 & 0x8000) == 0x8000) { flag1 = false; break; } if ((num5 & 0x800000) == 0x800000) { flag1 = false; break; } if (((num2 + num5) + 10) == this.m_ID3v2Header.TagSize) { flag1 = false; break; } stream.Seek((long)(-4), SeekOrigin.Current); int num6 = Utils.ReadInt32SyncSafe(stream); long num7 = stream.Position; bool flag2 = true; bool flag3 = true; if (((num7 + num5) + 2) >= num3) { flag1 = true; break; } stream.Seek((num7 + num5) + 2, SeekOrigin.Begin); buffer1 = Utils.Read(stream, num1); if ((((buffer1[0] < 0x30) || (buffer1[0] > 90)) || ((buffer1[1] < 0x30) || (buffer1[1] > 90))) || (((buffer1[2] < 0x30) || (buffer1[2] > 90)) || ((buffer1[3] < 0x30) || (buffer1[3] > 90)))) { flag3 = false; } stream.Seek((num7 + num6) + 2, SeekOrigin.Begin); buffer1 = Utils.Read(stream, num1); if ((((buffer1[0] < 0x30) || (buffer1[0] > 90)) || ((buffer1[1] < 0x30) || (buffer1[1] > 90))) || (((buffer1[2] < 0x30) || (buffer1[2] > 90)) || ((buffer1[3] < 0x30) || (buffer1[3] > 90)))) { flag2 = false; } if (flag3 != flag2) { flag1 = flag2; } break; } stream.Seek((long)(num5 + 2), SeekOrigin.Current); num2 += num5 + 10; } stream.Position = num4; if (!flag1) { info1.TagVersionOptions |= TagVersionOptions.UseNonSyncSafeFrameSizeID3v24; } } num3 = (this.m_ID3v2Header.TagSize - this.m_ID3v2ExtendedHeader.SizeIncludingSizeBytes) - num1; base.Read(stream, this.m_ID3v2Header.TagVersion, info1, num3, num1); } }
internal void Read(Stream stream, ID3v2TagVersion tagVersion, TagReadingInfo tagReadingInfo, int readUntil, int frameIDSize) { Dictionary <string, IBindingList> multipleOccurrenceFrames = GetMultipleOccurrenceFrames(tagVersion); Dictionary <string, IFrame> singleOccurrenceFrames = GetSingleOccurrenceFrames(tagVersion); int bytesRead = 0; while (bytesRead < readUntil) { byte[] frameIDBytes = stream.Read(frameIDSize); // If character is not a letter or number, padding reached, audio began, // or otherwise the frame is not readable if (frameIDSize == 4) { if (frameIDBytes[0] < 0x30 || frameIDBytes[0] > 0x5A || frameIDBytes[1] < 0x30 || frameIDBytes[1] > 0x5A || frameIDBytes[2] < 0x30 || frameIDBytes[2] > 0x5A || frameIDBytes[3] < 0x30 || frameIDBytes[3] > 0x5A) { // TODO: Try to keep reading and look for a valid frame if (frameIDBytes[0] != 0 && frameIDBytes[0] != 0xFF) { string msg = string.Format("Out of range FrameID - 0x{0:X}|0x{1:X}|0x{2:X}|0x{3:X}", frameIDBytes[0], frameIDBytes[1], frameIDBytes[2], frameIDBytes[3]); if (ByteUtils.ISO88591GetString(frameIDBytes) != "MP3e") { string tmpBadFrameID = ByteUtils.ISO88591GetString(frameIDBytes).TrimEnd('\0'); Trace.WriteLine(msg + " - " + tmpBadFrameID); } } break; } } else if (frameIDSize == 3) { if (frameIDBytes[0] < 0x30 || frameIDBytes[0] > 0x5A || frameIDBytes[1] < 0x30 || frameIDBytes[1] > 0x5A || frameIDBytes[2] < 0x30 || frameIDBytes[2] > 0x5A) { // TODO: Try to keep reading and look for a valid frame if (frameIDBytes[0] != 0 && frameIDBytes[0] != 0xFF) { string msg = string.Format("Out of range FrameID - 0x{0:X}|0x{1:X}|0x{2:X}", frameIDBytes[0], frameIDBytes[1], frameIDBytes[2]); Trace.WriteLine(msg); Trace.WriteLine(ByteUtils.ISO88591GetString(frameIDBytes)); } break; } } string frameID = ByteUtils.ISO88591GetString(frameIDBytes); // TODO: Take out //Console.WriteLine(tmpFrameID); // TODO: take out /* * COMM Frames: * SoundJam_CDDB_TrackNumber * SoundJam_CDDB_1 * iTunNORM * iTunSMPB * iTunes_CDDB_IDs * iTunes_CDDB_1 * iTunes_CDDB_TrackNumber */ IFrame frame; do { IBindingList bindingList; if (singleOccurrenceFrames.TryGetValue(frameID, out frame)) { frame.Read(tagReadingInfo, stream); bytesRead += frame.FrameHeader.FrameSizeTotal; //m_ReadFrames.Add(tmpFrame); } else if (multipleOccurrenceFrames.TryGetValue(frameID, out bindingList)) { frame = (IFrame)bindingList.AddNew(); frame.Read(tagReadingInfo, stream); //m_ReadFrames.Add(tmpFrame); bytesRead += frame.FrameHeader.FrameSizeTotal; } else { if (tagVersion == ID3v2TagVersion.ID3v24) { string newFrameID; if (_id3v24FrameAliases.TryGetValue(frameID, out newFrameID)) { frameID = newFrameID; } else { break; } } else if (tagVersion == ID3v2TagVersion.ID3v23) { string newFrameID; if (_id3v23FrameAliases.TryGetValue(frameID, out newFrameID)) { frameID = newFrameID; } else { break; } } else { break; } } } while (frame == null); // Frame is unknown if (frame == null) { if (frameID != "NCON" && // non standard (old music match) frameID != "MJMD" && // Non standard frame (Music Match XML) frameID != "TT22" && // 000.00 - maybe meant to be 3 letter TT2 frame, and value be 2000.00? still makes no sense frameID != "PCST" && // null data frameID != "TCAT" && // category (ie, comedy) (distorted view) frameID != "TKWD" && // looks like blog tags "comedy funny weird", etc (distorted view) frameID != "TDES" && // xml file - used by distortedview.com frameID != "TGID" && // url (from distortedview) frameID != "WFED" && // url (thanks distortedview) frameID != "CM1" && // some kind of comment, seen in ID3v2.2 frameID != "TMB" && // ripped by something other, not in spec frameID != "RTNG" && frameID != "XDOR" && // year frameID != "XSOP" && // looks like artist, "Allman Brothers Band, The" frameID != "TENK") // itunes encoder (todo: add alias?) { /*String msg = String.Format("Unrecognized FrameID '{0}' (not critical)", tmpFrameID); * Trace.WriteLine(msg);*/ } UnknownFrame unknownFrame = new UnknownFrame(frameID, tagReadingInfo, stream); _unknownFrames.Add(unknownFrame); //m_ReadFrames.Add(tmpUNKN); bytesRead += unknownFrame.FrameHeader.FrameSizeTotal; } } // Process iTunes comments for (int i = 0; i < m_CommentsList.Count;) { var comment = m_CommentsList[i]; if (comment.Description?.StartsWith("iTun", StringComparison.Ordinal) == true) { m_CommentsList.RemoveAt(i); m_iTunesCommentsList.Add(comment); } else { i++; } } // Process genre // TODO: may need cleanup if (!string.IsNullOrEmpty(m_Genre.Value)) { if (m_Genre.Value.StartsWith("(")) { int closeIndex = m_Genre.Value.IndexOf(')'); if (closeIndex != -1) { if (closeIndex != m_Genre.Value.Length - 1) { // Take text description m_Genre.Value = m_Genre.Value.Substring(closeIndex + 1, m_Genre.Value.Length - (closeIndex + 1)); } else { // Lookup genre value string innerValue = m_Genre.Value.Substring(1, closeIndex - 1); int innerValueResult; if (int.TryParse(innerValue, out innerValueResult)) { if (GenreHelper.GenreByIndex.Length > innerValueResult && innerValueResult >= 0) { m_Genre.Value = GenreHelper.GenreByIndex[innerValueResult]; } else { Trace.WriteLine("Unrecognized genre"); } } else { Trace.WriteLine("Unrecognized genre"); } } } } } }