Krita Source Code Documentation
Loading...
Searching...
No Matches
KoXmlWriter Class Reference

#include <KoXmlWriter.h>

+ Inheritance diagram for KoXmlWriter:

Classes

struct  Tag
 

Public Member Functions

void addAttribute (const char *attrName, bool value)
 
void addAttribute (const char *attrName, const char *value)
 
void addAttribute (const char *attrName, const QByteArray &value)
 Overloaded version of the one taking a const char* argument, for convenience.
 
void addAttribute (const char *attrName, const QString &value)
 
void addAttribute (const char *attrName, double value)
 
void addAttribute (const char *attrName, float value)
 
void addAttribute (const char *attrName, int value)
 
void addAttribute (const char *attrName, uint value)
 
void addCompleteElement (QIODevice *dev)
 
void addManifestEntry (const QString &fullPath, const QString &mediaType)
 
void addTextNode (const char *cstr)
 Adds a text node as a child of the current element.
 
void addTextNode (const QByteArray &cstr)
 Overloaded version of the one taking a const char* argument.
 
void addTextNode (const QString &str)
 
void endDocument ()
 Call this to terminate an XML document.
 
void endElement ()
 
 KoXmlWriter (QIODevice *dev, int indentLevel=0)
 
 Private (QIODevice *dev_, int indentLevel=0)
 
void startDocument (const char *rootElemName, const char *publicId=0, const char *systemId=0)
 
void startElement (const char *tagName, bool indentInside=true)
 
 ~KoXmlWriter ()
 Destructor.
 
 ~Private ()
 

Public Attributes

int baseIndentLevel
 
QIODevice * dev
 
char * escapeBuffer
 
char * indentBuffer
 
QStack< Tagtags
 

Private Member Functions

void closeStartElement (Tag &tag)
 
char * escapeForXML (const char *source, int length) const
 
 KoXmlWriter (const KoXmlWriter &)
 
KoXmlWriteroperator= (const KoXmlWriter &)
 
bool prepareForChild (bool indentInside=true)
 
void prepareForTextNode ()
 
void writeChar (char c)
 
void writeCString (const char *cstr)
 
void writeIndent ()
 Write out
followed by the number of spaces required.
 
- Private Member Functions inherited from Private
 Private (KisCanvas2 *c)
 

Private Attributes

Private *const d
 
- Private Attributes inherited from Private
KisCanvas2canvas
 
int displayedFrame
 
int intendedFrame
 

Detailed Description

A class for writing out XML (to any QIODevice), with a special attention on performance. The XML is being written out along the way, which avoids requiring the entire document in memory (like QDom does).

Definition at line 19 of file KoXmlWriter.cpp.

Constructor & Destructor Documentation

◆ ~Private()

KoXmlWriter::~Private ( )
inline

Definition at line 27 of file KoXmlWriter.cpp.

27 {
28 delete[] indentBuffer;
29 delete[] escapeBuffer;
30 //TODO: look at if we must delete "dev". For me we must delete it otherwise we will leak it
31 }
char * escapeBuffer
char * indentBuffer

◆ KoXmlWriter() [1/2]

KoXmlWriter::KoXmlWriter ( QIODevice * dev,
int indentLevel = 0 )
explicit

Create a KoXmlWriter instance to write out an XML document into the given QIODevice.

Definition at line 42 of file KoXmlWriter.cpp.

43 : d(new Private(dev, indentLevel))
44{
45 d->indentBuffer = new char[ s_indentBufferLength ];
46 memset(d->indentBuffer, ' ', s_indentBufferLength);
47 *d->indentBuffer = '\n'; // write newline before indentation, in one go
48
49 d->escapeBuffer = new char[s_escapeBufferLen];
50 if (!d->dev->isOpen())
51 d->dev->open(QIODevice::WriteOnly);
52
53}
static const int s_escapeBufferLen
static const int s_indentBufferLength
Private *const d
QIODevice * dev

References d, s_escapeBufferLen, and s_indentBufferLength.

◆ ~KoXmlWriter()

KoXmlWriter::~KoXmlWriter ( )

Destructor.

Definition at line 55 of file KoXmlWriter.cpp.

56{
57 delete d;
58}

References d.

◆ KoXmlWriter() [2/2]

