/* */ #include "ExpatXmlParser.h" #include #include #include #include #include "a2io.h" #include "BinaryStream.h" #include "BufferedFile.h" #include "ParserStateMachine.h" #include "A2STR.h" #include "a2functional.h" #include "XmlAttr.h" namespace aria2 { namespace { struct SessionData { std::deque charactersStack_; ParserStateMachine* psm_; SessionData(ParserStateMachine* psm) : psm_(psm) {} }; } // namespace namespace { void splitNsName(const char** localname, const char** nsUri, const char* src) { const char* sep = strchr(src, '\t'); if(sep) { *localname = sep+1; size_t nsUriLen = sep-src; char* temp = new char[nsUriLen+1]; memcpy(temp, src, nsUriLen); temp[nsUriLen] = '\0'; *nsUri = temp; } else { *localname = src; } } } // namespace namespace { 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) { XmlAttr xa; const char* attrNsName = *p++; if(*p == 0) { break; } splitNsName(&xa.localname, &xa.nsUri, attrNsName); const char* value = *p++; xa.value = value; xa.valueLength = strlen(value); xmlAttrs.push_back(xa); } } const char* localname = 0; const char* prefix = 0; const char* nsUri = 0; splitNsName(&localname, &nsUri, nsName); sd->psm_->beginElement(localname, prefix, nsUri, xmlAttrs); delete [] nsUri; for(std::vector::iterator i = xmlAttrs.begin(), eoi = xmlAttrs.end(); i != eoi; ++i) { delete [] (*i).nsUri; } if(sd->psm_->needsCharactersBuffering()) { sd->charactersStack_.push_front(A2STR::NIL); } } } // namespace namespace { void mlEndElement(void* userData, const char* nsName) { const char* localname = 0; const char* prefix = 0; const char* nsUri = 0; splitNsName(&localname, &nsUri, nsName); SessionData* sd = reinterpret_cast(userData); std::string characters; if(sd->psm_->needsCharactersBuffering()) { characters = sd->charactersStack_.front(); sd->charactersStack_.pop_front(); } sd->psm_->endElement(localname, prefix, nsUri, characters); delete [] nsUri; } } // namespace namespace { void mlCharacters(void* userData, const char* ch, int len) { SessionData* sd = reinterpret_cast(userData); if(sd->psm_->needsCharactersBuffering()) { sd->charactersStack_.front().append(&ch[0], &ch[len]); } } } // namespace XmlParser::XmlParser(ParserStateMachine* psm) : psm_(psm) {} XmlParser::~XmlParser() {} namespace { XML_Parser createParser(SessionData* sd) { XML_Parser parser = XML_ParserCreateNS(0, static_cast('\t')); XML_SetUserData(parser, sd); XML_SetElementHandler(parser, &mlStartElement, &mlEndElement); XML_SetCharacterDataHandler(parser, &mlCharacters); return parser; } } // namespace bool XmlParser::parseFile(const char* filename) { BufferedFile* fp = 0; if(strcmp(filename, DEV_STDIN) == 0) { fp = new BufferedFile(stdin); auto_delete_d deleter(fp); return parseFile(fp); } else { fp = new BufferedFile(filename, BufferedFile::READ); auto_delete_d deleter(fp); return parseFile(fp); } } bool XmlParser::parseFile(BufferedFile* fp) { char buf[4096]; SessionData sessionData(psm_); XML_Parser parser = createParser(&sessionData); auto_delete deleter(parser, XML_ParserFree); while(1) { size_t res = fp->read(buf, sizeof(buf)); if(XML_Parse(parser, buf, res, 0) == XML_STATUS_ERROR) { return false; } if(res < sizeof(buf)) { break; } } return XML_Parse(parser, 0, 0, 1) != XML_STATUS_ERROR && psm_->finished(); } bool XmlParser::parseBinaryStream(BinaryStream* bs) { const ssize_t bufSize = 4096; unsigned char buf[bufSize]; SessionData sessionData(psm_); XML_Parser parser = createParser(&sessionData); auto_delete deleter(parser, XML_ParserFree); off_t readOffset = 0; while(1) { ssize_t res = bs->readData(buf, bufSize, readOffset); if(res == 0) { break; } if(XML_Parse(parser, reinterpret_cast(buf), res, 0) == XML_STATUS_ERROR) { return false; } readOffset += res; } return XML_Parse(parser, 0, 0, 1) != XML_STATUS_ERROR && psm_->finished(); } bool XmlParser::parseMemory(const char* xml, size_t size) { SessionData sessionData(psm_); XML_Parser parser = createParser(&sessionData); auto_delete deleter(parser, XML_ParserFree); if(XML_Parse(parser, xml, size, 0) == XML_STATUS_ERROR) { return false; } return XML_Parse(parser, 0, 0, 1) != XML_STATUS_ERROR && psm_->finished(); } } // namespace aria2