THRIFT-1313 implement compact protocol for c_glib library
Client: C_glib
Chandler May <cjmay4754@gmail.com>
This closes #795
diff --git a/lib/c_glib/CMakeLists.txt b/lib/c_glib/CMakeLists.txt
index 2c0ce76..b409fbe 100644
--- a/lib/c_glib/CMakeLists.txt
+++ b/lib/c_glib/CMakeLists.txt
@@ -37,6 +37,8 @@
src/thrift/c_glib/protocol/thrift_protocol_factory.c
src/thrift/c_glib/protocol/thrift_binary_protocol.c
src/thrift/c_glib/protocol/thrift_binary_protocol_factory.c
+ src/thrift/c_glib/protocol/thrift_compact_protocol.c
+ src/thrift/c_glib/protocol/thrift_compact_protocol_factory.c
src/thrift/c_glib/transport/thrift_transport.c
src/thrift/c_glib/transport/thrift_transport_factory.c
src/thrift/c_glib/transport/thrift_buffered_transport_factory.c
diff --git a/lib/c_glib/Makefile.am b/lib/c_glib/Makefile.am
index 153d14b..71cb283 100755
--- a/lib/c_glib/Makefile.am
+++ b/lib/c_glib/Makefile.am
@@ -38,6 +38,8 @@
src/thrift/c_glib/protocol/thrift_protocol_factory.c \
src/thrift/c_glib/protocol/thrift_binary_protocol.c \
src/thrift/c_glib/protocol/thrift_binary_protocol_factory.c \
+ src/thrift/c_glib/protocol/thrift_compact_protocol.c \
+ src/thrift/c_glib/protocol/thrift_compact_protocol_factory.c \
src/thrift/c_glib/transport/thrift_transport.c \
src/thrift/c_glib/transport/thrift_transport_factory.c \
src/thrift/c_glib/transport/thrift_buffered_transport_factory.c \
@@ -64,7 +66,9 @@
include_protocol_HEADERS = src/thrift/c_glib/protocol/thrift_protocol.h \
src/thrift/c_glib/protocol/thrift_protocol_factory.h \
src/thrift/c_glib/protocol/thrift_binary_protocol.h \
- src/thrift/c_glib/protocol/thrift_binary_protocol_factory.h
+ src/thrift/c_glib/protocol/thrift_binary_protocol_factory.h \
+ src/thrift/c_glib/protocol/thrift_compact_protocol.h \
+ src/thrift/c_glib/protocol/thrift_compact_protocol_factory.h
include_transportdir = $(include_thriftdir)/transport
include_transport_HEADERS = src/thrift/c_glib/transport/thrift_buffered_transport.h \
diff --git a/lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol.c b/lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol.c
new file mode 100644
index 0000000..1b36904
--- /dev/null
+++ b/lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol.c
@@ -0,0 +1,1605 @@
+/*
+ * 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 <string.h>
+#include <stdio.h>
+
+#include <thrift/c_glib/thrift.h>
+#include <thrift/c_glib/protocol/thrift_protocol.h>
+#include <thrift/c_glib/protocol/thrift_compact_protocol.h>
+
+/*
+ * *_to_zigzag depend on the fact that the right shift
+ * operator on a signed integer is an arithmetic (sign-extending) shift.
+ * If this is not the case, the current implementation will not work.
+ */
+#if !defined(SIGNED_RIGHT_SHIFT_IS) || !defined(ARITHMETIC_RIGHT_SHIFT)
+# error "Unable to determine the behavior of a signed right shift"
+#endif
+#if SIGNED_RIGHT_SHIFT_IS != ARITHMETIC_RIGHT_SHIFT
+# error "thrift_compact_protocol only works if signed right shift is arithmetic"
+#endif
+
+/* object properties */
+enum _ThriftCompactProtocolProperties
+{
+ PROP_0,
+ PROP_THRIFT_COMPACT_PROTOCOL_STRING_LIMIT,
+ PROP_THRIFT_COMPACT_PROTOCOL_CONTAINER_LIMIT
+};
+
+G_DEFINE_TYPE (ThriftCompactProtocol, thrift_compact_protocol,
+ THRIFT_TYPE_PROTOCOL)
+
+static const gint8 PROTOCOL_ID = (gint8)0x82u;
+static const gint8 VERSION_N = 1;
+static const gint8 VERSION_MASK = 0x1f; /* 0001 1111 */
+static const gint8 TYPE_MASK = (gint8)0xe0u; /* 1110 0000 */
+static const gint8 TYPE_BITS = 0x07; /* 0000 0111 */
+static const gint32 TYPE_SHIFT_AMOUNT = 5;
+
+enum Types {
+ CT_STOP = 0x00,
+ CT_BOOLEAN_TRUE = 0x01,
+ CT_BOOLEAN_FALSE = 0x02,
+ CT_BYTE = 0x03,
+ CT_I16 = 0x04,
+ CT_I32 = 0x05,
+ CT_I64 = 0x06,
+ CT_DOUBLE = 0x07,
+ CT_BINARY = 0x08,
+ CT_LIST = 0x09,
+ CT_SET = 0x0A,
+ CT_MAP = 0x0B,
+ CT_STRUCT = 0x0C
+};
+
+static const gint8 TTypeToCType[16] = {
+ CT_STOP, /* T_STOP */
+ 0, /* unused */
+ CT_BOOLEAN_TRUE, /* T_BOOL */
+ CT_BYTE, /* T_BYTE */
+ CT_DOUBLE, /* T_DOUBLE */
+ 0, /* unused */
+ CT_I16, /* T_I16 */
+ 0, /* unused */
+ CT_I32, /* T_I32 */
+ 0, /* unused */
+ CT_I64, /* T_I64 */
+ CT_BINARY, /* T_STRING */
+ CT_STRUCT, /* T_STRUCT */
+ CT_MAP, /* T_MAP */
+ CT_SET, /* T_SET */
+ CT_LIST, /* T_LIST */
+};
+
+static guint64
+thrift_bitwise_cast_guint64 (const gdouble v)
+{
+ union {
+ gdouble from;
+ guint64 to;
+ } u;
+ u.from = v;
+ return u.to;
+}
+
+static gdouble
+thrift_bitwise_cast_gdouble (const guint64 v)
+{
+ union {
+ guint64 from;
+ gdouble to;
+ } u;
+ u.from = v;
+ return u.to;
+}
+
+/**
+ * Convert l into a zigzag long. This allows negative numbers to be
+ * represented compactly as a varint.
+ */
+static guint64
+i64_to_zigzag (const gint64 l)
+{
+ return (l << 1) ^ (l >> 63);
+}
+
+/**
+ * Convert n into a zigzag int. This allows negative numbers to be
+ * represented compactly as a varint.
+ */
+static guint32
+i32_to_zigzag (const gint32 n)
+{
+ return (n << 1) ^ (n >> 31);
+}
+
+/**
+ * Convert from zigzag int to int.
+ */
+static gint32
+zigzag_to_i32 (guint32 n)
+{
+ return (n >> 1) ^ (guint32) (-(gint32) (n & 1));
+}
+
+/**
+ * Convert from zigzag long to long.
+ */
+static gint64
+zigzag_to_i64 (guint64 n)
+{
+ return (n >> 1) ^ (guint64) (-(gint64) (n & 1));
+}
+
+ThriftType thrift_compact_protocol_get_ttype (ThriftCompactProtocol *protocol,
+ const gint8 type, GError **error)
+{
+ THRIFT_UNUSED_VAR (protocol);
+
+ switch (type) {
+ case T_STOP:
+ return T_STOP;
+ case CT_BOOLEAN_FALSE:
+ case CT_BOOLEAN_TRUE:
+ return T_BOOL;
+ case CT_BYTE:
+ return T_BYTE;
+ case CT_I16:
+ return T_I16;
+ case CT_I32:
+ return T_I32;
+ case CT_I64:
+ return T_I64;
+ case CT_DOUBLE:
+ return T_DOUBLE;
+ case CT_BINARY:
+ return T_STRING;
+ case CT_LIST:
+ return T_LIST;
+ case CT_SET:
+ return T_SET;
+ case CT_MAP:
+ return T_MAP;
+ case CT_STRUCT:
+ return T_STRUCT;
+ default:
+ g_set_error (error, THRIFT_PROTOCOL_ERROR,
+ THRIFT_PROTOCOL_ERROR_INVALID_DATA,
+ "unrecognized type");
+ return -1;
+ }
+}
+
+/**
+ * Write an i32 as a varint. Results in 1-5 bytes on the wire.
+ */
+gint32
+thrift_compact_protocol_write_varint32 (ThriftCompactProtocol *protocol,
+ const guint32 n,
+ GError **error)
+{
+ guint8 buf[5];
+ gint32 xfer;
+ guint32 m;
+
+ THRIFT_UNUSED_VAR (error);
+
+ xfer = 0;
+ m = n;
+
+ while (TRUE) {
+ if ((m & ~0x7F) == 0) {
+ buf[xfer++] = (gint8)m;
+ break;
+ } else {
+ buf[xfer++] = (gint8)((m & 0x7F) | 0x80);
+ m >>= 7;
+ }
+ }
+
+ if (thrift_transport_write (THRIFT_PROTOCOL (protocol)->transport,
+ (const gpointer) buf, xfer, error)) {
+ return xfer;
+ } else {
+ return -1;
+ }
+}
+
+/**
+ * Write an i64 as a varint. Results in 1-10 bytes on the wire.
+ */
+gint32
+thrift_compact_protocol_write_varint64 (ThriftCompactProtocol *protocol,
+ const guint64 n,
+ GError **error)
+{
+ guint8 buf[10];
+ gint32 xfer;
+ guint64 m;
+
+ THRIFT_UNUSED_VAR (error);
+
+ xfer = 0;
+ m = n;
+
+ while (TRUE) {
+ if ((m & ~0x7FL) == 0) {
+ buf[xfer++] = (gint8)m;
+ break;
+ } else {
+ buf[xfer++] = (gint8)((m & 0x7F) | 0x80);
+ m >>= 7;
+ }
+ }
+
+ if (thrift_transport_write (THRIFT_PROTOCOL (protocol)->transport,
+ (const gpointer) buf, xfer, error)) {
+ return xfer;
+ } else {
+ return -1;
+ }
+}
+
+/**
+ * Read an i64 from the wire as a proper varint. The MSB of each byte is set
+ * if there is another byte to follow. This can read up to 10 bytes.
+ */
+gint32
+thrift_compact_protocol_read_varint64 (ThriftCompactProtocol *protocol,
+ gint64 *i64,
+ GError **error)
+{
+ gint32 ret;
+ gint32 xfer;
+ guint64 val;
+ gint shift;
+ guint8 byte;
+
+ xfer = 0;
+ val = 0;
+ shift = 0;
+ byte = 0;
+
+ while (TRUE) {
+ if ((ret = thrift_transport_read (THRIFT_PROTOCOL (protocol)->transport,
+ (gpointer) &byte, 1, error)) < 0) {
+ return -1;
+ }
+ ++xfer;
+ val |= (guint64)(byte & 0x7f) << shift;
+ shift += 7;
+ if (!(byte & 0x80)) {
+ *i64 = (gint64) val;
+ return xfer;
+ }
+ if (G_UNLIKELY (xfer == 10)) { /* 7 * 9 < 64 < 7 * 10 */
+ g_set_error (error, THRIFT_PROTOCOL_ERROR,
+ THRIFT_PROTOCOL_ERROR_INVALID_DATA,
+ "variable-length int over 10 bytes");
+ return -1;
+ }
+ }
+}
+
+/**
+ * Read an i32 from the wire as a varint. The MSB of each byte is set
+ * if there is another byte to follow. This can read up to 5 bytes.
+ */
+gint32
+thrift_compact_protocol_read_varint32 (ThriftCompactProtocol *protocol,
+ gint32 *i32,
+ GError **error)
+{
+ gint64 val;
+ gint32 ret;
+ gint32 xfer;
+
+ xfer = 0;
+
+ if ((ret = thrift_compact_protocol_read_varint64 (protocol, &val,
+ error)) < 0) {
+ return -1;
+ }
+ xfer += ret;
+
+ *i32 = (gint32)val;
+
+ return xfer;
+}
+
+gint32
+thrift_compact_protocol_write_field_begin_internal (ThriftCompactProtocol
+ *protocol,
+ const gchar *name,
+ const ThriftType field_type,
+ const gint16 field_id,
+ const gint8 type_override,
+ GError **error)
+{
+ gint32 ret;
+ gint32 xfer;
+ gint8 type_to_write;
+
+ THRIFT_UNUSED_VAR (name);
+
+ xfer = 0;
+
+ /* if there's a type override, use that. */
+ type_to_write
+ = (type_override == -1 ? TTypeToCType[field_type] : type_override);
+
+ /* check if we can use delta encoding for the field id */
+ if (field_id > protocol->_last_field_id
+ && field_id - protocol->_last_field_id <= 15) {
+ /* write them together */
+ if ((ret = thrift_protocol_write_byte (THRIFT_PROTOCOL (protocol),
+ (gint8) ((field_id
+ - protocol->_last_field_id)
+ << 4 | type_to_write),
+ error)) < 0) {
+ return -1;
+ }
+ xfer += ret;
+ } else {
+ /* write them separate */
+ if ((ret = thrift_protocol_write_byte (THRIFT_PROTOCOL (protocol),
+ type_to_write, error)) < 0) {
+ return -1;
+ }
+ xfer += ret;
+
+ if ((ret = thrift_protocol_write_i16 (THRIFT_PROTOCOL (protocol), field_id,
+ error)) < 0) {
+ return -1;
+ }
+ xfer += ret;
+ }
+
+ protocol->_last_field_id = field_id;
+ return xfer;
+}
+
+/**
+ * Method for writing the start of lists and sets. List and sets on
+ * the wire differ only by the type indicator.
+ */
+gint32
+thrift_compact_protocol_write_collection_begin (ThriftCompactProtocol *protocol,
+ const ThriftType elem_type,
+ guint32 size, GError **error)
+{
+ gint32 ret;
+ gint32 xfer;
+
+ xfer = 0;
+
+ if (size <= 14) {
+ if ((ret = thrift_protocol_write_byte (THRIFT_PROTOCOL (protocol),
+ (gint8) (size << 4
+ | TTypeToCType[elem_type]),
+ error)) < 0) {
+ return -1;
+ }
+ xfer += ret;
+ } else {
+ if ((ret = thrift_protocol_write_byte (THRIFT_PROTOCOL (protocol),
+ (gint8) (0xf0
+ | TTypeToCType[elem_type]),
+ error)) < 0) {
+ return -1;
+ }
+ xfer += ret;
+
+ if ((ret = thrift_compact_protocol_write_varint32 (protocol,
+ (guint32) size,
+ error)) < 0) {
+ return -1;
+ }
+ xfer += ret;
+ }
+
+ return xfer;
+}
+
+/*
+ * public methods
+ */
+
+gint32
+thrift_compact_protocol_write_message_begin (ThriftProtocol *protocol,
+ const gchar *name,
+ const ThriftMessageType
+ message_type,
+ const gint32 seqid, GError **error)
+{
+ gint8 version;
+ gint32 ret;
+ gint32 xfer;
+
+ ThriftCompactProtocol *cp;
+
+ g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+ cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+ version = (VERSION_N & VERSION_MASK)
+ | (((gint32) message_type << TYPE_SHIFT_AMOUNT) & TYPE_MASK);
+ xfer = 0;
+
+ if ((ret = thrift_protocol_write_byte (protocol, PROTOCOL_ID, error)) < 0) {
+ return -1;
+ }
+ xfer += ret;
+
+ if ((ret = thrift_protocol_write_byte (protocol, version, error)) < 0) {
+ return -1;
+ }
+ xfer += ret;
+
+ if ((ret = thrift_compact_protocol_write_varint32 (cp,
+ (guint32) seqid,
+ error)) < 0) {
+ return -1;
+ }
+ xfer += ret;
+
+ if ((ret = thrift_protocol_write_string (protocol, name, error)) < 0) {
+ return -1;
+ }
+ xfer += ret;
+
+ return xfer;
+}
+
+gint32
+thrift_compact_protocol_write_message_end (ThriftProtocol *protocol,
+ GError **error)
+{
+ /* satisfy -Wall */
+ THRIFT_UNUSED_VAR (protocol);
+ THRIFT_UNUSED_VAR (error);
+ return 0;
+}
+
+gint32
+thrift_compact_protocol_write_struct_begin (ThriftProtocol *protocol,
+ const gchar *name,
+ GError **error)
+{
+ ThriftCompactProtocol *cp;
+ GQueue *q;
+
+ /* satisfy -Wall */
+ THRIFT_UNUSED_VAR (name);
+ THRIFT_UNUSED_VAR (error);
+
+ g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+ cp = THRIFT_COMPACT_PROTOCOL (protocol);
+ q = &(cp->_last_field);
+
+ g_queue_push_tail (q, GINT_TO_POINTER ((gint) cp->_last_field_id));
+ cp->_last_field_id = 0;
+ return 0;
+}
+
+gint32
+thrift_compact_protocol_write_struct_end (ThriftProtocol *protocol,
+ GError **error)
+{
+ ThriftCompactProtocol *cp;
+ GQueue *q;
+
+ /* satisfy -Wall */
+ THRIFT_UNUSED_VAR (error);
+
+ cp = THRIFT_COMPACT_PROTOCOL (protocol);
+ q = &(cp->_last_field);
+
+ g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+ cp->_last_field_id = (gint16) GPOINTER_TO_INT (g_queue_pop_tail (q));
+ return 0;
+}
+
+gint32
+thrift_compact_protocol_write_field_begin (ThriftProtocol *protocol,
+ const gchar *name,
+ const ThriftType field_type,
+ const gint16 field_id,
+ GError **error)
+{
+ ThriftCompactProtocol *cp;
+
+ g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+ cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+ if (field_type == T_BOOL) {
+ cp->_bool_field_name = name;
+ cp->_bool_field_type = field_type;
+ cp->_bool_field_id = field_id;
+ return 0;
+ } else {
+ return thrift_compact_protocol_write_field_begin_internal (cp, name,
+ field_type,
+ field_id, -1,
+ error);
+ }
+}
+
+gint32
+thrift_compact_protocol_write_field_end (ThriftProtocol *protocol,
+ GError **error)
+{
+ /* satisfy -Wall */
+ THRIFT_UNUSED_VAR (protocol);
+ THRIFT_UNUSED_VAR (error);
+ return 0;
+}
+
+gint32
+thrift_compact_protocol_write_field_stop (ThriftProtocol *protocol,
+ GError **error)
+{
+ g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+ return thrift_protocol_write_byte (protocol, (gint8) T_STOP, error);
+}
+
+gint32
+thrift_compact_protocol_write_map_begin (ThriftProtocol *protocol,
+ const ThriftType key_type,
+ const ThriftType value_type,
+ const guint32 size,
+ GError **error)
+{
+ gint32 ret;
+ gint32 xfer;
+
+ ThriftCompactProtocol *cp;
+
+ g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+ cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+ xfer = 0;
+
+ if ((ret = thrift_compact_protocol_write_varint32 (cp, (guint32) size,
+ error)) < 0) {
+ return -1;
+ }
+ xfer += ret;
+
+ if (size > 0) {
+ if ((ret = thrift_protocol_write_byte (protocol,
+ (gint8) (TTypeToCType[key_type] << 4
+ | TTypeToCType[value_type]),
+ error)) < 0) {
+ return -1;
+ }
+ xfer += ret;
+ }
+
+ return xfer;
+}
+
+gint32
+thrift_compact_protocol_write_map_end (ThriftProtocol *protocol,
+ GError **error)
+{
+ THRIFT_UNUSED_VAR (protocol);
+ THRIFT_UNUSED_VAR (error);
+ return 0;
+}
+
+gint32
+thrift_compact_protocol_write_list_begin (ThriftProtocol *protocol,
+ const ThriftType element_type,
+ const guint32 size,
+ GError **error)
+{
+ ThriftCompactProtocol *cp;
+
+ g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+ cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+ return thrift_compact_protocol_write_collection_begin (cp, element_type,
+ size, error);
+}
+
+gint32
+thrift_compact_protocol_write_list_end (ThriftProtocol *protocol,
+ GError **error)
+{
+ THRIFT_UNUSED_VAR (protocol);
+ THRIFT_UNUSED_VAR (error);
+ return 0;
+}
+
+gint32
+thrift_compact_protocol_write_set_begin (ThriftProtocol *protocol,
+ const ThriftType element_type,
+ const guint32 size,
+ GError **error)
+{
+ ThriftCompactProtocol *cp;
+
+ g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+ cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+ return thrift_compact_protocol_write_collection_begin (cp, element_type,
+ size, error);
+}
+
+gint32
+thrift_compact_protocol_write_set_end (ThriftProtocol *protocol, GError **error)
+{
+ THRIFT_UNUSED_VAR (protocol);
+ THRIFT_UNUSED_VAR (error);
+ return 0;
+}
+
+gint32
+thrift_compact_protocol_write_bool (ThriftProtocol *protocol,
+ const gboolean value, GError **error)
+{
+ ThriftCompactProtocol *cp;
+
+ gint32 ret;
+ gint32 xfer;
+
+ g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+ cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+ xfer = 0;
+
+ if (cp->_bool_field_name != NULL) {
+ /* we haven't written the field header yet */
+ if ((ret = thrift_compact_protocol_write_field_begin_internal (cp,
+ cp->_bool_field_name,
+ cp->_bool_field_type,
+ cp->_bool_field_id,
+ (gint8) (value
+ ? CT_BOOLEAN_TRUE : CT_BOOLEAN_FALSE),
+ error)) < 0) {
+ return -1;
+ }
+ xfer += ret;
+
+ cp->_bool_field_name = NULL;
+ } else {
+ /* we're not part of a field, so just write the value */
+ if ((ret = thrift_protocol_write_byte (protocol,
+ (gint8) (value ? CT_BOOLEAN_TRUE
+ : CT_BOOLEAN_FALSE),
+ error)) < 0) {
+ return -1;
+ }
+ xfer += ret;
+ }
+ return xfer;
+}
+
+gint32
+thrift_compact_protocol_write_byte (ThriftProtocol *protocol, const gint8 value,
+ GError **error)
+{
+ g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+ if (thrift_transport_write (protocol->transport,
+ (const gpointer) &value, 1, error)) {
+ return 1;
+ } else {
+ return -1;
+ }
+}
+
+gint32
+thrift_compact_protocol_write_i16 (ThriftProtocol *protocol, const gint16 value,
+ GError **error)
+{
+ ThriftCompactProtocol *cp;
+
+ g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+ cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+ return thrift_compact_protocol_write_varint32 (cp,
+ i32_to_zigzag ((gint32) value),
+ error);
+}
+
+gint32
+thrift_compact_protocol_write_i32 (ThriftProtocol *protocol, const gint32 value,
+ GError **error)
+{
+ ThriftCompactProtocol *cp;
+
+ g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+ cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+ return thrift_compact_protocol_write_varint32 (cp,
+ i32_to_zigzag (value),
+ error);
+}
+
+gint32
+thrift_compact_protocol_write_i64 (ThriftProtocol *protocol, const gint64 value,
+ GError **error)
+{
+ ThriftCompactProtocol *cp;
+
+ g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+ cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+ return thrift_compact_protocol_write_varint64 (cp,
+ i64_to_zigzag (value),
+ error);
+}
+
+gint32
+thrift_compact_protocol_write_double (ThriftProtocol *protocol,
+ const gdouble value, GError **error)
+{
+ guint64 bits;
+
+ g_assert (sizeof (gdouble) == sizeof (guint64));
+
+ g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+ bits = GUINT64_TO_LE (thrift_bitwise_cast_guint64 (value));
+ if (thrift_transport_write (protocol->transport,
+ (const gpointer) &bits, 8, error)) {
+ return 8;
+ } else {
+ return -1;
+ }
+}
+
+gint32
+thrift_compact_protocol_write_string (ThriftProtocol *protocol,
+ const gchar *str, GError **error)
+{
+ size_t len;
+
+ g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+ len = str != NULL ? strlen (str) : 0;
+ if (len > G_MAXINT32) {
+ g_set_error (error, THRIFT_PROTOCOL_ERROR,
+ THRIFT_PROTOCOL_ERROR_SIZE_LIMIT,
+ "string size (guess: %lu) is too large", (unsigned long) len);
+ return -1;
+ }
+
+ /* write the string length + 1 which includes the null terminator */
+ return thrift_protocol_write_binary (protocol, (const gpointer) str,
+ (const guint32) len, error);
+}
+
+gint32
+thrift_compact_protocol_write_binary (ThriftProtocol *protocol,
+ const gpointer buf,
+ const guint32 len, GError **error)
+{
+ ThriftCompactProtocol *cp;
+
+ gint32 ret;
+ gint32 xfer;
+
+ g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+ cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+ xfer = 0;
+
+ if ((ret = thrift_compact_protocol_write_varint32 (cp, len, error)) < 0) {
+ return -1;
+ }
+ xfer += ret;
+
+ if (len > 0) {
+ /* checking len + xfer > uint_max, but we don't want to overflow while
+ * checking for overflows. transforming to len > uint_max - xfer.
+ */
+ if (len > (guint32) (G_MAXINT32 - xfer)) {
+ g_set_error (error, THRIFT_PROTOCOL_ERROR,
+ THRIFT_PROTOCOL_ERROR_SIZE_LIMIT,
+ "size %d + %d is too large", len, xfer);
+ return -1;
+ }
+
+ if (thrift_transport_write (protocol->transport,
+ (const gpointer) buf, len, error) == FALSE) {
+ return -1;
+ }
+ xfer += len;
+ }
+
+ return xfer;
+}
+
+gint32
+thrift_compact_protocol_read_message_begin (ThriftProtocol *protocol,
+ gchar **name,
+ ThriftMessageType *message_type,
+ gint32 *seqid, GError **error)
+{
+ ThriftCompactProtocol *cp;
+
+ gint32 ret;
+ gint32 xfer;
+
+ gint8 protocol_id, version_and_type, version;
+
+ xfer = 0;
+
+ g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+ cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+ if ((ret = thrift_protocol_read_byte (protocol, &protocol_id, error)) < 0) {
+ return -1;
+ }
+ xfer += ret;
+
+ if (protocol_id != PROTOCOL_ID) {
+ g_set_error (error, THRIFT_PROTOCOL_ERROR,
+ THRIFT_PROTOCOL_ERROR_BAD_VERSION,
+ "bad protocol id");
+ return -1;
+ }
+
+ if ((ret = thrift_protocol_read_byte (protocol, &version_and_type,
+ error)) < 0) {
+ return -1;
+ }
+ xfer += ret;
+
+ version = (gint8)(version_and_type & VERSION_MASK);
+ if (version != VERSION_N) {
+ g_set_error (error, THRIFT_PROTOCOL_ERROR,
+ THRIFT_PROTOCOL_ERROR_BAD_VERSION,
+ "bad version and/or type");
+ return -1;
+ }
+
+ *message_type
+ = (ThriftMessageType)((version_and_type >> TYPE_SHIFT_AMOUNT) & TYPE_BITS);
+
+ if ((ret = thrift_compact_protocol_read_varint32 (cp, seqid, error)) < 0) {
+ return -1;
+ }
+ xfer += ret;
+
+ if ((ret = thrift_protocol_read_string (protocol, name, error)) < 0) {
+ return -1;
+ }
+ xfer += ret;
+
+ return xfer;
+}
+
+gint32
+thrift_compact_protocol_read_message_end (ThriftProtocol *protocol,
+ GError **error)
+{
+ THRIFT_UNUSED_VAR (protocol);
+ THRIFT_UNUSED_VAR (error);
+ return 0;
+}
+
+gint32
+thrift_compact_protocol_read_struct_begin (ThriftProtocol *protocol,
+ gchar **name,
+ GError **error)
+{
+ ThriftCompactProtocol *cp;
+ GQueue *q;
+
+ THRIFT_UNUSED_VAR (error);
+
+ g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+ cp = THRIFT_COMPACT_PROTOCOL (protocol);
+ q = &(cp->_last_field);
+
+ *name = NULL;
+
+ g_queue_push_tail (q, GINT_TO_POINTER ((gint) cp->_last_field_id));
+ cp->_last_field_id = 0;
+
+ return 0;
+}
+
+gint32
+thrift_compact_protocol_read_struct_end (ThriftProtocol *protocol,
+ GError **error)
+{
+ ThriftCompactProtocol *cp;
+ GQueue *q;
+
+ THRIFT_UNUSED_VAR (error);
+
+ g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+ cp = THRIFT_COMPACT_PROTOCOL (protocol);
+ q = &(cp->_last_field);
+
+ cp->_last_field_id = (gint16) GPOINTER_TO_INT (g_queue_pop_tail (q));
+
+ return 0;
+}
+
+gint32
+thrift_compact_protocol_read_field_begin (ThriftProtocol *protocol,
+ gchar **name,
+ ThriftType *field_type,
+ gint16 *field_id,
+ GError **error)
+{
+ ThriftCompactProtocol *cp;
+
+ gint32 ret;
+ gint32 xfer;
+
+ gint16 modifier;
+ gint8 byte;
+ gint8 type;
+
+ g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+ cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+ THRIFT_UNUSED_VAR (name);
+
+ xfer = 0;
+
+ if ((ret = thrift_protocol_read_byte (protocol, &byte, error)) < 0) {
+ return -1;
+ }
+ xfer += ret;
+
+ type = (byte & 0x0f);
+
+ /* if it's a stop, then we can return immediately, as the struct is over. */
+ if (type == T_STOP) {
+ *field_type = T_STOP;
+ *field_id = 0;
+ return xfer;
+ }
+
+ /* mask off the 4 MSB of the type header.
+ * it could contain a field id delta.
+ */
+ modifier = (gint16)(((guint8)byte & 0xf0) >> 4);
+ if (modifier == 0) {
+ /* not a delta, look ahead for the zigzag varint field id. */
+ if ((ret = thrift_protocol_read_i16 (protocol, field_id, error)) < 0) {
+ return -1;
+ }
+ xfer += ret;
+ } else {
+ *field_id = (gint16)(cp->_last_field_id + modifier);
+ }
+ if ((ret = thrift_compact_protocol_get_ttype (cp, type, error)) < 0) {
+ return -1;
+ }
+ *field_type = ret;
+
+ /* if this happens to be a boolean field, the value is encoded in the type */
+ if (type == CT_BOOLEAN_TRUE || type == CT_BOOLEAN_FALSE) {
+ /* save the boolean value in a special instance variable. */
+ cp->_has_bool_value = TRUE;
+ cp->_bool_value =
+ (type == CT_BOOLEAN_TRUE ? TRUE : FALSE);
+ }
+
+ /* push the new field onto the field stack so we can keep the deltas going. */
+ cp->_last_field_id = *field_id;
+
+ return xfer;
+}
+
+gint32
+thrift_compact_protocol_read_field_end (ThriftProtocol *protocol,
+ GError **error)
+{
+ THRIFT_UNUSED_VAR (protocol);
+ THRIFT_UNUSED_VAR (error);
+ return 0;
+}
+
+gint32
+thrift_compact_protocol_read_map_begin (ThriftProtocol *protocol,
+ ThriftType *key_type,
+ ThriftType *value_type,
+ guint32 *size,
+ GError **error)
+{
+ gint32 ret;
+ gint32 xfer;
+
+ gint8 kv_type;
+ gint32 msize;
+
+ ThriftCompactProtocol *cp;
+
+ g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+ kv_type = 0;
+ msize = 0;
+
+ cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+ xfer = 0;
+
+ if ((ret = thrift_compact_protocol_read_varint32 (cp, &msize, error)) <0) {
+ return -1;
+ }
+ xfer += ret;
+
+ /* still read the kv byte if negative size */
+ if (msize != 0) {
+ if ((ret = thrift_protocol_read_byte (protocol, &kv_type, error)) < 0) {
+ return -1;
+ }
+ xfer += ret;
+ }
+
+ if (cp->container_limit > 0 && msize > cp->container_limit) {
+ g_set_error (error, THRIFT_PROTOCOL_ERROR,
+ THRIFT_PROTOCOL_ERROR_SIZE_LIMIT,
+ "got size over limit (%d > %d)", msize, cp->container_limit);
+ return -1;
+ } else if (msize > 0) {
+ if ((ret = thrift_compact_protocol_get_ttype (cp,
+ (gint8)((guint8)kv_type
+ >> 4),
+ error)) < 0) {
+ return -1;
+ }
+ *key_type = ret;
+ if ((ret = thrift_compact_protocol_get_ttype (cp,
+ (gint8)((guint8)kv_type
+ & 0xf),
+ error)) < 0) {
+ return -1;
+ }
+ *value_type = ret;
+ *size = (guint32) msize;
+ } else if (msize == 0) {
+ *key_type = 0;
+ *value_type = 0;
+ *size = 0;
+ } else {
+ g_set_error (error, THRIFT_PROTOCOL_ERROR,
+ THRIFT_PROTOCOL_ERROR_NEGATIVE_SIZE,
+ "got negative size of %d", msize);
+ return -1;
+ }
+
+ return xfer;
+}
+
+gint32
+thrift_compact_protocol_read_map_end (ThriftProtocol *protocol,
+ GError **error)
+{
+ THRIFT_UNUSED_VAR (protocol);
+ THRIFT_UNUSED_VAR (error);
+ return 0;
+}
+
+gint32
+thrift_compact_protocol_read_list_begin (ThriftProtocol *protocol,
+ ThriftType *element_type,
+ guint32 *size, GError **error)
+{
+ ThriftCompactProtocol *cp;
+
+ gint32 ret;
+ gint32 xfer;
+
+ gint8 size_and_type;
+ gint32 lsize;
+
+ g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+ cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+ size_and_type = 0;
+
+ xfer = 0;
+
+ if ((ret = thrift_protocol_read_byte (protocol, &size_and_type, error)) < 0) {
+ return -1;
+ }
+ xfer += ret;
+
+ lsize = ((guint8)size_and_type >> 4) & 0x0f;
+ if (lsize == 15) {
+ if ((ret = thrift_compact_protocol_read_varint32 (cp, &lsize, error)) < 0) {
+ return -1;
+ }
+ xfer += ret;
+ }
+
+ if (lsize < 0) {
+ g_set_error (error, THRIFT_PROTOCOL_ERROR,
+ THRIFT_PROTOCOL_ERROR_NEGATIVE_SIZE,
+ "got negative size of %d", lsize);
+ return -1;
+ } else if (cp->container_limit > 0 && lsize > cp->container_limit) {
+ g_set_error (error, THRIFT_PROTOCOL_ERROR,
+ THRIFT_PROTOCOL_ERROR_SIZE_LIMIT,
+ "got size over limit (%d > %d)", lsize, cp->container_limit);
+ return -1;
+ }
+
+ if ((ret = thrift_compact_protocol_get_ttype (cp,
+ (gint8)(size_and_type & 0x0f),
+ error)) < 0) {
+ return -1;
+ }
+ *element_type = ret;
+ *size = (guint32) lsize;
+
+ return xfer;
+}
+
+gint32
+thrift_compact_protocol_read_list_end (ThriftProtocol *protocol,
+ GError **error)
+{
+ THRIFT_UNUSED_VAR (protocol);
+ THRIFT_UNUSED_VAR (error);
+ return 0;
+}
+
+gint32
+thrift_compact_protocol_read_set_begin (ThriftProtocol *protocol,
+ ThriftType *element_type,
+ guint32 *size, GError **error)
+{
+ g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+ return thrift_protocol_read_list_begin (protocol, element_type, size, error);
+}
+
+gint32
+thrift_compact_protocol_read_set_end (ThriftProtocol *protocol,
+ GError **error)
+{
+ THRIFT_UNUSED_VAR (protocol);
+ THRIFT_UNUSED_VAR (error);
+ return 0;
+}
+
+gint32
+thrift_compact_protocol_read_bool (ThriftProtocol *protocol, gboolean *value,
+ GError **error)
+{
+ ThriftCompactProtocol *cp;
+
+ gint32 ret;
+ gint32 xfer;
+
+ gint8 val;
+
+ g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+ cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+ xfer = 0;
+
+ if (cp->_has_bool_value == TRUE) {
+ *value = cp->_bool_value;
+ cp->_has_bool_value = FALSE;
+ return 0;
+ } else {
+ if ((ret = thrift_protocol_read_byte (protocol, &val, error)) < 0) {
+ return -1;
+ }
+ xfer += ret;
+
+ *value = (val == CT_BOOLEAN_TRUE);
+ return xfer;
+ }
+}
+
+gint32
+thrift_compact_protocol_read_byte (ThriftProtocol *protocol, gint8 *value,
+ GError **error)
+{
+ gint32 ret;
+ gpointer b[1];
+
+ g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+ if ((ret =
+ thrift_transport_read (protocol->transport,
+ b, 1, error)) < 0) {
+ return -1;
+ }
+ *value = *(gint8 *) b;
+ return ret;
+}
+
+gint32
+thrift_compact_protocol_read_i16 (ThriftProtocol *protocol, gint16 *value,
+ GError **error)
+{
+ ThriftCompactProtocol *cp;
+
+ gint32 ret;
+ gint32 val;
+ gint32 xfer;
+
+ g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+ cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+ xfer = 0;
+
+ if ((ret = thrift_compact_protocol_read_varint32 (cp, &val, error)) < 0) {
+ return -1;
+ }
+ xfer += ret;
+
+ *value = (gint16) zigzag_to_i32 ((guint32) val);
+
+ return xfer;
+}
+
+gint32
+thrift_compact_protocol_read_i32 (ThriftProtocol *protocol, gint32 *value,
+ GError **error)
+{
+ ThriftCompactProtocol *cp;
+
+ gint32 ret;
+ gint32 val;
+ gint32 xfer;
+
+ g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+ cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+ xfer = 0;
+
+ if ((ret = thrift_compact_protocol_read_varint32 (cp, &val, error)) < 0) {
+ return -1;
+ }
+ xfer += ret;
+
+ *value = zigzag_to_i32 ((guint32) val);
+
+ return xfer;
+}
+
+gint32
+thrift_compact_protocol_read_i64 (ThriftProtocol *protocol, gint64 *value,
+ GError **error)
+{
+ ThriftCompactProtocol *cp;
+
+ gint32 ret;
+ gint64 val;
+ gint32 xfer;
+
+ g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+ cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+ xfer = 0;
+
+ if ((ret = thrift_compact_protocol_read_varint64 (cp, &val, error)) < 0) {
+ return -1;
+ }
+ xfer += ret;
+
+ *value = zigzag_to_i64 ((guint64) val);
+
+ return xfer;
+}
+
+gint32
+thrift_compact_protocol_read_double (ThriftProtocol *protocol,
+ gdouble *value, GError **error)
+{
+ gint32 ret;
+ union {
+ guint64 bits;
+ guint8 b[8];
+ } u;
+
+ g_assert (sizeof (gdouble) == sizeof (guint64));
+
+ g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+ if ((ret =
+ thrift_transport_read (protocol->transport,
+ u.b, 8, error)) < 0) {
+ return -1;
+ }
+ u.bits = GUINT64_FROM_LE (u.bits);
+ *value = thrift_bitwise_cast_gdouble (u.bits);
+ return ret;
+}
+
+gint32
+thrift_compact_protocol_read_string (ThriftProtocol *protocol,
+ gchar **str, GError **error)
+{
+ ThriftCompactProtocol *cp;
+
+ gint32 ret;
+ gint32 xfer;
+
+ gint32 read_len;
+
+ g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+ cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+ xfer = 0;
+ read_len = 0;
+
+ /* read the length into read_len */
+ if ((ret =
+ thrift_compact_protocol_read_varint32 (cp, &read_len, error)) < 0) {
+ return -1;
+ }
+ xfer += ret;
+
+ if (cp->string_limit > 0 && read_len > cp->string_limit) {
+ g_set_error (error, THRIFT_PROTOCOL_ERROR,
+ THRIFT_PROTOCOL_ERROR_SIZE_LIMIT,
+ "got size over limit (%d > %d)", read_len, cp->string_limit);
+ *str = NULL;
+ return -1;
+ }
+
+ if (read_len > 0) {
+ /* allocate the memory as an array of unsigned char for binary data */
+ *str = g_new0 (gchar, read_len + 1);
+ if ((ret =
+ thrift_transport_read (protocol->transport,
+ *str, read_len, error)) < 0) {
+ g_free (*str);
+ *str = NULL;
+ return -1;
+ }
+ xfer += ret;
+
+ } else if (read_len == 0) {
+ *str = NULL;
+
+ } else {
+ g_set_error (error, THRIFT_PROTOCOL_ERROR,
+ THRIFT_PROTOCOL_ERROR_NEGATIVE_SIZE,
+ "got negative size of %d", read_len);
+ *str = NULL;
+ return -1;
+ }
+
+ return xfer;
+}
+
+gint32
+thrift_compact_protocol_read_binary (ThriftProtocol *protocol,
+ gpointer *buf, guint32 *len,
+ GError **error)
+{
+ ThriftCompactProtocol *cp;
+
+ gint32 ret;
+ gint32 xfer;
+
+ gint32 read_len;
+
+ g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
+
+ cp = THRIFT_COMPACT_PROTOCOL (protocol);
+
+ xfer = 0;
+ read_len = 0;
+
+ /* read the length into read_len */
+ if ((ret =
+ thrift_compact_protocol_read_varint32 (cp, &read_len, error)) < 0) {
+ return -1;
+ }
+ xfer += ret;
+
+ if (cp->string_limit > 0 && read_len > cp->string_limit) {
+ g_set_error (error, THRIFT_PROTOCOL_ERROR,
+ THRIFT_PROTOCOL_ERROR_SIZE_LIMIT,
+ "got size over limit (%d > %d)", read_len, cp->string_limit);
+ *buf = NULL;
+ *len = 0;
+ return -1;
+ }
+
+ if (read_len > 0) {
+ /* allocate the memory as an array of unsigned char for binary data */
+ *len = (guint32) read_len;
+ *buf = g_new (guchar, *len);
+ if ((ret =
+ thrift_transport_read (protocol->transport,
+ *buf, *len, error)) < 0) {
+ g_free (*buf);
+ *buf = NULL;
+ *len = 0;
+ return -1;
+ }
+ xfer += ret;
+
+ } else if (read_len == 0) {
+ *len = (guint32) read_len;
+ *buf = NULL;
+
+ } else {
+ g_set_error (error, THRIFT_PROTOCOL_ERROR,
+ THRIFT_PROTOCOL_ERROR_NEGATIVE_SIZE,
+ "got negative size of %d", read_len);
+ *buf = NULL;
+ *len = 0;
+ return -1;
+ }
+
+ return xfer;
+}
+
+/* property accessor */
+void
+thrift_compact_protocol_get_property (GObject *object, guint property_id,
+ GValue *value, GParamSpec *pspec)
+{
+ ThriftCompactProtocol *tc;
+
+ THRIFT_UNUSED_VAR (pspec);
+
+ tc = THRIFT_COMPACT_PROTOCOL (object);
+
+ switch (property_id) {
+ case PROP_THRIFT_COMPACT_PROTOCOL_STRING_LIMIT:
+ g_value_set_int (value, tc->string_limit);
+ break;
+ case PROP_THRIFT_COMPACT_PROTOCOL_CONTAINER_LIMIT:
+ g_value_set_int (value, tc->container_limit);
+ break;
+ }
+}
+
+/* property mutator */
+void
+thrift_compact_protocol_set_property (GObject *object, guint property_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ ThriftCompactProtocol *tc;
+
+ THRIFT_UNUSED_VAR (pspec);
+
+ tc = THRIFT_COMPACT_PROTOCOL (object);
+
+ switch (property_id) {
+ case PROP_THRIFT_COMPACT_PROTOCOL_STRING_LIMIT:
+ tc->string_limit = g_value_get_int (value);
+ break;
+ case PROP_THRIFT_COMPACT_PROTOCOL_CONTAINER_LIMIT:
+ tc->container_limit = g_value_get_int (value);
+ break;
+ }
+}
+
+/* initialize the class */
+static void
+thrift_compact_protocol_class_init (ThriftCompactProtocolClass *klass)
+{
+ ThriftProtocolClass *cls;
+ GObjectClass *gobject_class;
+ GParamSpec *param_spec;
+
+ cls = THRIFT_PROTOCOL_CLASS (klass);
+ gobject_class = G_OBJECT_CLASS (klass);
+ param_spec = NULL;
+
+ /* setup accessors and mutators */
+ gobject_class->get_property = thrift_compact_protocol_get_property;
+ gobject_class->set_property = thrift_compact_protocol_set_property;
+
+ param_spec = g_param_spec_int ("string_limit",
+ "Max allowed string size",
+ "Set the max string limit",
+ 0, /* min */
+ G_MAXINT32, /* max */
+ 0, /* default value */
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class,
+ PROP_THRIFT_COMPACT_PROTOCOL_STRING_LIMIT,
+ param_spec);
+
+ param_spec = g_param_spec_int ("container_limit",
+ "Max allowed container size",
+ "Set the max container limit",
+ 0, /* min */
+ G_MAXINT32, /* max */
+ 0, /* default value */
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class,
+ PROP_THRIFT_COMPACT_PROTOCOL_CONTAINER_LIMIT,
+ param_spec);
+
+ cls->write_message_begin = thrift_compact_protocol_write_message_begin;
+ cls->write_message_end = thrift_compact_protocol_write_message_end;
+ cls->write_struct_begin = thrift_compact_protocol_write_struct_begin;
+ cls->write_struct_end = thrift_compact_protocol_write_struct_end;
+ cls->write_field_begin = thrift_compact_protocol_write_field_begin;
+ cls->write_field_end = thrift_compact_protocol_write_field_end;
+ cls->write_field_stop = thrift_compact_protocol_write_field_stop;
+ cls->write_map_begin = thrift_compact_protocol_write_map_begin;
+ cls->write_map_end = thrift_compact_protocol_write_map_end;
+ cls->write_list_begin = thrift_compact_protocol_write_list_begin;
+ cls->write_list_end = thrift_compact_protocol_write_list_end;
+ cls->write_set_begin = thrift_compact_protocol_write_set_begin;
+ cls->write_set_end = thrift_compact_protocol_write_set_end;
+ cls->write_bool = thrift_compact_protocol_write_bool;
+ cls->write_byte = thrift_compact_protocol_write_byte;
+ cls->write_i16 = thrift_compact_protocol_write_i16;
+ cls->write_i32 = thrift_compact_protocol_write_i32;
+ cls->write_i64 = thrift_compact_protocol_write_i64;
+ cls->write_double = thrift_compact_protocol_write_double;
+ cls->write_string = thrift_compact_protocol_write_string;
+ cls->write_binary = thrift_compact_protocol_write_binary;
+ cls->read_message_begin = thrift_compact_protocol_read_message_begin;
+ cls->read_message_end = thrift_compact_protocol_read_message_end;
+ cls->read_struct_begin = thrift_compact_protocol_read_struct_begin;
+ cls->read_struct_end = thrift_compact_protocol_read_struct_end;
+ cls->read_field_begin = thrift_compact_protocol_read_field_begin;
+ cls->read_field_end = thrift_compact_protocol_read_field_end;
+ cls->read_map_begin = thrift_compact_protocol_read_map_begin;
+ cls->read_map_end = thrift_compact_protocol_read_map_end;
+ cls->read_list_begin = thrift_compact_protocol_read_list_begin;
+ cls->read_list_end = thrift_compact_protocol_read_list_end;
+ cls->read_set_begin = thrift_compact_protocol_read_set_begin;
+ cls->read_set_end = thrift_compact_protocol_read_set_end;
+ cls->read_bool = thrift_compact_protocol_read_bool;
+ cls->read_byte = thrift_compact_protocol_read_byte;
+ cls->read_i16 = thrift_compact_protocol_read_i16;
+ cls->read_i32 = thrift_compact_protocol_read_i32;
+ cls->read_i64 = thrift_compact_protocol_read_i64;
+ cls->read_double = thrift_compact_protocol_read_double;
+ cls->read_string = thrift_compact_protocol_read_string;
+ cls->read_binary = thrift_compact_protocol_read_binary;
+}
+
+static void
+thrift_compact_protocol_init (ThriftCompactProtocol *self)
+{
+ g_queue_init (&(self->_last_field));
+}
diff --git a/lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol.h b/lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol.h
new file mode 100644
index 0000000..effcaad
--- /dev/null
+++ b/lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol.h
@@ -0,0 +1,107 @@
+/*
+ * 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 _THRIFT_COMPACT_PROTOCOL_H
+#define _THRIFT_COMPACT_PROTOCOL_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <thrift/c_glib/protocol/thrift_protocol.h>
+#include <thrift/c_glib/transport/thrift_transport.h>
+
+G_BEGIN_DECLS
+
+/*! \file thrift_compact_protocol.h
+ * \brief Compact protocol implementation of a Thrift protocol. Implements the
+ * ThriftProtocol interface.
+ */
+
+/* type macros */
+#define THRIFT_TYPE_COMPACT_PROTOCOL (thrift_compact_protocol_get_type ())
+#define THRIFT_COMPACT_PROTOCOL(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), THRIFT_TYPE_COMPACT_PROTOCOL, \
+ ThriftCompactProtocol))
+#define THRIFT_IS_COMPACT_PROTOCOL(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THRIFT_TYPE_COMPACT_PROTOCOL))
+#define THRIFT_COMPACT_PROTOCOL_CLASS(c) \
+ (G_TYPE_CHECK_CLASS_CAST ((c), THRIFT_TYPE_COMPACT_PROTOCOL, \
+ ThriftCompactProtocolClass))
+#define THRIFT_IS_COMPACT_PROTOCOL_CLASS(c) \
+ (G_TYPE_CHECK_CLASS_TYPE ((c), THRIFT_TYPE_COMPACT_PROTOCOL))
+#define THRIFT_COMPACT_PROTOCOL_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), THRIFT_TYPE_COMPACT_PROTOCOL, \
+ ThriftCompactProtocolClass))
+
+
+typedef struct _ThriftCompactProtocol ThriftCompactProtocol;
+
+/*!
+ * Thrift Compact Protocol instance.
+ */
+struct _ThriftCompactProtocol
+{
+ ThriftProtocol parent;
+
+ /* protected */
+ gint32 string_limit;
+ gint32 container_limit;
+
+ /* private */
+
+ /**
+ * (Writing) If we encounter a boolean field begin, save the TField here
+ * so it can have the value incorporated.
+ */
+ const gchar* _bool_field_name;
+ ThriftType _bool_field_type;
+ gint16 _bool_field_id;
+
+ /**
+ * (Reading) If we read a field header, and it's a boolean field, save
+ * the boolean value here so that read_bool can use it.
+ */
+ gboolean _has_bool_value;
+ gboolean _bool_value;
+
+ /**
+ * Used to keep track of the last field for the current and previous structs,
+ * so we can do the delta stuff.
+ */
+
+ GQueue _last_field;
+ gint16 _last_field_id;
+};
+
+typedef struct _ThriftCompactProtocolClass ThriftCompactProtocolClass;
+
+/*!
+ * Thrift Compact Protocol class.
+ */
+struct _ThriftCompactProtocolClass
+{
+ ThriftProtocolClass parent;
+};
+
+/* used by THRIFT_TYPE_COMPACT_PROTOCOL */
+GType thrift_compact_protocol_get_type (void);
+
+G_END_DECLS
+
+#endif /* _THRIFT_COMPACT_PROTOCOL_H */
diff --git a/lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol_factory.c b/lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol_factory.c
new file mode 100644
index 0000000..e725e1f
--- /dev/null
+++ b/lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol_factory.c
@@ -0,0 +1,140 @@
+/*
+ * 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 <thrift/c_glib/thrift.h>
+#include <thrift/c_glib/protocol/thrift_compact_protocol.h>
+#include <thrift/c_glib/protocol/thrift_compact_protocol_factory.h>
+
+/* object properties */
+enum _ThriftCompactProtocolFactoryProperties
+{
+ PROP_0,
+ PROP_THRIFT_COMPACT_PROTOCOL_FACTORY_STRING_LIMIT,
+ PROP_THRIFT_COMPACT_PROTOCOL_FACTORY_CONTAINER_LIMIT
+};
+
+G_DEFINE_TYPE (ThriftCompactProtocolFactory, thrift_compact_protocol_factory,
+ THRIFT_TYPE_PROTOCOL_FACTORY)
+
+ThriftProtocol *
+thrift_compact_protocol_factory_get_protocol (ThriftProtocolFactory *factory,
+ ThriftTransport *transport)
+{
+ ThriftCompactProtocolFactory *tcf;
+ ThriftCompactProtocol *tc;
+
+ tcf = THRIFT_COMPACT_PROTOCOL_FACTORY (factory);
+
+ tc = g_object_new (THRIFT_TYPE_COMPACT_PROTOCOL,
+ "transport", transport,
+ "string_limit", tcf->string_limit,
+ "container_limit", tcf->container_limit,
+ NULL);
+
+ return THRIFT_PROTOCOL (tc);
+}
+
+/* property accessor */
+void
+thrift_compact_protocol_factory_get_property (GObject *object, guint property_id,
+ GValue *value, GParamSpec *pspec)
+{
+ ThriftCompactProtocolFactory *tcf;
+
+ THRIFT_UNUSED_VAR (pspec);
+
+ tcf = THRIFT_COMPACT_PROTOCOL_FACTORY (object);
+
+ switch (property_id) {
+ case PROP_THRIFT_COMPACT_PROTOCOL_FACTORY_STRING_LIMIT:
+ g_value_set_int (value, tcf->string_limit);
+ break;
+ case PROP_THRIFT_COMPACT_PROTOCOL_FACTORY_CONTAINER_LIMIT:
+ g_value_set_int (value, tcf->container_limit);
+ break;
+ }
+}
+
+/* property mutator */
+void
+thrift_compact_protocol_factory_set_property (GObject *object, guint property_id,
+ const GValue *value, GParamSpec
+ *pspec)
+{
+ ThriftCompactProtocolFactory *tcf;
+
+ THRIFT_UNUSED_VAR (pspec);
+
+ tcf = THRIFT_COMPACT_PROTOCOL_FACTORY (object);
+
+ switch (property_id) {
+ case PROP_THRIFT_COMPACT_PROTOCOL_FACTORY_STRING_LIMIT:
+ tcf->string_limit = g_value_get_int (value);
+ break;
+ case PROP_THRIFT_COMPACT_PROTOCOL_FACTORY_CONTAINER_LIMIT:
+ tcf->container_limit = g_value_get_int (value);
+ break;
+ }
+}
+
+static void
+thrift_compact_protocol_factory_class_init (ThriftCompactProtocolFactoryClass
+ *klass)
+{
+ ThriftProtocolFactoryClass *cls;
+ GObjectClass *gobject_class;
+ GParamSpec *param_spec;
+
+ cls = THRIFT_PROTOCOL_FACTORY_CLASS (klass);
+ gobject_class = G_OBJECT_CLASS (klass);
+ param_spec = NULL;
+
+ /* setup accessors and mutators */
+ gobject_class->get_property = thrift_compact_protocol_factory_get_property;
+ gobject_class->set_property = thrift_compact_protocol_factory_set_property;
+
+ param_spec = g_param_spec_int ("string_limit",
+ "Max allowed string size",
+ "Set the max string limit",
+ 0, /* min */
+ G_MAXINT32, /* max */
+ 0, /* default value */
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class,
+ PROP_THRIFT_COMPACT_PROTOCOL_FACTORY_STRING_LIMIT,
+ param_spec);
+
+ param_spec = g_param_spec_int ("container_limit",
+ "Max allowed container size",
+ "Set the max container limit",
+ 0, /* min */
+ G_MAXINT32, /* max */
+ 0, /* default value */
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class,
+ PROP_THRIFT_COMPACT_PROTOCOL_FACTORY_CONTAINER_LIMIT, param_spec);
+
+ cls->get_protocol = thrift_compact_protocol_factory_get_protocol;
+}
+
+static void
+thrift_compact_protocol_factory_init (ThriftCompactProtocolFactory *factory)
+{
+ THRIFT_UNUSED_VAR (factory);
+}
diff --git a/lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol_factory.h b/lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol_factory.h
new file mode 100644
index 0000000..3bf953b
--- /dev/null
+++ b/lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol_factory.h
@@ -0,0 +1,70 @@
+/*
+ * 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 _THRIFT_COMPACT_PROTOCOL_FACTORY_H
+#define _THRIFT_COMPACT_PROTOCOL_FACTORY_H
+
+#include <glib-object.h>
+
+#include <thrift/c_glib/protocol/thrift_protocol_factory.h>
+
+G_BEGIN_DECLS
+
+/* type macros */
+#define THRIFT_TYPE_COMPACT_PROTOCOL_FACTORY \
+ (thrift_compact_protocol_factory_get_type ())
+#define THRIFT_COMPACT_PROTOCOL_FACTORY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), THRIFT_TYPE_COMPACT_PROTOCOL_FACTORY, \
+ ThriftCompactProtocolFactory))
+#define THRIFT_IS_COMPACT_PROTOCOL_FACTORY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THRIFT_TYPE_COMPACT_PROTOCOL_FACTORY))
+#define THRIFT_COMPACT_PROTOCOL_FACTORY_CLASS(c) \
+ (G_TYPE_CHECK_CLASS_CAST ((c), THRIFT_TYPE_COMPACT_PROTOCOL_FACTORY, \
+ ThriftCompactProtocolFactoryClass))
+#define THRIFT_IS_COMPACT_PROTOCOL_FACTORY_CLASS(c) \
+ (G_TYPE_CHECK_CLASS_TYPE ((c), THRIFT_TYPE_COMPACT_PROTOCOL_FACTORY))
+#define THRIFT_COMPACT_PROTOCOL_FACTORY_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), THRIFT_TYPE_COMPACT_PROTOCOL_FACTORY, \
+ ThriftCompactProtocolFactoryClass))
+
+typedef struct _ThriftCompactProtocolFactory ThriftCompactProtocolFactory;
+
+struct _ThriftCompactProtocolFactory
+{
+ ThriftProtocolFactory parent;
+
+ /* protected */
+ gint32 string_limit;
+ gint32 container_limit;
+};
+
+typedef struct _ThriftCompactProtocolFactoryClass
+ ThriftCompactProtocolFactoryClass;
+
+struct _ThriftCompactProtocolFactoryClass
+{
+ ThriftProtocolFactoryClass parent;
+};
+
+/* used by THRIFT_TYPE_COMPACT_PROTOCOL_FACTORY */
+GType thrift_compact_protocol_factory_get_type (void);
+
+G_END_DECLS
+
+#endif /* _THRIFT_COMPACT_PROTOCOL_FACTORY_H */
diff --git a/lib/c_glib/test/CMakeLists.txt b/lib/c_glib/test/CMakeLists.txt
index 48a30d0..14454ed 100644
--- a/lib/c_glib/test/CMakeLists.txt
+++ b/lib/c_glib/test/CMakeLists.txt
@@ -73,6 +73,10 @@
target_link_libraries(testbinaryprotocol thrift_c_glib)
add_test(NAME testbinaryprotocol COMMAND testbinaryprotocol)
+add_executable(testcompactprotocol testcompactprotocol.c)
+target_link_libraries(testcompactprotocol thrift_c_glib)
+add_test(NAME testcompactprotocol COMMAND testcompactprotocol)
+
add_executable(testbufferedtransport testbufferedtransport.c)
target_link_libraries(testbufferedtransport thrift_c_glib)
add_test(NAME testbufferedtransport COMMAND testbufferedtransport)
diff --git a/lib/c_glib/test/Makefile.am b/lib/c_glib/test/Makefile.am
index 4d35f2a..43f3b4b 100755
--- a/lib/c_glib/test/Makefile.am
+++ b/lib/c_glib/test/Makefile.am
@@ -48,6 +48,7 @@
testcontainertest \
testtransportsocket \
testbinaryprotocol \
+ testcompactprotocol \
testbufferedtransport \
testframedtransport \
testmemorybuffer \
@@ -106,6 +107,14 @@
$(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_server_transport.o \
$(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_server_socket.o
+testcompactprotocol_SOURCES = testcompactprotocol.c
+testcompactprotocol_LDADD = \
+ $(top_builddir)/lib/c_glib/src/thrift/c_glib/protocol/libthrift_c_glib_la-thrift_protocol.o \
+ $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_transport.o \
+ $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_socket.o \
+ $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_server_transport.o \
+ $(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_server_socket.o
+
testbufferedtransport_SOURCES = testbufferedtransport.c
testbufferedtransport_LDADD = \
$(top_builddir)/lib/c_glib/src/thrift/c_glib/transport/libthrift_c_glib_la-thrift_transport.o \
diff --git a/lib/c_glib/test/testcompactprotocol.c b/lib/c_glib/test/testcompactprotocol.c
new file mode 100755
index 0000000..3d16dc0
--- /dev/null
+++ b/lib/c_glib/test/testcompactprotocol.c
@@ -0,0 +1,1074 @@
+/*
+ * 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.
+ */
+
+/* Disable string-function optimizations when glibc is used, as these produce
+ compiler warnings about string length when a string function is used inside
+ a call to assert () */
+#if !defined(__APPLE__) && !defined(__FreeBSD__) && \
+ !defined(__OpenBSD__) && !defined(__NetBSD__)
+#include <features.h>
+#endif
+
+#ifdef __GLIBC__
+#define __NO_STRING_INLINES 1
+#endif
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <netdb.h>
+#include <string.h>
+#include <sys/wait.h>
+
+#include <thrift/c_glib/protocol/thrift_protocol.h>
+#include <thrift/c_glib/transport/thrift_socket.h>
+#include <thrift/c_glib/transport/thrift_server_socket.h>
+
+#define TEST_BOOL TRUE
+#define TEST_BYTE 123
+#define TEST_I16 12345
+#define TEST_I32 1234567890
+#define TEST_I64 123456789012345
+#define TEST_NI16 (-12345)
+#define TEST_NI32 (-1234567890)
+#define TEST_NI64 (-123456789012345)
+#define TEST_DOUBLE 1234567890.123
+#define TEST_STRING "this is a test string 1234567890!@#$%^&*()"
+#define TEST_PORT 51199
+
+static int transport_read_count = 0;
+static int transport_read_error = 0;
+static int transport_read_error_at = -1;
+gint32
+my_thrift_transport_read (ThriftTransport *transport, gpointer buf,
+ guint32 len, GError **error)
+{
+ if (transport_read_count != transport_read_error_at
+ && transport_read_error == 0)
+ {
+ transport_read_count++;
+ return thrift_transport_read (transport, buf, len, error);
+ }
+ return -1;
+}
+
+static int transport_write_count = 0;
+static int transport_write_error = 0;
+static int transport_write_error_at = -1;
+gboolean
+my_thrift_transport_write (ThriftTransport *transport, const gpointer buf,
+ const guint32 len, GError **error)
+{
+ if (transport_write_count != transport_write_error_at
+ && transport_write_error == 0)
+ {
+ transport_write_count++;
+ return thrift_transport_write (transport, buf, len, error);
+ }
+ return FALSE;
+}
+
+#define thrift_transport_read my_thrift_transport_read
+#define thrift_transport_write my_thrift_transport_write
+#include "../src/thrift/c_glib/protocol/thrift_compact_protocol.c"
+#undef thrift_transport_read
+#undef thrift_transport_write
+
+static void thrift_server_primitives (const int port);
+static void thrift_server_complex_types (const int port);
+
+static void
+test_create_and_destroy (void)
+{
+ GObject *object = NULL;
+
+ /* create an object and then destroy it */
+ object = g_object_new (THRIFT_TYPE_COMPACT_PROTOCOL, NULL);
+ assert (object != NULL);
+ g_object_unref (object);
+}
+
+static void
+test_initialize (void)
+{
+ ThriftSocket *tsocket = NULL;
+ ThriftCompactProtocol *protocol = NULL;
+ ThriftSocket *temp = NULL;
+
+ /* create a ThriftTransport */
+ tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
+ "port", 51188, NULL);
+ assert (tsocket != NULL);
+ /* create a ThriftCompactProtocol using the Transport */
+ protocol = g_object_new (THRIFT_TYPE_COMPACT_PROTOCOL, "transport",
+ tsocket, NULL);
+ assert (protocol != NULL);
+ /* fetch the properties */
+ g_object_get (G_OBJECT (protocol), "transport", &temp, NULL);
+ g_object_unref (temp);
+
+ /* clean up memory */
+ g_object_unref (protocol);
+ g_object_unref (tsocket);
+}
+
+static void
+test_read_and_write_primitives (void)
+{
+ int status;
+ pid_t pid;
+ ThriftSocket *tsocket = NULL;
+ ThriftTransport *transport = NULL;
+ ThriftCompactProtocol *tc = NULL;
+ ThriftProtocol *protocol = NULL;
+ gpointer binary = (gpointer *) TEST_STRING;
+ guint32 len = strlen (TEST_STRING);
+ int port = TEST_PORT;
+
+ /* fork a server from the client */
+ pid = fork ();
+ assert (pid >= 0);
+
+ if (pid == 0)
+ {
+ /* child listens */
+ thrift_server_primitives (port);
+ exit (0);
+ } else {
+ /* parent. wait a bit for the socket to be created. */
+ sleep (1);
+
+ /* create a ThriftSocket */
+ tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
+ "port", port, NULL);
+ transport = THRIFT_TRANSPORT (tsocket);
+ thrift_transport_open (transport, NULL);
+ assert (thrift_transport_is_open (transport));
+
+ /* create a ThriftCompactTransport */
+ tc = g_object_new (THRIFT_TYPE_COMPACT_PROTOCOL, "transport",
+ tsocket, NULL);
+ protocol = THRIFT_PROTOCOL (tc);
+ assert (protocol != NULL);
+
+ /* write a bunch of primitives */
+ assert (thrift_compact_protocol_write_bool (protocol, TEST_BOOL, NULL) > 0);
+ assert (thrift_compact_protocol_write_byte (protocol, TEST_BYTE, NULL) > 0);
+ assert (thrift_compact_protocol_write_i16 (protocol, TEST_I16, NULL) > 0);
+ assert (thrift_compact_protocol_write_i32 (protocol, TEST_I32, NULL) > 0);
+ assert (thrift_compact_protocol_write_i64 (protocol, TEST_I64, NULL) > 0);
+ assert (thrift_compact_protocol_write_i16 (protocol, TEST_NI16, NULL) > 0);
+ assert (thrift_compact_protocol_write_i32 (protocol, TEST_NI32, NULL) > 0);
+ assert (thrift_compact_protocol_write_i64 (protocol, TEST_NI64, NULL) > 0);
+ assert (thrift_compact_protocol_write_i16 (protocol, 2, NULL) > 0);
+ assert (thrift_compact_protocol_write_i32 (protocol, 2, NULL) > 0);
+ assert (thrift_compact_protocol_write_i64 (protocol, 2, NULL) > 0);
+ assert (thrift_compact_protocol_write_i16 (protocol, -2, NULL) > 0);
+ assert (thrift_compact_protocol_write_i32 (protocol, -2, NULL) > 0);
+ assert (thrift_compact_protocol_write_i64 (protocol, -2, NULL) > 0);
+ assert (thrift_compact_protocol_write_double (protocol,
+ TEST_DOUBLE, NULL) > 0);
+ assert (thrift_compact_protocol_write_string (protocol,
+ TEST_STRING, NULL) > 0);
+ assert (thrift_compact_protocol_write_binary (protocol, binary,
+ len, NULL) > 0);
+ assert (thrift_compact_protocol_write_binary (protocol, NULL, 0, NULL) > 0);
+ assert (thrift_compact_protocol_write_binary (protocol, binary,
+ len, NULL) > 0);
+
+ /* test write errors */
+ transport_write_error = 1;
+ assert (thrift_compact_protocol_write_byte (protocol, TEST_BYTE,
+ NULL) == -1);
+ assert (thrift_compact_protocol_write_i16 (protocol, TEST_I16, NULL) == -1);
+ assert (thrift_compact_protocol_write_i32 (protocol, TEST_I32, NULL) == -1);
+ assert (thrift_compact_protocol_write_i64 (protocol, TEST_I64, NULL) == -1);
+ assert (thrift_compact_protocol_write_i16 (protocol, TEST_NI16,
+ NULL) == -1);
+ assert (thrift_compact_protocol_write_i32 (protocol, TEST_NI32,
+ NULL) == -1);
+ assert (thrift_compact_protocol_write_i64 (protocol, TEST_NI64,
+ NULL) == -1);
+ assert (thrift_compact_protocol_write_double (protocol, TEST_DOUBLE,
+ NULL) == -1);
+ assert (thrift_compact_protocol_write_binary (protocol, binary, len,
+ NULL) == -1);
+ transport_write_error = 0;
+
+ /* test binary partial failure */
+ transport_write_count = 0;
+ transport_write_error_at = 1;
+ assert (thrift_compact_protocol_write_binary (protocol, binary,
+ len, NULL) == -1);
+ transport_write_error_at = -1;
+
+ /* clean up */
+ thrift_transport_close (transport, NULL);
+ g_object_unref (tsocket);
+ g_object_unref (protocol);
+ assert (wait (&status) == pid);
+ assert (status == 0);
+ }
+}
+
+static void
+test_read_and_write_complex_types (void)
+{
+ int status;
+ pid_t pid;
+ ThriftSocket *tsocket = NULL;
+ ThriftTransport *transport = NULL;
+ ThriftCompactProtocol *tc = NULL;
+ ThriftProtocol *protocol = NULL;
+ int port = TEST_PORT;
+
+ /* fork a server from the client */
+ pid = fork ();
+ assert (pid >= 0);
+
+ if (pid == 0)
+ {
+ /* child listens */
+ thrift_server_complex_types (port);
+ exit (0);
+ } else {
+ /* parent. wait a bit for the socket to be created. */
+ sleep (1);
+
+ /* create a ThriftSocket */
+ tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
+ "port", port, NULL);
+ transport = THRIFT_TRANSPORT (tsocket);
+ thrift_transport_open (transport, NULL);
+ assert (thrift_transport_is_open (transport));
+
+ /* create a ThriftCompactTransport */
+ tc = g_object_new (THRIFT_TYPE_COMPACT_PROTOCOL, "transport",
+ tsocket, NULL);
+ protocol = THRIFT_PROTOCOL (tc);
+ assert (protocol != NULL);
+
+ /* test structures */
+ assert (thrift_compact_protocol_write_struct_begin (protocol,
+ NULL, NULL) == 0);
+ assert (thrift_compact_protocol_write_struct_end (protocol, NULL) == 0);
+
+ /* test field state w.r.t. deltas */
+
+ assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+ T_DOUBLE, 1, NULL) == 1);
+ assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+ T_DOUBLE,
+ 16, NULL) == 1);
+ assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+ T_DOUBLE,
+ 17, NULL) == 1);
+ assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+ T_DOUBLE,
+ 15, NULL) > 1);
+ assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+ T_DOUBLE,
+ 30, NULL) == 1);
+ assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+ T_DOUBLE,
+ 46, NULL) > 1);
+ assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+ T_DOUBLE,
+ 47, NULL) == 1);
+
+ /* test fields */
+ assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+ T_DOUBLE,
+ 1, NULL) > 1);
+ assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+
+ /* test field state w.r.t. structs */
+
+ assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+ T_DOUBLE,
+ 1, NULL) > 1);
+ assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+ assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+ T_DOUBLE,
+ 16, NULL) == 1);
+ assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+
+ assert (thrift_compact_protocol_write_struct_begin (protocol,
+ NULL, NULL) == 0);
+ assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+ T_DOUBLE,
+ 17, NULL) > 1);
+ assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+
+ assert (thrift_compact_protocol_write_struct_begin (protocol,
+ NULL, NULL) == 0);
+ assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+ T_DOUBLE,
+ 18, NULL) > 1);
+ assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+ assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+ T_DOUBLE,
+ 19, NULL) == 1);
+ assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+ assert (thrift_compact_protocol_write_struct_end (protocol, NULL) == 0);
+
+ assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+ T_DOUBLE,
+ 18, NULL) == 1);
+ assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+ assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+ T_DOUBLE,
+ 25, NULL) == 1);
+ assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+ assert (thrift_compact_protocol_write_struct_end (protocol, NULL) == 0);
+
+ assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+ T_DOUBLE,
+ 17, NULL) == 1);
+ assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+
+ /* test field state w.r.t. bools */
+
+ /* deltas */
+ /* non-bool field -> bool field -> non-bool field */
+ assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+ T_DOUBLE,
+ 18, NULL) == 1);
+ assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+ assert (thrift_compact_protocol_write_field_begin (protocol, "test", T_BOOL,
+ 19, NULL) == 0);
+ assert (thrift_compact_protocol_write_bool (protocol, TEST_BOOL,
+ NULL) == 1);
+ assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+ assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+ T_DOUBLE,
+ 20, NULL) == 1);
+ assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+ /* bool -> bool field -> bool */
+ assert (thrift_compact_protocol_write_bool (protocol, TEST_BOOL, NULL) > 0);
+ assert (thrift_compact_protocol_write_field_begin (protocol, "test", T_BOOL,
+ 21, NULL) == 0);
+ assert (thrift_compact_protocol_write_bool (protocol, TEST_BOOL,
+ NULL) == 1);
+ assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+ assert (thrift_compact_protocol_write_bool (protocol, TEST_BOOL, NULL) > 0);
+
+ /* no deltas */
+ /* non-bool field -> bool field -> non-bool field */
+ assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+ T_DOUBLE,
+ 1, NULL) > 1);
+ assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+ assert (thrift_compact_protocol_write_field_begin (protocol, "test", T_BOOL,
+ 1, NULL) == 0);
+ assert (thrift_compact_protocol_write_bool (protocol, TEST_BOOL, NULL) > 1);
+ assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+ assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+ T_DOUBLE,
+ 1, NULL) > 1);
+ assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+ /* bool -> bool field -> bool */
+ assert (thrift_compact_protocol_write_bool (protocol, TEST_BOOL, NULL) > 0);
+ assert (thrift_compact_protocol_write_field_begin (protocol, "test", T_BOOL,
+ 1, NULL) == 0);
+ assert (thrift_compact_protocol_write_bool (protocol, TEST_BOOL, NULL) > 1);
+ assert (thrift_compact_protocol_write_field_end (protocol, NULL) == 0);
+ assert (thrift_compact_protocol_write_bool (protocol, TEST_BOOL, NULL) > 0);
+
+ /* test write error */
+ transport_write_error = 1;
+ assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+ T_DOUBLE,
+ 1, NULL) == -1);
+ transport_write_error = 0;
+
+ /* test 2nd write error */
+ transport_write_count = 0;
+ transport_write_error_at = 1;
+ assert (thrift_compact_protocol_write_field_begin (protocol, "test",
+ T_DOUBLE,
+ 1, NULL) == -1);
+ transport_write_error_at = -1;
+
+ /* test 2nd read failure on a field */
+ thrift_compact_protocol_write_byte (protocol, T_DOUBLE, NULL);
+
+ /* test write_field_stop */
+ assert (thrift_compact_protocol_write_field_stop (protocol, NULL) > 0);
+
+ /* write a map */
+ assert (thrift_compact_protocol_write_map_begin (protocol, T_DOUBLE,
+ T_DOUBLE,
+ 1, NULL) > 0);
+ assert (thrift_compact_protocol_write_map_end (protocol, NULL) == 0);
+
+ /* test 1st read failure on map---nothing to do on our side */
+
+ /* test 2nd read failure on a map */
+ thrift_compact_protocol_write_byte (protocol, T_DOUBLE, NULL);
+
+ /* test 1st write failure on a map */
+ transport_write_error = 1;
+ assert (thrift_compact_protocol_write_map_begin (protocol, T_DOUBLE,
+ T_DOUBLE,
+ 1, NULL) == -1);
+ transport_write_error = 0;
+
+ /* test 2nd write failure on a map */
+ transport_write_count = 0;
+ transport_write_error_at = 1;
+ assert (thrift_compact_protocol_write_map_begin (protocol, T_DOUBLE,
+ T_DOUBLE,
+ 1, NULL) == -1);
+ transport_write_error_at = -1;
+
+ /* test negative map size */
+ thrift_compact_protocol_write_varint32 (tc, -10, NULL);
+ thrift_compact_protocol_write_byte (protocol, T_DOUBLE, NULL);
+
+ /* test list operations */
+ assert (thrift_compact_protocol_write_list_begin (protocol, T_DOUBLE,
+ 15, NULL) > 0);
+ assert (thrift_compact_protocol_write_list_end (protocol, NULL) == 0);
+
+ /* test 1st read failure on a small list---nothing to do on our end */
+
+ /* test 1st read failure on a big list---nothing to do on our end */
+
+ /* test 2nd read failure on a big list */
+ thrift_compact_protocol_write_byte (protocol, (gint8) 0xf0, NULL);
+
+ /* test negative list size */
+ thrift_compact_protocol_write_byte (protocol, (gint8) 0xf0, NULL);
+ thrift_compact_protocol_write_varint32 (tc, -10, NULL);
+
+ /* test first write error on a small list */
+ transport_write_error = 1;
+ assert (thrift_compact_protocol_write_list_begin (protocol, T_DOUBLE,
+ 14, NULL) == -1);
+ transport_write_error = 0;
+
+ /* test first write error on a big list */
+ transport_write_error = 1;
+ assert (thrift_compact_protocol_write_list_begin (protocol, T_DOUBLE,
+ 15, NULL) == -1);
+ transport_write_error = 0;
+
+ /* test 2nd write error on a big list */
+ transport_write_count = 0;
+ transport_write_error_at = 1;
+ assert (thrift_compact_protocol_write_list_begin (protocol, T_DOUBLE,
+ 15, NULL) == -1);
+ transport_write_error_at = -1;
+
+ /* test set operation s*/
+ assert (thrift_compact_protocol_write_set_begin (protocol, T_DOUBLE,
+ 1, NULL) > 0);
+ assert (thrift_compact_protocol_write_set_end (protocol, NULL) == 0);
+
+ /* invalid protocol */
+ assert (thrift_compact_protocol_write_byte (protocol, 0, NULL) > 0);
+
+ /* invalid version */
+ assert (thrift_compact_protocol_write_byte (protocol, (gint8) 0x82u,
+ NULL) > 0);
+ assert (thrift_compact_protocol_write_byte (protocol, 0, NULL) > 0);
+
+ /* send a valid message */
+ assert (thrift_compact_protocol_write_byte (protocol, (gint8) 0x82u,
+ NULL) > 0);
+ assert (thrift_compact_protocol_write_byte (protocol, 0x01u, NULL) > 0);
+ thrift_compact_protocol_write_varint32 (tc, 1, NULL);
+ thrift_compact_protocol_write_string (protocol, "test", NULL);
+
+ /* broken 2nd read */
+ thrift_compact_protocol_write_byte (protocol, (gint8) 0x82u, NULL);
+
+ /* send a broken 3rd read */
+ thrift_compact_protocol_write_byte (protocol, (gint8) 0x82u, NULL);
+ thrift_compact_protocol_write_byte (protocol, 0x01u, NULL);
+
+ /* send a broken 4th read */
+ thrift_compact_protocol_write_byte (protocol, (gint8) 0x82u, NULL);
+ thrift_compact_protocol_write_byte (protocol, 0x01u, NULL);
+ thrift_compact_protocol_write_varint32 (tc, 1, NULL);
+
+ /* send a valid message */
+ assert (thrift_compact_protocol_write_message_begin (protocol, "test",
+ T_CALL, 1, NULL) > 0);
+
+ assert (thrift_compact_protocol_write_message_end (protocol, NULL) == 0);
+
+ /* send broken writes */
+ transport_write_error = 1;
+ assert (thrift_compact_protocol_write_message_begin (protocol, "test",
+ T_CALL, 1, NULL) == -1);
+ transport_write_error = 0;
+
+ transport_write_count = 0;
+ transport_write_error_at = 1;
+ assert (thrift_compact_protocol_write_message_begin (protocol, "test",
+ T_CALL, 1, NULL) == -1);
+ transport_write_error_at = -1;
+
+ transport_write_count = 0;
+ transport_write_error_at = 2;
+ assert (thrift_compact_protocol_write_message_begin (protocol, "test",
+ T_CALL, 1, NULL) == -1);
+ transport_write_error_at = -1;
+
+ transport_write_count = 0;
+ transport_write_error_at = 3;
+ assert (thrift_compact_protocol_write_message_begin (protocol, "test",
+ T_CALL, 1, NULL) == -1);
+ transport_write_error_at = -1;
+
+ /* clean up */
+ thrift_transport_close (transport, NULL);
+ g_object_unref (tsocket);
+ g_object_unref (protocol);
+ assert (wait (&status) == pid);
+ assert (status == 0);
+ }
+}
+
+
+static void
+thrift_server_primitives (const int port)
+{
+ ThriftServerTransport *transport = NULL;
+ ThriftTransport *client = NULL;
+ ThriftCompactProtocol *tc = NULL;
+ ThriftProtocol *protocol = NULL;
+ gboolean value_boolean = FALSE;
+ gint8 value_byte = 0,
+ zigzag_p16 = 0, zigzag_p32 = 0, zigzag_p64 = 0,
+ zigzag_n16 = 0, zigzag_n32 = 0, zigzag_n64 = 0;
+ gint16 value_16 = 0;
+ gint32 value_32 = 0;
+ gint64 value_64 = 0;
+ gint16 value_n16 = 0;
+ gint32 value_n32 = 0;
+ gint64 value_n64 = 0;
+ gdouble value_double = 0;
+ gchar *string = NULL;
+ gpointer binary = NULL;
+ guint32 len = 0;
+ void *comparator = (void *) TEST_STRING;
+
+ ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
+ "port", port, NULL);
+ transport = THRIFT_SERVER_TRANSPORT (tsocket);
+ thrift_server_transport_listen (transport, NULL);
+ client = thrift_server_transport_accept (transport, NULL);
+ assert (client != NULL);
+
+ tc = g_object_new (THRIFT_TYPE_COMPACT_PROTOCOL, "transport",
+ client, NULL);
+ protocol = THRIFT_PROTOCOL (tc);
+
+ assert (thrift_compact_protocol_read_bool (protocol,
+ &value_boolean, NULL) > 0);
+ assert (thrift_compact_protocol_read_byte (protocol, &value_byte, NULL) > 0);
+ assert (thrift_compact_protocol_read_i16 (protocol, &value_16, NULL) > 0);
+ assert (thrift_compact_protocol_read_i32 (protocol, &value_32, NULL) > 0);
+ assert (thrift_compact_protocol_read_i64 (protocol, &value_64, NULL) > 0);
+ assert (thrift_compact_protocol_read_i16 (protocol, &value_n16, NULL) > 0);
+ assert (thrift_compact_protocol_read_i32 (protocol, &value_n32, NULL) > 0);
+ assert (thrift_compact_protocol_read_i64 (protocol, &value_n64, NULL) > 0);
+ assert (thrift_compact_protocol_read_byte (protocol, &zigzag_p16, NULL) > 0);
+ assert (thrift_compact_protocol_read_byte (protocol, &zigzag_p32, NULL) > 0);
+ assert (thrift_compact_protocol_read_byte (protocol, &zigzag_p64, NULL) > 0);
+ assert (thrift_compact_protocol_read_byte (protocol, &zigzag_n16, NULL) > 0);
+ assert (thrift_compact_protocol_read_byte (protocol, &zigzag_n32, NULL) > 0);
+ assert (thrift_compact_protocol_read_byte (protocol, &zigzag_n64, NULL) > 0);
+ assert (thrift_compact_protocol_read_double (protocol,
+ &value_double, NULL) > 0);
+ assert (thrift_compact_protocol_read_string (protocol, &string, NULL) > 0);
+ assert (thrift_compact_protocol_read_binary (protocol, &binary,
+ &len, NULL) > 0);
+
+ assert (value_boolean == TEST_BOOL);
+ assert (value_byte == TEST_BYTE);
+ assert (value_16 == TEST_I16);
+ assert (value_32 == TEST_I32);
+ assert (value_64 == TEST_I64);
+ assert (value_n16 == TEST_NI16);
+ assert (value_n32 == TEST_NI32);
+ assert (value_n64 == TEST_NI64);
+ assert (zigzag_p16 == 4);
+ assert (zigzag_p32 == 4);
+ assert (zigzag_p64 == 4);
+ assert (zigzag_n16 == 3);
+ assert (zigzag_n32 == 3);
+ assert (zigzag_n64 == 3);
+ assert (value_double == TEST_DOUBLE);
+ assert (strcmp (TEST_STRING, string) == 0);
+ assert (memcmp (comparator, binary, len) == 0);
+
+ g_free (string);
+ g_free (binary);
+
+ thrift_compact_protocol_read_binary (protocol, &binary, &len, NULL);
+ g_free (binary);
+
+ transport_read_count = 0;
+ transport_read_error_at = 0;
+ assert (thrift_compact_protocol_read_binary (protocol, &binary,
+ &len, NULL) == -1);
+ transport_read_error_at = -1;
+
+ transport_read_count = 0;
+ transport_read_error_at = 1;
+ assert (thrift_compact_protocol_read_binary (protocol, &binary,
+ &len, NULL) == -1);
+ transport_read_error_at = -1;
+
+ transport_read_error = 1;
+ assert (thrift_compact_protocol_read_bool (protocol,
+ &value_boolean, NULL) == -1);
+ assert (thrift_compact_protocol_read_byte (protocol,
+ &value_byte, NULL) == -1);
+ assert (thrift_compact_protocol_read_i16 (protocol,
+ &value_16, NULL) == -1);
+ assert (thrift_compact_protocol_read_i32 (protocol, &value_32, NULL) == -1);
+ assert (thrift_compact_protocol_read_i64 (protocol, &value_64, NULL) == -1);
+ assert (thrift_compact_protocol_read_i16 (protocol,
+ &value_n16, NULL) == -1);
+ assert (thrift_compact_protocol_read_i32 (protocol, &value_n32, NULL) == -1);
+ assert (thrift_compact_protocol_read_i64 (protocol, &value_n64, NULL) == -1);
+ assert (thrift_compact_protocol_read_double (protocol,
+ &value_double, NULL) == -1);
+ transport_read_error = 0;
+
+ /* test partial write failure */
+ thrift_protocol_read_i32 (protocol, &value_32, NULL);
+
+ thrift_transport_read_end (client, NULL);
+ thrift_transport_close (client, NULL);
+
+ g_object_unref (tc);
+ g_object_unref (client);
+ g_object_unref (tsocket);
+}
+
+static void
+thrift_server_complex_types (const int port)
+{
+ ThriftServerTransport *transport = NULL;
+ ThriftTransport *client = NULL;
+ ThriftCompactProtocol *tc = NULL;
+ ThriftProtocol *protocol = NULL;
+ gchar *struct_name = NULL;
+ gchar *field_name = NULL;
+ gchar *message_name = NULL;
+ ThriftType element_type, key_type, value_type, field_type;
+ ThriftMessageType message_type;
+ gboolean value_boolean = ! TEST_BOOL;
+ gint8 value = 0;
+ gint16 field_id = 0;
+ guint32 size = 0;
+ gint32 seqid = 0;
+ gint8 version_and_type = 0;
+ gint8 protocol_id = 0;
+
+ ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
+ "port", port, NULL);
+ transport = THRIFT_SERVER_TRANSPORT (tsocket);
+ thrift_server_transport_listen (transport, NULL);
+ client = thrift_server_transport_accept (transport, NULL);
+ assert (client != NULL);
+
+ tc = g_object_new (THRIFT_TYPE_COMPACT_PROTOCOL, "transport",
+ client, NULL);
+ protocol = THRIFT_PROTOCOL (tc);
+
+ /* test struct operations */
+
+ thrift_compact_protocol_read_struct_begin (protocol, &struct_name, NULL);
+ thrift_compact_protocol_read_struct_end (protocol, NULL);
+
+ /* test field state w.r.t. deltas */
+
+ field_id = 0;
+ assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+ &field_type,
+ &field_id, NULL) == 1);
+ assert (field_id == 1);
+ field_id = 0;
+ assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+ &field_type,
+ &field_id, NULL) == 1);
+ assert (field_id == 16);
+ field_id = 0;
+ assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+ &field_type,
+ &field_id, NULL) == 1);
+ assert (field_id == 17);
+ field_id = 0;
+ assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+ &field_type,
+ &field_id, NULL) > 1);
+ assert (field_id == 15);
+ field_id = 0;
+ assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+ &field_type,
+ &field_id, NULL) == 1);
+ assert (field_id == 30);
+ field_id = 0;
+ assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+ &field_type,
+ &field_id, NULL) > 1);
+ assert (field_id == 46);
+ field_id = 0;
+ assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+ &field_type,
+ &field_id, NULL) == 1);
+ assert (field_id == 47);
+ field_id = 0;
+
+ /* test field operations */
+
+ thrift_compact_protocol_read_field_begin (protocol, &field_name, &field_type,
+ &field_id, NULL);
+ thrift_compact_protocol_read_field_end (protocol, NULL);
+
+ /* test field state w.r.t. structs */
+
+ assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+ &field_type,
+ &field_id, NULL) > 1);
+ assert (field_id == 1);
+ field_id = 0;
+ thrift_compact_protocol_read_field_end (protocol, NULL);
+ assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+ &field_type,
+ &field_id, NULL) == 1);
+ assert (field_id == 16);
+ field_id = 0;
+ thrift_compact_protocol_read_field_end (protocol, NULL);
+
+ assert (thrift_compact_protocol_read_struct_begin (protocol,
+ &struct_name, NULL) == 0);
+ assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+ &field_type,
+ &field_id, NULL) > 1);
+ assert (field_id == 17);
+ field_id = 0;
+ thrift_compact_protocol_read_field_end (protocol, NULL);
+
+ assert (thrift_compact_protocol_read_struct_begin (protocol,
+ &struct_name, NULL) == 0);
+ assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+ &field_type,
+ &field_id, NULL) > 1);
+ assert (field_id == 18);
+ field_id = 0;
+ thrift_compact_protocol_read_field_end (protocol, NULL);
+ assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+ &field_type,
+ &field_id, NULL) == 1);
+ assert (field_id == 19);
+ field_id = 0;
+ thrift_compact_protocol_read_field_end (protocol, NULL);
+ assert (thrift_compact_protocol_read_struct_end (protocol, NULL) == 0);
+
+ assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+ &field_type,
+ &field_id, NULL) == 1);
+ assert (field_id == 18);
+ field_id = 0;
+ thrift_compact_protocol_read_field_end (protocol, NULL);
+ assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+ &field_type,
+ &field_id, NULL) == 1);
+ assert (field_id == 25);
+ field_id = 0;
+ thrift_compact_protocol_read_field_end (protocol, NULL);
+ assert (thrift_compact_protocol_read_struct_end (protocol, NULL) == 0);
+
+ assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+ &field_type,
+ &field_id, NULL) == 1);
+ assert (field_id == 17);
+ field_id = 0;
+ thrift_compact_protocol_read_field_end (protocol, NULL);
+
+ /* test field state w.r.t. bools */
+
+ /* deltas */
+ /* non-bool field -> bool field -> non-bool field */
+ assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+ &field_type,
+ &field_id, NULL) == 1);
+ thrift_compact_protocol_read_field_end (protocol, NULL);
+ assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+ &field_type,
+ &field_id, NULL) == 1);
+ assert (field_type == T_BOOL);
+ assert (thrift_compact_protocol_read_bool (protocol,
+ &value_boolean, NULL) == 0);
+ assert (value_boolean == TEST_BOOL);
+ value_boolean = ! TEST_BOOL;
+ thrift_compact_protocol_read_field_end (protocol, NULL);
+ assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+ &field_type,
+ &field_id, NULL) == 1);
+ thrift_compact_protocol_read_field_end (protocol, NULL);
+ /* bool -> bool field -> bool */
+ assert (thrift_compact_protocol_read_bool (protocol,
+ &value_boolean, NULL) > 0);
+ assert (value_boolean == TEST_BOOL);
+ value_boolean = ! TEST_BOOL;
+ assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+ &field_type,
+ &field_id, NULL) == 1);
+ assert (field_type == T_BOOL);
+ assert (thrift_compact_protocol_read_bool (protocol,
+ &value_boolean, NULL) == 0);
+ assert (value_boolean == TEST_BOOL);
+ value_boolean = ! TEST_BOOL;
+ thrift_compact_protocol_read_field_end (protocol, NULL);
+ assert (thrift_compact_protocol_read_bool (protocol,
+ &value_boolean, NULL) > 0);
+ assert (value_boolean == TEST_BOOL);
+ value_boolean = ! TEST_BOOL;
+
+ /* no deltas */
+ /* non-bool field -> bool field -> non-bool field */
+ assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+ &field_type,
+ &field_id, NULL) > 1);
+ thrift_compact_protocol_read_field_end (protocol, NULL);
+ assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+ &field_type,
+ &field_id, NULL) > 1);
+ assert (field_type == T_BOOL);
+ assert (thrift_compact_protocol_read_bool (protocol,
+ &value_boolean, NULL) == 0);
+ assert (value_boolean == TEST_BOOL);
+ value_boolean = ! TEST_BOOL;
+ thrift_compact_protocol_read_field_end (protocol, NULL);
+ assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+ &field_type,
+ &field_id, NULL) > 1);
+ thrift_compact_protocol_read_field_end (protocol, NULL);
+ /* bool -> bool field -> bool */
+ assert (thrift_compact_protocol_read_bool (protocol,
+ &value_boolean, NULL) > 0);
+ assert (value_boolean == TEST_BOOL);
+ value_boolean = ! TEST_BOOL;
+ assert (thrift_compact_protocol_read_field_begin (protocol, &field_name,
+ &field_type,
+ &field_id, NULL) > 1);
+ assert (field_type == T_BOOL);
+ assert (thrift_compact_protocol_read_bool (protocol,
+ &value_boolean, NULL) == 0);
+ assert (value_boolean == TEST_BOOL);
+ value_boolean = ! TEST_BOOL;
+ thrift_compact_protocol_read_field_end (protocol, NULL);
+ assert (thrift_compact_protocol_read_bool (protocol,
+ &value_boolean, NULL) > 0);
+ assert (value_boolean == TEST_BOOL);
+ value_boolean = ! TEST_BOOL;
+
+ /* test first read error on a field */
+ transport_read_error = 1;
+ assert (thrift_compact_protocol_read_field_begin (protocol,
+ &field_name, &field_type,
+ &field_id, NULL) == -1);
+ transport_read_error = 0;
+
+ /* test 2nd write failure */
+ thrift_compact_protocol_read_byte (protocol, &value, NULL);
+
+ /* test 2nd read failure on a field */
+ transport_read_count = 0;
+ transport_read_error_at = 1;
+ assert (thrift_compact_protocol_read_field_begin (protocol,
+ &field_name, &field_type,
+ &field_id, NULL) == -1);
+ transport_read_error_at = -1;
+
+ /* test field stop */
+ thrift_compact_protocol_read_field_begin (protocol, &field_name, &field_type,
+ &field_id, NULL);
+
+ /* test map operations */
+
+ thrift_compact_protocol_read_map_begin (protocol, &key_type, &value_type,
+ &size, NULL);
+ thrift_compact_protocol_read_map_end (protocol, NULL);
+
+ /* test 1st read failure on a map */
+ transport_read_count = 0;
+ transport_read_error_at = 0;
+ assert (thrift_compact_protocol_read_map_begin (protocol,
+ &key_type, &value_type,
+ &size, NULL) == -1);
+ transport_read_error_at = -1;
+
+ /* test 2nd read failure on a map */
+ transport_read_count = 0;
+ transport_read_error_at = 1;
+ assert (thrift_compact_protocol_read_map_begin (protocol,
+ &key_type, &value_type,
+ &size, NULL) == -1);
+ transport_read_error_at = -1;
+
+ /* test 1st write failure on map---nothing to do on our side */
+
+ /* test 2nd write failure */
+ thrift_compact_protocol_read_byte (protocol, &value, NULL);
+
+ /* test negative map size */
+ assert (thrift_compact_protocol_read_map_begin (protocol,
+ &key_type, &value_type,
+ &size, NULL) == -1);
+
+ /* test list operations */
+ thrift_compact_protocol_read_list_begin (protocol, &element_type, &size,
+ NULL);
+ thrift_compact_protocol_read_list_end (protocol, NULL);
+
+ /* test small list 1st read failure */
+ transport_read_error = 1;
+ assert (thrift_compact_protocol_read_list_begin (protocol, &element_type,
+ &size, NULL) == -1);
+ transport_read_error = 0;
+
+ /* test big list 1st read failure */
+ transport_read_error = 1;
+ assert (thrift_compact_protocol_read_list_begin (protocol, &element_type,
+ &size, NULL) == -1);
+ transport_read_error = 0;
+
+ /* test big list 2nd read failure */
+ transport_read_count = 0;
+ transport_read_error_at = 1;
+ thrift_compact_protocol_read_list_begin (protocol, &element_type, &size,
+ NULL);
+ transport_read_error_at = -1;
+
+ /* test negative list size failure */
+ thrift_compact_protocol_read_list_begin (protocol, &element_type, &size,
+ NULL);
+
+ /* test small list 1st write failure---nothing to do on our end */
+
+ /* test big list 1st write failure---nothing to do on our end */
+
+ /* test big list 2nd write failure */
+ thrift_compact_protocol_read_byte (protocol, &value, NULL);
+
+ /* test set operations */
+ thrift_compact_protocol_read_set_begin (protocol, &element_type, &size, NULL);
+ thrift_compact_protocol_read_set_end (protocol, NULL);
+
+ /* broken read */
+ transport_read_error = 1;
+ assert (thrift_compact_protocol_read_message_begin (protocol, &message_name,
+ &message_type, &seqid,
+ NULL) == -1);
+ transport_read_error = 0;
+
+ /* invalid protocol */
+ assert (thrift_compact_protocol_read_message_begin (protocol, &message_name,
+ &message_type, &seqid,
+ NULL) == -1);
+
+ /* invalid version */
+ assert (thrift_compact_protocol_read_message_begin (protocol, &message_name,
+ &message_type, &seqid,
+ NULL) == -1);
+
+ /* read a valid message */
+ assert (thrift_compact_protocol_read_message_begin (protocol, &message_name,
+ &message_type, &seqid,
+ NULL) > 0);
+ g_free (message_name);
+
+ /* broken 2nd read on a message */
+ transport_read_count = 0;
+ transport_read_error_at = 1;
+ assert (thrift_compact_protocol_read_message_begin (protocol, &message_name,
+ &message_type, &seqid,
+ NULL) == -1);
+ transport_read_error_at = -1;
+
+ /* broken 3rd read on a message */
+ transport_read_count = 0;
+ transport_read_error_at = 2;
+ assert (thrift_compact_protocol_read_message_begin (protocol, &message_name,
+ &message_type, &seqid,
+ NULL) == -1);
+ transport_read_error_at = -1;
+
+ /* broken 4th read on a message */
+ transport_read_count = 0;
+ transport_read_error_at = 3;
+ assert (thrift_compact_protocol_read_message_begin (protocol, &message_name,
+ &message_type, &seqid,
+ NULL) == -1);
+ transport_read_error_at = -1;
+
+ /* read a valid message */
+ assert (thrift_compact_protocol_read_message_begin (protocol, &message_name,
+ &message_type, &seqid,
+ NULL) > 0);
+ g_free (message_name);
+
+ assert (thrift_compact_protocol_read_message_end (protocol, NULL) == 0);
+
+ /* handle 2nd write failure on a message */
+ thrift_compact_protocol_read_byte (protocol, &protocol_id, NULL);
+
+ /* handle 3rd write failure on a message */
+ thrift_compact_protocol_read_byte (protocol, &protocol_id, NULL);
+ thrift_compact_protocol_read_byte (protocol, &version_and_type, NULL);
+
+ /* handle 4th write failure on a message */
+ thrift_compact_protocol_read_byte (protocol, &protocol_id, NULL);
+ thrift_compact_protocol_read_byte (protocol, &version_and_type, NULL);
+ thrift_compact_protocol_read_varint32 (tc, &seqid, NULL);
+
+ g_object_unref (client);
+ g_object_unref (tsocket);
+}
+
+int
+main (int argc, char *argv[])
+{
+#if (!GLIB_CHECK_VERSION (2, 36, 0))
+ g_type_init ();
+#endif
+
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add_func ("/testcompactprotocol/CreateAndDestroy",
+ test_create_and_destroy);
+ g_test_add_func ("/testcompactprotocol/Initialize", test_initialize);
+ g_test_add_func ("/testcompactprotocol/ReadAndWritePrimitives",
+ test_read_and_write_primitives);
+ g_test_add_func ("/testcompactprotocol/ReadAndWriteComplexTypes",
+ test_read_and_write_complex_types);
+
+ return g_test_run ();
+}