more eol-style
[xonotic/netradiant.git] / plugins / mapxml / xmlparse.cpp
1 //
2 // parses xml tree format into internal objects
3 //
4
5
6 #include "plugin.h"
7
8 void Patch_XMLParse(patchMesh_t *pPatch, xmlNodePtr surface)
9 {
10   char *str, *content;
11   int i, j;
12
13   for(xmlNodePtr current = surface->children; current != NULL; current = current->next)
14   {
15     if(current->type != XML_ELEMENT_NODE) continue;
16     if(!strcmp((char *)current->name, "matrix"))
17     {
18       str = (char *)xmlGetProp(current, (xmlChar *)"width");
19       pPatch->width = atoi(str);
20       xmlFree(str);
21       str = (char *)xmlGetProp(current, (xmlChar *)"height");
22       pPatch->height = atoi(str);
23       xmlFree(str);
24
25       content = Q_StrDup((char *)current->children->content);
26
27       str = strtok(content, " \n\r\t\v\0");
28       for(i=0; i<pPatch->width; i++)
29       {
30         for(j=0; j<pPatch->height; j++)
31         {
32           pPatch->ctrl[i][j].xyz[0] = atof(str);
33           str = strtok(NULL, " \n\r\t\v\0");
34           pPatch->ctrl[i][j].xyz[1] = atof(str);
35           str = strtok(NULL, " \n\r\t\v\0");
36           pPatch->ctrl[i][j].xyz[2] = atof(str);
37           str = strtok(NULL, " \n\r\t\v\0");
38           pPatch->ctrl[i][j].st[0] = atof(str);
39           str = strtok(NULL, " \n\r\t\v\0");
40           pPatch->ctrl[i][j].st[1] = atof(str);
41           str = strtok(NULL, " \n\r\t\v\0");
42         }
43       }
44
45       delete [] content;
46     }
47     else if(!strcmp((char *)current->name, "shader")) {
48       pPatch->pShader = QERApp_Shader_ForName((char*)current->children->content);
49       pPatch->d_texture = pPatch->pShader->getTexture();
50     }
51   }
52 }
53
54 void Face_XMLParse (face_t *face, xmlNodePtr surface)
55 {
56   char *str, *content;
57   int i, j;
58
59   for(xmlNodePtr current = surface->children; current != NULL; current = current->next)
60   {
61     if(current->type != XML_ELEMENT_NODE) continue;
62     if(!strcmp((char *)current->name, "planepts"))
63     {
64       content = Q_StrDup((char *)current->children->content);
65
66       str = strtok(content, " \n\r\t\v\0");
67       for (i=0 ; i<3 ; i++)
68             {
69                     for (j=0 ; j<3 ; j++)
70                     {
71                             face->planepts[i][j] = atof(str);
72           str = strtok(NULL, " \n\r\t\v\0");
73                     }
74       }
75
76       delete [] content;
77     }
78     else if(!strcmp((char *)current->name, "texdef"))
79     {
80       content = Q_StrDup((char *)current->children->content);
81   
82       str = strtok(content, " \n\r\t\v\0");
83       face->texdef.shift[0] = atof(str);
84       str = strtok(NULL, " \n\r\t\v\0");
85       face->texdef.shift[1] = atof(str);
86       str = strtok(NULL, " \n\r\t\v\0");
87       face->texdef.rotate = atof(str);
88       str = strtok(NULL, " \n\r\t\v\0");
89       face->texdef.scale[0] = atof(str);
90       str = strtok(NULL, " \n\r\t\v\0");
91       face->texdef.scale[1] = atof(str);
92
93       delete [] content;
94     }
95     else if(!strcmp((char *)current->name, "bpmatrix"))
96     {
97       content = Q_StrDup((char *)current->children->content);
98   
99       str = strtok(content, " \n\r\t\v\0");
100       face->brushprimit_texdef.coords[0][0] = atof(str);
101       str = strtok(NULL, " \n\r\t\v\0");
102       face->brushprimit_texdef.coords[0][1] = atof(str);
103       str = strtok(NULL, " \n\r\t\v\0");
104       face->brushprimit_texdef.coords[0][2] = atof(str);
105       str = strtok(NULL, " \n\r\t\v\0");
106       face->brushprimit_texdef.coords[1][0] = atof(str);
107       str = strtok(NULL, " \n\r\t\v\0");
108       face->brushprimit_texdef.coords[1][1] = atof(str);
109       str = strtok(NULL, " \n\r\t\v\0");
110       face->brushprimit_texdef.coords[1][2] = atof(str);
111
112       delete [] content;
113     }
114     else if(!strcmp((char *)current->name, "flags"))
115     {
116       content = Q_StrDup((char *)current->children->content);
117
118       str = strtok(content, " \n\r\t\v\0");
119       face->texdef.contents = atoi(str);
120       str = strtok(NULL, " \n\r\t\v\0");
121       face->texdef.flags = atoi(str);
122       str = strtok(NULL, " \n\r\t\v\0");
123       face->texdef.value = atoi(str);
124
125       delete [] content;
126     }
127     else if(!strcmp((char *)current->name, "shader"))
128     {
129       face->texdef.SetName((char *)current->children->content);
130     }
131   }
132 }
133
134 void Brush_XMLParse (brush_t *pBrush, xmlNodePtr primitive)
135 {
136   face_t    *f;
137
138   for(xmlNodePtr current = primitive->children; current != NULL; current = current->next)
139   {
140     if(current->type != XML_ELEMENT_NODE) continue;
141     f = pBrush->brush_faces;
142     pBrush->brush_faces = Face_Alloc();
143     Face_XMLParse(pBrush->brush_faces, current);
144     pBrush->brush_faces->next = f;
145   }
146 }
147
148 void Entity_XMLParse(entity_t *pEntity, xmlNodePtr entity)
149 {
150   brush_t *pBrush;
151
152   for(xmlNodePtr current = entity->children; current != NULL; current = current->next)
153   {
154     if(current->type != XML_ELEMENT_NODE) continue;
155     if(!strcmp((char *)current->name, "epair"))
156     {
157       char *key = (char *)xmlGetProp(current, (xmlChar *)"key");
158       char *value = (char *)xmlGetProp(current, (xmlChar *)"value");
159       SetKeyValue(pEntity, key, value);
160       xmlFree(key);
161       xmlFree(value);
162     }
163     else if(strcmp((char *)current->name, "brush") == 0)
164     {
165       pBrush = Brush_Alloc();
166       Brush_XMLParse(pBrush, current);
167       ((CPtrArray*)pEntity->pData)->Add(pBrush);
168     }
169     else if(strcmp((char *)current->name, "patch") == 0)
170     {
171       pBrush = Brush_Alloc();
172       pBrush->patchBrush = true;
173       pBrush->pPatch = Patch_Alloc();
174       pBrush->pPatch->pSymbiot = pBrush;
175       Patch_XMLParse(pBrush->pPatch, current);
176       ((CPtrArray*)pEntity->pData)->Add(pBrush);
177     }
178   }
179 }
180
181 void Map_XMLRead(CPtrArray *map, xmlNodePtr map_node)
182 {
183   entity_t *pEntity;
184   xmlNodePtr current;
185
186   for(current = map_node->children; current != NULL; current = current->next)
187   {
188     if(current->type != XML_ELEMENT_NODE) continue;
189     pEntity = Entity_Alloc();
190     pEntity->pData = new CPtrArray;
191     Entity_XMLParse(pEntity, current);
192     map->Add(pEntity);
193   }
194 }
195
196 // SPoG
197 // temporarily copied from qe3.cpp
198 // duplicate code starts here (note: g_strAppPath swapped for g_FuncTable.m_pfnGetQERPath())
199
200 void HandleXMLError( void* ctxt, const char* text, ... )
201 {
202   va_list argptr;
203   static char buf[32768];
204
205   va_start (argptr,text);
206   vsprintf (buf, text, argptr);
207   Sys_FPrintf (SYS_ERR, "XML %s\n", buf);
208   va_end (argptr);
209 }
210
211 #define DTD_BUFFER_LENGTH 1024
212 xmlDocPtr ParseXMLStream(IDataStream *stream, bool validate = false)
213 {
214   xmlDocPtr doc = NULL;
215   bool wellFormed = false, valid = false;
216   int res, size = 1024;
217   char chars[1024];
218   xmlParserCtxtPtr ctxt;
219
220   // SPoG
221   // HACK: use AppPath to resolve DTD location
222   // do a buffer-safe string copy and concatenate
223   int i;
224   char* w;
225   const char* r;
226   char buf[DTD_BUFFER_LENGTH];
227
228   w = buf;
229   i = 0;
230   // copy
231   //assert(g_FuncTable.m_pfnGetQERPath() != NULL);
232   for(r = g_FuncTable.m_pfnGetQERPath(); i<DTD_BUFFER_LENGTH && *r != '\0'; i++, r++)  w[i] = *r;
233   // concatenate
234   for(r = "dtds/"; i<DTD_BUFFER_LENGTH && *r != '\0'; i++, r++)  w[i] = *r;
235   // terminate
236   w[i] = '\0';
237
238   if(i == DTD_BUFFER_LENGTH)
239   {
240     HandleXMLError(NULL, "ERROR: buffer overflow: DTD path length too large\n");
241     return NULL;
242   }
243
244   //if(validate)
245   //  xmlDoValidityCheckingDefaultValue = 1;
246   //else
247     xmlDoValidityCheckingDefaultValue = 0;
248
249   xmlSetGenericErrorFunc(NULL, HandleXMLError);
250
251   res = stream->Read(chars, 4);
252   if (res > 0)
253   {
254     ctxt = xmlCreatePushParserCtxt(NULL, NULL, chars, res, buf);
255
256     while ((res = stream->Read(chars, size)) > 0)
257     {
258       xmlParseChunk(ctxt, chars, res, 0);
259     }
260     xmlParseChunk(ctxt, chars, 0, 1);
261     doc = ctxt->myDoc;
262
263     wellFormed = (ctxt->wellFormed == 1);
264     valid = (ctxt->valid == 1);
265
266     xmlFreeParserCtxt(ctxt);
267   }
268
269   if(wellFormed && (!validate || (validate && valid)))
270     return doc;
271
272   if(doc != NULL)
273     xmlFreeDoc(doc);
274
275   return NULL;
276 }
277
278 // duplicate code ends here
279
280 void Map_Read (IDataStream *in, CPtrArray *map)
281 {
282   xmlDocPtr doc;
283
284   doc = ParseXMLStream(in, false ); // quick hack while dtd validation is broken
285
286   if(doc != NULL)
287   {
288     xmlNodePtr node=doc->children;
289     while(node != NULL && node->type != XML_ELEMENT_NODE) node=node->next;
290     if(node != NULL)
291       Map_XMLRead(map, node);
292   }
293  
294   xmlFreeDoc(doc);
295 }