Diff of /trunk/src/osm.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 9 by harbaum, Fri Dec 12 20:06:32 2008 UTC revision 54 by harbaum, Fri Feb 6 12:06:30 2009 UTC
# Line 17  Line 17 
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    
20  #define OSM_STREAM_PARSER  /* these defines select one of three possible xml parsers */
21    /* this is in fact selected depending on the plattform in the Makefile */
22    // #define OSM_DOM_PARSER
23    // #define OSM_STREAM_PARSER
24    // #define OSM_QND_XML_PARSER
25    
26  #include <stdio.h>  #include <stdio.h>
27  #include <stdlib.h>  #include <stdlib.h>
# Line 31  Line 35 
35  #include <libxml/tree.h>  #include <libxml/tree.h>
36    
37  #include "appdata.h"  #include "appdata.h"
38    #include "banner.h"
39    
40  #ifndef LIBXML_TREE_ENABLED  #ifndef LIBXML_TREE_ENABLED
41  #error "Tree not enabled in libxml"  #error "Tree not enabled in libxml"
# Line 54  static void osm_bounds_dump(bounds_t *bo Line 59  static void osm_bounds_dump(bounds_t *bo
59           bounds->ll_min.lon, bounds->ll_max.lon);           bounds->ll_min.lon, bounds->ll_max.lon);
60  }  }
61    
62  #ifndef OSM_STREAM_PARSER  #ifdef OSM_DOM_PARSER
63  static bounds_t *osm_parse_osm_bounds(osm_t *osm,  static bounds_t *osm_parse_osm_bounds(osm_t *osm,
64                       xmlDocPtr doc, xmlNode *a_node) {                       xmlDocPtr doc, xmlNode *a_node) {
65    char *prop;    char *prop;
# Line 149  void osm_users_dump(user_t *user) { Line 154  void osm_users_dump(user_t *user) {
154  }  }
155    
156  static user_t *osm_user(osm_t *osm, char *name) {  static user_t *osm_user(osm_t *osm, char *name) {
157      if(!name) return NULL;
158    
159    /* search through user list */    /* search through user list */
160    user_t **user = &osm->user;    user_t **user = &osm->user;
# Line 170  static user_t *osm_user(osm_t *osm, char Line 176  static user_t *osm_user(osm_t *osm, char
176    
177  static  static
178  time_t convert_iso8601(const char *str) {  time_t convert_iso8601(const char *str) {
179      if(!str) return 0;
180    
181    tzset();    tzset();
182    
183    struct tm ctime;    struct tm ctime;
# Line 323  void osm_nodes_dump(node_t *node) { Line 331  void osm_nodes_dump(node_t *node) {
331    }    }
332  }  }
333    
334  #ifndef OSM_STREAM_PARSER  #ifdef OSM_DOM_PARSER
335  static node_t *osm_parse_osm_node(osm_t *osm,  static node_t *osm_parse_osm_node(osm_t *osm,
336                            xmlDocPtr doc, xmlNode *a_node) {                            xmlDocPtr doc, xmlNode *a_node) {
337    xmlNode *cur_node = NULL;    xmlNode *cur_node = NULL;
# Line 363  static node_t *osm_parse_osm_node(osm_t Line 371  static node_t *osm_parse_osm_node(osm_t
371      xmlFree(prop);      xmlFree(prop);
372    }    }
373    
374      /* append node to end of hash table if present */
375      if(osm->node_hash) {
376        hash_item_t **item = &osm->node_hash->hash[ID2HASH(node->id)];
377        while(*item) item = &(*item)->next;
378    
379        *item = g_new0(hash_item_t, 1);
380        (*item)->data.node = node;
381      }
382    
383    /* scan for tags and attach a list of tags */    /* scan for tags and attach a list of tags */
384    tag_t **tag = &node->tag;    tag_t **tag = &node->tag;
385    for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {    for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
# Line 474  node_chain_t *osm_parse_osm_way_nd(osm_t Line 491  node_chain_t *osm_parse_osm_way_nd(osm_t
491      node_chain_t *node_chain = g_new0(node_chain_t, 1);      node_chain_t *node_chain = g_new0(node_chain_t, 1);
492    
493      /* search matching node */      /* search matching node */
494      node_chain->node = osm->node;      node_chain->node = osm_get_node_by_id(osm, id);
     while(node_chain->node && node_chain->node->id != id)  
       node_chain->node = node_chain->node->next;  
   
495      if(!node_chain->node) printf("Node id %lu not found\n", id);      if(!node_chain->node) printf("Node id %lu not found\n", id);
496        else                  node_chain->node->ways++;
     if(node_chain->node)  
       node_chain->node->ways++;  
497    
498      xmlFree(prop);      xmlFree(prop);
499    
# Line 491  node_chain_t *osm_parse_osm_way_nd(osm_t Line 503  node_chain_t *osm_parse_osm_way_nd(osm_t
503    return NULL;    return NULL;
504  }  }
505    
506  #ifndef OSM_STREAM_PARSER  #ifdef OSM_DOM_PARSER
507  static way_t *osm_parse_osm_way(osm_t *osm,  static way_t *osm_parse_osm_way(osm_t *osm,
508                            xmlDocPtr doc, xmlNode *a_node) {                            xmlDocPtr doc, xmlNode *a_node) {
509    xmlNode *cur_node = NULL;    xmlNode *cur_node = NULL;
# Line 520  static way_t *osm_parse_osm_way(osm_t *o Line 532  static way_t *osm_parse_osm_way(osm_t *o
532      xmlFree(prop);      xmlFree(prop);
533    }    }
534    
535      /* append way to end of hash table if present */
536      if(osm->way_hash) {
537        hash_item_t **item = &osm->way_hash->hash[ID2HASH(way->id)];
538        while(*item) item = &(*item)->next;
539    
540        *item = g_new0(hash_item_t, 1);
541        (*item)->data.way = way;
542      }
543    
544    /* scan for tags/nodes and attach their lists */    /* scan for tags/nodes and attach their lists */
545    tag_t **tag = &way->tag;    tag_t **tag = &way->tag;
546    node_chain_t **node_chain = &way->node_chain;    node_chain_t **node_chain = &way->node_chain;
# Line 645  member_t *osm_parse_osm_relation_member( Line 666  member_t *osm_parse_osm_relation_member(
666    
667      case WAY:      case WAY:
668        /* search matching way */        /* search matching way */
669        member->way = osm->way;        member->way = osm_get_way_by_id(osm, id);
       while(member->way && member->way->id != id)  
         member->way = member->way->next;  
   
