/* */ #include "ExpatMetalinkProcessor.h" #include #include #include "DefaultDiskWriter.h" #include "MetalinkParserStateMachine.h" #include "Metalinker.h" #include "MetalinkEntry.h" #include "util.h" #include "message.h" #include "DlAbortEx.h" #include "MetalinkParserState.h" #include "A2STR.h" namespace aria2 { namespace { class SessionData { public: SharedHandle stm_; std::deque charactersStack_; SessionData(const SharedHandle& stm):stm_(stm) {} }; } static void splitNsName (std::string& localname, std::string& prefix, std::string& nsUri, const std::string& nsName) { std::pair nsNamePair; util::divide(nsNamePair, nsName, '\t'); if(nsNamePair.second.empty()) { localname = nsNamePair.first; } else { nsUri = nsNamePair.first; localname = nsNamePair.second; } } static void mlStartElement(void* userData, const char* nsName, const char** attrs) { SessionData* sd = reinterpret_cast(userData); std::vector xmlAttrs; if(attrs) { const char** p = attrs; while(*p != 0) { std::string attrNsName = *p++; if(*p == 0) { break; } std::string value = *p++; std::pair nsNamePair; util::divide(nsNamePair, attrNsName, '\t'); XmlAttr xa; if(nsNamePair.second.empty()) { xa.localname = nsNamePair.first; } else { xa.nsUri = nsNamePair.first; xa.localname = nsNamePair.second; } xa.value = value; xmlAttrs.push_back(xa); } } std::string localname; std::string prefix; std::string nsUri; splitNsName(localname, prefix, nsUri, nsName); sd->stm_->beginElement(localname, prefix, nsUri, xmlAttrs); if(sd->stm_->needsCharactersBuffering()) { sd->charactersStack_.push_front(A2STR::NIL); } } static void mlEndElement(void* userData, const char* nsName) { std::string localname; std::string prefix; std::string nsUri; splitNsName(localname, prefix, nsUri, nsName); SessionData* sd = reinterpret_cast(userData); std::string characters; if(sd->stm_->needsCharactersBuffering()) { characters = sd->charactersStack_.front(); sd->charactersStack_.pop_front(); } sd->stm_->endElement(localname, prefix, nsUri, 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]); } } static XML_Parser createParser(const SharedHandle& sessionData) { XML_Parser parser = XML_ParserCreateNS(0, static_cast('\t')); XML_SetUserData(parser, sessionData.get()); XML_SetElementHandler(parser, &mlStartElement, &mlEndElement); XML_SetCharacterDataHandler(parser, &mlCharacters); return parser; } static void checkError(XML_Parser parser) { if(XML_Parse(parser, 0, 0, 1) == XML_STATUS_ERROR) { throw DL_ABORT_EX(MSG_CANNOT_PARSE_METALINK); } SessionData* sessionData = reinterpret_cast(XML_GetUserData(parser)); const SharedHandle& stm = sessionData->stm_; if(!stm->finished()) { throw DL_ABORT_EX(MSG_CANNOT_PARSE_METALINK); } if(!stm->getErrors().empty()) { throw DL_ABORT_EX(stm->getErrorString()); } } SharedHandle MetalinkProcessor::parseFile(const std::string& filename) { if(filename == DEV_STDIN) { return parseFile(std::cin); } else { std::ifstream infile(filename.c_str(), std::ios::binary); return parseFile(infile); } } SharedHandle MetalinkProcessor::parseFile(std::istream& stream) { stm_.reset(new MetalinkParserStateMachine()); char buf[4096]; SharedHandle sessionData(new SessionData(stm_)); XML_Parser parser = createParser(sessionData); auto_delete deleter(parser, XML_ParserFree); while(stream) { stream.read(buf, sizeof(buf)); if(XML_Parse(parser, buf, stream.gcount(), 0) == XML_STATUS_ERROR) { throw DL_ABORT_EX(MSG_CANNOT_PARSE_METALINK); } } if(stream.bad()) { throw DL_ABORT_EX(MSG_CANNOT_PARSE_METALINK); } checkError(parser); return stm_->getResult(); } 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 = createParser(sessionData); 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; } checkError(parser); return stm_->getResult(); } } // namespace aria2