www.pudn.com > GGBT.rar > CategoryFileDB.cpp


// CategoryFileDB.cpp: implementation of the CCategoryFileDB class. 
// 
////////////////////////////////////////////////////////////////////// 
 
#include "stdafx.h" 
#include "testbt.h" 
#include "CategoryFileDB.h" 
 
 
#include "BTFormat.h" 
#include "FileBase.h" 
#include "val.h" 
#include "FileDB.h" 
#include "download.h" 
 
#include "SetupRegister.h" 
 
#ifdef _DEBUG 
#undef THIS_FILE 
static char THIS_FILE[]=__FILE__; 
#define new DEBUG_NEW 
#endif 
 
 
#define LOLONG(x) ((ULONG) x) 
#define HILONG(x) ((ULONG) (x / 0x100000000)) 
#define MAKELONG64(x, y)((_int64) x * 0x100000000 | (ULONG)y) 
 
string m_strDBFileSection = "Database"; 
string m_strDBFileKey = "path"; 
////////////////////////////////////////////////////////////////////// 
// Construction/Destruction 
////////////////////////////////////////////////////////////////////// 
 
CCategoryFileDB::CCategoryFileDB() 
{ 
	m_bNoNotifications = false; 
	m_lDirectoryIDMax = 0; 
	m_pSetupRegister = 0; 
	m_bModified = false; 
} 
 
CCategoryFileDB::~CCategoryFileDB() 
{ 
 
} 
 
BOOL CCategoryFileDB::CreateEx(CWnd *pParent, CRect &rc, long lParam, CSetupRegister* pSetupRegister) 
{ 
	m_pSetupRegister = pSetupRegister; 
	// SetDBSavePath(m_pSetupRegister); 
 
	return Create(WS_VISIBLE|WS_CHILD|WS_BORDER|TVS_HASBUTTONS | TVS_LINESATROOT | TVS_HASLINES|TVS_SHOWSELALWAYS,  
		rc, pParent, 32563215); 
} 
 
 
 
void CCategoryFileDB::DeleteAllData(CTreeCursor& curDel)  
{ 
	assert(false); 
} 
 
CSetupRegister* CCategoryFileDB::GetSetupRegister() const 
{ 
	assert(m_pSetupRegister); 
	return m_pSetupRegister; 
} 
 
/* 
bool CCategoryFileDB::IsLinkFileDBItem(CTreeCursor curItem, CFileDBItem* pFileDBItem) 
{ 
	if (curItem != m_curDownloading) 
		return false; 
 
	CCategoryDBItem* pCategoryDBItem = (CCategoryDBItem*)m_curDownloading.GetData(); 
	if (pCategoryDBItem->m_lDirectoryID == pFileDBItem->m_lDirectoryID) 
		return false; 
 
	return true; 
} 
//*/ 
 
//////////////////////////////////////////////////////////////////////// 
// file manipulate. 
 
bool CCategoryFileDB::OpenDBFile(string strDatabasePath) 
{ 
	if (strDatabasePath.empty()) 
		return false; 
 
	// assert(!m_bModified); 
	m_bModified = false; 
	// clear data loaded from db file 
	DeleteAllData(GetRootItem()); 
	GetRootItem().Delete();	 
	m_curRoot = m_curDownloading = m_curDownloaded = m_curRecycle = CTreeCursor(); 
 
	if (!LoadDatabase(strDatabasePath)) 
	{ 
		AfxMessageBox(CString("load db file(") + strDatabasePath.data() + ")error" ); 
		NewDatabase(); 
		return false; 
	} 
 
	GetRootItem().Select(); 
	AfxGetApp()->WriteProfileString(m_strDBFileSection.data(), m_strDBFileKey.data(), strDatabasePath.data());	 
	m_strDatabaseFileName = strDatabasePath; 
	return false; 
} 
 
