20#include "KoXmlWriter.h"
24#include <tqiodevice.h>
27static const int s_indentBufferLength = 100;
30 : m_dev( dev ), m_baseIndentLevel( indentLevel )
35void KoXmlWriter::init()
37 m_indentBuffer = new char[ s_indentBufferLength ];
38 memset( m_indentBuffer, ' ', s_indentBufferLength );
39 *m_indentBuffer = '\n';
41 m_escapeBuffer = new char[s_escapeBufferLen];
46 delete[] m_indentBuffer;
47 delete[] m_escapeBuffer;
52 Q_ASSERT( m_tags.isEmpty() );
53 writeCString( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
57 writeCString( "<!DOCTYPE " );
58 writeCString( rootElemName );
59 writeCString( " PUBLIC \"" );
60 writeCString( publicId );
61 writeCString( "\" \"" );
62 writeCString( systemId );
64 writeCString( ">\n" );
72 Q_ASSERT( m_tags.isEmpty() );
76bool KoXmlWriter::prepareForChild()
78 if ( !m_tags.isEmpty() ) {
79 Tag& parent = m_tags.top();
80 if ( !parent.hasChildren ) {
81 closeStartElement( parent );
82 parent.hasChildren = true;
83 parent.lastChildIsText = false;
85 if ( parent.indentInside ) {
88 return parent.indentInside;
93void KoXmlWriter::prepareForTextNode()
95 Tag& parent = m_tags.top();
96 if ( !parent.hasChildren ) {
97 closeStartElement( parent );
98 parent.hasChildren = true;
99 parent.lastChildIsText = true;
105 Q_ASSERT( tagName != 0 );
108 bool parentIndent = prepareForChild();
110 m_tags.push( Tag( tagName, parentIndent && indentInside ) );
112 writeCString( tagName );
119 writeCString( cstr );
126 bool openOk = indev->open( IO_ReadOnly );
130 static const int MAX_CHUNK_SIZE = 8*1024;
131 TQByteArray buffer(MAX_CHUNK_SIZE);
132 while ( !indev->atEnd() ) {
133 TQ_LONG len = indev->readBlock( buffer.data(), buffer.size() );
136 m_dev->writeBlock( buffer.data(), len );
142 if ( m_tags.isEmpty() )
143 kdWarning() << "Ouch, endElement() was called more times than startElement(). "
144 "The generated XML will be invalid! "
145 "Please report this bug (by saving the document to another format...)" << endl;
147 Tag tag = m_tags.pop();
149 if ( !tag.hasChildren ) {
150 writeCString( "/>" );
153 if ( tag.indentInside && !tag.lastChildIsText ) {
156 writeCString( "</" );
157 Q_ASSERT( tag.tagName != 0 );
158 writeCString( tag.tagName );
165 prepareForTextNode();
166 char* escaped = escapeForXML( cstr, -1 );
167 writeCString( escaped );
168 if(escaped != m_escapeBuffer)
174 prepareForTextNode();
175 writeCString( "<?" );
183 writeCString( attrName );
185 char* escaped = escapeForXML( value, -1 );
186 writeCString( escaped );
187 if(escaped != m_escapeBuffer)
195 str.setNum( value, 'g', DBL_DIG );
202 str.setNum( value, 'g', DBL_DIG );
207void KoXmlWriter::writeIndent()
210 m_dev->writeBlock( m_indentBuffer, kMin( indentLevel() + 1,
211 s_indentBufferLength ) );
214void KoXmlWriter::writeString( const TQString& str )
217 TQCString cstr = str.utf8();
218 m_dev->writeBlock( cstr.data(), cstr.size() - 1 );
223char* KoXmlWriter::escapeForXML( const char* source, int length = -1 ) const
227 char* destBoundary = m_escapeBuffer + s_escapeBufferLen - 6;
228 char* destination = m_escapeBuffer;
229 char* output = m_escapeBuffer;
230 const char* src = source;
232 if(destination >= destBoundary) {
238 length = tqstrlen( source );
239 uint newLength = length * 6 + 1;
240 char* buffer = new char[ newLength ];
241 destBoundary = buffer + newLength;
242 uint amountOfCharsAlreadyCopied = destination - m_escapeBuffer;
243 memcpy( buffer, m_escapeBuffer, amountOfCharsAlreadyCopied );
245 destination = buffer + amountOfCharsAlreadyCopied;
249 memcpy( destination, "<", 4 );
253 memcpy( destination, ">", 4 );
257 memcpy( destination, """, 6 );
262 memcpy( destination, "'", 6 );
267 memcpy( destination, "&", 5 );
274 *destination++ = *src++;
347 TQMap<int, int> tabCache;
353 uint len = text.length();
355 bool leadingSpace = false;
362 for ( uint i = 0; i < len ; ++i ) {
365 if ( nrSpaces > 0 ) {
377 if ( nrSpaces > 0 ) {
378 if ( !str.isEmpty() )
388 leadingSpace = false;
390 switch ( ch.unicode() ) {
392 if ( !str.isEmpty() )
396 if ( tabCache.contains( i ) )
401 if ( !str.isEmpty() )
418 if ( !str.isEmpty() ) {
421 if ( nrSpaces > 0 ) {
~KoXmlWriter() Destructor.
void addConfigItem(const TQString &configName, const TQString &value) Special helper for writing config item into settings.xml.
void startElement(const char *tagName, bool indentInside=true) Start a new element, as a child of the current element.
void addTextNode(const TQString &str) Overloaded version of addTextNode( const char* ), which is a bit slower because it needs to convert s...
void addAttributePt(const char *attrName, double value) Add an attribute which represents a distance, measured in pt The number is written out with the highe...
void endDocument() Call this to terminate an XML document.
void addTextSpan(const TQString &text) Adds a text span as nodes of the current element.
KoXmlWriter(TQIODevice *dev, int indentLevel=0) Create a KoXmlWriter instance to write out an XML document into the given TQIODevice.
void startDocument(const char *rootElemName, const char *publicId=0, const char *systemId=0) Start the XML document.
void endElement() Terminate the current element.
void addCompleteElement(const char *cstr) This is quite a special-purpose method, not for everyday use.
void addProcessingInstruction(const char *cstr) Adds a processing instruction.
void addManifestEntry(const TQString &fullPath, const TQString &mediaType) Special helper for writing "manifest" files This is equivalent to startElement/2*addAttribute/endElem...
void addAttribute(const char *attrName, const TQString &value) Overloaded version of addAttribute( const char*, const char* ), which is a bit slower because it need...
|