1/* $Id: upnpreplyparse.c,v 1.20 2017/12/12 11:26:25 nanard Exp $ */
2/* vim: tabstop=4 shiftwidth=4 noexpandtab
3 * MiniUPnP project
4 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
5 * (c) 2006-2019 Thomas Bernard
6 * This software is subject to the conditions detailed
7 * in the LICENCE file provided within the distribution */
8
9#include <stdlib.h>
10#include <string.h>
11#include <stdio.h>
12
13#include "upnpreplyparse.h"
14#include "minixml.h"
15
16static void
17NameValueParserStartElt(void * d, const char * name, int l)
18{
19 struct NameValueParserData * data = (struct NameValueParserData *)d;
20 data->topelt = 1;
21 if(l>63)
22 l = 63;
23 memcpy(data->curelt, name, l);
24 data->curelt[l] = '\0';
25 data->cdata = NULL;
26 data->cdatalen = 0;
27}
28
29static void
30NameValueParserEndElt(void * d, const char * name, int namelen)
31{
32 struct NameValueParserData * data = (struct NameValueParserData *)d;
33 struct NameValue * nv;
34 (void)name;
35 (void)namelen;
36 if(!data->topelt)
37 return;
38 if(strcmp(data->curelt, "NewPortListing") != 0)
39 {
40 int l;
41 /* standard case. Limited to n chars strings */
42 l = data->cdatalen;
43 nv = malloc(sizeof(struct NameValue));
44 if(nv == NULL)
45 {
46 /* malloc error */
47#ifdef DEBUG
48 fprintf(stderr, "%s: error allocating memory",
49 "NameValueParserEndElt");
50#endif /* DEBUG */
51 return;
52 }
53 if(l>=(int)sizeof(nv->value))
54 l = sizeof(nv->value) - 1;
55 strncpy(nv->name, data->curelt, 64);
56 nv->name[63] = '\0';
57 if(data->cdata != NULL)
58 {
59 memcpy(nv->value, data->cdata, l);
60 nv->value[l] = '\0';
61 }
62 else
63 {
64 nv->value[0] = '\0';
65 }
66 nv->l_next = data->l_head; /* insert in list */
67 data->l_head = nv;
68 }
69 data->cdata = NULL;
70 data->cdatalen = 0;
71 data->topelt = 0;
72}
73
74static void
75NameValueParserGetData(void * d, const char * datas, int l)
76{
77 struct NameValueParserData * data = (struct NameValueParserData *)d;
78 if(strcmp(data->curelt, "NewPortListing") == 0)
79 {
80 /* specific case for NewPortListing which is a XML Document */
81 free(data->portListing);
82 data->portListing = malloc(l + 1);
83 if(!data->portListing)
84 {
85 /* malloc error */
86#ifdef DEBUG
87 fprintf(stderr, "%s: error allocating memory",
88 "NameValueParserGetData");
89#endif /* DEBUG */
90 return;
91 }
92 memcpy(data->portListing, datas, l);
93 data->portListing[l] = '\0';
94 data->portListingLength = l;
95 }
96 else
97 {
98 /* standard case. */
99 data->cdata = datas;
100 data->cdatalen = l;
101 }
102}
103
104void
105ParseNameValue(const char * buffer, int bufsize,
106 struct NameValueParserData * data)
107{
108 struct xmlparser parser;
109 memset(data, 0, sizeof(struct NameValueParserData));
110 /* init xmlparser object */
111 parser.xmlstart = buffer;
112 parser.xmlsize = bufsize;
113 parser.data = data;
114 parser.starteltfunc = NameValueParserStartElt;
115 parser.endeltfunc = NameValueParserEndElt;
116 parser.datafunc = NameValueParserGetData;
117 parser.attfunc = 0;
118 parsexml(&parser);
119}
120
121void
122ClearNameValueList(struct NameValueParserData * pdata)
123{
124 struct NameValue * nv;
125 if(pdata->portListing)
126 {
127 free(pdata->portListing);
128 pdata->portListing = NULL;
129 pdata->portListingLength = 0;
130 }
131 while((nv = pdata->l_head) != NULL)
132 {
133 pdata->l_head = nv->l_next;
134 free(nv);
135 }
136}
137
138char *
139GetValueFromNameValueList(struct NameValueParserData * pdata,
140 const char * Name)
141{
142 struct NameValue * nv;
143 char * p = NULL;
144 for(nv = pdata->l_head;
145 (nv != NULL) && (p == NULL);
146 nv = nv->l_next)
147 {
148 if(strcmp(nv->name, Name) == 0)
149 p = nv->value;
150 }
151 return p;
152}
153
154#if 0
155/* useless now that minixml ignores namespaces by itself */
156char *
157GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata,
158 const char * Name)
159{
160 struct NameValue * nv;
161 char * p = NULL;
162 char * pname;
163 for(nv = pdata->head.lh_first;
164 (nv != NULL) && (p == NULL);
165 nv = nv->entries.le_next)
166 {
167 pname = strrchr(nv->name, ':');
168 if(pname)
169 pname++;
170 else
171 pname = nv->name;
172 if(strcmp(pname, Name)==0)
173 p = nv->value;
174 }
175 return p;
176}
177#endif
178
179/* debug all-in-one function
180 * do parsing then display to stdout */
181#ifdef DEBUG
182void
183DisplayNameValueList(char * buffer, int bufsize)
184{
185 struct NameValueParserData pdata;
186 struct NameValue * nv;
187 ParseNameValue(buffer, bufsize, &pdata);
188 for(nv = pdata.l_head;
189 nv != NULL;
190 nv = nv->l_next)
191 {
192 printf("%s = %s\n", nv->name, nv->value);
193 }
194 ClearNameValueList(&pdata);
195}
196#endif /* DEBUG */
197
198