KoXmlWriter::KoXmlWriter ( const KoXmlWriter & )
private

Member Function Documentation

◆ addAttribute() [1/8]

void KoXmlWriter::addAttribute ( const char * attrName,
bool value )
inline

Add an attribute whose value is an bool It is written as "true" or "false" based on value

Definition at line 80 of file KoXmlWriter.h.

80 {
81 addAttribute(attrName, value ? "true" : "false");
82 }
float value(const T *src, size_t ch)
void addAttribute(const char *attrName, const QString &value)
Definition KoXmlWriter.h:61

References value().

◆ addAttribute() [2/8]

void KoXmlWriter::addAttribute ( const char * attrName,
const char * value )

Add an attribute to the current element.

Definition at line 213 of file KoXmlWriter.cpp.

214{
215 writeChar(' ');
216 writeCString(attrName);
217 writeCString("=\"");
218 char* escaped = escapeForXML(value, -1);
220 if (escaped != d->escapeBuffer)
221 delete[] escaped;
222 writeChar('"');
223}
char * escapeForXML(const char *source, int length) const
void writeCString(const char *cstr)
void writeChar(char c)
const QMap< char, char > escaped

References d, escaped, escapeForXML(), value(), writeChar(), and writeCString().

◆ addAttribute() [3/8]

void KoXmlWriter::addAttribute ( const char * attrName,
const QByteArray & value )

Overloaded version of the one taking a const char* argument, for convenience.

Definition at line 200 of file KoXmlWriter.cpp.

201{
202 // Same as the const char* one, but here we know the size
203 writeChar(' ');
204 writeCString(attrName);
205 writeCString("=\"");
206 char* escaped = escapeForXML(value.constData(), value.size());
208 if (escaped != d->escapeBuffer)
209 delete[] escaped;
210 writeChar('"');
211}

References d, escaped, escapeForXML(), value(), writeChar(), and writeCString().

◆ addAttribute() [4/8]

void KoXmlWriter::addAttribute ( const char * attrName,
const QString & value )
inline

Overloaded version of addAttribute( const char*, const char* ), which is a bit slower because it needs to convert value to utf8 first.

Definition at line 61 of file KoXmlWriter.h.

61 {
62 addAttribute(attrName, value.toUtf8());
63 }

References value().

◆ addAttribute() [5/8]

void KoXmlWriter::addAttribute ( const char * attrName,
double value )

Add an attribute whose value is a floating point number The number is written out with the highest possible precision (unlike QString::number and setNum, which default to 6 digits)

Definition at line 225 of file KoXmlWriter.cpp.

226{
228}
QString toString(const QString &value)

References addAttribute(), KisDomUtils::toString(), and value().

◆ addAttribute() [6/8]

void KoXmlWriter::addAttribute ( const char * attrName,
float value )

Add an attribute whose value is a floating point number The number is written out with the highest possible precision (unlike QString::number and setNum, which default to 6 digits)

Definition at line 230 of file KoXmlWriter.cpp.

231{
233}

References addAttribute(), KisDomUtils::toString(), and value().

◆ addAttribute() [7/8]

void KoXmlWriter::addAttribute ( const char * attrName,
int value )
inline

Add an attribute whose value is an integer

Definition at line 67 of file KoXmlWriter.h.

67 {
68 addAttribute(attrName, QByteArray::number(value));
69 }

References value().

◆ addAttribute() [8/8]

void KoXmlWriter::addAttribute ( const char * attrName,
uint value )
inline

Add an attribute whose value is an unsigned integer

Definition at line 73 of file KoXmlWriter.h.

73 {
74 addAttribute(attrName, QByteArray::number(value));
75 }

References value().

◆ addCompleteElement()

void KoXmlWriter::addCompleteElement ( QIODevice * dev)

This is quite a special-purpose method, not for everyday use. It adds a complete element (with its attributes and child elements) as a child of the current element. The iodevice is supposed to be escaped for XML already, so it will usually come from another KoXmlWriter. This is usually used with KTempFile.

Definition at line 128 of file KoXmlWriter.cpp.

