/* */ #include "ExpatMetalinkProcessor.h" #include "DefaultDiskWriter.h" #include "MetalinkParserStateMachine.h" #include "Metalinker.h" #include "MetalinkEntry.h" #include "util.h" #include "message.h" #include "DlAbortEx.h" namespace aria2 { class SessionData { public: SharedHandle _stm; std::deque _charactersStack; SessionData(const SharedHandle& stm):_stm(stm) {} }; static void mlStartElement(void* userData, const char* name, const char** attrs) { SessionData* sd = reinterpret_cast(userData); std::map attrmap; if(attrs) { const char** p = attrs; while(*p != 0) { std::string name = *p++; if(*p == 0) { break; } std::string value = util::trim(*p++); attrmap[name] = value; } } sd->_stm->beginElement(name, attrmap); if(sd->_stm->needsCharactersBuffering()) { sd->_charactersStack.push_front(std::string()); } } static void mlEndElement(void* userData, const char* name) { SessionData* sd = reinterpret_cast(userData); std::string characters; if(sd->_stm->needsCharactersBuffering()) { characters = util::trim(sd->_charactersStack.front()); sd->_charactersStack.pop_front(); } sd->_stm->endElement(name, characters); } static void mlCharacters(void* userData, const char* ch, int len) { SessionData* sd = reinterpret_cast(userData); if(sd->_stm->needsCharactersBuffering()) { sd->_charactersStack.front() += std::string(&ch[0], &ch[len]); } } SharedHandle MetalinkProcessor::parseFile(const std::string& filename) { SharedHandle dw(new DefaultDiskWriter(filename)); dw->openExistingFile(); return parseFromBinaryStream(dw); } SharedHandle MetalinkProcessor::parseFromBinaryStream(const SharedHandle& binaryStream) { _stm.reset(new MetalinkParserStateMachine()); ssize_t bufSize = 4096; unsigned char buf[bufSize]; SharedHandle sessionData(new SessionData(_stm)); XML_Parser parser = XML_ParserCreate(0); try { XML_SetUserData(parser, sessionData.get()); XML_SetElementHandler(parser, &mlStartElement, &mlEndElement); XML_SetCharacterDataHandler(parser, &mlCharacters); off_t readOffset = 0; while(1) { ssize_t res = binaryStream->readData(buf, bufSize, readOffset); if(res == 0) { break; } if(XML_Parse(parser, reinterpret_cast(buf), res, 0) == XML_STATUS_ERROR) { throw DL_ABORT_EX(MSG_CANNOT_PARSE_METALINK); } readOffset += res; } if(XML_Parse(parser, 0, 0, 1) == XML_STATUS_ERROR) { throw DL_ABORT_EX(MSG_CANNOT_PARSE_METALINK); } } catch(Exception& e) { XML_ParserFree(parser); throw; } XML_ParserFree(parser); if(!_stm->finished()) { throw DL_ABORT_EX(MSG_CANNOT_PARSE_METALINK); } return _stm->getResult(); } } // namespace aria2