dd943bd871f4c95c76b280399a512315ff07e734
[occt.git] / src / LDOM / LDOM_BasicElement.cxx
1 // File:      LDOM_BasicElement.cxx
2 // Created:   26.06.01 21:22:14
3 // Author:    Alexander GRIGORIEV
4 // Copyright: OpenCascade 2001
5 // History:   AGV 140202: Replace(const char *) for (LDOMBasicString)=>myTagName
6
7 #include <LDOM_BasicElement.hxx>
8 #include <LDOM_BasicAttribute.hxx>
9 #include <LDOM_BasicText.hxx>
10 #include <LDOM_MemManager.hxx>
11
12 //=======================================================================
13 //function : Create
14 //purpose  : construction in the Document's data pool
15 //=======================================================================
16
17 LDOM_BasicElement& LDOM_BasicElement::Create
18                                         (const char                     * aName,
19                                          const Standard_Integer         aLen,
20                                          const Handle(LDOM_MemManager)& aDoc)
21 {
22   if (aName == NULL) {
23     static LDOM_BasicElement aVoidElement;
24     aVoidElement = LDOM_BasicElement();
25     return aVoidElement;
26   }
27   void * aMem = aDoc -> Allocate (sizeof(LDOM_BasicElement));
28   LDOM_BasicElement * aNewElem = new (aMem) LDOM_BasicElement;
29
30   Standard_Integer aHash;
31 //  aDoc -> HashedAllocate (aString, strlen(aString), aNewElem -> myTagName);
32   aNewElem -> myTagName =  aDoc -> HashedAllocate (aName, aLen, aHash);
33
34   aNewElem -> myNodeType = LDOM_Node::ELEMENT_NODE;
35   return * aNewElem;
36 }
37
38 //=======================================================================
39 //function : RemoveNodes
40 //purpose  : 
41 //=======================================================================
42
43 void LDOM_BasicElement::RemoveNodes ()
44 {
45   const LDOM_BasicNode * aNode = (const LDOM_BasicNode *) myFirstChild;
46   while (aNode) {
47     const LDOM_BasicNode * aNext = aNode -> GetSibling();
48     switch (aNode -> getNodeType ()) {
49     case LDOM_Node::ELEMENT_NODE:
50       {
51         LDOM_BasicElement& anElement = * (LDOM_BasicElement *) aNode;
52         anElement = NULL;
53         break;
54       }
55     case LDOM_Node::ATTRIBUTE_NODE:
56       {
57         LDOM_BasicAttribute& anAttr = * (LDOM_BasicAttribute *) aNode;
58         anAttr = NULL;
59         break;
60       }
61     case LDOM_Node::TEXT_NODE:
62     case LDOM_Node::COMMENT_NODE:
63     case LDOM_Node::CDATA_SECTION_NODE:
64       {
65         LDOM_BasicText& aTxt = * (LDOM_BasicText *) aNode;
66         aTxt = NULL;
67         break;
68       }
69     default: ;
70     }
71     aNode = aNext;
72   }
73   myFirstChild = NULL;
74 }
75
76 //=======================================================================
77 //function : operator =
78 //purpose  : Nullify
79 //=======================================================================
80
81 LDOM_BasicElement& LDOM_BasicElement:: operator = (const LDOM_NullPtr * aNull)
82 {
83   myTagName = NULL;
84   RemoveNodes ();
85   LDOM_BasicNode::operator= (aNull);
86   return * this;
87 }
88
89 //=======================================================================
90 //function : LDOM_BasicElement
91 //purpose  : Constructor
92 //=======================================================================
93 /*
94 LDOM_BasicElement::LDOM_BasicElement (const LDOM_Element& anElement)
95      : LDOM_BasicNode   (LDOM_Node::ELEMENT_NODE),
96        myAttributeMask  (0),
97        myFirstChild     (NULL)
98 {
99 //  LDOMString aNewTagName (anElement.getTagName(), anElement.myDocument);
100 //  myTagName = aNewTagName;
101   const LDOM_BasicElement& anOther =
102     (const LDOM_BasicElement&) anElement.Origin();
103   myTagName = anOther.GetTagName();
104 }
105 */
106 //=======================================================================
107 //function : ~LDOM_BasicElement
108 //purpose  : Destructor
109 //=======================================================================
110
111 LDOM_BasicElement::~LDOM_BasicElement ()
112 {
113   myTagName = NULL;
114   RemoveNodes ();
115 }
116
117 //=======================================================================
118 //function : GetLastChild
119 //purpose  : 
120 //=======================================================================
121
122 const LDOM_BasicNode * LDOM_BasicElement::GetLastChild () const
123 {
124   const LDOM_BasicNode * aNode = myFirstChild;
125   if (aNode) {
126     if (aNode -> getNodeType() == LDOM_Node::ATTRIBUTE_NODE)
127       aNode = NULL;
128     else
129       while (aNode -> mySibling) {
130         if (aNode -> mySibling -> getNodeType() == LDOM_Node::ATTRIBUTE_NODE)
131           break;
132         aNode = aNode -> mySibling;
133       }
134   }
135   return aNode;
136 }
137
138 //=======================================================================
139 //function : GetAttribute
140 //purpose  : 
141 //=======================================================================
142
143 const LDOM_BasicAttribute& LDOM_BasicElement::GetAttribute
144                                      (const LDOMBasicString& aName,
145                                       const LDOM_BasicNode   * aLastCh) const
146 {
147   const LDOM_BasicNode * aNode;
148   if (aLastCh)
149     aNode = aLastCh -> GetSibling (); 
150   else
151     aNode = myFirstChild;
152   const char * aNameStr = aName.GetString();
153   while (aNode) {
154     if (aNode -> getNodeType () == LDOM_Node::ATTRIBUTE_NODE) {
155       const LDOM_BasicAttribute * anAttr = (const LDOM_BasicAttribute *) aNode;
156       if (!strcmp (aNameStr, anAttr -> GetName()))
157         return * anAttr;
158     }
159     aNode = aNode -> mySibling;
160   }
161 static const LDOM_BasicAttribute aNullAttribute;
162   return aNullAttribute;
163 }
164
165 //=======================================================================
166 //function : GetFirstAttribute
167 //purpose  : private method
168 //=======================================================================
169
170 const LDOM_BasicAttribute * LDOM_BasicElement::GetFirstAttribute
171                                     (const LDOM_BasicNode *&  theLastCh,
172                                      const LDOM_BasicNode **& thePrevNode) const
173 {
174   //  Find the First Attribute as well as the Last Child among siblings
175   const LDOM_BasicNode * aFirstAttr;
176   const LDOM_BasicNode ** aPrevNode;
177   if (theLastCh) {
178     aFirstAttr = theLastCh -> mySibling; 
179     aPrevNode  = (const LDOM_BasicNode **) &(theLastCh -> mySibling);
180     while (aFirstAttr) {
181       if (aFirstAttr -> getNodeType() == LDOM_Node::ATTRIBUTE_NODE) break;
182       aPrevNode = (const LDOM_BasicNode **) & (aFirstAttr -> mySibling);
183       aFirstAttr = aFirstAttr -> mySibling;
184     }
185   } else {
186     aFirstAttr = myFirstChild;
187     aPrevNode  = (const LDOM_BasicNode **) &myFirstChild;
188     while (aFirstAttr) {
189       if (aFirstAttr -> getNodeType() == LDOM_Node::ATTRIBUTE_NODE) break;
190       if (aFirstAttr -> isNull() == Standard_False) theLastCh = aFirstAttr;
191       aPrevNode = (const LDOM_BasicNode **) & (aFirstAttr -> mySibling);
192       aFirstAttr = aFirstAttr -> mySibling;
193     }
194   }
195   thePrevNode = aPrevNode;
196   return (LDOM_BasicAttribute *) aFirstAttr;
197 }
198
199 //=======================================================================
200 //function : AddAttribute
201 //purpose  : Add or replace an attribute
202 //=======================================================================
203
204 const LDOM_BasicNode * LDOM_BasicElement::AddAttribute
205                                   (const LDOMBasicString&         anAttrName,
206                                    const LDOMBasicString&         anAttrValue,
207                                    const Handle(LDOM_MemManager)& aDocument,
208                                    const LDOM_BasicNode           * aLastCh)
209 {
210   //  Create attribute
211   Standard_Integer aHash;
212   LDOM_BasicAttribute& anAttr =
213     LDOM_BasicAttribute::Create (anAttrName, aDocument, aHash);
214   anAttr.myValue = anAttrValue;
215
216   //  Initialize the loop of attribute name search
217   const LDOM_BasicNode ** aPrNode;
218   const LDOM_BasicAttribute * aFirstAttr = GetFirstAttribute (aLastCh, aPrNode);
219   const char * aNameStr = anAttrName.GetString();
220
221   //  Check attribute hash value against the current mask
222   const unsigned int anAttrMaskValue = aHash & (8*sizeof(myAttributeMask) - 1);
223   const unsigned long anAttributeMask = (1 << anAttrMaskValue);
224 #ifdef DEBUG_MASK
225   anAttributeMask = 0xffffffff;
226 #endif
227   if ((myAttributeMask & anAttributeMask) == 0) {
228     // this is new attribute, OK
229     myAttributeMask |= anAttributeMask;
230     * aPrNode = &anAttr;
231     anAttr.SetSibling (aFirstAttr);
232   } else {
233     // this attribute may have already been installed  
234     LDOM_BasicAttribute * aCurrentAttr = (LDOM_BasicAttribute *) aFirstAttr;
235     while (aCurrentAttr) {
236       if (aCurrentAttr -> getNodeType() == LDOM_Node::ATTRIBUTE_NODE)
237         if (LDOM_MemManager::CompareStrings (aNameStr, aHash,
238                                              aCurrentAttr -> GetName())) {
239           aCurrentAttr -> SetValue (anAttrValue, aDocument);
240           break;
241         }
242       aCurrentAttr = (LDOM_BasicAttribute *) aCurrentAttr -> mySibling;
243     }
244     if (aCurrentAttr == NULL) {
245       // this is new attribute, OK
246       * aPrNode = &anAttr;
247       anAttr.SetSibling (aFirstAttr);
248     }
249   }
250   return aLastCh;
251 }
252
253 //=======================================================================
254 //function : RemoveAttribute
255 //purpose  : Find and delete an attribute from list
256 //=======================================================================
257
258 const LDOM_BasicNode * LDOM_BasicElement::RemoveAttribute
259                                         (const LDOMBasicString& aName,
260                                          const LDOM_BasicNode   * aLastCh) const
261 {
262   //  Check attribute hash value against the current mask
263   const char * const aNameStr = aName.GetString();
264   const Standard_Integer aHash =
265     LDOM_MemManager::Hash (aNameStr, strlen(aNameStr));
266   const unsigned int anAttrMaskValue = aHash & (8*sizeof(myAttributeMask) - 1);
267   const unsigned long anAttributeMask = (1 << anAttrMaskValue);
268 #ifdef DEBUG_MASK
269   anAttributeMask = 0xffffffff;
270 #endif
271   if ((myAttributeMask & anAttributeMask) == 0) {
272     ; // maybe cause for exception
273   } else {
274     const LDOM_BasicNode ** aPrevNode;  // dummy
275     const LDOM_BasicAttribute * anAttr = GetFirstAttribute (aLastCh, aPrevNode);
276     while (anAttr) {
277       if (anAttr -> getNodeType () == LDOM_Node::ATTRIBUTE_NODE)
278         if (LDOM_MemManager::CompareStrings(aNameStr,aHash,anAttr->GetName())) {
279           anAttr = NULL;
280           break;
281         }
282       anAttr = (const LDOM_BasicAttribute *) anAttr -> mySibling;
283     }
284   }
285   return aLastCh;
286 }
287
288 //=======================================================================
289 //function : RemoveChild
290 //purpose  : 
291 //=======================================================================
292
293 void LDOM_BasicElement::RemoveChild (const LDOM_BasicNode * aChild) const
294 {
295   const LDOM_BasicNode *  aNode = myFirstChild;
296   const LDOM_BasicNode ** aPrevNode = (const LDOM_BasicNode **) &myFirstChild;
297   while (aNode) {
298     if (aNode -> getNodeType() == LDOM_Node::ATTRIBUTE_NODE)
299       break;
300     if (aNode == aChild) {
301       * aPrevNode = aNode -> GetSibling();
302       * (LDOM_BasicNode *) aChild = NULL;
303       break;
304     }
305     aPrevNode = (const LDOM_BasicNode **) & (aNode -> mySibling);
306     aNode = aNode -> GetSibling();
307   }
308   // here may be the cause to throw an exception
309 }
310
311 //=======================================================================
312 //function : AppendChild
313 //purpose  : 
314 //=======================================================================
315
316 void LDOM_BasicElement::AppendChild (const LDOM_BasicNode *  aChild,
317                                      const LDOM_BasicNode *& aLastChild) const
318 {
319   if (aLastChild) {
320     (const LDOM_BasicNode *&) aChild -> mySibling = aLastChild -> mySibling;
321     (const LDOM_BasicNode *&) aLastChild -> mySibling = aChild;
322   } else {
323     const LDOM_BasicNode * aNode = myFirstChild;
324     const LDOM_BasicNode ** aPrevNode = (const LDOM_BasicNode **) &myFirstChild;
325     while (aNode) {
326       if (aNode -> getNodeType() == LDOM_Node::ATTRIBUTE_NODE) {
327         (const LDOM_BasicNode *&) aChild -> mySibling = aNode;
328         break;
329       }
330       aPrevNode = (const LDOM_BasicNode **) & (aNode -> mySibling);
331       aNode = aNode -> mySibling;
332     }
333     * aPrevNode = aChild;
334   }
335   aLastChild = aChild;
336 }
337
338 //=======================================================================
339 //function : AddElementsByTagName
340 //purpose  : Add to the List all sub-elements with the given name (recursive) 
341 //=======================================================================
342
343 void LDOM_BasicElement::AddElementsByTagName
344                 (LDOM_NodeList& aList, const LDOMBasicString& aTagName) const
345 {
346   const LDOM_BasicNode  * aNode         = myFirstChild;
347   const char            * aTagString    = aTagName.GetString();
348   while (aNode) {
349     if (aNode -> getNodeType() == LDOM_Node::ATTRIBUTE_NODE)
350       break;
351     if (aNode -> getNodeType() == LDOM_Node::ELEMENT_NODE) {
352       LDOM_BasicElement& anElement = * (LDOM_BasicElement *) aNode;
353 //      if (anElement.GetTagName().equals(aTagName))
354       if (strcmp (anElement.GetTagName(), aTagString) == 0)
355         aList.Append (anElement);
356       anElement.AddElementsByTagName (aList, aTagName);
357     }
358     aNode = aNode -> GetSibling();
359   }
360 }
361
362 //=======================================================================
363 //function : AddAttributes
364 //purpose  : 
365 //=======================================================================
366
367 void LDOM_BasicElement::AddAttributes (LDOM_NodeList&       aList,
368                                        const LDOM_BasicNode * aLastChild) const
369 {
370   const LDOM_BasicNode * aBNode;
371   if (aLastChild)
372     aBNode = aLastChild -> GetSibling();
373   else
374     aBNode = GetFirstChild();
375   while (aBNode) {
376     if (aBNode -> getNodeType() == LDOM_Node::ATTRIBUTE_NODE)
377       aList.Append (* aBNode);
378     aBNode = aBNode -> GetSibling();
379   }
380 }
381
382 //=======================================================================
383 //function : ReplaceElement
384 //purpose  : Copy data and children into this node from another one
385 //           The only preserved data is mySibling
386 //=======================================================================
387
388 void LDOM_BasicElement::ReplaceElement
389                                 (const LDOM_BasicElement&       anOtherElem,
390                                  const Handle(LDOM_MemManager)& aDocument)
391 {
392   myTagName          = anOtherElem.GetTagName();
393   myAttributeMask    = anOtherElem.myAttributeMask;
394   myFirstChild       = NULL;
395   const LDOM_BasicNode * aBNode = anOtherElem.GetFirstChild ();
396   const LDOM_BasicNode * aLastChild = NULL;
397
398   // Loop on children (non-attributes)
399   for (; aBNode != NULL; aBNode = aBNode -> GetSibling()) {
400     if (aBNode -> isNull())
401       continue;
402     LDOM_BasicNode * aNewBNode;
403     const LDOM_Node::NodeType aNewNodeType = aBNode -> getNodeType();
404     switch (aNewNodeType) {
405     case LDOM_Node::ELEMENT_NODE:
406       {
407         const LDOM_BasicElement& aBNodeElem = *(const LDOM_BasicElement*)aBNode;
408         const char * aTagString = aBNodeElem.GetTagName();
409         LDOM_BasicElement& aNewBNodeElem =
410           LDOM_BasicElement::Create (aTagString, strlen(aTagString), aDocument);
411         aNewBNodeElem.ReplaceElement (aBNodeElem, aDocument); //reccur
412         aNewBNode = &aNewBNodeElem;
413         break;
414       }
415     case LDOM_Node::ATTRIBUTE_NODE:
416       goto loop_attr;
417     case LDOM_Node::TEXT_NODE:
418     case LDOM_Node::COMMENT_NODE:
419     case LDOM_Node::CDATA_SECTION_NODE:
420       {
421         const LDOM_BasicText& aBNodeText = * (const LDOM_BasicText *) aBNode;
422         aNewBNode = &LDOM_BasicText::Create (aNewNodeType,
423                                              LDOMString(aBNodeText.GetData(),
424                                                         aDocument),
425                                              aDocument);
426         break;
427       }
428     default: continue;
429     }
430     if (GetFirstChild())
431       (const LDOM_BasicNode *&) aLastChild -> mySibling = aNewBNode;
432     else
433       (const LDOM_BasicNode *&) myFirstChild = aNewBNode;
434     (const LDOM_BasicNode *&) aLastChild = aNewBNode;
435   }
436
437   // Loop on attributes (in the end of the list of children)
438 loop_attr:
439   LDOM_BasicNode * aLastAttr = (LDOM_BasicNode *) aLastChild;
440   for (; aBNode != NULL; aBNode = aBNode -> GetSibling()) {
441     Standard_Integer aHash;
442     if (aBNode -> isNull()) continue;
443     const LDOM_BasicAttribute * aBNodeAtt= (const LDOM_BasicAttribute *) aBNode;
444     LDOM_BasicAttribute * aNewAtt =
445       &LDOM_BasicAttribute::Create (aBNodeAtt -> GetName(), aDocument, aHash);
446     aNewAtt -> SetValue (aBNodeAtt->myValue, aDocument);
447     if (aLastAttr)
448       aLastAttr -> SetSibling (aNewAtt);
449     else
450       myFirstChild = aNewAtt;
451     aLastAttr = aNewAtt;
452   }
453 }