Skip to content

Commit 9c86fad

Browse files
Merge pull request #7 from dreamer-coding/main
Adds on to JSON library
2 parents 4804ad3 + a9919a8 commit 9c86fad

File tree

3 files changed

+673
-0
lines changed

3 files changed

+673
-0
lines changed

code/logic/fossil/media/json.h

Lines changed: 349 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,198 @@ char *fossil_media_json_roundtrip(const char *json_text, int pretty, fossil_medi
250250
*/
251251
const char *fossil_media_json_type_name(fossil_media_json_type_t t);
252252

253+
/** @name Clone & Equality
254+
* @{
255+
*/
256+
257+
/**
258+
* @brief Deep-copy a JSON value.
259+
*
260+
* Recursively clones the entire JSON value and its children.
261+
*
262+
* @param src Source JSON value (must not be NULL).
263+
* @return Newly allocated JSON value on success, or NULL on failure.
264+
*/
265+
fossil_media_json_value_t *
266+
fossil_media_json_clone(const fossil_media_json_value_t *src);
267+
268+
/**
269+
* @brief Compare two JSON values for equality.
270+
*
271+
* Performs a deep structural and value comparison.
272+
*
273+
* @param a First JSON value.
274+
* @param b Second JSON value.
275+
* @return 1 if equal, 0 if not equal, -1 on error.
276+
*/
277+
int fossil_media_json_equals(const fossil_media_json_value_t *a,
278+
const fossil_media_json_value_t *b);
279+
280+
/** @} */
281+
282+
/** @name Type Helpers
283+
* @{
284+
*/
285+
286+
/**
287+
* @brief Check if a JSON value is null.
288+
*
289+
* @param v JSON value to check.
290+
* @return 1 if null, 0 otherwise.
291+
*/
292+
int fossil_media_json_is_null(const fossil_media_json_value_t *v);
293+
294+
/**
295+
* @brief Check if a JSON value is an array.
296+
*
297+
* @param v JSON value to check.
298+
* @return 1 if array, 0 otherwise.
299+
*/
300+
int fossil_media_json_is_array(const fossil_media_json_value_t *v);
301+
302+
/**
303+
* @brief Check if a JSON value is an object.
304+
*
305+
* @param v JSON value to check.
306+
* @return 1 if object, 0 otherwise.
307+
*/
308+
int fossil_media_json_is_object(const fossil_media_json_value_t *v);
309+
310+
/** @} */
311+
312+
/** @name Memory & Capacity
313+
* @{
314+
*/
315+
316+
/**
317+
* @brief Reserve capacity for a JSON array.
318+
*
319+
* Ensures that the array can hold at least `capacity` items without resizing.
320+
*
321+
* @param arr JSON array value (must be of type ARRAY).
322+
* @param capacity Desired capacity.
323+
* @return 0 on success, nonzero on error.
324+
*/
325+
int fossil_media_json_array_reserve(fossil_media_json_value_t *arr, size_t capacity);
326+
327+
/**
328+
* @brief Reserve capacity for a JSON object.
329+
*
330+
* Ensures that the object can hold at least `capacity` key/value pairs.
331+
*
332+
* @param obj JSON object value (must be of type OBJECT).
333+
* @param capacity Desired capacity.
334+
* @return 0 on success, nonzero on error.
335+
*/
336+
int fossil_media_json_object_reserve(fossil_media_json_value_t *obj, size_t capacity);
337+
338+
/** @} */
339+
340+
/** @name File I/O
341+
* @{
342+
*/
343+
344+
/**
345+
* @brief Parse a JSON file into a DOM tree.
346+
*
347+
* Reads the entire file and parses it into an internal DOM structure.
348+
*
349+
* @param filename Path to JSON file.
350+
* @param err_out Optional pointer to error details.
351+
* @return Pointer to the parsed JSON value, or NULL on failure.
352+
*/
353+
fossil_media_json_value_t *
354+
fossil_media_json_parse_file(const char *filename, fossil_media_json_error_t *err_out);
355+
356+
/**
357+
* @brief Write a JSON value to a file.
358+
*
359+
* Serializes the JSON value and writes it to the given file.
360+
*
361+
* @param v JSON value to write.
362+
* @param filename Path to output file.
363+
* @param pretty Nonzero for human-readable indentation.
364+
* @param err_out Optional pointer to error details.
365+
* @return 0 on success, nonzero on error.
366+
*/
367+
int fossil_media_json_write_file(const fossil_media_json_value_t *v,
368+
const char *filename,
369+
int pretty,
370+
fossil_media_json_error_t *err_out);
371+
372+
/** @} */
373+
374+
/** @name Number Handling
375+
* @{
376+
*/
377+
378+
/**
379+
* @brief Create a JSON integer value.
380+
*
381+
* Stores an integer in a JSON number node (lossless if within range).
382+
*
383+
* @param i Integer value.
384+
* @return Newly allocated JSON number value, or NULL if allocation fails.
385+
*/
386+
fossil_media_json_value_t *fossil_media_json_new_int(long long i);
387+
388+
/**
389+
* @brief Get an integer from a JSON number.
390+
*
391+
* @param v JSON number value.
392+
* @param out Output pointer to receive integer value.
393+
* @return 0 on success, nonzero if not a number or out of range.
394+
*/
395+
int fossil_media_json_get_int(const fossil_media_json_value_t *v, long long *out);
396+
397+
/** @} */
398+
399+
/** @name Debug & Validation
400+
* @{
401+
*/
402+
403+
/**
404+
* @brief Print a debug dump of a JSON value.
405+
*
406+
* Dumps the JSON tree in a human-readable indented format for debugging.
407+
*
408+
* @param v JSON value to dump.
409+
* @param indent Starting indentation level.
410+
*/
411+
void fossil_media_json_debug_dump(const fossil_media_json_value_t *v, int indent);
412+
413+
/**
414+
* @brief Validate JSON text without building a DOM.
415+
*
416+
* Parses the text and discards the result, returning only validity status.
417+
*
418+
* @param json_text Input JSON text (NUL-terminated).
419+
* @param err_out Optional pointer to error details.
420+
* @return 0 if valid, nonzero if invalid.
421+
*/
422+
int fossil_media_json_validate(const char *json_text, fossil_media_json_error_t *err_out);
423+
424+
/** @} */
425+
426+
/** @name Path Access
427+
* @{
428+
*/
429+
430+
/**
431+
* @brief Get a JSON value using a dotted path expression.
432+
*
433+
* Supports object keys and array indices, e.g. "user.name" or "items[2].id".
434+
*
435+
* @param root Root JSON value.
436+
* @param path Path string (UTF-8, cannot be NULL).
437+
* @return Pointer to the JSON value, or NULL if not found.
438+
*/
439+
fossil_media_json_value_t *
440+
fossil_media_json_get_path(const fossil_media_json_value_t *root, const char *path);
441+
442+
/** @} */
443+
444+
253445
#ifdef __cplusplus
254446
}
255447
#include <string>
@@ -437,6 +629,163 @@ namespace fossil {
437629
free(s);
438630
return result;
439631
}
632+
633+
/**
634+
* @brief Deep copy this JSON value.
635+
* @return A new Json object that is a clone of this value.
636+
* @throws JsonError if cloning fails.
637+
*/
638+
Json clone() const {
639+
fossil_media_json_value_t* v = fossil_media_json_clone(value_);
640+
if (!v) {
641+
throw JsonError("Failed to clone JSON value");
642+
}
643+
return Json(v);
644+
}
645+
646+
/**
647+
* @brief Compare this JSON value to another for equality.
648+
* @param other The other Json object to compare.
649+
* @return true if equal, false otherwise.
650+
* @throws JsonError if comparison fails.
651+
*/
652+
bool equals(const Json& other) const {
653+
int result = fossil_media_json_equals(value_, other.value_);
654+
if (result == -1) {
655+
throw JsonError("Failed to compare JSON values");
656+
}
657+
return result == 1;
658+
}
659+
660+
/**
661+
* @brief Check if this value is null.
662+
* @return true if null, false otherwise.
663+
*/
664+
bool is_null() const {
665+
return fossil_media_json_is_null(value_) == 1;
666+
}
667+
668+
/**
669+
* @brief Check if this value is an array.
670+
* @return true if array, false otherwise.
671+
*/
672+
bool is_array() const {
673+
return fossil_media_json_is_array(value_) == 1;
674+
}
675+
676+
/**
677+
* @brief Check if this value is an object.
678+
* @return true if object, false otherwise.
679+
*/
680+
bool is_object() const {
681+
return fossil_media_json_is_object(value_) == 1;
682+
}
683+
684+
/**
685+
* @brief Reserve capacity for a JSON array.
686+
* @param capacity Desired capacity.
687+
* @throws JsonError if not an array or reserve fails.
688+
*/
689+
void array_reserve(size_t capacity) {
690+
if (fossil_media_json_array_reserve(value_, capacity) != 0) {
691+
throw JsonError("Failed to reserve array capacity");
692+
}
693+
}
694+
695+
/**
696+
* @brief Reserve capacity for a JSON object.
697+
* @param capacity Desired capacity.
698+
* @throws JsonError if not an object or reserve fails.
699+
*/
700+
void object_reserve(size_t capacity) {
701+
if (fossil_media_json_object_reserve(value_, capacity) != 0) {
702+
throw JsonError("Failed to reserve object capacity");
703+
}
704+
}
705+
706+
/**
707+
* @brief Parse a JSON file into a Json object.
708+
* @param filename Path to JSON file.
709+
* @return Parsed Json object.
710+
* @throws JsonError if parsing fails.
711+
*/
712+
static Json parse_file(const std::string& filename) {
713+
fossil_media_json_error_t err{};
714+
fossil_media_json_value_t* val = fossil_media_json_parse_file(filename.c_str(), &err);
715+
if (!val) {
716+
throw JsonError(std::string("Parse file error: ") + err.message);
717+
}
718+
return Json(val);
719+
}
720+
721+
/**
722+
* @brief Write this JSON value to a file.
723+
* @param filename Path to output file.
724+
* @param pretty If true, output with indentation.
725+
* @throws JsonError if writing fails.
726+
*/
727+
void write_file(const std::string& filename, bool pretty = false) const {
728+
fossil_media_json_error_t err{};
729+
int rc = fossil_media_json_write_file(value_, filename.c_str(), pretty ? 1 : 0, &err);
730+
if (rc != 0) {
731+
throw JsonError(std::string("Write file error: ") + err.message);
732+
}
733+
}
734+
735+
/**
736+
* @brief Create a JSON integer value.
737+
* @param i Integer value.
738+
* @return Json object holding an integer.
739+
*/
740+
static Json new_int(long long i) {
741+
return Json(fossil_media_json_new_int(i));
742+
}
743+
744+
/**
745+
* @brief Get integer value from this JSON number.
746+
* @return Integer value.
747+
* @throws JsonError if not a number or out of range.
748+
*/
749+
long long get_int() const {
750+
long long out = 0;
751+
if (fossil_media_json_get_int(value_, &out) != 0) {
752+
throw JsonError("Failed to get integer from JSON value");
753+
}
754+
return out;
755+
}
756+
757+
/**
758+
* @brief Print a debug dump of this JSON value.
759+
* @param indent Starting indentation level.
760+
*/
761+
void debug_dump(int indent = 0) const {
762+
fossil_media_json_debug_dump(value_, indent);
763+
}
764+
765+
/**
766+
* @brief Validate JSON text without building a DOM.
767+
* @param text Input JSON text.
768+
* @return true if valid, false otherwise.
769+
*/
770+
static bool validate(const std::string& text) {
771+
fossil_media_json_error_t err{};
772+
return fossil_media_json_validate(text.c_str(), &err) == 0;
773+
}
774+
775+
/**
776+
* @brief Get a JSON value using a dotted path expression.
777+
* @param path Path string (e.g., "user.name" or "items[2].id").
778+
* @return Json object at the path.
779+
* @throws JsonError if not found.
780+
*/
781+
Json get_path(const std::string& path) const {
782+
fossil_media_json_value_t* v = fossil_media_json_get_path(value_, path.c_str());
783+
if (!v) {
784+
// Return a null Json object if path not found
785+
return Json(fossil_media_json_new_null());
786+
}
787+
return Json(v);
788+
}
440789

441790
private:
442791
fossil_media_json_value_t* value_;

0 commit comments

Comments
 (0)