Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIlya Zverev <zverik@textual.ru>2015-09-28 21:53:11 +0300
committerIlya Zverev <zverik@textual.ru>2015-09-28 21:53:11 +0300
commit325c889aaba51221a2390309c4f4f4c0cc45860d (patch)
tree644ef904ba868a5b6f1da14776db5e747f199117 /tools/osmctools
parent579f82d6b50efc951db1b7adebffc534e577d0b9 (diff)
Replace osmctools with a submodule from mapsme/osmctools
Diffstat (limited to 'tools/osmctools')
m---------tools/osmctools0
-rw-r--r--tools/osmctools/osmconvert.c11943
-rw-r--r--tools/osmctools/osmfilter.c6260
-rw-r--r--tools/osmctools/osmupdate.c1650
4 files changed, 0 insertions, 19853 deletions
diff --git a/tools/osmctools b/tools/osmctools
new file mode 160000
+Subproject 6da67ed2e19bd1eb817ba5d16d1d52c193d61fd
diff --git a/tools/osmctools/osmconvert.c b/tools/osmctools/osmconvert.c
deleted file mode 100644
index 71867e3f17..0000000000
--- a/tools/osmctools/osmconvert.c
+++ /dev/null
@@ -1,11943 +0,0 @@
-// osmconvert 2015-04-13 14:20
-#define VERSION "0.8.4"
-//
-// compile this file:
-// gcc osmconvert.c -lz -O3 -o osmconvert
-//
-// (c) 2011..2015 Markus Weber, Nuernberg
-// Richard Russo contributed the initiative to --add-bbox-tags option
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Affero General Public License
-// version 3 as published by the Free Software Foundation.
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-// You should have received a copy of this license along
-// with this program; if not, see http://www.gnu.org/licenses/.
-//
-// Other licenses are available on request; please ask the author.
-//
-// Modified on 20.08.2015 by Ilya Zverev
-
-#define MAXLOGLEVEL 2
-const char* shorthelptext=
-"\nosmconvert " VERSION " Parameter Overview\n"
-"(Please use --help to get more information.)\n"
-"\n"
-"<FILE> input file name\n"
-"- read from standard input\n"
-"-b=<x1>,<y1>,<x2>,<y2> apply a border box\n"
-"-B=<border_polygon> apply a border polygon\n"
-"--complete-ways do not clip ways at the borders\n"
-"--complex-ways do not clip multipolygons at the borders\n"
-"--all-to-nodes convert ways and relations to nodes\n"
-"--add-bbox-tags adds bbox tags to ways and relations\n"
-"--add-bboxarea-tags adds tags for estimated bbox areas\n"
-"--add-bboxweight-tags adds tags for log2 of bbox areas\n"
-"--object-type-offset=<id> offset for ways/relations if --all-to-nodes\n"
-"--max-objects=<n> space for --all-to-nodes, 1 obj. = 16 bytes\n"
-"--drop-broken-refs delete references to excluded nodes\n"
-"--drop-author delete changeset and user information\n"
-"--drop-version same as before, but delete version as well\n"
-"--drop-nodes delete all nodes\n"
-"--drop-ways delete all ways\n"
-"--drop-relations delete all relations\n"
-"--diff calculate differences between two files\n"
-"--diff-contents same as before, but compare whole contents\n"
-"--subtract subtract objects given by following files\n"
-"--pbf-granularity=<val> lon/lat granularity of .pbf input file\n"
-"--emulate-osmosis emulate Osmosis XML output format\n"
-"--emulate-pbf2osm emulate pbf2osm output format\n"
-"--fake-author set changeset to 1 and timestamp to 1970\n"
-"--fake-version set version number to 1\n"
-"--fake-lonlat set lon to 0 and lat to 0\n"
-"-h display this parameter overview\n"
-"--help display a more detailed help\n"
-"--merge-versions merge versions of each object in a file\n"
-"--out-osm write output in .osm format (default)\n"
-"--out-osc write output in .osc format (OSMChangefile)\n"
-"--out-osh write output in .osh format (visible-tags)\n"
-"--out-o5m write output in .o5m format (fast binary)\n"
-"--out-o5c write output in .o5c format (bin. Changef.)\n"
-"--out-pbf write output in .pbf format (bin. standard)\n"
-"--out-csv write output in .csv format (plain table)\n"
-"--out-none no standard output (for testing purposes)\n"
-"--csv=<column names> choose columns for csv format\n"
-"--csv-headline start csv output with a headline\n"
-"--csv-separator=<sep> separator character(s) for csv format\n"
-"--timestamp=<date_time> add a timestamp to the data\n"
-"--timestamp=NOW-<seconds> add a timestamp in seconds before now\n"
-"--out-timestamp output the file\'s timestamp, nothing else\n"
-"--out-statistics write statistics, nothing else\n"
-"--statistics write statistics to stderr\n"
-"-o=<outfile> reroute standard output to a file\n"
-"-t=<tempfile> define tempfile prefix\n"
-"--parameter-file=<file> param. in file, separated by empty lines\n"
-"--verbose activate verbose mode\n";
-const char* helptext=
-"\nosmconvert " VERSION "\n"
-"\n"
-"This program reads different file formats of the OpenStreetMap\n"
-"project and converts the data to the selected output file format.\n"
-"These formats can be read:\n"
-" .osm .osc .osc.gz .osh .o5m .o5c .pbf\n"
-"These formats can be written:\n"
-" .osm (default) .osc .osh .o5m .o5c .pbf\n"
-"\n"
-"Names of input files must be specified as command line parameters.\n"
-"Use - to read from standard input. You do not need to specify the\n"
-"input formats, osmconvert will recognize them by itself.\n"
-"The output format is .osm by default. If you want a different format,\n"
-"please specify it using the appropriate command line parameter.\n"
-"\n"
-"-b=<x1>,<y1>,<x2>,<y2>\n"
-" If you want to limit the geographical region, you can define\n"
-" a bounding box. To do this, enter the southwestern and the\n"
-" northeastern corners of that area. For example:\n"
-" -b=-0.5,51,0.5,52\n"
-"\n"
-"-B=<border_polygon>\n"
-" Alternatively to a bounding box you can use a border polygon\n"
-" to limit the geographical region.\n"
-" The format of a border polygon file can be found in the OSM\n"
-" Wiki: http://wiki.openstreetmap.org/wiki/Osmosis/\n"
-" Polygon_Filter_File_Format\n"
-" You do not need to strictly follow the format description,\n"
-" you must ensure that every line of coordinates starts with\n"
-" blanks.\n"
-"\n"
-"--complete-ways\n"
-" If applying a border box or a border polygon, all nodes\n"
-" the borders are excluded; even then if they belong to a way\n"
-" which is not entirely excluded because it has some nodes\n"
-" inside the borders.\n"
-" This option will ensure that every way stays complete, even\n"
-" it it intersects the borders. This will result in slower\n"
-" processing, and the program will loose its ability to read\n"
-" from standard input. It is recommended to use .o5m format as\n"
-" input format to compensate most of the speed disadvantage.\n"
-"\n"
-"--complex-ways\n"
-" Same as before, but multipolygons will not be cut at the\n"
-" borders too.\n"
-"\n"
-"--all-to-nodes\n"
-" Some applications do not have the ability to process ways or\n"
-" relations, they just accept nodes as input. However, more and\n"
-" more complex object are mapped as ways or even relations in\n"
-" order to get all their details into the database.\n"
-" Apply this option if you want to convert ways and relations\n"
-" to nodes and thereby make them available to applications\n"
-" which can only deal with nodes.\n"
-" For each way a node is created. The way's id is increased by\n"
-" 10^15 and taken as id for the new node. The node's longitude\n"
-" and latitude are set to the way's geographical center. Same\n"
-" applies to relations, however they get 2*10^15 as id offset.\n"
-"\n"
-"--add-bbox-tags\n"
-" This option adds a tag with a bounding box to each object.\n"
-" The tag will contain the border coordinates in this order:\n"
-" min Longitude, min Latitude, max Longitude , max Latitude.\n"
-" e.g.: <tag k=\"bBox\" v=\"-0.5000,51.0000,0.5000,52.0000\"/>\n"
-"\n"
-"--add-bboxarea-tags\n"
-" A tag for an estimated area value for the bbox is added to\n"
-" each way and each relation. The unit is square meters.\n"
-" For example: <tag k=\"bBoxArea\" v=\"33828002\"/>\n"
-"\n"
-"--add-bboxweight-tags\n"
-" This option will add the binary logarithm of the bbox area\n"
-" of each way and each relation.\n"
-" For example: <tag k=\"bBoxWeight\" v=\"20\"/>\n"
-"\n"
-"--object-type-offset=<id offset>\n"
-" If applying the --all-to-nodes option as explained above, you\n"
-" may adjust the id offset. For example:\n"
-" --object-type-offset=4000000000\n"
-" By appending \"+1\" to the offset, the program will create\n"
-" ids in a sequence with step 1. This might be useful if the\n"
-" there is a subsequently running application which cannot\n"
-" process large id numbers. Example:\n"
-" --object-type-offset=1900000000+1\n"
-"\n"
-"--drop-broken-refs\n"
-" Use this option if you need to delete references to nodes\n"
-" which have been excluded because lying outside the borders\n"
-" (mandatory for some applications, e.g. Map Composer, JOSM).\n"
-"\n"
-"--drop-author\n"
-" For most applications the author tags are not needed. If you\n"
-" specify this option, no author information will be written:\n"
-" no changeset, user or timestamp.\n"
-"\n"
-"--drop-version\n"
-" If you want to exclude not only the author information but\n"
-" also the version number, specify this option.\n"
-"\n"
-"--drop-nodes\n"
-"--drop-ways\n"
-"--drop-relations\n"
-" According to the combination of these parameters, no members\n"
-" of the referred section will be written.\n"
-"\n"
-"--diff\n"
-" Calculate difference between two files and create a new .osc\n"
-" or .o5c file.\n"
-" There must be TWO input files and borders cannot be applied.\n"
-" Both files must be sorted by object type and id. Created\n"
-" objects will appear in the output file as \"modified\", unless\n"
-" having version number 1.\n"
-"\n"
-"--diff-contents\n"
-" Similar to --diff, this option calculates differences between\n"
-" two OSM files. Here, to determine the differences complete\n"
-" OSM objects are consulted, not only the version numbers.\n"
-" Unfortunately, this option strictly requires both input files\n"
-" to have .o5m format.\n"
-"\n"
-"--subtract\n"
-" The output file will not contain any object which exists in\n"
-" one of the input files following this directive. For example:\n"
-" osmconvert input.o5m --subtract minus.o5m -o=output.o5m\n"
-"\n"
-"--pbf-granularity=<val>\n"
-" Rarely .pbf files come with non-standard granularity.\n"
-" osmconvert will recognize this and suggest to specify the\n"
-" abnormal lon/lat granularity using this command line option.\n"
-" Allowed values are: 100 (default), 1000, 10000, ..., 10000000.\n"
-"\n"
-"--emulate-osmosis\n"
-"--emulate-pbf2osm\n"
-" In case of .osm output format, the program will try to use\n"
-" the same data syntax as Osmosis, resp. pbf2osm.\n"
-"\n"
-"--fake-author\n"
-" If you have dropped author information (--drop-author) that\n"
-" data will be lost, of course. Some programs however require\n"
-" author information on input although they do not need that\n"
-" data. For this purpose, you can fake the author information.\n"
-" osmconvert will write changeset 1, timestamp 1970.\n"
-"\n"
-"--fake-version\n"
-" Same as --fake-author, but - if .osm xml is used as output\n"
-" format - only the version number will be written (version 1).\n"
-" This is useful if you want to inspect the data with JOSM.\n"
-"\n"
-"--fake-lonlat\n"
-" Some programs depend on getting longitude/latitude values,\n"
-" even when the object in question shall be deleted. With this\n"
-" option you can have osmconvert to fake these values:\n"
-" ... lat=\"0\" lon=\"0\" ...\n"
-" Note that this is for XML files only (.osc and .osh).\n"
-"\n"
-"-h\n"
-" Display a short parameter overview.\n"
-"\n"
-"--help\n"
-" Display this help.\n"
-"\n"
-"--merge-versions\n"
-" Some .osc files contain different versions of one object.\n"
-" Use this option to accept such duplicates on input.\n"
-"\n"
-"--out-osm\n"
-" Data will be written in .osm format. This is the default\n"
-" output format.\n"
-"\n"
-"--out-osc\n"
-" The OSM Change format will be used for output. Please note\n"
-" that OSM objects which are to be deleted will be represented\n"
-" by their ids only.\n"
-"\n"
-"--out-osh\n"
-" For every OSM object, the appropriate \'visible\' tag will be\n"
-" added to meet \'full planet history\' specification.\n"
-"\n"
-"--out-o5m\n"
-" The .o5m format will be used. This format has the same\n"
-" structure as the conventional .osm format, but the data are\n"
-" stored as binary numbers and are therefore much more compact\n"
-" than in .osm format. No packing is used, so you can pack .o5m\n"
-" files using every file packer you want, e.g. lzo, bz2, etc.\n"
-"\n"
-"--out-o5c\n"
-" This is the change file format of .o5m data format. All\n"
-" <delete> tags will not be performed as delete actions but\n"
-" converted into .o5c data format.\n"
-"\n"
-"--out-pbf\n"
-" For output, PBF format will be used.\n"
-"\n"
-"--out-csv\n"
-" A character separated list will be written to output.\n"
-" The default separator is Tab, the default columns are:\n"
-" type, id, name. You can change both by using the options\n"
-" --csv-separator= and --csv=\n"
-"\n"
-"--csv-headline\n"
-" Choose this option to print a headline to csv output.\n"
-"\n"
-"--csv-separator=<sep>\n"
-" You may change the default separator (Tab) to a different\n"
-" character or character sequence. For example:\n"
-" --csv-separator=\"; \"\n"
-"\n"
-"--csv=<columns>\n"
-" If you want to have certain columns in your csv list, please \n"
-" specify their names as shown in this example:\n"
-" --csv=\"@id name ref description\"\n"
-" There are a few special column names for header data:\n"
-" @otype (object type 0..2), @oname (object type name), @id\n"
-" @lon, @lat, @version, @timestamp, @changeset, @uid, @user\n"
-"\n"
-"--out-none\n"
-" This will be no standard output. This option is for testing\n"
-" purposes only.\n"
-"\n"
-"--timestamp=<date_and_time>\n"
-"--timestamp=NOW<seconds_relative_to_now>\n"
-" If you want to set the OSM timestamp of your output file,\n"
-" supply it with this option. Date and time must be formatted\n"
-" according OSM date/time specifications. For example:\n"
-" --timestamp=2011-01-31T23:59:30Z\n"
-" You also can supply a relative time in seconds, e.g. 24h ago:\n"
-" --timestamp=NOW-86400\n"
-"\n"
-"--out-timestamp\n"
-" With this option set, osmconvert prints just the time stamp\n"
-" of the input file, nothing else.\n"
-"\n"
-"--statistics\n"
-" This option activates a statistics counter. The program will\n"
-" print statistical data to stderr.\n"
-"\n"
-"--out-statistics\n"
-" Same as --statistics, but the statistical data will be\n"
-" written to standard output.\n"
-"\n"
-"-o=<outfile>\n"
-" Standard output will be rerouted to the specified file.\n"
-" If no output format has been specified, the program will\n"
-" rely the file name extension.\n"
-"\n"
-"-t=<tempfile>\n"
-" If borders are to be applied or broken references to be\n"
-" eliminated, osmconvert creates and uses two temporary files.\n"
-" This parameter defines their name prefix. The default value\n"
-" is \"osmconvert_tempfile\".\n"
-"\n"
-"--parameter-file=FILE\n"
-" If you want to supply one ore more command line arguments\n"
-" by a parameter file, please use this option and specify the\n"
-" file name. Within the parameter file, parameters must be\n"
-" separated by empty lines. Line feeds inside a parameter will\n"
-" be converted to spaces.\n"
-" Lines starting with \"// \" will be treated as comments.\n"
-"\n"
-"-v\n"
-"--verbose\n"
-" With activated \'verbose\' mode, some statistical data and\n"
-" diagnosis data will be displayed.\n"
-" If -v resp. --verbose is the first parameter in the line,\n"
-" osmconvert will display all input parameters.\n"
-"\n"
-"Examples\n"
-"\n"
-"./osmconvert europe.pbf --drop-author >europe.osm\n"
-"./osmconvert europe.pbf |gzip >europe.osm.gz\n"
-"bzcat europe.osm.bz2 |./osmconvert --out-pbf >europe.pbf\n"
-"./osmconvert europe.pbf -B=ch.poly >switzerland.osm\n"
-"./osmconvert switzerland.osm --out-o5m >switzerland.o5m\n"
-"./osmconvert june_july.osc --out-o5c >june_july.o5c\n"
-"./osmconvert june.o5m june_july.o5c.gz --out-o5m >july.o5m\n"
-"./osmconvert sep.osm sep_oct.osc oct_nov.osc >nov.osm\n"
-"./osmconvert northamerica.osm southamerica.osm >americas.osm\n"
-"\n"
-"Tuning\n"
-"\n"
-"To speed-up the process, the program uses some main memory for a\n"
-"hash table. By default, it uses 900 MB for storing a flag for every\n"
-"possible node, 90 for the way flags, and 10 relation flags.\n"
-"Every byte holds the flags for 8 ID numbers, i.e., in 900 MB the\n"
-"program can store 7200 million flags. As there are less than 3200\n"
-"million IDs for nodes at present (Oct 2014), 400 MB would suffice.\n"
-"So, for example, you can decrease the hash sizes to e.g. 400, 50 and\n"
-"2 MB using this option:\n"
-"\n"
-" --hash-memory=400-50-2\n"
-"\n"
-"But keep in mind that the OSM database is continuously expanding. For\n"
-"this reason the program-own default value is higher than shown in the\n"
-"example, and it may be appropriate to increase it in the future.\n"
-"If you do not want to bother with the details, you can enter the\n"
-"amount of memory as a sum, and the program will divide it by itself.\n"
-"For example:\n"
-"\n"
-" --hash-memory=1500\n"
-"\n"
-"These 1500 MB will be split in three parts: 1350 for nodes, 135 for\n"
-"ways, and 15 for relations.\n"
-"\n"
-"Because we are taking hashes, it is not necessary to provide all the\n"
-"suggested memory; the program will operate with less hash memory too.\n"
-"But, in this case, the border filter will be less effective, i.e.,\n"
-"some ways and some relations will be left in the output file although\n"
-"they should have been excluded.\n"
-"The maximum value the program accepts for the hash size is 4000 MiB;\n"
-"If you exceed the maximum amount of memory available on your system,\n"
-"the program will try to reduce this amount and display a warning\n"
-"message.\n"
-"\n"
-"There is another temporary memory space which is used only for the\n"
-"conversion of ways and relations to nodes (option --all-to-nodes).\n"
-"This space is sufficient for up to 25 Mio. OSM objects, 400 MB of\n"
-"main memory are needed for this purpose, 800 MB if extended option\n"
-"--add-bbox-tags has been invoked. If this is not sufficient or\n"
-"if you want to save memory, you can configure the maximum number of\n"
-"OSM objects by yourself. For example:\n"
-"\n"
-" --max-objects=35000000\n"
-"\n"
-"The number of references per object is limited to 100,000. This will\n"
-"be sufficient for all OSM files. If you are going to create your own\n"
-"OSM files by converting shapefiles or other files to OSM format, this\n"
-"might result in way objects with more than 100,000 nodes. For this\n"
-"reason you will need to increase the maximum accordingly. Example:\n"
-"\n"
-" --max-refs=400000\n"
-"\n"
-"Limitations\n"
-"\n"
-"When extracting a geographical region (using -b or -B), the input\n"
-"file must contain the objects ordered by their type: first, all\n"
-"nodes, next, all ways, followed by all relations. Within each of\n"
-"these sections, the objects section must be sorted by their id in\n"
-"ascending order.\n"
-"\n"
-"Usual .osm, .osc, .o5m, o5c and .pbf files adhere to this condition.\n"
-"This means that you do not have to worry about this limitation.\n"
-"osmconvert will display an error message if this sequence is broken.\n"
-"\n"
-"If a polygon file for borders is supplied, the maximum number of\n"
-"polygon points is about 40,000.\n"
-"\n"
-"This program is for experimental use. Expect malfunctions and data\n"
-"loss. Do not use the program in productive or commercial systems.\n"
-"\n"
-"There is NO WARRANTY, to the extent permitted by law.\n"
-"Please send any bug reports to markus.weber@gmx.com\n\n";
-
-#define _FILE_OFFSET_BITS 64
-#include <zlib.h>
-#include <inttypes.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <locale.h>
-#include <time.h>
-#include <ctype.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <signal.h>
-
-typedef enum {false= 0,true= 1} bool;
-typedef uint8_t byte;
-typedef unsigned int uint;
-#define isdig(x) isdigit((unsigned char)(x))
-static int loglevel= 0; // logging to stderr;
- // 0: no logging; 1: small logging; 2: normal logging;
- // 3: extended logging;
-#define DP(f) fprintf(stderr,"Debug: " #f "\n");
-#define DPv(f,...) fprintf(stderr,"Debug: " #f "\n",__VA_ARGS__);
-#define DPM(f,p,m) { byte* pp; int i,mm; static int msgn= 3; \
- if(--msgn>=0) { fprintf(stderr,"Debug memory: " #f); \
- pp= (byte*)(p); mm= (m); if(pp==NULL) fprintf(stderr,"\n (null)"); \
- else for(i= 0; i<mm; i++) { \
- if((i%16)==0) fprintf(stderr,"\n "); \
- fprintf(stderr," %02x",*pp++); } \
- fprintf(stderr,"\n"); } }
-#define UR(x) if(x){} // result value intentionally ignored
-#if __WIN32__
- #define NL "\r\n" // use CR/LF as new-line sequence
- #define off_t off64_t
- #define lseek lseek64
- z_off64_t gzseek64(gzFile,z_off64_t,int);
- #define gzseek gzseek64
-#else
- #define NL "\n" // use LF as new-line sequence
- #define O_BINARY 0
-#endif
-
-
-
-//------------------------------------------------------------
-// Module Global global variables for this program
-//------------------------------------------------------------
-
-// to distinguish global variable from local or module global
-// variables, they are preceded by 'global_';
-
-static bool global_diff= false; // calculate diff between two files
-static bool global_diffcontents= false;
- // calculate physical diff between two files; 'physical' means
- // that not only the version number is consulted to determine
- // object differences, the whole object contents is;
-static bool global_subtract= false; // any file which is opened
- // via read_open() resp. oo_open() while global_subtract==true
- // will be subtracted, i.e. the delete flags will be inverted:
- // <delete> works as non-delete and no-<delete> works as "stay";
- // be sure to have set this variable back to false before starting
- // processing, to exclude unwanted effects on temporary files;
-static bool global_mergeversions= false; // accept duplicate versions
-static bool global_dropversion= false; // exclude version
-static bool global_dropauthor= false; // exclude author information
-static bool global_fakeauthor= false; // fake author information
-static bool global_fakeversion= false; // fake just the version number
-static bool global_fakelonlat= false;
- // fake longitude and latitude in case of delete actions (.osc);
-static bool global_dropbrokenrefs= false; // exclude broken references
-static bool global_dropnodes= false; // exclude nodes section
-static bool global_dropways= false; // exclude ways section
-static bool global_droprelations= false; // exclude relations section
-static bool global_outo5m= false; // output shall have .o5m format
-static bool global_outo5c= false; // output shall have .o5c format
-static bool global_outosm= false; // output shall have .osm format
-static bool global_outosc= false; // output shall have .osc format
-static bool global_outosh= false; // output shall have .osh format
-static bool global_outpbf= false; // output shall have .pbf format
-static bool global_outcsv= false; // output shall have .csv format
-static bool global_outnone= false; // no standard output at all
-static int32_t global_pbfgranularity= 100;
- // granularity of lon/lat in .pbf files; unit: 1 nanodegree;
-static int32_t global_pbfgranularity100= 0;
- // granularity of lon/lat in .pbf files; unit: 100 nanodegrees;
- // 0: default: 100 nanodegrees;
-static bool global_emulatepbf2osm= false;
- // emulate pbf2osm compatible output
-static bool global_emulateosmosis= false;
- // emulate Osmosis compatible output
-static bool global_emulateosmium= false;
- // emulate Osmium compatible output
-static int64_t global_timestamp= 0;
- // manually chosen file timestamp; ==0: no file timestamp given;
-static bool global_outtimestamp= false;
- // print only the file timestamp, nothing else
-static bool global_statistics= false; // print statistics to stderr
-static bool global_outstatistics= false; // print statistics to stdout
-static bool global_csvheadline= false; // headline for csv
-static char global_csvseparator[16]= "\t"; // separator for csv
-static bool global_completeways= false; // when applying borders,
- // do not clip ways but include them as whole if at least a single
- // of its nodes lies inside the borders;
-static bool global_complexways= false; // same as global_completeways,
- // but multipolygons are included completely (with all ways and their
- // nodes), even when only a single nodes lies inside the borders;
-static int global_calccoords= 0;
- // calculate coordinates for all objects;
- // 0: no coordinates to calculate; 1: calculate coordinates;
- // -1: calculate coordinates and bbox;
-static bool global_alltonodes= false;
- // convert all ways and all relations to nodes
-static bool global_add= false;
- // add at least one tag shall be added;
- // global_add==global_addbbox|global_addbboxarea|global_addbboxweight
-static bool global_addbbox= false;
- // add bBox tags to ways and relations
-static bool global_addbboxarea= false;
- // add bBoxArea tags to ways and relations
-static bool global_addbboxweight= false;
- // add bBoxWeight tags to ways and relations
-static int64_t global_maxobjects= 25000000;
-static int64_t global_otypeoffset10= INT64_C(1000000000000000);
- // if global_calccoords!=0:
- // id offset for ways; *2: id offset for relations;
-static int64_t global_otypeoffset05,
- global_otypeoffset15,global_otypeoffset20;
- // (just to save CPU time for calculating the offset of relations)
-static int64_t global_otypeoffsetstep= 0;
- // if !=0, the program will not create the new id by adding
- // global_otypeoffset but by starting at global_otypeoffset
- // and adding 1 for every new way, resp. relation:
-static char global_tempfilename[350]= "osmconvert_tempfile";
- // prefix of names for temporary files
-static int64_t global_maxrefs= 100000;
-#define PERR(f) { static int msgn= 3; if(--msgn>=0) \
- fprintf(stderr,"osmconvert Error: " f "\n"); }
- // print error message
-#define PERRv(f,...) { static int msgn= 3; if(--msgn>=0) \
- fprintf(stderr,"osmconvert Error: " f "\n",__VA_ARGS__); }
- // print error message with value(s)
-#define WARN(f) { static int msgn= 3; if(--msgn>=0) \
- fprintf(stderr,"osmconvert Warning: " f "\n"); }
- // print a warning message, do it maximal 3 times
-#define WARNv(f,...) { static int msgn= 3; if(--msgn>=0) \
- fprintf(stderr,"osmconvert Warning: " f "\n",__VA_ARGS__); }
- // print a warning message with value(s), do it maximal 3 times
-#define PINFO(f) \
- fprintf(stderr,"osmconvert: " f "\n"); // print info message
-#define PINFOv(f,...) \
- fprintf(stderr,"osmconvert: " f "\n",__VA_ARGS__);
-#define ONAME(i) \
- (i==0? "node": i==1? "way": i==2? "relation": "unknown object")
-#define global_fileM 1002 // maximum number of input files
-
-//------------------------------------------------------------
-// end Module Global global variables for this program
-//------------------------------------------------------------
-
-
-
-static inline char* uint32toa(uint32_t v,char* s) {
- // convert uint32_t integer into string;
- // v: long integer value to convert;
- // return: s;
- // s[]: digit string;
- char* s1,*s2;
- char c;
-
- s1= s;
- if(v==0)
- *s1++= '0';
- s2= s1;
- while(v>0)
- { *s2++= "0123456789"[v%10]; v/= 10; }
- *s2--= 0;
- while(s2>s1)
- { c= *s1; *s1= *s2; *s2= c; s1++; s2--; }
- return s;
- } // end uint32toa()
-
-static inline char* int64toa(int64_t v,char* s) {
- // convert int64_t integer into string;
- // v: long integer value to convert;
- // return: s;
- // s[]: digit string;
- char* s1,*s2;
- char c;
-
- s1= s;
- if(v<0)
- { *s1++= '-'; v= -v; }
- else if(v==0)
- *s1++= '0';
- s2= s1;
- while(v>0)
- { *s2++= "0123456789"[v%10]; v/= 10; }
- *s2--= 0;
- while(s2>s1)
- { c= *s1; *s1= *s2; *s2= c; s1++; s2--; }
- return s;
- } // end int64toa()
-
-static inline char *stpcpy0(char *dest, const char *src) {
- // redefinition of C99's stpcpy() because it's missing in MinGW,
- // and declaration in Linux seems to be wrong;
- while(*src!=0)
- *dest++= *src++;
- *dest= 0;
- return dest;
- } // end stpcpy0()
-
-static inline char *strmcpy(char *dest, const char *src, size_t maxlen) {
- // similar to strcpy(), this procedure copies a character string;
- // here, the length is cared about, i.e. the target string will
- // be limited in case it is too long;
- // src[]: source string which is to be copied;
- // maxlen: maximum length of the destination string
- // (including terminator null);
- // return:
- // dest[]: destination string of the copy; this is the
- // function's return value too;
- char* d;
-
- if(maxlen==0)
-return dest;
- d= dest;
- while(--maxlen>0 && *src!=0)
- *d++= *src++;
- *d= 0;
- return dest;
- } // end strmcpy()
-#define strMcpy(d,s) strmcpy((d),(s),sizeof(d))
-
-static inline char *stpmcpy(char *dest, const char *src, size_t maxlen) {
- // similar to strmcpy(), this procedure copies a character string;
- // however, it returns the address of the destination string's
- // terminating zero character;
- // this makes it easier to concatenate strings;
- char* d;
-
- if(maxlen==0)
-return dest;
- d= dest;
- while(--maxlen>0 && *src!=0)
- *d++= *src++;
- *d= 0;
- return d;
- } // end stpmcpy()
-#define stpMcpy(d,s) stpmcpy(d,s,sizeof(d))
-
-static inline int strzcmp(const char* s1,const char* s2) {
- // similar to strcmp(), this procedure compares two character strings;
- // here, the number of characters which are to be compared is limited
- // to the length of the second string;
- // i.e., this procedure can be used to identify a short string s2
- // within a long string s1;
- // s1[]: first string;
- // s2[]: string to compare with the first string;
- // return:
- // 0: both strings are identical; the first string may be longer than
- // the second;
- // -1: the first string is alphabetical smaller than the second;
- // 1: the first string is alphabetical greater than the second;
- while(*s1==*s2 && *s1!=0) { s1++; s2++; }
- if(*s2==0)
- return 0;
- return *(unsigned char*)s1 < *(unsigned char*)s2? -1: 1;
- } // end strzcmp()
-
-static inline int strzlcmp(const char* s1,const char* s2) {
- // similar to strzcmp(), this procedure compares two character strings;
- // and accepts the first string to be longer than the second;
- // other than strzcmp(), this procedure returns the length of s2[] in
- // case both string contents are identical, and returns 0 otherwise;
- // s1[]: first string;
- // s2[]: string to compare with the first string;
- // return:
- // >0: both strings are identical, the length of the second string is
- // returned; the first string may be longer than the second;
- // 0: the string contents are not identical;
- const char* s2a;
-
- s2a= s2;
- while(*s1==*s2 && *s1!=0) { s1++; s2++; }
- if(*s2==0)
- return s2-s2a;
- return 0;
- } // end strzlcmp()
-
-static inline int strycmp(const char* s1,const char* s2) {
- // similar to strcmp(), this procedure compares two character strings;
- // here, both strings are end-aligned;
- // not more characters will be compared than are existing in string s2;
- // i.e., this procedure can be used to identify a file name extension;
- const char* s1e;
- int l;
-
- l= strchr(s2,0)-s2;
- s1e= strchr(s1,0);
- if(s1e-s1<l)
-return 1;
- s1= s1e-l;
- while(*s1==*s2 && *s1!=0) { s1++; s2++; }
- if(*s2==0)
- return 0;
- return *(unsigned char*)s1 < *(unsigned char*)s2? -1: 1;
- } // end strycmp()
-
-static inline bool file_exists(const char* file_name) {
- // query if a file exists;
- // file_name[]: name of the file in question;
- // return: the file exists;
- return access(file_name,R_OK)==0;
- } // file_exists()
-
-static inline int32_t msbit(int64_t v) {
- // gets the most significant 1-bit of a 64 bit integer value;
- int32_t msb;
-
- msb= 0;
- if(v>=0x100000000LL) {
- v/= 0x100000000LL;
- msb+= 32;
- }
- if(v>=0x10000L) {
- v/= 0x10000L;
- msb+= 16;
- }
- if(v>=0x100) {
- v/= 0x100;
- msb+= 8;
- }
- if(v>=0x10) {
- v/= 0x10;
- msb+= 4;
- }
- if(v>=0x4) {
- v/= 0x4;
- msb+= 2;
- }
- if(v>=0x2) {
- v/= 0x2;
- msb+= 1;
- }
- if(v!=0) {
- msb+= 1;
- }
- return msb;
- } // msbit()
-
-static inline int64_t cosrk(int32_t lat) {
- // this procedure calculates the Cosinus of the given latitude,
- // multiplies it with 40000k/(360*10^7)==0.00012345679,
- // and takes the reciprocal value of it;
- // lat: latitude in 100 nano degrees;
- // return: constant k needed to approximate the area of a
- // coordinte-defined bbox:
- // (lonmax-lonmin)*(latmax-latmin)/k
- static const int32_t cosrktab[901]= {
- 8100,8100,8100,8100,8100,8100,8100,8100,
- 8100,8100,8101,8101,8101,8102,8102,8102,
- 8103,8103,8103,8104,8104,8105,8105,8106,
- 8107,8107,8108,8109,8109,8110,8111,8111,
- 8112,8113,8114,8115,8116,8116,8117,8118,
- 8119,8120,8121,8122,8123,8125,8126,8127,
- 8128,8129,8130,8132,8133,8134,8136,8137,
- 8138,8140,8141,8143,8144,8146,8147,8149,
- 8150,8152,8154,8155,8157,8159,8160,8162,
- 8164,8166,8168,8169,8171,8173,8175,8177,
- 8179,8181,8183,8185,8187,8189,8192,8194,
- 8196,8198,8200,8203,8205,8207,8210,8212,
- 8215,8217,8219,8222,8224,8227,8230,8232,
- 8235,8237,8240,8243,8246,8248,8251,8254,
- 8257,8260,8263,8265,8268,8271,8274,8277,
- 8280,8284,8287,8290,8293,8296,8299,8303,
- 8306,8309,8313,8316,8319,8323,8326,8330,
- 8333,8337,8340,8344,8347,8351,8355,8358,
- 8362,8366,8370,8374,8377,8381,8385,8389,
- 8393,8397,8401,8405,8409,8413,8418,8422,
- 8426,8430,8434,8439,8443,8447,8452,8456,
- 8461,8465,8470,8474,8479,8483,8488,8493,
- 8497,8502,8507,8512,8516,8521,8526,8531,
- 8536,8541,8546,8551,8556,8561,8566,8571,
- 8577,8582,8587,8592,8598,8603,8608,8614,
- 8619,8625,8630,8636,8642,8647,8653,8658,
- 8664,8670,8676,8682,8687,8693,8699,8705,
- 8711,8717,8723,8729,8736,8742,8748,8754,
- 8761,8767,8773,8780,8786,8793,8799,8806,
- 8812,8819,8825,8832,8839,8846,8852,8859,
- 8866,8873,8880,8887,8894,8901,8908,8915,
- 8922,8930,8937,8944,8951,8959,8966,8974,
- 8981,8989,8996,9004,9012,9019,9027,9035,
- 9043,9050,9058,9066,9074,9082,9090,9098,
- 9107,9115,9123,9131,9140,9148,9156,9165,
- 9173,9182,9190,9199,9208,9216,9225,9234,
- 9243,9252,9261,9270,9279,9288,9297,9306,
- 9315,9325,9334,9343,9353,9362,9372,9381,
- 9391,9400,9410,9420,9430,9439,9449,9459,
- 9469,9479,9489,9499,9510,9520,9530,9540,
- 9551,9561,9572,9582,9593,9604,9614,9625,
- 9636,9647,9658,9669,9680,9691,9702,9713,
- 9724,9736,9747,9758,9770,9781,9793,9805,
- 9816,9828,9840,9852,9864,9876,9888,9900,
- 9912,9924,9937,9949,9961,9974,9986,9999,
- 10012,10024,10037,10050,10063,10076,10089,10102,
- 10115,10128,10142,10155,10169,10182,10196,10209,
- 10223,10237,10251,10265,10279,10293,10307,10321,
- 10335,10350,10364,10378,10393,10408,10422,10437,
- 10452,10467,10482,10497,10512,10527,10542,10558,
- 10573,10589,10604,10620,10636,10652,10668,10684,
- 10700,10716,10732,10748,10765,10781,10798,10815,
- 10831,10848,10865,10882,10899,10916,10934,10951,
- 10968,10986,11003,11021,11039,11057,11075,11093,
- 11111,11129,11148,11166,11185,11203,11222,11241,
- 11260,11279,11298,11317,11337,11356,11375,11395,
- 11415,11435,11455,11475,11495,11515,11535,11556,
- 11576,11597,11618,11639,11660,11681,11702,11724,
- 11745,11767,11788,11810,11832,11854,11876,11899,
- 11921,11944,11966,11989,12012,12035,12058,12081,
- 12105,12128,12152,12176,12200,12224,12248,12272,
- 12297,12321,12346,12371,12396,12421,12446,12472,
- 12497,12523,12549,12575,12601,12627,12654,12680,
- 12707,12734,12761,12788,12815,12843,12871,12898,
- 12926,12954,12983,13011,13040,13069,13098,13127,
- 13156,13186,13215,13245,13275,13305,13336,13366,
- 13397,13428,13459,13490,13522,13553,13585,13617,
- 13649,13682,13714,13747,13780,13813,13847,13880,
- 13914,13948,13982,14017,14051,14086,14121,14157,
- 14192,14228,14264,14300,14337,14373,14410,14447,
- 14485,14522,14560,14598,14637,14675,14714,14753,
- 14792,14832,14872,14912,14952,14993,15034,15075,
- 15116,15158,15200,15242,15285,15328,15371,15414,
- 15458,15502,15546,15591,15636,15681,15726,15772,
- 15818,15865,15912,15959,16006,16054,16102,16151,
- 16200,16249,16298,16348,16398,16449,16500,16551,
- 16603,16655,16707,16760,16813,16867,16921,16975,
- 17030,17085,17141,17197,17253,17310,17367,17425,
- 17483,17542,17601,17660,17720,17780,17841,17903,
- 17964,18027,18090,18153,18217,18281,18346,18411,
- 18477,18543,18610,18678,18746,18814,18883,18953,
- 19023,19094,19166,19238,19310,19384,19458,19532,
- 19607,19683,19759,19836,19914,19993,20072,20151,
- 20232,20313,20395,20478,20561,20645,20730,20815,
- 20902,20989,21077,21166,21255,21346,21437,21529,
- 21622,21716,21811,21906,22003,22100,22199,22298,
- 22398,22500,22602,22705,22810,22915,23021,23129,
- 23237,23347,23457,23569,23682,23796,23912,24028,
- 24146,24265,24385,24507,24630,24754,24879,25006,
- 25134,25264,25395,25527,25661,25796,25933,26072,
- 26212,26353,26496,26641,26788,26936,27086,27238,
- 27391,27547,27704,27863,28024,28187,28352,28519,
- 28688,28859,29033,29208,29386,29566,29748,29933,
- 30120,30310,30502,30696,30893,31093,31295,31501,
- 31709,31920,32134,32350,32570,32793,33019,33249,
- 33481,33717,33957,34200,34447,34697,34951,35209,
- 35471,35737,36007,36282,36560,36843,37131,37423,
- 37720,38022,38329,38641,38958,39281,39609,39943,
- 40282,40628,40980,41337,41702,42073,42450,42835,
- 43227,43626,44033,44447,44870,45301,45740,46188,
- 46646,47112,47588,48074,48570,49076,49594,50122,
- 50662,51214,51778,52355,52946,53549,54167,54800,
- 55447,56111,56790,57487,58200,58932,59683,60453,
- 61244,62056,62890,63747,64627,65533,66464,67423,
- 68409,69426,70473,71552,72665,73814,75000,76225,
- 77490,78799,80153,81554,83006,84510,86071,87690,
- 89371,91119,92937,94828,96799,98854,100998,103238,
- 105580,108030,110598,113290,116118,119090,122220,125518,
- 129000,132681,136578,140712,145105,149781,154769,160101,
- 165814,171950,178559,185697,193429,201834,211004,221047,
- 232095,244305,257873,273037,290097,309432,331529,357027,
- 386774,421931,464119,515683,580138,663010,773507,928203,
- 1160248,1546993,2320483,4640960,
- 2147483647 }; // cosrk values for 10th degrees from 0 to 90
-
- lat/= 1000000;
- // transform unit 100 nano degree into unit 10th degree
- if(lat<0) lat= -lat; // make it positive
- if(lat>900) lat= 900; // set maximum of 90 degree
- return cosrktab[lat];
- } // cosrk()
-// the table in the previous procedure has been generated by this
-// program:
-#if 0 // file cosrk.c, run it with: gcc cosrk.c -lm -o cosrk && ./cosrk
-#include <stdio.h>
-#include <math.h>
-#include <inttypes.h>
-int main() {
- int i;
- printf(" static const int32_t cosrktab[901]= {");
- i= 0;
- for(i= 0;i<900;i++) {
- if(i%8==0)
- printf("\n ");
- printf("%"PRIi32",",(int32_t)(
- 1/( cos(i/1800.0*3.14159265359) *0.00012345679)
- ));
- }
- printf("\n 2147483647");
- printf(" }; // cosrk values for 10th degrees from 0 to 90\n");
- return 0; }
-#endif
-
-
-
-//------------------------------------------------------------
-// Module pbf_ protobuf conversions module
-//------------------------------------------------------------
-
-// this module provides procedures for conversions from
-// protobuf formats to regular numbers;
-// as usual, all identifiers of a module have the same prefix,
-// in this case 'pbf'; an underline will follow in case of a
-// global accessible object, two underlines in case of objects
-// which are not meant to be accessed from outside this module;
-// the sections of private and public definitions are separated
-// by a horizontal line: ----
-// many procedures have a parameter 'pp'; here, the address of
-// a buffer pointer is expected; this pointer will be incremented
-// by the number of bytes the converted protobuf element consumes;
-
-//------------------------------------------------------------
-
-static inline uint32_t pbf_uint32(byte** pp) {
- // get the value of an unsigned integer;
- // pp: see module header;
- byte* p;
- uint32_t i;
- uint32_t fac;
-
- p= *pp;
- i= *p;
- if((*p & 0x80)==0) { // just one byte
- (*pp)++;
-return i;
- }
- i&= 0x7f;
- fac= 0x80;
- while(*++p & 0x80) { // more byte(s) will follow
- i+= (*p & 0x7f)*fac;
- fac<<= 7;
- }
- i+= *p++ *fac;
- *pp= p;
- return i;
- } // end pbf_uint32()
-
-static inline int32_t pbf_sint32(byte** pp) {
- // get the value of an unsigned integer;
- // pp: see module header;
- byte* p;
- int32_t i;
- int32_t fac;
- int sig;
-
- p= *pp;
- i= *p;
- if((*p & 0x80)==0) { // just one byte
- (*pp)++;
- if(i & 1) // negative
-return -1-(i>>1);
- else
-return i>>1;
- }
- sig= i & 1;
- i= (i & 0x7e)>>1;
- fac= 0x40;
- while(*++p & 0x80) { // more byte(s) will follow
- i+= (*p & 0x7f)*fac;
- fac<<= 7;
- }
- i+= *p++ *fac;
- *pp= p;
- if(sig) // negative
-return -1-i;
- else
-return i;
- } // end pbf_sint32()
-
-static inline uint64_t pbf_uint64(byte** pp) {
- // get the value of an unsigned integer;
- // pp: see module header;
- byte* p;
- uint64_t i;
- uint64_t fac;
-
- p= *pp;
- i= *p;
- if((*p & 0x80)==0) { // just one byte
- (*pp)++;
-return i;
- }
- i&= 0x7f;
- fac= 0x80;
- while(*++p & 0x80) { // more byte(s) will follow
- i+= (*p & 0x7f)*fac;
- fac<<= 7;
- }
- i+= *p++ *fac;
- *pp= p;
- return i;
- } // end pbf_uint64()
-
-static inline int64_t pbf_sint64(byte** pp) {
- // get the value of a signed integer;
- // pp: see module header;
- byte* p;
- int64_t i;
- int64_t fac;
- int sig;
-
- p= *pp;
- i= *p;
- if((*p & 0x80)==0) { // just one byte
- (*pp)++;
- if(i & 1) // negative
-return -1-(i>>1);
- else
-return i>>1;
- }
- sig= i & 1;
- i= (i & 0x7e)>>1;
- fac= 0x40;
- while(*++p & 0x80) { // more byte(s) will follow
- i+= (*p & 0x7f)*fac;
- fac<<= 7;
- }
- i+= *p++ *fac;
- *pp= p;
- if(sig) // negative
-return -1-i;
- else
-return i;
- } // end pbf_sint64()
-
-static inline bool pbf_jump(byte** pp) {
- // jump over a protobuf formatted element - no matter
- // which kind of element;
- // pp: see module header;
- // return: the data do not meet protobuf specifications (error);
- byte* p;
- int type;
- uint32_t u;
-
- p= *pp;
- type= *p & 0x07;
- switch(type) { // protobuf type
- case 0: // Varint
- while(*p & 0x80) p++; p++; // jump over id
- while(*p & 0x80) p++; p++; // jump over data
- break;
- case 1: // fixed 64 bit;
- while(*p & 0x80) p++; p++; // jump over id
- p+= 4; // jump over data
- break;
- case 2: // String
- while(*p & 0x80) p++; p++; // jump over id
- u= pbf_uint32(&p);
- p+= u; // jump over string contents
- break;
- case 5: // fixed 32 bit;
- while(*p & 0x80) p++; p++; // jump over id
- p+= 2; // jump over data
- break;
- default: // unknown id
- fprintf(stderr,"osmconvert: Format error: 0x%02X.\n",*p);
- (*pp)++;
-return true;
- } // end protobuf type
- *pp= p;
- return false;
- } // end pbf_jump()
-
-static inline void pbf_intjump(byte** pp) {
- // jump over a protobuf formatted integer;
- // pp: see module header;
- // we do not care about a possibly existing identifier,
- // therefore as the start address *pp the address of the
- // integer value is expected;
- byte* p;
-
- p= *pp;
- while(*p & 0x80) p++; p++;
- *pp= p;
- } // end pbf_intjump()
-
-//------------------------------------------------------------
-// end Module pbf_ protobuf conversions module
-//------------------------------------------------------------
-
-
-
-//------------------------------------------------------------
-// Module hash_ OSM hash module
-//------------------------------------------------------------
-
-// this module provides three hash tables with default sizes
-// of 320, 60 and 20 MB;
-// the procedures hash_seti() and hash_geti() allow bitwise
-// access to these tables;
-// as usual, all identifiers of a module have the same prefix,
-// in this case 'hash'; an underline will follow in case of a
-// global accessible object, two underlines in case of objects
-// which are not meant to be accessed from outside this module;
-// the sections of private and public definitions are separated
-// by a horizontal line: ----
-
-static bool hash__initialized= false;
-#define hash__M 3
-static unsigned char* hash__mem[hash__M]= {NULL,NULL,NULL};
- // start of the hash fields for each object type (node, way, relation);
-static uint32_t hash__max[hash__M]= {0,0,0};
- // size of the hash fields for each object type (node, way, relation);
-static int hash__error_number= 0;
- // 1: object too large
-
-static void hash__end() {
- // clean-up for hash module;
- // will be called at program's end;
- int o; // object type
-
- for(o= 0;o<hash__M;o++) {
- hash__max[o]= 0;
- if(hash__mem[o]!=NULL) {
- free(hash__mem[o]); hash__mem[o]= NULL; }
- }
- hash__initialized= false;
- } // end hash__end()
-
-//------------------------------------------------------------
-
-static int hash_ini(int n,int w,int r) {
- // initializes the hash module;
- // n: amount of memory which is to be allocated for nodes;
- // w: amount of memory which is to be allocated for ways;
- // r: amount of memory which is to be allocated for relations;
- // range for all input parameters: 1..4000, unit: MiB;
- // the second and any further call of this procedure will be ignored;
- // return: 0: initialization has been successful (enough memory);
- // 1: memory request had to been reduced to fit the system's
- // resources (warning);
- // 2: memory request was unsuccessful (error);
- // general note concerning OSM database:
- // number of objects at Oct 2010: 950M nodes, 82M ways, 1.3M relations;
- int o; // object type
- bool warning,error;
-
- warning= error= false;
- if(hash__initialized) // already initialized
- return 0; // ignore the call of this procedure
- // check parameters and store the values
- #define D(x,o) if(x<1) x= 1; else if(x>4000) x= 4000; \
- hash__max[o]= x*(1024*1024);
- D(n,0u) D(w,1u) D(r,2u)
- #undef D
- // allocate memory for each hash table
- for(o= 0;o<hash__M;o++) { // for each hash table
- do {
- hash__mem[o]= (unsigned char*)malloc(hash__max[o]);
- if(hash__mem[o]!=NULL) { // allocation successful
- memset(hash__mem[o],0,hash__max[o]); // clear all flags
- break;
- }
- // here: allocation unsuccessful
- // reduce amount by 50%
- hash__max[o]/=2;
- warning= true;
- // memorize that the user should be warned about this reduction
- // try to allocate the reduced amount of memory
- } while(hash__max[o]>=1024);
- if(hash__mem[o]==NULL) // allocation unsuccessful at all
- error= true; // memorize that the program should be aborted
- } // end for each hash table
- atexit(hash__end); // chain-in the clean-up procedure
- if(!error) hash__initialized= true;
- return error? 2: warning? 1: 0;
- } // end hash_ini()
-
-static inline void hash_seti(int o,int64_t idi) {
- // set a flag for a specific object type and ID;
- // o: object type; 0: node; 1: way; 2: relation;
- // caution: due to performance reasons the boundaries
- // are not checked;
- // id: id of the object;
- unsigned char* mem; // address of byte in hash table
- unsigned int ido; // bit offset to idi;
-
- if(!hash__initialized) return; // error prevention
- idi+= ((int64_t)hash__max[o])<<3; // consider small negative numbers
- ido= idi&0x7; // extract bit number (0..7)
- idi>>=3; // calculate byte offset
- idi%= hash__max[o]; // consider length of hash table
- mem= hash__mem[o]; // get start address of hash table
- mem+= idi; // calculate address of the byte
- *mem|= (1<<ido); // set bit
- } // end hash_seti()
-
-static inline void hash_cleari(int o,int64_t idi) {
- // clears a flag for a specific object type and ID;
- // o: object type; 0: node; 1: way; 2: relation;
- // caution: due to performance reasons the boundaries
- // are not checked;
- // id: id of the object;
- unsigned char* mem; // address of byte in hash table
- unsigned int ido; // bit offset to idi;
-
- if(!hash__initialized) return; // error prevention
- idi+= ((int64_t)hash__max[o])<<3; // consider small negative numbers
- ido= idi&0x7; // extract bit number (0..7)
- idi>>=3; // calculate byte offset
- idi%= hash__max[o]; // consider length of hash table
- mem= hash__mem[o]; // get start address of hash table
- mem+= idi; // calculate address of the byte
- *mem&= (unsigned char)(~0)^(1<<ido); // clear bit
- } // end hash_cleari()
-
-static inline bool hash_geti(int o,int64_t idi) {
- // get the status of a flag for a specific object type and ID;
- // (same as previous procedure, but id must be given as number);
- // o: object type; 0: node; 1: way; 2: relation; caution:
- // due to performance reasons the boundaries are not checked;
- // id: id of the object;
- unsigned char* mem;
- unsigned int ido; // bit offset to idi;
- bool flag;
-
- if(!hash__initialized) return true; // error prevention
- idi+= ((int64_t)hash__max[o])<<3; // consider small negative numbers
- ido= idi&0x7; // extract bit number (0..7)
- idi>>=3; // calculate byte offset
- idi%= hash__max[o]; // consider length of hash table
- mem= hash__mem[o]; // get start address of hash table
- mem+= idi; // calculate address of the byte
- flag= (*mem&(1<<ido))!=0; // get status of the addressed bit
- return flag;
- } // end hash_geti();
-
-static int hash_queryerror() {
- // determine if an error has occurred;
- return hash__error_number;
- } // end hash_queryerror()
-
-//------------------------------------------------------------
-// end Module hash_ OSM hash module
-//------------------------------------------------------------
-
-
-
-//------------------------------------------------------------
-// Module border_ OSM border module
-//------------------------------------------------------------
-
-// this module provides procedures for reading the border file
-// (.poly) and determine if a point lies inside or outside the
-// border polygon;
-// as usual, all identifiers of a module have the same prefix,
-// in this case 'border'; an underline will follow in case of a
-// global accessible object, two underlines in case of objects
-// which are not meant to be accessed from outside this module;
-// the sections of private and public definitions are separated
-// by a horizontal line: ----
-
-static const int32_t border__nil= 2000000000L;
-static int32_t border__bx1= 2000000000L,border__by1,
- border__bx2,border__by2;
- // in case of a border box:
- // coordinates of southwest and northeast corner;
-// in case of a border polygon:
-// for the border polygon, every edge is stored in a list;
-// to speed-up the inside/outside question we need to sort the edges
-// by x1; subsequently, for every edge there must be stored references
-// which refer to all that edges which overlap horizontally with
-// that region between x1 and the next higher x1 (x1 of the next edge
-// in the sorted list);
-#define border__edge_M 600004
-typedef struct border__edge_t {
- int32_t x1,y1,x2,y2; // coordinates of the edge; always: x1<x2;
- struct border__chain_t* chain;
- } border__edge_t;
- // the last element in this list will have x1==border__nil;
-static border__edge_t* border__edge;
-static int border__edge_n= 0; // number of elements in border__edge[0]
-#define border__chain_M (border__edge_M*8)
-typedef struct border__chain_t {
- border__edge_t* edge;
- struct border__chain_t* next;
- } border__chain_t;
- // the last element in this list will have edge==NULL;
- // the last element of each chain will be terminated with next==NULL;
-static border__chain_t* border__chain;
-
-static void border__end() {
- // close this module;
- // this procedure has no parameters because we want to be able
- // to call it via atexit();
-
- if(border__edge!=NULL)
- free(border__edge);
- border__edge= NULL;
- border__edge_n= 0;
- if(border__chain!=NULL)
- free(border__chain);
- border__chain= NULL;
- } // end border__end()
-
-static inline bool border__ini() {
- // initialize this module;
- // you may call this procedure repeatedly; only the first call
- // will have effect; subsequent calls will be ignored;
- // return: ==true: success, or the call has been ignored;
- // ==false: an error occurred during initialization;
- static bool firstrun= true;
-
- if(firstrun) {
- firstrun= false;
- atexit(border__end);
- border__edge= (border__edge_t*)
- malloc((border__edge_M+4)*sizeof(border__edge_t));
- if(border__edge==NULL)
-return false;
- border__chain= (border__chain_t*)
- malloc((border__chain_M+4)*sizeof(border__chain_t));
- if(border__chain==NULL)
-return false;
- }
- return true;
- } // end border__ini()
-
-static int border__qsort_edge(const void* a,const void* b) {
- // edge comparison for qsort()
- int32_t ax,bx;
-
- ax= ((border__edge_t*)a)->x1;
- bx= ((border__edge_t*)b)->x1;
- if(ax>bx)
-return 1;
- if(ax==bx)
-return 0;
- return -1;
- } // end border__qsort_edge()
-
-//------------------------------------------------------------
-
-static bool border_active= false; // borders are to be considered;
- // this variable must not be written from outside of the module;
-
-static bool border_box(const char* s) {
- // read coordinates of a border box;
- // s[]: coordinates as a string; example: "11,49,11.3,50"
- // return: success;
- double x1f,y1f; // coordinates of southwestern corner
- double x2f,y2f; // coordinates of northeastern corner
- int r;
-
- x1f= y1f= x2f= y2f= 200.1;
- r= sscanf(s,"%lG,%lG,%lG,%lG",&x1f,&y1f,&x2f,&y2f);
- if(r!=4 || x1f<-180.1 || x1f>180.1 || y1f<-90.1 || y1f>90.1 ||
- x2f<-180.1 || x2f>180.1 || y2f<-90.1 || y2f>90.1)
-return false;
- border_active=true;
- border__bx1= (int32_t)(x1f*10000000L);
- // convert floatingpoint to fixpoint
- border__by1= (int32_t)(y1f*10000000L);
- border__bx2= (int32_t)(x2f*10000000L);
- border__by2= (int32_t)(y2f*10000000L);
- return true;
- } // end border_box()
-
-static bool border_file(const char* fn) {
- // read border polygon file, store the coordinates, and determine
- // an enclosing border box to speed-up the calculations;
- // fn[]: file name;
- // return: success;
- static int32_t nil;
-
- if(!border__ini())
-return false;
- nil= border__nil;
-
- /* get border polygon */ {
- border__edge_t* bep; // growing pointer in border__edge[]
- border__edge_t* bee; // memory end of border__edge[]
- FILE* fi;
- char s[80],*sp;
- int32_t x0,y0; // coordinate of the first point in a section;
- // this is used to close an unclosed polygon;
- int32_t x1,y1; // last coordinates
- int32_t x,y;
-
- border__edge[0].x1= nil;
- fi= fopen(fn,"rb");
- if(fi==NULL)
-return false;
- bee= border__edge+(border__edge_M-2);
- bep= border__edge;
- x0= nil; // (sign that there is no first coordinate at the moment)
- x1= nil; // (sign that there is no last coordinate at the moment)
- for(;;) { // for every line in border file
- s[0]= 0;
- sp= fgets(s,sizeof(s),fi);
- if(bep>=bee) {
- fclose(fi);
-return false;
- }
- if(s[0]!=' ' && s[0]!='\t') { // not inside a section
- if(x0!=nil && x1!=nil && (x1!=x0 || y1!=y0)) {
- // last polygon was not closed
- if(x1==x0) { // the edge would be vertical
- // we have to insert an additional edge
- x0+= 3;
- if(x0>x1)
- { bep->x1= x1; bep->y1= y1; bep->x2= x0; bep->y2= y0; }
- else
- { bep->x1= x0; bep->y1= y0; bep->x2= x1; bep->y2= y1; }
- bep->chain= NULL;
- if(loglevel>=1)
- fprintf(stderr,
- "+ %i %"PRIi32",%"PRIi32",%"PRIi32",%"PRIi32"\n",
- (int)(bep-border__edge),
- bep->x1,bep->y1,bep->x2,bep->y2);
- bep++;
- x1= x0; y1= y0;
- x0-= 3;
- } // the edge would be vertical
- // close the polygon
- if(x0>x1)
- { bep->x1= x1; bep->y1= y1; bep->x2= x0; bep->y2= y0; }
- else
- { bep->x1= x0; bep->y1= y0; bep->x2= x1; bep->y2= y1; }
- bep->chain= NULL;
- if(loglevel>=1)
- fprintf(stderr,
- "c %i %"PRIi32",%"PRIi32",%"PRIi32",%"PRIi32"\n",
- (int)(bep-border__edge),bep->x1,bep->y1,bep->x2,bep->y2);
- bep++;
- } // end last polygon was not closed
- x0= x1= nil;
- } // end not inside a section
- else { // inside a section
- double xf,yf;
-
- xf= yf= 200.1;
- sscanf(s+1,"%lG %lG",&xf,&yf);
- if(xf<-180.1 || xf>180.1 || yf<-90.1 || yf>90.1) x= nil;
- else {
- x= (int32_t)(xf*10000000+0.5);
- y= (int32_t)(yf*10000000+0.5);
- }
- if(x!=nil) { // data plausible
- if(x1!=nil) { // there is a preceding coordinate
- if(x==x1) x+= 2; // do not accept exact north-south
- // lines, because then we may not be able to determine
- // if a point lies inside or outside the polygon;
- if(x>x1)
- { bep->x1= x1; bep->y1= y1; bep->x2= x; bep->y2= y; }
- else
- { bep->x1= x; bep->y1= y; bep->x2= x1; bep->y2= y1; }
- bep->chain= NULL;
- if(loglevel>=1)
- fprintf(stderr,
- "- %i %"PRIi32",%"PRIi32",%"PRIi32",%"PRIi32"\n",
- (int)(bep-border__edge),
- bep->x1,bep->y1,bep->x2,bep->y2);
- bep++;
- } // end there is a preceding coordinate
- x1= x; y1= y;
- if(x0==nil)
- { x0= x; y0= y; }
- } // end data plausible
- } // end inside a section
- if(sp==NULL) // end of border file
- break;
- } // end for every line in border file
- fclose(fi);
- bep->x1= nil; // set terminator of edge list
- border__edge_n= bep-border__edge; // set number of edges
- } // end get border polygon
-
- // sort edges ascending by x1 value
- if(loglevel>=1)
- fprintf(stderr,"Border polygons: %i. Now sorting.\n",
- border__edge_n);
- qsort(border__edge,border__edge_n,sizeof(border__edge_t),
- border__qsort_edge);
-
- /* generate chains for each edge */ {
- int32_t x2;
- border__chain_t* bcp; // growing pointer in chain storage
- border__edge_t* bep; // pointer in border__edge[]
- border__edge_t* bep2; // referenced edge
- border__chain_t* bcp2; // chain of referenced edge;
-
- bep= border__edge;
- bcp= border__chain;
- while(bep->x1!=nil) { // for each edge in list
- if(loglevel>=1)
- fprintf(stderr,
- "> %i %"PRIi32",%"PRIi32",%"PRIi32",%"PRIi32"\n",
- (int)(bep-border__edge),bep->x1,bep->y1,bep->x2,bep->y2);
- /*x1= bep->x1;*/ x2= bep->x2;
- bep2= bep;
- while(bep2>border__edge && (bep2-1)->x1==bep2->x1) bep2--;
- // we must examine previous edges having same x1 too;
- while(bep2->x1!=nil && bep2->x1 <= x2) {
- // for each following overlapping edge in list
- if(bep2==bep) { // own edge
- bep2++; // (needs not to be chained to itself)
- continue;
- }
- if(bcp>=border__chain+border__chain_M)
- // no more space in chain storage
-return false;
- if(loglevel>=2)
- fprintf(stderr,"+ add to chain of %i\n",
- (int)(bep2-border__edge));
- bcp2= bep2->chain;
- if(bcp2==NULL) // no chain yet
- bep2->chain= bcp; // add first chain link
- else { // edge already has a chain
- // go to the chain's end and add new chain link there
-
- while(bcp2->next!=NULL) bcp2= bcp2->next;
- bcp2->next= bcp;
- } // end edge already has a chain
- bcp->edge= bep;
- // add source edge to chain of overlapping edges
- bcp->next= NULL; // new chain termination
- bcp++;
- bep2++;
- } // for each following overlapping edge in list
- bep++;
- } // end for each edge in list
- } // end generate chains for each edge
-
- // test output
- if(loglevel>=2) {
- border__edge_t* bep,*bep2; // pointers in border__edge[]
- border__chain_t* bcp; // pointer in chain storage
-
- fprintf(stderr,"Chains:\n");
- bep= border__edge;
- while(bep->x1!=nil) { // for each edge in list
- fprintf(stderr,
- "> %i %"PRIi32",%"PRIi32",%"PRIi32",%"PRIi32"\n",
- (int)(bep-border__edge),bep->x1,bep->y1,bep->x2,bep->y2);
- bcp= bep->chain;
- while(bcp!=NULL) { // for each chain link in edge
- bep2= bcp->edge;
- fprintf(stderr,
- " %i %"PRIi32",%"PRIi32",%"PRIi32",%"PRIi32"\n",
- (int)(bep2-border__edge),
- bep2->x1,bep2->y1,bep2->x2,bep2->y2);
- bcp= bcp->next;
- } // end for each chain link in edge
- bep++;
- } // end for each edge in list
- } // end test output
-
- /* determine enclosing border box */ {
- border__edge_t* bep; // pointer in border__edge[]
-
- border__bx1= border__edge[0].x1;
- border__bx2= -2000000000L; // (default)
- border__by1= 2000000000L; border__by2= -2000000000L; // (default)
- bep= border__edge;
- while(bep->x1!=nil) { // for each coordinate of the polygon
- if(bep->x2>border__bx2) border__bx2= bep->x2;
- if(bep->y1<border__by1) border__by1= bep->y1;
- if(bep->y2<border__by1) border__by1= bep->y2;
- if(bep->y1>border__by2) border__by2= bep->y1;
- if(bep->y2>border__by2) border__by2= bep->y2;
- bep++;
- } // end for each coordinate of the polygon
- } // end determine enclosing border box
- border_active=true;
- if(loglevel>=1)
- fprintf(stderr,"End of border initialization.\n");
- return true;
- } // end border_file()
-
-static bool border_queryinside(int32_t x,int32_t y) {
- // determine if the given coordinate lies inside or outside the
- // border polygon(s);
- // x,y: coordinates of the given point in 0.0000001 degrees;
- // return: point lies inside the border polygon(s);
- static int32_t nil;
-
- nil= border__nil;
-
- #if MAXLOGLEVEL>=3
- if(loglevel>=3)
- fprintf(stderr,"# %li,%li\n",x,y);
- #endif
- // first, consider border box (if any)
- if(border__bx1!=nil) { // there is a border box
- if(x<border__bx1 || x>border__bx2 ||
- y<border__by1 || y>border__by2)
- // point lies outside the border box
-return false;
- } // end there is a border box
-
- /* second, consider border polygon (if any) */ {
- border__edge_t* bep; // pointer in border__edge[]
- border__chain_t* bcp; // pointer in border__chain[]
- int cross; // number of the crossings a line from the point
- // to the north pole would have ageinst the border lines
- // in border__coord[][];
-
- if(border__edge==NULL)
-return true;
- cross= 0;
-
- /* binary-search the edge with the closest x1 */ {
- int i,i1,i2; // iteration indexes
-
- i1= 0; i2= border__edge_n;
- while(i2>i1+1) {
- i= (i1+i2)/2;
- bep= border__edge+i;
-//fprintf(stderr,"s %i %i %i %li\n",i1,i,i2,bep->x1); ///
- if(bep->x1 > x) i2= i;
- else i1= i;
-//fprintf(stderr," %i %i %i\n",i1,i,i2); ///
- }
- bep= border__edge+i1;
- } // end binary-search the edge with the closest x1
-
- bcp= NULL;
- // (default, because we want to examine the own edge first)
- for(;;) { // for own edge and each edge in chain
- if(bep->x1 <= x && bep->x2 > x) { // point lies inside x-range
- if(bep->y1 > y && bep->y2 > y) {
- // line lies completely north of point
- cross++;
- #if MAXLOGLEVEL>=3
- if(loglevel>=3)
- fprintf(stderr,"= %i %li,%li,%li,%li\n",
- (int)(bep-border__edge),bep->x1,bep->y1,bep->x2,bep->y2);
- #endif
- }
- else if(bep->y1 > y || bep->y2 > y) {
- // one line end lies north of point
- if( (int64_t)(y-bep->y1)*(int64_t)(bep->x2-bep->x1) <
- (int64_t)(x-bep->x1)*(int64_t)(bep->y2-bep->y1) ) {
- // point lies south of the line
- cross++;
- #if MAXLOGLEVEL>=3
- if(loglevel>=3)
- fprintf(stderr,"/ %i %li,%li,%li,%li\n",
- (int)(bep-border__edge),
- bep->x1,bep->y1,bep->x2,bep->y2);
- #endif
- }
- #if MAXLOGLEVEL>=3
- else if(loglevel>=3)
- fprintf(stderr,". %i %li,%li,%li,%li\n",
- (int)(bep-border__edge),
- bep->x1,bep->y1,bep->x2,bep->y2);
- #endif
- } // end one line end north of point
- #if MAXLOGLEVEL>=3
- else if(loglevel>=3)
- fprintf(stderr,"_ %i %li,%li,%li,%li\n",
- (int)(bep-border__edge),bep->x1,bep->y1,bep->x2,bep->y2);
- #endif
- } // end point lies inside x-range
- if(bcp==NULL) // chain has not been examined
- bcp= bep->chain; // get the first chain link
- else
- bcp= bcp->next; // get the next chain link
- if(bcp==NULL) // no more chain links
- break;
- bep= bcp->edge;
- } // end for own edge and each edge in chain
-//if(loglevel>=3) fprintf(stderr,"# %li,%li cross %i\n",x,y,cross);
-return (cross&1)!=0; // odd number of crossings
- } // end second, consider border polygon (if any)
- } // end border_queryinside()
-
-static void border_querybox(int32_t* x1p,int32_t* y1p,
- int32_t* x2p,int32_t* y2p) {
- // get the values of a previously defined border box;
- // border_box() or border_file() must have been called;
- // return values are valid only if border_active==true;
- // *x1p,*y1p; // coordinates of southwestern corner;
- // *x2p,*y2p; // coordinates of northeastern corner;
- int32_t x1,y1,x2,y2;
-
- if(!border_active) {
- *x1p= *y1p= *x2p= *y2p= 0;
-return;
- }
- x1= border__bx1; y1= border__by1;
- x2= border__bx2; y2= border__by2;
- // round coordinates a bit
- #define D(x) { if(x%1000==1) { if(x>0) x--; else x++; } \
- else if((x)%1000==999) { if((x)>0) x++; else x--; } }
- D(x1) D(y1) D(x2) D(y2)
- #undef D
- *x1p= x1; *y1p= y1; *x2p= x2; *y2p= y2;
- } // end border_querybox()
-
-//------------------------------------------------------------
-// end Module border_ OSM border module
-//------------------------------------------------------------
-
-
-
-//------------------------------------------------------------
-// Module read_ OSM file read module
-//------------------------------------------------------------
-
-// this module provides procedures for buffered reading of
-// standard input;
-// as usual, all identifiers of a module have the same prefix,
-// in this case 'read'; an underline will follow in case of a
-// global accessible object, two underlines in case of objects
-// which are not meant to be accessed from outside this module;
-// the sections of private and public definitions are separated
-// by a horizontal line: ----
-
-#define read_PREFETCH ((32+3)*1024*1024)
- // number of bytes which will be available in the buffer after
- // every call of read_input();
- // (important for reading .pbf files:
- // size must be greater than pb__blockM)
-#define read__bufM (read_PREFETCH*5) // length of the buffer;
-#define read_GZ 3 // determines which read procedure set will be used;
- // ==0: use open(); ==1: use fopen();
- // ==2: use gzopen() (accept gzip compressed input files);
- // ==3: use gzopen() with increased gzip buffer;
-typedef struct { // members may not be accessed from external
- #if read_GZ==0
- int fd; // file descriptor
- off_t jumppos; // position to jump to; -1: invalid
- #elif read_GZ==1
- FILE* fi; // file stream
- off_t jumppos; // position to jump to; -1: invalid
- #else
- gzFile fi; // gzip file stream
- #if __WIN32__
- z_off64_t jumppos; // position to jump to; -1: invalid
- #else
- z_off_t jumppos; // position to jump to; -1: invalid
- #endif
- #endif
- int64_t counter;
- // byte counter to get the read position in input file;
- char filename[300];
- bool isstdin; // is standard input
- bool eof; // we are at the end of input file
- byte* bufp; // pointer in buf[]
- byte* bufe; // pointer to the end of valid input in buf[]
- uint64_t bufferstart;
- // dummy variable which marks the start of the read buffer
- // concatenated with this instance of read info structure;
- } read_info_t;
-static bool read__jumplock= false; // do not change .jumppos anymore;
-
-//------------------------------------------------------------
-
-static read_info_t* read_infop= NULL;
- // presently used read info structure, i.e. file handle
-#define read__buf ((byte*)&read_infop->bufferstart)
- // start address of the file's input buffer
-static byte* read_bufp= NULL; // may be incremented by external
- // up to the number of read_PREFETCH bytes before read_input() is
- // called again;
-static byte* read_bufe= NULL; // may not be changed from external
-
-static int read_open(const char* filename) {
- // open an input file;
- // filename[]: path and name of input file;
- // ==NULL: standard input;
- // return: 0: ok; !=0: error;
- // read_infop: handle of the file;
- // note that you should close every opened file with read_close()
- // before the program ends;
-
- // save status of presently processed input file (if any)
- if(read_infop!=NULL) {
- read_infop->bufp= read_bufp;
- read_infop->bufp= read_bufe;
- }
-
- // get memory space for file information and input buffer
- read_infop= (read_info_t*)malloc(sizeof(read_info_t)+read__bufM);
- if(read_infop==NULL) {
- fprintf(stderr,"osmconvert Error: could not get "
- "%i bytes of memory.\n",read__bufM);
-return 1;
- }
-
- // initialize read info structure
- #if read_GZ==0
- read_infop->fd= 0; // (default) standard input
- #else
- read_infop->fi= NULL; // (default) file not opened
- #endif
- if((read_infop->isstdin= filename==NULL))
- strcpy(read_infop->filename,"standard input");
- else
- strMcpy(read_infop->filename,filename);
- read_infop->eof= false; // we are not at the end of input file
- read_infop->bufp= read_infop->bufe= read__buf; // pointer in buf[]
- // pointer to the end of valid input in buf[]
- read_infop->counter= 0;
- read_infop->jumppos= 0;
- // store start of file as default jump destination
-
- // set modul-global variables which are associated with this file
- read_bufp= read_infop->bufp;
- read_bufe= read_infop->bufe;
-
- // open the file
- if(loglevel>=2)
- fprintf(stderr,"Read-opening: %s\n",read_infop->filename);
- if(read_infop->isstdin) { // stdin shall be used
- #if read_GZ==0
- read_infop->fd= 0;
- #elif read_GZ==1
- read_infop->fi= stdin;
- #else
- read_infop->fi= gzdopen(0,"rb");
- #if read_GZ==3 && ZLIB_VERNUM>=0x1235
- gzbuffer(read_infop->fi,128*1024);
- #endif
- #endif
- }
- else if(filename!=NULL) { // a real file shall be opened
- #if read_GZ==0
- read_infop->fd= open(filename,O_RDONLY|O_BINARY);
- #elif read_GZ==1
- read_infop->fi= fopen(filename,"rb");
- #else
- read_infop->fi= gzopen(filename,"rb");
- #if read_GZ==3 && ZLIB_VERNUM>=0x1235
- if(loglevel>=2)
- fprintf(stderr,"Read-opening: increasing gzbuffer.\n");
- gzbuffer(read_infop->fi,128*1024);
- #endif
- #endif
- #if read_GZ==0
- if(read_infop->fd<0) {
- #else
- if(read_infop->fi==NULL) {
- #endif
- fprintf(stderr,
- "osmconvert Error: could not open input file: %.80s\n",
- read_infop->filename);
- free(read_infop); read_infop= NULL;
- read_bufp= read_bufe= NULL;
-return 1;
- }
- } // end a real file shall be opened
-return 0;
- } // end read_open()
-
-static void read_close() {
- // close an opened file;
- // read_infop: handle of the file which is to close;
- if(read_infop==NULL) // handle not valid;
-return;
- if(loglevel>=2)
- fprintf(stderr,"Read-closing: %s\n",read_infop->filename);
- #if read_GZ==0
- if(read_infop->fd>0) // not standard input
- close(read_infop->fd);
- #elif read_GZ==1
- if(!read_infop->isstdin) // not standard input
- fclose(read_infop->fi);
- #else
- gzclose(read_infop->fi);
- #endif
- free(read_infop); read_infop= NULL;
- read_bufp= read_bufe= NULL;
- } // end read_close()
-
-static inline bool read_input() {
- // read data from standard input file, use an internal buffer;
- // make data available at read_bufp;
- // read_open() must have been called before calling this procedure;
- // return: there are no (more) bytes to read;
- // read_bufp: start of next bytes available;
- // may be incremented by the caller, up to read_bufe;
- // read_bufe: end of bytes in buffer;
- // must not be changed by the caller;
- // after having called this procedure, the caller may rely on
- // having available at least read_PREFETCH bytes at address
- // read_bufp - with one exception: if there are not enough bytes
- // left to read from standard input, every byte after the end of
- // the reminding part of the file in the buffer will be set to
- // 0x00 - up to read_bufp+read_PREFETCH;
- int l,r;
-
- if(read_bufp+read_PREFETCH>=read_bufe) { // read buffer is too low
- if(!read_infop->eof) { // still bytes in the file
- if(read_bufe>read_bufp) { // bytes remaining in buffer
- memmove(read__buf,read_bufp,read_bufe-read_bufp);
- // move remaining bytes to start of buffer
- read_bufe= read__buf+(read_bufe-read_bufp);
- // protect the remaining bytes at buffer start
- }
- else // no remaining bytes in buffer
- read_bufe= read__buf; // no bytes remaining to protect
- // add read bytes to debug counter
- read_bufp= read__buf;
- do { // while buffer has not been filled
- l= (read__buf+read__bufM)-read_bufe-4;
- // number of bytes to read
- #if read_GZ==0
- r= read(read_infop->fd,read_bufe,l);
- #elif read_GZ==1
- r= read(fileno(read_infop->fi),read_bufe,l);
- #else
- r= gzread(read_infop->fi,read_bufe,l);
- #endif
- if(r<=0) { // no more bytes in the file
- read_infop->eof= true;
- // memorize that there we are at end of file
- l= (read__buf+read__bufM)-read_bufe;
- // reminding space in buffer
- if(l>read_PREFETCH) l= read_PREFETCH;
- memset(read_bufe,0,l); // 2011-12-24
- // set reminding space up to prefetch bytes in buffer to 0
- break;
- }
- read_infop->counter+= r;
- read_bufe+= r; // set new mark for end of data
- read_bufe[0]= 0; read_bufe[1]= 0; // set 4 null-terminators
- read_bufe[2]= 0; read_bufe[3]= 0;
- } while(r<l); // end while buffer has not been filled
- } // end still bytes to read
- } // end read buffer is too low
- return read_infop->eof && read_bufp>=read_bufe;
- } // end read__input()
-
-static void read_switch(read_info_t* filehandle) {
- // switch to another already opened file;
- // filehandle: handle of the file which shall be switched to;
-
- // first, save status of presently processed input file
- if(read_infop!=NULL) {
- read_infop->bufp= read_bufp;
- read_infop->bufe= read_bufe;
- }
- // switch to new file information
- read_infop= filehandle;
- read_bufp= read_infop->bufp;
- read_bufe= read_infop->bufe;
- read_input();
- } // end read_switch()
-
-static inline int read_rewind() {
- // rewind the file, i.e., the file pointer is set
- // to the first byte in the file;
- // read_infop: handle of the file which is to rewind;
- // return: ==0: ok; !=0: rewind error;
- bool err;
-
- #if read_GZ==0
- err= lseek(read_infop->fd,0,SEEK_SET)<0;
- #elif read_GZ==1
- err= fseek(read_infop->fi,0,SEEK_SET)<0;
- #else
- err= gzseek(read_infop->fi,0,SEEK_SET)<0;
- #endif
- if(err) {
- PERRv("could not rewind file: %-80s",read_infop->filename)
-return 1;
- }
- read_infop->counter= 0;
- read_bufp= read_bufe; // force refetch
- read_infop->eof= false; // force retest for end of file
- read_input(); // ensure prefetch
-return 0;
- } // end read_rewind()
-
-static inline bool read_setjump() {
- // store the current position in the file as a destination
- // for a jump which will follow later;
- // if global_complexways is false, the call will be ignored;
- // the position is not stored anew if it has been locked
- // with read_infop->lockpos;
- // return: jump position has been stored;
- if(!global_complexways)
-return false;
- if(read__jumplock)
-return false;
- read_infop->jumppos= read_infop->counter-(read_bufe-read_bufp);
- return true;
- } // end read_setjump()
-
-static inline void read_lockjump() {
- // prevent a previously stored jump position from being overwritten;
- read__jumplock= true;
- } // end read_lockjump()
-
-static int read_jump() {
- // jump to a previously stored location it;
- // return: 0: jump ok;
- // 1: did not actually jump because we already were
- // at the desired position;
- // <0: error;
- #if read_GZ<2
- off_t pos; // present position in the file;
- #else
- #if __WIN32__
- z_off64_t pos; // position to jump to; -1: invalid
- #else
- z_off_t pos; // position to jump to; -1: invalid
- #endif
- #endif
- bool err;
-
- pos= read_infop->counter-(read_bufe-read_bufp);
- if(read_infop->jumppos==-1) {
- PERRv("no jump destination in file: %.80s",read_infop->filename)
-return -1;
- }
- #if read_GZ==0
- err= lseek(read_infop->fd,read_infop->jumppos,SEEK_SET)<0;
- #elif read_GZ==1
- err= fseek(read_infop->fi,read_infop->jumppos,SEEK_SET)<0;
- #else
- err= gzseek(read_infop->fi,read_infop->jumppos,SEEK_SET)<0;
- #endif
- if(err) {
- PERRv("could not jump in file: %.80s",read_infop->filename)
-return -2;
- }
- if(read_infop->jumppos!=pos) { // this was a real jump
- read_infop->counter= read_infop->jumppos;
- read_bufp= read_bufe; // force refetch
- read_infop->eof= false; // force retest for end of file
- read_input(); // ensure prefetch
-return 0;
- }
- // here: did not actually jump because we already were
- // at the desired position
-return 1;
- } // end read_jump()
-
-//------------------------------------------------------------
-// end Module read_ OSM file read module
-//------------------------------------------------------------
-
-
-
-//------------------------------------------------------------
-// Module write_ write module
-//------------------------------------------------------------
-
-// this module provides a procedure which writes a byte to
-// standard output;
-// as usual, all identifiers of a module have the same prefix,
-// in this case 'write'; an underline will follow in case of a
-// global accessible object, two underlines in case of objects
-// which are not meant to be accessed from outside this module;
-// the sections of private and public definitions are separated
-// by a horizontal line: ----
-
-static const char* write__filename= NULL;
- // last name of the file; ==NULL: standard output;
-static const char* write__filename_standard= NULL;
- // name of standard output file; ==NULL: standard output;
-static const char* write__filename_temp= NULL;
- // name of the tempfile; ==NULL: no tempfile;
-static char write__buf[UINT64_C(16000000)];
-static char* write__bufe= write__buf+sizeof(write__buf);
- // (const) water mark for buffer filled 100%
-static char* write__bufp= write__buf;
-static int write__fd= 1; // (initially standard output)
-static int write__fd_standard= 1; // (initially standard output)
-static inline void write_flush();
-
-static void write__close() {
- // close the last opened file;
- if(loglevel>=2)
- fprintf(stderr,"Write-closing FD: %i\n",write__fd);
- write_flush();
- if(write__fd>1) { // not standard output
- close(write__fd);
- write__fd= 1;
- }
- } // end write__close()
-
-static void write__end() {
- // terminate the services of this module;
- if(write__fd>1)
- write__close();
- if(write__fd_standard>1) {
- write__fd= write__fd_standard;
- write__close();
- write__fd_standard= 0;
- }
- if(loglevel<2)
- if(write__filename_temp!=NULL) unlink(write__filename_temp);
- } // end write__end()
-
-//------------------------------------------------------------
-
-static bool write_testmode= false; // no standard output
-static bool write_error= false; // an error has occurred
-
-static inline void write_flush() {
- if(write__bufp>write__buf && !write_testmode)
- // at least one byte in buffer AND not test mode
- write_error|=
- write(write__fd,write__buf,write__bufp-write__buf)<0;
- write__bufp= write__buf;
- } // end write_flush();
-
-static int write_open(const char* filename) {
- // open standard output file;
- // filename: name of the output file;
- // this string must be accessible until program end;
- // ==NULL: standard output;
- // this procedure must be called before any output is done;
- // return: 0: OK; !=0: error;
- static bool firstrun= true;
-
- if(loglevel>=2)
- fprintf(stderr,"Write-opening: %s\n",
- filename==NULL? "stdout": filename);
- if(filename!=NULL) { // not standard output
- write__fd= open(filename,
- O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,00600);
- if(write__fd<1) {
- fprintf(stderr,
- "osmconvert Error: could not open output file: %.80s\n",
- filename);
- write__fd= 1;
-return 1;
- }
- write__fd_standard= write__fd;
- write__filename_standard= filename;
- }
- if(firstrun) {
- firstrun= false;
- atexit(write__end);
- }
- return 0;
- } // end write_open()
-
-static int write_newfile(const char* filename) {
- // change to another (temporary) output file;
- // filename: new name of the output file;
- // this string must be accessible until program end
- // because the name will be needed to delete the file;
- // ==NULL: change back to standard output file;
- // the previous output file is closed by this procedure, unless
- // it is standard output;
- // return: 0: OK; !=0: error;
- if(loglevel>=2)
- fprintf(stderr,"Write-opening: %s\n",
- filename==NULL? "stdout": filename);
- if(filename==NULL) { // we are to change back to standard output file
- if(loglevel>=2)
- fprintf(stderr,"Write-reopening: %s\n",
- write__filename_standard==NULL? "stdout":
- write__filename_standard);
- write__close(); // close temporary file
- write__filename= write__filename_standard;
- write__fd= write__fd_standard;
- }
- else { // new temporary file shall be opened
- if(loglevel>=2)
- fprintf(stderr,"Write-opening: %s\n",filename);
- write__filename= filename;
- unlink(filename);
- write__fd= open(filename,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,00600);
- if(write__fd<1) {
- fprintf(stderr,
- "osmconvert Error: could not open output file: %.80s\n",
- filename);
- write__fd= 1;
-return 2;
- }
- write__filename_temp= filename;
- }
- return 0;
- } // end write_newfile()
-
-static inline void write_char(int c) {
- // write one byte to stdout, use a buffer;
- if(write__bufp>=write__bufe) { // the write buffer is full
- if(!write_testmode)
- write_error|=
- write(write__fd,write__buf,write__bufp-write__buf)<0;
- write__bufp= write__buf;
- }
- *write__bufp++= (char)c;
- } // end write_char();
-
-static inline void write_mem(const byte* b,int l) {
- // write a memory area to stdout, use a buffer;
- while(--l>=0) {
- if(write__bufp>=write__bufe) { // the write buffer is full
- if(!write_testmode)
- write_error|=
- write(write__fd,write__buf,write__bufp-write__buf)<0;
- write__bufp= write__buf;
- }
- *write__bufp++= (char)(*b++);
- }
- } // end write_mem();
-
-static inline void write_str(const char* s) {
- // write a string to stdout, use a buffer;
- while(*s!=0) {
- if(write__bufp>=write__bufe) { // the write buffer is full
- if(!write_testmode)
- write_error|=
- write(write__fd,write__buf,write__bufp-write__buf)<0;
- write__bufp= write__buf;
- }
- *write__bufp++= (char)(*s++);
- }
- } // end write_str();
-
-static inline void write_xmlstr(const char* s) {
- // write an XML string to stdout, use a buffer;
- // every character which is not allowed within an XML string
- // will be replaced by the appropriate decimal sequence;
- static byte allowedchar[]= {
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0, // \"&'
- 0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0, // <>
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1, // {}DEL
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- #if 1
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
- #else
- 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
- 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
- 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
- 4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0};
- #endif
- byte b0,b1,b2,b3;
- int i;
- uint32_t u;
- #define write__char_D(c) { \
- if(write__bufp>=write__bufe) { \
- if(!write_testmode) \
- write_error|= \
- write(write__fd,write__buf,write__bufp-write__buf)<0; \
- write__bufp= write__buf; \
- } \
- *write__bufp++= (char)(c); }
-
- for(;;) {
- b0= *s++;
- if(b0==0)
- break;
- i= allowedchar[b0];
- if(i==0) // this character may be written as is
- write__char_D(b0)
- else { // use numeric encoding
- if(--i<=0) // one byte
- u= b0;
- else {
- b1= *s++;
- if(--i<=0 && b1>=128) // two bytes
- u= ((b0&0x1f)<<6)+(b1&0x3f);
- else {
- b2= *s++;
- if(--i<=0 && b1>=128 && b2>=128) // three bytes
- u= ((b0&0x0f)<<12)+((b1&0x3f)<<6)+(b2&0x3f);
- else {
- b3= *s++;
- if(--i<=0 && b1>=128 && b2>=128 && b3>=128) // four bytes
- u= ((b0&0x07)<<18)+((b1&0x3f)<<12)+
- ((b1&0x3f)<<6)+(b2&0x3f);
- else
- u= (byte)'?';
- }
- }
- }
- write__char_D('&') write__char_D('#')
- if(u<100) {
- if(u>=10)
- write__char_D(u/10+'0')
- write__char_D(u%10+'0')
- }
- else if(u<1000) {
- write__char_D(u/100+'0')
- write__char_D((u/10)%10+'0')
- write__char_D(u%10+'0')
- }
- else {
- char st[30];
-
- uint32toa(u,st);
- write_str(st);
- }
- write__char_D(';')
- } // use numeric encoding
- }
- #undef write__char_D
- } // end write_xmlstr();
-
-static inline void write_xmlmnstr(const char* s) {
- // write an XML string to stdout, use a buffer;
- // every character which is not allowed within an XML string
- // will be replaced by the appropriate mnemonic or decimal sequence;
- static const byte allowedchar[]= {
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 0,0,9,0,0,0,9,9,0,0,0,0,0,0,0,0, // \"&'
- 0,0,0,0,0,0,0,0,0,0,0,0,9,0,9,0, // <>
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1, // {}DEL
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- #if 1
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
- #else
- 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
- 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
- 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
- 4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0};
- #endif
- byte b0,b1,b2,b3;
- int i;
- uint32_t u;
- #define write__char_D(c) { \
- if(write__bufp>=write__bufe) { \
- if(!write_testmode) \
- write_error|= \
- write(write__fd,write__buf,write__bufp-write__buf)<0; \
- write__bufp= write__buf; \
- } \
- *write__bufp++= (char)(c); }
- #define D(i) ((byte)(s[i]))
- #define DD ((byte)c)
-
- for(;;) {
- b0= *s++;
- if(b0==0)
- break;
- i= allowedchar[b0];
- if(i==0) // this character may be written as is
- write__char_D(b0)
- else if(i==9) { // there is a mnemonic for this character
- write__char_D('&')
- switch(b0) {
- case '\"':
- write__char_D('q') write__char_D('u') write__char_D('o')
- write__char_D('t')
- break;
- case '&':
- write__char_D('a') write__char_D('m') write__char_D('p')
- break;
- case '\'':
- write__char_D('a') write__char_D('p') write__char_D('o')
- write__char_D('s')
- break;
- case '<':
- write__char_D('l') write__char_D('t')
- break;
- case '>':
- write__char_D('g') write__char_D('t')
- break;
- default:
- write__char_D('?') // (should never reach here)
- }
- write__char_D(';')
- } // there is a mnemonic for this character
- else { // use numeric encoding
- if(--i<=0) // one byte
- u= b0;
- else {
- b1= *s++;
- if(--i<=0 && b1>=128) // two bytes
- u= ((b0&0x1f)<<6)+(b1&0x3f);
- else {
- b2= *s++;
- if(--i<=0 && b1>=128 && b2>=128) // three bytes
- u= ((b0&0x0f)<<12)+((b1&0x3f)<<6)+(b2&0x3f);
- else {
- b3= *s++;
- if(--i<=0 && b1>=128 && b2>=128 && b3>=128) // four bytes
- u= ((b0&0x07)<<18)+((b1&0x3f)<<12)+
- ((b1&0x3f)<<6)+(b2&0x3f);
- else
- u= (byte)'?';
- }
- }
- }
- write__char_D('&') write__char_D('#')
- if(u<100) {
- if(u>=10)
- write__char_D(u/10+'0')
- write__char_D(u%10+'0')
- }
- else if(u<1000) {
- write__char_D(u/100+'0')
- write__char_D((u/10)%10+'0')
- write__char_D(u%10+'0')
- }
- else {
- char st[30];
-
- uint32toa(u,st);
- write_str(st);
- }
- write__char_D(';')
- } // use numeric encoding
- }
- #undef DD
- #undef D
- #undef write__char_D
- } // end write_xmlmnstr();
-
-static inline void write_uint32(uint32_t v) {
- // write an unsigned 32 bit integer number to standard output;
- char s[20],*s1,*s2,c;
-
- s1= s;
- if(v==0)
- *s1++= '0';
- s2= s1;
- while(v>0)
- { *s2++= (v%10)+'0'; v/= 10; }
- *s2--= 0;
- while(s2>s1)
- { c= *s1; *s1= *s2; *s2= c; s1++; s2--; }
- write_str(s);
- } // end write_uint32()
-
-#if 0 // currently unused
-static inline void write_sint32(int32_t v) {
- // write a signed 32 bit integer number to standard output;
- char s[20],*s1,*s2,c;
-
- s1= s;
- if(v<0)
- { *s1++= '-'; v= -v; }
- else if(v==0)
- *s1++= '0';
- s2= s1;
- while(v>0)
- { *s2++= (v%10)+'0'; v/= 10; }
- *s2--= 0;
- while(s2>s1)
- { c= *s1; *s1= *s2; *s2= c; s1++; s2--; }
- write_str(s);
- } // end write_sint32()
-#endif
-
-static inline void write_uint64(uint64_t v) {
- // write an unsigned 64 bit integer number to standard output;
- char s[30],*s1,*s2,c;
-
- s1= s;
- if(v==0)
- *s1++= '0';
- s2= s1;
- while(v>0)
- { *s2++= (v%10)+'0'; v/= 10; }
- *s2--= 0;
- while(s2>s1)
- { c= *s1; *s1= *s2; *s2= c; s1++; s2--; }
- write_str(s);
- } // end write_uint64()
-
-static inline void write_createsint64(int64_t v,char* sp) {
- // create a signed 64 bit integer number;
- // return:
- // sp[30]: value v as decimal integer string;
- static char *s1,*s2,c;
-
- s1= sp;
- if(v<0)
- { *s1++= '-'; v= -v; }
- else if(v==0)
- *s1++= '0';
- s2= s1;
- while(v>0)
- { *s2++= (v%10)+'0'; v/= 10; }
- *s2--= 0;
- while(s2>s1)
- { c= *s1; *s1= *s2; *s2= c; s1++; s2--; }
- } // end write_sint64()
-
-static inline void write_sint64(int64_t v) {
- // write a signed 64 bit integer number to standard output;
- static char s[30],*s1,*s2,c;
-
- s1= s;
- if(v<0)
- { *s1++= '-'; v= -v; }
- else if(v==0)
- *s1++= '0';
- s2= s1;
- while(v>0)
- { *s2++= (v%10)+'0'; v/= 10; }
- *s2--= 0;
- while(s2>s1)
- { c= *s1; *s1= *s2; *s2= c; s1++; s2--; }
- write_str(s);
- } // end write_sint64()
-
-static inline char* write_createsfix7o(int32_t v,char* s) {
- // convert a signed 7 decimals fixpoint value into a string;
- // keep trailing zeros;
- // v: fixpoint value
- // return: pointer do string terminator;
- // s[12]: destination string;
- char* s1,*s2,*sterm,c;
- int i;
-
- s1= s;
- if(v<0)
- { *s1++= '-'; v= -v; }
- s2= s1;
- i= 7;
- while(--i>=0)
- { *s2++= (v%10)+'0'; v/= 10; }
- *s2++= '.';
- do
- { *s2++= (v%10)+'0'; v/= 10; }
- while(v>0);
- sterm= s2;
- *s2--= 0;
- while(s2>s1)
- { c= *s1; *s1= *s2; *s2= c; s1++; s2--; }
- return sterm;
- } // end write_createsfix7o()
-
-static inline void write_sfix7(int32_t v) {
- // write a signed 7 decimals fixpoint value to standard output;
- char s[20],*s1,*s2,c;
- int i;
-
- s1= s;
- if(v<0)
- { *s1++= '-'; v= -v; }
- s2= s1;
- i= 7;
- while((v%10)==0 && i>1) // trailing zeros
- { v/= 10; i--; }
- while(--i>=0)
- { *s2++= (v%10)+'0'; v/= 10; }
- *s2++= '.';
- do
- { *s2++= (v%10)+'0'; v/= 10; }
- while(v>0);
- *s2--= 0;
- while(s2>s1)
- { c= *s1; *s1= *s2; *s2= c; s1++; s2--; }
- write_str(s);
- } // end write_sfix7()
-
-static inline void write_sfix7o(int32_t v) {
- // write a signed 7 decimals fixpoint value to standard output;
- // keep trailing zeros;
- char s[20],*s1,*s2,c;
- int i;
-
- s1= s;
- if(v<0)
- { *s1++= '-'; v= -v; }
- s2= s1;
- i= 7;
- while(--i>=0)
- { *s2++= (v%10)+'0'; v/= 10; }
- *s2++= '.';
- do
- { *s2++= (v%10)+'0'; v/= 10; }
- while(v>0);
- *s2--= 0;
- while(s2>s1)
- { c= *s1; *s1= *s2; *s2= c; s1++; s2--; }
- write_str(s);
- } // end write_sfix7o()
-
-static inline void write_sfix6o(int32_t v) {
- // write a signed 6 decimals fixpoint value to standard output;
- // keep trailing zeros;
- char s[20],*s1,*s2,c;
- int i;
-
- s1= s;
- if(v<0)
- { *s1++= '-'; v= -v; }
- s2= s1;
- i= 6;
- while(--i>=0)
- { *s2++= (v%10)+'0'; v/= 10; }
- *s2++= '.';
- do
- { *s2++= (v%10)+'0'; v/= 10; }
- while(v>0);
- *s2--= 0;
- while(s2>s1)
- { c= *s1; *s1= *s2; *s2= c; s1++; s2--; }
- write_str(s);
- } // end write_sfix6o()
-
-#if 0 // currently unused
-static inline void write_sfix9(int64_t v) {
- // write a signed 9 decimals fixpoint value to standard output;
- char s[20],*s1,*s2,c;
- int i;
-
- s1= s;
- if(v<0)
- { *s1++= '-'; v= -v; }
- s2= s1;
- i= 9;
- while(--i>=0)
- { *s2++= (v%10)+'0'; v/= 10; }
- *s2++= '.';
- do
- { *s2++= (v%10)+'0'; v/= 10; }
- while(v>0);
- *s2--= 0;
- while(s2>s1)
- { c= *s1; *s1= *s2; *s2= c; s1++; s2--; }
- write_str(s);
- } // end write_sfix9()
-#endif
-
-static inline void write_createtimestamp(uint64_t v,char* sp) {
- // write a timestamp in OSM format, e.g.: "2010-09-30T19:23:30Z",
- // into a string;
- // v: value of the timestamp;
- // sp[21]: destination string;
- time_t vtime;
- struct tm tm;
- int i;
-
- vtime= v;
- #if __WIN32__
- memcpy(&tm,gmtime(&vtime),sizeof(tm));
- #else
- gmtime_r(&vtime,&tm);
- #endif
- i= tm.tm_year+1900;
- sp+= 3; *sp--= i%10+'0';
- i/=10; *sp--= i%10+'0';
- i/=10; *sp--= i%10+'0';
- i/=10; *sp= i%10+'0';
- sp+= 4; *sp++= '-';
- i= tm.tm_mon+1;
- *sp++= i/10+'0'; *sp++= i%10+'0'; *sp++= '-';
- i= tm.tm_mday;
- *sp++= i/10+'0'; *sp++= i%10+'0'; *sp++= 'T';
- i= tm.tm_hour;
- *sp++= i/10+'0'; *sp++= i%10+'0'; *sp++= ':';
- i= tm.tm_min;
- *sp++= i/10+'0'; *sp++= i%10+'0'; *sp++= ':';
- i= tm.tm_sec%60;
- *sp++= i/10+'0'; *sp++= i%10+'0'; *sp++= 'Z'; *sp= 0;
- } // end write_createtimestamp()
-
-static inline void write_timestamp(uint64_t v) {
- // write a timestamp in OSM format, e.g.: "2010-09-30T19:23:30Z"
- char s[30];
-
- write_createtimestamp(v,s);
- write_str(s);
- } // end write_timestamp()
-
-//------------------------------------------------------------
-// end Module write_ write module
-//------------------------------------------------------------
-
-
-
-//------------------------------------------------------------
-// Module csv_ csv write module
-//------------------------------------------------------------
-
-// this module provides procedures for generating csv output;
-// as usual, all identifiers of a module have the same prefix,
-// in this case 'csv'; an underline will follow in case of a
-// global accessible object, two underlines in case of objects
-// which are not meant to be accessed from outside this module;
-// the sections of private and public definitions are separated
-// by a horizontal line: ----
-
-#define csv__keyM 200 // max number of keys and vals
-#define csv__keyMM 256 // max number of characters +1 in key or val
-static char* csv__key= NULL; // [csv__keyM][csv__keyMM]
-static int csv__keyn= 0; // number of keys
-static char* csv__val= NULL; // [csv__keyM][csv__keyMM]
-static int csv__valn= 0; // number of vals
-// some booleans which tell us if certain keys are in column list;
-// this is for program acceleration
-static bool csv_key_otype= false, csv_key_oname= false,
- csv_key_id= false, csv_key_lon= false, csv_key_lat= false,
- csv_key_version=false, csv_key_timestamp=false,
- csv_key_changeset=false, csv_key_uid= false, csv_key_user= false;
-static char csv__sep0= '\t'; // first character of global_csvseparator;
-static char csv__rep0= ' '; // replacement character for separator char
-
-static void csv__end() {
- // clean-up csv processing;
-
- if(csv__key!=NULL)
- { free(csv__key); csv__key= NULL; }
- if(csv__val!=NULL)
- { free(csv__val); csv__val= NULL; }
- } // end csv__end()
-
-//------------------------------------------------------------
-
-static int csv_ini(const char* columns) {
- // initialize this module;
- // must be called before any other procedure is called;
- // may be called more than once; only the first call will
- // initialize this module, every other call will solely
- // overwrite the columns information if !=NULL;
- // columns[]: space-separated list of keys who are to be
- // used as column identifiers;
- // ==NULL: if list has already been given, do not
- // change it; if not, set list to default;
- // return: 0: everything went ok;
- // !=0: an error occurred;
- static bool firstrun= true;
-
- if(firstrun) {
- firstrun= false;
-
- csv__key= (char*)malloc(csv__keyM*csv__keyMM);
- csv__val= (char*)malloc(csv__keyM*csv__keyMM);
- if(csv__key==NULL || csv__val==NULL)
-return 1;
- atexit(csv__end);
- }
- if(columns==NULL) { // default columns shall be set
- if(csv__keyn==0) { // until now no column has been set
- // set default columns
- strcpy(&csv__key[0*csv__keyMM],"@oname");
- csv_key_oname= true;
- strcpy(&csv__key[1*csv__keyMM],"@id");
- csv_key_id= true;
- strcpy(&csv__key[2*csv__keyMM],"name");
- csv__keyn= 3;
- } // until now no column has been set
- } // default columns shall be set
- else { // new columns shall be set
- for(;;) { // for each column name
- int len;
- char* tp;
-
- len= strcspn(columns," ");
- if(len==0)
- break;
- if(csv__keyn>=csv__keyM) {
- WARN("too many csv columns")
- break;
- }
- len++;
- if(len>csv__keyMM) len= csv__keyMM; // limit key length
- tp= &csv__key[csv__keyn*csv__keyMM];
- strmcpy(tp,columns,len);
- csv__keyn++;
- if(strcmp(tp,"@otype")==0) csv_key_otype= true;
- else if(strcmp(tp,"@oname")==0) csv_key_oname= true;
- else if(strcmp(tp,"@id")==0) csv_key_id= true;
- else if(strcmp(tp,"@lon")==0) csv_key_lon= true;
- else if(strcmp(tp,"@lat")==0) csv_key_lat= true;
- else if(strcmp(tp,"@version")==0) csv_key_version= true;
- else if(strcmp(tp,"@timestamp")==0) csv_key_timestamp= true;
- else if(strcmp(tp,"@changeset")==0) csv_key_changeset= true;
- else if(strcmp(tp,"@uid")==0) csv_key_uid= true;
- else if(strcmp(tp,"@user")==0) csv_key_user= true;
- columns+= len-1;
- if(columns[0]==' ') columns++;
- } // for each column name
- } // new columns shall be set
- // care about separator chars
- if(global_csvseparator[0]==0 || global_csvseparator[1]!=0) {
- csv__sep0= 0;
- csv__rep0= 0;
- }
- else {
- csv__sep0= global_csvseparator[0];
- if(csv__sep0==' ')
- csv__rep0= '_';
- else
- csv__rep0= ' ';
- }
- return 0;
- } // end csv_ini()
-
-static void csv_add(const char* key,const char* val) {
- // test if the key's value shall be printed and do so if yes;
- int keyn;
- const char* kp;
-
- keyn= csv__keyn;
- kp= csv__key;
- while(keyn>0) { // for all keys in column list
- if(strcmp(key,kp)==0) { // key is in column list
- strmcpy(csv__val+(kp-csv__key),val,csv__keyMM);
- // store value
- csv__valn++;
- break;
- } // key is in column list
- kp+= csv__keyMM; // take next key in list
- keyn--;
- } // for all keys in column list
- } // end csv_add()
-
-static void csv_write() {
- // write a csv line - if csv data had been stored
- char* vp,*tp;
- int keyn;
-
- if(csv__valn==0)
-return;
- vp= csv__val;
- keyn= csv__keyn;
- while(keyn>0) { // for all keys in column list
- if(*vp!=0) { // there is a value for this key
- tp= vp;
- do {
- if(*tp==csv__sep0 || *tp==NL[0] || *tp==NL[1])
- // character identical with separator or line feed
- write_char(csv__rep0); // replace it by replacement char
- else
- write_char(*tp);
- tp++;
- } while(*tp!=0);
- *vp= 0; // delete list entry
- }
- vp+= csv__keyMM; // take next val in list
- keyn--;
- if(keyn>0) // at least one column will follow
- write_str(global_csvseparator);
- } // for all keys in column list
- write_str(NL);
- csv__valn= 0;
- } // end csv_write()
-
-static void csv_headline() {
- // write a headline to csv output file
- char* kp;
- int keyn;
-
- if(!global_csvheadline) // headline shall not be written
-return;
- kp= csv__key;
- keyn= csv__keyn;
- while(keyn>0) { // for all keys in column list
- csv_add(kp,kp);
- kp+= csv__keyMM; // take next key in list
- keyn--;
- } // for all keys in column list
- csv_write();
- } // end csv_headline()
-
-//------------------------------------------------------------
-// end Module csv_ csv write module
-//------------------------------------------------------------
-
-
-
-//------------------------------------------------------------
-// Module pb_ pbf read module
-//------------------------------------------------------------
-
-// this module provides procedures which read osm .pbf objects;
-// it uses procedures from modules read_ and pbf_;
-// as usual, all identifiers of a module have the same prefix,
-// in this case 'pb'; an underline will follow in case of a
-// global accessible object, two underlines in case of objects
-// which are not meant to be accessed from outside this module;
-// the sections of private and public definitions are separated
-// by a horizontal line: ----
-
-static int pb__decompress(byte* ibuf,uint isiz,byte* obuf,uint osizm,
- uint* osizp) {
- // decompress a block of data;
- // return: 0: decompression was successful;
- // !=0: error number from zlib;
- // *osizp: size of uncompressed data;
- z_stream strm;
- int r,i;
-
- // initialization
- strm.zalloc= Z_NULL;
- strm.zfree= Z_NULL;
- strm.opaque= Z_NULL;
- strm.next_in= Z_NULL;
- strm.total_in= 0;
- strm.avail_out= 0;
- strm.next_out= Z_NULL;
- strm.total_out= 0;
- strm.msg= NULL;
- r= inflateInit(&strm);
- if(r!=Z_OK)
-return r;
- // read data
- strm.next_in = ibuf;
- strm.avail_in= isiz;
- // decompress
- strm.next_out= obuf;
- strm.avail_out= osizm;
- r= inflate(&strm,Z_FINISH);
- if(r!=Z_OK && r!=Z_STREAM_END) {
- inflateEnd(&strm);
- *osizp= 0;
-return r;
- }
- // clean-up
- inflateEnd(&strm);
- obuf+= *osizp= osizm-(i= strm.avail_out);
- // add some zero bytes
- if(i>4) i= 4;
- while(--i>=0) *obuf++= 0;
- return 0;
- } // end pb__decompress()
-
-static inline int64_t pb__strtimetosint64(const char* s) {
- // read a timestamp in OSM format, e.g.: "2010-09-30T19:23:30Z",
- // and convert it to a signed 64-bit integer;
- // return: time as a number (seconds since 1970);
- // ==0: syntax error;
- if((s[0]!='1' && s[0]!='2') ||
- !isdig(s[1]) || !isdig(s[2]) || !isdig(s[3]) ||
- s[4]!='-' || !isdig(s[5]) || !isdig(s[6]) ||
- s[7]!='-' || !isdig(s[8]) || !isdig(s[9]) ||
- s[10]!='T' || !isdig(s[11]) || !isdig(s[12]) ||
- s[13]!=':' || !isdig(s[14]) || !isdig(s[15]) ||
- s[16]!=':' || !isdig(s[17]) || !isdig(s[18]) ||
- s[19]!='Z') // wrong syntax
-return 0;
- /* regular timestamp */ {
- struct tm tm;
-
- tm.tm_isdst= 0;
- tm.tm_year=
- (s[0]-'0')*1000+(s[1]-'0')*100+(s[2]-'0')*10+(s[3]-'0')-1900;
- tm.tm_mon= (s[5]-'0')*10+s[6]-'0'-1;
- tm.tm_mday= (s[8]-'0')*10+s[9]-'0';
- tm.tm_hour= (s[11]-'0')*10+s[12]-'0';
- tm.tm_min= (s[14]-'0')*10+s[15]-'0';
- tm.tm_sec= (s[17]-'0')*10+s[18]-'0';
- #if __WIN32__
- // use replcement for timegm() because Windows does not know it
-return mktime(&tm)-timezone;
- #else
-return timegm(&tm);
- #endif
- } // regular timestamp
- } // end pb__strtimetosint64()
-
-// for string primitive group table
-#define pb__strM (4*1024*1024)
- // maximum number of strings within each block
-static char* pb__str[pb__strM]; // string table
-static char** pb__stre= pb__str; // end of data in str[]
-static char** pb__stree= pb__str+pb__strM; // end of str[]
-static int pb__strm= 0;
-// for tags of densnodes (start and end address)
-static byte* pb__nodetags= NULL,*pb__nodetagse= NULL; // node tag pairs
-// for noderefs and tags of ways (start and end address each)
-static byte* pb__waynode= NULL,*pb__waynodee= NULL;
-static byte* pb__waykey= NULL,*pb__waykeye= NULL;
-static byte* pb__wayval= NULL,*pb__wayvale= NULL;
-// for refs and tags of relations (start and end address each)
-static byte* pb__relrefrole= NULL,*pb__relrefrolee= NULL;
-static byte* pb__relrefid= NULL,*pb__relrefide= NULL;
-static byte* pb__relreftype= NULL,*pb__relreftypee= NULL;
-static byte* pb__relkey= NULL,*pb__relkeye= NULL;
-static byte* pb__relval= NULL,*pb__relvale= NULL;
-
-//------------------------------------------------------------
-
-static bool pb_bbvalid= false;
- // the following bbox coordinates are valid;
-static int32_t pb_bbx1,pb_bby1,pb_bbx2,pb_bby2;
- // bbox coordinates (base 10^-7);
-static uint64_t pb_filetimestamp= 0;
-static int pb_type= -9; // type of the object which has been read;
- // 0: node; 1: way; 2: relation; 8: header;
- // -1: end of file; <= -10: error;
-static int64_t pb_id= 0; // id of read object
-static int32_t pb_lon= 0,pb_lat= 0; // coordinates of read node
-static int32_t pb_hisver= 0;
-static int64_t pb_histime= 0;
-static int64_t pb_hiscset= 0;
-static uint32_t pb_hisuid= 0;
-static char* pb_hisuser= "";
-static int32_t pb_hisvis= -1; // (default for 'unknown')
-
-static void pb_ini() {
- // initialize this module;
- // must be called as first procedure of this module;
- } // end pb_ini()
-
-static int pb_input(bool reset) {
- // read next pbf object and make it available via other
- // procedures of this mudule;
- // pb_ini() must have been called before calling this procedure;
- // reset: just reset al buffers, do nothing else;
- // this is if the file has been rewound;
- // return: >=0: OK; -1: end of file; <=-10: error;
- // pb_type: type of the object which has been read;
- // in dependence of object's type the following information
- // will be available:
- // pb_bbvalid: the following bbox coordinates are valid;
- // pb_bbx1,pb_bby1,pb_bbx2,pb_bby2: bbox coordinates (base 10^-7);
- // pb_filetimestamp: timestamp of the file; 0: no file timestamp;
- // pb_id: id of this object;
- // pb_lon: latitude in 100 nanodegree;
- // pb_lat: latitude in 100 nanodegree;
- // pb_hisver: version;
- // pb_histime: time (seconds since 1970)
- // pb_hiscset: changeset
- // pb_hisuid: uid; ==0: no user information available;
- // pb_hisuser: user name
- // subsequent to calling this procedure, the caller may call
- // the following procedures - depending on pb_type():
- // pb_noderef(), pb_ref(), pb_keyval()
- // the caller may omit these subsequent calls for ways and relations,
- // but he must not temporarily omit them for nodes;
- // if he omits such a subsequent call for one node, he must not
- // call pb_keyval() for any other of the following nodes because
- // this would result in wrong key/val data;
- #define END(r) {pb_type= (r); goto end;}
- // jump to procedure's end and provide a return code
- #define ENDE(r,f) { PERR(f) END(r) }
- // print error message, then jump to end
- #define ENDEv(r,f,...) { PERRv(f,__VA_ARGS__) END(r) }
- // print error message with value(s), then jump to end
- int blocktype= -1;
- // -1: expected; 0: unknown; 1: Header; 2: Data;
- #define pb__blockM (32*1024*1024) // maximum block size
- static byte zbuf[pb__blockM+1000];
- static byte* zbufp= zbuf,*zbufe= zbuf;
- static byte* groupp= zbuf,*groupe= zbuf;
- // memory area for primitive groups
- // start and end of different arrays, all used for dense nodes:
- static byte* nodeid= NULL,*nodeide= NULL; // node ids
- static byte* nodever= NULL,*nodevere= NULL; // versions
- static byte* nodetime= NULL,*nodetimee= NULL; // times
- static byte* nodecset= NULL,*nodecsete= NULL; // change sets
- static byte* nodeuid= NULL,*nodeuide= NULL; // user ids
- static byte* nodeuser= NULL,*nodeusere= NULL; // user names
- static byte* nodevis= NULL,*nodevise= NULL; // visible
- static byte* nodelat= NULL,*nodelate= NULL; // node latitudes
- static byte* nodelon= NULL,*nodelone= NULL; // node longitudes
- static uint32_t hisuser= 0; // string index of user name (delta coded)
- static bool waycomplete= false,relcomplete= false;
-
- if(reset) {
- zbufp= zbuf,zbufe= zbuf;
- groupp= zbuf,groupe= zbuf;
- nodeid= NULL,nodeide= NULL;
- nodever= NULL,nodevere= NULL;
- nodetime= NULL,nodetimee= NULL;
- nodecset= NULL,nodecsete= NULL;
- nodeuid= NULL,nodeuide= NULL;
- nodeuser= NULL,nodeusere= NULL;
- nodevis= NULL,nodevise= NULL;
- nodelat= NULL,nodelate= NULL;
- nodelon= NULL,nodelone= NULL;
- hisuser= 0;
- waycomplete= false,relcomplete= false;
- pb_type= 99;
-return 0;
- }
- for(;;) { // until we have a new object
- mainloop:
- if(nodeid<nodeide && nodelat<nodelate &&
- nodelon<nodelone) { // dense nodes left
- // provide a node
- pb_id+= pbf_sint64(&nodeid);
- if(global_pbfgranularity100!=0) {
- pb_lat+= pbf_sint32(&nodelat)*global_pbfgranularity100;
- pb_lon+= pbf_sint32(&nodelon)*global_pbfgranularity100;
- }
- else {
- pb_lat+= pbf_sint32(&nodelat);
- pb_lon+= pbf_sint32(&nodelon);
- }
- if(nodever>=nodevere || nodetime>=nodetimee ||
- nodecset>=nodecsete || nodeuid>=nodeuide ||
- nodeuser>=nodeusere) // no author information available
- pb_hisver= 0;
- else { // author information available
- pb_hisver= pbf_uint32(&nodever);
- pb_histime+= pbf_sint64(&nodetime);
- pb_hiscset+= pbf_sint64(&nodecset);
- pb_hisuid+= pbf_sint32(&nodeuid);
- hisuser+= pbf_sint32(&nodeuser);
- if(hisuser<pb__strm) // string index ok
- pb_hisuser= pb__str[hisuser];
- else { // string index overflow
- WARNv("node %"PRIi64" user string index overflow: %u>=%i",
- pb_id,hisuser,pb__strm)
- hisuser= 0; pb_hisuser= "";
- }
- pb_hisvis= -1;
- if(nodevis!=NULL && nodevis<nodevise) {
- pb_hisvis= pbf_uint32(&nodevis);
- }
- } // end author information available
- END(0)
- } // dense nodes left
- if(waycomplete) { // ways left
- // provide a way
- waycomplete= false;
- // (already got id and author integers)
- if(pb_hisver!=0 && hisuser>0) {
- // author information available
- if(hisuser<pb__strm) // string index ok
- pb_hisuser= pb__str[hisuser];
- else { // string index overflow
- WARNv("way %"PRIi64" user string index overflow: %u>=%i",
- pb_id,hisuser,pb__strm)
- hisuser= 0; pb_hisuser= "";
- }
- } // end author information available
- END(1)
- } // ways left
- if(relcomplete) { // relations left
- // provide a relation
- relcomplete= false;
- // (already got id and author integers)
- if(pb_hisver!=0 && hisuser>0) {
- // author information available
- if(hisuser<pb__strm) // string index ok
- pb_hisuser= pb__str[hisuser];
- else { // string index overflow
- WARNv("rel %"PRIi64" user string index overflow: %u>=%i",
- pb_id,hisuser,pb__strm)
- hisuser= 0; pb_hisuser= "";
- }
- } // end author information available
- END(2)
- } // relations left
- if(groupp<groupe) { // data in primitive group left
-//// provide a primitive group object
- byte* bp;
- int l;
-
- bp= groupp;
- while(bp<groupe) { // for each element in primitive group
- switch(bp[0]) { // first byte of primitive group element
- case 0x0a: // S 1, normal nodes
- ENDE(-201,"can only process dense nodes.")
- //// dense nodes
- case 0x12: // S 2, dense nodes
- bp++;
- l= pbf_uint32(&bp);
- if(bp+l>groupe)
- ENDEv(-202,"dense nodes too large: %u",l)
- groupp= bp+l;
- /* get all node data lists */ {
- // decode dense node part of primitive group of Data block
- byte* dne; // end of dense node memory area
- uint l;
- byte* bhise; // end of author section in buf[]
-
- dne= groupp;
- while(bp<dne) { // for every element in this loop
- switch(bp[0]) { // first byte of element
- case 0x0a: // S 1, ids
- bp++;
- l= pbf_uint32(&bp);
- if(bp+l>dne)
- ENDEv(-301,"node id table too large: %u",l)
- nodeid= bp;
- nodeide= (bp+= l);
- break;
- case 0x2a: // S 5, author - with subelements
- bp++;
- l= pbf_uint32(&bp);
- if(bp+l>dne)
- ENDEv(-302,"node author section too large: %u",l)
- if(global_dropversion) {
- // version number is not required
- bp+= l; // jump over this section and ignore it
- break;
- }
- bhise= bp+l;
- nodevis= NULL;
- while(bp<bhise) { // for each author subelement
- switch(bp[0]) {
- // first byte of element in author section
- case 0x0a: // S 1, versions
- bp++;
- l= pbf_uint32(&bp);
- if(bp+l>bhise)
- ENDEv(-303,"node version table too large: %u",l)
- nodever= bp;
- nodevere= (bp+= l);
- break;
- case 0x12: // S 2, times
- bp++;
- l= pbf_uint32(&bp);
- if(bp+l>bhise)
- ENDEv(-304,"node time table too large: %u",l)
- nodetime= bp;
- nodetimee= (bp+= l);
- break;
- case 0x1a: // S 3, change sets
- bp++;
- l= pbf_uint32(&bp);
- if(bp+l>bhise)
- ENDEv(-305,
- "node change set table too large: %u",l)
- nodecset= bp;
- nodecsete= (bp+= l);
- break;
- case 0x22: // S 4, user ids
- bp++;
- l= pbf_uint32(&bp);
- if(bp+l>bhise)
- ENDEv(-306,"node user id table too large: %u",l)
- nodeuid= bp;
- nodeuide= (bp+= l);
- break;
- case 0x2a: // S 5, user names
- bp++;
- l= pbf_uint32(&bp);
- if(bp+l>bhise)
- ENDEv(-307,"node user name table too large: %u",l);
- nodeuser= bp;
- nodeusere= (bp+= l);
- break;
- case 0x32: // S 6, visible
- bp++;
- l= pbf_uint32(&bp);
- if(bp+l>bhise)
- ENDEv(-308,"node version table too large: %u",l)
- nodevis= bp;
- nodevise= (bp+= l);
- break;
- default:
- WARNv("node author element type unknown: "
- "0x%02X 0x%02X.",bp[0],bp[1])
- if(pbf_jump(&bp))
- END(-308)
- } // end first byte of element
- } // end for each author subelement
- if(bp>bhise)
- ENDE(-309,"node author format length.")
- bp= bhise;
- break; // end author - with subelements
- case 0x42: // S 8, latitudes
- bp++;
- l= pbf_uint32(&bp);
- if(bp+l>dne)
- ENDEv(-310,"node latitude table too large: %u",l)
- nodelat= bp;
- nodelate= (bp+= l);
- break;
- case 0x4a: // S 9, longitudes
- bp++;
- l= pbf_uint32(&bp);
- if(bp+l>dne)
- ENDEv(-311,"node longitude table too large: %u",l)
- nodelon= bp;
- nodelone= (bp+= l);
- break;
- case 0x52: // S 10, tag pairs
- bp++;
- l= pbf_uint32(&bp);
- if(bp+l>dne)
- ENDEv(-312,"node tag pair table too large: %u",l)
- pb__nodetags= bp;
- pb__nodetagse= (bp+= l);
- break;
- default:
- WARNv("dense node element type unknown: "
- "0x%02X 0x%02X.",bp[0],bp[1])
- if(pbf_jump(&bp))
- END(-313)
- } // end first byte of element
- if(bp>dne)
- ENDE(-314,"dense node format length.")
- } // end for every element in this loop
- // reset (delta-coded) variables
- pb_id= 0;
- pb_lat= pb_lon= 0;
- pb_histime= 0;
- pb_hiscset= 0;
- pb_hisuid= 0;
- hisuser= 0;
- pb_hisuser= "";
- bp= groupp;
- if(nodeid<nodeide && nodelat<nodelate && nodelon<nodelone)
- // minimum contents available
- goto mainloop;
- } // get all node data lists
- break;
- //// ways
- case 0x1a: // S 3, ways
- bp++;
- l= pbf_uint32(&bp);
- if(bp+l>groupe)
- ENDEv(-204,"ways too large: %u",l)
- groupp= bp+l;
- /* get way data */ {
- byte* bpe; // end of ways memory area
- uint l;
- byte* bhise; // end of author section in zbuf[]
- int complete;
- // flags which determine if the dataset is complete
- int hiscomplete;
- // flags which determine if the author is complete
-
- bpe= groupp;
- complete= hiscomplete= 0;
- while(bp<bpe) { // for every element in this primitive group
- switch(bp[0]) { // first byte of element
- case 0x08: // V 1, id
- bp++;
- pb_id= pbf_uint64(&bp);
- complete|= 1;
- break;
- case 0x12: // S 2, keys
- bp++;
- l= pbf_uint32(&bp);
- if(bp+l>bpe)
- ENDEv(-401,"way key table too large: %u",l)
- pb__waykey= bp;
- pb__waykeye= (bp+= l);
- complete|= 2;
- break;
- case 0x1a: // S 3, vals
- bp++;
- l= pbf_uint32(&bp);
- /* deal with strange S 3 element at data set end */ {
- if(complete & (4|16)) {
- // already have vals or node refs
- WARNv("format 0x1a found: %02X",complete)
- break; // ignore this element
- }
- }
- if(bp+l>bpe)
- ENDEv(-403,"way val table too large: %u",l)
- pb__wayval= bp;
- pb__wayvale= (bp+= l);
- complete|= 4;
- break;
- case 0x22: // S 4, author - with subelements
- bp++;
- l= pbf_uint32(&bp);
- if(bp+l>bpe)
- ENDEv(-404,"way author section too large: %u",l)
- if(global_dropversion) {
- // version number is not required
- bp+= l; // jump over this section and ignore it
- break;
- }
- bhise= bp+l;
- pb_hisvis= -1;
- while(bp<bhise) { // for each author subelement
- switch(bp[0]) {
- // first byte of element in author section
- case 0x08: // V 1, version
- bp++;
- pb_hisver= pbf_uint32(&bp);
- hiscomplete|= 1;
- break;
- case 0x10: // V 2, timestamp
- bp++;
- pb_histime= pbf_uint64(&bp);
- hiscomplete|= 2;
- break;
- case 0x18: // V 3, cset
- bp++;
- pb_hiscset= pbf_uint64(&bp);
- hiscomplete|= 4;
- break;
- case 0x20: // V 4, uid
- bp++;
- pb_hisuid= pbf_uint32(&bp);
- hiscomplete|= 8;
- break;
- case 0x28: // V 5, user
- bp++;
- hisuser= pbf_uint32(&bp);
- hiscomplete|= 16;
- break;
- case 0x30: // V 6, visible
- bp++;
- pb_hisvis= pbf_uint32(&bp);
- break;
- default:
- WARNv("way author element type unknown: "
- "0x%02X 0x%02X.",bp[0],bp[1])
- if(pbf_jump(&bp))
- END(-408)
- } // end first byte of element
- } // end for each author subelement
- if(bp>bhise)
- ENDE(-411,"way author format length.")
- bp= bhise;
- complete|= 8;
- break; // end author - with subelements
- case 0x42: // S 8, node refs
- bp++;
- l= pbf_uint32(&bp);
- if(bp+l>bpe)
- ENDEv(-412,"way noderef table too large: %u",l)
- pb__waynode= bp;
- pb__waynodee= (bp+= l);
- complete|= 16;
- break;
- default:
- WARNv("way element type unknown: "
- "0x%02X 0x%02X 0x%02X 0x%02X + %i.",
- bp[0],bp[1],bp[2],bp[3],complete)
- if(pbf_jump(&bp))
- END(-421)
- } // end first byte of element
- if(bp>bpe)
- ENDE(-429,"way format length.")
- } // for every element in this primitive group
- bp= groupp;
- if((hiscomplete&7)!=7) // author information not available
- pb_hisver= 0;
- else if((hiscomplete&24)!=24) // no user information
- pb_hisuid= 0;
- #if 1 // 2014-06-16
- if((complete & 1)==1) { // minimum contents available
- // (at least id)
- #else
- if((complete & 17)==17) { // minimum contents available
- // (at least id and node refs)
- #endif
- waycomplete= true;
- goto mainloop;
- }
- } // get way data
- break;
- //// relations
- case 0x22: // S 4, rels
- bp++;
- l= pbf_uint32(&bp);
- if(bp+l>groupe)
- ENDEv(-206,"rels too large: %u",l)
- groupp= bp+l;
- /* get relation data */ {
- byte* bpe; // end of ways memory area
- uint l;
- byte* bhise; // end of author section in zbuf[]
- int complete;
- // flags which determine if the dataset is complete
- int hiscomplete; // flags which determine
- // if the author information is complete
-
- bpe= groupp;
- complete= hiscomplete= 0;
- while(bp<bpe) { // for every element in this primitive group
- switch(bp[0]) { // first byte of element
- case 0x08: // V 1, id
- bp++;
- pb_id= pbf_uint64(&bp);
- complete|= 1;
- break;
- case 0x12: // S 2, keys
- bp++;
- l= pbf_uint32(&bp);
- if(bp+l>bpe)
- ENDEv(-501,"rel key table too large: %u",l)
- pb__relkey= bp;
- pb__relkeye= (bp+= l);
- complete|= 2;
- break;
- case 0x1a: // S 3, vals
- bp++;
- l= pbf_uint32(&bp);
- if(bp+l>bpe)
- ENDEv(-502,"rel val table too large: %u",l)
- pb__relval= bp;
- pb__relvale= (bp+= l);
- complete|= 4;
- break;
- case 0x22: // S 4, author - with subelements
- bp++;
- l= pbf_uint32(&bp);
- if(bp+l>bpe)
- ENDEv(-503,"rel author section too large: %u",l)
- if(global_dropversion) {
- // version number is not required
- bp+= l; // jump over this section and ignore it
- break;
- }
- bhise= bp+l;
- pb_hisvis= -1;
- while(bp<bhise) { // for each author subelement
- switch(bp[0]) {
- // first byte of element in author section
- case 0x08: // V 1, version
- bp++;
- pb_hisver= pbf_uint32(&bp);
- hiscomplete|= 1;
- break;
- case 0x10: // V 2, timestamp
- bp++;
- pb_histime= pbf_uint64(&bp);
- hiscomplete|= 2;
- break;
- case 0x18: // V 3, cset
- bp++;
- pb_hiscset= pbf_uint64(&bp);
- hiscomplete|= 4;
- break;
- case 0x20: // V 4, uid
- bp++;
- pb_hisuid= pbf_uint32(&bp);
- hiscomplete|= 8;
- break;
- case 0x28: // V 5, user
- bp++;
- hisuser= pbf_uint32(&bp);
- hiscomplete|= 16;
- break;
- case 0x30: // V 6, visible
- bp++;
- pb_hisvis= pbf_uint32(&bp);
- break;
- default:
- WARNv("rel author element type unknown: "
- "0x%02X 0x%02X.",bp[0],bp[1])
- if(pbf_jump(&bp))
- END(-509)
- } // end first byte of element
- } // end for each author subelement
- if(bp>bhise)
- ENDE(-510,"rel author format length.")
- bp= bhise;
- complete|= 8;
- break; // end author - with subelements
- case 0x42: // S 8, refroles
- bp++;
- l= pbf_uint32(&bp);
- if(bp+l>bpe)
- ENDEv(-511,"rel role table too large: %u",l)
- pb__relrefrole= bp;
- pb__relrefrolee= (bp+= l);
- complete|= 16;
- break;
- case 0x4a: // S 9, refids
- bp++;
- l= pbf_uint32(&bp);
- if(bp+l>bpe)
- ENDEv(-512,"rel id table too large: %u",l)
- pb__relrefid= bp;
- pb__relrefide= (bp+= l);
- complete|= 32;
- break;
- case 0x52: // S 10, reftypes
- bp++;
- l= pbf_uint32(&bp);
- if(bp+l>bpe)
- ENDEv(-513,"rel type table too large: %u",l)
- pb__relreftype= bp;
- pb__relreftypee= (bp+= l);
- complete|= 64;
- break;
- default:
- WARNv("rel element type unknown: "
- "0x%02X 0x%02X 0x%02X 0x%02X + %i.",
- bp[0],bp[1],bp[2],bp[3],complete)
- if(pbf_jump(&bp))
- END(-514)
- } // end first byte of element
- if(bp>bpe)
- ENDE(-519,"rel format length.")
- } // for every element in this primitive group
- bp= groupp;
- if((hiscomplete&7)!=7) // author information not available
- pb_hisver= 0;
- else if((hiscomplete&24)!=24) // no user information
- pb_hisuid= 0;
- #if 1
- if((complete & 1)==1) { // minimum contents available (id)
- #else
- if((complete & 113)==113 ||
- (complete & 7)==7) { // minimum contents available
- // have at least id and refs (1|16|32|64) OR
- // have at least id and keyval (1|2|4)
- #endif
- relcomplete= true;
- goto mainloop;
- }
- } // get way data
- break;
- default:
- WARNv("primitive group element type unknown: "
- "0x%02X 0x%02X.",bp[0],bp[1])
- if(pbf_jump(&bp))
- END(-209)
- } // end first byte of primitive group element
- } // end for each element in primitive group
- } // data in primitive group left
- if(zbufp<zbufe) { // zbuf data left
-//// provide next primitive group
- if(blocktype==1) { // header block
- bool osmschema,densenodes;
- byte* bp;
- uint l;
- byte* bboxe;
- int64_t coord;
- // temporary, for rounding purposes sfix9 -> sfix7
- int bboxflags;
-
- osmschema= false;
- densenodes= false;
- bboxflags= 0;
- bp= zbufp;
- while(bp<zbufe) { // for every element in this loop
- switch(bp[0]) { // first byte of element
- case 0x0a: // S 1, bbox
- bp++;
- l= pbf_uint32(&bp);
- if(l>=100) // bbox group too large
- ENDEv(-41,"bbox group too large: %u",l)
- bboxe= bp+l;
- while(bp<bboxe) { // for every element in bbox
- switch(bp[0]) { // first byte of element in bbox
- case 0x08: // V 1, minlon
- bp++;
- coord= pbf_sint64(&bp);
- if(coord<0) coord-= 99;
- pb_bbx1= coord/100;
- bboxflags|= 0x01;
- break;
- case 0x10: // V 2, maxlon
- bp++;
- coord= pbf_sint64(&bp);
- if(coord>0) coord+= 99;
- pb_bbx2= coord/100;
- bboxflags|= 0x02;
- break;
- case 0x18: // V 3, maxlat
- bp++;
- coord= pbf_sint64(&bp);
- if(coord>0) coord+= 99;
- pb_bby2= coord/100;
- bboxflags|= 0x04;
- break;
- case 0x20: // V 4, minlat
- bp++;
- coord= pbf_sint64(&bp);
- if(coord<0) coord-= 99;
- pb_bby1= coord/100;
- bboxflags|= 0x08;
- break;
- default:
- WARNv("bbox element type unknown: "
- "0x%02X 0x%02X.",bp[0],bp[1])
- if(pbf_jump(&bp))
- END(-42)
- } // end first byte of element
- if(bp>bboxe)
- ENDE(-43,"bbox format length.")
- } // end for every element in bbox
- bp= bboxe;
- break;
- case 0x22: // S 4, required features
- bp++;
- l= pbf_uint32(&bp);
- if(memcmp(bp-1,"\x0e""OsmSchema-V0.6",15)==0)
- osmschema= true;
- else if(memcmp(bp-1,"\x0a""DenseNodes",11)==0)
- densenodes= true;
- else if(memcmp(bp-1,"\x15""HistoricalInformation",21)==0)
- ;
- else // unsupported feature
- ENDEv(-44,"unsupported feature: %.*s",l>50? 50: l,bp)
- bp+= l;
- break;
- case 0x2a: // 0x01 S 5, optional features
- bp++;
- l= pbf_uint32(&bp);
- if(memcmp(bp-1,"\x1e""timestamp=",11)==0) {
- // file timestamp available
- pb_filetimestamp= pb__strtimetosint64((char*)bp+10);
- } // file timestamp available
- bp+= l;
- break;
- case 0x82: // 0x01 S 16, writing program
- if(bp[1]!=0x01) goto h_unknown;
- bp+= 2;
- l= pbf_uint32(&bp);
- bp+= l; // (ignore this element)
- break;
- case 0x8a: // 0x01 S 17, source
- if(bp[1]!=0x01) goto h_unknown;
- bp+= 2;
- l= pbf_uint32(&bp);
- bp+= l; // (ignore this element)
- break;
- case 0x80: // 0x02 V 32, osmosis_replication_timestamp
- if(bp[1]!=0x02) goto h_unknown;
- bp+= 2;
- pb_filetimestamp= pbf_uint64(&bp);
- break;
- case 0x88: // 0x02 V 33, osmosis_replication_sequence_number
- if(bp[1]!=0x02) goto h_unknown;
- bp+= 2;
- pbf_uint64(&bp); // (ignore this element)
- break;
- case 0x92: // 0x02 S 34, osmosis_replication_base_url
- if(bp[1]!=0x02) goto h_unknown;
- bp+= 2;
- l= pbf_uint32(&bp);
- bp+= l; // (ignore this element)
- break;
- default:
- h_unknown:
- WARNv("header block element type unknown: "
- "0x%02X 0x%02X.",bp[0],bp[1])
- if(pbf_jump(&bp))
- END(-45)
- } // end first byte of element
- if(bp>zbufe)
- ENDE(-46,"header block format length.")
- } // end for every element in this loop
- if(!osmschema)
- ENDE(-47,"expected feature: OsmSchema-V0.6")
- if(!densenodes)
- ENDE(-48,"expected feature: DenseNodes")
- zbufp= bp;
- pb_bbvalid= bboxflags==0x0f;
- END(8)
- } // header block
- // here: data block
- // provide primitive groups
- /* process data block */ {
- byte* bp;
- uint l;
- static byte* bstre; // end of string table in zbuf[]
-
- bp= zbufp;
- pb__stre= pb__str;
- while(bp<zbufe) { // for every element in this loop
- switch(bp[0]) { // first byte of element
- case 0x0a: // S 1, string table
- bp++;
- l= pbf_uint32(&bp);
- if(bp+l>zbufe)
- ENDEv(-101,"string table too large: %u",l)
- bstre= bp+l;
- while(bp<bstre) { // for each element in string table
- if(bp[0]==0x0a) { // S 1, string
- *bp++= 0; // set null terminator for previous string
- l= pbf_uint32(&bp);
- if(bp+l>bstre) // string too large
- ENDEv(-102,"string too large: %u",l)
- if(pb__stre>=pb__stree)
- ENDEv(-103,"too many strings: %i",pb__strM)
- *pb__stre++= (char*)bp;
- bp+= l;
- } // end S 1, string
- else { // element type unknown
- byte* p;
-
- WARNv("string table element type unknown: "
- "0x%02X 0x%02X.",bp[0],bp[1])
- p= bp;
- if(pbf_jump(&bp))
- END(-104)
- *p= 0; // set null terminator for previous string
- } // end element type unknown
- } // end for each element in string table
- pb__strm= pb__stre-pb__str;
- bp= bstre;
- break;
- case 0x12: // S 2, primitive group
- *bp++= 0; // set null terminator for previous string
- l= pbf_uint32(&bp);
- if(bp+l>zbufe)
- ENDEv(-111,"primitive group too large: %u",l)
- groupp= bp;
- groupe= bp+l;
- zbufp= groupe;
- /**/goto mainloop; // we got a new primitive group
- case 0x88: // 0x01 V 17, nanodegrees
- if(bp[1]!=0x01) goto d_unknown;
- bp+= 2;
- l= pbf_uint32(&bp);
- if(l!=global_pbfgranularity) {
- if(l>100)
- ENDEv(-120,"please specify: "
- "--pbf-granularity=%u",l)
- else if(l==100)
- ENDE(-120,"please do not specify "
- "--pbf-granularity")
- else
- ENDEv(-121,"granularity %u must be >=100.",l)
- }
- break;
- case 0x90: // 0x01 V 18, millisec
- if(bp[1]!=0x01) goto d_unknown;
- bp+= 2;
- l= pbf_uint32(&bp);
- if(l!=1000)
- ENDEv(-122,"node milliseconds must be 1000: %u",l)
- break;
- case 0x98: // 0x01 V 19, latitude offset
- if(bp[1]!=0x01) goto d_unknown;
- bp+= 2;
- if(pbf_sint64(&bp)!=0)
- ENDE(-123,"cannot process latitude offsets.")
- break;
- case 0xa0: // 0x01 V 20, longitude offset
- if(bp[1]!=0x01) goto d_unknown;
- bp+= 2;
- if(pbf_sint64(&bp)!=0)
- ENDE(-124,"cannot process longitude offsets.")
- break;
- d_unknown:
- default:
- /* block */ {
- byte* p;
- WARNv("data block element type unknown: "
- "0x%02X 0x%02X.",bp[0],bp[1])
- p= bp;
- if(pbf_jump(&bp))
- END(-125)
- *p= 0; // set null terminator for previous string
- } // end block
- } // end first byte of element
- if(bp>zbufe)
- ENDE(-129,"data block format length.")
- } // end for every element in this loop
- } // process data block
- } // zbuf data left
-//// provide new zbuf data
- /* get new zbuf data */ {
- int datasize; // -1: expected;
- int rawsize; // -1: expected;
- int zdata; // -1: expected;
- // 1: encountered section with compressed data
- uint l;
- byte* p;
- int r;
-
- // initialization
- blocktype= datasize= rawsize= zdata= -1;
- read_setjump();
-
- // care for new input data
- if(read_bufp>read_bufe)
- ENDE(-11,"main format length.")
- read_input(); // get at least maximum block size
- if(read_bufp>=read_bufe) // at end of input file
- END(-1)
- if(read_bufp[0]!=0) // unknown id at outermost level
- ENDEv(-12,"main-element type unknown: "
- "0x%02X 0x%02X.",read_bufp[0],read_bufp[1])
- if(read_bufp[1]!=0 || read_bufp[2]!=0 ||
- read_bufp[3]<11 || read_bufp[3]>17)
- ENDEv(-13,"format blob header %i.",
- read_bufp[1]*65536+read_bufp[2]*256+read_bufp[3])
- read_bufp+= 4;
-
- // read new block header
- for(;;) { // read new block
- if(blocktype<0) { // block type expected
- if(read_bufp[0]!=0x0a) // not id S 1
- ENDEv(-21,"block type expected at: 0x%02X.",*read_bufp)
- read_bufp++;
- if(memcmp(read_bufp,"\x09OSMHeader",10)==0) {
- blocktype= 1;
- read_bufp+= 10;
- continue;
- }
- if(memcmp(read_bufp,"\x07OSMData",8)==0) {
- blocktype= 2;
- read_bufp+= 8;
- continue;
- }
- blocktype= 0;
- l= pbf_uint32(&read_bufp);
- if(read_bufp+l>read_bufe) // string too long
- ENDEv(-22,"block type too long: %.40s",read_bufp)
- WARNv("block type unknown: %.40s",read_bufp)
- read_bufp+= l;
- continue;
- } // end block type expected
- if(datasize<0) { // data size expected
- if(read_bufp[0]!=0x18) // not id V 3
- ENDEv(-23,"block data size "
- "expected at: 0x%02X.",*read_bufp)
- read_bufp++;
- datasize= pbf_uint32(&read_bufp);
- } // end data size expected
- if(blocktype==0) { // block type unknown
- read_bufp+= datasize; // jump over this block
- continue;
- } // end block type unknown
- if(rawsize<0) { // raw size expected
- if(read_bufp[0]!=0x10) // not id V 2
- ENDEv(-24,"block raw size "
- "expected at: 0x%02X.",*read_bufp)
- p= read_bufp;
- read_bufp++;
- rawsize= pbf_uint32(&read_bufp);
- datasize-= read_bufp-p;
- } // end raw size expected
- if(zdata<0) { // compressed data expected
- if(read_bufp[0]!=0x1a) // not id S 3
- ENDEv(-25,"compressed data "
- "expected at: 0x%02X.",*read_bufp)
- p= read_bufp;
- read_bufp++;
- l= pbf_uint32(&read_bufp);
- datasize-= read_bufp-p;
- if(datasize<0 || datasize>pb__blockM ||
- read_bufp+datasize>read_bufe) {
- PERRv("block data size too large: %i",datasize)
- fprintf(stderr,"Pointers: %p %p %p\n",
- read__buf,read_bufp,read_bufe);
- END(-26)
- }
- if(l!=datasize)
- ENDEv(-31,"compressed length: %i->%u.",datasize,l)
- // uncompress
- r= pb__decompress(read_bufp,l,zbuf,sizeof(zbuf),&l);
- if(r!=0)
- ENDEv(-32,"decompression failed: %i.",r)
- if(l!=rawsize)
- ENDEv(-33,"uncompressed length: %i->%u.",rawsize,l)
- zdata= 1;
- zbufp= zbuf; zbufe= zbuf+rawsize;
- pb__stre= pb__str;
- read_bufp+= datasize;
- break;
- } // end compressed data expected
- if(read_bufp[0]==0) // possibly a new block start
- break;
- } // end read new block
- if(zbufp<zbufe) // zbuf data available
- continue;
- // here: still no osm objects to read in zbuf[]
- ENDE(-39,"missing data in pbf block.")
- } // get new zbuf data
- } // until we have a new object
- end:
- return pb_type;
- } // end pb_input()
-
-static int pb_keyval(char** keyp,char** valp,int keyvalmax) {
- // read tags of an osm .pbf object;
- // keyp,valp: start addresses of lists in which the tags
- // will be stored in;
- // keyvalmax: maximum number of tags which can be stored in the list;
- // return: number of key/val tags which have been read;
- // this procedure should be called after OSM object data have
- // been provided by pb_input();
- // repetitive calls are not allowed because they would result
- // in wrong key/val data;
- int n;
-
- n= 0;
- if(pb_type==0) { // node
- int key,val;
-
- if(pb__nodetags<pb__nodetagse &&
- (key= pbf_uint32(&pb__nodetags))!=0) {
- // there are key/val pairs for this node
- do { // for every key/val pair
- val= pbf_uint32(&pb__nodetags);
- if(key>=pb__strm || val>=pb__strm) {
- PERRv("node key string index overflow: %u,%u>=%u",
- key,val,pb__strm)
-return 0;
- }
- if(++n<=keyvalmax) { // still space in output list
- *keyp++= pb__str[key];
- *valp++= pb__str[val];
- } // still space in output list
- key= pbf_uint32(&pb__nodetags);
- } while(key!=0); // end for every key/val pair
- } // end there are key/val pairs for this node
- } // node
- else if(pb_type==1) { // way
- while(pb__waykey<pb__waykeye && pb__wayval<pb__wayvale) {
- // there are still key/val pairs for this way
- uint key,val;
-
- key= pbf_uint32(&pb__waykey);
- val= pbf_uint32(&pb__wayval);
- if(key>=pb__strm || val>=pb__strm) {
- PERRv("way key string index overflow: %u,%u>=%i",
- key,val,pb__strm)
-return 0;
- }
- if(++n<=keyvalmax) { // still space in output list
- *keyp++= pb__str[key];
- *valp++= pb__str[val];
- } // still space in output list
- } // end there are still key/val pairs for this way
- } // way
- else if(pb_type==2) { // relation
- while(pb__relkey<pb__relkeye && pb__relval<pb__relvale) {
- // there are still refs for this relation
- uint key,val;
-
- key= pbf_uint32(&pb__relkey);
- val= pbf_uint32(&pb__relval);
- if(key>=pb__strm || val>=pb__strm) {
- PERRv("rel key string index overflow: %u,%u>=%i",
- key,val,pb__strm)
-return 0;
- }
- if(++n<=keyvalmax) { // still space in output list
- *keyp++= pb__str[key];
- *valp++= pb__str[val];
- } // still space in output list
- } // end there are still refs for this relation
- } // relation
- if(n>keyvalmax) {
- WARNv("too many key/val pairs for %s: %i>%i",
- ONAME(pb_id),n,keyvalmax)
- n= keyvalmax;
- }
- return n;
- } // end pb_keyval()
-
-static int pb_noderef(int64_t* refidp,int refmax) {
- // read node references of an osm .pbf way object;
- // refidp: start addresses of lists in which the node reference's
- // ids will be stored in;
- // refmax: maximum number of node references which can be stored
- // in the lists;
- // return: number of node references which have been read;
- // this procedure should be called after OSM way data have
- // been provided by pb_input();
- // repetitive calls are not allowed because they would result
- // in wrong noderef data;
- int64_t noderef;
- int n;
-
- n= 0;
- noderef= 0;
- while(pb__waynode<pb__waynodee) {
- // there are still noderefs for this way
- noderef+= pbf_sint64(&pb__waynode);
- if(++n<=refmax) { // still space in output list
- *refidp++= noderef;
- } // still space in output list
- } // there are still noderefs for this way
- if(n>refmax) {
- WARNv("too many noderefs for %s: %i>%i",ONAME(pb_id),n,refmax)
- n= refmax;
- }
- return n;
- } // end pb_noderef()
-
-static int pb_ref(int64_t* refidp,
- byte* reftypep,char** refrolep,int refmax) {
- // read references of an osm .pbf object;
- // refidp: start addresses of lists in which the reference's
- // ids will be stored in;
- // reftypep: same for their types;
- // refrolep: same for their roles;
- // refmax: maximum number of references which can be stored
- // in the lists;
- // return: number of references which have been read;
- // this procedure should be called after OSM relation data have
- // been provided by pb_input();
- // repetitive calls are not allowed because they would result
- // in wrong ref data;
- int64_t refid;
- int n;
-
- n= 0;
- refid= 0;
- while(pb__relrefid<pb__relrefide && pb__relreftype<pb__relreftypee &&
- pb__relrefrole<pb__relrefrolee) {
- // there are still refs for this relation
- int reftype,refrole;
-
- refid+= pbf_sint64(&pb__relrefid);
- reftype= pbf_uint32(&pb__relreftype);
- refrole= pbf_uint32(&pb__relrefrole);
- if(refrole>=pb__strm) {
- PERRv("rel refrole string index overflow: %u>=%u",
- refrole,pb__strm)
-return 0;
- }
- if(++n<=refmax) { // still space in output list
- *refidp++= refid;
- *reftypep++= reftype;
- *refrolep++= pb__str[refrole];
- } // still space in output list
- } // end there are still refs for this relation
- if(n>refmax) {
- WARNv("too many relrefs for %s: %i>%i",ONAME(pb_id),n,refmax)
- n= refmax;
- }
- return n;
- } // end pb_ref()
-
-//------------------------------------------------------------
-// end Module pb_ pbf read module
-//------------------------------------------------------------
-
-
-
-//------------------------------------------------------------
-// Module pstw_ pbf string write module
-//------------------------------------------------------------
-
-// this module provides procedures for collecting c-formatted
-// strings while eliminating string doublets;
-// this is needed to create Blobs for writing data in .pbf format;
-// as usual, all identifiers of a module have the same prefix,
-// in this case 'pstw'; an underline will follow in case of a
-// global accessible object, two underlines in case of objects
-// which are not meant to be accessed from outside this module;
-// the sections of private and public definitions are separated
-// by a horizontal line: ----
-
-// string processing
-// we need a string table to collect every string of a Blob;
-// the data entities do not contain stings, they just refer to
-// the strings in the string table; hence string doublets need
-// not to be stored physically;
-
-// how this is done
-//
-// there is a string memory; the pointer pstw__mem poits to the start
-// of this memory area; into this area every string is written, each
-// starting with 0x0a and the string length in pbf unsigned Varint
-// format;
-//
-// there is a string table which contains pointers to the start of each
-// string in the string memory area;
-//
-// there is a hash table which accelerates access to the string table;
-
-#define kilobytes *1000 // unit "kilo"
-#define Kibibytes *1024 // unit "Kibi"
-#define Megabytes *1000000 // unit "Mega"
-#define Mibibytes *1048576 // unit "Mibi"
-#define pstw__memM (30 Megabytes)
- // maximum number of bytes in the string memory
-#define pstw__tabM (1500000)
- // maximum number of strings in the table
-#define pstw__hashtabM 25000009 // (preferably a prime number)
- // --> 150001, 1500007, 5000011, 10000019, 15000017,
- // 20000003, 25000009, 30000049, 40000003, 50000017
-static char* pstw__mem= NULL; // pointer to the string memory
-static char* pstw__meme= NULL, *pstw__memee= NULL; // pointers to
- // the logical end and to the physical end of string memory
-typedef struct pstw__tab_struct {
- int index; // index of this string table element;
- int len; // length of the string contents
- char* mem0; // pointer to the string's header in string memory area,
- // i.e., the byte 0x0a and the string's length in Varint format;
- char* mem; // pointer to the string contents in string memory area
- int frequency; // number of occurrences of this string
- int hash;
- // hash value of this element, used as a backlink to the hash table;
- struct pstw__tab_struct* next;
- // for chaining of string table rows which match
- // the same hash value; the last element will point to NULL;
- } pstw__tab_t;
-static pstw__tab_t pstw__tab[pstw__tabM]; // string table
-static int pstw__tabn= 0; // number of entries in string table
-static pstw__tab_t* pstw__hashtab[pstw__hashtabM];
- // hash table; elements point to matching strings in pstw__tab[];
- // []==NULL: no matching element to this certain hash value;
-
-static inline uint32_t pstw__hash(const char* str,int* hash) {
- // get hash value of a string;
- // str[]: string from whose contents the hash is to be retrieved;
- // return: length of the string;
- // *hash: hash value in the range 0..(pstw__hashtabM-1);
- uint32_t c,h;
- const char* s;
-
- s= str;
- h= 0;
- for(;;) {
- if((c= *s++)==0) break; h+= c;
- if((c= *s++)==0) break; h+= c<<8;
- if((c= *s++)==0) break; h+= c<<16;
- if((c= *s++)==0) break; h+= c<<24;
- if((c= *s++)==0) break; h+= c<<4;
- if((c= *s++)==0) break; h+= c<<12;
- if((c= *s++)==0) break; h+= c<<20;
- }
- *hash= h % pstw__hashtabM;
- return (uint32_t)(s-str-1);
- } // end pstw__hash()
-
-static inline pstw__tab_t* pstw__getref(
- pstw__tab_t* tabp,const char* s) {
- // get the string table reference of a string;
- // tabp: presumed index in string table (we got it from hash table);
- // must be >=0 and <pstw__tabM, there is no boundary check;
- // s[]: string whose reference is to be determined;
- // return: pointer to string table entry;
- // ==NULL: this string has not been stored yet
- const char* sp,*tp;
- int len;
-
- do {
- // compare the string with the tab entry
- tp= tabp->mem;
- len= tabp->len;
- sp= s;
- while(*sp!=0 && len>0 && *sp==*tp) { len--; sp++; tp++; }
- if(*sp==0 && len==0) // string identical to string in table
- break;
- tabp= tabp->next;
- } while(tabp!=NULL);
- return tabp;
- } // end pstw__getref()
-
-static void pstw__end() {
- // clean-up string processing;
- if(pstw__mem!=NULL) {
- free(pstw__mem);
- pstw__mem= pstw__meme= pstw__memee= NULL;
- }
- } // end pstw__end()
-
-//------------------------------------------------------------
-
-static int pstw_ini() {
- // initialize this module;
- // must be called before any other procedure is called;
- // return: 0: everything went ok;
- // !=0: an error occurred;
- static bool firstrun= true;
-
- if(firstrun) {
- firstrun= false;
- pstw__mem= (char*)malloc(pstw__memM);
- if(pstw__mem==NULL)
-return 1;
- atexit(pstw__end);
- pstw__memee= pstw__mem+pstw__memM;
- pstw__meme= pstw__mem;
- }
- return 0;
- } // end pstw_ini()
-
-static inline void pstw_reset() {
- // clear string table and string hash table;
- // must be called before the first string is stored;
- memset(pstw__hashtab,0,sizeof(pstw__hashtab));
- pstw__meme= pstw__mem;
-
- // write string information of zero-string into string table
- pstw__tab->index= 0;
- pstw__tab->len= 0;
- pstw__tab->frequency= 0;
- pstw__tab->next= NULL;
- pstw__tab->hash= 0;
-
- // write zero-string into string information memory area
- pstw__tab->mem0= pstw__meme;
- *pstw__meme++= 0x0a; // write string header into string memory
- *pstw__meme++= 0; // write string length
- pstw__tab->mem= pstw__meme;
-
- pstw__tabn= 1; // start with index 1
- } // end pstw_reset()
-
-static inline int pstw_store(const char* s) {
- // store a string into string memory and return the string's index;
- // if an identical string has already been stored, omit writing,
- // just return the index of the stored string;
- // s[]: string to write;
- // return: index of the string in string memory;
- // <0: string could not be written (e.g. not enough memory);
- uint32_t sl; // length of the string
- int h; // hash value
- pstw__tab_t* tabp;
-
- sl= pstw__hash(s,&h);
- tabp= pstw__hashtab[h];
- if(tabp!=NULL) // string presumably stored already
- tabp= pstw__getref(tabp,s); // get the right one
- // (if there are more than one with the same hash value)
- if(tabp!=NULL) { // we found the right string in the table
- tabp->frequency++; // mark that the string has (another) duplicate
-return tabp->index;
- }
- // here: there is no matching string in the table
-
- // check for string table overflow
- if(pstw__tabn>=pstw__tabM) { // no entry left in string table
- PERR("PBF write: string table overflow.")
-return -1;
- }
- if(sl+10>(pstw__memee-pstw__meme)) {
- // not enough memory left in string memory area
- PERR("PBF write: string memory overflow.")
-return -2;
- }
-
- // write string information into string table
- tabp= pstw__tab+pstw__tabn;
- tabp->index= pstw__tabn++;
- tabp->len= sl;
- tabp->frequency= 1;
-
- // update hash table references accordingly
- tabp->next= pstw__hashtab[h];
- pstw__hashtab[h]= tabp; // link the new element to hash table
- tabp->hash= h; // back-link to hash table element
-
- // write string into string information memory area
- tabp->mem0= pstw__meme;
- *pstw__meme++= 0x0a; // write string header into string memory
- /* write the string length into string memory */ {
- uint32_t v,frac;
-
- v= sl;
- frac= v&0x7f;
- while(frac!=v) {
- *pstw__meme++= frac|0x80;
- v>>= 7;
- frac= v&0x7f;
- }
- *pstw__meme++= frac;
- } // write the string length into string memory
- tabp->mem= pstw__meme;
- strcpy(pstw__meme,s); // write string into string memory
- pstw__meme+= sl;
- return tabp->index;
- } // end pstw_store()
-
-#if 1
-static inline void pstw_write(byte** bufpp) {
- // write the string table in PBF format;
- // *bufpp: start address where to write the string table;
- // return:
- // *bufpp: address of the end of the written string table;
- size_t size;
-
- if(pstw__tabn==0) // not a single string in memory
-return;
- size= pstw__meme-pstw__mem;
- memcpy(*bufpp,pstw__mem,size);
- *bufpp+= size;
- } // end pstw_write()
-
-#else
-// remark:
-// in the present program structure the bare sorting of the
-// string table will lead to false output because string indexes
-// in data fields are not updated accordingly;
-// there would be an easy way to accomplish this for dense nodes,
-// but I don't know if it's worth the effort in the first place;
-
-static int pstw__qsort_write(const void* a,const void* b) {
- // string occurrences comparison for qsort() in pstw_write()
- int ax,bx;
-
- ax= ((pstw__tab_t**)a)->frequency;
- bx= ((pstw__tab_t**)b)->frequency;
- if(ax>bx)
-return 1;
- if(ax==bx)
-return 0;
- return -1;
- } // end pstw__qsort_write()
-
-static inline int pstw_write(byte** bufpp) {
- // write the string table in PBF format;
- // *bufpp: start address where to write the string table;
- // return: number of bytes written;
- // *bufpp: address of the end of the written string table;
- // not used at present:
- // before the string table is written, it has to be ordered by
- // the number of occurrences of the strings; the most frequently
- // used strings must be written first;
- pstw__tab_t* tabp,*taborder[pstw__tabM],**taborderp;
- int i;
- byte* bufp;
- int l;
-
- if(pstw__tabn==0) // not a single string in memory
-return;
-
- // sort the string table, using an index list
- taborderp= taborder;
- tabp= pstw__tab;
- for(i= 0; i<pstw__tabn; i++) // for every string in string table
- *taborderp++= tabp++; // create an index list of the string table
- qsort(taborder,pstw__tabn,sizeof(taborder[0]),pstw__qsort_write);
-
- // write the string table, using the list of sorted indexes
- bufp= *bufpp;
- taborderp= taborder;
- for(i= 0; i<pstw__tabn; i++) { // for every string in string table
- tabp= *taborder++;
- l= (int)(tabp->mem-tabp->mem0)+tabp->len;
- memcpy(bufp,tabp->mem0,l);
- bufp+= l;
- } // for every string in string table
- l= bufp-*bufpp;
- *bufpp= bufp;
- return l;
- } // end pstw_write()
-#endif
-
-static inline int pstw_queryspace() {
- // query how much memory space is presently used by the strings;
- // this is useful before calling pstw_write();
- return (int)(pstw__meme-pstw__mem);
- } // end pstw_queryspace()
-
-//------------------------------------------------------------
-// end Module pstw_ pbf string write module
-//------------------------------------------------------------
-
-
-
-//------------------------------------------------------------
-// Module pw_ PBF write module
-//------------------------------------------------------------
-
-// this module provides procedures which write .pbf objects;
-// it uses procedures from module write_;
-// as usual, all identifiers of a module have the same prefix,
-// in this case 'pw'; an underline will follow in case of a
-// global accessible object, two underlines in case of objects
-// which are not meant to be accessed from outside this module;
-// the sections of private and public definitions are separated
-// by a horizontal line: ----
-
-static int pw__compress(byte* ibuf,uint isiz,byte* obuf,uint osizm,
- uint* osizp) {
- // compress a block of data;
- // return: 0: compression was successful;
- // !=0: error number from zlib;
- // *osizp: size of compressed data;
- z_stream strm;
- int r,i;
-
- // initialization
- strm.zalloc= Z_NULL;
- strm.zfree= Z_NULL;
- strm.opaque= Z_NULL;
- strm.next_in= Z_NULL;
- strm.total_in= 0;
- strm.avail_out= 0;
- strm.next_out= Z_NULL;
- strm.total_out= 0;
- strm.msg= NULL;
- r= deflateInit(&strm,Z_DEFAULT_COMPRESSION);
- if(r!=Z_OK)
-return r;
-
- // read data
- strm.next_in = ibuf;
- strm.avail_in= isiz;
-
- // compress
- strm.next_out= obuf;
- strm.avail_out= osizm;
- r= deflate(&strm,Z_FINISH);
- if(/*r!=Z_OK &&*/ r!=Z_STREAM_END) {
- deflateEnd(&strm);
- *osizp= 0;
- if(r==0) r= 1000;
-return r;
- }
-
- // clean-up
- deflateEnd(&strm);
- obuf+= *osizp= osizm-(i= strm.avail_out);
-
- // add some zero bytes
- if(i>4) i= 4;
- while(--i>=0) *obuf++= 0;
- return 0;
- } // end pw__compress()
-
-// format description: BlobHeader must be less than 64 kilobytes;
-// uncompressed length of a Blob must be less than 32 megabytes;
-
-#define pw__compress_bufM (UINT64_C(35) Megabytes)
-static byte* pw__compress_buf= NULL; // buffer for compressed objects
-
-#define pw__bufM (UINT64_C(186) Megabytes)
-static byte* pw__buf= NULL; // buffer for objects in .pbf format
-static byte* pw__bufe= NULL; // logical end of the buffer
-static byte* pw__bufee= NULL; // physical end of the buffer
-
-typedef struct pw__obj_struct { // type of a pbf hierarchy object
- //struct pw__obj_struct parent; // parent object; ==NULL: none;
- byte* buf; // start address of pbf buffer for this hierarchy object;
- // this is where the header starts too;
- int headerlen; // usually .bufl-.buf;
- byte* bufl; // start address of object's length
- byte* bufc; // start address of object's contents
- byte* bufe; // write pointer in the pbf buffer
- byte* bufee; // end address of pbf buffer for this hierarchy object
- } pw__obj_t;
-
-#define pw__objM 20
-static pw__obj_t pw__obj[pw__objM];
-static pw__obj_t* pw__obje= pw__obj;
- // logical end of the object hierarchy array
-static pw__obj_t *pw__objee= pw__obj+pw__objM;
- // physical end of the object hierarchy array
-static pw__obj_t* pw__objp= NULL; // currently active hierarchy object
-
-static inline pw__obj_t* pw__obj_open(const char* header) {
- // open a new hierarchy level
- // header[20]: header which is to be written prior to the
- // contents length; zero-terminated;
- pw__obj_t* op;
-
- if(pw__obje==pw__obj) { // first hierarchy object
- pw__bufe= pw__buf;
- //pw__obje->parent= NULL;
- pw__obje->buf= pw__bufe;
- }
- else { // not the first hierarchy object
- if(pw__obje>=pw__objee) { // no space left in hierarchy array
- PERR("PBF write: hierarchy overflow.")
-return pw__objp;
- }
- op= pw__obje-1;
- if(op->bufee==pw__bufee) { // object is not a limited one
- pw__obje->buf= op->bufe;
- }
- else // object is a limited one
- pw__obje->buf= op->bufee;
- if(pw__obje->buf+50>pw__bufee) { // no space left PBF object buffer
- PERR("PBF write: object buffer overflow.")
-return pw__objp;
- }
- } // not the first hierarchy object
- pw__objp= pw__obje++;
- // write PBF object's header and pointers
- pw__objp->bufl= (byte*)stpmcpy((char*)pw__objp->buf,header,20);
- pw__objp->headerlen= (int)(pw__objp->bufl-pw__objp->buf);
- pw__objp->bufc= pw__objp->bufl+10;
- pw__objp->bufe= pw__objp->bufc;
- pw__objp->bufee= pw__bufee;
- return pw__objp;
- } // pw__obj_open()
-
-static inline void pw__obj_limit(int size) {
- // limit the maximum size of an PBF hierarchy object;
- // this is necessary if two or more PBF objects shall be written
- // simultaneously, e.g. when writing dense nodes;
-
- if(size>pw__objp->bufee-pw__objp->bufc-50) {
- PERRv("PBF write: object buffer limit too large: %i>%i.",
- size,(int)(pw__objp->bufee-pw__objp->bufc-50))
-return;
- }
- pw__objp->bufee= pw__objp->bufc+size;
- } // pw__obj_limit()
-
-static inline void pw__obj_limit_parent(pw__obj_t* parent) {
- // limit the size of a PBF hierarchy parent object to the
- // sum of the maximum sizes of its children;
- // parent: must point to the parent object;
- // pw__objp: must point to the last child of the parent;
- parent->bufee= pw__objp->bufee;
- } // pw__obj_limit_parent()
-
-static inline void pw__obj_compress() {
- // compress the contents of the current PBF hierarchy object;
- // pw__objp: pointer to current object;
- int r;
- unsigned int osiz; // size of the compressed contents
-
- r= pw__compress(pw__objp->bufc,pw__objp->bufe-pw__objp->bufc,
- pw__compress_buf,pw__compress_bufM,&osiz);
- if(r!=0) { // an error has occurred
- PERRv("PBF write: compression error %i.",r)
-return;
- }
- if(osiz>pw__objp->bufee-pw__objp->bufc) {
- PERRv("PBF write: compressed contents too large: %i>%i.",
- osiz,(int)(pw__objp->bufee-pw__objp->bufc))
-return;
- }
- memcpy(pw__objp->bufc,pw__compress_buf,osiz);
- pw__objp->bufe= pw__objp->bufc+osiz;
- } // pw__obj_compress()
-
-static inline void pw__obj_add_id(uint8_t pbfid) {
- // append a one-byte PBF id to PBF write buffer;
- // pbfid: PBF id;
- // pw__objp->bufe: write buffer position (will be
- // incremented by this procedure);
- if(pw__objp->bufe>=pw__objp->bufee) {
- PERR("PBF write: id memory overflow.")
-return;
- }
- *pw__objp->bufe++= pbfid;
- } // pw__obj_add_id()
-
-static inline void pw__obj_add_id2(uint16_t pbfid) {
- // append a two-byte PBF id to PBF write buffer;
- // pbfid: PBF id, high byte is stored first;
- // pw__objp->bufe: write buffer position (will be
- // incremented by 2 by this procedure);
- if(pw__objp->bufe+2>pw__objp->bufee) {
- PERR("PBF write: id2 memory overflow.")
-return;
- }
- *pw__objp->bufe++= (byte)(pbfid>>8);
- *pw__objp->bufe++= (byte)(pbfid&0xff);
- } // pw__obj_add_id2()
-
-static inline void pw__obj_add_uint32(uint32_t v) {
- // append a numeric value to PBF write buffer;
- // pw__objp->bufe: write buffer position
- // (will be updated by this procedure);
- uint32_t frac;
-
- if(pw__objp->bufe+10>pw__objp->bufee) {
- PERR("PBF write: uint32 memory overflow.")
-return;
- }
- frac= v&0x7f;
- while(frac!=v) {
- *pw__objp->bufe++= frac|0x80;
- v>>= 7;
- frac= v&0x7f;
- }
- *pw__objp->bufe++= frac;
- } // pw__obj_add_uint32()
-
-static inline void pw__obj_add_sint32(int32_t v) {
- // append a numeric value to PBF write buffer;
- // pw__objp->bufe: write buffer position
- // (will be updated by this procedure);
- uint32_t u;
- uint32_t frac;
-
- if(pw__objp->bufe+10>pw__objp->bufee) {
- PERR("PBF write: sint32 memory overflow.")
-return;
- }
- if(v<0) {
- u= -v;
- u= (u<<1)-1;
- }
- else
- u= v<<1;
- frac= u&0x7f;
- while(frac!=u) {
- *pw__objp->bufe++= frac|0x80;
- u>>= 7;
- frac= u&0x7f;
- }
- *pw__objp->bufe++= frac;
- } // pw__obj_add_sint32()
-
-static inline void pw__obj_add_uint64(uint64_t v) {
- // append a numeric value to PBF write buffer;
- // pw__objp->bufe: write buffer position
- // (will be updated by this procedure);
- uint32_t frac;
-
- if(pw__objp->bufe+10>pw__objp->bufee) {
- PERR("PBF write: uint64 memory overflow.")
-return;
- }
- frac= v&0x7f;
- while(frac!=v) {
- *pw__objp->bufe++= frac|0x80;
- v>>= 7;
- frac= v&0x7f;
- }
- *pw__objp->bufe++= frac;
- } // pw__obj_add_uint64()
-
-static inline void pw__obj_add_sint64(int64_t v) {
- // append a numeric value to PBF write buffer;
- // pw__objp->bufe: write buffer position
- // (will be updated by this procedure);
- uint64_t u;
- uint32_t frac;
-
- if(pw__objp->bufe+10>pw__objp->bufee) {
- PERR("PBF write: sint64 memory overflow.")
-return;
- }
- if(v<0) {
- u= -v;
- u= (u<<1)-1;
- }
- else
- u= v<<1;
- frac= u&0x7f;
- while(frac!=u) {
- *pw__objp->bufe++= frac|0x80;
- u>>= 7;
- frac= u&0x7f;
- }
- *pw__objp->bufe++= frac;
- } // pw__obj_add_sint64()
-
-#if 0 // not used at present
-static inline void pw__obj_add_mem(byte* s,uint32_t sl) {
- // append data to PBF write buffer;
- // s[]: data which are to append;
- // ls: length of the data;
- // pw__objp->bufe: write buffer position
- // (will be updated by this procedure);
-
- if(pw__objp->bufe+sl>pw__objp->bufee) {
- PERR("PBF write: mem memory overflow.")
-return;
- }
- memcpy(pw__objp->bufe,s,sl);
- pw__objp->bufe+= sl;
- } // pw__obj_add_mem()
-#endif
-
-static inline void pw__obj_add_str(const char* s) {
- // append a PBF string to PBF write buffer;
- // pw__objp->bufe: write buffer position
- // (will be updated by this procedure);
- uint32_t sl; // length of the string
-
- sl= strlen(s);
- if(pw__objp->bufe+10+sl>pw__objp->bufee) {
- PERR("PBF write: string memory overflow.")
-return;
- }
- /* write the string length into PBF write buffer */ {
- uint32_t v,frac;
-
- v= sl;
- frac= v&0x7f;
- while(frac!=v) {
- *pw__objp->bufe++= frac|0x80;
- v>>= 7;
- frac= v&0x7f;
- }
- *pw__objp->bufe++= frac;
- } // write the string length into PBF write buffer
- memcpy(pw__objp->bufe,s,sl);
- pw__objp->bufe+= sl;
- } // pw__obj_add_str()
-
-static inline void pw__obj_close() {
- // close an object which had been opened with pw__obj_open();
- // pw__objp: pointer to the object which is to close;
- // return:
- // pw__objp: points to the last opened object;
- pw__obj_t* op;
- int i;
- byte* bp;
- uint32_t len;
- uint32_t v,frac;
-
- if(pw__objp==pw__obj) { // this is the anchor object
- // write the object's data to standard output
- write_mem(pw__objp->buf,pw__objp->headerlen); // write header
- write_mem(pw__objp->bufc,(int)(pw__objp->bufe-pw__objp->bufc));
- // write contents
- // delete hierarchy object
- pw__objp= NULL;
- pw__obje= pw__obj;
-return;
- }
-
- // determine the parent object
- op= pw__objp;
- for(;;) { // search for the parent object
- if(op<=pw__obj) { // there is no parent object
- PERR("PBF write: no parent object.")
-return;
- }
- op--;
- if(op->buf!=NULL) // found our parent object
- break;
- }
-
- // write PBF object's header into parent object
- bp= pw__objp->buf;
- i= pw__objp->headerlen;
- while(--i>=0)
- *op->bufe++= *bp++;
-
- // write PBF object's length into parent object
- len= v= pw__objp->bufe-pw__objp->bufc;
- frac= v&0x7f;
- while(frac!=v) {
- *op->bufe++= frac|0x80;
- v>>= 7;
- frac= v&0x7f;
- }
- *op->bufe++= frac;
-
- // write PBF object's contents into parent object
- memmove(op->bufe,pw__objp->bufc,len);
- op->bufe+= len;
-
- // mark this object as deleted
- pw__objp->buf= NULL;
-
- // free the unused space in object hierarchy array
- while(pw__obje>pw__obj && pw__obje[-1].buf==NULL) pw__obje--;
- pw__objp= pw__obje-1;
- } // pw__obj_close()
-
-static inline void pw__obj_dispose() {
- // dispose an object which had been opened with pw__obj_open();
- // pw__objp: pointer to the object which is to close;
- // return:
- // pw__objp: points to the last opened object;
- if(pw__objp==pw__obj) { // this is the anchor object
- // delete hierarchy object
- pw__objp= NULL;
- pw__obje= pw__obj;
-return;
- }
-
- // mark this object as deleted
- pw__objp->buf= NULL;
-
- // free the unused space in object hierarchy array
- while(pw__obje>pw__obj && pw__obje[-1].buf==NULL) pw__obje--;
- pw__objp= pw__obje-1;
- } // pw__obj_dispose()
-
-static pw__obj_t* pw__st= NULL,*pw__dn_id= NULL,*pw__dn_his,
- *pw__dn_hisver= NULL,*pw__dn_histime= NULL,*pw__dn_hiscset= NULL,
- *pw__dn_hisuid= NULL,*pw__dn_hisuser= NULL,
- *pw__dn_lat= NULL,*pw__dn_lon= NULL,*pw__dn_keysvals= NULL;
-
-// some variables for delta coding
-static int64_t pw__dc_id= 0;
-static int32_t pw__dc_lon= 0,pw__dc_lat= 0;
-static int64_t pw__dc_histime= 0;
-static int64_t pw__dc_hiscset= 0;
-static uint32_t pw__dc_hisuid= 0;
-static uint32_t pw__dc_hisuser= 0;
-static int64_t pw__dc_noderef= 0;
-static int64_t pw__dc_ref= 0;
-
-static void pw__data(int otype) {
- // prepare or complete an 'OSMData fileblock';
- // should be called prior to writing each OSM object;
- // otype: type of the OSM object which is going to be written;
- // 0: node; 1: way; 2: relation; -1: none;
- static int otype_old= -1;
- static const int max_object_size= (250 kilobytes);
- // assumed maximum size of one OSM object
- #define pw__data_spaceM (31 Megabytes)
- // maximum size of one 'fileblock'
- static int used_space= pw__data_spaceM;
- // presently used memory space in present 'OSMData fileblock',
- // not including the strings
- int string_space; // memory space used by strings
- int remaining_space;
- // remaining memory space in present 'OSMData fileblock'
- int i;
-
- // determine remaining space in current 'OSMData fileblock';
- // the remaining space is usually guessed in a pessimistic manner;
- // if this estimate shows too less space, then a more exact
- // calculation is made;
- // this strategy has been chosen for performance reasons;
- used_space+= 64000; // increase used-space variable by the assumed
- // maximum size of one OSM object, not including the strings
- string_space= pstw_queryspace();
- remaining_space= pw__data_spaceM-used_space-string_space;
- if(remaining_space<max_object_size) { // might be too less space
- // calculate used space more exact
- if(otype_old==0) { // node
- used_space= (int)((pw__dn_id->bufe-pw__dn_id->buf)+
- (pw__dn_lat->bufe-pw__dn_lat->buf)+
- (pw__dn_lon->bufe-pw__dn_lon->buf)+
- (pw__dn_keysvals->bufe-pw__dn_keysvals->buf));
- if(!global_dropversion) {
- used_space+= (int)(pw__dn_hisver->bufe-pw__dn_hisver->buf);
- if(!global_dropauthor) {
- used_space+= (int)((pw__dn_histime->bufe-pw__dn_histime->buf)+
- (pw__dn_hiscset->bufe-pw__dn_hiscset->buf)+
- (pw__dn_hisuid->bufe-pw__dn_hisuid->buf)+
- (pw__dn_hisuser->bufe-pw__dn_hisuser->buf));
- }
- }
- }
- else if(otype_old>0) // way or relation
- used_space= (int)(pw__objp->bufe-pw__objp->buf);
- remaining_space= pw__data_spaceM-used_space-string_space;
- } // might be too less space
-
- // conclude or start an 'OSMData fileblock'
- if(otype!=otype_old || remaining_space<max_object_size) {
- // 'OSMData fileblock' must be concluded or started
- if(otype_old>=0) { // there has been object processing
- // complete current 'OSMData fileblock'
- used_space= pw__data_spaceM; // force new calculation next time
- i= pstw_queryspace();
- if(i>pw__st->bufee-pw__st->bufe)
- PERR("PBF write: string table memory overflow.")
- else
- pstw_write(&pw__st->bufe);
- pw__objp= pw__st; pw__obj_close(); // 'stringtable'
- switch(otype_old) { // select by OSM object type
- case 0: // node
- pw__objp= pw__dn_id; pw__obj_close();
- if(!global_dropversion) { // version number is to be written
- pw__objp= pw__dn_hisver; pw__obj_close();
- if(!global_dropauthor) { // author information is to be written
- pw__objp= pw__dn_histime; pw__obj_close();
- pw__objp= pw__dn_hiscset; pw__obj_close();
- pw__objp= pw__dn_hisuid; pw__obj_close();
- pw__objp= pw__dn_hisuser; pw__obj_close();
- } // author information is to be written
- pw__objp= pw__dn_his; pw__obj_close();
- } // version number is to be written
- pw__objp= pw__dn_lat; pw__obj_close();
- pw__objp= pw__dn_lon; pw__obj_close();
- pw__objp= pw__dn_keysvals; pw__obj_close();
- pw__obj_close(); // 'dense'
- break;
- case 1: // way
- break;
- case 2: // relation
- break;
- } // select by OSM object type
- pw__obj_close(); // 'primitivegroup'
- /* write 'raw_size' into hierarchy object's header */ {
- uint32_t v,frac;
- byte* bp;
-
- v= pw__objp->bufe-pw__objp->bufc;
- bp= pw__objp->buf+1;
- frac= v&0x7f;
- while(frac!=v) {
- *bp++= frac|0x80;
- v>>= 7;
- frac= v&0x7f;
- }
- *bp++= frac;
- *bp++= 0x1a;
- pw__objp->headerlen= bp-pw__objp->buf;
- }
- pw__obj_compress();
- pw__obj_close(); // 'zlib_data'
- pw__obj_close(); // 'datasize'
- /* write 'length of BlobHeader message' into object's header */ {
- byte* bp;
-
- bp= pw__objp->bufc+pw__objp->bufc[1]+3;
- while((*bp & 0x80)!=0) bp++;
- bp++;
- pw__objp->buf[0]= pw__objp->buf[1]= pw__objp->buf[2]= 0;
- pw__objp->buf[3]= bp-pw__objp->bufc;
- }
- pw__obj_close(); // 'Blobheader'
- otype_old= -1;
- } // there has been object processing
-
- // prepare new 'OSMData fileblock' if necessary
- if(otype!=otype_old) {
- pw__obj_open("----");
- // open anchor hierarchy object for 'OSMData fileblock'
- // (every fileblock starts with four zero-bytes;
- // the fourth zero-byte will be overwritten later
- // by the length of the BlobHeader;)
- pw__obj_add_id(0x0a); // S 1 'type'
- pw__obj_add_str("OSMData");
- pw__obj_open("\x18"); // V 3 'datasize'
- pw__obj_open("\x10----------\x1a"); // S 3 'zlib_data'
- // in the header: V 2 'raw_size'
- pw__st= pw__obj_open("\x0a"); // S 1 'stringtable'
- pw__obj_limit(30 Megabytes);
- pstw_reset();
- pw__obj_open("\x12"); // S 2 'primitivegroup'
- switch(otype) { // select by OSM object type
- case 0: // node
- pw__obj_open("\x12"); // S 2 'dense'
- pw__dn_id= pw__obj_open("\x0a"); // S 1 'id'
- pw__obj_limit(10 Megabytes);
- if(!global_dropversion) { // version number is to be written
- pw__dn_his= pw__obj_open("\x2a"); // S 5 'his'
- pw__dn_hisver= pw__obj_open("\x0a"); // S 1 'his.ver'
- pw__obj_limit(10 Megabytes);
- if(!global_dropauthor) { // author information is to be written
- pw__dn_histime= pw__obj_open("\x12"); // S 2 'his.time'
- pw__obj_limit(10 Megabytes);
- pw__dn_hiscset= pw__obj_open("\x1a"); // S 3 'his.cset'
- pw__obj_limit(10 Megabytes);
- pw__dn_hisuid= pw__obj_open("\x22"); // S 4 'his.uid'
- pw__obj_limit(8 Megabytes);
- pw__dn_hisuser= pw__obj_open("\x2a"); // S 5 'his.user'
- pw__obj_limit(6 Megabytes);
- } // author information is to be written
- pw__obj_limit_parent(pw__dn_his);
- } // version number is to be written
- pw__dn_lat= pw__obj_open("\x42"); // S 8 'lat'
- pw__obj_limit(30 Megabytes);
- pw__dn_lon= pw__obj_open("\x4a"); // S 9 'lon'
- pw__obj_limit(30 Megabytes);
- pw__dn_keysvals= pw__obj_open("\x52"); // S 10 'tags'
- pw__obj_limit(40 Megabytes);
- // reset variables for delta coding
- pw__dc_id= 0;
- pw__dc_lat= pw__dc_lon= 0;
- pw__dc_histime= 0;
- pw__dc_hiscset= 0;
- pw__dc_hisuid= 0;
- pw__dc_hisuser= 0;
- break;
- case 1: // way
- break;
- case 2: // relation
- break;
- } // select by OSM object type
- otype_old= otype;
- } // prepare new 'OSMData fileblock' if necessary
- } // 'OSMData fileblock' must be concluded or started
- } // pw__data()
-
-static void pw__end() {
- // clean-up this module;
- if(pw__obje!=pw__obj)
- PERR("PBF write: object hierarchy still open.")
- if(pw__buf!=NULL) {
- free(pw__buf);
- pw__buf= pw__bufe= pw__bufee= NULL;
- }
- pw__obje= pw__obj;
- pw__objp= NULL;
- if(pw__compress_buf!=NULL) {
- free(pw__compress_buf);
- pw__compress_buf= NULL;
- }
- } // end pw__end()
-
-//------------------------------------------------------------
-
-static inline int pw_ini() {
- // initialize this module;
- // must be called before any other procedure is called;
- // return: 0: everything went ok;
- // !=0: an error occurred;
- static bool firstrun= true;
- int r;
-
- if(firstrun) {
- firstrun= false;
- atexit(pw__end);
- pw__buf= (byte*)malloc(pw__bufM);
- pw__bufe= pw__buf;
- pw__bufee= pw__buf+pw__bufM;
- pw__compress_buf= (byte*)malloc(pw__compress_bufM);
- r= pstw_ini();
- if(pw__buf==NULL || pw__compress_buf==NULL || r!=0) {
- PERR("PBF write: not enough memory.")
-return 1;
- }
- }
- return 0;
- } // end pw_ini()
-
-static void pw_header(bool bboxvalid,
- int32_t x1,int32_t y1,int32_t x2,int32_t y2,int64_t timestamp) {
- // start writing PBF objects, i.e., write the 'OSMHeader fileblock';
- // bboxvalid: the following bbox coordinates are valid;
- // x1,y1,x2,y2: bbox coordinates (base 10^-7);
- // timestamp: file timestamp; ==0: no timestamp given;
- pw__obj_open("----");
- // open anchor hierarchy object for 'OSMHeader fileblock'
- // (every fileblock starts with four zero-bytes;
- // the fourth zero-byte will be overwritten later
- // by the length of the BlobHeader;)
- pw__obj_add_id(0x0a); // S 1 'type'
- pw__obj_add_str("OSMHeader");
- pw__obj_open("\x18"); // V 3 'datasize'
- pw__obj_open("\x10----------\x1a"); // S 3 'zlib_data'
- // in the header: V 2 'raw_size'
- if(bboxvalid) {
- pw__obj_open("\x0a"); // S 1 'bbox'
- pw__obj_add_id(0x08); // V 1 'minlon'
- pw__obj_add_sint64((int64_t)x1*100);
- pw__obj_add_id(0x10); // V 2 'maxlon'
- pw__obj_add_sint64((int64_t)x2*100);
- pw__obj_add_id(0x18); // V 3 'maxlat'
- pw__obj_add_sint64((int64_t)y2*100);
- pw__obj_add_id(0x20); // V 4 'minlat'
- pw__obj_add_sint64((int64_t)y1*100);
- pw__obj_close();
- }
- pw__obj_add_id(0x22); // S 4 'required_features'
- pw__obj_add_str("OsmSchema-V0.6");
- pw__obj_add_id(0x22); // S 4 'required_features'
- pw__obj_add_str("DenseNodes");
- pw__obj_add_id(0x2a); // S 5 'optional_features'
- pw__obj_add_str("Sort.Type_then_ID");
- if(timestamp!=0) { // file timestamp given
- char s[40],*sp;
-
- sp= stpcpy0(s,"timestamp=");
- write_createtimestamp(timestamp,sp);
- pw__obj_add_id(0x2a); // S 5 'optional_features'
- pw__obj_add_str(s);
- } // file timestamp given
- pw__obj_add_id2(0x8201); // S 16 'writingprogram'
- pw__obj_add_str("osmconvert "VERSION);
- pw__obj_add_id2(0x8a01); // S 17 'source'
- pw__obj_add_str("http://www.openstreetmap.org/api/0.6");
- if(timestamp!=0) { // file timestamp given
- pw__obj_add_id2(0x8002); // V 32 osmosis_replication_timestamp
- pw__obj_add_uint64(timestamp);
- } // file timestamp given
- /* write 'raw_size' into hierarchy object's header */ {
- uint32_t v,frac;
- byte* bp;
-
- v= pw__objp->bufe-pw__objp->bufc;
- bp= pw__objp->buf+1;
- frac= v&0x7f;
- while(frac!=v) {
- *bp++= frac|0x80;
- v>>= 7;
- frac= v&0x7f;
- }
- *bp++= frac;
- *bp++= 0x1a;
- pw__objp->headerlen= bp-pw__objp->buf;
- }
- pw__obj_compress();
- pw__obj_close(); // 'zlib_data'
- pw__obj_close(); // 'datasize'
- /* write 'length of BlobHeader message' into object's header */ {
- byte* bp;
-
- bp= pw__objp->bufc+pw__objp->bufc[1]+3;
- while((*bp & 0x80)!=0) bp++;
- bp++;
- pw__objp->buf[0]= pw__objp->buf[1]= pw__objp->buf[2]= 0;
- pw__objp->buf[3]= bp-pw__objp->bufc;
- }
- pw__obj_close(); // 'Blobheader'
- } // end pw_header()
-
-static inline void pw_foot() {
- // end writing a PBF file;
- pw__data(-1);
- } // end pw_foot()
-
-static inline void pw_flush() {
- // end writing a PBF dataset;
- pw__data(-1);
- } // end pw_flush()
-
-static inline void pw_node(int64_t id,
- int32_t hisver,int64_t histime,int64_t hiscset,
- uint32_t hisuid,const char* hisuser,int32_t lon,int32_t lat) {
- // start writing a PBF dense node dataset;
- // id: id of this object;
- // hisver: version; 0: no author information is to be written
- // histime: time (seconds since 1970)
- // hiscset: changeset
- // hisuid: uid
- // hisuser: user name
- // lon: latitude in 100 nanodegree;
- // lat: latitude in 100 nanodegree;
- int stid; // string id
-
- pw__data(0);
- pw__objp= pw__dn_id; pw__obj_add_sint64(id-pw__dc_id);
- pw__dc_id= id;
- if(!global_dropversion) { // version number is to be written
- if(hisver==0) hisver= 1;
- pw__objp= pw__dn_hisver; pw__obj_add_uint32(hisver);
- if(!global_dropauthor) { // author information is to be written
- if(histime==0) { histime= 1; hiscset= 1; hisuser= 0; }
- pw__objp= pw__dn_histime;
- pw__obj_add_sint64(histime-pw__dc_histime);
- pw__dc_histime= histime;
- pw__objp= pw__dn_hiscset;
- pw__obj_add_sint64(hiscset-pw__dc_hiscset);
- pw__dc_hiscset= hiscset;
- pw__objp= pw__dn_hisuid;
- pw__obj_add_sint32(hisuid-pw__dc_hisuid);
- pw__dc_hisuid= hisuid;
- pw__objp= pw__dn_hisuser;
- if(hisuid==0) hisuser= "";
- stid= pstw_store(hisuser);
- pw__obj_add_sint32(stid-pw__dc_hisuser);
- pw__dc_hisuser= stid;
- } // author information is to be written
- } // version number is to be written
- pw__objp= pw__dn_lat; pw__obj_add_sint64(lat-pw__dc_lat);
- pw__dc_lat= lat;
- pw__objp= pw__dn_lon;
- pw__obj_add_sint64((int64_t)lon-pw__dc_lon);
- pw__dc_lon= lon;
- } // end pw_node()
-
-static inline void pw_node_keyval(const char* key,const char* val) {
- // write node object's keyval;
- int stid; // string id
-
- pw__objp= pw__dn_keysvals;
- stid= pstw_store(key);
- pw__obj_add_uint32(stid);
- stid= pstw_store(val);
- pw__obj_add_uint32(stid);
- } // end pw_node_keyval()
-
-static inline void pw_node_close() {
- // close writing node object;
- pw__objp= pw__dn_keysvals;
- pw__obj_add_uint32(0);
- } // end pw_node_close()
-
-static pw__obj_t* pw__wayrel_keys= NULL,*pw__wayrel_vals= NULL,
- *pw__wayrel_his= NULL,*pw__way_noderefs= NULL,
- *pw__rel_roles= NULL,*pw__rel_refids= NULL,*pw__rel_types= NULL;
-
-static inline void pw_way(int64_t id,
- int32_t hisver,int64_t histime,int64_t hiscset,
- uint32_t hisuid,const char* hisuser) {
- // start writing a PBF way dataset;
- // id: id of this object;
- // hisver: version; 0: no author information is to be written;
- // histime: time (seconds since 1970)
- // hiscset: changeset
- // hisuid: uid
- // hisuser: user name;
- int stid; // string id
-
- pw__data(1);
- pw__obj_open("\x1a"); // S 3 'ways'
- pw__obj_add_id(0x08); // V 1 'id'
- pw__obj_add_uint64(id);
- pw__wayrel_keys= pw__obj_open("\x12"); // S 2 'keys'
- pw__obj_limit(20 Megabytes);
- pw__wayrel_vals= pw__obj_open("\x1a"); // S 3 'vals'
- pw__obj_limit(20 Megabytes);
- pw__wayrel_his= pw__obj_open("\x22"); // S 4 'his'
- pw__obj_limit(2000);
- pw__way_noderefs= pw__obj_open("\x42"); // S 8 'noderefs'
- pw__obj_limit(30 Megabytes);
- if(!global_dropversion) { // version number is to be written
- pw__objp= pw__wayrel_his;
- if(hisver==0) hisver= 1;
- pw__obj_add_id(0x08); // V 1 'hisver'
- pw__obj_add_uint32(hisver);
- if(!global_dropauthor) { // author information is to be written
- if(histime==0) {
- histime= 1; hiscset= 1; hisuser= 0; }
- pw__obj_add_id(0x10); // V 2 'histime'
- pw__obj_add_uint64(histime);
- pw__obj_add_id(0x18); // V 3 'hiscset'
- pw__obj_add_uint64(hiscset);
- pw__obj_add_id(0x20); // V 4 'hisuid'
- pw__obj_add_uint32(hisuid);
- pw__obj_add_id(0x28); // V 5 'hisuser'
- if(hisuid==0) hisuser= "";
- stid= pstw_store(hisuser);
- pw__obj_add_uint32(stid);
- } // author information is to be written
- } // version number is to be written
- pw__dc_noderef= 0;
- } // end pw_way()
-
-static inline void pw_wayrel_keyval(const char* key,const char* val) {
- // write a ways or a relations object's keyval;
- int stid; // string id
-
- pw__objp= pw__wayrel_keys;
- stid= pstw_store(key);
- pw__obj_add_uint32(stid);
- pw__objp= pw__wayrel_vals;
- stid= pstw_store(val);
- pw__obj_add_uint32(stid);
- } // end pw_wayrel_keyval()
-
-static inline void pw_way_ref(int64_t noderef) {
- // write a ways object's noderefs;
- pw__objp= pw__way_noderefs;
- pw__obj_add_sint64(noderef-pw__dc_noderef);
- pw__dc_noderef= noderef;
- } // end pw_way_ref()
-
-static inline void pw_way_close() {
- // close writing way object;
- pw__objp= pw__wayrel_keys;
- if(pw__objp->bufe==pw__objp->bufc) // object is empty
- pw__obj_dispose();
- else
- pw__obj_close();
- pw__objp= pw__wayrel_vals;
- if(pw__objp->bufe==pw__objp->bufc) // object is empty
- pw__obj_dispose();
- else
- pw__obj_close();
- pw__objp= pw__wayrel_his;
- if(pw__objp->bufe==pw__objp->bufc) // object is empty
- pw__obj_dispose();
- else
- pw__obj_close();
- pw__objp= pw__way_noderefs;
- if(pw__objp->bufe==pw__objp->bufc) // object is empty
- pw__obj_dispose();
- else
- pw__obj_close();
- pw__obj_close();
- } // end pw_way_close()
-
-static inline void pw_relation(int64_t id,
- int32_t hisver,int64_t histime,int64_t hiscset,
- uint32_t hisuid,const char* hisuser) {
- // start writing a PBF way dataset;
- // id: id of this object;
- // hisver: version; 0: no author information is to be written;
- // histime: time (seconds since 1970)
- // hiscset: changeset
- // hisuid: uid
- // hisuser: user name;
- int stid; // string id
-
- pw__data(2);
- pw__obj_open("\x22"); // S 4 'relations'
- pw__obj_add_id(0x08); // V 1 'id'
- pw__obj_add_uint64(id);
- pw__wayrel_keys= pw__obj_open("\x12"); // S 2 'keys'
- pw__obj_limit(20 Megabytes);
- pw__wayrel_vals= pw__obj_open("\x1a"); // S 3 'vals'
- pw__obj_limit(20 Megabytes);
- pw__wayrel_his= pw__obj_open("\x22"); // S 4 'his'
- pw__obj_limit(2000);
- pw__rel_roles= pw__obj_open("\x42"); // S 8 'role'
- pw__obj_limit(20 Megabytes);
- pw__rel_refids= pw__obj_open("\x4a"); // S 9 'refid'
- pw__obj_limit(20 Megabytes);
- pw__rel_types= pw__obj_open("\x52"); // S 10 'type'
- pw__obj_limit(20 Megabytes);
- if(!global_dropversion) { // version number is to be written
- pw__objp= pw__wayrel_his;
- if(hisver==0) hisver= 1;
- pw__obj_add_id(0x08); // V 1 'hisver'
- pw__obj_add_uint32(hisver);
- if(!global_dropauthor) { // author information is to be written
- if(histime==0) {
- histime= 1; hiscset= 1; hisuser= 0; }
- pw__obj_add_id(0x10); // V 2 'histime'
- pw__obj_add_uint64(histime);
- pw__obj_add_id(0x18); // V 3 'hiscset'
- pw__obj_add_uint64(hiscset);
- pw__obj_add_id(0x20); // V 4 'hisuid'
- pw__obj_add_uint32(hisuid);
- pw__obj_add_id(0x28); // V 5 'hisuser'
- if(hisuid==0) hisuser= "";
- stid= pstw_store(hisuser);
- pw__obj_add_uint32(stid);
- } // author information is to be written
- } // version number is to be written
- pw__dc_ref= 0;
- } // end pw_relation()
-
-static inline void pw_relation_ref(int64_t refid,int reftype,
- const char* refrole) {
- // write a relations object's refs
- int stid; // string id
-
- pw__objp= pw__rel_roles;
- stid= pstw_store(refrole);
- pw__obj_add_uint32(stid);
- pw__objp= pw__rel_refids;
- pw__obj_add_sint64(refid-pw__dc_ref);
- pw__dc_ref= refid;
- pw__objp= pw__rel_types;
- pw__obj_add_uint32(reftype);
- } // end pw_relation_ref()
-
-static inline void pw_relation_close() {
- // close writing relation object;
- pw__objp= pw__wayrel_keys;
- if(pw__objp->bufe==pw__objp->bufc) // object is empty
- pw__obj_dispose();
- else
- pw__obj_close();
- pw__objp= pw__wayrel_vals;
- if(pw__objp->bufe==pw__objp->bufc) // object is empty
- pw__obj_dispose();
- else
- pw__obj_close();
- pw__objp= pw__wayrel_his;
- if(pw__objp->bufe==pw__objp->bufc) // object is empty
- pw__obj_dispose();
- else
- pw__obj_close();
- pw__objp= pw__rel_roles;
- if(pw__objp->bufe==pw__objp->bufc) // object is empty
- pw__obj_dispose();
- else
- pw__obj_close();
- pw__objp= pw__rel_refids;
- if(pw__objp->bufe==pw__objp->bufc) // object is empty
- pw__obj_dispose();
- else
- pw__obj_close();
- pw__objp= pw__rel_types;
- if(pw__objp->bufe==pw__objp->bufc) // object is empty
- pw__obj_dispose();
- else
- pw__obj_close();
- pw__obj_close();
- } // end pw_relation_close()
-
-//------------------------------------------------------------
-// end Module pw_ PBF write module
-//------------------------------------------------------------
-
-
-
-//------------------------------------------------------------
-// Module posi_ OSM position module
-//------------------------------------------------------------
-
-// this module provides a geocoordinate table for to store
-// the coordinates of all OSM objects;
-// the procedures posi_set() (resp. posi_setbbox()) and
-// posi_get() allow access to this tables;
-// as usual, all identifiers of a module have the same prefix,
-// in this case 'posi'; an underline will follow for a global
-// accessible identifier, two underlines if the identifier
-// is not meant to be accessed from outside this module;
-// the sections of private and public definitions are separated
-// by a horizontal line: ----
-
-struct posi__mem_struct { // element of position array
- int64_t id;
- int32_t data[];
- } __attribute__((__packed__));
- // (do not change this structure; the search algorithm expects
- // the size of this structure to be 16 or 32 bytes)
- // data[] stands for either
- // int32_t x,y;
- // or
- // int32_t x,y,x1,y1,x2,y2; // (including bbox)
- // remarks to .x:
- // if you get posi_nil as value for x, you may assume that
- // the object has been stored, but its geoposition is unknown;
- // remarks to .id:
- // the caller of posi_set() and posi_get() has to care about adding
- // global_otypeoffset10 to the id if the object is a way and
- // global_otypeoffset20 to the id if the object is a relation;
-typedef struct posi__mem_struct posi__mem_t;
-static posi__mem_t* posi__mem= NULL; // start address of position array
-static posi__mem_t* posi__meme= NULL; // logical end address
-static posi__mem_t* posi__memee= NULL; // physical end address
-
-static void posi__end() {
- // clean-up for posi module;
- // will be called at program's end;
- if(posi__mem==NULL)
- PERR("not enough memory. Reduce --max-objects=")
- else { // was initialized
- if(posi__meme>=posi__memee) // not enough space in position array
- PERR("not enough space. Increase --max-objects=")
- else {
- int64_t siz;
-
- siz= (char*)posi__memee-(char*)posi__mem;
- siz= siz/4*3;
- if((char*)posi__meme-(char*)posi__mem>siz)
- // low space in position array
- WARN("low space. Try to increase --max-objects=")
- }
- free(posi__mem);
- posi__mem= NULL;
- }
- } // end posi__end()
-
-//------------------------------------------------------------
-
-static size_t posi__mem_size= 0; // size of structure
-static size_t posi__mem_increment= 0;
- // how many increments to ++ when allocating
-static size_t posi__mem_mask= 0;
- // bitmask to start at base of structure
-
-static int posi_ini() {
- // initialize the posi module;
- // return: 0: OK; 1: not enough memory;
- int64_t siz;
-
- global_otypeoffset05= global_otypeoffset10/2;
- global_otypeoffset15= global_otypeoffset10+global_otypeoffset05;
- global_otypeoffset20= global_otypeoffset10*2;
- if(global_otypeoffsetstep!=0)
- global_otypeoffsetstep= global_otypeoffset10;
- if(posi__mem!=NULL) // already initialized
-return 0;
- atexit(posi__end); // chain-in the clean-up procedure
- // allocate memory for the positions array
- if (global_calccoords<0) {
- posi__mem_size = 32;
- posi__mem_mask = ~0x1f;
- posi__mem_increment = 4;
- }
- else {
- posi__mem_size = 16;
- posi__mem_mask = ~0x0f;
- posi__mem_increment = 2;
- }
- siz= posi__mem_size*global_maxobjects;
- posi__mem= (posi__mem_t*)malloc(siz);
- if(posi__mem==NULL) // not enough memory
-return 1;
- posi__meme= posi__mem;
- posi__memee= (posi__mem_t*)((char*)posi__mem+siz);
- return 0;
- } // end posi_ini()
-
-static inline void posi_set(int64_t id,int32_t x,int32_t y) {
- // set geoposition for a specific object ID;
- // id: id of the object;
- // x,y: geocoordinates in 10^-7 degrees;
- if(posi__meme>=posi__memee) // not enough space in position array
- exit(70001);
- posi__meme->id= id;
- posi__meme->data[0]= x;
- posi__meme->data[1]= y;
- if (global_calccoords<0) {
- posi__meme->data[2]= x; // x_min
- posi__meme->data[3]= y; // y_min
- posi__meme->data[4]= x; // x_max
- posi__meme->data[5]= y; // y_max
- }
- posi__meme+= posi__mem_increment;
- } // end posi_set()
-
-static inline void posi_setbbox(int64_t id,int32_t x,int32_t y,
- int32_t xmin,int32_t ymin,int32_t xmax,int32_t ymax) {
- // same as posi_set(), however provide a bbox as well;
- // important: the caller must ensure that this module has been
- // initialized with global_calccoords= -1;
- if(posi__meme>=posi__memee) // not enough space in position array
- exit(70001);
- posi__meme->id= id;
- posi__meme->data[0]= x;
- posi__meme->data[1]= y;
- posi__meme->data[2]= xmin;
- posi__meme->data[3]= ymin;
- posi__meme->data[4]= xmax;
- posi__meme->data[5]= ymax;
- posi__meme+= posi__mem_increment;
- } // end posi_setbbox()
-
-static const int32_t posi_nil= 2000000000L;
-static int32_t* posi_xy= NULL; // position of latest read coordinates;
- // posi_xy[0]: x; posi_xy[1]: y;
- // posi_xy==NULL: no geoposition available for this id;
-
-static inline void posi_get(int64_t id) {
- // get the previously stored geopositions of an object;
- // id: id of the object;
- // return: posi_xy[0]: x; posi_xy[1]: y;
- // the caller may change the values for x and y;
- // posi_xy==NULL: no geoposition available for this id;
- // if this module has been initialized with global_calccoords
- // set to -1, the bbox addresses will be returned too:
- // posi_xy[2]: xmin; posi_xy[3]: ymin;
- // posi_xy[4]: xmax; posi_xy[5]: ymax;
- char* min,*max,*middle;
- int64_t middle_id;
-
- min= (char*)posi__mem;
- max= (char*)posi__meme;
- while(max>min) { // binary search
- middle= (((max-min-posi__mem_size)/2)&(posi__mem_mask))+min;
- middle_id= *(int64_t*)middle;
- if(middle_id==id) { // we found the right object
- posi_xy= (int32_t*)(middle+8);
-return;
- }
- if(middle_id>id)
- max= middle;
- else
- min= middle+posi__mem_size;
- } // binary search
- // here: did not find the geoposition of the object in question
- posi_xy= NULL;
- } // end posi_geti();
-
-//------------------------------------------------------------
-// end Module posi_ OSM position module
-//------------------------------------------------------------
-
-
-
-//------------------------------------------------------------
-// Module posr_ object ref temporary module
-//------------------------------------------------------------
-
-// this module provides procedures to use a temporary file for
-// storing relations' references when --all-to-nodes is used;
-// as usual, all identifiers of a module have the same prefix,
-// in this case 'posr'; an underline will follow for a global
-// accessible identifier, two underlines if the identifier
-// is not meant to be accessed from outside this module;
-// the sections of private and public definitions are separated
-// by a horizontal line: ----
-
-static char posr__filename[400]= "";
-static int posr__fd= -1; // file descriptor for temporary file
-#define posr__bufM 400000
-static int64_t posr__buf[posr__bufM],
- *posr__bufp,*posr__bufe,*posr__bufee;
- // buffer - used for write, and later for read;
-static bool posr__writemode; // buffer is used for writing
-
-static inline void posr__flush() {
- if(!posr__writemode || posr__bufp==posr__buf)
-return;
- UR(write(posr__fd,posr__buf,(char*)posr__bufp-(char*)posr__buf))
- posr__bufp= posr__buf;
- } // end posr__flush()
-
-static inline void posr__write(int64_t i) {
- // write an int64 to tempfile, use a buffer;
-//DPv(posr__write %lli,i)
- if(posr__bufp>=posr__bufee) posr__flush();
- *posr__bufp++= i;
- } // end posr__write()
-
-static void posr__end() {
- // clean-up for temporary file access;
- // will be called automatically at program end;
- if(posr__fd>2) {
- close(posr__fd);
- posr__fd= -1;
- }
- if(loglevel<2) unlink(posr__filename);
- } // end posr__end()
-
-//------------------------------------------------------------
-
-static int posr_ini(const char* filename) {
- // open a temporary file with the given name for random r/w access;
- // return: ==0: ok; !=0: error;
- strcpy(stpmcpy(posr__filename,filename,sizeof(posr__filename)-2),".2");
- if(posr__fd>=0) // file already open
-return 0; // ignore this call
- unlink(posr__filename);
- posr__fd= open(posr__filename,O_RDWR|O_CREAT|O_TRUNC|O_BINARY,00600);
- if(posr__fd<0) {
- PERRv("could not open temporary file: %.80s",posr__filename)
-return 1;
- }
- atexit(posr__end);
- posr__bufee= posr__buf+posr__bufM;
- posr__bufp= posr__bufe= posr__buf;
- posr__writemode= true;
- return 0;
- } // end posr_ini()
-
-static inline void posr_rel(int64_t relid,bool is_area) {
- // store the id of a relation in tempfile;
- // relid: id of this relation;
- // is_area: this relation describes an area;
- // otherwise: it describes a way;
- posr__write(0);
- posr__write(relid);
- posr__write(is_area);
- } // end posr_rel()
-
-static inline void posr_ref(int64_t refid) {
- // store the id of a reference in tempfile;
- posr__write(refid);
- } // end posr_ref()
-
-static int posr_rewind() {
- // rewind the file pointer;
- // return: ==0: ok; !=0: error;
- if(posr__writemode) {
- posr__flush(); posr__writemode= false; }
- if(lseek(posr__fd,0,SEEK_SET)<0) {
- PERRv("osmconvert Error: could not rewind temporary file %.80s",
- posr__filename)
-return 1;
- }
- posr__bufp= posr__bufe= posr__buf;
- return 0;
- } // end posr_rewind()
-
-static inline int posr_read(int64_t* ip) {
- // read one integer; meaning of the values of these integers:
- // every value is an interrelation reference id, with one exception:
- // integers which follow a 0-integer directly are relation ids;
- // return: ==0: ok; !=0: eof;
- int r,r2;
-
- if(posr__bufp>=posr__bufe) {
- r= read(posr__fd,posr__buf,sizeof(posr__buf));
- if(r<=0)
-return 1;
- posr__bufe= (int64_t*)((char*)posr__buf+r);
- if((r%8)!=0) { // odd number of bytes
- r2= read(posr__fd,posr__bufe,8-(r%8));
- // request the missing bytes
- if(r2<=0) // did not get the missing bytes
- posr__bufe= (int64_t*)((char*)posr__bufe-(r%8));
- else
- posr__bufe= (int64_t*)((char*)posr__bufe+r2);
- }
- posr__bufp= posr__buf;
- }
- *ip= *posr__bufp++;
- return 0;
- } // end posr_read()
-
-static void posr_processing(int* maxrewindp,int32_t** refxy) {
- // process temporary relation reference file;
- // the file must already have been written; this procedure
- // processes the interrelation references of this file and updates
- // the georeference table of module posi_ accordingly;
- // maxrewind: maximum number of rewinds;
- // refxy: memory space provided by the caller;
- // this is a temporarily used space for the coordinates
- // of the relations' members;
- // return:
- // maxrewind: <0: maximum number of rewinds was not sufficient;
- int changed;
- // number of relations whose flag has been changed, i.e.,
- // the recursive processing will continue;
- // if none of the relations' flags has been changed,
- // this procedure will end;
- int h; // counter for interrelational hierarchies
- int64_t relid; // relation id;
- int64_t refid; // interrelation reference id;
- bool jump_over; // jump over the presently processed relation
- int32_t* xy_rel; // geocoordinates of the processed relation;
- int32_t x_min,x_max,y_min,y_max;
- int32_t x_middle,y_middle,xy_distance,new_distance;
- int n; // number of referenced objects with coordinates
- int64_t temp64;
- bool is_area; // the relation describes an area
- int32_t** refxyp; // pointer in refxy array
- int r;
-
- h= 0; n=0;
- jump_over= true;
- relid= 0;
- while(*maxrewindp>=0) { // for every recursion
- changed= 0;
- if(posr_rewind()) // could not rewind
- break;
- for(;;) { // for every reference
- for(;;) { // get next id
- r= posr_read(&refid);
- if((r || refid==0) && n>0) { // (EOF OR new relation) AND
- // there have been coordinates for this relation
- x_middle= x_max/2+x_min/2;
- y_middle= (y_max+y_min)/2;
- // store the coordinates for this relation
-//DPv(is_area %i refxy %i,is_area,refxyp==refxy)
- if(global_calccoords<0) {
- xy_rel[2]= x_min;
- xy_rel[3]= y_min;
- xy_rel[4]= x_max;
- xy_rel[5]= y_max;
- }
- if(is_area || refxyp==refxy) {
- // take the center as position for this relation
- xy_rel[0]= x_middle;
- xy_rel[1]= y_middle;
- }
- else { // not an area
- int32_t x,y;
-
- // get the member position which is the nearest
- // to the center
- posi_xy= *--refxyp;
- x= posi_xy[0];
- y= posi_xy[1];
- xy_distance= abs(x-x_middle)+abs(y-y_middle);
- while(refxyp>refxy) {
- refxyp--;
- new_distance= abs(posi_xy[0]-x_middle)+
- abs(posi_xy[1]-y_middle);
- if(new_distance<xy_distance) {
- x= posi_xy[0];
- y= posi_xy[1];
- xy_distance= new_distance;
- }
- }
- xy_rel[0]= x;
- xy_rel[1]= y;
- } // not an area
- n= 0;
- changed++; // memorize that we calculated
- // at least one relation's position
- }
- if(r)
- goto rewind; // if at file end, rewind
- if(refid!=0)
- break;
- // here: a relation id will follow
- posr_read(&relid); // get the relation's id
- posr_read(&temp64); // get the relation's area flag
- is_area= temp64;
- posi_get(relid+global_otypeoffset20);
- // get the relation's geoposition
- xy_rel= posi_xy; // save address of relation's coordinate
- refxyp= refxy; // restart writing coordinate buffer
- jump_over= xy_rel==NULL || xy_rel[0]!=posi_nil;
- } // end get next id
- if(jump_over) // no element allocated for this very relation OR
- // position of this relation already known
- continue; // go on until next relation
- posi_get(refid); // get the reference's geoposition
- if(posi_xy==NULL || posi_xy[0]==posi_nil) {
- // position is unknown
- if(refid>global_otypeoffset15) { // refers to a relation
- n= 0; // ignore previously collected coordinates
- jump_over= true; // no yet able to determine the position
- }
- continue; // go on and examine next reference of this relation
- }
- *refxyp++= posi_xy; // store coordinate for reprocessing later
- if(n==0) { // first coordinate
- if(global_calccoords<0) {
- x_min = posi_xy[2];
- y_min = posi_xy[3];
- x_max = posi_xy[4];
- y_max = posi_xy[5];
- }
- else {
- // just store it as min and max
- x_min= x_max= posi_xy[0];
- y_min= y_max= posi_xy[1];
- }
- }
- else if(global_calccoords<0) {
- // adjust extrema
- if(posi_xy[2]<x_min && x_min-posi_xy[2]<900000000)
- x_min= posi_xy[2];
- else if(posi_xy[4]>x_max && posi_xy[4]-x_max<900000000)
- x_max= posi_xy[4];
- if(posi_xy[3]<y_min)
- y_min= posi_xy[3];
- else if(posi_xy[5]>y_max)
- y_max= posi_xy[5];
- }
- else { // additional coordinate
- // adjust extrema
- if(posi_xy[0]<x_min && x_min-posi_xy[0]<900000000)
- x_min= posi_xy[0];
- else if(posi_xy[0]>x_max && posi_xy[0]-x_max<900000000)
- x_max= posi_xy[0];
- if(posi_xy[1]<y_min)
- y_min= posi_xy[1];
- else if(posi_xy[1]>y_max)
- y_max= posi_xy[1];
- }
- n++;
- } // end for every reference
- rewind:
- if(loglevel>0) fprintf(stderr,
- "Interrelational hierarchy %i: %i dependencies.\n",++h,changed);
- if(changed==0) // no changes have been made in last recursion
- break; // end the processing
- (*maxrewindp)--;
- } // end for every recursion
- } // end posr_processing()
-
-//------------------------------------------------------------
-// end Module posr_ object ref temporary module
-//------------------------------------------------------------
-
-
-
-//------------------------------------------------------------
-// Module rr_ relref temporary module
-//------------------------------------------------------------
-
-// this module provides procedures to use a temporary file for
-// storing relation's references;
-// as usual, all identifiers of a module have the same prefix,
-// in this case 'rr'; an underline will follow in case of a
-// global accessible object, two underlines in case of objects
-// which are not meant to be accessed from outside this module;
-// the sections of private and public definitions are separated
-// by a horizontal line: ----
-
-static char rr__filename[400]= "";
-static int rr__fd= -1; // file descriptor for temporary file
-#define rr__bufM 400000
-static int64_t rr__buf[rr__bufM],*rr__bufp,*rr__bufe,*rr__bufee;
- // buffer - used for write, and later for read;
-static bool rr__writemode; // buffer is used for writing
-
-static inline void rr__flush() {
- if(!rr__writemode || rr__bufp==rr__buf)
-return;
- UR(write(rr__fd,rr__buf,(char*)rr__bufp-(char*)rr__buf))
- rr__bufp= rr__buf;
- } // end rr__flush()
-
-static inline void rr__write(int64_t i) {
- // write an int to tempfile, use a buffer;
- if(rr__bufp>=rr__bufee) rr__flush();
- *rr__bufp++= i;
- } // end rr__write()
-
-static void rr__end() {
- // clean-up for temporary file access;
- // will be called automatically at program end;
- if(rr__fd>2) {
- close(rr__fd);
- rr__fd= -1;
- }
- if(loglevel<2) unlink(rr__filename);
- } // end rr__end()
-
-//------------------------------------------------------------
-
-static int rr_ini(const char* filename) {
- // open a temporary file with the given name for random r/w access;
- // return: ==0: ok; !=0: error;
- strcpy(stpmcpy(rr__filename,filename,sizeof(rr__filename)-2),".0");
- if(rr__fd>=0) // file already open
-return 0; // ignore this call
- unlink(rr__filename);
- rr__fd= open(rr__filename,O_RDWR|O_CREAT|O_TRUNC|O_BINARY,00600);
- if(rr__fd<0) {
- fprintf(stderr,
- "osmconvert Error: could not open temporary file: %.80s\n",
- rr__filename);
-return 1;
- }
- atexit(rr__end);
- rr__bufee= rr__buf+rr__bufM;
- rr__bufp= rr__bufe= rr__buf;
- rr__writemode= true;
- return 0;
- } // end rr_ini()
-
-static inline void rr_rel(int64_t relid) {
- // store the id of a relation in tempfile;
- rr__write(0);
- rr__write(relid);
- } // end rr_rel()
-
-static inline void rr_ref(int64_t refid) {
- // store the id of an interrelation reference in tempfile;
- rr__write(refid);
- } // end rr_ref()
-
-static int rr_rewind() {
- // rewind the file pointer;
- // return: ==0: ok; !=0: error;
- if(rr__writemode) {
- rr__flush(); rr__writemode= false; }
- if(lseek(rr__fd,0,SEEK_SET)<0) {
- fprintf(stderr,"osmconvert Error: could not rewind temporary file"
- " %.80s\n",rr__filename);
-return 1;
- }
- rr__bufp= rr__bufe= rr__buf;
- return 0;
- } // end rr_rewind()
-
-static inline int rr_read(int64_t* ip) {
- // read one integer; meaning of the values of these integers:
- // every value is an interrelation reference id, with one exception:
- // integers which follow a 0-integer directly are relation ids;
- // note that we take 64-bit-integers although the number of relations
- // will never exceed 2^31; the reason is that Free OSM ("FOSM") uses
- // IDs > 2^16 for new data which adhere the cc-by-sa license;
- // return: ==0: ok; !=0: eof;
- int r,r2;
-
- if(rr__bufp>=rr__bufe) {
- r= read(rr__fd,rr__buf,sizeof(rr__buf));
- if(r<=0)
-return 1;
- rr__bufe= (int64_t*)((char*)rr__buf+r);
- if((r%8)!=0) { // odd number of bytes
- r2= read(rr__fd,rr__bufe,8-(r%8)); // request the missing bytes
- if(r2<=0) // did not get the missing bytes
- rr__bufe= (int64_t*)((char*)rr__bufe-(r%8));
- else
- rr__bufe= (int64_t*)((char*)rr__bufe+r2);
- }
- rr__bufp= rr__buf;
- }
- *ip= *rr__bufp++;
- return 0;
- } // end rr_read()
-
-//------------------------------------------------------------
-// end Module rr_ relref temporary module
-//------------------------------------------------------------
-
-
-
-//------------------------------------------------------------
-// Module cwn_ complete way ref temporary module
-//------------------------------------------------------------
-
-// this module provides procedures to use a temporary file for
-// storing a list of nodes which have to be marked as 'inside';
-// this is used if option --complete-ways is invoked;
-// as usual, all identifiers of a module have the same prefix,
-// in this case 'posi'; an underline will follow for a global
-// accessible identifier, two underlines if the identifier
-// is not meant to be accessed from outside this module;
-// the sections of private and public definitions are separated
-// by a horizontal line: ----
-
-static char cwn__filename[400]= "";
-static int cwn__fd= -1; // file descriptor for temporary file
-#define cwn__bufM 400000
-static int64_t cwn__buf[cwn__bufM],
- *cwn__bufp,*cwn__bufe,*cwn__bufee;
- // buffer - used for write, and later for read;
-static bool cwn__writemode; // buffer is used for writing
-
-static inline void cwn__flush() {
- if(!cwn__writemode || cwn__bufp==cwn__buf)
-return;
- UR(write(cwn__fd,cwn__buf,(char*)cwn__bufp-(char*)cwn__buf))
- cwn__bufp= cwn__buf;
- } // end cwn__flush()
-
-static inline void cwn__write(int64_t i) {
- // write an int64 to tempfile, use a buffer;
- if(cwn__bufp>=cwn__bufee) cwn__flush();
- *cwn__bufp++= i;
- } // end cwn__write()
-
-static void cwn__end() {
- // clean-up for temporary file access;
- // will be called automatically at program end;
- if(cwn__fd>2) {
- close(cwn__fd);
- cwn__fd= -1;
- }
- if(loglevel<2) unlink(cwn__filename);
- } // end cwn__end()
-
-//------------------------------------------------------------
-
-static int cwn_ini(const char* filename) {
- // open a temporary file with the given name for random r/w access;
- // return: ==0: ok; !=0: error;
- strcpy(stpmcpy(cwn__filename,filename,sizeof(cwn__filename)-2),".3");
- if(cwn__fd>=0) // file already open
-return 0; // ignore this call
- unlink(cwn__filename);
- cwn__fd= open(cwn__filename,O_RDWR|O_CREAT|O_TRUNC|O_BINARY,00600);
- if(cwn__fd<0) {
- PERRv("could not open temporary file: %.80s",cwn__filename)
-return 1;
- }
- atexit(cwn__end);
- cwn__bufee= cwn__buf+cwn__bufM;
- cwn__bufp= cwn__bufe= cwn__buf;
- cwn__writemode= true;
- return 0;
- } // end cwn_ini()
-
-static inline void cwn_ref(int64_t refid) {
- // store the id of a referenced node in tempfile;
- cwn__write(refid);
- } // end cwn_ref()
-
-static int cwn_rewind() {
- // rewind the file pointer;
- // return: ==0: ok; !=0: error;
- if(cwn__writemode) {
- cwn__flush(); cwn__writemode= false; }
- if(lseek(cwn__fd,0,SEEK_SET)<0) {
- PERRv("osmconvert Error: could not rewind temporary file %.80s",
- cwn__filename)
-return 1;
- }
- cwn__bufp= cwn__bufe= cwn__buf;
- return 0;
- } // end cwn_rewind()
-
-static inline int cwn_read(int64_t* ip) {
- // read the id of next referenced node;
- // return: ==0: ok; !=0: eof;
- int r,r2;
-
- if(cwn__bufp>=cwn__bufe) {
- r= read(cwn__fd,cwn__buf,sizeof(cwn__buf));
- if(r<=0)
-return 1;
- cwn__bufe= (int64_t*)((char*)cwn__buf+r);
- if((r%8)!=0) { // odd number of bytes
- r2= read(cwn__fd,cwn__bufe,8-(r%8));
- // request the missing bytes
- if(r2<=0) // did not get the missing bytes
- cwn__bufe= (int64_t*)((char*)cwn__bufe-(r%8));
- else
- cwn__bufe= (int64_t*)((char*)cwn__bufe+r2);
- }
- cwn__bufp= cwn__buf;
- }
- *ip= *cwn__bufp++;
- return 0;
- } // end cwn_read()
-
-static void cwn_processing() {
- // process temporary node reference file;
- // the file must already have been written; this procedure
- // sets the a flag in hash table (module hash_) for each node
- // which is referred to by an entry in the temporary file;
- int64_t id; // node id;
-
- if(cwn_rewind()) // could not rewind
-return;
- for(;;) { // get next id
- if(cwn_read(&id))
- break;
- hash_seti(0,id);
- }
- } // end cwn_processing()
-
-//------------------------------------------------------------
-// end Module cwn_ complete way ref temporary module
-//------------------------------------------------------------
-
-
-
-//------------------------------------------------------------
-// Module cww_ complex way ref temporary module
-//------------------------------------------------------------
-
-// this module provides procedures to use a temporary file for
-// storing a list of ways which have to be marked as 'inside';
-// this is used if option --complex-ways is invoked;
-// as usual, all identifiers of a module have the same prefix,
-// in this case 'posi'; an underline will follow for a global
-// accessible identifier, two underlines if the identifier
-// is not meant to be accessed from outside this module;
-// the sections of private and public definitions are separated
-// by a horizontal line: ----
-
-static char cww__filename[400]= "";
-static int cww__fd= -1; // file descriptor for temporary file
-#define cww__bufM 400000
-static int64_t cww__buf[cww__bufM],
- *cww__bufp,*cww__bufe,*cww__bufee;
- // buffer - used for write, and later for read;
-static bool cww__writemode; // buffer is used for writing
-
-static inline void cww__flush() {
- if(!cww__writemode || cww__bufp==cww__buf)
-return;
- UR(write(cww__fd,cww__buf,(char*)cww__bufp-(char*)cww__buf))
- cww__bufp= cww__buf;
- } // end cww__flush()
-
-static inline void cww__write(int64_t i) {
- // write an int64 to tempfile, use a buffer;
- if(cww__bufp>=cww__bufee) cww__flush();
- *cww__bufp++= i;
- } // end cww__write()
-
-static void cww__end() {
- // clean-up for temporary file access;
- // will be called automatically at program end;
- if(cww__fd>2) {
- close(cww__fd);
- cww__fd= -1;
- }
- if(loglevel<2) unlink(cww__filename);
- } // end cww__end()
-
-//------------------------------------------------------------
-
-static int cww_ini(const char* filename) {
- // open a temporary file with the given name for random r/w access;
- // return: ==0: ok; !=0: error;
- strcpy(stpmcpy(cww__filename,filename,sizeof(cww__filename)-2),".5");
- if(cww__fd>=0) // file already open
-return 0; // ignore this call
- unlink(cww__filename);
- cww__fd= open(cww__filename,O_RDWR|O_CREAT|O_TRUNC|O_BINARY,00600);
- if(cww__fd<0) {
- PERRv("could not open temporary file: %.80s",cww__filename)
-return 1;
- }
- atexit(cww__end);
- cww__bufee= cww__buf+cww__bufM;
- cww__bufp= cww__bufe= cww__buf;
- cww__writemode= true;
- return 0;
- } // end cww_ini()
-
-static inline void cww_ref(int64_t refid) {
- // store the id of a referenced way in tempfile;
- cww__write(refid);
- } // end cww_ref()
-
-static int cww_rewind() {
- // rewind the file pointer;
- // return: ==0: ok; !=0: error;
- if(cww__writemode) {
- cww__flush(); cww__writemode= false; }
- if(lseek(cww__fd,0,SEEK_SET)<0) {
- PERRv("osmconvert Error: could not rewind temporary file %.80s",
- cww__filename)
-return 1;
- }
- cww__bufp= cww__bufe= cww__buf;
- return 0;
- } // end cww_rewind()
-
-static inline int cww_read(int64_t* ip) {
- // read the id of next referenced node;
- // return: ==0: ok; !=0: eof;
- int r,r2;
-
- if(cww__bufp>=cww__bufe) {
- r= read(cww__fd,cww__buf,sizeof(cww__buf));
- if(r<=0)
-return 1;
- cww__bufe= (int64_t*)((char*)cww__buf+r);
- if((r%8)!=0) { // odd number of bytes
- r2= read(cww__fd,cww__bufe,8-(r%8));
- // request the missing bytes
- if(r2<=0) // did not get the missing bytes
- cww__bufe= (int64_t*)((char*)cww__bufe-(r%8));
- else
- cww__bufe= (int64_t*)((char*)cww__bufe+r2);
- }
- cww__bufp= cww__buf;
- }
- *ip= *cww__bufp++;
- return 0;
- } // end cww_read()
-
-static void cww_processing_set() {
- // process temporary way reference file;
- // the file must already have been written; this procedure
- // sets the a flag in hash table (module hash_) for each way
- // which is referred to by an entry in the temporary file;
- int64_t id; // way id;
-
- if(cww__filename[0]==0) // not initialized
-return;
- if(cww_rewind()) // could not rewind
-return;
- for(;;) { // get next id
- if(cww_read(&id))
- break;
- hash_seti(1,id);
- }
- } // end cww_processing_set()
-
-static void cww_processing_clear() {
- // process temporary way reference file;
- // the file must already have been written; this procedure
- // clears the a flag in hash table (module hash_) for each way
- // which is referred to by an entry in the temporary file;
- int64_t id; // way id;
-
- if(cww__filename[0]==0) // not initialized
-return;
- if(cww_rewind()) // could not rewind
-return;
- for(;;) { // get next id
- if(cww_read(&id))
- break;
- hash_cleari(1,id);
- }
- } // end cww_processing_clear()
-
-//------------------------------------------------------------
-// end Module cww_ complex way ref temporary module
-//------------------------------------------------------------
-
-
-
-//------------------------------------------------------------
-// Module o5_ o5m conversion module
-//------------------------------------------------------------
-
-// this module provides procedures which convert data to
-// o5m format;
-// as usual, all identifiers of a module have the same prefix,
-// in this case 'o5'; an underline will follow in case of a
-// global accessible object, two underlines in case of objects
-// which are not meant to be accessed from outside this module;
-// the sections of private and public definitions are separated
-// by a horizontal line: ----
-
-static inline void stw_reset();
-
-#define o5__bufM UINT64_C(5000000)
-static byte* o5__buf= NULL; // buffer for one object in .o5m format
-static byte* o5__bufe= NULL;
- // (const) water mark for buffer filled nearly 100%
-static byte* o5__bufp= NULL;
-static byte* o5__bufr0= NULL,*o5__bufr1= NULL;
- // start end end mark of a reference area in o5__buf[];
- // ==NULL: no mark set;
-
-// basis for delta coding
-static int64_t o5_id;
-static uint32_t o5_lat,o5_lon;
-static int64_t o5_cset;
-static int64_t o5_time;
-static int64_t o5_ref[3]; // for node, way, relation
-
-static inline void o5__resetvars() {
- // reset all delta coding counters;
- o5__bufp= o5__buf;
- o5__bufr0= o5__bufr1= o5__buf;
- o5_id= 0;
- o5_lat= o5_lon= 0;
- o5_cset= 0;
- o5_time= 0;
- o5_ref[0]= o5_ref[1]= o5_ref[2]= 0;
- stw_reset();
- } // end o5__resetvars()
-
-static void o5__end() {
- // clean-up for o5 module;
- // will be called at program's end;
- if(o5__buf!=NULL) {
- free(o5__buf); o5__buf= NULL; }
- } // end o5__end()
-
-//------------------------------------------------------------
-
-static inline void o5_reset() {
- // perform and write an o5m Reset;
- o5__resetvars();
- write_char(0xff); // write .o5m Reset
- } // end o5_reset()
-
-static int o5_ini() {
- // initialize this module;
- // must be called before any other procedure is called;
- // return: 0: everything went ok;
- // !=0: an error occurred;
- static bool firstrun= true;
-
- if(firstrun) {
- firstrun= false;
- o5__buf= (byte*)malloc(o5__bufM);
- if(o5__buf==NULL)
-return 1;
- atexit(o5__end);
- o5__bufe= o5__buf+o5__bufM-400000;
- }
- o5__resetvars();
- return 0;
- } // end o5_ini()
-
-static inline void o5_byte(byte b) {
- // write a single byte;
- // writing starts at position o5__bufp;
- // o5__bufp: incremented by 1;
- *o5__bufp++= b;
- } // end o5_byte()
-
-static inline int o5_str(const char* s) {
- // write a zero-terminated string;
- // writing starts at position o5__bufp;
- // return: bytes written;
- // o5__bufp: increased by the number of written bytes;
- byte* p0;
- byte c;
-
- p0= o5__bufp;
- if(o5__bufp>=o5__bufe) {
- static int msgn= 1;
- if(--msgn>=0) {
- fprintf(stderr,"osmconvert Error: .o5m memory overflow.\n");
-return 0;
- }
- }
- do *o5__bufp++= c= *s++;
- while(c!=0);
-return o5__bufp-p0;
- } // end o5_str()
-
-static inline int o5_uvar32buf(byte* p,uint32_t v) {
- // write an unsigned 32 bit integer as Varint into a buffer;
- // writing starts at position p;
- // return: bytes written;
- byte* p0;
- uint32_t frac;
-
- p0= p;
- frac= v&0x7f;
- if(frac==v) { // just one byte
- *p++= frac;
-return 1;
- }
- do {
- *p++= frac|0x80;
- v>>= 7;
- frac= v&0x7f;
- } while(frac!=v);
- *p++= frac;
-return p-p0;
- } // end o5_uvar32buf()
-
-static inline int o5_uvar32(uint32_t v) {
- // write an unsigned 32 bit integer as Varint;
- // writing starts at position o5__bufp;
- // return: bytes written;
- // o5__bufp: increased by the number of written bytes;
- byte* p0;
- uint32_t frac;
-
- if(o5__bufp>=o5__bufe) {
- static int msgn= 1;
- if(--msgn>=0) {
- fprintf(stderr,"osmconvert Error: .o5m memory overflow.\n");
-return 0;
- }
- }
- p0= o5__bufp;
- frac= v&0x7f;
- if(frac==v) { // just one byte
- *o5__bufp++= frac;
-return 1;
- }
- do {
- *o5__bufp++= frac|0x80;
- v>>= 7;
- frac= v&0x7f;
- } while(frac!=v);
- *o5__bufp++= frac;
-return o5__bufp-p0;
- } // end o5_uvar32()
-
-static inline int o5_svar32(int32_t v) {
- // write a signed 32 bit integer as signed Varint;
- // writing starts at position o5__bufp;
- // return: bytes written;
- // o5__bufp: increased by the number of written bytes;
- byte* p0;
- uint32_t u;
- uint32_t frac;
-
- if(o5__bufp>=o5__bufe) {
- static int msgn= 1;
- if(--msgn>=0) {
- fprintf(stderr,"osmconvert Error: .o5m memory overflow.\n");
-return 0;
- }
- }
- p0= o5__bufp;
- if(v<0) {
- u= -v;
- u= (u<<1)-1;
- }
- else
- u= v<<1;
- frac= u&0x7f;
- if(frac==u) { // just one byte
- *o5__bufp++= frac;
-return 1;
- }
- do {
- *o5__bufp++= frac|0x80;
- u>>= 7;
- frac= u&0x7f;
- } while(frac!=u);
- *o5__bufp++= frac;
-return o5__bufp-p0;
- } // end o5_svar32()
-
-static inline int o5_svar64(int64_t v) {
- // write a signed 64 bit integer as signed Varint;
- // writing starts at position o5__bufp;
- // return: bytes written;
- // o5__bufp: increased by the number of written bytes;
- byte* p0;
- uint64_t u;
- uint32_t frac;
-
- if(o5__bufp>=o5__bufe) {
- static int msgn= 1;
- if(--msgn>=0) {
- fprintf(stderr,"osmconvert Error: .o5m memory overflow.\n");
-return 0;
- }
- }
- p0= o5__bufp;
- if(v<0) {
- u= -v;
- u= (u<<1)-1;
- }
- else
- u= v<<1;
- frac= u&0x7f;
- if(frac==u) { // just one byte
- *o5__bufp++= frac;
-return 1;
- }
- do {
- *o5__bufp++= frac|0x80;
- u>>= 7;
- frac= u&0x7f;
- } while(frac!=u);
- *o5__bufp++= frac;
-return o5__bufp-p0;
- } // end o5_svar64()
-
-static inline void o5_markref(int pos) {
- // mark reference area;
- // pos: ==0: start; ==1: end;
- // 0 is accepted only once per dataset; only the first
- // request is valid;
- // 1 may be repeated, the last one counts;
- if(pos==0) {
- if(o5__bufr0==o5__buf) o5__bufr0= o5__bufp;
- }
- else
- o5__bufr1= o5__bufp;
- } // end o5_markref()
-
-static inline void o5_type(int type) {
- // mark object type we are going to process now;
- // should be called every time a new object is started to be
- // written into o5_buf[];
- // type: object type; 0: node; 1: way; 2: relation;
- // if object type has changed, a 0xff byte ("reset")
- // will be written;
- static int oldtype= -1;
-
- // process changes of object type
- if(type!=oldtype) { // object type has changed
- oldtype= type;
- o5_reset();
- }
- oldtype= type;
- } // end o5_type()
-
-static void o5_write() {
- // write o5__buf[] contents to standard output;
- // include object length information after byte 0 and include
- // ref area length information right before o5__bufr0 (if !=NULL);
- // if buffer is empty, this procedure does nothing;
- byte lens[30],reflens[30]; // lengths as pbf numbers
- int len; // object length
- int reflen; // reference area length
- int reflenslen; // length of pbf number of reflen
-
- // get some length information
- len= o5__bufp-o5__buf;
- if(len<=0) goto o5_write_end;
- reflen= 0; // (default)
- if(o5__bufr1<o5__bufr0) o5__bufr1= o5__bufr0;
- if(o5__bufr0>o5__buf) {
- // reference area contains at least 1 byte
- reflen= o5__bufr1-o5__bufr0;
- reflenslen= o5_uvar32buf(reflens,reflen);
- len+= reflenslen;
- } // end reference area contains at least 1 byte
-
- // write header
- if(--len>=0) {
- write_char(o5__buf[0]);
- write_mem(lens,o5_uvar32buf(lens,len));
- }
-
- // write body
- if(o5__bufr0<=o5__buf) // no reference area
- write_mem(o5__buf+1,o5__bufp-(o5__buf+1));
- else { // valid reference area
- write_mem(o5__buf+1,o5__bufr0-(o5__buf+1));
- write_mem(reflens,reflenslen);
- write_mem(o5__bufr0,o5__bufp-o5__bufr0);
- } // end valid reference area
-
- // reset buffer pointer
- o5_write_end:
- o5__bufp= o5__buf; // set original buffer pointer to buffer start
- o5__bufr0= o5__bufr1= o5__buf; // clear reference area marks
- } // end o5_write()
-
-//------------------------------------------------------------
-// end Module o5_ o5m conversion module
-//------------------------------------------------------------
-
-
-
-//------------------------------------------------------------
-// Module stw_ string write module
-//------------------------------------------------------------
-
-// this module provides procedures for conversions from
-// c formatted strings into referenced string data stream objects
-// - and writing it to buffered standard output;
-// as usual, all identifiers of a module have the same prefix,
-// in this case 'stw'; an underline will follow in case of a
-// global accessible object, two underlines in case of objects
-// which are not meant to be accessed from outside this module;
-// the sections of private and public definitions are separated
-// by a horizontal line: ----
-
-#define stw__tabM 15000
-#define stw__tabstrM 250 // must be < row size of stw__rab[]
-#define stw__hashtabM 150001 // (preferably a prime number)
-static char stw__tab[stw__tabM][256];
- // string table; see o5m documentation;
- // row length must be at least stw__tabstrM+2;
- // each row contains a double string; each of the two strings
- // is terminated by a zero byte, the lengths must not exceed
- // stw__tabstrM bytes in total;
-static int stw__tabi= 0;
- // index of last entered element in string table
-static int stw__hashtab[stw__hashtabM];
- // has table; elements point to matching strings in stw__tab[];
- // -1: no matching element;
-static int stw__tabprev[stw__tabM],stw__tabnext[stw__tabM];
- // for to chaining of string table rows which match
- // the same hash value; matching rows are chained in a loop;
- // if there is only one row matching, it will point to itself;
-static int stw__tabhash[stw__tabM];
- // has value of this element as a link back to the hash table;
- // a -1 element indicates that the string table entry is not used;
-
-static inline int stw__hash(const char* s1,const char* s2) {
- // get hash value of a string pair;
- // s2: ==NULL: single string; this is treated as s2=="";
- // return: hash value in the range 0..(stw__hashtabM-1);
- // -1: the strings are longer than stw__tabstrM characters in total;
- uint32_t h;
- uint32_t c;
- int len;
-
- #if 0 // not used because strings would not be transparent anymore
- if(*s1==(char)0xff) // string is marked as 'do-not-store';
-return -1;
- #endif
- len= stw__tabstrM;
- h= 0;
- for(;;) {
- if((c= *s1++)==0 || --len<0) break; h+= c;
- if((c= *s1++)==0 || --len<0) break; h+= c<<8;
- if((c= *s1++)==0 || --len<0) break; h+= c<<16;
- if((c= *s1++)==0 || --len<0) break; h+= c<<24;
- }
- if(s2!=NULL) for(;;) {
- if((c= *s2++)==0 || --len<0) break; h+= c;
- if((c= *s2++)==0 || --len<0) break; h+= c<<8;
- if((c= *s2++)==0 || --len<0) break; h+= c<<16;
- if((c= *s2++)==0 || --len<0) break; h+= c<<24;
- }
- if(len<0)
-return -1;
- h%= stw__hashtabM;
- return h;
- } // end stw__hash()
-
-static inline int stw__getref(int stri,const char* s1,const char* s2) {
- // get the string reference of a string pair;
- // the strings must not have more than 250 characters in total
- // (252 including terminators), there is no check in this procedure;
- // stri: presumed index in string table (we got it from hash table);
- // must be >=0 and <stw__tabM, there is no boundary check;
- // s2: ==NULL: it's not a string pair but a single string;
- // stw__hashnext[stri]: chain to further occurrences;
- // return: reference of the string;
- // ==-1: this string is not stored yet
- int strie; // index of last occurrence
- const char* sp,*tp;
- int ref;
-
- if(s2==NULL) s2="";
- strie= stri;
- do {
- // compare the string (pair) with the tab entry
- tp= stw__tab[stri];
- sp= s1;
- while(*tp==*sp && *tp!=0) { tp++; sp++; }
- if(*tp==0 && *sp==0) {
- // first string identical to first string in table
- tp++; // jump over first string terminator
- sp= s2;
- while(*tp==*sp && *tp!=0) { tp++; sp++; }
- if(*tp==0 && *sp==0) {
- // second string identical to second string in table
- ref= stw__tabi-stri;
- if(ref<=0) ref+= stw__tabM;
-return ref;
- }
- } // end first string identical to first string in table
- stri= stw__tabnext[stri];
- } while(stri!=strie);
- return -1;
- } // end stw__getref()
-
-//------------------------------------------------------------
-
-static inline void stw_reset() {
- // clear string table and string hash table;
- // must be called before any other procedure of this module
- // and may be called every time the string processing shall
- // be restarted;
- int i;
-
- stw__tabi= 0;
- i= stw__tabM;
- while(--i>=0) stw__tabhash[i]= -1;
- i= stw__hashtabM;
- while(--i>=0) stw__hashtab[i]= -1;
- } // end stw_reset()
-
-static void stw_write(const char* s1,const char* s2) {
- // write a string (pair), e.g. key/val, to o5m buffer;
- // if available, write a string reference instead of writing the
- // string pair directly;
- // no reference is used if the strings are longer than
- // 250 characters in total (252 including terminators);
- // s2: ==NULL: it's not a string pair but a single string;
- int h; // hash value
- int ref;
-
- /* try to find a matching string (pair) in string table */ {
- int i; // index in stw__tab[]
-
- ref= -1; // ref invalid (default)
- h= stw__hash(s1,s2);
- if(h>=0) { // string (pair) short enough for the string table
- i= stw__hashtab[h];
- if(i>=0) // string (pair) presumably stored already
- ref= stw__getref(i,s1,s2);
- } // end string (pair) short enough for the string table
- if(ref>=0) { // we found the string (pair) in the table
- o5_uvar32(ref); // write just the reference
-return;
- } // end we found the string (pair) in the table
- else { // we did not find the string (pair) in the table
- // write string data
- o5_byte(0); o5_str(s1);
- if(s2!=NULL) o5_str(s2); // string pair, not a single string
- if(h<0) // string (pair) too long,
- // cannot be stored in string table
-return;
- } // end we did not find the string (pair) in the table
- } // end try to find a matching string (pair) in string table
- // here: there is no matching string (pair) in the table
-
- /* free new element - if still being used */ {
- int h0; // hash value of old element
-
- h0= stw__tabhash[stw__tabi];
- if(h0>=0) { // new element in string table is still being used
- // delete old element
- if(stw__tabnext[stw__tabi]==stw__tabi)
- // self-chain, i.e., only this element
- stw__hashtab[h0]= -1; // invalidate link in hash table
- else { // one or more other elements in chain
- stw__hashtab[h0]= stw__tabnext[stw__tabi]; // just to ensure
- // that hash entry does not point to deleted element
- // now unchain deleted element
- stw__tabprev[stw__tabnext[stw__tabi]]= stw__tabprev[stw__tabi];
- stw__tabnext[stw__tabprev[stw__tabi]]= stw__tabnext[stw__tabi];
- } // end one or more other elements in chain
- } // end next element in string table is still being used
- } // end free new element - if still being used
-
- /* enter new string table element data */ {
- char* sp;
- int i;
-
- sp= stpcpy0(stw__tab[stw__tabi],s1)+1;
- // write first string into string table
- if(s2==NULL) // single string
- *sp= 0; // second string must be written as empty string
- // into string table
- else
- stpcpy0(sp,s2); // write second string into string table
- i= stw__hashtab[h];
- if(i<0) // no reference in hash table until now
- stw__tabprev[stw__tabi]= stw__tabnext[stw__tabi]= stw__tabi;
- // self-link the new element;
- else { // there is already a reference in hash table
- // in-chain the new element
- stw__tabnext[stw__tabi]= i;
- stw__tabprev[stw__tabi]= stw__tabprev[i];
- stw__tabnext[stw__tabprev[stw__tabi]]= stw__tabi;
- stw__tabprev[i]= stw__tabi;
- }
- stw__hashtab[h]= stw__tabi; // link the new element to hash table
- stw__tabhash[stw__tabi]= h; // backlink to hash table element
- // new element now in use; set index to oldest element
- if(++stw__tabi>=stw__tabM) { // index overflow
- stw__tabi= 0; // restart index
- if(loglevel>=2) {
- static int rs= 0;
- fprintf(stderr,
- "osmconvert: String table index restart %i\n",++rs);
- }
- } // end index overflow
- } // end enter new string table element data
- } // end stw_write()
-
-//------------------------------------------------------------
-// end Module stw_ string write module
-//------------------------------------------------------------
-
-
-
-//------------------------------------------------------------
-// Module str_ string read module
-//------------------------------------------------------------
-
-// this module provides procedures for conversions from
-// strings which have been stored in data stream objects to
-// c-formatted strings;
-// as usual, all identifiers of a module have the same prefix,
-// in this case 'str'; one underline will follow in case of a
-// global accessible object, two underlines in case of objects
-// which are not meant to be accessed from outside this module;
-// the sections of private and public definitions are separated
-// by a horizontal line: ----
-
-#define str__tabM (15000+4000)
- // +4000 because it might happen that an object has a lot of
- // key/val pairs or refroles which are not stored already;
-#define str__tabstrM 250 // must be < row size of str__rab[]
-typedef struct str__info_struct {
- // members of this structure must not be accessed
- // from outside this module;
- char tab[str__tabM][256];
- // string table; see o5m documentation;
- // row length must be at least str__tabstrM+2;
- // each row contains a double string; each of the two strings
- // is terminated by a zero byte, the logical lengths must not
- // exceed str__tabstrM bytes in total;
- // the first str__tabM lines of this array are used as
- // input buffer for strings;
- int tabi; // index of last entered element in string table;
- int tabn; // number of valid strings in string table;
- struct str__info_struct* prev; // address of previous unit;
- } str_info_t;
-str_info_t* str__infop= NULL;
-
-static void str__end() {
- // clean-up this module;
- str_info_t* p;
-
- while(str__infop!=NULL) {
- p= str__infop->prev;
- free(str__infop);
- str__infop= p;
- }
- } // end str__end()
-
-//------------------------------------------------------------
-
-static str_info_t* str_open() {
- // open an new string client unit;
- // this will allow us to process multiple o5m input files;
- // return: handle of the new unit;
- // ==NULL: error;
- // you do not need to care about closing the unit(s);
- static bool firstrun= true;
- str_info_t* prev;
-
- prev= str__infop;
- str__infop= (str_info_t*)malloc(sizeof(str_info_t));
- if(str__infop==NULL) {
- PERR("could not get memory for string buffer.")
-return NULL;
- }
- str__infop->tabi= 0;
- str__infop->tabn= 0;
- str__infop->prev= prev;
- if(firstrun) {
- firstrun= false;
- atexit(str__end);
- }
- return str__infop;
- } // end str_open()
-
-static inline void str_switch(str_info_t* sh) {
- // switch to another string unit
- // sh: string unit handle;
- str__infop= sh;
- } // end str_switch()
-
-static inline void str_reset() {
- // clear string table;
- // must be called before any other procedure of this module
- // and may be called every time the string processing shall
- // be restarted;
- if(str__infop!=NULL)
- str__infop->tabi= str__infop->tabn= 0;
- } // end str_reset()
-
-static void str_read(byte** pp,char** s1p,char** s2p) {
- // read an o5m formatted string (pair), e.g. key/val, from
- // standard input buffer;
- // if got a string reference, resolve it, using an internal
- // string table;
- // no reference is used if the strings are longer than
- // 250 characters in total (252 including terminators);
- // pp: address of a buffer pointer;
- // this pointer will be incremented by the number of bytes
- // the converted protobuf element consumes;
- // s2p: ==NULL: read not a string pair but a single string;
- // return:
- // *s1p,*s2p: pointers to the strings which have been read;
- char* p;
- int len1,len2;
- int ref;
- bool donotstore; // string has 'do not store flag' 2012-10-01
-
- p= (char*)*pp;
- if(*p==0) { // string (pair) given directly
- p++;
- donotstore= false;
- #if 0 // not used because strings would not be transparent anymore
- if(*p==(char)0xff) { // string has 'do-not-store' flag
- donotstore= true;
- p++;
- } // string has 'do-not-store' flag
- #endif
- *s1p= p;
- len1= strlen(p);
- p+= len1+1;
- if(s2p==NULL) { // single string
- if(!donotstore && len1<=str__tabstrM) {
- // single string short enough for string table
- stpcpy0(str__infop->tab[str__infop->tabi],*s1p)[1]= 0;
- // add a second terminator, just in case someone will try
- // to read this single string as a string pair later;
- if(++str__infop->tabi>=str__tabM) str__infop->tabi= 0;
- if(str__infop->tabn<str__tabM) str__infop->tabn++;
- } // end single string short enough for string table
- } // end single string
- else { // string pair
- *s2p= p;
- len2= strlen(p);
- p+= len2+1;
- if(!donotstore && len1+len2<=str__tabstrM) {
- // string pair short enough for string table
- memcpy(str__infop->tab[str__infop->tabi],*s1p,len1+len2+2);
- if(++str__infop->tabi>=str__tabM) str__infop->tabi= 0;
- if(str__infop->tabn<str__tabM) str__infop->tabn++;
- } // end string pair short enough for string table
- } // end string pair
- *pp= (byte*)p;
- } // end string (pair) given directly
- else { // string (pair) given by reference
- ref= pbf_uint32(pp);
- if(ref>str__infop->tabn) { // string reference invalid
- WARNv("invalid .o5m string reference: %i->%i",
- str__infop->tabn,ref)
- *s1p= "(invalid)";
- if(s2p!=NULL) // caller wants a string pair
- *s2p= "(invalid)";
- } // end string reference invalid
- else { // string reference valid
- ref= str__infop->tabi-ref;
- if(ref<0) ref+= str__tabM;
- *s1p= str__infop->tab[ref];
- if(s2p!=NULL) // caller wants a string pair
- *s2p= strchr(str__infop->tab[ref],0)+1;
- } // end string reference valid
- } // end string (pair) given by reference
- } // end str_read()
-
-//------------------------------------------------------------
-// end Module str_ string read module
-//------------------------------------------------------------
-
-
-
-//------------------------------------------------------------
-// Module wo_ write osm module
-//------------------------------------------------------------
-
-// this module provides procedures which write osm objects;
-// it uses procedures from module o5_;
-// as usual, all identifiers of a module have the same prefix,
-// in this case 'wo'; an underline will follow in case of a
-// global accessible object, two underlines in case of objects
-// which are not meant to be accessed from outside this module;
-// the sections of private and public definitions are separated
-// by a horizontal line: ----
-
-static int wo__format= 0; // output format;
- // 0: o5m; 11: native XML; 12: pbf2osm; 13: Osmosis; 14: Osmium;
- // 21: csv; -1: PBF;
-static bool wo__logaction= false; // write action for change files,
- // e.g. "<create>", "<delete>", etc.
-static char* wo__xmlclosetag= NULL; // close tag for XML output;
-static bool wo__xmlshorttag= false;
- // write the short tag ("/>") instead of the long tag;
-#define wo__CLOSE { /* close the newest written object; */ \
- if(wo__xmlclosetag!=NULL) { if(wo__xmlshorttag) write_str("\"/>"NL); \
- else write_str(wo__xmlclosetag); \
- wo__xmlclosetag= NULL; wo__xmlshorttag= false; } }
-#define wo__CONTINUE { /* continue an XML object */ \
- if(wo__xmlshorttag) { write_str("\">"NL); wo__xmlshorttag= false; \
- /* from now on: long close tag necessary; */ } }
-static int wo__lastaction= 0; // last action tag which has been set;
- // 0: no action tag; 1: "create"; 2: "modify"; 3: "delete";
- // this is used only in .osc files;
-
-static inline void wo__author(int32_t hisver,int64_t histime,
- int64_t hiscset,uint32_t hisuid,const char* hisuser) {
- // write osm object author;
- // must not be called if writing PBF format;
- // hisver: version; 0: no author is to be written
- // (necessary if o5m format);
- // histime: time (seconds since 1970)
- // hiscset: changeset
- // hisuid: uid
- // hisuser: user name
- // global_fakeauthor: the author contents will be faked that way
- // that the author data will be as short as
- // possible;
- // global fakeversion: same as global_fakeauthor, but for .osm
- // format: just the version will be written;
- // note that when writing o5m format, this procedure needs to be
- // called even if there is no author information to be written;
- // PBF and csv: this procedure is not called;
- if(global_fakeauthor|global_fakeversion) {
- hisver= 1; histime= 1; hiscset= 1; hisuid= 0; hisuser= "";
- }
- if(wo__format==0) { // o5m
- if(hisver==0 || global_dropversion) // no version number
- o5_byte(0x00);
- else { // version number available
- o5_uvar32(hisver);
- if(global_dropauthor) histime= 0;
- o5_svar64(histime-o5_time); o5_time= histime;
- if(histime!=0) {
- // author information available
- o5_svar64(hiscset-o5_cset); o5_cset= hiscset;
- if(hisuid==0 || hisuser==NULL || hisuser[0]==0)
- // user identification not available
- stw_write("","");
- else { // user identification available
- byte uidbuf[30];
-
- uidbuf[o5_uvar32buf(uidbuf,hisuid)]= 0;
- stw_write((const char*)uidbuf,hisuser);
- } // end user identification available
- } // end author information available
- } // end version number available
-return;
- } // end o5m
- // here: XML format
- if(global_fakeversion) {
- write_str("\" version=\"1");
-return;
- }
- if(hisver==0 || global_dropversion) // no version number
-return;
- switch(wo__format) { // depending on output format
- case 11: // native XML
- write_str("\" version=\""); write_uint32(hisver);
- if(histime!=0 && !global_dropauthor) {
- write_str("\" timestamp=\""); write_timestamp(histime);
- write_str("\" changeset=\""); write_uint64(hiscset);
- if(hisuid!=0 && hisuser[0]!=0) { // user information available
- write_str("\" uid=\""); write_uint32(hisuid);
- write_str("\" user=\""); write_xmlstr(hisuser);
- }
- }
- break;
- case 12: // pbf2osm XML
- write_str("\" version=\""); write_uint32(hisver);
- if(histime!=0 && !global_dropauthor) {
- write_str("\" changeset=\""); write_uint64(hiscset);
- if(hisuid!=0 && hisuser[0]!=0) { // user information available
- write_str("\" user=\""); write_xmlstr(hisuser);
- write_str("\" uid=\""); write_uint32(hisuid);
- }
- write_str("\" timestamp=\""); write_timestamp(histime);
- }
- break;
- case 13: // Osmosis XML
- write_str("\" version=\""); write_uint32(hisver);
- if(histime!=0 && !global_dropauthor) {
- write_str("\" timestamp=\""); write_timestamp(histime);
- if(hisuid!=0 && hisuser[0]!=0) { // user information available
- write_str("\" uid=\""); write_uint32(hisuid);
- write_str("\" user=\""); write_xmlmnstr(hisuser);
- }
- write_str("\" changeset=\""); write_uint64(hiscset);
- }
- break;
- case 14: // Osmium XML
- write_str("\" version=\""); write_uint32(hisver);
- if(histime!=0 && !global_dropauthor) {
- write_str("\" changeset=\""); write_uint64(hiscset);
- write_str("\" timestamp=\""); write_timestamp(histime);
- if(hisuid!=0 && hisuser[0]!=0) { // user information available
- write_str("\" uid=\""); write_uint32(hisuid);
- write_str("\" user=\""); write_xmlstr(hisuser);
- }
- }
- break;
- } // end depending on output format
- if(global_outosh) {
- if(wo__lastaction==3)
- write_str("\" visible=\"false");
- else
- write_str("\" visible=\"true");
- }
- } // end wo__author()
-
-static inline void wo__action(int action) {
- // set one of these action tags: "create", "modify", "delete";
- // write tags only if 'global_outosc' is true;
- // must only be called if writing XML format;
- // action: 0: no action tag; 1: "create"; 2: "modify"; 3: "delete";
- // caution: there is no check for validity of this parameter;
- static const char* starttag[]=
- {"","<create>"NL,"<modify>"NL,"<delete>"NL};
- static const char* endtag[]=
- {"","</create>"NL,"</modify>"NL,"</delete>"NL};
-
- if(global_outosc && action!=wo__lastaction) { // there was a change
- write_str(endtag[wo__lastaction]); // end last action
- write_str(starttag[action]); // start new action
- }
- wo__lastaction= action;
- } // end wo__action()
-
-//------------------------------------------------------------
-
-static void wo_start(int format,bool bboxvalid,
- int32_t x1,int32_t y1,int32_t x2,int32_t y2,int64_t timestamp) {
- // start writing osm objects;
- // format: 0: o5m; 11: native XML;
- // 12: pbf2osm; 13: Osmosis; 14: Osmium; 21:csv; -1: PBF;
- // bboxvalid: the following bbox coordinates are valid;
- // x1,y1,x2,y2: bbox coordinates (base 10^-7);
- // timestamp: file timestamp; ==0: no timestamp given;
- if(format<-1 || (format >0 && format<11) ||
- (format >14 && format<21) || format>21) format= 0;
- wo__format= format;
- wo__logaction= global_outosc || global_outosh;
- if(wo__format==0) { // o5m
- static const byte o5mfileheader[]= {0xff,0xe0,0x04,'o','5','m','2'};
- static const byte o5cfileheader[]= {0xff,0xe0,0x04,'o','5','c','2'};
-
- if(global_outo5c)
- write_mem(o5cfileheader,sizeof(o5cfileheader));
- else
- write_mem(o5mfileheader,sizeof(o5mfileheader));
- if(timestamp!=0) { // timestamp has been supplied
- o5_byte(0xdc); // timestamp
- o5_svar64(timestamp);
- o5_write(); // write this object
- }
- if(border_active) // borders are to be applied
- border_querybox(&x1,&y1,&x2,&y2);
- if(border_active || bboxvalid) {
- // borders are to be applied OR bbox has been supplied
- o5_byte(0xdb); // border box
- o5_svar32(x1); o5_svar32(y1);
- o5_svar32(x2); o5_svar32(y2);
- o5_write(); // write this object
- }
-return;
- } // end o5m
- if(wo__format<0) { // PBF
- if(border_active) // borders are to be applied
- border_querybox(&x1,&y1,&x2,&y2);
- bboxvalid= bboxvalid || border_active;
- pw_ini();
- pw_header(bboxvalid,x1,y1,x2,y2,timestamp);
-return;
- }
- if(wo__format==21) { // csv
- csv_headline();
-return;
- }
- // here: XML
- if(wo__format!=14)
- write_str("<?xml version=\'1.0\' encoding=\'UTF-8\'?>"NL);
- else // Osmium XML
- write_str("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"NL);
- if(global_outosc)
- write_str("<osmChange version=\"0.6\"");
- else
- write_str("<osm version=\"0.6\"");
- switch(wo__format) { // depending on output format
- case 11: // native XML
- write_str(" generator=\"osmconvert "VERSION"\"");
- break;
- case 12: // pbf2osm XML
- write_str(" generator=\"pbf2osm\"");
- break;
- case 13: // Osmosis XML
- write_str(" generator=\"Osmosis 0.40\"");
- break;
- case 14: // Osmium XML
- write_str(" generator="
- "\"Osmium (http://wiki.openstreetmap.org/wiki/Osmium)\"");
- break;
- } // end depending on output format
- if(timestamp!=0) {
- write_str(" timestamp=\""); write_timestamp(timestamp);
- write_char('\"');
- }
- write_str(">"NL);
- if(wo__format!=12) { // bbox may be written
- if(border_active) // borders are to be applied
- border_querybox(&x1,&y1,&x2,&y2);
- if(border_active || bboxvalid) { // borders are to be applied OR
- // bbox has been supplied
- if(wo__format==13) { // Osmosis
- // <bound box="53.80000,10.50000,54.00000,10.60000"
- // origin="0.40.1"/>
- write_str(" <bound box=\""); write_sfix7(y1);
- write_str(","); write_sfix7(x1);
- write_str(","); write_sfix7(y2);
- write_str(","); write_sfix7(x2);
- write_str("\" origin=\"0.40\"/>"NL);
- } // Osmosis
- else { // not Osmosis
- // <bounds minlat="53.8" minlon="10.5" maxlat="54."
- // maxlon="10.6"/>
- write_str("\t<bounds minlat=\""); write_sfix7(y1);
- write_str("\" minlon=\""); write_sfix7(x1);
- write_str("\" maxlat=\""); write_sfix7(y2);
- write_str("\" maxlon=\""); write_sfix7(x2);
- write_str("\"/>"NL);
- } // not Osmosis
- }
- } // end bbox may be written
- } // end wo_start()
-
-static void wo_end() {
- // end writing osm objects;
- switch(wo__format) { // depending on output format
- case 0: // o5m
- o5_write(); // write last object - if any
- write_char(0xfe); // write o5m eof indicator
- break;
- case 11: // native XML
- case 12: // pbf2osm XML
- case 13: // Osmosis XML
- case 14: // Osmium XML
- wo__CLOSE
- wo__action(0);
- write_str(global_outosc? "</osmChange>"NL: "</osm>"NL);
- if(wo__format>=12)
- write_str("<!--End of emulated output.-->"NL);
- break;
- case 21: // csv
- csv_write();
- // (just in case the last object has not been terminated)
- break;
- case -1: // PBF
- pw_foot();
- break;
- } // end depending on output format
- } // end wo_end()
-
-static inline void wo_flush() {
- // write temporarily stored object information;
- if(wo__format==0) // o5m
- o5_write(); // write last object - if any
- else if(wo__format<0) // PBF format
- pw_flush();
- else if(wo__format==21) // csv
- csv_write();
- else // any XML output format
- wo__CLOSE
- write_flush();
- } // end wo_flush()
-
-static int wo_format(int format) {
- // get or change output format;
- // format: -9: return the currently used format, do not change it;
- if(format==-9) // do not change the format
-return wo__format;
- wo_flush();
- if(format<-1 || (format >0 && format<11) ||
- (format >14 && format<21) || format>21) format= 0;
- wo__format= format;
- wo__logaction= global_outosc || global_outosh;
- return wo__format;
- } // end wo_format()
-
-static inline void wo_reset() {
- // in case of o5m format, write a Reset;
- // note that this is done automatically at every change of
- // object type; this procedure offers to write additional Resets
- // at every time you want;
- if(wo__format==0)
- o5_reset();
- } // end wo_reset()
-
-static inline void wo_node(int64_t id,
- int32_t hisver,int64_t histime,int64_t hiscset,
- uint32_t hisuid,const char* hisuser,int32_t lon,int32_t lat) {
- // write osm node body;
- // id: id of this object;
- // hisver: version; 0: no author information is to be written
- // (necessary if o5m format);
- // histime: time (seconds since 1970)
- // hiscset: changeset
- // hisuid: uid
- // hisuser: user name
- // lon: latitude in 100 nanodegree;
- // lat: latitude in 100 nanodegree;
- if(wo__format==0) { // o5m
- o5_write(); // write last object - if any
- o5_type(0);
- o5_byte(0x10); // data set id for node
- o5_svar64(id-o5_id); o5_id= id;
- wo__author(hisver,histime,hiscset,hisuid,hisuser);
- o5_svar32(lon-o5_lon); o5_lon= lon;
- o5_svar32(lat-o5_lat); o5_lat= lat;
-return;
- } // end o5m
- if(wo__format<0) { // PBF
- pw_node(id,hisver,histime,hiscset,hisuid,hisuser,lon,lat);
-return;
- }
- if(wo__format==21) { // csv
- char s[25];
-
- if(csv_key_otype)
- csv_add("@otype","0");
- if(csv_key_oname)
- csv_add("@oname",ONAME(0));
- if(csv_key_id) {
- int64toa(id,s);
- csv_add("@id",s);
- }
- if(csv_key_version) {
- uint32toa(hisver,s);
- csv_add("@version",s);
- }
- if(csv_key_timestamp) {
- write_createtimestamp(histime,s);
- csv_add("@timestamp",s);
- }
- if(csv_key_changeset) {
- int64toa(hiscset,s);
- csv_add("@changeset",s);
- }
- if(csv_key_uid) {
- uint32toa(hisuid,s);
- csv_add("@uid",s);
- }
- if(csv_key_user)
- csv_add("@user",hisuser);
- if(csv_key_lon) {
- write_createsfix7o(lon,s);
- csv_add("@lon",s);
- }
- if(csv_key_lat) {
- write_createsfix7o(lat,s);
- csv_add("@lat",s);
- }
-return;
- }
- // here: XML format
- wo__CLOSE
- if(wo__logaction)
- wo__action(hisver==1? 1: 2);
- switch(wo__format) { // depending on output format
- case 11: // native XML
- write_str("\t<node id=\""); write_sint64(id);
- write_str("\" lat=\""); write_sfix7(lat);
- write_str("\" lon=\""); write_sfix7(lon);
- wo__author(hisver,histime,hiscset,hisuid,hisuser);
- wo__xmlclosetag= "\t</node>"NL; // preset close tag
- break;
- case 12: // pbf2osm XML
- write_str("\t<node id=\""); write_sint64(id);
- write_str("\" lat=\""); write_sfix7o(lat);
- write_str("\" lon=\""); write_sfix7o(lon);
- wo__author(hisver,histime,hiscset,hisuid,hisuser);
- wo__xmlclosetag= "\t</node>"NL; // preset close tag
- break;
- case 13: // Osmosis XML
- write_str(" <node id=\""); write_sint64(id);
- wo__author(hisver,histime,hiscset,hisuid,hisuser);
- write_str("\" lat=\""); write_sfix7(lat);
- write_str("\" lon=\""); write_sfix7(lon);
- wo__xmlclosetag= " </node>"NL; // preset close tag
- break;
- case 14: // Osmium XML
- write_str(" <node id=\""); write_sint64(id);
- wo__author(hisver,histime,hiscset,hisuid,hisuser);
- if(lon>=0) lon= (lon+5)/10;
- else lon= (lon-5)/10;
- if(lat>=0) lat= (lat+5)/10;
- else lat= (lat-5)/10;
- write_str("\" lon=\""); write_sfix6o(lon);
- write_str("\" lat=\""); write_sfix6o(lat);
- wo__xmlclosetag= " </node>"NL; // preset close tag
- break;
- } // end depending on output format
- wo__xmlshorttag= true; // (default)
- } // end wo_node()
-
-static inline void wo_node_close() {
- // complete writing an OSM node;
- if(wo__format<0)
- pw_node_close();
- else if(wo__format==21)
- csv_write();
- } // end wo_node_close()
-
-static inline void wo_way(int64_t id,
- int32_t hisver,int64_t histime,int64_t hiscset,
- uint32_t hisuid,const char* hisuser) {
- // write osm way body;
- // id: id of this object;
- // hisver: version; 0: no author information is to be written
- // (necessary if o5m format);
- // histime: time (seconds since 1970)
- // hiscset: changeset
- // hisuid: uid
- // hisuser: user name
- if(wo__format==0) { // o5m
- o5_write(); // write last object - if any
- o5_type(1);
- o5_byte(0x11); // data set id for way
- o5_svar64(id-o5_id); o5_id= id;
- wo__author(hisver,histime,hiscset,hisuid,hisuser);
- o5_markref(0);
-return;
- } // end o5m
- if(wo__format<0) { // PBF
- pw_way(id,hisver,histime,hiscset,hisuid,hisuser);
-return;
- }
- if(wo__format==21) { // csv
- char s[25];
-
- if(csv_key_otype)
- csv_add("@otype","1");
- if(csv_key_oname)
- csv_add("@oname",ONAME(1));
- if(csv_key_id) {
- int64toa(id,s);
- csv_add("@id",s);
- }
- if(csv_key_version) {
- uint32toa(hisver,s);
- csv_add("@version",s);
- }
- if(csv_key_timestamp) {
- write_createtimestamp(histime,s);
- csv_add("@timestamp",s);
- }
- if(csv_key_changeset) {
- int64toa(hiscset,s);
- csv_add("@changeset",s);
- }
- if(csv_key_uid) {
- uint32toa(hisuid,s);
- csv_add("@uid",s);
- }
- if(csv_key_user)
- csv_add("@user",hisuser);
-return;
- }
- // here: XML format
- wo__CLOSE
- if(wo__logaction)
- wo__action(hisver==1? 1: 2);
- switch(wo__format) { // depending on output format
- case 11: // native XML
- write_str("\t<way id=\""); write_sint64(id);
- wo__author(hisver,histime,hiscset,hisuid,hisuser);
- wo__xmlclosetag= "\t</way>"NL; // preset close tag
- break;
- case 12: // pbf2osm XML
- write_str("\t<way id=\""); write_sint64(id);
- wo__author(hisver,histime,hiscset,hisuid,hisuser);
- wo__xmlclosetag= "\t</way>"NL; // preset close tag
- break;
- case 13: // Osmosis XML
- case 14: // Osmium XML
- write_str(" <way id=\""); write_sint64(id);
- wo__author(hisver,histime,hiscset,hisuid,hisuser);
- wo__xmlclosetag= " </way>"NL; // preset close tag
- break;
- } // end depending on output format
- wo__xmlshorttag= true; // (default)
- } // end wo_way()
-
-static inline void wo_way_close() {
- // complete writing an OSM way;
- if(wo__format<0)
- pw_way_close();
- else if(wo__format==21)
- csv_write();
- } // end wo_way_close()
-
-static inline void wo_relation(int64_t id,
- int32_t hisver,int64_t histime,int64_t hiscset,
- uint32_t hisuid,const char* hisuser) {
- // write osm relation body;
- // id: id of this object;
- // hisver: version; 0: no author information is to be written
- // (necessary if o5m format);
- // histime: time (seconds since 1970)
- // hiscset: changeset
- // hisuid: uid
- // hisuser: user name
- if(wo__format==0) { // o5m
- o5_write(); // write last object - if any
- o5_type(2);
- o5_byte(0x12); // data set id for relation
- o5_svar64(id-o5_id); o5_id= id;
- wo__author(hisver,histime,hiscset,hisuid,hisuser);
- o5_markref(0);
-return;
- } // end o5m
- if(wo__format<0) { // PBF
- pw_relation(id,hisver,histime,hiscset,hisuid,hisuser);
-return;
- }
- if(wo__format==21) { // csv
- char s[25];
-
- if(csv_key_otype)
- csv_add("@otype","2");
- if(csv_key_oname)
- csv_add("@oname",ONAME(2));
- if(csv_key_id) {
- int64toa(id,s);
- csv_add("@id",s);
- }
- if(csv_key_version) {
- uint32toa(hisver,s);
- csv_add("@version",s);
- }
- if(csv_key_timestamp) {
- write_createtimestamp(histime,s);
- csv_add("@timestamp",s);
- }
- if(csv_key_changeset) {
- int64toa(hiscset,s);
- csv_add("@changeset",s);
- }
- if(csv_key_uid) {
- uint32toa(hisuid,s);
- csv_add("@uid",s);
- }
- if(csv_key_user)
- csv_add("@user",hisuser);
-return;
- }
- // here: XML format
- wo__CLOSE
- if(wo__logaction)
- wo__action(hisver==1? 1: 2);
- switch(wo__format) { // depending on output format
- case 11: // native XML
- write_str("\t<relation id=\""); write_sint64(id);
- wo__author(hisver,histime,hiscset,hisuid,hisuser);
- wo__xmlclosetag= "\t</relation>"NL; // preset close tag
- break;
- case 12: // pbf2osm XML
- write_str("\t<relation id=\""); write_sint64(id);
- wo__author(hisver,histime,hiscset,hisuid,hisuser);
- wo__xmlclosetag= "\t</relation>"NL; // preset close tag
- break;
- case 13: // Osmosis XML
- case 14: // Osmium XML
- write_str(" <relation id=\""); write_sint64(id);
- wo__author(hisver,histime,hiscset,hisuid,hisuser);
- wo__xmlclosetag= " </relation>"NL; // preset close tag
- break;
- } // end depending on output format
- wo__xmlshorttag= true; // (default)
- } // end wo_relation()
-
-static inline void wo_relation_close() {
- // complete writing an OSM relation;
- if(wo__format<0)
- pw_relation_close();
- else if(wo__format==21)
- csv_write();
- } // end wo_relation_close()
-
-static void wo_delete(int otype,int64_t id,
- int32_t hisver,int64_t histime,int64_t hiscset,
- uint32_t hisuid,const char* hisuser) {
- // write osm delete request;
- // this is possible for o5m format only;
- // for any other output format, this procedure does nothing;
- // otype: 0: node; 1: way; 2: relation;
- // id: id of this object;
- // hisver: version; 0: no author informaton is to be written
- // (necessary if o5m format);
- // histime: time (seconds since 1970)
- // hiscset: changeset
- // hisuid: uid
- // hisuser: user name
- if(otype<0 || otype>2 || wo__format<0)
-return;
- if(wo__format==0) { // o5m (.o5c)
- o5_write(); // write last object - if any
- o5_type(otype);
- o5_byte(0x10+otype); // data set id
- o5_svar64(id-o5_id); o5_id= id;
- wo__author(hisver,histime,hiscset,hisuid,hisuser);
- } // end o5m (.o5c)
- else { // .osm (.osc)
- wo__CLOSE
- if(wo__logaction)
- wo__action(3);
- if(wo__format>=13) write_str(" <"); else write_str("\t<");
- write_str(ONAME(otype));
- write_str(" id=\""); write_sint64(id);
- if(global_fakelonlat)
- write_str("\" lat=\"0\" lon=\"0");
- wo__author(hisver,histime,hiscset,hisuid,hisuser);
- wo__xmlclosetag= "\"/>"NL; // preset close tag
- wo__xmlshorttag= false; // (default)
- wo__CLOSE // write close tag
- } // end .osm (.osc)
- } // end wo_delete()
-
-static inline void wo_noderef(int64_t noderef) {
- // write osm object node reference;
- if(wo__format==0) { // o5m
- o5_svar64(noderef-o5_ref[0]); o5_ref[0]= noderef;
- o5_markref(1);
-return;
- } // end o5m
- if(wo__format<0) { // PBF
- pw_way_ref(noderef);
-return;
- }
- if(wo__format==21) // csv
-return;
- // here: XML format
- wo__CONTINUE
- switch(wo__format) { // depending on output format
- case 11: // native XML
- case 12: // pbf2osm XML
- write_str("\t\t<nd ref=\""); write_sint64(noderef);
- write_str("\"/>"NL);
- break;
- case 13: // Osmosis XML
- case 14: // Osmium XML
- write_str(" <nd ref=\""); write_sint64(noderef);
- write_str("\"/>"NL);
- break;
- } // end depending on output format
- } // end wo_noderef()
-
-static inline void wo_ref(int64_t refid,int reftype,
- const char* refrole) {
- // write osm object reference;
- if(wo__format==0) { // o5m
- char o5typerole[4000];
-
- o5_svar64(refid-o5_ref[reftype]); o5_ref[reftype]= refid;
- o5typerole[0]= reftype+'0';
- strmcpy(o5typerole+1,refrole,sizeof(o5typerole)-1);
- stw_write(o5typerole,NULL);
- o5_markref(1);
-return;
- } // end o5m
- if(wo__format<0) { // PBF
- pw_relation_ref(refid,reftype,refrole);
-return;
- }
- if(wo__format==21) // csv
-return;
- // here: XML format
- wo__CONTINUE
- switch(wo__format) { // depending on output format
- case 11: // native XML
- case 12: // pbf2osm XML
- if(reftype==0)
- write_str("\t\t<member type=\"node\" ref=\"");
- else if(reftype==1)
- write_str("\t\t<member type=\"way\" ref=\"");
- else
- write_str("\t\t<member type=\"relation\" ref=\"");
- write_sint64(refid);
- write_str("\" role=\""); write_xmlstr(refrole);
- write_str("\"/>"NL);
- break;
- case 13: // Osmosis XML
- case 14: // Osmium XML
- if(reftype==0)
- write_str(" <member type=\"node\" ref=\"");
- else if(reftype==1)
- write_str(" <member type=\"way\" ref=\"");
- else
- write_str(" <member type=\"relation\" ref=\"");
- write_sint64(refid);
- write_str("\" role=\""); write_xmlmnstr(refrole);
- write_str("\"/>"NL);
- break;
- } // end depending on output format
- } // end wo_ref()
-
-static inline void wo_node_keyval(const char* key,const char* val) {
- // write an OSM node object's keyval;
- if(wo__format==0) { // o5m
- #if 0 // not used because strings would not be transparent anymore
- if(key[1]=='B' && strcmp(key,"bBox")==0 && strchr(val,',')!=0)
- // value is assumed to be dynamic, hence it should not be
- // stored in string list;
- // mark string pair as 'do-not-store';
- key= "\xff""bBox"; // 2012-10-14
- #endif
- stw_write(key,val);
-return;
- } // end o5m
- if(wo__format<0) { // PBF
- pw_node_keyval(key,val);
-return;
- }
- if(wo__format==21) { // csv
- csv_add(key,val);
-return;
- }
- // here: XML format
- wo__CONTINUE
- switch(wo__format) { // depending on output format
- case 11: // native XML
- write_str("\t\t<tag k=\""); write_xmlstr(key);
- write_str("\" v=\"");
-write_xmlstr(val);
- write_str("\"/>"NL);
- break;
- case 12: // pbf2osm XML
- write_str("\t\t<tag k=\""); write_xmlstr(key);
- write_str("\" v=\""); write_xmlstr(val);
- write_str("\" />"NL);
- break;
- case 13: // Osmosis XML
- case 14: // Osmium XML
- write_str(" <tag k=\""); write_xmlmnstr(key);
- write_str("\" v=\""); write_xmlmnstr(val);
- write_str("\"/>"NL);
- break;
- } // end depending on output format
- } // end wo_node_keyval()
-
-static inline void wo_wayrel_keyval(const char* key,const char* val) {
- // write an OSM way or relation object's keyval;
- if(wo__format==0) { // o5m
- stw_write(key,val);
-return;
- } // end o5m
- if(wo__format<0) { // PBF
- pw_wayrel_keyval(key,val);
-return;
- }
- if(wo__format==21) { // csv
- csv_add(key,val);
-return;
- }
- // here: XML format
- wo__CONTINUE
- switch(wo__format) { // depending on output format
- case 11: // native XML
- write_str("\t\t<tag k=\""); write_xmlstr(key);
- write_str("\" v=\"");
-write_xmlstr(val);
- write_str("\"/>"NL);
- break;
- case 12: // pbf2osm XML
- write_str("\t\t<tag k=\""); write_xmlstr(key);
- write_str("\" v=\""); write_xmlstr(val);
- write_str("\" />"NL);
- break;
- case 13: // Osmosis XML
- case 14: // Osmium XML
- write_str(" <tag k=\""); write_xmlmnstr(key);
- write_str("\" v=\""); write_xmlmnstr(val);
- write_str("\"/>"NL);
- break;
- } // end depending on output format
- } // end wo_wayrel_keyval()
-
-
-static inline void wo_addbboxtags(bool fornode,
- int32_t x_min, int32_t y_min,int32_t x_max, int32_t y_max) {
- // adds tags for bbox and box area if requested by
- // global_addbbox, global_addbboxarea resp. global_addbboxweight;
- // fornode: add the tag(s) to a node, not to way/rel;
- char s[84],*sp;
- int64_t area;
-
- if(global_addbbox) { // add bbox tags
- sp= s;
- sp= write_createsfix7o(x_min,sp);
- *sp++= ',';
- sp= write_createsfix7o(y_min,sp);
- *sp++= ',';
- sp= write_createsfix7o(x_max,sp);
- *sp++= ',';
- sp= write_createsfix7o(y_max,sp);
- if(fornode)
- wo_node_keyval("bBox",s);
- else
- wo_wayrel_keyval("bBox",s);
- } // add bbox tags
- if(global_addbboxarea|global_addbboxweight) {
- // add bbox area tags OR add bbox weight tags
- area= (int64_t)(x_max-x_min)*(int64_t)(y_max-y_min)/
- cosrk((y_min+y_max)/2);
- if(global_addbboxarea) { // add bbox area tags
- write_createsint64(area,s);
- if(fornode)
- wo_node_keyval("bBoxArea",s);
- else
- wo_wayrel_keyval("bBoxArea",s);
- } // add bbox area tags
- if(global_addbboxweight) { // add bbox weight tags
- write_createsint64(msbit(area),s);
- if(fornode)
- wo_node_keyval("bBoxWeight",s);
- else
- wo_wayrel_keyval("bBoxWeight",s);
- } // add bbox weight tags
- } // add bbox area tags OR add bbox weight tags
- } // end wo_addbboxtags()
-
-//------------------------------------------------------------
-// end Module wo_ write osm module
-//------------------------------------------------------------
-
-
-
-//------------------------------------------------------------
-// Module oo_ osm to osm module
-//------------------------------------------------------------
-
-// this module provides procedures which read osm objects,
-// process them and write them as osm objects, using module wo_;
-// that goes for .osm format as well as for .o5m format;
-// as usual, all identifiers of a module have the same prefix,
-// in this case 'oo'; an underline will follow in case of a
-// global accessible object, two underlines in case of objects
-// which are not meant to be accessed from outside this module;
-// the sections of private and public definitions are separated
-// by a horizontal line: ----
-
-static void oo__rrprocessing(int* maxrewindp) {
- // process temporary relation reference file;
- // the file must have been written; this procedure processes
- // the interrelation references of this file and updates
- // the hash table of module hash_ accordingly;
- // maxrewind: maximum number of rewinds;
- // return:
- // maxrewind: <0: maximum number of rewinds was not sufficient;
- int changed;
- // number of relations whose flag has been changed, i.e.,
- // the recursive processing will continue;
- // if none of the relations' flags has been changed,
- // this procedure will end;
- int h;
- int64_t relid; // relation id;
- int64_t refid; // interrelation reference id;
- bool flag;
-
- h= 0;
- relid= 0; flag= false;
- while(*maxrewindp>=0) { // for every recursion
- changed= 0;
- if(rr_rewind()) // could not rewind
- break;
- for(;;) { // for every reference
- for(;;) { // get next id
- if(rr_read(&refid))
- goto rewind; // if at file end, rewind
- if(refid!=0)
- break;
- // here: a relation id will follow
- rr_read(&relid); // get the relation id
- flag= hash_geti(2,relid); // get the related flag
- } // end get next id
- if(flag) // flag already set
- continue; // go on until next relation
- if(!hash_geti(2,refid)) // flag of reference is not set
- continue; // go on and examine next reference of this relation
- hash_seti(2,relid); // set flag of this relation
- flag= true;
- changed++; // memorize that we changed a flag
- } // end for every reference
- rewind:
- if(loglevel>0) fprintf(stderr,
- "Interrelational hierarchy %i: %i dependencies.\n",++h,changed);
- if(changed==0) // no changes have been made in last recursion
- break; // end the processing
- (*maxrewindp)--;
- } // end for every recursion
- } // end oo__rrprocessing()
-
-static byte oo__whitespace[]= {
- 0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0, // HT LF VT FF CR
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // SPC
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
-#define oo__ws(c) (oo__whitespace[(byte)(c)])
-static byte oo__whitespacenul[]= {
- 1,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0, // NUL HT LF VT FF CR
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, // SPC /
- 0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0, // <
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
-#define oo__wsnul(c) (oo__whitespacenul[(byte)(c)])
-static byte oo__letter[]= {
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,
- 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
-#define oo__le(c) (oo__letter[(byte)(c)])
-
-static const uint8_t* oo__hexnumber= (uint8_t*)
- // convert a hex character to a number
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x00\x00\x00\x00\x00\x00"
- "\x00\x0a\x0b\x0c\x0d\x0e\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x0a\x0b\x0c\x0d\x0e\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
-
-static inline uint32_t oo__strtouint32(const char* s) {
- // read a number and convert it to an unsigned 32-bit integer;
- // return: number;
- int32_t i;
- byte b;
-
- i= 0;
- for(;;) {
- b= (byte)(*s++ -'0');
- if(b>=10)
- break;
- i= i*10+b;
- }
- return i;
- } // end oo__strtouint32()
-
-#if 0 // presently unused
-static inline int32_t oo__strtosint32(const char* s) {
- // read a number and convert it to a signed 64-bit integer;
- // return: number;
- int sign;
- int32_t i;
- byte b;
-
- if(*s=='-') { s++; sign= -1; } else sign= 1;
- i= 0;
- for(;;) {
- b= (byte)(*s++ -'0');
- if(b>=10)
- break;
- i= i*10+b;
- }
- return i*sign;
- } // end oo__strtosint32()
-#endif
-
-static inline int64_t oo__strtosint64(const char* s) {
- // read a number and convert it to a signed 64-bit integer;
- // return: number;
- int sign;
- int64_t i;
- byte b;
-
- if(*s=='-') { s++; sign= -1; } else sign= 1;
- i= 0;
- for(;;) {
- b= (byte)(*s++ -'0');
- if(b>=10)
- break;
- i= i*10+b;
- }
- return i*sign;
- } // end oo__strtosint64()
-
-static const int32_t oo__nildeg= 2000000000L;
-
-static inline int32_t oo__strtodeg(char* s) {
- // read a number which represents a degree value and
- // convert it to a fixpoint number;
- // s[]: string with the number between -180 and 180,
- // e.g. "-179.99", "11", ".222";
- // return: number in 10 millionth degrees;
- // =='oo__nildeg': syntax error;
- static const long di[]= {10000000L,10000000L,1000000L,100000L,
- 10000L,1000L,100L,10L,1L};
- static const long* dig= di+1;
- int sign;
- int d; // position of decimal digit;
- long k;
- char c;
-
- if(*s=='-') { s++; sign= -1; } else sign= 1;
- if(!isdig(*s) && *s!='.')
-return border__nil;
- k= 0;
- d= -1;
- do { // for every digit
- c= *s++;
- if(c=='.') { d= 0; continue; } // start fractional part
- else if(!isdig(c) || c==0)
- break;
- k= k*10+c-'0';
- if(d>=0) d++;
- } while(d<7); // end for every digit
- k*= dig[d]*sign;
- return k;
- } // end oo__strtodeg()
-
-static inline int64_t oo__strtimetosint64(const char* s) {
- // read a timestamp in OSM format, e.g.: "2010-09-30T19:23:30Z",
- // and convert it to a signed 64-bit integer;
- // also allowed: relative time to NOW, e.g.: "NOW-86400",
- // which means '24 hours ago';
- // return: time as a number (seconds since 1970);
- // ==0: syntax error;
- if(s[0]=='N') { // presumably a relative time to 'now'
- if(s[1]!='O' || s[2]!='W' || (s[3]!='+' && s[3]!='-') ||
- !isdig(s[4])) // wrong syntax
-return 0;
- s+= 3; // jump over "NOW"
- if(*s=='+') s++; // jump over '+', if any
-return time(NULL)+oo__strtosint64(s);
- } // presumably a relative time to 'now'
- if((s[0]!='1' && s[0]!='2') ||
- !isdig(s[1]) || !isdig(s[2]) || !isdig(s[3]) ||
- s[4]!='-' || !isdig(s[5]) || !isdig(s[6]) ||
- s[7]!='-' || !isdig(s[8]) || !isdig(s[9]) ||
- s[10]!='T' || !isdig(s[11]) || !isdig(s[12]) ||
- s[13]!=':' || !isdig(s[14]) || !isdig(s[15]) ||
- s[16]!=':' || !isdig(s[17]) || !isdig(s[18]) ||
- s[19]!='Z') // wrong syntax
-return 0;
- /* regular timestamp */ {
- struct tm tm;
-
- tm.tm_isdst= 0;
- tm.tm_year=
- (s[0]-'0')*1000+(s[1]-'0')*100+(s[2]-'0')*10+(s[3]-'0')-1900;
- tm.tm_mon= (s[5]-'0')*10+s[6]-'0'-1;
- tm.tm_mday= (s[8]-'0')*10+s[9]-'0';
- tm.tm_hour= (s[11]-'0')*10+s[12]-'0';
- tm.tm_min= (s[14]-'0')*10+s[15]-'0';
- tm.tm_sec= (s[17]-'0')*10+s[18]-'0';
- #if __WIN32__
- // use replcement for timegm() because Windows does not know it
- #if 0
- if(original_timezone==&original_timezone_none) {
- original_timezone= getenv("TZ");
- putenv("TZ=");
- tzset();
- }
- #endif
- //DPv(timezone %lli,timezone)
-return mktime(&tm)-timezone;
- #else
-return timegm(&tm);
- #endif
- } // regular timestamp
- } // end oo__strtimetosint64()
-
-static inline void oo__xmltostr(char* s) {
- // read an xml string and convert is into a regular UTF-8 string,
- // for example: "Mayer&apos;s" -> "Mayer's";
- char* t; // pointer in overlapping target string
- char c;
- uint32_t u;
-
- for(;;) { // for all characters, until first '&' or string end;
- c= *s;
- if(c==0) // no character to convert
-return;
- if(c=='&')
- break;
- s++;
- }
- t= s;
- for(;;) { // for all characters after the first '&'
- c= *s++;
- if(c==0) // at the end of string
- break;
- if(c!='&') {
- *t++= c;
- continue;
- }
- c= *s;
- if(c=='#') { // numeric value
- c= *++s;
- if(c=='x') { // hex value
- s++;
- u= 0;
- for(;;) {
- c= *s++;
- if(c==';' || c==0)
- break;
- u= (u<<4)+oo__hexnumber[(byte)c];
- }
- } // end hex value
- else { // decimal value
- u= 0;
- for(;;) {
- c= *s++;
- if(c==';' || c==0)
- break;
- u= u*10+c-'0';
- }
- } // end decimal value
- if(u<128) // 1 byte sufficient
- *t++= (char)u;
- else if(u<2048) { // 2 bytes sufficient
- *t++= (u>>6)|0xc0; *t++= (u&0x3f)|0x80; }
- else if(u<65536) { // 3 bytes sufficient
- *t++= (u>>12)|0xe0; *t++= ((u>>6)&0x3f)|0x80;
- *t++= (u&0x3f)|0x80; }
- else { // 4 bytes necessary
- *t++= ((u>>18)&0x07)|0xf0; *t++= ((u>>12)&0x3f)|0x80;
- *t++= ((u>>6)&0x3f)|0x80; *t++= (u&0x3f)|0x80; }
- } // end numeric value
- else if(strzcmp(s,"quot;")==0) {
- s+= 5; *t++= '\"'; }
- else if(strzcmp(s,"apos;")==0) {
- s+= 5; *t++= '\''; }
- else if(strzcmp(s,"amp;")==0) {
- s+= 4; *t++= '&'; }
- else if(strzcmp(s,"lt;")==0) {
- s+= 3; *t++= '<'; }
- else if(strzcmp(s,"gt;")==0) {
- s+= 3; *t++= '>'; }
- else { // unknown escape code
- *t++= '&';
- }
- } // end for all characters after the first '&'
- *t= 0; // terminate target string
- //fprintf(stderr,"Z %s\n",s0);sleep(1);//,,
- } // end oo__xmltostr()
-
-static bool oo__xmlheadtag; // currently, we are inside an xml start tag,
- // maybe a short tag, e.g. <node ... > or <node ... />
- // (the second example is a so-called short tag)
-static char* oo__xmlkey,*oo__xmlval; // return values of oo__xmltag
-
-static inline bool oo__xmltag() {
- // read the next xml key/val and return them both;
- // due to performance reasons, global and module global variables
- // are used;
- // read_bufp: address at which the reading begins;
- // oo__xmlheadtag: see above;
- // return: no more xml keys/vals to read inside the outer xml tag;
- // oo__xmlkey,oo__xmlval: newest xml key/val which have been read;
- // "","": encountered the end of an
- // enclosed xml tag;
- char xmldelim;
- char c;
-
- for(;;) { // until break
- while(!oo__wsnul(*read_bufp)) read_bufp++;
- // find next whitespace or null character or '/'
- while(oo__ws(*read_bufp)) read_bufp++;
- // find first character after the whitespace(s)
- c= *read_bufp;
- if(c==0) {
- oo__xmlkey= oo__xmlval= "";
-return true;
- }
- else if(c=='/') {
- oo__xmlkey= oo__xmlval= "";
- c= *++read_bufp;
- read_bufp++;
- if(c=='>') { // short tag ends here
- if(oo__xmlheadtag) {
- // this ending short tag is the object's tag
- oo__xmlheadtag= false;
-return true;
- }
-return false;
- } // end short tag ands here
- continue;
- }
- else if(c=='<') {
- oo__xmlheadtag= false;
- if(*++read_bufp=='/' && (
- (c= *++read_bufp)=='n' || c=='w' || c=='r') ) {
- // this has been long tag which is ending now
- while(!oo__wsnul(*read_bufp)) read_bufp++;
- // find next whitespace
- oo__xmlkey= oo__xmlval= "";
-return true;
- }
- continue;
- }
- oo__xmlkey= (char*)read_bufp;
- while(oo__le(*read_bufp)) read_bufp++;
- if(*read_bufp!='=') {
- oo__xmlkey= "";
- continue;
- }
- *read_bufp++= 0;
- if(*read_bufp!='\"' && *read_bufp!='\'')
- continue;
- xmldelim= (char)*read_bufp;
- oo__xmlval= (char*)(++read_bufp);
- for(;;) {
- c= *read_bufp;
- if(c==xmldelim)
- break;
- if(c==0) {
- oo__xmlkey= oo__xmlval= "";
-return true;
- }
- read_bufp++;
- }
- *read_bufp++= 0;
- break;
- } // end until break
- oo__xmltostr(oo__xmlkey);
- oo__xmltostr(oo__xmlval);
- return false;
- } // end oo__xmltag()
-
-static int oo__error= 0; // error number which will be returned when
- // oo_main() terminates normal;
-typedef struct {
- read_info_t* ri; // file handle for input files
- read_info_t* riph; // file handle for input files;
- // this is a copy of .ri because it may be necessary to reaccess
- // a file which has already been logically closed;
- // used by the procedures oo__rewind() and oo__closeall();
- int format; // input file format;
- // ==-9: unknown; ==0: o5m; ==10: xml; ==-1: pbf;
- str_info_t* str; // string unit handle (if o5m format)
- uint64_t tyid; // type/id of last read osm object of this file
- uint32_t hisver; // OSM object version; needed for creating diff file
- const char* filename;
- bool endoffile;
- int deleteobject; // replacement for .osc <delete> tag
- // 0: not to delete; 1: delete this object; 2: delete from now on;
- int deleteobjectjump; // same as before but as save value for jumps
- // 0: not to delete; 1: delete this object; 2: delete from now on;
- bool subtract; // this file is to be subtracted, i.e., the
- // meaning of 'deleteobject' will be treated inversely;
- int64_t o5id; // for o5m delta coding
- int32_t o5lon,o5lat; // for o5m delta coding
- int64_t o5histime; // for o5m delta coding
- int64_t o5hiscset; // for o5m delta coding
- int64_t o5rid[3]; // for o5m delta coding
- } oo__if_t;
-static oo__if_t oo__if[global_fileM];
-static oo__if_t* oo__ifp= oo__if; // currently used element in oo__if[]
-#define oo__ifI (oo__ifp-oo__if) // index
-static oo__if_t* oo__ife= oo__if; // logical end of elements in oo__if[]
-static oo__if_t* oo__ifee= oo__if+global_fileM;
- // physical end of oo_if[]
-static int oo_ifn= 0; // number of currently open files
-
-static bool oo__bbvalid= false;
- // the following bbox coordinates are valid;
-static int32_t oo__bbx1= 0,oo__bby1= 0,oo__bbx2= 0,oo__bby2= 0;
- // bbox coordinates (base 10^-7) of the first input file;
-static int64_t oo__timestamp= 0;
- // file timestamp of the last input file which has a timestamp;
- // ==0: no file timestamp given;
-static bool oo__alreadyhavepbfobject= false;
-
-static void oo__mergebbox(int32_t bbx1,int32_t bby1,
- int32_t bbx2,int32_t bby2) {
- // merge new bbox coordinates to existing ones;
- // if there are no bbox coordinates at present,
- // just store the new coordinates;
- // bbx1 .. bby2: border box coordinates to merge;
- // return:
- // oo__bbvalid: following border box information is valid;
- // oo__bbx1 .. oo__bby2: border box coordinates;
-
- if(!oo__bbvalid) { // not yet any bbox stored
- // just store the new coordinates as bbox
- oo__bbx1= bbx1;
- oo__bby1= bby1;
- oo__bbx2= bbx2;
- oo__bby2= bby2;
- oo__bbvalid= true;
- } // not yet any bbox stored
- else { // there is already a bbox
- // merge the new coordinates with the existing bbox
- if(bbx1<oo__bbx1) oo__bbx1= bbx1;
- if(bby1<oo__bby1) oo__bby1= bby1;
- if(bbx2>oo__bbx2) oo__bbx2= bbx2;
- if(bby2>oo__bby2) oo__bby2= bby2;
- } // there is already a bbox
- } // oo__mergebbox()
-
-static void oo__findbb() {
- // find timestamp and border box in input file;
- // return:
- // oo__bbvalid: following border box information is valid;
- // oo__bbx1 .. oo__bby2: border box coordinates;
- // read_bufp will not be changed;
- byte* bufp,*bufe,*bufe1;
- int32_t bbx1= 0,bby1= 0,bbx2= 0,bby2= 0;
- // bbox coordinates (base 10^-7)
-
- bbx1= bby1= bbx2= bby2= 0;
- read_input();
- bufp= read_bufp; bufe= read_bufe;
- if(oo__ifp->format==0) { // o5m
- byte b; // latest byte which has been read
- int l;
-
- while(bufp<bufe) { // for all bytes
- b= *bufp;
- if(b==0 || (b>=0x10 && b<=0x12)) // regular dataset id
-return;
- if(b>=0xf0) { // single byte dataset
- bufp++;
- continue;
- } // end single byte dataset
- // here: non-object multibyte dataset
- if(b==0xdc) { // timestamp
- bufp++;
- l= pbf_uint32(&bufp);
- bufe1= bufp+l; if(bufe1>=bufe) bufe1= bufe;
- if(bufp<bufe1) oo__timestamp= pbf_sint64(&bufp);
- bufp= bufe1;
- continue;
- } // timestamp
- if(b==0xdb) { // border box
- bufp++;
- l= pbf_uint32(&bufp);
- bufe1= bufp+l; if(bufe1>=bufe) bufe1= bufe;
- if(bufp<bufe1) bbx1= pbf_sint32(&bufp);
- if(bufp<bufe1) bby1= pbf_sint32(&bufp);
- if(bufp<bufe1) bbx2= pbf_sint32(&bufp);
- if(bufp<bufe1) {
- bby2= pbf_sint32(&bufp);
- oo__mergebbox(bbx1,bby1,bbx2,bby2);
- }
- bufp= bufe1;
- continue;
- } // border box
- bufp++;
- l= pbf_uint32(&bufp); // jump over this dataset
- bufp+= l; // jump over this dataset
- } // end for all bytes
- } // end o5m
- else if(oo__ifp->format>0) { // osm xml
- char* sp;
- char c1,c2,c3; // next available characters
-
- while(bufp<bufe) { // for all bytes
- sp= strchr((char*)bufp,'<');
- if(sp==NULL)
- break;
- c1= sp[1]; c2= sp[2]; c3= sp[3];
- if(c1=='n' && c2=='o' && c3=='d')
-return;
- else if(c1=='w' && c2=='a' && c3=='y')
-return;
- else if(c1=='r' && c2=='e' && c3=='l')
-return;
- else if(c1=='o' && c2=='s' && c3=='m') {
- // "<osm"
- // timestamp must be supplied in this format:
- // <osm version="0.6" generator="OpenStreetMap planet.c"
- // timestamp="2010-08-18T00:11:04Z">
- int l;
- char c;
-
- sp++; // jump over '<'
- if(strzcmp(sp,"osmAugmentedDiff")==0)
- global_mergeversions= true;
- for(;;) { // jump over "osm ", "osmChange ", "osmAugmentedDiff"
- c= *sp;
- if(oo__wsnul(c))
- break;
- sp++;
- }
- for(;;) { // for every word in 'osm'
- c= *sp;
- if(c=='/' || c=='<' || c=='>' || c==0)
- break;
- if(oo__ws(c)) {
- sp++;
- continue;
- }
- if((l= strzlcmp(sp,"timestamp="))>0 &&
- (sp[10]=='\"' || sp[10]=='\'') && isdig(sp[11])) {
- sp+= l+1;
- oo__timestamp= oo__strtimetosint64(sp);
- }
- for(;;) { // find next whitespace or '<'
- c= *sp;
- if(oo__wsnul(c))
- break;
- sp++;
- }
- } // end for every word in 'osm'
- bufp++;
- continue;
- } // "<osm"
- else if(c1=='b' && c2=='o' && c3=='u') { // bounds
- // bounds may be supplied in one of these formats:
- // <bounds minlat="53.01104" minlon="8.481593"
- // maxlat="53.61092" maxlon="8.990601"/>
- // <bound box="49.10868,6.35017,49.64072,7.40979"
- // origin="http://www.openstreetmap.org/api/0.6"/>
- uint32_t bboxcomplete; // flags for bbx1 .. bby2
- int l;
- char c;
-
- bboxcomplete= 0;
- sp++; // jump over '<'
- for(;;) { // jump over "bounds ", resp. "bound "
- c= *sp;
- if(oo__wsnul(c))
- break;
- sp++;
- }
- for(;;) { // for every word in 'bounds'
- c= *sp;
- if(c=='/' || c=='<' || c=='>' || c==0)
- break;
- if(oo__ws(c) || c==',') {
- sp++;
- continue;
- }
- if((l= strzlcmp(sp,"box=\""))>0 ||
- (l= strzlcmp(sp,"box=\'"))>0) {
- sp+= l;
- c= *sp;
- }
- if((l= strzlcmp(sp,"minlat=\""))>0 ||
- (l= strzlcmp(sp,"minlat=\'"))>0 ||
- ((isdig(c) || c=='-' || c=='.') && (bboxcomplete&2)==0)) {
- sp+= l;
- bby1= oo__strtodeg(sp);
- if(bby1!=oo__nildeg) bboxcomplete|= 2;
- }
- else if((l= strzlcmp(sp,"minlon=\""))>0 ||
- (l= strzlcmp(sp,"minlon=\'"))>0 ||
- ((isdig(c) || c=='-' || c=='.') && (bboxcomplete&1)==0)) {
- sp+= l;
- bbx1= oo__strtodeg(sp);
- if(bbx1!=oo__nildeg) bboxcomplete|= 1;
- }
- else if((l= strzlcmp(sp,"maxlat=\""))>0 ||
- (l= strzlcmp(sp,"maxlat=\'"))>0 ||
- ((isdig(c) || c=='-' || c=='.') && (bboxcomplete&8)==0)) {
- sp+= l;
- bby2= oo__strtodeg(sp);
- if(bby2!=oo__nildeg) bboxcomplete|= 8;
- }
- else if((l= strzlcmp(sp,"maxlon=\""))>0 ||
- (l= strzlcmp(sp,"maxlon=\'"))>0 ||
- ((isdig(c) || c=='-' || c=='.') && (bboxcomplete&4)==0)) {
- sp+= l;
- bbx2= oo__strtodeg(sp);
- if(bbx2!=oo__nildeg) bboxcomplete|= 4;
- }
- for(;;) { // find next blank or comma
- c= *sp;
- if(oo__wsnul(c) || c==',')
- break;
- sp++;
- }
- } // end for every word in 'bounds'
- if(bboxcomplete==15)
- oo__mergebbox(bbx1,bby1,bbx2,bby2);
- bufp++;
- continue;
- } // bounds
- else {
- bufp++;
- continue;
- }
- } // end for all bytes of the file
- } // end osm xml
- else if(oo__ifp->format==-1) { // pbf
- //pb_input();
- if(pb_type==8) { // pbf header
- if(pb_bbvalid)
- oo__mergebbox(pb_bbx1,pb_bby1,pb_bbx2,pb_bby2);
- if(pb_filetimestamp!=0)
- oo__timestamp= pb_filetimestamp;
- } // end pbf header
- else
- oo__alreadyhavepbfobject= true;
- } // end pbf
- } // end oo__findbb()
-
-static inline int oo__gettyid() {
- // get tyid of the next object in the currently processed input file;
- // tyid is a combination of object type and id: we take the id and
- // add UINT64_C(0x0800000000000000) for nodes,
- // UINT64_C(0x1800000000000000) for ways, and
- // UINT64_C(0x2800000000000000) for relations;
- // if global_diff is set, besides tyid the hisver is retrieved too;
- // oo__ifp: handle of the currently processed input file;
- // return: ==0: ok; !=0: could not get tyid because starting object
- // is not an osm object;
- // oo__ifp->tyid: tyid of the starting osm object;
- // if there is not an osm object starting at
- // read_bufp, *iyidp remains unchanged;
- // oo__ifp->hisver: only if global_diff; version of next object;
- static const uint64_t idoffset[]= {UINT64_C(0x0800000000000000),
- UINT64_C(0x1800000000000000),UINT64_C(0x2800000000000000),
- 0,0,0,0,0,0,0,0,0,0,0,0,0,UINT64_C(0x0800000000000000),
- UINT64_C(0x1800000000000000),UINT64_C(0x2800000000000000)};
- int format;
-
- format= oo__ifp->format;
- if(format==0) { // o5m
- int64_t o5id;
- byte* p,b;
- int l;
-
- o5id= oo__ifp->o5id;
- p= read_bufp;
- while(p<read_bufe) {
- b= *p++;
- if(b>=0x10 && b<=0x12) { // osm object is starting here
- oo__ifp->tyid= idoffset[b];
- pbf_intjump(&p); // jump over length information
- oo__ifp->tyid+= o5id+pbf_sint64(&p);
- if(global_diff)
- oo__ifp->hisver= pbf_uint32(&p);
-return 0;
- }
- if(b>=0xf0) { // single byte
- if(b==0xff) // this is an o5m Reset object
- o5id= 0;
- continue;
- }
- // here: unknown o5m object
- l= pbf_uint32(&p); // get length of this object
- p+= l; // jump over this object;
- }
-return 1;
- }
- else if(format>0) { // 10: osm xml
- char* s;
- uint64_t r;
-
- s= (char*)read_bufp;
- for(;;) { // for every byte in XML object
- while(*s!='<' && *s!=0) s++;
- if(*s==0)
- break;
- s++;
- if(*s=='n' && s[1]=='o') r= UINT64_C(0x0800000000000000);
- else if(*s=='w'&& s[1]=='a') r= UINT64_C(0x1800000000000000);
- else if(*s=='r'&& s[1]=='e') r= UINT64_C(0x2800000000000000);
- else
- continue;
- do {
- s++;
- if(*s==0)
- break;
- } while(*s!=' ');
- while(*s==' ') s++;
- if(s[0]=='i' && s[1]=='d' && s[2]=='=' &&
- (s[3]=='\"' || s[3]=='\'')) { // found id
- oo__ifp->tyid= r+oo__strtosint64(s+4);
- if(!global_diff)
-return 0;
- oo__ifp->hisver= 0;
- for(;;) {
- if(*s=='>' || *s==0)
-return 0;
- if(s[0]==' ' && s[1]=='v' && s[2]=='e' && s[3]=='r' &&
- s[4]=='s' && s[5]=='i' && s[6]=='o' && s[7]=='n' &&
- s[8]=='=' && (s[9]=='\"' || s[9]=='\'') && isdig(s[10])) {
- // found version
- oo__ifp->hisver= oo__strtouint32(s+10);
-return 0;
- }
- s++;
- }
-return 0;
- } // end found id
- } // end for every byte in XML object
-return 1;
- }
- else if(format==-1) { // pbf
- while(pb_type>2) { // not an OSM object
- pb_input(false);
- oo__alreadyhavepbfobject= true;
- }
- if((pb_type & 3)!=pb_type) // still not an osm object
-return 1;
- oo__ifp->tyid= idoffset[pb_type]+pb_id;
- oo__ifp->hisver= pb_hisver;
-return 0;
- }
-return 2; // (unknown format)
- } // end oo__gettyid()
-
-static inline int oo__getformat() {
- // determine the formats of all opened files of unknown format
- // and store these determined formats;
- // do some intitialization for the format, of necessary;
- // oo__if[].format: !=-9: do nothing for this file;
- // return: 0: ok; !=0: error;
- // 5: too many pbf files;
- // this is, because the module pbf (see above)
- // does not have multi-client capabilities;
- // oo__if[].format: input file format; ==0: o5m; ==10: xml; ==-1: pbf;
- static int pbffilen= 0; // number of pbf input files;
- oo__if_t* ifptemp;
- byte* bufp;
- #define bufsp ((char*)bufp) // for signed char
-
- ifptemp= oo__ifp;
- oo__ifp= oo__if;
- while(oo__ifp<oo__ife) { // for all input files
- if(oo__ifp->ri!=NULL && oo__ifp->format==-9) {
- // format not yet determined
- read_switch(oo__ifp->ri);
- if(read_bufp[0]==0xef && read_bufp[1]==0xbb &&
- read_bufp[2]==0xbf && read_bufp[3]=='<')
- // UTF-8 BOM detected
- read_bufp+= 3; // jump over BOM
- if(read_bufp>=read_bufe) { // file empty
- PERRv("file empty: %.80s",oo__ifp->filename)
-return 2;
- }
- bufp= read_bufp;
- if(bufp[0]==0 && bufp[1]==0 && bufp[2]==0 &&
- bufp[3]>8 && bufp[3]<20) { // presumably .pbf format
- if(++pbffilen>1) { // pbf
- PERR("more than one .pbf input file is not allowed.");
-return 5;
- }
- oo__ifp->format= -1;
- pb_ini();
- pb_input(false);
- oo__alreadyhavepbfobject= true;
- }
- else if(strzcmp(bufsp,"<?xml")==0 ||
- strzcmp(bufsp,"<osm")==0) { // presumably .osm format
- oo__ifp->format= 10;
- }
- else if(bufp[0]==0xff && bufp[1]==0xe0 && (
- strzcmp(bufsp+2,"\x04""o5m2")==0 ||
- strzcmp(bufsp+2,"\x04""o5c2")==0 )) {
- // presumably .o5m format
- oo__ifp->format= 0;
- oo__ifp->str= str_open();
- // call some initialization of string read module
- }
- else if((bufp[0]==0xff && bufp[1]>=0x10 && bufp[1]<=0x12) ||
- (bufp[0]==0xff && bufp[1]==0xff &&
- bufp[2]>=0x10 && bufp[2]<=0x12) ||
- (bufp[0]==0xff && read_bufe==read_bufp+1)) {
- // presumably shortened .o5m format
- if(loglevel>=2)
- fprintf(stderr,"osmconvert: Not a standard .o5m file header "
- "%.80s\n",oo__ifp->filename);
- oo__ifp->format= 0;
- oo__ifp->str= str_open();
- // call some initialization of string read module
- }
- else { // unknown file format
- PERRv("unknown file format: %.80s",oo__ifp->filename)
-return 3;
- }
- oo__findbb();
- oo__ifp->tyid= 0;
- oo__ifp->hisver= 0;
- oo__gettyid();
- // initialize tyid of the currently used input file
- } // format not yet determined
- oo__ifp++;
- } // for all input files
- oo__ifp= ifptemp;
- if(loglevel>0 && oo__timestamp!=0) {
- char s[30]; // timestamp as string
-
- write_createtimestamp(oo__timestamp,s);
- fprintf(stderr,"osmconvert: File timestamp: %s\n",s);
- }
- if(global_timestamp!=0) // user wants a new file timestamp
- oo__timestamp= global_timestamp;
- return 0;
- #undef bufsp
- } // end oo__getformat()
-
-static uint64_t oo__tyidold= 0; // tyid of the last written object;
-
-static inline void oo__switch() {
- // determine the input file with the lowest tyid
- // and switch to it
- oo__if_t* ifp,*ifpmin;
- uint64_t tyidmin,tyidold,tyid;
-
- // update tyid of the currently used input file and check sequence
- if(oo__ifp!=NULL) { // handle of current input file is valid
- tyidold= oo__ifp->tyid;
- if(oo__gettyid()==0) { // new tyid is valid
-//DPv(got %llx %s,oo__ifp->tyid,oo__ifp->filename)
- if(oo__ifp->tyid<tyidold) { // wrong sequence
- int64_t id; int ty;
-
- oo__error= 91;
- ty= tyidold>>60;
- id= ((int64_t)(tyidold & UINT64_C(0xfffffffffffffff)))-
- INT64_C(0x800000000000000);
- WARNv("wrong order at %s %"PRIi64" in file %s",
- ONAME(ty),id,oo__ifp->filename)
- ty= oo__ifp->tyid>>60;
- id= ((int64_t)(oo__ifp->tyid & UINT64_C(0xfffffffffffffff)))-
- INT64_C(0x800000000000000);
- WARNv("next object is %s %"PRIi64,ONAME(ty),id)
- } // wrong sequence
- } // new tyid is valid
- } // end handle of current input file is valid
-
- // find file with smallest tyid
- tyidmin= UINT64_C(0xffffffffffffffff);
- ifpmin= oo__ifp;
- // default; therefore we do not switch in cases we do not
- // find a minimum
- ifp= oo__ife;
- while(ifp>oo__if) {
- ifp--;
- if(ifp->ri!=NULL) { // file handle is valid
-//DPv(have %llx %s,ifp->tyid,ifp->filename)
- tyid= ifp->tyid;
- if(tyid<tyidmin) {
- tyidmin= tyid;
- ifpmin= ifp;
- }
- } // file handle valid
- }
-
- // switch to that file
- if(ifpmin!=oo__ifp) {
- // that file is not the file we're already reading from
- oo__ifp= ifpmin;
- read_switch(oo__ifp->ri);
- str_switch(oo__ifp->str);
- }
-//DPv(chose %llx %s,oo__ifp->tyid,oo__ifp->filename)
- } // end oo__switch()
-
-static int oo_sequencetype= -1;
- // type of last object which has been processed;
- // -1: no object yet; 0: node; 1: way; 2: relation;
-static int64_t oo_sequenceid= INT64_C(-0x7fffffffffffffff);
- // id of last object which has been processed;
-
-static void oo__reset(oo__if_t* ifp) {
- // perform a reset of output procedures and variables;
- // this is mandatory if reading .o5m or .pbf and jumping
- // within the input file;
- ifp->o5id= 0;
- ifp->o5lat= ifp->o5lon= 0;
- ifp->o5hiscset= 0;
- ifp->o5histime= 0;
- ifp->o5rid[0]= ifp->o5rid[1]= ifp->o5rid[2]= 0;
- str_reset();
- if(ifp->format==-1)
- pb_input(true);
- } // oo__reset()
-
-static int oo__rewindall() {
- // rewind all input files;
- // return: 0: ok; !=0: error;
- oo__if_t* ifp,*ifp_sav;
-
- ifp_sav= oo__ifp; // save original info pointer
- ifp= oo__if;
- while(ifp<oo__ife) {
- if(ifp->riph!=NULL) {
- if(ifp->ri==NULL && ifp->riph!=NULL) {
- // file has been logically closed
- // logically reopen it
- ifp->ri= ifp->riph;
- oo_ifn++;
- }
- read_switch(ifp->ri);
- if(read_rewind())
-return 1;
- ifp->tyid= 1;
- ifp->endoffile= false;
- ifp->deleteobject= 0;
- oo__reset(ifp);
- }
- ifp++;
- }
- oo__ifp= ifp_sav; // restore original info pointer
- if(oo__ifp!=NULL && oo__ifp->ri!=NULL) {
- read_switch(oo__ifp->ri);
- str_switch(oo__ifp->str);
- }
- else
- oo__switch();
- oo__tyidold= 0;
- oo_sequencetype= -1;
- oo_sequenceid= INT64_C(-0x7fffffffffffffff);
- return 0;
- } // end oo__rewindall()
-
-static int oo__jumpall() {
- // jump in all input files to the previously stored position;
- // return: 0: ok; !=0: error;
- oo__if_t* ifp,*ifp_sav;
- int r;
-
- ifp_sav= oo__ifp; // save original info pointer
- ifp= oo__if;
- while(ifp<oo__ife) { // for all files
- if(ifp->riph!=NULL) { // file is still physically open
- if(ifp->ri==NULL && ifp->riph!=NULL) {
- // file has been logically closed
- // logically reopen it
- ifp->ri= ifp->riph;
- oo_ifn++;
- }
- read_switch(ifp->ri);
- r= read_jump();
- if(r<0) // jump error
-return 1;
- if(r==0) { // this was a real jump
- ifp->tyid= 1;
- ifp->endoffile= false;
- ifp->deleteobject= ifp->deleteobjectjump;
- oo__reset(ifp);
- }
- } // file is still physically open
- ifp++;
- } // for all files
- oo__ifp= ifp_sav; // restore original info pointer
- if(oo__ifp!=NULL && oo__ifp->ri!=NULL) {
- read_switch(oo__ifp->ri);
- str_switch(oo__ifp->str);
- }
- else {
- oo__switch();
- if(oo__ifp==NULL) { // no file chosen
- oo_ifn= 0;
- ifp= oo__if;
- while(ifp<oo__ife) { // for all files
- ifp->ri= NULL; // mark file as able to be logically reopened
- ifp++;
- }
- }
- }
- oo__tyidold= 0;
- oo_sequencetype= -1;
- oo_sequenceid= INT64_C(-0x7fffffffffffffff);
- return 0;
- } // end oo__jumpall()
-
-static void oo__close() {
- // logically close an input file;
- // oo__ifp: handle of currently active input file;
- // if this file has already been closed, nothing happens;
- // after calling this procedure, the handle of active input file
- // will be invalid; you may call oo__switch() to select the
- // next file in the sequence;
- if(oo__ifp!=NULL && oo__ifp->ri!=NULL) {
- if(!oo__ifp->endoffile && oo_ifn>0) // missing logical end of file
- fprintf(stderr,"osmconvert Warning: "
- "unexpected end of input file: %.80s\n",oo__ifp->filename);
- read_switch(oo__ifp->ri);
- //read_close();
- oo__ifp->ri= NULL;
- oo__ifp->tyid= UINT64_C(0xffffffffffffffff);
- // (to prevent this file being selected as next file
- // in the sequence)
- oo_ifn--;
- }
- oo__ifp= NULL;
- } // end oo__close()
-
-static void oo__closeall() {
- // close all input files;
- // after calling this procedure, the handle of active input file
- // will be invalid;
- oo_ifn= 0; // mark end of program;
- // this is used to suppress warning messages in oo__close()
- while(oo__ife>oo__if) {
- oo__ifp= --oo__ife;
- oo__ifp->endoffile= true; // suppress warnings (see oo__close())
- if(oo__ifp->riph!=NULL) {
- read_switch(oo__ifp->riph);
- read_close();
- }
- oo__ifp->ri= oo__ifp->riph= NULL;
- oo__ifp->tyid= UINT64_C(0xffffffffffffffff);
- }
- } // end oo__closeall()
-
-static void* oo__malloc_p[50];
- // pointers for controlled memory allocation
-static int oo__malloc_n= 0;
- // number of elements used in oo__malloc_p[]
-
-static void* oo__malloc(size_t size) {
- // same as malloc(), but the allocated memory will be
- // automatically freed at program end;
- void* mp;
-
- mp= malloc(size);
- if(mp==NULL) {
- PERRv("cannot allocate %"PRIi64" bytes of memory.",(int64_t)size);
- exit(1);
- }
- oo__malloc_p[oo__malloc_n++]= mp;
- return mp;
- } // oo__malloc()
-
-static void oo__end() {
- // clean-up this module;
- oo__closeall();
- while(oo__malloc_n>0)
- free(oo__malloc_p[--oo__malloc_n]);
- } // end oo__end()
-
-
-
-//------------------------------------------------------------
-
-static bool oo_open(const char* filename) {
- // open an input file;
- // filename[]: path and name of input file;
- // ==NULL: standard input;
- // return: 0: ok; 1: no appropriate input file;
- // 2: maximum number of input files exceeded;
- // the handle for the current input file oo__ifp is set
- // to the opened file;
- // after having opened all input files, call oo__getformat();
- // you do not need to care about closing the file;
- static bool firstrun= true;
-
- if(oo__ife>=oo__ifee) {
- fprintf(stderr,"osmconvert Error: too many input files.\n");
- fprintf(stderr,"osmconvert Error: too many input files: %d>%d\n",
- (int)(oo__ife-oo__if),global_fileM);
-return 2;
- }
- if(read_open(filename)!=0)
-return 1;
- oo__ife->ri= oo__ife->riph= read_infop;
- oo__ife->str= NULL;
- oo__ife->format= -9; // 'not yet determined'
- oo__ife->tyid= 0;
- if(filename==NULL)
- oo__ife->filename= "standard input";
- else
- oo__ife->filename= filename;
- oo__ife->endoffile= false;
- oo__ife->deleteobject= 0;
- oo__ife->subtract= global_subtract;
- oo__ifp= oo__ife++;
- oo_ifn++;
- if(firstrun) {
- firstrun= false;
- atexit(oo__end);
- }
- return 0;
- } // end oo_open()
-
-int dependencystage;
- // stage of the processing of interobject dependencies:
- // interrelation dependencies, --complete-ways or --complex-ways;
- // processing in stages allows us to reprocess parts of the data;
- // abbrevation "ht" means hash table (module hash_);
- //
- // 0: no recursive processing at all;
- //
- // option --complex-ways:
- // 11: no output;
- // for each node which is inside the borders,
- // set flag in ht;
- // store start of ways in read_setjump();
- // for each way which has a member with flag in ht,
- // set the way's flag in ht;
- // for each relation with a member with flag in ht,
- // store the relation's flag and write the ids
- // of member ways which have no flag in ht
- // (use cww_);
- // 11->12: at all files' end:
- // let all files jump to start of ways,
- // use read_jump();
- // set flags for ways, use cww_processing_set();
- // 12: no output;
- // for each way with a member with a flag in ht,
- // set the way's flag in ht and write the ids
- // of all the way's members (use cwn_);
- // 12->22: as soon as first relation shall be written:
- // rewind all files;
- // set flags for nodes, use cwn_processing();
- //
- // option --complete-ways:
- // 21: no output;
- // for each node inside the borders,
- // set flag in ht;
- // for each way with a member with a flag in ht,
- // set the way's flag in ht and write the ids
- // of all the way's members (use cwn_);
- // 21->22: as soon as first relation shall be written:
- // rewind all files;
- // set flags for nodes, use cwn_processing();
- // 22: write each node which has a flag in ht to output;
- // write each way which has a flag in ht to output;
- // 22->32: as soon as first relation shall be written:
- // clear flags for ways, use cww_processing_clear();
- // switch output to temporary file;
- //
- // regular procedure:
- // 31: for each node inside the borders,
- // set flag in ht;
- // for each way with a member with a flag in ht,
- // set the way's flag in ht;
- // 31->32: as soon as first relation shall be written:
- // switch output to temporary .o5m file;
- // 32: for each relation with a member with a flag
- // in ht, set the relation's flag in ht;
- // for each relation,
- // write its id and its members' ids
- // into a temporary file (use rr_);
- // if option --all-to-nodes is set, then
- // for each relation, write its members'
- // geopositions into a temporary file (use posr_);
- // 32->33: at all files' end:
- // process all interrelation references (use rr_);
- // if option --all-to-nodes is set, then
- // process position array (use posr_);
- // switch input to the temporary .o5m file;
- // switch output to regular output file;
- // 33: write each relation which has a flag in ht
- // to output; use temporary .o5m file as input;
- // 33->99: at all files' end: end this procedure;
- //
- // out-of-date:
- // 1: (this stage is applied only with --complete-ways option)
- // read nodes and ways, do not write anything; change to next
- // stage as soon as the first relation has been encountered;
- // now: 21;
- // 1->2: at this moment, rewind all input files;
- // now: 21->22;
- // 2: write nodes and ways, change to next stage as soon as
- // the first relation has been encountered;
- // now: 22 or 31;
- // 2->3: at this moment, change the regular output file to a
- // tempfile, and switch output format to .o5m;
- // now: 22->32 or 31->32;
- // 3: write interrelation references into a second to tempfile,
- // use modules rr_ or posr_ for this purpose;
- // now: 32;
- // 3->4: at this moment, change output back to standard output,
- // and change input to the start of the tempfile;
- // in addition to this, process temporarily stored
- // interrelation data;
- // now: 32->33;
- // 4: write only relations, use tempfile as input;
- // now: 33;
-static void oo__dependencystage(int ds) {
- // change the dependencystage;
- if(loglevel>=2)
- PINFOv("changing dependencystage from %i to %i.",dependencystage,ds)
- dependencystage= ds;
- } // oo__dependencystage()
-
-static int oo_main() {
- // start reading osm objects;
- // return: ==0: ok; !=0: error;
- // this procedure must only be called once;
- // before calling this procedure you must open an input file
- // using oo_open();
- int wformat; // output format;
- // 0: o5m; 11,12,13,14: some different XML formats;
- // 21: csv; -1: PBF;
- bool hashactive;
- // must be set to true if border_active OR global_dropbrokenrefs;
- static char o5mtempfile[400]; // must be static because
- // this file will be deleted by an at-exit procedure;
- #define oo__maxrewindINI 12
- int maxrewind; // maximum number of relation-relation dependencies
- int maxrewind_posr; // same as before, but for --all-to-nodes
- bool writeheader; // header must be written
- int otype; // type of currently processed object;
- // 0: node; 1: way; 2: relation;
- int64_t id;
- int32_t lon,lat;
- uint32_t hisver;
- int64_t histime;
- int64_t hiscset;
- uint32_t hisuid;
- char* hisuser;
- int64_t* refid; // ids of referenced object
- int64_t* refidee; // end address of array
- int64_t* refide,*refidp; // pointer in array
- int32_t** refxy; // coordinates of referenced object
- int32_t** refxyp; // pointer in array
- byte* reftype; // types of referenced objects
- byte* reftypee,*reftypep; // pointer in array
- char** refrole; // roles of referenced objects
- char** refrolee,**refrolep; // pointer in array
- #define oo__keyvalM 8000 // changed from 4000 to 8000
- // because there are old ways with this many key/val pairs
- // in full istory planet due to malicious Tiger import
- char* key[oo__keyvalM],*val[oo__keyvalM];
- char** keyee; // end address of first array
- char** keye,**keyp; // pointer in array
- char** vale,**valp; // pointer in array
- byte* bufp; // pointer in read buffer
- #define bufsp ((char*)bufp) // for signed char
- byte* bufe; // pointer in read buffer, end of object
- char c; // latest character which has been read
- byte b; // latest byte which has been read
- int l;
- byte* bp;
- char* sp;
- struct {
- int64_t nodes,ways,relations; // number of objects
- int64_t node_id_min,node_id_max;
- int64_t way_id_min,way_id_max;
- int64_t relation_id_min,relation_id_max;
- int64_t timestamp_min,timestamp_max;
- int32_t lon_min,lon_max;
- int32_t lat_min,lat_max;
- int32_t keyval_pairs_max;
- int keyval_pairs_otype;
- int64_t keyval_pairs_oid;
- int32_t noderefs_max;
- int64_t noderefs_oid;
- int32_t relrefs_max;
- int64_t relrefs_oid;
- } statistics;
- bool diffcompare; // the next object shall be compared
- // with the object which has just been read;
- bool diffdifference;
- // there was a difference in object comparison
-
- // procedure initialization
- atexit(oo__end);
- memset(&statistics,0,sizeof(statistics));
- oo__bbvalid= false;
- hashactive= border_active || global_dropbrokenrefs;
- dependencystage= 0; // 0: no recursive processing at all;
- maxrewind= maxrewind_posr= oo__maxrewindINI;
- writeheader= true;
- if(global_outo5m) wformat= 0;
- else if(global_outpbf) wformat= -1;
- else if(global_emulatepbf2osm) wformat= 12;
- else if(global_emulateosmosis) wformat= 13;
- else if(global_emulateosmium) wformat= 14;
- else if(global_outcsv) wformat= 21;
- else wformat= 11;
- refid= (int64_t*)oo__malloc(sizeof(int64_t)*global_maxrefs);
- refidee= refid+global_maxrefs;
- refxy= (int32_t**)oo__malloc(sizeof(int32_t*)*global_maxrefs);
- reftype= (byte*)oo__malloc(global_maxrefs);
- refrole= (char**)oo__malloc(sizeof(char*)*global_maxrefs);
- keyee= key+oo__keyvalM;
- diffcompare= false;
- diffdifference= false;
-
- // get input file format and care about tempfile name
- if(oo__getformat())
-return 5;
- if((hashactive && !global_droprelations) ||
- global_calccoords!=0) {
- // (borders to apply AND relations are required) OR
- // user wants ways and relations to be converted to nodes
- // initiate recursive processing;
- if(global_complexways) {
- oo__dependencystage(11);
- // 11: no output;
- // for each node which is inside the borders,
- // set flag in ht;
- // store start of ways in read_setjump();
- // for each way which has a member with flag in ht,
- // set the way's flag in ht;
- // for each relation with a member with flag in ht,
- // store the relation's flag and write the ids
- // of member ways which have no flag in ht
- // (use cww_);
- if(cwn_ini(global_tempfilename))
-return 28;
- if(cww_ini(global_tempfilename))
-return 28;
- }
- else if(global_completeways) {
- oo__dependencystage(21);
- // 21: no output;
- // for each node inside the borders,
- // set flag in ht;
- // for each way with a member with a flag in ht,
- // set the way's flag in ht and write the ids
- // of all the way's members (use cwn_);
- if(cwn_ini(global_tempfilename))
-return 28;
- }
- else
- oo__dependencystage(31);
- // 31: for each node inside the borders,
- // set flag in ht;
- // for each way with a member with a flag in ht,
- // set the way's flag in ht;
- strcpy(stpmcpy(o5mtempfile,global_tempfilename,
- sizeof(o5mtempfile)-2),".1");
- }
- else {
- oo__dependencystage(0); // no recursive processing
- global_completeways= false;
- global_complexways= false;
- }
-
- // print file timestamp and nothing else if requested
- if(global_outtimestamp) {
- if(oo__timestamp!=0) // file timestamp is valid
- write_timestamp(oo__timestamp);
- else
- write_str("(invalid timestamp)");
- write_str(NL);
-return 0; // nothing else to do here
- }
-
- // process the file
- for(;;) { // read all input files
-
- if(oo_ifn>0) { // at least one input file open
-
- // get next object - if .pbf
- //read_input(); (must not be here because of diffcompare)
- if(oo__ifp->format==-1) {
- if(!oo__alreadyhavepbfobject)
- pb_input(false);
- while(pb_type>2) // unknown pbf object
- pb_input(false); // get next object
- }
-
- // merging - if more than one file
- if((oo_ifn>1 || oo__tyidold>0) && dependencystage!=33)
- // input file switch necessary;
- // not:
- // 33: write each relation which has a flag in ht
- // to output;
- oo__switch();
- else if(global_mergeversions)
- oo__gettyid();
- else
- oo__ifp->tyid= 1;
- if(diffcompare && oo__ifp!=oo__if) {
- // comparison must be made with the first file but presently
- // the second file is active
- // switch to the first file
- oo__ifp= oo__if;
- read_switch(oo__ifp->ri);
- str_switch(oo__ifp->str);
- }
-
- // get next data
- read_input();
-
- } // at least one input file open
-
- // care about end of input file
- if(oo_ifn==0 || (read_bufp>=read_bufe && oo__ifp->format>=0) ||
- (oo__ifp->format==-1 && pb_type<0)) { // at end of input file
- if(oo_ifn>0) {
- if(oo__ifp->format==-1 && pb_type<0) {
- if(pb_type<-1) // error
-return 1000-pb_type;
- oo__ifp->endoffile= true;
- }
- oo__close();
- }
- if(oo_ifn>0) // still input files
- oo__switch();
- else { // at end of all input files
- // care about recursive processing
- if(dependencystage==11) {
- // 11: no output;
- // for each node which is inside the borders,
- // set flag in ht;
- // store start of ways in read_setjump();
- // for each way which has a member with flag in ht,
- // set the way's flag in ht;
- // for each relation with a member with flag in ht,
- // store the relation's flag and write the ids
- // of member ways which have no flag in ht
- // (use cww_);
- // 11->12: at all files' end:
- // let all files jump to start of ways,
- // use read_jump();
- // set flags for ways, use cww_processing_set();
- if(oo__jumpall())
-return 28;
- cww_processing_set();
- oo__dependencystage(12);
- // 12: no output;
- // for each way with a member with a flag in ht,
- // set the way's flag in ht and write the ids
- // of all the way's members (use cwn_);
- continue; // do not write this object
- }
- if(dependencystage==21 || dependencystage==12) {
- // 12: no output;
- // for each way with a member with a flag in ht,
- // set the way's flag in ht and write the ids
- // of all the way's members (use cwn_);
- // 21: no output;
- // for each node inside the borders,
- // set flag in ht;
- // for each way with a member with a flag in ht,
- // set the way's flag in ht and write the ids
- // of all the way's members (use cwn_);
- // 12->22: as soon as first relation shall be written:
- // rewind all files;
- // set flags for nodes, use cwn_processing();
- // 21->22: as soon as first relation shall be written:
- // rewind all files;
- // set flags for nodes, use cwn_processing();
- if(oo__rewindall())
-return 28;
- cwn_processing();
- oo__dependencystage(22);
- // 22: write each node which has a flag in ht to output;
- // write each way which has a flag in ht to output;
- continue; // do not write this object
- }
- if(dependencystage!=32) {
- // not:
- // 32: for each relation with a member with a flag
- // in ht, set the relation's flag in ht;
- // for each relation,
- // write its id and its members' ids
- // into a temporary file (use rr_);
- // if option --all-to-nodes is set, then
- // for each relation, write its members'
- // geopositions into a temporary file
- // (use posr_);
- if(dependencystage==33) {
- // 33: write each relation which has a flag in ht
- // to output; use temporary .o5m file as input;
- if(oo__ifp!=NULL)
- oo__ifp->endoffile= true;
- // this is because the file we have read
- // has been created as temporary file by the program
- // and does not contain an eof object;
- if(maxrewind_posr<maxrewind) maxrewind= maxrewind_posr;
- if(loglevel>0) fprintf(stderr,
- "Relation hierarchies: %i of maximal %i.\n",
- oo__maxrewindINI-maxrewind,oo__maxrewindINI);
- if(maxrewind<0)
- fprintf(stderr,
- "osmconvert Warning: relation dependencies too complex\n"
- " (more than %i hierarchy levels).\n"
- " A few relations might have been excluded\n"
- " although lying within the borders.\n",
- oo__maxrewindINI);
- }
- break;
- } // end dependencystage!=32
- // here: dependencystage==32
- // 32: for each relation with a member with a flag
- // in ht, set the relation's flag in ht;
- // for each relation,
- // write its id and its members' ids
- // into a temporary file (use rr_);
- // if option --all-to-nodes is set, then
- // for each relation, write its members'
- // geopositions into a temporary file (use posr_);
- // 32->33: at all files' end:
- // process all interrelation references (use rr_);
- // if option --all-to-nodes is set, then
- // process position array (use posr_);
- // switch input to the temporary .o5m file;
- // switch output to regular output file;
- if(!global_outnone) {
- wo_flush();
- wo_reset();
- wo_end();
- wo_flush();
- }
- if(write_newfile(NULL))
-return 21;
- if(!global_outnone) {
- wo_format(wformat);
- wo_reset();
- }
- if(hashactive)
- oo__rrprocessing(&maxrewind);
- if(global_calccoords!=0)
- posr_processing(&maxrewind_posr,refxy);
- oo__dependencystage(33); // enter next stage
- oo__tyidold= 0; // allow the next object to be written
- if(oo_open(o5mtempfile))
-return 22;
- if(oo__getformat())
-return 23;
- read_input();
- continue;
- } // at end of all input files
- } // at end of input file
-
- // care about unexpected contents at file end
- if(dependencystage<=31)
- // 31: for each node inside the borders,
- // set flag in ht;
- // for each way with a member with a flag in ht,
- // set the way's flag in ht;
- if(oo__ifp->endoffile) { // after logical end of file
- WARNv("osmconvert Warning: unexpected contents "
- "after logical end of file: %.80s",oo__ifp->filename)
- break;
- }
-
- readobject:
- bufp= read_bufp;
- b= *bufp; c= (char)b;
-
- // care about header and unknown objects
- if(oo__ifp->format<0) { // -1, pbf
- if(pb_type<0 || pb_type>2) // not a regular dataset id
- continue;
- otype= pb_type;
- oo__alreadyhavepbfobject= false;
- } // end pbf
- else if(oo__ifp->format==0) { // o5m
- if(b<0x10 || b>0x12) { // not a regular dataset id
- if(b>=0xf0) { // single byte dataset
- if(b==0xff) { // file start, resp. o5m reset
- if(read_setjump())
- oo__ifp->deleteobjectjump= oo__ifp->deleteobject;
- oo__reset(oo__ifp);
- }
- else if(b==0xfe)
- oo__ifp->endoffile= true;
- else if(write_testmode)
- WARNv("unknown .o5m short dataset id: 0x%02x",b)
- read_bufp++;
- continue;
- } // end single byte dataset
- else { // unknown multibyte dataset
- if(b!=0xdb && b!=0xdc && b!=0xe0)
- // not border box AND not header
- WARNv("unknown .o5m dataset id: 0x%02x",b)
- read_bufp++;
- l= pbf_uint32(&read_bufp); // length of this dataset
- read_bufp+= l; // jump over this dataset
- continue;
- } // end unknown multibyte dataset
- } // end not a regular dataset id
- otype= b&3;
- } // end o5m
- else { // xml
- while(c!=0 && c!='<') c= (char)*++bufp;
- if(c==0) {
- read_bufp= read_bufe;
- continue;
- }
- c= bufsp[1];
- if(c=='n' && bufsp[2]=='o' && bufsp[3]=='d') // node
- otype= 0;
- else if(c=='w' && bufsp[2]=='a') // way
- otype= 1;
- else if(c=='r' && bufsp[2]=='e') // relation
- otype= 2;
- else if(c=='c' || (c=='m' && bufsp[2]=='o') || c=='d' ||
- c=='i' || c=='k' || c=='e' ) {
- // create, modify or delete,
- // insert, keep or erase
- if(c=='d' || c=='e')
- oo__ifp->deleteobject= 2;
- read_bufp= bufp+1;
- continue;
- } // end create, modify or delete,
- // resp. insert, keep or erase
- else if(c=='/') { // xml end object
- if(bufsp[2]=='d' || bufsp[2]=='e') // end of delete or erase
- oo__ifp->deleteobject= 0;
- else if(strzcmp(bufsp+2,"osm>")==0) { // end of file
- oo__ifp->endoffile= true;
- read_bufp= bufp+6;
- while(oo__ws(*read_bufp)) read_bufp++;
- continue;
- } // end end of file
- else if(strzcmp(bufsp+2,"osmChange>")==0) { // end of file
- oo__ifp->endoffile= true;
- read_bufp= bufp+6+6;
- while(oo__ws(*read_bufp)) read_bufp++;
- continue;
- } // end end of file
- else if(strzcmp(bufsp+2,"osmAugmentedDiff>")==0) {
- // end of file
- oo__ifp->endoffile= true;
- read_bufp= bufp+6+13;
- while(oo__ws(*read_bufp)) read_bufp++;
- continue;
- } // end end of file
- goto unknownxmlobject;
- } // end xml end object
- else { // unknown xml object
- unknownxmlobject:
- bufp++;
- for(;;) { // find end of xml object
- c= *bufsp;
- if(c=='>' || c==0)
- break;
- bufp++;
- }
- read_bufp= bufp;
- continue;
- } // end unknown XML object
- // here: regular OSM XML object
- if(read_setjump())
- oo__ifp->deleteobjectjump= oo__ifp->deleteobject;
- read_bufp= bufp;
- } // end xml
-
- // write header
- if(writeheader) {
- writeheader= false;
- if(!global_outnone)
- wo_start(wformat,oo__bbvalid,
- oo__bbx1,oo__bby1,oo__bbx2,oo__bby2,oo__timestamp);
- }
-
- // object initialization
- if(!diffcompare) { // regularly read the object
- hisver= 0;
- histime= 0;
- hiscset= 0;
- hisuid= 0;
- hisuser= "";
- refide= refid;
- reftypee= reftype;
- refrolee= refrole;
- keye= key;
- vale= val;
- } // regularly read the object
- if(oo__ifp->deleteobject==1) oo__ifp->deleteobject= 0;
-
-
- // read one osm object
- if(oo__ifp->format<0) { // pbf
- // read id
- id= pb_id;
- // read coordinates (for nodes only)
- if(otype==0) { // node
- lon= pb_lon; lat= pb_lat;
- } // node
- // read author
- hisver= pb_hisver;
- if(hisver!=0) { // author information available
- histime= pb_histime;
- if(histime!=0) {
- hiscset= pb_hiscset;
- hisuid= pb_hisuid;
- hisuser= pb_hisuser;
- }
- } // end author information available
- oo__ifp->deleteobject= pb_hisvis==0? 1: 0;
- // read noderefs (for ways only)
- if(otype==1) // way
- refide= refid+pb_noderef(refid,global_maxrefs);
- // read refs (for relations only)
- else if(otype==2) { // relation
- l= pb_ref(refid,reftype,refrole,global_maxrefs);
- refide= refid+l;
- reftypee= reftype+l;
- refrolee= refrole+l;
- } // end relation
- // read node key/val pairs
- l= pb_keyval(key,val,oo__keyvalM);
- keye= key+l; vale= val+l;
- } // end pbf
- else if(oo__ifp->format==0) { // o5m
- bufp++;
- l= pbf_uint32(&bufp);
- read_bufp= bufe= bufp+l;
- if(diffcompare) { // just compare, do not store the object
- uint32_t hisverc;
- int64_t histimec;
- char* hisuserc;
- int64_t* refidc; // pointer for object contents comparison
- byte* reftypec; // pointer for object contents comparison
- char** refrolec; // pointer for object contents comparison
- char** keyc,**valc; // pointer for object contents comparison
-
- // initialize comparison variables
- hisverc= 0;
- histimec= 0;
- hisuserc= "";
- refidc= refid;
- reftypec= reftype;
- refrolec= refrole;
- keyc= key;
- valc= val;
-
- // compare object id
- if(id!=(oo__ifp->o5id+= pbf_sint64(&bufp)))
- diffdifference= true;
-
- // compare author
- hisverc= pbf_uint32(&bufp);
- if(hisverc!=hisver)
- diffdifference= true;
- if(hisverc!=0) { // author information available
- histimec= oo__ifp->o5histime+= pbf_sint64(&bufp);
- if(histimec!=0) {
- if(histimec!=histime)
- diffdifference= true;
- if(hiscset!=(oo__ifp->o5hiscset+= pbf_sint32(&bufp)))
- diffdifference= true;
- str_read(&bufp,&sp,&hisuserc);
- if(strcmp(hisuserc,hisuser)!=0)
- diffdifference= true;
- if(hisuid!=pbf_uint64((byte**)&sp))
- diffdifference= true;
- }
- } // end author information available
-
- if(bufp>=bufe) {
- // just the id and author, i.e. this is a delete request
- oo__ifp->deleteobject= 1;
- diffdifference= true;
- }
- else { // not a delete request
- oo__ifp->deleteobject= 0;
-
- // compare coordinates (for nodes only)
- if(otype==0) { // node
- // read node body
- if(lon!=(oo__ifp->o5lon+= pbf_sint32(&bufp)))
- diffdifference= true;
- if(lat!=(oo__ifp->o5lat+= pbf_sint32(&bufp)))
- diffdifference= true;
- } // end node
-
- // compare noderefs (for ways only)
- if(otype==1) { // way
- l= pbf_uint32(&bufp);
- bp= bufp+l;
- if(bp>bufe) bp= bufe; // (format error)
- while(bufp<bp && refidc<refidee) {
- if(*refidc!=(oo__ifp->o5rid[0]+= pbf_sint64(&bufp)))
- diffdifference= true;
- refidc++;
- }
- } // end way
-
- // compare refs (for relations only)
- else if(otype==2) { // relation
- int64_t ri; // temporary, refid
- int rt; // temporary, reftype
- char* rr; // temporary, refrole
-
- l= pbf_uint32(&bufp);
- bp= bufp+l;
- if(bp>bufe) bp= bufe; // (format error)
- while(bufp<bp && refidc<refidee) {
- ri= pbf_sint64(&bufp);
- str_read(&bufp,&rr,NULL);
- if(*reftypec!=(rt= (*rr++ -'0')%3))
- diffdifference= true;
- if(*refidc!=(oo__ifp->o5rid[rt]+= ri))
- diffdifference= true;
- if(refrolec>=refrolee || strcmp(*refrolec,rr)!=0)
- diffdifference= true;
- reftypec++;
- refidc++;
- refrolec++;
- }
- } // end relation
-
- // compare node key/val pairs
- while(bufp<bufe && keyc<keyee) {
- char* k,*v;
-
- k= v= "";
- str_read(&bufp,&k,&v);
- if(keyc>=keye || strcmp(k,*keyc)!=0 || strcmp(v,*valc)!=0)
- diffdifference= true;
- keyc++; valc++;
- }
- } // end not a delete request
-
- // compare indexes
- if(keyc!=keye || (otype>0 && refidc!=refide))
- diffdifference= true;
-
- } // just compare, do not store the object
- else { // regularly read the object
- // read object id
- id= oo__ifp->o5id+= pbf_sint64(&bufp);
- // read author
- hisver= pbf_uint32(&bufp);
- if(hisver!=0) { // author information available
- histime= oo__ifp->o5histime+= pbf_sint64(&bufp);
- if(histime!=0) {
- hiscset= oo__ifp->o5hiscset+= pbf_sint32(&bufp);
- str_read(&bufp,&sp,&hisuser);
- hisuid= pbf_uint64((byte**)&sp);
- }
- } // end author information available
- if(bufp>=bufe)
- // just the id and author, i.e. this is a delete request
- oo__ifp->deleteobject= 1;
- else { // not a delete request
- oo__ifp->deleteobject= 0;
- // read coordinates (for nodes only)
- if(otype==0) { // node
- // read node body
- lon= oo__ifp->o5lon+= pbf_sint32(&bufp);
- lat= oo__ifp->o5lat+= pbf_sint32(&bufp);
- } // end node
- // read noderefs (for ways only)
- if(otype==1) { // way
- l= pbf_uint32(&bufp);
- bp= bufp+l;
- if(bp>bufe) bp= bufe; // (format error)
- while(bufp<bp && refide<refidee)
- *refide++= oo__ifp->o5rid[0]+= pbf_sint64(&bufp);
- } // end way
- // read refs (for relations only)
- else if(otype==2) { // relation
- int64_t ri; // temporary, refid
- int rt; // temporary, reftype
- char* rr; // temporary, refrole
-
- l= pbf_uint32(&bufp);
- bp= bufp+l;
- if(bp>bufe) bp= bufe; // (format error)
- while(bufp<bp && refide<refidee) {
- ri= pbf_sint64(&bufp);
- str_read(&bufp,&rr,NULL);
- *reftypee++= rt= (*rr++ -'0')%3; // (suppress errors)
- *refide++= oo__ifp->o5rid[rt]+= ri;
- *refrolee++= rr;
- }
- } // end relation
- // read node key/val pairs
- keye= key; vale= val;
- while(bufp<bufe && keye<keyee)
- str_read(&bufp,keye++,vale++);
- } // end not a delete request
- } // regularly read the object
- } // end o5m
- else { // xml
- int64_t ri; // temporary, refid, rcomplete flag 1
- int rt; // temporary, reftype, rcomplete flag 2
- char* rr; // temporary, refrole, rcomplete flag 3
- int rcomplete;
- char* k; // temporary, key
- char* v; // temporary, val
- int r;
-
- read_bufp++; // jump over '<'
- oo__xmlheadtag= true; // (default)
- rcomplete= 0;
- k= v= NULL;
- for(;;) { // until break;
- r= oo__xmltag();
- if(oo__xmlheadtag) { // still in object header
- if(oo__xmlkey[0]=='i' && oo__xmlkey[1]=='d') // id
- id= oo__strtosint64(oo__xmlval);
- else if(oo__xmlkey[0]=='l') { // letter l
- if(oo__xmlkey[1]=='o') // lon
- lon= oo__strtodeg(oo__xmlval);
- else if(oo__xmlkey[1]=='a') // lon
- lat= oo__strtodeg(oo__xmlval);
- } // end letter l
- else if(oo__xmlkey[0]=='v' && oo__xmlkey[1]=='i') { // visible
- if(oo__xmlval[0]=='f' || oo__xmlval[0]=='n')
- if(oo__ifp->deleteobject==0)
- oo__ifp->deleteobject= 1;
- } // end visible
- else if(oo__xmlkey[0]=='a' && oo__xmlkey[1]=='c') { // action
- if(oo__xmlval[0]=='d' && oo__xmlval[1]=='e')
- if(oo__ifp->deleteobject==0)
- oo__ifp->deleteobject= 1;
- } // end action
- else if(!global_dropversion) { // version not to drop
- if(oo__xmlkey[0]=='v' && oo__xmlkey[1]=='e') // hisver
- hisver= oo__strtouint32(oo__xmlval);
- if(!global_dropauthor) { // author not to drop
- if(oo__xmlkey[0]=='t') // histime
- histime= oo__strtimetosint64(oo__xmlval);
- else if(oo__xmlkey[0]=='c') // hiscset
- hiscset= oo__strtosint64(oo__xmlval);
- else if(oo__xmlkey[0]=='u' && oo__xmlkey[1]=='i') // hisuid
- hisuid= oo__strtouint32(oo__xmlval);
- else if(oo__xmlkey[0]=='u' && oo__xmlkey[1]=='s') //hisuser
- hisuser= oo__xmlval;
- } // end author not to drop
- } // end version not to drop
- } // end still in object header
- else { // in object body
- if(oo__xmlkey[0]==0) { // xml tag completed
- if(rcomplete>=3) { // at least refid and reftype
- *refide++= ri;
- *reftypee++= rt;
- if(rcomplete<4) // refrole is missing
- rr= ""; // assume an empty string as refrole
- *refrolee++= rr;
- } // end at least refid and reftype
- rcomplete= 0;
- if(v!=NULL && k!=NULL) { // key/val available
- *keye++= k; *vale++= v;
- k= v= NULL;
- } // end key/val available
- } // end xml tag completed
- else { // inside xml tag
- if(otype!=0 && refide<refidee) {
- // not a node AND still space in refid array
- if(oo__xmlkey[0]=='r' && oo__xmlkey[1]=='e') { // refid
- ri= oo__strtosint64(oo__xmlval); rcomplete|= 1;
- if(otype==1) {rt= 0; rcomplete|= 2; } }
- else if(oo__xmlkey[0]=='t' && oo__xmlkey[1]=='y') {
- // reftype
- rt= oo__xmlval[0]=='n'? 0: oo__xmlval[0]=='w'? 1: 2;
- rcomplete|= 2; }
- else if(oo__xmlkey[0]=='r' && oo__xmlkey[1]=='o') {
- // refrole
- rr= oo__xmlval; rcomplete|= 4; }
- } // end still space in refid array
- if(keye<keyee) { // still space in key/val array
- if(oo__xmlkey[0]=='k') // key
- k= oo__xmlval;
- else if(oo__xmlkey[0]=='v') // val
- v= oo__xmlval;
- } // end still space in key/val array
- } // end inside xml tag
- } // end in object body
- if(r)
- break;
- } // end until break;
- } // end xml
-
- // care about multiple occurrences of one object within one file
- if(global_mergeversions) {
- // user allows duplicate objects in input file; that means
- // we must take the last object only of each duplicate
- // because this is assumed to be the newest;
- uint64_t tyidold;
-
- tyidold= oo__ifp->tyid;
- if(oo__gettyid()==0) {
- if(oo__ifp->tyid==tyidold) // next object has same type and id
- goto readobject; // dispose this object and take the next
- }
- oo__ifp->tyid= tyidold;
- }
-
- // care about possible array overflows
- if(refide>=refidee)
- PERRv("%s %"PRIi64" has too many refs.",ONAME(otype),id)
- if(keye>=keyee)
- PERRv("%s %"PRIi64" has too many key/val pairs.",
- ONAME(otype),id)
-
- // care about diffs and sequence
- if(global_diffcontents) { // diff contents is to be considered
- // care about identical contents if calculating a diff
- if(oo__ifp!=oo__if && oo__ifp->tyid==oo__if->tyid) {
- // second file and there is a similar object in the first file
- // and version numbers are different
- diffcompare= true; // compare with next object, do not read
- diffdifference= false; // (default)
- continue; // no check the first file
- }
- } // diff contents is to be considered
- else { // no diff contents is to be considered
- // stop processing if object is to ignore because of duplicates
- // in same or other file(s)
- if(oo__ifp->tyid<=oo__tyidold)
- continue;
- oo__tyidold= 0;
- if(oo_ifn>1)
- oo__tyidold= oo__ifp->tyid;
- // stop processing if in wrong stage for nodes or ways
- if(dependencystage>=32 && otype<=1)
- // 32: for each relation with a member with a flag
- // in ht, set the relation's flag in ht;
- // for each relation,
- // write its id and its members' ids
- // into a temporary file (use rr_);
- // if option --all-to-nodes is set, then
- // for each relation, write its members'
- // geopositions into a temporary file (use posr_);
- // 33: write each relation which has a flag in ht
- // to output; use temporary .o5m file as input;
- continue; // ignore this object
- // check sequence, if necessary
- if(oo_ifn==1 && dependencystage!=33) {
- // not:
- // 33: write each relation which has a flag in ht
- // to output; use temporary .o5m file as input;
- if(otype<=oo_sequencetype &&
- (otype<oo_sequencetype || id<oo_sequenceid ||
- (oo_ifn>1 && id<=oo_sequenceid))) {
- oo__error= 92;
- WARNv("wrong sequence at %s %"PRIi64,
- ONAME(oo_sequencetype),oo_sequenceid)
- WARNv("next object is %s %"PRIi64,ONAME(otype),id)
- }
- } // dependencystage>=32
- } // no diff contents is to be considered
- oo_sequencetype= otype; oo_sequenceid= id;
-
- // care about calculating a diff file
- if(global_diff) { // diff
- if(oo__ifp==oo__if) { // first file has been chosen
- if(diffcompare) {
- diffcompare= false;
- if(!diffdifference)
- continue; // there has not been a change in object's contents
- oo__ifp->deleteobject= 0;
- }
- else {
- //if(global_diffcontents && oo_ifn<2) continue;
- oo__ifp->deleteobject= 1; // add "delete request";
- }
- }
- else { // second file has been chosen
- if(oo__ifp->tyid==oo__if->tyid &&
- oo__ifp->hisver==oo__if->hisver)
- // there is a similar object in the first file
- continue; // ignore this object
- } // end second file has been chosen
- } // end diff
-
- // care about dependency stages
- if(dependencystage==11) {
- // 11: no output;
- // for each node which is inside the borders,
- // set flag in ht;
- // store start of ways in read_setjump();
- // for each way which has a member with flag in ht,
- // set the way's flag in ht;
- // for each relation with a member with flag in ht,
- // store the relation's flag and write the ids
- // of member ways which have no flag in ht
- // (use cww_);
- if(otype>=1) // way or relation
- read_lockjump();
- if((oo__ifp->deleteobject==0) ^ oo__ifp->subtract) {
- // object is not to delete
- if(otype==0) { // node
- if(!border_active || border_queryinside(lon,lat))
- // no border to be applied OR node lies inside
- hash_seti(0,id); // mark this node id as 'inside'
- } // node
- else if(otype==1) { // way
- refidp= refid;
- while(refidp<refide) { // for every referenced node
- if(hash_geti(0,*refidp))
- break;
- refidp++;
- } // end for every referenced node
- if(refidp<refide) // at least on node lies inside
- hash_seti(1,id); // memorize that this way lies inside
- } // way
- else { // relation
- int64_t ri; // temporary, refid
- int rt; // temporary, reftype
- char* rr; // temporary, refrole
- bool relinside; // this relation lies inside
- bool wayinside; // at least one way lies inside
- bool ismp; // this relation is a multipolygon
-
- relinside= wayinside= ismp= false;
- refidp= refid; reftypep= reftype; refrolep= refrole;
- while(refidp<refide) { // for every referenced object
- ri= *refidp; rt= *reftypep; rr= *refrolep;
- if(!relinside && hash_geti(rt,ri))
- relinside= true;
- if(!wayinside && rt==1 && (strcmp(rr,"outer")==0 ||
- strcmp(rr,"inner")==0) && hash_geti(1,ri))
- // referenced object is a way and part of
- // a multipolygon AND lies inside
- wayinside= true;
- refidp++; reftypep++; refrolep++;
- } // end for every referenced object
- if(relinside) { // relation lies inside
- hash_seti(2,id);
- if(wayinside) { // at least one way lies inside
- keyp= key; valp= val;
- while(keyp<keye) { // for all key/val pairs of this object
- if(strcmp(*keyp,"type")==0 &&
- strcmp(*valp,"multipolygon")==0) {
- ismp= true;
- break;
- }
- keyp++; valp++;
- } // for all key/val pairs of this object
- if(ismp) { // is multipolygon
- refidp= refid; reftypep= reftype; refrolep= refrole;
- while(refidp<refide) { // for every referenced object
- ri= *refidp; rt= *reftypep; rr= *refrolep;
- if(rt==1 && (strcmp(rr,"outer")==0 ||
- strcmp(rr,"inner")==0) &&
- !hash_geti(1,ri)) { // referenced object
- // is a way and part of the multipolygon AND
- // has not yet a flag in ht
- cww_ref(ri); // write id of the way
- }
- refidp++; reftypep++; refrolep++;
- } // end for every referenced object
- } // is multipolygon
- } // at least one way lies inside
- } // relation lies inside
- } // relation
- } // object is not to delete
-continue; // do not write this object
- } // dependencystage 11
- else if(dependencystage==12) {
- // 12: no output;
- // for each way with a member with a flag in ht,
- // set the way's flag in ht and write the ids
- // of all the way's members (use cwn_);
- if((oo__ifp->deleteobject==0) ^ oo__ifp->subtract) {
- // object is not to delete
- if(otype==1 && hash_geti(1,id)) {
- // way AND is marked in ht
- // store ids of all referenced nodes of this way
- refidp= refid;
- while(refidp<refide) { // for every referenced node
- cwn_ref(*refidp);
- refidp++;
- } // end for every referenced node
- } // way
- } // object is not to delete
-continue; // do not write this object
- } // dependencystage 12
- else if(dependencystage==21) {
- // 21: no output;
- // for each node inside the borders,
- // set flag in ht;
- // for each way with a member with a flag in ht,
- // set the way's flag in ht and write the ids
- // of all the way's members (use cwn_);
- if((oo__ifp->deleteobject==0) ^ oo__ifp->subtract) {
- // object is not to delete
- if(otype==0) { // node
- if(!border_active || border_queryinside(lon,lat))
- // no border to be applied OR node lies inside
- hash_seti(0,id); // mark this node id as 'inside'
- } // node
- else if(otype==1) { // way
- refidp= refid;
- while(refidp<refide) { // for every referenced node
- if(hash_geti(0,*refidp))
- break;
- refidp++;
- } // end for every referenced node
- if(refidp<refide) { // at least on node lies inside
- hash_seti(1,id); // memorize that this way lies inside
- // store ids of all referenced nodes of this way
- refidp= refid;
- while(refidp<refide) { // for every referenced node
- cwn_ref(*refidp);
- refidp++;
- } // end for every referenced node
- } // at least on node lies inside
- } // way
- else { // relation
- oo__ifp->endoffile= true; // suppress warnings
- oo__close(); // the next stage will be entered as soon as
- // all files have been closed;
- // 21->22: as soon as first relation shall be written:
- // rewind all files;
- // set flags for nodes, use cwn_processing();
- } // relation
- } // object is not to delete
-continue; // do not write this object
- } // dependencystage 21
- else if(otype==2) { // relation
- if(!global_droprelations &&
- (dependencystage==31 || dependencystage==22)) {
- // not relations to drop AND
- // 22: write each node which has a flag in ht to output;
- // write each way which has a flag in ht to output;
- // 31: for each node inside the borders,
- // set flag in ht;
- // for each way with a member with a flag in ht,
- // set the way's flag in ht;
- // 22->32: as soon as first relation shall be written:
- // clear flags for ways, use cww_processing_clear();
- // switch output to temporary file;
- // 31->32: as soon as first relation shall be written:
- // switch output to temporary .o5m file;
- wo_flush();
- if(write_newfile(o5mtempfile))
-return 24;
- wo_format(0);
- if(hashactive)
- if(rr_ini(global_tempfilename))
-return 25;
- if(dependencystage==22)
- cww_processing_clear();
- if(global_calccoords!=0)
- if(posr_ini(global_tempfilename))
-return 26;
- oo__dependencystage(32);
- // 32: for each relation with a member with a flag
- // in ht, set the relation's flag in ht;
- // for each relation,
- // write its id and its members' ids
- // into a temporary file (use rr_);
- // if option --all-to-nodes is set, then
- // for each relation, write its members'
- // geopositions into a temporary file (use posr_);
- } // dependencystage was 31
- } // relation
- else { // node or way
- } // node or way
- // end care about dependency stages
-
- // process object deletion
- if((oo__ifp->deleteobject!=0) ^ oo__ifp->subtract) {
- // object is to delete
- if((otype==0 && !global_dropnodes) ||
- (otype==1 && !global_dropways) ||
- (otype==2 && !global_droprelations))
- // section is not to drop anyway
- if(global_outo5c || global_outosc || global_outosh)
- // write o5c, osc or osh file
- wo_delete(otype,id,hisver,histime,hiscset,hisuid,hisuser);
- // write delete request
- continue; // end processing for this object
- } // end object is to delete
-
- // care about object statistics
- if(global_statistics &&
- dependencystage!=32) {
- // not:
- // 32: for each relation with a member with a flag
- // in ht, set the relation's flag in ht;
- // for each relation,
- // write its id and its members' ids
- // into a temporary file (use rr_);
- // if option --all-to-nodes is set, then
- // for each relation, write its members'
- // geopositions into a temporary file (use posr_);
-
- if(otype==0) { // node
- if(statistics.nodes==0) { // this is the first node
- statistics.lon_min= statistics.lon_max= lon;
- statistics.lat_min= statistics.lat_max= lat;
- }
- statistics.nodes++;
- if(statistics.node_id_min==0 || id<statistics.node_id_min)
- statistics.node_id_min= id;
- if(statistics.node_id_max==0 || id>statistics.node_id_max)
- statistics.node_id_max= id;
- if(lon<statistics.lon_min)
- statistics.lon_min= lon;
- if(lon>statistics.lon_max)
- statistics.lon_max= lon;
- if(lat<statistics.lat_min)
- statistics.lat_min= lat;
- if(lat>statistics.lat_max)
- statistics.lat_max= lat;
- }
- else if(otype==1) { // way
- statistics.ways++;
- if(statistics.way_id_min==0 || id<statistics.way_id_min)
- statistics.way_id_min= id;
- if(statistics.way_id_max==0 || id>statistics.way_id_max)
- statistics.way_id_max= id;
- if(refide-refid>statistics.noderefs_max) {
- statistics.noderefs_oid= id;
- statistics.noderefs_max= refide-refid;
- }
- }
- else if(otype==2) { // relation
- statistics.relations++;
- if(statistics.relation_id_min==0 ||
- id<statistics.relation_id_min)
- statistics.relation_id_min= id;
- if(statistics.relation_id_max==0 ||
- id>statistics.relation_id_max)
- statistics.relation_id_max= id;
- if(refide-refid>statistics.relrefs_max) {
- statistics.relrefs_oid= id;
- statistics.relrefs_max= refide-refid;
- }
- }
- if(histime!=0) { // timestamp valid
- if(statistics.timestamp_min==0 ||
- histime<statistics.timestamp_min)
- statistics.timestamp_min= histime;
- if(statistics.timestamp_max==0 ||
- histime>statistics.timestamp_max)
- statistics.timestamp_max= histime;
- }
- if(keye-key>statistics.keyval_pairs_max) {
- statistics.keyval_pairs_otype= otype;
- statistics.keyval_pairs_oid= id;
- statistics.keyval_pairs_max= keye-key;
- }
- } // object statistics
-
- // abort writing if user does not want any standard output
- if(global_outnone)
- continue;
-
- // write the object
- if(otype==0) { // write node
- bool inside; // node lies inside borders, if appl.
-
- if(!border_active) // no borders shall be applied
- inside= true;
- else if(dependencystage==22)
- // 22: write each node which has a flag in ht to output;
- // write each way which has a flag in ht to output;
- inside= hash_geti(0,id);
- else {
- inside= border_queryinside(lon,lat); // node lies inside
- if(inside)
- hash_seti(0,id); // mark this node id as 'inside'
- }
- if(inside) { // node lies inside
- if(global_calccoords!=0) {
- // check id range
- if(id>=global_otypeoffset05 || id<=-global_otypeoffset05)
- WARNv("node id %"PRIi64
- " out of range. Increase --object-type-offset",id)
- posi_set(id,lon,lat); // store position
- }
- if(!global_dropnodes) { // not to drop
- wo_node(id,
- hisver,histime,hiscset,hisuid,hisuser,lon,lat);
- keyp= key; valp= val;
- while(keyp<keye) // for all key/val pairs of this object
- wo_node_keyval(*keyp++,*valp++);
- wo_node_close();
- } // end not to drop
- } // end node lies inside
- } // write node
- else if(otype==1) { // write way
- bool inside; // way lies inside borders, if appl.
-
- if(!hashactive) // no borders shall be applied
- inside= true;
- else if(dependencystage==22)
- // 22: write each node which has a flag in ht to output;
- // write each way which has a flag in ht to output;
- inside= hash_geti(1,id);
- else { // borders are to be applied
- inside= false; // (default)
- refidp= refid;
- while(refidp<refide) { // for every referenced node
- if(hash_geti(0,*refidp)) {
- inside= true;
- break;
- }
- refidp++;
- } // end for every referenced node
- } // end borders are to be applied
- if(inside) { // no borders OR at least one node inside
- if(hashactive)
- hash_seti(1,id); // memorize that this way lies inside
- if(!global_dropways) { // not ways to drop
- if(global_calccoords!=0) {
- // coordinates of ways shall be calculated
- int32_t x_min,x_max,y_min,y_max;
- int32_t x_middle,y_middle,xy_distance,new_distance;
- bool is_area;
- int n; // number of referenced nodes with coordinates
-
- // check id range
- if(id>=global_otypeoffset05 || id<=-global_otypeoffset05)
- WARNv("way id %"PRIi64
- " out of range. Increase --object-type-offset",id)
-
- // determine the center of the way's bbox
- n= 0;
- refidp= refid; refxyp= refxy;
- while(refidp<refide) { // for every referenced node
- *refxyp= NULL; // (default)
- if(!global_dropbrokenrefs || hash_geti(0,*refidp)) {
- // referenced node lies inside the borders
- posi_get(*refidp); // get referenced node's coordinates
- *refxyp= posi_xy;
- if(posi_xy!=NULL) { // coordinate is valid
- if(n==0) { // first coordinate
- // just store it as min and max
- x_min= x_max= posi_xy[0];
- y_min= y_max= posi_xy[1];
- }
- else { // additional coordinate
- // adjust extrema
- if(posi_xy[0]<x_min && x_min-posi_xy[0]<900000000)
- x_min= posi_xy[0];
- else if(posi_xy[0]>
- x_max && posi_xy[0]-x_max<900000000)
- x_max= posi_xy[0];
- if(posi_xy[1]<y_min)
- y_min= posi_xy[1];
- else if(posi_xy[1]>y_max)
- y_max= posi_xy[1];
- }
- n++;
- } // coordinate is valid
- } // referenced node lies inside the borders
- refidp++; refxyp++;
- } // end for every referenced node
-
- // determine if the way is an area
- is_area= refide!=refid && refide[-1]==refid[0];
- // first node is the same as the last one
-
- // determine the valid center of the way
- x_middle= x_max/2+x_min/2;
- y_middle= (y_max+y_min)/2;
- if(is_area) {
- lon= x_middle;
- lat= y_middle;
- }
- else { // the way is not an area
- // determine the node which has the smallest distance
- // to the center of the bbox
- n= 0;
- refidp= refid; refxyp= refxy;
- while(refidp<refide) { // for every referenced node
- posi_xy= *refxyp;
- if(posi_xy!=NULL) {
- // there is a coordinate for this reference
- if(n==0) { // first coordinate
- // just store it as min and max
- lon= posi_xy[0];
- lat= posi_xy[1];
- xy_distance= abs(lon-x_middle)+abs(lat-y_middle);
- }
- else { // additional coordinate
- new_distance= abs(posi_xy[0]-x_middle)+
- abs(posi_xy[1]-y_middle);
- if(new_distance<xy_distance) {
- lon= posi_xy[0];
- lat= posi_xy[1];
- xy_distance= new_distance;
- }
- } // additional coordinate
- n++;
- } // there is a coordinate for this reference
- refidp++; refxyp++;
- //break; //<- uncomment to use the first node of each way
- } // end for every referenced node
- } // the way is not an area
- if(global_calccoords>0)
- posi_set(id+global_otypeoffset10,lon,lat);
- else
- posi_setbbox(id+global_otypeoffset10,lon,lat,
- x_min,y_min,x_max,y_max);
- if(global_alltonodes) { // convert all objects to nodes
- // write a node as a replacement for the way
- if(n>0) { // there is at least one coordinate available
- int64_t id_new;
-
- if(global_otypeoffsetstep!=0)
- id_new= global_otypeoffsetstep++;
- else
- id_new= id+global_otypeoffset10;
- wo_node(id_new,
- hisver,histime,hiscset,hisuid,hisuser,lon,lat);
- if(global_add)
- wo_addbboxtags(true,x_min,y_min,x_max,y_max);
- keyp= key; valp= val;
- while(keyp<keye) // for all key/val pairs of this object
- wo_node_keyval(*keyp++,*valp++);
- wo_node_close();
- } // there is at least one coordinate available
- } // convert all objects to nodes
- else { // objects are not to be converted to nodes
- wo_way(id,hisver,histime,hiscset,hisuid,hisuser);
- refidp= refid;
- while(refidp<refide) { // for every referenced node
- if(!global_dropbrokenrefs || hash_geti(0,*refidp))
- // referenced node lies inside the borders
- wo_noderef(*refidp);
- refidp++;
- } // end for every referenced node
- if(global_add)
- wo_addbboxtags(false,x_min,y_min,x_max,y_max);
- keyp= key; valp= val;
- while(keyp<keye) // for all key/val pairs of this object
- wo_wayrel_keyval(*keyp++,*valp++);
- wo_way_close();
- } // objects are not to be converted to nodes
- } // coordinates of ways shall be calculated
- else { // coordinates of ways need not to be calculated
- wo_way(id,hisver,histime,hiscset,hisuid,hisuser);
- refidp= refid;
- while(refidp<refide) { // for every referenced node
- if(!global_dropbrokenrefs || hash_geti(0,*refidp))
- // referenced node lies inside the borders
- wo_noderef(*refidp);
- refidp++;
- } // end for every referenced node
- keyp= key; valp= val;
- while(keyp<keye) // for all key/val pairs of this object
- wo_wayrel_keyval(*keyp++,*valp++);
- wo_way_close();
- } // coordinates of ways need not to be calculated
- } // end not ways to drop
- } // end no border OR at least one node inside
- } // write way
- else if(otype==2) { // write relation
- if(!global_droprelations) { // not relations to drop
- bool inside; // relation may lie inside borders, if appl.
- bool in; // relation lies inside borders
- int64_t ri; // temporary, refid
- int rt; // temporary, reftype
- char* rr; // temporary, refrole
-
- in= hash_geti(2,id);
- if(dependencystage==32) {
- // 32: for each relation with a member with a flag
- // in ht, set the relation's flag in ht;
- // for each relation,
- // write its id and its members' ids
- // into a temporary file (use rr_);
- // if option --all-to-nodes is set, then
- // for each relation, write its members'
- // geopositions into a temporary file (use posr_);
- bool has_highway,has_area; // relation has certain tags
- bool is_area; // the relation is assumed to represent an area
- bool idwritten,posridwritten;
-
- // determine if this relation is assumed to represent
- // an area or not
- has_highway= has_area= false;
- keyp= key; valp= val;
- while(keyp<keye) { // for all key/val pairs of this object
- if(strcmp(*keyp,"highway")==0 ||
- strcmp(*keyp,"waterway")==0 ||
- strcmp(*keyp,"railway")==0 ||
- strcmp(*keyp,"aerialway")==0 ||
- strcmp(*keyp,"power")==0 ||
- strcmp(*keyp,"route")==0
- )
- has_highway= true;
- else if(strcmp(*keyp,"area")==0 &&
- strcmp(*valp,"yes")==0)
- has_area= true;
- keyp++,valp++;
- }
- is_area= !has_highway || has_area;
-
- // write the id of this relation and its members
- // to a temporary file
- idwritten= posridwritten= false;
- refidp= refid; reftypep= reftype;
- while(refidp<refide) { // for every referenced object
- ri= *refidp;
- rt= *reftypep;
- if(hashactive) {
- if(rt==2) { // referenced object is a relation
- if(!idwritten) { // did not yet write our relation's id
- rr_rel(id); // write it now
- idwritten= true;
- }
- rr_ref(ri);
- }
- }
- if(global_calccoords!=0) {
- if(!posridwritten) {
- // did not yet write our relation's id
- // write it now
- posr_rel(id,is_area);
- posi_set(id+global_otypeoffset20,posi_nil,0);
- // reserve space for this relation's coordinates
- posridwritten= true;
- }
- if(rt==1) // way
- ri+= global_otypeoffset10;
- else if(rt==2) // relation
- ri+= global_otypeoffset20;
- posr_ref(ri);
- }
- refidp++; reftypep++;
- } // end for every referenced object
- inside= true;
- }
- else if(dependencystage==33) {
- // 33: write each relation which has a flag in ht
- // to output; use temporary .o5m file as input;
- inside= in;
- }
- else
- inside= true;
- if(inside) { // no borders OR at least one node inside
- if(global_alltonodes && dependencystage==33) {
- // all relations are to be converted to nodes AND
- // 33: write each relation which has a flag in ht
- // to output; use temporary .o5m file as input;
- if(id>=global_otypeoffset05 || id<=-global_otypeoffset05)
- WARNv("relation id %"PRIi64
- " out of range. Increase --object-type-offset",id)
- posi_get(id+global_otypeoffset20); // get coordinates
- if(posi_xy!=NULL && posi_xy[0]!=posi_nil) {
- // stored coordinates are valid
- int64_t id_new;
-
- if(global_otypeoffsetstep!=0)
- id_new= global_otypeoffsetstep++;
- else
- id_new= id+global_otypeoffset20;
- // write a node as a replacement for the relation
- wo_node(id_new,
- hisver,histime,hiscset,hisuid,hisuser,
- posi_xy[0],posi_xy[1]);
- if(global_add)
- wo_addbboxtags(true,
- posi_xy[2],posi_xy[3],posi_xy[4],posi_xy[5]);
- keyp= key; valp= val;
- while(keyp<keye) // for all key/val pairs of this object
- wo_node_keyval(*keyp++,*valp++);
- wo_node_close();
- } // stored coordinates are valid
- } // relations are to be converted to nodes
- else { // dependencystage!=33 OR not --all-to-nodes
- wo_relation(id,hisver,histime,hiscset,hisuid,hisuser);
- refidp= refid; reftypep= reftype; refrolep= refrole;
- while(refidp<refide) { // for every referenced object
- ri= *refidp;
- rt= *reftypep;
- rr= *refrolep;
-
- if(dependencystage<33) {
- // not:
- // 33: write each relation which has a flag in ht
- // to output;
- // use temporary .o5m file as input;
- if(rt==2 || hash_geti(rt,ri)) {
- // referenced object is a relation OR
- // lies inside the borders
- wo_ref(ri,rt,rr);
- if(rt!=2 && !in) {
- hash_seti(2,id); in= true; }
- }
- else { // referenced object lies outside the borders
- if(!global_dropbrokenrefs) {
- wo_ref(ri,rt,rr);
- }
- }
- }
- else { // dependencystage==33
- // 33: write each relation which has a flag in ht
- // to output;
- // use temporary .o5m file as input;
- if(!global_dropbrokenrefs || hash_geti(rt,ri)) {
- // broken refs are to be listed anyway OR
- // referenced object lies inside the borders
- wo_ref(ri,rt,rr);
- }
- }
- refidp++; reftypep++; refrolep++;
- } // end for every referenced object
- if(global_add) {
- posi_get(id+global_otypeoffset20); // get coordinates
- if(posi_xy!=NULL && posi_xy[0]!=posi_nil)
- // stored coordinates are valid
- wo_addbboxtags(false,
- posi_xy[2],posi_xy[3],posi_xy[4],posi_xy[5]);
- }
- keyp= key; valp= val;
- while(keyp<keye) // for all key/val pairs of this object
- wo_wayrel_keyval(*keyp++,*valp++);
- wo_relation_close();
- } // stage!=3 OR not --all-to-nodes
- } // end no borders OR at least one node inside
- } // end not relations to drop
- } // write relation
- } // end read all input files
- if(!global_outnone) {
- if(writeheader)
- wo_start(wformat,oo__bbvalid,
- oo__bbx1,oo__bby1,oo__bbx2,oo__bby2,oo__timestamp);
- wo_end();
- }
- if(global_statistics) { // print statistics
- FILE* fi;
- if(global_outstatistics) fi= stdout;
- else fi= stderr;
-
- if(statistics.timestamp_min!=0) {
- char timestamp[30];
-
- write_createtimestamp(statistics.timestamp_min,timestamp);
- fprintf(fi,"timestamp min: %s\n",timestamp);
- }
- if(statistics.timestamp_max!=0) {
- char timestamp[30];
-
- write_createtimestamp(statistics.timestamp_max,timestamp);
- fprintf(fi,"timestamp max: %s\n",timestamp);
- }
- if(statistics.nodes>0) { // at least one node
- char coord[20];
-
- write_createsfix7o(statistics.lon_min,coord);
- fprintf(fi,"lon min: %s\n",coord);
- write_createsfix7o(statistics.lon_max,coord);
- fprintf(fi,"lon max: %s\n",coord);
- write_createsfix7o(statistics.lat_min,coord);
- fprintf(fi,"lat min: %s\n",coord);
- write_createsfix7o(statistics.lat_max,coord);
- fprintf(fi,"lat max: %s\n",coord);
- }
- fprintf(fi,"nodes: %"PRIi64"\n",statistics.nodes);
- fprintf(fi,"ways: %"PRIi64"\n",statistics.ways);
- fprintf(fi,"relations: %"PRIi64"\n",statistics.relations);
- if(statistics.node_id_min!=0)
- fprintf(fi,"node id min: %"PRIi64"\n",statistics.node_id_min);
- if(statistics.node_id_max!=0)
- fprintf(fi,"node id max: %"PRIi64"\n",statistics.node_id_max);
- if(statistics.way_id_min!=0)
- fprintf(fi,"way id min: %"PRIi64"\n",statistics.way_id_min);
- if(statistics.way_id_max!=0)
- fprintf(fi,"way id max: %"PRIi64"\n",statistics.way_id_max);
- if(statistics.relation_id_min!=0)
- fprintf(fi,"relation id min: %"PRIi64"\n",
- statistics.relation_id_min);
- if(statistics.relation_id_max!=0)
- fprintf(fi,"relation id max: %"PRIi64"\n",
- statistics.relation_id_max);
- if(statistics.keyval_pairs_max!=0) {
- fprintf(fi,"keyval pairs max: %"PRIi32"\n",
- statistics.keyval_pairs_max);
- fprintf(fi,"keyval pairs max object: %s %"PRIi64"\n",
- ONAME(statistics.keyval_pairs_otype),
- statistics.keyval_pairs_oid);
- }
- if(statistics.noderefs_max!=0) {
- fprintf(fi,"noderefs max: %"PRIi32"\n",
- statistics.noderefs_max);
- fprintf(fi,"noderefs max object: way %"PRIi64"\n",
- statistics.noderefs_oid);
- }
- if(statistics.relrefs_max!=0) {
- fprintf(fi,"relrefs max: %"PRIi32"\n",
- statistics.relrefs_max);
- fprintf(fi,"relrefs max object: relation %"PRIi64"\n",
- statistics.relrefs_oid);
- }
- } // print statistics
- return oo__error;
- } // end oo_main()
-
-//------------------------------------------------------------
-// end Module oo_ osm to osm module
-//------------------------------------------------------------
-
-
-
-static void assistant_end();
-
-static bool assistant(int* argcp,char*** argvp) {
- // interactively guide the user through basic functions;
- // argcp==NULL AND argvp==NULL: to confirm that the calculation
- // has been terminated correctly;
- // argcp==NULL AND argvp!=NULL:
- // display 'bye message', do nothing else (third call);
- // usually, this procedure must be called twice: first, before
- // parsing the command line arguments, and second, after
- // the regular processing has been done without any error;
- // the third call will be done by atexit();
- // return: user wants to terminate the program;
- #define langM 2
- static int lang= 0;
- static const char* talk_lang1[langM]= { "", "de_" };
- static const char* talk_lang2[langM]= { "", "German_" };
- static const char* talk_section[langM]= {
- "-----------------------------------------------------------------\n"
- };
- static const char* talk_intro[langM]= {
- "\n"
- "osmconvert "VERSION"\n"
- "\n"
- "Converts .osm, .o5m, .pbf, .osc, .osh files, applies changes\n"
- "of .osc, .o5c, .osh files and sets limiting borders.\n"
- "Use command line option -h to get a parameter overview,\n"
- "or --help to get detailed help.\n"
- "\n"
- "If you are familiar with the command line, press <Return>.\n"
- "\n"
- "If you do not know how to operate the command line, please\n"
- "enter \"a\" (press key E and hit <Return>).\n"
- ,
- "\n"
- "osmconvert "VERSION"\n"
- "\n"
- "Konvertiert .osm-, .o5m-, .pbf-, .osc- und .osh-Dateien,\n"
- "spielt Updates von .osc-, .o5c- und .osh-Dateien ein und\n"
- "setzt geografische Grenzen.\n"
- "Die Kommandozeilenoption -h zeigt eine Parameteruebersicht,\n"
- "--help bringt eine detaillierte Hilfe (in Englisch).\n"
- "\n"
- "Wenn Sie mit der Kommandozeile vertraut sind, druecken Sie\n"
- "bitte <Return>.\n"
- "\n"
- "Falls Sie sich mit der Kommandozeile nicht auskennen, druecken\n"
- "Sie bitte \"a\" (Taste A und dann die Eingabetaste).\n"
- };
- static const char* talk_hello[langM]= {
- "Hi, I am osmconBert - just call me Bert.\n"
- "I will guide you through the basic functions of osmconvert.\n"
- "\n"
- "At first, please ensure to have the \"osmconvert\" file\n"
- "(resp. \"osmconvert.exe\" file if Windows) located in the\n"
- "same directory in which all your OSM data is stored.\n"
- "\n"
- "You may exit this program whenever you like. Just hold\n"
- "the <Ctrl> key and press the key C.\n"
- "\n"
- ,
- "Hallo, ich bin osmconBert - nennen Sie mich einfach Bert.\n"
- "Ich werde Sie durch die Standardfunktionen von osmconvert leiten.\n"
- "\n"
- "Bitte stellen Sie zuerst sicher, dass sich die Programmdatei\n"
- "\"osmconvert\" (bzw. \"osmconvert.exe\" im Fall von Windows) im\n"
- "gleichen Verzeichnis befindet wie Ihre OSM-Dateien.\n"
- "\n"
- "Sie koennen das Programm jederzeit beenden. Halten Sie dazu die\n"
- "<Strg>-Taste gedrueckt und druecken die Taste C.\n"
- "\n"
- };
- static const char* talk_input_file[langM]= {
- "Please please tell me the name of the file you want to process:\n"
- ,
- "Bitte nennen Sie mir den Namen der Datei, die verarbeitet werden soll:\n"
- };
- static const char* talk_not_found[langM]= {
- "Sorry, I cannot find a file with this name in the current directory.\n"
- "\n"
- ,
- "Sorry, ich kann diese Datei im aktuellen Verzeichnis nicht finden.\n"
- "\n"
- };
- static const char* talk_input_file_suffix[langM]= {
- "Sorry, the file must have \".osm\", \".o5m\" or \".pbf\" as suffix.\n"
- "\n"
- ,
- "Sorry, die Datei muss \".osm\", \".o5m\" oder \".pbf\" als Endung haben.\n"
- "\n"
- };
- static const char* talk_thanks[langM]= {
- "Thanks!\n"
- ,
- "Danke!\n"
- };
- static const char* talk_function[langM]= {
- "What may I do with this file?\n"
- "\n"
- " 1 convert it to a different file format\n"
- " 2 use an OSM Changefile to update this file\n"
- " 3 use a border box to limit the geographical region\n"
- " 4 use a border polygon file to limit the geographical region\n"
- " 5 minimize file size by deleting author information\n"
- " 6 display statistics of the file\n"
- "To options 3 or 4 you may also choose:\n"
- " a keep ways complete, even if they cross the border\n"
- " b keep ways and areas complete, even if they cross the border\n"
- "\n"
- "Please enter the number of one or more functions you choose:\n"
- ,
- "Was soll ich mit dieser Datei tun?\n"
- "\n"
- " 1 in ein anderes Format umwandeln\n"
- " 2 sie per OSM-Change-Datei aktualisieren\n"
- " 3 per Laengen- und Breitengrad einen Bereich ausschneiden\n"
- " 4 mit einer Polygon-Datei einen Bereich ausschneiden\n"
- " 5 Autorinformationen loeschen,damit Dateigroesse minimieren\n"
- " 6 statistische Daten zu dieser Datei anzeigen\n"
- "Zu den Optionen 3 oder 4 koennen zusaetzlich gewaehlt werden:\n"
- " a grenzueberschreitende Wege als Ganzes behalten\n"
- " b grenzueberschreitende Wege und Flaechen als Ganzes behalten\n"
- "\n"
- "Bitte waehlen Sie die Nummer(n) von einer oder mehreren Funktionen:\n"
- };
- static const char* talk_all_right[langM]= {
- "All right.\n"
- ,
- "Geht in Ordnung.\n"
- };
- static const char* talk_cannot_understand[langM]= {
- "Sorry, I could not understand.\n"
- "\n"
- ,
- "Sorry, das habe ich nicht verstanden.\n"
- "\n"
- };
- static const char* talk_two_borders[langM]= {
- "Please do not choose both, border box and border polygon.\n"
- "\n"
- ,
- "Bitte nicht beide Arten des Ausschneidens gleichzeitig waehlen.\n"
- "\n"
- };
- static const char* talk_changefile[langM]= {
- "Please tell me the name of the OSM Changefile:\n"
- ,
- "Bitte nennen Sie mir den Namen der OSM-Change-Datei:\n"
- };
- static const char* talk_changefile_suffix[langM]= {
- "Sorry, the Changefile must have \".osc\" or \".o5c\" as suffix.\n"
- "\n"
- ,
- "Sorry, die Change-Datei muss \".osc\" oder \".o5c\" als Endung haben.\n"
- "\n"
- };
- static const char* talk_polygon_file[langM]= {
- "Please tell me the name of the polygon file:\n"
- ,
- "Bitte nennen Sie mir den Namen der Polygon-Datei:\n"
- };
- static const char* talk_polygon_file_suffix[langM]= {
- "Sorry, the polygon file must have \".poly\" as suffix.\n"
- "\n"
- ,
- "Sorry, die Polygon-Datei muss \".poly\" als Endung haben.\n"
- "\n"
- };
- static const char* talk_coordinates[langM]= {
- "We need the coordinates of the border box.\n"
- "The unit is degree, just enter each number, e.g.: -35.75\n"
- ,
- "Wir brauchen die Bereichs-Koordinaten in Grad,\n"
- "aber jeweils ohne Einheitenbezeichnung, also z.B.: 7,75\n"
- };
- static const char* talk_minlon[langM]= {
- "Please tell me the minimum longitude:\n"
- ,
- "Bitte nennen Sie mir den Minimum-Laengengrad:\n"
- };
- static const char* talk_maxlon[langM]= {
- "Please tell me the maximum longitude:\n"
- ,
- "Bitte nennen Sie mir den Maximum-Laengengrad:\n"
- };
- static const char* talk_minlat[langM]= {
- "Please tell me the minimum latitude:\n"
- ,
- "Bitte nennen Sie mir den Minimum-Breitengrad:\n"
- };
- static const char* talk_maxlat[langM]= {
- "Please tell me the maximum latitude:\n"
- ,
- "Bitte nennen Sie mir den Maximum-Breitengrad:\n"
- };
- static const char* talk_output_format[langM]= {
- "Please choose the output file format:\n"
- "\n"
- "1 .osm (standard XML format - results in very large files)\n"
- "2 .o5m (binary format - allows fast)\n"
- "3 .pbf (standard binary format - results in small files)\n"
- "\n"
- "Enter 1, 2 or 3:\n"
- ,
- "Bitte waehlen Sie das Format der Ausgabe-Datei:\n"
- "\n"
- "1 .osm (Standard-XML-Format - ergibt sehr grosse Dateien)\n"
- "2 .o5m (binaeres Format - recht schnell)\n"
- "3 .pbf (binaeres Standard-Format - ergibt kleine Dateien)\n"
- "\n"
- "1, 2 oder 3 eingeben:\n"
- };
- static const char* talk_working[langM]= {
- "Now, please hang on - I am working for you.\n"
- "If the input file is very large, this will take several minutes.\n"
- "\n"
- "If you want to get acquainted with the much more powerful\n"
- "command line, this would have been your command:\n"
- "\n"
- ,
- "Einen Moment bitte - ich arbeite fuer Sie.\n"
- "Falls die Eingabe-Datei sehr gross ist, dauert das einige Minuten.\n"
- "\n"
- "Fall Sie sich mit der viel leistungsfaehigeren Kommandozeilen-\n"
- "eingabe vertraut machen wollen, das waere Ihr Kommando gewesen:\n"
- "\n"
- };
- static const char* talk_finished[langM]= {
- "Finished! Calculation time: "
- ,
- "Fertig! Berechnungsdauer: "
- };
- static const char* talk_finished_file[langM]= {
- "I just completed your new file with this name:\n"
- ,
- "Soeben habe ich Ihre neue Datei mit diesem Namen fertiggestellt:\n"
- };
- static const char* talk_error[langM]= {
- "I am sorry, an error has occurred (see above).\n"
- ,
- "Es tut mir Leid, es ist ein Fehler aufgetreten (siehe oben).\n"
- };
- static const char* talk_bye[langM]= {
- "\n"
- "Thanks for visiting me. Bye!\n"
- "Yours, Bert\n"
- "(To close this window, please press <Return>.)\n"
- ,
- "\n"
- "Danke fuer Ihren Besuch. Tschues!\n"
- "Schoene Gruesse - Bert\n"
- "(Zum Schließen dieses Fensters bitte die Eingabetaste druecken.)\n"
- };
- #define DD(s) fprintf(stderr,"%s",(s[lang])); // display text
- #define DI(s) s[0]= 0; UR(fgets(s,sizeof(s),stdin)) \
- if(strchr(s,'\r')!=NULL) *strchr(s,'\r')= 0; \
- if(strchr(s,'\n')!=NULL) *strchr(s,'\n')= 0; // get user's response
- bool
- function_convert= false,
- function_update= false,
- function_border_box= false,
- function_border_polygon= false,
- function_drop_author= false,
- function_statistics= false;
- int function_cut_mode= 0;
- // 0: normal; 1: complete ways; 2: complex ways;
- static bool function_only_statistics= false;
- static time_t start_time;
- bool verbose;
- char s[500]; // temporary string for several purposes
- char* sp;
- static char input_file[500];
- bool file_type_osm,file_type_osc,file_type_o5m,file_type_o5c,
- file_type_pbf;
- static char changefile[500];
- char polygon_file[500];
- char minlon[30],maxlon[30],minlat[30],maxlat[30];
- static char output_file[550]= ""; // the first three characters
- // are reserved for the commandline option "-o="
- int i;
-
- // display 'bye message' - if requested
- if(argcp==NULL) {
- static bool no_error= false;
-
- if(argvp==NULL)
- no_error= true;
- else {
- if(output_file[0]!=0) {
- DD(talk_section)
- if(no_error) {
- DD(talk_finished)
- fprintf(stderr,"%"PRIi64"s.\n",
- (int64_t)(time(NULL)-start_time));
- DD(talk_finished_file)
- fprintf(stderr," %s",output_file+3);
- }
- else
- DD(talk_error)
- DD(talk_bye)
- DI(s)
- }
- else if(function_only_statistics) {
- DD(talk_section)
- if(no_error) {
- DD(talk_finished)
- fprintf(stderr,"%"PRIi64"s.\n",
- (int64_t)(time(NULL)-start_time));
- }
- else
- DD(talk_error)
- DD(talk_bye)
- DI(s)
- }
- }
-return false;
- }
-
- // initialization
- atexit(assistant_end);
- for(i= 1; i<langM; i++) {
- talk_section[i]= talk_section[0];
- // (this dialog text is the same for all languages)
- }
- verbose= false;
-
- /* get system language */ {
- const char* syslang;
-
- syslang= setlocale(LC_ALL,"");
- lang= langM;
- while(--lang>0)
- if(syslang!=NULL &&
- (strzcmp(syslang,talk_lang1[lang])==0 ||
- strzcmp(syslang,talk_lang2[lang])==0)) break;
- setlocale(LC_ALL,"C"); // switch back to C standard
- }
-
- // introduction
- DD(talk_intro)
- DI(s)
- sp= s;
- while(*sp==' ') sp++; // dispose of leading spaces
- if((*sp!='a' && *sp!='A') || sp[1]!=0)
-return true;
- verbose= isupper(*(unsigned char*)sp);
-
- // choose input file
- DD(talk_section)
- DD(talk_hello)
- for(;;) {
- DD(talk_input_file)
- DI(input_file)
- file_type_osm= strycmp(input_file,".osm")==0;
- file_type_osc= strycmp(input_file,".osc")==0;
- file_type_o5m= strycmp(input_file,".o5m")==0;
- file_type_o5c= strycmp(input_file,".o5c")==0;
- file_type_pbf= strycmp(input_file,".pbf")==0;
- if(!file_type_osm && !file_type_osc && !file_type_o5m &&
- !file_type_o5c && !file_type_pbf) {
- DD(talk_input_file_suffix)
- continue;
- }
- if(input_file[strcspn(input_file,"\"\', :;|&\\")]!=0 ||
- !file_exists(input_file)) {
- DD(talk_not_found)
- continue;
- }
- break;
- }
- DD(talk_thanks)
-
- // choose function
- DD(talk_section)
- for(;;) {
- function_convert= function_update= function_border_polygon=
- function_border_box= function_statistics= false;
- DD(talk_function)
- DI(s)
- i= 0; // here: number of selected functions
- sp= s;
- while(*sp!=0) {
- if(*sp=='1')
- function_convert= true;
- else if(*sp=='2')
- function_update= true;
- else if(*sp=='3')
- function_border_box= true;
- else if(*sp=='4')
- function_border_polygon= true;
- else if(*sp=='5')
- function_drop_author= true;
- else if(*sp=='6')
- function_statistics= true;
- else if(*sp=='a' || *sp=='A') {
- if(function_cut_mode==0)
- function_cut_mode= 1;
- }
- else if(*sp=='b' || *sp=='B')
- function_cut_mode= 2;
- else if(*sp==' ' || *sp==',' || *sp==';') {
- sp++;
- continue;
- }
- else { // syntax error
- i= 0; // ignore previous input
- break;
- }
- i++; sp++;
- }
- if(function_border_box && function_border_polygon) {
- DD(talk_two_borders)
- continue;
- }
- if(i==0) { // no function has been chosen OR syntax error
- DD(talk_cannot_understand)
- continue;
- }
- if(function_cut_mode!=0 &&
- !function_border_box && !function_border_polygon)
- function_border_box= true;
- break;
- }
- function_only_statistics= function_statistics &&
- !function_convert && !function_update &&
- !function_border_polygon && !function_border_box;
- DD(talk_all_right)
-
- // choose OSM Changefile
- if(function_update) {
- DD(talk_section)
- for(;;) {
- DD(talk_changefile)
- DI(changefile)
- if(strycmp(changefile,".osc")!=0 &&
- strycmp(changefile,".o5c")!=0) {
- DD(talk_changefile_suffix)
- continue;
- }
- if(changefile[strcspn(changefile,"\"\' ,:;|&\\")]!=0 ||
- !file_exists(changefile)) {
- DD(talk_not_found)
- continue;
- }
- break;
- }
- DD(talk_thanks)
- }
-
- // choose polygon file
- if(function_border_polygon) {
- DD(talk_section)
- for(;;) {
- DD(talk_polygon_file)
- DI(polygon_file)
- if(strycmp(polygon_file,".poly")!=0) {
- DD(talk_polygon_file_suffix)
- continue;
- }
- if(polygon_file[strcspn(polygon_file,"\"\' ,:;|&\\")]!=0 ||
- !file_exists(polygon_file)) {
- DD(talk_not_found)
- continue;
- }
- break;
- }
- DD(talk_thanks)
- }
-
- // choose coordinates
- if(function_border_box) {
- DD(talk_section)
- for(;;) {
- #define D(s) DI(s) \
- while(strchr(s,',')!=NULL) *strchr(s,',')= '.'; \
- if(s[0]==0 || s[strspn(s,"0123456789.-")]!=0) { \
- DD(talk_cannot_understand) continue; }
- DD(talk_coordinates)
- DD(talk_minlon)
- D(minlon)
- DD(talk_minlat)
- D(minlat)
- DD(talk_maxlon)
- D(maxlon)
- DD(talk_maxlat)
- D(maxlat)
- #undef D
- break;
- }
- DD(talk_thanks)
- }
-
- // choose file type
- if(function_convert) {
- file_type_osm= file_type_osc= file_type_o5m=
- file_type_o5c= file_type_pbf= false;
- DD(talk_section)
- for(;;) {
- DD(talk_output_format)
- DI(s)
- sp= s; while(*sp==' ') sp++; // ignore spaces
- if(*sp=='1')
- file_type_osm= true;
- else if(*sp=='2')
- file_type_o5m= true;
- else if(*sp=='3')
- file_type_pbf= true;
- else {
- DD(talk_cannot_understand)
- continue;
- }
- break;
- }
- DD(talk_thanks)
- }
-
- // assemble output file name
- DD(talk_section)
- if(!function_only_statistics) {
- if(file_type_osm) strcpy(s,".osm");
- if(file_type_osc) strcpy(s,".osc");
- if(file_type_o5m) strcpy(s,".o5m");
- if(file_type_o5c) strcpy(s,".o5c");
- if(file_type_pbf) strcpy(s,".pbf");
- sp= stpcpy0(output_file,"-o=");
- strcpy(sp,input_file);
- sp= strrchr(sp,'.');
- if(sp==NULL) sp= strchr(output_file,0);
- i= 1;
- do
- sprintf(sp,"_%02i%s",i,s);
- while(++i<9999 && file_exists(output_file+3));
- }
-
- /* create new commandline arguments */ {
- int argc;
- static char* argv[10];
- static char border[550];
-
- argc= 0;
- argv[argc++]= (*argvp)[0]; // save program name
- if(verbose)
- argv[argc++]= "-v"; // activate verbose mode
- argv[argc++]= input_file;
- if(function_update)
- argv[argc++]= changefile;
- if(function_border_polygon) {
- sp= stpcpy0(border,"-B=");
- strcpy(sp,polygon_file);
- argv[argc++]= border;
- }
- else if(function_border_box) {
- sprintf(border,"-b=%s,%s,%s,%s",minlon,minlat,maxlon,maxlat);
- argv[argc++]= border;
- }
- if(function_drop_author)
- argv[argc++]= "--drop-author";
- if(function_cut_mode==1)
- argv[argc++]= "--complete-ways";
- if(function_cut_mode==2)
- argv[argc++]= "--complex-ways";
- if(function_only_statistics)
- argv[argc++]= "--out-statistics";
- else if(function_statistics)
- argv[argc++]= "--statistics";
- if(output_file[0]!=0) {
- if(file_type_osm) argv[argc++]= "--out-osm";
- else if(file_type_osc) argv[argc++]= "--out-osc";
- else if(file_type_o5m) argv[argc++]= "--out-o5m";
- else if(file_type_o5c) argv[argc++]= "--out-o5c";
- else if(file_type_pbf) argv[argc++]= "--out-pbf";
- argv[argc++]= output_file;
- }
- // return commandline variables
- *argcp= argc;
- *argvp= argv;
-
- // display the virtual command line
- DD(talk_working)
- fprintf(stderr,"osmconvert");
- i= 0;
- while(++i<argc)
- fprintf(stderr," %s",argv[i]);
- fprintf(stderr,"\n");
- DD(talk_section)
- }
-
- start_time= time(NULL);
- #undef langM
- #undef DP
- #undef DI
- return false;
- } // assistant()
-
-static void assistant_end() {
- // will be called via atexit()
- assistant(NULL,(char***)assistant_end);
- } // assistant_end()
-
-
-
-#if !__WIN32__
-void sigcatcher(int sig) {
- fprintf(stderr,"osmconvert: Output has been terminated.\n");
- exit(1);
- } // end sigcatcher()
-#endif
-
-int main(int argc,char** argv) {
- // main program;
- // for the meaning of the calling line parameters please look at the
- // contents of helptext[];
- bool usesstdin;
- static char outputfilename[400]= ""; // standard output file name
- // =="": standard output 'stdout'
- int h_n,h_w,h_r; // user-suggested hash size in MiB, for
- // hash tables of nodes, ways, and relations;
- int r,l;
- const char* a; // command line argument
- static FILE* parafile= NULL;
- static char* aa= NULL; // buffer for parameter file line
- char* ap; // pointer in aa[]
- int aamax; // maximum length of string to read
- #define main__aaM 1000000
-
- #if !__WIN32__
- /* care about signal handler */ {
- static struct sigaction siga;
-
- siga.sa_handler= sigcatcher;
- sigemptyset(&siga.sa_mask);
- siga.sa_flags= 0;
- sigaction(SIGPIPE,&siga,NULL);
- }
- #endif
-
- // initializations
- usesstdin= false;
- h_n= h_w= h_r= 0;
- #if __WIN32__
- setmode(fileno(stdout),O_BINARY);
- setmode(fileno(stdin),O_BINARY);
- #endif
-
- // read command line parameters
- if(argc<=1) { // no command line parameters given
- if(assistant(&argc,&argv)) // call interactive program guide
-return 0;
- }
- while(parafile!=NULL || argc>0) {
- // for every parameter in command line
- if(parafile!=NULL) do {
- // there are parameters waiting in a parameter file
- ap= aa;
- for(;;) {
- aamax= main__aaM-1-(ap-aa);
- if(fgets(ap,aamax,parafile)==NULL) {
- if(ap>aa) {
- if(ap>aa && ap[-1]==' ')
- *--ap= 0; // cut one trailing space
- break;
- }
- goto parafileend;
- }
- if(strzcmp(ap,"// ")==0)
- continue;
- if(ap>aa && (*ap=='\r' || *ap=='\n' || *ap==0)) {
- // end of this parameter
- while(ap>aa && (ap[-1]=='\r' || ap[-1]=='\n')) *--ap= 0;
- // eliminate trailing NL
- if(ap>aa && ap[-1]==' ')
- *--ap= 0; // cut one trailing space
- break;
- }
- ap= strchr(ap,0); // find end of string
- while(ap>aa && (ap[-1]=='\r' || ap[-1]=='\n'))
- *--ap= 0; // cut newline chars
- *ap++= ' '; *ap= 0; // add a space
- }
- a= aa;
- while(*a!=0 && strchr(" \t\r\n",*a)!=NULL) a++;
- if(*a!=0)
- break;
- parafileend:
- fclose(parafile); parafile= NULL;
- free(aa); aa= NULL;
- } while(false);
- if(parafile==NULL) {
- if(--argc<=0)
- break;
- argv++; // switch to next parameter; as the first one is just
- // the program name, we must do this previous reading the
- // first 'real' parameter;
- a= argv[0];
- }
- if((l= strzlcmp(a,"--parameter-file="))>0 && a[l]!=0) {
- // parameter file
- parafile= fopen(a+l,"r");
- if(parafile==NULL) {
- PERRv("Cannot open parameter file: %.80s",a+l)
- perror("osmconvert");
-return 1;
- }
- aa= (char*)malloc(main__aaM);
- if(aa==NULL) {
- PERR("Cannot get memory for parameter file.")
- fclose(parafile); parafile= NULL;
-return 1;
- }
- aa[0]= 0;
- continue; // take next parameter
- }
- if(loglevel>0) // verbose mode
- fprintf(stderr,"osmconvert Parameter: %.2000s\n",a);
- if(strcmp(a,"-h")==0) { // user wants parameter overview
- fprintf(stdout,"%s",shorthelptext); // print brief help text
- // (took "%s", to prevent oversensitive compiler reactions)
-return 0;
- }
- if(strcmp(a,"-help")==0 || strcmp(a,"--help")==0) {
- // user wants help text
- fprintf(stdout,"%s",helptext); // print help text
- // (took "%s", to prevent oversensitive compiler reactions)
-return 0;
- }
- if(strzcmp(a,"--diff-c")==0) {
- // user wants a diff file to be calculated
- global_diffcontents= true;
- global_diff= true;
- continue; // take next parameter
- }
- if(strcmp(a,"--diff")==0) {
- // user wants a diff file to be calculated
- global_diff= true;
- continue; // take next parameter
- }
- if(strcmp(a,"--subtract")==0) {
- // user wants to subtract any following input file
- global_subtract= true;
- continue; // take next parameter
- }
- if(strzcmp(a,"--drop-his")==0) {
- // (deprecated)
- PINFO("Option --drop-history is deprecated. Using --drop-author.");
- global_dropauthor= true;
- continue; // take next parameter
- }
- if(strzcmp(a,"--drop-aut")==0) {
- // user does not want author information in standard output
- global_dropauthor= true;
- continue; // take next parameter
- }
- if(strzcmp(a,"--drop-ver")==0) {
- // user does not want version number in standard output
- global_dropauthor= true;
- global_dropversion= true;
- continue; // take next parameter
- }
- if(strzcmp(a,"--fake-his")==0) {
- // (deprecated)
- PINFO("Option --fake-history is deprecated. Using --fake-author.");
- global_fakeauthor= true;
- continue; // take next parameter
- }
- if(strzcmp(a,"--fake-aut")==0) {
- // user wants faked author information
- global_fakeauthor= true;
- continue; // take next parameter
- }
- if(strzcmp(a,"--fake-ver")==0) {
- // user wants just a faked version number as meta data
- global_fakeversion= true;
- continue; // take next parameter
- }
- if(strzcmp(a,"--fake-lonlat")==0) {
- // user wants just faked longitude and latitude
- // in case of delete actions (.osc files);
- global_fakelonlat= true;
- continue; // take next parameter
- }
- if(strzcmp(a,"--drop-bro")==0) {
- // user does not want broken references in standard output
- global_dropbrokenrefs= true;
- continue; // take next parameter
- }
- if(strzcmp(a,"--drop-nod")==0) {
- // user does not want nodes section in standard output
- global_dropnodes= true;
- continue; // take next parameter
- }
- if(strzcmp(a,"--drop-way")==0) {
- // user does not want ways section in standard output
- global_dropways= true;
- continue; // take next parameter
- }
- if(strzcmp(a,"--drop-rel")==0) {
- // user does not want relations section in standard output
- global_droprelations= true;
- continue; // take next parameter
- }
- if(strzcmp(a,"--merge-ver")==0) {
- // user wants duplicate versions in input files to be merged
- global_mergeversions= true;
- continue; // take next parameter
- }
- if((l= strzlcmp(a,"--csv="))>0 && a[l]!=0) {
- // user-defined columns for csv format
- csv_ini(a+l);
- global_outcsv= true;
- continue; // take next parameter
- }
- if(strcmp(a,"--csv-headline")==0) {
- // write headline to csv output
- global_csvheadline= true;
- global_outcsv= true;
- continue; // take next parameter
- }
- if((l= strzlcmp(a,"--csv-separator="))>0 && a[l]!=0) {
- // user-defined separator for csv format
- strMcpy(global_csvseparator,a+l);
- global_outcsv= true;
- continue; // take next parameter
- }
- if(strcmp(a,"--in-josm")==0) {
- // deprecated;
- // this option is still accepted for compatibility reasons;
- continue; // take next parameter
- }
- if(strcmp(a,"--out-o5m")==0 ||
- strcmp(a,"-5")==0) {
- // user wants output in o5m format
- global_outo5m= true;
- continue; // take next parameter
- }
- if(strcmp(a,"--out-o5c")==0 ||
- strcmp(a,"-5c")==0) {
- // user wants output in o5m format
- global_outo5m= global_outo5c= true;
- continue; // take next parameter
- }
- if(strcmp(a,"--out-osm")==0) {
- // user wants output in osm format
- global_outosm= true;
- continue; // take next parameter
- }
- if(strcmp(a,"--out-osc")==0) {
- // user wants output in osc format
- global_outosc= true;
- continue; // take next parameter
- }
- if(strcmp(a,"--out-osh")==0) {
- // user wants output in osc format
- global_outosh= true;
- continue; // take next parameter
- }
- if(strcmp(a,"--out-none")==0) {
- // user does not want any standard output
- global_outnone= true;
- continue; // take next parameter
- }
- if(strcmp(a,"--out-pbf")==0) {
- // user wants output in PBF format
- global_outpbf= true;
- continue; // take next parameter
- }
- if(strcmp(a,"--out-csv")==0) {
- // user wants output in CSV format
- global_outcsv= true;
- continue; // take next parameter
- }
- if((l= strzlcmp(a,"--pbf-granularity="))>0 && a[l]!=0) {
- // specify lon/lat granularity for .pbf input files
- global_pbfgranularity= oo__strtouint32(a+l);
- global_pbfgranularity100= global_pbfgranularity/100;
- global_pbfgranularity= global_pbfgranularity100*100;
- if(global_pbfgranularity==1) global_pbfgranularity= 0;
- continue; // take next parameter
- }
- if(strzcmp(a,"--emulate-pbf2")==0) {
- // emulate pbf2osm compatible output
- global_emulatepbf2osm= true;
- continue; // take next parameter
- }
- if(strzcmp(a,"--emulate-osmo")==0) {
- // emulate Osmosis compatible output
- global_emulateosmosis= true;
- continue; // take next parameter
- }
- if(strzcmp(a,"--emulate-osmi")==0) {
- // emulate Osmium compatible output
- global_emulateosmium= true;
- continue; // take next parameter
- }
- if((l= strzlcmp(a,"--timestamp="))>0 && a[l]!=0) {
- // user-defined file timestamp
- global_timestamp= oo__strtimetosint64(a+l);
- continue; // take next parameter
- }
- if(strcmp(a,"--out-timestamp")==0) {
- // user wants output in osc format
- global_outtimestamp= true;
- continue; // take next parameter
- }
- if(strcmp(a,"--statistics")==0) {
- // print statistics (usually to stderr)
- global_statistics= true;
- continue; // take next parameter
- }
- if(strcmp(a,"--out-statistics")==0) { // print statistics to stdout
- global_outstatistics= true;
- global_statistics= true;
- global_outnone= true;
- continue; // take next parameter
- }
- if(strcmp(a,"--complete-ways")==0) {
- // do not clip ways when applying borders
- global_completeways= true;
- continue; // take next parameter
- }
- if(strcmp(a,"--complex-ways")==0) {
- // do not clip multipolygons when applying borders
- global_complexways= true;
- continue; // take next parameter
- }
- if(strcmp(a,"--all-to-nodes")==0) {
- // convert ways and relations to nodes
- if(global_calccoords==0) global_calccoords= 1;
- global_alltonodes= true;
- continue; // take next parameter
- }
- if(strcmp(a,"--all-to-nodes-bbox")==0) {
- // convert ways and relations to nodes,
- // and compute a bounding box
- PINFO("Option --all-to-nodes-bbox is deprecated. "
- "Using --all-to-nodes and --add-bbox-tags.");
- global_calccoords= -1;
- global_alltonodes= true;
- global_addbbox= true;
- global_add= true;
- continue; // take next parameter
- }
- if(strcmp(a,"--add-bbox-tags")==0) {
- // compute a bounding box and add it as tag
- global_calccoords= -1;
- global_addbbox= true;
- global_add= true;
- continue; // take next parameter
- }
- if(strcmp(a,"--add-bboxarea-tags")==0) {
- // compute a bounding box and add its area as tag
- global_calccoords= -1;
- global_addbboxarea= true;
- global_add= true;
- continue; // take next parameter
- }
- if(strcmp(a,"--add-bboxweight-tags")==0) {
- // compute a bounding box and add its weight as tag
- global_calccoords= -1;
- global_addbboxweight= true;
- global_add= true;
- continue; // take next parameter
- }
- if((l= strzlcmp(a,"--max-objects="))>0 && a[l]!=0) {
- // define maximum number of objects for --all-to-nodes
- global_maxobjects= oo__strtosint64(a+l);
- if(global_maxobjects<4) global_maxobjects= 4;
- continue; // take next parameter
- }
- if((l= strzlcmp(a,"--max-refs="))>0 && a[l]!=0) {
- // define maximum number of references
- global_maxrefs= oo__strtosint64(a+l);
- if(global_maxrefs<1) global_maxrefs= 1;
- continue; // take next parameter
- }
- if((l= strzlcmp(a,"--object-type-offset="))>0 && a[l]!=0) {
- // define id offset for ways and relations for --all-to-nodes
- global_otypeoffset10= oo__strtosint64(a+l);
- if(global_otypeoffset10<10) global_otypeoffset10= 10;
- if(strstr(a+l,"+1")!=NULL)
- global_otypeoffsetstep= true;
- continue; // take next parameter
- }
- if(strzcmp(a,"-t=")==0 && a[3]!=0) {
- // user-defined prefix for names of temorary files
- strmcpy(global_tempfilename,a+3,sizeof(global_tempfilename)-30);
- continue; // take next parameter
- }
- if(strzcmp(a,"-o=")==0 && a[3]!=0) {
- // reroute standard output to a file
- strMcpy(outputfilename,a+3);
- continue; // take next parameter
- }
- if((strcmp(a,"-v")==0 || strcmp(a,"--verbose")==0 ||
- strzcmp(a,"-v=")==0 || strzcmp(a,"--verbose=")==0) &&
- loglevel==0) { // test mode - if not given already
- char* sp;
-
- sp= strchr(a,'=');
- if(sp!=NULL) loglevel= sp[1]-'0'; else loglevel= 1;
- if(loglevel<1) loglevel= 1;
- if(loglevel>MAXLOGLEVEL) loglevel= MAXLOGLEVEL;
- if(a[1]=='-') { // must be "--verbose" and not "-v"
- if(loglevel==1)
- fprintf(stderr,"osmconvert: Verbose mode.\n");
- else
- fprintf(stderr,"osmconvert: Verbose mode %i.\n",loglevel);
- }
- continue; // take next parameter
- }
- if(strcmp(a,"-t")==0) {
- // test mode
- write_testmode= true;
- fprintf(stderr,"osmconvert: Entering test mode.\n");
- continue; // take next parameter
- }
- if(((l= strzlcmp(a,"--hash-memory="))>0 ||
- (l= strzlcmp(a,"-h="))>0) && isdig(a[l])) {
- // "-h=...": user wants a specific hash size;
- const char* p;
-
- p= a+l; // jump over "-h="
- h_n= h_w= h_r= 0;
- // read the up to three values for hash tables' size;
- // format examples: "-h=200-20-10", "-h=1200"
- while(isdig(*p)) { h_n= h_n*10+*p-'0'; p++; }
- if(*p!=0) { p++; while(isdig(*p)) { h_w= h_w*10+*p-'0'; p++; } }
- if(*p!=0) { p++; while(isdig(*p)) { h_r= h_r*10+*p-'0'; p++; } }
- continue; // take next parameter
- }
- if(strzcmp(a,"-b=")==0) {
- // border consideration by a bounding box
- if(!border_box(a+3)) {
- fprintf(stderr,"osmconvert Error: use border format: "
- " -b=\"x1,y1,x2,y2\"\n");
-return 3;
- } // end border consideration by a bounding box
- continue; // take next parameter
- }
- if(strzcmp(a,"-B=")==0) {
- // border consideration by polygon file
- if(!border_file(a+3)) {
- fprintf(stderr,
- "osmconvert Error: no polygon file or too large: %s\n",a);
-return 4;
- } // end border consideration by polygon file
- continue; // take next parameter
- }
- if(strcmp(a,"-")==0) { // use standard input
- usesstdin= true;
- if(oo_open(NULL)) // file cannot be read
-return 2;
- continue; // take next parameter
- }
- if(a[0]=='-') {
- PERRv("unrecognized option: %.80s",a)
-return 1;
- }
- // here: parameter must be a file name
- if(strcmp(a,"/dev/stdin")==0)
- usesstdin= true;
- if(oo_open(a)) // file cannot be read
-return 2;
- } // end for every parameter in command line
-
- // process parameters
- global_subtract= false;
- if(usesstdin && global_completeways) {
- PERR("cannot apply --complete-ways when reading standard input.")
-return 2;
- }
- if(usesstdin && global_complexways) {
- PERR("cannot apply --complex-ways when reading standard input.")
-return 2;
- }
- if(global_completeways || global_complexways) {
- uint32_t zlibflags;
- zlibflags= zlibCompileFlags();
- if(loglevel>=2) {
- PINFOv("zlib "ZLIB_VERSION" flags: %08"PRIx32"",zlibflags)
- }
- //if((zlibflags&0xc0) <= 0x40)
- //WARN("you are using the 32 bit zlib. Hence file size max. 2 GB.")
- }
- if(oo_ifn==0) { // no input files given
- PERR("use \"-\" to read from standard input or try: osmconvert -h")
-return 0; // end the program, because without having input files
- // we do not know what to do;
- }
- if(outputfilename[0]!=0 && !global_outo5m &&
- !global_outo5c && !global_outosm && !global_outosc &&
- !global_outosh && !global_outpbf && !global_outcsv &&
- !global_outnone && !global_outstatistics) {
- // have output file name AND output format not defined
- // try to determine the output format by evaluating
- // the file name extension
- if(strycmp(outputfilename,".o5m")==0) global_outo5m= true;
- else if(strycmp(outputfilename,".o5c")==0)
- global_outo5m= global_outo5c= true;
- else if(strycmp(outputfilename,".osm")==0) global_outosm= true;
- else if(strycmp(outputfilename,".osc")==0) global_outosc= true;
- else if(strycmp(outputfilename,".osh")==0) global_outosh= true;
- else if(strycmp(outputfilename,".pbf")==0) global_outpbf= true;
- else if(strycmp(outputfilename,".csv")==0) global_outcsv= true;
- }
- if(write_open(outputfilename[0]!=0? outputfilename: NULL)!=0)
-return 3;
- if(border_active || global_dropbrokenrefs) { // user wants borders
- int r;
-
- if(global_diff) {
- PERR(
- "-b=, -B=, --drop-brokenrefs must not be combined with --diff");
-return 6;
- }
- if(h_n==0) h_n= 1000; // use standard value if not set otherwise
- if(h_w==0 && h_r==0) {
- // user chose simple form for hash memory value
- // take the one given value as reference and determine the
- // three values using these factors: 90%, 9%, 1%
- h_w= h_n/10; h_r= h_n/100;
- h_n-= h_w; h_w-= h_r; }
- r= hash_ini(h_n,h_w,h_r); // initialize hash table
- if(r==1)
- fprintf(stderr,"osmconvert: Hash size had to be reduced.\n");
- else if(r==2)
- fprintf(stderr,"osmconvert: Not enough memory for hash.\n");
- } // end user wants borders
- if(global_outo5m || border_active || global_dropbrokenrefs ||
- global_calccoords!=0) {
- // .o5m format is needed as output
- if(o5_ini()!=0) {
- fprintf(stderr,"osmconvert: Not enough memory for .o5m buffer.\n");
-return 5;
- }
- } // end user wants borders
- if(global_diff) {
- if(oo_ifn!=2) {
- PERR("Option --diff requires exactly two input files.");
-return 7;
- }
- if(!global_outosc && !global_outosh && !global_outo5c)
- global_outosc= true;
- } // end diff
- sprintf(strchr(global_tempfilename,0),".%"PRIi64,(int64_t)getpid());
- if(loglevel>=2)
- fprintf(stderr,"Tempfiles: %s.*\n",global_tempfilename);
- if(global_calccoords!=0)
- posi_ini();
- if(global_outcsv)
- csv_ini(NULL);
-
- // do the work
- r= oo_main();
- if(loglevel>=2) { // verbose
- if(read_bufp!=NULL && read_bufp<read_bufe)
- fprintf(stderr,"osmconvert: Next bytes to parse:\n"
- " %.02X %.02X %.02X %.02X %.02X %.02X %.02X %.02X\n",
- read_bufp[0],read_bufp[1],read_bufp[2],read_bufp[3],
- read_bufp[4],read_bufp[5],read_bufp[6],read_bufp[7]);
- } // verbose
- write_flush();
- if(hash_queryerror()!=0)
- r= 91;
- if(write_error) {
- r= 92;
- PERR("write error.")
- }
- if(loglevel>0) { // verbose mode
- if(oo_sequenceid!=INT64_C(-0x7fffffffffffffff))
- fprintf(stderr,"osmconvert: Last processed: %s %"PRIu64".\n",
- ONAME(oo_sequencetype),oo_sequenceid);
- if(r!=0)
- fprintf(stderr,"osmconvert Exit: %i\n",r);
- } // verbose mode
- assistant(NULL,NULL);
- return r;
- } // end main()
-
diff --git a/tools/osmctools/osmfilter.c b/tools/osmctools/osmfilter.c
deleted file mode 100644
index 387cd4766b..0000000000
--- a/tools/osmctools/osmfilter.c
+++ /dev/null
@@ -1,6260 +0,0 @@
-// osmfilter 2015-04-14 19:50
-#define VERSION "1.4.0"
-//
-// compile this file:
-// gcc osmfilter.c -O3 -o osmfilter
-//
-// (c) 2011..2015 Markus Weber, Nuernberg
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Affero General Public License
-// version 3 as published by the Free Software Foundation.
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-// You should have received a copy of this license along
-// with this program; if not, see http://www.gnu.org/licenses/.
-// Other licenses are available on request; please ask the author.
-
-#define MAXLOGLEVEL 2
-const char* shorthelptext=
-"\nosmfilter " VERSION " Parameter Overview\n"
-"(Please use --help to get more information.)\n"
-"\n"
-"<file> file to filter; (.o5m faster than .osm)\n"
-"--keep= define which objects are to be kept\n"
-"--keep-nodes= same as above, but applies to nodes only,\n"
-"--keep-ways= etc.\n"
-"--keep-relations= Examples:\n"
-"--keep-nodes-ways= --keep=\"amenity=pub =bar\"\n"
-"--keep-nodes-relations= --keep=\"tunnel=yes and lit=yes\"\n"
-"--keep-ways-relations=\n"
-"--drop= define which objects are to be dropped\n"
-"--drop-...(see above)= similar to --keep-...= (see above)\n"
-"--keep-tags= define which tags are to be kept\n"
-"--keep-node-tags= same as above, but applies to nodes only,\n"
-"--keep-way-tags= etc.\n"
-"--keep-relation-tags=\n"
-"--keep-node-way-tags=\n"
-"--keep-node-relation-tags=\n"
-"--keep-way-relation-tags=\n"
-"--drop-tags= define which tags are to be dropped\n"
-"--drop-...-tags= similar to --keep-...-tags= (see above)\n"
-"--drop-author delete changeset and user information\n"
-"--drop-version same as before, but delete version as well\n"
-"--drop-nodes delete all nodes\n"
-"--drop-ways delete all ways\n"
-"--drop-relations delete all relations\n"
-"--emulate-osmosis emulate Osmosis XML output format\n"
-"--emulate-pbf2osm emulate pbf2osm output format\n"
-"--fake-author set changeset to 1 and timestamp to 1970\n"
-"--fake-version set version number to 1\n"
-"--fake-lonlat set lon to 0 and lat to 0\n"
-"-h display this parameter overview\n"
-"--help display a more detailed help\n"
-"--ignore-dependencies ignore dependencies between OSM objects\n"
-"--out-key= write statistics (for the key, if supplied)\n"
-"--out-count= same as before, but sorted by occurrence\n"
-"--out-osm write output in .osm format (default)\n"
-"--out-osc write output in .osc format (OSMChangefile)\n"
-"--out-osh write output in .osh format (visible-tags)\n"
-"--out-o5m write output in .o5m format (fast binary)\n"
-"--out-o5c write output in .o5c format (bin. Changef.)\n"
-"-o=<outfile> reroute standard output to a file\n"
-"-t=<tempfile> define tempfile prefix\n"
-"--parameter-file=<file> param. in file, separated by empty lines\n"
-"--verbose activate verbose mode\n";
-const char* helptext=
-"\nosmfilter " VERSION "\n"
-"\n"
-"THIS PROGRAM IS FOR EXPERIMENTAL USE ONLY.\n"
-"PLEASE EXPECT MALFUNCTION AND DATA LOSS.\n"
-"SAVE YOUR DATA BEFORE STARTING THIS PROGRAM.\n"
-"\n"
-"This program filters OpenStreetMap data.\n"
-"\n"
-"The input file name must be supplied as command line argument. The\n"
-"file must not be a stream. Redirections from standard input will not\n"
-"work because the program needs random access to the file. You do not\n"
-"need to specify the input format, osmfilter will recognize these\n"
-"formats: .osm (XML), .osc (OSM Change File), .osh (OSM Full History),\n"
-".o5m (speed-optimized) and .o5c (speed-optimized Change File).\n"
-"\n"
-"The output format is .osm by default. If you want a different format,\n"
-"please specify it using the appropriate command line parameter.\n"
-"\n"
-"--keep=OBJECT_FILTER\n"
-" All object types (nodes, ways and relations) will be kept\n"
-" if they meet the filter criteria. Same applies to dependent\n"
-" objects, e.g. nodes in ways, ways in relations, relations in\n"
-" other relations.\n"
-" Please look below for a syntax description of OBJECT_FILTER.\n"
-"\n"
-"--keep-nodes=OBJECT_FILTER\n"
-"--keep-ways=OBJECT_FILTER\n"
-"--keep-relations=OBJECT_FILTER\n"
-"--keep-nodes-ways=OBJECT_FILTER\n"
-"--keep-nodes-relations=OBJECT_FILTER\n"
-"--keep-ways-relations=OBJECT_FILTER\n"
-" Same as above, but just for the specified object types.\n"
-"\n"
-"--drop=OBJECT_FILTER\n"
-" All object types (nodes, ways and relations) which meet the\n"
-" supplied filter criteria will be dropped, regardless of\n"
-" meeting the criteria of a keep filter (see above).\n"
-" Please look below for a syntax description of OBJECT_FILTER.\n"
-"\n"
-"--drop-nodes=OBJECT_FILTER\n"
-"--drop-ways=OBJECT_FILTER\n"
-"--drop-relations=OBJECT_FILTER\n"
-"--drop-nodes-ways=OBJECT_FILTER\n"
-"--drop-nodes-relations=OBJECT_FILTER\n"
-"--drop-ways-relations=OBJECT_FILTER\n"
-" Same as above, but just for the specified object types.\n"
-"\n"
-"--keep-tags=TAG_FILTER\n"
-" The in TAG_FILTER specified tags will be allowed on output.\n"
-" Please look below for a syntax description of TAG_FILTER.\n"
-"\n"
-"--keep-node-tags=TAG_FILTER\n"
-"--keep-way-tags=TAG_FILTER\n"
-"--keep-relation-tags=TAG_FILTER\n"
-"--keep-node-way-tags=TAG_FILTER\n"
-"--keep-node-relation-tags=TAG_FILTER\n"
-"--keep-way-relation-tags=TAG_FILTER\n"
-" Same as above, but just for the specified object types.\n"
-"\n"
-"--drop-tags=TAG_FILTER\n"
-" The specified tags will be dropped. This overrules the\n"
-" previously described parameter --keep-tags.\n"
-" Please look below for a syntax description of TAG_FILTER.\n"
-"\n"
-"--drop-node-tags=TAG_FILTER\n"
-"--drop-way-tags=TAG_FILTER\n"
-"--drop-relation-tags=TAG_FILTER\n"
-"--drop-node-way-tags=TAG_FILTER\n"
-"--drop-node-relation-tags=TAG_FILTER\n"
-"--drop-way-relation-tags=TAG_FILTER\n"
-" Same as above, but just for the specified object types.\n"
-"\n"
-"--drop-author\n"
-" For most applications the author tags are not needed. If you\n"
-" specify this option, no author information will be written:\n"
-" no changeset, user or timestamp.\n"
-"\n"
-"--drop-version\n"
-" If you want to exclude not only the author information but\n"
-" also the version number, specify this option.\n"
-"\n"
-"--drop-nodes\n"
-"--drop-ways\n"
-"--drop-relations\n"
-" According to the combination of these parameters, no members\n"
-" of the referred section will be written.\n"
- "\n"
-"--emulate-osmosis\n"
-"--emulate-pbf2osm\n"
-" In case of .osm output format, the program will try to use\n"
-" the same data syntax as Osmosis, resp. pbf2osm.\n"
-"\n"
-"--fake-author\n"
-" If you have dropped author information (--drop-author) that\n"
-" data will be lost, of course. Some programs however require\n"
-" author information on input although they do not need that\n"
-" data. For this purpose, you can fake the author information.\n"
-" o5mfiler will write changeset 1, timestamp 1970.\n"
-"\n"
-"--fake-version\n"
-" Same as --fake-author, but - if .osm xml is used as output\n"
-" format - only the version number will be written (version 1).\n"
-" This is useful if you want to inspect the data with JOSM.\n"
-"\n"
-"--fake-lonlat\n"
-" Some programs depend on getting longitude/latitude values,\n"
-" even when the object in question shall be deleted. With this\n"
-" option you can have osmfilter to fake these values:\n"
-" ... lat=\"0\" lon=\"0\" ...\n"
-" Note that this is for XML files only (.osc and .osh).\n"
-"\n"
-"-h\n"
-" Display a short parameter overview.\n"
-"\n"
-"--help\n"
-" Display this help.\n"
-"\n"
-"--ignore-dependencies\n"
-" Usually, all member nodes of a way which meets the filter\n"
-" criteria will be included as well. Same applies to members of\n"
-" included relations. If you activate this option, all these\n"
-" dependencies between OSM objects will be ignored.\n"
-"\n"
-"--out-key=KEYNAME\n"
-" The output will contain no regular OSM data but only\n"
-" statistics: a list of all used keys is assembled. Left to\n"
-" each key, the number of occurrences is printed.\n"
-" If KEYNAME is given, the program will list all values which\n"
-" are used in connections with this key.\n"
-" You may use wildcard characters for KEYNAME, but only at the\n"
-" beginning and/or at the end. For example: --out-key=addr:*\n"
-"\n"
-"--out-count=KEYNAME\n"
-" Same as --out-key=, but the list is sorted by the number of\n"
-" occurrences of the keys resp. values.\n"
-"\n"
-"--out-osm\n"
-" Data will be written in .osm format. This is the default\n"
-" output format.\n"
-"\n"
-"--out-osc\n"
-" The OSM Change format will be used for output. Please note\n"
-" that OSM objects which are to be deleted are represented by\n"
-" their ids only.\n"
-"\n"
-"--out-osh\n"
-" For every OSM object, the appropriate \'visible\' tag will be\n" " added to meet \'full planet history\' specification.\n"
-"\n"
-"--out-o5m\n"
-" The .o5m format will be used. This format has the same\n"
-" structure as the conventional .osm format, but the data are\n"
-" stored as binary numbers and are therefore much more compact\n"
-" than in .osm format. No packing is used, so you can pack .o5m\n"
-" files using every file packer you want, e.g. lzo, bz2, etc.\n"
-"\n"
-"--out-o5c\n"
-" This is the change file format of .o5m data format. All\n"
-" <delete> tags will not be performed as delete actions but\n"
-" converted into .o5c data format.\n"
-"\n"
-"-o=<outfile>\n"
-" Standard output will be rerouted to the specified file.\n"
-" If no output format has been specified, the program will\n"
-" proceed according to the file name extension.\n"
-"\n"
-"-t=<tempfile>\n"
-" osmfilter uses a temporary file to process interrelational\n"
-" dependencies. This parameter defines the name prefix. The\n"
-" default value is \"osmfilter_tempfile\".\n"
-"\n"
-"--parameter-file=FILE\n"
-" If you want to supply one ore more command line arguments\n"
-" by a parameter file, please use this option and specify the\n"
-" file name. Within the parameter file, parameters must be\n"
-" separated by empty lines. Line feeds inside a parameter will\n"
-" be converted to spaces.\n"
-" Lines starting with \"// \" will be treated as comments.\n"
-"\n"
-"-v\n"
-"--verbose\n"
-" With activated \'verbose\' mode, some statistical data and\n"
-" diagnosis data will be displayed.\n"
-" If -v resp. --verbose is the first parameter in the line,\n"
-" osmfilter will display all input parameters.\n"
-"\n"
-"OBJECT_FILTER\n"
-" Some of the command line arguments need a filter to be\n"
-" specified. This filter definition consists of key/val pairs\n"
-" and uses the following syntax:\n"
-" \"KEY1=VAL1 OP KEY2=VAL2 OP KEY3=VAL3 ...\"\n"
-" OP is the Boolean operator, it must be either \"and\" or \"or\".\n"
-" As usual, \"and\" will be processed prior to \"or\". If you\n"
-" want to influence the sequence of processing, you may use\n"
-" brackets to do so. Please note that brackets always must be\n"
-" padded by spaces. Example: lit=yes and ( note=a or source=b )\n"
-" Instead of each \"=\" you may enter one of these comparison\n"
-" operators: != (not equal), <, >, <=, >=\n"
-" The program will use ASCII-alphabetic comparison unless you\n" " compare against a value which is starting with a digit.\n"
-" If there are different possible values for the same key, you\n"
-" need to write the key only once. For example:\n"
-" \"amenity=restaurant =pub =bar\"\n"
-" It is allowed to omit the value. In this case, the program\n"
-" will accept every value for the defined key. For example:\n"
-" \"all highway= lit=yes\"\n"
-" You may use wildcard characters for key or value, but only at\n"
-" the beginning and/or at the end. For example:\n"
-" wikipedia:*= highway=*ary ref_name=*central*\n"
-" Please be careful with wildcards in keys since only the first\n"
-" key which meets the pattern will be processed.\n"
-" There are three special keys which represent object id, user\n"
-" id and user name: @id, @uid and @user. They allow you to\n"
-" search for certain objects or for edits of specific users.\n"
-"\n"
-"TAG_FILTER\n"
-" The tag filter determines which tags will be kept and which\n"
-" will be not. The example\n"
-" --keep-tags=\"highway=motorway =primary\"\n"
-" will not accept \"highway\" tags other than \"motorway\" or\n"
-" \"primary\". Note that neither the object itself will be\n"
-" deleted, nor the remaining tags. If you want to drop every\n"
-" tag which is not mentioned in a list, use this example:\n"
-" all highway= amenity= name=\n"
-"\n"
-"Examples\n"
-"\n"
-"./osmfilter europe.o5m --keep=amenity=bar -o=new.o5m\n"
-"./osmfilter a.osm --keep-nodes=lit=yes --drop-ways -o=light.osm\n"
-"./osmfilter a.osm --keep=\"\n"
-" place=city or ( place=town and population>=10000 )\" -o=b.osm\n"
-"./osmfilter region.o5m --keep=\"bridge=yes and layer>=2\" -o=r.o5m\n"
-"\n"
-"Tuning\n"
-"\n"
-"To speed-up the process, the program uses some main memory for a\n"
-"hash table. By default, it uses 900 MB for storing a flag for every\n"
-"possible node, 90 for the way flags, and 10 relation flags.\n"
-"Every byte holds the flags for 8 ID numbers, i.e., in 900 MB the\n"
-"program can store 7200 million flags. As there are less than 3200\n"
-"million IDs for nodes at present (Oct 2014), 400 MB would suffice.\n"
-"So, for example, you can decrease the hash sizes to e.g. 400, 50 and\n"
-"2 MB (for relations, 2 flags are needed each) using this option:\n"
-"\n"
-" --hash-memory=400-50-2\n"
-"\n"
-"But keep in mind that the OSM database is continuously expanding. For\n"
-"this reason the program-own default value is higher than shown in the\n"
-"example, and it may be appropriate to increase it in the future.\n"
-"If you do not want to bother with the details, you can enter the\n"
-"amount of memory as a sum, and the program will divide it by itself.\n"
-"For example:\n"
-"\n"
-" --hash-memory=1500\n"
-"\n"
-"These 1500 MB will be split in three parts: 1350 for nodes, 135 for\n"
-"ways, and 15 for relations.\n"
-"\n"
-"Because we are taking hashes, it is not necessary to provide all the\n"
-"suggested memory; the program will operate with less hash memory too.\n"
-"But, in this case, the border filter will be less effective, i.e.,\n"
-"some ways and some relations will be left in the output file although\n"
-"they should have been excluded.\n"
-"The maximum value the program accepts for the hash size is 4000 MiB;\n"
-"If you exceed the maximum amount of memory available on your system,\n"
-"the program will try to reduce this amount and display a warning\n"
-"message.\n"
-"\n"
-"Limitations\n"
-"\n"
-"When filtering whole OSM objects (--keep...=, --drop...=), the input\n"
-"file must contain the objects ordered by their type: first, all nodes\n"
-"nodes, next, all ways, followed by all relations.\n"
-"\n"
-"Usual .osm, .osc, .o5m and o5c files adhere to this condition. This\n"
-"means that you do not have to worry about this limitation. osmfilter\n"
-"will display an error message if this sequence is broken.\n"
-"\n"
-"The number of key/val pairs in each filter parameter is limited to\n"
-"1000, the length of each key or val is limited to 100.\n"
-"\n"
-"There is NO WARRANTY, to the extent permitted by law.\n"
-"Please send any bug reports to markus.weber@gmx.com\n\n";
-
-#define _FILE_OFFSET_BITS 64
-#include <inttypes.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <time.h>
-#include <ctype.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <signal.h>
-
-typedef enum {false= 0,true= 1} bool;
-typedef uint8_t byte;
-typedef unsigned int uint;
-#define isdig(x) isdigit((unsigned char)(x))
-static byte isdigi_tab[]= {
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
-#define isdigi(c) (isdigi_tab[(c)]) // digit
-static byte digival_tab[]= {
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 1,2,3,4,5,6,7,8,9,10,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
-#define digival(c) (digival_tab[(c)])
- // value of a digit, starting with 1, for comparisons only
-
-static int loglevel= 0; // logging to stderr;
- // 0: no logging; 1: small logging; 2: normal logging;
- // 3: extended logging;
-#define UR(x) if(x){} // result value intentionally ignored
-#define DP(f) fprintf(stderr,"- Debug: " #f "\n");
-#define DPv(f,...) fprintf(stderr,"- Debug: " #f "\n",__VA_ARGS__);
-#if __WIN32__
- #define NL "\r\n" // use CR/LF as new-line sequence
- #define off_t off64_t
- #define lseek lseek64
-#else
- #define NL "\n" // use LF as new-line sequence
- #define O_BINARY 0
-#endif
-
-
-
-//------------------------------------------------------------
-// Module Global global variables for this program
-//------------------------------------------------------------
-
-// to distinguish global variable from local or module global
-// variables, they are preceded by 'global_';
-
-static bool global_dropversion= false; // exclude version
-static bool global_dropauthor= false; // exclude author information
-static bool global_fakeauthor= false; // fake author information
-static bool global_fakeversion= false; // fake just the version number
-static bool global_fakelonlat= false;
- // fake longitude and latitude in case of delete actions (.osc);
-static bool global_dropnodes= false; // exclude nodes section
-static bool global_dropways= false; // exclude ways section
-static bool global_droprelations= false; // exclude relations section
-static bool global_outo5m= false; // output shall have .o5m format
-static bool global_outo5c= false; // output shall have .o5c format
-static bool global_outosm= false; // output shall have .osm format
-static bool global_outosc= false; // output shall have .osc format
-static bool global_outosh= false; // output shall have .osh format
-static const char* global_outkey= NULL;
- // =="": do not write osm data, write a list of keys instead;
- // !=NULL && !="": write a list of vals to the key this variable
- // points to;
-static bool global_outsort= false; // sort item list by count;
-static bool global_emulatepbf2osm= false;
- // emulate pbf2osm compatible output
-static bool global_emulateosmosis= false;
- // emulate Osmosis compatible output
-static bool global_emulateosmium= false;
- // emulate Osmium compatible output
-static char global_tempfilename[350]= "osmfilter_tempfile";
- // prefix of names for temporary files
-static bool global_recursive= false; // recursive processing necessary
-static bool global_ignoredependencies= false;
- // user wants interobject dependencies to be ignored
-#define PERR(f) { static int msgn= 3; if(--msgn>=0) \
- fprintf(stderr,"osmfilter Error: " f "\n"); }
- // print error message
-#define PERRv(f,...) { static int msgn= 3; if(--msgn>=0) \
- fprintf(stderr,"osmfilter Error: " f "\n",__VA_ARGS__); }
- // print error message with value(s)
-#define WARN(f) { static int msgn= 3; if(--msgn>=0) \
- fprintf(stderr,"osmfilter Warning: " f "\n"); }
- // print a warning message, do it maximal 3 times
-#define WARNv(f,...) { static int msgn= 3; if(--msgn>=0) \
- fprintf(stderr,"osmfilter Warning: " f "\n",__VA_ARGS__); }
- // print a warning message with value(s), do it maximal 3 times
-#define PINFO(f) \
- fprintf(stderr,"osmfilter: " f "\n"); // print info message
-#define PINFOv(f,...) \
- fprintf(stderr,"osmfilter: " f "\n",__VA_ARGS__);
-#define ONAME(i) \
- (i==0? "node": i==1? "way": i==2? "relation": "unknown object")
-#define global_fileM 1 // maximum number of input files
-
-//------------------------------------------------------------
-// end Module Global global variables for this program
-//------------------------------------------------------------
-
-
-
-static inline char* int32toa(int32_t v,char* s) {
- // convert int32_t integer into string;
- // v: long integer value to convert;
- // return: s;
- // s[]: digit string;
- char* s1,*s2;
- char c;
-
- s1= s;
- if(v<0)
- { *s1++= '-'; v= -v; }
- else if(v==0)
- *s1++= '0';
- s2= s1;
- while(v>0)
- { *s2++= "0123456789"[v%10]; v/= 10; }
- *s2--= 0;
- while(s2>s1)
- { c= *s1; *s1= *s2; *s2= c; s1++; s2--; }
- return s;
- } // end int32toa()
-
-static inline char* uint32toa(uint32_t v,char* s) {
- // convert uint32_t integer into string;
- // v: long integer value to convert;
- // return: s;
- // s[]: digit string;
- char* s1,*s2;
- char c;
-
- s1= s;
- if(v==0)
- *s1++= '0';
- s2= s1;
- while(v>0)
- { *s2++= "0123456789"[v%10]; v/= 10; }
- *s2--= 0;
- while(s2>s1)
- { c= *s1; *s1= *s2; *s2= c; s1++; s2--; }
- return s;
- } // end uint32toa()
-
-static inline char* int64toa(int64_t v,char* s) {
- // convert int64_t integer into string;
- // v: long integer value to convert;
- // return: s;
- // s[]: digit string;
- char* s1,*s2;
- char c;
-
- s1= s;
- if(v<0)
- { *s1++= '-'; v= -v; }
- else if(v==0)
- *s1++= '0';
- s2= s1;
- while(v>0)
- { *s2++= "0123456789"[v%10]; v/= 10; }
- *s2--= 0;
- while(s2>s1)
- { c= *s1; *s1= *s2; *s2= c; s1++; s2--; }
- return s;
- } // end int64toa()
-
-static inline char *stpcpy0(char *dest, const char *src) {
- // redefinition of C99's stpcpy() because it's missing in MinGW,
- // and declaration in Linux seems to be wrong;
- while(*src!=0)
- *dest++= *src++;
- *dest= 0;
- return dest;
- } // end stpcpy0()
-
-static inline char *strmcpy(char *dest, const char *src, size_t maxlen) {
- // similar to strcpy(), this procedure copies a character string;
- // here, the length is cared about, i.e. the target string will
- // be limited in case it is too long;
- // src[]: source string which is to be copied;
- // maxlen: maximum length of the destination string
- // (including terminator null);
- // return:
- // dest[]: destination string of the copy; this is the
- // function's return value too;
- char* d;
-
- if(maxlen==0)
-return dest;
- d= dest;
- while(--maxlen>0 && *src!=0)
- *d++= *src++;
- *d= 0;
- return dest;
- } // end strmcpy()
-#define strMcpy(d,s) strmcpy((d),(s),sizeof(d))
-
-static char *stpmcpy(char *dest, const char *src, size_t maxlen) {
- // similar to strmcpy(), this procedure copies a character string;
- // however, it returns the address of the destination string's
- // terminating zero character;
- // this makes it easier to concatenate strings;
- char* d;
-
- if(maxlen==0)
-return dest;
- d= dest;
- while(--maxlen>0 && *src!=0)
- *d++= *src++;
- *d= 0;
- return d;
- } // end stpmcpy()
-#define stpMcpy(d,s) stpmcpy(d,s,sizeof(d))
-
-static inline int strzcmp(const char* s1,const char* s2) {
- // similar to strcmp(), this procedure compares two character strings;
- // here, the number of characters which are to be compared is limited
- // to the length of the second string;
- // i.e., this procedure can be used to identify a short string s2
- // within a long string s1;
- // s1[]: first string;
- // s2[]: string to compare with the first string;
- // return:
- // 0: both strings are identical; the first string may be longer than
- // the second;
- // -1: the first string is alphabetical smaller than the second;
- // 1: the first string is alphabetical greater than the second;
- while(*s1==*s2 && *s1!=0) { s1++; s2++; }
- if(*s2==0)
- return 0;
- return *(unsigned char*)s1 < *(unsigned char*)s2? -1: 1;
- } // end strzcmp()
-
-static inline int strzlcmp(const char* s1,const char* s2) {
- // similar to strzcmp(), this procedure compares two character strings;
- // and accepts the first string to be longer than the second;
- // other than strzcmp(), this procedure returns the length of s2[] in
- // case both string contents are identical, and returns 0 otherwise;
- // s1[]: first string;
- // s2[]: string to compare with the first string;
- // return:
- // >0: both strings are identical, the length of the second string is
- // returned; the first string may be longer than the second;
- // 0: the string contents are not identical;
- const char* s2a;
-
- s2a= s2;
- while(*s1==*s2 && *s1!=0) { s1++; s2++; }
- if(*s2==0)
- return s2-s2a;
- return 0;
- } // end strzlcmp()
-
-static inline int strycmp(const char* s1,const char* s2) {
- // similar to strcmp(), this procedure compares two character strings;
- // here, both strings are end-aligned;
- // not more characters will be compared than are existing in string s2;
- // i.e., this procedure can be used to identify a file name extension;
- const char* s1e;
- int l;
-
- l= strchr(s2,0)-s2;
- s1e= strchr(s1,0);
- if(s1e-s1<l)
-return 1;
- s1= s1e-l;
- while(*s1==*s2 && *s1!=0) { s1++; s2++; }
- if(*s2==0)
- return 0;
- return *(unsigned char*)s1 < *(unsigned char*)s2? -1: 1;
- } // end strycmp()
-
-
-
-//------------------------------------------------------------
-// Module pbf_ protobuf conversions module
-//------------------------------------------------------------
-
-// this module provides procedures for conversions from
-// protobuf formats to regular numbers;
-// as usual, all identifiers of a module have the same prefix,
-// in this case 'pbf'; one underline will follow in case of a
-// global accessible object, two underlines in case of objects
-// which are not meant to be accessed from outside this module;
-// the sections of private and public definitions are separated
-// by a horizontal line: ----
-// many procedures have a parameter 'pp'; here, the address of
-// a buffer pointer is expected; this pointer will be incremented
-// by the number of bytes the converted protobuf element consumes;
-
-//------------------------------------------------------------
-
-static inline uint32_t pbf_uint32(byte** pp) {
- // get the value of an unsigned integer;
- // pp: see module header;
- byte* p;
- uint32_t i;
- uint32_t fac;
-
- p= *pp;
- i= *p;
- if((*p & 0x80)==0) { // just one byte
- (*pp)++;
-return i;
- }
- i&= 0x7f;
- fac= 0x80;
- while(*++p & 0x80) { // more byte(s) will follow
- i+= (*p & 0x7f)*fac;
- fac<<= 7;
- }
- i+= *p++ *fac;
- *pp= p;
- return i;
- } // end pbf_uint32()
-
-static inline int32_t pbf_sint32(byte** pp) {
- // get the value of an unsigned integer;
- // pp: see module header;
- byte* p;
- int32_t i;
- int32_t fac;
- int sig;
-
- p= *pp;
- i= *p;
- if((*p & 0x80)==0) { // just one byte
- (*pp)++;
- if(i & 1) // negative
-return -1-(i>>1);
- else
-return i>>1;
- }
- sig= i & 1;
- i= (i & 0x7e)>>1;
- fac= 0x40;
- while(*++p & 0x80) { // more byte(s) will follow
- i+= (*p & 0x7f)*fac;
- fac<<= 7;
- }
- i+= *p++ *fac;
- *pp= p;
- if(sig) // negative
-return -1-i;
- else
-return i;
- } // end pbf_sint32()
-
-static inline uint64_t pbf_uint64(byte** pp) {
- // get the value of an unsigned integer;
- // pp: see module header;
- byte* p;
- uint64_t i;
- uint64_t fac;
-
- p= *pp;
- i= *p;
- if((*p & 0x80)==0) { // just one byte
- (*pp)++;
-return i;
- }
- i&= 0x7f;
- fac= 0x80;
- while(*++p & 0x80) { // more byte(s) will follow
- i+= (*p & 0x7f)*fac;
- fac<<= 7;
- }
- i+= *p++ *fac;
- *pp= p;
- return i;
- } // end pbf_uint64()
-
-static inline int64_t pbf_sint64(byte** pp) {
- // get the value of a signed integer;
- // pp: see module header;
- byte* p;
- int64_t i;
- int64_t fac;
- int sig;
-
- p= *pp;
- i= *p;
- if((*p & 0x80)==0) { // just one byte
- (*pp)++;
- if(i & 1) // negative
-return -1-(i>>1);
- else
-return i>>1;
- }
- sig= i & 1;
- i= (i & 0x7e)>>1;
- fac= 0x40;
- while(*++p & 0x80) { // more byte(s) will follow
- i+= (*p & 0x7f)*fac;
- fac<<= 7;
- }
- i+= *p++ *fac;
- *pp= p;
- if(sig) // negative
-return -1-i;
- else
-return i;
- } // end pbf_sint64()
-
-#if 0 // not used at present
-static inline void pbf_intjump(byte** pp) {
- // jump over a protobuf formatted integer;
- // pp: see module header;
- // we do not care about a possibly existing identifier,
- // therefore as the start address *pp the address of the
- // integer value is expected;
- byte* p;
-
- p= *pp;
- while(*p & 0x80) p++; p++;
- *pp= p;
- } // end pbf_intjump()
-#endif
-
-//------------------------------------------------------------
-// end Module pbf_ protobuf conversions module
-//------------------------------------------------------------
-
-
-
-//------------------------------------------------------------
-// Module hash_ OSM hash module
-//------------------------------------------------------------
-
-// this module provides three hash tables with default sizes
-// of 320, 60 and 20 MB;
-// the procedures hash_seti() and hash_geti() allow bitwise
-// access to these tables;
-// as usual, all identifiers of a module have the same prefix,
-// in this case 'hash'; one underline will follow in case of a
-// global accessible object, two underlines in case of objects
-// which are not meant to be accessed from outside this module;
-// the sections of private and public definitions are separated
-// by a horizontal line: ----
-
-static bool hash__initialized= false;
-#define hash__M 4
-static unsigned char* hash__mem[hash__M]= {NULL,NULL,NULL,NULL};
- // start of the hash fields for each object type (node, way, relation);
-static uint32_t hash__max[hash__M]= {0,0,0,0};
- // size of the hash fields for each object type
- // (node, way, positive relation, negative relation);
-static int hash__errornumber= 0;
- // 1: object too large
-
-static void hash__end() {
- // clean-up for hash module;
- // will be called at program's end;
- int o; // object type
-
- for(o= 0;o<hash__M;o++) {
- hash__max[o]= 0;
- if(hash__mem[o]!=NULL) {
- free(hash__mem[o]); hash__mem[o]= NULL; }
- }
- hash__initialized= false;
- } // end hash__end()
-
-//------------------------------------------------------------
-
-static int hash_ini(int n,int w,int r) {
- // initializes the hash module;
- // n: amount of memory which is to be allocated for nodes;
- // w: amount of memory which is to be allocated for ways;
- // r: amount of memory which is to be allocated for relations;
- // this will be divided for the two relation has fields:
- // one field for positive relations and one for negative relations;
- // range for all input parameters: 1..4000, unit: MiB;
- // the second and any further call of this procedure will be ignored;
- // return: 0: initialization has been successful (enough memory);
- // 1: memory request had to been reduced to fit the system's
- // resources (warning);
- // 2: memory request was unsuccessful (error);
- // general note concerning OSM database:
- // number of objects at Oct 2010: 950M nodes, 82M ways, 1.3M relations;
- // number of objects at May 2011: 1.3G nodes, 114M ways, 1.6M relations;
- int o; // object type
- bool warning,error;
-
- warning= error= false;
- if(hash__initialized) // already initialized
- return 0; // ignore the call of this procedure
- // check parameters and store the values
- #define D(x,o) if(x<1) x= 1; else if(x>4000) x= 4000; \
- hash__max[o]= x*(1024*1024);
- D(n,0) D(w,1) D(r,2) D(r,3)
- #undef D
- // allocate memory for each hash table
- for(o= 0;o<hash__M;o++) { // for each hash table
- do {
- hash__mem[o]= (unsigned char*)malloc(hash__max[o]);
- if(hash__mem[o]!=NULL) { // allocation successful
- memset(hash__mem[o],0,hash__max[o]); // clear all flags
- break;
- }
- // here: allocation unsuccessful
- // reduce amount by 50%
- hash__max[o]/=2;
- warning= true;
- // memorize that the user should be warned about this reduction
- // try to allocate the reduced amount of memory
- } while(hash__max[o]>=1024);
- if(hash__mem[o]==NULL) // allocation unsuccessful at all
- error= true; // memorize that the program should be aborted
- } // end for each hash table
- atexit(hash__end); // chain-in the clean-up procedure
- if(!error) hash__initialized= true;
- return error? 2: warning? 1: 0;
- } // end hash_ini()
-
-static void hash_seti(int o,int64_t idi) {
- // set a flag for a specific object type and ID;
- // o: object type; 0: node; 1: way; 2: relation;
- // caution: due to performance reasons the boundaries
- // are not checked;
- // id: id of the object;
- unsigned char* mem; // address of byte in hash table
- unsigned int ido; // bit offset to idi;
-
- if(!hash__initialized) return; // ignore this call
- idi+= ((int64_t)hash__max[o])<<3; // consider small negative numbers
- ido= idi&0x7; // extract bit number (0..7)
- idi>>=3; // calculate byte offset
- idi%= hash__max[o]; // consider length of hash table
- mem= hash__mem[o]; // get start address of hash table
- mem+= idi; // calculate address of the byte
- *mem|= (1<<ido); // set bit
- } // end hash_seti()
-
-static bool hash_relseti(int64_t idi) {
- // set the status of a flag for a relation of a specific ID;
- // the flag is set only if this relations does not have a set flag
- // in the 'negative relations' hash field;
- // id: id of the object;
- // return: the flag has been set by this call of this procedure;
- // this procedure assumes that both, the hash field for positive
- // relations and the hash field for negative relations, have the
- // same size;
- unsigned char* mem;
- unsigned int ido; // bit offset to idi;
- unsigned char bitmask;
- bool r;
-
- if(!hash__initialized) return true; // ignore this call
- idi+= ((int64_t)hash__max[2])<<3; // consider small negative numbers
- ido= idi&0x7; // extract bit number (0..7)
- idi>>=3; // calculate byte offset
- idi%= hash__max[2]; // consider length of hash table
- mem= hash__mem[3]; // get start address of negative hash table
- mem+= idi; // calculate address of the byte
- if((*mem&(1<<ido))!=0) // the relation's negative flag is set
-return false; // end processing here because we do not want to
- // set the relation's positive flag
- mem= hash__mem[2]; // get start address of positive hash table
- mem+= idi; // calculate address of the byte
- bitmask= 1<<ido; // determine the bitmask
- r= (*mem&bitmask)==0; // the addressed bit has not been set until now
- *mem|= bitmask; // set bit
- return r;
- } // end hash_relseti();
-
-static bool hash_geti(int o,int64_t idi) {
- // get the status of a flag for a specific object type and ID;
- // (same as previous procedure, but id must be given as number);
- // o: object type; 0: node; 1: way; 2: relation; caution:
- // due to performance reasons the boundaries are not checked;
- // id: id of the object; the id is given as a string of decimal digits;
- // a specific string terminator is not necessary, it is assumed
- // that the id number ends with the first non-digit character;
- unsigned char* mem;
- unsigned int ido; // bit offset to idi;
- bool flag;
-
- if(!hash__initialized) return false;
- idi+= ((int64_t)hash__max[o])<<3; // consider small negative numbers
- ido= idi&0x7; // extract bit number (0..7)
- idi>>=3; // calculate byte offset
- idi%= hash__max[o]; // consider length of hash table
- mem= hash__mem[o]; // get start address of hash table
- mem+= idi; // calculate address of the byte
- flag= (*mem&(1<<ido))!=0; // get status of the addressed bit
- return flag;
- } // end hash_geti();
-
-static int hash_queryerror() {
- // determine if an error has occurred;
- return hash__errornumber;
- } // end hash_queryerror()
-
-//------------------------------------------------------------
-// end Module hash_ OSM hash module
-//------------------------------------------------------------
-
-
-
-//------------------------------------------------------------
-// Module read_ OSM file read module
-//------------------------------------------------------------
-
-// this module provides procedures for buffered reading of
-// standard input;
-// as usual, all identifiers of a module have the same prefix,
-// in this case 'read'; one underline will follow in case of a
-// global accessible object, two underlines in case of objects
-// which are not meant to be accessed from outside this module;
-// the sections of private and public definitions are separated
-// by a horizontal line: ----
-
-#define read_PREFETCH ((32+3)*1024*1024)
- // number of bytes which will be available in the buffer after
- // every call of read_input();
- // (important for reading .pbf files:
- // size must be greater than pb__blockM)
-#define read__bufM (read_PREFETCH*5) // length of the buffer;
-typedef struct { // members may not be accessed from external
- int fd; // file descriptor
- bool eof; // we are at the end of input file
- byte* bufp; // pointer in buf[]
- byte* bufe; // pointer to the end of valid input in buf[]
- int64_t read__counter;
- // byte counter to get the read position in input file;
- uint64_t bufferstart;
- // dummy variable which marks the start of the read buffer
- // concatenated with this instance of read info structure;
- } read_info_t;
-
-//------------------------------------------------------------
-
-static read_info_t* read_infop= NULL;
- // presently used read info structure, i.e. file handle
-#define read__buf ((byte*)&read_infop->bufferstart)
- // start address of the file's input buffer
-static byte* read_bufp= NULL; // may be incremented by external
- // up to the number of read_PREFETCH bytes before read_input() is
- // called again;
-static byte* read_bufe= NULL; // may not be changed from external
-
-static int read_open(const char* filename) {
- // open an input file;
- // filename[]: path and name of input file;
- // ==NULL: standard input;
- // return: 0: ok; !=0: error;
- // read_infop: handle of the file;
- // note that you should close ever opened file with read_close()
- // before the program ends;
-
- // save status of presently processed input file (if any)
- if(read_infop!=NULL) {
- read_infop->bufp= read_bufp;
- read_infop->bufp= read_bufe;
- }
-
- // get memory space for file information and input buffer
- read_infop= (read_info_t*)malloc(sizeof(read_info_t)+read__bufM);
- if(read_infop==NULL) {
- PERRv("could not get %i bytes of memory.",read__bufM)
-return 1;
- }
-
- // initialize read info structure
- read_infop->fd= 0; // (default) standard input
- read_infop->eof= false; // we are at the end of input file
- read_infop->bufp= read_infop->bufe= read__buf; // pointer in buf[]
- // pointer to the end of valid input in buf[]
- read_infop->read__counter= 0;
-
- // set modul-global variables which are associated with this file
- read_bufp= read_infop->bufp;
- read_bufe= read_infop->bufe;
-
- // open the file
- if(loglevel>=2)
- fprintf(stderr,"Read-opening: %s",
- filename==NULL? "stdin": filename);
- if(filename==NULL) // stdin shall be opened
- read_infop->fd= 0;
- else if(filename!=NULL) { // a real file shall be opened
- read_infop->fd= open(filename,O_RDONLY|O_BINARY);
- if(read_infop->fd<0) {
- if(loglevel>=2)
- fprintf(stderr," -> failed\n");
- PERRv("could not open input file: %.80s",
- filename==NULL? "standard input": filename)
- free(read_infop); read_infop= NULL;
- read_bufp= read_bufe= NULL;
-return 1;
- }
- } // end a real file shall be opened
- if(loglevel>=2)
- fprintf(stderr," -> FD %i\n",read_infop->fd);
-return 0;
- } // end read_open()
-
-static void read_close() {
- // close an opened file;
- // read_infop: handle of the file which is to close;
- int fd;
-
- if(read_infop==NULL) // handle not valid;
-return;
- fd= read_infop->fd;
- if(loglevel>=1) { // verbose
- fprintf(stderr,"osmfilter: Number of bytes read: %"PRIu64"\n",
- read_infop->read__counter);
- }
- if(loglevel>=2) {
- fprintf(stderr,"Read-closing FD: %i\n",fd);
- }
- if(fd>0) // not standard input
- close(fd);
- free(read_infop); read_infop= NULL;
- read_bufp= read_bufe= NULL;
- } // end read_close()
-
-static inline bool read_input() {
- // read data from standard input file, use an internal buffer;
- // make data available at read_bufp;
- // read_open() must have been called before calling this procedure;
- // return: there are no (more) bytes to read;
- // read_bufp: start of next bytes available;
- // may be incremented by the caller, up to read_bufe;
- // read_bufe: end of bytes in buffer;
- // must not be changed by the caller;
- // after having called this procedure, the caller may rely on
- // having available at least read_PREFETCH bytes at address
- // read_bufp - with one exception: if there are not enough bytes
- // left to read from standard input, every byte after the end of
- // the reminding part of the file in the buffer will be set to
- // 0x00 - up to read_bufp+read_PREFETCH;
- int l,r;
-
- if(read_bufp+read_PREFETCH>=read_bufe) { // read buffer is too low
- if(!read_infop->eof) { // still bytes in the file
- if(read_bufe>read_bufp) { // bytes remaining in buffer
- memmove(read__buf,read_bufp,read_bufe-read_bufp);
- // move remaining bytes to start of buffer
- read_bufe= read__buf+(read_bufe-read_bufp);
- // protect the remaining bytes at buffer start
- }
- else // no remaining bytes in buffer
- read_bufe= read__buf; // no bytes remaining to protect
- // add read bytes to debug counter
- read_bufp= read__buf;
- do { // while buffer has not been filled
- l= (read__buf+read__bufM)-read_bufe-4;
- // number of bytes to read
- r= read(read_infop->fd,read_bufe,l);
- if(r<=0) { // no more bytes in the file
- read_infop->eof= true;
- // memorize that there we are at end of file
- l= (read__buf+read__bufM)-read_bufe;
- // reminding space in buffer
- if(l>read_PREFETCH) l= read_PREFETCH;
- memset(read_bufe,0,l); // 2011-12-24
- // set reminding space up to prefetch bytes in buffer to 0
- break;
- }
- read_infop->read__counter+= r;
- read_bufe+= r; // set new mark for end of data
- read_bufe[0]= 0; read_bufe[1]= 0; // set 4 null-terminators
- read_bufe[2]= 0; read_bufe[3]= 0;
- } while(r<l); // end while buffer has not been filled
- } // end still bytes to read
- } // end read buffer is too low
- return read_infop->eof && read_bufp>=read_bufe;
- } // end read_input()
-
-static void read_switch(read_info_t* filehandle) {
- // switch to another already opened file;
- // filehandle: handle of the file which shall be switched to;
-
- // first, save status of presently processed input file
- if(read_infop!=NULL) {
- read_infop->bufp= read_bufp;
- read_infop->bufe= read_bufe;
- }
- // switch to new file information
- read_infop= filehandle;
- read_bufp= read_infop->bufp;
- read_bufe= read_infop->bufe;
- read_input();
- } // end read_switch()
-
-static inline int read_jump(int position,bool jump) {
- // memorize the current position in the file or jump to it;
- // position: 0..2; storage position;
- // be careful, no boundary checking is done;
- // jump: jump to a previously stored position;
- // return: ==0: ok; !=0: error;
- static off_t pos[3]= {-1,-1,-1};
-
- if(jump) {
- if(pos[position]==-1 ||
- lseek(read_infop->fd,pos[position],SEEK_SET)<0) {
- PERRv("could not rewind input file to position %i.",position)
-return 1;
- }
- read_infop->read__counter= pos[position];
- read_bufp= read_bufe; // force refetch
- read_infop->eof= false; // force retest for end of file
- read_input(); // ensure prefetch
- }
- else {
- pos[position]= read_infop->read__counter-(read_bufe-read_bufp);
- // get current position, take buffer pointer into account;
- }
-return 0;
- } // end read_jump()
-
-//------------------------------------------------------------
-// end Module read_ OSM file read module
-//------------------------------------------------------------
-
-
-
-//------------------------------------------------------------
-// Module write_ write module
-//------------------------------------------------------------
-
-// this module provides a procedure which writes a byte to
-// standard output;
-// as usual, all identifiers of a module have the same prefix,
-// in this case 'write'; one underline will follow in case of a
-// global accessible object, two underlines in case of objects
-// which are not meant to be accessed from outside this module;
-// the sections of private and public definitions are separated
-// by a horizontal line: ----
-
-static char write__buf[UINT64_C(16000000)];
-static char* write__bufe= write__buf+sizeof(write__buf);
- // (const) water mark for buffer filled 100%
-static char* write__bufp= write__buf;
-static int write__fd= 1; // (initially standard output)
-static inline void write_flush();
-
-static void write__end() {
- // terminate the services of this module;
- if(write__fd>1) { // not standard output
- if(loglevel>=2)
- fprintf(stderr,"Write-closing FD: %i\n",write__fd);
- close(write__fd);
- write__fd= 1;
- }
- } // end write__end()
-
-//------------------------------------------------------------
-
-static bool write_testmode= false; // no standard output
-static bool write_error= false; // an error has occurred
-
-static inline void write_flush() {
- if(write__bufp>write__buf && !write_testmode)
- // at least one byte in buffer AND not test mode
- write_error|=
- write(write__fd,write__buf,write__bufp-write__buf)<0;
- write__bufp= write__buf;
- } // end write_flush();
-
-static int write_open(const char* filename) {
- // open standard output file;
- // filename: name of the output file;
- // this string must be accessible until program end;
- // ==NULL: standard output;
- // this procedure must be called before any output is done;
- // return: 0: OK; !=0: error;
- static bool firstrun= true;
-
- if(loglevel>=2)
- fprintf(stderr,"Write-opening: %s\n",
- filename==NULL? "stdout": filename);
- if(filename!=NULL) { // not standard output
- write__fd= open(filename,
- O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,00600);
- if(write__fd<1) {
- PERRv("could not open output file: %.80s\n",filename)
- write__fd= 1;
-return 1;
- }
- }
- if(firstrun) {
- firstrun= false;
- atexit(write__end);
- }
- return 0;
- } // end write_open()
-
-static inline void write_char(int c) {
- // write one byte to stdout, use a buffer;
- if(write__bufp>=write__bufe) { // the write buffer is full
- if(!write_testmode)
- write_error|=
- write(write__fd,write__buf,write__bufp-write__buf)<0;
- write__bufp= write__buf;
- }
- *write__bufp++= (char)c;
- } // end write_char();
-
-static inline void write_mem(const byte* b,int l) {
- // write a memory area to stdout, use a buffer;
- while(--l>=0) {
- if(write__bufp>=write__bufe) { // the write buffer is full
- if(!write_testmode)
- write_error|=
- write(write__fd,write__buf,write__bufp-write__buf)<0;
- write__bufp= write__buf;
- }
- *write__bufp++= (char)(*b++);
- }
- } // end write_mem();
-
-static inline void write_str(const char* s) {
- // write a string to stdout, use a buffer;
- while(*s!=0) {
- if(write__bufp>=write__bufe) { // the write buffer is full
- if(!write_testmode)
- write_error|=
- write(write__fd,write__buf,write__bufp-write__buf)<0;
- write__bufp= write__buf;
- }
- *write__bufp++= (char)(*s++);
- }
- } // end write_str();
-
-static inline void write_xmlstr(const char* s) {
- // write an XML string to stdout, use a buffer;
- // every character which is not allowed within an XML string
- // will be replaced by the appropriate decimal sequence;
- static byte allowedchar[]= {
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0, // \"&'
- 0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0, // <>
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1, // {}DEL
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- #if 1
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
- #else
- 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
- 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
- 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
- 4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0};
- #endif
- byte b0,b1,b2,b3;
- int i;
- uint32_t u;
- #define write__char_D(c) { \
- if(write__bufp>=write__bufe) { \
- if(!write_testmode) \
- write_error|= \
- write(write__fd,write__buf,write__bufp-write__buf)<0; \
- write__bufp= write__buf; \
- } \
- *write__bufp++= (char)(c); }
- #define D(i) ((byte)(s[i]))
- #define DD ((byte)c)
-
- for(;;) {
- b0= *s++;
- if(b0==0)
- break;
- i= allowedchar[b0];
- if(i==0) // this character may be written as is
- write__char_D(b0)
- else { // use numeric encoding
- if(--i<=0) // one byte
- u= b0;
- else {
- b1= *s++;
- if(--i<=0 && b1>=128) // two bytes
- u= ((b0&0x1f)<<6)+(b1&0x3f);
- else {
- b2= *s++;
- if(--i<=0 && b1>=128 && b2>=128) // three bytes
- u= ((b0&0x0f)<<12)+((b1&0x3f)<<6)+(b2&0x3f);
- else {
- b3= *s++;
- if(--i<=0 && b1>=128 && b2>=128 && b3>=128) // four bytes
- u= ((b0&0x07)<<18)+((b1&0x3f)<<12)+
- ((b1&0x3f)<<6)+(b2&0x3f);
- else
- u= (byte)'?';
- }
- }
- }
- write__char_D('&') write__char_D('#')
- if(u<100) {
- if(u>=10)
- write__char_D(u/10+'0')
- write__char_D(u%10+'0')
- }
- else if(u<1000) {
- write__char_D(u/100+'0')
- write__char_D((u/10)%10+'0')
- write__char_D(u%10+'0')
- }
- else {
- char st[30];
-
- uint32toa(u,st);
- write_str(st);
- }
- write__char_D(';')
- } // use numeric encoding
- }
- #undef DD
- #undef D
- #undef write__char_D
- } // end write_xmlstr();
-
-static inline void write_xmlmnstr(const char* s) {
- // write an XML string to stdout, use a buffer;
- // every character which is not allowed within an XML string
- // will be replaced by the appropriate mnemonic or decimal sequence;
- static byte allowedchar[]= {
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 0,0,9,0,0,0,9,9,0,0,0,0,0,0,0,0, // \"&'
- 0,0,0,0,0,0,0,0,0,0,0,0,9,0,9,0, // <>
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1, // {}DEL
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- #if 1
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
- #else
- 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
- 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
- 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
- 4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0};
- #endif
- byte b0,b1,b2,b3;
- int i;
- uint32_t u;
- #define write__char_D(c) { \
- if(write__bufp>=write__bufe) { \
- if(!write_testmode) \
- write_error|= \
- write(write__fd,write__buf,write__bufp-write__buf)<0; \
- write__bufp= write__buf; \
- } \
- *write__bufp++= (char)(c); }
- #define D(i) ((byte)(s[i]))
- #define DD ((byte)c)
-
- for(;;) {
- b0= *s++;
- if(b0==0)
- break;
- i= allowedchar[b0];
- if(i==0) // this character may be written as is
- write__char_D(b0)
- else if(i==9) { // there is a mnemonic for this character
- write__char_D('&')
- switch(b0) {
- case '\"':
- write__char_D('q') write__char_D('u') write__char_D('o')
- write__char_D('t')
- break;
- case '&':
- write__char_D('a') write__char_D('m') write__char_D('p')
- break;
- case '\'':
- write__char_D('a') write__char_D('p') write__char_D('o')
- write__char_D('s')
- break;
- case '<':
- write__char_D('l') write__char_D('t')
- break;
- case '>':
- write__char_D('g') write__char_D('t')
- break;
- default:
- write__char_D('?') // (should never reach here)
- }
- write__char_D(';')
- } // there is a mnemonic for this character
- else { // use numeric encoding
- if(--i<=0) // one byte
- u= b0;
- else {
- b1= *s++;
- if(--i<=0 && b1>=128) // two bytes
- u= ((b0&0x1f)<<6)+(b1&0x3f);
- else {
- b2= *s++;
- if(--i<=0 && b1>=128 && b2>=128) // three bytes
- u= ((b0&0x0f)<<12)+((b1&0x3f)<<6)+(b2&0x3f);
- else {
- b3= *s++;
- if(--i<=0 && b1>=128 && b2>=128 && b3>=128) // four bytes
- u= ((b0&0x07)<<18)+((b1&0x3f)<<12)+
- ((b1&0x3f)<<6)+(b2&0x3f);
- else
- u= (byte)'?';
- }
- }
- }
- write__char_D('&') write__char_D('#')
- if(u<100) {
- if(u>=10)
- write__char_D(u/10+'0')
- write__char_D(u%10+'0')
- }
- else if(u<1000) {
- write__char_D(u/100+'0')
- write__char_D((u/10)%10+'0')
- write__char_D(u%10+'0')
- }
- else {
- char st[30];
-
- uint32toa(u,st);
- write_str(st);
- }
- write__char_D(';')
- } // use numeric encoding
- }
- #undef DD
- #undef D
- #undef write__char_D
- } // end write_xmlmnstr();
-
-static inline void write_uint32(uint32_t v) {
- // write an unsigned 32 bit integer number to standard output;
- char s[20],*s1,*s2,c;
-
- s1= s;
- if(v==0)
- *s1++= '0';
- s2= s1;
- while(v>0)
- { *s2++= (v%10)+'0'; v/= 10; }
- *s2--= 0;
- while(s2>s1)
- { c= *s1; *s1= *s2; *s2= c; s1++; s2--; }
- write_str(s);
- } // end write_uint32()
-
-#if 0 // not used at present
-static inline void write_sint32(int32_t v) {
- // write a signed 32 bit integer number to standard output;
- char s[20],*s1,*s2,c;
-
- s1= s;
- if(v<0)
- { *s1++= '-'; v= -v; }
- else if(v==0)
- *s1++= '0';
- s2= s1;
- while(v>0)
- { *s2++= (v%10)+'0'; v/= 10; }
- *s2--= 0;
- while(s2>s1)
- { c= *s1; *s1= *s2; *s2= c; s1++; s2--; }
- write_str(s);
- } // end write_sint32()
-#endif
-
-static inline void write_uint64(uint64_t v) {
- // write an unsigned 64 bit integer number to standard output;
- char s[30],*s1,*s2,c;
-
- s1= s;
- if(v==0)
- *s1++= '0';
- s2= s1;
- while(v>0)
- { *s2++= (v%10)+'0'; v/= 10; }
- *s2--= 0;
- while(s2>s1)
- { c= *s1; *s1= *s2; *s2= c; s1++; s2--; }
- write_str(s);
- } // end write_uint64()
-
-static inline void write_sint64(int64_t v) {
- // write a signed 64 bit integer number to standard output;
- static char s[30],*s1,*s2,c;
-
- s1= s;
- if(v<0)
- { *s1++= '-'; v= -v; }
- else if(v==0)
- *s1++= '0';
- s2= s1;
- while(v>0)
- { *s2++= (v%10)+'0'; v/= 10; }
- *s2--= 0;
- while(s2>s1)
- { c= *s1; *s1= *s2; *s2= c; s1++; s2--; }
- write_str(s);
- } // end write_sint64()
-
-static inline void write_sfix7(int32_t v) {
- // write a signed 7 decimals fixpoint value to standard output;
- char s[20],*s1,*s2,c;
- int i;
-
- s1= s;
- if(v<0)
- { *s1++= '-'; v= -v; }
- s2= s1;
- i= 7;
- while((v%10)==0 && i>1) // trailing zeros
- { v/= 10; i--; }
- while(--i>=0)
- { *s2++= (v%10)+'0'; v/= 10; }
- *s2++= '.';
- do
- { *s2++= (v%10)+'0'; v/= 10; }
- while(v>0);
- *s2--= 0;
- while(s2>s1)
- { c= *s1; *s1= *s2; *s2= c; s1++; s2--; }
- write_str(s);
- } // end write_sfix7()
-
-static inline void write_sfix7o(int32_t v) {
- // write a signed 7 decimals fixpoint value to standard output;
- // keep trailing zeros;
- char s[20],*s1,*s2,c;
- int i;
-
- s1= s;
- if(v<0)
- { *s1++= '-'; v= -v; }
- s2= s1;
- i= 7;
- while(--i>=0)
- { *s2++= (v%10)+'0'; v/= 10; }
- *s2++= '.';
- do
- { *s2++= (v%10)+'0'; v/= 10; }
- while(v>0);
- *s2--= 0;
- while(s2>s1)
- { c= *s1; *s1= *s2; *s2= c; s1++; s2--; }
- write_str(s);
- } // end write_sfix7o()
-
-static inline void write_sfix6o(int32_t v) {
- // write a signed 6 decimals fixpoint value to standard output;
- // keep trailing zeros;
- char s[20],*s1,*s2,c;
- int i;
-
- s1= s;
- if(v<0)
- { *s1++= '-'; v= -v; }
- s2= s1;
- i= 6;
- while(--i>=0)
- { *s2++= (v%10)+'0'; v/= 10; }
- *s2++= '.';
- do
- { *s2++= (v%10)+'0'; v/= 10; }
- while(v>0);
- *s2--= 0;
- while(s2>s1)
- { c= *s1; *s1= *s2; *s2= c; s1++; s2--; }
- write_str(s);
- } // end write_sfix6o()
-
-#if 0 // currently unused
-static inline void write_sfix9(int64_t v) {
- // write a signed 9 decimals fixpoint value to standard output;
- char s[20],*s1,*s2,c;
- int i;
-
- s1= s;
- if(v<0)
- { *s1++= '-'; v= -v; }
- s2= s1;
- i= 9;
- while(--i>=0)
- { *s2++= (v%10)+'0'; v/= 10; }
- *s2++= '.';
- do
- { *s2++= (v%10)+'0'; v/= 10; }
- while(v>0);
- *s2--= 0;
- while(s2>s1)
- { c= *s1; *s1= *s2; *s2= c; s1++; s2--; }
- write_str(s);
- } // end write_sfix9()
-#endif
-
-static void write_timestamp(uint64_t v) {
- // write a timestamp in OSM format, e.g.: "2010-09-30T19:23:30Z"
- time_t vtime;
- struct tm tm;
- char s[30],*sp;
- int i;
-
- vtime= v;
- #if __WIN32__
- memcpy(&tm,gmtime(&vtime),sizeof(tm));
- #else
- gmtime_r(&vtime,&tm);
- #endif
- i= tm.tm_year+1900;
- sp= s+3; *sp--= i%10+'0';
- i/=10; *sp--= i%10+'0';
- i/=10; *sp--= i%10+'0';
- i/=10; *sp= i%10+'0';
- sp+= 4; *sp++= '-';
- i= tm.tm_mon+1;
- *sp++= i/10+'0'; *sp++= i%10+'0'; *sp++= '-';
- i= tm.tm_mday;
- *sp++= i/10+'0'; *sp++= i%10+'0'; *sp++= 'T';
- i= tm.tm_hour;
- *sp++= i/10+'0'; *sp++= i%10+'0'; *sp++= ':';
- i= tm.tm_min;
- *sp++= i/10+'0'; *sp++= i%10+'0'; *sp++= ':';
- i= tm.tm_sec%60;
- *sp++= i/10+'0'; *sp++= i%10+'0'; *sp++= 'Z'; *sp= 0;
- write_str(s);
- } // end write_timestamp()
-
-//------------------------------------------------------------
-// end Module write_ write module
-//------------------------------------------------------------
-
-
-
-//------------------------------------------------------------
-// Module count_ tag count module
-//------------------------------------------------------------
-
-// this module contains procedures which are responsible for
-// counting the keys or the values of OSM tags;
-// as usual, all identifiers of a module have the same prefix,
-// in this case 'count_'; one underline will follow in case of a
-// global accessible object, two underlines in case of objects
-// which are not meant to be accessed from outside this module;
-// the sections of private and public definitions are separated
-// by a horizontal line: ----
-
-#define count__itemM 1000000
-#define count__itemMs "1000000"
-#define count__nameL 60
-#define count__nameLs "60"
-#define STR(s) #s
-
-typedef struct {
- int32_t counter;
- char name[count__nameL];
- } count__item_t;
-static count__item_t* count__item= NULL;
-static count__item_t* count__iteme= NULL,*count__itemee= NULL;
- // last logical and last physical element (each exclusive);
-static count__item_t** count__index= NULL;
- // index table of the item table
-static count__item_t** count__indexe= NULL;
- // last logical element (exclusive);
-
-static int count__qsortcount(const void* a,const void* b) {
- // count comparison for qsort()
- int32_t ax,bx;
-
- ax= (*(count__item_t**)a)->counter;
- bx= (*(count__item_t**)b)->counter;
- if(ax>bx)
-return -1;
- if(ax<bx)
-return 1;
- return
- strcmp((*(count__item_t**)a)->name,(*(count__item_t**)b)->name);
- } // end count__qsortcount()
-
-static void count__end() {
- // clean-up module's variables;
- if(count__item!=NULL) {
- free(count__item);
- count__item= NULL;
- }
- if(count__index!=NULL) {
- free(count__index);
- count__index= NULL;
- }
- } // end count__end()
-
-//------------------------------------------------------------
-
-static int count_ini() {
- // initialize this module;
- // return: ==0: ok; 1: could not get the memory;
- if(count__item!=NULL) // already initialized
-return 0;
- count__item=
- (count__item_t*)malloc(sizeof(count__item_t)*count__itemM);
- if(count__item==NULL)
- goto error;
- count__iteme= count__item;
- count__itemee= count__item+count__itemM;
- atexit(count__end);
- count__index=
- (count__item_t**)malloc(sizeof(count__item_t*)*count__itemM);
- if(count__index==NULL)
- goto error;
- count__indexe= count__index;
- return 0;
-error:
- PERR("could not get memory for the counter.")
- return 1;
- } // end count_ini()
-
-static inline void count_add(const char* name) {
- // add a new name to the item table;
- count__item_t** low,**mid,**high;
- const byte* np,*sp;
- static int compare= -1;
- int size;
-
- // determine if the name already exists in the table;
- low= count__index; high= count__indexe-1; mid= count__index;
- while(low<=high) {
- mid= low+(high-low)/2;
- np= (byte*)name;
- sp= (byte*)((*mid)->name);
- #define D if((compare= *np-*sp)==0 && *np!=0) {np++; sp++;
- // (just to speed-up the comparison a bit)
- D D D D D D D D D D D D D D D D
- compare= strncmp((char*)np,(char*)sp,count__nameL-1-16);
- }}}}}}}}}}}}}}}}
- #undef D
- if(compare==0)
- break;
- if(compare<0)
- high= mid-1;
- else
- low= mid+1;
- }
- if(compare==0) { // found element match
- // increment this element's counter
- (*mid)->counter++;
-return;
- } // found element match
- // here: did not find a matching element
-
- // add a new element to the and insert new index into index list
- if(count__iteme>=count__itemee) { // no space left in table
- WARN("too many items to count (maximum is "count__itemMs").")
-return;
- } // end no space left in table
- count__iteme->counter= 1;
- strMcpy(count__iteme->name,name);
- if(compare>0) mid++;
- size= (char*)count__indexe-(char*)mid;
- if(size>0)
- memmove(mid+1,mid,size);
- *mid= count__iteme;
- count__iteme++;
- count__indexe++;
- } // end count_add()
-
-static void count_sort() {
- // sort the list of items by the number of their occurrence
- qsort(count__index,count__indexe-count__index,sizeof(*count__index),
- count__qsortcount);
- } // end count_sort()
-
-static void count_write() {
- // write the list of items to output stream
- char s[20+count__nameL+10];
- count__item_t** kpp,*kp;
-
- kpp= count__index;
- while(kpp<count__indexe) {
- kp= *kpp;
- sprintf(s,"%11i\t%."count__nameLs"s"NL,kp->counter,kp->name);
- write_str(s);
- kpp++;
- }
- } // end count_write()
-
-//------------------------------------------------------------
-// end Module count_ tag count module
-//------------------------------------------------------------
-
-
-
-//------------------------------------------------------------
-// Module fil_ osm filter module
-//------------------------------------------------------------
-
-// this module contains procedures which are responsible for
-// filtering OSM data;
-// as usual, all identifiers of a module have the same prefix,
-// in this case 'fil_'; one underline will follow in case of a
-// global accessible object, two underlines in case of objects
-// which are not meant to be accessed from outside this module;
-// the sections of private and public definitions are separated
-// by a horizontal line: ----
-
-static inline void fil_stresccpy(char *dest, const char *src,
- size_t len) {
- // similar as strmpy(), but remove every initial '\\' character;
- // len: length of the source string - without terminating zero;
- while(len>0) {
- if(*src=='\\') { src++; len--; }
- if(!(len>0) || *src==0)
- break;
- len--;
- *dest++= *src++;
- }
- *dest= 0;
- } // end fil_stresccpy()
-
-static inline bool fil__cmp(const char* s1,const char* s2) {
- // this procedure compares two character strings;
- // s1[]: first string;
- // s2[0]: operator which shall be used for comparison;
- // 0: '=', and there are wildcards coded in s2[1]:
- // s2[1]==1: wildcard at start;
- // s2[1]==2: wildcard at end;
- // s2[1]==3: wildcard at both, start and end;
- // 1: '!=', and there are wildcards coded in s2[1];
- // 2: '='
- // 4: '<'
- // 5: '>='
- // 6: '>'
- // 7: '<='
- // 8: unused
- // 9: unused
- // 10: '=', numeric
- // 11: '!=', numeric
- // 12: '<', numeric
- // 13: '>=', numeric
- // 14: '>', numeric
- // 15: '<=', numeric
- // s2+1: string to compare with the first string;
- // this string will start at s2+2 if wildcards are supplied;
- // return: condition is met;
- int op,wc; // operator, wildcard flags
- int diff; // (for numeric comparison)
- unsigned char s1v,s2v; // (for numeric comparison)
-
- op= *s2++;
- if(op==2) { // '='
- // first we care about the 'equal' operator
- // because it's the most frequently used option
- while(*s1==*s2 && *s1!=0) { s1++; s2++; }
- return *s1==0 && *s2==0;
- }
- switch(op) { // depending on comparison operator
- case 0: // '=', and there are wildcards
- wc= *s2++;
- if(wc==2) { // wildcard at end
- while(*s1==*s2 && *s1!=0) { s1++; s2++; }
- return *s2==0;
- } // wildcard at end
- if(wc==1) { // wildcard at start
- const char* s11,*s22;
-
- while(*s1!=0) { // for all start positions in s1[]
- s11= s1; s22= s2;
- while(*s11==*s22 && *s11!=0) { s11++; s22++; }
- if(*s11==0 && *s22==0)
- return true;
- s1++;
- } // for all start positions in s1[]
- return false;
- } // wildcard at start
- /* wildcards at start and end */ {
- const char* s11,*s22;
-
- while(*s1!=0) { // for all start positions in s1[]
- s11= s1; s22= s2;
- while(*s11==*s22 && *s11!=0) { s11++; s22++; }
- if(*s22==0)
- return true;
- s1++;
- } // for all start positions in s1[]
- return false;
- } // wildcards at start and end
- case 1: // '!=', and there are wildcards
- wc= *s2++;
- if(wc==2) { // wildcard at end
- while(*s1==*s2 && *s1!=0) { s1++; s2++; }
- return *s2!=0;
- } // wildcard at end
- if(wc==1) { // wildcard at start
- const char* s11,*s22;
-
- while(*s1!=0) { // for all start positions in s1[]
- s11= s1; s22= s2;
- while(*s11==*s22 && *s11!=0) { s11++; s22++; }
- if(*s11==0 && *s22==0)
- return false;
- s1++;
- } // for all start positions in s1[]
- return true;
- } // wildcard at start
- /* wildcards at start and end */ {
- const char* s11,*s22;
-
- while(*s1!=0) { // for all start positions in s1[]
- s11= s1; s22= s2;
- while(*s11==*s22 && *s11!=0) { s11++; s22++; }
- if(*s22==0)
- return false;
- s1++;
- } // for all start positions in s1[]
- return true;
- } // wildcards at start and end
- //case 2: // '=' (we already cared about this)
- case 3: // '!='
- while(*s1==*s2 && *s1!=0) { s1++; s2++; }
- return *s1!=0 || *s2!=0;
- case 4: // '<'
- while(*s1==*s2 && *s1!=0) { s1++; s2++; }
- return *(unsigned char*)s1 < *(unsigned char*)s2;
- case 5: // '>='
- while(*s1==*s2 && *s1!=0) { s1++; s2++; }
- return *(unsigned char*)s1 >= *(unsigned char*)s2;
- case 6: // '>'
- while(*s1==*s2 && *s1!=0) { s1++; s2++; }
- return *(unsigned char*)s1 > *(unsigned char*)s2;
- case 7: // '<='
- while(*s1==*s2 && *s1!=0) { s1++; s2++; }
- return *(unsigned char*)s1 <= *(unsigned char*)s2;
- case 10: // '=', numeric
- while(*s1=='0') s1++;
- while(*s2=='0') s2++;
- while(*s1==*s2 && isdigi(*(unsigned char*)s1))
- { s1++; s2++; }
- if(*s1=='.') {
- if(*s2=='.') {
- do { s1++; s2++; }
- while(*s1==*s2 && isdigi(*(unsigned char*)s1));
- if(!isdigi(*(unsigned char*)s1)) {
- while(*s2=='0') s2++;
- return !isdigi(*(unsigned char*)s2);
- }
- if(!isdigi(*(unsigned char*)s2)) {
- while(*s1=='0') s1++;
- return !isdigi(*(unsigned char*)s1);
- }
- return !isdigi(*(unsigned char*)s1) &&
- !isdigi(*(unsigned char*)s2);
- }
- do s1++;
- while(*s1=='0');
- return !isdigi(*(unsigned char*)s1);
- }
- if(*s2=='.') {
- do s2++;
- while(*s2=='0');
- return !isdigi(*(unsigned char*)s2);
- }
- return !isdigi(*(unsigned char*)s1) && !isdigi(*(unsigned char*)s2);
- case 11: // '!=', numeric
- while(*s1=='0') s1++;
- while(*s2=='0') s2++;
- while(*s1==*s2 && isdigi(*(unsigned char*)s1))
- { s1++; s2++; }
- if(*s1=='.') {
- if(*s2=='.') {
- do { s1++; s2++; }
- while(*s1==*s2 && isdigi(*(unsigned char*)s1));
- if(!isdigi(*(unsigned char*)s1)) {
- while(*s2=='0') s2++;
- return isdigi(*(unsigned char*)s2);
- }
- if(!isdigi(*(unsigned char*)s2)) {
- while(*s1=='0') s1++;
- return isdigi(*(unsigned char*)s1);
- }
- return isdigi(*(unsigned char*)s1) ||
- isdigi(*(unsigned char*)s2);
- }
- do s1++;
- while(*s1=='0');
- return isdigi(*(unsigned char*)s1);
- }
- if(*s2=='.') {
- do s2++;
- while(*s2=='0');
- return isdigi(*(unsigned char*)s2);
- }
- return isdigi(*(unsigned char*)s1) || isdigi(*(unsigned char*)s2);
- case 12: /* '<', numeric */
- #define Ds1 s1
- #define Ds2 s2
- s1v= *(unsigned char*)Ds1; s2v= *(unsigned char*)Ds2;
- if(s1v=='-') {
- if(s2v=='-') {
- Ds1++; s2v= *(unsigned char*)Ds1;
- Ds2++; s1v= *(unsigned char*)Ds2;
- goto op_14;
- }
- return true;
- }
- else if(s2v=='-')
- return false;
- op_12:
- while(s1v=='0') { Ds1++; s1v= *(unsigned char*)Ds1; }
- while(s2v=='0') { Ds2++; s2v= *(unsigned char*)Ds2; }
- while(s1v==s2v && isdigi(s1v)) {
- Ds1++; s1v= *(unsigned char*)Ds1;
- Ds2++; s2v= *(unsigned char*)Ds2;
- }
- diff= digival(s1v)-digival(s2v);
- while(isdigi(s1v) && isdigi(s2v)) {
- Ds1++; s1v= *(unsigned char*)Ds1;
- Ds2++; s2v= *(unsigned char*)Ds2;
- }
- if(s1v=='.') {
- if(s2v=='.') {
- if(diff!=0)
- return diff<0;
- do {
- Ds1++; s1v= *(unsigned char*)Ds1;
- Ds2++; s2v= *(unsigned char*)Ds2;
- } while(s1v==s2v && isdigi(s1v));
- while(s2v=='0') { Ds2++; s2v= *(unsigned char*)Ds2; }
- return digival(s1v) < digival(s2v);
- }
- return isdigi(s2v) || diff<0;
- }
- if(s2v=='.') {
- if(isdigi(s1v))
- return false;
- if(diff!=0)
- return diff<0;
- do { Ds2++; s2v= *(unsigned char*)Ds2; } while(s2v=='0');
- return isdigi(s2v);
- }
- return isdigi(s2v) || (!isdigi(s1v) && diff<0);
- #undef Ds1
- #undef Ds2
- case 13: /* '>=', numeric */
- #define Ds1 s1
- #define Ds2 s2
- s1v= *(unsigned char*)Ds1; s2v= *(unsigned char*)Ds2;
- if(s1v=='-') {
- if(s2v=='-') {
- Ds1++; s2v= *(unsigned char*)Ds1;
- Ds2++; s1v= *(unsigned char*)Ds2;
- goto op_15;
- }
- return false;
- }
- else if(s2v=='-')
- return true;
- op_13:
- while(s1v=='0') { Ds1++; s1v= *(unsigned char*)Ds1; }
- while(s2v=='0') { Ds2++; s2v= *(unsigned char*)Ds2; }
- while(s1v==s2v && isdigi(s1v)) {
- Ds1++; s1v= *(unsigned char*)Ds1;
- Ds2++; s2v= *(unsigned char*)Ds2;
- }
- diff= digival(s1v)-digival(s2v);
- while(isdigi(s1v) && isdigi(s2v)) {
- Ds1++; s1v= *(unsigned char*)Ds1;
- Ds2++; s2v= *(unsigned char*)Ds2;
- }
- if(s1v=='.') {
- if(s2v=='.') {
- if(diff!=0)
- return diff>=0;
- do {
- Ds1++; s1v= *(unsigned char*)Ds1;
- Ds2++; s2v= *(unsigned char*)Ds2;
- } while(s1v==s2v && isdigi(s1v));
- while(s2v=='0') { Ds2++; s2v= *(unsigned char*)Ds2; }
- return digival(s1v) >= digival(s2v);
- }
- return !isdigi(s2v) && diff>=0;
- }
- if(s2v=='.') {
- if(isdigi(s1v))
- return true;
- if(diff!=0)
- return diff>=0;
- do { Ds2++; s2v= *(unsigned char*)Ds2; } while(s2v=='0');
- return !isdigi(s2v);
- }
- return !isdigi(s2v) && (isdigi(s1v) || diff>=0);
- #undef Ds1
- #undef Ds2
- case 14: /* '>', numeric */
- #define Ds1 s2
- #define Ds2 s1
- s1v= *(unsigned char*)Ds1; s2v= *(unsigned char*)Ds2;
- if(s1v=='-') {
- if(s2v=='-') {
- Ds1++; s2v= *(unsigned char*)Ds1;
- Ds2++; s1v= *(unsigned char*)Ds2;
- goto op_12;
- }
- return true;
- }
- else if(s2v=='-')
- return false;
- op_14:
- while(s1v=='0') { Ds1++; s1v= *(unsigned char*)Ds1; }
- while(s2v=='0') { Ds2++; s2v= *(unsigned char*)Ds2; }
- while(s1v==s2v && isdigi(s1v)) {
- Ds1++; s1v= *(unsigned char*)Ds1;
- Ds2++; s2v= *(unsigned char*)Ds2;
- }
- diff= digival(s1v)-digival(s2v);
- while(isdigi(s1v) && isdigi(s2v)) {
- Ds1++; s1v= *(unsigned char*)Ds1;
- Ds2++; s2v= *(unsigned char*)Ds2;
- }
- if(s1v=='.') {
- if(s2v=='.') {
- if(diff!=0)
- return diff<0;
- do {
- Ds1++; s1v= *(unsigned char*)Ds1;
- Ds2++; s2v= *(unsigned char*)Ds2;
- } while(s1v==s2v && isdigi(s1v));
- while(s2v=='0') { Ds2++; s2v= *(unsigned char*)Ds2; }
- return digival(s1v) < digival(s2v);
- }
- return isdigi(s2v) || diff<0;
- }
- if(s2v=='.') {
- if(isdigi(s1v))
- return false;
- if(diff!=0)
- return diff<0;
- do { Ds2++; s2v= *(unsigned char*)Ds2; } while(s2v=='0');
- return isdigi(s2v);
- }
- return isdigi(s2v) || (!isdigi(s1v) && diff<0);
- #undef Ds1
- #undef Ds2
- case 15: /* '<=', numeric */
- #define Ds1 s2
- #define Ds2 s1
- s1v= *(unsigned char*)Ds1; s2v= *(unsigned char*)Ds2;
- if(s1v=='-') {
- if(s2v=='-') {
- Ds1++; s2v= *(unsigned char*)Ds1;
- Ds2++; s1v= *(unsigned char*)Ds2;
- goto op_13;
- }
- return false;
- }
- else if(s2v=='-')
- return true;
- op_15:
- while(s1v=='0') { Ds1++; s1v= *(unsigned char*)Ds1; }
- while(s2v=='0') { Ds2++; s2v= *(unsigned char*)Ds2; }
- while(s1v==s2v && isdigi(s1v)) {
- Ds1++; s1v= *(unsigned char*)Ds1;
- Ds2++; s2v= *(unsigned char*)Ds2;
- }
- diff= digival(s1v)-digival(s2v);
- while(isdigi(s1v) && isdigi(s2v)) {
- Ds1++; s1v= *(unsigned char*)Ds1;
- Ds2++; s2v= *(unsigned char*)Ds2;
- }
- if(s1v=='.') {
- if(s2v=='.') {
- if(diff!=0)
- return diff>=0;
- do {
- Ds1++; s1v= *(unsigned char*)Ds1;
- Ds2++; s2v= *(unsigned char*)Ds2;
- } while(s1v==s2v && isdigi(s1v));
- while(s2v=='0') { Ds2++; s2v= *(unsigned char*)Ds2; }
- return digival(s1v) >= digival(s2v);
- }
- return !isdigi(s2v) && diff>=0;
- }
- if(s2v=='.') {
- if(isdigi(s1v))
- return true;
- if(diff!=0)
- return diff>=0;
- do { Ds2++; s2v= *(unsigned char*)Ds2; } while(s2v=='0');
- return !isdigi(s2v);
- }
- return !isdigi(s2v) && (isdigi(s1v) || diff>=0);
- #undef Ds1
- #undef Ds2
- // (no default)
- } // depending on comparison operator
- return false; // (we never get here)
- } // end fil__cmp()
-
-#define fil__pairM 1000 // maximum number of key-val-pairs
-#define fil__pairkM 100 // maximum length of key or val;
-#define fil__pairtM 12 // maximum number of filter types;
- // these filter types are defined as follows:
- // 0: keep node object;
- // 1: keep way object;
- // 2: keep relation object;
- // 3: drop node object;
- // 4: drop way object;
- // 5: drop relation object;
- // 6: keep node tag;
- // 7: keep way tag;
- // 8: keep relation tag;
- // 9: drop node tag;
- // 10: drop way tag;
- // 11: drop relation tag;
-typedef struct { // key/val pair for the include filter
- char k[fil__pairkM+8]; // key to compare;
- // [0]==0 && [1]==0: same key as previous key in list;
- char v[fil__pairkM+8]; // value to the key in .k[];
- // the first byte represents a comparison operator,
- // see parameter s2[]in fil__cmp() for details;
- // [0]==0 && [1]==0: any value will be accepted;
- int left_bracketn;
- // number of opening brackets right before the comparison
- int right_bracketn;
- // number of closing brackets right after the comparison
- bool operator;
- // Boolean operator right after the closing bracket, resp.
- // right after the comparison, if there is no closing bracket;
- // false: OR; true: AND;
- } fil__pair_t;
-static fil__pair_t fil__pair[fil__pairtM][fil__pairM+2]=
- {{{{0},{0},0,0,false}}};
-static fil__pair_t* fil__paire[fil__pairtM]=
- { &fil__pair[0][0],&fil__pair[1][0],
- &fil__pair[2][0],&fil__pair[3][0],
- &fil__pair[4][0],&fil__pair[5][0],
- &fil__pair[6][0],&fil__pair[7][0],
- &fil__pair[8][0],&fil__pair[9][0],
- &fil__pair[10][0],&fil__pair[11][0] };
-static fil__pair_t* fil__pairee[fil__pairtM]=
- { &fil__pair[0][fil__pairM],&fil__pair[1][fil__pairM],
- &fil__pair[2][fil__pairM],&fil__pair[3][fil__pairM],
- &fil__pair[4][fil__pairM],&fil__pair[5][fil__pairM],
- &fil__pair[6][fil__pairM],&fil__pair[7][fil__pairM],
- &fil__pair[8][fil__pairM],&fil__pair[9][fil__pairM],
- &fil__pair[10][fil__pairM],&fil__pair[11][fil__pairM] };
-static int fil__err_tagsbool= 0;
- // number of Boolean expressions in tags filter
-static int fil__err_tagsbracket= 0;
- // number of brackets in tags filter
-
-//------------------------------------------------------------
-
-static inline void fil_cpy(char *dest, const char *src,
- size_t len,int op) {
- // similar as strmpy(), but remove every initial '\\' character;
- // len: length of the source string - without terminating zero;
- // op: comparison operator;
- // 2: '='
- // 4: '<'
- // 5: '>='
- // 6: '>'
- // 7: '<='
- // return: dest[0]: comparison operator; additional possible values:
- // 0: '=', and there are wildcards coded in dest[1]:
- // dest[1]==1: wildcard at start;
- // dest[1]==2: wildcard at end;
- // dest[1]==3: wildcard at both, start and end;
- // 1: '!=', and there are wildcards coded in dest[1];
- // 10: '=', numeric
- // 11: '!=', numeric
- // 12: '<', numeric
- // 13: '>=', numeric
- // 14: '>', numeric
- // 15: '<=', numeric
- int wc; // wildcard indicator, see fil__cmp()
-
- if(op<0) { // unknown operator
- WARNv("unknown comparison at: %.80s",src)
- op= 2; // assume '='
- }
- if(len>(fil__pairkM)) {
- len= fil__pairkM; // delimit value length
- WARNv("filter argument too long: %.*s",fil__pairkM,src)
- }
- wc= 0; // (default)
- if(len>=2 && src[0]=='*') { // wildcard at start
- wc|= 1;
- src++; len--;
- }
- if((len>=2 && src[len-1]=='*' && src[len-2]!='\\') ||
- (len==1 && src[len-1]=='*')) {
- // wildcard at end
- wc|= 2;
- len--;
- }
- if(wc==0) { // no wildcard(s)
- const char* v;
-
- v= src;
- if(*v=='-') v++; // jump over sign
- if(isdig(*v)) // numeric value
- op+= 8;
- dest[0]= op;
- fil_stresccpy(dest+1,src,len); // store this value
- } // no wildcard(s)
- else { // wildcard(s)
- dest[0]= op&1;
- dest[1]= wc;
- fil_stresccpy(dest+2,src,len); // store this value
- } // wildcard(s)
- } // end fil_cpy()
-
-static bool fil_active[fil__pairtM]=
- {false,false,false,false,false,false,
- false,false,false,false,false,false};
- // the related filter list has at least one element;
- // may be written only by this module;
-static bool fil_activeo[3]= {false,false,false};
- // at least one of the filter lists 6..8 and 9..11 has
- // at least one element;
- // index is otype: 0: node; 1: way; 2: relation;
-static bool fil_meetall[fil__pairtM]=
- {false,false,false,false,false,false,
- false,false,false,false,false,false};
- // the tested object must meet all criteria of this filter;
- // for ftype==0..3 ('keep object'):
- // conditions are combined with 'AND';
- // ftype==6..8 ('keep tags'):
- // every tag which is not listed in the filter parameter will
- // be deleted;
- // this element is valid only if there is at least one
- // entry in previous fields;
-
-static bool fil_filterheader= false;
- // there are filter parameters which affect the header; therefore the
- // OSM object header values must be checked;
- // this value must not be changed from outside the module;
-
-static void fil_ini() {
- // initialize this mudule;
- // (this procedure is not speed-optimized)
- int i;
-
- //memset(fil__pair,0,sizeof(fil__pair));
- for(i= 0; i<fil__pairtM; i++) {
- fil__paire[i]= &fil__pair[i][0];
- fil__pairee[i]= &fil__pair[i][fil__pairM];
- fil_active[i]= false;
- fil_activeo[i/4]= false;
- fil_meetall[i]= false;
- fil__pair[i][0].left_bracketn= 0;
- }
- fil__err_tagsbool= fil__err_tagsbracket= 0;
- fil_filterheader= false;
- } // fil_ini()
-
-static void fil_parse(int ftype,const char* arg) {
- // interprets a command line argument and stores filter information;
- // Boolean terms are recognized;
- // ftype: filter type; see explanation at fil__pairtM;
- // arg[]: filter information; e.g.:
- // "amenity=restaurant && name=John =Meyer"
- fil__pair_t* fp,*fe,*fee;
- const char* pk,*pv,*pe; // pointers in parameter for key/val pairs;
- // pk: key; pv: val; pe: end of val;
- bool meetall; // same as fil_meetall[ftype]
- int len; // string length
- int argop; // argument operator; 0: unknown; '&', '|', '(', ')';
- int op; // operator, see fil__cmp()
-
- fp= fil__pair[ftype];
- fe= fil__paire[ftype];
- fee= fil__pairee[ftype];
- if(loglevel>0)
- PINFOv("Filter: %s %s%s:",
- ftype/3%2==0? "keep": "drop",ONAME(ftype%3),
- ftype<6? "s": " tags")
- pk= arg;
- while(*pk==' ') pk++; // jump over spaces
- if(strzcmp(pk,"all ")==0 || strzcmp(pk,"and ")==0) {
- if(loglevel>0)
- PINFO("Filter: meet all conditions.")
- fil_meetall[ftype]= true;
- pk+= 4;
- }
- meetall= fil_meetall[ftype];
- while(pk!=NULL && fe<fee) { // for every key/val pair
- while(*pk==' ') pk++; // jump over (additional) spaces
- if(*pk==0)
- break;
- pe= pk;
- while((*pe!=' ' || pe[-1]=='\\') && *pe!=0) pe++;
- // get end of this pair
- len= pe-pk; // length of this argument
- argop= 0; // (default)
- if(len==2 && strzcmp(pk,"&&")==0) argop= '&';
- else if(len==2 && strzcmp(pk,"||")==0) argop= '|';
- else if(len==3 && strzcmp(pk,"AND")==0) argop= '&';
- else if(len==2 && strzcmp(pk,"OR")==0) argop= '|';
- else if(len==3 && strzcmp(pk,"and")==0) argop= '&';
- else if(len==2 && strzcmp(pk,"or")==0) argop= '|';
- else if(len==1 && strzcmp(pk,"(")==0) argop= '(';
- else if(len==1 && strzcmp(pk,")")==0) argop= ')';
- if(argop!=0) { // this is an argument operator
- if(ftype>=6) { // filter type applies to tags
- if(argop=='(' || argop==')')
- fil__err_tagsbracket++;
- else
- fil__err_tagsbool++;
- pk= pe; // jump to next key/val pair in parameter list
- continue;
- } // filter type applies to tags
- if(fe==fp) { // first argument
- if(argop=='(') {
- if(loglevel>0) PINFO("Filter: (")
- fe[0].left_bracketn++;
- }
- else
- WARNv("Unknown operator at start of: %.80s",pk)
- }
- else switch(argop) { // in dependence of argument operator
- // add Boolean operator to previous comparison
- case '&':
- if(loglevel>0) PINFO("Filter: AND")
- fe[-1].operator= true; break;
- case '|':
- if(loglevel>0) PINFO("Filter: OR")
- fe[-1].operator= false; break;
- case ')':
- if(loglevel>0) PINFO("Filter: )")
- if(fe[0].left_bracketn!=0)
- WARNv("Bracket error at: %.80s",pk)
- fe[-1].right_bracketn++;
- break;
- case '(':
- if(loglevel>0) PINFO("Filter: (")
- fe[0].left_bracketn++;
- break;
- } // in dependence of argument operator
- pk= pe; // jump to next key/val pair in parameter list
- continue;
- }
- pv= pk;
- while(((*pv!='=' && *pv!='<' && *pv!='>' &&
- (*pv!='!' || pv[1]!='=')) ||
- (pv>pk && pv[-1]=='\\')) && pv<pe) pv++;
- // find operator =, <, >, !=
- if(pv>=pe-1) pv= pe; // there was no operator in this pair
- len= pv-pk; // length of this key
- if(len>(fil__pairkM)) {
- len= fil__pairkM; // delimit key length
- WARNv("filter key too long: %.*s",fil__pairkM,pk)
- }
- op= -1; // 'unknown operator' (default)
- if(pv>=pe) { // there is a key but no value
- if(len>0 && pk[len-1]=='=') len--;
- fil_cpy(fe->k,pk,len,2); // store this key, op='='
- memset(fe->v,0,3); // store empty value
- }
- else { // key and value
- if(len==0) // no key given
- memset(fe->k,0,3); // store empty key,
- // i.e., mark pair as 'pair with same key';
- // note that this is not allowed at start of term,
- // after bracket(s) and after different operators;
- // this will be checked in fil_plausi();
- else
- fil_cpy(fe->k,pk,len,2); // store this key, op='='
- if(*pv=='=') op= 2;
- else if(*pv=='!' && pv[1]=='=') op= 3;
- else if(*pv=='<' && pv[1]!='=') op= 4;
- else if(*pv=='>' && pv[1]=='=') op= 5;
- else if(*pv=='>' && pv[1]!='=') op= 6;
- else if(*pv=='<' && pv[1]=='=') op= 7;
- if(op<0) { // unknown operator
- WARNv("unknown comparison at: %.80s",pv)
- op= 2; // assume '='
- }
- pv++; // jump over operator
- if(pv<pe && *pv=='=') pv++;
- // jump over second character of a two-character operator
- len= pe-pv; // length of this value
- fil_cpy(fe->v,pv,len,op); // store this value
- } // key and value
- if(loglevel>0) {
- static const char* ops[]= { "?",
- "=","!=","=","!=","<",">=",">","<=",
- "?","?","=(numeric)","!=(numeric)",
- "<(numeric)",">=(numeric)",">(numeric)","<=(numeric)" };
-
- PINFOv("Filter: %s\"%.80s\"%s %s %s\"%.80s\"%s",
- fe->k[0]<=1 && (fe->k[1] & 1)? "*": "",
- *(int16_t*)(fe->k)==0? "(last key)":
- fe->k[0]>=2? fe->k+1: fe->k+2,
- fe->k[0]<=1 && (fe->k[1] & 2)? "*": "",
- ops[fe->v[0]+1],
- fe->v[0]<=1 && (fe->v[1] & 1)? "*": "",
- *(int16_t*)(fe->v)==0? "(anything)":
- fe->v[0]>=2? fe->v+1: fe->v+2,
- fe->v[0]<=1 && (fe->v[1] & 2)? "*": "");
- }
- if(fe->k[1]=='@')
- fil_filterheader= true;
- fe->right_bracketn= 0;
- fe->operator= false;
- if(fe>fp && meetall && *(int16_t*)fe->k!=0)
- // not first comparison AND all conditions are to be met AND
- // this comparison has not an empty key
- fe[-1].operator= true;
- fe++; // next pair in key/val table
- fe->left_bracketn= 0;
- pk= pe; // jump to next key/val pair in parameter list
- } // end for every key/val pair
- if(fe>=fee)
- WARN("too many filter parameters.")
- fil__paire[ftype]= fe;
- fil_active[ftype]= true;
- if(ftype/3==2 || ftype/3==3) // keep tags OR drop tags
- fil_activeo[ftype%3]= true;
- if(ftype<6)
- global_recursive= true; // recursive processing is necessary
- } // end fil_parse()
-
-static int fil_plausi() {
- // check plausibility of filter parameter;
- // may be called after all parameters have been parsed
- // with fil_parse();
- // furthermore, this procedure inserts brackets to invert
- // Boolean operator priorities if the keyword "all" had been given;
- // return: o: OK; !=0: syntax error;
- int ft; // filter type
- int bracket_balance;
- int bl; // open brackets without correspondence
- int br; // closed brackets without correspondence
- int bm; // bracket occurrences if 'meetall'
- fil__pair_t* f,*fp,*fe;
- int synt; // number of syntax errors
- //int tagsbool; // number of Boolean expressions in tags filter
- //int tagsbracket; // number of brackets in tags filter
-
- // check plausibility
- bl= br= bm= synt= 0;
- //tagsbool= tagsbracket= 0;
- for(ft= 0;ft<6;ft++) { // for every object filter type
- fp= f= fil__pair[ft]; fe= fil__paire[ft];
- bracket_balance= 0;
- while(fp<fe) { // for every key/val pair in filter
- bracket_balance+= fp->left_bracketn-fp->right_bracketn;
- if(fil_meetall[ft] &&
- (fp->left_bracketn!=0 || fp->right_bracketn!=0))
- bm++;
- if(*(int16_t*)fp->k==0) { // empty key
- if(fp==f) {
- PERR("empty key cannot start a term.")
- synt++;
- }
- else if(fp[-1].right_bracketn!=0 || fp[0].left_bracketn!=0) {
- PERR("empty key not valid after bracket.")
- synt++;
- }
- else if(fp>=f+2 && !fp[-1].operator &&
- fp[-2].operator) {
- // last operators were AND and OR
- PERR("empty key must not follow OR after AND.")
- synt++;
- }
- #if 0
- else if(fp>=f+2 && *(int16_t*)fp[-1].k==0 &&
- fp[-1].operator!=fp[-2].operator) {
- // last key was empty too, AND operator changed
- PERR("empty keys must not follow different operators.")
- synt++;
- }
- #endif
- } // empty key
- fp++;
- } // for every key/val pair in filter
- if(bracket_balance>0)
- bl+= bracket_balance;
- else if(bracket_balance<0)
- br+= -bracket_balance;
- } // for every filter type
- if(bl==1)
- PERR("missing one right bracket.")
- else if(bl>1)
- PERRv("missing %i right brackets.",bl)
- if(br==1)
- PERR("missing one left bracket.")
- else if(br>1)
- PERRv("missing %i left brackets.",br)
- if(bm>0)
- PERR("brackets not allowed if keyword \"all\".")
- if(fil__err_tagsbool!=0)
- PERR("Boolean operators must not be used in tags filter.")
- if(fil__err_tagsbracket!=0)
- PERR("brackets must not be used in tags filter.")
-
- // preprocess operator priority if keyword "all"
- for(ft= 0;ft<fil__pairtM;ft++) { // for every filter type
- if(fil_meetall[ft]) {
- fp= f= fil__pair[ft]; fe= fil__paire[ft];
- while(fp<fe) { // for every key/val pair in filter
-
- if(!fp[0].operator && fp<fe-1 &&
- (fp==f || fp[-1].operator)) {
- // change to 'or'
- fp[0].left_bracketn++;
- if(loglevel>=2)
- PINFOv("inserting[%i][%i]: \"(\"",
- ft,(int)(fp-fil__pair[ft]))
- }
- else if(!fp[-1].operator && fp>f &&
- (fp[0].operator || fp==fe-1)) {
- // change to 'and'
- fp[0].right_bracketn++;
- if(loglevel>=2)
- PINFOv("inserting[%i][%i]: \")\"",
- ft,(int)(fp-fil__pair[ft]))
- }
- fp++;
- } // for every key/val pair in filter
- }
- } // for every filter type
-
- return bl+br+bm*100+synt*1000+
- (fil__err_tagsbool+fil__err_tagsbracket)*10000;
- } // fil_plausi()
-
-static inline bool fil_check0(int otype,
- char** key,char** keye,char** val,char** vale) {
- // check if OSM object matches filter criteria;
- // at this procedure, filter type 0..2 is applied: 'keep object';
- // keyp,keye,valp,vale: tag list;
- // otype: 0: node; 1: way; 2: relation;
- // return: given tag list matches keep criteria;
- bool result,gotkey;
- char** keyp,**valp;
- fil__pair_t* fp,*fe;
- int bracket_balance;
- int bb; // temporary for bracket_balance
- char* v; // previous value of a key which compared successfully
-
- result= false;
- v= NULL; // (default)
- valp= &v; // (default)
- bracket_balance= 0;
- fp= fil__pair[otype]; fe= fil__paire[otype];
- while(fp<fe) { // for every key/val pair in filter
- bracket_balance+= fp->left_bracketn;
- if(*(int16_t*)(fp->k)==0) {
- if(v!=NULL)
- result= fil__cmp(v,fp->v);
- }
- else {
- result= gotkey= false; // (default)
- keyp= key; valp= val;
- while(keyp<keye) { // for all key/val pairs of this object
- if(fil__cmp(*keyp,fp->k)) { // right key
- gotkey= true;
- v= *valp;
- if(*(int16_t*)(fp->k)==0 || fil__cmp(v,fp->v)) {
- // right value
- result= true;
- break;
- }
- }
- keyp++; valp++;
- } // for all key/val pairs of this object
- if(!gotkey) { // did not find a matching key
- char c;
-
- c= *fp->v;
- if(c==1 || c==3) // 'unequal' operator 2012-02-03
- result= true; // accept this equation as fulfilled
- }
- }
- #if MAXLOGLEVEL>=3
- if(loglevel>=3)
- PINFOv("comparison[%i][%i]==%i",otype,fp-fil__pair[otype],result)
- #endif
- if(result) { // comparison satisfied
- if(fp->operator) { // Boolean operator is AND
- // (continue with next comparison)
- } // Boolean operator is AND
- else { // Boolean operator is OR
- // at each encountered 'or':
- // jump to after next operand at lower layer
- bracket_balance-= fp->right_bracketn;
- if(bracket_balance<=0) // we already are at lowest level
-return result;
- bb= bracket_balance;
- fp++;
- while(fp<fe) {
- bracket_balance+= fp->left_bracketn;
- bracket_balance-= fp->right_bracketn;
- if(bracket_balance>=bb) { // same level or higher
- fp++;
- continue;
- }
- if(fp->operator) { // next operator is 'and'
- fp++;
- break; // go on by evaluating this operator
- }
- // here: next operator is an 'or'
- if(bracket_balance<=0) // we are at lowest level
-return result;
- bb= bracket_balance; // from now on ignore this level
- fp++;
- }
- v= NULL; // previous value no longer valid
- continue;
- } // Boolean operator is OR
- } // comparison satisfied
- else { // comparison not satisfied
- if(fp->operator) { // Boolean operator is AND
- // jump to after next 'or' within same brackets or
- // lower layer, but not into the space between new brackets
- bracket_balance-= fp->right_bracketn;
- bb= bracket_balance;
- fp++;
- while(fp<fe) {
- bracket_balance+= fp->left_bracketn;
- bracket_balance-= fp->right_bracketn;
- if(bracket_balance<bb)
- bb= bracket_balance;
- if(bracket_balance<=bb && !fp->operator) {
- // not in a new bracket AND next operator is 'or'
- fp++;
- break;
- }
- fp++;
- }
- v= NULL; // previous value no longer valid
- continue;
- } // Boolean operator is AND
- else { // Boolean operator is OR
- // (continue with next comparison)
- } // Boolean operator is OR
- } // comparison not satisfied
- bracket_balance-= fp->right_bracketn;
- fp++;
- } // for every key/val pair in filter
- return result;
- } // end fil_check0()
-
-static inline bool fil_check1(int otype,
- char** key,char** keye,char** val,char** vale) {
- // check if OSM object matches filter criteria;
- // at this procedure, filter type 4..6 is applied: 'drop object';
- // keyp,keye,valp,vale: tag list;
- // otype: 0: node; 1: way; 2: relation;
- // return: given tag list matches keep criteria;
- bool result;
- char** keyp,**valp;
- fil__pair_t* fp,*fe;
- int bracket_balance;
- int bb; // temporary for bracket_balance
- char* v; // previous value of a key which compared successfully
-
- result= false;
- v= NULL; // (default)
- valp= &v; // (default)
- bracket_balance= 0;
- fp= fil__pair[3+otype]; fe= fil__paire[3+otype];
- while(fp<fe) { // for every key/val pair in filter
- bracket_balance+= fp->left_bracketn;
- if(*(int16_t*)(fp->k)==0) {
- if(v!=NULL)
- result= fil__cmp(v,fp->v);
- }
- else {
- result= false; // (default)
- keyp= key; valp= val;
- while(keyp<keye) { // for all key/val pairs of this object
- if(fil__cmp(*keyp,fp->k)) { // right key
- v= *valp;
- if(*(int16_t*)(fp->k)==0 || fil__cmp(v,fp->v)) {
- // right value
- result= true;
- break;
- }
- }
- keyp++; valp++;
- } // for all key/val pairs of this object
- }
- #if MAXLOGLEVEL>=3
- if(loglevel>=3)
- PINFOv("comparison[%i][%i]==%i",
- 3+otype,fp-fil__pair[3+otype],result)
- #endif
- if(result) { // comparison satisfied
- if(fp->operator) { // Boolean operator is AND
- // (continue with next comparison)
- } // Boolean operator is AND
- else { // Boolean operator is OR
- // at each encountered 'or':
- // jump to after next operand at lower layer
- bracket_balance-= fp->right_bracketn;
- if(bracket_balance<=0) // we already are at lowest level
-return result;
- bb= bracket_balance;
- fp++;
- while(fp<fe) {
- bracket_balance+= fp->left_bracketn;
- bracket_balance-= fp->right_bracketn;
- if(bracket_balance>=bb) { // same level or higher
- fp++;
- continue;
- }
- if(fp->operator) { // next operator is 'and'
- fp++;
- break; // go on by evaluating this operator
- }
- // here: next operator is an 'or'
- if(bracket_balance<=0) // we are at lowest level
-return result;
- bb= bracket_balance; // from now on ignore this level
- fp++;
- }
- v= NULL; // previous value no longer valid
- continue;
- } // Boolean operator is OR
- } // comparison satisfied
- else { // comparison not satisfied
- if(fp->operator) { // Boolean operator is AND
- // jump to after next 'or' within same brackets or
- // lower layer, but not into the space between new brackets
- bracket_balance-= fp->right_bracketn;
- bb= bracket_balance;
- fp++;
- while(fp<fe) {
- bracket_balance+= fp->left_bracketn;
- bracket_balance-= fp->right_bracketn;
- if(bracket_balance<bb)
- bb= bracket_balance;
- if(bracket_balance<=bb && !fp->operator) {
- // not in a new bracket AND next operator is 'or'
- fp++;
- break;
- }
- fp++;
- }
- v= NULL; // previous value no longer valid
- continue;
- } // Boolean operator is AND
- else { // Boolean operator is OR
- // (continue with next comparison)
- } // Boolean operator is OR
- } // comparison not satisfied
- bracket_balance-= fp->right_bracketn;
- fp++;
- } // for every key/val pair in filter
- return result;
- } // end fil_check1()
-
-static inline bool fil_check2(int otype,
- const char* key,const char* val) {
- // test if filter allows this tag to be kept;
- // at this procedure, filters type 6..8 and 9..11 are applied:
- // 'keep tag';
- // otype: 0: node; 1: way; 2: relation;
- // return: given key[] and val[] match keep criteria;
- fil__pair_t* fp,*fe;
- const char* k; // last key in filter
- bool keymatch;
-
- // apply keep-filter
- if(fil_active[6+otype]) {
- k= "name"; // (default)
- keymatch= false;
- fp= &fil__pair[6+otype][0]; fe= fil__paire[6+otype];
- while(fp<fe) {
- if(*(int16_t*)(fp->k)!=0) k= fp->k;
- keymatch= fil__cmp(key,k);
- if(keymatch && (*(int16_t*)(fp->v)==0 || fil__cmp(val,fp->v)))
- goto keep;
- fp++;
- }
- if(keymatch || fil_meetall[6+otype])
-return false;
- }
- keep:
- // apply drop-filter
- if(fil_active[9+otype]) {
- k= "name"; // (default)
- fp= &fil__pair[9+otype][0]; fe= fil__paire[9+otype];
- while(fp<fe) {
- if(*(int16_t*)(fp->k)!=0) k= fp->k;
- if(fil__cmp(key,k) && (*(int16_t*)(fp->v)==0 ||
- fil__cmp(val,fp->v)))
-return false;
- fp++;
- }
- }
- return true;
- } // end fil_check2()
-
-//------------------------------------------------------------
-// end Module fil_ osm filter module
-//------------------------------------------------------------
-
-
-
-//------------------------------------------------------------
-// Module rr_ relref temporary module
-//------------------------------------------------------------
-
-// this module provides procedures to use a temporary file for
-// storing relation's references;
-// as usual, all identifiers of a module have the same prefix,
-// in this case 'rr_'; one underline will follow in case of a
-// global accessible object, two underlines in case of objects
-// which are not meant to be accessed from outside this module;
-// the sections of private and public definitions are separated
-// by a horizontal line: ----
-
-static char rr__filename[400]= "";
-static int rr__fd= -1; // file descriptor for temporary file
-#define rr__bufM 400000
-static int32_t rr__buf[rr__bufM],*rr__bufp,*rr__bufe,*rr__bufee;
- // buffer - used for write, and later for read;
-static bool rr__writemode; // buffer is used for writing
-
-static void rr__flush() {
- if(!rr__writemode || rr__bufp==rr__buf)
-return;
- UR(write(rr__fd,rr__buf,(char*)rr__bufp-(char*)rr__buf))
- rr__bufp= rr__buf;
- } // end rr__flush()
-
-static inline void rr__write(int32_t i) {
- // write an int to tempfile, use a buffer;
- if(rr__bufp>=rr__bufee) rr__flush();
- *rr__bufp++= i;
- } // end rr__write()
-
-static void rr__end() {
- // clean-up for temporary file access;
- // will be called automatically at program end;
- if(rr__fd>2) {
- close(rr__fd);
- rr__fd= -1;
- }
- if(loglevel<2) unlink(rr__filename);
- } // end rr__end()
-
-//------------------------------------------------------------
-
-static int rr_ini(const char* filename) {
- // open a temporary file with the given name for random r/w access;
- // return: ==0: ok; !=0: error;
- strcpy(stpmcpy(rr__filename,filename,sizeof(rr__filename)-2),".0");
- if(rr__fd>=0) // file already open
-return 0; // ignore this call
- unlink(rr__filename);
- rr__fd= open(rr__filename,O_RDWR|O_CREAT|O_TRUNC|O_BINARY,00600);
- if(rr__fd<0) {
- PERRv("could not open temporary file: %.80s",rr__filename)
-return 1;
- }
- atexit(rr__end);
- rr__bufee= rr__buf+rr__bufM;
- rr__bufp= rr__bufe= rr__buf;
- rr__writemode= true;
- return 0;
- } // end rr_ini()
-
-static inline void rr_rel(int32_t relid) {
- // store the id of a relation in tempfile;
- rr__write(0);
- rr__write(relid);
- } // end rr_rel()
-
-static inline void rr_ref(int32_t refid) {
- // store the id of an interrelation reference in tempfile;
- rr__write(refid);
- } // end rr_ref()
-
-static int rr_rewind() {
- // rewind the file pointer;
- // return: ==0: ok; !=0: error;
- if(rr__writemode) {
- rr__flush(); rr__writemode= false; }
- if(lseek(rr__fd,0,SEEK_SET)<0) {
- PERR("could not rewind temporary file.");
-return 1;
- }
- rr__bufp= rr__bufe= rr__buf;
- return 0;
- } // end rr_rewind()
-
-static int rr_read(int32_t* ip) {
- // read one integer; meaning of the values of these integers:
- // every value is an interrelation reference id, with one exception:
- // integers which follow a 0-integer directly are relation ids;
- // note that we take 32-bit-integers instead of the 64-bit-integers
- // we usually take for object ids; this is because the range of
- // relation ids will not exceed the 2^15 range in near future;
- // return: ==0: ok; !=0: eof;
- int r,r2;
-
- if(rr__bufp>=rr__bufe) {
- r= read(rr__fd,rr__buf,sizeof(rr__buf));
- if(r<=0)
-return 1;
- rr__bufe= (int32_t*)((char*)rr__buf+r);
- if((r%4)!=0) { // odd number of bytes
- r2= read(rr__fd,rr__bufe,4-(r%4)); // request the missing bytes
- if(r2<=0) // did not get the missing bytes
- rr__bufe= (int32_t*)((char*)rr__bufe-(r%4));
- else
- rr__bufe= (int32_t*)((char*)rr__bufe+r2);
- }
- rr__bufp= rr__buf;
- }
- *ip= *rr__bufp++;
- return 0;
- } // end rr_read()
-
-//------------------------------------------------------------
-// end Module rr_ relref temporary module
-//------------------------------------------------------------
-
-
-
-//------------------------------------------------------------
-// Module o5_ o5m conversion module
-//------------------------------------------------------------
-
-// this module provides procedures which convert data to
-// o5m format;
-// as usual, all identifiers of a module have the same prefix,
-// in this case 'o5'; one underline will follow in case of a
-// global accessible object, two underlines in case of objects
-// which are not meant to be accessed from outside this module;
-// the sections of private and public definitions are separated
-// by a horizontal line: ----
-
-static inline void stw_reset();
-
-#define o5__bufM UINT64_C(5000000)
-static byte* o5__buf= NULL; // buffer for one object in .o5m format
-static byte* o5__bufe= NULL;
- // (const) water mark for buffer filled nearly 100%
-static byte* o5__bufp= NULL;
-static byte* o5__bufr0= NULL,*o5__bufr1= NULL;
- // start end end mark of a reference area in o5__buf[];
- // ==NULL: no mark set;
-
-// basis for delta coding
-static int64_t o5_id;
-static uint32_t o5_lat,o5_lon;
-static int64_t o5_cset;
-static int64_t o5_time;
-static int64_t o5_ref[3]; // for node, way, relation
-
-static inline void o5__resetvars(void) {
- // reset all delta coding counters;
- o5__bufp= o5__buf;
- o5__bufr0= o5__bufr1= o5__buf;
- o5_id= 0;
- o5_lat= o5_lon= 0;
- o5_cset= 0;
- o5_time= 0;
- o5_ref[0]= o5_ref[1]= o5_ref[2]= 0;
- stw_reset();
- } // end o5__resetvars()
-
-static void o5__end() {
- // clean-up for o5 module;
- // will be called at program's end;
- if(o5__buf!=NULL) {
- free(o5__buf); o5__buf= NULL; }
- } // end o5__end()
-
-//------------------------------------------------------------
-
-static inline void o5_reset(void) {
- // perform and write an o5m Reset;
- o5__resetvars();
- write_char(0xff); // write .o5m Reset
- } // end o5_reset()
-
-static int o5_ini(void) {
- // initialize this module;
- // must be called before any other procedure is called;
- // return: 0: everything went ok;
- // !=0: an error occurred;
- static bool firstrun= true;
-
- if(firstrun) {
- firstrun= false;
- o5__buf= (byte*)malloc(o5__bufM);
- if(o5__buf==NULL)
-return 1;
- atexit(o5__end);
- o5__bufe= o5__buf+o5__bufM-400000;
- }
- o5__resetvars();
- return 0;
- } // end o5_ini()
-
-static inline void o5_byte(byte b) {
- // write a single byte;
- // writing starts at position o5__bufp;
- // o5__bufp: incremented by 1;
- *o5__bufp++= b;
- } // end o5_byte()
-
-static inline int o5_str(const char* s) {
- // write a zero-terminated string;
- // writing starts at position o5__bufp;
- // return: bytes written;
- // o5__bufp: increased by the number of written bytes;
- byte* p0;
- byte c;
-
- p0= o5__bufp;
- if(o5__bufp>=o5__bufe) {
- static int msgn= 1;
- if(--msgn>=0) {
- PERR(".o5m memory overflow.")
-return 0;
- }
- }
- do *o5__bufp++= c= *s++;
- while(c!=0);
-return o5__bufp-p0;
- } // end o5_str()
-
-static inline int o5_uvar32buf(byte* p,uint32_t v) {
- // write an unsigned 32 bit integer as Varint into a buffer;
- // writing starts at position p;
- // return: bytes written;
- byte* p0;
- uint32_t frac;
-
- p0= p;
- frac= v&0x7f;
- if(frac==v) { // just one byte
- *p++= frac;
-return 1;
- }
- do {
- *p++= frac|0x80;
- v>>= 7;
- frac= v&0x7f;
- } while(frac!=v);
- *p++= frac;
-return p-p0;
- } // end o5_uvar32buf()
-
-static inline int o5_uvar32(uint32_t v) {
- // write an unsigned 32 bit integer as Varint;
- // writing starts at position o5__bufp;
- // return: bytes written;
- // o5__bufp: increased by the number of written bytes;
- byte* p0;
- uint32_t frac;
-
- if(o5__bufp>=o5__bufe) {
- static int msgn= 1;
- if(--msgn>=0) {
- PERR(".o5m memory overflow.")
-return 0;
- }
- }
- p0= o5__bufp;
- frac= v&0x7f;
- if(frac==v) { // just one byte
- *o5__bufp++= frac;
-return 1;
- }
- do {
- *o5__bufp++= frac|0x80;
- v>>= 7;
- frac= v&0x7f;
- } while(frac!=v);
- *o5__bufp++= frac;
-return o5__bufp-p0;
- } // end o5_uvar32()
-
-static inline int o5_svar32(int32_t v) {
- // write a signed 32 bit integer as signed Varint;
- // writing starts at position o5__bufp;
- // return: bytes written;
- // o5__bufp: increased by the number of written bytes;
- byte* p0;
- uint32_t u;
- uint32_t frac;
-
- if(o5__bufp>=o5__bufe) {
- static int msgn= 1;
- if(--msgn>=0) {
- PERR(".o5m memory overflow.")
-return 0;
- }
- }
- p0= o5__bufp;
- if(v<0) {
- u= -v;
- u= (u<<1)-1;
- }
- else
- u= v<<1;
- frac= u&0x7f;
- if(frac==u) { // just one byte
- *o5__bufp++= frac;
-return 1;
- }
- do {
- *o5__bufp++= frac|0x80;
- u>>= 7;
- frac= u&0x7f;
- } while(frac!=u);
- *o5__bufp++= frac;
-return o5__bufp-p0;
- } // end o5_svar32()
-
-static inline int o5_svar64(int64_t v) {
- // write a signed 64 bit integer as signed Varint;
- // writing starts at position o5__bufp;
- // return: bytes written;
- // o5__bufp: increased by the number of written bytes;
- byte* p0;
- uint64_t u;
- uint32_t frac;
-
- if(o5__bufp>=o5__bufe) {
- static int msgn= 1;
- if(--msgn>=0) {
- PERR(".o5m memory overflow.");
-return 0;
- }
- }
- p0= o5__bufp;
- if(v<0) {
- u= -v;
- u= (u<<1)-1;
- }
- else
- u= v<<1;
- frac= u&0x7f;
- if(frac==u) { // just one byte
- *o5__bufp++= frac;
-return 1;
- }
- do {
- *o5__bufp++= frac|0x80;
- u>>= 7;
- frac= u&0x7f;
- } while(frac!=u);
- *o5__bufp++= frac;
-return o5__bufp-p0;
- } // end o5_svar64()
-
-static inline void o5_markref(int pos) {
- // mark reference area;
- // pos: ==0: start; ==1: end;
- // 0 is accepted only once per dataset; only the first
- // request is valid;
- // 1 may be repeated, the last one counts;
- if(pos==0) {
- if(o5__bufr0==o5__buf) o5__bufr0= o5__bufp;
- }
- else
- o5__bufr1= o5__bufp;
- } // end o5_markref()
-
-static void o5_type(int type) {
- // mark object type we are going to process now;
- // should be called every time a new object is started to be
- // written into o5_buf[];
- // type: object type; 0: node; 1: way; 2: relation;
- // if object type hase changed, a 0xff byte ("reset")
- // will be written;
- static int oldtype= -1;
-
- // process changes of object type
- if(type!=oldtype) { // object type has changed
- oldtype= type;
- o5_reset();
- }
- oldtype= type;
- } // end o5_type()
-
-static void o5_write() {
- // write o5__buf[] contents to standard output;
- // include object length information after byte 0 and include
- // ref area length information right before o5__bufr0 (if !=NULL);
- // if buffer is empty, this procedure does nothing;
- byte buftemp[30];
- int reflen; // reference area length
- int len; // object length
-
- // get some length information
- len= o5__bufp-o5__buf;
- if(len<=0) goto o5_write_end;
- reflen= 0; // (default)
- if(o5__bufr1<o5__bufr0) o5__bufr1= o5__bufr0;
- if(o5__bufr0>o5__buf) {
- // reference area contains at least 1 byte
- reflen= o5__bufr1-o5__bufr0;
- len+= o5_uvar32buf(buftemp,reflen);
- } // end reference area contains at least 1 byte
-
- // write header
- if(--len>=0) {
- write_char(o5__buf[0]);
- write_mem(buftemp,o5_uvar32buf(buftemp,len));
- }
-
- // write body
- if(o5__bufr0==o5__buf) // no reference area
- write_mem(o5__buf+1,o5__bufp-(o5__buf+1));
- else { // valid reference area
- write_mem(o5__buf+1,o5__bufr0-(o5__buf+1));
- write_mem(buftemp,o5_uvar32buf(buftemp,reflen));
- write_mem(o5__bufr0,o5__bufp-o5__bufr0);
- } // end valid reference area
-
- // reset buffer pointer
- o5_write_end:
- o5__bufp= o5__buf; // set original buffer pointer to buffer start
- o5__bufr0= o5__bufr1= o5__buf; // clear reference area marks
- } // end o5_write()
-
-//------------------------------------------------------------
-// end Module o5_ o5m conversion module
-//------------------------------------------------------------
-
-
-
-//------------------------------------------------------------
-// Module stw_ string write module
-//------------------------------------------------------------
-
-// this module provides procedures for conversions from
-// c formatted strings into referenced string data stream objects
-// - and writing it to buffered standard output;
-// as usual, all identifiers of a module have the same prefix,
-// in this case 'stw'; one underline will follow in case of a
-// global accessible object, two underlines in case of objects
-// which are not meant to be accessed from outside this module;
-// the sections of private and public definitions are separated
-// by a horizontal line: ----
-
-#define stw__tabM 15000
-#define stw__tabstrM 250 // must be < row size of stw__rab[]
-#define stw__hashtabM 150001 // (preferably a prime number)
-static char stw__tab[stw__tabM][256];
- // string table; see o5m documentation;
- // row length must be at least stw__tabstrM+2;
- // each row contains a double string; each of the two strings
- // is terminated by a zero byte, the lengths must not exceed
- // stw__tabstrM bytes in total;
-static int stw__tabi= 0;
- // index of last entered element in string table
-static int stw__hashtab[stw__hashtabM];
- // has table; elements point to matching strings in stw__tab[];
- // -1: no matching element;
-static int stw__tabprev[stw__tabM],stw__tabnext[stw__tabM];
- // for to chaining of string table rows which match
- // the same hash value; matching rows are chained in a loop;
- // if there is only one row matching, it will point to itself;
-static int stw__tabhash[stw__tabM];
- // has value of this element as a link back to the hash table;
- // a -1 element indicates that the string table entry is not used;
-
-static inline int stw__hash(const char* s1,const char* s2) {
- // get hash value of a string pair;
- // s2: ==NULL: single string; this is treated as s2=="";
- // return: hash value in the range 0..(stw__hashtabM-1);
- // -1: the strings are longer than stw__tabstrM characters in total;
- uint32_t h;
- uint32_t c;
- int len;
-
- len= stw__tabstrM;
- h= 0;
- for(;;) {
- if((c= *s1++)==0 || --len<0) break; h+= c;
- if((c= *s1++)==0 || --len<0) break; h+= c<<8;
- if((c= *s1++)==0 || --len<0) break; h+= c<<16;
- if((c= *s1++)==0 || --len<0) break; h+= c<<24;
- }
- if(s2!=NULL) for(;;) {
- if((c= *s2++)==0 || --len<0) break; h+= c;
- if((c= *s2++)==0 || --len<0) break; h+= c<<8;
- if((c= *s2++)==0 || --len<0) break; h+= c<<16;
- if((c= *s2++)==0 || --len<0) break; h+= c<<24;
- }
- if(len<0)
-return -1;
- h%= stw__hashtabM;
- return h;
- } // end stw_hash()
-
-static inline int stw__getref(int stri,const char* s1,const char* s2) {
- // get the string reference of a string pair;
- // the strings must not have more than 250 characters in total
- // (252 including terminators), there is no check in this procedure;
- // stri: presumed index in string table (we got it from hash table);
- // must be >=0 and <stw__tabM, there is no boundary check;
- // s2: ==NULL: it's not a string pair but a single string;
- // stw__hashnext[stri]: chain to further occurrences;
- // return: reference of the string;
- // ==-1: this string is not stored yet
- int strie; // index of last occurrence
- const char* sp,*tp;
- int ref;
-
- if(s2==NULL) s2="";
- strie= stri;
- do {
- // compare the string (pair) with the tab entry
- tp= stw__tab[stri];
- sp= s1;
- while(*tp==*sp && *tp!=0) { tp++; sp++; }
- if(*tp==0 && *sp==0) {
- // first string identical to first string in table
- tp++; // jump over first string terminator
- sp= s2;
- while(*tp==*sp && *tp!=0) { tp++; sp++; }
- if(*tp==0 && *sp==0) {
- // second string identical to second string in table
- ref= stw__tabi-stri;
- if(ref<=0) ref+= stw__tabM;
-return ref;
- }
- } // end first string identical to first string in table
- stri= stw__tabnext[stri];
- } while(stri!=strie);
- return -1;
- } // end stw__getref()
-
-//------------------------------------------------------------
-
-static inline void stw_reset() {
- // clear string table and string hash table;
- // must be called before any other procedure of this module
- // and may be called every time the string processing shall
- // be restarted;
- int i;
-
- stw__tabi= 0;
- i= stw__tabM;
- while(--i>=0) stw__tabhash[i]= -1;
- i= stw__hashtabM;
- while(--i>=0) stw__hashtab[i]= -1;
- } // end stw_reset()
-
-static void stw_write(const char* s1,const char* s2) {
- // write a string (pair), e.g. key/val, to o5m buffer;
- // if available, write a string reference instead of writing the
- // string pair directly;
- // no reference is used if the strings are longer than
- // 250 characters in total (252 including terminators);
- // s2: ==NULL: it's not a string pair but a single string;
- int h; // hash value
- int ref;
-
- /* try to find a matching string (pair) in string table */ {
- int i; // index in stw__tab[]
-
- ref= -1; // ref invalid (default)
- h= stw__hash(s1,s2);
- if(h>=0) { // string (pair) short enough for the string table
- i= stw__hashtab[h];
- if(i>=0) // string (pair) presumably stored already
- ref= stw__getref(i,s1,s2);
- } // end string (pair) short enough for the string table
- if(ref>=0) { // we found the string (pair) in the table
- o5_uvar32(ref); // write just the reference
-return;
- } // end we found the string (pair) in the table
- else { // we did not find the string (pair) in the table
- // write string data
- o5_byte(0); o5_str(s1);
- if(s2!=NULL) o5_str(s2); // string pair, not a single string
- if(h<0) // string (pair) too long,
- // cannot be stored in string table
-return;
- } // end we did not find the string (pair) in the table
- } // end try to find a matching string (pair) in string table
- // here: there is no matching string (pair) in the table
-
- /* free new element - if still being used */ {
- int h0; // hash value of old element
-
- h0= stw__tabhash[stw__tabi];
- if(h0>=0) { // new element in string table is still being used
- // delete old element
- if(stw__tabnext[stw__tabi]==stw__tabi)
- // self-chain, i.e., only this element
- stw__hashtab[h0]= -1; // invalidate link in hash table
- else { // one or more other elements in chain
- stw__hashtab[h0]= stw__tabnext[stw__tabi]; // just to ensure
- // that hash entry does not point to deleted element
- // now unchain deleted element
- stw__tabprev[stw__tabnext[stw__tabi]]= stw__tabprev[stw__tabi];
- stw__tabnext[stw__tabprev[stw__tabi]]= stw__tabnext[stw__tabi];
- } // end one or more other elements in chain
- } // end next element in string table is still being used
- } // end free new element - if still being used
-
- /* enter new string table element data */ {
- char* sp;
- int i;
-
- sp= stpcpy0(stw__tab[stw__tabi],s1)+1;
- // write first string into string table
- if(s2==NULL) // single string
- *sp= 0; // second string must be written as empty string
- // into string table
- else
- stpcpy0(sp,s2); // write second string into string table
- i= stw__hashtab[h];
- if(i<0) // no reference in hash table until now
- stw__tabprev[stw__tabi]= stw__tabnext[stw__tabi]= stw__tabi;
- // self-link the new element;
- else { // there is already a reference in hash table
- // in-chain the new element
- stw__tabnext[stw__tabi]= i;
- stw__tabprev[stw__tabi]= stw__tabprev[i];
- stw__tabnext[stw__tabprev[stw__tabi]]= stw__tabi;
- stw__tabprev[i]= stw__tabi;
- }
- stw__hashtab[h]= stw__tabi; // link the new element to hash table
- stw__tabhash[stw__tabi]= h; // backlink to hash table element
- // new element now in use; set index to oldest element
- if(++stw__tabi>=stw__tabM) { // index overflow
- stw__tabi= 0; // restart index
- if(loglevel>=2) {
- static int rs= 0;
- fprintf(stderr,
- "osmfilter: string table index restart %i\n",++rs);
- }
- } // end index overflow
- } // end enter new string table element data
- } // end stw_write()
-
-//------------------------------------------------------------
-// end Module stw_ string write module
-//------------------------------------------------------------
-
-
-
-//------------------------------------------------------------
-// Module str_ string read module
-//------------------------------------------------------------
-
-// this module provides procedures for conversions from
-// strings which have been stored in data stream objects to
-// c-formatted strings;
-// as usual, all identifiers of a module have the same prefix,
-// in this case 'str'; one underline will follow in case of a
-// global accessible object, two underlines in case of objects
-// which are not meant to be accessed from outside this module;
-// the sections of private and public definitions are separated
-// by a horizontal line: ----
-
-#define str__tabM (15000+4000)
- // +4000 because it might happen that an object has a lot of
- // key/val pairs or refroles which are not stored already;
-#define str__tabstrM 250 // must be < row size of str__rab[]
-typedef struct str__info_struct {
- // members of this structure must not be accessed
- // from outside this module;
- char tab[str__tabM][256];
- // string table; see o5m documentation;
- // row length must be at least str__tabstrM+2;
- // each row contains a double string; each of the two strings
- // is terminated by a zero byte, the logical lengths must not
- // exceed str__tabstrM bytes in total;
- // the first str__tabM lines of this array are used as
- // input buffer for strings;
- int tabi; // index of last entered element in string table;
- int tabn; // number of valid strings in string table;
- struct str__info_struct* prev; // address of previous unit;
- } str_info_t;
-str_info_t* str__infop= NULL;
-
-static void str__end() {
- // clean-up this module;
- str_info_t* p;
-
- while(str__infop!=NULL) {
- p= str__infop->prev;
- free(str__infop);
- str__infop= p;
- }
- } // end str__end()
-
-//------------------------------------------------------------
-
-static str_info_t* str_open() {
- // open an new string client unit;
- // this will allow us to process multiple o5m input files;
- // return: handle of the new unit;
- // ==NULL: error;
- // you do not need to care about closing the unit(s);
- static bool firstrun= true;
- str_info_t* prev;
-
- prev= str__infop;
- str__infop= (str_info_t*)malloc(sizeof(str_info_t));
- if(str__infop==NULL) {
- PERR("could not get memory for string buffer.")
-return NULL;
- }
- str__infop->tabi= 0;
- str__infop->tabn= 0;
- str__infop->prev= prev;
- if(firstrun) {
- firstrun= false;
- atexit(str__end);
- }
- return str__infop;
- } // end str_open()
-
-#if 0 // unused at present
-static void str_switch(str_info_t* sh) {
- // switch to another string unit
- // sh: string unit handle;
- str__infop= sh;
- } // end str_switch()
-#endif
-
-static void str_reset() {
- // clear string table;
- // must be called before any other procedure of this module
- // and may be called every time the string processing shall
- // be restarted;
- str__infop->tabi= str__infop->tabn= 0;
- } // end str_reset()
-
-static void str_read(byte** pp,char** s1p,char** s2p) {
- // read an o5m formatted string (pair), e.g. key/val, from
- // standard input buffer;
- // if got a string reference, resolve it, using an internal
- // string table;
- // no reference is used if the strings are longer than
- // 250 characters in total (252 including terminators);
- // pp: address of a buffer pointer;
- // this pointer will be incremented by the number of bytes
- // the converted protobuf element consumes;
- // s2p: ==NULL: read not a string pair but a single string;
- // return:
- // *s1p,*s2p: pointers to the strings which have been read;
- char* p;
- int len1,len2;
- int ref;
- bool donotstore; // string has 'do not store flag' 2012-10-01
-
- p= (char*)*pp;
- if(*p==0) { // string (pair) given directly
- p++;
- donotstore= false;
- #if 0 // not used because strings would not be transparent anymore
- if(*p==(char)0xff) { // string has 'do-not-store' flag
- donotstore= true;
- p++;
- } // string has 'do-not-store' flag
- #endif
- *s1p= p;
- len1= strlen(p);
- p+= len1+1;
- if(s2p==NULL) { // single string
- if(!donotstore && len1<=str__tabstrM) {
- // single string short enough for string table
- stpcpy0(str__infop->tab[str__infop->tabi],*s1p)[1]= 0;
- // add a second terminator, just in case someone will try
- // to read this single string as a string pair later;
- if(++str__infop->tabi>=str__tabM) str__infop->tabi= 0;
- if(str__infop->tabn<str__tabM) str__infop->tabn++;
- } // end single string short enough for string table
- } // end single string
- else { // string pair
- *s2p= p;
- len2= strlen(p);
- p+= len2+1;
- if(!donotstore && len1+len2<=str__tabstrM) {
- // string pair short enough for string table
- memcpy(str__infop->tab[str__infop->tabi],*s1p,len1+len2+2);
- if(++str__infop->tabi>=str__tabM) str__infop->tabi= 0;
- if(str__infop->tabn<str__tabM) str__infop->tabn++;
- } // end string pair short enough for string table
- } // end string pair
- *pp= (byte*)p;
- } // end string (pair) given directly
- else { // string (pair) given by reference
- ref= pbf_uint32(pp);
- if(ref>str__infop->tabn) { // string reference invalid
- WARNv("invalid .o5m string reference: %i->%i",
- str__infop->tabn,ref)
- *s1p= "(invalid)";
- if(s2p!=NULL) // caller wants a string pair
- *s2p= "(invalid)";
- } // end string reference invalid
- else { // string reference valid
- ref= str__infop->tabi-ref;
- if(ref<0) ref+= str__tabM;
- *s1p= str__infop->tab[ref];
- if(s2p!=NULL) // caller wants a string pair
- *s2p= strchr(str__infop->tab[ref],0)+1;
- } // end string reference valid
- } // end string (pair) given by reference
- } // end str_read()
-
-//------------------------------------------------------------
-// end Module str_ string read module
-//------------------------------------------------------------
-
-
-
-//------------------------------------------------------------
-// Module wo_ write osm module
-//------------------------------------------------------------
-
-// this module provides procedures which write osm objects;
-// it uses procedures from module o5_;
-// as usual, all identifiers of a module have the same prefix,
-// in this case 'wo'; one underline will follow in case of a
-// global accessible object, two underlines in case of objects
-// which are not meant to be accessed from outside this module;
-// the sections of private and public definitions are separated
-// by a horizontal line: ----
-
-static int wo__format= 0; // output format;
- // 0: o5m; 11: native XML; 12: pbf2osm; 13: Osmosis; 14: Osmium;
- // -1: write key list;
-static bool wo__logaction= false; // write action for change files,
- // e.g. "<create>", "<delete>", etc.
-static char* wo__xmlclosetag= NULL; // close tag for XML output;
-static bool wo__xmlshorttag= false;
- // write the short tag ("/>") instead of the long tag;
-#define wo__CLOSE { /* close the newest written object; */ \
- if(wo__xmlclosetag!=NULL) { if(wo__xmlshorttag) write_str("\"/>"NL); \
- else write_str(wo__xmlclosetag); \
- wo__xmlclosetag= NULL; wo__xmlshorttag= false; } }
-#define wo__CONTINUE { /* continue an XML object */ \
- if(wo__xmlshorttag) { write_str("\">"NL); wo__xmlshorttag= false; \
- /* from now on: long close tag necessary; */ } }
-static int wo__lastaction= 0; // last action tag which has been set;
- // 0: no action tag; 1: "create"; 2: "modify"; 3: "delete";
- // this is used only in .osc files;
-
-static inline void wo__author(int32_t hisver,int64_t histime,
- int64_t hiscset,uint32_t hisuid,const char* hisuser) {
- // write osm object author information;
- // hisver: version; 0: no author information is to be written
- // (necessary if o5m format);
- // histime: time (seconds since 1970)
- // hiscset: changeset
- // hisuid: uid
- // hisuser: user name
- // global_fakeauthor: the author contents will be faked that way
- // that the author data will be as short as
- // possible;
- // global fakeversion: same as global_fakeauthor, but for .osm
- // format: just the version will be written;
- // note that when writing o5m format, this procedure needs to be
- // called even if there is no author information to be written;
- if(global_fakeauthor|global_fakeversion) {
- hisver= 1; histime= 1; hiscset= 1; hisuid= 0; hisuser= "";
- }
- if(wo__format==0) { // o5m
- if(hisver==0 || global_dropversion) // no version number
- o5_byte(0x00);
- else { // version number available
- o5_uvar32(hisver);
- if(global_dropauthor) histime= 0;
- o5_svar64(histime-o5_time); o5_time= histime;
- if(histime!=0) {
- // author information available
- o5_svar64(hiscset-o5_cset); o5_cset= hiscset;
- if(hisuid==0 || hisuser==NULL || hisuser[0]==0)
- // user identification not available
- stw_write("","");
- else { // user identification available
- byte uidbuf[30];
-
- uidbuf[o5_uvar32buf(uidbuf,hisuid)]= 0;
- stw_write((const char*)uidbuf,hisuser);
- } // end user identification available
- } // end author information available
- } // end version number available
-return;
- } // end o5m
- // here: XML format
- if(global_fakeversion) {
- write_str("\" version=\"1");
-return;
- }
- if(hisver==0 || global_dropversion) // no version number
-return;
- switch(wo__format) { // depending on output format
- case 11: // native XML
- write_str("\" version=\""); write_uint32(hisver);
- if(histime!=0 && !global_dropauthor) {
- write_str("\" timestamp=\""); write_timestamp(histime);
- write_str("\" changeset=\""); write_uint64(hiscset);
- if(hisuid!=0 && hisuser[0]!=0) { // user information available
- write_str("\" uid=\""); write_uint32(hisuid);
- write_str("\" user=\""); write_xmlstr(hisuser);
- }
- }
- break;
- case 12: // pbf2osm XML
- write_str("\" version=\""); write_uint32(hisver);
- if(histime!=0 && !global_dropauthor) {
- write_str("\" changeset=\""); write_uint64(hiscset);
- if(hisuid!=0 && hisuser[0]!=0) { // user information available
- write_str("\" user=\""); write_xmlstr(hisuser);
- write_str("\" uid=\""); write_uint32(hisuid);
- }
- write_str("\" timestamp=\""); write_timestamp(histime);
- }
- break;
- case 13: // Osmosis XML
- write_str("\" version=\""); write_uint32(hisver);
- if(histime!=0 && !global_dropauthor) {
- write_str("\" timestamp=\""); write_timestamp(histime);
- if(hisuid!=0 && hisuser[0]!=0) { // user information available
- write_str("\" uid=\""); write_uint32(hisuid);
- write_str("\" user=\""); write_xmlmnstr(hisuser);
- }
- write_str("\" changeset=\""); write_uint64(hiscset);
- }
- break;
- case 14: // Osmium XML
- write_str("\" version=\""); write_uint32(hisver);
- if(histime!=0 && !global_dropauthor) {
- write_str("\" changeset=\""); write_uint64(hiscset);
- write_str("\" timestamp=\""); write_timestamp(histime);
- if(hisuid!=0 && hisuser[0]!=0) { // user information available
- write_str("\" uid=\""); write_uint32(hisuid);
- write_str("\" user=\""); write_xmlstr(hisuser);
- }
- }
- break;
- } // end depending on output format
- if(global_outosh) {
- if(wo__lastaction==3)
- write_str("\" visible=\"false");
- else
- write_str("\" visible=\"true");
- }
- } // end wo__author()
-
-static inline void wo__action(int action) {
- // set one of these action tags: "create", "modify", "delete";
- // write tags only if 'global_outosc' is true;
- // action: 0: no action tag; 1: "create"; 2: "modify"; 3: "delete";
- // caution: there is no check for validity of this parameter;
- static const char* starttag[]=
- {"","<create>"NL,"<modify>"NL,"<delete>"NL};
- static const char* endtag[]=
- {"","</create>"NL,"</modify>"NL,"</delete>"NL};
- if(global_outosc && action!=wo__lastaction) { // there was a change
- write_str(endtag[wo__lastaction]); // end last action
- write_str(starttag[action]); // start new action
- }
- wo__lastaction= action;
- } // end wo__action()
-
-//------------------------------------------------------------
-
-static void wo_start(int format,bool bboxvalid,
- int32_t x1,int32_t y1,int32_t x2,int32_t y2) {
- // start writing osm objects;
- // format: 0: o5m; 11: native XML;
- // 12: pbf2osm; 13: Osmosis; 14: Osmium;
- // -1: write key list;
- // bboxvalid: the following bbox coordinates are valid;
- // x1,y1,x2,y2: bbox coordinates (base 10^-7);
- if(format<-1 || (format >0 && format<11) || format>14) format= 0;
- wo__format= format;
- wo__logaction= global_outosc || global_outosh;
- if(wo__format<0) { // item list
- count_ini();
-return;
- }
- if(wo__format==0) { // o5m
- static const byte o5mfileheader[]= {0xff,0xe0,0x04,'o','5','m','2'};
- static const byte o5cfileheader[]= {0xff,0xe0,0x04,'o','5','c','2'};
-
- if(global_outo5c)
- write_mem(o5cfileheader,sizeof(o5cfileheader));
- else
- write_mem(o5mfileheader,sizeof(o5mfileheader));
- if(bboxvalid) { // bbox has been supplied
- o5_byte(0xdb); // border box
- o5_svar32(x1); o5_svar32(y1);
- o5_svar32(x2); o5_svar32(y2);
- o5_write(); // write this object
- }
-return;
- } // end o5m
- // here: XML
- if(wo__format!=14)
- write_str("<?xml version=\'1.0\' encoding=\'UTF-8\'?>"NL);
- else // Osmium XML
- write_str("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"NL);
- if(global_outosc)
- write_str("<osmChange version=\"0.6\"");
- else
- write_str("<osm version=\"0.6\"");
- switch(wo__format) { // depending on output format
- case 11: // native XML
- write_str(" generator=\"osmfilter "VERSION"\"");
- break;
- case 12: // pbf2osm XML
- write_str(" generator=\"pbf2osm\"");
- break;
- case 13: // Osmosis XML
- write_str(" generator=\"Osmosis 0.39\"");
- break;
- case 14: // Osmium XML
- write_str(" generator="
- "\"Osmium (http://wiki.openstreetmap.org/wiki/Osmium)\"");
- break;
- } // end depending on output format
- write_str(">"NL);
- if(wo__format!=12) { // bbox may be written
- if(bboxvalid) { // borders are to be applied OR
- // bbox has been supplied
- if(wo__format==13) { // Osmosis
- // <bound box="53.80000,10.50000,54.00000,10.60000"
- // origin="0.40.1"/>
- write_str(" <bound box=\""); write_sfix7(y1);
- write_str(","); write_sfix7(x1);
- write_str(","); write_sfix7(y2);
- write_str(","); write_sfix7(x2);
- write_str("\" origin=\"0.40\"/>"NL);
- } // Osmosis
- else { // not Osmosis
- // <bounds minlat="53.8" minlon="10.5" maxlat="54."
- // maxlon="10.6"/>
- write_str("\t<bounds minlat=\""); write_sfix7(y1);
- write_str("\" minlon=\""); write_sfix7(x1);
- write_str("\" maxlat=\""); write_sfix7(y2);
- write_str("\" maxlon=\""); write_sfix7(x2);
- write_str("\"/>"NL);
- } // not Osmosis
- }
- } // end bbox may be written
- } // end wo_start()
-
-static void wo_end() {
- // end writing osm objects;
- switch(wo__format) { // depending on output format
- case -1:
- if(global_outsort)
- count_sort();
- count_write();
- break;
- case 0: // o5m
- o5_write(); // write last object - if any
- write_char(0xfe); // write o5m eof indicator
- break;
- case 11: // native XML
- case 12: // pbf2osm XML
- case 13: // Osmosis XML
- case 14: // Osmium XML
- wo__CLOSE
- wo__action(0);
- write_str(global_outosc? "</osmChange>"NL: "</osm>"NL);
- if(wo__format>=12)
- write_str("<!--End of emulated output.-->"NL);
- break;
- } // end depending on output format
- } // end wo_end()
-
-static inline void wo_node(int64_t id,
- int32_t hisver,int64_t histime,int64_t hiscset,
- uint32_t hisuid,const char* hisuser,int32_t lon,int32_t lat) {
- // write osm node body;
- // id: id of this object;
- // hisver: version; 0: no author information is to be written
- // (necessary if o5m format);
- // histime: time (seconds since 1970)
- // hiscset: changeset
- // hisuid: uid
- // hisuser: user name
- // lon: latitude in 100 nanodegree;
- // lat: latitude in 100 nanodegree;
- if(wo__format==0) { // o5m
- o5_write(); // write last object - if any
- o5_type(0);
- o5_byte(0x10); // data set id for node
- o5_svar64(id-o5_id); o5_id= id;
- wo__author(hisver,histime,hiscset,hisuid,hisuser);
- o5_svar32(lon-o5_lon); o5_lon= lon;
- o5_svar32(lat-o5_lat); o5_lat= lat;
-return;
- } // end o5m
- if(wo__format<0) // item list
-return;
- wo__CLOSE
- if(wo__logaction)
- wo__action(hisver==1? 1: 2);
- switch(wo__format) { // depending on output format
- case 11: // native XML
- write_str("\t<node id=\""); write_sint64(id);
- write_str("\" lat=\""); write_sfix7(lat);
- write_str("\" lon=\""); write_sfix7(lon);
- wo__author(hisver,histime,hiscset,hisuid,hisuser);
- wo__xmlclosetag= "\t</node>"NL; // preset close tag
- break;
- case 12: // pbf2osm XML
- write_str("\t<node id=\""); write_sint64(id);
- write_str("\" lat=\""); write_sfix7o(lat);
- write_str("\" lon=\""); write_sfix7o(lon);
- wo__author(hisver,histime,hiscset,hisuid,hisuser);
- wo__xmlclosetag= "\t</node>"NL; // preset close tag
- break;
- case 13: // Osmosis XML
- write_str(" <node id=\""); write_sint64(id);
- wo__author(hisver,histime,hiscset,hisuid,hisuser);
- write_str("\" lat=\""); write_sfix7(lat);
- write_str("\" lon=\""); write_sfix7(lon);
- wo__xmlclosetag= " </node>"NL; // preset close tag
- break;
- case 14: // Osmium XML
- write_str(" <node id=\""); write_sint64(id);
- wo__author(hisver,histime,hiscset,hisuid,hisuser);
- if(lon>=0) lon= (lon+5)/10;
- else lon= (lon-5)/10;
- if(lat>=0) lat= (lat+5)/10;
- else lat= (lat-5)/10;
- write_str("\" lon=\""); write_sfix6o(lon);
- write_str("\" lat=\""); write_sfix6o(lat);
- wo__xmlclosetag= " </node>"NL; // preset close tag
- break;
- } // end depending on output format
- wo__xmlshorttag= true; // (default)
- } // end wo_node()
-
-static inline void wo_way(int64_t id,
- int32_t hisver,int64_t histime,int64_t hiscset,
- uint32_t hisuid,const char* hisuser) {
- // write osm way body;
- // id: id of this object;
- // hisver: version; 0: no author information is to be written
- // (necessary if o5m format);
- // histime: time (seconds since 1970)
- // hiscset: changeset
- // hisuid: uid
- // hisuser: user name
- if(wo__format==0) { // o5m
- o5_write(); // write last object - if any
- o5_type(1);
- o5_byte(0x11); // data set id for way
- o5_svar64(id-o5_id); o5_id= id;
- wo__author(hisver,histime,hiscset,hisuid,hisuser);
- o5_markref(0);
-return;
- } // end o5m
- if(wo__format<0) // item list
-return;
- wo__CLOSE
- if(wo__logaction)
- wo__action(hisver==1? 1: 2);
- switch(wo__format) { // depending on output format
- case 11: // native XML
- write_str("\t<way id=\""); write_sint64(id);
- wo__author(hisver,histime,hiscset,hisuid,hisuser);
- wo__xmlclosetag= "\t</way>"NL; // preset close tag
- break;
- case 12: // pbf2osm XML
- write_str("\t<way id=\""); write_sint64(id);
- wo__author(hisver,histime,hiscset,hisuid,hisuser);
- wo__xmlclosetag= "\t</way>"NL; // preset close tag
- break;
- case 13: // Osmosis XML
- case 14: // Osmium XML
- write_str(" <way id=\""); write_sint64(id);
- wo__author(hisver,histime,hiscset,hisuid,hisuser);
- wo__xmlclosetag= " </way>"NL; // preset close tag
- break;
- } // end depending on output format
- wo__xmlshorttag= true; // (default)
- } // end wo_way()
-
-static inline void wo_relation(int64_t id,
- int32_t hisver,int64_t histime,int64_t hiscset,
- uint32_t hisuid,const char* hisuser) {
- // write osm relation body;
- // id: id of this object;
- // hisver: version; 0: no author information is to be written
- // (necessary if o5m format);
- // histime: time (seconds since 1970)
- // hiscset: changeset
- // hisuid: uid
- // hisuser: user name
- if(wo__format==0) { // o5m
- o5_write(); // write last object - if any
- o5_type(2);
- o5_byte(0x12); // data set id for relation
- o5_svar64(id-o5_id); o5_id= id;
- wo__author(hisver,histime,hiscset,hisuid,hisuser);
- o5_markref(0);
-return;
- } // end o5m
- if(wo__format<0) // item list
-return;
- wo__CLOSE
- if(wo__logaction)
- wo__action(hisver==1? 1: 2);
- switch(wo__format) { // depending on output format
- case 11: // native XML
- write_str("\t<relation id=\""); write_sint64(id);
- wo__author(hisver,histime,hiscset,hisuid,hisuser);
- wo__xmlclosetag= "\t</relation>"NL; // preset close tag
- break;
- case 12: // pbf2osm XML
- write_str("\t<relation id=\""); write_sint64(id);
- wo__author(hisver,histime,hiscset,hisuid,hisuser);
- wo__xmlclosetag= "\t</relation>"NL; // preset close tag
- break;
- case 13: // Osmosis XML
- case 14: // Osmium XML
- write_str(" <relation id=\""); write_sint64(id);
- wo__author(hisver,histime,hiscset,hisuid,hisuser);
- wo__xmlclosetag= " </relation>"NL; // preset close tag
- break;
- } // end depending on output format
- wo__xmlshorttag= true; // (default)
- } // end wo_relation()
-
-static void wo_delete(int otype,int64_t id,
- int32_t hisver,int64_t histime,int64_t hiscset,
- uint32_t hisuid,const char* hisuser) {
- // write osm delete request;
- // this is possible for o5m format only;
- // for any other output format, this procedure does nothing;
- // otype: 0: node; 1: way; 2: relation;
- // id: id of this object;
- // hisver: version; 0: no author information is to be written
- // (necessary if o5m format);
- // histime: time (seconds since 1970)
- // hiscset: changeset
- // hisuid: uid
- // hisuser: user name
- if(wo__format<0) // item list
-return;
- if(otype<0 || otype>2)
-return;
- if(wo__format==0) { // o5m (.o5c)
- o5_write(); // write last object - if any
- o5_type(otype);
- o5_byte(0x10+otype); // data set id
- o5_svar64(id-o5_id); o5_id= id;
- wo__author(hisver,histime,hiscset,hisuid,hisuser);
- } // end o5m (.o5c)
- else { // .osm (.osc)
- wo__CLOSE
- if(wo__logaction)
- wo__action(3);
- if(wo__format>=13) write_str(" <"); else write_str("\t<");
- write_str(ONAME(otype));
- write_str(" id=\""); write_sint64(id);
- wo__author(hisver,histime,hiscset,hisuid,hisuser);
- if(global_fakelonlat)
- write_str("\" lat=\"0\" lon=\"0");
- wo__xmlclosetag= "\"/>"NL; // preset close tag
- wo__xmlshorttag= false; // (default)
- wo__CLOSE // write close tag
- } // end .osm (.osc)
- } // end wo_delete()
-
-static inline void wo_noderef(int64_t noderef) {
- // write osm object node reference;
- if(wo__format==0) { // o5m
- o5_svar64(noderef-o5_ref[0]); o5_ref[0]= noderef;
- o5_markref(1);
-return;
- } // end o5m
- if(wo__format<0) // item list
-return;
- // here: XML format
- wo__CONTINUE
- switch(wo__format) { // depending on output format
- case 11: // native XML
- case 12: // pbf2osm XML
- write_str("\t\t<nd ref=\""); write_sint64(noderef);
- write_str("\"/>"NL);
- break;
- case 13: // Osmosis XML
- case 14: // Osmium XML
- write_str(" <nd ref=\""); write_sint64(noderef);
- write_str("\"/>"NL);
- break;
- } // end depending on output format
- } // end wo_noderef()
-
-static inline void wo_ref(int64_t refid,int reftype,
- const char* refrole) {
- // write osm object reference;
- if(wo__format==0) { // o5m
- char o5typerole[4000];
-
- o5_svar64(refid-o5_ref[reftype]); o5_ref[reftype]= refid;
- o5typerole[0]= reftype+'0';
- strmcpy(o5typerole+1,refrole,sizeof(o5typerole)-1);
- stw_write(o5typerole,NULL);
- o5_markref(1);
-return;
- } // end o5m
- if(wo__format<0) // item list
-return;
- // here: XML format
- wo__CONTINUE
- switch(wo__format) { // depending on output format
- case 11: // native XML
- case 12: // pbf2osm XML
- if(reftype==0)
- write_str("\t\t<member type=\"node\" ref=\"");
- else if(reftype==1)
- write_str("\t\t<member type=\"way\" ref=\"");
- else
- write_str("\t\t<member type=\"relation\" ref=\"");
- write_sint64(refid);
- write_str("\" role=\""); write_xmlstr(refrole);
- write_str("\"/>"NL);
- break;
- case 13: // Osmosis XML
- case 14: // Osmium XML
- if(reftype==0)
- write_str(" <member type=\"node\" ref=\"");
- else if(reftype==1)
- write_str(" <member type=\"way\" ref=\"");
- else
- write_str(" <member type=\"relation\" ref=\"");
- write_sint64(refid);
- write_str("\" role=\""); write_xmlmnstr(refrole);
- write_str("\"/>"NL);
- break;
- } // end depending on output format
- } // end wo_ref()
-
-static inline void wo_keyval(const char* key,const char* val) {
- // write osm object's keyval;
- if(wo__format==0) { // o5m
- stw_write(key,val);
-return;
- } // end o5m
- if(wo__format<0) { // item list
- if(*(int16_t*)global_outkey==0) // list keys
- count_add(key);
- else { // list vals of one specific key
- if(fil__cmp(key,global_outkey))
- // this is the key of which we want its vals listed
- count_add(val);
- }
-return;
- }
- // here: XML format
- wo__CONTINUE
- switch(wo__format) { // depending on output format
- case 11: // native XML
- write_str("\t\t<tag k=\""); write_xmlstr(key);
- write_str("\" v=\""); write_xmlstr(val);
- write_str("\"/>"NL);
- break;
- case 12: // pbf2osm XML
- write_str("\t\t<tag k=\""); write_xmlstr(key);
- write_str("\" v=\""); write_xmlstr(val);
- write_str("\" />"NL);
- break;
- case 13: // Osmosis XML
- case 14: // Osmium XML
- write_str(" <tag k=\""); write_xmlmnstr(key);
- write_str("\" v=\""); write_xmlmnstr(val);
- write_str("\"/>"NL);
- break;
- } // end depending on output format
- } // end wo_keyval()
-
-//------------------------------------------------------------
-// end Module wo_ write osm module
-//------------------------------------------------------------
-
-
-
-//------------------------------------------------------------
-// Module oo_ osm to osm module
-//------------------------------------------------------------
-
-// this module provides procedures which read osm objects,
-// process them and write them as osm objects, using module wo_;
-// that goes for .osm format as well as for .o5m format;
-// as usual, all identifiers of a module have the same prefix,
-// in this case 'oo'; one underline will follow in case of a
-// global accessible object, two underlines in case of objects
-// which are not meant to be accessed from outside this module;
-// the sections of private and public definitions are separated
-// by a horizontal line: ----
-
-static void oo__inverserrprocessing(int* maxrewindp) {
- // process temporary relation reference file;
- // the file must have been written; this procedure processes
- // the interrelation references of this file and updates
- // the hash table of module hash_ accordingly;
- // maxrewind: maximum number of rewinds;
- // return:
- // maxrewind: <0: maximum number of rewinds was not sufficient;
- // if there is no relation reference file, this procedure does
- // nothing;
- int changed;
- // number of relations whose flag has been changed, i.e.,
- // the recursive processing will continue;
- // if none of the relations' flags has been changed,
- // this procedure will end;
- int h;
- int32_t relid; // relation id;
- int32_t refid; // interrelation reference id;
- bool flag;
-
- h= 0;
- relid= 0; flag= false;
- while(*maxrewindp>=0) { // for every recursion
- changed= 0;
- if(rr_rewind()) // could not rewind
- break;
- for(;;) { // for every reference
- for(;;) { // get next id
- if(rr_read(&refid))
- goto rewind; // if at file end, rewind
- if(refid!=0)
- break;
- // here: a relation id will follow
- rr_read(&relid); // get the relation id
- flag= hash_geti(2,relid); // get flag of this relation
- } // end get next id
- if(!flag) // flag of this relation has not been set
- continue; // go on until next relation
- if(hash_relseti(refid)) // set flag of referenced relation;
- // flag of reference was not set
- changed++; // memorize that we changed a flag
- } // end for every reference
- rewind:
- if(loglevel>0) fprintf(stderr,
- "Interrelational hierarchy %i: %i dependencies.\n",++h,changed);
- if(changed==0) // no changes have been made in last recursion
- break; // end the processing
- (*maxrewindp)--;
- } // end for every recursion
- } // end oo__inverserrprocessing()
-
-static byte oo__whitespace[]= {
- 0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0, // HT LF VT FF CR
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // SPC
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
-#define oo__ws(c) (oo__whitespace[(byte)(c)])
-static byte oo__whitespacenul[]= {
- 1,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0, // NUL HT LF VT FF CR
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, // SPC /
- 0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0, // <
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
-#define oo__wsnul(c) (oo__whitespacenul[(byte)(c)])
-static byte oo__letter[]= {
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,
- 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
-#define oo__le(c) (oo__letter[(byte)(c)])
-
-static const uint8_t* oo__hexnumber= (uint8_t*)
- // convert a hex character to a number
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x00\x00\x00\x00\x00\x00"
- "\x00\x0a\x0b\x0c\x0d\x0e\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x0a\x0b\x0c\x0d\x0e\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
-
-static uint32_t oo__strtouint32(const char* s) {
- // read a number and convert it to an unsigned 64-bit integer;
- // return: number;
- int32_t i;
- byte b;
-
- i= 0;
- for(;;) {
- b= (byte)(*s++ -'0');
- if(b>=10)
- break;
- i= i*10+b;
- }
- return i;
- } // end oo__strtouint32()
-
-#if 0 // presently unused
-static int32_t oo__strtosint32(const char* s) {
- // read a number and convert it to a signed 64-bit integer;
- // return: number;
- int sign;
- int32_t i;
- byte b;
-
- if(*s=='-') { s++; sign= -1; } else sign= 1;
- i= 0;
- for(;;) {
- b= (byte)(*s++ -'0');
- if(b>=10)
- break;
- i= i*10+b;
- }
- return i*sign;
- } // end oo__strtosint32()
-#endif
-
-static int64_t oo__strtosint64(const char* s) {
- // read a number and convert it to a signed 64-bit integer;
- // return: number;
- int sign;
- int64_t i;
- byte b;
-
- if(*s=='-') { s++; sign= -1; } else sign= 1;
- i= 0;
- for(;;) {
- b= (byte)(*s++ -'0');
- if(b>=10)
- break;
- i= i*10+b;
- }
- return i*sign;
- } // end oo__strtosint64()
-
-static const int32_t oo__nildeg= 2000000000L;
-
-static int32_t oo__strtodeg(char* s) {
- // read a number which represents a degree value and
- // convert it to a fixpoint number;
- // s[]: string with the number between -180 and 180,
- // e.g. "-179.99", "11", ".222";
- // return: number in 10 millionth degrees;
- // =='oo__nildeg': syntax error;
- static const long di[]= {10000000L,10000000L,1000000L,100000L,
- 10000L,1000L,100L,10L,1L};
- static const long* dig= di+1;
- int sign;
- int d; // position of decimal digit;
- long k;
- char c;
-
- if(*s=='-') { s++; sign= -1; } else sign= 1;
- if(!isdig(*s) && *s!='.')
-return oo__nildeg;
- k= 0;
- d= -1;
- do { // for every digit
- c= *s++;
- if(c=='.') { d= 0; continue; } // start fractional part
- else if(!isdig(c) || c==0)
- break;
- k= k*10+c-'0';
- if(d>=0) d++;
- } while(d<7); // end for every digit
- k*= dig[d]*sign;
- return k;
- } // end oo__strtodeg()
-
-static int64_t oo__strtimetosint64(const char* s) {
- // read a timestamp in OSM format, e.g.: "2010-09-30T19:23:30Z",
- // and convert it to a signed 64-bit integer;
- // return: time as a number (seconds since 1970);
- struct tm tm;
-
- tm.tm_isdst= 0;
- tm.tm_year=
- (s[0]-'0')*1000+(s[1]-'0')*100+(s[2]-'0')*10+(s[3]-'0')-1900;
- tm.tm_mon= (s[5]-'0')*10+s[6]-'0'-1;
- tm.tm_mday= (s[8]-'0')*10+s[9]-'0';
- tm.tm_hour= (s[11]-'0')*10+s[12]-'0';
- tm.tm_min= (s[14]-'0')*10+s[15]-'0';
- tm.tm_sec= (s[17]-'0')*10+s[18]-'0';
- #if __WIN32__
- // use replcement for timegm() because Windows does not know it
- #if 0
- if(oo__tz==NULL) {
- oo__tz= getenv("TZ");
- putenv("TZ=");
- tzset();
- }
- return mktime(&tm);
- #endif
- return mktime(&tm)-timezone;
- #else
- return timegm(&tm);
- #endif
- } // end oo__strtimetosint64()
-
-static void oo__xmltostr(char* s) {
- // read an xml string and convert is into a regular UTF-8 string,
- // for example: "Mayer&apos;s" -> "Mayer's";
- char* t; // pointer in overlapping target string
- char c;
- uint32_t u;
-
- //char* s0; s0= s;
- for(;;) { // for all characters, until first '&' or string end;
- c= *s;
- if(c==0) // no character to convert
-return;
- if(c=='&')
- break;
- s++;
- }
- //fprintf(stderr,"A %s\n",s0);//,,
- t= s;
- for(;;) { // for all characters after the first '&'
- c= *s++;
- if(c==0) // at the end of string
- break;
- if(c!='&') {
- *t++= c;
- continue;
- }
- c= *s;
- if(c=='#') { // numeric value
- c= *++s;
- if(c=='x') { // hex value
- s++;
- u= 0;
- for(;;) {
- c= *s++;
- if(c==';' || c==0)
- break;
- u= (u<<4)+oo__hexnumber[(byte)c];
- }
- } // end hex value
- else { // decimal value
- u= 0;
- for(;;) {
- c= *s++;
- if(c==';' || c==0)
- break;
- u= u*10+c-'0';
- }
- } // end decimal value
- if(u<128) // 1 byte sufficient
- *t++= (char)u;
- else if(u<2048) { // 2 bytes sufficient
- *t++= (u>>6)|0xc0; *t++= (u&0x3f)|0x80; }
- else if(u<65536) { // 3 bytes sufficient
- *t++= (u>>12)|0xe0; *t++= ((u>>6)&0x3f)|0x80;
- *t++= (u&0x3f)|0x80; }
- else { // 4 bytes necessary
- *t++= ((u>>18)&0x07)|0xf0; *t++= ((u>>12)&0x3f)|0x80;
- *t++= ((u>>6)&0x3f)|0x80; *t++= (u&0x3f)|0x80; }
- } // end numeric value
- else if(strzcmp(s,"quot;")==0) {
- s+= 5; *t++= '\"'; }
- else if(strzcmp(s,"apos;")==0) {
- s+= 5; *t++= '\''; }
- else if(strzcmp(s,"amp;")==0) {
- s+= 4; *t++= '&'; }
- else if(strzcmp(s,"lt;")==0) {
- s+= 3; *t++= '<'; }
- else if(strzcmp(s,"gt;")==0) {
- s+= 3; *t++= '>'; }
- else { // unknown escape code
- *t++= '&';
- }
- } // end for all characters after the first '&'
- *t= 0; // terminate target string
- //fprintf(stderr,"Z %s\n",s0);sleep(1);//,,
- } // end oo__xmltostr()
-
-static bool oo__xmlheadtag; // currently, we are inside an xml start tag,
- // maybe a short tag, e.g. <node ... > or <node ... />
- // (the second example is a so-called short tag)
-static char* oo__xmlkey,*oo__xmlval; // return values of oo__xmltag
-
-static bool oo__xmltag() {
- // read the next xml key/val and return them both;
- // due to performance reasons, global and module global variables
- // are used;
- // read_bufp: address at which the reading begins;
- // oo__xmlheadtag: see above;
- // return: no more xml keys/vals to read inside the outer xml tag;
- // oo__xmlkey,oo__xmlval: newest xml key/val which have been read;
- // "","": encountered the end of an
- // enclosed xml tag;
- char c;
- char xmldelim;
-
- for(;;) { // until break
- while(!oo__wsnul(*read_bufp)) read_bufp++;
- // find next whitespace or null character or '/'
- while(oo__ws(*read_bufp)) read_bufp++;
- // find first character after the whitespace(s)
- c= *read_bufp;
- if(c==0) {
- oo__xmlkey= oo__xmlval= "";
-return true;
- }
- else if(c=='/') {
- oo__xmlkey= oo__xmlval= "";
- c= *++read_bufp;
- read_bufp++;
- if(c=='>') { // short tag ands here
- if(oo__xmlheadtag) {
- // this ending short tag is the object's tag
- oo__xmlheadtag= false;
-return true;
- }
-return false;
- } // end short tag ands here
- continue;
- }
- else if(c=='<') {
- oo__xmlheadtag= false;
- if(*++read_bufp=='/' && (
- (c= *++read_bufp)=='n' || c=='w' || c=='r') ) {
- // this has been long tag which is ending now
- while(!oo__wsnul(*read_bufp)) read_bufp++;
- // find next whitespace
- oo__xmlkey= oo__xmlval= "";
-return true;
- }
- continue;
- }
- oo__xmlkey= (char*)read_bufp;
- while(oo__le(*read_bufp)) read_bufp++;
- if(*read_bufp!='=') {
- oo__xmlkey= "";
- continue;
- }
- *read_bufp++= 0;
- if(*read_bufp!='\"' && *read_bufp!='\'')
- continue;
- xmldelim= (char)*read_bufp;
- oo__xmlval= (char*)(++read_bufp);
- for(;;) {
- c= *read_bufp;
- if(c==xmldelim)
- break;
- if(c==0) {
- oo__xmlkey= oo__xmlval= "";
-return true;
- }
- read_bufp++;
- }
- *read_bufp++= 0;
- break;
- } // end until break
- oo__xmltostr(oo__xmlkey);
- oo__xmltostr(oo__xmlval);
- return false;
- } // end oo__xmltag()
-
-typedef struct {
- read_info_t* ri; // file handles for input files
- int format; // input file format;
- // ==-9: unknown; ==0: o5m; ==10: xml; ==-1: pbf;
- str_info_t* str; // string unit handle (if o5m format)
- const char* filename;
- bool endoffile;
- int deleteobject; // replacement for .osc <delete> tag
- // 0: not to delete; 1: delete this object; 2: delete from now on;
- int64_t o5id; // for o5m delta coding
- int32_t o5lon,o5lat; // for o5m delta coding
- int64_t o5histime; // for o5m delta coding
- int64_t o5hiscset; // for o5m delta coding
- int64_t o5rid[3]; // for o5m delta coding
- } oo__if_t;
-static oo__if_t oo__if[global_fileM];
-static oo__if_t* oo__ifp= oo__if; // currently used element in oo__if[]
-#define oo__ifI (oo__ifp-oo__if) // index
-static oo__if_t* oo__ife= oo__if; // logical end of elements in oo__if[]
-static oo__if_t* oo__ifee= oo__if+global_fileM;
- // physical end of oo_if[]
-static int oo_ifn= 0; // number of currently open files
-
-static int oo__getformat() {
- // determine the formats of all opened files of unknown format
- // and store these determined formats;
- // do some intitialization for the format, of necessary;
- // oo__if[].format: !=-9: do nothing for this file;
- // return: 0: ok; !=0: error;
- // 5: too many pbf files;
- // this is, because the module pbf (see above)
- // does not have multi-client capabilities;
- // oo__if[].format: input file format; ==0: o5m; ==10: xml; ==-1: pbf;
- oo__if_t* ifptemp;
- byte* bufp;
- #define bufsp ((char*)bufp) // for signed char
-
- ifptemp= oo__ifp;
- oo__ifp= oo__if;
- while(oo__ifp<oo__ife) { // for all input files
- if(oo__ifp->ri!=NULL && oo__ifp->format==-9) {
- // format not yet determined
- read_switch(oo__ifp->ri);
- if(read_bufp>=read_bufe) { // file empty
- PERRv("file empty: %.80s",oo__ifp->filename)
-return 2;
- }
- bufp= read_bufp;
- if(bufp[0]==0 && bufp[1]==0 && bufp[2]==0 &&
- bufp[3]>8 && bufp[3]<20) { // presumably .pbf format
- PERR("cannot process .pbf format.");
-return 5;
- }
- else if(strzcmp(bufsp,"<?xml")==0 ||
- strzcmp(bufsp,"<osm")==0) { // presumably .osm format
- oo__ifp->format= 10;
- }
- else if(bufp[0]==0xff && bufp[1]==0xe0 && (
- strzcmp(bufsp+2,"\x04""o5m2")==0 ||
- strzcmp(bufsp+2,"\x04""o5c2")==0 )) {
- // presumably .o5m format
- oo__ifp->format= 0;
- oo__ifp->str= str_open();
- // call some initialization of string read module
- }
- else if((bufp[0]==0xff && bufp[1]>=0x10 && bufp[1]<=0x12) ||
- (bufp[0]==0xff && bufp[1]==0xff &&
- bufp[2]>=0x10 && bufp[2]<=0x12) ||
- (bufp[0]==0xff && read_bufe==read_bufp+1)) {
- // presumably shortened .o5m format
- if(loglevel>=2)
- fprintf(stderr,"osmfilter: Not a standard .o5m file header "
- "%.80s\n",oo__ifp->filename);
- oo__ifp->format= 0;
- oo__ifp->str= str_open();
- // call some initialization of string read module
- }
- else { // unknown file format
- PERRv("unknown file format: %.80s",oo__ifp->filename)
-return 3;
- }
- } // format not yet determined
- oo__ifp++;
- } // for all input files
- oo__ifp= ifptemp;
- return 0;
- #undef bufsp
- } // end oo__getformat()
-
-static void oo__reset() {
- // reset counters for writing o5m files;
- if(oo__ifp->format==0) { // o5m
- oo__ifp->o5id= 0;
- oo__ifp->o5lat= oo__ifp->o5lon= 0;
- oo__ifp->o5hiscset= 0;
- oo__ifp->o5histime= 0;
- oo__ifp->o5rid[0]= oo__ifp->o5rid[1]= oo__ifp->o5rid[2]= 0;
- str_reset();
- } // o5m
- } // oo__reset()
-
-static bool oo__bbvalid= false;
- // the following bbox coordinates are valid;
-static int32_t oo__bbx1= 0,oo__bby1= 0,oo__bbx2= 0,oo__bby2= 0;
- // bbox coordinates (base 10^-7);
-
-static void oo__findbb() {
- // find border box in input file (if any);
- // return:
- // oo__bbvalid: following border box information is valid;
- // oo__bbx1 .. oo__bby2: border box coordinates;
- // read_bufp will not be changed;
- byte* bufp,*bufe;
-
- read_input();
- bufp= read_bufp; bufe= read_bufe;
- if(oo__ifp->format==0) { // o5m
- byte b; // latest byte which has been read
- int l;
-
- while(bufp<bufe) { // for all bytes
- b= *bufp;
- if(b==0 || (b>=0x10 && b<=0x12)) // regular dataset id
-return;
- if(b>=0xf0) { // single byte dataset
- bufp++;
- continue;
- } // end single byte dataset
- // here: non-object multibyte dataset
- if(b==0xdb) { // border box
- bufp++;
- l= pbf_uint32(&bufp);
- bufe= bufp+l;
- if(bufp<bufe) oo__bbx1= pbf_sint32(&bufp);
- if(bufp<bufe) oo__bby1= pbf_sint32(&bufp);
- if(bufp<bufe) oo__bbx2= pbf_sint32(&bufp);
- if(bufp<bufe) {
- oo__bby2= pbf_sint32(&bufp);
- oo__bbvalid= true;
- }
-return;
- } // border box
- bufp++;
- l= pbf_uint32(&bufp); // jump over this dataset
- bufp+= l; // jump over this dataset
- } // end for all bytes
- } // end o5m
- else { // osm xml
- char* sp;
- char c1,c2,c3; // next available characters
-
- while(bufp<bufe) { // for all bytes
- sp= strchr((char*)bufp,'<');
- if(sp==NULL)
- break;
- c1= sp[1]; c2= sp[2]; c3= sp[3];
- if(c1=='n' && c2=='o' && c3=='d')
-return;
- else if(c1=='w' && c2=='a' && c3=='y')
-return;
- else if(c1=='r' && c2=='e' && c3=='l')
-return;
- else if(c1=='b' && c2=='o' && c3=='u') { // bounds
- // bounds may be supplied in one of these formats:
- // <bounds minlat="53.01104" minlon="8.481593"
- // maxlat="53.61092" maxlon="8.990601"/>
- // <bound box="49.10868,6.35017,49.64072,7.40979"
- // origin="http://www.openstreetmap.org/api/0.6"/>
- uint32_t bboxcomplete; // flags for oo__bbx1 .. oo__bby2
- int l;
- char c;
-
- bboxcomplete= 0;
- sp++; // jump over '<'
- for(;;) { // jump over "bounds ", resp. "bound "
- c= *sp;
- if(oo__wsnul(c))
- break;
- sp++;
- }
- for(;;) { // for every word in 'bounds'
- c= *sp;
- if(c=='/' || c=='>' || c==0)
- break;
- if(oo__ws(c) || c==',') {
- sp++;
- continue;
- }
- if((l= strzlcmp(sp,"box=\""))>0 ||
- (l= strzlcmp(sp,"box=\'"))>0) {
- sp+= l;
- c= *sp;
- }
- if((l= strzlcmp(sp,"minlat=\""))>0 ||
- (l= strzlcmp(sp,"minlat=\'"))>0 ||
- ((isdig(c) || c=='-' || c=='.') && (bboxcomplete&2)==0)) {
- sp+= l;
- oo__bby1= oo__strtodeg(sp);
- if(oo__bby1!=oo__nildeg) bboxcomplete|= 2;
- }
- else if((l= strzlcmp(sp,"minlon=\""))>0 ||
- (l= strzlcmp(sp,"minlon=\'"))>0 ||
- ((isdig(c) || c=='-' || c=='.') && (bboxcomplete&1)==0)) {
- sp+= l;
- oo__bbx1= oo__strtodeg(sp);
- if(oo__bbx1!=oo__nildeg) bboxcomplete|= 1;
- }
- else if((l= strzlcmp(sp,"maxlat=\""))>0 ||
- (l= strzlcmp(sp,"maxlat=\'"))>0 ||
- ((isdig(c) || c=='-' || c=='.') && (bboxcomplete&8)==0)) {
- sp+= l;
- oo__bby2= oo__strtodeg(sp);
- if(oo__bby2!=oo__nildeg) bboxcomplete|= 8;
- }
- else if((l= strzlcmp(sp,"maxlon=\""))>0 ||
- (l= strzlcmp(sp,"maxlon=\'"))>0 ||
- ((isdig(c) || c=='-' || c=='.') && (bboxcomplete&4)==0)) {
- sp+= l;
- oo__bbx2= oo__strtodeg(sp);
- if(oo__bbx2!=oo__nildeg) bboxcomplete|= 4;
- }
- for(;;) { // find next blank or comma
- c= *sp;
- if(oo__wsnul(c) || c==',')
- break;
- sp++;
- }
- } // end for every word in 'bounds'
- oo__bbvalid= bboxcomplete==15;
-return;
- } // bounds
- else {
- bufp++;
- continue;
- }
- } // end for all bytes of the file
- } // end osm xml
- } // end oo__findbb()
-
-static int oo__findpos() {
- // find input file positions of the starts of node, way
- // and relation sections;
- // oo__ifp->format: ==0: o5m; ==1: osm xml;
- // return: ==0: OK; !=0: error;
- // positions are stored via read_jump(o,false), whereas
- // o==0: node, o==1: way; o==2: relation;
- // note that each of these positions will be stored, even if there
- // is no object of the related type;
- // this procedure assumes that the read position in the file is at
- // byte 0 when being called; the caller may not expect the read
- // cursor to be at the relations' start when this function returns;
- // if there are no relations in the file, the read cursor will be
- // at or near the end of the file;
- int otype,otypeold; // type of currently processed object;
- // -1: unknown; 0: node; 1: way; 2: relation;
-
- read_jump(0,false); // start of nodes (default)
- read_jump(1,false); // start of ways (default)
- read_jump(2,false); // start of relations (default)
- if(oo__ifp->format==0) { // o5m
- byte b; // latest byte which has been read
- int l;
- bool reset;
-
- otypeold= -1;
- reset= true; // (default for file start)
- while(read_bufp<read_bufe) { // for all bytes of the file
- read_input();
- b= *read_bufp;
- if(b<0x10 || b>0x12) { // not a regular dataset id
- if(b>=0xf0) { // single byte dataset
- if(b==0xff) // file start, resp. o5m reset
- reset= true;
- read_bufp++;
- continue;
- } // end single byte dataset
- // here: non-object multibyte dataset
- read_bufp++;
- l= pbf_uint32(&read_bufp); // jump over this dataset
- read_bufp+= l; // jump over this dataset
- continue;
- } // end not a regular dataset id
- otype= b&3;
- if(otype!=otypeold) { // object type has changed
- if(!reset) {
- PERRv("no .o5m reset tag before first %s",ONAME(otype))
-return 1;
- }
- read_jump(otype,false); // store this position
- if(otype>=otypeold+2)
- read_jump(otype-1,false);
- // store this position for start of last object too
- if(otype>=otypeold+3)
- read_jump(otype-2,false);
- // store this position for start of object
- // before last object too
- if(otype==2) // we are at start of relations
-return 0;
- otypeold= otype;
- } // object type has changed
- read_bufp++;
- l= pbf_uint32(&read_bufp); // jump over this dataset
- read_bufp+= l; // jump over this dataset
- reset= false;
- } // end for all bytes of the file
- } // end o5m
- else { // osm xml
- char* sp;
- char c1,c2,c3; // next available characters
-
- otypeold= -1;
- while(read_bufp<read_bufe) { // for all bytes of the file
- sp= strchr((char*)read_bufp,'<');
- if(sp==NULL)
- break;
- if(sp+10>=(char*)read_bufe) {
- // too close to end of prefetched data
- read_bufp= (byte*)sp;
- read_input();
- sp= (char*)read_bufp;
- }
- c1= sp[1]; c2= sp[2]; c3= sp[3];
- if(c1=='n' && c2=='o' && c3=='d')
- otype= 0;
- else if(c1=='w' && c2=='a' && c3=='y')
- otype= 1;
- else if(c1=='r' && c2=='e' && c3=='l')
- otype= 2;
- else {
- read_bufp= (byte*)sp+1;
- continue;
- }
- read_bufp= (byte*)sp;
- if(otype!=otypeold) { // object type has changed
- read_jump(otype,false); // store this position
- if(otype>=otypeold+2)
- read_jump(otype-1,false);
- // store this position for start of last object too
- if(otype>=otypeold+3)
- read_jump(otype-2,false);
- // store this position for start of object
- // before last object too
- if(otype==2) // we are at start of relations
-return 0;
- otypeold= otype;
- } // object type has changed
- read_bufp= (byte*)sp+1;
- } // end for all bytes of the file
- } // end osm xml
- if(otype<2) // did not encounter any relations
- read_jump(2,false); // set end position as start of relations
- if(otype<1) // did not encounter any ways
- read_jump(1,false); // set end position as start of ways
-return 0;
- } // end oo__findpos()
-
-static void oo__close() {
- // close an input file;
- // oo__ifp: handle of currently active input file;
- // if this file has already been closed, nothing happens;
- // after calling this procedure, the handle of active input file
- // will be invalid;
- if(oo__ifp!=NULL && oo__ifp->ri!=NULL) {
- if(!oo__ifp->endoffile && oo_ifn>0) // missing logical end of file
- fprintf(stderr,"osmfilter Warning: "
- "unexpected end of input file: %.80s\n",oo__ifp->filename);
- read_close(oo__ifp->ri);
- oo__ifp->ri= NULL;
- oo_ifn--;
- }
- oo__ifp= NULL;
- } // end oo__close()
-
-static void oo__end() {
- // clean-up this module;
- oo_ifn= 0; // mark end of program;
- // this is used to supress warning messages in oo__close()
- while(oo__ife>oo__if) {
- oo__ifp= --oo__ife;
- oo__close();
- }
- oo_ifn= 0;
- #if 0
- if(oo__tz!=NULL) { // time zone must be restored
- char s[256];
-
- snprintf(s,sizeof(s),"TZ=%s",oo__tz);
- putenv(s);
- tzset();
- oo__tz= NULL;
- } // time zone must be restored
- #endif
- } // end oo__end()
-
-//------------------------------------------------------------
-
-static bool oo_open(const char* filename) {
- // open an input file;
- // filename[]: path and name of input file;
- // ==NULL: standard input;
- // return: 0: ok; 1: no appropriate input file;
- // 2: maximum number of input files exceeded;
- // the handle for the current input file oo__ifp is set
- // to the opened file;
- // after having opened all input files, call oo__getformat();
- // you do not need to care about closing the file;
- static bool firstrun= true;
-
- if(oo__ife>=oo__ifee) {
- PERR("too many input files.")
-return 2;
- }
- if(read_open(filename)!=0)
-return 1;
- oo__ife->ri= read_infop;
- oo__ife->str= NULL;
- oo__ife->format= -9; // 'not yet determined'
- oo__ife->filename= filename;
- oo__ife->endoffile= false;
- oo__ife->deleteobject= 0;
- oo__ifp= oo__ife++;
- oo_ifn++;
- if(firstrun) {
- firstrun= false;
- atexit(oo__end);
- }
- return 0;
- } // end oo_open()
-
-static int oo_sequencetype= -1;
- // type of last object which has been processed;
- // -1: no object yet; 0: node; 1: way; 2: relation;
-static int64_t oo_sequenceid= INT64_C(-0x7fffffffffffffff);
- // id of last object which has been processed;
-
-static int oo_main() {
- // start reading osm objects;
- // return: ==0: ok; !=0: error;
- // this procedure must only be called once;
- // before calling this procedure you must open an input file
- // using oo_open();
- int wformat; // output format
- // 0: o5m; 11: osm; 12: pbf2osm emulation; 13: Osmosis emulation;
- // 21: output key list;
- int filterstage;
- // stage of the processing of interrelation dependencies;
- // 0: search for start of ways and start of relations;
- // change to stage 1 as soon as encountered the first relation;
- // 1: write interrelation references into a tempfile;
- // apply filter and update hash flags for relations;
- // change to stage 2 as soon as end of file has been reached;
- // 1->2: process interrelation dependencies,
- // jump to start of relations;
- // 2: parse relations and update hash flags of dependent objects;
- // change to stage 3 as soon as last relation has been parsed;
- // 2->3: jump to start of ways;
- // 3: parse ways and update hash flags of dependent nodes;
- // change to stage 3 as soon as last way has been parsed;
- // 3->4: jump to start of nodes;
- // 4: process the whole file;
- static char o5mtempfile[400]; // must be static because
- // this file will be deleted by an at-exit procedure;
- #define oo__maxrewindINI 12
- int maxrewind; // maximum number of relation-relation dependencies
- bool writeheader; // header must be written
- int otype; // type of currently processed object;
- // 0: node; 1: way; 2: relation;
- uint32_t complete; // flags for valid data
- int64_t id; // flag mask 1 (see oo__if_t)
- int32_t lon,lat; // flag masks 2, 4 (see oo__if_t)
- uint32_t hisver; // flag mask 8
- int64_t histime; // flag mask 16 (see oo__if_t)
- int64_t hiscset; // flag mask 32 (see oo__if_t)
- uint32_t hisuid; // flag mask 64
- char* hisuser; // flag mask 128
- // int64_t rid[3]; // for delta-coding (see oo__if_t)
- #define oo__refM 100000
- int64_t refid[oo__refM];
- int64_t* refidee; // end address of array
- int64_t* refide,*refidp; // pointer in array
- byte reftype[oo__refM];
- byte* reftypee,*reftypep; // pointer in array
- char* refrole[oo__refM];
- char** refrolee,**refrolep; // pointer in array
- #define oo__keyvalM 8000
- char* key[oo__keyvalM],*val[oo__keyvalM];
- char** keyee; // end address of array
- char** keye,**keyp; // pointer in array
- char** vale,**valp; // pointer in array
- char** keyf,**valf; // same as keye, vale, but for filter procedure;
- byte* bufp; // pointer in read buffer
- #define bufsp ((char*)bufp) // for signed char
- byte* bufe; // pointer in read buffer, end of object
- char c; // latest character which has been read
- byte b; // latest byte which has been read
- int l;
- byte* bp;
- char* sp;
-
- // procedure initialization
- atexit(oo__end);
- filterstage= 0;
- // 0: search for start of ways and start of relations;
- maxrewind= oo__maxrewindINI;
- if(rr_ini(global_tempfilename))
-return 4;
- writeheader= true;
- if(global_outo5m) wformat= 0;
- else if(global_emulatepbf2osm) wformat= 12;
- else if(global_emulateosmosis) wformat= 13;
- else if(global_emulateosmium) wformat= 14;
- else if(global_outkey!=NULL) wformat= -1;
- else wformat= 11;
- refidee= refid+oo__refM;
- keyee= key+oo__keyvalM-5; // decremented because we are going to add
- // some header information for filtering;
- // get input file format and care about tempfile name
- if(oo__getformat())
-return 5;
- strcpy(stpmcpy(o5mtempfile,global_tempfilename,
- sizeof(o5mtempfile)-2),".0");
-
- oo__findbb();
- if(global_recursive) {
- // find file positions of node, way and relation section's starts
- // here: filterstage==0
- // 0: search for start of ways and start of relations;
- if(oo__findpos())
- return 6;
- filterstage= 1;
- // 1: write interrelation references into a tempfile;
- }
- else
- filterstage= 4;
- // 4: process the whole file;
-
- // process the file
- for(;;) { // read input file
-
- // get next object
- read_input();
-
- // care about recursive processing
- if(read_bufp>=read_bufe) {
- // at end of input file;
- if(filterstage==1) {
- // 1: write interrelation references into a tempfile;
- // 1->2: process interrelation dependencies,
- oo__inverserrprocessing(&maxrewind);
- if(read_jump(1,true)) // jump to start of ways
-return 14;
- if(oo__ifp->format==0) oo__reset();
- filterstage= 2; // 2: parse relations and update hash flags;
- continue;
- }
- if(filterstage==2) {
- // 2: parse relations and update hash flags;
- if(read_jump(1,true)) // jump to start of ways
-return 15;
- if(oo__ifp->format==0) oo__reset();
- filterstage= 3; // 3: parse ways and update hash flags;
- continue;
- }
- if(filterstage==3) {
- // 3: parse ways and update hash flags;
- // (we did not expect eof here)
- if(read_jump(0,true)) // jump to start of nodes
-return 16;
- if(oo__ifp->format==0) oo__reset();
- filterstage= 4; // 4: process the whole file;
- continue;
- }
- // here: filterstage==4 // 4: process the whole file;
- if(loglevel>0) {
- if(global_recursive)
- fprintf(stderr,
- "osmfilter: Relation hierarchies: %i of maximal %i.\n",
- oo__maxrewindINI-maxrewind,oo__maxrewindINI);
- else
- fprintf(stderr,"osmfilter: No hierarchical filtering.\n");
- }
- if(maxrewind<0)
- fprintf(stderr,
- "osmfilter Warning: relation dependencies too complex\n"
- " (more than %i hierarchy levels).\n"
- " A few relations might have been excluded\n"
- " although meeting filter criteria.\n",
- oo__maxrewindINI);
- oo__close();
- break;
- } // end at end of input file
- if(oo__ifp->endoffile) { // after logical end of file
- fprintf(stderr,"osmfilter Warning: unexpected contents "
- "after logical end of file.\n");
- break;
- }
- bufp= read_bufp;
- b= *bufp; c= (char)b;
-
- // care about header and unknown objects
- if(oo__ifp->format==0) { // o5m
- if(b<0x10 || b>0x12) { // not a regular dataset id
- if(b>=0xf0) { // single byte dataset
- if(b==0xff) // file start, resp. o5m reset
- oo__reset();
- else if(b==0xfe) {
- if(filterstage==4)
- oo__ifp->endoffile= true;
- }
- else if(write_testmode)
- WARNv("unknown .o5m short dataset id: 0x%02x",b)
- read_bufp++;
- continue;
- } // end single byte dataset
- else { // unknown multibyte dataset
- if(write_testmode && b!=0xe0 && b!=0xdb && b!=0xdc)
- WARNv("unknown .o5m dataset id: 0x%02x",b)
- read_bufp++;
- l= pbf_uint32(&read_bufp); // jump over this dataset
- read_bufp+= l; // jump over this dataset
- continue;
- } // end unknown multibyte dataset
- } // end not a regular dataset id
- otype= b&3;
- } // end o5m
- else { // xml
- while(c!=0 && c!='<') c= (char)*++bufp;
- if(c==0) {
- read_bufp= read_bufe;
- continue;
- }
- c= bufsp[1];
- if(c=='n' && bufsp[2]=='o' && bufsp[3]=='d') // node 2012-12-13
- otype= 0;
- else if(c=='w' && bufsp[2]=='a' && bufsp[3]=='y') // way
- otype= 1;
- else if(c=='r' && bufsp[2]=='e' && bufsp[3]=='l') // relation
- otype= 2;
- else if(c=='c' || (c=='m' && bufsp[2]=='o') || c=='d') {
- // create, modify or delete
- if(c=='d')
- oo__ifp->deleteobject= 2;
- read_bufp= bufp+1;
- continue;
- } // end create, modify or delete
- else if(c=='/') { // xml end object
- if(bufsp[2]=='d') // end of delete
- oo__ifp->deleteobject= 0;
- else if(strzcmp(bufsp+2,"osm>")==0) { // end of file
- if(filterstage==4)
- oo__ifp->endoffile= true;
- read_bufp= bufp+6;
- while(oo__ws(*read_bufp)) read_bufp++;
- continue;
- } // end end of file
- goto unknownxmlobject;
- } // end xml end object
- else { // unknown xml object
- unknownxmlobject:
- bufp++;
- for(;;) { // find end of xml object
- c= *bufsp;
- if(c=='>' || c==0)
- break;
- bufp++;
- }
- read_bufp= bufp;
- continue;
- } // end unknown XML object
- read_bufp= bufp;
- } // end xml
-
- // care about filterstage changes
- if(filterstage==3 && otype==2) {
- // 3: parse ways and update hash flags;
- // here: encountered the first relation;
- // 3->4: jump to start of nodes;
- if(read_jump(0,true))
-return 18;
- if(oo__ifp->format==0) oo__reset();
- filterstage= 4; // 4: process the whole file;
- continue;
- }
-
- // write header
- if(writeheader) {
- writeheader= false;
- wo_start(wformat,oo__bbvalid && oo_ifn==1,
- oo__bbx1,oo__bby1,oo__bbx2,oo__bby2);
- }
-
- // object initialization
- complete= 0;
- hisver= 0;
- histime= 0;
- hiscset= 0;
- hisuid= 0;
- hisuser= "";
- refide= refid;
- reftypee= reftype;
- refrolee= refrole;
- keye= key;
- vale= val;
- if(oo__ifp->deleteobject==1) oo__ifp->deleteobject= 0;
-
- // read one osm object
- if(oo__ifp->format==0) { // o5m
- // read object id
- bufp++;
- l= pbf_uint32(&bufp);
- read_bufp= bufe= bufp+l;
- id= oo__ifp->o5id+= pbf_sint64(&bufp);
- // read author
- hisver= pbf_uint32(&bufp);
- if(hisver!=0) { // author information available
- if(!global_dropversion) complete|= 8;
- histime= oo__ifp->o5histime+= pbf_sint64(&bufp);
- if(histime!=0) {
- hiscset= oo__ifp->o5hiscset+= pbf_sint32(&bufp);
- str_read(&bufp,&sp,&hisuser);
- hisuid= pbf_uint64((byte**)&sp);
- if(!global_dropauthor) complete|= 16+32+64+128;
- }
- } // end author information available
- if(bufp>=bufe)
- // just the id and author, i.e. this is a delete request
- oo__ifp->deleteobject= 1;
- else { // not a delete request
- oo__ifp->deleteobject= 0;
- // read coordinates (for nodes only)
- if(otype==0) { // node
- // read node body
- lon= oo__ifp->o5lon+= pbf_sint32(&bufp);
- lat= oo__ifp->o5lat+= pbf_sint32(&bufp);
- } // end node
- complete|= 1+2+4;
- // read noderefs (for ways only)
- if(otype==1) { // way
- l= pbf_uint32(&bufp);
- bp= bufp+l;
- if(bp>bufe) bp= bufe; // (format error)
- while(bufp<bp && refide<refidee)
- *refide++= oo__ifp->o5rid[0]+= pbf_sint64(&bufp);
- } // end way
- // read refs (for relations only)
- else if(otype==2) { // relation
- int64_t ri; // temporary, refid
- int rt; // temporary, reftype
- char* rr; // temporary, refrole
-
- l= pbf_uint32(&bufp);
- bp= bufp+l;
- if(bp>bufe) bp= bufe; // (format error)
- while(bufp<bp && refide<refidee) {
- ri= pbf_sint64(&bufp);
- str_read(&bufp,&rr,NULL);
- *reftypee++= rt= (*rr++ -'0')%3; // (suppress errors)
- *refide++= oo__ifp->o5rid[rt]+= ri;
- *refrolee++= rr;
- }
- } // end relation
- // read node key/val pairs
- keye= key; vale= val;
- while(bufp<bufe && keye<keyee)
- str_read(&bufp,keye++,vale++);
- } // end not a delete request
- } // end o5m
- else { // osm xml
- int64_t ri; // temporary, refid, rcomplete flag 1
- int rt; // temporary, reftype, rcomplete flag 2
- char* rr; // temporary, refrole, rcomplete flag 3
- int rcomplete;
- char* k; // temporary, key
- char* v; // temporary, val
- int r;
-
- read_bufp++; // jump over '<'
- oo__xmlheadtag= true; // (default)
- rcomplete= 0;
- k= v= NULL;
- for(;;) { // until break;
- r= oo__xmltag();
- if(oo__xmlheadtag) { // still in object header
- if(oo__xmlkey[0]=='i') { // id
- id= oo__strtosint64(oo__xmlval); complete|= 1; }
- else if(oo__xmlkey[0]=='l') { // letter l
- if(oo__xmlkey[1]=='o') { // lon
- lon= oo__strtodeg(oo__xmlval); complete|= 2; }
- else if(oo__xmlkey[1]=='a') { // lon
- lat= oo__strtodeg(oo__xmlval); complete|= 4; }
- } // end letter l
- else if(oo__xmlkey[0]=='v' && oo__xmlkey[1]=='i') { // visible
- if(oo__xmlval[0]=='f' || oo__xmlval[0]=='n')
- if(oo__ifp->deleteobject==0)
- oo__ifp->deleteobject= 1;
- } // end visible
- else if(oo__xmlkey[0]=='a' && oo__xmlkey[1]=='c') { // action
- if(oo__xmlval[0]=='d' && oo__xmlval[1]=='e')
- if(oo__ifp->deleteobject==0)
- oo__ifp->deleteobject= 1;
- } // end action
- else if(!global_dropversion) { // version not to drop
- if(oo__xmlkey[0]=='v' && oo__xmlkey[1]=='e') { // hisver
- hisver= oo__strtouint32(oo__xmlval); complete|= 8; }
- if(!global_dropauthor) { // author not to drop
- if(oo__xmlkey[0]=='t') { // histime
- histime= oo__strtimetosint64(oo__xmlval); complete|= 16; }
- else if(oo__xmlkey[0]=='c') { // hiscset
- hiscset= oo__strtosint64(oo__xmlval); complete|= 32; }
- else if(oo__xmlkey[0]=='u' && oo__xmlkey[1]=='i') {// hisuid
- hisuid= oo__strtouint32(oo__xmlval); complete|= 64; }
- else if(oo__xmlkey[0]=='u' && oo__xmlkey[1]=='s') {//hisuser
- hisuser= oo__xmlval; complete|= 128; }
- } // end author not to drop
- } // end version not to drop
- } // end still in object header
- else { // in object body
- if(oo__xmlkey[0]==0) { // xml tag completed
- if(rcomplete>=3) { // at least refid and reftype
- *refide++= ri;
- *reftypee++= rt;
- if(rcomplete<4) // refrole is missing
- rr= ""; // assume an empty string as refrole
- *refrolee++= rr;
- } // end at least refid and reftype
- rcomplete= 0;
- if(v!=NULL && k!=NULL) { // key/val available
- *keye++= k; *vale++= v;
- k= v= NULL;
- } // end key/val available
- } // end xml tag completed
- else { // inside xml tag
- if(otype!=0 && refide<refidee) {
- // not a node AND still space in refid array
- if(oo__xmlkey[0]=='r' && oo__xmlkey[1]=='e') { // refid
- ri= oo__strtosint64(oo__xmlval); rcomplete|= 1;
- if(otype==1) {rt= 0; rcomplete|= 2; } }
- else if(oo__xmlkey[0]=='t' && oo__xmlkey[1]=='y') {
- // reftype
- rt= oo__xmlval[0]=='n'? 0: oo__xmlval[0]=='w'? 1: 2;
- rcomplete|= 2; }
- else if(oo__xmlkey[0]=='r' && oo__xmlkey[1]=='o') {
- // refrole
- rr= oo__xmlval; rcomplete|= 4; }
- } // end still space in refid array
- if(keye<keyee) { // still space in key/val array
- if(oo__xmlkey[0]=='k') // key
- k= oo__xmlval;
- else if(oo__xmlkey[0]=='v') // val
- v= oo__xmlval;
- } // end still space in key/val array
- } // end inside xml tag
- } // end in object body
- if(r)
- break;
- } // end until break;
- } // end xml
-
- // care about possible array overflows
- if(refide>refidee)
- WARNv("way %"PRIi64" has too many noderefs.",id)
- if(refide>refidee)
- WARNv("relation %"PRIi64" has too many refs.",id)
- if(keye>=keyee)
- WARNv("%s %"PRIi64" has too many key/val pairs.",
- ONAME(otype),id)
-
- // check sequence, if in right filterstage
- if(filterstage==4) {
- if(otype<=oo_sequencetype &&
- (otype<oo_sequencetype || id<oo_sequenceid ||
- (oo_ifn>1 && id<=oo_sequenceid)))
- WARNv("wrong sequence at %s %"PRIi64,ONAME(otype),id)
- oo_sequencetype= otype; oo_sequenceid= id;
- }
-
- // (process object deletion - moved downward)
-
- // write interrelation dependencies into temporary file
- if(filterstage==1 && otype==2) { // in stage 1 AND have relation
- int64_t ri; // temporary, refid
- int rt; // temporary, reftype
- bool idwritten;
-
- idwritten= false;
- refidp= refid; reftypep= reftype;
- while(refidp<refide) { // for every referenced object
- ri= *refidp;
- rt= *reftypep;
- if(rt==2) { // referenced object is a relation
- if(!idwritten) { // did not yet write our relation's id
- rr_rel(id); // write it now
- idwritten= true;
- }
- rr_ref(ri);
- }
- refidp++; reftypep++;
- } // end for every referenced object
- } // in stage 1
-
- // prepare author information for filtering:
- // simply add them as key/val tags;
- keyf= keye; valf= vale;
- if(fil_filterheader) {
- static char ids[30],uids[30];
-
- *keyf++= "@id";
- *valf++= int64toa(id,ids);
- *keyf++= "@uid";
- *valf++= int32toa(hisuid,uids);
- *keyf++= "@user";
- *valf++= hisuser;
- }
-
- /* care about filtering, dependent on the filterstage */ {
- bool flag; // flag for this object;
- bool keep; // keep this object;
-
- keep= flag= hash_geti(otype,id);
- if(!keep && (filterstage!=4 || otype==0 || !global_recursive)) {
- // object not already to keep AND
- // (in stage !=4, or if object is a node)
- if(!fil_active[otype])
- keep= true;
- else // filter 'keep object' shall be applied
- keep= fil_check0(otype,key,keyf,val,valf);
- } // in stage !=3, or if object is a way
-
- // care about 'drop object' filter
- if(keep || (filterstage==1 && otype==2)) {
- if(fil_active[3+otype]) {
- // filter 'drop object' shall be applied
- if(fil_check1(otype,key,keyf,val,valf))
- keep= false;
- } // filter 'drop object' shall be applied
- }
-
- if(!keep) // object is to dispose
- continue; // we are finished here
- if(!flag) // flag for this object is not set yet
- hash_seti(otype,id); // memorize that this object will be kept
-
- // care about objects which depend on this object
- if(filterstage<4) { // in stage 1, 2 or 3
- if(filterstage==2 && otype==2) {
- // in stage 2 AND have relation
- // 2: parse relations and update hash flags
- // of dependent objects;
- refidp= refid; reftypep= reftype;
- while(refidp<refide) { // for every referenced object
- hash_seti(*reftypep++,*refidp++); // mark referenced node
- } // end for every referenced object
- } // in stage 2 AND have way
- else if(filterstage==3 && otype==1) {
- // in stage 3 AND have way
- // 3: parse ways and update hash flags of dependent nodes;
- refidp= refid;
- while(refidp<refide) { // for every referenced node
- hash_seti(0,*refidp++); // mark referenced node
- } // end for every referenced node
- } // in stage 3 AND have relation
- continue; // we are finished here
- } // in stage 1, 2 or 3
- // here: 4: process the whole file;
- } // care about filtering, dependent on the filterstage
-
- // process object deletion
- if(oo__ifp->deleteobject!=0) { // object is to delete
- if((otype==0 && !global_dropnodes) ||
- (otype==1 && !global_dropways) ||
- (otype==2 && !global_droprelations))
- // section is not to drop anyway
- if(global_outo5c || global_outosc || global_outosh)
- // write o5c, osc or osh file
- wo_delete(otype,id,hisver,histime,hiscset,hisuid,hisuser);
- // write delete request
- continue; // end processing for this object
- } // end object is to delete
-
- // write the object
- if(otype==0) { // write node
- if(!global_dropnodes) { // not to drop
- wo_node(id,
- hisver,histime,hiscset,hisuid,hisuser,lon,lat);
- keyp= key; valp= val;
- while(keyp<keye) { // for all key/val pairs of this object
- if(!fil_activeo[otype] || fil_check2(otype,*keyp,*valp))
- wo_keyval(*keyp,*valp);
- keyp++; valp++;
- }
- } // end not to drop
- } // write node
- else if(otype==1) { // write way
- if(!global_dropways) { // not ways to drop
- wo_way(id,hisver,histime,hiscset,hisuid,hisuser);
- refidp= refid;
- while(refidp<refide) // for every referenced node
- wo_noderef(*refidp++);
- keyp= key; valp= val;
- while(keyp<keye) { // for all key/val pairs of this object
- if(!fil_activeo[otype] || fil_check2(otype,*keyp,*valp))
- wo_keyval(*keyp,*valp);
- keyp++; valp++;
- }
- } // end not ways to drop
- } // write way
- else if(otype==2) { // write relation
- if(!global_droprelations) { // not relations to drop
- wo_relation(id,hisver,histime,hiscset,hisuid,hisuser);
- refidp= refid; reftypep= reftype; refrolep= refrole;
- while(refidp<refide) // for every referenced object
- wo_ref(*refidp++,*reftypep++,*refrolep++);
- keyp= key; valp= val;
- while(keyp<keye) { // for all key/val pairs of this object
- if(!fil_activeo[otype] || fil_check2(otype,*keyp,*valp))
- wo_keyval(*keyp,*valp);
- keyp++; valp++;
- }
- } // end not relations to drop
- } // write relation
- } // end read all input files
- if(writeheader)
- wo_start(wformat,oo__bbvalid && oo_ifn==1,
- oo__bbx1,oo__bby1,oo__bbx2,oo__bby2);
- wo_end();
- return 0;
- } // end oo_main()
-
-//------------------------------------------------------------
-// end Module oo_ osm to osm module
-//------------------------------------------------------------
-
-
-
-#if !__WIN32__
-void sigcatcher(int sig) {
- fprintf(stderr,"osmfilter: output has been terminated.\n");
- exit(1);
- } // end sigchatcher()
-#endif
-
-int main(int argc,const char** argv) {
- // main program;
- // for the meaning of the calling line parameters please look at the
- // contents of helptext[];
- static char outputfilename[400]= ""; // standard output file name
- // =="": standard output 'stdout'
- int h_n,h_w,h_r; // user-suggested hash size in MiB, for
- // hash tables of nodes, ways, and relations;
- int r,l;
- const char* a;
- static FILE* parafile= NULL;
- static char* aa= NULL; // buffer for parameter file line
- char* ap; // pointer in aa[]
- int aamax; // maximum length of string to read
- #define main__aaM 1000000
-
- #if !__WIN32__
- /* care about signal handler */ {
- static struct sigaction siga;
-
- siga.sa_handler= sigcatcher;
- sigemptyset(&siga.sa_mask);
- siga.sa_flags= 0;
- sigaction(SIGPIPE,&siga,NULL);
- }
- #endif
-
- // initializations
- h_n= h_w= h_r= 0;
- fil_ini();
- #if __WIN32__
- setmode(fileno(stdout),O_BINARY);
- setmode(fileno(stdin),O_BINARY);
- #endif
-
- // read command line parameters
- if(argc<=1) { // no command line parameters given
- fprintf(stderr,"osmfilter "VERSION"\n"
- "Filters .o5m, .o5c, .osm, .osc and .osh files.\n"
- "Use command line option -h to get a parameter overview,\n"
- "or --help to get detailed help.\n");
-return 0; // end the program, because without having parameters
- // we do not know what to do;
- }
- while(parafile!=NULL || argc>0) {
- // for every parameter in command line
- if(parafile!=NULL) do {
- // there are parameters waiting in a parameter file
- ap= aa;
- for(;;) {
- aamax= main__aaM-1-(ap-aa);
- if(fgets(ap,aamax,parafile)==NULL) {
- if(ap>aa) {
- if(ap>aa && ap[-1]==' ')
- *--ap= 0; // cut one trailing space
- break;
- }
- goto parafileend;
- }
- if(strzcmp(ap,"// ")==0)
- continue;
- if(ap>aa && (*ap=='\r' || *ap=='\n' || *ap==0)) {
- // end of this parameter
- while(ap>aa && (ap[-1]=='\r' || ap[-1]=='\n')) *--ap= 0;
- // eliminate trailing NL
- if(ap>aa && ap[-1]==' ')
- *--ap= 0; // cut one trailing space
- break;
- }
- ap= strchr(ap,0); // find end of string
- while(ap>aa && (ap[-1]=='\r' || ap[-1]=='\n'))
- *--ap= 0; // cut newline chars
- *ap++= ' '; *ap= 0; // add a space
- }
- a= aa;
- while(*a!=0 && strchr(" \t\r\n",*a)!=NULL) a++;
- if(*a!=0)
- break;
- parafileend:
- fclose(parafile); parafile= NULL;
- free(aa); aa= NULL;
- } while(false);
- if(parafile==NULL) {
- if(--argc<=0)
- break;
- argv++; // switch to next parameter; as the first one is just
- // the program name, we must do this previous reading the
- // first 'real' parameter;
- a= argv[0];
- }
- if((l= strzlcmp(a,"--parameter-file="))>0 && a[l]!=0) {
- // parameter file
- parafile= fopen(a+l,"r");
- if(parafile==NULL) {
- PERRv("Cannot open parameter file: %.80s",a+l)
- perror("osmfilter");
-return 1;
- }
- aa= (char*)malloc(main__aaM);
- if(aa==NULL) {
- PERR("Cannot get memory for parameter file.")
- fclose(parafile); parafile= NULL;
-return 1;
- }
- aa[0]= 0;
- continue; // take next parameter
- }
- if(loglevel>0) // verbose mode
- fprintf(stderr,"osmfilter Parameter: %.2000s\n",a);
- if(strcmp(a,"-h")==0) { // user wants parameter overview
- fprintf(stdout,"%s",shorthelptext); // print brief help text
- // (took "%s", to prevent oversensitive compiler reactions)
-return 0;
- }
- if(strcmp(a,"-help")==0 || strcmp(a,"--help")==0) {
- // user wants help text
- fprintf(stdout,"%s",helptext); // print help text
- // (took "%s", to prevent oversensitive compiler reactions)
-return 0;
- }
- if(strzcmp(a,"--drop-his")==0) {
- // (deprecated)
- PINFO("Option --drop-history is deprecated. Using --drop-author.");
- global_dropauthor= true;
- continue; // take next parameter
- }
- if(strzcmp(a,"--drop-aut")==0) {
- // user does not want author information in standard output
- global_dropauthor= true;
- continue; // take next parameter
- }
- if(strzcmp(argv[0],"--drop-ver")==0) {
- // user does not want version number in standard output
- global_dropauthor= true;
- global_dropversion= true;
- continue; // take next parameter
- }
- if(strzcmp(a,"--fake-his")==0) {
- // (deprecated)
- PINFO("Option --fake-history is deprecated. Using --fake-author.");
- global_fakeauthor= true;
- continue; // take next parameter
- }
- if(strzcmp(a,"--fake-aut")==0) {
- // user wants faked author information
- global_fakeauthor= true;
- continue; // take next parameter
- }
- if(strzcmp(a,"--fake-ver")==0) {
- // user wants just a faked version number as meta data
- global_fakeversion= true;
- continue; // take next parameter
- }
- if(strzcmp(a,"--fake-lonlat")==0) {
- // user wants just faked longitude and latitude
- // in case of delete actions (.osc files);
- global_fakelonlat= true;
- continue; // take next parameter
- }
- if(strcmp(a,"--drop-nodes")==0) {
- // user does not want nodes section in standard output
- global_dropnodes= true;
- continue; // take next parameter
- }
- if(strcmp(a,"--drop-ways")==0) {
- // user does not want ways section in standard output
- global_dropways= true;
- continue; // take next parameter
- }
- if(strcmp(a,"--drop-relations")==0) {
- // user does not want relations section in standard output
- global_droprelations= true;
- continue; // take next parameter
- }
- if(strzcmp(a,"--ignore-dep")==0) {
- // user does interobject dependencies to be ignored
- global_ignoredependencies= true;
- continue; // take next parameter
- }
- if(strcmp(argv[0],"--in-josm")==0) {
- // deprecated;
- // this option is still accepted for compatibility reasons;
- continue; // take next parameter
- }
- if(strcmp(a,"--out-o5m")==0 ||
- strcmp(argv[0],"-5")==0) {
- // user wants output in o5m format
- global_outo5m= true;
- continue; // take next parameter
- }
- if(strcmp(a,"--out-osm")==0) {
- // user wants output in osm format
- global_outosm= true;
- continue; // take next parameter
- }
- if(strcmp(a,"--out-o5c")==0 ||
- strcmp(a,"-5c")==0) {
- // user wants output in o5c format
- global_outo5m= global_outo5c= true;
- continue; // take next parameter
- }
- if(strcmp(a,"--out-osm")==0) {
- // user wants output in osm format
- // this is default anyway, hence ignore this parameter
- continue; // take next parameter
- }
- if(strcmp(a,"--out-osc")==0) {
- // user wants output in osc format
- global_outosc= true;
- continue; // take next parameter
- }
- if(strcmp(argv[0],"--out-osh")==0) {
- // user wants output in osc format
- global_outosh= true;
- continue; // take next parameter
- }
- if((l= strzlcmp(a,"--out-key"))>0 ||
- (l= strzlcmp(a,"--out-count"))>0) {
- // user wants a list of keys or vals as output
- static char k[300]= {0,0,0};
- int len;
-
- global_outkey= k; // we shall create a list of keys
- if(a[l]=='=' && a[l+1]!=0) {
- // we shall create list of vals to a certain key
- global_outkey= a+l+1;
- len= strlen(global_outkey);
- if(len>=sizeof(k)-2) len= sizeof(k)-3;
- fil_cpy(k,global_outkey,len,2);
- global_outkey= k;
- }
- if(a[6]=='c') global_outsort= true;
- continue; // take next parameter
- }
- if(strzcmp(argv[0],"--emulate-pbf2")==0) {
- // emulate pbf2osm compatible output
- global_emulatepbf2osm= true;
- continue; // take next parameter
- }
- if(strzcmp(argv[0],"--emulate-osmo")==0) {
- // emulate Osmosis compatible output
- global_emulateosmosis= true;
- continue; // take next parameter
- }
- if(strzcmp(argv[0],"--emulate-osmi")==0) {
- // emulate Osmium compatible output
- global_emulateosmium= true;
- continue; // take next parameter
- }
- if(strzcmp(a,"-t=")==0 && a[3]!=0) {
- // user-defined prefix for names of temorary files
- strmcpy(global_tempfilename,a+3,sizeof(global_tempfilename)-30);
- continue; // take next parameter
- }
- if(strzcmp(a,"-o=")==0 && a[3]!=0) {
- // reroute standard output to a file
- strMcpy(outputfilename,a+3);
- continue; // take next parameter
- }
- if((strcmp(a,"-v")==0 || strcmp(a,"--verbose")==0 ||
- strzcmp(a,"-v=")==0 || strzcmp(a,"--verbose=")==0) &&
- loglevel==0) { // test mode - if not given already
- char* sp;
-
- sp= strchr(a,'=');
- if(sp!=NULL) loglevel= sp[1]-'0'; else loglevel= 1;
- if(loglevel<1) loglevel= 1;
- if(loglevel>MAXLOGLEVEL) loglevel= MAXLOGLEVEL;
- if(a[1]=='-') { // must be "--verbose" and not "-v"
- if(loglevel==1)
- fprintf(stderr,"osmfilter: Verbose mode.\n");
- else
- fprintf(stderr,"osmfilter: Verbose mode %i.\n",loglevel);
- }
- continue; // take next parameter
- }
- if(strcmp(a,"-t")==0) {
- // test mode
- write_testmode= true;
- fprintf(stderr,"osmfilter: Entering test mode.\n");
- continue; // take next parameter
- }
- if(((l= strzlcmp(a,"--hash-memory="))>0 ||
- (l= strzlcmp(a,"-h="))>0) && isdig(a[l])) {
- // "-h=...": user wants a specific hash size;
- const char* p;
-
- p= a+l; // jump over "-h="
- h_n= h_w= h_r= 0;
- // read the up to three values for hash tables' size;
- // format examples: "-h=200-20-10", "-h=1200"
- while(isdig(*p)) { h_n= h_n*10+*p-'0'; p++; }
- if(*p!=0) { p++; while(isdig(*p)) { h_w= h_w*10+*p-'0'; p++; } }
- if(*p!=0) { p++; while(isdig(*p)) { h_r= h_r*10+*p-'0'; p++; } }
- continue; // take next parameter
- }
- #define F(t) fil_parse(t,a+l);
- #define D(p,f) if((l= strzlcmp(a,#p))>0) { f continue; }
- D(--keep=,F(0)F(1)F(2))
- D(--keep-nodes=,F(0))
- D(--keep-ways=,F(1))
- D(--keep-relations=,F(2))
- D(--keep-nodes-ways=,F(0)F(1))
- D(--keep-nodes-relations=,F(0)F(2))
- D(--keep-ways-relations=,F(1)F(2))
- D(--drop=,F(3)F(4)F(5))
- D(--drop-nodes=,F(3))
- D(--drop-ways=,F(4))
- D(--drop-relations=,F(5))
- D(--drop-nodes-ways=,F(3)F(4))
- D(--drop-nodes-relations=,F(3)F(5))
- D(--drop-ways-relations=,F(4)F(5))
- D(--keep-tags=,F(6)F(7)F(8))
- D(--keep-node-tags=,F(6))
- D(--keep-way-tags=,F(7))
- D(--keep-relation-tags=,F(8))
- D(--keep-node-way-tags=,F(6)F(7))
- D(--keep-node-relation-tags=,F(6)F(8))
- D(--keep-way-relation-tags=,F(7)F(8))
- D(--drop-tags=,F(9)F(10)F(11))
- D(--drop-node-tags=,F(9))
- D(--drop-way-tags=,F(10))
- D(--drop-relation-tags=,F(11))
- D(--drop-node-way-tags=,F(9)F(10))
- D(--drop-node-relation-tags=,F(9)F(11))
- D(--drop-way-relation-tags=,F(10)F(11))
- #undef D
- #undef F
- if(a[0]=='-') {
- PERRv("unrecognized option: %.80s",a)
-return 1;
- }
- // here: parameter must be a file name
- if(oo_open(a)) // file cannot be read
-return 1;
- } // end for every parameter in command line
- // process parameters
- if(oo_ifn==0) { // no input files given
- PERR("please specify the input file or try: osmfilter -h")
-return 0; // end the program, because without having input files
- // we do not know what to do;
- } // for every parameter in command line
-
- // check plausibility of filter strings
- if(fil_plausi()!=0)
-return 2;
-
- // initialize hash module
- if(outputfilename[0]!=0 && !global_outo5m &&
- !global_outo5c && !global_outosm && !global_outosc &&
- !global_outosh) {
- // have output file name AND output format not defined
- // try to determine the output format by evaluating
- // the file name extension
- if(strycmp(outputfilename,".o5m")==0) global_outo5m= true;
- else if(strycmp(outputfilename,".o5c")==0)
- global_outo5m= global_outo5c= true;
- else if(strycmp(outputfilename,".osm")==0) global_outosm= true;
- else if(strycmp(outputfilename,".osc")==0) global_outosc= true;
- else if(strycmp(outputfilename,".osh")==0) global_outosh= true;
- if(strycmp(outputfilename,".pbf")==0) {
- PERR(".pbf format is not supported. Please use .o5m.")
-return 3;
- }
- }
- if(write_open(outputfilename[0]!=0? outputfilename: NULL)!=0)
-return 3;
- if(global_ignoredependencies)
- // user does interobject dependencies to be ignored
- global_recursive= false;
- if(global_recursive) {
- int r;
-
- if(h_n==0) h_n= 1000; // use standard value if not set otherwise
- if(h_w==0 && h_r==0) {
- // user chose simple form for hash memory value
- // take the one given value as reference and determine the
- // three values using these factors: 90%, 9%, 1%
- h_w= h_n/10; h_r= h_n/100;
- h_n-= h_w; h_w-= h_r; }
- r= hash_ini(h_n,h_w,h_r); // initialize hash table
- if(r==1)
- fprintf(stderr,"osmfilter: Hash size had to be reduced.\n");
- else if(r==2)
- fprintf(stderr,"osmfilter: Not enough memory for hash.\n");
- } // end user wants borders
-
- // do further initializations
- if(global_outo5m) { // .o5m format is needed as output
- if(o5_ini()!=0) {
- fprintf(stderr,"osmfilter: Not enough memory for .o5m buffer.\n");
-return 5;
- }
- } // end .o5m format is needed as output
- sprintf(strchr(global_tempfilename,0),".%"PRIi64,(int64_t)getpid());
- if(loglevel>=2)
- fprintf(stderr,"Tempfiles: %s.*\n",global_tempfilename);
-
- // do the work
- r= oo_main();
- if(loglevel>=2) { // verbose
- if(read_bufp!=NULL && read_bufp<read_bufe)
- fprintf(stderr,"osmfilter: Next bytes to parse:\n"
- " %.02X %.02X %.02X %.02X %.02X %.02X %.02X %.02X\n",
- read_bufp[0],read_bufp[1],read_bufp[2],read_bufp[3],
- read_bufp[4],read_bufp[5],read_bufp[6],read_bufp[7]);
- } // verbose
- write_flush();
- if(hash_queryerror()!=0)
- r= 91;
- if(write_error) {
- r= 92;
- PERR("write error.")
- }
- if(loglevel>0) { // verbose mode
- if(oo_sequenceid!=INT64_C(-0x7fffffffffffffff))
- fprintf(stderr,"osmfilter: Last processed: %s %"PRIu64".\n",
- ONAME(oo_sequencetype),oo_sequenceid);
- if(r!=0)
- fprintf(stderr,"osmfilter Exit: %i\n",r);
- } // verbose mode
- return r;
- } // end main()
-
diff --git a/tools/osmctools/osmupdate.c b/tools/osmctools/osmupdate.c
deleted file mode 100644
index eef6de266c..0000000000
--- a/tools/osmctools/osmupdate.c
+++ /dev/null
@@ -1,1650 +0,0 @@
-// osmupdate 2015-04-15 10:00
-#define VERSION "0.4.1"
-//
-// compile this file:
-// gcc osmupdate.c -o osmupdate
-//
-// (c) 2011..2015 Markus Weber, Nuernberg
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Affero General Public License
-// version 3 as published by the Free Software Foundation.
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-// You should have received a copy of this license along
-// with this program; if not, see http://www.gnu.org/licenses/.
-//
-// Other licenses are available on request; please ask the author.
-
-#define MAXLOGLEVEL 2
-const char* helptext=
-"\nosmupdate " VERSION "\n"
-"\n"
-"This program cares about updating an .osm, .o5m or .pbf file. It\n"
-"will download and apply OSM Change files (.osc) from the servers of\n"
-"\"planet.openstreetmap.org\".\n"
-"It also can assemble a new .osc or .o5c file which can be used to\n"
-"update your OSM data file at a later time.\n"
-"\n"
-"Prequesites\n"
-"\n"
-"To run this program, please download and install two other programs\n"
-"first: \"osmconvert\" and \"wget\".\n"
-"\n"
-"Usage\n"
-"\n"
-"Two command line arguments are mandatory: the name of the old and the\n"
-"name of the new OSM data file. If the old data file does not have a\n"
-"file timestamp, you may want to specify this timestamp manually on\n"
-"the command line. If you do not, the program will try to determine\n"
-"the timestamp by examining the whole old data file.\n"
-"Instead of the second parameter, you alternatively may specify the\n"
-"name of a change file (.osc or .o5c). In this case, you also may\n"
-"replace the name of the old OSM data file by a timestamp.\n"
-"Command line arguments which are not recognized by osmupdate will be\n"
-"passed to osmconvert. Use this opportunity to supply a bounding box\n"
-"or a bounding polygon if you are going to update a regional change\n"
-"file. You also may exclude unneeded meta data from your file by\n"
-"specifying this osmconvert option: --drop-author\n"
-"\n"
-"Usage Examples\n"
-"\n"
-" ./osmupdate old_file.o5m new_file.o5m\n"
-" ./osmupdate old_file.pbf new_file.pbf\n"
-" ./osmupdate old_file.osm new_file.osm\n"
-" The old OSM data will be updated and written as new_file.o5m\n"
-" or new_file.o5m. For safety reasons osmupdate will not delete\n"
-" the old file. If you do not need it as backup file, please\n"
-" delete it by yourself.\n"
-"\n"
-" ./osmupdate old_file.osm 2011-07-15T23:30:00Z new_file.osm\n"
-" ./osmupdate old_file.osm NOW-86400 new_file.osm\n"
-" If your old OSM data file does not contain a file timestamp,\n"
-" or you do not want to rely on this timestamp, it can be\n"
-" specified manually. Relative times are in seconds to NOW.\n"
-"\n"
-" ./osmupdate old_file.o5m change_file.o5c\n"
-" ./osmupdate old_file.osm change_file.osc\n"
-" ./osmupdate 2011-07-15T23:30:00Z change_file.o5c\n"
-" ./osmupdate 2011-07-15T23:30:00Z change_file.osc.gz\n"
-" ./osmupdate NOW-3600 change_file.osc.gz\n"
-" Here, the old OSM data file is not updated directly. An OSM\n"
-" changefile is written instead. This changefile can be used to\n"
-" update the OSM data file afterwards.\n"
-" You will have recognized the extension .gz in the last\n"
-" example. In this case, the OSM Change file will be written\n"
-" with gzip compression. To accomplish this, you need to have\n"
-" the program gzip installed on your system.\n"
-"\n"
-" ./osmupdate london_old.o5m london_new.o5m -B=london.poly\n"
-" The OSM data file london_old.o5m will be updated. Hence the\n"
-" downloaded OSM changefiles contain not only London, but the\n"
-" whole planet, a lot of unneeded data will be added to this\n"
-" regional file. The -B= argument will clip these superfluous\n"
-" data.\n"
-"\n"
-"The program osmupdate recognizes a few command line options:\n"
-"\n"
-"--max-days=UPDATE_RANGE\n"
-" By default, the maximum time range for to assemble a\n"
-" cumulated changefile is 250 days. You can change this by\n"
-" giving a different maximum number of days, for example 300.\n"
-" If you do, please ensure that there are daily change files\n"
-" available for such a wide range of time.\n"
-"\n"
-"--minute\n"
-"--hour\n"
-"--day\n"
-"--sporadic\n"
-" By default, osmupdate uses a combination of minutely, hourly\n"
-" and daily changefiles. If you want to limit these changefile\n"
-" categories, use one or two of these options and choose that\n"
-" category/ies you want to be used.\n"
-" The option --sporadic allows processing changefile sources\n"
-" which do not have the usual \"minute\", \"hour\" and \"day\"\n"
-" subdirectories.\n"
-"\n"
-"--max-merge=COUNT\n"
-" The subprogram osmconvert is able to merge more than two\n"
-" changefiles in one run. This ability increases merging speed.\n"
-" Unfortunately, every changefile consumes about 200 MB of main\n"
-" memory while being processed. For this reason, the number of\n"
-" parallely processable changefiles is limited.\n"
-" Use this commandline argument to determine the maximum number\n"
-" of parallely processed changefiles. The default value is 7.\n"
-"\n"
-"-t=TEMPPATH\n"
-"--tempfiles=TEMPPATH\n"
-" On order to cache changefiles, osmupdate needs a separate\n"
-" directory. This parameter defines the name of this directory,\n"
-" including the prefix of the tempfiles' names.\n"
-" The default value is \"osmupdate_temp/temp\".\n"
-"\n"
-"--keep-tempfiles\n"
-" Use this option if you want to keep local copies of every\n"
-" downloaded file. This is strongly recommended if you are\n"
-" going to assemble different changefiles which overlap in\n"
-" time ranges. Your data traffic will be minimized.\n"
-" Do not invoke this option if you are going to use different\n"
-" change file sources (option --base-url). This would cause\n"
-" severe data corruption.\n"
-"\n"
-"--compression-level=LEVEL\n"
-" Define level for gzip compression. Values between 1 (low\n"
-" compression, but fast) and 9 (high compression, but slow).\n"
-"\n"
-"--base-url=BASE_URL\n"
-" To accelerate downloads or to get regional file updates you\n"
-" may specify an alternative download location. Please enter\n"
-" its URL, or simply the word \"mirror\" if you want to use\n"
-" gwdg's planet server.\n"
-"\n"
-"--base-url-suffix=BASE_URL_SUFFIX\n"
-" To use old planet URLs, you may need to add the suffix\n"
-" \"-replicate\" because it was custom to have this word in the\n"
-" URL, right after the period identifier \"day\" etc.\n"
-"\n"
-"-v\n"
-"--verbose\n"
-" With activated \'verbose\' mode, some statistical data and\n"
-" diagnosis data will be displayed.\n"
-" If -v resp. --verbose is the first parameter in the line,\n"
-" osmupdate will display all input parameters.\n"
-"\n"
-"This program is for experimental use. Expect malfunctions and data\n"
-"loss. Do not use the program in productive or commercial systems.\n"
-"\n"
-"There is NO WARRANTY, to the extent permitted by law.\n"
-"Please send any bug reports to markus.weber@gmx.com\n\n";
-
-#define _FILE_OFFSET_BITS 64
-#include <zlib.h>
-#include <inttypes.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-#include <time.h>
-#include <ctype.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <sys/stat.h>
-
-typedef enum {false= 0,true= 1} bool;
-typedef uint8_t byte;
-typedef unsigned int uint;
-#define isdig(x) isdigit((unsigned char)(x))
-static int loglevel= 0; // logging to stderr;
- // 0: no logging; 1: small logging; 2: normal logging;
- // 3: extended logging;
-#define DP(f) fprintf(stderr,"Debug: " #f "\n");
-#define DPv(f,...) fprintf(stderr,"Debug: " #f "\n",__VA_ARGS__);
-#define DPM(f,p,m) { byte* pp; int i,mm; static int msgn= 3; \
- if(--msgn>=0) { fprintf(stderr,"Debug memory: " #f); \
- pp= (byte*)(p); mm= (m); if(pp==NULL) fprintf(stderr,"\n (null)"); \
- else for(i= 0; i<mm; i++) { \
- if((i%16)==0) fprintf(stderr,"\n "); \
- fprintf(stderr," %02x",*pp++); } \
- fprintf(stderr,"\n"); } }
-#if __WIN32__
- #define NL "\r\n" // use CR/LF as new-line sequence
- #define DIRSEP '\\'
- #define DIRSEPS "\\"
- #define DELFILE "del"
- #define off_t off64_t
- #define lseek lseek64
-#else
- #define NL "\n" // use LF as new-line sequence
- #define DIRSEP '/'
- #define DIRSEPS "/"
- #define DELFILE "rm"
- #define O_BINARY 0
-#endif
-
-
-
-static inline char *strmcpy(char *dest, const char *src, size_t maxlen) {
- // similar to strcpy(), this procedure copies a character string;
- // here, the length is cared about, i.e. the target string will
- // be limited in case it is too long;
- // src[]: source string which is to be copied;
- // maxlen: maximum length of the destination string
- // (including terminator null);
- // return:
- // dest[]: destination string of the copy; this is the
- // function's return value too;
- char* d;
-
- if(maxlen==0)
-return dest;
- d= dest;
- while(--maxlen>0 && *src!=0)
- *d++= *src++;
- *d= 0;
- return dest;
- } // end strmcpy()
-#define strMcpy(d,s) strmcpy((d),(s),sizeof(d))
-
-static inline char *stecpy(char** destp, char* destend,
- const char* src) {
- // same as stppcpy(), but you may define a pointer which the
- // destination will not be allowed to cross, whether or not the
- // string will be completed at that moment;
- // in either case, the destination string will be terminated with 0;
- char* dest;
-
- dest= *destp;
- if(dest>=destend)
-return dest;
- destend--;
- while(*src!=0 && dest<destend)
- *dest++= *src++;
- *dest= 0;
- *destp= dest;
- return dest;
- } // end stecpy()
-
-static inline char *stpesccpy(char *dest, const char *src) {
- // same as C99's stpcpy(), but all quotation marks, apostrophes
- // and backslashes will be escaped (i.e., preceded) by backslashes;
- // for windows, backslashes will not be escaped;
- while(*src!=0) {
- if(*src=='\'' || *src=='\"'
- #if !__WIN32__
- || *src=='\\'
- #endif
- )
- *dest++= '\\';
- *dest++= *src++;
- }
- *dest= 0;
- return dest;
- } // stpesccpy()
-
-static inline char *steesccpy(char **destp,char *destend,
- const char *src) {
- // same as stppesccpy(), but you may define a pointer which the
- // destination will not be allowed to cross, whether or not the
- // string will be completed at that moment;
- // in either case, the destination string will be terminated with 0;
- char* dest;
-
- dest= *destp;
- if(dest>=destend)
-return dest;
- destend-= 2;
- while(*src!=0 && dest<destend) {
- if(*src=='\'' || *src=='\"'
- #if !__WIN32__
- || *src=='\\'
- #endif
- )
- *dest++= '\\';
- *dest++= *src++;
- }
- *dest= 0;
- *destp= dest;
- return dest;
- } // steesccpy()
-
-static inline char *stpmcpy(char *dest, const char *src, size_t maxlen) {
- // similar to strmcpy(), this procedure copies a character string;
- // however, it returns the address of the destination string's
- // terminating zero character;
- // this makes it easier to concatenate strings;
- char* d;
-
- if(maxlen==0)
-return dest;
- d= dest;
- while(--maxlen>0 && *src!=0)
- *d++= *src++;
- *d= 0;
- return d;
- } // end stpmcpy()
-#define stpMcpy(d,s) stpmcpy(d,s,sizeof(d))
-
-static inline int strzcmp(const char* s1,const char* s2) {
- // similar to strcmp(), this procedure compares two character strings;
- // here, the number of characters which are to be compared is limited
- // to the length of the second string;
- // i.e., this procedure can be used to identify a short string s2
- // within a long string s1;
- // s1[]: first string;
- // s2[]: string to compare with the first string;
- // return:
- // 0: both strings are identical; the first string may be longer than
- // the second;
- // -1: the first string is alphabetical smaller than the second;
- // 1: the first string is alphabetical greater than the second;
- while(*s1==*s2 && *s1!=0) { s1++; s2++; }
- if(*s2==0)
- return 0;
- return *(unsigned char*)s1 < *(unsigned char*)s2? -1: 1;
- } // end strzcmp()
-
-static inline int strycmp(const char* s1,const char* s2) {
- // similar to strcmp(), this procedure compares two character strings;
- // here, both strings are end-aligned;
- // not more characters will be compared than are existing in string s2;
- // i.e., this procedure can be used to identify a file name extension;
- const char* s1e;
- int l;
-
- l= strchr(s2,0)-s2;
- s1e= strchr(s1,0);
- if(s1e-s1<l)
-return 1;
- s1= s1e-l;
- while(*s1==*s2 && *s1!=0) { s1++; s2++; }
- if(*s2==0)
- return 0;
- return *(unsigned char*)s1 < *(unsigned char*)s2? -1: 1;
- } // end strycmp()
-
-static inline uint32_t strtouint32(const char* s) {
- // read a number and convert it to an unsigned 32-bit integer;
- // return: number;
- int32_t i;
- byte b;
-
- i= 0;
- for(;;) {
- b= (byte)(*s++ -'0');
- if(b>=10)
- break;
- i= i*10+b;
- }
- return i;
- } // end strtouint32()
-
-static inline int64_t strtosint64(const char* s) {
- // read a number and convert it to a signed 64-bit integer;
- // return: number;
- int sign;
- int64_t i;
- byte b;
-
- if(*s=='-') { s++; sign= -1; } else sign= 1;
- i= 0;
- for(;;) {
- b= (byte)(*s++ -'0');
- if(b>=10)
- break;
- i= i*10+b;
- }
- return i*sign;
- } // end strtosint64()
-
-static inline int64_t strtimetosint64(const char* s) {
- // read a timestamp in OSM format, e.g.: "2010-09-30T19:23:30Z",
- // and convert it to a signed 64-bit integer;
- // also allowed: relative time to NOW, e.g.: "NOW-86400",
- // which means '24 hours ago';
- // return: time as a number (seconds since 1970);
- // ==0: syntax error;
- if(s[0]=='N') { // presumably a relative time to 'now'
- if(s[1]!='O' || s[2]!='W' || (s[3]!='+' && s[3]!='-') ||
- !isdig(s[4])) // wrong syntax
-return 0;
- s+= 3; // jump over "NOW"
- if(*s=='+') s++; // jump over '+', if any
-return time(NULL)+strtosint64(s);
- } // presumably a relative time to 'now'
- if((s[0]!='1' && s[0]!='2') ||
- !isdig(s[1]) || !isdig(s[2]) || !isdig(s[3]) ||
- s[4]!='-' || !isdig(s[5]) || !isdig(s[6]) ||
- s[7]!='-' || !isdig(s[8]) || !isdig(s[9]) ||
- s[10]!='T' || !isdig(s[11]) || !isdig(s[12]) ||
- s[13]!=':' || !isdig(s[14]) || !isdig(s[15]) ||
- s[16]!=':' || !isdig(s[17]) || !isdig(s[18]) ||
- s[19]!='Z') // wrong syntax
-return 0;
- /* regular timestamp */ {
- struct tm tm;
-
- tm.tm_isdst= 0;
- tm.tm_year=
- (s[0]-'0')*1000+(s[1]-'0')*100+(s[2]-'0')*10+(s[3]-'0')-1900;
- tm.tm_mon= (s[5]-'0')*10+s[6]-'0'-1;
- tm.tm_mday= (s[8]-'0')*10+s[9]-'0';
- tm.tm_hour= (s[11]-'0')*10+s[12]-'0';
- tm.tm_min= (s[14]-'0')*10+s[15]-'0';
- tm.tm_sec= (s[17]-'0')*10+s[18]-'0';
- #if __WIN32__
-return mktime(&tm)-timezone;
- #else
-return timegm(&tm);
- #endif
- } // regular timestamp
- } // end strtimetosint64()
-
-static inline void int64tostrtime(uint64_t v,char* sp) {
- // write a timestamp in OSM format, e.g.: "2010-09-30T19:23:30Z",
- // into a string;
- // v: value of the timestamp;
- // sp[21]: destination string;
- time_t vtime;
- struct tm tm;
- int i;
-
- vtime= v;
- #if __WIN32__
- memcpy(&tm,gmtime(&vtime),sizeof(tm));
- #else
- gmtime_r(&vtime,&tm);
- #endif
- i= tm.tm_year+1900;
- sp+= 3; *sp--= i%10+'0';
- i/=10; *sp--= i%10+'0';
- i/=10; *sp--= i%10+'0';
- i/=10; *sp= i%10+'0';
- sp+= 4; *sp++= '-';
- i= tm.tm_mon+1;
- *sp++= i/10+'0'; *sp++= i%10+'0'; *sp++= '-';
- i= tm.tm_mday;
- *sp++= i/10+'0'; *sp++= i%10+'0'; *sp++= 'T';
- i= tm.tm_hour;
- *sp++= i/10+'0'; *sp++= i%10+'0'; *sp++= ':';
- i= tm.tm_min;
- *sp++= i/10+'0'; *sp++= i%10+'0'; *sp++= ':';
- i= tm.tm_sec%60;
- *sp++= i/10+'0'; *sp++= i%10+'0'; *sp++= 'Z'; *sp= 0;
- } // end int64tostrtime()
-
-static inline bool file_exists(const char* file_name) {
- // query if a file exists;
- // file_name[]: name of the file in question;
- // return: the file exists;
- return access(file_name,R_OK)==0;
- } // file_exists()
-
-static inline int64_t file_length(const char* file_name) {
- // retrieve length of a file;
- // file_name[]: file name;
- // return: number of bytes of this file;
- // if the file could not be accessed, the return value is -1;
- struct stat s;
- int r;
-
- r= stat(file_name,&s);
- if(r==0)
-return s.st_size;
- #if !__WIN32__
- if(errno==EOVERFLOW) // size larger than 2^31
-return 0x7fffffff;
- #endif
- return -1;
- } // end file_length()
-
-
-
-//------------------------------------------------------------
-// Module Global global variables for this program
-//------------------------------------------------------------
-
-// to distinguish global variable from local or module global
-// variables, they are preceded by 'global_';
-
-static const char global_osmconvert_program_here_in_dir[]=
- "./osmconvert";
-static const char* global_osmconvert_program=
- global_osmconvert_program_here_in_dir+2;
- // path to osmconvert program
-static char global_tempfile_name[450]= "";
- // prefix of names for temporary files
-static bool global_keep_tempfiles= false;
- // temporary files shall not be deleted at program end
-static char global_osmconvert_arguments[2000]= "";
- // general command line arguments for osmconvert;
-#define max_number_of_changefiles_in_cache 100
-static int global_max_merge= 7;
- // maximum number of parallely processed changefiles
-static const char* global_gzip_parameters= "";
- // parameters for gzip compression
-static char global_base_url[400]=
- "http://planet.openstreetmap.org/replication";
-static char global_base_url_suffix[100]="";
- // for old replication URL, to get "day-replication" instead of "day"
-
-#define PERR(f) \
- fprintf(stderr,"osmupdate Error: " f "\n");
- // print error message
-#define PERRv(f,...) \
- fprintf(stderr,"osmupdate Error: " f "\n",__VA_ARGS__);
- // print error message with value(s)
-#define WARN(f) { static int msgn= 3; if(--msgn>=0) \
- fprintf(stderr,"osmupdate Warning: " f "\n"); }
- // print a warning message, do it maximal 3 times
-#define WARNv(f,...) { static int msgn= 3; if(--msgn>=0) \
- fprintf(stderr,"osmupdate Warning: " f "\n",__VA_ARGS__); }
- // print a warning message with value(s), do it maximal 3 times
-#define PINFO(f) \
- fprintf(stderr,"osmupdate: " f "\n"); // print info message
-#define PINFOv(f,...) \
- fprintf(stderr,"osmupdate: " f "\n",__VA_ARGS__);
-#define ONAME(i) \
- (i==0? "node": i==1? "way": i==2? "relation": "unknown object")
-
-//------------------------------------------------------------
-// end Module Global global variables for this program
-//------------------------------------------------------------
-
-
-
-static void shell_command(const char* command,char* result) {
- // execute a shell command;
- // command[]: shell command;
- // result[1000]: result of the command;
- FILE* fp;
- char* result_p;
- int maxlen;
- int r;
-
- if(loglevel>=2)
- PINFOv("Executing shell command:\n%s",command)
- fp= popen(command,"r");
- if(fp==NULL) {
- PERR("Could not execute shell command.")
- result[0]= 0;
-exit(1);
- }
- result_p= result;
- maxlen= 1000-1;
- while(maxlen>0) {
- r= read(fileno(fp),result_p,maxlen);
- if(r==0) // end of data
- break;
- if(r<0)
-exit(errno); // (thanks to Ben Konrath)
- result_p+= r;
- maxlen-= r;
- }
- *result_p= 0;
- if(pclose(fp)==-1)
-exit(errno); // (thanks to Ben Konrath)
- if(loglevel>=2)
- PINFOv("Got shell command result:\n%s",result)
- } // end shell_command()
-
-typedef enum {cft_UNKNOWN,cft_MINUTELY,cft_HOURLY,cft_DAILY,cft_SPORADIC}
- changefile_type_t;
-#define CFTNAME(i) \
- (i==cft_MINUTELY? "minutely": i==cft_HOURLY? "hourly": \
- i==cft_DAILY? "daily": i==cft_SPORADIC? "sporadic": "unknown")
-
-static int64_t get_file_timestamp(const char* file_name) {
- // get the timestamp of a specific file;
- // if the file timestamp is not available, this procedure tries
- // to retrieve the timestamp from the file's statistics;
- // return: timestamp of the file (seconds from Jan 01 1970);
- // ==0: no file timestamp available;
- char command[500],*command_p,result[1000];
- char* command_e= command+sizeof(command);
- int64_t file_timestamp;
-
- command_p= command;
- stecpy(&command_p,command_e,global_osmconvert_program);
- stecpy(&command_p,command_e," --out-timestamp \"");
- steesccpy(&command_p,command_e,file_name);
- stecpy(&command_p,command_e,"\" 2>&1");
- shell_command(command,result);
- if(result[0]!='(' && (result[0]<'1' || result[0]>'2')) {
- // command not found
- PERR("Please install program osmconvert first.")
-exit(1);
- } // command not found
- file_timestamp= strtimetosint64(result);
- if(file_timestamp==0) { // the file has no file timestamp
- // try to get the timestamp from the file's statistics
- char* p;
-
- if(loglevel>0) { // verbose mode
- PINFOv("file %s has no file timestamp.",file_name)
- PINFO("Running statistics to get the timestamp.")
- }
- command_p= command;
- stecpy(&command_p,command_e,global_osmconvert_program);
- stecpy(&command_p,command_e," --out-statistics \"");
- steesccpy(&command_p,command_e,file_name);
- stecpy(&command_p,command_e,"\" 2>&1");
- shell_command(command,result);
- p= strstr(result,"timestamp max: ");
- if(p!=NULL) {
- file_timestamp= strtimetosint64(p+15);
- PINFO("Aging the timestamp by 4 hours for safety reasons.")
- file_timestamp-= 4*3600;
- }
- } // the file has no file timestamp
- if(loglevel>0) { // verbose mode
- char ts[30];
-
- if(file_timestamp==0)
- strcpy(ts,"(no timestamp)");
- else
- int64tostrtime(file_timestamp,ts);
- PINFOv("timestamp of %s: %s",file_name,ts)
- } // verbose mode
- return file_timestamp;
- } // get_file_timestamp()
-
-static int64_t get_newest_changefile_timestamp(
- changefile_type_t changefile_type,int32_t* file_sequence_number) {
- // get sequence number and timestamp of the newest changefile
- // of a specific changefile type;
- // changefile_type: minutely, hourly, daily, sporadic changefile;
- // return: timestamp of the file (seconds from Jan 01 1970);
- // ==0: no file timestamp available;
- // *file_sequence_number: sequence number of the newest changefile;
- static bool firstrun= true;
- char command[1000],*command_p;
- char* command_e= command+sizeof(command);
- char result[1000];
- int64_t changefile_timestamp;
-
- #if __WIN32__
- static char newest_timestamp_file_name[400];
- if(firstrun) {
- // create the file name for the newest timestamp;
- // this is only needed for Windows as Windows' wget
- // cannot write the downloaded file to standard output;
- // usually: "osmupdate_temp/temp.7"
- strcpy(stpmcpy(newest_timestamp_file_name,global_tempfile_name,
- sizeof(newest_timestamp_file_name)-5),".7");
- }
- #endif
- command_p= command;
- stecpy(&command_p,command_e,
- "wget -q ");
- stecpy(&command_p,command_e,global_base_url);
- switch(changefile_type) { // changefile type
- case cft_MINUTELY:
- stecpy(&command_p,command_e,"/minute");
- break;
- case cft_HOURLY:
- stecpy(&command_p,command_e,"/hour");
- break;
- case cft_DAILY:
- stecpy(&command_p,command_e,"/day");
- break;
- case cft_SPORADIC:
- break;
- default: // invalid change file type
-return 0;
- } // changefile type
- stecpy(&command_p,command_e,global_base_url_suffix);
- stecpy(&command_p,command_e,"/state.txt");
- #if __WIN32__
- stecpy(&command_p,command_e," -O \"");
- steesccpy(&command_p,command_e,newest_timestamp_file_name);
- stecpy(&command_p,command_e,"\" 2>&1");
- #else
- stecpy(&command_p,command_e," -O - 2>&1");
- #endif
- shell_command(command,result);
- if(firstrun) { // first run
- firstrun= false;
- if(result[0]!='#' && (result[0]<'1' || result[0]>'2') && (
- strstr(result,"not found")!=NULL ||
- strstr(result,"cannot find")!=NULL)) { // command not found
- PERR("Please install program wget first.")
-exit(1);
- } // command not found
- } // first run
- #if __WIN32__
- result[0]= 0;
- /* copy tempfile contents to result[] */ {
- int fd,r;
-
- fd= open(newest_timestamp_file_name,O_RDONLY);
- if(fd>0) {
- r= read(fd,result,sizeof(result)-1);
- if(r>=0)
- result[r]= 0;
- close(fd);
- }
- }
- if(loglevel<2)
- unlink(newest_timestamp_file_name);
- #endif
- if(result[0]=='#') { // full status information
- // get sequence number
- char* sequence_number_p;
- sequence_number_p= strstr(result,"sequenceNumber=");
- if(sequence_number_p!=NULL) // found sequence number
- *file_sequence_number= strtouint32(sequence_number_p+15);
- // get timestamp
- char* timestamp_p;
- timestamp_p= strstr(result,"timestamp=");
- // search timestamp line
- if(timestamp_p!=NULL && timestamp_p-result<sizeof(result)-30) {
- // found timestamp line
- // cpy timestam to begin of result[]
- timestamp_p+= 10; // jump over text
- memcpy(result,timestamp_p,13);
- memcpy(result+13,timestamp_p+14,3);
- memcpy(result+16,timestamp_p+18,4);
- } // found timestamp line
- } // full status information
- changefile_timestamp= strtimetosint64(result);
- if(loglevel>0) { // verbose mode
- char ts[30];
-
- if(changefile_timestamp==0)
- strcpy(ts,"(no timestamp)");
- else
- int64tostrtime(changefile_timestamp,ts);
- PINFOv("newest %s timestamp: %s",CFTNAME(changefile_type),ts)
- } // verbose mode
-return changefile_timestamp;
- } // get_newest_changefile_timestamp
-
-static int64_t get_changefile_timestamp(
- changefile_type_t changefile_type,int32_t file_sequence_number) {
- // download and inspect the timestamp of a specific changefile which
- // is available in the Internet;
- // a timestamp file will not be downloaded if it
- // already exists locally as temporary file;
- // changefile_type: minutely, hourly, daily, sporadic changefile;
- // file_sequence_number: sequence number of the file;
- // uses:
- // global_tempfile_name
- // return: timestamp of the changefile (seconds from Jan 01 1970);
- // ==0: no file timestamp available;
- char command[2000]; char* command_p;
- char* command_e= command+sizeof(command);
- char result[1000];
- char timestamp_cachefile_name[400];
- int fd,r; // file descriptor; number of bytes which have been read
- char timestamp_contents[1000]; // contents of the timestamp
- int64_t changefile_timestamp;
- char* sp;
-
- // create the file name for the cached timestamp; example:
- // "osmupdate_temp/temp.m000012345.txt"
- sp= stpmcpy(timestamp_cachefile_name,global_tempfile_name,
- sizeof(timestamp_cachefile_name[0])-20);
- *sp++= '.';
- *sp++= CFTNAME(changefile_type)[0];
- // 'm', 'h', 'd', 's': minutely, hourly, daily, sporadic timestamps
- sprintf(sp,"%09"PRIi32".txt",file_sequence_number);
- // add sequence number and file name extension
-
- // download the timestamp into a cache file
- if(file_length(timestamp_cachefile_name)<10) {
- // timestamp has not been downloaded yet
- command_p= command;
- stecpy(&command_p,command_e,"wget -nv -c ");
- stecpy(&command_p,command_e,global_base_url);
- if(changefile_type==cft_MINUTELY)
- stecpy(&command_p,command_e,"/minute");
- else if(changefile_type==cft_HOURLY)
- stecpy(&command_p,command_e,"/hour");
- else if(changefile_type==cft_DAILY)
- stecpy(&command_p,command_e,"/day");
- else if(changefile_type==cft_SPORADIC)
- ;
- else // invalid change file type
- return 0;
- stecpy(&command_p,command_e,global_base_url_suffix);
- stecpy(&command_p,command_e,"/");
- /* assemble Sequence path */ {
- int l;
- l= sprintf(command_p,"%03i/%03i/%03i",
- file_sequence_number/1000000,file_sequence_number/1000%1000,
- file_sequence_number%1000);
- command_p+= l;
- }
- stecpy(&command_p,command_e,".state.txt -O \"");
- steesccpy(&command_p,command_e,timestamp_cachefile_name);
- stecpy(&command_p,command_e,"\" 2>&1");
- shell_command(command,result);
- } // timestamp has not been downloaded yet
-
- // read the timestamp cache file
- fd= open(timestamp_cachefile_name,O_RDONLY|O_BINARY);
- if(fd<=0) // could not open the file
- timestamp_contents[0]= 0; // hence we did not read anything
- else { // could open the file
- r= read(fd,timestamp_contents,sizeof(timestamp_contents)-1);
- if(r<0) r= 0;
- timestamp_contents[r]= 0; // set string terminator
- close(fd);
- } // could open the file
-
- // parse the timestamp information
- if(timestamp_contents[0]=='#') { // full status information
- // get timestamp
- char* timestamp_p;
- timestamp_p= strstr(timestamp_contents,"timestamp=");
- // search timestamp line
- if(timestamp_p!=NULL &&
- timestamp_p-timestamp_contents<sizeof(timestamp_contents)-30) {
- // found timestamp line
- // copy timestamp to begin of timestamp_contents[]
- timestamp_p+= 10; // jump over text
- memcpy(timestamp_contents,timestamp_p,13);
- memcpy(timestamp_contents+13,timestamp_p+14,3);
- memcpy(timestamp_contents+16,timestamp_p+18,4);
- } // found timestamp line
- } // full status information
- changefile_timestamp= strtimetosint64(timestamp_contents);
-
- if(loglevel>0) { // verbose mode
- char ts[30];
-
- if(changefile_timestamp==0)
- strcpy(ts,"(no timestamp)");
- else
- int64tostrtime(changefile_timestamp,ts);
- PINFOv("%s changefile %i: %s",
- CFTNAME(changefile_type),file_sequence_number,ts)
- } // verbose mode
- if(changefile_timestamp==0) { // no timestamp
- if(file_sequence_number==0) // first file in repository
- changefile_timestamp= 1; // set virtual very old timestamp
- else {
- PERRv("no timestamp for %s changefile %i.",
- CFTNAME(changefile_type),file_sequence_number)
-exit(1);
- }
- } // no timestamp
-return changefile_timestamp;
- } // get_changefile_timestamp
-
-static void process_changefile(
- changefile_type_t changefile_type,int32_t file_sequence_number,
- int64_t new_timestamp) {
- // download and process a change file;
- // change files will not be processed one by one, but cumulated
- // until some files have been downloaded and then processed in a group;
- // a file will not be downloaded if it already exists locally as
- // temporary file;
- // changefile_type: minutely, hourly, daily, sporadic changefile;
- // file_sequence_number: sequence number of the file;
- // ==0: process the remaining files which
- // are waiting in the cache; cleanup;
- // new_timestamp: timestamp of the new file which is to be created;
- // ==0: the procedure will assume the newest of all
- // timestamps which has been passed since the
- // program has been started;
- // uses:
- // global_max_merge
- // global_tempfile_name
- static bool firstrun= true;
- static int number_of_changefiles_in_cache= 0;
- static int64_t newest_new_timestamp= 0;
- static char master_cachefile_name[400];
- static char master_cachefile_name_temp[400];
- static char cachefile_name[max_number_of_changefiles_in_cache][400];
- char command[4000+200*max_number_of_changefiles_in_cache];
- char* command_e= command+sizeof(command);
- char* command_p;
- char result[1000];
-
- if(firstrun) {
- firstrun= false;
- // create the file name for the cached master changefile;
- // usually: "osmupdate_temp/temp.8"
- strcpy(stpmcpy(master_cachefile_name,global_tempfile_name,
- sizeof(master_cachefile_name)-5),".8");
- strcpy(stpmcpy(master_cachefile_name_temp,global_tempfile_name,
- sizeof(master_cachefile_name_temp)-5),".9");
- unlink(master_cachefile_name);
- unlink(master_cachefile_name_temp);
- }
- if(new_timestamp>newest_new_timestamp)
- newest_new_timestamp= new_timestamp;
- if(file_sequence_number!=0) { // changefile download requested
- char* this_cachefile_name=
- cachefile_name[number_of_changefiles_in_cache];
- int64_t old_file_length;
- char* sp;
-
- // create the file name for the cached changefile; example:
- // "osmupdate_temp/temp.m000012345.osc.gz"
- sp= stpmcpy(this_cachefile_name,global_tempfile_name,
- sizeof(cachefile_name[0])-20);
- *sp++= '.';
- *sp++= CFTNAME(changefile_type)[0];
- // 'm', 'h', 'd', 's': minutely, hourly, daily,
- // sporadic changefiles
- sprintf(sp,"%09"PRIi32".osc.gz",file_sequence_number);
- // add sequence number and file name extension
-
- // assemble the URL and download the changefile
- old_file_length= file_length(this_cachefile_name);
- if(loglevel>0 && old_file_length<10)
- // verbose mode AND file not downloaded yet
- PINFOv("%s changefile %i: downloading",
- CFTNAME(changefile_type),file_sequence_number)
- command_p= command;
- stecpy(&command_p,command_e,"wget -nv -c ");
- stecpy(&command_p,command_e,global_base_url);
- switch(changefile_type) { // changefile type
- case cft_MINUTELY:
- stecpy(&command_p,command_e,"/minute");
- break;
- case cft_HOURLY:
- stecpy(&command_p,command_e,"/hour");
- break;
- case cft_DAILY:
- stecpy(&command_p,command_e,"/day");
- break;
- case cft_SPORADIC:
- break;
- default: // invalid change file type
- return;
- } // changefile type
- stecpy(&command_p,command_e,global_base_url_suffix);
- stecpy(&command_p,command_e,"/");
-
- /* process sequence number */ {
- int l;
- l= sprintf(command_p,"%03i/%03i/%03i.osc.gz",
- file_sequence_number/1000000,file_sequence_number/1000%1000,
- file_sequence_number%1000);
- command_p+= l;
- } // process sequence number
-
- stecpy(&command_p,command_e," -O \"");
- steesccpy(&command_p,command_e,this_cachefile_name);
- stecpy(&command_p,command_e,"\" 2>&1 && echo \"Wget Command Ok\"");
- shell_command(command,result);
- if(strstr(result,"Wget Command Ok")==NULL) { // download error
- PERRv("Could not download %s changefile %i",
- CFTNAME(changefile_type),file_sequence_number)
- PINFOv("wget Error message:\n%s",result)
-exit(1);
- }
- if(loglevel>0 && old_file_length>=10) {
- // verbose mode AND file was already in cache
- if(file_length(this_cachefile_name)!=old_file_length)
- PINFOv("%s changefile %i: download completed",
- CFTNAME(changefile_type),file_sequence_number)
- else
- PINFOv("%s changefile %i: already in cache",
- CFTNAME(changefile_type),file_sequence_number)
- } // verbose mode
- number_of_changefiles_in_cache++;
- } // changefile download requested
-
- if(number_of_changefiles_in_cache>=global_max_merge
- || (file_sequence_number==0 && number_of_changefiles_in_cache>0)) {
- // at least one change files must be merged
- // merge all changefiles which are waiting in cache
- if(loglevel>0)
- PINFO("Merging changefiles.")
- command_p= command;
- stecpy(&command_p,command_e,global_osmconvert_program);
- stecpy(&command_p,command_e," --merge-versions ");
- stecpy(&command_p,command_e,global_osmconvert_arguments);
- while(number_of_changefiles_in_cache>0) {
- // for all changefiles in cache
- number_of_changefiles_in_cache--;
- stecpy(&command_p,command_e," \"");
- steesccpy(&command_p,command_e,
- cachefile_name[number_of_changefiles_in_cache]);
- stecpy(&command_p,command_e,"\"");
- } // for all changefiles in cache
- if(file_exists(master_cachefile_name)) {
- stecpy(&command_p,command_e," \"");
- steesccpy(&command_p,command_e,master_cachefile_name);
- stecpy(&command_p,command_e,"\"");
- }
- if(newest_new_timestamp!=0) {
- stecpy(&command_p,command_e," --timestamp=");
- if(command_e-command_p>=30)
- int64tostrtime(newest_new_timestamp,command_p);
- command_p= strchr(command_p,0);
- }
- stecpy(&command_p,command_e," --out-o5c >\"");
- steesccpy(&command_p,command_e,master_cachefile_name_temp);
- stecpy(&command_p,command_e,"\"");
- shell_command(command,result);
- if(file_length(master_cachefile_name_temp)<10 ||
- strstr(result,"Error")!=NULL ||
- strstr(result,"error")!=NULL) { // merging failed
- PERRv("Merging of changefiles failed:\n%s",command)
- if(result[0]!=0)
- PERRv("%s",result)
-exit(1);
- } // merging failed
- unlink(master_cachefile_name);
- rename(master_cachefile_name_temp,master_cachefile_name);
- } // at lease one change files must be merged
- } // process_changefile()
-
-#if !__WIN32__
-void sigcatcher(int sig) {
- fprintf(stderr,"osmupdate: Output has been terminated.\n");
- exit(1);
- } // end sigchatcher()
-#endif
-
-int main(int argc,const char** argv) {
- // main procedure;
- // for the meaning of the calling line parameters please look at the
- // contents of helptext[];
-
- // variables for command line arguments
- int main_return_value;
- const char* a; // command line argument
- char* osmconvert_arguments_p;
- // pointer in global_osmconvert_arguments[]
- char final_osmconvert_arguments[2000];
- // command line arguments for the final run of osmconvert;
- char* final_osmconvert_arguments_p;
- // pointer in final_osmconvert_arguments[]
- const char* old_file; // name of the old OSM file
- int64_t old_timestamp; // timestamp of the old OSM file
- const char* new_file; // name of the new OSM file or OSM Change file
- bool new_file_is_o5; // the new file is type .o5m or .o5c
- bool new_file_is_pbf; // the new file is type .pbf
- bool new_file_is_changefile; // the new file is a changefile
- bool new_file_is_gz; // the new file is a gzip compressed
- int64_t max_update_range; // maximum range for cumulating changefiles
- // in order to update an OSM file; unit: seconds;
- char tempfile_directory[400]; // directory for temporary files
- bool process_minutely,process_hourly,process_daily,process_sporadic;
- // if one of these variables is true, then only the chosen categories
- // shall be processed;
- bool no_minutely,no_hourly,no_daily;
- // the category shall not be processed;
-
- // regular variables
- int64_t minutely_timestamp,hourly_timestamp,daily_timestamp,
- sporadic_timestamp;
- // timestamps for changefiles which are available in the Internet;
- // unit: seconds after Jan 01 1970;
- int32_t minutely_sequence_number,hourly_sequence_number,
- daily_sequence_number,sporadic_sequence_number;
- int64_t timestamp;
- int64_t next_timestamp;
-
- // care about clean-up procedures
- #if !__WIN32__
- /* care about signal handler */ {
- static struct sigaction siga;
-
- siga.sa_handler= sigcatcher;
- sigemptyset(&siga.sa_mask);
- siga.sa_flags= 0;
- sigaction(SIGPIPE,&siga,NULL);
- }
- #endif
-
- // initializations
- main_return_value= 0; // (default)
- #if __WIN32__
- setmode(fileno(stdout),O_BINARY);
- setmode(fileno(stdin),O_BINARY);
- #endif
- osmconvert_arguments_p= global_osmconvert_arguments;
- final_osmconvert_arguments[0]= 0;
- final_osmconvert_arguments_p= final_osmconvert_arguments;
- old_file= NULL;
- old_timestamp= 0;
- new_file= NULL;
- new_file_is_o5= false;
- new_file_is_pbf= false;
- new_file_is_changefile= false;
- new_file_is_gz= false;
- max_update_range= 250*86400;
- process_minutely= process_hourly= process_daily= process_sporadic=
- false;
- no_minutely= no_hourly= no_daily= false;
- if(file_exists(global_osmconvert_program))
- // must be Linux (no ".exe" at the end) AND
- // osmconvert program seems to be in this directory
- global_osmconvert_program= global_osmconvert_program_here_in_dir;
-
- // read command line parameters
- if(argc<=1) { // no command line parameters given
- fprintf(stderr,"osmupdate " VERSION "\n"
- "Updates .osm and .o5m files, downloads .osc and o5c files.\n"
- "To get detailed help, please enter: ./osmupdate -h\n");
-return 0; // end the program, because without having parameters
- // we do not know what to do;
- }
- while(--argc>0) { // for every parameter in command line
- argv++; // switch to next parameter; as the first one is just
- // the program name, we must do this prior reading the
- // first 'real' parameter;
- a= argv[0];
- if(loglevel>0) // verbose mode
- fprintf(stderr,"osmupdate Parameter: %.2000s\n",a);
- if(strcmp(a,"-h")==0 || strcmp(a,"-help")==0 ||
- strcmp(a,"--help")==0) { // user wants help text
- fprintf(stdout,"%s",helptext); // print help text
- // (took "%s", to prevent oversensitive compiler reactions)
-return 0;
- }
- if((strcmp(a,"-v")==0 || strcmp(a,"--verbose")==0 ||
- strzcmp(a,"-v=")==0 || strzcmp(a,"--verbose=")==0) &&
- loglevel==0) { // test mode - if not given already
- char* sp;
-
- sp= strchr(a,'=');
- if(sp!=NULL) loglevel= sp[1]-'0'; else loglevel= 1;
- if(loglevel<1) loglevel= 1;
- if(loglevel>MAXLOGLEVEL) loglevel= MAXLOGLEVEL;
- if(a[1]=='-') { // must be "--verbose" and not "-v"
- if(loglevel==1)
- fprintf(stderr,"osmupdate: Verbose mode.\n");
- else
- fprintf(stderr,"osmupdate: Verbose mode %i.\n",loglevel);
- }
- continue; // take next parameter
- }
- if(strzcmp(a,"--max-days=")==0) { // maximum update range
- max_update_range= (int64_t)strtouint32(a+11)*86400;
- continue; // take next parameter
- }
- if((strzcmp(a,"-t=")==0 || strzcmp(a,"--tempfiles=")==0) &&
- global_tempfile_name[0]==0) {
- // user-defined prefix for names of temorary files
- strmcpy(global_tempfile_name,strchr(a,'=')+1,
- sizeof(global_tempfile_name)-50);
- continue; // take next parameter
- }
- if(strzcmp(a,"--keep-tempfiles")==0) {
- // temporary files shall not be deleted at program end
- global_keep_tempfiles= true;
- continue; // take next parameter
- }
- if(strzcmp(a,"--compression-level=")==0) {
- // gzip compression level
- static char gzip_par[3]= "";
-
- if(a[20]<'1' || a[20]>'9' || a[21]!=0) {
- PINFO("Range error. Changed to --compression-level=3")
- gzip_par[0]= '-'; gzip_par[1]= '3'; gzip_par[2]= 0;
- }
- else {
- gzip_par[0]= '-'; gzip_par[1]= a[20]; gzip_par[2]= 0;
- global_gzip_parameters= gzip_par;
- }
- continue; // take next parameter
- }
- if(strzcmp(a,"--max-merge=")==0) {
- // maximum number of parallely processed changefiles
- global_max_merge= strtouint32(a+12);
- if(global_max_merge<2) {
- global_max_merge= 2;
- PINFO("Range error. Increased to --max-merge=2")
- }
- if(global_max_merge>max_number_of_changefiles_in_cache) {
- global_max_merge= max_number_of_changefiles_in_cache;
- PINFOv("Range error. Decreased to --max-merge=%i",
- max_number_of_changefiles_in_cache)
- }
- continue; // take next parameter
- }
- if(strzcmp(a,"--minute")==0) { // process minutely data
- // accept "--minute" as well as old syntax "--minutely"
- process_minutely= true;
- continue; // take next parameter
- }
- if(strzcmp(a,"--hour")==0) { // process hourly data
- // accept "--hour" as well as old syntax "--hourly"
- process_hourly= true;
- continue; // take next parameter
- }
- if(strcmp(a,"--day")==0 || strzcmp(a,"--daily")==0) {
- // process daily data;
- // accept "--day" as well as old syntax "--daily"
- process_daily= true;
- continue; // take next parameter
- }
- if(strcmp(a,"--sporadic")==0) {
- // process sporadic data;
- process_sporadic= true;
- continue; // take next parameter
- }
- if((strzcmp(a,"--base-url=")==0 && a[11]!=0) ||
- (strzcmp(a,"--planet-url=")==0 && a[13]!=0)) {
- // change base url
- // the second option keyword is deprecated but still supported
- const char* ap;
- char* sp;
-
- ap= a+11;
- if(a[2]=='p') ap+= 2;
- if(strcmp(ap,"mirror")==0)
- strcpy(global_base_url,"ftp://ftp5.gwdg.de/pub/misc/"
- "openstreetmap/planet.openstreetmap.org/replication");
- else if(strstr(ap,"://")!=NULL)
- strmcpy(global_base_url,ap,sizeof(global_base_url)-1);
- else {
- strcpy(global_base_url,"http://");
- strmcpy(global_base_url+7,ap,sizeof(global_base_url)-8);
- }
- sp= strchr(global_base_url,0);
- if(sp>global_base_url && sp[-1]=='/')
- sp[-1]= 0;
- continue; // take next parameter
- }
- if(strzcmp(a,"--base-url-suffix=")==0 && a[20]!=0) {
- // change base url suffix
- strMcpy(global_base_url_suffix,a+18);
- continue; // take next parameter
- }
- if(strzcmp(a,"--planet-url-suffix=")==0 && a[20]!=0) {
- // change base url suffix (this option keyword is deprecated)
- strMcpy(global_base_url_suffix,a+20);
- continue; // take next parameter
- }
- if(a[0]=='-') {
- // command line argument not recognized by osmupdate
- // store it so we can pass it to osmconvert later
- int len;
-
- len= strlen(a)+3;
- if(osmconvert_arguments_p-global_osmconvert_arguments+len
- >=sizeof(global_osmconvert_arguments) ||
- final_osmconvert_arguments_p-final_osmconvert_arguments+len
- >=sizeof(final_osmconvert_arguments)) {
- PERR("too many command line arguments for osmconvert.")
-return 1;
- }
- if(strcmp(a,"--complete-ways")==0 ||
- strcmp(a,"--complex-ways")==0 ||
- strcmp(a,"--drop-brokenrefs")==0 ||
- strcmp(a,"--drop-broken-refs")==0) {
- WARNv("option %.80s does not work with updates.",a)
- continue; // take next parameter
- }
- if(strzcmp(a,"-b=")!=0 && strzcmp(a,"-B=")!=0) {
- // not a bounding box and not a bounding polygon
- *osmconvert_arguments_p++= ' ';
- *osmconvert_arguments_p++= '\"';
- osmconvert_arguments_p= stpesccpy(osmconvert_arguments_p,a);
- *osmconvert_arguments_p++= '\"';
- *osmconvert_arguments_p= 0;
- }
- *final_osmconvert_arguments_p++= ' ';
- *final_osmconvert_arguments_p++= '\"';
- final_osmconvert_arguments_p=
- stpesccpy(final_osmconvert_arguments_p,a);
- *final_osmconvert_arguments_p++= '\"';
- *final_osmconvert_arguments_p= 0;
- continue; // take next parameter
- }
- if(old_timestamp==0) {
- old_timestamp= strtimetosint64(a);
- if(old_timestamp!=0) // this is a valid timestamp
- continue; // take next parameter
- }
- // here: parameter must be a file name
- if(old_file==NULL && old_timestamp==0) { // name of the old file
- old_file= a;
- continue; // take next parameter
- }
- if(new_file==NULL) { // name of the new file
- new_file= a;
- new_file_is_o5=
- strycmp(new_file,".o5m")==0 || strycmp(new_file,".o5c")==0 ||
- strycmp(new_file,".o5m.gz")==0 ||
- strycmp(new_file,".o5c.gz")==0;
- new_file_is_pbf=
- strycmp(new_file,".pbf")==0;
- new_file_is_changefile=
- strycmp(new_file,".osc")==0 || strycmp(new_file,".o5c")==0 ||
- strycmp(new_file,".osc.gz")==0 ||
- strycmp(new_file,".o5c.gz")==0;
- new_file_is_gz= strycmp(new_file,".gz")==0;
- continue; // take next parameter
- }
- } // end for every parameter in command line
-
- /* create tempfile directory for cached timestamps and changefiles */ {
- char *sp;
-
- if(strlen(global_tempfile_name)<2) // not set yet
- strcpy(global_tempfile_name,"osmupdate_temp"DIRSEPS"temp");
- // take default
- sp= strchr(global_tempfile_name,0);
- if(sp[-1]==DIRSEP) // it's a bare directory
- strcpy(sp,"temp"); // add a file name prefix
- strMcpy(tempfile_directory,global_tempfile_name);
- sp= strrchr(tempfile_directory,DIRSEP);
- // get last directory separator
- if(sp!=NULL) *sp= 0; // if found any, cut the string here
- #if __WIN32__
- mkdir(tempfile_directory);
- #else
- mkdir(tempfile_directory,0700);
- #endif
- }
-
- // get file timestamp of OSM input file
- if(old_timestamp==0) { // no timestamp given by the user
- if(old_file==NULL) { // no file name given for the old OSM file
- PERR("Specify at least the old OSM file's name or its timestamp.")
-return 1;
- }
- if(!file_exists(old_file)) { // old OSM file does not exist
- PERRv("Old OSM file does not exist: %.80s",old_file);
-return 1;
- }
- old_timestamp= get_file_timestamp(old_file);
- if(old_timestamp==0) {
- PERRv("Old OSM file does not contain a timestamp: %.80s",old_file);
- PERR("Please specify the timestamp manually, e.g.: "
- "2011-07-15T23:30:00Z");
-return 1;
- }
- } // end no timestamp given by the user
-
- // parameter consistency check
- if(new_file==NULL) {
- PERR("No output file was specified.");
-return 1;
- }
- if(old_file!=NULL && strcmp(old_file,new_file)==0) {
- PERR("Input file and output file are identical.");
-return 1;
- }
- if(old_file==NULL && !new_file_is_changefile) {
- PERR("If no old OSM file is specified, osmupdate can only "
- "generate a changefile.");
-return 1;
- }
-
- // initialize sequence numbers and timestamps
- minutely_sequence_number= hourly_sequence_number=
- daily_sequence_number= sporadic_sequence_number= 0;
- minutely_timestamp= hourly_timestamp=
- daily_timestamp= sporadic_timestamp= 0;
-
- // care about user defined processing categories
- if(process_minutely || process_hourly ||
- process_daily || process_sporadic) {
- // user wants specific type(s) of chancefiles to be processed
- if(!process_minutely) no_minutely= true;
- if(!process_hourly) no_hourly= true;
- if(!process_daily) no_daily= true;
- }
- else {
- // try to get sporadic timestamp
- sporadic_timestamp= get_newest_changefile_timestamp(
- cft_SPORADIC,&sporadic_sequence_number);
- if(sporadic_timestamp!=0) {
- // there is a timestamp at the highest directory level,
- // this must be a so-called sporadic timestamp
- if(loglevel>0) {
- PINFO("Found status information in base URL root.")
- PINFO("Ignoring subdirectories \"minute\", \"hour\", \"day\".")
- }
- process_sporadic= true; // let's take it
- no_minutely= no_hourly= no_daily= true;
- }
- }
-
- // get last timestamp for each, minutely, hourly, daily,
- // and sporadic diff files
- if(!no_minutely) {
- minutely_timestamp= get_newest_changefile_timestamp(
- cft_MINUTELY,&minutely_sequence_number);
- if(minutely_timestamp==0) {
- PERR("Could not get the newest minutely timestamp from the Internet.")
-return 1;
- }
- }
- if(!no_hourly) {
- hourly_timestamp= get_newest_changefile_timestamp(
- cft_HOURLY,&hourly_sequence_number);
- if(hourly_timestamp==0) {
- PERR("Could not get the newest hourly timestamp from the Internet.")
- return 1;
- }
- }
- if(!no_daily) {
- daily_timestamp= get_newest_changefile_timestamp(
- cft_DAILY,&daily_sequence_number);
- if(daily_timestamp==0) {
- PERR("Could not get the newest daily timestamp from the Internet.")
- return 1;
- }
- }
- if(process_sporadic && sporadic_timestamp==0) {
- sporadic_timestamp= get_newest_changefile_timestamp(
- cft_SPORADIC,&sporadic_sequence_number);
- if(sporadic_timestamp==0) {
- PERR("Could not get the newest sporadic timestamp "
- "from the Internet.")
- return 1;
- }
- }
-
- // check maximum update range
- if(minutely_timestamp-old_timestamp>max_update_range) {
- // update range too large
- int days;
- days= (int)((minutely_timestamp-old_timestamp+86399)/86400);
- PERRv("Update range too large: %i days.",days)
- PINFOv("To allow such a wide range, add: --max-days=%i",days)
-return 1;
- } // update range too large
-
- // clear last hourly timestamp if
- // OSM old file's timestamp > latest hourly timestamp - 30 minutes
- if(old_timestamp>hourly_timestamp-30*60 && !no_minutely)
- hourly_timestamp= 0; // (let's take minutely updates)
-
- // clear last daily timestamp if
- // OSM file timestamp > latest daily timestamp - 16 hours
- if(old_timestamp>daily_timestamp-16*3600 &&
- !(no_hourly && no_minutely))
- daily_timestamp= 0; // (let's take hourly and minutely updates)
-
- // initialize start timestamp
- timestamp= 0;
- if(timestamp<minutely_timestamp) timestamp= minutely_timestamp;
- if(timestamp<hourly_timestamp) timestamp= hourly_timestamp;
- if(timestamp<daily_timestamp) timestamp= daily_timestamp;
- if(timestamp<sporadic_timestamp) timestamp= sporadic_timestamp;
-
- // get and process minutely diff files from last minutely timestamp
- // backward; stop just before latest hourly timestamp or OSM
- // file timestamp has been reached;
- if(minutely_timestamp!=0) {
- next_timestamp= timestamp;
- while(next_timestamp>hourly_timestamp &&
- next_timestamp>old_timestamp) {
- timestamp= next_timestamp;
- process_changefile(cft_MINUTELY,minutely_sequence_number,timestamp);
- minutely_sequence_number--;
- next_timestamp= get_changefile_timestamp(
- cft_MINUTELY,minutely_sequence_number);
- }
- }
-
- // get and process hourly diff files from last hourly timestamp
- // backward; stop just before last daily timestamp or OSM
- // file timestamp has been reached;
- if(hourly_timestamp!=0) {
- next_timestamp= timestamp;
- while(next_timestamp>daily_timestamp &&
- next_timestamp>old_timestamp) {
- timestamp= next_timestamp;
- process_changefile(cft_HOURLY,hourly_sequence_number,timestamp);
- hourly_sequence_number--;
- next_timestamp= get_changefile_timestamp(
- cft_HOURLY,hourly_sequence_number);
- }
- }
-
- // get and process daily diff files from last daily timestamp
- // backward; stop just before OSM file timestamp has been reached;
- if(daily_timestamp!=0) {
- next_timestamp= timestamp;
- while(next_timestamp>old_timestamp) {
- timestamp= next_timestamp;
- process_changefile(cft_DAILY,daily_sequence_number,timestamp);
- daily_sequence_number--;
- next_timestamp= get_changefile_timestamp(
- cft_DAILY,daily_sequence_number);
- }
- }
-
- // get and process sporadic diff files from last sporadic timestamp
- // backward; stop just before OSM file timestamp has been reached;
- if(sporadic_timestamp!=0) {
- next_timestamp= timestamp;
- while(next_timestamp>old_timestamp) {
- timestamp= next_timestamp;
- process_changefile(
- cft_SPORADIC,sporadic_sequence_number,timestamp);
- sporadic_sequence_number--;
- next_timestamp= get_changefile_timestamp(
- cft_SPORADIC,sporadic_sequence_number);
- }
- }
-
- // process remaining files which may still wait in the cache;
- process_changefile(0,0,0);
-
- /* create requested output file */ {
- char master_cachefile_name[400];
- char command[2000],*command_p;
- char* command_e= command+sizeof(command);
- char result[1000];
-
- if(loglevel>0)
- PINFO("Creating output file.")
- strcpy(stpmcpy(master_cachefile_name,global_tempfile_name,
- sizeof(master_cachefile_name)-5),".8");
- if(!file_exists(master_cachefile_name)) {
- if(old_file==NULL)
- PINFO("There is no changefile since this timestamp.")
- else
- PINFO("Your OSM file is already up-to-date.")
-return 21;
- }
- command_p= command;
- if(new_file_is_changefile) { // changefile
- if(new_file_is_gz) { // compressed
- if(new_file_is_o5) { // .o5c.gz
- stecpy(&command_p,command_e,"gzip ");
- stecpy(&command_p,command_e,global_gzip_parameters);
- stecpy(&command_p,command_e," <\"");
- steesccpy(&command_p,command_e,master_cachefile_name);
- stecpy(&command_p,command_e,"\" >\"");
- steesccpy(&command_p,command_e,new_file);
- stecpy(&command_p,command_e,"\"");
- }
- else { // .osc.gz
- stecpy(&command_p,command_e,global_osmconvert_program);
- stecpy(&command_p,command_e," ");
- stecpy(&command_p,command_e,global_osmconvert_arguments);
- stecpy(&command_p,command_e," \"");
- steesccpy(&command_p,command_e,master_cachefile_name);
- stecpy(&command_p,command_e,"\" --out-osc |gzip ");
- stecpy(&command_p,command_e,global_gzip_parameters);
- stecpy(&command_p,command_e," >\"");
- steesccpy(&command_p,command_e,new_file);
- stecpy(&command_p,command_e,"\"");
- }
- shell_command(command,result);
- } // compressed
- else { // uncompressed
- if(new_file_is_o5) // .o5c
- rename(master_cachefile_name,new_file);
- else { // .osc
- stecpy(&command_p,command_e,global_osmconvert_program);
- stecpy(&command_p,command_e," ");
- stecpy(&command_p,command_e,global_osmconvert_arguments);
- stecpy(&command_p,command_e," \"");
- steesccpy(&command_p,command_e,master_cachefile_name);
- stecpy(&command_p,command_e,"\" --out-osc >\"");
- steesccpy(&command_p,command_e,new_file);
- stecpy(&command_p,command_e,"\"");
- shell_command(command,result);
- }
- } // uncompressed
- } // changefile
- else { // OSM file
- #if 0
- if(loglevel>=2) {
- PINFOv("oc %s",global_osmconvert_program)
- PINFOv("fa %s",final_osmconvert_arguments)
- PINFOv("of %s",old_file)
- PINFOv("mc %s",master_cachefile_name)
- }
- #endif
- stecpy(&command_p,command_e,global_osmconvert_program);
- stecpy(&command_p,command_e," ");
- stecpy(&command_p,command_e,final_osmconvert_arguments);
- stecpy(&command_p,command_e," \"");
- steesccpy(&command_p,command_e,old_file);
- stecpy(&command_p,command_e,"\" \"");
- steesccpy(&command_p,command_e,master_cachefile_name);
- if(new_file_is_gz) { // compressed
- if(new_file_is_o5) { // .o5m.gz
- stecpy(&command_p,command_e,"\" --out-o5m |gzip ");
- stecpy(&command_p,command_e,global_gzip_parameters);
- stecpy(&command_p,command_e," >\"");
- steesccpy(&command_p,command_e,new_file);
- stecpy(&command_p,command_e,"\"");
- }
- else { // .osm.gz
- stecpy(&command_p,command_e,"\" --out-osm |gzip ");
- stecpy(&command_p,command_e,global_gzip_parameters);
- stecpy(&command_p,command_e," >\"");
- steesccpy(&command_p,command_e,new_file);
- stecpy(&command_p,command_e,"\"");
- }
- } // compressed
- else { // uncompressed
- if(new_file_is_pbf) { // .pbf
- stecpy(&command_p,command_e,"\" --out-pbf >\"");
- steesccpy(&command_p,command_e,new_file);
- stecpy(&command_p,command_e,"\"");
- }
- else if(new_file_is_o5) { // .o5m
- stecpy(&command_p,command_e,"\" --out-o5m >\"");
- steesccpy(&command_p,command_e,new_file);
- stecpy(&command_p,command_e,"\"");
- }
- else { // .osm
- stecpy(&command_p,command_e,"\" --out-osm >\"");
- steesccpy(&command_p,command_e,new_file);
- stecpy(&command_p,command_e,"\"");
- }
- } // uncompressed
- shell_command(command,result);
- } // OSM file
- if(loglevel<2)
- unlink(master_cachefile_name);
- } // create requested output file
-
- // delete tempfiles
- if(global_keep_tempfiles) { // tempfiles shall be kept
- if(loglevel>0)
- PINFO("Keeping temporary files.")
- } // tempfiles shall be kept
- else { // tempfiles shall be deleted
- char command[500],*command_p,result[1000];
- char* command_e= command+sizeof(command);
-
- if(loglevel>0)
- PINFO("Deleting temporary files.")
- command_p= command;
- stecpy(&command_p,command_e,DELFILE" \"");
- steesccpy(&command_p,command_e,global_tempfile_name);
- stecpy(&command_p,command_e,"\".*");
- shell_command(command,result);
- rmdir(tempfile_directory);
- } // tempfiles shall be deleted
-
- if(main_return_value==0 && loglevel>0)
- PINFO("Completed successfully.")
-
- return main_return_value;
- } // end main()
-