129{
131 const bool wasOpen = indev->isOpen();
132 // Always (re)open the device in readonly mode, it might be
133 // already open but for writing, and we need to rewind.
134 const bool openOk = indev->open(QIODevice::ReadOnly);
135 Q_ASSERT(openOk);
136 if (!openOk) {
137 warnStore << "Failed to re-open the device! wasOpen=" << wasOpen;
138 return;
139 }
140
141 QString indentString;
142 indentString.fill((' '), d->tags.size() + d->baseIndentLevel);
143 QByteArray indentBuf(indentString.toUtf8());
144
145 QByteArray buffer;
146 while (!indev->atEnd()) {
147 buffer = indev->readLine();
148
149 d->dev->write(indentBuf);
150 d->dev->write(buffer);
151 }
152
153 if (!wasOpen) {
154 // Restore initial state
155 indev->close();
156 }
157}
#define warnStore
Definition StoreDebug.h:16
bool prepareForChild(bool indentInside=true)

References d, prepareForChild(), and warnStore.

◆ addManifestEntry()

void KoXmlWriter::addManifestEntry ( const QString & fullPath,
const QString & mediaType )

Special helper for writing "manifest" files This is equivalent to startElement/2*addAttribute/endElement This API will probably have to change (or not be used anymore) when we add support for encrypting/signing.

Note
OASIS-specific

Definition at line 316 of file KoXmlWriter.cpp.

317{
318 startElement("manifest:file-entry");
319 addAttribute("manifest:media-type", mediaType);
320 addAttribute("manifest:full-path", fullPath);
321 endElement();
322}
void startElement(const char *tagName, bool indentInside=true)
void endElement()

References addAttribute(), endElement(), and startElement().

◆ addTextNode() [1/3]

void KoXmlWriter::addTextNode ( const char * cstr)

Adds a text node as a child of the current element.

This is appends the literal content of str to the contents of the element. E.g. addTextNode( "foo" ) inside a <p> element gives <p>foo</p>, and startElement( "b" ); endElement( "b" ); addTextNode( "foo" ) gives <p><b/>foo</p>

Definition at line 191 of file KoXmlWriter.cpp.

192{
194 char* escaped = escapeForXML(cstr, -1);
196 if (escaped != d->escapeBuffer)
197 delete[] escaped;
198}
void prepareForTextNode()

References d, escaped, escapeForXML(), prepareForTextNode(), and writeCString().

◆ addTextNode() [2/3]

void KoXmlWriter::addTextNode ( const QByteArray & cstr)

Overloaded version of the one taking a const char* argument.

Definition at line 181 of file KoXmlWriter.cpp.

182{
183 // Same as the const char* version below, but here we know the size
185 char* escaped = escapeForXML(cstr.constData(), cstr.size());
187 if (escaped != d->escapeBuffer)
188 delete[] escaped;
189}

References d, escaped, escapeForXML(), prepareForTextNode(), and writeCString().

◆ addTextNode() [3/3]

void KoXmlWriter::addTextNode ( const QString & str)
inline

Overloaded version of addTextNode( const char* ), which is a bit slower because it needs to convert str to utf8 first.

Definition at line 115 of file KoXmlWriter.h.

115 {
116 addTextNode(str.toUtf8());
117 }
void addTextNode(const QString &str)

◆ closeStartElement()

void KoXmlWriter::closeStartElement ( Tag & tag)
inlineprivate

Definition at line 192 of file KoXmlWriter.h.

192 {
193 if (!tag.openingTagClosed) {
194 tag.openingTagClosed = true;
195 writeChar('>');
196 }
197 }

References KoXmlWriter::Tag::openingTagClosed.

◆ endDocument()

void KoXmlWriter::endDocument ( )

Call this to terminate an XML document.

Definition at line 78 of file KoXmlWriter.cpp.

79{
80 // just to do exactly like QDom does (newline at end of file).
81 writeChar('\n');
82 Q_ASSERT(d->tags.isEmpty());
83}

References d, and writeChar().

◆ endElement()

void KoXmlWriter::endElement ( )

Terminate the current element. After this you should start a new one (sibling), add a sibling text node, or close another one (end of siblings).

Definition at line 159 of file KoXmlWriter.cpp.

