libpurple/image.c

changeset 38277
061e91dd78d4
parent 36049
bffbd724134d
child 38278
f61362f66bbb
--- a/libpurple/image.c	Fri Sep 30 09:50:21 2016 -0500
+++ b/libpurple/image.c	Mon Sep 12 23:56:39 2016 -0500
@@ -30,176 +30,145 @@
 
 typedef struct {
 	gchar *path;
-	GString *contents;
+
+	GBytes *contents;
 
 	const gchar *extension;
 	const gchar *mime;
 	gchar *gen_filename;
 	gchar *friendly_filename;
-
-	gboolean is_ready;
-	gboolean has_failed;
 } PurpleImagePrivate;
 
-enum
-{
+enum {
 	PROP_0,
-	PROP_IS_READY,
-	PROP_HAS_FAILED,
 	PROP_LAST
 };
 
-enum
-{
-	SIG_READY,
-	SIG_FAILED,
-	SIG_LAST
-};
-
 static GObjectClass *parent_class;
-static guint signals[SIG_LAST];
 static GParamSpec *properties[PROP_LAST];
 
 /******************************************************************************
- * Internal logic
+ * Object stuff
  ******************************************************************************/
+static void
+purple_image_init(PurpleImage *image) {
+}
 
 static void
-has_failed(PurpleImage *image)
-{
-	gboolean ready_changed;
-	PurpleImagePrivate *priv;
-	priv = PURPLE_IMAGE_GET_PRIVATE(image);
+purple_image_finalize(GObject *obj) {
+	PurpleImagePrivate *priv = PURPLE_IMAGE_GET_PRIVATE(obj);
 
-	g_return_if_fail(!priv->has_failed);
-
-	priv->has_failed = TRUE;
-	ready_changed = (priv->is_ready != FALSE);
-	priv->is_ready = FALSE;
+	g_bytes_unref(priv->contents);
 
-	if (priv->contents) {
-		g_string_free(priv->contents, TRUE);
-		priv->contents = NULL;
-	}
+	g_free(priv->path);
+	g_free(priv->gen_filename);
+	g_free(priv->friendly_filename);
 
-	if (ready_changed) {
-		g_object_notify_by_pspec(G_OBJECT(image),
-			properties[PROP_IS_READY]);
-	}
-	g_object_notify_by_pspec(G_OBJECT(image), properties[PROP_HAS_FAILED]);
-	g_signal_emit(image, signals[SIG_FAILED], 0);
+	G_OBJECT_CLASS(parent_class)->finalize(obj);
 }
 
 static void
-became_ready(PurpleImage *image)
+purple_image_set_property(GObject *object, guint par_id,
+                          const GValue *value, GParamSpec *pspec)
 {
-	PurpleImagePrivate *priv;
-	priv = PURPLE_IMAGE_GET_PRIVATE(image);
+	switch (par_id) {
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(object, par_id, pspec);
+			break;
+	}
+}
 
-	g_return_if_fail(!priv->has_failed);
-	g_return_if_fail(!priv->is_ready);
-
-	priv->is_ready = TRUE;
-
-	g_object_notify_by_pspec(G_OBJECT(image), properties[PROP_IS_READY]);
-	g_signal_emit(image, signals[SIG_READY], 0);
+static void
+purple_image_get_property(GObject *object, guint par_id, GValue *value,
+                          GParamSpec *pspec)
+{
+	switch (par_id) {
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(object, par_id, pspec);
+			break;
+	}
 }
 
 static void
-steal_contents(PurpleImagePrivate *priv, gpointer data, gsize length)
-{
-	g_return_if_fail(priv != NULL);
-	g_return_if_fail(priv->contents == NULL);
-	g_return_if_fail(data != NULL);
-	g_return_if_fail(length > 0);
+purple_image_class_init(PurpleImageClass *klass) {
+	GObjectClass *gobj_class = G_OBJECT_CLASS(klass);
+
+	parent_class = g_type_class_peek_parent(klass);
 
-	priv->contents = g_string_new(NULL);
-	g_free(priv->contents->str);
-	priv->contents->str = data;
-	priv->contents->len = priv->contents->allocated_len = length;
+	gobj_class->finalize = purple_image_finalize;
+	gobj_class->get_property = purple_image_get_property;
+	gobj_class->set_property = purple_image_set_property;
+
+	g_object_class_install_properties(gobj_class, PROP_LAST, properties);
 }
 
-static void
-fill_data(PurpleImage *image)
-{
-	PurpleImagePrivate *priv;
-	GError *error = NULL;
-	gchar *contents;
-	gsize length;
-
-	priv = PURPLE_IMAGE_GET_PRIVATE(image);
-	if (priv->contents)
-		return;
-
-	if (!priv->is_ready)
-		return;
-
-	g_return_if_fail(priv->path);
-	(void)g_file_get_contents(priv->path, &contents, &length, &error);
-	if (error) {
-		purple_debug_error("image", "failed to read '%s' image: %s",
-			priv->path, error->message);
-		g_error_free(error);
-
-		has_failed(image);
-		return;
-	}
-
-	steal_contents(priv, contents, length);
-}
-
+G_DEFINE_TYPE_WITH_PRIVATE(PurpleImage, purple_image, G_TYPE_OBJECT);
 
 /******************************************************************************
- * API implementation
+ * API
  ******************************************************************************/
-
 PurpleImage *
-purple_image_new_from_file(const gchar *path, gboolean be_eager)
-{
-	PurpleImagePrivate *priv;
-	PurpleImage *img;
-
-	g_return_val_if_fail(path != NULL, NULL);
-	g_return_val_if_fail(g_file_test(path, G_FILE_TEST_EXISTS), NULL);
-
-	img = g_object_new(PURPLE_TYPE_IMAGE, NULL);
-	purple_image_set_friendly_filename(img, path);
-	priv = PURPLE_IMAGE_GET_PRIVATE(img);
-	priv->path = g_strdup(path);
-
-	if (be_eager) {
-		fill_data(img);
-		if (!priv->contents) {
-			g_object_unref(img);
-			return NULL;
-		}
-
-		g_assert(priv->is_ready && !priv->has_failed);
-	}
-
-	return img;
+purple_image_new_from_bytes(GBytes *bytes, GError **error) {
+	return g_object_new(
+		PURPLE_TYPE_IMAGE,
+		NULL
+	);
 }
 
 PurpleImage *
-purple_image_new_from_data(gpointer data, gsize length)
-{
-	PurpleImage *img;
-	PurpleImagePrivate *priv;
+purple_image_new_from_file(const gchar *path) {
+	PurpleImage *image = NULL;
+	GBytes *bytes = NULL;
+	gchar *contents = NULL;
+	gsize length = 0;
+
+	if(!g_file_test(path, G_FILE_TEST_EXISTS)) {
+		return NULL;
+	}
+
+	if(!g_file_get_contents(path, &contents, &length, NULL)) {
+		return NULL;
+	}
+
+	bytes = g_bytes_new_take(contents, length);
+
+	image = purple_image_new_from_bytes(bytes, NULL);
+
+	g_bytes_unref(bytes);
+
+	return image;
+}
 
-	g_return_val_if_fail(data != NULL, NULL);
-	g_return_val_if_fail(length > 0, NULL);
+PurpleImage *
+purple_image_new_from_data(const guint8 *data, gsize length) {
+	PurpleImage *image;
+	GBytes *bytes = NULL;
+
+	bytes = g_bytes_new(data, length);
+
+	image = purple_image_new_from_bytes(bytes, NULL);
+
+	g_bytes_unref(bytes);
 
-	img = g_object_new(PURPLE_TYPE_IMAGE, NULL);
-	priv = PURPLE_IMAGE_GET_PRIVATE(img);
+	return image;
+}
+
+PurpleImage *
+purple_image_new_from_data_take(guint8 *data, gsize length) {
+	PurpleImage *image;
+	GBytes *bytes = NULL;
 
-	steal_contents(priv, data, length);
+	bytes = g_bytes_new(data, length);
+
+	image = purple_image_new_from_bytes(bytes, NULL);
 
-	return img;
+	g_bytes_unref(bytes);
+
+	return image;
 }
 
 gboolean
-purple_image_save(PurpleImage *image, const gchar *path)
-{
+purple_image_save(PurpleImage *image, const gchar *path) {
 	PurpleImagePrivate *priv = PURPLE_IMAGE_GET_PRIVATE(image);
 	gconstpointer data;
 	gsize len;
@@ -223,8 +192,7 @@
 }
 
 const gchar *
-purple_image_get_path(PurpleImage *image)
-{
+purple_image_get_path(PurpleImage *image) {
 	PurpleImagePrivate *priv = PURPLE_IMAGE_GET_PRIVATE(image);
 
 	g_return_val_if_fail(priv != NULL, NULL);
@@ -232,58 +200,30 @@
 	return priv->path;
 }
 
-gboolean
-purple_image_is_ready(PurpleImage *image)
-{
-	PurpleImagePrivate *priv = PURPLE_IMAGE_GET_PRIVATE(image);
-
-	g_return_val_if_fail(priv != NULL, FALSE);
-
-	return priv->is_ready;
-}
+gsize
+purple_image_get_size(PurpleImage *image) {
+	PurpleImagePrivate *priv;
 
-gboolean
-purple_image_has_failed(PurpleImage *image)
-{
-	PurpleImagePrivate *priv = PURPLE_IMAGE_GET_PRIVATE(image);
-
-	g_return_val_if_fail(priv != NULL, TRUE);
+	g_return_val_if_fail(PURPLE_IS_IMAGE(image), 0);
 
-	return priv->has_failed;
-}
-
-gsize
-purple_image_get_size(PurpleImage *image)
-{
-	PurpleImagePrivate *priv;
 	priv = PURPLE_IMAGE_GET_PRIVATE(image);
 
-	g_return_val_if_fail(priv != NULL, 0);
-	g_return_val_if_fail(priv->is_ready, 0);
-
-	fill_data(image);
-	g_return_val_if_fail(priv->contents, 0);
-
-	return priv->contents->len;
+	return g_bytes_get_size(priv->contents);
 }
 
 gconstpointer
-purple_image_get_data(PurpleImage *image)
-{
-	PurpleImagePrivate *priv = PURPLE_IMAGE_GET_PRIVATE(image);
+purple_image_get_data(PurpleImage *image) {
+	PurpleImagePrivate *priv = NULL;
 
-	g_return_val_if_fail(priv != NULL, NULL);
-	g_return_val_if_fail(priv->is_ready, NULL);
+	g_return_val_if_fail(PURPLE_IS_IMAGE(image), NULL);
 
-	fill_data(image);
-	g_return_val_if_fail(priv->contents, NULL);
+	priv = PURPLE_IMAGE_GET_PRIVATE(image);
 
-	return priv->contents->str;
+	return g_bytes_get_data(priv->contents, NULL);
 }
 
 const gchar *
-purple_image_get_extension(PurpleImage *image)
-{
+purple_image_get_extension(PurpleImage *image) {
 	PurpleImagePrivate *priv = PURPLE_IMAGE_GET_PRIVATE(image);
 	gconstpointer data;
 
@@ -317,8 +257,7 @@
 }
 
 const gchar *
-purple_image_get_mimetype(PurpleImage *image)
-{
+purple_image_get_mimetype(PurpleImage *image) {
 	PurpleImagePrivate *priv = PURPLE_IMAGE_GET_PRIVATE(image);
 	const gchar *ext = purple_image_get_extension(image);
 
@@ -346,8 +285,7 @@
 }
 
 const gchar *
-purple_image_generate_filename(PurpleImage *image)
-{
+purple_image_generate_filename(PurpleImage *image) {
 	PurpleImagePrivate *priv = PURPLE_IMAGE_GET_PRIVATE(image);
 	gconstpointer data;
 	gsize len;
@@ -375,8 +313,7 @@
 }
 
 void
-purple_image_set_friendly_filename(PurpleImage *image, const gchar *filename)
-{
+purple_image_set_friendly_filename(PurpleImage *image, const gchar *filename) {
 	PurpleImagePrivate *priv = PURPLE_IMAGE_GET_PRIVATE(image);
 	gchar *newname;
 	const gchar *escaped;
@@ -400,223 +337,33 @@
 }
 
 const gchar *
-purple_image_get_friendly_filename(PurpleImage *image)
-{
-	PurpleImagePrivate *priv = PURPLE_IMAGE_GET_PRIVATE(image);
+purple_image_get_friendly_filename(PurpleImage *image) {
+	PurpleImagePrivate *priv = NULL;
 
-	g_return_val_if_fail(priv != NULL, NULL);
+	g_return_val_if_fail(PURPLE_IS_IMAGE(image), NULL);
 
-	if (G_UNLIKELY(!priv->friendly_filename)) {
-		const gchar *newname = purple_image_generate_filename(image);
-		gsize newname_len = strlen(newname);
+	priv = PURPLE_IMAGE_GET_PRIVATE(image);
 
-		if (newname_len < 10)
-			return NULL;
-
-		/* let's use last 6 characters from checksum + 4 characters
-		 * from file ext */
-		newname += newname_len - 10;
-		priv->friendly_filename = g_strdup(newname);
+	if(priv->friendly_filename) {
+		return priv->friendly_filename;
 	}
 
-	if (G_UNLIKELY(priv->is_ready &&
-		strchr(priv->friendly_filename, '.') == NULL))
-	{
-		const gchar *ext = purple_image_get_extension(image);
-		gchar *tmp;
-		if (!ext)
-			return priv->friendly_filename;
-
-		tmp = g_strdup_printf("%s.%s", priv->friendly_filename, ext);
-		g_free(priv->friendly_filename);
-		priv->friendly_filename = tmp;
-	}
-
-	return priv->friendly_filename;
+	return purple_image_get_friendly_filename(image);
 }
 
 PurpleImage *
-purple_image_transfer_new(void)
-{
-	PurpleImage *img;
-	PurpleImagePrivate *priv;
-
-	img = g_object_new(PURPLE_TYPE_IMAGE, NULL);
-	priv = PURPLE_IMAGE_GET_PRIVATE(img);
-
-	priv->is_ready = FALSE;
-	priv->contents = g_string_new(NULL);
-
-	return img;
-}
-
-void
-purple_image_transfer_write(PurpleImage *image, gconstpointer data,
-	gsize length)
-{
-	PurpleImagePrivate *priv =
-		PURPLE_IMAGE_GET_PRIVATE(image);
-
-	g_return_if_fail(priv != NULL);
-	g_return_if_fail(!priv->has_failed);
-	g_return_if_fail(!priv->is_ready);
-	g_return_if_fail(priv->contents != NULL);
-	g_return_if_fail(data != NULL || length == 0);
-
-	if (length == 0)
-		return;
-
-	g_string_append_len(priv->contents, (const gchar*)data, length);
-}
-
-void
-purple_image_transfer_close(PurpleImage *image)
-{
-	PurpleImagePrivate *priv =
-		PURPLE_IMAGE_GET_PRIVATE(image);
-
-	g_return_if_fail(priv != NULL);
-	g_return_if_fail(!priv->has_failed);
-	g_return_if_fail(!priv->is_ready);
-	g_return_if_fail(priv->contents != NULL);
-
-	if (priv->contents->len == 0) {
-		purple_debug_error("image", "image is empty");
-		has_failed(image);
-		return;
-	}
-
-	became_ready(image);
+purple_image_transfer_new(void) {
+	return NULL;
 }
 
 void
-purple_image_transfer_failed(PurpleImage *image)
-{
-	PurpleImagePrivate *priv =
-		PURPLE_IMAGE_GET_PRIVATE(image);
-
-	g_return_if_fail(priv != NULL);
-	g_return_if_fail(!priv->has_failed);
-	g_return_if_fail(!priv->is_ready);
-
-	has_failed(image);
-}
-
-/******************************************************************************
- * Object stuff
- ******************************************************************************/
-
-static void
-purple_image_init(GTypeInstance *instance, gpointer klass)
-{
-	PurpleImage *image = PURPLE_IMAGE(instance);
-	PurpleImagePrivate *priv =
-		PURPLE_IMAGE_GET_PRIVATE(image);
-
-	priv->contents = NULL;
-	priv->is_ready = TRUE;
-	priv->has_failed = FALSE;
-}
-
-static void
-purple_image_finalize(GObject *obj)
-{
-	PurpleImage *image = PURPLE_IMAGE(obj);
-	PurpleImagePrivate *priv =
-		PURPLE_IMAGE_GET_PRIVATE(image);
-
-	if (priv->contents)
-		g_string_free(priv->contents, TRUE);
-	g_free(priv->path);
-	g_free(priv->gen_filename);
-	g_free(priv->friendly_filename);
-
-	G_OBJECT_CLASS(parent_class)->finalize(obj);
-}
-
-static void
-purple_image_get_property(GObject *object, guint par_id, GValue *value,
-	GParamSpec *pspec)
-{
-	PurpleImage *image = PURPLE_IMAGE(object);
-	PurpleImagePrivate *priv = PURPLE_IMAGE_GET_PRIVATE(image);
-
-	switch (par_id) {
-		case PROP_IS_READY:
-			g_value_set_boolean(value, priv->is_ready);
-			break;
-		case PROP_HAS_FAILED:
-			g_value_set_boolean(value, priv->has_failed);
-			break;
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(object, par_id, pspec);
-			break;
-	}
+purple_image_transfer_write(PurpleImage *image, gconstpointer data, gsize length) {
 }
 
-static void
-purple_image_class_init(PurpleImageClass *klass)
-{
-	GObjectClass *gobj_class = G_OBJECT_CLASS(klass);
-
-	parent_class = g_type_class_peek_parent(klass);
-
-	g_type_class_add_private(klass, sizeof(PurpleImagePrivate));
-
-	gobj_class->finalize = purple_image_finalize;
-	gobj_class->get_property = purple_image_get_property;
-
-	properties[PROP_IS_READY] = g_param_spec_boolean("is-ready",
-		"Is ready", "The image is ready to be displayed. Image may "
-		"change the state to failed in a single case: if it's backed "
-		"by a file and that file fails to load",
-		TRUE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
-
-	properties[PROP_HAS_FAILED] = g_param_spec_boolean("has-failed",
-		"Has hailed", "The remote host has failed to send the image",
-		FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
-
-	g_object_class_install_properties(gobj_class, PROP_LAST, properties);
-
-	/**
-	 * PurpleImage::failed:
-	 * @image: a image that failed to transfer.
-	 *
-	 * Called when a @image fails to be transferred. It's guaranteed to be
-	 * fired at most once for a particular @image.
-	 */
-	signals[SIG_FAILED] = g_signal_new("failed", G_OBJECT_CLASS_TYPE(klass),
-		0, 0, NULL, NULL,
-		g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
-
-	/**
-	 * PurpleImage::ready:
-	 * @image: a image that became ready.
-	 *
-	 * Called when a @image becames ready to be displayed. It's guaranteed to be
-	 * fired at most once for a particular @image.
-	 */
-	signals[SIG_READY] = g_signal_new("ready", G_OBJECT_CLASS_TYPE(klass),
-		0, 0, NULL, NULL,
-		g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+void
+purple_image_transfer_close(PurpleImage *image) {
 }
 
-GType
-purple_image_get_type(void)
-{
-	static GType type = 0;
-
-	if (G_UNLIKELY(type == 0)) {
-		static const GTypeInfo info = {
-			.class_size = sizeof(PurpleImageClass),
-			.class_init = (GClassInitFunc)purple_image_class_init,
-			.instance_size = sizeof(PurpleImage),
-			.instance_init = purple_image_init,
-		};
-
-		type = g_type_register_static(G_TYPE_OBJECT,
-			"PurpleImage", &info, 0);
-	}
-
-	return type;
+void
+purple_image_transfer_failed(PurpleImage *image) {
 }

mercurial