gmio_stl: fix case where solid name is composed of many words

This commit is contained in:
Hugues Delorme 2015-07-10 10:55:02 +02:00
parent 2857f5ca30
commit 26fc957569
2 changed files with 192 additions and 44 deletions

View File

@ -22,6 +22,7 @@
#include "../gmio_core/error.h" #include "../gmio_core/error.h"
#include "../gmio_core/internal/helper_stream.h" #include "../gmio_core/internal/helper_stream.h"
#include "../gmio_core/internal/helper_transfer.h" #include "../gmio_core/internal/helper_transfer.h"
#include "../gmio_core/internal/min_max.h"
#include "../gmio_core/internal/string_parse.h" #include "../gmio_core/internal/string_parse.h"
#include "../gmio_core/internal/string_utils.h" #include "../gmio_core/internal/string_utils.h"
@ -77,6 +78,9 @@
* *
*/ */
/* Fixed maximum length of any string_buffer user in this source file */
enum { GMIO_STLA_READ_STRING_BUFFER_LEN = 1024 };
/* gmio_stream_fwd_iterator_stla_cookie */ /* gmio_stream_fwd_iterator_stla_cookie */
typedef struct typedef struct
{ {
@ -93,19 +97,19 @@ typedef struct
/* gmio_stla_token */ /* gmio_stla_token */
typedef enum typedef enum
{ {
ENDFACET_token, ENDFACET_token = 0x0001,
ENDLOOP_token, ENDLOOP_token = 0x0002,
ENDSOLID_token, ENDSOLID_token = 0x0004,
FACET_token, FACET_token = 0x0008,
ID_token, ID_token = 0x0010,
FLOAT_token = ID_token, FLOAT_token = ID_token,
LOOP_token, LOOP_token = 0x0020,
NORMAL_token, NORMAL_token = 0x0040,
OUTER_token, OUTER_token = 0x0080,
SOLID_token, SOLID_token = 0x0100,
VERTEX_token, VERTEX_token = 0x0200,
empty_token, empty_token = 0x0400,
unknown_token unknown_token = 0x0800
} gmio_stla_token_t; } gmio_stla_token_t;
/* gmio_stla_parse_data */ /* gmio_stla_parse_data */
@ -141,12 +145,6 @@ GMIO_INLINE gmio_bool_t parsing_can_continue(
return GMIO_FALSE; return GMIO_FALSE;
} }
GMIO_INLINE const char* current_token_as_identifier(
const gmio_stla_parse_data_t* data)
{
return data->token == ID_token ? data->string_buffer.ptr : "";
}
GMIO_INLINE int get_current_token_as_float32( GMIO_INLINE int get_current_token_as_float32(
const gmio_stla_parse_data_t* data, gmio_float32_t* value_ptr) const gmio_stla_parse_data_t* data, gmio_float32_t* value_ptr)
{ {
@ -206,12 +204,8 @@ GMIO_INLINE void parsing_error_token_expected(
parsing_error_msg(data, msg); parsing_error_msg(data, msg);
} }
static gmio_stla_token_t parsing_find_token( static gmio_stla_token_t parsing_find_token(const char* word, size_t word_len)
const gmio_string_buffer_t* str_buffer)
{ {
const char* word = str_buffer->ptr;
const size_t word_len = str_buffer->len;
/* Get rid of ill-formed token */ /* Get rid of ill-formed token */
if (word_len == 0) if (word_len == 0)
return empty_token; return empty_token;
@ -280,13 +274,20 @@ static gmio_stla_token_t parsing_find_token(
return ID_token; return ID_token;
} }
GMIO_INLINE gmio_stla_token_t parsing_find_token_from_buff(
const gmio_string_buffer_t* str_buffer)
{
return parsing_find_token(str_buffer->ptr, str_buffer->len);
}
GMIO_INLINE void parsing_advance(gmio_stla_parse_data_t* data) GMIO_INLINE void parsing_advance(gmio_stla_parse_data_t* data)
{ {
if (!parsing_can_continue(data)) if (!parsing_can_continue(data))
return; return;
data->string_buffer.len = 0;
if (gmio_eat_word(&data->stream_iterator, &data->string_buffer) == 0) if (gmio_eat_word(&data->stream_iterator, &data->string_buffer) == 0)
data->token = parsing_find_token(&data->string_buffer); data->token = parsing_find_token_from_buff(&data->string_buffer);
else else
data->token = unknown_token; data->token = unknown_token;
@ -306,15 +307,65 @@ GMIO_INLINE void parsing_eat_token(
parsing_error_token_expected(data, token); parsing_error_token_expected(data, token);
} }
static void parse_eat_until_token(
gmio_stla_parse_data_t* data,
int end_tokens)
{
if (!parsing_can_continue(data))
return;
if ((data->token & end_tokens) == 0) {
gmio_string_stream_fwd_iterator_t* stream_it = &data->stream_iterator;
gmio_string_buffer_t* string_buf = &data->string_buffer;
int end_token_found = 0;
do {
const size_t previous_buff_len = string_buf->len;
int res_eat_word = 0; /* Result of gmio_eat_word() */
const char* next_word = NULL; /* Pointer on next word string */
size_t next_word_len = 0; /* Length of next word string */
gmio_copy_spaces(stream_it, string_buf);
/* Next word */
next_word = string_buf->ptr + string_buf->len;
res_eat_word = gmio_eat_word(stream_it, string_buf);
next_word_len =
(string_buf->ptr + string_buf->len) - next_word;
/* Qualify token */
data->token =
res_eat_word == 0 ?
parsing_find_token(next_word, next_word_len) :
unknown_token;
/* End token found ? */
end_token_found = data->token & end_tokens;
/* True ?
* trim string_buf so it contains only contents before end token */
if (end_token_found) {
string_buf->len = previous_buff_len;
string_buf->ptr[previous_buff_len] = 0;
}
} while (!end_token_found && string_buf->len < string_buf->max_len);
if (!end_token_found) {
parsing_error_msg(
data,
"end token not found in parse_eat_until_token()");
}
}
}
static void parse_solidname_beg(gmio_stla_parse_data_t* data) static void parse_solidname_beg(gmio_stla_parse_data_t* data)
{ {
if (!parsing_can_continue(data)) if (!parsing_can_continue(data))
return; return;
switch (data->token) { switch (data->token) {
case ENDSOLID_token:
case FACET_token:
case ID_token: case ID_token:
/* Solid name can be made of multiple words */
parse_eat_until_token(data, FACET_token | ENDSOLID_token);
break;
case FACET_token:
case ENDSOLID_token:
gmio_string_buffer_clear(&data->string_buffer);
break; break;
default: default:
parsing_error_msg(data, "unexpected token for 'solid <name>'"); parsing_error_msg(data, "unexpected token for 'solid <name>'");
@ -349,7 +400,7 @@ static void parse_beginsolid(gmio_stla_parse_data_t* data)
gmio_stl_mesh_creator_ascii_begin_solid( gmio_stl_mesh_creator_ascii_begin_solid(
data->creator, data->creator,
data->stream_iterator_cookie.stream_size, data->stream_iterator_cookie.stream_size,
current_token_as_identifier(data)); data->string_buffer.ptr);
} }
if (data->token == ID_token) if (data->token == ID_token)
parsing_eat_token(ID_token, data); parsing_eat_token(ID_token, data);
@ -452,8 +503,6 @@ static void parse_solid(gmio_stla_parse_data_t* data)
} }
} }
enum { GMIO_STLA_READ_STRING_BUFFER_LEN = 512 };
int gmio_stla_read(gmio_transfer_t* trsf, gmio_stl_mesh_creator_t* creator) int gmio_stla_read(gmio_transfer_t* trsf, gmio_stl_mesh_creator_t* creator)
{ {
char fixed_buffer[GMIO_STLA_READ_STRING_BUFFER_LEN]; char fixed_buffer[GMIO_STLA_READ_STRING_BUFFER_LEN];

View File

@ -22,6 +22,24 @@
#include <stddef.h> #include <stddef.h>
#include <string.h> #include <string.h>
struct stl_testcase_result
{
char solid_name[2048];
};
typedef struct stl_testcase_result stl_testcase_result_t;
void ascii_begin_solid(
void* cookie, size_t stream_size, const char* solid_name)
{
GMIO_UNUSED(stream_size);
stl_testcase_result_t* res = (stl_testcase_result_t*)cookie;
if (res != NULL) {
res->solid_name[0] = 0;
if (solid_name != NULL)
strcpy(&res->solid_name[0], solid_name);
}
}
static void add_triangle( static void add_triangle(
void* cookie, uint32_t tri_id, const gmio_stl_triangle_t* triangle) void* cookie, uint32_t tri_id, const gmio_stl_triangle_t* triangle)
{ {
@ -30,35 +48,102 @@ static void add_triangle(
GMIO_UNUSED(triangle); GMIO_UNUSED(triangle);
} }
struct filepath_errorcode struct stl_testcase
{ {
const char* filepath; const char* filepath;
int errorcode; int errorcode;
gmio_stl_format_t format;
const char* solid_name;
}; };
typedef struct filepath_errorcode filepath_errorcode_t; typedef struct stl_testcase stl_testcase;
const char* test_stl_read() const char* test_stl_read()
{ {
const filepath_errorcode_t expected[] = { const stl_testcase expected[] = {
{ "tests/models/file_empty", GMIO_STL_ERROR_UNKNOWN_FORMAT }, { "tests/models/file_empty",
{ "tests/models/solid_4vertex.stla", GMIO_STL_ERROR_PARSING }, GMIO_STL_ERROR_UNKNOWN_FORMAT,
{ "tests/models/solid_anonymous_empty.stla", GMIO_ERROR_OK }, GMIO_STL_FORMAT_UNKNOWN,
{ "tests/models/solid_empty.stla", GMIO_ERROR_OK }, NULL
{ "tests/models/solid_empty.stlb", GMIO_ERROR_OK }, },
{ "tests/models/solid_lack_z.stla", GMIO_STL_ERROR_PARSING }, { "tests/models/solid_4vertex.stla",
{ "tests/models/solid_one_facet.stla", GMIO_ERROR_OK }, GMIO_STL_ERROR_PARSING,
{ "tests/models/solid_one_facet.le_stlb", GMIO_ERROR_OK }, GMIO_STL_FORMAT_ASCII,
{ "tests/models/solid_one_facet_uppercase.stla", GMIO_ERROR_OK } NULL
},
{ "tests/models/solid_anonymous_empty.stla",
GMIO_ERROR_OK,
GMIO_STL_FORMAT_ASCII,
NULL
},
{ "tests/models/solid_empty.stla",
GMIO_ERROR_OK,
GMIO_STL_FORMAT_ASCII,
"emptysolid"
},
{ "tests/models/solid_empty.stlb",
GMIO_ERROR_OK,
GMIO_STL_FORMAT_BINARY_LE,
NULL
},
{ "tests/models/solid_empty_name_many_words.stla",
GMIO_ERROR_OK,
GMIO_STL_FORMAT_ASCII,
"name with multiple words"
},
{ "tests/models/solid_empty_name_many_words_single_letters.stla",
GMIO_ERROR_OK,
GMIO_STL_FORMAT_ASCII,
"a b c d e f\t\tg h"
},
{ "tests/models/solid_lack_z.stla",
GMIO_STL_ERROR_PARSING,
GMIO_STL_FORMAT_ASCII,
NULL
},
{ "tests/models/solid_one_facet.stla",
GMIO_ERROR_OK,
GMIO_STL_FORMAT_ASCII,
NULL
},
{ "tests/models/solid_one_facet.le_stlb",
GMIO_ERROR_OK,
GMIO_STL_FORMAT_BINARY_LE,
NULL
},
{ "tests/models/solid_one_facet_uppercase.stla",
GMIO_ERROR_OK,
GMIO_STL_FORMAT_ASCII,
NULL
}
}; };
const size_t expected_count = const size_t expected_count =
sizeof(expected) / sizeof(filepath_errorcode_t); sizeof(expected) / sizeof(stl_testcase);
size_t i; /* for loop counter */ size_t i; /* for loop counter */
gmio_stl_mesh_creator_t meshc = {0}; gmio_stl_mesh_creator_t meshc = {0};
stl_testcase_result_t result = {0};
meshc.cookie = &result;
meshc.ascii_begin_solid_func = &ascii_begin_solid;
meshc.add_triangle_func = &add_triangle; meshc.add_triangle_func = &add_triangle;
for (i = 0; i < expected_count; ++i) { for (i = 0; i < expected_count; ++i) {
const int err = gmio_stl_read_file(expected[i].filepath, &meshc, NULL); const gmio_stl_format_t format =
gmio_stl_get_format_file(expected[i].filepath);
const int err =
gmio_stl_read_file(expected[i].filepath, &meshc, NULL);
/* Check format */
if (format != expected[i].format) {
printf("\nfilepath : %s\n"
"expected format : %d\n"
"actual format : %d\n",
expected[i].filepath,
expected[i].format,
format);
}
UTEST_ASSERT(format == expected[i].format);
/* Check error code */
if (err != expected[i].errorcode) { if (err != expected[i].errorcode) {
printf("\nfilepath : %s\n" printf("\nfilepath : %s\n"
"expected error : 0x%x\n" "expected error : 0x%x\n"
@ -68,12 +153,26 @@ const char* test_stl_read()
err); err);
} }
UTEST_ASSERT(err == expected[i].errorcode); UTEST_ASSERT(err == expected[i].errorcode);
/* Check solid name */
if (expected[i].format == GMIO_STL_FORMAT_ASCII) {
const char* expected_name =
expected[i].solid_name != NULL ? expected[i].solid_name : "";
if (strcmp(result.solid_name, expected_name) != 0) {
printf("\nfilepath : %s\n"
"expected solidname : %s\n"
"actual solidname : %s\n",
expected[i].filepath,
expected_name,
result.solid_name);
}
UTEST_ASSERT(strcmp(result.solid_name, expected_name) == 0);
}
} }
return NULL; return NULL;
} }
struct stl_triangle_array struct stl_triangle_array
{ {
gmio_stl_triangle_t* ptr; gmio_stl_triangle_t* ptr;