public static Id3v2Frame CreateFrame(ByteVector data, uint version)
        {
            Id3v2FrameHeader header  = new Id3v2FrameHeader(data, version);
            ByteVector       frameId = header.FrameId;

            // A quick sanity check -- make sure that the frameId is 4 uppercase
            // Latin1 characters.  Also make sure that there is data in the frame.

            if (frameId == null || frameId.Count != (version < 3 ? 3 : 4) || header.FrameSize < 0)
            {
                return(null);
            }

            foreach (byte b in frameId)
            {
                char c = (char)b;
                if ((c < 'A' || c > 'Z') && (c < '1' || c > '9'))
                {
                    return(null);
                }
            }

            // Windows Media Player may create zero byte frames. Just send them
            // off as unknown.
            if (header.FrameSize == 0)
            {
                return(new Id3v2UnknownFrame(data, header));
            }

            // TagLib doesn'type mess with encrypted frames, so just treat them
            // as unknown frames.

            if (header.Compression)
            {
                TagLibDebugger.Debug("Compressed frames are currently not supported.");
                return(new Id3v2UnknownFrame(data, header));
            }

            if (header.Encryption)
            {
                TagLibDebugger.Debug("Encrypted frames are currently not supported.");
                return(new Id3v2UnknownFrame(data, header));
            }

            if (!UpdateFrame(header))
            {
                header.TagAlterPreservation = true;
                return(new Id3v2UnknownFrame(data, header));
            }

            foreach (FrameCreator creator in frameCreators)
            {
                Id3v2Frame frame = creator(data, header);
                if (frame != null)
                {
                    return(frame);
                }
            }


            // UpdateFrame() might have updated the frame ID.

            frameId = header.FrameId;

            // This is where things get necissarily nasty.  Here we determine which
            // Frame subclass (or if none is found simply an Frame) based
            // on the frame ID.  Since there are a lot of possibilities, that means
            // a lot of if blocks.

            // Text Identification (frames 4.2)

            if (frameId.StartsWith("T"))
            {
                Id3v2TextIdentificationFrame frame = frameId != "TXXX"
                                ? new Id3v2TextIdentificationFrame(data, header)
                                : new Id3v2UserTextIdentificationFrame(data, header);

                if (useDefaultEncoding)
                {
                    frame.TextEncoding = defaultEncoding;
                }

                return(frame);
            }

            // Comments (frames 4.10)

            if (frameId == "COMM")
            {
                Id3v2CommentsFrame frame = new Id3v2CommentsFrame(data, header);

                if (useDefaultEncoding)
                {
                    frame.TextEncoding = defaultEncoding;
                }

                return(frame);
            }

            // Attached Picture (frames 4.14)

            if (frameId == "APIC")
            {
                Id3v2AttachedPictureFrame f = new Id3v2AttachedPictureFrame(data, header);

                if (useDefaultEncoding)
                {
                    f.TextEncoding = defaultEncoding;
                }

                return(f);
            }

            // Relative Volume Adjustment (frames 4.11)

            if (frameId == "RVA2")
            {
                return(new Id3v2RelativeVolumeFrame(data, header));
            }

            // Unique File Identifier (frames 4.1)

            if (frameId == "UFID")
            {
                return(new Id3v2UniqueFileIdentifierFrame(data, header));
            }

            // Private (frames 4.27)

            if (frameId == "PRIV")
            {
                return(new Id3v2PrivateFrame(data, header));
            }

            return(new Id3v2UnknownFrame(data, header));
        }
예제 #2
0
        private void Scan()
        {
            // Scan the metadata pages

            if (scanned || !IsValid)
            {
                return;
            }

            uint ipacket  = 0;
            long overhead = 0;

            ByteVector metadata_header = GetPacket(ipacket++);

            if (metadata_header == null)
            {
                return;
            }

            ByteVector header;

            if (!metadata_header.StartsWith("fLaC"))
            {
                // FLAC 1.1.2+
                if (metadata_header.Mid(1, 4) != "FLAC")
                {
                    return;
                }

                if (metadata_header[5] != 1)
                {
                    return;                     // not version 1
                }
                metadata_header = metadata_header.Mid(13);
            }
            else
            {
                // FLAC 1.1.0 & 1.1.1
                metadata_header = GetPacket(ipacket++);

                if (metadata_header == null)
                {
                    return;
                }
            }

            header = metadata_header.Mid(0, 4);
            // Header format (from spec):
            // <1> Last-metadata-block flag
            // <7> BLOCK_TYPE
            //    0 : STREAMINFO
            //    1 : PADDING
            //    ..
            //    4 : VORBIS_COMMENT
            //    ..
            // <24> Length of metadata to follow

            byte block_type = (byte)(header[0] & 0x7f);
            bool last_block = (header[0] & 0x80) != 0;
            uint length     = header.Mid(1, 3).ToUInt();

            overhead += length;

            // Sanity: First block should be the stream_info metadata

            if (block_type != 0)
            {
                TagLibDebugger.Debug("Ogg.Flac.File.Scan() -- Invalid Ogg/FLAC stream");
                return;
            }

            stream_info_data = metadata_header.Mid(4, (int)length);

            // Search through the remaining metadata

            while (!last_block)
            {
                metadata_header = GetPacket(ipacket++);

                if (metadata_header == null)
                {
                    return;
                }

                header     = metadata_header.Mid(0, 4);
                block_type = (byte)(header[0] & 0x7f);
                last_block = (header[0] & 0x80) != 0;
                length     = header.Mid(1, 3).ToUInt();
                overhead  += length;

                if (block_type == 4)
                {
                    xiph_comment_data = metadata_header.Mid(4, (int)length);
                    has_xiph_comment  = true;
                    comment_packet    = ipacket;
                }
                else if (block_type > 5)
                {
                    TagLibDebugger.Debug("Ogg.Flac.File.Scan() -- Unknown metadata block");
                }
            }

            // End of metadata, now comes the datastream
            stream_start  = overhead;
            stream_length = Length - stream_start;

            scanned = true;
        }