4 * An glib SMIL library.
6 * Authored By Koos Vriezen <koos.vriezen@gmail.com>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
26 * @short_description: A simple io abstraction.
36 #include <glib/gprintf.h>
38 #define LAUGH_IO_GET_PRIVATE(obj) \
39 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), LAUGH_TYPE_IO, LaughIOPrivate))
49 static guint laugh_io_signals
[LAST_SIGNAL
] = { 0 };
51 struct _LaughIOPrivate
{
56 GCancellable
*cancellable
;
57 unsigned char *buffer
;
62 static gpointer laugh_io_parent_class
= ((void *)0);
64 static void _laugh_io_clear_gio (LaughIOPrivate
*priv
, gboolean cancel
) {
65 if (priv
->cancellable
) {
67 g_cancellable_cancel (priv
->cancellable
);
68 g_free (priv
->buffer
);
71 g_object_unref (G_OBJECT (priv
->cancellable
));
72 priv
->cancellable
= NULL
;
74 g_object_unref (G_OBJECT (priv
->fin
));
78 g_object_unref (G_OBJECT (priv
->file
));
84 static void laugh_io_finalize (GObject
*object
) {
85 G_OBJECT_CLASS (laugh_io_parent_class
)->finalize (object
);
88 static void laugh_io_dispose (GObject
*object
) {
89 LaughIO
*laughio
= LAUGH_IO(object
);
91 _laugh_io_clear_gio (laughio
->priv
, TRUE
);
92 if (laughio
->priv
->uri
)
93 g_free (laughio
->priv
->uri
);
94 if (laughio
->priv
->mime
)
95 g_free (laughio
->priv
->mime
);
97 G_OBJECT_CLASS (laugh_io_parent_class
)->dispose (object
);
100 static void laugh_io_class_init (LaughIOClass
*klass
) {
101 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
103 laugh_io_parent_class
= g_type_class_peek_parent (klass
);
105 gobject_class
->finalize
= laugh_io_finalize
;
106 gobject_class
->dispose
= laugh_io_dispose
;
108 g_type_class_add_private (gobject_class
, sizeof (LaughIOPrivate
));
110 laugh_io_signals
[MIME
] =
111 g_signal_new ("mime-type",
112 G_TYPE_FROM_CLASS (gobject_class
),
114 G_STRUCT_OFFSET (LaughIOClass
, mime_type
),
116 g_cclosure_marshal_VOID__STRING
,
120 laugh_io_signals
[COMPLETED
] =
121 g_signal_new ("completed",
122 G_TYPE_FROM_CLASS (gobject_class
),
124 G_STRUCT_OFFSET (LaughIOClass
, completed
),
126 g_cclosure_marshal_VOID__UINT_POINTER
,
128 G_TYPE_UINT
, G_TYPE_POINTER
);
131 static void laugh_io_instance_init (GTypeInstance
*instance
, gpointer g_class
)
133 LaughIO
*self
= (LaughIO
*)instance
;
135 self
->priv
= LAUGH_IO_GET_PRIVATE (self
);
137 self
->priv
->uri
= NULL
;
138 self
->priv
->mime
= NULL
;
141 GType
laugh_io_get_type (void)
143 static GType type
= 0;
145 static const GTypeInfo info
= {
146 sizeof (LaughIOClass
),
147 NULL
, /* base_init */
148 NULL
, /* base_finalize */
149 (GClassInitFunc
) laugh_io_class_init
, /* class_init */
150 NULL
, /* class_finalize */
151 NULL
, /* class_data */
154 laugh_io_instance_init
/* instance_init */
156 type
= g_type_register_static (G_TYPE_OBJECT
,
163 LaughIO
*laugh_io_new (const gchar
*uri
)
170 laughio
= LAUGH_IO (g_object_new (LAUGH_TYPE_IO
, NULL
));
171 if (uri
[0] == '/' || !g_strstr_len (uri
, 15, ":/")) {
172 GFile
*file
= g_file_new_for_path (uri
);
173 laughio
->priv
->uri
= g_file_get_uri (file
);
174 g_object_unref (file
);
176 laughio
->priv
->uri
= g_strdup (uri
);
182 void _laugh_io_read_async (GObject
*source
, GAsyncResult
*res
, LaughIO
*io
)
184 LaughIOPrivate
*priv
= io
->priv
;
185 if (priv
->cancellable
) {
186 gsize sz
= g_input_stream_read_finish (priv
->fin
, res
, NULL
);
188 gsize grow
= priv
->buf_size
< 4096 ? 4096 : 8192;
189 g_object_ref (G_OBJECT (io
));
191 if (!priv
->buf_pos
) {
193 gchar
*mt
= g_content_type_guess (NULL
, priv
->buffer
, sz
, &b
);
196 g_signal_emit (io
, laugh_io_signals
[MIME
], 0, priv
->mime
);
199 if (priv
->cancellable
) {
200 priv
->buf_size
+= grow
;
201 priv
->buffer
= g_try_realloc (priv
->buffer
, priv
->buf_size
);
203 g_input_stream_read_async (priv
->fin
,
204 priv
->buffer
+ priv
->buf_pos
,
205 grow
-1, G_PRIORITY_DEFAULT
, priv
->cancellable
,
206 (GAsyncReadyCallback
) _laugh_io_read_async
, io
);
208 g_object_unref (G_OBJECT (io
));
209 } else if (sz
== 0) {
210 char *s
= (char *)priv
->buffer
;
211 s
[priv
->buf_pos
] = 0;
212 _laugh_io_clear_gio (priv
, FALSE
);
213 g_signal_emit (io
, laugh_io_signals
[COMPLETED
], 0,
214 priv
->buf_pos
, priv
->buffer
);
216 _laugh_io_clear_gio (priv
, TRUE
);
217 g_signal_emit (io
, laugh_io_signals
[COMPLETED
], 0, 0, NULL
);
223 void _laugh_io_open_async (GObject
*source
, GAsyncResult
*res
, LaughIO
*io
)
225 LaughIOPrivate
*priv
= io
->priv
;
226 if (priv
->cancellable
) {
227 priv
->fin
= (GInputStream
*) g_file_read_finish (priv
->file
, res
, NULL
);
229 priv
->buffer
= g_malloc (300);
230 priv
->buf_size
= 300;
232 g_input_stream_read_async (priv
->fin
,
233 priv
->buffer
, priv
->buf_size
-1,
234 G_PRIORITY_DEFAULT
, priv
->cancellable
,
235 (GAsyncReadyCallback
) _laugh_io_read_async
, io
);
237 _laugh_io_clear_gio (priv
, TRUE
);
238 g_signal_emit (io
, laugh_io_signals
[COMPLETED
], 0, 0, NULL
);
243 gboolean
laugh_io_open (LaughIO
*io
)
245 LaughIOPrivate
*priv
;
247 g_return_if_fail (LAUGH_IS_IO (io
));
251 priv
->file
= g_file_new_for_uri (priv
->uri
);
252 priv
->cancellable
= g_cancellable_new ();
253 g_file_read_async (priv
->file
, G_PRIORITY_DEFAULT
,
255 (GAsyncReadyCallback
) _laugh_io_open_async
, io
);
260 void laugh_io_cancel (LaughIO
*io
)
262 g_return_if_fail (LAUGH_IS_IO (io
));
264 _laugh_io_clear_gio (io
->priv
, TRUE
);
267 const gchar
*laugh_io_get_uri (LaughIO
*io
)
269 g_return_if_fail (LAUGH_IS_IO (io
));
271 return io
->priv
->uri
;
274 /*#define LAUGH_IO_TEST*/
276 /* gcc laugh-io.c -o iotest `pkg-config --libs --cflags gio-2.0 glib-2.0 gthread-2.0` -DLAUGH_IO_TEST*/
278 #include <sys/types.h>
279 #include <sys/stat.h>
283 static GMainLoop
*mainloop
;
284 static int output_fd
;
285 static const char *accept_mime
;
287 void mime_type_callback (LaughIO
*laugh_io
, const gchar
*mime
, gpointer d
)
289 g_printf ("cb mime: %s\n", mime
);
290 if (accept_mime
&& strcmp (mime
, accept_mime
)) {
291 laugh_io_cancel (laugh_io
);
292 g_main_loop_quit (mainloop
);
296 void completed_callback (LaughIO
*laugh_io
, gsize sz
, gpointer data
, gpointer d
)
298 g_printf ("cb completed: %u\n", sz
);
299 write (output_fd
, data
, sz
);
300 g_main_loop_quit (mainloop
);
303 int main (int argc
, char **argv
)
308 g_printerr ("usage %s uri outputfile <accept-mime>\n", argv
[0]);
312 output_fd
= open (argv
[2], O_CREAT
| O_WRONLY
, 0644);
314 g_printerr ("could not write to %s\n", argv
[2]);
319 accept_mime
= argv
[3];
321 g_thread_init (NULL
);
324 l
= laugh_io_new (argv
[1]);
325 g_printf ("uri: %s\n", laugh_io_get_uri (l
));
327 g_signal_connect (G_OBJECT (l
), "mime-type", (GCallback
)mime_type_callback
, 0);
328 g_signal_connect (G_OBJECT (l
), "completed", (GCallback
)completed_callback
, 0);
331 mainloop
= g_main_loop_new (NULL
, TRUE
);
332 g_main_loop_run (mainloop
);
334 g_object_unref (G_OBJECT (l
));