Diff of /trunk/src/osm.c

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

revision 6 by achadwick, Thu Dec 11 13:26:13 2008 UTC revision 42 by harbaum, Wed Jan 21 20:01:18 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    /* 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>
28  #include <string.h>  #include <string.h>
# Line 29  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 40  Line 47 
47  #define OSM_SORT_LAST  #define OSM_SORT_LAST
48  // #define OSM_SORT_FIRST  // #define OSM_SORT_FIRST
49    
50  /* ------------------------- user handling --------------------- */  /* ------------------------- bounds handling --------------------- */
51    
52  static void osm_bounds_free(bounds_t *bounds) {  static void osm_bounds_free(bounds_t *bounds) {
53    free(bounds);    free(bounds);
# Line 52  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    #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 92  static bounds_t *osm_parse_osm_bounds(os Line 100  static bounds_t *osm_parse_osm_bounds(os
100             bounds->ll_min.lat, bounds->ll_min.lon,             bounds->ll_min.lat, bounds->ll_min.lon,
101             bounds->ll_max.lat, bounds->ll_max.lon);             bounds->ll_max.lat, bounds->ll_max.lon);
102    
103      g_free(bounds);      osm_bounds_free(bounds);
104      return NULL;      return NULL;
105    }    }
106    
# Line 122  static bounds_t *osm_parse_osm_bounds(os Line 130  static bounds_t *osm_parse_osm_bounds(os
130    
131    return bounds;    return bounds;
132  }  }
133    #endif
134    
135  /* ------------------------- user handling --------------------- */  /* ------------------------- user handling --------------------- */
136    
# Line 145  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 166  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 319  void osm_nodes_dump(node_t *node) { Line 331  void osm_nodes_dump(node_t *node) {
331    }    }
332  }  }
333    
334    #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 358  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 375  static node_t *osm_parse_osm_node(osm_t Line 397  static node_t *osm_parse_osm_node(osm_t
397    
398    return node;    return node;
399  }  }
400    #endif
401    
402  /* ------------------- way handling ------------------- */  /* ------------------- way handling ------------------- */
403    
# Line 468  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 485  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    #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 513  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 534  static way_t *osm_parse_osm_way(osm_t *o Line 562  static way_t *osm_parse_osm_way(osm_t *o
562    
563    return way;    return way;
564  }  }
565    #endif
566    
567  /* ------------------- relation handling ------------------- */  /* ------------------- relation handling ------------------- */
568    
# Line 637  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 649  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 661  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 688  member_t *osm_parse_osm_relation_member( Line 708  member_t *osm_parse_osm_relation_member(
708    return member;    return member;
709  }  }
710    
711    #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 739  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 821  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 854  static osm_t *osm_parse_doc(xmlDocPtr do Line 877  static osm_t *osm_parse_doc(xmlDocPtr do
877    
878    return osm;    return osm;
879  }  }
880    #endif
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 876  void osm_dump(osm_t *osm) { Line 925  void osm_dump(osm_t *osm) {
925    osm_relations_dump(osm->relation);    osm_relations_dump(osm->relation);
926  }  }
927    
928  osm_t *osm_parse(char *filename) {  #ifdef OSM_STREAM_PARSER
929    xmlDoc *doc = NULL;  /* -------------------------- stream parser tests ------------------- */
930    
931    LIBXML_TEST_VERSION;  #include <libxml/xmlreader.h>
932    
933    /* parse the file and get the DOM */  static gint my_strcmp(const xmlChar *a, const xmlChar *b) {
934    if ((doc = xmlReadFile(filename, NULL, 0)) == NULL) {    if(!a && !b) return 0;
935      xmlErrorPtr errP = xmlGetLastError();    if(!a) return -1;
936      errorf(NULL, "While parsing \"%s\":\n\n%s", filename, errP->message);    if(!b) return +1;
937      return NULL;    return strcmp((char*)a,(char*)b);
938    }
939    
940    /* skip current element incl. everything below (mainly for testing) */
941    /* returns FALSE if something failed */
942    static gboolean skip_element(xmlTextReaderPtr reader) {
943      g_assert(xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT);
944      const xmlChar *name = xmlTextReaderConstName(reader);
945      g_assert(name);
946      int depth = xmlTextReaderDepth(reader);
947    
948      if(xmlTextReaderIsEmptyElement(reader))
949        return TRUE;
950    
951      int ret = xmlTextReaderRead(reader);
952      while((ret == 1) &&
953            ((xmlTextReaderNodeType(reader) != XML_READER_TYPE_END_ELEMENT) ||
954             (xmlTextReaderDepth(reader) > depth) ||
955             (my_strcmp(xmlTextReaderConstName(reader), name) != 0))) {
956        ret = xmlTextReaderRead(reader);
957      }
958      return(ret == 1);
959    }
960    
961    /* parse bounds */
962    static bounds_t *process_bounds(xmlTextReaderPtr reader) {
963      char *prop = NULL;
964      bounds_t *bounds = g_new0(bounds_t, 1);
965    
966      bounds->ll_min.lat = bounds->ll_min.lon = NAN;
967      bounds->ll_max.lat = bounds->ll_max.lon = NAN;
968    
969      if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "minlat"))) {
970        bounds->ll_min.lat = g_ascii_strtod(prop, NULL);
971        xmlFree(prop);
972    }    }
   
   return osm_parse_doc(doc);  
 }  
