mirror of
https://forge.fsky.io/lda/Parsee.git
synced 2026-03-14 02:05:17 +00:00
This should be a nice list of future XEPs to be implemented, so that I can keep track of these without having to keep all of these in my head.
198 lines
4.9 KiB
C
198 lines
4.9 KiB
C
#include <XML.h>
|
|
|
|
#include <Cytoplasm/Log.h>
|
|
#include <Cytoplasm/Str.h>
|
|
|
|
#include <string.h>
|
|
|
|
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, "</%s>", 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;
|
|
}
|
|
}
|