1 | /** |
|
|
2 | * Navit, a modular navigation system. |
|
|
3 | * Copyright (C) 2005-2011 Navit Team |
|
|
4 | * |
|
|
5 | * This program is free software; you can redistribute it and/or |
|
|
6 | * modify it under the terms of the GNU General Public License |
|
|
7 | * version 2 as published by the Free Software Foundation. |
|
|
8 | * |
|
|
9 | * This program is distributed in the hope that it will be useful, |
|
|
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
|
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
|
12 | * GNU General Public License for more details. |
|
|
13 | * |
|
|
14 | * You should have received a copy of the GNU General Public License |
|
|
15 | * along with this program; if not, write to the |
|
|
16 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
|
|
17 | * Boston, MA 02110-1301, USA. |
|
|
18 | */ |
|
|
19 | #include <string.h> |
|
|
20 | #include <stdlib.h> |
|
|
21 | #include <math.h> |
|
|
22 | #include <unistd.h> |
|
|
23 | #include <time.h> |
|
|
24 | #include <zlib.h> |
|
|
25 | #include "maptool.h" |
|
|
26 | #include "debug.h" |
|
|
27 | #include "linguistics.h" |
|
|
28 | #include "file.h" |
|
|
29 | #include "generated-code/fileformat.pb-c.h" |
|
|
30 | #include "generated-code/osmformat.pb-c.h" |
|
|
31 | |
|
|
32 | |
|
|
33 | static double latlon_scale=10000000.0; |
|
|
34 | |
|
|
35 | static OSMPBF__BlobHeader * |
|
|
36 | read_header(FILE *f) |
|
|
37 | { |
|
|
38 | unsigned char *buffer,lenb[4]; |
|
|
39 | int len; |
|
|
40 | |
|
|
41 | len=sizeof(lenb); |
|
|
42 | if (fread(lenb, 4, 1, f) != 1) |
|
|
43 | return NULL; |
|
|
44 | len=(lenb[0] << 24) | (lenb[1] << 16) | (lenb[2] << 8) | lenb[3]; |
|
|
45 | buffer=alloca(len); |
|
|
46 | if (fread(buffer, len, 1, f) != 1) |
|
|
47 | return NULL; |
|
|
48 | return osmpbf__blob_header__unpack(&protobuf_c_system_allocator, len, buffer); |
|
|
49 | } |
|
|
50 | |
|
|
51 | |
|
|
52 | static OSMPBF__Blob * |
|
|
53 | read_blob(OSMPBF__BlobHeader *header, FILE *f) |
|
|
54 | { |
|
|
55 | unsigned char *buffer; |
|
|
56 | int len=header->datasize; |
|
|
57 | |
|
|
58 | buffer=alloca(len); |
|
|
59 | if (fread(buffer, len, 1, f) != 1) |
|
|
60 | return NULL; |
|
|
61 | return osmpbf__blob__unpack(&protobuf_c_system_allocator, len, buffer); |
|
|
62 | } |
|
|
63 | |
|
|
64 | static unsigned char * |
|
|
65 | uncompress_blob(OSMPBF__Blob *blob) |
|
|
66 | { |
|
|
67 | unsigned char *ret=malloc(blob->raw_size); |
|
|
68 | int zerr; |
|
|
69 | z_stream strm; |
|
|
70 | |
|
|
71 | if (!ret) |
|
|
72 | return NULL; |
|
|
73 | strm.zalloc = Z_NULL; |
|
|
74 | strm.zfree = Z_NULL; |
|
|
75 | strm.opaque = Z_NULL; |
|
|
76 | strm.avail_in=blob->zlib_data.len; |
|
|
77 | strm.next_in=blob->zlib_data.data; |
|
|
78 | strm.avail_out=blob->raw_size; |
|
|
79 | strm.next_out=ret; |
|
|
80 | zerr = inflateInit(&strm); |
|
|
81 | if (zerr != Z_OK) { |
|
|
82 | free(ret); |
|
|
83 | return NULL; |
|
|
84 | } |
|
|
85 | zerr = inflate(&strm, Z_NO_FLUSH); |
|
|
86 | if (zerr != Z_STREAM_END) { |
|
|
87 | free(ret); |
|
|
88 | return NULL; |
|
|
89 | } |
|
|
90 | inflateEnd(&strm); |
|
|
91 | return ret; |
|
|
92 | } |
|
|
93 | |
|
|
94 | static int |
|
|
95 | get_string(char *buffer, int buffer_size, OSMPBF__PrimitiveBlock *primitive_block, int id, int escape) |
|
|
96 | { |
|
|
97 | int len=primitive_block->stringtable->s[id].len; |
|
|
98 | char *data=(char *)primitive_block->stringtable->s[id].data; |
|
|
99 | if (primitive_block->stringtable->s[id].len >= buffer_size) { |
|
|
100 | buffer[0]='\0'; |
|
|
101 | return 0; |
|
|
102 | } |
|
|
103 | if (escape) { |
|
|
104 | int i; |
|
|
105 | char *p=buffer; |
|
|
106 | for (i = 0 ; i < len ; i++) { |
|
|
107 | switch(data[i]) { |
|
|
108 | case '\t': |
|
|
109 | case '\r': |
|
|
110 | case '\n': |
|
|
111 | case '>': |
|
|
112 | case '<': |
|
|
113 | case '\'': |
|
|
114 | case '"': |
|
|
115 | case '&': |
|
|
116 | sprintf(p,"&#%d;",data[i]); |
|
|
117 | p+=strlen(p); |
|
|
118 | break; |
|
|
119 | default: |
|
|
120 | *p++=data[i]; |
|
|
121 | } |
|
|
122 | } |
|
|
123 | *p++='\0'; |
|
|
124 | return 1; |
|
|
125 | } else { |
|
|
126 | strncpy(buffer, data, len); |
|
|
127 | buffer[len]='\0'; |
|
|
128 | return 1; |
|
|
129 | } |
|
|
130 | } |
|
|
131 | |
|
|
132 | |
|
|
133 | static void |
|
|
134 | process_osmheader(OSMPBF__Blob *blob, unsigned char *data) |
|
|
135 | { |
|
|
136 | OSMPBF__HeaderBlock *header_block; |
|
|
137 | header_block=osmpbf__header_block__unpack(&protobuf_c_system_allocator, blob->raw_size, data); |
|
|
138 | osmpbf__header_block__free_unpacked(header_block, &protobuf_c_system_allocator); |
|
|
139 | } |
|
|
140 | |
|
|
141 | #if 0 |
|
|
142 | |
|
|
143 | static void |
|
|
144 | process_user(OSMPBF__PrimitiveBlock *primitive_block, int user_sid, int uid, int swap) |
|
|
145 | { |
|
|
146 | char userbuff[1024]; |
|
|
147 | get_string(userbuff, sizeof(userbuff), primitive_block, user_sid, 1); |
|
|
148 | if (userbuff[0] && uid != -1) { |
|
|
149 | if (swap) |
|
|
150 | printf(" uid=\"%d\" user=\"%s\"",uid,userbuff); |
|
|
151 | else |
|
|
152 | printf(" user=\"%s\" uid=\"%d\"",userbuff,uid); |
|
|
153 | } |
|
|
154 | } |
|
|
155 | |
|
|
156 | static void |
|
|
157 | process_timestamp(long long timestamp) |
|
|
158 | { |
|
|
159 | time_t ts; |
|
|
160 | struct tm *tm; |
|
|
161 | char tsbuff[1024]; |
|
|
162 | ts=timestamp; |
|
|
163 | tm=gmtime(&ts); |
|
|
164 | strftime(tsbuff, sizeof(tsbuff), "%Y-%m-%dT%H:%M:%SZ", tm); |
|
|
165 | printf(" timestamp=\"%s\"",tsbuff); |
|
|
166 | } |
|
|
167 | |
|
|
168 | #endif |
|
|
169 | |
|
|
170 | static void |
|
|
171 | process_tag(OSMPBF__PrimitiveBlock *primitive_block, int key, int val) |
|
|
172 | { |
|
|
173 | char keybuff[1024]; |
|
|
174 | char valbuff[1024]; |
|
|
175 | #if 0 |
|
|
176 | get_string(keybuff, sizeof(keybuff), primitive_block, key, 1); |
|
|
177 | get_string(valbuff, sizeof(valbuff), primitive_block, val, 1); |
|
|
178 | printf("\t\t<tag k=\"%s\" v=\"%s\" />\n",keybuff,valbuff); |
|
|
179 | #else |
|
|
180 | get_string(keybuff, sizeof(keybuff), primitive_block, key, 0); |
|
|
181 | get_string(valbuff, sizeof(valbuff), primitive_block, val, 0); |
|
|
182 | osm_add_tag(keybuff, valbuff); |
|
|
183 | #endif |
|
|
184 | } |
|
|
185 | |
|
|
186 | |
|
|
187 | static void |
|
|
188 | process_dense(OSMPBF__PrimitiveBlock *primitive_block, OSMPBF__DenseNodes *dense, FILE *out_nodes) |
|
|
189 | { |
|
|
190 | int i,j=0,has_tags; |
|
|
191 | long long id=0,lat=0,lon=0,changeset=0,timestamp=0; |
|
|
192 | int version,user_sid=0,uid=0; |
|
|
193 | |
|
|
194 | if (!dense) |
|
|
195 | return; |
|
|
196 | |
|
|
197 | for (i = 0 ; i < dense->n_id ; i++) { |
|
|
198 | id+=dense->id[i]; |
|
|
199 | lat+=dense->lat[i]; |
|
|
200 | lon+=dense->lon[i]; |
|
|
201 | version=dense->denseinfo->version[i]; |
|
|
202 | changeset+=dense->denseinfo->changeset[i]; |
|
|
203 | user_sid+=dense->denseinfo->user_sid[i]; |
|
|
204 | uid+=dense->denseinfo->uid[i]; |
|
|
205 | timestamp+=dense->denseinfo->timestamp[i]; |
|
|
206 | has_tags=dense->keys_vals && dense->keys_vals[j]; |
|
|
207 | osm_add_node(id, lat/latlon_scale,lon/latlon_scale); |
|
|
208 | #if 0 |
|
|
209 | printf("\t<node id=\"%Ld\" lat=\"%.7f\" lon=\"%.7f\" version=\"%d\" changeset=\"%Ld\"",id,lat/latlon_scale,lon/latlon_scale,version,changeset); |
|
|
210 | process_user(primitive_block, user_sid, uid, 0); |
|
|
211 | process_timestamp(timestamp); |
|
|
212 | #endif |
|
|
213 | if (has_tags) { |
|
|
214 | #if 0 |
|
|
215 | printf(">\n"); |
|
|
216 | #endif |
|
|
217 | while (dense->keys_vals[j]) { |
|
|
218 | process_tag(primitive_block, dense->keys_vals[j], dense->keys_vals[j+1]); |
|
|
219 | j+=2; |
|
|
220 | } |
|
|
221 | #if 0 |
|
|
222 | printf("\t</node>\n"); |
|
|
223 | } else |
|
|
224 | printf("/>\n"); |
|
|
225 | #else |
|
|
226 | } |
|
|
227 | #endif |
|
|
228 | osm_end_node(out_nodes); |
|
|
229 | j++; |
|
|
230 | } |
|
|
231 | } |
|
|
232 | |
|
|
233 | #if 0 |
|
|
234 | static void |
|
|
235 | process_info(OSMPBF__PrimitiveBlock *primitive_block, OSMPBF__Info *info) |
|
|
236 | { |
|
|
237 | printf(" version=\"%d\" changeset=\"%Ld\"",info->version,info->changeset); |
|
|
238 | process_user(primitive_block, info->user_sid, info->uid, 1); |
|
|
239 | process_timestamp(info->timestamp); |
|
|
240 | } |
|
|
241 | #endif |
|
|
242 | |
|
|
243 | static void |
|
|
244 | process_way(OSMPBF__PrimitiveBlock *primitive_block, OSMPBF__Way *way, FILE *out_ways) |
|
|
245 | { |
|
|
246 | int i; |
|
|
247 | long long ref=0; |
|
|
248 | |
|
|
249 | osm_add_way(way->id); |
|
|
250 | #if 0 |
|
|
251 | printf("\t<way id=\"%Ld\"",way->id); |
|
|
252 | process_info(primitive_block, way->info); |
|
|
253 | printf(">\n"); |
|
|
254 | #else |
|
|
255 | #endif |
|
|
256 | for (i = 0 ; i < way->n_refs ; i++) { |
|
|
257 | ref+=way->refs[i]; |
|
|
258 | osm_add_nd(ref); |
|
|
259 | #if 0 |
|
|
260 | printf("\t\t<nd ref=\"%Ld\"/>\n",ref); |
|
|
261 | #else |
|
|
262 | #endif |
|
|
263 | } |
|
|
264 | for (i = 0 ; i < way->n_keys ; i++) |
|
|
265 | process_tag(primitive_block, way->keys[i], way->vals[i]); |
|
|
266 | #if 0 |
|
|
267 | printf("\t</way>\n"); |
|
|
268 | #endif |
|
|
269 | osm_end_way(out_ways); |
|
|
270 | } |
|
|
271 | |
|
|
272 | static void |
|
|
273 | process_relation(OSMPBF__PrimitiveBlock *primitive_block, OSMPBF__Relation *relation, FILE *out_turn_restrictions, FILE *out_boundaries) |
|
|
274 | { |
|
|
275 | int i; |
|
|
276 | long long ref=0; |
|
|
277 | char rolebuff[1024]; |
|
|
278 | |
|
|
279 | #if 0 |
|
|
280 | printf("\t<relation id=\"%Ld\"",relation->id); |
|
|
281 | process_info(primitive_block, relation->info); |
|
|
282 | printf(">\n"); |
|
|
283 | #endif |
|
|
284 | osm_add_relation(relation->id); |
|
|
285 | for (i = 0 ; i < relation->n_roles_sid ; i++) { |
|
|
286 | #if 0 |
|
|
287 | printf("\t\t<member type=\""); |
|
|
288 | switch (relation->types[i]) { |
|
|
289 | case 0: |
|
|
290 | printf("node"); |
|
|
291 | break; |
|
|
292 | case 1: |
|
|
293 | printf("way"); |
|
|
294 | break; |
|
|
295 | case 2: |
|
|
296 | printf("relation"); |
|
|
297 | break; |
|
|
298 | default: |
|
|
299 | printf("unknown"); |
|
|
300 | break; |
|
|
301 | } |
|
|
302 | #endif |
|
|
303 | ref+=relation->memids[i]; |
|
|
304 | get_string(rolebuff, sizeof(rolebuff), primitive_block, relation->roles_sid[i], 1); |
|
|
305 | #if 0 |
|
|
306 | printf("\" ref=\"%Ld\" role=\"%s\"/>\n",ref,rolebuff); |
|
|
307 | #else |
|
|
308 | osm_add_member(relation->types[i]+1,ref,rolebuff); |
|
|
309 | #endif |
|
|
310 | } |
|
|
311 | for (i = 0 ; i < relation->n_keys ; i++) |
|
|
312 | process_tag(primitive_block, relation->keys[i], relation->vals[i]); |
|
|
313 | #if 0 |
|
|
314 | printf("\t</relation>\n"); |
|
|
315 | #else |
|
|
316 | osm_end_relation(out_turn_restrictions, out_boundaries); |
|
|
317 | #endif |
|
|
318 | } |
|
|
319 | |
|
|
320 | static void |
|
|
321 | process_osmdata(OSMPBF__Blob *blob, unsigned char *data, FILE *out_nodes, FILE *out_ways, FILE *out_turn_restrictions, FILE *out_boundaries) |
|
|
322 | { |
|
|
323 | int i,j; |
|
|
324 | OSMPBF__PrimitiveBlock *primitive_block; |
|
|
325 | primitive_block=osmpbf__primitive_block__unpack(&protobuf_c_system_allocator, blob->raw_size, data); |
|
|
326 | for (i = 0 ; i < primitive_block->n_primitivegroup ; i++) { |
|
|
327 | OSMPBF__PrimitiveGroup *primitive_group=primitive_block->primitivegroup[i]; |
|
|
328 | process_dense(primitive_block, primitive_group->dense, out_nodes); |
|
|
329 | for (j = 0 ; j < primitive_group->n_ways ; j++) |
|
|
330 | process_way(primitive_block, primitive_group->ways[j], out_ways); |
|
|
331 | for (j = 0 ; j < primitive_group->n_relations ; j++) |
|
|
332 | process_relation(primitive_block, primitive_group->relations[j], out_turn_restrictions, out_boundaries); |
|
|
333 | #if 0 |
|
|
334 | printf("Group %p %d %d %d %d\n",primitive_group->dense,primitive_group->n_nodes,primitive_group->n_ways,primitive_group->n_relations,primitive_group->n_changesets); |
|
|
335 | #endif |
|
|
336 | } |
|
|
337 | osmpbf__primitive_block__free_unpacked(primitive_block, &protobuf_c_system_allocator); |
|
|
338 | } |
|
|
339 | |
|
|
340 | |
|
|
341 | int |
|
|
342 | map_collect_data_osm_protobuf(FILE *in, FILE *out_ways, FILE *out_nodes, FILE *out_turn_restrictions, FILE *out_boundaries) |
|
|
343 | { |
|
|
344 | OSMPBF__BlobHeader *header; |
|
|
345 | OSMPBF__Blob *blob; |
|
|
346 | unsigned char *data; |
|
|
347 | #if 0 |
|
|
348 | printf("<?xml version='1.0' encoding='UTF-8'?>\n"); |
|
|
349 | printf("<osm version=\"0.6\" generator=\"pbf2osm\">\n"); |
|
|
350 | #endif |
|
|
351 | while ((header=read_header(in))) { |
|
|
352 | blob=read_blob(header, in); |
|
|
353 | data=uncompress_blob(blob); |
|
|
354 | if (!strcmp(header->type,"OSMHeader")) { |
|
|
355 | process_osmheader(blob, data); |
|
|
356 | } else if (!strcmp(header->type,"OSMData")) { |
|
|
357 | process_osmdata(blob, data, out_nodes, out_ways, out_turn_restrictions, out_boundaries); |
|
|
358 | } else { |
|
|
359 | printf("unknown\n"); |
|
|
360 | return 0; |
|
|
361 | } |
|
|
362 | free(data); |
|
|
363 | osmpbf__blob__free_unpacked(blob, &protobuf_c_system_allocator); |
|
|
364 | osmpbf__blob_header__free_unpacked(header, &protobuf_c_system_allocator); |
|
|
365 | } |
|
|
366 | #if 0 |
|
|
367 | printf("</osm>\n"); |
|
|
368 | #endif |
|
|
369 | return 1; |
|
|
370 | } |
|
|