0

i coded a ID3-Tag-Reader with C#, and it works just fine, except the Audio File contains a GEOB-Frame. Reading it's Header is like in every other Frame, so i would get the right size (cause i do in every other Frame). Let's say, i get a size of 7725 Bytes for the Frames Body. Iterating through my array shows, that the next Frame comes at position 24497. So what do i do wrong?

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

Please help me out

DirtyNative
  • 2,553
  • 2
  • 33
  • 58
  • *"I think there is no need for sharing some code, cause it all works, except the GEOB Frame, but if you wish, i will post some."* It doesn't **all** work then, and its difficult to tell you what you did wrong since all you describe is that you get the wrong value, not how you are getting it specifically. Please post the relevant code. – Ron Beyer Oct 05 '15 at 15:24
  • Alright, i added some relevant code. – DirtyNative Oct 05 '15 at 19:31

0 Answers0