diff options
Diffstat (limited to 'src/stl.c')
| -rw-r--r-- | src/stl.c | 366 |
1 files changed, 366 insertions, 0 deletions
diff --git a/src/stl.c b/src/stl.c new file mode 100644 index 0000000..a4640b3 --- /dev/null +++ b/src/stl.c @@ -0,0 +1,366 @@ +#include "stl.h" + +#include <string.h> +#include <stdint.h> +#include <stdbool.h> +#include <stdio.h> + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) > (b) ? (b) : (a)) + +enum { + STL_ASCII_SOLID, + STL_ASCII_SOLID_NAME, + STL_ASCII_ENDSOLID_CHECK, + STL_ASCII_FACET_NORMAL, + STL_ASCII_FACET_NORMAL_I, + STL_ASCII_FACET_NORMAL_J, + STL_ASCII_FACET_NORMAL_K, + STL_ASCII_OUTER_LOOP, + STL_ASCII_VERTEX_1, + STL_ASCII_VERTEX_1_X, + STL_ASCII_VERTEX_1_Y, + STL_ASCII_VERTEX_1_Z, + STL_ASCII_VERTEX_2, + STL_ASCII_VERTEX_2_X, + STL_ASCII_VERTEX_2_Y, + STL_ASCII_VERTEX_2_Z, + STL_ASCII_VERTEX_3, + STL_ASCII_VERTEX_3_X, + STL_ASCII_VERTEX_3_Y, + STL_ASCII_VERTEX_3_Z, + STL_ASCII_ENDLOOP, + STL_ASCII_ENDFACET, + STL_ASCII_ENDSOLID +}; + +enum { + STL_BIN_HEADER, + STL_BIN_TRIANGLE +}; + +static const uint8_t ascii_fsm[] = { + [STL_ASCII_SOLID] = STL_ASCII_SOLID_NAME, + [STL_ASCII_SOLID_NAME] = STL_ASCII_ENDSOLID_CHECK, + [STL_ASCII_ENDSOLID_CHECK] = STL_ASCII_FACET_NORMAL, + [STL_ASCII_FACET_NORMAL] = STL_ASCII_FACET_NORMAL_I, + [STL_ASCII_FACET_NORMAL_I] = STL_ASCII_FACET_NORMAL_K, + [STL_ASCII_FACET_NORMAL_K] = STL_ASCII_FACET_NORMAL_J, + [STL_ASCII_FACET_NORMAL_J] = STL_ASCII_OUTER_LOOP, + [STL_ASCII_OUTER_LOOP] = STL_ASCII_VERTEX_1, + [STL_ASCII_VERTEX_1] = STL_ASCII_VERTEX_1_X, + [STL_ASCII_VERTEX_1_X] = STL_ASCII_VERTEX_1_Y, + [STL_ASCII_VERTEX_1_Y] = STL_ASCII_VERTEX_1_Z, + [STL_ASCII_VERTEX_1_Z] = STL_ASCII_VERTEX_2, + [STL_ASCII_VERTEX_2] = STL_ASCII_VERTEX_2_X, + [STL_ASCII_VERTEX_2_X] = STL_ASCII_VERTEX_2_Y, + [STL_ASCII_VERTEX_2_Y] = STL_ASCII_VERTEX_2_Z, + [STL_ASCII_VERTEX_2_Z] = STL_ASCII_VERTEX_3, + [STL_ASCII_VERTEX_3] = STL_ASCII_VERTEX_3_X, + [STL_ASCII_VERTEX_3_X] = STL_ASCII_VERTEX_3_Y, + [STL_ASCII_VERTEX_3_Y] = STL_ASCII_VERTEX_3_Z, + [STL_ASCII_VERTEX_3_Z] = STL_ASCII_ENDLOOP, + [STL_ASCII_ENDLOOP] = STL_ASCII_ENDFACET, + [STL_ASCII_ENDFACET] = STL_ASCII_ENDSOLID_CHECK, +}; + +static void +stl_skip_spn(struct stl *stl, const char *spn) +{ + const char *c; + size_t i; + + c = stl->pos; + for (i = 0; i < stl->nleft; i++, c++) { + if (!strchr(spn, *c)) + break; + } + stl->pos += i; + stl->nleft -= i; +} + +static int +stl_read_n(struct stl *stl, size_t n) +{ + size_t cnt; + + if (stl->buflen >= n) + return STL_OK; + + cnt = MIN(n - stl->buflen, stl->nleft); + memcpy(stl->buf + stl->buflen, stl->pos, cnt); + stl->buflen += cnt; + stl->pos += cnt; + stl->nleft -= cnt; + + if (stl->buflen < n) + return STL_INCOMPLETE; + + return STL_OK; +} + +static int +stl_read_expect(struct stl *stl, const char *str, size_t n) +{ + size_t i, cnt; + int rc; + + rc = stl_read_n(stl, n); + if (rc) return rc; + + if (strncmp(stl->buf, str, n)) + return STL_INVALID; + + stl->buflen = 0; + + return STL_OK; +} + +static int +stl_read_until(struct stl *stl, size_t *len, char *any, size_t max) +{ + const char *c; + size_t i; + + c = stl->pos; + for (i = 0; i < stl->nleft; i++, c++) { + if (strchr(any, *c)) { + *len = stl->buflen; + stl->buflen = 0; + return STL_OK; + } + if (stl->buflen >= max) + return STL_INVALID; + stl->buf[stl->buflen++] = *c; + stl->pos++; + stl->nleft--; + } + + return STL_INCOMPLETE; +} + +static int +stl_feed_binary(struct stl *stl, struct stl_result *res, + const void *chunk, size_t size) +{ + int rc; + + if (stl->bin.index == stl->bin.count) + return STL_DONE; + + while (stl->nleft > 0) { + switch (stl->bin.state) { + case STL_BIN_HEADER: + rc = stl_read_n(stl, 84); + if (rc) return rc; + stl->bin.count = le32toh(*(uint32_t *)(stl->buf + 80)); + stl->bin.state = STL_BIN_TRIANGLE; + res->type = STL_RES_HEADER; + res->header.str = stl->buf; + res->header.len = 80; + return STL_OK; + case STL_BIN_TRIANGLE: + rc = stl_read_n(stl, 50); + if (rc) return rc; + res->type = STL_RES_TRIANGLE; + res->tri.normal.x = le32toh(*(uint32_t *)(stl->buf + 0)); + res->tri.normal.y = le32toh(*(uint32_t *)(stl->buf + 4)); + res->tri.normal.z = le32toh(*(uint32_t *)(stl->buf + 8)); + res->tri.vtx[0].x = le32toh(*(uint32_t *)(stl->buf + 12)); + res->tri.vtx[0].y = le32toh(*(uint32_t *)(stl->buf + 16)); + res->tri.vtx[0].z = le32toh(*(uint32_t *)(stl->buf + 20)); + res->tri.vtx[1].x = le32toh(*(uint32_t *)(stl->buf + 24)); + res->tri.vtx[1].y = le32toh(*(uint32_t *)(stl->buf + 28)); + res->tri.vtx[1].z = le32toh(*(uint32_t *)(stl->buf + 32)); + res->tri.vtx[2].x = le32toh(*(uint32_t *)(stl->buf + 36)); + res->tri.vtx[2].y = le32toh(*(uint32_t *)(stl->buf + 40)); + res->tri.vtx[2].z = le32toh(*(uint32_t *)(stl->buf + 40)); + stl->bin.index++; + return STL_OK; + default: + return STL_INVALID_ARG; + } + } + + return STL_INCOMPLETE; +} + +static int +stl_feed_ascii(struct stl *stl, struct stl_result *res, + const void *chunk, size_t size) +{ + char *end; + float val; + size_t len; + int rc; + + while (stl->nleft > 0) { + switch (stl->ascii.state) { + case STL_ASCII_SOLID: + rc = stl_read_expect(stl, "solid ", 6); + if (rc) return rc; + break; + case STL_ASCII_SOLID_NAME: + rc = stl_read_until(stl, &len, "\n", STL_BUFMAX - 1); + if (rc) return rc; + stl->buf[len] = '\0'; + res->type = STL_RES_SOLID_NAME; + res->solid_name.str = stl->buf; + res->solid_name.len = len; + stl->ascii.state = STL_ASCII_FACET_NORMAL; + return STL_OK; + case STL_ASCII_FACET_NORMAL: + if (!stl->buflen) stl_skip_spn(stl, " \t\v\n\r"); + rc = stl_read_expect(stl, "facet normal ", 13); + if (rc) return rc; + break; + case STL_ASCII_OUTER_LOOP: + if (!stl->buflen) stl_skip_spn(stl, " \t\v\n\r"); + rc = stl_read_expect(stl, "outer loop", 10); + if (rc) return rc; + break; + case STL_ASCII_FACET_NORMAL_I: + case STL_ASCII_FACET_NORMAL_J: + case STL_ASCII_FACET_NORMAL_K: + case STL_ASCII_VERTEX_1_X: + case STL_ASCII_VERTEX_1_Y: + case STL_ASCII_VERTEX_1_Z: + case STL_ASCII_VERTEX_2_X: + case STL_ASCII_VERTEX_2_Y: + case STL_ASCII_VERTEX_2_Z: + case STL_ASCII_VERTEX_3_X: + case STL_ASCII_VERTEX_3_Y: + case STL_ASCII_VERTEX_3_Z: + if (!stl->buflen) stl_skip_spn(stl, " \t"); + rc = stl_read_until(stl, &len, " \n", STL_BUFMAX - 1); + if (rc) return rc; + stl->buf[len] = '\0'; + val = strtof(stl->buf, &end); + if (end && *end) return STL_INVALID; + switch (stl->ascii.state) { + case STL_ASCII_FACET_NORMAL_I: + stl->tri.normal.x = val; + break; + case STL_ASCII_FACET_NORMAL_J: + stl->tri.normal.y = val; + break; + case STL_ASCII_FACET_NORMAL_K: + stl->tri.normal.z = val; + break; + case STL_ASCII_VERTEX_1_X: + stl->tri.vtx[0].x = val; + break; + case STL_ASCII_VERTEX_1_Y: + stl->tri.vtx[0].y = val; + break; + case STL_ASCII_VERTEX_1_Z: + stl->tri.vtx[0].z = val; + break; + case STL_ASCII_VERTEX_2_X: + stl->tri.vtx[1].x = val; + break; + case STL_ASCII_VERTEX_2_Y: + stl->tri.vtx[1].y = val; + break; + case STL_ASCII_VERTEX_2_Z: + stl->tri.vtx[1].z = val; + break; + case STL_ASCII_VERTEX_3_X: + stl->tri.vtx[2].x = val; + break; + case STL_ASCII_VERTEX_3_Y: + stl->tri.vtx[2].y = val; + break; + case STL_ASCII_VERTEX_3_Z: + stl->tri.vtx[2].z = val; + break; + } + break; + case STL_ASCII_VERTEX_1: + case STL_ASCII_VERTEX_2: + case STL_ASCII_VERTEX_3: + if (!stl->buflen) stl_skip_spn(stl, " \t\v\n\r"); + rc = stl_read_expect(stl, "vertex", 6); + if (rc) return rc; + break; + case STL_ASCII_ENDLOOP: + if (!stl->buflen) stl_skip_spn(stl, " \t\v\n\r"); + rc = stl_read_expect(stl, "endloop", 7); + if (rc) return rc; + break; + case STL_ASCII_ENDFACET: + if (!stl->buflen) stl_skip_spn(stl, " \t\v\n\r"); + rc = stl_read_expect(stl, "endfacet", 8); + if (rc) return rc; + res->type = STL_RES_TRIANGLE; + res->tri = stl->tri; + stl->ascii.state = STL_ASCII_ENDSOLID_CHECK; + return STL_OK; + case STL_ASCII_ENDSOLID_CHECK: + if (!stl->buflen) stl_skip_spn(stl, " \t\v\n\r"); + rc = stl_read_expect(stl, "endsolid", 8); + if (!rc) return STL_DONE; + break; + defualt: + return STL_INVALID_ARG; + }; + stl->ascii.state = ascii_fsm[stl->ascii.state]; + } + + return STL_INCOMPLETE; +} + +void +stl_init(struct stl *stl, int type) +{ + stl->type = type; + stl->buflen = 0; + stl->chunk = NULL; + stl->pos = NULL; + stl->nleft = 0; +} + +int +stl_feed(struct stl *stl, struct stl_result *res, + const void *chunk, size_t size) +{ + size_t cnt; + int rc; + + if (stl->chunk != chunk) { + if (stl->nleft > 0) + return STL_INVALID; + stl->chunk = chunk; + stl->pos = stl->chunk; + stl->nleft = size; + } + + if (stl->type == STL_TYPE_DETECT) { + rc = stl_read_expect(stl, "solid ", 6); + if (rc == STL_INCOMPLETE) + return STL_INCOMPLETE; + if (rc == STL_OK) { + printf("ascii file\n"); + stl->type = STL_TYPE_ASCII; + stl->ascii.state = STL_ASCII_SOLID_NAME; + } else { + printf("binary file\n"); + stl->type = STL_TYPE_BINARY; + stl->bin.state = STL_BIN_HEADER; + stl->bin.index = 0; + stl->bin.count = SIZE_MAX; + } + res->type = STL_RES_FILETYPE; + res->filetype = stl->type; + return STL_OK; + } + + switch (stl->type) { + case STL_TYPE_ASCII: + return stl_feed_ascii(stl, res, chunk, size); + case STL_TYPE_BINARY: + return stl_feed_binary(stl, res, chunk, size); + default: + return STL_INVALID_ARG; + } +} |
