atomicqueue: make sure a min initial_size is used
[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 /**
24  * SECTION:gsturihandler
25  * @short_description: Interface to ease URI handling in plugins.
26  *
27  * The URIHandler is an interface that is implemented by Source and Sink 
28  * #GstElement to simplify then handling of URI.
29  *
30  * An application can use the following functions to quickly get an element
31  * that handles the given URI for reading or writing
32  * (gst_element_make_from_uri()).
33  *
34  * Source and Sink plugins should implement this interface when possible.
35  *
36  * Last reviewed on 2005-11-09 (0.9.4)
37  */
38
39 #ifdef HAVE_CONFIG_H
40 #  include "config.h"
41 #endif
42
43 #include "gst_private.h"
44 #include "gsturi.h"
45 #include "gstinfo.h"
46 #include "gstmarshal.h"
47 #include "gstregistry.h"
48
49 #include <string.h>
50
51 GST_DEBUG_CATEGORY_STATIC (gst_uri_handler_debug);
52 #define GST_CAT_DEFAULT gst_uri_handler_debug
53
54 enum
55 {
56   NEW_URI,
57   LAST_SIGNAL
58 };
59
60 static guint gst_uri_handler_signals[LAST_SIGNAL] = { 0 };
61
62 static void gst_uri_handler_base_init (gpointer g_class);
63
64 GType
65 gst_uri_handler_get_type (void)
66 {
67   static volatile gsize urihandler_type = 0;
68
69   if (g_once_init_enter (&urihandler_type)) {
70     GType _type;
71     static const GTypeInfo urihandler_info = {
72       sizeof (GstURIHandlerInterface),
73       gst_uri_handler_base_init,
74       NULL,
75       NULL,
76       NULL,
77       NULL,
78       0,
79       0,
80       NULL,
81       NULL
82     };
83
84     _type = g_type_register_static (G_TYPE_INTERFACE,
85         "GstURIHandler", &urihandler_info, 0);
86
87     GST_DEBUG_CATEGORY_INIT (gst_uri_handler_debug, "GST_URI", GST_DEBUG_BOLD,
88         "handling of URIs");
89     g_once_init_leave (&urihandler_type, _type);
90   }
91   return urihandler_type;
92 }
93
94 static void
95 gst_uri_handler_base_init (gpointer g_class)
96 {
97   static gboolean initialized = FALSE;
98
99   if (G_UNLIKELY (!initialized)) {
100
101     /**
102      * GstURIHandler::new-uri:
103      * @handler: The #GstURIHandler which emitted the signal
104      * @uri: (transfer none): The new URI, or NULL if the URI was removed
105      *
106      * The URI of the given @handler has changed.
107      */
108
109     gst_uri_handler_signals[NEW_URI] =
110         g_signal_new ("new-uri", GST_TYPE_URI_HANDLER, G_SIGNAL_RUN_LAST,
111         G_STRUCT_OFFSET (GstURIHandlerInterface, new_uri), NULL, NULL,
112         gst_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING);
113     initialized = TRUE;
114   }
115 }
116
117 static const guchar acceptable[96] = {  /* X0   X1   X2   X3   X4   X5   X6   X7   X8   X9   XA   XB   XC   XD   XE   XF */
118   0x00, 0x3F, 0x20, 0x20, 0x20, 0x00, 0x2C, 0x3F, 0x3F, 0x3F, 0x3F, 0x22, 0x20, 0x3F, 0x3F, 0x1C,       /* 2X  !"#$%&'()*+,-./   */
119   0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x38, 0x20, 0x20, 0x2C, 0x20, 0x2C,       /* 3X 0123456789:;<=>?   */
120   0x30, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,       /* 4X @ABCDEFGHIJKLMNO   */
121   0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x20, 0x20, 0x20, 0x20, 0x3F,       /* 5X PQRSTUVWXYZ[\]^_   */
122   0x20, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,       /* 6X `abcdefghijklmno   */
123   0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x20, 0x20, 0x20, 0x3F, 0x20        /* 7X pqrstuvwxyz{|}~DEL */
124 };
125
126 typedef enum
127 {
128   UNSAFE_ALL = 0x1,             /* Escape all unsafe characters   */
129   UNSAFE_ALLOW_PLUS = 0x2,      /* Allows '+'  */
130   UNSAFE_PATH = 0x4,            /* Allows '/' and '?' and '&' and '='  */
131   UNSAFE_DOS_PATH = 0x8,        /* Allows '/' and '?' and '&' and '=' and ':' */
132   UNSAFE_HOST = 0x10,           /* Allows '/' and ':' and '@' */
133   UNSAFE_SLASHES = 0x20         /* Allows all characters except for '/' and '%' */
134 } UnsafeCharacterSet;
135
136 #define HEX_ESCAPE '%'
137
138 /*  Escape undesirable characters using %
139  *  -------------------------------------
140  *
141  * This function takes a pointer to a string in which
142  * some characters may be unacceptable unescaped.
143  * It returns a string which has these characters
144  * represented by a '%' character followed by two hex digits.
145  *
146  * This routine returns a g_malloced string.
147  */
148
149 static const gchar hex[16] = "0123456789ABCDEF";
150
151 static gchar *
152 escape_string_internal (const gchar * string, UnsafeCharacterSet mask)
153 {
154 #define ACCEPTABLE_CHAR(a) ((a)>=32 && (a)<128 && (acceptable[(a)-32] & use_mask))
155
156   const gchar *p;
157   gchar *q;
158   gchar *result;
159   guchar c;
160   gint unacceptable;
161   UnsafeCharacterSet use_mask;
162
163   g_return_val_if_fail (mask == UNSAFE_ALL
164       || mask == UNSAFE_ALLOW_PLUS
165       || mask == UNSAFE_PATH
166       || mask == UNSAFE_DOS_PATH
167       || mask == UNSAFE_HOST || mask == UNSAFE_SLASHES, NULL);
168
169   if (string == NULL) {
170     return NULL;
171   }
172
173   unacceptable = 0;
174   use_mask = mask;
175   for (p = string; *p != '\0'; p++) {
176     c = *p;
177     if (!ACCEPTABLE_CHAR (c)) {
178       unacceptable++;
179     }
180     if ((use_mask == UNSAFE_HOST) && (unacceptable || (c == '/'))) {
181       /* when escaping a host, if we hit something that needs to be escaped, or we finally
182        * hit a path separator, revert to path mode (the host segment of the url is over).
183        */
184       use_mask = UNSAFE_PATH;
185     }
186   }
187
188   result = g_malloc (p - string + unacceptable * 2 + 1);
189
190   use_mask = mask;
191   for (q = result, p = string; *p != '\0'; p++) {
192     c = *p;
193
194     if (!ACCEPTABLE_CHAR (c)) {
195       *q++ = HEX_ESCAPE;        /* means hex coming */
196       *q++ = hex[c >> 4];
197       *q++ = hex[c & 15];
198     } else {
199       *q++ = c;
200     }
201     if ((use_mask == UNSAFE_HOST) && (!ACCEPTABLE_CHAR (c) || (c == '/'))) {
202       use_mask = UNSAFE_PATH;
203     }
204   }
205
206   *q = '\0';
207
208   return result;
209 }
210
211 /* escape_string:
212  * @string: string to be escaped
213  *
214  * Escapes @string, replacing any and all special characters
215  * with equivalent escape sequences.
216  *
217  * Return value: a newly allocated string equivalent to @string
218  * but with all special characters escaped
219  **/
220 static gchar *
221 escape_string (const gchar * string)
222 {
223   return escape_string_internal (string, UNSAFE_ALL);
224 }
225
226 static int
227 hex_to_int (gchar c)
228 {
229   return c >= '0' && c <= '9' ? c - '0'
230       : c >= 'A' && c <= 'F' ? c - 'A' + 10
231       : c >= 'a' && c <= 'f' ? c - 'a' + 10 : -1;
232 }
233
234 static int
235 unescape_character (const char *scanner)
236 {
237   int first_digit;
238   int second_digit;
239
240   first_digit = hex_to_int (*scanner++);
241   if (first_digit < 0) {
242     return -1;
243   }
244
245   second_digit = hex_to_int (*scanner);
246   if (second_digit < 0) {
247     return -1;
248   }
249
250   return (first_digit << 4) | second_digit;
251 }
252
253 /* unescape_string:
254  * @escaped_string: an escaped URI, path, or other string
255  * @illegal_characters: a string containing a sequence of characters
256  * considered "illegal", '\0' is automatically in this list.
257  *
258  * Decodes escaped characters (i.e. PERCENTxx sequences) in @escaped_string.
259  * Characters are encoded in PERCENTxy form, where xy is the ASCII hex code
260  * for character 16x+y.
261  *
262  * Return value: a newly allocated string with the unescaped equivalents,
263  * or %NULL if @escaped_string contained one of the characters
264  * in @illegal_characters.
265  **/
266 static char *
267 unescape_string (const gchar * escaped_string, const gchar * illegal_characters)
268 {
269   const gchar *in;
270   gchar *out, *result;
271   gint character;
272
273   if (escaped_string == NULL) {
274     return NULL;
275   }
276
277   result = g_malloc (strlen (escaped_string) + 1);
278
279   out = result;
280   for (in = escaped_string; *in != '\0'; in++) {
281     character = *in;
282     if (*in == HEX_ESCAPE) {
283       character = unescape_character (in + 1);
284
285       /* Check for an illegal character. We consider '\0' illegal here. */
286       if (character <= 0
287           || (illegal_characters != NULL
288               && strchr (illegal_characters, (char) character) != NULL)) {
289         g_free (result);
290         return NULL;
291       }
292       in += 2;
293     }
294     *out++ = (char) character;
295   }
296
297   *out = '\0';
298   g_assert ((gsize) (out - result) <= strlen (escaped_string));
299   return result;
300
301 }
302
303
304 static void
305 gst_uri_protocol_check_internal (const gchar * uri, gchar ** endptr)
306 {
307   gchar *check = (gchar *) uri;
308
309   g_assert (uri != NULL);
310   g_assert (endptr != NULL);
311
312   if (g_ascii_isalpha (*check)) {
313     check++;
314     while (g_ascii_isalnum (*check) || *check == '+'
315         || *check == '-' || *check == '.')
316       check++;
317   }
318
319   *endptr = check;
320 }
321
322 /**
323  * gst_uri_protocol_is_valid:
324  * @protocol: A string
325  *
326  * Tests if the given string is a valid protocol identifier. Protocols
327  * must consist of alphanumeric characters, '+', '-' and '.' and must
328  * start with a alphabetic character. See RFC 3986 Section 3.1.
329  *
330  * Returns: TRUE if the string is a valid protocol identifier, FALSE otherwise.
331  */
332 gboolean
333 gst_uri_protocol_is_valid (const gchar * protocol)
334 {
335   gchar *endptr;
336
337   g_return_val_if_fail (protocol != NULL, FALSE);
338
339   gst_uri_protocol_check_internal (protocol, &endptr);
340
341   return *endptr == '\0' && endptr != protocol;
342 }
343
344 /**
345  * gst_uri_is_valid:
346  * @uri: A URI string
347  *
348  * Tests if the given string is a valid URI identifier. URIs start with a valid
349  * scheme followed by ":" and maybe a string identifying the location.
350  *
351  * Returns: TRUE if the string is a valid URI
352  */
353 gboolean
354 gst_uri_is_valid (const gchar * uri)
355 {
356   gchar *endptr;
357
358   g_return_val_if_fail (uri != NULL, FALSE);
359
360   gst_uri_protocol_check_internal (uri, &endptr);
361
362   return *endptr == ':';
363 }
364
365 /**
366  * gst_uri_get_protocol:
367  * @uri: A URI string
368  *
369  * Extracts the protocol out of a given valid URI. The returned string must be
370  * freed using g_free().
371  *
372  * Returns: The protocol for this URI.
373  */
374 gchar *
375 gst_uri_get_protocol (const gchar * uri)
376 {
377   gchar *colon;
378
379   g_return_val_if_fail (uri != NULL, NULL);
380   g_return_val_if_fail (gst_uri_is_valid (uri), NULL);
381
382   colon = strstr (uri, ":");
383
384   return g_ascii_strdown (uri, colon - uri);
385 }
386
387 /**
388  * gst_uri_has_protocol:
389  * @uri: a URI string
390  * @protocol: a protocol string (e.g. "http")
391  *
392  * Checks if the protocol of a given valid URI matches @protocol.
393  *
394  * Returns: %TRUE if the protocol matches.
395  *
396  * Since: 0.10.4
397  */
398 gboolean
399 gst_uri_has_protocol (const gchar * uri, const gchar * protocol)
400 {
401   gchar *colon;
402
403   g_return_val_if_fail (uri != NULL, FALSE);
404   g_return_val_if_fail (protocol != NULL, FALSE);
405   g_return_val_if_fail (gst_uri_is_valid (uri), FALSE);
406
407   colon = strstr (uri, ":");
408
409   if (colon == NULL)
410     return FALSE;
411
412   return (g_ascii_strncasecmp (uri, protocol, (gsize) (colon - uri)) == 0);
413 }
414
415 /**
416  * gst_uri_get_location:
417  * @uri: A URI string
418  *
419  * Extracts the location out of a given valid URI, ie. the protocol and "://"
420  * are stripped from the URI, which means that the location returned includes
421  * the hostname if one is specified. The returned string must be freed using
422  * g_free().
423  *
424  * Free-function: g_free
425  *
426  * Returns: (transfer full) (array zero-terminated=1): the location for this
427  *     URI. Returns NULL if the URI isn't valid. If the URI does not contain
428  *     a location, an empty string is returned.
429  */
430 gchar *
431 gst_uri_get_location (const gchar * uri)
432 {
433   const gchar *colon;
434   gchar *unescaped = NULL;
435
436   g_return_val_if_fail (uri != NULL, NULL);
437   g_return_val_if_fail (gst_uri_is_valid (uri), NULL);
438
439   colon = strstr (uri, "://");
440   if (!colon)
441     return NULL;
442
443   unescaped = unescape_string (colon + 3, "/");
444
445   /* On Windows an URI might look like file:///c:/foo/bar.txt or
446    * file:///c|/foo/bar.txt (some Netscape versions) and we want to
447    * return c:/foo/bar.txt as location rather than /c:/foo/bar.txt.
448    * Can't use g_filename_from_uri() here because it will only handle the
449    * file:// protocol */
450 #ifdef G_OS_WIN32
451   if (unescaped != NULL && unescaped[0] == '/' &&
452       g_ascii_isalpha (unescaped[1]) &&
453       (unescaped[2] == ':' || unescaped[2] == '|')) {
454     unescaped[2] = ':';
455     g_memmove (unescaped, unescaped + 1, strlen (unescaped + 1) + 1);
456   }
457 #endif
458
459   GST_LOG ("extracted location '%s' from URI '%s'", GST_STR_NULL (unescaped),
460       uri);
461   return unescaped;
462 }
463
464 /**
465  * gst_uri_construct:
466  * @protocol: Protocol for URI
467  * @location: (array zero-terminated=1) (transfer none): Location for URI
468  *
469  * Constructs a URI for a given valid protocol and location.
470  *
471  * Free-function: g_free
472  *
473  * Returns: (transfer full) (array zero-terminated=1): a new string for this
474  *     URI. Returns NULL if the given URI protocol is not valid, or the given
475  *     location is NULL.
476  */
477 gchar *
478 gst_uri_construct (const gchar * protocol, const gchar * location)
479 {
480   char *escaped, *proto_lowercase;
481   char *retval;
482
483   g_return_val_if_fail (gst_uri_protocol_is_valid (protocol), NULL);
484   g_return_val_if_fail (location != NULL, NULL);
485
486   proto_lowercase = g_ascii_strdown (protocol, -1);
487   escaped = escape_string (location);
488   retval = g_strdup_printf ("%s://%s", proto_lowercase, escaped);
489   g_free (escaped);
490   g_free (proto_lowercase);
491
492   return retval;
493 }
494
495 typedef struct
496 {
497   GstURIType type;
498   const gchar *protocol;
499 }
500 SearchEntry;
501
502 static gboolean
503 search_by_entry (GstPluginFeature * feature, gpointer search_entry)
504 {
505   gchar **protocols;
506   GstElementFactory *factory;
507   SearchEntry *entry = (SearchEntry *) search_entry;
508
509   if (!GST_IS_ELEMENT_FACTORY (feature))
510     return FALSE;
511   factory = GST_ELEMENT_FACTORY_CAST (feature);
512
513   if (factory->uri_type != entry->type)
514     return FALSE;
515
516   protocols = gst_element_factory_get_uri_protocols (factory);
517
518   if (protocols == NULL) {
519     g_warning ("Factory '%s' implements GstUriHandler interface but returned "
520         "no supported protocols!", gst_plugin_feature_get_name (feature));
521     return FALSE;
522   }
523
524   while (*protocols != NULL) {
525     if (g_ascii_strcasecmp (*protocols, entry->protocol) == 0)
526       return TRUE;
527     protocols++;
528   }
529   return FALSE;
530 }
531
532 static gint
533 sort_by_rank (GstPluginFeature * first, GstPluginFeature * second)
534 {
535   return gst_plugin_feature_get_rank (second) -
536       gst_plugin_feature_get_rank (first);
537 }
538
539 static GList *
540 get_element_factories_from_uri_protocol (const GstURIType type,
541     const gchar * protocol)
542 {
543   GList *possibilities;
544   SearchEntry entry;
545
546   g_return_val_if_fail (protocol, NULL);
547
548   entry.type = type;
549   entry.protocol = protocol;
550   possibilities = gst_registry_feature_filter (gst_registry_get_default (),
551       search_by_entry, FALSE, &entry);
552
553   return possibilities;
554 }
555
556 /**
557  * gst_uri_protocol_is_supported:
558  * @type: Whether to check for a source or a sink
559  * @protocol: Protocol that should be checked for (e.g. "http" or "smb")
560  *
561  * Checks if an element exists that supports the given URI protocol. Note
562  * that a positive return value does not imply that a subsequent call to
563  * gst_element_make_from_uri() is guaranteed to work.
564  *
565  * Returns: TRUE
566  *
567  * Since: 0.10.13
568 */
569 gboolean
570 gst_uri_protocol_is_supported (const GstURIType type, const gchar * protocol)
571 {
572   GList *possibilities;
573
574   g_return_val_if_fail (protocol, FALSE);
575
576   possibilities = get_element_factories_from_uri_protocol (type, protocol);
577
578   if (possibilities) {
579     g_list_free (possibilities);
580     return TRUE;
581   } else
582     return FALSE;
583 }
584
585 /**
586  * gst_element_make_from_uri:
587  * @type: Whether to create a source or a sink
588  * @uri: URI to create an element for
589  * @elementname: (allow-none): Name of created element, can be NULL.
590  *
591  * Creates an element for handling the given URI.
592  *
593  * Returns: (transfer full): a new element or NULL if none could be created
594  */
595 GstElement *
596 gst_element_make_from_uri (const GstURIType type, const gchar * uri,
597     const gchar * elementname)
598 {
599   GList *possibilities, *walk;
600   gchar *protocol;
601   GstElement *ret = NULL;
602
603   g_return_val_if_fail (GST_URI_TYPE_IS_VALID (type), NULL);
604   g_return_val_if_fail (gst_uri_is_valid (uri), NULL);
605
606   protocol = gst_uri_get_protocol (uri);
607   possibilities = get_element_factories_from_uri_protocol (type, protocol);
608   g_free (protocol);
609
610   if (!possibilities) {
611     GST_DEBUG ("No %s for URI '%s'", type == GST_URI_SINK ? "sink" : "source",
612         uri);
613     return NULL;
614   }
615
616   possibilities = g_list_sort (possibilities, (GCompareFunc) sort_by_rank);
617   walk = possibilities;
618   while (walk) {
619     if ((ret =
620             gst_element_factory_create (GST_ELEMENT_FACTORY_CAST (walk->data),
621                 elementname)) != NULL) {
622       GstURIHandler *handler = GST_URI_HANDLER (ret);
623
624       if (gst_uri_handler_set_uri (handler, uri))
625         break;
626       gst_object_unref (ret);
627       ret = NULL;
628     }
629     walk = walk->next;
630   }
631   gst_plugin_feature_list_free (possibilities);
632
633   GST_LOG_OBJECT (ret, "created %s for URL '%s'",
634       type == GST_URI_SINK ? "sink" : "source", uri);
635   return ret;
636 }
637
638 /**
639  * gst_uri_handler_get_uri_type:
640  * @handler: A #GstURIHandler.
641  *
642  * Gets the type of the given URI handler
643  *
644  * Returns: the #GstURIType of the URI handler.
645  * Returns #GST_URI_UNKNOWN if the @handler isn't implemented correctly.
646  */
647 guint
648 gst_uri_handler_get_uri_type (GstURIHandler * handler)
649 {
650   GstURIHandlerInterface *iface;
651   guint ret;
652
653   g_return_val_if_fail (GST_IS_URI_HANDLER (handler), GST_URI_UNKNOWN);
654
655   iface = GST_URI_HANDLER_GET_INTERFACE (handler);
656   g_return_val_if_fail (iface != NULL, GST_URI_UNKNOWN);
657   g_return_val_if_fail (iface->get_type != NULL
658       || iface->get_type_full != NULL, GST_URI_UNKNOWN);
659
660   if (iface->get_type != NULL)
661     ret = iface->get_type ();
662   else
663     ret = iface->get_type_full (G_OBJECT_TYPE (handler));
664   g_return_val_if_fail (GST_URI_TYPE_IS_VALID (ret), GST_URI_UNKNOWN);
665
666   return ret;
667 }
668
669 /**
670  * gst_uri_handler_get_protocols:
671  * @handler: A #GstURIHandler.
672  *
673  * Gets the list of protocols supported by @handler. This list may not be
674  * modified.
675  *
676  * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): the
677  *     supported protocols. Returns NULL if the @handler isn't implemented
678  *     properly, or the @handler doesn't support any protocols.
679  */
680 gchar **
681 gst_uri_handler_get_protocols (GstURIHandler * handler)
682 {
683   GstURIHandlerInterface *iface;
684   gchar **ret;
685
686   g_return_val_if_fail (GST_IS_URI_HANDLER (handler), NULL);
687
688   iface = GST_URI_HANDLER_GET_INTERFACE (handler);
689   g_return_val_if_fail (iface != NULL, NULL);
690   g_return_val_if_fail (iface->get_protocols != NULL ||
691       iface->get_protocols_full != NULL, NULL);
692
693   if (iface->get_protocols != NULL) {
694     ret = iface->get_protocols ();
695   } else {
696     ret = iface->get_protocols_full (G_OBJECT_TYPE (handler));
697   }
698   g_return_val_if_fail (ret != NULL, NULL);
699
700   return ret;
701 }
702
703 /**
704  * gst_uri_handler_get_uri:
705  * @handler: A #GstURIHandler
706  *
707  * Gets the currently handled URI.
708  *
709  * Returns: (transfer none): the URI currently handled by the @handler.
710  *   Returns NULL if there are no URI currently handled. The
711  *   returned string must not be modified or freed.
712  */
713 G_CONST_RETURN gchar *
714 gst_uri_handler_get_uri (GstURIHandler * handler)
715 {
716   GstURIHandlerInterface *iface;
717   const gchar *ret;
718
719   g_return_val_if_fail (GST_IS_URI_HANDLER (handler), NULL);
720
721   iface = GST_URI_HANDLER_GET_INTERFACE (handler);
722   g_return_val_if_fail (iface != NULL, NULL);
723   g_return_val_if_fail (iface->get_uri != NULL, NULL);
724   ret = iface->get_uri (handler);
725   if (ret != NULL)
726     g_return_val_if_fail (gst_uri_is_valid (ret), NULL);
727
728   return ret;
729 }
730
731 /**
732  * gst_uri_handler_set_uri:
733  * @handler: A #GstURIHandler
734  * @uri: URI to set
735  *
736  * Tries to set the URI of the given handler.
737  *
738  * Returns: TRUE if the URI was set successfully, else FALSE.
739  */
740 gboolean
741 gst_uri_handler_set_uri (GstURIHandler * handler, const gchar * uri)
742 {
743   GstURIHandlerInterface *iface;
744   gboolean ret;
745   gchar *new_uri, *protocol, *location, *colon;
746
747   g_return_val_if_fail (GST_IS_URI_HANDLER (handler), FALSE);
748   g_return_val_if_fail (gst_uri_is_valid (uri), FALSE);
749
750   iface = GST_URI_HANDLER_GET_INTERFACE (handler);
751   g_return_val_if_fail (iface != NULL, FALSE);
752   g_return_val_if_fail (iface->set_uri != NULL, FALSE);
753
754   protocol = gst_uri_get_protocol (uri);
755
756   colon = strstr (uri, ":");
757   location = g_strdup (colon);
758
759   new_uri = g_strdup_printf ("%s%s", protocol, location);
760
761   ret = iface->set_uri (handler, uri);
762
763   g_free (new_uri);
764   g_free (location);
765   g_free (protocol);
766
767   return ret;
768 }
769
770 /**
771  * gst_uri_handler_new_uri:
772  * @handler: A #GstURIHandler
773  * @uri: new URI or NULL if it was unset
774  *
775  * Emits the new-uri signal for a given handler, when that handler has a new URI.
776  * This function should only be called by URI handlers themselves.
777  */
778 void
779 gst_uri_handler_new_uri (GstURIHandler * handler, const gchar * uri)
780 {
781   g_return_if_fail (GST_IS_URI_HANDLER (handler));
782
783   g_signal_emit (handler, gst_uri_handler_signals[NEW_URI], 0, uri);
784 }