#include "xmlreader.h"
#include <string.h>
#define min(a,b) (a<b?a:b)
int indexOf(char* s1, char* s2, int i0){
int n= strlen(s2);
for (int i= i0; s1[i]; i++){
if (!strncmp(s1 + i, s2, n)){
return i;
}
}
return -1;
}
int indexOf2(char* s1, char* s2a, char* s2b, int i0){
int na= strlen(s2a);
int nb= strlen(s2b);
for (int i= i0; s1[i]; i++){
if (!strncmp(s1 + i, s2a, na)
||!strncmp(s1 + i, s2b, nb)){
return i;
}
}
return -1;
}
int indexOfAny(char* s1, char* s2, int i0){
int n= strlen(s2);
for (int i= i0; s1[i]; i++){
for (int j= 0; j < n; j++){
if (s1[i]==s2[j]){
return i;
}
}
}
return -1;
}
XmlReader::~XmlReader(){
delete axParent; }
XmlReader::XmlReader(FILE* pfIn){
fseek(pfIn, 0, SEEK_END);
long lFSize= ftell(pfIn);
fseek(pfIn, 0, SEEK_SET);
char* sBuf= new char[lFSize + 1];
fread(sBuf, lFSize, 1, pfIn);
axParent= new XmlElement*[32]; readElements(sBuf, lFSize);
char* sName= axParent[0]->getName();
fprintf(stderr, "%s: %d elementen\n", sName, axParent[0]->countChildren());
delete sName;
} int XmlReader::readElements(char* sBuf, int lFSize){
bool bBeforeEl= true;
int iTab= 0; int nElementen= 0;
int i= 0;
while (i < lFSize){
if (bBeforeEl){
int iLT= indexOf(sBuf, "<", i);
if (iLT < 0){
break; }
i= iLT + 1; bool bTagX= sBuf[i]=='!';
bool bTagC= bTagX && sBuf[(i)+1]=='-';
bool bTagQ= sBuf[i]=='?';
if (bTagC){
int iEndComment= indexOf(sBuf, "-->", i);
if (iEndComment < 0){
fprintf(stderr, "xml: <!---element niet afgesloten\n");
break; }
i= iEndComment + 3;
continue; } else if (bTagX){
int iEndX= indexOf(sBuf, ">", i);
if (iEndX < 0){
fprintf(stderr, "xml: <!-element niet afgesloten\n");
break; }
i= iEndX + 1;
continue; } else if (bTagQ){
int iEndQ= indexOf(sBuf, ">", i);
if (iEndQ < 0){
fprintf(stderr, "xml: <?-element niet afgesloten\n");
break; }
i= iEndQ + 2;
continue; }
int iEndName= indexOfAny(sBuf, "> /\n\r\t", i);
while (sBuf[iEndName]=='/' && sBuf[iEndName+1]!='>'){
iEndName= indexOfAny(sBuf, "> /\n\r\t", iEndName + 1);
}
int iTagEnd= indexOf2(sBuf, ">", "/>", i);
if (iEndName < 0){
fprintf(stderr, "xml: elementnaam niet afgesloten.\n");
break; }
bool bShortEnd= sBuf[iTagEnd]=='/';
bool bAttributes= sBuf[iEndName]==' ';
bool bEndTag= sBuf[i]=='/';
if (bEndTag){
iTab--;
if (iTab==0){
return i; }
continue; }
nElementen++;
char* sName= new char[iEndName - i + 1];
strncpy(sName, sBuf + i, iEndName - i);
sName[iEndName - i]= '\0';
XmlElement* xel= new XmlElement(iTab, sName);
xel->parseAttributes(sBuf + iEndName, iTagEnd - iEndName);
if (!bShortEnd){
int iNextEl= indexOf(sBuf, "<", iTagEnd);
if (iNextEl > iTagEnd){
xel->parseValue(sBuf + iTagEnd + 1, iNextEl - (iTagEnd + 1));
}
}
if (iTab > 0){
axParent[iTab-1]->addChild(xel);
}
xel->print();
if (!bShortEnd){
axParent[iTab]= xel;
iTab++;
}
delete sName;
}
i++;
}
return i; } XmlElement* XmlReader::getRootElement(){
return axParent[0]->clone();
}
XmlElement::XmlElement(int iTab, char* sName){
this->iTab= iTab;
this->sName= new char[strlen(sName) + 1];
strcpy(this->sName, sName);
this->nAttrs= 0;
this->asAttr= NULL;
this->sValue= NULL;
this->nChildren= 0;
this->axChild= NULL;
}
XmlElement* XmlElement::clone(){
XmlElement* x= new XmlElement(iTab, sName);
x->nAttrs= nAttrs;
x->asAttr= nAttrs > 0 ? new char*[nAttrs] : NULL;
for (int i= 0; i < nAttrs; i++){
x->asAttr[i]= new char[strlen(asAttr[i]) + 1];
strcpy(x->asAttr[i], asAttr[i]);
}
if (sValue){
x->sValue= new char[strlen(sValue) + 1];
strcpy(x->sValue, sValue);
}
x->nChildren= nChildren;
if (nChildren > 0){
x->axChild= new XmlElement*[nChildren];
for (int i= 0; i < nChildren; i++){
x->axChild[i]= axChild[i]; }
}
return x;
}
XmlElement::~XmlElement(){
for (int i= nAttrs - 1; i >= 0; i--){
delete asAttr[i];
}
if (asAttr){
delete asAttr;
}
if (sValue){
delete sValue;
}
delete sName;
if (axChild){
delete axChild; }
}
void XmlElement::deleteChildren(){
for (int i= 0; i < nChildren; i++){
axChild[i]->deleteChildren();
delete axChild[i];
}
}
void XmlElement::decode(char* sValue){
for(;;){
int iStartCode= indexOf(sValue, "&#", 0);
if (iStartCode < 0){
break;
}
int iEndCode= indexOf(sValue, ";", iStartCode + 2);
int iAscii= 0;
int iMultip= 10;
for (int i= iStartCode + 2; i < iEndCode; i++){
if (sValue[i]=='x'){
iMultip= 16;
continue;
}
iAscii*=iMultip;
int iDec;
if (sValue[i] <= '9'){
iDec= sValue[i] - '0';
} else if (sValue[i] >= 'a'){
iDec= sValue[i] + 10 - 'a';
} else if (sValue[i] >= 'A'){
iDec= sValue[i] + 10 - 'A';
} else{
}
iAscii+=iDec;
}
sValue[iStartCode]= (char) iAscii;
strcpy(sValue + iStartCode + 1, sValue + iEndCode + 1);
}
} char* XmlElement::getAttributeValue(int i){
int iTab= indexOf(asAttr[i], "\t", 0);
char* sValue= new char[strlen(asAttr[i]) - iTab];
strcpy(sValue, asAttr[i] + iTab + 1);
decode(sValue);
return sValue;
}
char* XmlElement::getAttribute(char* sName){
for (int i= 0; i < nAttrs; i++){
if (indexOf(asAttr[i], sName, 0)==0 && asAttr[i][strlen(sName)]=='\t'){
return getAttributeValue(i);
}
}
return NULL;
}
char* XmlElement::getValue(){
if (!sValue){
return NULL;
}
char* sRet= new char[strlen(sValue) + 1];
strcpy(sRet, sValue);
decode(sRet);
return sRet;
}
void XmlElement::print(){
for (int j= 0; j < iTab; j++){
printf(" ");
}
printf("%s\n", sName, nAttrs);
for (int i= 0; i < nAttrs; i++){
int iSep= indexOf(asAttr[i], "\t", 0);
char* sValue= getAttributeValue(i);
for (int j= 0; j < iTab; j++){
printf(" ");
}
printf("> %.*s = %s\n", iSep, asAttr[i], sValue);
delete sValue;
}
if (sValue){
for (int j= 0; j < iTab; j++){
printf(" ");
}
printf("\\ %s\n", sValue);
}
}
void XmlElement::parseAttributes(char* sSrc, int nChars){
char* sAttrs= new char[nChars + 1];
strncpy(sAttrs, sSrc, nChars);
sAttrs[nChars]= '\0';
for (int i= 0; i < nChars; i++){
if (sAttrs[i] <= ' '){
continue;
}
int j= i;
for(;;){if (sAttrs[j]=='='||sAttrs[j]<=' '){break;} j++;}
int k= j;
for(;;){if (sAttrs[k]=='='){break;} k++;}
int l= k + 1;
for(;;){if (sAttrs[l]=='"'){break;} l++;}
int m= l + 1;
for(;;){if (sAttrs[m]=='"'){break;} m++;}
int nAttrValueChars= (j-i) + 1 + (m - l - 1); char* sAttrValue= new char[nAttrValueChars + 1];
strncpy(sAttrValue, sAttrs + i, (j-i));
strncpy(sAttrValue + (j-i), "\t", 1);
strncpy(sAttrValue + (j-i) + 1, sAttrs + l + 1, (m - l - 1));
sAttrValue[nAttrValueChars]= '\0';
addAttrValue(sAttrValue);
delete sAttrValue;
i= m + 1;
}
delete sAttrs;
} void XmlElement::addAttrValue(char* sAttrValue){
char* sNew= new char[strlen(sAttrValue) + 1];
strcpy(sNew, sAttrValue);
char** asAttr0= asAttr;
asAttr= new char*[nAttrs + 1];
for (int i= 0; i < nAttrs; i++){
asAttr[i]= asAttr0[i];
}
asAttr[nAttrs]= sNew;
nAttrs++;
if (asAttr0){
delete asAttr0;
}
} void XmlElement::parseValue(char* sSrc, int nChars){
int i0= 0;
while (i0 < nChars){
if (sSrc[i0] > ' '){
break;
}
i0++;
}
if (i0==nChars){
return; }
sValue= new char[nChars + 1];
strncpy(sValue, sSrc, nChars);
sValue[nChars]= '\0';
} void XmlElement::addChild(XmlElement* xChild){
XmlElement** axChild0= axChild;
axChild= new XmlElement*[nChildren + 1];
for (int i= 0; i < nChildren; i++){
axChild[i]= axChild0[i];
}
axChild[nChildren]= xChild;
nChildren++;
if (axChild0){
delete axChild0;
}
}
int XmlElement::countChildren(){
return nChildren;
}
char* XmlElement::getName(){
char* sRet= new char[strlen(sName) + 1];
strcpy(sRet, sName);
return sRet;
}
XmlElement* XmlElement::getChild(int i){
if (i >= nChildren){
return NULL;
} else{
return axChild[i]->clone();
}
}
XmlElement* XmlElement::getChild(char* sName){
for (int i= 0; i < nChildren; i++){
if (strcmp(axChild[i]->sName, sName)){
continue;
}
return axChild[i]->clone();
}
return NULL;
}
bool XmlElement::isName(char* sName){
return !strcmp(sName, this->sName);
}