Coverage Report

Created: 2026-07-25 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pidgin/libpurple/imgstore.c
Line
Count
Source
1
/**
2
 * @file imgstore.c IM Image Store API
3
 * @ingroup core
4
 */
5
6
/* purple
7
 *
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.
11
 *
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.
16
 *
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.
21
 *
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
25
 *
26
*/
27
28
#include "internal.h"
29
30
#include "dbus-maybe.h"
31
#include "debug.h"
32
#include "imgstore.h"
33
#include "util.h"
34
35
static GHashTable *imgstore;
36
static unsigned int nextid = 0;
37
38
/*
39
 * NOTE: purple_imgstore_add() creates these without zeroing the memory, so
40
 * NOTE: make sure to update that function when adding members.
41
 */
42
struct _PurpleStoredImage
43
{
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. */
49
};
50
51
PurpleStoredImage *
52
purple_imgstore_add(gpointer data, size_t size, const char *filename)
53
0
{
54
0
  PurpleStoredImage *img;
55
56
0
  g_return_val_if_fail(data != NULL, NULL);
57
0
  g_return_val_if_fail(size > 0, NULL);
58
59
0
  img = g_new(PurpleStoredImage, 1);
60
0
  PURPLE_DBUS_REGISTER_POINTER(img, PurpleStoredImage);
61
0
  img->data = data;
62
0
  img->size = size;
63
0
  img->filename = g_strdup(filename);
64
0
  img->refcount = 1;
65
0
  img->id = 0;
66
67
0
  return img;
68
0
}
69
70
PurpleStoredImage *
71
purple_imgstore_new_from_file(const char *path)
72
0
{
73
0
  gchar *data = NULL;
74
0
  size_t len;
75
0
  GError *err = NULL;
76
77
0
  g_return_val_if_fail(path != NULL && *path != '\0', NULL);
78
79
0
  if (!g_file_get_contents(path, &data, &len, &err)) {
80
0
    purple_debug_error("imgstore", "Error reading %s: %s\n",
81
0
        path, err->message);
82
0
    g_error_free(err);
83
0
    return NULL;
84
0
  }
85
0
  return purple_imgstore_add(data, len, path);
86
0
}
87
88
int
89
purple_imgstore_add_with_id(gpointer data, size_t size, const char *filename)
90
0
{
91
0
  PurpleStoredImage *img = purple_imgstore_add(data, size, filename);
92
0
  if (!img) {
93
0
    return 0;
94
0
  }
95
96
  /*
97
   * Use the next unused id number.  We do it in a loop on the
98
   * off chance that nextid wraps back around to 0 and the hash
99
   * table still contains entries from the first time around.
100
   */
101
0
  do {
102
0
    img->id = ++nextid;
103
0
  } while (img->id == 0 || g_hash_table_lookup(imgstore, &(img->id)) != NULL);
104
105
0
  g_hash_table_insert(imgstore, &(img->id), img);
106
107
0
  return img->id;
108
0
}
109
110
PurpleStoredImage *purple_imgstore_find_by_id(int id)
111
0
{
112
0
  PurpleStoredImage *img = g_hash_table_lookup(imgstore, &id);
113
114
0
  if (img != NULL)
115
0
    purple_debug_misc("imgstore", "retrieved image id %d\n", img->id);
116
117
0
  return img;
118
0
}
119
120
gconstpointer purple_imgstore_get_data(PurpleStoredImage *img)
121
0
{
122
0
  g_return_val_if_fail(img != NULL, NULL);
123
124
0
  return img->data;
125
0
}
126
127
size_t purple_imgstore_get_size(PurpleStoredImage *img)
128
0
{
129
0
  g_return_val_if_fail(img != NULL, 0);
130
131
0
  return img->size;
132
0
}
133
134
const char *purple_imgstore_get_filename(const PurpleStoredImage *img)
135
0
{
136
0
  g_return_val_if_fail(img != NULL, NULL);
137
138
0
  return img->filename;
139
0
}
140
141
const char *purple_imgstore_get_extension(PurpleStoredImage *img)
142
0
{
143
0
  g_return_val_if_fail(img != NULL, NULL);
144
145
0
  return purple_util_get_image_extension(img->data, img->size);
146
0
}
147
148
void purple_imgstore_ref_by_id(int id)
149
0
{
150
0
  PurpleStoredImage *img = purple_imgstore_find_by_id(id);
151
152
0
  g_return_if_fail(img != NULL);
153
154
0
  purple_imgstore_ref(img);
155
0
}
156
157
void purple_imgstore_unref_by_id(int id)
158
0
{
159
0
  PurpleStoredImage *img = purple_imgstore_find_by_id(id);
160
161
0
  g_return_if_fail(img != NULL);
162
163
0
  purple_imgstore_unref(img);
164
0
}
165
166
PurpleStoredImage *
167
purple_imgstore_ref(PurpleStoredImage *img)
168
0
{
169
0
  g_return_val_if_fail(img != NULL, NULL);
170
171
0
  img->refcount++;
172
173
0
  return img;
174
0
}
175
176
PurpleStoredImage *
177
purple_imgstore_unref(PurpleStoredImage *img)
178
0
{
179
0
  if (img == NULL)
180
0
    return NULL;
181
182
0
  g_return_val_if_fail(img->refcount > 0, NULL);
183
184
0
  img->refcount--;
185
186
0
  if (img->refcount == 0)
187
0
  {
188
0
    purple_signal_emit(purple_imgstore_get_handle(),
189
0
                       "image-deleting", img);
190
0
    if (img->id)
191
0
      g_hash_table_remove(imgstore, &img->id);
192
193
0
    g_free(img->data);
194
0
    g_free(img->filename);
195
0
    PURPLE_DBUS_UNREGISTER_POINTER(img);
196
0
    g_free(img);
197
0
    img = NULL;
198
0
  }
199
200
0
  return img;
201
0
}
202
203
void *
204
purple_imgstore_get_handle()
205
0
{
206
0
  static int handle;
207
208
0
  return &handle;
209
0
}
210
211
void
212
purple_imgstore_init()
213
0
{
214
0
  void *handle = purple_imgstore_get_handle();
215
216
0
  purple_signal_register(handle, "image-deleting",
217
0
                         purple_marshal_VOID__POINTER, NULL,
218
0
                         1,
219
0
                         purple_value_new(PURPLE_TYPE_SUBTYPE,
220
0
                                          PURPLE_SUBTYPE_STORED_IMAGE));
221
222
0
  imgstore = g_hash_table_new(g_int_hash, g_int_equal);
223
0
}
224
225
void
226
purple_imgstore_uninit()
227
0
{
228
0
  g_hash_table_destroy(imgstore);
229
230
0
  purple_signals_unregister_by_instance(purple_imgstore_get_handle());
231
0
}