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-2017 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 		data->portListing = malloc(l + 1);
82 		if(!data->portListing)
83 		{
84 			/* malloc error */
85 #ifdef DEBUG
86 			fprintf(stderr, "%s: error allocating memory",
87 			        "NameValueParserGetData");
88 #endif /* DEBUG */
89 			return;
90 		}
91 		memcpy(data->portListing, datas, l);
92 		data->portListing[l] = '\0';
93 		data->portListingLength = l;
94 	}
95 	else
96 	{
97 		/* standard case. */
98 		data->cdata = datas;
99 		data->cdatalen = l;
100 	}
101 }
102 
103 void
ParseNameValue(const char * buffer,int bufsize,struct NameValueParserData * data)104 ParseNameValue(const char * buffer, int bufsize,
105                struct NameValueParserData * data)
106 {
107 	struct xmlparser parser;
108 	memset(data, 0, sizeof(struct NameValueParserData));
109 	/* init xmlparser object */
110 	parser.xmlstart = buffer;
111 	parser.xmlsize = bufsize;
112 	parser.data = data;
113 	parser.starteltfunc = NameValueParserStartElt;
114 	parser.endeltfunc = NameValueParserEndElt;
115 	parser.datafunc = NameValueParserGetData;
116 	parser.attfunc = 0;
117 	parsexml(&parser);
118 }
119 
120 void
ClearNameValueList(struct NameValueParserData * pdata)121 ClearNameValueList(struct NameValueParserData * pdata)
122 {
123     struct NameValue * nv;
124 	if(pdata->portListing)
125 	{
126 		free(pdata->portListing);
127 		pdata->portListing = NULL;
128 		pdata->portListingLength = 0;
129 	}
130     while((nv = pdata->l_head) != NULL)
131     {
132 		pdata->l_head = nv->l_next;
133         free(nv);
134     }
135 }
136 
137 char *
GetValueFromNameValueList(struct NameValueParserData * pdata,const char * Name)138 GetValueFromNameValueList(struct NameValueParserData * pdata,
139                           const char * Name)
140 {
141     struct NameValue * nv;
142     char * p = NULL;
143     for(nv = pdata->l_head;
144         (nv != NULL) && (p == NULL);
145         nv = nv->l_next)
146     {
147         if(strcmp(nv->name, Name) == 0)
148             p = nv->value;
149     }
150     return p;
151 }
152 
153 #if 0
154 /* useless now that minixml ignores namespaces by itself */
155 char *
156 GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata,
157                                   const char * Name)
158 {
159 	struct NameValue * nv;
160 	char * p = NULL;
161 	char * pname;
162 	for(nv = pdata->head.lh_first;
163 	    (nv != NULL) && (p == NULL);
164 		nv = nv->entries.le_next)
165 	{
166 		pname = strrchr(nv->name, ':');
167 		if(pname)
168 			pname++;
169 		else
170 			pname = nv->name;
171 		if(strcmp(pname, Name)==0)
172 			p = nv->value;
173 	}
174 	return p;
175 }
176 #endif
177 
178 /* debug all-in-one function
179  * do parsing then display to stdout */
180 #ifdef DEBUG
181 void
DisplayNameValueList(char * buffer,int bufsize)182 DisplayNameValueList(char * buffer, int bufsize)
183 {
184     struct NameValueParserData pdata;
185     struct NameValue * nv;
186     ParseNameValue(buffer, bufsize, &pdata);
187     for(nv = pdata.l_head;
188         nv != NULL;
189         nv = nv->l_next)
190     {
191         printf("%s = %s\n", nv->name, nv->value);
192     }
193     ClearNameValueList(&pdata);
194 }
195 #endif /* DEBUG */
196 
197