Exemple #1
0
        /// <summary>
        ///    Populates the current instance with the contents of the
        ///    raw ID3v2 frame.
        /// </summary>
        /// <param name="data">
        ///    A <see cref="ByteVector" /> object containing the raw
        ///    extended header structure.
        /// </param>
        /// <param name="version">
        ///    A <see cref="byte" /> value indicating the ID3v2 version.
        /// </param>
        protected void Parse(ByteVector data, byte version)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }

            size = (version == 3 ? 4u : 0u) + SynchData.ToUInt(data.Mid(0, 4));
        }
Exemple #2
0
        /// <summary>
        ///    Renders the current instance as a raw ID3v2 header.
        /// </summary>
        /// <returns>
        ///    A <see cref="ByteVector" /> object containing the
        ///    rendered header.
        /// </returns>
        public ByteVector Render()
        {
            ByteVector v = new ByteVector();

            v.Add(FileIdentifier);
            v.Add(MajorVersion);
            v.Add(RevisionNumber);
            v.Add((byte)flags);
            v.Add(SynchData.FromUInt(TagSize));
            return(v);
        }
Exemple #3
0
        /// <summary>
        ///    Constructs and initializes a new instance of <see
        ///    cref="Header" /> by reading it from raw header data.
        /// </summary>
        /// <param name="data">
        ///    A <see cref="ByteVector" /> object containing the raw
        ///    data to build the new instance from.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///    <paramref name="data" /> is <see langword="null" />.
        /// </exception>
        /// <exception cref="CorruptFileException">
        ///    <paramref name="data" /> is smaller than <see
        ///    cref="Size" />, does not begin with <see
        ///    cref="FileIdentifier" />, contains invalid flag data,
        ///    or contains invalid size data.
        /// </exception>
        public Header(ByteVector data)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }

            if (data.Count < Size)
            {
                throw new CorruptFileException(
                          "Provided data is smaller than object size.");
            }

            if (!data.StartsWith(FileIdentifier))
            {
                throw new CorruptFileException(
                          "Provided data does not start with the file identifier");
            }

            major_version   = data [3];
            revision_number = data [4];
            flags           = (HeaderFlags)data [5];

            if (major_version == 2 && ((int)flags & 127) != 0)
            {
                throw new CorruptFileException(
                          "Invalid flags set on version 2 tag.");
            }

            if (major_version == 3 && ((int)flags & 15) != 0)
            {
                throw new CorruptFileException(
                          "Invalid flags set on version 3 tag.");
            }

            if (major_version == 4 && ((int)flags & 7) != 0)
            {
                throw new CorruptFileException(
                          "Invalid flags set on version 4 tag.");
            }

            for (int i = 6; i < 10; i++)
            {
                if (data [i] >= 128)
                {
                    throw new CorruptFileException(
                              "One of the bytes in the header was greater than the allowed 128.");
                }
            }

            tag_size = SynchData.ToUInt(data.Mid(6, 4));
        }
Exemple #4
0
        /// <summary>
        ///    Renders the current instance, encoded in a specified
        ///    ID3v2 version.
        /// </summary>
        /// <param name="version">
        ///    A <see cref="byte" /> value specifying the version of
        ///    ID3v2 to use when encoding the current instance.
        /// </param>
        /// <returns>
        ///    A <see cref="ByteVector" /> object containing the
        ///    rendered version of the current instance.
        /// </returns>
        /// <exception cref="NotImplementedException">
        ///    The version specified in the current instance is
        ///    unsupported.
        /// </exception>
        public ByteVector Render(byte version)
        {
            ByteVector data = new ByteVector();
            ByteVector id   = ConvertId(frame_id, version, true);

            if (id == null)
            {
                throw new NotImplementedException();
            }

            switch (version)
            {
            case 2:
                data.Add(id);
                data.Add(ByteVector.FromUInt(frame_size)
                         .Mid(1, 3));

                return(data);

            case 3:
                ushort new_flags = (ushort)(
                    (((ushort)flags << 1) & 0xE000) |
                    (((ushort)flags << 4) & 0x00C0) |
                    (((ushort)flags >> 1) & 0x0020));

                data.Add(id);
                data.Add(ByteVector.FromUInt(frame_size));
                data.Add(ByteVector.FromUShort(new_flags));

                return(data);

            case 4:
                data.Add(id);
                data.Add(SynchData.FromUInt(frame_size));
                data.Add(ByteVector.FromUShort((ushort)flags));

                return(data);

            default:
                throw new NotImplementedException(
                          "Unsupported tag version.");
            }
        }