160{
161 if (d->tags.isEmpty())
162 warnStore << "EndElement() was called more times than startElement(). "
163 "The generated XML will be invalid! "
164 "Please report this bug (by saving the document to another format...)" << Qt::endl;
165
166 Tag tag = d->tags.pop();
167
168 if (!tag.hasChildren) {
169 writeCString("/>");
170 } else {
171 if (tag.indentInside && !tag.lastChildIsText) {
172 writeIndent();
173 }
174 writeCString("</");
175 Q_ASSERT(tag.tagName != 0);
176 writeCString(tag.tagName);
177 writeChar('>');
178 }
179}
void writeIndent()
Write out followed by the number of spaces required.

References d, KoXmlWriter::Tag::hasChildren, KoXmlWriter::Tag::indentInside, KoXmlWriter::Tag::lastChildIsText, KoXmlWriter::Tag::tagName, warnStore, writeChar(), writeCString(), and writeIndent().

◆ escapeForXML()

char * KoXmlWriter::escapeForXML ( const char * source,
int length = -1 ) const
private

Definition at line 245 of file KoXmlWriter.cpp.

246{
247 // we're going to be pessimistic on char length; so lets make the outputLength less
248 // the amount one char can take: 6
249 char* destBoundary = d->escapeBuffer + s_escapeBufferLen - 6;
250 char* destination = d->escapeBuffer;
251 char* output = d->escapeBuffer;
252 const char* src = source; // src moves, source remains
253 for (;;) {
254 if (destination >= destBoundary) {
255 // When we come to realize that our escaped string is going to
256 // be bigger than the escape buffer (this shouldn't happen very often...),
257 // we drop the idea of using it, and we allocate a bigger buffer.
258 // Note that this if() can only be hit once per call to the method.
259 if (length == -1)
260 length = qstrlen(source); // expensive...
261 uint newLength = length * 6 + 1; // worst case. 6 is due to &quot; and &apos;
262 char* buffer = new char[ newLength ];
263 destBoundary = buffer + newLength;
264 uint amountOfCharsAlreadyCopied = destination - d->escapeBuffer;
265 memcpy(buffer, d->escapeBuffer, amountOfCharsAlreadyCopied);
266 output = buffer;
267 destination = buffer + amountOfCharsAlreadyCopied;
268 }
269 switch (*src) {
270 case 60: // <
271 memcpy(destination, "&lt;", 4);
272 destination += 4;
273 break;
274 case 62: // >
275 memcpy(destination, "&gt;", 4);
276 destination += 4;
277 break;
278 case 34: // "
279 memcpy(destination, "&quot;", 6);
280 destination += 6;
281 break;
282#if 0 // needed?
283 case 39: // '
284 memcpy(destination, "&apos;", 6);
285 destination += 6;
286 break;
287#endif
288 case 38: // &
289 memcpy(destination, "&amp;", 5);
290 destination += 5;
291 break;
292 case 0:
293 *destination = '\0';
294 return output;
295 // Control codes accepted in XML 1.0 documents.
296 case 9:
297 case 10:
298 case 13:
299 *destination++ = *src++;
300 continue;
301 default:
302 // Don't add control codes not accepted in XML 1.0 documents.
303 if (*src > 0 && *src < 32) {
304 ++src;
305 } else {
306 *destination++ = *src++;
307 }
308 continue;
309 }
310 ++src;
311 }
312 // NOTREACHED (see case 0)
313 return output;
314}
qreal length(const QPointF &vec)
Definition Ellipse.cc:82
KisMagneticGraph::vertex_descriptor source(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g)
unsigned int uint

References d, length(), s_escapeBufferLen, and source().

◆ operator=()

KoXmlWriter & KoXmlWriter::operator= ( const KoXmlWriter & )
private

◆ prepareForChild()

bool KoXmlWriter::prepareForChild ( bool indentInside = true)
private

Definition at line 86 of file KoXmlWriter.cpp.

87{
88 if (!d->tags.isEmpty()) {
89 Tag& parent = d->tags.top();
90 if (!parent.hasChildren) {
91 closeStartElement(parent);
92 parent.hasChildren = true;
93 parent.lastChildIsText = false;
94 }
95 if (parent.indentInside && indentInside) {
97 }
98 return parent.indentInside && indentInside;
99 }
100 return indentInside;
101}
void closeStartElement(Tag &tag)
ChildIterator< value_type, is_const > parent(const ChildIterator< value_type, is_const > &it)
Definition KisForest.h:327

References closeStartElement(), d, and writeIndent().

