📄 knownfile.cpp
字号:
// parts of this file are based on work from pan One (http://home-3.tiscali.nl/~meost/pms/)
//this file is part of eMule
//Copyright (C)2002-2004 Merkur ( devs@emule-project.net / http://www.emule-project.net )
//
//This program 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.
//
//This program 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 this program; if not, write to the Free Software
//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include "stdafx.h"
#include <io.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <share.h>
#ifdef _DEBUG
#include "DebugHelpers.h"
#endif
#include "emule.h"
#include "KnownFile.h"
#include "KnownFileList.h"
#include "SharedFileList.h"
#include "UpDownClient.h"
#include "MMServer.h"
#include "ClientList.h"
#include "opcodes.h"
#include "ini2.h"
#define NOMD4MACROS
#include "kademlia/utils/md4.h"
#include "FrameGrabThread.h"
#include "CxImage/xImage.h"
#include "OtherFunctions.h"
#include "Preferences.h"
#include "PartFile.h"
#include "Packets.h"
#include "Kademlia/Kademlia/SearchManager.h"
#include "SafeFile.h"
#include "shahashset.h"
// id3lib
#include <id3/tag.h>
#include <id3/misc_support.h>
// DirectShow MediaDet
#include <strmif.h>
//#include <uuids.h>
#define _DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
EXTERN_C const GUID DECLSPEC_SELECTANY name \
= { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
_DEFINE_GUID(MEDIATYPE_Video, 0x73646976, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
_DEFINE_GUID(MEDIATYPE_Audio, 0x73647561, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
_DEFINE_GUID(FORMAT_VideoInfo,0x05589f80, 0xc356, 0x11ce, 0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a);
_DEFINE_GUID(FORMAT_WaveFormatEx,0x05589f81, 0xc356, 0x11ce, 0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a);
#include <qedit.h>
typedef struct tagVIDEOINFOHEADER {
RECT rcSource; // The bit we really want to use
RECT rcTarget; // Where the video should go
DWORD dwBitRate; // Approximate bit data rate
DWORD dwBitErrorRate; // Bit error rate for this stream
REFERENCE_TIME AvgTimePerFrame; // Average time per frame (100ns units)
BITMAPINFOHEADER bmiHeader;
} VIDEOINFOHEADER;
#include "emuledlg.h"
#include "SharedFilesWnd.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#define META_DATA_VER 1
void CFileStatistic::MergeFileStats( CFileStatistic *toMerge )
{
requested += toMerge->GetRequests();
accepted += toMerge->GetAccepts();
transferred += toMerge->GetTransferred();
alltimerequested += toMerge->GetAllTimeRequests();
alltimetransferred += toMerge->GetAllTimeTransferred();
alltimeaccepted += toMerge->GetAllTimeAccepts();
}
void CFileStatistic::AddRequest(){
requested++;
alltimerequested++;
theApp.knownfiles->requested++;
theApp.sharedfiles->UpdateFile(fileParent);
}
void CFileStatistic::AddAccepted(){
accepted++;
alltimeaccepted++;
theApp.knownfiles->accepted++;
theApp.sharedfiles->UpdateFile(fileParent);
}
void CFileStatistic::AddTransferred(uint64 bytes){
transferred += bytes;
alltimetransferred += bytes;
theApp.knownfiles->transferred += bytes;
theApp.sharedfiles->UpdateFile(fileParent);
}
IMPLEMENT_DYNAMIC(CAbstractFile, CObject)
CAbstractFile::CAbstractFile()
{
md4clr(m_abyFileHash);
m_nFileSize = 0;
m_uRating = 0;
}
#ifdef _DEBUG
void CAbstractFile::AssertValid() const
{
CObject::AssertValid();
(void)m_strFileName;
(void)m_abyFileHash[16];
(void)m_nFileSize;
(void)m_strComment;
(void)m_uRating;
(void)m_strFileType;
taglist.AssertValid();
}
void CAbstractFile::Dump(CDumpContext& dc) const
{
CObject::Dump(dc);
}
#endif
IMPLEMENT_DYNAMIC(CKnownFile, CAbstractFile)
CKnownFile::CKnownFile()
{
m_iPartCount = 0;
m_iED2KPartCount = 0;
m_iED2KPartHashCount = 0;
m_tUtcLastModified = 0;
if(thePrefs.GetNewAutoUp()){
m_iUpPriority = PR_HIGH;
m_bAutoUpPriority = true;
}
else{
m_iUpPriority = PR_NORMAL;
m_bAutoUpPriority = false;
}
statistic.fileParent = this;
m_bCommentLoaded = false;
(void)m_strComment;
m_PublishedED2K = false;
kadFileSearchID = 0;
m_PublishedKadSrc = 0;
m_lastPublishTimeKadSrc = 0;
m_nCompleteSourcesTime = time(NULL);
m_nCompleteSourcesCount = 1;
m_nCompleteSourcesCountLo = 1;
m_nCompleteSourcesCountHi = 1;
m_uMetaDataVer = 0;
m_pAICHHashSet = new CAICHHashSet(this);
}
CKnownFile::~CKnownFile()
{
for (int i = 0; i < hashlist.GetSize(); i++)
delete[] hashlist[i];
for (int i = 0; i < taglist.GetSize(); i++)
delete taglist[i];
delete m_pAICHHashSet;
}
#ifdef _DEBUG
void CKnownFile::AssertValid() const
{
CAbstractFile::AssertValid();
(void)m_tUtcLastModified;
(void)statistic;
(void)m_nCompleteSourcesTime;
(void)m_nCompleteSourcesCount;
(void)m_nCompleteSourcesCountLo;
(void)m_nCompleteSourcesCountHi;
m_ClientUploadList.AssertValid();
m_AvailPartFrequency.AssertValid();
hashlist.AssertValid();
(void)m_strDirectory;
(void)m_strFilePath;
CHECK_BOOL(m_bCommentLoaded);
(void)m_iPartCount;
(void)m_iED2KPartCount;
(void)m_iED2KPartHashCount;
ASSERT( m_iUpPriority == PR_VERYLOW || m_iUpPriority == PR_LOW || m_iUpPriority == PR_NORMAL || m_iUpPriority == PR_HIGH || m_iUpPriority == PR_VERYHIGH );
CHECK_BOOL(m_bAutoUpPriority);
(void)s_ShareStatusBar;
CHECK_BOOL(m_PublishedED2K);
(void)kadFileSearchID;
(void)m_lastPublishTimeKadSrc;
(void)m_PublishedKadSrc;
(void)wordlist;
}
void CKnownFile::Dump(CDumpContext& dc) const
{
CAbstractFile::Dump(dc);
}
#endif
CBarShader CKnownFile::s_ShareStatusBar(16);
void CKnownFile::DrawShareStatusBar(CDC* dc, LPCRECT rect, bool onlygreyrect, bool bFlat) const
{
const COLORREF crMissing = RGB(255, 0, 0);
s_ShareStatusBar.SetFileSize(GetFileSize());
s_ShareStatusBar.SetHeight(rect->bottom - rect->top);
s_ShareStatusBar.SetWidth(rect->right - rect->left);
s_ShareStatusBar.Fill(crMissing);
if (!onlygreyrect && !m_AvailPartFrequency.IsEmpty()) {
COLORREF crProgress;
COLORREF crHave;
COLORREF crPending;
if(bFlat) {
crProgress = RGB(0, 150, 0);
crHave = RGB(0, 0, 0);
crPending = RGB(255,208,0);
} else {
crProgress = RGB(0, 224, 0);
crHave = RGB(104, 104, 104);
crPending = RGB(255, 208, 0);
}
for (int i = 0; i < GetPartCount(); i++){
if(m_AvailPartFrequency[i] > 0 ){
COLORREF color = RGB(0, (210-(22*(m_AvailPartFrequency[i]-1)) < 0)? 0:210-(22*(m_AvailPartFrequency[i]-1)), 255);
s_ShareStatusBar.FillRange(PARTSIZE*(i),PARTSIZE*(i+1),color);
}
}
}
s_ShareStatusBar.Draw(dc, rect->left, rect->top, bFlat);
}
// SLUGFILLER: heapsortCompletesrc
static void HeapSort(CArray<uint16,uint16> &count, uint32 first, uint32 last){
uint32 r;
for ( r = first; !(r & 0x80000000) && (r<<1) < last; ){
uint32 r2 = (r<<1)+1;
if (r2 != last)
if (count[r2] < count[r2+1])
r2++;
if (count[r] < count[r2]){
uint16 t = count[r2];
count[r2] = count[r];
count[r] = t;
r = r2;
}
else
break;
}
}
// SLUGFILLER: heapsortCompletesrc
void CKnownFile::UpdatePartsInfo()
{
// Cache part count
uint16 partcount = GetPartCount();
bool flag = (time(NULL) - m_nCompleteSourcesTime > 0);
// Reset part counters
if(m_AvailPartFrequency.GetSize() < partcount)
m_AvailPartFrequency.SetSize(partcount);
for(int i = 0; i < partcount; i++)
m_AvailPartFrequency[i] = 1;
CArray<uint16, uint16> count;
if (flag)
count.SetSize(0, m_ClientUploadList.GetSize());
for (POSITION pos = m_ClientUploadList.GetHeadPosition(); pos != 0; )
{
CUpDownClient* cur_src = m_ClientUploadList.GetNext(pos);
//This could be a partfile that just completed.. Many of these clients will not have this information.
if(cur_src->m_abyUpPartStatus && cur_src->GetUpPartCount() == partcount )
{
for (uint16 i = 0; i < partcount; i++)
{
if (cur_src->IsUpPartAvailable(i))
m_AvailPartFrequency[i] += 1;
}
if ( flag )
count.Add(cur_src->GetUpCompleteSourcesCount());
}
}
if (flag)
{
m_nCompleteSourcesCount = m_nCompleteSourcesCountLo = m_nCompleteSourcesCountHi = 0;
if( partcount > 0)
m_nCompleteSourcesCount = m_AvailPartFrequency[0];
for (uint16 i = 1; i < partcount; i++)
{
if( m_nCompleteSourcesCount > m_AvailPartFrequency[i])
m_nCompleteSourcesCount = m_AvailPartFrequency[i];
}
count.Add(m_nCompleteSourcesCount);
int n = count.GetSize();
if (n > 0)
{
// SLUGFILLER: heapsortCompletesrc
int r;
for (r = n/2; r--; )
HeapSort(count, r, n-1);
for (r = n; --r; ){
uint16 t = count[r];
count[r] = count[0];
count[0] = t;
HeapSort(count, 0, r-1);
}
// SLUGFILLER: heapsortCompletesrc
// calculate range
int i = n >> 1; // (n / 2)
int j = (n * 3) >> 2; // (n * 3) / 4
int k = (n * 7) >> 3; // (n * 7) / 8
//For complete files, trust the people your uploading to more...
//For low guess and normal guess count
// If we see more sources then the guessed low and normal, use what we see.
// If we see less sources then the guessed low, adjust network accounts for 100%, we account for 0% with what we see and make sure we are still above the normal.
//For high guess
// Adjust 100% network and 0% what we see.
if (n < 20)
{
if ( count.GetAt(i) < m_nCompleteSourcesCount )
m_nCompleteSourcesCountLo = m_nCompleteSourcesCount;
else
m_nCompleteSourcesCountLo = count.GetAt(i);
m_nCompleteSourcesCount= m_nCompleteSourcesCountLo;
m_nCompleteSourcesCountHi= count.GetAt(j);
if( m_nCompleteSourcesCountHi < m_nCompleteSourcesCount )
m_nCompleteSourcesCountHi = m_nCompleteSourcesCount;
}
else
//Many sources..
//For low guess
// Use what we see.
//For normal guess
// Adjust network accounts for 100%, we account for 0% with what we see and make sure we are still above the low.
//For high guess
// Adjust network accounts for 100%, we account for 0% with what we see and make sure we are still above the normal.
{
m_nCompleteSourcesCountLo= m_nCompleteSourcesCount;
m_nCompleteSourcesCount= count.GetAt(j);
if( m_nCompleteSourcesCount < m_nCompleteSourcesCountLo )
m_nCompleteSourcesCount = m_nCompleteSourcesCountLo;
m_nCompleteSourcesCountHi= count.GetAt(k);
if( m_nCompleteSourcesCountHi < m_nCompleteSourcesCount )
m_nCompleteSourcesCountHi = m_nCompleteSourcesCount;
}
}
m_nCompleteSourcesTime = time(NULL) + (60);
}
if (theApp.emuledlg->sharedfileswnd->m_hWnd)
theApp.emuledlg->sharedfileswnd->sharedfilesctrl.UpdateFile(this);
}
void CKnownFile::AddUploadingClient(CUpDownClient* client){
POSITION pos = m_ClientUploadList.Find(client); // to be sure
if(pos == NULL){
m_ClientUploadList.AddTail(client);
UpdateAutoUpPriority();
}
}
void CKnownFile::RemoveUploadingClient(CUpDownClient* client){
POSITION pos = m_ClientUploadList.Find(client); // to be sure
if(pos != NULL){
m_ClientUploadList.RemoveAt(pos);
UpdateAutoUpPriority();
}
}
#ifdef _DEBUG
void Dump(const Kademlia::WordList& wordlist)
{
Kademlia::WordList::const_iterator it;
for (it = wordlist.begin(); it != wordlist.end(); it++)
{
const CStringW& rstrKeyword = *it;
TRACE(" %ls\n", rstrKeyword);
}
}
#endif
void CKnownFile::SetFileName(LPCTSTR pszFileName, bool bReplaceInvalidFileSystemChars)
{
CAbstractFile::SetFileName(pszFileName, bReplaceInvalidFileSystemChars);
wordlist.clear();
Kademlia::CSearchManager::getWords(GetFileName(), &wordlist);
}
void CKnownFile::SetPath(LPCTSTR path)
{
m_strDirectory = path;
}
void CKnownFile::SetFilePath(LPCTSTR pszFilePath)
{
m_strFilePath = pszFilePath;
}
bool CKnownFile::CreateFromFile(LPCTSTR in_directory, LPCTSTR in_filename, LPVOID pvProgressParam)
{
SetPath(in_directory);
SetFileName(in_filename);
// open file
CString strFilePath;
_tmakepath(strFilePath.GetBuffer(MAX_PATH), NULL, in_directory, in_filename, NULL);
strFilePath.ReleaseBuffer();
SetFilePath(strFilePath);
FILE* file = _tfsopen(strFilePath, _T("rbS"), _SH_DENYNO); // can not use _SH_DENYWR because we may access a completing part file
if (!file){
theApp.QueueLogLine(false, GetResString(IDS_ERR_FILEOPEN) + _T(" - %hs"), strFilePath, _T(""), strerror(errno));
return false;
}
// set filesize
if (_filelengthi64(file->_file)>=4294967296){
fclose(file);
return false; // not supported by network
}
SetFileSize(_filelength(file->_file));
// we are reading the file data later in 8K blocks, adjust the internal file stream buffer accordingly
setvbuf(file, NULL, _IOFBF, 1024*8*2);
m_AvailPartFrequency.SetSize(GetPartCount());
for (uint32 i = 0; i < GetPartCount();i++)
m_AvailPartFrequency[i] = 0;
// create hashset
uint32 togo = m_nFileSize;
for (uint16 hashcount = 0; togo >= PARTSIZE; ) {
uchar* newhash = new uchar[16];
CAICHHashTree* pBlockAICHHashTree = m_pAICHHashSet->m_pHashTree.FindHash(hashcount*PARTSIZE, PARTSIZE);
ASSERT( pBlockAICHHashTree != NULL );
CreateHashFromFile(file, PARTSIZE, newhash, pBlockAICHHashTree);
// SLUGFILLER: SafeHash - quick fallback
if (theApp.emuledlg==NULL || !theApp.emuledlg->IsRunning()){ // in case of shutdown while still hashing
fclose(file);
delete[] newhash;
return false;
}
hashlist.Add(newhash);
togo -= PARTSIZE;
hashcount++;
if (pvProgressParam && theApp.emuledlg && theApp.emuledlg->IsRunning()){
ASSERT( ((CKnownFile*)pvProgressParam)->IsKindOf(RUNTIME_CLASS(CKnownFile)) );
ASSERT( ((CKnownFile*)pvProgressParam)->GetFileSize() == GetFileSize() );
UINT uProgress = ((ULONGLONG)(GetFileSize() - togo) * 100) / GetFileSize();
ASSERT( uProgress <= 100 );
VERIFY( PostMessage(theApp.emuledlg->GetSafeHwnd(), TM_FILEOPPROGRESS, uProgress, (LPARAM)pvProgressParam) );
}
}
uchar* lasthash = new uchar[16];
md4clr(lasthash);
CAICHHashTree* pBlockAICHHashTree;
if (togo == 0)
pBlockAICHHashTree = NULL; // sha hashtree doesnt takes hash of 0-sized data
else{
pBlockAICHHashTree = m_pAICHHashSet->m_pHashTree.FindHash(hashcount*PARTSIZE, togo);
ASSERT( pBlockAICHHashTree != NULL );
}
CreateHashFromFile(file, togo, lasthash, pBlockAICHHashTree);
m_pAICHHashSet->ReCalculateHash(false);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -