Пример #1
0
        public ByteVector ReadBlock(int length)
        {
            if (length == 0)
            {
                return(new ByteVector());
            }

            try
            {
                Mode = FileAccessMode.Read;
            }
            catch (TagLibException)
            {
                TagLibDebugger.Debug(GetType().ToString() + ".ReadBlock() failed. Invalid File: " + Name);
                return(null);
            }

            if (length > bufferSize && (long)length > Length)
            {
                length = (int)Length;
            }

            byte[] buffer = new byte[length];
            int    count  = fileStream.Read(buffer, 0, length);

            return(new ByteVector(buffer, count));
        }
Пример #2
0
        private void Parse(ByteVector data)
        {
            // Check to see if a valid Xing header is available.

            if (!data.StartsWith("Xing"))
            {
                return;
            }

            // If the XingHeader doesn'type contain the number of frames and the total stream
            // info it'field invalid.

            if ((data[7] & 0x02) == 0)
            {
                TagLibDebugger.Debug("MPEG::XingHeader::parse() -- Xing header doesn't contain the total number of frames.");
                return;
            }

            if ((data[7] & 0x04) == 0)
            {
                TagLibDebugger.Debug("MPEG::XingHeader::parse() -- Xing header doesn't contain the total stream size.");
                return;
            }

            frames = data.Mid(8, 4).ToUInt();
            size   = data.Mid(12, 4).ToUInt();

            valid = true;
        }
Пример #3
0
        public static OggPage[] Paginate(ByteVectorCollection packets, PaginationStrategy strategy, uint streamSerialNumber,
                                         int firstPage, bool firstPacketContinued, bool lastPacketCompleted, bool containsLastPacket)
        {
            ArrayList l = new ArrayList();

            int totalSize = 0;

            foreach (ByteVector b in packets)
            {
                totalSize += b.Count;
            }

            if (strategy == PaginationStrategy.Repaginate || totalSize + packets.Count > 255 * 256)
            {
                TagLibDebugger.Debug("Ogg.Page.Paginate() -- Sorry!  Repagination is not yet implemented.");
                return((OggPage[])l.ToArray(typeof(OggPage)));
            }

            // TODO: Handle creation of multiple pages here with appropriate pagination.

            OggPage p = new OggPage(packets, streamSerialNumber, firstPage, firstPacketContinued,
                                    lastPacketCompleted, containsLastPacket);

            l.Add(p);

            return((OggPage[])l.ToArray(typeof(OggPage)));
        }
Пример #4
0
        public void Parse(ByteVector data)
        {
            if (data != null)
            {
                // 11 buffer is the minimum size for an APE item
                if (data.Count < 11)
                {
                    TagLibDebugger.Debug("APE.Item.Parse() -- no data in item");
                    return;
                }

                uint value_length = data.Mid(0, 4).ToUInt(false);
                uint flags        = data.Mid(4, 4).ToUInt(false);

                int pos = data.Find(new ByteVector(1), 8);

                key   = data.Mid(8, pos - 8).ToString(StringType.UTF8);
                value = data.Mid(pos + 1, (int)value_length);

                ReadOnly = (flags & 1) == 1;
                Type     = (ApeItemType)((flags >> 1) & 3);

                if (Type != ApeItemType.Binary)
                {
                    text.Clear();
                    text = new StringCollection(ByteVectorCollection.Split(value, (byte)0), StringType.UTF8);
                }
            }
            else
            {
                throw new ArgumentNullException("data");
            }
        }
Пример #5
0
        public void SetPacket(uint index, ByteVector packet)
        {
            while (packetToPageMap.Count <= index)
            {
                if (!NextPage())
                {
                    TagLibDebugger.Debug("Ogg.File.SetPacket() -- Could not set the requested packet.");
                    return;
                }
            }

            foreach (int page in (IntCollection)packetToPageMap[(int)index])
            {
                dirtyPages.SortedInsert(page, true);
            }

            if (dirtyPackets.ContainsKey(index))
            {
                dirtyPackets[index] = packet;
            }
            else
            {
                dirtyPackets.Add(index, packet);
            }
        }
Пример #6
0
        protected void Parse(ByteVector data)
        {
            if (data.Count < Size)
            {
                return;
            }

            // do some sanity checking -- even in ID3v2.3.0 and less the tag size is a
            // synch-safe integer, so all buffer must be less than 128.  If this is not
            // true then this is an invalid tag.

            // note that we're doing things a little out of order here -- the size is
            // later in the bytestream than the version

            ByteVector sizeData = data.Mid(6, 4);

            if (sizeData.Count != 4)
            {
                tagSize = 0;
                TagLibDebugger.Debug("ID3v2.Header.Parse () - The tag size as read was 0 bytes!");
                return;
            }

            foreach (byte b in sizeData)
            {
                if (b >= 128)
                {
                    tagSize = 0;
                    TagLibDebugger.Debug("ID3v2.Header.Parse () - One of the size bytes in the id3v2 header was greater than the allowed 128.");
                    return;
                }
            }

            // The first three buffer, data[0..2], are the File Identifier, "ID3". (structure 3.1 "file identifier")

            // Read the version number from the fourth and fifth buffer.
            majorVersion   = data[3];             // (structure 3.1 "major version")
            revisionNumber = data[4];             // (structure 3.1 "revision number")

            // Read the flags, the first four bits of the sixth byte.
            byte flags = data[5];

            desynchronization     = ((flags >> 7) & 1) == 1;     // (structure 3.1.a)
            extendedHeader        = ((flags >> 6) & 1) == 1;     // (structure 3.1.b)
            experimentalIndicator = ((flags >> 5) & 1) == 1;     // (structure 3.1.channelMode)
            footerPresent         = ((flags >> 4) & 1) == 1;     // (structure 3.1.d)

            // Get the size from the remaining four buffer (read above)

            tagSize = Id3v2SynchData.ToUInt(sizeData);             // (structure 3.1 "size")
        }
Пример #7
0
        private void ParsePrivateFields(ByteVector data)
        {
            if (data.Count < 1)
            {
                TagLibDebugger.Debug("A private frame must contain at least 1 byte.");
                return;
            }

            ByteVectorCollection list = ByteVectorCollection.Split(data, TextDelimiter(StringType.Latin1), 1, 2);

            if (list.Count == 2)
            {
                owner = list[0].ToString(StringType.Latin1);
                data  = list[1];
            }
        }