void CCategoryFileDB::LoadDBFile() 
{ 
	CString strDatabasePath = AfxGetApp()->GetProfileString(m_strDBFileSection.data(), m_strDBFileKey.data()); 
	if (!strDatabasePath.IsEmpty()) 
	{ 
		if (LoadDatabase(strDatabasePath.GetBuffer(0))) 
		{ 
			m_strDatabaseFileName = strDatabasePath; 
			return; 
		} 
		else 
		{ 
			AfxMessageBox(CString("load db file(") + strDatabasePath + ")error"); 
		} 
	} 
	 
	// load default database left by the uninstalled, create new database, register it. 
	strDatabasePath = GetDefaultDatabasePath().data(); 
	if (!LoadDatabase(strDatabasePath.GetBuffer(0))) 
	{ 
		NewDatabase(); 
		SaveDatabase(strDatabasePath.GetBuffer(0)); 
	} 
	 
	AfxGetApp()->WriteProfileString(m_strDBFileSection.data(), m_strDBFileKey.data(), strDatabasePath); 
	m_strDatabaseFileName = strDatabasePath; 
} 
 
void CCategoryFileDB::NewDatabase() 
{ 
	m_bModified = true; 
 
	// clear data loaded from db file 
	DeleteAllData(GetRootItem()); 
	GetRootItem().Delete();	 
	m_curRoot = m_curDownloading = m_curDownloaded = m_curRecycle = CTreeCursor(); 
	 
	// create default dir. 
	m_lDirectoryIDMax = 0; 
 
	m_curRoot = GetRootItem().AddTail("根目录", IID_ROOT); 
	m_curRoot.SetData((long) new CCategoryDBItem("c:\\download", m_lDirectoryIDMax++)); 
	 
	m_curDownloading = m_curRoot.AddTail("未完成任务", IID_DOWNLOADING_DIRECTORY); 
	m_curDownloading.SetData((long) new CCategoryDBItem("c:\\download\\downloading", m_lDirectoryIDMax++)); 
	 
	m_curDownloaded = m_curRoot.AddTail("下载保存目录", IID_DOWNLOADED_DIRECTORY); 
	m_curDownloaded.SetData((long) new CCategoryDBItem("c:\\download\\downloaded", m_lDirectoryIDMax++)); 
 
	CTreeCursor curMusic = m_curDownloaded.AddTail("音乐", IID_DIRECTORY); 
	curMusic.SetData((long) new CCategoryDBItem("c:\\download\\downloaded\\music", m_lDirectoryIDMax++)); 
	 
	CTreeCursor cuMovie = m_curDownloaded.AddTail("影视", IID_DIRECTORY); 
	cuMovie.SetData((long) new CCategoryDBItem("c:\\download\\downloaded\\Movie", m_lDirectoryIDMax++)); 
 
	CTreeCursor cuSoftware = m_curDownloaded.AddTail("软件", IID_DIRECTORY); 
	cuSoftware.SetData((long) new CCategoryDBItem("c:\\download\\downloaded\\SoftWare", m_lDirectoryIDMax++)); 
	 
	m_curRecycle = m_curRoot.AddTail("回收站", IID_RECYCLE); 
	m_curRecycle.SetData((long) new CCategoryDBItem("c:\\download\\recycle", m_lDirectoryIDMax++)); 
 
	assert(m_curRoot == GetRootItem() != 0); 
 
	// m_strDatabaseFileName = "Untitled"; 
} 
 
