19c2202ce2709200ad775dca6c743ecfcc9ff71a
[platform/upstream/gstreamer.git] / gst / gsturi.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *
5  * gsturi.c: register URI handlers
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #  include "config.h"
25 #endif
26
27 #include "gsturi.h"
28 #include "gstinfo.h"
29 #include "gstregistrypool.h"
30 #include "gstmarshal.h"
31
32 #include <string.h>
33
34 GST_DEBUG_CATEGORY_STATIC (gst_uri_handler_debug);
35 #define GST_CAT_DEFAULT gst_uri_handler_debug
36
37 static void gst_uri_handler_base_init (gpointer g_class);
38
39 GType
40 gst_uri_handler_get_type (void)
41 {
42   static GType urihandler_type = 0;
43
44   if (!urihandler_type) {
45     static const GTypeInfo urihandler_info = {
46       sizeof (GstURIHandlerInterface),
47       gst_uri_handler_base_init,
48       NULL,
49       NULL,
50       NULL,
51       NULL,
52       0,
53       0,
54       NULL,
55       NULL
56     };
57
58     urihandler_type = g_type_register_static (G_TYPE_INTERFACE,
59         "GstURIHandler", &urihandler_info, 0);
60
61     GST_DEBUG_CATEGORY_INIT (gst_uri_handler_debug, "GST_URI", GST_DEBUG_BOLD,
62         "handling of URIs");
63   }
64   return urihandler_type;
65 }
66 static void
67 gst_uri_handler_base_init (gpointer g_class)
68 {
69   static gboolean initialized = FALSE;
70
71   if (!initialized) {
72     g_signal_new ("new-uri", GST_TYPE_URI_HANDLER, G_SIGNAL_RUN_LAST,
73         G_STRUCT_OFFSET (GstURIHandlerInterface, new_uri), NULL, NULL,
74         gst_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING);
75     initialized = TRUE;
76   }
77 }
78
79 static void
80 gst_uri_protocol_check_internal (const gchar * uri, gchar ** endptr)
81 {
82   gchar *check = (gchar *) uri;
83
84   g_assert (uri != NULL);
85   g_assert (endptr != NULL);
86
87   if (g_ascii_isalpha (*check)) {
88     check++;
89     while (g_ascii_isalnum (*check))
90       check++;
91   }
92
93   *endptr = check;
94 }
95
96 /**
97  * gst_uri_protocol_is_valid:
98  * @protocol: string to check
99  *
100  * Tests if the given string is a valid protocol identifier. Protocols
101  * must consist of alphanumeric characters and not start with a number.
102  *
103  * Returns: TRUE if the string is a valid protocol identifier
104  */
105 gboolean
106 gst_uri_protocol_is_valid (const gchar * protocol)
107 {
108   gchar *endptr;
109
110   g_return_val_if_fail (protocol != NULL, FALSE);
111
112   gst_uri_protocol_check_internal (protocol, &endptr);
113
114   return *endptr == '\0' && endptr != protocol;
115 }
116
117 /**
118  * gst_uri_is_valid:
119  * @protocol: string to check
120  *
121  * Tests if the given string is a valid URI identifier. URIs start with a valid
122  * protocol followed by "://" and a string identifying the location.
123  *
124  * Returns: TRUE if the string is a valid URI
125  */
126 gboolean
127 gst_uri_is_valid (const gchar * uri)
128 {
129   gchar *endptr;
130
131   g_return_val_if_fail (uri != NULL, FALSE);
132
133   gst_uri_protocol_check_internal (uri, &endptr);
134
135   return (*endptr == ':' && *(endptr + 1) == '/' && *(endptr + 2) == '/');
136 }
137
138 /**
139  * gst_uri_get_protocol:
140  * @uri: URI to get protocol from
141  *
142  * Extracts the protocol out of a given valid URI. The returned string must be
143  * freed using g_free().
144  *
145  * Returns: The protocol for this URI.
146  */
147 gchar *
148 gst_uri_get_protocol (const gchar * uri)
149 {
150   gchar *colon;
151
152   g_return_val_if_fail (uri != NULL, NULL);
153   g_return_val_if_fail (gst_uri_is_valid (uri), NULL);
154
155   colon = strstr (uri, "://");
156
157   return g_strndup (uri, colon - uri);
158 }
159
160 /**
161  * gst_uri_get_location:
162  * @uri: URI to get the location from
163  *
164  * Extracts the location out of a given valid URI. So the protocol and "://"
165  * are stripped from the URI. The returned string must be freed using 
166  * g_free().
167  *
168  * Returns: The location for this URI.
169  */
170 gchar *
171 gst_uri_get_location (const gchar * uri)
172 {
173   gchar *colon;
174
175   g_return_val_if_fail (uri != NULL, NULL);
176   g_return_val_if_fail (gst_uri_is_valid (uri), NULL);
177
178   colon = strstr (uri, "://");
179
180   return g_strdup (colon + 3);
181 }
182
183 /**
184  * gst_uri_construct:
185  * @protocol: protocol for URI
186  * @location: location for URI
187  *
188  * Constructs a URI for a given valid protocol and location.
189  *
190  * Returns: a new string for this URI
191  */
192 gchar *
193 gst_uri_construct (const gchar * protocol, const gchar * location)
194 {
195   g_return_val_if_fail (gst_uri_protocol_is_valid (protocol), NULL);
196   g_return_val_if_fail (location != NULL, NULL);
197
198   return g_strdup_printf ("%s://%s", protocol, location);
199 }
200 typedef struct
201 {
202   GstURIType type;
203   gchar *protocol;
204 }
205 SearchEntry;
206 static gboolean
207 search_by_entry (GstPluginFeature * feature, gpointer search_entry)
208 {
209   gchar **protocols;
210   GstElementFactory *factory;
211   SearchEntry *entry = (SearchEntry *) search_entry;
212
213   if (!GST_IS_ELEMENT_FACTORY (feature))
214     return FALSE;
215   factory = GST_ELEMENT_FACTORY (feature);
216
217   if (gst_element_factory_get_uri_type (factory) != entry->type)
218     return FALSE;
219
220   protocols = gst_element_factory_get_uri_protocols (factory);
221   /* must be set when uri type is valid */
222   g_assert (protocols);
223   while (*protocols != NULL) {
224     if (strcmp (*protocols, entry->protocol) == 0)
225       return TRUE;
226     protocols++;
227   }
228   return FALSE;
229 }
230
231 static gint
232 sort_by_rank (gconstpointer a, gconstpointer b)
233 {
234   GstPluginFeature *first = GST_PLUGIN_FEATURE (a);
235   GstPluginFeature *second = GST_PLUGIN_FEATURE (b);
236
237   return gst_plugin_feature_get_rank (second) -
238       gst_plugin_feature_get_rank (first);
239 }
240
241 /**
242  * gst_element_make_from_uri:
243  * @type: wether to create a source or a sink
244  * @uri: URI to create element for
245  * @elementname: optional name of created element
246  *
247  * Creates an element for handling the given URI. 
248  * 
249  * Returns: a new element or NULL if none could be created
250  */
251 GstElement *
252 gst_element_make_from_uri (const GstURIType type, const gchar * uri,
253     const gchar * elementname)
254 {
255   GList *possibilities, *walk;
256   SearchEntry entry;
257   GstElement *ret = NULL;
258
259   g_return_val_if_fail (GST_URI_TYPE_IS_VALID (type), NULL);
260   g_return_val_if_fail (gst_uri_is_valid (uri), NULL);
261
262   entry.type = type;
263   entry.protocol = gst_uri_get_protocol (uri);
264   possibilities =
265       gst_registry_pool_feature_filter (search_by_entry, FALSE, &entry);
266   g_free (entry.protocol);
267
268   if (!possibilities) {
269     GST_DEBUG ("No %s for URI '%s'", type == GST_URI_SINK ? "sink" : "source",
270         uri);
271     return NULL;
272   }
273
274   possibilities = g_list_sort (possibilities, sort_by_rank);
275   walk = possibilities;
276   while (walk) {
277     if ((ret = gst_element_factory_create (GST_ELEMENT_FACTORY (walk->data),
278                 elementname)) != NULL) {
279       GstURIHandler *handler = GST_URI_HANDLER (ret);
280
281       if (gst_uri_handler_set_uri (handler, uri))
282         break;
283       g_object_unref (ret);
284       ret = NULL;
285     }
286   }
287   g_list_free (possibilities);
288
289   GST_LOG_OBJECT (ret, "created %s for URL '%s'",
290       type == GST_URI_SINK ? "sink" : "source", uri);
291   return ret;
292 }
293
294 /**
295  * gst_uri_handler_get_uri_type:
296  * @handler: Handler to query type of
297  *
298  * Gets the type of a URI handler
299  *
300  * Returns: the type of the URI handler
301  */
302 guint
303 gst_uri_handler_get_uri_type (GstURIHandler * handler)
304 {
305   GstURIHandlerInterface *iface;
306   guint ret;
307
308   g_return_val_if_fail (GST_IS_URI_HANDLER (handler), GST_URI_UNKNOWN);
309
310   iface = GST_URI_HANDLER_GET_INTERFACE (handler);
311   g_return_val_if_fail (iface != NULL, GST_URI_UNKNOWN);
312   g_return_val_if_fail (iface->get_type != NULL, GST_URI_UNKNOWN);
313   ret = iface->get_type ();
314   g_return_val_if_fail (GST_URI_TYPE_IS_VALID (ret), GST_URI_UNKNOWN);
315
316   return ret;
317 }
318
319 /**
320  * gst_uri_handler_get_protocols:
321  * @handler: Handler to get protocols for
322  *
323  * Gets the list of supported protocols for this handler. This list may not be
324  * modified.
325  *
326  * Returns: the supported protocols
327  */
328 gchar **
329 gst_uri_handler_get_protocols (GstURIHandler * handler)
330 {
331   GstURIHandlerInterface *iface;
332   gchar **ret;
333
334   g_return_val_if_fail (GST_IS_URI_HANDLER (handler), NULL);
335
336   iface = GST_URI_HANDLER_GET_INTERFACE (handler);
337   g_return_val_if_fail (iface != NULL, NULL);
338   g_return_val_if_fail (iface->get_protocols != NULL, NULL);
339   ret = iface->get_protocols ();
340   g_return_val_if_fail (ret != NULL, NULL);
341
342   return ret;
343 }
344
345 /**
346  * gst_uri_handler_get_uri:
347  * @handler: handler to query URI of
348  *
349  * Gets the currently handled URI of the handler or NULL, if none is set.
350  *
351  * Returns: the URI
352  */
353 G_CONST_RETURN gchar *
354 gst_uri_handler_get_uri (GstURIHandler * handler)
355 {
356   GstURIHandlerInterface *iface;
357   const gchar *ret;
358
359   g_return_val_if_fail (GST_IS_URI_HANDLER (handler), NULL);
360
361   iface = GST_URI_HANDLER_GET_INTERFACE (handler);
362   g_return_val_if_fail (iface != NULL, NULL);
363   g_return_val_if_fail (iface->get_uri != NULL, NULL);
364   ret = iface->get_uri (handler);
365   if (ret != NULL)
366     g_return_val_if_fail (gst_uri_is_valid (ret), NULL);
367
368   return ret;
369 }
370
371 /**
372  * gst_uri_handler_set_uri:
373  * @handler: handler to set URI of
374  * @uri: URI to set
375  *
376  * Tries to set the URI of the given handler and returns TRUE if it succeeded.
377  *
378  * Returns: TRUE, if the URI was set successfully
379  */
380 gboolean
381 gst_uri_handler_set_uri (GstURIHandler * handler, const gchar * uri)
382 {
383   GstURIHandlerInterface *iface;
384
385   g_return_val_if_fail (GST_IS_URI_HANDLER (handler), FALSE);
386   g_return_val_if_fail (gst_uri_is_valid (uri), FALSE);
387
388   iface = GST_URI_HANDLER_GET_INTERFACE (handler);
389   g_return_val_if_fail (iface != NULL, FALSE);
390   g_return_val_if_fail (iface->set_uri != NULL, FALSE);
391   return iface->set_uri (handler, uri);
392 }
393
394 /**
395  * gst_uri_handler_new_uri:
396  * @handler: handler with a new URI
397  * @uri: new URI or NULL if it was unset
398  *
399  * Emits the new-uri event for a given handler, when that handler has a new URI.
400  * This function should only be called by URI handlers themselves.
401  */
402 void
403 gst_uri_handler_new_uri (GstURIHandler * handler, const gchar * uri)
404 {
405   g_return_if_fail (GST_IS_URI_HANDLER (handler));
406
407   g_signal_emit_by_name (handler, "new-uri", uri);
408 }