You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by as...@apache.org on 2016/11/14 18:28:37 UTC
[16/20] qpid-proton git commit: PROTON-1350 PROTON-1351: Introduce
proton-c core library - Created new core proton library qpid-proton-core
which only contains protocol processsing and no IO. - Rearranged source tree
to separate core protocol code and
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/codec.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/codec.c b/proton-c/src/core/codec.c
new file mode 100644
index 0000000..67769ad
--- /dev/null
+++ b/proton-c/src/core/codec.c
@@ -0,0 +1,2141 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <proton/object.h>
+#include <proton/codec.h>
+#include <proton/error.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "encodings.h"
+#define DEFINE_FIELDS
+#include "protocol.h"
+#include "platform/platform_fmt.h"
+#include "util.h"
+#include "decoder.h"
+#include "encoder.h"
+#include "data.h"
+#include "log_private.h"
+
+const char *pn_type_name(pn_type_t type)
+{
+ switch (type)
+ {
+ case PN_NULL: return "PN_NULL";
+ case PN_BOOL: return "PN_BOOL";
+ case PN_UBYTE: return "PN_UBYTE";
+ case PN_BYTE: return "PN_BYTE";
+ case PN_USHORT: return "PN_USHORT";
+ case PN_SHORT: return "PN_SHORT";
+ case PN_UINT: return "PN_UINT";
+ case PN_INT: return "PN_INT";
+ case PN_CHAR: return "PN_CHAR";
+ case PN_ULONG: return "PN_ULONG";
+ case PN_LONG: return "PN_LONG";
+ case PN_TIMESTAMP: return "PN_TIMESTAMP";
+ case PN_FLOAT: return "PN_FLOAT";
+ case PN_DOUBLE: return "PN_DOUBLE";
+ case PN_DECIMAL32: return "PN_DECIMAL32";
+ case PN_DECIMAL64: return "PN_DECIMAL64";
+ case PN_DECIMAL128: return "PN_DECIMAL128";
+ case PN_UUID: return "PN_UUID";
+ case PN_BINARY: return "PN_BINARY";
+ case PN_STRING: return "PN_STRING";
+ case PN_SYMBOL: return "PN_SYMBOL";
+ case PN_DESCRIBED: return "PN_DESCRIBED";
+ case PN_ARRAY: return "PN_ARRAY";
+ case PN_LIST: return "PN_LIST";
+ case PN_MAP: return "PN_MAP";
+ default: break;
+ }
+
+ return "<UNKNOWN>";
+}
+
+static inline void pni_atom_init(pn_atom_t *atom, pn_type_t type)
+{
+ memset(atom, 0, sizeof(pn_atom_t));
+ atom->type = type;
+}
+
+// data
+
+static void pn_data_finalize(void *object)
+{
+ pn_data_t *data = (pn_data_t *) object;
+ free(data->nodes);
+ pn_buffer_free(data->buf);
+ pn_free(data->str);
+ pn_error_free(data->error);
+ pn_free(data->decoder);
+ pn_free(data->encoder);
+}
+
+static const pn_fields_t *pni_node_fields(pn_data_t *data, pni_node_t *node)
+{
+ if (!node) return NULL;
+ if (node->atom.type != PN_DESCRIBED) return NULL;
+
+ pni_node_t *descriptor = pn_data_node(data, node->down);
+
+ if (!descriptor || descriptor->atom.type != PN_ULONG) {
+ return NULL;
+ }
+
+ if (descriptor->atom.u.as_ulong >= FIELD_MIN && descriptor->atom.u.as_ulong <= FIELD_MAX) {
+ const pn_fields_t *f = &FIELDS[descriptor->atom.u.as_ulong-FIELD_MIN];
+ return (f->name_index!=0) ? f : NULL;
+ } else {
+ return NULL;
+ }
+}
+
+static int pni_node_index(pn_data_t *data, pni_node_t *node)
+{
+ int count = 0;
+ while (node) {
+ node = pn_data_node(data, node->prev);
+ count++;
+ }
+ return count - 1;
+}
+
+int pni_inspect_atom(pn_atom_t *atom, pn_string_t *str)
+{
+ switch (atom->type) {
+ case PN_NULL:
+ return pn_string_addf(str, "null");
+ case PN_BOOL:
+ return pn_string_addf(str, atom->u.as_bool ? "true" : "false");
+ case PN_UBYTE:
+ return pn_string_addf(str, "%" PRIu8, atom->u.as_ubyte);
+ case PN_BYTE:
+ return pn_string_addf(str, "%" PRIi8, atom->u.as_byte);
+ case PN_USHORT:
+ return pn_string_addf(str, "%" PRIu16, atom->u.as_ushort);
+ case PN_SHORT:
+ return pn_string_addf(str, "%" PRIi16, atom->u.as_short);
+ case PN_UINT:
+ return pn_string_addf(str, "%" PRIu32, atom->u.as_uint);
+ case PN_INT:
+ return pn_string_addf(str, "%" PRIi32, atom->u.as_int);
+ case PN_CHAR:
+ return pn_string_addf(str, "%c", atom->u.as_char);
+ case PN_ULONG:
+ return pn_string_addf(str, "%" PRIu64, atom->u.as_ulong);
+ case PN_LONG:
+ return pn_string_addf(str, "%" PRIi64, atom->u.as_long);
+ case PN_TIMESTAMP:
+ return pn_string_addf(str, "%" PRIi64, atom->u.as_timestamp);
+ case PN_FLOAT:
+ return pn_string_addf(str, "%g", atom->u.as_float);
+ case PN_DOUBLE:
+ return pn_string_addf(str, "%g", atom->u.as_double);
+ case PN_DECIMAL32:
+ return pn_string_addf(str, "D32(%" PRIu32 ")", atom->u.as_decimal32);
+ case PN_DECIMAL64:
+ return pn_string_addf(str, "D64(%" PRIu64 ")", atom->u.as_decimal64);
+ case PN_DECIMAL128:
+ return pn_string_addf(str, "D128(%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
+ "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
+ "%02hhx%02hhx)",
+ atom->u.as_decimal128.bytes[0],
+ atom->u.as_decimal128.bytes[1],
+ atom->u.as_decimal128.bytes[2],
+ atom->u.as_decimal128.bytes[3],
+ atom->u.as_decimal128.bytes[4],
+ atom->u.as_decimal128.bytes[5],
+ atom->u.as_decimal128.bytes[6],
+ atom->u.as_decimal128.bytes[7],
+ atom->u.as_decimal128.bytes[8],
+ atom->u.as_decimal128.bytes[9],
+ atom->u.as_decimal128.bytes[10],
+ atom->u.as_decimal128.bytes[11],
+ atom->u.as_decimal128.bytes[12],
+ atom->u.as_decimal128.bytes[13],
+ atom->u.as_decimal128.bytes[14],
+ atom->u.as_decimal128.bytes[15]);
+ case PN_UUID:
+ return pn_string_addf(str, "UUID(%02hhx%02hhx%02hhx%02hhx-"
+ "%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-"
+ "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx)",
+ atom->u.as_uuid.bytes[0],
+ atom->u.as_uuid.bytes[1],
+ atom->u.as_uuid.bytes[2],
+ atom->u.as_uuid.bytes[3],
+ atom->u.as_uuid.bytes[4],
+ atom->u.as_uuid.bytes[5],
+ atom->u.as_uuid.bytes[6],
+ atom->u.as_uuid.bytes[7],
+ atom->u.as_uuid.bytes[8],
+ atom->u.as_uuid.bytes[9],
+ atom->u.as_uuid.bytes[10],
+ atom->u.as_uuid.bytes[11],
+ atom->u.as_uuid.bytes[12],
+ atom->u.as_uuid.bytes[13],
+ atom->u.as_uuid.bytes[14],
+ atom->u.as_uuid.bytes[15]);
+ case PN_BINARY:
+ case PN_STRING:
+ case PN_SYMBOL:
+ {
+ int err;
+ const char *pfx;
+ pn_bytes_t bin = atom->u.as_bytes;
+ bool quote;
+ switch (atom->type) {
+ case PN_BINARY:
+ pfx = "b";
+ quote = true;
+ break;
+ case PN_STRING:
+ pfx = "";
+ quote = true;
+ break;
+ case PN_SYMBOL:
+ pfx = ":";
+ quote = false;
+ for (unsigned i = 0; i < bin.size; i++) {
+ if (!isalpha(bin.start[i])) {
+ quote = true;
+ break;
+ }
+ }
+ break;
+ default:
+ assert(false);
+ return PN_ERR;
+ }
+
+ if ((err = pn_string_addf(str, "%s", pfx))) return err;
+ if (quote) if ((err = pn_string_addf(str, "\""))) return err;
+ if ((err = pn_quote(str, bin.start, bin.size))) return err;
+ if (quote) if ((err = pn_string_addf(str, "\""))) return err;
+ return 0;
+ }
+ case PN_LIST:
+ return pn_string_addf(str, "<list>");
+ case PN_MAP:
+ return pn_string_addf(str, "<map>");
+ case PN_ARRAY:
+ return pn_string_addf(str, "<array>");
+ case PN_DESCRIBED:
+ return pn_string_addf(str, "<described>");
+ default:
+ return pn_string_addf(str, "<undefined: %i>", atom->type);
+ }
+}
+
+int pni_inspect_enter(void *ctx, pn_data_t *data, pni_node_t *node)
+{
+ pn_string_t *str = (pn_string_t *) ctx;
+ pn_atom_t *atom = (pn_atom_t *) &node->atom;
+
+ pni_node_t *parent = pn_data_node(data, node->parent);
+ const pn_fields_t *fields = pni_node_fields(data, parent);
+ pni_node_t *grandparent = parent ? pn_data_node(data, parent->parent) : NULL;
+ const pn_fields_t *grandfields = pni_node_fields(data, grandparent);
+ int index = pni_node_index(data, node);
+
+ int err;
+
+ if (grandfields) {
+ if (atom->type == PN_NULL) {
+ return 0;
+ }
+ const char *name = (index < grandfields->field_count)
+ ? FIELD_STRINGPOOL.STRING0+FIELD_FIELDS[grandfields->first_field_index+index]
+ : NULL;
+ if (name) {
+ err = pn_string_addf(str, "%s=", name);
+ if (err) return err;
+ }
+ }
+
+ switch (atom->type) {
+ case PN_DESCRIBED:
+ return pn_string_addf(str, "@");
+ case PN_ARRAY:
+ // XXX: need to fix for described arrays
+ return pn_string_addf(str, "@%s[", pn_type_name(node->type));
+ case PN_LIST:
+ return pn_string_addf(str, "[");
+ case PN_MAP:
+ return pn_string_addf(str, "{");
+ default:
+ if (fields && index == 0) {
+ err = pn_string_addf(str, "%s", FIELD_STRINGPOOL.STRING0+FIELD_NAME[fields->name_index]);
+ if (err) return err;
+ err = pn_string_addf(str, "(");
+ if (err) return err;
+ err = pni_inspect_atom(atom, str);
+ if (err) return err;
+ return pn_string_addf(str, ")");
+ } else {
+ return pni_inspect_atom(atom, str);
+ }
+ }
+}
+
+pni_node_t *pni_next_nonnull(pn_data_t *data, pni_node_t *node)
+{
+ while (node) {
+ node = pn_data_node(data, node->next);
+ if (node && node->atom.type != PN_NULL) {
+ return node;
+ }
+ }
+
+ return NULL;
+}
+
+int pni_inspect_exit(void *ctx, pn_data_t *data, pni_node_t *node)
+{
+ pn_string_t *str = (pn_string_t *) ctx;
+ pni_node_t *parent = pn_data_node(data, node->parent);
+ pni_node_t *grandparent = parent ? pn_data_node(data, parent->parent) : NULL;
+ const pn_fields_t *grandfields = pni_node_fields(data, grandparent);
+ pni_node_t *next = pn_data_node(data, node->next);
+ int err;
+
+ switch (node->atom.type) {
+ case PN_ARRAY:
+ case PN_LIST:
+ err = pn_string_addf(str, "]");
+ if (err) return err;
+ break;
+ case PN_MAP:
+ err = pn_string_addf(str, "}");
+ if (err) return err;
+ break;
+ default:
+ break;
+ }
+
+ if (!grandfields || node->atom.type != PN_NULL) {
+ if (next) {
+ int index = pni_node_index(data, node);
+ if (parent && parent->atom.type == PN_MAP && (index % 2) == 0) {
+ err = pn_string_addf(str, "=");
+ } else if (parent && parent->atom.type == PN_DESCRIBED && index == 0) {
+ err = pn_string_addf(str, " ");
+ if (err) return err;
+ } else {
+ if (!grandfields || pni_next_nonnull(data, node)) {
+ err = pn_string_addf(str, ", ");
+ if (err) return err;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int pn_data_inspect(void *obj, pn_string_t *dst)
+{
+ pn_data_t *data = (pn_data_t *) obj;
+
+ return pni_data_traverse(data, pni_inspect_enter, pni_inspect_exit, dst);
+}
+
+#define pn_data_initialize NULL
+#define pn_data_hashcode NULL
+#define pn_data_compare NULL
+
+pn_data_t *pn_data(size_t capacity)
+{
+ static const pn_class_t clazz = PN_CLASS(pn_data);
+ pn_data_t *data = (pn_data_t *) pn_class_new(&clazz, sizeof(pn_data_t));
+ data->capacity = capacity;
+ data->size = 0;
+ data->nodes = capacity ? (pni_node_t *) malloc(capacity * sizeof(pni_node_t)) : NULL;
+ data->buf = pn_buffer(64);
+ data->parent = 0;
+ data->current = 0;
+ data->base_parent = 0;
+ data->base_current = 0;
+ data->decoder = pn_decoder();
+ data->encoder = pn_encoder();
+ data->error = pn_error();
+ data->str = pn_string(NULL);
+ return data;
+}
+
+void pn_data_free(pn_data_t *data)
+{
+ pn_free(data);
+}
+
+int pn_data_errno(pn_data_t *data)
+{
+ return pn_error_code(data->error);
+}
+
+pn_error_t *pn_data_error(pn_data_t *data)
+{
+ return data->error;
+}
+
+size_t pn_data_size(pn_data_t *data)
+{
+ return data ? data->size : 0;
+}
+
+void pn_data_clear(pn_data_t *data)
+{
+ if (data) {
+ data->size = 0;
+ data->parent = 0;
+ data->current = 0;
+ data->base_parent = 0;
+ data->base_current = 0;
+ pn_buffer_clear(data->buf);
+ }
+}
+
+static int pni_data_grow(pn_data_t *data)
+{
+ size_t capacity = data->capacity ? data->capacity : 2;
+ if (capacity >= PNI_NID_MAX) return PN_OUT_OF_MEMORY;
+ else if (capacity < PNI_NID_MAX/2) capacity *= 2;
+ else capacity = PNI_NID_MAX;
+
+ pni_node_t *new_nodes = (pni_node_t *)realloc(data->nodes, capacity * sizeof(pni_node_t));
+ if (new_nodes == NULL) return PN_OUT_OF_MEMORY;
+ data->capacity = capacity;
+ data->nodes = new_nodes;
+ return 0;
+}
+
+static ssize_t pni_data_intern(pn_data_t *data, const char *start, size_t size)
+{
+ size_t offset = pn_buffer_size(data->buf);
+ int err = pn_buffer_append(data->buf, start, size);
+ if (err) return err;
+ err = pn_buffer_append(data->buf, "\0", 1);
+ if (err) return err;
+ return offset;
+}
+
+static pn_bytes_t *pni_data_bytes(pn_data_t *data, pni_node_t *node)
+{
+ switch (node->atom.type) {
+ case PN_BINARY:
+ case PN_STRING:
+ case PN_SYMBOL:
+ return &node->atom.u.as_bytes;
+ default: return NULL;
+ }
+}
+
+static void pni_data_rebase(pn_data_t *data, char *base)
+{
+ for (unsigned i = 0; i < data->size; i++) {
+ pni_node_t *node = &data->nodes[i];
+ if (node->data) {
+ pn_bytes_t *bytes = pni_data_bytes(data, node);
+ bytes->start = base + node->data_offset;
+ }
+ }
+}
+
+static int pni_data_intern_node(pn_data_t *data, pni_node_t *node)
+{
+ pn_bytes_t *bytes = pni_data_bytes(data, node);
+ if (!bytes) return 0;
+ size_t oldcap = pn_buffer_capacity(data->buf);
+ ssize_t offset = pni_data_intern(data, bytes->start, bytes->size);
+ if (offset < 0) return offset;
+ node->data = true;
+ node->data_offset = offset;
+ node->data_size = bytes->size;
+ pn_rwbytes_t buf = pn_buffer_memory(data->buf);
+ bytes->start = buf.start + offset;
+
+ if (pn_buffer_capacity(data->buf) != oldcap) {
+ pni_data_rebase(data, buf.start);
+ }
+
+ return 0;
+}
+
+int pn_data_vfill(pn_data_t *data, const char *fmt, va_list ap)
+{
+ int err = 0;
+ const char *begin = fmt;
+ while (*fmt) {
+ char code = *(fmt++);
+ if (!code) return 0;
+
+ switch (code) {
+ case 'n':
+ err = pn_data_put_null(data);
+ break;
+ case 'o':
+ err = pn_data_put_bool(data, va_arg(ap, int));
+ break;
+ case 'B':
+ err = pn_data_put_ubyte(data, va_arg(ap, unsigned int));
+ break;
+ case 'b':
+ err = pn_data_put_byte(data, va_arg(ap, int));
+ break;
+ case 'H':
+ err = pn_data_put_ushort(data, va_arg(ap, unsigned int));
+ break;
+ case 'h':
+ err = pn_data_put_short(data, va_arg(ap, int));
+ break;
+ case 'I':
+ err = pn_data_put_uint(data, va_arg(ap, uint32_t));
+ break;
+ case 'i':
+ err = pn_data_put_int(data, va_arg(ap, uint32_t));
+ break;
+ case 'L':
+ err = pn_data_put_ulong(data, va_arg(ap, uint64_t));
+ break;
+ case 'l':
+ err = pn_data_put_long(data, va_arg(ap, int64_t));
+ break;
+ case 't':
+ err = pn_data_put_timestamp(data, va_arg(ap, pn_timestamp_t));
+ break;
+ case 'f':
+ err = pn_data_put_float(data, va_arg(ap, double));
+ break;
+ case 'd':
+ err = pn_data_put_double(data, va_arg(ap, double));
+ break;
+ case 'z':
+ {
+ // For maximum portability, caller must pass these as two separate args, not a single struct
+ size_t size = va_arg(ap, size_t);
+ char *start = va_arg(ap, char *);
+ if (start) {
+ err = pn_data_put_binary(data, pn_bytes(size, start));
+ } else {
+ err = pn_data_put_null(data);
+ }
+ }
+ break;
+ case 'S':
+ case 's':
+ {
+ char *start = va_arg(ap, char *);
+ size_t size;
+ if (start) {
+ size = strlen(start);
+ if (code == 'S') {
+ err = pn_data_put_string(data, pn_bytes(size, start));
+ } else {
+ err = pn_data_put_symbol(data, pn_bytes(size, start));
+ }
+ } else {
+ err = pn_data_put_null(data);
+ }
+ }
+ break;
+ case 'D':
+ err = pn_data_put_described(data);
+ pn_data_enter(data);
+ break;
+ case 'T':
+ {
+ pni_node_t *parent = pn_data_node(data, data->parent);
+ if (parent->atom.type == PN_ARRAY) {
+ parent->type = (pn_type_t) va_arg(ap, int);
+ } else {
+ return pn_error_format(data->error, PN_ERR, "naked type");
+ }
+ }
+ break;
+ case '@':
+ {
+ bool described;
+ if (*(fmt + 1) == 'D') {
+ fmt++;
+ described = true;
+ } else {
+ described = false;
+ }
+ err = pn_data_put_array(data, described, (pn_type_t) 0);
+ pn_data_enter(data);
+ }
+ break;
+ case '[':
+ if (fmt < (begin + 2) || *(fmt - 2) != 'T') {
+ err = pn_data_put_list(data);
+ if (err) return err;
+ pn_data_enter(data);
+ }
+ break;
+ case '{':
+ err = pn_data_put_map(data);
+ if (err) return err;
+ pn_data_enter(data);
+ break;
+ case '}':
+ case ']':
+ if (!pn_data_exit(data))
+ return pn_error_format(data->error, PN_ERR, "exit failed");
+ break;
+ case '?':
+ if (!va_arg(ap, int)) {
+ err = pn_data_put_null(data);
+ if (err) return err;
+ pn_data_enter(data);
+ }
+ break;
+ case '*':
+ {
+ int count = va_arg(ap, int);
+ void *ptr = va_arg(ap, void *);
+
+ char c = *(fmt++);
+
+ switch (c)
+ {
+ case 's':
+ {
+ char **sptr = (char **) ptr;
+ for (int i = 0; i < count; i++)
+ {
+ char *sym = *(sptr++);
+ err = pn_data_fill(data, "s", sym);
+ if (err) return err;
+ }
+ }
+ break;
+ default:
+ pn_logf("unrecognized * code: 0x%.2X '%c'", code, code);
+ return PN_ARG_ERR;
+ }
+ }
+ break;
+ case 'C':
+ {
+ pn_data_t *src = va_arg(ap, pn_data_t *);
+ if (src && pn_data_size(src) > 0) {
+ err = pn_data_appendn(data, src, 1);
+ if (err) return err;
+ } else {
+ err = pn_data_put_null(data);
+ if (err) return err;
+ }
+ }
+ break;
+ default:
+ pn_logf("unrecognized fill code: 0x%.2X '%c'", code, code);
+ return PN_ARG_ERR;
+ }
+
+ if (err) return err;
+
+ pni_node_t *parent = pn_data_node(data, data->parent);
+ while (parent) {
+ if (parent->atom.type == PN_DESCRIBED && parent->children == 2) {
+ pn_data_exit(data);
+ parent = pn_data_node(data, data->parent);
+ } else if (parent->atom.type == PN_NULL && parent->children == 1) {
+ pn_data_exit(data);
+ pni_node_t *current = pn_data_node(data, data->current);
+ current->down = 0;
+ current->children = 0;
+ parent = pn_data_node(data, data->parent);
+ } else {
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+int pn_data_fill(pn_data_t *data, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ int err = pn_data_vfill(data, fmt, ap);
+ va_end(ap);
+ return err;
+}
+
+static bool pn_scan_next(pn_data_t *data, pn_type_t *type, bool suspend)
+{
+ if (suspend) return false;
+ bool found = pn_data_next(data);
+ if (found) {
+ *type = pn_data_type(data);
+ return true;
+ } else {
+ pni_node_t *parent = pn_data_node(data, data->parent);
+ if (parent && parent->atom.type == PN_DESCRIBED) {
+ pn_data_exit(data);
+ return pn_scan_next(data, type, suspend);
+ } else {
+ *type = PN_INVALID;
+ return false;
+ }
+ }
+}
+
+static pni_node_t *pni_data_peek(pn_data_t *data);
+
+int pn_data_vscan(pn_data_t *data, const char *fmt, va_list ap)
+{
+ pn_data_rewind(data);
+ bool *scanarg = NULL;
+ bool at = false;
+ int level = 0;
+ int count_level = -1;
+ int resume_count = 0;
+
+ while (*fmt) {
+ char code = *(fmt++);
+
+ bool found = false;
+ pn_type_t type;
+
+ bool scanned = false;
+ bool suspend = resume_count > 0;
+
+ switch (code) {
+ case 'n':
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_NULL) {
+ scanned = true;
+ } else {
+ scanned = false;
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 'o':
+ {
+ bool *value = va_arg(ap, bool *);
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_BOOL) {
+ *value = pn_data_get_bool(data);
+ scanned = true;
+ } else {
+ *value = 0;
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 'B':
+ {
+ uint8_t *value = va_arg(ap, uint8_t *);
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_UBYTE) {
+ *value = pn_data_get_ubyte(data);
+ scanned = true;
+ } else {
+ *value = 0;
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 'b':
+ {
+ int8_t *value = va_arg(ap, int8_t *);
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_BYTE) {
+ *value = pn_data_get_byte(data);
+ scanned = true;
+ } else {
+ *value = 0;
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 'H':
+ {
+ uint16_t *value = va_arg(ap, uint16_t *);
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_USHORT) {
+ *value = pn_data_get_ushort(data);
+ scanned = true;
+ } else {
+ *value = 0;
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 'h':
+ {
+ int16_t *value = va_arg(ap, int16_t *);
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_SHORT) {
+ *value = pn_data_get_short(data);
+ scanned = true;
+ } else {
+ *value = 0;
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 'I':
+ {
+ uint32_t *value = va_arg(ap, uint32_t *);
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_UINT) {
+ *value = pn_data_get_uint(data);
+ scanned = true;
+ } else {
+ *value = 0;
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 'i':
+ {
+ int32_t *value = va_arg(ap, int32_t *);
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_INT) {
+ *value = pn_data_get_int(data);
+ scanned = true;
+ } else {
+ *value = 0;
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 'c':
+ {
+ pn_char_t *value = va_arg(ap, pn_char_t *);
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_CHAR) {
+ *value = pn_data_get_char(data);
+ scanned = true;
+ } else {
+ *value = 0;
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 'L':
+ {
+ uint64_t *value = va_arg(ap, uint64_t *);
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_ULONG) {
+ *value = pn_data_get_ulong(data);
+ scanned = true;
+ } else {
+ *value = 0;
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 'l':
+ {
+ int64_t *value = va_arg(ap, int64_t *);
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_LONG) {
+ *value = pn_data_get_long(data);
+ scanned = true;
+ } else {
+ *value = 0;
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 't':
+ {
+ pn_timestamp_t *value = va_arg(ap, pn_timestamp_t *);
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_TIMESTAMP) {
+ *value = pn_data_get_timestamp(data);
+ scanned = true;
+ } else {
+ *value = 0;
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 'f':
+ {
+ float *value = va_arg(ap, float *);
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_FLOAT) {
+ *value = pn_data_get_float(data);
+ scanned = true;
+ } else {
+ *value = 0;
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 'd':
+ {
+ double *value = va_arg(ap, double *);
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_DOUBLE) {
+ *value = pn_data_get_double(data);
+ scanned = true;
+ } else {
+ *value = 0;
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 'z':
+ {
+ pn_bytes_t *bytes = va_arg(ap, pn_bytes_t *);
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_BINARY) {
+ *bytes = pn_data_get_binary(data);
+ scanned = true;
+ } else {
+ bytes->start = 0;
+ bytes->size = 0;
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 'S':
+ {
+ pn_bytes_t *bytes = va_arg(ap, pn_bytes_t *);
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_STRING) {
+ *bytes = pn_data_get_string(data);
+ scanned = true;
+ } else {
+ bytes->start = 0;
+ bytes->size = 0;
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 's':
+ {
+ pn_bytes_t *bytes = va_arg(ap, pn_bytes_t *);
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_SYMBOL) {
+ *bytes = pn_data_get_symbol(data);
+ scanned = true;
+ } else {
+ bytes->start = 0;
+ bytes->size = 0;
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case 'D':
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_DESCRIBED) {
+ pn_data_enter(data);
+ scanned = true;
+ } else {
+ if (!suspend) {
+ resume_count = 3;
+ count_level = level;
+ }
+ scanned = false;
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case '@':
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_ARRAY) {
+ pn_data_enter(data);
+ scanned = true;
+ at = true;
+ } else {
+ if (!suspend) {
+ resume_count = 3;
+ count_level = level;
+ }
+ scanned = false;
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case '[':
+ if (at) {
+ scanned = true;
+ at = false;
+ } else {
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_LIST) {
+ pn_data_enter(data);
+ scanned = true;
+ } else {
+ if (!suspend) {
+ resume_count = 1;
+ count_level = level;
+ }
+ scanned = false;
+ }
+ }
+ level++;
+ break;
+ case '{':
+ found = pn_scan_next(data, &type, suspend);
+ if (found && type == PN_MAP) {
+ pn_data_enter(data);
+ scanned = true;
+ } else {
+ if (resume_count) {
+ resume_count = 1;
+ count_level = level;
+ }
+ scanned = false;
+ }
+ level++;
+ break;
+ case ']':
+ case '}':
+ level--;
+ if (!suspend && !pn_data_exit(data))
+ return pn_error_format(data->error, PN_ERR, "exit failed");
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case '.':
+ found = pn_scan_next(data, &type, suspend);
+ scanned = found;
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ case '?':
+ if (!*fmt || *fmt == '?')
+ return pn_error_format(data->error, PN_ARG_ERR, "codes must follow a ?");
+ scanarg = va_arg(ap, bool *);
+ break;
+ case 'C':
+ {
+ pn_data_t *dst = va_arg(ap, pn_data_t *);
+ if (!suspend) {
+ size_t old = pn_data_size(dst);
+ pni_node_t *next = pni_data_peek(data);
+ if (next && next->atom.type != PN_NULL) {
+ pn_data_narrow(data);
+ int err = pn_data_appendn(dst, data, 1);
+ pn_data_widen(data);
+ if (err) return err;
+ scanned = pn_data_size(dst) > old;
+ } else {
+ scanned = false;
+ }
+ pn_data_next(data);
+ } else {
+ scanned = false;
+ }
+ }
+ if (resume_count && level == count_level) resume_count--;
+ break;
+ default:
+ return pn_error_format(data->error, PN_ARG_ERR, "unrecognized scan code: 0x%.2X '%c'", code, code);
+ }
+
+ if (scanarg && code != '?') {
+ *scanarg = scanned;
+ scanarg = NULL;
+ }
+ }
+
+ return 0;
+}
+
+int pn_data_scan(pn_data_t *data, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ int err = pn_data_vscan(data, fmt, ap);
+ va_end(ap);
+ return err;
+}
+
+static int pni_data_inspectify(pn_data_t *data)
+{
+ int err = pn_string_set(data->str, "");
+ if (err) return err;
+ return pn_data_inspect(data, data->str);
+}
+
+int pn_data_print(pn_data_t *data)
+{
+ int err = pni_data_inspectify(data);
+ if (err) return err;
+ printf("%s", pn_string_get(data->str));
+ return 0;
+}
+
+int pn_data_format(pn_data_t *data, char *bytes, size_t *size)
+{
+ int err = pni_data_inspectify(data);
+ if (err) return err;
+ if (pn_string_size(data->str) >= *size) {
+ return PN_OVERFLOW;
+ } else {
+ pn_string_put(data->str, bytes);
+ *size = pn_string_size(data->str);
+ return 0;
+ }
+}
+
+static size_t pni_data_id(pn_data_t *data, pni_node_t *node)
+{
+ return node - data->nodes + 1;
+}
+
+static pni_node_t *pni_data_new(pn_data_t *data)
+{
+ if ((data->capacity <= data->size) && (pni_data_grow(data) != 0)) return NULL;
+ pni_node_t *node = pn_data_node(data, ++(data->size));
+ node->next = 0;
+ node->down = 0;
+ node->children = 0;
+ return node;
+}
+
+void pn_data_rewind(pn_data_t *data)
+{
+ data->parent = data->base_parent;
+ data->current = data->base_current;
+}
+
+static pni_node_t *pni_data_current(pn_data_t *data)
+{
+ return pn_data_node(data, data->current);
+}
+
+void pn_data_narrow(pn_data_t *data)
+{
+ data->base_parent = data->parent;
+ data->base_current = data->current;
+}
+
+void pn_data_widen(pn_data_t *data)
+{
+ data->base_parent = 0;
+ data->base_current = 0;
+}
+
+pn_handle_t pn_data_point(pn_data_t *data)
+{
+ if (data->current) {
+ return (pn_handle_t)(uintptr_t)data->current;
+ } else {
+ return (pn_handle_t)(uintptr_t)-data->parent;
+ }
+}
+
+bool pn_data_restore(pn_data_t *data, pn_handle_t point)
+{
+ pn_shandle_t spoint = (pn_shandle_t) point;
+ if (spoint <= 0 && ((size_t) (-spoint)) <= data->size) {
+ data->parent = -((pn_shandle_t) point);
+ data->current = 0;
+ return true;
+ } else if (spoint && spoint <= data->size) {
+ data->current = spoint;
+ pni_node_t *current = pni_data_current(data);
+ data->parent = current->parent;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+static pni_node_t *pni_data_peek(pn_data_t *data)
+{
+ pni_node_t *current = pni_data_current(data);
+ if (current) {
+ return pn_data_node(data, current->next);
+ }
+
+ pni_node_t *parent = pn_data_node(data, data->parent);
+ if (parent) {
+ return pn_data_node(data, parent->down);
+ }
+
+ return NULL;
+}
+
+bool pn_data_next(pn_data_t *data)
+{
+ pni_node_t *current = pni_data_current(data);
+ pni_node_t *parent = pn_data_node(data, data->parent);
+ size_t next;
+
+ if (current) {
+ next = current->next;
+ } else if (parent && parent->down) {
+ next = parent->down;
+ } else if (!parent && data->size) {
+ next = 1;
+ } else {
+ return false;
+ }
+
+ if (next) {
+ data->current = next;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool pn_data_prev(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->prev) {
+ data->current = node->prev;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+int pni_data_traverse(pn_data_t *data,
+ int (*enter)(void *ctx, pn_data_t *data, pni_node_t *node),
+ int (*exit)(void *ctx, pn_data_t *data, pni_node_t *node),
+ void *ctx)
+{
+ pni_node_t *node = data->size ? pn_data_node(data, 1) : NULL;
+ while (node) {
+ pni_node_t *parent = pn_data_node(data, node->parent);
+
+ int err = enter(ctx, data, node);
+ if (err) return err;
+
+ size_t next = 0;
+ if (node->down) {
+ next = node->down;
+ } else if (node->next) {
+ err = exit(ctx, data, node);
+ if (err) return err;
+ next = node->next;
+ } else {
+ err = exit(ctx, data, node);
+ if (err) return err;
+ while (parent) {
+ err = exit(ctx, data, parent);
+ if (err) return err;
+ if (parent->next) {
+ next = parent->next;
+ break;
+ } else {
+ parent = pn_data_node(data, parent->parent);
+ }
+ }
+ }
+
+ node = pn_data_node(data, next);
+ }
+
+ return 0;
+}
+
+pn_type_t pn_data_type(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node) {
+ return node->atom.type;
+ } else {
+ return PN_INVALID;
+ }
+}
+
+pn_type_t pni_data_parent_type(pn_data_t *data)
+{
+ pni_node_t *node = pn_data_node(data, data->parent);
+ if (node) {
+ return node->atom.type;
+ } else {
+ return PN_INVALID;
+ }
+}
+
+size_t pn_data_siblings(pn_data_t *data)
+{
+ pni_node_t *node = pn_data_node(data, data->parent);
+ if (node) {
+ return node->children;
+ } else {
+ return 0;
+ }
+}
+
+bool pn_data_enter(pn_data_t *data)
+{
+ if (data->current) {
+ data->parent = data->current;
+ data->current = 0;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool pn_data_exit(pn_data_t *data)
+{
+ if (data->parent) {
+ pni_node_t *parent = pn_data_node(data, data->parent);
+ data->current = data->parent;
+ data->parent = parent->parent;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool pn_data_lookup(pn_data_t *data, const char *name)
+{
+ while (pn_data_next(data)) {
+ pn_type_t type = pn_data_type(data);
+
+ switch (type) {
+ case PN_STRING:
+ case PN_SYMBOL:
+ {
+ pn_bytes_t bytes = pn_data_get_bytes(data);
+ if (strlen(name) == bytes.size && !strncmp(name, bytes.start, bytes.size)) {
+ return pn_data_next(data);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ // skip the value
+ pn_data_next(data);
+ }
+
+ return false;
+}
+
+void pn_data_dump(pn_data_t *data)
+{
+ printf("{current=%" PN_ZI ", parent=%" PN_ZI "}\n", (size_t) data->current, (size_t) data->parent);
+ for (unsigned i = 0; i < data->size; i++)
+ {
+ pni_node_t *node = &data->nodes[i];
+ pn_string_set(data->str, "");
+ pni_inspect_atom((pn_atom_t *) &node->atom, data->str);
+ printf("Node %i: prev=%" PN_ZI ", next=%" PN_ZI ", parent=%" PN_ZI ", down=%" PN_ZI
+ ", children=%" PN_ZI ", type=%s (%s)\n",
+ i + 1, (size_t) node->prev,
+ (size_t) node->next,
+ (size_t) node->parent,
+ (size_t) node->down,
+ (size_t) node->children,
+ pn_type_name(node->atom.type), pn_string_get(data->str));
+ }
+}
+
+static pni_node_t *pni_data_add(pn_data_t *data)
+{
+ pni_node_t *current = pni_data_current(data);
+ pni_node_t *parent = pn_data_node(data, data->parent);
+ pni_node_t *node;
+
+ if (current) {
+ if (current->next) {
+ node = pn_data_node(data, current->next);
+ } else {
+ node = pni_data_new(data);
+ if (!node) return NULL;
+
+ // refresh the pointers in case we grew
+ current = pni_data_current(data);
+ parent = pn_data_node(data, data->parent);
+ node->prev = data->current;
+ current->next = pni_data_id(data, node);
+ node->parent = data->parent;
+ if (parent) {
+ if (!parent->down) {
+ parent->down = pni_data_id(data, node);
+ }
+ parent->children++;
+ }
+ }
+ } else if (parent) {
+ if (parent->down) {
+ node = pn_data_node(data, parent->down);
+ } else {
+ node = pni_data_new(data);
+ if (!node) return NULL;
+
+ // refresh the pointers in case we grew
+ parent = pn_data_node(data, data->parent);
+ node->prev = 0;
+ node->parent = data->parent;
+ parent->down = pni_data_id(data, node);
+ parent->children++;
+ }
+ } else if (data->size) {
+ node = pn_data_node(data, 1);
+ } else {
+ node = pni_data_new(data);
+ if (!node) return NULL;
+
+ node->prev = 0;
+ node->parent = 0;
+ }
+
+ node->down = 0;
+ node->children = 0;
+ node->data = false;
+ node->data_offset = 0;
+ node->data_size = 0;
+ data->current = pni_data_id(data, node);
+ return node;
+}
+
+ssize_t pn_data_encode(pn_data_t *data, char *bytes, size_t size)
+{
+ return pn_encoder_encode(data->encoder, data, bytes, size);
+}
+
+ssize_t pn_data_encoded_size(pn_data_t *data)
+{
+ return pn_encoder_size(data->encoder, data);
+}
+
+ssize_t pn_data_decode(pn_data_t *data, const char *bytes, size_t size)
+{
+ return pn_decoder_decode(data->decoder, bytes, size, data);
+}
+
+int pn_data_put_list(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_LIST;
+ return 0;
+}
+
+int pn_data_put_map(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_MAP;
+ return 0;
+}
+
+int pn_data_put_array(pn_data_t *data, bool described, pn_type_t type)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_ARRAY;
+ node->described = described;
+ node->type = type;
+ return 0;
+}
+
+void pni_data_set_array_type(pn_data_t *data, pn_type_t type)
+{
+ pni_node_t *array = pni_data_current(data);
+ if (array) array->type = type;
+}
+
+int pn_data_put_described(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_DESCRIBED;
+ return 0;
+}
+
+int pn_data_put_null(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ pni_atom_init(&node->atom, PN_NULL);
+ return 0;
+}
+
+int pn_data_put_bool(pn_data_t *data, bool b)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_BOOL;
+ node->atom.u.as_bool = b;
+ return 0;
+}
+
+int pn_data_put_ubyte(pn_data_t *data, uint8_t ub)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_UBYTE;
+ node->atom.u.as_ubyte = ub;
+ return 0;
+}
+
+int pn_data_put_byte(pn_data_t *data, int8_t b)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_BYTE;
+ node->atom.u.as_byte = b;
+ return 0;
+}
+
+int pn_data_put_ushort(pn_data_t *data, uint16_t us)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_USHORT;
+ node->atom.u.as_ushort = us;
+ return 0;
+}
+
+int pn_data_put_short(pn_data_t *data, int16_t s)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_SHORT;
+ node->atom.u.as_short = s;
+ return 0;
+}
+
+int pn_data_put_uint(pn_data_t *data, uint32_t ui)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_UINT;
+ node->atom.u.as_uint = ui;
+ return 0;
+}
+
+int pn_data_put_int(pn_data_t *data, int32_t i)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_INT;
+ node->atom.u.as_int = i;
+ return 0;
+}
+
+int pn_data_put_char(pn_data_t *data, pn_char_t c)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_CHAR;
+ node->atom.u.as_char = c;
+ return 0;
+}
+
+int pn_data_put_ulong(pn_data_t *data, uint64_t ul)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_ULONG;
+ node->atom.u.as_ulong = ul;
+ return 0;
+}
+
+int pn_data_put_long(pn_data_t *data, int64_t l)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_LONG;
+ node->atom.u.as_long = l;
+ return 0;
+}
+
+int pn_data_put_timestamp(pn_data_t *data, pn_timestamp_t t)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_TIMESTAMP;
+ node->atom.u.as_timestamp = t;
+ return 0;
+}
+
+int pn_data_put_float(pn_data_t *data, float f)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_FLOAT;
+ node->atom.u.as_float = f;
+ return 0;
+}
+
+int pn_data_put_double(pn_data_t *data, double d)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_DOUBLE;
+ node->atom.u.as_double = d;
+ return 0;
+}
+
+int pn_data_put_decimal32(pn_data_t *data, pn_decimal32_t d)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_DECIMAL32;
+ node->atom.u.as_decimal32 = d;
+ return 0;
+}
+
+int pn_data_put_decimal64(pn_data_t *data, pn_decimal64_t d)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_DECIMAL64;
+ node->atom.u.as_decimal64 = d;
+ return 0;
+}
+
+int pn_data_put_decimal128(pn_data_t *data, pn_decimal128_t d)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_DECIMAL128;
+ memmove(node->atom.u.as_decimal128.bytes, d.bytes, 16);
+ return 0;
+}
+
+int pn_data_put_uuid(pn_data_t *data, pn_uuid_t u)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_UUID;
+ memmove(node->atom.u.as_uuid.bytes, u.bytes, 16);
+ return 0;
+}
+
+int pn_data_put_binary(pn_data_t *data, pn_bytes_t bytes)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_BINARY;
+ node->atom.u.as_bytes = bytes;
+ return pni_data_intern_node(data, node);
+}
+
+int pn_data_put_string(pn_data_t *data, pn_bytes_t string)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_STRING;
+ node->atom.u.as_bytes = string;
+ return pni_data_intern_node(data, node);
+}
+
+int pn_data_put_symbol(pn_data_t *data, pn_bytes_t symbol)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom.type = PN_SYMBOL;
+ node->atom.u.as_bytes = symbol;
+ return pni_data_intern_node(data, node);
+}
+
+int pn_data_put_atom(pn_data_t *data, pn_atom_t atom)
+{
+ pni_node_t *node = pni_data_add(data);
+ if (node == NULL) return PN_OUT_OF_MEMORY;
+ node->atom = atom;
+ return pni_data_intern_node(data, node);
+}
+
+size_t pn_data_get_list(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_LIST) {
+ return node->children;
+ } else {
+ return 0;
+ }
+}
+
+size_t pn_data_get_map(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_MAP) {
+ return node->children;
+ } else {
+ return 0;
+ }
+}
+
+size_t pn_data_get_array(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_ARRAY) {
+ if (node->described) {
+ return node->children - 1;
+ } else {
+ return node->children;
+ }
+ } else {
+ return 0;
+ }
+}
+
+bool pn_data_is_array_described(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_ARRAY) {
+ return node->described;
+ } else {
+ return false;
+ }
+}
+
+pn_type_t pn_data_get_array_type(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_ARRAY) {
+ return node->type;
+ } else {
+ return PN_INVALID;
+ }
+}
+
+bool pn_data_is_described(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ return node && node->atom.type == PN_DESCRIBED;
+}
+
+bool pn_data_is_null(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ return node && node->atom.type == PN_NULL;
+}
+
+bool pn_data_get_bool(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_BOOL) {
+ return node->atom.u.as_bool;
+ } else {
+ return false;
+ }
+}
+
+uint8_t pn_data_get_ubyte(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_UBYTE) {
+ return node->atom.u.as_ubyte;
+ } else {
+ return 0;
+ }
+}
+
+int8_t pn_data_get_byte(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_BYTE) {
+ return node->atom.u.as_byte;
+ } else {
+ return 0;
+ }
+}
+
+uint16_t pn_data_get_ushort(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_USHORT) {
+ return node->atom.u.as_ushort;
+ } else {
+ return 0;
+ }
+}
+
+int16_t pn_data_get_short(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_SHORT) {
+ return node->atom.u.as_short;
+ } else {
+ return 0;
+ }
+}
+
+uint32_t pn_data_get_uint(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_UINT) {
+ return node->atom.u.as_uint;
+ } else {
+ return 0;
+ }
+}
+
+int32_t pn_data_get_int(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_INT) {
+ return node->atom.u.as_int;
+ } else {
+ return 0;
+ }
+}
+
+pn_char_t pn_data_get_char(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_CHAR) {
+ return node->atom.u.as_char;
+ } else {
+ return 0;
+ }
+}
+
+uint64_t pn_data_get_ulong(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_ULONG) {
+ return node->atom.u.as_ulong;
+ } else {
+ return 0;
+ }
+}
+
+int64_t pn_data_get_long(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_LONG) {
+ return node->atom.u.as_long;
+ } else {
+ return 0;
+ }
+}
+
+pn_timestamp_t pn_data_get_timestamp(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_TIMESTAMP) {
+ return node->atom.u.as_timestamp;
+ } else {
+ return 0;
+ }
+}
+
+float pn_data_get_float(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_FLOAT) {
+ return node->atom.u.as_float;
+ } else {
+ return 0;
+ }
+}
+
+double pn_data_get_double(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_DOUBLE) {
+ return node->atom.u.as_double;
+ } else {
+ return 0;
+ }
+}
+
+pn_decimal32_t pn_data_get_decimal32(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_DECIMAL32) {
+ return node->atom.u.as_decimal32;
+ } else {
+ return 0;
+ }
+}
+
+pn_decimal64_t pn_data_get_decimal64(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_DECIMAL64) {
+ return node->atom.u.as_decimal64;
+ } else {
+ return 0;
+ }
+}
+
+pn_decimal128_t pn_data_get_decimal128(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_DECIMAL128) {
+ return node->atom.u.as_decimal128;
+ } else {
+ pn_decimal128_t t = {{0}};
+ return t;
+ }
+}
+
+pn_uuid_t pn_data_get_uuid(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_UUID) {
+ return node->atom.u.as_uuid;
+ } else {
+ pn_uuid_t t = {{0}};
+ return t;
+ }
+}
+
+pn_bytes_t pn_data_get_binary(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_BINARY) {
+ return node->atom.u.as_bytes;
+ } else {
+ pn_bytes_t t = {0};
+ return t;
+ }
+}
+
+pn_bytes_t pn_data_get_string(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_STRING) {
+ return node->atom.u.as_bytes;
+ } else {
+ pn_bytes_t t = {0};
+ return t;
+ }
+}
+
+pn_bytes_t pn_data_get_symbol(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && node->atom.type == PN_SYMBOL) {
+ return node->atom.u.as_bytes;
+ } else {
+ pn_bytes_t t = {0};
+ return t;
+ }
+}
+
+pn_bytes_t pn_data_get_bytes(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node && (node->atom.type == PN_BINARY ||
+ node->atom.type == PN_STRING ||
+ node->atom.type == PN_SYMBOL)) {
+ return node->atom.u.as_bytes;
+ } else {
+ pn_bytes_t t = {0};
+ return t;
+ }
+}
+
+pn_atom_t pn_data_get_atom(pn_data_t *data)
+{
+ pni_node_t *node = pni_data_current(data);
+ if (node) {
+ return *((pn_atom_t *) &node->atom);
+ } else {
+ pn_atom_t t = {PN_NULL, {0,}};
+ return t;
+ }
+}
+
+int pn_data_copy(pn_data_t *data, pn_data_t *src)
+{
+ pn_data_clear(data);
+ int err = pn_data_append(data, src);
+ pn_data_rewind(data);
+ return err;
+}
+
+int pn_data_append(pn_data_t *data, pn_data_t *src)
+{
+ return pn_data_appendn(data, src, -1);
+}
+
+int pn_data_appendn(pn_data_t *data, pn_data_t *src, int limit)
+{
+ int err = 0;
+ int level = 0, count = 0;
+ bool stop = false;
+ pn_handle_t point = pn_data_point(src);
+ pn_data_rewind(src);
+
+ while (true) {
+ while (!pn_data_next(src)) {
+ if (level > 0) {
+ pn_data_exit(data);
+ pn_data_exit(src);
+ level--;
+ continue;
+ }
+
+ if (!pn_data_next(src)) {
+ stop = true;
+ }
+ break;
+ }
+
+ if (stop) break;
+
+ if (level == 0 && count == limit)
+ break;
+
+ pn_type_t type = pn_data_type(src);
+ switch (type) {
+ case PN_NULL:
+ err = pn_data_put_null(data);
+ if (level == 0) count++;
+ break;
+ case PN_BOOL:
+ err = pn_data_put_bool(data, pn_data_get_bool(src));
+ if (level == 0) count++;
+ break;
+ case PN_UBYTE:
+ err = pn_data_put_ubyte(data, pn_data_get_ubyte(src));
+ if (level == 0) count++;
+ break;
+ case PN_BYTE:
+ err = pn_data_put_byte(data, pn_data_get_byte(src));
+ if (level == 0) count++;
+ break;
+ case PN_USHORT:
+ err = pn_data_put_ushort(data, pn_data_get_ushort(src));
+ if (level == 0) count++;
+ break;
+ case PN_SHORT:
+ err = pn_data_put_short(data, pn_data_get_short(src));
+ if (level == 0) count++;
+ break;
+ case PN_UINT:
+ err = pn_data_put_uint(data, pn_data_get_uint(src));
+ if (level == 0) count++;
+ break;
+ case PN_INT:
+ err = pn_data_put_int(data, pn_data_get_int(src));
+ if (level == 0) count++;
+ break;
+ case PN_CHAR:
+ err = pn_data_put_char(data, pn_data_get_char(src));
+ if (level == 0) count++;
+ break;
+ case PN_ULONG:
+ err = pn_data_put_ulong(data, pn_data_get_ulong(src));
+ if (level == 0) count++;
+ break;
+ case PN_LONG:
+ err = pn_data_put_long(data, pn_data_get_long(src));
+ if (level == 0) count++;
+ break;
+ case PN_TIMESTAMP:
+ err = pn_data_put_timestamp(data, pn_data_get_timestamp(src));
+ if (level == 0) count++;
+ break;
+ case PN_FLOAT:
+ err = pn_data_put_float(data, pn_data_get_float(src));
+ if (level == 0) count++;
+ break;
+ case PN_DOUBLE:
+ err = pn_data_put_double(data, pn_data_get_double(src));
+ if (level == 0) count++;
+ break;
+ case PN_DECIMAL32:
+ err = pn_data_put_decimal32(data, pn_data_get_decimal32(src));
+ if (level == 0) count++;
+ break;
+ case PN_DECIMAL64:
+ err = pn_data_put_decimal64(data, pn_data_get_decimal64(src));
+ if (level == 0) count++;
+ break;
+ case PN_DECIMAL128:
+ err = pn_data_put_decimal128(data, pn_data_get_decimal128(src));
+ if (level == 0) count++;
+ break;
+ case PN_UUID:
+ err = pn_data_put_uuid(data, pn_data_get_uuid(src));
+ if (level == 0) count++;
+ break;
+ case PN_BINARY:
+ err = pn_data_put_binary(data, pn_data_get_binary(src));
+ if (level == 0) count++;
+ break;
+ case PN_STRING:
+ err = pn_data_put_string(data, pn_data_get_string(src));
+ if (level == 0) count++;
+ break;
+ case PN_SYMBOL:
+ err = pn_data_put_symbol(data, pn_data_get_symbol(src));
+ if (level == 0) count++;
+ break;
+ case PN_DESCRIBED:
+ err = pn_data_put_described(data);
+ if (level == 0) count++;
+ if (err) { pn_data_restore(src, point); return err; }
+ pn_data_enter(data);
+ pn_data_enter(src);
+ level++;
+ break;
+ case PN_ARRAY:
+ err = pn_data_put_array(data, pn_data_is_array_described(src),
+ pn_data_get_array_type(src));
+ if (level == 0) count++;
+ if (err) { pn_data_restore(src, point); return err; }
+ pn_data_enter(data);
+ pn_data_enter(src);
+ level++;
+ break;
+ case PN_LIST:
+ err = pn_data_put_list(data);
+ if (level == 0) count++;
+ if (err) { pn_data_restore(src, point); return err; }
+ pn_data_enter(data);
+ pn_data_enter(src);
+ level++;
+ break;
+ case PN_MAP:
+ err = pn_data_put_map(data);
+ if (level == 0) count++;
+ if (err) { pn_data_restore(src, point); return err; }
+ pn_data_enter(data);
+ pn_data_enter(src);
+ level++;
+ break;
+ default:
+ break;
+ }
+
+ if (err) { pn_data_restore(src, point); return err; }
+ }
+
+ pn_data_restore(src, point);
+
+ return 0;
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/config.h
----------------------------------------------------------------------
diff --git a/proton-c/src/core/config.h b/proton-c/src/core/config.h
new file mode 100644
index 0000000..5a2e7bc
--- /dev/null
+++ b/proton-c/src/core/config.h
@@ -0,0 +1,32 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+#ifndef _PROTON_SRC_CONFIG_H
+#define _PROTON_SRC_CONFIG_H
+
+#ifndef PN_TRANSPORT_INITIAL_FRAME_SIZE
+# define PN_TRANSPORT_INITIAL_FRAME_SIZE (512) /* bytes */
+#endif
+
+#ifndef PN_SASL_MAX_BUFFSIZE
+# define PN_SASL_MAX_BUFFSIZE (32768) /* bytes */
+#endif
+
+#endif /* _PROTON_SRC_CONFIG_H */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/connection_engine.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/connection_engine.c b/proton-c/src/core/connection_engine.c
new file mode 100644
index 0000000..5d184a1
--- /dev/null
+++ b/proton-c/src/core/connection_engine.c
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#include "engine-internal.h"
+
+#include <proton/connection.h>
+#include <proton/connection_engine.h>
+#include <proton/transport.h>
+#include <string.h>
+
+int pn_connection_engine_init(pn_connection_engine_t* e) {
+ memset(e, 0, sizeof(*e));
+ e->connection = pn_connection();
+ e->transport = pn_transport();
+ e->collector = pn_collector();
+ if (!e->connection || !e->transport || !e->collector) {
+ pn_connection_engine_final(e);
+ return PN_OUT_OF_MEMORY;
+ }
+ pn_connection_collect(e->connection, e->collector);
+ return PN_OK;
+}
+
+void pn_connection_engine_final(pn_connection_engine_t* e) {
+ if (e->transport && e->connection) {
+ pn_transport_unbind(e->transport);
+ pn_decref(e->transport);
+ }
+ if (e->collector)
+ pn_collector_free(e->collector); /* Break cycle with connection */
+ if (e->connection)
+ pn_decref(e->connection);
+ memset(e, 0, sizeof(*e));
+}
+
+pn_rwbytes_t pn_connection_engine_read_buffer(pn_connection_engine_t* e) {
+ ssize_t cap = pn_transport_capacity(e->transport);
+ if (cap > 0)
+ return pn_rwbytes(cap, pn_transport_tail(e->transport));
+ else
+ return pn_rwbytes(0, 0);
+}
+
+void pn_connection_engine_read_done(pn_connection_engine_t* e, size_t n) {
+ if (n > 0)
+ pn_transport_process(e->transport, n);
+}
+
+void pn_connection_engine_read_close(pn_connection_engine_t* e) {
+ pn_transport_close_tail(e->transport);
+}
+
+pn_bytes_t pn_connection_engine_write_buffer(pn_connection_engine_t* e) {
+ ssize_t pending = pn_transport_pending(e->transport);
+ if (pending > 0)
+ return pn_bytes(pending, pn_transport_head(e->transport));
+ else
+ return pn_bytes(0, 0);
+}
+
+void pn_connection_engine_write_done(pn_connection_engine_t* e, size_t n) {
+ if (n > 0)
+ pn_transport_pop(e->transport, n);
+}
+
+void pn_connection_engine_write_close(pn_connection_engine_t* e){
+ pn_transport_close_head(e->transport);
+}
+
+void pn_connection_engine_disconnected(pn_connection_engine_t* e) {
+ pn_connection_engine_read_close(e);
+ pn_connection_engine_write_close(e);
+}
+
+static void log_event(pn_connection_engine_t *engine, pn_event_t* event) {
+ if (event && engine->transport->trace & PN_TRACE_EVT) {
+ pn_string_t *str = pn_string(NULL);
+ pn_inspect(event, str);
+ pn_transport_log(engine->transport, pn_string_get(str));
+ pn_free(str);
+ }
+}
+
+pn_event_t* pn_connection_engine_dispatch(pn_connection_engine_t* e) {
+ if (e->event) { /* Already returned */
+ if (pn_event_type(e->event) == PN_CONNECTION_INIT)
+ pn_transport_bind(e->transport, e->connection);
+ pn_collector_pop(e->collector);
+ }
+ e->event = pn_collector_peek(e->collector);
+ log_event(e, e->event);
+ return e->event;
+}
+
+bool pn_connection_engine_finished(pn_connection_engine_t* e) {
+ return pn_transport_closed(e->transport) && (pn_collector_peek(e->collector) == NULL);
+}
+
+pn_connection_t* pn_connection_engine_connection(pn_connection_engine_t* e) {
+ return e->connection;
+}
+
+pn_transport_t* pn_connection_engine_transport(pn_connection_engine_t* e) {
+ return e->transport;
+}
+
+pn_condition_t* pn_connection_engine_condition(pn_connection_engine_t* e) {
+ return pn_transport_condition(e->transport);
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/data.h
----------------------------------------------------------------------
diff --git a/proton-c/src/core/data.h b/proton-c/src/core/data.h
new file mode 100644
index 0000000..94dc7d6
--- /dev/null
+++ b/proton-c/src/core/data.h
@@ -0,0 +1,75 @@
+#ifndef _PROTON_DATA_H
+#define _PROTON_DATA_H 1
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <proton/codec.h>
+#include "buffer.h"
+#include "decoder.h"
+#include "encoder.h"
+
+typedef uint16_t pni_nid_t;
+#define PNI_NID_MAX ((pni_nid_t)-1)
+
+typedef struct {
+ char *start;
+ size_t data_offset;
+ size_t data_size;
+ pn_atom_t atom;
+ pn_type_t type;
+ pni_nid_t next;
+ pni_nid_t prev;
+ pni_nid_t down;
+ pni_nid_t parent;
+ pni_nid_t children;
+ // for arrays
+ bool described;
+ bool data;
+ bool small;
+} pni_node_t;
+
+struct pn_data_t {
+ pni_node_t *nodes;
+ pn_buffer_t *buf;
+ pn_decoder_t *decoder;
+ pn_encoder_t *encoder;
+ pn_error_t *error;
+ pn_string_t *str;
+ pni_nid_t capacity;
+ pni_nid_t size;
+ pni_nid_t parent;
+ pni_nid_t current;
+ pni_nid_t base_parent;
+ pni_nid_t base_current;
+};
+
+static inline pni_node_t * pn_data_node(pn_data_t *data, pni_nid_t nd)
+{
+ return nd ? (data->nodes + nd - 1) : NULL;
+}
+
+int pni_data_traverse(pn_data_t *data,
+ int (*enter)(void *ctx, pn_data_t *data, pni_node_t *node),
+ int (*exit)(void *ctx, pn_data_t *data, pni_node_t *node),
+ void *ctx);
+
+#endif /* data.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/decoder.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/decoder.c b/proton-c/src/core/decoder.c
new file mode 100644
index 0000000..b0c8d79
--- /dev/null
+++ b/proton-c/src/core/decoder.c
@@ -0,0 +1,497 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <proton/error.h>
+#include <proton/object.h>
+#include <proton/codec.h>
+#include "encodings.h"
+#include "decoder.h"
+
+#include <string.h>
+
+struct pn_decoder_t {
+ const char *input;
+ size_t size;
+ const char *position;
+ pn_error_t *error;
+};
+
+static void pn_decoder_initialize(void *obj)
+{
+ pn_decoder_t *decoder = (pn_decoder_t *) obj;
+ decoder->input = NULL;
+ decoder->size = 0;
+ decoder->position = NULL;
+ decoder->error = pn_error();
+}
+
+static void pn_decoder_finalize(void *obj) {
+ pn_decoder_t *decoder = (pn_decoder_t *) obj;
+ pn_error_free(decoder->error);
+}
+
+#define pn_decoder_hashcode NULL
+#define pn_decoder_compare NULL
+#define pn_decoder_inspect NULL
+
+pn_decoder_t *pn_decoder()
+{
+ static const pn_class_t clazz = PN_CLASS(pn_decoder);
+ return (pn_decoder_t *) pn_class_new(&clazz, sizeof(pn_decoder_t));
+}
+
+static inline uint8_t pn_decoder_readf8(pn_decoder_t *decoder)
+{
+ uint8_t r = decoder->position[0];
+ decoder->position++;
+ return r;
+}
+
+static inline uint16_t pn_decoder_readf16(pn_decoder_t *decoder)
+{
+ uint16_t a = (uint8_t) decoder->position[0];
+ uint16_t b = (uint8_t) decoder->position[1];
+ uint16_t r = a << 8
+ | b;
+ decoder->position += 2;
+ return r;
+}
+
+static inline uint32_t pn_decoder_readf32(pn_decoder_t *decoder)
+{
+ uint32_t a = (uint8_t) decoder->position[0];
+ uint32_t b = (uint8_t) decoder->position[1];
+ uint32_t c = (uint8_t) decoder->position[2];
+ uint32_t d = (uint8_t) decoder->position[3];
+ uint32_t r = a << 24
+ | b << 16
+ | c << 8
+ | d;
+ decoder->position += 4;
+ return r;
+}
+
+static inline uint64_t pn_decoder_readf64(pn_decoder_t *decoder)
+{
+ uint64_t a = pn_decoder_readf32(decoder);
+ uint64_t b = pn_decoder_readf32(decoder);
+ return a << 32 | b;
+}
+
+static inline void pn_decoder_readf128(pn_decoder_t *decoder, void *dst)
+{
+ memmove(dst, decoder->position, 16);
+ decoder->position += 16;
+}
+
+static inline size_t pn_decoder_remaining(pn_decoder_t *decoder)
+{
+ return decoder->input + decoder->size - decoder->position;
+}
+
+typedef union {
+ uint32_t i;
+ uint32_t a[2];
+ uint64_t l;
+ float f;
+ double d;
+} conv_t;
+
+static inline pn_type_t pn_code2type(uint8_t code)
+{
+ switch (code)
+ {
+ case PNE_DESCRIPTOR:
+ return (pn_type_t) PN_ARG_ERR;
+ case PNE_NULL:
+ return PN_NULL;
+ case PNE_TRUE:
+ case PNE_FALSE:
+ case PNE_BOOLEAN:
+ return PN_BOOL;
+ case PNE_UBYTE:
+ return PN_UBYTE;
+ case PNE_BYTE:
+ return PN_BYTE;
+ case PNE_USHORT:
+ return PN_USHORT;
+ case PNE_SHORT:
+ return PN_SHORT;
+ case PNE_UINT0:
+ case PNE_SMALLUINT:
+ case PNE_UINT:
+ return PN_UINT;
+ case PNE_SMALLINT:
+ case PNE_INT:
+ return PN_INT;
+ case PNE_UTF32:
+ return PN_CHAR;
+ case PNE_FLOAT:
+ return PN_FLOAT;
+ case PNE_LONG:
+ case PNE_SMALLLONG:
+ return PN_LONG;
+ case PNE_MS64:
+ return PN_TIMESTAMP;
+ case PNE_DOUBLE:
+ return PN_DOUBLE;
+ case PNE_DECIMAL32:
+ return PN_DECIMAL32;
+ case PNE_DECIMAL64:
+ return PN_DECIMAL64;
+ case PNE_DECIMAL128:
+ return PN_DECIMAL128;
+ case PNE_UUID:
+ return PN_UUID;
+ case PNE_ULONG0:
+ case PNE_SMALLULONG:
+ case PNE_ULONG:
+ return PN_ULONG;
+ case PNE_VBIN8:
+ case PNE_VBIN32:
+ return PN_BINARY;
+ case PNE_STR8_UTF8:
+ case PNE_STR32_UTF8:
+ return PN_STRING;
+ case PNE_SYM8:
+ case PNE_SYM32:
+ return PN_SYMBOL;
+ case PNE_LIST0:
+ case PNE_LIST8:
+ case PNE_LIST32:
+ return PN_LIST;
+ case PNE_ARRAY8:
+ case PNE_ARRAY32:
+ return PN_ARRAY;
+ case PNE_MAP8:
+ case PNE_MAP32:
+ return PN_MAP;
+ default:
+ return (pn_type_t) PN_ARG_ERR;
+ }
+}
+
+static int pni_decoder_decode_type(pn_decoder_t *decoder, pn_data_t *data, uint8_t *code);
+static int pni_decoder_single(pn_decoder_t *decoder, pn_data_t *data);
+void pni_data_set_array_type(pn_data_t *data, pn_type_t type);
+
+static int pni_decoder_decode_value(pn_decoder_t *decoder, pn_data_t *data, uint8_t code)
+{
+ int err;
+ conv_t conv;
+ pn_decimal128_t dec128;
+ pn_uuid_t uuid;
+ size_t size;
+ size_t count;
+
+ switch (code)
+ {
+ case PNE_NULL:
+ err = pn_data_put_null(data);
+ break;
+ case PNE_TRUE:
+ err = pn_data_put_bool(data, true);
+ break;
+ case PNE_FALSE:
+ err = pn_data_put_bool(data, false);
+ break;
+ case PNE_BOOLEAN:
+ if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
+ err = pn_data_put_bool(data, pn_decoder_readf8(decoder) != 0);
+ break;
+ case PNE_UBYTE:
+ if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
+ err = pn_data_put_ubyte(data, pn_decoder_readf8(decoder));
+ break;
+ case PNE_BYTE:
+ if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
+ err = pn_data_put_byte(data, pn_decoder_readf8(decoder));
+ break;
+ case PNE_USHORT:
+ if (pn_decoder_remaining(decoder) < 2) return PN_UNDERFLOW;
+ err = pn_data_put_ushort(data, pn_decoder_readf16(decoder));
+ break;
+ case PNE_SHORT:
+ if (pn_decoder_remaining(decoder) < 2) return PN_UNDERFLOW;
+ err = pn_data_put_short(data, pn_decoder_readf16(decoder));
+ break;
+ case PNE_UINT:
+ if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
+ err = pn_data_put_uint(data, pn_decoder_readf32(decoder));
+ break;
+ case PNE_UINT0:
+ err = pn_data_put_uint(data, 0);
+ break;
+ case PNE_SMALLUINT:
+ if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
+ err = pn_data_put_uint(data, pn_decoder_readf8(decoder));
+ break;
+ case PNE_SMALLINT:
+ if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
+ err = pn_data_put_int(data, (int8_t)pn_decoder_readf8(decoder));
+ break;
+ case PNE_INT:
+ if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
+ err = pn_data_put_int(data, pn_decoder_readf32(decoder));
+ break;
+ case PNE_UTF32:
+ if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
+ err = pn_data_put_char(data, pn_decoder_readf32(decoder));
+ break;
+ case PNE_FLOAT:
+ if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
+ // XXX: this assumes the platform uses IEEE floats
+ conv.i = pn_decoder_readf32(decoder);
+ err = pn_data_put_float(data, conv.f);
+ break;
+ case PNE_DECIMAL32:
+ if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
+ err = pn_data_put_decimal32(data, pn_decoder_readf32(decoder));
+ break;
+ case PNE_ULONG:
+ if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
+ err = pn_data_put_ulong(data, pn_decoder_readf64(decoder));
+ break;
+ case PNE_LONG:
+ if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
+ err = pn_data_put_long(data, pn_decoder_readf64(decoder));
+ break;
+ case PNE_MS64:
+ if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
+ err = pn_data_put_timestamp(data, pn_decoder_readf64(decoder));
+ break;
+ case PNE_DOUBLE:
+ // XXX: this assumes the platform uses IEEE floats
+ if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
+ conv.l = pn_decoder_readf64(decoder);
+ err = pn_data_put_double(data, conv.d);
+ break;
+ case PNE_DECIMAL64:
+ if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
+ err = pn_data_put_decimal64(data, pn_decoder_readf64(decoder));
+ break;
+ case PNE_ULONG0:
+ err = pn_data_put_ulong(data, 0);
+ break;
+ case PNE_SMALLULONG:
+ if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
+ err = pn_data_put_ulong(data, pn_decoder_readf8(decoder));
+ break;
+ case PNE_SMALLLONG:
+ if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
+ err = pn_data_put_long(data, (int8_t)pn_decoder_readf8(decoder));
+ break;
+ case PNE_DECIMAL128:
+ if (pn_decoder_remaining(decoder) < 16) return PN_UNDERFLOW;
+ pn_decoder_readf128(decoder, &dec128);
+ err = pn_data_put_decimal128(data, dec128);
+ break;
+ case PNE_UUID:
+ if (pn_decoder_remaining(decoder) < 16) return PN_UNDERFLOW;
+ pn_decoder_readf128(decoder, &uuid);
+ err = pn_data_put_uuid(data, uuid);
+ break;
+ case PNE_VBIN8:
+ case PNE_STR8_UTF8:
+ case PNE_SYM8:
+ case PNE_VBIN32:
+ case PNE_STR32_UTF8:
+ case PNE_SYM32:
+ switch (code & 0xF0)
+ {
+ case 0xA0:
+ if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
+ size = pn_decoder_readf8(decoder);
+ break;
+ case 0xB0:
+ if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
+ size = pn_decoder_readf32(decoder);
+ break;
+ default:
+ return PN_ARG_ERR;
+ }
+
+ if (pn_decoder_remaining(decoder) < size) return PN_UNDERFLOW;
+
+ {
+ char *start = (char *) decoder->position;
+ pn_bytes_t bytes = {size, start};
+ switch (code & 0x0F)
+ {
+ case 0x0:
+ err = pn_data_put_binary(data, bytes);
+ break;
+ case 0x1:
+ err = pn_data_put_string(data, bytes);
+ break;
+ case 0x3:
+ err = pn_data_put_symbol(data, bytes);
+ break;
+ default:
+ return PN_ARG_ERR;
+ }
+ }
+
+ decoder->position += size;
+ break;
+ case PNE_LIST0:
+ err = pn_data_put_list(data);
+ break;
+ case PNE_ARRAY8:
+ case PNE_ARRAY32:
+ case PNE_LIST8:
+ case PNE_LIST32:
+ case PNE_MAP8:
+ case PNE_MAP32:
+ switch (code)
+ {
+ case PNE_ARRAY8:
+ case PNE_LIST8:
+ case PNE_MAP8:
+ if (pn_decoder_remaining(decoder) < 2) return PN_UNDERFLOW;
+ size = pn_decoder_readf8(decoder);
+ count = pn_decoder_readf8(decoder);
+ break;
+ case PNE_ARRAY32:
+ case PNE_LIST32:
+ case PNE_MAP32:
+ size = pn_decoder_readf32(decoder);
+ count = pn_decoder_readf32(decoder);
+ break;
+ default:
+ return PN_ARG_ERR;
+ }
+
+ switch (code)
+ {
+ case PNE_ARRAY8:
+ case PNE_ARRAY32:
+ {
+ uint8_t next = *decoder->position;
+ bool described = (next == PNE_DESCRIPTOR);
+ err = pn_data_put_array(data, described, (pn_type_t) 0);
+ if (err) return err;
+
+ pn_data_enter(data);
+ uint8_t acode;
+ int e = pni_decoder_decode_type(decoder, data, &acode);
+ if (e) return e;
+ pn_type_t type = pn_code2type(acode);
+ if ((int)type < 0) return (int)type;
+ for (size_t i = 0; i < count; i++)
+ {
+ e = pni_decoder_decode_value(decoder, data, acode);
+ if (e) return e;
+ }
+ pn_data_exit(data);
+
+ pni_data_set_array_type(data, type);
+ }
+ return 0;
+ case PNE_LIST8:
+ case PNE_LIST32:
+ err = pn_data_put_list(data);
+ if (err) return err;
+ break;
+ case PNE_MAP8:
+ case PNE_MAP32:
+ err = pn_data_put_map(data);
+ if (err) return err;
+ break;
+ default:
+ return PN_ARG_ERR;
+ }
+
+ pn_data_enter(data);
+ for (size_t i = 0; i < count; i++)
+ {
+ int e = pni_decoder_single(decoder, data);
+ if (e) return e;
+ }
+ pn_data_exit(data);
+
+ return 0;
+ default:
+ return pn_error_format(decoder->error, PN_ARG_ERR, "unrecognized typecode: %u", code);
+ }
+
+ return err;
+}
+
+pn_type_t pni_data_parent_type(pn_data_t *data);
+
+static int pni_decoder_decode_type(pn_decoder_t *decoder, pn_data_t *data, uint8_t *code)
+{
+ int err;
+
+ if (!pn_decoder_remaining(decoder)) {
+ return PN_UNDERFLOW;
+ }
+
+ uint8_t next = *decoder->position++;
+
+ if (next == PNE_DESCRIPTOR) {
+ if (pni_data_parent_type(data) != PN_ARRAY) {
+ err = pn_data_put_described(data);
+ if (err) return err;
+ // pni_decoder_single has the corresponding exit
+ pn_data_enter(data);
+ }
+ err = pni_decoder_single(decoder, data);
+ if (err) return err;
+ err = pni_decoder_decode_type(decoder, data, code);
+ if (err) return err;
+ } else {
+ *code = next;
+ }
+
+ return 0;
+}
+
+size_t pn_data_siblings(pn_data_t *data);
+
+int pni_decoder_single(pn_decoder_t *decoder, pn_data_t *data)
+{
+ uint8_t code;
+ int err = pni_decoder_decode_type(decoder, data, &code);
+ if (err) return err;
+ err = pni_decoder_decode_value(decoder, data, code);
+ if (err) return err;
+ if (pni_data_parent_type(data) == PN_DESCRIBED && pn_data_siblings(data) > 1) {
+ pn_data_exit(data);
+ }
+ return 0;
+}
+
+ssize_t pn_decoder_decode(pn_decoder_t *decoder, const char *src, size_t size, pn_data_t *dst)
+{
+ decoder->input = src;
+ decoder->size = size;
+ decoder->position = src;
+
+ int err = pni_decoder_single(decoder, dst);
+
+ if (err == PN_UNDERFLOW)
+ return pn_error_format(pn_data_error(dst), PN_UNDERFLOW, "not enough data to decode");
+ if (err) return err;
+
+ return decoder->position - decoder->input;
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/decoder.h
----------------------------------------------------------------------
diff --git a/proton-c/src/core/decoder.h b/proton-c/src/core/decoder.h
new file mode 100644
index 0000000..b7de898
--- /dev/null
+++ b/proton-c/src/core/decoder.h
@@ -0,0 +1,30 @@
+#ifndef _PROTON_DECODER_H
+#define _PROTON_DECODER_H 1
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+typedef struct pn_decoder_t pn_decoder_t;
+
+pn_decoder_t *pn_decoder(void);
+ssize_t pn_decoder_decode(pn_decoder_t *decoder, const char *src, size_t size, pn_data_t *dst);
+
+#endif /* decoder.h */
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/a5850716/proton-c/src/core/dispatch_actions.h
----------------------------------------------------------------------
diff --git a/proton-c/src/core/dispatch_actions.h b/proton-c/src/core/dispatch_actions.h
new file mode 100644
index 0000000..ea2d8b2
--- /dev/null
+++ b/proton-c/src/core/dispatch_actions.h
@@ -0,0 +1,49 @@
+#ifndef _PROTON_DISPATCH_ACTIONS_H
+#define _PROTON_DISPATCH_ACTIONS_H 1
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "dispatcher.h"
+
+#define AMQP_FRAME_TYPE (0)
+#define SASL_FRAME_TYPE (1)
+
+
+/* AMQP actions */
+int pn_do_open(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_begin(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_attach(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_transfer(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_flow(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_disposition(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_detach(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_end(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_close(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+
+/* SASL actions */
+int pn_do_init(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_mechanisms(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_challenge(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_response(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+int pn_do_outcome(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload);
+
+#endif // _PROTON_DISPATCH_ACTIONS_H
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org