virtual bool OnFile(OnFileStruct *onFileStruct) { char fullPathToDir[1024]; if (onFileStruct->fileName[0] && onFileStruct->fileData && subdirLen < strlen(onFileStruct->fileName)) { strcpy(fullPathToDir, outputSubdir); strcat(fullPathToDir, onFileStruct->fileName+subdirLen); WriteFileWithDirectories(fullPathToDir, (char*)onFileStruct->fileData, (unsigned int ) onFileStruct->byteLengthOfThisFile); } else fullPathToDir[0]=0; return onFileCallback->OnFile(onFileStruct); }
virtual bool OnFile(OnFileStruct *onFileStruct) { AutopatcherClientThreadInfo *inStruct = RakNet::OP_NEW<AutopatcherClientThreadInfo>( _FILE_AND_LINE_ ); inStruct->prePatchFile=0; inStruct->postPatchFile=0; memcpy(&(inStruct->onFileStruct), onFileStruct, sizeof(OnFileStruct)); memcpy(inStruct->applicationDirectory,applicationDirectory,sizeof(applicationDirectory)); if (onFileStruct->context.op==PC_HASH_1_WITH_PATCH || onFileStruct->context.op==PC_HASH_2_WITH_PATCH) onFileStruct->context.op=PC_NOTICE_FILE_DOWNLOADED_PATCH; else onFileStruct->context.op=PC_NOTICE_FILE_DOWNLOADED; onFileCallback->OnFile(onFileStruct); threadPool.AddInput(AutopatcherClientWorkerThread, inStruct); // Return false means don't delete OnFileStruct::data return false; }
// Update is run in the user thread virtual bool Update(void) { if (threadPool.HasOutputFast() && threadPool.HasOutput()) { AutopatcherClientThreadInfo *threadInfo = threadPool.GetOutput(); threadInfo->onFileStruct.context.op=threadInfo->result; switch (threadInfo->result) { case PC_NOTICE_WILL_COPY_ON_RESTART: { client->CopyAndRestart(threadInfo->onFileStruct.fileName); if (threadInfo->onFileStruct.context.op==PC_WRITE_FILE) { // Regular file in use but we can write the temporary file. Restart and copy it over the existing onFileCallback->OnFile(&threadInfo->onFileStruct); } else { // Regular file in use but we can write the temporary file. Restart and copy it over the existing rakFree_Ex(threadInfo->onFileStruct.fileData, _FILE_AND_LINE_ ); threadInfo->onFileStruct.fileData=threadInfo->postPatchFile; onFileCallback->OnFile(&threadInfo->onFileStruct); threadInfo->onFileStruct.fileData=0; } } break; case PC_ERROR_FILE_WRITE_FAILURE: { if (threadInfo->onFileStruct.context.op==PC_WRITE_FILE) { onFileCallback->OnFile(&threadInfo->onFileStruct); } else { rakFree_Ex(threadInfo->onFileStruct.fileData, _FILE_AND_LINE_ ); threadInfo->onFileStruct.fileData=threadInfo->postPatchFile; threadInfo->onFileStruct.byteLengthOfThisFile=threadInfo->postPatchLength; onFileCallback->OnFile(&threadInfo->onFileStruct); threadInfo->onFileStruct.fileData=0; } } break; case PC_ERROR_PATCH_TARGET_MISSING: { onFileCallback->OnFile(&threadInfo->onFileStruct); client->Redownload(threadInfo->onFileStruct.fileName); } break; case PC_ERROR_PATCH_APPLICATION_FAILURE: { // Failure - signal class and download this file. onFileCallback->OnFile(&threadInfo->onFileStruct); client->Redownload(threadInfo->onFileStruct.fileName); } break; case PC_ERROR_PATCH_RESULT_CHECKSUM_FAILURE: { // Failure - signal class and download this file. onFileCallback->OnFile(&threadInfo->onFileStruct); client->Redownload(threadInfo->onFileStruct.fileName); } break; default: { if (threadInfo->onFileStruct.context.op==PC_WRITE_FILE) { onFileCallback->OnFile(&threadInfo->onFileStruct); } else { rakFree_Ex(threadInfo->onFileStruct.fileData, _FILE_AND_LINE_ ); threadInfo->onFileStruct.fileData=threadInfo->postPatchFile; onFileCallback->OnFile(&threadInfo->onFileStruct); threadInfo->onFileStruct.fileData=0; } } break; } if (threadInfo->prePatchFile) rakFree_Ex(threadInfo->prePatchFile, _FILE_AND_LINE_ ); if (threadInfo->postPatchFile) rakFree_Ex(threadInfo->postPatchFile, _FILE_AND_LINE_ ); if (threadInfo->onFileStruct.fileData) rakFree_Ex(threadInfo->onFileStruct.fileData, _FILE_AND_LINE_ ); RakNet::OP_DELETE(threadInfo, _FILE_AND_LINE_); } // If both input and output are empty, we are done. if (onFileCallback->Update()==false) canDeleteUser=true; if ( downloadComplete && canDeleteUser && threadPool.IsWorking()==false) { // Stop threads before calling OnThreadCompletion, in case the other thread starts a new instance of this thread. StopThreads(); client->OnThreadCompletion(); return false; } return true; }