* Copyright (c) 1999-2000, Eric Moon.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions, and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "Importer.h"
#include <stdexcept>
#include <Autolock.h>
#include <Debug.h>
using namespace std;
__USE_CORTEX_NAMESPACE
void _oc_handle_start(
void* pUser,
const XML_Char* pName,
const XML_Char** ppAtts) {
((Importer*)pUser)->xmlElementStart(pName, ppAtts);
}
void _oc_handle_end(
void* pUser,
const XML_Char* pName) {
((Importer*)pUser)->xmlElementEnd(pName);
}
void _oc_handle_pi(
void* pUser,
const XML_Char* pTarget,
const XML_Char* pData) {
((Importer*)pUser)->xmlProcessingInstruction(pTarget, pData);
}
void _oc_handle_char(
void* pUser,
const XML_Char* pData,
int length) {
((Importer*)pUser)->xmlCharacterData(pData, length);
}
void _oc_handle_default(
void* pUser,
const XML_Char* pData,
int length) {
((Importer*)pUser)->xmlDefaultData(pData, length);
}
Importer::~Importer() {
freeParser();
delete m_context;
}
Importer::Importer(
list<BString>& errors) :
m_parser(0),
m_docType(0),
m_identify(false),
m_context(new ImportContext(errors)),
m_rootObject(0) {
initParser();
}
Importer::Importer(
ImportContext* context) :
m_parser(0),
m_docType(0),
m_identify(false),
m_context(context),
m_rootObject(0) {
ASSERT(m_context);
initParser();
}
Importer::Importer(
list<BString>& errors,
IPersistent* rootObject,
XML::DocumentType* docType) :
m_parser(0),
m_docType(docType),
m_identify(false),
m_context(new ImportContext(errors)),
m_rootObject(rootObject) {
ASSERT(rootObject);
ASSERT(docType);
initParser();
}
Importer::Importer(
ImportContext* context,
IPersistent* rootObject,
XML::DocumentType* docType) :
m_parser(0),
m_docType(docType),
m_identify(false),
m_context(context),
m_rootObject(rootObject) {
ASSERT(m_context);
ASSERT(rootObject);
ASSERT(docType);
initParser();
}
const ImportContext& Importer::context() const {
return *m_context;
}
XML::DocumentType* Importer::docType() const {
return m_docType;
}
IPersistent* Importer::target() const {
return m_rootObject;
}
void Importer::setIdentifyMode() {
reset();
m_docType = 0;
m_identify = true;
}
void Importer::reset() {
m_identify = false;
m_context->reset();
m_rootObject = 0;
}
bool Importer::parseBuffer(
const char* pBuffer,
uint32 length,
bool last) {
ASSERT(m_parser);
int err = XML_Parse(m_parser, pBuffer, length, last);
if(!err) {
BString str = "Parse Error: ";
str << XML_ErrorString(XML_GetErrorCode(m_parser));
m_context->reportError(str.String());
return false;
} else
return true;
}
void Importer::initParser() {
ASSERT(!m_parser);
m_parser = XML_ParserCreate(0);
m_context->m_pParser = m_parser;
XML_SetElementHandler(
m_parser,
&_oc_handle_start,
&_oc_handle_end);
XML_SetProcessingInstructionHandler(
m_parser,
&_oc_handle_pi);
XML_SetCharacterDataHandler(
m_parser,
&_oc_handle_char);
XML_SetDefaultHandlerExpand(
m_parser,
&_oc_handle_default);
XML_SetUserData(
m_parser,
(void*)this);
}
void Importer::freeParser() {
ASSERT(m_parser);
XML_ParserFree(m_parser);
m_parser = 0;
}
void Importer::xmlElementStart(
const char* pName,
const char** ppAttributes) {
if(m_context->m_state != ImportContext::PARSING)
return;
IPersistent* target = 0;
if(!m_context->m_elementStack.size()) {
if(m_rootObject) {
ASSERT(m_docType);
if(m_docType->rootElement != pName) {
BString err("Unexpected document element (should be <");
err << m_docType->rootElement << "/>";
m_context->reportError(err.String());
return;
}
target = m_rootObject;
}
else {
BAutolock _l(XML::s_docTypeLock);
XML::doc_type_map::iterator it = XML::s_docTypeMap.find(
BString(pName));
if(it != XML::s_docTypeMap.end())
m_docType = (*it).second;
else {
BString err("No document type registered for element '");
err << pName << "'.";
m_context->reportError(err.String());
return;
}
if(m_identify) {
m_context->m_state = ImportContext::COMPLETE;
return;
}
}
}
ASSERT(m_docType);
m_context->m_elementStack.push_back(pName);
if(!target)
target = m_docType->objectFor(pName);
if(target) {
m_context->m_objectStack.push_back(
make_pair(m_context->element(), target));
target->xmlImportBegin(*m_context);
if(m_context->state() != ImportContext::PARSING)
return;
while(*ppAttributes) {
target->xmlImportAttribute(
ppAttributes[0],
ppAttributes[1],
*m_context);
if(m_context->state() != ImportContext::PARSING)
return;
ppAttributes += 2;
}
} else {
ASSERT(m_context->m_objectStack.size());
IPersistent* curObject = m_context->m_objectStack.back().second;
ASSERT(curObject);
curObject->xmlImportChildBegin(
pName,
*m_context);
if(m_context->state() != ImportContext::PARSING)
return;
while(*ppAttributes) {
curObject->xmlImportChildAttribute(
ppAttributes[0],
ppAttributes[1],
*m_context);
if(m_context->state() != ImportContext::PARSING)
return;
ppAttributes += 2;
}
}
}
void Importer::xmlElementEnd(
const char* pName) {
if(m_context->m_state != ImportContext::PARSING)
return;
ASSERT(m_docType);
if(!m_context->m_elementStack.size() ||
m_context->m_elementStack.back() != pName) {
m_context->reportError("Mismatched end tag.");
return;
}
IPersistent* pObject = 0;
if(!m_context->m_objectStack.size()) {
m_context->reportError("No object being constructed.");
return;
}
if(m_context->m_objectStack.back().first == m_context->element()) {
pObject = m_context->m_objectStack.back().second;
m_context->m_objectStack.pop_back();
}
if(pObject) {
pObject->xmlImportComplete(
*m_context);
if(m_context->state() != ImportContext::PARSING)
return;
if(m_context->m_objectStack.size()) {
m_context->m_objectStack.back().second->xmlImportChild(
pObject,
*m_context);
} else {
ASSERT(m_context->m_elementStack.size() == 1);
m_context->m_state = ImportContext::COMPLETE;
if(m_rootObject) {
ASSERT(m_rootObject == pObject);
} else
m_rootObject = pObject;
}
}
else {
ASSERT(m_context->m_objectStack.size());
IPersistent* curObject = m_context->m_objectStack.back().second;
ASSERT(curObject);
curObject->xmlImportChildComplete(
pName,
*m_context);
}
m_context->m_elementStack.pop_back();
ASSERT(m_context->m_objectStack.size() <= m_context->m_elementStack.size());
}
void Importer::xmlProcessingInstruction(
const char* pTarget,
const char* pData) {
if(m_context->m_state != ImportContext::PARSING)
return;
}
void Importer::xmlCharacterData(
const char* pData,
int32 length) {
if(m_context->m_state != ImportContext::PARSING)
return;
IPersistent* pObject = 0;
if(!m_context->m_objectStack.size()) {
m_context->reportError("No object being constructed.");
return;
}
pObject = m_context->m_objectStack.back().second;
if(m_context->m_objectStack.back().first == m_context->element()) {
pObject->xmlImportContent(
pData,
length,
*m_context);
}
else {
pObject->xmlImportChildContent(
pData,
length,
*m_context);
}
}
void Importer::xmlDefaultData(
const char* pData,
int32 length) {
if(m_context->m_state != ImportContext::PARSING)
return;
}