📄 partfile.cpp
字号:
bool finished = false;
while (!finished)
{
// Need to empty lists to avoid infinite loop when file is smaller than 180k
// Otherwise it would keep looping to find 3 blocks, there is only one and it is requested
liGoodParts.RemoveAll();
liPossibleParts.RemoveAll();
// Barry - Top priority should be to continue downloading from current blocks (if anything left to download)
bool foundPriorityPart = false;
CString gettingParts;
sender->ShowDownloadingParts(&gettingParts);
for (int i=(gettingParts.GetLength()-1); i>=0; i--)
{
if ((gettingParts.GetAt(i) == 'Y') && (GetNextEmptyBlockInPart(i, 0)))
{
liGoodParts.AddHead(i);
foundPriorityPart = true;
}
}
// Barry - Give priorty to end parts of archives and movies
if ((!foundPriorityPart) && (IsArchive() || IsMovie()) && theApp.glob_prefs->GetPreviewPrio())
{
uint32 partCount = GetPartCount();
// First part
if (sender->IsPartAvailable(0) && GetNextEmptyBlockInPart(0, 0))
{
liGoodParts.AddHead(0);
foundPriorityPart = true;
}
else if ((partCount > 1))
{
// Last part
if (sender->IsPartAvailable(partCount-1) && GetNextEmptyBlockInPart(partCount-1, 0))
{
liGoodParts.AddHead(partCount-1);
foundPriorityPart = true;
}
// Barry - Better to get rarest than these, add to list, but do not exclude all others.
// These get priority over other parts with same availability.
else if (partCount > 2)
{
// Second part
if (sender->IsPartAvailable(1) && GetNextEmptyBlockInPart(1, 0))
liGoodParts.AddHead(1);
// Penultimate part
else if (sender->IsPartAvailable(partCount-2) && GetNextEmptyBlockInPart(partCount-2, 0))
liGoodParts.AddHead(partCount-2);
}
}
}
if (!foundPriorityPart)
{
randomness = (uint16)ROUND(((float)rand()/RAND_MAX)*(GetPartCount()-1));
for (uint16 i = 0;i != GetPartCount();i++){
if (sender->IsPartAvailable(randomness))
{
if (partsav[randomness] && !IsComplete(randomness*PARTSIZE,((randomness+1)*PARTSIZE)-1)){
/*if (IsCorruptedPart(randomness)){
if (GetNextEmptyBlockInPart(randomness,0)){
goodpart = randomness;
break;
}
}
else */
if (IsPureGap(randomness*PARTSIZE,((randomness+1)*PARTSIZE)-1))
{
if (GetNextEmptyBlockInPart(randomness,0))
liPossibleParts.AddHead(randomness);
}
else if (GetNextEmptyBlockInPart(randomness,0))
liGoodParts.AddTail(randomness); // Barry - Add after archive/movie entries
}
}
randomness++;
if (randomness == GetPartCount())
randomness = 0;
}
}
CList<int,int>* usedlist;
if (!liGoodParts.IsEmpty())
usedlist = &liGoodParts;
else if (!liPossibleParts.IsEmpty())
usedlist = &liPossibleParts;
else{
if (!newblockcount){
return false;
}
else
break;
}
uint16 nRarest = 0xFFFF;
uint16 usedpart = usedlist->GetHead();
for (POSITION pos = usedlist->GetHeadPosition();pos != 0;usedlist->GetNext(pos)){
if (m_SrcpartFrequency.GetCount() >= usedlist->GetAt(pos)
&& m_SrcpartFrequency[usedlist->GetAt(pos)] < nRarest){
nRarest = m_SrcpartFrequency[usedlist->GetAt(pos)];
usedpart = usedlist->GetAt(pos);
}
}
while (true){
Requested_Block_Struct* block = new Requested_Block_Struct;
if (GetNextEmptyBlockInPart(usedpart,block)){
requestedblocks_list.AddTail(block);
newblocks[newblockcount] = block;
newblockcount++;
if (newblockcount == requestedCount){
finished = true;
break;
}
}
else
{
delete block;
break;
}
}
} //wend
*count = newblockcount;
return true;
}
void CPartFile::RemoveBlockFromList(uint32 start,uint32 end){
POSITION pos1,pos2;
for (pos1 = requestedblocks_list.GetHeadPosition(); ( pos2 = pos1 ) != NULL; ){
requestedblocks_list.GetNext(pos1);
if (requestedblocks_list.GetAt(pos2)->StartOffset <= start && requestedblocks_list.GetAt(pos2)->EndOffset >= end)
requestedblocks_list.RemoveAt(pos2);
}
}
void CPartFile::RemoveAllRequestedBlocks(void)
{
requestedblocks_list.RemoveAll();
}
void CPartFile::CompleteFile(bool bIsHashingDone){
if( this->srcarevisible )
theApp.emuledlg->transferwnd.downloadlistctrl.HideSources(this);
status = PS_COMPLETING;
if (!bIsHashingDone){
//m_hpartfile.Flush(); // flush the OS buffer before completing...
datarate = 0;
char* partfileb = nstrdup(partmetfilename);
partfileb[strlen(partmetfilename)-4] = 0;
CAddFileThread* addfilethread = (CAddFileThread*) AfxBeginThread(RUNTIME_CLASS(CAddFileThread), THREAD_PRIORITY_BELOW_NORMAL,0, CREATE_SUSPENDED);
addfilethread->SetValues(0,theApp.glob_prefs->GetTempDir(),partfileb,this);
addfilethread->ResumeThread();
delete[] partfileb;
return;
}
else{
StopFile();
// guess I was wrong about not need to spaw a thread.. It is if the temp and incoming dirs are on different partitions/drives and the file is large...[oz]
CWinThread *pThread = AfxBeginThread((AFX_THREADPROC)CompleteThreadProc, this, THREAD_PRIORITY_BELOW_NORMAL, 0, CREATE_SUSPENDED); // Lord KiRon - using threads for file completion
if (pThread)
pThread->ResumeThread();
else
throw CString(_T(GetResString(IDS_ERR_FILECOMPLETIONTHREAD))); // move this to resources
}
theApp.emuledlg->transferwnd.downloadlistctrl.ShowFilesCount();
UpdateDisplayedInfo(true);
}
UINT CPartFile::CompleteThreadProc(CPartFile* pFile)
{
if (!pFile)
return -1;
pFile->PerformFileComplete();
return 0;
}
// Lord KiRon - using threads for file completion
BOOL CPartFile::PerformFileComplete()
{
CSingleLock(&m_FileCompleteMutex,TRUE); // will be unlocked on exit
char* partfilename = nstrdup(fullname);
partfilename[strlen(fullname)-4] = 0;
char* newfilename = nstrdup(GetFileName());
strcpy(newfilename, (LPCTSTR)theApp.StripInvalidFilenameChars(newfilename));
char* newname = new char[strlen(newfilename)+strlen(theApp.glob_prefs->GetIncomingDir())+MAX_PATH];
CString indir;
if (PathFileExists( theApp.glob_prefs->GetCategory(GetCategory())->incomingpath)) {
indir=theApp.glob_prefs->GetCategory(GetCategory())->incomingpath;
sprintf(newname,"%s\\%s",indir,newfilename);
} else{
indir=theApp.glob_prefs->GetIncomingDir();
sprintf(newname,"%s\\%s",indir,newfilename);
}
// close permanent handle
if (m_hpartfile.m_hFile != INVALID_HANDLE_VALUE)
m_hpartfile.Close();
bool renamed = false;
if(PathFileExists(newname))
{
renamed = true;
int namecount = 0;
size_t length = strlen(newfilename);
ASSERT(length != 0); //name should never be 0
//the file extension
char *ext = strrchr(newfilename, '.');
if(ext == NULL)
ext = newfilename + length;
char *last = ext; //new end is the file name before extension
last[0] = 0; //truncate file name
//serch for matching ()s and check if it contains a number
if((ext != newfilename) && (strrchr(newfilename, ')') + 1 == last)) {
char *first = strrchr(newfilename, '(');
if(first != NULL) {
first++;
bool found = true;
for(char *step = first; step < last - 1; step++)
if(*step < '0' || *step > '9') {
found = false;
break;
}
if(found) {
namecount = atoi(first);
last = first - 1;
last[0] = 0; //truncate again
}
}
}
CString strTestName;
do {
namecount++;
strTestName.Format("%s\\%s(%d).%s", theApp.glob_prefs->GetIncomingDir(),
newfilename, namecount, min(ext + 1, newfilename + length));
} while(PathFileExists(strTestName));
delete[] newname;
newname = nstrdup(strTestName);
}
delete newfilename;
if (rename(partfilename,newname)){
delete[] partfilename;
delete[] newname;
if (this) theApp.emuledlg->AddLogLine(true,GetResString(IDS_ERR_COMPLETIONFAILED),GetFileName());
paused = true;
status = PS_ERROR;
theApp.downloadqueue->StartNextFile();
return FALSE;
}
if (remove(fullname))
theApp.emuledlg->AddLogLine(true,GetResString(IDS_ERR_DELETEFAILED),fullname);
CString BAKName(fullname);
BAKName.Append(".BAK");
if (::DeleteFile(BAKName) == 0)
theApp.emuledlg->AddLogLine(true,GetResString(IDS_ERR_DELETE), BAKName);
delete[] partfilename;
delete[] fullname;
fullname = newname;
delete[] directory;
directory = nstrdup(indir);
status = PS_COMPLETE;
paused = false;
theApp.emuledlg->AddLogLine(true,GetResString(IDS_DOWNLOADDONE),GetFileName());
theApp.emuledlg->ShowNotifier(GetResString(IDS_TBN_DOWNLOADDONE)+"\n"+GetFileName(), TBN_DLOAD);
if (renamed)
theApp.emuledlg->AddLogLine(true, GetResString(IDS_DOWNLOADRENAMED), strrchr(newname, '\\') + 1);
theApp.knownfiles->SafeAddKFile(this);
theApp.downloadqueue->RemoveFile(this);
//theApp.emuledlg->transferwnd.downloadlistctrl.UpdateItem(this);
UpdateDisplayedInfo();
theApp.emuledlg->transferwnd.downloadlistctrl.ShowFilesCount();
//SHAddToRecentDocs(SHARD_PATH, fullname); // This is a real nasty call that takes ~110 ms on my 1.4 GHz Athlon and isn't really needed afai see...[ozon]
// Barry - Just in case
// transfered = m_nFileSize;
theApp.downloadqueue->StartNextFile();
return TRUE;
}
void CPartFile::RemoveAllSources(bool bTryToSwap){
//TODO transfer sources to other downloading files if possible
POSITION pos1,pos2;
for (int sl=0;sl<SOURCESSLOTS;sl++) if (!srclists[sl].IsEmpty())
for( pos1 = srclists[sl].GetHeadPosition(); ( pos2 = pos1 ) != NULL; ){
srclists[sl].GetNext(pos1);
if (bTryToSwap){
if (!srclists[sl].GetAt(pos2)->SwapToAnotherFile(true))
theApp.downloadqueue->RemoveSource(srclists[sl].GetAt(pos2));
}
else
theApp.downloadqueue->RemoveSource(srclists[sl].GetAt(pos2));
}
UpdateFileRatingCommentAvail();
}
void CPartFile::DeleteFile(){
ASSERT ( !m_bPreviewing );
// Barry - Need to tell any connected clients to stop sending the file
StopFile();
theApp.sharedfiles->RemoveFile(this);
theApp.downloadqueue->RemoveFile(this);
theApp.emuledlg->transferwnd.downloadlistctrl.RemoveFile(this);
if (m_hpartfile.m_hFile != INVALID_HANDLE_VALUE)
m_hpartfile.Close();
if (remove(fullname))
theApp.emuledlg->AddLogLine(true,GetResString(IDS_ERR_DELETE),fullname);
char* partfilename = nstrdup(fullname);
partfilename[strlen(fullname)-4] = 0;
if (remove(partfilename))
theApp.emuledlg->AddLogLine(true,GetResString(IDS_ERR_DELETE),partfilename);
CString BAKName(fullname);
BAKName.Append(".BAK");
if (::DeleteFile(BAKName) == 0)
theApp.emuledlg->AddLogLine(true,GetResString(IDS_ERR_DELETE), BAKName);
delete[] partfilename;
delete this;
}
bool CPartFile::HashSinglePart(uint16 partnumber)
{
if ((GetHashCount() <= partnumber) && (GetPartCount() > 1)){
theApp.emuledlg->AddLogLine(true,GetResString(IDS_ERR_HASHERRORWARNING),GetFileName());
this->hashsetneeded = true;
return true;
}
else if(!GetPartHash(partnumber) && GetPartCount() != 1){
theApp.emuledlg->AddLogLine(true,GetResString(IDS_ERR_INCOMPLETEHASH),GetFileName());
this->hashsetneeded = true;
return true;
}
else{
uchar hashresult[16];
m_hpartfile.Seek((LONGLONG)PARTSIZE*partnumber,0);
uint32 length = PARTSIZE;
if (PARTSIZE*(partnumber+1) > m_hpartfile.GetLength())
length = (m_hpartfile.GetLength()- (PARTSIZE*partnumber));
CreateHashFromFile(&m_hpartfile,length,hashresult);
if (GetPartCount() > 1){
if (memcmp(hashresult,GetPartHash(partnumber),16))
return false;
else
return true;
}
else{
if (memcmp(hashresult,m_abyFileHash,16))
return false;
else
return true;
}
}
}
bool CPartFile::IsCorruptedPart(uint16 partnumber){
return corrupted_list.Find(partnumber);
}
bool CPartFile::IsMovie(){
//TODO use filetags instead ststr
CString extension = CString(GetFileName()).MakeLower();
int pos=extension.ReverseFind('.');
if (pos>=0) extension=extension.Mid(pos);
return (extension.CompareNoCase(".avi")==0 || extension.CompareNoCase(".mpg")==0 || extension.CompareNoCase(".mpeg")==0 || extension.CompareNoCase(".ogm")==0 || extension.CompareNoCase(".bin")==0);
}
// Barry - Also want to preview zip/rar files
bool CPartFile::IsArchive()
{
CString extension = CString(GetFileName()).Right(4);
return ((extension.CompareNoCase(".zip") == 0) || (extension.CompareNoCase(".rar") == 0));
}
void CPartFile::SetDownPriority(uint8 np){
m_iDownPriority = np;
UpdateDisplayedInfo(true);
SavePartFile();
}
void CPartFile::StopFile(){
// Barry - Need to tell any connected clients to stop sending the file
PauseFile();
RemoveAllSources(true);
paused = true;
stopped=true;
datarate = 0;
transferingsrc = 0;
FlushBuffer();
UpdateDisplayedInfo(true);
}
void CPartFile::PauseFile(){
if (status==PS_COMPLETE || status==PS_COMPLETING) return;
Packet* packet = new Packet(OP_CANCELTRANSFER,0);
POSITION pos1,pos2;
for (int sl=0;sl<SOURCESSLOTS;sl++) if (!srclists[sl].IsEmpty())
for( pos1 = srclists[sl].GetHeadPosition(); ( pos2 = pos1 ) != NULL; ){
srclists[sl].GetNext(pos1);
CUpDownClient* cur_src = srclists[sl].GetAt(pos2);
if (cur_src->GetDownloadState() == DS_DOWNLOADING){
theApp.uploadqueue->AddUpDataOverheadOther(packet->size);
cur_src->socket->SendPacket(packet,false,true);
cur_src->SetDownloadState(DS_ONQUEUE);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -