Skip to main content

cjson_binding/
cjson_ffi.rs

1/***************************************************************************
2 *
3 * cJSON FFI BINDING FOR RUST
4 * Copyright (C) 2026 Antonio Salsi <passy.linux@zresa.it>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <https://www.gnu.org/licenses/>.
18 *
19 ***************************************************************************/
20
21#![allow(non_upper_case_globals)]
22#![allow(non_camel_case_types)]
23#![allow(non_snake_case)]
24#![allow(dead_code)]
25#![allow(clashing_extern_declarations)]
26
27use core::ffi::{c_char, c_double, c_int, c_void};
28
29// ========================
30// COSTANTI
31// ========================
32
33pub const cJSON_Invalid: c_int = 0;
34pub const cJSON_False: c_int = 1 << 0;
35pub const cJSON_True: c_int = 1 << 1;
36pub const cJSON_NULL: c_int = 1 << 2;
37pub const cJSON_Number: c_int = 1 << 3;
38pub const cJSON_String: c_int = 1 << 4;
39pub const cJSON_Array: c_int = 1 << 5;
40pub const cJSON_Object: c_int = 1 << 6;
41pub const cJSON_Raw: c_int = 1 << 7;
42
43pub const cJSON_IsReference: c_int = 256;
44pub const cJSON_StringIsConst: c_int = 512;
45
46pub const CJSON_VERSION_MAJOR: c_int = 1;
47pub const CJSON_VERSION_MINOR: c_int = 7;
48pub const CJSON_VERSION_PATCH: c_int = 19;
49
50pub const CJSON_NESTING_LIMIT: c_int = 1000;
51pub const CJSON_CIRCULAR_LIMIT: c_int = 10000;
52
53// ========================
54// TYPES
55// ========================
56
57// Struct cJSON
58#[repr(C)]
59pub struct cJSON {
60    pub next: *mut cJSON,
61    pub prev: *mut cJSON,
62    pub child: *mut cJSON,
63    pub type_: c_int, // "type" it is a reserved keyword in Rust
64    pub valuestring: *mut c_char,
65    pub valueint: c_int,
66    pub valuedouble: c_double,
67    pub string: *mut c_char,
68}
69
70pub type cJSON_bool = c_int;
71
72// cJSON_Hooks struct
73#[repr(C)]
74pub struct cJSON_Hooks {
75    pub malloc_fn: Option<unsafe extern "C" fn(size: usize) -> *mut c_void>,
76    pub free_fn: Option<unsafe extern "C" fn(ptr: *mut c_void)>,
77}
78
79// ========================
80// FUNCTIONS C (declare extern "C")
81// ========================
82
83unsafe extern "C" {
84    pub fn cJSON_Version() -> *const c_char;
85
86    pub fn cJSON_InitHooks(hooks: *mut cJSON_Hooks);
87
88    pub fn cJSON_Parse(value: *const c_char) -> *mut cJSON;
89    pub fn cJSON_ParseWithLength(value: *const c_char, buffer_length: usize) -> *mut cJSON;
90    pub fn cJSON_ParseWithOpts(
91        value: *const c_char,
92        return_parse_end: *mut *const c_char,
93        require_null_terminated: cJSON_bool,
94    ) -> *mut cJSON;
95    pub fn cJSON_ParseWithLengthOpts(
96        value: *const c_char,
97        buffer_length: usize,
98        return_parse_end: *mut *const c_char,
99        require_null_terminated: cJSON_bool,
100    ) -> *mut cJSON;
101
102    pub fn cJSON_Print(item: *const cJSON) -> *mut c_char;
103    pub fn cJSON_PrintUnformatted(item: *const cJSON) -> *mut c_char;
104    pub fn cJSON_PrintBuffered(item: *const cJSON, prebuffer: c_int, fmt: cJSON_bool) -> *mut c_char;
105    pub fn cJSON_PrintPreallocated(
106        item: *mut cJSON,
107        buffer: *mut c_char,
108        length: c_int,
109        format: cJSON_bool,
110    ) -> cJSON_bool;
111
112    pub fn cJSON_Delete(item: *mut cJSON);
113
114    pub fn cJSON_GetArraySize(array: *const cJSON) -> c_int;
115    pub fn cJSON_GetArrayItem(array: *const cJSON, index: c_int) -> *mut cJSON;
116    pub fn cJSON_GetObjectItem(object: *const cJSON, string: *const c_char) -> *mut cJSON;
117    pub fn cJSON_GetObjectItemCaseSensitive(object: *const cJSON, string: *const c_char) -> *mut cJSON;
118    pub fn cJSON_HasObjectItem(object: *const cJSON, string: *const c_char) -> cJSON_bool;
119
120    pub fn cJSON_GetErrorPtr() -> *const c_char;
121
122    pub fn cJSON_GetStringValue(item: *const cJSON) -> *const c_char;
123    pub fn cJSON_GetNumberValue(item: *const cJSON) -> c_double;
124
125    pub fn cJSON_IsInvalid(item: *const cJSON) -> cJSON_bool;
126    pub fn cJSON_IsFalse(item: *const cJSON) -> cJSON_bool;
127    pub fn cJSON_IsTrue(item: *const cJSON) -> cJSON_bool;
128    pub fn cJSON_IsBool(item: *const cJSON) -> cJSON_bool;
129    pub fn cJSON_IsNull(item: *const cJSON) -> cJSON_bool;
130    pub fn cJSON_IsNumber(item: *const cJSON) -> cJSON_bool;
131    pub fn cJSON_IsString(item: *const cJSON) -> cJSON_bool;
132    pub fn cJSON_IsArray(item: *const cJSON) -> cJSON_bool;
133    pub fn cJSON_IsObject(item: *const cJSON) -> cJSON_bool;
134    pub fn cJSON_IsRaw(item: *const cJSON) -> cJSON_bool;
135
136    pub fn cJSON_CreateNull() -> *mut cJSON;
137    pub fn cJSON_CreateTrue() -> *mut cJSON;
138    pub fn cJSON_CreateFalse() -> *mut cJSON;
139    pub fn cJSON_CreateBool(boolean: cJSON_bool) -> *mut cJSON;
140    pub fn cJSON_CreateNumber(num: c_double) -> *mut cJSON;
141    pub fn cJSON_CreateString(string: *const c_char) -> *mut cJSON;
142    pub fn cJSON_CreateRaw(raw: *const c_char) -> *mut cJSON;
143    pub fn cJSON_CreateArray() -> *mut cJSON;
144    pub fn cJSON_CreateObject() -> *mut cJSON;
145
146    pub fn cJSON_CreateStringReference(string: *const c_char) -> *mut cJSON;
147    pub fn cJSON_CreateObjectReference(child: *const cJSON) -> *mut cJSON;
148    pub fn cJSON_CreateArrayReference(child: *const cJSON) -> *mut cJSON;
149
150    pub fn cJSON_CreateIntArray(numbers: *const c_int, count: c_int) -> *mut cJSON;
151    pub fn cJSON_CreateFloatArray(numbers: *const f32, count: c_int) -> *mut cJSON;
152    pub fn cJSON_CreateDoubleArray(numbers: *const c_double, count: c_int) -> *mut cJSON;
153    pub fn cJSON_CreateStringArray(strings: *const *const c_char, count: c_int) -> *mut cJSON;
154
155    pub fn cJSON_AddItemToArray(array: *mut cJSON, item: *mut cJSON) -> cJSON_bool;
156    pub fn cJSON_AddItemToObject(object: *mut cJSON, string: *const c_char, item: *mut cJSON) -> cJSON_bool;
157    pub fn cJSON_AddItemToObjectCS(object: *mut cJSON, string: *const c_char, item: *mut cJSON) -> cJSON_bool;
158    pub fn cJSON_AddItemReferenceToArray(array: *mut cJSON, item: *mut cJSON) -> cJSON_bool;
159    pub fn cJSON_AddItemReferenceToObject(object: *mut cJSON, string: *const c_char, item: *mut cJSON) -> cJSON_bool;
160
161    pub fn cJSON_DetachItemViaPointer(parent: *mut cJSON, item: *mut cJSON) -> *mut cJSON;
162    pub fn cJSON_DetachItemFromArray(array: *mut cJSON, which: c_int) -> *mut cJSON;
163    pub fn cJSON_DeleteItemFromArray(array: *mut cJSON, which: c_int);
164    pub fn cJSON_DetachItemFromObject(object: *mut cJSON, string: *const c_char) -> *mut cJSON;
165    pub fn cJSON_DetachItemFromObjectCaseSensitive(object: *mut cJSON, string: *const c_char) -> *mut cJSON;
166    pub fn cJSON_DeleteItemFromObject(object: *mut cJSON, string: *const c_char);
167    pub fn cJSON_DeleteItemFromObjectCaseSensitive(object: *mut cJSON, string: *const c_char);
168
169    pub fn cJSON_InsertItemInArray(array: *mut cJSON, which: c_int, newitem: *mut cJSON) -> cJSON_bool;
170    pub fn cJSON_ReplaceItemViaPointer(parent: *mut cJSON, item: *mut cJSON, replacement: *mut cJSON) -> cJSON_bool;
171    pub fn cJSON_ReplaceItemInArray(array: *mut cJSON, which: c_int, newitem: *mut cJSON) -> cJSON_bool;
172    pub fn cJSON_ReplaceItemInObject(object: *mut cJSON, string: *const c_char, newitem: *mut cJSON) -> cJSON_bool;
173    pub fn cJSON_ReplaceItemInObjectCaseSensitive(object: *mut cJSON, string: *const c_char, newitem: *mut cJSON) -> cJSON_bool;
174
175    pub fn cJSON_Duplicate(item: *const cJSON, recurse: cJSON_bool) -> *mut cJSON;
176    pub fn cJSON_Compare(a: *const cJSON, b: *const cJSON, case_sensitive: cJSON_bool) -> cJSON_bool;
177
178    pub fn cJSON_Minify(json: *mut c_char);
179
180    pub fn cJSON_AddNullToObject(object: *mut cJSON, name: *const c_char) -> *mut cJSON;
181    pub fn cJSON_AddTrueToObject(object: *mut cJSON, name: *const c_char) -> *mut cJSON;
182    pub fn cJSON_AddFalseToObject(object: *mut cJSON, name: *const c_char) -> *mut cJSON;
183    pub fn cJSON_AddBoolToObject(object: *mut cJSON, name: *const c_char, boolean: cJSON_bool) -> *mut cJSON;
184    pub fn cJSON_AddNumberToObject(object: *mut cJSON, name: *const c_char, number: c_double) -> *mut cJSON;
185    pub fn cJSON_AddStringToObject(object: *mut cJSON, name: *const c_char, string: *const c_char) -> *mut cJSON;
186    pub fn cJSON_AddRawToObject(object: *mut cJSON, name: *const c_char, raw: *const c_char) -> *mut cJSON;
187    pub fn cJSON_AddObjectToObject(object: *mut cJSON, name: *const c_char) -> *mut cJSON;
188    pub fn cJSON_AddArrayToObject(object: *mut cJSON, name: *const c_char) -> *mut cJSON;
189
190    pub fn cJSON_SetNumberHelper(object: *mut cJSON, number: c_double) -> c_double;
191    pub fn cJSON_SetValuestring(object: *mut cJSON, valuestring: *const c_char) -> *mut c_char;
192
193    pub fn cJSON_malloc(size: usize) -> *mut c_void;
194    pub fn cJSON_free(object: *mut c_void);
195}
196
197// ========================
198// MACRO (translated from C to Rust)
199// ========================
200
201// cJSON_SetIntValue
202#[macro_export]
203macro_rules! cJSON_SetIntValue {
204    ($object:expr, $number:expr) => {
205        if let Some(obj) = unsafe { $object.as_mut() } {
206            obj.valueint = $number;
207            obj.valuedouble = $number as f64;
208            $number
209        } else {
210            $number
211        }
212    };
213}
214
215// cJSON_SetNumberValue
216#[macro_export]
217macro_rules! cJSON_SetNumberValue {
218    ($object:expr, $number:expr) => {
219        if let Some(obj) = unsafe { $object.as_mut() } {
220            crate::cJSON_SetNumberHelper(obj, $number as f64)
221        } else {
222            $number as f64
223        }
224    };
225}
226
227// cJSON_SetBoolValue
228#[macro_export]
229macro_rules! cJSON_SetBoolValue {
230    ($object:expr, $boolValue:expr) => {
231        if let Some(obj) = unsafe { $object.as_mut() } {
232            if (obj.type_ & (crate::cJSON_False | crate::cJSON_True)) != 0 {
233                obj.type_ = (obj.type_ & !(crate::cJSON_False | crate::cJSON_True)) | if $boolValue { crate::cJSON_True } else { crate::cJSON_False };
234                obj.type_
235            } else {
236                crate::cJSON_Invalid
237            }
238        } else {
239            crate::cJSON_Invalid
240        }
241    };
242}
243
244// cJSON_ArrayForEach
245#[macro_export]
246macro_rules! cJSON_ArrayForEach {
247    ($element:ident, $array:expr) => {
248        let mut $element = if let Some(arr) = unsafe { $array.as_ref() } {
249            arr.child
250        } else {
251            core::ptr::null_mut()
252        };
253        while !($element).is_null() {
254            {
255                // body of the loop goes here
256            }
257            $element = unsafe { (*$element).next };
258        }
259    };
260}
261
262// // ========================
263// // FUNZIONI DI UTILITÀ (opzionali)
264// // ========================
265
266// // Wrapper sicuro per cJSON_Delete (evita double free)
267// pub unsafe fn cJSON_Delete_safe(item: *mut cJSON) {
268//     if !item.is_null() {
269//         unsafe { cJSON_Delete(item); }
270//     }
271// }
272
273// // Wrapper per cJSON_Parse con gestione errori — usa alloc::string::String
274// pub unsafe fn cJSON_Parse_safe(json_str: &str) -> Option<*mut cJSON> {
275//     let c_str = CString::new(json_str).ok()?;
276//     let ptr = unsafe { cJSON_Parse(c_str.as_ptr()) };
277//     if ptr.is_null() {
278//         None
279//     } else {
280//         Some(ptr)
281//     }
282// }
283
284// // Wrapper per cJSON_Print con deallocazione automatica — ritorna alloc::string::String
285// pub unsafe fn cJSON_Print_safe(item: *mut cJSON) -> Option<String> {
286//     if item.is_null() {
287//         return None;
288//     }
289//     let c_str = unsafe { cJSON_Print(item) };
290//     if c_str.is_null() {
291//         return None;
292//     }
293//     let rust_str = unsafe { CStr::from_ptr(c_str).to_string_lossy().into_owned() };
294//     unsafe { cJSON_free(c_str as *mut c_void); }
295//     Some(rust_str)
296// }
297
298// // Wrapper per cJSON_GetStringValue — ritorna String
299// pub unsafe fn cJSON_GetStringValue_safe(item: *const cJSON) -> Option<String> {
300//     if item.is_null() {
301//         return None;
302//     }
303//     let c_str = unsafe { cJSON_GetStringValue(item) };
304//     if c_str.is_null() {
305//         return None;
306//     }
307//     Some(unsafe { CStr::from_ptr(c_str).to_string_lossy().into_owned() })
308// }
309
310// // Wrapper per cJSON_GetNumberValue — ritorna f64
311// pub unsafe fn cJSON_GetNumberValue_safe(item: *const cJSON) -> Option<f64> {
312//     if item.is_null() {
313//         return None;
314//     }
315//     Some(unsafe { cJSON_GetNumberValue(item) })
316// }