Пример #8
0
        //private void Read(ByteVector data, long streamLength, ReadStyle style)
        private void Read(ByteVector data, long streamLength)
        {
            if (data.Count < 18)
            {
                TagLibDebugger.Debug("FLAC.Properties.Read() - FLAC properties must contain at least 18 bytes.");
                return;
            }

            int pos = 0;

            // Minimum block size (in samples)
            pos += 2;

            // Maximum block size (in samples)
            pos += 2;

            // Minimum frame size (in buffer)
            pos += 3;

            // Maximum frame size (in buffer)
            pos += 3;

            uint flags = data.Mid(pos, 4).ToUInt(true);

            sampleRate  = (int)(flags >> 12);
            channels    = (int)(((flags >> 9) & 7) + 1);
            sampleWidth = (int)(((flags >> 4) & 31) + 1);

            // The last 4 bits are the most significant 4 bits for the 36 bit
            // stream length in samples. (Audio files measured in days)

            double high_length = (double)(sampleRate > 0 ? (((flags & 0xf) << 28) / sampleRate) << 4 : 0);

            pos += 4;

            duration = sampleRate > 0 ? TimeSpan.FromSeconds((double)data.Mid(pos, 4).ToUInt(true) / (double)sampleRate + high_length) : TimeSpan.Zero;
            pos     += 4;

            // Uncompressed bitrate:

            //bitrate = ((sampleRate * channels) / 1000) * sample_width;

            // Real bitrate:
            bitrate = (int)(duration > TimeSpan.Zero ? ((streamLength * 8L) / duration.TotalSeconds) / 1000 : 0);
        }
Пример #9
0
        //////////////////////////////////////////////////////////////////////////
        // private methods
        //////////////////////////////////////////////////////////////////////////
        private void Read(ReadStyle propertiesStyle)
        {
            ByteVector comment_header_data = GetPacket(1);

            if (comment_header_data.Mid(0, 7) != vorbis_comment_header_id)
            {
                TagLibDebugger.Debug("Vorbis.File.Read() - Could not find the Vorbis comment header.");
                SetValid(false);
                return;
            }

            comment = new OggXiphComment(comment_header_data.Mid(7));

            if (propertiesStyle != ReadStyle.None)
            {
                properties = new OggVorbisProperties(this, propertiesStyle);
            }
        }
Пример #10
0
        protected void Read()
        {
            if (file != null && file.IsValid)
            {
                file.Seek(tagOffset);

                // read the tag -- always 128 buffer
                ByteVector data = file.ReadBlock(128);

                // some initial sanity checking
                if (data.Count == 128 && data.StartsWith(FileIdentifier))                 //"TAG"))
                {
                    Parse(data);
                }
                else
                {
                    TagLibDebugger.Debug("ID3v1 tag is not valid or could not be read at the specified offset.");
                }
            }
        }
Пример #11
0
        public void WriteBlock(ByteVector data)
        {
            if (data != null)
            {
                try
                {
                    Mode = FileAccessMode.Write;
                }
                catch (TagLibException)
                {
                    TagLibDebugger.Debug(GetType().ToString() + ".WriteBlock () failed. Read-only File: " + Name);
                    return;
                }

                fileStream.Write(data.GetDataBuffer(), 0, data.Count);
            }
            else
            {
                throw new ArgumentNullException("data");
            }
        }
Пример #12
0
        // Overwrite the box'field header with a new header incorporating a size
        // change.
        public virtual void OverwriteHeader(long sizeChange)
        {
            // If we don'type have a header we can'type do anything.
            if (header == null || header.Position < 0)
            {
                TagLibDebugger.Debug("Box.OverWriteHeader() - No header to overwrite.");
                return;
            }

            // Make sure this alteration won'type screw up the reading of children.
            LoadChildren();

            // Save the header'field original position and size.
            long position = header.Position;
            long oldSize  = header.HeaderSize;

            // Update the data size.
            header.DataSize = (ulong)((long)header.DataSize + sizeChange);

            // Render the header onto the file.
            File.Insert(header.Render(), position, oldSize);
        }
Пример #13
0
        public ByteVector Render()
        {
            ByteVector data = header.Render();

            if (packets.IsEmpty)
            {
                if (file != null)
                {
                    file.Seek(packetOffset);
                    data.Add(file.ReadBlock(dataSize));
                }
                else
                {
                    TagLibDebugger.Debug("Ogg.Page.Render() -- this page is empty!");
                }
            }
            else
            {
                foreach (ByteVector v in packets)
                {
                    data.Add(v);
                }
            }

            // Compute and set the checksum for the Ogg page.  The checksum is taken over
            // the entire page with the 4 buffer reserved for the checksum zeroed and then
            // inserted in buffer 22-25 of the page header.

            ByteVector checksum = ByteVector.FromUInt(data.Checksum, false);

            for (int i = 0; i < 4; i++)
            {
                data [i + 22] = checksum [i];
            }

            return(data);
        }
Пример #14
0
        private void ParseCommentsFields(ByteVector data)
        {
            if (data.Count < 5)
            {
                TagLibDebugger.Debug("A comment frame must contain at least 5 bytes.");
                return;
            }

            textEncoding = (StringType)data[0];
            language     = data.Mid(1, 3);

            int byte_align = textEncoding == StringType.Latin1 || textEncoding == StringType.UTF8 ? 1 : 2;

            ByteVectorCollection l = ByteVectorCollection.Split(data.Mid(4), TextDelimiter(textEncoding), byte_align, 2);

            if (l.Count == 2)
            {
                if (l[0].Data != null && l[0].Data.Count > 0)
                {
                    description = l[0].ToString(textEncoding);
                }
                else
                {
                    description = string.Empty;
                }

                if (l[1].Data != null && l[1].Data.Count > 0)
                {
                    text = l[1].ToString(textEncoding);
                }
                else
                {
                    text = string.Empty;
                }
            }
        }
        //private void Read(OggVorbisFile file, ReadStyle style)
        private void Read(OggVorbisFile file)
        {
            // Get the identification header from the Ogg implementation.

            ByteVector data = file.GetPacket(0);

            int pos = 0;

            if (data.Mid(pos, 7) != vorbisCommentHeaderId)
            {
                TagLibDebugger.Debug("Vorbis.Properties.Read() -- invalid Vorbis identification header");
                return;
            }

            pos += 7;

            vorbisVersion = (int)data.Mid(pos, 4).ToUInt(false);
            pos          += 4;

            channels = data[pos];
            pos     += 1;

            sampleRate = (int)data.Mid(pos, 4).ToUInt(false);
            pos       += 4;

            bitrateMaximum = (int)data.Mid(pos, 4).ToUInt(false);
            pos           += 4;

            bitrateNominal = (int)data.Mid(pos, 4).ToUInt(false);
            pos           += 4;

            bitrateMinimum = (int)data.Mid(pos, 4).ToUInt(false);

            // TODO: Later this should be only the "fast" mode.
            bitrate = bitrateNominal;

            // Find the length of the file.  See http://wiki.xiph.org/VorbisStreamLength/
            // for my notes on the topic.

            OggPageHeader first = file.FirstPageHeader;
            OggPageHeader last  = file.LastPageHeader;

            if (first != null && last != null)
            {
                long start = first.AbsoluteGranularPosition;
                long end   = last.AbsoluteGranularPosition;

                if (start >= 0 && end >= 0 && sampleRate > 0)
                {
                    duration = TimeSpan.FromSeconds(((double)(end - start) / (double)sampleRate));
                }
                else
                {
                    TagLibDebugger.Debug("Vorbis.Properties.Read() -- Either the PCM " +
                                         "values for the start or end of this file was " +
                                         "incorrect or the sample rate is zero.");
                }
            }
            else
            {
                TagLibDebugger.Debug("Vorbis.Properties.Read() -- Could not find valid first and last Ogg pages.");
            }
        }
