1 | /* $Id: minixml.c,v 1.12 2017/12/12 11:17:40 nanard Exp $ */ |
2 | /* vim: tabstop=4 shiftwidth=4 noexpandtab |
3 | * minixml.c : the minimum size a xml parser can be ! */ |
4 | /* Project : miniupnp |
5 | * webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ |
6 | * Author : Thomas Bernard |
7 | |
8 | Copyright (c) 2005-2017, Thomas BERNARD |
9 | All rights reserved. |
10 | |
11 | Redistribution and use in source and binary forms, with or without |
12 | modification, are permitted provided that the following conditions are met: |
13 | |
14 | * Redistributions of source code must retain the above copyright notice, |
15 | this list of conditions and the following disclaimer. |
16 | * Redistributions in binary form must reproduce the above copyright notice, |
17 | this list of conditions and the following disclaimer in the documentation |
18 | and/or other materials provided with the distribution. |
19 | * The name of the author may not be used to endorse or promote products |
20 | derived from this software without specific prior written permission. |
21 | |
22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
23 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
24 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
25 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
26 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
27 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
28 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
29 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
30 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
31 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
32 | POSSIBILITY OF SUCH DAMAGE. |
33 | */ |
34 | #include <string.h> |
35 | #include "minixml.h" |
36 | |
37 | /* parseatt : used to parse the argument list |
38 | * return 0 (false) in case of success and -1 (true) if the end |
39 | * of the xmlbuffer is reached. */ |
40 | static int parseatt(struct xmlparser * p) |
41 | { |
42 | const char * attname; |
43 | int attnamelen; |
44 | const char * attvalue; |
45 | int attvaluelen; |
46 | while(p->xml < p->xmlend) |
47 | { |
48 | if(*p->xml=='/' || *p->xml=='>') |
49 | return 0; |
50 | if( !IS_WHITE_SPACE(*p->xml) ) |
51 | { |
52 | char sep; |
53 | attname = p->xml; |
54 | attnamelen = 0; |
55 | while(*p->xml!='=' && !IS_WHITE_SPACE(*p->xml) ) |
56 | { |
57 | attnamelen++; p->xml++; |
58 | if(p->xml >= p->xmlend) |
59 | return -1; |
60 | } |
61 | while(*(p->xml++) != '=') |
62 | { |
63 | if(p->xml >= p->xmlend) |
64 | return -1; |
65 | } |
66 | while(IS_WHITE_SPACE(*p->xml)) |
67 | { |
68 | p->xml++; |
69 | if(p->xml >= p->xmlend) |
70 | return -1; |
71 | } |
72 | sep = *p->xml; |
73 | if(sep=='\'' || sep=='\"') |
74 | { |
75 | p->xml++; |
76 | if(p->xml >= p->xmlend) |
77 | return -1; |
78 | attvalue = p->xml; |
79 | attvaluelen = 0; |
80 | while(*p->xml != sep) |
81 | { |
82 | attvaluelen++; p->xml++; |
83 | if(p->xml >= p->xmlend) |
84 | return -1; |
85 | } |
86 | } |
87 | else |
88 | { |
89 | attvalue = p->xml; |
90 | attvaluelen = 0; |
91 | while( !IS_WHITE_SPACE(*p->xml) |
92 | && *p->xml != '>' && *p->xml != '/') |
93 | { |
94 | attvaluelen++; p->xml++; |
95 | if(p->xml >= p->xmlend) |
96 | return -1; |
97 | } |
98 | } |
99 | /*printf("%.*s='%.*s'\n", |
100 | attnamelen, attname, attvaluelen, attvalue);*/ |
101 | if(p->attfunc) |
102 | p->attfunc(p->data, attname, attnamelen, attvalue, attvaluelen); |
103 | } |
104 | p->xml++; |
105 | } |
106 | return -1; |
107 | } |
108 | |
109 | /* parseelt parse the xml stream and |
110 | * call the callback functions when needed... */ |
111 | static void parseelt(struct xmlparser * p) |
112 | { |
113 | int i; |
114 | const char * elementname; |
115 | while(p->xml < (p->xmlend - 1)) |
116 | { |
117 | if((p->xml + 4) <= p->xmlend && (0 == memcmp(p->xml, "<!--" , 4))) |
118 | { |
119 | p->xml += 3; |
120 | /* ignore comments */ |
121 | do |
122 | { |
123 | p->xml++; |
124 | if ((p->xml + 3) >= p->xmlend) |
125 | return; |
126 | } |
127 | while(memcmp(p->xml, "-->" , 3) != 0); |
128 | p->xml += 3; |
129 | } |
130 | else if((p->xml)[0]=='<' && (p->xml)[1]!='?') |
131 | { |
132 | i = 0; elementname = ++p->xml; |
133 | while( !IS_WHITE_SPACE(*p->xml) |
134 | && (*p->xml!='>') && (*p->xml!='/') |
135 | ) |
136 | { |
137 | i++; p->xml++; |
138 | if (p->xml >= p->xmlend) |
139 | return; |
140 | /* to ignore namespace : */ |
141 | if(*p->xml==':') |
142 | { |
143 | i = 0; |
144 | elementname = ++p->xml; |
145 | } |
146 | } |
147 | if(i>0) |
148 | { |
149 | if(p->starteltfunc) |
150 | p->starteltfunc(p->data, elementname, i); |
151 | if(parseatt(p)) |
152 | return; |
153 | if(*p->xml!='/') |
154 | { |
155 | const char * data; |
156 | i = 0; data = ++p->xml; |
157 | if (p->xml >= p->xmlend) |
158 | return; |
159 | while( IS_WHITE_SPACE(*p->xml) ) |
160 | { |
161 | i++; p->xml++; |
162 | if (p->xml >= p->xmlend) |
163 | return; |
164 | } |
165 | /* CDATA are at least 9 + 3 characters long : <![CDATA[ ]]> */ |
166 | if((p->xmlend >= (p->xml + (9 + 3))) && (memcmp(p->xml, "<![CDATA[" , 9) == 0)) |
167 | { |
168 | /* CDATA handling */ |
169 | p->xml += 9; |
170 | data = p->xml; |
171 | i = 0; |
172 | while(memcmp(p->xml, "]]>" , 3) != 0) |
173 | { |
174 | i++; p->xml++; |
175 | if ((p->xml + 3) >= p->xmlend) |
176 | return; |
177 | } |
178 | if(i>0 && p->datafunc) |
179 | p->datafunc(p->data, data, i); |
180 | while(*p->xml!='<') |
181 | { |
182 | p->xml++; |
183 | if (p->xml >= p->xmlend) |
184 | return; |
185 | } |
186 | } |
187 | else |
188 | { |
189 | while(*p->xml!='<') |
190 | { |
191 | i++; p->xml++; |
192 | if ((p->xml + 1) >= p->xmlend) |
193 | return; |
194 | } |
195 | if(i>0 && p->datafunc && *(p->xml + 1) == '/') |
196 | p->datafunc(p->data, data, i); |
197 | } |
198 | } |
199 | } |
200 | else if(*p->xml == '/') |
201 | { |
202 | i = 0; elementname = ++p->xml; |
203 | if (p->xml >= p->xmlend) |
204 | return; |
205 | while((*p->xml != '>')) |
206 | { |
207 | i++; p->xml++; |
208 | if (p->xml >= p->xmlend) |
209 | return; |
210 | } |
211 | if(p->endeltfunc) |
212 | p->endeltfunc(p->data, elementname, i); |
213 | p->xml++; |
214 | } |
215 | } |
216 | else |
217 | { |
218 | p->xml++; |
219 | } |
220 | } |
221 | } |
222 | |
223 | /* the parser must be initialized before calling this function */ |
224 | void parsexml(struct xmlparser * parser) |
225 | { |
226 | parser->xml = parser->xmlstart; |
227 | parser->xmlend = parser->xmlstart + parser->xmlsize; |
228 | parseelt(parser); |
229 | } |
230 | |
231 | |
232 | |