protected override void SetPicture(TagLib.File file, Tag tag) { TagLib.Ogg.File oggFile = (TagLib.Ogg.File)file; GroupedComment groupedCommentTag = (GroupedComment)tag; if (string.IsNullOrWhiteSpace(CoverFilePath)) { return; } // Is there a way to get Ogg file header using TagLib#? PropertyInfo headerProp = oggFile.GetType().GetProperty("LastPageHeader", BindingFlags.Instance | BindingFlags.NonPublic); PageHeader header = (PageHeader)headerProp.GetValue(oggFile); // Add cover art to Vorbis Comment approved METADATA_BLOCK_PICTURE field. TagLib.Flac.Picture pic = new TagLib.Flac.Picture(new Picture(CoverFilePath)) { Description = "" }; ByteVector picData = pic.Render(); XiphComment xiphComment = groupedCommentTag.GetComment(header.StreamSerialNumber); xiphComment.SetField("METADATA_BLOCK_PICTURE", Convert.ToBase64String(picData.Data)); }
/// <summary> /// Constructs and initializes a new instance of <see /// cref="Page" /> by reading a raw Ogg page from a specified /// position in a specified file. /// </summary> /// <param name="file"> /// A <see cref="File" /> object containing the file from /// which the contents of the new instance are to be read. /// </param> /// <param name="position"> /// A <see cref="long" /> value specify at what position to /// read. /// </param> /// <exception cref="ArgumentNullException"> /// <paramref name="file" /> is <see langword="null" />. /// </exception> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="position" /> is less than zero or greater /// than the size of the file. /// </exception> /// <exception cref="CorruptFileException"> /// The Ogg identifier could not be found at the correct /// location. /// </exception> public Page(File file, long position) : this(new PageHeader (file, position)) { file.Seek (position + header.Size); foreach (int packet_size in header.PacketSizes) packets.Add (file.ReadBlock (packet_size)); }
public Page (File file, long position) : this (new PageHeader (file, position)) { if (file == null) throw new ArgumentNullException ("file"); file.Seek (position + header.Size); foreach (int packet_size in header.PacketSizes) packets.Add (file.ReadBlock (packet_size)); }
public File (File.IFileAbstraction abstraction, ReadStyle propertiesStyle) : base (abstraction) { Mode = AccessMode.Read; try { tag = new GroupedComment (); Read (propertiesStyle); TagTypesOnDisk = TagTypes; } finally { Mode = AccessMode.Closed; } }
/// <summary> /// Constructs and initializes a new instance of <see /// cref="File" /> for a specified file abstraction with an /// average read style. /// </summary> /// <param name="abstraction"> /// A <see cref="IFileAbstraction" /> object to use when /// reading from and writing to the file. /// </param> /// <exception cref="ArgumentNullException"> /// <paramref name="abstraction" /> is <see langword="null" /// />. /// </exception> public File (File.IFileAbstraction abstraction) : this (abstraction, ReadStyle.Average) { }
public static void OverwriteSequenceNumbers (File file, long position, IDictionary<uint, int> shiftTable) { bool done = true; foreach (KeyValuePair<uint, int> pair in shiftTable) if (pair.Value != 0) { done = false; break; } if (done) return; while (position < file.Length) { PageHeader header = new PageHeader (file, position); int size = (int) (header.Size + header.DataSize); if (shiftTable.ContainsKey (header.StreamSerialNumber) && shiftTable [header.StreamSerialNumber] != 0) { file.Seek (position); ByteVector page_data = file.ReadBlock (size); ByteVector new_data = ByteVector.FromUInt ( (uint)(header.PageSequenceNumber + shiftTable [header.StreamSerialNumber]), false); for (int i = 18; i < 22; i ++) page_data [i] = new_data [i - 18]; for (int i = 22; i < 26; i++) page_data [i] = 0; new_data.Add (ByteVector.FromUInt ( page_data.Checksum, false)); file.Seek (position + 18); file.WriteBlock (new_data); } position += size; } }
/// <summary> /// Constructs and initializes a new instance of <see /// cref="PageHeader" /> by reading a raw Ogg page header /// from a specified position in a specified file. /// </summary> /// <param name="file"> /// A <see cref="File" /> object containing the file from /// which the contents of the new instance are to be read. /// </param> /// <param name="position"> /// A <see cref="long" /> value specify at what position to /// read. /// </param> /// <exception cref="ArgumentNullException"> /// <paramref name="file" /> is <see langword="null" />. /// </exception> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="position" /> is less than zero or greater /// than the size of the file. /// </exception> /// <exception cref="CorruptFileException"> /// The Ogg identifier could not be found at the correct /// location. /// </exception> public PageHeader(File file, long position) { if (file == null) throw new ArgumentNullException ("file"); if (position < 0 || position > file.Length - 27) throw new ArgumentOutOfRangeException ( "position"); file.Seek (position); // An Ogg page header is at least 27 bytes, so we'll go // ahead and read that much and then get the rest when // we're ready for it. ByteVector data = file.ReadBlock (27); if (data.Count < 27 || !data.StartsWith ("OggS")) System.Console.WriteLine( "Error reading page header"); version = data [4]; this.flags = (PageFlags) data [5]; absolute_granular_position = data.Mid(6, 8).ToULong ( false); stream_serial_number = data.Mid(14, 4).ToUInt (false); page_sequence_number = data.Mid(18, 4).ToUInt (false); // Byte number 27 is the number of page segments, which // is the only variable length portion of the page // header. After reading the number of page segments // we'll then read in the coresponding data for this // count. int page_segment_count = data [26]; ByteVector page_segments = file.ReadBlock (page_segment_count); // Another sanity check. if (page_segment_count < 1 || page_segments.Count != page_segment_count) System.Console.WriteLine( "Incorrect number of page segments"); // The base size of an Ogg page 27 bytes plus the number // of lacing values. size = (uint)(27 + page_segment_count); packet_sizes = new List<int> (); int packet_size = 0; data_size = 0; for (int i = 0; i < page_segment_count; i++) { data_size += page_segments [i]; packet_size += page_segments [i]; if (page_segments [i] < 255) { packet_sizes.Add (packet_size); packet_size = 0; } } if (packet_size > 0) packet_sizes.Add (packet_size); }
/// <summary> /// Overwrites all page headers in a file starting at a /// specified position, shifting the page sequence numbers /// a set amount. /// </summary> /// <param name="file"> /// A <see cref="File" /> object containing the file to /// update. /// </param> /// <param name="position"> /// A <see cref="long" /> value specify at what position to /// start updating. /// </param> /// <param name="shiftTable"> /// A <see cref="T:System.Collections.Generic.IDictionary`2" /// /> object where the key is the serial number of the /// stream to update and the value is the amount to offset /// the page sequence numbers in the stream. /// </param> /// <exception cref="ArgumentNullException"> /// <paramref name="file" /> or <paramref name="shiftTable" /// /> is <see langword="null" />. /// </exception> /// <remarks> /// When the number of pages in a stream changes, all /// subsequent pages in the stream need to have their page /// sequence number update in order to remain valid. /// Additionally, when the page sequence number changes, the /// page needs to have its checksum recomputed. This makes /// for a costly recalculation if large comment data is /// added. /// </remarks> public static void OverwriteSequenceNumbers (File file, long position, IDictionary<uint, int> shiftTable) { if (file == null) throw new ArgumentNullException ("file"); if (shiftTable == null) throw new ArgumentNullException ("shiftTable"); // Check to see if there are no changes to be made. bool done = true; foreach (KeyValuePair<uint, int> pair in shiftTable) if (pair.Value != 0) { done = false; break; } // If the file is fine, quit. if (done) return; while (position < file.Length - 27) { PageHeader header = new PageHeader (file, position); int size = (int) (header.Size + header.DataSize); if (shiftTable.ContainsKey (header.StreamSerialNumber) && shiftTable [header.StreamSerialNumber] != 0) { file.Seek (position); ByteVector page_data = file.ReadBlock (size); ByteVector new_data = ByteVector.FromUInt ( (uint)(header.PageSequenceNumber + shiftTable [header.StreamSerialNumber]), false); for (int i = 18; i < 22; i ++) page_data [i] = new_data [i - 18]; for (int i = 22; i < 26; i++) page_data [i] = 0; new_data.Add (ByteVector.FromUInt ( page_data.Checksum, false)); file.Seek (position + 18); file.WriteBlock (new_data); } position += size; } }