Пример #16
0
        public void Save(TagTypes types, bool stripOthers)
        {
            if (types == TagTypes.None && stripOthers)
            {
                if (!Strip(TagTypes.AllTags))
                {
                    throw new TagLibException(TagLibError.MpegCouldNotStripTags);
                }

                return;
            }

            if (id3v2_tag == null && id3v1_tag == null && ape_tag == null)
            {
                if (stripOthers)
                {
                    if (!Strip(TagTypes.AllTags))
                    {
                        throw new TagLibException(TagLibError.MpegCouldNotStripTags);
                    }
                }

                return;
            }

            if (IsReadOnly)
            {
                throw new ReadOnlyException();
            }

            Mode = FileAccessMode.Write;

            // Create the tags if we've been asked to.  Copy the values from the tag that
            // does exist into the new tag.

            if ((types & TagTypes.Id3v2) != 0 && id3v1_tag != null)
            {
                TagLib.Tag.Duplicate(id3v1_tag, FindTag(TagTypes.Id3v2, true), false);
            }

            if ((types & TagTypes.Id3v1) != 0 && id3v2_tag != null)
            {
                TagLib.Tag.Duplicate(id3v2_tag, FindTag(TagTypes.Id3v1, true), false);
            }

            bool success = true;

            if ((TagTypes.Id3v2 & types) != 0 && id3v2_tag != null && !id3v2_tag.IsEmpty)
            {
                long id3v2_location = FindId3v2();
                int  id3v2_size     = 0;

                if (id3v2_location < 0)
                {
                    id3v2_location = 0;
                }
                else
                {
                    Seek(id3v2_location);
                    Id3v2Header header = new Id3v2Header(ReadBlock((int)Id3v2Header.Size));

                    if (header.TagSize == 0)
                    {
                        TagLibDebugger.Debug("Mpc.File.Save() -- Id3v2 header is broken. Ignoring.");
                    }
                    else
                    {
                        id3v2_size = (int)header.CompleteTagSize;
                    }
                }

                Insert(id3v2_tag.Render(), id3v2_location, id3v2_size);
            }
            else if (stripOthers)
            {
                success = Strip(TagTypes.Id3v2) && success;
            }

            if ((TagTypes.Id3v1 & types) != 0 && id3v1_tag != null && !id3v1_tag.IsEmpty)
            {
                long id3v1_location = FindId3v1();
                if (id3v1_location < 0)
                {
                    Seek(0, System.IO.SeekOrigin.End);
                }
                else
                {
                    Seek(id3v1_location);
                }

                WriteBlock(id3v1_tag.Render());
            }
            else if (stripOthers)
            {
                success = (Strip(TagTypes.Id3v1, false) && success);
            }

            // Dont save an APE-tag unless one has been created
            if ((TagTypes.Ape & types) != 0 && ape_tag != null && !ape_tag.IsEmpty)
            {
                long ape_location = FindApe(FindId3v1() >= 0);
                long ape_size     = 0;

                if (ape_location < 0)
                {
                    ape_location = Length;
                }
                else
                {
                    Seek(ape_location);
                    ape_size     = (new ApeFooter(ReadBlock((int)ApeFooter.Size))).CompleteTagSize;
                    ape_location = ape_location + ApeFooter.Size - ape_size;
                }

                Insert(ape_tag.Render(), ape_location, ape_size);
            }
            else if (stripOthers)
            {
                success = (Strip(TagTypes.Ape, false) && success);
            }

            Mode = FileAccessMode.Closed;

            if (!success)
            {
                throw new TagLibException(TagLibError.MpegCouldNotWriteTags);
            }
        }
Пример #17
0
        private void Parse(ByteVector data)
        {
            if (data.Count < 4 || data[0] != 0xff)
            {
                TagLibDebugger.Debug("Mpeg.Header.Parse() -- First byte did not match MPEG synch.");
                return;
            }

            uint flags = data.ToUInt();

            // Check for the second byte'field part of the MPEG synch

            if ((flags & 0xFFE00000) != 0xFFE00000)
            {
                TagLibDebugger.Debug("Mpeg.Header.Parse() -- Second byte did not match MPEG synch.");
                return;
            }

            // Set the MPEG version
            switch ((flags >> 19) & 0x03)
            {
            case 0: version = MpegVersion.TwoPointFive; break;

            case 2: version = MpegVersion.Two; break;

            case 3: version = MpegVersion.One; break;
            }

            // Set the MPEG layer
            switch ((flags >> 17) & 0x03)
            {
            case 1: layer = 3; break;

            case 2: layer = 2; break;

            case 3: layer = 1; break;
            }

            protectionEnabled = ((flags >> 16) & 1) == 0;

            // Set the bitrate
            int[, ,] bitrates = new int[2, 3, 16] {
                {                                                                                // Version 1
                    { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0 }, // layer 1
                    { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0 },    // layer 2
                    { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0 } // layer 3
                },
                {                                                                             // Version 2 or 2.5
                    { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0 }, // layer 1
                    { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 },      // layer 2
                    { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 }  // layer 3
                }
            };

            int versionIndex = version == MpegVersion.One ? 0 : 1;
            int layerIndex   = layer > 0 ? layer - 1 : 0;

            // The bitrate index is encoded as the first 4 bits of the 3rd byte,
            // index.e. 1111xxxx

            int i = (int)(flags >> 12) & 0x0F;

            bitrate = bitrates[versionIndex, layerIndex, i];

            // Set the sample rate

            int[,] sampleRates = new int[3, 4] {
                { 44100, 48000, 32000, 0 }, // Version 1
                { 22050, 24000, 16000, 0 }, // Version 2
                { 11025, 12000, 8000, 0 } // Version 2.5
            };

            // The sample rate index is encoded as two bits in the 3nd byte,
            // index.e. xxxx11xx
            i = (int)(flags >> 10) & 0x03;

            sampleRate = sampleRates[(int)version, i];

            if (sampleRate == 0)
            {
                TagLibDebugger.Debug("Mpeg.Header.Parse() -- Invalid sample rate.");
                return;
            }

            // The channel mode is encoded as a 2 bit value at the end of the 3nd
            // byte, index.e. xxxxxx11
            channelMode = (MpegChannelMode)((flags >> 16) & 0x3);

            // TODO: Add mode extension for completeness

            isCopyrighted = (flags & 1) == 1;
            isOriginal    = ((flags >> 1) & 1) == 1;

            // Calculate the frame length
            if (layer == 1)
            {
                frameLength = 24000 * 2 * bitrate / sampleRate + (IsPadded ? 1 : 0);
            }
            else
            {
                frameLength = 72000 * bitrate / sampleRate + (IsPadded ? 1 : 0);
            }

            // Now that we're done parsing, set this to be a valid frame.
            isValid = true;
        }
