0029452: Application Framework - Failed to read an Ocaf XML document with 1.#QNAN...
[occt.git] / src / XmlObjMgt / XmlObjMgt.cxx
CommitLineData
b311480e 1// Created on: 2001-07-18
2// Created by: Julia DOROVSKIKH
973c2be1 3// Copyright (c) 2001-2014 OPEN CASCADE SAS
b311480e 4//
973c2be1 5// This file is part of Open CASCADE Technology software library.
b311480e 6//
d5f74e42 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
973c2be1 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.
b311480e 12//
973c2be1 13// Alternatively, this file may be used under the terms of Open CASCADE
14// commercial license or contractual agreement.
b311480e 15
16//AGV 150202: Add parameter isClearText to SetStringValue()
7fd59977 17
7fd59977 18#include <LDOM_Text.hxx>
42cf5bc1 19#include <TCollection_AsciiString.hxx>
20#include <TCollection_ExtendedString.hxx>
21#include <XmlObjMgt.hxx>
22#include <XmlObjMgt_Document.hxx>
7fd59977 23
24#include <errno.h>
25#include <stdio.h>
e13b9464 26#include <limits>
27
7fd59977 28static const char aRefPrefix [] = "/document/label";
29static const char aRefElem1 [] = "/label[@tag=";
30static const char aRefElem2 [] = "]";
31
32//=======================================================================
33//function : IdString
34//purpose : return name of ID attribute to be used everywhere
35//=======================================================================
36
37const 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
50void 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
65XmlObjMgt_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//=======================================================================
86void 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
008aef40 94 v = (unsigned short)(v >> (4*k));
7fd59977 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
110Standard_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];
91322f44 122 Sprintf (&buf0[0], "##%04x", 0xfeff); // set UNICODE header
7fd59977 123 char * buf = &buf0[6];
124// Standard_Integer i = 0;
125// while (i <= (aLen - 4)) {
91322f44 126// Sprintf (&buf[i*4], "%04x%04x%04x%04x", aString[i], aString[i+1],
7fd59977 127// aString[i+2], aString[i+3]);
128// i += 4;
129// }
130// while (i < aLen) {
91322f44 131// Sprintf (&buf[i*4], "%04x", aString[i]);
7fd59977 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
148Standard_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
162Standard_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);
ec2039e9 195 Standard_Integer aLen = (Standard_Integer)(aPtr - &aSource[1]);
196 if (aTagValue < 0 || aLen == 0 || aPtr[0] != aQuote ||
7fd59977 197 errno == ERANGE || errno == EINVAL)
198 return Standard_False;
7fd59977 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;
547702a1 210 Standard::Free (aTagEntry);
7fd59977 211 return Standard_True;
212}
213
214//=======================================================================
215//function : SetTagEntryString
216//purpose : Form an XPath string corresponding to the input TagEntry
217//=======================================================================
218
219void 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
302f96fb 241 for(;;) {
7fd59977 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);
7dc9e047 251 Standard_Integer aTagSize = (Standard_Integer)(ptr - aTagEntry);
ec2039e9 252 if (aTagValue < 0 || aTagSize == 0 ||
253 errno == ERANGE || errno == EINVAL)
254 return; // error
7fd59977 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;
547702a1 266 Standard::Free (aTarget);
7fd59977 267}
268
269//=======================================================================
270//function : FindChildElement
271//purpose :
272//=======================================================================
273XmlObjMgt_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
301XmlObjMgt_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//=======================================================================
316XmlObjMgt_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//=======================================================================
327Standard_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//=======================================================================
344Standard_Boolean XmlObjMgt::GetReal (Standard_CString& theString,
345 Standard_Real& theValue)
346{
347 char * ptr;
348 errno = 0;
e13b9464 349 theValue = Strtod (theString, &ptr);
7fd59977 350 if (ptr == theString || errno == ERANGE || errno == EINVAL)
351 return Standard_False;
e13b9464 352
7fd59977 353 theString = ptr;
e13b9464 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
7fd59977 380 return Standard_True;
381}
382
383//=======================================================================
384//function : GetReal
385//purpose : Convert LDOMString to Real
386//=======================================================================
387Standard_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 {
7fd59977 402 const char * aString = theString.GetString();
e13b9464 403 return GetReal (aString, theValue);
7fd59977 404 }
405 }
406 return Standard_True;
407}