implemented infinite backoff (fixes #311767)
[dasher.git] / Src / DasherCore / XMLUtil.cpp
blob64ec09f200dc52f3d73eaa2356b5b8b39a504558
2 #include "XMLUtil.h"
4 #include <sys/types.h>
5 #include <sys/stat.h>
7 // Track memory leaks on Windows to the line that new'd the memory
8 #ifdef _WIN32
9 #ifdef _DEBUG
10 #define DEBUG_NEW new( _NORMAL_BLOCK, THIS_FILE, __LINE__ )
11 #define new DEBUG_NEW
12 #undef THIS_FILE
13 static char THIS_FILE[] = __FILE__;
14 #endif
15 #endif
17 bool XMLUtil::IsWhiteSpace(char cLetter)
19 if ((cLetter == ' ') ||
20 (cLetter == '\n') ||
21 (cLetter == '\r') ||
22 (cLetter == '\t'))
23 return true;
25 return false;
28 // See if a character is 0 - 9
29 bool XMLUtil::IsDigit(char cLetter)
31 if ((cLetter >= '0') && (cLetter <= '9'))
32 return true;
33 return false;
36 // Strip the leading and trailing white space off a string.
37 string XMLUtil::StripWhiteSpace(const string& strText)
39 string strResult = "";
41 strResult.reserve(strText.length());
43 int iStart = 0;
44 while ((iStart < (int) strText.length()) && (IsWhiteSpace(strText[iStart])))
45 iStart++;
47 int iEnd = strText.length() - 1;
48 while ((iEnd > 0) && (IsWhiteSpace(strText[iEnd])))
49 iEnd--;
51 strResult = strText.substr(iStart, iEnd - iStart + 1);
53 return strResult;
56 // Return a string containing the contents of a file
57 string XMLUtil::LoadFile(const string& strFilename, unsigned int iSizeHint)
59 string strResult = "";
61 char szBuffer[XML_UTIL_READ_BUFFER_SIZE];
62 FILE* fp = NULL;
63 fp = fopen(strFilename.c_str(), "r");
64 if (fp != NULL)
66 #ifdef _WIN32
67 struct __stat64 buf;
68 int result;
69 result = _stat64(strFilename.c_str(), &buf);
70 strResult.reserve((unsigned long) buf.st_size + 256);
71 #else
72 // On unix, we default to 128,000 bytes or whatever the caller passed in as a hint
73 strResult.reserve(iSizeHint);
74 #endif
76 while (!feof(fp))
78 memset(szBuffer, 0, XML_UTIL_READ_BUFFER_SIZE);
79 fread(szBuffer, 1, XML_UTIL_READ_BUFFER_SIZE - 1, fp);
80 strResult += szBuffer;
83 fclose(fp);
84 fp = NULL;
87 return strResult;
91 // Returns what is between the given tag in the passed XML. We only return the first matching
92 // tag if there are multiple in the XML. Tags are case sensitive.
93 string XMLUtil::GetElementString(const string& strTag, const string& strXML, bool bStripWhiteSpace)
95 string strResult = "";
96 string strStart = "";
97 string strEnd = "";
99 strStart += "<";
100 strStart += strTag;
101 strStart += ">";
103 strEnd += "</";
104 strEnd += strTag;
105 strEnd += ">";
107 int iPosStart = strXML.find(strStart);
108 int iPosEnd = strXML.find(strEnd);
110 if ((iPosStart != -1) && (iPosEnd != -1))
112 strResult = strXML.substr(iPosStart + strStart.length(), iPosEnd - (iPosStart + strStart.length()));
115 if (bStripWhiteSpace)
116 strResult = StripWhiteSpace(strResult);
118 return strResult;
121 // Return the integer representing an element
122 int XMLUtil::GetElementInt(const string& strTag, const string& strXML, bool* pFound)
124 string strElement = GetElementString(strTag, strXML);
126 unsigned int i = 0;
127 for (i = 0; i < strElement.size(); i++)
129 if (i == 0)
131 if ((!IsDigit(strElement[i])) && ((strElement[i] != '-')))
132 break;
134 else
135 if (!IsDigit(strElement[i]))
136 break;
139 // Only try and convert something that is all digits
140 if (i == strElement.size())
142 if (pFound != NULL)
143 *pFound = true;
144 return atoi(strElement.c_str());
146 else
148 if (pFound != NULL)
149 *pFound = false;
150 return -1;
154 int64 XMLUtil::GetElementLongLong(const string& strTag, const string& strXML, bool* pFound)
156 string strElement = GetElementString(strTag, strXML);
158 unsigned int i = 0;
159 for (i = 0; i < strElement.size(); i++)
161 if (i == 0)
163 if ((!IsDigit(strElement[i])) && ((strElement[i] != '-')))
164 break;
166 else
167 if (!IsDigit(strElement[i]))
168 break;
171 // Only try and convert something that is all digits
172 if ((i > 0) && (i == strElement.size()))
174 if (pFound != NULL)
175 *pFound = true;
176 #ifdef _WIN32
177 return _atoi64(strElement.c_str());
178 #else
179 return atoll(strElement.c_str());
180 #endif
182 else
184 if (pFound != NULL)
185 *pFound = false;
186 return -1;
190 // Optionally can pass back a bool that tell us if the tag was found
191 float XMLUtil::GetElementFloat(const string& strTag, const string& strXML, bool* pFound)
193 string strElement = GetElementString(strTag, strXML);
195 bool bFoundDot = false;
197 unsigned int i = 0;
198 for (i = 0; i < strElement.size(); i++)
200 if (i == 0)
202 if ((!IsDigit(strElement[i])) && ((strElement[i] != '-')))
203 break;
205 else
207 if (!IsDigit(strElement[i]))
209 if ((strElement[i] == '.') && (!bFoundDot))
210 bFoundDot = true;
211 else
212 break;
217 // Only try and convert something that is all digits
218 if ((i > 0) && (i == strElement.size()))
220 if (pFound != NULL)
221 *pFound = true;
222 return (float) atof(strElement.c_str());
224 else
226 if (pFound != NULL)
227 *pFound = false;
228 return (float) 0.0;
232 // Return a vector containing all the text inside all tags matching the passed one
233 VECTOR_STRING XMLUtil::GetElementStrings(const string& strTag, const string& strXML, bool bStripWhiteSpace)
235 VECTOR_STRING vResult;
236 vResult.reserve(XML_UTIL_DEFAULT_VECTOR_SIZE);
238 string strStart = "";
239 string strEnd = "";
240 string strResult = "";
242 strStart += "<";
243 strStart += strTag;
244 strStart += ">";
246 strEnd += "</";
247 strEnd += strTag;
248 strEnd += ">";
250 int iPosStart = strXML.find(strStart);
251 int iPosEnd = strXML.find(strEnd);
253 while ((iPosStart != string::npos) && (iPosEnd != string::npos))
255 // We want to be able to handle having the same tag emedded in itself.
256 // So between the start tag and the first instance of the end tag,
257 // we'll count any other instances of the start tag. If we find some
258 // then we require that we continue until we get that number more of
259 // close tags.
260 int iCurrentStart = iPosStart + strStart.length();
261 int iEmbedCount = 0;
262 while ((iCurrentStart != string::npos) && (iCurrentStart < iPosEnd))
264 iCurrentStart = strXML.find(strStart, iCurrentStart);
265 if ((iCurrentStart != string::npos) && (iCurrentStart < iPosEnd))
267 iEmbedCount++;
268 iCurrentStart += strStart.length();
271 // Now look for end tag to balance the start tags
272 for (int i = 0; i < iEmbedCount; i++)
274 iPosEnd = strXML.find(strEnd, iPosEnd + strEnd.length());
276 // Check to make sure we're still matching tags
277 if (iPosEnd == string::npos)
278 break;
281 strResult = strXML.substr(iPosStart + strStart.length(), iPosEnd - (iPosStart + strStart.length()));
283 if (bStripWhiteSpace)
284 strResult = StripWhiteSpace(strResult);
286 iPosStart = strXML.find(strStart, iPosEnd + strEnd.length());
288 if (iPosStart != string::npos)
289 iPosEnd = strXML.find(strEnd, iPosStart);
291 vResult.push_back(strResult);
294 return vResult;
297 VECTOR_NAME_VALUE_PAIR XMLUtil::GetNameValuePairs(const string& strXML, bool bStripWhiteSpace)
299 VECTOR_NAME_VALUE_PAIR vResult;
300 vResult.reserve(XML_UTIL_DEFAULT_VECTOR_SIZE);
302 bool bInStartTag = false;
303 string strName = "";
304 string strValue = "";
306 unsigned int i = 0;
307 while (i < strXML.length())
309 if ((!bInStartTag) && (strXML[i] == '<'))
311 // Starting a new tag
312 bInStartTag = true;
314 else if (bInStartTag)
316 if (strXML[i] == '>')
318 // Hit the end of the start tag, get everything
319 // until we find the end tag.
321 string strFind = "</";
322 strFind += strName;
323 strFind += ">";
325 int iPos = -1;
326 iPos = strXML.find(strFind, i);
328 if (iPos != -1)
330 strValue = strXML.substr(i + 1, iPos - i - 1);
332 NameValuePair sPair;
333 sPair.strName = strName;
334 sPair.strValue = strValue;
336 vResult.push_back(sPair);
338 i = iPos + strFind.length();
341 else
342 break;
344 bInStartTag = false;
345 strName = "";
346 strValue = "";
348 else
349 strName += strXML[i];
352 i++;
355 return vResult;