Diff of /trunk/src/osm.c

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

revision 35 by achadwick, Wed Dec 31 17:26:59 2008 UTC revision 75 by harbaum, Thu Feb 12 19:58:20 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 55  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 150  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 171  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 324  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 364  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 475  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 492  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 521  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 559  void osm_members_free(member_t *member) Line 578  void osm_members_free(member_t *member)
578    }    }
579  }  }
580    
581    void osm_relation_free(relation_t *relation) {
582      osm_tags_free(relation->tag);
583      osm_members_free(relation->member);
584    
585      g_free(relation);
586    }
587    
588  static void osm_relations_free(relation_t *relation) {  static void osm_relations_free(relation_t *relation) {
589    while(relation) {    while(relation) {
590      relation_t *next = relation->next;      relation_t *next = relation->next;
591        osm_relation_free(relation);
     osm_tags_free(relation->tag);  
     osm_members_free(relation->member);  
   
     g_free(relation);  
592      relation = next;      relation = next;
593    }    }
594  }  }
# Line 646  member_t *osm_parse_osm_relation_member( Line 668  member_t *osm_parse_osm_relation_member(
668    
669      case WAY:      case WAY:
670        /* search matching way */        /* search matching way */
671        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;  
   
672        if(!member->way) {        if(!member->way) {
673          member->type = WAY_ID;          member->type = WAY_ID;
674          member->id = id;          member->id = id;
# Line 658  member_t *osm_parse_osm_relation_member( Line 677  member_t *osm_parse_osm_relation_member(
677    
678      case NODE:      case NODE:
679        /* search matching node */        /* search matching node */
680        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;  
   
681        if(!member->node) {        if(!member->node) {
682          member->type = NODE_ID;          member->type = NODE_ID;
683          member->id = id;          member->id = id;
# Line 670  member_t *osm_parse_osm_relation_member( Line 686  member_t *osm_parse_osm_relation_member(
686    
687      case RELATION:      case RELATION:
688        /* search matching relation */        /* search matching relation */
689        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;  
   
690        if(!member->relation) {        if(!member->relation) {
691          member->type = NODE_ID;          member->type = NODE_ID;
692          member->id = id;          member->id = id;
# Line 697  member_t *osm_parse_osm_relation_member( Line 710  member_t *osm_parse_osm_relation_member(
710    return member;    return member;
711  }  }
712    
713  #ifndef OSM_STREAM_PARSER  #ifdef OSM_DOM_PARSER
714  static relation_t *osm_parse_osm_relation(osm_t *osm,  static relation_t *osm_parse_osm_relation(osm_t *osm,
715                            xmlDocPtr doc, xmlNode *a_node) {                            xmlDocPtr doc, xmlNode *a_node) {
716    xmlNode *cur_node = NULL;    xmlNode *cur_node = NULL;
# Line 749  static relation_t *osm_parse_osm_relatio Line 762  static relation_t *osm_parse_osm_relatio
762    
763  /* ----------------------- generic xml handling -------------------------- */  /* ----------------------- generic xml handling -------------------------- */
764    
765  /* parse loc entry */  /* parse osm entry */
766  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) {
767    xmlNode *cur_node = NULL;    xmlNode *cur_node = NULL;
768    
# Line 831  static osm_t *osm_parse_root(xmlDocPtr d Line 844  static osm_t *osm_parse_root(xmlDocPtr d
844    
845    /* allocate memory to hold osm file description */    /* allocate memory to hold osm file description */
846    osm = g_new0(osm_t, 1);    osm = g_new0(osm_t, 1);
847      osm->node_hash = g_new0(hash_table_t, 1);
848      osm->way_hash = g_new0(hash_table_t, 1);
849    
850    for (cur_node = a_node; cur_node; cur_node = cur_node->next) {    for (cur_node = a_node; cur_node; cur_node = cur_node->next) {
851      if (cur_node->type == XML_ELEMENT_NODE) {      if (cur_node->type == XML_ELEMENT_NODE) {
# Line 868  static osm_t *osm_parse_doc(xmlDocPtr do Line 883  static osm_t *osm_parse_doc(xmlDocPtr do
883    
884  /* ------------------ osm handling ----------------- */  /* ------------------ osm handling ----------------- */
885    
886    /* the two hash tables eat over 512kBytes memory and may thus be */
887    /* freed at any time. osm2go can work without them (albeit slower) */
888    static void hash_table_free(hash_table_t *table) {
889      if(!table) return;
890    
891      int i;
892      for(i=0;i<65536;i++) {
893        hash_item_t *item = table->hash[i];
894        while(item) {
895          hash_item_t *next = item->next;
896          g_free(item);
897          item = next;
898        }
899      }
900    }
901    
902    void osm_hash_tables_free(osm_t *osm) {
903      hash_table_free(osm->node_hash);
904      osm->node_hash = NULL;
905      hash_table_free(osm->way_hash);
906      osm->way_hash = NULL;
907    }
908    
909  void osm_free(icon_t **icon, osm_t *osm) {  void osm_free(icon_t **icon, osm_t *osm) {
910    if(!osm) return;    if(!osm) return;
911    
912      osm_hash_tables_free(osm);
913    
914    if(osm->bounds)   osm_bounds_free(osm->bounds);    if(osm->bounds)   osm_bounds_free(osm->bounds);
915    if(osm->user)     osm_users_free(osm->user);    if(osm->user)     osm_users_free(osm->user);
916    if(osm->way)      osm_ways_free(osm->way);    if(osm->way)      osm_ways_free(osm->way);
# Line 1051  static node_t *process_node(xmlTextReade Line 1091  static node_t *process_node(xmlTextReade
1091    
1092    pos2lpos(osm->bounds, &node->pos, &node->lpos);    pos2lpos(osm->bounds, &node->pos, &node->lpos);
1093    
1094      /* append node to end of hash table if present */
1095      if(osm->node_hash) {
1096        hash_item_t **item = &osm->node_hash->hash[ID2HASH(node->id)];
1097        while(*item) item = &(*item)->next;
1098    
1099        *item = g_new0(hash_item_t, 1);
1100        (*item)->data.node = node;
1101      }
1102    
1103    /* just an empty element? then return the node as it is */    /* just an empty element? then return the node as it is */
1104    if(xmlTextReaderIsEmptyElement(reader))    if(xmlTextReaderIsEmptyElement(reader))
1105      return node;      return node;
# Line 1088  static node_chain_t *process_nd(xmlTextR Line 1137  static node_chain_t *process_nd(xmlTextR
1137      node_chain_t *node_chain = g_new0(node_chain_t, 1);      node_chain_t *node_chain = g_new0(node_chain_t, 1);
1138    
1139      /* search matching node */      /* search matching node */
1140      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;  
   
1141      if(!node_chain->node) printf("Node id %lu not found\n", id);      if(!node_chain->node) printf("Node id %lu not found\n", id);
1142        else                  node_chain->node->ways++;
     if(node_chain->node)  
       node_chain->node->ways++;  
1143    
1144      xmlFree(prop);      xmlFree(prop);
1145    
# Line 1132  static way_t *process_way(xmlTextReaderP Line 1176  static way_t *process_way(xmlTextReaderP
1176      xmlFree(prop);      xmlFree(prop);
1177    }    }
1178    
1179      /* append way to end of hash table if present */
1180      if(osm->way_hash) {
1181        hash_item_t **item = &osm->way_hash->hash[ID2HASH(way->id)];
1182        while(*item) item = &(*item)->next;
1183    
1184        *item = g_new0(hash_item_t, 1);
1185        (*item)->data.way = way;
1186      }
1187    
1188    /* just an empty element? then return the way as it is */    /* just an empty element? then return the way as it is */
1189    /* (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) */
1190    if(xmlTextReaderIsEmptyElement(reader))    if(xmlTextReaderIsEmptyElement(reader))
# Line 1187  static member_t *process_member(xmlTextR Line 1240  static member_t *process_member(xmlTextR
1240    
1241      case WAY:      case WAY:
1242        /* search matching way */        /* search matching way */
1243        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;  
   
1244        if(!member->way) {        if(!member->way) {
1245          member->type = WAY_ID;          member->type = WAY_ID;
1246          member->id = id;          member->id = id;
# Line 1199  static member_t *process_member(xmlTextR Line 1249  static member_t *process_member(xmlTextR
1249    
1250      case NODE:      case NODE:
1251        /* search matching node */        /* search matching node */
1252        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;  
   
1253        if(!member->node) {        if(!member->node) {
1254          member->type = NODE_ID;          member->type = NODE_ID;
1255          member->id = id;          member->id = id;
# Line 1211  static member_t *process_member(xmlTextR Line 1258  static member_t *process_member(xmlTextR
1258    
1259      case RELATION:      case RELATION:
1260        /* search matching relation */        /* search matching relation */
1261        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;  
   
1262        if(!member->relation) {        if(!member->relation) {
1263          member->type = NODE_ID;          member->type = NODE_ID;
1264          member->id = id;          member->id = id;
# Line 1300  static relation_t *process_relation(xmlT Line 1344  static relation_t *process_relation(xmlT
1344  static osm_t *process_osm(xmlTextReaderPtr reader) {  static osm_t *process_osm(xmlTextReaderPtr reader) {
1345    /* alloc osm structure */    /* alloc osm structure */
1346    osm_t *osm = g_new0(osm_t, 1);    osm_t *osm = g_new0(osm_t, 1);
1347      osm->node_hash = g_new0(hash_table_t, 1);
1348      osm->way_hash = g_new0(hash_table_t, 1);
1349    
1350    node_t **node = &osm->node;    node_t **node = &osm->node;
1351    way_t **way = &osm->way;    way_t **way = &osm->way;
# Line 1385  static osm_t *process_file(const char *f Line 1431  static osm_t *process_file(const char *f
1431  /* ----------------------- end of stream parser tests ------------------- */  /* ----------------------- end of stream parser tests ------------------- */
1432  #endif  #endif
1433    
1434    #ifdef OSM_QND_XML_PARSER
1435    /* -------------------------- qnd-xml parser tests ------------------- */
1436    
1437    #ifdef USE_FLOAT
1438    #define GET_PROP_POS(a,b,c) qnd_xml_get_prop_float(a, b, c)
1439    #else
1440    #define GET_PROP_POS(a,b,c) qnd_xml_get_prop_double(a, b, c)
1441    #endif
1442    
1443    gboolean osm_bounds_cb(qnd_xml_stack_t *stack,
1444                           qnd_xml_attribute_t *attributes, gpointer data) {
1445    
1446      /* get parent pointer */
1447      osm_t *osm = (osm_t*)stack->prev->userdata[0];
1448    
1449      if(osm->bounds) {
1450        errorf(NULL, "Doubly defined bounds");
1451        return FALSE;
1452      }
1453    
1454      bounds_t *bounds = osm->bounds = g_new0(bounds_t, 1);
1455    
1456      bounds->ll_min.lat = bounds->ll_min.lon = NAN;
1457      bounds->ll_max.lat = bounds->ll_max.lon = NAN;
1458    
1459      GET_PROP_POS(attributes, "minlat", &bounds->ll_min.lat);
1460      GET_PROP_POS(attributes, "minlon", &bounds->ll_min.lon);
1461      GET_PROP_POS(attributes, "maxlat", &bounds->ll_max.lat);
1462      GET_PROP_POS(attributes, "maxlon", &bounds->ll_max.lon);
1463    
1464      if(isnan(bounds->ll_min.lat) || isnan(bounds->ll_min.lon) ||
1465         isnan(bounds->ll_max.lat) || isnan(bounds->ll_max.lon)) {
1466        errorf(NULL, "Invalid coordinate in bounds (%f/%f/%f/%f)",
1467               bounds->ll_min.lat, bounds->ll_min.lon,
1468               bounds->ll_max.lat, bounds->ll_max.lon);
1469    
1470        osm_bounds_free(bounds);
1471        osm->bounds = NULL;
1472        return FALSE;
1473      }
1474    
1475    
1476      /* calculate map zone which will be used as a reference for all */
1477      /* drawing/projection later on */
1478      pos_t center = { (bounds->ll_max.lat + bounds->ll_min.lat)/2,
1479                       (bounds->ll_max.lon + bounds->ll_min.lon)/2 };
1480    
1481      pos2lpos_center(&center, &bounds->center);
1482    
1483      /* the scale is needed to accomodate for "streching" */
1484      /* by the mercartor projection */
1485      bounds->scale = cos(DEG2RAD(center.lat));
1486    
1487      pos2lpos_center(&bounds->ll_min, &bounds->min);
1488      bounds->min.x -= bounds->center.x;
1489      bounds->min.y -= bounds->center.y;
1490      bounds->min.x *= bounds->scale;
1491      bounds->min.y *= bounds->scale;
1492    
1493      pos2lpos_center(&bounds->ll_max, &bounds->max);
1494      bounds->max.x -= bounds->center.x;
1495      bounds->max.y -= bounds->center.y;
1496      bounds->max.x *= bounds->scale;
1497      bounds->max.y *= bounds->scale;
1498    
1499      return TRUE;
1500    }
1501    
1502    static gboolean osm_tag_cb(qnd_xml_stack_t *stack,
1503                             qnd_xml_attribute_t *attributes, gpointer data) {
1504    
1505      tag_t *tag = *(tag_t**)stack->prev->userdata[1] = g_new0(tag_t, 1);
1506    
1507      tag->key = qnd_xml_get_prop_str(attributes, "k");
1508      tag->value = qnd_xml_get_prop_str(attributes, "v");
1509    
1510      if(!tag->key || !tag->value) {
1511        printf("incomplete tag key/value %s/%s\n", tag->key, tag->value);
1512        osm_tags_free(tag);
1513        tag = NULL;
1514      } else
1515        stack->prev->userdata[1] = &tag->next;
1516    
1517      return TRUE;
1518    }
1519    
1520    static gboolean osm_node_cb(qnd_xml_stack_t *stack,
1521                         qnd_xml_attribute_t *attributes, gpointer data) {
1522    
1523      osm_t *osm = (osm_t*)stack->prev->userdata[0];
1524    
1525      /* allocate a new node structure. userdata[1] points to the current */
1526      /* position a new node is to be stored */
1527      node_t *node = *(node_t**)stack->prev->userdata[1] =
1528        stack->userdata[0] = g_new0(node_t, 1);
1529      stack->prev->userdata[1] = &node->next;
1530    
1531      qnd_xml_get_prop_gulong(attributes, "id", &node->id);
1532      GET_PROP_POS(attributes, "lat", &node->pos.lat);
1533      GET_PROP_POS(attributes, "lon", &node->pos.lon);
1534      node->user = osm_user(osm, qnd_xml_get_prop(attributes, "user"));
1535      node->visible = qnd_xml_get_prop_is(attributes, "visible", "true");
1536      node->time = convert_iso8601(qnd_xml_get_prop(attributes, "timestamp"));
1537    
1538      pos2lpos(osm->bounds, &node->pos, &node->lpos);
1539    
1540      /* store current tag pointer in userdata for fast access to current tag */
1541      stack->userdata[1] = &node->tag;
1542    
1543      /* append node to end of hash table if present */
1544      if(osm->node_hash) {
1545        hash_item_t **item = &osm->node_hash->hash[ID2HASH(node->id)];
1546        while(*item) item = &(*item)->next;
1547    
1548        *item = g_new0(hash_item_t, 1);
1549        (*item)->data.node = node;
1550      }
1551    
1552      return TRUE;
1553    }
1554    
1555    static gboolean osm_way_nd_cb(qnd_xml_stack_t *stack,
1556                             qnd_xml_attribute_t *attributes, gpointer data) {
1557    
1558      osm_t *osm = (osm_t*)stack->prev->prev->userdata[0];
1559    
1560      item_id_t id;
1561      if(qnd_xml_get_prop_gulong(attributes, "ref", &id)) {
1562        /* allocate a new node_chain structure */
1563        node_chain_t *node_chain = *(node_chain_t**)stack->prev->userdata[2] =
1564          g_new0(node_chain_t, 1);
1565    
1566        /* search matching node */
1567        node_chain->node = osm_get_node_by_id(osm, id);
1568        if(!node_chain->node) printf("Node id %lu not found\n", id);
1569        else                  node_chain->node->ways++;
1570    
1571        stack->prev->userdata[2] = &node_chain->next;
1572      }
1573    
1574      return TRUE;
1575    }
1576    
1577    gboolean osm_way_cb(qnd_xml_stack_t *stack,
1578                        qnd_xml_attribute_t *attributes, gpointer data) {
1579    
1580      osm_t *osm = (osm_t*)stack->prev->userdata[0];
1581    
1582      /* allocate a new way structure. userdata[2] points to the current */
1583      /* position a new way is to be stored in the way list */
1584      way_t *way = *(way_t**)stack->prev->userdata[2] =
1585        stack->userdata[0] = g_new0(way_t, 1);
1586      stack->prev->userdata[2] = &way->next;
1587    
1588      qnd_xml_get_prop_gulong(attributes, "id", &way->id);
1589      way->user = osm_user(osm, qnd_xml_get_prop(attributes, "user"));
1590      way->visible = qnd_xml_get_prop_is(attributes, "visible", "true");
1591      way->time = convert_iso8601(qnd_xml_get_prop(attributes, "timestamp"));
1592    
1593      /* store current tag and node_chain pointers in userdata for fast */
1594      /* access to current tag/node_chain entry */
1595      stack->userdata[1] = &way->tag;
1596      stack->userdata[2] = &way->node_chain;
1597    
1598      /* append way to end of hash table if present */
1599      if(osm->way_hash) {
1600        hash_item_t **item = &osm->way_hash->hash[ID2HASH(way->id)];
1601        while(*item) item = &(*item)->next;
1602    
1603        *item = g_new0(hash_item_t, 1);
1604        (*item)->data.way = way;
1605      }
1606    
1607      return TRUE;
1608    }
1609    
1610    static gboolean osm_rel_member_cb(qnd_xml_stack_t *stack,
1611                             qnd_xml_attribute_t *attributes, gpointer data) {
1612    
1613      osm_t *osm = (osm_t*)stack->prev->prev->userdata[0];
1614    
1615      member_t *member = *(member_t**)stack->prev->userdata[2] =
1616        g_new0(member_t, 1);
1617      stack->prev->userdata[2] = &member->next;
1618      member->type = ILLEGAL;
1619    
1620      char *type = qnd_xml_get_prop(attributes, "type");
1621      if(type) {
1622        if(strcasecmp(type, "way") == 0)           member->type = WAY;
1623        else if(strcasecmp(type, "node") == 0)     member->type = NODE;
1624        else if(strcasecmp(type, "relation") == 0) member->type = RELATION;
1625      }
1626    
1627      item_id_t id;
1628      if(qnd_xml_get_prop_gulong(attributes, "ref", &id)) {
1629        switch(member->type) {
1630        case ILLEGAL:
1631          printf("Unable to store illegal type\n");
1632          break;
1633    
1634        case WAY:
1635          /* search matching way */
1636          member->way = osm_get_way_by_id(osm, id);
1637          if(!member->way) {
1638            member->type = WAY_ID;
1639            member->id = id;
1640          }
1641          break;
1642    
1643        case NODE:
1644          /* search matching node */
1645          member->node = osm_get_node_by_id(osm, id);
1646          if(!member->node) {
1647            member->type = NODE_ID;
1648            member->id = id;
1649          }
1650          break;
1651    
1652        case RELATION:
1653          /* search matching relation */
1654          member->relation = osm_get_relation_by_id(osm, id);
1655          if(!member->relation) {
1656            member->type = NODE_ID;
1657            member->id = id;
1658          }
1659          break;
1660    
1661        case WAY_ID:
1662        case NODE_ID:
1663        case RELATION_ID:
1664          break;
1665        }
1666      }
1667    
1668      return TRUE;
1669    }
1670    
1671    gboolean osm_rel_cb(qnd_xml_stack_t *stack,
1672                        qnd_xml_attribute_t *attributes, gpointer data) {
1673    
1674      osm_t *osm = (osm_t*)stack->prev->userdata[0];
1675    
1676      /* allocate a new relation structure. userdata[3] points to the current */
1677      /* position a new relation is to be stored at in the relation list */
1678      relation_t *relation = *(relation_t**)stack->prev->userdata[3] =
1679        stack->userdata[0] = g_new0(relation_t, 1);
1680      stack->prev->userdata[3] = &relation->next;
1681    
1682      qnd_xml_get_prop_gulong(attributes, "id", &relation->id);
1683      relation->user = osm_user(osm, qnd_xml_get_prop(attributes, "user"));
1684      relation->visible = qnd_xml_get_prop_is(attributes, "visible", "true");
1685      relation->time = convert_iso8601(qnd_xml_get_prop(attributes, "timestamp"));
1686    
1687      /* store current tag and member pointers in userdata for fast access */
1688      /* to current tag and members in their chains */
1689      stack->userdata[1] = &relation->tag;
1690      stack->userdata[2] = &relation->member;
1691    
1692      return TRUE;
1693    }
1694    
1695    gboolean osm_cb(qnd_xml_stack_t *stack,
1696                    qnd_xml_attribute_t *attributes, gpointer data) {
1697    
1698      g_assert(!stack->userdata[0]);
1699    
1700      /* also set parents (roots) userdata as it's the parsers return value */
1701      osm_t *osm = stack->prev->userdata[0] =
1702        stack->userdata[0] = g_new0(osm_t, 1);
1703    
1704      osm->node_hash = g_new0(hash_table_t, 1);
1705      osm->way_hash = g_new0(hash_table_t, 1);
1706    
1707      /* store direct pointers for faster list access */
1708      /* (otherwise we'd have to search the end of the lists for every item */
1709      /* to be attached) */
1710      stack->userdata[1] = &osm->node;
1711      stack->userdata[2] = &osm->way;
1712      stack->userdata[3] = &osm->relation;
1713    
1714      return TRUE;
1715    }
1716    
1717    
1718    /* these structures describe the content qnd_xml expects while parsing */
1719    qnd_xml_entry_t osm_node_tag = { "tag", osm_tag_cb, QND_XML_LEAF };
1720    
1721    qnd_xml_entry_t osm_way_tag = { "tag", osm_tag_cb, QND_XML_LEAF };
1722    qnd_xml_entry_t osm_way_nd = { "nd", osm_way_nd_cb, QND_XML_LEAF };
1723    
1724    qnd_xml_entry_t osm_rel_tag = { "tag", osm_tag_cb, QND_XML_LEAF };
1725    qnd_xml_entry_t osm_rel_member = { "member", osm_rel_member_cb, QND_XML_LEAF };
1726    
1727    qnd_xml_entry_t osm_bounds = { "bounds", osm_bounds_cb, QND_XML_LEAF };
1728    
1729    qnd_xml_entry_t *node_children[] = { &osm_node_tag },
1730      osm_node = { "node", osm_node_cb, QND_XML_CHILDREN(node_children) };
1731    
1732    qnd_xml_entry_t *way_children[] = { &osm_way_tag, &osm_way_nd },
1733      osm_way = { "way", osm_way_cb, QND_XML_CHILDREN(way_children) };
1734    
1735    qnd_xml_entry_t *rel_children[] = { &osm_rel_tag, &osm_rel_member },
1736      osm_rel = { "rel", osm_rel_cb, QND_XML_CHILDREN(rel_children) };
1737    
1738    /* the osm element */
1739    qnd_xml_entry_t *osm_children[] = {
1740      &osm_bounds, &osm_node, &osm_way, &osm_rel };
1741    qnd_xml_entry_t osm = { "osm", osm_cb, QND_XML_CHILDREN(osm_children) };
1742    
1743    /* the root element */
1744    qnd_xml_entry_t *root_children[] = { &osm };
1745    qnd_xml_entry_t root = { "<root>", NULL, QND_XML_CHILDREN(root_children) };
1746    
1747    // gcc `pkg-config --cflags --libs glib-2.0` -o qnd_xml qnd_xml.c
1748    
1749    
1750    
1751    /* ----------------------- end of qnd-xml parser tests ------------------- */
1752    #endif
1753    
1754    
1755  #include <sys/time.h>  #include <sys/time.h>
1756    
1757  osm_t *osm_parse(char *filename) {  osm_t *osm_parse(char *filename) {
# Line 1392  osm_t *osm_parse(char *filename) { Line 1759  osm_t *osm_parse(char *filename) {
1759    struct timeval start;    struct timeval start;
1760    gettimeofday(&start, NULL);    gettimeofday(&start, NULL);
1761    
1762    #ifdef OSM_STREAM_PARSER
1763    LIBXML_TEST_VERSION;    LIBXML_TEST_VERSION;
1764    
 #ifdef OSM_STREAM_PARSER  
1765    // use stream parser    // use stream parser
1766    osm_t *osm = process_file(filename);    osm_t *osm = process_file(filename);
1767    xmlCleanupParser();    xmlCleanupParser();
1768    #endif
1769    
1770    #ifdef OSM_DOM_PARSER
1771      LIBXML_TEST_VERSION;
1772    
 #else  
1773    // parse into a tree    // parse into a tree
1774    /* parse the file and get the DOM */    /* parse the file and get the DOM */
1775    xmlDoc *doc = NULL;    xmlDoc *doc = NULL;
# Line 1412  osm_t *osm_parse(char *filename) { Line 1782  osm_t *osm_parse(char *filename) {
1782    osm_t *osm = osm_parse_doc(doc);    osm_t *osm = osm_parse_doc(doc);
1783  #endif  #endif
1784    
1785    #ifdef OSM_QND_XML_PARSER
1786      osm_t *osm = NULL;
1787      if(!(osm = qnd_xml_parse(filename, &root, NULL))) {
1788        errorf(NULL, "While parsing \"%s\"", filename);
1789        return NULL;
1790      }
1791    #endif
1792    
1793    struct timeval end;    struct timeval end;
1794    gettimeofday(&end, NULL);    gettimeofday(&end, NULL);
1795    
# Line 1670  char *osm_generate_xml_relation(osm_t *o Line 2048  char *osm_generate_xml_relation(osm_t *o
2048    return osm_generate_xml(osm, RELATION, relation);    return osm_generate_xml(osm, RELATION, relation);
2049  }  }
2050    
2051    /* the following three functions are eating much CPU power */
2052    /* as they search the objects lists. Hashing is supposed to help */
2053  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) {
2054      if(id > 0 && osm->node_hash) {
2055        // use hash table if present
2056        hash_item_t *item = osm->node_hash->hash[ID2HASH(id)];
2057        while(item) {
2058          if(item->data.node->id == id)
2059            return item->data.node;
2060    
2061          item = item->next;
2062        }
2063      }
2064    
2065      /* use linear search if no hash tables are present or search in hash table failed */
2066    node_t *node = osm->node;    node_t *node = osm->node;
2067    while(node) {    while(node) {
2068      if(node->id == id)      if(node->id == id)
2069        return node;        return node;
2070    
2071      node = node->next;      node = node->next;
2072    }    }
2073    
2074    return NULL;    return NULL;
2075  }  }
2076    
2077  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) {
2078      if(id > 0 && osm->way_hash) {
2079        // use hash table if present
2080        hash_item_t *item = osm->way_hash->hash[ID2HASH(id)];
2081        while(item) {
2082          if(item->data.way->id == id)
2083            return item->data.way;
2084    
2085          item = item->next;
2086        }
2087      }
2088    
2089      /* use linear search if no hash tables are present or search on hash table failed */
2090    way_t *way = osm->way;    way_t *way = osm->way;
2091    while(way) {    while(way) {
2092      if(way->id == id)      if(way->id == id)
2093        return way;        return way;
2094    
2095      way = way->next;      way = way->next;
2096    }    }
2097    
2098    return NULL;    return NULL;
2099  }  }
2100    
2101  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) {
2102      // use linear search
2103    relation_t *relation = osm->relation;    relation_t *relation = osm->relation;
2104    while(relation) {    while(relation) {
2105      if(relation->id == id)      if(relation->id == id)
# Line 1750  item_id_t osm_new_node_id(osm_t *osm) { Line 2157  item_id_t osm_new_node_id(osm_t *osm) {
2157    return 0;    return 0;
2158  }  }
2159    
2160    item_id_t osm_new_relation_id(osm_t *osm) {
2161      item_id_t id = -1;
2162    
2163      while(TRUE) {
2164        gboolean found = FALSE;
2165        relation_t *relation = osm->relation;
2166        while(relation) {
2167          if(relation->id == id)
2168            found = TRUE;
2169    
2170          relation = relation->next;
2171        }
2172    
2173        /* no such id so far -> use it */
2174        if(!found) return id;
2175    
2176        id--;
2177      }
2178      g_assert(0);
2179      return 0;
2180    }
2181    
2182  node_t *osm_node_new(osm_t *osm, gint x, gint y) {  node_t *osm_node_new(osm_t *osm, gint x, gint y) {
2183    printf("Creating new node\n");    printf("Creating new node\n");
2184    
# Line 1786  void osm_node_attach(osm_t *osm, node_t Line 2215  void osm_node_attach(osm_t *osm, node_t
2215    *lnode = node;    *lnode = node;
2216  }  }
2217    
2218    void osm_node_restore(osm_t *osm, node_t *node) {
2219      printf("Restoring node\n");
2220    
2221      /* attach to end of node list */
2222      node_t **lnode = &osm->node;
2223      while(*lnode) lnode = &(*lnode)->next;
2224      *lnode = node;
2225    }
2226    
2227  way_t *osm_way_new(void) {  way_t *osm_way_new(void) {
2228    printf("Creating new way\n");    printf("Creating new way\n");
2229    
# Line 2062  void osm_way_remove_from_relation(osm_t Line 2500  void osm_way_remove_from_relation(osm_t
2500    }    }
2501  }  }
2502    
2503    relation_t *osm_relation_new(void) {
2504      printf("Creating new relation\n");
2505    
2506      relation_t *relation = g_new0(relation_t, 1);
2507      relation->visible = TRUE;
2508      relation->flags = OSM_FLAG_NEW;
2509      relation->time = time(NULL);
2510    
2511      /* add created_by tag */
2512      relation->tag = g_new0(tag_t, 1);
2513      relation->tag->key = g_strdup("created_by");
2514      relation->tag->value = g_strdup(PACKAGE " v" VERSION);
2515    
2516      return relation;
2517    }
2518    
2519    void osm_relation_attach(osm_t *osm, relation_t *relation) {
2520      printf("Attaching relation\n");
2521    
2522      relation->id = osm_new_relation_id(osm);
2523      relation->flags = OSM_FLAG_NEW;
2524    
2525      /* attach to end of relation list */
2526      relation_t **lrelation = &osm->relation;
2527      while(*lrelation) lrelation = &(*lrelation)->next;
2528      *lrelation = relation;
2529    }
2530    
2531    
2532  void osm_way_delete(osm_t *osm, icon_t **icon,  void osm_way_delete(osm_t *osm, icon_t **icon,
2533                      way_t *way, gboolean permanently) {                      way_t *way, gboolean permanently) {
2534    
# Line 2125  void osm_way_delete(osm_t *osm, icon_t * Line 2592  void osm_way_delete(osm_t *osm, icon_t *
2592    }    }
2593  }  }
2594    
2595    void osm_relation_delete(osm_t *osm, relation_t *relation,
2596                             gboolean permanently) {
2597    
2598      /* new relations aren't stored on the server and are just */
2599      /* deleted permanently */
2600      if(relation->flags & OSM_FLAG_NEW) {
2601        printf("About to delete NEW relation #%ld -> force permanent delete\n",
2602               relation->id);
2603        permanently = TRUE;
2604      }
2605    
2606      /* the deletion of a relation doesn't affect the members as they */
2607      /* don't have any reference to the relation they are part of */
2608    
2609      if(!permanently) {
2610        printf("mark relation #%ld as deleted\n", relation->id);
2611        relation->flags |= OSM_FLAG_DELETED;
2612      } else {
2613        printf("permanently delete relation #%ld\n", relation->id);
2614    
2615        /* remove it from the chain */
2616        relation_t **crelation = &osm->relation;
2617        int found = 0;
2618    
2619        while(*crelation) {
2620          if(*crelation == relation) {
2621            found++;
2622            *crelation = (*crelation)->next;
2623    
2624            osm_relation_free(relation);
2625          } else
2626            crelation = &((*crelation)->next);
2627        }
2628        g_assert(found == 1);
2629      }
2630    }
2631    
2632  void osm_way_revert(way_t *way) {  void osm_way_revert(way_t *way) {
2633    node_chain_t *new = NULL;    node_chain_t *new = NULL;
2634    
# Line 2200  tag_t *osm_tags_copy(tag_t *src_tag, gbo Line 2704  tag_t *osm_tags_copy(tag_t *src_tag, gbo
2704    
2705    return new_tags;    return new_tags;
2706  }  }
2707    
2708    /* return plain text of type */
2709    char *osm_type_string(type_t type) {
2710      const struct { type_t type; char *name; } types[] = {
2711        { ILLEGAL,     "illegal" },
2712        { NODE,        "node" },
2713        { WAY,         "way" },
2714        { RELATION,    "relation" },
2715        { NODE_ID,     "node id" },
2716        { WAY_ID,      "way id" },
2717        { RELATION_ID, "relation id" },
2718        { 0, NULL }
2719      };
2720    
2721      int i;
2722      for(i=0;types[i].name;i++)
2723        if(type == types[i].type)
2724          return types[i].name;
2725    
2726      return NULL;
2727    }
2728    
2729    char *osm_object_string(type_t type, void *object) {
2730      char *type_str = osm_type_string(type);
2731    
2732      if(!object)
2733        return g_strdup_printf("%s #<invalid>", type_str);
2734    
2735      switch(type) {
2736      case ILLEGAL:
2737        return g_strdup_printf("%s #<unspec>", type_str);
2738        break;
2739      case NODE:
2740        return g_strdup_printf("%s #%ld", type_str, ((node_t*)object)->id);
2741        break;
2742      case WAY:
2743        return g_strdup_printf("%s #%ld", type_str, ((way_t*)object)->id);
2744        break;
2745      case RELATION:
2746        return g_strdup_printf("%s #%ld", type_str, ((relation_t*)object)->id);
2747        break;
2748      case NODE_ID:
2749      case WAY_ID:
2750      case RELATION_ID:
2751        return g_strdup_printf("%s #%ld", type_str, *((item_id_t*)object));
2752        break;
2753      }
2754      return NULL;
2755    }
2756    
2757  // vim:et:ts=8:sw=2:sts=2:ai  // vim:et:ts=8:sw=2:sts=2:ai

Legend:
Removed from v.35  
changed lines
  Added in v.75