void CCategoryFileDB::SaveAs(string strDatabasePath) 
{ 
	if (strDatabasePath.empty()) 
	{ 
		assert(false); 
		return; 
	} 
	if (m_strDatabaseFileName == strDatabasePath) 
		return; 
	 
	string strOldTorrentDir = _GetDBSavePath(m_strDatabaseFileName), 
		strNewTorrentDir = _GetDBSavePath(strDatabasePath); 
 
	SaveDatabase(strDatabasePath); 
	AfxGetApp()->WriteProfileString(m_strDBFileSection.data(), m_strDBFileKey.data(), strDatabasePath.data()); 
	m_strDatabaseFileName = strDatabasePath; 
 
	 
 
	DWORD dwAttr = GetFileAttributes(strNewTorrentDir.data()); 
	if (dwAttr == 0xffffffff ) 
	{ 
		if (!MakeDirecotry(strNewTorrentDir)) 
		{ 
			AfxMessageBox(CString("can't create direcotry (") + strNewTorrentDir.data() + ")" ); 
			return ; 
		} 
	} 
	else if (!(dwAttr & FILE_ATTRIBUTE_DIRECTORY)) 
	{ 
		AfxMessageBox(CString("can't create direcotry (") + strNewTorrentDir.data() + ")" ); 
		return ; 
	} 
 
	if (strOldTorrentDir != strNewTorrentDir) 
	{ 
		if (!MoveDiretory(strOldTorrentDir, strNewTorrentDir)) 
		{ 
			AfxMessageBox(CString("move from (") + strOldTorrentDir.data() + ") to (" + strNewTorrentDir.data() + ") error." ); 
			return ; 
		} 
	} 
} 
 
void CCategoryFileDB::Save() 
{ 
	if (m_bModified) 
	{ 
		assert(false); 
		return; 
	} 
 
	CString strDatabasePath = AfxGetApp()->GetProfileString(m_strDBFileSection.data(), m_strDBFileKey.data()); 
	if (strDatabasePath.IsEmpty()) 
	{ 
		assert(false); 
		return; 
	} 
	SaveDatabase(strDatabasePath.GetBuffer(0));	 
} 
 
bool CCategoryFileDB::IsModifyed() 
{ 
	return m_bModified; 
} 
 
void CCategoryFileDB::SetModifed(bool bModified) 
{ 
	m_bModified = bModified; 
} 
 
 
string CCategoryFileDB::GetDBSavePath() const 
{ 
	if (m_strDatabaseFileName.empty()) 
	{ 
		assert(false); 
	} 
 
	string strSavePath = _GetDBSavePath(m_strDatabaseFileName); 
	return strSavePath; 
	/* 
	string strName; 
	string strSavePath; 
	bool bRet = SplitPathName(m_strDatabaseFileName, strSavePath, strName);		 
	assert(bRet && strSavePath.empty()); 
 
	strSavePath = formatDir(strSavePath) + "Torrent Files\\"; 
 
	return strSavePath; 
	//*/ 
} 
 
string CCategoryFileDB::_GetDBSavePath(const string strDatabaseFileName) const 
{ 
	string strName; 
	string strSavePath; 
	bool bRet = SplitPathName(strDatabaseFileName, strSavePath, strName);		 
	assert(bRet && !strSavePath.empty()); 
 
	strSavePath = formatDir(strSavePath) + "Torrent Files\\"; 
 
	return strSavePath; 
} 
 
string CCategoryFileDB::GetDatabaseFullPath() 
{ 
	return m_strDatabaseFileName; 
} 
 
string CCategoryFileDB::GetDatabaseName() 
{	 
	if (IsModifyed()) 
		return "无标题"; 
 
	string strName; 
	string strSavePath; 
	SplitPathName(m_strDatabaseFileName, strSavePath, strName); 
 
	if (strName.empty()) 
		strName = "无标题"; 
 
	return strName; 
} 
 
string CCategoryFileDB::GetDefaultDatabasePath() 
{ 
	// get the directory in which the exe file exist. 
	char szModuleFileName[1024] = {0}; 
	if (!GetModuleFileName(AfxGetApp()->m_hInstance, szModuleFileName, 1024))		 
	{ 
		assert(false); 
		return ""; 
	} 
 
	char path_buffer[_MAX_PATH]; 
	char drive[_MAX_DRIVE]; 
	char dir[_MAX_DIR]; 
	char fname[_MAX_FNAME]; 
	char ext[_MAX_EXT];		 
	 
	_splitpath(szModuleFileName, drive, dir, fname, ext ); 
	_makepath(path_buffer, drive, dir, 0, 0); 
	string strDatabasePath = path_buffer; 
	if (strDatabasePath.size() <= 0) 
	{ 
		assert(false); 
		return ""; 
	} 
	 
	if (strDatabasePath[strDatabasePath.size() - 1] != '\\') 
		strDatabasePath+= '\\'; 
	 
	strDatabasePath += "default.bt"; 
 
	return strDatabasePath; 
} 
//////////////////////////////////////////////////////////////////////// 
// file db save. 
 
