From dbdb45bd24b5948861e174bc7c0c76af5511644d Mon Sep 17 00:00:00 2001 From: Hugues Delorme Date: Sat, 2 Mar 2013 22:05:17 +0100 Subject: [PATCH] Add first working impl of STL ASCII reading --- qmake.build/c/libstl/libstl.pro | 2 + src/c/libstl/stla_read.c | 287 ++++++++++++++++++++++++++++++++ src/c/libstl/stla_read.h | 42 +++++ 3 files changed, 331 insertions(+) create mode 100644 src/c/libstl/stla_read.c create mode 100644 src/c/libstl/stla_read.h diff --git a/qmake.build/c/libstl/libstl.pro b/qmake.build/c/libstl/libstl.pro index 9ab9f9f..11cbc1b 100644 --- a/qmake.build/c/libstl/libstl.pro +++ b/qmake.build/c/libstl/libstl.pro @@ -27,6 +27,7 @@ HEADERS += \ ../../../src/c/stream.h \ ../../../src/c/task_control.h \ ../../../src/c/libstl/stl_global.h \ + ../../../src/c/libstl/stla_read.h \ ../../../src/c/libstl/stlb_read.h \ ../../../src/c/libstl/stlb_write.h \ ../../../src/c/libstl/stl_triangle.h \ @@ -36,6 +37,7 @@ SOURCES += \ ../../../src/c/endian.c \ ../../../src/c/stream.c \ ../../../src/c/task_control.c \ + ../../../src/c/libstl/stla_read.c \ ../../../src/c/libstl/stlb_read.c \ ../../../src/c/libstl/stlb_write.c diff --git a/src/c/libstl/stla_read.c b/src/c/libstl/stla_read.c new file mode 100644 index 0000000..bad7d1c --- /dev/null +++ b/src/c/libstl/stla_read.c @@ -0,0 +1,287 @@ +#include "stla_read.h" + +#include /* isspace() */ +#include +#include +#include + +typedef struct foug_stream_fwd_iterator +{ + foug_stream_t* stream; + char* buffer; + uint32_t buffer_offset; + uint32_t buffer_size; + size_t stream_offset; + + void* cookie; + void (*stream_read_hook)(const struct foug_stream_fwd_iterator* it); + +} foug_stream_fwd_iterator_t; + +static void foug_stream_fwd_iterator_read_hook(const foug_stream_fwd_iterator_t* it) +{ + foug_task_control_t* ctrl = it != NULL ? (foug_task_control_t*)(it->cookie) : NULL; + /*if (ctrl != NULL) + foug_task_control_set_progress(ctrl, it->stream_offset); */ +} + +static char* current_char(foug_stream_fwd_iterator_t* it) +{ + if (it == NULL) + return NULL; + + if (it->buffer_offset < it->buffer_size) + return it->buffer + it->buffer_offset; + return NULL; +} + +static char* next_char(foug_stream_fwd_iterator_t* it) +{ + size_t char_count_read; + + if (it == NULL) + return NULL; + + if ((it->buffer_offset + 1) < it->buffer_size) { + ++(it->buffer_offset); + ++(it->stream_offset); + return it->buffer + it->buffer_offset; + } + else { + if (foug_stream_error(it->stream) != 0 || foug_stream_at_end(it->stream)) + return NULL; + /* Read next chunk of data */ + char_count_read = foug_stream_read(it->stream, it->buffer, sizeof(char), it->buffer_size); + if (foug_stream_error(it->stream) != 0) { + return NULL; + } + else { + it->buffer_offset = 0; + ++(it->stream_offset); + it->buffer_size = char_count_read; + return it->buffer; + } + } +} + +void foug_stream_fwd_iterator_init(foug_stream_fwd_iterator_t* it) +{ + it->buffer_offset = it->buffer_size;/* This will cause the first call to foug_stream_read() */ + next_char(it); +} + +static void skip_spaces(foug_stream_fwd_iterator_t* it) +{ + char* curr_char = current_char(it); + while (curr_char != NULL && isspace(*curr_char)) + curr_char = next_char(it); +} + +static int eat_token(foug_stream_fwd_iterator_t* it, const char* token) +{ + uint32_t i; + const char* stream_curr_char; + + if (token == NULL || current_char(it) == NULL) + return -1; + + skip_spaces(it); + stream_curr_char = current_char(it); + + for (i = 0; token[i] != 0 && stream_curr_char != NULL; ++i) { + if (token[i] != *stream_curr_char) + return -2; + stream_curr_char = next_char(it); + } + + return token[i] != 0 ? -3 : 0; +} + +typedef struct foug_string_buffer +{ + char* data; + size_t max_len; + size_t len; +} foug_string_buffer_t; + +static int eat_string(foug_stream_fwd_iterator_t* it, foug_string_buffer_t* str_buffer) +{ + size_t i; + const char* stream_curr_char; + int isspace_res; + + if (str_buffer == NULL || str_buffer->data == NULL || str_buffer->max_len == 0) + return -1; + + str_buffer->len = 0; + skip_spaces(it); + stream_curr_char = current_char(it); + + isspace_res = 0; + i = 0; + while (i < str_buffer->max_len && stream_curr_char != NULL && !isspace_res) { + isspace_res = isspace(*stream_curr_char); + if (!isspace_res) { + str_buffer->data[i] = *stream_curr_char; + stream_curr_char = next_char(it); + ++i; + } + } + + if (i < str_buffer->max_len) { + str_buffer->data[i] = 0; /* End string with null terminator */ + str_buffer->len = i ; + if (stream_curr_char != NULL || foug_stream_at_end(it->stream)) + return 0; + return -2; + } + return -3; +} + +static int read_real32(foug_stream_fwd_iterator_t* it, + foug_string_buffer_t* str_buffer, + foug_real32_t* value_ptr) +{ + char* conv_end_ptr; /* for strtod() */ + + if (eat_string(it, str_buffer) != 0) + return -1; + *value_ptr = (foug_real32_t)strtod(str_buffer->data, &conv_end_ptr); + if (conv_end_ptr == str_buffer->data || errno == ERANGE) + return -2; + + return 0; +} + +static int read_coords(foug_stream_fwd_iterator_t* it, + foug_string_buffer_t* str_buffer, + foug_stl_coords_t* coords_ptr) +{ + if (read_real32(it, str_buffer, &coords_ptr->x) != 0) + return -1; + if (read_real32(it, str_buffer, &coords_ptr->y) != 0) + return -1; + if (read_real32(it, str_buffer, &coords_ptr->z) != 0) + return -1; + return 0; +} + +static int eat_facet(foug_stream_fwd_iterator_t* it, + foug_string_buffer_t* str_buffer, + foug_stl_triangle_t* triangle) +{ + /* Try to eat "facet" */ + if (eat_string(it, str_buffer) != 0) + return -1; + if (strcmp(str_buffer->data, "facet") != 0) /* Maybe "endsolid" */ + return 1; + + /* Read normal */ + if (eat_token(it, "normal") != 0) + return -2; + if (read_coords(it, str_buffer, &triangle->normal) != 0) + return -3; + + /* Try to eat "outer loop" */ + if (eat_token(it, "outer") != 0) + return -2; + if (eat_token(it, "loop") != 0) + return -2; + + /* Read vertex 1 */ + if (eat_token(it, "vertex") != 0) + return -2; + if (read_coords(it, str_buffer, &triangle->v1) != 0) + return -3; + + /* Read vertex 2 */ + if (eat_token(it, "vertex") != 0) + return -2; + if (read_coords(it, str_buffer, &triangle->v2) != 0) + return -3; + + /* Read vertex 3 */ + if (eat_token(it, "vertex") != 0) + return -2; + if (read_coords(it, str_buffer, &triangle->v3) != 0) + return -3; + + /* Try to eat "endloop" */ + if (eat_token(it, "endloop") != 0) + return -2; + + /* Try to eat "endfacet" */ + if (eat_token(it, "endfacet") != 0) + return -2; + + return 0; +} + +#define FOUG_STLA_READ_STRING_BUFFER_LEN 512 + +int foug_stla_read(foug_stla_read_args_t *args) +{ + foug_task_progress_t progress; + char fixed_buffer[FOUG_STLA_READ_STRING_BUFFER_LEN]; + foug_string_buffer_t string_buffer; + foug_stl_triangle_t triangle; + foug_stream_fwd_iterator_t it; + int eat_facet_result; + + if (args->buffer == NULL) + return FOUG_STLA_READ_NULL_BUFFER; + if (args->buffer_size == 0) + return FOUG_STLA_READ_INVALID_BUFFER_SIZE_ERROR; + + it.stream = &(args->stream); + it.buffer = args->buffer; + it.buffer_offset = 0; + it.buffer_size = args->buffer_size; + it.stream_offset = 0; + it.cookie = &(args->task_control); + it.stream_read_hook = foug_stream_fwd_iterator_read_hook; + foug_stream_fwd_iterator_init(&it); + + string_buffer.data = fixed_buffer; + string_buffer.max_len = FOUG_STLA_READ_STRING_BUFFER_LEN; + string_buffer.len = 0; + + progress.range_min = 0.f; + progress.range_max = (foug_real32_t)args->data_size_hint; + progress.value = 0.f; + args->task_control.is_stop_requested = 0; + + /* Eat solids */ + while (eat_token(&it, "solid") == 0) { + /* Try to eat solid's name */ + if (eat_string(&it, &string_buffer) != 0) { + return FOUG_STLA_READ_PARSE_ERROR; + } + if (args->geom_input.begin_solid_func != NULL) + args->geom_input.begin_solid_func(&args->geom_input, string_buffer.data); + + /* Try to eat facets */ + while ((eat_facet_result = eat_facet(&it, &string_buffer, &triangle)) >= 0) { + if (eat_facet_result == 0) { + if (args->geom_input.process_next_triangle_func != NULL) + args->geom_input.process_next_triangle_func(&args->geom_input, &triangle); + } + else { + break; /* Ate "endsolid" */ + } + } /* end while */ + + /* Handle "endsolid" */ + if (eat_facet_result > 0) { + if (eat_string(&it, &string_buffer) != 0) + return FOUG_STLA_READ_PARSE_ERROR; + if (args->geom_input.end_solid_func != NULL) + args->geom_input.end_solid_func(&args->geom_input, string_buffer.data); + } + else { + return FOUG_STLA_READ_PARSE_ERROR; + } + } + + return FOUG_STLA_READ_NO_ERROR; +} diff --git a/src/c/libstl/stla_read.h b/src/c/libstl/stla_read.h new file mode 100644 index 0000000..5551a50 --- /dev/null +++ b/src/c/libstl/stla_read.h @@ -0,0 +1,42 @@ +#ifndef FOUG_C_LIBSTL_STLA_READ_H +#define FOUG_C_LIBSTL_STLA_READ_H + +#include "stl_global.h" +#include "stl_triangle.h" +#include "../stream.h" +#include "../task_control.h" + +/* foug_stla_geom_input */ +typedef struct foug_stla_geom_input foug_stla_geom_input_t; +struct foug_stla_geom_input +{ + void* cookie; + void (*begin_solid_func)(foug_stla_geom_input_t*, const char* name); + void (*process_next_triangle_func)(foug_stla_geom_input_t*, const foug_stl_triangle_t*); + void (*end_solid_func)(foug_stla_geom_input_t*, const char* name); + /* void (*parse_error_func)(foug_stla_geom_input_t*, size_t, size_t); */ +}; + +/* foug_stla_read_args */ +typedef struct foug_stla_read_args +{ + foug_stla_geom_input_t geom_input; + foug_stream_t stream; + foug_task_control_t task_control; + char* buffer; + uint32_t buffer_size; + size_t data_size_hint; +} foug_stla_read_args_t; + +FOUG_DATAEX_LIBSTL_EXPORT +int foug_stla_read(foug_stla_read_args_t* args); + +/* Error codes returned by foug_stlb_read() */ +#define FOUG_STLA_READ_NO_ERROR 0 +#define FOUG_STLA_READ_NULL_BUFFER 3 +#define FOUG_STLA_READ_INVALID_BUFFER_SIZE_ERROR 4 +#define FOUG_STLA_READ_PARSE_ERROR 5 +#define FOUG_STLA_READ_STREAM_ERROR 7 +#define FOUG_STLA_READ_TASK_STOPPED_ERROR 8 + +#endif /* FOUG_C_LIBSTL_STLA_READ_H */