diff options
Diffstat (limited to 'libgimpbase/gimpwire.c')
-rw-r--r-- | libgimpbase/gimpwire.c | 695 |
1 files changed, 695 insertions, 0 deletions
diff --git a/libgimpbase/gimpwire.c b/libgimpbase/gimpwire.c new file mode 100644 index 0000000..9382bee --- /dev/null +++ b/libgimpbase/gimpwire.c @@ -0,0 +1,695 @@ +/* LIBGIMP - The GIMP Library + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball + * + * This library is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <string.h> + +#include <glib-object.h> + +#include <libgimpcolor/gimpcolortypes.h> + +#include "gimpwire.h" + + +typedef struct _GimpWireHandler GimpWireHandler; + +struct _GimpWireHandler +{ + guint32 type; + GimpWireReadFunc read_func; + GimpWireWriteFunc write_func; + GimpWireDestroyFunc destroy_func; +}; + + +static GHashTable *wire_ht = NULL; +static GimpWireIOFunc wire_read_func = NULL; +static GimpWireIOFunc wire_write_func = NULL; +static GimpWireFlushFunc wire_flush_func = NULL; +static gboolean wire_error_val = FALSE; + + +static void gimp_wire_init (void); + + +void +gimp_wire_register (guint32 type, + GimpWireReadFunc read_func, + GimpWireWriteFunc write_func, + GimpWireDestroyFunc destroy_func) +{ + GimpWireHandler *handler; + + if (! wire_ht) + gimp_wire_init (); + + handler = g_hash_table_lookup (wire_ht, &type); + + if (! handler) + handler = g_slice_new0 (GimpWireHandler); + + handler->type = type; + handler->read_func = read_func; + handler->write_func = write_func; + handler->destroy_func = destroy_func; + + g_hash_table_insert (wire_ht, &handler->type, handler); +} + +void +gimp_wire_set_reader (GimpWireIOFunc read_func) +{ + wire_read_func = read_func; +} + +void +gimp_wire_set_writer (GimpWireIOFunc write_func) +{ + wire_write_func = write_func; +} + +void +gimp_wire_set_flusher (GimpWireFlushFunc flush_func) +{ + wire_flush_func = flush_func; +} + +gboolean +gimp_wire_read (GIOChannel *channel, + guint8 *buf, + gsize count, + gpointer user_data) +{ + if (wire_read_func) + { + if (!(* wire_read_func) (channel, buf, count, user_data)) + { + /* Gives a confusing error message most of the time, disable: + g_warning ("%s: gimp_wire_read: error", g_get_prgname ()); + */ + wire_error_val = TRUE; + return FALSE; + } + } + else + { + GIOStatus status; + GError *error = NULL; + gsize bytes; + + while (count > 0) + { + do + { + bytes = 0; + status = g_io_channel_read_chars (channel, + (gchar *) buf, count, + &bytes, + &error); + } + while (G_UNLIKELY (status == G_IO_STATUS_AGAIN)); + + if (G_UNLIKELY (status != G_IO_STATUS_NORMAL)) + { + if (error) + { + g_warning ("%s: gimp_wire_read(): error: %s", + g_get_prgname (), error->message); + g_error_free (error); + } + else + { + g_warning ("%s: gimp_wire_read(): error", + g_get_prgname ()); + } + + wire_error_val = TRUE; + return FALSE; + } + + if (G_UNLIKELY (bytes == 0)) + { + g_warning ("%s: gimp_wire_read(): unexpected EOF", + g_get_prgname ()); + wire_error_val = TRUE; + return FALSE; + } + + count -= bytes; + buf += bytes; + } + } + + return TRUE; +} + +gboolean +gimp_wire_write (GIOChannel *channel, + const guint8 *buf, + gsize count, + gpointer user_data) +{ + if (wire_write_func) + { + if (!(* wire_write_func) (channel, (guint8 *) buf, count, user_data)) + { + g_warning ("%s: gimp_wire_write: error", g_get_prgname ()); + wire_error_val = TRUE; + return FALSE; + } + } + else + { + GIOStatus status; + GError *error = NULL; + gsize bytes; + + while (count > 0) + { + do + { + bytes = 0; + status = g_io_channel_write_chars (channel, + (const gchar *) buf, count, + &bytes, + &error); + } + while (G_UNLIKELY (status == G_IO_STATUS_AGAIN)); + + if (G_UNLIKELY (status != G_IO_STATUS_NORMAL)) + { + if (error) + { + g_warning ("%s: gimp_wire_write(): error: %s", + g_get_prgname (), error->message); + g_error_free (error); + } + else + { + g_warning ("%s: gimp_wire_write(): error", + g_get_prgname ()); + } + + wire_error_val = TRUE; + return FALSE; + } + + count -= bytes; + buf += bytes; + } + } + + return TRUE; +} + +gboolean +gimp_wire_flush (GIOChannel *channel, + gpointer user_data) +{ + if (wire_flush_func) + return (* wire_flush_func) (channel, user_data); + + return FALSE; +} + +gboolean +gimp_wire_error (void) +{ + return wire_error_val; +} + +void +gimp_wire_clear_error (void) +{ + wire_error_val = FALSE; +} + +gboolean +gimp_wire_read_msg (GIOChannel *channel, + GimpWireMessage *msg, + gpointer user_data) +{ + GimpWireHandler *handler; + + if (G_UNLIKELY (! wire_ht)) + g_error ("gimp_wire_read_msg: the wire protocol has not been initialized"); + + if (wire_error_val) + return !wire_error_val; + + if (! _gimp_wire_read_int32 (channel, &msg->type, 1, user_data)) + return FALSE; + + handler = g_hash_table_lookup (wire_ht, &msg->type); + + if (G_UNLIKELY (! handler)) + g_error ("gimp_wire_read_msg: could not find handler for message: %d", + msg->type); + + (* handler->read_func) (channel, msg, user_data); + + return !wire_error_val; +} + +gboolean +gimp_wire_write_msg (GIOChannel *channel, + GimpWireMessage *msg, + gpointer user_data) +{ + GimpWireHandler *handler; + + if (G_UNLIKELY (! wire_ht)) + g_error ("gimp_wire_write_msg: the wire protocol has not been initialized"); + + if (wire_error_val) + return !wire_error_val; + + handler = g_hash_table_lookup (wire_ht, &msg->type); + + if (G_UNLIKELY (! handler)) + g_error ("gimp_wire_write_msg: could not find handler for message: %d", + msg->type); + + if (! _gimp_wire_write_int32 (channel, &msg->type, 1, user_data)) + return FALSE; + + (* handler->write_func) (channel, msg, user_data); + + return !wire_error_val; +} + +void +gimp_wire_destroy (GimpWireMessage *msg) +{ + GimpWireHandler *handler; + + if (G_UNLIKELY (! wire_ht)) + g_error ("gimp_wire_destroy: the wire protocol has not been initialized"); + + handler = g_hash_table_lookup (wire_ht, &msg->type); + + if (G_UNLIKELY (! handler)) + g_error ("gimp_wire_destroy: could not find handler for message: %d\n", + msg->type); + + (* handler->destroy_func) (msg); +} + +gboolean +_gimp_wire_read_int64 (GIOChannel *channel, + guint64 *data, + gint count, + gpointer user_data) +{ + g_return_val_if_fail (count >= 0, FALSE); + + if (count > 0) + { + if (! _gimp_wire_read_int8 (channel, + (guint8 *) data, count * 8, user_data)) + return FALSE; + + while (count--) + { + *data = GUINT64_FROM_BE (*data); + data++; + } + } + + return TRUE; +} + +gboolean +_gimp_wire_read_int32 (GIOChannel *channel, + guint32 *data, + gint count, + gpointer user_data) +{ + g_return_val_if_fail (count >= 0, FALSE); + + if (count > 0) + { + if (! _gimp_wire_read_int8 (channel, + (guint8 *) data, count * 4, user_data)) + return FALSE; + + while (count--) + { + *data = g_ntohl (*data); + data++; + } + } + + return TRUE; +} + +gboolean +_gimp_wire_read_int16 (GIOChannel *channel, + guint16 *data, + gint count, + gpointer user_data) +{ + g_return_val_if_fail (count >= 0, FALSE); + + if (count > 0) + { + if (! _gimp_wire_read_int8 (channel, + (guint8 *) data, count * 2, user_data)) + return FALSE; + + while (count--) + { + *data = g_ntohs (*data); + data++; + } + } + + return TRUE; +} + +gboolean +_gimp_wire_read_int8 (GIOChannel *channel, + guint8 *data, + gint count, + gpointer user_data) +{ + g_return_val_if_fail (count >= 0, FALSE); + + return gimp_wire_read (channel, data, count, user_data); +} + +gboolean +_gimp_wire_read_double (GIOChannel *channel, + gdouble *data, + gint count, + gpointer user_data) +{ + gdouble *t; + guint8 tmp[8]; + gint i; + + g_return_val_if_fail (count >= 0, FALSE); + + t = (gdouble *) tmp; + + for (i = 0; i < count; i++) + { +#if (G_BYTE_ORDER == G_LITTLE_ENDIAN) + gint j; +#endif + + if (! _gimp_wire_read_int8 (channel, tmp, 8, user_data)) + return FALSE; + +#if (G_BYTE_ORDER == G_LITTLE_ENDIAN) + for (j = 0; j < 4; j++) + { + guint8 swap; + + swap = tmp[j]; + tmp[j] = tmp[7 - j]; + tmp[7 - j] = swap; + } +#endif + + data[i] = *t; + } + + return TRUE; +} + +gboolean +_gimp_wire_read_string (GIOChannel *channel, + gchar **data, + gint count, + gpointer user_data) +{ + gint i; + + g_return_val_if_fail (count >= 0, FALSE); + + for (i = 0; i < count; i++) + { + guint32 tmp; + + if (! _gimp_wire_read_int32 (channel, &tmp, 1, user_data)) + return FALSE; + + if (tmp > 0) + { + data[i] = g_try_new (gchar, tmp); + + if (! data[i]) + { + g_printerr ("%s: failed to allocate %u bytes\n", G_STRFUNC, tmp); + return FALSE; + } + + if (! _gimp_wire_read_int8 (channel, + (guint8 *) data[i], tmp, user_data)) + { + g_free (data[i]); + return FALSE; + } + + /* make sure that the string is NULL-terminated */ + data[i][tmp - 1] = '\0'; + } + else + { + data[i] = NULL; + } + } + + return TRUE; +} + +gboolean +_gimp_wire_read_color (GIOChannel *channel, + GimpRGB *data, + gint count, + gpointer user_data) +{ + g_return_val_if_fail (count >= 0, FALSE); + + return _gimp_wire_read_double (channel, + (gdouble *) data, 4 * count, user_data); +} + +gboolean +_gimp_wire_write_int64 (GIOChannel *channel, + const guint64 *data, + gint count, + gpointer user_data) +{ + g_return_val_if_fail (count >= 0, FALSE); + + if (count > 0) + { + gint i; + + for (i = 0; i < count; i++) + { + guint64 tmp = GUINT64_TO_BE (data[i]); + + if (! _gimp_wire_write_int8 (channel, + (const guint8 *) &tmp, 8, user_data)) + return FALSE; + } + } + + return TRUE; +} + +gboolean +_gimp_wire_write_int32 (GIOChannel *channel, + const guint32 *data, + gint count, + gpointer user_data) +{ + g_return_val_if_fail (count >= 0, FALSE); + + if (count > 0) + { + gint i; + + for (i = 0; i < count; i++) + { + guint32 tmp = g_htonl (data[i]); + + if (! _gimp_wire_write_int8 (channel, + (const guint8 *) &tmp, 4, user_data)) + return FALSE; + } + } + + return TRUE; +} + +gboolean +_gimp_wire_write_int16 (GIOChannel *channel, + const guint16 *data, + gint count, + gpointer user_data) +{ + g_return_val_if_fail (count >= 0, FALSE); + + if (count > 0) + { + gint i; + + for (i = 0; i < count; i++) + { + guint16 tmp = g_htons (data[i]); + + if (! _gimp_wire_write_int8 (channel, + (const guint8 *) &tmp, 2, user_data)) + return FALSE; + } + } + + return TRUE; +} + +gboolean +_gimp_wire_write_int8 (GIOChannel *channel, + const guint8 *data, + gint count, + gpointer user_data) +{ + g_return_val_if_fail (count >= 0, FALSE); + + return gimp_wire_write (channel, data, count, user_data); +} + +gboolean +_gimp_wire_write_double (GIOChannel *channel, + const gdouble *data, + gint count, + gpointer user_data) +{ + gdouble *t; + guint8 tmp[8]; + gint i; +#if (G_BYTE_ORDER == G_LITTLE_ENDIAN) + gint j; +#endif + + g_return_val_if_fail (count >= 0, FALSE); + + t = (gdouble *) tmp; + + for (i = 0; i < count; i++) + { + *t = data[i]; + +#if (G_BYTE_ORDER == G_LITTLE_ENDIAN) + for (j = 0; j < 4; j++) + { + guint8 swap; + + swap = tmp[j]; + tmp[j] = tmp[7 - j]; + tmp[7 - j] = swap; + } +#endif + + if (! _gimp_wire_write_int8 (channel, tmp, 8, user_data)) + return FALSE; + +#if 0 + { + gint k; + + g_print ("Wire representation of %f:\t", data[i]); + + for (k = 0; k < 8; k++) + g_print ("%02x ", tmp[k]); + + g_print ("\n"); + } +#endif + } + + return TRUE; +} + +gboolean +_gimp_wire_write_string (GIOChannel *channel, + gchar **data, + gint count, + gpointer user_data) +{ + gint i; + + g_return_val_if_fail (count >= 0, FALSE); + + for (i = 0; i < count; i++) + { + guint32 tmp; + + if (data[i]) + tmp = strlen (data[i]) + 1; + else + tmp = 0; + + if (! _gimp_wire_write_int32 (channel, &tmp, 1, user_data)) + return FALSE; + + if (tmp > 0) + if (! _gimp_wire_write_int8 (channel, + (const guint8 *) data[i], tmp, user_data)) + return FALSE; + } + + return TRUE; +} + +gboolean +_gimp_wire_write_color (GIOChannel *channel, + const GimpRGB *data, + gint count, + gpointer user_data) +{ + g_return_val_if_fail (count >= 0, FALSE); + + return _gimp_wire_write_double (channel, + (gdouble *) data, 4 * count, user_data); +} + +static guint +gimp_wire_hash (const guint32 *key) +{ + return *key; +} + +static gboolean +gimp_wire_compare (const guint32 *a, + const guint32 *b) +{ + return (*a == *b); +} + +static void +gimp_wire_init (void) +{ + if (! wire_ht) + wire_ht = g_hash_table_new ((GHashFunc) gimp_wire_hash, + (GCompareFunc) gimp_wire_compare); +} |