void CCategoryFileDB::SaveDatabase(string strDatabasePath) 
{ 
	m_bModified = false; 
 
	try 
	{ 
		CVal* pRet = bencode_rec(m_curRoot); 
		if (!pRet)  
		{ 
			AfxMessageBox("encode tree data error"); 
			return; 
		} 
 
		auto_ptr aRet(pRet); 
		CFileDB::WriteFileEx(strDatabasePath, pRet); 
	} 
	catch (string e) 
	{ 
		AfxMessageBox((string("SaveDatabase error : ") + e).data()); 
	} 
} 
 
CVal* CCategoryFileDB::bencode_FileDBItems(vector& vFileDbItems) 
{ 
	// format data 
	PVALLIST pFileList = new VALLIST(); 
 
	for (int i=0; im_strTorrentFileName); 
		(*pFileInfoMap)["filename"] = new CVal(pItem->m_strFileName); 
		(*pFileInfoMap)["complete"] = new CVal((long)(((float)pItem->m_fComplete)*100)); 
		(*pFileInfoMap)["time"] = new CVal(pItem->m_tTime); 
		(*pFileInfoMap)["infohash"] = new CVal(pItem->m_strHash); 
		(*pFileInfoMap)["dirid"] = new CVal(pItem->m_lDirectoryID); 
		(*pFileInfoMap)["ModifiedTime"] = new CVal(pItem->m_tModifiedTime); 
		(*pFileInfoMap)["PieceCount"] = new CVal(pItem->m_lPieceCount); 
 
		(*pFileInfoMap)["special"] = new CVal(pItem->m_bSpecialRunParameter ? 1L : 0L); 
		(*pFileInfoMap)["SpeedMode"] = new CVal(pItem->m_lUploadSpeedMode); 
		(*pFileInfoMap)["UpMaxSpeed"] = new CVal(pItem->m_lUploadSpeedMax); 
		(*pFileInfoMap)["UpMaxpeers"] = new CVal(pItem->m_lUploadPeerMax); 
		(*pFileInfoMap)["fc"] = new CVal((long)(((float)pItem->m_fCompletePart)*100)); 
 
		(*pFileInfoMap)["kpHour"] = new CVal(pItem->m_lCompleteKeepSeedHour); 
		(*pFileInfoMap)["PeersMin"] = new CVal(pItem->m_lPeersMin); 
		(*pFileInfoMap)["PeersMax"] = new CVal(pItem->m_lPeersMax); 
		(*pFileInfoMap)["errMax"] = new CVal(pItem->m_lConnectErrorMax); 
		(*pFileInfoMap)["ConIntval"] = new CVal(pItem->m_lConnectIntval);		 
 
 
		// 
		// file size. 
		// 
		ASSERT(pItem->m_lFileSize >= 0); 
 
		(*pFileInfoMap)["size"] = new CVal(LOLONG(pItem->m_lFileSize)); 
 
		if (HILONG(pItem->m_lFileSize)) 
			(*pFileInfoMap)["sizeh"] = new CVal(HILONG(pItem->m_lFileSize)); 
 
		 
		if (!pItem->m_strComment.empty()) 
			(*pFileInfoMap)["comment"] = new CVal(pItem->m_strComment); 
		 
		 
 
		// UnneededFiles. 
		if (!pItem->m_vUnneededFileInx.empty()) 
			(*pFileInfoMap)["UnNeed"] = bencode_UnNeededFiles(pItem->m_vUnneededFileInx); 
 
		// mark the unclosed. 
		if (pItem->m_bUnclosed)// && pItem->m_pDownload->IsDownloading()) 
			(*pFileInfoMap)["Unclosed"] = new CVal(1); 
 
		memstream memBuf; 
		pItem->GetHave(memBuf); 
		if (memBuf.size()) 
		{ 
			(*pFileInfoMap)["haves"] = new CVal(memBuf, memBuf.size()); 
		} 
 
		pFileList->push_back(new CVal(pFileInfoMap)); 
	} 
 
	CVal* pVal = new CVal(pFileList); 
	return pVal; 
} 
 
