www.pudn.com > DCPlusPlus-src.zip > DirectoryListing.cpp
/*
* Copyright (C) 2001-2004 Jacek Sieka, j_s at telia com
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "stdinc.h"
#include "DCPlusPlus.h"
#include "DirectoryListing.h"
#include "QueueManager.h"
#include "SearchManager.h"
#include "StringTokenizer.h"
#include "ADLSearch.h"
#include "SimpleXML.h"
#include "FilteredFile.h"
#include "BZUtils.h"
#include "CryptoManager.h"
void DirectoryListing::loadFile(const string& name, bool doAdl) {
string txt;
// For now, we detect type by ending...
string ext = Util::getFileExt(name);
if(Util::stricmp(ext, ".DcLst") == 0) {
size_t len = (size_t)::File::getSize(name);
AutoArray buf(len);
::File(name, ::File::READ, ::File::OPEN).read(buf, len);
CryptoManager::getInstance()->decodeHuffman(buf, txt, len);
load(txt, doAdl);
} else if(Util::stricmp(ext, ".bz2") == 0) {
::File ff(name, ::File::READ, ::File::OPEN);
FilteredInputStream f(&ff);
const size_t BUF_SIZE = 64*1024;
char buf[BUF_SIZE];
size_t len;
for(;;) {
size_t n = BUF_SIZE;
len = f.read(buf, n);
txt.append(buf, len);
if(len < BUF_SIZE)
break;
}
loadXML(txt, doAdl);
}
}
void DirectoryListing::load(const string& in, bool doAdl) {
StringTokenizer t(in, '\n');
StringList& tokens = t.getTokens();
string::size_type indent = 0;
// Prepare ADLSearch manager
ADLSearchManager* pADLSearch = ADLSearchManager::getInstance();
ADLSearchManager::DestDirList destDirs;
StringMap params;
if(doAdl) {
params["nick"] = getUser()->getNick();
pADLSearch->setUser(getUser());
pADLSearch->PrepareDestinationDirectories(destDirs, root, params);
pADLSearch->setBreakOnFirst(BOOLSETTING(ADLS_BREAK_ON_FIRST));
}
Directory* cur = root;
string fullPath;
for(StringIter i = tokens.begin(); i != tokens.end(); ++i)
{
string& tok = *i;
string::size_type j = tok.find_first_not_of('\t');
if(j == string::npos) {
break;
}
while(j < indent) {
// Wind up directory structure
cur = cur->getParent();
dcassert(cur != NULL);
indent--;
string::size_type l = fullPath.find_last_of('\\');
if(l != string::npos) {
fullPath.erase(fullPath.begin() + l, fullPath.end());
}
if(doAdl)
pADLSearch->StepUpDirectory(destDirs);
}
string::size_type k = tok.find('|', j);
if(k != string::npos) {
// this must be a file...
cur->files.push_back(new File(cur, tok.substr(j, k-j), Util::toInt64(tok.substr(k+1))));
// ADLSearch
if(doAdl)
pADLSearch->MatchesFile(destDirs, cur->files.back(), fullPath);
} else {
// A directory
string name = tok.substr(j, tok.length()-j-1);
fullPath += '\\';
fullPath += name;
Directory::Iter di = ::find(cur->directories.begin(), cur->directories.end(), name);
if(di != cur->directories.end()) {
cur = *di;
} else {
Directory* d = new Directory(cur, name);
cur->directories.push_back(d);
cur = d;
}
if(doAdl)
pADLSearch->MatchesDirectory(destDirs, cur, fullPath);
indent++;
}
}
// Finalize ADLSearch manager
if(doAdl)
pADLSearch->FinalizeDestinationDirectories(destDirs, root);
}
class ListLoader : public SimpleXMLReader::CallBack {
public:
ListLoader(DirectoryListing::Directory* root, const User::Ptr& user, bool aDoAdl) : cur(root), inListing(false), doAdl(aDoAdl) {
if(doAdl) {
params["nick"] = user->getNick();
ADLSearchManager::getInstance()->setUser(user);
ADLSearchManager::getInstance()->PrepareDestinationDirectories(destDirs, root, params);
ADLSearchManager::getInstance()->setBreakOnFirst(BOOLSETTING(ADLS_BREAK_ON_FIRST));
}
lastFileIter = cur->files.begin();
};
virtual ~ListLoader() { }
virtual void startTag(const string& name, StringPairList& attribs, bool simple);
virtual void endTag(const string& name, const string& data);
private:
string fullPath;
ADLSearchManager::DestDirList destDirs;
DirectoryListing::Directory* cur;
DirectoryListing::File::Iter lastFileIter;
StringMap params;
bool inListing;
bool doAdl;
};
void DirectoryListing::loadXML(const string& xml, bool doAdl) {
setUtf8(true);
ListLoader ll(getRoot(), getUser(), doAdl);
SimpleXMLReader(&ll).fromXML(xml);
}
static const string sFileListing = "FileListing";
static const string sDirectory = "Directory";
static const string sFile = "File";
static const string sName = "Name";
static const string sSize = "Size";
static const string sTTH = "TTH";
void ListLoader::startTag(const string& name, StringPairList& attribs, bool) {
if(inListing) {
if(name == sFile) {
const string& n = getAttrib(attribs, sName, 0);
if(n.empty())
return;
const string& s = getAttrib(attribs, sSize, 1);
if(s.empty())
return;
const string& h = getAttrib(attribs, sTTH, 2);
DirectoryListing::File* f = h.empty() ? new DirectoryListing::File(cur, n, Util::toInt64(s)) : new DirectoryListing::File(cur, n, Util::toInt64(s), h);
cur->files.push_back(f);
if(doAdl)
ADLSearchManager::getInstance()->MatchesFile(destDirs, f, fullPath);
} else if(name == sDirectory) {
const string& n = getAttrib(attribs, sName, 0);
if(n.empty()) {
throw SimpleXMLException("Directory missing name attribute");
}
DirectoryListing::Directory* d = new DirectoryListing::Directory(cur, n);
cur->directories.push_back(d);
cur = d;
fullPath += '\\';
fullPath += d->getName();
// ADLSearch
if(doAdl)
ADLSearchManager::getInstance()->MatchesDirectory(destDirs, d, fullPath);
}
} else if(name == sFileListing) {
inListing = true;
}
}
void ListLoader::endTag(const string& name, const string&) {
if(inListing) {
if(name == sDirectory) {
cur = cur->getParent();
dcassert(fullPath.find('\\') != string::npos);
fullPath.erase(fullPath.rfind('\\'));
if(doAdl)
ADLSearchManager::getInstance()->StepUpDirectory(destDirs);
lastFileIter = cur->files.begin();
} else if(name == sFileListing) {
// cur should be root now...
if(doAdl)
ADLSearchManager::getInstance()->FinalizeDestinationDirectories(destDirs, cur);
inListing = false;
}
}
}
string DirectoryListing::getPath(Directory* d) {
string dir;
dir.reserve(128);
dir.append(d->getName());
dir.append(1, '\\');
Directory* cur = d->getParent();
while(cur!=root) {
dir.insert(0, cur->getName() + '\\');
cur = cur->getParent();
}
return dir;
}
static inline const string& escaper(const string& n, string& tmp, bool utf8) {
return utf8 ? n : (tmp.clear(), Text::acpToUtf8(n, tmp));
}
void DirectoryListing::download(Directory* aDir, const string& aTarget, bool highPrio) {
string tmp;
string target = (aDir == getRoot()) ? aTarget : aTarget + escaper(aDir->getName(), tmp, getUtf8()) + '\\';
// First, recurse over the directories
Directory::List& lst = aDir->directories;
sort(lst.begin(), lst.end(), Directory::DirSort());
for(Directory::Iter j = lst.begin(); j != lst.end(); ++j) {
download(*j, target, highPrio);
}
// Then add the files
File::List& l = aDir->files;
sort(l.begin(), l.end(), File::FileSort());
for(File::Iter i = aDir->files.begin(); i != aDir->files.end(); ++i) {
File* file = *i;
try {
download(file, target + escaper(file->getName(), tmp, getUtf8()), false, highPrio);
} catch(const QueueException&) {
// Catch it here to allow parts of directories to be added...
} catch(const FileException&) {
//..
}
}
}
void DirectoryListing::download(const string& aDir, const string& aTarget, bool highPrio) {
dcassert(aDir.size() > 2);
dcassert(aDir[aDir.size() - 1] == '\\');
Directory* d = find(aDir, getRoot());
if(d != NULL)
download(d, aTarget, highPrio);
}
void DirectoryListing::download(File* aFile, const string& aTarget, bool view, bool highPrio) {
int flags = (getUtf8() ? QueueItem::FLAG_SOURCE_UTF8 : 0) |
(view ? (QueueItem::FLAG_TEXT | QueueItem::FLAG_CLIENT_VIEW) : QueueItem::FLAG_RESUME);
if(getUtf8()) {
QueueManager::getInstance()->add(getPath(aFile) + aFile->getName(), aFile->getSize(), user, aTarget,
aFile->getTTH(), flags, highPrio || view ? QueueItem::HIGHEST : QueueItem::DEFAULT);
} else {
QueueManager::getInstance()->add(Text::acpToUtf8(getPath(aFile) + aFile->getName()), aFile->getSize(), user, aTarget,
aFile->getTTH(), flags, highPrio || view ? QueueItem::HIGHEST : QueueItem::DEFAULT);
}
}
DirectoryListing::Directory* DirectoryListing::find(const string& aName, Directory* current) {
string::size_type end = aName.find('\\');
dcassert(end != string::npos);
string name = aName.substr(0, end);
Directory::Iter i = ::find(current->directories.begin(), current->directories.end(), name);
if(i != current->directories.end()) {
if(end == (aName.size() - 1))
return *i;
else
return find(aName.substr(end + 1), *i);
}
return NULL;
}
int64_t DirectoryListing::Directory::getTotalSize(bool adl) {
int64_t x = getSize();
for(Iter i = directories.begin(); i != directories.end(); ++i) {
if(!(adl && (*i)->getAdls()))
x += (*i)->getTotalSize(adls);
}
return x;
}
size_t DirectoryListing::Directory::getTotalFileCount(bool adl) {
size_t x = getFileCount();
for(Iter i = directories.begin(); i != directories.end(); ++i) {
if(!(adl && (*i)->getAdls()))
x += (*i)->getTotalFileCount(adls);
}
return x;
}
/**
* @file
* $Id: DirectoryListing.cpp,v 1.38 2004/09/26 18:54:08 arnetheduck Exp $
*/