aboutsummaryrefslogtreecommitdiffstats
path: root/facebook/facebook-util.c
diff options
context:
space:
mode:
authorjgeboski <jgeboski@gmail.com>2015-01-01 20:34:17 -0500
committerjgeboski <jgeboski@gmail.com>2015-01-14 16:06:03 -0500
commitcefcc09b3a91f882a4511f675750d1798494969b (patch)
treeaa42fa5520dcc1c686175ea7f0404fee9afdc1bf /facebook/facebook-util.c
parentaaf01c2b00420fd7e28b80c1a3c419f074b2b542 (diff)
downloadbitlbee-facebook-cefcc09b3a91f882a4511f675750d1798494969b.tar.gz
bitlbee-facebook-cefcc09b3a91f882a4511f675750d1798494969b.tar.bz2
bitlbee-facebook-cefcc09b3a91f882a4511f675750d1798494969b.tar.xz
Implemented initial MQTT interface
Diffstat (limited to 'facebook/facebook-util.c')
-rw-r--r--facebook/facebook-util.c221
1 files changed, 221 insertions, 0 deletions
diff --git a/facebook/facebook-util.c b/facebook/facebook-util.c
index 84cc581..5cea807 100644
--- a/facebook/facebook-util.c
+++ b/facebook/facebook-util.c
@@ -15,7 +15,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <stdarg.h>
#include <string.h>
+#include <zlib.h>
#include "facebook-util.h"
@@ -41,6 +43,80 @@ gboolean fb_util_debugging(void)
#endif /* DEBUG_FACEBOOK */
/**
+ * Dumps a #GByteArray to the debugging stream. This formats the output
+ * similar to that of `hexdump -C`.
+ *
+ * @param bytes The #GByteArray.
+ * @param indent The indent width.
+ * @param fmt The format string or NULL.
+ * @param ... The format arguments.
+ **/
+#ifdef DEBUG_FACEBOOK
+void fb_util_hexdump(const GByteArray *bytes, guint indent,
+ const gchar *fmt, ...)
+{
+ GString *gstr;
+ va_list ap;
+ gchar *instr;
+ guint i;
+ guint j;
+ gchar c;
+
+ if (fmt != NULL) {
+ va_start(ap, fmt);
+ instr = g_strdup_vprintf(fmt, ap);
+ FB_UTIL_DEBUGLN("%s", instr);
+ g_free(instr);
+ va_end(ap);
+ }
+
+ instr = g_strnfill(indent, ' ');
+ gstr = g_string_sized_new(80);
+ i = 0;
+
+ if (G_UNLIKELY(bytes == NULL))
+ goto finish;
+
+ for (; i < bytes->len; i += 16) {
+ g_string_append_printf(gstr, "%s%08x ", instr, i);
+
+ for (j = 0; j < 16; j++) {
+ if ((i + j) < bytes->len) {
+ g_string_append_printf(gstr, "%02x ", bytes->data[i + j]);
+ } else {
+ g_string_append(gstr, " ");
+ }
+
+ if (j == 7)
+ g_string_append_c(gstr, ' ');
+ }
+
+ g_string_append(gstr, " |");
+
+ for (j = 0; (j < 16) && ((i + j) < bytes->len); j++) {
+ c = bytes->data[i + j];
+
+ if (!g_ascii_isprint(c) || g_ascii_isspace(c))
+ c = '.';
+
+ g_string_append_c(gstr, c);
+ }
+
+ g_string_append_c(gstr, '|');
+ FB_UTIL_DEBUGLN("%s", gstr->str);
+ g_string_erase(gstr, 0, -1);
+ }
+
+finish:
+ g_string_append_printf(gstr, "%s%08x", instr, i);
+ FB_UTIL_DEBUGLN("%s", gstr->str);
+
+ g_string_free(gstr, TRUE);
+ g_free(instr);
+}
+#endif /* DEBUG_FACEBOOK */
+
+/**
* Compare two strings case insensitively. This is useful for where
* the return value must be a boolean, such as with a #GEqualFunc.
*
@@ -53,3 +129,148 @@ gboolean fb_util_str_iequal(const gchar *s1, const gchar *s2)
{
return g_ascii_strcasecmp(s1, s2) == 0;
}
+
+/**
+ * Implemented #alloc_func for #g_malloc().
+ *
+ * @param opaque The user-defined data, which is NULL.
+ * @param items The number of items.
+ * @param size The size of each item.
+ *
+ * @return The pointer to the allocated memory.
+ **/
+static voidpf fb_util_zalloc(voidpf opaque, uInt items, uInt size)
+{
+ return g_malloc(size * items);
+}
+
+/**
+ * Implemented #free_func for #g_free().
+ *
+ * @param opaque The user-defined data, which is NULL.
+ * @param address The pointer address.
+ **/
+static void fb_util_zfree(voidpf opaque, voidpf address)
+{
+ g_free(address);
+}
+
+/**
+ * Determines if a #GByteArray is zlib compressed.
+ *
+ * @param bytes The #GByteArray.
+ *
+ * @return TRUE if the #GByteArray is compressed, otherwise FALSE.
+ **/
+gboolean fb_util_zcompressed(const GByteArray *bytes)
+{
+ guint8 b0;
+ guint8 b1;
+
+ g_return_if_fail(bytes != NULL);
+
+ if (bytes->len < 2)
+ return FALSE;
+
+ b0 = *(bytes->data + 0);
+ b1 = *(bytes->data + 1);
+
+ return ((((b0 << 8) | b1) % 31) == 0) && /* Check the header */
+ ((b0 & 0x0F) == Z_DEFLATED); /* Check the method */
+}
+
+/**
+ * Compresses a #GByteArray with zlib. The returned #GByteArray should
+ * be freed with #g_byte_array_free() when no longer needed.
+ *
+ * @param bytes The #GByteArray.
+ *
+ * @return The resulting #GByteArray, or NULL on error.
+ **/
+GByteArray *fb_util_zcompress(const GByteArray *bytes)
+{
+ GByteArray *ret;
+ z_stream zs;
+ gsize size;
+ gint res;
+
+ g_return_if_fail(bytes != NULL);
+
+ memset(&zs, 0, sizeof zs);
+ zs.zalloc = fb_util_zalloc;
+ zs.zfree = fb_util_zfree;
+ zs.next_in = bytes->data;
+ zs.avail_in = bytes->len;
+
+ if (deflateInit(&zs, Z_BEST_COMPRESSION) != Z_OK)
+ return NULL;
+
+ size = compressBound(bytes->len);
+ ret = g_byte_array_new();
+
+ g_byte_array_set_size(ret, size);
+
+ zs.next_out = ret->data;
+ zs.avail_out = size;
+
+ res = deflate(&zs, Z_FINISH);
+
+ if (res != Z_STREAM_END) {
+ deflateEnd(&zs);
+ g_byte_array_free(ret, TRUE);
+ return NULL;
+ }
+
+ size -= zs.avail_out;
+ g_byte_array_remove_range(ret, size, ret->len - size);
+
+ deflateEnd(&zs);
+ return ret;
+}
+
+/**
+ * Uncompresses a zlib compressed #GByteArray. The returned #GByteArray
+ * should be freed with #g_byte_array_free() when no longer needed.
+ *
+ * @param bytes The #GByteArray.
+ *
+ * @return The resulting #GByteArray, or NULL on error.
+ **/
+GByteArray *fb_util_zuncompress(const GByteArray *bytes)
+{
+ GByteArray *ret;
+ z_stream zs;
+ guint8 out[1024];
+ gint res;
+
+ g_return_if_fail(bytes != NULL);
+
+ memset(&zs, 0, sizeof zs);
+ zs.zalloc = fb_util_zalloc;
+ zs.zfree = fb_util_zfree;
+ zs.next_in = bytes->data;
+ zs.avail_in = bytes->len;
+
+ if (inflateInit(&zs) != Z_OK)
+ return NULL;
+
+ ret = g_byte_array_new();
+
+ do {
+ zs.next_out = out;
+ zs.avail_out = sizeof out;
+
+ res = inflate(&zs, Z_NO_FLUSH);
+
+ if ((res != Z_OK) && (res != Z_STREAM_END)) {
+ inflateEnd(&zs);
+ g_byte_array_free(ret, TRUE);
+ return NULL;
+ }
+
+ g_byte_array_append(ret, out, sizeof out - zs.avail_out);
+ } while (res != Z_STREAM_END);
+
+ inflateEnd(&zs);
+ return ret;
+}