17 |
* along with OSM2Go. If not, see <http://www.gnu.org/licenses/>. |
* along with OSM2Go. If not, see <http://www.gnu.org/licenses/>. |
18 |
*/ |
*/ |
19 |
|
|
|
/* these defines select one of three possible xml parsers */ |
|
|
/* this is in fact selected depending on the plattform in the Makefile */ |
|
|
// #define OSM_DOM_PARSER |
|
|
// #define OSM_STREAM_PARSER |
|
|
|
|
20 |
#include <stdio.h> |
#include <stdio.h> |
21 |
#include <stdlib.h> |
#include <stdlib.h> |
22 |
#include <string.h> |
#include <string.h> |
53 |
bounds->ll_min.lon, bounds->ll_max.lon); |
bounds->ll_min.lon, bounds->ll_max.lon); |
54 |
} |
} |
55 |
|
|
|
#ifdef OSM_DOM_PARSER |
|
|
static bounds_t *osm_parse_osm_bounds(osm_t *osm, |
|
|
xmlDocPtr doc, xmlNode *a_node) { |
|
|
char *prop; |
|
|
|
|
|
if(osm->bounds) { |
|
|
errorf(NULL, "Doubly defined bounds"); |
|
|
return NULL; |
|
|
} |
|
|
|
|
|
bounds_t *bounds = g_new0(bounds_t, 1); |
|
|
|
|
|
bounds->ll_min.lat = bounds->ll_min.lon = NAN; |
|
|
bounds->ll_max.lat = bounds->ll_max.lon = NAN; |
|
|
|
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"minlat"))) { |
|
|
bounds->ll_min.lat = g_ascii_strtod(prop, NULL); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"maxlat"))) { |
|
|
bounds->ll_max.lat = g_ascii_strtod(prop, NULL); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"minlon"))) { |
|
|
bounds->ll_min.lon = g_ascii_strtod(prop, NULL); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"maxlon"))) { |
|
|
bounds->ll_max.lon = g_ascii_strtod(prop, NULL); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
if(isnan(bounds->ll_min.lat) || isnan(bounds->ll_min.lon) || |
|
|
isnan(bounds->ll_max.lat) || isnan(bounds->ll_max.lon)) { |
|
|
errorf(NULL, "Invalid coordinate in bounds (%f/%f/%f/%f)", |
|
|
bounds->ll_min.lat, bounds->ll_min.lon, |
|
|
bounds->ll_max.lat, bounds->ll_max.lon); |
|
|
|
|
|
osm_bounds_free(bounds); |
|
|
return NULL; |
|
|
} |
|
|
|
|
|
|
|
|
/* calculate map zone which will be used as a reference for all */ |
|
|
/* drawing/projection later on */ |
|
|
pos_t center = { (bounds->ll_max.lat + bounds->ll_min.lat)/2, |
|
|
(bounds->ll_max.lon + bounds->ll_min.lon)/2 }; |
|
|
|
|
|
pos2lpos_center(¢er, &bounds->center); |
|
|
|
|
|
/* the scale is needed to accomodate for "streching" */ |
|
|
/* by the mercartor projection */ |
|
|
bounds->scale = cos(DEG2RAD(center.lat)); |
|
|
|
|
|
pos2lpos_center(&bounds->ll_min, &bounds->min); |
|
|
bounds->min.x -= bounds->center.x; |
|
|
bounds->min.y -= bounds->center.y; |
|
|
bounds->min.x *= bounds->scale; |
|
|
bounds->min.y *= bounds->scale; |
|
|
|
|
|
pos2lpos_center(&bounds->ll_max, &bounds->max); |
|
|
bounds->max.x -= bounds->center.x; |
|
|
bounds->max.y -= bounds->center.y; |
|
|
bounds->max.x *= bounds->scale; |
|
|
bounds->max.y *= bounds->scale; |
|
|
|
|
|
return bounds; |
|
|
} |
|
|
#endif |
|
|
|
|
56 |
/* ------------------------- user handling --------------------- */ |
/* ------------------------- user handling --------------------- */ |
57 |
|
|
58 |
void osm_users_free(user_t *user) { |
void osm_users_free(user_t *user) { |
252 |
} |
} |
253 |
} |
} |
254 |
|
|
|
#ifdef OSM_DOM_PARSER |
|
|
static node_t *osm_parse_osm_node(osm_t *osm, |
|
|
xmlDocPtr doc, xmlNode *a_node) { |
|
|
xmlNode *cur_node = NULL; |
|
|
|
|
|
/* allocate a new node structure */ |
|
|
node_t *node = g_new0(node_t, 1); |
|
|
node->pos.lat = node->pos.lon = NAN; |
|
|
|
|
|
char *prop; |
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"id"))) { |
|
|
node->id = strtoul(prop, NULL, 10); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"lat"))) { |
|
|
node->pos.lat = g_ascii_strtod(prop, NULL); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"lon"))) { |
|
|
node->pos.lon = g_ascii_strtod(prop, NULL); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"user"))) { |
|
|
node->user = osm_user(osm, prop); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"visible"))) { |
|
|
node->visible = (strcasecmp(prop, "true") == 0); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"timestamp"))) { |
|
|
node->time = convert_iso8601(prop); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
/* append node to end of hash table if present */ |
|
|
if(osm->node_hash) { |
|
|
hash_item_t **item = &osm->node_hash->hash[ID2HASH(node->id)]; |
|
|
while(*item) item = &(*item)->next; |
|
|
|
|
|
*item = g_new0(hash_item_t, 1); |
|
|
(*item)->data.node = node; |
|
|
} |
|
|
|
|
|
/* scan for tags and attach a list of tags */ |
|
|
tag_t **tag = &node->tag; |
|
|
for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) { |
|
|
if (cur_node->type == XML_ELEMENT_NODE) { |
|
|
if(strcasecmp((char*)cur_node->name, "tag") == 0) { |
|
|
/* attach tag to node */ |
|
|
*tag = osm_parse_osm_tag(osm, doc, cur_node); |
|
|
if(*tag) tag = &((*tag)->next); |
|
|
} else |
|
|
printf("found unhandled osm/node/%s\n", cur_node->name); |
|
|
} |
|
|
} |
|
|
|
|
|
pos2lpos(osm->bounds, &node->pos, &node->lpos); |
|
|
|
|
|
return node; |
|
|
} |
|
|
#endif |
|
|
|
|
255 |
/* ------------------- way handling ------------------- */ |
/* ------------------- way handling ------------------- */ |
256 |
|
|
257 |
void osm_node_chain_free(node_chain_t *node_chain) { |
void osm_node_chain_free(node_chain_t *node_chain) { |
356 |
return NULL; |
return NULL; |
357 |
} |
} |
358 |
|
|
|
#ifdef OSM_DOM_PARSER |
|
|
static way_t *osm_parse_osm_way(osm_t *osm, |
|
|
xmlDocPtr doc, xmlNode *a_node) { |
|
|
xmlNode *cur_node = NULL; |
|
|
|
|
|
/* allocate a new way structure */ |
|
|
way_t *way = g_new0(way_t, 1); |
|
|
|
|
|
char *prop; |
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"id"))) { |
|
|
way->id = strtoul(prop, NULL, 10); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"user"))) { |
|
|
way->user = osm_user(osm, prop); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"visible"))) { |
|
|
way->visible = (strcasecmp(prop, "true") == 0); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"timestamp"))) { |
|
|
way->time = convert_iso8601(prop); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
/* append way to end of hash table if present */ |
|
|
if(osm->way_hash) { |
|
|
hash_item_t **item = &osm->way_hash->hash[ID2HASH(way->id)]; |
|
|
while(*item) item = &(*item)->next; |
|
|
|
|
|
*item = g_new0(hash_item_t, 1); |
|
|
(*item)->data.way = way; |
|
|
} |
|
|
|
|
|
/* scan for tags/nodes and attach their lists */ |
|
|
tag_t **tag = &way->tag; |
|
|
node_chain_t **node_chain = &way->node_chain; |
|
|
|
|
|
for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) { |
|
|
if (cur_node->type == XML_ELEMENT_NODE) { |
|
|
if(strcasecmp((char*)cur_node->name, "tag") == 0) { |
|
|
/* attach tag to node */ |
|
|
*tag = osm_parse_osm_tag(osm, doc, cur_node); |
|
|
if(*tag) tag = &((*tag)->next); |
|
|
} else if(strcasecmp((char*)cur_node->name, "nd") == 0) { |
|
|
*node_chain = osm_parse_osm_way_nd(osm, doc, cur_node); |
|
|
if(*node_chain) |
|
|
node_chain = &((*node_chain)->next); |
|
|
} else |
|
|
printf("found unhandled osm/node/%s\n", cur_node->name); |
|
|
} |
|
|
} |
|
|
|
|
|
return way; |
|
|
} |
|
|
#endif |
|
|
|
|
359 |
/* ------------------- relation handling ------------------- */ |
/* ------------------- relation handling ------------------- */ |
360 |
|
|
361 |
void osm_member_free(member_t *member) { |
void osm_member_free(member_t *member) { |
503 |
return member; |
return member; |
504 |
} |
} |
505 |
|
|
|
#ifdef OSM_DOM_PARSER |
|
|
static relation_t *osm_parse_osm_relation(osm_t *osm, |
|
|
xmlDocPtr doc, xmlNode *a_node) { |
|
|
xmlNode *cur_node = NULL; |
|
|
|
|
|
/* allocate a new relation structure */ |
|
|
relation_t *relation = g_new0(relation_t, 1); |
|
|
|
|
|
char *prop; |
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"id"))) { |
|
|
relation->id = strtoul(prop, NULL, 10); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"user"))) { |
|
|
relation->user = osm_user(osm, prop); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"visible"))) { |
|
|
relation->visible = (strcasecmp(prop, "true") == 0); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"timestamp"))) { |
|
|
relation->time = convert_iso8601(prop); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
/* scan for tags and attach a list of tags */ |
|
|
tag_t **tag = &relation->tag; |
|
|
member_t **member = &relation->member; |
|
|
|
|
|
for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) { |
|
|
if (cur_node->type == XML_ELEMENT_NODE) { |
|
|
if(strcasecmp((char*)cur_node->name, "tag") == 0) { |
|
|
/* attach tag to node */ |
|
|
*tag = osm_parse_osm_tag(osm, doc, cur_node); |
|
|
if(*tag) tag = &((*tag)->next); |
|
|
} else if(strcasecmp((char*)cur_node->name, "member") == 0) { |
|
|
*member = osm_parse_osm_relation_member(osm, doc, cur_node); |
|
|
if(*member) member = &((*member)->next); |
|
|
} else |
|
|
printf("found unhandled osm/node/%s\n", cur_node->name); |
|
|
} |
|
|
} |
|
|
|
|
|
return relation; |
|
|
} |
|
|
|
|
|
/* ----------------------- generic xml handling -------------------------- */ |
|
|
|
|
|
/* parse osm entry */ |
|
|
static void osm_parse_osm(osm_t *osm, xmlDocPtr doc, xmlNode * a_node) { |
|
|
xmlNode *cur_node = NULL; |
|
|
|
|
|
for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) { |
|
|
if (cur_node->type == XML_ELEMENT_NODE) { |
|
|
if(strcasecmp((char*)cur_node->name, "bounds") == 0) |
|
|
osm->bounds = osm_parse_osm_bounds(osm, doc, cur_node); |
|
|
else if(strcasecmp((char*)cur_node->name, "node") == 0) { |
|
|
/* parse node and attach it to chain */ |
|
|
node_t *new = osm_parse_osm_node(osm, doc, cur_node); |
|
|
if(new) { |
|
|
node_t **node = &osm->node; |
|
|
|
|
|
#ifdef OSM_SORT_ID |
|
|
/* search chain of nodes */ |
|
|
while(*node && ((*node)->id < new->id)) |
|
|
node = &(*node)->next; |
|
|
#endif |
|
|
|
|
|
#ifdef OSM_SORT_LAST |
|
|
while(*node) node = &(*node)->next; |
|
|
#endif |
|
|
|
|
|
/* insert into chain */ |
|
|
new->next = *node; |
|
|
*node = new; |
|
|
} |
|
|
} else if(strcasecmp((char*)cur_node->name, "way") == 0) { |
|
|
/* parse way and attach it to chain */ |
|
|
way_t *new = osm_parse_osm_way(osm, doc, cur_node); |
|
|
if(new) { |
|
|
way_t **way = &osm->way; |
|
|
|
|
|
#ifdef OSM_SORT_ID |
|
|
/* insert into chain */ |
|
|
while(*way && ((*way)->id < new->id)) |
|
|
way = &(*way)->next; |
|
|
#endif |
|
|
|
|
|
#ifdef OSM_SORT_LAST |
|
|
while(*way) way = &(*way)->next; |
|
|
#endif |
|
|
|
|
|
/* insert into chain */ |
|
|
new->next = *way; |
|
|
*way = new; |
|
|
} |
|
|
} else if(strcasecmp((char*)cur_node->name, "relation") == 0) { |
|
|
/* parse relation and attach it to chain */ |
|
|
relation_t *new = osm_parse_osm_relation(osm, doc, cur_node); |
|
|
if(new) { |
|
|
relation_t **relation = &osm->relation; |
|
|
|
|
|
#ifdef OSM_SORT_ID |
|
|
/* search chain of ways */ |
|
|
while(*relation && ((*relation)->id < new->id)) |
|
|
relation = &(*relation)->next; |
|
|
#endif |
|
|
|
|
|
#ifdef OSM_SORT_LAST |
|
|
while(*relation) relation = &(*relation)->next; |
|
|
#endif |
|
|
|
|
|
/* insert into chain */ |
|
|
new->next = *relation; |
|
|
*relation = new; |
|
|
} |
|
|
} else |
|
|
printf("found unhandled osm/%s\n", cur_node->name); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
/* parse root element and search for "osm" */ |
|
|
static osm_t *osm_parse_root(xmlDocPtr doc, xmlNode * a_node) { |
|
|
osm_t *osm; |
|
|
xmlNode *cur_node = NULL; |
|
|
|
|
|
/* allocate memory to hold osm file description */ |
|
|
osm = g_new0(osm_t, 1); |
|
|
osm->node_hash = g_new0(hash_table_t, 1); |
|
|
osm->way_hash = g_new0(hash_table_t, 1); |
|
|
|
|
|
for (cur_node = a_node; cur_node; cur_node = cur_node->next) { |
|
|
if (cur_node->type == XML_ELEMENT_NODE) { |
|
|
/* parse osm osm file ... */ |
|
|
if(strcasecmp((char*)cur_node->name, "osm") == 0) |
|
|
osm_parse_osm(osm, doc, cur_node); |
|
|
else |
|
|
printf("found unhandled %s\n", cur_node->name); |
|
|
} |
|
|
} |
|
|
|
|
|
return osm; |
|
|
} |
|
|
|
|
|
static osm_t *osm_parse_doc(xmlDocPtr doc) { |
|
|
osm_t *osm; |
|
|
|
|
|
/* Get the root element node */ |
|
|
xmlNode *root_element = xmlDocGetRootElement(doc); |
|
|
|
|
|
osm = osm_parse_root(doc, root_element); |
|
|
|
|
|
/*free the document */ |
|
|
xmlFreeDoc(doc); |
|
|
|
|
|
/* |
|
|
* Free the global variables that may |
|
|
* have been allocated by the parser. |
|
|
*/ |
|
|
xmlCleanupParser(); |
|
|
|
|
|
return osm; |
|
|
} |
|
|
#endif |
|
|
|
|
506 |
/* ------------------ osm handling ----------------- */ |
/* ------------------ osm handling ----------------- */ |
507 |
|
|
508 |
/* the two hash tables eat over 512kBytes memory and may thus be */ |
/* the two hash tables eat over 512kBytes memory and may thus be */ |
549 |
osm_relations_dump(osm->relation); |
osm_relations_dump(osm->relation); |
550 |
} |
} |
551 |
|
|
552 |
#ifdef OSM_STREAM_PARSER |
/* -------------------------- stream parser ------------------- */ |
|
/* -------------------------- stream parser tests ------------------- */ |
|
553 |
|
|
554 |
#include <libxml/xmlreader.h> |
#include <libxml/xmlreader.h> |
555 |
|
|
1049 |
return osm; |
return osm; |
1050 |
} |
} |
1051 |
|
|
1052 |
/* ----------------------- end of stream parser tests ------------------- */ |
/* ----------------------- end of stream parser ------------------- */ |
|
#endif |
|
|
|
|
|
#ifdef OSM_QND_XML_PARSER |
|
|
/* -------------------------- qnd-xml parser tests ------------------- */ |
|
|
|
|
|
#ifdef USE_FLOAT |
|
|
#define GET_PROP_POS(a,b,c) qnd_xml_get_prop_float(a, b, c) |
|
|
#else |
|
|
#define GET_PROP_POS(a,b,c) qnd_xml_get_prop_double(a, b, c) |
|
|
#endif |
|
|
|
|
|
gboolean osm_bounds_cb(qnd_xml_stack_t *stack, |
|
|
qnd_xml_attribute_t *attributes, gpointer data) { |
|
|
|
|
|
/* get parent pointer */ |
|
|
osm_t *osm = (osm_t*)stack->prev->userdata[0]; |
|
|
|
|
|
if(osm->bounds) { |
|
|
errorf(NULL, "Doubly defined bounds"); |
|
|
return FALSE; |
|
|
} |
|
|
|
|
|
bounds_t *bounds = osm->bounds = g_new0(bounds_t, 1); |
|
|
|
|
|
bounds->ll_min.lat = bounds->ll_min.lon = NAN; |
|
|
bounds->ll_max.lat = bounds->ll_max.lon = NAN; |
|
|
|
|
|
GET_PROP_POS(attributes, "minlat", &bounds->ll_min.lat); |
|
|
GET_PROP_POS(attributes, "minlon", &bounds->ll_min.lon); |
|
|
GET_PROP_POS(attributes, "maxlat", &bounds->ll_max.lat); |
|
|
GET_PROP_POS(attributes, "maxlon", &bounds->ll_max.lon); |
|
|
|
|
|
if(isnan(bounds->ll_min.lat) || isnan(bounds->ll_min.lon) || |
|
|
isnan(bounds->ll_max.lat) || isnan(bounds->ll_max.lon)) { |
|
|
errorf(NULL, "Invalid coordinate in bounds (%f/%f/%f/%f)", |
|
|
bounds->ll_min.lat, bounds->ll_min.lon, |
|
|
bounds->ll_max.lat, bounds->ll_max.lon); |
|
|
|
|
|
osm_bounds_free(bounds); |
|
|
osm->bounds = NULL; |
|
|
return FALSE; |
|
|
} |
|
|
|
|
|
|
|
|
/* calculate map zone which will be used as a reference for all */ |
|
|
/* drawing/projection later on */ |
|
|
pos_t center = { (bounds->ll_max.lat + bounds->ll_min.lat)/2, |
|
|
(bounds->ll_max.lon + bounds->ll_min.lon)/2 }; |
|
|
|
|
|
pos2lpos_center(¢er, &bounds->center); |
|
|
|
|
|
/* the scale is needed to accomodate for "streching" */ |
|
|
/* by the mercartor projection */ |
|
|
bounds->scale = cos(DEG2RAD(center.lat)); |
|
|
|
|
|
pos2lpos_center(&bounds->ll_min, &bounds->min); |
|
|
bounds->min.x -= bounds->center.x; |
|
|
bounds->min.y -= bounds->center.y; |
|
|
bounds->min.x *= bounds->scale; |
|
|
bounds->min.y *= bounds->scale; |
|
|
|
|
|
pos2lpos_center(&bounds->ll_max, &bounds->max); |
|
|
bounds->max.x -= bounds->center.x; |
|
|
bounds->max.y -= bounds->center.y; |
|
|
bounds->max.x *= bounds->scale; |
|
|
bounds->max.y *= bounds->scale; |
|
|
|
|
|
return TRUE; |
|
|
} |
|
|
|
|
|
static gboolean osm_tag_cb(qnd_xml_stack_t *stack, |
|
|
qnd_xml_attribute_t *attributes, gpointer data) { |
|
|
|
|
|
tag_t *tag = *(tag_t**)stack->prev->userdata[1] = g_new0(tag_t, 1); |
|
|
|
|
|
tag->key = qnd_xml_get_prop_str(attributes, "k"); |
|
|
tag->value = qnd_xml_get_prop_str(attributes, "v"); |
|
|
|
|
|
if(!tag->key || !tag->value) { |
|
|
printf("incomplete tag key/value %s/%s\n", tag->key, tag->value); |
|
|
osm_tags_free(tag); |
|
|
tag = NULL; |
|
|
} else |
|
|
stack->prev->userdata[1] = &tag->next; |
|
|
|
|
|
return TRUE; |
|
|
} |
|
|
|
|
|
static gboolean osm_node_cb(qnd_xml_stack_t *stack, |
|
|
qnd_xml_attribute_t *attributes, gpointer data) { |
|
|
|
|
|
osm_t *osm = (osm_t*)stack->prev->userdata[0]; |
|
|
|
|
|
/* allocate a new node structure. userdata[1] points to the current */ |
|
|
/* position a new node is to be stored */ |
|
|
node_t *node = *(node_t**)stack->prev->userdata[1] = |
|
|
stack->userdata[0] = g_new0(node_t, 1); |
|
|
stack->prev->userdata[1] = &node->next; |
|
|
|
|
|
qnd_xml_get_prop_gulong(attributes, "id", &node->id); |
|
|
GET_PROP_POS(attributes, "lat", &node->pos.lat); |
|
|
GET_PROP_POS(attributes, "lon", &node->pos.lon); |
|
|
node->user = osm_user(osm, qnd_xml_get_prop(attributes, "user")); |
|
|
node->visible = qnd_xml_get_prop_is(attributes, "visible", "true"); |
|
|
node->time = convert_iso8601(qnd_xml_get_prop(attributes, "timestamp")); |
|
|
|
|
|
pos2lpos(osm->bounds, &node->pos, &node->lpos); |
|
|
|
|
|
/* store current tag pointer in userdata for fast access to current tag */ |
|
|
stack->userdata[1] = &node->tag; |
|
|
|
|
|
/* append node to end of hash table if present */ |
|
|
if(osm->node_hash) { |
|
|
hash_item_t **item = &osm->node_hash->hash[ID2HASH(node->id)]; |
|
|
while(*item) item = &(*item)->next; |
|
|
|
|
|
*item = g_new0(hash_item_t, 1); |
|
|
(*item)->data.node = node; |
|
|
} |
|
|
|
|
|
return TRUE; |
|
|
} |
|
|
|
|
|
static gboolean osm_way_nd_cb(qnd_xml_stack_t *stack, |
|
|
qnd_xml_attribute_t *attributes, gpointer data) { |
|
|
|
|
|
osm_t *osm = (osm_t*)stack->prev->prev->userdata[0]; |
|
|
|
|
|
item_id_t id; |
|
|
if(qnd_xml_get_prop_gulong(attributes, "ref", &id)) { |
|
|
/* allocate a new node_chain structure */ |
|
|
node_chain_t *node_chain = *(node_chain_t**)stack->prev->userdata[2] = |
|
|
g_new0(node_chain_t, 1); |
|
|
|
|
|
/* search matching node */ |
|
|
node_chain->node = osm_get_node_by_id(osm, id); |
|
|
if(!node_chain->node) printf("Node id %lu not found\n", id); |
|
|
else node_chain->node->ways++; |
|
|
|
|
|
stack->prev->userdata[2] = &node_chain->next; |
|
|
} |
|
|
|
|
|
return TRUE; |
|
|
} |
|
|
|
|
|
gboolean osm_way_cb(qnd_xml_stack_t *stack, |
|
|
qnd_xml_attribute_t *attributes, gpointer data) { |
|
|
|
|
|
osm_t *osm = (osm_t*)stack->prev->userdata[0]; |
|
|
|
|
|
/* allocate a new way structure. userdata[2] points to the current */ |
|
|
/* position a new way is to be stored in the way list */ |
|
|
way_t *way = *(way_t**)stack->prev->userdata[2] = |
|
|
stack->userdata[0] = g_new0(way_t, 1); |
|
|
stack->prev->userdata[2] = &way->next; |
|
|
|
|
|
qnd_xml_get_prop_gulong(attributes, "id", &way->id); |
|
|
way->user = osm_user(osm, qnd_xml_get_prop(attributes, "user")); |
|
|
way->visible = qnd_xml_get_prop_is(attributes, "visible", "true"); |
|
|
way->time = convert_iso8601(qnd_xml_get_prop(attributes, "timestamp")); |
|
|
|
|
|
/* store current tag and node_chain pointers in userdata for fast */ |
|
|
/* access to current tag/node_chain entry */ |
|
|
stack->userdata[1] = &way->tag; |
|
|
stack->userdata[2] = &way->node_chain; |
|
|
|
|
|
/* append way to end of hash table if present */ |
|
|
if(osm->way_hash) { |
|
|
hash_item_t **item = &osm->way_hash->hash[ID2HASH(way->id)]; |
|
|
while(*item) item = &(*item)->next; |
|
|
|
|
|
*item = g_new0(hash_item_t, 1); |
|
|
(*item)->data.way = way; |
|
|
} |
|
|
|
|
|
return TRUE; |
|
|
} |
|
|
|
|
|
static gboolean osm_rel_member_cb(qnd_xml_stack_t *stack, |
|
|
qnd_xml_attribute_t *attributes, gpointer data) { |
|
|
|
|
|
osm_t *osm = (osm_t*)stack->prev->prev->userdata[0]; |
|
|
|
|
|
member_t *member = *(member_t**)stack->prev->userdata[2] = |
|
|
g_new0(member_t, 1); |
|
|
stack->prev->userdata[2] = &member->next; |
|
|
member->type = ILLEGAL; |
|
|
|
|
|
char *type = qnd_xml_get_prop(attributes, "type"); |
|
|
if(type) { |
|
|
if(strcasecmp(type, "way") == 0) member->type = WAY; |
|
|
else if(strcasecmp(type, "node") == 0) member->type = NODE; |
|
|
else if(strcasecmp(type, "relation") == 0) member->type = RELATION; |
|
|
} |
|
|
|
|
|
item_id_t id; |
|
|
if(qnd_xml_get_prop_gulong(attributes, "ref", &id)) { |
|
|
switch(member->type) { |
|
|
case ILLEGAL: |
|
|
printf("Unable to store illegal type\n"); |
|
|
break; |
|
|
|
|
|
case WAY: |
|
|
/* search matching way */ |
|
|
member->way = osm_get_way_by_id(osm, id); |
|
|
if(!member->way) { |
|
|
member->type = WAY_ID; |
|
|
member->id = id; |
|
|
} |
|
|
break; |
|
|
|
|
|
case NODE: |
|
|
/* search matching node */ |
|
|
member->node = osm_get_node_by_id(osm, id); |
|
|
if(!member->node) { |
|
|
member->type = NODE_ID; |
|
|
member->id = id; |
|
|
} |
|
|
break; |
|
|
|
|
|
case RELATION: |
|
|
/* search matching relation */ |
|
|
member->relation = osm_get_relation_by_id(osm, id); |
|
|
if(!member->relation) { |
|
|
member->type = NODE_ID; |
|
|
member->id = id; |
|
|
} |
|
|
break; |
|
|
|
|
|
case WAY_ID: |
|
|
case NODE_ID: |
|
|
case RELATION_ID: |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
return TRUE; |
|
|
} |
|
|
|
|
|
gboolean osm_rel_cb(qnd_xml_stack_t *stack, |
|
|
qnd_xml_attribute_t *attributes, gpointer data) { |
|
|
|
|
|
osm_t *osm = (osm_t*)stack->prev->userdata[0]; |
|
|
|
|
|
/* allocate a new relation structure. userdata[3] points to the current */ |
|
|
/* position a new relation is to be stored at in the relation list */ |
|
|
relation_t *relation = *(relation_t**)stack->prev->userdata[3] = |
|
|
stack->userdata[0] = g_new0(relation_t, 1); |
|
|
stack->prev->userdata[3] = &relation->next; |
|
|
|
|
|
qnd_xml_get_prop_gulong(attributes, "id", &relation->id); |
|
|
relation->user = osm_user(osm, qnd_xml_get_prop(attributes, "user")); |
|
|
relation->visible = qnd_xml_get_prop_is(attributes, "visible", "true"); |
|
|
relation->time = convert_iso8601(qnd_xml_get_prop(attributes, "timestamp")); |
|
|
|
|
|
/* store current tag and member pointers in userdata for fast access */ |
|
|
/* to current tag and members in their chains */ |
|
|
stack->userdata[1] = &relation->tag; |
|
|
stack->userdata[2] = &relation->member; |
|
|
|
|
|
return TRUE; |
|
|
} |
|
|
|
|
|
gboolean osm_cb(qnd_xml_stack_t *stack, |
|
|
qnd_xml_attribute_t *attributes, gpointer data) { |
|
|
|
|
|
g_assert(!stack->userdata[0]); |
|
|
|
|
|
/* also set parents (roots) userdata as it's the parsers return value */ |
|
|
osm_t *osm = stack->prev->userdata[0] = |
|
|
stack->userdata[0] = g_new0(osm_t, 1); |
|
|
|
|
|
osm->node_hash = g_new0(hash_table_t, 1); |
|
|
osm->way_hash = g_new0(hash_table_t, 1); |
|
|
|
|
|
/* store direct pointers for faster list access */ |
|
|
/* (otherwise we'd have to search the end of the lists for every item */ |
|
|
/* to be attached) */ |
|
|
stack->userdata[1] = &osm->node; |
|
|
stack->userdata[2] = &osm->way; |
|
|
stack->userdata[3] = &osm->relation; |
|
|
|
|
|
return TRUE; |
|
|
} |
|
|
|
|
|
|
|
|
/* these structures describe the content qnd_xml expects while parsing */ |
|
|
qnd_xml_entry_t osm_node_tag = { "tag", osm_tag_cb, QND_XML_LEAF }; |
|
|
|
|
|
qnd_xml_entry_t osm_way_tag = { "tag", osm_tag_cb, QND_XML_LEAF }; |
|
|
qnd_xml_entry_t osm_way_nd = { "nd", osm_way_nd_cb, QND_XML_LEAF }; |
|
|
|
|
|
qnd_xml_entry_t osm_rel_tag = { "tag", osm_tag_cb, QND_XML_LEAF }; |
|
|
qnd_xml_entry_t osm_rel_member = { "member", osm_rel_member_cb, QND_XML_LEAF }; |
|
|
|
|
|
qnd_xml_entry_t osm_bounds = { "bounds", osm_bounds_cb, QND_XML_LEAF }; |
|
|
|
|
|
qnd_xml_entry_t *node_children[] = { &osm_node_tag }, |
|
|
osm_node = { "node", osm_node_cb, QND_XML_CHILDREN(node_children) }; |
|
|
|
|
|
qnd_xml_entry_t *way_children[] = { &osm_way_tag, &osm_way_nd }, |
|
|
osm_way = { "way", osm_way_cb, QND_XML_CHILDREN(way_children) }; |
|
|
|
|
|
qnd_xml_entry_t *rel_children[] = { &osm_rel_tag, &osm_rel_member }, |
|
|
osm_rel = { "rel", osm_rel_cb, QND_XML_CHILDREN(rel_children) }; |
|
|
|
|
|
/* the osm element */ |
|
|
qnd_xml_entry_t *osm_children[] = { |
|
|
&osm_bounds, &osm_node, &osm_way, &osm_rel }; |
|
|
qnd_xml_entry_t osm = { "osm", osm_cb, QND_XML_CHILDREN(osm_children) }; |
|
|
|
|
|
/* the root element */ |
|
|
qnd_xml_entry_t *root_children[] = { &osm }; |
|
|
qnd_xml_entry_t root = { "<root>", NULL, QND_XML_CHILDREN(root_children) }; |
|
|
|
|
|
// gcc `pkg-config --cflags --libs glib-2.0` -o qnd_xml qnd_xml.c |
|
|
|
|
|
|
|
|
|
|
|
/* ----------------------- end of qnd-xml parser tests ------------------- */ |
|
|
#endif |
|
|
|
|
1053 |
|
|
1054 |
#include <sys/time.h> |
#include <sys/time.h> |
1055 |
|
|
1058 |
struct timeval start; |
struct timeval start; |
1059 |
gettimeofday(&start, NULL); |
gettimeofday(&start, NULL); |
1060 |
|
|
|
#ifdef OSM_STREAM_PARSER |
|
1061 |
LIBXML_TEST_VERSION; |
LIBXML_TEST_VERSION; |
1062 |
|
|
1063 |
// use stream parser |
// use stream parser |
1064 |
osm_t *osm = process_file(filename); |
osm_t *osm = process_file(filename); |
1065 |
xmlCleanupParser(); |
xmlCleanupParser(); |
|
#endif |
|
|
|
|
|
#ifdef OSM_DOM_PARSER |
|
|
LIBXML_TEST_VERSION; |
|
|
|
|
|
// parse into a tree |
|
|
/* parse the file and get the DOM */ |
|
|
xmlDoc *doc = NULL; |
|
|
if ((doc = xmlReadFile(filename, NULL, 0)) == NULL) { |
|
|
xmlErrorPtr errP = xmlGetLastError(); |
|
|
errorf(NULL, "While parsing \"%s\":\n\n%s", filename, errP->message); |
|
|
return NULL; |
|
|
} |
|
|
|
|
|
osm_t *osm = osm_parse_doc(doc); |
|
|
#endif |
|
|
|
|
|
#ifdef OSM_QND_XML_PARSER |
|
|
osm_t *osm = NULL; |
|
|
if(!(osm = qnd_xml_parse(filename, &root, NULL))) { |
|
|
errorf(NULL, "While parsing \"%s\"", filename); |
|
|
return NULL; |
|
|
} |
|
|
#endif |
|
1066 |
|
|
1067 |
struct timeval end; |
struct timeval end; |
1068 |
gettimeofday(&end, NULL); |
gettimeofday(&end, NULL); |