4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, see <http://www.gnu.org/licenses/>.
19 * SECTION: e-data-capture
20 * @include: e-util/e-util.h
21 * @short_description: Capture data from streams
23 * #EDataCapture is a #GConverter that captures data until the end of
24 * the input data is seen, then emits a #EDataCapture:finished signal
25 * with the captured data in a #GBytes instance.
27 * When used with #GConverterInputStream or #GConverterOutputStream,
28 * an #EDataCapture can discreetly capture the stream content for the
32 #include "e-data-capture.h"
36 #define E_DATA_CAPTURE_GET_PRIVATE(obj) \
37 (G_TYPE_INSTANCE_GET_PRIVATE \
38 ((obj), E_TYPE_DATA_CAPTURE, EDataCapturePrivate))
40 typedef struct _SignalClosure SignalClosure
;
42 struct _EDataCapturePrivate
{
43 GMainContext
*main_context
;
44 GByteArray
*byte_array
;
45 GMutex byte_array_lock
;
48 struct _SignalClosure
{
49 GWeakRef data_capture
;
63 static guint signals
[LAST_SIGNAL
];
65 /* Forward Declarations */
66 static void e_data_capture_converter_init (GConverterIface
*iface
);
68 G_DEFINE_TYPE_WITH_CODE (
72 G_IMPLEMENT_INTERFACE (
74 e_data_capture_converter_init
))
77 signal_closure_free (SignalClosure
*signal_closure
)
79 g_weak_ref_set (&signal_closure
->data_capture
, NULL
);
80 g_bytes_unref (signal_closure
->data
);
82 g_slice_free (SignalClosure
, signal_closure
);
86 data_capture_emit_finished_idle_cb (gpointer user_data
)
88 SignalClosure
*signal_closure
= user_data
;
89 EDataCapture
*data_capture
;
91 data_capture
= g_weak_ref_get (&signal_closure
->data_capture
);
93 if (data_capture
!= NULL
) {
97 signal_closure
->data
);
98 g_object_unref (data_capture
);
105 data_capture_set_main_context (EDataCapture
*data_capture
,
106 GMainContext
*main_context
)
108 g_return_if_fail (data_capture
->priv
->main_context
== NULL
);
110 if (main_context
!= NULL
)
111 g_main_context_ref (main_context
);
113 main_context
= g_main_context_ref_thread_default ();
115 data_capture
->priv
->main_context
= main_context
;
119 data_capture_set_property (GObject
*object
,
124 switch (property_id
) {
125 case PROP_MAIN_CONTEXT
:
126 data_capture_set_main_context (
127 E_DATA_CAPTURE (object
),
128 g_value_get_boxed (value
));
132 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
136 data_capture_get_property (GObject
*object
,
141 switch (property_id
) {
142 case PROP_MAIN_CONTEXT
:
145 e_data_capture_ref_main_context (
146 E_DATA_CAPTURE (object
)));
150 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
154 data_capture_finalize (GObject
*object
)
156 EDataCapturePrivate
*priv
;
158 priv
= E_DATA_CAPTURE_GET_PRIVATE (object
);
160 g_main_context_unref (priv
->main_context
);
162 g_byte_array_free (priv
->byte_array
, TRUE
);
163 g_mutex_clear (&priv
->byte_array_lock
);
165 /* Chain up to parent's finalize() method. */
166 G_OBJECT_CLASS (e_data_capture_parent_class
)->finalize (object
);
169 static GConverterResult
170 data_capture_convert (GConverter
*converter
,
175 GConverterFlags flags
,
177 gsize
*bytes_written
,
180 EDataCapture
*data_capture
;
181 GConverterResult result
;
183 data_capture
= E_DATA_CAPTURE (converter
);
185 /* Output buffer needs to be at least as large as the input buffer.
186 * The error message should never make it to the user interface so
187 * no need to translate. */
188 if (outbuf_size
< inbuf_size
) {
189 g_set_error_literal (
192 "EDataCapture needs more space");
193 return G_CONVERTER_ERROR
;
196 memcpy (outbuf
, inbuf
, inbuf_size
);
197 *bytes_read
= *bytes_written
= inbuf_size
;
199 g_mutex_lock (&data_capture
->priv
->byte_array_lock
);
201 g_byte_array_append (
202 data_capture
->priv
->byte_array
, inbuf
, inbuf_size
);
204 if ((flags
& G_CONVERTER_INPUT_AT_END
) != 0) {
205 GSource
*idle_source
;
206 GMainContext
*main_context
;
207 SignalClosure
*signal_closure
;
209 signal_closure
= g_slice_new0 (SignalClosure
);
210 g_weak_ref_set (&signal_closure
->data_capture
, data_capture
);
211 signal_closure
->data
= g_bytes_new (
212 data_capture
->priv
->byte_array
->data
,
213 data_capture
->priv
->byte_array
->len
);
215 main_context
= e_data_capture_ref_main_context (data_capture
);
217 idle_source
= g_idle_source_new ();
218 g_source_set_callback (
220 data_capture_emit_finished_idle_cb
,
222 (GDestroyNotify
) signal_closure_free
);
223 g_source_set_priority (idle_source
, G_PRIORITY_HIGH_IDLE
);
224 g_source_attach (idle_source
, main_context
);
225 g_source_unref (idle_source
);
227 g_main_context_unref (main_context
);
230 g_mutex_unlock (&data_capture
->priv
->byte_array_lock
);
232 if ((flags
& G_CONVERTER_INPUT_AT_END
) != 0)
233 result
= G_CONVERTER_FINISHED
;
234 else if ((flags
& G_CONVERTER_FLUSH
) != 0)
235 result
= G_CONVERTER_FLUSHED
;
237 result
= G_CONVERTER_CONVERTED
;
243 data_capture_reset (GConverter
*converter
)
245 EDataCapture
*data_capture
;
247 data_capture
= E_DATA_CAPTURE (converter
);
249 g_mutex_lock (&data_capture
->priv
->byte_array_lock
);
251 g_byte_array_set_size (data_capture
->priv
->byte_array
, 0);
253 g_mutex_unlock (&data_capture
->priv
->byte_array_lock
);
257 e_data_capture_class_init (EDataCaptureClass
*class)
259 GObjectClass
*object_class
;
261 g_type_class_add_private (class, sizeof (EDataCapturePrivate
));
263 object_class
= G_OBJECT_CLASS (class);
264 object_class
->set_property
= data_capture_set_property
;
265 object_class
->get_property
= data_capture_get_property
;
266 object_class
->finalize
= data_capture_finalize
;
269 * EDataCapture:main-context:
271 * The #GMainContext from which to emit the #EDataCapture::finished
274 g_object_class_install_property (
280 "The main loop context from "
281 "which to emit the 'finished' signal",
284 G_PARAM_CONSTRUCT_ONLY
|
285 G_PARAM_STATIC_STRINGS
));
288 * EDataCapture::finished:
289 * @data_capture: the #EDataCapture that received the signal
290 * @data: the captured data
292 * The ::finished signal is emitted when there is no more input
293 * data to be captured.
295 signals
[FINISHED
] = g_signal_new (
297 G_TYPE_FROM_CLASS (class),
299 G_STRUCT_OFFSET (EDataCaptureClass
, finished
),
306 e_data_capture_converter_init (GConverterIface
*iface
)
308 iface
->convert
= data_capture_convert
;
309 iface
->reset
= data_capture_reset
;
313 e_data_capture_init (EDataCapture
*data_capture
)
315 data_capture
->priv
= E_DATA_CAPTURE_GET_PRIVATE (data_capture
);
317 data_capture
->priv
->byte_array
= g_byte_array_new ();
318 g_mutex_init (&data_capture
->priv
->byte_array_lock
);
322 * e_data_capture_new:
323 * @main_context: a #GMainContext, or %NULL
325 * Creates a new #EDataCapture. If @main_context is %NULL, then the
326 * #EDataCapture:finished signal will be emitted from the thread-default
327 * #GMainContext for this thread.
329 * Returns: an #EDataCapture
332 e_data_capture_new (GMainContext
*main_context
)
334 return g_object_new (
336 "main-context", main_context
, NULL
);
340 * e_data_capture_ref_main_context:
341 * @data_capture: an #EDataCapture
343 * Returns the #GMainContext from which the #EDataCapture:finished signal
346 * The returned #GMainContext is referenced for thread-safety and must be
347 * unreferenced with g_main_context_unref() when finished with it.
349 * Returns: a #GMainContext
352 e_data_capture_ref_main_context (EDataCapture
*data_capture
)
354 g_return_val_if_fail (E_IS_DATA_CAPTURE (data_capture
), NULL
);
356 return g_main_context_ref (data_capture
->priv
->main_context
);