aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosé Bollo <jose.bollo@iot.bzh>2018-06-14 13:23:02 +0000
committerGerrit Code Review <gerrit@automotivelinux.org>2018-06-14 13:23:02 +0000
commit03966c169d4f93f7ee3258c0f49f6cfd6f2b7b10 (patch)
tree5d76d83d52da0525f25a4519ccb58a05478df3ae
parentc92d55d47367d1d97aa0782f3456033f0f5f73db (diff)
parent436bbc24ea7fbe34d740f56574c52b5aaf7cbf58 (diff)
Merge changes from topic 'binding-v3'
* changes: wrap-json: Update for y/Y afm-udb: refactor add_fields_of_content afm-udb: split read_unit_file afm-udb: improve comment afm-binding: fix author
-rw-r--r--src/afm-binding.c2
-rw-r--r--src/afm-udb.c132
-rw-r--r--src/wrap-json.c248
-rw-r--r--src/wrap-json.md36
4 files changed, 351 insertions, 67 deletions
diff --git a/src/afm-binding.c b/src/afm-binding.c
index ae7c9db..4c52203 100644
--- a/src/afm-binding.c
+++ b/src/afm-binding.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2015-2018 "IoT.bzh"
- * Author "Fulup Ar Foll"
+ * Author José Bollo <jose.bollo@iot.bzh>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/src/afm-udb.c b/src/afm-udb.c
index be1a5d3..7f4a16e 100644
--- a/src/afm-udb.c
+++ b/src/afm-udb.c
@@ -182,17 +182,25 @@ static int add_fields_of_content(
{
char *name, *value, *read, *write;
- read = strstr(content, x_afm_prefix);
- while (read) {
+ /* start at the beginning */
+ read = content;
+ for (;;) {
+ /* search the next key */
+ read = strstr(read, x_afm_prefix);
+ if (!read)
+ return 0;
+
+ /* search to equal */
name = read + x_afm_prefix_length;
value = strchr(name, '=');
if (value == NULL)
- read = strstr(name, x_afm_prefix);
+ read = name; /* not found */
else {
+ /* get the value (translate it) */
*value++ = 0;
read = write = value;
while(*read && *read != '\n') {
- if (read[0] != '\\')
+ if (*read != '\\')
*write++ = *read++;
else {
switch(*++read) {
@@ -203,13 +211,14 @@ static int add_fields_of_content(
read += !!*read;
}
}
- read = strstr(read, x_afm_prefix);
+ read += !!*read;
*write = 0;
+
+ /* add the found field now */
if (add_field(priv, pub, name, value) < 0)
return -1;
}
}
- return 0;
}
/*
@@ -275,64 +284,76 @@ error:
}
/*
- * read a unit file
+ * Crop and trim unit 'content' of 'length'. Return the new length.
*/
-static int read_unit_file(const char *path, char **content, size_t *length)
+static size_t crop_and_trim_unit_content(char *content, size_t length)
{
- int rc, st;
+ int st;
char c, *read, *write;
- /* read the file */
- rc = getfile(path, content, length);
- if (rc >= 0) {
- /* removes any comment and join continued lines */
- st = 0;
- read = write = *content;
- for (;;) {
- do { c = *read++; } while (c == '\r');
- if (!c)
+ /* removes any comment and join continued lines */
+ st = 0;
+ read = write = content;
+ for (;;) {
+ do { c = *read++; } while (c == '\r');
+ if (!c)
+ break;
+ switch (st) {
+ case 0:
+ /* state 0: begin of a line */
+ if (c == ';' || c == '#') {
+ st = 3; /* removes lines starting with ; or # */
break;
- switch (st) {
- case 0:
- /* state 0: begin of a line */
- if (c == ';' || c == '#') {
- st = 3; /* removes lines starting with ; or # */
- break;
- }
- if (c == '\n')
- break; /* removes empty lines */
+ }
+ if (c == '\n')
+ break; /* removes empty lines */
enter_state_1:
- st = 1;
- /*@fallthrough@*/
- case 1:
- /* state 1: emitting a normal line */
- if (c == '\\')
- st = 2;
- else {
- *write++ = c;
- if (c == '\n')
- st = 0;
- }
- break;
- case 2:
- /* state 2: character after '\' */
- if (c == '\n')
- c = ' ';
- else
- *write++ = '\\';
- goto enter_state_1;
- case 3:
- /* state 3: inside a comment, wait its end */
+ st = 1;
+ /*@fallthrough@*/
+ case 1:
+ /* state 1: emitting a normal line */
+ if (c == '\\')
+ st = 2;
+ else {
+ *write++ = c;
if (c == '\n')
st = 0;
- break;
}
+ break;
+ case 2:
+ /* state 2: character after '\' */
+ if (c == '\n')
+ c = ' ';
+ else
+ *write++ = '\\';
+ goto enter_state_1;
+ case 3:
+ /* state 3: inside a comment, wait its end */
+ if (c == '\n')
+ st = 0;
+ break;
}
- if (st == 1)
- *write++ = '\n';
- *write = 0;
- *length = (size_t)(write - *content);
- *content = realloc(*content, *length + 1);
+ }
+ if (st == 1)
+ *write++ = '\n';
+ *write = 0;
+ return (size_t)(write - content);
+}
+
+/*
+ * read a unit file
+ */
+static int read_unit_file(const char *path, char **content, size_t *length)
+{
+ int rc;
+ size_t nl;
+
+ /* read the file */
+ rc = getfile(path, content, length);
+ if (rc >= 0) {
+ /* crop and trim it */
+ *length = nl = crop_and_trim_unit_content(*content, *length);
+ *content = realloc(*content, nl + 1);
}
return rc;
}
@@ -474,6 +495,9 @@ error:
return -1;
}
+/*
+ * set the default language to 'lang'
+ */
void afm_udb_set_default_lang(const char *lang)
{
char *oldval = default_lang;
diff --git a/src/wrap-json.c b/src/wrap-json.c
index b25503a..7fc8a9c 100644
--- a/src/wrap-json.c
+++ b/src/wrap-json.c
@@ -39,15 +39,16 @@ enum {
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])
@@ -67,7 +68,8 @@ static const char *pack_errors[_wrap_json_error_count_] =
[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)
@@ -87,12 +89,165 @@ int wrap_json_get_error_code(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)
{
@@ -110,6 +265,7 @@ int wrap_json_vpack(struct json_object **result, const char *desc, va_list args)
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;
@@ -218,6 +374,30 @@ int wrap_json_vpack(struct json_object **result, const char *desc, va_list args)
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])
@@ -347,7 +527,8 @@ static int vunpack(struct json_object *object, const char *desc, va_list args, i
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; size_t index; size_t count; char type; } stack[STACKCOUNT], *top;
struct json_object *obj;
struct json_object **po;
@@ -477,6 +658,32 @@ static int vunpack(struct json_object *object, const char *desc, va_list args, i
}
}
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 '{':
@@ -656,8 +863,8 @@ static void object_for_all(struct json_object *object, void (*callback)(void*,st
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 i = 0;
+ size_t n = json_object_array_length(object);
+ size_t i = 0;
while(i < n)
callback(closure, json_object_array_get_idx(object, i++));
}
@@ -699,8 +906,8 @@ void wrap_json_for_all(struct json_object *object, void (*callback)(void*,struct
else if (!json_object_is_type(object, json_type_array))
callback(closure, object, NULL);
else {
- int n = json_object_array_length(object);
- int i = 0;
+ size_t n = json_object_array_length(object);
+ size_t i = 0;
while(i < n)
callback(closure, json_object_array_get_idx(object, i++), NULL);
}
@@ -731,6 +938,7 @@ int64_t *xI[10];
double *xf[10];
struct json_object *xo[10];
size_t xz[10];
+uint8_t *xy[10];
void u(const char *value, const char *desc, ...)
{
@@ -744,6 +952,7 @@ 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);
@@ -772,6 +981,14 @@ void u(const char *value, const char *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++;
@@ -839,6 +1056,12 @@ int main()
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]);
@@ -915,6 +1138,13 @@ int main()
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;
}
diff --git a/src/wrap-json.md b/src/wrap-json.md
index 92940f1..8f7693c 100644
--- a/src/wrap-json.md
+++ b/src/wrap-json.md
@@ -2,7 +2,7 @@ WRAP-JSON facility
==================
The facility wrap-json is based on the pack/unpack API on the
-libray jansson. The two chapters below are copied from the
+library jansson. The two chapters below are copied from the
documentation of jansson library copyrighted by Petri Lehtinen
(see at end).
@@ -66,6 +66,28 @@ arguments.
: Like `+#` but the length argument is of type size\_t.
+`y` (byte array) \[const uint8_t \*, size\_t\]
+
+: Convert the byte array whose length is given to
+ its base64url string representation.
+
+`Y` (byte array) \[const uint8_t \*, size\_t\]
+
+: Like 'y' but output is base64.
+
+`y?`, `Y?` (byte array or null) \[const uint8_t \*, size\_t\]
+
+: Like 'y' or 'Y' but allows to output a JSON null value
+ either when the buffer is *NULL* or when the size is *0*.
+
+`y*`, `y*` (optional byte array) \[const uint8_t \*, size\_t\]
+
+: Like 'y' or 'Y' but do not put JSON value
+ either when the buffer is *NULL* or when the size is *0*.
+ This format can only be used inside an object or an array. If used
+ inside an object, the corresponding key is additionally suppressed
+ when the value is omitted. See below for an example.
+
`n` (null)
: Output a JSON null value. No argument is consumed.
@@ -183,6 +205,16 @@ type whose address should be passed.
: Convert a JSON string to a pointer to a null terminated UTF-8 string
and its length.
+`y` (byte array) \[uint8_t \*\*, size\_t \*\]
+
+: Convert an input string base64url encoded to its
+ byte array representation. The result and its length
+ are stored. The returned buffer must be freed by the caller.
+
+`Y` (byte array) \[uint8_t \*\*, size\_t \*\]
+
+: Like 'y' but input is base64.
+
`n` (null)
: Expect a JSON null value. Nothing is extracted.
@@ -279,7 +311,6 @@ Examples:
"bar", &myint2, &myint3);
/* myint1, myint2 or myint3 is no touched as "foo" and "bar" don't exist */
-
Copyright
---------
@@ -302,4 +333,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-