2014-10-23 22:40:27 +00:00
# include <stdio.h>
# include <stdlib.h>
2016-04-26 21:01:59 +00:00
# include <string.h>
2014-10-23 22:40:27 +00:00
# include <unistd.h>
# include <sqlite3.h>
2017-07-07 19:37:08 +00:00
# include <getopt.h>
2014-10-23 22:40:27 +00:00
# include <string>
2016-04-22 20:27:03 +00:00
# include <vector>
2016-04-25 21:19:38 +00:00
# include <map>
2017-02-27 18:10:28 +00:00
# include <set>
2014-10-23 22:40:27 +00:00
# include <zlib.h>
# include <math.h>
2016-03-22 23:50:01 +00:00
# include <fcntl.h>
2017-11-30 00:24:48 +00:00
# include <dirent.h>
2016-03-22 23:50:01 +00:00
# include <sys/stat.h>
# include <sys/mman.h>
2016-05-17 22:43:42 +00:00
# include <protozero/pbf_reader.hpp>
2017-11-30 00:24:48 +00:00
# include <sys/stat.h>
2016-04-27 19:22:47 +00:00
# include "mvt.hpp"
2016-04-27 21:00:14 +00:00
# include "projection.hpp"
2016-04-27 22:09:06 +00:00
# include "geometry.hpp"
2016-12-05 22:12:39 +00:00
# include "write_json.hpp"
2017-11-30 00:24:48 +00:00
# include "jsonpull/jsonpull.h"
2017-11-30 23:37:46 +00:00
# include "dirtiles.hpp"
2015-10-09 19:41:28 +00:00
2017-01-24 22:14:10 +00:00
int minzoom = 0 ;
int maxzoom = 32 ;
2017-05-05 17:56:50 +00:00
bool force = false ;
2017-01-24 22:14:10 +00:00
2018-03-16 20:43:21 +00:00
void do_stats ( mvt_tile & tile , size_t size , bool compressed , int z , unsigned x , unsigned y , json_writer & state ) {
state . json_write_hash ( ) ;
2018-03-15 22:19:52 +00:00
2018-03-16 20:43:21 +00:00
state . json_write_string ( " zoom " ) ;
state . json_write_signed ( z ) ;
2018-03-15 22:19:52 +00:00
2018-03-16 20:43:21 +00:00
state . json_write_string ( " x " ) ;
state . json_write_unsigned ( x ) ;
2018-03-15 22:19:52 +00:00
2018-03-16 20:43:21 +00:00
state . json_write_string ( " y " ) ;
state . json_write_unsigned ( y ) ;
2018-03-15 22:19:52 +00:00
2018-03-16 20:43:21 +00:00
state . json_write_string ( " bytes " ) ;
state . json_write_unsigned ( size ) ;
2018-03-15 22:19:52 +00:00
2018-03-16 20:43:21 +00:00
state . json_write_string ( " compressed " ) ;
state . json_write_bool ( compressed ) ;
2018-03-15 22:19:52 +00:00
2018-03-16 20:43:21 +00:00
state . json_write_string ( " layers " ) ;
state . json_write_hash ( ) ;
2017-10-10 00:05:29 +00:00
for ( size_t i = 0 ; i < tile . layers . size ( ) ; i + + ) {
2018-03-16 20:43:21 +00:00
state . json_write_string ( tile . layers [ i ] . name ) ;
2017-10-10 00:05:29 +00:00
2018-03-15 22:19:52 +00:00
size_t points = 0 , lines = 0 , polygons = 0 ;
2017-10-10 00:05:29 +00:00
for ( size_t j = 0 ; j < tile . layers [ i ] . features . size ( ) ; j + + ) {
if ( tile . layers [ i ] . features [ j ] . type = = mvt_point ) {
points + + ;
} else if ( tile . layers [ i ] . features [ j ] . type = = mvt_linestring ) {
lines + + ;
} else if ( tile . layers [ i ] . features [ j ] . type = = mvt_polygon ) {
polygons + + ;
}
}
2018-03-16 20:43:21 +00:00
state . json_write_hash ( ) ;
2018-03-15 22:19:52 +00:00
2018-03-16 20:43:21 +00:00
state . json_write_string ( " points " ) ;
state . json_write_unsigned ( points ) ;
2018-03-15 22:19:52 +00:00
2018-03-16 20:43:21 +00:00
state . json_write_string ( " lines " ) ;
state . json_write_unsigned ( lines ) ;
2018-03-15 22:19:52 +00:00
2018-03-16 20:43:21 +00:00
state . json_write_string ( " polygons " ) ;
state . json_write_unsigned ( polygons ) ;
2018-03-15 22:19:52 +00:00
2018-03-16 20:43:21 +00:00
state . json_write_string ( " extent " ) ;
state . json_write_signed ( tile . layers [ i ] . extent ) ;
2018-03-15 22:19:52 +00:00
2018-03-16 20:43:21 +00:00
state . json_end_hash ( ) ;
2017-10-10 00:05:29 +00:00
}
2018-03-16 20:43:21 +00:00
state . json_end_hash ( ) ;
state . json_end_hash ( ) ;
2018-03-15 22:19:52 +00:00
2018-03-16 20:43:21 +00:00
state . json_write_newline ( ) ;
2017-10-10 00:05:29 +00:00
}
2018-03-16 20:43:21 +00:00
void handle ( std : : string message , int z , unsigned x , unsigned y , std : : set < std : : string > const & to_decode , bool pipeline , bool stats , json_writer & state ) {
2016-04-22 22:10:16 +00:00
mvt_tile tile ;
2017-05-11 19:08:47 +00:00
bool was_compressed ;
2014-10-23 22:40:27 +00:00
2016-05-17 22:43:42 +00:00
try {
2017-05-11 19:08:47 +00:00
if ( ! tile . decode ( message , was_compressed ) ) {
2016-05-17 22:43:42 +00:00
fprintf ( stderr , " Couldn't parse tile %d/%u/%u \n " , z , x , y ) ;
exit ( EXIT_FAILURE ) ;
}
} catch ( protozero : : unknown_pbf_wire_type_exception e ) {
fprintf ( stderr , " PBF decoding error in tile %d/%u/%u \n " , z , x , y ) ;
2014-10-23 22:40:27 +00:00
exit ( EXIT_FAILURE ) ;
}
2017-10-10 00:05:29 +00:00
if ( stats ) {
2018-03-15 23:10:30 +00:00
do_stats ( tile , message . size ( ) , was_compressed , z , x , y , state ) ;
2017-10-10 00:05:29 +00:00
return ;
}
2017-03-28 23:25:40 +00:00
if ( ! pipeline ) {
2018-03-16 20:43:21 +00:00
state . json_write_hash ( ) ;
2018-03-15 23:10:30 +00:00
2018-03-16 20:43:21 +00:00
state . json_write_string ( " type " ) ;
state . json_write_string ( " FeatureCollection " ) ;
2015-10-19 18:12:11 +00:00
2018-03-14 23:35:59 +00:00
if ( true ) {
2018-03-16 20:43:21 +00:00
state . json_write_string ( " properties " ) ;
state . json_write_hash ( ) ;
2018-03-15 23:10:30 +00:00
2018-03-16 20:43:21 +00:00
state . json_write_string ( " zoom " ) ;
state . json_write_signed ( z ) ;
2018-03-15 23:10:30 +00:00
2018-03-16 20:43:21 +00:00
state . json_write_string ( " x " ) ;
state . json_write_signed ( x ) ;
2018-03-15 23:10:30 +00:00
2018-03-16 20:43:21 +00:00
state . json_write_string ( " y " ) ;
state . json_write_signed ( y ) ;
2018-03-15 23:10:30 +00:00
2017-05-13 00:20:30 +00:00
if ( ! was_compressed ) {
2018-03-16 20:43:21 +00:00
state . json_write_string ( " compressed " ) ;
state . json_write_bool ( false ) ;
2017-05-13 00:20:30 +00:00
}
2018-03-15 23:10:30 +00:00
2018-03-16 20:43:21 +00:00
state . json_end_hash ( ) ;
2016-06-28 22:27:19 +00:00
2017-03-28 23:25:40 +00:00
if ( projection ! = projections ) {
2018-03-16 20:43:21 +00:00
state . json_write_string ( " crs " ) ;
state . json_write_hash ( ) ;
2018-03-15 23:10:30 +00:00
2018-03-16 20:43:21 +00:00
state . json_write_string ( " type " ) ;
state . json_write_string ( " name " ) ;
2018-03-15 23:10:30 +00:00
2018-03-16 20:43:21 +00:00
state . json_write_string ( " properties " ) ;
state . json_write_hash ( ) ;
2018-03-15 23:10:30 +00:00
2018-03-16 20:43:21 +00:00
state . json_write_string ( " name " ) ;
state . json_write_string ( projection - > alias ) ;
2018-03-15 23:10:30 +00:00
2018-03-16 20:43:21 +00:00
state . json_end_hash ( ) ;
state . json_end_hash ( ) ;
2017-03-28 23:25:40 +00:00
}
2016-06-28 22:27:19 +00:00
}
2015-10-19 18:12:11 +00:00
2018-03-16 20:43:21 +00:00
state . json_write_string ( " features " ) ;
state . json_write_array ( ) ;
state . json_write_newline ( ) ;
2017-03-28 23:25:40 +00:00
}
2015-10-09 19:41:28 +00:00
2017-02-27 18:10:28 +00:00
bool first_layer = true ;
2016-04-23 06:32:02 +00:00
for ( size_t l = 0 ; l < tile . layers . size ( ) ; l + + ) {
2016-04-22 22:10:16 +00:00
mvt_layer & layer = tile . layers [ l ] ;
2014-10-23 22:40:27 +00:00
2017-10-30 19:48:55 +00:00
if ( layer . extent < = 0 ) {
fprintf ( stderr , " Impossible layer extent %lld in mbtiles \n " , layer . extent ) ;
exit ( EXIT_FAILURE ) ;
}
2017-02-27 18:10:28 +00:00
if ( to_decode . size ( ) ! = 0 & & ! to_decode . count ( layer . name ) ) {
continue ;
}
2017-03-28 23:25:40 +00:00
if ( ! pipeline ) {
2018-03-14 23:35:59 +00:00
if ( true ) {
2017-03-28 23:25:40 +00:00
if ( ! first_layer ) {
2018-03-16 20:43:21 +00:00
state . json_comma_newline ( ) ;
2017-03-28 23:25:40 +00:00
}
2015-10-31 00:30:18 +00:00
2018-03-16 20:43:21 +00:00
state . json_write_hash ( ) ;
2018-03-15 23:10:30 +00:00
2018-03-16 20:43:21 +00:00
state . json_write_string ( " type " ) ;
state . json_write_string ( " FeatureCollection " ) ;
2015-10-31 00:30:18 +00:00
2018-03-16 20:43:21 +00:00
state . json_write_string ( " properties " ) ;
state . json_write_hash ( ) ;
2018-03-15 23:10:30 +00:00
2018-03-16 20:43:21 +00:00
state . json_write_string ( " layer " ) ;
state . json_write_string ( layer . name ) ;
2018-03-15 23:10:30 +00:00
2018-03-16 20:43:21 +00:00
state . json_write_string ( " version " ) ;
state . json_write_signed ( layer . version ) ;
2018-03-15 23:10:30 +00:00
2018-03-16 20:43:21 +00:00
state . json_write_string ( " extent " ) ;
state . json_write_signed ( layer . extent ) ;
2018-03-15 23:10:30 +00:00
2018-03-16 20:43:21 +00:00
state . json_end_hash ( ) ;
2018-03-15 23:10:30 +00:00
2018-03-16 20:43:21 +00:00
state . json_write_string ( " features " ) ;
state . json_write_array ( ) ;
2018-03-15 23:10:30 +00:00
2018-03-16 20:43:21 +00:00
state . json_write_newline ( ) ;
2017-03-28 23:25:40 +00:00
first_layer = false ;
}
2015-10-31 00:30:18 +00:00
}
2017-10-30 20:14:38 +00:00
// X and Y are unsigned, so no need to check <0
2017-11-07 19:38:38 +00:00
if ( x > ( 1ULL < < z ) | | y > ( 1ULL < < z ) ) {
2017-10-30 20:14:38 +00:00
fprintf ( stderr , " Impossible tile %d/%u/%u \n " , z , x , y ) ;
exit ( EXIT_FAILURE ) ;
}
2018-03-16 20:43:21 +00:00
layer_to_geojson ( layer , z , x , y , ! pipeline , pipeline , pipeline , false , 0 , 0 , 0 , ! force , state ) ;
2015-10-31 00:30:18 +00:00
2017-03-28 23:25:40 +00:00
if ( ! pipeline ) {
2018-03-14 23:35:59 +00:00
if ( true ) {
2018-03-16 20:43:21 +00:00
state . json_end_array ( ) ;
state . json_end_hash ( ) ;
state . json_write_newline ( ) ;
2017-03-28 23:25:40 +00:00
}
2015-10-31 00:30:18 +00:00
}
2014-10-23 22:40:27 +00:00
}
2015-10-09 19:41:28 +00:00
2017-03-28 23:25:40 +00:00
if ( ! pipeline ) {
2018-03-16 20:43:21 +00:00
state . json_end_array ( ) ;
state . json_end_hash ( ) ;
state . json_write_newline ( ) ;
2017-03-28 23:25:40 +00:00
}
2014-10-23 22:40:27 +00:00
}
2017-11-30 00:24:48 +00:00
void decode ( char * fname , int z , unsigned x , unsigned y , std : : set < std : : string > const & to_decode , bool pipeline , bool stats ) {
sqlite3 * db = NULL ;
bool isdir = false ;
2014-10-27 23:00:16 +00:00
int oz = z ;
unsigned ox = x , oy = y ;
2018-03-16 20:43:21 +00:00
json_writer state ( stdout ) ;
2014-10-23 22:40:27 +00:00
2016-12-07 18:57:56 +00:00
int fd = open ( fname , O_RDONLY | O_CLOEXEC ) ;
2016-03-22 23:50:01 +00:00
if ( fd > = 0 ) {
struct stat st ;
if ( fstat ( fd , & st ) = = 0 ) {
if ( st . st_size < 50 * 1024 * 1024 ) {
char * map = ( char * ) mmap ( NULL , st . st_size , PROT_READ , MAP_PRIVATE , fd , 0 ) ;
if ( map ! = NULL & & map ! = MAP_FAILED ) {
if ( strcmp ( map , " SQLite format 3 " ) ! = 0 ) {
2016-03-23 00:12:09 +00:00
if ( z > = 0 ) {
std : : string s = std : : string ( map , st . st_size ) ;
2018-03-15 23:10:30 +00:00
handle ( s , z , x , y , to_decode , pipeline , stats , state ) ;
2016-03-23 00:12:09 +00:00
munmap ( map , st . st_size ) ;
return ;
} else {
fprintf ( stderr , " Must specify zoom/x/y to decode a single pbf file \n " ) ;
exit ( EXIT_FAILURE ) ;
}
2016-03-22 23:50:01 +00:00
}
}
munmap ( map , st . st_size ) ;
}
} else {
perror ( " fstat " ) ;
}
2016-12-01 23:34:44 +00:00
if ( close ( fd ) ! = 0 ) {
perror ( " close " ) ;
exit ( EXIT_FAILURE ) ;
}
2016-03-22 23:50:01 +00:00
} else {
perror ( fname ) ;
}
2017-11-30 00:24:48 +00:00
struct stat st ;
std : : vector < zxy > tiles ;
if ( stat ( fname , & st ) = = 0 & & ( st . st_mode & S_IFDIR ) ! = 0 ) {
isdir = true ;
2017-11-30 23:49:14 +00:00
db = dirmeta2tmp ( fname ) ;
tiles = enumerate_dirtiles ( fname ) ;
2017-11-30 00:24:48 +00:00
} else {
if ( sqlite3_open ( fname , & db ) ! = SQLITE_OK ) {
fprintf ( stderr , " %s: %s \n " , fname , sqlite3_errmsg ( db ) ) ;
exit ( EXIT_FAILURE ) ;
}
2014-10-23 22:40:27 +00:00
}
2015-10-19 18:12:11 +00:00
if ( z < 0 ) {
2017-03-28 23:25:40 +00:00
int within = 0 ;
2016-01-28 22:06:51 +00:00
2017-10-10 00:05:29 +00:00
if ( ! pipeline & & ! stats ) {
2018-03-16 20:43:21 +00:00
state . json_write_hash ( ) ;
2018-03-15 23:10:30 +00:00
2018-03-16 20:43:21 +00:00
state . json_write_string ( " type " ) ;
state . json_write_string ( " FeatureCollection " ) ;
2018-03-15 23:10:30 +00:00
2018-03-16 20:43:21 +00:00
state . json_write_string ( " properties " ) ;
state . json_write_hash ( ) ;
state . json_write_newline ( ) ;
2016-01-28 22:06:51 +00:00
2017-03-28 23:25:40 +00:00
const char * sql2 = " SELECT name, value from metadata order by name; " ;
sqlite3_stmt * stmt2 ;
if ( sqlite3_prepare_v2 ( db , sql2 , - 1 , & stmt2 , NULL ) ! = SQLITE_OK ) {
fprintf ( stderr , " %s: select failed: %s \n " , fname , sqlite3_errmsg ( db ) ) ;
exit ( EXIT_FAILURE ) ;
2016-01-28 22:06:51 +00:00
}
2017-03-28 23:25:40 +00:00
while ( sqlite3_step ( stmt2 ) = = SQLITE_ROW ) {
if ( within ) {
2018-03-16 20:43:21 +00:00
state . json_comma_newline ( ) ;
2017-03-28 23:25:40 +00:00
}
within = 1 ;
2016-01-28 22:06:51 +00:00
2017-03-28 23:25:40 +00:00
const unsigned char * name = sqlite3_column_text ( stmt2 , 0 ) ;
const unsigned char * value = sqlite3_column_text ( stmt2 , 1 ) ;
2017-10-28 00:38:07 +00:00
if ( name = = NULL | | value = = NULL ) {
fprintf ( stderr , " Corrupt mbtiles file: null metadata \n " ) ;
exit ( EXIT_FAILURE ) ;
}
2018-03-16 20:43:21 +00:00
state . json_write_string ( ( char * ) name ) ;
state . json_write_string ( ( char * ) value ) ;
2017-03-28 23:25:40 +00:00
}
2016-01-28 22:06:51 +00:00
2018-03-16 20:43:21 +00:00
state . json_write_newline ( ) ;
2018-03-15 23:10:30 +00:00
state . wantnl = false ; // XXX
2017-03-28 23:25:40 +00:00
sqlite3_finalize ( stmt2 ) ;
}
2016-01-28 22:06:51 +00:00
2017-10-10 00:05:29 +00:00
if ( stats ) {
2018-03-16 20:43:21 +00:00
state . json_write_array ( ) ;
state . json_write_newline ( ) ;
2017-10-10 00:05:29 +00:00
}
if ( ! pipeline & & ! stats ) {
2018-03-16 20:43:21 +00:00
state . json_end_hash ( ) ;
2018-03-15 23:10:30 +00:00
2018-03-16 20:43:21 +00:00
state . json_write_string ( " features " ) ;
state . json_write_array ( ) ;
state . json_write_newline ( ) ;
2017-03-28 23:25:40 +00:00
}
2014-10-23 22:40:27 +00:00
2017-11-30 00:24:48 +00:00
if ( isdir ) {
within = 0 ;
for ( size_t i = 0 ; i < tiles . size ( ) ; i + + ) {
if ( ! pipeline & & ! stats ) {
if ( within ) {
2018-03-16 20:43:21 +00:00
state . json_comma_newline ( ) ;
2017-11-30 00:24:48 +00:00
}
within = 1 ;
2017-10-10 00:05:29 +00:00
}
2017-11-30 00:24:48 +00:00
if ( stats ) {
if ( within ) {
2018-03-16 20:43:21 +00:00
state . json_comma_newline ( ) ;
2017-11-30 00:24:48 +00:00
}
within = 1 ;
2017-03-28 23:25:40 +00:00
}
2015-10-19 18:12:11 +00:00
2017-11-30 23:37:46 +00:00
std : : string fn = std : : string ( fname ) + " / " + tiles [ i ] . path ( ) ;
2017-11-30 00:24:48 +00:00
FILE * f = fopen ( fn . c_str ( ) , " rb " ) ;
if ( f = = NULL ) {
perror ( fn . c_str ( ) ) ;
exit ( EXIT_FAILURE ) ;
}
2017-10-30 19:55:22 +00:00
2017-11-30 00:24:48 +00:00
std : : string s ;
char buf [ 2000 ] ;
ssize_t n ;
while ( ( n = fread ( buf , 1 , 2000 , f ) ) > 0 ) {
s . append ( std : : string ( buf , n ) ) ;
}
fclose ( f ) ;
2018-03-15 23:10:30 +00:00
handle ( s , tiles [ i ] . z , tiles [ i ] . x , tiles [ i ] . y , to_decode , pipeline , stats , state ) ;
2017-11-30 00:24:48 +00:00
}
} else {
const char * sql = " SELECT tile_data, zoom_level, tile_column, tile_row from tiles where zoom_level between ? and ? order by zoom_level, tile_column, tile_row; " ;
sqlite3_stmt * stmt ;
if ( sqlite3_prepare_v2 ( db , sql , - 1 , & stmt , NULL ) ! = SQLITE_OK ) {
fprintf ( stderr , " %s: select failed: %s \n " , fname , sqlite3_errmsg ( db ) ) ;
2017-10-30 19:55:22 +00:00
exit ( EXIT_FAILURE ) ;
}
2017-11-30 00:24:48 +00:00
sqlite3_bind_int ( stmt , 1 , minzoom ) ;
sqlite3_bind_int ( stmt , 2 , maxzoom ) ;
within = 0 ;
while ( sqlite3_step ( stmt ) = = SQLITE_ROW ) {
if ( ! pipeline & & ! stats ) {
if ( within ) {
2018-03-16 20:43:21 +00:00
state . json_comma_newline ( ) ;
2017-11-30 00:24:48 +00:00
}
within = 1 ;
}
if ( stats ) {
if ( within ) {
2018-03-16 20:43:21 +00:00
state . json_comma_newline ( ) ;
2017-11-30 00:24:48 +00:00
}
within = 1 ;
}
int len = sqlite3_column_bytes ( stmt , 0 ) ;
int tz = sqlite3_column_int ( stmt , 1 ) ;
int tx = sqlite3_column_int ( stmt , 2 ) ;
int ty = sqlite3_column_int ( stmt , 3 ) ;
2014-10-23 22:40:27 +00:00
2017-11-30 00:24:48 +00:00
if ( tz < 0 | | tz > = 32 ) {
fprintf ( stderr , " Impossible zoom level %d in mbtiles \n " , tz ) ;
exit ( EXIT_FAILURE ) ;
}
ty = ( 1LL < < tz ) - 1 - ty ;
const char * s = ( const char * ) sqlite3_column_blob ( stmt , 0 ) ;
2018-03-15 23:10:30 +00:00
handle ( std : : string ( s , len ) , tz , tx , ty , to_decode , pipeline , stats , state ) ;
2017-11-30 00:24:48 +00:00
}
sqlite3_finalize ( stmt ) ;
2014-10-27 23:00:16 +00:00
}
2014-10-23 22:40:27 +00:00
2017-10-10 00:05:29 +00:00
if ( ! pipeline & & ! stats ) {
2018-03-16 20:43:21 +00:00
state . json_end_array ( ) ;
state . json_end_hash ( ) ;
state . json_write_newline ( ) ;
2017-03-28 23:25:40 +00:00
}
2017-10-10 00:05:29 +00:00
if ( stats ) {
2018-03-16 20:43:21 +00:00
state . json_end_array ( ) ;
state . json_write_newline ( ) ;
2018-03-15 23:10:30 +00:00
}
if ( pipeline ) {
2018-03-16 20:43:21 +00:00
state . json_write_newline ( ) ;
2017-10-10 00:05:29 +00:00
}
2015-10-19 18:12:11 +00:00
} else {
int handled = 0 ;
while ( z > = 0 & & ! handled ) {
const char * sql = " SELECT tile_data from tiles where zoom_level = ? and tile_column = ? and tile_row = ?; " ;
sqlite3_stmt * stmt ;
if ( sqlite3_prepare_v2 ( db , sql , - 1 , & stmt , NULL ) ! = SQLITE_OK ) {
fprintf ( stderr , " %s: select failed: %s \n " , fname , sqlite3_errmsg ( db ) ) ;
exit ( EXIT_FAILURE ) ;
}
sqlite3_bind_int ( stmt , 1 , z ) ;
sqlite3_bind_int ( stmt , 2 , x ) ;
sqlite3_bind_int ( stmt , 3 , ( 1LL < < z ) - 1 - y ) ;
while ( sqlite3_step ( stmt ) = = SQLITE_ROW ) {
int len = sqlite3_column_bytes ( stmt , 0 ) ;
const char * s = ( const char * ) sqlite3_column_blob ( stmt , 0 ) ;
if ( z ! = oz ) {
fprintf ( stderr , " %s: Warning: using tile %d/%u/%u instead of %d/%u/%u \n " , fname , z , x , y , oz , ox , oy ) ;
}
2018-03-15 23:10:30 +00:00
handle ( std : : string ( s , len ) , z , x , y , to_decode , pipeline , stats , state ) ;
2015-10-19 18:12:11 +00:00
handled = 1 ;
}
2014-10-27 23:00:16 +00:00
2015-10-19 18:12:11 +00:00
sqlite3_finalize ( stmt ) ;
z - - ;
x / = 2 ;
y / = 2 ;
}
2014-10-27 23:00:16 +00:00
}
2014-10-23 22:40:27 +00:00
2015-06-03 18:21:40 +00:00
if ( sqlite3_close ( db ) ! = SQLITE_OK ) {
fprintf ( stderr , " %s: could not close database: %s \n " , fname , sqlite3_errmsg ( db ) ) ;
exit ( EXIT_FAILURE ) ;
}
2014-10-23 22:40:27 +00:00
}
void usage ( char * * argv ) {
2017-08-08 18:08:10 +00:00
fprintf ( stderr , " Usage: %s [-s projection] [-Z minzoom] [-z maxzoom] [-l layer ...] file.mbtiles [zoom x y] \n " , argv [ 0 ] ) ;
2014-10-23 22:40:27 +00:00
exit ( EXIT_FAILURE ) ;
}
int main ( int argc , char * * argv ) {
extern int optind ;
2016-06-28 22:18:27 +00:00
extern char * optarg ;
2014-10-23 22:40:27 +00:00
int i ;
2017-02-27 18:10:28 +00:00
std : : set < std : : string > to_decode ;
2017-03-28 23:25:40 +00:00
bool pipeline = false ;
2017-10-10 00:05:29 +00:00
bool stats = false ;
2014-10-23 22:40:27 +00:00
2017-07-07 19:37:08 +00:00
struct option long_options [ ] = {
{ " projection " , required_argument , 0 , ' s ' } ,
{ " maximum-zoom " , required_argument , 0 , ' z ' } ,
{ " minimum-zoom " , required_argument , 0 , ' Z ' } ,
{ " layer " , required_argument , 0 , ' l ' } ,
2017-08-08 18:08:10 +00:00
{ " tag-layer-and-zoom " , no_argument , 0 , ' c ' } ,
2017-10-10 00:05:29 +00:00
{ " stats " , no_argument , 0 , ' S ' } ,
2017-07-07 19:37:08 +00:00
{ " force " , no_argument , 0 , ' f ' } ,
{ 0 , 0 , 0 , 0 } ,
} ;
std : : string getopt_str ;
for ( size_t lo = 0 ; long_options [ lo ] . name ! = NULL ; lo + + ) {
if ( long_options [ lo ] . val > ' ' ) {
getopt_str . push_back ( long_options [ lo ] . val ) ;
if ( long_options [ lo ] . has_arg = = required_argument ) {
getopt_str . push_back ( ' : ' ) ;
}
}
}
while ( ( i = getopt_long ( argc , argv , getopt_str . c_str ( ) , long_options , NULL ) ) ! = - 1 ) {
2016-06-28 22:18:27 +00:00
switch ( i ) {
2017-07-07 19:37:08 +00:00
case 0 :
break ;
case ' s ' :
2016-06-28 22:18:27 +00:00
set_projection_or_exit ( optarg ) ;
break ;
2017-01-24 22:14:10 +00:00
case ' z ' :
maxzoom = atoi ( optarg ) ;
break ;
case ' Z ' :
minzoom = atoi ( optarg ) ;
break ;
2017-02-27 18:10:28 +00:00
case ' l ' :
to_decode . insert ( optarg ) ;
break ;
2017-03-28 23:25:40 +00:00
case ' c ' :
pipeline = true ;
break ;
2017-10-10 00:05:29 +00:00
case ' S ' :
stats = true ;
break ;
2017-05-05 17:56:50 +00:00
case ' f ' :
force = true ;
break ;
2016-06-28 22:18:27 +00:00
default :
usage ( argv ) ;
}
2014-10-23 22:40:27 +00:00
}
2015-10-19 18:12:11 +00:00
if ( argc = = optind + 4 ) {
2017-10-10 00:05:29 +00:00
decode ( argv [ optind ] , atoi ( argv [ optind + 1 ] ) , atoi ( argv [ optind + 2 ] ) , atoi ( argv [ optind + 3 ] ) , to_decode , pipeline , stats ) ;
2015-10-19 18:12:11 +00:00
} else if ( argc = = optind + 1 ) {
2017-10-10 00:05:29 +00:00
decode ( argv [ optind ] , - 1 , - 1 , - 1 , to_decode , pipeline , stats ) ;
2015-10-19 18:12:11 +00:00
} else {
2014-10-23 22:40:27 +00:00
usage ( argv ) ;
}
return 0 ;
}