670        if(!member->way) {        if(!member->way) {
671          member->type = WAY_ID;          member->type = WAY_ID;
672          member->id = id;          member->id = id;
# Line 657  member_t *osm_parse_osm_relation_member( Line 675  member_t *osm_parse_osm_relation_member(
675    
676      case NODE:      case NODE:
677        /* search matching node */        /* search matching node */
678        member->node = osm->node;        member->node = osm_get_node_by_id(osm, id);
       while(member->node && member->node->id != id)  
         member->node = member->node->next;  
   
679        if(!member->node) {        if(!member->node) {
680          member->type = NODE_ID;          member->type = NODE_ID;
681          member->id = id;          member->id = id;
# Line 669  member_t *osm_parse_osm_relation_member( Line 684  member_t *osm_parse_osm_relation_member(
684    
685      case RELATION:      case RELATION:
686        /* search matching relation */        /* search matching relation */
687        member->relation = osm->relation;        member->relation = osm_get_relation_by_id(osm, id);
       while(member->relation && member->relation->id != id)  
         member->relation = member->relation->next;  
   
688        if(!member->relation) {        if(!member->relation) {
689          member->type = NODE_ID;          member->type = NODE_ID;
690          member->id = id;          member->id = id;
# Line 696  member_t *osm_parse_osm_relation_member( Line 708  member_t *osm_parse_osm_relation_member(
708    return member;    return member;
709  }  }
710    
711  #ifndef OSM_STREAM_PARSER  #ifdef OSM_DOM_PARSER
712  static relation_t *osm_parse_osm_relation(osm_t *osm,  static relation_t *osm_parse_osm_relation(osm_t *osm,
713                            xmlDocPtr doc, xmlNode *a_node) {                            xmlDocPtr doc, xmlNode *a_node) {
714    xmlNode *cur_node = NULL;    xmlNode *cur_node = NULL;
# Line 748  static relation_t *osm_parse_osm_relatio Line 760  static relation_t *osm_parse_osm_relatio
760    
761  /* ----------------------- generic xml handling -------------------------- */  /* ----------------------- generic xml handling -------------------------- */
762    
763  /* parse loc entry */  /* parse osm entry */
764  static void osm_parse_osm(osm_t *osm, xmlDocPtr doc, xmlNode * a_node) {  static void osm_parse_osm(osm_t *osm, xmlDocPtr doc, xmlNode * a_node) {
765    xmlNode *cur_node = NULL;    xmlNode *cur_node = NULL;
766    
# Line 830  static osm_t *osm_parse_root(xmlDocPtr d Line 842  static osm_t *osm_parse_root(xmlDocPtr d
842    
843    /* allocate memory to hold osm file description */    /* allocate memory to hold osm file description */
844    osm = g_new0(osm_t, 1);    osm = g_new0(osm_t, 1);
845      osm->node_hash = g_new0(hash_table_t, 1);
846      osm->way_hash = g_new0(hash_table_t, 1);
847    
848    for (cur_node = a_node; cur_node; cur_node = cur_node->next) {    for (cur_node = a_node; cur_node; cur_node = cur_node->next) {
849      if (cur_node->type == XML_ELEMENT_NODE) {      if (cur_node->type == XML_ELEMENT_NODE) {
# Line 867  static osm_t *osm_parse_doc(xmlDocPtr do Line 881  static osm_t *osm_parse_doc(xmlDocPtr do
881    
882  /* ------------------ osm handling ----------------- */  /* ------------------ osm handling ----------------- */
883    
884    /* the two hash tables eat over 512kBytes memory and may thus be */
885    /* freed at any time. osm2go can work without them (albeit slower) */
886    static void hash_table_free(hash_table_t *table) {
887      if(!table) return;
888    
889      int i;
890      for(i=0;i<65536;i++) {
891        hash_item_t *item = table->hash[i];
892        while(item) {
893          hash_item_t *next = item->next;
894          g_free(item);
895          item = next;
896        }
897      }
898    }
899    
900    void osm_hash_tables_free(osm_t *osm) {
901      hash_table_free(osm->node_hash);
902      osm->node_hash = NULL;
903      hash_table_free(osm->way_hash);
904      osm->way_hash = NULL;
905    }
906    
907  void osm_free(icon_t **icon, osm_t *osm) {  void osm_free(icon_t **icon, osm_t *osm) {
908    if(!osm) return;    if(!osm) return;
909    
910      osm_hash_tables_free(osm);
911    
912    if(osm->bounds)   osm_bounds_free(osm->bounds);    if(osm->bounds)   osm_bounds_free(osm->bounds);
913    if(osm->user)     osm_users_free(osm->user);    if(osm->user)     osm_users_free(osm->user);
914    if(osm->way)      osm_ways_free(osm->way);    if(osm->way)      osm_ways_free(osm->way);
# Line 1050  static node_t *process_node(xmlTextReade Line 1089  static node_t *process_node(xmlTextReade
1089    
1090    pos2lpos(osm->bounds, &node->pos, &node->lpos);    pos2lpos(osm->bounds, &node->pos, &node->lpos);
1091    
1092      /* append node to end of hash table if present */
1093      if(osm->node_hash) {
1094        hash_item_t **item = &osm->node_hash->hash[ID2HASH(node->id)];
1095        while(*item) item = &(*item)->next;
1096    
1097        *item = g_new0(hash_item_t, 1);
1098        (*item)->data.node = node;
1099      }
1100    
1101    /* just an empty element? then return the node as it is */    /* just an empty element? then return the node as it is */
1102    if(xmlTextReaderIsEmptyElement(reader))    if(xmlTextReaderIsEmptyElement(reader))
1103      return node;      return node;
# Line 1087  static node_chain_t *process_nd(xmlTextR Line 1135  static node_chain_t *process_nd(xmlTextR
1135      node_chain_t *node_chain = g_new0(node_chain_t, 1);      node_chain_t *node_chain = g_new0(node_chain_t, 1);
1136    
1137      /* search matching node */      /* search matching node */
1138      node_chain->node = osm->node;      node_chain->node = osm_get_node_by_id(osm, id);
     while(node_chain->node && node_chain->node->id != id)  
       node_chain->node = node_chain->node->next;  
   
1139      if(!node_chain->node) printf("Node id %lu not found\n", id);      if(!node_chain->node) printf("Node id %lu not found\n", id);
1140        else                  node_chain->node->ways++;
     if(node_chain->node)  
       node_chain->node->ways++;  
1141    
1142      xmlFree(prop);      xmlFree(prop);
1143    
# Line 1131  static way_t *process_way(xmlTextReaderP Line 1174  static way_t *process_way(xmlTextReaderP
1174      xmlFree(prop);      xmlFree(prop);
1175    }    }
1176    
1177      /* append way to end of hash table if present */
1178      if(osm->way_hash) {
1179        hash_item_t **item = &osm->way_hash->hash[ID2HASH(way->id)];
1180        while(*item) item = &(*item)->next;
1181    
1182        *item = g_new0(hash_item_t, 1);
1183        (*item)->data.way = way;
1184      }
1185    
1186    /* just an empty element? then return the way as it is */    /* just an empty element? then return the way as it is */
1187    /* (this should in fact never happen as this would be a way without nodes) */    /* (this should in fact never happen as this would be a way without nodes) */
1188    if(xmlTextReaderIsEmptyElement(reader))    if(xmlTextReaderIsEmptyElement(reader))
# Line 1186  static member_t *process_member(xmlTextR Line 1238  static member_t *process_member(xmlTextR
1238    
1239      case WAY:      case WAY:
1240        /* search matching way */        /* search matching way */
1241        member->way = osm->way;        member->way = osm_get_way_by_id(osm, id);
       while(member->way && member->way->id != id)  
         member->way = member->way->next;  
   
1242        if(!member->way) {        if(!member->way) {
1243          member->type = WAY_ID;          member->type = WAY_ID;
1244          member->id = id;          member->id = id;
# Line 1198  static member_t *process_member(xmlTextR Line 1247  static member_t *process_member(xmlTextR
1247    
1248      case NODE:      case NODE:
1249        /* search matching node */        /* search matching node */
1250        member->node = osm->node;        member->node = osm_get_node_by_id(osm, id);
       while(member->node && member->node->id != id)  
         member->node = member->node->next;  
   
1251        if(!member->node) {        if(!member->node) {
1252          member->type = NODE_ID;          member->type = NODE_ID;
1253          member->id = id;          member->id = id;
# Line 1210  static member_t *process_member(xmlTextR Line 1256  static member_t *process_member(xmlTextR
1256    
1257      case RELATION:      case RELATION:
1258        /* search matching relation */        /* search matching relation */
1259        member->relation = osm->relation;        member->relation = osm_get_relation_by_id(osm, id);
       while(member->relation && member->relation->id != id)  
         member->relation = member->relation->next;  
   
1260        if(!member->relation) {        if(!member->relation) {
1261          member->type = NODE_ID;          member->type = NODE_ID;
1262          member->id = id;          member->id = id;
# Line 1281  static relation_t *process_relation(xmlT Line 1324  static relation_t *process_relation(xmlT
1324    
1325      if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) {      if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) {
1326        char *subname = (char*)xmlTextReaderConstName(reader);        char *subname = (char*)xmlTextReaderConstName(reader);
1327        if(strcasecmp(subname, "nd") == 0) {        if(strcasecmp(subname, "member") == 0) {
1328          *member = process_member(reader, osm);          *member = process_member(reader, osm);
1329          if(*member) member = &(*member)->next;          if(*member) member = &(*member)->next;
1330        } else if(strcasecmp(subname, "tag") == 0) {        } else if(strcasecmp(subname, "tag") == 0) {
# Line 1299  static relation_t *process_relation(xmlT Line 1342  static relation_t *process_relation(xmlT
1342  static osm_t *process_osm(xmlTextReaderPtr reader) {  static osm_t *process_osm(xmlTextReaderPtr reader) {
1343    /* alloc osm structure */    /* alloc osm structure */
1344    osm_t *osm = g_new0(osm_t, 1);    osm_t *osm = g_new0(osm_t, 1);
1345      osm->node_hash = g_new0(hash_table_t, 1);
1346      osm->way_hash = g_new0(hash_table_t, 1);
1347    
1348    node_t **node = &osm->node;    node_t **node = &osm->node;
1349    way_t **way = &osm->way;    way_t **way = &osm->way;
# Line 1310  static osm_t *process_osm(xmlTextReaderP Line 1355  static osm_t *process_osm(xmlTextReaderP
1355    g_assert(name);    g_assert(name);
1356    
1357    /* read next node */    /* read next node */
1358      int num_elems = 0;
1359      const int tick_every = 50; // Balance responsive appearance with performance.
1360    int ret = xmlTextReaderRead(reader);    int ret = xmlTextReaderRead(reader);
1361    while(ret == 1) {    while(ret == 1) {
1362    
# Line 1346  static osm_t *process_osm(xmlTextReaderP Line 1393  static osm_t *process_osm(xmlTextReaderP
1393        break;        break;
1394      }      }
1395      ret = xmlTextReaderRead(reader);      ret = xmlTextReaderRead(reader);
1396    
1397        if (num_elems++ > tick_every) {
1398          num_elems = 0;
1399          banner_busy_tick();
1400        }
1401    }    }
1402    
1403    g_assert(0);    g_assert(0);
# Line 1377  static osm_t *process_file(const char *f Line 1429  static osm_t *process_file(const char *f
1429  /* ----------------------- end of stream parser tests ------------------- */  /* ----------------------- end of stream parser tests ------------------- */
1430  #endif  #endif
1431    
1432    #ifdef OSM_QND_XML_PARSER
1433    /* -------------------------- qnd-xml parser tests ------------------- */
1434    
1435    #ifdef USE_FLOAT
1436    #define GET_PROP_POS(a,b,c) qnd_xml_get_prop_float(a, b, c)
1437    #else
1438    #define GET_PROP_POS(a,b,c) qnd_xml_get_prop_double(a, b, c)
1439    #endif
1440    
1441    gboolean osm_bounds_cb(qnd_xml_stack_t *stack,
1442                           qnd_xml_attribute_t *attributes, gpointer data) {
1443    
1444      /* get parent pointer */
1445      osm_t *osm = (osm_t*)stack->prev->userdata[0];
1446    
1447      if(osm->bounds) {
1448        errorf(NULL, "Doubly defined bounds");
1449        return FALSE;
1450      }
1451    
1452      bounds_t *bounds = osm->bounds = g_new0(bounds_t, 1);
1453    
1454      bounds->ll_min.lat = bounds->ll_min.lon = NAN;
1455      bounds->ll_max.lat = bounds->ll_max.lon = NAN;
1456    
1457      GET_PROP_POS(attributes, "minlat", &bounds->ll_min.lat);
1458      GET_PROP_POS(attributes, "minlon", &bounds->ll_min.lon);
1459      GET_PROP_POS(attributes, "maxlat", &bounds->ll_max.lat);
1460      GET_PROP_POS(attributes, "maxlon", &bounds->ll_max.lon);
1461    
1462      if(isnan(bounds->ll_min.lat) || isnan(bounds->ll_min.lon) ||
1463         isnan(bounds->ll_max.lat) || isnan(bounds->ll_max.lon)) {
1464        errorf(NULL, "Invalid coordinate in bounds (%f/%f/%f/%f)",
1465               bounds->ll_min.lat, bounds->ll_min.lon,
1466               bounds->ll_max.lat, bounds->ll_max.lon);
1467    
1468        osm_bounds_free(bounds);
1469        osm->bounds = NULL;
1470        return FALSE;
1471      }
1472    
1473    
1474      /* calculate map zone which will be used as a reference for all */
1475      /* drawing/projection later on */
1476      pos_t center = { (bounds->ll_max.lat + bounds->ll_min.lat)/2,
1477                       (bounds->ll_max.lon + bounds->ll_min.lon)/2 };
1478    
1479      pos2lpos_center(&center, &bounds->center);
1480    
1481      /* the scale is needed to accomodate for "streching" */
1482      /* by the mercartor projection */
1483      bounds->scale = cos(DEG2RAD(center.lat));
1484    
1485      pos2lpos_center(&bounds->ll_min, &bounds->min);
1486      bounds->min.x -= bounds->center.x;
1487      bounds->min.y -= bounds->center.y;
1488      bounds->min.x *= bounds->scale;
1489      bounds->min.y *= bounds->scale;
1490    
1491      pos2lpos_center(&bounds->ll_max, &bounds->max);
1492      bounds->max.x -= bounds->center.x;
1493      bounds->max.y -= bounds->center.y;
1494      bounds->max.x *= bounds->scale;
1495      bounds->max.y *= bounds->scale;
1496    
1497      return TRUE;
1498    }
1499    
1500    static gboolean osm_tag_cb(qnd_xml_stack_t *stack,
1501                             qnd_xml_attribute_t *attributes, gpointer data) {
1502    
1503      tag_t *tag = *(tag_t**)stack->prev->userdata[1] = g_new0(tag_t, 1);
1504    
1505      tag->key = qnd_xml_get_prop_str(attributes, "k");
1506      tag->value = qnd_xml_get_prop_str(attributes, "v");
1507    
1508      if(!tag->key || !tag->value) {
1509        printf("incomplete tag key/value %s/%s\n", tag->key, tag->value);
1510        osm_tags_free(tag);
1511        tag = NULL;
1512      } else
1513        stack->prev->userdata[1] = &tag->next;
1514    
1515      return TRUE;
1516    }
1517    
1518    static gboolean osm_node_cb(qnd_xml_stack_t *stack,
1519                         qnd_xml_attribute_t *attributes, gpointer data) {
1520    
1521      osm_t *osm = (osm_t*)stack->prev->userdata[0];
1522    
1523      /* allocate a new node structure. userdata[1] points to the current */
1524      /* position a new node is to be stored */
1525      node_t *node = *(node_t**)stack->prev->userdata[1] =
1526        stack->userdata[0] = g_new0(node_t, 1);
1527      stack->prev->userdata[1] = &node->next;
1528    
1529      qnd_xml_get_prop_gulong(attributes, "id", &node->id);
1530      GET_PROP_POS(attributes, "lat", &node->pos.lat);
1531      GET_PROP_POS(attributes, "lon", &node->pos.lon);
1532      node->user = osm_user(osm, qnd_xml_get_prop(attributes, "user"));
1533      node->visible = qnd_xml_get_prop_is(attributes, "visible", "true");
1534      node->time = convert_iso8601(qnd_xml_get_prop(attributes, "timestamp"));
1535    
1536      pos2lpos(osm->bounds, &node->pos, &node->lpos);
1537    
1538      /* store current tag pointer in userdata for fast access to current tag */
1539      stack->userdata[1] = &node->tag;
1540    
1541      /* append node to end of hash table if present */
1542      if(osm->node_hash) {
1543        hash_item_t **item = &osm->node_hash->hash[ID2HASH(node->id)];
1544        while(*item) item = &(*item)->next;
1545    
1546        *item = g_new0(hash_item_t, 1);
1547        (*item)->data.node = node;
1548      }
1549    
1550      return TRUE;
1551    }
1552    
1553    static gboolean osm_way_nd_cb(qnd_xml_stack_t *stack,
1554                             qnd_xml_attribute_t *attributes, gpointer data) {
1555    
1556      osm_t *osm = (osm_t*)stack->prev->prev->userdata[0];
1557    
1558      item_id_t id;
1559      if(qnd_xml_get_prop_gulong(attributes, "ref", &id)) {
1560        /* allocate a new node_chain structure */
1561        node_chain_t *node_chain = *(node_chain_t**)stack->prev->userdata[2] =
1562          g_new0(node_chain_t, 1);
1563    
1564        /* search matching node */
1565        node_chain->node = osm_get_node_by_id(osm, id);
1566        if(!node_chain->node) printf("Node id %lu not found\n", id);
1567        else                  node_chain->node->ways++;
1568    
1569        stack->prev->userdata[2] = &node_chain->next;
1570      }
1571    
1572      return TRUE;
1573    }
1574    
1575    gboolean osm_way_cb(qnd_xml_stack_t *stack,
1576                        qnd_xml_attribute_t *attributes, gpointer data) {
1577    
1578      osm_t *osm = (osm_t*)stack->prev->userdata[0];
1579    
1580      /* allocate a new way structure. userdata[2] points to the current */
1581      /* position a new way is to be stored in the way list */
1582      way_t *way = *(way_t**)stack->prev->userdata[2] =
1583        stack->userdata[0] = g_new0(way_t, 1);
1584      stack->prev->userdata[2] = &way->next;
1585    
1586      qnd_xml_get_prop_gulong(attributes, "id", &way->id);
1587      way->user = osm_user(osm, qnd_xml_get_prop(attributes, "user"));
1588      way->visible = qnd_xml_get_prop_is(attributes, "visible", "true");
1589      way->time = convert_iso8601(qnd_xml_get_prop(attributes, "timestamp"));
1590    
1591      /* store current tag and node_chain pointers in userdata for fast */
1592      /* access to current tag/node_chain entry */
1593      stack->userdata[1] = &way->tag;
1594      stack->userdata[2] = &way->node_chain;
1595    
1596      /* append way to end of hash table if present */
1597      if(osm->way_hash) {
1598        hash_item_t **item = &osm->way_hash->hash[ID2HASH(way->id)];
1599        while(*item) item = &(*item)->next;
1600    
1601        *item = g_new0(hash_item_t, 1);
1602        (*item)->data.way = way;
1603      }
1604    
1605      return TRUE;
1606    }
1607    
1608    static gboolean osm_rel_member_cb(qnd_xml_stack_t *stack,
1609                             qnd_xml_attribute_t *attributes, gpointer data) {
1610    
1611      osm_t *osm = (osm_t*)stack->prev->prev->userdata[0];
1612    
1613      member_t *member = *(member_t**)stack->prev->userdata[2] =
1614        g_new0(member_t, 1);
1615      stack->prev->userdata[2] = &member->next;
1616      member->type = ILLEGAL;
1617    
1618      char *type = qnd_xml_get_prop(attributes, "type");
1619      if(type) {
1620        if(strcasecmp(type, "way") == 0)           member->type = WAY;
1621        else if(strcasecmp(type, "node") == 0)     member->type = NODE;
1622        else if(strcasecmp(type, "relation") == 0) member->type = RELATION;
1623      }
1624    
1625      item_id_t id;
1626      if(qnd_xml_get_prop_gulong(attributes, "ref", &id)) {
1627        switch(member->type) {
1628        case ILLEGAL:
1629          printf("Unable to store illegal type\n");
1630          break;
1631    
1632        case WAY:
1633          /* search matching way */
1634          member->way = osm_get_way_by_id(osm, id);
1635          if(!member->way) {
1636            member->type = WAY_ID;
1637            member->id = id;
1638          }
1639          break;
1640    
1641        case NODE:
1642          /* search matching node */
1643          member->node = osm_get_node_by_id(osm, id);
1644          if(!member->node) {
1645            member->type = NODE_ID;
1646            member->id = id;
1647          }
1648          break;
1649    
1650        case RELATION:
1651          /* search matching relation */
1652          member->relation = osm_get_relation_by_id(osm, id);
1653          if(!member->relation) {
1654            member->type = NODE_ID;
1655            member->id = id;
1656          }
1657          break;
1658    
1659        case WAY_ID:
1660        case NODE_ID:
1661        case RELATION_ID:
1662          break;
1663        }
1664      }
1665    
1666      return TRUE;
1667    }
1668    
1669    gboolean osm_rel_cb(qnd_xml_stack_t *stack,
1670                        qnd_xml_attribute_t *attributes, gpointer data) {
1671    
1672      osm_t *osm = (osm_t*)stack->prev->userdata[0];
1673    
1674      /* allocate a new relation structure. userdata[3] points to the current */
1675      /* position a new relation is to be stored at in the relation list */
1676      relation_t *relation = *(relation_t**)stack->prev->userdata[3] =
1677        stack->userdata[0] = g_new0(relation_t, 1);
1678      stack->prev->userdata[3] = &relation->next;
1679    
1680      qnd_xml_get_prop_gulong(attributes, "id", &relation->id);
1681      relation->user = osm_user(osm, qnd_xml_get_prop(attributes, "user"));
1682      relation->visible = qnd_xml_get_prop_is(attributes, "visible", "true");
1683      relation->time = convert_iso8601(qnd_xml_get_prop(attributes, "timestamp"));
1684    
1685      /* store current tag and member pointers in userdata for fast access */
1686      /* to current tag and members in their chains */
1687      stack->userdata[1] = &relation->tag;
1688      stack->userdata[2] = &relation->member;
1689    
1690      return TRUE;
1691    }
1692    
1693    gboolean osm_cb(qnd_xml_stack_t *stack,
1694                    qnd_xml_attribute_t *attributes, gpointer data) {
1695    
1696      g_assert(!stack->userdata[0]);
1697    
1698      /* also set parents (roots) userdata as it's the parsers return value */
1699      osm_t *osm = stack->prev->userdata[0] =
1700        stack->userdata[0] = g_new0(osm_t, 1);
1701    
1702      osm->node_hash = g_new0(hash_table_t, 1);
1703      osm->way_hash = g_new0(hash_table_t, 1);
1704    
1705      /* store direct pointers for faster list access */
1706      /* (otherwise we'd have to search the end of the lists for every item */
1707      /* to be attached) */
1708      stack->userdata[1] = &osm->node;
1709      stack->userdata[2] = &osm->way;
1710      stack->userdata[3] = &osm->relation;
1711    
1712      return TRUE;
1713    }
1714    
1715    
1716    /* these structures describe the content qnd_xml expects while parsing */
1717    qnd_xml_entry_t osm_node_tag = { "tag", osm_tag_cb, QND_XML_LEAF };
1718    
1719    qnd_xml_entry_t osm_way_tag = { "tag", osm_tag_cb, QND_XML_LEAF };
1720    qnd_xml_entry_t osm_way_nd = { "nd", osm_way_nd_cb, QND_XML_LEAF };
1721    
1722    qnd_xml_entry_t osm_rel_tag = { "tag", osm_tag_cb, QND_XML_LEAF };
1723    qnd_xml_entry_t osm_rel_member = { "member", osm_rel_member_cb, QND_XML_LEAF };
1724    
1725    qnd_xml_entry_t osm_bounds = { "bounds", osm_bounds_cb, QND_XML_LEAF };
1726    
1727    qnd_xml_entry_t *node_children[] = { &osm_node_tag },
1728      osm_node = { "node", osm_node_cb, QND_XML_CHILDREN(node_children) };
1729    
1730    qnd_xml_entry_t *way_children[] = { &osm_way_tag, &osm_way_nd },
1731      osm_way = { "way", osm_way_cb, QND_XML_CHILDREN(way_children) };
1732    
1733    qnd_xml_entry_t *rel_children[] = { &osm_rel_tag, &osm_rel_member },
1734      osm_rel = { "rel", osm_rel_cb, QND_XML_CHILDREN(rel_children) };
1735    
1736    /* the osm element */
1737    qnd_xml_entry_t *osm_children[] = {
1738      &osm_bounds, &osm_node, &osm_way, &osm_rel };
1739    qnd_xml_entry_t osm = { "osm", osm_cb, QND_XML_CHILDREN(osm_children) };
1740    
1741    /* the root element */
1742    qnd_xml_entry_t *root_children[] = { &osm };
1743    qnd_xml_entry_t root = { "<root>", NULL, QND_XML_CHILDREN(root_children) };
1744    
1745    // gcc `pkg-config --cflags --libs glib-2.0` -o qnd_xml qnd_xml.c
1746    
1747    
1748    
1749    /* ----------------------- end of qnd-xml parser tests ------------------- */
1750    #endif
1751    
1752    
1753  #include <sys/time.h>  #include <sys/time.h>
1754    
1755  osm_t *osm_parse(char *filename) {  osm_t *osm_parse(char *filename) {
# Line 1384  osm_t *osm_parse(char *filename) { Line 1757  osm_t *osm_parse(char *filename) {
1757    struct timeval start;    struct timeval start;
1758    gettimeofday(&start, NULL);    gettimeofday(&start, NULL);
1759    
1760    #ifdef OSM_STREAM_PARSER
1761    LIBXML_TEST_VERSION;    LIBXML_TEST_VERSION;
1762    
 #ifdef OSM_STREAM_PARSER  
1763    // use stream parser    // use stream parser
1764    osm_t *osm = process_file(filename);    osm_t *osm = process_file(filename);
1765    xmlCleanupParser();    xmlCleanupParser();
1766    #endif
1767    
1768    #ifdef OSM_DOM_PARSER
1769      LIBXML_TEST_VERSION;
1770    
 #else  
1771    // parse into a tree    // parse into a tree
1772    /* parse the file and get the DOM */    /* parse the file and get the DOM */
1773    xmlDoc *doc = NULL;    xmlDoc *doc = NULL;
# Line 1404  osm_t *osm_parse(char *filename) { Line 1780  osm_t *osm_parse(char *filename) {
1780    osm_t *osm = osm_parse_doc(doc);    osm_t *osm = osm_parse_doc(doc);
1781  #endif  #endif
1782    
1783    #ifdef OSM_QND_XML_PARSER
1784      osm_t *osm = NULL;
1785      if(!(osm = qnd_xml_parse(filename, &root, NULL))) {
1786        errorf(NULL, "While parsing \"%s\"", filename);
1787        return NULL;
1788      }
1789    #endif
1790    
1791    struct timeval end;    struct timeval end;
1792    gettimeofday(&end, NULL);    gettimeofday(&end, NULL);
1793    
# Line 1662  char *osm_generate_xml_relation(osm_t *o Line 2046  char *osm_generate_xml_relation(osm_t *o
2046    return osm_generate_xml(osm, RELATION, relation);    return osm_generate_xml(osm, RELATION, relation);
2047  }  }
2048    
2049    /* the following three functions are eating much CPU power */
2050    /* as they search the objects lists. Hashing is supposed to help */
2051  node_t *osm_get_node_by_id(osm_t *osm, item_id_t id) {  node_t *osm_get_node_by_id(osm_t *osm, item_id_t id) {
2052      if(id > 0 && osm->node_hash) {
2053        // use hash table if present
2054        hash_item_t *item = osm->node_hash->hash[ID2HASH(id)];
2055        while(item) {
2056          if(item->data.node->id == id)
2057            return item->data.node;
2058    
2059          item = item->next;
2060        }
2061      }
2062    
2063      /* use linear search if no hash tables are present or search in hash table failed */
2064    node_t *node = osm->node;    node_t *node = osm->node;
2065    while(node) {    while(node) {
2066      if(node->id == id)      if(node->id == id)
2067        return node;        return node;
2068    
2069      node = node->next;      node = node->next;
2070    }    }
2071    
2072    return NULL;    return NULL;
2073  }  }
2074    
2075  way_t *osm_get_way_by_id(osm_t *osm, item_id_t id) {  way_t *osm_get_way_by_id(osm_t *osm, item_id_t id) {
2076      if(id > 0 && osm->way_hash) {
2077        // use hash table if present
2078        hash_item_t *item = osm->way_hash->hash[ID2HASH(id)];
2079        while(item) {
2080          if(item->data.way->id == id)
2081            return item->data.way;
2082    
2083          item = item->next;
2084        }
2085      }
2086    
2087      /* use linear search if no hash tables are present or search on hash table failed */
2088    way_t *way = osm->way;    way_t *way = osm->way;
2089    while(way) {    while(way) {
2090      if(way->id == id)      if(way->id == id)
2091        return way;        return way;
2092    
2093      way = way->next;      way = way->next;
2094    }    }
2095    
2096    return NULL;    return NULL;
2097  }  }
2098    
2099  relation_t *osm_get_relation_by_id(osm_t *osm, item_id_t id) {  relation_t *osm_get_relation_by_id(osm_t *osm, item_id_t id) {
2100      // use linear search
2101    relation_t *relation = osm->relation;    relation_t *relation = osm->relation;
2102    while(relation) {    while(relation) {
2103      if(relation->id == id)      if(relation->id == id)
# Line 2192  tag_t *osm_tags_copy(tag_t *src_tag, gbo Line 2605  tag_t *osm_tags_copy(tag_t *src_tag, gbo
2605    
2606    return new_tags;    return new_tags;
2607  }  }
2608    
2609    /* return plain text of type */
2610    char *osm_type_string(type_t type) {
2611      const struct { type_t type; char *name; } types[] = {
2612        { ILLEGAL,     "illegal" },
2613        { NODE,        "node" },
2614        { WAY,         "way" },
2615        { RELATION,    "relation" },
2616        { NODE_ID,     "node id" },
2617        { WAY_ID,      "way id" },
2618        { RELATION_ID, "relation id" },
2619        { 0, NULL }
2620      };
2621    
2622      int i;
2623      for(i=0;types[i].name;i++)
2624        if(type == types[i].type)
2625          return types[i].name;
2626    
2627      return NULL;
2628    }
2629    
2630    
2631    // vim:et:ts=8:sw=2:sts=2:ai

Legend:
Removed from v.9  
changed lines
  Added in v.54