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