1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <xml/xml_tinyParser.h>
18
19int32_t xml_errno;
20
21#ifdef XML_DOM_PARSER
22
23#define XML_IS_WHITESPACE(x) ((x) == '\t' || (x) == '\n' || (x) == ' ' || (x) == '\r')
24#define XML_IS_NAMECHAR(ch) (isalpha(ch) || isdigit(ch) || ch ==':' || \
25                             ch == '_' || ch == '-' || ch =='.')
26
27static uint8_t *xml_ignore_blank(uint8_t *buffer)
28{
29    if (NULL == buffer)
30        return NULL;
31
32    while (XML_IS_WHITESPACE(*buffer))
33        buffer++;
34
35    return buffer;
36}
37
38static uint8_t *xml_goto_tagend(uint8_t *buffer)
39{
40    int32_t nameLen, valueLen;
41    uint8_t *name, *value;
42
43    if (NULL == buffer)
44        return NULL;
45
46    /* Ignore the start-tag */
47    if (*buffer == '<') {
48        buffer++;
49        while (buffer != NULL && XML_IS_NAMECHAR(*buffer))
50            buffer++;
51        if (NULL == buffer)
52            return NULL;
53    }
54
55    do {
56        if (NULL == (buffer = xml_ignore_blank(buffer)))
57            return NULL;
58
59        if (*buffer == '>' || (*buffer == '/' && *(buffer + 1) == '>'))
60            return buffer;
61
62        if (NULL ==
63            XML_DOM_getAttr(buffer, &name, &nameLen, &value, &valueLen))
64            return NULL;
65
66        buffer = value + valueLen + 1;
67    } while (*buffer != '\0');
68
69    return NULL;
70}
71
72static uint8_t *xml_match_tag(uint8_t *buffer)
73{
74    int32_t tagLen, tagType, bal;
75
76    if (NULL == buffer)
77        return NULL;
78
79    bal = 0;
80    do {
81        if (NULL == (buffer = XML_DOM_getTag(buffer, &tagLen, &tagType)))
82            return NULL;
83
84        switch (tagType) {
85        case XML_TAG_SELF:
86        case XML_TAG_START:
87            if (NULL == (buffer = xml_goto_tagend(buffer + tagLen + 1)))
88                return NULL;
89            if (strncmp((char *)buffer, "/>", 2) == 0) {
90                buffer += 2;
91            } else {
92                bal++;
93            }
94            break;
95
96        case XML_TAG_END:
97            if (bal <= 0)
98                return NULL;
99            buffer = buffer + tagLen + 2;
100            bal--;
101            break;
102        }
103    } while (bal != 0);
104
105    return buffer;
106}
107
108uint8_t *XML_DOM_getAttr(uint8_t *buffer, uint8_t **pName, int32_t *nameLen,
109                      uint8_t **pValue, int32_t *valueLen)
110{
111    uint8_t charQuoted;
112
113    if (NULL == buffer) {
114        XML_ERROR(XML_ERROR_BUFFER_NULL);
115        return NULL;
116    }
117
118    /* Ignore the tag */
119    if (*buffer == '<') {
120        buffer++;
121        /* Ignore the STag */
122        while (buffer != NULL && XML_IS_NAMECHAR(*buffer))
123            buffer++;
124        if (NULL == buffer)
125            return NULL;
126    }
127
128    if (NULL == (buffer = xml_ignore_blank(buffer))) {
129        XML_ERROR(XML_ERROR_BUFFER_NULL);
130        return NULL;
131    }
132
133    /* Name */
134    *pName = buffer;
135    while (buffer != NULL && XML_IS_NAMECHAR(*buffer))
136        buffer++;
137    if (NULL == buffer) {
138        XML_ERROR(XML_ERROR_ATTR_NAME);
139        return NULL;
140    }
141    *nameLen = buffer - *pName;
142    if (*nameLen <= 0) {
143        XML_ERROR(XML_ERROR_ATTR_NAME);
144        return NULL;
145    }
146
147    /* '=' */
148    buffer = xml_ignore_blank(buffer);
149    if (NULL == buffer || *buffer != '=') {
150        XML_ERROR(XML_ERROR_ATTR_MISSED_EQUAL);
151        return NULL;
152    }
153
154    /* Value */
155    buffer++;
156    buffer = xml_ignore_blank(buffer);
157    if (NULL == buffer || (*buffer != '"' && *buffer != '\'')) {
158        XML_ERROR(XML_ERROR_ATTR_VALUE);
159        return NULL;
160    }
161    charQuoted = *buffer++;
162    *pValue = buffer;
163    while (*buffer != '\0' && *buffer != charQuoted)
164        buffer++;
165    if (*buffer != charQuoted) {
166        XML_ERROR(XML_ERROR_ATTR_VALUE);
167        return NULL;
168    }
169    *valueLen = buffer - *pValue;
170
171    XML_ERROR(XML_ERROR_OK);
172
173    return buffer + 1;
174}
175
176uint8_t *XML_DOM_getValue(uint8_t *buffer, uint8_t **pValue, int32_t *valueLen)
177{
178    uint8_t *pEnd;
179
180    if (NULL == buffer) {
181        XML_ERROR(XML_ERROR_BUFFER_NULL);
182        return NULL;
183    }
184
185    /* Ignore the STag */
186    if (*buffer == '<') {
187        buffer++;
188        /* If it's an end_tag, no value should be returned */
189        if (*buffer == '/') {
190            *valueLen = 0;
191            XML_ERROR(XML_ERROR_NOVALUE);
192            return NULL;
193        }
194
195        while (buffer != NULL && XML_IS_NAMECHAR(*buffer))
196            buffer++;
197        if (NULL == buffer) {
198            XML_ERROR(XML_ERROR_BUFFER_NULL);
199            return NULL;
200        }
201
202        if (NULL == (buffer = xml_goto_tagend(buffer))) {
203            XML_ERROR(XML_ERROR_PROPERTY_END);
204            return NULL;
205        }
206    }
207
208    /* <test/> node found */
209    if (*buffer == '/') {
210        if (*(buffer + 1) != '>') {
211            XML_ERROR(XML_ERROR_PROPERTY_END);
212            return NULL;
213        }
214        XML_ERROR(XML_ERROR_OK);
215        *valueLen = 0;
216        return buffer;
217    }
218
219    if (*buffer == '>')
220        buffer++;
221
222    if (NULL == (buffer = xml_ignore_blank(buffer))) {
223        XML_ERROR(XML_ERROR_BUFFER_NULL);
224        return NULL;
225    }
226
227    /* the following is a tag instead of the value */
228    if (*buffer == '<') { /* nono value, such as <test></test> */
229        buffer++;
230        if (*buffer != '/') {
231            XML_ERROR(XML_ERROR_ENDTAG);
232            return NULL;
233        }
234        *valueLen = 0;
235        XML_ERROR(XML_ERROR_OK);
236        return NULL;
237    }
238
239    *pValue = buffer;
240    pEnd = NULL;
241    while (*buffer != '\0' && *buffer != '<') {
242        if (!XML_IS_WHITESPACE(*buffer))
243            pEnd = buffer;
244        buffer++;
245    }
246    if (*buffer != '<' || pEnd == NULL) {
247        XML_ERROR(XML_ERROR_VALUE);
248        return NULL;
249    }
250
251    *valueLen = pEnd - *pValue + 1;
252
253    buffer++;
254    if (*buffer != '/') {
255        XML_ERROR(XML_ERROR_ENDTAG);
256        return NULL;
257    }
258
259    XML_ERROR(XML_ERROR_OK);
260
261    return buffer - 1;
262}
263
264uint8_t *XML_DOM_getTag(uint8_t *buffer, int32_t *tagLen, int32_t *tagType)
265{
266    uint8_t *pStart;
267
268    /* WARNING: <!-- --> comment is not supported in this verison */
269    if (NULL == buffer) {
270        XML_ERROR(XML_ERROR_BUFFER_NULL);
271        return NULL;
272    }
273
274    do {
275        while (*buffer != '<') {
276            if (*buffer == '\0') {
277                XML_ERROR(XML_ERROR_BUFFER_NULL);
278                return NULL;
279            }
280
281            if (*buffer == '\"' || *buffer == '\'') {
282                uint8_t charQuoted = *buffer;
283                buffer++;
284                while (*buffer != '\0' && *buffer != charQuoted)
285                    buffer++;
286                if (*buffer == '\0') {
287                    XML_ERROR(XML_ERROR_BUFFER_NULL);
288                    return NULL;
289                }
290            }
291            buffer++;
292        }
293        buffer++;
294    } while (*buffer == '!' || *buffer == '?');
295
296    pStart = buffer - 1;
297
298    if (*buffer == '/') {
299        buffer++;
300        *tagType = XML_TAG_END;
301    } else {
302        /* check here if it is self-end-tag */
303        uint8_t *pCheck = xml_goto_tagend(pStart);
304        if (pCheck == NULL) {
305            XML_ERROR(XML_ERROR_PROPERTY_END);
306            return NULL;
307        }
308
309        if (*pCheck == '>')
310            *tagType = XML_TAG_START;
311        else if (strncmp((char *)pCheck, "/>", 2) == 0)
312            *tagType = XML_TAG_SELF;
313        else {
314            XML_ERROR(XML_ERROR_PROPERTY_END);
315            return NULL;
316        }
317    }
318
319    while (buffer != NULL && XML_IS_NAMECHAR(*buffer))
320        buffer++;
321    if (NULL == buffer) {
322        XML_ERROR(XML_ERROR_BUFFER_NULL);
323        return NULL;
324    }
325
326    if (*tagType == XML_TAG_END)
327        *tagLen = buffer - pStart - 2;
328    else
329        *tagLen = buffer - pStart - 1;
330
331    XML_ERROR(XML_ERROR_OK);
332
333    return pStart;
334}
335
336uint8_t *XML_DOM_getNode(uint8_t *buffer, const uint8_t *const node)
337{
338    uint8_t *pStart;
339    uint8_t buf[XML_MAX_PROPERTY_LEN + 2];
340    uint8_t *nodeStr = buf;
341    uint8_t *retPtr = NULL;
342    int32_t tagLen, tagType;
343    uint8_t *lastNode = (uint8_t *)"";
344
345    if (NULL == buffer) {
346        XML_ERROR(XML_ERROR_BUFFER_NULL);
347        return NULL;
348    }
349
350    strncpy((char *)nodeStr, (char *)node, XML_MAX_PROPERTY_LEN);
351    strcat((char *)nodeStr, "\\");
352    pStart = (uint8_t *)strchr((char *)nodeStr, '\\');
353
354    while (pStart != NULL) {
355        *pStart = '\0';
356
357        /* get the first start_tag from buffer */
358        if (NULL == (buffer = XML_DOM_getTag(buffer, &tagLen, &tagType))) {
359            XML_ERROR(XML_ERROR_NO_SUCH_NODE);
360            return NULL;
361        }
362
363        if (tagType == XML_TAG_END) {
364            if (0 ==
365                strncmp((char *)lastNode, (char *)(buffer + 2), strlen((char *)lastNode)))
366                XML_ERROR(XML_ERROR_NO_SUCH_NODE);
367            else
368                XML_ERROR(XML_ERROR_NO_START_TAG);
369            return NULL;
370        }
371
372        /* wrong node, contiue to fetch the next node */
373        if ((int32_t) strlen((char *)nodeStr) != tagLen
374            || strncmp((char *)nodeStr, (char *)(buffer + 1), tagLen) != 0) {
375            /* we should ignore all the middle code */
376            buffer = xml_match_tag(buffer);
377            continue;
378        }
379
380        retPtr = buffer;        /* retPtr starts with '<xxx>' */
381        buffer += (tagLen + 1);
382
383        if (tagType == XML_TAG_SELF) {
384            nodeStr = pStart + 1;
385            break;
386        }
387
388        lastNode = nodeStr;
389        nodeStr = pStart + 1;
390        pStart = (uint8_t *)strchr((char *)nodeStr, '\\');
391    }
392
393    /* Check 5: nodeStr should be empty here */
394    if (*nodeStr != '\0') {
395        XML_ERROR(XML_ERROR_NO_SUCH_NODE);
396        return NULL;
397    }
398
399    XML_ERROR(XML_ERROR_OK);
400
401    return retPtr;
402}
403
404uint8_t *XML_DOM_getNodeValue(uint8_t *buffer, uint8_t *node,
405                           uint8_t **value, int32_t *valueLen)
406{
407    uint8_t *pStart;
408    uint8_t *lastTag;
409
410    if (NULL == node || NULL == buffer) {
411        XML_ERROR(XML_ERROR_BUFFER_NULL);
412        return NULL;
413    }
414
415    lastTag = node + strlen((char *)node) - 1;
416    while (lastTag >= node && *lastTag != '\\')
417        lastTag--;
418    lastTag++;
419
420    if (NULL == (pStart = XML_DOM_getNode(buffer, node)))
421        return NULL;
422
423    pStart += (strlen((char *)lastTag) + 1);
424
425    if (NULL == (pStart = xml_goto_tagend(pStart))) {
426        XML_ERROR(XML_ERROR_PROPERTY_END);
427        return NULL;
428    }
429
430    if (NULL == (pStart = XML_DOM_getValue(pStart, value, valueLen)))
431        return NULL;
432
433    /* Check the end tag */
434#ifdef XML_DOM_CHECK_ENDTAG
435    if (strncmp((char *)pStart, "/>", 2) == 0) {
436
437    } else if (strncmp((char *)lastTag, (char *)(pStart + 2), strlen((char *)lastTag)) !=
438               0) {
439        XML_ERROR(XML_ERROR_ENDTAG);
440        return NULL;
441    }
442#endif
443
444    XML_ERROR(XML_ERROR_OK);
445
446    return *value;
447}
448
449uint8_t *XML_DOM_getNextNode(uint8_t *buffer, uint8_t **pNodeName, int32_t *nodenameLen)
450{
451    int32_t tagType;
452
453    if (NULL == buffer)
454        return NULL;
455
456    do {
457        if (NULL ==
458            (buffer = XML_DOM_getTag(buffer + 1, nodenameLen, &tagType))) {
459            XML_ERROR(XML_ERROR_NO_SUCH_NODE);
460            return NULL;
461        }
462    } while (tagType == XML_TAG_END);
463
464    *pNodeName = buffer + 1;
465
466    XML_ERROR(XML_ERROR_OK);
467
468    return buffer;
469}
470
471#endif /* XML_DOM_PARSER */
472
473#ifdef WBXML_DOM_PARSER
474
475#ifdef WBXML_OLD_VERSION
476uint8_t *WBXML_DOM_getNode(uint8_t *buffer, int32_t bufferLen,
477                                 uint8_t *node)
478{
479    int32_t i = 0, j = 0;
480
481    if (NULL == buffer || node == NULL) {
482        XML_ERROR(XML_ERROR_BUFFER_NULL);
483        return NULL;
484    }
485
486    while (i < bufferLen) {
487        if (WBXML_GET_TAG(buffer[i]) == WBXML_GET_TAG(node[j])) {
488            j++;
489            if (node[j] == '\0')
490                break;
491
492            /* Check if there is the content(it should have content) */
493            if (!WBXML_HAS_CONTENT(buffer[i])) {
494                /*XML_ERROR(WBXML_ERROR_MISSED_CONTENT); */
495                XML_ERROR(XML_ERROR_NO_SUCH_NODE);
496                return NULL;
497            }
498
499            /* Ignore the attrib filed */
500            if (WBXML_HAS_ATTR(buffer[i])) {
501                while (i < bufferLen && buffer[i] != WBXML_ATTR_END)
502                    i++;
503                if (i >= bufferLen)
504                    break;
505            }
506        }
507        i++;
508
509        /* Ignore the content filed */
510        if (buffer[i] == WBXML_STR_I) {
511            while (i < bufferLen && buffer[i] != WBXML_END)
512                i++;
513            if (i >= bufferLen)
514                break;
515            i++;
516        }
517    }
518
519    if (i >= bufferLen) {
520        XML_ERROR(XML_ERROR_NO_SUCH_NODE);
521        return NULL;
522    }
523
524    XML_ERROR(XML_ERROR_OK);
525
526    return buffer + i + 1;
527}
528
529uint8_t *WBXML_DOM_getNodeValue(uint8_t *buffer, int32_t bufferLen,
530                                      uint8_t *node,
531                                      uint8_t **value, int32_t *valueLen)
532{
533    int32_t i;
534    uint8_t *pEnd;
535
536    *value = NULL;
537    *valueLen = 0;
538
539    pEnd = buffer + bufferLen;
540    buffer = WBXML_DOM_getNode(buffer, bufferLen, node);
541    if (NULL == buffer) {
542        XML_ERROR(XML_ERROR_NO_SUCH_NODE);
543        return NULL;
544    }
545
546    if (*buffer == WBXML_OPAUE) {
547        buffer++;
548        *valueLen = WBXML_GetUintVar(buffer, &i);
549        if (*valueLen < 0) {
550            XML_ERROR(WBXML_ERROR_MBUINT32);
551            return NULL;
552        }
553        buffer += i;
554        *value = buffer;
555        return *value;
556    }
557
558    if (*buffer != WBXML_STR_I) {
559        XML_ERROR(WBXML_ERROR_MISSED_STARTTAG);
560        return NULL;
561    }
562
563    buffer++;
564
565    i = 0;
566    while ((buffer + i) < pEnd && buffer[i] != WBXML_END)
567        i++;
568
569    if (buffer[i] != WBXML_END) {
570        XML_ERROR(WBXML_ERROR_MISSED_ENDTAG);
571        return NULL;
572    }
573
574    *value = buffer;
575    *valueLen = i;
576    XML_ERROR(XML_ERROR_OK);
577
578    return *value;
579}
580#endif /* WBXML_OLD_VERSION */
581
582#define MAX_UINT_VAR_BYTE                                    4
583#define UINTVAR_INVALID                                      -1
584int32_t WBXML_GetUintVar(const uint8_t *const buffer, int32_t *len)
585{
586    int32_t i, byteLen;
587    int32_t sum;
588
589    byteLen = 0;
590    while ((buffer[byteLen] & 0x80) > 0 && byteLen < MAX_UINT_VAR_BYTE)
591        byteLen++;
592
593    if (byteLen > MAX_UINT_VAR_BYTE)
594        return UINTVAR_INVALID;
595
596    *len = byteLen + 1;
597    sum = buffer[byteLen];
598    for (i = byteLen - 1; i >= 0; i--)
599        sum += ((buffer[i] & 0x7F) << 7 * (byteLen - i));
600
601    return sum;
602}
603
604XML_BOOL WBXML_DOM_Init(WBXML * pWbxml, uint8_t *buffer,
605                        int32_t bufferLen)
606{
607    int32_t num, len;
608
609    pWbxml->End = buffer + bufferLen;
610    pWbxml->version = *buffer++;
611    if (UINTVAR_INVALID == (num = WBXML_GetUintVar(buffer, &len)))
612        return XML_FALSE;
613    buffer += len;
614    pWbxml->publicid = num;
615    if (UINTVAR_INVALID == (num = WBXML_GetUintVar(buffer, &len)))
616        return XML_FALSE;
617    buffer += len;
618    pWbxml->charset = num;
619    if (UINTVAR_INVALID == (num = WBXML_GetUintVar(buffer, &len)))
620        return XML_FALSE;
621    buffer += len;
622    pWbxml->strTable = buffer;
623    pWbxml->strTableLen = num;
624    buffer += num;
625    pWbxml->curPtr = pWbxml->Content = buffer;
626    pWbxml->depth = 0;
627
628    return XML_TRUE;
629}
630
631void WBXML_DOM_Rewind(WBXML * pWbxml)
632{
633    pWbxml->curPtr = pWbxml->Content;
634}
635
636XML_BOOL WBXML_DOM_Eof(WBXML * pWbxml)
637{
638    if (pWbxml->curPtr > pWbxml->End)
639        return XML_TRUE;
640
641    return XML_FALSE;
642}
643
644uint8_t WBXML_DOM_GetTag(WBXML * pWbxml)
645{
646    uint8_t tagChar;
647
648    if (pWbxml->curPtr > pWbxml->End)
649        return XML_EOF;
650
651    tagChar = *pWbxml->curPtr;
652    pWbxml->curPtr++;
653
654    if (WBXML_GET_TAG(tagChar) == WBXML_CONTENT_END)
655        pWbxml->depth--;
656    else
657        pWbxml->depth++;
658
659    return tagChar;
660}
661
662uint8_t WBXML_DOM_GetChar(WBXML * pWbxml)
663{
664    return *pWbxml->curPtr++;
665}
666
667void WBXML_DOM_Seek(WBXML * pWbxml, int32_t offset)
668{
669    pWbxml->curPtr += offset;
670}
671
672uint8_t WBXML_DOM_GetUIntVar(WBXML * pWbxml)
673{
674    int32_t num, len;
675
676    num = WBXML_GetUintVar(pWbxml->curPtr, &len);
677    pWbxml->curPtr += len;
678
679    return (uint8_t)num;
680}
681
682#ifdef XML_TREE_STRUCTURE
683
684#ifdef DEBUG_MODE
685static int32_t malloc_times = 0;
686static int32_t free_times = 0;
687void XML_PrintMallocInfo()
688{
689    printf("====XML_PrintMallocInfo====\n");
690    printf(" Total malloc times:%d\n", malloc_times);
691    printf(" Total free   times:%d\n", free_times);
692    printf("===========================\n");
693}
694#endif
695
696void *xml_malloc(int32_t size)
697{
698#ifdef DEBUG_MODE
699    malloc_times++;
700#endif
701    return malloc(size);
702}
703
704void xml_free(void *buffer)
705{
706#ifdef DEBUG_MODE
707    free_times++;
708#endif
709    free(buffer);
710}
711
712XML_TREE *xml_tree_fillnode(uint8_t **buf, int32_t tagLen)
713{
714    XML_TREE *Tree;
715    uint8_t *pAttr, *pName, *pValue;
716    int32_t nameLen, valueLen;
717    uint8_t *buffer = *buf;
718
719    if (NULL == (Tree = (XML_TREE *) xml_malloc(sizeof(XML_TREE))))
720        return NULL;
721    memset(Tree, 0, sizeof(XML_TREE));
722
723    strncpy((char *)Tree->tag, (char *)++buffer, tagLen);
724    buffer += tagLen;
725    pAttr = buffer;
726
727    /* attribute */
728    while (NULL !=
729           (pAttr =
730            XML_DOM_getAttr(pAttr, &pName, &nameLen, &pValue,
731                            &valueLen))) {
732        XML_TREE_ATTR *attr;
733        if (NULL ==
734            (attr = (XML_TREE_ATTR *) xml_malloc(sizeof(XML_TREE_ATTR))))
735            return NULL;
736        memset(attr, 0, sizeof(XML_TREE_ATTR));
737        strncpy((char *)attr->name, (char *)pName, nameLen);
738        strncpy((char *)attr->value, (char *)pValue, valueLen);
739        buffer = pValue + valueLen + 1;
740
741        if (NULL != Tree->attr) // no attribute now
742            Tree->last_attr->next = attr;
743        else
744            Tree->attr = attr;
745        Tree->last_attr = attr;
746    }
747
748    /* value */
749    pAttr = XML_DOM_getValue(buffer, &pValue, &valueLen);
750    if (pAttr != NULL && valueLen > 0) {
751        strncpy((char *)Tree->value, (char *)pValue, valueLen);
752        buffer = pValue + valueLen;
753    }
754
755    *buf = buffer;
756    return Tree;
757}
758
759XML_TREE *XML_makeTree(uint8_t **buf)
760{
761    uint8_t *pBuf;
762    int32_t valueLen, tagType;
763    uint8_t *buffer = *buf;
764    XML_TREE *TreeHead = NULL;
765
766    if (NULL == (buffer = XML_DOM_getTag(buffer, &valueLen, &tagType)))
767        return NULL;
768    if (XML_TAG_END == tagType)
769        return NULL;
770    if (NULL == (TreeHead = xml_tree_fillnode(&buffer, valueLen)))
771        return NULL;
772    if (XML_TAG_SELF == tagType) {
773        *buf = buffer;
774        return TreeHead;
775    }
776
777    do {
778        if (NULL == (pBuf = XML_DOM_getTag(buffer, &valueLen, &tagType)))
779            return NULL;
780
781        switch (tagType) {
782        case XML_TAG_SELF:
783        case XML_TAG_START:
784            if (NULL == TreeHead->child)
785                TreeHead->child = XML_makeTree(&buffer);
786            else if (NULL == TreeHead->child->last_brother) {
787                TreeHead->child->brother = XML_makeTree(&buffer);
788                TreeHead->child->last_brother = TreeHead->child->brother;
789            } else {
790                TreeHead->child->last_brother->brother =
791                    XML_makeTree(&buffer);
792                TreeHead->child->last_brother =
793                    TreeHead->child->last_brother->brother;
794            }
795            break;
796        case XML_TAG_END:
797            *buf = pBuf;
798            return TreeHead;
799        }
800        buffer++;
801    } while (1);
802}
803
804void XML_freeTree(XML_TREE * pTree)
805{
806    XML_TREE *p, *pNext;
807    XML_TREE_ATTR *pa, *lastpa;
808
809    if (NULL == pTree)
810        return;
811
812    p = pTree->brother;
813    while (NULL != p) {
814        pNext = p->brother;
815        p->brother = NULL;
816        XML_freeTree(p);
817        p = pNext;
818    }
819
820    if (NULL != pTree->child)
821        XML_freeTree(pTree->child);
822
823    pa = pTree->attr;
824    while (NULL != pa) {
825        lastpa = pa;
826        pa = pa->next;
827        xml_free(lastpa);
828    }
829    xml_free(pTree);
830}
831
832#endif /* XML_TREE_STRUCTURE */
833
834#endif /* WBXML_DOM_PARSER */
835