[go: up one dir, main page]

Menu

[b9cce2]: / src / metatile.c  Maximize  Restore  History

Download this file

194 lines (175 with data), 6.1 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
/*
* viking -- GPS Data and Topo Analyzer, Explorer, and Manager
*
* Copyright (C) 2014, Rob Norris <rw_norris@hotmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/*
* Mostly imported from https://github.com/openstreetmap/mod_tile/
* Release 0.4
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include "metatile.h"
/**
* metatile.h
*/
#define META_MAGIC "META"
#define META_MAGIC_COMPRESSED "METZ"
struct entry {
int offset;
int size;
};
struct meta_layout {
char magic[4]; // META_MAGIC or META_MAGIC_COMPRESSED
int count; // METATILE ^ 2
int x, y, z; // lowest x,y of this metatile, plus z
struct entry index[]; // count entries
// Followed by the tile data
// The index offsets are measured from the start of the file
};
// Use this to enable meta-tiles which will render NxN tiles at once
// Note: This should be a power of 2 (2, 4, 8, 16 ...)
#define METATILE (8)
/**
* xyz_to_meta:
* Based on function from mod_tile/src/store_file_utils.c
*
* Returns the path to the meta-tile and the offset within the meta-tile
*/
int xyz_to_meta(char *path, size_t len, const char *dir, int x, int y, int z)
{
unsigned char i, hash[5], offset, mask;
// Each meta tile winds up in its own file, with several in each leaf directory
// the .meta tile name is based on the sub-tile at (0,0)
mask = METATILE - 1;
offset = (x & mask) * METATILE + (y & mask);
x &= ~mask;
y &= ~mask;
for (i=0; i<5; i++) {
hash[i] = ((x & 0x0f) << 4) | (y & 0x0f);
x >>= 4;
y >>= 4;
}
snprintf(path, len, "%s/%d/%u/%u/%u/%u/%u.meta", dir, z, hash[4], hash[3], hash[2], hash[1], hash[0]);
return offset;
}
/**
* metatile_read:
* From function in mod_tile/src/store_file.c
* Slightly reworked to use simplified xyz_to_meta() above
*
* Reads into buf upto size specified by sz
*
* Returns whether the file is in a compressed format (possibly only gzip)
*
* Error messages returned in log_msg
*/
int metatile_read(const char *dir, int x, int y, int z, char *buf, size_t sz, int * compressed, char * log_msg)
{
int ignored;
char path[PATH_MAX];
int meta_offset, fd;
unsigned int pos;
unsigned int header_len = sizeof(struct meta_layout) + METATILE*METATILE*sizeof(struct entry);
struct meta_layout *meta = (struct meta_layout *)malloc(header_len);
size_t file_offset, tile_size;
meta_offset = xyz_to_meta(path, sizeof(path), dir, x, y, z);
fd = open(path, O_RDONLY);
if (fd < 0) {
ignored = snprintf(log_msg,PATH_MAX - 1, "Could not open metatile %s. Reason: %s\n", path, strerror(errno));
free(meta);
if ( (size_t)ignored > sizeof(path) ) return -1; // Use 'ignored' at least once to silence the compiler
return -1;
}
pos = 0;
while (pos < header_len) {
size_t len = header_len - pos;
int got = read(fd, ((unsigned char *) meta) + pos, len);
if (got < 0) {
ignored = snprintf(log_msg,PATH_MAX - 1, "Failed to read complete header for metatile %s Reason: %s\n", path, strerror(errno));
close(fd);
free(meta);
return -2;
} else if (got > 0) {
pos += got;
} else {
break;
}
}
if (pos < header_len) {
ignored = snprintf(log_msg,PATH_MAX - 1, "Meta file %s too small to contain header\n", path);
close(fd);
free(meta);
return -3;
}
if (memcmp(meta->magic, META_MAGIC, strlen(META_MAGIC))) {
if (memcmp(meta->magic, META_MAGIC_COMPRESSED, strlen(META_MAGIC_COMPRESSED))) {
ignored = snprintf(log_msg,PATH_MAX - 1, "Meta file %s header magic mismatch\n", path);
close(fd);
free(meta);
return -4;
} else {
*compressed = 1;
}
} else *compressed = 0;
// Currently this code only works with fixed metatile sizes (due to xyz_to_meta above)
if (meta->count != (METATILE * METATILE)) {
ignored = snprintf(log_msg, PATH_MAX - 1, "Meta file %s header bad count %d != %d\n", path, meta->count, METATILE * METATILE);
free(meta);
close(fd);
return -5;
}
file_offset = meta->index[meta_offset].offset;
tile_size = meta->index[meta_offset].size;
free(meta);
if (tile_size > sz) {
ignored = snprintf(log_msg, PATH_MAX - 1, "Truncating tile %zd to fit buffer of %zd\n", tile_size, sz);
tile_size = sz;
close(fd);
return -6;
}
if (lseek(fd, file_offset, SEEK_SET) < 0) {
ignored = snprintf(log_msg, PATH_MAX - 1, "Meta file %s seek error: %s\n", path, strerror(errno));
close(fd);
return -7;
}
pos = 0;
while (pos < tile_size) {
size_t len = tile_size - pos;
int got = read(fd, buf + pos, len);
if (got < 0) {
ignored = snprintf(log_msg, PATH_MAX - 1, "Failed to read data from file %s. Reason: %s\n", path, strerror(errno));
close(fd);
return -8;
} else if (got > 0) {
pos += got;
} else {
break;
}
}
close(fd);
return pos;
}