1/* $Id: upnpreplyparse.c,v 1.18 2014/11/05 05:36:08 nanard Exp $ */
2/* MiniUPnP project
3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4 * (c) 2006-2014 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
15static void
16NameValueParserStartElt(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
28static void
29NameValueParserEndElt(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		nv->l_next = data->l_head;	/* insert in list */
57		data->l_head = nv;
58	}
59	data->cdata = NULL;
60	data->cdatalen = 0;
61	data->topelt = 0;
62}
63
64static void
65NameValueParserGetData(void * d, const char * datas, int l)
66{
67    struct NameValueParserData * data = (struct NameValueParserData *)d;
68	if(strcmp(data->curelt, "NewPortListing") == 0)
69	{
70		/* specific case for NewPortListing which is a XML Document */
71		data->portListing = malloc(l + 1);
72		if(!data->portListing)
73		{
74			/* malloc error */
75			return;
76		}
77		memcpy(data->portListing, datas, l);
78		data->portListing[l] = '\0';
79		data->portListingLength = l;
80	}
81	else
82	{
83		/* standard case. */
84		data->cdata = datas;
85		data->cdatalen = l;
86	}
87}
88
89void
90ParseNameValue(const char * buffer, int bufsize,
91               struct NameValueParserData * data)
92{
93	struct xmlparser parser;
94	data->l_head = NULL;
95	data->portListing = NULL;
96	data->portListingLength = 0;
97	/* init xmlparser object */
98	parser.xmlstart = buffer;
99	parser.xmlsize = bufsize;
100	parser.data = data;
101	parser.starteltfunc = NameValueParserStartElt;
102	parser.endeltfunc = NameValueParserEndElt;
103	parser.datafunc = NameValueParserGetData;
104	parser.attfunc = 0;
105	parsexml(&parser);
106}
107
108void
109ClearNameValueList(struct NameValueParserData * pdata)
110{
111    struct NameValue * nv;
112	if(pdata->portListing)
113	{
114		free(pdata->portListing);
115		pdata->portListing = NULL;
116		pdata->portListingLength = 0;
117	}
118    while((nv = pdata->l_head) != NULL)
119    {
120		pdata->l_head = nv->l_next;
121        free(nv);
122    }
123}
124
125char *
126GetValueFromNameValueList(struct NameValueParserData * pdata,
127                          const char * Name)
128{
129    struct NameValue * nv;
130    char * p = NULL;
131    for(nv = pdata->l_head;
132        (nv != NULL) && (p == NULL);
133        nv = nv->l_next)
134    {
135        if(strcmp(nv->name, Name) == 0)
136            p = nv->value;
137    }
138    return p;
139}
140
141#if 0
142/* useless now that minixml ignores namespaces by itself */
143char *
144GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata,
145                                  const char * Name)
146{
147	struct NameValue * nv;
148	char * p = NULL;
149	char * pname;
150	for(nv = pdata->head.lh_first;
151	    (nv != NULL) && (p == NULL);
152		nv = nv->entries.le_next)
153	{
154		pname = strrchr(nv->name, ':');
155		if(pname)
156			pname++;
157		else
158			pname = nv->name;
159		if(strcmp(pname, Name)==0)
160			p = nv->value;
161	}
162	return p;
163}
164#endif
165
166/* debug all-in-one function
167 * do parsing then display to stdout */
168#ifdef DEBUG
169void
170DisplayNameValueList(char * buffer, int bufsize)
171{
172    struct NameValueParserData pdata;
173    struct NameValue * nv;
174    ParseNameValue(buffer, bufsize, &pdata);
175    for(nv = pdata.l_head;
176        nv != NULL;
177        nv = nv->l_next)
178    {
179        printf("%s = %s\n", nv->name, nv->value);
180    }
181    ClearNameValueList(&pdata);
182}
183#endif
184
185