75#ifndef _CRT_SECURE_NO_DEPRECATE
76#define _CRT_SECURE_NO_DEPRECATE
85#define WIN32_LEAN_AND_MEAN
101XMLCSTR XMLNode::getVersion() {
return _X(
"v2.30"); }
104static XMLNode::XMLCharEncoding characterEncoding=XMLNode::encoding_UTF8;
105static char guessWideCharChars=1, dropWhiteSpace=1;
107inline int mmin(
const int t1,
const int t2 ) {
return t1 < t2 ? t1 : t2; }
113typedef struct {
XMLCSTR lpszOpen;
int openTagLen;
XMLCSTR lpszClose;} ALLXMLClearTag;
114static ALLXMLClearTag XMLClearTags[] =
116 {
_X(
"<![CDATA["),9,
_X(
"]]>") },
117 {
_X(
"<!DOCTYPE"),9,
_X(
">") },
118 {
_X(
"<PRE>") ,5,
_X(
"</PRE>") },
119 {
_X(
"<Script>") ,8,
_X(
"</Script>")},
120 {
_X(
"<!--") ,4,
_X(
"-->") },
129static XMLCharacterEntity XMLEntities[] =
131 {
_X(
"&" ), 5,
_X(
'&' )},
132 {
_X(
"<" ), 4,
_X(
'<' )},
133 {
_X(
">" ), 4,
_X(
'>' )},
134 {
_X(
"""), 6,
_X(
'\"')},
135 {
_X(
"'"), 6,
_X(
'\'')},
142#define INDENTCHAR _X('\t')
172 return _X(
"Unknown");
184#ifdef XML_NO_WIDE_CHAR
185char myIsTextWideChar(
const void *b,
int len) {
return FALSE; }
187 #if defined (UNDER_CE) || !defined(_XMLWINDOWS)
188 char myIsTextWideChar(
const void *b,
int len)
192 if ((((
unsigned long)b)%
sizeof(
wchar_t))!=0)
return FALSE;
194 const wchar_t *s=(
const wchar_t*)b;
197 if (len<(
int)
sizeof(
wchar_t))
return FALSE;
200 if (len&1)
return FALSE;
203 len=mmin(256,len/
sizeof(
wchar_t));
206 if (*((
unsigned short*)s) == 0xFFFE)
return TRUE;
207 if (*((
unsigned short*)s) == 0xFEFF)
return TRUE;
211 for (i=0; i<len; i++)
if (s[i]<=(
unsigned short)255) stats++;
212 if (stats>len/2)
return TRUE;
215 for (i=0; i<len; i++)
if (!s[i])
return TRUE;
220 char myIsTextWideChar(
const void *b,
int l) {
return (
char)IsTextUnicode((CONST LPVOID)b,l,NULL); };
227 wchar_t *myMultiByteToWideChar(
const char *s)
230 if (characterEncoding==XMLNode::encoding_UTF8) i=(int)MultiByteToWideChar(CP_UTF8,0 ,s,-1,NULL,0);
231 else i=(int)MultiByteToWideChar(CP_ACP ,MB_PRECOMPOSED,s,-1,NULL,0);
232 if (i<0)
return NULL;
233 wchar_t *d=(
wchar_t *)malloc((i+1)*
sizeof(
XMLCHAR));
234 if (characterEncoding==XMLNode::encoding_UTF8) i=(int)MultiByteToWideChar(CP_UTF8,0 ,s,-1,d,i);
235 else i=(int)MultiByteToWideChar(CP_ACP ,MB_PRECOMPOSED,s,-1,d,i);
239 static inline FILE *xfopen(
XMLCSTR filename,
XMLCSTR mode) {
return _wfopen(filename,mode); }
240 static inline int xstrlen(
XMLCSTR c) {
return (
int)wcslen(c); }
241 static inline int xstrnicmp(
XMLCSTR c1,
XMLCSTR c2,
int l) {
return _wcsnicmp(c1,c2,l);}
242 static inline int xstrncmp(
XMLCSTR c1,
XMLCSTR c2,
int l) {
return wcsncmp(c1,c2,l);}
243 static inline int xstricmp(
XMLCSTR c1,
XMLCSTR c2) {
return _wcsicmp(c1,c2); }
247 char *myWideCharToMultiByte(
const wchar_t *s)
249 UINT codePage=CP_ACP;
if (characterEncoding==XMLNode::encoding_UTF8) codePage=CP_UTF8;
250 int i=(int)WideCharToMultiByte(codePage,
259 if (i<0)
return NULL;
260 char *d=(
char*)malloc(i+1);
261 WideCharToMultiByte(codePage,
273 static inline FILE *xfopen(
XMLCSTR filename,
XMLCSTR mode) {
return fopen(filename,mode); }
274 static inline int xstrlen(
XMLCSTR c) {
return (
int)strlen(c); }
276 static inline int xstrncmp(
XMLCSTR c1,
XMLCSTR c2,
int l) {
return strncmp(c1,c2,l);}
282 static inline int _strnicmp(
char *c1,
char *c2,
int l){
return strnicmp(c1,c2,l);}
286 #ifdef XML_NO_WIDE_CHAR
287 char *myWideCharToMultiByte(
const wchar_t *s) {
return NULL; }
289 char *myWideCharToMultiByte(
const wchar_t *s)
292 int i=(int)wcsrtombs(NULL,&ss,0,NULL);
293 if (i<0)
return NULL;
294 char *d=(
char *)malloc(i+1);
295 wcsrtombs(d,&s,i,NULL);
301 wchar_t *myMultiByteToWideChar(
const char *s)
304 int i=(int)mbsrtowcs(NULL,&ss,0,NULL);
305 if (i<0)
return NULL;
306 wchar_t *d=(
wchar_t *)malloc((i+1)*
sizeof(
wchar_t));
307 mbsrtowcs(d,&s,i,NULL);
311 int xstrlen(
XMLCSTR c) {
return wcslen(c); }
315 static inline int xstrnicmp(
XMLCSTR c1,
XMLCSTR c2,
int l) {
return wsncasecmp(c1,c2,l);}
316 static inline int xstrncmp(
XMLCSTR c1,
XMLCSTR c2,
int l) {
return wsncmp(c1,c2,l);}
317 static inline int xstricmp(
XMLCSTR c1,
XMLCSTR c2) {
return wscasecmp(c1,c2); }
320 static inline int xstrnicmp(
XMLCSTR c1,
XMLCSTR c2,
int l) {
return wcsncasecmp(c1,c2,l);}
321 static inline int xstrncmp(
XMLCSTR c1,
XMLCSTR c2,
int l) {
return wcsncmp(c1,c2,l);}
322 static inline int xstricmp(
XMLCSTR c1,
XMLCSTR c2) {
return wcscasecmp(c1,c2); }
328 char *filenameAscii=myWideCharToMultiByte(filename);
330 if (mode[0]==
_X(
'r')) f=fopen(filenameAscii,
"rb");
331 else f=fopen(filenameAscii,
"wb");
336 static inline FILE *xfopen(
XMLCSTR filename,
XMLCSTR mode) {
return fopen(filename,mode); }
337 static inline int xstrlen(
XMLCSTR c) {
return strlen(c); }
338 static inline int xstrnicmp(
XMLCSTR c1,
XMLCSTR c2,
int l) {
return strncasecmp(c1,c2,l);}
339 static inline int xstrncmp(
XMLCSTR c1,
XMLCSTR c2,
int l) {
return strncmp(c1,c2,l);}
340 static inline int xstricmp(
XMLCSTR c1,
XMLCSTR c2) {
return strcasecmp(c1,c2); }
344 static inline int _strnicmp(
const char *c1,
const char *c2,
int l) {
return strncasecmp(c1,c2,l);}
357 FILE *f=xfopen(filename,
_X(
"rb"));
361 int l=(int)fread(bb,1,200,f);
368 XMLNode xnode=XMLNode::parseFile(filename,tag,&pResults);
374 char message[2000],*s1=(
char*)
"",*s3=(
char*)
"";
XMLCSTR s2=
_X(
"");
377#if defined(_XMLWINDOWS)
378 sprintf_s(message, 2000,
380 snprintf(message, 2000,
383 "XML Parsing error inside file '%S'.\n%S\nAt line %i, column %i.\n%s%S%s"
385 "XML Parsing error inside file '%s'.\n%s\nAt line %i, column %i.\n%s%s%s"
387 ,filename,XMLNode::getError(pResults.error),pResults.nLine,pResults.nColumn,s1,s2,s3);
390#
if defined(_XMLWINDOWS) && !defined(UNDER_CE) && !defined(_XMLPARSER_NO_MESSAGEBOX_)
391 MessageBoxA(NULL,message,
"XML Parsing error",MB_OK|MB_ICONERROR|MB_TOPMOST);
393 printf(
"%s",message);
413static const char XML_utf8ByteTable[256] =
416 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
417 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
418 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
419 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
420 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
421 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
422 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
423 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
424 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
425 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
426 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
427 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
428 1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
429 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
430 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
431 4,4,4,4,4,1,1,1,1,1,1,1,1,1,1,1
433static const char XML_asciiByteTable[256] =
435 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
436 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
437 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
438 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
439 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
440 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
442static const char XML_sjisByteTable[256] =
445 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
446 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
447 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
448 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
449 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
450 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
451 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
452 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
453 1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
454 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
455 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
456 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
457 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
458 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
459 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
460 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
462static const char *XML_ByteTable=(
const char *)XML_utf8ByteTable;
467XMLClear XMLNode::emptyXMLClear={ NULL, NULL, NULL};
471typedef enum XMLTokenTypeTag
480 eTokenShortHandClose,
490 int nIndex,nIndexMissigEndTag;
501 ALLXMLClearTag *pClr;
521XMLError XMLNode::writeToFile(
XMLCSTR filename,
const char *encoding,
char nFormat)
const
524 FILE *f=xfopen(filename,
_X(
"wb"));
527 unsigned char h[2]={ 0xFF, 0xFE };
531 if (!fwrite(
_X(
"<?xml version=\"1.0\" encoding=\"utf-16\"?>\n"),
sizeof(
wchar_t)*40,1,f))
544 if (!encoding) encoding=
"ISO-8859-1";
565 if (lpszData==NULL)
return NULL;
568 if (cbData==0) cbData=(int)xstrlen(lpszData);
572 memcpy(lpszNew, lpszData, (cbData) *
sizeof(
XMLCHAR));
573 lpszNew[cbData] = (
XMLCHAR)NULL;
582 XMLCharacterEntity *entity;
588 if (ch==entity->c) {xstrcpy(dest,entity->s); dest+=entity->l; source++;
goto out_of_loop1; }
592 *(dest++)=*(source++);
594 switch(XML_ByteTable[(
unsigned char)ch])
596 case 4: *(dest++)=*(source++);
597 case 3: *(dest++)=*(source++);
598 case 2: *(dest++)=*(source++);
599 case 1: *(dest++)=*(source++);
610int lengthXMLString(
XMLCSTR source)
613 XMLCharacterEntity *entity;
620 if (ch==entity->c) { r+=entity->l; source++;
goto out_of_loop1; }
626 ch=XML_ByteTable[(
unsigned char)ch]; r+=ch; source+=ch;
634ToXMLStringTool::~ToXMLStringTool(){
freeBuffer(); }
635void ToXMLStringTool::freeBuffer(){
if (buf) free(buf); buf=NULL; buflen=0; }
638 int l=lengthXMLString(source)+1;
639 if (l>buflen) { buflen=l; buf=(
XMLSTR)realloc(buf,l*
sizeof(
XMLCHAR)); }
640 return toXMLStringUnSafe(buf,source);
658 XMLCharacterEntity *entity;
663 if ((lo>2)&&(s[1]==
_X(
'#')))
666 if ((*s==
_X(
'X'))||(*s==
_X(
'x'))) { s++; lo--; }
667 while ((*s)&&(*s!=
_X(
';'))&&((lo--)>0)) s++;
679 if ((lo>=entity->l)&&(xstrnicmp(s,entity->s,entity->l)==0)) { s+=entity->l; lo-=entity->l;
break; }
693 j=XML_ByteTable[(
unsigned char)*s]; s+=j; lo-=j; ll+=j-1;
708 if ((*ss==
_X(
'X'))||(*ss==
_X(
'x')))
713 if ((*ss>=
_X(
'0'))&&(*ss<=
_X(
'9'))) j=(j<<4)+*ss-
_X(
'0');
714 else if ((*ss>=
_X(
'A'))&&(*ss<=
_X(
'F'))) j=(j<<4)+*ss-
_X(
'A')+10;
715 else if ((*ss>=
_X(
'a'))&&(*ss<=
_X(
'f'))) j=(j<<4)+*ss-
_X(
'a')+10;
723 if ((*ss>=
_X(
'0'))&&(*ss<=
_X(
'9'))) j=(j*10)+*ss-
_X(
'0');
734 if (xstrnicmp(ss,entity->s,entity->l)==0) { *(d++)=entity->c; ss+=entity->l;
break; }
743 switch(XML_ByteTable[(
unsigned char)*ss])
745 case 4: *(d++)=*(ss++); ll--;
746 case 3: *(d++)=*(ss++); ll--;
747 case 2: *(d++)=*(ss++); ll--;
748 case 1: *(d++)=*(ss++);
757#define XML_isSPACECHAR(ch) ((ch==_X('\n'))||(ch==_X(' '))||(ch== _X('\t'))||(ch==_X('\r')))
765 if (!cclose)
return 1;
766 int l=(int)xstrlen(cclose);
767 if (xstrnicmp(cclose, copen, l)!=0)
return 1;
769 if (XML_isSPACECHAR(c)||
773 (c==
_X(
'=' )))
return 0;
778static inline XMLCHAR getNextChar(XML *pXML)
780 XMLCHAR ch = pXML->lpXML[pXML->nIndex];
782 if (ch!=0) pXML->nIndex++;
784 pXML->nIndex+=XML_ByteTable[(
unsigned char)ch];
791static NextToken GetNextToken(XML *pXML,
int *pcbToken,
enum XMLTokenTypeTag *pType)
796 int indexStart,nFoundMatch,nIsText=
FALSE;
800 do { indexStart=pXML->nIndex; ch=getNextChar(pXML); }
while XML_isSPACECHAR(ch);
805 result.pStr = &pXML->lpXML[indexStart];
809 ALLXMLClearTag *ctag=XMLClearTags;
812 if (xstrncmp(ctag->lpszOpen, result.pStr, ctag->openTagLen)==0)
815 pXML->nIndex+=ctag->openTagLen-1;
820 }
while(ctag->lpszOpen);
829 *pType = eTokenQuotedText;
836 while((ch = getNextChar(pXML)))
838 if (ch==chTemp) { nFoundMatch =
TRUE;
break; }
839 if (ch==
_X(
'<'))
break;
843 if (nFoundMatch ==
FALSE)
845 pXML->nIndex=indexStart+1;
857 *pType = eTokenEquals;
862 *pType = eTokenCloseTag;
870 chTemp = pXML->lpXML[pXML->nIndex];
873 if (chTemp ==
_X(
'/'))
877 *pType = eTokenTagEnd;
881 else if (chTemp ==
_X(
'?'))
886 *pType = eTokenDeclaration;
892 *pType = eTokenTagStart;
900 chTemp = pXML->lpXML[pXML->nIndex];
903 if (chTemp ==
_X(
'>'))
907 *pType = eTokenShortHandClose;
924 while((ch = getNextChar(pXML)))
926 if XML_isSPACECHAR(ch)
930 }
else if (ch==
_X(
'/'))
934 ch=pXML->lpXML[pXML->nIndex];
936 if (ch==
_X(
'>')) { pXML->nIndex--;
break; }
938 }
else if ((ch==
_X(
'<'))||(ch==
_X(
'>'))||(ch==
_X(
'=')))
940 pXML->nIndex--;
break;
944 *pcbToken = pXML->nIndex-indexStart;
949 *pType = eTokenError;
958 if (!d) { free(lpszName);
return NULL; }
959 if (d->lpszName&&(lpszName!=d->lpszName)) free((
void*)d->lpszName);
960 d->lpszName=lpszName;
965XMLNode::XMLNode(
struct XMLNodeDataTag *p){ d=p; (p->ref_count)++; }
966XMLNode::XMLNode(XMLNodeData *pParent,
XMLSTR lpszName,
char isDeclaration)
968 d=(XMLNodeData*)malloc(
sizeof(XMLNodeData));
979 d->pParent = pParent;
992#define MEMORYINCREASE 50
994static inline void myFree(
void *p) {
if (p) free(p); };
995static inline void *myRealloc(
void *p,
int newsize,
int memInc,
int sizeofElem)
997 if (p==NULL) {
if (memInc)
return malloc(memInc*sizeofElem);
return malloc(sizeofElem); }
998 if ((memInc==0)||((newsize%memInc)==0)) p=realloc(p,(newsize+memInc)*sizeofElem);
1007int XMLNode::findPosition(XMLNodeData *d,
int index,
XMLElementType xtype)
1009 if (index<0)
return -1;
1010 int i=0,j=(int)((index<<2)+xtype),*o=d->pOrder;
while (o[i]!=j) i++;
return i;
1015int XMLNode::removeOrderElement(XMLNodeData *d,
XMLElementType t,
int index)
1017 int n=d->nChild+d->nText+d->nClear, *o=d->pOrder,i=findPosition(d,index,t);
1018 memmove(o+i, o+i+1, (n-i)*
sizeof(
int));
1020 if ((o[i]&3)==(
int)t) o[i]-=4;
1028void *XMLNode::addToOrder(
int memoryIncrease,
int *_pos,
int nc,
void *p,
int size,
XMLElementType xtype)
1032 p=myRealloc(p,(nc+1),memoryIncrease,size);
1033 int n=d->nChild+d->nText+d->nClear;
1034 d->pOrder=(
int*)myRealloc(d->pOrder,n+1,memoryIncrease*3,
sizeof(
int));
1035 int pos=*_pos,*o=d->pOrder;
1037 if ((pos<0)||(pos>=n)) { *_pos=nc; o[n]=(int)((nc<<2)+xtype);
return p; }
1040 memmove(o+i+1, o+i, (n-i)*
sizeof(
int));
1042 while ((pos<n)&&((o[pos]&3)!=(
int)xtype)) pos++;
1043 if (pos==n) { *_pos=nc; o[n]=(int)((nc<<2)+xtype);
return p; }
1046 for (i=pos+1;i<=n;i++)
if ((o[i]&3)==(
int)xtype) o[i]+=4;
1048 *_pos=pos=o[pos]>>2;
1049 memmove(((
char*)p)+(pos+1)*size,((
char*)p)+pos*size,(nc-pos)*size);
1055XMLNode XMLNode::addChild_priv(
int memoryIncrease,
XMLSTR lpszName,
char isDeclaration,
int pos)
1059 d->pChild[pos].d=NULL;
1062 return d->pChild[pos];
1070 int nc=d->nAttribute;
1074 pAttr->lpszValue = lpszValuev;
1080XMLCSTR XMLNode::addText_priv(
int memoryIncrease,
XMLSTR lpszValue,
int pos)
1082 if (!lpszValue)
return NULL;
1083 if (!d) { myFree(lpszValue);
return NULL; }
1085 d->pText[pos]=lpszValue;
1098 if (!lpszOpen) lpszOpen=XMLClearTags->lpszOpen;
1099 if (!lpszClose) lpszClose=XMLClearTags->lpszClose;
1100 pNewClear->lpszOpenTag = lpszOpen;
1101 pNewClear->lpszCloseTag = lpszClose;
1108char XMLNode::parseClearTag(
void *px,
void *_pClear)
1110 XML *pXML=(XML *)px;
1111 ALLXMLClearTag pClear=*((ALLXMLClearTag*)_pClear);
1114 XMLCSTR lpXML=&pXML->lpXML[pXML->nIndex];
1119 if (pClear.lpszOpen==XMLClearTags[1].lpszOpen)
1124 if (*pCh==
_X(
'<')) { pClear.lpszClose=docTypeEnd; lpszTemp=xstrstr(lpXML,docTypeEnd);
break; }
1125 else if (*pCh==
_X(
'>')) { lpszTemp=pCh;
break; }
1129 pCh+=XML_ByteTable[(
unsigned char)(*pCh)];
1132 }
else lpszTemp=xstrstr(lpXML, pClear.lpszClose);
1137 cbTemp = (int)(lpszTemp - lpXML);
1139 pXML->nIndex += cbTemp+(int)xstrlen(pClear.lpszClose);
1142 addClear_priv(MEMORYINCREASE,
stringDup(lpXML,cbTemp), pClear.lpszOpen, pClear.lpszClose,-1);
1151void XMLNode::exactMemory(XMLNodeData *d)
1153 if (d->pOrder) d->pOrder=(
int*)realloc(d->pOrder,(d->nChild+d->nText+d->nClear)*
sizeof(
int));
1154 if (d->pChild) d->pChild=(
XMLNode*)realloc(d->pChild,d->nChild*
sizeof(
XMLNode));
1156 if (d->pText) d->pText=(
XMLCSTR*)realloc(d->pText,d->nText*
sizeof(
XMLSTR));
1157 if (d->pClear) d->pClear=(
XMLClear *)realloc(d->pClear,d->nClear*
sizeof(
XMLClear));
1160char XMLNode::maybeAddTxT(
void *pa,
XMLCSTR tokenPStr)
1162 XML *pXML=(XML *)pa;
1163 XMLCSTR lpszText=pXML->lpszText;
1164 if (!lpszText)
return 0;
1165 if (dropWhiteSpace)
while (XML_isSPACECHAR(*lpszText)&&(lpszText!=tokenPStr)) lpszText++;
1166 int cbText = (int)(tokenPStr - lpszText);
1167 if (!cbText) { pXML->lpszText=NULL;
return 0; }
1168 if (dropWhiteSpace) { cbText--;
while ((cbText)&&XML_isSPACECHAR(lpszText[cbText])) cbText--; cbText++; }
1169 if (!cbText) { pXML->lpszText=NULL;
return 0; }
1170 XMLSTR lpt=fromXMLString(lpszText,cbText,pXML);
1172 addText_priv(MEMORYINCREASE,lpt,-1);
1173 pXML->lpszText=NULL;
1178int XMLNode::ParseXMLElement(
void *pa)
1180 XML *pXML=(XML *)pa;
1182 enum XMLTokenTypeTag xtype;
1189 enum Attrib attrib = eAttribName;
1197 pXML->nFirst =
FALSE;
1198 status = eOutsideTag;
1202 status = eInsideTag;
1209 token = GetNextToken(pXML, &cbToken, &xtype);
1211 if (xtype != eTokenError)
1225 case eTokenCloseTag:
1226 case eTokenShortHandClose:
1227 case eTokenQuotedText:
1232 case eTokenTagStart:
1233 case eTokenDeclaration:
1236 nDeclaration = (xtype == eTokenDeclaration);
1239 if (maybeAddTxT(pXML,token.pStr))
return FALSE;
1242 token = GetNextToken(pXML, &cbToken, &xtype);
1246 if (xtype != eTokenText)
1255#ifdef APPROXIMATE_PARSING
1257 myTagCompare(d->lpszName, token.pStr) == 0)
1261 pXML->lpNewElement = token.pStr;
1262 pXML->cbNewElement = cbToken;
1270 pNew = addChild_priv(MEMORYINCREASE,
stringDup(token.pStr,cbToken), nDeclaration,-1);
1272 while (!pNew.isEmpty())
1278 if (!pNew.ParseXMLElement(pXML))
return FALSE;
1301 if (myTagCompare(d->lpszName, pXML->lpEndTag)==0)
1308 if (pXML->cbNewElement)
1318 if (myTagCompare(d->lpszName, pXML->lpNewElement)==0)
1324 pNew = addChild_priv(MEMORYINCREASE,
stringDup(pXML->lpNewElement,pXML->cbNewElement),0,-1);
1325 pXML->cbNewElement = 0;
1342 if (maybeAddTxT(pXML,token.pStr))
return FALSE;
1345 token = GetNextToken(pXML, &cbTemp, &xtype);
1348 if (xtype != eTokenText)
1353 lpszTemp = token.pStr;
1356 token = GetNextToken(pXML, &cbToken, &xtype);
1357 if (xtype != eTokenCloseTag)
1362 pXML->lpszText=pXML->lpXML+pXML->nIndex;
1367 if (myTagCompare(d->lpszName, lpszTemp) != 0)
1368#ifdef STRICT_PARSING
1371 pXML->nIndexMissigEndTag=pXML->nIndex;
1377 pXML->nIndexMissigEndTag=pXML->nIndex;
1378 pXML->lpEndTag = lpszTemp;
1379 pXML->cbEndTag = cbTemp;
1390 if (maybeAddTxT(pXML,token.pStr))
return FALSE;
1391 if (parseClearTag(pXML, token.pClr))
return FALSE;
1392 pXML->lpszText=pXML->lpXML+pXML->nIndex;
1418 lpszTemp = token.pStr;
1420 attrib = eAttribEquals;
1425 case eTokenCloseTag:
1427 status = eOutsideTag;
1428 pXML->lpszText=pXML->lpXML+pXML->nIndex;
1433 case eTokenShortHandClose:
1435 pXML->lpszText=pXML->lpXML+pXML->nIndex;
1439 case eTokenQuotedText:
1440 case eTokenTagStart:
1443 case eTokenDeclaration:
1460 addAttribute_priv(MEMORYINCREASE,
stringDup(lpszTemp,cbTemp), NULL);
1463 lpszTemp = token.pStr;
1469 case eTokenShortHandClose:
1470 case eTokenCloseTag:
1473 pXML->lpszText=pXML->lpXML+pXML->nIndex;
1475 if (d->isDeclaration &&
1476 (lpszTemp[cbTemp-1]) ==
_X(
'?'))
1484 addAttribute_priv(MEMORYINCREASE,
stringDup(lpszTemp,cbTemp), NULL);
1488 if (xtype == eTokenShortHandClose)
1495 status = eOutsideTag;
1503 attrib = eAttribValue;
1507 case eTokenQuotedText:
1508 case eTokenTagStart:
1510 case eTokenDeclaration:
1527 case eTokenQuotedText:
1530 if (d->isDeclaration &&
1531 (token.pStr[cbToken-1]) ==
_X(
'?'))
1539 if (xtype==eTokenQuotedText) { token.pStr++; cbToken-=2; }
1543 attrVal=fromXMLString(attrVal,cbToken,pXML);
1544 if (!attrVal)
return FALSE;
1546 addAttribute_priv(MEMORYINCREASE,
stringDup(lpszTemp,cbTemp),attrVal);
1550 attrib = eAttribName;
1554 case eTokenTagStart:
1556 case eTokenCloseTag:
1557 case eTokenShortHandClose:
1559 case eTokenDeclaration:
1572 if ((!d->isDeclaration)&&(d->pParent))
1574#ifdef STRICT_PARSING
1579 pXML->nIndexMissigEndTag=pXML->nIndex;
1581 maybeAddTxT(pXML,pXML->lpXML+pXML->nIndex);
1596 pResults->nLine = 1;
1597 pResults->nColumn = 1;
1598 while (xml.nIndex<nUpto)
1600 ch = getNextChar(&xml);
1601 if (ch !=
_X(
'\n')) pResults->nColumn++;
1605 pResults->nColumn=1;
1619 pResults->nColumn=0;
1625 struct XML xml={ lpszXML, lpszXML, 0, 0,
eXMLErrorNone, NULL, 0, NULL, 0,
TRUE };
1628 xnode.ParseXMLElement(&xml);
1631 if ((xnode.nChildNode()==1)&&(xnode.nElement()==1)) xnode=xnode.getChildNode();
1637 if (tag&&xstrlen(tag)&&((!name)||(xstricmp(xnode.getName(),tag))))
1641 while (i<xnode.nChildNode())
1643 nodeTmp=xnode.getChildNode(i);
1644 if (xstricmp(nodeTmp.getName(),tag)==0)
break;
1645 if (nodeTmp.isDeclaration()) { xnode=nodeTmp; i=0; }
else i++;
1647 if (i>=xnode.nChildNode())
1653 pResults->nColumn=0;
1669 pResults->error = error;
1676 CountLinesAndColumns(xml.lpXML, xml.nIndex, pResults);
1684 if (pResults) { pResults->nLine=0; pResults->nColumn=0; }
1685 FILE *f=xfopen(filename,
_X(
"rb"));
1687 fseek(f,0,SEEK_END);
1688 int l=ftell(f),headerSz=0;
1690 fseek(f,0,SEEK_SET);
1691 unsigned char *buf=(
unsigned char*)malloc(l+4);
1692 size_t dummy = fread(buf,l,1,f);
1694 buf[l]=0;buf[l+1]=0;buf[l+2]=0;buf[l+3]=0;
1696 if (guessWideCharChars)
1698 if (!myIsTextWideChar(buf,l))
1700 if ((buf[0]==0xef)&&(buf[1]==0xbb)&&(buf[2]==0xbf)) headerSz=3;
1701 XMLSTR b2=myMultiByteToWideChar((
const char*)(buf+headerSz));
1702 free(buf); buf=(
unsigned char*)b2; headerSz=0;
1705 if ((buf[0]==0xef)&&(buf[1]==0xff)) headerSz=2;
1706 if ((buf[0]==0xff)&&(buf[1]==0xfe)) headerSz=2;
1710 if (guessWideCharChars)
1712 if (myIsTextWideChar(buf,l))
1715 if ((buf[0]==0xef)&&(buf[1]==0xff)) headerSz=2;
1716 if ((buf[0]==0xff)&&(buf[1]==0xfe)) headerSz=2;
1717 char *b2=myWideCharToMultiByte((
const wchar_t*)(buf+headerSz));
1718 free(buf); buf=(
unsigned char*)b2; headerSz=0;
1721 if ((buf[0]==0xef)&&(buf[1]==0xbb)&&(buf[2]==0xbf)) headerSz=3;
1732static inline void charmemset(
XMLSTR dest,
XMLCHAR c,
int l) {
while (l--) *(dest++)=c; }
1739int XMLNode::CreateXMLStringR(XMLNodeData *pEntry,
XMLSTR lpszMarker,
int nFormat)
1744 int nChildFormat=-1;
1745 int nElementI=pEntry->nChild+pEntry->nText+pEntry->nClear;
1750#define LENSTR(lpsz) (lpsz ? xstrlen(lpsz) : 0)
1753 cbElement = (int)LENSTR(pEntry->lpszName);
1758 cb = nFormat == -1 ? 0 : nFormat;
1762 if (cb) charmemset(lpszMarker, INDENTCHAR,
sizeof(
XMLCHAR)*cb);
1764 lpszMarker[nResult++]=
_X(
'<');
1765 if (pEntry->isDeclaration) lpszMarker[nResult++]=
_X(
'?');
1766 xstrcpy(&lpszMarker[nResult], pEntry->lpszName);
1768 lpszMarker[nResult++]=
_X(
' ');
1772 nResult+=cbElement+2+cb;
1773 if (pEntry->isDeclaration) nResult++;
1778 for (i=0; i<pEntry->nAttribute; i++)
1781 cb = (int)LENSTR(pAttr->lpszName);
1784 if (lpszMarker) xstrcpy(&lpszMarker[nResult], pAttr->lpszName);
1787 if (pAttr->lpszValue)
1789 cb=(int)lengthXMLString(pAttr->lpszValue);
1792 lpszMarker[nResult]=
_X(
'=');
1793 lpszMarker[nResult+1]=
_X(
'"');
1794 if (cb) toXMLStringUnSafe(&lpszMarker[nResult+2],pAttr->lpszValue);
1795 lpszMarker[nResult+cb+2]=
_X(
'"');
1799 if (lpszMarker) lpszMarker[nResult] =
_X(
' ');
1805 if (pEntry->isDeclaration)
1809 lpszMarker[nResult-1]=
_X(
'?');
1810 lpszMarker[nResult]=
_X(
'>');
1815 if (lpszMarker) lpszMarker[nResult]=
_X(
'\n');
1822 if (lpszMarker) lpszMarker[nResult-1]=
_X(
'>');
1825 if (lpszMarker) lpszMarker[nResult]=
_X(
'\n');
1835 if (cbElement&&(!pEntry->isDeclaration)) nChildFormat=nFormat+1;
1836 else nChildFormat=nFormat;
1840 for (i=0; i<nElementI; i++)
1842 j=pEntry->pOrder[i];
1849 XMLCSTR pChild=pEntry->pText[j>>2];
1850 cb = (int)lengthXMLString(pChild);
1857 charmemset(&lpszMarker[nResult],INDENTCHAR,
sizeof(
XMLCHAR)*(nFormat + 1));
1858 toXMLStringUnSafe(&lpszMarker[nResult+nFormat+1],pChild);
1859 lpszMarker[nResult+nFormat+1+cb]=
_X(
'\n');
1861 nResult+=cb+nFormat+2;
1864 if (lpszMarker) toXMLStringUnSafe(&lpszMarker[nResult], pChild);
1874 XMLClear *pChild=pEntry->pClear+(j>>2);
1876 cb = (int)LENSTR(pChild->lpszOpenTag);
1883 charmemset(&lpszMarker[nResult], INDENTCHAR,
sizeof(
XMLCHAR)*(nFormat + 1));
1884 xstrcpy(&lpszMarker[nResult+nFormat+1], pChild->lpszOpenTag);
1886 nResult+=cb+nFormat+1;
1890 if (lpszMarker)xstrcpy(&lpszMarker[nResult], pChild->lpszOpenTag);
1896 cb = (int)LENSTR(pChild->lpszValue);
1899 if (lpszMarker) xstrcpy(&lpszMarker[nResult], pChild->lpszValue);
1904 cb = (int)LENSTR(pChild->lpszCloseTag);
1907 if (lpszMarker) xstrcpy(&lpszMarker[nResult], pChild->lpszCloseTag);
1913 if (lpszMarker) lpszMarker[nResult] =
_X(
'\n');
1923 nResult += CreateXMLStringR(pEntry->pChild[j>>2].d, lpszMarker ? lpszMarker + nResult : 0, nChildFormat);
1930 if ((cbElement)&&(!pEntry->isDeclaration))
1943 charmemset(&lpszMarker[nResult], INDENTCHAR,
sizeof(
XMLCHAR)*nFormat);
1948 xstrcpy(&lpszMarker[nResult],
_X(
"</"));
1950 xstrcpy(&lpszMarker[nResult], pEntry->lpszName);
1951 nResult += cbElement;
1955 xstrcpy(&lpszMarker[nResult],
_X(
">"));
1959 xstrcpy(&lpszMarker[nResult],
_X(
">\n"));
1964 if (nFormat != -1) nResult+=cbElement+4+nFormat;
1965 else nResult+=cbElement+3;
1976 xstrcpy(&lpszMarker[nResult],
_X(
"/>"));
1981 xstrcpy(&lpszMarker[nResult],
_X(
"/>\n"));
1987 nResult += nFormat == -1 ? 2 : 3;
2006XMLSTR XMLNode::createXMLString(
int nFormat,
int *pnSize)
const
2008 if (!d) {
if (pnSize) *pnSize=0;
return NULL; }
2010 XMLSTR lpszResult = NULL;
2014 if (!dropWhiteSpace) nFormat=0;
2015 nFormat = nFormat ? 0 : -1;
2016 cbStr = CreateXMLStringR(d, 0, nFormat);
2021 CreateXMLStringR(d, lpszResult, nFormat);
2022 if (pnSize) *pnSize = cbStr;
2026int XMLNode::detachFromParent(XMLNodeData *d)
2028 XMLNode *pa=d->pParent->pChild;
2030 while (((
void*)(pa[i].d))!=((
void*)d)) i++;
2031 d->pParent->nChild--;
2032 if (d->pParent->nChild) memmove(pa+i,pa+i+1,(d->pParent->nChild-i)*
sizeof(
XMLNode));
2033 else { free(pa); d->pParent->pChild=NULL; }
2034 return removeOrderElement(d->pParent,
eNodeChild,i);
2037XMLNode::~XMLNode() { deleteNodeContent_priv(1,0); }
2038void XMLNode::deleteNodeContent(){ deleteNodeContent_priv(0,1); }
2039void XMLNode::deleteNodeContent_priv(
char isInDestuctor,
char force)
2042 if (isInDestuctor) (d->ref_count)--;
2043 if ((d->ref_count==0)||force)
2046 if (d->pParent) detachFromParent(d);
2047 for(i=0; i<d->nChild; i++) { d->pChild[i].d->pParent=NULL; d->pChild[i].deleteNodeContent_priv(1,force); }
2049 for(i=0; i<d->nText; i++) free((
void*)d->pText[i]);
2051 for(i=0; i<d->nClear; i++) free((
void*)d->pClear[i].lpszValue);
2053 for(i=0; i<d->nAttribute; i++)
2055 free((
void*)d->pAttribute[i].lpszName);
2056 if (d->pAttribute[i].lpszValue) free((
void*)d->pAttribute[i].lpszValue);
2058 myFree(d->pAttribute);
2060 myFree((
void*)d->lpszName);
2061 d->nChild=0; d->nText=0; d->nClear=0; d->nAttribute=0;
2062 d->pChild=NULL; d->pText=NULL; d->pClear=NULL; d->pAttribute=NULL;
2063 d->pOrder=NULL; d->lpszName=NULL; d->pParent=NULL;
2065 if (d->ref_count==0)
2074 XMLNodeData *dc=childNode.d;
2075 if ((!dc)||(!d))
return childNode;
2076 if (dc->pParent) {
if ((detachFromParent(dc)<=pos)&&(dc->pParent==d)) pos--; }
else dc->ref_count++;
2081 d->pChild[pos].d=dc;
2086void XMLNode::deleteAttribute(
int i)
2088 if ((!d)||(i<0)||(i>=d->nAttribute))
return;
2091 free((
void*)p->lpszName);
2092 if (p->lpszValue) free((
void*)p->lpszValue);
2093 if (d->nAttribute) memmove(p,p+1,(d->nAttribute-i)*
sizeof(
XMLAttribute));
else { free(p); d->pAttribute=NULL; }
2097void XMLNode::deleteAttribute(
XMLCSTR lpszName)
2106 if (!d) {
if (lpszNewValue) free(lpszNewValue);
if (lpszNewName) free(lpszNewName);
return NULL; }
2107 if (i>=d->nAttribute)
2113 if (p->lpszValue&&p->lpszValue!=lpszNewValue) free((
void*)p->lpszValue);
2114 p->lpszValue=lpszNewValue;
2115 if (lpszNewName&&p->lpszName!=lpszNewName) { free((
void*)p->lpszName); p->lpszName=lpszNewName; };
2137int XMLNode::indexText(
XMLCSTR lpszValue)
const
2141 if (!lpszValue) {
if (l)
return 0;
return -1; }
2143 for (i=0; i<l; i++)
if (lpszValue==p[i])
return i;
2147void XMLNode::deleteText(
int i)
2149 if ((!d)||(i<0)||(i>=d->nText))
return;
2153 if (d->nText) memmove(p,p+1,(d->nText-i)*
sizeof(
XMLCSTR));
else { free(p); d->pText=NULL; }
2157void XMLNode::deleteText(
XMLCSTR lpszValue) {
deleteText(indexText(lpszValue)); }
2161 if (!d) {
if (lpszNewValue) free(lpszNewValue);
return NULL; }
2164 if (*p!=lpszNewValue) { free((
void*)*p); *p=lpszNewValue; }
2165 return lpszNewValue;
2170 if (!d) {
if (lpszNewValue) free(lpszNewValue);
return NULL; }
2171 int i=indexText(lpszOldValue);
2176void XMLNode::deleteClear(
int i)
2178 if ((!d)||(i<0)||(i>=d->nClear))
return;
2181 free((
void*)p->lpszValue);
2182 if (d->nClear) memmove(p,p+1,(d->nClear-i)*
sizeof(
XMLClear));
else { free(p); d->pClear=NULL; }
2186int XMLNode::indexClear(
XMLCSTR lpszValue)
const
2190 if (!lpszValue) {
if (l)
return 0;
return -1; }
2192 for (i=0; i<l; i++)
if (lpszValue==p[i].lpszValue)
return i;
2201 if (!d) {
if (lpszNewContent) free(lpszNewContent);
return NULL; }
2204 if (lpszNewContent!=p->lpszValue) { free((
void*)p->lpszValue); p->lpszValue=lpszNewContent; }
2210 if (!d) {
if (lpszNewContent) free(lpszNewContent);
return NULL; }
2211 int i=indexClear(lpszOldValue);
2227 deleteNodeContent_priv(1,0);
2229 if (d) (d->ref_count) ++ ;
2234XMLNode::XMLNode(
const XMLNode &A)
2238 if (d) (d->ref_count)++ ;
2241int XMLNode::nChildNode(
XMLCSTR name)
const
2244 int i,j=0,n=d->nChild;
2248 if (xstricmp(pc->d->lpszName, name)==0) j++;
2257 int i=0,n=d->nChild;
2262 if (xstricmp(pc->d->lpszName, name)==0)
2280int XMLNode::positionOfText (
int i)
const {
if (i>=d->nText ) i=d->nText-1;
return findPosition(d,i,
eNodeText ); }
2281int XMLNode::positionOfClear (
int i)
const {
if (i>=d->nClear) i=d->nClear-1;
return findPosition(d,i,
eNodeClear); }
2282int XMLNode::positionOfChildNode(
int i)
const {
if (i>=d->nChild) i=d->nChild-1;
return findPosition(d,i,
eNodeChild); }
2283int XMLNode::positionOfText (
XMLCSTR lpszValue)
const {
return positionOfText (indexText (lpszValue)); }
2286int XMLNode::positionOfChildNode(
XMLNode x)
const
2288 if ((!d)||(!x.d))
return -1;
2289 XMLNodeData *dd=x.d;
2292 while (i--)
if (pc[i].d==dd)
return findPosition(d,i,
eNodeChild);
2295int XMLNode::positionOfChildNode(
XMLCSTR name,
int count)
const
2299 do {
getChildNode(name,&j);
if (j<0)
return -1; }
while (count--);
2319 t=x.getAttribute(attributeName,&j);
2320 if (t&&(xstricmp(attributeValue,t)==0)) {
if (k) *k=i+1;
return x; }
2324 if (x.isAttributeSet(attributeName)) {
if (k) *k=i+1;
return x; }
2327 }
while (!x.isEmpty());
2334 if (!d)
return NULL;
2335 int i=0,n=d->nAttribute;
2340 if (xstricmp(pAttr->lpszName, lpszAttrib)==0)
2343 return pAttr->lpszValue;
2350char XMLNode::isAttributeSet(
XMLCSTR lpszAttrib)
const
2352 if (!d)
return FALSE;
2353 int i,n=d->nAttribute;
2357 if (xstricmp(pAttr->lpszName, lpszAttrib)==0)
2368 if (!d)
return NULL;
2381 c.attrib=d->pAttribute[i];
2386 i=(d->pOrder[i])>>2;
2389 case eNodeChild: c.child = d->pChild[i];
break;
2390 case eNodeText: c.text = d->pText[i];
break;
2391 case eNodeClear: c.clear = d->pClear[i];
break;
2397XMLCSTR XMLNode::getName()
const {
if (!d)
return NULL;
return d->lpszName; }
2398int XMLNode::nText()
const {
if (!d)
return 0;
return d->nText; }
2399int XMLNode::nChildNode()
const {
if (!d)
return 0;
return d->nChild; }
2400int XMLNode::nAttribute()
const {
if (!d)
return 0;
return d->nAttribute; }
2401int XMLNode::nClear()
const {
if (!d)
return 0;
return d->nClear; }
2402int XMLNode::nElement()
const {
if (!d)
return 0;
return d->nAttribute+d->nChild+d->nText+d->nClear; }
2403XMLClear XMLNode::getClear (
int i)
const {
if ((!d)||(i>=d->nClear ))
return emptyXMLClear;
return d->pClear[i]; }
2405XMLCSTR XMLNode::getAttributeName (
int i)
const {
if ((!d)||(i>=d->nAttribute))
return NULL;
return d->pAttribute[i].lpszName; }
2406XMLCSTR XMLNode::getAttributeValue(
int i)
const {
if ((!d)||(i>=d->nAttribute))
return NULL;
return d->pAttribute[i].lpszValue; }
2407XMLCSTR XMLNode::getText (
int i)
const {
if ((!d)||(i>=d->nText ))
return NULL;
return d->pText[i]; }
2408XMLNode XMLNode::getChildNode (
int i)
const {
if ((!d)||(i>=d->nChild ))
return emptyXMLNode;
return d->pChild[i]; }
2410char XMLNode::isDeclaration ( )
const {
if (!d)
return 0;
return d->isDeclaration; }
2411char XMLNode::isEmpty ( )
const {
return (d==NULL); }
2412XMLNode XMLNode::emptyNode ( ) {
return XMLNode::emptyXMLNode; }
2414XMLNode XMLNode::addChild(
XMLCSTR lpszName,
char isDeclaration,
int pos)
2416XMLNode XMLNode::addChild_WOSD(
XMLSTR lpszName,
char isDeclaration,
int pos)
2421 {
return addAttribute_priv(0,lpszName,lpszValuev); }
2423 {
return addText_priv(0,
stringDup(lpszValue),pos); }
2425 {
return addText_priv(0,lpszValue,pos); }
2427 {
return addClear_priv(0,
stringDup(lpszValue),lpszOpen,lpszClose,pos); }
2429 {
return addClear_priv(0,lpszValue,lpszOpen,lpszClose,pos); }
2449char XMLNode::setGlobalOptions(XMLCharEncoding _characterEncoding,
char _guessWideCharChars,
char _dropWhiteSpace)
2451 guessWideCharChars=_guessWideCharChars; dropWhiteSpace=_dropWhiteSpace;
2453 if (_characterEncoding) characterEncoding=_characterEncoding;
2455 switch(_characterEncoding)
2457 case encoding_UTF8: characterEncoding=_characterEncoding; XML_ByteTable=XML_utf8ByteTable;
break;
2458 case encoding_ascii: characterEncoding=_characterEncoding; XML_ByteTable=XML_asciiByteTable;
break;
2459 case encoding_ShiftJIS: characterEncoding=_characterEncoding; XML_ByteTable=XML_sjisByteTable;
break;
2466XMLNode::XMLCharEncoding XMLNode::guessCharEncoding(
void *buf,
int l,
char useXMLEncodingAttribute)
2472 if (guessWideCharChars&&(myIsTextWideChar(buf,l)))
return (
XMLCharEncoding)0;
2473 unsigned char *b=(
unsigned char*)buf;
2474 if ((b[0]==0xef)&&(b[1]==0xbb)&&(b[2]==0xbf))
return encoding_UTF8;
2480 switch (XML_utf8ByteTable[b[i]])
2482 case 4: i++;
if ((i<l)&&(b[i]& 0xC0)!=0x80) { bestGuess=
encoding_ascii; i=l; }
2483 case 3: i++;
if ((i<l)&&(b[i]& 0xC0)!=0x80) { bestGuess=
encoding_ascii; i=l; }
2484 case 2: i++;
if ((i<l)&&(b[i]& 0xC0)!=0x80) { bestGuess=
encoding_ascii; i=l; }
2488 if (!useXMLEncodingAttribute)
return bestGuess;
2495 b=(
unsigned char*)strstr(bb,
"encoding");
2496 if (!b)
return bestGuess;
2497 b+=8;
while XML_isSPACECHAR(*b) b++;
if (*b!=
'=')
return bestGuess;
2498 b++;
while XML_isSPACECHAR(*b) b++;
if ((*b!=
'\'')&&(*b!=
'"'))
return bestGuess;
2499 b++;
while XML_isSPACECHAR(*b) b++;
2501 if ((
_strnicmp((
char*)b,
"utf-8",5)==0)||
2508 if ((
_strnicmp((
char*)b,
"shiftjis",8)==0)||
2509 (
_strnicmp((
char*)b,
"shift-jis",9)==0)||
2515#undef XML_isSPACECHAR
2521static const char base64Fillchar =
_X(
'=');
2524XMLCSTR base64EncodeTable=
_X(
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
2528const unsigned char base64DecodeTable[] = {
2529 99,98,98,98,98,98,98,98,98,97, 97,98,98,97,98,98,98,98,98,98, 98,98,98,98,98,98,98,98,98,98,
2530 98,98,97,98,98,98,98,98,98,98, 98,98,98,62,98,98,98,63,52,53, 54,55,56,57,58,59,60,61,98,98,
2531 98,96,98,98,98, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, 15,16,17,18,19,20,21,22,23,24,
2532 25,98,98,98,98,98,98,26,27,28, 29,30,31,32,33,34,35,36,37,38, 39,40,41,42,43,44,45,46,47,48,
2533 49,50,51,98,98,98,98,98,98,98, 98,98,98,98,98,98,98,98,98,98, 98,98,98,98,98,98,98,98,98,98,
2534 98,98,98,98,98,98,98,98,98,98, 98,98,98,98,98,98,98,98,98,98, 98,98,98,98,98,98,98,98,98,98,
2535 98,98,98,98,98,98,98,98,98,98, 98,98,98,98,98,98,98,98,98,98, 98,98,98,98,98,98,98,98,98,98,
2536 98,98,98,98,98,98,98,98,98,98, 98,98,98,98,98,98,98,98,98,98, 98,98,98,98,98,98,98,98,98,98,
2537 98,98,98,98,98,98,98,98,98,98, 98,98,98,98,98,98
2540XMLParserBase64Tool::~XMLParserBase64Tool(){
freeBuffer(); }
2542void XMLParserBase64Tool::freeBuffer(){
if (buf) free(buf); buf=NULL; buflen=0; }
2544int XMLParserBase64Tool::encodeLength(
int inlen,
char formatted)
2546 unsigned int i=((inlen-1)/3*4+4+1);
2547 if (formatted) i+=inlen/54;
2551XMLSTR XMLParserBase64Tool::encode(
unsigned char *inbuf,
unsigned int inlen,
char formatted)
2553 int i=
encodeLength(inlen,formatted),k=17,eLen=inlen/3,j;
2559 j=(inbuf[0]<<16)|(inbuf[1]<<8)|inbuf[2]; inbuf+=3;
2561 *(curr++)=base64EncodeTable[ j>>18 ];
2562 *(curr++)=base64EncodeTable[(j>>12)&0x3f];
2563 *(curr++)=base64EncodeTable[(j>> 6)&0x3f];
2564 *(curr++)=base64EncodeTable[(j )&0x3f];
2565 if (formatted) {
if (!k) { *(curr++)=
_X(
'\n'); k=18; } k--; }
2570 *(curr++)=base64EncodeTable[ inbuf[0]>>2 ];
2571 *(curr++)=base64EncodeTable[(inbuf[0]<<4)&0x3F];
2572 *(curr++)=base64Fillchar;
2573 *(curr++)=base64Fillchar;
2576 j=(inbuf[0]<<8)|inbuf[1];
2577 *(curr++)=base64EncodeTable[ j>>10 ];
2578 *(curr++)=base64EncodeTable[(j>> 4)&0x3f];
2579 *(curr++)=base64EncodeTable[(j<< 2)&0x3f];
2580 *(curr++)=base64Fillchar;
2586unsigned int XMLParserBase64Tool::decodeSize(
XMLCSTR data,
XMLError *xe)
2597 c=base64DecodeTable[(
unsigned char)(*data)];
2603 if (size==0)
return 0;
2604 do { data--; size--; }
while(*data==base64Fillchar); size++;
2605 return (
unsigned int)((size*3)/4);
2608unsigned char XMLParserBase64Tool::decode(
XMLCSTR data,
unsigned char *buf,
int len,
XMLError *xe)
2617#define BASE64DECODE_READ_NEXT_CHAR(c) \
2619 if (data[i]>255){ c=98; break; } \
2620 c=base64DecodeTable[(unsigned char)data[i++]]; \
2622 if(c==98){ if(xe)*xe=eXMLErrorBase64DecodeIllegalCharacter; return 0; }
2624#define BASE64DECODE_READ_NEXT_CHAR(c) \
2625 do { c=base64DecodeTable[(unsigned char)data[i++]]; }while (c==97); \
2626 if(c==98){ if(xe)*xe=eXMLErrorBase64DecodeIllegalCharacter; return 0; }
2629 BASE64DECODE_READ_NEXT_CHAR(c)
2630 if (c==99) {
return 2; }
2633 if (p==(
int)len)
return 2;
2638 BASE64DECODE_READ_NEXT_CHAR(d)
2641 buf[p++]=(
unsigned char)((c<<2)|((d>>4)&0x3));
2643 BASE64DECODE_READ_NEXT_CHAR(c)
2647 if (c==96)
return 2;
2652 buf[p++]=(
unsigned char)(((d<<4)&0xf0)|((c>>2)&0xf));
2654 BASE64DECODE_READ_NEXT_CHAR(d)
2658 if (d==96)
return 2;
2663 buf[p++]=(
unsigned char)(((c<<6)&0xc0)|d);
2666#undef BASE64DECODE_READ_NEXT_CHAR
2668void XMLParserBase64Tool::alloc(
int newsize)
2670 if ((!buf)&&(newsize)) { buf=malloc(newsize); buflen=newsize;
return; }
2671 if (newsize>buflen) { buf=realloc(buf,newsize); buflen=newsize; }
2674unsigned char *XMLParserBase64Tool::decode(
XMLCSTR data,
int *outlen,
XMLError *xe)
2678 if (outlen) *outlen=len;
2679 if (!len)
return NULL;
2681 if(!
decode(data,(
unsigned char*)buf,len,xe)){
return NULL; }
2682 return (
unsigned char*)buf;
2687bool XMLNode::UnitTest()
2693 "<library name=\"central\" open=\"true\">"
2694 "<book id=\"b1\" lang=\"en\">"
2695 "<title>Hello World</title>"
2696 "<author>Ada</author>"
2698 "<book id=\"b2\" lang=\"fr\">"
2699 "<title>Bonjour</title>"
2704 XMLNode root = XMLNode::parseString(doc,
"library", &results);
2707 XMLNode::getError(results.error), results.nLine, results.nColumn);
2710 if (root.isEmpty()) {
2718 if (!root.getName() || strcmp(root.getName(),
"library") != 0) {
2719 unittest::fail(
"root name mismatch: expected 'library', got '%s'",
2720 root.getName() ? root.getName() :
"(null)");
2725 if (root.nAttribute() != 2) {
2726 unittest::fail(
"root attribute count mismatch: expected 2, got %d", root.nAttribute());
2729 XMLCSTR nameAttr = root.getAttribute(
"name");
2730 if (!nameAttr || strcmp(nameAttr,
"central") != 0) {
2731 unittest::fail(
"root @name mismatch: expected 'central', got '%s'", nameAttr ? nameAttr :
"(null)");
2734 XMLCSTR openAttr = root.getAttribute(
"open");
2735 if (!openAttr || strcmp(openAttr,
"true") != 0) {
2736 unittest::fail(
"root @open mismatch: expected 'true', got '%s'", openAttr ? openAttr :
"(null)");
2739 if (!root.isAttributeSet(
"name")) {
2747 if (root.nChildNode() != 2) {
2748 unittest::fail(
"root child count mismatch: expected 2, got %d", root.nChildNode());
2751 if (root.nChildNode(
"book") != 2) {
2752 unittest::fail(
"root book-child count mismatch: expected 2, got %d", root.nChildNode(
"book"));
2756 XMLNode book1 = root.getChildNode(
"book", 0);
2757 if (book1.isEmpty() || !book1.getName() || strcmp(book1.getName(),
"book") != 0) {
2761 XMLCSTR id1 = book1.getAttribute(
"id");
2762 if (!id1 || strcmp(id1,
"b1") != 0) {
2763 unittest::fail(
"book[0] @id mismatch: expected 'b1', got '%s'", id1 ? id1 :
"(null)");
2766 XMLCSTR lang1 = book1.getAttribute(
"lang");
2767 if (!lang1 || strcmp(lang1,
"en") != 0) {
2768 unittest::fail(
"book[0] @lang mismatch: expected 'en', got '%s'", lang1 ? lang1 :
"(null)");
2773 if (book1.nChildNode() != 2) {
2774 unittest::fail(
"book[0] child count mismatch: expected 2, got %d", book1.nChildNode());
2780 XMLNode title1 = book1.getChildNode(
"title", 0);
2781 if (title1.isEmpty()) {
2785 if (title1.nText() < 1 || !title1.getText(0) || strcmp(title1.getText(0),
"Hello World") != 0) {
2786 unittest::fail(
"book[0]/title text mismatch: expected 'Hello World', got '%s'",
2787 title1.getText(0) ? title1.getText(0) :
"(null)");
2790 XMLNode author1 = book1.getChildNode(
"author", 0);
2791 if (author1.isEmpty() || !author1.getText(0) || strcmp(author1.getText(0),
"Ada") != 0) {
2792 unittest::fail(
"book[0]/author text mismatch: expected 'Ada', got '%s'",
2793 author1.getText(0) ? author1.getText(0) :
"(null)");
2798 XMLNode book2 = root.getChildNode(
"book", 1);
2799 XMLCSTR id2 = book2.getAttribute(
"id");
2800 if (!id2 || strcmp(id2,
"b2") != 0) {
2801 unittest::fail(
"book[1] @id mismatch: expected 'b2', got '%s'", id2 ? id2 :
"(null)");
2804 if (book2.nChildNode() != 1) {
2805 unittest::fail(
"book[1] child count mismatch: expected 1, got %d", book2.nChildNode());
2808 XMLNode title2 = book2.getChildNode(
"title", 0);
2809 if (title2.isEmpty() || !title2.getText(0) || strcmp(title2.getText(0),
"Bonjour") != 0) {
2810 unittest::fail(
"book[1]/title text mismatch: expected 'Bonjour', got '%s'",
2811 title2.getText(0) ? title2.getText(0) :
"(null)");
2817 XMLNode::parseString(
"<a><b></a>",
"a", &badResults);
2819 unittest::fail(
"malformed XML <a><b></a> was accepted without error");
2822 unittest::detail(
"malformed-doc error correctly reported: %s", XMLNode::getError(badResults.error));
2827 const int iterations = 20000;
2828 const size_t docBytes = strlen(doc);
2830 for (
int i = 0; i < iterations; i++) {
2831 XMLNode n = XMLNode::parseString(doc,
"library");
2833 if (n.nChildNode() != 2) {
2834 unittest::fail(
"throughput iteration %d produced wrong child count", i);
2839 if (us <= 0.0) us = 1.0;
2840 double parsesPerSec = (double)iterations / us * 1e6;
2841 double mbPerSec = ((double)iterations * (double)docBytes) / us;
2842 unittest::detail(
"parsed %d docs of %lu bytes in %.0f us", iterations, (
unsigned long)docBytes, us);
2845 unittest::metric(
"avg_parse_latency", us / (
double)iterations,
"us",
false);
2853 "xml", XMLNode::UnitTest,
2854 "XML parser: parse nested elements/attributes/text and parse throughput",
"util");
CMSDK time: µs-resolution 64-bit timestamps and the Time Mapping Constant (TMC).
Core fixed-width scalar typedefs and the PsyType / PsyContext hierarchical identifiers.
Small, dependency-free unit test harness used by all CMSDK object tests.
static UnitTestRunner & instance()
Access the singleton (created on first use).
void registerTest(const char *name, UnitTestFunc func, const char *description="", const char *category="", bool inDefaultRun=true)
Register a test with the runner.
uint64 GetTimeNow()
Return the current absolute time (µs since year 0) according to the TMC.
void fail(const char *fmt,...)
Set an explanatory reason shown on the FAIL line.
void metric(const char *name, double value, const char *unit="", bool higherIsBetter=true)
Record a performance metric.
void detail(const char *fmt,...)
Verbose-only indented diagnostic line (shown only when verbose=1).
void progress(int percent, const char *action)
Report progress with a short description of the current action.
XMLDLLENTRY void freeXMLString(XMLSTR t)
void Register_XMLParser_Tests()
struct cmlabs::XMLResults XMLResults
struct cmlabs::XMLNodeContents XMLNodeContents
struct XMLDLLENTRY cmlabs::XMLNode XMLNode
XMLDLLENTRY XMLSTR stringDup(XMLCSTR source, int cbData=0)
@ eXMLErrorCannotOpenWriteFile
@ eXMLErrorUnexpectedToken
@ eXMLErrorFirstTagNotFound
@ eXMLErrorCannotWriteFile
@ eXMLErrorBase64DecodeBufferTooSmall
@ eXMLErrorBase64DecodeIllegalCharacter
@ eXMLErrorUnmatchedEndClearTag
@ eXMLErrorBase64DataSizeIsNotMultipleOf4
@ eXMLErrorUnknownCharacterEntity
@ eXMLErrorMissingTagName
@ eXMLErrorBase64DecodeTruncatedData
@ eXMLErrorMissingEndTagName
@ eXMLErrorUnmatchedEndTag
@ eXMLErrorCharConversionError
struct cmlabs::XMLClear XMLClear
struct cmlabs::XMLAttribute XMLAttribute
XMLCSTR addText_WOSD(XMLSTR lpszValue, int pos=-1)
int positionOfClear(int i=0) const
static XMLNode parseString(XMLCSTR lpXMLString, XMLCSTR tag=NULL, XMLResults *pResults=NULL)
XMLCSTR updateText_WOSD(XMLSTR lpszNewValue, int i=0)
char isDeclaration() const
static XMLNode emptyXMLNode
static XMLCharEncoding guessCharEncoding(void *buffer, int bufLen, char useXMLEncodingAttribute=1)
void deleteAttribute(XMLCSTR lpszName)
XMLAttribute getAttribute(int i=0) const
XMLNode getChildNode(int i=0) const
int positionOfText(int i=0) const
XMLClear * addClear_WOSD(XMLSTR lpszValue, XMLCSTR lpszOpen=NULL, XMLCSTR lpszClose=NULL, int pos=-1)
static char setGlobalOptions(XMLCharEncoding characterEncoding=XMLNode::encoding_UTF8, char guessWideCharChars=1, char dropWhiteSpace=1)
XMLClear * updateClear_WOSD(XMLSTR lpszNewContent, int i=0)
XMLCSTR updateName_WOSD(XMLSTR lpszName)
XMLSTR createXMLString(int nFormat=1, int *pnSize=NULL) const
int positionOfChildNode(int i=0) const
void deleteClear(int i=0)
static XMLAttribute emptyXMLAttribute
XMLAttribute * addAttribute_WOSD(XMLSTR lpszName, XMLSTR lpszValue)
XMLAttribute * updateAttribute_WOSD(XMLAttribute *newAttribute, XMLAttribute *oldAttribute)
static XMLClear emptyXMLClear
Small recursive XML DOM parser (XMLNode) used by CMSDK for all PsySpec XML parsing.