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

221 lines
5.6 KiB
C++

/*
* 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; either version 2
* of the License, or (at your option) any later version.
*
* 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
*/
#include <set>
#include <string>
#include <vector>
#include <stdexcept>
#include <expat.h>
#include "housestylewriter.h"
#include "contexthandler.h"
using namespace std;
HouseStyleWriter::HouseStyleWriter ( vector<ContextMatch> &v ) :
hswd ( new HouseStyleWriterData() )
{
set<size_t> elementSet;
size_t vectorsize = v.size();
for ( size_t i = 0; i < vectorsize; ++i )
elementSet.insert ( v[i].elementCount );
hswd->setState ( STATE_UNKNOWN );
hswd->v = v;
hswd->elementSet = elementSet;
XML_SetUserData ( p, hswd.get() );
XML_SetElementHandler ( p, start, end );
XML_SetCharacterDataHandler ( p, characterdata );
XML_SetXmlDeclHandler ( p, xmldecl );
XML_SetCdataSectionHandler ( p, cdatastart, cdataend );
XML_SetDefaultHandler ( p, defaulthandler );
}
HouseStyleWriter::~HouseStyleWriter()
{}
string HouseStyleWriter::getOutput()
{
return hswd->output;
}
void XMLCALL HouseStyleWriter::start ( void *data, const XML_Char *el, const XML_Char **attr )
{
HouseStyleWriterData *hswd;
hswd = ( HouseStyleWriterData * ) data;
hswd->setState ( STATE_ON_START );
if ( hswd->textnode.size() )
{
if ( hswd->elementSet.count ( hswd->getCount() ) )
modify ( hswd->v, hswd->textnode, hswd->getCount() );
hswd->output += xmliseTextNode ( hswd->textnode );
hswd->textnode = "";
}
hswd->output += '<';
hswd->output += el;
for ( ; *attr; attr += 2 )
{
hswd->output += ' ';
hswd->output += *attr;
hswd->output += "=\"";
hswd->output += xmliseAttribute ( * ( attr + 1 ) );
hswd->output += '"';
}
hswd->output += '>';
}
void XMLCALL HouseStyleWriter::end ( void *data, const XML_Char *el )
{
HouseStyleWriterData *hswd;
hswd = ( HouseStyleWriterData * ) data;
//++(hswd->elementCount);
hswd->setState ( STATE_ON_END );
if ( hswd->textnode.size() )
{
if ( hswd->elementSet.count ( hswd->getCount() ) )
modify ( hswd->v, hswd->textnode, hswd->getCount() );
hswd->output += xmliseTextNode ( hswd->textnode );
hswd->textnode = "";
}
hswd->output += "</";
hswd->output += el;
hswd->output += '>';
}
void XMLCALL HouseStyleWriter::characterdata ( void *data, const XML_Char *s, int len )
{
HouseStyleWriterData *hswd;
hswd = ( HouseStyleWriterData * ) data;
hswd->textnode.append ( s, len );
}
void XMLCALL HouseStyleWriter::xmldecl (
void *data,
const XML_Char *version,
const XML_Char *encoding,
int standalone )
{
HouseStyleWriterData *hswd;
hswd = ( HouseStyleWriterData * ) data;
hswd->output += "<?xml version=\"";
hswd->output += version;
hswd->output += "\" encoding=\"UTF-8\"";
if ( standalone != -1 )
{
hswd->output += " standalone=\"";
hswd->output += ( standalone ) ? "yes" : "no";
hswd->output += "\"";
}
hswd->output += "?>";
}
void XMLCALL HouseStyleWriter::cdatastart ( void *data )
{
HouseStyleWriterData *hswd;
hswd = ( HouseStyleWriterData * ) data;
hswd->setState ( STATE_ON_CDATA_START );
if ( hswd->textnode.size() )
{
if ( hswd->elementSet.count ( hswd->getCount() ) )
modify ( hswd->v, hswd->textnode, hswd->getCount() );
hswd->output += hswd->textnode;
hswd->textnode = "";
}
hswd->output += "<![CDATA[";
}
void XMLCALL HouseStyleWriter::cdataend ( void *data )
{
HouseStyleWriterData *hswd;
hswd = ( HouseStyleWriterData * ) data;
hswd->setState ( STATE_ON_CDATA_END );
if ( hswd->textnode.size() )
{
if ( hswd->elementSet.count ( hswd->getCount() ) )
modify ( hswd->v, hswd->textnode, hswd->getCount() );
hswd->output += hswd->textnode;
hswd->textnode = "";
}
hswd->output += "]]>";
}
void XMLCALL HouseStyleWriter::defaulthandler (
void *data,
const XML_Char *s,
int len )
{
HouseStyleWriterData *hswd;
hswd = ( HouseStyleWriterData * ) data;
hswd->output.append ( s, len );
}
void HouseStyleWriter::modify (
vector<ContextMatch> &v,
string &buffer,
unsigned elementCount )
{
int vectorsize, os_adjust, exclusion;
vectorsize = v.size();
os_adjust = exclusion = 0;
string cmp1, cmp2;
for ( int i = 0; i < vectorsize; ++i )
{
unsigned vectorElementCount = v[i].elementCount;
if ( vectorElementCount < elementCount )
continue;
else if ( vectorElementCount > elementCount )
break;
else if ( vectorElementCount == elementCount )
{
int offset = ( int ) v[i].offset + os_adjust;
if ( offset < exclusion )
continue;
// check match is as expected
try
{
cmp1 = v[i].match;
cmp2 = buffer.substr ( offset, v[i].match.size() );
}
catch ( std::exception& e )
{
continue;
}
if ( cmp1.compare ( cmp2 ) )
continue;
buffer.replace ( offset, v[i].match.size(), v[i].replace.c_str() );
os_adjust += v[i].replace.size() - v[i].match.size();
exclusion = offset + v[i].replace.size();
}
}
}