MRPT  1.9.9
xmlParser.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | https://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2019, Individual contributors, see AUTHORS file |
6  | See: https://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See: https://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 <cstdlib>
25 #include <cstring>
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 auto* 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
767 {
770  eTokenTagStart, /* "<" */
771  eTokenTagEnd, /* "</" */
772  eTokenCloseTag, /* ">" */
773  eTokenEquals, /* "=" */
774  eTokenDeclaration, /* "<?" */
778 } XMLTokenType;
779 
780 // Main structure used for parsing XML
781 typedef struct XML
782 {
788  int cbEndTag;
791  int nFirst;
792 } XML;
793 
794 typedef struct
795 {
798 } NextToken;
799 
800 // Enumeration used when parsing attributes
801 using Attrib = enum Attrib { eAttribName = 0, eAttribEquals, eAttribValue };
802 
803 // Enumeration used when parsing elements to dictate whether we are currently
804 // inside a tag
805 using Status = enum Status { eInsideTag = 0, eOutsideTag };
806 
808  XMLCSTR filename, const char* encoding, char nFormat) const
809 {
810  if (!d) return eXMLErrorNone;
811  FILE* f = xfopen(filename, _CXML("wb"));
812  if (!f) return eXMLErrorCannotOpenWriteFile;
813 #ifdef _XMLWIDECHAR
814  unsigned char h[2] = {0xFF, 0xFE};
815  if (!fwrite(h, 2, 1, f)) return eXMLErrorCannotWriteFile;
816  if ((!isDeclaration()) &&
817  ((d->lpszName) || (!getChildNode().isDeclaration())))
818  {
819  if (!fwrite(
820  L"<?xml version=\"1.0\" encoding=\"utf-16\"?>\n",
821  sizeof(wchar_t) * 40, 1, f))
823  }
824 #else
825  if ((!isDeclaration()) &&
826  ((d->lpszName) || (!getChildNode().isDeclaration())))
827  {
829  {
830  // header so that windows recognize the file as UTF-8:
831  unsigned char h[3] = {0xEF, 0xBB, 0xBF};
832  if (!fwrite(h, 3, 1, f)) return eXMLErrorCannotWriteFile;
833  encoding = "utf-8";
834  }
836  encoding = "SHIFT-JIS";
837 
838  if (!encoding) encoding = "ISO-8859-1";
839  if (fprintf(f, "<?xml version=\"1.0\" encoding=\"%s\"?>\n", encoding) <
840  0)
842  }
843  else
844  {
846  {
847  unsigned char h[3] = {0xEF, 0xBB, 0xBF};
848  if (!fwrite(h, 3, 1, f)) return eXMLErrorCannotWriteFile;
849  }
850  }
851 #endif
852  int i;
853  XMLSTR t = createXMLString(nFormat, &i);
854  if (!fwrite(t, sizeof(XMLCHAR) * i, 1, f)) return eXMLErrorCannotWriteFile;
855  if (fclose(f) != 0) return eXMLErrorCannotWriteFile;
856  free(t);
857  return eXMLErrorNone;
858 }
859 
860 // Duplicate a given string.
861 XMLSTR stringDup(XMLCSTR lpszData, int cbData)
862 {
863  if (lpszData == nullptr) return nullptr;
864 
865  XMLSTR lpszNew;
866  if (cbData == -1) cbData = (int)xstrlen(lpszData);
867  lpszNew = (XMLSTR)malloc((cbData + 1) * sizeof(XMLCHAR));
868  if (lpszNew)
869  {
870  memcpy(lpszNew, lpszData, (cbData) * sizeof(XMLCHAR));
871  lpszNew[cbData] = (XMLCHAR)NULL;
872  }
873  return lpszNew;
874 }
875 
877 {
878  XMLSTR dd = dest;
879  XMLCHAR ch;
880  XMLCharacterEntity* entity;
881  while ((ch = *source) != '\0')
882  {
883  entity = XMLEntities;
884  do
885  {
886  if (ch == entity->c)
887  {
888  xstrcpy(dest, entity->s);
889  dest += entity->l;
890  source++;
891  goto out_of_loop1;
892  }
893  entity++;
894  } while (entity->s);
895 #ifdef _XMLWIDECHAR
896  *(dest++) = *(source++);
897 #else
898  switch (XML_ByteTable[(unsigned char)ch])
899  {
900  case 4:
901  *(dest++) = *(source++);
902  [[fallthrough]];
903  case 3:
904  *(dest++) = *(source++);
905  [[fallthrough]];
906  case 2:
907  *(dest++) = *(source++);
908  [[fallthrough]];
909  case 1:
910  *(dest++) = *(source++);
911  break;
912  }
913 #endif
914  out_of_loop1:;
915  }
916  *dest = 0;
917  return dd;
918 }
919 
920 // private (used while rendering):
922 {
923  int r = 0;
924  XMLCharacterEntity* entity;
925  XMLCHAR ch;
926  while ((ch = *source) != '\0')
927  {
928  entity = XMLEntities;
929  do
930  {
931  if (ch == entity->c)
932  {
933  r += entity->l;
934  source++;
935  goto out_of_loop1;
936  }
937  entity++;
938  } while (entity->s);
939 #ifdef _XMLWIDECHAR
940  r++;
941  source++;
942 #else
943  ch = XML_ByteTable[(unsigned char)ch];
944  r += ch;
945  source += ch;
946 #endif
947  out_of_loop1:;
948  }
949  return r;
950 }
951 
954 {
955  if (buf) free(buf);
956  buf = nullptr;
957  buflen = 0;
958 }
960 {
961  int l = lengthXMLString(source) + 1;
962  if (l > buflen)
963  {
964  buflen = l;
965  buf = (XMLSTR)realloc(buf, l * sizeof(XMLCHAR));
966  }
967  return toXMLUnSafe(buf, source);
968 }
969 
970 // private:
972 {
973  // This function is the opposite of the function "toXMLString". It decodes
974  // the escape
975  // sequences &amp;, &quot;, &apos;, &lt;, &gt; and replace them by the
976  // characters
977  // &,",',<,>. This function is used internally by the XML Parser. All the
978  // calls to
979  // the XML library will always gives you back "decoded" strings.
980  //
981  // in: string (s) and length (lo) of string
982  // out: new allocated string converted from xml
983  if (!s) return nullptr;
984 
985  int ll = 0, j;
986  XMLSTR d;
987  XMLCSTR ss = s;
988  XMLCharacterEntity* entity;
989  while ((lo > 0) && (*s))
990  {
991  if (*s == _CXML('&'))
992  {
993  if ((lo > 2) && (s[1] == _CXML('#')))
994  {
995  s += 2;
996  lo -= 2;
997  if ((*s == _CXML('X')) || (*s == _CXML('x')))
998  {
999  s++;
1000  lo--;
1001  }
1002  while ((*s) && (*s != _CXML(';')) && ((lo--) > 0)) s++;
1003  if (*s != _CXML(';'))
1004  {
1006  return nullptr;
1007  }
1008  s++;
1009  lo--;
1010  }
1011  else
1012  {
1013  entity = XMLEntities;
1014  do
1015  {
1016  if ((lo >= entity->l) &&
1017  (xstrnicmp(s, entity->s, entity->l) == 0))
1018  {
1019  s += entity->l;
1020  lo -= entity->l;
1021  break;
1022  }
1023  entity++;
1024  } while (entity->s);
1025  if (!entity->s)
1026  {
1028  return nullptr;
1029  }
1030  }
1031  }
1032  else
1033  {
1034 #ifdef _XMLWIDECHAR
1035  s++;
1036  lo--;
1037 #else
1038  j = XML_ByteTable[(unsigned char)*s];
1039  s += j;
1040  lo -= j;
1041  ll += j - 1;
1042 #endif
1043  }
1044  ll++;
1045  }
1046 
1047  d = (XMLSTR)malloc((ll + 1) * sizeof(XMLCHAR));
1048  s = d;
1049  while (ll-- > 0)
1050  {
1051  if (*ss == _CXML('&'))
1052  {
1053  if (ss[1] == _CXML('#'))
1054  {
1055  ss += 2;
1056  j = 0;
1057  if ((*ss == _CXML('X')) || (*ss == _CXML('x')))
1058  {
1059  ss++;
1060  while (*ss != _CXML(';'))
1061  {
1062  if ((*ss >= _CXML('0')) && (*ss <= _CXML('9')))
1063  j = (j << 4) + *ss - _CXML('0');
1064  else if ((*ss >= _CXML('A')) && (*ss <= _CXML('F')))
1065  j = (j << 4) + *ss - _CXML('A') + 10;
1066  else if ((*ss >= _CXML('a')) && (*ss <= _CXML('f')))
1067  j = (j << 4) + *ss - _CXML('a') + 10;
1068  else
1069  {
1070  free((void*)s);
1072  return nullptr;
1073  }
1074  ss++;
1075  }
1076  }
1077  else
1078  {
1079  while (*ss != _CXML(';'))
1080  {
1081  if ((*ss >= _CXML('0')) && (*ss <= _CXML('9')))
1082  j = (j * 10) + *ss - _CXML('0');
1083  else
1084  {
1085  free((void*)s);
1087  return nullptr;
1088  }
1089  ss++;
1090  }
1091  }
1092 #ifndef _XMLWIDECHAR
1093  if (j > 255)
1094  {
1095  free((void*)s);
1097  return nullptr;
1098  }
1099 #endif
1100  (*d++) = (XMLCHAR)j;
1101  ss++;
1102  }
1103  else
1104  {
1105  entity = XMLEntities;
1106  do
1107  {
1108  if (xstrnicmp(ss, entity->s, entity->l) == 0)
1109  {
1110  *(d++) = entity->c;
1111  ss += entity->l;
1112  break;
1113  }
1114  entity++;
1115  } while (entity->s);
1116  }
1117  }
1118  else
1119  {
1120 #ifdef _XMLWIDECHAR
1121  *(d++) = *(ss++);
1122 #else
1123  switch (XML_ByteTable[(unsigned char)*ss])
1124  {
1125  case 4:
1126  *(d++) = *(ss++);
1127  ll--;
1128  /*FALLTHROUGH*/
1129  case 3:
1130  *(d++) = *(ss++);
1131  ll--;
1132  /*FALLTHROUGH*/
1133  case 2:
1134  *(d++) = *(ss++);
1135  ll--;
1136  /*FALLTHROUGH*/
1137  case 1:
1138  *(d++) = *(ss++);
1139  /*FALLTHROUGH*/
1140  }
1141 #endif
1142  }
1143  }
1144  *d = 0;
1145  return (XMLSTR)s;
1146 }
1147 
1148 #define XML_isSPACECHAR(ch) \
1149  ((ch == _CXML('\n')) || (ch == _CXML(' ')) || (ch == _CXML('\t')) || \
1150  (ch == _CXML('\r')))
1151 
1152 // private:
1153 char myTagCompare(XMLCSTR cclose, XMLCSTR copen)
1154 // !!!! WARNING strange convention&:
1155 // return 0 if equals
1156 // return 1 if different
1157 {
1158  if (!cclose) return 1;
1159  int l = (int)xstrlen(cclose);
1160  if (xstrnicmp(cclose, copen, l) != 0) return 1;
1161  const XMLCHAR c = copen[l];
1162  if (XML_isSPACECHAR(c) || (c == _CXML('/')) || (c == _CXML('<')) ||
1163  (c == _CXML('>')) || (c == _CXML('=')))
1164  return 0;
1165  return 1;
1166 }
1167 
1168 // Obtain the next character from the string.
1169 static inline XMLCHAR getNextChar(XML* pXML)
1170 {
1171  XMLCHAR ch = pXML->lpXML[pXML->nIndex];
1172 #ifdef _XMLWIDECHAR
1173  if (ch != 0) pXML->nIndex++;
1174 #else
1175  pXML->nIndex += XML_ByteTable[(unsigned char)ch];
1176 #endif
1177  return ch;
1178 }
1179 
1180 // Find the next token in a string.
1181 // pcbToken contains the number of characters that have been read.
1183  XML* pXML, int* pcbToken, enum XMLTokenTypeTag* pType)
1184 {
1185  NextToken result;
1186  XMLCHAR ch;
1187  XMLCHAR chTemp;
1188  int indexStart, nFoundMatch, nIsText = FALSE;
1189  result.pClr = nullptr; // prevent warning
1190 
1191  // Find next non-white space character
1192  do
1193  {
1194  indexStart = pXML->nIndex;
1195  ch = getNextChar(pXML);
1196  } while XML_isSPACECHAR(ch);
1197 
1198  if (ch)
1199  {
1200  // Cache the current string pointer
1201  result.pStr = &pXML->lpXML[indexStart];
1202 
1203  // First check whether the token is in the clear tag list (meaning it
1204  // does not need formatting).
1205  ALLXMLClearTag* ctag = XMLClearTags;
1206  do
1207  {
1208  if (xstrncmp(ctag->lpszOpen, result.pStr, ctag->openTagLen) == 0)
1209  {
1210  result.pClr = ctag;
1211  pXML->nIndex += ctag->openTagLen - 1;
1212  *pType = eTokenClear;
1213  return result;
1214  }
1215  ctag++;
1216  } while (ctag->lpszOpen);
1217 
1218  // If we didn't find a clear tag then check for standard tokens
1219  switch (ch)
1220  {
1221  // Check for quotes
1222  case _CXML('\''):
1223  case _CXML('\"'):
1224  // Type of token
1225  *pType = eTokenQuotedText;
1226  chTemp = ch;
1227 
1228  // Set the size
1229  nFoundMatch = FALSE;
1230 
1231  // Search through the string to find a matching quote
1232  while ((ch = getNextChar(pXML)))
1233  {
1234  if (ch == chTemp)
1235  {
1236  nFoundMatch = TRUE;
1237  break;
1238  }
1239  if (ch == _CXML('<')) break;
1240  }
1241 
1242  // If we failed to find a matching quote
1243  if (nFoundMatch == FALSE)
1244  {
1245  pXML->nIndex = indexStart + 1;
1246  nIsText = TRUE;
1247  break;
1248  }
1249 
1250  // 4.02.2002
1251  // if (FindNonWhiteSpace(pXML)) pXML->nIndex--;
1252 
1253  break;
1254 
1255  // Equals (used with attribute values)
1256  case _CXML('='):
1257  *pType = eTokenEquals;
1258  break;
1259 
1260  // Close tag
1261  case _CXML('>'):
1262  *pType = eTokenCloseTag;
1263  break;
1264 
1265  // Check for tag start and tag end
1266  case _CXML('<'):
1267 
1268  // Peek at the next character to see if we have an end tag '</',
1269  // or an xml declaration '<?'
1270  chTemp = pXML->lpXML[pXML->nIndex];
1271 
1272  // If we have a tag end...
1273  if (chTemp == _CXML('/'))
1274  {
1275  // Set the type and ensure we point at the next character
1276  getNextChar(pXML);
1277  *pType = eTokenTagEnd;
1278  }
1279 
1280  // If we have an XML declaration tag
1281  else if (chTemp == _CXML('?'))
1282  {
1283  // Set the type and ensure we point at the next character
1284  getNextChar(pXML);
1285  *pType = eTokenDeclaration;
1286  }
1287 
1288  // Otherwise we must have a start tag
1289  else
1290  {
1291  *pType = eTokenTagStart;
1292  }
1293  break;
1294 
1295  // Check to see if we have a short hand type end tag ('/>').
1296  case _CXML('/'):
1297 
1298  // Peek at the next character to see if we have a short end tag
1299  // '/>'
1300  chTemp = pXML->lpXML[pXML->nIndex];
1301 
1302  // If we have a short hand end tag...
1303  if (chTemp == _CXML('>'))
1304  {
1305  // Set the type and ensure we point at the next character
1306  getNextChar(pXML);
1307  *pType = eTokenShortHandClose;
1308  break;
1309  }
1310  /*FALLTHROUGH*/
1311 
1312  // If we haven't found a short hand closing tag then drop into the
1313  // text process
1314 
1315  // Other characters
1316  default:
1317  nIsText = TRUE;
1318  }
1319 
1320  // If this is a TEXT node
1321  if (nIsText)
1322  {
1323  // Indicate we are dealing with text
1324  *pType = eTokenText;
1325  while ((ch = getNextChar(pXML)))
1326  {
1327  if
1328  XML_isSPACECHAR(ch)
1329  {
1330  indexStart++;
1331  break;
1332  }
1333  else if (ch == _CXML('/'))
1334  {
1335  // If we find a slash then this maybe text or a short hand
1336  // end tag
1337  // Peek at the next character to see it we have short hand
1338  // end tag
1339  ch = pXML->lpXML[pXML->nIndex];
1340  // If we found a short hand end tag then we need to exit the
1341  // loop
1342  if (ch == _CXML('>'))
1343  {
1344  pXML->nIndex--;
1345  break;
1346  }
1347  }
1348  else if (
1349  (ch == _CXML('<')) || (ch == _CXML('>')) ||
1350  (ch == _CXML('=')))
1351  {
1352  pXML->nIndex--;
1353  break;
1354  }
1355  }
1356  }
1357  *pcbToken = pXML->nIndex - indexStart;
1358  }
1359  else
1360  {
1361  // If we failed to obtain a valid character
1362  *pcbToken = 0;
1363  *pType = eTokenError;
1364  result.pStr = nullptr;
1365  }
1366 
1367  return result;
1368 }
1369 
1371 {
1372  if (!d)
1373  {
1374  free(lpszName);
1375  return nullptr;
1376  }
1377  if (d->lpszName && (lpszName != d->lpszName)) free((void*)d->lpszName);
1378  d->lpszName = lpszName;
1379  return lpszName;
1380 }
1381 
1382 // private:
1384 {
1385  d = p;
1386  (p->ref_count)++;
1387 }
1388 XMLNode::XMLNode(XMLNodeData* pParent, XMLSTR lpszName, char isDeclaration)
1389 {
1390  d = (XMLNodeData*)malloc(sizeof(XMLNodeData));
1391  d->ref_count = 1;
1392 
1393  d->lpszName = nullptr;
1394  d->nChild = 0;
1395  d->nText = 0;
1396  d->nClear = 0;
1397  d->nAttribute = 0;
1398 
1399  d->isDeclaration = isDeclaration;
1400 
1401  d->pParent = pParent;
1402  d->pChild = nullptr;
1403  d->pText = nullptr;
1404  d->pClear = nullptr;
1405  d->pAttribute = nullptr;
1406  d->pOrder = nullptr;
1407 
1408  updateName_WOSD(lpszName);
1409 }
1410 
1411 XMLNode XMLNode::createXMLTopNode_WOSD(XMLSTR lpszName, char isDeclaration)
1412 {
1413  return XMLNode(nullptr, lpszName, isDeclaration);
1414 }
1415 XMLNode XMLNode::createXMLTopNode(XMLCSTR lpszName, char isDeclaration)
1416 {
1417  return XMLNode(nullptr, stringDup(lpszName), isDeclaration);
1418 }
1419 
1420 #define MEMORYINCREASE 50
1421 
1422 static inline void myFree(void* p)
1423 {
1424  if (p) free(p);
1425 }
1426 static inline void* myRealloc(void* p, int newsize, int memInc, int sizeofElem)
1427 {
1428  if (p == nullptr)
1429  {
1430  if (memInc) return malloc(memInc * sizeofElem);
1431  return malloc(sizeofElem);
1432  }
1433  if ((memInc == 0) || ((newsize % memInc) == 0))
1434  p = realloc(p, (newsize + memInc) * sizeofElem);
1435  // if (!p)
1436  // {
1437  // printf("XMLParser Error: Not enough memory! Aborting...\n");
1438  // exit(220);
1439  // }
1440  return p;
1441 }
1442 
1443 // private:
1445  XMLNodeData* d, int index, XMLElementType xxtype)
1446 {
1447  if (index < 0) return -1;
1448  int i = 0, j = (int)((index << 2) + xxtype), *o = d->pOrder;
1449  while (o[i] != j) i++;
1450  return i;
1451 }
1452 
1453 // private:
1454 // update "order" information when deleting a content of a XMLNode
1456 {
1457  int n = d->nChild + d->nText + d->nClear, *o = d->pOrder,
1458  i = findPosition(d, index, t);
1459  memmove(o + i, o + i + 1, (n - i) * sizeof(int));
1460  for (; i < n; i++)
1461  if ((o[i] & 3) == (int)t) o[i] -= 4;
1462  // We should normally do:
1463  // d->pOrder=(int)realloc(d->pOrder,n*sizeof(int));
1464  // but we skip reallocation because it's too time consuming.
1465  // Anyway, at the end, it will be free'd completely at once.
1466  return i;
1467 }
1468 
1470  int memoryIncrease, int* _pos, int nc, void* p, int size,
1471  XMLElementType xtype)
1472 {
1473  // in: *_pos is the position inside d->pOrder ("-1" means "EndOf")
1474  // out: *_pos is the index inside p
1475  p = myRealloc(p, (nc + 1), memoryIncrease, size);
1476  int n = d->nChild + d->nText + d->nClear;
1477  d->pOrder =
1478  (int*)myRealloc(d->pOrder, n + 1, memoryIncrease * 3, sizeof(int));
1479  int pos = *_pos, *o = d->pOrder;
1480 
1481  if ((pos < 0) || (pos >= n))
1482  {
1483  *_pos = nc;
1484  o[n] = (int)((nc << 2) + xtype);
1485  return p;
1486  }
1487 
1488  int i = pos;
1489  memmove(o + i + 1, o + i, (n - i) * sizeof(int));
1490 
1491  while ((pos < n) && ((o[pos] & 3) != (int)xtype)) pos++;
1492  if (pos == n)
1493  {
1494  *_pos = nc;
1495  o[n] = (int)((nc << 2) + xtype);
1496  return p;
1497  }
1498 
1499  o[i] = o[pos];
1500  for (i = pos + 1; i <= n; i++)
1501  if ((o[i] & 3) == (int)xtype) o[i] += 4;
1502 
1503  *_pos = pos = o[pos] >> 2;
1504  memmove(
1505  ((char*)p) + (pos + 1) * size, ((char*)p) + pos * size,
1506  (nc - pos) * size);
1507 
1508  return p;
1509 }
1510 
1511 // Add a child node to the given element.
1513  int memoryIncrease, XMLSTR lpszName, char isDeclaration, int pos)
1514 {
1515  if (!lpszName) return emptyXMLNode;
1516  d->pChild = (XMLNode*)addToOrder(
1517  memoryIncrease, &pos, d->nChild, d->pChild, sizeof(XMLNode),
1518  eNodeChild);
1519  d->pChild[pos].d = nullptr;
1520  d->pChild[pos] = XMLNode(d, lpszName, isDeclaration);
1521  d->nChild++;
1522  return d->pChild[pos];
1523 }
1524 
1525 // Add an attribute to an element.
1527  int memoryIncrease, XMLSTR lpszName, XMLSTR lpszValuev)
1528 {
1529  if (!lpszName) return &emptyXMLAttribute;
1530  if (!d)
1531  {
1532  myFree(lpszName);
1533  myFree(lpszValuev);
1534  return &emptyXMLAttribute;
1535  }
1536  int nc = d->nAttribute;
1537  d->pAttribute = (XMLAttribute*)myRealloc(
1538  d->pAttribute, (nc + 1), memoryIncrease, sizeof(XMLAttribute));
1539  XMLAttribute* pAttr = d->pAttribute + nc;
1540  pAttr->lpszName = lpszName;
1541  pAttr->lpszValue = lpszValuev;
1542  d->nAttribute++;
1543  return pAttr;
1544 }
1545 
1546 // Add text to the element.
1547 XMLCSTR XMLNode::addText_priv(int memoryIncrease, XMLSTR lpszValue, int pos)
1548 {
1549  if (!lpszValue) return nullptr;
1550  if (!d)
1551  {
1552  myFree(lpszValue);
1553  return nullptr;
1554  }
1555  d->pText = (XMLCSTR*)addToOrder(
1556  memoryIncrease, &pos, d->nText, d->pText, sizeof(XMLSTR), eNodeText);
1557  d->pText[pos] = lpszValue;
1558  d->nText++;
1559  return lpszValue;
1560 }
1561 
1562 // Add clear (unformatted) text to the element.
1564  int memoryIncrease, XMLSTR lpszValue, XMLCSTR lpszOpen, XMLCSTR lpszClose,
1565  int pos)
1566 {
1567  if (!lpszValue) return &emptyXMLClear;
1568  if (!d)
1569  {
1570  myFree(lpszValue);
1571  return &emptyXMLClear;
1572  }
1573  d->pClear = (XMLClear*)addToOrder(
1574  memoryIncrease, &pos, d->nClear, d->pClear, sizeof(XMLClear),
1575  eNodeClear);
1576  XMLClear* pNewClear = d->pClear + pos;
1577  pNewClear->lpszValue = lpszValue;
1578  if (!lpszOpen) lpszOpen = XMLClearTags->lpszOpen;
1579  if (!lpszClose) lpszClose = XMLClearTags->lpszClose;
1580  pNewClear->lpszOpenTag = lpszOpen;
1581  pNewClear->lpszCloseTag = lpszClose;
1582  d->nClear++;
1583  return pNewClear;
1584 }
1585 
1586 // private:
1587 // Parse a clear (unformatted) type node.
1588 char XMLNode::parseClearTag(void* px, void* _pClear)
1589 {
1590  XML* pXML = (XML*)px;
1591  ALLXMLClearTag pClear = *((ALLXMLClearTag*)_pClear);
1592  int cbTemp = 0;
1593  XMLCSTR lpszTemp = nullptr;
1594  XMLCSTR lpXML = &pXML->lpXML[pXML->nIndex];
1595  static XMLCSTR docTypeEnd = _CXML("]>");
1596 
1597  // Find the closing tag
1598  // Seems the <!DOCTYPE need a better treatment so lets handle it
1599  if (pClear.lpszOpen == XMLClearTags[1].lpszOpen)
1600  {
1601  XMLCSTR pCh = lpXML;
1602  while (*pCh)
1603  {
1604  if (*pCh == _CXML('<'))
1605  {
1606  pClear.lpszClose = docTypeEnd;
1607  lpszTemp = xstrstr(lpXML, docTypeEnd);
1608  break;
1609  }
1610  else if (*pCh == _CXML('>'))
1611  {
1612  lpszTemp = pCh;
1613  break;
1614  }
1615 #ifdef _XMLWIDECHAR
1616  pCh++;
1617 #else
1618  pCh += XML_ByteTable[(unsigned char)(*pCh)];
1619 #endif
1620  }
1621  }
1622  else
1623  lpszTemp = xstrstr(lpXML, pClear.lpszClose);
1624 
1625  if (lpszTemp)
1626  {
1627  // Cache the size and increment the index
1628  cbTemp = (int)(lpszTemp - lpXML);
1629 
1630  pXML->nIndex += cbTemp + (int)xstrlen(pClear.lpszClose);
1631 
1632  // Add the clear node to the current element
1633  addClear_priv(
1634  MEMORYINCREASE, stringDup(lpXML, cbTemp), pClear.lpszOpen,
1635  pClear.lpszClose, -1);
1636  return 0;
1637  }
1638 
1639  // If we failed to find the end tag
1641  return 1;
1642 }
1643 
1645 {
1646  if (d->pOrder)
1647  d->pOrder = (int*)realloc(
1648  d->pOrder, (d->nChild + d->nText + d->nClear) * sizeof(int));
1649  if (d->pChild)
1650  d->pChild = (XMLNode*)realloc(d->pChild, d->nChild * sizeof(XMLNode));
1651  if (d->pAttribute)
1652  d->pAttribute = (XMLAttribute*)realloc(
1653  d->pAttribute, d->nAttribute * sizeof(XMLAttribute));
1654  if (d->pText)
1655  d->pText = (XMLCSTR*)realloc(d->pText, d->nText * sizeof(XMLSTR));
1656  if (d->pClear)
1657  d->pClear = (XMLClear*)realloc(d->pClear, d->nClear * sizeof(XMLClear));
1658 }
1659 
1660 char XMLNode::maybeAddTxT(void* pa, XMLCSTR tokenPStr)
1661 {
1662  XML* pXML = (XML*)pa;
1663  XMLCSTR lpszText = pXML->lpszText;
1664  if (!lpszText) return 0;
1665  if (dropWhiteSpace)
1666  while (XML_isSPACECHAR(*lpszText) && (lpszText != tokenPStr))
1667  lpszText++;
1668  int cbText = (int)(tokenPStr - lpszText);
1669  if (!cbText)
1670  {
1671  pXML->lpszText = nullptr;
1672  return 0;
1673  }
1674  if (dropWhiteSpace)
1675  {
1676  cbText--;
1677  while ((cbText) && XML_isSPACECHAR(lpszText[cbText])) cbText--;
1678  cbText++;
1679  }
1680  if (!cbText)
1681  {
1682  pXML->lpszText = nullptr;
1683  return 0;
1684  }
1685  XMLSTR lpt = fromXMLString(lpszText, cbText, pXML);
1686  if (!lpt) return 1;
1687  pXML->lpszText = nullptr;
1688  if (removeCommentsInMiddleOfText && d->nText && d->nClear)
1689  {
1690  // if the previous insertion was a comment (<!-- -->) AND
1691  // if the previous previous insertion was a text then, delete the
1692  // comment and append the text
1693  int n = d->nChild + d->nText + d->nClear - 1, *o = d->pOrder;
1694  if (((o[n] & 3) == eNodeClear) && ((o[n - 1] & 3) == eNodeText))
1695  {
1696  int i = o[n] >> 2;
1697  if (d->pClear[i].lpszOpenTag == XMLClearTags[2].lpszOpen)
1698  {
1699  deleteClear(i);
1700  i = o[n - 1] >> 2;
1701  n = xstrlen(d->pText[i]);
1702  int n2 = xstrlen(lpt) + 1;
1703  d->pText[i] = (XMLSTR)realloc(
1704  (void*)d->pText[i], (n + n2) * sizeof(XMLCHAR));
1705  if (!d->pText[i]) return 1;
1706  memcpy((void*)(d->pText[i] + n), lpt, n2 * sizeof(XMLCHAR));
1707  free(lpt);
1708  return 0;
1709  }
1710  }
1711  }
1712  addText_priv(MEMORYINCREASE, lpt, -1);
1713  return 0;
1714 }
1715 // private:
1716 // Recursively parse an XML element.
1718 {
1719  XML* pXML = (XML*)pa;
1720  int cbToken;
1721  enum XMLTokenTypeTag xtype;
1722  NextToken token;
1723  XMLCSTR lpszTemp = nullptr;
1724  int cbTemp = 0;
1725  char nDeclaration;
1726  XMLNode pNew;
1727  enum Status status; // inside or outside a tag
1728  enum Attrib attrib = eAttribName;
1729 
1730  assert(pXML);
1731 
1732  // If this is the first call to the function
1733  if (pXML->nFirst)
1734  {
1735  // Assume we are outside of a tag definition
1736  pXML->nFirst = FALSE;
1737  status = eOutsideTag;
1738  }
1739  else
1740  {
1741  // If this is not the first call then we should only be called when
1742  // inside a tag.
1743  status = eInsideTag;
1744  }
1745 
1746  // Iterate through the tokens in the document
1747  for (;;)
1748  {
1749  // Obtain the next token
1750  token = GetNextToken(pXML, &cbToken, &xtype);
1751 
1752  if (xtype != eTokenError)
1753  {
1754  // Check the current status
1755  switch (status)
1756  {
1757  // If we are outside of a tag definition
1758  case eOutsideTag:
1759 
1760  // Check what type of token we obtained
1761  switch (xtype)
1762  {
1763  // If we have found text or quoted text
1764  case eTokenText:
1765  case eTokenCloseTag: /* '>' */
1766  case eTokenShortHandClose: /* '/>' */
1767  case eTokenQuotedText:
1768  case eTokenEquals:
1769  break;
1770 
1771  // If we found a start tag '<' and declarations '<?'
1772  case eTokenTagStart:
1773  case eTokenDeclaration:
1774 
1775  // Cache whether this new element is a declaration
1776  // or not
1777  nDeclaration = (xtype == eTokenDeclaration);
1778 
1779  // If we have node text then add this to the element
1780  if (maybeAddTxT(pXML, token.pStr)) return FALSE;
1781 
1782  // Find the name of the tag
1783  token = GetNextToken(pXML, &cbToken, &xtype);
1784 
1785  // Return an error if we couldn't obtain the next
1786  // token or
1787  // it wasnt text
1788  if (xtype != eTokenText)
1789  {
1791  return FALSE;
1792  }
1793 
1794  // If we found a new element which is the same as
1795  // this element then we need to pass this back to
1796  // the caller..
1797 
1798 #ifdef APPROXIMATE_PARSING
1799  if (d->lpszName &&
1800  myTagCompare(d->lpszName, token.pStr) == 0)
1801  {
1802  // Indicate to the caller that it needs to
1803  // create a
1804  // new element.
1805  pXML->lpNewElement = token.pStr;
1806  pXML->cbNewElement = cbToken;
1807  return TRUE;
1808  }
1809  else
1810 #endif
1811  {
1812  // If the name of the new element differs from
1813  // the name of
1814  // the current element we need to add the new
1815  // element to
1816  // the current one and recurse
1817  pNew = addChild_priv(
1819  stringDup(token.pStr, cbToken),
1820  nDeclaration, -1);
1821 
1822  while (!pNew.isEmpty())
1823  {
1824  // Callself to process the new node. If we
1825  // return
1826  // FALSE this means we dont have any more
1827  // processing to do...
1828 
1829  if (!pNew.ParseXMLElement(pXML))
1830  return FALSE;
1831  else
1832  {
1833  // If the call to recurse this function
1834  // evented in a end tag specified in XML
1835  // then
1836  // we need to unwind the calls to this
1837  // function until we find the
1838  // appropriate node
1839  // (the element name and end tag name
1840  // must
1841  // match)
1842  if (pXML->cbEndTag)
1843  {
1844  // If we are back at the root node
1845  // then we
1846  // have an unmatched end tag
1847  if (!d->lpszName)
1848  {
1849  pXML->error =
1851  return FALSE;
1852  }
1853 
1854  // If the end tag matches the name
1855  // of this
1856  // element then we only need to
1857  // unwind
1858  // once more...
1859 
1860  if (myTagCompare(
1861  d->lpszName,
1862  pXML->lpEndTag) == 0)
1863  {
1864  pXML->cbEndTag = 0;
1865  }
1866 
1867  return TRUE;
1868  }
1869  else if (pXML->cbNewElement)
1870  {
1871  // If the call indicated a new
1872  // element is to
1873  // be created on THIS element.
1874 
1875  // If the name of this element
1876  // matches the
1877  // name of the element we need to
1878  // create
1879  // then we need to return to the
1880  // caller
1881  // and let it process the element.
1882 
1883  if (myTagCompare(
1884  d->lpszName,
1885  pXML->lpNewElement) == 0)
1886  {
1887  return TRUE;
1888  }
1889 
1890  // Add the new element and recurse
1891  pNew = addChild_priv(
1893  stringDup(
1894  pXML->lpNewElement,
1895  pXML->cbNewElement),
1896  0, -1);
1897  pXML->cbNewElement = 0;
1898  }
1899  else
1900  {
1901  // If we didn't have a new element
1902  // to create
1903  pNew = emptyXMLNode;
1904  }
1905  }
1906  }
1907  }
1908  break;
1909 
1910  // If we found an end tag
1911  case eTokenTagEnd:
1912 
1913  // If we have node text then add this to the element
1914  if (maybeAddTxT(pXML, token.pStr)) return FALSE;
1915 
1916  // Find the name of the end tag
1917  token = GetNextToken(pXML, &cbTemp, &xtype);
1918 
1919  // The end tag should be text
1920  if (xtype != eTokenText)
1921  {
1923  return FALSE;
1924  }
1925  lpszTemp = token.pStr;
1926 
1927  // After the end tag we should find a closing tag
1928  token = GetNextToken(pXML, &cbToken, &xtype);
1929  if (xtype != eTokenCloseTag)
1930  {
1932  return FALSE;
1933  }
1934  pXML->lpszText = pXML->lpXML + pXML->nIndex;
1935 
1936  // We need to return to the previous caller. If the
1937  // name
1938  // of the tag cannot be found we need to keep
1939  // returning to
1940  // caller until we find a match
1941  if (myTagCompare(d->lpszName, lpszTemp) != 0)
1942 #ifdef STRICT_PARSING
1943  {
1945  pXML->nIndexMissigEndTag = pXML->nIndex;
1946  return FALSE;
1947  }
1948 #else
1949  {
1950  pXML->error = eXMLErrorMissingEndTag;
1951  pXML->nIndexMissigEndTag = pXML->nIndex;
1952  pXML->lpEndTag = lpszTemp;
1953  pXML->cbEndTag = cbTemp;
1954  }
1955 #endif
1956 
1957  // Return to the caller
1958  exactMemory(d);
1959  return TRUE;
1960 
1961  // If we found a clear (unformatted) token
1962  case eTokenClear:
1963  // If we have node text then add this to the element
1964  if (maybeAddTxT(pXML, token.pStr)) return FALSE;
1965  if (parseClearTag(pXML, token.pClr)) return FALSE;
1966  pXML->lpszText = pXML->lpXML + pXML->nIndex;
1967  break;
1968 
1969  default:
1970  break;
1971  }
1972  break;
1973 
1974  // If we are inside a tag definition we need to search for
1975  // attributes
1976  case eInsideTag:
1977 
1978  // Check what part of the attribute (name, equals, value) we
1979  // are looking for.
1980  switch (attrib)
1981  {
1982  // If we are looking for a new attribute
1983  case eAttribName:
1984 
1985  // Check what the current token type is
1986  switch (xtype)
1987  {
1988  // If the current type is text...
1989  // Eg. 'attribute'
1990  case eTokenText:
1991  // Cache the token then indicate that we are
1992  // next to
1993  // look for the equals
1994  lpszTemp = token.pStr;
1995  cbTemp = cbToken;
1996  attrib = eAttribEquals;
1997  break;
1998 
1999  // If we found a closing tag...
2000  // Eg. '>'
2001  case eTokenCloseTag:
2002  // We are now outside the tag
2003  status = eOutsideTag;
2004  pXML->lpszText = pXML->lpXML + pXML->nIndex;
2005  break;
2006 
2007  // If we found a short hand '/>' closing tag
2008  // then we can
2009  // return to the caller
2010  case eTokenShortHandClose:
2011  exactMemory(d);
2012  pXML->lpszText = pXML->lpXML + pXML->nIndex;
2013  return TRUE;
2014 
2015  // Errors...
2016  case eTokenQuotedText: /* '"SomeText"' */
2017  case eTokenTagStart: /* '<' */
2018  case eTokenTagEnd: /* '</' */
2019  case eTokenEquals: /* '=' */
2020  case eTokenDeclaration: /* '<?' */
2021  case eTokenClear:
2023  return FALSE;
2024  default:
2025  break;
2026  }
2027  break;
2028 
2029  // If we are looking for an equals
2030  case eAttribEquals:
2031  // Check what the current token type is
2032  switch (xtype)
2033  {
2034  // If the current type is text...
2035  // Eg. 'Attribute AnotherAttribute'
2036  case eTokenText:
2037  // Add the unvalued attribute to the list
2040  stringDup(lpszTemp, cbTemp), nullptr);
2041  // Cache the token then indicate. We are
2042  // next to
2043  // look for the equals attribute
2044  lpszTemp = token.pStr;
2045  cbTemp = cbToken;
2046  break;
2047 
2048  // If we found a closing tag 'Attribute >' or a
2049  // short hand
2050  // closing tag 'Attribute />'
2051  case eTokenShortHandClose:
2052  case eTokenCloseTag:
2053  // If we are a declaration element '<?' then
2054  // we need
2055  // to remove extra closing '?' if it exists
2056  pXML->lpszText = pXML->lpXML + pXML->nIndex;
2057 
2058  if (d->isDeclaration &&
2059  (lpszTemp[cbTemp - 1]) == _CXML('?'))
2060  {
2061  cbTemp--;
2062  if (d->pParent && d->pParent->pParent)
2063  xtype = eTokenShortHandClose;
2064  }
2065 
2066  if (cbTemp)
2067  {
2068  // Add the unvalued attribute to the
2069  // list
2072  stringDup(lpszTemp, cbTemp),
2073  nullptr);
2074  }
2075 
2076  // If this is the end of the tag then return
2077  // to the caller
2078  if (xtype == eTokenShortHandClose)
2079  {
2080  exactMemory(d);
2081  return TRUE;
2082  }
2083 
2084  // We are now outside the tag
2085  status = eOutsideTag;
2086  break;
2087 
2088  // If we found the equals token...
2089  // Eg. 'Attribute ='
2090  case eTokenEquals:
2091  // Indicate that we next need to search for
2092  // the value
2093  // for the attribute
2094  attrib = eAttribValue;
2095  break;
2096 
2097  // Errors...
2098  case eTokenQuotedText: /* 'Attribute
2099  "InvalidAttr"'*/
2100  case eTokenTagStart: /* 'Attribute <' */
2101  case eTokenTagEnd: /* 'Attribute </' */
2102  case eTokenDeclaration: /* 'Attribute <?' */
2103  case eTokenClear:
2105  return FALSE;
2106  default:
2107  break;
2108  }
2109  break;
2110 
2111  // If we are looking for an attribute value
2112  case eAttribValue:
2113  // Check what the current token type is
2114  switch (xtype)
2115  {
2116  // If the current type is text or quoted text...
2117  // Eg. 'Attribute = "Value"' or 'Attribute =
2118  // Value' or
2119  // 'Attribute = 'Value''.
2120  case eTokenText:
2121  case eTokenQuotedText:
2122  // If we are a declaration element '<?' then
2123  // we need
2124  // to remove extra closing '?' if it exists
2125  if (d->isDeclaration &&
2126  (token.pStr[cbToken - 1]) == _CXML('?'))
2127  {
2128  cbToken--;
2129  }
2130 
2131  if (cbTemp)
2132  {
2133  // Add the valued attribute to the list
2134  if (xtype == eTokenQuotedText)
2135  {
2136  token.pStr++;
2137  cbToken -= 2;
2138  }
2139  XMLSTR attrVal = (XMLSTR)token.pStr;
2140  if (attrVal)
2141  {
2142  attrVal = fromXMLString(
2143  attrVal, cbToken, pXML);
2144  if (!attrVal) return FALSE;
2145  }
2148  stringDup(lpszTemp, cbTemp),
2149  attrVal);
2150  }
2151 
2152  // Indicate we are searching for a new
2153  // attribute
2154  attrib = eAttribName;
2155  break;
2156 
2157  // Errors...
2158  case eTokenTagStart: /* 'Attr = <' */
2159  case eTokenTagEnd: /* 'Attr = </' */
2160  case eTokenCloseTag: /* 'Attr = >' */
2161  case eTokenShortHandClose: /* "Attr = />" */
2162  case eTokenEquals: /* 'Attr = =' */
2163  case eTokenDeclaration: /* 'Attr = <?' */
2164  case eTokenClear:
2166  return FALSE;
2167  break;
2168  default:
2169  break;
2170  }
2171  }
2172  }
2173  }
2174  // If we failed to obtain the next token
2175  else
2176  {
2177  if ((!d->isDeclaration) && (d->pParent))
2178  {
2179 #ifdef STRICT_PARSING
2181 #else
2182  pXML->error = eXMLErrorMissingEndTag;
2183 #endif
2184  pXML->nIndexMissigEndTag = pXML->nIndex;
2185  }
2186  maybeAddTxT(pXML, pXML->lpXML + pXML->nIndex);
2187  return FALSE;
2188  }
2189  }
2190 }
2191 
2192 // Count the number of lines and columns in an XML string.
2193 static void CountLinesAndColumns(XMLCSTR lpXML, int nUpto, XMLResults* pResults)
2194 {
2195  XMLCHAR ch;
2196  assert(lpXML);
2197  assert(pResults);
2198 
2199  struct XML xml = {lpXML, lpXML, 0, 0, eXMLErrorNone,
2200  nullptr, 0, nullptr, 0, TRUE};
2201 
2202  pResults->nLine = 1;
2203  pResults->nColumn = 1;
2204  while (xml.nIndex < nUpto)
2205  {
2206  ch = getNextChar(&xml);
2207  if (ch != _CXML('\n'))
2208  pResults->nColumn++;
2209  else
2210  {
2211  pResults->nLine++;
2212  pResults->nColumn = 1;
2213  }
2214  }
2215 }
2216 
2217 // Parse XML and return the root element.
2219 {
2220  if (!lpszXML)
2221  {
2222  if (pResults)
2223  {
2224  pResults->error = eXMLErrorNoElements;
2225  pResults->nLine = 0;
2226  pResults->nColumn = 0;
2227  }
2228  return emptyXMLNode;
2229  }
2230 
2231  XMLNode xnode(nullptr, nullptr, FALSE);
2232  struct XML xml = {lpszXML, lpszXML, 0, 0, eXMLErrorNone,
2233  nullptr, 0, nullptr, 0, TRUE};
2234 
2235  // Create header element
2236  xnode.ParseXMLElement(&xml);
2237  enum XMLError error = xml.error;
2238  if (!xnode.nChildNode()) error = eXMLErrorNoXMLTagFound;
2239  if ((xnode.nChildNode() == 1) && (xnode.nElement() == 1))
2240  xnode = xnode.getChildNode(); // skip the empty node
2241 
2242  // If no error occurred
2243  if ((error == eXMLErrorNone) || (error == eXMLErrorMissingEndTag) ||
2245  {
2246  XMLCSTR name = xnode.getName();
2247  if (tag && (*tag) && ((!name) || (xstricmp(name, tag))))
2248  {
2249  xnode = xnode.getChildNode(tag);
2250  if (xnode.isEmpty())
2251  {
2252  if (pResults)
2253  {
2254  pResults->error = eXMLErrorFirstTagNotFound;
2255  pResults->nLine = 0;
2256  pResults->nColumn = 0;
2257  }
2258  return emptyXMLNode;
2259  }
2260  }
2261  }
2262  else
2263  {
2264  // Cleanup: this will destroy all the nodes
2265  xnode = emptyXMLNode;
2266  }
2267 
2268  // If we have been given somewhere to place results
2269  if (pResults)
2270  {
2271  pResults->error = error;
2272 
2273  // If we have an error
2274  if (error != eXMLErrorNone)
2275  {
2277  xml.nIndex = xml.nIndexMissigEndTag;
2278  // Find which line and column it starts on.
2279  CountLinesAndColumns(xml.lpXML, xml.nIndex, pResults);
2280  }
2281  }
2282  return xnode;
2283 }
2284 
2286 {
2287  if (pResults)
2288  {
2289  pResults->nLine = 0;
2290  pResults->nColumn = 0;
2291  }
2292  FILE* f = xfopen(filename, _CXML("rb"));
2293  if (f == nullptr)
2294  {
2295  if (pResults) pResults->error = eXMLErrorFileNotFound;
2296  return emptyXMLNode;
2297  }
2298  fseek(f, 0, SEEK_END);
2299  int l = ftell(f), headerSz = 0;
2300  if (!l)
2301  {
2302  if (pResults) pResults->error = eXMLErrorEmpty;
2303  fclose(f);
2304  return emptyXMLNode;
2305  }
2306  fseek(f, 0, SEEK_SET);
2307  auto* buf = (unsigned char*)malloc(l + 4);
2308  int really_read = (int)fread(buf, 1, l, f); // JLBC
2309  if (really_read != l) buf[0] = '\0';
2310  fclose(f);
2311  buf[l] = 0;
2312  buf[l + 1] = 0;
2313  buf[l + 2] = 0;
2314  buf[l + 3] = 0;
2315 #ifdef _XMLWIDECHAR
2316  if (guessWideCharChars)
2317  {
2318  if (!myIsTextWideChar(buf, l))
2319  {
2321  if ((buf[0] == 0xef) && (buf[1] == 0xbb) && (buf[2] == 0xbf))
2322  {
2323  headerSz = 3;
2325  }
2326  XMLSTR b2 =
2327  myMultiByteToWideChar((const char*)(buf + headerSz), ce);
2328  free(buf);
2329  buf = (unsigned char*)b2;
2330  headerSz = 0;
2331  }
2332  else
2333  {
2334  if ((buf[0] == 0xef) && (buf[1] == 0xff)) headerSz = 2;
2335  if ((buf[0] == 0xff) && (buf[1] == 0xfe)) headerSz = 2;
2336  }
2337  }
2338 #else
2339  if (guessWideCharChars)
2340  {
2341  if (myIsTextWideChar(buf, l))
2342  {
2343  if ((buf[0] == 0xef) && (buf[1] == 0xff)) headerSz = 2;
2344  if ((buf[0] == 0xff) && (buf[1] == 0xfe)) headerSz = 2;
2345  char* b2 = myWideCharToMultiByte((const wchar_t*)(buf + headerSz));
2346  free(buf);
2347  buf = (unsigned char*)b2;
2348  headerSz = 0;
2349  }
2350  else
2351  {
2352  if ((buf[0] == 0xef) && (buf[1] == 0xbb) && (buf[2] == 0xbf))
2353  headerSz = 3;
2354  }
2355  }
2356 #endif
2357 
2358  if (!buf)
2359  {
2360  if (pResults) pResults->error = eXMLErrorCharConversionError;
2361  return emptyXMLNode;
2362  }
2363  XMLNode x = parseString((XMLSTR)(buf + headerSz), tag, pResults);
2364  free(buf);
2365  return x;
2366 }
2367 
2368 static inline void charmemset(XMLSTR dest, XMLCHAR c, int l)
2369 {
2370  while (l--) *(dest++) = c;
2371 }
2372 // private:
2373 // Creates an user friendly XML string from a given element with
2374 // appropriate white space and carriage returns.
2375 //
2376 // This recurses through all subnodes then adds contents of the nodes to the
2377 // string.
2379  XMLNodeData* pEntry, XMLSTR lpszMarker, int nFormat)
2380 {
2381  int nResult = 0;
2382  int cb = nFormat < 0 ? 0 : nFormat;
2383  int cbElement;
2384  int nChildFormat = -1;
2385  int nElementI = pEntry->nChild + pEntry->nText + pEntry->nClear;
2386  int i, j;
2387  if ((nFormat >= 0) && (nElementI == 1) && (pEntry->nText == 1) &&
2388  (!pEntry->isDeclaration))
2389  nFormat = -2;
2390 
2391  assert(pEntry);
2392 
2393 #define LENSTR(lpsz) (lpsz ? xstrlen(lpsz) : 0)
2394 
2395  // If the element has no name then assume this is the head node.
2396  cbElement = (int)LENSTR(pEntry->lpszName);
2397 
2398  if (cbElement)
2399  {
2400  // "<elementname "
2401  if (lpszMarker)
2402  {
2403  if (cb) charmemset(lpszMarker, INDENTCHAR, cb);
2404  nResult = cb;
2405  lpszMarker[nResult++] = _CXML('<');
2406  if (pEntry->isDeclaration) lpszMarker[nResult++] = _CXML('?');
2407  xstrcpy(&lpszMarker[nResult], pEntry->lpszName);
2408  nResult += cbElement;
2409  lpszMarker[nResult++] = _CXML(' ');
2410  }
2411  else
2412  {
2413  nResult += cbElement + 2 + cb;
2414  if (pEntry->isDeclaration) nResult++;
2415  }
2416 
2417  // Enumerate attributes and add them to the string
2418  XMLAttribute* pAttr = pEntry->pAttribute;
2419  for (i = 0; i < pEntry->nAttribute; i++)
2420  {
2421  // "Attrib
2422  cb = (int)LENSTR(pAttr->lpszName);
2423  if (cb)
2424  {
2425  if (lpszMarker) xstrcpy(&lpszMarker[nResult], pAttr->lpszName);
2426  nResult += cb;
2427  // "Attrib=Value "
2428  if (pAttr->lpszValue)
2429  {
2430  cb =
2432  if (lpszMarker)
2433  {
2434  lpszMarker[nResult] = _CXML('=');
2435  lpszMarker[nResult + 1] = _CXML('"');
2436  if (cb)
2438  &lpszMarker[nResult + 2], pAttr->lpszValue);
2439  lpszMarker[nResult + cb + 2] = _CXML('"');
2440  }
2441  nResult += cb + 3;
2442  }
2443  if (lpszMarker) lpszMarker[nResult] = _CXML(' ');
2444  nResult++;
2445  }
2446  pAttr++;
2447  }
2448 
2449  if (pEntry->isDeclaration)
2450  {
2451  if (lpszMarker)
2452  {
2453  lpszMarker[nResult - 1] = _CXML('?');
2454  lpszMarker[nResult] = _CXML('>');
2455  }
2456  nResult++;
2457  if (nFormat != -1)
2458  {
2459  if (lpszMarker) lpszMarker[nResult] = _CXML('\n');
2460  nResult++;
2461  }
2462  }
2463  else
2464  // If there are child nodes we need to terminate the start tag
2465  if (nElementI)
2466  {
2467  if (lpszMarker) lpszMarker[nResult - 1] = _CXML('>');
2468  if (nFormat >= 0)
2469  {
2470  if (lpszMarker) lpszMarker[nResult] = _CXML('\n');
2471  nResult++;
2472  }
2473  }
2474  else
2475  nResult--;
2476  }
2477 
2478  // Calculate the child format for when we recurse. This is used to
2479  // determine the number of spaces used for prefixes.
2480  if (nFormat != -1)
2481  {
2482  if (cbElement && (!pEntry->isDeclaration))
2483  nChildFormat = nFormat + 1;
2484  else
2485  nChildFormat = nFormat;
2486  }
2487 
2488  // Enumerate through remaining children
2489  for (i = 0; i < nElementI; i++)
2490  {
2491  j = pEntry->pOrder[i];
2492  switch ((XMLElementType)(j & 3))
2493  {
2494  // Text nodes
2495  case eNodeText:
2496  {
2497  // "Text"
2498  XMLCSTR pChild = pEntry->pText[j >> 2];
2499  cb = (int)ToXMLStringTool::lengthXMLString(pChild);
2500  if (cb)
2501  {
2502  if (nFormat >= 0)
2503  {
2504  if (lpszMarker)
2505  {
2506  charmemset(
2507  &lpszMarker[nResult], INDENTCHAR, nFormat + 1);
2509  &lpszMarker[nResult + nFormat + 1], pChild);
2510  lpszMarker[nResult + nFormat + 1 + cb] =
2511  _CXML('\n');
2512  }
2513  nResult += cb + nFormat + 2;
2514  }
2515  else
2516  {
2517  if (lpszMarker)
2519  &lpszMarker[nResult], pChild);
2520  nResult += cb;
2521  }
2522  }
2523  break;
2524  }
2525 
2526  // Clear type nodes
2527  case eNodeClear:
2528  {
2529  XMLClear* pChild = pEntry->pClear + (j >> 2);
2530  // "OpenTag"
2531  cb = (int)LENSTR(pChild->lpszOpenTag);
2532  if (cb)
2533  {
2534  if (nFormat != -1)
2535  {
2536  if (lpszMarker)
2537  {
2538  charmemset(
2539  &lpszMarker[nResult], INDENTCHAR, nFormat + 1);
2540  xstrcpy(
2541  &lpszMarker[nResult + nFormat + 1],
2542  pChild->lpszOpenTag);
2543  }
2544  nResult += cb + nFormat + 1;
2545  }
2546  else
2547  {
2548  if (lpszMarker)
2549  xstrcpy(&lpszMarker[nResult], pChild->lpszOpenTag);
2550  nResult += cb;
2551  }
2552  }
2553 
2554  // "OpenTag Value"
2555  cb = (int)LENSTR(pChild->lpszValue);
2556  if (cb)
2557  {
2558  if (lpszMarker)
2559  xstrcpy(&lpszMarker[nResult], pChild->lpszValue);
2560  nResult += cb;
2561  }
2562 
2563  // "OpenTag Value CloseTag"
2564  cb = (int)LENSTR(pChild->lpszCloseTag);
2565  if (cb)
2566  {
2567  if (lpszMarker)
2568  xstrcpy(&lpszMarker[nResult], pChild->lpszCloseTag);
2569  nResult += cb;
2570  }
2571 
2572  if (nFormat != -1)
2573  {
2574  if (lpszMarker) lpszMarker[nResult] = _CXML('\n');
2575  nResult++;
2576  }
2577  break;
2578  }
2579 
2580  // Element nodes
2581  case eNodeChild:
2582  {
2583  // Recursively add child nodes
2584  nResult += CreateXMLStringR(
2585  pEntry->pChild[j >> 2].d,
2586  lpszMarker ? lpszMarker + nResult : nullptr, nChildFormat);
2587  break;
2588  }
2589  default:
2590  break;
2591  }
2592  }
2593 
2594  if ((cbElement) && (!pEntry->isDeclaration))
2595  {
2596  // If we have child entries we need to use long XML notation for
2597  // closing the element - "<elementname>blah blah blah</elementname>"
2598  if (nElementI)
2599  {
2600  // "</elementname>\0"
2601  if (lpszMarker)
2602  {
2603  if (nFormat >= 0)
2604  {
2605  charmemset(&lpszMarker[nResult], INDENTCHAR, nFormat);
2606  nResult += nFormat;
2607  }
2608 
2609  lpszMarker[nResult] = _CXML('<');
2610  lpszMarker[nResult + 1] = _CXML('/');
2611  nResult += 2;
2612  xstrcpy(&lpszMarker[nResult], pEntry->lpszName);
2613  nResult += cbElement;
2614 
2615  lpszMarker[nResult] = _CXML('>');
2616  if (nFormat == -1)
2617  nResult++;
2618  else
2619  {
2620  lpszMarker[nResult + 1] = _CXML('\n');
2621  nResult += 2;
2622  }
2623  }
2624  else
2625  {
2626  if (nFormat >= 0)
2627  nResult += cbElement + 4 + nFormat;
2628  else if (nFormat == -1)
2629  nResult += cbElement + 3;
2630  else
2631  nResult += cbElement + 4;
2632  }
2633  }
2634  else
2635  {
2636  // If there are no children we can use shorthand XML notation -
2637  // "<elementname/>"
2638  // "/>\0"
2639  if (lpszMarker)
2640  {
2641  lpszMarker[nResult] = _CXML('/');
2642  lpszMarker[nResult + 1] = _CXML('>');
2643  if (nFormat != -1) lpszMarker[nResult + 2] = _CXML('\n');
2644  }
2645  nResult += nFormat == -1 ? 2 : 3;
2646  }
2647  }
2648 
2649  return nResult;
2650 }
2651 
2652 #undef LENSTR
2653 
2654 // Create an XML string
2655 // @param int nFormat - 0 if no formatting is required
2656 // otherwise nonzero for formatted text
2657 // with carriage returns and indentation.
2658 // @param int *pnSize - [out] pointer to the size of the
2659 // returned string not including the
2660 // nullptr terminator.
2661 // @return XMLSTR - Allocated XML string, you must free
2662 // this with free().
2663 XMLSTR XMLNode::createXMLString(int nFormat, int* pnSize) const
2664 {
2665  if (!d)
2666  {
2667  if (pnSize) *pnSize = 0;
2668  return nullptr;
2669  }
2670 
2671  XMLSTR lpszResult = nullptr;
2672  int cbStr;
2673 
2674  // Recursively Calculate the size of the XML string
2675  if (!dropWhiteSpace) nFormat = 0;
2676  nFormat = nFormat ? 0 : -1;
2677  cbStr = CreateXMLStringR(d, nullptr, nFormat);
2678  // Alllocate memory for the XML string + the nullptr terminator and
2679  // create the recursively XML string.
2680  lpszResult = (XMLSTR)malloc((cbStr + 1) * sizeof(XMLCHAR));
2681  CreateXMLStringR(d, lpszResult, nFormat);
2682  lpszResult[cbStr] = _CXML('\0');
2683  if (pnSize) *pnSize = cbStr;
2684  return lpszResult;
2685 }
2686 
2688 {
2689  XMLNode* pa = d->pParent->pChild;
2690  int i = 0;
2691  while (((void*)(pa[i].d)) != ((void*)d)) i++;
2692  d->pParent->nChild--;
2693  if (d->pParent->nChild)
2694  memmove(pa + i, pa + i + 1, (d->pParent->nChild - i) * sizeof(XMLNode));
2695  else
2696  {
2697  free(pa);
2698  d->pParent->pChild = nullptr;
2699  }
2700  return removeOrderElement(d->pParent, eNodeChild, i);
2701 }
2702 
2704 {
2705  if (!d) return;
2706  d->ref_count--;
2707  emptyTheNode(0);
2708 }
2710 {
2711  if (!d) return;
2712  if (d->pParent)
2713  {
2715  d->pParent = nullptr;
2716  d->ref_count--;
2717  }
2718  emptyTheNode(1);
2719 }
2720 void XMLNode::emptyTheNode(char force)
2721 {
2722  XMLNodeData* dd = d; // warning: must stay this way!
2723  if ((dd->ref_count == 0) || force)
2724  {
2725  if (d->pParent) detachFromParent(d);
2726  int i;
2727  XMLNode* pc;
2728  for (i = 0; i < dd->nChild; i++)
2729  {
2730  pc = dd->pChild + i;
2731  pc->d->pParent = nullptr;
2732  pc->d->ref_count--;
2733  pc->emptyTheNode(force);
2734  }
2735  myFree(dd->pChild);
2736  for (i = 0; i < dd->nText; i++) free((void*)dd->pText[i]);
2737  myFree(dd->pText);
2738  for (i = 0; i < dd->nClear; i++) free((void*)dd->pClear[i].lpszValue);
2739  myFree(dd->pClear);
2740  for (i = 0; i < dd->nAttribute; i++)
2741  {
2742  free((void*)dd->pAttribute[i].lpszName);
2743  if (dd->pAttribute[i].lpszValue)
2744  free((void*)dd->pAttribute[i].lpszValue);
2745  }
2746  myFree(dd->pAttribute);
2747  myFree(dd->pOrder);
2748  myFree((void*)dd->lpszName);
2749  dd->nChild = 0;
2750  dd->nText = 0;
2751  dd->nClear = 0;
2752  dd->nAttribute = 0;
2753  dd->pChild = nullptr;
2754  dd->pText = nullptr;
2755  dd->pClear = nullptr;
2756  dd->pAttribute = nullptr;
2757  dd->pOrder = nullptr;
2758  dd->lpszName = nullptr;
2759  dd->pParent = nullptr;
2760  }
2761  if (dd->ref_count == 0)
2762  {
2763  free(dd);
2764  d = nullptr;
2765  }
2766 }
2767 
2769 {
2770  // shallow copy
2771  if (this != &A)
2772  {
2773  if (d)
2774  {
2775  d->ref_count--;
2776  emptyTheNode(0);
2777  }
2778  d = A.d;
2779  if (d) (d->ref_count)++;
2780  }
2781  return *this;
2782 }
2783 
2785 {
2786  // shallow copy
2787  d = A.d;
2788  if (d) (d->ref_count)++;
2789 }
2790 
2792 {
2793  if (!d) return XMLNode::emptyXMLNode;
2794  XMLNode x(nullptr, stringDup(d->lpszName), d->isDeclaration);
2795  XMLNodeData* p = x.d;
2796  int n = d->nAttribute;
2797  if (n)
2798  {
2799  p->nAttribute = n;
2800  p->pAttribute = (XMLAttribute*)malloc(n * sizeof(XMLAttribute));
2801  while (n--)
2802  {
2803  p->pAttribute[n].lpszName = stringDup(d->pAttribute[n].lpszName);
2804  p->pAttribute[n].lpszValue = stringDup(d->pAttribute[n].lpszValue);
2805  }
2806  }
2807  if (d->pOrder)
2808  {
2809  n = (d->nChild + d->nText + d->nClear) * sizeof(int);
2810  p->pOrder = (int*)malloc(n);
2811  memcpy(p->pOrder, d->pOrder, n);
2812  }
2813  n = d->nText;
2814  if (n)
2815  {
2816  p->nText = n;
2817  p->pText = (XMLCSTR*)malloc(n * sizeof(XMLCSTR));
2818  while (n--) p->pText[n] = stringDup(d->pText[n]);
2819  }
2820  n = d->nClear;
2821  if (n)
2822  {
2823  p->nClear = n;
2824  p->pClear = (XMLClear*)malloc(n * sizeof(XMLClear));
2825  while (n--)
2826  {
2827  p->pClear[n].lpszCloseTag = d->pClear[n].lpszCloseTag;
2828  p->pClear[n].lpszOpenTag = d->pClear[n].lpszOpenTag;
2829  p->pClear[n].lpszValue = stringDup(d->pClear[n].lpszValue);
2830  }
2831  }
2832  n = d->nChild;
2833  if (n)
2834  {
2835  p->nChild = n;
2836  p->pChild = (XMLNode*)malloc(n * sizeof(XMLNode));
2837  while (n--)
2838  {
2839  p->pChild[n].d = nullptr;
2840  p->pChild[n] = d->pChild[n].deepCopy();
2841  p->pChild[n].d->pParent = p;
2842  }
2843  }
2844  return x;
2845 }
2846 
2847 XMLNode XMLNode::addChild(XMLNode childNode, int pos)
2848 {
2849  XMLNodeData* dc = childNode.d;
2850  if ((!dc) || (!d)) return childNode;
2851  if (!dc->lpszName)
2852  {
2853  // this is a root node: todo: correct fix
2854  int j = pos;
2855  while (dc->nChild)
2856  {
2857  addChild(dc->pChild[0], j);
2858  if (pos >= 0) j++;
2859  }
2860  return childNode;
2861  }
2862  if (dc->pParent)
2863  {
2864  if ((detachFromParent(dc) <= pos) && (dc->pParent == d)) pos--;
2865  }
2866  else
2867  dc->ref_count++;
2868  dc->pParent = d;
2869  // int nc=d->nChild;
2870  // d->pChild=(XMLNode*)myRealloc(d->pChild,(nc+1),memoryIncrease,sizeof(XMLNode));
2871  d->pChild = (XMLNode*)addToOrder(
2872  0, &pos, d->nChild, d->pChild, sizeof(XMLNode), eNodeChild);
2873  d->pChild[pos].d = dc;
2874  d->nChild++;
2875  return childNode;
2876 }
2877 
2879 {
2880  if ((!d) || (i < 0) || (i >= d->nAttribute)) return;
2881  d->nAttribute--;
2882  XMLAttribute* p = d->pAttribute + i;
2883  free((void*)p->lpszName);
2884  if (p->lpszValue) free((void*)p->lpszValue);
2885  if (d->nAttribute)
2886  memmove(p, p + 1, (d->nAttribute - i) * sizeof(XMLAttribute));
2887  else
2888  {
2889  free(p);
2890  d->pAttribute = nullptr;
2891  }
2892 }
2893 
2895 {
2896  if (a) deleteAttribute(a->lpszName);
2897 }
2899 {
2900  int j = 0;
2901  getAttribute(lpszName, &j);
2902  if (j) deleteAttribute(j - 1);
2903 }
2904 
2906  XMLSTR lpszNewValue, XMLSTR lpszNewName, int i)
2907 {
2908  if (!d)
2909  {
2910  if (lpszNewValue) free(lpszNewValue);
2911  if (lpszNewName) free(lpszNewName);
2912  return nullptr;
2913  }
2914  if (i >= d->nAttribute)
2915  {
2916  if (lpszNewName) return addAttribute_WOSD(lpszNewName, lpszNewValue);
2917  return nullptr;
2918  }
2919  XMLAttribute* p = d->pAttribute + i;
2920  if (p->lpszValue && p->lpszValue != lpszNewValue) free((void*)p->lpszValue);
2921  p->lpszValue = lpszNewValue;
2922  if (lpszNewName && p->lpszName != lpszNewName)
2923  {
2924  free((void*)p->lpszName);
2925  p->lpszName = lpszNewName;
2926  };
2927  return p;
2928 }
2929 
2931  XMLAttribute* newAttribute, XMLAttribute* oldAttribute)
2932 {
2933  if (oldAttribute)
2934  return updateAttribute_WOSD(
2935  (XMLSTR)newAttribute->lpszValue, (XMLSTR)newAttribute->lpszName,
2936  oldAttribute->lpszName);
2937  return addAttribute_WOSD(
2938  (XMLSTR)newAttribute->lpszName, (XMLSTR)newAttribute->lpszValue);
2939 }
2940 
2942  XMLSTR lpszNewValue, XMLSTR lpszNewName, XMLCSTR lpszOldName)
2943 {
2944  int j = 0;
2945  getAttribute(lpszOldName, &j);
2946  if (j)
2947  return updateAttribute_WOSD(lpszNewValue, lpszNewName, j - 1);
2948  else
2949  {
2950  if (lpszNewName)
2951  return addAttribute_WOSD(lpszNewName, lpszNewValue);
2952  else
2953  return addAttribute_WOSD(stringDup(lpszOldName), lpszNewValue);
2954  }
2955 }
2956 
2957 int XMLNode::indexText(XMLCSTR lpszValue) const
2958 {
2959  if (!d) return -1;
2960  int i, l = d->nText;
2961  if (!lpszValue)
2962  {
2963  if (l) return 0;
2964  return -1;
2965  }
2966  XMLCSTR* p = d->pText;
2967  for (i = 0; i < l; i++)
2968  if (lpszValue == p[i]) return i;
2969  return -1;
2970 }
2971 
2973 {
2974  if ((!d) || (i < 0) || (i >= d->nText)) return;
2975  d->nText--;
2976  XMLCSTR* p = d->pText + i;
2977  free((void*)*p);
2978  if (d->nText)
2979  memmove(p, p + 1, (d->nText - i) * sizeof(XMLCSTR));
2980  else
2981  {
2982  free(p);
2983  d->pText = nullptr;
2984  }
2986 }
2987 
2989 {
2990  deleteText(indexText(lpszValue));
2991 }
2992 
2994 {
2995  if (!d)
2996  {
2997  if (lpszNewValue) free(lpszNewValue);
2998  return nullptr;
2999  }
3000  if (i >= d->nText) return addText_WOSD(lpszNewValue);
3001  XMLCSTR* p = d->pText + i;
3002  if (*p != lpszNewValue)
3003  {
3004  free((void*)*p);
3005  *p = lpszNewValue;
3006  }
3007  return lpszNewValue;
3008 }
3009 
3010 XMLCSTR XMLNode::updateText_WOSD(XMLSTR lpszNewValue, XMLCSTR lpszOldValue)
3011 {
3012  if (!d)
3013  {
3014  if (lpszNewValue) free(lpszNewValue);
3015  return nullptr;
3016  }
3017  int i = indexText(lpszOldValue);
3018  if (i >= 0) return updateText_WOSD(lpszNewValue, i);
3019  return addText_WOSD(lpszNewValue);
3020 }
3021 
3023 {
3024  if ((!d) || (i < 0) || (i >= d->nClear)) return;
3025  d->nClear--;
3026  XMLClear* p = d->pClear + i;
3027  free((void*)p->lpszValue);
3028  if (d->nClear)
3029  memmove(p, p + 1, (d->nClear - i) * sizeof(XMLClear));
3030  else
3031  {
3032  free(p);
3033  d->pClear = nullptr;
3034  }
3036 }
3037 
3038 int XMLNode::indexClear(XMLCSTR lpszValue) const
3039 {
3040  if (!d) return -1;
3041  int i, l = d->nClear;
3042  if (!lpszValue)
3043  {
3044  if (l) return 0;
3045  return -1;
3046  }
3047  XMLClear* p = d->pClear;
3048  for (i = 0; i < l; i++)
3049  if (lpszValue == p[i].lpszValue) return i;
3050  return -1;
3051 }
3052 
3054 {
3055  deleteClear(indexClear(lpszValue));
3056 }
3058 {
3059  if (a) deleteClear(a->lpszValue);
3060 }
3061 
3063 {
3064  if (!d)
3065  {
3066  if (lpszNewContent) free(lpszNewContent);
3067  return nullptr;
3068  }
3069  if (i >= d->nClear) return addClear_WOSD(lpszNewContent);
3070  XMLClear* p = d->pClear + i;
3071  if (lpszNewContent != p->lpszValue)
3072  {
3073  free((void*)p->lpszValue);
3074  p->lpszValue = lpszNewContent;
3075  }
3076  return p;
3077 }
3078 
3079 XMLClear* XMLNode::updateClear_WOSD(XMLSTR lpszNewContent, XMLCSTR lpszOldValue)
3080 {
3081  if (!d)
3082  {
3083  if (lpszNewContent) free(lpszNewContent);
3084  return nullptr;
3085  }
3086  int i = indexClear(lpszOldValue);
3087  if (i >= 0) return updateClear_WOSD(lpszNewContent, i);
3088  return addClear_WOSD(lpszNewContent);
3089 }
3090 
3092 {
3093  if (oldP)
3094  return updateClear_WOSD(
3095  (XMLSTR)newP->lpszValue, (XMLSTR)oldP->lpszValue);
3096  return nullptr;
3097 }
3098 
3100 {
3101  if (!d) return 0;
3102  int i, j = 0, n = d->nChild;
3103  XMLNode* pc = d->pChild;
3104  for (i = 0; i < n; i++)
3105  {
3106  if (xstricmp(pc->d->lpszName, name) == 0) j++;
3107  pc++;
3108  }
3109  return j;
3110 }
3111 
3113 {
3114  if (!d) return emptyXMLNode;
3115  int i = 0, n = d->nChild;
3116  if (j) i = *j;
3117  XMLNode* pc = d->pChild + i;
3118  for (; i < n; i++)
3119  {
3120  if (!xstricmp(pc->d->lpszName, name))
3121  {
3122  if (j) *j = i + 1;
3123  return *pc;
3124  }
3125  pc++;
3126  }
3127  return emptyXMLNode;
3128 }
3129 
3131 {
3132  if (!d) return emptyXMLNode;
3133  if (j >= 0)
3134  {
3135  int i = 0;
3136  while (j-- > 0) getChildNode(name, &i);
3137  return getChildNode(name, &i);
3138  }
3139  int i = d->nChild;
3140  while (i--)
3141  if (!xstricmp(name, d->pChild[i].d->lpszName)) break;
3142  if (i < 0) return emptyXMLNode;
3143  return getChildNode(i);
3144 }
3145 
3147  XMLCSTR _path, char createMissing, XMLCHAR sep)
3148 {
3149  XMLSTR path = stringDup(_path);
3150  XMLNode x = getChildNodeByPath(path, createMissing, sep);
3151  if (path) free(path);
3152  return x;
3153 }
3154 
3156  XMLSTR path, char createIfMissing, XMLCHAR sep)
3157 {
3158  if ((!path) || (!(*path))) return *this;
3159  XMLNode xn, xbase = *this;
3160  XMLCHAR *tend1, sepString[2];
3161  sepString[0] = sep;
3162  sepString[1] = 0;
3163  tend1 = xstrstr(path, sepString);
3164  while (tend1)
3165  {
3166  *tend1 = 0;
3167  xn = xbase.getChildNode(path);
3168  if (xn.isEmpty())
3169  {
3170  if (createIfMissing)
3171  xn = xbase.addChild(path);
3172  else
3173  return XMLNode::emptyXMLNode;
3174  }
3175  xbase = xn;
3176  path = tend1 + 1;
3177  tend1 = xstrstr(path, sepString);
3178  }
3179  xn = xbase.getChildNode(path);
3180  if (xn.isEmpty() && createIfMissing) xn = xbase.addChild(path);
3181  return xn;
3182 }
3183 
3185 {
3186  if (i >= d->nText) i = d->nText - 1;
3187  return findPosition(d, i, eNodeText);
3188 }
3190 {
3191  if (i >= d->nClear) i = d->nClear - 1;
3192  return findPosition(d, i, eNodeClear);
3193 }
3195 {
3196  if (i >= d->nChild) i = d->nChild - 1;
3197  return findPosition(d, i, eNodeChild);
3198 }
3200 {
3201  return positionOfText(indexText(lpszValue));
3202 }
3204 {
3205  return positionOfClear(indexClear(lpszValue));
3206 }
3208 {
3209  if (a) return positionOfClear(a->lpszValue);
3210  return positionOfClear();
3211 }
3213 {
3214  if ((!d) || (!x.d)) return -1;
3215  XMLNodeData* dd = x.d;
3216  XMLNode* pc = d->pChild;
3217  int i = d->nChild;
3218  while (i--)
3219  if (pc[i].d == dd) return findPosition(d, i, eNodeChild);
3220  return -1;
3221 }
3223 {
3224  if (!name) return positionOfChildNode(count);
3225  int j = 0;
3226  do
3227  {
3228  getChildNode(name, &j);
3229  if (j < 0) return -1;
3230  } while (count--);
3231  return findPosition(d, j - 1, eNodeChild);
3232 }
3233 
3235  XMLCSTR name, XMLCSTR attributeName, XMLCSTR attributeValue, int* k) const
3236 {
3237  int i = 0, j;
3238  if (k) i = *k;
3239  XMLNode x;
3240  XMLCSTR t;
3241  do
3242  {
3243  x = getChildNode(name, &i);
3244  if (!x.isEmpty())
3245  {
3246  if (attributeValue)
3247  {
3248  j = 0;
3249  do
3250  {
3251  t = x.getAttribute(attributeName, &j);
3252  if (t && (xstricmp(attributeValue, t) == 0))
3253  {
3254  if (k) *k = i;
3255  return x;
3256  }
3257  } while (t);
3258  }
3259  else
3260  {
3261  if (x.isAttributeSet(attributeName))
3262  {
3263  if (k) *k = i;
3264  return x;
3265  }
3266  }
3267  }
3268  } while (!x.isEmpty());
3269  return emptyXMLNode;
3270 }
3271 
3272 // Find an attribute on an node.
3273 XMLCSTR XMLNode::getAttribute(XMLCSTR lpszAttrib, int* j) const
3274 {
3275  if (!d) return nullptr;
3276  int i = 0, n = d->nAttribute;
3277  if (j) i = *j;
3278  XMLAttribute* pAttr = d->pAttribute + i;
3279  for (; i < n; i++)
3280  {
3281  if (xstricmp(pAttr->lpszName, lpszAttrib) == 0)
3282  {
3283  if (j) *j = i + 1;
3284  return pAttr->lpszValue;
3285  }
3286  pAttr++;
3287  }
3288  return nullptr;
3289 }
3290 
3291 char XMLNode::isAttributeSet(XMLCSTR lpszAttrib) const
3292 {
3293  if (!d) return FALSE;
3294  int i, n = d->nAttribute;
3295  XMLAttribute* pAttr = d->pAttribute;
3296  for (i = 0; i < n; i++)
3297  {
3298  if (xstricmp(pAttr->lpszName, lpszAttrib) == 0)
3299  {
3300  return TRUE;
3301  }
3302  pAttr++;
3303  }
3304  return FALSE;
3305 }
3306 
3308 {
3309  if (!d) return nullptr;
3310  int i = 0;
3311  while (j-- > 0) getAttribute(name, &i);
3312  return getAttribute(name, &i);
3313 }
3314 
3316 {
3318  if (!d)
3319  {
3320  c.etype = eNodeNULL;
3321  return c;
3322  }
3323  if (i < d->nAttribute)
3324  {
3325  c.etype = eNodeAttribute;
3326  c.attrib = d->pAttribute[i];
3327  return c;
3328  }
3329  i -= d->nAttribute;
3330  c.etype = (XMLElementType)(d->pOrder[i] & 3);
3331  i = (d->pOrder[i]) >> 2;
3332  switch (c.etype)
3333  {
3334  case eNodeChild:
3335  c.child = d->pChild[i];
3336  break;
3337  case eNodeText:
3338  c.text = d->pText[i];
3339  break;
3340  case eNodeClear:
3341  c.clear = d->pClear[i];
3342  break;
3343  default:
3344  break;
3345  }
3346  return c;
3347 }
3348 
3350 {
3351  if (!d) return nullptr;
3352  return d->lpszName;
3353 }
3354 int XMLNode::nText() const
3355 {
3356  if (!d) return 0;
3357  return d->nText;
3358 }
3360 {
3361  if (!d) return 0;
3362  return d->nChild;
3363 }
3365 {
3366  if (!d) return 0;
3367  return d->nAttribute;
3368 }
3369 int XMLNode::nClear() const
3370 {
3371  if (!d) return 0;
3372  return d->nClear;
3373 }
3375 {
3376  if (!d) return 0;
3377  return d->nAttribute + d->nChild + d->nText + d->nClear;
3378 }
3380 {
3381  if ((!d) || (i >= d->nClear)) return emptyXMLClear;
3382  return d->pClear[i];
3383 }
3385 {
3386  if ((!d) || (i >= d->nAttribute)) return emptyXMLAttribute;
3387  return d->pAttribute[i];
3388 }
3390 {
3391  if ((!d) || (i >= d->nAttribute)) return nullptr;
3392  return d->pAttribute[i].lpszName;
3393 }
3395 {
3396  if ((!d) || (i >= d->nAttribute)) return nullptr;
3397  return d->pAttribute[i].lpszValue;
3398 }
3400 {
3401  if ((!d) || (i >= d->nText)) return nullptr;
3402  return d->pText[i];
3403 }
3405 {
3406  if ((!d) || (i >= d->nChild)) return emptyXMLNode;
3407  return d->pChild[i];
3408 }
3410 {
3411  if ((!d) || (!d->pParent)) return emptyXMLNode;
3412  return XMLNode(d->pParent);
3413 }
3415 {
3416  if (!d) return 0;
3417  return d->isDeclaration;
3418 }
3419 char XMLNode::isEmpty() const { return (d == nullptr); }
3422  XMLCSTR lpszName, char isDeclaration, XMLElementPosition pos)
3423 {
3424  return addChild_priv(0, stringDup(lpszName), isDeclaration, pos);
3425 }
3427  XMLSTR lpszName, char isDeclaration, XMLElementPosition pos)
3428 {
3429  return addChild_priv(0, lpszName, isDeclaration, pos);
3430 }
3432 {
3433  return addAttribute_priv(0, stringDup(lpszName), stringDup(lpszValue));
3434 }
3436 {
3437  return addAttribute_priv(0, lpszName, lpszValuev);
3438 }
3440 {
3441  return addText_priv(0, stringDup(lpszValue), pos);
3442 }
3444 {
3445  return addText_priv(0, lpszValue, pos);
3446 }
3448  XMLCSTR lpszValue, XMLCSTR lpszOpen, XMLCSTR lpszClose,
3449  XMLElementPosition pos)
3450 {
3451  return addClear_priv(0, stringDup(lpszValue), lpszOpen, lpszClose, pos);
3452 }
3454  XMLSTR lpszValue, XMLCSTR lpszOpen, XMLCSTR lpszClose,
3455  XMLElementPosition pos)
3456 {
3457  return addClear_priv(0, lpszValue, lpszOpen, lpszClose, pos);
3458 }
3460 {
3461  return updateName_WOSD(stringDup(lpszName));
3462 }
3464  XMLAttribute* newAttribute, XMLAttribute* oldAttribute)
3465 {
3466  return updateAttribute_WOSD(
3467  stringDup(newAttribute->lpszValue), stringDup(newAttribute->lpszName),
3468  oldAttribute->lpszName);
3469 }
3471  XMLCSTR lpszNewValue, XMLCSTR lpszNewName, int i)
3472 {
3473  return updateAttribute_WOSD(
3474  stringDup(lpszNewValue), stringDup(lpszNewName), i);
3475 }
3477  XMLCSTR lpszNewValue, XMLCSTR lpszNewName, XMLCSTR lpszOldName)
3478 {
3479  return updateAttribute_WOSD(
3480  stringDup(lpszNewValue), stringDup(lpszNewName), lpszOldName);
3481 }
3483 {
3484  return updateText_WOSD(stringDup(lpszNewValue), i);
3485 }
3486 XMLCSTR XMLNode::updateText(XMLCSTR lpszNewValue, XMLCSTR lpszOldValue)
3487 {
3488  return updateText_WOSD(stringDup(lpszNewValue), lpszOldValue);
3489 }
3490 XMLClear* XMLNode::updateClear(XMLCSTR lpszNewContent, int i)
3491 {
3492  return updateClear_WOSD(stringDup(lpszNewContent), i);
3493 }
3494 XMLClear* XMLNode::updateClear(XMLCSTR lpszNewValue, XMLCSTR lpszOldValue)
3495 {
3496  return updateClear_WOSD(stringDup(lpszNewValue), lpszOldValue);
3497 }
3499 {
3500  return updateClear_WOSD(stringDup(newP->lpszValue), oldP->lpszValue);
3501 }
3502 
3504  XMLCharEncoding _characterEncoding, char _guessWideCharChars,
3505  char _dropWhiteSpace, char _removeCommentsInMiddleOfText)
3506 {
3507  guessWideCharChars = _guessWideCharChars;
3508  dropWhiteSpace = _dropWhiteSpace;
3509  removeCommentsInMiddleOfText = _removeCommentsInMiddleOfText;
3510 #ifdef _XMLWIDECHAR
3511  if (_characterEncoding) characterEncoding = _characterEncoding;
3512 #else
3513  switch (_characterEncoding)
3514  {
3515  case char_encoding_UTF8:
3516  characterEncoding = _characterEncoding;
3518  break;
3519  case char_encoding_legacy:
3520  characterEncoding = _characterEncoding;
3522  break;
3524  characterEncoding = _characterEncoding;
3526  break;
3527  case char_encoding_GB2312:
3528  characterEncoding = _characterEncoding;
3530  break;
3531  case char_encoding_Big5:
3532  case char_encoding_GBK:
3533  characterEncoding = _characterEncoding;
3535  break;
3536  default:
3537  return 1;
3538  }
3539 #endif
3540  return 0;
3541 }
3542 
3544  void* buf, int l, char useXMLEncodingAttribute)
3545 {
3546 #ifdef _XMLWIDECHAR
3547  return (XMLCharEncoding)0;
3548 #else
3549  if (l < 25) return (XMLCharEncoding)0;
3550  if (guessWideCharChars && (myIsTextWideChar(buf, l)))
3551  return (XMLCharEncoding)0;
3552  auto* b = (unsigned char*)buf;
3553  if ((b[0] == 0xef) && (b[1] == 0xbb) && (b[2] == 0xbf))
3554  return char_encoding_UTF8;
3555 
3556  // Match utf-8 model ?
3557  XMLCharEncoding bestGuess = char_encoding_UTF8;
3558  int i = 0;
3559  while (i < l) switch (XML_utf8ByteTable[b[i]])
3560  {
3561  case 4:
3562  i++;
3563  if ((i < l) && (b[i] & 0xC0) != 0x80)
3564  {
3565  bestGuess = char_encoding_legacy;
3566  i = l;
3567  } // 10bbbbbb ?
3568  /*FALLTHROUGH*/
3569  case 3:
3570  i++;
3571  if ((i < l) && (b[i] & 0xC0) != 0x80)
3572  {
3573  bestGuess = char_encoding_legacy;
3574  i = l;
3575  } // 10bbbbbb ?
3576  /*FALLTHROUGH*/
3577  case 2:
3578  i++;
3579  if ((i < l) && (b[i] & 0xC0) != 0x80)
3580  {
3581  bestGuess = char_encoding_legacy;
3582  i = l;
3583  } // 10bbbbbb ?
3584  /*FALLTHROUGH*/
3585  case 1:
3586  i++;
3587  break;
3588  case 0:
3589  i = l;
3590  /*FALLTHROUGH*/
3591  }
3592  if (!useXMLEncodingAttribute) return bestGuess;
3593  // if encoding is specified and different from utf-8 than it's non-utf8
3594  // otherwise it's utf-8
3595  char bb[201];
3596  l = mmin(l, 200);
3597  memcpy(bb, buf, l); // copy buf into bb to be able to do "bb[l]=0"
3598  bb[l] = 0;
3599  b = (unsigned char*)strstr(bb, "encoding");
3600  if (!b) return bestGuess;
3601  b += 8;
3602  while
3603  XML_isSPACECHAR(*b) b++;
3604  if (*b != '=') return bestGuess;
3605  b++;
3606  while
3607  XML_isSPACECHAR(*b) b++;
3608  if ((*b != '\'') && (*b != '"')) return bestGuess;
3609  b++;
3610  while
3611  XML_isSPACECHAR(*b) b++;
3612 
3613  if ((xstrnicmp((char*)b, "utf-8", 5) == 0) ||
3614  (xstrnicmp((char*)b, "utf8", 4) == 0))
3615  {
3616  if (bestGuess == char_encoding_legacy) return char_encoding_error;
3617  return char_encoding_UTF8;
3618  }
3619 
3620  if ((xstrnicmp((char*)b, "shiftjis", 8) == 0) ||
3621  (xstrnicmp((char*)b, "shift-jis", 9) == 0) ||
3622  (xstrnicmp((char*)b, "sjis", 4) == 0))
3623  return char_encoding_ShiftJIS;
3624 
3625  if (xstrnicmp((char*)b, "GB2312", 6) == 0) return char_encoding_GB2312;
3626  if (xstrnicmp((char*)b, "Big5", 4) == 0) return char_encoding_Big5;
3627  if (xstrnicmp((char*)b, "GBK", 3) == 0) return char_encoding_GBK;
3628 
3629  return char_encoding_legacy;
3630 #endif
3631 }
3632 #undef XML_isSPACECHAR
3633 
3634 //////////////////////////////////////////////////////////
3635 // Here starts the base64 conversion functions. //
3636 //////////////////////////////////////////////////////////
3637 
3638 static const char base64Fillchar =
3639  _CXML('='); // used to mark partial words at the end
3640 
3641 // this lookup table defines the base64 encoding
3643  _CXML("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
3644 
3645 // Decode Table gives the index of any valid base64 character in the Base64
3646 // table]
3647 // 96: '=' - 97: space char - 98: illegal char - 99: end of string
3648 const unsigned char base64DecodeTable[] = {
3649  99, 98, 98, 98, 98, 98, 98, 98, 98, 97, 97, 98, 98, 97, 98, 98,
3650  98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, // 00 -29
3651  98, 98, 97, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 62, 98, 98,
3652  98, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 98, 98, // 30 -59
3653  98, 96, 98, 98, 98, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
3654  11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 60 -89
3655  25, 98, 98, 98, 98, 98, 98, 26, 27, 28, 29, 30, 31, 32, 33, 34,
3656  35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, // 90 -119
3657  49, 50, 51, 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, // 120 -149
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, // 150 -179
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, // 180 -209
3663  98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98,
3664  98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, // 210 -239
3665  98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98 // 240 -255
3666 };
3667 
3670 {
3671  if (buf) free(buf);
3672  buf = nullptr;
3673  buflen = 0;
3674 }
3675 
3676 int XMLParserBase64Tool::encodeLength(int inlen, char formatted)
3677 {
3678  unsigned int i = ((inlen - 1) / 3 * 4 + 4 + 1);
3679  if (formatted) i += inlen / 54;
3680  return i;
3681 }
3682 
3684  unsigned char* inbuf, unsigned int inlen, char formatted)
3685 {
3686  int i = encodeLength(inlen, formatted), k = 17, eLen = inlen / 3, j;
3687  alloc(i * sizeof(XMLCHAR));
3688  XMLSTR curr = (XMLSTR)buf;
3689  for (i = 0; i < eLen; i++)
3690  {
3691  // Copy next three bytes into lower 24 bits of int, paying attention to
3692  // sign.
3693  j = (inbuf[0] << 16) | (inbuf[1] << 8) | inbuf[2];
3694  inbuf += 3;
3695  // Encode the int into four chars
3696  *(curr++) = base64EncodeTable[j >> 18];
3697  *(curr++) = base64EncodeTable[(j >> 12) & 0x3f];
3698  *(curr++) = base64EncodeTable[(j >> 6) & 0x3f];
3699  *(curr++) = base64EncodeTable[(j)&0x3f];
3700  if (formatted)
3701  {
3702  if (!k)
3703  {
3704  *(curr++) = _CXML('\n');
3705  k = 18;
3706  }
3707  k--;
3708  }
3709  }
3710  eLen = inlen - eLen * 3; // 0 - 2.
3711  if (eLen == 1)
3712  {
3713  *(curr++) = base64EncodeTable[inbuf[0] >> 2];
3714  *(curr++) = base64EncodeTable[(inbuf[0] << 4) & 0x3F];
3715  *(curr++) = base64Fillchar;
3716  *(curr++) = base64Fillchar;
3717  }
3718  else if (eLen == 2)
3719  {
3720  j = (inbuf[0] << 8) | inbuf[1];
3721  *(curr++) = base64EncodeTable[j >> 10];
3722  *(curr++) = base64EncodeTable[(j >> 4) & 0x3f];
3723  *(curr++) = base64EncodeTable[(j << 2) & 0x3f];
3724  *(curr++) = base64Fillchar;
3725  }
3726  *(curr++) = 0;
3727  return (XMLSTR)buf;
3728 }
3729 
3731 {
3732  if (xe) *xe = eXMLErrorNone;
3733  int size = 0;
3734  unsigned char c;
3735  // skip any extra characters (e.g. newlines or spaces)
3736  while (*data)
3737  {
3738 #ifdef _XMLWIDECHAR
3739  if (*data > 255)
3740  {
3742  return 0;
3743  }
3744 #endif
3745  c = base64DecodeTable[(unsigned char)(*data)];
3746  if (c < 97)
3747  size++;
3748  else if (c == 98)
3749  {
3751  return 0;
3752  }
3753  data++;
3754  }
3755  if (xe && (size % 4 != 0)) *xe = eXMLErrorBase64DataSizeIsNotMultipleOf4;
3756  if (size == 0) return 0;
3757  do
3758  {
3759  data--;
3760  size--;
3761  } while (*data == base64Fillchar);
3762  size++;
3763  return (unsigned int)((size * 3) / 4);
3764 }
3765 
3767  XMLCSTR data, unsigned char* buf, int len, XMLError* xe)
3768 {
3769  if (xe) *xe = eXMLErrorNone;
3770  int i = 0, p = 0;
3771  unsigned char d, c;
3772  for (;;)
3773  {
3774 #ifdef _XMLWIDECHAR
3775 #define BASE64DECODE_READ_NEXT_CHAR(c) \
3776  do \
3777  { \
3778  if (data[i] > 255) \
3779  { \
3780  c = 98; \
3781  break; \
3782  } \
3783  c = base64DecodeTable[(unsigned char)data[i++]]; \
3784  } while (c == 97); \
3785  if (c == 98) \
3786  { \
3787  if (xe) *xe = eXMLErrorBase64DecodeIllegalCharacter; \
3788  return 0; \
3789  }
3790 #else
3791 #define BASE64DECODE_READ_NEXT_CHAR(c) \
3792  do \
3793  { \
3794  c = base64DecodeTable[(unsigned char)data[i++]]; \
3795  } while (c == 97); \
3796  if (c == 98) \
3797  { \
3798  if (xe) *xe = eXMLErrorBase64DecodeIllegalCharacter; \
3799  return 0; \
3800  }
3801 #endif
3802 
3804  if (c == 99)
3805  {
3806  return 2;
3807  }
3808  if (c == 96)
3809  {
3810  if (p == (int)len) return 2;
3811  if (xe) *xe = eXMLErrorBase64DecodeTruncatedData;
3812  return 1;
3813  }
3814 
3816  if ((d == 99) || (d == 96))
3817  {
3818  if (xe) *xe = eXMLErrorBase64DecodeTruncatedData;
3819  return 1;
3820  }
3821  if (p == (int)len)
3822  {
3824  return 0;
3825  }
3826  buf[p++] = (unsigned char)((c << 2) | ((d >> 4) & 0x3));
3827 
3829  if (c == 99)
3830  {
3831  if (xe) *xe = eXMLErrorBase64DecodeTruncatedData;
3832  return 1;
3833  }
3834  if (p == (int)len)
3835  {
3836  if (c == 96) return 2;
3838  return 0;
3839  }
3840  if (c == 96)
3841  {
3842  if (xe) *xe = eXMLErrorBase64DecodeTruncatedData;
3843  return 1;
3844  }
3845  buf[p++] = (unsigned char)(((d << 4) & 0xf0) | ((c >> 2) & 0xf));
3846 
3848  if (d == 99)
3849  {
3850  if (xe) *xe = eXMLErrorBase64DecodeTruncatedData;
3851  return 1;
3852  }
3853  if (p == (int)len)
3854  {
3855  if (d == 96) return 2;
3857  return 0;
3858  }
3859  if (d == 96)
3860  {
3861  if (xe) *xe = eXMLErrorBase64DecodeTruncatedData;
3862  return 1;
3863  }
3864  buf[p++] = (unsigned char)(((c << 6) & 0xc0) | d);
3865  }
3866 }
3867 #undef BASE64DECODE_READ_NEXT_CHAR
3868 
3870 {
3871  if ((!buf) && (newsize))
3872  {
3873  buf = malloc(newsize);
3874  buflen = newsize;
3875  return;
3876  }
3877  if (newsize > buflen)
3878  {
3879  buf = realloc(buf, newsize);
3880  buflen = newsize;
3881  }
3882 }
3883 
3885  XMLCSTR data, int* outlen, XMLError* xe)
3886 {
3887  if (xe) *xe = eXMLErrorNone;
3888  unsigned int len = decodeSize(data, xe);
3889  if (outlen) *outlen = len;
3890  if (!len) return nullptr;
3891  alloc(len + 1);
3892  if (!decode(data, (unsigned char*)buf, len, xe))
3893  {
3894  return nullptr;
3895  }
3896  return (unsigned char*)buf;
3897 }
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:3234
int nAttribute() const
next attribute content with specific name (return a nullptr if failing)
Definition: xmlParser.cpp:3364
char isAttributeSet(XMLCSTR name) const
test if an attribute with a specific name is given
Definition: xmlParser.cpp:3291
static const char XML_gbk_big5_ByteTable[256]
Definition: xmlParser.cpp:721
GLuint GLuint GLsizei count
Definition: glext.h:3532
XMLCSTR updateName_WOSD(XMLSTR lpszName)
change node&#39;s name
Definition: xmlParser.cpp:1370
XMLNode getParentNode() const
return the parent node
Definition: xmlParser.cpp:3409
XMLSTR toXML(XMLCSTR source)
returns a pointer to an internal buffer
Definition: xmlParser.cpp:959
XMLElementType
Enumeration used to manage type of data.
Definition: xmlParser.h:265
#define _CXML(c)
Definition: xmlParser.h:224
#define MEMORYINCREASE
Definition: xmlParser.cpp:1420
XMLCSTR base64EncodeTable
Definition: xmlParser.cpp:3642
XMLCHAR xmltoc(XMLCSTR t, XMLCHAR v)
Definition: xmlParser.cpp:515
GLdouble GLdouble t
Definition: glext.h:3695
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:3683
#define XMLCHAR
Definition: xmlParser.h:227
void alloc(int newsize)
Definition: xmlParser.cpp:3869
static ALLXMLClearTag XMLClearTags[]
Definition: xmlParser.cpp:49
enum Attrib { eAttribName=0, eAttribEquals, eAttribValue } Attrib
Definition: xmlParser.cpp:801
char maybeAddTxT(void *pa, XMLCSTR tokenPStr)
Definition: xmlParser.cpp:1660
struct XML XML
XMLCSTR lpszOpenTag
Definition: xmlParser.h:285
void deleteAttribute(int i=0)
Delete the ith attribute of the current XMLNode.
Definition: xmlParser.cpp:2878
#define INDENTCHAR
Definition: xmlParser.cpp:78
Main Class representing a XML node.
Definition: xmlParser.h:314
int nColumn
Definition: xmlParser.h:278
XMLCSTR lpXML
Definition: xmlParser.cpp:783
static void myFree(void *p)
Definition: xmlParser.cpp:1422
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:3490
XMLError writeToFile(XMLCSTR filename, const char *encoding=nullptr, char nFormat=1) const
Save the content of an xmlNode inside a file.
Definition: xmlParser.cpp:807
int void fclose(FILE *f)
An OS-independent version of fclose.
Definition: os.cpp:275
XMLClear * addClear(XMLCSTR lpszValue, XMLCSTR lpszOpen=nullptr, XMLCSTR lpszClose=nullptr, XMLElementPosition pos=-1)
Add a new clear tag.
Definition: xmlParser.cpp:3447
void freeBuffer()
call this function when you have finished using
Definition: xmlParser.cpp:953
XMLCharEncoding
childNode with the specified name if (name==nullptr) return the position of the ith childNode ...
Definition: xmlParser.h:778
int _strnicmp(const char *str, const char *subStr, size_t count) noexcept
An OS-independent version of strnicmp.
Definition: os.cpp:346
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:2218
XMLNode getChildNodeByPath(XMLSTR path, char createNodeIfMissing=0, XMLCHAR sep='/')
name/attribute (return an empty node if failing)
Definition: xmlParser.cpp:3155
GLenum GLsizei n
Definition: glext.h:5136
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:3482
Structure for XML clear (unformatted) node (usually comments)
Definition: xmlParser.h:282
#define SEEK_END
Definition: zconf.h:302
void * addToOrder(int memInc, int *_pos, int nc, void *p, int size, XMLElementType xtype)
Definition: xmlParser.cpp:1469
char isEmpty() const
is this node Empty?
Definition: xmlParser.cpp:3419
int nIndex
Definition: xmlParser.cpp:785
This structure is given by the function XMLNode::enumContents.
Definition: xmlParser.h:942
static int xstrnicmp(XMLCSTR c1, XMLCSTR c2, int l)
Definition: xmlParser.cpp:284
XMLCSTR lpNewElement
Definition: xmlParser.cpp:789
XMLSTR stringDup(XMLCSTR lpszData, int cbData)
Duplicate (copy in a new allocated buffer) the source string.
Definition: xmlParser.cpp:861
static XMLNode createXMLTopNode(XMLCSTR lpszName, char isDeclaration=FALSE)
Create the top node of an XMLNode structure.
Definition: xmlParser.cpp:1415
int nClear() const
nbr of clear field
Definition: xmlParser.cpp:3369
XMLClear * addClear_WOSD(XMLSTR lpszValue, XMLCSTR lpszOpen=nullptr, XMLCSTR lpszClose=nullptr, XMLElementPosition pos=-1)
Add a new clear Tag.
Definition: xmlParser.cpp:3453
XMLNode addChild_priv(int, XMLSTR, char, int)
Definition: xmlParser.cpp:1512
static void * myRealloc(void *p, int newsize, int memInc, int sizeofElem)
Definition: xmlParser.cpp:1426
XMLAttribute * addAttribute_priv(int, XMLSTR, XMLSTR)
Definition: xmlParser.cpp:1526
#define XMLCSTR
Definition: xmlParser.h:225
XMLCSTR pStr
Definition: xmlParser.cpp:797
static int removeOrderElement(XMLNodeData *d, XMLElementType t, int index)
Definition: xmlParser.cpp:1455
XMLCSTR lpEndTag
Definition: xmlParser.cpp:787
XMLElementPosition positionOfChildNode(int i=0) const
Definition: xmlParser.cpp:3194
GLdouble s
Definition: glext.h:3682
GLenum GLsizei len
Definition: glext.h:4756
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:523
void deleteText(int i=0)
with the name "anAttribute->lpszName" (the "strcmp" function is used to find the right attribute) ...
Definition: xmlParser.cpp:2972
#define BASE64DECODE_READ_NEXT_CHAR(c)
XMLNode & operator=(const XMLNode &A)
to allow shallow/fast copy:
Definition: xmlParser.cpp:2768
int ParseXMLElement(void *pXML)
Definition: xmlParser.cpp:1717
static XMLCSTR getError(XMLError error)
this gives you a
Definition: xmlParser.cpp:83
XMLNodeData * d
Definition: xmlParser.h:918
int mmin(const int t1, const int t2)
Definition: xmlParser.cpp:37
int nChildNode() const
nbr of child node
Definition: xmlParser.cpp:3359
XMLCSTR getText(int i=0) const
return ith text field
Definition: xmlParser.cpp:3399
struct XMLAttribute XMLAttribute
Structure for XML attribute.
int nText() const
nbr of text field
Definition: xmlParser.cpp:3354
static XMLNode createXMLTopNode_WOSD(XMLSTR lpszName, char isDeclaration=FALSE)
Create the top node of an XMLNode structure.
Definition: xmlParser.cpp:1411
static int encodeLength(int inBufLen, char formatted=0)
this object to release memory used by the internal buffer.
Definition: xmlParser.cpp:3676
XMLCSTR addText_WOSD(XMLSTR lpszValue, XMLElementPosition pos=-1)
Add a new text content.
Definition: xmlParser.cpp:3443
XMLNode()=default
XMLAttribute getAttribute(int i=0) const
return ith attribute
Definition: xmlParser.cpp:3384
static NextToken GetNextToken(XML *pXML, int *pcbToken, enum XMLTokenTypeTag *pType)
Definition: xmlParser.cpp:1182
XMLCSTR addText_priv(int, XMLSTR, int)
Definition: xmlParser.cpp:1547
enum XMLError error
Definition: xmlParser.cpp:786
int nElement() const
clear) of the current XMLNode.
Definition: xmlParser.cpp:3374
static XMLCHAR getNextChar(XML *pXML)
Definition: xmlParser.cpp:1169
GLuint index
Definition: glext.h:4068
const GLubyte * c
Definition: glext.h:6406
XMLNode addChild_WOSD(XMLSTR lpszName, char isDeclaration=FALSE, XMLElementPosition pos=-1)
Add a new child node.
Definition: xmlParser.cpp:3426
void emptyTheNode(char force)
Definition: xmlParser.cpp:2720
XMLError
Enumeration for XML parse errors.
Definition: xmlParser.h:237
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:2709
static int detachFromParent(XMLNodeData *d)
Definition: xmlParser.cpp:2687
#define XMLSTR
Definition: xmlParser.h:226
int indexClear(XMLCSTR lpszValue) const
Definition: xmlParser.cpp:3038
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:3503
XMLAttribute * updateAttribute_WOSD(XMLAttribute *newAttribute, XMLAttribute *oldAttribute)
if the attribute to update is
Definition: xmlParser.cpp:2930
XMLCSTR updateName(XMLCSTR lpszName)
change node&#39;s name
Definition: xmlParser.cpp:3459
XMLNodeContents enumContents(XMLElementPosition i) const
enumerate all the different contents (attribute,child,text,
Definition: xmlParser.cpp:3315
static XMLNode emptyNode()
return XMLNode::emptyXMLNode;
Definition: xmlParser.cpp:3420
static unsigned int decodeSize(XMLCSTR inString, XMLError *xe=nullptr)
containing the base64 string containing the binary data encoded from "inByteBuf"
Definition: xmlParser.cpp:3730
GLubyte GLubyte b
Definition: glext.h:6372
int cbNewElement
Definition: xmlParser.cpp:790
#define XML_isSPACECHAR(ch)
Definition: xmlParser.cpp:1148
XMLElementPosition positionOfText(int i=0) const
Definition: xmlParser.cpp:3184
XMLCSTR lpszValue
Definition: xmlParser.h:284
XMLElementPosition positionOfClear(int i=0) const
Definition: xmlParser.cpp:3189
enum Status { eInsideTag=0, eOutsideTag } Status
Definition: xmlParser.cpp:805
static void charmemset(XMLSTR dest, XMLCHAR c, int l)
Definition: xmlParser.cpp:2368
static char dropWhiteSpace
Definition: xmlParser.cpp:34
static void CountLinesAndColumns(XMLCSTR lpXML, int nUpto, XMLResults *pResults)
Definition: xmlParser.cpp:2193
static XMLElementPosition findPosition(XMLNodeData *d, int index, XMLElementType xtype)
Definition: xmlParser.cpp:1444
static int xstricmp(XMLCSTR c1, XMLCSTR c2)
Definition: xmlParser.cpp:288
struct XMLNode::XMLNodeDataTag XMLNodeData
static XMLAttribute emptyXMLAttribute
Definition: xmlParser.h:524
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:1644
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:410
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:3543
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:2285
XMLCSTR lpszOpen
Definition: xmlParser.cpp:45
GLint mode
Definition: glext.h:5753
XMLAttribute * updateAttribute(XMLAttribute *newAttribute, XMLAttribute *oldAttribute)
if the attribute to update is
Definition: xmlParser.cpp:3463
XMLCSTR lpszName
Definition: xmlParser.h:292
XMLCSTR addText(XMLCSTR lpszValue, XMLElementPosition pos=-1)
Add a new text content.
Definition: xmlParser.cpp:3439
int indexText(XMLCSTR lpszValue) const
Definition: xmlParser.cpp:2957
const GLdouble * v
Definition: glext.h:3684
XMLSTR createXMLString(int nFormat=1, int *pnSize=nullptr) const
user-friendly explanation of the parsing error
Definition: xmlParser.cpp:2663
XMLAttribute * addAttribute_WOSD(XMLSTR lpszName, XMLSTR lpszValue)
Add a new attribute.
Definition: xmlParser.cpp:3435
int nIndexMissigEndTag
Definition: xmlParser.cpp:785
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:2993
int XMLElementPosition
XMLElementPosition are not interchangeable with simple indexes.
Definition: xmlParser.h:297
GLdouble GLdouble GLdouble r
Definition: glext.h:3711
static int lengthXMLString(XMLCSTR source)
deprecated: use "toXML" instead
Definition: xmlParser.cpp:921
#define SEEK_SET
Definition: zconf.h:300
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:3884
char parseClearTag(void *px, void *pa)
Definition: xmlParser.cpp:1588
static const char * XML_ByteTable
Definition: xmlParser.cpp:756
static const char base64Fillchar
Definition: xmlParser.cpp:3638
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:3062
#define FALSE
Definition: xmlParser.h:230
char myTagCompare(XMLCSTR cclose, XMLCSTR copen)
Definition: xmlParser.cpp:1153
char xmltob(XMLCSTR t, char v)
Definition: xmlParser.cpp:489
_u8 status
Definition: rplidar_cmd.h:19
GLuint const GLchar * name
Definition: glext.h:4068
GLsizei GLsizei GLchar * source
Definition: glext.h:4097
Structure for XML attribute.
Definition: xmlParser.h:290
const unsigned char base64DecodeTable[]
Definition: xmlParser.cpp:3648
int nFirst
Definition: xmlParser.cpp:791
static char guessWideCharChars
Definition: xmlParser.cpp:34
ALLXMLClearTag * pClr
Definition: xmlParser.cpp:796
XMLCSTR lpszClose
Definition: xmlParser.cpp:47
char myIsTextWideChar(const void *b, int l)
Definition: xmlParser.cpp:193
XMLCSTR lpszValue
Definition: xmlParser.h:293
FILE * fopen(const char *fileName, const char *mode) noexcept
An OS-independent version of fopen.
Definition: os.cpp:257
enum XMLError error
Definition: xmlParser.h:277
XMLNode addChild(XMLCSTR lpszName, char isDeclaration=FALSE, XMLElementPosition pos=-1)
Add a new child node.
Definition: xmlParser.cpp:3421
static int CreateXMLStringR(XMLNodeData *pEntry, XMLSTR lpszMarker, int nFormat)
Definition: xmlParser.cpp:2378
long xmltol(XMLCSTR t, long v)
Definition: xmlParser.cpp:499
GLsizeiptr size
Definition: glext.h:3934
XMLCSTR lpszText
Definition: xmlParser.cpp:784
enum XMLTokenTypeTag XMLTokenType
GLenum GLint x
Definition: glext.h:3542
XMLClear getClear(int i=0) const
return ith clear field (comments)
Definition: xmlParser.cpp:3379
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:299
XMLCSTR getAttributeValue(int i=0) const
return ith attribute value
Definition: xmlParser.cpp:3394
static XMLNode emptyXMLNode
Definition: xmlParser.h:522
XMLTokenTypeTag
Definition: xmlParser.cpp:766
char isDeclaration() const
is this node a declaration <? .... ?>
Definition: xmlParser.cpp:3414
int cbEndTag
Definition: xmlParser.cpp:788
#define TRUE
Definition: xmlParser.h:233
void freeBuffer()
Call this function when you have finished using.
Definition: xmlParser.cpp:3669
char * myWideCharToMultiByte(const wchar_t *s)
Definition: xmlParser.cpp:243
GLsizei GLsizei GLenum GLenum const GLvoid * data
Definition: glext.h:3550
GLubyte GLubyte GLubyte a
Definition: glext.h:6372
GLfloat GLfloat p
Definition: glext.h:6398
XMLCSTR getAttributeName(int i=0) const
return ith attribute name
Definition: xmlParser.cpp:3389
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:3022
XMLCSTR lpszCloseTag
Definition: xmlParser.h:286
int nChildNode(XMLCSTR name) const
return the number of child node with specific name
Definition: xmlParser.cpp:3099
XMLNode deepCopy() const
deep copy (duplicate/clone) a XMLNode
Definition: xmlParser.cpp:2791
Structure used to obtain error details if the parse fails.
Definition: xmlParser.h:275
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:191
static XMLSTR toXMLUnSafe(XMLSTR dest, XMLCSTR source)
that contains a XML-encoded string based on the "source" parameter.
Definition: xmlParser.cpp:876
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:971
XMLCSTR getName() const
name of the node
Definition: xmlParser.cpp:3349
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:358
XMLNode getChildNode(int i=0) const
return ith child node
Definition: xmlParser.cpp:3404
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:3431
static const char XML_legacyByteTable[256]
Definition: xmlParser.cpp:639
XMLClear * addClear_priv(int, XMLSTR, XMLCSTR, XMLCSTR, int)
Definition: xmlParser.cpp:1563
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: 8fe78517f Sun Jul 14 19:43:28 2019 +0200 at lun oct 28 02:10:00 CET 2019