star-stl

Load STereo Lithography (StL) file format
git clone git://git.meso-star.fr/star-stl.git
Log | Files | Refs | README | LICENSE

commit 2ece078a8792331f46aab354dc134266fabe6835
parent 359302006508ab1e516f930cef2525eeab07d8b4
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Mon, 24 Feb 2025 16:26:38 +0100

Merge branch 'release_0.5.1_r1' into develop

Diffstat:
MREADME.md | 2++
Msrc/sstl.c | 123+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Msrc/sstl.h | 4+++-
Msrc/test_sstl_load.c | 6+++---
4 files changed, 88 insertions(+), 47 deletions(-)

diff --git a/README.md b/README.md @@ -18,6 +18,8 @@ Edit config.mk as needed, then run: ## Release notes ### Version 0.5.1 +- Fix issues when reading on stdin +- Add a warning if trailing chars detected after the solid in ascii files. - Add the read data type in the descriptor. - Fix a false error log message (should have been an information message). diff --git a/src/sstl.c b/src/sstl.c @@ -28,6 +28,7 @@ #include <string.h> #include <stdio.h> +#include <ctype.h> #ifdef COMPILER_CL #pragma warning(push) @@ -44,12 +45,19 @@ enum allowed_load_steps { TRY_READ_ALL = 3 }; +enum read_type { + STARTED_ASCII = BIT(0), + STARTED_BIN = BIT(1), + OK_ASCII = BIT(2), + OK_BINARY = BIT(3) +}; + struct solid { char* name; unsigned* indices; float* vertices; float* normals; - enum sstl_read_type read_type; + enum read_type read_type; }; static const struct solid SOLID_NULL = { NULL, NULL, NULL, NULL, 0 }; @@ -125,12 +133,13 @@ streamer_release(struct streamer* streamer) static char* streamer_read_line (struct streamer* streamer, - int checking_solid) + int checking_solid, + size_t* count) { const size_t buf_chunk = 256; - size_t read_sz; + size_t read_sz, read_count = 0; char* line; - ASSERT(streamer); + ASSERT(streamer && count); if(checking_solid) { size_t current = sa_size(streamer->buf); @@ -147,6 +156,7 @@ streamer_read_line for(;(line=fgets(streamer->buf, (int)read_sz, streamer->stream)); ++streamer->iline) { + size_t l; /* If checking for a line starting with "solid", stop reading early if the * line does not. If no error, ensure that the whole line is read */ @@ -155,6 +165,9 @@ streamer_read_line size_t remain_sz; if(checking_solid) { if(0 != strncmp("solid", line, 5)) { + l = strlen(line); + read_count += l; + *count = read_count; /* Dont read further */ return line; } @@ -176,7 +189,9 @@ streamer_read_line checking_solid = 0; } - if(strspn(streamer->buf, " \t\r\n") != strlen(streamer->buf)) { /* Not empty */ + l = strlen(streamer->buf); + read_count += l; + if(strspn(streamer->buf, " \t\r\n") != l) { /* Not empty */ /* Remove newline character(s) */ size_t last_char = strlen(line); while(last_char-- && (line[last_char]=='\n' || line[last_char]=='\r')); @@ -185,6 +200,7 @@ streamer_read_line } } ++streamer->iline; + *count += read_count; return line; } @@ -287,7 +303,7 @@ parse_name_string res = RES_MEM_ERR; goto error; } - strcpy(name, tk); + strcpy(remain, tk); } exit: @@ -323,6 +339,8 @@ parse_solid_name goto error; } + solid->read_type |= STARTED_ASCII; + OK(parse_name_string(sstl, strtok_r(NULL, "\0", tok_ctx), &solid->name, filename, iline, tok_ctx)); @@ -443,7 +461,8 @@ load_ascii_stream (struct sstl* sstl, FILE* stream, const char* stream_name, - int allowed) + int allowed, + size_t* count) { res_T res = RES_OK; struct streamer streamer; @@ -452,11 +471,11 @@ load_ascii_stream char* tok_ctx; char* tk; - ASSERT(sstl && stream && stream_name); + ASSERT(sstl && stream && stream_name && count); streamer_init(&streamer, stream, stream_name); clear(sstl); - line = streamer_read_line(&streamer, 1); + line = streamer_read_line(&streamer, 1, count); OK(parse_solid_name(sstl, &solid, line, streamer.name, streamer.iline, allowed, &tok_ctx)); @@ -465,7 +484,7 @@ load_ascii_stream unsigned facet[3]; int ivertex; - line = streamer_read_line(&streamer, 0); + line = streamer_read_line(&streamer, 0, count); if(!line) { print_log(sstl, LOG_ERROR, "%s:%lu: missing directive.\n", streamer.name, (unsigned long)streamer.iline); @@ -493,12 +512,12 @@ load_ascii_stream streamer.iline, &tok_ctx)); /* Parse the Outer loop directive */ - line = streamer_read_line(&streamer, 0); + line = streamer_read_line(&streamer, 0, count); OK(parse_outer_loop(sstl, line, streamer.name, streamer.iline, &tok_ctx)); /* Parse the facet vertices. Assume that only 3 vertices are submitted */ FOR_EACH(ivertex, 0, 3) { - line = streamer_read_line(&streamer, 0); + line = streamer_read_line(&streamer, 0, count); OK(parse_solid_vertex(sstl, &solid, facet+ivertex, line, streamer.name, streamer.iline, &tok_ctx)); } @@ -513,10 +532,10 @@ load_ascii_stream } f3_set(sa_add(solid.normals, 3), normal); - line = streamer_read_line(&streamer, 0); + line = streamer_read_line(&streamer, 0, count); OK(parse_directive(sstl, "endloop", line, streamer.name, streamer.iline, &tok_ctx)); - line = streamer_read_line(&streamer, 0); + line = streamer_read_line(&streamer, 0, count); OK(parse_directive(sstl, "endfacet", line, streamer.name, streamer.iline, &tok_ctx)); } @@ -534,9 +553,22 @@ load_ascii_stream } sa_release(name); } + if(sstl->verbose) { + int tmp, non_space = 0; + size_t i = 0; + while (EOF != (tmp = fgetc(stream))) { + i++; + if(!isspace(tmp)) non_space = 1; + } + if(non_space) { + print_log(sstl, LOG_WARNING, + "%s: %u unexpected trailing characters.\n", + stream_name, i); + } + } /* Register the solid */ - solid.read_type = SSTL_ASCII; + solid.read_type |= OK_ASCII; sstl->solid = solid; exit: @@ -572,6 +604,9 @@ load_binary_stream res = RES_BAD_ARG; goto error; } + + solid.read_type |= STARTED_BIN; + if(1 != fread(&triangles_count, 4, 1, stream)) { print_log(sstl, LOG_ERROR, "%s: missing triangle count.\n", stream_name); res = RES_BAD_ARG; @@ -608,16 +643,18 @@ load_binary_stream sa_push(solid.indices, index); } } - i = 0; - while (1 == fread(header, 1, 1, stream)) i++; - if(i) { - print_log(sstl, LOG_WARNING, - "%s: %u unexpected trailing bytes.\n", - stream_name, i); + if(sstl->verbose) { + i = 0; + while (1 == fread(header, 1, 1, stream)) i++; + if(i) { + print_log(sstl, LOG_WARNING, + "%s: %u unexpected trailing bytes.\n", + stream_name, i); + } } /* Register the solid */ - solid.read_type = SSTL_BINARY; + solid.read_type |= OK_BINARY; sstl->solid = solid; exit: @@ -627,16 +664,6 @@ error: goto exit; } -#if defined(COMPILER_GCC) - #define FTELL(P, S) \ - if(-1L == ((P) = ftell(S))) { res = RES_IO_ERR; goto error; } -#elif defined(COMPILER_CL) - #define FTELL(S) \ - if(-1L == ((P) = _ftelli64(S))) { res = RES_IO_ERR; goto error; } -#else - #error Undefined FTELL macro -#endif - static res_T load_stream (struct sstl* sstl, @@ -645,35 +672,41 @@ load_stream int allowed) { res_T res = RES_OK; - long long int idx1, idx2; int log = (allowed == TRY_READ_ALL); - size_t count; + size_t count = 0; - ASSERT(sstl && stream && stream_name && allowed); + ASSERT(sstl && stream && allowed); /* Try reading as an ASCII file; if the file doesn't start with "solid" the * file is not read past the first 5 characters, so that we can continue * reading as a binary file, exploiting the fact that binary files' first 80 * characters are meaningless */ - FTELL(idx1, stream); if(allowed & TRY_READ_ASCII) { if(log) { print_log(sstl, LOG_OUTPUT, "%s: attempt to read as ASCII file.\n", stream_name); } - res = load_ascii_stream(sstl, stream, stream_name, allowed); + res = load_ascii_stream(sstl, stream, stream_name, allowed, &count); if(res == RES_OK) { if(log) print_log(sstl, LOG_OUTPUT, "Attempt successful.\n"); goto exit; } } + /* If here the stream could not be read as ASCII */ if(!(allowed & TRY_READ_BINARY)) goto exit; - FTELL(idx2, stream); - ASSERT(idx2 >= idx1); - count = (size_t)(idx2 - idx1); - if(count > CHECK_SOLID_LEN) + if(sstl->solid.read_type & STARTED_ASCII) { /* "solid" was found: was an ill-formed ASCII file */ return res; + } + if(count > 80) { + /* Don't know if can happen, but further code cannot handle this */ + print_log(sstl, LOG_ERROR, + "%s: cannot attempt to read as binary file" + " (too many bytes read while trying ascii read).\n", + stream_name); + res = RES_BAD_ARG; + goto error; + } if(log) { print_log(sstl, LOG_OUTPUT, "%s: attempt to read as binary file.\n", stream_name); @@ -874,7 +907,7 @@ write_stream res = data->get_triangle_vertices(i, data->data, vtx); OKP(fprintf(stream, " outer loop\n")); for(n = 0; n < 3; n++) { - OKP(fprintf(stream, " vertex %g %g %g\n", SPLIT3(vtx[n]))); + OKP(fprintf(stream, " vertex %.16g %.16g %.16g\n", SPLIT3(vtx[n]))); } OKP(fprintf(stream, " endloop\n")); OKP(fprintf(stream, " endfacet\n")); @@ -1013,8 +1046,12 @@ sstl_load_stream(struct sstl* sstl, FILE* stream) res_T sstl_get_desc(struct sstl* sstl, struct sstl_desc* desc) { - if(!sstl || !desc) return RES_BAD_ARG; + if(!sstl || !desc + /* OK_ASCII xor OK_BIN */ + || (sstl->solid.read_type & OK_BINARY) == (sstl->solid.read_type & OK_ASCII)) + return RES_BAD_ARG; desc->solid_name = sstl->solid.name; + desc->read_type = (sstl->solid.read_type & OK_ASCII) ? SSTL_ASCII : SSTL_BINARY; desc->vertices_count = sa_size(sstl->solid.vertices); ASSERT(desc->vertices_count % 3 == 0); desc->vertices_count /= 3/* # coords per vertex */; diff --git a/src/sstl.h b/src/sstl.h @@ -71,6 +71,8 @@ struct sstl_write_data { void (*print_error_log)(const void* data, const char* msg, ...); unsigned triangles_count; }; +#define SSTL_WRITE_DATA_NULL__ { NULL, NULL, NULL, NULL, NULL, 0 } +static const struct sstl_write_data SSTL_WRITE_DATA_NULL = SSTL_WRITE_DATA_NULL__; /* Forward declaration of external types */ struct logger; @@ -138,7 +140,7 @@ sstl_load_stream FILE* stream); /* Create a sstl_write_data from a sstl. - * The returned descriptor is valid until a new load process */ + * The result is valid as long as the input sstl is valid */ SSTL_API res_T sstl_pack_write_data (const struct sstl* sstl, diff --git a/src/test_sstl_load.c b/src/test_sstl_load.c @@ -175,13 +175,13 @@ test_basic(struct sstl* sstl) file = tmpfile(); CHK(file != NULL); fwrite(test1, sizeof(char), strlen(test1), file); - + rewind(file); CHK(sstl_load_stream_ascii(NULL, NULL) == RES_BAD_ARG); CHK(sstl_load_stream_ascii(sstl, NULL) == RES_BAD_ARG); CHK(sstl_load_stream_ascii(NULL, file) == RES_BAD_ARG); CHK(sstl_load_stream_ascii(sstl, file) == RES_OK); - + rewind(file); CHK(sstl_load_stream_binary(NULL, NULL) == RES_BAD_ARG); CHK(sstl_load_stream_binary(sstl, NULL) == RES_BAD_ARG); @@ -225,7 +225,7 @@ test_basic(struct sstl* sstl) rewind(file); CHK(sstl_load_stream_binary(sstl,file) == RES_OK); fclose(file); - + CHK(sstl_get_desc(sstl, &desc) == RES_OK); CHK(desc.solid_name == NULL); CHK(desc.vertices_count == 3);