Пример #18
0
        public ByteVector GetPacket(uint index)
        {
            // Check to see if we're called setPacket() for this packet since the last
            // save:

            if (dirtyPackets.ContainsKey(index))
            {
                return(dirtyPackets[index]);
            }

            // If we haven'type indexed the page where the packet we're interested in starts,
            // begin reading pages until we have.

            while (packetToPageMap.Count <= index)
            {
                if (!NextPage())
                {
                    TagLibDebugger.Debug("Ogg.File.Packet() -- Could not find the requested packet.");
                    return(null);
                }
            }

            // Start reading at the first page that contains part (or all) of this packet.
            // If the last read stopped at the packet that we're interested in, don'type
            // reread its packet text.  (This should make sequential packet reads fast.)

            int pageIndex = ((IntCollection)packetToPageMap[(int)index])[0];

            if (currentPacketPage != pages[pageIndex])
            {
                currentPacketPage = pages[pageIndex];
                currentPackets    = currentPacketPage.Packets;
            }

            // If the packet is completely contained in the first page that it'field in, then
            // just return it now.

            if ((currentPacketPage.ContainsPacket((int)index) & ContainsPacketSettings.CompletePacket) != 0)
            {
                return(currentPackets[(int)(index - currentPacketPage.FirstPacketIndex)]);
            }

            // If the packet is *not* completely contained in the first page that it'field a
            // part of then that packet trails off the end of the page.  Continue appending
            // the pages' packet data until we hit a page that either does not end with the
            // packet that we're fetching or where the last packet is complete.

            ByteVector packet = currentPackets[currentPackets.Count - 1];

            while ((currentPacketPage.ContainsPacket((int)index) & ContainsPacketSettings.EndsWithPacket) != 0 &&
                   !currentPacketPage.Header.LastPacketCompleted)
            {
                pageIndex++;
                if (pageIndex == pages.Count && !NextPage())
                {
                    TagLibDebugger.Debug("Ogg.File.Packet() -- Could not find the requested packet.");
                    return(null);
                }

                currentPacketPage = (OggPage)pages[pageIndex];
                currentPackets    = currentPacketPage.Packets;
                packet.Add(currentPackets[0]);
            }

            return(packet);
        }
Пример #19
0
        private static bool UpdateFrame(Id3v2FrameHeader header)
        {
            ByteVector frameId = header.FrameId;

            switch (header.Version)
            {
            case 2:                     // ID3v2.2
            {
                if (frameId == "CRM" ||
                    frameId == "EQU" ||
                    frameId == "LNK" ||
                    frameId == "RVA" ||
                    frameId == "TIM" ||
                    frameId == "TSI")
                {
                    TagLibDebugger.Debug("ID3v2.4 no longer supports the frame type "
                                         + frameId.ToString() + ".  It will be discarded from the tag.");

                    return(false);
                }

                // ID3v2.2 only used 3 buffer for the frame ID, so we need to convert all of
                // the frames to their 4 byte ID3v2.4 equivalent.

                ConvertFrame("BUF", "RBUF", header);
                ConvertFrame("CNT", "PCNT", header);
                ConvertFrame("COM", "COMM", header);
                ConvertFrame("CRA", "AENC", header);
                ConvertFrame("ETC", "ETCO", header);
                ConvertFrame("GEO", "GEOB", header);
                ConvertFrame("IPL", "TIPL", header);
                ConvertFrame("MCI", "MCDI", header);
                ConvertFrame("MLL", "MLLT", header);
                ConvertFrame("PIC", "APIC", header);
                ConvertFrame("POP", "POPM", header);
                ConvertFrame("REV", "RVRB", header);
                ConvertFrame("SLT", "SYLT", header);
                ConvertFrame("STC", "SYTC", header);
                ConvertFrame("TAL", "TALB", header);
                ConvertFrame("TBP", "TBPM", header);
                ConvertFrame("TCM", "TCOM", header);
                ConvertFrame("TCO", "TCON", header);
                ConvertFrame("TCR", "TCOP", header);
                ConvertFrame("TDA", "TDRC", header);
                ConvertFrame("TDY", "TDLY", header);
                ConvertFrame("TEN", "TENC", header);
                ConvertFrame("TFT", "TFLT", header);
                ConvertFrame("TKE", "TKEY", header);
                ConvertFrame("TLA", "TLAN", header);
                ConvertFrame("TLE", "TLEN", header);
                ConvertFrame("TMT", "TMED", header);
                ConvertFrame("TOA", "TOAL", header);
                ConvertFrame("TOF", "TOFN", header);
                ConvertFrame("TOL", "TOLY", header);
                ConvertFrame("TOR", "TDOR", header);
                ConvertFrame("TOT", "TOAL", header);
                ConvertFrame("TP1", "TPE1", header);
                ConvertFrame("TP2", "TPE2", header);
                ConvertFrame("TP3", "TPE3", header);
                ConvertFrame("TP4", "TPE4", header);
                ConvertFrame("TPA", "TPOS", header);
                ConvertFrame("TPB", "TPUB", header);
                ConvertFrame("TRC", "TSRC", header);
                ConvertFrame("TRD", "TDRC", header);
                ConvertFrame("TRK", "TRCK", header);
                ConvertFrame("TSS", "TSSE", header);
                ConvertFrame("TT1", "TIT1", header);
                ConvertFrame("TT2", "TIT2", header);
                ConvertFrame("TT3", "TIT3", header);
                ConvertFrame("TXT", "TOLY", header);
                ConvertFrame("TXX", "TXXX", header);
                ConvertFrame("TYE", "TDRC", header);
                ConvertFrame("UFI", "UFID", header);
                ConvertFrame("ULT", "USLT", header);
                ConvertFrame("WAF", "WOAF", header);
                ConvertFrame("WAR", "WOAR", header);
                ConvertFrame("WAS", "WOAS", header);
                ConvertFrame("WCM", "WCOM", header);
                ConvertFrame("WCP", "WCOP", header);
                ConvertFrame("WPB", "WPUB", header);
                ConvertFrame("WXX", "WXXX", header);
            }
            break;

            case 3:                     // ID3v2.3
            {
                if (frameId == "EQUA" ||
                    frameId == "RVAD" ||
                    frameId == "TIME" ||
                    frameId == "TRDA" ||
                    frameId == "TSIZ" ||
                    frameId == "TDAT")
                {
                    TagLibDebugger.Debug("ID3v2.4 no longer supports the frame type "
                                         + frameId.ToString() + ".  It will be discarded from the tag.");

                    return(false);
                }

                ConvertFrame("TORY", "TDOR", header);
                ConvertFrame("TYER", "TDRC", header);
            }
            break;

            default:
            {
                // This should catch a typo that existed in TagLib up to and including
                // version 1.1 where TRDC was used for the year rather than TDRC.

                ConvertFrame("TRDC", "TDRC", header);
            }
            break;
            }

            return(true);
        }
