gwenhywfar  4.6.0beta
xmlctx.c
Go to the documentation of this file.
1 /***************************************************************************
2  $RCSfile$
3  -------------------
4  cvs : $Id: xsd.c 656 2004-12-22 17:02:05Z aquamaniac $
5  begin : Sat Jun 28 2003
6  copyright : (C) 2003 by Martin Preuss
7  email : martin@libchipcard.de
8 
9  ***************************************************************************
10  * *
11  * This library is free software; you can redistribute it and/or *
12  * modify it under the terms of the GNU Lesser General Public *
13  * License as published by the Free Software Foundation; either *
14  * version 2.1 of the License, or (at your option) any later version. *
15  * *
16  * This library is distributed in the hope that it will be useful, *
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
19  * Lesser General Public License for more details. *
20  * *
21  * You should have received a copy of the GNU Lesser General Public *
22  * License along with this library; if not, write to the Free Software *
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
24  * MA 02111-1307 USA *
25  * *
26  ***************************************************************************/
27 
28 #ifdef HAVE_CONFIG_H
29 # include <config.h>
30 #endif
31 
32 
33 #include "xmlctx_p.h"
34 #include "gwenhywfar/debug.h"
35 #include "gwenhywfar/misc.h"
36 #include "gwenhywfar/text.h"
37 #include "gwenhywfar/path.h"
38 #include "i18n_l.h"
39 
40 #include <stdlib.h>
41 #include <assert.h>
42 #include <string.h>
43 #include <ctype.h>
44 
45 
46 
48 
49 
50 
51 
53  GWEN_XML_CONTEXT *ctx;
54 
56  ctx->_refCount=1;
58 
59  ctx->flags=flags;
60 
61  return ctx;
62 }
63 
64 
65 
67  if (ctx) {
68  assert(ctx->_refCount);
69  if (ctx->_refCount==1) {
71  ctx->_refCount=0;
72  GWEN_FREE_OBJECT(ctx);
73  }
74  else
75  ctx->_refCount--;
76  }
77 }
78 
79 
80 
82  assert(ctx);
83  assert(ctx->_refCount);
84  ctx->_refCount++;
85 }
86 
87 
88 
89 uint32_t GWEN_XmlCtx_GetFlags(const GWEN_XML_CONTEXT *ctx) {
90  assert(ctx);
91  return ctx->flags;
92 }
93 
94 
95 
96 void GWEN_XmlCtx_SetFlags(GWEN_XML_CONTEXT *ctx, uint32_t f) {
97  assert(ctx);
98  ctx->flags=f;
99 }
100 
101 
102 
104  assert(ctx);
105  return ctx->depth;
106 }
107 
108 
109 
111  assert(ctx);
112  ctx->depth=i;
113 }
114 
115 
116 
118  assert(ctx);
119  ctx->depth++;
120 }
121 
122 
123 
125  assert(ctx);
126  if (ctx->depth<1)
127  return -1;
128  ctx->depth--;
129  return 0;
130 }
131 
132 
133 
135  assert(ctx);
136  return ctx->finishedElements;
137 }
138 
139 
140 
142  assert(ctx);
143  ctx->finishedElements++;
144 }
145 
146 
147 
149  assert(ctx);
150  ctx->finishedElements=0;
151 }
152 
153 
154 
156  assert(ctx);
157  ctx->currentNode=n;
158 }
159 
160 
161 
163  assert(ctx);
164  return ctx->currentNode;
165 }
166 
167 
168 
170  assert(ctx);
171  ctx->currentHeader=n;
172 }
173 
174 
175 
177  assert(ctx);
178  return ctx->currentHeader;
179 }
180 
181 
182 
186 
187  assert(ctx);
188  of=ctx->startTagFn;
189  ctx->startTagFn=f;
190  return of;
191 }
192 
193 
194 
198 
199  assert(ctx);
200  of=ctx->endTagFn;
201  ctx->endTagFn=f;
202  return of;
203 }
204 
205 
206 
210 
211  assert(ctx);
212  of=ctx->addDataFn;
213  ctx->addDataFn=f;
214  return of;
215 }
216 
217 
218 
222 
223  assert(ctx);
224  of=ctx->addAttrFn;
225  ctx->addAttrFn=f;
226  return of;
227 }
228 
229 
230 
235 
236  assert(ctx);
237  of=ctx->addCommentFn;
238  ctx->addCommentFn=f;
239  return of;
240 }
241 
242 
243 
244 
245 int GWEN_XmlCtx_StartTag(GWEN_XML_CONTEXT *ctx, const char *tagName) {
246  assert(ctx);
247 
248  if (ctx->startTagFn)
249  return ctx->startTagFn(ctx, tagName);
250  else {
251  DBG_INFO(GWEN_LOGDOMAIN, "Starting tag: [%s]", tagName);
252  return 0;
253  }
254 }
255 
256 
257 
258 int GWEN_XmlCtx_EndTag(GWEN_XML_CONTEXT *ctx, int closing) {
259  assert(ctx);
260 
261  if (ctx->endTagFn)
262  return ctx->endTagFn(ctx, closing);
263  else {
264  DBG_INFO(GWEN_LOGDOMAIN, "Ending tag (%s)", closing?"closing":"not closing");
265  return 0;
266  }
267 }
268 
269 
270 
271 int GWEN_XmlCtx_AddData(GWEN_XML_CONTEXT *ctx, const char *data) {
272  assert(ctx);
273 
274  if (ctx->addDataFn)
275  return ctx->addDataFn(ctx, data);
276  else {
277  DBG_INFO(GWEN_LOGDOMAIN, "Adding data: [%s]", data);
278  return 0;
279  }
280 }
281 
282 
283 
284 int GWEN_XmlCtx_AddComment(GWEN_XML_CONTEXT *ctx, const char *data) {
285  assert(ctx);
286 
287  if (ctx->addCommentFn)
288  return ctx->addCommentFn(ctx, data);
289  else {
290  DBG_INFO(GWEN_LOGDOMAIN, "Adding comment: [%s]", data);
291  return 0;
292  }
293 }
294 
295 
296 
298  const char *attrName,
299  const char *attrData) {
300  assert(ctx);
301 
302  if (ctx->addAttrFn)
303  return ctx->addAttrFn(ctx, attrName, attrData);
304  else {
305  DBG_INFO(GWEN_LOGDOMAIN, "Adding attribute: [%s]=[%s]",
306  attrName, attrData);
307  return 0;
308  }
309 }
310 
311 
312 
313 
314 
315 
316 
317 
319  GWEN_XML_CONTEXT *ctx;
320 
321  ctx=GWEN_XmlCtx_new(flags);
322  assert(ctx);
323 
325 
331 
332  return ctx;
333 }
334 
335 
336 
337 int GWEN_XmlCtxStore_StartTag(GWEN_XML_CONTEXT *ctx, const char *tagName) {
338  GWEN_XMLNODE *currNode;
339  GWEN_XMLNODE *newNode;
340 
341  currNode=GWEN_XmlCtx_GetCurrentNode(ctx);
342  if (currNode==NULL)
343  return GWEN_ERROR_INVALID;
344 
345  if (*tagName=='?' && (GWEN_XmlCtx_GetFlags(ctx) & GWEN_XML_FLAGS_HANDLE_HEADERS)) {
346  newNode=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, tagName);
347  assert(newNode);
348  DBG_VERBOUS(GWEN_LOGDOMAIN, "Adding header [%s] to [%s]",
349  GWEN_XMLNode_GetData(newNode),
350  GWEN_XMLNode_GetData(currNode));
351  GWEN_XMLNode_AddHeader(currNode, newNode);
352  GWEN_XmlCtx_SetCurrentHeader(ctx, newNode);
353  }
354  else if (strcasecmp(tagName, "!DOCTYPE")==0) {
355  newNode=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, tagName);
356  assert(newNode);
357  DBG_VERBOUS(GWEN_LOGDOMAIN, "Adding header [%s] to [%s]",
358  GWEN_XMLNode_GetData(newNode),
359  GWEN_XMLNode_GetData(currNode));
360  GWEN_XMLNode_AddHeader(currNode, newNode);
361  GWEN_XmlCtx_SetCurrentHeader(ctx, newNode);
362  }
363  else if (*tagName=='/') {
364  const char *s;
365 
366  tagName++;
367  DBG_VERBOUS(GWEN_LOGDOMAIN, "Finishing tag [%s]", tagName);
368  s=GWEN_XMLNode_GetData(currNode);
369  if (s==NULL) {
370  DBG_INFO(GWEN_LOGDOMAIN, "Current node tag has no name");
371  return GWEN_ERROR_BAD_DATA;
372  }
373 
374  if (strcasecmp(s, tagName)!=0) {
377  "Endtag does not match curent tag (%s != %s)", s, tagName);
378  return GWEN_ERROR_BAD_DATA;
379  }
380  else {
381  newNode=currNode;
382 
383  while( (newNode=GWEN_XMLNode_GetParent(newNode)) ) {
385  s=GWEN_XMLNode_GetData(newNode);
386  if (strcasecmp(s, tagName)==0)
387  break;
388  }
389  if (newNode)
390  newNode=GWEN_XMLNode_GetParent(newNode);
391  if (newNode) {
392  GWEN_XmlCtx_SetCurrentNode(ctx, newNode);
394  }
395  else {
396  DBG_INFO(GWEN_LOGDOMAIN, "No matching parent node for [%s]",
397  tagName);
398  return GWEN_ERROR_BAD_DATA;
399  }
400  }
401  }
402  else {
403  newNode=GWEN_XMLNode_GetParent(currNode);
404  if (newNode==NULL) {
405  DBG_INFO(GWEN_LOGDOMAIN, "No parent node at [%s]", tagName);
406  return GWEN_ERROR_BAD_DATA;
407  }
408  GWEN_XmlCtx_SetCurrentNode(ctx, newNode);
410  }
411  /* one more element finished */
413  }
414  else {
415  newNode=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, tagName);
416  assert(newNode);
417  GWEN_XMLNode_AddChild(currNode, newNode);
418  GWEN_XmlCtx_SetCurrentNode(ctx, newNode);
420  DBG_VERBOUS(GWEN_LOGDOMAIN, "Starting tag [%s]", tagName);
421  }
422 
423  return 0;
424 }
425 
426 
427 
429  GWEN_XMLNODE *currNode;
430 
431  currNode=GWEN_XmlCtx_GetCurrentHeader(ctx);
432  if (currNode) {
433  DBG_VERBOUS(GWEN_LOGDOMAIN, "Ending header [%s]", GWEN_XMLNode_GetData(currNode));
435  }
436  else {
437  currNode=GWEN_XmlCtx_GetCurrentNode(ctx);
438  if (currNode==NULL)
439  return GWEN_ERROR_INVALID;
440  DBG_VERBOUS(GWEN_LOGDOMAIN, "Ending tag [%s] (%s)",
441  GWEN_XMLNode_GetData(currNode),
442  closing?"closing":"not closing");
443 
444  if (closing) {
445  GWEN_XMLNODE *newNode;
446 
447  newNode=GWEN_XMLNode_GetParent(currNode);
448  if (newNode==NULL) {
449  DBG_INFO(GWEN_LOGDOMAIN, "No parent node at [%s]", GWEN_XMLNode_GetData(currNode));
450  return GWEN_ERROR_BAD_DATA;
451  }
452  GWEN_XmlCtx_SetCurrentNode(ctx, newNode);
453  /* one more element finished */
456  }
457  }
458 
459  return 0;
460 }
461 
462 
463 
464 int GWEN_XmlCtxStore_AddData(GWEN_XML_CONTEXT *ctx, const char *data) {
465  GWEN_XMLNODE *currNode;
466  GWEN_BUFFER *buf;
467  uint32_t flags;
468 
469  flags=GWEN_XmlCtx_GetFlags(ctx);
470  currNode=GWEN_XmlCtx_GetCurrentNode(ctx);
471  if (currNode==NULL)
472  return GWEN_ERROR_INVALID;
473 
474  buf=GWEN_Buffer_new(0, 64, 0, 1);
475  if (GWEN_Text_UnescapeXmlToBuffer(data, buf)) {
476  GWEN_Buffer_free(buf);
477  DBG_INFO(GWEN_LOGDOMAIN, "here");
478  return GWEN_ERROR_BAD_DATA;
479  }
480 
481  if (!(flags & GWEN_XML_FLAGS_NO_CONDENSE) ||
482  (flags & GWEN_XML_FLAGS_KEEP_CNTRL) ||
483  (flags & GWEN_XML_FLAGS_KEEP_BLANKS)) {
484  const uint8_t *p;
485  uint8_t *dst;
486  uint8_t *src;
487  unsigned int size;
488  unsigned int i;
489  int lastWasBlank;
490  uint8_t *lastBlankPos;
491  uint32_t bStart=0;
492 
493  dst=(uint8_t*)GWEN_Buffer_GetStart(buf);
494  src=dst;
495  if (!(flags & GWEN_XML_FLAGS_KEEP_BLANKS)) {
496  if (flags & GWEN_XML_FLAGS_KEEP_CNTRL) {
497  while(*src && (*src==32 || *src==9))
498  src++;
499  }
500  else {
501  while(*src && *src<33)
502  src++;
503  }
504  }
505 
506  p=src;
507  bStart=src-((uint8_t*)GWEN_Buffer_GetStart(buf));
508  size=GWEN_Buffer_GetUsedBytes(buf)-bStart;
509  lastWasBlank=0;
510  lastBlankPos=0;
511 
512  for (i=0; i<size; i++) {
513  uint8_t c;
514 
515  c=*p;
516  if (!(flags & GWEN_XML_FLAGS_KEEP_CNTRL) && c<32)
517  c=32;
518 
519  /* remember next loop whether this char was a blank */
520  if (!(flags & GWEN_XML_FLAGS_NO_CONDENSE) && c==32) {
521  if (!lastWasBlank) {
522  /* store only one blank */
523  lastWasBlank=1;
524  lastBlankPos=dst;
525  *(dst++)=c;
526  }
527  }
528  else {
529  lastWasBlank=0;
530  lastBlankPos=0;
531  *(dst++)=c;
532  }
533  p++;
534  }
535 
536  /* remove trailing blanks */
537  if (lastBlankPos!=0)
538  dst=lastBlankPos;
539 
540  size=dst-(uint8_t*)GWEN_Buffer_GetStart(buf);
541  GWEN_Buffer_Crop(buf, 0, size);
542  }
543 
544  if (GWEN_Buffer_GetUsedBytes(buf)) {
545  GWEN_XMLNODE *newNode;
546 
548  assert(newNode);
549  GWEN_XMLNode_AddChild(currNode, newNode);
550  DBG_VERBOUS(GWEN_LOGDOMAIN, "Setting this data: [%s]", GWEN_Buffer_GetStart(buf));
551  }
552  GWEN_Buffer_free(buf);
553 
554  return 0;
555 }
556 
557 
558 
560  return 0;
561 }
562 
563 
564 
566  const char *attrName,
567  const char *attrData) {
568  GWEN_XMLNODE *currNode;
569 
570  currNode=GWEN_XmlCtx_GetCurrentHeader(ctx);
571  if (currNode) {
572  DBG_VERBOUS(GWEN_LOGDOMAIN, "Setting attribute of header [%s]: [%s]=[%s]",
573  GWEN_XMLNode_GetData(currNode), attrName, attrData);
574  GWEN_XMLNode_SetProperty(currNode, attrName, attrData);
575  }
576  else {
577  int isNormalProperty=1;
578 
579  currNode=GWEN_XmlCtx_GetCurrentNode(ctx);
580  if (currNode==NULL)
581  return GWEN_ERROR_INVALID;
582  if (attrData==NULL)
583  attrData="";
584 
585  if (ctx->flags & GWEN_XML_FLAGS_HANDLE_NAMESPACES) {
586  if (strcasecmp(attrName, "xmlns")==0) {
588 
589  DBG_VERBOUS(GWEN_LOGDOMAIN, "Adding namespace [%s] to node [%s]",
590  attrData, GWEN_XMLNode_GetData(currNode));
591  ns=GWEN_XMLNode_NameSpace_new("", attrData);
592  GWEN_XMLNode_AddNameSpace(currNode, ns);
594  isNormalProperty=0;
595  }
596  else if (strncasecmp(attrName, "xmlns:", 6)==0) {
597  const char *name;
598 
599  name=strchr(attrName, ':');
600  if (name) {
601  name++;
602  if (*name) {
604 
605  DBG_VERBOUS(GWEN_LOGDOMAIN, "Adding namespace [%s]=[%s]",
606  name, attrData);
607  ns=GWEN_XMLNode_NameSpace_new(name, attrData);
608  GWEN_XMLNode_AddNameSpace(currNode, ns);
610  isNormalProperty=0;
611  }
612  }
613  }
614  }
615 
616  if (isNormalProperty) {
617  GWEN_BUFFER *buf;
618 
619  DBG_VERBOUS(GWEN_LOGDOMAIN, "Setting attribute of tag [%s]: [%s]=[%s]",
620  GWEN_XMLNode_GetData(currNode), attrName, attrData);
621  buf=GWEN_Buffer_new(0, 64, 0, 1);
622  if (GWEN_Text_UnescapeXmlToBuffer(attrData, buf)) {
623  GWEN_Buffer_free(buf);
624  DBG_INFO(GWEN_LOGDOMAIN, "here");
625  return GWEN_ERROR_BAD_DATA;
626  }
627  GWEN_XMLNode_SetProperty(currNode, attrName, GWEN_Buffer_GetStart(buf));
628  GWEN_Buffer_free(buf);
629  }
630  }
631 
632  return 0;
633 }
634 
635 
636 
637 
638 
639