Mercurial > libjeffpc
changeset 465:c4ac06c3ee4a
val: move nvl packing code to live closer to val code
This is in preparation for packing getting refactored to be a part of val
code.
Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author | Josef 'Jeff' Sipek <jeffpc@josefsipek.net> |
---|---|
date | Sun, 01 Apr 2018 13:17:25 -0400 |
parents | b1e4c7607050 |
children | 8635533bc2b6 |
files | CMakeLists.txt nvl_fmt_cbor.c nvl_fmt_json.c nvl_impl.h nvl_pack.c nvl_unpack.c val_fmt_cbor.c val_fmt_json.c val_impl_packing.h val_pack.c val_unpack.c |
diffstat | 11 files changed, 686 insertions(+), 686 deletions(-) [+] |
line wrap: on
line diff
--- a/CMakeLists.txt Sat Mar 31 17:34:16 2018 -0400 +++ b/CMakeLists.txt Sun Apr 01 13:17:25 2018 -0400 @@ -99,10 +99,6 @@ mem_array.c nvl.c nvl_convert.c - nvl_fmt_cbor.c - nvl_fmt_json.c - nvl_pack.c - nvl_unpack.c padding.c qstring.c rand.c @@ -121,7 +117,11 @@ uuid.c val.c val_array.c + val_fmt_cbor.c + val_fmt_json.c val_nvl.c + val_pack.c + val_unpack.c version.c ${UMEM_EXTRA_SOURCE} )
--- a/nvl_fmt_cbor.c Sat Mar 31 17:34:16 2018 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2017-2018 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * 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. - */ - -#include <jeffpc/nvl.h> -#include <jeffpc/cbor.h> - -#include "nvl_impl.h" - -/* - * nvl packing interface - */ - -static int cbor_nvl_prologue(struct buffer *buffer, struct nvlist *nvl) -{ - return cbor_pack_map_start(buffer, CBOR_UNKNOWN_NELEM); -} - -static int cbor_nvl_epilogue(struct buffer *buffer, struct nvlist *nvl) -{ - return cbor_pack_map_end(buffer, CBOR_UNKNOWN_NELEM); -} - -static int cbor_array_prologue(struct buffer *buffer, struct val *const *vals, - size_t nelem) -{ - return cbor_pack_array_start(buffer, nelem); -} - -static int cbor_array_epilogue(struct buffer *buffer, struct val *const *vals, - size_t nelem) -{ - return cbor_pack_array_end(buffer, nelem); -} - -const struct nvops nvops_cbor = { - .pack = { - .nvl_prologue = cbor_nvl_prologue, - .nvl_epilogue = cbor_nvl_epilogue, - - .array_prologue = cbor_array_prologue, - .array_epilogue = cbor_array_epilogue, - - .val_blob = cbor_pack_blob, - .val_bool = cbor_pack_bool, - .val_int = cbor_pack_uint, - .val_null = cbor_pack_null, - .val_str = cbor_pack_cstr, - } -};
--- a/nvl_fmt_json.c Sat Mar 31 17:34:16 2018 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,174 +0,0 @@ -/* - * Copyright (c) 2017-2018 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * 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. - */ - -#include <jeffpc/nvl.h> - -#include "nvl_impl.h" - -static int json_nvl_prologue(struct buffer *buffer, struct nvlist *nvl) -{ - return buffer_append_c(buffer, '{'); -} - -static int json_nvl_name_sep(struct buffer *buffer, const struct nvpair *pair) -{ - return buffer_append_c(buffer, ':'); -} - -static int json_nvl_val_sep(struct buffer *buffer, const struct nvpair *pair) -{ - return buffer_append_c(buffer, ','); -} - -static int json_nvl_epilogue(struct buffer *buffer, struct nvlist *nvl) -{ - return buffer_append_c(buffer, '}'); -} - -static int json_array_prologue(struct buffer *buffer, struct val *const *vals, - size_t nelem) -{ - return buffer_append_c(buffer, '['); -} - -static int json_array_val_sep(struct buffer *buffer, const struct val *val) -{ - return buffer_append_c(buffer, ','); -} - -static int json_array_epilogue(struct buffer *buffer, struct val *const *vals, - size_t nelem) -{ - return buffer_append_c(buffer, ']'); -} - -static int json_val_bool(struct buffer *buffer, bool b) -{ - return buffer_append_cstr(buffer, b ? "true" : "false"); -} - -static int json_val_int(struct buffer *buffer, uint64_t i) -{ - char tmp[sizeof(i) * 2 * 2 + 1]; /* FIXME: hexdump would take 2x */ - - snprintf(tmp, sizeof(tmp), "%"PRIu64, i); - - return buffer_append_cstr(buffer, tmp); -} - -static int json_val_null(struct buffer *buffer) -{ - return buffer_append_cstr(buffer, "null"); -} - -static int __escape_char(struct buffer *buffer, uint64_t c) -{ - char tmp[7]; - - /* FIXME: char outside of basic multilingual plane */ - if (c > 0xffff) - return -ENOTSUP; - - snprintf(tmp, sizeof(tmp), "\\u%04"PRIX64, c); - - return buffer_append_cstr(buffer, tmp); -} - -static int __escape_ctrl_char(struct buffer *buffer, uint8_t c) -{ - const char *mapped = NULL; - - switch (c) { - case '\b': - mapped = "\\b"; - break; - case '\f': - mapped = "\\f"; - break; - case '\n': - mapped = "\\n"; - break; - case '\r': - mapped = "\\r"; - break; - case '\t': - mapped = "\\t"; - break; - } - - if (mapped) - return buffer_append_cstr(buffer, mapped); - - return __escape_char(buffer, c); -} - -static int json_val_str(struct buffer *buffer, const char *str) -{ - int ret; - - if ((ret = buffer_append_c(buffer, '"'))) - return ret; - - /* append the string... escaped */ - for (; *str; str++) { - uint8_t c = *str; - - if (c <= 0x1f) { - /* control character, must be escaped */ - ret = __escape_ctrl_char(buffer, c); - } else if ((c == '"') || (c == '\\')) { - /* quote or backslash */ - char tmp[3] = { '\\', c, '\0' }; - - ret = buffer_append_cstr(buffer, tmp); - } else { - /* no escape necessary */ - ret = buffer_append_c(buffer, c); - } - - if (ret) - return ret; - } - - if ((ret = buffer_append_c(buffer, '"'))) - return ret; - - return 0; -} - -const struct nvops nvops_json = { - .pack = { - .nvl_prologue = json_nvl_prologue, /* { */ - .nvl_name_sep = json_nvl_name_sep, /* : */ - .nvl_val_sep = json_nvl_val_sep, /* , */ - .nvl_epilogue = json_nvl_epilogue, /* } */ - - .array_prologue = json_array_prologue, /* [ */ - .array_val_sep = json_array_val_sep, /* , */ - .array_epilogue = json_array_epilogue, /* ] */ - - .val_bool = json_val_bool, - .val_int = json_val_int, - .val_null = json_val_null, - .val_str = json_val_str, - } -};
--- a/nvl_impl.h Sat Mar 31 17:34:16 2018 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2017-2018 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * 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. - */ - -#ifndef __JEFFPC_NVL_IMPL_H -#define __JEFFPC_NVL_IMPL_H - -#include <jeffpc/nvl.h> -#include <jeffpc/buffer.h> - -#define CALL(ops, op, args) \ - ({ \ - int _ret = 0; \ - \ - if (ops->op) \ - _ret = ops->op args; \ - \ - _ret; \ - }) - -#define CALL_OR_FAIL(ops, op, args) \ - ({ \ - int _ret = -ENOTSUP; \ - \ - if (ops->op) \ - _ret = ops->op args; \ - \ - _ret; \ - }) - -/* - * Packing operations - * - * A required function pointer is only required when an item of that type - * must be encoded. For example, if an encoder doesn't implement packing of - * strings, packing of all nvlists *with* strings will fail because of this - * limitation. Packing of nvlists *without* strings may or may not fail for - * other reasons. - */ -struct nvpackops { - /* - * top-level encoder hooks - * - * Optional: All. - */ - int (*buffer_finish)(struct buffer *buffer); - - /* - * nvlist encoders - * - * Required: At least one of prologue or epilogue. - * Optional: The rest. - */ - int (*nvl_prologue)(struct buffer *buffer, struct nvlist *nvl); - int (*nvl_name_sep)(struct buffer *buffer, const struct nvpair *pair); - int (*nvl_val_sep)(struct buffer *buffer, const struct nvpair *pair); - int (*nvl_epilogue)(struct buffer *buffer, struct nvlist *nvl); - - /* - * array encoders - * - * Required: At least one of prologue or epilogue. - * Optional: The rest. - */ - int (*array_prologue)(struct buffer *buffer, struct val *const *vals, - size_t nelem); - int (*array_val_sep)(struct buffer *buffer, const struct val *val); - int (*array_epilogue)(struct buffer *buffer, struct val *const *vals, - size_t nelem); - - /* - * nvpair - * - * Optional: All. - */ - int (*pair_prologue)(struct buffer *buffer, const struct nvpair *pair); - int (*pair_epilogue)(struct buffer *buffer, const struct nvpair *pair); - - /* - * value encoders - * - * Required: All. - */ - int (*val_blob)(struct buffer *buffer, const void *data, size_t size); - int (*val_bool)(struct buffer *buffer, bool b); - int (*val_int)(struct buffer *buffer, uint64_t i); - int (*val_null)(struct buffer *buffer); - int (*val_str)(struct buffer *buffer, const char *str); -}; - -struct nvunpackops { - /* TODO */ -}; - -struct nvops { - const struct nvpackops pack; - const struct nvunpackops unpack; -}; - -extern const struct nvops nvops_cbor; -extern const struct nvops nvops_json; - -static inline const struct nvops *select_ops(enum nvformat format) -{ - switch (format) { - case NVF_CBOR: - return &nvops_cbor; - case NVF_JSON: - return &nvops_json; - } - - return NULL; -} - -#endif
--- a/nvl_pack.c Sat Mar 31 17:34:16 2018 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,248 +0,0 @@ -/* - * Copyright (c) 2017-2018 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * 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. - */ - -#include <jeffpc/nvl.h> -#include <jeffpc/buffer.h> - -#include "nvl_impl.h" - -static int pack_nvl(const struct nvpackops *ops, struct buffer *buffer, - struct nvlist *nvl); -static int pack_val(const struct nvpackops *ops, struct buffer *buffer, - struct val *val); - -static int pack_array(const struct nvpackops *ops, struct buffer *buffer, - struct val **vals, size_t nelem) -{ - bool first = true; - size_t i; - int ret; - - if (!ops->array_prologue && !ops->array_epilogue) - return -ENOTSUP; - - if ((ret = CALL(ops, array_prologue, (buffer, vals, nelem)))) - return ret; - - for (i = 0; i < nelem; i++) { - struct val *val = vals[i]; - - if (first) { - first = false; - if ((ret = CALL(ops, array_val_sep, (buffer, val)))) - return ret; - } - - if ((ret = pack_val(ops, buffer, val))) - return ret; - } - - if ((ret = CALL(ops, array_epilogue, (buffer, vals, nelem)))) - return ret; - - return 0; -} - -static int pack_blob(const struct nvpackops *ops, struct buffer *buffer, - const void *data, size_t size) -{ - return CALL_OR_FAIL(ops, val_blob, (buffer, data, size)); -} - -static int pack_bool(const struct nvpackops *ops, struct buffer *buffer, - bool b) -{ - return CALL_OR_FAIL(ops, val_bool, (buffer, b)); -} - -static int pack_int(const struct nvpackops *ops, struct buffer *buffer, - uint64_t i) -{ - return CALL_OR_FAIL(ops, val_int, (buffer, i)); -} - -static int pack_null(const struct nvpackops *ops, struct buffer *buffer) -{ - return CALL_OR_FAIL(ops, val_null, (buffer)); -} - -static int pack_string(const struct nvpackops *ops, struct buffer *buffer, - struct str *str) -{ - const char *s; - - /* - * Even though we try to avoid NULL pointers to indicate empty - * strings, they can crop up from many places. So, it is safer to - * do the check here. - */ - s = str ? str_cstr(str) : ""; - - return CALL_OR_FAIL(ops, val_str, (buffer, s)); -} - -static int pack_val(const struct nvpackops *ops, struct buffer *buffer, - struct val *val) -{ - int ret = -ENOTSUP; - - switch (val->type) { - case VT_ARRAY: - ret = pack_array(ops, buffer, val->array.vals, - val->array.nelem); - break; - case VT_BLOB: - ret = pack_blob(ops, buffer, val->blob.ptr, - val->blob.size); - break; - case VT_BOOL: - ret = pack_bool(ops, buffer, val->b); - break; - case VT_INT: - ret = pack_int(ops, buffer, val->i); - break; - case VT_NULL: - ret = pack_null(ops, buffer); - break; - case VT_NVL: - ret = pack_nvl(ops, buffer, val_cast_to_nvl(val)); - break; - case VT_STR: - ret = pack_string(ops, buffer, val_cast_to_str(val)); - break; - case VT_SYM: - case VT_CONS: - case VT_CHAR: - /* not supported */ - break; - } - - return ret; -} - -static int pack_pair(const struct nvpackops *ops, struct buffer *buffer, - const struct nvpair *pair) -{ - int ret; - - if ((ret = CALL(ops, pair_prologue, (buffer, pair)))) - return ret; - - if ((ret = pack_string(ops, buffer, pair->name))) - return ret; - - if ((ret = CALL(ops, nvl_name_sep, (buffer, pair)))) - return ret; - - if ((ret = pack_val(ops, buffer, pair->value))) - return ret; - - if ((ret = CALL(ops, pair_epilogue, (buffer, pair)))) - return ret; - - return 0; -} - -static int pack_nvl(const struct nvpackops *ops, struct buffer *buffer, - struct nvlist *nvl) -{ - const struct nvpair *pair; - bool first = true; - int ret; - - if (!ops->nvl_prologue && !ops->nvl_epilogue) - return -ENOTSUP; - - if ((ret = CALL(ops, nvl_prologue, (buffer, nvl)))) - return ret; - - nvl_for_each(pair, nvl) { - if (first) { - first = false; - } else { - if ((ret = CALL(ops, nvl_val_sep, (buffer, pair)))) - return ret; - } - - if ((ret = pack_pair(ops, buffer, pair))) - return ret; - } - - if ((ret = CALL(ops, nvl_epilogue, (buffer, nvl)))) - return ret; - - return 0; -} - -static int __nvl_pack(const struct nvpackops *ops, struct buffer *buffer, - struct nvlist *nvl, bool call_finish) -{ - int ret; - - ret = pack_nvl(ops, buffer, nvl); - if (ret) - return ret; - - if (!call_finish) - return 0; - - return CALL(ops, buffer_finish, (buffer)); -} - -struct buffer *nvl_pack(struct nvlist *nvl, enum nvformat format) -{ - const struct nvops *ops; - struct buffer *buffer; - int ret; - - ops = select_ops(format); - if (!ops) - return ERR_PTR(-ENOTSUP); - - buffer = buffer_alloc(1024); - if (IS_ERR(buffer)) - return buffer; - - ret = __nvl_pack(&ops->pack, buffer, nvl, true); - if (!ret) - return buffer; - - buffer_free(buffer); - return ERR_PTR(ret); -} - -ssize_t nvl_size(struct nvlist *nvl, enum nvformat format) -{ - const struct nvops *ops; - struct buffer buffer; - int ret; - - ops = select_ops(format); - if (!ops) - return -ENOTSUP; - - buffer_init_sink(&buffer); - - ret = __nvl_pack(&ops->pack, &buffer, nvl, false); - - return ret ? ret : buffer_used(&buffer); -}
--- a/nvl_unpack.c Sat Mar 31 17:34:16 2018 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2017 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * 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. - */ - -#include <jeffpc/nvl.h> -#include <jeffpc/buffer.h> - -#include "nvl_impl.h" - -static int unpack_nvl(const struct nvunpackops *ops, const struct buffer *buffer, - struct nvlist *nvl) -{ - return -ENOTSUP; /* FIXME */ -} - -struct nvlist *nvl_unpack(const void *ptr, size_t len, enum nvformat format) -{ - const struct buffer buffer = { - .data = (void *) ptr, - .used = len, - .allocsize = len, - }; - const struct nvops *ops; - struct nvlist *nvl; - int ret; - - ops = select_ops(format); - if (!ops) - return ERR_PTR(-ENOTSUP); - - nvl = nvl_alloc(); - if (!nvl) - return ERR_PTR(-ENOMEM); - - ret = unpack_nvl(&ops->unpack, &buffer, nvl); - if (!ret) - return nvl; - - nvl_putref(nvl); - return ERR_PTR(ret); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/val_fmt_cbor.c Sun Apr 01 13:17:25 2018 -0400 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2017-2018 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * 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. + */ + +#include <jeffpc/nvl.h> +#include <jeffpc/cbor.h> + +#include "val_impl_packing.h" + +/* + * nvl packing interface + */ + +static int cbor_nvl_prologue(struct buffer *buffer, struct nvlist *nvl) +{ + return cbor_pack_map_start(buffer, CBOR_UNKNOWN_NELEM); +} + +static int cbor_nvl_epilogue(struct buffer *buffer, struct nvlist *nvl) +{ + return cbor_pack_map_end(buffer, CBOR_UNKNOWN_NELEM); +} + +static int cbor_array_prologue(struct buffer *buffer, struct val *const *vals, + size_t nelem) +{ + return cbor_pack_array_start(buffer, nelem); +} + +static int cbor_array_epilogue(struct buffer *buffer, struct val *const *vals, + size_t nelem) +{ + return cbor_pack_array_end(buffer, nelem); +} + +const struct nvops nvops_cbor = { + .pack = { + .nvl_prologue = cbor_nvl_prologue, + .nvl_epilogue = cbor_nvl_epilogue, + + .array_prologue = cbor_array_prologue, + .array_epilogue = cbor_array_epilogue, + + .val_blob = cbor_pack_blob, + .val_bool = cbor_pack_bool, + .val_int = cbor_pack_uint, + .val_null = cbor_pack_null, + .val_str = cbor_pack_cstr, + } +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/val_fmt_json.c Sun Apr 01 13:17:25 2018 -0400 @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2017-2018 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * 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. + */ + +#include <jeffpc/nvl.h> + +#include "val_impl_packing.h" + +static int json_nvl_prologue(struct buffer *buffer, struct nvlist *nvl) +{ + return buffer_append_c(buffer, '{'); +} + +static int json_nvl_name_sep(struct buffer *buffer, const struct nvpair *pair) +{ + return buffer_append_c(buffer, ':'); +} + +static int json_nvl_val_sep(struct buffer *buffer, const struct nvpair *pair) +{ + return buffer_append_c(buffer, ','); +} + +static int json_nvl_epilogue(struct buffer *buffer, struct nvlist *nvl) +{ + return buffer_append_c(buffer, '}'); +} + +static int json_array_prologue(struct buffer *buffer, struct val *const *vals, + size_t nelem) +{ + return buffer_append_c(buffer, '['); +} + +static int json_array_val_sep(struct buffer *buffer, const struct val *val) +{ + return buffer_append_c(buffer, ','); +} + +static int json_array_epilogue(struct buffer *buffer, struct val *const *vals, + size_t nelem) +{ + return buffer_append_c(buffer, ']'); +} + +static int json_val_bool(struct buffer *buffer, bool b) +{ + return buffer_append_cstr(buffer, b ? "true" : "false"); +} + +static int json_val_int(struct buffer *buffer, uint64_t i) +{ + char tmp[sizeof(i) * 2 * 2 + 1]; /* FIXME: hexdump would take 2x */ + + snprintf(tmp, sizeof(tmp), "%"PRIu64, i); + + return buffer_append_cstr(buffer, tmp); +} + +static int json_val_null(struct buffer *buffer) +{ + return buffer_append_cstr(buffer, "null"); +} + +static int __escape_char(struct buffer *buffer, uint64_t c) +{ + char tmp[7]; + + /* FIXME: char outside of basic multilingual plane */ + if (c > 0xffff) + return -ENOTSUP; + + snprintf(tmp, sizeof(tmp), "\\u%04"PRIX64, c); + + return buffer_append_cstr(buffer, tmp); +} + +static int __escape_ctrl_char(struct buffer *buffer, uint8_t c) +{ + const char *mapped = NULL; + + switch (c) { + case '\b': + mapped = "\\b"; + break; + case '\f': + mapped = "\\f"; + break; + case '\n': + mapped = "\\n"; + break; + case '\r': + mapped = "\\r"; + break; + case '\t': + mapped = "\\t"; + break; + } + + if (mapped) + return buffer_append_cstr(buffer, mapped); + + return __escape_char(buffer, c); +} + +static int json_val_str(struct buffer *buffer, const char *str) +{ + int ret; + + if ((ret = buffer_append_c(buffer, '"'))) + return ret; + + /* append the string... escaped */ + for (; *str; str++) { + uint8_t c = *str; + + if (c <= 0x1f) { + /* control character, must be escaped */ + ret = __escape_ctrl_char(buffer, c); + } else if ((c == '"') || (c == '\\')) { + /* quote or backslash */ + char tmp[3] = { '\\', c, '\0' }; + + ret = buffer_append_cstr(buffer, tmp); + } else { + /* no escape necessary */ + ret = buffer_append_c(buffer, c); + } + + if (ret) + return ret; + } + + if ((ret = buffer_append_c(buffer, '"'))) + return ret; + + return 0; +} + +const struct nvops nvops_json = { + .pack = { + .nvl_prologue = json_nvl_prologue, /* { */ + .nvl_name_sep = json_nvl_name_sep, /* : */ + .nvl_val_sep = json_nvl_val_sep, /* , */ + .nvl_epilogue = json_nvl_epilogue, /* } */ + + .array_prologue = json_array_prologue, /* [ */ + .array_val_sep = json_array_val_sep, /* , */ + .array_epilogue = json_array_epilogue, /* ] */ + + .val_bool = json_val_bool, + .val_int = json_val_int, + .val_null = json_val_null, + .val_str = json_val_str, + } +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/val_impl_packing.h Sun Apr 01 13:17:25 2018 -0400 @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2017-2018 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * 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. + */ + +#ifndef __JEFFPC_NVL_IMPL_H +#define __JEFFPC_NVL_IMPL_H + +#include <jeffpc/nvl.h> +#include <jeffpc/buffer.h> + +#define CALL(ops, op, args) \ + ({ \ + int _ret = 0; \ + \ + if (ops->op) \ + _ret = ops->op args; \ + \ + _ret; \ + }) + +#define CALL_OR_FAIL(ops, op, args) \ + ({ \ + int _ret = -ENOTSUP; \ + \ + if (ops->op) \ + _ret = ops->op args; \ + \ + _ret; \ + }) + +/* + * Packing operations + * + * A required function pointer is only required when an item of that type + * must be encoded. For example, if an encoder doesn't implement packing of + * strings, packing of all nvlists *with* strings will fail because of this + * limitation. Packing of nvlists *without* strings may or may not fail for + * other reasons. + */ +struct nvpackops { + /* + * top-level encoder hooks + * + * Optional: All. + */ + int (*buffer_finish)(struct buffer *buffer); + + /* + * nvlist encoders + * + * Required: At least one of prologue or epilogue. + * Optional: The rest. + */ + int (*nvl_prologue)(struct buffer *buffer, struct nvlist *nvl); + int (*nvl_name_sep)(struct buffer *buffer, const struct nvpair *pair); + int (*nvl_val_sep)(struct buffer *buffer, const struct nvpair *pair); + int (*nvl_epilogue)(struct buffer *buffer, struct nvlist *nvl); + + /* + * array encoders + * + * Required: At least one of prologue or epilogue. + * Optional: The rest. + */ + int (*array_prologue)(struct buffer *buffer, struct val *const *vals, + size_t nelem); + int (*array_val_sep)(struct buffer *buffer, const struct val *val); + int (*array_epilogue)(struct buffer *buffer, struct val *const *vals, + size_t nelem); + + /* + * nvpair + * + * Optional: All. + */ + int (*pair_prologue)(struct buffer *buffer, const struct nvpair *pair); + int (*pair_epilogue)(struct buffer *buffer, const struct nvpair *pair); + + /* + * value encoders + * + * Required: All. + */ + int (*val_blob)(struct buffer *buffer, const void *data, size_t size); + int (*val_bool)(struct buffer *buffer, bool b); + int (*val_int)(struct buffer *buffer, uint64_t i); + int (*val_null)(struct buffer *buffer); + int (*val_str)(struct buffer *buffer, const char *str); +}; + +struct nvunpackops { + /* TODO */ +}; + +struct nvops { + const struct nvpackops pack; + const struct nvunpackops unpack; +}; + +extern const struct nvops nvops_cbor; +extern const struct nvops nvops_json; + +static inline const struct nvops *select_ops(enum nvformat format) +{ + switch (format) { + case NVF_CBOR: + return &nvops_cbor; + case NVF_JSON: + return &nvops_json; + } + + return NULL; +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/val_pack.c Sun Apr 01 13:17:25 2018 -0400 @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2017-2018 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * 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. + */ + +#include <jeffpc/nvl.h> +#include <jeffpc/buffer.h> + +#include "val_impl_packing.h" + +static int pack_nvl(const struct nvpackops *ops, struct buffer *buffer, + struct nvlist *nvl); +static int pack_val(const struct nvpackops *ops, struct buffer *buffer, + struct val *val); + +static int pack_array(const struct nvpackops *ops, struct buffer *buffer, + struct val **vals, size_t nelem) +{ + bool first = true; + size_t i; + int ret; + + if (!ops->array_prologue && !ops->array_epilogue) + return -ENOTSUP; + + if ((ret = CALL(ops, array_prologue, (buffer, vals, nelem)))) + return ret; + + for (i = 0; i < nelem; i++) { + struct val *val = vals[i]; + + if (first) { + first = false; + if ((ret = CALL(ops, array_val_sep, (buffer, val)))) + return ret; + } + + if ((ret = pack_val(ops, buffer, val))) + return ret; + } + + if ((ret = CALL(ops, array_epilogue, (buffer, vals, nelem)))) + return ret; + + return 0; +} + +static int pack_blob(const struct nvpackops *ops, struct buffer *buffer, + const void *data, size_t size) +{ + return CALL_OR_FAIL(ops, val_blob, (buffer, data, size)); +} + +static int pack_bool(const struct nvpackops *ops, struct buffer *buffer, + bool b) +{ + return CALL_OR_FAIL(ops, val_bool, (buffer, b)); +} + +static int pack_int(const struct nvpackops *ops, struct buffer *buffer, + uint64_t i) +{ + return CALL_OR_FAIL(ops, val_int, (buffer, i)); +} + +static int pack_null(const struct nvpackops *ops, struct buffer *buffer) +{ + return CALL_OR_FAIL(ops, val_null, (buffer)); +} + +static int pack_string(const struct nvpackops *ops, struct buffer *buffer, + struct str *str) +{ + const char *s; + + /* + * Even though we try to avoid NULL pointers to indicate empty + * strings, they can crop up from many places. So, it is safer to + * do the check here. + */ + s = str ? str_cstr(str) : ""; + + return CALL_OR_FAIL(ops, val_str, (buffer, s)); +} + +static int pack_val(const struct nvpackops *ops, struct buffer *buffer, + struct val *val) +{ + int ret = -ENOTSUP; + + switch (val->type) { + case VT_ARRAY: + ret = pack_array(ops, buffer, val->array.vals, + val->array.nelem); + break; + case VT_BLOB: + ret = pack_blob(ops, buffer, val->blob.ptr, + val->blob.size); + break; + case VT_BOOL: + ret = pack_bool(ops, buffer, val->b); + break; + case VT_INT: + ret = pack_int(ops, buffer, val->i); + break; + case VT_NULL: + ret = pack_null(ops, buffer); + break; + case VT_NVL: + ret = pack_nvl(ops, buffer, val_cast_to_nvl(val)); + break; + case VT_STR: + ret = pack_string(ops, buffer, val_cast_to_str(val)); + break; + case VT_SYM: + case VT_CONS: + case VT_CHAR: + /* not supported */ + break; + } + + return ret; +} + +static int pack_pair(const struct nvpackops *ops, struct buffer *buffer, + const struct nvpair *pair) +{ + int ret; + + if ((ret = CALL(ops, pair_prologue, (buffer, pair)))) + return ret; + + if ((ret = pack_string(ops, buffer, pair->name))) + return ret; + + if ((ret = CALL(ops, nvl_name_sep, (buffer, pair)))) + return ret; + + if ((ret = pack_val(ops, buffer, pair->value))) + return ret; + + if ((ret = CALL(ops, pair_epilogue, (buffer, pair)))) + return ret; + + return 0; +} + +static int pack_nvl(const struct nvpackops *ops, struct buffer *buffer, + struct nvlist *nvl) +{ + const struct nvpair *pair; + bool first = true; + int ret; + + if (!ops->nvl_prologue && !ops->nvl_epilogue) + return -ENOTSUP; + + if ((ret = CALL(ops, nvl_prologue, (buffer, nvl)))) + return ret; + + nvl_for_each(pair, nvl) { + if (first) { + first = false; + } else { + if ((ret = CALL(ops, nvl_val_sep, (buffer, pair)))) + return ret; + } + + if ((ret = pack_pair(ops, buffer, pair))) + return ret; + } + + if ((ret = CALL(ops, nvl_epilogue, (buffer, nvl)))) + return ret; + + return 0; +} + +static int __nvl_pack(const struct nvpackops *ops, struct buffer *buffer, + struct nvlist *nvl, bool call_finish) +{ + int ret; + + ret = pack_nvl(ops, buffer, nvl); + if (ret) + return ret; + + if (!call_finish) + return 0; + + return CALL(ops, buffer_finish, (buffer)); +} + +struct buffer *nvl_pack(struct nvlist *nvl, enum nvformat format) +{ + const struct nvops *ops; + struct buffer *buffer; + int ret; + + ops = select_ops(format); + if (!ops) + return ERR_PTR(-ENOTSUP); + + buffer = buffer_alloc(1024); + if (IS_ERR(buffer)) + return buffer; + + ret = __nvl_pack(&ops->pack, buffer, nvl, true); + if (!ret) + return buffer; + + buffer_free(buffer); + return ERR_PTR(ret); +} + +ssize_t nvl_size(struct nvlist *nvl, enum nvformat format) +{ + const struct nvops *ops; + struct buffer buffer; + int ret; + + ops = select_ops(format); + if (!ops) + return -ENOTSUP; + + buffer_init_sink(&buffer); + + ret = __nvl_pack(&ops->pack, &buffer, nvl, false); + + return ret ? ret : buffer_used(&buffer); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/val_unpack.c Sun Apr 01 13:17:25 2018 -0400 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2017-2018 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * 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. + */ + +#include <jeffpc/nvl.h> +#include <jeffpc/buffer.h> + +#include "val_impl_packing.h" + +static int unpack_nvl(const struct nvunpackops *ops, const struct buffer *buffer, + struct nvlist *nvl) +{ + return -ENOTSUP; /* FIXME */ +} + +struct nvlist *nvl_unpack(const void *ptr, size_t len, enum nvformat format) +{ + const struct buffer buffer = { + .data = (void *) ptr, + .used = len, + .allocsize = len, + }; + const struct nvops *ops; + struct nvlist *nvl; + int ret; + + ops = select_ops(format); + if (!ops) + return ERR_PTR(-ENOTSUP); + + nvl = nvl_alloc(); + if (!nvl) + return ERR_PTR(-ENOMEM); + + ret = unpack_nvl(&ops->unpack, &buffer, nvl); + if (!ret) + return nvl; + + nvl_putref(nvl); + return ERR_PTR(ret); +}