Add laugh-layout
[laugh.git] / src / laugh-io.c
blob91615c8c7732448daf4478b1d32ebe79aaf9133f
1 /*
2 * Laugh.
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.
24 /**
25 * SECTION:laugh-io
26 * @short_description: A simple io abstraction.
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
33 #include "laugh-io.h"
35 #include <gio/gio.h>
36 #include <glib/gprintf.h>
38 #define LAUGH_IO_GET_PRIVATE(obj) \
39 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), LAUGH_TYPE_IO, LaughIOPrivate))
41 enum
43 MIME,
44 COMPLETED,
46 LAST_SIGNAL
49 static guint laugh_io_signals[LAST_SIGNAL] = { 0 };
51 struct _LaughIOPrivate {
52 gchar *uri;
53 gchar *mime;
54 GFile *file;
55 GInputStream *fin;
56 GCancellable *cancellable;
57 unsigned char *buffer;
58 gsize buf_size;
59 gsize buf_pos;
62 static gpointer laugh_io_parent_class = ((void *)0);
64 static void _laugh_io_clear_gio (LaughIOPrivate *priv, gboolean cancel) {
65 if (priv->cancellable) {
66 if (cancel) {
67 g_cancellable_cancel (priv->cancellable);
68 g_free (priv->buffer);
69 priv->buffer = NULL;
71 g_object_unref (G_OBJECT (priv->cancellable));
72 priv->cancellable = NULL;
73 if (priv->fin) {
74 g_object_unref (G_OBJECT (priv->fin));
75 priv->fin = NULL;
77 if (priv->file) {
78 g_object_unref (G_OBJECT (priv->file));
79 priv->file = NULL;
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),
113 G_SIGNAL_RUN_LAST,
114 G_STRUCT_OFFSET (LaughIOClass, mime_type),
115 NULL, NULL,
116 g_cclosure_marshal_VOID__STRING,
117 G_TYPE_NONE, 1,
118 G_TYPE_STRING);
120 laugh_io_signals[COMPLETED] =
121 g_signal_new ("completed",
122 G_TYPE_FROM_CLASS (gobject_class),
123 G_SIGNAL_RUN_LAST,
124 G_STRUCT_OFFSET (LaughIOClass, completed),
125 NULL, NULL,
126 g_cclosure_marshal_VOID__UINT_POINTER,
127 G_TYPE_NONE, 2,
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;
144 if (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 */
152 sizeof (LaughIO),
153 0, /* n_preallocs */
154 laugh_io_instance_init /* instance_init */
156 type = g_type_register_static (G_TYPE_OBJECT,
157 "LaughIOType",
158 &info, 0);
160 return type;
163 LaughIO *laugh_io_new (const gchar *uri)
165 LaughIO *laughio;
167 if (!uri)
168 return NULL;
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);
175 } else {
176 laughio->priv->uri = g_strdup (uri);
178 return laughio;
181 static
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);
187 if (sz > 0) {
188 gsize grow = priv->buf_size < 4096 ? 4096 : 8192;
189 g_object_ref (G_OBJECT (io));
191 if (!priv->buf_pos) {
192 gboolean b;
193 gchar *mt = g_content_type_guess (NULL, priv->buffer, sz, &b);
194 if (mt) {
195 priv->mime = mt;
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);
202 priv->buf_pos += sz;
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);
215 } else {
216 _laugh_io_clear_gio (priv, TRUE);
217 g_signal_emit (io, laugh_io_signals[COMPLETED], 0, 0, NULL);
222 static
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);
228 if (priv->fin) {
229 priv->buffer = g_malloc (300);
230 priv->buf_size = 300;
231 priv->buf_pos = 0;
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);
236 } else {
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));
249 priv = io->priv;
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,
254 priv->cancellable,
255 (GAsyncReadyCallback) _laugh_io_open_async, io);
257 return TRUE;
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*/
275 #ifdef 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*/
277 #include <unistd.h>
278 #include <sys/types.h>
279 #include <sys/stat.h>
280 #include <fcntl.h>
281 #include <string.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)
305 LaughIO *l;
307 if (argc < 3) {
308 g_printerr ("usage %s uri outputfile <accept-mime>\n", argv[0]);
309 return 1;
312 output_fd = open (argv[2], O_CREAT | O_WRONLY, 0644);
313 if (output_fd < 0) {
314 g_printerr ("could not write to %s\n", argv[2]);
315 return 1;
318 if (argc > 3)
319 accept_mime = argv[3];
321 g_thread_init (NULL);
322 g_type_init ();
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);
329 laugh_io_open (l);
331 mainloop = g_main_loop_new (NULL, TRUE);
332 g_main_loop_run (mainloop);
334 g_object_unref (G_OBJECT (l));
335 close (output_fd);
337 return 0;
340 #endif