xmlctx.c

Go to the documentation of this file.
00001 /***************************************************************************
00002  $RCSfile$
00003  -------------------
00004  cvs         : $Id: xsd.c 656 2004-12-22 17:02:05Z aquamaniac $
00005  begin       : Sat Jun 28 2003
00006  copyright   : (C) 2003 by Martin Preuss
00007  email       : martin@libchipcard.de
00008 
00009  ***************************************************************************
00010  *                                                                         *
00011  *   This library is free software; you can redistribute it and/or         *
00012  *   modify it under the terms of the GNU Lesser General Public            *
00013  *   License as published by the Free Software Foundation; either          *
00014  *   version 2.1 of the License, or (at your option) any later version.    *
00015  *                                                                         *
00016  *   This library is distributed in the hope that it will be useful,       *
00017  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00018  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00019  *   Lesser General Public License for more details.                       *
00020  *                                                                         *
00021  *   You should have received a copy of the GNU Lesser General Public      *
00022  *   License along with this library; if not, write to the Free Software   *
00023  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston,                 *
00024  *   MA  02111-1307  USA                                                   *
00025  *                                                                         *
00026  ***************************************************************************/
00027 
00028 #ifdef HAVE_CONFIG_H
00029 # include <config.h>
00030 #endif
00031 
00032 
00033 #include "xmlctx_p.h"
00034 #include "gwenhywfar/debug.h"
00035 #include "gwenhywfar/misc.h"
00036 #include "gwenhywfar/text.h"
00037 #include "gwenhywfar/path.h"
00038 #include "i18n_l.h"
00039 
00040 #include <stdlib.h>
00041 #include <assert.h>
00042 #include <string.h>
00043 #include <ctype.h>
00044 
00045 
00046 
00047 GWEN_INHERIT_FUNCTIONS(GWEN_XML_CONTEXT)
00048 
00049 
00050 
00051 
00052 GWEN_XML_CONTEXT *GWEN_XmlCtx_new(uint32_t flags,
00053                                   uint32_t guiid,
00054                                   int timeout) {
00055   GWEN_XML_CONTEXT *ctx;
00056 
00057   GWEN_NEW_OBJECT(GWEN_XML_CONTEXT, ctx);
00058   GWEN_INHERIT_INIT(GWEN_XML_CONTEXT, ctx);
00059 
00060   ctx->flags=flags;
00061   ctx->guiid=guiid;
00062   ctx->timeout=timeout;
00063 
00064   return ctx;
00065 }
00066 
00067 
00068 
00069 void GWEN_XmlCtx_free(GWEN_XML_CONTEXT *ctx) {
00070   if (ctx) {
00071     GWEN_INHERIT_FINI(GWEN_XML_CONTEXT, ctx);
00072     GWEN_FREE_OBJECT(ctx);
00073   }
00074 }
00075 
00076 
00077 
00078 uint32_t GWEN_XmlCtx_GetGuiId(const GWEN_XML_CONTEXT *ctx) {
00079   assert(ctx);
00080   return ctx->guiid;
00081 }
00082 
00083 
00084 
00085 int GWEN_XmlCtx_GetTimeout(const GWEN_XML_CONTEXT *ctx) {
00086   assert(ctx);
00087   return ctx->timeout;
00088 }
00089 
00090 
00091 
00092 uint32_t GWEN_XmlCtx_GetFlags(const GWEN_XML_CONTEXT *ctx) {
00093   assert(ctx);
00094   return ctx->flags;
00095 }
00096 
00097 
00098 
00099 void GWEN_XmlCtx_SetFlags(GWEN_XML_CONTEXT *ctx, uint32_t f) {
00100   assert(ctx);
00101   ctx->flags=f;
00102 }
00103 
00104 
00105 
00106 int GWEN_XmlCtx_GetDepth(const GWEN_XML_CONTEXT *ctx) {
00107   assert(ctx);
00108   return ctx->depth;
00109 }
00110 
00111 
00112 
00113 void GWEN_XmlCtx_SetDepth(GWEN_XML_CONTEXT *ctx, int i) {
00114   assert(ctx);
00115   ctx->depth=i;
00116 }
00117 
00118 
00119 
00120 void GWEN_XmlCtx_IncDepth(GWEN_XML_CONTEXT *ctx) {
00121   assert(ctx);
00122   ctx->depth++;
00123 }
00124 
00125 
00126 
00127 int GWEN_XmlCtx_DecDepth(GWEN_XML_CONTEXT *ctx) {
00128   assert(ctx);
00129   if (ctx->depth<1)
00130     return -1;
00131   ctx->depth--;
00132   return 0;
00133 }
00134 
00135 
00136 
00137 uint32_t GWEN_XmlCtx_GetFinishedElement(const GWEN_XML_CONTEXT *ctx) {
00138   assert(ctx);
00139   return ctx->finishedElements;
00140 }
00141 
00142 
00143 
00144 void GWEN_XmlCtx_IncFinishedElement(GWEN_XML_CONTEXT *ctx) {
00145   assert(ctx);
00146   ctx->finishedElements++;
00147 }
00148 
00149 
00150 
00151 void GWEN_XmlCtx_ResetFinishedElement(GWEN_XML_CONTEXT *ctx) {
00152   assert(ctx);
00153   ctx->finishedElements=0;
00154 }
00155 
00156 
00157 
00158 void GWEN_XmlCtx_SetCurrentNode(GWEN_XML_CONTEXT *ctx, GWEN_XMLNODE *n) {
00159   assert(ctx);
00160   ctx->currentNode=n;
00161 }
00162 
00163 
00164 
00165 GWEN_XMLNODE *GWEN_XmlCtx_GetCurrentNode(const GWEN_XML_CONTEXT *ctx) {
00166   assert(ctx);
00167   return ctx->currentNode;
00168 }
00169 
00170 
00171 
00172 void GWEN_XmlCtx_SetCurrentHeader(GWEN_XML_CONTEXT *ctx, GWEN_XMLNODE *n) {
00173   assert(ctx);
00174   ctx->currentHeader=n;
00175 }
00176 
00177 
00178 
00179 GWEN_XMLNODE *GWEN_XmlCtx_GetCurrentHeader(const GWEN_XML_CONTEXT *ctx) {
00180   assert(ctx);
00181   return ctx->currentHeader;
00182 }
00183 
00184 
00185 
00186 GWEN_XMLCTX_STARTTAG_FN GWEN_XmlCtx_SetStartTagFn(GWEN_XML_CONTEXT *ctx,
00187                                                   GWEN_XMLCTX_STARTTAG_FN f){
00188   GWEN_XMLCTX_STARTTAG_FN of;
00189 
00190   assert(ctx);
00191   of=ctx->startTagFn;
00192   ctx->startTagFn=f;
00193   return of;
00194 }
00195 
00196 
00197 
00198 GWEN_XMLCTX_ENDTAG_FN GWEN_XmlCtx_SetEndTagFn(GWEN_XML_CONTEXT *ctx,
00199                                               GWEN_XMLCTX_ENDTAG_FN f) {
00200   GWEN_XMLCTX_ENDTAG_FN of;
00201 
00202   assert(ctx);
00203   of=ctx->endTagFn;
00204   ctx->endTagFn=f;
00205   return of;
00206 }
00207 
00208 
00209 
00210 GWEN_XMLCTX_ADDDATA_FN GWEN_XmlCtx_SetAddDataFn(GWEN_XML_CONTEXT *ctx,
00211                                                 GWEN_XMLCTX_ADDDATA_FN f) {
00212   GWEN_XMLCTX_ADDDATA_FN of;
00213 
00214   assert(ctx);
00215   of=ctx->addDataFn;
00216   ctx->addDataFn=f;
00217   return of;
00218 }
00219 
00220 
00221 
00222 GWEN_XMLCTX_ADDATTR_FN GWEN_XmlCtx_SetAddAttrFn(GWEN_XML_CONTEXT *ctx,
00223                                                 GWEN_XMLCTX_ADDATTR_FN f) {
00224   GWEN_XMLCTX_ADDATTR_FN of;
00225 
00226   assert(ctx);
00227   of=ctx->addAttrFn;
00228   ctx->addAttrFn=f;
00229   return of;
00230 }
00231 
00232 
00233 
00234 GWEN_XMLCTX_ADDCOMMENT_FN
00235 GWEN_XmlCtx_SetAddCommentFn(GWEN_XML_CONTEXT *ctx,
00236                             GWEN_XMLCTX_ADDCOMMENT_FN f) {
00237   GWEN_XMLCTX_ADDCOMMENT_FN of;
00238 
00239   assert(ctx);
00240   of=ctx->addCommentFn;
00241   ctx->addCommentFn=f;
00242   return of;
00243 }
00244 
00245 
00246 
00247 
00248 int GWEN_XmlCtx_StartTag(GWEN_XML_CONTEXT *ctx, const char *tagName) {
00249   assert(ctx);
00250 
00251   if (ctx->startTagFn)
00252     return ctx->startTagFn(ctx, tagName);
00253   else {
00254     DBG_INFO(GWEN_LOGDOMAIN, "Starting tag: [%s]", tagName);
00255     return 0;
00256   }
00257 }
00258 
00259 
00260 
00261 int GWEN_XmlCtx_EndTag(GWEN_XML_CONTEXT *ctx, int closing) {
00262   assert(ctx);
00263 
00264   if (ctx->endTagFn)
00265     return ctx->endTagFn(ctx, closing);
00266   else {
00267     DBG_INFO(GWEN_LOGDOMAIN, "Ending tag (%s)", closing?"closing":"not closing");
00268     return 0;
00269   }
00270 }
00271 
00272 
00273 
00274 int GWEN_XmlCtx_AddData(GWEN_XML_CONTEXT *ctx, const char *data) {
00275   assert(ctx);
00276 
00277   if (ctx->addDataFn)
00278     return ctx->addDataFn(ctx, data);
00279   else {
00280     DBG_INFO(GWEN_LOGDOMAIN, "Adding data: [%s]", data);
00281     return 0;
00282   }
00283 }
00284 
00285 
00286 
00287 int GWEN_XmlCtx_AddComment(GWEN_XML_CONTEXT *ctx, const char *data) {
00288   assert(ctx);
00289 
00290   if (ctx->addCommentFn)
00291     return ctx->addCommentFn(ctx, data);
00292   else {
00293     DBG_INFO(GWEN_LOGDOMAIN, "Adding comment: [%s]", data);
00294     return 0;
00295   }
00296 }
00297 
00298 
00299 
00300 int GWEN_XmlCtx_AddAttr(GWEN_XML_CONTEXT *ctx,
00301                         const char *attrName,
00302                         const char *attrData) {
00303   assert(ctx);
00304 
00305   if (ctx->addAttrFn)
00306     return ctx->addAttrFn(ctx, attrName, attrData);
00307   else {
00308     DBG_INFO(GWEN_LOGDOMAIN, "Adding attribute: [%s]=[%s]",
00309              attrName, attrData);
00310     return 0;
00311   }
00312 }
00313 
00314 
00315 
00316 
00317 
00318 
00319 
00320 
00321 GWEN_XML_CONTEXT *GWEN_XmlCtxStore_new(GWEN_XMLNODE *n,
00322                                        uint32_t flags,
00323                                        uint32_t guiid,
00324                                        int timeout) {
00325   GWEN_XML_CONTEXT *ctx;
00326 
00327   ctx=GWEN_XmlCtx_new(flags, guiid, timeout);
00328   assert(ctx);
00329 
00330   GWEN_XmlCtx_SetCurrentNode(ctx, n);
00331 
00332   GWEN_XmlCtx_SetStartTagFn(ctx, GWEN_XmlCtxStore_StartTag);
00333   GWEN_XmlCtx_SetEndTagFn(ctx, GWEN_XmlCtxStore_EndTag);
00334   GWEN_XmlCtx_SetAddDataFn(ctx, GWEN_XmlCtxStore_AddData);
00335   GWEN_XmlCtx_SetAddCommentFn(ctx, GWEN_XmlCtxStore_AddComment);
00336   GWEN_XmlCtx_SetAddAttrFn(ctx, GWEN_XmlCtxStore_AddAttr);
00337 
00338   return ctx;
00339 }
00340 
00341 
00342 
00343 int GWEN_XmlCtxStore_StartTag(GWEN_XML_CONTEXT *ctx, const char *tagName) {
00344   GWEN_XMLNODE *currNode;
00345   GWEN_XMLNODE *newNode;
00346 
00347   currNode=GWEN_XmlCtx_GetCurrentNode(ctx);
00348   if (currNode==NULL)
00349     return GWEN_ERROR_INVALID;
00350 
00351   if (*tagName=='?' && (GWEN_XmlCtx_GetFlags(ctx) & GWEN_XML_FLAGS_HANDLE_HEADERS)) {
00352     newNode=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, tagName);
00353     assert(newNode);
00354     DBG_VERBOUS(GWEN_LOGDOMAIN, "Adding header [%s] to [%s]",
00355                 GWEN_XMLNode_GetData(newNode),
00356                 GWEN_XMLNode_GetData(currNode));
00357     GWEN_XMLNode_AddHeader(currNode, newNode);
00358     GWEN_XmlCtx_SetCurrentHeader(ctx, newNode);
00359   }
00360   else if (*tagName=='/') {
00361     const char *s;
00362 
00363     tagName++;
00364     DBG_VERBOUS(GWEN_LOGDOMAIN, "Finishing tag [%s]", tagName);
00365     s=GWEN_XMLNode_GetData(currNode);
00366     if (s==NULL) {
00367       DBG_INFO(GWEN_LOGDOMAIN, "Current node tag has no name");
00368       return GWEN_ERROR_BAD_DATA;
00369     }
00370 
00371     if (strcasecmp(s, tagName)!=0) {
00372       if (!(GWEN_XmlCtx_GetFlags(ctx) & GWEN_XML_FLAGS_TOLERANT_ENDTAGS)) {
00373         DBG_INFO(GWEN_LOGDOMAIN,
00374                  "Endtag does not match curent tag (%s != %s)", s, tagName);
00375         return GWEN_ERROR_BAD_DATA;
00376       }
00377       else {
00378         newNode=currNode;
00379         
00380         while( (newNode=GWEN_XMLNode_GetParent(newNode)) ) {
00381           GWEN_XmlCtx_DecDepth(ctx);
00382           s=GWEN_XMLNode_GetData(newNode);
00383           if (strcasecmp(s, tagName)==0)
00384             break;
00385         }
00386         if (newNode)
00387           newNode=GWEN_XMLNode_GetParent(newNode);
00388         if (newNode) {
00389           GWEN_XmlCtx_SetCurrentNode(ctx, newNode);
00390           GWEN_XmlCtx_DecDepth(ctx);
00391         }
00392         else {
00393           DBG_INFO(GWEN_LOGDOMAIN, "No matching parent node for [%s]",
00394                    tagName);
00395           return GWEN_ERROR_BAD_DATA;
00396         }
00397       }
00398     }
00399     else {
00400       newNode=GWEN_XMLNode_GetParent(currNode);
00401       if (newNode==NULL) {
00402         DBG_INFO(GWEN_LOGDOMAIN, "No parent node at [%s]", tagName);
00403         return GWEN_ERROR_BAD_DATA;
00404       }
00405       GWEN_XmlCtx_SetCurrentNode(ctx, newNode);
00406       GWEN_XmlCtx_DecDepth(ctx);
00407     }
00408     /* one more element finished */
00409     GWEN_XmlCtx_IncFinishedElement(ctx);
00410   }
00411   else {
00412     newNode=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, tagName);
00413     assert(newNode);
00414     GWEN_XMLNode_AddChild(currNode, newNode);
00415     GWEN_XmlCtx_SetCurrentNode(ctx, newNode);
00416     GWEN_XmlCtx_IncDepth(ctx);
00417     DBG_VERBOUS(GWEN_LOGDOMAIN, "Starting tag [%s]", tagName);
00418   }
00419 
00420   return 0;
00421 }
00422 
00423 
00424 
00425 int GWEN_XmlCtxStore_EndTag(GWEN_XML_CONTEXT *ctx, int closing) {
00426   GWEN_XMLNODE *currNode;
00427 
00428   currNode=GWEN_XmlCtx_GetCurrentHeader(ctx);
00429   if (currNode) {
00430     DBG_VERBOUS(GWEN_LOGDOMAIN, "Ending header [%s]", GWEN_XMLNode_GetData(currNode));
00431     GWEN_XmlCtx_SetCurrentHeader(ctx, NULL);
00432   }
00433   else {
00434     currNode=GWEN_XmlCtx_GetCurrentNode(ctx);
00435     if (currNode==NULL)
00436       return GWEN_ERROR_INVALID;
00437     DBG_VERBOUS(GWEN_LOGDOMAIN, "Ending tag [%s] (%s)",
00438                 GWEN_XMLNode_GetData(currNode),
00439                 closing?"closing":"not closing");
00440 
00441     if (closing) {
00442       GWEN_XMLNODE *newNode;
00443 
00444       newNode=GWEN_XMLNode_GetParent(currNode);
00445       if (newNode==NULL) {
00446         DBG_INFO(GWEN_LOGDOMAIN, "No parent node at [%s]", GWEN_XMLNode_GetData(currNode));
00447         return GWEN_ERROR_BAD_DATA;
00448       }
00449       GWEN_XmlCtx_SetCurrentNode(ctx, newNode);
00450       /* one more element finished */
00451       GWEN_XmlCtx_DecDepth(ctx);
00452       GWEN_XmlCtx_IncFinishedElement(ctx);
00453     }
00454   }
00455 
00456   return 0;
00457 }
00458 
00459 
00460 
00461 int GWEN_XmlCtxStore_AddData(GWEN_XML_CONTEXT *ctx, const char *data) {
00462   GWEN_XMLNODE *currNode;
00463   GWEN_BUFFER *buf;
00464   uint32_t flags;
00465 
00466   flags=GWEN_XmlCtx_GetFlags(ctx);
00467   currNode=GWEN_XmlCtx_GetCurrentNode(ctx);
00468   if (currNode==NULL)
00469     return GWEN_ERROR_INVALID;
00470 
00471   buf=GWEN_Buffer_new(0, 64, 0, 1);
00472   if (GWEN_Text_UnescapeXmlToBuffer(data, buf)) {
00473     GWEN_Buffer_free(buf);
00474     DBG_INFO(GWEN_LOGDOMAIN, "here");
00475     return GWEN_ERROR_BAD_DATA;
00476   }
00477 
00478   if (!(flags & GWEN_XML_FLAGS_NO_CONDENSE) ||
00479       (flags & GWEN_XML_FLAGS_KEEP_CNTRL) ||
00480       (flags & GWEN_XML_FLAGS_KEEP_BLANKS)) {
00481     const uint8_t *p;
00482     uint8_t *dst;
00483     uint8_t *src;
00484     unsigned int size;
00485     unsigned int i;
00486     int lastWasBlank;
00487     uint8_t *lastBlankPos;
00488     uint32_t bStart=0;
00489 
00490     dst=(uint8_t*)GWEN_Buffer_GetStart(buf);
00491     src=dst;
00492     if (!(flags & GWEN_XML_FLAGS_KEEP_BLANKS)) {
00493       if (flags & GWEN_XML_FLAGS_KEEP_CNTRL) {
00494         while(*src && (*src==32 || *src==9))
00495           src++;
00496       }
00497       else {
00498         while(*src && *src<33)
00499           src++;
00500       }
00501     }
00502 
00503     p=src;
00504     bStart=src-((uint8_t*)GWEN_Buffer_GetStart(buf));
00505     size=GWEN_Buffer_GetUsedBytes(buf)-bStart;
00506     lastWasBlank=0;
00507     lastBlankPos=0;
00508 
00509     for (i=0; i<size; i++) {
00510       uint8_t c;
00511 
00512       c=*p;
00513       if (!(flags & GWEN_XML_FLAGS_KEEP_CNTRL) && c<32)
00514         c=32;
00515 
00516       /* remember next loop whether this char was a blank */
00517       if (!(flags & GWEN_XML_FLAGS_NO_CONDENSE) && c==32) {
00518         if (!lastWasBlank) {
00519           /* store only one blank */
00520           lastWasBlank=1;
00521           lastBlankPos=dst;
00522           *(dst++)=c;
00523         }
00524       }
00525       else {
00526         lastWasBlank=0;
00527         lastBlankPos=0;
00528         *(dst++)=c;
00529       }
00530       p++;
00531     }
00532 
00533     /* remove trailing blanks */
00534     if (lastBlankPos!=0)
00535       dst=lastBlankPos;
00536 
00537     size=dst-(uint8_t*)GWEN_Buffer_GetStart(buf);
00538     GWEN_Buffer_Crop(buf, 0, size);
00539   }
00540 
00541   if (GWEN_Buffer_GetUsedBytes(buf)) {
00542     GWEN_XMLNODE *newNode;
00543 
00544     newNode=GWEN_XMLNode_new(GWEN_XMLNodeTypeData, GWEN_Buffer_GetStart(buf));
00545     assert(newNode);
00546     GWEN_XMLNode_AddChild(currNode, newNode);
00547     DBG_VERBOUS(GWEN_LOGDOMAIN, "Setting this data: [%s]", GWEN_Buffer_GetStart(buf));
00548   }
00549   GWEN_Buffer_free(buf);
00550 
00551   return 0;
00552 }
00553 
00554 
00555 
00556 int GWEN_XmlCtxStore_AddComment(GWEN_UNUSED GWEN_XML_CONTEXT *ctx, GWEN_UNUSED const char *data) {
00557   return 0;
00558 }
00559 
00560 
00561 
00562 int GWEN_XmlCtxStore_AddAttr(GWEN_XML_CONTEXT *ctx,
00563                              const char *attrName,
00564                              const char *attrData) {
00565   GWEN_XMLNODE *currNode;
00566 
00567   currNode=GWEN_XmlCtx_GetCurrentHeader(ctx);
00568   if (currNode) {
00569     DBG_VERBOUS(GWEN_LOGDOMAIN, "Setting attribute of header [%s]: [%s]=[%s]",
00570                 GWEN_XMLNode_GetData(currNode), attrName, attrData);
00571     GWEN_XMLNode_SetProperty(currNode, attrName, attrData);
00572   }
00573   else {
00574     int isNormalProperty=1;
00575 
00576     currNode=GWEN_XmlCtx_GetCurrentNode(ctx);
00577     if (currNode==NULL)
00578       return GWEN_ERROR_INVALID;
00579     if (attrData==NULL)
00580       attrData="";
00581 
00582     if (ctx->flags & GWEN_XML_FLAGS_HANDLE_NAMESPACES) {
00583       if (strcasecmp(attrName, "xmlns")==0) {
00584         GWEN_XMLNODE_NAMESPACE *ns;
00585 
00586         DBG_VERBOUS(GWEN_LOGDOMAIN, "Adding namespace [%s] to node [%s]",
00587                     attrData, GWEN_XMLNode_GetData(currNode));
00588         ns=GWEN_XMLNode_NameSpace_new("", attrData);
00589         GWEN_XMLNode_AddNameSpace(currNode, ns);
00590         GWEN_XMLNode_NameSpace_free(ns);
00591         isNormalProperty=0;
00592       }
00593       else if (strncasecmp(attrName, "xmlns:", 6)==0) {
00594         const char *name;
00595 
00596         name=strchr(attrName, ':');
00597         if (name) {
00598           name++;
00599           if (*name) {
00600             GWEN_XMLNODE_NAMESPACE *ns;
00601 
00602             DBG_VERBOUS(GWEN_LOGDOMAIN, "Adding namespace [%s]=[%s]",
00603                         name, attrData);
00604             ns=GWEN_XMLNode_NameSpace_new(name, attrData);
00605             GWEN_XMLNode_AddNameSpace(currNode, ns);
00606             GWEN_XMLNode_NameSpace_free(ns);
00607             isNormalProperty=0;
00608           }
00609         }
00610       }
00611     }
00612 
00613     if (isNormalProperty) {
00614       DBG_VERBOUS(GWEN_LOGDOMAIN, "Setting attribute of tag [%s]: [%s]=[%s]",
00615                   GWEN_XMLNode_GetData(currNode), attrName, attrData);
00616       GWEN_XMLNode_SetProperty(currNode, attrName, attrData);
00617     }
00618   }
00619 
00620   return 0;
00621 }
00622 
00623 
00624 
00625 
00626 
00627 
Generated on Mon Jul 5 22:52:48 2010 for gwenhywfar by  doxygen 1.6.3