You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by jr...@apache.org on 2018/04/05 19:34:14 UTC

[39/51] [partial] qpid-proton git commit: PROTON-1728: Reorganize the source tree

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/src/core/message-internal.h
----------------------------------------------------------------------
diff --git a/c/src/core/message-internal.h b/c/src/core/message-internal.h
new file mode 100644
index 0000000..7b59bb7
--- /dev/null
+++ b/c/src/core/message-internal.h
@@ -0,0 +1,43 @@
+#ifndef CORE_MESSAGE_INTERNAL_H
+#define CORE_MESSAGE_INTERNAL_H
+
+/*
+ * 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/message.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @cond INTERNAL */
+
+/** Construct a message with extra storage */
+PN_EXTERN pn_message_t * pni_message_with_extra(size_t extra);
+
+/** Pointer to extra space allocated by pn_message_with_extra(). */
+PN_EXTERN void* pni_message_get_extra(pn_message_t *msg);
+
+/** @endcond */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CORE_MESSAGE_INTERNAL_H

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/src/core/message.c
----------------------------------------------------------------------
diff --git a/c/src/core/message.c b/c/src/core/message.c
new file mode 100644
index 0000000..8f0bcf7
--- /dev/null
+++ b/c/src/core/message.c
@@ -0,0 +1,897 @@
+/*
+ *
+ * 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 "platform/platform_fmt.h"
+
+#include "max_align.h"
+#include "message-internal.h"
+#include "protocol.h"
+#include "util.h"
+
+#include <proton/object.h>
+#include <proton/codec.h>
+#include <proton/error.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+// message
+
+struct pn_message_t {
+  pn_timestamp_t expiry_time;
+  pn_timestamp_t creation_time;
+  pn_data_t *id;
+  pn_string_t *user_id;
+  pn_string_t *address;
+  pn_string_t *subject;
+  pn_string_t *reply_to;
+  pn_data_t *correlation_id;
+  pn_string_t *content_type;
+  pn_string_t *content_encoding;
+  pn_string_t *group_id;
+  pn_string_t *reply_to_group_id;
+
+  pn_data_t *data;
+  pn_data_t *instructions;
+  pn_data_t *annotations;
+  pn_data_t *properties;
+  pn_data_t *body;
+
+  pn_error_t *error;
+
+  pn_sequence_t group_sequence;
+  pn_millis_t ttl;
+  uint32_t delivery_count;
+
+  uint8_t priority;
+
+  bool durable;
+  bool first_acquirer;
+  bool inferred;
+};
+
+void pn_message_finalize(void *obj)
+{
+  pn_message_t *msg = (pn_message_t *) obj;
+  pn_free(msg->user_id);
+  pn_free(msg->address);
+  pn_free(msg->subject);
+  pn_free(msg->reply_to);
+  pn_free(msg->content_type);
+  pn_free(msg->content_encoding);
+  pn_free(msg->group_id);
+  pn_free(msg->reply_to_group_id);
+  pn_data_free(msg->id);
+  pn_data_free(msg->correlation_id);
+  pn_data_free(msg->data);
+  pn_data_free(msg->instructions);
+  pn_data_free(msg->annotations);
+  pn_data_free(msg->properties);
+  pn_data_free(msg->body);
+  pn_error_free(msg->error);
+}
+
+int pn_message_inspect(void *obj, pn_string_t *dst)
+{
+  pn_message_t *msg = (pn_message_t *) obj;
+  int err = pn_string_addf(dst, "Message{");
+  if (err) return err;
+
+  bool comma = false;
+
+  if (pn_string_get(msg->address)) {
+    err = pn_string_addf(dst, "address=");
+    if (err) return err;
+    err = pn_inspect(msg->address, dst);
+    if (err) return err;
+    err = pn_string_addf(dst, ", ");
+    if (err) return err;
+    comma = true;
+  }
+
+  if (msg->durable) {
+    err = pn_string_addf(dst, "durable=%i, ", msg->durable);
+    if (err) return err;
+    comma = true;
+  }
+
+  if (msg->priority != HEADER_PRIORITY_DEFAULT) {
+    err = pn_string_addf(dst, "priority=%i, ", msg->priority);
+    if (err) return err;
+    comma = true;
+  }
+
+  if (msg->ttl) {
+    err = pn_string_addf(dst, "ttl=%" PRIu32 ", ", msg->ttl);
+    if (err) return err;
+    comma = true;
+  }
+
+  if (msg->first_acquirer) {
+    err = pn_string_addf(dst, "first_acquirer=%i, ", msg->first_acquirer);
+    if (err) return err;
+    comma = true;
+  }
+
+  if (msg->delivery_count) {
+    err = pn_string_addf(dst, "delivery_count=%" PRIu32 ", ", msg->delivery_count);
+    if (err) return err;
+    comma = true;
+  }
+
+  if (pn_data_size(msg->id)) {
+    err = pn_string_addf(dst, "id=");
+    if (err) return err;
+    err = pn_inspect(msg->id, dst);
+    if (err) return err;
+    err = pn_string_addf(dst, ", ");
+    if (err) return err;
+    comma = true;
+  }
+
+  if (pn_string_get(msg->user_id)) {
+    err = pn_string_addf(dst, "user_id=");
+    if (err) return err;
+    err = pn_inspect(msg->user_id, dst);
+    if (err) return err;
+    err = pn_string_addf(dst, ", ");
+    if (err) return err;
+    comma = true;
+  }
+
+  if (pn_string_get(msg->subject)) {
+    err = pn_string_addf(dst, "subject=");
+    if (err) return err;
+    err = pn_inspect(msg->subject, dst);
+    if (err) return err;
+    err = pn_string_addf(dst, ", ");
+    if (err) return err;
+    comma = true;
+  }
+
+  if (pn_string_get(msg->reply_to)) {
+    err = pn_string_addf(dst, "reply_to=");
+    if (err) return err;
+    err = pn_inspect(msg->reply_to, dst);
+    if (err) return err;
+    err = pn_string_addf(dst, ", ");
+    if (err) return err;
+    comma = true;
+  }
+
+  if (pn_data_size(msg->correlation_id)) {
+    err = pn_string_addf(dst, "correlation_id=");
+    if (err) return err;
+    err = pn_inspect(msg->correlation_id, dst);
+    if (err) return err;
+    err = pn_string_addf(dst, ", ");
+    if (err) return err;
+    comma = true;
+  }
+
+  if (pn_string_get(msg->content_type)) {
+    err = pn_string_addf(dst, "content_type=");
+    if (err) return err;
+    err = pn_inspect(msg->content_type, dst);
+    if (err) return err;
+    err = pn_string_addf(dst, ", ");
+    if (err) return err;
+    comma = true;
+  }
+
+  if (pn_string_get(msg->content_encoding)) {
+    err = pn_string_addf(dst, "content_encoding=");
+    if (err) return err;
+    err = pn_inspect(msg->content_encoding, dst);
+    if (err) return err;
+    err = pn_string_addf(dst, ", ");
+    if (err) return err;
+    comma = true;
+  }
+
+  if (msg->expiry_time) {
+    err = pn_string_addf(dst, "expiry_time=%" PRIi64 ", ", msg->expiry_time);
+    if (err) return err;
+    comma = true;
+  }
+
+  if (msg->creation_time) {
+    err = pn_string_addf(dst, "creation_time=%" PRIi64 ", ", msg->creation_time);
+    if (err) return err;
+    comma = true;
+  }
+
+  if (pn_string_get(msg->group_id)) {
+    err = pn_string_addf(dst, "group_id=");
+    if (err) return err;
+    err = pn_inspect(msg->group_id, dst);
+    if (err) return err;
+    err = pn_string_addf(dst, ", ");
+    if (err) return err;
+    comma = true;
+  }
+
+  if (msg->group_sequence) {
+    err = pn_string_addf(dst, "group_sequence=%" PRIi32 ", ", msg->group_sequence);
+    if (err) return err;
+    comma = true;
+  }
+
+  if (pn_string_get(msg->reply_to_group_id)) {
+    err = pn_string_addf(dst, "reply_to_group_id=");
+    if (err) return err;
+    err = pn_inspect(msg->reply_to_group_id, dst);
+    if (err) return err;
+    err = pn_string_addf(dst, ", ");
+    if (err) return err;
+    comma = true;
+  }
+
+  if (msg->inferred) {
+    err = pn_string_addf(dst, "inferred=%i, ", msg->inferred);
+    if (err) return err;
+    comma = true;
+  }
+
+  if (pn_data_size(msg->instructions)) {
+    err = pn_string_addf(dst, "instructions=");
+    if (err) return err;
+    err = pn_inspect(msg->instructions, dst);
+    if (err) return err;
+    err = pn_string_addf(dst, ", ");
+    if (err) return err;
+    comma = true;
+  }
+
+  if (pn_data_size(msg->annotations)) {
+    err = pn_string_addf(dst, "annotations=");
+    if (err) return err;
+    err = pn_inspect(msg->annotations, dst);
+    if (err) return err;
+    err = pn_string_addf(dst, ", ");
+    if (err) return err;
+    comma = true;
+  }
+
+  if (pn_data_size(msg->properties)) {
+    err = pn_string_addf(dst, "properties=");
+    if (err) return err;
+    err = pn_inspect(msg->properties, dst);
+    if (err) return err;
+    err = pn_string_addf(dst, ", ");
+    if (err) return err;
+    comma = true;
+  }
+
+  if (pn_data_size(msg->body)) {
+    err = pn_string_addf(dst, "body=");
+    if (err) return err;
+    err = pn_inspect(msg->body, dst);
+    if (err) return err;
+    err = pn_string_addf(dst, ", ");
+    if (err) return err;
+    comma = true;
+  }
+
+  if (comma) {
+    int err = pn_string_resize(dst, pn_string_size(dst) - 2);
+    if (err) return err;
+  }
+
+  return pn_string_addf(dst, "}");
+}
+
+#define pn_message_initialize NULL
+#define pn_message_hashcode NULL
+#define pn_message_compare NULL
+
+static pn_message_t *pni_message_new(size_t size)
+{
+  static const pn_class_t clazz = PN_CLASS(pn_message);
+  pn_message_t *msg = (pn_message_t *) pn_class_new(&clazz, size);
+  msg->durable = false;
+  msg->priority = HEADER_PRIORITY_DEFAULT;
+  msg->ttl = 0;
+  msg->first_acquirer = false;
+  msg->delivery_count = 0;
+  msg->id = pn_data(1);
+  msg->user_id = pn_string(NULL);
+  msg->address = pn_string(NULL);
+  msg->subject = pn_string(NULL);
+  msg->reply_to = pn_string(NULL);
+  msg->correlation_id = pn_data(1);
+  msg->content_type = pn_string(NULL);
+  msg->content_encoding = pn_string(NULL);
+  msg->expiry_time = 0;
+  msg->creation_time = 0;
+  msg->group_id = pn_string(NULL);
+  msg->group_sequence = 0;
+  msg->reply_to_group_id = pn_string(NULL);
+
+  msg->inferred = false;
+  msg->data = pn_data(16);
+  msg->instructions = pn_data(16);
+  msg->annotations = pn_data(16);
+  msg->properties = pn_data(16);
+  msg->body = pn_data(16);
+
+  msg->error = pn_error();
+  return msg;
+}
+
+pn_message_t *pn_message() {
+  return pni_message_new(sizeof(pn_message_t));
+}
+
+/* Maximally aligned message to make extra storage safe for any type */
+typedef union {
+  pn_message_t m;
+  pn_max_align_t a;
+}  pni_aligned_message_t;
+
+pn_message_t *pni_message_with_extra(size_t extra) {
+  return pni_message_new(sizeof(pni_aligned_message_t) + extra);
+}
+
+void *pni_message_get_extra(pn_message_t *m) {
+  return ((char*)m) + sizeof(pni_aligned_message_t);
+}
+
+void pn_message_free(pn_message_t *msg)
+{
+  pn_free(msg);
+}
+
+void pn_message_clear(pn_message_t *msg)
+{
+  msg->durable = false;
+  msg->priority = HEADER_PRIORITY_DEFAULT;
+  msg->ttl = 0;
+  msg->first_acquirer = false;
+  msg->delivery_count = 0;
+  pn_data_clear(msg->id);
+  pn_string_clear(msg->user_id);
+  pn_string_clear(msg->address);
+  pn_string_clear(msg->subject);
+  pn_string_clear(msg->reply_to);
+  pn_data_clear(msg->correlation_id);
+  pn_string_clear(msg->content_type);
+  pn_string_clear(msg->content_encoding);
+  msg->expiry_time = 0;
+  msg->creation_time = 0;
+  pn_string_clear(msg->group_id);
+  msg->group_sequence = 0;
+  pn_string_clear(msg->reply_to_group_id);
+  msg->inferred = false;
+  pn_data_clear(msg->data);
+  pn_data_clear(msg->instructions);
+  pn_data_clear(msg->annotations);
+  pn_data_clear(msg->properties);
+  pn_data_clear(msg->body);
+}
+
+int pn_message_errno(pn_message_t *msg)
+{
+  assert(msg);
+  return pn_error_code(msg->error);
+}
+
+pn_error_t *pn_message_error(pn_message_t *msg)
+{
+  assert(msg);
+  return msg->error;
+}
+
+bool pn_message_is_inferred(pn_message_t *msg)
+{
+  assert(msg);
+  return msg->inferred;
+}
+
+int pn_message_set_inferred(pn_message_t *msg, bool inferred)
+{
+  assert(msg);
+  msg->inferred = inferred;
+  return 0;
+}
+
+bool pn_message_is_durable(pn_message_t *msg)
+{
+  assert(msg);
+  return msg->durable;
+}
+int pn_message_set_durable(pn_message_t *msg, bool durable)
+{
+  assert(msg);
+  msg->durable = durable;
+  return 0;
+}
+
+
+uint8_t pn_message_get_priority(pn_message_t *msg)
+{
+  assert(msg);
+  return msg->priority;
+}
+int pn_message_set_priority(pn_message_t *msg, uint8_t priority)
+{
+  assert(msg);
+  msg->priority = priority;
+  return 0;
+}
+
+pn_millis_t pn_message_get_ttl(pn_message_t *msg)
+{
+  assert(msg);
+  return msg->ttl;
+}
+int pn_message_set_ttl(pn_message_t *msg, pn_millis_t ttl)
+{
+  assert(msg);
+  msg->ttl = ttl;
+  return 0;
+}
+
+bool pn_message_is_first_acquirer(pn_message_t *msg)
+{
+  assert(msg);
+  return msg->first_acquirer;
+}
+int pn_message_set_first_acquirer(pn_message_t *msg, bool first)
+{
+  assert(msg);
+  msg->first_acquirer = first;
+  return 0;
+}
+
+uint32_t pn_message_get_delivery_count(pn_message_t *msg)
+{
+  assert(msg);
+  return msg->delivery_count;
+}
+int pn_message_set_delivery_count(pn_message_t *msg, uint32_t count)
+{
+  assert(msg);
+  msg->delivery_count = count;
+  return 0;
+}
+
+pn_data_t *pn_message_id(pn_message_t *msg)
+{
+  assert(msg);
+  return msg->id;
+}
+pn_atom_t pn_message_get_id(pn_message_t *msg)
+{
+  assert(msg);
+  return pn_data_get_atom(msg->id);
+}
+int pn_message_set_id(pn_message_t *msg, pn_atom_t id)
+{
+  assert(msg);
+  pn_data_rewind(msg->id);
+  return pn_data_put_atom(msg->id, id);
+}
+
+static pn_bytes_t pn_string_get_bytes(pn_string_t *string)
+{
+  return pn_bytes(pn_string_size(string), (char *) pn_string_get(string));
+}
+
+static int pn_string_set_bytes(pn_string_t *string, pn_bytes_t bytes)
+{
+  return pn_string_setn(string, bytes.start, bytes.size);
+}
+
+pn_bytes_t pn_message_get_user_id(pn_message_t *msg)
+{
+  assert(msg);
+  return pn_string_get_bytes(msg->user_id);
+}
+int pn_message_set_user_id(pn_message_t *msg, pn_bytes_t user_id)
+{
+  assert(msg);
+  return pn_string_set_bytes(msg->user_id, user_id);
+}
+
+const char *pn_message_get_address(pn_message_t *msg)
+{
+  assert(msg);
+  return pn_string_get(msg->address);
+}
+int pn_message_set_address(pn_message_t *msg, const char *address)
+{
+  assert(msg);
+  return pn_string_set(msg->address, address);
+}
+
+const char *pn_message_get_subject(pn_message_t *msg)
+{
+  assert(msg);
+  return pn_string_get(msg->subject);
+}
+int pn_message_set_subject(pn_message_t *msg, const char *subject)
+{
+  assert(msg);
+  return pn_string_set(msg->subject, subject);
+}
+
+const char *pn_message_get_reply_to(pn_message_t *msg)
+{
+  assert(msg);
+  return pn_string_get(msg->reply_to);
+}
+int pn_message_set_reply_to(pn_message_t *msg, const char *reply_to)
+{
+  assert(msg);
+  return pn_string_set(msg->reply_to, reply_to);
+}
+
+pn_data_t *pn_message_correlation_id(pn_message_t *msg)
+{
+  assert(msg);
+  return msg->correlation_id;
+}
+pn_atom_t pn_message_get_correlation_id(pn_message_t *msg)
+{
+  assert(msg);
+  return pn_data_get_atom(msg->correlation_id);
+}
+int pn_message_set_correlation_id(pn_message_t *msg, pn_atom_t atom)
+{
+  assert(msg);
+  pn_data_rewind(msg->correlation_id);
+  return pn_data_put_atom(msg->correlation_id, atom);
+}
+
+const char *pn_message_get_content_type(pn_message_t *msg)
+{
+  assert(msg);
+  return pn_string_get(msg->content_type);
+}
+int pn_message_set_content_type(pn_message_t *msg, const char *type)
+{
+  assert(msg);
+  return pn_string_set(msg->content_type, type);
+}
+
+const char *pn_message_get_content_encoding(pn_message_t *msg)
+{
+  assert(msg);
+  return pn_string_get(msg->content_encoding);
+}
+int pn_message_set_content_encoding(pn_message_t *msg, const char *encoding)
+{
+  assert(msg);
+  return pn_string_set(msg->content_encoding, encoding);
+}
+
+pn_timestamp_t pn_message_get_expiry_time(pn_message_t *msg)
+{
+  assert(msg);
+  return msg->expiry_time;
+}
+int pn_message_set_expiry_time(pn_message_t *msg, pn_timestamp_t time)
+{
+  assert(msg);
+  msg->expiry_time = time;
+  return 0;
+}
+
+pn_timestamp_t pn_message_get_creation_time(pn_message_t *msg)
+{
+  assert(msg);
+  return msg->creation_time;
+}
+int pn_message_set_creation_time(pn_message_t *msg, pn_timestamp_t time)
+{
+  assert(msg);
+  msg->creation_time = time;
+  return 0;
+}
+
+const char *pn_message_get_group_id(pn_message_t *msg)
+{
+  assert(msg);
+  return pn_string_get(msg->group_id);
+}
+int pn_message_set_group_id(pn_message_t *msg, const char *group_id)
+{
+  assert(msg);
+  return pn_string_set(msg->group_id, group_id);
+}
+
+pn_sequence_t pn_message_get_group_sequence(pn_message_t *msg)
+{
+  assert(msg);
+  return msg->group_sequence;
+}
+int pn_message_set_group_sequence(pn_message_t *msg, pn_sequence_t n)
+{
+  assert(msg);
+  msg->group_sequence = n;
+  return 0;
+}
+
+const char *pn_message_get_reply_to_group_id(pn_message_t *msg)
+{
+  assert(msg);
+  return pn_string_get(msg->reply_to_group_id);
+}
+int pn_message_set_reply_to_group_id(pn_message_t *msg, const char *reply_to_group_id)
+{
+  assert(msg);
+  return pn_string_set(msg->reply_to_group_id, reply_to_group_id);
+}
+
+int pn_message_decode(pn_message_t *msg, const char *bytes, size_t size)
+{
+  assert(msg && bytes && size);
+
+  pn_message_clear(msg);
+
+  while (size) {
+    pn_data_clear(msg->data);
+    ssize_t used = pn_data_decode(msg->data, bytes, size);
+    if (used < 0)
+        return pn_error_format(msg->error, used, "data error: %s",
+                               pn_error_text(pn_data_error(msg->data)));
+    size -= used;
+    bytes += used;
+    bool scanned;
+    uint64_t desc;
+    int err = pn_data_scan(msg->data, "D?L.", &scanned, &desc);
+    if (err) return pn_error_format(msg->error, err, "data error: %s",
+                                    pn_error_text(pn_data_error(msg->data)));
+    if (!scanned) {
+      desc = 0;
+    }
+
+    pn_data_rewind(msg->data);
+    pn_data_next(msg->data);
+    pn_data_enter(msg->data);
+    pn_data_next(msg->data);
+
+    switch (desc) {
+    case HEADER: {
+      bool priority_q;
+      uint8_t priority;
+      err = pn_data_scan(msg->data, "D.[o?BIoI]",
+                         &msg->durable,
+                         &priority_q, &priority,
+                         &msg->ttl,
+                         &msg->first_acquirer,
+                         &msg->delivery_count);
+      if (err) return pn_error_format(msg->error, err, "data error: %s",
+                                      pn_error_text(pn_data_error(msg->data)));
+      msg->priority = priority_q ? priority : HEADER_PRIORITY_DEFAULT;
+      break;
+    }
+    case PROPERTIES:
+      {
+        pn_bytes_t user_id, address, subject, reply_to, ctype, cencoding,
+          group_id, reply_to_group_id;
+        pn_data_clear(msg->id);
+        pn_data_clear(msg->correlation_id);
+        err = pn_data_scan(msg->data, "D.[CzSSSCssttSIS]", msg->id,
+                           &user_id, &address, &subject, &reply_to,
+                           msg->correlation_id, &ctype, &cencoding,
+                           &msg->expiry_time, &msg->creation_time, &group_id,
+                           &msg->group_sequence, &reply_to_group_id);
+        if (err) return pn_error_format(msg->error, err, "data error: %s",
+                                        pn_error_text(pn_data_error(msg->data)));
+        err = pn_string_set_bytes(msg->user_id, user_id);
+        if (err) return pn_error_format(msg->error, err, "error setting user_id");
+        err = pn_string_setn(msg->address, address.start, address.size);
+        if (err) return pn_error_format(msg->error, err, "error setting address");
+        err = pn_string_setn(msg->subject, subject.start, subject.size);
+        if (err) return pn_error_format(msg->error, err, "error setting subject");
+        err = pn_string_setn(msg->reply_to, reply_to.start, reply_to.size);
+        if (err) return pn_error_format(msg->error, err, "error setting reply_to");
+        err = pn_string_setn(msg->content_type, ctype.start, ctype.size);
+        if (err) return pn_error_format(msg->error, err, "error setting content_type");
+        err = pn_string_setn(msg->content_encoding, cencoding.start,
+                             cencoding.size);
+        if (err) return pn_error_format(msg->error, err, "error setting content_encoding");
+        err = pn_string_setn(msg->group_id, group_id.start, group_id.size);
+        if (err) return pn_error_format(msg->error, err, "error setting group_id");
+        err = pn_string_setn(msg->reply_to_group_id, reply_to_group_id.start,
+                             reply_to_group_id.size);
+        if (err) return pn_error_format(msg->error, err, "error setting reply_to_group_id");
+      }
+      break;
+    case DELIVERY_ANNOTATIONS:
+      pn_data_narrow(msg->data);
+      err = pn_data_copy(msg->instructions, msg->data);
+      if (err) return err;
+      break;
+    case MESSAGE_ANNOTATIONS:
+      pn_data_narrow(msg->data);
+      err = pn_data_copy(msg->annotations, msg->data);
+      if (err) return err;
+      break;
+    case APPLICATION_PROPERTIES:
+      pn_data_narrow(msg->data);
+      err = pn_data_copy(msg->properties, msg->data);
+      if (err) return err;
+      break;
+    case DATA:
+    case AMQP_SEQUENCE:
+    case AMQP_VALUE:
+      pn_data_narrow(msg->data);
+      err = pn_data_copy(msg->body, msg->data);
+      if (err) return err;
+      break;
+    case FOOTER:
+      break;
+    default:
+      err = pn_data_copy(msg->body, msg->data);
+      if (err) return err;
+      break;
+    }
+  }
+
+  pn_data_clear(msg->data);
+  return 0;
+}
+
+int pn_message_encode(pn_message_t *msg, char *bytes, size_t *size)
+{
+  if (!msg || !bytes || !size || !*size) return PN_ARG_ERR;
+  pn_data_clear(msg->data);
+  pn_message_data(msg, msg->data);
+  size_t remaining = *size;
+  ssize_t encoded = pn_data_encode(msg->data, bytes, remaining);
+  if (encoded < 0) {
+    if (encoded == PN_OVERFLOW) {
+      return encoded;
+    } else {
+      return pn_error_format(msg->error, encoded, "data error: %s",
+                             pn_error_text(pn_data_error(msg->data)));
+    }
+  }
+  bytes += encoded;
+  remaining -= encoded;
+  *size -= remaining;
+  pn_data_clear(msg->data);
+  return 0;
+}
+
+int pn_message_data(pn_message_t *msg, pn_data_t *data)
+{
+  pn_data_clear(data);
+  int err = pn_data_fill(data, "DL[?o?B?I?o?I]", HEADER,
+                         msg->durable, msg->durable,
+                         msg->priority!=HEADER_PRIORITY_DEFAULT, msg->priority,
+                         (bool)msg->ttl, msg->ttl,
+                         msg->first_acquirer, msg->first_acquirer,
+                         (bool)msg->delivery_count, msg->delivery_count);
+  if (err)
+    return pn_error_format(msg->error, err, "data error: %s",
+                           pn_error_text(pn_data_error(data)));
+
+  if (pn_data_size(msg->instructions)) {
+    pn_data_put_described(data);
+    pn_data_enter(data);
+    pn_data_put_ulong(data, DELIVERY_ANNOTATIONS);
+    pn_data_rewind(msg->instructions);
+    err = pn_data_append(data, msg->instructions);
+    if (err)
+      return pn_error_format(msg->error, err, "data error: %s",
+                             pn_error_text(pn_data_error(data)));
+    pn_data_exit(data);
+  }
+
+  if (pn_data_size(msg->annotations)) {
+    pn_data_put_described(data);
+    pn_data_enter(data);
+    pn_data_put_ulong(data, MESSAGE_ANNOTATIONS);
+    pn_data_rewind(msg->annotations);
+    err = pn_data_append(data, msg->annotations);
+    if (err)
+      return pn_error_format(msg->error, err, "data error: %s",
+                             pn_error_text(pn_data_error(data)));
+    pn_data_exit(data);
+  }
+
+  err = pn_data_fill(data, "DL[CzSSSCss?t?tS?IS]", PROPERTIES,
+                     msg->id,
+                     pn_string_size(msg->user_id), pn_string_get(msg->user_id),
+                     pn_string_get(msg->address),
+                     pn_string_get(msg->subject),
+                     pn_string_get(msg->reply_to),
+                     msg->correlation_id,
+                     pn_string_get(msg->content_type),
+                     pn_string_get(msg->content_encoding),
+                     (bool)msg->expiry_time, msg->expiry_time,
+                     (bool)msg->creation_time, msg->creation_time,
+                     pn_string_get(msg->group_id),
+                     /*
+                      * As a heuristic, null out group_sequence if there is no group_id and
+                      * group_sequence is 0. In this case it is extremely unlikely we want
+                      * group semantics
+                      */
+                     (bool)pn_string_get(msg->group_id) || (bool)msg->group_sequence , msg->group_sequence,
+                     pn_string_get(msg->reply_to_group_id));
+  if (err)
+    return pn_error_format(msg->error, err, "data error: %s",
+                           pn_error_text(pn_data_error(data)));
+
+  if (pn_data_size(msg->properties)) {
+    pn_data_put_described(data);
+    pn_data_enter(data);
+    pn_data_put_ulong(data, APPLICATION_PROPERTIES);
+    pn_data_rewind(msg->properties);
+    err = pn_data_append(data, msg->properties);
+    if (err)
+      return pn_error_format(msg->error, err, "data error: %s",
+                             pn_error_text(pn_data_error(data)));
+    pn_data_exit(data);
+  }
+
+  if (pn_data_size(msg->body)) {
+    pn_data_rewind(msg->body);
+    pn_data_next(msg->body);
+    pn_type_t body_type = pn_data_type(msg->body);
+    pn_data_rewind(msg->body);
+
+    pn_data_put_described(data);
+    pn_data_enter(data);
+    if (msg->inferred) {
+      switch (body_type) {
+      case PN_BINARY:
+        pn_data_put_ulong(data, DATA);
+        break;
+      case PN_LIST:
+        pn_data_put_ulong(data, AMQP_SEQUENCE);
+        break;
+      default:
+        pn_data_put_ulong(data, AMQP_VALUE);
+        break;
+      }
+    } else {
+      pn_data_put_ulong(data, AMQP_VALUE);
+    }
+    pn_data_append(data, msg->body);
+  }
+  return 0;
+}
+
+pn_data_t *pn_message_instructions(pn_message_t *msg)
+{
+  return msg ? msg->instructions : NULL;
+}
+
+pn_data_t *pn_message_annotations(pn_message_t *msg)
+{
+  return msg ? msg->annotations : NULL;
+}
+
+pn_data_t *pn_message_properties(pn_message_t *msg)
+{
+  return msg ? msg->properties : NULL;
+}
+
+pn_data_t *pn_message_body(pn_message_t *msg)
+{
+  return msg ? msg->body : NULL;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/src/core/object/iterator.c
----------------------------------------------------------------------
diff --git a/c/src/core/object/iterator.c b/c/src/core/object/iterator.c
new file mode 100644
index 0000000..61b3b8e
--- /dev/null
+++ b/c/src/core/object/iterator.c
@@ -0,0 +1,78 @@
+/*
+ *
+ * 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 <stdlib.h>
+#include <assert.h>
+
+struct pn_iterator_t {
+  pn_iterator_next_t next;
+  size_t size;
+  void *state;
+};
+
+static void pn_iterator_initialize(void *object)
+{
+  pn_iterator_t *it = (pn_iterator_t *) object;
+  it->next = NULL;
+  it->size = 0;
+  it->state = NULL;
+}
+
+static void pn_iterator_finalize(void *object)
+{
+  pn_iterator_t *it = (pn_iterator_t *) object;
+  free(it->state);
+}
+
+#define CID_pn_iterator CID_pn_object
+#define pn_iterator_hashcode NULL
+#define pn_iterator_compare NULL
+#define pn_iterator_inspect NULL
+
+pn_iterator_t *pn_iterator()
+{
+  static const pn_class_t clazz = PN_CLASS(pn_iterator);
+  pn_iterator_t *it = (pn_iterator_t *) pn_class_new(&clazz, sizeof(pn_iterator_t));
+  return it;
+}
+
+void  *pn_iterator_start(pn_iterator_t *iterator, pn_iterator_next_t next,
+                         size_t size) {
+  assert(iterator);
+  assert(next);
+  iterator->next = next;
+  if (iterator->size < size) {
+    iterator->state = realloc(iterator->state, size);
+  }
+  return iterator->state;
+}
+
+void *pn_iterator_next(pn_iterator_t *iterator) {
+  assert(iterator);
+  if (iterator->next) {
+    void *result = iterator->next(iterator->state);
+    if (!result) iterator->next = NULL;
+    return result;
+  } else {
+    return NULL;
+  }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/src/core/object/list.c
----------------------------------------------------------------------
diff --git a/c/src/core/object/list.c b/c/src/core/object/list.c
new file mode 100644
index 0000000..76c70d2
--- /dev/null
+++ b/c/src/core/object/list.c
@@ -0,0 +1,267 @@
+/*
+ *
+ * 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 <stdlib.h>
+#include <assert.h>
+
+struct pn_list_t {
+  const pn_class_t *clazz;
+  size_t capacity;
+  size_t size;
+  void **elements;
+};
+
+size_t pn_list_size(pn_list_t *list)
+{
+  assert(list);
+  return list->size;
+}
+
+void *pn_list_get(pn_list_t *list, int index)
+{
+  assert(list); assert(list->size);
+  return list->elements[index % list->size];
+}
+
+void pn_list_set(pn_list_t *list, int index, void *value)
+{
+  assert(list); assert(list->size);
+  void *old = list->elements[index % list->size];
+  pn_class_decref(list->clazz, old);
+  list->elements[index % list->size] = value;
+  pn_class_incref(list->clazz, value);
+}
+
+static void pni_list_ensure(pn_list_t *list, size_t capacity)
+{
+  assert(list);
+  if (list->capacity < capacity) {
+    size_t newcap = list->capacity;
+    while (newcap < capacity) { newcap *= 2; }
+    list->elements = (void **) realloc(list->elements, newcap * sizeof(void *));
+    assert(list->elements);
+    list->capacity = newcap;
+  }
+}
+
+int pn_list_add(pn_list_t *list, void *value)
+{
+  assert(list);
+  pni_list_ensure(list, list->size + 1);
+  list->elements[list->size++] = value;
+  pn_class_incref(list->clazz, value);
+  return 0;
+}
+
+void *pn_list_pop(pn_list_t *list)
+{
+  assert(list);
+  if (list->size) {
+    return list->elements[--list->size];
+  } else {
+    return NULL;
+  }
+}
+
+ssize_t pn_list_index(pn_list_t *list, void *value)
+{
+  for (size_t i = 0; i < list->size; i++) {
+    if (pn_class_equals(list->clazz, list->elements[i], value)) {
+      return i;
+    }
+  }
+
+  return -1;
+}
+
+bool pn_list_remove(pn_list_t *list, void *value)
+{
+  assert(list);
+  ssize_t idx = pn_list_index(list, value);
+  if (idx < 0) {
+    return false;
+  } else {
+    pn_list_del(list, idx, 1);
+  }
+
+  return true;
+}
+
+void pn_list_del(pn_list_t *list, int index, int n)
+{
+  assert(list);
+  if (!list->size) { return; }
+  index %= list->size;
+
+  for (int i = 0; i < n; i++) {
+    pn_class_decref(list->clazz, list->elements[index + i]);
+  }
+
+  size_t slide = list->size - (index + n);
+  for (size_t i = 0; i < slide; i++) {
+    list->elements[index + i] = list->elements[index + n + i];
+  }
+
+  list->size -= n;
+}
+
+void pn_list_clear(pn_list_t *list)
+{
+  assert(list);
+  pn_list_del(list, 0, list->size);
+}
+
+void pn_list_minpush(pn_list_t *list, void *value)
+{
+  assert(list);
+  pn_list_add(list, value);
+  // we use one based indexing for the heap
+  void **heap = list->elements - 1;
+  int now = list->size;
+  while (now > 1 && pn_class_compare(list->clazz, heap[now/2], value) > 0) {
+    heap[now] = heap[now/2];
+    now /= 2;
+  }
+  heap[now] = value;
+}
+
+void *pn_list_minpop(pn_list_t *list)
+{
+  assert(list);
+  // we use one based indexing for the heap
+  void **heap = list->elements - 1;
+  void *min = heap[1];
+  void *last = pn_list_pop(list);
+  int size = pn_list_size(list);
+  int now, child;
+  for (now = 1; now*2 <= size; now = child) {
+    child = now*2;
+    if (child != size && pn_class_compare(list->clazz, heap[child], heap[child + 1]) > 0) {
+      child++;
+    }
+    if (pn_class_compare(list->clazz, last, heap[child]) > 0) {
+      heap[now] = heap[child];
+    } else {
+      break;
+    }
+  }
+  heap[now] = last;
+  return min;
+}
+
+typedef struct {
+  pn_list_t *list;
+  size_t index;
+} pni_list_iter_t;
+
+static void *pni_list_next(void *ctx)
+{
+  pni_list_iter_t *iter = (pni_list_iter_t *) ctx;
+  if (iter->index < pn_list_size(iter->list)) {
+    return pn_list_get(iter->list, iter->index++);
+  } else {
+    return NULL;
+  }
+}
+
+void pn_list_iterator(pn_list_t *list, pn_iterator_t *iter)
+{
+  pni_list_iter_t *liter = (pni_list_iter_t *) pn_iterator_start(iter, pni_list_next, sizeof(pni_list_iter_t));
+  liter->list = list;
+  liter->index = 0;
+}
+
+static void pn_list_finalize(void *object)
+{
+  assert(object);
+  pn_list_t *list = (pn_list_t *) object;
+  for (size_t i = 0; i < list->size; i++) {
+    pn_class_decref(list->clazz, pn_list_get(list, i));
+  }
+  free(list->elements);
+}
+
+static uintptr_t pn_list_hashcode(void *object)
+{
+  assert(object);
+  pn_list_t *list = (pn_list_t *) object;
+  uintptr_t hash = 1;
+
+  for (size_t i = 0; i < list->size; i++) {
+    hash = hash * 31 + pn_hashcode(pn_list_get(list, i));
+  }
+
+  return hash;
+}
+
+static intptr_t pn_list_compare(void *oa, void *ob)
+{
+  assert(oa); assert(ob);
+  pn_list_t *a = (pn_list_t *) oa;
+  pn_list_t *b = (pn_list_t *) ob;
+
+  size_t na = pn_list_size(a);
+  size_t nb = pn_list_size(b);
+  if (na != nb) {
+    return nb - na;
+  } else {
+    for (size_t i = 0; i < na; i++) {
+      intptr_t delta = pn_compare(pn_list_get(a, i), pn_list_get(b, i));
+      if (delta) return delta;
+    }
+  }
+
+  return 0;
+}
+
+static int pn_list_inspect(void *obj, pn_string_t *dst)
+{
+  assert(obj);
+  pn_list_t *list = (pn_list_t *) obj;
+  int err = pn_string_addf(dst, "[");
+  if (err) return err;
+  size_t n = pn_list_size(list);
+  for (size_t i = 0; i < n; i++) {
+    if (i > 0) {
+      err = pn_string_addf(dst, ", ");
+      if (err) return err;
+    }
+    err = pn_class_inspect(list->clazz, pn_list_get(list, i), dst);
+    if (err) return err;
+  }
+  return pn_string_addf(dst, "]");
+}
+
+#define pn_list_initialize NULL
+
+pn_list_t *pn_list(const pn_class_t *clazz, size_t capacity)
+{
+  static const pn_class_t list_clazz = PN_CLASS(pn_list);
+
+  pn_list_t *list = (pn_list_t *) pn_class_new(&list_clazz, sizeof(pn_list_t));
+  list->clazz = clazz;
+  list->capacity = capacity ? capacity : 16;
+  list->elements = (void **) malloc(list->capacity * sizeof(void *));
+  list->size = 0;
+  return list;
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/src/core/object/map.c
----------------------------------------------------------------------
diff --git a/c/src/core/object/map.c b/c/src/core/object/map.c
new file mode 100644
index 0000000..cd38f19
--- /dev/null
+++ b/c/src/core/object/map.c
@@ -0,0 +1,461 @@
+/*
+ *
+ * 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 <stdlib.h>
+#include <assert.h>
+
+#define PNI_ENTRY_FREE (0)
+#define PNI_ENTRY_LINK (1)
+#define PNI_ENTRY_TAIL (2)
+
+typedef struct {
+  void *key;
+  void *value;
+  size_t next;
+  uint8_t state;
+} pni_entry_t;
+
+struct pn_map_t {
+  const pn_class_t *key;
+  const pn_class_t *value;
+  pni_entry_t *entries;
+  size_t capacity;
+  size_t addressable;
+  size_t size;
+  uintptr_t (*hashcode)(void *key);
+  bool (*equals)(void *a, void *b);
+  float load_factor;
+};
+
+static void pn_map_finalize(void *object)
+{
+  pn_map_t *map = (pn_map_t *) object;
+
+  for (size_t i = 0; i < map->capacity; i++) {
+    if (map->entries[i].state != PNI_ENTRY_FREE) {
+      pn_class_decref(map->key, map->entries[i].key);
+      pn_class_decref(map->value, map->entries[i].value);
+    }
+  }
+
+  free(map->entries);
+}
+
+static uintptr_t pn_map_hashcode(void *object)
+{
+  pn_map_t *map = (pn_map_t *) object;
+
+  uintptr_t hashcode = 0;
+
+  for (size_t i = 0; i < map->capacity; i++) {
+    if (map->entries[i].state != PNI_ENTRY_FREE) {
+      void *key = map->entries[i].key;
+      void *value = map->entries[i].value;
+      hashcode += pn_hashcode(key) ^ pn_hashcode(value);
+    }
+  }
+
+  return hashcode;
+}
+
+static void pni_map_allocate(pn_map_t *map)
+{
+  map->entries = (pni_entry_t *) malloc(map->capacity * sizeof (pni_entry_t));
+  if (map->entries != NULL) {
+    for (size_t i = 0; i < map->capacity; i++) {
+      map->entries[i].key = NULL;
+      map->entries[i].value = NULL;
+      map->entries[i].next = 0;
+      map->entries[i].state = PNI_ENTRY_FREE;
+    }
+  }
+  map->size = 0;
+}
+
+static int pn_map_inspect(void *obj, pn_string_t *dst)
+{
+  assert(obj);
+  pn_map_t *map = (pn_map_t *) obj;
+  int err = pn_string_addf(dst, "{");
+  if (err) return err;
+  pn_handle_t entry = pn_map_head(map);
+  bool first = true;
+  while (entry) {
+    if (first) {
+      first = false;
+    } else {
+      err = pn_string_addf(dst, ", ");
+      if (err) return err;
+    }
+    err = pn_class_inspect(map->key, pn_map_key(map, entry), dst);
+    if (err) return err;
+    err = pn_string_addf(dst, ": ");
+    if (err) return err;
+    err = pn_class_inspect(map->value, pn_map_value(map, entry), dst);
+    if (err) return err;
+    entry = pn_map_next(map, entry);
+  }
+  return pn_string_addf(dst, "}");
+}
+
+#define pn_map_initialize NULL
+#define pn_map_compare NULL
+
+pn_map_t *pn_map(const pn_class_t *key, const pn_class_t *value,
+                 size_t capacity, float load_factor)
+{
+  static const pn_class_t clazz = PN_CLASS(pn_map);
+
+  pn_map_t *map = (pn_map_t *) pn_class_new(&clazz, sizeof(pn_map_t));
+  map->key = key;
+  map->value = value;
+  map->capacity = capacity ? capacity : 16;
+  map->addressable = (size_t) (map->capacity * 0.86);
+  if (!map->addressable) map->addressable = map->capacity;
+  map->load_factor = load_factor;
+  map->hashcode = pn_hashcode;
+  map->equals = pn_equals;
+  pni_map_allocate(map);
+  return map;
+}
+
+size_t pn_map_size(pn_map_t *map)
+{
+  assert(map);
+  return map->size;
+}
+
+static float pni_map_load(pn_map_t *map)
+{
+  return ((float) map->size) / ((float) map->addressable);
+}
+
+static bool pni_map_ensure(pn_map_t *map, size_t capacity)
+{
+  float load = pni_map_load(map);
+  if (capacity <= map->capacity && load <= map->load_factor) {
+    return false;
+  }
+
+  size_t oldcap = map->capacity;
+
+  while (map->capacity < capacity || pni_map_load(map) > map->load_factor) {
+    map->capacity *= 2;
+    map->addressable = (size_t) (0.86 * map->capacity);
+  }
+
+  pni_entry_t *entries = map->entries;
+  pni_map_allocate(map);
+
+  for (size_t i = 0; i < oldcap; i++) {
+    if (entries[i].state != PNI_ENTRY_FREE) {
+      void *key = entries[i].key;
+      void *value = entries[i].value;
+      pn_map_put(map, key, value);
+    }
+  }
+
+  for (size_t i = 0; i < oldcap; i++) {
+    if (entries[i].state != PNI_ENTRY_FREE) {
+      void *key = entries[i].key;
+      void *value = entries[i].value;
+      pn_class_decref(map->key, key);
+      pn_class_decref(map->value, value);
+    }
+  }
+
+  free(entries);
+  return true;
+}
+
+static pni_entry_t *pni_map_entry(pn_map_t *map, void *key, pni_entry_t **pprev, bool create)
+{
+  uintptr_t hashcode = map->hashcode(key);
+
+  pni_entry_t *entry = &map->entries[hashcode % map->addressable];
+  pni_entry_t *prev = NULL;
+
+  if (entry->state == PNI_ENTRY_FREE) {
+    if (create) {
+      entry->state = PNI_ENTRY_TAIL;
+      entry->key = key;
+      pn_class_incref(map->key, key);
+      map->size++;
+      return entry;
+    } else {
+      return NULL;
+    }
+  }
+
+  while (true) {
+    if (map->equals(entry->key, key)) {
+      if (pprev) *pprev = prev;
+      return entry;
+    }
+
+    if (entry->state == PNI_ENTRY_TAIL) {
+      break;
+    } else {
+      prev = entry;
+      entry = &map->entries[entry->next];
+    }
+  }
+
+  if (create) {
+    if (pni_map_ensure(map, map->size + 1)) {
+      // if we had to grow the table we need to start over
+      return pni_map_entry(map, key, pprev, create);
+    }
+
+    size_t empty = 0;
+    for (size_t i = 0; i < map->capacity; i++) {
+      size_t idx = map->capacity - i - 1;
+      if (map->entries[idx].state == PNI_ENTRY_FREE) {
+        empty = idx;
+        break;
+      }
+    }
+    entry->next = empty;
+    entry->state = PNI_ENTRY_LINK;
+    map->entries[empty].state = PNI_ENTRY_TAIL;
+    map->entries[empty].key = key;
+    pn_class_incref(map->key, key);
+    if (pprev) *pprev = entry;
+    map->size++;
+    return &map->entries[empty];
+  } else {
+    return NULL;
+  }
+}
+
+int pn_map_put(pn_map_t *map, void *key, void *value)
+{
+  assert(map);
+  pni_entry_t *entry = pni_map_entry(map, key, NULL, true);
+  void *dref_val = entry->value;
+  entry->value = value;
+  pn_class_incref(map->value, value);
+  pn_class_decref(map->value, dref_val);
+  return 0;
+}
+
+void *pn_map_get(pn_map_t *map, void *key)
+{
+  assert(map);
+  pni_entry_t *entry = pni_map_entry(map, key, NULL, false);
+  return entry ? entry->value : NULL;
+}
+
+static void pni_map_rehash(pn_map_t *map, size_t index)
+{
+  //reinsert entries in chain starting at index
+  assert(map);
+  size_t i = index;
+  bool complete = false;
+  while (!complete) {
+    pni_entry_t *entry = &map->entries[i];
+    assert(entry);
+    assert(entry->state != PNI_ENTRY_FREE);
+    size_t current = i;
+    if (entry->state == PNI_ENTRY_TAIL) {
+      complete = true;
+    } else {
+      assert(entry->state == PNI_ENTRY_LINK);
+      i = entry->next;
+    }
+    uintptr_t hashcode = map->hashcode(entry->key);
+    pni_entry_t *reloc = &map->entries[hashcode % map->addressable];
+    if (reloc->state == PNI_ENTRY_FREE) {
+      //correct addressable slot is available, copy into that...
+      reloc->state = PNI_ENTRY_TAIL;
+      reloc->key = entry->key;
+      reloc->value = entry->value;
+      //...then free the current entry
+      entry->key = NULL;
+      entry->value = NULL;
+      entry->state = PNI_ENTRY_FREE;
+      entry->next = 0;
+    } else {
+      //iterate to end of chain...
+      while (reloc->state == PNI_ENTRY_LINK) {
+        reloc = &map->entries[reloc->next];
+      }
+      assert(reloc->state == PNI_ENTRY_TAIL);
+      //... and append current entry
+      reloc->state = PNI_ENTRY_LINK;
+      reloc->next = current;
+      entry->state = PNI_ENTRY_TAIL;
+      entry->next = 0;
+    }
+  }
+}
+
+void pn_map_del(pn_map_t *map, void *key)
+{
+  assert(map);
+  pni_entry_t *prev = NULL;
+  pni_entry_t *entry = pni_map_entry(map, key, &prev, false);
+  if (entry) {
+    uint8_t orig_state = entry->state;
+    size_t orig_next = entry->next;
+
+    void *dref_key = entry->key;
+    void *dref_value = entry->value;
+    if (prev) {
+      prev->next = 0;
+      prev->state = PNI_ENTRY_TAIL;
+    }
+    entry->state = PNI_ENTRY_FREE;
+    entry->next = 0;
+    entry->key = NULL;
+    entry->value = NULL;
+    map->size--;
+
+    if (orig_state == PNI_ENTRY_LINK) {
+      pni_map_rehash(map, orig_next);
+    }
+
+    // do this last as it may trigger further deletions
+    pn_class_decref(map->key, dref_key);
+    pn_class_decref(map->value, dref_value);
+  }
+}
+
+pn_handle_t pn_map_head(pn_map_t *map)
+{
+  assert(map);
+  for (size_t i = 0; i < map->capacity; i++)
+  {
+    if (map->entries[i].state != PNI_ENTRY_FREE) {
+      return (pn_handle_t)(i + 1);
+    }
+  }
+
+  return 0;
+}
+
+pn_handle_t pn_map_next(pn_map_t *map, pn_handle_t entry)
+{
+  for (size_t i = (size_t)entry; i < map->capacity; i++) {
+    if (map->entries[i].state != PNI_ENTRY_FREE) {
+      return (pn_handle_t)(i + 1);
+    }
+  }
+
+  return 0;
+}
+
+void *pn_map_key(pn_map_t *map, pn_handle_t entry)
+{
+  assert(map);
+  assert(entry);
+  return map->entries[(size_t)entry - 1].key;
+}
+
+void *pn_map_value(pn_map_t *map, pn_handle_t entry)
+{
+  assert(map);
+  assert(entry);
+  return map->entries[(size_t)entry - 1].value;
+}
+
+struct pn_hash_t {
+  pn_map_t map;
+};
+
+static uintptr_t pni_identity_hashcode(void *obj)
+{
+  return (uintptr_t ) obj;
+}
+
+static bool pni_identity_equals(void *a, void *b)
+{
+  return a == b;
+}
+
+#define CID_pni_uintptr CID_pn_void
+static const pn_class_t *pni_uintptr_reify(void *object);
+#define pni_uintptr_new NULL
+#define pni_uintptr_free NULL
+#define pni_uintptr_initialize NULL
+static void pni_uintptr_incref(void *object) {}
+static void pni_uintptr_decref(void *object) {}
+static int pni_uintptr_refcount(void *object) { return -1; }
+#define pni_uintptr_finalize NULL
+#define pni_uintptr_hashcode NULL
+#define pni_uintptr_compare NULL
+#define pni_uintptr_inspect NULL
+
+static const pn_class_t PN_UINTPTR[] = {PN_METACLASS(pni_uintptr)};
+
+static const pn_class_t *pni_uintptr_reify(void *object)
+{
+  return PN_UINTPTR;
+}
+
+pn_hash_t *pn_hash(const pn_class_t *clazz, size_t capacity, float load_factor)
+{
+  pn_hash_t *hash = (pn_hash_t *) pn_map(PN_UINTPTR, clazz, capacity, load_factor);
+  hash->map.hashcode = pni_identity_hashcode;
+  hash->map.equals = pni_identity_equals;
+  return hash;
+}
+
+size_t pn_hash_size(pn_hash_t *hash)
+{
+  return pn_map_size(&hash->map);
+}
+
+int pn_hash_put(pn_hash_t *hash, uintptr_t key, void *value)
+{
+  return pn_map_put(&hash->map, (void *) key, value);
+}
+
+void *pn_hash_get(pn_hash_t *hash, uintptr_t key)
+{
+  return pn_map_get(&hash->map, (void *) key);
+}
+
+void pn_hash_del(pn_hash_t *hash, uintptr_t key)
+{
+  pn_map_del(&hash->map, (void *) key);
+}
+
+pn_handle_t pn_hash_head(pn_hash_t *hash)
+{
+  return pn_map_head(&hash->map);
+}
+
+pn_handle_t pn_hash_next(pn_hash_t *hash, pn_handle_t entry)
+{
+  return pn_map_next(&hash->map, entry);
+}
+
+uintptr_t pn_hash_key(pn_hash_t *hash, pn_handle_t entry)
+{
+  return (uintptr_t) pn_map_key(&hash->map, entry);
+}
+
+void *pn_hash_value(pn_hash_t *hash, pn_handle_t entry)
+{
+  return pn_map_value(&hash->map, entry);
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/src/core/object/object.c
----------------------------------------------------------------------
diff --git a/c/src/core/object/object.c b/c/src/core/object/object.c
new file mode 100644
index 0000000..a6952b6
--- /dev/null
+++ b/c/src/core/object/object.c
@@ -0,0 +1,312 @@
+/*
+ *
+ * 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 <stdlib.h>
+#include <assert.h>
+
+#define pn_object_initialize NULL
+#define pn_object_finalize NULL
+#define pn_object_inspect NULL
+uintptr_t pn_object_hashcode(void *object) { return (uintptr_t) object; }
+intptr_t pn_object_compare(void *a, void *b) { return (intptr_t) a - (intptr_t) b; }
+
+const pn_class_t PN_OBJECT[] = {PN_CLASS(pn_object)};
+
+#define pn_void_initialize NULL
+void *pn_void_new(const pn_class_t *clazz, size_t size) { return malloc(size); }
+void pn_void_incref(void* p) {}
+void pn_void_decref(void* p) {}
+int pn_void_refcount(void *object) { return -1; }
+#define pn_void_finalize NULL
+static void pn_void_free(void *object) { free(object); }
+static const pn_class_t *pn_void_reify(void *object) { return PN_VOID; }
+uintptr_t pn_void_hashcode(void *object) { return (uintptr_t) object; }
+intptr_t pn_void_compare(void *a, void *b) { return (intptr_t) a - (intptr_t) b; }
+int pn_void_inspect(void *object, pn_string_t *dst) { return pn_string_addf(dst, "%p", object); }
+
+const pn_class_t PN_VOID[] = {PN_METACLASS(pn_void)};
+
+const char *pn_class_name(const pn_class_t *clazz)
+{
+  return clazz->name;
+}
+
+pn_cid_t pn_class_id(const pn_class_t *clazz)
+{
+  return clazz->cid;
+}
+
+void *pn_class_new(const pn_class_t *clazz, size_t size)
+{
+  assert(clazz);
+  void *object = clazz->newinst(clazz, size);
+  if (clazz->initialize) {
+    clazz->initialize(object);
+  }
+  return object;
+}
+
+void *pn_class_incref(const pn_class_t *clazz, void *object)
+{
+  assert(clazz);
+  if (object) {
+    clazz = clazz->reify(object);
+    clazz->incref(object);
+  }
+  return object;
+}
+
+int pn_class_refcount(const pn_class_t *clazz, void *object)
+{
+  assert(clazz);
+  clazz = clazz->reify(object);
+  return clazz->refcount(object);
+}
+
+int pn_class_decref(const pn_class_t *clazz, void *object)
+{
+  assert(clazz);
+
+  if (object) {
+    clazz = clazz->reify(object);
+    clazz->decref(object);
+    int rc = clazz->refcount(object);
+    if (rc == 0) {
+      if (clazz->finalize) {
+        clazz->finalize(object);
+        // check the refcount again in case the finalizer created a
+        // new reference
+        rc = clazz->refcount(object);
+      }
+      if (rc == 0) {
+        clazz->free(object);
+        return 0;
+      }
+    } else {
+      return rc;
+    }
+  }
+
+  return 0;
+}
+
+void pn_class_free(const pn_class_t *clazz, void *object)
+{
+  assert(clazz);
+  if (object) {
+    clazz = clazz->reify(object);
+    int rc = clazz->refcount(object);
+    assert(rc == 1 || rc == -1);
+    if (rc == 1) {
+      rc = pn_class_decref(clazz, object);
+      assert(rc == 0);
+    } else {
+      if (clazz->finalize) {
+        clazz->finalize(object);
+      }
+      clazz->free(object);
+    }
+  }
+}
+
+const pn_class_t *pn_class_reify(const pn_class_t *clazz, void *object)
+{
+  assert(clazz);
+  return clazz->reify(object);
+}
+
+uintptr_t pn_class_hashcode(const pn_class_t *clazz, void *object)
+{
+  assert(clazz);
+
+  if (!object) return 0;
+
+  clazz = clazz->reify(object);
+
+  if (clazz->hashcode) {
+    return clazz->hashcode(object);
+  } else {
+    return (uintptr_t) object;
+  }
+}
+
+intptr_t pn_class_compare(const pn_class_t *clazz, void *a, void *b)
+{
+  assert(clazz);
+
+  if (a == b) return 0;
+
+  clazz = clazz->reify(a);
+
+  if (a && b && clazz->compare) {
+    return clazz->compare(a, b);
+  } else {
+    return (intptr_t) a - (intptr_t) b;
+  }
+}
+
+bool pn_class_equals(const pn_class_t *clazz, void *a, void *b)
+{
+  return pn_class_compare(clazz, a, b) == 0;
+}
+
+int pn_class_inspect(const pn_class_t *clazz, void *object, pn_string_t *dst)
+{
+  assert(clazz);
+
+  clazz = clazz->reify(object);
+
+  if (!pn_string_get(dst)) {
+    pn_string_set(dst, "");
+  }
+
+  if (object && clazz->inspect) {
+    return clazz->inspect(object, dst);
+  }
+
+  const char *name = clazz->name ? clazz->name : "<anon>";
+
+  return pn_string_addf(dst, "%s<%p>", name, object);
+}
+
+typedef struct {
+  const pn_class_t *clazz;
+  int refcount;
+} pni_head_t;
+
+#define pni_head(PTR) \
+  (((pni_head_t *) (PTR)) - 1)
+
+void *pn_object_new(const pn_class_t *clazz, size_t size)
+{
+  void *object = NULL;
+  pni_head_t *head = (pni_head_t *) calloc(1, sizeof(pni_head_t) + size);
+  if (head != NULL) {
+    object = head + 1;
+    head->clazz = clazz;
+    head->refcount = 1;
+  }
+  return object;
+}
+
+const pn_class_t *pn_object_reify(void *object)
+{
+  if (object) {
+    return pni_head(object)->clazz;
+  } else {
+    return PN_OBJECT;
+  }
+}
+
+void pn_object_incref(void *object)
+{
+  if (object) {
+    pni_head(object)->refcount++;
+  }
+}
+
+int pn_object_refcount(void *object)
+{
+  assert(object);
+  return pni_head(object)->refcount;
+}
+
+void pn_object_decref(void *object)
+{
+  pni_head_t *head = pni_head(object);
+  assert(head->refcount > 0);
+  head->refcount--;
+}
+
+void pn_object_free(void *object)
+{
+  pni_head_t *head = pni_head(object);
+  free(head);
+}
+
+void *pn_incref(void *object)
+{
+  return pn_class_incref(PN_OBJECT, object);
+}
+
+int pn_decref(void *object)
+{
+  return pn_class_decref(PN_OBJECT, object);
+}
+
+int pn_refcount(void *object)
+{
+  return pn_class_refcount(PN_OBJECT, object);
+}
+
+void pn_free(void *object)
+{
+  pn_class_free(PN_OBJECT, object);
+}
+
+const pn_class_t *pn_class(void *object)
+{
+  return pn_class_reify(PN_OBJECT, object);
+}
+
+uintptr_t pn_hashcode(void *object)
+{
+  return pn_class_hashcode(PN_OBJECT, object);
+}
+
+intptr_t pn_compare(void *a, void *b)
+{
+  return pn_class_compare(PN_OBJECT, a, b);
+}
+
+bool pn_equals(void *a, void *b)
+{
+  return !pn_compare(a, b);
+}
+
+int pn_inspect(void *object, pn_string_t *dst)
+{
+  return pn_class_inspect(PN_OBJECT, object, dst);
+}
+
+#define pn_weakref_new NULL
+#define pn_weakref_initialize NULL
+#define pn_weakref_finalize NULL
+#define pn_weakref_free NULL
+
+static void pn_weakref_incref(void *object) {}
+static void pn_weakref_decref(void *object) {}
+static int pn_weakref_refcount(void *object) { return -1; }
+static const pn_class_t *pn_weakref_reify(void *object) {
+  return PN_WEAKREF;
+}
+static uintptr_t pn_weakref_hashcode(void *object) {
+  return pn_hashcode(object);
+}
+static intptr_t pn_weakref_compare(void *a, void *b) {
+  return pn_compare(a, b);
+}
+static int pn_weakref_inspect(void *object, pn_string_t *dst) {
+  return pn_inspect(object, dst);
+}
+
+const pn_class_t PN_WEAKREF[] = {PN_METACLASS(pn_weakref)};

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/src/core/object/record.c
----------------------------------------------------------------------
diff --git a/c/src/core/object/record.c b/c/src/core/object/record.c
new file mode 100644
index 0000000..6f4fe0a
--- /dev/null
+++ b/c/src/core/object/record.c
@@ -0,0 +1,153 @@
+/*
+ *
+ * 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 <stdlib.h>
+#include <assert.h>
+
+typedef struct {
+  pn_handle_t key;
+  const pn_class_t *clazz;
+  void *value;
+} pni_field_t;
+
+struct pn_record_t {
+  size_t size;
+  size_t capacity;
+  pni_field_t *fields;
+};
+
+static void pn_record_initialize(void *object)
+{
+  pn_record_t *record = (pn_record_t *) object;
+  record->size = 0;
+  record->capacity = 0;
+  record->fields = NULL;
+}
+
+static void pn_record_finalize(void *object)
+{
+  pn_record_t *record = (pn_record_t *) object;
+  for (size_t i = 0; i < record->size; i++) {
+    pni_field_t *v = &record->fields[i];
+    pn_class_decref(v->clazz, v->value);
+  }
+  free(record->fields);
+}
+
+#define pn_record_hashcode NULL
+#define pn_record_compare NULL
+#define pn_record_inspect NULL
+
+pn_record_t *pn_record(void)
+{
+  static const pn_class_t clazz = PN_CLASS(pn_record);
+  pn_record_t *record = (pn_record_t *) pn_class_new(&clazz, sizeof(pn_record_t));
+  pn_record_def(record, PN_LEGCTX, PN_VOID);
+  return record;
+}
+
+static pni_field_t *pni_record_find(pn_record_t *record, pn_handle_t key) {
+  for (size_t i = 0; i < record->size; i++) {
+    pni_field_t *field = &record->fields[i];
+    if (field->key == key) {
+      return field;
+    }
+  }
+  return NULL;
+}
+
+static pni_field_t *pni_record_create(pn_record_t *record) {
+  record->size++;
+  if (record->size > record->capacity) {
+    record->fields = (pni_field_t *) realloc(record->fields, record->size * sizeof(pni_field_t));
+    record->capacity = record->size;
+  }
+  pni_field_t *field = &record->fields[record->size - 1];
+  field->key = 0;
+  field->clazz = NULL;
+  field->value = NULL;
+  return field;
+}
+
+void pn_record_def(pn_record_t *record, pn_handle_t key, const pn_class_t *clazz)
+{
+  assert(record);
+  assert(clazz);
+
+  pni_field_t *field = pni_record_find(record, key);
+  if (field) {
+    assert(field->clazz == clazz);
+  } else {
+    field = pni_record_create(record);
+    field->key = key;
+    field->clazz = clazz;
+  }
+}
+
+bool pn_record_has(pn_record_t *record, pn_handle_t key)
+{
+  assert(record);
+  pni_field_t *field = pni_record_find(record, key);
+  if (field) {
+    return true;
+  } else {
+    return false;
+  }
+}
+
+void *pn_record_get(pn_record_t *record, pn_handle_t key)
+{
+  assert(record);
+  pni_field_t *field = pni_record_find(record, key);
+  if (field) {
+    return field->value;
+  } else {
+    return NULL;
+  }
+}
+
+void pn_record_set(pn_record_t *record, pn_handle_t key, void *value)
+{
+  assert(record);
+
+  pni_field_t *field = pni_record_find(record, key);
+  if (field) {
+    void *old = field->value;
+    field->value = value;
+    pn_class_incref(field->clazz, value);
+    pn_class_decref(field->clazz, old);
+  }
+}
+
+void pn_record_clear(pn_record_t *record)
+{
+  assert(record);
+  for (size_t i = 0; i < record->size; i++) {
+    pni_field_t *field = &record->fields[i];
+    pn_class_decref(field->clazz, field->value);
+    field->key = 0;
+    field->clazz = NULL;
+    field->value = NULL;
+  }
+  record->size = 0;
+  pn_record_def(record, PN_LEGCTX, PN_VOID);
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/37136940/c/src/core/object/string.c
----------------------------------------------------------------------
diff --git a/c/src/core/object/string.c b/c/src/core/object/string.c
new file mode 100644
index 0000000..71db6c4
--- /dev/null
+++ b/c/src/core/object/string.c
@@ -0,0 +1,270 @@
+/*
+ *
+ * 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 "platform/platform.h"
+
+#include <proton/error.h>
+#include <proton/object.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+
+#define PNI_NULL_SIZE (-1)
+
+struct pn_string_t {
+  char *bytes;
+  ssize_t size;       // PNI_NULL_SIZE (-1) means null
+  size_t capacity;
+};
+
+static void pn_string_finalize(void *object)
+{
+  pn_string_t *string = (pn_string_t *) object;
+  free(string->bytes);
+}
+
+static uintptr_t pn_string_hashcode(void *object)
+{
+  pn_string_t *string = (pn_string_t *) object;
+  if (string->size == PNI_NULL_SIZE) {
+    return 0;
+  }
+
+  uintptr_t hashcode = 1;
+  for (ssize_t i = 0; i < string->size; i++) {
+    hashcode = hashcode * 31 + string->bytes[i];
+  }
+  return hashcode;
+}
+
+static intptr_t pn_string_compare(void *oa, void *ob)
+{
+  pn_string_t *a = (pn_string_t *) oa;
+  pn_string_t *b = (pn_string_t *) ob;
+  if (a->size != b->size) {
+    return b->size - a->size;
+  }
+
+  if (a->size == PNI_NULL_SIZE) {
+    return 0;
+  } else {
+    return memcmp(a->bytes, b->bytes, a->size);
+  }
+}
+
+static int pn_string_inspect(void *obj, pn_string_t *dst)
+{
+  pn_string_t *str = (pn_string_t *) obj;
+  if (str->size == PNI_NULL_SIZE) {
+    return pn_string_addf(dst, "null");
+  }
+
+  int err = pn_string_addf(dst, "\"");
+  if (err) return err;
+
+  for (int i = 0; i < str->size; i++) {
+    uint8_t c = str->bytes[i];
+    if (isprint(c)) {
+      err = pn_string_addf(dst, "%c", c);
+      if (err) return err;
+    } else {
+      err = pn_string_addf(dst, "\\x%.2x", c);
+      if (err) return err;
+    }
+  }
+
+  return pn_string_addf(dst, "\"");
+}
+
+pn_string_t *pn_string(const char *bytes)
+{
+  return pn_stringn(bytes, bytes ? strlen(bytes) : 0);
+}
+
+#define pn_string_initialize NULL
+
+
+pn_string_t *pn_stringn(const char *bytes, size_t n)
+{
+  static const pn_class_t clazz = PN_CLASS(pn_string);
+  pn_string_t *string = (pn_string_t *) pn_class_new(&clazz, sizeof(pn_string_t));
+  string->capacity = n ? n * sizeof(char) : 16;
+  string->bytes = (char *) malloc(string->capacity);
+  pn_string_setn(string, bytes, n);
+  return string;
+}
+
+const char *pn_string_get(pn_string_t *string)
+{
+  assert(string);
+  if (string->size == PNI_NULL_SIZE) {
+    return NULL;
+  } else {
+    return string->bytes;
+  }
+}
+
+size_t pn_string_size(pn_string_t *string)
+{
+  assert(string);
+  if (string->size == PNI_NULL_SIZE) {
+    return 0;
+  } else {
+    return string->size;
+  }
+}
+
+int pn_string_set(pn_string_t *string, const char *bytes)
+{
+  return pn_string_setn(string, bytes, bytes ? strlen(bytes) : 0);
+}
+
+int pn_string_grow(pn_string_t *string, size_t capacity)
+{
+  bool grow = false;
+  while (string->capacity < (capacity*sizeof(char) + 1)) {
+    string->capacity *= 2;
+    grow = true;
+  }
+
+  if (grow) {
+    char *growed = (char *) realloc(string->bytes, string->capacity);
+    if (growed) {
+      string->bytes = growed;
+    } else {
+      return PN_ERR;
+    }
+  }
+
+  return 0;
+}
+
+int pn_string_setn(pn_string_t *string, const char *bytes, size_t n)
+{
+  int err = pn_string_grow(string, n);
+  if (err) return err;
+
+  if (bytes) {
+    memcpy(string->bytes, bytes, n*sizeof(char));
+    string->bytes[n] = '\0';
+    string->size = n;
+  } else {
+    string->size = PNI_NULL_SIZE;
+  }
+
+  return 0;
+}
+
+ssize_t pn_string_put(pn_string_t *string, char *dst)
+{
+  assert(string);
+  assert(dst);
+
+  if (string->size != PNI_NULL_SIZE) {
+    memcpy(dst, string->bytes, string->size + 1);
+  }
+
+  return string->size;
+}
+
+void pn_string_clear(pn_string_t *string)
+{
+  pn_string_set(string, NULL);
+}
+
+int pn_string_format(pn_string_t *string, const char *format, ...)
+{
+  va_list ap;
+
+  va_start(ap, format);
+  int err = pn_string_vformat(string, format, ap);
+  va_end(ap);
+  return err;
+}
+
+int pn_string_vformat(pn_string_t *string, const char *format, va_list ap)
+{
+  pn_string_set(string, "");
+  return pn_string_vaddf(string, format, ap);
+}
+
+int pn_string_addf(pn_string_t *string, const char *format, ...)
+{
+  va_list ap;
+
+  va_start(ap, format);
+  int err = pn_string_vaddf(string, format, ap);
+  va_end(ap);
+  return err;
+}
+
+int pn_string_vaddf(pn_string_t *string, const char *format, va_list ap)
+{
+  va_list copy;
+
+  if (string->size == PNI_NULL_SIZE) {
+    return PN_ERR;
+  }
+
+  while (true) {
+    va_copy(copy, ap);
+    int err = pni_vsnprintf(string->bytes + string->size, string->capacity - string->size, format, copy);
+    va_end(copy);
+    if (err < 0) {
+      return err;
+    } else if ((size_t) err >= string->capacity - string->size) {
+      pn_string_grow(string, string->size + err);
+    } else {
+      string->size += err;
+      return 0;
+    }
+  }
+}
+
+char *pn_string_buffer(pn_string_t *string)
+{
+  assert(string);
+  return string->bytes;
+}
+
+size_t pn_string_capacity(pn_string_t *string)
+{
+  assert(string);
+  return string->capacity - 1;
+}
+
+int pn_string_resize(pn_string_t *string, size_t size)
+{
+  assert(string);
+  int err = pn_string_grow(string, size);
+  if (err) return err;
+  string->size = size;
+  string->bytes[size] = '\0';
+  return 0;
+}
+
+int pn_string_copy(pn_string_t *string, pn_string_t *src)
+{
+  assert(string);
+  return pn_string_setn(string, pn_string_get(src), pn_string_size(src));
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org