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);
		}
        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));
        }