*/
#include <string.h>
+#include <limits.h>
#include "wrap-json.h"
wrap_json_error_incomplete,
wrap_json_error_missfit_type,
wrap_json_error_key_not_found,
+ wrap_json_error_bad_base64,
_wrap_json_error_count_
};
static const char ignore_all[] = " \t\n\r,:";
-static const char pack_accept_arr[] = "][{snbiIfoO";
+static const char pack_accept_arr[] = "][{snbiIfoOyY";
static const char pack_accept_key[] = "s}";
#define pack_accept_any (&pack_accept_arr[1])
-static const char unpack_accept_arr[] = "*!][{snbiIfFoO";
+static const char unpack_accept_arr[] = "*!][{snbiIfFoOyY";
static const char unpack_accept_key[] = "*!s}";
#define unpack_accept_any (&unpack_accept_arr[3])
[wrap_json_error_out_of_range] = "array too small",
[wrap_json_error_incomplete] = "incomplete container",
[wrap_json_error_missfit_type] = "missfit of type",
- [wrap_json_error_key_not_found] = "key not found"
+ [wrap_json_error_key_not_found] = "key not found",
+ [wrap_json_error_bad_base64] = "bad base64 encoding"
};
int wrap_json_get_error_position(int rc)
const char *wrap_json_get_error_string(int rc)
{
rc = wrap_json_get_error_code(rc);
- if (rc >= sizeof pack_errors / sizeof *pack_errors)
+ if (rc >= (int)(sizeof pack_errors / sizeof *pack_errors))
rc = 0;
return pack_errors[rc];
}
+static int encode_base64(
+ const uint8_t *data,
+ size_t datalen,
+ char **encoded,
+ size_t *encodedlen,
+ int width,
+ int pad,
+ int url)
+{
+ uint16_t u16 = 0;
+ uint8_t u8 = 0;
+ size_t in, out, rlen, n3, r3, iout, nout;
+ int iw;
+ char *result, c;
+
+ /* compute unformatted output length */
+ n3 = datalen / 3;
+ r3 = datalen % 3;
+ nout = 4 * n3 + r3 + !!r3;
+
+ /* deduce formatted output length */
+ rlen = nout;
+ if (pad)
+ rlen += ((~rlen) + 1) & 3;
+ if (width)
+ rlen += rlen / width;
+
+ /* allocate the output */
+ result = malloc(rlen + 1);
+ if (result == NULL)
+ return wrap_json_error_out_of_memory;
+
+ /* compute the formatted output */
+ iw = width;
+ for (in = out = iout = 0 ; iout < nout ; iout++) {
+ /* get in 'u8' the 6 bits value to add */
+ switch (iout & 3) {
+ case 0:
+ u16 = (uint16_t)data[in++];
+ u8 = (uint8_t)(u16 >> 2);
+ break;
+ case 1:
+ u16 = (uint16_t)(u16 << 8);
+ if (in < datalen)
+ u16 = (uint16_t)(u16 | data[in++]);
+ u8 = (uint8_t)(u16 >> 4);
+ break;
+ case 2:
+ u16 = (uint16_t)(u16 << 8);
+ if (in < datalen)
+ u16 = (uint16_t)(u16 | data[in++]);
+ u8 = (uint8_t)(u16 >> 6);
+ break;
+ case 3:
+ u8 = (uint8_t)u16;
+ break;
+ }
+ u8 &= 63;
+
+ /* encode 'u8' to the char 'c' */
+ if (u8 < 52) {
+ if (u8 < 26)
+ c = (char)('A' + u8);
+ else
+ c = (char)('a' + u8 - 26);
+ } else {
+ if (u8 < 62)
+ c = (char)('0' + u8 - 52);
+ else if (u8 == 62)
+ c = url ? '-' : '+';
+ else
+ c = url ? '_' : '/';
+ }
+
+ /* put to output with format */
+ result[out++] = c;
+ if (iw && !--iw) {
+ result[out++] = '\n';
+ iw = width;
+ }
+ }
+
+ /* pad the output */
+ while (out < rlen) {
+ result[out++] = '=';
+ if (iw && !--iw) {
+ result[out++] = '\n';
+ iw = width;
+ }
+ }
+
+ /* terminate */
+ result[out] = 0;
+ *encoded = result;
+ *encodedlen = rlen;
+ return 0;
+}
+static int decode_base64(
+ const char *data,
+ size_t datalen,
+ uint8_t **decoded,
+ size_t *decodedlen,
+ int url)
+{
+ uint16_t u16;
+ uint8_t u8, *result;
+ size_t in, out, iin;
+ char c;
+
+ /* allocate enougth output */
+ result = malloc(datalen);
+ if (result == NULL)
+ return wrap_json_error_out_of_memory;
+
+ /* decode the input */
+ for (iin = in = out = 0 ; in < datalen ; in++) {
+ c = data[in];
+ if (c != '\n' && c != '\r' && c != '=') {
+ if ('A' <= c && c <= 'Z')
+ u8 = (uint8_t)(c - 'A');
+ else if ('a' <= c && c <= 'z')
+ u8 = (uint8_t)(c - 'a' + 26);
+ else if ('0' <= c && c <= '9')
+ u8 = (uint8_t)(c - '0' + 52);
+ else if (c == '+' || c == '-')
+ u8 = (uint8_t)62;
+ else if (c == '/' || c == '_')
+ u8 = (uint8_t)63;
+ else {
+ free(result);
+ return wrap_json_error_bad_base64;
+ }
+ if (!iin) {
+ u16 = (uint16_t)u8;
+ iin = 6;
+ } else {
+ u16 = (uint16_t)((u16 << 6) | u8);
+ iin -= 2;
+ u8 = (uint8_t)(u16 >> iin);
+ result[out++] = u8;
+ }
+ }
+ }
+
+ /* terminate */
+ *decoded = realloc(result, out);
+ if (out && *decoded == NULL) {
+ free(result);
+ return wrap_json_error_out_of_memory;
+ }
+ *decodedlen = out;
+ return 0;
+}
static inline const char *skip(const char *d)
{
char c;
const char *d;
char buffer[256];
+ struct { const uint8_t *in; size_t insz; char *out; size_t outsz; } bytes;
struct { const char *str; size_t sz; } strs[STRCOUNT];
struct { struct json_object *cont, *key; const char *acc; char type; } stack[STACKCOUNT], *top;
struct json_object *obj;
if (c == 'O')
json_object_get(obj);
break;
+ case 'y':
+ case 'Y':
+ bytes.in = va_arg(args, const uint8_t*);
+ bytes.insz = va_arg(args, size_t);
+ if (bytes.in == NULL || bytes.insz == 0)
+ obj = NULL;
+ else {
+ rc = encode_base64(bytes.in, bytes.insz,
+ &bytes.out, &bytes.outsz, 0, 0, c == 'y');
+ if (rc)
+ goto error;
+ obj = json_object_new_string_len(bytes.out, (int)bytes.outsz);
+ free(bytes.out);
+ if (!obj)
+ goto out_of_memory;
+ }
+ if (*d == '?')
+ d = skip(++d);
+ else if (*d != '*' && !obj) {
+ obj = json_object_new_string_len(d, 0);
+ if (!obj)
+ goto out_of_memory;
+ }
+ break;
case '[':
case '{':
if (++top >= &stack[STACKCOUNT])
int *pi = NULL;
int64_t *pI = NULL;
size_t *pz = NULL;
- struct { struct json_object *parent; const char *acc; int index, count; char type; } stack[STACKCOUNT], *top;
+ uint8_t **py = NULL;
+ struct { struct json_object *parent; const char *acc; int index; int count; char type; } stack[STACKCOUNT], *top;
struct json_object *obj;
struct json_object **po;
}
}
break;
+ case 'y':
+ case 'Y':
+ if (store) {
+ py = va_arg(args, uint8_t **);
+ pz = va_arg(args, size_t *);
+ }
+ if (!ignore) {
+ if (obj == NULL) {
+ if (store && py && pz) {
+ *py = NULL;
+ *pz = 0;
+ }
+ } else {
+ if (!json_object_is_type(obj, json_type_string))
+ goto missfit;
+ if (store && py && pz) {
+ rc = decode_base64(
+ json_object_get_string(obj),
+ (size_t)json_object_get_string_len(obj),
+ py, pz, c == 'y');
+ if (rc)
+ goto error;
+ }
+ }
+ }
+ break;
case '[':
case '{':
if (!ignore) {
if (!json_object_is_type(obj, json_type_array))
goto missfit;
- top->count = json_object_array_length(obj);
+ top->count = (int)json_object_array_length(obj);
}
xacc[0] = ']';
acc = unpack_accept_arr;
static void array_for_all(struct json_object *object, void (*callback)(void*,struct json_object*), void *closure)
{
- int n = json_object_array_length(object);
+ int n = (int)json_object_array_length(object);
int i = 0;
while(i < n)
callback(closure, json_object_array_get_idx(object, i++));
else if (!json_object_is_type(object, json_type_array))
callback(closure, object, NULL);
else {
- int n = json_object_array_length(object);
+ int n = (int)json_object_array_length(object);
int i = 0;
while(i < n)
callback(closure, json_object_array_get_idx(object, i++), NULL);
}
}
+static struct json_object *clone_any(struct json_object *object, int deep);
+
+static struct json_object *clone_object(struct json_object *object, int subdeep)
+{
+ struct json_object *r = json_object_new_object();
+ struct json_object_iterator it = json_object_iter_begin(object);
+ struct json_object_iterator end = json_object_iter_end(object);
+ while (!json_object_iter_equal(&it, &end)) {
+ json_object_object_add(r,
+ json_object_iter_peek_name(&it),
+ clone_any(json_object_iter_peek_value(&it), subdeep));
+ json_object_iter_next(&it);
+ }
+ return r;
+}
+
+static struct json_object *clone_array(struct json_object *object, int subdeep)
+{
+ int n = json_object_array_length(object);
+ struct json_object *r = json_object_new_array();
+ while (n) {
+ n--;
+ json_object_array_put_idx(r, n,
+ clone_any(json_object_array_get_idx(object, n), subdeep));
+ }
+ return r;
+}
+
+static struct json_object *clone_any(struct json_object *object, int deep)
+{
+ if (deep) {
+ switch (json_object_get_type(object)) {
+ case json_type_object:
+ return clone_object(object, deep - 1);
+ case json_type_array:
+ return clone_array(object, deep - 1);
+ default:
+ break;
+ }
+ }
+ return json_object_get(object);
+}
+
+struct json_object *wrap_json_clone(struct json_object *object)
+{
+ return clone_any(object, 1);
+}
+
+struct json_object *wrap_json_clone_deep(struct json_object *object)
+{
+ return clone_any(object, INT_MAX);
+}
+
+void wrap_json_object_add(struct json_object *dest, struct json_object *added)
+{
+ struct json_object_iterator it, end;
+ if (json_object_is_type(dest, json_type_object) && json_object_is_type(added, json_type_object)) {
+ it = json_object_iter_begin(added);
+ end = json_object_iter_end(added);
+ while (!json_object_iter_equal(&it, &end)) {
+ json_object_object_add(dest,
+ json_object_iter_peek_name(&it),
+ json_object_get(json_object_iter_peek_value(&it)));
+ json_object_iter_next(&it);
+ }
+ }
+}
+
#if defined(WRAP_JSON_TEST)
#include <stdio.h>
+void tclone(struct json_object *obj)
+{
+ struct json_object *o;
+
+ o = wrap_json_clone(obj);
+ if (strcmp(json_object_to_json_string(obj), json_object_to_json_string(o)))
+ printf("ERROR in clone: %s VERSUS %s\n", json_object_to_json_string(obj), json_object_to_json_string(o));
+ json_object_put(o);
+
+ o = wrap_json_clone_deep(obj);
+ if (strcmp(json_object_to_json_string(obj), json_object_to_json_string(o)))
+ printf("ERROR in clone_deep: %s VERSUS %s\n", json_object_to_json_string(obj), json_object_to_json_string(o));
+ json_object_put(o);
+}
+
void p(const char *desc, ...)
{
int rc;
printf(" SUCCESS %s\n\n", json_object_to_json_string(result));
else
printf(" ERROR[char %d err %d] %s\n\n", wrap_json_get_error_position(rc), wrap_json_get_error_code(rc), wrap_json_get_error_string(rc));
+ tclone(result);
json_object_put(result);
}
double *xf[10];
struct json_object *xo[10];
size_t xz[10];
+uint8_t *xy[10];
void u(const char *value, const char *desc, ...)
{
memset(xI, 0, sizeof xI);
memset(xf, 0, sizeof xf);
memset(xo, 0, sizeof xo);
+ memset(xy, 0, sizeof xy);
memset(xz, 0, sizeof xz);
obj = json_tokener_parse(value);
va_start(args, desc);
case 'F': printf(" F:%f", *va_arg(args, double*)); k = m&1; break;
case 'o': printf(" o:%s", json_object_to_json_string(*va_arg(args, struct json_object**))); k = m&1; break;
case 'O': o = *va_arg(args, struct json_object**); printf(" O:%s", json_object_to_json_string(o)); json_object_put(o); k = m&1; break;
+ case 'y':
+ case 'Y': {
+ uint8_t *p = *va_arg(args, uint8_t**);
+ size_t s = *va_arg(args, size_t*);
+ printf(" y/%d:%.*s", (int)s, (int)s, (char*)p);
+ k ^= m&1;
+ break;
+ }
default: break;
}
desc++;
va_end(args);
printf("\n\n");
}
+ tclone(obj);
json_object_put(obj);
}
P("{ {}: s }", "foo");
P("{ s: {}, s:[ii{} }", "foo", "bar", 12, 13);
P("[[[[[ [[[[[ [[[[ }]]]] ]]]] ]]]]]");
+ P("y", "???????hello>>>>>>>", (size_t)19);
+ P("Y", "???????hello>>>>>>>", (size_t)19);
+ P("{sy?}", "foo", "hi", (size_t)2);
+ P("{sy?}", "foo", NULL, 0);
+ P("{sy*}", "foo", "hi", (size_t)2);
+ P("{sy*}", "foo", NULL, 0);
U("true", "b", &xi[0]);
U("false", "b", &xi[0]);
U("{}", "{s?{s?i}}", "foo", "bar", &xi[0]);
U("{\"foo\":42,\"baz\":45}", "{s?isi!}", "baz", &xi[0], "foo", &xi[1]);
U("{\"foo\":42}", "{s?isi!}", "baz", &xi[0], "foo", &xi[1]);
+
+ U("\"Pz8_Pz8_P2hlbGxvPj4-Pj4-Pg\"", "y", &xy[0], &xz[0]);
+ U("\"\"", "y", &xy[0], &xz[0]);
+ U("null", "y", &xy[0], &xz[0]);
+ U("{\"foo\":\"Pz8_Pz8_P2hlbGxvPj4-Pj4-Pg\"}", "{s?y}", "foo", &xy[0], &xz[0]);
+ U("{\"foo\":\"\"}", "{s?y}", "foo", &xy[0], &xz[0]);
+ U("{}", "{s?y}", "foo", &xy[0], &xz[0]);
return 0;
}