1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 /*
19  * $Id: DOMDocumentImpl.hpp 679340 2008-07-24 10:28:29Z borisk $
20  */
21 
22 #if !defined(XERCESC_INCLUDE_GUARD_DOMDOCUMENTIMPL_HPP)
23 #define XERCESC_INCLUDE_GUARD_DOMDOCUMENTIMPL_HPP
24 
25 //
26 //  This file is part of the internal implementation of the C++ XML DOM.
27 //  It should NOT be included or used directly by application programs.
28 //
29 //  Applications should include the file <xercesc/dom/DOM.hpp> for the entire
30 //  DOM API, or xercesc/dom/DOM*.hpp for individual DOM classes, where the class
31 //  name is substituded for the *.
32 //
33 
34 #include <xercesc/util/RefArrayOf.hpp>
35 #include <xercesc/util/RefStackOf.hpp>
36 #include <xercesc/util/RefHash2KeysTableOf.hpp>
37 #include <xercesc/util/StringPool.hpp>
38 #include <xercesc/util/KeyRefPair.hpp>
39 #include <xercesc/util/XMLChar.hpp>
40 #include <xercesc/dom/DOMDocument.hpp>
41 #include <xercesc/dom/DOMUserDataHandler.hpp>
42 #include <xercesc/dom/DOMMemoryManager.hpp>
43 #include "DOMNodeImpl.hpp"
44 #include "DOMStringPool.hpp"
45 #include "DOMParentNode.hpp"
46 #include "DOMDeepNodeListPool.hpp"
47 
48 XERCES_CPP_NAMESPACE_BEGIN
49 
50 
51 class DOMAttrImpl;
52 class DOMCDATASectionImpl;
53 class DOMCommentImpl;
54 class DOMConfiguration;
55 class DOMDeepNodeListImpl;
56 class DOMDocumentFragmentImpl;
57 class DOMDocumentTypeImpl;
58 class DOMElementImpl;
59 class DOMEntityImpl;
60 class DOMEntityReferenceImpl;
61 class DOMNotationImpl;
62 class DOMProcessingInstructionImpl;
63 class DOMTextImpl;
64 class DOMNodeIteratorImpl;
65 class DOMNormalizer;
66 class DOMTreeWalkerImpl;
67 class DOMNodeFilter;
68 class DOMNodeFilterImpl;
69 class DOMImplementation;
70 class DOMNodeIDMap;
71 class DOMRangeImpl;
72 class DOMBuffer;
73 class MemoryManager;
74 class XPathNSResolver;
75 class XPathExpression;
76 
77 typedef RefVectorOf<DOMRangeImpl>        Ranges;
78 typedef RefVectorOf<DOMNodeIteratorImpl>     NodeIterators;
79 typedef KeyRefPair<void, DOMUserDataHandler> DOMUserDataRecord;
80 typedef RefStackOf<DOMNode>               DOMNodePtr;
81 
82 class CDOM_EXPORT DOMDocumentImpl: public XMemory, public DOMMemoryManager, public DOMDocument {
83 public:
84     // -----------------------------------------------------------------------
85     //  data
86     // -----------------------------------------------------------------------
87     DOMNodeImpl           fNode;           // Implements common node functionality.
88     DOMParentNode         fParent;         // Implements common parent node functionality
89     DOMNodeIDMap*         fNodeIDMap;     // for use by GetElementsById().
90 
91 public:
92     DOMDocumentImpl(DOMImplementation* domImpl, MemoryManager* const manager = XMLPlatformUtils::fgMemoryManager);
93     DOMDocumentImpl(const XMLCh*     namespaceURI,     //DOM Level 2
94                     const XMLCh*     qualifiedName,
95                     DOMDocumentType* doctype,
96                     DOMImplementation* domImpl,
97                     MemoryManager* const manager = XMLPlatformUtils::fgMemoryManager);
98     virtual ~DOMDocumentImpl();
99 
100     void                         setDocumentType(DOMDocumentType *doctype);
101 
102 public:
103     // Add all functions that are pure virtual in DOMNODE
104     DOMNODE_FUNCTIONS;
105 
106 public:
107     // Add all functions that are pure virtual in DOMDocument
108     virtual DOMAttr*             createAttribute(const XMLCh *name);
109     virtual DOMCDATASection*     createCDATASection(const XMLCh *data);
110     virtual DOMComment*          createComment(const XMLCh *data);
111     virtual DOMDocumentFragment* createDocumentFragment();
112     virtual DOMDocumentType*     createDocumentType(const XMLCh *name);
113     virtual DOMDocumentType*     createDocumentType(const XMLCh *qName,
114                                                     const XMLCh *publicId,
115                                                     const XMLCh *systemId);
116     virtual DOMElement*          createElement(const XMLCh * tagName);
117     virtual DOMElement*          createElementNoCheck(const XMLCh *tagName);
118     virtual DOMEntity*           createEntity(const XMLCh * name);
119     virtual DOMEntityReference*  createEntityReference(const XMLCh * name);
120     virtual DOMNotation*         createNotation(const XMLCh * name);
121     virtual DOMProcessingInstruction* createProcessingInstruction(const XMLCh * target, const XMLCh * data);
122     virtual DOMText*             createTextNode(const XMLCh * data);
123     virtual DOMDocumentType*     getDoctype() const;
124     virtual DOMElement*          getDocumentElement() const;
125     virtual DOMNodeList*         getElementsByTagName(const XMLCh * tagname) const;
126     virtual DOMImplementation*   getImplementation() const;
127     bool                         isXMLName(const XMLCh * s);
128     virtual DOMNodeIterator*     createNodeIterator(DOMNode *root,
129                                                     DOMNodeFilter::ShowType whatToShow,
130                                                     DOMNodeFilter* filter,
131                                                     bool entityReferenceExpansion);
132     virtual DOMTreeWalker*       createTreeWalker(DOMNode *root,
133                                                   DOMNodeFilter::ShowType whatToShow,
134                                                   DOMNodeFilter* filter,
135                                                   bool entityReferenceExpansion);
136 
137 
138     virtual DOMRange*            createRange();
139     virtual Ranges*              getRanges() const;  //non-standard api
140     virtual NodeIterators*       getNodeIterators() const;  //non-standard api
141     virtual void                 removeRange(DOMRangeImpl* range); //non-standard api
142     virtual void                 removeNodeIterator(DOMNodeIteratorImpl* nodeIterator); //non-standard api
143 
144     virtual DOMXPathExpression* createExpression(const XMLCh *expression,
145                                                  const DOMXPathNSResolver *resolver);
146     virtual DOMXPathNSResolver* createNSResolver(const DOMNode *nodeResolver);
147     virtual DOMXPathResult* evaluate(const XMLCh *expression,
148                                      const DOMNode *contextNode,
149                                      const DOMXPathNSResolver *resolver,
150                                      DOMXPathResult::ResultType type,
151                                      DOMXPathResult* result);
152 
153 
154     // Extension to be called by the Parser
155     DOMEntityReference*  createEntityReferenceByParser(const XMLCh * name);
156 
157     // Add all functions that are pure virtual in DOMMemoryManager
158     virtual XMLSize_t getMemoryAllocationBlockSize() const;
159     virtual void setMemoryAllocationBlockSize(XMLSize_t size);
160     virtual void* allocate(XMLSize_t amount);
161     virtual void* allocate(XMLSize_t amount, DOMMemoryManager::NodeObjectType type);
162     virtual void release(DOMNode* object, DOMMemoryManager::NodeObjectType type);
163     virtual XMLCh* cloneString(const XMLCh *src);
164 
165     //
166     // Functions to keep track of document mutations, so that node list chached
167     //   information can be invalidated.  One global changes counter per document.
168     //
169     virtual void                 changed();
170     virtual int                  changes() const;
171 
172     /**
173      * Sets whether the DOM implementation performs error checking
174      * upon operations. Turning off error checking only affects
175      * the following DOM checks:
176      * <ul>
177      * <li>Checking strings to make sure that all characters are
178      *     legal XML characters
179      * <li>Hierarchy checking such as allowed children, checks for
180      *     cycles, etc.
181      * </ul>
182      * <p>
183      * Turning off error checking does <em>not</em> turn off the
184      * following checks:
185      * <ul>
186      * <li>Read only checks
187      * <li>Checks related to DOM events
188      * </ul>
189      */
setErrorChecking(bool check)190     inline void setErrorChecking(bool check) {
191         errorChecking = check;
192     }
193 
194     /**
195      * Returns true if the DOM implementation performs error checking.
196      */
getErrorChecking() const197     inline bool getErrorChecking() const {
198         return errorChecking;
199     }
200 
201     //Introduced in DOM Level 2
202     virtual DOMNode*             importNode(const DOMNode *source, bool deep);
203     virtual DOMElement*          createElementNS(const XMLCh *namespaceURI,
204                                                  const XMLCh *qualifiedName);
205     virtual DOMElement*          createElementNS(const XMLCh *namespaceURI,
206                                                  const XMLCh *qualifiedName,
207                                                  const XMLFileLoc lineNo,
208                                                  const XMLFileLoc columnNo);
209     virtual DOMAttr*             createAttributeNS(const XMLCh *namespaceURI,
210                                                    const XMLCh *qualifiedName);
211     virtual DOMNodeList*         getElementsByTagNameNS(const XMLCh *namespaceURI,
212                                                         const XMLCh *localName) const;
213     virtual DOMElement*          getElementById(const XMLCh *elementId) const;
214 
215     //Introduced in DOM Level 3
216     virtual const XMLCh*         getInputEncoding() const;
217     virtual const XMLCh*         getXmlEncoding() const;
218     virtual bool                 getXmlStandalone() const;
219     virtual void                 setXmlStandalone(bool standalone);
220     virtual const XMLCh*         getXmlVersion() const;
221     virtual void                 setXmlVersion(const XMLCh* version);
222     virtual const XMLCh*         getDocumentURI() const;
223     virtual void                 setDocumentURI(const XMLCh* documentURI);
224     virtual bool                 getStrictErrorChecking() const;
225     virtual void                 setStrictErrorChecking(bool strictErrorChecking);
226     virtual DOMNode*             adoptNode(DOMNode* source);
227     virtual void                 normalizeDocument();
228     virtual DOMConfiguration*    getDOMConfig() const;
229 
230     void                         setInputEncoding(const XMLCh* actualEncoding);
231     void                         setXmlEncoding(const XMLCh* encoding);
232     // helper functions to prevent storing userdata pointers on every node.
233     void*                        setUserData(DOMNodeImpl* n,
234                                             const XMLCh* key,
235                                             void* data,
236                                             DOMUserDataHandler* handler);
237     void*                        getUserData(const DOMNodeImpl* n,
238                                              const XMLCh* key) const;
239     void                         callUserDataHandlers(const DOMNodeImpl* n,
240                                                       DOMUserDataHandler::DOMOperationType operation,
241                                                       const DOMNode* src,
242                                                       DOMNode* dst) const;
243     void                         transferUserData(DOMNodeImpl* n1, DOMNodeImpl* n2);
244 
245     DOMNode*                     renameNode(DOMNode* n,
246                                             const XMLCh* namespaceURI,
247                                             const XMLCh* name);
248 
249     //Return the index > 0 of ':' in the given qualified name qName="prefix:localName".
250     //Return 0 if there is no ':', or -1 if qName is malformed such as ":abcd".
251     static  int                  indexofQualifiedName(const XMLCh * qName);
252     static  bool                 isKidOK(DOMNode *parent, DOMNode *child);
253 
getNodeIDMap()254     inline DOMNodeIDMap*         getNodeIDMap() {return fNodeIDMap;};
255 
256 
257     //
258     // Memory Management Functions.  All memory is allocated by and owned by
259     //                               a document, and is not recovered until the
260     //                               document itself is deleted.
261     //
262     const XMLCh*                 getPooledString(const XMLCh*);
263     const XMLCh*                 getPooledNString(const XMLCh*, XMLSize_t);
264     void                         deleteHeap();
265     void                         releaseDocNotifyUserData(DOMNode* object);
266     void                         releaseBuffer(DOMBuffer* buffer);
267     DOMBuffer*                   popBuffer(XMLSize_t nMinSize);
268     MemoryManager*               getMemoryManager() const;
269 
270     // Factory methods for getting/creating node lists.
271     // Because nothing is ever deleted, the implementation caches and recycles
272     //  previously used instances of DOMDeepNodeList
273     //
274     DOMNodeList*                 getDeepNodeList(const DOMNode *rootNode, const XMLCh *tagName);
275     DOMNodeList*                 getDeepNodeList(const DOMNode *rootNode,    //DOM Level 2
276                                                  const XMLCh *namespaceURI,
277                                                  const XMLCh *localName);
278 
279 protected:
280     //Internal helper functions
281     virtual DOMNode*             importNode(const DOMNode *source, bool deep, bool cloningNode);
282 
283 private:
284     // -----------------------------------------------------------------------
285     // Unimplemented constructors and operators
286     // -----------------------------------------------------------------------
287     DOMDocumentImpl(const DOMDocumentImpl &);
288     DOMDocumentImpl & operator = (const DOMDocumentImpl &);
289 
290 protected:
291     // -----------------------------------------------------------------------
292     //  data
293     // -----------------------------------------------------------------------
294     // New data introduced in DOM Level 3
295     const XMLCh*          fInputEncoding;
296     const XMLCh*          fXmlEncoding;
297     bool                  fXmlStandalone;
298     const XMLCh*          fXmlVersion;
299     const XMLCh*          fDocumentURI;
300     DOMConfiguration*     fDOMConfiguration;
301 
302     XMLStringPool         fUserDataTableKeys;
303     RefHash2KeysTableOf<DOMUserDataRecord, PtrHasher>* fUserDataTable;
304 
305 
306     // Per-Document heap Variables.
307     //   The heap consists of one or more biggish blocks which are
308     //   sub-allocated for individual allocations of nodes, strings, etc.
309     //   The big blocks form a linked list, allowing them to be located for deletion.
310     //
311     //   There is no provision for deleting suballocated blocks, other than
312     //     deleting the entire heap when the document is deleted.
313     //
314     //   There is no header on individual sub-allocated blocks.
315     //   The header on big blocks consists only of a single back pointer to
316     //    the previously allocated big block (our linked list of big blocks)
317     //
318     //
319     //   revisit - this heap should be encapsulated into its own
320     //                  class, rather than hanging naked on Document.
321     //
322     void*                 fCurrentBlock;
323     char*                 fFreePtr;
324     XMLSize_t             fFreeBytesRemaining,
325                           fHeapAllocSize;
326 
327     // To recycle the DOMNode pointer
328     RefArrayOf<DOMNodePtr>* fRecycleNodePtr;
329 
330     // To recycle DOMBuffer pointer
331     RefStackOf<DOMBuffer>* fRecycleBufferPtr;
332 
333     // Pool of DOMNodeList for getElementsByTagName
334     DOMDeepNodeListPool<DOMDeepNodeListImpl>* fNodeListPool;
335 
336     // Other data
337     DOMDocumentType*      fDocType;
338     DOMElement*           fDocElement;
339 
340     DOMStringPoolEntry**  fNameTable;
341     XMLSize_t             fNameTableSize;
342 
343     DOMNormalizer*        fNormalizer;
344     Ranges*               fRanges;
345     NodeIterators*        fNodeIterators;
346     MemoryManager*        fMemoryManager;   // configurable memory manager
347     DOMImplementation*    fDOMImplementation;
348 
349     int                   fChanges;
350     bool                  errorChecking;    // Bypass error checking.
351 
352 };
353 
getMemoryManager() const354 inline MemoryManager* DOMDocumentImpl::getMemoryManager() const
355 {
356     return fMemoryManager;
357 }
358 
getPooledString(const XMLCh * in)359 inline const XMLCh*  DOMDocumentImpl::getPooledString(const XMLCh *in)
360 {
361   if (in == 0)
362     return 0;
363 
364   DOMStringPoolEntry    **pspe;
365   DOMStringPoolEntry    *spe;
366 
367   XMLSize_t inHash = XMLString::hash(in, fNameTableSize);
368   pspe = &fNameTable[inHash];
369   while (*pspe != 0)
370   {
371     if (XMLString::equals((*pspe)->fString, in))
372       return (*pspe)->fString;
373     pspe = &((*pspe)->fNext);
374   }
375 
376   // This string hasn't been seen before.  Add it to the pool.
377   //
378 
379   // Compute size to allocate.  Note that there's 1 char of string
380   // declared in the struct, so we don't need to add one again to
381   // account for the trailing null.
382   //
383   XMLSize_t sizeToAllocate = sizeof(DOMStringPoolEntry) + XMLString::stringLen(in)*sizeof(XMLCh);
384   *pspe = spe = (DOMStringPoolEntry *)allocate(sizeToAllocate);
385   spe->fNext = 0;
386   XMLString::copyString((XMLCh*)spe->fString, in);
387 
388   return spe->fString;
389 }
390 
391 inline const XMLCh* DOMDocumentImpl::
getPooledNString(const XMLCh * in,XMLSize_t n)392 getPooledNString(const XMLCh *in, XMLSize_t n)
393 {
394   if (in == 0)
395     return 0;
396 
397   DOMStringPoolEntry    **pspe;
398   DOMStringPoolEntry    *spe;
399 
400   XMLSize_t inHash = XMLString::hashN(in, n, fNameTableSize);
401   pspe = &fNameTable[inHash];
402   while (*pspe != 0)
403   {
404     if (XMLString::equalsN((*pspe)->fString, in, n))
405       return (*pspe)->fString;
406     pspe = &((*pspe)->fNext);
407   }
408 
409   // This string hasn't been seen before.  Add it to the pool.
410   //
411 
412   // Compute size to allocate.  Note that there's 1 char of string
413   // declared in the struct, so we don't need to add one again to
414   // account for the trailing null.
415   //
416   XMLSize_t sizeToAllocate = sizeof(DOMStringPoolEntry) + n*sizeof(XMLCh);
417   *pspe = spe = (DOMStringPoolEntry *)allocate(sizeToAllocate);
418   spe->fNext = 0;
419   XMLString::copyNString((XMLCh*)spe->fString, in, n);
420 
421   return spe->fString;
422 }
423 
indexofQualifiedName(const XMLCh * name)424 inline int DOMDocumentImpl::indexofQualifiedName(const XMLCh* name)
425 {
426   int i = 0;
427   int colon = -1;
428   int colon_count = 0;
429   for (; *name != 0; ++i, ++name)
430   {
431     if (*name == chColon)
432     {
433       ++colon_count;
434       colon = i;
435     }
436   }
437 
438   if (i == 0 || colon == 0 || colon == (i - 1) || colon_count > 1)
439     return -1;
440 
441   return colon != -1 ? colon : 0;
442 }
443 
444 XERCES_CPP_NAMESPACE_END
445 
446 // ---------------------------------------------------------------------------
447 //
448 //  Operator new.  Global overloaded version, lets any object be allocated on
449 //                 the heap owned by a document.
450 //
451 // ---------------------------------------------------------------------------
operator new(size_t amt,XERCES_CPP_NAMESPACE_QUALIFIER DOMDocumentImpl * doc,XERCES_CPP_NAMESPACE_QUALIFIER DOMMemoryManager::NodeObjectType type)452 inline void * operator new(size_t amt, XERCES_CPP_NAMESPACE_QUALIFIER DOMDocumentImpl *doc, XERCES_CPP_NAMESPACE_QUALIFIER DOMMemoryManager::NodeObjectType type)
453 {
454     void *p = doc->allocate(amt, type);
455     return p;
456 }
457 
operator new(size_t amt,XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument * doc,XERCES_CPP_NAMESPACE_QUALIFIER DOMMemoryManager::NodeObjectType type)458 inline void * operator new(size_t amt, XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *doc, XERCES_CPP_NAMESPACE_QUALIFIER DOMMemoryManager::NodeObjectType type)
459 {
460     XERCES_CPP_NAMESPACE_QUALIFIER DOMMemoryManager* mgr=(XERCES_CPP_NAMESPACE_QUALIFIER DOMMemoryManager*)doc->getFeature(XERCES_CPP_NAMESPACE_QUALIFIER XMLUni::fgXercescInterfaceDOMMemoryManager,0);
461     void* p=0;
462     if(mgr)
463         p = mgr->allocate(amt, type);
464     return p;
465 }
466 
operator new(size_t amt,XERCES_CPP_NAMESPACE_QUALIFIER DOMDocumentImpl * doc)467 inline void * operator new(size_t amt, XERCES_CPP_NAMESPACE_QUALIFIER DOMDocumentImpl *doc)
468 {
469     void* p = doc->allocate(amt);
470     return p;
471 }
472 
operator new(size_t amt,XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument * doc)473 inline void * operator new(size_t amt, XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *doc)
474 {
475     XERCES_CPP_NAMESPACE_QUALIFIER DOMMemoryManager* mgr=(XERCES_CPP_NAMESPACE_QUALIFIER DOMMemoryManager*)doc->getFeature(XERCES_CPP_NAMESPACE_QUALIFIER XMLUni::fgXercescInterfaceDOMMemoryManager,0);
476     void* p=0;
477     if(mgr)
478         p = mgr->allocate(amt);
479     return p;
480 }
481 
482 // ---------------------------------------------------------------------------
483 //  For DOM:
484 //  Bypass compiler warning:
485 //    no matching operator delete found; memory will not be freed if initialization throws an exception
486 // ---------------------------------------------------------------------------
487 #if !defined(XERCES_NO_MATCHING_DELETE_OPERATOR)
operator delete(void *,XERCES_CPP_NAMESPACE_QUALIFIER DOMDocumentImpl *,XERCES_CPP_NAMESPACE_QUALIFIER DOMMemoryManager::NodeObjectType)488 inline void operator delete(void* /*ptr*/, XERCES_CPP_NAMESPACE_QUALIFIER DOMDocumentImpl * /*doc*/, XERCES_CPP_NAMESPACE_QUALIFIER DOMMemoryManager::NodeObjectType /*type*/)
489 {
490     return;
491 }
operator delete(void *,XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *,XERCES_CPP_NAMESPACE_QUALIFIER DOMMemoryManager::NodeObjectType)492 inline void operator delete(void* /*ptr*/, XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument * /*doc*/, XERCES_CPP_NAMESPACE_QUALIFIER DOMMemoryManager::NodeObjectType /*type*/)
493 {
494     return;
495 }
496 
operator delete(void *,XERCES_CPP_NAMESPACE_QUALIFIER DOMDocumentImpl *)497 inline void operator delete(void* /*ptr*/, XERCES_CPP_NAMESPACE_QUALIFIER DOMDocumentImpl * /*doc*/)
498 {
499     return;
500 }
operator delete(void *,XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *)501 inline void operator delete(void* /*ptr*/, XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument * /*doc*/)
502 {
503     return;
504 }
505 #endif
506 
507 #endif
508