2016-04-27 21:19:10 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
2016-08-09 00:14:48 +00:00
|
|
|
#include <string>
|
2016-08-08 22:36:49 +00:00
|
|
|
#include <vector>
|
|
|
|
#include <sqlite3.h>
|
2016-08-30 00:42:46 +00:00
|
|
|
#include <set>
|
|
|
|
#include <map>
|
2016-04-27 21:22:44 +00:00
|
|
|
#include "protozero/varint.hpp"
|
2016-08-08 22:36:49 +00:00
|
|
|
#include "geometry.hpp"
|
2016-08-30 00:42:46 +00:00
|
|
|
#include "mbtiles.hpp"
|
2016-08-08 22:36:49 +00:00
|
|
|
#include "tile.hpp"
|
2016-04-27 21:19:10 +00:00
|
|
|
#include "serial.hpp"
|
|
|
|
|
|
|
|
size_t fwrite_check(const void *ptr, size_t size, size_t nitems, FILE *stream, const char *fname) {
|
|
|
|
size_t w = fwrite(ptr, size, nitems, stream);
|
|
|
|
if (w != nitems) {
|
|
|
|
fprintf(stderr, "%s: Write to temporary file failed: %s\n", fname, strerror(errno));
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
return w;
|
|
|
|
}
|
|
|
|
|
|
|
|
void serialize_int(FILE *out, int n, long long *fpos, const char *fname) {
|
|
|
|
serialize_long_long(out, n, fpos, fname);
|
|
|
|
}
|
|
|
|
|
|
|
|
void serialize_long_long(FILE *out, long long n, long long *fpos, const char *fname) {
|
2016-10-14 22:47:54 +00:00
|
|
|
unsigned long long zigzag = protozero::encode_zigzag64(n);
|
2016-04-27 21:19:10 +00:00
|
|
|
|
2016-07-15 22:00:40 +00:00
|
|
|
serialize_ulong_long(out, zigzag, fpos, fname);
|
|
|
|
}
|
|
|
|
|
|
|
|
void serialize_ulong_long(FILE *out, unsigned long long zigzag, long long *fpos, const char *fname) {
|
2016-04-27 21:19:10 +00:00
|
|
|
while (1) {
|
|
|
|
unsigned char b = zigzag & 0x7F;
|
|
|
|
if ((zigzag >> 7) != 0) {
|
|
|
|
b |= 0x80;
|
|
|
|
if (putc(b, out) == EOF) {
|
|
|
|
fprintf(stderr, "%s: Write to temporary file failed: %s\n", fname, strerror(errno));
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
*fpos += 1;
|
|
|
|
zigzag >>= 7;
|
|
|
|
} else {
|
|
|
|
if (putc(b, out) == EOF) {
|
|
|
|
fprintf(stderr, "%s: Write to temporary file failed: %s\n", fname, strerror(errno));
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
*fpos += 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void serialize_byte(FILE *out, signed char n, long long *fpos, const char *fname) {
|
|
|
|
fwrite_check(&n, sizeof(signed char), 1, out, fname);
|
|
|
|
*fpos += sizeof(signed char);
|
|
|
|
}
|
|
|
|
|
|
|
|
void serialize_uint(FILE *out, unsigned n, long long *fpos, const char *fname) {
|
|
|
|
fwrite_check(&n, sizeof(unsigned), 1, out, fname);
|
|
|
|
*fpos += sizeof(unsigned);
|
|
|
|
}
|
|
|
|
|
|
|
|
void deserialize_int(char **f, int *n) {
|
|
|
|
long long ll;
|
|
|
|
deserialize_long_long(f, &ll);
|
|
|
|
*n = ll;
|
|
|
|
}
|
|
|
|
|
|
|
|
void deserialize_long_long(char **f, long long *n) {
|
|
|
|
unsigned long long zigzag = 0;
|
2016-07-15 22:00:40 +00:00
|
|
|
deserialize_ulong_long(f, &zigzag);
|
2016-10-14 22:47:54 +00:00
|
|
|
*n = protozero::decode_zigzag64(zigzag);
|
2016-07-15 22:00:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void deserialize_ulong_long(char **f, unsigned long long *zigzag) {
|
|
|
|
*zigzag = 0;
|
2016-04-27 21:19:10 +00:00
|
|
|
int shift = 0;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
if ((**f & 0x80) == 0) {
|
2016-07-15 22:00:40 +00:00
|
|
|
*zigzag |= ((unsigned long long) **f) << shift;
|
2016-04-27 21:19:10 +00:00
|
|
|
*f += 1;
|
|
|
|
shift += 7;
|
|
|
|
break;
|
|
|
|
} else {
|
2016-07-15 22:00:40 +00:00
|
|
|
*zigzag |= ((unsigned long long) (**f & 0x7F)) << shift;
|
2016-04-27 21:19:10 +00:00
|
|
|
*f += 1;
|
|
|
|
shift += 7;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void deserialize_uint(char **f, unsigned *n) {
|
|
|
|
memcpy(n, *f, sizeof(unsigned));
|
|
|
|
*f += sizeof(unsigned);
|
|
|
|
}
|
|
|
|
|
|
|
|
void deserialize_byte(char **f, signed char *n) {
|
|
|
|
memcpy(n, *f, sizeof(signed char));
|
|
|
|
*f += sizeof(signed char);
|
|
|
|
}
|
|
|
|
|
|
|
|
int deserialize_long_long_io(FILE *f, long long *n, long long *geompos) {
|
|
|
|
unsigned long long zigzag = 0;
|
2016-07-15 22:00:40 +00:00
|
|
|
int ret = deserialize_ulong_long_io(f, &zigzag, geompos);
|
2016-10-14 22:47:54 +00:00
|
|
|
*n = protozero::decode_zigzag64(zigzag);
|
2016-07-15 22:00:40 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int deserialize_ulong_long_io(FILE *f, unsigned long long *zigzag, long long *geompos) {
|
|
|
|
*zigzag = 0;
|
2016-04-27 21:19:10 +00:00
|
|
|
int shift = 0;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
int c = getc(f);
|
|
|
|
if (c == EOF) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
(*geompos)++;
|
|
|
|
|
|
|
|
if ((c & 0x80) == 0) {
|
2016-07-15 22:00:40 +00:00
|
|
|
*zigzag |= ((unsigned long long) c) << shift;
|
2016-04-27 21:19:10 +00:00
|
|
|
shift += 7;
|
|
|
|
break;
|
|
|
|
} else {
|
2016-07-15 22:00:40 +00:00
|
|
|
*zigzag |= ((unsigned long long) (c & 0x7F)) << shift;
|
2016-04-27 21:19:10 +00:00
|
|
|
shift += 7;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int deserialize_int_io(FILE *f, int *n, long long *geompos) {
|
|
|
|
long long ll = 0;
|
|
|
|
int ret = deserialize_long_long_io(f, &ll, geompos);
|
|
|
|
*n = ll;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int deserialize_uint_io(FILE *f, unsigned *n, long long *geompos) {
|
|
|
|
if (fread(n, sizeof(unsigned), 1, f) != 1) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
*geompos += sizeof(unsigned);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int deserialize_byte_io(FILE *f, signed char *n, long long *geompos) {
|
|
|
|
int c = getc(f);
|
|
|
|
if (c == EOF) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
*n = c;
|
|
|
|
(*geompos)++;
|
|
|
|
return 1;
|
|
|
|
}
|
2016-08-08 22:36:49 +00:00
|
|
|
|
|
|
|
static void write_geometry(drawvec const &dv, long long *fpos, FILE *out, const char *fname, long long wx, long long wy) {
|
|
|
|
for (size_t i = 0; i < dv.size(); i++) {
|
2016-08-09 00:08:36 +00:00
|
|
|
if (dv[i].op == VT_MOVETO || dv[i].op == VT_LINETO) {
|
2016-08-08 22:36:49 +00:00
|
|
|
serialize_byte(out, dv[i].op, fpos, fname);
|
|
|
|
serialize_long_long(out, dv[i].x - wx, fpos, fname);
|
|
|
|
serialize_long_long(out, dv[i].y - wy, fpos, fname);
|
|
|
|
wx = dv[i].x;
|
|
|
|
wy = dv[i].y;
|
2016-08-09 00:08:36 +00:00
|
|
|
} else {
|
|
|
|
serialize_byte(out, dv[i].op, fpos, fname);
|
2016-08-08 22:36:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-10 22:31:09 +00:00
|
|
|
void serialize_feature(FILE *geomfile, serial_feature *sf, long long *geompos, const char *fname, long long wx, long long wy, bool include_minzoom) {
|
2016-08-08 22:36:49 +00:00
|
|
|
serialize_byte(geomfile, sf->t, geompos, fname);
|
|
|
|
|
2016-11-12 01:37:46 +00:00
|
|
|
long long layer = 0;
|
2016-11-17 01:35:25 +00:00
|
|
|
layer |= sf->layer << 6;
|
|
|
|
layer |= (sf->seq != 0) << 5;
|
2016-11-12 01:37:46 +00:00
|
|
|
layer |= (sf->index != 0) << 4;
|
|
|
|
layer |= (sf->extent != 0) << 3;
|
|
|
|
layer |= sf->has_id << 2;
|
|
|
|
layer |= sf->has_tippecanoe_minzoom << 1;
|
|
|
|
layer |= sf->has_tippecanoe_maxzoom << 0;
|
|
|
|
|
|
|
|
serialize_long_long(geomfile, layer, geompos, fname);
|
2016-11-17 01:35:25 +00:00
|
|
|
if (sf->seq != 0) {
|
|
|
|
serialize_long_long(geomfile, sf->seq, geompos, fname);
|
|
|
|
}
|
2016-08-08 22:36:49 +00:00
|
|
|
if (sf->has_tippecanoe_minzoom) {
|
|
|
|
serialize_int(geomfile, sf->tippecanoe_minzoom, geompos, fname);
|
|
|
|
}
|
|
|
|
if (sf->has_tippecanoe_maxzoom) {
|
|
|
|
serialize_int(geomfile, sf->tippecanoe_maxzoom, geompos, fname);
|
|
|
|
}
|
|
|
|
if (sf->has_id) {
|
|
|
|
serialize_ulong_long(geomfile, sf->id, geompos, fname);
|
|
|
|
}
|
|
|
|
|
|
|
|
serialize_int(geomfile, sf->segment, geompos, fname);
|
|
|
|
|
|
|
|
write_geometry(sf->geometry, geompos, geomfile, fname, wx, wy);
|
|
|
|
serialize_byte(geomfile, VT_END, geompos, fname);
|
2016-11-12 01:37:46 +00:00
|
|
|
if (sf->index != 0) {
|
|
|
|
serialize_ulong_long(geomfile, sf->index, geompos, fname);
|
|
|
|
}
|
|
|
|
if (sf->extent != 0) {
|
|
|
|
serialize_long_long(geomfile, sf->extent, geompos, fname);
|
|
|
|
}
|
2016-08-08 22:36:49 +00:00
|
|
|
|
|
|
|
serialize_int(geomfile, sf->m, geompos, fname);
|
2016-11-17 18:11:59 +00:00
|
|
|
if (sf->m != 0) {
|
|
|
|
serialize_long_long(geomfile, sf->metapos, geompos, fname);
|
|
|
|
}
|
2016-08-09 00:08:36 +00:00
|
|
|
|
|
|
|
if (sf->metapos < 0 && sf->m != sf->keys.size()) {
|
2016-08-09 00:14:48 +00:00
|
|
|
fprintf(stderr, "Internal error: %lld doesn't match %lld\n", (long long) sf->m, (long long) sf->keys.size());
|
2016-08-09 00:08:36 +00:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
2016-08-08 22:36:49 +00:00
|
|
|
for (size_t i = 0; i < sf->keys.size(); i++) {
|
|
|
|
serialize_long_long(geomfile, sf->keys[i], geompos, fname);
|
|
|
|
serialize_long_long(geomfile, sf->values[i], geompos, fname);
|
|
|
|
}
|
|
|
|
|
2016-10-10 22:31:09 +00:00
|
|
|
if (include_minzoom) {
|
|
|
|
serialize_byte(geomfile, sf->feature_minzoom, geompos, fname);
|
|
|
|
}
|
2016-08-08 22:36:49 +00:00
|
|
|
}
|