Skip to content

Commit de8b378

Browse files
#1408 Escape separator characters in entity name when using ecs_get_path
1 parent 7327b73 commit de8b378

File tree

5 files changed

+276
-3
lines changed

5 files changed

+276
-3
lines changed

distr/flecs.c

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10343,7 +10343,28 @@ bool flecs_path_append(
1034310343
}
1034410344

1034510345
if (name) {
10346-
ecs_strbuf_appendstrn(buf, name, name_len);
10346+
/* Check if we need to escape separator character */
10347+
const char *sep_in_name = NULL;
10348+
if (!sep[1]) {
10349+
sep_in_name = strchr(name, sep[0]);
10350+
}
10351+
10352+
if (sep_in_name) {
10353+
const char *name_ptr = name;
10354+
while (sep_in_name) {
10355+
ecs_size_t len = flecs_ito(int32_t, sep_in_name - name_ptr);
10356+
ecs_strbuf_appendstrn(buf, name_ptr, len);
10357+
ecs_strbuf_appendch(buf, '\\');
10358+
ecs_strbuf_appendch(buf, sep[0]);
10359+
10360+
name_ptr = sep_in_name + 1;
10361+
sep_in_name = strchr(name_ptr, sep[0]);
10362+
}
10363+
10364+
ecs_strbuf_appendstr(buf, name_ptr);
10365+
} else {
10366+
ecs_strbuf_appendstrn(buf, name, name_len);
10367+
}
1034710368
} else {
1034810369
ecs_strbuf_appendch(buf, '#');
1034910370
ecs_strbuf_appendint(buf, flecs_uto(int64_t, (uint32_t)child));

src/entity_name.c

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,28 @@ bool flecs_path_append(
6161
}
6262

6363
if (name) {
64-
ecs_strbuf_appendstrn(buf, name, name_len);
64+
/* Check if we need to escape separator character */
65+
const char *sep_in_name = NULL;
66+
if (!sep[1]) {
67+
sep_in_name = strchr(name, sep[0]);
68+
}
69+
70+
if (sep_in_name) {
71+
const char *name_ptr = name;
72+
while (sep_in_name) {
73+
ecs_size_t len = flecs_ito(int32_t, sep_in_name - name_ptr);
74+
ecs_strbuf_appendstrn(buf, name_ptr, len);
75+
ecs_strbuf_appendch(buf, '\\');
76+
ecs_strbuf_appendch(buf, sep[0]);
77+
78+
name_ptr = sep_in_name + 1;
79+
sep_in_name = strchr(name_ptr, sep[0]);
80+
}
81+
82+
ecs_strbuf_appendstr(buf, name_ptr);
83+
} else {
84+
ecs_strbuf_appendstrn(buf, name, name_len);
85+
}
6586
} else {
6687
ecs_strbuf_appendch(buf, '#');
6788
ecs_strbuf_appendint(buf, flecs_uto(int64_t, (uint32_t)child));

test/core/project.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,16 @@
627627
"path_custom_prefix",
628628
"path_prefix_rel_match",
629629
"path_prefix_rel_no_match",
630+
"path_escaped_sep",
631+
"path_escaped_two_sep",
632+
"path_escaped_two_consecutive_sep",
633+
"path_escaped_sep_at_begin",
634+
"path_escaped_sep_at_end",
635+
"path_escaped_sep_w_parent",
636+
"path_only_escaped_sep",
637+
"path_only_escaped_sep_w_parent",
638+
"path_only_escaped_two_sep",
639+
"path_only_escaped_two_sep_w_parent",
630640
"fullpath_for_core",
631641
"path_w_number",
632642
"path_w_entity_id",

test/core/src/Hierarchies.c

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,177 @@ void Hierarchies_path_w_entity_id(void) {
381381
ecs_fini(world);
382382
}
383383

384+
void Hierarchies_path_escaped_sep(void) {
385+
ecs_world_t *world = ecs_mini();
386+
387+
ecs_entity_t e = ecs_entity(world, { .name = "foo\\.bar"});
388+
test_assert(e != 0);
389+
test_str(ecs_get_name(world, e), "foo.bar");
390+
test_assert(ecs_get_parent(world, e) == 0);
391+
test_assert(ecs_lookup(world, "foo\\.bar") == e);
392+
393+
char *path = ecs_get_path(world, e);
394+
test_str(path, "foo\\.bar");
395+
ecs_os_free(path);
396+
397+
ecs_fini(world);
398+
}
399+
400+
void Hierarchies_path_escaped_two_sep(void) {
401+
ecs_world_t *world = ecs_mini();
402+
403+
ecs_entity_t e = ecs_entity(world, { .name = "foo\\.bar\\.woo"});
404+
test_assert(e != 0);
405+
test_str(ecs_get_name(world, e), "foo.bar.woo");
406+
test_assert(ecs_get_parent(world, e) == 0);
407+
test_assert(ecs_lookup(world, "foo\\.bar\\.woo") == e);
408+
409+
char *path = ecs_get_path(world, e);
410+
test_str(path, "foo\\.bar\\.woo");
411+
ecs_os_free(path);
412+
413+
ecs_fini(world);
414+
}
415+
416+
void Hierarchies_path_escaped_two_consecutive_sep(void) {
417+
ecs_world_t *world = ecs_mini();
418+
419+
ecs_entity_t e = ecs_entity(world, { .name = "foo\\.\\.bar\\.woo"});
420+
test_assert(e != 0);
421+
test_str(ecs_get_name(world, e), "foo..bar.woo");
422+
test_assert(ecs_get_parent(world, e) == 0);
423+
test_assert(ecs_lookup(world, "foo\\.\\.bar\\.woo") == e);
424+
425+
char *path = ecs_get_path(world, e);
426+
test_str(path, "foo\\.\\.bar\\.woo");
427+
ecs_os_free(path);
428+
429+
ecs_fini(world);
430+
}
431+
432+
void Hierarchies_path_escaped_sep_at_begin(void) {
433+
ecs_world_t *world = ecs_mini();
434+
435+
ecs_entity_t e = ecs_entity(world, { .name = "\\.foo\\.bar"});
436+
test_assert(e != 0);
437+
test_str(ecs_get_name(world, e), ".foo.bar");
438+
test_assert(ecs_get_parent(world, e) == 0);
439+
test_assert(ecs_lookup(world, "\\.foo\\.bar") == e);
440+
441+
char *path = ecs_get_path(world, e);
442+
test_str(path, "\\.foo\\.bar");
443+
ecs_os_free(path);
444+
445+
ecs_fini(world);
446+
}
447+
448+
void Hierarchies_path_escaped_sep_at_end(void) {
449+
ecs_world_t *world = ecs_mini();
450+
451+
ecs_entity_t e = ecs_entity(world, { .name = "foo\\.bar\\."});
452+
test_assert(e != 0);
453+
test_str(ecs_get_name(world, e), "foo.bar.");
454+
test_assert(ecs_get_parent(world, e) == 0);
455+
test_assert(ecs_lookup(world, "foo\\.bar\\.") == e);
456+
457+
char *path = ecs_get_path(world, e);
458+
test_str(path, "foo\\.bar\\.");
459+
ecs_os_free(path);
460+
461+
ecs_fini(world);
462+
}
463+
464+
void Hierarchies_path_escaped_sep_w_parent(void) {
465+
ecs_world_t *world = ecs_mini();
466+
467+
ecs_entity_t e = ecs_entity(world, { .name = "parent.foo\\.bar"});
468+
test_assert(e != 0);
469+
ecs_entity_t p = ecs_lookup(world, "parent");
470+
test_assert(p != 0);
471+
472+
test_str(ecs_get_name(world, e), "foo.bar");
473+
test_assert(ecs_get_parent(world, e) == p);
474+
test_assert(ecs_lookup(world, "parent.foo\\.bar") == e);
475+
476+
char *path = ecs_get_path(world, e);
477+
test_str(path, "parent.foo\\.bar");
478+
ecs_os_free(path);
479+
480+
ecs_fini(world);
481+
}
482+
483+
void Hierarchies_path_only_escaped_sep(void) {
484+
ecs_world_t *world = ecs_mini();
485+
486+
ecs_entity_t e = ecs_entity(world, { .name = "\\."});
487+
test_assert(e != 0);
488+
489+
test_str(ecs_get_name(world, e), ".");
490+
test_assert(ecs_get_parent(world, e) == 0);
491+
test_assert(ecs_lookup(world, "\\.") == e);
492+
493+
char *path = ecs_get_path(world, e);
494+
test_str(path, "\\.");
495+
ecs_os_free(path);
496+
497+
ecs_fini(world);
498+
}
499+
500+
void Hierarchies_path_only_escaped_sep_w_parent(void) {
501+
ecs_world_t *world = ecs_mini();
502+
503+
ecs_entity_t e = ecs_entity(world, { .name = "parent.\\."});
504+
test_assert(e != 0);
505+
ecs_entity_t p = ecs_lookup(world, "parent");
506+
test_assert(p != 0);
507+
508+
test_str(ecs_get_name(world, e), ".");
509+
test_assert(ecs_get_parent(world, e) == p);
510+
test_assert(ecs_lookup(world, "parent.\\.") == e);
511+
512+
char *path = ecs_get_path(world, e);
513+
test_str(path, "parent.\\.");
514+
ecs_os_free(path);
515+
516+
ecs_fini(world);
517+
}
518+
519+
void Hierarchies_path_only_escaped_two_sep(void) {
520+
ecs_world_t *world = ecs_mini();
521+
522+
ecs_entity_t e = ecs_entity(world, { .name = "\\.\\."});
523+
test_assert(e != 0);
524+
525+
test_str(ecs_get_name(world, e), "..");
526+
test_assert(ecs_get_parent(world, e) == 0);
527+
test_assert(ecs_lookup(world, "\\.\\.") == e);
528+
529+
char *path = ecs_get_path(world, e);
530+
test_str(path, "\\.\\.");
531+
ecs_os_free(path);
532+
533+
ecs_fini(world);
534+
}
535+
536+
void Hierarchies_path_only_escaped_two_sep_w_parent(void) {
537+
ecs_world_t *world = ecs_mini();
538+
539+
ecs_entity_t e = ecs_entity(world, { .name = "parent.\\.\\."});
540+
test_assert(e != 0);
541+
ecs_entity_t p = ecs_lookup(world, "parent");
542+
test_assert(p != 0);
543+
544+
test_str(ecs_get_name(world, e), "..");
545+
test_assert(ecs_get_parent(world, e) == p);
546+
test_assert(ecs_lookup(world, "parent.\\.\\.") == e);
547+
548+
char *path = ecs_get_path(world, e);
549+
test_str(path, "parent.\\.\\.");
550+
ecs_os_free(path);
551+
552+
ecs_fini(world);
553+
}
554+
384555
void Hierarchies_lookup_depth_0(void) {
385556
ecs_world_t *world = ecs_mini();
386557

test/core/src/main.c

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,16 @@ void Hierarchies_path_custom_sep(void);
596596
void Hierarchies_path_custom_prefix(void);
597597
void Hierarchies_path_prefix_rel_match(void);
598598
void Hierarchies_path_prefix_rel_no_match(void);
599+
void Hierarchies_path_escaped_sep(void);
600+
void Hierarchies_path_escaped_two_sep(void);
601+
void Hierarchies_path_escaped_two_consecutive_sep(void);
602+
void Hierarchies_path_escaped_sep_at_begin(void);
603+
void Hierarchies_path_escaped_sep_at_end(void);
604+
void Hierarchies_path_escaped_sep_w_parent(void);
605+
void Hierarchies_path_only_escaped_sep(void);
606+
void Hierarchies_path_only_escaped_sep_w_parent(void);
607+
void Hierarchies_path_only_escaped_two_sep(void);
608+
void Hierarchies_path_only_escaped_two_sep_w_parent(void);
599609
void Hierarchies_fullpath_for_core(void);
600610
void Hierarchies_path_w_number(void);
601611
void Hierarchies_path_w_entity_id(void);
@@ -4550,6 +4560,46 @@ bake_test_case Hierarchies_testcases[] = {
45504560
"path_prefix_rel_no_match",
45514561
Hierarchies_path_prefix_rel_no_match
45524562
},
4563+
{
4564+
"path_escaped_sep",
4565+
Hierarchies_path_escaped_sep
4566+
},
4567+
{
4568+
"path_escaped_two_sep",
4569+
Hierarchies_path_escaped_two_sep
4570+
},
4571+
{
4572+
"path_escaped_two_consecutive_sep",
4573+
Hierarchies_path_escaped_two_consecutive_sep
4574+
},
4575+
{
4576+
"path_escaped_sep_at_begin",
4577+
Hierarchies_path_escaped_sep_at_begin
4578+
},
4579+
{
4580+
"path_escaped_sep_at_end",
4581+
Hierarchies_path_escaped_sep_at_end
4582+
},
4583+
{
4584+
"path_escaped_sep_w_parent",
4585+
Hierarchies_path_escaped_sep_w_parent
4586+
},
4587+
{
4588+
"path_only_escaped_sep",
4589+
Hierarchies_path_only_escaped_sep
4590+
},
4591+
{
4592+
"path_only_escaped_sep_w_parent",
4593+
Hierarchies_path_only_escaped_sep_w_parent
4594+
},
4595+
{
4596+
"path_only_escaped_two_sep",
4597+
Hierarchies_path_only_escaped_two_sep
4598+
},
4599+
{
4600+
"path_only_escaped_two_sep_w_parent",
4601+
Hierarchies_path_only_escaped_two_sep_w_parent
4602+
},
45534603
{
45544604
"fullpath_for_core",
45554605
Hierarchies_fullpath_for_core
@@ -11145,7 +11195,7 @@ static bake_test_suite suites[] = {
1114511195
"Hierarchies",
1114611196
Hierarchies_setup,
1114711197
NULL,
11148-
95,
11198+
105,
1114911199
Hierarchies_testcases
1115011200
},
1115111201
{

0 commit comments

Comments
 (0)