File size: 2,802 Bytes
38adf92
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <errno.h>
#include "dims.h"

static int find(const char **a, int n, const char *s) {
    for (int i = 0; i < n; i++) if (!strcmp(a[i], s)) return i;
    return -1;
}

static int fail(const char *status, const char *msg) {
    printf("Status: %s\r\nContent-Type: text/plain\r\n\r\n%s\n", status, msg);
    return 0;
}

int main(void) {
    char q[256] = "";
    const char *e = getenv("QUERY_STRING");
    if (e) strncpy(q, e, sizeof q - 1);

    char s[32] = "", c[32] = ""; int t = -1, z = -1;
    for (char *tok = strtok(q, "&"); tok; tok = strtok(NULL, "&")) {
        char *eq = strchr(tok, '='); if (!eq) continue; *eq = 0; char *v = eq + 1;
        if (!strcmp(tok, "s")) strncpy(s, v, 31);
        else if (!strcmp(tok, "c")) strncpy(c, v, 31);
        else if (!strcmp(tok, "t") || !strcmp(tok, "z")) {
            char *end; errno = 0;
            unsigned long u = strtoul(v, &end, 10);
            int val = (v[0] >= '0' && v[0] <= '9' && !errno && !*end && u <= 1000000) ? (int)u : -1;
            if (tok[0] == 't') t = val; else z = val;
        }
    }

    int si = find(SC, NSC, s), ci = find(CH, NCH, c);
    if (si < 0 || ci < 0 || t < 0 || t >= NT || z < 0 || z >= NZ)
        return fail("404", "bad params");
    long idx = TILE_INDEX(si, ci, t, z);

    const char *dir = getenv("DATA_DIR");
    if (!dir) dir = "/www";
    char path[1024];
    int64_t off, nxt;

    snprintf(path, sizeof path, "%s/offsets.bin", dir);
    FILE *of = fopen(path, "rb");
    if (!of) return fail("500", "no offsets");
    if (fseeko(of, idx * 8, SEEK_SET) != 0 ||
        fread(&off, 8, 1, of) != 1 || fread(&nxt, 8, 1, of) != 1) {
        fclose(of);
        return fail("500", "bad index");
    }
    fclose(of);
    long len = (long)(nxt - off);
    if (off < 0 || len <= 0) return fail("500", "bad offset");

    snprintf(path, sizeof path, "%s/tiles.bin", dir);
    FILE *bf = fopen(path, "rb");
    if (!bf) return fail("500", "no tiles");
    if (fseeko(bf, 0, SEEK_END) != 0 || off + len > ftello(bf) ||
        fseeko(bf, off, SEEK_SET) != 0) {
        fclose(bf);
        return fail("500", "offset out of range");
    }

    printf("Content-Type: image/svg+xml\r\n"
           "Cache-Control: max-age=31536000, immutable\r\n"
           "Content-Length: %ld\r\n\r\n", len);
    fflush(stdout);

    int ch, rc = 0;                      // stdio buffers getc/putc internally
    for (long i = 0; i < len; i++) {
        if ((ch = getc(bf)) == EOF) { rc = 1; break; }     // source truncated / read error
        if (putc(ch, stdout) == EOF) { rc = 1; break; }    // write error / client gone
    }
    if (ferror(bf)) rc = 1;
    fclose(bf);
    if (fflush(stdout) == EOF) rc = 1;
    return rc;
}