/* * Copyright (C) 2005 Alo Sarv <madcat_@users.sourceforge.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /** * \file files.cpp Implementation of TorrentFile and PartialTorrent classes */ #include <hncore/bt/files.h> namespace Bt { // TorrentFile class // ----------------- TorrentFile::TorrentFile(const std::vector<SharedFile*> &files) { CHECK_THROW(files.size()); uint64_t offset = 0; for (uint32_t i = 0; i < files.size(); ++i) { m_children[offset] = files[i]; offset += files[i]->getSize(); } m_size = offset + 1; logDebug("TorrentFile, childmap:"); boost::format fmt("[%11d] %s (%d bytes)"); for (Iter i = m_children.begin(); i != m_children.end(); ++i) { logDebug( fmt % (*i).first % (*i).second->getName() % (*i).second->getSize() ); } } TorrentFile::~TorrentFile() {} std::string TorrentFile::read(uint64_t begin, uint64_t end) { Iter i = m_children.upper_bound(begin); CHECK_THROW(i != m_children.end()); begin -= (*i).first; end -= (*i).first; std::string tmpData; while (end > (*i).second->getSize()) { tmpData += (*i).second->read(begin, (*i).second->getSize()); begin = 0; end -= (*i).second->getSize(); ++i; assert(i != m_children.end()); } return tmpData; } // PartialTorrent class // -------------------- PartialTorrent::PartialTorrent(const std::vector<PartData*> &files) { CHECK_THROW(files.size()); uint64_t offset = 0; for (uint32_t i = 0; i < files.size(); ++i) { m_children[offset] = files[i]; m_childrenReverse[files[i]] = offset; offset += files[i]->getSize(); files[i]->dataAdded.connect( boost::bind(&PartialTorrent::onDataAdded, this, _1, _2, _3) ); files[i]->onCorruption.connect( boost::bind(&PartialTorrent::onChildCorruption, this, _1, _2, _3) ); } m_size = offset + 1; logDebug("PartialTorrent, childmap:"); boost::format fmt("[%11d] %s (%d bytes)"); for (Iter i = m_children.begin(); i != m_children.end(); ++i) { logDebug( fmt % (*i).first % (*i).second->getName() % (*i).second->getSize() ); } } PartialTorrent::~PartialTorrent() {} void PartialTorrent::doWrite(uint64_t begin, const std::string &data) { Iter i = m_children.lower_bound(begin); CHECK_THROW(i != m_children.end()); begin -= (*i).first; uint32_t pos = 0; while (begin + data.size() > (*i).second->getSize()) { PartData *pd = (*i).second; pd->write(begin, data.substr(pos, pd->getSize() - begin)); pos += pd->getSize() - begin; ++i; begin = 0; } if (data.size()) { assert(i != m_children.end()); (*i).second->write(0, data); } } void PartialTorrent::onDataAdded(PartData *f, uint64_t offset, uint32_t amount){ RIter i = m_childrenReverse.find(f); assert(i != m_childrenReverse.end()); m_complete.merge(offset + (*i).second, offset + (*i).second + amount); } void PartialTorrent::verifyRange(Range64 range, const HashBase *ref) { boost::shared_ptr<HashWork> c; std::vector<boost::filesystem::path> files; Iter i = m_children.lower_bound(range.begin()); files.push_back((*i).second->getLocation()); range.begin(range.begin() - (*i).first); while (++i != m_children.end() && (*i).first < range.end()) { files.push_back((*i).second->getLocation()); } range.end(range.end() - (*i).first); c.reset(new TorrentHasher(files, range.begin(), range.end(), ref)); c->getEventTable().addHandler( c, dynamic_cast<PartData*>(this), &PartData::onHashEvent ); WorkThread::instance().postWork(c); } void PartialTorrent::corruption(uint64_t begin, uint64_t end) { Iter i = m_children.lower_bound(begin); assert(i != m_children.end()); begin -= (*i).first; while (end - (*i).first > (*i).second->getSize()) { (*i).second->corruption(begin, end - (*i).first); begin = 0; ++i; } } void PartialTorrent::onChildCorruption( PartData *file, uint64_t begin, uint64_t end ) { RIter i = m_childrenReverse.find(file); assert(i != m_childrenReverse.end()); m_complete.erase(begin + (*i).second, begin + (*i).second + end); } // TorrentHasher class // ------------------- TorrentHasher::TorrentHasher( const std::vector<boost::filesystem::path> &files, uint64_t begin, uint64_t end, const HashBase *ref ) : HashWork(files[0], begin, end, ref), m_files(files), m_curFile(m_files.begin()) {} uint64_t TorrentHasher::readNext(uint64_t pos) { uint64_t tmp = HashWork::readNext(pos); while (tmp < getBufSize() && ++m_curFile != m_files.end()) { m_fileName = *m_curFile; openFile(); tmp += HashWork::readNext(0); } return tmp; } }