/* */ #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*)userData)->_charactersStack.push_front(std::string()); 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; } } ((SessionData*)userData)->_stm->beginElement(name, attrmap); } static void mlEndElement(void* userData, const char* name) { SessionData* sd = (SessionData*)userData; sd->_stm->endElement(name, Util::trim(sd->_charactersStack.front())); sd->_charactersStack.pop_front(); } static void mlCharacters(void* userData, const char* ch, int len) { ((SessionData*)userData)->_charactersStack.front() += std::string(&ch[0], &ch[len]); } ExpatMetalinkProcessor::ExpatMetalinkProcessor(): _stm(0) {} SharedHandle ExpatMetalinkProcessor::parseFile(const std::string& filename) { SharedHandle dw = new DefaultDiskWriter(); dw->openExistingFile(filename); return parseFromBinaryStream(dw); } SharedHandle ExpatMetalinkProcessor::parseFromBinaryStream(const SharedHandle& binaryStream) { _stm = 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, (const char*)buf, res, 0) == XML_STATUS_ERROR) { throw new DlAbortEx(MSG_CANNOT_PARSE_METALINK); } readOffset += res; } if(XML_Parse(parser, 0, 0, 1) == XML_STATUS_ERROR) { throw new DlAbortEx(MSG_CANNOT_PARSE_METALINK); } } catch(Exception* e) { XML_ParserFree(parser); throw; } XML_ParserFree(parser); if(!_stm->finished()) { throw new DlAbortEx(MSG_CANNOT_PARSE_METALINK); } return _stm->getResult(); } } // namespace aria2