Simple Frage zu id3v2



  • freeze schrieb:

    Die Frame-Inhalte sind bei ID3v2 dynamisch

    Nun ja, kommt drauf an wie du dynamisch interpretierst.
    Ich nehme mal an, dass du für Version 2.4.0 programmierst. Der Aufbau ist ja hier beschrieben. Letztendlich sieht der Aufbau des ID3V2 Tags so aus:

    +-----------------------------+
    |      Header (10 bytes)      |
    +-----------------------------+
    |       Extended Header       |
    | (variable length, OPTIONAL) |
    +-----------------------------+
    |   Frames (variable length)  |
    +-----------------------------+
    |           Padding           |
    | (variable length, OPTIONAL) |
    +-----------------------------+
    | Footer (10 bytes, OPTIONAL) |
    +-----------------------------+
    

    Wenn du den Tag jetzt einliest, musst du diese Struktur abarbeiten, also Byte für Byte (nicht wortwörtlich zu verstehen 🙂 ) einlesen. Du siehst ja, dass an einigen Stellen OPTIONAL steht, also musst du irgendwoher wissen, ob der ensprechende Block existiert oder nicht. ZB erfährst du im Header ob der Extended Header existiert oder nicht, entsprechend liest du den dann oder eben nicht.
    Genauso wie das "Gesamtkunstwerk" einen fest definierten Aufbau hat, hat auch jeder Frame eine feste Struktur, bestehend aus einem 10 Byte Header + Framedaten. Wie diese Daten dann interpretiert werden müssen, hängt wiederum von der Frame-ID ab. Welche Frames wie interpretiert werden, ist ja in der Dokumentation beschrieben.
    Bisher werd ich aus deinem Code nicht so recht schlau. Was willst du zB mit ByteLength? Auch dein Einstieg ins Programm ist nicht sonderlich glücklich, da du immer davon ausgehst, dass jemand der das Programm startet, auch eine Datei angibt. Und wenn du nur lesen willst, dann nimm lieber ifstream. Meine ersten paar Zeilen würden eher so aussehen:

    int main(int argc, char* argv[])
    {
        if (argc < 2)
        {
            cout << "keine Datei angegeben" << endl;
            return 0;
        }
        ifstream file(argv[1], ios::binary);
        ....
    } // code ungetestet
    

    So, und ab da kannst du dann Block für Block und Frame für Frame einlesen. Ist ein Frame uninteressant, kannst du den ja erstmal überspringen und später dessen Auswertung implementieren.
    Es gibt allerdings auch noch einige knifflige Sachen: Stichwort Unsynchronisation.



  • Vielen Dank groovemaster2002

    Du hast Recht das mein Programm nicht der Überflieger ist, soll auch im Moment noch nicht so sein.
    Das was ich gepostet habe ist nur ein Testprogramm in dem ich probiere. Wenn dann etwas funktioniert implementiere ich dies in meine Klasse. Nun zu dem dynamischen, ich finde das diese doch dynamisch im ID3v2 sind, da der Titel beispielsweise eine variable Größe haben kann. Beim ID3v1 hat der Titel maximal 30 Bytes. Ich hoffe das ich mich nicht falsch Ausdrücke ich verwende den Begriff Frames für die Daten wie Titel, Interpret, Album, Jahr, ...

    Den Rest entweder Header, oder sontiges, aber für den Anfang würde mich mal das eben besprochene Interessieren, also Titel usw. Man muß ja mal irgendwo anfangen. Wenn dies dann klappt, das lese ich halt die Header usw. aus.

    Rom wurde ja auch nicht von einem zum anderen Tag erbaut. 😉

    Jedoch würde mich noch folgendes interessieren

    groovemaster2002 schrieb:

    Genauso wie das "Gesamtkunstwerk" einen fest definierten Aufbau hat, hat auch jeder Frame eine feste Struktur, bestehend aus einem 10 Byte Header + Framedaten. Wie diese Daten dann interpretiert werden müssen, hängt wiederum von der Frame-ID ab. Welche Frames wie interpretiert werden, ist ja in der Dokumentation beschrieben.

    Wenn ich mir zum Beispiel eine MP3-Datei anschaue dann steht dort

    ...TIT2^@^@^@^_^@^@^@Hier kommt der TitelTYER^@^@^@^Z^@^@^@2003...
    

    TIT2 = Hier kommt der Titel
    TYER = 2003

    Der Wert "ByteLength" ist demzufolge "TIT2" bzw. in diesem Beispiel auch "TYER", da diese ja 4 Bytes sind.
    Dies hat aber nichts wichtiges zu bedeuten, ich definiere mir in Testprogrammen nur gerne Variablen, dessen Wert öfters vorkommt, um nicht alles zu ändern.

    Wäre froh wenn Du mir noch helfen könntest

    Lg _freeze_



  • freeze schrieb:

    Der Wert "ByteLength" ist demzufolge "TIT2" bzw. in diesem Beispiel auch "TYER", da diese ja 4 Bytes sind.
    Dies hat aber nichts wichtiges zu bedeuten, ich definiere mir in Testprogrammen nur gerne Variablen, dessen Wert öfters vorkommt, um nicht alles zu ändern.

    Is schon ok, mich hatte nur der Name etwas irritiert. Ich hätte das wohl FrameNameLength oder so genannt.

    freeze schrieb:

    Ich hoffe das ich mich nicht falsch Ausdrücke ich verwende den Begriff Frames für die Daten wie Titel, Interpret, Album, Jahr, ...

    Ebenfalls ok, nur gehören zu einem Frame halt nicht nur die direkten Daten, die Doku spricht hier von Feldern, sondern auch der Header.

    freeze schrieb:

    Nun zu dem dynamischen, ich finde das diese doch dynamisch im ID3v2 sind, da der Titel beispielsweise eine variable Größe haben kann. Beim ID3v1 hat der Titel maximal 30 Bytes.

    Das ist schon richtig, nur spielt das keine wesentliche Rolle. Ob du nun direkt 30 Bytes liest oder erst einen Header, die Grösse dort rausholst und dann entsprechend viel liest, wird ein Programm in seiner Grundstruktur nicht verändern.

    freeze schrieb:

    Wenn dies dann klappt, das lese ich halt die Header usw. aus.

    Genau andersrum wird ein Schuh daraus, erst musst du die Header lesen, dann die entsprechenden Infos, zB Titel etc.
    Das ganze könnte ungefähr so aussehen:
    [pseudocode]
    1. lese Tag Header
    2. Tag Header auswerten (ist da noch ein Extended Header ? ja: 3. / nein: 4.)
    3. Extended Header lesen
    4. lese Frame Header (ID, Grösse)
    5. lese Framedaten entsprechend ID und Grösse (oder überspring sie, falls uninteressant)
    6. weitere Frames verfügbar ? ja: 4. / nein: 7.
    7. Padding / Footer
    [/pseudocode]
    Optional Padding und Footer kannst du ja erstmal weglassen.



  • OK, also ich mache es nach Deinem Vorschlag, ist auch irgendwie logischer,
    als mitten drinnen anzufangen. Nur habe ich das jetzte kleinere Problem,
    und zwar lese ich ja die Version und die nächsten 4 Bits aus, um die
    Informationen wie Unsynchonisatzion, ... auszulesen.

    OK, das mit dem "ID3" funktioniert mal :), jedoch alles weitere macht mir Probleme.
    Ich habe Dir mal meine *.CPP und *.HPP mitgepostet.
    Irgendwie klappt das mit der Version und dem nächsten Byte nicht.

    3.1.   ID3v2 header
    
       The first part of the ID3v2 tag is the 10 byte tag header, laid out
       as follows:
    
         ID3v2/file identifier      "ID3"
         ID3v2 version              $04 00
         ID3v2 flags                %abcd0000
         ID3v2 size             4 * %0xxxxxxx
    
       The first three bytes of the tag are always "ID3", to indicate that
       this is an ID3v2 tag, directly followed by the two version bytes. The
       first byte of ID3v2 version is its major version, while the second
       byte is its revision number. In this case this is ID3v2.4.0. All
       revisions are backwards compatible while major versions are not. If
       software with ID3v2.4.0 and below support should encounter version
       five or higher it should simply ignore the whole tag. Version or
       revision will never be $FF.
    
       The version is followed by the ID3v2 flags field, of which currently
       four flags are used.
    
       a - Unsynchronisation
    
         Bit 7 in the 'ID3v2 flags' indicates whether or not
         unsynchronisation is applied on all frames (see section 6.1 for
         details); a set bit indicates usage.
    
       b - Extended header
    
         The second bit (bit 6) indicates whether or not the header is
         followed by an extended header. The extended header is described in
         section 3.2. A set bit indicates the presence of an extended
         header.
    
       c - Experimental indicator
    
         The third bit (bit 5) is used as an 'experimental indicator'. This
         flag SHALL always be set when the tag is in an experimental stage.
    
       d - Footer present
    
         Bit 4 indicates that a footer (section 3.4) is present at the very
         end of the tag. A set bit indicates the presence of a footer.
    
       All the other flags MUST be cleared. If one of these undefined flags
       are set, the tag might not be readable for a parser that does not
       know the flags function.
    
       The ID3v2 tag size is stored as a 32 bit synchsafe integer (section
       6.2), making a total of 28 effective bits (representing up to 256MB).
    
       The ID3v2 tag size is the sum of the byte length of the extended
       header, the padding and the frames after unsynchronisation. If a
       footer is present this equals to ('total size' - 20) bytes, otherwise
       ('total size' - 10) bytes.
    
       An ID3v2 tag can be detected with the following pattern:
         $49 44 33 yy yy xx zz zz zz zz
       Where yy is less than $FF, xx is the 'flags' byte and zz is less than
       $80.
    

    id3.hpp:

    #ifndef ID3_HPP
    #define ID3_HPP
    
    #include <algorithm>
    #include <fstream>
    #include <iostream>
    #include <string>
    #include <sstream>
    #include <vector>
    
    class ID3 {
      private:
        bool id3v2;
        bool synchron, extended, experimental, footer;
        short version_major;
        short version_revision;
        std::string filename;
        ID3();
    
      public:
        ID3(std::string);
        ~ID3();
        std::string getInfo() const;
        bool isID3v2() const;
        std::string getFilename() const;
        std::string getVersion() const;
        bool isSynchron() const;
        bool isExtended() const;
        bool isExperimental() const;
        bool isFooter() const;
    };
    
    #endif
    

    id3.cpp

    #include "id3.hpp"
    
    using namespace std;
    
    ID3::ID3() {
    }
    
    ID3::ID3(string filename) {
      this->filename = filename;
      fstream file(filename.c_str(), ios::in | ios::binary);
      if(file) {
        char header[11];
        file.read(header, 10);
        header[10] = '\0';
        if(header[0] == 'I' && header[1] == 'D' && header[2] == '3')
          this->id3v2 = true;
        else
          this->id3v2 = false;
    
        this->version_major = header[3];
        this->version_revision = header[4];
    
        char tmpExt[4];
        tmpExt[0] = header[5];
        tmpExt[1] = header[5];
        tmpExt[2] = header[5];
        tmpExt[3] = header[5];
        if(0x01 & (tmpExt[0] >> 7))
          this->synchron = true;
        else
          this->synchron = false;
    
        if(0x01 & (tmpExt[1] >> 6))
          this->extended = true;
        else
          this->extended = false;
    
        if(0x01 & (tmpExt[2] >> 5))
          this->experimental = true;
        else
          this->experimental = false;
    
        if(0x01 & (tmpExt[3] >> 4))
          this->footer = true;
        else
          this->footer = false;
        file.close();
      }
    }
    
    ID3::~ID3() {
    }
    
    string ID3::getInfo() const {
    }
    
    bool ID3::isID3v2() const {
      return this->id3v2;
    }
    
    string ID3::getFilename() const {
      return this->filename;
    }
    
    string ID3::getVersion() const {
      stringstream sversion;
      string version;
      sversion << this->version_major;
      sversion << ".";
      sversion << this->version_revision;
      sversion >> version;
      return version;
    }
    
    bool ID3::isSynchron() const {
      return this->synchron;
    }
    
    bool ID3::isExtended() const {
      return this->extended;
    }
    
    bool ID3::isExperimental() const {
      return this->experimental;
    }
    
    bool ID3::isFooter() const {
      return this->footer;
    }
    


  • OK, also ich mache es nach Deinem Vorschlag, ist auch irgendwie logischer,
    als mitten drinnen anzufangen. Nur habe ich das jetzte kleinere Problem,
    und zwar lese ich ja die Version und die nächsten 4 Bits aus, um die
    Informationen wie Unsynchonisatzion, ... auszulesen.

    OK, das mit dem "ID3" funktioniert mal :), jedoch alles weitere macht mir Probleme.
    Ich habe Dir mal meine *.CPP und *.HPP mitgepostet.
    Irgendwie klappt das mit der Version und dem nächsten Byte nicht.

    3.1.   ID3v2 header
    
       The first part of the ID3v2 tag is the 10 byte tag header, laid out
       as follows:
    
         ID3v2/file identifier      "ID3"
         ID3v2 version              $04 00
         ID3v2 flags                %abcd0000
         ID3v2 size             4 * %0xxxxxxx
    
       The first three bytes of the tag are always "ID3", to indicate that
       this is an ID3v2 tag, directly followed by the two version bytes. The
       first byte of ID3v2 version is its major version, while the second
       byte is its revision number. In this case this is ID3v2.4.0. All
       revisions are backwards compatible while major versions are not. If
       software with ID3v2.4.0 and below support should encounter version
       five or higher it should simply ignore the whole tag. Version or
       revision will never be $FF.
    
       The version is followed by the ID3v2 flags field, of which currently
       four flags are used.
    
       a - Unsynchronisation
    
         Bit 7 in the 'ID3v2 flags' indicates whether or not
         unsynchronisation is applied on all frames (see section 6.1 for
         details); a set bit indicates usage.
    
       b - Extended header
    
         The second bit (bit 6) indicates whether or not the header is
         followed by an extended header. The extended header is described in
         section 3.2. A set bit indicates the presence of an extended
         header.
    
       c - Experimental indicator
    
         The third bit (bit 5) is used as an 'experimental indicator'. This
         flag SHALL always be set when the tag is in an experimental stage.
    
       d - Footer present
    
         Bit 4 indicates that a footer (section 3.4) is present at the very
         end of the tag. A set bit indicates the presence of a footer.
    
       All the other flags MUST be cleared. If one of these undefined flags
       are set, the tag might not be readable for a parser that does not
       know the flags function.
    
       The ID3v2 tag size is stored as a 32 bit synchsafe integer (section
       6.2), making a total of 28 effective bits (representing up to 256MB).
    
       The ID3v2 tag size is the sum of the byte length of the extended
       header, the padding and the frames after unsynchronisation. If a
       footer is present this equals to ('total size' - 20) bytes, otherwise
       ('total size' - 10) bytes.
    
       An ID3v2 tag can be detected with the following pattern:
         $49 44 33 yy yy xx zz zz zz zz
       Where yy is less than $FF, xx is the 'flags' byte and zz is less than
       $80.
    

    id3.hpp:

    #ifndef ID3_HPP
    #define ID3_HPP
    
    #include <algorithm>
    #include <fstream>
    #include <iostream>
    #include <string>
    #include <sstream>
    #include <vector>
    
    class ID3 {
      private:
        bool id3v2;
        bool synchron, extended, experimental, footer;
        short version_major;
        short version_revision;
        std::string filename;
        ID3();
    
      public:
        ID3(std::string);
        ~ID3();
        std::string getInfo() const;
        bool isID3v2() const;
        std::string getFilename() const;
        std::string getVersion() const;
        bool isSynchron() const;
        bool isExtended() const;
        bool isExperimental() const;
        bool isFooter() const;
    };
    
    #endif
    

    id3.cpp

    #include "id3.hpp"
    
    using namespace std;
    
    ID3::ID3() {
    }
    
    ID3::ID3(string filename) {
      this->filename = filename;
      fstream file(filename.c_str(), ios::in | ios::binary);
      if(file) {
        char header[11];
        file.read(header, 10);
        header[10] = '\0';
        if(header[0] == 'I' && header[1] == 'D' && header[2] == '3')
          this->id3v2 = true;
        else
          this->id3v2 = false;
    
        this->version_major = header[3];
        this->version_revision = header[4];
    
        char tmpExt[4];
        tmpExt[0] = header[5];
        tmpExt[1] = header[5];
        tmpExt[2] = header[5];
        tmpExt[3] = header[5];
        if(0x01 & (tmpExt[0] >> 7))
          this->synchron = true;
        else
          this->synchron = false;
    
        if(0x01 & (tmpExt[1] >> 6))
          this->extended = true;
        else
          this->extended = false;
    
        if(0x01 & (tmpExt[2] >> 5))
          this->experimental = true;
        else
          this->experimental = false;
    
        if(0x01 & (tmpExt[3] >> 4))
          this->footer = true;
        else
          this->footer = false;
        file.close();
      }
    }
    
    ID3::~ID3() {
    }
    
    string ID3::getInfo() const {
    }
    
    bool ID3::isID3v2() const {
      return this->id3v2;
    }
    
    string ID3::getFilename() const {
      return this->filename;
    }
    
    string ID3::getVersion() const {
      stringstream sversion;
      string version;
      sversion << this->version_major;
      sversion << ".";
      sversion << this->version_revision;
      sversion >> version;
      return version;
    }
    
    bool ID3::isSynchron() const {
      return this->synchron;
    }
    
    bool ID3::isExtended() const {
      return this->extended;
    }
    
    bool ID3::isExperimental() const {
      return this->experimental;
    }
    
    bool ID3::isFooter() const {
      return this->footer;
    }
    


  • freeze schrieb:

    if(header[0] == 'I' && header[1] == 'D' && header[2] == '3')
          this->id3v2 = true;
        else
          this->id3v2 = false;
    

    Der if/else Konstrukt ist hier unnötig.

    this->id3v2 = header[0] == 'I' && header[1] == 'D' && header[2] == '3';
    

    Hier genauso:

    freeze schrieb:

    if(0x01 & (tmpExt[0] >> 7))
          this->synchron = true;
        else
          this->synchron = false;
    

    ->

    this->synchron = (tmpExt[0] & 0x80) != 0; // != 0 zwar ueberfluessig, besaenftigt aber Compiler bezueglich Warnungen (zumindest MSC)
    // etc.
    

    freeze schrieb:

    char tmpExt[4];
        tmpExt[0] = header[5];
        tmpExt[1] = header[5];
        tmpExt[2] = header[5];
        tmpExt[3] = header[5];
    

    Was machst du denn hier? Wieso legst du 4 Kopien des 6. Bytes an?

    freeze schrieb:

    string ID3::getVersion() const {
      stringstream sversion;
      string version;
      sversion << this->version_major;
      sversion << ".";
      sversion << this->version_revision;
      sversion >> version;
      return version;
    }
    

    Der temp. String ist eingentlich unnötig.

    string ID3::getVersion() const {
      stringstream sversion;
      sversion << this->version_major;
      sversion << ".";
      sversion << this->version_revision;
      return sversion.str();
    }
    

    Ansonsten versteh ich nicht, wo dein Problem momentan liegt. Sieht doch bisher ok aus.



  • groovemaster2002 schrieb:

    this->synchron = (tmpExt[0] & 0x80) != 0; // != 0 zwar ueberfluessig, besaenftigt aber Compiler bezueglich Warnungen (zumindest MSC)
    // etc.
    

    Ansonsten versteh ich nicht, wo dein Problem momentan liegt. Sieht doch bisher ok aus.

    Ja, also mein Hauptprobelm liegt darin, da ich das mit den Bits nicht ganz verstehe, deswegen habe ich mir auch 4 kopien angelegt, weil ich nicht wußte, ob er diese jetzt verschiebt oder nicht. Denn wenn er sie verschiebt, dann ist doch die nächste Kontrollstruktur falsch, weil er schon verschoben hat.

    Der folgende Ausdruck von Dir:

    this->synchron = (tmpExt[0] & 0x80) != 0;
    

    was für ein bit wird da jetzt verschoben??

    Könntest Du mir das mit den bits kurz erklären, vielleicht kapiere ich es jetzt.
    Also angenommen ich habe 1 Byte (char), dieses wäre dann beispielsweise so aufgebaut

    11011100
    

    Hätte ich dann mit Deinem Ausdruck kontrolliert ob

    [b]1[/b]1011100
    

    oder ob

    1101110[b]0[/b]
    

    auf '1' ist?
    und müßte ich dann beim 7. Bit

    this->synchron = (tmpExt[0] & 0x70) != 0;
    

    schreiben?
    Sorry für die Fragen, aber mit Binär hatte ich vorher so meine Schwächen, deswegen würde ich gerne diese kleine Projekt durchziehen, um wieder gelernt zu haben, denn man lernt ja nie aus.

    Vielen Dank auf jedenfalls bis hierher.

    Lg _freeze_



  • Einfach gesagt, solang du keine Assignment Operatoren ins Spiel bringst (also &=, >>=, <<=, etc.) wird auch nix verändert. Das tmpExt ist also unnötig.

    Hex Werte, wie auch Werte anderer Darstellungsformen (zB binär, oktal oder dezimal), haben auf der rechten Seite die Stelle mit der geringsten Wertigkeit und links entsprechend die Stelle mit der höchsten Wertigkeit. Um das mal an deinem binären Beispiel zu verdeutlichen:

    Stelle      7 6 5 4 3 2 1 0
    Stellenwert 1 1 0 1 1 1 0 0
    

    0x80 binär:

    10000000
    

    Und jetzt noch beide Werte mit einem binären UND (&) verknüpft:

    11011100
    & [b]1[/b]0000000
    = [b]1[/b]0000000
    

    Also deine erste Version ist richtig.
    Wenn du jetzt Bit 6 (also 7. Bit) prüfen willst und den Hex Wert brauchst, musst du einfach entsprechenden Binärwert umwandeln:

    01000000
    

    Das überlass ich mal dir (als kleine Übung sozusagen 😃 , 0x70 jedenfalls ist falsch).
    Wie man von einem Darstellungssystem in ein anderes umwandelt, mag zwar kompliziert aussehen, ist aber relativ einfach wenn man erst mal kapiert hat wie's funktioniert. Letztendlich funktioniert ja alles auf die gleiche Art und Weise, mit dem Unterschied der unterschiedlichen Basen (binär=2, octal=8, dezimal=10, hexadezimal=16) und den daraus resultierenden Gegebenheiten. Und da die Basis von hex rein zufällig auch noch ein exponentielles Vielfaches der von binär ist, vereinfacht das die Umwandlung vom einen zum anderen System zusätzlich. Denn für die Anzahl der Werte, die in eine hex Stelle passen, braucht man genau 4 binäre Stellen.



  • OK, also ich habe mal folgendes probiert:

    this->synchron = (tmpExt[0] & 0x80) != 0;     // 10000000
    this->extended = (tmpExt[0] & 0x40) != 0;     // 01000000
    this->experimental = (tmpExt[0] & 0x20) != 0; // 00100000
    this->footer = (tmpExt[0] & 0x10) != 0;       // 00010000
    

    Jedoch bekomme ich bei jedem Wert ein false zurück, und irgendwie glaube ich nicht, das bei meinen ganzen MP3's immer der selbe Wert(false) ist.

    Stimmt das überhaupt mit diesen Werten?

    Lg freeze



  • Deine Hex Werte stimmen erstmal. Ich frag mich nur ob tmpExt[0] noch stimmt, sollte das nicht header[5] oder so was sein? Und wieso sollte nicht alles false sein? Kannst ja zur Not mit nem Hexeditor nachkontrollieren.



  • Also ich weiß nicht, vielleicht bin ich im moment etwas verwirrt, ab steht im extended header nicht ob Titel usw. da sind? Und wenn das Extended Header Bit nun auf false ist, da wären ja auch kein Titel usw. da oder? Ausserdem funktioniert das mit der Version, so wie es in den Postings schon vorhanden ist nicht richtig, da ich Werte zwischen 0 und 65535? Ich glaube kaum das 65535 eine richtige Version ist 🙂

    LG freeze



  • freeze schrieb:

    Also ich weiß nicht, vielleicht bin ich im moment etwas verwirrt, ab steht im extended header nicht ob Titel usw. da sind?

    Nö. Ob Titel etc. vorhanden sind, bekommst du mit, wenn du die Frames liest und der entsprechende Frame halt dabei ist.

    freeze schrieb:

    Ausserdem funktioniert das mit der Version, so wie es in den Postings schon vorhanden ist nicht richtig, da ich Werte zwischen 0 und 65535? Ich glaube kaum das 65535 eine richtige Version ist

    Darüber würde ich mir erstmal keine Gedanken machen. Wichtig ist, dass der grundlegende Algorithmus zum Einlesen des Tags funktioniert, später kannst du dir immer noch Gedanken über solche Feinheiten machen (seitdenn du willst v2.3.0 und v2.4.0 implementieren). Deine Werte können auch dadurch entstehen, dass du zB mp3's einliest, die keinen ID3 Tag haben. Vielleicht solltest du ne Exception werfen, wenn 'ID3' nicht gefunden wird, oder zumindest erstmal ne Nachricht ausgeben. Ausserdem würde ich folgende Zeilen nochmal überarbeiten:

    char header[11];
        file.read(header, 10);
        header[10] = '\0';
    

    Wie schon in einem früheren Post gesagt, du musst dir die eingelesenen Daten als reine Rohdaten vorstellen. Also keine Strings oder ähnliches, dh

    char header[10];
        file.read(header, 10);
    

    reicht vollkommen aus, obwohl ich die Header Elemente wohl eher noch unsigned machen würde, immerhin spricht die Doku ja von Bytes. Und bei Verwendung von signed können eher mal unerwartete Ergebnisse auftreten, wenn man auf einer solchen Low-Level Datenebene arbeitet.


Anmelden zum Antworten