#include #include #include #include #include #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; }