gmio_stl: simplify code of gmio_stla_infos_get()
This commit is contained in:
parent
f8e73f5747
commit
b7bceff748
@ -214,7 +214,7 @@ static void bmk_gmio_stl_readwrite_conv(const void* filepath)
|
|||||||
fclose(outfile);
|
fclose(outfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bmk_gmio_stl_infos_get(const void* filepath)
|
void bmk_gmio_stl_infos_get_all(const void* filepath)
|
||||||
{
|
{
|
||||||
static bool already_exec = false;
|
static bool already_exec = false;
|
||||||
FILE* file = fopen(filepath, "rb");
|
FILE* file = fopen(filepath, "rb");
|
||||||
@ -225,7 +225,7 @@ void bmk_gmio_stl_infos_get(const void* filepath)
|
|||||||
gmio_stl_infos_get(&infos, stream, GMIO_STL_INFO_FLAG_ALL, NULL);
|
gmio_stl_infos_get(&infos, stream, GMIO_STL_INFO_FLAG_ALL, NULL);
|
||||||
|
|
||||||
if (!already_exec) {
|
if (!already_exec) {
|
||||||
printf("stl_infos_get()\n"
|
printf("stl_infos_get(ALL)\n"
|
||||||
" File: %s\n"
|
" File: %s\n"
|
||||||
" Size: %uKo\n"
|
" Size: %uKo\n"
|
||||||
" Facets: %u\n",
|
" Facets: %u\n",
|
||||||
@ -247,6 +247,29 @@ void bmk_gmio_stl_infos_get(const void* filepath)
|
|||||||
fclose(file);
|
fclose(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void bmk_gmio_stl_infos_get_size(const void* filepath)
|
||||||
|
{
|
||||||
|
static bool already_exec = false;
|
||||||
|
FILE* file = fopen(filepath, "rb");
|
||||||
|
|
||||||
|
if (file != NULL) {
|
||||||
|
const struct gmio_stream stream = gmio_stream_stdio(file);
|
||||||
|
struct gmio_stl_infos infos = {0};
|
||||||
|
gmio_stl_infos_get(&infos, stream, GMIO_STL_INFO_FLAG_SIZE, NULL);
|
||||||
|
|
||||||
|
if (!already_exec) {
|
||||||
|
printf("stl_infos_get(SIZE)\n"
|
||||||
|
" File: %s\n"
|
||||||
|
" Size: %uKo\n",
|
||||||
|
(const char*)filepath,
|
||||||
|
infos.size / 1024);
|
||||||
|
}
|
||||||
|
already_exec = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
@ -261,7 +284,10 @@ int main(int argc, char** argv)
|
|||||||
bmk_gmio_stl_readwrite_conv, NULL,
|
bmk_gmio_stl_readwrite_conv, NULL,
|
||||||
NULL, NULL },
|
NULL, NULL },
|
||||||
{ "stl_infos_get(ALL)",
|
{ "stl_infos_get(ALL)",
|
||||||
bmk_gmio_stl_infos_get, NULL,
|
bmk_gmio_stl_infos_get_all, NULL,
|
||||||
|
NULL, NULL },
|
||||||
|
{ "stl_infos_get(size)",
|
||||||
|
bmk_gmio_stl_infos_get_size, NULL,
|
||||||
NULL, NULL },
|
NULL, NULL },
|
||||||
{0}
|
{0}
|
||||||
};
|
};
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
/* Skip characters until an ASCII space is met */
|
||||||
static const char* gmio_stringstream_skip_until_ascii_space(
|
static const char* gmio_stringstream_skip_until_ascii_space(
|
||||||
struct gmio_stringstream* sstream)
|
struct gmio_stringstream* sstream)
|
||||||
{
|
{
|
||||||
@ -34,79 +35,27 @@ static const char* gmio_stringstream_skip_until_ascii_space(
|
|||||||
return curr_char;
|
return curr_char;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* gmio_stringstream_skip_word(
|
/* Eats \p str case-insensitive, stops on any difference */
|
||||||
struct gmio_stringstream* sstream)
|
static bool gmio_stringstream_icase_eat(
|
||||||
|
struct gmio_stringstream* sstream, const char* str)
|
||||||
{
|
{
|
||||||
gmio_stringstream_skip_ascii_spaces(sstream);
|
const char* c = gmio_stringstream_next_char(sstream);
|
||||||
return gmio_stringstream_skip_until_ascii_space(sstream);
|
while (c != NULL && *str != 0) {
|
||||||
|
if (!gmio_ascii_char_iequals(*c, *str))
|
||||||
|
return false;
|
||||||
|
c = gmio_stringstream_next_char(sstream);
|
||||||
|
++str;
|
||||||
|
}
|
||||||
|
return *str == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gmio_skip_xyz_coords(struct gmio_stla_parse_data* data)
|
/* Callback invoked by gmio_stringstream */
|
||||||
{
|
static void gmio_stringstream_update_streamsize(
|
||||||
struct gmio_stringstream* sstream = &data->strstream;
|
|
||||||
gmio_stringstream_skip_word(sstream);
|
|
||||||
gmio_stringstream_skip_word(sstream);
|
|
||||||
gmio_stringstream_skip_word(sstream);
|
|
||||||
data->strbuff.len = 0;
|
|
||||||
data->token = unknown_token;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int gmio_skip_facet(struct gmio_stla_parse_data* data)
|
|
||||||
{
|
|
||||||
int errc = 0;
|
|
||||||
if (data->token != FACET_token)
|
|
||||||
errc += gmio_stla_eat_next_token_inplace(data, FACET_token);
|
|
||||||
|
|
||||||
errc += gmio_stringstream_skip_word(&data->strstream) == NULL; /* normal */
|
|
||||||
gmio_skip_xyz_coords(data);
|
|
||||||
|
|
||||||
errc += gmio_stringstream_skip_word(&data->strstream) == NULL; /* outer */
|
|
||||||
errc += gmio_stringstream_skip_word(&data->strstream) == NULL; /* loop */
|
|
||||||
|
|
||||||
errc += gmio_stringstream_skip_word(&data->strstream) == NULL; /* vertex */
|
|
||||||
gmio_skip_xyz_coords(data);
|
|
||||||
errc += gmio_stringstream_skip_word(&data->strstream) == NULL; /* vertex */
|
|
||||||
gmio_skip_xyz_coords(data);
|
|
||||||
errc += gmio_stringstream_skip_word(&data->strstream) == NULL; /* vertex */
|
|
||||||
gmio_skip_xyz_coords(data);
|
|
||||||
|
|
||||||
errc += gmio_stringstream_skip_word(&data->strstream) == NULL; /* endloop */
|
|
||||||
errc += gmio_stringstream_skip_word(&data->strstream) == NULL; /* endfacet */
|
|
||||||
|
|
||||||
return errc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int gmio_stla_check_next_token(
|
|
||||||
struct gmio_stringstream* sstream, const char* expected_token_str)
|
|
||||||
{
|
|
||||||
const char* stream_char = NULL;
|
|
||||||
|
|
||||||
stream_char = gmio_stringstream_skip_ascii_spaces(sstream);
|
|
||||||
for (;;) {
|
|
||||||
if (stream_char == NULL || gmio_ascii_isspace(*stream_char)) {
|
|
||||||
if (*expected_token_str == 0)
|
|
||||||
return 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (!gmio_ascii_char_iequals(*stream_char, *expected_token_str)
|
|
||||||
|| *expected_token_str == 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
stream_char = gmio_stringstream_next_char(sstream);
|
|
||||||
++expected_token_str;
|
|
||||||
}
|
|
||||||
gmio_stringstream_skip_word(sstream);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gmio_stringstream_stla_read_hook(
|
|
||||||
void* cookie, const struct gmio_string* strbuff)
|
void* cookie, const struct gmio_string* strbuff)
|
||||||
{
|
{
|
||||||
struct gmio_stringstream_stla_cookie* tcookie =
|
gmio_streamsize_t* ptr_size = (gmio_streamsize_t*)(cookie);
|
||||||
(struct gmio_stringstream_stla_cookie*)(cookie);
|
if (ptr_size != NULL)
|
||||||
if (tcookie != NULL)
|
*ptr_size += strbuff->len;
|
||||||
tcookie->stream_offset += strbuff->len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int gmio_stla_infos_get(
|
int gmio_stla_infos_get(
|
||||||
@ -123,13 +72,9 @@ int gmio_stla_infos_get(
|
|||||||
(flags & GMIO_STLA_INFO_FLAG_SOLIDNAME) != 0;
|
(flags & GMIO_STLA_INFO_FLAG_SOLIDNAME) != 0;
|
||||||
|
|
||||||
void* const mblock_ptr = opts->stream_memblock.ptr;
|
void* const mblock_ptr = opts->stream_memblock.ptr;
|
||||||
/* Leave one byte to end the string buffer with 0 */
|
/* Leave one byte to end of string buffer */
|
||||||
const size_t mblock_size = opts->stream_memblock.size - 1;
|
const size_t mblock_size = opts->stream_memblock.size - 1;
|
||||||
struct gmio_stla_parse_data parse_data = {0};
|
struct gmio_stringstream sstream = {0};
|
||||||
struct gmio_stringstream* sstream = &parse_data.strstream;
|
|
||||||
struct gmio_string* strbuff = &parse_data.strbuff;
|
|
||||||
char fixed_buffer[GMIO_STLA_READ_STRING_MAX_LEN];
|
|
||||||
|
|
||||||
int err = GMIO_ERROR_OK;
|
int err = GMIO_ERROR_OK;
|
||||||
|
|
||||||
if (flags == 0)
|
if (flags == 0)
|
||||||
@ -137,56 +82,96 @@ int gmio_stla_infos_get(
|
|||||||
if (!gmio_check_memblock(&err, &opts->stream_memblock))
|
if (!gmio_check_memblock(&err, &opts->stream_memblock))
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
parse_data.strstream =
|
/* Initialize string stream */
|
||||||
gmio_stringstream(stream, gmio_string(mblock_ptr, 0, mblock_size));
|
sstream.stream = stream;
|
||||||
parse_data.strstream.func_stream_read_hook = gmio_stringstream_stla_read_hook;
|
sstream.strbuff = gmio_string(mblock_ptr, 0, mblock_size);
|
||||||
|
if (flag_size) {
|
||||||
|
infos->size = 0;
|
||||||
|
sstream.cookie = &infos->size;
|
||||||
|
sstream.func_stream_read_hook = gmio_stringstream_update_streamsize;
|
||||||
|
}
|
||||||
|
gmio_stringstream_init_pos(&sstream);
|
||||||
|
|
||||||
|
if (flag_stla_solidname) {
|
||||||
|
struct gmio_stla_parse_data parse_data = {0};
|
||||||
|
const struct gmio_string* strbuff = &parse_data.strbuff;
|
||||||
|
char fixed_buffer[GMIO_STLA_READ_STRING_MAX_LEN] = {0};
|
||||||
|
|
||||||
|
parse_data.strstream = sstream;
|
||||||
parse_data.strbuff = gmio_string(fixed_buffer, 0, sizeof(fixed_buffer));
|
parse_data.strbuff = gmio_string(fixed_buffer, 0, sizeof(fixed_buffer));
|
||||||
|
|
||||||
gmio_stringstream_skip_word(sstream); /* Skip "\s*solid" */
|
/* Skip "\s*solid" */
|
||||||
|
gmio_stringstream_skip_ascii_spaces(&parse_data.strstream);
|
||||||
|
gmio_stringstream_skip_until_ascii_space(&parse_data.strstream);
|
||||||
|
|
||||||
|
/* Eat solid name */
|
||||||
gmio_stla_parse_solidname_beg(&parse_data);
|
gmio_stla_parse_solidname_beg(&parse_data);
|
||||||
if (flag_stla_solidname) {
|
|
||||||
|
/* Copy parsed solid name into infos->stla_solid_name */
|
||||||
|
{
|
||||||
const size_t name_len_for_cpy =
|
const size_t name_len_for_cpy =
|
||||||
GMIO_MIN(infos->stla_solidname_maxlen, strbuff->len);
|
GMIO_MIN(infos->stla_solidname_maxlen - 1, strbuff->len);
|
||||||
|
|
||||||
strncpy(infos->stla_solidname, strbuff->ptr, name_len_for_cpy);
|
strncpy(infos->stla_solidname, strbuff->ptr, name_len_for_cpy);
|
||||||
/* Null terminate C string */
|
/* Null terminate C string */
|
||||||
if (name_len_for_cpy != 0)
|
if (name_len_for_cpy != 0)
|
||||||
infos->stla_solidname[name_len_for_cpy - 1] = 0;
|
infos->stla_solidname[name_len_for_cpy] = 0;
|
||||||
else if (infos->stla_solidname_maxlen != 0)
|
else if (infos->stla_solidname_maxlen != 0)
|
||||||
infos->stla_solidname[0] = 0;
|
infos->stla_solidname[0] = 0;
|
||||||
gmio_string_clear(strbuff);
|
}
|
||||||
|
sstream = parse_data.strstream;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flag_facet_count) {
|
if (flag_facet_count) {
|
||||||
|
bool endfound = false;
|
||||||
|
|
||||||
infos->facet_count = 0;
|
infos->facet_count = 0;
|
||||||
while (parse_data.token == FACET_token
|
|
||||||
&& !parse_data.error
|
while (!endfound) {
|
||||||
&& gmio_stringstream_current_char(sstream) != NULL)
|
const char* c = gmio_stringstream_skip_ascii_spaces(&sstream);
|
||||||
{
|
if (c != NULL) {
|
||||||
if (gmio_skip_facet(&parse_data) == 0) {
|
if (gmio_ascii_char_iequals(*c, 'f')) {
|
||||||
|
if (gmio_stringstream_icase_eat(&sstream, "acet"))
|
||||||
++infos->facet_count;
|
++infos->facet_count;
|
||||||
/* Eat next unknown token */
|
|
||||||
strbuff->len = 0;
|
|
||||||
gmio_stringstream_eat_word(sstream, strbuff);
|
|
||||||
parse_data.token =
|
|
||||||
gmio_stla_find_token(strbuff->ptr, strbuff->len);
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
endfound =
|
||||||
|
gmio_ascii_char_iequals(*c, 'e')
|
||||||
|
&& gmio_stringstream_icase_eat(&sstream, "ndsolid");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
endfound = true;
|
||||||
|
}
|
||||||
|
gmio_stringstream_skip_until_ascii_space(&sstream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flag_size) {
|
if (flag_size) {
|
||||||
if (flag_facet_count) { /* We should be near "endsolid" token */
|
/* On case flag_facet_count is on, we should already be after "endsolid"
|
||||||
if (parse_data.token != ENDSOLID_token)
|
* token */
|
||||||
gmio_stla_eat_next_token(&parse_data, ENDSOLID_token);
|
if (!flag_facet_count) {
|
||||||
|
bool endfound = false;
|
||||||
|
while (!endfound) {
|
||||||
|
const char* c = gmio_stringstream_skip_ascii_spaces(&sstream);
|
||||||
|
if (c != NULL) {
|
||||||
|
endfound =
|
||||||
|
gmio_ascii_char_iequals(*c, 'e')
|
||||||
|
&& gmio_stringstream_icase_eat(&sstream, "ndsolid");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
while (!gmio_stla_check_next_token(sstream, "endsolid")
|
endfound = true;
|
||||||
&& !parse_data.error
|
}
|
||||||
&& gmio_stringstream_current_char(sstream) != NULL)
|
gmio_stringstream_skip_until_ascii_space(&sstream);
|
||||||
{
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
infos->size = parse_data.strstream_cookie.stream_offset;
|
{ /* Eat whole line */
|
||||||
infos->size += sstream->strbuff_at - strbuff->ptr;
|
const char* c = gmio_stringstream_current_char(&sstream);
|
||||||
|
while (c != NULL && *c != '\n' && *c != '\r')
|
||||||
|
c = gmio_stringstream_next_char(&sstream);
|
||||||
|
}
|
||||||
|
infos->size -= sstream.strbuff_end - sstream.strbuff_at;
|
||||||
|
infos->size = GMIO_MAX(0, infos->size);
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
@ -26,35 +26,39 @@ struct gmio_test_stl_infos
|
|||||||
const char* filepath;
|
const char* filepath;
|
||||||
enum gmio_stl_format format;
|
enum gmio_stl_format format;
|
||||||
uint32_t expected_facet_count;
|
uint32_t expected_facet_count;
|
||||||
gmio_streamsize_t expected_size; /* -2: don't check size
|
gmio_streamsize_t expected_size; /* -1: check against actual file size */
|
||||||
* -1: check against actual file size */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct gmio_test_stl_infos tests[] = {
|
static const struct gmio_test_stl_infos tests[] = {
|
||||||
{ "models/file_empty", GMIO_STL_FORMAT_UNKNOWN, 0, 0 },
|
{ "models/file_empty", GMIO_STL_FORMAT_UNKNOWN, 0, 0 },
|
||||||
{ "models/solid_4vertex.stla", GMIO_STL_FORMAT_ASCII, 1, -2 },
|
{ "models/solid_4vertex.stla", GMIO_STL_FORMAT_ASCII, 1, -1 },
|
||||||
{ "models/solid_anonymous_empty.stla", GMIO_STL_FORMAT_ASCII, 0, -2 },
|
{ "models/solid_anonymous_empty.stla", GMIO_STL_FORMAT_ASCII, 0, -1 },
|
||||||
{ "models/solid_empty.stla", GMIO_STL_FORMAT_ASCII, 0, -2 },
|
{ "models/solid_empty.stla", GMIO_STL_FORMAT_ASCII, 0, -1 },
|
||||||
{ "models/solid_empty.stlb", GMIO_STL_FORMAT_BINARY_LE, 0, -1 },
|
{ "models/solid_empty.stlb", GMIO_STL_FORMAT_BINARY_LE, 0, -1 },
|
||||||
{ "models/solid_empty_name_many_words.stla", GMIO_STL_FORMAT_ASCII, 0, -2 },
|
{ "models/solid_empty_name_many_words.stla", GMIO_STL_FORMAT_ASCII, 0, -1 },
|
||||||
{ "models/solid_empty_name_many_words_single_letters.stla", GMIO_STL_FORMAT_ASCII, 0, -2 },
|
{ "models/solid_empty_name_many_words_single_letters.stla", GMIO_STL_FORMAT_ASCII, 0, -1 },
|
||||||
{ "models/solid_grabcad_arm11_link0_hb.le_stlb", GMIO_STL_FORMAT_BINARY_LE, 1436, -1 },
|
{ "models/solid_grabcad_arm11_link0_hb.le_stlb", GMIO_STL_FORMAT_BINARY_LE, 1436, -1 },
|
||||||
{ "models/solid_jburkardt_sphere.stla", GMIO_STL_FORMAT_ASCII, 228, -2 },
|
{ "models/solid_jburkardt_sphere.stla", GMIO_STL_FORMAT_ASCII, 228, -1 },
|
||||||
{ "models/solid_lack_z.stla", GMIO_STL_FORMAT_ASCII, 1, -2 },
|
{ "models/solid_lack_z.stla", GMIO_STL_FORMAT_ASCII, 1, -1 },
|
||||||
{ "models/solid_one_facet.be_stlb", GMIO_STL_FORMAT_BINARY_BE, 1, -1 },
|
{ "models/solid_one_facet.be_stlb", GMIO_STL_FORMAT_BINARY_BE, 1, -1 },
|
||||||
{ "models/solid_one_facet.le_stlb", GMIO_STL_FORMAT_BINARY_LE, 1, -1 },
|
{ "models/solid_one_facet.le_stlb", GMIO_STL_FORMAT_BINARY_LE, 1, -1 },
|
||||||
{ "models/solid_one_facet.stla", GMIO_STL_FORMAT_ASCII, 1, -2 },
|
{ "models/solid_one_facet.stla", GMIO_STL_FORMAT_ASCII, 1, -1 },
|
||||||
{ "models/solid_one_facet_uppercase.stla", GMIO_STL_FORMAT_ASCII, 1, -2 }
|
{ "models/solid_one_facet_uppercase.stla", GMIO_STL_FORMAT_ASCII, 1, -1 }
|
||||||
};
|
};
|
||||||
|
|
||||||
const char* generic_test_stl_infos(const struct gmio_test_stl_infos* test)
|
const char* generic_test_stl_infos(const struct gmio_test_stl_infos* test)
|
||||||
{
|
{
|
||||||
FILE* file = fopen(test->filepath, "rb");
|
FILE* file = fopen(test->filepath, "rb");
|
||||||
gmio_streamsize_t expected_size = test->expected_size;
|
gmio_streamsize_t expected_size = test->expected_size;
|
||||||
|
char stla_solid_name[512] = {0};
|
||||||
struct gmio_stl_infos infos = {0};
|
struct gmio_stl_infos infos = {0};
|
||||||
struct gmio_stream stream = gmio_stream_stdio(file);
|
struct gmio_stream stream = gmio_stream_stdio(file);
|
||||||
int error = GMIO_ERROR_OK;
|
int error = GMIO_ERROR_OK;
|
||||||
|
|
||||||
|
puts(test->filepath);
|
||||||
|
|
||||||
|
infos.stla_solidname = stla_solid_name;
|
||||||
|
infos.stla_solidname_maxlen = sizeof(stla_solid_name) - 1;
|
||||||
error = gmio_stl_infos_get(&infos, stream, GMIO_STL_INFO_FLAG_ALL, NULL);
|
error = gmio_stl_infos_get(&infos, stream, GMIO_STL_INFO_FLAG_ALL, NULL);
|
||||||
if (test->format != GMIO_STL_FORMAT_UNKNOWN) {
|
if (test->format != GMIO_STL_FORMAT_UNKNOWN) {
|
||||||
UTEST_COMPARE_INT(GMIO_ERROR_OK, error);
|
UTEST_COMPARE_INT(GMIO_ERROR_OK, error);
|
||||||
@ -68,8 +72,21 @@ const char* generic_test_stl_infos(const struct gmio_test_stl_infos* test)
|
|||||||
|
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
|
||||||
if (test->expected_size != -2)
|
if (test->format == GMIO_STL_FORMAT_ASCII) {
|
||||||
|
const size_t name_len = strlen(stla_solid_name);
|
||||||
|
#if 0
|
||||||
|
printf("expected_size=%d "
|
||||||
|
"name_len=%d "
|
||||||
|
"infos.size=%d "
|
||||||
|
"infos.solid_name=%s\n",
|
||||||
|
expected_size, name_len, infos.size, infos.stla_solidname);
|
||||||
|
#endif
|
||||||
|
UTEST_ASSERT((expected_size - name_len) <= infos.size);
|
||||||
|
UTEST_ASSERT(infos.size <= (expected_size + name_len));
|
||||||
|
}
|
||||||
|
else {
|
||||||
UTEST_COMPARE_INT(expected_size, infos.size);
|
UTEST_COMPARE_INT(expected_size, infos.size);
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user