973    
974  gboolean osm_sanity_check(GtkWidget *parent, osm_t *osm) {    if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "maxlat"))) {
975    if(!osm->bounds) {      bounds->ll_max.lat = g_ascii_strtod(prop, NULL);
976      errorf(parent, _("Invalid data in OSM file:\n"      xmlFree(prop);
                      "Boundary box missing!"));  
     return FALSE;  
977    }    }
978    if(!osm->node) {  
979      errorf(parent, _("Invalid data in OSM file:\n"    if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "minlon"))) {
980                       "No drawable content found!"));      bounds->ll_min.lon = g_ascii_strtod(prop, NULL);
981      return FALSE;      xmlFree(prop);
982    }    }
983    return TRUE;  
984      if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "maxlon"))) {
985        bounds->ll_max.lon = g_ascii_strtod(prop, NULL);
986        xmlFree(prop);
987      }
988    
989      if(isnan(bounds->ll_min.lat) || isnan(bounds->ll_min.lon) ||
990         isnan(bounds->ll_max.lat) || isnan(bounds->ll_max.lon)) {
991        errorf(NULL, "Invalid coordinate in bounds (%f/%f/%f/%f)",
992               bounds->ll_min.lat, bounds->ll_min.lon,
993               bounds->ll_max.lat, bounds->ll_max.lon);
994    
995        osm_bounds_free(bounds);
996        return NULL;
997      }
998    
999      /* skip everything below */
1000      skip_element(reader);
1001    
1002      /* calculate map zone which will be used as a reference for all */
1003      /* drawing/projection later on */
1004      pos_t center = { (bounds->ll_max.lat + bounds->ll_min.lat)/2,
1005                       (bounds->ll_max.lon + bounds->ll_min.lon)/2 };
1006    
1007      pos2lpos_center(&center, &bounds->center);
1008    
1009      /* the scale is needed to accomodate for "streching" */
1010      /* by the mercartor projection */
1011      bounds->scale = cos(DEG2RAD(center.lat));
1012    
1013      pos2lpos_center(&bounds->ll_min, &bounds->min);
1014      bounds->min.x -= bounds->center.x;
1015      bounds->min.y -= bounds->center.y;
1016      bounds->min.x *= bounds->scale;
1017      bounds->min.y *= bounds->scale;
1018    
1019      pos2lpos_center(&bounds->ll_max, &bounds->max);
1020      bounds->max.x -= bounds->center.x;
1021      bounds->max.y -= bounds->center.y;
1022      bounds->max.x *= bounds->scale;
1023      bounds->max.y *= bounds->scale;
1024    
1025      return bounds;
1026  }  }
1027    
1028  /* ------------------------- misc access functions -------------- */  static tag_t *process_tag(xmlTextReaderPtr reader) {
1029      /* allocate a new tag structure */
1030      tag_t *tag = g_new0(tag_t, 1);
1031    
1032  char *osm_tag_get_by_key(tag_t *tag, char *key) {    char *prop;
1033    if(!tag || !key) return NULL;    if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "k"))) {
1034        if(strlen(prop) > 0) tag->key = g_strdup(prop);
1035        xmlFree(prop);
1036      }
1037    
1038    while(tag) {    if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "v"))) {
1039      if(strcasecmp(tag->key, key) == 0)      if(strlen(prop) > 0) tag->value = g_strdup(prop);
1040        return tag->value;      xmlFree(prop);
1041      }
1042    
1043      tag = tag->next;    if(!tag->key || !tag->value) {
1044        printf("incomplete tag key/value %s/%s\n", tag->key, tag->value);
1045        osm_tags_free(tag);
1046        tag = NULL;
1047    }    }
1048    
1049    return NULL;    skip_element(reader);
1050      return tag;
1051  }  }
1052    
1053  char *osm_way_get_value(way_t *way, char *key) {  static node_t *process_node(xmlTextReaderPtr reader, osm_t *osm) {
   tag_t *tag = way->tag;  
1054    
1055    while(tag) {    /* allocate a new node structure */
1056      if(strcasecmp(tag->key, key) == 0)    node_t *node = g_new0(node_t, 1);
1057        return tag->value;    node->pos.lat = node->pos.lon = NAN;
1058    
1059      tag = tag->next;    char *prop;
1060      if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "id"))) {
1061        node->id = strtoul(prop, NULL, 10);
1062        xmlFree(prop);
1063    }    }
1064    
1065    return NULL;    if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "lat"))) {
1066  }      node->pos.lat = g_ascii_strtod(prop, NULL);
1067        xmlFree(prop);
1068      }
1069    
1070  char *osm_node_get_value(node_t *node, char *key) {    if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "lon"))) {
1071    tag_t *tag = node->tag;      node->pos.lon = g_ascii_strtod(prop, NULL);
1072        xmlFree(prop);
1073      }
1074    
1075    while(tag) {    if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "user"))) {
1076      if(strcasecmp(tag->key, key) == 0)      node->user = osm_user(osm, prop);
1077        return tag->value;      xmlFree(prop);
1078      }
1079    
1080      tag = tag->next;    if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "visible"))) {
1081        node->visible = (strcasecmp(prop, "true") == 0);
1082        xmlFree(prop);
1083    }    }
1084    
1085    return NULL;    if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "timestamp"))) {
1086  }      node->time = convert_iso8601(prop);
1087        xmlFree(prop);
1088      }
1089    
1090  gboolean osm_way_has_value(way_t *way, char *str) {    pos2lpos(osm->bounds, &node->pos, &node->lpos);
   tag_t *tag = way->tag;  
1091    
1092    while(tag) {    /* append node to end of hash table if present */
1093      if(tag->value && strcasecmp(tag->value, str) == 0)    if(osm->node_hash) {
1094        return TRUE;      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      tag = tag->next;    /* just an empty element? then return the node as it is */
1102      if(xmlTextReaderIsEmptyElement(reader))
1103        return node;
1104    
1105      /* parse tags if present */
1106      int depth = xmlTextReaderDepth(reader);
1107    
1108      /* scan all elements on same level or its children */
1109      tag_t **tag = &node->tag;
1110      int ret = xmlTextReaderRead(reader);
1111      while((ret == 1) &&
1112            ((xmlTextReaderNodeType(reader) != XML_READER_TYPE_END_ELEMENT) ||
1113             (xmlTextReaderDepth(reader) != depth))) {
1114    
1115        if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) {
1116          char *subname = (char*)xmlTextReaderConstName(reader);
1117          if(strcasecmp(subname, "tag") == 0) {
1118            *tag = process_tag(reader);
1119            if(*tag) tag = &(*tag)->next;
1120          } else
1121            skip_element(reader);
1122        }
1123    
1124        ret = xmlTextReaderRead(reader);
1125    }    }
1126    return FALSE;  
1127      return node;
1128  }  }
1129    
1130  gboolean osm_node_has_value(node_t *node, char *str) {  static node_chain_t *process_nd(xmlTextReaderPtr reader, osm_t *osm) {
1131    tag_t *tag = node->tag;    char *prop;
1132    
1133    while(tag) {    if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "ref"))) {
1134      if(tag->value && strcasecmp(tag->value, str) == 0)      item_id_t id = strtoul(prop, NULL, 10);
1135        return TRUE;      node_chain_t *node_chain = g_new0(node_chain_t, 1);
1136    
1137        /* search matching node */
1138        node_chain->node = osm_get_node_by_id(osm, id);
1139        if(!node_chain->node) printf("Node id %lu not found\n", id);
1140        else                  node_chain->node->ways++;
1141    
1142      tag = tag->next;      xmlFree(prop);
1143    
1144        skip_element(reader);
1145        return node_chain;
1146    }    }
1147    return FALSE;  
1148      skip_element(reader);
1149      return NULL;
1150  }  }
1151    
1152  gboolean osm_node_has_tag(node_t *node) {  static way_t *process_way(xmlTextReaderPtr reader, osm_t *osm) {
1153    tag_t *tag = node->tag;    /* allocate a new way structure */
1154      way_t *way = g_new0(way_t, 1);
1155    
1156    if(tag && strcasecmp(tag->key, "created_by") == 0)    char *prop;
1157      tag = tag->next;    if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "id"))) {
1158        way->id = strtoul(prop, NULL, 10);
1159        xmlFree(prop);
1160      }
1161    
1162    return tag != NULL;    if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "user"))) {
1163  }      way->user = osm_user(osm, prop);
1164        xmlFree(prop);
1165      }
1166    
1167  /* return true if node is part of way */    if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "visible"))) {
1168  gboolean osm_node_in_way(way_t *way, node_t *node) {      way->visible = (strcasecmp(prop, "true") == 0);
1169    node_chain_t *node_chain = way->node_chain;      xmlFree(prop);
1170    while(node_chain) {    }
     if(node_chain->node == node)  
       return TRUE;  
1171    
1172      node_chain = node_chain->next;    if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "timestamp"))) {
1173        way->time = convert_iso8601(prop);
1174        xmlFree(prop);
1175    }    }
   return FALSE;  
 }  
