Check out the latest version of Routino: svn co http://routino.org/svn/trunk routino
Contents of /branches/MSVC/src/osmo5mparse.c
Parent Directory
|
Revision Log
Revision 1235 -
(show annotations)
(download)
(as text)
Sat Dec 29 11:19:23 2012 UTC (12 years, 2 months ago) by amb
Original Path: trunk/src/osmo5mparse.c
File MIME type: text/x-csrc
File size: 17091 byte(s)
Sat Dec 29 11:19:23 2012 UTC (12 years, 2 months ago) by amb
Original Path: trunk/src/osmo5mparse.c
File MIME type: text/x-csrc
File size: 17091 byte(s)
Replace the remaining 'long long' and 'unsigned long long' types with uint64_t.
1 | /*************************************** |
2 | A simple o5m/o5c parser. |
3 | |
4 | Part of the Routino routing software. |
5 | ******************/ /****************** |
6 | This file Copyright 2012 Andrew M. Bishop |
7 | |
8 | This program is free software: you can redistribute it and/or modify |
9 | it under the terms of the GNU Affero General Public License as published by |
10 | the Free Software Foundation, either version 3 of the License, or |
11 | (at your option) any later version. |
12 | |
13 | This program is distributed in the hope that it will be useful, |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | GNU Affero General Public License for more details. |
17 | |
18 | You should have received a copy of the GNU Affero General Public License |
19 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
20 | ***************************************/ |
21 | |
22 | |
23 | #include <stdio.h> |
24 | #include <unistd.h> |
25 | #include <stdlib.h> |
26 | #include <string.h> |
27 | #include <inttypes.h> |
28 | #include <stdint.h> |
29 | |
30 | #include "osmparser.h" |
31 | #include "tagging.h" |
32 | #include "logging.h" |
33 | |
34 | |
35 | /* At the top level */ |
36 | |
37 | #define O5M_FILE_NODE 0x10 |
38 | #define O5M_FILE_WAY 0x11 |
39 | #define O5M_FILE_RELATION 0x12 |
40 | #define O5M_FILE_BOUNDING_BOX 0xdb |
41 | #define O5M_FILE_TIMESTAMP 0xdc |
42 | #define O5M_FILE_HEADER 0xe0 |
43 | #define O5M_FILE_SYNC 0xee |
44 | #define O5M_FILE_JUMP 0xef |
45 | #define O5M_FILE_END 0xfe |
46 | #define O5M_FILE_RESET 0xff |
47 | |
48 | /* Errors */ |
49 | |
50 | #define O5M_EOF 0 |
51 | |
52 | #define O5M_ERROR_UNEXP_EOF 100 |
53 | #define O5M_ERROR_RESET_NOT_FIRST 101 |
54 | #define O5M_ERROR_HEADER_NOT_FIRST 102 |
55 | #define O5M_ERROR_EXPECTED_O5M 103 |
56 | #define O5M_ERROR_EXPECTED_O5C 104 |
57 | #define O5M_ERROR_FILE_LEVEL 105 |
58 | |
59 | |
60 | |
61 | /* Parsing variables and functions */ |
62 | |
63 | static uint64_t byteno=0; |
64 | static uint64_t nnodes=0,nways=0,nrelations=0; |
65 | |
66 | static int64_t id=0; |
67 | static int32_t lat=0; |
68 | static int32_t lon=0; |
69 | static int64_t timestamp=0; |
70 | static int64_t node_refid=0,way_refid=0,relation_refid=0; |
71 | |
72 | static int mode_change=MODE_NORMAL; |
73 | |
74 | static int buffer_allocated; |
75 | static unsigned char *buffer=NULL; |
76 | static unsigned char *buffer_ptr,*buffer_end; |
77 | |
78 | static int string_table_start=0; |
79 | static unsigned char **string_table=NULL; |
80 | |
81 | #define STRING_TABLE_ALLOCATED 15000 |
82 | |
83 | |
84 | /*++++++++++++++++++++++++++++++++++++++ |
85 | Refill the data buffer and set the pointers. |
86 | |
87 | int buffer_refill Return 0 if everything is OK or 1 for EOF. |
88 | |
89 | int fd The file descriptor to read from. |
90 | |
91 | uint32_t bytes The number of bytes to read. |
92 | ++++++++++++++++++++++++++++++++++++++*/ |
93 | |
94 | static inline int buffer_refill(int fd,uint32_t bytes) |
95 | { |
96 | ssize_t n,m; |
97 | uint32_t totalbytes; |
98 | |
99 | m=buffer_end-buffer_ptr; |
100 | |
101 | if(m) |
102 | memmove(buffer,buffer_ptr,m); |
103 | |
104 | totalbytes=bytes+m; |
105 | |
106 | if(totalbytes>buffer_allocated) |
107 | buffer=(unsigned char *)realloc(buffer,buffer_allocated=totalbytes); |
108 | |
109 | byteno+=bytes; |
110 | |
111 | buffer_ptr=buffer; |
112 | buffer_end=buffer+m; |
113 | |
114 | do |
115 | { |
116 | n=read(fd,buffer_end,bytes); |
117 | |
118 | if(n<=0) |
119 | return(1); |
120 | |
121 | buffer_end+=n; |
122 | bytes-=n; |
123 | } |
124 | while(bytes>0); |
125 | |
126 | return(0); |
127 | } |
128 | |
129 | static void process_node(void); |
130 | static void process_way(void); |
131 | static void process_relation(void); |
132 | static void process_info(void); |
133 | static unsigned char *process_string(int pair,unsigned char **buf_ptr,unsigned char **string1,unsigned char **string2); |
134 | |
135 | |
136 | /* Macros to simplify the parser (and make it look more like the XML parser) */ |
137 | |
138 | #define BEGIN(xx) do{ state=(xx); goto finish_parsing; } while(0) |
139 | |
140 | #define BUFFER_CHARS(xx) do{ if(buffer_refill(fd,(xx))) BEGIN(O5M_ERROR_UNEXP_EOF); } while(0) |
141 | |
142 | |
143 | /* O5M decoding */ |
144 | |
145 | #define O5M_LATITUDE(xx) (double)(1E-7*(xx)) |
146 | #define O5M_LONGITUDE(xx) (double)(1E-7*(xx)) |
147 | |
148 | |
149 | /*++++++++++++++++++++++++++++++++++++++ |
150 | Parse a PBF int32 data value. |
151 | |
152 | uint32_t pbf_int32 Returns the integer value. |
153 | |
154 | unsigned char **ptr The pointer to read the data from. |
155 | ++++++++++++++++++++++++++++++++++++++*/ |
156 | |
157 | static inline uint32_t pbf_int32(unsigned char **ptr) |
158 | { |
159 | uint32_t result=(**ptr)&0x7F; |
160 | |
161 | if((**ptr)&0x80) result+=((*++(*ptr))&0x7F)<<7; |
162 | if((**ptr)&0x80) result+=((*++(*ptr))&0x7F)<<14; |
163 | if((**ptr)&0x80) result+=((*++(*ptr))&0x7F)<<21; |
164 | if((**ptr)&0x80) result+=((*++(*ptr))&0x7F)<<28; |
165 | |
166 | (*ptr)++; |
167 | |
168 | return(result); |
169 | } |
170 | |
171 | |
172 | /*++++++++++++++++++++++++++++++++++++++ |
173 | Parse a PBF int32 data value. |
174 | |
175 | int32_t pbf_sint32 Returns the integer value. |
176 | |
177 | unsigned char **ptr The pointer to read the data from. |
178 | ++++++++++++++++++++++++++++++++++++++*/ |
179 | |
180 | static inline int32_t pbf_sint32(unsigned char **ptr) |
181 | { |
182 | int64_t result=((**ptr)&0x7E)>>1; |
183 | int sign=(**ptr)&0x01; |
184 | |
185 | if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<6; |
186 | if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<13; |
187 | if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<20; |
188 | if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<27; |
189 | |
190 | (*ptr)++; |
191 | |
192 | if(sign) |
193 | result=-result-1; |
194 | |
195 | return(result); |
196 | } |
197 | |
198 | |
199 | /*++++++++++++++++++++++++++++++++++++++ |
200 | Parse a PBF int64 data value. |
201 | |
202 | int64_t pbf_int64 Returns the integer value. |
203 | |
204 | unsigned char **ptr The pointer to read the data from. |
205 | ++++++++++++++++++++++++++++++++++++++*/ |
206 | |
207 | static inline int64_t pbf_int64(unsigned char **ptr) |
208 | { |
209 | uint64_t result=(**ptr)&0x7F; |
210 | |
211 | if((**ptr)&0x80) result+=(uint64_t)((*++(*ptr))&0x7F)<<7; |
212 | if((**ptr)&0x80) result+=(uint64_t)((*++(*ptr))&0x7F)<<14; |
213 | if((**ptr)&0x80) result+=(uint64_t)((*++(*ptr))&0x7F)<<21; |
214 | if((**ptr)&0x80) result+=(uint64_t)((*++(*ptr))&0x7F)<<28; |
215 | if((**ptr)&0x80) result+=(uint64_t)((*++(*ptr))&0x7F)<<35; |
216 | if((**ptr)&0x80) result+=(uint64_t)((*++(*ptr))&0x7F)<<42; |
217 | if((**ptr)&0x80) result+=(uint64_t)((*++(*ptr))&0x7F)<<49; |
218 | if((**ptr)&0x80) result+=(uint64_t)((*++(*ptr))&0x7F)<<56; |
219 | if((**ptr)&0x80) result+=(uint64_t)((*++(*ptr))&0x7F)<<63; |
220 | |
221 | (*ptr)++; |
222 | |
223 | return(result); |
224 | } |
225 | |
226 | |
227 | /*++++++++++++++++++++++++++++++++++++++ |
228 | Parse a PBF sint64 data value. |
229 | |
230 | int64_t pbf_sint64 Returns the integer value. |
231 | |
232 | unsigned char **ptr The pointer to read the data from. |
233 | ++++++++++++++++++++++++++++++++++++++*/ |
234 | |
235 | static inline int64_t pbf_sint64(unsigned char **ptr) |
236 | { |
237 | int64_t result=((**ptr)&0x7E)>>1; |
238 | int sign=(**ptr)&0x01; |
239 | |
240 | if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<6; |
241 | if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<13; |
242 | if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<20; |
243 | if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<27; |
244 | if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<34; |
245 | if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<41; |
246 | if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<48; |
247 | if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<55; |
248 | if((**ptr)&0x80) result+=(int64_t)((*++(*ptr))&0x7F)<<62; |
249 | |
250 | (*ptr)++; |
251 | |
252 | if(sign) |
253 | result=-result-1; |
254 | |
255 | return(result); |
256 | } |
257 | |
258 | |
259 | /*++++++++++++++++++++++++++++++++++++++ |
260 | Parse the O5M and call the functions for each OSM item as seen. |
261 | |
262 | int ParseO5M Returns 0 if OK or something else in case of an error. |
263 | |
264 | int fd The file descriptor of the file to parse. |
265 | |
266 | int changes Set to 1 if this is expected to be a changes file, otherwise zero. |
267 | ++++++++++++++++++++++++++++++++++++++*/ |
268 | |
269 | int ParseO5M(int fd,int changes) |
270 | { |
271 | int i; |
272 | int state; |
273 | int number_reset=0; |
274 | int error; |
275 | |
276 | /* Print the initial message */ |
277 | |
278 | nnodes=0,nways=0,nrelations=0; |
279 | |
280 | printf_first("Reading: Bytes=0 Nodes=0 Ways=0 Relations=0"); |
281 | |
282 | /* The actual parser. */ |
283 | |
284 | if(changes) |
285 | mode_change=MODE_MODIFY; |
286 | |
287 | string_table_start=0; |
288 | string_table=(unsigned char **)malloc(STRING_TABLE_ALLOCATED*sizeof(unsigned char *)); |
289 | for(i=0;i<STRING_TABLE_ALLOCATED;i++) |
290 | string_table[i]=(unsigned char*)malloc(252); |
291 | |
292 | buffer_allocated=4096; |
293 | buffer=(unsigned char*)malloc(buffer_allocated); |
294 | |
295 | buffer_ptr=buffer_end=buffer; |
296 | |
297 | while(1) |
298 | { |
299 | uint32_t dataset_length=0; |
300 | |
301 | /* ================ Parsing states ================ */ |
302 | |
303 | BUFFER_CHARS(1); |
304 | |
305 | state=*buffer_ptr++; |
306 | |
307 | if(state!=O5M_FILE_END && state!=O5M_FILE_RESET) |
308 | { |
309 | uint32_t length; |
310 | unsigned char *ptr; |
311 | |
312 | if(number_reset==0) |
313 | BEGIN(O5M_ERROR_RESET_NOT_FIRST); |
314 | |
315 | BUFFER_CHARS(4); |
316 | |
317 | ptr=buffer_ptr; |
318 | dataset_length=pbf_int32(&buffer_ptr); |
319 | |
320 | length=dataset_length-4+(buffer_ptr-ptr); |
321 | |
322 | BUFFER_CHARS(length); |
323 | } |
324 | else if(state==O5M_FILE_END) |
325 | ; |
326 | else if(state==O5M_FILE_RESET) |
327 | number_reset++; |
328 | |
329 | switch(state) |
330 | { |
331 | case O5M_FILE_NODE: |
332 | |
333 | process_node(); |
334 | |
335 | break; |
336 | |
337 | case O5M_FILE_WAY: |
338 | |
339 | process_way(); |
340 | |
341 | break; |
342 | |
343 | case O5M_FILE_RELATION: |
344 | |
345 | process_relation(); |
346 | |
347 | break; |
348 | |
349 | case O5M_FILE_BOUNDING_BOX: |
350 | |
351 | buffer_ptr+=dataset_length; |
352 | |
353 | break; |
354 | |
355 | case O5M_FILE_TIMESTAMP: |
356 | |
357 | buffer_ptr+=dataset_length; |
358 | |
359 | break; |
360 | |
361 | case O5M_FILE_HEADER: |
362 | |
363 | if(number_reset!=1) |
364 | BEGIN(O5M_ERROR_HEADER_NOT_FIRST); |
365 | |
366 | if(!changes && strncmp((char*)buffer_ptr,"o5m2",4)) |
367 | BEGIN(O5M_ERROR_EXPECTED_O5M); |
368 | |
369 | if( changes && strncmp((char*)buffer_ptr,"o5c2",4)) |
370 | BEGIN(O5M_ERROR_EXPECTED_O5C); |
371 | |
372 | buffer_ptr+=dataset_length; |
373 | |
374 | break; |
375 | |
376 | case O5M_FILE_SYNC: |
377 | |
378 | buffer_ptr+=dataset_length; |
379 | |
380 | break; |
381 | |
382 | case O5M_FILE_JUMP: |
383 | |
384 | buffer_ptr+=dataset_length; |
385 | |
386 | break; |
387 | |
388 | case O5M_FILE_END: |
389 | |
390 | BEGIN(O5M_EOF); |
391 | |
392 | break; |
393 | |
394 | case O5M_FILE_RESET: |
395 | |
396 | string_table_start=0; |
397 | id=0; |
398 | lat=0; |
399 | lon=0; |
400 | timestamp=0; |
401 | node_refid=0,way_refid=0,relation_refid=0; |
402 | |
403 | break; |
404 | |
405 | default: |
406 | |
407 | error=state; |
408 | BEGIN(O5M_ERROR_FILE_LEVEL); |
409 | } |
410 | } |
411 | |
412 | |
413 | finish_parsing: |
414 | |
415 | switch(state) |
416 | { |
417 | /* End of file */ |
418 | |
419 | case O5M_EOF: |
420 | break; |
421 | |
422 | |
423 | /* ================ Error states ================ */ |
424 | |
425 | |
426 | case O5M_ERROR_UNEXP_EOF: |
427 | fprintf(stderr,"O5M Parser: Error at byte %llu: unexpected end of file seen.\n",byteno); |
428 | break; |
429 | |
430 | case O5M_ERROR_RESET_NOT_FIRST: |
431 | fprintf(stderr,"O5M Parser: Error at byte %llu: Reset was not the first byte.\n",byteno); |
432 | break; |
433 | |
434 | case O5M_ERROR_HEADER_NOT_FIRST: |
435 | fprintf(stderr,"O5M Parser: Error at byte %llu: Header was not the first section.\n",byteno); |
436 | break; |
437 | |
438 | case O5M_ERROR_EXPECTED_O5M: |
439 | fprintf(stderr,"O5M Parser: Error at byte %llu: Expected O5M format but header disagrees.\n",byteno); |
440 | break; |
441 | |
442 | case O5M_ERROR_EXPECTED_O5C: |
443 | fprintf(stderr,"O5M Parser: Error at byte %llu: Expected O5C format but header disagrees.\n",byteno); |
444 | break; |
445 | |
446 | case O5M_ERROR_FILE_LEVEL: |
447 | fprintf(stderr,"O5M Parser: Error at byte %llu: Unexpected dataset type %02x.\n",byteno,error); |
448 | break; |
449 | } |
450 | |
451 | /* Free the parser variables */ |
452 | |
453 | for(i=0;i<STRING_TABLE_ALLOCATED;i++) |
454 | free(string_table[i]); |
455 | free(string_table); |
456 | |
457 | free(buffer); |
458 | |
459 | /* Print the final message */ |
460 | |
461 | printf_last("Read: Bytes=%"PRIu64" Nodes=%"PRIu64" Ways=%"PRIu64" Relations=%"PRIu64,byteno,nnodes,nways,nrelations); |
462 | |
463 | return(state); |
464 | } |
465 | |
466 | |
467 | /*++++++++++++++++++++++++++++++++++++++ |
468 | Process an O5M Node dataset. |
469 | ++++++++++++++++++++++++++++++++++++++*/ |
470 | |
471 | static void process_node(void) |
472 | { |
473 | int64_t delta_id; |
474 | int32_t delta_lat; |
475 | int32_t delta_lon; |
476 | TagList *tags=NULL,*result=NULL; |
477 | int mode=mode_change; |
478 | |
479 | delta_id=pbf_sint64(&buffer_ptr); |
480 | id+=delta_id; |
481 | |
482 | if(buffer_ptr<buffer_end) |
483 | { |
484 | if(*buffer_ptr!=0) |
485 | process_info(); |
486 | else |
487 | buffer_ptr++; |
488 | } |
489 | |
490 | if(buffer_ptr<buffer_end) |
491 | { |
492 | delta_lon=pbf_sint32(&buffer_ptr); |
493 | lon+=delta_lon; |
494 | |
495 | delta_lat=pbf_sint32(&buffer_ptr); |
496 | lat+=delta_lat; |
497 | } |
498 | else |
499 | mode=MODE_DELETE; |
500 | |
501 | /* Mangle the data and send it to the OSM parser */ |
502 | |
503 | nnodes++; |
504 | |
505 | if(!(nnodes%10000)) |
506 | printf_middle("Reading: Bytes=%"PRIu64" Nodes=%"PRIu64" Ways=%"PRIu64" Relations=%"PRIu64,byteno,nnodes,nways,nrelations); |
507 | |
508 | tags=NewTagList(); |
509 | |
510 | while(buffer_ptr<buffer_end) |
511 | { |
512 | unsigned char *key,*val; |
513 | |
514 | process_string(2,&buffer_ptr,&key,&val); |
515 | |
516 | AppendTag(tags,(char*)key,(char*)val); |
517 | } |
518 | |
519 | result=ApplyNodeTaggingRules(tags,id); |
520 | |
521 | ProcessNodeTags(result,id,O5M_LATITUDE(lat),O5M_LONGITUDE(lon),mode); |
522 | |
523 | DeleteTagList(tags); |
524 | DeleteTagList(result); |
525 | } |
526 | |
527 | |
528 | /*++++++++++++++++++++++++++++++++++++++ |
529 | Process an O5M Way dataset. |
530 | ++++++++++++++++++++++++++++++++++++++*/ |
531 | |
532 | static void process_way(void) |
533 | { |
534 | int64_t delta_id; |
535 | TagList *tags=NULL,*result=NULL; |
536 | int mode=mode_change; |
537 | unsigned char *refs=NULL,*refs_end; |
538 | |
539 | delta_id=pbf_sint64(&buffer_ptr); |
540 | id+=delta_id; |
541 | |
542 | if(buffer_ptr<buffer_end) |
543 | { |
544 | if(*buffer_ptr!=0) |
545 | process_info(); |
546 | else |
547 | buffer_ptr++; |
548 | } |
549 | |
550 | if(buffer_ptr<buffer_end) |
551 | { |
552 | uint32_t length; |
553 | |
554 | length=pbf_int32(&buffer_ptr); |
555 | |
556 | if(length) |
557 | { |
558 | refs=buffer_ptr; |
559 | refs_end=buffer_ptr+length; |
560 | |
561 | buffer_ptr=refs_end; |
562 | } |
563 | } |
564 | else |
565 | mode=MODE_DELETE; |
566 | |
567 | /* Mangle the data and send it to the OSM parser */ |
568 | |
569 | nways++; |
570 | |
571 | if(!(nways%1000)) |
572 | printf_middle("Reading: Bytes=%"PRIu64" Nodes=%"PRIu64" Ways=%"PRIu64" Relations=%"PRIu64,byteno,nnodes,nways,nrelations); |
573 | |
574 | AddWayRefs(0); |
575 | |
576 | if(refs) |
577 | while(refs<refs_end) |
578 | { |
579 | int64_t delta_ref; |
580 | |
581 | delta_ref=pbf_sint64(&refs); |
582 | node_refid+=delta_ref; |
583 | |
584 | AddWayRefs(node_refid); |
585 | } |
586 | |
587 | tags=NewTagList(); |
588 | |
589 | while(buffer_ptr<buffer_end) |
590 | { |
591 | unsigned char *key,*val; |
592 | |
593 | process_string(2,&buffer_ptr,&key,&val); |
594 | |
595 | AppendTag(tags,(char*)key,(char*)val); |
596 | } |
597 | |
598 | result=ApplyWayTaggingRules(tags,id); |
599 | |
600 | ProcessWayTags(result,id,mode); |
601 | |
602 | DeleteTagList(tags); |
603 | DeleteTagList(result); |
604 | } |
605 | |
606 | |
607 | /*++++++++++++++++++++++++++++++++++++++ |
608 | Process an O5M Relation dataset. |
609 | ++++++++++++++++++++++++++++++++++++++*/ |
610 | |
611 | static void process_relation() |
612 | { |
613 | int64_t delta_id; |
614 | TagList *tags=NULL,*result=NULL; |
615 | int mode=mode_change; |
616 | unsigned char *refs=NULL,*refs_end; |
617 | |
618 | delta_id=pbf_sint64(&buffer_ptr); |
619 | id+=delta_id; |
620 | |
621 | if(buffer_ptr<buffer_end) |
622 | { |
623 | if(*buffer_ptr!=0) |
624 | process_info(); |
625 | else |
626 | buffer_ptr++; |
627 | } |
628 | |
629 | if(buffer_ptr<buffer_end) |
630 | { |
631 | uint32_t length; |
632 | |
633 | length=pbf_int32(&buffer_ptr); |
634 | |
635 | if(length) |
636 | { |
637 | refs=buffer_ptr; |
638 | refs_end=buffer_ptr+length; |
639 | |
640 | buffer_ptr=refs_end; |
641 | } |
642 | } |
643 | else |
644 | mode=MODE_DELETE; |
645 | |
646 | /* Mangle the data and send it to the OSM parser */ |
647 | |
648 | nrelations++; |
649 | |
650 | if(!(nrelations%1000)) |
651 | printf_middle("Reading: Bytes=%"PRIu64" Nodes=%"PRIu64" Ways=%"PRIu64" Relations=%"PRIu64,byteno,nnodes,nways,nrelations); |
652 | |
653 | AddRelationRefs(0,0,0,NULL); |
654 | |
655 | if(refs) |
656 | while(refs<refs_end) |
657 | { |
658 | int64_t delta_ref; |
659 | unsigned char *typerole=NULL; |
660 | |
661 | delta_ref=pbf_sint64(&refs); |
662 | |
663 | typerole=process_string(1,&refs,NULL,NULL); |
664 | |
665 | if(*typerole=='0') |
666 | { |
667 | node_refid+=delta_ref; |
668 | |
669 | AddRelationRefs(node_refid,0,0,(char*)(typerole+1)); |
670 | } |
671 | else if(*typerole=='1') |
672 | { |
673 | way_refid+=delta_ref; |
674 | |
675 | AddRelationRefs(0,way_refid,0,(char*)(typerole+1)); |
676 | } |
677 | else if(*typerole=='2') |
678 | { |
679 | relation_refid+=delta_ref; |
680 | |
681 | AddRelationRefs(0,0,relation_refid,(char*)(typerole+1)); |
682 | } |
683 | } |
684 | |
685 | tags=NewTagList(); |
686 | |
687 | while(buffer_ptr<buffer_end) |
688 | { |
689 | unsigned char *key,*val; |
690 | |
691 | process_string(2,&buffer_ptr,&key,&val); |
692 | |
693 | AppendTag(tags,(char*)key,(char*)val); |
694 | } |
695 | |
696 | result=ApplyRelationTaggingRules(tags,id); |
697 | |
698 | ProcessRelationTags(result,id,mode); |
699 | |
700 | DeleteTagList(tags); |
701 | DeleteTagList(result); |
702 | } |
703 | |
704 | |
705 | /*++++++++++++++++++++++++++++++++++++++ |
706 | Process an O5M info message. |
707 | ++++++++++++++++++++++++++++++++++++++*/ |
708 | |
709 | static void process_info(void) |
710 | { |
711 | int64_t timestamp_delta; |
712 | |
713 | pbf_int32(&buffer_ptr); /* version */ |
714 | |
715 | timestamp_delta=pbf_sint64(&buffer_ptr); |
716 | timestamp+=timestamp_delta; |
717 | |
718 | if(timestamp!=0) |
719 | { |
720 | pbf_sint32(&buffer_ptr); /* changeset */ |
721 | |
722 | process_string(2,&buffer_ptr,NULL,NULL); /* user */ |
723 | } |
724 | } |
725 | |
726 | |
727 | /*++++++++++++++++++++++++++++++++++++++ |
728 | Process an O5M string and take care of maintaining the string table. |
729 | |
730 | unsigned char *process_string_pair Return a pointer to the concatenation of the two strings. |
731 | |
732 | int pair Set to 2 for a pair or 1 for a single string. |
733 | |
734 | unsigned char **buf_ptr The pointer to the buffer that is to be updated. |
735 | |
736 | unsigned char **string1 Returns a pointer to the first of the strings in the pair. |
737 | |
738 | unsigned char **string2 Returns a pointer to the second of the strings in the pair. |
739 | ++++++++++++++++++++++++++++++++++++++*/ |
740 | |
741 | static unsigned char *process_string(int pair,unsigned char **buf_ptr,unsigned char **string1,unsigned char **string2) |
742 | { |
743 | int lookup=0; |
744 | unsigned char *string; |
745 | unsigned char *p; |
746 | |
747 | if(**buf_ptr==0) |
748 | string=*buf_ptr+1; |
749 | else |
750 | { |
751 | uint32_t position=pbf_int32(buf_ptr); |
752 | |
753 | string=string_table[(string_table_start-position+STRING_TABLE_ALLOCATED)%STRING_TABLE_ALLOCATED]; |
754 | |
755 | lookup=1; |
756 | } |
757 | |
758 | p=string; |
759 | |
760 | if(pair==2) |
761 | { |
762 | if(string1) |
763 | *string1=p; |
764 | |
765 | while(*p) p++; |
766 | |
767 | p++; |
768 | |
769 | if(string2) |
770 | *string2=p; |
771 | } |
772 | |
773 | while(*p) p++; |
774 | |
775 | if(!lookup) |
776 | { |
777 | if((p-string)<252) |
778 | { |
779 | memcpy(string_table[string_table_start],string,p-string+1); |
780 | |
781 | string_table_start=(string_table_start+1)%STRING_TABLE_ALLOCATED; |
782 | } |
783 | |
784 | *buf_ptr=p+1; |
785 | } |
786 | |
787 | return(string); |
788 | } |