star-stl

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

commit a82dcc0640a6b74cdf93eef56552476df40d27cc
parent ce7b081f45c2a94936f9306bcc3c88a99d6b66d1
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Mon, 24 Feb 2025 16:19:27 +0100

Fix stdin compatibility

Code used ftell that is not stdin compatible.
Code is not ftell free.

Diffstat:
Msrc/sstl.c | 91+++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
1 file changed, 56 insertions(+), 35 deletions(-)

diff --git a/src/sstl.c b/src/sstl.c @@ -45,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 }; @@ -126,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); @@ -148,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 */ @@ -156,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; } @@ -177,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')); @@ -186,6 +200,7 @@ streamer_read_line } } ++streamer->iline; + *count += read_count; return line; } @@ -324,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)); @@ -444,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; @@ -453,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)); @@ -466,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); @@ -494,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)); } @@ -514,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)); } @@ -550,7 +568,7 @@ load_ascii_stream } /* Register the solid */ - solid.read_type = SSTL_ASCII; + solid.read_type |= OK_ASCII; sstl->solid = solid; exit: @@ -586,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; @@ -633,7 +654,7 @@ load_binary_stream } /* Register the solid */ - solid.read_type = SSTL_BINARY; + solid.read_type |= OK_BINARY; sstl->solid = solid; exit: @@ -643,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, @@ -661,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); @@ -1029,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 */;