source: subversion/applications/utils/import/srtm2wayinfo/osm-parse.cpp

Last change on this file was 17101, checked in by herm, 8 years ago

Support different storage systems for ways.

File size: 6.8 KB
Line 
1/* Copyright (c) 2009 Hermann Kraus
2 * This software is available under a "MIT Style" license
3 * (see COPYING).
4 */
5/** \file
6  * Minimalistic OSM parser.
7  * Only handles the attributes required for this project and ignores everything else.
8  */
9#include "osm-parse.h"
10
11#include <QString>
12#include <QFile>
13#include <QDebug>
14
15/** Parse an OSM-XML file.
16  * This function is just a wrapper that creates an QFile object
17  * and calls parse(QFile *).
18  */
19void OsmData::parse(QString filename)
20{
21    QFile f(filename);
22    f.open(QIODevice::ReadOnly);
23    parse(&f);
24    f.close();
25}
26
27/** Checks if c is a character that ends a parameter value. */
28static inline bool isDelim(char c)
29{
30    return (c == ' ') || (c == '<') || (c == '\t') || (c == '>') || (c == '/');
31}
32
33// NOTE: These defines are for debugging only.
34// #define NO_NODES
35// #define NO_WAYS
36// #define STOP_AT_FIRST_WAY
37
38
39void OsmData::processTag(char *tag)
40{
41    #ifndef NO_NODES
42    if (!strncmp(tag, "node", 5)) {
43        (*nodes)[nodeid] = OsmNode(lat, lon);
44        nodes_total++;
45        if (!(nodes_total & 0x3ffff)) qDebug() << "Nodes:" << nodes_total;
46    }
47    #else
48    #warning Parsing of nodes is disabled.
49    #endif
50   
51    #ifndef NO_WAYS
52//     else
53    if (!strncmp(tag, "way", 4)) {
54        keep = false;
55        currentWay.clear();
56        currentWay.setId(wayid);
57    } else if (!strncmp(tag, "nd", 3)) {
58        currentWay.addNode(noderef);
59    } else if (!strncmp(tag, "/way", 5)) {
60        if (keep) {
61            ways->append(currentWay);
62            foreach(OsmNodeId nodeid, currentWay.nodes) {
63                (*nodes)[nodeid].incOrder();
64            }
65            nodes_referenced += currentWay.nodes.count();
66            kept++;
67        } else {
68            //The way object will be reused
69            discarded++;
70        }
71    }
72    #else
73    #warning Parsing of ways is disabled.
74    #ifdef STOP_AT_FIRST_WAY
75        if (!strncmp(tag, "way", 4)) {
76            exit(0);
77        }
78    #endif
79    #endif
80}
81
82void OsmData::processParam(char *tag, char *name, char *value)
83{
84    if (!strcmp("lat", name)) {
85        lat = atof(value);
86    } else if (!strcmp("lon", name)) {
87        lon = atof(value);
88    } else if (!strcmp("ref", name)) {
89        noderef = atoi(value);
90    } else if (!strcmp("id", name)) {
91        if (!strcmp("node", tag)) {
92            nodeid = atoi(value);
93        } else {
94            wayid = atoi(value);
95        }
96    } else if (!strcmp("k", name) && !strcmp("highway", value)) {
97        keep = true;
98    }
99}
100
101/** Length of the main read buffer. */
102#define BUFFER_LEN 1024
103/** Maximum tag name length. Longer values are truncated.*/
104#define TAG_LEN 16
105/** Maximum parameter name length. Longer values are truncated.*/
106#define PARAM_NAME_LEN 16
107/** Maximum parameter value length. Longer values are truncated. */
108#define PARAM_VALUE_LEN 16
109
110/** Parse an OSM-XML file.
111  * Stores information about the parsed data in the "nodes" and "ways" arrays.
112  * \note This parser doesn't fail when the input data is invalid. It goes on
113  *        reading and produces unpredictable results. However there should be
114  *        no possiblity of a buffer overrun.
115  */
116void OsmData::parse(QFile *file)
117{
118    kept = discarded = nodes_referenced = nodes_total = 0;
119    QDataStream stream(file);
120    char buffer[BUFFER_LEN];
121    char tag[TAG_LEN];
122    char param_name[PARAM_NAME_LEN];
123    char param_value[PARAM_VALUE_LEN];
124    int tag_pos, name_pos, value_pos;
125    int count;
126    bool inside_quotes;
127    enum {
128        state_waiting_for_tag_start,
129        state_waiting_for_tag_end,
130        state_waiting_for_param_end,
131        state_tag,
132        state_param_name,
133        state_param_value,
134    } state;
135
136    do {
137        count = stream.readRawData(buffer, BUFFER_LEN);
138        int i;
139        for (i = 0; i < count; i++) {
140            char c = buffer[i];
141            //Shortcuts to keep processing time low
142            if ((state == state_waiting_for_tag_start) && (c != '<')) continue;
143            if ((state == state_waiting_for_tag_end) && (c != '>')) continue;
144            if (c == '<') {
145                //A < always starts a new tag (except in CDATA areas which we don't have in OSM data)
146                state = state_tag;
147                tag_pos = 0;
148                continue;
149            }
150            if (c == '>') {
151                if (tag_pos) {
152                    tag[tag_pos] = 0;
153                }
154                if (value_pos) { //Value is terminated by this end-of-tag-char
155                    param_value[value_pos] = 0;
156                    //qDebug() << "\tValue1:" << param_value;
157                    processParam(tag, param_name, param_value);
158                }
159                processTag(tag);
160                state = state_waiting_for_tag_start;
161            }
162            /******************************************************************/
163            if (state == state_tag) {
164                if (isblank(c)) {
165                    if (!tag_pos) continue; //Tag text has not started yes
166                    else {
167                        state = state_param_name;
168                        name_pos = 0;
169                        tag[tag_pos] = 0;
170                        tag_pos = 0;
171                        //qDebug() << "Tag:" << tag;
172                    }
173                } else if (tag_pos < TAG_LEN-1) {
174                    tag[tag_pos++] = c;
175                }
176            }
177            /******************************************************************/
178            if (state == state_param_name) {
179                if ((c == '"') || (c == '\'') || isblank(c)) continue; //Ignore some chars
180                if (c == '=') {
181                    //Name ended
182                    state = state_param_value;
183                    value_pos = 0;
184                    inside_quotes = false;
185                    param_name[name_pos] = 0;
186                    //qDebug() << "\tParam:" << param_name;
187                } else if (name_pos < PARAM_NAME_LEN-1) {
188                    param_name[name_pos++] = c;
189                }
190            }
191            /******************************************************************/
192            if (state == state_param_value) {
193                if (c == '"' || c == '\'') {
194                    inside_quotes = !inside_quotes;
195                    continue;
196                }
197                if (!inside_quotes && isDelim(c)) {
198                    param_value[value_pos] = 0;
199                    state = state_param_name;
200                    name_pos = 0;
201                    processParam(tag, param_name, param_value);
202                    value_pos = 0;
203                    continue;
204                }
205                if ((c == '=' || isblank(c))) continue;
206                if (value_pos < PARAM_VALUE_LEN-1) {
207                    param_value[value_pos++] = c;
208                }
209            }
210        }
211    }
212    while (count > 0);
213    qDebug() << "Kept:" << kept << "Discarded:" << discarded <<  "Noderefs:" << nodes_referenced << "Nodes:" << nodes_total;
214}
Note: See TracBrowser for help on using the repository browser.