diff options
Diffstat (limited to 'tileserver')
-rw-r--r-- | tileserver/Makefile | 31 | ||||
-rw-r--r-- | tileserver/base64.c | 272 | ||||
-rw-r--r-- | tileserver/base64.h | 25 | ||||
-rw-r--r-- | tileserver/cdb.c | 476 | ||||
-rw-r--r-- | tileserver/cdb.h | 61 | ||||
-rwxr-xr-x | tileserver/cdbtestrun | 149 | ||||
-rw-r--r-- | tileserver/netstring.c | 44 | ||||
-rw-r--r-- | tileserver/netstring.h | 22 | ||||
-rw-r--r-- | tileserver/tileserver.c | 524 | ||||
-rw-r--r-- | tileserver/tileset.c | 208 | ||||
-rw-r--r-- | tileserver/tileset.h | 32 | ||||
-rw-r--r-- | tileserver/util.c | 53 | ||||
-rw-r--r-- | tileserver/util.h | 36 |
13 files changed, 0 insertions, 1933 deletions
diff --git a/tileserver/Makefile b/tileserver/Makefile deleted file mode 100644 index b9ffc302f..000000000 --- a/tileserver/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# Makefile: -# Build tile server. -# -# Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved. -# Email: chris@mysociety.org; WWW: http://www.mysociety.org/ -# -# $Id: Makefile,v 1.1 2006-09-20 15:45:51 chris Exp $ -# - -CFLAGS = -Wall -g -O99 -I/software/include -LDFLAGS = -L/software/lib -LDLIBS = -lfcgi - -# for debugging -#CFLAGS += -DNO_FASTCGI - -SRCS = base64.c cdb.c netstring.c tileserver.c tileset.c util.c -OBJS = $(SRCS:.c=.o) -HDRS = base64.h cdb.h netstring.h tileset.h util.h -TXTS = - -tileserver: Makefile $(OBJS) - $(CC) -o tileserver $(OBJS) $(LDFLAGS) $(LDLIBS) - -clean: - rm -f tileserver $(OBJS) *~ core - -%.o: %.c Makefile - $(CC) $(CFLAGS) -c -o $@ $< - diff --git a/tileserver/base64.c b/tileserver/base64.c deleted file mode 100644 index 08723e31c..000000000 --- a/tileserver/base64.c +++ /dev/null @@ -1,272 +0,0 @@ -/* - * base64.c: - * Base64 and "base64ish" encoding and decoding. - * - * Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved. - * Email: chris@mysociety.org; WWW: http://www.mysociety.org/ - * - */ - -static const char rcsid[] = "$Id: base64.c,v 1.1 2006-09-20 10:25:14 chris Exp $"; - -#include <stdbool.h> -#include <stdint.h> -#include <string.h> - -static const char b64chars[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789" - "+/="; - -static const char b64ishchars[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789" - "-_="; - -/* base64_encode IN INLEN OUT B64ISH NOPAD - * Encode INLEN bytes at IN into the buffer at OUT. The total number of bytes - * written is recorded in *OUTLEN. OUT must have space for at least - * 1 + 4 * (INLEN + 3) / 3 + 1 bytes. Returns a pointer to OUT. This function - * always succeeds. If B64ISH is true, the alternate "base64ish" alphabet is - * used instead of the standard one. If NOPAD is true, "=" padding is not added - * at the end of the transformed buffer. */ -char *base64_encode(const void *in, const size_t inlen, char *out, - const bool b64ish, const bool nopad) { - const char *alphabet; - const uint8_t *b; - char *p; - size_t i; - - alphabet = b64ish ? b64ishchars : b64chars; - b = (const uint8_t*)in; - - for (i = 0, p = out; i < inlen; i += 3) { - uint8_t bb[3] = {0}; - unsigned j; - size_t n, k; - - n = inlen - i; - if (n > 3) n = 3; - for (k = 0; k < n; ++k) bb[k] = b[i + k]; - - j = bb[0] >> 2; - *(p++) = alphabet[j]; - - j = ((bb[0] & 3) << 4) | (bb[1] >> 4); - *(p++) = alphabet[j]; - - if (n == 1) { - if (!nopad) { - *(p++) = '='; - *(p++) = '='; - } - break; - } - - j = ((bb[1] & 0xf) << 2) | (bb[2] >> 6); - *(p++) = alphabet[j]; - if (n == 2) { - if (!nopad) - *(p++) = '='; - break; - } - - j = bb[2] & 0x3f; - *(p++) = alphabet[j]; - } - - *p = 0; - - return out; -} - -/* base64_decode IN OUT OUTLEN B64ISH - * Decode the string at IN into OUT. If B64ISH is true, the alternate - * "base64ish" alphabet is used instead of the standard one. Returns the number - * of characters consumed and saves the number of output bytes decoded in - * *OUTLEN; the number of characters consumed will be smaller than the length - * of the input string if an invalid character was encountered in IN. OUT must - * have space for at least 3 * (INLEN / 4) bytes of output. */ -size_t base64_decode(const char *in, void *out, size_t *outlen, - const bool b64ish) { - const char *alphabet; - uint8_t *b; - size_t inlen = 0, consumed = 0, len = 0, i; - - inlen = strlen(in); - alphabet = b64ish ? b64ishchars : b64chars; - b = (uint8_t*)out; - - for (i = 0; i < inlen; i += 4) { - char bb[5] = "===="; - size_t n, j; - const char *p; - - n = inlen - i; - if (n > 4) n = 4; - memcpy(bb, in + i, n); - - if (!(p = strchr(alphabet, bb[0]))) - break; - j = p - alphabet; - b[len] = (uint8_t)(j << 2); - ++consumed; - - if (!(p = strchr(alphabet, bb[1]))) - break; - j = p - alphabet; - b[len++] |= (uint8_t)(j >> 4); - b[len] = (uint8_t)(j << 4); - ++consumed; - - if ('=' == bb[2]) { - ++consumed; - if ('=' == *p) ++consumed; /* potentially skip last char */ - break; - } else if (!(p = strchr(alphabet, bb[2]))) - break; - j = p - alphabet; - b[len++] |= (uint8_t)(j >> 2); - b[len] = (uint8_t)(j << 6); - ++consumed; - - if ('=' == bb[3]) { - ++consumed; - break; - } else if (!(p = strchr(alphabet, bb[3]))) - break; - j = p - alphabet; - b[len++] |= (uint8_t)j; - ++consumed; - } - - *outlen = len; - return consumed; -} - -#ifdef BASE64_TEST_PROGRAM - -/* - * Small test program -- reads base64-encoded or raw data on standard input, - * and writes on standard output the decoded/encoded version. Driven by - * base64test. - */ - -#include <ctype.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> - -#define err(...) \ - do { \ - fprintf(stderr, "base64test: "); \ - fprintf(stderr, __VA_ARGS__); \ - fprintf(stderr, "\n"); \ - } while (0) -#define die(...) do { err(__VA_ARGS__); exit(1); } while (0) - -struct datum { - void *buf; - size_t len; -}; - -static struct datum *netstring_read(FILE *fp) { - unsigned int len = 0; - int c; - struct datum *d; - -#define FAIL(what) \ - do { \ - if (feof(fp)) \ - die("%s: Premature EOF", what); \ - else \ - die("%s: %s", what, strerror(errno)); \ - } while (0) - - while (EOF != (c = getc(fp))) { - if (isdigit(c)) - len = 10 * len + c - '0'; - else if (c == ':') - break; - else - die("bad character '%c' in netstring length", c); - } - - if (feof(fp) || ferror(fp)) - FAIL("while reading netstring length"); - - if (!(d = malloc((sizeof *d) + len + 1))) - die("malloc: %s", strerror(errno)); - d->buf = (char*)d + (sizeof *d); - d->len = len; - ((char*)d->buf)[len] = 0; /* ensure NUL-terminated */ - - if (d->len != fread(d->buf, 1, d->len, fp)) - FAIL("while reading netstring data"); - - if (EOF == (c = getc(fp))) { - if (feof(fp)) - die("while reading netstring trailer: Premature EOF"); - else - die("while reading netstring trailer: %s", strerror(errno)); - } - - return d; -} - -void netstring_write(FILE *fp, const struct datum *d) { - fprintf(fp, "%u:", (unsigned)d->len); - if (d->len != fwrite(d->buf, 1, d->len, fp)) - die("while writing netstring value: %s", strerror(errno)); - if (1 != fprintf(fp, ",")) - die("while writing netstring trailer: %s", strerror(errno)); -} - -/* main ARGC ARGV - * Entry point. */ -int main(int argc, char *argv[]) { - while (1) { - int c; - struct datum *d, d2; - size_t l; - - if (EOF == (c = getc(stdin))) - die("premature EOF reading command character"); - else if ('X' == c) - break; - - d = netstring_read(stdin); - - switch (c) { - case 'B': /* base64 */ - case 'b': /* base64ish */ - if (!(d2.buf = malloc(d->len))) - die("malloc: %s", strerror(errno)); - l = base64_decode(d->buf, d2.buf, &d2.len, c == 'b'); - netstring_write(stdout, &d2); - free(d2.buf); - break; - - case 'R': /* to base64 */ - case 'r': /* to base64ish */ - if (!(d2.buf = malloc(1 + 4 * (1 + d->len / 3)))) - die("malloc: %s", strerror(errno)); - base64_encode(d->buf, d->len, d2.buf, c == 'r', 0); - d2.len = strlen((char*)d2.buf); - netstring_write(stdout, &d2); - free(d2.buf); - break; - - default: - die("bad command character '%c'", c); - } - - free(d); - fflush(stdout); - } - return 0; -} - -#endif /* BASE64_TEST_PROGRAM */ diff --git a/tileserver/base64.h b/tileserver/base64.h deleted file mode 100644 index 3c61cabc3..000000000 --- a/tileserver/base64.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * base64.h: - * Base64 and "base64ish" encoding and decoding. - * - * Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved. - * Email: chris@mysociety.org; WWW: http://www.mysociety.org/ - * - * $Id: base64.h,v 1.2 2006-09-20 13:22:58 chris Exp $ - * - */ - -#ifndef __BASE64_H_ /* include guard */ -#define __BASE64_H_ - -#include <sys/types.h> - -#include <stdbool.h> - -/* base64.c */ -char *base64_encode(const void *in, const size_t inlen, char *out, - const bool b64ish, const bool nopad); -size_t base64_decode(const char *in, void *out, size_t *outlen, - const bool b64ish); - -#endif /* __BASE64_H_ */ diff --git a/tileserver/cdb.c b/tileserver/cdb.c deleted file mode 100644 index 2f9667f2d..000000000 --- a/tileserver/cdb.c +++ /dev/null @@ -1,476 +0,0 @@ -/* - * cdb.c: - * Read data from Dan-Bernstein-style CDB files. - * - * See: http://cr.yp.to/cdb/cdb.txt -- but note also the statement in - * http://cr.yp.to/cdb/reading.html that, "There may be several records under a - * single key. You can use cdb_findnext to find the next record under this - * key." We don't support (or use) this mode, but it should probably be added - * to the code for completeness. - * - * Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved. - * Email: chris@mysociety.org; WWW: http://www.mysociety.org/ - * - */ - -static const char rcsid[] = "$Id: cdb.c,v 1.6 2006-09-22 12:25:46 francis Exp $"; - -#include <sys/types.h> - -#include <errno.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <sys/stat.h> - -#define CDB_IMPL -#include "cdb.h" - -#ifdef VERBOSE_DEBUGGING -# define debug(...) \ - do { \ - fprintf(stderr, __VA_ARGS__); \ - fprintf(stderr, "\n"); \ - } while (0) -#else -# define debug(...) do { } while (0) -#endif /* VERBOSE_DEBUGGING */ - -/* struct cdb - * Internals of CDB object. */ -struct cdb { - FILE *c_fp; - struct stat c_st; - bool c_close_on_destroy; - struct { - uint32_t off, len; - } c_hashlocs[256]; -}; - -/* Length of the initial portion of the file which gives the hash table - * locations. */ -#define HASHPTR_LEN (256 * 8) - -static size_t do_fread(FILE *fp, void *buf, const size_t len) { - return fread(buf, 1, len, fp); -} - -/* cdb_hash BUF LEN - * Return the hash value of the LEN bytes at BUF. */ -cdb_hash_t cdb_hash(const unsigned char *buf, const size_t len) { - uint32_t h = 5381; - size_t i; - for (i = 0; i < len; ++i) { - h = ((h << 5) + h) ^ buf[i]; - } - return h; -} - -/* cdb_hash_str STRING - * Return the hash value of the given STRING. */ -cdb_hash_t cdb_hash_str(const char *s) { - return cdb_hash((unsigned char*)s, strlen(s)); -} - -/* cdb_hash_datum D - * Return the hash value of the DATUM. */ -cdb_hash_t cdb_hash_datum(const cdb_datum d) { - return cdb_hash(d->cd_buf, d->cd_len); -} - -/* cdb_open_fp FP - * Open a CDB file for which a stdio file pointer FP is available. Returns a - * cdb object on success or NULL on failure, setting cdb_errno. */ -cdb cdb_open_fp(FILE *fp) { - struct cdb *C = NULL, Cz = {0}; - unsigned char buf[HASHPTR_LEN]; - struct stat st; - int i; - -#define FAIL(e) do { cdb_errno = e; goto fail; } while (0) - - if (-1 == fstat(fileno(fp), &st)) - FAIL(errno); - - if (st.st_size < HASHPTR_LEN) - FAIL(CDB_FILE_TOO_SMALL); - - if (!(C = malloc(sizeof *C))) - FAIL(CDB_OUT_OF_MEMORY); - - /* wording conditional like this prevents a warning with 32-bit off_t */ - if ((st.st_size >> 31) > 1) - FAIL(CDB_FILE_TOO_BIG); - - *C = Cz; - C->c_fp = fp; - C->c_st = st; - - if (HASHPTR_LEN != do_fread(fp, buf, HASHPTR_LEN)) { - if (feof(fp)) - FAIL(CDB_FILE_TRUNCATED); - else - FAIL(errno); - } - - for (i = 0; i < 256; ++i) { - memcpy(&C->c_hashlocs[i].off, buf + 8 * i, 4); - memcpy(&C->c_hashlocs[i].len, buf + 8 * i + 4, 4); - /* byte ordering -- CDB is defined as a little-endian format, so - * this is fine on i386, but not elsewhere. */ - /* NB len is in slots not bytes */ - if (C->c_hashlocs[i].off < HASHPTR_LEN - || C->c_hashlocs[i].off > C->c_st.st_size - || C->c_st.st_size - C->c_hashlocs[i].off < C->c_hashlocs[i].len * 8) - FAIL(CDB_BAD_HASHLOC_PTR); - } - - return C; - -fail: - free(C); - return NULL; - -#undef FAIL -} - -/* yuk */ -#define ALIGNMENT 4 /* __alignof(long double) on i386 */ -typedef uint32_t ptr_int_t; /* XXX needs changing on 64-bit architectures */ - -/* cdb_datum_alloc LEN - * Allocate space for a single cdb_datum holding up to LEN bytes. Free with - * cdb_datum_free. Returns the newly-allocated datum on success or NULL on - * failure (out of memory). */ -cdb_datum cdb_datum_alloc(const size_t len) { - cdb_datum d; - if (!(d = malloc((sizeof *d) + ALIGNMENT + len))) { - cdb_errno = CDB_OUT_OF_MEMORY; - return NULL; - } - d->cd_buf = (void*)(((ptr_int_t)d + (sizeof *d) + ALIGNMENT) & ~(ALIGNMENT - 1)); - d->cd_len = len; - return d; -} - -/* cdb_datum_free D - * Free storage associated with D. */ -void cdb_datum_free(cdb_datum d) { - if (d) free(d); -} - -/* cdb_open FILE - * Open the named CDB FILE, returning a cdb object on success or NULL on - * failure, setting cdb_errno. */ -cdb cdb_open(const char *name) { - cdb C = NULL; - FILE *fp; - if (!(fp = fopen(name, "rb"))) { - cdb_errno = errno; - return NULL; - } else if (!(C = cdb_open_fp(fp))) - fclose(fp); - else - C->c_close_on_destroy = 1; - return C; -} - -/* cdb_close C - * Free storage associated with C, and, if it was opened by cdb_open, also - * close the associated file pointer. */ -void cdb_close(cdb C) { - if (!C) return; - if (C->c_close_on_destroy) - fclose(C->c_fp); - free(C); -} - -/* get_slot C OFFSET SLOT HASH WHERE - * Save in *HASH and *WHERE the hash value and offset in the file pointed to by - * the indexed SLOT in the hash table beginning at OFFSET. Returns 0 on success - * or an error code on failure. */ -static cdb_result_t get_slot(cdb C, const uint32_t offset, const uint32_t slot, - cdb_hash_t *hash, uint32_t *where) { - unsigned char buf[8]; - - if (-1 == fseek(C->c_fp, offset + 8 * slot, SEEK_SET)) - return errno; - - if (8 != do_fread(C->c_fp, buf, 8)) { - if (feof(C->c_fp)) - return CDB_FILE_TRUNCATED; - else - return errno; - } - - memcpy(hash, buf, 4); - memcpy(where, buf + 4, 4); - - return 0; -} - -/* cdb_get C KEY - * Look up the database entry identified by KEY. Returns the data retrieved on - * success or NULL on failure, setting cdb_errno. The returned data should be - * freed with cdb_datum_free. */ -/* XXX add a mode where caller supplies storage */ -cdb_datum cdb_get(cdb C, const cdb_datum key) { - cdb_hash_t h, h8, sh; - uint32_t slot0, slot; - cdb_datum val = NULL; - -#define FAIL(e) do { cdb_errno = e; goto fail; } while (0) - - if (key->cd_len > C->c_st.st_size) - FAIL(CDB_NOT_FOUND); - - h = cdb_hash_datum(key); - h8 = h & 0xff; - - debug("key len = %u", (unsigned)key->cd_len); - debug("hash = %08x, hash255 = %02x", (unsigned)h, (unsigned)h8); - - if (!C->c_hashlocs[h8].off || !C->c_hashlocs[h8].len) - FAIL(CDB_NOT_FOUND); - - debug("hash table %u starts at offset %u and has %u slots", - (unsigned)h8, - (unsigned)C->c_hashlocs[h8].off, - (unsigned)C->c_hashlocs[h8].len); - - slot = slot0 = (h >> 8) % C->c_hashlocs[h8].len; - - debug(" %06x %% %u = %u", (unsigned)(h >> 8), C->c_hashlocs[h8].len, (unsigned)slot); - - do { - unsigned char buf[8]; - uint32_t where, keylen, vallen; - cdb_result_t e; - - debug(" looking in slot %u", (unsigned)slot); - - if ((e = get_slot(C, C->c_hashlocs[h8].off, slot, &sh, &where))) - FAIL(e); - - debug(" hash = %08x, offset = %u", (unsigned)sh, (unsigned)where); - - if (sh == h) { - if (0 == where) - FAIL(CDB_NOT_FOUND); - - /* Have a potential slot. Grab the key and value length. */ - if (-1 == fseek(C->c_fp, where, SEEK_SET)) - FAIL(errno); - else if (8 != do_fread(C->c_fp, buf, 8)) { - if (feof(C->c_fp)) - FAIL(CDB_FILE_TRUNCATED); - else - FAIL(errno); - } - - memcpy(&keylen, buf, 4); - memcpy(&vallen, buf + 4, 4); - - debug(" key len = %u, val len = %u", - (unsigned)keylen, (unsigned)vallen); - - if (keylen == key->cd_len) { - size_t i; - for (i = 0; i < key->cd_len; ++i) { - int c; - if (EOF == (c = getc(C->c_fp))) { - if (feof(C->c_fp)) - FAIL(CDB_FILE_TRUNCATED); - else - FAIL(errno); - } else if (c != (int)(((unsigned char*)key->cd_buf)[i])) - break; - } - - if (i == key->cd_len) { - /* Got it. */ - if (!(val = cdb_datum_alloc(vallen + 1))) - FAIL(CDB_OUT_OF_MEMORY); - /* Ensure NUL-terminated. */ - ((char*)val->cd_buf)[vallen] = 0; - val->cd_len--; - if (val->cd_len != do_fread(C->c_fp, val->cd_buf, - val->cd_len)) { - if (feof(C->c_fp)) - FAIL(CDB_FILE_TRUNCATED); - else - FAIL(errno); - } else - return val; - } - } - } - - slot = (slot + 1) % C->c_hashlocs[h8].len; - } while (slot != slot0); - - cdb_errno = CDB_NOT_FOUND; - -fail: - if (val) cdb_datum_free(val); - return NULL; - -#undef FAIL -} - -/* cdb_get_string C STRING - * As for cdb_get, but construct the KEY datum from STRING. */ -cdb_datum cdb_get_string(cdb C, const char *s) { - struct cdb_datum d; - d.cd_len = strlen(s); - d.cd_buf = (void*)s; - return cdb_get(C, &d); -} - -/* cdb_get_buf C BUF LEN - * As for cdb_get, buf construct the KEY datum from BUF and LEN. */ -cdb_datum cdb_get_buf(cdb C, const void *buf, const size_t len) { - struct cdb_datum d; - d.cd_len = len; - d.cd_buf = (void*)buf; - return cdb_get(C, &d); -} - -/* cdb_strerror E - * Return the text of the error message corresponding to E. */ -char *cdb_strerror(const cdb_result_t e) { - if (e > 0) - return strerror(e); - else if (e == 0) - return "Success"; - else { - switch (e) { - case CDB_OUT_OF_MEMORY: - return "Out of memory"; - case CDB_FILE_TOO_SMALL: - return "File is too small to be a valid CDB file"; - case CDB_FILE_TOO_BIG: - return "File is too large to be a valid CDB file"; - case CDB_BAD_HASHLOC_PTR: - return "Bad hash-table location pointer in CDB file header"; - case CDB_BAD_RECORD_PTR: - return "Bad record location pointer in CDB hash table"; - case CDB_NOT_FOUND: - return "Record not found in CDB file"; - default: - return "Unknown CDB internal error code"; - } - } -} - -#ifdef CDB_TEST_PROGRAM - -/* - * Little test program -- reads keys as netstrings on standard input, and - * writes on standard output either "X" for not found, or netstrings giving the - * values of those keys. - */ - -#include <ctype.h> - -#define err(...) \ - do { \ - fprintf(stderr, "cdbtest: "); \ - fprintf(stderr, __VA_ARGS__); \ - fprintf(stderr, "\n"); \ - } while (0) -#define die(...) do { err(__VA_ARGS__); exit(1); } while (0) - -static cdb_datum netstring_read(FILE *fp) { - unsigned int len = 0; - int c; - cdb_datum d; - -#define FAIL(what) \ - do { \ - if (feof(fp)) \ - die("%s: Premature EOF", what); \ - else \ - die("%s: %s", what, strerror(errno)); \ - } while (0) - - while (EOF != (c = getc(fp))) { - if (isdigit(c)) - len = 10 * len + c - '0'; - else if (c == ':') - break; - else - die("bad character '%c' in netstring length", c); - } - - if (feof(fp) || ferror(fp)) - FAIL("while reading netstring length"); - - if (!(d = cdb_datum_alloc(len))) - die("while reading netstring: cdb_datum_alloc(%u): %s", - len, cdb_strerror(cdb_errno)); - - if (d->cd_len != do_fread(fp, d->cd_buf, d->cd_len)) - FAIL("while reading netstring data"); - - if (EOF == (c = getc(fp))) { - if (feof(fp)) - die("while reading netstring trailer: Premature EOF"); - else - die("while reading netstring trailer: %s", strerror(errno)); - } - - return d; -} - -void netstring_write(FILE *fp, const cdb_datum d) { - fprintf(fp, "%u:", (unsigned)d->cd_len); - if (d->cd_len != fwrite(d->cd_buf, 1, d->cd_len, fp)) - die("while writing netstring value: %s", strerror(errno)); - if (1 != fprintf(fp, ",")) - die("while writing netstring trailer: %s", strerror(errno)); -} - -/* main ARGC ARGV - * Entry point. */ -int main(int argc, char *argv[]) { - cdb C; - if (argc != 2) - die("single argument should be name of CDB file"); - else if (!(C = cdb_open(argv[1]))) - die("%s: %s", argv[1], cdb_strerror(cdb_errno)); - - while (1) { - cdb_datum key, val; - int c; - - c = getc(stdin); - if ('X' == c) - break; - else - ungetc(c, stdin); - key = netstring_read(stdin); - - if (!(val = cdb_get(C, key))) { - if (CDB_NOT_FOUND == cdb_errno) - putc('X', stdout); - else - die("cdb_get: %s", cdb_strerror(cdb_errno)); - } else { - netstring_write(stdout, val); - cdb_datum_free(val); - } - fflush(stdout); - - cdb_datum_free(key); - } - - cdb_close(C); - - return 0; -} - -#endif /* CDB_TEST_PROGRAM */ diff --git a/tileserver/cdb.h b/tileserver/cdb.h deleted file mode 100644 index e5959297f..000000000 --- a/tileserver/cdb.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * cdb.h: - * Interface to Dan-Bernstein-style CDB files. - * - * Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved. - * Email: chris@mysociety.org; WWW: http://www.mysociety.org/ - * - * $Id: cdb.h,v 1.4 2006-09-20 14:24:10 chris Exp $ - * - */ - -#ifndef __CDB_H_ /* include guard */ -#define __CDB_H_ - -#include <sys/types.h> - -#include <stdint.h> -#include <stdio.h> - -typedef int cdb_result_t; -typedef uint32_t cdb_hash_t; - -typedef struct cdb_datum { - void *cd_buf; - size_t cd_len; -} *cdb_datum; - -typedef struct cdb *cdb; - -/* error codes */ -#define CDB_OUT_OF_MEMORY -1 -#define CDB_FILE_TOO_SMALL -2 -#define CDB_FILE_TOO_BIG -3 -#define CDB_FILE_TRUNCATED -4 - /* one of the initial 256 pointers pointed outside the file */ -#define CDB_BAD_HASHLOC_PTR -5 - /* a datum pointer pointed outside the file or otherwise somewhere bogus */ -#define CDB_BAD_RECORD_PTR -6 - /* the record wasn't found */ -#define CDB_NOT_FOUND -7 - -#ifndef CDB_IMPL -extern -#endif /* CDB_IMPL */ - cdb_result_t cdb_errno; /* XXX threads */ - -/* cdb.c */ -cdb_hash_t cdb_hash(const unsigned char *buf, const size_t len); -cdb_hash_t cdb_hash_str(const char *s); -cdb_hash_t cdb_hash_datum(const cdb_datum d); -cdb cdb_open_fp(FILE *fp); -cdb cdb_open(const char *name); -void cdb_close(cdb C); -cdb_datum cdb_datum_alloc(const size_t len); -void cdb_datum_free(cdb_datum d); -cdb_datum cdb_get(cdb C, const cdb_datum key); -cdb_datum cdb_get_string(cdb C, const char *str); -cdb_datum cdb_get_buf(cdb C, const void *buf, const size_t len); -char *cdb_strerror(const cdb_result_t e); - -#endif /* __CDB_H_ */ diff --git a/tileserver/cdbtestrun b/tileserver/cdbtestrun deleted file mode 100755 index a83c23e60..000000000 --- a/tileserver/cdbtestrun +++ /dev/null @@ -1,149 +0,0 @@ -#!/usr/bin/perl -w -# -# cdbtestrun: -# Run the CDB test program. -# -# Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved. -# Email: chris@mysociety.org; WWW: http://www.mysociety.org/ -# - -my $rcsid = ''; $rcsid .= '$Id: cdbtestrun,v 1.1 2006-09-19 18:26:35 chris Exp $'; - -use strict; - -use CDB_File; -use IO::Pipe; -use POSIX qw(); - -sub random_string ($) { - my $len = shift; - my $x = ''; - while (length($x) < $len) { - $x .= pack('N', int(rand(0xffffffff))); - } - return substr($x, 0, $len); -} - -my %h; -my $C = new CDB_File("test.cdb", "test.tmp") - or die "test.tmp: $!"; - -my $nkeys = shift(@ARGV); -$nkeys ||= 100000; -die "'$nkeys' is not a valid number of keys" if ($nkeys !~ /^[1-9]\d*$/); - -for (my $i = 0; $i < $nkeys; ++$i) { - my $key; - do { - $key = random_string(1 + int(rand(16))); - } while (exists($h{$key})); - my $val = random_string(int(rand(100))); - - $h{$key} = $val; - $C->insert($key, $val); - - printf STDERR "\rwriting keys: %d/%d", $i, $nkeys - if (0 == ($i % 100)); -} - -print STDERR "\rwriting keys: $nkeys/$nkeys\n"; -print STDERR "finalising database... "; -$C->finish(); -print STDERR "done\n"; - -# Make a pipe to the test program and fork it. -my $p1 = new IO::Pipe(); # parent writes to this -my $p2 = new IO::Pipe(); # and reads from this. - -my $pid = fork(); -if (!defined($pid)) { - die "fork: $!"; -} elsif (0 == $pid) { - $p1->reader(); - POSIX::close(0); - POSIX::dup($p1->fileno()); - $p2->writer(); - POSIX::close(1); - POSIX::dup($p2->fileno()); - -# { exec("valgrind", "./cdbtest", "test.cdb"); } - { exec("./cdbtest", "test.cdb"); } - - print STDERR "exec ./cdbtest: $!\n"; - POSIX::_exit(255); -} - -sub netstring_read ($) { - my $h = shift; - my $len = 0; - while (defined(my $c = $h->getc())) { - if ($c eq 'X' && $len == 0) { - return undef; - } elsif ($c eq ':') { - last; - } elsif ($c !~ /^\d$/) { - die "bad character '$c' in netstring length"; - } else { - $len = $len * 10 + ord($c) - ord('0'); - } - } - - my $buf = ''; - $h->read($buf, $len, 0); - - if ($h->getc() ne ',') { - die "bad character at netstring trailer"; - } - - return $buf; -} - -sub netstring_write ($$) { - my $h = shift; - $h->printf('%d:', length($_[0])); - $h->print($_[0]); - $h->print(','); - $h->flush(); -} - -$p1->writer(); -$p2->reader(); - -print STDERR "child pid = $pid... press enter to continue\n"; -<STDIN>; - -my $n = 0; -foreach my $key (keys(%h)) { - if (rand() < 0.05) { - my $key; - do { - $key = random_string(1 + int(rand(16))); - } while (exists($h{$key})); - netstring_write($p1, $key); - my $val = netstring_read($p2); - if (defined($val)) { - die "test code said value present when it wasn't"; - } - } - - netstring_write($p1, $key); - my $val = netstring_read($p2); - if (!defined($val)) { - die "test code said val was not present when it was"; - } elsif ($val ne $h{$key}) { - print "GOT=$val\n"; - print "WANTED=$val\n"; - die "value mismatch"; - } - - ++$n; - printf STDERR "\rtesting %d/%d", $n, $nkeys - if (0 == ($n % 100)); -} -print STDERR "\rtesting $n/$nkeys\n"; - -$p1->write('X'); -$p1->flush(); -wait(); - -print STDERR "completed with no errors\n"; diff --git a/tileserver/netstring.c b/tileserver/netstring.c deleted file mode 100644 index f6bbc3b72..000000000 --- a/tileserver/netstring.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * netstring.c: - * Write netstrings to strings. - * - * Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved. - * Email: chris@mysociety.org; WWW: http://www.mysociety.org/ - * - */ - -static const char rcsid[] = "$Id: netstring.c,v 1.2 2006-09-20 13:24:08 chris Exp $"; - -#include <sys/types.h> -#include <stdio.h> -#include <string.h> - -/* netstring_write OUT BUFFER LEN - * Write the LEN-byte BUFFER to OUT as a netstring, returning the number of - * bytes. If OUT is NULL, returns the number of bytes required. */ -size_t netstring_write(char *out, const void *buf, const size_t len) { - size_t l = 0; - char dummy[32]; - l += sprintf(out ? out : dummy, "%u:", (unsigned)len); - if (out) memcpy(out + l, buf, len); - l += len; - if (out) out[l] = ','; - ++l; - return l; -} - -/* netstring_write_string OUT STRING - * Write the NUL-terminated STRING to OUT as a netstring, returning the number - * of bytes used. If OUT is NULL, return the number of bytes required. */ -size_t netstring_write_string(char *out, const char *str) { - return netstring_write(out, str, strlen(str)); -} - -/* netstring_write_string OUT I - * Write I to OUT as a decimal integer formatted as a netstring, returning the - * number of bytes used. If OUT is NULL, return the number of bytes required. */ -size_t netstring_write_int(char *out, const int i) { - char str[32]; - sprintf(str, "%d", i); - return netstring_write_string(out, str); -} diff --git a/tileserver/netstring.h b/tileserver/netstring.h deleted file mode 100644 index 83d5aabfc..000000000 --- a/tileserver/netstring.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * netstring.h: - * Write netstrings into strings. - * - * Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved. - * Email: chris@mysociety.org; WWW: http://www.mysociety.org/ - * - * $Id: netstring.h,v 1.1 2006-09-20 10:25:14 chris Exp $ - * - */ - -#ifndef __NETSTRING_H_ /* include guard */ -#define __NETSTRING_H_ - -#include <sys/types.h> - -/* netstring.c */ -size_t netstring_write(char *out, const void *buf, const size_t len); -size_t netstring_write_string(char *out, const char *str); -size_t netstring_write_int(char *out, const int i); - -#endif /* __NETSTRING_H_ */ diff --git a/tileserver/tileserver.c b/tileserver/tileserver.c deleted file mode 100644 index 672319c11..000000000 --- a/tileserver/tileserver.c +++ /dev/null @@ -1,524 +0,0 @@ -/* - * tileserver.c: - * Serve map tiles and information about map tiles. - * - * Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved. - * Email: chris@mysociety.org; WWW: http://www.mysociety.org/ - * - */ - -static const char rcsid[] = "$Id: tileserver.c,v 1.10 2006-09-22 12:25:43 chris Exp $"; - -/* - * This is slightly complicated by the fact that we indirect tile references - * via hashes of the tiles themselves. We support the following queries: - * - * http://host/path/tileserver/TILESET/HASH - * to get an individual tile image in TILESET identified by HASH; - * http://host/path/tileserver/TILESET/E,N/FORMAT - * to get the identity of the tile at (E, N) in TILESET in the given - * FORMAT; - * http://host/path/tileserver/TILESET/W-E,S-N/FORMAT - * to get the identities of the tiles in the block with SW corner (W, S) - * and NE corner (E, N) in the given FORMAT. - * - * What FORMATS should we support? RABX and JSON are the obvious ones I guess. - * Add TEXT for debugging. - */ - -#include <sys/types.h> - -#include <errno.h> -#ifndef NO_FASTCGI -#include <fcgi_stdio.h> -#endif -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> - -#include <sys/stat.h> - -#include "base64.h" -#include "netstring.h" -#include "tileset.h" -#include "util.h" - -/* tiles_basedir - * The configured path to tilesets. */ -static char *tiles_basedir; - -#define HTTP_BAD_REQUEST 400 -#define HTTP_UNAUTHORIZED 401 -#define HTTP_FORBIDDEN 403 -#define HTTP_NOT_FOUND 404 -#define HTTP_INTERNAL_SERVER_ERROR 500 -#define HTTP_NOT_IMPLEMENTED 501 -#define HTTP_SERVICE_UNAVAILABLE 503 - -/* error STATUS TEXT - * Send an error to the client with the given HTTP STATUS and TEXT. */ -void error(int status, const char *s) { - if (status < 100 || status > 999) - status = 500; - printf( - "Status: %03d\r\n" - "Content-Type: text/plain; charset=us-ascii\r\n" - "Content-Length: %u\r\n" - "\r\n" - "%s\n", - status, - strlen(s) + 1, - s); -} - -/* struct request - * Definition of a request we handle. */ -struct request { - char *r_tileset; - enum { - FN_GET_TILE = 0, - FN_GET_TILEIDS - } r_function; - - uint8_t r_tileid[TILEID_LEN]; - - int r_west, r_east, r_south, r_north; - enum { - F_RABX, - F_JSON, - F_TEXT, - F_HTML - } r_format; - - char *r_buf; -}; - -void request_free(struct request *R); - -/* request_parse PATHINFO - * Parse a request from PATHINFO. Returns a request on success or NULL on - * failure. */ -struct request *request_parse(const char *path_info) { - const char *p, *q; - struct request *R = NULL, Rz = {0}; - - /* Some trivial syntax checks. */ - if (!*path_info || *path_info == '/' || !strchr(path_info, '/')) { - err("PATH_INFO of \"%s\" is not a valid request", path_info); - return NULL; - } - - - /* - * TILESET/HASH - * TILESET/E,N/FORMAT - * TILESET/W-E,S-N/FORMAT - */ - - /* Tileset name consists of alphanumerics and hyphen. */ - p = path_info + strspn(path_info, - "0123456789" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "-"); - - if (*p != '/') - return NULL; - - R = xmalloc(sizeof *R); - *R = Rz; - R->r_buf = xmalloc(strlen(path_info) + 1); - R->r_tileset = R->r_buf; - - strncpy(R->r_tileset, path_info, p - path_info); - R->r_tileset[p - path_info] = 0; - - ++p; - - /* Mode. */ - if ((q = strchr(p, '/'))) { - /* Tile IDs request. */ - R->r_function = FN_GET_TILEIDS; - - /* Identify format requested. */ - ++q; - if (!strcmp(q, "RABX")) - R->r_format = F_RABX; - else if (!strcmp(q, "JSON")) - R->r_format = F_JSON; - else if (!strcmp(q, "text")) - R->r_format = F_TEXT; - else if (!strcmp(q, "html")) - R->r_format = F_HTML; - else { - err("request for unknown tile ID result format \"%s\"", q); - goto fail; - } - - if (4 == sscanf(p, "%d-%d,%d-%d", - &R->r_west, &R->r_east, &R->r_south, &R->r_north)) { - if (R->r_west < 0 || R->r_south < 0 - || R->r_east < R->r_west || R->r_north < R->r_south) { - err("area range query has invalid coordinates or order"); - goto fail; - } else - return R; - } else if (2 == sscanf(p, "%d,%d", &R->r_west, &R->r_south)) { - R->r_east = R->r_west; - R->r_north = R->r_south; - if (R->r_west < 0 || R->r_south < 0) { - err("tile ID query has negative coordinates"); - goto fail; - } else - return R; - } - } else { - size_t l; - - /* Tile request. */ - R->r_function = FN_GET_TILE; - if (strlen(p) != TILEID_LEN_B64) - goto fail; - - /* Decode it. Really this is "base64ish", so that we don't have to - * deal with '+' or '/' in the URL. */ - base64_decode(p, R->r_tileid, &l, 1); - if (l != TILEID_LEN) - goto fail; - - return R; - } - -fail: - request_free(R); - return NULL; -} - -/* request_free R - * Free storage allocated for R. */ -void request_free(struct request *R) { - if (!R) return; - xfree(R->r_buf); - xfree(R); -} - -void handle_request(void) { - char *path_info; - struct request *R; - static char *path; - static size_t pathlen; - size_t l; - tileset T; - time_t now; - struct tm *tm; - char date[32]; - const char *last_modified = "Wed, 20 Sep 2006 17:27:40 GMT"; - const unsigned cache_max_age = 365 * 86400; - - /* Date: header is required if we give a 304 Not Modified response. */ - time(&now); - tm = gmtime(&now); - strftime(date, sizeof date, "%a, %d %b %Y %H:%M:%S GMT", tm); - - /* All requests are given via PATH_INFO. */ - if (!(path_info = getenv("PATH_INFO"))) { - error(400, "No request path supplied"); - return; - } - - if ('/' == *path_info) - ++path_info; - - if (!(R = request_parse(path_info))) { - error(400, "Bad request"); - return; - } - - /* So we have a valid request. */ - l = strlen(R->r_tileset) + strlen(tiles_basedir) + 2; - if (pathlen < l) - path = xrealloc(path, pathlen = l); - sprintf(path, "%s/%s", tiles_basedir, R->r_tileset); - - if (!(T = tileset_open(path))) { - error(404, "Tileset not found"); - /* XXX assumption about the nature of the error */ - request_free(R); - return; - } - - /* XXX this is poor -- if the client sends If-Modified-Since: we just - * assume that it hasn't been. We might want to do something more clever at - * some point. */ - if (getenv("HTTP_IF_MODIFIED_SINCE")) { - printf( - "Status: 304 Not Modified\r\n" - "Date: %s\r\n" - "\r\n", date); - tileset_close(T); - request_free(R); - return; - } - - if (FN_GET_TILE == R->r_function) { - /* - * Send a single tile image to the client. - */ - void *buf; - size_t len; - - if ((buf = tileset_get_tile(T, R->r_tileid, &len))) { - printf( - "Content-Type: image/png\r\n" - "Content-Length: %u\r\n" - "Last-Modified: %s\r\n" - "Date: %s\r\n" - "Cache-Control: max-age=%u\r\n" - "\r\n", len, last_modified, date, cache_max_age); - fwrite(buf, 1, len, stdout); - xfree(buf); - } else - error(404, "Tile not found"); - /* XXX error assumption */ - } else if (FN_GET_TILEIDS == R->r_function) { - /* - * Send one or more tile IDs to the client, in some useful format. - */ - unsigned x, y; - static char *buf; - static size_t buflen, n; - unsigned rows, cols; - char *p; - - rows = R->r_north + 1 - R->r_south; - cols = R->r_east + 1 - R->r_west; - n = cols * rows; - if (buflen < n * TILEID_LEN_B64 + 256) - buf = xrealloc(buf, buflen = n * TILEID_LEN_B64 + 256); - - /* Send start of array in whatever format. */ - p = buf; - switch (R->r_format) { - case F_RABX: - /* Format as array of arrays. */ - *(p++) = 'L'; - p += netstring_write_int(p, (int)rows); - break; - - case F_JSON: - /* Ditto. */ - *(p++) = '['; - break; - - case F_TEXT: - /* Space and LF separated matrix so no special leader. */ - break; - - case F_HTML: - strcpy(p, - "<html><head><title>tileserver test</title></head><body>"); - p += strlen(p); - - if (R->r_west > 0) - p += sprintf(p, "<a href=\"../%u-%u,%u-%u/html\">west</a> ", - R->r_west - 1, R->r_east - 1, - R->r_south, R->r_north); - p += sprintf(p, "<a href=\"../%u-%u,%u-%u/html\">east</a> ", - R->r_west + 1, R->r_east + 1, - R->r_south, R->r_north); - - p += sprintf(p, "<a href=\"../%u-%u,%u-%u/html\">north</a> ", - R->r_west, R->r_east, - R->r_south + 1, R->r_north + 1); - if (R->r_south > 0) - p += sprintf(p, "<a href=\"../%u-%u,%u-%u/html\">south</a> ", - R->r_west, R->r_east, - R->r_south - 1, R->r_north - 1); - p += sprintf(p, "<br>"); - break; - } - - /* Iterate over tile IDs. */ - for (y = R->r_north; y >= R->r_south; --y) { - switch (R->r_format) { - case F_RABX: - *(p++) = 'L'; - p += netstring_write_int(p, (int)cols); - break; - - case F_JSON: - *(p++) = '['; - break; - - case F_TEXT: - break; /* nothing */ - - case F_HTML: - break; /* nothing */ - } - - for (x = R->r_west; x <= R->r_east; ++x) { - uint8_t id[TILEID_LEN]; - char idb64[TILEID_LEN_B64 + 1]; - bool isnull = 0; - - if (!(tileset_get_tileid(T, x, y, id))) - isnull = 1; - else - base64_encode(id, TILEID_LEN, idb64, 1, 1); - - if (p + 256 > buf + buflen) { - size_t n; - n = p - buf; - buf = xrealloc(buf, buflen *= 2); - p = buf + n; - } - - switch (R->r_format) { - case F_RABX: - if (isnull) - *(p++) = 'N'; - else { - *(p++) = 'T'; - p += netstring_write_string(p, idb64); - } - break; - - case F_JSON: - if (isnull) { - strcpy(p, "null"); - p += 4; - } else { - *(p++) = '"'; - strcpy(p, idb64); - p += TILEID_LEN_B64; - *(p++) = '"'; - } - if (x < R->r_east) - *(p++) = ','; - break; - - case F_TEXT: - if (isnull) - *(p++) = '-'; - else { - strcpy(p, idb64); - p += TILEID_LEN_B64; - } - if (x < R->r_east) - *(p++) = ' '; - break; - - case F_HTML: - if (isnull) - ; /* not much we can do without the tile sizes */ - else - p += sprintf(p, - "<img title=\"%u,%u\" src=\"../%s\">", - x, y, - idb64); - break; - } - } - - switch (R->r_format) { - case F_RABX: - break; /* no row terminator */ - - case F_JSON: - *(p++) = ']'; - if (y < R->r_north) - *(p++) = ','; - break; - - case F_TEXT: - *(p++) = '\n'; - break; - - case F_HTML: - p += sprintf(p, "<br>"); - break; - } - } - - /* Array terminator. */ - switch (R->r_format) { - case F_RABX: - break; - - case F_JSON: - *(p++) = ']'; - break; - - case F_TEXT: - break; - - case F_HTML: - p += sprintf(p, "</body></html>"); - } - /* NB no terminating NUL */ - - /* Actually send it. */ - printf("Content-Type: "); - switch (R->r_format) { - case F_RABX: - printf("application/octet-stream"); - break; - - case F_JSON: - /* Not really clear what CT to use here but Yahoo use - * "text/javascript" and presumably they've done more testing - * than us.... */ - printf("text/javascript"); - break; - - case F_TEXT: - printf("text/plain; charset=us-ascii"); - break; - - case F_HTML: - printf("text/html; charset=us-ascii"); - break; - } - printf("\r\n" - "Content-Length: %u\r\n" - "Last-Modified: %s\r\n" - "Date: %s\r\n" - "Cache-Control: max-age=%u\r\n" - "\r\n", - (unsigned)(p - buf), last_modified, date, cache_max_age); - - fwrite(buf, 1, p - buf, stdout); - } - - tileset_close(T); - request_free(R); -} - -int main(int argc, char *argv[]) { - struct stat st; - bool initialised = 0; - -#ifndef NO_FASTCGI - while (FCGI_Accept() >= 0) -#endif - { - /* Stupid order since with fcgi_stdio if we haven't called FCGI_Accept - * we don't get any stderr output.... */ - if (!initialised) { - if (argc != 2) - die("single argument is path to tile sets"); - tiles_basedir = argv[1]; - if (-1 == stat(tiles_basedir, &st)) - die("%s: stat: %s", tiles_basedir, strerror(errno)); - else if (!S_ISDIR(st.st_mode)) - die("%s: Not a directory", tiles_basedir); - initialised = 1; - } - - handle_request(); - } - - return 0; -} diff --git a/tileserver/tileset.c b/tileserver/tileset.c deleted file mode 100644 index 866125e30..000000000 --- a/tileserver/tileset.c +++ /dev/null @@ -1,208 +0,0 @@ -/* - * tileset.c: - * Interface to an individual tile set. - * - * Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved. - * Email: chris@mysociety.org; WWW: http://www.mysociety.org/ - * - */ - -static const char rcsid[] = "$Id: tileset.c,v 1.6 2006-09-20 16:44:53 chris Exp $"; - -/* - * Tile sets are stored in directory trees which contain indices of tile - * locations to tile IDs, packed archives of tile images, and indices of where - * each tile image lives in the corresponding packed file. Tile IDs are SHA1 - * digests of the tile contents, enabling efficient storage in the presence of - * repeated tiles. - * - * Note that this doesn't have attractive properties for locality of reference. - * That will need fixing if performance under the current scheme is not - * acceptable. - */ - -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "cdb.h" -#include "tileset.h" -#include "util.h" - -#define TILEID_LEN 20 - -struct tileset { - char *t_path, *t_pathbuf; - cdb t_tileid_idx; - /* Tile IDs are stored in the tile ID database in N-by-N square blocks, - * so that the tile ID for (X, Y) is obtained by getting the block for - * (X / N, Y / N) and looking up (X, Y) within it. The blocking factor is - * (hopefully!) chosen to be about a disk block in size. It is stored in - * the tile ID database. Rather than allocating a specific tile ID for a - * tile which is not present, each information block is preceded by a - * coverage bitmap. */ - unsigned t_blocking; - bool t_first; - unsigned t_x, t_y; - cdb_datum t_block; - /* File pointer open on an image file and the name of the file it's open - * on. */ - char *t_imgfile; - FILE *t_fpimg; -}; - - -/* tileset_open PATH - * Open the tileset at PATH, returning a tileset object on success or NULL on - * failure. */ -tileset tileset_open(const char *path) { - struct tileset *T, Tz = {0}; - cdb_datum d = NULL; - char *s; - int i; - - T = xmalloc(sizeof *T); - *T = Tz; - - T->t_first = 1; - T->t_path = xstrdup(path); - T->t_pathbuf = xmalloc(strlen(path) + sizeof "/tiles/a/b/c/tiles.cdb"); - - /* Open the tile ID index. */ - sprintf(T->t_pathbuf, "%s/index.cdb", T->t_path); - if (!(T->t_tileid_idx = cdb_open(T->t_pathbuf))) - goto fail; - - /* get blocking factor */ - if (!(d = cdb_get_string(T->t_tileid_idx, "blocking"))) - goto fail; - s = (char*)d->cd_buf; - if (!(i = atoi(s)) || i < 0) - goto fail; - T->t_blocking = (unsigned)i; - - cdb_datum_free(d); - - return T; - -fail: - tileset_close(T); - if (d) cdb_datum_free(d); - return NULL; -} - -/* tileset_close T - * Free resources associated with T. */ -void tileset_close(tileset T) { - if (!T) return; - cdb_close(T->t_tileid_idx); - xfree(T->t_path); - xfree(T->t_pathbuf); - xfree(T); -} - -/* tileset_path T - * Return the path used to open T. */ -char *tileset_path(tileset T) { - return T->t_path; -} - -static size_t blockmap_bitmap_len(const unsigned blocking) { - return (blocking * blocking + 8) / 8; -} - -static size_t blockmap_len(const unsigned blocking) { - size_t l; - /* Bitmap of null tiles. */ - l = blockmap_bitmap_len(blocking); - /* Tile IDs themselves */ - l += blocking * blocking * TILEID_LEN; - return l; -} - -/* tileset_get_tileid T X Y ID - * Write into ID the tile ID of the tile at (X, Y) in T, returning true on - * success or false on failure. */ -bool tileset_get_tileid(tileset T, const unsigned x, const unsigned y, - uint8_t *id) { - unsigned x2, y2, off, off0; - uint8_t *b; - - if (T->t_first || T->t_x != x || T->t_y != y) { - /* Grab block from database. */ - char buf[32]; - - T->t_first = 0; - if (T->t_block) cdb_datum_free(T->t_block); - - sprintf(buf, "%u,%u", x / T->t_blocking, y / T->t_blocking); - if (!(T->t_block = cdb_get_string(T->t_tileid_idx, buf))) - return 0; - } - - if (T->t_block->cd_len != blockmap_len(T->t_blocking)) - return 0; - /* XXX also report bogus ID block */ - - b = (uint8_t*)T->t_block->cd_buf; - - x2 = x % T->t_blocking; - y2 = y % T->t_blocking; - off = (x2 + y2 * T->t_blocking); - - /* For a tile not present the corresponding bit in the bitmap is set. */ - if (b[off >> 3] & (1 << (off & 7))) - return 0; - - off0 = blockmap_bitmap_len(T->t_blocking); - memcpy(id, b + off0 + off * TILEID_LEN, TILEID_LEN); - - return 1; -} - -/* tileset_get_tile T ID LEN - * Retrieve the tile identified by ID, writing its length into *LEN and - * returning a malloced buffer containing its contents on success, or returning - * NULL on failure. */ -void *tileset_get_tile(tileset T, const uint8_t *id, size_t *len) { - cdb idx = NULL; - cdb_datum d = NULL; - void *ret = NULL; - unsigned off; - FILE *fp = NULL; - - sprintf(T->t_pathbuf, "%s/tiles/%x/%x/%x/tiles.cdb", - T->t_path, (unsigned)(id[0] >> 4), - (unsigned)(id[0] & 0xf), (unsigned)(id[1] >> 4)); - if (!(idx = cdb_open(T->t_pathbuf))) - return NULL; - /* also maybe report bogus index */ - - if (!(d = cdb_get_buf(idx, id, TILEID_LEN))) - goto fail; - - if (2 != sscanf((char*)d->cd_buf, "%x:%x", &off, len)) - goto fail; - - sprintf(T->t_pathbuf, "%s/tiles/%x/%x/%x/tiles", - T->t_path, (unsigned)(id[0] >> 4), - (unsigned)(id[0] & 0xf), (unsigned)(id[1] >> 4)); - if (!(fp = fopen(T->t_pathbuf, "rb"))) - goto fail; - else if (-1 == fseek(fp, off, SEEK_SET)) - goto fail; - - ret = xmalloc(*len); - if (*len != fread(ret, 1, *len, fp)) { - xfree(ret); - goto fail; - } - -fail: - if (idx) cdb_close(idx); - if (d) cdb_datum_free(d); - if (fp) fclose(fp); - return ret; -} diff --git a/tileserver/tileset.h b/tileserver/tileset.h deleted file mode 100644 index 58b22a5e2..000000000 --- a/tileserver/tileset.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * tileset.h: - * Interface to an individual tile set. - * - * Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved. - * Email: chris@mysociety.org; WWW: http://www.mysociety.org/ - * - * $Id: tileset.h,v 1.2 2006-09-20 13:24:58 chris Exp $ - * - */ - -#ifndef __TILESET_H_ /* include guard */ -#define __TILESET_H_ - -#include <sys/types.h> - -#include <stdbool.h> -#include <stdint.h> - -#define TILEID_LEN 20 -#define TILEID_LEN_B64 27 - -typedef struct tileset *tileset; - -/* tileset.c */ -tileset tileset_open(const char *path); -void tileset_close(tileset T); -bool tileset_get_tileid(tileset T, const unsigned x, const unsigned y, - uint8_t *id); -void *tileset_get_tile(tileset T, const uint8_t *id, size_t *len); - -#endif /* __TILESET_H_ */ diff --git a/tileserver/util.c b/tileserver/util.c deleted file mode 100644 index fbc500438..000000000 --- a/tileserver/util.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * util.c: - * Miscellaneous utility functions. - * - * Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved. - * Email: chris@mysociety.org; WWW: http://www.mysociety.org/ - * - */ - -static const char rcsid[] = "$Id: util.c,v 1.1 2006-09-20 15:45:51 chris Exp $"; - -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "util.h" - -/* - * Wrappers for memory-allocation functions. - */ -void *xmalloc(const size_t s) { - void *v; - if (!(v = malloc(s))) - die("malloc(%u bytes): %s", (unsigned)s, strerror(errno)); - return v; -} - -void *xcalloc(const size_t a, const size_t b) { - void *v; - if (!(v = calloc(a, b))) - die("calloc(%u * %u bytes): %s", - (unsigned)a, (unsigned)b, strerror(errno)); - return v; -} - -void *xrealloc(void *b, const size_t s) { - void *v; - if (!(v = realloc(b, s))) - die("realloc(%u bytes): %s", (unsigned)s, strerror(errno)); - return v; -} - -char *xstrdup(const char *s) { - char *t; - if (!(t = strdup(s))) - die("strdup(%u bytes): %s", (unsigned)(strlen(s) + 1), strerror(errno)); - return t; -} - -void xfree(void *v) { - if (v) free(v); -} diff --git a/tileserver/util.h b/tileserver/util.h deleted file mode 100644 index a2f1f7bc8..000000000 --- a/tileserver/util.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * util.h: - * Utilities. - * - * Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved. - * Email: chris@mysociety.org; WWW: http://www.mysociety.org/ - * - * $Id: util.h,v 1.1 2006-09-20 15:45:51 chris Exp $ - * - */ - -#ifndef __UTIL_H_ /* include guard */ -#define __UTIL_H_ - -/* err FORMAT [ARG ...] - * Write an error message to standard error. */ - /* XXX format this with a timestamp for the error-log? */ -#define err(...) \ - do { \ - fprintf(stderr, "tileserver: "); \ - fprintf(stderr, __VA_ARGS__); \ - fprintf(stderr, "\n"); \ - } while (0) - -/* die FORMAT [ARG ...] - * Write an error message to standard error and exit unsuccessfully. */ -#define die(...) do { err(__VA_ARGS__); exit(1); } while (0) - -/* util.c */ -void *xmalloc(const size_t s); -void *xcalloc(const size_t a, const size_t b); -void *xrealloc(void *b, const size_t s); -char *xstrdup(const char *s); -void xfree(void *v); - -#endif /* __UTIL_H_ */ |