1176    
1177  static void osm_generate_tags(tag_t *tag, xmlNodePtr node) {    /* append way to end of hash table if present */
1178    while(tag) {    if(osm->way_hash) {
1179      /* make sure "created_by" tag contains our id */      hash_item_t **item = &osm->way_hash->hash[ID2HASH(way->id)];
1180      if(strcasecmp(tag->key, "created_by") == 0) {      while(*item) item = &(*item)->next;
1181        g_free(tag->value);  
1182        tag->value = g_strdup(PACKAGE " v" VERSION);      *item = g_new0(hash_item_t, 1);
1183      }      (*item)->data.way = way;
1184      }
1185    
1186      xmlNodePtr tag_node = xmlNewChild(node, NULL, BAD_CAST "tag", NULL);    /* just an empty element? then return the way as it is */
1187      xmlNewProp(tag_node, BAD_CAST "k", BAD_CAST tag->key);    /* (this should in fact never happen as this would be a way without nodes) */
1188      xmlNewProp(tag_node, BAD_CAST "v", BAD_CAST tag->value);    if(xmlTextReaderIsEmptyElement(reader))
1189      tag = tag->next;      return way;
1190    
1191      /* parse tags/nodes if present */
1192      int depth = xmlTextReaderDepth(reader);
1193    
1194      /* scan all elements on same level or its children */
1195      tag_t **tag = &way->tag;
1196      node_chain_t **node_chain = &way->node_chain;
1197      int ret = xmlTextReaderRead(reader);
1198      while((ret == 1) &&
1199            ((xmlTextReaderNodeType(reader) != XML_READER_TYPE_END_ELEMENT) ||
1200             (xmlTextReaderDepth(reader) != depth))) {
1201    
1202        if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) {
1203          char *subname = (char*)xmlTextReaderConstName(reader);
1204          if(strcasecmp(subname, "nd") == 0) {
1205            *node_chain = process_nd(reader, osm);
1206            if(*node_chain) node_chain = &(*node_chain)->next;
1207          } else if(strcasecmp(subname, "tag") == 0) {
1208            *tag = process_tag(reader);
1209            if(*tag) tag = &(*tag)->next;
1210          } else
1211            skip_element(reader);
1212        }
1213        ret = xmlTextReaderRead(reader);
1214    }    }
1215    
1216      return way;
1217  }  }
1218    
1219  /* build xml representation for a way */  static member_t *process_member(xmlTextReaderPtr reader, osm_t *osm) {
1220  char *osm_generate_xml(osm_t *osm, type_t type, void *item) {    char *prop;
1221    char str[32];    member_t *member = g_new0(member_t, 1);
1222    xmlChar *result = NULL;    member->type = ILLEGAL;
   int len = 0;  
1223    
1224    LIBXML_TEST_VERSION;    if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "type"))) {
1225        if(strcasecmp(prop, "way") == 0)           member->type = WAY;
1226        else if(strcasecmp(prop, "node") == 0)     member->type = NODE;
1227        else if(strcasecmp(prop, "relation") == 0) member->type = RELATION;
1228        xmlFree(prop);
1229      }
1230    
1231    xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");    if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "ref"))) {
1232    xmlNodePtr root_node = xmlNewNode(NULL, BAD_CAST "osm");      item_id_t id = strtoul(prop, NULL, 10);
1233    xmlNewProp(root_node, BAD_CAST "version", BAD_CAST "0.5");  
1234        switch(member->type) {
1235        case ILLEGAL:
1236          printf("Unable to store illegal type\n");
1237          break;
1238    
1239        case WAY:
1240          /* search matching way */
1241          member->way = osm_get_way_by_id(osm, id);
1242          if(!member->way) {
1243            member->type = WAY_ID;
1244            member->id = id;
1245          }
1246          break;
1247    
1248        case NODE:
1249          /* search matching node */
1250          member->node = osm_get_node_by_id(osm, id);
1251          if(!member->node) {
1252            member->type = NODE_ID;
1253            member->id = id;
1254          }
1255          break;
1256    
1257        case RELATION:
1258          /* search matching relation */
1259          member->relation = osm_get_relation_by_id(osm, id);
1260          if(!member->relation) {
1261            member->type = NODE_ID;
1262            member->id = id;
1263          }
1264          break;
1265    
1266        case WAY_ID:
1267        case NODE_ID:
1268        case RELATION_ID:
1269          break;
1270        }
1271    
1272        xmlFree(prop);
1273      }
1274    
1275      if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "role"))) {
1276        if(strlen(prop) > 0) member->role = g_strdup(prop);
1277        xmlFree(prop);
1278      }
1279    
1280      return member;
1281    }
1282    
1283    static relation_t *process_relation(xmlTextReaderPtr reader, osm_t *osm) {
1284      /* allocate a new relation structure */
1285      relation_t *relation = g_new0(relation_t, 1);
1286    
1287      char *prop;
1288      if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "id"))) {
1289        relation->id = strtoul(prop, NULL, 10);
1290        xmlFree(prop);
1291      }
1292    
1293      if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "user"))) {
1294        relation->user = osm_user(osm, prop);
1295        xmlFree(prop);
1296      }
1297    
1298      if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "visible"))) {
1299        relation->visible = (strcasecmp(prop, "true") == 0);
1300        xmlFree(prop);
1301      }
1302    
1303      if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "timestamp"))) {
1304        relation->time = convert_iso8601(prop);
1305        xmlFree(prop);
1306      }
1307    
1308      /* just an empty element? then return the relation as it is */
1309      /* (this should in fact never happen as this would be a relation */
1310      /* without members) */
1311      if(xmlTextReaderIsEmptyElement(reader))
1312        return relation;
1313    
1314      /* parse tags/member if present */
1315      int depth = xmlTextReaderDepth(reader);
1316    
1317      /* scan all elements on same level or its children */
1318      tag_t **tag = &relation->tag;
1319      member_t **member = &relation->member;
1320      int ret = xmlTextReaderRead(reader);
1321      while((ret == 1) &&
1322            ((xmlTextReaderNodeType(reader) != XML_READER_TYPE_END_ELEMENT) ||
1323             (xmlTextReaderDepth(reader) != depth))) {
1324    
1325        if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) {
1326          char *subname = (char*)xmlTextReaderConstName(reader);
1327          if(strcasecmp(subname, "member") == 0) {
1328            *member = process_member(reader, osm);
1329            if(*member) member = &(*member)->next;
1330          } else if(strcasecmp(subname, "tag") == 0) {
1331            *tag = process_tag(reader);
1332            if(*tag) tag = &(*tag)->next;
1333          } else
1334            skip_element(reader);
1335        }
1336        ret = xmlTextReaderRead(reader);
1337      }
1338    
1339      return relation;
1340    }
1341    
1342    static osm_t *process_osm(xmlTextReaderPtr reader) {
1343      /* alloc osm structure */
1344      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;
1349      way_t **way = &osm->way;
1350      relation_t **relation = &osm->relation;
1351    
1352      /* no attributes of interest */
1353    
1354      const xmlChar *name = xmlTextReaderConstName(reader);
1355      g_assert(name);
1356    
1357      /* read next node */
1358      int num_elems = 0;
1359      const int tick_every = 50; // Balance responsive appearance with performance.
1360      int ret = xmlTextReaderRead(reader);
1361      while(ret == 1) {
1362    
1363        switch(xmlTextReaderNodeType(reader)) {
1364        case XML_READER_TYPE_ELEMENT:
1365    
1366          g_assert(xmlTextReaderDepth(reader) == 1);
1367          char *name = (char*)xmlTextReaderConstName(reader);
1368          if(strcasecmp(name, "bounds") == 0) {
1369            osm->bounds = process_bounds(reader);
1370          } else if(strcasecmp(name, "node") == 0) {
1371            *node = process_node(reader, osm);
1372            if(*node) node = &(*node)->next;
1373          } else if(strcasecmp(name, "way") == 0) {
1374            *way = process_way(reader, osm);
1375            if(*way) way = &(*way)->next;
1376          } else if(strcasecmp(name, "relation") == 0) {
1377            *relation = process_relation(reader, osm);
1378            if(*relation) relation = &(*relation)->next;
1379          } else {
1380            printf("something unknown found\n");
1381            g_assert(0);
1382            skip_element(reader);
1383          }
1384          break;
1385    
1386        case XML_READER_TYPE_END_ELEMENT:
1387          /* end element must be for the current element */
1388          g_assert(xmlTextReaderDepth(reader) == 0);
1389          return osm;
1390          break;
1391    
1392        default:
1393          break;
1394        }
1395        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);
1404      return NULL;
1405    }
1406    
1407    static osm_t *process_file(const char *filename) {
1408      osm_t *osm = NULL;
1409      xmlTextReaderPtr reader;
1410      int ret;
1411    
1412      reader = xmlReaderForFile(filename, NULL, 0);
1413      if (reader != NULL) {
1414        ret = xmlTextReaderRead(reader);
1415        if(ret == 1) {
1416          char *name = (char*)xmlTextReaderConstName(reader);
1417          if(name && strcasecmp(name, "osm") == 0)
1418            osm = process_osm(reader);
1419        } else
1420          printf("file empty\n");
1421    
1422        xmlFreeTextReader(reader);
1423      } else {
1424        fprintf(stderr, "Unable to open %s\n", filename);
1425      }
1426      return osm;
1427    }
1428    
1429    /* ----------------------- end of stream parser tests ------------------- */
1430    #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>
1754    
1755    osm_t *osm_parse(char *filename) {
1756    
1757      struct timeval start;
1758      gettimeofday(&start, NULL);
1759    
1760    #ifdef OSM_STREAM_PARSER
1761      LIBXML_TEST_VERSION;
1762    
1763      // use stream parser
1764      osm_t *osm = process_file(filename);
1765      xmlCleanupParser();
1766    #endif
1767    
1768    #ifdef OSM_DOM_PARSER
1769      LIBXML_TEST_VERSION;
1770    
1771      // parse into a tree
1772      /* parse the file and get the DOM */
1773      xmlDoc *doc = NULL;
1774      if ((doc = xmlReadFile(filename, NULL, 0)) == NULL) {
1775        xmlErrorPtr errP = xmlGetLastError();
1776        errorf(NULL, "While parsing \"%s\":\n\n%s", filename, errP->message);
1777        return NULL;
1778      }
1779    
1780      osm_t *osm = osm_parse_doc(doc);
1781    #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;
1792      gettimeofday(&end, NULL);
1793    
1794      printf("total parse time: %ldms\n",
1795             (end.tv_usec - start.tv_usec)/1000 +
1796             (end.tv_sec - start.tv_sec)*1000);
1797    
1798      return osm;
1799    }
1800    
1801    gboolean osm_sanity_check(GtkWidget *parent, osm_t *osm) {
1802      if(!osm->bounds) {
1803        errorf(parent, _("Invalid data in OSM file:\n"
1804                         "Boundary box missing!"));
1805        return FALSE;
1806      }
1807      if(!osm->node) {
1808        errorf(parent, _("Invalid data in OSM file:\n"
1809                         "No drawable content found!"));
1810        return FALSE;
1811      }
1812      return TRUE;
1813    }
1814    
1815    /* ------------------------- misc access functions -------------- */
1816    
1817    char *osm_tag_get_by_key(tag_t *tag, char *key) {
1818      if(!tag || !key) return NULL;
1819    
1820      while(tag) {
1821        if(strcasecmp(tag->key, key) == 0)
1822          return tag->value;
1823    
1824        tag = tag->next;
1825      }
1826    
1827      return NULL;
1828    }
1829    
1830    char *osm_way_get_value(way_t *way, char *key) {
1831      tag_t *tag = way->tag;
1832    
1833      while(tag) {
1834        if(strcasecmp(tag->key, key) == 0)
1835          return tag->value;
1836    
1837        tag = tag->next;
1838      }
1839    
1840      return NULL;
1841    }
1842    
1843    char *osm_node_get_value(node_t *node, char *key) {
1844      tag_t *tag = node->tag;
1845    
1846      while(tag) {
1847        if(strcasecmp(tag->key, key) == 0)
1848          return tag->value;
1849    
1850        tag = tag->next;
1851      }
1852    
1853      return NULL;
1854    }
1855    
1856    gboolean osm_way_has_value(way_t *way, char *str) {
1857      tag_t *tag = way->tag;
1858    
1859      while(tag) {
1860        if(tag->value && strcasecmp(tag->value, str) == 0)
1861          return TRUE;
1862    
1863        tag = tag->next;
1864      }
1865      return FALSE;
1866    }
1867    
1868    gboolean osm_node_has_value(node_t *node, char *str) {
1869      tag_t *tag = node->tag;
1870    
1871      while(tag) {
1872        if(tag->value && strcasecmp(tag->value, str) == 0)
1873          return TRUE;
1874    
1875        tag = tag->next;
1876      }
1877      return FALSE;
1878    }
1879    
1880    gboolean osm_node_has_tag(node_t *node) {
1881      tag_t *tag = node->tag;
1882    
1883      if(tag && strcasecmp(tag->key, "created_by") == 0)
1884        tag = tag->next;
1885    
1886      return tag != NULL;
1887    }
1888    
1889    /* return true if node is part of way */
1890    gboolean osm_node_in_way(way_t *way, node_t *node) {
1891      node_chain_t *node_chain = way->node_chain;
1892      while(node_chain) {
1893        if(node_chain->node == node)
1894          return TRUE;
1895    
1896        node_chain = node_chain->next;
1897      }
1898      return FALSE;
1899    }
1900    
1901    static void osm_generate_tags(tag_t *tag, xmlNodePtr node) {
1902      while(tag) {
1903        /* make sure "created_by" tag contains our id */
1904        if(strcasecmp(tag->key, "created_by") == 0) {
1905          g_free(tag->value);
1906          tag->value = g_strdup(PACKAGE " v" VERSION);
1907        }
1908    
1909        xmlNodePtr tag_node = xmlNewChild(node, NULL, BAD_CAST "tag", NULL);
1910        xmlNewProp(tag_node, BAD_CAST "k", BAD_CAST tag->key);
1911        xmlNewProp(tag_node, BAD_CAST "v", BAD_CAST tag->value);
1912        tag = tag->next;
1913      }
1914    }
1915    
1916    /* build xml representation for a way */
1917    char *osm_generate_xml(osm_t *osm, type_t type, void *item) {
1918      char str[32];
1919      xmlChar *result = NULL;
1920      int len = 0;
1921    
1922      LIBXML_TEST_VERSION;
1923    
1924      xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
1925      xmlNodePtr root_node = xmlNewNode(NULL, BAD_CAST "osm");
1926      xmlNewProp(root_node, BAD_CAST "version", BAD_CAST "0.5");
1927    xmlNewProp(root_node, BAD_CAST "generator", BAD_CAST PACKAGE " V" VERSION);    xmlNewProp(root_node, BAD_CAST "generator", BAD_CAST PACKAGE " V" VERSION);
1928    xmlDocSetRootElement(doc, root_node);    xmlDocSetRootElement(doc, root_node);
1929    
# Line 1139  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 1468  way_chain_t *osm_node_to_way(osm_t *osm, Line 2404  way_chain_t *osm_node_to_way(osm_t *osm,
2404        cur_chain = &((*cur_chain)->next);        cur_chain = &((*cur_chain)->next);
2405      }      }
2406    
2407      way = way->next;       way = way->next;
2408    }    }
2409    
2410    return chain;    return chain;
# Line 1669  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    // vim:et:ts=8:sw=2:sts=2:ai

Legend:
Removed from v.6  
changed lines
  Added in v.42