/// <summary> /// Initializes a new instance of the <see cref="Id3v2SynchronizedLyricsFrame"/> class. /// </summary> /// <param name="version">The version.</param> /// <exception cref="InvalidVersionException">Thrown if <paramref name="version"/> is not supported by this frame.</exception> public Id3v2SynchronizedLyricsFrame(Id3v2Version version) : base(version) { if (!IsVersionSupported(version)) throw new InvalidVersionException(String.Format("Version {0} not supported by this frame.", version)); BindLyricSyncListEvents(); }
/// <summary> /// Initializes a new instance of the <see cref="Id3v2EventTimingCodesFrame" /> class. /// </summary> /// <param name="version">The version.</param> /// <exception cref="InvalidVersionException">Thrown if <paramref name="version" /> is not supported by this frame.</exception> public Id3v2EventTimingCodesFrame(Id3v2Version version) : base(version) { if (!IsVersionSupported(version)) throw new InvalidVersionException(String.Format("Version {0} not supported by this frame.", version)); BindKeyEventListEvents(); }
/// <summary> /// Initializes a new instance of the <see cref="Id3v2Equalisation2Frame"/> class. /// </summary> /// <param name="version">The version.</param> /// <exception cref="InvalidVersionException">Thrown if <paramref name="version"/> is not supported by this frame.</exception> public Id3v2Equalisation2Frame(Id3v2Version version) : base(version) { if (!IsVersionSupported(version)) throw new InvalidVersionException(String.Format("Version {0} not supported by this frame.", version)); BindAdjustmentPointsListEvents(); }
/// <summary> /// Initializes a new instance of the <see cref="Id3v2RelativeVolumeAdjustment2Frame"/> class. /// </summary> /// <param name="version">The version.</param> /// <exception cref="InvalidVersionException">Thrown if <paramref name="version"/> is not supported by this frame.</exception> public Id3v2RelativeVolumeAdjustment2Frame(Id3v2Version version) : base(version) { if (!IsVersionSupported(version)) throw new InvalidVersionException(String.Format("Version {0} not supported by this frame.", version)); BindChannelInformationListEvents(); }
/// <summary> /// Initializes a new instance of the <see cref="Id3v2InvolvedPeopleListFrame"/> class. /// </summary> /// <param name="version">The version.</param> /// <exception cref="InvalidVersionException">Thrown if <paramref name="version"/> is not supported by this frame.</exception> public Id3v2InvolvedPeopleListFrame(Id3v2Version version) : base(version) { if (!IsVersionSupported(version)) throw new InvalidVersionException(String.Format("Version {0} not supported by this frame.", version)); BindInvolvedPeopleListEvents(); }
////------------------------------------------------------------------------------------------------------------------------------ /// <summary> /// Initializes a new instance of the <see cref="Id3v2LinkedInformationFrame" /> class. /// </summary> /// <param name="version">The version.</param> /// <param name="frameIdentifier">The frame identifier.</param> /// <exception cref="System.ArgumentNullException">Thrown if <paramref name="frameIdentifier" /> is null.</exception> /// <exception cref="InvalidVersionException">Thrown if <paramref name="version"/> is not supported by this frame.</exception> public Id3v2LinkedInformationFrame(Id3v2Version version, string frameIdentifier) : base(version) { if (frameIdentifier == null) throw new ArgumentNullException("frameIdentifier"); if (!IsVersionSupported(version)) throw new InvalidVersionException(String.Format("Version {0} not supported by this frame.", version)); FrameIdentifier = frameIdentifier; }
////------------------------------------------------------------------------------------------------------------------------------ /// <summary> /// Initializes a new instance of the <see cref="Id3v2UrlLinkFrame"/> class. /// </summary> /// <param name="version">The version.</param> /// <param name="identifier">The identifier of the frame type for the <see cref="Id3v2Version"/> supplied.</param> /// <remarks> /// When the <paramref name="identifier"/> is not a valid/known identifier for the <paramref name="version"/>, it will look through all the known identifiers /// and see if a known identifier partly matches the <paramref name="identifier"/>. If found, it will get the proper identifier for the <paramref name="version"/>; /// otherwise, an <exception cref="InvalidDataException">invalid identifier exception</exception> is thrown. /// </remarks> public Id3v2UrlLinkFrame(Id3v2Version version, string identifier) : base(version) { if (!IsValidUrlLinkIdentifier(version, identifier)) { // Maybe the identifier is actually a valid identifier but for the wrong version; try to find the 'real' identifier here. KeyValuePair<Id3v2UrlLinkFrameIdentifier, Dictionary<string, Id3v2Version[]>>[] pairs = Identifiers.Where( urlLinkFramePair => urlLinkFramePair.Value.OrderByDescending(f => f.Key).Any(f => f.Key.IndexOf(identifier, StringComparison.OrdinalIgnoreCase) >= 0)) .ToArray(); // Grab the 'real' identifier for the version supplied. identifier = pairs.Any() ? pairs[0].Value.Where(t => t.Value.Contains(version)).Select(t => t.Key).FirstOrDefault() : null; if (String.IsNullOrEmpty(identifier)) throw new InvalidDataException("identifier is not a valid identifier."); } _identifier = identifier; }
/// <summary> /// Determines whether the specified version is supported by the frame. /// </summary> /// <param name="version">The version.</param> /// <returns> /// <c>true</c> if the specified version is supported; otherwise, <c>false</c>. /// </returns> public override bool IsVersionSupported(Id3v2Version version) { return (version >= Id3v2Version.Id3v230); }
/// <summary> /// Gets the length of the <see cref="Identifier" />, in bytes. /// </summary> /// <param name="version">The version.</param> /// <returns>The length of the identifier field.</returns> /// <remarks> /// The length of the name field is 3 bytes for <see cref="Id3v2Version.Id3v220" /> /// and 4 bytes for <see cref="Id3v2Version.Id3v230" /> and later. /// </remarks> public static int GetIdentifierFieldLength(Id3v2Version version) { return (version < Id3v2Version.Id3v230) ? 3 : 4; }
/// <summary> /// Gets the proper size of the frame as best as possible. /// </summary> /// <param name="version">The version.</param> /// <param name="frameSize">Size of the frame.</param> /// <param name="maximumFrameSize">Maximum size of the frame.</param> /// <returns> /// The proper size of the frame; as best as possible. There are programs writing incorrect frame size's in a ID3v2Tag. /// This function tries to find the best frame size as possible; based on some theory and test files. /// </returns> private static int GetFrameSize(Id3v2Version version, long frameSize, long maximumFrameSize) { // The frame ID is followed by a size descriptor containing the size of the data in the final frame, after encryption, compression and unsynchronization. // The size is excluding the frame header ('total frame size' - 10 bytes) and stored as a 32 bit synchsafe integer. if (version >= Id3v2Version.Id3v240) { // Check if all the bytes are valid unsynched bytes (the last bit {most left bit of the first byte in Windows Calculator} should be 0) byte[] frameSizeBytes = BitConverter.GetBytes(frameSize); if (frameSizeBytes.All(b => (b & 0x80) == 0)) return (int)Id3v2Tag.GetUnsynchedValue(frameSizeBytes, 0, 4); // Some badly written ID3v2 programs write the frame size as-is; i.e. synched. They don't bother to read the specs properly -_- // frame sizes like '0xAAFB0000' probably only need to be reversed... if (frameSize >= 0x1000000) { long size = StreamBuffer.SwitchEndianness(frameSize, 4); return (int)((size > frameSize) ? frameSize : Math.Min(size, maximumFrameSize)); } } return (int)Math.Min(frameSize, maximumFrameSize); }
/// <summary> /// Determines whether the <paramref name="version"/> is a valid version. /// </summary> /// <param name="version">The version.</param> /// <returns> /// <c>true</c> if the version is valid; otherwise, <c>false</c>. /// </returns> public static bool IsValidVersion(Id3v2Version version) { return Enum.TryParse(version.ToString(), true, out version); }
////------------------------------------------------------------------------------------------------------------------------------ private void SetFlags(Id3v2Version version, int extendedFlags) { TagIsUpdate = ((version >= Id3v2Version.Id3v240) ? (extendedFlags & Id3v240ExtendedHeaderFlags.TagIsUpdate) : 0) != 0; CrcDataPresent = (((version >= Id3v2Version.Id3v230) && (version < Id3v2Version.Id3v240)) ? (extendedFlags & Id3v230ExtendedHeaderFlags.CrcPresent) : (version >= Id3v2Version.Id3v240) ? (extendedFlags & Id3v240ExtendedHeaderFlags.CrcPresent) : 0) != 0; TagIsRestricted = ((version >= Id3v2Version.Id3v240) ? (extendedFlags & Id3v240ExtendedHeaderFlags.TagIsRestricted) : 0) != 0; }
////------------------------------------------------------------------------------------------------------------------------------ /// <summary> /// Determines whether the specified version and identifier matches any of the <see cref="Identifiers"/>. /// </summary> /// <param name="version">The version.</param> /// <param name="identifier">The identifier.</param> /// <returns> /// true if the <paramref name="version"/> and <paramref name="identifier"/> were found; otherwise, false. /// </returns> /// <remarks> /// A match is found when either the <see cref="Identifiers"/> is set and contains the <paramref name="identifier"/> for the given <paramref name="version"/> /// (or no <see cref="Id3v2Version"/> is specified for the <paramref name="identifier"/> in <see cref="Identifiers"/>), /// or when <see cref="PartialComparer"/> is set and returns <c>true</c>. /// </remarks> public bool IsMatch(Id3v2Version version, string identifier) { return (Identifiers != null && Identifiers.Any( i => String.Equals(i.Key, identifier, StringComparison.OrdinalIgnoreCase) && ((i.Value == null) || i.Value.Contains(version)))) || ((PartialComparer != null) && PartialComparer(version, identifier)); }
/// <summary> /// Initializes a new instance of the <see cref="Id3v2UniqueFileIdentifierFrame"/> class. /// </summary> /// <param name="version">The version.</param> /// <exception cref="InvalidVersionException">Thrown if <paramref name="version"/> is not supported by this frame.</exception> public Id3v2UniqueFileIdentifierFrame(Id3v2Version version) : base(version) { if (!IsVersionSupported(version)) throw new InvalidVersionException(String.Format("Version {0} not supported by this frame.", version)); }
/// <summary> /// Initializes a new instance of the <see cref="Id3v2UserDefinedTextInformationFrame"/> class. /// </summary> /// <param name="version">The version.</param> /// <exception cref="InvalidVersionException">Thrown if <paramref name="version"/> is not supported by this frame.</exception> public Id3v2UserDefinedTextInformationFrame(Id3v2Version version) : base(version) { if (!IsVersionSupported(version)) throw new InvalidVersionException(String.Format("Version {0} not supported by this frame.", version)); }
/// <summary> /// Gets the length of the extended flags field for the specified <see cref="Id3v2Version"/>. /// </summary> /// <param name="version">The version.</param> /// <returns>The length of the extended flags field, in bytes.</returns> public int GetFlagsFieldLength(Id3v2Version version) { if (version < Id3v2Version.Id3v230) return 0; if (version < Id3v2Version.Id3v240) return 2; return (version == Id3v2Version.Id3v240) ? 1 : _extendedFlagsFieldLength; }
////------------------------------------------------------------------------------------------------------------------------------ /// <summary> /// Gets the size of the extended header for the specified <see cref="Id3v2Version"/>. /// </summary> /// <remarks> /// This property only applies for version <see cref="Id3v2Version.Id3v230"/> and later. /// <para /> /// <see cref="Id3v2Version.Id3v230"/>: /// Where the extended header size, currently 6 or 10 bytes, excludes itself. /// The extended header is considered separate from the header proper, and as such is subject to unsynchronization. /// <para /> /// <see cref="Id3v2Version.Id3v240"/> and later: /// Where the extended header size is the size of the whole extended header, stored as a 32 bit synchsafe integer. /// An extended header can thus never have a size of fewer than six bytes. /// </remarks> public int GetHeaderSize(Id3v2Version version) { if ((version >= Id3v2Version.Id3v230) && (version < Id3v2Version.Id3v240)) return 6 + (CrcDataPresent ? GetCrcDataLength(version) : 0); if (version >= Id3v2Version.Id3v240) return 6 + (TagIsUpdate ? GetTagIsUpdateDataLength(version) : 0) + (CrcDataPresent ? GetCrcDataLength(version) : 0) + (TagIsRestricted ? GetTagRestrictionsDataLength(version) : 0); return 0; }
/// <summary> /// Initializes a new instance of the <see cref="Id3v2CommentFrame"/> class. /// </summary> /// <param name="version">The version.</param> public Id3v2iTunesNormalizationFrame(Id3v2Version version) : base(version) { }
/// <summary> /// Determines whether the specified version is supported by the frame. /// </summary> /// <param name="version">The version.</param> /// <returns> /// <c>true</c> if the specified version is supported; otherwise, <c>false</c>. /// </returns> public override bool IsVersionSupported(Id3v2Version version) { return true; }
/// <summary> /// Initializes a new instance of the <see cref="Id3v2EncryptionMethodRegistrationFrame" /> class. /// </summary> /// <param name="version">The version.</param> /// <exception cref="InvalidVersionException">Thrown if <paramref name="version"/> is not supported by this frame.</exception> public Id3v2EncryptionMethodRegistrationFrame(Id3v2Version version) : base(version) { if (!IsVersionSupported(version)) throw new InvalidVersionException(String.Format("Version {0} not supported by this frame.", version)); }
////------------------------------------------------------------------------------------------------------------------------------ /// <summary> /// Determines whether the identifier is valid for the specified version. /// </summary> /// <param name="version">The version.</param> /// <param name="identifier">The identifier.</param> /// <returns> /// <c>true</c> if the identifier is valid for the specified version; otherwise, <c>false</c>. /// </returns> /// <remarks> /// A valid identifier is made out of the characters capital A-Z and 0-9, and is 3 or 4 bytes long depending on the <see cref="Version"/>. /// <para /> /// Use <see cref="GetIdentifierFieldLength"/> to get the required field length of the <paramref name="identifier"/>. /// </remarks> public static bool IsValidIdentifier(Id3v2Version version, string identifier) { if (identifier == null) throw new ArgumentNullException("identifier"); return (identifier.Length == GetIdentifierFieldLength(version)) && identifier.All(c => IsValidIdentifierByte((short)c)); }
/// <summary> /// Gets the length of the CRC data for the specified <see cref="Id3v2Version"/>. /// </summary> /// <value> /// The length of the CRC data. /// </value> /// <remarks> /// This property only applies for version <see cref="Id3v2Version.Id3v230"/> and later. /// </remarks> public static int GetCrcDataLength(Id3v2Version version) { if (version < Id3v2Version.Id3v230) return 0; if (version < Id3v2Version.Id3v240) return 4; return (version >= Id3v2Version.Id3v240) ? 5 : 0; }
////------------------------------------------------------------------------------------------------------------------------------ /// <summary> /// Gets the length of the data size field. /// </summary> /// <param name="version">The version.</param> /// <returns> /// The length for the data size field. /// </returns> private static int GetDataSizeFieldLength(Id3v2Version version) { return (version < Id3v2Version.Id3v230) ? 3 : 4; }
/// <summary> /// Gets the length of the <see cref="TagIsUpdate"/> data field for the specified <see cref="Id3v2Version"/>. /// </summary> /// <value> /// The length of the <see cref="TagIsUpdate"/> data field. /// </value> /// <remarks> /// This property only applies for version <see cref="Id3v2Version.Id3v240"/> and later. /// </remarks> public static int GetTagIsUpdateDataLength(Id3v2Version version) { return (version >= Id3v2Version.Id3v240) ? 1 : 0; }
/// <summary> /// Gets the size of the frame header for the <see cref="Id3v2Version"/>. /// </summary> /// <param name="version">The <see cref="Id3v2Version"/>.</param> /// <returns> /// The size of the frame header; in bytes. /// </returns> private static int GetHeaderSize(Id3v2Version version) { return (version < Id3v2Version.Id3v230) ? 6 : 10; }
/// <summary> /// Gets the length of the tag restrictions data for the specified <see cref="Id3v2Version"/>. /// </summary> /// <value> /// The length of the tag restrictions data. /// </value> /// <remarks> /// This property only applies for version <see cref="Id3v2Version.Id3v240"/> and later. /// </remarks> public static int GetTagRestrictionsDataLength(Id3v2Version version) { return (version >= Id3v2Version.Id3v240) ? 1 : 0; }
/// <summary> /// Initializes a new instance of the <see cref="Id3v2ExperimentalRelativeVolumeAdjustment2Frame"/> class. /// </summary> /// <param name="version">The version.</param> /// <exception cref="InvalidVersionException">Thrown if <paramref name="version"/> is not supported by this frame.</exception> public Id3v2ExperimentalRelativeVolumeAdjustment2Frame(Id3v2Version version) : base(version) { if (!IsVersionSupported(version)) throw new InvalidVersionException(String.Format("Version {0} not supported by this frame.", version)); }
////------------------------------------------------------------------------------------------------------------------------------ /// <summary> /// Initializes a new instance of the <see cref="Id3v2ExtendedHeader" /> class reading the <see cref="extendedFlags"/> for the specified <see cref="version"/>. /// </summary> /// <param name="version">The version.</param> /// <param name="extendedFlags">The extended flags.</param> public static Id3v2ExtendedHeader InitExtendedHeader(Id3v2Version version, int extendedFlags) { Id3v2ExtendedHeader header = new Id3v2ExtendedHeader(); header.SetFlags(version, extendedFlags); return header; }
/// <summary> /// Initializes a new instance of the <see cref="Id3v2OwnershipFrame"/> class. /// </summary> /// <param name="version">The version.</param> /// <exception cref="InvalidVersionException">Thrown if <paramref name="version"/> is not supported by this frame.</exception> public Id3v2OwnershipFrame(Id3v2Version version) : base(version) { if (!IsVersionSupported(version)) throw new InvalidVersionException(String.Format("Version {0} not supported by this frame.", version)); }
/// <summary> /// Gets the extended flags for the specified <see cref="Id3v2Version"/>. /// </summary> /// <value> /// The extended flags. /// </value> /// The extended flags field, with its size described by 'number of flag bytes', is defined as: %0bcd0000 public int GetFlags(Id3v2Version version) { int flags = 0; if (TagIsUpdate) { flags |= (version >= Id3v2Version.Id3v240) ? Id3v240ExtendedHeaderFlags.TagIsUpdate : 0; } if (CrcDataPresent) { flags |= ((version >= Id3v2Version.Id3v230) && (version < Id3v2Version.Id3v240)) ? Id3v230ExtendedHeaderFlags.CrcPresent : (version >= Id3v2Version.Id3v240) ? Id3v240ExtendedHeaderFlags.CrcPresent : 0; } if (TagIsRestricted) { flags |= (version >= Id3v2Version.Id3v240) ? Id3v240ExtendedHeaderFlags.TagIsRestricted : 0; } return flags; }