///// <summary> ///// find the first non-zero character in the stream ///// then back up one, so it will be the first char that gets read ///// and the stream position is pointing to the start of the non-zero (e.g. audio) data ///// </summary> ///// <param name="stream"></param> ///// <returns></returns> //static private uint SeekEndOfPadding( Stream stream ) //{ // uint index = 0; // while( stream.ReadByte() == 0 ) // { // ++index; // } // stream.Seek(-1, SeekOrigin.Current); // return index; //} /// <summary> /// Save the ID3v2 frames to a binary stream /// </summary> /// <param name="frameModel">Model keeping the ID3 Tag structure</param> /// <param name="stream">Stream keeping the ID3 Tag</param> public static void Serialize(FrameModel frameModel, Stream stream) { if (frameModel.Count <= 0) { throw new InvalidTagException("Can't serialize a ID3v2 tag without any frames, there must be at least one present."); } MemoryStream memory = new MemoryStream(); BinaryWriter writer = new BinaryWriter(memory); FrameHelper frameHelper = new FrameHelper(frameModel.Header); // Write the frames in binary format foreach (IFrame frameBase in frameModel) { //TODO: Do validations on tag name correctness byte[] frameId = new byte[4]; UTF8Encoding.UTF8.GetBytes(frameBase.FrameId, 0, 4, frameId, 0); writer.Write(frameId); // Write the 4 byte text tag byte[] frame = frameHelper.Make(frameBase); uint frameSize = (uint)frame.Length; if (frameModel.Header.Version == 4) { Sync.Safe(frameSize); } writer.Write(Swap.UInt32(frameSize)); writer.Write(Swap.UInt16(frameBase.Flags)); writer.Write(frame); } uint id3TagSize = (uint)memory.Position; // Skip the header 10 bytes for now, we will come back and write the Header // with the correct size once have the tag size + padding stream.Seek(10, SeekOrigin.Begin); // TODO: Add extended header handling if (frameModel.Header.Unsync == true) { id3TagSize += Sync.Safe(memory, stream, id3TagSize); } else { memory.WriteTo(stream); } // update the TagSize stored in the tagModel frameModel.Header.TagSize = id3TagSize; // next write the padding of zeros, if any if (frameModel.Header.Padding) { byte[] bytes = new byte[frameModel.Header.PaddingSize]; stream.Write(bytes, 0, (int)frameModel.Header.PaddingSize); } // next write the footer, if any if (frameModel.Header.Footer) { frameModel.Header.SerializeFooter(stream); } // Now seek back to the start and write the header long position = stream.Position; stream.Seek(0, SeekOrigin.Begin); frameModel.Header.Serialize(stream); // reset position to the end of the tag stream.Position = position; }
/// <summary> /// Save the ID3v2 frames to a binary stream /// </summary> /// <param name="frameModel">Model keeping the ID3 Tag structure</param> /// <param name="stream">Stream keeping the ID3 Tag</param> public static void Serialize(TagModel frameModel, Stream stream) { if (frameModel.Count <= 0) throw new InvalidTagException("Can't serialize a ID3v2 tag without any frames, there must be at least one present."); var memory = new MemoryStream(); var writer = new BinaryWriter(memory); var frameHelper = new FrameHelper(frameModel.Header); // Write the frames in binary format foreach (FrameBase frame in frameModel) { //TODO: Do validations on tag name correctness byte[] frameId = new byte[4]; UTF8Encoding.UTF8.GetBytes(frame.FrameId, 0, 4, frameId, 0); string s = UTF8Encoding.UTF8.GetString(frameId); writer.Write(frameId); // Write the 4 byte text tag ushort flags; byte[] buffer = frameHelper.Make(frame, out flags); s = UTF8Encoding.UTF8.GetString(buffer); uint frameSize = (uint)buffer.Length; if (frameModel.Header.Version == 4) frameSize = Sync.Safe(frameSize); writer.Write(Swap.UInt32(frameSize)); writer.Write(Swap.UInt16(flags)); writer.Write(buffer); } uint id3TagSize = (uint)memory.Position; // Skip the header 10 bytes for now, we will come back and write the Header // with the correct size once have the tag size + padding stream.Seek(10, SeekOrigin.Begin); // TODO: Add extended header handling if (frameModel.Header.Unsync == true) id3TagSize += Sync.Safe(memory, stream, id3TagSize); else memory.WriteTo(stream); // update the TagSize stored in the tagModel frameModel.Header.TagSize = id3TagSize; // next write the padding of zeros, if any if (frameModel.Header.Padding) { for (int i = 0; i < frameModel.Header.PaddingSize; i++) stream.WriteByte(0); } // next write the footer, if any if (frameModel.Header.Footer) frameModel.Header.SerializeFooter(stream); // Now seek back to the start and write the header long position = stream.Position; stream.Seek(0, SeekOrigin.Begin); frameModel.Header.Serialize(stream); // reset position to the end of the tag stream.Position = position; }
/// <summary> /// Save the ID3v2 frames to a binary stream /// </summary> /// <param name="frameModel">Model keeping the ID3 Tag structure</param> /// <param name="stream">Stream keeping the ID3 Tag</param> public static void Serialize([NotNull] TagModel frameModel, [NotNull] Stream stream) { if (frameModel.Count <= 0) { throw new InvalidTagException("Can't serialize a ID3v2 tag without any frames, there must be at least one present."); } using (var memory = new MemoryStream()) using (var writer = new BinaryWriter(memory, Encoding.UTF8, true)) { var frameHelper = new FrameHelper(frameModel.Header); // Write the frames in binary format foreach (var frame in frameModel) { //TODO: Do validations on tag name correctness var frameId = new byte[4]; Encoding.UTF8.GetBytes(frame.FrameId, 0, 4, frameId, 0); writer.Write(frameId); // Write the 4 byte text tag var buffer = frameHelper.Make(frame, out var flags); var frameSize = (uint)buffer.Length; if (frameModel.Header.Version == 4) { frameSize = Sync.Safe(frameSize); } writer.Write(Swap.UInt32(frameSize)); writer.Write(Swap.UInt16(flags)); writer.Write(buffer); } var id3TagSize = (uint)memory.Position; // Skip the header 10 bytes for now, we will come back and write the Header // with the correct size once have the tag size + padding stream.Seek(10, SeekOrigin.Begin); // TODO: Add extended header handling if (frameModel.Header.Unsync) { id3TagSize += Sync.Safe(memory, stream, id3TagSize); } else { memory.WriteTo(stream); } // update the TagSize stored in the tagModel frameModel.Header.TagSize = id3TagSize; // If padding + tag size is too big, shrink the padding (rather than throwing an exception) frameModel.Header.PaddingSize = Math.Min(frameModel.Header.PaddingSize, 0x10000000 - id3TagSize); // next write the padding of zeros, if any if (frameModel.Header.Padding) { for (var i = 0; i < frameModel.Header.PaddingSize; i++) { stream.WriteByte(0); } } // next write the footer, if any if (frameModel.Header.Footer) { frameModel.Header.SerializeFooter(stream); } // Now seek back to the start and write the header var position = stream.Position; stream.Seek(0, SeekOrigin.Begin); frameModel.Header.Serialize(stream); // reset position to the end of the tag stream.Position = position; } }