/* */ #include "XML2SAXMetalinkProcessor.h" #include "BinaryStream.h" #include "MetalinkParserStateMachine.h" #include "Util.h" #include "message.h" class SessionData { public: MetalinkParserStateMachineHandle _stm; Strings _charactersStack; SessionData(const MetalinkParserStateMachineHandle& stm):_stm(stm) {} }; typedef SharedHandle SessionDataHandle; static void mlStartElement(void* userData, const xmlChar* name, const xmlChar** attrs) { ((SessionData*)userData)->_charactersStack.push_front(string()); map attrmap; if(attrs) { const xmlChar** p = attrs; while(*p != 0) { string name = (const char*)*p++; if(*p == 0) { break; } string value = Util::trim((const char*)*p++); attrmap[name] = value; } } ((SessionData*)userData)->_stm->beginElement((const char*)name, attrmap); } static void mlEndElement(void* userData, const xmlChar* name) { SessionData* sd = (SessionData*)userData; sd->_stm->endElement((const char*)name, Util::trim(sd->_charactersStack.front())); sd->_charactersStack.pop_front(); } static void mlCharacters(void* userData, const xmlChar* ch, int len) { ((SessionData*)userData)->_charactersStack.front() += string(&ch[0], &ch[len]); } static xmlSAXHandler mySAXHandler = { 0, // internalSubsetSAXFunc 0, // isStandaloneSAXFunc 0, // hasInternalSubsetSAXFunc 0, // hasExternalSubsetSAXFunc 0, // resolveEntitySAXFunc 0, // getEntitySAXFunc 0, // entityDeclSAXFunc 0, // notationDeclSAXFunc 0, // attributeDeclSAXFunc 0, // elementDeclSAXFunc 0, // unparsedEntityDeclSAXFunc 0, // setDocumentLocatorSAXFunc 0, // startDocumentSAXFunc 0, // endDocumentSAXFunc &mlStartElement, // startElementSAXFunc &mlEndElement, // endElementSAXFunc 0, // referenceSAXFunc &mlCharacters, // charactersSAXFunc 0, // ignorableWhitespaceSAXFunc 0, // processingInstructionSAXFunc 0, // commentSAXFunc 0, // warningSAXFunc 0, // errorSAXFunc 0, // fatalErrorSAXFunc 0, // getParameterEntitySAXFunc 0, // cdataBlockSAXFunc 0, // externalSubsetSAXFunc 0, // unsigned int initialized 0, // void * _private 0, // startElementNsSAX2Func 0, // endElementNsSAX2Func 0, // xmlStructuredErrorFunc }; XML2SAXMetalinkProcessor::XML2SAXMetalinkProcessor(): _stm(0) {} MetalinkerHandle XML2SAXMetalinkProcessor::parseFile(const string& filename) { _stm = new MetalinkParserStateMachine(); SessionDataHandle sessionData = new SessionData(_stm); int32_t retval = xmlSAXUserParseFile(&mySAXHandler, sessionData.get(), filename.c_str()); if(retval != 0) { throw new DlAbortEx(MSG_CANNOT_PARSE_METALINK); } return _stm->getResult(); } MetalinkerHandle XML2SAXMetalinkProcessor::parseFromBinaryStream(const BinaryStreamHandle& binaryStream) { _stm = new MetalinkParserStateMachine(); int32_t bufSize = 4096; unsigned char buf[bufSize]; int32_t res = binaryStream->readData(buf, 4, 0); if(res != 4) { throw new DlAbortEx("Too small data for parsing XML."); } SessionDataHandle sessionData = new SessionData(_stm); xmlParserCtxtPtr ctx = xmlCreatePushParserCtxt(&mySAXHandler, sessionData.get(), (const char*)buf, res, 0); int64_t readOffset = res; while(1) { int32_t res = binaryStream->readData(buf, bufSize, readOffset); if(res == 0) { break; } if(xmlParseChunk(ctx, (const char*)buf, res, 0) != 0) { throw new DlAbortEx(MSG_CANNOT_PARSE_METALINK); } readOffset += res; } xmlParseChunk(ctx, (const char*)buf, 0, 1); xmlFreeParserCtxt(ctx); if(!_stm->finished()) { throw new DlAbortEx(MSG_CANNOT_PARSE_METALINK); } return _stm->getResult(); }