Coverage Report

Created: 2026-09-01 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensips/db/pi_xml.c
Line
Count
Source
1
/*
2
 * Small XML DOM adapter for the PI framework.
3
 *
4
 * The parser itself is yxml, a small MIT-licensed streaming XML parser.
5
 */
6
#include <stdio.h>
7
#include <stdlib.h>
8
#include <string.h>
9
#include <strings.h>
10
11
#include "../mem/mem.h"
12
#include "pi_xml.h"
13
#include "../lib/yxml.h"
14
15
0
#define PI_XML_DOC_MAGIC 0x5049584d
16
17
static char *pi_xml_strdup(const char *s)
18
0
{
19
0
  char *copy = malloc(strlen(s) + 1);
20
0
  if (copy) strcpy(copy, s);
21
0
  return copy;
22
0
}
23
24
static void pi_xml_free_node(xmlNodePtr node)
25
0
{
26
0
  xmlNodePtr child, next;
27
0
  xmlAttrPtr attr, attr_next;
28
29
0
  if (!node) return;
30
0
  for (child = node->children; child; child = next) {
31
0
    next = child->next;
32
0
    pi_xml_free_node(child);
33
0
  }
34
0
  for (attr = node->properties; attr; attr = attr_next) {
35
0
    attr_next = attr->next;
36
0
    pi_xml_free_node(attr->children);
37
0
    free(attr->name);
38
0
    free(attr);
39
0
  }
40
0
  free(node->name);
41
0
  free(node->content);
42
0
  free(node);
43
0
}
44
45
static void pi_xml_append_child(xmlNodePtr parent, xmlNodePtr child)
46
0
{
47
0
  xmlNodePtr *tail;
48
0
  child->parent = parent;
49
0
  if (!parent->children) {
50
0
    parent->children = child;
51
0
    return;
52
0
  }
53
0
  for (tail = &parent->children; *tail; tail = &(*tail)->next);
54
0
  *tail = child;
55
0
}
56
57
static int pi_xml_append_content(xmlNodePtr node, const char *data)
58
0
{
59
0
  size_t old_len = node->content ? strlen(node->content) : 0;
60
0
  size_t add_len = strlen(data);
61
0
  char *content = realloc(node->content, old_len + add_len + 1);
62
0
  if (!content) return -1;
63
0
  memcpy(content + old_len, data, add_len + 1);
64
0
  node->content = content;
65
0
  return 0;
66
0
}
67
68
static int pi_xml_add_attr(xmlNodePtr node, const char *name,
69
    const char *value)
