diff options
author | Ilya Zverev <zverik@textual.ru> | 2015-09-28 21:53:11 +0300 |
---|---|---|
committer | Ilya Zverev <zverik@textual.ru> | 2015-09-28 21:53:11 +0300 |
commit | 325c889aaba51221a2390309c4f4f4c0cc45860d (patch) | |
tree | 644ef904ba868a5b6f1da14776db5e747f199117 /tools/osmctools | |
parent | 579f82d6b50efc951db1b7adebffc534e577d0b9 (diff) |
Replace osmctools with a submodule from mapsme/osmctools
Diffstat (limited to 'tools/osmctools')
m--------- | tools/osmctools | 0 | ||||
-rw-r--r-- | tools/osmctools/osmconvert.c | 11943 | ||||
-rw-r--r-- | tools/osmctools/osmfilter.c | 6260 | ||||
-rw-r--r-- | tools/osmctools/osmupdate.c | 1650 |
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'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'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() - |