Пример #20
0
        //////////////////////////////////////////////////////////////////////////
        // private methods
        //////////////////////////////////////////////////////////////////////////

        private void Read()
        {
            // Since we've likely just looked for the ID3v1 tag, start at the end of the
            // file where we're least likely to have to have to move the disk head.

            long last = file.LastFrameOffset;

            if (last < 0)
            {
                TagLibDebugger.Debug("Mpeg.Properties.Read() -- Could not find a valid last MPEG frame in the stream.");
                return;
            }

            file.Seek(last);
            MpegHeader last_header = new MpegHeader(file.ReadBlock(4));

            long first = file.FirstFrameOffset;

            if (first < 0)
            {
                TagLibDebugger.Debug("Mpeg.Properties.Read() -- Could not find a valid first MPEG frame in the stream.");
                return;
            }

            if (!last_header.IsValid)
            {
                long pos = last;

                while (pos > first)
                {
                    pos = file.PreviousFrameOffset(pos);

                    if (pos < 0)
                    {
                        break;
                    }

                    file.Seek(pos);
                    MpegHeader header = new MpegHeader(file.ReadBlock(4));

                    if (header.IsValid)
                    {
                        last_header = header;
                        last        = pos;
                        break;
                    }
                }
            }

            // Now jump back to the front of the file and read what we need from there.

            file.Seek(first);
            MpegHeader first_header = new MpegHeader(file.ReadBlock(4));

            if (!first_header.IsValid || !last_header.IsValid)
            {
                TagLibDebugger.Debug("Mpeg.Properties.Read() -- Page headers were invalid.");
                return;
            }

            // Check for a Xing header that will help us in gathering information about a
            // VBR stream.

            int xing_header_offset = MpegXingHeader.XingHeaderOffset(first_header.Version,
                                                                     first_header.ChannelMode);

            file.Seek(first + xing_header_offset);
            MpegXingHeader xing_header = new MpegXingHeader(file.ReadBlock(16));

            // Read the length and the bitrate from the Xing header.

            if (xing_header.IsValid && first_header.SampleRate > 0 && xing_header.TotalFrames > 0)
            {
                int [] block_size = { 0, 384, 1152, 1152 };

                double time_per_frame = block_size [first_header.Layer];
                time_per_frame = first_header.SampleRate > 0 ? time_per_frame / first_header.SampleRate : 0;
                duration       = new TimeSpan((int)(time_per_frame * xing_header.TotalFrames) * TimeSpan.TicksPerSecond);
                bitrate        = (int)(duration > TimeSpan.Zero ? ((xing_header.TotalSize * 8L) / duration.TotalSeconds) / 1000 : 0);
            }

            // Since there was no valid Xing header found, we hope that we're in a constant
            // bitrate file.

            // TODO: Make this more robust with audio property detection for VBR without a
            // Xing header.

            else if (first_header.FrameLength > 0 && first_header.Bitrate > 0)
            {
                int frames = (int)((last - first) / first_header.FrameLength + 1);

                duration = TimeSpan.FromSeconds((double)(first_header.FrameLength * frames) / (double)(first_header.Bitrate * 125) + 0.5);
                bitrate  = first_header.Bitrate;
            }


            sample_rate    = first_header.SampleRate;
            channels       = first_header.ChannelMode == MpegChannelMode.SingleChannel ? 1 : 2;
            version        = first_header.Version;
            layer          = first_header.Layer;
            channel_mode   = first_header.ChannelMode;
            is_copyrighted = first_header.IsCopyrighted;
            is_original    = first_header.IsOriginal;
        }
