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 
16 static void
NameValueParserStartElt(void * d,const char * name,int l)17 NameValueParserStartElt(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 
29 static void
NameValueParserEndElt(void * d,const char * name,int namelen)30 NameValueParserEndElt(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 
74 static void
NameValueParserGetData(void * d,const char * datas,int l)75 NameValueParserGetData(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 
104 void
ParseNameValue(const char * buffer,int bufsize,struct NameValueParserData * data)105 ParseNameValue(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 
121 void
ClearNameValueList(struct NameValueParserData * pdata)122 ClearNameValueList(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 
138 char *
GetValueFromNameValueList(struct NameValueParserData * pdata,const char * Name)139 GetValueFromNameValueList(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 */
156 char *
157 GetValueFromNameValueListIgnoreNS(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
182 void
DisplayNameValueList(char * buffer,int bufsize)183 DisplayNameValueList(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