示例#1
0
        internal void Deserialize(Stream stream)
        {
            using (var reader = new TagReader(stream))
                Size = reader.ReadUInt32SyncSafe();
            if (Size < 6)
            {
                throw new AudioInvalidException("Corrupt id3 extended header.");
            }

            // Seek past it for now
            stream.Seek((int)Size, SeekOrigin.Current);
        }
示例#2
0
        internal void Deserialize(Stream stream)
        {
            using (var reader = new TagReader(stream))
            {
                // Read the tag identifier
#if NETSTANDARD2_0
                var idTag = reader.ReadBytes(3);
#else
                Span <byte> idTag = stackalloc byte[3];
                reader.Read(idTag);
#endif
                if (_id3.AsSpan().SequenceCompareTo(idTag) != 0)
                {
                    throw new TagNotFoundException("ID3v2 tag identifier was not found.");
                }

                // Get the id3v2 version byte
                Version = reader.ReadByte();
                if (Version == 0xFF)
                {
                    throw new AudioInvalidException("Corrupt header: invalid ID3v2 version.");
                }

                // Get the id3v2 revision byte
                if (reader.ReadByte() == 0xFF)
                {
                    throw new AudioInvalidException("Corrupt header: invalid ID3v2 revision.");
                }

                // Parse the flag byte
                var id3Flags = (byte)(0xF0 & reader.ReadByte());
                Unsynchronisation = (id3Flags & 0b1000_0000) > 0;
                HasExtendedHeader = (id3Flags & 0b0100_0000) > 0;
                _hasFooter        = (id3Flags & 0b0001_0000) > 0;

                // Get the id3v2 size, swap and un-sync the integer
                TagSize = reader.ReadUInt32SyncSafe();
                if (TagSize == 0)
                {
                    throw new AudioInvalidException("Corrupt header: tag size can't be zero.");
                }
            }
        }
示例#3
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();
            }
        }