www.pudn.com > MP3CORD.rar > musiccatalog.cpp


/*____________________________________________________________________________ 
 
        FreeAmp - The Free MP3 Player 
 
        Portions Copyright (C) 1999 EMusic.com 
 
        This program is free software; you can redistribute it and/or modify 
        it under the terms of the GNU General Public License as published by 
        the Free Software Foundation; either version 2 of the License, or 
        (at your option) any later version. 
 
        This program is distributed in the hope that it will be useful, 
        but WITHOUT ANY WARRANTY; without even the implied warranty of 
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
        GNU General Public License for more details. 
 
        You should have received a copy of the GNU General Public License 
        along with this program; if not, write to the Free Software 
        Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
 
        $Id: musiccatalog.cpp,v 1.36 2000/01/19 22:20:29 ijr Exp $ 
____________________________________________________________________________*/ 
 
// The debugger can't handle symbols more than 255 characters long. 
// STL often creates symbols longer than that. 
// When symbols are longer than 255 characters, the warning is disabled. 
#ifdef WIN32 
#pragma warning(disable:4786)  
#endif 
 
#include  
 
#ifdef WIN32 
#include  
#else 
#include  
#include "win32impl.h" 
#endif 
 
#include  
#include  
 
#if !defined(WIN32) 
#include  
typedef ostrstream ostringstream; 
#else 
#include  
#endif 
 
using namespace std; 
 
#include "config.h" 
#include "musiccatalog.h" 
#include "player.h" 
#include "utility.h" 
#include "debug.h" 
 
#define METADATABASE_VERSION 1 
 
MusicCatalog::MusicCatalog(FAContext *context, char *databasepath) 
{ 
    m_database = NULL; 
    m_context = context; 
    m_plm = context->plm; 
    m_mutex = new Mutex(); 
    m_catMutex = new Mutex(); 
    m_inUpdateSong = false; 
    m_acceptItemChanged = false; 
    m_artistList = new vector; 
    m_unsorted = new vector; 
    m_playlists = new vector; 
    m_streams = new vector; 
    
    if (databasepath) 
        SetDatabase(databasepath); 
} 
 
MusicCatalog::~MusicCatalog() 
{ 
    vector::iterator a; 
    vector::iterator p; 
 
    if (m_database) 
        delete m_database; 
 
    for(a = m_artistList->begin(); a != m_artistList->end(); a++) 
       delete (*a); 
    delete m_artistList; 
 
    for(p = m_unsorted->begin(); p != m_unsorted->end(); p++) 
       delete (*p); 
    delete m_unsorted; 
     
    for(p = m_streams->begin(); p != m_streams->end(); p++) 
       delete (*p); 
    delete m_streams; 
     
    delete m_playlists; 
    delete m_mutex; 
    delete m_catMutex; 
} 
 
class comp_catalog { 
  public: 
      bool operator()(PlaylistItem *a, PlaylistItem *b) 
      { 
          if (a->GetMetaData().Track() == b->GetMetaData().Track()) 
             // sort alphabetically... 
             return (a->GetMetaData().Title() < b->GetMetaData().Title()); 
          return (a->GetMetaData().Track() < b->GetMetaData().Track()); 
      } 
      bool operator()(AlbumList *a, AlbumList *b) 
      { 
          return (a->name < b->name); 
      } 
      bool operator()(ArtistList *a, ArtistList *b) 
      { 
          return (a->name < b->name); 
      } 
}; 
 
void MusicCatalog::Sort(void) 
{ 
    m_catMutex->Acquire(); 
    // Sort the playlists... 
    sort(m_playlists->begin(), m_playlists->end()); 
 
    // Sort the uncategorized tracks 
    sort(m_unsorted->begin(), m_unsorted->end(), comp_catalog()); 
 
    // Sort the rest o the junk 
    vector::iterator i = m_artistList->begin(); 
    for (; i != m_artistList->end(); i++) { 
        vector::iterator j = (*i)->m_albumList->begin(); 
        for (; j != (*i)->m_albumList->end(); j++) { 
            sort((*j)->m_trackList->begin(), (*j)->m_trackList->end(),  
                 comp_catalog()); 
        } 
        sort((*i)->m_albumList->begin(), (*i)->m_albumList->end(),  
             comp_catalog()); 
    } 
    sort(m_artistList->begin(), m_artistList->end(), comp_catalog()); 
 
    // Sort the streams 
    sort(m_streams->begin(), m_streams->end(), comp_catalog()); 
 
    m_catMutex->Release(); 
} 
 
