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