Пример #21
0
        public override void Save()
        {
            if (IsReadOnly)
            {
                throw new ReadOnlyException();
            }

            Mode = FileAccessMode.Write;

            long flac_data_begin;
            long flac_data_end;

            // Update ID3 tags
            if (id3v2_tag != null)
            {
                ByteVector id3v2_tag_data = id3v2_tag.Render();

                long id3v2_location = FindId3v2();
                if (id3v2_location >= 0)
                {
                    int id3v2_size = 0;

                    Seek(id3v2_location);
                    Id3v2Header header = new Id3v2Header(ReadBlock((int)Id3v2Header.Size));

                    if (header.TagSize == 0)
                    {
                        TagLibDebugger.Debug("Flac.File.Save() -- Id3v2 header is broken. Ignoring.");
                    }
                    else
                    {
                        id3v2_size = (int)header.CompleteTagSize;
                    }

                    Insert(id3v2_tag_data, id3v2_location, id3v2_size);
                    System.Console.WriteLine("ID3v2: " + id3v2_size + " " + id3v2_tag_data.Count);
                    flac_data_begin = id3v2_location + id3v2_tag_data.Count;
                }
                else
                {
                    Insert(id3v2_tag_data, 0, 0);
                    flac_data_begin = id3v2_tag_data.Count;
                }
            }
            else
            {
                flac_data_begin = 0;
            }

            if (id3v1_tag != null)
            {
                long id3v1_location = FindId3v1();

                if (id3v1_location >= 0)
                {
                    Seek(id3v1_location);
                }
                else
                {
                    Seek(0, System.IO.SeekOrigin.End);
                }

                flac_data_end = Tell;
                WriteBlock(id3v1_tag.Render());
            }
            else
            {
                flac_data_end = Length;
            }


            // Create new vorbis comments is they don'type exist.
            FindTag(TagTypes.Xiph, true);

            xiph_comment_data = comment.Render(false);

            ByteVector v = ByteVector.FromUInt((uint)xiph_comment_data.Count);

            // Set the type of the comment to be a Xiph / Vorbis comment
            // (See scan() for comments on header-format)
            v[0] = 4;
            v.Add(xiph_comment_data);


            // If file already have comment => find and update it
            //                       if not => insert one

            scanned = false;

            if (Scan(flac_data_begin, flac_data_end) != null)
            {
                long next_page_offset = flac_start;
                Seek(next_page_offset);
                ByteVector header = ReadBlock(4);
                uint       length = header.Mid(1, 3).ToUInt();

                next_page_offset += length + 4;

                // Search through the remaining metadata

                byte block_type = (byte)(header[0] & 0x7f);
                bool last_block = (header[0] & 0x80) != 0;

                while (!last_block)
                {
                    Seek(next_page_offset);

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

                    // Type is vorbiscomment
                    if (block_type == 4)
                    {
                        long next_keep = (last_block ? 0 : FindPaddingBreak(next_page_offset + length + 4,
                                                                            next_page_offset + XiphCommentData.Count + 8,
                                                                            ref last_block));
                        uint padding_length;
                        if (next_keep != 0)
                        {
                            // There is space for comment and padding blocks without rewriting the whole file.
                            // Note this can not overflow.
                            padding_length = (uint)(next_keep - (next_page_offset + XiphCommentData.Count + 8));
                        }
                        else
                        {
                            // Not enough space, so we will have to rewrite the whole file following this block
                            padding_length = (uint)XiphCommentData.Count;
                            if (padding_length < 4096)
                            {
                                padding_length = 4096;
                            }
                            next_keep = next_page_offset + length + 4;
                        }

                        ByteVector padding = ByteVector.FromUInt(padding_length);
                        padding[0] = 1;
                        if (last_block)
                        {
                            padding[0] = (byte)(padding[0] | 0x80);
                        }
                        padding.Resize((int)(padding_length + 4));

                        Insert(v + padding, next_page_offset, next_keep - next_page_offset);
                        //System.Console.WriteLine ("OGG: " + (next_keep - next_page_offset) + " " + (vector.Count + padding.Count));

                        break;
                    }

                    next_page_offset += length + 4;
                }
            }
            else
            {
                long next_page_offset = flac_start;

                Seek(next_page_offset);

                ByteVector header     = ReadBlock(4);
                bool       last_block = (header[0] & 0x80) != 0;
                uint       length     = header.Mid(1, 3).ToUInt();

                // If last block was last, make this one last

                if (last_block)
                {
                    // Copy the bottom seven bits into the new value

                    ByteVector h = (byte)(header[0] & 0x7F);
                    Insert(h, next_page_offset, 1);

                    // Set the last bit
                    v[0] = (byte)(v[0] | 0x80);
                }

                Insert(v, next_page_offset + length + 4, 0);
            }

            Mode = FileAccessMode.Closed;
        }