Error MusicCatalog::RemovePlaylist(const char *url) 
{ 
    assert(url); 
 
    if (!m_database->Working()) 
        return kError_DatabaseNotWorking; 
 
    char *data = m_database->Value(url); 
 
    if (!data) 
        return kError_ItemNotFound; 
 
    delete [] data; 
    m_database->Remove(url); 
 
    m_catMutex->Acquire(); 
 
    vector::iterator i = m_playlists->begin(); 
    for (; i != m_playlists->end(); i++) 
         if ((*i) == url) { 
             string tempstr = url; 
             if (tempstr.find("currentlist.m3u") >= tempstr.length()) { 
                 string sUrl = url;  
                 m_context->target->AcceptEvent(new MusicCatalogPlaylistRemovedEvent(sUrl)); 
                 m_playlists->erase(i); 
             } 
             m_catMutex->Release(); 
             return kError_NoErr; 
         }    
 
    m_catMutex->Release(); 
    return kError_ItemNotFound; 
} 
 
 
Error MusicCatalog::AddPlaylist(const char *url) 
{ 
    assert(url); 
 
    if (!m_database->Working()) 
        return kError_DatabaseNotWorking; 
     
    char *data = m_database->Value(url); 
    if (!data)  
        m_database->Insert(url, "P"); 
    else  
        delete [] data; 
 
    bool found = false; 
    m_catMutex->Acquire(); 
    vector::iterator i = m_playlists->begin(); 
    for (; i != m_playlists->end(); i++) 
         if ((*i) == url) 
             found = true; 
     
    if (!found) { 
        string tempstr = url; 
        if (tempstr.find("currentlist.m3u") < tempstr.length())  
            m_playlists->insert(m_playlists->begin(), url); 
        else 
            m_playlists->push_back(url); 
 
        string sUrl = url; 
        m_context->target->AcceptEvent(new MusicCatalogPlaylistAddedEvent(sUrl)); 
        m_catMutex->Release(); 
        return kError_NoErr; 
    } 
 
    m_catMutex->Release(); 
    return kError_DuplicateItem; 
} 
 
Error MusicCatalog::RemoveStream(const char *url) 
{ 
    assert(url); 
 
    if (!m_database->Working()) 
        return kError_DatabaseNotWorking; 
 
    MetaData *meta = ReadMetaDataFromDatabase(url); 
    if (!meta) 
        return kError_ItemNotFound; 
 
    m_database->Remove(url); 
 
    m_catMutex->Acquire(); 
     
    vector::iterator i = m_streams->begin(); 
    for (; i != m_streams->end(); i++) 
         if ((*i)->URL() == url) { 
             AcceptEvent(new MusicCatalogStreamRemovedEvent(*i)); 
             m_streams->erase(i); 
             break; 
         } 
 
    m_catMutex->Release(); 
 
    delete meta; 
    return kError_NoErr; 
} 
 
Error MusicCatalog::RemoveSong(const char *url) 
{ 
    assert(url); 
 
    if (!m_database->Working()) 
        return kError_DatabaseNotWorking; 
 
    MetaData *meta = ReadMetaDataFromDatabase(url); 
    if (!meta) 
        return kError_ItemNotFound; 
 
    m_database->Remove(url); 
 
    m_catMutex->Acquire(); 
    if ((meta->Artist().size() == 0) || (meta->Artist() == " ")) { 
        vector::iterator i = m_unsorted->begin(); 
        for (; i != m_unsorted->end(); i++) 
            if ((*i)->URL() == url) 
            { 
                AcceptEvent(new MusicCatalogTrackRemovedEvent(*i, NULL, NULL));      
                m_unsorted->erase(i); 
                break; 
            } 
    } 
    else  
    { 
        vector::iterator    i; 
        vector              *alList; 
        vector::iterator     j; 
        vector           *trList; 
        vector::iterator  k; 
        bool                              found = false; 
         
        i = m_artistList->begin(); 
        for (; i != m_artistList->end() && !found; i++)  
        { 
            if (meta->Artist() == (*i)->name)  
            { 
                alList = (*i)->m_albumList; 
                j = alList->begin(); 
                for (; j != alList->end() && !found; j++)  
                { 
                    if (meta->Album() == (*j)->name)  
                    { 
                        trList = (*j)->m_trackList; 
                        k = trList->begin(); 
                        for (; k != trList->end() && !found; k++) 
                            if (url == (*k)->URL()) 
                            { 
                                AcceptEvent(new MusicCatalogTrackRemovedEvent(*k, *i, *j)); 
                                trList->erase(k); 
                                found = true; 
                                break; 
                            }     
 
                        if (trList->size() == 0) 
                            alList->erase(j); 
                     } 
                } 
 
                if (alList->size() == 0) 
                    m_artistList->erase(i); 
            } 
        } 
    } 
 
    delete meta; 
 
    m_catMutex->Release(); 
    return kError_NoErr; 
} 
 
