Skip to content

Commit

Permalink
#1408 Escape separator characters in entity name when using ecs_get_path
Browse files Browse the repository at this point in the history
  • Loading branch information
SanderMertens authored Oct 19, 2024
1 parent 7327b73 commit de8b378
Show file tree
Hide file tree
Showing 5 changed files with 276 additions and 3 deletions.
23 changes: 22 additions & 1 deletion distr/flecs.c
Original file line number Diff line number Diff line change
Expand Up @@ -10343,7 +10343,28 @@ bool flecs_path_append(
}

if (name) {
ecs_strbuf_appendstrn(buf, name, name_len);
/* Check if we need to escape separator character */
const char *sep_in_name = NULL;
if (!sep[1]) {
sep_in_name = strchr(name, sep[0]);
}

if (sep_in_name) {
const char *name_ptr = name;
while (sep_in_name) {
ecs_size_t len = flecs_ito(int32_t, sep_in_name - name_ptr);
ecs_strbuf_appendstrn(buf, name_ptr, len);
ecs_strbuf_appendch(buf, '\\');
ecs_strbuf_appendch(buf, sep[0]);

name_ptr = sep_in_name + 1;
sep_in_name = strchr(name_ptr, sep[0]);
}

ecs_strbuf_appendstr(buf, name_ptr);
} else {
ecs_strbuf_appendstrn(buf, name, name_len);
}
} else {
ecs_strbuf_appendch(buf, '#');
ecs_strbuf_appendint(buf, flecs_uto(int64_t, (uint32_t)child));
Expand Down
23 changes: 22 additions & 1 deletion src/entity_name.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,28 @@ bool flecs_path_append(
}

if (name) {
ecs_strbuf_appendstrn(buf, name, name_len);
/* Check if we need to escape separator character */
const char *sep_in_name = NULL;
if (!sep[1]) {
sep_in_name = strchr(name, sep[0]);
}

if (sep_in_name) {
const char *name_ptr = name;
while (sep_in_name) {
ecs_size_t len = flecs_ito(int32_t, sep_in_name - name_ptr);
ecs_strbuf_appendstrn(buf, name_ptr, len);
ecs_strbuf_appendch(buf, '\\');
ecs_strbuf_appendch(buf, sep[0]);

name_ptr = sep_in_name + 1;
sep_in_name = strchr(name_ptr, sep[0]);
}

ecs_strbuf_appendstr(buf, name_ptr);
} else {
ecs_strbuf_appendstrn(buf, name, name_len);
}
} else {
ecs_strbuf_appendch(buf, '#');
ecs_strbuf_appendint(buf, flecs_uto(int64_t, (uint32_t)child));
Expand Down
10 changes: 10 additions & 0 deletions test/core/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,16 @@
"path_custom_prefix",
"path_prefix_rel_match",
"path_prefix_rel_no_match",
"path_escaped_sep",
"path_escaped_two_sep",
"path_escaped_two_consecutive_sep",
"path_escaped_sep_at_begin",
"path_escaped_sep_at_end",
"path_escaped_sep_w_parent",
"path_only_escaped_sep",
"path_only_escaped_sep_w_parent",
"path_only_escaped_two_sep",
"path_only_escaped_two_sep_w_parent",
"fullpath_for_core",
"path_w_number",
"path_w_entity_id",
Expand Down
171 changes: 171 additions & 0 deletions test/core/src/Hierarchies.c
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,177 @@ void Hierarchies_path_w_entity_id(void) {
ecs_fini(world);
}

void Hierarchies_path_escaped_sep(void) {
ecs_world_t *world = ecs_mini();

ecs_entity_t e = ecs_entity(world, { .name = "foo\\.bar"});
test_assert(e != 0);
test_str(ecs_get_name(world, e), "foo.bar");
test_assert(ecs_get_parent(world, e) == 0);
test_assert(ecs_lookup(world, "foo\\.bar") == e);

char *path = ecs_get_path(world, e);
test_str(path, "foo\\.bar");
ecs_os_free(path);

ecs_fini(world);
}

void Hierarchies_path_escaped_two_sep(void) {
ecs_world_t *world = ecs_mini();

ecs_entity_t e = ecs_entity(world, { .name = "foo\\.bar\\.woo"});
test_assert(e != 0);
test_str(ecs_get_name(world, e), "foo.bar.woo");
test_assert(ecs_get_parent(world, e) == 0);
test_assert(ecs_lookup(world, "foo\\.bar\\.woo") == e);

char *path = ecs_get_path(world, e);
test_str(path, "foo\\.bar\\.woo");
ecs_os_free(path);

ecs_fini(world);
}

void Hierarchies_path_escaped_two_consecutive_sep(void) {
ecs_world_t *world = ecs_mini();

ecs_entity_t e = ecs_entity(world, { .name = "foo\\.\\.bar\\.woo"});
test_assert(e != 0);
test_str(ecs_get_name(world, e), "foo..bar.woo");
test_assert(ecs_get_parent(world, e) == 0);
test_assert(ecs_lookup(world, "foo\\.\\.bar\\.woo") == e);

char *path = ecs_get_path(world, e);
test_str(path, "foo\\.\\.bar\\.woo");
ecs_os_free(path);

ecs_fini(world);
}

void Hierarchies_path_escaped_sep_at_begin(void) {
ecs_world_t *world = ecs_mini();

ecs_entity_t e = ecs_entity(world, { .name = "\\.foo\\.bar"});
test_assert(e != 0);
test_str(ecs_get_name(world, e), ".foo.bar");
test_assert(ecs_get_parent(world, e) == 0);
test_assert(ecs_lookup(world, "\\.foo\\.bar") == e);

char *path = ecs_get_path(world, e);
test_str(path, "\\.foo\\.bar");
ecs_os_free(path);

ecs_fini(world);
}

void Hierarchies_path_escaped_sep_at_end(void) {
ecs_world_t *world = ecs_mini();

ecs_entity_t e = ecs_entity(world, { .name = "foo\\.bar\\."});
test_assert(e != 0);
test_str(ecs_get_name(world, e), "foo.bar.");
test_assert(ecs_get_parent(world, e) == 0);
test_assert(ecs_lookup(world, "foo\\.bar\\.") == e);

char *path = ecs_get_path(world, e);
test_str(path, "foo\\.bar\\.");
ecs_os_free(path);

ecs_fini(world);
}

void Hierarchies_path_escaped_sep_w_parent(void) {
ecs_world_t *world = ecs_mini();

ecs_entity_t e = ecs_entity(world, { .name = "parent.foo\\.bar"});
test_assert(e != 0);
ecs_entity_t p = ecs_lookup(world, "parent");
test_assert(p != 0);

test_str(ecs_get_name(world, e), "foo.bar");
test_assert(ecs_get_parent(world, e) == p);
test_assert(ecs_lookup(world, "parent.foo\\.bar") == e);

char *path = ecs_get_path(world, e);
test_str(path, "parent.foo\\.bar");
ecs_os_free(path);

ecs_fini(world);
}

void Hierarchies_path_only_escaped_sep(void) {
ecs_world_t *world = ecs_mini();

ecs_entity_t e = ecs_entity(world, { .name = "\\."});
test_assert(e != 0);

test_str(ecs_get_name(world, e), ".");
test_assert(ecs_get_parent(world, e) == 0);
test_assert(ecs_lookup(world, "\\.") == e);

char *path = ecs_get_path(world, e);
test_str(path, "\\.");
ecs_os_free(path);

ecs_fini(world);
}

void Hierarchies_path_only_escaped_sep_w_parent(void) {
ecs_world_t *world = ecs_mini();

ecs_entity_t e = ecs_entity(world, { .name = "parent.\\."});
test_assert(e != 0);
ecs_entity_t p = ecs_lookup(world, "parent");
test_assert(p != 0);

test_str(ecs_get_name(world, e), ".");
test_assert(ecs_get_parent(world, e) == p);
test_assert(ecs_lookup(world, "parent.\\.") == e);

char *path = ecs_get_path(world, e);
test_str(path, "parent.\\.");
ecs_os_free(path);

ecs_fini(world);
}

void Hierarchies_path_only_escaped_two_sep(void) {
ecs_world_t *world = ecs_mini();

ecs_entity_t e = ecs_entity(world, { .name = "\\.\\."});
test_assert(e != 0);

test_str(ecs_get_name(world, e), "..");
test_assert(ecs_get_parent(world, e) == 0);
test_assert(ecs_lookup(world, "\\.\\.") == e);

char *path = ecs_get_path(world, e);
test_str(path, "\\.\\.");
ecs_os_free(path);

ecs_fini(world);
}

void Hierarchies_path_only_escaped_two_sep_w_parent(void) {
ecs_world_t *world = ecs_mini();

ecs_entity_t e = ecs_entity(world, { .name = "parent.\\.\\."});
test_assert(e != 0);
ecs_entity_t p = ecs_lookup(world, "parent");
test_assert(p != 0);

test_str(ecs_get_name(world, e), "..");
test_assert(ecs_get_parent(world, e) == p);
test_assert(ecs_lookup(world, "parent.\\.\\.") == e);

char *path = ecs_get_path(world, e);
test_str(path, "parent.\\.\\.");
ecs_os_free(path);

ecs_fini(world);
}

void Hierarchies_lookup_depth_0(void) {
ecs_world_t *world = ecs_mini();

Expand Down
52 changes: 51 additions & 1 deletion test/core/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,16 @@ void Hierarchies_path_custom_sep(void);
void Hierarchies_path_custom_prefix(void);
void Hierarchies_path_prefix_rel_match(void);
void Hierarchies_path_prefix_rel_no_match(void);
void Hierarchies_path_escaped_sep(void);
void Hierarchies_path_escaped_two_sep(void);
void Hierarchies_path_escaped_two_consecutive_sep(void);
void Hierarchies_path_escaped_sep_at_begin(void);
void Hierarchies_path_escaped_sep_at_end(void);
void Hierarchies_path_escaped_sep_w_parent(void);
void Hierarchies_path_only_escaped_sep(void);
void Hierarchies_path_only_escaped_sep_w_parent(void);
void Hierarchies_path_only_escaped_two_sep(void);
void Hierarchies_path_only_escaped_two_sep_w_parent(void);
void Hierarchies_fullpath_for_core(void);
void Hierarchies_path_w_number(void);
void Hierarchies_path_w_entity_id(void);
Expand Down Expand Up @@ -4550,6 +4560,46 @@ bake_test_case Hierarchies_testcases[] = {
"path_prefix_rel_no_match",
Hierarchies_path_prefix_rel_no_match
},
{
"path_escaped_sep",
Hierarchies_path_escaped_sep
},
{
"path_escaped_two_sep",
Hierarchies_path_escaped_two_sep
},
{
"path_escaped_two_consecutive_sep",
Hierarchies_path_escaped_two_consecutive_sep
},
{
"path_escaped_sep_at_begin",
Hierarchies_path_escaped_sep_at_begin
},
{
"path_escaped_sep_at_end",
Hierarchies_path_escaped_sep_at_end
},
{
"path_escaped_sep_w_parent",
Hierarchies_path_escaped_sep_w_parent
},
{
"path_only_escaped_sep",
Hierarchies_path_only_escaped_sep
},
{
"path_only_escaped_sep_w_parent",
Hierarchies_path_only_escaped_sep_w_parent
},
{
"path_only_escaped_two_sep",
Hierarchies_path_only_escaped_two_sep
},
{
"path_only_escaped_two_sep_w_parent",
Hierarchies_path_only_escaped_two_sep_w_parent
},
{
"fullpath_for_core",
Hierarchies_fullpath_for_core
Expand Down Expand Up @@ -11145,7 +11195,7 @@ static bake_test_suite suites[] = {
"Hierarchies",
Hierarchies_setup,
NULL,
95,
105,
Hierarchies_testcases
},
{
Expand Down

0 comments on commit de8b378

Please sign in to comment.