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--;
2035 if (d->pParent->nChild) memmove((
void*)(pa+i),(
void*)(pa+i+1),(d->pParent->nChild-i)*
sizeof(
XMLNode));
2036 else { free(pa); d->pParent->pChild=NULL; }
2037 return removeOrderElement(d->pParent,
eNodeChild,i);
2040XMLNode::~XMLNode() { deleteNodeContent_priv(1,0); }
2041void XMLNode::deleteNodeContent(){ deleteNodeContent_priv(0,1); }
2042void XMLNode::deleteNodeContent_priv(
char isInDestuctor,
char force)
2045 if (isInDestuctor) (d->ref_count)--;
2046 if ((d->ref_count==0)||force)
2049 if (d->pParent) detachFromParent(d);
2050 for(i=0; i<d->nChild; i++) { d->pChild[i].d->pParent=NULL; d->pChild[i].deleteNodeContent_priv(1,force); }
2052 for(i=0; i<d->nText; i++) free((
void*)d->pText[i]);
2054 for(i=0; i<d->nClear; i++) free((
void*)d->pClear[i].lpszValue);
2056 for(i=0; i<d->nAttribute; i++)
2058 free((
void*)d->pAttribute[i].lpszName);
2059 if (d->pAttribute[i].lpszValue) free((
void*)d->pAttribute[i].lpszValue);
2061 myFree(d->pAttribute);
2063 myFree((
void*)d->lpszName);
2064 d->nChild=0; d->nText=0; d->nClear=0; d->nAttribute=0;
2065 d->pChild=NULL; d->pText=NULL; d->pClear=NULL; d->pAttribute=NULL;
2066 d->pOrder=NULL; d->lpszName=NULL; d->pParent=NULL;
2068 if (d->ref_count==0)
2077 XMLNodeData *dc=childNode.d;
2078 if ((!dc)||(!d))
return childNode;
2079 if (dc->pParent) {
if ((detachFromParent(dc)<=pos)&&(dc->pParent==d)) pos--; }
else dc->ref_count++;
2084 d->pChild[pos].d=dc;
2089void XMLNode::deleteAttribute(
int i)
2091 if ((!d)||(i<0)||(i>=d->nAttribute))
return;
2094 free((
void*)p->lpszName);
2095 if (p->lpszValue) free((
void*)p->lpszValue);
2096 if (d->nAttribute) memmove(p,p+1,(d->nAttribute-i)*
sizeof(
XMLAttribute));
else { free(p); d->pAttribute=NULL; }
2100void XMLNode::deleteAttribute(
XMLCSTR lpszName)
2109 if (!d) {
if (lpszNewValue) free(lpszNewValue);
if (lpszNewName) free(lpszNewName);
return NULL; }
2110 if (i>=d->nAttribute)
2116 if (p->lpszValue&&p->lpszValue!=lpszNewValue) free((
void*)p->lpszValue);
2117 p->lpszValue=lpszNewValue;
2118 if (lpszNewName&&p->lpszName!=lpszNewName) { free((
void*)p->lpszName); p->lpszName=lpszNewName; };
2140int XMLNode::indexText(
XMLCSTR lpszValue)
const
2144 if (!lpszValue) {
if (l)
return 0;
return -1; }
2146 for (i=0; i<l; i++)
if (lpszValue==p[i])
return i;
2150void XMLNode::deleteText(
int i)
2152 if ((!d)||(i<0)||(i>=d->nText))
return;
2156 if (d->nText) memmove(p,p+1,(d->nText-i)*
sizeof(
XMLCSTR));
else { free(p); d->pText=NULL; }
2160void XMLNode::deleteText(
XMLCSTR lpszValue) {
deleteText(indexText(lpszValue)); }
2164 if (!d) {
if (lpszNewValue) free(lpszNewValue);
return NULL; }
2167 if (*p!=lpszNewValue) { free((
void*)*p); *p=lpszNewValue; }
2168 return lpszNewValue;
2173 if (!d) {
if (lpszNewValue) free(lpszNewValue);
return NULL; }
2174 int i=indexText(lpszOldValue);
2179void XMLNode::deleteClear(
int i)
2181 if ((!d)||(i<0)||(i>=d->nClear))
return;
2184 free((
void*)p->lpszValue);
2185 if (d->nClear) memmove(p,p+1,(d->nClear-i)*
sizeof(
XMLClear));
else { free(p); d->pClear=NULL; }
2189int XMLNode::indexClear(
XMLCSTR lpszValue)
const
2193 if (!lpszValue) {
if (l)
return 0;
return -1; }
2195 for (i=0; i<l; i++)
if (lpszValue==p[i].lpszValue)
return i;
2204 if (!d) {
if (lpszNewContent) free(lpszNewContent);
return NULL; }
2207 if (lpszNewContent!=p->lpszValue) { free((
void*)p->lpszValue); p->lpszValue=lpszNewContent; }
2213 if (!d) {
if (lpszNewContent) free(lpszNewContent);
return NULL; }
2214 int i=indexClear(lpszOldValue);
2230 deleteNodeContent_priv(1,0);
2232 if (d) (d->ref_count) ++ ;
2237XMLNode::XMLNode(
const XMLNode &A)
2241 if (d) (d->ref_count)++ ;
2244int XMLNode::nChildNode(
XMLCSTR name)
const
2247 int i,j=0,n=d->nChild;
2251 if (xstricmp(pc->d->lpszName, name)==0) j++;
2260 int i=0,n=d->nChild;
2265 if (xstricmp(pc->d->lpszName, name)==0)
2283int XMLNode::positionOfText (
int i)
const {
if (i>=d->nText ) i=d->nText-1;
return findPosition(d,i,
eNodeText ); }
2284int XMLNode::positionOfClear (
int i)
const {
if (i>=d->nClear) i=d->nClear-1;
return findPosition(d,i,
eNodeClear); }
2285int XMLNode::positionOfChildNode(
int i)
const {
if (i>=d->nChild) i=d->nChild-1;
return findPosition(d,i,
eNodeChild); }
2286int XMLNode::positionOfText (
XMLCSTR lpszValue)
const {
return positionOfText (indexText (lpszValue)); }
2289int XMLNode::positionOfChildNode(
XMLNode x)
const
2291 if ((!d)||(!x.d))
return -1;
2292 XMLNodeData *dd=x.d;
2295 while (i--)
if (pc[i].d==dd)
return findPosition(d,i,
eNodeChild);
2298int XMLNode::positionOfChildNode(
XMLCSTR name,
int count)
const
2302 do {
getChildNode(name,&j);
if (j<0)
return -1; }
while (count--);
2322 t=x.getAttribute(attributeName,&j);
2323 if (t&&(xstricmp(attributeValue,t)==0)) {
if (k) *k=i+1;
return x; }
2327 if (x.isAttributeSet(attributeName)) {
if (k) *k=i+1;
return x; }
2330 }
while (!x.isEmpty());
2337 if (!d)
return NULL;
2338 int i=0,n=d->nAttribute;
2343 if (xstricmp(pAttr->lpszName, lpszAttrib)==0)
2346 return pAttr->lpszValue;
2353char XMLNode::isAttributeSet(
XMLCSTR lpszAttrib)
const
2355 if (!d)
return FALSE;
2356 int i,n=d->nAttribute;
2360 if (xstricmp(pAttr->lpszName, lpszAttrib)==0)
2371 if (!d)
return NULL;
2384 c.attrib=d->pAttribute[i];
2389 i=(d->pOrder[i])>>2;
2392 case eNodeChild: c.child = d->pChild[i];
break;
2393 case eNodeText: c.text = d->pText[i];
break;
2394 case eNodeClear: c.clear = d->pClear[i];
break;
2400XMLCSTR XMLNode::getName()
const {
if (!d)
return NULL;
return d->lpszName; }
2401int XMLNode::nText()
const {
if (!d)
return 0;
return d->nText; }
2402int XMLNode::nChildNode()
const {
if (!d)
return 0;
return d->nChild; }
2403int XMLNode::nAttribute()
const {
if (!d)
return 0;
return d->nAttribute; }
2404int XMLNode::nClear()
const {
if (!d)
return 0;
return d->nClear; }
2405int XMLNode::nElement()
const {
if (!d)
return 0;
return d->nAttribute+d->nChild+d->nText+d->nClear; }
2406XMLClear XMLNode::getClear (
int i)
const {
if ((!d)||(i>=d->nClear ))
return emptyXMLClear;
return d->pClear[i]; }
2408XMLCSTR XMLNode::getAttributeName (
int i)
const {
if ((!d)||(i>=d->nAttribute))
return NULL;
return d->pAttribute[i].lpszName; }
2409XMLCSTR XMLNode::getAttributeValue(
int i)
const {
if ((!d)||(i>=d->nAttribute))
return NULL;
return d->pAttribute[i].lpszValue; }
2410XMLCSTR XMLNode::getText (
int i)
const {
if ((!d)||(i>=d->nText ))
return NULL;
return d->pText[i]; }
2411XMLNode XMLNode::getChildNode (
int i)
const {
if ((!d)||(i>=d->nChild ))
return emptyXMLNode;
return d->pChild[i]; }
2413char XMLNode::isDeclaration ( )
const {
if (!d)
return 0;
return d->isDeclaration; }
2414char XMLNode::isEmpty ( )
const {
return (d==NULL); }
2415XMLNode XMLNode::emptyNode ( ) {
return XMLNode::emptyXMLNode; }
2417XMLNode XMLNode::addChild(
XMLCSTR lpszName,
char isDeclaration,
int pos)
2419XMLNode XMLNode::addChild_WOSD(
XMLSTR lpszName,
char isDeclaration,
int pos)
2424 {
return addAttribute_priv(0,lpszName,lpszValuev); }
2426 {
return addText_priv(0,
stringDup(lpszValue),pos); }
2428 {
return addText_priv(0,lpszValue,pos); }
2430 {
return addClear_priv(0,
stringDup(lpszValue),lpszOpen,lpszClose,pos); }
2432 {
return addClear_priv(0,lpszValue,lpszOpen,lpszClose,pos); }
2452char XMLNode::setGlobalOptions(XMLCharEncoding _characterEncoding,
char _guessWideCharChars,
char _dropWhiteSpace)
2454 guessWideCharChars=_guessWideCharChars; dropWhiteSpace=_dropWhiteSpace;
2456 if (_characterEncoding) characterEncoding=_characterEncoding;
2458 switch(_characterEncoding)
2460 case encoding_UTF8: characterEncoding=_characterEncoding; XML_ByteTable=XML_utf8ByteTable;
break;
2461 case encoding_ascii: characterEncoding=_characterEncoding; XML_ByteTable=XML_asciiByteTable;
break;
2462 case encoding_ShiftJIS: characterEncoding=_characterEncoding; XML_ByteTable=XML_sjisByteTable;
break;
2469XMLNode::XMLCharEncoding XMLNode::guessCharEncoding(
void *buf,
int l,
char useXMLEncodingAttribute)
2475 if (guessWideCharChars&&(myIsTextWideChar(buf,l)))
return (
XMLCharEncoding)0;
2476 unsigned char *b=(
unsigned char*)buf;
2477 if ((b[0]==0xef)&&(b[1]==0xbb)&&(b[2]==0xbf))
return encoding_UTF8;
2483 switch (XML_utf8ByteTable[b[i]])
2485 case 4: i++;
if ((i<l)&&(b[i]& 0xC0)!=0x80) { bestGuess=
encoding_ascii; i=l; }
2486 case 3: i++;
if ((i<l)&&(b[i]& 0xC0)!=0x80) { bestGuess=
encoding_ascii; i=l; }
2487 case 2: i++;
if ((i<l)&&(b[i]& 0xC0)!=0x80) { bestGuess=
encoding_ascii; i=l; }
2491 if (!useXMLEncodingAttribute)
return bestGuess;
2498 b=(
unsigned char*)strstr(bb,
"encoding");
2499 if (!b)
return bestGuess;
2500 b+=8;
while XML_isSPACECHAR(*b) b++;
if (*b!=
'=')
return bestGuess;
2501 b++;
while XML_isSPACECHAR(*b) b++;
if ((*b!=
'\'')&&(*b!=
'"'))
return bestGuess;
2502 b++;
while XML_isSPACECHAR(*b) b++;
2504 if ((
_strnicmp((
char*)b,
"utf-8",5)==0)||
2511 if ((
_strnicmp((
char*)b,
"shiftjis",8)==0)||
2512 (
_strnicmp((
char*)b,
"shift-jis",9)==0)||
2518#undef XML_isSPACECHAR
2524static const char base64Fillchar =
_X(
'=');
2527XMLCSTR base64EncodeTable=
_X(
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
2531const unsigned char base64DecodeTable[] = {
2532 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,
2533 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,
2534 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,
2535 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,
2536 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,
2537 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,
2538 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,
2539 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,
2540 98,98,98,98,98,98,98,98,98,98, 98,98,98,98,98,98
2543XMLParserBase64Tool::~XMLParserBase64Tool(){
freeBuffer(); }
2545void XMLParserBase64Tool::freeBuffer(){
if (buf) free(buf); buf=NULL; buflen=0; }
2547int XMLParserBase64Tool::encodeLength(
int inlen,
char formatted)
2549 unsigned int i=((inlen-1)/3*4+4+1);
2550 if (formatted) i+=inlen/54;
2554XMLSTR XMLParserBase64Tool::encode(
unsigned char *inbuf,
unsigned int inlen,
char formatted)
2556 int i=
encodeLength(inlen,formatted),k=17,eLen=inlen/3,j;
2562 j=(inbuf[0]<<16)|(inbuf[1]<<8)|inbuf[2]; inbuf+=3;
2564 *(curr++)=base64EncodeTable[ j>>18 ];
2565 *(curr++)=base64EncodeTable[(j>>12)&0x3f];
2566 *(curr++)=base64EncodeTable[(j>> 6)&0x3f];
2567 *(curr++)=base64EncodeTable[(j )&0x3f];
2568 if (formatted) {
if (!k) { *(curr++)=
_X(
'\n'); k=18; } k--; }
2573 *(curr++)=base64EncodeTable[ inbuf[0]>>2 ];
2574 *(curr++)=base64EncodeTable[(inbuf[0]<<4)&0x3F];
2575 *(curr++)=base64Fillchar;
2576 *(curr++)=base64Fillchar;
2579 j=(inbuf[0]<<8)|inbuf[1];
2580 *(curr++)=base64EncodeTable[ j>>10 ];
2581 *(curr++)=base64EncodeTable[(j>> 4)&0x3f];
2582 *(curr++)=base64EncodeTable[(j<< 2)&0x3f];
2583 *(curr++)=base64Fillchar;
2589unsigned int XMLParserBase64Tool::decodeSize(
XMLCSTR data,
XMLError *xe)
2600 c=base64DecodeTable[(
unsigned char)(*data)];
2606 if (size==0)
return 0;
2607 do { data--; size--; }
while(*data==base64Fillchar); size++;
2608 return (
unsigned int)((size*3)/4);
2611unsigned char XMLParserBase64Tool::decode(
XMLCSTR data,
unsigned char *buf,
int len,
XMLError *xe)
2620#define BASE64DECODE_READ_NEXT_CHAR(c) \
2622 if (data[i]>255){ c=98; break; } \
2623 c=base64DecodeTable[(unsigned char)data[i++]]; \
2625 if(c==98){ if(xe)*xe=eXMLErrorBase64DecodeIllegalCharacter; return 0; }
2627#define BASE64DECODE_READ_NEXT_CHAR(c) \
2628 do { c=base64DecodeTable[(unsigned char)data[i++]]; }while (c==97); \
2629 if(c==98){ if(xe)*xe=eXMLErrorBase64DecodeIllegalCharacter; return 0; }
2632 BASE64DECODE_READ_NEXT_CHAR(c)
2633 if (c==99) {
return 2; }
2636 if (p==(
int)len)
return 2;
2641 BASE64DECODE_READ_NEXT_CHAR(d)
2644 buf[p++]=(
unsigned char)((c<<2)|((d>>4)&0x3));
2646 BASE64DECODE_READ_NEXT_CHAR(c)
2650 if (c==96)
return 2;
2655 buf[p++]=(
unsigned char)(((d<<4)&0xf0)|((c>>2)&0xf));
2657 BASE64DECODE_READ_NEXT_CHAR(d)
2661 if (d==96)
return 2;
2666 buf[p++]=(
unsigned char)(((c<<6)&0xc0)|d);
2669#undef BASE64DECODE_READ_NEXT_CHAR
2671void XMLParserBase64Tool::alloc(
int newsize)
2673 if ((!buf)&&(newsize)) { buf=malloc(newsize); buflen=newsize;
return; }
2674 if (newsize>buflen) { buf=realloc(buf,newsize); buflen=newsize; }
2677unsigned char *XMLParserBase64Tool::decode(
XMLCSTR data,
int *outlen,
XMLError *xe)
2681 if (outlen) *outlen=len;
2682 if (!len)
return NULL;
2684 if(!
decode(data,(
unsigned char*)buf,len,xe)){
return NULL; }
2685 return (
unsigned char*)buf;
2690bool XMLNode::UnitTest()
2696 "<library name=\"central\" open=\"true\">"
2697 "<book id=\"b1\" lang=\"en\">"
2698 "<title>Hello World</title>"
2699 "<author>Ada</author>"
2701 "<book id=\"b2\" lang=\"fr\">"
2702 "<title>Bonjour</title>"
2707 XMLNode root = XMLNode::parseString(doc,
"library", &results);
2710 XMLNode::getError(results.error), results.nLine, results.nColumn);
2713 if (root.isEmpty()) {
2721 if (!root.getName() || strcmp(root.getName(),
"library") != 0) {
2722 unittest::fail(
"root name mismatch: expected 'library', got '%s'",
2723 root.getName() ? root.getName() :
"(null)");
2728 if (root.nAttribute() != 2) {
2729 unittest::fail(
"root attribute count mismatch: expected 2, got %d", root.nAttribute());
2732 XMLCSTR nameAttr = root.getAttribute(
"name");
2733 if (!nameAttr || strcmp(nameAttr,
"central") != 0) {
2734 unittest::fail(
"root @name mismatch: expected 'central', got '%s'", nameAttr ? nameAttr :
"(null)");
2737 XMLCSTR openAttr = root.getAttribute(
"open");
2738 if (!openAttr || strcmp(openAttr,
"true") != 0) {
2739 unittest::fail(
"root @open mismatch: expected 'true', got '%s'", openAttr ? openAttr :
"(null)");
2742 if (!root.isAttributeSet(
"name")) {
2750 if (root.nChildNode() != 2) {
2751 unittest::fail(
"root child count mismatch: expected 2, got %d", root.nChildNode());
2754 if (root.nChildNode(
"book") != 2) {
2755 unittest::fail(
"root book-child count mismatch: expected 2, got %d", root.nChildNode(
"book"));
2759 XMLNode book1 = root.getChildNode(
"book", 0);
2760 if (book1.isEmpty() || !book1.getName() || strcmp(book1.getName(),
"book") != 0) {
2764 XMLCSTR id1 = book1.getAttribute(
"id");
2765 if (!id1 || strcmp(id1,
"b1") != 0) {
2766 unittest::fail(
"book[0] @id mismatch: expected 'b1', got '%s'", id1 ? id1 :
"(null)");
2769 XMLCSTR lang1 = book1.getAttribute(
"lang");
2770 if (!lang1 || strcmp(lang1,
"en") != 0) {
2771 unittest::fail(
"book[0] @lang mismatch: expected 'en', got '%s'", lang1 ? lang1 :
"(null)");
2776 if (book1.nChildNode() != 2) {
2777 unittest::fail(
"book[0] child count mismatch: expected 2, got %d", book1.nChildNode());
2783 XMLNode title1 = book1.getChildNode(
"title", 0);
2784 if (title1.isEmpty()) {
2788 if (title1.nText() < 1 || !title1.getText(0) || strcmp(title1.getText(0),
"Hello World") != 0) {
2789 unittest::fail(
"book[0]/title text mismatch: expected 'Hello World', got '%s'",
2790 title1.getText(0) ? title1.getText(0) :
"(null)");
2793 XMLNode author1 = book1.getChildNode(
"author", 0);
2794 if (author1.isEmpty() || !author1.getText(0) || strcmp(author1.getText(0),
"Ada") != 0) {
2795 unittest::fail(
"book[0]/author text mismatch: expected 'Ada', got '%s'",
2796 author1.getText(0) ? author1.getText(0) :
"(null)");
2801 XMLNode book2 = root.getChildNode(
"book", 1);
2802 XMLCSTR id2 = book2.getAttribute(
"id");
2803 if (!id2 || strcmp(id2,
"b2") != 0) {
2804 unittest::fail(
"book[1] @id mismatch: expected 'b2', got '%s'", id2 ? id2 :
"(null)");
2807 if (book2.nChildNode() != 1) {
2808 unittest::fail(
"book[1] child count mismatch: expected 1, got %d", book2.nChildNode());
2811 XMLNode title2 = book2.getChildNode(
"title", 0);
2812 if (title2.isEmpty() || !title2.getText(0) || strcmp(title2.getText(0),
"Bonjour") != 0) {
2813 unittest::fail(
"book[1]/title text mismatch: expected 'Bonjour', got '%s'",
2814 title2.getText(0) ? title2.getText(0) :
"(null)");
2820 XMLNode::parseString(
"<a><b></a>",
"a", &badResults);
2822 unittest::fail(
"malformed XML <a><b></a> was accepted without error");
2825 unittest::detail(
"malformed-doc error correctly reported: %s", XMLNode::getError(badResults.error));
2830 const int iterations = 20000;
2831 const size_t docBytes = strlen(doc);
2833 for (
int i = 0; i < iterations; i++) {
2834 XMLNode n = XMLNode::parseString(doc,
"library");
2836 if (n.nChildNode() != 2) {
2837 unittest::fail(
"throughput iteration %d produced wrong child count", i);
2842 if (us <= 0.0) us = 1.0;
2843 double parsesPerSec = (double)iterations / us * 1e6;
2844 double mbPerSec = ((double)iterations * (double)docBytes) / us;
2845 unittest::detail(
"parsed %d docs of %lu bytes in %.0f us", iterations, (
unsigned long)docBytes, us);
2848 unittest::metric(
"avg_parse_latency", us / (
double)iterations,
"us",
false);
2856 "xml", XMLNode::UnitTest,
2857 "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.