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