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