CVal* CCategoryFileDB::bencode_UnNeededFiles(vector& vUnNeededFiles) 
{ 
	// format data 
	PVALLIST pFileList = new VALLIST(); 
	 
	for (int i=0; ipush_back(new CVal(pFileInfoMap)); 
	} 
	 
	CVal* pVal = new CVal(pFileList); 
	return pVal; 
} 
 
 
CVal* CCategoryFileDB::bencode_rec(CTreeCursor& curItem) 
{ 
	if (!curItem) 
	{ 
		assert(curItem); 
		return 0; 
	} 
 
	PVALLIST pChildList = new VALLIST(); 
	if (curItem.HasChildren()) 
	{ 
		CTreeCursor curChild = curItem.GetChild(); 
		while (curChild) 
		{ 
			CVal* pRet = bencode_rec(curChild); 
			pChildList->push_back(pRet); 
			curChild = curChild.GetNext(TVGN_NEXT); 
		} 
	} 
 
	CCategoryDBItem* pItem = (CCategoryDBItem*)curItem.GetData(); 
 
	PVALMAP pDirInfoMap = new VALMAP(); 
	(*pDirInfoMap)["dirname"] = new CVal(string(curItem.GetText())); 
	(*pDirInfoMap)["directory"] = new CVal(pItem->m_strDefaultDirectory); 
	(*pDirInfoMap)["childlist"] = new CVal(pChildList); 
	(*pDirInfoMap)["type"] = new CVal((long)curItem.GetImageID()); 
	(*pDirInfoMap)["id"] = new CVal(pItem->m_lDirectoryID); 
	(*pDirInfoMap)["filedbitems"] = bencode_FileDBItems(pItem->m_vFileDBItems); 
 
	CVal* pRetVal = new CVal(pDirInfoMap); 
	return pRetVal; 
} 
 
//////////////////////////////////////////////////////////////////////// 
// file db load. 
 
bool CCategoryFileDB::LoadDatabase(string strDatabasePath) 
{ 
	m_bNoNotifications = true; 
 
	string strErr; 
	bool bRet = true; 
	try 
	{ 
		CVal* pVal = CFileDB::OpenFileEx(strDatabasePath); 
		auto_ptr aVal(pVal); 
		if (pVal && bdencode_rec(pVal, GetRootItem())) 
			bRet = true; 
		else  
		{ 
			m_bNoNotifications = false; 
			return false; 
		} 
 
		/* 
		if (!LoadGenerateLinks()) 
			bRet = false; 
		//*/ 
 
		m_bNoNotifications = false; 
	} 
	catch (string e) 
	{ 
		strErr = e; 
		bRet = false; 
		m_bNoNotifications = false; 
	} 
	 
	if (!bRet || !m_curRoot || !m_curDownloading || !m_curDownloaded || !m_curRecycle) 
	{		 
		m_bNoNotifications = true; 
		DeleteAllData(GetRootItem()); 
		GetRootItem().Delete(); 
		m_curRoot = m_curDownloading = m_curDownloaded = m_curRecycle = CTreeCursor(); 
		m_bNoNotifications = false; 
		return false; 
	} 
 
	return true; 
} 
 
