internal static byte[] ApplyUnsynchronization(byte[] data) { MemoryStream ms = new MemoryStream(data.Length * 2); UnsyncFilterStream fs = new UnsyncFilterStream(ms, UnsyncMode.Write, true); fs.Write(data, 0, data.Length); fs.ApplyFinalization(); ms.Close(); return ms.ToArray(); }
private static void WriteContentToStream(Stream s, ID3v2Tag tag) { if ((tag.Flags & ID3v2TagFlags.Unsync) == ID3v2TagFlags.Unsync) { UnsyncFilterStream unsyncFilterStream = new UnsyncFilterStream(s, UnsyncMode.Write, true); foreach (Frame f in tag.Frames) { FrameEncoder.EncodeFrame(unsyncFilterStream, f, tag); } unsyncFilterStream.ApplyFinalization(); } else { foreach (Frame f in tag.Frames) { FrameEncoder.EncodeFrame(s, f, tag); } } }
/* * ID3 Tag Identifier * 03 00 2 bytes Version information * xx Tag flags * xx xx xx xx Tag size excluding header but including extended header as sync safe integer * [Extended header] * {Frames} * [Padding] included in tag size * * Note: Unsync is applied on tag level; footer is not allowed. * */ private static void EncodeID3v2_3Tag(Stream s, ID3v2Tag tag) { long paddingLen; byte flags = 0; const long TagHeaderSize = 10L; const long ExtHeaderSizeWithCrc = 14L; const long ExtHeaderSizeWithoutCrc = 10L; /* generate flag byte */ if ((tag.Flags & ID3v2TagFlags.Unsync) == ID3v2TagFlags.Unsync) { flags |= 0x80; } if (tag.ExtendedHeader != null) { flags |= 0x40; } if ((tag.Flags & ID3v2TagFlags.Experimental) == ID3v2TagFlags.Experimental) { flags |= 0x20; } /* write tag header */ StringEncoder.WriteLatin1String(s, "ID3", 3); s.WriteByte(0x03); s.WriteByte(0x00); s.WriteByte(flags); /* skip size */ s.Position += 4; if (tag.ExtendedHeader != null) { long crc; byte[] frameData = GetFrameRawData(tag); if ((tag.ExtendedHeader.Flags & ExtendedHeaderFlags.CrcPresent) == ExtendedHeaderFlags.CrcPresent) { crc = Crc32.ComputeCrc(frameData); paddingLen = ComputePaddingSize(frameData.Length + TagHeaderSize + ExtHeaderSizeWithCrc, tag); } else { crc = -1L; paddingLen = ComputePaddingSize(frameData.Length + TagHeaderSize + ExtHeaderSizeWithoutCrc, tag); } if ((tag.Flags & ID3v2TagFlags.Unsync) == ID3v2TagFlags.Unsync) { UnsyncFilterStream unsyncFilterStream = new UnsyncFilterStream(s, UnsyncMode.Write, true); EncodeID3v2_3ExtendedHeader(unsyncFilterStream, tag.ExtendedHeader, paddingLen, crc); unsyncFilterStream.Write(frameData, 0, frameData.Length); unsyncFilterStream.ApplyFinalization(); } else { EncodeID3v2_3ExtendedHeader(s, tag.ExtendedHeader, paddingLen, crc); s.Write(frameData, 0, frameData.Length); } } else { /* no extended header */ WriteContentToStream(s, tag); paddingLen = ComputePaddingSize(s.Length, tag); } /* update tag size */ s.SetLength(s.Length + paddingLen); s.Position = 6; NumberConverter.WriteInt(s.Length - TagHeaderSize, s, 4, true); }