1 /* <!-- copyright */
2 /*
3  * libmetalink
4  *
5  * Copyright (c) 2008 Tatsuhiro Tsujikawa
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23  * THE SOFTWARE.
24  */
25 /* copyright --> */
26 #include "metalink_pstate.h"
27 
28 #include <string.h>
29 #include <stdlib.h>
30 #include <errno.h>
31 #include <limits.h>
32 
33 #include "metalink_pstm.h"
34 #include "metalink_helper.h"
35 
new_metalink_pstate(void)36 metalink_pstate_t* new_metalink_pstate(void)
37 {
38   metalink_pstate_t* state;
39   state = malloc(sizeof(metalink_pstate_t));
40   if(state) {
41     memset(state, 0, sizeof(metalink_pstate_t));
42   }
43   return state;
44 }
45 
delete_metalink_pstate(metalink_pstate_t * state)46 void delete_metalink_pstate(metalink_pstate_t* state)
47 {
48   free(state);
49 }
50 
get_attribute_value(const char ** attrs,const char * name)51 const char* get_attribute_value(const char** attrs, const char* name)
52 {
53   const char** p;
54   const char* cname;
55 
56   if(attrs == NULL) {
57     return NULL;
58   }
59 
60   p = attrs;
61   while(*p) {
62     cname = *p++;
63     if(*p == 0) {
64       break;
65     }
66     if(strcmp(cname, name) == 0) {
67       break;
68     } else {
69       ++p;
70     }
71   }
72   return *p;
73 }
74 
75 /**
76  * set error code to metalink_pctrl and transit to null state, where no further
77  * state transition takes place.
78  */
error_handler(metalink_pstm_t * stm,metalink_error_t error)79 void error_handler(metalink_pstm_t* stm, metalink_error_t error)
80 {
81   metalink_pctrl_set_error(stm->ctrl, error);
82   metalink_pstm_enter_null_state(stm);
83 }
84 
85 
86 /* null handler doing nothing */
null_state_start_fun(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char ** attrs)87 void null_state_start_fun(metalink_pstm_t* stm,
88 			  const char* name,
89 			  const char* ns_uri,
90 			  const char** attrs) {}
91 
null_state_end_fun(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char * characters)92 void null_state_end_fun(metalink_pstm_t* stm,
93 			const char* name,
94 			const char* ns_uri,
95 			const char* characters) {}
96 
97 /* initial state */
initial_state_start_fun(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char ** attrs)98 void initial_state_start_fun(metalink_pstm_t* stm,
99 			     const char* name, const char* ns_uri,
100 			     const char** attrs)
101 {
102   if(strcmp("metalink", name) == 0) {
103     if (strcmp(METALINK_V3_NS_URI, ns_uri) == 0) {
104       const char* type;
105       const char* origin;
106       metalink_pctrl_set_version(stm->ctrl, METALINK_VERSION_3);
107 
108       type = get_attribute_value(attrs, "type");
109       if(type && strcmp("dynamic", type) == 0) {
110         metalink_pctrl_set_origin_dynamic(stm->ctrl, 1);
111       }
112       origin = get_attribute_value(attrs, "origin");
113       if(origin) {
114         metalink_pctrl_set_origin(stm->ctrl, origin);
115       }
116 
117       metalink_pstm_enter_metalink_state(stm);
118     }
119     else if (strcmp(METALINK_V4_NS_URI, ns_uri) == 0) {
120       metalink_pctrl_set_version(stm->ctrl, METALINK_VERSION_4);
121       metalink_pstm_enter_metalink_state_v4(stm);
122     } else {
123       metalink_pctrl_set_version(stm->ctrl, METALINK_VERSION_UNKNOWN);
124       metalink_pstm_enter_skip_state(stm);
125     }
126   } else {
127     metalink_pstm_enter_skip_state(stm);
128   }
129 }
130 
initial_state_end_fun(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char * characters)131 void initial_state_end_fun(metalink_pstm_t* stm,
132 			   const char* name, const char* ns_uri,
133 			   const char* characters) {}
134 
135 /* skip state */
skip_state_start_fun(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char ** attrs)136 void skip_state_start_fun(metalink_pstm_t* stm,
137 			  const char* name, const char* ns_uri,
138 			  const char** attrs)
139 {
140   ++stm->state->skip_depth;
141 }
142 
skip_state_end_fun(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char * characters)143 void skip_state_end_fun(metalink_pstm_t* stm,
144 			const char* name, const char* ns_uri,
145 			const char* characters)
146 {
147   if(--stm->state->skip_depth == 0) {
148     metalink_pstm_exit_skip_state(stm);
149   }
150 }
151 
152 /* size state <size> */
size_state_start_fun(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char ** attrs)153 void size_state_start_fun(metalink_pstm_t* stm,
154 			  const char* name, const char* ns_uri,
155 			  const char** attrs)
156 {
157   metalink_pstm_enter_skip_state(stm);
158 }
159 
size_state_end_fun(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char * characters)160 void size_state_end_fun(metalink_pstm_t* stm,
161 		        const char* name, const char* ns_uri,
162 		        const char* characters)
163 {
164   long long int size = 0;
165 
166   /* TODO evaluate endptr(2nd argument) */
167   errno = 0;
168   size = strtoll(characters, 0, 10);
169   if(errno == ERANGE || size < 0) {
170     /* overflow or parse error or negative integer detected. */
171     /* current Metalink specification does not require size. */
172     size = 0;
173   }
174   metalink_pctrl_file_set_size(stm->ctrl, size);
175 
176   if(strcmp(METALINK_V3_NS_URI, ns_uri) == 0) {
177     metalink_pstm_enter_file_state(stm);
178   } else if(strcmp(METALINK_V4_NS_URI, ns_uri) == 0) {
179     metalink_pstm_enter_file_state_v4(stm);
180   } else {
181     error_handler(stm, METALINK_ERR_NAMESPACE_ERROR);
182   }
183 }
184 
185 /* version state <version> */
version_state_start_fun(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char ** attrs)186 void version_state_start_fun(metalink_pstm_t* stm,
187 			     const char* name, const char* ns_uri,
188 			     const char** attrs)
189 {
190   metalink_pstm_enter_skip_state(stm);
191 }
192 
version_state_end_fun(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char * characters)193 void version_state_end_fun(metalink_pstm_t* stm,
194 			   const char* name, const char* ns_uri,
195 			   const char* characters)
196 {
197   metalink_error_t r;
198   r = metalink_pctrl_file_set_version(stm->ctrl, characters);
199   if(r == 0) {
200     metalink_pstm_enter_file_state(stm);
201   } else {
202     error_handler(stm, r);
203   }
204 
205   if(strcmp(METALINK_V3_NS_URI, ns_uri) == 0) {
206     metalink_pstm_enter_file_state(stm);
207   } else if(strcmp(METALINK_V4_NS_URI, ns_uri) == 0) {
208     metalink_pstm_enter_file_state_v4(stm);
209   } else {
210     error_handler(stm, METALINK_ERR_NAMESPACE_ERROR);
211   }
212 }
213 
214 /* language state <language> */
language_state_start_fun(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char ** attrs)215 void language_state_start_fun(metalink_pstm_t* stm,
216 			      const char* name, const char* ns_uri,
217 			      const char** attrs)
218 {
219   metalink_pstm_enter_skip_state(stm);
220 }
221 
language_state_end_fun(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char * characters)222 void language_state_end_fun(metalink_pstm_t* stm,
223 			    const char* name, const char* ns_uri,
224 			    const char* characters)
225 {
226   metalink_error_t r;
227   r = metalink_pctrl_add_language(stm->ctrl, characters);
228   if(r != 0) {
229     error_handler(stm, r);
230     return;
231   }
232 
233   if(strcmp(METALINK_V3_NS_URI, ns_uri) == 0) {
234     metalink_pstm_enter_file_state(stm);
235   } else if(strcmp(METALINK_V4_NS_URI, ns_uri) == 0) {
236     metalink_pstm_enter_file_state_v4(stm);
237   } else {
238     error_handler(stm, METALINK_ERR_NAMESPACE_ERROR);
239   }
240 }
241 
242 /* os state <os> */
os_state_start_fun(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char ** attrs)243 void os_state_start_fun(metalink_pstm_t* stm,
244 		        const char* name, const char* ns_uri,
245 		        const char** attrs)
246 {
247   metalink_pstm_enter_skip_state(stm);
248 }
249 
os_state_end_fun(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char * characters)250 void os_state_end_fun(metalink_pstm_t* stm,
251 		      const char* name, const char* ns_uri,
252 		      const char* characters)
253 {
254   metalink_error_t r;
255   r = metalink_pctrl_add_os(stm->ctrl, characters);
256   if(r != 0) {
257     error_handler(stm, r);
258     return;
259   }
260 
261   if(strcmp(METALINK_V3_NS_URI, ns_uri) == 0) {
262     metalink_pstm_enter_file_state(stm);
263   } else if(strcmp(METALINK_V4_NS_URI, ns_uri) == 0) {
264     metalink_pstm_enter_file_state_v4(stm);
265   } else {
266     error_handler(stm, METALINK_ERR_NAMESPACE_ERROR);
267   }
268 }
269 
270 /* url state <url> */
url_state_start_fun(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char ** attrs)271 void url_state_start_fun(metalink_pstm_t* stm,
272 			 const char* name, const char* ns_uri,
273 			 const char** attrs)
274 {
275   metalink_pstm_enter_skip_state(stm);
276 }
277 
url_state_end_fun(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char * characters)278 void url_state_end_fun(metalink_pstm_t* stm,
279 		       const char* name, const char* ns_uri,
280 		       const char* characters)
281 {
282   metalink_error_t r;
283   r = metalink_pctrl_resource_set_url(stm->ctrl, characters);
284   if(r != 0) {
285     /* TODO clear intermidiate resource transaction. */
286     error_handler(stm, r);
287     return;
288   }
289   r = metalink_pctrl_commit_resource_transaction(stm->ctrl);
290   if(r != 0) {
291     error_handler(stm, r);
292     return;
293   }
294 
295   if(strcmp(METALINK_V3_NS_URI, ns_uri) == 0) {
296     metalink_pstm_enter_resources_state(stm);
297   } else if(strcmp(METALINK_V4_NS_URI, ns_uri) == 0) {
298     metalink_pstm_enter_file_state_v4(stm);
299   } else {
300     error_handler(stm, METALINK_ERR_NAMESPACE_ERROR);
301   }
302 }
303 
304 /* hash state <hash> */
hash_state_start_fun(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char ** attrs)305 void hash_state_start_fun(metalink_pstm_t* stm,
306 			  const char* name, const char* ns_uri,
307 			  const char** attrs)
308 {
309   metalink_pstm_enter_skip_state(stm);
310 }
311 
hash_state_end_fun(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char * characters)312 void hash_state_end_fun(metalink_pstm_t* stm,
313 		        const char* name, const char* ns_uri,
314 		        const char* characters)
315 {
316   metalink_error_t r;
317   r = metalink_pctrl_checksum_set_hash(stm->ctrl, characters);
318   if(r != 0) {
319     error_handler(stm, r);
320     return;
321   }
322   r = metalink_pctrl_commit_checksum_transaction(stm->ctrl);
323   if(r != 0) {
324     error_handler(stm, r);
325     return;
326   }
327 
328   if(strcmp(METALINK_V3_NS_URI, ns_uri) == 0) {
329     metalink_pstm_enter_verification_state(stm);
330   } else if(strcmp(METALINK_V4_NS_URI, ns_uri) == 0) {
331     metalink_pstm_enter_file_state_v4(stm);
332   } else {
333     error_handler(stm, METALINK_ERR_NAMESPACE_ERROR);
334   }
335 }
336 
337 /* piece hash state <hash> inside of <pieces> */
piece_hash_state_start_fun(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char ** attrs)338 void piece_hash_state_start_fun(metalink_pstm_t* stm,
339 			        const char* name, const char* ns_uri,
340 			        const char** attrs)
341 {
342   metalink_pstm_enter_skip_state(stm);
343 }
344 
piece_hash_state_end_fun(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char * characters)345 void piece_hash_state_end_fun(metalink_pstm_t* stm,
346 			      const char* name, const char* ns_uri,
347 			      const char* characters)
348 {
349   metalink_error_t r;
350   metalink_pctrl_piece_hash_set_hash(stm->ctrl, characters);
351   r = metalink_pctrl_commit_piece_hash_transaction(stm->ctrl);
352   if(r != 0) {
353     error_handler(stm, r);
354     return;
355   }
356 
357   if(strcmp(METALINK_V3_NS_URI, ns_uri) == 0) {
358     metalink_pstm_enter_pieces_state(stm);
359   } else if(strcmp(METALINK_V4_NS_URI, ns_uri) == 0) {
360     metalink_pstm_enter_pieces_state_v4(stm);
361   } else {
362     error_handler(stm, METALINK_ERR_NAMESPACE_ERROR);
363   }
364 }
365 
366 /* fin state */
fin_state_start_fun(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char ** attrs)367 void fin_state_start_fun(metalink_pstm_t* stm,
368 			 const char* name, const char* ns_uri,
369 			 const char** attrs) {}
370 
fin_state_end_fun(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char * characters)371 void fin_state_end_fun(metalink_pstm_t* stm,
372 		       const char* name, const char* ns_uri,
373 		       const char* characters) {}
374 
375