Search code examples
c++c++builder-2010bassbass.dll

TAG_ID3 (from Bass 2.4.4) doesn't work properly


I'm trying to read ID3v1 tags from mp3 files using "BASS.dll"(via bass.lib and bass.h).
It works fine until .mp3 file has title (or artist) has 30 characters.
Instead Happy Times (Feat. Margaux Bos I get Happy Times (Feat. Margaux BosEmigrate
with Emigrate added (that's artist tag).

How to make it work properly, without adding artist tag?
Here is my source code:

//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit2.h"
#include "bass.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm2 *Form2;

//---------------------------------------------------------------------------
__fastcall TForm2::TForm2(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm2::Button1Click(TObject *Sender)
{
    BASS_Init(-1, 44000, 0, 0, 0);

    if(OpenDialog1->Execute())
    {
       HSTREAM stream = BASS_StreamCreateFile(false, OpenDialog1->FileName.c_str(), 0, 0, 0);
       TAG_ID3 *tags = (TAG_ID3*)BASS_ChannelGetTags(stream, BASS_TAG_ID3);
       Edit1->Text = tags->title;
    }
}

Solution

  • The text fields of the TAG_ID3 struct are not guaranteed to be null terminated, but your code is treating them as if they are, so it ends up reading into the next field when a null terminator is not present. To fix that, you have to take their max lengths into account, eg:

    Edit1->Text = AnsiString().sprintf("%.*s", sizeof(tags->title), tags->title);
    

    Or:

    Edit1->Text = AnsiString(tags->title, sizeof(tags->title)).TrimRight();
    

    Same with all of other text fields:

    • id: 3 chars
    • title: 30 chars
    • artist: 30 chars
    • album: 30 chars
    • year: 4 chars
    • comment: 30 chars

    You can use a simple template wrapper to help you:

    template<size_t N>
    String toString(char (&arr)[N])
    {
        return AnsiString().sprintf("%.*s", N, arr); 
        /* or:
        return AnsiString(arr, N).TrimRight();
        */
    }
    
    Edit1->Text = toString(tags->title);
    

    Note that the comment field has an additional caveat to watch out for:

    If the 30th character is non-null whilst the 29th character is null, then the 30th character is the track number and the comment is limited to the first 28 characters.