bool CFile::Cache(const CStdString& strFileName, const CStdString& strDest, XFILE::IFileCallback* pCallback, void* pContext) { CFile file; CAsyncFileCallback* helper = NULL; if (file.Open(strFileName, true, READ_TRUNCATED)) { if (file.GetLength() <= 0) { CLog::Log(LOGWARNING, "FILE::cache: the file %s has a length of 0 bytes", strFileName.c_str()); file.Close(); // Never save 0 byte files from the Plex Media Server. if (strFileName.Find(":32400") != -1) return false; } CFile newFile; if (CUtil::IsHD(strDest)) // create possible missing dirs { std::vector<CStdString> tokens; CStdString strDirectory; CUtil::GetDirectory(strDest,strDirectory); CUtil::RemoveSlashAtEnd(strDirectory); // for the test below if (!(strDirectory.size() == 2 && strDirectory[1] == ':')) { CUtil::Tokenize(strDirectory,tokens,"\\"); CStdString strCurrPath = tokens[0]+"\\"; for (std::vector<CStdString>::iterator iter=tokens.begin()+1;iter!=tokens.end();++iter) { strCurrPath += *iter+"\\"; CDirectory::Create(strCurrPath); } } } if (CFile::Exists(strDest)) CFile::Delete(strDest); if (!newFile.OpenForWrite(strDest, true, true)) // overwrite always { file.Close(); return false; } /* larger then 1 meg, let's do rendering async */ // Async render cannot be done in Linux because of the resulting ThreadMessage deadlock #ifndef _LINUX if( file.GetLength() > 1024*1024 ) helper = new CAsyncFileCallback(pCallback, pContext); #endif // 128k is optimal for xbox int iBufferSize = 128 * 1024; CAutoBuffer buffer(iBufferSize); int iRead, iWrite; UINT64 llFileSize = file.GetLength(); UINT64 llFileSizeOrg = llFileSize; UINT64 llPos = 0; int ipercent = 0; CStopWatch timer; timer.StartZero(); float start = 0.0f; while (llFileSize > 0) { g_application.ResetScreenSaver(); unsigned int iBytesToRead = iBufferSize; /* make sure we don't try to read more than filesize*/ if (iBytesToRead > llFileSize) iBytesToRead = llFileSize; iRead = file.Read(buffer.get(), iBytesToRead); if (iRead == 0) break; else if (iRead < 0) { CLog::Log(LOGERROR, "%s - Failed read from file %s", __FUNCTION__, strFileName.c_str()); break; } /* write data and make sure we managed to write it all */ iWrite = 0; while(iWrite < iRead) { int iWrite2 = newFile.Write(buffer.get()+iWrite, iRead-iWrite); if(iWrite2 <=0) break; iWrite+=iWrite2; } if (iWrite != iRead) { CLog::Log(LOGERROR, "%s - Failed write to file %s", __FUNCTION__, strDest.c_str()); break; } llFileSize -= iRead; llPos += iRead; // calculate the current and average speeds float end = timer.GetElapsedSeconds(); float averageSpeed = llPos / end; start = end; float fPercent = 100.0f * (float)llPos / (float)llFileSizeOrg; if ((int)fPercent != ipercent) { if( helper ) { helper->SetStatus((int)fPercent, averageSpeed); if(helper->IsCanceled()) break; } else if( pCallback ) { if (!pCallback->OnFileCallback(pContext, ipercent, averageSpeed)) break; } ipercent = (int)fPercent; } } /* close both files */ newFile.Close(); file.Close(); if(helper) delete helper; /* verify that we managed to completed the file */ if (llPos != llFileSizeOrg) { CFile::Delete(strDest); return false; } return true; } return false; }
bool CFile::Cache(const CStdString& _strFileName, const CStdString& _strDest, XFILE::IFileCallback* pCallback, void* pContext) { CFile file; CAsyncFileCallback* helper = NULL; CStdString strFileName = _strFileName; if (CUtil::IsSpecial(strFileName)) { strFileName = _P(_strFileName); } CStdString strDest = _strDest; if (CUtil::IsSpecial(strDest)) { strDest = _P(_strDest); } if (file.Open(strFileName, READ_TRUNCATED)) { CFile newFile; if (CUtil::IsHD(strDest)) // create possible missing dirs { CStdString strDirectory; CUtil::GetDirectory(strDest,strDirectory); CDirectory::CreateRecursive(strDirectory); } if (CFile::Exists(strDest)) CFile::Delete(strDest); if (!newFile.OpenForWrite(strDest, true)) // overwrite always { file.Close(); return false; } /* larger then 1 meg, let's do rendering async */ // Async render cannot be done in SDL builds because of the resulting ThreadMessage deadlock // we should call CAsyncFileCopy::Copy() instead. #if defined(_XBOX) if( file.GetLength() > 1024*1024 ) helper = new CAsyncFileCallback(pCallback, pContext); #endif // 128k is optimal for xbox int iBufferSize = 128 * 1024; CAutoBuffer buffer(iBufferSize); int iRead, iWrite; UINT64 llFileSizeOrg = file.GetLength(); UINT64 llPos = 0; int ipercent = 0; bool finishedReading = false; CStopWatch timer; timer.StartZero(); float start = 0.0f; while (!finishedReading) { g_application.ResetScreenSaver(); iRead = file.Read(buffer.get(), iBufferSize); if (iRead == 0) { finishedReading = true; break; } else if (iRead < 0) { CLog::Log(LOGERROR, "%s - Failed read from file %s", __FUNCTION__, strFileName.c_str()); break; } /* write data and make sure we managed to write it all */ iWrite = 0; while(iWrite < iRead) { int iWrite2 = newFile.Write(buffer.get()+iWrite, iRead-iWrite); if(iWrite2 <=0) break; iWrite+=iWrite2; } if (iWrite != iRead) { CLog::Log(LOGERROR, "%s - Failed write to file %s", __FUNCTION__, strDest.c_str()); break; } llPos += iRead; // calculate the current and average speeds float end = timer.GetElapsedSeconds(); float averageSpeed = llPos / end; start = end; float fPercent; if (llFileSizeOrg > 0) { fPercent = 100.0f * (float)llPos / (float)llFileSizeOrg; } else { fPercent = 50.0f; } if ((int)fPercent != ipercent) { if( helper ) { helper->SetStatus((int)fPercent, averageSpeed); if(helper->IsCanceled()) break; } else if( pCallback ) { if (!pCallback->OnFileCallback(pContext, ipercent, averageSpeed)) break; } ipercent = (int)fPercent; } } /* close both files */ newFile.Close(); file.Close(); delete helper; /* verify that we managed to completed the file */ if (llFileSizeOrg > 0 && llPos != llFileSizeOrg) { CFile::Delete(strDest); return false; } return true; } return false; }