Error MusicCatalog::AddStream(const char *url) 
{ 
    assert(url); 
   
    if (!m_database->Working()) 
        return kError_DatabaseNotWorking; 
 
    PlaylistItem *newstream; 
 
    MetaData *meta = ReadMetaDataFromDatabase(url); 
 
    if (!meta) 
        return kError_DatabaseNotWorking; 
 
    newstream = new PlaylistItem(url, meta); 
 
    m_catMutex->Acquire(); 
 
    vector::iterator i = m_streams->begin(); 
    for (; i != m_streams->end(); i++)  
        if ((*i)->URL() == url) 
            return kError_DuplicateItem; 
 
    m_streams->push_back(newstream); 
    AcceptEvent(new MusicCatalogStreamAddedEvent(newstream)); 
 
    m_catMutex->Release(); 
 
    return kError_NoErr; 
} 
 
Error MusicCatalog::AddSong(const char *url) 
{ 
    assert(url); 
 
    if (!m_database->Working()) 
        return kError_DatabaseNotWorking; 
 
    PlaylistItem *newtrack; 
 
    MetaData *meta = ReadMetaDataFromDatabase(url); 
 
    if (!meta) { 
        newtrack = new PlaylistItem(url); 
        m_context->plm->RetrieveMetaData(newtrack); 
 
        while (newtrack->GetState() != kPlaylistItemState_Normal) 
            usleep(5); 
 
        MetaData tempdata = (MetaData)(newtrack->GetMetaData()); 
        WriteMetaDataToDatabase(url, tempdata); 
 
        delete newtrack; 
 
        meta = ReadMetaDataFromDatabase(url); 
    } 
 
    newtrack = new PlaylistItem(url, meta); 
 
    m_catMutex->Acquire(); 
    if ((meta->Artist().size() == 0) || (meta->Artist() == " ")) { 
 
        vector::iterator i = m_unsorted->begin(); 
        for (; i != m_unsorted->end(); i++) 
             if ((*i)->URL() == url) 
                 return kError_DuplicateItem; 
 
        m_unsorted->push_back(newtrack); 
        AcceptEvent(new MusicCatalogTrackAddedEvent(newtrack, NULL, NULL)); 
    } 
    else { 
        bool changed = false; 
        if (meta->Album() == " " || meta->Album().size() == 0) { 
            string unknownstr = string("Unknown"); 
            meta->SetAlbum(unknownstr.c_str()); 
            changed = true; 
        } 
        if (meta->Title() == " " || meta->Title().size() == 0) { 
            string unknownstr = string("Unknown"); 
            meta->SetTitle(unknownstr.c_str()); 
            changed = true; 
        } 
   
        if (changed) 
            WriteMetaDataToDatabase(url, *meta); 
 
        bool found_artist = false; 
        vector::iterator i = m_artistList->begin(); 
        for (; i != m_artistList->end(); i++) { 
            if (meta->Artist() == (*i)->name) { 
                bool found_album = false; 
                found_artist = true; 
                vector *alList = (*i)->m_albumList; 
                vector::iterator j = alList->begin(); 
                for (; j != alList->end(); j++) { 
                    if (meta->Album() == (*j)->name) { 
                        found_album = true; 
                        
                        vector *trList = (*j)->m_trackList; 
                        vector::iterator k = trList->begin(); 
                        for (; k != trList->end(); k++) { 
                            if ((*k)->URL() == url) { 
                                delete newtrack;   
                                m_catMutex->Release(); 
                                return kError_DuplicateItem; 
                            } 
                        } 
                        (*j)->m_trackList->push_back(newtrack); 
                        AcceptEvent(new MusicCatalogTrackAddedEvent(newtrack, *i, *j)); 
                        break; 
                     } 
                } 
                if (!found_album) { 
                    AlbumList *newalbum = new AlbumList; 
                    newalbum->name = meta->Album(); 
                    newalbum->m_trackList->push_back(newtrack); 
                    alList->push_back(newalbum); 
                    AcceptEvent(new MusicCatalogTrackAddedEvent(newtrack, (*i), newalbum)); 
                    break; 
                } 
            } 
        } 
        if (!found_artist) { 
            ArtistList *newartist = new ArtistList; 
            newartist->name = meta->Artist(); 
            AlbumList *newalbum = new AlbumList; 
            newalbum->name = meta->Album(); 
            newalbum->m_trackList->push_back(newtrack); 
            newartist->m_albumList->push_back(newalbum); 
            m_artistList->push_back(newartist); 
            AcceptEvent(new MusicCatalogTrackAddedEvent(newtrack, newartist, newalbum)); 
        } 
    } 
    delete meta; 
    m_catMutex->Release(); 
    return kError_NoErr; 
} 
 
