/* * camel-filter-input-stream.c * * This library is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . * */ /** * SECTION: camel-filter-input-stream * @short_description: Filtered input stream * @include: camel/camel.h * @see_also: #GInputStream, #CamelMimeFilter * * #CamelFilterInputStream is similar to #GConverterInputStream, except it * operates on a #CamelMimeFilter instead of a #GConverter. * * This class is meant to be a temporary solution until all of Camel's MIME * filters are ported to the #GConverter interface. **/ #include "camel-filter-input-stream.h" #include #define CAMEL_FILTER_INPUT_STREAM_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE \ ((obj), CAMEL_TYPE_FILTER_INPUT_STREAM, CamelFilterInputStreamPrivate)) #define READ_PAD (128) /* bytes padded before buffer */ #define READ_SIZE (4096) struct _CamelFilterInputStreamPrivate { CamelMimeFilter *filter; gchar real_buffer[READ_SIZE + READ_PAD]; gchar *buffer; /* points to real_buffer + READ_PAD */ gchar *filtered; gsize filtered_length; }; enum { PROP_0, PROP_FILTER }; G_DEFINE_TYPE ( CamelFilterInputStream, camel_filter_input_stream, G_TYPE_FILTER_INPUT_STREAM) static void filter_input_stream_set_filter (CamelFilterInputStream *filter_stream, CamelMimeFilter *filter) { g_return_if_fail (CAMEL_IS_MIME_FILTER (filter)); g_return_if_fail (filter_stream->priv->filter == NULL); filter_stream->priv->filter = g_object_ref (filter); } static void filter_input_stream_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { switch (property_id) { case PROP_FILTER: filter_input_stream_set_filter ( CAMEL_FILTER_INPUT_STREAM (object), g_value_get_object (value)); return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } static void filter_input_stream_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { switch (property_id) { case PROP_FILTER: g_value_set_object ( value, camel_filter_input_stream_get_filter ( CAMEL_FILTER_INPUT_STREAM (object))); return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } static void filter_input_stream_dispose (GObject *object) { CamelFilterInputStreamPrivate *priv; priv = CAMEL_FILTER_INPUT_STREAM_GET_PRIVATE (object); g_clear_object (&priv->filter); /* Chain up to parent's dispose() method. */ G_OBJECT_CLASS (camel_filter_input_stream_parent_class)-> dispose (object); } static gssize filter_input_stream_read (GInputStream *stream, gpointer buffer, gsize count, GCancellable *cancellable, GError **error) { CamelFilterInputStreamPrivate *priv; CamelMimeFilter *filter; GInputStream *base_stream; gssize n_bytes_read; gsize presize = READ_PAD; priv = CAMEL_FILTER_INPUT_STREAM_GET_PRIVATE (stream); filter = camel_filter_input_stream_get_filter ( CAMEL_FILTER_INPUT_STREAM (stream)); base_stream = g_filter_input_stream_get_base_stream ( G_FILTER_INPUT_STREAM (stream)); /* If we already have some filtered data, return it. */ if (priv->filtered_length > 0) goto exit; n_bytes_read = g_input_stream_read ( base_stream, priv->buffer, READ_SIZE, cancellable, error); if (n_bytes_read == 0) { camel_mime_filter_complete ( filter, priv->filtered, priv->filtered_length, presize, &priv->filtered, &priv->filtered_length, &presize); n_bytes_read = priv->filtered_length; if (n_bytes_read > 0) goto exit; } if (n_bytes_read <= 0) return n_bytes_read; priv->filtered = priv->buffer; priv->filtered_length = n_bytes_read; camel_mime_filter_filter ( filter, priv->filtered, priv->filtered_length, presize, &priv->filtered, &priv->filtered_length, &presize); exit: n_bytes_read = MIN (count, priv->filtered_length); memcpy (buffer, priv->filtered, n_bytes_read); priv->filtered_length -= n_bytes_read; priv->filtered += n_bytes_read; return n_bytes_read; } static void camel_filter_input_stream_class_init (CamelFilterInputStreamClass *class) { GObjectClass *object_class; GInputStreamClass *stream_class; g_type_class_add_private ( class, sizeof (CamelFilterInputStreamPrivate)); object_class = G_OBJECT_CLASS (class); object_class->set_property = filter_input_stream_set_property; object_class->get_property = filter_input_stream_get_property; object_class->dispose = filter_input_stream_dispose; stream_class = G_INPUT_STREAM_CLASS (class); stream_class->read_fn = filter_input_stream_read; g_object_class_install_property ( object_class, PROP_FILTER, g_param_spec_object ( "filter", "Filter", "The MIME filter object", CAMEL_TYPE_MIME_FILTER, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); } static void camel_filter_input_stream_init (CamelFilterInputStream *filter_stream) { filter_stream->priv = CAMEL_FILTER_INPUT_STREAM_GET_PRIVATE (filter_stream); filter_stream->priv->buffer = filter_stream->priv->real_buffer + READ_PAD; } /** * camel_filter_input_stream_new: * @base_stream: a #GInputStream * @filter: a #CamelMimeFilter * * Creates a new filtered input stream for the @base_stream. * * Returns: a new #GInputStream * * Since: 3.12 **/ GInputStream * camel_filter_input_stream_new (GInputStream *base_stream, CamelMimeFilter *filter) { g_return_val_if_fail (G_IS_INPUT_STREAM (base_stream), NULL); g_return_val_if_fail (CAMEL_IS_MIME_FILTER (filter), NULL); return g_object_new ( CAMEL_TYPE_FILTER_INPUT_STREAM, "base-stream", base_stream, "filter", filter, NULL); } /** * camel_filter_input_stream_get_filter: * @filter_stream: a #CamelFilterInputStream * * Gets the #CamelMimeFilter that is used by @filter_stream. * * Returns: a #CamelMimeFilter * * Since: 3.12 **/ CamelMimeFilter * camel_filter_input_stream_get_filter (CamelFilterInputStream *filter_stream) { g_return_val_if_fail ( CAMEL_IS_FILTER_INPUT_STREAM (filter_stream), NULL); return filter_stream->priv->filter; }