bool CCategoryFileDB::bdencode_FileDBItems(CVal* pVal, vector& vFileDbItems, HTREEITEM hTreeItem) 
{ 
	if (pVal->vt != VT_PLIST) 
		return false; 
	VALLIST& FileList = *(pVal->plistVal); 
 
	for (int i=0; ivt != VT_PMAP)	 
			return false; 
		PVALMAP pFileInfoMap = FileList[i]->pmapVal;  
 
		if (!HasKey(pFileInfoMap, "TFileName") || 
			!HasKey(pFileInfoMap, "filename") ||  
			!HasKey(pFileInfoMap, "size") || 
			!HasKey(pFileInfoMap, "complete") || 
			!HasKey(pFileInfoMap, "time") || 
			!HasKey(pFileInfoMap, "infohash") || 
			!HasKey(pFileInfoMap, "dirid") || 
			!HasKey(pFileInfoMap, "ModifiedTime") || 
			!HasKey(pFileInfoMap, "PieceCount")  
			) 
		return false; 
 
		 
 
		// 
		// filesize. 
		// 
		long lFileSizeLow = (*pFileInfoMap)["size"]->lVal; 
		long lFileSizeHigh = 0; 
 
		if (HasKey(pFileInfoMap, "sizeh")) 
			lFileSizeHigh = (*pFileInfoMap)["sizeh"]->lVal; 
		 
		BLONG lFileSize = MAKELONG64(lFileSizeHigh, lFileSizeLow); 
 
		// 
		// comment 
		// 
		string strComment; 
		if (HasKey(pFileInfoMap, "comment")) 
		{ 
			strComment = (*pFileInfoMap)["comment"]->pstrVal; 
		} 
		 
		CFileDBItem * pFileDBItem = new CFileDBItem((*pFileInfoMap)["TFileName"]->pstrVal,  
													(*pFileInfoMap)["filename"]->pstrVal, 
													lFileSize, 
													((float)(*pFileInfoMap)["complete"]->lVal)/100, 
													(*pFileInfoMap)["time"]->lVal, 
													(*pFileInfoMap)["infohash"]->pstrVal, 
													(*pFileInfoMap)["dirid"]->lVal, 
													(*pFileInfoMap)["ModifiedTime"]->lVal, 
													(*pFileInfoMap)["PieceCount"]->lVal, 
													strComment); 
 
		if (HasKey(pFileInfoMap, "special") && 
			HasKey(pFileInfoMap, "SpeedMode") && 
			HasKey(pFileInfoMap, "UpMaxSpeed") && 
			HasKey(pFileInfoMap, "UpMaxpeers")) 
		{ 
			pFileDBItem->m_bSpecialRunParameter = (*pFileInfoMap)["special"]->lVal > 0; 
			pFileDBItem->m_lUploadSpeedMode = (*pFileInfoMap)["SpeedMode"]->lVal; 
			pFileDBItem->m_lUploadSpeedMax = (*pFileInfoMap)["UpMaxSpeed"]->lVal; 
			pFileDBItem->m_lUploadPeerMax = (*pFileInfoMap)["UpMaxpeers"]->lVal; 
 
			if ( 
				!HasKey(pFileInfoMap, "kpHour") || 
				!HasKey(pFileInfoMap, "PeersMin") || 
				!HasKey(pFileInfoMap, "PeersMax") || 
				!HasKey(pFileInfoMap, "errMax") || 
				!HasKey(pFileInfoMap, "ConIntval") 
				) 
			{ 
				return false; 
			} 
			 
			pFileDBItem->m_lCompleteKeepSeedHour = (*pFileInfoMap)["kpHour"]->lVal; 
			pFileDBItem->m_lPeersMin = (*pFileInfoMap)["PeersMin"]->lVal; 
			pFileDBItem->m_lPeersMax = (*pFileInfoMap)["PeersMax"]->lVal; 
			pFileDBItem->m_lConnectErrorMax = (*pFileInfoMap)["errMax"]->lVal; 
			pFileDBItem->m_lConnectIntval = (*pFileInfoMap)["ConIntval"]->lVal; 
		} 
 
		// UnNeedFiles. 
		if (HasKey(pFileInfoMap, "UnNeed")) 
		{ 
			if (!bdencode_UnNeedFiles((*pFileInfoMap)["UnNeed"], pFileDBItem->m_vUnneededFileInx)) 
				return false; 
		} 
		if (HasKey(pFileInfoMap, "fc")) 
			pFileDBItem->m_fCompletePart = ((float)(*pFileInfoMap)["fc"]->lVal)/100; 
		 
		if (HasKey(pFileInfoMap, "haves")) 
		{ 
			assert((pFileDBItem->m_fComplete < 1) || pFileDBItem->m_fComplete != 0); 
 
			memstream memBuf; 
			memBuf.write((*pFileInfoMap)["haves"]->pstrVal, (*pFileInfoMap)["haves"]->lstrLen); 
			pFileDBItem->SetHave(memBuf); 
		} 
		 
		// mark the unclosed. 
		if (HasKey(pFileInfoMap, "Unclosed")) 
			m_vUncloseds.push_back(CUnclosed(pFileDBItem, hTreeItem)); 
 
		vFileDbItems.push_back(pFileDBItem); 
	} 
 
	return true; 
} 
 
