Exemple #1
0
        static FrameBase ReadFrame(BinaryReader reader, string frameId, FrameFlags flags, uint frameSize)
        {
#if NETSTANDARD2_0
            var frameDataBuffer = reader.ReadBytes((int)frameSize);
#else
            // Use heap allocations for frames > 256kB (usually pictures)
            var frameDataBuffer = frameSize < 0x40000
                ? stackalloc byte[(int)frameSize]
                : new byte[(int)frameSize];
            reader.Read(frameDataBuffer);
#endif
            return(FrameFactory.Build(frameId, flags, frameDataBuffer));
        }
Exemple #2
0
        internal static TagModel Deserialize(Stream stream)
        {
            var tagModel = new TagModel();

            tagModel.Header.Deserialize(stream);
            if (tagModel.Header.Version != 3 & tagModel.Header.Version != 4)
            {
                throw new AudioUnsupportedException("ID3v2 Version " + tagModel.Header.Version + " is not supported.");
            }

            var id3TagSize = tagModel.Header.TagSize;

            MemoryStream?memory = null;

            try
            {
                if (tagModel.Header.Unsynchronisation)
                {
                    memory      = new(new byte[stream.Length]);
                    id3TagSize -= Sync.Unsafe(stream, memory, id3TagSize);
                    stream      = memory;
                    if (id3TagSize <= 0)
                    {
                        throw new AudioInvalidException("Data is missing after the header.");
                    }
                }

                uint rawSize;

                // Seek past the extended header
                if (tagModel.Header.HasExtendedHeader)
                {
                    tagModel.ExtendedHeader.Deserialize(stream);
                    rawSize = id3TagSize - 4 - tagModel.ExtendedHeader.Size;
                    if (id3TagSize <= 0)
                    {
                        throw new AudioInvalidException("Data is missing after the extended header.");
                    }
                }
                else
                {
                    rawSize = id3TagSize;
                }

                // Tags should have at least one frame
                if (rawSize <= 0)
                {
                    throw new AudioInvalidException("No frames are present in the tag.");
                }

                uint index = 0;
#if NETSTANDARD2_0
                var frameIdBuffer = new byte[4];
#else
                Span <byte> frameIdBuffer = stackalloc byte[4];
#endif

                while (index < rawSize)
                {
                    // Read one byte first, looking for padding
#if NETSTANDARD2_0
                    stream.Read(frameIdBuffer, 0, 1);
#else
                    stream.Read(frameIdBuffer.Slice(0, 1));
#endif

                    // We reached the padding
                    if (frameIdBuffer[0] == 0)
                    {
                        tagModel.Header.PaddingSize = rawSize - index;
                        stream.Seek(tagModel.Header.PaddingSize - 1, SeekOrigin.Current);

                        break;
                    }

                    // 10 is the minimum size of a valid frame
                    if (index + 10 > rawSize)
                    {
                        throw new AudioInvalidException("Tag is corrupt: incomplete frame.");
                    }

                    // Read the rest of the frame ID
#if NETSTANDARD2_0
                    stream.Read(frameIdBuffer, 1, 3);
#else
                    stream.Read(frameIdBuffer.Slice(1, 3));
#endif
                    index += 4;

                    using (var reader = new TagReader(stream))
                    {
                        var frameSize = tagModel.Header.Version == 4
                            ? reader.ReadUInt32SyncSafe()
                            : reader.ReadUInt32BigEndian();
                        index += 4;

                        // The size of the frame can't be larger than the available space
                        if (frameSize > rawSize - index)
                        {
                            throw new AudioInvalidException(
                                      "A frame is corrupt: can't be larger than the available space remaining.");
                        }

                        var flags = new FrameFlags(reader.ReadUInt16BigEndian(), tagModel.Header.Version);
                        index += 2;

                        tagModel.Frames.Add(ReadFrame(reader,
#if NETSTANDARD2_0
                                                      Encoding.ASCII.GetString(frameIdBuffer, 0, 4), flags, frameSize));
#else
                                                      Encoding.ASCII.GetString(frameIdBuffer), flags, frameSize));
#endif

                        index += frameSize;
                    }
                }

                return(tagModel);
            }
            finally
            {
                memory?.Close();
            }
        }