1 /* Copyright (C) 2009 Trend Micro Inc.
4 * This program is a free software; you can redistribute it
5 * and/or modify it under the terms of the GNU General Public
6 * License (version 2) as published by the FSF - Free Software
19 #include "os_xml_internal.h"
22 static int _oscomment(FILE *fp) __attribute__((nonnull));
23 static int _writecontent(const char *str, size_t size, unsigned int parent, OS_XML *_lxml) __attribute__((nonnull));
24 static int _writememory(const char *str, XML_TYPE type, size_t size,
25 unsigned int parent, OS_XML *_lxml) __attribute__((nonnull));
26 static int _xml_fgetc(FILE *fp) __attribute__((nonnull));
27 static int _ReadElem(FILE *fp, unsigned int parent, OS_XML *_lxml) __attribute__((nonnull));
28 static int _getattributes(FILE *fp, unsigned int parent, OS_XML *_lxml) __attribute__((nonnull));
29 static void xml_error(OS_XML *_lxml, const char *msg, ...) __attribute__((format(printf, 2, 3), nonnull));
32 static unsigned int _line;
36 static int _xml_fgetc(FILE *fp)
41 if (c == '\n') { /* add newline */
48 static void xml_error(OS_XML *_lxml, const char *msg, ...)
53 memset(_lxml->err, '\0', XML_ERR_LENGTH);
54 vsnprintf(_lxml->err, XML_ERR_LENGTH - 1, msg, args);
56 _lxml->err_line = _line;
60 void OS_ClearXML(OS_XML *_lxml)
63 for (i = 0; i < _lxml->cur; i++) {
89 memset(_lxml->err, '\0', XML_ERR_LENGTH);
92 /* Read an XML file and generate the necessary structs */
93 int OS_ReadXML(const char *file, OS_XML *_lxml)
99 /* Initialize xml structure */
110 memset(_lxml->err, '\0', XML_ERR_LENGTH);
112 fp = fopen(file, "r");
114 xml_error(_lxml, "XMLERR: File '%s' not found.", file);
121 if ((r = _ReadElem(fp, 0, _lxml)) < 0) { /* First position */
128 for (i = 0; i < _lxml->cur; i++) {
129 if (_lxml->ck[i] == 0) {
130 xml_error(_lxml, "XMLERR: Element '%s' not closed.", _lxml->el[i]);
140 static int _oscomment(FILE *fp)
143 if ((c = fgetc(fp)) == _R_COM) {
144 while ((c = _xml_fgetc(fp)) != EOF) {
146 if ((c = fgetc(fp)) == _R_CONFE) {
150 } else if (c == '-') { /* W3C way of finishing comments */
151 if ((c = _xml_fgetc(fp)) == '-') {
152 if ((c = fgetc(fp)) == _R_CONFE) {
169 static int _ReadElem(FILE *fp, unsigned int parent, OS_XML *_lxml)
172 unsigned int count = 0;
173 unsigned int _currentlycont = 0;
174 short int location = -1;
177 char elem[XML_MAXSIZE + 1];
178 char cont[XML_MAXSIZE + 1];
179 char closedelim[XML_MAXSIZE + 1];
181 memset(elem, '\0', XML_MAXSIZE + 1);
182 memset(cont, '\0', XML_MAXSIZE + 1);
183 memset(closedelim, '\0', XML_MAXSIZE + 1);
185 while ((c = _xml_fgetc(fp)) != EOF) {
188 } else if (prevv == '\\') {
195 if (count >= XML_MAXSIZE) {
196 xml_error(_lxml, "XMLERR: String overflow.");
200 /* Check for comments */
203 if ((r = _oscomment(fp)) < 0) {
204 xml_error(_lxml, "XMLERR: Comment not closed.");
212 if ((location == -1) && (prevv == 0)) {
214 if ((c = fgetc(fp)) == '/') {
215 xml_error(_lxml, "XMLERR: Element not opened.");
226 else if ((location == 0) && ((c == _R_CONFE) || isspace(c))) {
231 /* Remove the / at the end of the element name */
232 if (count > 0 && elem[count - 1] == '/') {
234 elem[count - 1] = '\0';
237 if (_writememory(elem, XML_ELEM, count + 1, parent, _lxml) < 0) {
240 _currentlycont = _lxml->cur - 1;
242 if ((_ga = _getattributes(fp, parent, _lxml)) < 0) {
247 /* If the element is closed already (finished in />) */
248 if ((_ge == '/') || (_ga == '/')) {
249 if (_writecontent("\0", 2, _currentlycont, _lxml) < 0) {
252 _lxml->ck[_currentlycont] = 1;
257 memset(elem, '\0', XML_MAXSIZE);
258 memset(closedelim, '\0', XML_MAXSIZE);
259 memset(cont, '\0', XML_MAXSIZE);
270 else if ((location == 2) && (c == _R_CONFE)) {
271 closedelim[count] = '\0';
272 if (strcmp(closedelim, elem) != 0) {
273 xml_error(_lxml, "XMLERR: Element '%s' not closed.", elem);
276 if (_writecontent(cont, strlen(cont) + 1, _currentlycont, _lxml) < 0) {
279 _lxml->ck[_currentlycont] = 1;
280 memset(elem, '\0', XML_MAXSIZE);
281 memset(closedelim, '\0', XML_MAXSIZE);
282 memset(cont, '\0', XML_MAXSIZE);
289 } else if ((location == 1) && (c == _R_CONFS) && (prevv == 0)) {
290 if ((c = fgetc(fp)) == '/') {
296 ungetc(_R_CONFS, fp);
298 if (_ReadElem(fp, parent + 1, _lxml) < 0) {
305 elem[count++] = (char) c;
306 } else if (location == 1) {
307 cont[count++] = (char) c;
308 } else if (location == 2) {
309 closedelim[count++] = (char) c;
312 if ((_R_CONFS == c) && (prevv != 0)) {
317 if (location == -1) {
321 xml_error(_lxml, "XMLERR: End of file and some elements were not closed.");
325 static int _writememory(const char *str, XML_TYPE type, size_t size,
326 unsigned int parent, OS_XML *_lxml)
333 /* Allocate for the element */
334 tmp = (char **)realloc(_lxml->el, (_lxml->cur + 1) * sizeof(char *));
339 _lxml->el[_lxml->cur] = (char *)calloc(size, sizeof(char));
340 if (_lxml->el[_lxml->cur] == NULL) {
343 strncpy(_lxml->el[_lxml->cur], str, size - 1);
345 /* Allocate for the content */
346 tmp = (char **)realloc(_lxml->ct, (_lxml->cur + 1) * sizeof(char *));
351 _lxml->ct[_lxml->cur] = NULL;
353 /* Allocate for the type */
354 tmp4 = (XML_TYPE *) realloc(_lxml->tp, (_lxml->cur + 1) * sizeof(XML_TYPE));
359 _lxml->tp[_lxml->cur] = type;
361 /* Allocate for the relation */
362 tmp3 = (unsigned int *) realloc(_lxml->rl, (_lxml->cur + 1) * sizeof(unsigned int));
367 _lxml->rl[_lxml->cur] = parent;
369 /* Allocate for the "check" */
370 tmp2 = (int *) realloc(_lxml->ck, (_lxml->cur + 1) * sizeof(int));
375 _lxml->ck[_lxml->cur] = 0;
377 /* Allocate for the line */
378 tmp3 = (unsigned int *) realloc(_lxml->ln, (_lxml->cur + 1) * sizeof(unsigned int));
383 _lxml->ln[_lxml->cur] = _line;
385 /* Attributes does not need to be closed */
386 if (type == XML_ATTR) {
387 _lxml->ck[_lxml->cur] = 1;
390 /* Check if it is a variable */
391 if (strcasecmp(XML_VAR, str) == 0) {
392 _lxml->tp[_lxml->cur] = XML_VARIABLE_BEGIN;
399 snprintf(_lxml->err, XML_ERR_LENGTH, "XMLERR: Memory error.");
403 static int _writecontent(const char *str, size_t size, unsigned int parent, OS_XML *_lxml)
405 _lxml->ct[parent] = (char *)calloc(size, sizeof(char));
406 if ( _lxml->ct[parent] == NULL) {
407 snprintf(_lxml->err, XML_ERR_LENGTH, "XMLERR: Memory error.");
410 strncpy(_lxml->ct[parent], str, size - 1);
415 /* Read the attributes of an element */
416 static int _getattributes(FILE *fp, unsigned int parent, OS_XML *_lxml)
419 unsigned int count = 0;
423 char attr[XML_MAXSIZE + 1];
424 char value[XML_MAXSIZE + 1];
426 memset(attr, '\0', XML_MAXSIZE + 1);
427 memset(value, '\0', XML_MAXSIZE + 1);
429 while ((c = _xml_fgetc(fp)) != EOF) {
430 if (count >= XML_MAXSIZE) {
431 attr[count - 1] = '\0';
433 "XMLERR: Overflow attempt at attribute '%.20s'.", attr);
437 else if ((c == _R_CONFE) || ((location == 0) && (c == '/'))) {
439 xml_error(_lxml, "XMLERR: Attribute '%s' not closed.",
442 } else if ((location == 0) && (count > 0)) {
443 xml_error(_lxml, "XMLERR: Attribute '%s' has no value.",
446 } else if (c == '/') {
451 } else if ((location == 0) && (c == '=')) {
454 /* Check for existing attribute with same name */
455 unsigned int i = _lxml->cur - 1;
456 /* Search attributes backwards in same parent */
457 while (_lxml->rl[i] == parent && _lxml->tp[i] == XML_ATTR) {
458 if (strcmp(_lxml->el[i], attr) == 0) {
459 xml_error(_lxml, "XMLERR: Attribute '%s' already defined.", attr);
463 /* Continue with previous element */
471 if ((c != '"') && (c != '\'')) {
472 unsigned short int _err = 1;
474 while ((c = _xml_fgetc(fp)) != EOF) {
477 } else if ((c == '"') || (c == '\'')) {
487 "XMLERR: Attribute '%s' not followed by a \" or \'."
496 } else if ((location == 0) && (isspace(c))) {
500 xml_error(_lxml, "XMLERR: Attribute '%s' has no value.", attr);
503 } else if ((location == 1) && (c == c_to_match)) {
506 if (_writememory(attr, XML_ATTR, strlen(attr) + 1,
507 parent, _lxml) < 0) {
510 if (_writecontent(value, count + 1, _lxml->cur - 1, _lxml) < 0) {
515 return (_getattributes(fp, parent, _lxml));
516 } else if (c == _R_CONFE) {
518 } else if (c == '/') {
523 "XMLERR: Bad attribute closing for '%s'='%s'.",
526 } else if (location == 0) {
527 attr[count++] = (char) c;
528 } else if (location == 1) {
529 value[count++] = (char) c;
533 xml_error(_lxml, "XMLERR: End of file while reading an attribute.");