#include #include #include #include XMLElement * XMLCDecode(Stream *stream, bool autofree, bool html) { #define push(x) ArrayAdd(stack, x) #define pop(x) ArrayDelete(stack, ArraySize(stack) - 1) #define peek(x) ArrayGet(stack, ArraySize(stack) - 1) XMLexer *lexer; XMLEvent *event; XMLElement *ret = NULL; XMLElement *top; char *key, *val; size_t i; Array *stack; if (!stream) { return NULL; } lexer = XMLCreateLexer(stream, autofree); stack = ArrayCreate(); while ((event = XMLCrank(lexer)) && (!ret || ArraySize(stack))) { bool flag = false; switch (event->type) { case XML_LEXER_STARTELEM: /* Create a new element that will populated. */ top = XMLCreateTag(event->element); XMLAddChild(peek(), top); while (HashMapIterate(event->attrs, &key, (void **) &val)) { XMLAddAttr(top, key, val); } if (!ret) { /* If we didn't have any element before, this one is * going to be our top of the stack */ ret = top; } /* HACK!!! */ if (!StrEquals(event->element, "br") || !html) { push(top); } break; case XML_LEXER_ELEM: /* Create a new element that will populated. */ top = XMLCreateTag(event->element); XMLAddChild(peek(), top); while (HashMapIterate(event->attrs, &key, (void **) &val)) { XMLAddAttr(top, key, val); } if (!ret) { /* If we didn't have any element before, this one is * going to be our top of the stack */ ret = top; } push(top); /* Fallthrough */ case XML_LEXER_ENDELEM: /* Pop out an element out of the DOM. */ pop(); if (!ArraySize(stack)) { XMLFreeEvent(event); event = NULL; flag = true; break; } break; case XML_LEXER_DATA: if (!peek()) { break; } top = XMLCreateText(event->data); XMLAddChild(peek(), top); break; default: break; } if (flag) { break; } XMLFreeEvent(event); event = NULL; } XMLFreeEvent(event); for (i = 0; i < ArraySize(stack); i++) { XMLElement *e = ArrayGet(stack, i); if (e == ret) { continue; } //XMLFreeElement(e); } ArrayFree(stack); XMLFreeLexer(lexer); return ret; } void XMLEncodeString(Stream *stream, char *data) { size_t i; for (i = 0; i < strlen(data); i++) { char c = data[i]; if (c == '<') { StreamPrintf(stream, "<"); continue; } else if (c == '>') { StreamPrintf(stream, ">"); continue; } else if (c == '&') { StreamPrintf(stream, "&"); continue; } else if (c == '\'') { StreamPrintf(stream, "'"); continue; } else if (c == '"') { StreamPrintf(stream, """); continue; } StreamPrintf(stream, "%c", c); } } void XMLEncodeTag(Stream *stream, XMLElement *element) { char *key, *val; StreamPrintf(stream, "<%s", element->name); while (HashMapIterate(element->attrs, &key, (void **) &val)) { StreamPrintf(stream, " %s='", key); XMLEncodeString(stream, val); StreamPrintf(stream, "'"); } if (ArraySize(element->children)) { size_t i; XMLElement *child; StreamPrintf(stream, ">", key, val); for (i = 0; i < ArraySize(element->children); i++) { child = ArrayGet(element->children, i); XMLEncode(stream, child); } StreamPrintf(stream, "", element->name); return; } StreamPrintf(stream, "/>"); } void XMLEncode(Stream *stream, XMLElement *element) { if (!stream || !element) { return; } switch (element->type) { case XML_ELEMENT_TAG: XMLEncodeTag(stream, element); return; case XML_ELEMENT_DATA: XMLEncodeString(stream, element->data); return; default: /* TODO */ break; } }