00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
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
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
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
00517 if (!(flags & GWEN_XML_FLAGS_NO_CONDENSE) && c==32) {
00518 if (!lastWasBlank) {
00519
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
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