0

我用 C# 编写了一个 ID3-Tag-Reader,它工作得很好,除了音频文件包含一个GEOB-Frame。阅读它的标题就像在每个其他框架中一样,所以我会得到正确的大小(因为我在每个其他框架中都这样做)。假设我得到Frames Body的大小为7725 Bytes。遍历我的数组显示,下一个 Frame 位于位置24497。那么我做错了什么?

public abstract class ID3v2Frame
{

    /// <summary>
    /// Gets or sets the frame identifier.
    /// </summary>
    /// <value>The frame identifier.</value>
    public FrameIdentifier FrameIdentifier { get; set; }

    /// <summary>
    /// The Header of the Frame
    /// </summary>
    /// <value>The header.</value>
    protected FrameHeader FrameHeader { get; set; }

    /// <summary>
    /// The Frame's Body which contains the values
    /// </summary>
    /// <value>The frame body.</value>
    protected FrameBody FrameBody { get; set; }

    /// <summary>
    /// The size of Header added with the size of Body
    /// </summary>
    /// <value>The size of the frame.</value>
    protected int FrameSize { get { return FrameHeader.HeaderSize + FrameHeader.BodySize; } }

    public ID3v2Frame(){

    }

    public ID3v2Frame (ID3v2 version, FrameIdentifier identifier, String content)
    {
        this.FrameIdentifier = identifier;
        FrameHeader = FrameHeader.CreateHeader(identifier.GetIDByVersion(version), content.Length);

        FrameBody = FrameBody.CreateBody (content);
    }

    public ID3v2Frame (byte[] allBytes, FrameIdentifier identifier)
    {
        this.FrameIdentifier = identifier;

        FrameHeader = new FrameHeader (allBytes);

        byte[] bytesBody = new byte[allBytes.Length - FrameHeader.HeaderSize];
        Array.Copy (allBytes, ID3v2Header.HeaderSize, bytesBody, 0, bytesBody.Length);

        FrameBody = new FrameBody (bytesBody, FrameHeader.BodySize);
    }

    public virtual void SetValue (String value)
    {
        FrameBody.Content = value;
    }

    public virtual String GetValue ()
    {
        return FrameBody.Content;
    }

    public override string ToString ()
    {
        return FrameHeader + " - " + FrameBody;
    }

    public virtual byte[] GetAsByte ()
    {
        byte[] output = new byte[0];

        FrameHeader.BodySize = FrameBody.GetContentLength ();

        ArrayMerger.MergeArrays (ref output, FrameHeader.GetAsByteArray (), FrameBody.GetAsByteArray ());

        return output;
    }

    public virtual int GetFrameSize ()
    {
        return FrameHeader.HeaderSize + FrameHeader.BodySize;
    }

    public virtual bool IsAvailableInVersion (ID3v2 version)
    {
        if (version is ID3v2_2 && this.FrameIdentifier.FrameID2_2 != "") {
            return true;
        } else if (version is ID3v2_3 && this.FrameIdentifier.FrameID2_3 != "") {
            return true;
        } else if (version is ID3v2_4 && this.FrameIdentifier.FrameID2_4 != "") {
            return true;
        } else {
            return false;
        }
    }

    /*
    public static ID3v2Frame createFrame(String identifier){
        ID3v2Frame frame = new ID3v2Frame (identifier);

        frame.FrameHeader = FrameHeader.CreateHeader (identifier, 0);
        frame.FrameBody = FrameBody.CreateBody ();

        return frame;

    } */
}



public class FrameHeader {

    /// <summary>
    /// Gets or sets the frame ID.
    /// </summary>
    /// <value>The frame ID.</value>
    public String FrameID { get; set; }

    /// <summary>
    /// The frame ID.
    /// </summary>
    private byte[] frameID = new byte[4];

    /// <summary>
    /// The Size of the Frame's Body
    /// </summary>
    /// <value>The size of the body.</value>
    public Int32 BodySize { get; set; }

    /// <summary>
    /// The size of the body.
    /// </summary>
    private byte[] bodySize = new byte[4];