70
0
{
71
0
  xmlAttrPtr attr, *tail;
72
0
  attr = calloc(1, sizeof(*attr));
73
0
  if (!attr) return -1;
74
0
  attr->name = pi_xml_strdup(name);
75
0
  attr->children = calloc(1, sizeof(*attr->children));
76
0
  if (!attr->name || !attr->children) {
77
0
    free(attr->children);
78
0
    free(attr->name);
79
0
    free(attr);
80
0
    return -1;
81
0
  }
82
0
  attr->children->content = pi_xml_strdup(value);
83
0
  if (!attr->children->content) {
84
0
    pi_xml_free_node(attr->children);
85
0
    free(attr->name);
86
0
    free(attr);
87
0
    return -1;
88
0
  }
89
0
  for (tail = &node->properties; *tail; tail = &(*tail)->next);
90
0
  *tail = attr;
91
0
  return 0;
92
0
}
93
94
xmlDocPtr pi_xml_parse_file(const char *filename)
95
0
{
96
0
  FILE *file;
97
0
  long size;
98
0
  char *input = NULL, *attrval = NULL;
99
0
  size_t pos, attr_len = 0;
100
0
  char stack[65536];
101
0
  yxml_t parser;
102
0
  xmlDocPtr doc = NULL;
103
0
  xmlNodePtr current = NULL, node;
104
0
  yxml_ret_t ret;
105
106
0
  file = fopen(filename, "rb");
107
0
  if (!file) return NULL;
108
0
  if (fseek(file, 0, SEEK_END) || (size = ftell(file)) < 0 ||
109
0
    fseek(file, 0, SEEK_SET)) goto error;
110
0
  input = malloc((size_t)size);
111
0
  if (!input || fread(input, 1, (size_t)size, file) != (size_t)size)
112
0
    goto error;
113
0
  fclose(file);
114
0
  file = NULL;
115
116
0
  doc = calloc(1, sizeof(*doc));
117
0
  if (!doc) goto error;
118
0
  doc->magic = PI_XML_DOC_MAGIC;
119
0
  yxml_init(&parser, stack, sizeof(stack));
120
0
  for (pos = 0; pos < (size_t)size; pos++) {
121
0
    ret = yxml_parse(&parser, (unsigned char)input[pos]);
122
0
    if (ret < 0) goto error;
123
0
    switch (ret) {
124
0
    case YXML_ELEMSTART:
125
0
      node = calloc(1, sizeof(*node));
126
0
      if (!node) goto error;
127
0
      node->name = strndup(parser.elem,
128
0
          yxml_symlen(&parser, parser.elem));
129
0
      if (!node->name) {
130
0
        pi_xml_free_node(node);
131
0
        goto error;
132
0
      }
133
0
      if (current) pi_xml_append_child(current, node);
134
0
      else if (!doc->children) doc->children = node;
135
0
      else {
136
0
        pi_xml_free_node(node);
137
0
        goto error;
138
0
      }
139
0
      current = node;
140
0
      break;
141
0
    case YXML_ATTRSTART:
142
0
      free(attrval);
143
0
      attrval = calloc(1, 1);
144
0
      attr_len = 0;
145
0
      if (!attrval) goto error;
146
0
      break;
147
0
    case YXML_ATTRVAL: {
148
0
        size_t len = strlen(parser.data);
149
0
        char *value = realloc(attrval, attr_len + len + 1);
150
0
        if (!value) goto error;
151
0
        memcpy(value + attr_len, parser.data, len + 1);
152
0
        attrval = value;
153
0
        attr_len += len;
154
0
      }
155
0
      break;
156
0
    case YXML_ATTREND:
157
0
      if (!current || pi_xml_add_attr(current, parser.attr, attrval))
158
0
        goto error;
159
0
      break;
160
0
    case YXML_CONTENT:
161
0
      if (!current || pi_xml_append_content(current, parser.data))
162
0
        goto error;
163
0
      break;
164
0
    case YXML_ELEMEND:
165
0
      if (!current) goto error;
166
0
      current = current->parent;
167
0
      break;
168
0
    default:
169
0
      break;
170
0
    }
171
0
  }
172
0
  if (yxml_eof(&parser) < 0 || current) goto error;
173
0
  free(attrval);
174
0
  free(input);
175
0
  return doc;
176
177
0
error:
178
0
  if (file) fclose(file);
179
0
  free(attrval);
180
0
  free(input);
181
0
  if (doc) {
182
0
    pi_xml_free_node(doc->children);
183
0
    free(doc);
184
0
  }
185
0
  return NULL;
186
0
}
187
188
char *pi_xml_node_get_content(xmlNodePtr node)
189
0
{
190
0
  xmlNodePtr child;
191
0
  size_t len = 0;
192
0
  char *content;
193
194
0
  if (!node) return NULL;
195
0
  if (node->content) len = strlen(node->content);
196
0
  for (child = node->children; child; child = child->next)
197
0
    if (child->content) len += strlen(child->content);
198
0
  content = malloc(len + 1);
199
0
  if (!content) return NULL;
200
0
  content[0] = 0;
201
0
  if (node->content) strcat(content, node->content);
202
0
  for (child = node->children; child; child = child->next)
203
0
    if (child->content) strcat(content, child->content);
204
0
  return content;
205
0
}
206
207
void pi_xml_free(void *ptr)
208
0
{
209
0
  xmlDocPtr doc = ptr;
210
0
  if (!ptr) return;
211
0
  if (doc->magic == PI_XML_DOC_MAGIC) {
212
0
    pi_xml_free_node(doc->children);
213
0
    free(doc);
214
0
  } else free(ptr);
215
0
}
216
217
int pi_xml_strcasecmp(const xmlChar *a, const xmlChar *b)
218
0
{
219
0
  return strcasecmp(a, b);
220
0
}