////------------------------------------------------------------------------------------------------------------------------------ /// <summary> /// Raises the <see cref="FieldParse"/> event. /// </summary> /// <param name="e">The <see cref="AudioVideoLib.Tags.Lyrics3v2FieldParseEventArgs"/> instance containing the event data.</param> private void OnFieldParse(Lyrics3v2FieldParseEventArgs e) { EventHandler<Lyrics3v2FieldParseEventArgs> eventHandlers = FieldParse; if (eventHandlers == null) return; foreach (EventHandler<Lyrics3v2FieldParseEventArgs> eventHandler in eventHandlers.GetInvocationList()) { eventHandler(this, e); if (e.Cancel) break; } }
////------------------------------------------------------------------------------------------------------------------------------ /// <inheritdoc/> public IAudioTagOffset ReadFromStream(Stream stream, TagOrigin tagOrigin) { if (stream == null) throw new ArgumentNullException("stream"); if (!stream.CanRead) throw new InvalidOperationException("stream can not be read"); if (!stream.CanSeek) throw new InvalidOperationException("stream can not be seeked"); StreamBuffer sb = stream as StreamBuffer ?? new StreamBuffer(stream); long startOffset = FindIdentifier(sb, tagOrigin); if (startOffset < 0) return null; long endOffset = 0; if (tagOrigin == TagOrigin.End) { endOffset = startOffset + FooterIdentifierBytes.Length; sb.Position = Math.Max(sb.Position - FooterIdentifierBytes.Length - Lyrics3v2Tag.TagSizeLength, 0); string strTagSize = sb.ReadString(Lyrics3v2Tag.TagSizeLength); long tagSize; if (!Int64.TryParse(strTagSize, out tagSize)) { #if DEBUG throw new InvalidDataException(String.Format("Can't parse size value {0} before footer.", strTagSize)); #else return null; #endif } long currentPosition = sb.Position; // The Lyrics3 block ends with a six character size descriptor and the string "LYRICS200". // The size value includes the "LYRICSBEGIN" string, but does not include the 6 character size descriptor and the trailing "LYRICS200" string. sb.Position = Math.Max(sb.Position - tagSize - Lyrics3v2Tag.TagSizeLength, 0); startOffset = FindIdentifier(sb, TagOrigin.Start); if (startOffset < 0) { // Header could be off sb.Position = Math.Max(sb.Position - (tagSize - 5), 0); if (sb.Position > 0) { startOffset = FindIdentifier(sb, TagOrigin.End); if (startOffset < 0) startOffset = sb.Position = currentPosition; } } } // Read the fields. List<Lyrics3v2Field> fields = new List<Lyrics3v2Field>(); long bytesRead = HeaderIdentifierBytes.Length; long streamLength = (endOffset > 0) ? endOffset : Math.Max(sb.Length, endOffset); while (startOffset + bytesRead < streamLength) { long startPosition = sb.Position; // Read field if needed. Lyrics3v2Field field = Lyrics3v2Field.ReadFromStream(sb, streamLength - bytesRead); if (field != null) { Lyrics3v2FieldParseEventArgs fieldParseEventArgs = new Lyrics3v2FieldParseEventArgs(field); OnFieldParse(fieldParseEventArgs); if (!fieldParseEventArgs.Cancel) { // Call after read event. Lyrics3v2FieldParsedEventArgs parsedEventArgs = new Lyrics3v2FieldParsedEventArgs(field); OnFieldParsed(parsedEventArgs); fields.Add(field); } } else { sb.Position = startPosition; break; } bytesRead += (sb.Position - startPosition); } if (endOffset == 0) { // The Lyrics3 block ends with a six character size descriptor and the string "LYRICS200". // The size value includes the "LYRICSBEGIN" string, but does not include the 6 character size descriptor and the trailing "LYRICS200" string. string strTagSize = sb.ReadString(6); long tagSize; if (!Int64.TryParse(strTagSize, out tagSize)) { #if DEBUG throw new InvalidDataException(String.Format("Can't parse size value {0} before footer.", strTagSize)); #else return null; #endif } int bRead; string footerIdentifier = sb.ReadString(FooterIdentifierBytes.Length, true, out bRead); if (!String.Equals(footerIdentifier, Lyrics3v2Tag.FooterIdentifier)) { #if DEBUG throw new InvalidDataException( String.Format("Footer identifier {0} not recognized; expected {1}", footerIdentifier, Lyrics3v2Tag.FooterIdentifier)); #else sb.Position -= bRead; #endif } endOffset = sb.Position; } #if DEBUG long totalDataSize = (endOffset - startOffset) - Lyrics3v2Tag.TagSizeLength - FooterIdentifierBytes.Length; //if (totalDataSize != bytesRead) //{ // // If the amount of bytes we read doesn't match the size of the tag indicated in the header, // throw new InvalidDataException( // String.Format( // "Amount of bytes read ({0}) does not match size indicated before footer ({1}).", // totalDataSize, // bytesRead)); //} #endif Lyrics3v2Tag tag = new Lyrics3v2Tag(); tag.SetFields(fields); return new AudioTagOffset(tagOrigin, startOffset, endOffset, tag); }