Пример #22
0
        private ByteVector Scan(long begin, long end)
        {
            ByteVector xiph_comment_data = null;

            // Scan the metadata pages

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

            long next_page_offset;
            long file_size = Length;

            next_page_offset = Find("fLaC", begin);

            if (next_page_offset < 0)
            {
                TagLibDebugger.Debug("Flac.File.Scan () -- FLAC stream not found");
                SetValid(false);
                return(null);
            }

            next_page_offset += 4;
            flac_start        = next_page_offset;

            Seek(next_page_offset);

            ByteVector header = ReadBlock(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();

            // First block should be the stream_info metadata
            if (block_type != 0)
            {
                TagLibDebugger.Debug("Flac.File.Scan() -- invalid FLAC stream");
                SetValid(false);
                return(null);
            }
            stream_info_data  = ReadBlock((int)length);
            next_page_offset += length + 4;

            // Search through the remaining metadata

            while (!last_block)
            {
                header     = ReadBlock(4);
                block_type = (byte)(header[0] & 0x7f);
                last_block = (header[0] & 0x80) != 0;
                length     = header.Mid(1, 3).ToUInt();

                // Found the vorbis-comment
                if (block_type == 4)
                {
                    xiph_comment_data = ReadBlock((int)length);
                }

                next_page_offset += length + 4;
                if (next_page_offset >= file_size)
                {
                    TagLibDebugger.Debug("Flac.File.Scan() -- FLAC stream corrupted");
                    SetValid(false);
                    return(null);
                }
                Seek(next_page_offset);
            }

            // End of metadata, now comes the datastream
            stream_start  = next_page_offset;
            stream_length = end - stream_start;

            scanned = true;

            return(xiph_comment_data);
        }
Пример #23
0
        public void SetData(ByteVector data, uint version)
        {
            if (data != null)
            {
                this.version = version;

                if (version < 3)
                {
                    // ID3v2.2

                    if (data.Count < 3)
                    {
                        TagLibDebugger.Debug("You must at least specify a frame ID.");
                        return;
                    }

                    // Set the frame ID -- the first three buffer

                    frameId = data.Mid(0, 3);

                    // If the full header information was not passed in, do not continue to the
                    // steps to parse the frame size and flags.

                    if (data.Count < 6)
                    {
                        frameSize = 0;
                        return;
                    }

                    frameSize = data.Mid(3, 3).ToUInt();
                }
                else if (version == 3)
                {
                    // ID3v2.3

                    if (data.Count < 4)
                    {
                        TagLibDebugger.Debug("You must at least specify a frame ID.");
                        return;
                    }

                    // Set the frame ID -- the first four buffer

                    frameId = data.Mid(0, 4);

                    // If the full header information was not passed in, do not continue to the
                    // steps to parse the frame size and flags.

                    if (data.Count < 10)
                    {
                        frameSize = 0;
                        return;
                    }

                    // Set the size -- the frame size is the four buffer starting at byte four in
                    // the frame header (structure 4)

                    frameSize = data.Mid(4, 4).ToUInt();

                    // read the first byte of flags
                    tagAlterPreservation  = ((data[8] >> 7) & 1) == 1;        // (structure 3.3.1.a)
                    fileAlterPreservation = ((data[8] >> 6) & 1) == 1;        // (structure 3.3.1.b)
                    readOnly = ((data[8] >> 5) & 1) == 1;                     // (structure 3.3.1.channelMode)

                    // read the second byte of flags
                    compression      = ((data[9] >> 7) & 1) == 1;               // (structure 3.3.1.index)
                    encryption       = ((data[9] >> 6) & 1) == 1;               // (structure 3.3.1.j)
                    groupingIdentity = ((data[9] >> 5) & 1) == 1;               // (structure 3.3.1.k)
                }
                else
                {
                    // ID3v2.4

                    if (data.Count < 4)
                    {
                        TagLibDebugger.Debug("You must at least specify a frame ID.");
                        return;
                    }

                    // Set the frame ID -- the first four buffer

                    frameId = data.Mid(0, 4);

                    // If the full header information was not passed in, do not continue to the
                    // steps to parse the frame size and flags.

                    if (data.Count < 10)
                    {
                        frameSize = 0;
                        return;
                    }

                    // Set the size -- the frame size is the four buffer starting at byte four in
                    // the frame header (structure 4)

                    frameSize = Id3v2SynchData.ToUInt(data.Mid(4, 4));

                    // read the first byte of flags
                    tagAlterPreservation  = ((data[8] >> 6) & 1) == 1;        // (structure 4.1.1.a)
                    fileAlterPreservation = ((data[8] >> 5) & 1) == 1;        // (structure 4.1.1.b)
                    readOnly = ((data[8] >> 4) & 1) == 1;                     // (structure 4.1.1.channelMode)

                    // read the second byte of flags
                    groupingIdentity    = ((data[9] >> 6) & 1) == 1;            // (structure 4.1.2.header)
                    compression         = ((data[9] >> 3) & 1) == 1;            // (structure 4.1.2.k)
                    encryption          = ((data[9] >> 2) & 1) == 1;            // (structure 4.1.2.m)
                    desynchronization   = ((data[9] >> 1) & 1) == 1;            // (structure 4.1.2.n)
                    dataLengthIndicator = (data[9] & 1) == 1;                   // (structure 4.1.2.position)
                }
            }
            else
            {
                throw new ArgumentNullException("data");
            }
        }
Пример #24
0
        public override void Save()
        {
            if (IsReadOnly)
            {
                throw new ReadOnlyException();
            }

            Mode = FileAccessMode.Write;

            // Update ID3v2 tag
            long id3v2_location = FindId3v2();
            int  id3v2_size     = 0;

            if (id3v2_location != -1)
            {
                Seek(id3v2_location);
                Id3v2Header header = new Id3v2Header(ReadBlock((int)Id3v2Header.Size));
                if (header.TagSize == 0)
                {
                    TagLibDebugger.Debug("Mpc.File.Save() -- Id3v2 header is broken. Ignoring.");
                    id3v2_location = -1;
                }
                else
                {
                    id3v2_size = (int)header.CompleteTagSize;
                }
            }

            if (id3v2Tag != null)
            {
                if (id3v2_location >= 0)
                {
                    Insert(id3v2Tag.Render(), id3v2_location, id3v2_size);
                }
                else
                {
                    Insert(id3v2Tag.Render(), 0, 0);
                }
            }
            else if (id3v2_location >= 0)
            {
                RemoveBlock(id3v2_location, id3v2_size);
            }


            // Update ID3v1 tag
            long id3v1_location = FindId3v1();

            if (id3v1Tag != null)
            {
                if (id3v1_location >= 0)
                {
                    Insert(id3v1Tag.Render(), id3v1_location, 128);
                }
                else
                {
                    Seek(0, System.IO.SeekOrigin.End);
                    id3v1_location = Tell;
                    WriteBlock(id3v1Tag.Render());
                }
            }
            else if (id3v1_location >= 0)
            {
                RemoveBlock(id3v1_location, 128);
                id3v1_location = -1;
            }


            // Update APE tag
            long ape_location = FindApe(id3v1_location != -1);
            long ape_size     = 0;

            if (ape_location >= 0)
            {
                Seek(ape_location);
                ape_size     = (new ApeFooter(ReadBlock((int)ApeFooter.Size))).CompleteTagSize;
                ape_location = ape_location + ApeFooter.Size - ape_size;
            }

            if (apeTag != null)
            {
                if (ape_location >= 0)
                {
                    Insert(apeTag.Render(), ape_location, ape_size);
                }
                else
                {
                    if (id3v1_location >= 0)
                    {
                        Insert(apeTag.Render(), id3v1_location, 0);
                    }
                    else
                    {
                        Seek(0, System.IO.SeekOrigin.End);
                        WriteBlock(apeTag.Render());
                    }
                }
            }
            else if (ape_location >= 0)
            {
                RemoveBlock(ape_location, ape_size);
            }

            Mode = FileAccessMode.Closed;
        }
Пример #25
0
        private void Read(OggFile file, long file_offset)
        {
            file.Seek(file_offset);

            // An Ogg page header is at least 27 buffer, so we'll go ahead and read that
            // much and then get the rest when we're ready for it.

            ByteVector data = file.ReadBlock(27);

            // Sanity check -- make sure that we were in fact able to read as much data as
            // we asked for and that the page begins with "OggS".

            if (data.Count != 27 || !data.StartsWith("OggS"))
            {
                TagLibDebugger.Debug("Ogg.PageHeader.Read() -- error reading page header");
                return;
            }

            byte flags = data[5];

            firstPacketContinued = (flags & 1) != 0;
            firstPageOfStream    = ((flags >> 1) & 1) != 0;
            lastPageOfStream     = ((flags >> 2) & 1) != 0;

            absoluteGranularPosition = data.Mid(6, 8).ToLong(false);
            streamSerialNumber       = data.Mid(14, 4).ToUInt(false);
            pageSequenceNumber       = (int)data.Mid(18, 4).ToUInt(false);

            // Byte number 27 is the number of page segments, which is the only variable
            // length portion of the page header.  After reading the number of page
            // segments we'll then read in the coresponding data for this count.

            int pageSegmentCount = data[26];

            ByteVector page_segments = file.ReadBlock(pageSegmentCount);

            // Another sanity check.

            if (pageSegmentCount < 1 || page_segments.Count != pageSegmentCount)
            {
                return;
            }

            // The base size of an Ogg page 27 buffer plus the number of lacing values.

            size = 27 + pageSegmentCount;

            int packetSize = 0;

            for (int i = 0; i < pageSegmentCount; i++)
            {
                dataSize   += page_segments[i];
                packetSize += page_segments[i];

                if (page_segments[i] < 255)
                {
                    packetSizes.Add(packetSize);
                    packetSize = 0;
                }
            }

            if (packetSize > 0)
            {
                packetSizes.Add(packetSize);
                lastPacketCompleted = false;
            }
            else
            {
                lastPacketCompleted = true;
            }

            isValid = true;
        }
Пример #26
0
        protected void Parse(ByteVector data)
        {
            if (data != null)
            {
                try
                {
                    int frameDataPosition = 0;
                    int frameDataLength   = data.Count;

                    // check for extended header

                    if (header.ExtendedHeader)
                    {
                        if (ExtendedHeader == null)
                        {
                            extendedHeader = new Id3v2ExtendedHeader();
                        }

                        ExtendedHeader.SetData(data);

                        if (ExtendedHeader.Size <= data.Count)
                        {
                            frameDataPosition += (int)ExtendedHeader.Size;
                            frameDataLength   -= (int)ExtendedHeader.Size;
                        }
                    }

                    // check for footer -- we don'type actually need to parse it, as it *must*
                    // contain the same data as the header, but we do need to account for its
                    // size.

                    if (header.FooterPresent && Id3v2Footer.Size <= frameDataLength)
                    {
                        frameDataLength -= (int)Id3v2Footer.Size;
                    }

                    // parse frames

                    // Make sure that there is at least enough room in the remaining frame data for
                    // a frame header.

                    while (frameDataPosition < frameDataLength - Id3v2FrameHeader.Size(header.MajorVersion))
                    {
                        // If the next data is position is 0, assume that we've hit the padding
                        // portion of the frame data.
                        if (data[frameDataPosition] == 0)
                        {
                            if (header.FooterPresent)
                            {
                                TagLibDebugger.Debug("Padding *and* a footer found.  This is not allowed by the spec.");
                            }

                            return;
                        }

                        Id3v2Frame frame = Id3v2FrameFactory.CreateFrame(data.Mid(frameDataPosition), header.MajorVersion);

                        if (frame == null)
                        {
                            return;
                        }

                        // Checks to make sure that frame parsed correctly.
                        if (frame.Size < 0)
                        {
                            return;
                        }

                        frameDataPosition += (int)(frame.Size + Id3v2FrameHeader.Size(header.MajorVersion));
                        // Only add frames with content so we don'type send out just we got in.
                        if (frame.Size > 0)
                        {
                            AddFrame(frame);
                        }
                    }
                }
                catch (Exception ex)
                {
                    throw new ApplicationException("There was an error parsing this ID3 tag", ex);
                }
            }
            else
            {
                throw new ArgumentNullException("data");
            }
        }
Пример #27
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;
        }
