http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/33ab96fb/htrace-c/src/util/cmp.c
----------------------------------------------------------------------
diff --git a/htrace-c/src/util/cmp.c b/htrace-c/src/util/cmp.c
new file mode 100644
index 0000000..9d3101f
--- /dev/null
+++ b/htrace-c/src/util/cmp.c
@@ -0,0 +1,2674 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Charles Gunyon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "cmp.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <unistd.h>
+
+static const uint32_t version = 10;
+static const uint32_t mp_version = 5;
+
+enum {
+  POSITIVE_FIXNUM_MARKER = 0x00,
+  FIXMAP_MARKER          = 0x80,
+  FIXARRAY_MARKER        = 0x90,
+  FIXSTR_MARKER          = 0xA0,
+  NIL_MARKER             = 0xC0,
+  FALSE_MARKER           = 0xC2,
+  TRUE_MARKER            = 0xC3,
+  BIN8_MARKER            = 0xC4,
+  BIN16_MARKER           = 0xC5,
+  BIN32_MARKER           = 0xC6,
+  EXT8_MARKER            = 0xC7,
+  EXT16_MARKER           = 0xC8,
+  EXT32_MARKER           = 0xC9,
+  FLOAT_MARKER           = 0xCA,
+  DOUBLE_MARKER          = 0xCB,
+  U8_MARKER              = 0xCC,
+  U16_MARKER             = 0xCD,
+  U32_MARKER             = 0xCE,
+  U64_MARKER             = 0xCF,
+  S8_MARKER              = 0xD0,
+  S16_MARKER             = 0xD1,
+  S32_MARKER             = 0xD2,
+  S64_MARKER             = 0xD3,
+  FIXEXT1_MARKER         = 0xD4,
+  FIXEXT2_MARKER         = 0xD5,
+  FIXEXT4_MARKER         = 0xD6,
+  FIXEXT8_MARKER         = 0xD7,
+  FIXEXT16_MARKER        = 0xD8,
+  STR8_MARKER            = 0xD9,
+  STR16_MARKER           = 0xDA,
+  STR32_MARKER           = 0xDB,
+  ARRAY16_MARKER         = 0xDC,
+  ARRAY32_MARKER         = 0xDD,
+  MAP16_MARKER           = 0xDE,
+  MAP32_MARKER           = 0xDF,
+  NEGATIVE_FIXNUM_MARKER = 0xE0
+};
+
+enum {
+  FIXARRAY_SIZE        = 0xF,
+  FIXMAP_SIZE          = 0xF,
+  FIXSTR_SIZE          = 0x1F
+};
+
+enum {
+  ERROR_NONE,
+  STR_DATA_LENGTH_TOO_LONG_ERROR,
+  BIN_DATA_LENGTH_TOO_LONG_ERROR,
+  ARRAY_LENGTH_TOO_LONG_ERROR,
+  MAP_LENGTH_TOO_LONG_ERROR,
+  INPUT_VALUE_TOO_LARGE_ERROR,
+  FIXED_VALUE_WRITING_ERROR,
+  TYPE_MARKER_READING_ERROR,
+  TYPE_MARKER_WRITING_ERROR,
+  DATA_READING_ERROR,
+  DATA_WRITING_ERROR,
+  EXT_TYPE_READING_ERROR,
+  EXT_TYPE_WRITING_ERROR,
+  INVALID_TYPE_ERROR,
+  LENGTH_READING_ERROR,
+  LENGTH_WRITING_ERROR,
+  ERROR_MAX
+};
+
+const char *cmp_error_messages[ERROR_MAX + 1] = {
+  "No Error",
+  "Specified string data length is too long (> 0xFFFFFFFF)",
+  "Specified binary data length is too long (> 0xFFFFFFFF)",
+  "Specified array length is too long (> 0xFFFFFFFF)",
+  "Specified map length is too long (> 0xFFFFFFFF)",
+  "Input value is too large",
+  "Error writing fixed value",
+  "Error reading type marker",
+  "Error writing type marker",
+  "Error reading packed data",
+  "Error writing packed data",
+  "Error reading ext type",
+  "Error writing ext type",
+  "Invalid type",
+  "Error reading size",
+  "Error writing size",
+  "Max Error"
+};
+
+static const int32_t _i = 1;
+#define is_bigendian() ((*(char *)&_i) == 0)
+
+static uint16_t be16(uint16_t x) {
+  char *b = (char *)&x;
+
+  if (!is_bigendian()) {
+    char swap = 0;
+
+    swap = b[0];
+    b[0] = b[1];
+    b[1] = swap;
+  }
+
+  return x;
+}
+
+static uint32_t be32(uint32_t x) {
+  char *b = (char *)&x;
+
+  if (!is_bigendian()) {
+    char swap = 0;
+
+    swap = b[0];
+    b[0] = b[3];
+    b[3] = swap;
+
+    swap = b[1];
+    b[1] = b[2];
+    b[2] = swap;
+  }
+
+  return x;
+}
+
+static uint64_t be64(uint64_t x) {
+  char *b = (char *)&x;
+
+  if (!is_bigendian()) {
+    char swap = 0;
+
+    swap = b[0];
+    b[0] = b[7];
+    b[7] = swap;
+
+    swap = b[1];
+    b[1] = b[6];
+    b[6] = swap;
+
+    swap = b[2];
+    b[2] = b[5];
+    b[5] = swap;
+
+    swap = b[3];
+    b[3] = b[4];
+    b[4] = swap;
+  }
+
+  return x;
+}
+
+static float befloat(float x) {
+  char *b = (char *)&x;
+
+  if (!is_bigendian()) {
+    char swap = 0;
+
+    swap = b[0];
+    b[0] = b[3];
+    b[3] = swap;
+
+    swap = b[1];
+    b[1] = b[2];
+    b[2] = swap;
+  }
+
+  return x;
+}
+
+static double bedouble(double x) {
+  char *b = (char *)&x;
+
+  if (!is_bigendian()) {
+    char swap = 0;
+
+    swap = b[0];
+    b[0] = b[7];
+    b[7] = swap;
+
+    swap = b[1];
+    b[1] = b[6];
+    b[6] = swap;
+
+    swap = b[2];
+    b[2] = b[5];
+    b[5] = swap;
+
+    swap = b[3];
+    b[3] = b[4];
+    b[4] = swap;
+  }
+
+  return x;
+}
+
+static bool read_byte(cmp_ctx_t *ctx, uint8_t *x) {
+  return ctx->read(ctx, x, sizeof(uint8_t));
+}
+
+static bool write_byte(cmp_ctx_t *ctx, uint8_t x) {
+  return (ctx->write(ctx, &x, sizeof(uint8_t)) == (sizeof(uint8_t)));
+}
+
+static bool read_type_marker(cmp_ctx_t *ctx, uint8_t *marker) {
+  if (read_byte(ctx, marker))
+    return true;
+
+  ctx->error = TYPE_MARKER_READING_ERROR;
+  return false;
+}
+
+static bool write_type_marker(cmp_ctx_t *ctx, uint8_t marker) {
+  if (write_byte(ctx, marker))
+    return true;
+
+  ctx->error = TYPE_MARKER_WRITING_ERROR;
+  return false;
+}
+
+static bool write_fixed_value(cmp_ctx_t *ctx, uint8_t value) {
+  if (write_byte(ctx, value))
+    return true;
+
+  ctx->error = FIXED_VALUE_WRITING_ERROR;
+  return false;
+}
+
+void cmp_init(cmp_ctx_t *ctx, void *buf, cmp_reader read, cmp_writer write) {
+  ctx->error = ERROR_NONE;
+  ctx->buf = buf;
+  ctx->read = read;
+  ctx->write = write;
+}
+
+uint32_t cmp_version(void) {
+  return version;
+}
+
+uint32_t cmp_mp_version(void) {
+  return mp_version;
+}
+
+const char* cmp_strerror(cmp_ctx_t *ctx) {
+  if (ctx->error > ERROR_NONE && ctx->error < ERROR_MAX)
+    return cmp_error_messages[ctx->error];
+
+  return "";
+}
+
+bool cmp_write_pfix(cmp_ctx_t *ctx, uint8_t c) {
+  if (c <= 0x7F)
+    return write_fixed_value(ctx, c);
+
+  ctx->error = INPUT_VALUE_TOO_LARGE_ERROR;
+  return false;
+}
+
+bool cmp_write_nfix(cmp_ctx_t *ctx, int8_t c) {
+  if (c >= -32 && c <= -1)
+    return write_fixed_value(ctx, c);
+
+  ctx->error = INPUT_VALUE_TOO_LARGE_ERROR;
+  return false;
+}
+
+bool cmp_write_sfix(cmp_ctx_t *ctx, int8_t c) {
+  if (c >= 0)
+    return cmp_write_pfix(ctx, c);
+  if (c >= -32 && c <= -1)
+    return cmp_write_nfix(ctx, c);
+
+  ctx->error = INPUT_VALUE_TOO_LARGE_ERROR;
+  return false;
+}
+
+bool cmp_write_s8(cmp_ctx_t *ctx, int8_t c) {
+  if (!write_type_marker(ctx, S8_MARKER))
+    return false;
+
+  return ctx->write(ctx, &c, sizeof(int8_t));
+}
+
+bool cmp_write_s16(cmp_ctx_t *ctx, int16_t s) {
+  if (!write_type_marker(ctx, S16_MARKER))
+    return false;
+
+  s = be16(s);
+
+  return ctx->write(ctx, &s, sizeof(int16_t));
+}
+
+bool cmp_write_s32(cmp_ctx_t *ctx, int32_t i) {
+  if (!write_type_marker(ctx, S32_MARKER))
+    return false;
+
+  i = be32(i);
+
+  return ctx->write(ctx, &i, sizeof(int32_t));
+}
+
+bool cmp_write_s64(cmp_ctx_t *ctx, int64_t l) {
+  if (!write_type_marker(ctx, S64_MARKER))
+    return false;
+
+  l = be64(l);
+
+  return ctx->write(ctx, &l, sizeof(int64_t));
+}
+
+bool cmp_write_sint(cmp_ctx_t *ctx, int64_t d) {
+  if (d >= 0)
+    return cmp_write_uint(ctx, d);
+  if (d >= -32)
+    return cmp_write_nfix(ctx, d);
+  if (d >= -128)
+    return cmp_write_s8(ctx, d);
+  if (d >= -32768)
+    return cmp_write_s16(ctx, d);
+  if (d >= (-2147483647 - 1))
+    return cmp_write_s32(ctx, (int32_t) d);
+
+  return cmp_write_s64(ctx, d);
+}
+
+bool cmp_write_ufix(cmp_ctx_t *ctx, uint8_t c) {
+  return cmp_write_pfix(ctx, c);
+}
+
+bool cmp_write_u8(cmp_ctx_t *ctx, uint8_t c) {
+  if (!write_type_marker(ctx, U8_MARKER))
+    return false;
+
+  return ctx->write(ctx, &c, sizeof(uint8_t));
+}
+
+bool cmp_write_u16(cmp_ctx_t *ctx, uint16_t s) {
+  if (!write_type_marker(ctx, U16_MARKER))
+    return false;
+
+  s = be16(s);
+
+  return ctx->write(ctx, &s, sizeof(uint16_t));
+}
+
+bool cmp_write_u32(cmp_ctx_t *ctx, uint32_t i) {
+  if (!write_type_marker(ctx, U32_MARKER))
+    return false;
+
+  i = be32(i);
+
+  return ctx->write(ctx, &i, sizeof(uint32_t));
+}
+
+bool cmp_write_u64(cmp_ctx_t *ctx, uint64_t l) {
+  if (!write_type_marker(ctx, U64_MARKER))
+    return false;
+
+  l = be64(l);
+
+  return ctx->write(ctx, &l, sizeof(uint64_t));
+}
+
+bool cmp_write_uint(cmp_ctx_t *ctx, uint64_t u) {
+  if (u <= 0x7F)
+    return cmp_write_pfix(ctx, u);
+  if (u <= 0xFF)
+    return cmp_write_u8(ctx, u);
+  if (u <= 0xFFFF)
+    return cmp_write_u16(ctx, u);
+  if (u <= 0xFFFFFFFF)
+    return cmp_write_u32(ctx, (uint32_t) u);
+
+  return cmp_write_u64(ctx, u);
+}
+
+bool cmp_write_float(cmp_ctx_t *ctx, float f) {
+  if (!write_type_marker(ctx, FLOAT_MARKER))
+    return false;
+
+  f = befloat(f);
+
+  return ctx->write(ctx, &f, sizeof(float));
+}
+
+bool cmp_write_double(cmp_ctx_t *ctx, double d) {
+  if (!write_type_marker(ctx, DOUBLE_MARKER))
+    return false;
+
+  d = bedouble(d);
+
+  return ctx->write(ctx, &d, sizeof(double));
+}
+
+bool cmp_write_nil(cmp_ctx_t *ctx) {
+  return write_type_marker(ctx, NIL_MARKER);
+}
+
+bool cmp_write_true(cmp_ctx_t *ctx) {
+  return write_type_marker(ctx, TRUE_MARKER);
+}
+
+bool cmp_write_false(cmp_ctx_t *ctx) {
+  return write_type_marker(ctx, FALSE_MARKER);
+}
+
+bool cmp_write_bool(cmp_ctx_t *ctx, bool b) {
+  if (b)
+    return cmp_write_true(ctx);
+
+  return cmp_write_false(ctx);
+}
+
+bool cmp_write_u8_as_bool(cmp_ctx_t *ctx, uint8_t b) {
+  if (b)
+    return cmp_write_true(ctx);
+
+  return cmp_write_false(ctx);
+}
+
+bool cmp_write_fixstr_marker(cmp_ctx_t *ctx, uint8_t size) {
+  if (size <= FIXSTR_SIZE)
+    return write_fixed_value(ctx, FIXSTR_MARKER | size);
+
+  ctx->error = INPUT_VALUE_TOO_LARGE_ERROR;
+  return false;
+}
+
+bool cmp_write_fixstr(cmp_ctx_t *ctx, const char *data, uint8_t size) {
+  if (!cmp_write_fixstr_marker(ctx, size))
+    return false;
+
+  if (size == 0)
+    return true;
+
+  if (ctx->write(ctx, data, size))
+    return true;
+
+  ctx->error = DATA_WRITING_ERROR;
+  return false;
+}
+
+bool cmp_write_str8_marker(cmp_ctx_t *ctx, uint8_t size) {
+  if (!write_type_marker(ctx, STR8_MARKER))
+    return false;
+
+  if (ctx->write(ctx, &size, sizeof(uint8_t)))
+    return true;
+
+  ctx->error = LENGTH_WRITING_ERROR;
+  return false;
+}
+
+bool cmp_write_str8(cmp_ctx_t *ctx, const char *data, uint8_t size) {
+  if (!cmp_write_str8_marker(ctx, size))
+    return false;
+
+  if (size == 0)
+    return true;
+
+  if (ctx->write(ctx, data, size))
+    return true;
+
+  ctx->error = DATA_WRITING_ERROR;
+  return false;
+}
+
+bool cmp_write_str16_marker(cmp_ctx_t *ctx, uint16_t size) {
+  if (!write_type_marker(ctx, STR16_MARKER))
+    return false;
+
+  size = be16(size);
+
+  if (ctx->write(ctx, &size, sizeof(uint16_t)))
+    return true;
+
+  ctx->error = LENGTH_WRITING_ERROR;
+  return false;
+}
+
+bool cmp_write_str16(cmp_ctx_t *ctx, const char *data, uint16_t size) {
+  if (!cmp_write_str16_marker(ctx, size))
+    return false;
+
+  if (size == 0)
+    return true;
+
+  if (ctx->write(ctx, data, size))
+    return true;
+
+  ctx->error = DATA_WRITING_ERROR;
+  return false;
+}
+
+bool cmp_write_str32_marker(cmp_ctx_t *ctx, uint32_t size) {
+  if (!write_type_marker(ctx, STR32_MARKER))
+    return false;
+
+  size = be32(size);
+
+  if (ctx->write(ctx, &size, sizeof(uint32_t)))
+    return true;
+
+  ctx->error = LENGTH_WRITING_ERROR;
+  return false;
+}
+
+bool cmp_write_str32(cmp_ctx_t *ctx, const char *data, uint32_t size) {
+  if (!cmp_write_str32_marker(ctx, size))
+    return false;
+
+  if (size == 0)
+    return true;
+
+  if (ctx->write(ctx, data, size))
+    return true;
+
+  ctx->error = DATA_WRITING_ERROR;
+  return false;
+}
+
+bool cmp_write_str_marker(cmp_ctx_t *ctx, uint32_t size) {
+  if (size <= FIXSTR_SIZE)
+    return cmp_write_fixstr_marker(ctx, size);
+  if (size <= 0xFF)
+    return cmp_write_str8_marker(ctx, size);
+  if (size <= 0xFFFF)
+    return cmp_write_str16_marker(ctx, size);
+
+  return cmp_write_str32_marker(ctx, size);
+}
+
+bool cmp_write_str(cmp_ctx_t *ctx, const char *data, uint32_t size) {
+  if (size <= FIXSTR_SIZE)
+    return cmp_write_fixstr(ctx, data, size);
+  if (size <= 0xFF)
+    return cmp_write_str8(ctx, data, size);
+  if (size <= 0xFFFF)
+    return cmp_write_str16(ctx, data, size);
+
+  return cmp_write_str32(ctx, data, size);
+}
+
+bool cmp_write_bin8_marker(cmp_ctx_t *ctx, uint8_t size) {
+  if (!write_type_marker(ctx, BIN8_MARKER))
+    return false;
+
+  if (ctx->write(ctx, &size, sizeof(uint8_t)))
+    return true;
+
+  ctx->error = LENGTH_WRITING_ERROR;
+  return false;
+}
+
+bool cmp_write_bin8(cmp_ctx_t *ctx, const void *data, uint8_t size) {
+  if (!cmp_write_bin8_marker(ctx, size))
+    return false;
+
+  if (size == 0)
+    return true;
+
+  if (ctx->write(ctx, data, size))
+    return true;
+
+  ctx->error = DATA_WRITING_ERROR;
+  return false;
+}
+
+bool cmp_write_bin16_marker(cmp_ctx_t *ctx, uint16_t size) {
+  if (!write_type_marker(ctx, BIN16_MARKER))
+    return false;
+
+  size = be16(size);
+
+  if (ctx->write(ctx, &size, sizeof(uint16_t)))
+    return true;
+
+  ctx->error = LENGTH_WRITING_ERROR;
+  return false;
+}
+
+bool cmp_write_bin16(cmp_ctx_t *ctx, const void *data, uint16_t size) {
+  if (!cmp_write_bin16_marker(ctx, size))
+    return false;
+
+  if (size == 0)
+    return true;
+
+  if (ctx->write(ctx, data, size))
+    return true;
+
+  ctx->error = DATA_WRITING_ERROR;
+  return false;
+}
+
+bool cmp_write_bin32_marker(cmp_ctx_t *ctx, uint32_t size) {
+  if (!write_type_marker(ctx, BIN32_MARKER))
+    return false;
+
+  size = be32(size);
+
+  if (ctx->write(ctx, &size, sizeof(uint32_t)))
+    return true;
+
+  ctx->error = LENGTH_WRITING_ERROR;
+  return false;
+}
+
+bool cmp_write_bin32(cmp_ctx_t *ctx, const void *data, uint32_t size) {
+  if (!cmp_write_bin32_marker(ctx, size))
+    return false;
+
+  if (size == 0)
+    return true;
+
+  if (ctx->write(ctx, data, size))
+    return true;
+
+  ctx->error = DATA_WRITING_ERROR;
+  return false;
+}
+
+bool cmp_write_bin_marker(cmp_ctx_t *ctx, uint32_t size) {
+  if (size <= 0xFF)
+    return cmp_write_bin8_marker(ctx, size);
+  if (size <= 0xFFFF)
+    return cmp_write_bin16_marker(ctx, size);
+
+  return cmp_write_bin32_marker(ctx, size);
+}
+
+bool cmp_write_bin(cmp_ctx_t *ctx, const void *data, uint32_t size) {
+  if (size <= 0xFF)
+    return cmp_write_bin8(ctx, data, size);
+  if (size <= 0xFFFF)
+    return cmp_write_bin16(ctx, data, size);
+
+  return cmp_write_bin32(ctx, data, size);
+}
+
+bool cmp_write_fixarray(cmp_ctx_t *ctx, uint8_t size) {
+  if (size <= FIXARRAY_SIZE)
+    return write_fixed_value(ctx, FIXARRAY_MARKER | size);
+
+  ctx->error = INPUT_VALUE_TOO_LARGE_ERROR;
+  return false;
+}
+
+bool cmp_write_array16(cmp_ctx_t *ctx, uint16_t size) {
+  if (!write_type_marker(ctx, ARRAY16_MARKER))
+    return false;
+
+  size = be16(size);
+
+  if (ctx->write(ctx, &size, sizeof(uint16_t)))
+    return true;
+
+  ctx->error = LENGTH_WRITING_ERROR;
+  return false;
+}
+
+bool cmp_write_array32(cmp_ctx_t *ctx, uint32_t size) {
+  if (!write_type_marker(ctx, ARRAY32_MARKER))
+    return false;
+
+  size = be32(size);
+
+  if (ctx->write(ctx, &size, sizeof(uint32_t)))
+    return true;
+
+  ctx->error = LENGTH_WRITING_ERROR;
+  return false;
+}
+
+bool cmp_write_array(cmp_ctx_t *ctx, uint32_t size) {
+  if (size <= FIXARRAY_SIZE)
+    return cmp_write_fixarray(ctx, size);
+  if (size <= 0xFFFF)
+    return cmp_write_array16(ctx, size);
+
+  return cmp_write_array32(ctx, size);
+}
+
+bool cmp_write_fixmap(cmp_ctx_t *ctx, uint8_t size) {
+  if (size <= FIXMAP_SIZE)
+    return write_fixed_value(ctx, FIXMAP_MARKER | size);
+
+  ctx->error = INPUT_VALUE_TOO_LARGE_ERROR;
+  return false;
+}
+
+bool cmp_write_map16(cmp_ctx_t *ctx, uint16_t size) {
+  if (!write_type_marker(ctx, MAP16_MARKER))
+    return false;
+
+  size = be16(size);
+
+  if (ctx->write(ctx, &size, sizeof(uint16_t)))
+    return true;
+
+  ctx->error = LENGTH_WRITING_ERROR;
+  return false;
+}
+
+bool cmp_write_map32(cmp_ctx_t *ctx, uint32_t size) {
+  if (!write_type_marker(ctx, MAP32_MARKER))
+    return false;
+
+  size = be32(size);
+
+  if (ctx->write(ctx, &size, sizeof(uint32_t)))
+    return true;
+
+  ctx->error = LENGTH_WRITING_ERROR;
+  return false;
+}
+
+bool cmp_write_map(cmp_ctx_t *ctx, uint32_t size) {
+  if (size <= FIXMAP_SIZE)
+    return cmp_write_fixmap(ctx, size);
+  if (size <= 0xFFFF)
+    return cmp_write_map16(ctx, size);
+
+  return cmp_write_map32(ctx, size);
+}
+
+bool cmp_write_fixext1_marker(cmp_ctx_t *ctx, int8_t type) {
+  if (!write_type_marker(ctx, FIXEXT1_MARKER))
+    return false;
+
+  if (ctx->write(ctx, &type, sizeof(int8_t)))
+    return true;
+
+  ctx->error = EXT_TYPE_WRITING_ERROR;
+  return false;
+}
+
+bool cmp_write_fixext1(cmp_ctx_t *ctx, int8_t type, const void *data) {
+  if (!cmp_write_fixext1_marker(ctx, type))
+    return false;
+
+  if (ctx->write(ctx, data, 1))
+    return true;
+
+  ctx->error = DATA_WRITING_ERROR;
+  return false;
+}
+
+bool cmp_write_fixext2_marker(cmp_ctx_t *ctx, int8_t type) {
+  if (!write_type_marker(ctx, FIXEXT2_MARKER))
+    return false;
+
+  if (ctx->write(ctx, &type, sizeof(int8_t)))
+    return true;
+
+  ctx->error = EXT_TYPE_WRITING_ERROR;
+  return false;
+}
+
+bool cmp_write_fixext2(cmp_ctx_t *ctx, int8_t type, const void *data) {
+  if (!cmp_write_fixext2_marker(ctx, type))
+    return false;
+
+  if (ctx->write(ctx, data, 2))
+    return true;
+
+  ctx->error = DATA_WRITING_ERROR;
+  return false;
+}
+
+bool cmp_write_fixext4_marker(cmp_ctx_t *ctx, int8_t type) {
+  if (!write_type_marker(ctx, FIXEXT4_MARKER))
+    return false;
+
+  if (ctx->write(ctx, &type, sizeof(int8_t)))
+    return true;
+
+  ctx->error = EXT_TYPE_WRITING_ERROR;
+  return false;
+}
+
+bool cmp_write_fixext4(cmp_ctx_t *ctx, int8_t type, const void *data) {
+  if (!cmp_write_fixext4_marker(ctx, type))
+    return false;
+
+  if (ctx->write(ctx, data, 4))
+    return true;
+
+  ctx->error = DATA_WRITING_ERROR;
+  return false;
+}
+
+bool cmp_write_fixext8_marker(cmp_ctx_t *ctx, int8_t type) {
+  if (!write_type_marker(ctx, FIXEXT8_MARKER))
+    return false;
+
+  if (ctx->write(ctx, &type, sizeof(int8_t)))
+    return true;
+
+  ctx->error = EXT_TYPE_WRITING_ERROR;
+  return false;
+}
+
+bool cmp_write_fixext8(cmp_ctx_t *ctx, int8_t type, const void *data) {
+  if (!cmp_write_fixext8_marker(ctx, type))
+    return false;
+
+  if (ctx->write(ctx, data, 8))
+    return true;
+
+  ctx->error = DATA_WRITING_ERROR;
+  return false;
+}
+
+bool cmp_write_fixext16_marker(cmp_ctx_t *ctx, int8_t type) {
+  if (!write_type_marker(ctx, FIXEXT16_MARKER))
+    return false;
+
+  if (ctx->write(ctx, &type, sizeof(int8_t)))
+    return true;
+
+  ctx->error = EXT_TYPE_WRITING_ERROR;
+  return false;
+}
+
+bool cmp_write_fixext16(cmp_ctx_t *ctx, int8_t type, const void *data) {
+  if (!cmp_write_fixext16_marker(ctx, type))
+    return false;
+
+  if (ctx->write(ctx, data, 16))
+    return true;
+
+  ctx->error = DATA_WRITING_ERROR;
+  return false;
+}
+
+bool cmp_write_ext8_marker(cmp_ctx_t *ctx, int8_t type, uint8_t size) {
+  if (!write_type_marker(ctx, EXT8_MARKER))
+    return false;
+
+  if (!ctx->write(ctx, &size, sizeof(uint8_t))) {
+    ctx->error = LENGTH_WRITING_ERROR;
+    return false;
+  }
+
+  if (ctx->write(ctx, &type, sizeof(int8_t)))
+    return true;
+
+  ctx->error = EXT_TYPE_WRITING_ERROR;
+  return false;
+}
+
+bool cmp_write_ext8(cmp_ctx_t *ctx, int8_t tp, uint8_t sz, const void *data) {
+  if (!cmp_write_ext8_marker(ctx, tp, sz))
+    return false;
+
+  if (ctx->write(ctx, data, sz))
+    return true;
+
+  ctx->error = DATA_WRITING_ERROR;
+  return false;
+}
+
+bool cmp_write_ext16_marker(cmp_ctx_t *ctx, int8_t type, uint16_t size) {
+  if (!write_type_marker(ctx, EXT16_MARKER))
+    return false;
+
+  size = be16(size);
+
+  if (!ctx->write(ctx, &size, sizeof(uint16_t))) {
+    ctx->error = LENGTH_WRITING_ERROR;
+    return false;
+  }
+
+  if (ctx->write(ctx, &type, sizeof(int8_t)))
+    return true;
+
+  ctx->error = EXT_TYPE_WRITING_ERROR;
+  return false;
+}
+
+bool cmp_write_ext16(cmp_ctx_t *ctx, int8_t tp, uint16_t sz, const void *data) 
{
+  if (!cmp_write_ext16_marker(ctx, tp, sz))
+    return false;
+
+  if (ctx->write(ctx, data, sz))
+    return true;
+
+  ctx->error = DATA_WRITING_ERROR;
+  return false;
+}
+
+bool cmp_write_ext32_marker(cmp_ctx_t *ctx, int8_t type, uint32_t size) {
+  if (!write_type_marker(ctx, EXT32_MARKER))
+    return false;
+
+  size = be32(size);
+
+  if (!ctx->write(ctx, &size, sizeof(uint32_t))) {
+    ctx->error = LENGTH_WRITING_ERROR;
+    return false;
+  }
+
+  if (ctx->write(ctx, &type, sizeof(int8_t)))
+    return true;
+
+  ctx->error = EXT_TYPE_WRITING_ERROR;
+  return false;
+}
+
+bool cmp_write_ext32(cmp_ctx_t *ctx, int8_t tp, uint32_t sz, const void *data) 
{
+  if (!cmp_write_ext32_marker(ctx, tp, sz))
+    return false;
+
+  if (ctx->write(ctx, data, sz))
+    return true;
+
+  ctx->error = DATA_WRITING_ERROR;
+  return false;
+}
+
+bool cmp_write_ext_marker(cmp_ctx_t *ctx, int8_t tp, uint32_t sz) {
+  if (sz == 1)
+    return cmp_write_fixext1_marker(ctx, tp);
+  if (sz == 2)
+    return cmp_write_fixext2_marker(ctx, tp);
+  if (sz == 4)
+    return cmp_write_fixext4_marker(ctx, tp);
+  if (sz == 8)
+    return cmp_write_fixext8_marker(ctx, tp);
+  if (sz == 16)
+    return cmp_write_fixext16_marker(ctx, tp);
+  if (sz <= 0xFF)
+    return cmp_write_ext8_marker(ctx, tp, sz);
+  if (sz <= 0xFFFF)
+    return cmp_write_ext16_marker(ctx, tp, sz);
+
+  return cmp_write_ext32_marker(ctx, tp, sz);
+}
+
+bool cmp_write_ext(cmp_ctx_t *ctx, int8_t tp, uint32_t sz, const void *data) {
+  if (sz == 1)
+    return cmp_write_fixext1(ctx, tp, data);
+  if (sz == 2)
+    return cmp_write_fixext2(ctx, tp, data);
+  if (sz == 4)
+    return cmp_write_fixext4(ctx, tp, data);
+  if (sz == 8)
+    return cmp_write_fixext8(ctx, tp, data);
+  if (sz == 16)
+    return cmp_write_fixext16(ctx, tp, data);
+  if (sz <= 0xFF)
+    return cmp_write_ext8(ctx, tp, sz, data);
+  if (sz <= 0xFFFF)
+    return cmp_write_ext16(ctx, tp, sz, data);
+
+  return cmp_write_ext32(ctx, tp, sz, data);
+}
+
+bool cmp_write_object(cmp_ctx_t *ctx, cmp_object_t *obj) {
+  switch(obj->type) {
+    case CMP_TYPE_POSITIVE_FIXNUM:
+      return cmp_write_pfix(ctx, obj->as.u8);
+    case CMP_TYPE_FIXMAP:
+      return cmp_write_fixmap(ctx, obj->as.map_size);
+    case CMP_TYPE_FIXARRAY:
+      return cmp_write_fixarray(ctx, obj->as.array_size);
+    case CMP_TYPE_FIXSTR:
+      return cmp_write_fixstr_marker(ctx, obj->as.str_size);
+    case CMP_TYPE_NIL:
+      return cmp_write_nil(ctx);
+    case CMP_TYPE_BOOLEAN:
+      if (obj->as.boolean)
+        return cmp_write_true(ctx);
+      return cmp_write_false(ctx);
+    case CMP_TYPE_BIN8:
+      return cmp_write_bin8_marker(ctx, obj->as.bin_size);
+    case CMP_TYPE_BIN16:
+      return cmp_write_bin16_marker(ctx, obj->as.bin_size);
+    case CMP_TYPE_BIN32:
+      return cmp_write_bin32_marker(ctx, obj->as.bin_size);
+    case CMP_TYPE_EXT8:
+      return cmp_write_ext8_marker(ctx, obj->as.ext.type, obj->as.ext.size);
+    case CMP_TYPE_EXT16:
+      return cmp_write_ext16_marker(ctx, obj->as.ext.type, obj->as.ext.size);
+    case CMP_TYPE_EXT32:
+      return cmp_write_ext32_marker(ctx, obj->as.ext.type, obj->as.ext.size);
+    case CMP_TYPE_FLOAT:
+      return cmp_write_float(ctx, obj->as.flt);
+    case CMP_TYPE_DOUBLE:
+      return cmp_write_double(ctx, obj->as.dbl);
+    case CMP_TYPE_UINT8:
+      return cmp_write_u8(ctx, obj->as.u8);
+    case CMP_TYPE_UINT16:
+      return cmp_write_u16(ctx, obj->as.u16);
+    case CMP_TYPE_UINT32:
+      return cmp_write_u32(ctx, obj->as.u32);
+    case CMP_TYPE_UINT64:
+      return cmp_write_u64(ctx, obj->as.u64);
+    case CMP_TYPE_SINT8:
+      return cmp_write_s8(ctx, obj->as.s8);
+    case CMP_TYPE_SINT16:
+      return cmp_write_s16(ctx, obj->as.s16);
+    case CMP_TYPE_SINT32:
+      return cmp_write_s32(ctx, obj->as.s32);
+    case CMP_TYPE_SINT64:
+      return cmp_write_s64(ctx, obj->as.s64);
+    case CMP_TYPE_FIXEXT1:
+      return cmp_write_fixext1_marker(ctx, obj->as.ext.type);
+    case CMP_TYPE_FIXEXT2:
+      return cmp_write_fixext2_marker(ctx, obj->as.ext.type);
+    case CMP_TYPE_FIXEXT4:
+      return cmp_write_fixext4_marker(ctx, obj->as.ext.type);
+    case CMP_TYPE_FIXEXT8:
+      return cmp_write_fixext8_marker(ctx, obj->as.ext.type);
+    case CMP_TYPE_FIXEXT16:
+      return cmp_write_fixext16_marker(ctx, obj->as.ext.type);
+    case CMP_TYPE_STR8:
+      return cmp_write_str8_marker(ctx, obj->as.str_size);
+    case CMP_TYPE_STR16:
+      return cmp_write_str16_marker(ctx, obj->as.str_size);
+    case CMP_TYPE_STR32:
+      return cmp_write_str32_marker(ctx, obj->as.str_size);
+    case CMP_TYPE_ARRAY16:
+      return cmp_write_array16(ctx, obj->as.array_size);
+    case CMP_TYPE_ARRAY32:
+      return cmp_write_array32(ctx, obj->as.array_size);
+    case CMP_TYPE_MAP16:
+      return cmp_write_map16(ctx, obj->as.map_size);
+    case CMP_TYPE_MAP32:
+      return cmp_write_map32(ctx, obj->as.map_size);
+    case CMP_TYPE_NEGATIVE_FIXNUM:
+      return cmp_write_nfix(ctx, obj->as.s8);
+    default:
+      ctx->error = INVALID_TYPE_ERROR;
+      return false;
+  }
+}
+
+bool cmp_read_pfix(cmp_ctx_t *ctx, uint8_t *c) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+
+  if (obj.type != CMP_TYPE_POSITIVE_FIXNUM) {
+    ctx->error = INVALID_TYPE_ERROR;
+    return false;
+  }
+
+  *c = obj.as.u8;
+  return true;
+}
+
+bool cmp_read_nfix(cmp_ctx_t *ctx, int8_t *c) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+
+  if (obj.type != CMP_TYPE_NEGATIVE_FIXNUM) {
+    ctx->error = INVALID_TYPE_ERROR;
+    return false;
+  }
+
+  *c = obj.as.s8;
+  return true;
+}
+
+bool cmp_read_sfix(cmp_ctx_t *ctx, int8_t *c) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+
+  switch (obj.type) {
+    case CMP_TYPE_POSITIVE_FIXNUM:
+    case CMP_TYPE_NEGATIVE_FIXNUM:
+      *c = obj.as.s8;
+      return true;
+    default:
+      ctx->error = INVALID_TYPE_ERROR;
+      return false;
+  }
+}
+
+bool cmp_read_s8(cmp_ctx_t *ctx, int8_t *c) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+
+  if (obj.type != CMP_TYPE_SINT8) {
+    ctx->error = INVALID_TYPE_ERROR;
+    return false;
+  }
+
+  *c = obj.as.s8;
+  return true;
+}
+
+bool cmp_read_s16(cmp_ctx_t *ctx, int16_t *s) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+
+  if (obj.type != CMP_TYPE_SINT16) {
+    ctx->error = INVALID_TYPE_ERROR;
+    return false;
+  }
+
+  *s = obj.as.s16;
+  return true;
+}
+
+bool cmp_read_s32(cmp_ctx_t *ctx, int32_t *i) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+
+  if (obj.type != CMP_TYPE_SINT32) {
+    ctx->error = INVALID_TYPE_ERROR;
+    return false;
+  }
+
+  *i = obj.as.s32;
+  return true;
+}
+
+bool cmp_read_s64(cmp_ctx_t *ctx, int64_t *l) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+
+  if (obj.type != CMP_TYPE_SINT64) {
+    ctx->error = INVALID_TYPE_ERROR;
+    return false;
+  }
+
+  *l = obj.as.s64;
+  return true;
+}
+
+bool cmp_read_char(cmp_ctx_t *ctx, int8_t *c) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+
+  switch (obj.type) {
+    case CMP_TYPE_POSITIVE_FIXNUM:
+    case CMP_TYPE_NEGATIVE_FIXNUM:
+    case CMP_TYPE_SINT8:
+      *c = obj.as.s8;
+      return true;
+    case CMP_TYPE_UINT8:
+      if (obj.as.u8 <= 127) {
+        *c = obj.as.u8;
+        return true;
+      }
+    default:
+      ctx->error = INVALID_TYPE_ERROR;
+      return false;
+  }
+}
+
+bool cmp_read_short(cmp_ctx_t *ctx, int16_t *s) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+
+  switch (obj.type) {
+    case CMP_TYPE_POSITIVE_FIXNUM:
+    case CMP_TYPE_NEGATIVE_FIXNUM:
+    case CMP_TYPE_SINT8:
+      *s = obj.as.s8;
+      return true;
+    case CMP_TYPE_UINT8:
+      *s = obj.as.u8;
+      return true;
+    case CMP_TYPE_SINT16:
+      *s = obj.as.s16;
+      return true;
+    case CMP_TYPE_UINT16:
+      if (obj.as.u16 <= 32767) {
+        *s = obj.as.u16;
+        return true;
+      }
+    default:
+      ctx->error = INVALID_TYPE_ERROR;
+      return false;
+  }
+}
+
+bool cmp_read_int(cmp_ctx_t *ctx, int32_t *i) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+
+  switch (obj.type) {
+    case CMP_TYPE_POSITIVE_FIXNUM:
+    case CMP_TYPE_NEGATIVE_FIXNUM:
+    case CMP_TYPE_SINT8:
+      *i = obj.as.s8;
+      return true;
+    case CMP_TYPE_UINT8:
+      *i = obj.as.u8;
+      return true;
+    case CMP_TYPE_SINT16:
+      *i = obj.as.s16;
+      return true;
+    case CMP_TYPE_UINT16:
+      *i = obj.as.u16;
+      return true;
+    case CMP_TYPE_SINT32:
+      *i = obj.as.s32;
+      return true;
+    case CMP_TYPE_UINT32:
+      if (obj.as.u32 <= 2147483647) {
+        *i = obj.as.u32;
+        return true;
+      }
+    default:
+      ctx->error = INVALID_TYPE_ERROR;
+      return false;
+  }
+}
+
+bool cmp_read_long(cmp_ctx_t *ctx, int64_t *d) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+
+  switch (obj.type) {
+    case CMP_TYPE_POSITIVE_FIXNUM:
+    case CMP_TYPE_NEGATIVE_FIXNUM:
+    case CMP_TYPE_SINT8:
+      *d = obj.as.s8;
+      return true;
+    case CMP_TYPE_UINT8:
+      *d = obj.as.u8;
+      return true;
+    case CMP_TYPE_SINT16:
+      *d = obj.as.s16;
+      return true;
+    case CMP_TYPE_UINT16:
+      *d = obj.as.u16;
+      return true;
+    case CMP_TYPE_SINT32:
+      *d = obj.as.s32;
+      return true;
+    case CMP_TYPE_UINT32:
+      *d = obj.as.u32;
+      return true;
+    case CMP_TYPE_SINT64:
+      *d = obj.as.s64;
+      return true;
+    case CMP_TYPE_UINT64:
+      if (obj.as.u64 <= 9223372036854775807) {
+        *d = obj.as.u64;
+        return true;
+      }
+    default:
+      ctx->error = INVALID_TYPE_ERROR;
+      return false;
+  }
+}
+
+bool cmp_read_sinteger(cmp_ctx_t *ctx, int64_t *d) {
+  return cmp_read_long(ctx, d);
+}
+
+bool cmp_read_ufix(cmp_ctx_t *ctx, uint8_t *c) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+
+  if (obj.type != CMP_TYPE_NEGATIVE_FIXNUM) {
+    ctx->error = INVALID_TYPE_ERROR;
+    return false;
+  }
+
+  *c = obj.as.u8;
+  return true;
+}
+
+bool cmp_read_u8(cmp_ctx_t *ctx, uint8_t *c) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+
+  if (obj.type != CMP_TYPE_UINT8) {
+    ctx->error = INVALID_TYPE_ERROR;
+    return false;
+  }
+
+  *c = obj.as.u8;
+  return true;
+}
+
+bool cmp_read_u16(cmp_ctx_t *ctx, uint16_t *s) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+
+  if (obj.type != CMP_TYPE_UINT16) {
+    ctx->error = INVALID_TYPE_ERROR;
+    return false;
+  }
+
+  *s = obj.as.u16;
+  return true;
+}
+
+bool cmp_read_u32(cmp_ctx_t *ctx, uint32_t *i) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+
+  if (obj.type != CMP_TYPE_UINT32) {
+    ctx->error = INVALID_TYPE_ERROR;
+    return false;
+  }
+
+  *i = obj.as.u32;
+  return true;
+}
+
+bool cmp_read_u64(cmp_ctx_t *ctx, uint64_t *l) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+
+  if (obj.type != CMP_TYPE_UINT64) {
+    ctx->error = INVALID_TYPE_ERROR;
+    return false;
+  }
+
+  *l = obj.as.u64;
+  return true;
+}
+
+bool cmp_read_uchar(cmp_ctx_t *ctx, uint8_t *c) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+
+  switch (obj.type) {
+    case CMP_TYPE_POSITIVE_FIXNUM:
+    case CMP_TYPE_UINT8:
+      *c = obj.as.u8;
+      return true;
+    default:
+      ctx->error = INVALID_TYPE_ERROR;
+      return false;
+  }
+}
+
+bool cmp_read_ushort(cmp_ctx_t *ctx, uint16_t *s) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+
+  switch (obj.type) {
+    case CMP_TYPE_POSITIVE_FIXNUM:
+    case CMP_TYPE_UINT8:
+      *s = obj.as.u8;
+      return true;
+    case CMP_TYPE_UINT16:
+      *s = obj.as.u16;
+      return true;
+    default:
+      ctx->error = INVALID_TYPE_ERROR;
+      return false;
+  }
+}
+
+bool cmp_read_uint(cmp_ctx_t *ctx, uint32_t *i) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+
+  switch (obj.type) {
+    case CMP_TYPE_POSITIVE_FIXNUM:
+    case CMP_TYPE_UINT8:
+      *i = obj.as.u8;
+      return true;
+    case CMP_TYPE_UINT16:
+      *i = obj.as.u16;
+      return true;
+    case CMP_TYPE_UINT32:
+      *i = obj.as.u32;
+      return true;
+    default:
+      ctx->error = INVALID_TYPE_ERROR;
+      return false;
+  }
+}
+
+bool cmp_read_ulong(cmp_ctx_t *ctx, uint64_t *u) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+
+  switch (obj.type) {
+    case CMP_TYPE_POSITIVE_FIXNUM:
+    case CMP_TYPE_UINT8:
+      *u = obj.as.u8;
+      return true;
+    case CMP_TYPE_UINT16:
+      *u = obj.as.u16;
+      return true;
+    case CMP_TYPE_UINT32:
+      *u = obj.as.u32;
+      return true;
+    case CMP_TYPE_UINT64:
+      *u = obj.as.u64;
+      return true;
+    default:
+      ctx->error = INVALID_TYPE_ERROR;
+      return false;
+  }
+}
+
+bool cmp_read_uinteger(cmp_ctx_t *ctx, uint64_t *d) {
+  return cmp_read_ulong(ctx, d);
+}
+
+bool cmp_read_float(cmp_ctx_t *ctx, float *f) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+
+  if (obj.type != CMP_TYPE_FLOAT) {
+    ctx->error = INVALID_TYPE_ERROR;
+    return false;
+  }
+
+  *f = obj.as.flt;
+
+  return true;
+}
+
+bool cmp_read_double(cmp_ctx_t *ctx, double *d) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+
+  if (obj.type != CMP_TYPE_DOUBLE) {
+    ctx->error = INVALID_TYPE_ERROR;
+    return false;
+  }
+
+  *d = obj.as.dbl;
+
+  return true;
+}
+
+bool cmp_read_nil(cmp_ctx_t *ctx) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+
+  if (obj.type == CMP_TYPE_NIL)
+    return true;
+
+  ctx->error = INVALID_TYPE_ERROR;
+  return false;
+}
+
+bool cmp_read_bool(cmp_ctx_t *ctx, bool *b) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+
+  if (obj.type != CMP_TYPE_BOOLEAN) {
+    ctx->error = INVALID_TYPE_ERROR;
+    return false;
+  }
+
+  if (obj.as.boolean)
+    *b = true;
+  else
+    *b = false;
+
+  return true;
+}
+
+bool cmp_read_bool_as_u8(cmp_ctx_t *ctx, uint8_t *b) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+
+  if (obj.type != CMP_TYPE_BOOLEAN) {
+    ctx->error = INVALID_TYPE_ERROR;
+    return false;
+  }
+
+  if (obj.as.boolean)
+    *b = 1;
+  else
+    *b = 0;
+
+  return true;
+}
+
+bool cmp_read_str_size(cmp_ctx_t *ctx, uint32_t *size) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+
+  switch (obj.type) {
+    case CMP_TYPE_FIXSTR:
+    case CMP_TYPE_STR8:
+    case CMP_TYPE_STR16:
+    case CMP_TYPE_STR32:
+      *size = obj.as.str_size;
+      return true;
+    default:
+      ctx->error = INVALID_TYPE_ERROR;
+      return false;
+  }
+}
+
+bool cmp_read_str(cmp_ctx_t *ctx, char *data, uint32_t *size) {
+  uint32_t str_size = 0;
+
+  if (!cmp_read_str_size(ctx, &str_size))
+    return false;
+
+  if ((str_size + 1) > *size) {
+    *size = str_size;
+    ctx->error = STR_DATA_LENGTH_TOO_LONG_ERROR;
+    return false;
+  }
+
+  if (!ctx->read(ctx, data, str_size)) {
+    ctx->error = DATA_READING_ERROR;
+    return false;
+  }
+
+  data[str_size] = 0;
+
+  *size = str_size;
+  return true;
+}
+
+bool cmp_read_bin_size(cmp_ctx_t *ctx, uint32_t *size) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+
+  switch (obj.type) {
+    case CMP_TYPE_BIN8:
+    case CMP_TYPE_BIN16:
+    case CMP_TYPE_BIN32:
+      *size = obj.as.bin_size;
+      return true;
+    default:
+      ctx->error = INVALID_TYPE_ERROR;
+      return false;
+  }
+}
+
+bool cmp_read_bin(cmp_ctx_t *ctx, void *data, uint32_t *size) {
+  uint32_t bin_size = 0;
+
+  if (!cmp_read_bin_size(ctx, &bin_size))
+    return false;
+
+  if (bin_size > *size) {
+    ctx->error = BIN_DATA_LENGTH_TOO_LONG_ERROR;
+    return false;
+  }
+
+  if (!ctx->read(ctx, data, bin_size)) {
+    ctx->error = DATA_READING_ERROR;
+    return false;
+  }
+
+  *size = bin_size;
+  return true;
+}
+
+bool cmp_read_array(cmp_ctx_t *ctx, uint32_t *size) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+
+  switch (obj.type) {
+    case CMP_TYPE_FIXARRAY:
+    case CMP_TYPE_ARRAY16:
+    case CMP_TYPE_ARRAY32:
+      *size = obj.as.array_size;
+      return true;
+    default:
+      ctx->error = INVALID_TYPE_ERROR;
+      return false;
+  }
+}
+
+bool cmp_read_map(cmp_ctx_t *ctx, uint32_t *size) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+
+  switch (obj.type) {
+    case CMP_TYPE_FIXMAP:
+    case CMP_TYPE_MAP16:
+    case CMP_TYPE_MAP32:
+      *size = obj.as.map_size;
+      return true;
+    default:
+      ctx->error = INVALID_TYPE_ERROR;
+      return false;
+  }
+}
+
+bool cmp_read_fixext1_marker(cmp_ctx_t *ctx, int8_t *type) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+  
+  if (obj.type != CMP_TYPE_FIXEXT1) {
+    ctx->error = INVALID_TYPE_ERROR;
+    return false;
+  }
+
+  *type = obj.as.ext.type;
+  return true;
+}
+
+bool cmp_read_fixext1(cmp_ctx_t *ctx, int8_t *type, void *data) {
+  if (!cmp_read_fixext1_marker(ctx, type))
+    return false;
+
+  if (ctx->read(ctx, data, 1))
+    return true;
+
+  ctx->error = DATA_READING_ERROR;
+  return false;
+}
+
+bool cmp_read_fixext2_marker(cmp_ctx_t *ctx, int8_t *type) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+  
+  if (obj.type != CMP_TYPE_FIXEXT2) {
+    ctx->error = INVALID_TYPE_ERROR;
+    return false;
+  }
+
+  *type = obj.as.ext.type;
+  return true;
+}
+
+bool cmp_read_fixext2(cmp_ctx_t *ctx, int8_t *type, void *data) {
+  if (!cmp_read_fixext2_marker(ctx, type))
+    return false;
+
+  if (ctx->read(ctx, data, 2))
+    return true;
+
+  ctx->error = DATA_READING_ERROR;
+  return false;
+}
+
+bool cmp_read_fixext4_marker(cmp_ctx_t *ctx, int8_t *type) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+  
+  if (obj.type != CMP_TYPE_FIXEXT4) {
+    ctx->error = INVALID_TYPE_ERROR;
+    return false;
+  }
+
+  *type = obj.as.ext.type;
+  return true;
+}
+
+bool cmp_read_fixext4(cmp_ctx_t *ctx, int8_t *type, void *data) {
+  if (!cmp_read_fixext4_marker(ctx, type))
+    return false;
+
+  if (ctx->read(ctx, data, 4))
+    return true;
+
+  ctx->error = DATA_READING_ERROR;
+  return false;
+}
+
+bool cmp_read_fixext8_marker(cmp_ctx_t *ctx, int8_t *type) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+  
+  if (obj.type != CMP_TYPE_FIXEXT8) {
+    ctx->error = INVALID_TYPE_ERROR;
+    return false;
+  }
+
+  *type = obj.as.ext.type;
+  return true;
+}
+
+bool cmp_read_fixext8(cmp_ctx_t *ctx, int8_t *type, void *data) {
+  if (!cmp_read_fixext8_marker(ctx, type))
+    return false;
+
+  if (ctx->read(ctx, data, 8))
+    return true;
+
+  ctx->error = DATA_READING_ERROR;
+  return false;
+}
+
+bool cmp_read_fixext16_marker(cmp_ctx_t *ctx, int8_t *type) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+  
+  if (obj.type != CMP_TYPE_FIXEXT16) {
+    ctx->error = INVALID_TYPE_ERROR;
+    return false;
+  }
+
+  *type = obj.as.ext.type;
+  return true;
+}
+
+bool cmp_read_fixext16(cmp_ctx_t *ctx, int8_t *type, void *data) {
+  if (!cmp_read_fixext16_marker(ctx, type))
+    return false;
+
+  if (ctx->read(ctx, data, 16))
+    return true;
+
+  ctx->error = DATA_READING_ERROR;
+  return false;
+}
+
+bool cmp_read_ext8_marker(cmp_ctx_t *ctx, int8_t *type, uint8_t *size) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+
+  if (obj.type != CMP_TYPE_EXT8) {
+    ctx->error = INVALID_TYPE_ERROR;
+    return false;
+  }
+
+  *type = obj.as.ext.type;
+  *size = obj.as.ext.size;
+
+  return true;
+}
+
+bool cmp_read_ext8(cmp_ctx_t *ctx, int8_t *type, uint8_t *size, void *data) {
+  if (!cmp_read_ext8_marker(ctx, type, size))
+    return false;
+
+  if (ctx->read(ctx, data, *size))
+    return true;
+
+  ctx->error = DATA_READING_ERROR;
+  return false;
+}
+
+bool cmp_read_ext16_marker(cmp_ctx_t *ctx, int8_t *type, uint16_t *size) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+
+  if (obj.type != CMP_TYPE_EXT16) {
+    ctx->error = INVALID_TYPE_ERROR;
+    return false;
+  }
+
+  *type = obj.as.ext.type;
+  *size = obj.as.ext.size;
+
+  return true;
+}
+
+bool cmp_read_ext16(cmp_ctx_t *ctx, int8_t *type, uint16_t *size, void *data) {
+  if (!cmp_read_ext16_marker(ctx, type, size))
+    return false;
+
+  if (ctx->read(ctx, data, *size))
+    return true;
+
+  ctx->error = DATA_READING_ERROR;
+  return false;
+}
+
+bool cmp_read_ext32_marker(cmp_ctx_t *ctx, int8_t *type, uint32_t *size) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+
+  if (obj.type != CMP_TYPE_EXT32) {
+    ctx->error = INVALID_TYPE_ERROR;
+    return false;
+  }
+
+  *type = obj.as.ext.type;
+  *size = obj.as.ext.size;
+
+  return true;
+}
+
+bool cmp_read_ext32(cmp_ctx_t *ctx, int8_t *type, uint32_t *size, void *data) {
+  if (!cmp_read_ext32_marker(ctx, type, size))
+    return false;
+
+  if (ctx->read(ctx, data, *size))
+    return true;
+
+  ctx->error = DATA_READING_ERROR;
+  return false;
+}
+
+bool cmp_read_ext_marker(cmp_ctx_t *ctx, int8_t *type, uint32_t *size) {
+  cmp_object_t obj;
+
+  if (!cmp_read_object(ctx, &obj))
+    return false;
+
+  switch (obj.type) {
+    case CMP_TYPE_FIXEXT1:
+    case CMP_TYPE_FIXEXT2:
+    case CMP_TYPE_FIXEXT4:
+    case CMP_TYPE_FIXEXT8:
+    case CMP_TYPE_FIXEXT16:
+    case CMP_TYPE_EXT8:
+    case CMP_TYPE_EXT16:
+    case CMP_TYPE_EXT32:
+      *type = obj.as.ext.type;
+      *size = obj.as.ext.size;
+      return true;
+    default:
+      ctx->error = INVALID_TYPE_ERROR;
+      return false;
+  }
+}
+
+bool cmp_read_ext(cmp_ctx_t *ctx, int8_t *type, uint32_t *size, void *data) {
+  if (!cmp_read_ext_marker(ctx, type, size))
+    return false;
+
+  if (ctx->read(ctx, data, *size))
+    return true;
+
+  ctx->error = DATA_READING_ERROR;
+  return false;
+}
+
+bool cmp_read_object(cmp_ctx_t *ctx, cmp_object_t *obj) {
+  uint8_t type_marker = 0;
+
+  if (!read_type_marker(ctx, &type_marker))
+    return false;
+
+  if (type_marker <= 0x7F) {
+    obj->type = CMP_TYPE_POSITIVE_FIXNUM;
+    obj->as.u8 = type_marker;
+  }
+  else if (type_marker <= 0x8F) {
+    obj->type = CMP_TYPE_FIXMAP;
+    obj->as.map_size = type_marker & FIXMAP_SIZE;
+  }
+  else if (type_marker <= 0x9F) {
+    obj->type = CMP_TYPE_FIXARRAY;
+    obj->as.array_size = type_marker & FIXARRAY_SIZE;
+  }
+  else if (type_marker <= 0xBF) {
+    obj->type = CMP_TYPE_FIXSTR;
+    obj->as.str_size = type_marker & FIXSTR_SIZE;
+  }
+  else if (type_marker == NIL_MARKER) {
+    obj->type = CMP_TYPE_NIL;
+    obj->as.u8 = 0;
+  }
+  else if (type_marker == FALSE_MARKER) {
+    obj->type = CMP_TYPE_BOOLEAN;
+    obj->as.boolean = false;
+  }
+  else if (type_marker == TRUE_MARKER) {
+    obj->type = CMP_TYPE_BOOLEAN;
+    obj->as.boolean = true;
+  }
+  else if (type_marker == BIN8_MARKER) {
+    obj->type = CMP_TYPE_BIN8;
+    if (!ctx->read(ctx, &obj->as.u8, sizeof(uint8_t))) {
+      ctx->error = LENGTH_READING_ERROR;
+      return false;
+    }
+    obj->as.bin_size = obj->as.u8;
+  }
+  else if (type_marker == BIN16_MARKER) {
+    obj->type = CMP_TYPE_BIN16;
+    if (!ctx->read(ctx, &obj->as.u16, sizeof(uint16_t))) {
+      ctx->error = LENGTH_READING_ERROR;
+      return false;
+    }
+    obj->as.bin_size = be16(obj->as.u16);
+  }
+  else if (type_marker == BIN32_MARKER) {
+    obj->type = CMP_TYPE_BIN32;
+    if (!ctx->read(ctx, &obj->as.u32, sizeof(uint32_t))) {
+      ctx->error = LENGTH_READING_ERROR;
+      return false;
+    }
+    obj->as.bin_size = be32(obj->as.u32);
+  }
+  else if (type_marker == EXT8_MARKER) {
+    uint8_t ext_size;
+    int8_t ext_type;
+
+    obj->type = CMP_TYPE_EXT8;
+    if (!ctx->read(ctx, &ext_size, sizeof(uint8_t))) {
+      ctx->error = LENGTH_READING_ERROR;
+      return false;
+    }
+    if (!ctx->read(ctx, &ext_type, sizeof(int8_t))) {
+      ctx->error = EXT_TYPE_READING_ERROR;
+      return false;
+    }
+    obj->as.ext.size = ext_size;
+    obj->as.ext.type = ext_type;
+  }
+  else if (type_marker == EXT16_MARKER) {
+    int8_t ext_type;
+    uint16_t ext_size;
+
+    obj->type = CMP_TYPE_EXT16;
+    if (!ctx->read(ctx, &ext_size, sizeof(uint16_t))) {
+      ctx->error = LENGTH_READING_ERROR;
+      return false;
+    }
+    if (!ctx->read(ctx, &ext_type, sizeof(int8_t))) {
+      ctx->error = EXT_TYPE_READING_ERROR;
+      return false;
+    }
+    obj->as.ext.size = be16(ext_size);
+    obj->as.ext.type = ext_type;
+  }
+  else if (type_marker == EXT32_MARKER) {
+    int8_t ext_type;
+    uint32_t ext_size;
+
+    obj->type = CMP_TYPE_EXT32;
+    if (!ctx->read(ctx, &ext_size, sizeof(uint32_t))) {
+      ctx->error = LENGTH_READING_ERROR;
+      return false;
+    }
+    if (!ctx->read(ctx, &ext_type, sizeof(int8_t))) {
+      ctx->error = EXT_TYPE_READING_ERROR;
+      return false;
+    }
+    obj->as.ext.size = be32(ext_size);
+    obj->as.ext.type = ext_type;
+  }
+  else if (type_marker == FLOAT_MARKER) {
+    obj->type = CMP_TYPE_FLOAT;
+    if (!ctx->read(ctx, &obj->as.flt, sizeof(float))) {
+      ctx->error = DATA_READING_ERROR;
+      return false;
+    }
+    obj->as.flt = befloat(obj->as.flt);
+  }
+  else if (type_marker == DOUBLE_MARKER) {
+    obj->type = CMP_TYPE_DOUBLE;
+    if (!ctx->read(ctx, &obj->as.dbl, sizeof(double))) {
+      ctx->error = DATA_READING_ERROR;
+      return false;
+    }
+    obj->as.dbl = bedouble(obj->as.dbl);
+  }
+  else if (type_marker == U8_MARKER) {
+    obj->type = CMP_TYPE_UINT8;
+    if (!ctx->read(ctx, &obj->as.u8, sizeof(uint8_t))) {
+      ctx->error = DATA_READING_ERROR;
+      return false;
+    }
+  }
+  else if (type_marker == U16_MARKER) {
+    obj->type = CMP_TYPE_UINT16;
+    if (!ctx->read(ctx, &obj->as.u16, sizeof(uint16_t))) {
+      ctx->error = DATA_READING_ERROR;
+      return false;
+    }
+    obj->as.u16 = be16(obj->as.u16);
+  }
+  else if (type_marker == U32_MARKER) {
+    obj->type = CMP_TYPE_UINT32;
+    if (!ctx->read(ctx, &obj->as.u32, sizeof(uint32_t))) {
+      ctx->error = DATA_READING_ERROR;
+      return false;
+    }
+    obj->as.u32 = be32(obj->as.u32);
+  }
+  else if (type_marker == U64_MARKER) {
+    obj->type = CMP_TYPE_UINT64;
+    if (!ctx->read(ctx, &obj->as.u64, sizeof(uint64_t))) {
+      ctx->error = DATA_READING_ERROR;
+      return false;
+    }
+    obj->as.u64 = be64(obj->as.u64);
+  }
+  else if (type_marker == S8_MARKER) {
+    obj->type = CMP_TYPE_SINT8;
+    if (!ctx->read(ctx, &obj->as.s8, sizeof(int8_t))) {
+      ctx->error = DATA_READING_ERROR;
+      return false;
+    }
+  }
+  else if (type_marker == S16_MARKER) {
+    obj->type = CMP_TYPE_SINT16;
+    if (!ctx->read(ctx, &obj->as.s16, sizeof(int16_t))) {
+      ctx->error = DATA_READING_ERROR;
+      return false;
+    }
+    obj->as.s16 = be16(obj->as.s16);
+  }
+  else if (type_marker == S32_MARKER) {
+    obj->type = CMP_TYPE_SINT32;
+    if (!ctx->read(ctx, &obj->as.s32, sizeof(int32_t))) {
+      ctx->error = DATA_READING_ERROR;
+      return false;
+    }
+    obj->as.s32 = be32(obj->as.s32);
+  }
+  else if (type_marker == S64_MARKER) {
+    obj->type = CMP_TYPE_SINT64;
+    if (!ctx->read(ctx, &obj->as.s64, sizeof(int64_t))) {
+      ctx->error = DATA_READING_ERROR;
+      return false;
+    }
+    obj->as.s64 = be64(obj->as.s64);
+  }
+  else if (type_marker == FIXEXT1_MARKER) {
+    obj->type = CMP_TYPE_FIXEXT1;
+    if (!ctx->read(ctx, &obj->as.ext.type, sizeof(int8_t))) {
+      ctx->error = EXT_TYPE_READING_ERROR;
+      return false;
+    }
+    obj->as.ext.size = 1;
+  }
+  else if (type_marker == FIXEXT2_MARKER) {
+    obj->type = CMP_TYPE_FIXEXT2;
+    if (!ctx->read(ctx, &obj->as.ext.type, sizeof(int8_t))) {
+      ctx->error = EXT_TYPE_READING_ERROR;
+      return false;
+    }
+    obj->as.ext.size = 2;
+  }
+  else if (type_marker == FIXEXT4_MARKER) {
+    obj->type = CMP_TYPE_FIXEXT4;
+    if (!ctx->read(ctx, &obj->as.ext.type, sizeof(int8_t))) {
+      ctx->error = EXT_TYPE_READING_ERROR;
+      return false;
+    }
+    obj->as.ext.size = 4;
+  }
+  else if (type_marker == FIXEXT8_MARKER) {
+    obj->type = CMP_TYPE_FIXEXT8;
+    if (!ctx->read(ctx, &obj->as.ext.type, sizeof(int8_t))) {
+      ctx->error = EXT_TYPE_READING_ERROR;
+      return false;
+    }
+    obj->as.ext.size = 8;
+  }
+  else if (type_marker == FIXEXT16_MARKER) {
+    obj->type = CMP_TYPE_FIXEXT16;
+    if (!ctx->read(ctx, &obj->as.ext.type, sizeof(int8_t))) {
+      ctx->error = EXT_TYPE_READING_ERROR;
+      return false;
+    }
+    obj->as.ext.size = 16;
+  }
+  else if (type_marker == STR8_MARKER) {
+    obj->type = CMP_TYPE_STR8;
+    if (!ctx->read(ctx, &obj->as.u8, sizeof(uint8_t))) {
+      ctx->error = DATA_READING_ERROR;
+      return false;
+    }
+    obj->as.str_size = obj->as.u8;
+  }
+  else if (type_marker == STR16_MARKER) {
+    obj->type = CMP_TYPE_STR16;
+    if (!ctx->read(ctx, &obj->as.u16, sizeof(uint16_t))) {
+      ctx->error = DATA_READING_ERROR;
+      return false;
+    }
+    obj->as.str_size = be16(obj->as.u16);
+  }
+  else if (type_marker == STR32_MARKER) {
+    obj->type = CMP_TYPE_STR32;
+    if (!ctx->read(ctx, &obj->as.u32, sizeof(uint32_t))) {
+      ctx->error = DATA_READING_ERROR;
+      return false;
+    }
+    obj->as.str_size = be32(obj->as.u32);
+  }
+  else if (type_marker == ARRAY16_MARKER) {
+    obj->type = CMP_TYPE_ARRAY16;
+    if (!ctx->read(ctx, &obj->as.u16, sizeof(uint16_t))) {
+      ctx->error = DATA_READING_ERROR;
+      return false;
+    }
+    obj->as.array_size = be16(obj->as.u16);
+  }
+  else if (type_marker == ARRAY32_MARKER) {
+    obj->type = CMP_TYPE_ARRAY32;
+    if (!ctx->read(ctx, &obj->as.u32, sizeof(uint32_t))) {
+      ctx->error = DATA_READING_ERROR;
+      return false;
+    }
+    obj->as.array_size = be32(obj->as.u32);
+  }
+  else if (type_marker == MAP16_MARKER) {
+    obj->type = CMP_TYPE_MAP16;
+    if (!ctx->read(ctx, &obj->as.u16, sizeof(uint16_t))) {
+      ctx->error = DATA_READING_ERROR;
+      return false;
+    }
+    obj->as.map_size = be16(obj->as.u16);
+  }
+  else if (type_marker == MAP32_MARKER) {
+    obj->type = CMP_TYPE_MAP32;
+    if (!ctx->read(ctx, &obj->as.u32, sizeof(uint32_t))) {
+      ctx->error = DATA_READING_ERROR;
+      return false;
+    }
+    obj->as.map_size = be32(obj->as.u32);
+  }
+  else if (type_marker >= NEGATIVE_FIXNUM_MARKER) {
+    obj->type = CMP_TYPE_NEGATIVE_FIXNUM;
+    obj->as.s8 = type_marker;
+  }
+  else {
+    ctx->error = INVALID_TYPE_ERROR;
+    return false;
+  }
+
+  return true;
+}
+
+bool cmp_object_is_char(cmp_object_t *obj) {
+  switch (obj->type) {
+    case CMP_TYPE_NEGATIVE_FIXNUM:
+    case CMP_TYPE_SINT8:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool cmp_object_is_short(cmp_object_t *obj) {
+  switch (obj->type) {
+    case CMP_TYPE_NEGATIVE_FIXNUM:
+    case CMP_TYPE_SINT8:
+    case CMP_TYPE_SINT16:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool cmp_object_is_int(cmp_object_t *obj) {
+  switch (obj->type) {
+    case CMP_TYPE_NEGATIVE_FIXNUM:
+    case CMP_TYPE_SINT8:
+    case CMP_TYPE_SINT16:
+    case CMP_TYPE_SINT32:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool cmp_object_is_long(cmp_object_t *obj) {
+  switch (obj->type) {
+    case CMP_TYPE_NEGATIVE_FIXNUM:
+    case CMP_TYPE_SINT8:
+    case CMP_TYPE_SINT16:
+    case CMP_TYPE_SINT32:
+    case CMP_TYPE_SINT64:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool cmp_object_is_sinteger(cmp_object_t *obj) {
+  return cmp_object_is_long(obj);
+}
+
+bool cmp_object_is_uchar(cmp_object_t *obj) {
+  switch (obj->type) {
+    case CMP_TYPE_POSITIVE_FIXNUM:
+    case CMP_TYPE_UINT8:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool cmp_object_is_ushort(cmp_object_t *obj) {
+  switch (obj->type) {
+    case CMP_TYPE_POSITIVE_FIXNUM:
+    case CMP_TYPE_UINT8:
+      return true;
+    case CMP_TYPE_UINT16:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool cmp_object_is_uint(cmp_object_t *obj) {
+  switch (obj->type) {
+    case CMP_TYPE_POSITIVE_FIXNUM:
+    case CMP_TYPE_UINT8:
+    case CMP_TYPE_UINT16:
+    case CMP_TYPE_UINT32:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool cmp_object_is_ulong(cmp_object_t *obj) {
+  switch (obj->type) {
+    case CMP_TYPE_POSITIVE_FIXNUM:
+    case CMP_TYPE_UINT8:
+    case CMP_TYPE_UINT16:
+    case CMP_TYPE_UINT32:
+    case CMP_TYPE_UINT64:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool cmp_object_is_uinteger(cmp_object_t *obj) {
+  return cmp_object_is_ulong(obj);
+}
+
+bool cmp_object_is_float(cmp_object_t *obj) {
+  if (obj->type == CMP_TYPE_FLOAT)
+    return true;
+
+  return false;
+}
+
+bool cmp_object_is_double(cmp_object_t *obj) {
+  if (obj->type == CMP_TYPE_DOUBLE)
+    return true;
+
+  return false;
+}
+
+bool cmp_object_is_nil(cmp_object_t *obj) {
+  if (obj->type == CMP_TYPE_NIL)
+    return true;
+
+  return false;
+}
+
+bool cmp_object_is_bool(cmp_object_t *obj) {
+  if (obj->type == CMP_TYPE_BOOLEAN)
+    return true;
+
+  return false;
+}
+
+bool cmp_object_is_str(cmp_object_t *obj) {
+  switch (obj->type) {
+    case CMP_TYPE_FIXSTR:
+    case CMP_TYPE_STR8:
+    case CMP_TYPE_STR16:
+    case CMP_TYPE_STR32:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool cmp_object_is_bin(cmp_object_t *obj) {
+  switch (obj->type) {
+    case CMP_TYPE_BIN8:
+    case CMP_TYPE_BIN16:
+    case CMP_TYPE_BIN32:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool cmp_object_is_array(cmp_object_t *obj) {
+  switch (obj->type) {
+    case CMP_TYPE_FIXARRAY:
+    case CMP_TYPE_ARRAY16:
+    case CMP_TYPE_ARRAY32:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool cmp_object_is_map(cmp_object_t *obj) {
+  switch (obj->type) {
+    case CMP_TYPE_FIXMAP:
+    case CMP_TYPE_MAP16:
+    case CMP_TYPE_MAP32:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool cmp_object_is_ext(cmp_object_t *obj) {
+  switch (obj->type) {
+    case CMP_TYPE_FIXEXT1:
+    case CMP_TYPE_FIXEXT2:
+    case CMP_TYPE_FIXEXT4:
+    case CMP_TYPE_FIXEXT8:
+    case CMP_TYPE_FIXEXT16:
+    case CMP_TYPE_EXT8:
+    case CMP_TYPE_EXT16:
+    case CMP_TYPE_EXT32:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool cmp_object_as_char(cmp_object_t *obj, int8_t *c) {
+  switch (obj->type) {
+    case CMP_TYPE_POSITIVE_FIXNUM:
+    case CMP_TYPE_NEGATIVE_FIXNUM:
+    case CMP_TYPE_SINT8:
+      *c = obj->as.s8;
+      return true;
+    case CMP_TYPE_UINT8:
+      if (obj->as.u8 <= 127) {
+        *c = obj->as.s8;
+        return true;
+      }
+    default:
+        return false;
+  }
+}
+
+bool cmp_object_as_short(cmp_object_t *obj, int16_t *s) {
+  switch (obj->type) {
+    case CMP_TYPE_POSITIVE_FIXNUM:
+    case CMP_TYPE_NEGATIVE_FIXNUM:
+    case CMP_TYPE_SINT8:
+      *s = obj->as.s8;
+      return true;
+    case CMP_TYPE_UINT8:
+      *s = obj->as.u8;
+      return true;
+    case CMP_TYPE_SINT16:
+      *s = obj->as.s16;
+      return true;
+    case CMP_TYPE_UINT16:
+      if (obj->as.u16 <= 32767) {
+        *s = obj->as.u16;
+        return true;
+      }
+    default:
+        return false;
+  }
+}
+
+bool cmp_object_as_int(cmp_object_t *obj, int32_t *i) {
+  switch (obj->type) {
+    case CMP_TYPE_POSITIVE_FIXNUM:
+    case CMP_TYPE_NEGATIVE_FIXNUM:
+    case CMP_TYPE_SINT8:
+      *i = obj->as.s8;
+      return true;
+    case CMP_TYPE_UINT8:
+      *i = obj->as.u8;
+      return true;
+    case CMP_TYPE_SINT16:
+      *i = obj->as.s16;
+      return true;
+    case CMP_TYPE_UINT16:
+      *i = obj->as.u16;
+      return true;
+    case CMP_TYPE_SINT32:
+      *i = obj->as.s32;
+      return true;
+    case CMP_TYPE_UINT32:
+      if (obj->as.u32 <= 2147483647) {
+        *i = obj->as.u32;
+        return true;
+      }
+    default:
+        return false;
+  }
+}
+
+bool cmp_object_as_long(cmp_object_t *obj, int64_t *d) {
+  switch (obj->type) {
+    case CMP_TYPE_POSITIVE_FIXNUM:
+    case CMP_TYPE_NEGATIVE_FIXNUM:
+    case CMP_TYPE_SINT8:
+      *d = obj->as.s8;
+      return true;
+    case CMP_TYPE_UINT8:
+      *d = obj->as.u8;
+      return true;
+    case CMP_TYPE_SINT16:
+      *d = obj->as.s16;
+      return true;
+    case CMP_TYPE_UINT16:
+      *d = obj->as.u16;
+      return true;
+    case CMP_TYPE_SINT32:
+      *d = obj->as.s32;
+      return true;
+    case CMP_TYPE_UINT32:
+      *d = obj->as.u32;
+      return true;
+    case CMP_TYPE_SINT64:
+      *d = obj->as.s64;
+      return true;
+    case CMP_TYPE_UINT64:
+      if (obj->as.u64 <= 9223372036854775807) {
+        *d = obj->as.u64;
+        return true;
+      }
+    default:
+        return false;
+  }
+}
+
+bool cmp_object_as_sinteger(cmp_object_t *obj, int64_t *d) {
+  return cmp_object_as_long(obj, d);
+}
+
+bool cmp_object_as_uchar(cmp_object_t *obj, uint8_t *c) {
+  switch (obj->type) {
+    case CMP_TYPE_POSITIVE_FIXNUM:
+    case CMP_TYPE_UINT8:
+      *c = obj->as.u8;
+      return true;
+    default:
+        return false;
+  }
+}
+
+bool cmp_object_as_ushort(cmp_object_t *obj, uint16_t *s) {
+  switch (obj->type) {
+    case CMP_TYPE_POSITIVE_FIXNUM:
+    case CMP_TYPE_UINT8:
+      *s = obj->as.u8;
+      return true;
+    case CMP_TYPE_UINT16:
+      *s = obj->as.u16;
+      return true;
+    default:
+        return false;
+  }
+}
+
+bool cmp_object_as_uint(cmp_object_t *obj, uint32_t *i) {
+  switch (obj->type) {
+    case CMP_TYPE_POSITIVE_FIXNUM:
+    case CMP_TYPE_UINT8:
+      *i = obj->as.u8;
+      return true;
+    case CMP_TYPE_UINT16:
+      *i = obj->as.u16;
+      return true;
+    case CMP_TYPE_UINT32:
+      *i = obj->as.u32;
+      return true;
+    default:
+        return false;
+  }
+}
+
+bool cmp_object_as_ulong(cmp_object_t *obj, uint64_t *u) {
+  switch (obj->type) {
+    case CMP_TYPE_POSITIVE_FIXNUM:
+    case CMP_TYPE_UINT8:
+      *u = obj->as.u8;
+      return true;
+    case CMP_TYPE_UINT16:
+      *u = obj->as.u16;
+      return true;
+    case CMP_TYPE_UINT32:
+      *u = obj->as.u32;
+      return true;
+    case CMP_TYPE_UINT64:
+      *u = obj->as.u64;
+      return true;
+    default:
+        return false;
+  }
+}
+
+bool cmp_object_as_uinteger(cmp_object_t *obj, uint64_t *d) {
+  return cmp_object_as_ulong(obj, d);
+}
+
+bool cmp_object_as_float(cmp_object_t *obj, float *f) {
+  if (obj->type == CMP_TYPE_FLOAT) {
+    *f = obj->as.flt;
+    return true;
+  }
+
+  return false;
+}
+
+bool cmp_object_as_double(cmp_object_t *obj, double *d) {
+  if (obj->type == CMP_TYPE_DOUBLE) {
+    *d = obj->as.dbl;
+    return true;
+  }
+
+  return false;
+}
+
+bool cmp_object_as_bool(cmp_object_t *obj, bool *b) {
+  if (obj->type == CMP_TYPE_BOOLEAN) {
+    if (obj->as.boolean)
+      *b = true;
+    else
+      *b = false;
+
+    return true;
+  }
+
+  return false;
+}
+
+bool cmp_object_as_str(cmp_object_t *obj, uint32_t *size) {
+  switch (obj->type) {
+    case CMP_TYPE_FIXSTR:
+    case CMP_TYPE_STR8:
+    case CMP_TYPE_STR16:
+    case CMP_TYPE_STR32:
+      *size = obj->as.str_size;
+      return true;
+    default:
+        return false;
+  }
+}
+
+bool cmp_object_as_bin(cmp_object_t *obj, uint32_t *size) {
+  switch (obj->type) {
+    case CMP_TYPE_BIN8:
+    case CMP_TYPE_BIN16:
+    case CMP_TYPE_BIN32:
+      *size = obj->as.bin_size;
+      return true;
+    default:
+        return false;
+  }
+}
+
+bool cmp_object_as_array(cmp_object_t *obj, uint32_t *size) {
+  switch (obj->type) {
+    case CMP_TYPE_FIXARRAY:
+    case CMP_TYPE_ARRAY16:
+    case CMP_TYPE_ARRAY32:
+      *size = obj->as.array_size;
+      return true;
+    default:
+        return false;
+  }
+}
+
+bool cmp_object_as_map(cmp_object_t *obj, uint32_t *size) {
+  switch (obj->type) {
+    case CMP_TYPE_FIXMAP:
+    case CMP_TYPE_MAP16:
+    case CMP_TYPE_MAP32:
+      *size = obj->as.map_size;
+      return true;
+    default:
+        return false;
+  }
+}
+
+bool cmp_object_as_ext(cmp_object_t *obj, int8_t *type, uint32_t *size) {
+  switch (obj->type) {
+    case CMP_TYPE_FIXEXT1:
+    case CMP_TYPE_FIXEXT2:
+    case CMP_TYPE_FIXEXT4:
+    case CMP_TYPE_FIXEXT8:
+    case CMP_TYPE_FIXEXT16:
+    case CMP_TYPE_EXT8:
+    case CMP_TYPE_EXT16:
+    case CMP_TYPE_EXT32:
+      *type = obj->as.ext.type;
+      *size = obj->as.ext.size;
+      return true;
+    default:
+        return false;
+  }
+}
+
+/* vi: set et ts=2 sw=2: */
+

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/33ab96fb/htrace-c/src/util/cmp.h
----------------------------------------------------------------------
diff --git a/htrace-c/src/util/cmp.h b/htrace-c/src/util/cmp.h
new file mode 100644
index 0000000..c94efd0
--- /dev/null
+++ b/htrace-c/src/util/cmp.h
@@ -0,0 +1,441 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Charles Gunyon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef CMP_H__
+#define CMP_H__
+
+#include <stdint.h> /* for uint32_t, etc. */
+#include <unistd.h> /* for size_t */
+
+// Define bool, true, false, etc. to avoid adding a dependency on C99
+// that we don't really need.
+#undef bool
+#define bool int
+#undef true
+#define true 1
+#undef false
+#define false 0
+
+struct cmp_ctx_s;
+
+typedef bool   (*cmp_reader)(struct cmp_ctx_s *ctx, void *data, size_t limit);
+typedef size_t (*cmp_writer)(struct cmp_ctx_s *ctx, const void *data,
+                                                    size_t count);
+
+enum {
+  CMP_TYPE_POSITIVE_FIXNUM, /*  0 */
+  CMP_TYPE_FIXMAP,          /*  1 */
+  CMP_TYPE_FIXARRAY,        /*  2 */
+  CMP_TYPE_FIXSTR,          /*  3 */
+  CMP_TYPE_NIL,             /*  4 */
+  CMP_TYPE_BOOLEAN,         /*  5 */
+  CMP_TYPE_BIN8,            /*  6 */
+  CMP_TYPE_BIN16,           /*  7 */
+  CMP_TYPE_BIN32,           /*  8 */
+  CMP_TYPE_EXT8,            /*  9 */
+  CMP_TYPE_EXT16,           /* 10 */
+  CMP_TYPE_EXT32,           /* 11 */
+  CMP_TYPE_FLOAT,           /* 12 */
+  CMP_TYPE_DOUBLE,          /* 13 */
+  CMP_TYPE_UINT8,           /* 14 */
+  CMP_TYPE_UINT16,          /* 15 */
+  CMP_TYPE_UINT32,          /* 16 */
+  CMP_TYPE_UINT64,          /* 17 */
+  CMP_TYPE_SINT8,           /* 18 */
+  CMP_TYPE_SINT16,          /* 19 */
+  CMP_TYPE_SINT32,          /* 20 */
+  CMP_TYPE_SINT64,          /* 21 */
+  CMP_TYPE_FIXEXT1,         /* 22 */
+  CMP_TYPE_FIXEXT2,         /* 23 */
+  CMP_TYPE_FIXEXT4,         /* 24 */
+  CMP_TYPE_FIXEXT8,         /* 25 */
+  CMP_TYPE_FIXEXT16,        /* 26 */
+  CMP_TYPE_STR8,            /* 27 */
+  CMP_TYPE_STR16,           /* 28 */
+  CMP_TYPE_STR32,           /* 29 */
+  CMP_TYPE_ARRAY16,         /* 30 */
+  CMP_TYPE_ARRAY32,         /* 31 */
+  CMP_TYPE_MAP16,           /* 32 */
+  CMP_TYPE_MAP32,           /* 33 */
+  CMP_TYPE_NEGATIVE_FIXNUM  /* 34 */
+};
+
+typedef struct cmp_ext_s {
+  int8_t type;
+  uint32_t size;
+} cmp_ext_t;
+
+union cmp_object_data_u {
+  bool      boolean;
+  uint8_t   u8;
+  uint16_t  u16;
+  uint32_t  u32;
+  uint64_t  u64;
+  int8_t    s8;
+  int16_t   s16;
+  int32_t   s32;
+  int64_t   s64;
+  float     flt;
+  double    dbl;
+  uint32_t  array_size;
+  uint32_t  map_size;
+  uint32_t  str_size;
+  uint32_t  bin_size;
+  cmp_ext_t ext;
+};
+
+typedef struct cmp_ctx_s {
+  uint8_t     error;
+  void       *buf;
+  cmp_reader  read;
+  cmp_writer  write;
+} cmp_ctx_t;
+
+typedef struct cmp_object_s {
+  uint8_t type;
+  union cmp_object_data_u as;
+} cmp_object_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * ============================================================================
+ * === Main API
+ * ============================================================================
+ */
+
+/* Initializes a CMP context */
+void cmp_init(cmp_ctx_t *ctx, void *buf, cmp_reader read, cmp_writer write);
+
+/* Returns CMP's version */
+uint32_t cmp_version(void);
+
+/* Returns the MessagePack version employed by CMP */
+uint32_t cmp_mp_version(void);
+
+/* Returns a string description of a CMP context's error */
+const char* cmp_strerror(cmp_ctx_t *ctx);
+
+/* Writes a signed integer to the backend */
+bool cmp_write_sint(cmp_ctx_t *ctx, int64_t d);
+
+/* Writes an unsigned integer to the backend */
+bool cmp_write_uint(cmp_ctx_t *ctx, uint64_t u);
+
+/* Writes a single-precision float to the backend */
+bool cmp_write_float(cmp_ctx_t *ctx, float f);
+
+/* Writes a double-precision float to the backend */
+bool cmp_write_double(cmp_ctx_t *ctx, double d);
+
+/* Writes NULL to the backend */
+bool cmp_write_nil(cmp_ctx_t *ctx);
+
+/* Writes true to the backend */
+bool cmp_write_true(cmp_ctx_t *ctx);
+
+/* Writes false to the backend */
+bool cmp_write_false(cmp_ctx_t *ctx);
+
+/* Writes a boolean value to the backend */
+bool cmp_write_bool(cmp_ctx_t *ctx, bool b);
+
+/*
+ * Writes an unsigned char's value to the backend as a boolean.  This is useful
+ * if you are using a different boolean type in your application.
+ */
+bool cmp_write_u8_as_bool(cmp_ctx_t *ctx, uint8_t b);
+
+/*
+ * Writes a string to the backend; according to the MessagePack spec, this must
+ * be encoded using UTF-8, but CMP leaves that job up to the programmer.
+ */
+bool cmp_write_str(cmp_ctx_t *ctx, const char *data, uint32_t size);
+
+/*
+ * Writes the string marker to the backend.  This is useful if you are writing
+ * data in chunks instead of a single shot.
+ */
+bool cmp_write_str_marker(cmp_ctx_t *ctx, uint32_t size);
+
+/* Writes binary data to the backend */
+bool cmp_write_bin(cmp_ctx_t *ctx, const void *data, uint32_t size);
+
+/*
+ * Writes the binary data marker to the backend.  This is useful if you are
+ * writing data in chunks instead of a single shot.
+ */
+bool cmp_write_bin_marker(cmp_ctx_t *ctx, uint32_t size);
+
+/* Writes an array to the backend. */
+bool cmp_write_array(cmp_ctx_t *ctx, uint32_t size);
+
+/* Writes a map to the backend. */
+bool cmp_write_map(cmp_ctx_t *ctx, uint32_t size);
+
+/* Writes an extended type to the backend */
+bool cmp_write_ext(cmp_ctx_t *ctx, int8_t type, uint32_t size,
+                                   const void *data);
+
+/*
+ * Writes the extended type marker to the backend.  This is useful if you want
+ * to write the type's data in chunks instead of a single shot.
+ */
+bool cmp_write_ext_marker(cmp_ctx_t *ctx, int8_t type, uint32_t size);
+
+/* Writes an object to the backend */
+bool cmp_write_object(cmp_ctx_t *ctx, cmp_object_t *obj);
+
+/* Reads a signed integer that fits inside a signed char */
+bool cmp_read_char(cmp_ctx_t *ctx, int8_t *c);
+
+/* Reads a signed integer that fits inside a signed short */
+bool cmp_read_short(cmp_ctx_t *ctx, int16_t *s);
+
+/* Reads a signed integer that fits inside a signed int */
+bool cmp_read_int(cmp_ctx_t *ctx, int32_t *i);
+
+/* Reads a signed integer that fits inside a signed long */
+bool cmp_read_long(cmp_ctx_t *ctx, int64_t *d);
+
+/* Reads a signed integer */
+bool cmp_read_sinteger(cmp_ctx_t *ctx, int64_t *d);
+
+/* Reads an unsigned integer that fits inside an unsigned char */
+bool cmp_read_uchar(cmp_ctx_t *ctx, uint8_t *c);
+
+/* Reads an unsigned integer that fits inside an unsigned short */
+bool cmp_read_ushort(cmp_ctx_t *ctx, uint16_t *s);
+
+/* Reads an unsigned integer that fits inside an unsigned int */
+bool cmp_read_uint(cmp_ctx_t *ctx, uint32_t *i);
+
+/* Reads an unsigned integer that fits inside an unsigned long */
+bool cmp_read_ulong(cmp_ctx_t *ctx, uint64_t *u);
+
+/* Reads an unsigned integer */
+bool cmp_read_uinteger(cmp_ctx_t *ctx, uint64_t *u);
+
+/* Reads a single-precision float from the backend */
+bool cmp_read_float(cmp_ctx_t *ctx, float *f);
+
+/* Reads a double-precision float from the backend */
+bool cmp_read_double(cmp_ctx_t *ctx, double *d);
+
+/* "Reads" (more like "skips") a NULL value from the backend */
+bool cmp_read_nil(cmp_ctx_t *ctx);
+
+/* Reads a boolean from the backend */
+bool cmp_read_bool(cmp_ctx_t *ctx, bool *b);
+
+/*
+ * Reads a boolean as an unsigned char from the backend; this is useful if your
+ * application uses a different boolean type.
+ */
+bool cmp_read_bool_as_u8(cmp_ctx_t *ctx, uint8_t *b);
+
+/* Reads a string's size from the backend */
+bool cmp_read_str_size(cmp_ctx_t *ctx, uint32_t *size);
+
+/*
+ * Reads a string from the backend; according to the spec, the string's data
+ * ought to be encoded using UTF-8, 
+ */
+bool cmp_read_str(cmp_ctx_t *ctx, char *data, uint32_t *size);
+
+/* Reads the size of packed binary data from the backend */
+bool cmp_read_bin_size(cmp_ctx_t *ctx, uint32_t *size);
+
+/* Reads packed binary data from the backend */
+bool cmp_read_bin(cmp_ctx_t *ctx, void *data, uint32_t *size);
+
+/* Reads an array from the backend */
+bool cmp_read_array(cmp_ctx_t *ctx, uint32_t *size);
+
+/* Reads a map from the backend */
+bool cmp_read_map(cmp_ctx_t *ctx, uint32_t *size);
+
+/* Reads the extended type's marker from the backend */
+bool cmp_read_ext_marker(cmp_ctx_t *ctx, int8_t *type, uint32_t *size);
+
+/* Reads an extended type from the backend */
+bool cmp_read_ext(cmp_ctx_t *ctx, int8_t *type, uint32_t *size, void *data);
+
+/* Reads an object from the backend */
+bool cmp_read_object(cmp_ctx_t *ctx, cmp_object_t *obj);
+
+/*
+ * ============================================================================
+ * === Specific API
+ * ============================================================================
+ */
+
+bool cmp_write_pfix(cmp_ctx_t *ctx, uint8_t c);
+bool cmp_write_nfix(cmp_ctx_t *ctx, int8_t c);
+
+bool cmp_write_sfix(cmp_ctx_t *ctx, int8_t c);
+bool cmp_write_s8(cmp_ctx_t *ctx, int8_t c);
+bool cmp_write_s16(cmp_ctx_t *ctx, int16_t s);
+bool cmp_write_s32(cmp_ctx_t *ctx, int32_t i);
+bool cmp_write_s64(cmp_ctx_t *ctx, int64_t l);
+
+bool cmp_write_ufix(cmp_ctx_t *ctx, uint8_t c);
+bool cmp_write_u8(cmp_ctx_t *ctx, uint8_t c);
+bool cmp_write_u16(cmp_ctx_t *ctx, uint16_t s);
+bool cmp_write_u32(cmp_ctx_t *ctx, uint32_t i);
+bool cmp_write_u64(cmp_ctx_t *ctx, uint64_t l);
+
+bool cmp_write_fixstr_marker(cmp_ctx_t *ctx, uint8_t size);
+bool cmp_write_fixstr(cmp_ctx_t *ctx, const char *data, uint8_t size);
+bool cmp_write_str8_marker(cmp_ctx_t *ctx, uint8_t size);
+bool cmp_write_str8(cmp_ctx_t *ctx, const char *data, uint8_t size);
+bool cmp_write_str16_marker(cmp_ctx_t *ctx, uint16_t size);
+bool cmp_write_str16(cmp_ctx_t *ctx, const char *data, uint16_t size);
+bool cmp_write_str32_marker(cmp_ctx_t *ctx, uint32_t size);
+bool cmp_write_str32(cmp_ctx_t *ctx, const char *data, uint32_t size);
+
+bool cmp_write_bin8_marker(cmp_ctx_t *ctx, uint8_t size);
+bool cmp_write_bin8(cmp_ctx_t *ctx, const void *data, uint8_t size);
+bool cmp_write_bin16_marker(cmp_ctx_t *ctx, uint16_t size);
+bool cmp_write_bin16(cmp_ctx_t *ctx, const void *data, uint16_t size);
+bool cmp_write_bin32_marker(cmp_ctx_t *ctx, uint32_t size);
+bool cmp_write_bin32(cmp_ctx_t *ctx, const void *data, uint32_t size);
+
+bool cmp_write_fixarray(cmp_ctx_t *ctx, uint8_t size);
+bool cmp_write_array16(cmp_ctx_t *ctx, uint16_t size);
+bool cmp_write_array32(cmp_ctx_t *ctx, uint32_t size);
+
+bool cmp_write_fixmap(cmp_ctx_t *ctx, uint8_t size);
+bool cmp_write_map16(cmp_ctx_t *ctx, uint16_t size);
+bool cmp_write_map32(cmp_ctx_t *ctx, uint32_t size);
+
+bool cmp_write_fixext1_marker(cmp_ctx_t *ctx, int8_t type);
+bool cmp_write_fixext1(cmp_ctx_t *ctx, int8_t type, const void *data);
+bool cmp_write_fixext2_marker(cmp_ctx_t *ctx, int8_t type);
+bool cmp_write_fixext2(cmp_ctx_t *ctx, int8_t type, const void *data);
+bool cmp_write_fixext4_marker(cmp_ctx_t *ctx, int8_t type);
+bool cmp_write_fixext4(cmp_ctx_t *ctx, int8_t type, const void *data);
+bool cmp_write_fixext8_marker(cmp_ctx_t *ctx, int8_t type);
+bool cmp_write_fixext8(cmp_ctx_t *ctx, int8_t type, const void *data);
+bool cmp_write_fixext16_marker(cmp_ctx_t *ctx, int8_t type);
+bool cmp_write_fixext16(cmp_ctx_t *ctx, int8_t type, const void *data);
+
+bool cmp_write_ext8_marker(cmp_ctx_t *ctx, int8_t type, uint8_t size);
+bool cmp_write_ext8(cmp_ctx_t *ctx, int8_t type, uint8_t size,
+                                    const void *data);
+bool cmp_write_ext16_marker(cmp_ctx_t *ctx, int8_t type, uint16_t size);
+bool cmp_write_ext16(cmp_ctx_t *ctx, int8_t type, uint16_t size,
+                                     const void *data);
+bool cmp_write_ext32_marker(cmp_ctx_t *ctx, int8_t type, uint32_t size);
+bool cmp_write_ext32(cmp_ctx_t *ctx, int8_t type, uint32_t size,
+                                     const void *data);
+
+bool cmp_read_pfix(cmp_ctx_t *ctx, uint8_t *c);
+bool cmp_read_nfix(cmp_ctx_t *ctx, int8_t *c);
+
+bool cmp_read_sfix(cmp_ctx_t *ctx, int8_t *c);
+bool cmp_read_s8(cmp_ctx_t *ctx, int8_t *c);
+bool cmp_read_s16(cmp_ctx_t *ctx, int16_t *s);
+bool cmp_read_s32(cmp_ctx_t *ctx, int32_t *i);
+bool cmp_read_s64(cmp_ctx_t *ctx, int64_t *l);
+
+bool cmp_read_ufix(cmp_ctx_t *ctx, uint8_t *c);
+bool cmp_read_u8(cmp_ctx_t *ctx, uint8_t *c);
+bool cmp_read_u16(cmp_ctx_t *ctx, uint16_t *s);
+bool cmp_read_u32(cmp_ctx_t *ctx, uint32_t *i);
+bool cmp_read_u64(cmp_ctx_t *ctx, uint64_t *l);
+
+bool cmp_read_fixext1_marker(cmp_ctx_t *ctx, int8_t *type);
+bool cmp_read_fixext1(cmp_ctx_t *ctx, int8_t *type, void *data);
+bool cmp_read_fixext2_marker(cmp_ctx_t *ctx, int8_t *type);
+bool cmp_read_fixext2(cmp_ctx_t *ctx, int8_t *type, void *data);
+bool cmp_read_fixext4_marker(cmp_ctx_t *ctx, int8_t *type);
+bool cmp_read_fixext4(cmp_ctx_t *ctx, int8_t *type, void *data);
+bool cmp_read_fixext8_marker(cmp_ctx_t *ctx, int8_t *type);
+bool cmp_read_fixext8(cmp_ctx_t *ctx, int8_t *type, void *data);
+bool cmp_read_fixext16_marker(cmp_ctx_t *ctx, int8_t *type);
+bool cmp_read_fixext16(cmp_ctx_t *ctx, int8_t *type, void *data);
+
+bool cmp_read_ext8_marker(cmp_ctx_t *ctx, int8_t *type, uint8_t *size);
+bool cmp_read_ext8(cmp_ctx_t *ctx, int8_t *type, uint8_t *size, void *data);
+bool cmp_read_ext16_marker(cmp_ctx_t *ctx, int8_t *type, uint16_t *size);
+bool cmp_read_ext16(cmp_ctx_t *ctx, int8_t *type, uint16_t *size, void *data);
+bool cmp_read_ext32_marker(cmp_ctx_t *ctx, int8_t *type, uint32_t *size);
+bool cmp_read_ext32(cmp_ctx_t *ctx, int8_t *type, uint32_t *size, void *data);
+
+/*
+ * ============================================================================
+ * === Object API
+ * ============================================================================
+ */
+
+bool cmp_object_is_char(cmp_object_t *obj);
+bool cmp_object_is_short(cmp_object_t *obj);
+bool cmp_object_is_int(cmp_object_t *obj);
+bool cmp_object_is_long(cmp_object_t *obj);
+bool cmp_object_is_sinteger(cmp_object_t *obj);
+bool cmp_object_is_uchar(cmp_object_t *obj);
+bool cmp_object_is_ushort(cmp_object_t *obj);
+bool cmp_object_is_uint(cmp_object_t *obj);
+bool cmp_object_is_ulong(cmp_object_t *obj);
+bool cmp_object_is_uinteger(cmp_object_t *obj);
+bool cmp_object_is_float(cmp_object_t *obj);
+bool cmp_object_is_double(cmp_object_t *obj);
+bool cmp_object_is_nil(cmp_object_t *obj);
+bool cmp_object_is_bool(cmp_object_t *obj);
+bool cmp_object_is_str(cmp_object_t *obj);
+bool cmp_object_is_bin(cmp_object_t *obj);
+bool cmp_object_is_array(cmp_object_t *obj);
+bool cmp_object_is_map(cmp_object_t *obj);
+bool cmp_object_is_ext(cmp_object_t *obj);
+
+bool cmp_object_as_char(cmp_object_t *obj, int8_t *c);
+bool cmp_object_as_short(cmp_object_t *obj, int16_t *s);
+bool cmp_object_as_int(cmp_object_t *obj, int32_t *i);
+bool cmp_object_as_long(cmp_object_t *obj, int64_t *d);
+bool cmp_object_as_sinteger(cmp_object_t *obj, int64_t *d);
+bool cmp_object_as_uchar(cmp_object_t *obj, uint8_t *c);
+bool cmp_object_as_ushort(cmp_object_t *obj, uint16_t *s);
+bool cmp_object_as_uint(cmp_object_t *obj, uint32_t *i);
+bool cmp_object_as_ulong(cmp_object_t *obj, uint64_t *u);
+bool cmp_object_as_uinteger(cmp_object_t *obj, uint64_t *u);
+bool cmp_object_as_float(cmp_object_t *obj, float *f);
+bool cmp_object_as_double(cmp_object_t *obj, double *d);
+bool cmp_object_as_bool(cmp_object_t *obj, bool *b);
+bool cmp_object_as_str(cmp_object_t *obj, uint32_t *size);
+bool cmp_object_as_bin(cmp_object_t *obj, uint32_t *size);
+bool cmp_object_as_array(cmp_object_t *obj, uint32_t *size);
+bool cmp_object_as_map(cmp_object_t *obj, uint32_t *size);
+bool cmp_object_as_ext(cmp_object_t *obj, int8_t *type, uint32_t *size);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* CMP_H__ */
+
+/* vi: set et ts=2 sw=2: */
+

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/33ab96fb/htrace-c/src/util/cmp_util.c
----------------------------------------------------------------------
diff --git a/htrace-c/src/util/cmp_util.c b/htrace-c/src/util/cmp_util.c
new file mode 100644
index 0000000..ec6d1e5
--- /dev/null
+++ b/htrace-c/src/util/cmp_util.c
@@ -0,0 +1,90 @@
+/**
+ * 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 "util/cmp_util.h"
+
+#include <stdint.h>
+#include <string.h>
+
+/**
+ * @file cmp_util.c
+ *
+ * Utilities for using the CMP library.
+ */
+
+static size_t cmp_counter_write_fn(struct cmp_ctx_s *c, const void *data,
+                                   size_t count)
+{
+    struct cmp_counter_ctx *ctx = (struct cmp_counter_ctx *)c;
+    ctx->count += count;
+    return count;
+}
+
+void cmp_counter_ctx_init(struct cmp_counter_ctx *ctx)
+{
+    cmp_init(&ctx->base, NULL, NULL, cmp_counter_write_fn);
+    ctx->count = 0;
+}
+
+static size_t cmp_bcopy_write_fn(struct cmp_ctx_s *c, const void *data,
+                                 size_t count)
+{
+    struct cmp_bcopy_ctx *ctx = (struct cmp_bcopy_ctx *)c;
+    uint64_t rem, o = ctx->off;
+
+    rem = ctx->len - o;
+    if (rem < count) {
+        count = rem;
+    }
+    memcpy(((uint8_t*)ctx->base.buf) + o, data, count);
+    ctx->off = o + count;
+    return count;
+}
+
+size_t cmp_bcopy_write_nocheck_fn(struct cmp_ctx_s *c, const void *data,
+                                  size_t count)
+{
+    struct cmp_bcopy_ctx *ctx = (struct cmp_bcopy_ctx *)c;
+    uint64_t o = ctx->off;
+    memcpy(((uint8_t*)ctx->base.buf) + o, data, count);
+    ctx->off = o + count;
+    return count;
+}
+
+static int cmp_bcopy_reader(struct cmp_ctx_s *c, void *data, size_t limit)
+{
+    struct cmp_bcopy_ctx *ctx = (struct cmp_bcopy_ctx *)c;
+    size_t count, o = ctx->off;
+
+    count = ctx->len - o;
+    if (count > limit) {
+        count = limit;
+    }
+    memcpy(data, ((uint8_t*)ctx->base.buf) + o, count);
+    ctx->off = o + count;
+    return count;
+}
+
+void cmp_bcopy_ctx_init(struct cmp_bcopy_ctx *ctx, void *buf, uint64_t len)
+{
+    cmp_init(&ctx->base, buf, cmp_bcopy_reader, cmp_bcopy_write_fn);
+    ctx->off = 0;
+    ctx->len = len;
+}
+
+// vim:ts=4:sw=4:et

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/33ab96fb/htrace-c/src/util/cmp_util.h
----------------------------------------------------------------------
diff --git a/htrace-c/src/util/cmp_util.h b/htrace-c/src/util/cmp_util.h
new file mode 100644
index 0000000..0164244
--- /dev/null
+++ b/htrace-c/src/util/cmp_util.h
@@ -0,0 +1,76 @@
+/**
+ * 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 APACHE_HTRACE_UTIL_CMP_UTIL_H
+#define APACHE_HTRACE_UTIL_CMP_UTIL_H
+
+/**
+ * @file cmp_util.h
+ *
+ * Utilities for using the CMP library.
+ *
+ * This is an internal header, not intended for external use.
+ */
+
+#include "util/cmp.h"
+
+#include <stdint.h> /* for uint64_t */
+
+/**
+ * CMP context for counting the number of bytes in the serialized form.
+ */
+struct cmp_counter_ctx {
+    cmp_ctx_t base;
+    uint64_t count;
+};
+
+/**
+ * Initialize a CMP counter ctx.
+ * This doesn't allocate any memory.
+ *
+ * @param ctx           The context to initialize.
+ */
+void cmp_counter_ctx_init(struct cmp_counter_ctx *ctx);
+
+/**
+ * CMP context for counting the number of bytes in the serialized form.
+ */
+struct cmp_bcopy_ctx {
+    cmp_ctx_t base;
+    uint64_t off;
+    uint64_t len;
+};
+
+/**
+ * Initialize a CMP writer ctx.
+ * This doesn't allocate any memory.
+ *
+ * @param ctx           The context to initialize.
+ */
+void cmp_bcopy_ctx_init(struct cmp_bcopy_ctx *ctx, void *buf, uint64_t len);
+
+/**
+ * A version of the bcopy write function that does not perform bounds checking.
+ * Useful if the serialized size has already been determined.
+ */
+size_t cmp_bcopy_write_nocheck_fn(struct cmp_ctx_s *c, const void *data,
+                                  size_t count);
+
+#endif
+
+// vim: ts=4:sw=4:tw=79:et

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/33ab96fb/htrace-htraced/src/go/Godeps/Godeps.json
----------------------------------------------------------------------
diff --git a/htrace-htraced/src/go/Godeps/Godeps.json 
b/htrace-htraced/src/go/Godeps/Godeps.json
index 10c8e5d..0677fd2 100644
--- a/htrace-htraced/src/go/Godeps/Godeps.json
+++ b/htrace-htraced/src/go/Godeps/Godeps.json
@@ -21,6 +21,10 @@
         {
             "ImportPath": "github.com/jmhodges/levigo",
             "Rev": "2c43dde93d0e056173706534afd514fcbc1dd578"
+        },
+        {
+            "ImportPath": "github.com/ugorji/go",
+            "Rev": "08bbe4aa39b9f189f4e294b5c8408b5fa5787bb2"
         }
     ]
 }

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/33ab96fb/htrace-htraced/src/go/gobuild.sh
----------------------------------------------------------------------
diff --git a/htrace-htraced/src/go/gobuild.sh b/htrace-htraced/src/go/gobuild.sh
index 1a4e5f1..81c9f7d 100755
--- a/htrace-htraced/src/go/gobuild.sh
+++ b/htrace-htraced/src/go/gobuild.sh
@@ -47,6 +47,11 @@ mkdir -p "${GOBIN}" || die "failed to mkdir -p ${GOBIN}"
 cd "${GOBIN}" || die "failed to cd to ${SCRIPT_DIR}"
 export GOPATH="${GOBIN}:${SCRIPT_DIR}"
 
+# Use the unsafe package when possible to get greater speed.  For example,
+# go-codec can bypass the overhead of converting between []byte and string in
+# some cases when using unsafe.
+TAGS="-tags unsafe"
+
 # Check for go
 which go &> /dev/null
 if [ $? -ne 0 ]; then
@@ -100,12 +105,12 @@ install)
 
     # Inject the release and git version into the htraced ldflags.
     FLAGS="-X main.RELEASE_VERSION ${RELEASE_VERSION} -X main.GIT_VERSION 
${GIT_VERSION}"
-    go install -ldflags "${FLAGS}" -v org/apache/htrace/... "$@"
+    go install ${TAGS} -ldflags "${FLAGS}" -v org/apache/htrace/... "$@"
     ;;
 bench)
-    go test org/apache/htrace/... -test.bench=. "$@"
+    go test org/apache/htrace/... ${TAGS} -test.bench=. "$@"
     ;;
 *)
-    go ${ACTION} org/apache/htrace/... "$@"
+    go ${ACTION} org/apache/htrace/... ${TAGS} "$@"
     ;;
 esac

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/33ab96fb/htrace-htraced/src/go/src/org/apache/htrace/client/hclient.go
----------------------------------------------------------------------
diff --git a/htrace-htraced/src/go/src/org/apache/htrace/client/hclient.go 
b/htrace-htraced/src/go/src/org/apache/htrace/client/hclient.go
index 5406d73..608dd59 100644
--- a/htrace-htraced/src/go/src/org/apache/htrace/client/hclient.go
+++ b/htrace-htraced/src/go/src/org/apache/htrace/client/hclient.go
@@ -20,10 +20,11 @@
 package client
 
 import (
+       "bytes"
        "encoding/binary"
-       "encoding/json"
        "errors"
        "fmt"
+       "github.com/ugorji/go/codec"
        "io"
        "net"
        "net/rpc"
@@ -45,11 +46,16 @@ func (cdc *HrpcClientCodec) WriteRequest(req *rpc.Request, 
msg interface{}) erro
                return errors.New(fmt.Sprintf("HrpcClientCodec: Unknown method 
name %s",
                        req.ServiceMethod))
        }
-       buf, err := json.Marshal(msg)
+       mh := new(codec.MsgpackHandle)
+       mh.WriteExt = true
+       w := bytes.NewBuffer(make([]byte, 0, 2048))
+       enc := codec.NewEncoder(w, mh)
+       err := enc.Encode(msg)
        if err != nil {
                return errors.New(fmt.Sprintf("HrpcClientCodec: Unable to 
marshal "+
-                       "message as JSON: %s", err.Error()))
+                       "message as msgpack: %s", err.Error()))
        }
+       buf := w.Bytes()
        if len(buf) > common.MAX_HRPC_BODY_LENGTH {
                return errors.New(fmt.Sprintf("HrpcClientCodec: message body is 
%d "+
                        "bytes, but the maximum message size is %d bytes.",
@@ -115,7 +121,9 @@ func (cdc *HrpcClientCodec) ReadResponseHeader(resp 
*rpc.Response) error {
 }
 
 func (cdc *HrpcClientCodec) ReadResponseBody(body interface{}) error {
-       dec := json.NewDecoder(io.LimitReader(cdc.rwc, int64(cdc.length)))
+       mh := new(codec.MsgpackHandle)
+       mh.WriteExt = true
+       dec := codec.NewDecoder(io.LimitReader(cdc.rwc, int64(cdc.length)), mh)
        err := dec.Decode(body)
        if err != nil {
                return errors.New(fmt.Sprintf("Failed to read response body: 
%s",

http://git-wip-us.apache.org/repos/asf/incubator-htrace/blob/33ab96fb/htrace-htraced/src/go/src/org/apache/htrace/common/rpc.go
----------------------------------------------------------------------
diff --git a/htrace-htraced/src/go/src/org/apache/htrace/common/rpc.go 
b/htrace-htraced/src/go/src/org/apache/htrace/common/rpc.go
index cdf7e08..fe50a44 100644
--- a/htrace-htraced/src/go/src/org/apache/htrace/common/rpc.go
+++ b/htrace-htraced/src/go/src/org/apache/htrace/common/rpc.go
@@ -20,7 +20,7 @@
 package common
 
 // The 4-byte magic number which is sent first in the HRPC header
-const HRPC_MAGIC = 0x48545243
+const HRPC_MAGIC = 0x43525448
 
 // Method ID codes.  Do not reorder these.
 const (


Reply via email to