/* daapd Song Cache (c) deleet 2003, Johannes Zander daapd 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. daapd 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 daapd; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include "types.h" namespace SongCache { namespace { // internal linkage is fine... const Tag::TagType SONG_TYPE = 'ddsi'; const Tag::TagType CONT_TYPE = 'ddci'; const Tag::TagType DATA_TYPE = 'dddi'; struct Data { std::string& str; Data( std::string& _str ) : str( _str ) {} }; ////// // input inline TagInput& operator >> ( TagInput& in, Data data ) { Tag tag; return( in >> tag >> data.str >> end ); } TagInput& operator >> ( TagInput& in, Song* song ) { if( song && in.peekTagType()==SONG_TYPE ) { Tag tag; in >> tag >> song->id >> song->kind >> Data( song->path ) >> Data( song->name ) >> Data( song->album ) >> Data( song->artist ) >> Data( song->composer ) >> Data( song->comment ) >> Data( song->description ) >> Data( song->genre ) >> song->year >> song->time >> song->starttime >> song->stoptime >> song->size >> song->trackcount >> song->tracknumber >> song->disccount >> song->discnumber >> song->compilation >> Data( song->format ) >> song->bitrate >> song->samplerate >> song->dateadded >> song->datemodified >> song->userrating >> song->bpm >> Data( song->eqpreset ) >> song->relativevolume >> song->datakind >> Data( song->dataurl ) >> song->disabled >> end; } return( in ); } ////// // output inline TagOutput& operator << ( TagOutput& out, Data data ) { return( out << Tag( DATA_TYPE ) << Chunk( (const u8*) data.str.data(), data.str.size()) << end ); } TagOutput& operator << ( TagOutput& out, Song* song ) { if( song ) { out << Tag( SONG_TYPE ) << song->id << song->kind << Data( song->path ) << Data( song->name ) << Data( song->album ) << Data( song->artist ) << Data( song->composer ) << Data( song->comment ) << Data( song->description ) << Data( song->genre ) << song->year << song->time << song->starttime << song->stoptime << song->size << song->trackcount << song->tracknumber << song->disccount << song->discnumber << song->compilation << Data( song->format ) << song->bitrate << song->samplerate << song->dateadded << song->datemodified << song->userrating << song->bpm << Data( song->eqpreset ) << song->relativevolume << song->datakind << Data( song->dataurl ) << song->disabled << end; } return( out ); } } ////// // SongCache public bool load( const char* cachefile, Dictionary& songDB, u8 verbose ) { bool result = false; FILE* file = fopen( cachefile, "rb" ); if( file ) { fseek( file, 0, SEEK_END ); long size = ftell( file ); u8* buffer = new u8[size]; fseek( file, 0, SEEK_SET ); if( fread( buffer, size, 1, file )) { Chunk ch = Chunk( buffer, size ); TagInput in( ch ); if( in.peekTagType()==CONT_TYPE ) { Tag tag; in >> tag; while( in.leftInTag()>0 ) if( in.peekTagType()==SONG_TYPE ) { Song *song = new Song; in >> song; if( verbose) printf( "reading %s from cache\n", song->path.c_str() ); if( in.isCorrupted() || songDB.add( song, song->path )<0 ) delete song; } else in >> skipTag; // unknown in >> end; } result = !in.isCorrupted(); } delete[]buffer; fclose( file ); } return( result ); } bool save( const char* cachefile, const Dictionary& songDB, u8 verbose ) { bool result = false; errno = 0; FILE* file = fopen( cachefile, "wb" ); if( verbose ) perror("Creating Cache file"); if( file ) { TagOutput out; out << Tag( CONT_TYPE ); std::vector songPointers; songDB.collectPointers( songPointers ); if( verbose ) printf("Saving %d song entries\n", (int) songPointers.size()); for( u32 i=0; i