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

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