2010-12-10 2 views
2

Я играю с TagLib (в Windows, построенном с помощью MingW). Я пытаюсь распознать TagLib, когда в файле MP3 нет информации ID3v1 или ID3v2. Согласно TagLib documentation, функция ID3v2Tag() в объекте MPEG File должна возвращать указатель NULL, когда в файле нет информации ID3v2.Неожиданный возврат не-NULL

К сожалению, это не происходит. У меня есть некоторые тестовые файлы MP3, которые я сделал, что я использую в своем коде (я сделал файлы доступны):

  • blank.mp3 (download), нет ID3v1 или ID3v2 информации вообще. Я могу подтвердить это, выполнив обычный текстовый поиск для «TAG» и «ID3» в двоичном содержимом файлов.
  • only_album_id3v2.mp3 (download), имеет информацию ID3v2 (только установлен альбом)
  • only_album_id3v1.mp3 (download), имеет информацию ID3v1 (только установлен альбом)

Вот мой код.

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

Запуск этой программы должен сломаться, из-за ошибки NULL указателя на cout << at->album() << endl;, но он работает просто отлично. Кроме того, когда я cout << ct << endl;, он возвращает адрес памяти.

Вот результат:

Test.

тест альбом id3v2

Программа выполняется.

EDIT: Вот новый тест.

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

И вот выход.

Тест.
at is not NULL.
bt не является NULL.
ct не является NULL.
Программа выполнена.

+0

Что вы ожидаете? Исключение? Вы передаете значения NULL в поток, который не выводится в консоли, если я это правильно вижу. Разве это не ожидалось? – Kissaki 2010-12-10 02:13:34

+0

Выполняется ли «Программа». Действительно вывод? Как я не вижу этого в вашем исходном коде. – Kissaki 2010-12-10 02:15:13

+0

@ Kissaki, не должен `cout << ct << endl;` выводить 0 в поток, если ct NULL? Кроме того, я исправил пример кода, чтобы он соответствовал выходу. Раньше я обновлял выход, но не код. Теперь они соответствуют – 2010-12-10 04:47:54

ответ

5

Я кратко рассмотрел код TagLib.

Я ничего не знаю об этом и никогда не использовал его, но код выглядит багги для меня. Вот почему -

В MPEG :: File :: read() мы ищем тег - d->ID3v2Location = findID3v2();. Если он не существует, он не добавляется к вектору тегов. Это чек - if(d->ID3v2Location >= 0).

Однако, в конце функции, как раз перед возвращением, у нас -

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

Теперь Id3v2Tag(create) с истинным параметром, на самом деле вызывает return d->tag.access(ID3v2Index, create);. Функция доступа() является -

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

Так что, когда create верно, мы создаем совершенно новый, пустой тег и поместить его в вектор (с помощью функции set()).

Это означает, что независимо от того, содержит ли файл теги или нет, они добавляются к вектору. Это не документированное поведение. Похож на ошибку.

Я не знаю, почему эти две строки нужны там - просмотр истории этого файла может подсказывать, почему они были добавлены, но я этого не делал.

В любом случае, я хочу подчеркнуть, что я никогда не исполнял этот код. Это основано на чисто статическом чтении только очень мелких деталей, не зная о масштабных проблемах.

Я думаю, что открытие отчета об ошибке не может повредить.

1

Использование нулевого указателя не обязательно приводит к появлению какой-либо ошибки; это неопределенное поведение. Возможно, это работает, или это может сделать что-то действительно странное.

В этом случае компилятор, вероятно, генерирует вызов TagLib :: ID3v2 :: Tag :: album с Указатель имеет значение null, но даже это не гарантируется. То, что происходит внутри функции, - это догадка.

Если функция может возвращать NULL, вы должны явно ее проверять и делать что-то другое.

0

Taglib создает «пустой» ID3v2Tag и ID3v1Tag в объекте, если файл его не имеет.