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_v3.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 
36 /* metalink state <metalink> */
metalink_state_start_fun_v3(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char ** attrs)37 void metalink_state_start_fun_v3(metalink_pstm_t* stm,
38 				 const char* name, const char* ns_uri,
39 				 const char** attrs)
40 {
41   if(strcmp("tags", name) == 0) {
42     metalink_pstm_enter_tags_state(stm);
43   }else if(strcmp("identity", name) == 0) {
44     metalink_pstm_enter_identity_state(stm);
45   }else if(strcmp("files", name) == 0) {
46     metalink_pstm_enter_files_state(stm);
47   } else {
48     metalink_pstm_enter_skip_state(stm);
49   }
50 }
51 
metalink_state_end_fun_v3(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char * characters)52 void metalink_state_end_fun_v3(metalink_pstm_t* stm,
53 			       const char* name, const char* ns_uri,
54 			       const char* characters)
55 {
56   metalink_pstm_enter_fin_state(stm);
57 }
58 
59 /* identity state <identity> */
identity_state_start_fun_v3(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char ** attrs)60 void identity_state_start_fun_v3(metalink_pstm_t* stm,
61 				 const char* name, const char* ns_uri,
62 				 const char** attrs)
63 {
64   metalink_pstm_enter_skip_state(stm);
65 }
66 
identity_state_end_fun_v3(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char * characters)67 void identity_state_end_fun_v3(metalink_pstm_t* stm,
68 			       const char* name, const char* ns_uri,
69 			       const char* characters)
70 {
71   metalink_error_t r;
72   r = metalink_pctrl_set_identity(stm->ctrl, characters);
73   if(r == 0) {
74     metalink_pstm_enter_metalink_state(stm);
75   } else {
76     error_handler(stm, r);
77   }
78 }
79 
80 /* tags state <tags> */
tags_state_start_fun_v3(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char ** attrs)81 void tags_state_start_fun_v3(metalink_pstm_t* stm,
82 			const char* name, const char* ns_uri,
83 			const char** attrs)
84 {
85   metalink_pstm_enter_skip_state(stm);
86 }
87 
tags_state_end_fun_v3(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char * characters)88 void tags_state_end_fun_v3(metalink_pstm_t* stm,
89 			   const char* name, const char* ns_uri,
90 			   const char* characters)
91 {
92   metalink_error_t r;
93   r = metalink_pctrl_set_tags(stm->ctrl, characters);
94   if(r == 0) {
95     metalink_pstm_enter_metalink_state(stm);
96   } else {
97     error_handler(stm, r);
98   }
99 }
100 
101 /* files state <files> */
files_state_start_fun_v3(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char ** attrs)102 void files_state_start_fun_v3(metalink_pstm_t* stm,
103 			      const char* name, const char* ns_uri,
104 			      const char** attrs)
105 {
106   metalink_error_t r;
107   if(strcmp("file", name) == 0) {
108     const char* fname;
109     metalink_file_t* file;
110 
111     fname = get_attribute_value(attrs, "name");
112     if(!metalink_check_safe_path(fname)) {
113       /* name is required attribute. If name is NULL or it is not
114          safe, skip this entry. */
115       metalink_pstm_enter_skip_state(stm);
116       return;
117     }
118 
119     file = metalink_pctrl_new_file_transaction(stm->ctrl);
120     if(!file) {
121       error_handler(stm, METALINK_ERR_BAD_ALLOC);
122       return;
123     }
124     r = metalink_pctrl_file_set_name(stm->ctrl, fname);
125     if(r != 0) {
126       error_handler(stm, r);
127       return;
128     }
129     metalink_pstm_enter_file_state(stm);
130   } else {
131     metalink_pstm_enter_skip_state(stm);
132   }
133 }
134 
files_state_end_fun_v3(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char * characters)135 void files_state_end_fun_v3(metalink_pstm_t* stm,
136 			    const char* name, const char* ns_uri,
137 			    const char* characters)
138 {
139   metalink_error_t r;
140   r = metalink_pctrl_metalink_accumulate_files(stm->ctrl);
141   if(r == 0) {
142     metalink_pstm_enter_metalink_state(stm);
143   } else {
144     error_handler(stm, r);
145   }
146 }
147 
148 /* file state <file> */
file_state_start_fun_v3(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char ** attrs)149 void file_state_start_fun_v3(metalink_pstm_t* stm,
150 			     const char* name, const char* ns_uri,
151 			     const char** attrs)
152 {
153   if(strcmp("size", name) == 0) {
154     metalink_pstm_enter_size_state(stm);
155   } else if(strcmp("version", name) == 0) {
156     metalink_pstm_enter_version_state(stm);
157   } else if(strcmp("language", name) == 0) {
158     metalink_pstm_enter_language_state(stm);
159   } else if(strcmp("os", name) == 0) {
160     metalink_pstm_enter_os_state(stm);
161   } else if(strcmp("verification", name) == 0) {
162     metalink_pstm_enter_verification_state(stm);
163   } else if(strcmp("resources", name) == 0) {
164     const char* value;
165     long int maxconnections = 0;
166 
167     value = get_attribute_value(attrs, "maxconnections");
168     if(value) {
169       errno = 0;
170       maxconnections = strtol(value, 0, 10);
171       if(errno == ERANGE  || maxconnections < 0 || maxconnections > INT_MAX) {
172 	/* error, maxconnection is not positive integer. */
173 	maxconnections = 0;
174       }
175     }
176     metalink_pctrl_file_set_maxconnections(stm->ctrl, maxconnections);
177 
178     metalink_pstm_enter_resources_state(stm);
179   } else {
180     metalink_pstm_enter_skip_state(stm);
181   }
182 }
183 
file_state_end_fun_v3(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char * characters)184 void file_state_end_fun_v3(metalink_pstm_t* stm,
185 			   const char* name, const char* ns_uri,
186 			   const char* characters)
187 {
188   metalink_error_t r;
189   r = metalink_pctrl_commit_file_transaction(stm->ctrl);
190   if(r != 0) {
191     error_handler(stm, r);
192     return;
193   }
194   metalink_pstm_enter_files_state(stm);
195 }
196 
197 /* resources state <resources> */
resources_state_start_fun_v3(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char ** attrs)198 void resources_state_start_fun_v3(metalink_pstm_t* stm,
199 				  const char* name, const char* ns_uri,
200 				  const char** attrs)
201 {
202   metalink_error_t r;
203   if(strcmp("url", name) == 0) {
204     const char* type;
205     const char* location;
206     const char* value;
207     long int preference = 0;
208     long int maxconnections = 0;
209     metalink_resource_t* resource;
210 
211     resource = metalink_pctrl_new_resource_transaction(stm->ctrl);
212     if(!resource) {
213       error_handler(stm, METALINK_ERR_BAD_ALLOC);
214       return;
215     }
216 
217     type = get_attribute_value(attrs, "type");
218     if(!type) {
219       /* type attribute is required, but not found. Skip current url tag. */
220       metalink_pstm_enter_skip_state(stm);
221       return;
222     }
223     r = metalink_pctrl_resource_set_type(stm->ctrl, type);
224     if(r != 0) {
225       error_handler(stm, r);
226       return;
227     }
228 
229     location = get_attribute_value(attrs, "location");
230     if(location) {
231       r = metalink_pctrl_resource_set_location(stm->ctrl, location);
232       if(r != 0) {
233 	error_handler(stm, r);
234 	return;
235       }
236     }
237 
238     value = get_attribute_value(attrs, "preference");
239     if(value) {
240       errno = 0;
241       preference = strtol(value, 0, 10);
242       if(errno == ERANGE || preference < 0 || preference > INT_MAX) {
243 	/* error, preference is not positive integer. */
244 	preference = 0;
245       }
246     }
247     metalink_pctrl_resource_set_preference(stm->ctrl, preference);
248 
249     value = get_attribute_value(attrs, "maxconnections");
250     if(value) {
251       errno = 0;
252       maxconnections = strtol(value, 0, 10);
253       if(errno == ERANGE || maxconnections < 0 || maxconnections > INT_MAX) {
254 	/* error, maxconnections is not positive integer. */
255 	maxconnections = 0;
256       }
257     }
258     metalink_pctrl_resource_set_maxconnections(stm->ctrl, maxconnections);
259 
260     metalink_pstm_enter_url_state(stm);
261   } else {
262     metalink_pstm_enter_skip_state(stm);
263   }
264 
265 }
266 
resources_state_end_fun_v3(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char * characters)267 void resources_state_end_fun_v3(metalink_pstm_t* stm,
268 				const char* name, const char* ns_uri,
269 				const char* characters)
270 {
271   metalink_pstm_enter_file_state(stm);
272 }
273 
274 /* verification state <verification> */
verification_state_start_fun_v3(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char ** attrs)275 void verification_state_start_fun_v3(metalink_pstm_t* stm,
276 				  const char* name, const char* ns_uri,
277 				  const char** attrs)
278 {
279   metalink_error_t r;
280   if(strcmp("hash", name) == 0) {
281     const char* type;
282     metalink_checksum_t* checksum;
283 
284     type = get_attribute_value(attrs, "type");
285     if(!type) {
286       /* type is required attribute, if not specified, then skip this tag */
287       metalink_pstm_enter_skip_state(stm);
288       return;
289     }
290     checksum = metalink_pctrl_new_checksum_transaction(stm->ctrl);
291     if(!checksum) {
292       error_handler(stm, METALINK_ERR_BAD_ALLOC);
293       return;
294     }
295     r = metalink_checksum_set_type(checksum, type);
296     if(r != 0) {
297       error_handler(stm, METALINK_ERR_BAD_ALLOC);
298       return;
299     }
300     metalink_pstm_enter_hash_state(stm);
301   } else if(strcmp("pieces", name) == 0) {
302     const char* type;
303     const char* value;
304     long int length;
305     metalink_chunk_checksum_t* chunk_checksum;
306 
307     type = get_attribute_value(attrs, "type");
308     if(!type) {
309       /* type is required attribute, so if not specified, then skip this tag. */
310       metalink_pstm_enter_skip_state(stm);
311       return;
312     }
313 
314     value = get_attribute_value(attrs, "length");
315     if(value) {
316       errno = 0;
317       length = strtol(value, 0, 10);
318       if(errno == ERANGE || length < 0 || length > INT_MAX) {
319 	/* error, length is not positive integer. */
320 	/* length is required attribute, so if not specified, then skip this tag*/
321 	metalink_pstm_enter_skip_state(stm);
322 	return;
323       }
324     } else {
325       /* length is required attribute, so if not specified, then skip this tag*/
326       metalink_pstm_enter_skip_state(stm);
327       return;
328     }
329 
330     chunk_checksum = metalink_pctrl_new_chunk_checksum_transaction(stm->ctrl);
331     if(!chunk_checksum) {
332       error_handler(stm, METALINK_ERR_BAD_ALLOC);
333       return;
334     }
335     r = metalink_chunk_checksum_set_type(chunk_checksum, type);
336     if(r != 0) {
337       error_handler(stm, METALINK_ERR_BAD_ALLOC);
338       return;
339     }
340     metalink_chunk_checksum_set_length(chunk_checksum, length);
341 
342     metalink_pstm_enter_pieces_state(stm);
343   } else {
344     metalink_pstm_enter_skip_state(stm);
345   }
346 }
347 
verification_state_end_fun_v3(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char * characters)348 void verification_state_end_fun_v3(metalink_pstm_t* stm,
349 				   const char* name, const char* ns_uri,
350 				   const char* characters)
351 {
352   metalink_pstm_enter_file_state(stm);
353 }
354 
355 /* pieces state <pieces> */
pieces_state_start_fun_v3(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char ** attrs)356 void pieces_state_start_fun_v3(metalink_pstm_t* stm,
357 			       const char* name, const char* ns_uri,
358 			       const char** attrs)
359 {
360   if(strcmp("hash", name) == 0) {
361     const char* value;
362     long int piece;
363     metalink_piece_hash_t* piece_hash;
364 
365     value = get_attribute_value(attrs, "piece");
366     if(value) {
367       errno = 0;
368       piece = strtol(value, 0, 10);
369       if(errno == ERANGE || piece < 0 || piece > INT_MAX) {
370 	/* error, piece is not positive integer. */
371 	/* piece is required attribute, but it is missing. Skip this tag. */
372 	metalink_pstm_enter_skip_state(stm);
373 	return;
374       }
375     } else {
376       /* value is required attribute, but it is missing. Skip this tag. */
377       metalink_pstm_enter_skip_state(stm);
378       return;
379     }
380 
381     piece_hash = metalink_pctrl_new_piece_hash_transaction(stm->ctrl);
382     if(!piece_hash) {
383       error_handler(stm, METALINK_ERR_BAD_ALLOC);
384       return;
385     }
386     metalink_pctrl_piece_hash_set_piece(stm->ctrl, piece);
387 
388     metalink_pstm_enter_piece_hash_state(stm);
389   } else {
390     metalink_pstm_enter_skip_state(stm);
391   }
392 }
393 
pieces_state_end_fun_v3(metalink_pstm_t * stm,const char * name,const char * ns_uri,const char * characters)394 void pieces_state_end_fun_v3(metalink_pstm_t* stm,
395 			     const char* name, const char* ns_uri,
396 			     const char* characters)
397 {
398   metalink_error_t r;
399   r = metalink_pctrl_commit_chunk_checksum_transaction(stm->ctrl);
400   if(r != 0) {
401     error_handler(stm, r);
402     return;
403   }
404 
405   metalink_pstm_enter_verification_state(stm);
406 }
407 
408