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