/* */ #include "DefaultBtContext.h" #include "MetaFileUtil.h" #include "Dictionary.h" #include "List.h" #include "Data.h" #include "DlAbortEx.h" #include "ShaVisitor.h" #include "Util.h" #include DefaultBtContext::DefaultBtContext() {} DefaultBtContext::~DefaultBtContext() {} string DefaultBtContext::generatePeerId() const { string peerId = "-aria2-"; peerId += Util::randomAlpha(20-peerId.size()); return peerId; } const unsigned char* DefaultBtContext::getInfoHash() const { return infoHash; } int32_t DefaultBtContext::getInfoHashLength() const { return INFO_HASH_LENGTH; } string DefaultBtContext::getInfoHashAsString() const { return infoHashString; } void DefaultBtContext::clear() { memset(infoHash, 0, INFO_HASH_LENGTH); infoHashString = ""; pieceHashes.clear(); fileEntries.clear(); totalLength = 0; pieceLength = 0; fileMode = BtContext::SINGLE; numPieces = 0; name = ""; announceTiers.clear(); } void DefaultBtContext::extractPieceHash(const unsigned char* hashData, int32_t hashDataLength, int32_t hashLength) { assert(hashDataLength > 0); assert(hashLength > 0); int32_t numPieces = hashDataLength/hashLength; assert(numPieces > 0); for(int32_t i = 0; i < numPieces; i++) { pieceHashes.push_back(Util::toHex(&hashData[i*hashLength], hashLength)); } } void DefaultBtContext::extractFileEntries(Dictionary* infoDic, const string& defaultName) { // TODO use dynamic_cast Data* nameData = (Data*)infoDic->get("name"); if(nameData) { name = nameData->toString(); } else { char* basec = strdup(defaultName.c_str()); name = string(basename(basec))+".file"; free(basec); } // TODO use dynamic_cast List* files = (List*)infoDic->get("files"); if(files) { int64_t length = 0; int64_t offset = 0; // multi-file mode fileMode = BtContext::MULTI; const MetaList& metaList = files->getList(); for(MetaList::const_iterator itr = metaList.begin(); itr != metaList.end(); itr++) { Dictionary* fileDic = (Dictionary*)(*itr); // TODO use dynamic_cast Data* lengthData = (Data*)fileDic->get("length"); length += lengthData->toLLInt(); // TODO use dynamic_cast List* pathList = (List*)fileDic->get("path"); const MetaList& paths = pathList->getList(); string path; for(int32_t i = 0; i < (int32_t)paths.size()-1; i++) { Data* subpath = (Data*)paths.at(i); path += subpath->toString()+"/"; } // TODO use dynamic_cast Data* lastPath = (Data*)paths.back(); path += lastPath->toString(); FileEntryHandle fileEntry(new FileEntry(path, lengthData->toLLInt(), offset)); fileEntries.push_back(fileEntry); offset += fileEntry->getLength(); } totalLength = length; } else { // single-file mode; fileMode = BtContext::SINGLE; Data* length = (Data*)infoDic->get("length"); totalLength = length->toLLInt(); FileEntryHandle fileEntry(new FileEntry(name, totalLength, 0)); fileEntries.push_back(fileEntry); } } void DefaultBtContext::extractAnnounce(Data* announceData) { Strings urls; urls.push_back(announceData->toString()); announceTiers.push_back(AnnounceTierHandle(new AnnounceTier(urls))); } void DefaultBtContext::extractAnnounceList(List* announceListData) { for(MetaList::const_iterator itr = announceListData->getList().begin(); itr != announceListData->getList().end(); itr++) { const List* elem = (List*)*itr; Strings urls; for(MetaList::const_iterator elemItr = elem->getList().begin(); elemItr != elem->getList().end(); elemItr++) { const Data* data = (Data*)*elemItr; urls.push_back(data->toString()); } if(urls.size()) { AnnounceTierHandle tier(new AnnounceTier(urls)); announceTiers.push_back(tier); } } } void DefaultBtContext::load(const string& torrentFile) { clear(); MetaEntry* rootEntry = MetaFileUtil::parseMetaFile(torrentFile); if(!dynamic_cast(rootEntry)) { throw new DlAbortEx("torrent file does not contain a root dictionary ."); } SharedHandle rootDic = SharedHandle((Dictionary*)rootEntry); Dictionary* infoDic = (Dictionary*)rootDic->get("info"); // retrieve infoHash ShaVisitor v; infoDic->accept(&v); int32_t len; v.getHash(infoHash, len); infoHashString = Util::toHex(infoHash, INFO_HASH_LENGTH); // calculate the number of pieces Data* pieceHashData = (Data*)infoDic->get("pieces"); numPieces = pieceHashData->getLen()/PIECE_HASH_LENGTH; // retrieve piece length Data* pieceLengthData = (Data*)infoDic->get("piece length"); pieceLength = pieceLengthData->toInt(); // retrieve piece hashes extractPieceHash((unsigned char*)pieceHashData->getData(), pieceHashData->getLen(), PIECE_HASH_LENGTH); // retrieve file entries extractFileEntries(infoDic, torrentFile); // retrieve announce Data* announceData = (Data*)rootDic->get("announce"); List* announceListData = (List*)rootDic->get("announce-list"); if(announceListData) { extractAnnounceList(announceListData); } else if(announceData) { extractAnnounce(announceData); } if(!announceTiers.size()) { throw new DlAbortEx("No announce URL found."); } } string DefaultBtContext::getPieceHash(int32_t index) const { if(index < 0 || numPieces <= index) { return ""; } return pieceHashes.at(index); } int64_t DefaultBtContext::getTotalLength() const { return totalLength; } BtContext::FILE_MODE DefaultBtContext::getFileMode() const { return fileMode; } FileEntries DefaultBtContext::getFileEntries() const { return fileEntries; } AnnounceTiers DefaultBtContext::getAnnounceTiers() const { return announceTiers; } string DefaultBtContext::getName() const { return name; } int32_t DefaultBtContext::getPieceLength() const { return pieceLength; } int32_t DefaultBtContext::getNumPieces() const { return numPieces; }