Spaces:
Sleeping
Sleeping
| 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; | |
| } | |