Coverage Report

Created: 2025-11-23 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/poco/XML/src/DOMBuilder.cpp
Line
Count
Source
1
//
2
// DOMBuilder.cpp
3
//
4
// Library: XML
5
// Package: DOM
6
// Module:  DOMBuilder
7
//
8
// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
9
// and Contributors.
10
//
11
// SPDX-License-Identifier: BSL-1.0
12
//
13
14
15
#include "Poco/DOM/DOMBuilder.h"
16
#include "Poco/DOM/Document.h"
17
#include "Poco/DOM/DocumentType.h"
18
#include "Poco/DOM/CharacterData.h"
19
#include "Poco/DOM/Text.h"
20
#include "Poco/DOM/Comment.h"
21
#include "Poco/DOM/CDATASection.h"
22
#include "Poco/DOM/Element.h"
23
#include "Poco/DOM/Attr.h"
24
#include "Poco/DOM/Entity.h"
25
#include "Poco/DOM/EntityReference.h"
26
#include "Poco/DOM/Notation.h"
27
#include "Poco/DOM/ProcessingInstruction.h"
28
#include "Poco/DOM/AutoPtr.h"
29
#include "Poco/SAX/XMLReader.h"
30
#include "Poco/SAX/AttributesImpl.h"
31
#include "Poco/XML/XMLException.h"
32
33
34
namespace Poco {
35
namespace XML {
36
37
38
const XMLString DOMBuilder::EMPTY_STRING;
39
40
41
DOMBuilder::DOMBuilder(XMLReader& xmlReader, NamePool* pNamePool, std::size_t maxDepth):
42
26.0k
  _xmlReader(xmlReader),
43
26.0k
  _pNamePool(pNamePool),
44
26.0k
  _maxDepth(maxDepth),
45
26.0k
  _pDocument(nullptr),
46
26.0k
  _pParent(nullptr),
47
26.0k
  _pPrevious(nullptr),
48
26.0k
  _inCDATA(false),
49
26.0k
  _namespaces(true),
50
26.0k
  _depth(0)
51
26.0k
{
52
26.0k
  _xmlReader.setContentHandler(this);
53
26.0k
  _xmlReader.setDTDHandler(this);
54
26.0k
  _xmlReader.setProperty(XMLReader::PROPERTY_LEXICAL_HANDLER, static_cast<LexicalHandler*>(this));
55
56
26.0k
  if (_pNamePool) _pNamePool->duplicate();
57
26.0k
}
58
59
60
DOMBuilder::~DOMBuilder()
61
26.0k
{
62
26.0k
  if (_pNamePool) _pNamePool->release();
63
26.0k
}
64
65
66
Document* DOMBuilder::parse(const XMLString& uri)
67
0
{
68
0
  setupParse();
69
0
  _pDocument->suspendEvents();
70
0
  try
71
0
  {
72
0
    _xmlReader.parse(uri);
73
0
  }
74
0
  catch (...)
75
0
  {
76
0
    _pDocument->release();
77
0
    _pDocument = nullptr;
78
0
    _pParent   = nullptr;
79
0
    _pPrevious = nullptr;
80
0
    throw;
81
0
  }
82
0
  _pDocument->resumeEvents();
83
0
  _pDocument->collectGarbage();
84
0
  return _pDocument;
85
0
}
86
87
88
Document* DOMBuilder::parse(InputSource* pInputSource)
89
0
{
90
0
  setupParse();
91
0
  _pDocument->suspendEvents();
92
0
  try
93
0
  {
94
0
    _xmlReader.parse(pInputSource);
95
0
  }
96
0
  catch (...)
97
0
  {
98
0
    _pDocument->release();
99
0
    _pDocument = nullptr;
100
0
    _pParent   = nullptr;
101
0
    _pPrevious = nullptr;
102
0
    throw;
103
0
  }
104
0
  _pDocument->resumeEvents();
105
0
  _pDocument->collectGarbage();
106
0
  return _pDocument;
107
0
}
108
109
110
Document* DOMBuilder::parseMemoryNP(const char* xml, std::size_t size)
111
26.0k
{
112
26.0k
  setupParse();
113
26.0k
  _pDocument->suspendEvents();
114
26.0k
  try
115
26.0k
  {
116
26.0k
    _xmlReader.parseMemoryNP(xml, size);
117
26.0k
  }
118
26.0k
  catch (...)
119
26.0k
  {
120
25.9k
    _pDocument->release();
121
25.9k
    _pDocument = nullptr;
122
25.9k
    _pParent   = nullptr;
123
25.9k
    _pPrevious = nullptr;
124
25.9k
    throw;
125
25.9k
  }
126
118
  _pDocument->resumeEvents();
127
118
  _pDocument->collectGarbage();
128
118
  return _pDocument;
129
26.0k
}
130
131
132
void DOMBuilder::setupParse()
133
26.0k
{
134
26.0k
  _pDocument  = new Document(_pNamePool);
135
26.0k
  _pParent    = _pDocument;
136
26.0k
  _pPrevious  = nullptr;
137
26.0k
  _inCDATA    = false;
138
26.0k
  _namespaces = _xmlReader.getFeature(XMLReader::FEATURE_NAMESPACES);
139
26.0k
}
140
141
142
inline void DOMBuilder::appendNode(AbstractNode* pNode)
143
2.19M
{
144
2.19M
  if (_pPrevious && _pPrevious != _pParent)
145
1.89M
  {
146
1.89M
    _pPrevious->_pNext = pNode;
147
1.89M
    pNode->_pParent = _pParent;
148
1.89M
    pNode->duplicate();
149
1.89M
  }
150
303k
  else _pParent->appendChild(pNode);
151
2.19M
  _pPrevious = pNode;
152
2.19M
}
153
154
155
void DOMBuilder::notationDecl(const XMLString& name, const XMLString* publicId, const XMLString* systemId)
156
35.5k
{
157
35.5k
  DocumentType* pDoctype = _pDocument->getDoctype();
158
35.5k
  if (pDoctype)
159
35.5k
  {
160
35.5k
    AutoPtr<Notation> pNotation = _pDocument->createNotation(name, (publicId ? *publicId : EMPTY_STRING), (systemId ? *systemId : EMPTY_STRING));
161
35.5k
    pDoctype->appendChild(pNotation);
162
35.5k
  }
163
35.5k
}
164
165
166
void DOMBuilder::unparsedEntityDecl(const XMLString& name, const XMLString* publicId, const XMLString& systemId, const XMLString& notationName)
167
835
{
168
835
  DocumentType* pDoctype = _pDocument->getDoctype();
169
835
  if (pDoctype)
170
835
  {
171
835
    AutoPtr<Entity> pEntity = _pDocument->createEntity(name, publicId ? *publicId : EMPTY_STRING, systemId, notationName);
172
835
    pDoctype->appendChild(pEntity);
173
835
  }
174
835
}
175
176
177
void DOMBuilder::setDocumentLocator(const Locator* loc)
178
26.0k
{
179
26.0k
}
180
181
182
void DOMBuilder::startDocument()
183
26.0k
{
184
26.0k
}
185
186
187
void DOMBuilder::endDocument()
188
118
{
189
118
}
190
191
192
void DOMBuilder::startElement(const XMLString& uri, const XMLString& localName, const XMLString& qname, const Attributes& attributes)
193
998k
{
194
998k
  ++_depth;
195
998k
  if (_maxDepth > 0 && _depth > _maxDepth) throw XMLException("Maximum element depth exceeded");
196
197
997k
  AutoPtr<Element> pElem = _namespaces ? _pDocument->createElementNS(uri, qname.empty() ? localName : qname) : _pDocument->createElement(qname);
198
199
997k
  const AttributesImpl& attrs = dynamic_cast<const AttributesImpl&>(attributes);
200
997k
  Attr* pPrevAttr = nullptr;
201
997k
  for (const auto& attr: attrs)
202
395k
  {
203
395k
    AutoPtr<Attr> pAttr = new Attr(_pDocument, nullptr, attr.namespaceURI, attr.localName, attr.qname, attr.value, attr.specified);
204
395k
    pPrevAttr = pElem->addAttributeNodeNP(pPrevAttr, pAttr);
205
395k
  }
206
997k
  appendNode(pElem);
207
997k
  _pParent = pElem;
208
997k
}
209
210
211
void DOMBuilder::endElement(const XMLString& uri, const XMLString& localName, const XMLString& qname)
212
720k
{
213
720k
  --_depth;
214
215
720k
  _pPrevious = _pParent;
216
720k
  _pParent   = static_cast<AbstractContainerNode*>(_pParent->parentNode());
217
720k
}
218
219
220
void DOMBuilder::characters(const XMLChar ch[], int start, int length)
221
5.66M
{
222
5.66M
  if (_inCDATA)
223
2.14M
  {
224
2.14M
    if (_pPrevious && _pPrevious->nodeType() == Node::CDATA_SECTION_NODE)
225
2.13M
    {
226
2.13M
      static_cast<CDATASection*>(_pPrevious)->appendData(XMLString(ch + start, length));
227
2.13M
    }
228
10.0k
    else
229
10.0k
    {
230
10.0k
      AutoPtr<CDATASection> pCDATA = _pDocument->createCDATASection(XMLString(ch + start, length));
231
10.0k
      appendNode(pCDATA);
232
10.0k
    }
233
2.14M
  }
234
3.51M
  else
235
3.51M
  {
236
3.51M
    if (_pPrevious && _pPrevious->nodeType() == Node::TEXT_NODE)
237
2.91M
    {
238
2.91M
      static_cast<Text*>(_pPrevious)->appendData(XMLString(ch + start, length));
239
2.91M
    }
240
602k
    else
241
602k
    {
242
602k
      AutoPtr<Text> pText = _pDocument->createTextNode(XMLString(ch + start, length));
243
602k
      appendNode(pText);
244
602k
    }
245
3.51M
  }
246
5.66M
}
247
248
249
void DOMBuilder::ignorableWhitespace(const XMLChar ch[], int start, int length)
250
0
{
251
0
  characters(ch, start, length);
252
0
}
253
254
255
void DOMBuilder::processingInstruction(const XMLString& target, const XMLString& data)
256
168k
{
257
168k
  AutoPtr<ProcessingInstruction> pPI = _pDocument->createProcessingInstruction(target, data);
258
168k
  appendNode(pPI);
259
168k
}
260
261
262
void DOMBuilder::startPrefixMapping(const XMLString& prefix, const XMLString& uri)
263
15.9k
{
264
15.9k
}
265
266
267
void DOMBuilder::endPrefixMapping(const XMLString& prefix)
268
4.42k
{
269
4.42k
}
270
271
272
void DOMBuilder::skippedEntity(const XMLString& name)
273
63.3k
{
274
63.3k
  AutoPtr<EntityReference> pER = _pDocument->createEntityReference(name);
275
63.3k
  appendNode(pER);
276
63.3k
}
277
278
279
void DOMBuilder::startDTD(const XMLString& name, const XMLString& publicId, const XMLString& systemId)
280
10.6k
{
281
10.6k
  AutoPtr<DocumentType> pDoctype = new DocumentType(_pDocument, name, publicId, systemId);
282
10.6k
  _pDocument->setDoctype(pDoctype);
283
10.6k
}
284
285
286
void DOMBuilder::endDTD()
287
4.38k
{
288
4.38k
}
289
290
291
void DOMBuilder::startEntity(const XMLString& name)
292
0
{
293
0
}
294
295
296
void DOMBuilder::endEntity(const XMLString& name)
297
0
{
298
0
}
299
300
301
void DOMBuilder::startCDATA()
302
380k
{
303
380k
  _inCDATA = true;
304
380k
}
305
306
307
void DOMBuilder::endCDATA()
308
379k
{
309
379k
  _inCDATA = false;
310
379k
}
311
312
313
void DOMBuilder::comment(const XMLChar ch[], int start, int length)
314
352k
{
315
352k
  AutoPtr<Comment> pComment = _pDocument->createComment(XMLString(ch + start, length));
316
352k
  appendNode(pComment);
317
352k
}
318
319
320
} } // namespace Poco::XML