Error MusicCatalog::UpdateSong(PlaylistItem *item) 
{ 
    assert(item); 
 
    if (!m_database->Working()) 
        return kError_DatabaseNotWorking; 
 
    m_inUpdateSong = true; 
 
    Error err = RemoveSong(item->URL().c_str()); 
     
    if (IsError(err)) 
        return err; 
    
    WriteMetaDataToDatabase(item->URL().c_str(), item->GetMetaData()); 
 
    m_database->Sync(); 
 
    err = AddSong(item->URL().c_str()); 
 
    if (IsError(err)) 
        return err; 
 
    m_inUpdateSong = false; 
 
    m_context->target->AcceptEvent(new MusicCatalogTrackChangedEvent(m_oldItem, m_newItem, m_oldArtist, m_newArtist, m_oldAlbum, m_newAlbum)); 
 
    return kError_NoErr; 
} 
 
Error MusicCatalog::Remove(const char *url) 
{ 
    assert(url); 
 
    if (!m_database->Working()) 
        return kError_DatabaseNotWorking; 
 
    char *data = m_database->Value(url); 
    if (!data) 
        return kError_ItemNotFound; 
 
    Error retvalue = kError_YouScrewedUp; 
 
    if (!strncmp("P", data, 1)) 
        retvalue = RemovePlaylist(url); 
    else if (!strncmp("M", data, 1)) 
        retvalue = RemoveSong(url); 
    else if (!strncmp("S", data, 1)) 
        retvalue = RemoveStream(url); 
 
    delete [] data; 
 
    return retvalue; 
} 
 
Error MusicCatalog::Add(const char *url) 
{ 
    assert(url); 
 
    if (!m_database->Working()) 
        return kError_DatabaseNotWorking; 
 
    char *data = m_database->Value(url); 
    if (!data) 
        return kError_ItemNotFound; 
 
    Error retvalue = kError_YouScrewedUp; 
 
    if (!strncmp("P", data, 1)) 
        retvalue = AddPlaylist(url); 
    else if (!strncmp("M", data, 1))  
        retvalue = AddSong(url); 
    else if (!strncmp("S", data, 1)) 
        retvalue = AddStream(url); 
 
    delete [] data; 
 
    return retvalue; 
} 
 
void MusicCatalog::ClearCatalog() 
{ 
    m_catMutex->Acquire(); 
    delete m_artistList; 
    delete m_unsorted; 
    delete m_playlists; 
    delete m_streams; 
    m_artistList = new vector; 
    m_unsorted = new vector; 
    m_playlists = new vector; 
    m_streams = new vector; 
    m_catMutex->Release(); 
    m_context->target->AcceptEvent(new Event(INFO_MusicCatalogCleared)); 
} 
 
Error MusicCatalog::RePopulateFromDatabase() 
{ 
    if (!m_database->Working()) 
        return kError_DatabaseNotWorking; 
 
    ClearCatalog(); 
  
    char *key = m_database->NextKey(NULL); 
    Error err = kError_NoErr; 
 
    while (key) { 
        err = Add(key); 
 
        if (IsError(err)) { 
             m_context->target->AcceptEvent(new ErrorMessageEvent("There was an internal error during generation of the Music Catalog")); 
             return kError_YouScrewedUp; 
        } 
             
        key = m_database->NextKey(key); 
    } 
    return kError_NoErr; 
} 
 
