/* * xx xx xx xx Extended Header size, excluding itself; currently 6 or 10 bytes; not sync safe. * xx xx Flags * xx xx xx xx Size of padding; not sync safe * [xx xx xx xx] 4 bytes of CRC Data; not sync safe * */ private static void EncodeID3v2_3ExtendedHeader(Stream s, ExtendedHeader extHeader, long paddingLen, long crc) { bool writeCRCData = ((extHeader.Flags & ExtendedHeaderFlags.CrcPresent) == ExtendedHeaderFlags.CrcPresent); int size = (writeCRCData ? 10 : 6); NumberConverter.WriteInt(size, s, 4, false); s.WriteByte((writeCRCData ? (byte)0x80 : (byte)0x00)); s.WriteByte(0x00); NumberConverter.WriteInt(paddingLen, s, 4, false); if (writeCRCData) { NumberConverter.WriteInt(crc, s, 4, false); /* update crc checksum in extended header */ extHeader.CrcChecksum = crc; } }
/* * xx xx xx xx Extended header size(min 6) as syncsafe int * xx Number of flag bytes(currently 1) * xx Flags * {sizeByte [flagdata]} For every set bit in flag one entry * */ private static void EncodeID3v2_4ExtendedHeader(Stream s, ExtendedHeader extHeader, long crc) { int size = 6; byte flagByte = 0; /* compute flag byte */ if ((extHeader.Flags & ExtendedHeaderFlags.UpdateTag) == ExtendedHeaderFlags.UpdateTag) { flagByte |= 0x40; size += 1; } if ((extHeader.Flags & ExtendedHeaderFlags.CrcPresent) == ExtendedHeaderFlags.CrcPresent) { flagByte |= 0x20; size += 6; } if ((extHeader.Flags & ExtendedHeaderFlags.RestrictTag) == ExtendedHeaderFlags.RestrictTag) { flagByte |= 0x10; size += 2; } /* write Header */ NumberConverter.WriteInt(size, s, 4, true); s.WriteByte(0x01); s.WriteByte(flagByte); /* write attached data */ if ((extHeader.Flags & ExtendedHeaderFlags.UpdateTag) != 0) { s.WriteByte(0x00); } if ((extHeader.Flags & ExtendedHeaderFlags.CrcPresent) != 0) { s.WriteByte(0x05); NumberConverter.WriteInt(crc, s, 5, true); /* update crc checksum in extended header */ extHeader.CrcChecksum = crc; } if ((extHeader.Flags & ExtendedHeaderFlags.RestrictTag) != 0) { byte restrictFlagByte = 0; restrictFlagByte |= (byte)extHeader.TagSizeRestriction; restrictFlagByte |= (byte)extHeader.TextEncodingRestriction; restrictFlagByte |= (byte)extHeader.TextFieldSizeRestriction; restrictFlagByte |= (byte)extHeader.TextFieldSizeRestriction; restrictFlagByte |= (byte)extHeader.ImageEncodingRestriction; restrictFlagByte |= (byte)extHeader.ImageSizeRestriction; s.WriteByte(0x01); s.WriteByte(restrictFlagByte); } }
/* * xx xx xx xx Extended header size(min 6) as syncsafe int * xx Number of flag bytes(currently 1) * xx Flags * {sizeByte [flagdata]} For every set bit in flag one entry * */ private static int DecodeID3v2_4ExtendedHeader(byte[] tagContent, ExtendedHeader extHeader) { int extHeaderSize, index; CheckLength(tagContent, 6); extHeaderSize = NumberConverter.ReadInt32(tagContent, 0, 4, true); if (extHeaderSize < 6) { throw new ID3ParseException("Size mismatch in extended header."); } if (tagContent[4] != 0x01) { throw new ID3ParseException("Flag byte count in extended header does not match."); } CheckLength(tagContent, extHeaderSize); /* parse extended header flags */ extHeader.Flags = ExtendedHeaderFlags.None; index = 6; if ((tagContent[5] & 0x40) != 0) { extHeader.Flags |= ExtendedHeaderFlags.UpdateTag; if (index >= extHeaderSize || tagContent[index] != 0x00) { throw new ID3ParseException("Error while parsing extended header flag data."); } index += 1; } if ((tagContent[5] & 0x20) != 0) { extHeader.Flags |= ExtendedHeaderFlags.CrcPresent; if (index + 5 >= extHeaderSize || tagContent[index] != 0x05) { throw new ID3ParseException("Error while parsing extended header flag data."); } long savedCrc = NumberConverter.ReadInt64(tagContent, index + 1, 5, true); Crc32 crcCalculator = new Crc32(); crcCalculator.UpdateCrc(tagContent, extHeaderSize, tagContent.Length - extHeaderSize); if (savedCrc != crcCalculator.Crc) { throw new ID3CrcMismatchException(savedCrc, crcCalculator.Crc); } extHeader.CrcChecksum = savedCrc; index += 6; } if ((tagContent[5] & 0x10) != 0) { extHeader.Flags |= ExtendedHeaderFlags.RestrictTag; if (index + 1 >= extHeaderSize || tagContent[index] != 0x01) { throw new ID3ParseException("Error while parsing extended header flag data."); } index += 1; extHeader.TagSizeRestriction = (TagSizeRestriction)(tagContent[index] & 0xC0); extHeader.TextEncodingRestriction = (TextEncodingRestriction)(tagContent[index] & 0x20); extHeader.TextFieldSizeRestriction = (TextFieldSizeRestriction)(tagContent[index] & 0x18); extHeader.ImageEncodingRestriction = (ImageEncodingRestriction)(tagContent[index] & 0x4); extHeader.ImageSizeRestriction = (ImageSizeRestriction)(tagContent[index] & 0x3); index += 1; } if ((tagContent[5] & 0x8F) != 0) { throw new ID3ParseException("Invalid entended header flag set."); } if (index != extHeaderSize) { throw new ID3ParseException("Size mismatch in extended header."); } return extHeaderSize; }
public bool Equals(ExtendedHeader other) { if (other == null) { return false; } if (flags != other.flags) { return false; } if ((flags & ExtendedHeaderFlags.CrcPresent) == ExtendedHeaderFlags.CrcPresent && crcChecksum != other.crcChecksum) { return false; } if ((flags & ExtendedHeaderFlags.RestrictTag) == ExtendedHeaderFlags.RestrictTag) { if (textEncodingRestriction != other.textEncodingRestriction || tagSizeRestriction != other.tagSizeRestriction || textFieldSizeRestriction != other.textFieldSizeRestriction || imageEncodingRestriction != other.imageEncodingRestriction || imageSizeRestriction != other.imageSizeRestriction) { return false; } } return true; }
/* * xx xx xx xx Extended Header size, excluding itself; currently 6 or 10 bytes; not sync safe. * xx xx Flags * xx xx xx xx Size of padding; not sync safe * [xx xx xx xx] 4 bytes of CRC Data; not sync safe * */ private static int DecodeID3v2_3ExtendedHeader(byte[] tagContent, ExtendedHeader extHeader) { int extHeaderSize, paddingSize; CheckLength(tagContent, 10); extHeaderSize = NumberConverter.ReadInt32(tagContent, 0, 4, false); paddingSize = NumberConverter.ReadInt32(tagContent, 6, 4, false); if ((tagContent[4] & 0x7F) != 0 || tagContent[5] != 0x00) { throw new ID3ParseException("Unknown extended header flag set."); } if (tagContent[4] == 0x80) { extHeader.Flags = ExtendedHeaderFlags.CrcPresent; if (extHeaderSize != 10) { throw new ID3ParseException("Invalid extended header size."); } CheckLength(tagContent, 14); long savedCrc = NumberConverter.ReadInt64(tagContent, 10, 4, false); int dataLength = tagContent.Length - 14 - paddingSize; Crc32 crcCalculator = new Crc32(); if (dataLength < 0) { throw new ID3ParseException("Padding size mismatch in extended header."); } crcCalculator.UpdateCrc(tagContent, 14, dataLength); if (savedCrc != crcCalculator.Crc) { throw new ID3CrcMismatchException(savedCrc, crcCalculator.Crc); } extHeader.CrcChecksum = savedCrc; } else { extHeader.Flags = ExtendedHeaderFlags.None; if (extHeaderSize != 6) { throw new ID3ParseException("Invalid extended header size."); } } return extHeaderSize; }