From 13b65f01132c41be9ab8d9f92c2c5ca605c366d8 Mon Sep 17 00:00:00 2001 From: Louis Burda Date: Sat, 29 May 2021 14:24:31 +0200 Subject: changed repo structure and commited releease files such that default docker-compose worklow commands work in testvm --- src/stlfile.c | 415 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 415 insertions(+) create mode 100644 src/stlfile.c (limited to 'src/stlfile.c') diff --git a/src/stlfile.c b/src/stlfile.c new file mode 100644 index 0000000..88fc430 --- /dev/null +++ b/src/stlfile.c @@ -0,0 +1,415 @@ +#include "stlfile.h" + +static const char wsset[] = " \r\n\t"; +static const struct { + int code; + const char *str; +} kwmap[] = { + { KW_SOLID_BEGIN, "solid" }, + { KW_SOLID_END, "endsolid" }, + { KW_LOOP_BEGIN, "outer loop" }, + { KW_LOOP_END, "endloop" }, + { KW_FACET_BEGIN, "facet normal" }, + { KW_FACET_END, "endfacet" }, + { KW_VERTEX, "vertex" }, +}; + +void +stack_init(struct stack *stack) +{ + stack->cap = 10; + stack->data = checkp(malloc(sizeof(int) * stack->cap)); + stack->count = 0; +} + +void +stack_push(struct stack *stack, int v) +{ + if (stack->count == stack->cap) { + stack->cap *= 2; + stack->data = checkp(realloc(stack->data, sizeof(int) * stack->cap)); + } + + stack->data[stack->count] = v; + stack->count++; +} + +int +stack_pop(struct stack *stack) +{ + if (stack->count == 0) + return -1; + + stack->count--; + return stack->data[stack->count]; +} + +void +stack_free(struct stack *stack) +{ + free(stack->data); +} + +int +stack_ind(struct stack *stack, int search) +{ + int i; + for (i = 0; i < stack->count; i++) + if (stack->data[i] == search) + return i; + return -1; +} + +int +isws(char c) +{ + return c && strchr(wsset, c); +} + +char* +skipws(char *p) +{ + for (; isws(*p); p++); + return p; +} + +char* +consume_arg(char **start, char **end) +{ + char *c, *tmp; + + *start = skipws(*start); + if (!*start) return NULL; + for (c = *start; *c && !isws(*c); c++); + tmp = *start; + *start = c + 1; + *end = c; + return tmp; +} + +int +consume_keyword(char **start) +{ + char *bp; + int i, len; + + bp = skipws(*start); + + for (i = 0; i < ARRSIZE(kwmap); i++) { + len = strlen(kwmap[i].str); + if (!strncmp(kwmap[i].str, bp, len) && (!bp[len] || isws(bp[len]))) { + // printf("GOT: %s\n", kwmap[i].str); + *start = bp + len + (bp[len] ? 1 : 0); + return kwmap[i].code; + } + } + + return KW_UNKNOWN; +} + +#define PARSE_FAIL(...) \ + do { fprintf(stderr, "FORMAT ERR: " __VA_ARGS__); goto fail; } while (0) + +int +parse_file_ascii(struct parseinfo *info, char *buf, size_t len) +{ + char *bp, *arg, *prev, *tmp, *end; + struct stack states; + float farg; + int i, kw; + + stack_init(&states); + + info->type = TYPE_ASCII; + info->loopcount = 0; + + memset(info->header, 0, 80); + + for (i = 0; i < 3; i++) { + info->bbmin[i] = INFINITY; + info->bbmax[i] = -INFINITY; + } + + bp = prev = buf; + while ((kw = consume_keyword(&bp))) { + switch (kw) { + case KW_SOLID_BEGIN: + stack_push(&states, STATE_SOLID); + if (stack_ind(&states, KW_SOLID_BEGIN) != -1) + PARSE_FAIL("Multiple nested solids!\n"); + tmp = bp; + if (!consume_keyword(&bp) && (arg = consume_arg(&bp, &end))) { + info->solidname = strndup(arg, end - arg); + } else { + bp = tmp; + } + break; + case KW_SOLID_END: + if ((kw = stack_pop(&states)) != STATE_SOLID) + PARSE_FAIL("Improper nesting, parent: %s\n", kwmap[kw].str); + tmp = bp; + if (info->solidname && !consume_keyword(&bp) + && (arg = consume_arg(&bp, &end))) { + if (strncmp(info->solidname, arg, end - arg)) + PARSE_FAIL("Solid end/begin names do not match!\n"); + } else { + bp = tmp; + } + break; + case KW_LOOP_BEGIN: + stack_push(&states, STATE_LOOP); + if (stack_ind(&states, KW_LOOP_BEGIN) != -1) + PARSE_FAIL("Multiple nested loops!\n"); + break; + case KW_LOOP_END: + if ((kw = stack_pop(&states)) != STATE_LOOP) + PARSE_FAIL("Improper nesting, parent: %s\n", kwmap[kw].str); + info->loopcount++; + break; + case KW_FACET_BEGIN: + stack_push(&states, STATE_FACET); + if (stack_ind(&states, KW_LOOP_BEGIN) != -1) + PARSE_FAIL("Multiple nested facets!\n"); + for (i = 0; i < 3; i++) { + if (!(arg = consume_arg(&bp, &end))) + PARSE_FAIL("Facet with less than 3 args!\n"); + farg = strtof(arg, &tmp); + if (!isws(*tmp)) + PARSE_FAIL("Facet with invalid arg '%s'!\n", arg); + } + break; + case KW_FACET_END: + if ((kw = stack_pop(&states)) != STATE_FACET) + PARSE_FAIL("Improper nesting, parent: %s\n", kwmap[kw].str); + break; + case KW_VERTEX: + for (i = 0; i < 3; i++) { + if (!(arg = consume_arg(&bp, &end))) + PARSE_FAIL("Vertex with less than 3 args!\n"); + farg = strtof(arg, &tmp); + if (!isws(*tmp)) + PARSE_FAIL("Vertex with invalid arg '%s'!\n", arg); + info->bbmin[i] = MIN(info->bbmin[i], farg); + info->bbmax[i] = MAX(info->bbmax[i], farg); + } + break; + case KW_UNKNOWN: + prev = skipws(prev); + PARSE_FAIL("Expected keyword, got:\n%.*s...\n", 30, prev); + } + prev = bp; + } + + if (states.count) + PARSE_FAIL("Expected keyword, got:\n%.*s...\n", 30, bp); + + stack_free(&states); + return OK; + +fail: + stack_free(&states); + return FAIL; +} + +int +parse_file_bin(struct parseinfo *info, char *buf, size_t len) +{ + char *bp, *end = buf + len; + int i, k, m; + float v; + + info->type = TYPE_BIN; + + if (len < 84) + PARSE_FAIL("Truncated data! (header missing)\n"); + + memcpy(info->header, buf, 80); + + if (strlen(buf + 1)) + info->solidname = checkp(strdup(buf + 1)); + + bp = buf + 80; + info->loopcount = le32toh(*(uint32_t*)bp); + + if (!info->loopcount) { + memset(info->bbmax, 0, sizeof(float) * 3); + memset(info->bbmin, 0, sizeof(float) * 3); + return OK; + } + + for (i = 0; i < 3; i++) { + info->bbmin[i] = INFINITY; + info->bbmax[i] = -INFINITY; + } + + for (i = 0; i < info->loopcount; i++) { + if (bp + 50 > end) + PARSE_FAIL("Truncated data! (loops missing)\n"); + bp += 12; + for (k = 0; k < 3; k++, bp += 12) { + for (m = 0; m < 3; m++) { + v = fle32toh(*(float*)(bp + 4 * m)); + info->bbmin[m] = MIN(info->bbmin[m], v); + info->bbmax[m] = MAX(info->bbmax[m], v); + } + } + bp += 2; + } + + return OK; + +fail: + return FAIL; +} + +int +parse_file(struct parseinfo *info, char *buf, size_t len) +{ + int status; + const char *resp; + char *bp; + + if (info->valid) free_info(info); + + if (len < 7) { + fprintf(stderr, "File too small!\n"); + return FAIL; + } + + info->filesize = len; + + /* check bin vs ascii with first keyword */ + for (bp = buf; isws(*bp); bp++); + status = !strncmp("solid", bp, 5) && isws(bp[5]) + ? parse_file_ascii(info, buf, len) + : parse_file_bin(info, buf, len); + if (status == FAIL) return FAIL; + + if (!info->solidname) info->solidname = checkp(strdup("")); + + if (!info->modelname) { + resp = ask("Please enter your model name: "); + if (strlen(resp) < 4) { + fprintf(stderr, "Model name is too short!\n"); + return FAIL; + } + info->modelname = checkp(strdup(resp)); + } + + info->hash = checkp(strdup(mhash(info->modelname, -1))); + + return OK; +} + +int +save_info(struct parseinfo *info, FILE *f) +{ + size_t nwrote = 0; + int i; + + nwrote += fwrite(&info->type, sizeof(int), 1, f); + nwrote += fwrite(&info->loopcount, sizeof(int), 1, f); + nwrote += fwrite(&info->filesize, sizeof(unsigned), 1, f); + + for (i = 0; i < 3; i++) { + nwrote += fwrite(&info->bbmin[i], sizeof(float), 1, f); + nwrote += fwrite(&info->bbmax[i], sizeof(float), 1, f); + } + + nwrote += fwrite(info->header, 80, 1, f); + + if (nwrote != 10) return FAIL; + + fputstr(f, info->solidname); + fputstr(f, info->hash); + fputstr(f, info->modelname); + + return OK; +} + +int +load_info(struct parseinfo *info, FILE *f) +{ + size_t nread = 0; + int i; + + nread += fread(&info->type, sizeof(int), 1, f); + nread += fread(&info->loopcount, sizeof(int), 1, f); + nread += fread(&info->filesize, sizeof(unsigned), 1, f); + + for (i = 0; i < 3; i++) { + nread += fread(&info->bbmin[i], sizeof(float), 1, f); + nread += fread(&info->bbmax[i], sizeof(float), 1, f); + } + + nread += fread(info->header, 80, 1, f); + + if (nread != 10) return FAIL; + + freadstr(f, &info->solidname); + freadstr(f, &info->hash); + freadstr(f, &info->modelname); + + info->valid = 1; + + return OK; +} + +void +print_info(struct parseinfo *info) +{ + int i, k; + +#define FILTERCHAR(c) ((c) >= 32 ? (c) : ' ') + + printf(" === Model info === \n"); + + printf(" File Size: %u\n", info->filesize); + + if (info->type == TYPE_BIN) { + printf(" Header:\n"); + for (i = 0; i < 80; i += k) { + printf(" "); + for (k = 0; k < MIN(80 - i, 20); k++) + printf(" %02x", (uint8_t) info->header[i+k]); + printf(" | "); + for (k = 0; k < MIN(80 - i, 20); k++) + printf("%c", FILTERCHAR(info->header[i+k])); + printf("\n"); + } + } + + printf(" Model ID: %s\n", info->hash); + printf(" Model Name: %s\n", info->modelname); + printf(" Solid Name: %s\n", info->solidname); + printf(" Triangle Count: %i\n", info->loopcount); + printf(" Bounding Box Size: %.2f x %.2f x %.2f\n", + info->bbmax[0] - info->bbmin[0], + info->bbmax[1] - info->bbmin[1], + info->bbmax[2] - info->bbmin[2]); + printf(" Bounding Box Origin: %.2f x %.2f x %.2f\n", + info->bbmin[0], info->bbmin[1], info->bbmin[2]); + + printf(" ================== \n"); +} + +void +free_info(struct parseinfo *info) +{ + NULLFREE(info->hash); + NULLFREE(info->modelname); + NULLFREE(info->solidname); + info->valid = 0; +} + +float fle32toh(float v) +{ + union { + uint32_t u; + float f; + } conv; + + conv.f = v; + conv.u = le32toh(conv.u); + return conv.f; +} -- cgit v1.2.3-71-gd317