0031875: Draw Harness, ViewerTest - command vaspects -mostContinuity lacks g1 and...
[occt.git] / src / XmlObjMgt / XmlObjMgt.cxx
1 // Created on: 2001-07-18
2 // Created by: Julia DOROVSKIKH
3 // Copyright (c) 2001-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 //AGV 150202: Add parameter isClearText to SetStringValue()
17
18 #include <LDOM_Text.hxx>
19 #include <TCollection_AsciiString.hxx>
20 #include <TCollection_ExtendedString.hxx>
21 #include <XmlObjMgt.hxx>
22 #include <XmlObjMgt_Document.hxx>
23
24 #include <errno.h>
25 #include <stdio.h>
26 #include <limits>
27
28 static const char aRefPrefix [] = "/document/label";
29 static const char aRefElem1  [] = "/label[@tag=";
30 static const char aRefElem2  [] = "]";
31
32 //=======================================================================
33 //function : IdString
34 //purpose  : return name of ID attribute to be used everywhere
35 //=======================================================================
36
37 const XmlObjMgt_DOMString& XmlObjMgt::IdString ()
38 {
39   static const LDOMString aString ("id");
40   return aString;
41 }
42
43 //=======================================================================
44 //function : SetStringValue
45 //purpose  : Add theData as the last child text node to theElement
46 //remark   : Set isClearText to True if only you guarantee that the string
47 //           does not contain '&', '<', '>', '\"', '\'', etc.
48 //=======================================================================
49
50 void XmlObjMgt::SetStringValue (XmlObjMgt_Element&         theElement,
51                                 const XmlObjMgt_DOMString& theData,
52                                 const Standard_Boolean     isClearText)
53 {
54   XmlObjMgt_Document aDocument = theElement.getOwnerDocument();
55   LDOM_Text aText = aDocument.createTextNode (theData);
56   if (isClearText) aText.SetValueClear();
57   theElement.appendChild (aText);
58 }
59
60 //=======================================================================
61 //function : GetStringValue
62 //purpose  : returns the first child text node
63 //=======================================================================
64
65 XmlObjMgt_DOMString XmlObjMgt::GetStringValue
66                                         (const XmlObjMgt_Element& theElement)
67 {
68   XmlObjMgt_DOMString aString;
69   for (LDOM_Node aNode = theElement.getFirstChild();
70        aNode != NULL;
71        aNode = aNode.getNextSibling())
72   {
73     if (aNode.getNodeType() == LDOM_Node::TEXT_NODE) {
74       aString = ((const LDOM_Text&)aNode).getData();
75       break;
76     }
77   }
78   return aString;
79 }
80
81 //=======================================================================
82 //function : SprintfExtStr
83 //purpose  : Converts theString to hex printable representation and put it
84 //         : to the out buffer
85 //=======================================================================
86 void SprintfExtStr(char * out, const TCollection_ExtendedString& theString) {
87   unsigned short * p = (unsigned short *)theString.ToExtString();
88   int len = theString.Length();
89   int i = 0;
90   unsigned short mask[4] = {0xf000,0x0f00,0x00f0,0x000f};
91   while (len) {
92     for(int j = 0,k=3; j<4; j++,k--) {
93       unsigned short v = *(p+i) & mask[j];//x000
94       v = (unsigned short)(v >> (4*k));
95       if(v < 10)
96         v |= 0x30;
97       else
98         v += 87;
99       out[4*i+j] = (char)v;
100     }
101     i++;len--;
102   }
103   out[4*theString.Length()] = 0x00;
104 }
105 //=======================================================================
106 //function : SetExtendedString
107 //purpose  : Add text node to element and initialize it with string
108 //=======================================================================
109
110 Standard_Boolean XmlObjMgt::SetExtendedString
111                                   (XmlObjMgt_Element&                theElement,
112                                    const TCollection_ExtendedString& theString)
113 {
114   TCollection_AsciiString anAString;
115   if (theString.IsAscii()) {
116     anAString = TCollection_AsciiString (theString, '?');
117     SetStringValue (theElement, anAString.ToCString());
118   } else {
119     const Standard_Integer aLen = theString.Length();
120 //    const Standard_ExtCharacter * aString = theString.ToExtString();
121     char * buf0 = new char [4 * (aLen + 1) + 3];
122     Sprintf (&buf0[0], "##%04x", 0xfeff);          // set UNICODE header
123     char * buf = &buf0[6];
124 //     Standard_Integer i = 0;
125 //     while (i <= (aLen - 4)) {
126 //       Sprintf (&buf[i*4], "%04x%04x%04x%04x", aString[i], aString[i+1],
127 //                aString[i+2], aString[i+3]);
128 //         i += 4;
129 //     }
130 //     while (i < aLen) {
131 //       Sprintf (&buf[i*4], "%04x", aString[i]);
132 //       ++i;
133 //     }
134 //     buf[4*aLen] = '\0';
135
136     SprintfExtStr(buf, theString);  
137     SetStringValue (theElement, buf0);
138     delete [] buf0;
139   }
140   return Standard_True;
141 }
142
143 //=======================================================================
144 //function : GetExtendedString
145 //purpose  : Get the first text node in theElement and convert to ExtendedStr
146 //=======================================================================
147
148 Standard_Boolean XmlObjMgt::GetExtendedString
149                                 (const XmlObjMgt_Element&       theElement,
150                                  TCollection_ExtendedString&    theString)
151 {
152   theString = GetStringValue (theElement);
153   return Standard_True;
154 }
155
156 //=======================================================================
157 //function : GetTagEntryString
158 //purpose  : Convert XPath expression (DOMString) into TagEntry string
159 //           Returns False on error
160 //=======================================================================
161
162 Standard_Boolean XmlObjMgt::GetTagEntryString
163                                         (const XmlObjMgt_DOMString& theSource,
164                                          TCollection_AsciiString&   theTagEntry)
165 {
166   //    Check the prefix
167   const size_t aPrefixSize = sizeof(aRefPrefix) - 1;
168   const char * aSource = theSource.GetString();
169   if (strncmp (aSource, aRefPrefix, aPrefixSize))
170     return Standard_False;
171
172   //    Beging aTagEntry string
173   char * aTagEntry =
174     (char *) Standard::Allocate (strlen(aSource)/2);  // quite enough to hold it
175   char * aTagEntryPtr = aTagEntry + 1;
176   * aTagEntry = '0';
177   aSource += aPrefixSize;
178
179   //    Find all individual tags in a loop
180   const size_t anElem1Size = sizeof(aRefElem1) - 1;
181   const size_t anElem2Size = sizeof(aRefElem2) - 1;
182   while (aSource[0] != '\0') {
183     //  Check the first part of individual tag: "/label[@tag="
184     if (strncmp (aSource, aRefElem1, anElem1Size))
185       return Standard_False;
186     aSource += anElem1Size;
187     const char aQuote = aSource[0];
188     if (aQuote != '\'' && aQuote != '\"')
189       return Standard_False;
190
191     //  Check the integer value of the tag
192     errno = 0;
193     char * aPtr;
194     long aTagValue = strtol (&aSource[1], &aPtr, 10);
195     Standard_Integer aLen = (Standard_Integer)(aPtr - &aSource[1]);
196     if (aTagValue < 0 || aLen == 0 || aPtr[0] != aQuote ||
197         errno == ERANGE || errno == EINVAL)
198       return Standard_False;
199     aTagEntryPtr[0] = ':';
200     memcpy (&aTagEntryPtr[1], &aSource[1], aLen);
201     aTagEntryPtr += (aLen + 1);
202
203     //  Check the final part of individual tag : "]"
204     if (strncmp (aPtr + 1, aRefElem2, anElem2Size))
205       return Standard_False;
206     aSource = aPtr + 1 + anElem2Size;
207   }
208   aTagEntryPtr[0] = '\0';
209   theTagEntry = aTagEntry;
210   Standard::Free (aTagEntry);
211   return Standard_True;
212 }
213
214 //=======================================================================
215 //function : SetTagEntryString
216 //purpose  : Form an XPath string corresponding to the input TagEntry
217 //=======================================================================
218
219 void XmlObjMgt::SetTagEntryString (XmlObjMgt_DOMString&           theTarget,
220                                    const TCollection_AsciiString& theTagEntry)
221 {
222   //    Begin parsing theTagEntry
223   const char * aTagEntry = (const char*) theTagEntry.ToCString() + 1;
224   if (aTagEntry[-1] != '0')
225     return;
226
227   //    Count the number of tags in the label entry string
228   const char * aPtr = aTagEntry;
229   Standard_Integer aTagCount = 0;
230   while (* aPtr) if (* aPtr++ == ':') aTagCount ++;
231
232   //    Create a buffer to accumulate the XPath reference
233   const size_t anElem1Size = sizeof(aRefElem1) - 1;
234   const size_t anElem2Size = sizeof(aRefElem2) - 1;
235   char * aTarget =
236     (char *) Standard::Allocate (sizeof(aRefPrefix) + aTagCount *
237                                  (anElem1Size + anElem2Size + 12));
238   memcpy (aTarget, aRefPrefix, sizeof (aRefPrefix) - 1);
239   char * aTargetPtr = aTarget + (sizeof (aRefPrefix) - 1);
240
241   for(;;) {
242     //  Check for the end-of-string; find the delimeter ':'
243     aPtr = strchr (aTagEntry, ':');
244     if (aPtr == NULL) break;
245     aTagEntry = aPtr + 1;
246
247     //  Find the range of characters for an integer number
248     errno = 0;
249     char * ptr;
250     long aTagValue = strtol (aTagEntry, &ptr, 10);
251     Standard_Integer aTagSize = (Standard_Integer)(ptr - aTagEntry);
252     if (aTagValue < 0 || aTagSize == 0 ||
253         errno == ERANGE || errno == EINVAL)
254       return;           // error
255
256     //  Add one XPath level to the expression in aTarget
257     memcpy (&aTargetPtr[0],                     aRefElem1, anElem1Size);
258     aTargetPtr[anElem1Size] = '\"';
259     memcpy (&aTargetPtr[anElem1Size+1],         aTagEntry, aTagSize);
260     aTargetPtr[anElem1Size+aTagSize+1] = '\"';
261     memcpy (&aTargetPtr[anElem1Size+aTagSize+2],aRefElem2, anElem2Size);
262     aTargetPtr += (anElem1Size + aTagSize + anElem2Size + 2);
263   }
264   * aTargetPtr = '\0';
265   theTarget = aTarget;
266   Standard::Free (aTarget);
267 }
268
269 //=======================================================================
270 //function : FindChildElement
271 //purpose  : 
272 //=======================================================================
273 XmlObjMgt_Element XmlObjMgt::FindChildElement
274                                          (const XmlObjMgt_Element& theSource,
275                                           const Standard_Integer   theId)
276 {
277   LDOM_Node aNode = theSource.getFirstChild();
278   Standard_Integer anId;
279   while ( !aNode.isNull() )
280   {
281     if ( aNode.getNodeType() == LDOM_Node::ELEMENT_NODE )
282     {
283       LDOM_Element anElem = (LDOM_Element &) aNode;
284       if (anElem.getAttribute (IdString()).GetInteger(anId))
285         if (anId == theId) return anElem;
286     }
287     aNode = aNode.getNextSibling();
288   }
289
290   // find in all the document // to be done
291 //  LDOM_Document aDoc = theSource.getOwnerDocument();
292
293   return LDOM_Element();
294 }
295
296 //=======================================================================
297 //function : FindChildByRef
298 //purpose  : 
299 //=======================================================================
300
301 XmlObjMgt_Element XmlObjMgt::FindChildByRef
302                                        (const XmlObjMgt_Element&   theSource,
303                                         const XmlObjMgt_DOMString& theRefName)
304 {
305   Standard_Integer anID;
306   if (theSource.getAttribute (theRefName).GetInteger (anID))
307     return FindChildElement (theSource, anID);
308   return LDOM_Element();
309 }
310
311
312 //=======================================================================
313 //function : FindChildByName
314 //purpose  : 
315 //=======================================================================
316 XmlObjMgt_Element XmlObjMgt::FindChildByName
317                                          (const XmlObjMgt_Element&   theSource,
318                                           const XmlObjMgt_DOMString& theName)
319 {
320   return theSource.GetChildByTagName(theName);
321 }
322
323 //=======================================================================
324 //function : GetInteger
325 //purpose  : 
326 //=======================================================================
327 Standard_Boolean XmlObjMgt::GetInteger (Standard_CString& theString,
328                                         Standard_Integer& theValue)
329 {
330   char * ptr;
331   errno = 0;
332   long aValue = strtol (theString, &ptr, 10);
333   if (ptr == theString || errno == ERANGE || errno == EINVAL)
334     return Standard_False;
335   theValue = Standard_Integer (aValue);
336   theString = ptr;
337   return Standard_True;
338 }
339
340 //=======================================================================
341 //function : GetReal
342 //purpose  : 
343 //=======================================================================
344 Standard_Boolean XmlObjMgt::GetReal (Standard_CString& theString,
345                                      Standard_Real&    theValue)
346 {
347   char * ptr;
348   errno = 0;
349   theValue = Strtod (theString, &ptr);
350   if (ptr == theString || errno == ERANGE || errno == EINVAL)
351     return Standard_False;
352
353   theString = ptr;
354
355   // detect NAN or infinite values written by old MSVC run-time as -1. with 
356   // suffix "#QNAN" or "#SNAN" or "#INF"
357   if (*ptr == '#')
358   {
359     if (! strncmp (ptr, "#QNAN", 5) || ! strncmp (ptr, "#SNAN", 5))
360     {
361       theString = ptr + 5;
362       theValue = std::numeric_limits<double>::quiet_NaN();
363       return Standard_True;
364     }
365     else if (! strncmp (ptr, "#INF", 4))
366     {
367       theString = ptr + 4;
368       theValue = (theValue < 0 ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity());
369       return Standard_True;
370     }
371     else 
372       return Standard_False;
373   }
374   else if (*ptr && ! IsSpace (*ptr))
375   {
376     // report failure if reading stopped not at the end of the string or space
377     return Standard_False;
378   }
379
380   return Standard_True;
381 }
382
383 //=======================================================================
384 //function : GetReal
385 //purpose  : Convert LDOMString to Real
386 //=======================================================================
387 Standard_Boolean XmlObjMgt::GetReal (const XmlObjMgt_DOMString& theString,
388                                      Standard_Real&             theValue)
389 {
390   switch (theString.Type()) {
391   case LDOMBasicString::LDOM_NULL:
392     return Standard_False;
393   case LDOMBasicString::LDOM_Integer:
394     {
395       Standard_Integer anIntValue;
396       theString.GetInteger(anIntValue);
397       theValue = Standard_Real(anIntValue);
398       break;
399     }
400   default:      // LDOM_Ascii*
401     {
402       const char * aString = theString.GetString();
403       return GetReal (aString, theValue);
404     }
405   }
406   return Standard_True;
407 }