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 |
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 |
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 |
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 |
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 |
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 * |
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 |
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 | |