void MusicCatalog::SetDatabase(const char *path) 
{ 
    if (m_database) 
        delete m_database; 
 
    m_database = new Database(path, METADATABASE_VERSION); 
 
    if (!m_database->Working()) { 
        delete m_database; 
        m_database = NULL; 
    } 
 
    PruneDatabase(); 
 
    if (m_database) { 
        RePopulateFromDatabase(); 
        Sort(); 
    } 
} 
 
void MusicCatalog::PruneDatabase(void) 
{ 
    char *key = m_database->NextKey(NULL); 
    struct stat st; 
 
    while (key) { 
        if (!strncmp("file://", key, 7)) { 
            uint32 length = strlen(key) + 1; 
            char *filename = new char[length]; 
 
            if (IsntError(URLToFilePath(key, filename, &length))) 
                if (-1 == stat(filename, &st)) { 
                    m_database->Remove(key); 
                    key = NULL; 
                } 
 
            delete [] filename; 
        } 
        key = m_database->NextKey(key); 
    } 
} 
 
typedef struct MusicSearchThreadStruct { 
    MusicCatalog *mc; 
    vector pathList; 
    Thread *thread; 
} MusicSearchThreadStruct; 
 
void MusicCatalog::SearchMusic(vector &pathList) 
{ 
    if (!m_database->Working()) 
        return; 
 
    Thread *thread = Thread::CreateThread(); 
 
    if (thread) { 
        MusicSearchThreadStruct *mst = new MusicSearchThreadStruct; 
 
        mst->mc = this; 
        mst->pathList = pathList; 
        mst->thread = thread; 
 
        thread->Create(musicsearch_thread_function, mst); 
    } 
} 
 
void MusicCatalog::StopSearchMusic(void) 
{ 
    m_exit = true; 
} 
 
void MusicCatalog::musicsearch_thread_function(void *arg) 
{ 
    MusicSearchThreadStruct *mst = (MusicSearchThreadStruct *)arg; 
 
    mst->mc->m_mutex->Acquire(); 
 
    mst->mc->m_exit = false; 
    mst->mc->DoSearchPaths(mst->pathList); 
 
    mst->mc->AcceptEvent(new Event(INFO_SearchMusicDone)); 
 
    mst->mc->m_mutex->Release(); 
 
    delete mst->thread; 
    delete mst; 
} 
 
void MusicCatalog::DoSearchPaths(vector &pathList) 
{ 
    vector::iterator i; 
     
    m_acceptItemChanged = true; 
    m_itemWaitCount = 0; 
 
    for(i = pathList.begin(); i != pathList.end(); i++) 
        DoSearchMusic((char *)(*i).c_str()); 
 
    while (m_itemWaitCount > 0) 
        usleep(5); 
    m_acceptItemChanged = false; 
} 
 
