1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * gsf-clip-data.c: clipboard data
5 * Copyright (C) 2006 Novell Inc
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of version 2.1 of the GNU Lesser General Public
9 * License as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
22 #include "gsf-config.h"
23 #include <glib/gi18n-lib.h>
24 #include "gsf-clip-data.h"
25 #include "gsf-utils.h"
26 #include "gsf-impl-utils.h"
28 /* Private part of the GsfClipData structure */
29 struct _GsfClipDataPrivate {
34 static GObjectClass *gsf_clip_data_parent_class;
36 gsf_clip_data_finalize (GObject *object)
38 GsfClipData *clip_data;
39 GsfClipDataPrivate *priv;
41 clip_data = GSF_CLIP_DATA (object);
42 priv = clip_data->priv;
45 g_object_unref (priv->data_blob);
49 gsf_clip_data_parent_class->finalize (object);
53 gsf_clip_data_init (GsfClipData *clip_data)
55 GsfClipDataPrivate *priv;
57 priv = g_new0 (GsfClipDataPrivate, 1);
58 clip_data->priv = priv;
61 gsf_clip_data_class_init (GObjectClass *gobject_class)
63 gobject_class->finalize = gsf_clip_data_finalize;
65 gsf_clip_data_parent_class = g_type_class_peek_parent (gobject_class);
69 GSF_CLASS (GsfClipData, gsf_clip_data,
70 gsf_clip_data_class_init, gsf_clip_data_init,
75 * @format: Format for the data inside the @data_blob
76 * @data_blob: Object which holds the binary contents for the #GsfClipData
78 * Creates a new #GsfClipData object. This function acquires a reference to the
79 * @data_blob, so you should unref the blob on your own if you no longer need it
82 * Return value: A newly-created #GsfClipData.
85 gsf_clip_data_new (GsfClipFormat format, GsfBlob *data_blob)
87 GsfClipData *clip_data;
88 GsfClipDataPrivate *priv;
90 g_return_val_if_fail (GSF_IS_BLOB (data_blob), NULL);
92 clip_data = g_object_new (GSF_TYPE_CLIP_DATA, NULL);
93 if (G_UNLIKELY (NULL == clip_data)) return NULL;
95 priv = clip_data->priv;
97 priv->format = format;
98 priv->data_blob = g_object_ref (data_blob);
104 * gsf_clip_data_get_format:
105 * @clip_data: A #GsfClipData.
107 * Queries the clipboard data format of a #GsfClipData. The format refers to the data
108 * blob inside the @clip_data; use gsf_clip_data_get_data_blob() to get that data blob.
110 * Return value: The format in which the #GsfClipData's data blob is stored.
113 gsf_clip_data_get_format (GsfClipData *clip_data)
115 GsfClipDataPrivate *priv;
117 g_return_val_if_fail (GSF_IS_CLIP_DATA (clip_data), GSF_CLIP_FORMAT_UNKNOWN);
119 priv = clip_data->priv;
124 * gsf_clip_data_get_data_blob:
125 * @clip_data: A #GsfClipData.
127 * Queries the data blob that actually stores a #GsfClipData's binary data.
129 * Return value: A new reference to the #GsfBlob that stores this @clip_data's
130 * binary data. You must use g_object_unref() to dispose of that data blob when
131 * you are done with it.
134 gsf_clip_data_get_data_blob (GsfClipData *clip_data)
136 GsfClipDataPrivate *priv;
138 g_return_val_if_fail (GSF_IS_CLIP_DATA (clip_data), NULL);
140 priv = clip_data->priv;
141 return g_object_ref (priv->data_blob);
145 set_error_missing_clipboard_data (GError **error, const char *format_name, gsize at_least_size)
149 size_str = g_strdup_printf ("%" G_GSIZE_FORMAT, at_least_size);
152 GSF_ERROR_INVALID_DATA,
153 _("The clip_data is in %s, but it is smaller than "
154 "at least %s bytes"),
161 get_windows_clipboard_data_offset (GsfClipFormatWindows format)
163 struct format_offset_pair {
164 GsfClipFormatWindows format;
168 static const struct format_offset_pair pairs[] = {
169 { GSF_CLIP_FORMAT_WINDOWS_UNKNOWN, 4 },
170 { GSF_CLIP_FORMAT_WINDOWS_METAFILE, 12 },
171 { GSF_CLIP_FORMAT_WINDOWS_DIB, 4 },
172 { GSF_CLIP_FORMAT_WINDOWS_ENHANCED_METAFILE, 4 } /* FIXME: does this have a PACKEDMETA in front
173 * as well, similar to GSF_CLIP_FORMAT_WINDOWS_METAFILE? */
175 static const int num_pairs = G_N_ELEMENTS (pairs);
179 for (i = 0; i < num_pairs; i++)
180 if (pairs[i].format == format)
181 return pairs[i].offset;
183 g_assert_not_reached ();
188 * check_format_windows:
189 * @format : #GsfClipFormatWindows
190 * @format_name : const char *
191 * @blob_size : #gsize
194 * Checks that the specified blob size matches the expected size for the format.
196 * Returns: the same format if the size is correct, or
197 * GSF_CLIP_FORMAT_WINDOWS_ERROR if the size is too small.
199 static GsfClipFormatWindows
200 check_format_windows (GsfClipFormatWindows format, const char *format_name, gsize blob_size, GError **error)
204 offset = get_windows_clipboard_data_offset (format);
205 if (blob_size <= offset) {
206 set_error_missing_clipboard_data (error, format_name, offset + 1);
207 format = GSF_CLIP_FORMAT_WINDOWS_ERROR;
214 * gsf_clip_data_get_windows_clipboard_format:
215 * @clip_data: A #GsfClipData.
216 * @error: Location to store error, or %NULL
218 * Queries the Windows clipboard data format for a #GsfClipData. The @clip_data must
219 * have been created with #GSF_CLIP_FORMAT_WINDOWS_CLIPBOARD.
221 * Returns: A #GsfClipFormatWindows value.
223 * Possible errors: #GSF_ERROR_INVALID_DATA if the data blob in the @clip_data is
224 * smaller than it should be; in this case GSF_CLIP_FORMAT_WINDOWS_ERROR will be returned.
227 gsf_clip_data_get_windows_clipboard_format (GsfClipData *clip_data, GError **error)
229 GsfClipDataPrivate *priv;
233 GsfClipFormatWindows format;
235 g_return_val_if_fail (GSF_IS_CLIP_DATA (clip_data), GSF_CLIP_FORMAT_WINDOWS_ERROR);
236 g_return_val_if_fail (error == NULL || *error == NULL, GSF_CLIP_FORMAT_WINDOWS_ERROR);
238 priv = clip_data->priv;
239 g_return_val_if_fail (priv->format == GSF_CLIP_FORMAT_WINDOWS_CLIPBOARD, GSF_CLIP_FORMAT_WINDOWS_ERROR);
241 size = gsf_blob_get_size (priv->data_blob);
246 GSF_ERROR_INVALID_DATA,
247 _("The clip_data is in Windows clipboard format, but it is smaller than "
248 "the required 4 bytes."));
249 return GSF_CLIP_FORMAT_WINDOWS_ERROR;
252 data = gsf_blob_peek_data (priv->data_blob);
254 value = GSF_LE_GET_GUINT32 (data);
257 case GSF_CLIP_FORMAT_WINDOWS_METAFILE:
258 format = check_format_windows (GSF_CLIP_FORMAT_WINDOWS_METAFILE, _("Windows Metafile format"),
262 case GSF_CLIP_FORMAT_WINDOWS_DIB:
263 case 2: /* CF_BITMAP */
264 format = check_format_windows (GSF_CLIP_FORMAT_WINDOWS_DIB, _("Windows DIB or BITMAP format"),
268 case GSF_CLIP_FORMAT_WINDOWS_ENHANCED_METAFILE:
269 format = check_format_windows (GSF_CLIP_FORMAT_WINDOWS_ENHANCED_METAFILE, _("Windows Enhanced Metafile format"),
274 format = GSF_CLIP_FORMAT_WINDOWS_UNKNOWN;
282 * gsf_clip_data_peek_real_data:
283 * @clip_data: A #GsfClipData.
284 * @ret_size: Location to return the size of the returned data buffer.
285 * @error: Location to store error, or %NULL.
287 * Queries a pointer directly to the clipboard data of a #GsfClipData. The
288 * resulting pointer is not necessarily the same data pointer that was passed to
289 * gsf_blob_new() prior to creating the @clip_data. For example, if the data is
290 * in #GSF_CLIP_FORMAT_WINDOWS_CLIPBOARD format, then it will have extra header
291 * bytes in front of the actual metafile data. This function will skip over
292 * those header bytes if necessary and return a pointer to the "real" data.
294 * Return value: Pointer to the real clipboard data. The size in bytes of this
295 * buffer is returned in the @ret_size argument.
298 gsf_clip_data_peek_real_data (GsfClipData *clip_data, gsize *ret_size, GError **error)
300 GsfClipDataPrivate *priv;
304 g_return_val_if_fail (GSF_IS_CLIP_DATA (clip_data), NULL);
305 g_return_val_if_fail (ret_size != NULL, NULL);
306 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
308 priv = clip_data->priv;
310 data = gsf_blob_peek_data (priv->data_blob);
312 if (priv->format == GSF_CLIP_FORMAT_WINDOWS_CLIPBOARD) {
313 GsfClipFormatWindows win_format;
315 win_format = gsf_clip_data_get_windows_clipboard_format (clip_data, error);
316 if (win_format == GSF_CLIP_FORMAT_WINDOWS_ERROR)
319 /* gsf_clip_data_get_windows_clipboard_format() already did the size checks for us,
320 * so we can jump to the offset right away without doing extra checks.
323 offset = get_windows_clipboard_data_offset (win_format);
327 *ret_size = gsf_blob_get_size (priv->data_blob) - offset;
328 return (char *) data + offset; /* cast to avoid warning about void pointer arithmetic */