MRPT  1.9.9
xmlParser.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2018, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #ifndef _CRT_SECURE_NO_DEPRECATE
11 #define _CRT_SECURE_NO_DEPRECATE
12 #endif
13 #undef _UNICODE // JLBC
14 #include "xmlParser.h"
15 #ifdef _XMLWINDOWS
16 #define WIN32_LEAN_AND_MEAN
17 #include <Windows.h> // to have IsTextUnicode, MultiByteToWideChar, WideCharToMultiByte to handle unicode files
18 // to have "MessageBoxA" to display error messages for openFilHelper
19 #endif
20 
21 #include <memory.h>
22 #include <cassert>
23 #include <cstdio>
24 #include <cstring>
25 #include <cstdlib>
26 
27 XMLCSTR XMLNode::getVersion() { return _CXML("v2.39"); }
29 {
30  if (t) free(t);
31 }
32 
34 static char guessWideCharChars = 1, dropWhiteSpace = 1,
36 
37 inline int mmin(const int t1, const int t2) { return t1 < t2 ? t1 : t2; }
38 // You can modify the initialization of the variable "XMLClearTags" below
39 // to change the clearTags that are currently recognized by the library.
40 // The number on the second columns is the length of the string inside the
41 // first column. The "<!DOCTYPE" declaration must be the second in the list.
42 // The "<!--" declaration must be the third in the list.
43 typedef struct
44 {
50  {_CXML("<![CDATA["), 9, _CXML("]]>")},
51  {_CXML("<!DOCTYPE"), 9, _CXML(">")},
52  {_CXML("<!--"), 4, _CXML("-->")},
53  {_CXML("<PRE>"), 5, _CXML("</PRE>")},
54  // { _CXML("<Script>") ,8, _CXML("</Script>")},
55  {nullptr, 0, nullptr}};
56 
57 // You can modify the initialization of the variable "XMLEntities" below
58 // to change the character entities that are currently recognized by the
59 // library.
60 // The number on the second columns is the length of the string inside the
61 // first column. Additionally, the syntaxes "&#xA0;" and "&#160;" are
62 // recognized.
63 typedef struct
64 {
66  int l;
70  {_CXML("&amp;"), 5, _CXML('&')}, {_CXML("&lt;"), 4, _CXML('<')},
71  {_CXML("&gt;"), 4, _CXML('>')}, {_CXML("&quot;"), 6, _CXML('\"')},
72  {_CXML("&apos;"), 6, _CXML('\'')}, {nullptr, 0, '\0'}};
73 
74 // When rendering the XMLNode to a string (using the "createXMLString"
75 // function),
76 // you can ask for a beautiful formatting. This formatting is using the
77 // following indentation character:
78 #define INDENTCHAR _CXML('\t')
79 
80 // The following function parses the XML errors into a user friendly string.
81 // You can edit this to change the output language of the library to something
82 // else.
84 {
85  switch (xerror)
86  {
87  case eXMLErrorNone:
88  return _CXML("No error");
90  return _CXML("Warning: Unmatched end tag");
92  return _CXML("Warning: No XML tag found");
93  case eXMLErrorEmpty:
94  return _CXML("Error: No XML data");
96  return _CXML("Error: Missing start tag name");
98  return _CXML("Error: Missing end tag name");
100  return _CXML("Error: Unmatched end tag");
102  return _CXML("Error: Unmatched clear tag end");
104  return _CXML("Error: Unexpected token found");
105  case eXMLErrorNoElements:
106  return _CXML("Error: No elements found");
108  return _CXML("Error: File not found");
110  return _CXML("Error: First Tag not found");
112  return _CXML("Error: Unknown character entity");
114  return _CXML(
115  "Error: Character code above 255 is forbidden in MultiByte "
116  "char mode.");
118  return _CXML(
119  "Error: unable to convert between WideChar and MultiByte "
120  "chars");
122  return _CXML("Error: unable to open file for writing");
124  return _CXML("Error: cannot write into file");
125 
127  return _CXML(
128  "Warning: Base64-string length is not a multiple of 4");
130  return _CXML("Warning: Base64-string is truncated");
132  return _CXML("Error: Base64-string contains an illegal character");
134  return _CXML("Error: Base64 decode output buffer is too small");
135  };
136  return _CXML("Unknown");
137 }
138 
139 /////////////////////////////////////////////////////////////////////////
140 // Here start the abstraction layer to be OS-independent //
141 /////////////////////////////////////////////////////////////////////////
142 
143 // Here is an abstraction layer to access some common string manipulation
144 // functions.
145 // The abstraction layer is currently working for gcc, Microsoft Visual Studio
146 // 6.0,
147 // Microsoft Visual Studio .NET, CC (sun compiler) and Borland C++.
148 // If you plan to "port" the library to a new system/compiler, all you have to
149 // do is
150 // to edit the following lines.
151 #ifdef XML_NO_WIDE_CHAR
152 char myIsTextWideChar(const void* b, int len) { return FALSE; }
153 #else
154 #if defined(UNDER_CE) || !defined(_XMLWINDOWS)
155 char myIsTextWideChar(
156  const void* b, int len) // inspired by the Wine API: RtlIsTextUnicode
157 {
158 #ifdef sun
159  // for SPARC processors: wchar_t* buffers must always be alligned, otherwise
160  // it's a char* buffer.
161  if ((((unsigned long)b) % sizeof(wchar_t)) != 0) return FALSE;
162 #endif
163  const wchar_t* s = (const wchar_t*)b;
164 
165  // buffer too small:
166  if (len < (int)sizeof(wchar_t)) return FALSE;
167 
168  // odd length test
169  if (len & 1) return FALSE;
170 
171  /* only checks the first 256 characters */
172  len = mmin(256, len / sizeof(wchar_t));
173 
174  // Check for the special byte order:
175  if (*((unsigned short*)s) == 0xFFFE)
176  return TRUE; // IS_TEXT_UNICODE_REVERSE_SIGNATURE;
177  if (*((unsigned short*)s) == 0xFEFF)
178  return TRUE; // IS_TEXT_UNICODE_SIGNATURE
179 
180  // checks for ASCII characters in the UNICODE stream
181  int i, stats = 0;
182  for (i = 0; i < len; i++)
183  if (s[i] <= (unsigned short)255) stats++;
184  if (stats > len / 2) return TRUE;
185 
186  // Check for UNICODE nullptr chars
187  for (i = 0; i < len; i++)
188  if (!s[i]) return TRUE;
189 
190  return FALSE;
191 }
192 #else
193 char myIsTextWideChar(const void* b, int l)
194 {
195  return (char)IsTextUnicode((CONST LPVOID)b, l, nullptr);
196 }
197 #endif
198 #endif
199 
200 #ifdef _XMLWINDOWS
201 // for Microsoft Visual Studio 6.0 and Microsoft Visual Studio .NET and Borland
202 // C++ Builder 6.0
203 #ifdef _XMLWIDECHAR
204 wchar_t* myMultiByteToWideChar(const char* s, XMLNode::XMLCharEncoding ce)
205 {
206  int i;
207  if (ce == XMLNode::char_encoding_UTF8)
208  i = (int)MultiByteToWideChar(CP_UTF8, 0, s, -1, nullptr, 0);
209  else
210  i = (int)MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, s, -1, nullptr, 0);
211  if (i < 0) return nullptr;
212  wchar_t* d = (wchar_t*)malloc((i + 1) * sizeof(XMLCHAR));
213  if (ce == XMLNode::char_encoding_UTF8)
214  i = (int)MultiByteToWideChar(CP_UTF8, 0, s, -1, d, i);
215  else
216  i = (int)MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, s, -1, d, i);
217  d[i] = 0;
218  return d;
219 }
220 static inline FILE* xfopen(XMLCSTR filename, XMLCSTR mode)
221 {
222  return _wfopen(filename, mode);
223 }
224 static inline int xstrlen(XMLCSTR c) { return (int)wcslen(c); }
225 static inline int xstrnicmp(XMLCSTR c1, XMLCSTR c2, int l)
226 {
227  return _wcsnicmp(c1, c2, l);
228 }
229 static inline int xstrncmp(XMLCSTR c1, XMLCSTR c2, int l)
230 {
231  return wcsncmp(c1, c2, l);
232 }
233 static inline int xstricmp(XMLCSTR c1, XMLCSTR c2) { return _wcsicmp(c1, c2); }
234 static inline XMLSTR xstrstr(XMLCSTR c1, XMLCSTR c2)
235 {
236  return (XMLSTR)wcsstr(c1, c2);
237 }
238 static inline XMLSTR xstrcpy(XMLSTR c1, XMLCSTR c2)
239 {
240  return (XMLSTR)wcscpy(c1, c2);
241 }
242 #else
243 char* myWideCharToMultiByte(const wchar_t* s)
244 {
245  UINT codePage = CP_ACP;
246  if (characterEncoding == XMLNode::char_encoding_UTF8) codePage = CP_UTF8;
247  int i = (int)WideCharToMultiByte(
248  codePage, // code page
249  0, // performance and mapping flags
250  s, // wide-character string
251  -1, // number of chars in string
252  nullptr, // buffer for new string
253  0, // size of buffer
254  nullptr, // default for unmappable chars
255  nullptr // set when default char used
256  );
257  if (i < 0) return nullptr;
258  char* d = (char*)malloc(i + 1);
259  WideCharToMultiByte(
260  codePage, // code page
261  0, // performance and mapping flags
262  s, // wide-character string
263  -1, // number of chars in string
264  d, // buffer for new string
265  i, // size of buffer
266  nullptr, // default for unmappable chars
267  nullptr // set when default char used
268  );
269  d[i] = 0;
270  return d;
271 }
272 static inline FILE* xfopen(XMLCSTR filename, XMLCSTR mode)
273 {
274  return fopen(filename, mode);
275 }
276 static inline int xstrlen(XMLCSTR c) { return (int)strlen(c); }
277 #ifdef __BORLANDC__
278 static inline int xstrnicmp(XMLCSTR c1, XMLCSTR c2, int l)
279 {
280  return strnicmp(c1, c2, l);
281 }
282 static inline int xstricmp(XMLCSTR c1, XMLCSTR c2) { return stricmp(c1, c2); }
283 #else
284 static inline int xstrnicmp(XMLCSTR c1, XMLCSTR c2, int l)
285 {
286  return _strnicmp(c1, c2, l);
287 }
288 static inline int xstricmp(XMLCSTR c1, XMLCSTR c2) { return _stricmp(c1, c2); }
289 #endif
290 static inline int xstrncmp(XMLCSTR c1, XMLCSTR c2, int l)
291 {
292  return strncmp(c1, c2, l);
293 }
294 static inline XMLSTR xstrstr(XMLCSTR c1, XMLCSTR c2)
295 {
296  return (XMLSTR)strstr(c1, c2);
297 }
298 static inline XMLSTR xstrcpy(XMLSTR c1, XMLCSTR c2)
299 {
300  return (XMLSTR)strcpy(c1, c2);
301 }
302 #endif
303 #else
304 // for gcc and CC
305 #ifdef XML_NO_WIDE_CHAR
306 char* myWideCharToMultiByte(const wchar_t* s) { return nullptr; }
307 #else
308 char* myWideCharToMultiByte(const wchar_t* s)
309 {
310  const wchar_t* ss = s;
311  int i = (int)wcsrtombs(nullptr, &ss, 0, nullptr);
312  if (i < 0) return nullptr;
313  char* d = (char*)malloc(i + 1);
314  wcsrtombs(d, &s, i, nullptr);
315  d[i] = 0;
316  return d;
317 }
318 #endif
319 #ifdef _XMLWIDECHAR
320 wchar_t* myMultiByteToWideChar(const char* s, XMLNode::XMLCharEncoding ce)
321 {
322  const char* ss = s;
323  int i = (int)mbsrtowcs(nullptr, &ss, 0, nullptr);
324  if (i < 0) return nullptr;
325  wchar_t* d = (wchar_t*)malloc((i + 1) * sizeof(wchar_t));
326  mbsrtowcs(d, &s, i, nullptr);
327  d[i] = 0;
328  return d;
329 }
330 int xstrlen(XMLCSTR c) { return wcslen(c); }
331 #ifdef sun
332 // for CC
333 #include <widec.h>
334 static inline int xstrnicmp(XMLCSTR c1, XMLCSTR c2, int l)
335 {
336  return wsncasecmp(c1, c2, l);
337 }
338 static inline int xstrncmp(XMLCSTR c1, XMLCSTR c2, int l)
339 {
340  return wsncmp(c1, c2, l);
341 }
342 static inline int xstricmp(XMLCSTR c1, XMLCSTR c2) { return wscasecmp(c1, c2); }
343 #else
344 // for gcc
345 static inline int xstrnicmp(XMLCSTR c1, XMLCSTR c2, int l)
346 {
347  return wcsncasecmp(c1, c2, l);
348 }
349 static inline int xstrncmp(XMLCSTR c1, XMLCSTR c2, int l)
350 {
351  return wcsncmp(c1, c2, l);
352 }
353 static inline int xstricmp(XMLCSTR c1, XMLCSTR c2)
354 {
355  return wcscasecmp(c1, c2);
356 }
357 #endif
358 static inline XMLSTR xstrstr(XMLCSTR c1, XMLCSTR c2)
359 {
360  return (XMLSTR)wcsstr(c1, c2);
361 }
362 static inline XMLSTR xstrcpy(XMLSTR c1, XMLCSTR c2)
363 {
364  return (XMLSTR)wcscpy(c1, c2);
365 }
366 static inline FILE* xfopen(XMLCSTR filename, XMLCSTR mode)
367 {
368  char* filenameAscii = myWideCharToMultiByte(filename);
369  FILE* f;
370  if (mode[0] == _CXML('r'))
371  f = fopen(filenameAscii, "rb");
372  else
373  f = fopen(filenameAscii, "wb");
374  free(filenameAscii);
375  return f;
376 }
377 #else
378 static inline FILE* xfopen(XMLCSTR filename, XMLCSTR mode)
379 {
380  return fopen(filename, mode);
381 }
382 static inline int xstrlen(XMLCSTR c) { return strlen(c); }
383 static inline int xstrnicmp(XMLCSTR c1, XMLCSTR c2, int l)
384 {
385  return strncasecmp(c1, c2, l);
386 }
387 static inline int xstrncmp(XMLCSTR c1, XMLCSTR c2, int l)
388 {
389  return strncmp(c1, c2, l);
390 }
391 static inline int xstricmp(XMLCSTR c1, XMLCSTR c2)
392 {
393  return strcasecmp(c1, c2);
394 }
395 static inline XMLSTR xstrstr(XMLCSTR c1, XMLCSTR c2)
396 {
397  return (XMLSTR)strstr(c1, c2);
398 }
399 static inline XMLSTR xstrcpy(XMLSTR c1, XMLCSTR c2)
400 {
401  return (XMLSTR)strcpy(c1, c2);
402 }
403 #endif
404 #ifdef __clang__
405 #pragma clang diagnostic push
406 #pragma clang diagnostic ignored "-Wunused-function"
407 static inline int _strnicmp(const char* c1, const char* c2, int l)
408 {
409  return strncasecmp(c1, c2, l);
410 }
411 #pragma clang diagnostic pop
412 #endif
413 #endif
414 
415 ///////////////////////////////////////////////////////////////////////////////
416 // the "xmltoc,xmltob,xmltoi,xmltol,xmltof,xmltoa" functions //
417 ///////////////////////////////////////////////////////////////////////////////
418 // These 6 functions are not used inside the XMLparser.
419 // There are only here as "convenience" functions for the user.
420 // If you don't need them, you can delete them without any trouble.
421 #ifdef _XMLWIDECHAR
422 #ifdef _XMLWINDOWS
423 // for Microsoft Visual Studio 6.0 and Microsoft Visual Studio .NET and Borland
424 // C++ Builder 6.0
425 char xmltob(XMLCSTR t, int v)
426 {
427  if (t && (*t)) return (char)_wtoi(t);
428  return v;
429 }
430 int xmltoi(XMLCSTR t, int v)
431 {
432  if (t && (*t)) return _wtoi(t);
433  return v;
434 }
435 long xmltol(XMLCSTR t, long v)
436 {
437  if (t && (*t)) return _wtol(t);
438  return v;
439 }
440 double xmltof(XMLCSTR t, double v)
441 {
442  if (t && (*t)) wscanf(t, "%f", &v); /*v=_wtof(t);*/
443  return v;
444 }
445 #else
446 #ifdef sun
447 // for CC
448 #include <widec.h>
449 char xmltob(XMLCSTR t, int v)
450 {
451  if (t) return (char)wstol(t, nullptr, 10);
452  return v;
453 }
454 int xmltoi(XMLCSTR t, int v)
455 {
456  if (t) return (int)wstol(t, nullptr, 10);
457  return v;
458 }
459 long xmltol(XMLCSTR t, long v)
460 {
461  if (t) return wstol(t, nullptr, 10);
462  return v;
463 }
464 #else
465 // for gcc
466 char xmltob(XMLCSTR t, int v)
467 {
468  if (t) return (char)wcstol(t, nullptr, 10);
469  return v;
470 }
471 int xmltoi(XMLCSTR t, int v)
472 {
473  if (t) return (int)wcstol(t, nullptr, 10);
474  return v;
475 }
476 long xmltol(XMLCSTR t, long v)
477 {
478  if (t) return wcstol(t, nullptr, 10);
479  return v;
480 }
481 #endif
482 double xmltof(XMLCSTR t, double v)
483 {
484  if (t && (*t)) wscanf(t, "%f", &v); /*v=_wtof(t);*/
485  return v;
486 }
487 #endif
488 #else
489 char xmltob(XMLCSTR t, char v)
490 {
491  if (t && (*t)) return (char)atoi(t);
492  return v;
493 }
494 int xmltoi(XMLCSTR t, int v)
495 {
496  if (t && (*t)) return atoi(t);
497  return v;
498 }
499 long xmltol(XMLCSTR t, long v)
500 {
501  if (t && (*t)) return atol(t);
502  return v;
503 }
504 double xmltof(XMLCSTR t, double v)
505 {
506  if (t && (*t)) return atof(t);
507  return v;
508 }
509 #endif
511 {
512  if (t) return t;
513  return v;
514 }
516 {
517  if (t && (*t)) return *t;
518  return v;
519 }
520 
521 /////////////////////////////////////////////////////////////////////////
522 // the "openFileHelper" function //
523 /////////////////////////////////////////////////////////////////////////
524 
525 // Since each application has its own way to report and deal with errors, you
526 // should modify & rewrite
527 // the following "openFileHelper" function to get an "error reporting mechanism"
528 // tailored to your needs.
530 {
531  // guess the value of the global parameter "characterEncoding"
532  // (the guess is based on the first 200 bytes of the file).
533  FILE* f = xfopen(filename, _CXML("rb"));
534  if (f)
535  {
536  char bb[205];
537  int l = (int)fread(bb, 1, 200, f);
541  fclose(f);
542  }
543 
544  // parse the file
545  XMLResults pResults;
546  XMLNode xnode = XMLNode::parseFile(filename, tag, &pResults);
547 
548  // display error message (if any)
549  if (pResults.error != eXMLErrorNone)
550  {
551  // create message
552  char message[2000], *s1 = (char *)"", *s3 = (char *)"";
553  XMLCSTR s2 = _CXML("");
554  if (pResults.error == eXMLErrorFirstTagNotFound)
555  {
556  s1 = (char*)"First Tag should be '";
557  s2 = tag;
558  s3 = (char*)"'.\n";
559  }
560  sprintf(
561  message,
562 #ifdef _XMLWIDECHAR
563  "XML Parsing error inside file '%S'.\n%S\nAt line %i, column "
564  "%i.\n%s%S%s"
565 #else
566  "XML Parsing error inside file '%s'.\n%s\nAt line %i, column "
567  "%i.\n%s%s%s"
568 #endif
569  ,
570  filename, XMLNode::getError(pResults.error), pResults.nLine,
571  pResults.nColumn, s1, s2, s3);
572 
573 // display message
574 #if defined(_XMLWINDOWS) && !defined(UNDER_CE) && \
575  !defined(_XMLPARSER_NO_MESSAGEBOX_)
576  MessageBoxA(
577  nullptr, message, "XML Parsing error",
578  MB_OK | MB_ICONERROR | MB_TOPMOST);
579 #else
580  printf("%s", message);
581 #endif
582  // exit(255);
583  }
584  return xnode;
585 }
586 
587 /////////////////////////////////////////////////////////////////////////
588 // Here start the core implementation of the XMLParser library //
589 /////////////////////////////////////////////////////////////////////////
590 
591 // You should normally not change anything below this point.
592 
593 #ifndef _XMLWIDECHAR
594 // If "characterEncoding=ascii" then we assume that all characters have the same
595 // length of 1 byte.
596 // If "characterEncoding=UTF8" then the characters have different lengths (from
597 // 1 byte to 4 bytes).
598 // If "characterEncoding=ShiftJIS" then the characters have different lengths
599 // (from 1 byte to 2 bytes).
600 // This table is used as lookup-table to know the length of a character (in
601 // byte) based on the
602 // content of the first byte of the character.
603 // (note: if you modify this, you must always have XML_utf8ByteTable[0]=0 ).
604 static const char XML_utf8ByteTable[256] = {
605  // 0 1 2 3 4 5 6 7 8 9 a b c d e f
606  0, 1, 1, 1, 1, 1, 1, 1,
607  1, 1, 1, 1, 1, 1, 1, 1, // 0x00
608  1, 1, 1, 1, 1, 1, 1, 1,
609  1, 1, 1, 1, 1, 1, 1, 1, // 0x10
610  1, 1, 1, 1, 1, 1, 1, 1,
611  1, 1, 1, 1, 1, 1, 1, 1, // 0x20
612  1, 1, 1, 1, 1, 1, 1, 1,
613  1, 1, 1, 1, 1, 1, 1, 1, // 0x30
614  1, 1, 1, 1, 1, 1, 1, 1,
615  1, 1, 1, 1, 1, 1, 1, 1, // 0x40
616  1, 1, 1, 1, 1, 1, 1, 1,
617  1, 1, 1, 1, 1, 1, 1, 1, // 0x50
618  1, 1, 1, 1, 1, 1, 1, 1,
619  1, 1, 1, 1, 1, 1, 1, 1, // 0x60
620  1, 1, 1, 1, 1, 1, 1, 1,
621  1, 1, 1, 1, 1, 1, 1, 1, // 0x70 End of ASCII range
622  1, 1, 1, 1, 1, 1, 1, 1,
623  1, 1, 1, 1, 1, 1, 1, 1, // 0x80 0x80 to 0xc1 invalid
624  1, 1, 1, 1, 1, 1, 1, 1,
625  1, 1, 1, 1, 1, 1, 1, 1, // 0x90
626  1, 1, 1, 1, 1, 1, 1, 1,
627  1, 1, 1, 1, 1, 1, 1, 1, // 0xa0
628  1, 1, 1, 1, 1, 1, 1, 1,
629  1, 1, 1, 1, 1, 1, 1, 1, // 0xb0
630  1, 1, 2, 2, 2, 2, 2, 2,
631  2, 2, 2, 2, 2, 2, 2, 2, // 0xc0 0xc2 to 0xdf 2 byte
632  2, 2, 2, 2, 2, 2, 2, 2,
633  2, 2, 2, 2, 2, 2, 2, 2, // 0xd0
634  3, 3, 3, 3, 3, 3, 3, 3,
635  3, 3, 3, 3, 3, 3, 3, 3, // 0xe0 0xe0 to 0xef 3 byte
636  4, 4, 4, 4, 4, 1, 1, 1,
637  1, 1, 1, 1, 1, 1, 1, 1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid
638 };
639 static const char XML_legacyByteTable[256] = {
640  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
641  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
642  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
643  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
644  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
645  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
646  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
647  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
648  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
649  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
650  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
651 static const char XML_sjisByteTable[256] = {
652  // 0 1 2 3 4 5 6 7 8 9 a b c d e f
653  0, 1, 1, 1, 1, 1, 1, 1,
654  1, 1, 1, 1, 1, 1, 1, 1, // 0x00
655  1, 1, 1, 1, 1, 1, 1, 1,
656  1, 1, 1, 1, 1, 1, 1, 1, // 0x10
657  1, 1, 1, 1, 1, 1, 1, 1,
658  1, 1, 1, 1, 1, 1, 1, 1, // 0x20
659  1, 1, 1, 1, 1, 1, 1, 1,
660  1, 1, 1, 1, 1, 1, 1, 1, // 0x30
661  1, 1, 1, 1, 1, 1, 1, 1,
662  1, 1, 1, 1, 1, 1, 1, 1, // 0x40
663  1, 1, 1, 1, 1, 1, 1, 1,
664  1, 1, 1, 1, 1, 1, 1, 1, // 0x50
665  1, 1, 1, 1, 1, 1, 1, 1,
666  1, 1, 1, 1, 1, 1, 1, 1, // 0x60
667  1, 1, 1, 1, 1, 1, 1, 1,
668  1, 1, 1, 1, 1, 1, 1, 1, // 0x70
669  1, 2, 2, 2, 2, 2, 2, 2,
670  2, 2, 2, 2, 2, 2, 2, 2, // 0x80 0x81 to 0x9F 2 bytes
671  2, 2, 2, 2, 2, 2, 2, 2,
672  2, 2, 2, 2, 2, 2, 2, 2, // 0x90
673  1, 1, 1, 1, 1, 1, 1, 1,
674  1, 1, 1, 1, 1, 1, 1, 1, // 0xa0
675  1, 1, 1, 1, 1, 1, 1, 1,
676  1, 1, 1, 1, 1, 1, 1, 1, // 0xb0
677  1, 1, 1, 1, 1, 1, 1, 1,
678  1, 1, 1, 1, 1, 1, 1, 1, // 0xc0
679  1, 1, 1, 1, 1, 1, 1, 1,
680  1, 1, 1, 1, 1, 1, 1, 1, // 0xd0
681  2, 2, 2, 2, 2, 2, 2, 2,
682  2, 2, 2, 2, 2, 2, 2, 2, // 0xe0 0xe0 to 0xef 2 bytes
683  1, 1, 1, 1, 1, 1, 1, 1,
684  1, 1, 1, 1, 1, 1, 1, 1 // 0xf0
685 };
686 static const char XML_gb2312ByteTable[256] = {
687  // 0 1 2 3 4 5 6 7 8 9 a b c d e f
688  0, 1, 1, 1, 1, 1, 1, 1,
689  1, 1, 1, 1, 1, 1, 1, 1, // 0x00
690  1, 1, 1, 1, 1, 1, 1, 1,
691  1, 1, 1, 1, 1, 1, 1, 1, // 0x10
692  1, 1, 1, 1, 1, 1, 1, 1,
693  1, 1, 1, 1, 1, 1, 1, 1, // 0x20
694  1, 1, 1, 1, 1, 1, 1, 1,
695  1, 1, 1, 1, 1, 1, 1, 1, // 0x30
696  1, 1, 1, 1, 1, 1, 1, 1,
697  1, 1, 1, 1, 1, 1, 1, 1, // 0x40
698  1, 1, 1, 1, 1, 1, 1, 1,
699  1, 1, 1, 1, 1, 1, 1, 1, // 0x50
700  1, 1, 1, 1, 1, 1, 1, 1,
701  1, 1, 1, 1, 1, 1, 1, 1, // 0x60
702  1, 1, 1, 1, 1, 1, 1, 1,
703  1, 1, 1, 1, 1, 1, 1, 1, // 0x70
704  1, 1, 1, 1, 1, 1, 1, 1,
705  1, 1, 1, 1, 1, 1, 1, 1, // 0x80
706  1, 1, 1, 1, 1, 1, 1, 1,
707  1, 1, 1, 1, 1, 1, 1, 1, // 0x90
708  1, 2, 2, 2, 2, 2, 2, 2,
709  2, 2, 2, 2, 2, 2, 2, 2, // 0xa0 0xa1 to 0xf7 2 bytes
710  2, 2, 2, 2, 2, 2, 2, 2,
711  2, 2, 2, 2, 2, 2, 2, 2, // 0xb0
712  2, 2, 2, 2, 2, 2, 2, 2,
713  2, 2, 2, 2, 2, 2, 2, 2, // 0xc0
714  2, 2, 2, 2, 2, 2, 2, 2,
715  2, 2, 2, 2, 2, 2, 2, 2, // 0xd0
716  2, 2, 2, 2, 2, 2, 2, 2,
717  2, 2, 2, 2, 2, 2, 2, 2, // 0xe0
718  2, 2, 2, 2, 2, 2, 2, 2,
719  1, 1, 1, 1, 1, 1, 1, 1 // 0xf0
720 };
721 static const char XML_gbk_big5_ByteTable[256] = {
722  // 0 1 2 3 4 5 6 7 8 9 a b c d e f
723  0, 1, 1, 1, 1, 1, 1, 1,
724  1, 1, 1, 1, 1, 1, 1, 1, // 0x00
725  1, 1, 1, 1, 1, 1, 1, 1,
726  1, 1, 1, 1, 1, 1, 1, 1, // 0x10
727  1, 1, 1, 1, 1, 1, 1, 1,
728  1, 1, 1, 1, 1, 1, 1, 1, // 0x20
729  1, 1, 1, 1, 1, 1, 1, 1,
730  1, 1, 1, 1, 1, 1, 1, 1, // 0x30
731  1, 1, 1, 1, 1, 1, 1, 1,
732  1, 1, 1, 1, 1, 1, 1, 1, // 0x40
733  1, 1, 1, 1, 1, 1, 1, 1,
734  1, 1, 1, 1, 1, 1, 1, 1, // 0x50
735  1, 1, 1, 1, 1, 1, 1, 1,
736  1, 1, 1, 1, 1, 1, 1, 1, // 0x60
737  1, 1, 1, 1, 1, 1, 1, 1,
738  1, 1, 1, 1, 1, 1, 1, 1, // 0x70
739  1, 2, 2, 2, 2, 2, 2, 2,
740  2, 2, 2, 2, 2, 2, 2, 2, // 0x80 0x81 to 0xfe 2 bytes
741  2, 2, 2, 2, 2, 2, 2, 2,
742  2, 2, 2, 2, 2, 2, 2, 2, // 0x90
743  2, 2, 2, 2, 2, 2, 2, 2,
744  2, 2, 2, 2, 2, 2, 2, 2, // 0xa0
745  2, 2, 2, 2, 2, 2, 2, 2,
746  2, 2, 2, 2, 2, 2, 2, 2, // 0xb0
747  2, 2, 2, 2, 2, 2, 2, 2,
748  2, 2, 2, 2, 2, 2, 2, 2, // 0xc0
749  2, 2, 2, 2, 2, 2, 2, 2,
750  2, 2, 2, 2, 2, 2, 2, 2, // 0xd0
751  2, 2, 2, 2, 2, 2, 2, 2,
752  2, 2, 2, 2, 2, 2, 2, 2, // 0xe0
753  2, 2, 2, 2, 2, 2, 2, 2,
754  2, 2, 2, 2, 2, 2, 2, 1 // 0xf0
755 };
756 static const char* XML_ByteTable =
757  (const char*)XML_utf8ByteTable; // the default is
758 // "characterEncoding=XMLNode::encoding_UTF8"
759 #endif
760 
762 XMLClear XMLNode::emptyXMLClear = {nullptr, nullptr, nullptr};
763 XMLAttribute XMLNode::emptyXMLAttribute = {nullptr, nullptr};
764 
765 // Enumeration used to decipher what type a token is
766 typedef enum XMLTokenTypeTag {
769  eTokenTagStart, /* "<" */
770  eTokenTagEnd, /* "</" */
771  eTokenCloseTag, /* ">" */
772  eTokenEquals, /* "=" */
773  eTokenDeclaration, /* "<?" */
777 } XMLTokenType;
778 
779 // Main structure used for parsing XML
780 typedef struct XML
781 {
787  int cbEndTag;
790  int nFirst;
791 } XML;
792 
793 typedef struct
794 {
797 } NextToken;
798 
799 // Enumeration used when parsing attributes
800 using Attrib = enum Attrib { eAttribName = 0, eAttribEquals, eAttribValue };
801 
802 // Enumeration used when parsing elements to dictate whether we are currently
803 // inside a tag
804 using Status = enum Status { eInsideTag = 0, eOutsideTag };
805 
807  XMLCSTR filename, const char* encoding, char nFormat) const
808 {
809  if (!d) return eXMLErrorNone;
810  FILE* f = xfopen(filename, _CXML("wb"));
811  if (!f) return eXMLErrorCannotOpenWriteFile;
812 #ifdef _XMLWIDECHAR
813  unsigned char h[2] = {0xFF, 0xFE};
814  if (!fwrite(h, 2, 1, f)) return eXMLErrorCannotWriteFile;
815  if ((!isDeclaration()) &&
816  ((d->lpszName) || (!getChildNode().isDeclaration())))
817  {
818  if (!fwrite(
819  L"<?xml version=\"1.0\" encoding=\"utf-16\"?>\n",
820  sizeof(wchar_t) * 40, 1, f))
822  }
823 #else
824  if ((!isDeclaration()) &&
825  ((d->lpszName) || (!getChildNode().isDeclaration())))
826  {
828  {
829  // header so that windows recognize the file as UTF-8:
830  unsigned char h[3] = {0xEF, 0xBB, 0xBF};
831  if (!fwrite(h, 3, 1, f)) return eXMLErrorCannotWriteFile;
832  encoding = "utf-8";
833  }
835  encoding = "SHIFT-JIS";
836 
837  if (!encoding) encoding = "ISO-8859-1";
838  if (fprintf(f, "<?xml version=\"1.0\" encoding=\"%s\"?>\n", encoding) <
839  0)
841  }
842  else
843  {
845  {
846  unsigned char h[3] = {0xEF, 0xBB, 0xBF};
847  if (!fwrite(h, 3, 1, f)) return eXMLErrorCannotWriteFile;
848  }
849  }
850 #endif
851  int i;
852  XMLSTR t = createXMLString(nFormat, &i);
853  if (!fwrite(t, sizeof(XMLCHAR) * i, 1, f)) return eXMLErrorCannotWriteFile;
854  if (fclose(f) != 0) return eXMLErrorCannotWriteFile;
855  free(t);
856  return eXMLErrorNone;
857 }
858 
859 // Duplicate a given string.
860 XMLSTR stringDup(XMLCSTR lpszData, int cbData)
861 {
862  if (lpszData == nullptr) return nullptr;
863 
864  XMLSTR lpszNew;
865  if (cbData == -1) cbData = (int)xstrlen(lpszData);
866  lpszNew = (XMLSTR)malloc((cbData + 1) * sizeof(XMLCHAR));
867  if (lpszNew)
868  {
869  memcpy(lpszNew, lpszData, (cbData) * sizeof(XMLCHAR));
870  lpszNew[cbData] = (XMLCHAR)NULL;
871  }
872  return lpszNew;
873 }
874 
876 {
877  XMLSTR dd = dest;
878  XMLCHAR ch;
879  XMLCharacterEntity* entity;
880  while ((ch = *source) != '\0')
881  {
882  entity = XMLEntities;
883  do
884  {
885  if (ch == entity->c)
886  {
887  xstrcpy(dest, entity->s);
888  dest += entity->l;
889  source++;
890  goto out_of_loop1;
891  }
892  entity++;
893  } while (entity->s);
894 #ifdef _XMLWIDECHAR
895  *(dest++) = *(source++);
896 #else
897  switch (XML_ByteTable[(unsigned char)ch])
898  {
899  case 4:
900  *(dest++) = *(source++);
901  /*FALLTHROUGH*/
902  case 3:
903  *(dest++) = *(source++);
904  /*FALLTHROUGH*/
905  case 2:
906  *(dest++) = *(source++);
907  /*FALLTHROUGH*/
908  case 1:
909  *(dest++) = *(source++);
910  /*FALLTHROUGH*/
911  }
912 #endif
913  out_of_loop1:;
914  }
915  *dest = 0;
916  return dd;
917 }
918 
919 // private (used while rendering):
921 {
922  int r = 0;
923  XMLCharacterEntity* entity;
924  XMLCHAR ch;
925  while ((ch = *source) != '\0')
926  {
927  entity = XMLEntities;
928  do
929  {
930  if (ch == entity->c)
931  {
932  r += entity->l;
933  source++;
934  goto out_of_loop1;
935  }
936  entity++;
937  } while (entity->s);
938 #ifdef _XMLWIDECHAR
939  r++;
940  source++;
941 #else
942  ch = XML_ByteTable[(unsigned char)ch];
943  r += ch;
944  source += ch;
945 #endif
946  out_of_loop1:;
947  }
948  return r;
949 }
950 
953 {
954  if (buf) free(buf);
955  buf = nullptr;
956  buflen = 0;
957 }
959 {
960  int l = lengthXMLString(source) + 1;
961  if (l > buflen)
962  {
963  buflen = l;
964  buf = (XMLSTR)realloc(buf, l * sizeof(XMLCHAR));
965  }
966  return toXMLUnSafe(buf, source);
967 }
968 
969 // private:
971 {
972  // This function is the opposite of the function "toXMLString". It decodes
973  // the escape
974  // sequences &amp;, &quot;, &apos;, &lt;, &gt; and replace them by the
975  // characters
976  // &,",',<,>. This function is used internally by the XML Parser. All the
977  // calls to
978  // the XML library will always gives you back "decoded" strings.
979  //
980  // in: string (s) and length (lo) of string
981  // out: new allocated string converted from xml
982  if (!s) return nullptr;
983 
984  int ll = 0, j;
985  XMLSTR d;
986  XMLCSTR ss = s;
987  XMLCharacterEntity* entity;
988  while ((lo > 0) && (*s))
989  {
990  if (*s == _CXML('&'))
991  {
992  if ((lo > 2) && (s[1] == _CXML('#')))
993  {
994  s += 2;
995  lo -= 2;
996  if ((*s == _CXML('X')) || (*s == _CXML('x')))
997  {
998  s++;
999  lo--;
1000  }
1001  while ((*s) && (*s != _CXML(';')) && ((lo--) > 0)) s++;
1002  if (*s != _CXML(';'))
1003  {
1005  return nullptr;
1006  }
1007  s++;
1008  lo--;
1009  }
1010  else
1011  {
1012  entity = XMLEntities;
1013  do
1014  {
1015  if ((lo >= entity->l) &&
1016  (xstrnicmp(s, entity->s, entity->l) == 0))
1017  {
1018  s += entity->l;
1019  lo -= entity->l;
1020  break;
1021  }
1022  entity++;
1023  } while (entity->s);
1024  if (!entity->s)
1025  {
1027  return nullptr;
1028  }
1029  }
1030  }
1031  else
1032  {
1033 #ifdef _XMLWIDECHAR
1034  s++;
1035  lo--;
1036 #else
1037  j = XML_ByteTable[(unsigned char)*s];
1038  s += j;
1039  lo -= j;
1040  ll += j - 1;
1041 #endif
1042  }
1043  ll++;
1044  }
1045 
1046  d = (XMLSTR)malloc((ll + 1) * sizeof(XMLCHAR));
1047  s = d;
1048  while (ll-- > 0)
1049  {
1050  if (*ss == _CXML('&'))
1051  {
1052  if (ss[1] == _CXML('#'))
1053  {
1054  ss += 2;
1055  j = 0;
1056  if ((*ss == _CXML('X')) || (*ss == _CXML('x')))
1057  {
1058  ss++;
1059  while (*ss != _CXML(';'))
1060  {
1061  if ((*ss >= _CXML('0')) && (*ss <= _CXML('9')))
1062  j = (j << 4) + *ss - _CXML('0');
1063  else if ((*ss >= _CXML('A')) && (*ss <= _CXML('F')))
1064  j = (j << 4) + *ss - _CXML('A') + 10;
1065  else if ((*ss >= _CXML('a')) && (*ss <= _CXML('f')))
1066  j = (j << 4) + *ss - _CXML('a') + 10;
1067  else
1068  {
1069  free((void*)s);
1071  return nullptr;
1072  }
1073  ss++;
1074  }
1075  }
1076  else
1077  {
1078  while (*ss != _CXML(';'))
1079  {
1080  if ((*ss >= _CXML('0')) && (*ss <= _CXML('9')))
1081  j = (j * 10) + *ss - _CXML('0');
1082  else
1083  {
1084  free((void*)s);
1086  return nullptr;
1087  }
1088  ss++;
1089  }
1090  }
1091 #ifndef _XMLWIDECHAR
1092  if (j > 255)
1093  {
1094  free((void*)s);
1096  return nullptr;
1097  }
1098 #endif
1099  (*d++) = (XMLCHAR)j;
1100  ss++;
1101  }
1102  else
1103  {
1104  entity = XMLEntities;
1105  do
1106  {
1107  if (xstrnicmp(ss, entity->s, entity->l) == 0)
1108  {
1109  *(d++) = entity->c;
1110  ss += entity->l;
1111  break;
1112  }
1113  entity++;
1114  } while (entity->s);
1115  }
1116  }
1117  else
1118  {
1119 #ifdef _XMLWIDECHAR
1120  *(d++) = *(ss++);
1121 #else
1122  switch (XML_ByteTable[(unsigned char)*ss])
1123  {
1124  case 4:
1125  *(d++) = *(ss++);
1126  ll--;
1127  /*FALLTHROUGH*/
1128  case 3:
1129  *(d++) = *(ss++);
1130  ll--;
1131  /*FALLTHROUGH*/
1132  case 2:
1133  *(d++) = *(ss++);
1134  ll--;
1135  /*FALLTHROUGH*/
1136  case 1:
1137  *(d++) = *(ss++);
1138  /*FALLTHROUGH*/
1139  }
1140 #endif
1141  }
1142  }
1143  *d = 0;
1144  return (XMLSTR)s;
1145 }
1146 
1147 #define XML_isSPACECHAR(ch) \
1148  ((ch == _CXML('\n')) || (ch == _CXML(' ')) || (ch == _CXML('\t')) || \
1149  (ch == _CXML('\r')))
1150 
1151 // private:
1152 char myTagCompare(XMLCSTR cclose, XMLCSTR copen)
1153 // !!!! WARNING strange convention&:
1154 // return 0 if equals
1155 // return 1 if different
1156 {
1157  if (!cclose) return 1;
1158  int l = (int)xstrlen(cclose);
1159  if (xstrnicmp(cclose, copen, l) != 0) return 1;
1160  const XMLCHAR c = copen[l];
1161  if (XML_isSPACECHAR(c) || (c == _CXML('/')) || (c == _CXML('<')) ||
1162  (c == _CXML('>')) || (c == _CXML('=')))
1163  return 0;
1164  return 1;
1165 }
1166 
1167 // Obtain the next character from the string.
1168 static inline XMLCHAR getNextChar(XML* pXML)
1169 {
1170  XMLCHAR ch = pXML->lpXML[pXML->nIndex];
1171 #ifdef _XMLWIDECHAR
1172  if (ch != 0) pXML->nIndex++;
1173 #else
1174  pXML->nIndex += XML_ByteTable[(unsigned char)ch];
1175 #endif
1176  return ch;
1177 }
1178 
1179 // Find the next token in a string.
1180 // pcbToken contains the number of characters that have been read.
1182  XML* pXML, int* pcbToken, enum XMLTokenTypeTag* pType)
1183 {
1184  NextToken result;
1185  XMLCHAR ch;
1186  XMLCHAR chTemp;
1187  int indexStart, nFoundMatch, nIsText = FALSE;
1188  result.pClr = nullptr; // prevent warning
1189 
1190  // Find next non-white space character
1191  do
1192  {
1193  indexStart = pXML->nIndex;
1194  ch = getNextChar(pXML);
1195  } while XML_isSPACECHAR(ch);
1196 
1197  if (ch)
1198  {
1199  // Cache the current string pointer
1200  result.pStr = &pXML->lpXML[indexStart];
1201 
1202  // First check whether the token is in the clear tag list (meaning it
1203  // does not need formatting).
1204  ALLXMLClearTag* ctag = XMLClearTags;
1205  do
1206  {
1207  if (xstrncmp(ctag->lpszOpen, result.pStr, ctag->openTagLen) == 0)
1208  {
1209  result.pClr = ctag;
1210  pXML->nIndex += ctag->openTagLen - 1;
1211  *pType = eTokenClear;
1212  return result;
1213  }
1214  ctag++;
1215  } while (ctag->lpszOpen);
1216 
1217  // If we didn't find a clear tag then check for standard tokens
1218  switch (ch)
1219  {
1220  // Check for quotes
1221  case _CXML('\''):
1222  case _CXML('\"'):
1223  // Type of token
1224  *pType = eTokenQuotedText;
1225  chTemp = ch;
1226 
1227  // Set the size
1228  nFoundMatch = FALSE;
1229 
1230  // Search through the string to find a matching quote
1231  while ((ch = getNextChar(pXML)))
1232  {
1233  if (ch == chTemp)
1234  {
1235  nFoundMatch = TRUE;
1236  break;
1237  }
1238  if (ch == _CXML('<')) break;
1239  }
1240 
1241  // If we failed to find a matching quote
1242  if (nFoundMatch == FALSE)
1243  {
1244  pXML->nIndex = indexStart + 1;
1245  nIsText = TRUE;
1246  break;
1247  }
1248 
1249  // 4.02.2002
1250  // if (FindNonWhiteSpace(pXML)) pXML->nIndex--;
1251 
1252  break;
1253 
1254  // Equals (used with attribute values)
1255  case _CXML('='):
1256  *pType = eTokenEquals;
1257  break;
1258 
1259  // Close tag
1260  case _CXML('>'):
1261  *pType = eTokenCloseTag;
1262  break;
1263 
1264  // Check for tag start and tag end
1265  case _CXML('<'):
1266 
1267  // Peek at the next character to see if we have an end tag '</',
1268  // or an xml declaration '<?'
1269  chTemp = pXML->lpXML[pXML->nIndex];
1270 
1271  // If we have a tag end...
1272  if (chTemp == _CXML('/'))
1273  {
1274  // Set the type and ensure we point at the next character
1275  getNextChar(pXML);
1276  *pType = eTokenTagEnd;
1277  }
1278 
1279  // If we have an XML declaration tag
1280  else if (chTemp == _CXML('?'))
1281  {
1282  // Set the type and ensure we point at the next character
1283  getNextChar(pXML);
1284  *pType = eTokenDeclaration;
1285  }
1286 
1287  // Otherwise we must have a start tag
1288  else
1289  {
1290  *pType = eTokenTagStart;
1291  }
1292  break;
1293 
1294  // Check to see if we have a short hand type end tag ('/>').
1295  case _CXML('/'):
1296 
1297  // Peek at the next character to see if we have a short end tag
1298  // '/>'
1299  chTemp = pXML->lpXML[pXML->nIndex];
1300 
1301  // If we have a short hand end tag...
1302  if (chTemp == _CXML('>'))
1303  {
1304  // Set the type and ensure we point at the next character
1305  getNextChar(pXML);
1306  *pType = eTokenShortHandClose;
1307  break;
1308  }
1309  /*FALLTHROUGH*/
1310 
1311  // If we haven't found a short hand closing tag then drop into the
1312  // text process
1313 
1314  // Other characters
1315  default:
1316  nIsText = TRUE;
1317  }
1318 
1319  // If this is a TEXT node
1320  if (nIsText)
1321  {
1322  // Indicate we are dealing with text
1323  *pType = eTokenText;
1324  while ((ch = getNextChar(pXML)))
1325  {
1326  if
1327  XML_isSPACECHAR(ch)
1328  {
1329  indexStart++;
1330  break;
1331  }
1332  else if (ch == _CXML('/'))
1333  {
1334  // If we find a slash then this maybe text or a short hand
1335  // end tag
1336  // Peek at the next character to see it we have short hand
1337  // end tag
1338  ch = pXML->lpXML[pXML->nIndex];
1339  // If we found a short hand end tag then we need to exit the
1340  // loop
1341  if (ch == _CXML('>'))
1342  {
1343  pXML->nIndex--;
1344  break;
1345  }
1346  }
1347  else if (
1348  (ch == _CXML('<')) || (ch == _CXML('>')) ||
1349  (ch == _CXML('=')))
1350  {
1351  pXML->nIndex--;
1352  break;
1353  }
1354  }
1355  }
1356  *pcbToken = pXML->nIndex - indexStart;
1357  }
1358  else
1359  {
1360  // If we failed to obtain a valid character
1361  *pcbToken = 0;
1362  *pType = eTokenError;
1363  result.pStr = nullptr;
1364  }
1365 
1366  return result;
1367 }
1368 
1370 {
1371  if (!d)
1372  {
1373  free(lpszName);
1374  return nullptr;
1375  }
1376  if (d->lpszName && (lpszName != d->lpszName)) free((void*)d->lpszName);
1377  d->lpszName = lpszName;
1378  return lpszName;
1379 }
1380 
1381 // private:
1383 {
1384  d = p;
1385  (p->ref_count)++;
1386 }
1387 XMLNode::XMLNode(XMLNodeData* pParent, XMLSTR lpszName, char isDeclaration)
1388 {
1389  d = (XMLNodeData*)malloc(sizeof(XMLNodeData));
1390  d->ref_count = 1;
1391 
1392  d->lpszName = nullptr;
1393  d->nChild = 0;
1394  d->nText = 0;
1395  d->nClear = 0;
1396  d->nAttribute = 0;
1397 
1398  d->isDeclaration = isDeclaration;
1399 
1400  d->pParent = pParent;
1401  d->pChild = nullptr;
1402  d->pText = nullptr;
1403  d->pClear = nullptr;
1404  d->pAttribute = nullptr;
1405  d->pOrder = nullptr;
1406 
1407  updateName_WOSD(lpszName);
1408 }
1409 
1410 XMLNode XMLNode::createXMLTopNode_WOSD(XMLSTR lpszName, char isDeclaration)
1411 {
1412  return XMLNode(nullptr, lpszName, isDeclaration);
1413 }
1414 XMLNode XMLNode::createXMLTopNode(XMLCSTR lpszName, char isDeclaration)
1415 {
1416  return XMLNode(nullptr, stringDup(lpszName), isDeclaration);
1417 }
1418 
1419 #define MEMORYINCREASE 50
1420 
1421 static inline void myFree(void* p)
1422 {
1423  if (p) free(p);
1424 }
1425 static inline void* myRealloc(void* p, int newsize, int memInc, int sizeofElem)
1426 {
1427  if (p == nullptr)
1428  {
1429  if (memInc) return malloc(memInc * sizeofElem);
1430  return malloc(sizeofElem);
1431  }
1432  if ((memInc == 0) || ((newsize % memInc) == 0))
1433  p = realloc(p, (newsize + memInc) * sizeofElem);
1434  // if (!p)
1435  // {
1436  // printf("XMLParser Error: Not enough memory! Aborting...\n");
1437  // exit(220);
1438  // }
1439  return p;
1440 }
1441 
1442 // private:
1444  XMLNodeData* d, int index, XMLElementType xxtype)
1445 {
1446  if (index < 0) return -1;
1447  int i = 0, j = (int)((index << 2) + xxtype), *o = d->pOrder;
1448  while (o[i] != j) i++;
1449  return i;
1450 }
1451 
1452 // private:
1453 // update "order" information when deleting a content of a XMLNode
1455 {
1456  int n = d->nChild + d->nText + d->nClear, *o = d->pOrder,
1457  i = findPosition(d, index, t);
1458  memmove(o + i, o + i + 1, (n - i) * sizeof(int));
1459  for (; i < n; i++)
1460  if ((o[i] & 3) == (int)t) o[i] -= 4;
1461  // We should normally do:
1462  // d->pOrder=(int)realloc(d->pOrder,n*sizeof(int));
1463  // but we skip reallocation because it's too time consuming.
1464  // Anyway, at the end, it will be free'd completely at once.
1465  return i;
1466 }
1467 
1469  int memoryIncrease, int* _pos, int nc, void* p, int size,
1470  XMLElementType xtype)
1471 {
1472  // in: *_pos is the position inside d->pOrder ("-1" means "EndOf")
1473  // out: *_pos is the index inside p
1474  p = myRealloc(p, (nc + 1), memoryIncrease, size);
1475  int n = d->nChild + d->nText + d->nClear;
1476  d->pOrder =
1477  (int*)myRealloc(d->pOrder, n + 1, memoryIncrease * 3, sizeof(int));
1478  int pos = *_pos, *o = d->pOrder;
1479 
1480  if ((pos < 0) || (pos >= n))
1481  {
1482  *_pos = nc;
1483  o[n] = (int)((nc << 2) + xtype);
1484  return p;
1485  }
1486 
1487  int i = pos;
1488  memmove(o + i + 1, o + i, (n - i) * sizeof(int));
1489 
1490  while ((pos < n) && ((o[pos] & 3) != (int)xtype)) pos++;
1491  if (pos == n)
1492  {
1493  *_pos = nc;
1494  o[n] = (int)((nc << 2) + xtype);
1495  return p;
1496  }
1497 
1498  o[i] = o[pos];
1499  for (i = pos + 1; i <= n; i++)
1500  if ((o[i] & 3) == (int)xtype) o[i] += 4;
1501 
1502  *_pos = pos = o[pos] >> 2;
1503  memmove(
1504  ((char*)p) + (pos + 1) * size, ((char*)p) + pos * size,
1505  (nc - pos) * size);
1506 
1507  return p;
1508 }
1509 
1510 // Add a child node to the given element.
1512  int memoryIncrease, XMLSTR lpszName, char isDeclaration, int pos)
1513 {
1514  if (!lpszName) return emptyXMLNode;
1515  d->pChild = (XMLNode*)addToOrder(
1516  memoryIncrease, &pos, d->nChild, d->pChild, sizeof(XMLNode),
1517  eNodeChild);
1518  d->pChild[pos].d = nullptr;
1519  d->pChild[pos] = XMLNode(d, lpszName, isDeclaration);
1520  d->nChild++;
1521  return d->pChild[pos];
1522 }
1523 
1524 // Add an attribute to an element.
1526  int memoryIncrease, XMLSTR lpszName, XMLSTR lpszValuev)
1527 {
1528  if (!lpszName) return &emptyXMLAttribute;
1529  if (!d)
1530  {
1531  myFree(lpszName);
1532  myFree(lpszValuev);
1533  return &emptyXMLAttribute;
1534  }
1535  int nc = d->nAttribute;
1536  d->pAttribute = (XMLAttribute*)myRealloc(
1537  d->pAttribute, (nc + 1), memoryIncrease, sizeof(XMLAttribute));
1538  XMLAttribute* pAttr = d->pAttribute + nc;
1539  pAttr->lpszName = lpszName;
1540  pAttr->lpszValue = lpszValuev;
1541  d->nAttribute++;
1542  return pAttr;
1543 }
1544 
1545 // Add text to the element.
1546 XMLCSTR XMLNode::addText_priv(int memoryIncrease, XMLSTR lpszValue, int pos)
1547 {
1548  if (!lpszValue) return nullptr;
1549  if (!d)
1550  {
1551  myFree(lpszValue);
1552  return nullptr;
1553  }
1554  d->pText = (XMLCSTR*)addToOrder(
1555  memoryIncrease, &pos, d->nText, d->pText, sizeof(XMLSTR), eNodeText);
1556  d->pText[pos] = lpszValue;
1557  d->nText++;
1558  return lpszValue;
1559 }
1560 
1561 // Add clear (unformatted) text to the element.
1563  int memoryIncrease, XMLSTR lpszValue, XMLCSTR lpszOpen, XMLCSTR lpszClose,
1564  int pos)
1565 {
1566  if (!lpszValue) return &emptyXMLClear;
1567  if (!d)
1568  {
1569  myFree(lpszValue);
1570  return &emptyXMLClear;
1571  }
1572  d->pClear = (XMLClear*)addToOrder(
1573  memoryIncrease, &pos, d->nClear, d->pClear, sizeof(XMLClear),
1574  eNodeClear);
1575  XMLClear* pNewClear = d->pClear + pos;
1576  pNewClear->lpszValue = lpszValue;
1577  if (!lpszOpen) lpszOpen = XMLClearTags->lpszOpen;
1578  if (!lpszClose) lpszClose = XMLClearTags->lpszClose;
1579  pNewClear->lpszOpenTag = lpszOpen;
1580  pNewClear->lpszCloseTag = lpszClose;
1581  d->nClear++;
1582  return pNewClear;
1583 }
1584 
1585 // private:
1586 // Parse a clear (unformatted) type node.
1587 char XMLNode::parseClearTag(void* px, void* _pClear)
1588 {
1589  XML* pXML = (XML*)px;
1590  ALLXMLClearTag pClear = *((ALLXMLClearTag*)_pClear);
1591  int cbTemp = 0;
1592  XMLCSTR lpszTemp = nullptr;
1593  XMLCSTR lpXML = &pXML->lpXML[pXML->nIndex];
1594  static XMLCSTR docTypeEnd = _CXML("]>");
1595 
1596  // Find the closing tag
1597  // Seems the <!DOCTYPE need a better treatment so lets handle it
1598  if (pClear.lpszOpen == XMLClearTags[1].lpszOpen)
1599  {
1600  XMLCSTR pCh = lpXML;
1601  while (*pCh)
1602  {
1603  if (*pCh == _CXML('<'))
1604  {
1605  pClear.lpszClose = docTypeEnd;
1606  lpszTemp = xstrstr(lpXML, docTypeEnd);
1607  break;
1608  }
1609  else if (*pCh == _CXML('>'))
1610  {
1611  lpszTemp = pCh;
1612  break;
1613  }
1614 #ifdef _XMLWIDECHAR
1615  pCh++;
1616 #else
1617  pCh += XML_ByteTable[(unsigned char)(*pCh)];
1618 #endif
1619  }
1620  }
1621  else
1622  lpszTemp = xstrstr(lpXML, pClear.lpszClose);
1623 
1624  if (lpszTemp)
1625  {
1626  // Cache the size and increment the index
1627  cbTemp = (int)(lpszTemp - lpXML);
1628 
1629  pXML->nIndex += cbTemp + (int)xstrlen(pClear.lpszClose);
1630 
1631  // Add the clear node to the current element
1632  addClear_priv(
1633  MEMORYINCREASE, stringDup(lpXML, cbTemp), pClear.lpszOpen,
1634  pClear.lpszClose, -1);
1635  return 0;
1636  }
1637 
1638  // If we failed to find the end tag
1640  return 1;
1641 }
1642 
1644 {
1645  if (d->pOrder)
1646  d->pOrder = (int*)realloc(
1647  d->pOrder, (d->nChild + d->nText + d->nClear) * sizeof(int));
1648  if (d->pChild)
1649  d->pChild = (XMLNode*)realloc(d->pChild, d->nChild * sizeof(XMLNode));
1650  if (d->pAttribute)
1651  d->pAttribute = (XMLAttribute*)realloc(
1652  d->pAttribute, d->nAttribute * sizeof(XMLAttribute));
1653  if (d->pText)
1654  d->pText = (XMLCSTR*)realloc(d->pText, d->nText * sizeof(XMLSTR));
1655  if (d->pClear)
1656  d->pClear = (XMLClear*)realloc(d->pClear, d->nClear * sizeof(XMLClear));
1657 }
1658 
1659 char XMLNode::maybeAddTxT(void* pa, XMLCSTR tokenPStr)
1660 {
1661  XML* pXML = (XML*)pa;
1662  XMLCSTR lpszText = pXML->lpszText;
1663  if (!lpszText) return 0;
1664  if (dropWhiteSpace)
1665  while (XML_isSPACECHAR(*lpszText) && (lpszText != tokenPStr))
1666  lpszText++;
1667  int cbText = (int)(tokenPStr - lpszText);
1668  if (!cbText)
1669  {
1670  pXML->lpszText = nullptr;
1671  return 0;
1672  }
1673  if (dropWhiteSpace)
1674  {
1675  cbText--;
1676  while ((cbText) && XML_isSPACECHAR(lpszText[cbText])) cbText--;
1677  cbText++;
1678  }
1679  if (!cbText)
1680  {
1681  pXML->lpszText = nullptr;
1682  return 0;
1683  }
1684  XMLSTR lpt = fromXMLString(lpszText, cbText, pXML);
1685  if (!lpt) return 1;
1686  pXML->lpszText = nullptr;
1687  if (removeCommentsInMiddleOfText && d->nText && d->nClear)
1688  {
1689  // if the previous insertion was a comment (<!-- -->) AND
1690  // if the previous previous insertion was a text then, delete the
1691  // comment and append the text
1692  int n = d->nChild + d->nText + d->nClear - 1, *o = d->pOrder;
1693  if (((o[n] & 3) == eNodeClear) && ((o[n - 1] & 3) == eNodeText))
1694  {
1695  int i = o[n] >> 2;
1696  if (d->pClear[i].lpszOpenTag == XMLClearTags[2].lpszOpen)
1697  {
1698  deleteClear(i);
1699  i = o[n - 1] >> 2;
1700  n = xstrlen(d->pText[i]);
1701  int n2 = xstrlen(lpt) + 1;
1702  d->pText[i] = (XMLSTR)realloc(
1703  (void*)d->pText[i], (n + n2) * sizeof(XMLCHAR));
1704  if (!d->pText[i]) return 1;
1705  memcpy((void*)(d->pText[i] + n), lpt, n2 * sizeof(XMLCHAR));
1706  free(lpt);
1707  return 0;
1708  }
1709  }
1710  }
1711  addText_priv(MEMORYINCREASE, lpt, -1);
1712  return 0;
1713 }
1714 // private:
1715 // Recursively parse an XML element.
1717 {
1718  XML* pXML = (XML*)pa;
1719  int cbToken;
1720  enum XMLTokenTypeTag xtype;
1721  NextToken token;
1722  XMLCSTR lpszTemp = nullptr;
1723  int cbTemp = 0;
1724  char nDeclaration;
1725  XMLNode pNew;
1726  enum Status status; // inside or outside a tag
1727  enum Attrib attrib = eAttribName;
1728 
1729  assert(pXML);
1730 
1731  // If this is the first call to the function
1732  if (pXML->nFirst)
1733  {
1734  // Assume we are outside of a tag definition
1735  pXML->nFirst = FALSE;
1736  status = eOutsideTag;
1737  }
1738  else
1739  {
1740  // If this is not the first call then we should only be called when
1741  // inside a tag.
1742  status = eInsideTag;
1743  }
1744 
1745  // Iterate through the tokens in the document
1746  for (;;)
1747  {
1748  // Obtain the next token
1749  token = GetNextToken(pXML, &cbToken, &xtype);
1750 
1751  if (xtype != eTokenError)
1752  {
1753  // Check the current status
1754  switch (status)
1755  {
1756  // If we are outside of a tag definition
1757  case eOutsideTag:
1758 
1759  // Check what type of token we obtained
1760  switch (xtype)
1761  {
1762  // If we have found text or quoted text
1763  case eTokenText:
1764  case eTokenCloseTag: /* '>' */
1765  case eTokenShortHandClose: /* '/>' */
1766  case eTokenQuotedText:
1767  case eTokenEquals:
1768  break;
1769 
1770  // If we found a start tag '<' and declarations '<?'
1771  case eTokenTagStart:
1772  case eTokenDeclaration:
1773 
1774  // Cache whether this new element is a declaration
1775  // or not
1776  nDeclaration = (xtype == eTokenDeclaration);
1777 
1778  // If we have node text then add this to the element
1779  if (maybeAddTxT(pXML, token.pStr)) return FALSE;
1780 
1781  // Find the name of the tag
1782  token = GetNextToken(pXML, &cbToken, &xtype);
1783 
1784  // Return an error if we couldn't obtain the next
1785  // token or
1786  // it wasnt text
1787  if (xtype != eTokenText)
1788  {
1790  return FALSE;
1791  }
1792 
1793 // If we found a new element which is the same as this
1794 // element then we need to pass this back to the caller..
1795 
1796 #ifdef APPROXIMATE_PARSING
1797  if (d->lpszName &&
1798  myTagCompare(d->lpszName, token.pStr) == 0)
1799  {
1800  // Indicate to the caller that it needs to
1801  // create a
1802  // new element.
1803  pXML->lpNewElement = token.pStr;
1804  pXML->cbNewElement = cbToken;
1805  return TRUE;
1806  }
1807  else
1808 #endif
1809  {
1810  // If the name of the new element differs from
1811  // the name of
1812  // the current element we need to add the new
1813  // element to
1814  // the current one and recurse
1815  pNew = addChild_priv(
1817  stringDup(token.pStr, cbToken),
1818  nDeclaration, -1);
1819 
1820  while (!pNew.isEmpty())
1821  {
1822  // Callself to process the new node. If we
1823  // return
1824  // FALSE this means we dont have any more
1825  // processing to do...
1826 
1827  if (!pNew.ParseXMLElement(pXML))
1828  return FALSE;
1829  else
1830  {
1831  // If the call to recurse this function
1832  // evented in a end tag specified in XML
1833  // then
1834  // we need to unwind the calls to this
1835  // function until we find the
1836  // appropriate node
1837  // (the element name and end tag name
1838  // must
1839  // match)
1840  if (pXML->cbEndTag)
1841  {
1842  // If we are back at the root node
1843  // then we
1844  // have an unmatched end tag
1845  if (!d->lpszName)
1846  {
1847  pXML->error =
1849  return FALSE;
1850  }
1851 
1852  // If the end tag matches the name
1853  // of this
1854  // element then we only need to
1855  // unwind
1856  // once more...
1857 
1858  if (myTagCompare(
1859  d->lpszName,
1860  pXML->lpEndTag) == 0)
1861  {
1862  pXML->cbEndTag = 0;
1863  }
1864 
1865  return TRUE;
1866  }
1867  else if (pXML->cbNewElement)
1868  {
1869  // If the call indicated a new
1870  // element is to
1871  // be created on THIS element.
1872 
1873  // If the name of this element
1874  // matches the
1875  // name of the element we need to
1876  // create
1877  // then we need to return to the
1878  // caller
1879  // and let it process the element.
1880 
1881  if (myTagCompare(
1882  d->lpszName,
1883  pXML->lpNewElement) == 0)
1884  {
1885  return TRUE;
1886  }
1887 
1888  // Add the new element and recurse
1889  pNew = addChild_priv(
1891  stringDup(
1892  pXML->lpNewElement,
1893  pXML->cbNewElement),
1894  0, -1);
1895  pXML->cbNewElement = 0;
1896  }
1897  else
1898  {
1899  // If we didn't have a new element
1900  // to create
1901  pNew = emptyXMLNode;
1902  }
1903  }
1904  }
1905  }
1906  break;
1907 
1908  // If we found an end tag
1909  case eTokenTagEnd:
1910 
1911  // If we have node text then add this to the element
1912  if (maybeAddTxT(pXML, token.pStr)) return FALSE;
1913 
1914  // Find the name of the end tag
1915  token = GetNextToken(pXML, &cbTemp, &xtype);
1916 
1917  // The end tag should be text
1918  if (xtype != eTokenText)
1919  {
1921  return FALSE;
1922  }
1923  lpszTemp = token.pStr;
1924 
1925  // After the end tag we should find a closing tag
1926  token = GetNextToken(pXML, &cbToken, &xtype);
1927  if (xtype != eTokenCloseTag)
1928  {
1930  return FALSE;
1931  }
1932  pXML->lpszText = pXML->lpXML + pXML->nIndex;
1933 
1934  // We need to return to the previous caller. If the
1935  // name
1936  // of the tag cannot be found we need to keep
1937  // returning to
1938  // caller until we find a match
1939  if (myTagCompare(d->lpszName, lpszTemp) != 0)
1940 #ifdef STRICT_PARSING
1941  {
1943  pXML->nIndexMissigEndTag = pXML->nIndex;
1944  return FALSE;
1945  }
1946 #else
1947  {
1948  pXML->error = eXMLErrorMissingEndTag;
1949  pXML->nIndexMissigEndTag = pXML->nIndex;
1950  pXML->lpEndTag = lpszTemp;
1951  pXML->cbEndTag = cbTemp;
1952  }
1953 #endif
1954 
1955  // Return to the caller
1956  exactMemory(d);
1957  return TRUE;
1958 
1959  // If we found a clear (unformatted) token
1960  case eTokenClear:
1961  // If we have node text then add this to the element
1962  if (maybeAddTxT(pXML, token.pStr)) return FALSE;
1963  if (parseClearTag(pXML, token.pClr)) return FALSE;
1964  pXML->lpszText = pXML->lpXML + pXML->nIndex;
1965  break;
1966 
1967  default:
1968  break;
1969  }
1970  break;
1971 
1972  // If we are inside a tag definition we need to search for
1973  // attributes
1974  case eInsideTag:
1975 
1976  // Check what part of the attribute (name, equals, value) we
1977  // are looking for.
1978  switch (attrib)
1979  {
1980  // If we are looking for a new attribute
1981  case eAttribName:
1982 
1983  // Check what the current token type is
1984  switch (xtype)
1985  {
1986  // If the current type is text...
1987  // Eg. 'attribute'
1988  case eTokenText:
1989  // Cache the token then indicate that we are
1990  // next to
1991  // look for the equals
1992  lpszTemp = token.pStr;
1993  cbTemp = cbToken;
1994  attrib = eAttribEquals;
1995  break;
1996 
1997  // If we found a closing tag...
1998  // Eg. '>'
1999  case eTokenCloseTag:
2000  // We are now outside the tag
2001  status = eOutsideTag;
2002  pXML->lpszText = pXML->lpXML + pXML->nIndex;
2003  break;
2004 
2005  // If we found a short hand '/>' closing tag
2006  // then we can
2007  // return to the caller
2008  case eTokenShortHandClose:
2009  exactMemory(d);
2010  pXML->lpszText = pXML->lpXML + pXML->nIndex;
2011  return TRUE;
2012 
2013  // Errors...
2014  case eTokenQuotedText: /* '"SomeText"' */
2015  case eTokenTagStart: /* '<' */
2016  case eTokenTagEnd: /* '</' */
2017  case eTokenEquals: /* '=' */
2018  case eTokenDeclaration: /* '<?' */
2019  case eTokenClear:
2021  return FALSE;
2022  default:
2023  break;
2024  }
2025  break;
2026 
2027  // If we are looking for an equals
2028  case eAttribEquals:
2029  // Check what the current token type is
2030  switch (xtype)
2031  {
2032  // If the current type is text...
2033  // Eg. 'Attribute AnotherAttribute'
2034  case eTokenText:
2035  // Add the unvalued attribute to the list
2038  stringDup(lpszTemp, cbTemp), nullptr);
2039  // Cache the token then indicate. We are
2040  // next to
2041  // look for the equals attribute
2042  lpszTemp = token.pStr;
2043  cbTemp = cbToken;
2044  break;
2045 
2046  // If we found a closing tag 'Attribute >' or a
2047  // short hand
2048  // closing tag 'Attribute />'
2049  case eTokenShortHandClose:
2050  case eTokenCloseTag:
2051  // If we are a declaration element '<?' then
2052  // we need
2053  // to remove extra closing '?' if it exists
2054  pXML->lpszText = pXML->lpXML + pXML->nIndex;
2055 
2056  if (d->isDeclaration &&
2057  (lpszTemp[cbTemp - 1]) == _CXML('?'))
2058  {
2059  cbTemp--;
2060  if (d->pParent && d->pParent->pParent)
2061  xtype = eTokenShortHandClose;
2062  }
2063 
2064  if (cbTemp)
2065  {
2066  // Add the unvalued attribute to the
2067  // list
2070  stringDup(lpszTemp, cbTemp),
2071  nullptr);
2072  }
2073 
2074  // If this is the end of the tag then return
2075  // to the caller
2076  if (xtype == eTokenShortHandClose)
2077  {
2078  exactMemory(d);
2079  return TRUE;
2080  }
2081 
2082  // We are now outside the tag
2083  status = eOutsideTag;
2084  break;
2085 
2086  // If we found the equals token...
2087  // Eg. 'Attribute ='
2088  case eTokenEquals:
2089  // Indicate that we next need to search for
2090  // the value
2091  // for the attribute
2092  attrib = eAttribValue;
2093  break;
2094 
2095  // Errors...
2096  case eTokenQuotedText: /* 'Attribute
2097  "InvalidAttr"'*/
2098  case eTokenTagStart: /* 'Attribute <' */
2099  case eTokenTagEnd: /* 'Attribute </' */
2100  case eTokenDeclaration: /* 'Attribute <?' */
2101  case eTokenClear:
2103  return FALSE;
2104  default:
2105  break;
2106  }
2107  break;
2108 
2109  // If we are looking for an attribute value
2110  case eAttribValue:
2111  // Check what the current token type is
2112  switch (xtype)
2113  {
2114  // If the current type is text or quoted text...
2115  // Eg. 'Attribute = "Value"' or 'Attribute =
2116  // Value' or
2117  // 'Attribute = 'Value''.
2118  case eTokenText:
2119  case eTokenQuotedText:
2120  // If we are a declaration element '<?' then
2121  // we need
2122  // to remove extra closing '?' if it exists
2123  if (d->isDeclaration &&
2124  (token.pStr[cbToken - 1]) == _CXML('?'))
2125  {
2126  cbToken--;
2127  }
2128 
2129  if (cbTemp)
2130  {
2131  // Add the valued attribute to the list
2132  if (xtype == eTokenQuotedText)
2133  {
2134  token.pStr++;
2135  cbToken -= 2;
2136  }
2137  XMLSTR attrVal = (XMLSTR)token.pStr;
2138  if (attrVal)
2139  {
2140  attrVal = fromXMLString(
2141  attrVal, cbToken, pXML);
2142  if (!attrVal) return FALSE;
2143  }
2146  stringDup(lpszTemp, cbTemp),
2147  attrVal);
2148  }
2149 
2150  // Indicate we are searching for a new
2151  // attribute
2152  attrib = eAttribName;
2153  break;
2154 
2155  // Errors...
2156  case eTokenTagStart: /* 'Attr = <' */
2157  case eTokenTagEnd: /* 'Attr = </' */
2158  case eTokenCloseTag: /* 'Attr = >' */
2159  case eTokenShortHandClose: /* "Attr = />" */
2160  case eTokenEquals: /* 'Attr = =' */
2161  case eTokenDeclaration: /* 'Attr = <?' */
2162  case eTokenClear:
2164  return FALSE;
2165  break;
2166  default:
2167  break;
2168  }
2169  }
2170  }
2171  }
2172  // If we failed to obtain the next token
2173  else
2174  {
2175  if ((!d->isDeclaration) && (d->pParent))
2176  {
2177 #ifdef STRICT_PARSING
2179 #else
2180  pXML->error = eXMLErrorMissingEndTag;
2181 #endif
2182  pXML->nIndexMissigEndTag = pXML->nIndex;
2183  }
2184  maybeAddTxT(pXML, pXML->lpXML + pXML->nIndex);
2185  return FALSE;
2186  }
2187  }
2188 }
2189 
2190 // Count the number of lines and columns in an XML string.
2191 static void CountLinesAndColumns(XMLCSTR lpXML, int nUpto, XMLResults* pResults)
2192 {
2193  XMLCHAR ch;
2194  assert(lpXML);
2195  assert(pResults);
2196 
2197  struct XML xml = {lpXML, lpXML, 0, 0, eXMLErrorNone,
2198  nullptr, 0, nullptr, 0, TRUE};
2199 
2200  pResults->nLine = 1;
2201  pResults->nColumn = 1;
2202  while (xml.nIndex < nUpto)
2203  {
2204  ch = getNextChar(&xml);
2205  if (ch != _CXML('\n'))
2206  pResults->nColumn++;
2207  else
2208  {
2209  pResults->nLine++;
2210  pResults->nColumn = 1;
2211  }
2212  }
2213 }
2214 
2215 // Parse XML and return the root element.
2217 {
2218  if (!lpszXML)
2219  {
2220  if (pResults)
2221  {
2222  pResults->error = eXMLErrorNoElements;
2223  pResults->nLine = 0;
2224  pResults->nColumn = 0;
2225  }
2226  return emptyXMLNode;
2227  }
2228 
2229  XMLNode xnode(nullptr, nullptr, FALSE);
2230  struct XML xml = {lpszXML, lpszXML, 0, 0, eXMLErrorNone,
2231  nullptr, 0, nullptr, 0, TRUE};
2232 
2233  // Create header element
2234  xnode.ParseXMLElement(&xml);
2235  enum XMLError error = xml.error;
2236  if (!xnode.nChildNode()) error = eXMLErrorNoXMLTagFound;
2237  if ((xnode.nChildNode() == 1) && (xnode.nElement() == 1))
2238  xnode = xnode.getChildNode(); // skip the empty node
2239 
2240  // If no error occurred
2241  if ((error == eXMLErrorNone) || (error == eXMLErrorMissingEndTag) ||
2243  {
2244  XMLCSTR name = xnode.getName();
2245  if (tag && (*tag) && ((!name) || (xstricmp(name, tag))))
2246  {
2247  xnode = xnode.getChildNode(tag);
2248  if (xnode.isEmpty())
2249  {
2250  if (pResults)
2251  {
2252  pResults->error = eXMLErrorFirstTagNotFound;
2253  pResults->nLine = 0;
2254  pResults->nColumn = 0;
2255  }
2256  return emptyXMLNode;
2257  }
2258  }
2259  }
2260  else
2261  {
2262  // Cleanup: this will destroy all the nodes
2263  xnode = emptyXMLNode;
2264  }
2265 
2266  // If we have been given somewhere to place results
2267  if (pResults)
2268  {
2269  pResults->error = error;
2270 
2271  // If we have an error
2272  if (error != eXMLErrorNone)
2273  {
2275  xml.nIndex = xml.nIndexMissigEndTag;
2276  // Find which line and column it starts on.
2277  CountLinesAndColumns(xml.lpXML, xml.nIndex, pResults);
2278  }
2279  }
2280  return xnode;
2281 }
2282 
2284 {
2285  if (pResults)
2286  {
2287  pResults->nLine = 0;
2288  pResults->nColumn = 0;
2289  }
2290  FILE* f = xfopen(filename, _CXML("rb"));
2291  if (f == nullptr)
2292  {
2293  if (pResults) pResults->error = eXMLErrorFileNotFound;
2294  return emptyXMLNode;
2295  }
2296  fseek(f, 0, SEEK_END);
2297  int l = ftell(f), headerSz = 0;
2298  if (!l)
2299  {
2300  if (pResults) pResults->error = eXMLErrorEmpty;
2301  fclose(f);
2302  return emptyXMLNode;
2303  }
2304  fseek(f, 0, SEEK_SET);
2305  unsigned char* buf = (unsigned char*)malloc(l + 4);
2306  int really_read = (int)fread(buf, 1, l, f); // JLBC
2307  if (really_read != l) buf[0] = '\0';
2308  fclose(f);
2309  buf[l] = 0;
2310  buf[l + 1] = 0;
2311  buf[l + 2] = 0;
2312  buf[l + 3] = 0;
2313 #ifdef _XMLWIDECHAR
2314  if (guessWideCharChars)
2315  {
2316  if (!myIsTextWideChar(buf, l))
2317  {
2319  if ((buf[0] == 0xef) && (buf[1] == 0xbb) && (buf[2] == 0xbf))
2320  {
2321  headerSz = 3;
2323  }
2324  XMLSTR b2 =
2325  myMultiByteToWideChar((const char*)(buf + headerSz), ce);
2326  free(buf);
2327  buf = (unsigned char*)b2;
2328  headerSz = 0;
2329  }
2330  else
2331  {
2332  if ((buf[0] == 0xef) && (buf[1] == 0xff)) headerSz = 2;
2333  if ((buf[0] == 0xff) && (buf[1] == 0xfe)) headerSz = 2;
2334  }
2335  }
2336 #else
2337  if (guessWideCharChars)
2338  {
2339  if (myIsTextWideChar(buf, l))
2340  {
2341  if ((buf[0] == 0xef) && (buf[1] == 0xff)) headerSz = 2;
2342  if ((buf[0] == 0xff) && (buf[1] == 0xfe)) headerSz = 2;
2343  char* b2 = myWideCharToMultiByte((const wchar_t*)(buf + headerSz));
2344  free(buf);
2345  buf = (unsigned char*)b2;
2346  headerSz = 0;
2347  }
2348  else
2349  {
2350  if ((buf[0] == 0xef) && (buf[1] == 0xbb) && (buf[2] == 0xbf))
2351  headerSz = 3;
2352  }
2353  }
2354 #endif
2355 
2356  if (!buf)
2357  {
2358  if (pResults) pResults->error = eXMLErrorCharConversionError;
2359  return emptyXMLNode;
2360  }
2361  XMLNode x = parseString((XMLSTR)(buf + headerSz), tag, pResults);
2362  free(buf);
2363  return x;
2364 }
2365 
2366 static inline void charmemset(XMLSTR dest, XMLCHAR c, int l)
2367 {
2368  while (l--) *(dest++) = c;
2369 }
2370 // private:
2371 // Creates an user friendly XML string from a given element with
2372 // appropriate white space and carriage returns.
2373 //
2374 // This recurses through all subnodes then adds contents of the nodes to the
2375 // string.
2377  XMLNodeData* pEntry, XMLSTR lpszMarker, int nFormat)
2378 {
2379  int nResult = 0;
2380  int cb = nFormat < 0 ? 0 : nFormat;
2381  int cbElement;
2382  int nChildFormat = -1;
2383  int nElementI = pEntry->nChild + pEntry->nText + pEntry->nClear;
2384  int i, j;
2385  if ((nFormat >= 0) && (nElementI == 1) && (pEntry->nText == 1) &&
2386  (!pEntry->isDeclaration))
2387  nFormat = -2;
2388 
2389  assert(pEntry);
2390 
2391 #define LENSTR(lpsz) (lpsz ? xstrlen(lpsz) : 0)
2392 
2393  // If the element has no name then assume this is the head node.
2394  cbElement = (int)LENSTR(pEntry->lpszName);
2395 
2396  if (cbElement)
2397  {
2398  // "<elementname "
2399  if (lpszMarker)
2400  {
2401  if (cb) charmemset(lpszMarker, INDENTCHAR, cb);
2402  nResult = cb;
2403  lpszMarker[nResult++] = _CXML('<');
2404  if (pEntry->isDeclaration) lpszMarker[nResult++] = _CXML('?');
2405  xstrcpy(&lpszMarker[nResult], pEntry->lpszName);
2406  nResult += cbElement;
2407  lpszMarker[nResult++] = _CXML(' ');
2408  }
2409  else
2410  {
2411  nResult += cbElement + 2 + cb;
2412  if (pEntry->isDeclaration) nResult++;
2413  }
2414 
2415  // Enumerate attributes and add them to the string
2416  XMLAttribute* pAttr = pEntry->pAttribute;
2417  for (i = 0; i < pEntry->nAttribute; i++)
2418  {
2419  // "Attrib
2420  cb = (int)LENSTR(pAttr->lpszName);
2421  if (cb)
2422  {
2423  if (lpszMarker) xstrcpy(&lpszMarker[nResult], pAttr->lpszName);
2424  nResult += cb;
2425  // "Attrib=Value "
2426  if (pAttr->lpszValue)
2427  {
2428  cb =
2430  if (lpszMarker)
2431  {
2432  lpszMarker[nResult] = _CXML('=');
2433  lpszMarker[nResult + 1] = _CXML('"');
2434  if (cb)
2436  &lpszMarker[nResult + 2], pAttr->lpszValue);
2437  lpszMarker[nResult + cb + 2] = _CXML('"');
2438  }
2439  nResult += cb + 3;
2440  }
2441  if (lpszMarker) lpszMarker[nResult] = _CXML(' ');
2442  nResult++;
2443  }
2444  pAttr++;
2445  }
2446 
2447  if (pEntry->isDeclaration)
2448  {
2449  if (lpszMarker)
2450  {
2451  lpszMarker[nResult - 1] = _CXML('?');
2452  lpszMarker[nResult] = _CXML('>');
2453  }
2454  nResult++;
2455  if (nFormat != -1)
2456  {
2457  if (lpszMarker) lpszMarker[nResult] = _CXML('\n');
2458  nResult++;
2459  }
2460  }
2461  else
2462  // If there are child nodes we need to terminate the start tag
2463  if (nElementI)
2464  {
2465  if (lpszMarker) lpszMarker[nResult - 1] = _CXML('>');
2466  if (nFormat >= 0)
2467  {
2468  if (lpszMarker) lpszMarker[nResult] = _CXML('\n');
2469  nResult++;
2470  }
2471  }
2472  else
2473  nResult--;
2474  }
2475 
2476  // Calculate the child format for when we recurse. This is used to
2477  // determine the number of spaces used for prefixes.
2478  if (nFormat != -1)
2479  {
2480  if (cbElement && (!pEntry->isDeclaration))
2481  nChildFormat = nFormat + 1;
2482  else
2483  nChildFormat = nFormat;
2484  }
2485 
2486  // Enumerate through remaining children
2487  for (i = 0; i < nElementI; i++)
2488  {
2489  j = pEntry->pOrder[i];
2490  switch ((XMLElementType)(j & 3))
2491  {
2492  // Text nodes
2493  case eNodeText:
2494  {
2495  // "Text"
2496  XMLCSTR pChild = pEntry->pText[j >> 2];
2497  cb = (int)ToXMLStringTool::lengthXMLString(pChild);
2498  if (cb)
2499  {
2500  if (nFormat >= 0)
2501  {
2502  if (lpszMarker)
2503  {
2504  charmemset(
2505  &lpszMarker[nResult], INDENTCHAR, nFormat + 1);
2507  &lpszMarker[nResult + nFormat + 1], pChild);
2508  lpszMarker[nResult + nFormat + 1 + cb] =
2509  _CXML('\n');
2510  }
2511  nResult += cb + nFormat + 2;
2512  }
2513  else
2514  {
2515  if (lpszMarker)
2517  &lpszMarker[nResult], pChild);
2518  nResult += cb;
2519  }
2520  }
2521  break;
2522  }
2523 
2524  // Clear type nodes
2525  case eNodeClear:
2526  {
2527  XMLClear* pChild = pEntry->pClear + (j >> 2);
2528  // "OpenTag"
2529  cb = (int)LENSTR(pChild->lpszOpenTag);
2530  if (cb)
2531  {
2532  if (nFormat != -1)
2533  {
2534  if (lpszMarker)
2535  {
2536  charmemset(
2537  &lpszMarker[nResult], INDENTCHAR, nFormat + 1);
2538  xstrcpy(
2539  &lpszMarker[nResult + nFormat + 1],
2540  pChild->lpszOpenTag);
2541  }
2542  nResult += cb + nFormat + 1;
2543  }
2544  else
2545  {
2546  if (lpszMarker)
2547  xstrcpy(&lpszMarker[nResult], pChild->lpszOpenTag);
2548  nResult += cb;
2549  }
2550  }
2551 
2552  // "OpenTag Value"
2553  cb = (int)LENSTR(pChild->lpszValue);
2554  if (cb)
2555  {
2556  if (lpszMarker)
2557  xstrcpy(&lpszMarker[nResult], pChild->lpszValue);
2558  nResult += cb;
2559  }
2560 
2561  // "OpenTag Value CloseTag"
2562  cb = (int)LENSTR(pChild->lpszCloseTag);
2563  if (cb)
2564  {
2565  if (lpszMarker)
2566  xstrcpy(&lpszMarker[nResult], pChild->lpszCloseTag);
2567  nResult += cb;
2568  }
2569 
2570  if (nFormat != -1)
2571  {
2572  if (lpszMarker) lpszMarker[nResult] = _CXML('\n');
2573  nResult++;
2574  }
2575  break;
2576  }
2577 
2578  // Element nodes
2579  case eNodeChild:
2580  {
2581  // Recursively add child nodes
2582  nResult += CreateXMLStringR(
2583  pEntry->pChild[j >> 2].d,
2584  lpszMarker ? lpszMarker + nResult : 0, nChildFormat);
2585  break;
2586  }
2587  default:
2588  break;
2589  }
2590  }
2591 
2592  if ((cbElement) && (!pEntry->isDeclaration))
2593  {
2594  // If we have child entries we need to use long XML notation for
2595  // closing the element - "<elementname>blah blah blah</elementname>"
2596  if (nElementI)
2597  {
2598  // "</elementname>\0"
2599  if (lpszMarker)
2600  {
2601  if (nFormat >= 0)
2602  {
2603  charmemset(&lpszMarker[nResult], INDENTCHAR, nFormat);
2604  nResult += nFormat;
2605  }
2606 
2607  lpszMarker[nResult] = _CXML('<');
2608  lpszMarker[nResult + 1] = _CXML('/');
2609  nResult += 2;
2610  xstrcpy(&lpszMarker[nResult], pEntry->lpszName);
2611  nResult += cbElement;
2612 
2613  lpszMarker[nResult] = _CXML('>');
2614  if (nFormat == -1)
2615  nResult++;
2616  else
2617  {
2618  lpszMarker[nResult + 1] = _CXML('\n');
2619  nResult += 2;
2620  }
2621  }
2622  else
2623  {
2624  if (nFormat >= 0)
2625  nResult += cbElement + 4 + nFormat;
2626  else if (nFormat == -1)
2627  nResult += cbElement + 3;
2628  else
2629  nResult += cbElement + 4;
2630  }
2631  }
2632  else
2633  {
2634  // If there are no children we can use shorthand XML notation -
2635  // "<elementname/>"
2636  // "/>\0"
2637  if (lpszMarker)
2638  {
2639  lpszMarker[nResult] = _CXML('/');
2640  lpszMarker[nResult + 1] = _CXML('>');
2641  if (nFormat != -1) lpszMarker[nResult + 2] = _CXML('\n');
2642  }
2643  nResult += nFormat == -1 ? 2 : 3;
2644  }
2645  }
2646 
2647  return nResult;
2648 }
2649 
2650 #undef LENSTR
2651 
2652 // Create an XML string
2653 // @param int nFormat - 0 if no formatting is required
2654 // otherwise nonzero for formatted text
2655 // with carriage returns and indentation.
2656 // @param int *pnSize - [out] pointer to the size of the
2657 // returned string not including the
2658 // nullptr terminator.
2659 // @return XMLSTR - Allocated XML string, you must free
2660 // this with free().
2661 XMLSTR XMLNode::createXMLString(int nFormat, int* pnSize) const
2662 {
2663  if (!d)
2664  {
2665  if (pnSize) *pnSize = 0;
2666  return nullptr;
2667  }
2668 
2669  XMLSTR lpszResult = nullptr;
2670  int cbStr;
2671 
2672  // Recursively Calculate the size of the XML string
2673  if (!dropWhiteSpace) nFormat = 0;
2674  nFormat = nFormat ? 0 : -1;
2675  cbStr = CreateXMLStringR(d, 0, nFormat);
2676  // Alllocate memory for the XML string + the nullptr terminator and
2677  // create the recursively XML string.
2678  lpszResult = (XMLSTR)malloc((cbStr + 1) * sizeof(XMLCHAR));
2679  CreateXMLStringR(d, lpszResult, nFormat);
2680  lpszResult[cbStr] = _CXML('\0');
2681  if (pnSize) *pnSize = cbStr;
2682  return lpszResult;
2683 }
2684 
2686 {
2687  XMLNode* pa = d->pParent->pChild;
2688  int i = 0;
2689  while (((void*)(pa[i].d)) != ((void*)d)) i++;
2690  d->pParent->nChild--;
2691  if (d->pParent->nChild)
2692  memmove(pa + i, pa + i + 1, (d->pParent->nChild - i) * sizeof(XMLNode));
2693  else
2694  {
2695  free(pa);
2696  d->pParent->pChild = nullptr;
2697  }
2698  return removeOrderElement(d->pParent, eNodeChild, i);
2699 }
2700 
2702 {
2703  if (!d) return;
2704  d->ref_count--;
2705  emptyTheNode(0);
2706 }
2708 {
2709  if (!d) return;
2710  if (d->pParent)
2711  {
2713  d->pParent = nullptr;
2714  d->ref_count--;
2715  }
2716  emptyTheNode(1);
2717 }
2718 void XMLNode::emptyTheNode(char force)
2719 {
2720  XMLNodeData* dd = d; // warning: must stay this way!
2721  if ((dd->ref_count == 0) || force)
2722  {
2723  if (d->pParent) detachFromParent(d);
2724  int i;
2725  XMLNode* pc;
2726  for (i = 0; i < dd->nChild; i++)
2727  {
2728  pc = dd->pChild + i;
2729  pc->d->pParent = nullptr;
2730  pc->d->ref_count--;
2731  pc->emptyTheNode(force);
2732  }
2733  myFree(dd->pChild);
2734  for (i = 0; i < dd->nText; i++) free((void*)dd->pText[i]);
2735  myFree(dd->pText);
2736  for (i = 0; i < dd->nClear; i++) free((void*)dd->pClear[i].lpszValue);
2737  myFree(dd->pClear);
2738  for (i = 0; i < dd->nAttribute; i++)
2739  {
2740  free((void*)dd->pAttribute[i].lpszName);
2741  if (dd->pAttribute[i].lpszValue)
2742  free((void*)dd->pAttribute[i].lpszValue);
2743  }
2744  myFree(dd->pAttribute);
2745  myFree(dd->pOrder);
2746  myFree((void*)dd->lpszName);
2747  dd->nChild = 0;
2748  dd->nText = 0;
2749  dd->nClear = 0;
2750  dd->nAttribute = 0;
2751  dd->pChild = nullptr;
2752  dd->pText = nullptr;
2753  dd->pClear = nullptr;
2754  dd->pAttribute = nullptr;
2755  dd->pOrder = nullptr;
2756  dd->lpszName = nullptr;
2757  dd->pParent = nullptr;
2758  }
2759  if (dd->ref_count == 0)
2760  {
2761  free(dd);
2762  d = nullptr;
2763  }
2764 }
2765 
2767 {
2768  // shallow copy
2769  if (this != &A)
2770  {
2771  if (d)
2772  {
2773  d->ref_count--;
2774  emptyTheNode(0);
2775  }
2776  d = A.d;
2777  if (d) (d->ref_count)++;
2778  }
2779  return *this;
2780 }
2781 
2783 {
2784  // shallow copy
2785  d = A.d;
2786  if (d) (d->ref_count)++;
2787 }
2788 
2790 {
2791  if (!d) return XMLNode::emptyXMLNode;
2792  XMLNode x(nullptr, stringDup(d->lpszName), d->isDeclaration);
2793  XMLNodeData* p = x.d;
2794  int n = d->nAttribute;
2795  if (n)
2796  {
2797  p->nAttribute = n;
2798  p->pAttribute = (XMLAttribute*)malloc(n * sizeof(XMLAttribute));
2799  while (n--)
2800  {
2801  p->pAttribute[n].lpszName = stringDup(d->pAttribute[n].lpszName);
2802  p->pAttribute[n].lpszValue = stringDup(d->pAttribute[n].lpszValue);
2803  }
2804  }
2805  if (d->pOrder)
2806  {
2807  n = (d->nChild + d->nText + d->nClear) * sizeof(int);
2808  p->pOrder = (int*)malloc(n);
2809  memcpy(p->pOrder, d->pOrder, n);
2810  }
2811  n = d->nText;
2812  if (n)
2813  {
2814  p->nText = n;
2815  p->pText = (XMLCSTR*)malloc(n * sizeof(XMLCSTR));
2816  while (n--) p->pText[n] = stringDup(d->pText[n]);
2817  }
2818  n = d->nClear;
2819  if (n)
2820  {
2821  p->nClear = n;
2822  p->pClear = (XMLClear*)malloc(n * sizeof(XMLClear));
2823  while (n--)
2824  {
2825  p->pClear[n].lpszCloseTag = d->pClear[n].lpszCloseTag;
2826  p->pClear[n].lpszOpenTag = d->pClear[n].lpszOpenTag;
2827  p->pClear[n].lpszValue = stringDup(d->pClear[n].lpszValue);
2828  }
2829  }
2830  n = d->nChild;
2831  if (n)
2832  {
2833  p->nChild = n;
2834  p->pChild = (XMLNode*)malloc(n * sizeof(XMLNode));
2835  while (n--)
2836  {
2837  p->pChild[n].d = nullptr;
2838  p->pChild[n] = d->pChild[n].deepCopy();
2839  p->pChild[n].d->pParent = p;
2840  }
2841  }
2842  return x;
2843 }
2844 
2845 XMLNode XMLNode::addChild(XMLNode childNode, int pos)
2846 {
2847  XMLNodeData* dc = childNode.d;
2848  if ((!dc) || (!d)) return childNode;
2849  if (!dc->lpszName)
2850  {
2851  // this is a root node: todo: correct fix
2852  int j = pos;
2853  while (dc->nChild)
2854  {
2855  addChild(dc->pChild[0], j);
2856  if (pos >= 0) j++;
2857  }
2858  return childNode;
2859  }
2860  if (dc->pParent)
2861  {
2862  if ((detachFromParent(dc) <= pos) && (dc->pParent == d)) pos--;
2863  }
2864  else
2865  dc->ref_count++;
2866  dc->pParent = d;
2867  // int nc=d->nChild;
2868  // d->pChild=(XMLNode*)myRealloc(d->pChild,(nc+1),memoryIncrease,sizeof(XMLNode));
2869  d->pChild = (XMLNode*)addToOrder(
2870  0, &pos, d->nChild, d->pChild, sizeof(XMLNode), eNodeChild);
2871  d->pChild[pos].d = dc;
2872  d->nChild++;
2873  return childNode;
2874 }
2875 
2877 {
2878  if ((!d) || (i < 0) || (i >= d->nAttribute)) return;
2879  d->nAttribute--;
2880  XMLAttribute* p = d->pAttribute + i;
2881  free((void*)p->lpszName);
2882  if (p->lpszValue) free((void*)p->lpszValue);
2883  if (d->nAttribute)
2884  memmove(p, p + 1, (d->nAttribute - i) * sizeof(XMLAttribute));
2885  else
2886  {
2887  free(p);
2888  d->pAttribute = nullptr;
2889  }
2890 }
2891 
2893 {
2894  if (a) deleteAttribute(a->lpszName);
2895 }
2897 {
2898  int j = 0;
2899  getAttribute(lpszName, &j);
2900  if (j) deleteAttribute(j - 1);
2901 }
2902 
2904  XMLSTR lpszNewValue, XMLSTR lpszNewName, int i)
2905 {
2906  if (!d)
2907  {
2908  if (lpszNewValue) free(lpszNewValue);
2909  if (lpszNewName) free(lpszNewName);
2910  return nullptr;
2911  }
2912  if (i >= d->nAttribute)
2913  {
2914  if (lpszNewName) return addAttribute_WOSD(lpszNewName, lpszNewValue);
2915  return nullptr;
2916  }
2917  XMLAttribute* p = d->pAttribute + i;
2918  if (p->lpszValue && p->lpszValue != lpszNewValue) free((void*)p->lpszValue);
2919  p->lpszValue = lpszNewValue;
2920  if (lpszNewName && p->lpszName != lpszNewName)
2921  {
2922  free((void*)p->lpszName);
2923  p->lpszName = lpszNewName;
2924  };
2925  return p;
2926 }
2927 
2929  XMLAttribute* newAttribute, XMLAttribute* oldAttribute)
2930 {
2931  if (oldAttribute)
2932  return updateAttribute_WOSD(
2933  (XMLSTR)newAttribute->lpszValue, (XMLSTR)newAttribute->lpszName,
2934  oldAttribute->lpszName);
2935  return addAttribute_WOSD(
2936  (XMLSTR)newAttribute->lpszName, (XMLSTR)newAttribute->lpszValue);
2937 }
2938 
2940  XMLSTR lpszNewValue, XMLSTR lpszNewName, XMLCSTR lpszOldName)
2941 {
2942  int j = 0;
2943  getAttribute(lpszOldName, &j);
2944  if (j)
2945  return updateAttribute_WOSD(lpszNewValue, lpszNewName, j - 1);
2946  else
2947  {
2948  if (lpszNewName)
2949  return addAttribute_WOSD(lpszNewName, lpszNewValue);
2950  else
2951  return addAttribute_WOSD(stringDup(lpszOldName), lpszNewValue);
2952  }
2953 }
2954 
2955 int XMLNode::indexText(XMLCSTR lpszValue) const
2956 {
2957  if (!d) return -1;
2958  int i, l = d->nText;
2959  if (!lpszValue)
2960  {
2961  if (l) return 0;
2962  return -1;
2963  }
2964  XMLCSTR* p = d->pText;
2965  for (i = 0; i < l; i++)
2966  if (lpszValue == p[i]) return i;
2967  return -1;
2968 }
2969 
2971 {
2972  if ((!d) || (i < 0) || (i >= d->nText)) return;
2973  d->nText--;
2974  XMLCSTR* p = d->pText + i;
2975  free((void*)*p);
2976  if (d->nText)
2977  memmove(p, p + 1, (d->nText - i) * sizeof(XMLCSTR));
2978  else
2979  {
2980  free(p);
2981  d->pText = nullptr;
2982  }
2984 }
2985 
2987 {
2988  deleteText(indexText(lpszValue));
2989 }
2990 
2992 {
2993  if (!d)
2994  {
2995  if (lpszNewValue) free(lpszNewValue);
2996  return nullptr;
2997  }
2998  if (i >= d->nText) return addText_WOSD(lpszNewValue);
2999  XMLCSTR* p = d->pText + i;
3000  if (*p != lpszNewValue)
3001  {
3002  free((void*)*p);
3003  *p = lpszNewValue;
3004  }
3005  return lpszNewValue;
3006 }
3007 
3008 XMLCSTR XMLNode::updateText_WOSD(XMLSTR lpszNewValue, XMLCSTR lpszOldValue)
3009 {
3010  if (!d)
3011  {
3012  if (lpszNewValue) free(lpszNewValue);
3013  return nullptr;
3014  }
3015  int i = indexText(lpszOldValue);
3016  if (i >= 0) return updateText_WOSD(lpszNewValue, i);
3017  return addText_WOSD(lpszNewValue);
3018 }
3019 
3021 {
3022  if ((!d) || (i < 0) || (i >= d->nClear)) return;
3023  d->nClear--;
3024  XMLClear* p = d->pClear + i;
3025  free((void*)p->lpszValue);
3026  if (d->nClear)
3027  memmove(p, p + 1, (d->nClear - i) * sizeof(XMLClear));
3028  else
3029  {
3030  free(p);
3031  d->pClear = nullptr;
3032  }
3034 }
3035 
3036 int XMLNode::indexClear(XMLCSTR lpszValue) const
3037 {
3038  if (!d) return -1;
3039  int i, l = d->nClear;
3040  if (!lpszValue)
3041  {
3042  if (l) return 0;
3043  return -1;
3044  }
3045  XMLClear* p = d->pClear;
3046  for (i = 0; i < l; i++)
3047  if (lpszValue == p[i].lpszValue) return i;
3048  return -1;
3049 }
3050 
3052 {
3053  deleteClear(indexClear(lpszValue));
3054 }
3056 {
3057  if (a) deleteClear(a->lpszValue);
3058 }
3059 
3061 {
3062  if (!d)
3063  {
3064  if (lpszNewContent) free(lpszNewContent);
3065  return nullptr;
3066  }
3067  if (i >= d->nClear) return addClear_WOSD(lpszNewContent);
3068  XMLClear* p = d->pClear + i;
3069  if (lpszNewContent != p->lpszValue)
3070  {
3071  free((void*)p->lpszValue);
3072  p->lpszValue = lpszNewContent;
3073  }
3074  return p;
3075 }
3076 
3077 XMLClear* XMLNode::updateClear_WOSD(XMLSTR lpszNewContent, XMLCSTR lpszOldValue)
3078 {
3079  if (!d)
3080  {
3081  if (lpszNewContent) free(lpszNewContent);
3082  return nullptr;
3083  }
3084  int i = indexClear(lpszOldValue);
3085  if (i >= 0) return updateClear_WOSD(lpszNewContent, i);
3086  return addClear_WOSD(lpszNewContent);
3087 }
3088 
3090 {
3091  if (oldP)
3092  return updateClear_WOSD(
3093  (XMLSTR)newP->lpszValue, (XMLSTR)oldP->lpszValue);
3094  return nullptr;
3095 }
3096 
3098 {
3099  if (!d) return 0;
3100  int i, j = 0, n = d->nChild;
3101  XMLNode* pc = d->pChild;
3102  for (i = 0; i < n; i++)
3103  {
3104  if (xstricmp(pc->d->lpszName, name) == 0) j++;
3105  pc++;
3106  }
3107  return j;
3108 }
3109 
3111 {
3112  if (!d) return emptyXMLNode;
3113  int i = 0, n = d->nChild;
3114  if (j) i = *j;
3115  XMLNode* pc = d->pChild + i;
3116  for (; i < n; i++)
3117  {
3118  if (!xstricmp(pc->d->lpszName, name))
3119  {
3120  if (j) *j = i + 1;
3121  return *pc;
3122  }
3123  pc++;
3124  }
3125  return emptyXMLNode;
3126 }
3127 
3129 {
3130  if (!d) return emptyXMLNode;
3131  if (j >= 0)
3132  {
3133  int i = 0;
3134  while (j-- > 0) getChildNode(name, &i);
3135  return getChildNode(name, &i);
3136  }
3137  int i = d->nChild;
3138  while (i--)
3139  if (!xstricmp(name, d->pChild[i].d->lpszName)) break;
3140  if (i < 0) return emptyXMLNode;
3141  return getChildNode(i);
3142 }
3143 
3145  XMLCSTR _path, char createMissing, XMLCHAR sep)
3146 {
3147  XMLSTR path = stringDup(_path);
3148  XMLNode x = getChildNodeByPath(path, createMissing, sep);
3149  if (path) free(path);
3150  return x;
3151 }
3152 
3154  XMLSTR path, char createIfMissing, XMLCHAR sep)
3155 {
3156  if ((!path) || (!(*path))) return *this;
3157  XMLNode xn, xbase = *this;
3158  XMLCHAR *tend1, sepString[2];
3159  sepString[0] = sep;
3160  sepString[1] = 0;
3161  tend1 = xstrstr(path, sepString);
3162  while (tend1)
3163  {
3164  *tend1 = 0;
3165  xn = xbase.getChildNode(path);
3166  if (xn.isEmpty())
3167  {
3168  if (createIfMissing)
3169  xn = xbase.addChild(path);
3170  else
3171  return XMLNode::emptyXMLNode;
3172  }
3173  xbase = xn;
3174  path = tend1 + 1;
3175  tend1 = xstrstr(path, sepString);
3176  }
3177  xn = xbase.getChildNode(path);
3178  if (xn.isEmpty() && createIfMissing) xn = xbase.addChild(path);
3179  return xn;
3180 }
3181 
3183 {
3184  if (i >= d->nText) i = d->nText - 1;
3185  return findPosition(d, i, eNodeText);
3186 }
3188 {
3189  if (i >= d->nClear) i = d->nClear - 1;
3190  return findPosition(d, i, eNodeClear);
3191 }
3193 {
3194  if (i >= d->nChild) i = d->nChild - 1;
3195  return findPosition(d, i, eNodeChild);
3196 }
3198 {
3199  return positionOfText(indexText(lpszValue));
3200 }
3202 {
3203  return positionOfClear(indexClear(lpszValue));
3204 }
3206 {
3207  if (a) return positionOfClear(a->lpszValue);
3208  return positionOfClear();
3209 }
3211 {
3212  if ((!d) || (!x.d)) return -1;
3213  XMLNodeData* dd = x.d;
3214  XMLNode* pc = d->pChild;
3215  int i = d->nChild;
3216  while (i--)
3217  if (pc[i].d == dd) return findPosition(d, i, eNodeChild);
3218  return -1;
3219 }
3221 {
3222  if (!name) return positionOfChildNode(count);
3223  int j = 0;
3224  do
3225  {
3226  getChildNode(name, &j);
3227  if (j < 0) return -1;
3228  } while (count--);
3229  return findPosition(d, j - 1, eNodeChild);
3230 }
3231 
3233  XMLCSTR name, XMLCSTR attributeName, XMLCSTR attributeValue, int* k) const
3234 {
3235  int i = 0, j;
3236  if (k) i = *k;
3237  XMLNode x;
3238  XMLCSTR t;
3239  do
3240  {
3241  x = getChildNode(name, &i);
3242  if (!x.isEmpty())
3243  {
3244  if (attributeValue)
3245  {
3246  j = 0;
3247  do
3248  {
3249  t = x.getAttribute(attributeName, &j);
3250  if (t && (xstricmp(attributeValue, t) == 0))
3251  {
3252  if (k) *k = i;
3253  return x;
3254  }
3255  } while (t);
3256  }
3257  else
3258  {
3259  if (x.isAttributeSet(attributeName))
3260  {
3261  if (k) *k = i;
3262  return x;
3263  }
3264  }
3265  }
3266  } while (!x.isEmpty());
3267  return emptyXMLNode;
3268 }
3269 
3270 // Find an attribute on an node.
3271 XMLCSTR XMLNode::getAttribute(XMLCSTR lpszAttrib, int* j) const
3272 {
3273  if (!d) return nullptr;
3274  int i = 0, n = d->nAttribute;
3275  if (j) i = *j;
3276  XMLAttribute* pAttr = d->pAttribute + i;
3277  for (; i < n; i++)
3278  {
3279  if (xstricmp(pAttr->lpszName, lpszAttrib) == 0)
3280  {
3281  if (j) *j = i + 1;
3282  return pAttr->lpszValue;
3283  }
3284  pAttr++;
3285  }
3286  return nullptr;
3287 }
3288 
3289 char XMLNode::isAttributeSet(XMLCSTR lpszAttrib) const
3290 {
3291  if (!d) return FALSE;
3292  int i, n = d->nAttribute;
3293  XMLAttribute* pAttr = d->pAttribute;
3294  for (i = 0; i < n; i++)
3295  {
3296  if (xstricmp(pAttr->lpszName, lpszAttrib) == 0)
3297  {
3298  return TRUE;
3299  }
3300  pAttr++;
3301  }
3302  return FALSE;
3303 }
3304 
3306 {
3307  if (!d) return nullptr;
3308  int i = 0;
3309  while (j-- > 0) getAttribute(name, &i);
3310  return getAttribute(name, &i);
3311 }
3312 
3314 {
3316  if (!d)
3317  {
3318  c.etype = eNodeNULL;
3319  return c;
3320  }
3321  if (i < d->nAttribute)
3322  {
3323  c.etype = eNodeAttribute;
3324  c.attrib = d->pAttribute[i];
3325  return c;
3326  }
3327  i -= d->nAttribute;
3328  c.etype = (XMLElementType)(d->pOrder[i] & 3);
3329  i = (d->pOrder[i]) >> 2;
3330  switch (c.etype)
3331  {
3332  case eNodeChild:
3333  c.child = d->pChild[i];
3334  break;
3335  case eNodeText:
3336  c.text = d->pText[i];
3337  break;
3338  case eNodeClear:
3339  c.clear = d->pClear[i];
3340  break;
3341  default:
3342  break;
3343  }
3344  return c;
3345 }
3346 
3348 {
3349  if (!d) return nullptr;
3350  return d->lpszName;
3351 }
3352 int XMLNode::nText() const
3353 {
3354  if (!d) return 0;
3355  return d->nText;
3356 }
3358 {
3359  if (!d) return 0;
3360  return d->nChild;
3361 }
3363 {
3364  if (!d) return 0;
3365  return d->nAttribute;
3366 }
3367 int XMLNode::nClear() const
3368 {
3369  if (!d) return 0;
3370  return d->nClear;
3371 }
3373 {
3374  if (!d) return 0;
3375  return d->nAttribute + d->nChild + d->nText + d->nClear;
3376 }
3378 {
3379  if ((!d) || (i >= d->nClear)) return emptyXMLClear;
3380  return d->pClear[i];
3381 }
3383 {
3384  if ((!d) || (i >= d->nAttribute)) return emptyXMLAttribute;
3385  return d->pAttribute[i];
3386 }
3388 {
3389  if ((!d) || (i >= d->nAttribute)) return nullptr;
3390  return d->pAttribute[i].lpszName;
3391 }
3393 {
3394  if ((!d) || (i >= d->nAttribute)) return nullptr;
3395  return d->pAttribute[i].lpszValue;
3396 }
3398 {
3399  if ((!d) || (i >= d->nText)) return nullptr;
3400  return d->pText[i];
3401 }
3403 {
3404  if ((!d) || (i >= d->nChild)) return emptyXMLNode;
3405  return d->pChild[i];
3406 }
3408 {
3409  if ((!d) || (!d->pParent)) return emptyXMLNode;
3410  return XMLNode(d->pParent);
3411 }
3413 {
3414  if (!d) return 0;
3415  return d->isDeclaration;
3416 }
3417 char XMLNode::isEmpty() const { return (d == nullptr); }
3420  XMLCSTR lpszName, char isDeclaration, XMLElementPosition pos)
3421 {
3422  return addChild_priv(0, stringDup(lpszName), isDeclaration, pos);
3423 }
3425  XMLSTR lpszName, char isDeclaration, XMLElementPosition pos)
3426 {
3427  return addChild_priv(0, lpszName, isDeclaration, pos);
3428 }
3430 {
3431  return addAttribute_priv(0, stringDup(lpszName), stringDup(lpszValue));
3432 }
3434 {
3435  return addAttribute_priv(0, lpszName, lpszValuev);
3436 }
3438 {
3439  return addText_priv(0, stringDup(lpszValue), pos);
3440 }
3442 {
3443  return addText_priv(0, lpszValue, pos);
3444 }
3446  XMLCSTR lpszValue, XMLCSTR lpszOpen, XMLCSTR lpszClose,
3447  XMLElementPosition pos)
3448 {
3449  return addClear_priv(0, stringDup(lpszValue), lpszOpen, lpszClose, pos);
3450 }
3452  XMLSTR lpszValue, XMLCSTR lpszOpen, XMLCSTR lpszClose,
3453  XMLElementPosition pos)
3454 {
3455  return addClear_priv(0, lpszValue, lpszOpen, lpszClose, pos);
3456 }
3458 {
3459  return updateName_WOSD(stringDup(lpszName));
3460 }
3462  XMLAttribute* newAttribute, XMLAttribute* oldAttribute)
3463 {
3464  return updateAttribute_WOSD(
3465  stringDup(newAttribute->lpszValue), stringDup(newAttribute->lpszName),
3466  oldAttribute->lpszName);
3467 }
3469  XMLCSTR lpszNewValue, XMLCSTR lpszNewName, int i)
3470 {
3471  return updateAttribute_WOSD(
3472  stringDup(lpszNewValue), stringDup(lpszNewName), i);
3473 }
3475  XMLCSTR lpszNewValue, XMLCSTR lpszNewName, XMLCSTR lpszOldName)
3476 {
3477  return updateAttribute_WOSD(
3478  stringDup(lpszNewValue), stringDup(lpszNewName), lpszOldName);
3479 }
3481 {
3482  return updateText_WOSD(stringDup(lpszNewValue), i);
3483 }
3484 XMLCSTR XMLNode::updateText(XMLCSTR lpszNewValue, XMLCSTR lpszOldValue)
3485 {
3486  return updateText_WOSD(stringDup(lpszNewValue), lpszOldValue);
3487 }
3488 XMLClear* XMLNode::updateClear(XMLCSTR lpszNewContent, int i)
3489 {
3490  return updateClear_WOSD(stringDup(lpszNewContent), i);
3491 }
3492 XMLClear* XMLNode::updateClear(XMLCSTR lpszNewValue, XMLCSTR lpszOldValue)
3493 {
3494  return updateClear_WOSD(stringDup(lpszNewValue), lpszOldValue);
3495 }
3497 {
3498  return updateClear_WOSD(stringDup(newP->lpszValue), oldP->lpszValue);
3499 }
3500 
3502  XMLCharEncoding _characterEncoding, char _guessWideCharChars,
3503  char _dropWhiteSpace, char _removeCommentsInMiddleOfText)
3504 {
3505  guessWideCharChars = _guessWideCharChars;
3506  dropWhiteSpace = _dropWhiteSpace;
3507  removeCommentsInMiddleOfText = _removeCommentsInMiddleOfText;
3508 #ifdef _XMLWIDECHAR
3509  if (_characterEncoding) characterEncoding = _characterEncoding;
3510 #else
3511  switch (_characterEncoding)
3512  {
3513  case char_encoding_UTF8:
3514  characterEncoding = _characterEncoding;
3516  break;
3517  case char_encoding_legacy:
3518  characterEncoding = _characterEncoding;
3520  break;
3522  characterEncoding = _characterEncoding;
3524  break;
3525  case char_encoding_GB2312:
3526  characterEncoding = _characterEncoding;
3528  break;
3529  case char_encoding_Big5:
3530  case char_encoding_GBK:
3531  characterEncoding = _characterEncoding;
3533  break;
3534  default:
3535  return 1;
3536  }
3537 #endif
3538  return 0;
3539 }
3540 
3542  void* buf, int l, char useXMLEncodingAttribute)
3543 {
3544 #ifdef _XMLWIDECHAR
3545  return (XMLCharEncoding)0;
3546 #else
3547  if (l < 25) return (XMLCharEncoding)0;
3548  if (guessWideCharChars && (myIsTextWideChar(buf, l)))
3549  return (XMLCharEncoding)0;
3550  unsigned char* b = (unsigned char*)buf;
3551  if ((b[0] == 0xef) && (b[1] == 0xbb) && (b[2] == 0xbf))
3552  return char_encoding_UTF8;
3553 
3554  // Match utf-8 model ?
3555  XMLCharEncoding bestGuess = char_encoding_UTF8;
3556  int i = 0;
3557  while (i < l) switch (XML_utf8ByteTable[b[i]])
3558  {
3559  case 4:
3560  i++;
3561  if ((i < l) && (b[i] & 0xC0) != 0x80)
3562  {
3563  bestGuess = char_encoding_legacy;
3564  i = l;
3565  } // 10bbbbbb ?
3566  /*FALLTHROUGH*/
3567  case 3:
3568  i++;
3569  if ((i < l) && (b[i] & 0xC0) != 0x80)
3570  {
3571  bestGuess = char_encoding_legacy;
3572  i = l;
3573  } // 10bbbbbb ?
3574  /*FALLTHROUGH*/
3575  case 2:
3576  i++;
3577  if ((i < l) && (b[i] & 0xC0) != 0x80)
3578  {
3579  bestGuess = char_encoding_legacy;
3580  i = l;
3581  } // 10bbbbbb ?
3582  /*FALLTHROUGH*/
3583  case 1:
3584  i++;
3585  break;
3586  case 0:
3587  i = l;
3588  /*FALLTHROUGH*/
3589  }
3590  if (!useXMLEncodingAttribute) return bestGuess;
3591  // if encoding is specified and different from utf-8 than it's non-utf8
3592  // otherwise it's utf-8
3593  char bb[201];
3594  l = mmin(l, 200);
3595  memcpy(bb, buf, l); // copy buf into bb to be able to do "bb[l]=0"
3596  bb[l] = 0;
3597  b = (unsigned char*)strstr(bb, "encoding");
3598  if (!b) return bestGuess;
3599  b += 8;
3600  while
3601  XML_isSPACECHAR(*b) b++;
3602  if (*b != '=') return bestGuess;
3603  b++;
3604  while
3605  XML_isSPACECHAR(*b) b++;
3606  if ((*b != '\'') && (*b != '"')) return bestGuess;
3607  b++;
3608  while
3609  XML_isSPACECHAR(*b) b++;
3610 
3611  if ((xstrnicmp((char*)b, "utf-8", 5) == 0) ||
3612  (xstrnicmp((char*)b, "utf8", 4) == 0))
3613  {
3614  if (bestGuess == char_encoding_legacy) return char_encoding_error;
3615  return char_encoding_UTF8;
3616  }
3617 
3618  if ((xstrnicmp((char*)b, "shiftjis", 8) == 0) ||
3619  (xstrnicmp((char*)b, "shift-jis", 9) == 0) ||
3620  (xstrnicmp((char*)b, "sjis", 4) == 0))
3621  return char_encoding_ShiftJIS;
3622 
3623  if (xstrnicmp((char*)b, "GB2312", 6) == 0) return char_encoding_GB2312;
3624  if (xstrnicmp((char*)b, "Big5", 4) == 0) return char_encoding_Big5;
3625  if (xstrnicmp((char*)b, "GBK", 3) == 0) return char_encoding_GBK;
3626 
3627  return char_encoding_legacy;
3628 #endif
3629 }
3630 #undef XML_isSPACECHAR
3631 
3632 //////////////////////////////////////////////////////////
3633 // Here starts the base64 conversion functions. //
3634 //////////////////////////////////////////////////////////
3635 
3636 static const char base64Fillchar =
3637  _CXML('='); // used to mark partial words at the end
3638 
3639 // this lookup table defines the base64 encoding
3641  _CXML("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
3642 
3643 // Decode Table gives the index of any valid base64 character in the Base64
3644 // table]
3645 // 96: '=' - 97: space char - 98: illegal char - 99: end of string
3646 const unsigned char base64DecodeTable[] = {
3647  99, 98, 98, 98, 98, 98, 98, 98, 98, 97, 97, 98, 98, 97, 98, 98,
3648  98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, // 00 -29
3649  98, 98, 97, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 62, 98, 98,
3650  98, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 98, 98, // 30 -59
3651  98, 96, 98, 98, 98, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
3652  11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 60 -89
3653  25, 98, 98, 98, 98, 98, 98, 26, 27, 28, 29, 30, 31, 32, 33, 34,
3654  35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, // 90 -119
3655  49, 50, 51, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98,
3656  98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, // 120 -149
3657  98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98,
3658  98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, // 150 -179
3659  98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98,
3660  98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, // 180 -209
3661  98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98,
3662  98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, // 210 -239
3663  98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98 // 240 -255
3664 };
3665 
3668 {
3669  if (buf) free(buf);
3670  buf = nullptr;
3671  buflen = 0;
3672 }
3673 
3674 int XMLParserBase64Tool::encodeLength(int inlen, char formatted)
3675 {
3676  unsigned int i = ((inlen - 1) / 3 * 4 + 4 + 1);
3677  if (formatted) i += inlen / 54;
3678  return i;
3679 }
3680 
3682  unsigned char* inbuf, unsigned int inlen, char formatted)
3683 {
3684  int i = encodeLength(inlen, formatted), k = 17, eLen = inlen / 3, j;
3685  alloc(i * sizeof(XMLCHAR));
3686  XMLSTR curr = (XMLSTR)buf;
3687  for (i = 0; i < eLen; i++)
3688  {
3689  // Copy next three bytes into lower 24 bits of int, paying attention to
3690  // sign.
3691  j = (inbuf[0] << 16) | (inbuf[1] << 8) | inbuf[2];
3692  inbuf += 3;
3693  // Encode the int into four chars
3694  *(curr++) = base64EncodeTable[j >> 18];
3695  *(curr++) = base64EncodeTable[(j >> 12) & 0x3f];
3696  *(curr++) = base64EncodeTable[(j >> 6) & 0x3f];
3697  *(curr++) = base64EncodeTable[(j)&0x3f];
3698  if (formatted)
3699  {
3700  if (!k)
3701  {
3702  *(curr++) = _CXML('\n');
3703  k = 18;
3704  }
3705  k--;
3706  }
3707  }
3708  eLen = inlen - eLen * 3; // 0 - 2.
3709  if (eLen == 1)
3710  {
3711  *(curr++) = base64EncodeTable[inbuf[0] >> 2];
3712  *(curr++) = base64EncodeTable[(inbuf[0] << 4) & 0x3F];
3713  *(curr++) = base64Fillchar;
3714  *(curr++) = base64Fillchar;
3715  }
3716  else if (eLen == 2)
3717  {
3718  j = (inbuf[0] << 8) | inbuf[1];
3719  *(curr++) = base64EncodeTable[j >> 10];
3720  *(curr++) = base64EncodeTable[(j >> 4) & 0x3f];
3721  *(curr++) = base64EncodeTable[(j << 2) & 0x3f];
3722  *(curr++) = base64Fillchar;
3723  }
3724  *(curr++) = 0;
3725  return (XMLSTR)buf;
3726 }
3727 
3729 {
3730  if (xe) *xe = eXMLErrorNone;
3731  int size = 0;
3732  unsigned char c;
3733  // skip any extra characters (e.g. newlines or spaces)
3734  while (*data)
3735  {
3736 #ifdef _XMLWIDECHAR
3737  if (*data > 255)
3738  {
3740  return 0;
3741  }
3742 #endif
3743  c = base64DecodeTable[(unsigned char)(*data)];
3744  if (c < 97)
3745  size++;
3746  else if (c == 98)
3747  {
3749  return 0;
3750  }
3751  data++;
3752  }
3753  if (xe && (size % 4 != 0)) *xe = eXMLErrorBase64DataSizeIsNotMultipleOf4;
3754  if (size == 0) return 0;
3755  do
3756  {
3757  data--;
3758  size--;
3759  } while (*data == base64Fillchar);
3760  size++;
3761  return (unsigned int)((size * 3) / 4);
3762 }
3763 
3765  XMLCSTR data, unsigned char* buf, int len, XMLError* xe)
3766 {
3767  if (xe) *xe = eXMLErrorNone;
3768  int i = 0, p = 0;
3769  unsigned char d, c;
3770  for (;;)
3771  {
3772 #ifdef _XMLWIDECHAR
3773 #define BASE64DECODE_READ_NEXT_CHAR(c) \
3774  do \
3775  { \
3776  if (data[i] > 255) \
3777  { \
3778  c = 98; \
3779  break; \
3780  } \
3781  c = base64DecodeTable[(unsigned char)data[i++]]; \
3782  } while (c == 97); \
3783  if (c == 98) \
3784  { \
3785  if (xe) *xe = eXMLErrorBase64DecodeIllegalCharacter; \
3786  return 0; \
3787  }
3788 #else
3789 #define BASE64DECODE_READ_NEXT_CHAR(c) \
3790  do \
3791  { \
3792  c = base64DecodeTable[(unsigned char)data[i++]]; \
3793  } while (c == 97); \
3794  if (c == 98) \
3795  { \
3796  if (xe) *xe = eXMLErrorBase64DecodeIllegalCharacter; \
3797  return 0; \
3798  }
3799 #endif
3800 
3802  if (c == 99)
3803  {
3804  return 2;
3805  }
3806  if (c == 96)
3807  {
3808  if (p == (int)len) return 2;
3809  if (xe) *xe = eXMLErrorBase64DecodeTruncatedData;
3810  return 1;
3811  }
3812 
3814  if ((d == 99) || (d == 96))
3815  {
3816  if (xe) *xe = eXMLErrorBase64DecodeTruncatedData;
3817  return 1;
3818  }
3819  if (p == (int)len)
3820  {
3822  return 0;
3823  }
3824  buf[p++] = (unsigned char)((c << 2) | ((d >> 4) & 0x3));
3825 
3827  if (c == 99)
3828  {
3829  if (xe) *xe = eXMLErrorBase64DecodeTruncatedData;
3830  return 1;
3831  }
3832  if (p == (int)len)
3833  {
3834  if (c == 96) return 2;
3836  return 0;
3837  }
3838  if (c == 96)
3839  {
3840  if (xe) *xe = eXMLErrorBase64DecodeTruncatedData;
3841  return 1;
3842  }
3843  buf[p++] = (unsigned char)(((d << 4) & 0xf0) | ((c >> 2) & 0xf));
3844 
3846  if (d == 99)
3847  {
3848  if (xe) *xe = eXMLErrorBase64DecodeTruncatedData;
3849  return 1;
3850  }
3851  if (p == (int)len)
3852  {
3853  if (d == 96) return 2;
3855  return 0;
3856  }
3857  if (d == 96)
3858  {
3859  if (xe) *xe = eXMLErrorBase64DecodeTruncatedData;
3860  return 1;
3861  }
3862  buf[p++] = (unsigned char)(((c << 6) & 0xc0) | d);
3863  }
3864 }
3865 #undef BASE64DECODE_READ_NEXT_CHAR
3866 
3868 {
3869  if ((!buf) && (newsize))
3870  {
3871  buf = malloc(newsize);
3872  buflen = newsize;
3873  return;
3874  }
3875  if (newsize > buflen)
3876  {
3877  buf = realloc(buf, newsize);
3878  buflen = newsize;
3879  }
3880 }
3881 
3883  XMLCSTR data, int* outlen, XMLError* xe)
3884 {
3885  if (xe) *xe = eXMLErrorNone;
3886  unsigned int len = decodeSize(data, xe);
3887  if (outlen) *outlen = len;
3888  if (!len) return nullptr;
3889  alloc(len + 1);
3890  if (!decode(data, (unsigned char*)buf, len, xe))
3891  {
3892  return nullptr;
3893  }
3894  return (unsigned char*)buf;
3895 }
static XMLCSTR getVersion()
Return the XMLParser library version number.
Definition: xmlParser.cpp:27
XMLNode getChildNodeWithAttribute(XMLCSTR tagName, XMLCSTR attributeName, XMLCSTR attributeValue=nullptr, int *i=nullptr) const
next child node with specific name (return an empty node if failing)
Definition: xmlParser.cpp:3232
int nAttribute() const
next attribute content with specific name (return a nullptr if failing)
Definition: xmlParser.cpp:3362
char isAttributeSet(XMLCSTR name) const
test if an attribute with a specific name is given
Definition: xmlParser.cpp:3289
static const char XML_gbk_big5_ByteTable[256]
Definition: xmlParser.cpp:721
GLuint GLuint GLsizei count
Definition: glext.h:3528
XMLCSTR updateName_WOSD(XMLSTR lpszName)
change node&#39;s name
Definition: xmlParser.cpp:1369
XMLNode getParentNode() const
return the parent node
Definition: xmlParser.cpp:3407
XMLSTR toXML(XMLCSTR source)
object to release memory used by the internal buffer.
Definition: xmlParser.cpp:958
XMLElementType
Enumeration used to manage type of data.
Definition: xmlParser.h:265
#define _CXML(c)
Definition: xmlParser.h:225
#define MEMORYINCREASE
Definition: xmlParser.cpp:1419
XMLCSTR base64EncodeTable
Definition: xmlParser.cpp:3640
XMLCHAR xmltoc(XMLCSTR t, XMLCHAR v)
Definition: xmlParser.cpp:515
GLdouble GLdouble t
Definition: glext.h:3689
XMLSTR encode(unsigned char *inByteBuf, unsigned int inByteLen, char formatted=0)
length of the base64 string that encodes a data buffer of size inBufLen bytes.
Definition: xmlParser.cpp:3681
#define XMLCHAR
Definition: xmlParser.h:228
void alloc(int newsize)
Definition: xmlParser.cpp:3867
static ALLXMLClearTag XMLClearTags[]
Definition: xmlParser.cpp:49
enum Attrib { eAttribName=0, eAttribEquals, eAttribValue } Attrib
Definition: xmlParser.cpp:800
char maybeAddTxT(void *pa, XMLCSTR tokenPStr)
Definition: xmlParser.cpp:1659
struct XML XML
XMLCSTR lpszOpenTag
Definition: xmlParser.h:284
void deleteAttribute(int i=0)
Delete the ith attribute of the current XMLNode.
Definition: xmlParser.cpp:2876
#define INDENTCHAR
Definition: xmlParser.cpp:78
Main Class representing a XML node.
Definition: xmlParser.h:313
int nColumn
Definition: xmlParser.h:277
XMLCSTR lpXML
Definition: xmlParser.cpp:782
static void myFree(void *p)
Definition: xmlParser.cpp:1421
static XMLSTR xstrstr(XMLCSTR c1, XMLCSTR c2)
Definition: xmlParser.cpp:294
XMLClear * updateClear(XMLCSTR lpszNewContent, int i=0)
text to update is missing, a new one will be added
Definition: xmlParser.cpp:3488
XMLError writeToFile(XMLCSTR filename, const char *encoding=nullptr, char nFormat=1) const
Save the content of an xmlNode inside a file.
Definition: xmlParser.cpp:806
int void fclose(FILE *f)
An OS-independent version of fclose.
Definition: os.cpp:273
XMLClear * addClear(XMLCSTR lpszValue, XMLCSTR lpszOpen=nullptr, XMLCSTR lpszClose=nullptr, XMLElementPosition pos=-1)
Add a new clear tag.
Definition: xmlParser.cpp:3445
void freeBuffer()
call this function when you have finished using this
Definition: xmlParser.cpp:952
XMLCharEncoding
childNode with the specified name if (name==nullptr) return the position of the ith childNode ...
Definition: xmlParser.h:777
int _strnicmp(const char *str, const char *subStr, size_t count) noexcept
An OS-independent version of strnicmp.
Definition: os.cpp:344
static XMLNode parseString(XMLCSTR lpXMLString, XMLCSTR tag=nullptr, XMLResults *pResults=nullptr)
Parse an XML string and return the root of a XMLNode tree representing the string.
Definition: xmlParser.cpp:2216
XMLNode getChildNodeByPath(XMLSTR path, char createNodeIfMissing=0, XMLCHAR sep='/')
name/attribute (return an empty node if failing)
Definition: xmlParser.cpp:3153
GLenum GLsizei n
Definition: glext.h:5074
XMLCSTR updateText(XMLCSTR lpszNewValue, int i=0)
change the name of the attribute if the attribute to update is missing, a new one will be added ...
Definition: xmlParser.cpp:3480
Structure for XML clear (unformatted) node (usually comments)
Definition: xmlParser.h:281
#define SEEK_END
Definition: zconf.h:303
void * addToOrder(int memInc, int *_pos, int nc, void *p, int size, XMLElementType xtype)
Definition: xmlParser.cpp:1468
char isEmpty() const
is this node Empty?
Definition: xmlParser.cpp:3417
int nIndex
Definition: xmlParser.cpp:784
This structure is given by the function XMLNode::enumContents.
Definition: xmlParser.h:940
static int xstrnicmp(XMLCSTR c1, XMLCSTR c2, int l)
Definition: xmlParser.cpp:284
XMLCSTR lpNewElement
Definition: xmlParser.cpp:788
XMLSTR stringDup(XMLCSTR lpszData, int cbData)
Duplicate (copy in a new allocated buffer) the source string.
Definition: xmlParser.cpp:860
static XMLNode createXMLTopNode(XMLCSTR lpszName, char isDeclaration=FALSE)
Create the top node of an XMLNode structure.
Definition: xmlParser.cpp:1414
int nClear() const
nbr of clear field
Definition: xmlParser.cpp:3367
XMLClear * addClear_WOSD(XMLSTR lpszValue, XMLCSTR lpszOpen=nullptr, XMLCSTR lpszClose=nullptr, XMLElementPosition pos=-1)
Add a new clear Tag.
Definition: xmlParser.cpp:3451
XMLNode addChild_priv(int, XMLSTR, char, int)
Definition: xmlParser.cpp:1511
static void * myRealloc(void *p, int newsize, int memInc, int sizeofElem)
Definition: xmlParser.cpp:1425
XMLAttribute * addAttribute_priv(int, XMLSTR, XMLSTR)
Definition: xmlParser.cpp:1525
#define XMLCSTR
Definition: xmlParser.h:226
XMLCSTR pStr
Definition: xmlParser.cpp:796
static int removeOrderElement(XMLNodeData *d, XMLElementType t, int index)
Definition: xmlParser.cpp:1454
XMLCSTR lpEndTag
Definition: xmlParser.cpp:786
XMLElementPosition positionOfChildNode(int i=0) const
Definition: xmlParser.cpp:3192
GLdouble s
Definition: glext.h:3676
GLenum GLsizei len
Definition: glext.h:4712
static const char XML_gb2312ByteTable[256]
Definition: xmlParser.cpp:686
static int xstrncmp(XMLCSTR c1, XMLCSTR c2, int l)
Definition: xmlParser.cpp:290
static XMLClear emptyXMLClear
Definition: xmlParser.h:522
void deleteText(int i=0)
with the name "anAttribute->lpszName" (the "strcmp" function is used to find the right attribute) ...
Definition: xmlParser.cpp:2970
#define BASE64DECODE_READ_NEXT_CHAR(c)
XMLNode & operator=(const XMLNode &A)
to allow shallow/fast copy:
Definition: xmlParser.cpp:2766
int ParseXMLElement(void *pXML)
Definition: xmlParser.cpp:1716
static XMLCSTR getError(XMLError error)
this gives you a
Definition: xmlParser.cpp:83
XMLNodeData * d
Definition: xmlParser.h:916
int mmin(const int t1, const int t2)
Definition: xmlParser.cpp:37
int nChildNode() const
nbr of child node
Definition: xmlParser.cpp:3357
XMLCSTR getText(int i=0) const
return ith text field
Definition: xmlParser.cpp:3397
struct XMLAttribute XMLAttribute
Structure for XML attribute.
XMLNode()
Definition: xmlParser.h:520
int nText() const
nbr of text field
Definition: xmlParser.cpp:3352
static XMLNode createXMLTopNode_WOSD(XMLSTR lpszName, char isDeclaration=FALSE)
Create the top node of an XMLNode structure.
Definition: xmlParser.cpp:1410
static int encodeLength(int inBufLen, char formatted=0)
this object to release memory used by the internal buffer.
Definition: xmlParser.cpp:3674
XMLCSTR addText_WOSD(XMLSTR lpszValue, XMLElementPosition pos=-1)
Add a new text content.
Definition: xmlParser.cpp:3441
XMLAttribute getAttribute(int i=0) const
return ith attribute
Definition: xmlParser.cpp:3382
static NextToken GetNextToken(XML *pXML, int *pcbToken, enum XMLTokenTypeTag *pType)
Definition: xmlParser.cpp:1181
XMLCSTR addText_priv(int, XMLSTR, int)
Definition: xmlParser.cpp:1546
enum XMLError error
Definition: xmlParser.cpp:785
int nElement() const
clear) of the current XMLNode.
Definition: xmlParser.cpp:3372
static XMLCHAR getNextChar(XML *pXML)
Definition: xmlParser.cpp:1168
GLuint index
Definition: glext.h:4054
const GLubyte * c
Definition: glext.h:6313
XMLNode addChild_WOSD(XMLSTR lpszName, char isDeclaration=FALSE, XMLElementPosition pos=-1)
Add a new child node.
Definition: xmlParser.cpp:3424
void emptyTheNode(char force)
Definition: xmlParser.cpp:2718
XMLError
Enumeration for XML parse errors.
Definition: xmlParser.h:238
XMLCSTR xmltoa(XMLCSTR t, XMLCSTR v)
Definition: xmlParser.cpp:510
void deleteNodeContent()
The "deleteNodeContent" function forces the deletion of the content of this XMLNode and the subtree...
Definition: xmlParser.cpp:2707
static int detachFromParent(XMLNodeData *d)
Definition: xmlParser.cpp:2685
#define XMLSTR
Definition: xmlParser.h:227
int indexClear(XMLCSTR lpszValue) const
Definition: xmlParser.cpp:3036
static XMLNode::XMLCharEncoding characterEncoding
Definition: xmlParser.cpp:33
static char setGlobalOptions(XMLCharEncoding characterEncoding=XMLNode::char_encoding_UTF8, char guessWideCharChars=1, char dropWhiteSpace=1, char removeCommentsInMiddleOfText=1)
Sets the global options for the conversions.
Definition: xmlParser.cpp:3501
XMLAttribute * updateAttribute_WOSD(XMLAttribute *newAttribute, XMLAttribute *oldAttribute)
if the attribute to update is
Definition: xmlParser.cpp:2928
XMLCSTR updateName(XMLCSTR lpszName)
change node&#39;s name
Definition: xmlParser.cpp:3457
XMLNodeContents enumContents(XMLElementPosition i) const
enumerate all the different contents (attribute,child,text,
Definition: xmlParser.cpp:3313
static XMLNode emptyNode()
return XMLNode::emptyXMLNode;
Definition: xmlParser.cpp:3418
static unsigned int decodeSize(XMLCSTR inString, XMLError *xe=nullptr)
containing the base64 string containing the binary data encoded from "inByteBuf"
Definition: xmlParser.cpp:3728
GLubyte GLubyte b
Definition: glext.h:6279
int cbNewElement
Definition: xmlParser.cpp:789
#define XML_isSPACECHAR(ch)
Definition: xmlParser.cpp:1147
XMLElementPosition positionOfText(int i=0) const
Definition: xmlParser.cpp:3182
XMLCSTR lpszValue
Definition: xmlParser.h:283
XMLElementPosition positionOfClear(int i=0) const
Definition: xmlParser.cpp:3187
enum Status { eInsideTag=0, eOutsideTag } Status
Definition: xmlParser.cpp:804
static void charmemset(XMLSTR dest, XMLCHAR c, int l)
Definition: xmlParser.cpp:2366
static char dropWhiteSpace
Definition: xmlParser.cpp:34
static void CountLinesAndColumns(XMLCSTR lpXML, int nUpto, XMLResults *pResults)
Definition: xmlParser.cpp:2191
static XMLElementPosition findPosition(XMLNodeData *d, int index, XMLElementType xtype)
Definition: xmlParser.cpp:1443
static int xstricmp(XMLCSTR c1, XMLCSTR c2)
Definition: xmlParser.cpp:288
struct XMLNode::XMLNodeDataTag XMLNodeData
static XMLAttribute emptyXMLAttribute
Definition: xmlParser.h:523
static XMLSTR xstrcpy(XMLSTR c1, XMLCSTR c2)
Definition: xmlParser.cpp:298
static const char XML_sjisByteTable[256]
Definition: xmlParser.cpp:651
static XMLCharacterEntity XMLEntities[]
Definition: xmlParser.cpp:69
static void exactMemory(XMLNodeData *d)
Definition: xmlParser.cpp:1643
static FILE * xfopen(XMLCSTR filename, XMLCSTR mode)
Definition: xmlParser.cpp:272
#define LENSTR(lpsz)
int fprintf(FILE *fil, const char *format,...) noexcept MRPT_printf_format_check(2
An OS-independent version of fprintf.
Definition: os.cpp:406
static XMLCharEncoding guessCharEncoding(void *buffer, int bufLen, char useXMLEncodingAttribute=1)
Guess the character encoding of the string (ascii, utf8 or shift-JIS)
Definition: xmlParser.cpp:3541
static XMLNode parseFile(XMLCSTR filename, XMLCSTR tag=nullptr, XMLResults *pResults=nullptr)
Parse an XML file and return the root of a XMLNode tree representing the file.
Definition: xmlParser.cpp:2283
XMLCSTR lpszOpen
Definition: xmlParser.cpp:45
GLint mode
Definition: glext.h:5669
XMLAttribute * updateAttribute(XMLAttribute *newAttribute, XMLAttribute *oldAttribute)
if the attribute to update is
Definition: xmlParser.cpp:3461
XMLCSTR lpszName
Definition: xmlParser.h:291
XMLCSTR addText(XMLCSTR lpszValue, XMLElementPosition pos=-1)
Add a new text content.
Definition: xmlParser.cpp:3437
int indexText(XMLCSTR lpszValue) const
Definition: xmlParser.cpp:2955
const GLdouble * v
Definition: glext.h:3678
XMLSTR createXMLString(int nFormat=1, int *pnSize=nullptr) const
user-friendly explanation of the parsing error
Definition: xmlParser.cpp:2661
XMLAttribute * addAttribute_WOSD(XMLSTR lpszName, XMLSTR lpszValue)
Add a new attribute.
Definition: xmlParser.cpp:3433
int nIndexMissigEndTag
Definition: xmlParser.cpp:784
XMLCSTR updateText_WOSD(XMLSTR lpszNewValue, int i=0)
change the name of the attribute if the attribute to update is missing, a new one will be added ...
Definition: xmlParser.cpp:2991
int XMLElementPosition
XMLElementPosition are not interchangeable with simple indexes.
Definition: xmlParser.h:296
GLdouble GLdouble GLdouble r
Definition: glext.h:3705
static int lengthXMLString(XMLCSTR source)
deprecated: use "toXML" instead
Definition: xmlParser.cpp:920
#define SEEK_SET
Definition: zconf.h:301
unsigned char * decode(XMLCSTR inString, int *outByteLen=nullptr, XMLError *xe=nullptr)
The "decode" function returns a pointer to a buffer containing the binary data decoded from "inString...
Definition: xmlParser.cpp:3882
char parseClearTag(void *px, void *pa)
Definition: xmlParser.cpp:1587
static const char * XML_ByteTable
Definition: xmlParser.cpp:756
static const char base64Fillchar
Definition: xmlParser.cpp:3636
static const char XML_utf8ByteTable[256]
Definition: xmlParser.cpp:604
XMLClear * updateClear_WOSD(XMLSTR lpszNewContent, int i=0)
is missing, a new one will be added
Definition: xmlParser.cpp:3060
#define FALSE
Definition: xmlParser.h:231
char myTagCompare(XMLCSTR cclose, XMLCSTR copen)
Definition: xmlParser.cpp:1152
char xmltob(XMLCSTR t, char v)
Definition: xmlParser.cpp:489
_u8 status
Definition: rplidar_cmd.h:19
GLuint const GLchar * name
Definition: glext.h:4054
GLsizei GLsizei GLchar * source
Definition: glext.h:4082
Structure for XML attribute.
Definition: xmlParser.h:289
const unsigned char base64DecodeTable[]
Definition: xmlParser.cpp:3646
int nFirst
Definition: xmlParser.cpp:790
static char guessWideCharChars
Definition: xmlParser.cpp:34
ALLXMLClearTag * pClr
Definition: xmlParser.cpp:795
XMLCSTR lpszClose
Definition: xmlParser.cpp:47
char myIsTextWideChar(const void *b, int l)
Definition: xmlParser.cpp:193
XMLCSTR lpszValue
Definition: xmlParser.h:292
FILE * fopen(const char *fileName, const char *mode) noexcept
An OS-independent version of fopen.
Definition: os.cpp:255
enum XMLError error
Definition: xmlParser.h:276
XMLNode addChild(XMLCSTR lpszName, char isDeclaration=FALSE, XMLElementPosition pos=-1)
Add a new child node.
Definition: xmlParser.cpp:3419
static int CreateXMLStringR(XMLNodeData *pEntry, XMLSTR lpszMarker, int nFormat)
Definition: xmlParser.cpp:2376
long xmltol(XMLCSTR t, long v)
Definition: xmlParser.cpp:499
GLsizeiptr size
Definition: glext.h:3923
XMLCSTR lpszText
Definition: xmlParser.cpp:783
enum XMLTokenTypeTag XMLTokenType
GLenum GLint x
Definition: glext.h:3538
XMLClear getClear(int i=0) const
return ith clear field (comments)
Definition: xmlParser.cpp:3377
static char removeCommentsInMiddleOfText
Definition: xmlParser.cpp:35
char * strcpy(char *dest, size_t destSize, const char *source) noexcept
An OS-independent version of strcpy.
Definition: os.cpp:297
XMLCSTR getAttributeValue(int i=0) const
return ith attribute value
Definition: xmlParser.cpp:3392
static XMLNode emptyXMLNode
Definition: xmlParser.h:520
XMLTokenTypeTag
Definition: xmlParser.cpp:766
char isDeclaration() const
is this node a declaration <? .... ?>
Definition: xmlParser.cpp:3412
int cbEndTag
Definition: xmlParser.cpp:787
#define TRUE
Definition: xmlParser.h:234
void freeBuffer()
Call this function when you have finished using.
Definition: xmlParser.cpp:3667
char * myWideCharToMultiByte(const wchar_t *s)
Definition: xmlParser.cpp:243
GLsizei GLsizei GLenum GLenum const GLvoid * data
Definition: glext.h:3546
GLubyte GLubyte GLubyte a
Definition: glext.h:6279
GLfloat GLfloat p
Definition: glext.h:6305
XMLCSTR getAttributeName(int i=0) const
return ith attribute name
Definition: xmlParser.cpp:3387
void freeXMLString(XMLSTR t)
to free the string allocated inside the "stringDup" function or the "createXMLString" function...
Definition: xmlParser.cpp:28
void deleteClear(int i=0)
"lpszValue" inside the current XMLNode (direct "pointer-to-pointer" comparison is used to find the ri...
Definition: xmlParser.cpp:3020
XMLCSTR lpszCloseTag
Definition: xmlParser.h:285
int nChildNode(XMLCSTR name) const
return the number of child node with specific name
Definition: xmlParser.cpp:3097
XMLNode deepCopy() const
deep copy (duplicate/clone) a XMLNode
Definition: xmlParser.cpp:2789
Structure used to obtain error details if the parse fails.
Definition: xmlParser.h:274
double xmltof(XMLCSTR t, double v)
Definition: xmlParser.cpp:504
int sprintf(char *buf, size_t bufSize, const char *format,...) noexcept MRPT_printf_format_check(3
An OS-independent version of sprintf (Notice the bufSize param, which may be ignored in some compiler...
Definition: os.cpp:189
static XMLSTR toXMLUnSafe(XMLSTR dest, XMLCSTR source)
that contains a XML-encoded string based on the "source" parameter.
Definition: xmlParser.cpp:875
static int xstrlen(XMLCSTR c)
Definition: xmlParser.cpp:276
int xmltoi(XMLCSTR t, int v)
Definition: xmlParser.cpp:494
XMLSTR fromXMLString(XMLCSTR s, int lo, XML *pXML)
Definition: xmlParser.cpp:970
XMLCSTR getName() const
name of the node
Definition: xmlParser.cpp:3347
void memcpy(void *dest, size_t destSize, const void *src, size_t copyCount) noexcept
An OS and compiler independent version of "memcpy".
Definition: os.cpp:356
XMLNode getChildNode(int i=0) const
return ith child node
Definition: xmlParser.cpp:3402
XMLAttribute * addAttribute(XMLCSTR lpszName, XMLCSTR lpszValuev)
it will be detached from it&#39;s parents before being attached to the current XMLNode ...
Definition: xmlParser.cpp:3429
static const char XML_legacyByteTable[256]
Definition: xmlParser.cpp:639
XMLClear * addClear_priv(int, XMLSTR, XMLCSTR, XMLCSTR, int)
Definition: xmlParser.cpp:1562
static XMLNode openFileHelper(XMLCSTR filename, XMLCSTR tag=nullptr)
Parse an XML file and return the root of a XMLNode tree representing the file.
Definition: xmlParser.cpp:529



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: 7d5e6d718 Fri Aug 24 01:51:28 2018 +0200 at lun nov 2 08:35:50 CET 2020