void MusicCatalog::DoSearchMusic(char *path) 
{ 
    vector *metalist = new vector; 
 
    WIN32_FIND_DATA find; 
    HANDLE handle; 
    string search = path; 
 
#ifndef WIN32 
    if (!strcmp(path, "/dev") || !strcmp(path, "/proc")) 
        return; 
#endif 
  
    string *info = new string("Searching: "); 
    (*info) += path; 
    m_context->player->AcceptEvent(new BrowserMessageEvent(info->c_str())); 
    delete info; 
    
    if (search[search.size() - 1] != DIR_MARKER) 
       search.append(DIR_MARKER_STR); 
 
    search.append("*"); 
#ifdef WIN32 
    search.append(".*"); 
#endif 
 
    handle = FindFirstFile((char *)search.c_str(), &find); 
 
    if (handle != INVALID_HANDLE_VALUE) 
    { 
        do 
        { 
            char *fileExt; 
#ifndef WIN32 
            if (find.dwFileAttributes == FILE_ATTRIBUTE_SYMLINK) 
                continue; 
#endif 
            if (find.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY) 
            { 
                if (!(!strcmp("." , find.cFileName) || !strcmp("..", find.cFileName))) 
                { 
                    string newDir = path;  
                    if (path[strlen(path) - 1] != DIR_MARKER) 
                        newDir.append(DIR_MARKER_STR); 
                    newDir.append(find.cFileName); 
 
                    DoSearchMusic((char *)newDir.c_str()); 
                } 
            } 
            else if ((fileExt = m_context->player->GetExtension(find.cFileName))) 
            { 
                if (m_plm->IsSupportedPlaylistFormat(fileExt) &&  
                    strcmp("currentlist.m3u", find.cFileName)) 
                { 
                    string file = path; 
                    file.append(DIR_MARKER_STR); 
                    file.append(find.cFileName); 
 
                    uint32 urlLength = strlen(file.c_str()) + 10; 
                    char *url = new char[urlLength]; 
 
                    if (IsntError(FilePathToURL(file.c_str(), url, &urlLength))) 
                        m_database->Insert(url, "P"); 
 
                    delete [] url; 
                } 
                else if (m_context->player->IsSupportedExtension(fileExt)) 
                { 
                    string file = path; 
                    file.append(DIR_MARKER_STR); 
                    file.append(find.cFileName); 
 
                    char *tempurl = new char[file.length() + 10]; 
                    uint32 length = file.length() + 10; 
 
                    if (IsError(FilePathToURL(file.c_str(), tempurl, &length))) 
                    { 
                        continue; 
                    } 
                        
                    PlaylistItem *plist = new PlaylistItem(tempurl); 
                    metalist->push_back(plist); 
                    m_itemWaitCount++; 
 
                    delete [] tempurl; 
                } 
                delete fileExt; 
            } 
        } 
        while (FindNextFile(handle, &find) && !m_exit); 
        FindClose(handle); 
 
        if (metalist->size() > 0) 
            m_plm->RetrieveMetaData(metalist); 
        else  
            delete metalist; 
    } 
} 
 
void MusicCatalog::WriteMetaDataToDatabase(const char *url,  
                                           const MetaData metadata, 
                                           MetadataStorageType type) 
{ 
    if (!m_database->Working()) 
        return; 
 
    ostringstream ost; 
    char num[256]; 
    const char *kDatabaseDelimiter = " "; 
 
    if (type == kTypeStream) 
        ost << "S" << kDatabaseDelimiter; 
    else 
        ost << "M" << kDatabaseDelimiter; 
 
    ost << 9 << kDatabaseDelimiter; 
 
    ost << metadata.Artist().size() << kDatabaseDelimiter; 
    ost << metadata.Album().size() << kDatabaseDelimiter; 
    ost << metadata.Title().size() << kDatabaseDelimiter; 
    ost << metadata.Comment().size() << kDatabaseDelimiter; 
    ost << metadata.Genre().size() << kDatabaseDelimiter; 
 
    sprintf(num, "%ld", (long int)metadata.Year()); 
    ost << strlen(num) << kDatabaseDelimiter; 
    sprintf(num, "%ld", (long int)metadata.Track()); 
    ost << strlen(num) << kDatabaseDelimiter; 
    sprintf(num, "%ld", (long int)metadata.Time()); 
    ost << strlen(num) << kDatabaseDelimiter; 
    sprintf(num, "%ld", (long int)metadata.Size()); 
    ost << strlen(num) << kDatabaseDelimiter; 
 
    ost << metadata.Artist(); 
    ost << metadata.Album(); 
    ost << metadata.Title(); 
    ost << metadata.Comment(); 
    ost << metadata.Genre(); 
    ost << metadata.Year(); 
    ost << metadata.Track(); 
    ost << metadata.Time(); 
    ost << metadata.Size(); 
    ost << '\0'; 
 
#ifdef WIN32 
    m_database->Insert(url, (char *)ost.str().c_str()); 
#else 
    m_database->Insert(url, (char *)ost.str()); 
#endif 
} 
 
