--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dbutils/json.c Tue Dec 09 18:24:48 2025 +0100 @@ -0,0 +1,97 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2024 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "json.h" + +CxJsonValue* dbuObjectToJson(DBUClass *type, void *obj, const CxAllocator *a) { + return dbuObjectToJson2(type, obj, a, false, false); +} + +CxJsonValue* dbuObjectToJson2(DBUClass *type, void *obj, const CxAllocator *a, bool setNull, bool forceString) { + if(obj == NULL) { + return cxJsonCreateLiteral(a, CX_JSON_NULL); + } + if(!a) { + a = cxDefaultAllocator; + } + + CxJsonValue *value = cxJsonCreateObj(a); + if(!value) { + return NULL; + } + + // add all primitive values + CxMapIterator i = cxMapIteratorValues(type->fields); + cx_foreach(DBUField *, field, i) { + CxJsonValue *child = NULL; + if(field->toBool) { + bool b = field->toBool(field, obj); + child = cxJsonCreateLiteral(a, b ? CX_JSON_TRUE : CX_JSON_FALSE); + } else if(field->toInt64) { + int64_t i = field->toInt64(field, obj); + child = cxJsonCreateInteger(a, i); + } else if(field->toUInt64) { + uint64_t u = field->toUInt64(field, obj); + child = cxJsonCreateInteger(a, (int64_t)u); + } else if(field->toDouble) { + double d = field->toDouble(field, obj); + child = cxJsonCreateNumber(a, d); + } else if(field->toString) { + cxmutstr s = field->toString(field, obj, a); + if(s.ptr) { + // we don't want to copy the string again, therefore + // we can't use cxJsonCreateString + child = cxMalloc(a, sizeof(CxJsonValue)); + if(!child) { + cxFree(a, s.ptr); + return NULL; + } + child->allocator = a; + child->type = CX_JSON_STRING; + child->value.string = s; + } + } else if(field->toBinary) { + // TODO + } else { + continue; // non-serializable field + } + + if(!child) { + cxJsonValueFree(value); + return NULL; + } + + if(cxJsonObjPut(value, field->name, child)) { + cxJsonValueFree(child); + cxJsonValueFree(value); + return NULL; + } + } + + return value; +}