From: Mattia Basaglia Date: Wed, 19 Nov 2014 18:01:51 +0000 (+0100) Subject: Add support for loading XML from QuakeC X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=0c2d7f0f746d69e448a2a179a096eaa68f57b100;p=xonotic%2Fdarkplaces.git Add support for loading XML from QuakeC (Requires libxml) --- diff --git a/makefile b/makefile index bbd0a76d..83891936 100644 --- a/makefile +++ b/makefile @@ -334,6 +334,9 @@ ifeq ($(DP_LINK_CRYPTO_RIJNDAEL), dlopen) CFLAGS_CRYPTO_RIJNDAEL= endif +LIB_XML=$(shell xml2-config --libs) +CFLAGS_LIBXML=$(shell xml2-config --cflags) + ##### Sound configuration ##### ifndef DP_SOUND_API diff --git a/makefile.inc b/makefile.inc index c7e98d22..5140e9a4 100644 --- a/makefile.inc +++ b/makefile.inc @@ -158,6 +158,7 @@ OBJ_COMMON= \ view.o \ wad.o \ world.o \ + xml.o \ zone.o OBJ_MENU= \ @@ -172,7 +173,7 @@ OBJ_SDL= builddate.c sys_sdl.o vid_sdl.o thread_sdl.o $(OBJ_MENU) $(OBJ_SND_COMM # Compilation -CFLAGS_COMMON=$(CFLAGS_MAKEDEP) $(CFLAGS_PRELOAD) $(CFLAGS_FS) $(CFLAGS_WARNINGS) $(CFLAGS_LIBZ) $(CFLAGS_LIBJPEG) $(CFLAGS_D3D) -D_FILE_OFFSET_BITS=64 -D__KERNEL_STRICT_NAMES -I../../../ +CFLAGS_COMMON=$(CFLAGS_MAKEDEP) $(CFLAGS_PRELOAD) $(CFLAGS_FS) $(CFLAGS_WARNINGS) $(CFLAGS_LIBZ) $(CFLAGS_LIBJPEG) $(CFLAGS_D3D) -D_FILE_OFFSET_BITS=64 -D__KERNEL_STRICT_NAMES -I../../../ $(CFLAGS_LIBXML) CFLAGS_CLIENT=-DCONFIG_MENU -DCONFIG_CD $(CFLAGS_VIDEO_CAPTURE) CFLAGS_SERVER= CFLAGS_DEBUG=-ggdb @@ -205,7 +206,7 @@ LDFLAGS_RELEASE=$(OPTIM_RELEASE) -DSVNREVISION=`{ test -d .svn && svnversion; } OBJ_GLX= builddate.c sys_linux.o vid_glx.o thread_pthread.o keysym2ucs.o $(OBJ_MENU) $(OBJ_SOUND) $(OBJ_CD) $(OBJ_VIDEO_CAPTURE) $(OBJ_COMMON) -LDFLAGS_UNIXCOMMON=-lm $(LIB_ODE) $(LIB_Z) $(LIB_JPEG) $(LIB_CRYPTO) $(LIB_CRYPTO_RIJNDAEL) +LDFLAGS_UNIXCOMMON=-lm $(LIB_ODE) $(LIB_Z) $(LIB_JPEG) $(LIB_CRYPTO) $(LIB_CRYPTO_RIJNDAEL) $(LIB_XML) LDFLAGS_UNIXCL=-L$(UNIX_X11LIBPATH) -lX11 -lXpm -lXext -lXxf86vm -pthread $(LIB_SOUND) LDFLAGS_UNIXCL_PRELOAD=-lz -ljpeg -lpng -logg -ltheora -lvorbis -lvorbisenc -lvorbisfile -lcurl LDFLAGS_UNIXSV_PRELOAD=-lz -ljpeg -lpng -lcurl diff --git a/progsvm.h b/progsvm.h index 02cb4bea..36a84ff9 100644 --- a/progsvm.h +++ b/progsvm.h @@ -630,6 +630,7 @@ typedef struct prvm_prog_s fssearch_t *opensearches[PRVM_MAX_OPENSEARCHES]; const char * opensearches_origin[PRVM_MAX_OPENSEARCHES]; skeleton_t *skeletons[MAX_EDICTS]; + void* open_xml_files[PRVM_MAX_OPENFILES]; // buffer for storing all tempstrings created during one invocation of ExecuteProgram sizebuf_t tempstringsbuf; diff --git a/prvm_cmds.c b/prvm_cmds.c index 187930b2..14dcf049 100644 --- a/prvm_cmds.c +++ b/prvm_cmds.c @@ -1760,7 +1760,10 @@ void VM_Files_Init(prvm_prog_t *prog) { int i; for (i = 0;i < PRVM_MAX_OPENFILES;i++) + { prog->openfiles[i] = NULL; + prog->open_xml_files[i] = NULL; + } } void VM_Files_CloseAll(prvm_prog_t *prog) @@ -1771,6 +1774,7 @@ void VM_Files_CloseAll(prvm_prog_t *prog) if (prog->openfiles[i]) FS_Close(prog->openfiles[i]); prog->openfiles[i] = NULL; + XML_Close(prog,i); } } diff --git a/svvm_cmds.c b/svvm_cmds.c index ff55c4fd..16d91e9c 100644 --- a/svvm_cmds.c +++ b/svvm_cmds.c @@ -2,6 +2,7 @@ #include "prvm_cmds.h" #include "jpeg.h" +#include "xml.h" //============================================================================ // Server @@ -3308,17 +3309,17 @@ NULL, // #124 NULL, // #125 NULL, // #126 NULL, // #127 -NULL, // #128 -NULL, // #129 -NULL, // #130 -NULL, // #131 -NULL, // #132 -NULL, // #133 -NULL, // #134 -NULL, // #135 -NULL, // #136 -NULL, // #137 -NULL, // #138 +VM_xml_open, // #128 +VM_xml_close, // #129 +VM_xml_tree_name, // #130 +VM_xml_tree_text, // #131 +VM_xml_tree_leaf, // #132 +VM_xml_tree_child, // #133 +VM_xml_tree_parent, // #134 +VM_xml_tree_has_sibling, // #135 +VM_xml_tree_next, // #136 +VM_xml_tree_type, // #137 +VM_xml_tree_root, // #138 NULL, // #139 NULL, // #140 NULL, // #141 diff --git a/xml.c b/xml.c new file mode 100644 index 00000000..2efd6925 --- /dev/null +++ b/xml.c @@ -0,0 +1,256 @@ +#include "xml.h" +#include +#include + +typedef struct +{ + xmlDocPtr doc; + xmlNodePtr node; + xmlAttrPtr attribute; +} qxml_t; + +typedef qxml_t* qxml_p; + +static qxml_p VM_Xml_Data(prvm_prog_t *prog, int index) +{ + if (index < 0 || index >= PRVM_MAX_OPENFILES) + { + Con_Printf("VM_Xml_Data: invalid file handle %i used in %s\n", index, prog->name); + return NULL; + } + if (prog->open_xml_files[index] == NULL) + { + Con_Printf("VM_Xml_Data: no such file handle %i (or file has been closed) in %s\n", index, prog->name); + return NULL; + } + return (qxml_p)prog->open_xml_files[index]; +} + +void XML_Close(prvm_prog_t *prog, int index) +{ + if ( prog->open_xml_files[index] != NULL ) + { + qxml_p xml = (qxml_p)prog->open_xml_files[index]; + xmlFreeDoc(xml->doc); + free(xml); + prog->open_xml_files[index] = NULL; + } +} + +void VM_xml_open(prvm_prog_t *prog) +{ + const char* filename; + + char* data; + size_t datasize; + qfile_t* filepointer; + char vabuf[1024]; + + xmlDocPtr doc; + int docid; + qxml_p xml; + + VM_SAFEPARMCOUNT(1,VM_xmlopen); + filename = PRVM_G_STRING(OFS_PARM0); + + + for (docid = 0; docid < PRVM_MAX_OPENFILES; docid++) + if (prog->open_xml_files[docid] == NULL) + break; + if (docid >= PRVM_MAX_OPENFILES) + { + PRVM_G_FLOAT(OFS_RETURN) = 0; + VM_Warning(prog, "VM_xmlopen: %s ran out of file handles (%i)\n", prog->name, PRVM_MAX_OPENFILES); + return; + } + + filepointer = FS_OpenVirtualFile(va(vabuf, sizeof(vabuf), "data/%s", filename), false); + if (filepointer == NULL) + filepointer = FS_OpenVirtualFile(va(vabuf, sizeof(vabuf), "%s", filename), false); + + if ( filepointer == NULL ) + { + PRVM_G_FLOAT(OFS_RETURN) = 0; + VM_Warning(prog, "VM_xmlopen: Failed to open: %s\n", filename); + return; + } + + datasize = FS_FileSize(filepointer); + data = malloc(datasize); + FS_Read(filepointer,data,datasize); + FS_Close(filepointer); + + doc = xmlParseMemory(data,datasize); + free(data); + + if (doc == NULL) + { + PRVM_G_FLOAT(OFS_RETURN) = 0; + VM_Warning(prog, "VM_xmlopen: Failed to load XML: %s\n", filename); + return; + } + + xml = malloc(sizeof(qxml_t)); + xml->doc = doc; + xml->node = xmlDocGetRootElement(doc); + xml->attribute = NULL; + prog->open_xml_files[docid] = xml; + + PRVM_G_FLOAT(OFS_RETURN) = docid+1; // ensure non-zero file id in QuakeC +} + +void VM_xml_close(prvm_prog_t *prog) +{ + int fileindex; + VM_SAFEPARMCOUNT(1,VM_xmlclose); + fileindex = PRVM_G_FLOAT(OFS_PARM0); + XML_Close(prog,fileindex-1); +} + +// TODO find out if errorreturn is really needed to return 0... +#define VM_XML_CHECK_RETURN(funcname, errorreturn) \ + VM_SAFEPARMCOUNT(1,#funcname); \ + xml = VM_Xml_Data(prog,PRVM_G_FLOAT(OFS_PARM0)-1); \ + if ( !xml ) {\ + errorreturn; \ + return; \ + }\ + if ( !xml->node ) { \ + VM_Warning(prog, #funcname": null node in %s\n",prog->name); \ + errorreturn; \ + return; \ + } \ + Con_Printf(#funcname":\n\tnode: %s\n\ttype: %d\n\tattr: %s\n\tnext: %s\n\tprev: %s\n\tprnt: %s\n\tchld: %s\n",\ + xml->node->name, \ + xml->node->type, \ + xml->attribute ? (char*)xml->attribute->name : "NULL", \ + xml->node->next ? (char*)xml->node->next->name : "NULL", \ + xml->node->prev ? (char*)xml->node->prev->name : "NULL", \ + xml->node->parent ? (char*)xml->node->parent->name : "NULL", \ + xml->node->children ? (char*)xml->node->children->name : "NULL" \ + ); +#define VM_XML_CHECK(funcname) VM_XML_CHECK_RETURN(funcname,) + +void VM_xml_tree_name(prvm_prog_t *prog) +{ + qxml_p xml; + const xmlChar* xs; + char s[VM_STRINGTEMP_LENGTH] = { 0 }; + VM_XML_CHECK(VM_xml_tree_name); + if ( xml->attribute ) + xs = xml->attribute->name; + else + xs = xml->node->name; + memcpy(s,xs,xmlStrlen(xs)); + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, s); +} + +void VM_xml_tree_text(prvm_prog_t *prog) +{ + qxml_p xml; + xmlChar* xs; + char s[VM_STRINGTEMP_LENGTH] = { 0 }; + VM_XML_CHECK(VM_xml_tree_text); + + if ( xml->attribute ) + { + xs = xmlGetProp(xml->node,xml->attribute->name); + memcpy(s,xs,xmlStrlen(xs)); + xmlFree(xs); + } + else if ( xml->node->type == XML_ELEMENT_NODE ) + { + xs = xmlNodeListGetString(xml->doc,xml->node->children,1); + memcpy(s,xs,xmlStrlen(xs)); + xmlFree(xs); + } + else + memcpy(s,xml->node->content,xmlStrlen(xml->node->content)); + PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, s); +} + +void VM_xml_tree_leaf(prvm_prog_t *prog) +{ + qxml_p xml; + VM_XML_CHECK_RETURN(VM_xml_tree_leaf, PRVM_G_FLOAT(OFS_RETURN) = 0); + if ( xml->attribute ) + PRVM_G_FLOAT(OFS_RETURN) = 1; + else + PRVM_G_FLOAT(OFS_RETURN) = !xml->node->children; +} + +void VM_xml_tree_child(prvm_prog_t *prog) +{ + qxml_p xml; + VM_XML_CHECK(VM_xml_tree_child); + if ( xml->attribute ) + VM_Warning(prog, "VM_xml_tree_child: trying to get the child of attribute \"%s\"!\n", + xml->attribute->name); + else if ( xml->node->children ) + xml->node = xml->node->children; + else + VM_Warning(prog, "VM_xml_tree_child: trying to get the child of leaf element \"%s\"!\n", + xml->node->name); +} + +void VM_xml_tree_parent(prvm_prog_t *prog) +{ + qxml_p xml; + VM_XML_CHECK(VM_xml_tree_parent); + if ( xml->attribute ) + xml->attribute = NULL; + else if ( xml->node->parent ) + xml->node = xml->node->parent; + else + VM_Warning(prog, "VM_xml_tree_parent: trying to get the parent of root element \"%s\"!\n", + xml->node->name); +} + +void VM_xml_tree_has_sibling(prvm_prog_t *prog) +{ + qxml_p xml; + VM_XML_CHECK_RETURN(VM_xml_tree_has_sibling, PRVM_G_FLOAT(OFS_RETURN) = 0); + if ( xml->attribute ) + PRVM_G_FLOAT(OFS_RETURN) = !!xml->attribute->next; + else + PRVM_G_FLOAT(OFS_RETURN) = !!xml->node->next; +} + +void VM_xml_tree_next(prvm_prog_t *prog) +{ + qxml_p xml; + VM_XML_CHECK(VM_xml_tree_next); + if ( xml->attribute ) + { + if ( xml->attribute->next ) + xml->attribute = xml->attribute->next; + else + VM_Warning(prog,"VM_xml_tree_next: trying to get next sibling of last attribute \"%s\"!\n", + xml->attribute->name); + } + else if ( xml->node->next ) + xml->node = xml->node->next; + else + VM_Warning(prog,"VM_xml_tree_next: trying to get next sibling of last element \"%s\"!\n", + xml->node->name); +} + +void VM_xml_tree_type(prvm_prog_t *prog) +{ + qxml_p xml; + VM_XML_CHECK_RETURN(VM_xml_tree_type, PRVM_G_FLOAT(OFS_RETURN) = 0); + if ( xml->attribute ) + PRVM_G_FLOAT(OFS_RETURN) = XML_ATTRIBUTE_NODE; + else + PRVM_G_FLOAT(OFS_RETURN) = xml->node->type; +} + +void VM_xml_tree_root(prvm_prog_t *prog) +{ + qxml_p xml; + VM_SAFEPARMCOUNT(1,VM_xml_tree_root); + xml = VM_Xml_Data(prog,PRVM_G_FLOAT(OFS_PARM0)-1); + if ( !xml ) + return; + xml->node = xmlDocGetRootElement(xml->doc); +} \ No newline at end of file diff --git a/xml.h b/xml.h new file mode 100644 index 00000000..e0155cd6 --- /dev/null +++ b/xml.h @@ -0,0 +1,20 @@ +#ifndef XML_H +#define XML_H + +#include "prvm_cmds.h" + +void VM_xml_open(prvm_prog_t *prog); +void VM_xml_close(prvm_prog_t *prog); +void VM_xml_tree_name(prvm_prog_t *prog); +void VM_xml_tree_text(prvm_prog_t *prog); +void VM_xml_tree_leaf(prvm_prog_t *prog); +void VM_xml_tree_child(prvm_prog_t *prog); +void VM_xml_tree_parent(prvm_prog_t *prog); +void VM_xml_tree_has_sibling(prvm_prog_t *prog); +void VM_xml_tree_next(prvm_prog_t *prog); +void VM_xml_tree_type(prvm_prog_t *prog); +void VM_xml_tree_root(prvm_prog_t *prog); + +void XML_Close(prvm_prog_t *prog, int index); + +#endif