Parent Directory | Revision Log
Asynchronous network io
1 | /* |
2 | * Copyright (C) 2008 Till Harbaum <till@harbaum.org>. |
3 | * |
4 | * This file is part of OSM2Go. |
5 | * |
6 | * OSM2Go is free software: you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation, either version 3 of the License, or |
9 | * (at your option) any later version. |
10 | * |
11 | * OSM2Go is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU General Public License |
17 | * along with OSM2Go. If not, see <http://www.gnu.org/licenses/>. |
18 | */ |
19 | |
20 | /* |
21 | * diff.c - generate and restore changes on the current data set |
22 | */ |
23 | |
24 | #include "appdata.h" |
25 | |
26 | #include <libxml/parser.h> |
27 | #include <libxml/tree.h> |
28 | |
29 | #if !defined(LIBXML_TREE_ENABLED) || !defined(LIBXML_OUTPUT_ENABLED) |
30 | #error "libxml doesn't support required tree or output" |
31 | #endif |
32 | |
33 | static void diff_save_tags(tag_t *tag, xmlNodePtr node) { |
34 | while(tag) { |
35 | xmlNodePtr tag_node = xmlNewChild(node, NULL, |
36 | BAD_CAST "tag", NULL); |
37 | xmlNewProp(tag_node, BAD_CAST "k", BAD_CAST tag->key); |
38 | xmlNewProp(tag_node, BAD_CAST "v", BAD_CAST tag->value); |
39 | tag = tag->next; |
40 | } |
41 | } |
42 | |
43 | static void diff_save_state_n_id(int flags, xmlNodePtr node, item_id_t id) { |
44 | if(flags & OSM_FLAG_DELETED) |
45 | xmlNewProp(node, BAD_CAST "state", BAD_CAST "deleted"); |
46 | else if(flags & OSM_FLAG_NEW) |
47 | xmlNewProp(node, BAD_CAST "state", BAD_CAST "new"); |
48 | |
49 | /* all items need an id */ |
50 | char *id_str = g_strdup_printf("%ld", id); |
51 | xmlNewProp(node, BAD_CAST "id", BAD_CAST id_str); |
52 | g_free(id_str); |
53 | } |
54 | |
55 | static void diff_save_nodes(node_t *node, xmlNodePtr root_node) { |
56 | /* store all modfied nodes */ |
57 | while(node) { |
58 | if(node->flags) { |
59 | xmlNodePtr node_node = xmlNewChild(root_node, NULL, |
60 | BAD_CAST "node", NULL); |
61 | |
62 | diff_save_state_n_id(node->flags, node_node, node->id); |
63 | |
64 | if(!(node->flags & OSM_FLAG_DELETED)) { |
65 | char str[32]; |
66 | |
67 | /* additional info is only required if the node hasn't been deleted */ |
68 | g_ascii_dtostr(str, sizeof(str), node->pos.lat); |
69 | xmlNewProp(node_node, BAD_CAST "lat", BAD_CAST str); |
70 | g_ascii_dtostr(str, sizeof(str), node->pos.lon); |
71 | xmlNewProp(node_node, BAD_CAST "lon", BAD_CAST str); |
72 | snprintf(str, sizeof(str), "%ld", node->time); |
73 | xmlNewProp(node_node, BAD_CAST "time", BAD_CAST str); |
74 | |
75 | diff_save_tags(node->tag, node_node); |
76 | } |
77 | } |
78 | node = node->next; |
79 | } |
80 | } |
81 | |
82 | static void diff_save_ways(way_t *way, xmlNodePtr root_node) { |
83 | |
84 | /* store all modfied ways */ |
85 | while(way) { |
86 | if(way->flags) { |
87 | xmlNodePtr node_way = xmlNewChild(root_node, NULL, |
88 | BAD_CAST "way", NULL); |
89 | |
90 | diff_save_state_n_id(way->flags, node_way, way->id); |
91 | |
92 | if(way->flags & OSM_FLAG_HIDDEN) |
93 | xmlNewProp(node_way, BAD_CAST "hidden", BAD_CAST "true"); |
94 | |
95 | /* additional info is only required if the way hasn't been deleted */ |
96 | /* and of the dirty or new flags are set. (otherwise e.g. only */ |
97 | /* the hidden flag may be set) */ |
98 | if((!(way->flags & OSM_FLAG_DELETED)) && |
99 | (way->flags & (OSM_FLAG_DIRTY | OSM_FLAG_NEW))) { |
100 | node_chain_t *node_chain = way->node_chain; |
101 | while(node_chain) { |
102 | xmlNodePtr node_node = xmlNewChild(node_way, NULL, |
103 | BAD_CAST "nd", NULL); |
104 | char *id = g_strdup_printf("%ld", node_chain->node->id); |
105 | xmlNewProp(node_node, BAD_CAST "ref", BAD_CAST id); |
106 | g_free(id); |
107 | node_chain = node_chain->next; |
108 | } |
109 | diff_save_tags(way->tag, node_way); |
110 | } |
111 | } |
112 | way = way->next; |
113 | } |
114 | } |
115 | |
116 | static void diff_save_relations(relation_t *relation, xmlNodePtr root_node) { |
117 | |
118 | /* store all modfied relations */ |
119 | while(relation) { |
120 | if(relation->flags) { |
121 | xmlNodePtr node_rel = xmlNewChild(root_node, NULL, |
122 | BAD_CAST "relation", NULL); |
123 | |
124 | diff_save_state_n_id(relation->flags, node_rel, relation->id); |
125 | |
126 | if(!(relation->flags & OSM_FLAG_DELETED)) { |
127 | /* additional info is only required if the relation */ |
128 | /* hasn't been deleted */ |
129 | member_t *member = relation->member; |
130 | while(member) { |
131 | xmlNodePtr node_member = xmlNewChild(node_rel, NULL, |
132 | BAD_CAST "member", NULL); |
133 | |
134 | char *ref = NULL; |
135 | switch(member->type) { |
136 | case NODE: |
137 | xmlNewProp(node_member, BAD_CAST "type", BAD_CAST "node"); |
138 | ref = g_strdup_printf("%ld", member->node->id); |
139 | break; |
140 | case WAY: |
141 | xmlNewProp(node_member, BAD_CAST "type", BAD_CAST "way"); |
142 | ref = g_strdup_printf("%ld", member->way->id); |
143 | break; |
144 | case RELATION: |
145 | xmlNewProp(node_member, BAD_CAST "type", BAD_CAST "relation"); |
146 | ref = g_strdup_printf("%ld", member->relation->id); |
147 | break; |
148 | |
149 | /* XXX_ID's are used if this is a reference to an item not */ |
150 | /* stored in this xml data set */ |
151 | case NODE_ID: |
152 | xmlNewProp(node_member, BAD_CAST "type", BAD_CAST "node"); |
153 | ref = g_strdup_printf("%ld", member->id); |
154 | break; |
155 | case WAY_ID: |
156 | xmlNewProp(node_member, BAD_CAST "type", BAD_CAST "way"); |
157 | ref = g_strdup_printf("%ld", member->id); |
158 | break; |
159 | case RELATION_ID: |
160 | xmlNewProp(node_member, BAD_CAST "type", BAD_CAST "relation"); |
161 | ref = g_strdup_printf("%ld", member->id); |
162 | break; |
163 | |
164 | default: |
165 | printf("unexpected member type %d\n", member->type); |
166 | break; |
167 | } |
168 | |
169 | g_assert(ref); |
170 | xmlNewProp(node_member, BAD_CAST "ref", BAD_CAST ref); |
171 | g_free(ref); |
172 | |
173 | if(member->role) |
174 | xmlNewProp(node_member, BAD_CAST "role", BAD_CAST member->role); |
175 | |
176 | member = member->next; |
177 | } |
178 | diff_save_tags(relation->tag, node_rel); |
179 | } |
180 | } |
181 | relation = relation->next; |
182 | } |
183 | } |
184 | |
185 | |
186 | /* return true if no diff needs to be saved */ |
187 | gboolean diff_is_clean(osm_t *osm, gboolean honor_hidden_flags) { |
188 | gboolean clean = TRUE; |
189 | |
190 | /* check if a diff is necessary */ |
191 | node_t *node = osm->node; |
192 | while(node && clean) { |
193 | if(node->flags) clean = FALSE; |
194 | node = node->next; |
195 | } |
196 | |
197 | way_t *way = osm->way; |
198 | while(way && clean) { |
199 | if(honor_hidden_flags) { |
200 | if(way->flags) clean = FALSE; |
201 | } else |
202 | if(way->flags & ~OSM_FLAG_HIDDEN) |
203 | clean = FALSE; |
204 | |
205 | way = way->next; |
206 | } |
207 | |
208 | relation_t *relation = osm->relation; |
209 | while(relation && clean) { |
210 | if(relation->flags) clean = FALSE; |
211 | relation = relation->next; |
212 | } |
213 | |
214 | return clean; |
215 | } |
216 | |
217 | void diff_save(project_t *project, osm_t *osm) { |
218 | if(!project || !osm) return; |
219 | |
220 | char *diff_name = |
221 | g_strdup_printf("%s/%s.diff", project->path, project->name); |
222 | |
223 | if(diff_is_clean(osm, TRUE)) { |
224 | printf("data set is clean, removing diff if present\n"); |
225 | g_remove(diff_name); |
226 | g_free(diff_name); |
227 | return; |
228 | } |
229 | |
230 | printf("data set is dirty, generating diff\n"); |
231 | |
232 | LIBXML_TEST_VERSION; |
233 | |
234 | xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0"); |
235 | xmlNodePtr root_node = xmlNewNode(NULL, BAD_CAST "diff"); |
236 | xmlNewProp(root_node, BAD_CAST "name", BAD_CAST project->name); |
237 | xmlDocSetRootElement(doc, root_node); |
238 | |
239 | diff_save_nodes(osm->node, root_node); |
240 | diff_save_ways(osm->way, root_node); |
241 | diff_save_relations(osm->relation, root_node); |
242 | |
243 | xmlSaveFormatFileEnc(diff_name, doc, "UTF-8", 1); |
244 | xmlFreeDoc(doc); |
245 | xmlCleanupParser(); |
246 | |
247 | g_free(diff_name); |
248 | } |
249 | |
250 | static int xml_get_prop_int(xmlNode *node, char *prop, int def) { |
251 | char *str = (char*)xmlGetProp(node, BAD_CAST prop); |
252 | int value = def; |
253 | |
254 | if(str) { |
255 | value = strtoul(str, NULL, 10); |
256 | xmlFree(str); |
257 | } |
258 | |
259 | return value; |
260 | } |
261 | |
262 | static int xml_get_prop_state(xmlNode *node, char *prop) { |
263 | char *str = (char*)xmlGetProp(node, BAD_CAST prop); |
264 | |
265 | if(str) { |
266 | if(strcasecmp(str, "new") == 0) { |
267 | xmlFree(str); |
268 | return OSM_FLAG_NEW; |
269 | } |
270 | |
271 | if(strcasecmp(str, "deleted") == 0) { |
272 | xmlFree(str); |
273 | return OSM_FLAG_DELETED; |
274 | } |
275 | |
276 | g_assert(0); |
277 | } |
278 | |
279 | return OSM_FLAG_DIRTY; |
280 | } |
281 | |
282 | static pos_t *xml_get_prop_pos(xmlNode *node) { |
283 | char *str_lat = (char*)xmlGetProp(node, BAD_CAST "lat"); |
284 | char *str_lon = (char*)xmlGetProp(node, BAD_CAST "lon"); |
285 | |
286 | if(!str_lon || !str_lat) { |
287 | if(!str_lon) xmlFree(str_lon); |
288 | if(!str_lat) xmlFree(str_lat); |
289 | return NULL; |
290 | } |
291 | |
292 | pos_t *pos = g_new0(pos_t, 1); |
293 | pos->lat = g_ascii_strtod(str_lat, NULL); |
294 | pos->lon = g_ascii_strtod(str_lon, NULL); |
295 | |
296 | xmlFree(str_lon); |
297 | xmlFree(str_lat); |
298 | |
299 | return pos; |
300 | } |
301 | |
302 | static tag_t *xml_scan_tags(xmlDoc *doc, xmlNodePtr node, osm_t *osm) { |
303 | /* scan for tags */ |
304 | tag_t *first_tag = NULL; |
305 | tag_t **tag = &first_tag; |
306 | |
307 | while(node) { |
308 | if(node->type == XML_ELEMENT_NODE) { |
309 | if(strcasecmp((char*)node->name, "tag") == 0) { |
310 | /* attach tag to node/way */ |
311 | *tag = osm_parse_osm_tag(osm, doc, node); |
312 | if(*tag) tag = &((*tag)->next); |
313 | } |
314 | } |
315 | node = node->next; |
316 | } |
317 | return first_tag; |
318 | } |
319 | |
320 | void diff_restore_node(xmlDoc *doc, xmlNodePtr node_node, osm_t *osm) { |
321 | printf("Restoring node\n"); |
322 | |
323 | /* read properties */ |
324 | item_id_t id = xml_get_prop_int(node_node, "id", ID_ILLEGAL); |
325 | if(id == ID_ILLEGAL) { |
326 | printf(" Node entry missing id\n"); |
327 | return; |
328 | } |
329 | |
330 | int state = xml_get_prop_state(node_node, "state"); |
331 | pos_t *pos = xml_get_prop_pos(node_node); |
332 | |
333 | if(!(state & OSM_FLAG_DELETED) && !pos) { |
334 | printf(" Node not deleted, but no valid position\n"); |
335 | return; |
336 | } |
337 | |
338 | /* evaluate properties */ |
339 | node_t *node = NULL; |
340 | |
341 | switch(state) { |
342 | case OSM_FLAG_NEW: |
343 | printf(" Restoring NEW node\n"); |
344 | |
345 | node = g_new0(node_t, 1); |
346 | node->visible = TRUE; |
347 | node->flags = OSM_FLAG_NEW; |
348 | node->time = xml_get_prop_int(node_node, "time", 0); |
349 | if(!node->time) node->time = time(NULL); |
350 | |
351 | /* attach to end of node list */ |
352 | node_t **lnode = &osm->node; |
353 | while(*lnode) lnode = &(*lnode)->next; |
354 | *lnode = node; |
355 | break; |
356 | |
357 | case OSM_FLAG_DELETED: |
358 | printf(" Restoring DELETE flag\n"); |
359 | |
360 | if((node = osm_get_node_by_id(osm, id))) |
361 | node->flags |= OSM_FLAG_DELETED; |
362 | else |
363 | printf(" WARNING: no node with that id found\n"); |
364 | break; |
365 | |
366 | case OSM_FLAG_DIRTY: |
367 | printf(" Valid id/position (DIRTY)\n"); |
368 | |
369 | if((node = osm_get_node_by_id(osm, id))) |
370 | node->flags |= OSM_FLAG_DIRTY; |
371 | else |
372 | printf(" WARNING: no node with that id found\n"); |
373 | break; |
374 | |
375 | default: |
376 | printf(" Illegal node entry\n"); |
377 | return; |
378 | break; |
379 | } |
380 | |
381 | if(!node) { |
382 | printf(" no valid node\n"); |
383 | return; |
384 | } |
385 | |
386 | /* update id and position from diff */ |
387 | node->id = id; |
388 | if(pos) { |
389 | node->pos.lat = pos->lat; |
390 | node->pos.lon = pos->lon; |
391 | |
392 | pos2lpos(osm->bounds, &node->pos, &node->lpos); |
393 | |
394 | g_free(pos); |
395 | } |
396 | |
397 | /* node may be an existing node, so remove tags to */ |
398 | /* make space for new ones */ |
399 | if(node->tag) { |
400 | printf(" removing existing tags for diff tags\n"); |
401 | osm_tag_free(node->tag); |
402 | node->tag = NULL; |
403 | } |
404 | |
405 | node->tag = xml_scan_tags(doc, node_node->children, osm); |
406 | } |
407 | |
408 | void diff_restore_way(xmlDoc *doc, xmlNodePtr node_node, osm_t *osm) { |
409 | printf("Restoring way\n"); |
410 | |
411 | item_id_t id = xml_get_prop_int(node_node, "id", ID_ILLEGAL); |
412 | if(id == ID_ILLEGAL) { |
413 | printf(" entry missing id\n"); |
414 | return; |
415 | } |
416 | |
417 | int state = xml_get_prop_state(node_node, "state"); |
418 | |
419 | /* handle hidden flag */ |
420 | gboolean hidden = FALSE; |
421 | char *str = (char*)xmlGetProp(node_node, BAD_CAST "hidden"); |
422 | if(str) { |
423 | if(strcasecmp(str, "true") == 0) |
424 | hidden = TRUE; |
425 | |
426 | xmlFree(str); |
427 | } |
428 | |
429 | |
430 | /* evaluate properties */ |
431 | way_t *way = NULL; |
432 | switch(state) { |
433 | case OSM_FLAG_NEW: |
434 | printf(" Restoring NEW way\n"); |
435 | |
436 | way = g_new0(way_t, 1); |
437 | way->visible = TRUE; |
438 | way->flags = OSM_FLAG_NEW; |
439 | way->time = xml_get_prop_int(node_node, "time", 0); |
440 | if(!way->time) way->time = time(NULL); |
441 | |
442 | /* attach to end of way list */ |
443 | way_t **lway = &osm->way; |
444 | while(*lway) lway = &(*lway)->next; |
445 | *lway = way; |
446 | break; |
447 | |
448 | case OSM_FLAG_DELETED: |
449 | printf(" Restoring DELETE flag\n"); |
450 | |
451 | if((way = osm_get_way_by_id(osm, id))) |
452 | way->flags |= OSM_FLAG_DELETED; |
453 | else |
454 | printf(" WARNING: no way with that id found\n"); |
455 | break; |
456 | |
457 | case OSM_FLAG_DIRTY: |
458 | printf(" Valid id (DIRTY)\n"); |
459 | |
460 | if((way = osm_get_way_by_id(osm, id))) |
461 | way->flags |= OSM_FLAG_DIRTY; |
462 | else |
463 | printf(" WARNING: no way with that id found\n"); |
464 | break; |
465 | |
466 | default: |
467 | printf(" Illegal way entry\n"); |
468 | return; |
469 | } |
470 | |
471 | if(!way) { |
472 | printf(" no valid way\n"); |
473 | return; |
474 | } |
475 | |
476 | /* update id from diff */ |
477 | way->id = id; |
478 | |
479 | /* update node_chain */ |
480 | if(hidden) |
481 | way->flags |= OSM_FLAG_HIDDEN; |
482 | |
483 | gboolean installed_new_nodes = FALSE; |
484 | |
485 | /* scan for nodes */ |
486 | node_chain_t **node_chain = &way->node_chain; |
487 | xmlNode *nd_node = NULL; |
488 | for(nd_node = node_node->children; nd_node; nd_node = nd_node->next) { |
489 | if(nd_node->type == XML_ELEMENT_NODE) { |
490 | if(strcasecmp((char*)nd_node->name, "nd") == 0) { |
491 | |
492 | /* only replace the original nodes if new nodes have actually been */ |
493 | /* found. */ |
494 | if(!installed_new_nodes) { |
495 | /* way may be an existing way, so remove nodes to */ |
496 | /* make space for new ones */ |
497 | if(way->node_chain) { |
498 | printf(" removing existing nodes for diff nodes\n"); |
499 | osm_node_chain_free(way->node_chain); |
500 | way->node_chain = NULL; |
501 | } |
502 | |
503 | installed_new_nodes = TRUE; |
504 | } |
505 | |
506 | /* attach node to node_chain */ |
507 | *node_chain = osm_parse_osm_way_nd(osm, doc, nd_node); |
508 | if(*node_chain) |
509 | node_chain = &((*node_chain)->next); |
510 | } |
511 | } |
512 | } |
513 | |
514 | /* only replace tags if nodes have been found before. if no nodes */ |
515 | /* were found this wasn't a dirty entry but e.g. only the hidden */ |
516 | /* flag had been set */ |
517 | if(installed_new_nodes) { |
518 | |
519 | /* node may be an existing node, so remove tags to */ |
520 | /* make space for new ones */ |
521 | if(way->tag) { |
522 | printf(" removing existing tags for diff tags\n"); |
523 | osm_tag_free(way->tag); |
524 | way->tag = NULL; |
525 | } |
526 | |
527 | way->tag = xml_scan_tags(doc, node_node->children, osm); |
528 | } else { |
529 | printf(" no nodes restored, way isn't dirty!\n"); |
530 | way->flags &= ~OSM_FLAG_DIRTY; |
531 | } |
532 | } |
533 | |
534 | void diff_restore_relation(xmlDoc *doc, xmlNodePtr node_rel, osm_t *osm) { |
535 | printf("Restoring relation\n"); |
536 | |
537 | item_id_t id = xml_get_prop_int(node_rel, "id", ID_ILLEGAL); |
538 | if(id == ID_ILLEGAL) { |
539 | printf(" entry missing id\n"); |
540 | return; |
541 | } |
542 | |
543 | int state = xml_get_prop_state(node_rel, "state"); |
544 | |
545 | /* evaluate properties */ |
546 | relation_t *relation = NULL; |
547 | switch(state) { |
548 | case OSM_FLAG_NEW: |
549 | printf(" Restoring NEW relation\n"); |
550 | |
551 | relation = g_new0(relation_t, 1); |
552 | relation->visible = TRUE; |
553 | relation->flags = OSM_FLAG_NEW; |
554 | relation->time = xml_get_prop_int(node_rel, "time", 0); |
555 | if(!relation->time) relation->time = time(NULL); |
556 | |
557 | /* attach to end of relation list */ |
558 | relation_t **lrelation = &osm->relation; |
559 | while(*lrelation) lrelation = &(*lrelation)->next; |
560 | *lrelation = relation; |
561 | break; |
562 | |
563 | case OSM_FLAG_DELETED: |
564 | printf(" Restoring DELETE flag\n"); |
565 | |
566 | if((relation = osm_get_relation_by_id(osm, id))) |
567 | relation->flags |= OSM_FLAG_DELETED; |
568 | else |
569 | printf(" WARNING: no relation with that id found\n"); |
570 | break; |
571 | |
572 | case OSM_FLAG_DIRTY: |
573 | printf(" Valid id (DIRTY)\n"); |
574 | |
575 | if((relation = osm_get_relation_by_id(osm, id))) |
576 | relation->flags |= OSM_FLAG_DIRTY; |
577 | else |
578 | printf(" WARNING: no relation with that id found\n"); |
579 | break; |
580 | |
581 | default: |
582 | printf(" Illegal relation entry\n"); |
583 | return; |
584 | } |
585 | |
586 | if(!relation) { |
587 | printf(" no valid relation\n"); |
588 | return; |
589 | } |
590 | |
591 | /* update id from diff */ |
592 | relation->id = id; |
593 | |
594 | /* update members */ |
595 | |
596 | /* this may be an existing relation, so remove members to */ |
597 | /* make space for new ones */ |
598 | if(relation->member) { |
599 | printf(" removing existing members for diff members\n"); |
600 | osm_members_free(relation->member); |
601 | relation->member = NULL; |
602 | } |
603 | |
604 | /* scan for members */ |
605 | member_t **member = &relation->member; |
606 | xmlNode *member_node = NULL; |
607 | for(member_node = node_rel->children; member_node; |
608 | member_node = member_node->next) { |
609 | if(member_node->type == XML_ELEMENT_NODE) { |
610 | if(strcasecmp((char*)member_node->name, "member") == 0) { |
611 | /* attach member to member_chain */ |
612 | *member = osm_parse_osm_relation_member(osm, doc, member_node); |
613 | if(*member) |
614 | member = &((*member)->next); |
615 | } |
616 | } |
617 | } |
618 | |
619 | /* node may be an existing node, so remove tags to */ |
620 | /* make space for new ones */ |
621 | if(relation->tag) { |
622 | printf(" removing existing tags for diff tags\n"); |
623 | osm_tag_free(relation->tag); |
624 | relation->tag = NULL; |
625 | } |
626 | |
627 | relation->tag = xml_scan_tags(doc, node_rel->children, osm); |
628 | } |
629 | |
630 | void diff_restore(appdata_t *appdata, project_t *project, osm_t *osm) { |
631 | if(!project || !osm) return; |
632 | |
633 | char *diff_name = g_strdup_printf("%s/%s.diff", project->path, project->name); |
634 | |
635 | if(!g_file_test(diff_name, G_FILE_TEST_EXISTS)) { |
636 | printf("no diff present!\n"); |
637 | g_free(diff_name); |
638 | return; |
639 | } |
640 | |
641 | printf("diff found, applying ...\n"); |
642 | |
643 | xmlDoc *doc = NULL; |
644 | xmlNode *root_element = NULL; |
645 | |
646 | /* parse the file and get the DOM */ |
647 | if((doc = xmlReadFile(diff_name, NULL, 0)) == NULL) { |
648 | errorf(GTK_WIDGET(appdata->window), |
649 | "Error: could not parse file %s\n", diff_name); |
650 | g_free(diff_name); |
651 | return; |
652 | } |
653 | |
654 | /* Get the root element node */ |
655 | root_element = xmlDocGetRootElement(doc); |
656 | |
657 | xmlNode *cur_node = NULL; |
658 | for (cur_node = root_element; cur_node; cur_node = cur_node->next) { |
659 | if (cur_node->type == XML_ELEMENT_NODE) { |
660 | if(strcasecmp((char*)cur_node->name, "diff") == 0) { |
661 | char *str = (char*)xmlGetProp(cur_node, BAD_CAST "name"); |
662 | if(str) { |
663 | printf("diff for project %s\n", str); |
664 | if(strcmp(project->name, str) != 0) { |
665 | messagef(GTK_WIDGET(appdata->window), _("Warning"), |
666 | "Diff name (%s) does not match project name (%s)", |
667 | str, project->name); |
668 | } |
669 | xmlFree(str); |
670 | } |
671 | |
672 | xmlNodePtr node_node = cur_node->children; |
673 | while(node_node) { |
674 | if(node_node->type == XML_ELEMENT_NODE) { |
675 | |
676 | if(strcasecmp((char*)node_node->name, "node") == 0) |
677 | diff_restore_node(doc, node_node, osm); |
678 | |
679 | else if(strcasecmp((char*)node_node->name, "way") == 0) |
680 | diff_restore_way(doc, node_node, osm); |
681 | |
682 | else if(strcasecmp((char*)node_node->name, "relation") == 0) |
683 | diff_restore_relation(doc, node_node, osm); |
684 | |
685 | else |
686 | printf("WARNING: item %s not restored\n", node_node->name); |
687 | } |
688 | node_node = node_node->next; |
689 | } |
690 | } |
691 | } |
692 | } |
693 | |
694 | g_free(diff_name); |
695 | |
696 | xmlFreeDoc(doc); |
697 | xmlCleanupParser(); |
698 | |
699 | /* check for hidden ways and update menu accordingly */ |
700 | gboolean something_is_hidden = FALSE; |
701 | way_t *way = osm->way; |
702 | while(!something_is_hidden && way) { |
703 | if(way->flags & OSM_FLAG_HIDDEN) |
704 | something_is_hidden = TRUE; |
705 | |
706 | way = way->next; |
707 | } |
708 | |
709 | if(something_is_hidden) { |
710 | printf("hidden flags have been restored, enable show_add menu\n"); |
711 | |
712 | statusbar_set(appdata, _("Some objects have been hidden"), TRUE); |
713 | gtk_widget_set_sensitive(appdata->menu_item_map_show_all, TRUE); |
714 | } |
715 | } |
716 | |
717 | gboolean diff_present(project_t *project) { |
718 | char *diff_name = g_strdup_printf("%s/%s.diff", project->path, project->name); |
719 | |
720 | if(!g_file_test(diff_name, G_FILE_TEST_EXISTS)) { |
721 | printf("no diff present!\n"); |
722 | g_free(diff_name); |
723 | return FALSE; |
724 | } |
725 | |
726 | g_free(diff_name); |
727 | return TRUE; |
728 | } |
729 | |
730 | void diff_remove(project_t *project) { |
731 | char *diff_name = g_strdup_printf("%s/%s.diff", project->path, project->name); |
732 | g_remove(diff_name); |
733 | g_free(diff_name); |
734 | } |