    /// <summary>
    /// The flags: 0abc0000 0h00kmnp
    /// </summary>
    private byte[] flags = new byte[2];

    /// <summary>
    /// The size of the header.
    /// </summary>
    public const int HeaderSize = 10;

    /// <summary>
    /// a - Tag alter preservation
    /// 
    /// This flag tells the tag parser what to do with this frame if it is
    /// unknown and the tag is altered in any way. This applies to all
    /// kinds of alterations, including adding more padding and reordering
    /// the frames.
    ///
    /// 0     Frame should be preserved.
    /// 1     Frame should be discarded.
    /// </summary>
    /// <value><c>true</c> if tag alter preservation; otherwise, <c>false</c>.</value>
    public bool TagAlterPreservation { get; set; }

    /// <summary>
    /// b - File alter preservation
    /// 
    /// This flag tells the tag parser what to do with this frame if it is
    /// unknown and the file, excluding the tag, is altered. This does not
    /// apply when the audio is completely replaced with other audio data.
    ///
    /// 0     Frame should be preserved.
    /// 1     Frame should be discarded.
    /// </summary>
    /// <value><c>true</c> if file alter preservation; otherwise, <c>false</c>.</value>
    public bool FileAlterPreservation { get; set; }

    /// <summary>
    /// c - Read only
    /// 
    /// This flag, if set, tells the software that the contents of this
    /// frame are intended to be read only. Changing the contents might
    /// break something, e.g. a signature. If the contents are changed,
    /// without knowledge of why the frame was flagged read only and
    /// without taking the proper means to compensate, e.g. recalculating
    /// the signature, the bit MUST be cleared.
    /// </summary>
    /// <value><c>true</c> if tag alter preservation; otherwise, <c>false</c>.</value>
    public bool ReadOnly { get; set; }

    /// <summary>
    /// h - Grouping identity
    ///
    /// This flag indicates whether or not this frame belongs in a group
    /// with other frames. If set, a group identifier byte is added to the
    /// frame. Every frame with the same group identifier belongs to the
    /// same group.
    ///
    /// 0     Frame does not contain group information
    /// 1     Frame contains group information
    /// </summary>
    /// <value><c>true</c> if grouping identity; otherwise, <c>false</c>.</value>
    public bool GroupingIdentity { get; set; }

    /// <summary>
    /// k - Compression
    ///
    /// This flag indicates whether or not the frame is compressed.
    /// A 'Data Length Indicator' byte MUST be included in the frame.
    ///
    /// 0     Frame is not compressed.
    /// 1     Frame is compressed using zlib [zlib] deflate method.
    /// If set, this requires the 'Data Length Indicator' bit
    /// to be set as well.
    /// </summary>
    /// <value><c>true</c> if compression; otherwise, <c>false</c>.</value>
    public bool Compression { get; set; }

    /// <summary>
    /// m - Encryption
    ///
    /// This flag indicates whether or not the frame is encrypted. If set,
    /// one byte indicating with which method it was encrypted will be
    /// added to the frame. See description of the ENCR frame for more
    ///     information about encryption method registration. Encryption
    ///     should be done after compression. Whether or not setting this flag
    ///     requires the presence of a 'Data Length Indicator' depends on the
    ///     specific algorithm used.
    ///
    ///     0     Frame is not encrypted.
    ///     1     Frame is encrypted.
    /// </summary>
    /// <value><c>true</c> if encryption; otherwise, <c>false</c>.</value>
    public bool Encryption { get; set; }

    /// <summary>
    /// n - Unsynchronisation
    ///
    /// This flag indicates whether or not unsynchronisation was applied
    /// to this frame. See section 6 for details on unsynchronisation.
    ///     If this flag is set all data from the end of this header to the
    ///     end of this frame has been unsynchronised. Although desirable, the
    ///     presence of a 'Data Length Indicator' is not made mandatory by
    ///     unsynchronisation.
    ///
    ///     0     Frame has not been unsynchronised.
    ///     1     Frame has been unsyrchronised.
    /// </summary>
    /// <value><c>true</c> if encryption; otherwise, <c>false</c>.</value>
    public bool Unsynchronisation { get; set; }

