2010-12-10 16 views
2

Ich spiele mit TagLib (unter Windows, mit MingW). Ich versuche TagLib zu erkennen, wenn keine ID3v1- oder ID3v2-Informationen in einer MP3-Datei vorhanden sind. Laut der TagLib documentation sollte die ID3v2Tag() - Funktion in einem MPEG-Dateiobjekt einen Nullzeiger zurückgeben, wenn keine ID3v2-Informationen in der Datei vorhanden sind.Unerwartete Non-NULL-Rückgabe

Leider tritt dies nicht auf. Ich habe einige Test MP3-Dateien, die ich gemacht habe, dass ich in meinem Code verwenden (ich die Dateien zur Verfügung gestellt haben):

  • blank.mp3 (download), überhaupt kein ID3v1 oder ID3v2 Informationen. Ich kann dies bestätigen, indem ich eine einfache Textsuche nach "TAG" und "ID3" im binären Inhalt der Dateien durchführe.
  • only_album_id3v2.mp3 (download), ID3v2 Informationen hat (nur das Album gesetzt) ​​
  • only_album_id3v1.mp3 (download), hat ID3v1 Informationen (nur das Album gesetzt) ​​

Hier ist mein Code.

#include <iostream> 

#include <mpeg/mpegfile.h> 
#include <mpeg/id3v2/id3v2tag.h> 

using namespace std; 

int main() 
{ 
    cout << "Test." << endl; 

    TagLib::MPEG::File a("tests/other/blank.mp3"); 
    TagLib::MPEG::File b("tests/id3v2/only_album_id3v2.mp3"); 
    TagLib::MPEG::File c("tests/id3v1/only_album_id3v1.mp3"); 


    TagLib::ID3v2::Tag * at = a.ID3v2Tag(); 
    TagLib::ID3v2::Tag * bt = b.ID3v2Tag(); 
    TagLib::ID3v2::Tag * ct = c.ID3v2Tag(); 

    cout << at->album() << endl; 
    cout << bt->album() << endl; 
    cout << ct->album() << endl; 

    cout << "The program is done."; 

    return 0; 
} 

Das Ausführen dieses Programms brechen sollte, entstand durch einen NULL-Zeiger Fehler auf cout << at->album() << endl;, aber es läuft ganz gut. Auch wenn I cout << ct << endl;, gibt es eine Speicheradresse zurück. Hier

ist die Ausgabe:

-Test.

Test Album id3v2

Das Programm durchgeführt wird.

EDIT: Hier ist ein neuer Test.

#include <iostream> 

#include <mpeg/mpegfile.h> 
#include <mpeg/id3v2/id3v2tag.h> 

using namespace std; 

int main() 
{ 
    cout << "Test." << endl; 

    TagLib::MPEG::File a("tests/other/blank.mp3"); 
    TagLib::MPEG::File b("tests/id3v2/only_album_id3v2.mp3"); 
    TagLib::MPEG::File c("tests/id3v1/only_album_id3v1.mp3"); 


    TagLib::ID3v2::Tag * at = a.ID3v2Tag(); 
    TagLib::ID3v2::Tag * bt = b.ID3v2Tag(); 
    TagLib::ID3v2::Tag * ct = c.ID3v2Tag(); 

    if(at == NULL) 
    { 
     cout << "at is NULL."; 
    } 
    else 
    { 
     cout << "at is not NULL."; 
    } 
    cout << endl; 

    if(bt == NULL) 
    { 
     cout << "bt is NULL."; 
    } 
    else 
    { 
     cout << "bt is not NULL."; 
    } 
    cout << endl; 

    if(ct == NULL) 
    { 
     cout << "ct is NULL."; 
    } 
    else 
    { 
     cout << "ct is not NULL."; 
    } 
    cout << endl; 

    cout << "The program is done."; 

    return 0; 
} 

Und hier ist der Ausgang.

Test.
bei ist nicht NULL.
BT ist nicht NULL.
ct ist nicht NULL.
Das Programm ist fertig.

+0

Was erwarten Sie? Eine Ausnahme? Sie übergeben NULL-Werte an einen Stream, der nicht in der Konsole ausgegeben wird, wenn ich das richtig sehe. Ist das nicht erwartet? – Kissaki

+0

Ist das 'Das Programm fertig 'wirklich ausgegeben? Wie ich das in deinem Quellcode nicht sehe. – Kissaki

+0