bool CCategoryFileDB::bdencode_UnNeedFiles(CVal* pVal, vector& vFileDbItems) 
{ 
	if (pVal->vt != VT_PLIST) 
		return false; 
 
	VALLIST& FileList = *(pVal->plistVal); 
 
	for (int i=0; ivt != VT_PMAP)	 
			return false; 
 
		PVALMAP pFileInfoMap = FileList[i]->pmapVal;  
 
		if (!HasKey(pFileInfoMap, "x") || !HasKey(pFileInfoMap, "y")) 
			return false; 
 
		 
		CSize size((*pFileInfoMap)["x"]->lVal, (*pFileInfoMap)["y"]->lVal); 
 
		vFileDbItems.push_back(size); 
	} 
	return true; 
} 
 
bool CCategoryFileDB::bdencode_rec(CVal* pVal, CTreeCursor& curItem) 
{ 
	// check type. 
	if (pVal->vt != VT_PMAP) 
		return false; 
 
	if (!HasKey(pVal->pmapVal, "dirname") || 
		!HasKey(pVal->pmapVal, "directory") ||  
		!HasKey(pVal->pmapVal, "childlist") || 
		!HasKey(pVal->pmapVal, "type") || 
		!HasKey(pVal->pmapVal, "filedbitems")|| 
		!HasKey(pVal->pmapVal, "id")) 
		return false; 
 
	if ((*pVal)["dirname"]->vt != VT_PSTR ||  
		(*pVal)["directory"]->vt != VT_PSTR || 
		(*pVal)["childlist"]->vt != VT_PLIST || 
		(*pVal)["type"]->vt != VT_LONG || 
		(*pVal)["filedbitems"]->vt != VT_PLIST || 
		(*pVal)["id"]->vt != VT_LONG) 
		return false; 
 
	// ltype is imageid, default item has identity imageid, others must be IID_DIRECTORY. 
	long lType = (*pVal)["type"]->lVal; 
	assert(lType >= IID_ROOT && lType <= IID_DIRECTORY); 
 
	long lDirectoryId = (*pVal)["id"]->lVal; 
	if (lDirectoryId >= m_lDirectoryIDMax) 
		m_lDirectoryIDMax = lDirectoryId + 1; 
 
	// fill the data.*** 
	CTreeCursor curNew = curItem.AddTail((*pVal)["dirname"]->pstrVal, lType); 
	CCategoryDBItem* pDBItem = new CCategoryDBItem((*pVal)["directory"]->pstrVal, lDirectoryId); 
	curNew.SetData((long)pDBItem); 
	if (!bdencode_FileDBItems((*pVal)["filedbitems"], pDBItem->m_vFileDBItems, curNew)) 
		return false; 
 
	// check whether the default items exist, if not the db file corrupted. 
	switch (lType) 
	{ 
	case IID_ROOT: 
		if (m_curRoot) 
			return false; 
		else 
		{ 
			m_curRoot = curNew; 
			m_curRoot.SetText("根目录"); 
		} 
		break; 
 
	case IID_DOWNLOADED_DIRECTORY: 
		if (m_curDownloaded) 
			return false; 
		else 
		{ 
			m_curDownloaded = curNew; 
			m_curDownloaded.SetText("下载保存目录"); 
		} 
		break; 
 
	case IID_DOWNLOADING_DIRECTORY: 
		if (m_curDownloading) 
			return false; 
		else 
		{ 
			m_curDownloading = curNew; 
			m_curDownloading.SetText("未完成任务"); 
		} 
		break; 
 
	case IID_RECYCLE: 
		if (m_curRecycle) 
			return false; 
		else 
		{ 
			m_curRecycle = curNew; 
			m_curRecycle.SetText("回收站"); 
		} 
		break; 
 
	case IID_DIRECTORY: 
		break; 
 
	default: 
			return false; 
		break; 
	} 
 
	// recurse into childs. 
	VALLIST& ChildList = *(*pVal)["childlist"]->plistVal; 
	for (int i=0; im_lDirectoryID); 
	CCategoryDBItem* pTrueCategory = (CCategoryDBItem*)curTrueCategory.GetData(); 
	assert(curTrueCategory && pTrueCategory); 
	 
	for (int i=0; im_vFileDBItems.size(); i++) 
	{ 
		if (pTrueCategory->m_vFileDBItems[i]->m_strHash == pLinkFileDBItem->m_strHash) 
		{ 
			return pTrueCategory->m_vFileDBItems[i]; 
		} 
	} 
 
	return 0; 
} 
 
