bool IWORKParser::parse() { const shared_ptr<xmlTextReader> sharedReader(xmlReaderForIO(readFromStream, closeStream, m_input.get(), "", nullptr, 0), xmlFreeTextReader); if (!sharedReader) return false; xmlTextReaderPtr reader = sharedReader.get(); assert(reader); const IWORKTokenizer &tokenizer = getTokenizer(); stack<IWORKXMLContextPtr_t> contextStack; int ret = xmlTextReaderRead(reader); contextStack.push(createDocumentContext()); bool keynoteDocTypeChecked=false; char const *defaultNS=nullptr; while ((1 == ret)) { switch (xmlTextReaderNodeType(reader)) { case XML_READER_TYPE_ELEMENT: { if (!keynoteDocTypeChecked) { // check for keynote 1 file with doctype node and not a namespace in first node keynoteDocTypeChecked=true; if (xmlTextReaderNodeType(reader)==XML_READER_TYPE_ELEMENT && xmlTextReaderConstNamespaceUri(reader)==nullptr) defaultNS="http://developer.apple.com/schemas/APXL"; } const int id = tokenizer.getQualifiedId(char_cast(xmlTextReaderConstLocalName(reader)), defaultNS ? defaultNS : char_cast(xmlTextReaderConstNamespaceUri(reader))); IWORKXMLContextPtr_t newContext = contextStack.top()->element(id); if (!newContext) newContext = createDiscardContext(); const bool isEmpty = xmlTextReaderIsEmptyElement(reader); newContext->startOfElement(); if (xmlTextReaderHasAttributes(reader)) { ret = xmlTextReaderMoveToFirstAttribute(reader); while (1 == ret) { processAttribute(reader, newContext, tokenizer); ret = xmlTextReaderMoveToNextAttribute(reader); } } if (isEmpty) newContext->endOfElement(); else contextStack.push(newContext); break; } case XML_READER_TYPE_END_ELEMENT: { contextStack.top()->endOfElement(); contextStack.pop(); break; } case XML_READER_TYPE_CDATA : { const xmlChar *text = xmlTextReaderConstValue(reader); if (text) contextStack.top()->CDATA(char_cast(text)); break; } case XML_READER_TYPE_TEXT : { xmlChar *const text = xmlTextReaderReadString(reader); contextStack.top()->text(char_cast(text)); xmlFree(text); break; } default: break; } ret = xmlTextReaderRead(reader); } while (!contextStack.empty()) // finish parsing in case of broken XML { contextStack.top()->endOfElement(); contextStack.pop(); } xmlTextReaderClose(reader); return true; }
bool IWORKParser::parse() { const shared_ptr<xmlTextReader> sharedReader(xmlReaderForIO(readFromStream, closeStream, m_input.get(), "", 0, 0), xmlFreeTextReader); if (!sharedReader) return false; xmlTextReaderPtr reader = sharedReader.get(); assert(reader); const IWORKTokenizer &tokenizer = getTokenizer(); stack<IWORKXMLContextPtr_t> contextStack; int ret = xmlTextReaderRead(reader); contextStack.push(createDocumentContext()); while ((1 == ret)) { switch (xmlTextReaderNodeType(reader)) { case XML_READER_TYPE_ELEMENT: { const int id = tokenizer.getQualifiedId(char_cast(xmlTextReaderConstLocalName(reader)), char_cast(xmlTextReaderConstNamespaceUri(reader))); IWORKXMLContextPtr_t newContext = contextStack.top()->element(id); if (!newContext) newContext = createDiscardContext(); const bool isEmpty = xmlTextReaderIsEmptyElement(reader); newContext->startOfElement(); if (xmlTextReaderHasAttributes(reader)) { ret = xmlTextReaderMoveToFirstAttribute(reader); while (1 == ret) { processAttribute(reader, newContext, tokenizer); ret = xmlTextReaderMoveToNextAttribute(reader); } } if (isEmpty) newContext->endOfElement(); else contextStack.push(newContext); break; } case XML_READER_TYPE_END_ELEMENT: { contextStack.top()->endOfElement(); contextStack.pop(); break; } case XML_READER_TYPE_TEXT : { xmlChar *const text = xmlTextReaderReadString(reader); contextStack.top()->text(char_cast(text)); xmlFree(text); break; } default: break; } ret = xmlTextReaderRead(reader); } while (!contextStack.empty()) // finish parsing in case of broken XML { contextStack.top()->endOfElement(); contextStack.pop(); } xmlTextReaderClose(reader); return true; }