2011-06-21 19:31:46 +03:00
|
|
|
/*
|
|
|
|
Copyright (C) 2011 Markus Kauppila <markus.kauppila@gmail.com>
|
|
|
|
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
|
|
warranty. In no event will the authors be held liable for any damages
|
|
|
|
arising from the use of this software.
|
|
|
|
|
|
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
|
|
including commercial applications, and to alter it and redistribute it
|
|
|
|
freely, subject to the following restrictions:
|
|
|
|
|
|
|
|
1. The origin of this software must not be misrepresented; you must not
|
|
|
|
claim that you wrote the original software. If you use this software
|
|
|
|
in a product, an acknowledgment in the product documentation would be
|
|
|
|
appreciated but is not required.
|
|
|
|
2. Altered source versions must be plainly marked as such, and must not be
|
|
|
|
misrepresented as being the original software.
|
|
|
|
3. This notice may not be removed or altered from any source distribution.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
#include <SDL/SDL.h>
|
|
|
|
|
|
|
|
#include "xml.h"
|
2011-06-28 17:03:38 +03:00
|
|
|
#include "logger_helpers.h"
|
|
|
|
|
|
|
|
/*! Size for xml element buffer */
|
|
|
|
#define bufferSize 1024
|
|
|
|
/*! Buffer for storing the xml element under construction */
|
|
|
|
static char buffer[bufferSize];
|
|
|
|
|
|
|
|
/*! Pointer to XML root element's tag */
|
|
|
|
static const char *root;
|
2011-06-21 19:31:46 +03:00
|
|
|
|
|
|
|
/*!
|
|
|
|
* Defines structure used for "counting" open XML-tags
|
|
|
|
*/
|
|
|
|
typedef struct TagList {
|
|
|
|
const char *tag;
|
|
|
|
struct TagList *next;
|
|
|
|
} TagList;
|
|
|
|
|
|
|
|
static TagList *openTags = NULL;
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Prepend the open tags list
|
|
|
|
*
|
|
|
|
* \return On error returns non-zero value, otherwise zero will returned
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
AddOpenTag(const char *tag)
|
|
|
|
{
|
|
|
|
TagList *openTag = SDL_malloc(sizeof(TagList));
|
|
|
|
if(openTag == NULL) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
memset(openTag, 0, sizeof(TagList));
|
|
|
|
|
2011-06-24 14:35:14 +03:00
|
|
|
const int tagSize = SDL_strlen(tag) + 1;
|
|
|
|
openTag->tag = SDL_malloc(tagSize);
|
2011-06-28 17:03:38 +03:00
|
|
|
if(openTag->tag == NULL) {
|
|
|
|
SDL_free(openTag);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-06-26 23:04:37 +03:00
|
|
|
strncpy((char *)openTag->tag, (char *)tag, tagSize);
|
2011-06-24 14:35:14 +03:00
|
|
|
|
2011-06-21 19:31:46 +03:00
|
|
|
openTag->next = openTags;
|
|
|
|
|
|
|
|
openTags = openTag;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Removes the first tag from the open tag list
|
|
|
|
*
|
|
|
|
* \return On error returns non-zero value, otherwise zero will returned
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
RemoveOpenTag(const char *tag)
|
|
|
|
{
|
2011-06-28 17:03:38 +03:00
|
|
|
if(openTags == NULL || ValidateString(tag) == 0) {
|
2011-06-21 19:31:46 +03:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int retVal = 0;
|
|
|
|
|
2011-06-24 14:35:14 +03:00
|
|
|
const int size = SDL_strlen(tag);
|
|
|
|
char *tempTag = SDL_malloc(size);
|
|
|
|
strncpy(tempTag, tag, size);
|
|
|
|
|
2011-06-21 19:31:46 +03:00
|
|
|
// Tag should always be the same as previously opened tag
|
|
|
|
// It prevents opening and ending tag mismatch
|
2011-06-28 17:03:38 +03:00
|
|
|
if(SDL_strncmp(tempTag, tag, size) == 0) {
|
2011-06-21 19:31:46 +03:00
|
|
|
TagList *openTag = openTags;
|
2011-06-26 23:04:37 +03:00
|
|
|
SDL_free((char *)openTag->tag);
|
2011-06-21 19:31:46 +03:00
|
|
|
|
2011-06-24 14:35:14 +03:00
|
|
|
openTags = openTags->next;
|
|
|
|
SDL_free(openTag);
|
2011-06-21 19:31:46 +03:00
|
|
|
} else {
|
2011-06-24 14:35:14 +03:00
|
|
|
//printf("Debug | xml.c:RemoveOpenTag(): open/end tag mismatch");
|
2011-06-21 19:31:46 +03:00
|
|
|
retVal = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return retVal;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Debug function. Prints the contents of the open tags list.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
PrintOpenTags()
|
|
|
|
{
|
|
|
|
printf("\nOpen tags:\n");
|
|
|
|
|
|
|
|
TagList *openTag = NULL;
|
|
|
|
for(openTag = openTags; openTag; openTag = openTag->next) {
|
|
|
|
printf("\ttag: %s\n", openTag->tag);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-22 21:56:23 +03:00
|
|
|
|
|
|
|
/*!
|
|
|
|
* Converts the special characters ', ", <, >, and & to
|
|
|
|
* corresponding entities: ' " < > and &
|
|
|
|
*
|
|
|
|
* \param string String to be escaped
|
2011-06-28 17:03:38 +03:00
|
|
|
* \return Newly allocated escaped string
|
2011-06-22 21:56:23 +03:00
|
|
|
*/
|
2011-06-28 17:03:38 +03:00
|
|
|
const char *
|
|
|
|
EscapeString(const char *string)
|
|
|
|
{
|
|
|
|
//const int bufferSize = 4096;
|
2011-06-22 21:56:23 +03:00
|
|
|
char buffer[bufferSize];
|
|
|
|
memset(buffer, 0, bufferSize);
|
|
|
|
|
|
|
|
// prevents the code doing a 'bus error'
|
2011-06-23 22:00:03 +03:00
|
|
|
char *stringBuffer = SDL_malloc(bufferSize);
|
2011-06-28 17:03:38 +03:00
|
|
|
if(stringBuffer == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2011-06-22 21:56:23 +03:00
|
|
|
strncpy(stringBuffer, string, bufferSize);
|
|
|
|
|
|
|
|
// Ampersand (&) must be first, otherwise it'll mess up the other entities
|
|
|
|
char *characters[] = {"&", "'", "\"", "<", ">"};
|
|
|
|
char *entities[] = {"&", "'", """, "<", ">"};
|
|
|
|
int maxCount = 5;
|
|
|
|
|
|
|
|
int counter = 0;
|
|
|
|
for(; counter < maxCount; ++counter) {
|
|
|
|
char *character = characters[counter];
|
|
|
|
char *entity = entities[counter];
|
|
|
|
|
|
|
|
if(strstr(stringBuffer, character) == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
char *token = strtok(stringBuffer, character);
|
|
|
|
while(token) {
|
|
|
|
char *nextToken = strtok(NULL, character);
|
|
|
|
|
2011-06-27 11:53:14 +03:00
|
|
|
int bytesLeft = bufferSize - SDL_strlen(buffer);
|
|
|
|
if(bytesLeft) {
|
|
|
|
strncat(buffer, token, bytesLeft);
|
|
|
|
} else {
|
|
|
|
// \! todo there's probably better way to report an error?
|
|
|
|
fprintf(stderr, "xml.c | EscapingString: Buffer is full");
|
|
|
|
}
|
|
|
|
|
2011-06-22 21:56:23 +03:00
|
|
|
if(nextToken)
|
|
|
|
strcat(buffer, entity);
|
|
|
|
|
|
|
|
token = nextToken;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(stringBuffer, buffer, bufferSize);
|
|
|
|
memset(buffer, 0, bufferSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
return stringBuffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-06-21 19:31:46 +03:00
|
|
|
/*
|
|
|
|
===================
|
|
|
|
|
2011-06-22 17:41:37 +03:00
|
|
|
Functions to handle creation of XML elements
|
2011-06-21 19:31:46 +03:00
|
|
|
|
|
|
|
===================
|
|
|
|
*/
|
|
|
|
|
2011-06-23 22:00:03 +03:00
|
|
|
char *
|
2011-06-30 17:11:39 +03:00
|
|
|
XMLOpenDocument(const char *rootTag, const char *xslStyle)
|
2011-06-21 19:31:46 +03:00
|
|
|
{
|
2011-06-27 11:53:14 +03:00
|
|
|
const char *doctype = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n";
|
2011-06-21 19:31:46 +03:00
|
|
|
|
2011-06-28 23:15:43 +03:00
|
|
|
//! \todo make this optional (and let the user supply the filename?)
|
2011-06-30 17:11:39 +03:00
|
|
|
const char *styleStart = "<?xml-stylesheet type=\"text/xsl\" href=\"";
|
|
|
|
const char *styleEnd = "\"?>\n";
|
|
|
|
|
|
|
|
const int sizeStyleStart = SDL_strlen(styleStart);
|
|
|
|
const int sizeStyleEnd = SDL_strlen(styleEnd);
|
|
|
|
const int sizeStyleSheetName = SDL_strlen(xslStyle);
|
|
|
|
|
|
|
|
const int tempSize = sizeStyleStart + sizeStyleEnd + sizeStyleSheetName + 1;
|
|
|
|
char *style = SDL_malloc(tempSize);
|
|
|
|
memset(style, 0, tempSize);
|
2011-07-01 11:12:35 +03:00
|
|
|
SDL_snprintf(style, tempSize, "%s%s%s", styleStart, xslStyle, styleEnd);
|
2011-06-28 23:15:43 +03:00
|
|
|
|
2011-06-22 18:13:06 +03:00
|
|
|
memset(buffer, 0, bufferSize);
|
2011-07-01 11:12:35 +03:00
|
|
|
SDL_snprintf(buffer, bufferSize, "<%s>", rootTag);
|
2011-06-21 19:31:46 +03:00
|
|
|
|
|
|
|
AddOpenTag(rootTag);
|
2011-06-21 22:04:44 +03:00
|
|
|
|
|
|
|
root = rootTag; // it's fine, as long as rootTag points to static memory?
|
2011-06-23 22:00:03 +03:00
|
|
|
|
|
|
|
const int doctypeSize = SDL_strlen(doctype);
|
2011-06-28 23:15:43 +03:00
|
|
|
const int styleSize = SDL_strlen(style);
|
2011-06-23 22:00:03 +03:00
|
|
|
const int tagSize = SDL_strlen(buffer);
|
|
|
|
|
2011-06-28 23:15:43 +03:00
|
|
|
const int size = doctypeSize + styleSize + tagSize + 1; // extra byte for '\0'
|
|
|
|
char *retBuf = SDL_malloc(size);
|
|
|
|
|
|
|
|
// fill in the previous allocated retBuf
|
|
|
|
strcat(retBuf, doctype);
|
|
|
|
strcat(retBuf, style);
|
|
|
|
strcat(retBuf, buffer);
|
|
|
|
|
2011-06-30 17:11:39 +03:00
|
|
|
SDL_free(style);
|
|
|
|
|
2011-06-28 23:15:43 +03:00
|
|
|
return retBuf;
|
2011-06-21 19:31:46 +03:00
|
|
|
}
|
|
|
|
|
2011-06-23 22:00:03 +03:00
|
|
|
char *
|
2011-06-21 19:31:46 +03:00
|
|
|
XMLCloseDocument() {
|
2011-06-23 22:00:03 +03:00
|
|
|
return XMLCloseElement(root);
|
2011-06-21 19:31:46 +03:00
|
|
|
}
|
|
|
|
|
2011-06-23 22:00:03 +03:00
|
|
|
char *
|
2011-06-21 19:31:46 +03:00
|
|
|
XMLOpenElement(const char *tag)
|
|
|
|
{
|
2011-06-22 18:13:06 +03:00
|
|
|
memset(buffer, 0, bufferSize);
|
2011-07-01 11:12:35 +03:00
|
|
|
SDL_snprintf(buffer, bufferSize, "<%s>", tag);
|
2011-06-21 19:31:46 +03:00
|
|
|
|
|
|
|
AddOpenTag(tag);
|
2011-06-23 22:00:03 +03:00
|
|
|
|
|
|
|
const int size = SDL_strlen(buffer);
|
|
|
|
char *ret = SDL_malloc(size + 1);
|
|
|
|
strncpy(ret, buffer, size);
|
|
|
|
ret[size] = '\0';
|
|
|
|
|
|
|
|
return ret;
|
2011-06-21 19:31:46 +03:00
|
|
|
}
|
|
|
|
|
2011-06-23 22:00:03 +03:00
|
|
|
char *
|
2011-06-21 19:31:46 +03:00
|
|
|
XMLAddContent(const char *content)
|
|
|
|
{
|
2011-06-28 17:03:38 +03:00
|
|
|
if(ValidateString(content) == 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-06-22 21:56:23 +03:00
|
|
|
const char *escapedContent = EscapeString(content);
|
|
|
|
|
2011-06-28 17:03:38 +03:00
|
|
|
if(SDL_strlen(escapedContent) >= bufferSize) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-06-22 18:13:06 +03:00
|
|
|
memset(buffer, 0, bufferSize);
|
2011-07-01 11:12:35 +03:00
|
|
|
SDL_snprintf(buffer, bufferSize, "%s", escapedContent);
|
2011-06-23 22:00:03 +03:00
|
|
|
SDL_free((char *)escapedContent);
|
|
|
|
|
|
|
|
const int size = SDL_strlen(buffer);
|
|
|
|
char *ret = SDL_malloc(size + 1);
|
|
|
|
strncpy(ret, buffer, size);
|
|
|
|
ret[size] = '\0';
|
|
|
|
|
|
|
|
return ret;
|
2011-06-22 18:13:06 +03:00
|
|
|
}
|
2011-06-21 19:31:46 +03:00
|
|
|
|
2011-06-23 22:00:03 +03:00
|
|
|
char *
|
2011-06-21 19:31:46 +03:00
|
|
|
XMLCloseElement(const char *tag)
|
|
|
|
{
|
2011-06-28 17:03:38 +03:00
|
|
|
if(ValidateString(tag) == 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int retBufferSize = 150;
|
|
|
|
char *ret = SDL_malloc(retBufferSize);
|
|
|
|
memset(ret, 0, retBufferSize);
|
2011-06-23 22:00:03 +03:00
|
|
|
|
2011-06-28 17:03:38 +03:00
|
|
|
// \todo check that element we're trying to close is actually open,
|
|
|
|
// otherwise it'll cause nesting problems
|
2011-06-27 16:41:45 +03:00
|
|
|
|
2011-06-21 19:31:46 +03:00
|
|
|
// Close the open tags with proper nesting. Closes tags until it finds
|
|
|
|
// the given tag which is the last tag that will be closed
|
|
|
|
TagList *openTag = openTags;
|
|
|
|
while(openTag) {
|
|
|
|
TagList *temp = openTag->next;
|
|
|
|
|
2011-06-24 14:35:14 +03:00
|
|
|
char *lowOpenTag = ToLowerCase(openTag->tag);
|
|
|
|
char *lowTag = ToLowerCase(tag);
|
2011-06-23 22:00:03 +03:00
|
|
|
|
2011-06-24 14:35:14 +03:00
|
|
|
const int openTagSize = SDL_strlen(lowOpenTag);
|
|
|
|
const int tagSize = SDL_strlen(lowTag);
|
2011-06-21 19:31:46 +03:00
|
|
|
const int compSize = (openTagSize > tagSize) ? openTagSize : tagSize;
|
|
|
|
|
2011-06-24 14:35:14 +03:00
|
|
|
memset(buffer, 0, bufferSize);
|
|
|
|
|
2011-06-21 19:31:46 +03:00
|
|
|
int breakOut = 0;
|
2011-06-24 14:35:14 +03:00
|
|
|
if(SDL_strncmp(lowOpenTag, lowTag, compSize) == 0) {
|
2011-06-21 19:31:46 +03:00
|
|
|
breakOut = 1;
|
2011-07-01 11:12:35 +03:00
|
|
|
SDL_snprintf(buffer, bufferSize, "</%s>", tag);
|
2011-06-24 14:35:14 +03:00
|
|
|
} else {
|
2011-07-01 11:12:35 +03:00
|
|
|
SDL_snprintf(buffer, bufferSize, "</%s>", openTag->tag);
|
2011-06-21 19:31:46 +03:00
|
|
|
}
|
|
|
|
|
2011-06-24 14:35:14 +03:00
|
|
|
SDL_free(lowOpenTag);
|
|
|
|
SDL_free(lowTag);
|
|
|
|
|
2011-06-27 11:53:14 +03:00
|
|
|
int bytesLeft = bufferSize - SDL_strlen(ret);
|
|
|
|
if(bytesLeft) {
|
|
|
|
strncat(ret, buffer, bytesLeft);
|
|
|
|
} else {
|
|
|
|
// \! todo there's probably better way to report an error?
|
|
|
|
fprintf(stderr, "xml.c | XMLCloseElement: Buffer is full");
|
|
|
|
}
|
2011-06-24 14:35:14 +03:00
|
|
|
|
2011-06-21 19:31:46 +03:00
|
|
|
RemoveOpenTag(openTag->tag);
|
|
|
|
|
|
|
|
openTag = temp;
|
|
|
|
|
|
|
|
if(breakOut) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2011-06-23 22:00:03 +03:00
|
|
|
|
|
|
|
return ret;
|
2011-06-21 19:31:46 +03:00
|
|
|
}
|
2011-06-21 22:04:44 +03:00
|
|
|
|