コード例 #1
0
        /// <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);

            ApeHeader headerOrFooter = ReadHeader(sb, tagOrigin);
            if (headerOrFooter == null)
                return null;

            // Don't throw an exception; just return here. The read header could be a false match.
            if (headerOrFooter.Size > ApeTag.MaxAllowedSize)
                return null;

            ApeTag tag = new ApeTag(headerOrFooter.Version, headerOrFooter.Flags);
            long startOffset, endOffset;
            ApeHeader header = null, footer = null;
            if (tag.IsHeader)
            {
                header = headerOrFooter;
                startOffset = header.Position;
                endOffset = Math.Min(startOffset + ApeTag.HeaderSize + header.Size, sb.Length);
                if (endOffset > sb.Length)
                {
            #if DEBUG
                    throw new EndOfStreamException("Tag at start could not be read: stream is truncated.");
            #else
                    return null;
            #endif
                }
                tag.UseHeader = true;
            }
            else
            {
                footer = headerOrFooter;
                endOffset = Math.Min(footer.Position + ApeTag.FooterSize, sb.Length);
                startOffset = Math.Max(endOffset - footer.Size - (tag.UseHeader ? ApeTag.HeaderSize : 0), 0);
                if (endOffset > sb.Length)
                {
            #if DEBUG
                    throw new EndOfStreamException("Tag at end could not be read: stream is truncated.");
            #else
                    return null;
            #endif
                }
                tag.UseFooter = true;

                // Seek to the start of the tag.
                sb.Seek(startOffset, SeekOrigin.Begin);

                if (tag.UseHeader)
                {
                    // Read the 'header' as if it was the start of the tag
                    header = ReadHeader(sb, TagOrigin.Start);
                    if (header == null)
                    {
                        // Size in the header could be off.
                        // Read the 'footer' as if it was at the end of the tag
                        sb.Seek(startOffset, SeekOrigin.Begin);
                        header = ReadHeader(sb, TagOrigin.End);
                        if (header == null)
                        {
                            tag.UseHeader = false;
                            sb.Seek(startOffset, SeekOrigin.Begin);
                        }
                    }

                    if (header != null)
                    {
                        startOffset = header.Position;
                        header.Size = (int)Math.Max(endOffset - (startOffset + ApeTag.HeaderSize), 0);
                        footer.Size = Math.Max(header.Size, footer.Size);
                    }

                    if (footer.Size > ApeTag.MaxAllowedSize)
                    {
            #if DEBUG
                        throw new InvalidDataException(
                            String.Format("Size ({0}) is larger than the max allowed size ({1})", footer.Size, ApeTag.MaxAllowedSize));
            #else
                        return null;
            #endif
                    }
                }
                ValidateHeader(header, footer);
            }

            int totalSizeItems = Math.Max(headerOrFooter.Size - ApeTag.FooterSize, 0);
            if ((sb.Length - sb.Position) < totalSizeItems)
            {
            #if DEBUG
                throw new IndexOutOfRangeException(
                    String.Format("Ape field ({0}) is bigger than amount of bytes left in stream ({1}).", totalSizeItems, sb.Length - sb.Position));
            #else
                return null;
            #endif
            }

            // Parse the individual frames.
            List<ApeItem> items = new List<ApeItem>();
            long bytesRead = 0;
            while (bytesRead < totalSizeItems)
            {
                long startPosition = sb.Position;

                ApeItem item = ApeItem.ReadFromStream(tag.Version, sb, totalSizeItems - bytesRead);
                if (item != null)
                {
                    ApeItemParseEventArgs parseEventArgs = new ApeItemParseEventArgs(item);
                    OnItemParse(parseEventArgs);

                    if (!parseEventArgs.Cancel)
                    {
                        if (parseEventArgs.Item != null)
                            item = parseEventArgs.Item;

                        if (item != null)
                        {
                            // Call after read event.
                            ApeItemParsedEventArgs parsedEventArgs = new ApeItemParsedEventArgs(item);
                            OnItemParsed(parsedEventArgs);

                            items.Add(parsedEventArgs.Item);
                        }
                    }
                }
                bytesRead += (sb.Position - startPosition);
            }

            #if DEBUG
            //if (items.Count != headerOrFooter.FrameCount)
                //throw new InvalidDataException("items.Count does not match FrameCount");

            if (items.Count > ApeTag.MaxAllowedFields)
            {
                throw new InvalidDataException(
                    String.Format("Tag has more fields ('{0}') than the allowed max fields count ('{1}').", items.Count, ApeTag.MaxAllowedFields));
            }

            //if (bytesRead != totalSizeItems)
            //{
            //    throw new InvalidDataException(
            //        String.Format("Amount of bytes read ({0}) does not match expected size ({1}).", bytesRead, totalSizeItems));
            //}
            #endif

            if (tag.IsHeader && tag.UseFooter)
            {
                sb.Position += ApeTag.FooterSize;
                footer = ReadHeader(sb, TagOrigin.End);
            }

            ValidateHeader(header, footer);

            tag.SetItems(items);

            return new AudioTagOffset(tagOrigin, startOffset, endOffset, tag);
        }
コード例 #2
0
 /// <summary>
 /// Raises the <see cref="ItemParsed"/> event.
 /// </summary>
 /// <param name="e">The <see cref="AudioVideoLib.Tags.ApeItemParsedEventArgs"/> instance containing the event data.</param>
 private void OnItemParsed(ApeItemParsedEventArgs e)
 {
     EventHandler<ApeItemParsedEventArgs> eventHandlers = ItemParsed;
     if (eventHandlers != null)
         eventHandlers(this, e);
 }