gmio_stl: fix case where solid name is composed of many words
This commit is contained in:
parent
2857f5ca30
commit
26fc957569
@ -22,6 +22,7 @@
|
||||
#include "../gmio_core/error.h"
|
||||
#include "../gmio_core/internal/helper_stream.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_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 */
|
||||
typedef struct
|
||||
{
|
||||
@ -93,19 +97,19 @@ typedef struct
|
||||
/* gmio_stla_token */
|
||||
typedef enum
|
||||
{
|
||||
ENDFACET_token,
|
||||
ENDLOOP_token,
|
||||
ENDSOLID_token,
|
||||
FACET_token,
|
||||
ID_token,
|
||||
ENDFACET_token = 0x0001,
|
||||
ENDLOOP_token = 0x0002,
|
||||
ENDSOLID_token = 0x0004,
|
||||
FACET_token = 0x0008,
|
||||
ID_token = 0x0010,
|
||||
FLOAT_token = ID_token,
|
||||
LOOP_token,
|
||||
NORMAL_token,
|
||||
OUTER_token,
|
||||
SOLID_token,
|
||||
VERTEX_token,
|
||||
empty_token,
|
||||
unknown_token
|
||||
LOOP_token = 0x0020,
|
||||
NORMAL_token = 0x0040,
|
||||
OUTER_token = 0x0080,
|
||||
SOLID_token = 0x0100,
|
||||
VERTEX_token = 0x0200,
|
||||
empty_token = 0x0400,
|
||||
unknown_token = 0x0800
|
||||
} gmio_stla_token_t;
|
||||
|
||||
/* gmio_stla_parse_data */
|
||||
@ -141,12 +145,6 @@ GMIO_INLINE gmio_bool_t parsing_can_continue(
|
||||
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(
|
||||
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);
|
||||
}
|
||||
|
||||
static gmio_stla_token_t parsing_find_token(
|
||||
const gmio_string_buffer_t* str_buffer)
|
||||
static gmio_stla_token_t parsing_find_token(const char* word, size_t word_len)
|
||||
{
|
||||
const char* word = str_buffer->ptr;
|
||||
const size_t word_len = str_buffer->len;
|
||||
|
||||
/* Get rid of ill-formed token */
|
||||
if (word_len == 0)
|
||||
return empty_token;
|
||||
@ -280,13 +274,20 @@ static gmio_stla_token_t parsing_find_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)
|
||||
{
|
||||
if (!parsing_can_continue(data))
|
||||
return;
|
||||
|
||||
data->string_buffer.len = 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
|
||||
data->token = unknown_token;
|
||||
|
||||
@ -306,15 +307,65 @@ GMIO_INLINE void parsing_eat_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)
|
||||
{
|
||||
if (!parsing_can_continue(data))
|
||||
return;
|
||||
|
||||
switch (data->token) {
|
||||
case ENDSOLID_token:
|
||||
case FACET_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;
|
||||
default:
|
||||
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(
|
||||
data->creator,
|
||||
data->stream_iterator_cookie.stream_size,
|
||||
current_token_as_identifier(data));
|
||||
data->string_buffer.ptr);
|
||||
}
|
||||
if (data->token == ID_token)
|
||||
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)
|
||||
{
|
||||
char fixed_buffer[GMIO_STLA_READ_STRING_BUFFER_LEN];
|
||||
|
@ -22,6 +22,24 @@
|
||||
#include <stddef.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(
|
||||
void* cookie, uint32_t tri_id, const gmio_stl_triangle_t* triangle)
|
||||
{
|
||||
@ -30,35 +48,102 @@ static void add_triangle(
|
||||
GMIO_UNUSED(triangle);
|
||||
}
|
||||
|
||||
struct filepath_errorcode
|
||||
struct stl_testcase
|
||||
{
|
||||
const char* filepath;
|
||||
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 filepath_errorcode_t expected[] = {
|
||||
{ "tests/models/file_empty", GMIO_STL_ERROR_UNKNOWN_FORMAT },
|
||||
{ "tests/models/solid_4vertex.stla", GMIO_STL_ERROR_PARSING },
|
||||
{ "tests/models/solid_anonymous_empty.stla", GMIO_ERROR_OK },
|
||||
{ "tests/models/solid_empty.stla", GMIO_ERROR_OK },
|
||||
{ "tests/models/solid_empty.stlb", GMIO_ERROR_OK },
|
||||
{ "tests/models/solid_lack_z.stla", GMIO_STL_ERROR_PARSING },
|
||||
{ "tests/models/solid_one_facet.stla", GMIO_ERROR_OK },
|
||||
{ "tests/models/solid_one_facet.le_stlb", GMIO_ERROR_OK },
|
||||
{ "tests/models/solid_one_facet_uppercase.stla", GMIO_ERROR_OK }
|
||||
const stl_testcase expected[] = {
|
||||
{ "tests/models/file_empty",
|
||||
GMIO_STL_ERROR_UNKNOWN_FORMAT,
|
||||
GMIO_STL_FORMAT_UNKNOWN,
|
||||
NULL
|
||||
},
|
||||
{ "tests/models/solid_4vertex.stla",
|
||||
GMIO_STL_ERROR_PARSING,
|
||||
GMIO_STL_FORMAT_ASCII,
|
||||
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 =
|
||||
sizeof(expected) / sizeof(filepath_errorcode_t);
|
||||
sizeof(expected) / sizeof(stl_testcase);
|
||||
size_t i; /* for loop counter */
|
||||
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;
|
||||
|
||||
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) {
|
||||
printf("\nfilepath : %s\n"
|
||||
"expected error : 0x%x\n"
|
||||
@ -68,12 +153,26 @@ const char* test_stl_read()
|
||||
err);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
struct stl_triangle_array
|
||||
{
|
||||
gmio_stl_triangle_t* ptr;
|
||||
|
Loading…
Reference in New Issue
Block a user