Fix a crash when remote users have certain characters in their
[pidgin-git.git] / libpurple / imgstore.c
blobb7fed1910997bcafabc3df44d215744dc8057ea2
1 /**
2 * @file imgstore.c IM Image Store API
3 * @ingroup core
4 */
6 /* purple
8 * Purple is the legal property of its developers, whose names are too numerous
9 * to list here. Please refer to the COPYRIGHT file distributed with this
10 * source distribution.
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
28 #include "internal.h"
30 #include "dbus-maybe.h"
31 #include "debug.h"
32 #include "imgstore.h"
33 #include "util.h"
35 static GHashTable *imgstore;
36 static unsigned int nextid = 0;
39 * NOTE: purple_imgstore_add() creates these without zeroing the memory, so
40 * NOTE: make sure to update that function when adding members.
42 struct _PurpleStoredImage
44 int id;
45 guint8 refcount;
46 size_t size; /**< The image data's size. */
47 char *filename; /**< The filename (for the UI) */
48 gpointer data; /**< The image data. */
51 PurpleStoredImage *
52 purple_imgstore_add(gpointer data, size_t size, const char *filename)
54 PurpleStoredImage *img;
56 g_return_val_if_fail(data != NULL, NULL);
57 g_return_val_if_fail(size > 0, NULL);
59 img = g_new(PurpleStoredImage, 1);
60 PURPLE_DBUS_REGISTER_POINTER(img, PurpleStoredImage);
61 img->data = data;
62 img->size = size;
63 img->filename = g_strdup(filename);
64 img->refcount = 1;
65 img->id = 0;
67 return img;
70 PurpleStoredImage *
71 purple_imgstore_new_from_file(const char *path)
73 gchar *data = NULL;
74 size_t len;
75 GError *err = NULL;
77 g_return_val_if_fail(path != NULL && *path != '\0', NULL);
79 if (!g_file_get_contents(path, &data, &len, &err)) {
80 purple_debug_error("imgstore", "Error reading %s: %s\n",
81 path, err->message);
82 g_error_free(err);
83 return NULL;
85 return purple_imgstore_add(data, len, path);
88 int
89 purple_imgstore_add_with_id(gpointer data, size_t size, const char *filename)
91 PurpleStoredImage *img = purple_imgstore_add(data, size, filename);
92 if (img) {
94 * Use the next unused id number. We do it in a loop on the
95 * off chance that nextid wraps back around to 0 and the hash
96 * table still contains entries from the first time around.
98 do {
99 img->id = ++nextid;
100 } while (img->id == 0 || g_hash_table_lookup(imgstore, &(img->id)) != NULL);
102 g_hash_table_insert(imgstore, &(img->id), img);
105 return (img ? img->id : 0);
108 PurpleStoredImage *purple_imgstore_find_by_id(int id) {
109 PurpleStoredImage *img = g_hash_table_lookup(imgstore, &id);
111 if (img != NULL)
112 purple_debug_misc("imgstore", "retrieved image id %d\n", img->id);
114 return img;
117 gconstpointer purple_imgstore_get_data(PurpleStoredImage *img) {
118 g_return_val_if_fail(img != NULL, NULL);
120 return img->data;
123 size_t purple_imgstore_get_size(PurpleStoredImage *img)
125 g_return_val_if_fail(img != NULL, 0);
127 return img->size;
130 const char *purple_imgstore_get_filename(const PurpleStoredImage *img)
132 g_return_val_if_fail(img != NULL, NULL);
134 return img->filename;
137 const char *purple_imgstore_get_extension(PurpleStoredImage *img)
139 g_return_val_if_fail(img != NULL, NULL);
141 return purple_util_get_image_extension(img->data, img->size);
144 void purple_imgstore_ref_by_id(int id)
146 PurpleStoredImage *img = purple_imgstore_find_by_id(id);
148 g_return_if_fail(img != NULL);
150 purple_imgstore_ref(img);
153 void purple_imgstore_unref_by_id(int id)
155 PurpleStoredImage *img = purple_imgstore_find_by_id(id);
157 g_return_if_fail(img != NULL);
159 purple_imgstore_unref(img);
162 PurpleStoredImage *
163 purple_imgstore_ref(PurpleStoredImage *img)
165 g_return_val_if_fail(img != NULL, NULL);
167 img->refcount++;
169 return img;
172 PurpleStoredImage *
173 purple_imgstore_unref(PurpleStoredImage *img)
175 if (img == NULL)
176 return NULL;
178 g_return_val_if_fail(img->refcount > 0, NULL);
180 img->refcount--;
182 if (img->refcount == 0)
184 purple_signal_emit(purple_imgstore_get_handle(),
185 "image-deleting", img);
186 if (img->id)
187 g_hash_table_remove(imgstore, &img->id);
189 g_free(img->data);
190 g_free(img->filename);
191 PURPLE_DBUS_UNREGISTER_POINTER(img);
192 g_free(img);
193 img = NULL;
196 return img;
199 void *
200 purple_imgstore_get_handle()
202 static int handle;
204 return &handle;
207 void
208 purple_imgstore_init()
210 void *handle = purple_imgstore_get_handle();
212 purple_signal_register(handle, "image-deleting",
213 purple_marshal_VOID__POINTER, NULL,
215 purple_value_new(PURPLE_TYPE_SUBTYPE,
216 PURPLE_SUBTYPE_STORED_IMAGE));
218 imgstore = g_hash_table_new(g_int_hash, g_int_equal);
221 void
222 purple_imgstore_uninit()
224 g_hash_table_destroy(imgstore);
226 purple_signals_unregister_by_instance(purple_imgstore_get_handle());