    /// <summary>
    /// p - Data length indicator
    ///
    /// This flag indicates that a data length indicator has been added to
    /// the frame. The data length indicator is the value one would write
    /// as the 'Frame length' if all of the frame format flags were
    /// zeroed, represented as a 32 bit synchsafe integer.
    ///
    /// 0      There is no Data Length Indicator.
    /// 1      A data length Indicator has been added to the frame.
    /// </summary>
    /// <value><c>true</c> if data length indicator; otherwise, <c>false</c>.</value>
    public bool DataLengthIndicator { get; set; }

    public FrameHeader(){

    }

    public FrameHeader (byte[] bytes) {
        this.Load (bytes);
    }

    public void Load (byte[] bytes) {

        using (MemoryStream fs = new MemoryStream (bytes, true)) {

            // Frame ID
            fs.Read (frameID, 0, frameID.Length);
            FrameID = Encoding.UTF8.GetString (frameID, 0, frameID.Length);

            // Bodysize
            fs.Read (bodySize, 0, bodySize.Length);

            int testBodySize = BitConverter.ToInt32 (bodySize, 0);

            BodySize = SynchsafeToInt (bodySize);



            // Flags
            fs.Read (flags, 0, flags.Length);

            TagAlterPreservation = GetBit (flags [0], 1);
            FileAlterPreservation = GetBit (flags [0], 2);
            ReadOnly = GetBit (flags [0], 3);

            GroupingIdentity = GetBit (flags [1], 1);
            Compression = GetBit (flags [1], 4);
            Encryption = GetBit (flags [1], 5);
            Unsynchronisation = GetBit (flags [1], 6);
            DataLengthIndicator = GetBit (flags [1], 7);
        }
    }

    public int SynchsafeToInt(byte[] synchsafe)
    {
        if (BitConverter.IsLittleEndian)
            Array.Reverse (synchsafe);

        return BitConverter.ToInt32 (synchsafe, 0);
    }

    public byte[] SynchsafeToByteArray(int synchsafe){
        byte[] theBytes = BitConverter.GetBytes (synchsafe);

        if (BitConverter.IsLittleEndian)
            Array.Reverse (theBytes);

        return theBytes;
    }

    private bool GetBit (byte b, int bitNumber) {
        return (b & (1 << bitNumber)) != 0;
    }

    public override string ToString () {
        return FrameID;
    }

    public byte[] GetAsByteArray () {
        byte[] output = new byte[0];
        ArrayMerger.MergeArrays (ref output, output, TextEncoder.EncodeString (FrameID, 0));

        byte[] bodySizeArray = SynchsafeToByteArray (this.BodySize);

        ArrayMerger.MergeArrays (ref output, output, bodySizeArray);
        ArrayMerger.MergeArrays (ref output, output, flags);

        return output;
    }

    public static FrameHeader CreateHeader(String frameID, Int32 bodysize){
        FrameHeader header = new FrameHeader ();
        header.FrameID = frameID;
        header.BodySize = bodysize;

        return header;
    }
}



public class GeneralObjectFrameBody : FrameBody{

    public String MIMEType { get; set; }
    private byte[] mimeBytes = new byte[0];

    public String Filename { get; set; }

    public GeneralObjectFrameBody (String content) {
    }

    public GeneralObjectFrameBody (byte[] bytes, int length) {
        int index = 0;

        for (int i = 0; i < bytes.Length; i++){
            if (bytes[i] == 65){
                byte[] tempBytes = new byte[4] { bytes[i], bytes[i+1], bytes[i +2],bytes[i +3]};
                String tempString = TextEncoder.DecodeByteArray (tempBytes, 0);
                Logger.output (tempString + " found at " + i);
                if (bytes[i + 1] == 80){
                    if (bytes [i + 2] == 73) {
                        if (bytes [i + 3] == 67) {
                            Logger.output ("Next Frame found at " + i);
                        }
                    }
                }
            }
        }
    }
}

请帮帮我

4

0 回答 0