@Kissaki, sollte nicht 'cout << ct << endl;' eine 0 an den Stream ausgeben, wenn ct NULL ist? Außerdem habe ich das Codebeispiel an die Ausgabe angepasst. Vorher habe ich die Ausgabe aktualisiert, aber nicht den Code. Jetzt stimmen sie überein –

Antwort

5

Ich untersuchte den TagLib-Code kurz.

Ich weiß nichts darüber und habe es nie benutzt, aber der Code sieht mir buggy. Hier ist warum -

In MPEG :: File :: read() suchen wir nach einem Tag - d->ID3v2Location = findID3v2();. Wenn es nicht existiert, wird es nicht zum Variablenvektor hinzugefügt. Dies ist der Scheck - if(d->ID3v2Location >= 0).

jedoch am Ende der Funktion, kurz vor der Rückkehr, wir haben -

// Make sure that we have our default tag types available. 
ID3v2Tag(true); 
ID3v1Tag(true); 

Nun Id3v2Tag(create) mit einem wahren Parameter tatsächlich rufen return d->tag.access(ID3v2Index, create);. Die Zugang() Funktion ist -

template <class T> T *access(int index, bool create) 
{ 
    if(!create || tag(index)) 
    return static_cast<T *>(tag(index)); 

    set(index, new T); 
    return static_cast<T *>(tag(index)); 
} 

Also, wenn create wahr ist, schaffen wir ein brandneuen, leeren Tag und es in dem Vektor (mit der set() Funktion) platzieren.

Dies bedeutet, dass unabhängig davon, ob die Datei die Tags enthält oder nicht, sie zum Vektor hinzugefügt werden. Dies ist nicht das dokumentierte Verhalten. Sieht nach einem Fehler aus.

Ich weiß nicht, warum diese beiden Zeilen dort benötigt werden - Blick auf den Verlauf dieser Datei könnte Hinweise darauf geben, warum sie hinzugefügt wurden, aber das habe ich nicht getan.

Wie auch immer, ich möchte betonen, dass ich diesen Code nie wirklich ausgeführt habe. Dies beruht darauf, dass nur sehr kleine Teile rein statisch gelesen werden, ohne große Probleme zu kennen.

Ich denke, dass das Öffnen eines Fehlerberichts nicht schaden kann.

+0

Um mögliche Fehler zu vermeiden, habe ich die beiden Aufrufe nicht kommentiert, sondern drei zusätzliche Funktionen hinzugefügt, die einen privaten booleschen Wert (hasID3v2, hasID3v1, hasAPE) zurückgeben. Danke, dass du das unterstrichen hast! –

+0

Ich habe die Dateihistorie nachgeschlagen und es stellt sich heraus, dass diese Zeilen eingeführt wurden [5 Jahre] (https://github.com/taglib/taglib/commit/37e2d6293f6312fb1fa7383d42726dc10e733a27). Wie auch immer, ich frage mich, wie man überprüft, ob das ID3-Tag verfügbar ist, damit ich beim Speichern (m4a zum Beispiel) nicht die falsche Datei verletze? –

+0

Ich habe [einen Fehlerbericht] (https://github.com/taglib/taglib/issues/250) nur für den Fall eingereicht. –

1

Die Verwendung eines Nullzeigers führt nicht unbedingt zu einem Fehler, den Sie sehen können. es ist undefiniertes Verhalten. Es scheint zu funktionieren, oder es könnte etwas wirklich wirklich Seltsames tun.

In diesem Fall generiert der Compiler wahrscheinlich einen Aufruf an TagLib :: ID3v2 :: Tag :: album mit dem Zeiger auf Null gesetzt, aber auch dies ist nicht garantiert. Was innerhalb der Funktion passiert, ist eine Vermutung.

Wenn die Funktion NULL zurückgeben kann, sollten Sie explizit nach etwas suchen und etwas anderes tun.

+0

Ich glaube, ich verstehe, was Sie sagen, und ich aktualisiert meine Frage zu passen, was Sie vorschlagen. Das Problem besteht weiterhin. –

0

Taglib erstellen eine "leere" ID3v2Tag und ID3v1Tag im Objekt, wenn die Datei keine haben.

+1

Dies ist meines Wissens nur möglich, wenn Sie TRUE an die ID3v2Tag() - Funktion eines MPEG-Dateiobjekts übergeben. –

+0

Ja, aber im Consuktor der Klasse TagLib :: MPEG :: Datei Aufruf ID3v2Tag und ID3v1Tag, mit dem Parameter als TRUE. –