◆ prepareForTextNode()

void KoXmlWriter::prepareForTextNode ( )
private

Definition at line 103 of file KoXmlWriter.cpp.

104{
105 if (d->tags.isEmpty())
106 return;
107 Tag& parent = d->tags.top();
108 if (!parent.hasChildren) {
109 closeStartElement(parent);
110 parent.hasChildren = true;
111 parent.lastChildIsText = true;
112 }
113}

References closeStartElement(), and d.

◆ Private()

KoXmlWriter::Private ( QIODevice * dev_,
int indentLevel = 0 )
inline

Definition at line 22 of file KoXmlWriter.cpp.

23 : dev(dev_)
24 , baseIndentLevel(indentLevel)
25 {}

◆ startDocument()

void KoXmlWriter::startDocument ( const char * rootElemName,
const char * publicId = 0,
const char * systemId = 0 )

Start the XML document. This writes out the <?xml?> tag with utf8 encoding, and the DOCTYPE.

Parameters
rootElemNamethe name of the root element, used in the DOCTYPE tag.
publicIdthe public identifier, e.g. "-//OpenOffice.org//DTD OfficeDocument 1.0//EN"
systemIdthe system identifier, e.g. "office.dtd" or a full URL to it.

Definition at line 60 of file KoXmlWriter.cpp.

61{
62 Q_ASSERT(d->tags.isEmpty());
63 writeCString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
64 // There isn't much point in a doctype if there's no DTD to refer to
65 // (I'm told that files that are validated by a RelaxNG schema cannot refer to the schema)
66 if (publicId) {
67 writeCString("<!DOCTYPE ");
68 writeCString(rootElemName);
69 writeCString(" PUBLIC \"");
70 writeCString(publicId);
71 writeCString("\" \"");
72 writeCString(systemId);
73 writeCString("\"");
74 writeCString(">\n");
75 }
76}

References d, and writeCString().

◆ startElement()

void KoXmlWriter::startElement ( const char * tagName,
bool indentInside = true )

Start a new element, as a child of the current element.

Parameters
tagNamethe name of the tag.
indentInsideif set to false, there will be no indentation inside this tag. This is useful for elements where whitespace matters.

Definition at line 115 of file KoXmlWriter.cpp.

116{
117 Q_ASSERT(tagName != 0);
118
119 // Tell parent that it has children
120 indentInside = prepareForChild(indentInside);
121
122 d->tags.push(Tag(tagName, indentInside));
123 writeChar('<');
124 writeCString(tagName);
125 //kDebug(s_area) << tagName;
126}

References d, prepareForChild(), writeChar(), and writeCString().

◆ writeChar()

void KoXmlWriter::writeChar ( char c)
private

Definition at line 330 of file KoXmlWriter.cpp.

330 {
331 d->dev->putChar(c);
332}

References d.

◆ writeCString()

void KoXmlWriter::writeCString ( const char * cstr)
private

Definition at line 325 of file KoXmlWriter.cpp.

325 {
326 d->dev->write(cstr, qstrlen(cstr));
327}

References d.

◆ writeIndent()

void KoXmlWriter::writeIndent ( )
private

Write out
followed by the number of spaces required.

Definition at line 235 of file KoXmlWriter.cpp.

236{
237 // +1 because of the leading '\n'
238 d->dev->write(d->indentBuffer, qMin(d->tags.size() + d->baseIndentLevel + 1,
240}

References d, and s_indentBufferLength.

Member Data Documentation

◆ baseIndentLevel

int KoXmlWriter::baseIndentLevel

Definition at line 35 of file KoXmlWriter.cpp.

◆ d

Private* const KoXmlWriter::d
private

Definition at line 203 of file KoXmlWriter.h.

◆ dev

QIODevice* KoXmlWriter::dev

Definition at line 33 of file KoXmlWriter.cpp.

◆ escapeBuffer

char* KoXmlWriter::escapeBuffer

Definition at line 39 of file KoXmlWriter.cpp.

◆ indentBuffer

char* KoXmlWriter::indentBuffer

Definition at line 37 of file KoXmlWriter.cpp.

◆ tags

QStack<Tag> KoXmlWriter::tags

Definition at line 34 of file KoXmlWriter.cpp.


The documentation for this class was generated from the following files: