#include "stdafx.h" #include "FMloader.h" #include extern CFMLoader gl_Loader; /* * LOADER DEFINES */ // "Serverip/name:user:pw" #define HTTPCONNECTSTRING "levelone.alfahost.org:web95f1:DRT6hkfV" #define HTTPBASEDIR "/php-temp/data/" #define HTTPCRCFILELIST "crcfilelist.txt" #define BLOCKSIZE 15000 //#define HTTPCONNECTSTRING "213.251.166.19:visit:visit" //#define HTTPBASEDIR "/php-temp/data/" //#define HTTPCRCFILELIST "crcfilelist.txt" /************************************************************************/ /* Cache / Stream redirect module */ /************************************************************************/ class CRedirectFile_Module : public CStreamModule { public: CRedirectFile_Module(); ~CRedirectFile_Module(); virtual int ioCtl( char *iCmd, void *ioOption );// send a command down the stream private: CdevFile *stdiomod; }; CRedirectFile_Module::CRedirectFile_Module() { stdiomod = new CdevFile(); } CRedirectFile_Module::~CRedirectFile_Module() { delete stdiomod; } CRedirectFile_Module::ioCtl(char* iCmd, void *ioOption ) { if( 0 == strcmp(iCmd,"OPEN") ){ // Test local cached first char path[256]; gl_Loader.MakeLocalPath(path,(char*)ioOption); if( OK == llfile_IoCtlStream( LLFILE_STREAM_STDIO, "EXIST", path) ) { // push the stdio driver stdiomod->link(this,mNext); if( llfile_IoCtlStream( LLFILE_STREAM_STDIO, "EXIST", path) ){ // Failed 2nd, remove driver stdiomod->unlink(); return -1; } // Redirected OPEN return stdiomod->ioCtl("OPEN",path); } } else if ( 0 == strcmp(iCmd,"CLOSE") ) { if( stdiomod->mPrev == this ){ stdiomod->unlink(); return stdiomod->ioCtl("CLOSE",0); } } return CStreamModule::ioCtl(iCmd,ioOption); } /************************************************************************/ /* CFMLOADER */ /************************************************************************/ CFMLoader::CFMLoader(void) { m_cbfunc = 0; m_usrPtr = 0; m_cur_stream = LLFILE_STREAM_STDIO; m_http_stream = LLFILE_STREAM_STDIO; m_approx_bytes_to_download = 0; } CFMLoader::~CFMLoader(void) { } /* * Functioncall sequence * 1) Init(); --> opens http, retrieves crcfilelist.txt * 2) TestFileList(); --> buils download list * 3) DownloadFiles(); --> download unmatched crc files from http * ... * On demand call: * LoadBitmap("bitmapfile"); * LoadIcon("iconfile"); * LoadWave("wavefile"); */ void CFMLoader::Init(const char * httpserver) { m_cur_stream = llfile_OpenStream( LLFILE_STREAM_ZIP, "RES:IMG_DATA" ); m_http_stream = llfile_OpenStream( LLFILE_STREAM_HTTP, httpserver); if( m_http_stream ) // http connect success { BuildCrcFileList(); } llfile_PushModule(m_cur_stream,new CRedirectFile_Module(),HEAD); llfile_current_stream = m_cur_stream; } /* * TestFileList, compares each file's crc with the filecrclist which * is downloaded from the httpserver * Returns number of files to be downloaded. * IF the parameter list is NULL, the server list will be used * -1 = failure */ int CFMLoader::TestFileList(char *list) { if( m_crc_list.InQueue() == 0 ) return -1; // Cannot test file, BuildCrcFileList failed if( list == NULL ){ queue_itr cItr(m_crc_list); crcEntry *E; while( E = cItr.Next() ){ TestFile(E->filename); } // return number of files that should be downloaded return m_download_queue.InQueue(); } char *Start = list; char filename[256]; Start = GetFirststring(list,filename,'\n'); while( *filename != 0 ){ TestFile(filename); Start = GetSubstring(Start,filename,'\n'); } // return number of files that should be downloaded return m_download_queue.InQueue(); } /* * Start downloading * returns count of sucessfull downloaded files */ int CFMLoader::DownloadFiles(ReadHookPtr cbfunc, void * usrPtr) { // now start to download int cnt=0; char * filetoload; m_cbfunc = cbfunc; m_usrPtr = usrPtr; CReadHookModule *fRHMod = new CReadHookModule( BLOCKSIZE, m_cbfunc, m_usrPtr ); llfile_PushModule(m_http_stream,fRHMod,HEAD); while( NULL != ( filetoload = m_download_queue.Get() ) ) { if( true == HttpDownloadFile( filetoload ) ) { // file ok cnt ++; } // not needed anymore free(filetoload); } llfile_PopModule(m_http_stream,fRHMod); llfile_current_stream = GetCurStream(); return cnt; } /************************************************************************/ /* Tests a single file and add to download queue */ /************************************************************************/ void CFMLoader::TestFile(const char*filename) { /* * First try to load from the filesystem */ int size; char * fptr = (char*)llfile_LoadToMem(filename,&size); if( fptr != NULL ){ //Build CRC crc32l cur = CRC32::GetMemCRC(fptr,size); llmem_free(fptr); // Download if no match int rc=CompareCrcToHttpList( filename, cur ); if( rc > 0 ){ m_download_queue.Put( strdup(filename) ); m_approx_bytes_to_download += rc; } } else { // This file was never downloaded before // and is not known by the data.zip, // so put it to the download queue m_download_queue.Put( strdup(filename) ); } } /************************************************************************/ /* Makes HTTP Path */ /************************************************************************/ void CFMLoader::MakeHttpPath(char *buf, const char *filename ) { strcpy(buf,HTTPBASEDIR); for(int i=0; buf[i]!=0; i++){ if( buf[i] == '\\' ) buf[i] ='/'; } if( i > 0 && buf[i-1] != '/' ) strcat(buf,"/"); strcat(buf,filename); } /************************************************************************/ /* Makes local Path */ /************************************************************************/ void CFMLoader::MakeLocalPath(char *buf, const char *filename ) { strcpy(buf,"/TMP:"); if( filename[0] == '/' || filename[0] == '\\' ) filename ++; strcat(buf,filename); } /************************************************************************/ /* Build crc file list */ /************************************************************************/ void CFMLoader::BuildCrcFileList() { if( !m_http_stream ) return; // nothing todo, http session closed llfile_current_stream = m_http_stream; char path[256]; MakeHttpPath(path,HTTPCRCFILELIST); if( ! llfile_IsFileExisting(path) ) return; // file not found /* * CRCFILE list on the server, download and build list */ CReadHookModule *rhempty = new CReadHookModule(15000,0,0); llfile_PushModule(m_http_stream, rhempty, HEAD); int size; char * crcf = (char*) llfile_LoadToMem(path,&size); llfile_PopModule(m_http_stream, rhempty, true); // rhempty deleted by function if( crcf == 0 ){ return; // load error } /* * Build list */ char line[256]; char * Start = GetFirststring(crcf,line,'\n'); while( *line != 0 && Start ){ crcEntry *entry = new crcEntry; char fname[256]; if( 3 == sscanf(line,"%s %x %d",fname,&entry->crc,&entry->size) ){ entry->filename = strdup(fname); m_crc_list.Put(entry); } else delete entry; Start = GetSubstring(Start,line,'\n'); } DebugOutLn("FileCRC list ok"); } /************************************************************************/ /* Compare CRC to crc list */ /************************************************************************/ int CFMLoader::CompareCrcToHttpList(const char *filename, crc32l crc) { /* * check m_crc_list, path */ if( m_crc_list.IsEmpty() == true ) return -2; char FNbuf[256]; strcpy(FNbuf,filename); char *FN = strrchr(filename,'/'); if( FN == NULL ){ FN = strrchr(filename,'\\'); } if( FN == NULL ) FN = FNbuf; else FN++; //FN = pointer to filename without path queue_itr itr(m_crc_list); crcEntry *E; while( E = itr.Next() ){ if( 0 == strcmp(FN,E->filename) ){ if( crc == E->crc ) return 0; else return E->size; } } return -1; } /************************************************************************/ /* HTTP Download File */ /************************************************************************/ bool CFMLoader::HttpDownloadFile(const char *filename) { llfile_eSTREAM eS = llfile_current_stream; llfile_current_stream = m_http_stream; char HTTPpath[256]; MakeHttpPath(HTTPpath,filename); int size; void * lmem = llfile_LoadToMem(HTTPpath,&size); if( lmem == 0 || size==0 ){ llfile_current_stream = eS; return false; } /* * Save to disk */ char TMPpath[256]; MakeLocalPath(TMPpath,filename); FILE * F = (FILE*)drv_fileopen(TMPpath,1); if( F ){ if( 1 != fwrite(lmem,size,1,F) ){ drv_fileclose((void*)F); unlink(TMPpath); //delete file, upon fileerror llfile_current_stream = eS; return false; } else drv_fileclose((void*)F); } llfile_current_stream = eS; return true; } // returns total amount of byte to be downloaded int CFMLoader::GetApproxDownloadSize() { return m_approx_bytes_to_download; } // returns number of files in the transfer queue int CFMLoader::GetCntFiles() { return m_download_queue.InQueue(); } /* * returns full path to local resources */ char * CFMLoader::MakePath(const char* filename) { static char path[256]; ::GetTempPath( 256, path); strcat(path,filename); return path; }