Exemple #5
0
        /// <summary>
        ///    Constructs and initializes a new instance of <see
        ///    cref="FrameHeader" /> by reading it from raw header data
        ///    of a specified version.
        /// </summary>
        /// <param name="data">
        ///    A <see cref="ByteVector" /> object containing the raw
        ///    data to build the new instance from.
        /// </param>
        /// <param name="version">
        ///    A <see cref="byte" /> value containing the ID3v2 version
        ///    with which the data in <paramref name="data" /> was
        ///    encoded.
        /// </param>
        /// <remarks>
        ///    If the data size is smaller than the size of a full
        ///    header, the data is just treated as a frame identifier
        ///    and the remaining values are zeroed.
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        ///    <paramref name="data" /> is <see langword="null" />.
        /// </exception>
        /// <exception cref="CorruptFileException">
        ///    <paramref name="data" /> is smaller than the size of a
        ///    frame identifier or <paramref name="version" /> is less
        ///    than 2 or more than 4.
        /// </exception>
        public FrameHeader(ByteVector data, byte version)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }

            flags      = 0;
            frame_size = 0;

            if (version < 2 || version > 4)
            {
                throw new CorruptFileException(
                          "Unsupported tag version.");
            }

            if (data.Count < (version == 2 ? 3 : 4))
            {
                throw new CorruptFileException(
                          "Data must contain at least a frame ID.");
            }

            switch (version)
            {
            case 2:
                // Set the frame ID -- the first three bytes
                frame_id = ConvertId(data.Mid(0, 3), version,
                                     false);

                // 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)
                {
                    return;
                }

                frame_size = data.Mid(3, 3).ToUInt();
                return;

            case 3:
                // Set the frame ID -- the first four bytes
                frame_id = ConvertId(data.Mid(0, 4), version,
                                     false);

                // 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)
                {
                    return;
                }

                // Store the flags internally as version 2.4.
                frame_size = data.Mid(4, 4).ToUInt();
                flags      = (FrameFlags)(
                    ((data [8] << 7) & 0x7000) |
                    ((data [9] >> 4) & 0x000C) |
                    ((data [9] << 1) & 0x0040));

                return;

            case 4:
                // Set the frame ID -- the first four bytes
                frame_id = new ReadOnlyByteVector(
                    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)
                {
                    return;
                }

                frame_size = SynchData.ToUInt(data.Mid(4, 4));
                flags      = (FrameFlags)data.Mid(8, 2).ToUShort();

                return;

            default:
                throw new CorruptFileException(
                          "Unsupported tag version.");
            }
        }