bool CCategoryFileDB::LoadGenerateLinks() 
{ 
	CCategoryDBItem* pItem = (CCategoryDBItem*)m_curDownloading.GetData(); 
	assert(pItem && m_curDownloading); 
 
	bool bRet = true; 
	for (int i=0; im_vFileDBItems.size(); i++) 
	{ 
		if (IsLinkFileDBItem(m_curDownloading, pItem->m_vFileDBItems[i])) 
		{ 
			// get true FileDBItem.can't return. continue release mem. otherwise destroy wnd not release the mem.			 
			assert(!pItem->m_vFileDBItems[i]->m_pDownload); 
			CFileDBItem* pTrueFileDBItem = GetLinkTrueFileDBItem(pItem->m_vFileDBItems[i]); 
			if (!pTrueFileDBItem) 
			{ 
				assert(pTrueFileDBItem); 
				bRet = false; 
			} 
 
			delete pItem->m_vFileDBItems[i]; 
			pItem->m_vFileDBItems[i] = pTrueFileDBItem; 
		} 
	} 
 
	return bRet; 
} 
//*/ 
 
CTreeCursor CCategoryFileDB::findCursorByDirid(long lDirectoryID) 
{ 
	return findCursorByDiridRec(GetRootItem(), lDirectoryID); 
} 
 
CTreeCursor CCategoryFileDB::findCursorByDiridRec(CTreeCursor curItem, long lDirectoryID) 
{	 
	CCategoryDBItem* pItem = (CCategoryDBItem*)curItem.GetData(); 
 
	if (pItem->m_lDirectoryID == lDirectoryID) 
		return curItem; 
	 
	if (curItem.HasChildren()) 
	{ 
		CTreeCursor curChild = curItem.GetChild(); 
		while (curChild) 
		{ 
			CTreeCursor curRet = findCursorByDiridRec(curChild, lDirectoryID); 
			if (curRet)  
			{ 
				return curRet; 
			} 
			curChild = curChild.GetNext(TVGN_NEXT); 
		} 
	} 
 
	return CTreeCursor(0, 0); 
} 
 
 
/* 
void CCategoryFileDB::SetDBSavePath(CSetupRegister* pSetupRegister) 
{ 
	assert(pSetupRegister); 
	m_strDBSavePath = pSetupRegister->m_strTorrentDir; 
} 
string CCategoryFileDB::GetDBSavePath() const 
{ 
	assert(!m_strDBSavePath.empty()); 
	return formatDir(m_strDBSavePath); 
} 
//*/