xml-copy-editor-code/src/xmlpromptgenerator.cpp

348 lines
9.6 KiB
C++
Raw Normal View History

/*
* Copyright 2005-2007 Gerald Schmidt.
*
* This file is part of Xml Copy Editor.
*
* Xml Copy Editor is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* Xml Copy Editor is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Xml Copy Editor; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
2007-09-07 23:17:30 +02:00
#include <wx/wx.h>
#include <wx/filename.h>
#include <stdexcept>
#include "xmlpromptgenerator.h"
#include "xmlencodinghandler.h"
#include "readfile.h"
#include "replace.h"
#include "getword.h"
#include "pathresolver.h"
#include "catalogresolver.h"
#include "xmlschemaparser.h"
2007-09-08 00:25:30 +02:00
XmlPromptGenerator::XmlPromptGenerator (
const std::string& catalogPath,
const std::string& basePath,
const std::string& auxPath ) : d ( new PromptGeneratorData() )
2007-09-07 23:17:30 +02:00
{
2007-09-08 00:25:30 +02:00
XML_SetUserData ( p, d.get() );
d->p = p;
d->catalogPath = catalogPath;
d->auxPath = auxPath;
d->elementDeclRecurseLevel = 0;
d->rootElement = true;
d->dtdFound = false;
XML_SetParamEntityParsing ( p, XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE );
XML_SetElementHandler ( p, starthandler, endhandler );
XML_SetDoctypeDeclHandler ( p, doctypedeclstarthandler, doctypedeclendhandler );
XML_SetElementDeclHandler ( p, elementdeclhandler );
XML_SetAttlistDeclHandler ( p, attlistdeclhandler );
XML_SetEntityDeclHandler ( p, entitydeclhandler );
XML_SetExternalEntityRefHandlerArg ( p, d.get() );
XML_SetExternalEntityRefHandler ( p, externalentityrefhandler );
XML_SetBase ( p, basePath.c_str() );
if ( !auxPath.empty() )
XML_UseForeignDTD ( p, true );
2007-09-07 23:17:30 +02:00
}
XmlPromptGenerator::~XmlPromptGenerator()
2007-09-08 00:25:30 +02:00
{}
2007-09-07 23:17:30 +02:00
2007-09-08 00:25:30 +02:00
void XMLCALL XmlPromptGenerator::starthandler (
void *data,
const XML_Char *el,
const XML_Char **attr )
2007-09-07 23:17:30 +02:00
{
2007-09-08 00:25:30 +02:00
PromptGeneratorData *d;
d = ( PromptGeneratorData * ) data;
d->push ( el );
std::string parent, element;
parent = d->getParent();
element = el;
// update elementMap
if ( d->elementMap.find ( parent ) == d->elementMap.end() )
{
std::set<std::string> childSet;
childSet.insert ( element );
d->elementMap.insert ( make_pair ( parent, childSet ) );
}
else
d->elementMap[parent].insert ( element );
std::string attributeName, attributeValue;
// update attributeMap
// case 1: element unknown, no attributes
if ( ! ( *attr ) && d->attributeMap.find ( element ) == d->attributeMap.end() )
2007-09-07 23:17:30 +02:00
{
2007-09-08 00:25:30 +02:00
std::map<std::string, std::set<std::string> > currentAttributeMap;
d->attributeMap.insert ( make_pair ( element, currentAttributeMap ) );
2007-09-07 23:17:30 +02:00
}
2007-09-08 00:25:30 +02:00
for ( ; *attr; attr += 2 )
{
attributeName = *attr;
attributeValue = * ( attr + 1 );
d->attributeMap[element][attributeName].insert ( attributeValue );
/*
// TBD: may not be xsi: check for http://www.w3.org/2001/XMLSchema-instance
while (d->rootElement && strstr((const char *)attr, "xsi:noNamespaceSchemaLocation"))
{
std::string schemaPath = PathResolver::run(attributeValue, d->auxPath);
std::string buffer;
if (!ReadFile::run(schemaPath, buffer))
break;
XmlSchemaParser xsp(d, true);
if (!xsp.parse(buffer))
break;
XML_StopParser(d->p, false);
return;
}
*/
}
d->rootElement = false;
2007-09-07 23:17:30 +02:00
}
2007-09-08 00:25:30 +02:00
void XMLCALL XmlPromptGenerator::endhandler ( void *data, const XML_Char *el )
2007-09-07 23:17:30 +02:00
{
2007-09-08 00:25:30 +02:00
PromptGeneratorData *d;
d = ( PromptGeneratorData * ) data;
d->pop();
2007-09-07 23:17:30 +02:00
}
bool XmlPromptGenerator::getDtdFound()
{
2007-09-08 00:25:30 +02:00
return d->dtdFound;
2007-09-07 23:17:30 +02:00
}
2007-09-08 00:25:30 +02:00
void XmlPromptGenerator::getAttributeMap (
std::map<std::string, std::map<std::string, std::set<std::string> > >
&attributeMap )
2007-09-07 23:17:30 +02:00
{
2007-09-08 00:25:30 +02:00
attributeMap = d->attributeMap;
2007-09-07 23:17:30 +02:00
}
2007-09-08 00:25:30 +02:00
void XmlPromptGenerator::getRequiredAttributeMap (
std::map<std::string, std::set<std::string> >& requiredAttributeMap )
2007-09-07 23:17:30 +02:00
{
2007-09-08 00:25:30 +02:00
requiredAttributeMap = d->requiredAttributeMap;
2007-09-07 23:17:30 +02:00
}
2007-09-08 00:25:30 +02:00
void XmlPromptGenerator::getElementMap (
std::map<std::string, std::set<std::string> > &elementMap )
2007-09-07 23:17:30 +02:00
{
2007-09-08 00:25:30 +02:00
elementMap = d->elementMap;
2007-09-07 23:17:30 +02:00
}
2007-09-08 00:25:30 +02:00
void XmlPromptGenerator::getEntitySet (
std::set<std::string> &entitySet )
2007-09-07 23:17:30 +02:00
{
2007-09-08 00:25:30 +02:00
entitySet = d->entitySet;
2007-09-07 23:17:30 +02:00
}
// handlers for DOCTYPE handling
2007-09-08 00:25:30 +02:00
void XMLCALL XmlPromptGenerator::doctypedeclstarthandler (
void *data,
const XML_Char *doctypeName,
const XML_Char *sysid,
const XML_Char *pubid,
int has_internal_subset )
2007-09-07 23:17:30 +02:00
{
2007-09-08 00:25:30 +02:00
PromptGeneratorData *d;
d = ( PromptGeneratorData * ) data;
2007-09-07 23:17:30 +02:00
}
2007-09-08 00:25:30 +02:00
void XMLCALL XmlPromptGenerator::doctypedeclendhandler ( void *data )
2007-09-07 23:17:30 +02:00
{
2007-09-08 00:25:30 +02:00
PromptGeneratorData *d;
d = ( PromptGeneratorData * ) data;
if ( !d->elementMap.empty() )
{
d->dtdFound = true;
XML_StopParser ( d->p, false );
}
2007-09-07 23:17:30 +02:00
}
2007-09-08 00:25:30 +02:00
void XMLCALL XmlPromptGenerator::elementdeclhandler (
void *data,
const XML_Char *name,
XML_Content *model )
2007-09-07 23:17:30 +02:00
{
2007-09-08 00:25:30 +02:00
PromptGeneratorData *d;
d = ( PromptGeneratorData * ) data;
d->elementDeclRecurseLevel += 1;
std::string myElement = name;
unsigned num = model->numchildren;
for ( unsigned i = 0; i < num; i++ )
2007-09-07 23:17:30 +02:00
{
2007-09-08 00:25:30 +02:00
XML_Content myContent = model->children[i];
XML_Char *myName = myContent.name;
if ( myName )
d->elementMap[myElement].insert ( ( const char * ) myName );
else
{
// recurse
XmlPromptGenerator::elementdeclhandler ( ( void * ) d, name, &myContent );
}
}
d->elementDeclRecurseLevel -= 1;
// only one call to XML_FreeContentModel per content tree
if ( d->elementDeclRecurseLevel == 0 )
{
XML_FreeContentModel ( d->p, model );
2007-09-07 23:17:30 +02:00
}
}
2007-09-08 00:25:30 +02:00
void XMLCALL XmlPromptGenerator::attlistdeclhandler (
void *data,
const XML_Char *elname,
const XML_Char *attname,
const XML_Char *att_type,
const XML_Char *dflt,
int isrequired )
2007-09-07 23:17:30 +02:00
{
2007-09-08 00:25:30 +02:00
PromptGeneratorData *d;
d = ( PromptGeneratorData * ) data;
std::set<std::string> attributeValues;
if ( *att_type == '(' ) // change to exclude _known_ identifiers?
{
size_t len;
char *s, *word;
s = ( char * ) att_type;
while ( ( word = GetWord::run ( &s, &len ) ) != NULL )
{
std::string currentValue ( word, len );
attributeValues.insert ( currentValue );
}
}
if ( attributeValues.empty() )
{
d->attributeMap[elname][attname].insert ( "" );
return;
}
std::set<std::string>::iterator it;
for ( it = attributeValues.begin(); it != attributeValues.end(); it++ )
d->attributeMap[elname][attname].insert ( *it );
if ( isrequired )
2007-09-07 23:17:30 +02:00
{
2007-09-08 00:25:30 +02:00
d->requiredAttributeMap[elname].insert ( attname );
2007-09-07 23:17:30 +02:00
}
}
2007-09-08 00:25:30 +02:00
int XMLCALL XmlPromptGenerator::externalentityrefhandler (
XML_Parser p,
const XML_Char *context,
const XML_Char *base,
const XML_Char *systemId,
const XML_Char *publicId )
2007-09-07 23:17:30 +02:00
{
2007-09-08 00:25:30 +02:00
PromptGeneratorData *d;
d = ( PromptGeneratorData * ) p; // arg is set to user data in c'tor
2007-09-07 23:17:30 +02:00
2007-09-08 00:25:30 +02:00
std::string buffer;
2007-09-07 23:17:30 +02:00
2007-09-08 00:25:30 +02:00
// auxPath req'd?
if ( !systemId && !publicId )
2007-09-07 23:17:30 +02:00
{
2007-09-08 00:25:30 +02:00
ReadFile::run ( d->auxPath, buffer );
if ( buffer.empty() )
{
return false;
}
std::string encoding = XmlEncodingHandler::get ( buffer );
XML_Parser dtdParser = XML_ExternalEntityParserCreate ( d->p, context, encoding.c_str() );
if ( !dtdParser )
return false;
XML_SetBase ( dtdParser, d->auxPath.c_str() );
return XML_Parse ( dtdParser, buffer.c_str(), buffer.size(), true );
2007-09-07 23:17:30 +02:00
}
2007-09-08 00:25:30 +02:00
std::string stdPublicId;
if ( publicId )
stdPublicId = publicId;
std::string stdSystemId = CatalogResolver::lookupPublicId ( stdPublicId, d->catalogPath );
if ( stdSystemId.empty() && systemId )
stdSystemId = systemId;
Replace::run ( stdSystemId, "file:///", "", false );
Replace::run ( stdSystemId, "%20", " ", false );
if ( base )
2007-09-07 23:17:30 +02:00
{
2007-09-08 00:25:30 +02:00
std::string test = PathResolver::run ( stdSystemId, base );
if ( !test.empty() )
{
stdSystemId = test;
}
2007-09-07 23:17:30 +02:00
}
2007-09-08 00:25:30 +02:00
if ( !stdSystemId.empty() )
{
ReadFile::run ( stdSystemId, buffer );
}
2007-09-07 23:17:30 +02:00
2007-09-08 00:25:30 +02:00
std::string encoding = XmlEncodingHandler::get ( buffer );
XML_Parser dtdParser = XML_ExternalEntityParserCreate ( d->p, context, encoding.c_str() );//"UTF-8");
if ( !dtdParser )
return false;
2007-09-07 23:17:30 +02:00
2007-09-08 00:25:30 +02:00
wxString wideName, wideDir;
wideName = wxString ( stdSystemId.c_str(), wxConvUTF8, stdSystemId.size() );
wxFileName fn ( wideName );
wideDir = fn.GetPath();
XML_SetBase ( dtdParser, wideName.mb_str ( wxConvUTF8 ) );
2007-09-07 23:17:30 +02:00
2007-09-08 00:25:30 +02:00
return XML_Parse ( dtdParser, buffer.c_str(), buffer.size(), true );
2007-09-07 23:17:30 +02:00
}
2007-09-08 00:25:30 +02:00
void XMLCALL XmlPromptGenerator::entitydeclhandler (
void *data,
const XML_Char *entityName,
int is_parameter_entity,
const XML_Char *value,
int value_length,
const XML_Char *base,
const XML_Char *systemId,
const XML_Char *publicId,
const XML_Char *notationName )
2007-09-07 23:17:30 +02:00
{
2007-09-08 00:25:30 +02:00
PromptGeneratorData *d;
d = ( PromptGeneratorData * ) data; // arg is set to user data in c'tor
if (
entityName &&
!is_parameter_entity &&
!systemId &&
!publicId &&
!notationName )
{
d->entitySet.insert ( entityName );
}
2007-09-07 23:17:30 +02:00
}