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>
# 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>
# include <sys/stat.h>
# include <sys/mman.h>
2016-05-17 22:43:42 +00:00
# include <protozero/pbf_reader.hpp>
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"
2014-10-25 00:22:14 +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
2015-10-09 19:41:28 +00:00
void printq ( const char * s ) {
putchar ( ' " ' ) ;
for ( ; * s ; s + + ) {
if ( * s = = ' \\ ' | | * s = = ' " ' ) {
printf ( " \\ %c " , * s ) ;
} else if ( * s > = 0 & & * s < ' ' ) {
printf ( " \\ u%04x " , * s ) ;
} else {
putchar ( * s ) ;
}
}
putchar ( ' " ' ) ;
}
2016-04-27 22:09:06 +00:00
struct lonlat {
2015-10-09 19:41:28 +00:00
int op ;
double lon ;
double lat ;
2016-05-10 19:13:03 +00:00
int x ;
int y ;
2015-10-09 19:41:28 +00:00
2016-05-10 19:13:03 +00:00
lonlat ( int nop , double nlon , double nlat , int nx , int ny ) {
2016-05-03 22:48:42 +00:00
this - > op = nop ;
this - > lon = nlon ;
this - > lat = nlat ;
2016-05-10 19:13:03 +00:00
this - > x = nx ;
this - > y = ny ;
2015-10-09 19:41:28 +00:00
}
} ;
2017-02-27 18:10:28 +00:00
void handle ( std : : string message , int z , unsigned x , unsigned y , int describe , std : : set < std : : string > const & to_decode ) {
2015-10-09 19:41:28 +00:00
int within = 0 ;
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 ) ;
}
2015-10-19 18:12:11 +00:00
printf ( " { \" type \" : \" FeatureCollection \" " ) ;
if ( describe ) {
2017-05-11 19:08:47 +00:00
printf ( " , \" properties \" : { \" zoom \" : %d, \" x \" : %d, \" y \" : %d " , z , x , y ) ;
if ( ! was_compressed ) {
printf ( " , \" compressed \" : false " ) ;
}
printf ( " } " ) ;
2016-06-28 22:27:19 +00:00
if ( projection ! = projections ) {
printf ( " , \" crs \" : { \" type \" : \" name \" , \" properties \" : { \" name \" : " ) ;
printq ( projection - > alias ) ;
printf ( " } } " ) ;
}
2015-10-19 18:12:11 +00:00
}
printf ( " , \" features \" : [ \n " ) ;
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 ] ;
2016-04-22 20:27:03 +00:00
int extent = layer . extent ;
2014-10-23 22:40:27 +00:00
2017-02-27 18:10:28 +00:00
if ( to_decode . size ( ) ! = 0 & & ! to_decode . count ( layer . name ) ) {
continue ;
}
2015-10-31 00:30:18 +00:00
if ( describe ) {
2017-02-27 18:10:28 +00:00
if ( ! first_layer ) {
2015-10-31 00:30:18 +00:00
printf ( " , \n " ) ;
}
printf ( " { \" type \" : \" FeatureCollection \" " ) ;
2015-11-02 22:03:45 +00:00
printf ( " , \" properties \" : { \" layer \" : " ) ;
2016-04-22 20:27:03 +00:00
printq ( layer . name . c_str ( ) ) ;
2016-06-16 19:50:08 +00:00
printf ( " , \" version \" : %d, \" extent \" : %d " , layer . version , layer . extent ) ;
2015-10-31 00:30:18 +00:00
printf ( " } " ) ;
printf ( " , \" features \" : [ \n " ) ;
2017-02-27 18:10:28 +00:00
first_layer = false ;
2015-10-31 00:30:18 +00:00
within = 0 ;
}
2016-04-23 06:32:02 +00:00
for ( size_t f = 0 ; f < layer . features . size ( ) ; f + + ) {
2016-04-22 22:10:16 +00:00
mvt_feature & feat = layer . features [ f ] ;
2014-10-23 22:40:27 +00:00
2015-10-09 19:41:28 +00:00
if ( within ) {
printf ( " , \n " ) ;
}
within = 1 ;
printf ( " { \" type \" : \" Feature \" " ) ;
2016-07-15 20:58:15 +00:00
if ( feat . has_id ) {
printf ( " , \" id \" : %llu " , feat . id ) ;
}
2015-10-09 19:41:28 +00:00
printf ( " , \" properties \" : { " ) ;
2016-04-22 20:27:03 +00:00
for ( size_t t = 0 ; t + 1 < feat . tags . size ( ) ; t + = 2 ) {
2015-10-09 19:41:28 +00:00
if ( t ! = 0 ) {
printf ( " , " ) ;
}
2016-04-22 22:06:26 +00:00
if ( feat . tags [ t ] > = layer . keys . size ( ) ) {
fprintf ( stderr , " Error: out of bounds feature key \n " ) ;
exit ( EXIT_FAILURE ) ;
}
if ( feat . tags [ t + 1 ] > = layer . values . size ( ) ) {
fprintf ( stderr , " Error: out of bounds feature value \n " ) ;
exit ( EXIT_FAILURE ) ;
}
2016-04-22 20:27:03 +00:00
const char * key = layer . keys [ feat . tags [ t ] ] . c_str ( ) ;
2016-04-22 22:10:16 +00:00
mvt_value const & val = layer . values [ feat . tags [ t + 1 ] ] ;
2015-10-09 19:41:28 +00:00
2016-04-22 22:10:16 +00:00
if ( val . type = = mvt_string ) {
2015-10-09 19:41:28 +00:00
printq ( key ) ;
printf ( " : " ) ;
2016-04-22 20:27:03 +00:00
printq ( val . string_value . c_str ( ) ) ;
2016-04-22 22:10:16 +00:00
} else if ( val . type = = mvt_int ) {
2015-10-09 19:41:28 +00:00
printq ( key ) ;
2016-04-22 20:27:03 +00:00
printf ( " : %lld " , ( long long ) val . numeric_value . int_value ) ;
2016-04-22 22:10:16 +00:00
} else if ( val . type = = mvt_double ) {
2015-10-09 19:41:28 +00:00
printq ( key ) ;
2016-04-22 20:27:03 +00:00
double v = val . numeric_value . double_value ;
2015-12-15 00:10:34 +00:00
if ( v = = ( long long ) v ) {
printf ( " : %lld " , ( long long ) v ) ;
} else {
printf ( " : %g " , v ) ;
}
2016-04-22 22:10:16 +00:00
} else if ( val . type = = mvt_float ) {
2015-10-09 19:41:28 +00:00
printq ( key ) ;
2016-04-22 20:27:03 +00:00
double v = val . numeric_value . float_value ;
2015-12-15 00:10:34 +00:00
if ( v = = ( long long ) v ) {
printf ( " : %lld " , ( long long ) v ) ;
} else {
printf ( " : %g " , v ) ;
}
2016-04-22 22:10:16 +00:00
} else if ( val . type = = mvt_sint ) {
2015-10-09 19:41:28 +00:00
printq ( key ) ;
2016-04-22 20:27:03 +00:00
printf ( " : %lld " , ( long long ) val . numeric_value . sint_value ) ;
2016-04-22 22:10:16 +00:00
} else if ( val . type = = mvt_uint ) {
2015-10-09 19:41:28 +00:00
printq ( key ) ;
2016-04-22 20:27:03 +00:00
printf ( " : %lld " , ( long long ) val . numeric_value . uint_value ) ;
2016-04-22 22:10:16 +00:00
} else if ( val . type = = mvt_bool ) {
2015-10-09 19:41:28 +00:00
printq ( key ) ;
2016-04-22 20:27:03 +00:00
printf ( " : %s " , val . numeric_value . bool_value ? " true " : " false " ) ;
2015-10-09 19:41:28 +00:00
}
}
printf ( " }, \" geometry \" : { " ) ;
2016-04-27 22:09:06 +00:00
std : : vector < lonlat > ops ;
2015-10-09 19:41:28 +00:00
2016-04-23 06:32:02 +00:00
for ( size_t g = 0 ; g < feat . geometry . size ( ) ; g + + ) {
2016-04-22 20:27:03 +00:00
int op = feat . geometry [ g ] . op ;
long long px = feat . geometry [ g ] . x ;
long long py = feat . geometry [ g ] . y ;
2014-10-23 22:40:27 +00:00
2015-10-09 19:41:28 +00:00
if ( op = = VT_MOVETO | | op = = VT_LINETO ) {
2016-04-22 20:27:03 +00:00
long long scale = 1LL < < ( 32 - z ) ;
long long wx = scale * x + ( scale / extent ) * px ;
long long wy = scale * y + ( scale / extent ) * py ;
2014-10-23 22:40:27 +00:00
2016-04-22 20:27:03 +00:00
double lat , lon ;
2016-06-28 22:18:27 +00:00
projection - > unproject ( wx , wy , 32 , & lon , & lat ) ;
2015-10-09 19:41:28 +00:00
2016-05-10 19:13:03 +00:00
ops . push_back ( lonlat ( op , lon , lat , px , py ) ) ;
2015-10-09 19:41:28 +00:00
} else {
2016-05-10 19:13:03 +00:00
ops . push_back ( lonlat ( op , 0 , 0 , 0 , 0 ) ) ;
2014-10-23 22:40:27 +00:00
}
}
2015-10-09 19:41:28 +00:00
2016-04-22 20:27:03 +00:00
if ( feat . type = = VT_POINT ) {
2015-10-09 19:41:28 +00:00
if ( ops . size ( ) = = 1 ) {
printf ( " \" type \" : \" Point \" , \" coordinates \" : [ %f, %f ] " , ops [ 0 ] . lon , ops [ 0 ] . lat ) ;
} else {
printf ( " \" type \" : \" MultiPoint \" , \" coordinates \" : [ " ) ;
2016-03-25 19:20:32 +00:00
for ( size_t i = 0 ; i < ops . size ( ) ; i + + ) {
2015-10-09 19:41:28 +00:00
if ( i ! = 0 ) {
printf ( " , " ) ;
}
printf ( " [ %f, %f ] " , ops [ i ] . lon , ops [ i ] . lat ) ;
}
printf ( " ] " ) ;
}
2016-04-22 20:27:03 +00:00
} else if ( feat . type = = VT_LINE ) {
2015-10-09 19:41:28 +00:00
int movetos = 0 ;
2016-03-25 19:20:32 +00:00
for ( size_t i = 0 ; i < ops . size ( ) ; i + + ) {
2015-10-09 19:41:28 +00:00
if ( ops [ i ] . op = = VT_MOVETO ) {
movetos + + ;
}
}
if ( movetos < 2 ) {
printf ( " \" type \" : \" LineString \" , \" coordinates \" : [ " ) ;
2016-03-25 19:20:32 +00:00
for ( size_t i = 0 ; i < ops . size ( ) ; i + + ) {
2015-10-09 19:41:28 +00:00
if ( i ! = 0 ) {
printf ( " , " ) ;
}
printf ( " [ %f, %f ] " , ops [ i ] . lon , ops [ i ] . lat ) ;
}
printf ( " ] " ) ;
} else {
printf ( " \" type \" : \" MultiLineString \" , \" coordinates \" : [ [ " ) ;
int state = 0 ;
2016-03-25 19:20:32 +00:00
for ( size_t i = 0 ; i < ops . size ( ) ; i + + ) {
2015-10-09 19:41:28 +00:00
if ( ops [ i ] . op = = VT_MOVETO ) {
if ( state = = 0 ) {
printf ( " [ %f, %f ] " , ops [ i ] . lon , ops [ i ] . lat ) ;
state = 1 ;
} else {
printf ( " ], [ " ) ;
printf ( " [ %f, %f ] " , ops [ i ] . lon , ops [ i ] . lat ) ;
state = 1 ;
}
} else {
printf ( " , [ %f, %f ] " , ops [ i ] . lon , ops [ i ] . lat ) ;
}
}
printf ( " ] ] " ) ;
}
2016-04-22 20:27:03 +00:00
} else if ( feat . type = = VT_POLYGON ) {
2016-04-27 22:09:06 +00:00
std : : vector < std : : vector < lonlat > > rings ;
2015-10-09 23:45:34 +00:00
std : : vector < double > areas ;
2015-10-09 19:41:28 +00:00
2016-03-25 19:20:32 +00:00
for ( size_t i = 0 ; i < ops . size ( ) ; i + + ) {
2015-10-09 23:45:34 +00:00
if ( ops [ i ] . op = = VT_MOVETO ) {
2016-04-27 22:09:06 +00:00
rings . push_back ( std : : vector < lonlat > ( ) ) ;
2015-10-09 23:45:34 +00:00
areas . push_back ( 0 ) ;
}
int n = rings . size ( ) - 1 ;
if ( n > = 0 ) {
2016-05-10 19:13:03 +00:00
if ( ops [ i ] . op = = VT_CLOSEPATH ) {
rings [ n ] . push_back ( rings [ n ] [ 0 ] ) ;
} else {
rings [ n ] . push_back ( ops [ i ] ) ;
}
2015-10-09 23:45:34 +00:00
}
2017-05-05 17:56:50 +00:00
2017-05-05 18:22:40 +00:00
if ( i + 1 > = ops . size ( ) | | ops [ i + 1 ] . op = = VT_MOVETO ) {
2017-05-05 17:56:50 +00:00
if ( ops [ i ] . op ! = VT_CLOSEPATH ) {
2017-05-12 18:15:27 +00:00
static bool warned = false ;
if ( ! warned ) {
fprintf ( stderr , " Ring does not end with closepath (ends with %d) \n " , ops [ i ] . op ) ;
if ( ! force ) {
exit ( EXIT_FAILURE ) ;
}
warned = true ;
2017-05-05 17:56:50 +00:00
}
}
}
2015-10-09 23:45:34 +00:00
}
int outer = 0 ;
2016-03-25 19:20:32 +00:00
for ( size_t i = 0 ; i < rings . size ( ) ; i + + ) {
2016-05-10 19:13:03 +00:00
long double area = 0 ;
2016-03-25 19:20:32 +00:00
for ( size_t k = 0 ; k < rings [ i ] . size ( ) ; k + + ) {
2015-10-09 23:45:34 +00:00
if ( rings [ i ] [ k ] . op ! = VT_CLOSEPATH ) {
2016-05-10 19:13:03 +00:00
area + = rings [ i ] [ k ] . x * rings [ i ] [ ( k + 1 ) % rings [ i ] . size ( ) ] . y ;
area - = rings [ i ] [ k ] . y * rings [ i ] [ ( k + 1 ) % rings [ i ] . size ( ) ] . x ;
2015-10-09 23:45:34 +00:00
}
}
areas [ i ] = area ;
2016-05-10 19:13:03 +00:00
if ( areas [ i ] > = 0 | | i = = 0 ) {
2015-10-09 23:45:34 +00:00
outer + + ;
}
// printf("area %f\n", area / .00000274 / .00000274);
}
if ( outer > 1 ) {
printf ( " \" type \" : \" MultiPolygon \" , \" coordinates \" : [ [ [ " ) ;
} else {
printf ( " \" type \" : \" Polygon \" , \" coordinates \" : [ [ " ) ;
}
int state = 0 ;
2016-03-25 19:20:32 +00:00
for ( size_t i = 0 ; i < rings . size ( ) ; i + + ) {
2017-05-05 17:56:50 +00:00
if ( i = = 0 & & areas [ i ] < 0 ) {
2017-05-12 18:15:27 +00:00
static bool warned = false ;
if ( ! warned ) {
fprintf ( stderr , " Polygon begins with an inner ring \n " ) ;
if ( ! force ) {
exit ( EXIT_FAILURE ) ;
}
warned = true ;
2017-05-05 17:56:50 +00:00
}
}
2016-05-10 19:13:03 +00:00
if ( areas [ i ] > = 0 ) {
2015-10-09 23:45:34 +00:00
if ( state ! = 0 ) {
// new multipolygon
printf ( " ] ], [ [ " ) ;
}
state = 1 ;
}
if ( state = = 2 ) {
// new ring in the same polygon
printf ( " ], [ " ) ;
}
2016-03-25 19:20:32 +00:00
for ( size_t j = 0 ; j < rings [ i ] . size ( ) ; j + + ) {
2015-10-09 23:45:34 +00:00
if ( rings [ i ] [ j ] . op ! = VT_CLOSEPATH ) {
if ( j ! = 0 ) {
printf ( " , " ) ;
}
printf ( " [ %f, %f ] " , rings [ i ] [ j ] . lon , rings [ i ] [ j ] . lat ) ;
2015-10-28 21:34:57 +00:00
} else {
if ( j ! = 0 ) {
printf ( " , " ) ;
}
printf ( " [ %f, %f ] " , rings [ i ] [ 0 ] . lon , rings [ i ] [ 0 ] . lat ) ;
2015-10-09 23:45:34 +00:00
}
}
state = 2 ;
}
if ( outer > 1 ) {
printf ( " ] ] ] " ) ;
} else {
printf ( " ] ] " ) ;
}
2015-10-09 19:41:28 +00:00
}
printf ( " } } \n " ) ;
2014-10-23 22:40:27 +00:00
}
2015-10-31 00:30:18 +00:00
if ( describe ) {
printf ( " ] } \n " ) ;
}
2014-10-23 22:40:27 +00:00
}
2015-10-09 19:41:28 +00:00
printf ( " ] } \n " ) ;
2014-10-23 22:40:27 +00:00
}
2017-02-27 18:10:28 +00:00
void decode ( char * fname , int z , unsigned x , unsigned y , std : : set < std : : string > const & to_decode ) {
2014-10-23 22:40:27 +00:00
sqlite3 * db ;
2014-10-27 23:00:16 +00:00
int oz = z ;
unsigned ox = x , oy = y ;
2014-10-23 22:40:27 +00:00
2016-03-22 23:50:01 +00:00
int fd = open ( fname , O_RDONLY ) ;
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 ) ;
2017-02-27 18:10:28 +00:00
handle ( s , z , x , y , 1 , to_decode ) ;
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 " ) ;
}
close ( fd ) ;
} else {
perror ( fname ) ;
}
2014-10-23 22:40:27 +00:00
if ( sqlite3_open ( fname , & db ) ! = SQLITE_OK ) {
2015-06-03 18:21:40 +00:00
fprintf ( stderr , " %s: %s \n " , fname , sqlite3_errmsg ( db ) ) ;
2014-10-23 22:40:27 +00:00
exit ( EXIT_FAILURE ) ;
}
2015-10-19 18:12:11 +00:00
if ( z < 0 ) {
2016-01-28 22:06:51 +00:00
printf ( " { \" type \" : \" FeatureCollection \" , \" properties \" : { \n " ) ;
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 ) ;
}
int within = 0 ;
while ( sqlite3_step ( stmt2 ) = = SQLITE_ROW ) {
if ( within ) {
printf ( " , \n " ) ;
}
within = 1 ;
const unsigned char * name = sqlite3_column_text ( stmt2 , 0 ) ;
const unsigned char * value = sqlite3_column_text ( stmt2 , 1 ) ;
printq ( ( char * ) name ) ;
printf ( " : " ) ;
printq ( ( char * ) value ) ;
}
sqlite3_finalize ( stmt2 ) ;
2017-01-24 22:14:10 +00:00
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; " ;
2014-10-27 23:00:16 +00:00
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 ) ;
}
2014-10-23 22:40:27 +00:00
2017-01-24 22:14:10 +00:00
sqlite3_bind_int ( stmt , 1 , minzoom ) ;
sqlite3_bind_int ( stmt , 2 , maxzoom ) ;
2016-01-28 22:06:51 +00:00
printf ( " \n }, \" features \" : [ \n " ) ;
2014-10-23 22:40:27 +00:00
2016-01-28 22:06:51 +00:00
within = 0 ;
2014-10-27 23:00:16 +00:00
while ( sqlite3_step ( stmt ) = = SQLITE_ROW ) {
2015-10-19 18:12:11 +00:00
if ( within ) {
printf ( " , \n " ) ;
}
within = 1 ;
2014-10-27 23:00:16 +00:00
int len = sqlite3_column_bytes ( stmt , 0 ) ;
2016-05-03 22:48:42 +00:00
int tz = sqlite3_column_int ( stmt , 1 ) ;
int tx = sqlite3_column_int ( stmt , 2 ) ;
int ty = sqlite3_column_int ( stmt , 3 ) ;
ty = ( 1LL < < tz ) - 1 - ty ;
2014-10-27 23:00:16 +00:00
const char * s = ( const char * ) sqlite3_column_blob ( stmt , 0 ) ;
2014-10-23 22:40:27 +00:00
2017-02-27 18:10:28 +00:00
handle ( std : : string ( s , len ) , tz , tx , ty , 1 , to_decode ) ;
2014-10-27 23:00:16 +00:00
}
2014-10-23 22:40:27 +00:00
2015-10-19 18:12:11 +00:00
printf ( " ] } \n " ) ;
2014-10-27 23:00:16 +00:00
sqlite3_finalize ( stmt ) ;
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 ) ;
}
2017-02-27 18:10:28 +00:00
handle ( std : : string ( s , len ) , z , x , y , 0 , to_decode ) ;
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-02-27 18:10:28 +00:00
fprintf ( stderr , " Usage: %s [-t 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 ;
2014-10-23 22:40:27 +00:00
2017-05-05 17:56:50 +00:00
while ( ( i = getopt ( argc , argv , " t:Z:z:l:f " ) ) ! = - 1 ) {
2016-06-28 22:18:27 +00:00
switch ( i ) {
case ' t ' :
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-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-02-27 18:10:28 +00:00
decode ( argv [ optind ] , atoi ( argv [ optind + 1 ] ) , atoi ( argv [ optind + 2 ] ) , atoi ( argv [ optind + 3 ] ) , to_decode ) ;
2015-10-19 18:12:11 +00:00
} else if ( argc = = optind + 1 ) {
2017-02-27 18:10:28 +00:00
decode ( argv [ optind ] , - 1 , - 1 , - 1 , to_decode ) ;
2015-10-19 18:12:11 +00:00
} else {
2014-10-23 22:40:27 +00:00
usage ( argv ) ;
}
return 0 ;
}