MetaData *MusicCatalog::ReadMetaDataFromDatabase(const char *url) 
{ 
    if (!m_database->Working()) 
        return NULL; 
 
    char *dbasedata = m_database->Value(url); 
 
    if (!dbasedata) 
        return NULL; 
 
    MetaData *metadata = new MetaData(); 
    char *value = dbasedata + 2; 
 
    uint32 numFields = 0; 
    int offset = 0; 
 
    sscanf(value, "%lu%n", (long unsigned int *)&numFields, &offset); 
    uint32* fieldLength =  new uint32[numFields]; 
 
    for(uint32 i = 0; i < numFields; i++) 
    { 
        int temp; 
 
        sscanf(value + offset, " %lu %n", (long unsigned int *)&fieldLength[i], 
	                                  &temp); 
 
        if (i == numFields - 1) { 
            char intholder[10]; 
            sprintf(intholder, "%lu", (long unsigned int)fieldLength[i]); 
            offset += strlen(intholder) + 1; 
        } 
        else 
            offset += temp; 
    } 
 
    string data = value; 
    data.erase(0, offset); 
 
    uint32 count = 0; 
 
    for(uint32 j = 0; j < numFields; j++) 
    { 
        if (fieldLength[j] == 0)  
            continue; 
 
        switch(j) 
        { 
            case 0: 
                metadata->SetArtist(data.substr(count, fieldLength[j]).c_str()); 
                break; 
            case 1: 
                metadata->SetAlbum(data.substr(count, fieldLength[j]).c_str()); 
                break; 
            case 2: 
                metadata->SetTitle(data.substr(count, fieldLength[j]).c_str()); 
                break; 
            case 3: 
                metadata->SetComment(data.substr(count, fieldLength[j]).c_str()); 
                break; 
            case 4: 
                metadata->SetGenre(data.substr(count, fieldLength[j]).c_str()); 
                break; 
            case 5: 
                metadata->SetYear(atoi(data.substr(count, fieldLength[j]).c_str())); 
                break; 
            case 6: 
                metadata->SetTrack(atoi(data.substr(count, fieldLength[j]).c_str())); 
                break; 
            case 7: 
                metadata->SetTime(atoi(data.substr(count, fieldLength[j]).c_str())); 
                break; 
            case 8: 
                metadata->SetSize(atoi(data.substr(count, fieldLength[j]).c_str())); 
                break; 
            default: 
                break; 
 
        } 
 
        count += fieldLength[j]; 
    } 
 
    delete [] fieldLength; 
 
    delete [] dbasedata; 
 
    return metadata; 
} 
 
int32 MusicCatalog::AcceptEvent(Event *e) 
{ 
    switch (e->Type()) { 
        case INFO_MusicCatalogTrackRemoved: { 
            if (m_inUpdateSong) { 
                MusicCatalogTrackRemovedEvent *mctr =  
                                             (MusicCatalogTrackRemovedEvent *)e; 
                m_oldItem = (PlaylistItem *)mctr->Item(); 
                m_oldArtist = (ArtistList *)mctr->Artist(); 
                m_oldAlbum = (AlbumList *)mctr->Album(); 
      
                delete e; 
            } 
            else  
                m_context->target->AcceptEvent(e); 
            break; } 
        case INFO_MusicCatalogTrackAdded: { 
            if (m_inUpdateSong) { 
                MusicCatalogTrackAddedEvent *mcta = 
                                             (MusicCatalogTrackAddedEvent *)e; 
                m_newItem = (PlaylistItem *)mcta->Item(); 
                m_newArtist = (ArtistList *)mcta->Artist(); 
                m_newAlbum = (AlbumList *)mcta->Album(); 
 
                delete e; 
            } 
            else  
                m_context->target->AcceptEvent(e); 
            break; } 
        case INFO_PlaylistItemUpdated: { 
            if (m_acceptItemChanged) { 
                PlaylistItemUpdatedEvent *piu = (PlaylistItemUpdatedEvent *)e; 
                WriteMetaDataToDatabase(piu->Item()->URL().c_str(),  
                                        (MetaData)piu->Item()->GetMetaData()); 
 
                delete piu->Item(); 
                m_itemWaitCount--; 
            } 
            break; } 
        case INFO_SearchMusicDone: { 
            m_database->Sync(); 
            string info = "Pruning the Music Catalog Database..."; 
            m_context->target->AcceptEvent(new BrowserMessageEvent(info.c_str())); 
            PruneDatabase(); 
            info = "Regenerating the Music Catalog Database..."; 
            m_context->target->AcceptEvent(new BrowserMessageEvent(info.c_str())); 
            RePopulateFromDatabase(); 
            info = "Sorting the Music Catalog Database..."; 
            m_context->target->AcceptEvent(new BrowserMessageEvent(info.c_str())); 
            Sort(); 
            m_context->target->AcceptEvent(new Event(INFO_SearchMusicDone)); 
            delete e; 
            break; 
        }  
    } 
    return 0;  
}