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