Build XML tree from XML tokeniser, print xml tree

This commit is contained in:
Doyle Thai 2016-08-23 15:19:03 +10:00
parent a1ff789485
commit 2c1d3f9593
2 changed files with 171 additions and 37 deletions

View File

@ -84,37 +84,76 @@ INTERNAL void rendererInit(GameState *state, v2 windowSize)
#endif #endif
} }
typedef struct XmlAttribute
{
b32 init;
char *name;
char *value;
struct XmlAttribute *next;
} XmlAttribute;
typedef struct XmlNode typedef struct XmlNode
{ {
char *name; char *name;
XmlAttribute attribute;
char **fieldName; // NOTE(doyle): Track if node has more children
char **fieldValue; b32 isClosed;
i32 numFields;
// NOTE(doyle): Direct child/parent
struct XmlNode **children; struct XmlNode *parent;
struct XmlNode *child;
// NOTE(doyle): Else all other nodes
struct XmlNode *next;
} XmlNode; } XmlNode;
enum TokenType enum XmlTokenType
{ {
tokentype_unknown, xmltokentype_unknown,
tokentype_openArrow, xmltokentype_openArrow,
tokentype_closeArrow, xmltokentype_closeArrow,
tokentype_string, xmltokentype_name,
tokentype_equals, xmltokentype_value,
tokentype_quotes, xmltokentype_equals,
tokentype_backslash, xmltokentype_quotes,
tokentype_count, xmltokentype_backslash,
xmltokentype_count,
}; };
typedef struct Token typedef struct XmlToken
{ {
// TODO(doyle): Dynamic size string in tokens maybe. // TODO(doyle): Dynamic size string in tokens maybe.
enum TokenType type; enum XmlTokenType type;
char string[128]; char string[128];
i32 len; i32 len;
} Token; } XmlToken;
INTERNAL void debug_recursivePrintXmlTree(XmlNode *root)
{
if (!root)
{
return;
}
else
{
printf("%s ", root->name);
XmlAttribute *attribute = &root->attribute;
printf("| %s = %s", attribute->name, attribute->value);
while (attribute->next)
{
attribute = attribute->next;
printf("| %s = %04s", attribute->name, attribute->value);
}
printf("\n");
debug_recursivePrintXmlTree(root->child);
debug_recursivePrintXmlTree(root->next);
}
}
INTERNAL void assetInit(GameState *state) INTERNAL void assetInit(GameState *state)
{ {
@ -137,7 +176,7 @@ INTERNAL void assetInit(GameState *state)
arena, "data/textures/WorldTraveller/ClaudeSpriteSheet.xml", arena, "data/textures/WorldTraveller/ClaudeSpriteSheet.xml",
&xmlFileRead); &xmlFileRead);
Token *tokens = PLATFORM_MEM_ALLOC(arena, 8192, Token); XmlToken *xmlTokens = PLATFORM_MEM_ALLOC(arena, 8192, XmlToken);
i32 tokenIndex = 0; i32 tokenIndex = 0;
if (result) if (result)
{ {
@ -156,33 +195,33 @@ INTERNAL void assetInit(GameState *state)
case '/': case '/':
{ {
enum TokenType type = tokentype_unknown; enum XmlTokenType type = xmltokentype_unknown;
if (c == '<') if (c == '<')
{ {
type = tokentype_openArrow; type = xmltokentype_openArrow;
} }
else if (c == '>') else if (c == '>')
{ {
type = tokentype_closeArrow; type = xmltokentype_closeArrow;
} }
else if (c == '=') else if (c == '=')
{ {
type = tokentype_equals; type = xmltokentype_equals;
} }
else else
{ {
type = tokentype_backslash; type = xmltokentype_backslash;
} }
tokens[tokenIndex].type = type; xmlTokens[tokenIndex].type = type;
tokens[tokenIndex].len = 1; xmlTokens[tokenIndex].len = 1;
tokenIndex++; tokenIndex++;
break; break;
} }
case '"': case '"':
{ {
tokens[tokenIndex].type = tokentype_string; xmlTokens[tokenIndex].type = xmltokentype_value;
for (i32 j = i + 1; j < xmlFileRead.size; j++) for (i32 j = i + 1; j < xmlFileRead.size; j++)
{ {
char c = (CAST(char *) xmlFileRead.buffer)[j]; char c = (CAST(char *) xmlFileRead.buffer)[j];
@ -193,16 +232,17 @@ INTERNAL void assetInit(GameState *state)
} }
else else
{ {
tokens[tokenIndex].string[tokens[tokenIndex].len++] = c; xmlTokens[tokenIndex]
.string[xmlTokens[tokenIndex].len++] = c;
#ifdef DENGINE_DEBUG #ifdef DENGINE_DEBUG
ASSERT(tokens[tokenIndex].len < ASSERT(xmlTokens[tokenIndex].len <
ARRAY_COUNT(tokens[tokenIndex].string)); ARRAY_COUNT(xmlTokens[tokenIndex].string));
#endif #endif
} }
} }
// NOTE(doyle): +1 to skip the closing quotes // NOTE(doyle): +1 to skip the closing quotes
i += (tokens[tokenIndex].len + 1); i += (xmlTokens[tokenIndex].len + 1);
tokenIndex++; tokenIndex++;
break; break;
} }
@ -211,7 +251,7 @@ INTERNAL void assetInit(GameState *state)
{ {
if ((c >= 'a' && c <= 'z') || c >= 'A' && c <= 'Z') if ((c >= 'a' && c <= 'z') || c >= 'A' && c <= 'Z')
{ {
tokens[tokenIndex].type = tokentype_string; xmlTokens[tokenIndex].type = xmltokentype_name;
for (i32 j = i; j < xmlFileRead.size; j++) for (i32 j = i; j < xmlFileRead.size; j++)
{ {
char c = (CAST(char *) xmlFileRead.buffer)[j]; char c = (CAST(char *) xmlFileRead.buffer)[j];
@ -222,15 +262,15 @@ INTERNAL void assetInit(GameState *state)
} }
else else
{ {
tokens[tokenIndex] xmlTokens[tokenIndex]
.string[tokens[tokenIndex].len++] = c; .string[xmlTokens[tokenIndex].len++] = c;
#ifdef DENGINE_DEBUG #ifdef DENGINE_DEBUG
ASSERT(tokens[tokenIndex].len < ASSERT(xmlTokens[tokenIndex].len <
ARRAY_COUNT(tokens[tokenIndex].string)); ARRAY_COUNT(xmlTokens[tokenIndex].string));
#endif #endif
} }
} }
i += tokens[tokenIndex].len; i += xmlTokens[tokenIndex].len;
tokenIndex++; tokenIndex++;
} }
break; break;
@ -239,6 +279,99 @@ INTERNAL void assetInit(GameState *state)
} }
} }
XmlNode root = {0};
XmlNode *node = &root;
node->parent = node;
for (i32 i = 0; i < tokenIndex; i++)
{
XmlToken *token = &xmlTokens[i];
switch (token->type)
{
case xmltokentype_openArrow:
{
/* Open arrows are followed by the node name */
token = &xmlTokens[++i];
node->name = token->string;
break;
}
case xmltokentype_name:
{
// TODO(doyle): Store latest attribute pointer so we aren't always
// chasing the linked list each iteration. Do the same for children
// node
/* Xml Attributes are a linked list, get first free entry */
XmlAttribute *attribute = &node->attribute;
if (attribute->init)
{
while (attribute->next)
attribute = attribute->next;
attribute->next = PLATFORM_MEM_ALLOC(arena, 1, XmlAttribute);
attribute = attribute->next;
}
/* Just plain text is a node attribute name */
attribute->name = token->string;
/* Followed by the value */
token = &xmlTokens[++i];
attribute->value = token->string;
attribute->init = TRUE;
break;
}
case xmltokentype_closeArrow:
{
XmlToken prevToken = xmlTokens[i - 1];
/* Closed node means we can return to parent */
if (prevToken.type == xmltokentype_backslash)
{
node->isClosed = TRUE;
node = node->parent;
}
if (!node->isClosed)
{
/* Unclosed node means next fields will be children of node */
/* If the first child is free allocate, otherwise we have to
* iterate through the child's next node(s) */
if (!node->child)
{
node->child = PLATFORM_MEM_ALLOC(arena, 1, XmlNode);
node->child->parent = node;
node = node->child;
}
else
{
XmlNode *nodeToCheck = node->child;
while (nodeToCheck->next)
nodeToCheck = nodeToCheck->next;
nodeToCheck->next = PLATFORM_MEM_ALLOC(arena, 1, XmlNode);
nodeToCheck->next->parent = node;
node = nodeToCheck->next;
}
}
break;
}
default:
{
break;
}
}
}
debug_recursivePrintXmlTree(&root);
/* Load textures */ /* Load textures */
asset_loadTextureImage(assetManager, asset_loadTextureImage(assetManager,
"data/textures/WorldTraveller/TerraSprite1024.png", "data/textures/WorldTraveller/TerraSprite1024.png",

View File

@ -35,5 +35,6 @@ char *common_memset(char *const ptr, const i32 value, const i32 numBytes);
// Max buffer size should be 11 for 32 bit integers // Max buffer size should be 11 for 32 bit integers
void common_itoa(i32 value, char *buf, i32 bufSize); void common_itoa(i32 value, char *buf, i32 bufSize);
i32 common_atoi(char *buf, i32 bufSize);
#endif #endif