Add:maptool:parse osm tag addr:postcode| From #1031. thanks ziaou
[profile/ivi/navit.git] / navit / navit / maptool / osm_protobuf.c
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, struct maptool_osm *osm)
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(osm);
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, struct maptool_osm *osm)
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(osm);
270 }
271
272 static void
273 process_relation(OSMPBF__PrimitiveBlock *primitive_block, OSMPBF__Relation *relation, struct maptool_osm *osm)
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(osm);
317 #endif
318 }
319
320 static void
321 process_osmdata(OSMPBF__Blob *blob, unsigned char *data, struct maptool_osm *osm)
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, osm);
329                 for (j = 0 ; j < primitive_group->n_ways ; j++)
330                         process_way(primitive_block, primitive_group->ways[j], osm);
331                 for (j = 0 ; j < primitive_group->n_relations ; j++)
332                         process_relation(primitive_block, primitive_group->relations[j], osm);
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, struct maptool_osm *osm)
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, osm);
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 }