Exemple #6
0
        /// <summary>
        ///    Extracts the field data from the raw data portion of an
        ///    ID3v2 frame.
        /// </summary>
        /// <param name="frameData">
        ///    A <see cref="ByteVector" /> object containing fraw frame
        ///    data.
        /// </param>
        /// <param name="offset">
        ///    A <see cref="int" /> value containing the index at which
        ///    the data is contained.
        /// </param>
        /// <param name="version">
        ///    A <see cref="byte" /> value containing the ID3v2 version
        ///    of the data.
        /// </param>
        /// <returns>
        ///    A <see cref="ByteVector" /> object containing the
        ///    extracted field data.
        /// </returns>
        /// <remarks>
        ///    This method is necessary for extracting extra data
        ///    prepended to the frame such as the grouping ID.
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        ///    <paramref name="frameData" /> is <see langword="null" />.
        /// </exception>
        protected ByteVector FieldData(ByteVector frameData,
                                       int offset, byte version)
        {
            if (frameData == null)
            {
                throw new ArgumentNullException("frameData");
            }

            int data_offset = offset + (int)FrameHeader.Size(version);
            int data_length = (int)Size;

            if ((Flags & (FrameFlags.Compression |
                          FrameFlags.DataLengthIndicator)) != 0)
            {
                data_offset += 4;
                data_length -= 4;
            }

            if ((Flags & FrameFlags.GroupingIdentity) != 0)
            {
                if (frameData.Count >= data_offset)
                {
                    throw new TagLib.CorruptFileException(
                              "Frame data incomplete.");
                }
                group_id = frameData [data_offset++];
                data_length--;
            }

            if ((Flags & FrameFlags.Encryption) != 0)
            {
                if (frameData.Count >= data_offset)
                {
                    throw new TagLib.CorruptFileException(
                              "Frame data incomplete.");
                }
                encryption_id = frameData [data_offset++];
                data_length--;
            }

            data_length = Math.Min(data_length, frameData.Count - data_offset);
            if (data_length < 0)
            {
                throw new CorruptFileException(
                          "Frame size less than zero.");
            }

            ByteVector data = frameData.Mid(data_offset,
                                            data_length);

            if ((Flags & FrameFlags.Unsynchronisation) != 0)
            {
                int before_length = data.Count;
                SynchData.ResynchByteVector(data);
                data_length -= (data.Count - before_length);
            }

            // FIXME: Implement encryption.
            if ((Flags & FrameFlags.Encryption) != 0)
            {
                throw new NotImplementedException();
            }

            // FIXME: Implement compression.
            if ((Flags & FrameFlags.Compression) != 0)
            {
                throw new NotImplementedException();
            }

            /*
             * if(d->header->compression()) {
             *      ByteVector data(frameDataLength);
             *      uLongf uLongTmp = frameDataLength;
             *      ::uncompress((Bytef *) data.data(),
             *      (uLongf *) &uLongTmp,
             *      (Bytef *) frameData.data() + frameDataOffset,
             *      size());
             *      return data;
             * }
             */

            return(data);
        }
Exemple #7
0
        /// <summary>
        ///    Renders the current instance, encoded in a specified
        ///    ID3v2 version.
        /// </summary>
        /// <param name="version">
        ///    A <see cref="byte" /> value specifying the version of
        ///    ID3v2 to use when encoding the current instance.
        /// </param>
        /// <returns>
        ///    A <see cref="ByteVector" /> object containing the
        ///    rendered version of the current instance.
        /// </returns>
        /// <exception cref="NotImplementedException">
        ///    The current instance uses some feature that cannot be
        ///    implemented in the specified ID3v2 version, or uses a
        ///    feature, such as encryption or compression, which is not
        ///    yet implemented in the library.
        /// </exception>
        public virtual ByteVector Render(byte version)
        {
            // Remove flags that are not supported by older versions
            // of ID3v2.
            if (version < 4)
            {
                Flags &= ~(FrameFlags.DataLengthIndicator |
                           FrameFlags.Unsynchronisation);
            }

            if (version < 3)
            {
                Flags &= ~(FrameFlags.Compression |
                           FrameFlags.Encryption |
                           FrameFlags.FileAlterPreservation |
                           FrameFlags.GroupingIdentity |
                           FrameFlags.ReadOnly |
                           FrameFlags.TagAlterPreservation);
            }

            ByteVector field_data = RenderFields(version);

            // If we don't have any content, don't render anything.
            // This will cause the frame to not be rendered.
            if (field_data.Count == 0)
            {
                return(new ByteVector());
            }

            ByteVector front_data = new ByteVector();

            if ((Flags & (FrameFlags.Compression |
                          FrameFlags.DataLengthIndicator)) != 0)
            {
                front_data.Add(ByteVector.FromUInt((uint)
                                                   field_data.Count));
            }

            if ((Flags & FrameFlags.GroupingIdentity) != 0)
            {
                front_data.Add(group_id);
            }

            if ((Flags & FrameFlags.Encryption) != 0)
            {
                front_data.Add(encryption_id);
            }

            // FIXME: Implement compression.
            if ((Flags & FrameFlags.Compression) != 0)
            {
                throw new NotImplementedException(
                          "Compression not yet supported");
            }

            // FIXME: Implement encryption.
            if ((Flags & FrameFlags.Encryption) != 0)
            {
                throw new NotImplementedException(
                          "Encryption not yet supported");
            }

            if ((Flags & FrameFlags.Unsynchronisation) != 0)
            {
                SynchData.UnsynchByteVector(field_data);
            }

            if (front_data.Count > 0)
            {
                field_data.Insert(0, front_data);
            }

            header.FrameSize = (uint)field_data.Count;
            ByteVector header_data = header.Render(version);

            header_data.Add(field_data);

            return(header_data);
        }