Main Page | Modules | Class Hierarchy | Class List | File List | Class Members | File Members

xmlprofile.cpp

00001 /* MuSE - Multiple Streaming Engine
00002  * Copyright (C) 2000-2003 Denis Rojo aka jaromil <jaromil@dyne.org>
00003  *
00004  * This source code is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Public License as published 
00006  * by the Free Software Foundation; either version 2 of the License,
00007  * or (at your option) any later version.
00008  *
00009  * This source code is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00012  * Please refer to the GNU Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Public License along with
00015  * this source code; if not, write to:
00016  * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00017  *
00018  * "$Id: xmlprofile.cpp,v 1.1 2005/04/24 02:13:12 xant Exp $"
00019  *
00020  */
00021 #include "xmlprofile.h"
00022 #include <string.h>
00023 #include <stdio.h>
00024 #include <stdlib.h>
00025 #include <sys/types.h>
00026 #include <sys/stat.h>
00027 #include "jutils.h"
00028 
00029 #define XML_ELEMENT_NONE 0
00030 #define XML_ELEMENT_START 1
00031 #define XML_ELEMENT_VALUE 2
00032 #define XML_ELEMENT_END 3
00033 #define XML_ELEMENT_UNIQUE 4
00034 
00035 #define SKIP_BLANKS(__p) \
00036         while((*__p==' ' || *__p=='\t' || *__p=='\r' || *__p == '\n') && *__p!=0) __p++; 
00037                 
00038 #define ADVANCE_ELEMENT(__p) \
00039         while(*__p!='>' && *__p!=' ' && *__p!='\t' && *__p!='\r' && *__p != '\n' && *__p!=0) __p++;
00040                 
00041 #define ADVANCE_TO_ATTR_VALUE(__p) \
00042         while(*__p!='=' && *__p!=' ' && *__p!='\t' && *__p!='\r' && *__p != '\n' && *__p!=0) __p++;\
00043         SKIP_BLANKS(__p);
00044 
00045 XmlProfile::XmlProfile(char *category,char *repository) {
00046         int fd;
00047         
00048         rootElements = new Linklist;
00049 
00050         xmlFile=(char *)malloc(strlen(category)+strlen(repository)+6);
00051         sprintf(xmlFile,"%s/%s.xml",repository,category);
00052         XmlErr err=XmlParseFile(xmlFile);
00053 }
00054 
00055 XmlProfile::~XmlProfile() {
00056         if(xmlFile) free(xmlFile);
00057         for(int i=1;i<=rootElements->len();i++) {
00058                 Entry *entry = rootElements->pick(i);
00059                 if(entry) {
00060                         XmlTag *element = (XmlTag *)entry->get_value();
00061                         if(element) delete element;
00062                 }
00063         }
00064         delete rootElements;
00065 }
00066 
00067 XmlErr XmlProfile::XmlStartHandler(char *element,
00068         char **attr_names, char **attr_values) 
00069 {
00070         XmlTag *newTag = new XmlTag(element,cTag);
00071         XmlErr err;
00072         func("new tag found %s\n",element);
00073         if(cTag) {
00074                 err = cTag->addChild(newTag);
00075                 if(err!=XML_NOERR)
00076                         error("Can't add new child %s for element %s ",newTag->name(),cTag->name());
00077                 else
00078                         func("Added new child %s for element %s ",newTag->name(),cTag->name());
00079         }
00080         else {
00081                 err = addRootElement(newTag);
00082                 if(err!=XML_NOERR)
00083                         error("Can't add new root element %s",newTag->name());
00084                 else
00085                         func("Added new root element %s",newTag->name());
00086         }
00087         cTag = newTag;
00088         unsigned int offset = 0;
00089         if(attr_names && attr_values) {
00090                 while(attr_names[offset]!=NULL) {
00091                         err=newTag->addAttribute(attr_names[offset],attr_values[offset]);
00092                         if(err==XML_NOERR) {
00093                                 func("Added new attr %s => %s for element %s",
00094                                         attr_names[offset],attr_values[offset],newTag->name());
00095                         } else {
00096                                 error("Can't add new attr %s => %s for element %s",
00097                                         attr_names[offset],attr_values[offset],newTag->name());
00098                         }
00099                         offset++;
00100                 }
00101         }
00102         return XML_NOERR;
00103 }
00104 
00105 XmlErr XmlProfile::XmlEndHandler(char *element) 
00106 {
00107         if(cTag) {
00108                 XmlTag *parent = cTag->parent();
00109                 cTag = parent;
00110                 return XML_NOERR;
00111         }
00112         return -1;
00113 }
00114 
00115 XmlErr XmlProfile::XmlValueHandler(char *text) 
00116 {
00117         char *val = (char *)text;
00118         if(val) {
00119                 while((*val == ' ' || *val == '\t' ||
00120                         *val == '\r' || *val == '\n') && *val != 0) val++;
00121                 char *p = val+strlen(val)-1;
00122                 while((*p == ' ' || *p == '\t' ||
00123                         *p == '\r' || *p == '\n') && p != val) 
00124                 {
00125                         *p=0;
00126                         p--;
00127                 }
00128                 if(strlen(val)>0) {
00129                         if(cTag) cTag->value((char *)val);
00130                         else error("cTag == NULL while handling a value!!");
00131                 }
00132                 return XML_NOERR;
00133         }
00134         return -1;
00135 }
00136 
00137 XmlErr XmlProfile::XmlParseFile(char *path) {
00138         struct stat fileStat;
00139         if(!path) return XML_BADARGS;
00140         stat(path,&fileStat);
00141         FILE *inFile=NULL;
00142         XmlErr err;
00143         cTag=NULL;
00144         if(fileStat.st_size>0) {
00145                 char *buffer=(char *)malloc(fileStat.st_size+1);
00146                 inFile=fopen(path,"r");
00147                 fread(buffer,1,fileStat.st_size,inFile);
00148                 buffer[fileStat.st_size]=0;
00149         
00150                 err=XmlParseBuffer(buffer);
00151                 free(buffer);
00152         }
00153 }
00154 
00155 XmlErr XmlProfile::XmlParseBuffer(char *buffer) {
00156         XmlErr err;
00157         int state=XML_ELEMENT_NONE;
00158         char *p=buffer;
00159         //unsigned int offset=fileStat.st_size;
00160         while(*p!=0) {
00161                 SKIP_BLANKS(p);
00162                 char *mark;
00163                 if(*p=='<') {
00164                         p++;
00165                         if(*p=='/') {
00166                                 p++;
00167                                 SKIP_BLANKS(p);
00168                                 mark=p;
00169                                 while(*p!='>' && *p!=0) p++;
00170                                 if(*p=='>') {
00171                                         char *end=(char *)malloc(p-mark+1);
00172                                         strncpy(end,mark,p-mark);
00173                                         end[p-mark]=0;
00174                                         p++;
00175                                         state=XML_ELEMENT_END;
00176                                         err=XmlEndHandler(end);
00177                                         if(end) free(end);
00178                                         if(err!=XML_NOERR) return(err);
00179                                 }
00180                         }
00181                         else { /* start tag */
00182                                 char *start = NULL;
00183                                 char **attrs = NULL;
00184                                 char **values = NULL;
00185                                 unsigned int nAttrs = 0;
00186                                 state=XML_ELEMENT_START;
00187                                 SKIP_BLANKS(p);
00188                                 mark=p;
00189                                 ADVANCE_ELEMENT(p);
00190                                 start = (char *)malloc(p-mark+1);
00191                                 strncpy(start,mark,p-mark);
00192                                 start[p-mark]=0;
00193                                 SKIP_BLANKS(p);
00194                                 while(*p!='>' && *p!=0) {
00195                                         if(*p=='/' && *(p+1)=='>') {
00196                                                 state=XML_ELEMENT_UNIQUE;
00197                                                 p++;
00198                                         }
00199                                         else {
00200                                                 mark=p;
00201                                                 ADVANCE_TO_ATTR_VALUE(p);
00202                                                 if(*p=='=') {
00203                                                         char *tmpAttr=(char *)malloc(p-mark+1);
00204                                                         strncpy(tmpAttr,mark,p-mark);
00205                                                         tmpAttr[p-mark]=0;
00206                                                         p++;
00207                                                         SKIP_BLANKS(p);
00208                                                         if(*p == '"' || *p == '\'') {
00209                                                                 int quote = *p;
00210                                                                 p++;
00211                                                                 mark=p;
00212                                                                 while(*p!=quote && *p!=0) p++;
00213                                                                 if(*p==quote) {
00214                                                                         char *tmpVal = (char *)malloc(p-mark+1);
00215                                                                         strncpy(tmpVal,mark,p-mark);
00216                                                                         tmpVal[p-mark]=0;
00217                                                                         /* add new attribute */
00218                                                                         nAttrs++;
00219                                                                         attrs=(char **)realloc(attrs,sizeof(char *)*nAttrs+1);
00220                                                                         attrs[nAttrs-1]=tmpAttr;
00221                                                                         attrs[nAttrs]=NULL;
00222                                                                         values=(char **)realloc(values,sizeof(char *)*nAttrs+1);
00223                                                                         values[nAttrs-1]=tmpVal;
00224                                                                         values[nAttrs]=NULL;
00225                                                                         p++;
00226                                                                         SKIP_BLANKS(p);
00227                                                                 }
00228                                                                 else {
00229                                                                         free(tmpAttr);
00230                                                                 }
00231                                                         }
00232                                                         else {
00233                                                                 free(tmpAttr);
00234                                                         }
00235                                                 }
00236                                         }
00237                                 }
00238                                 err = XmlStartHandler(start,attrs,values);
00239 #define XML_FREE_ATTRIBUTES \
00240         if(nAttrs>0) {\
00241                 for(int i=0;i<nAttrs;i++) {\
00242                         if(attrs[i]) free(attrs[i]);\
00243                         if(values[i]) free(values[i]);\
00244                 }\
00245                 free(attrs);\
00246                 attrs=NULL;\
00247                 free(values);\
00248                 values=NULL;\
00249                 nAttrs=0;\
00250         }\
00251         if(start) free(start);
00252                                 if(err!=XML_NOERR) {
00253                                         XML_FREE_ATTRIBUTES
00254                                         return err;
00255                                 }
00256                                 if(state==XML_ELEMENT_UNIQUE) {
00257                                         err = XmlEndHandler(start);
00258                                         if(err!=XML_NOERR) {
00259                                                 XML_FREE_ATTRIBUTES
00260                                                 return err;
00261                                         }
00262                                 }
00263                                 XML_FREE_ATTRIBUTES
00264                                 p++;
00265                         }
00266                 } //if(*p=='<')
00267                 else if(state == XML_ELEMENT_START) {
00268                         state=XML_ELEMENT_VALUE;
00269                         mark=p;
00270                         while(*p != '<' && *p != 0) p++;
00271                         if(*p == '<') {
00272                                 char *value = (char *)malloc(p-mark);
00273                                 strncpy(value,mark,p-mark);
00274                                 value[p-mark]=0;
00275                                 err=XmlValueHandler(value);
00276                                 if(value) free(value);
00277                                 if(err!=XML_NOERR) return(err);
00278                                 //p++;
00279                         }
00280                 }
00281                 else {
00282                         /* XXX */
00283                         p++;
00284                 }
00285         } // while(*p!=0)
00286         return XML_NOERR;
00287 }
00288 
00289 XmlErr XmlProfile::addRootElement(XmlTag *element) {
00290         if(!element) return XML_BADARGS;
00291         Entry *newEntry = new Entry((void *)element);
00292         if(newEntry) rootElements->append(newEntry);
00293         return XML_NOERR;
00294 }
00295 
00296 XmlTag *XmlProfile::getRootElement(char *name) {
00297         for(int i=1;i<rootElements->len();i++) {
00298                 XmlTag *element = getRootElement(i);
00299                 if(element && strcmp(element->name(),name) == 0) 
00300                         return(element);
00301         }
00302         return NULL;
00303 }
00304 
00305 XmlTag *XmlProfile::getRootElement(int index) {
00306         Entry *entry = rootElements->pick(index);
00307         if(entry) {
00308                 XmlTag *element = (XmlTag *)entry->get_value();
00309                 if(element) return(element);
00310         }
00311         return NULL;
00312 }
00313 
00314 /* XXX - the real proble here is when you have multiple tags with the same name ...
00315  * this method will return always the first one !!! */
00316 XmlTag *XmlProfile::getElement(char *path) {
00317         char *tagName,*tkContext;
00318         XmlTag *tag = NULL;
00319         if(!path) return NULL;
00320         if(*path == '/') path++;
00321         char *lbuf = strdup(path);
00322         char *rootTagName = strtok_r(lbuf,"/",&tkContext);
00323         if(rootTagName) {
00324                 tag=getRootElement(rootTagName);
00325                 for (tagName = strtok_r(lbuf,"/",&tkContext);
00326                         tagName; tagName = strtok_r(NULL,"/",&tkContext))
00327                 {
00328                         tag=tag->getChild(tagName);
00329                         if(!tag) {
00330                                 free(lbuf);
00331                                 return NULL;
00332                         }
00333                 }
00334         }
00335         else {
00336                 tag=getRootElement(path);
00337         }
00338         free(lbuf);
00339         return tag;
00340 }
00341 
00342 char *XmlProfile::dumpXml() {
00343         char *dump = (char *)malloc(1);
00344         *dump=0;
00345         for (int i=1;i<=rootElements->len();i++) {
00346                 Entry *rEntry = rootElements->pick(i);
00347                 XmlTag *rTag = (XmlTag *)rEntry->get_value();
00348                 if(rTag) {
00349                         char *branch = dumpBranch(rTag,0);
00350                         if(branch) {
00351                                 dump=(char *)realloc(dump,strlen(dump)+strlen(branch)+1);
00352                                 strcat(dump,branch);
00353                                 free(branch);
00354                         }
00355                 }
00356         }
00357         return(dump);
00358 }
00359 
00360 char *XmlProfile::dumpBranch(XmlTag *rTag,unsigned int depth) {
00361         int i,n;
00362         char *out = NULL;
00363         char *startTag = (char *)malloc(depth+strlen(rTag->name()+5)); /* enough space even for '/>' */
00364         char *endTag = (char *)malloc(depth+strlen(rTag->name()+5));
00365         char *value = NULL;;
00366         char *childDump = (char *)malloc(1);
00367         *childDump=0;
00368         *startTag=0;
00369         *endTag=0;
00370         char *vTemp = rTag->value();
00371         if(vTemp) {
00372                 value = (char *)malloc(depth+strlen(vTemp)+2);
00373         //      for(n=0;n<=depth;n++) strcat(value,"\t"); /* one more tab */
00374         //      strcat(value," ");
00375                 strcat(value,vTemp);
00376                 strcat(value," ");
00377                 //strcat(value,"\n");
00378                 free(vTemp);
00379         }
00380         
00381         for(n=0;n<depth;n++) strcat(startTag,"\t");
00382         strcat(startTag,"<");
00383         strcat(startTag,rTag->name());
00384         if(rTag->numAttributes()>0) {
00385                 for(i=1;i<=rTag->attributes->len();i++) {
00386                         XmlTagAttribute *attr = rTag->getAttribute(i);
00387                         if(attr) {
00388                                 startTag = (char *)realloc(startTag,strlen(startTag)+
00389                                         strlen(attr->name)+strlen(attr->value)+6);
00390                                 strcat(startTag," ");
00391                                 strcat(startTag,attr->name);
00392                                 strcat(startTag,"=\"");
00393                                 strcat(startTag,attr->value); /* XXX - should escape '"' char */
00394                                 //strcat(startTag,"\" ");
00395                                 strcat(startTag,"\" "); /* maybe better with the whitespace? */
00396                         }
00397                 }
00398         }
00399         if(value||rTag->numChildren()) {
00400                 if(rTag->numChildren() > 0) {
00401                         strcat(startTag,">\n");
00402                         for(n=0;n<depth;n++) strcat(endTag,"\t");
00403                         for(i=1;i<=rTag->numChildren();i++) {
00404                                 XmlTag *child = rTag->getChild(i);
00405                                 if(child) {
00406                                         char *childBuff = dumpBranch(child,depth+1);
00407                                         childDump = (char *)realloc(childDump,strlen(childDump)+strlen(childBuff)+2);
00408                                         strcat(childDump,childBuff);
00409                                         //strcat(childDump,"\n");
00410                                         free(childBuff);
00411                                 }
00412                         }
00413                 }
00414                 else {
00415                         strcat(startTag,"> ");
00416                 }
00417                 strcat(endTag,"</");
00418                 strcat(endTag,rTag->name());
00419                 strcat(endTag,">\n");
00420                 out = (char *)malloc(strlen(startTag)+strlen(endTag)+
00421                         (value?strlen(value)+1:0)+strlen(childDump)+1);
00422                 strcpy(out,startTag);
00423                 if(value) {
00424                         //strcat(out,value);
00425                         if(rTag->numChildren()) {
00426                                 for(n=0;n<=depth;n++) strcat(out,"\t");
00427                                 strcat(out,value);
00428                                 strcat(out,"\n");
00429                         }
00430                         else {
00431                                 strcat(out,value);
00432                         }
00433                 }
00434                 strcat(out,childDump);
00435                 strcat(out,endTag);
00436                 if(value) free(value);
00437         }
00438         else {
00439                 strcat(startTag,"/>\n");
00440                 out=strdup(startTag);
00441         }
00442         free(startTag);
00443         free(endTag);
00444         free(childDump);
00445         return out;
00446 }
00447 
00448 XmlErr XmlProfile::update() {
00449         struct stat fileStat;
00450         stat(xmlFile,&fileStat);
00451         FILE *saveFile=NULL;
00452         if(fileStat.st_size>0) { /* backup old profiles */
00453                 saveFile=fopen(xmlFile,"r");
00454                 if(!saveFile) {
00455                         error("Can't open %s for reading !!",xmlFile);
00456                         return XML_UPDATE_ERR;
00457                 }
00458                 char *backup = (char *)malloc(fileStat.st_size+1);
00459                 fread(backup,1,fileStat.st_size,saveFile);
00460                 backup[fileStat.st_size]=0;
00461                 fclose(saveFile);
00462                 char *backupPath = (char *)malloc(strlen(xmlFile+5));
00463                 sprintf(backupPath,"%s.bck",xmlFile);
00464                 FILE *backupFile=fopen(backupPath,"w+");
00465                 if(backupFile) {
00466                         fwrite(backup,1,fileStat.st_size,backupFile);
00467                         fclose(backupFile);
00468                 }
00469                 else {
00470                         error("Can't open backup file (%s) for writing! ",backupPath);
00471                         if(!saveFile) return XML_UPDATE_ERR;
00472                 }
00473                 free(backupPath);
00474                 free(backup);
00475         } /* end of backup */
00476 
00477         char *dump = dumpXml();
00478         if(dump) {
00479                 saveFile=fopen(xmlFile,"w+");
00480                 if(saveFile) {
00481                 fwrite(dump,1,strlen(dump),saveFile);
00482                 free(dump);
00483                 fclose(saveFile);
00484                 }
00485                 else {
00486                         error("Can't open output file %s",xmlFile);
00487                         if(!saveFile) return XML_UPDATE_ERR;
00488                 }
00489         }
00490 }
00491 
00492 /* ------------------------------------------------------------------------------------- */
00493 /* XmlTag */
00494 
00495 XmlTag::XmlTag(const char *name,XmlTag *parentEntry) {
00496         _parent = parentEntry;
00497         _name = strdup(name); /* could be just a reference to 'name' since it must be a const */
00498         _value=NULL;
00499         children = new Linklist();
00500         attributes = new Linklist();
00501         if(_parent) {
00502                 char *pPath = _parent->path();
00503                         if(pPath) {
00504                         unsigned int pathLen = strlen(pPath)+1+strlen(_parent->name())+1;
00505                         _path = (char *)malloc(pathLen);
00506                         memset(_path,0,pathLen);
00507                         sprintf(_path,"%s/%s",pPath,_parent->name());
00508                         }
00509                         else {
00510                                 _path=strdup(_parent->name());
00511                         }
00512         }
00513         else {
00514                 _path = NULL;
00515         }
00516 }
00517 
00518 XmlTag::XmlTag(const char *name,char *val,XmlTag *parentEntry) {
00519         XmlTag(name,parentEntry);
00520         _value = strdup(val);
00521 }
00522 
00523 XmlTag::~XmlTag() {
00524         int i;
00525         Entry *entry;
00526         if(_value) free(_value);
00527         if(_name) free(_name);
00528         if(_path) free(_path);
00529         for (i=1;i<= children->len();i++) {
00530                 entry = children->pick(i);
00531                 if(entry) {
00532                         XmlTag *tag =  (XmlTag *)entry->get_value();
00533                         if(tag) 
00534                                 delete tag;
00535                 }
00536         }
00537         delete children;
00538         for (i=1;i<=attributes->len();i++) {
00539                 entry = attributes->pick(i);
00540                 if(entry) {
00541                         XmlTagAttribute *attr = (XmlTagAttribute *)entry->get_value();
00542                         if(attr) {
00543                                 if(attr->name) free(attr->name);
00544                                 if(attr->value) free(attr->value);
00545                                 free(attr);
00546                         }
00547                 }
00548         }
00549         delete attributes;
00550 }
00551 
00552 char *XmlTag::path() {
00553         return _path;
00554 }
00555 
00556 char *XmlTag::name() {
00557         return _name;
00558 }
00559 
00560 char *XmlTag::value() {
00561         return _value;
00562 }
00563 
00564 XmlTag *XmlTag::parent() {
00565         return _parent;
00566 }
00567 
00568 XmlErr XmlTag::value(char *val) {
00569         unsigned int valLen=0;
00570         if(!val) return XML_BADARGS;
00571         _value=(char *)realloc(_value,strlen(val)+1);
00572         strcpy(_value,val);
00573         return XML_NOERR;
00574 }
00575 
00576 XmlErr XmlTag::addChild(XmlTag *child) {
00577         if(!child) return XML_BADARGS;
00578         Entry *newEntry = new Entry((void *)child);
00579         children->append(newEntry);
00580         return XML_NOERR;
00581 }
00582 
00583 XmlErr XmlTag::numChildren() {
00584         return children->len();
00585 }
00586 
00587 XmlTag *XmlTag::getChild(int index) {
00588         Entry *entry = children->pick(index);
00589         if(entry) return (XmlTag *)entry->get_value();
00590         return NULL;
00591 }
00592 
00593 XmlTag *XmlTag::getChild(char *name) {
00594         for(int i=1;i<=children->len();i++) {
00595                 XmlTag *child=getChild(i);
00596                 if(strcmp(child->name(),name)==0) 
00597                         return child;
00598         }
00599         return NULL;
00600 }
00601 
00602 XmlErr XmlTag::addAttribute(char *attrName, char *attrValue) {
00603         if(!attrName||!attrValue) return XML_BADARGS;
00604         XmlTagAttribute *newAttr = (XmlTagAttribute *)malloc(sizeof(XmlTagAttribute));
00605         newAttr->name = strdup(attrName);
00606         newAttr->value = strdup(attrValue);
00607         Entry *newEntry = new Entry((void *)newAttr);
00608         attributes->append(newEntry);
00609         return XML_NOERR;
00610 }
00611 
00612 XmlTagAttribute *XmlTag::getAttribute(int index) {
00613         if(index > attributes->len()) return NULL;      
00614         Entry *entry = attributes->pick(index);
00615         if(entry) {
00616                 return (XmlTagAttribute *)entry->get_value();
00617         }
00618         return NULL;
00619 }
00620 
00621 XmlTagAttribute *XmlTag::getAttribute(char *name) {
00622         for(int i=1;i<=attributes->len();i++) {
00623                 XmlTagAttribute *attr = getAttribute(i);
00624                 if(attr && strcmp(attr->name,name) == 0)
00625                         return attr;
00626         }
00627         return NULL;
00628 }
00629 
00630 int XmlTag::numAttributes() {
00631         return attributes->len();
00632 }
00633 

Generated on Mon Apr 25 12:22:40 2005 for MuSE by doxygen 1.3.4