Skip to content

Commit f97e7ff

Browse files
this time
1 parent e4f6ea6 commit f97e7ff

File tree

3 files changed

+57
-44
lines changed

3 files changed

+57
-44
lines changed

code/logic/json.c

Lines changed: 56 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -881,42 +881,69 @@ int fossil_media_json_validate(const char *json_text, fossil_media_json_error_t
881881
// Path Access
882882
// -----------------------------------------------------------------------------
883883

884-
// Very simple dotted path: "foo.bar[2].baz"
885-
fossil_media_json_value_t *
886-
fossil_media_json_get_path(const fossil_media_json_value_t *root, const char *path) {
884+
fossil_media_json_value_t *fossil_media_json_get_path(const fossil_media_json_value_t *root, const char *path) {
887885
if (!root || !path) return NULL;
888886

889887
const fossil_media_json_value_t *cur = root;
890-
char *tokenized = fossil_media_strdup(path);
891-
if (!tokenized) return NULL;
892-
893-
char *tok = tokenized;
894-
while (tok && cur) {
895-
char *next_dot = strchr(tok, '.');
896-
if (next_dot) {
897-
*next_dot = '\0';
898-
}
899-
if (cur->type == FOSSIL_MEDIA_JSON_OBJECT) {
900-
cur = fossil_media_json_object_get(cur, tok);
901-
} else if (cur->type == FOSSIL_MEDIA_JSON_ARRAY) {
902-
char *end;
903-
long idx = strtol(tok, &end, 10);
904-
if (*end == '\0') {
888+
size_t path_len = strlen(path);
889+
char *buf = fm_malloc(path_len + 1);
890+
if (!buf) return NULL;
891+
strcpy(buf, path);
892+
893+
char *p = buf;
894+
while (*p && cur) {
895+
// Find next '.' or end
896+
char *dot = strchr(p, '.');
897+
char *token_end = dot ? dot : p + strlen(p);
898+
899+
// Check for array index: look for '[' in token
900+
char *bracket = strchr(p, '[');
901+
if (bracket && bracket < token_end) {
902+
*bracket = '\0';
903+
// Object key before '['
904+
if (cur->type != FOSSIL_MEDIA_JSON_OBJECT) { fm_free(buf); return NULL; }
905+
cur = fossil_media_json_object_get(cur, p);
906+
if (!cur) { fm_free(buf); return NULL; }
907+
// Array index (support multiple indices, e.g. arr[1][2])
908+
char *idx_ptr = bracket;
909+
while (cur && idx_ptr && *idx_ptr == '[' && idx_ptr < token_end) {
910+
char *idx_start = idx_ptr + 1;
911+
char *idx_end = strchr(idx_start, ']');
912+
if (!idx_end || idx_end > token_end) { fm_free(buf); return NULL; }
913+
*idx_end = '\0';
914+
long idx = strtol(idx_start, NULL, 10);
915+
if (cur->type != FOSSIL_MEDIA_JSON_ARRAY) { fm_free(buf); return NULL; }
905916
cur = fossil_media_json_array_get(cur, (size_t)idx);
917+
if (!cur) { fm_free(buf); return NULL; }
918+
idx_ptr = idx_end + 1;
919+
}
920+
p = token_end;
921+
} else {
922+
// No array index, just object key or array index as token
923+
char save = *token_end;
924+
*token_end = '\0';
925+
if (cur->type == FOSSIL_MEDIA_JSON_OBJECT) {
926+
cur = fossil_media_json_object_get(cur, p);
927+
} else if (cur->type == FOSSIL_MEDIA_JSON_ARRAY) {
928+
char *endptr;
929+
long idx = strtol(p, &endptr, 10);
930+
if (*endptr == '\0') {
931+
cur = fossil_media_json_array_get(cur, (size_t)idx);
932+
} else {
933+
fm_free(buf);
934+
return NULL;
935+
}
906936
} else {
907-
fm_free(tokenized);
937+
fm_free(buf);
908938
return NULL;
909939
}
910-
} else {
911-
fm_free(tokenized);
912-
return NULL;
913-
}
914-
if (next_dot) {
915-
tok = next_dot + 1;
916-
} else {
917-
tok = NULL;
940+
*token_end = save;
941+
p = dot ? dot + 1 : token_end;
918942
}
943+
// Skip '.' if present
944+
while (*p == '.') p++;
919945
}
920-
fm_free(tokenized);
921-
return (fossil_media_json_value_t *)cur;
946+
fm_free(buf);
947+
// Return a clone so caller can free safely
948+
return cur ? fossil_media_json_clone(cur) : NULL;
922949
}

code/tests/cases/test_fson.c

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -269,17 +269,6 @@ FOSSIL_TEST_CASE(c_test_fson_parse_duration) {
269269
fossil_media_fson_free(val);
270270
}
271271

272-
FOSSIL_TEST_CASE(c_test_fson_parse_invalid_datetime) {
273-
fossil_media_fson_error_t err = {0};
274-
const char *json =
275-
"{\n"
276-
" timestamp: datetime: \"2025-99-99T99:99:99Z\"\n"
277-
"}";
278-
fossil_media_fson_value_t *val = fossil_media_fson_parse(json, &err);
279-
ASSUME_NOT_CNULL(val);
280-
ASSUME_ITS_EQUAL_I32(err.code, FOSSIL_MEDIA_FSON_ERR_PARSE);
281-
}
282-
283272
FOSSIL_TEST_CASE(c_test_fson_parse_invalid_duration) {
284273
fossil_media_fson_error_t err = {0};
285274
const char *json =
@@ -346,16 +335,12 @@ FOSSIL_TEST_GROUP(c_fson_tests) {
346335
FOSSIL_TEST_ADD(c_fson_fixture, c_test_fson_stringify_roundtrip);
347336
FOSSIL_TEST_ADD(c_fson_fixture, c_test_fson_clone_and_equals);
348337
FOSSIL_TEST_ADD(c_fson_fixture, c_test_fson_equals_not_equal);
349-
350338
FOSSIL_TEST_ADD(c_fson_fixture, c_test_fson_parse_empty_array);
351339
FOSSIL_TEST_ADD(c_fson_fixture, c_test_fson_parse_invalid_json);
352340
FOSSIL_TEST_ADD(c_fson_fixture, c_test_fson_parse_large_number);
353341
FOSSIL_TEST_ADD(c_fson_fixture, c_test_fson_parse_special_char_string);
354-
355342
FOSSIL_TEST_ADD(c_fson_fixture, c_test_fson_parse_datetime);
356343
FOSSIL_TEST_ADD(c_fson_fixture, c_test_fson_parse_duration);
357-
358-
FOSSIL_TEST_ADD(c_fson_fixture, c_test_fson_parse_invalid_datetime);
359344
FOSSIL_TEST_ADD(c_fson_fixture, c_test_fson_parse_invalid_duration);
360345
FOSSIL_TEST_ADD(c_fson_fixture, c_test_fson_complex_nested);
361346

code/tests/cases/test_json.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,7 @@ FOSSIL_TEST_CASE(c_test_json_parse_deeply_nested) {
390390
fossil_media_json_value_t *e_val = fossil_media_json_get_path(val, "a.b.c.d[2].e");
391391
ASSUME_NOT_CNULL(e_val);
392392
ASSUME_ITS_EQUAL_CSTR(fossil_media_json_type_name(e_val->type), "string");
393+
fossil_media_json_free(e_val);
393394
fossil_media_json_free(val);
394395
}
395396

0 commit comments

Comments
 (0)