Пример #28
0
        public bool Strip(TagTypes types, bool freeMemory)
        {
            FileAccessMode original_mode = Mode;

            if (IsReadOnly)
            {
                TagLibDebugger.Debug("Mpeg.File.Strip() - Cannot strip tags from a read only file.");
                return(false);
            }

            try
            {
                Mode = FileAccessMode.Write;
            }
            catch (TagLibException)
            {
                TagLibDebugger.Debug("Mpeg.File.Strip() - Cannot strip tags from a read only file.");
                return(false);
            }

            if ((types & TagTypes.Id3v2) != 0)
            {
                long id3v2_location = FindId3v2();
                if (id3v2_location >= 0)
                {
                    Seek(id3v2_location);
                    Id3v2Header header = new Id3v2Header(ReadBlock((int)Id3v2Header.Size));

                    if (header.TagSize == 0)
                    {
                        TagLibDebugger.Debug("Mpc.File.Save() -- Id3v2 header is broken. Ignoring.");
                    }
                    else
                    {
                        RemoveBlock(id3v2_location, (int)header.CompleteTagSize);
                    }
                }

                if (freeMemory)
                {
                    id3v2_tag = null;
                }
            }

            long id3v1_location = FindId3v1();

            if ((types & TagTypes.Id3v1) != 0)
            {
                if (id3v1_location >= 0)
                {
                    Truncate(id3v1_location);
                    id3v1_location = -1;
                }

                if (freeMemory)
                {
                    id3v1_tag = null;
                }
            }

            if ((types & TagTypes.Ape) != 0)
            {
                long ape_location = FindApe(id3v1_location >= 0);
                if (ape_location != -1)
                {
                    Seek(ape_location);
                    int ape_size = (int)(new ApeFooter(ReadBlock((int)ApeFooter.Size))).CompleteTagSize;
                    ape_location = ape_location + ApeFooter.Size - ape_size;
                    RemoveBlock(ape_location, ape_size);
                }

                if (freeMemory)
                {
                    ape_tag = null;
                }
            }

            tag.SetTags(id3v2_tag, ape_tag, id3v1_tag);

            Mode = original_mode;
            return(true);
        }
Пример #29
0
        public Mpeg4AppleElementaryStreamDescriptor(Mpeg4BoxHeader header, Mpeg4Box parent) : base(header, parent)
        {
            //WARNING: this was changed from accessing the Data property directy to instead
            // use LoadBoxData which returns a reference to the underlying data.  This change
            // was required to avoid accessing the virtual methods that the Data property uses
            // Everything should still work but if it doesn't then this change is the culprit...

            decoderConfiguration = new ByteVector();

            uint length;

            // This box contains a ton of information.
            int offset = 0;

            // This is a safe alternative to the Data property
            // it will be a reference to the same underlying structure and so should work identically to Data
            ByteVector boxData = LoadBoxData();

            // Elementary Stream Descriptor Tag
            if (boxData[offset++] == 3)
            {
                // We have a descriptor tag. Check that it'field at least 20 long.
                if ((length = ReadLength(boxData, offset)) < 20)
                {
                    TagLibDebugger.Debug("TagLib.Mpeg4.AppleElementaryStreamDescriptor () - Could not read data. Too small.");
                    return;
                }
                offset += 4;

                streamId = boxData.Mid(offset, 2).ToShort();
                offset  += 2;

                streamPriority = boxData[offset++];
            }
            else
            {
                // The tag wasn'type found, so the next two byte are the ID, and
                // after that, business as usual.
                streamId = boxData.Mid(offset, 2).ToShort();
                offset  += 2;
            }

            // Verify that the next data is the Decoder Configuration Descriptor
            // Tag and escape if it won'type work out.
            if (boxData[offset++] != 4)
            {
                TagLibDebugger.Debug("TagLib.Mpeg4.AppleElementaryStreamDescriptor () - Could not identify decoder configuration descriptor.");
                return;
            }

            // Check that it'field at least 15 long.
            if ((length = ReadLength(boxData, offset)) < 15)
            {
                TagLibDebugger.Debug("TagLib.Mpeg4.AppleElementaryStreamDescriptor () - Could not read data. Too small.");
                return;
            }
            offset += 4;

            // Read a lot of good info.
            objectTypeId   = boxData[offset++];
            streamType     = boxData[offset++];
            bufferSize     = boxData.Mid(offset, 3).ToUInt();
            offset        += 3;
            maximumBitrate = boxData.Mid(offset, 4).ToUInt();
            offset        += 4;
            averageBitrate = boxData.Mid(offset, 4).ToUInt();
            offset        += 4;

            // Verify that the next data is the Decoder Specific Descriptor
            // Tag and escape if it won'type work out.
            if (boxData[offset++] != 5)
            {
                TagLibDebugger.Debug("TagLib.Mpeg4.AppleElementaryStreamDescriptor () - Could not identify decoder specific descriptor.");
                return;
            }

            // The rest of the info is decoder specific.
            length  = ReadLength(boxData, offset);
            offset += 4;
            decoderConfiguration = boxData.Mid(offset, (int)length);
        }
Пример #30
0
        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));
        }