gmyth/src/gmyth_uri.c
author leo_sobral
Fri Mar 23 15:26:38 2007 +0000 (2007-03-23)
branchtrunk
changeset 444 d6603c86582f
parent 421 d04e08f9893a
child 446 d260ed30f4de
permissions -rwxr-xr-x
[svn r449] warnings removed
     1 /** 
     2  * GMyth Library
     3  *
     4  * @file gmyth/gmyth_uri.c
     5  * 
     6  * @brief <p> GMythURI utils
     7  *  - Extracts and parses a URI char string, in according with the RFC 2396 
     8  *    [http://www.ietf.org/rfc/rfc2396.txt]
     9  * 
    10  * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia.
    11  * @author Rosfran Borges <rosfran.borges@indt.org.br>
    12  *
    13  *//*
    14  * 
    15  * This program is free software; you can redistribute it and/or modify
    16  * it under the terms of the GNU Lesser General Public License as published by
    17  * the Free Software Foundation; either version 2 of the License, or
    18  * (at your option) any later version.
    19  *
    20  * This program is distributed in the hope that it will be useful,
    21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    23  * GNU General Public License for more details.
    24  *
    25  * You should have received a copy of the GNU Lesser General Public License
    26  * along with this program; if not, write to the Free Software
    27  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    28  */
    29  
    30 #ifdef HAVE_CONFIG_H
    31 #include "config.h"
    32 #endif
    33 
    34 #include "gmyth_uri.h"
    35 
    36 #include <glib.h>
    37 #include <string.h>
    38 #include <stdlib.h>
    39 
    40 #include "gmyth_debug.h"
    41 
    42 static void gmyth_uri_class_init          (GMythURIClass *klass);
    43 static void gmyth_uri_init                (GMythURI *object);
    44 
    45 static void gmyth_uri_dispose  (GObject *object);
    46 static void gmyth_uri_finalize (GObject *object);
    47 
    48 static void gmyth_uri_parser_setup_and_new(GMythURI *uri, const gchar *value);
    49 static gchar* gmyth_uri_print_field(const GString* field);
    50 
    51 G_DEFINE_TYPE(GMythURI, gmyth_uri, G_TYPE_OBJECT)
    52 
    53 static void
    54 gmyth_uri_class_init (GMythURIClass *klass)
    55 {
    56 	GObjectClass *gobject_class;
    57 
    58     gobject_class = (GObjectClass *) klass;
    59 	
    60     gobject_class->dispose  = gmyth_uri_dispose;
    61     gobject_class->finalize = gmyth_uri_finalize;	
    62 }
    63 
    64 static void
    65 gmyth_uri_init (GMythURI *gmyth_uri)
    66 {
    67 }
    68 
    69 static void
    70 gmyth_uri_dispose  (GObject *object)
    71 {
    72 	GMythURI *gmyth_uri = GMYTH_URI(object);
    73 
    74 	if ( gmyth_uri->host != NULL ) {
    75 		g_string_free( gmyth_uri->host, TRUE );
    76 		gmyth_uri->host = NULL;
    77 	}
    78 	
    79 	if ( gmyth_uri->protocol != NULL ) {
    80 		g_string_free( gmyth_uri->protocol, TRUE );
    81 		gmyth_uri->protocol = NULL;
    82 	}
    83 	
    84 	if ( gmyth_uri->path != NULL ) {
    85 		g_string_free( gmyth_uri->path, TRUE );
    86 		gmyth_uri->path = NULL;
    87 	}
    88 	
    89 	if ( gmyth_uri->fragment != NULL ) {
    90 		g_string_free( gmyth_uri->fragment, TRUE );
    91 		gmyth_uri->fragment = NULL;
    92 	}
    93 	
    94 	if ( gmyth_uri->user != NULL ) {
    95 		g_string_free( gmyth_uri->user, TRUE );
    96 		gmyth_uri->user = NULL;
    97 	}
    98 	
    99 	if ( gmyth_uri->password != NULL ) {
   100 		g_string_free( gmyth_uri->password, TRUE );
   101 		gmyth_uri->password = NULL;
   102 	}
   103 	
   104 	if ( gmyth_uri->query != NULL ) {
   105 		g_string_free( gmyth_uri->query, TRUE );
   106 		gmyth_uri->query = NULL;
   107 	}	
   108 
   109 	if ( gmyth_uri->uri != NULL ) {
   110 		g_string_free( gmyth_uri->uri, TRUE );
   111 		gmyth_uri->uri = NULL;
   112 	}	
   113 
   114 
   115 	G_OBJECT_CLASS (gmyth_uri_parent_class)->dispose (object);
   116 }
   117 
   118 static void
   119 gmyth_uri_finalize (GObject *object)
   120 {
   121 	//GMythURI *gmyth_uri = GMYTH_URI(object);
   122 
   123 	g_signal_handlers_destroy (object);
   124 
   125 	G_OBJECT_CLASS (gmyth_uri_parent_class)->finalize (object);
   126 }
   127 
   128 /** 
   129  * Creates a new instance of GMythURI.
   130  * 
   131  * @return a new instance of GMythURI.
   132  */
   133 GMythURI *
   134 gmyth_uri_new (void) 
   135 {
   136     GMythURI *gmyth_uri = GMYTH_URI (g_object_new (GMYTH_URI_TYPE, NULL));
   137     
   138     return gmyth_uri;
   139 }
   140 
   141 /** 
   142  * Creates a new instance of GMythURI.
   143  * 
   144  * @param uri_str The URI string representing this URI instance.
   145  * 
   146  * @return a new instance of GMythURI.
   147  */
   148 GMythURI *
   149 gmyth_uri_new_with_value (const gchar *uri_str) 
   150 {
   151     GMythURI *gmyth_uri = GMYTH_URI (g_object_new (GMYTH_URI_TYPE, NULL));
   152     
   153     gmyth_uri_parser_setup_and_new (gmyth_uri, uri_str);
   154     
   155     return gmyth_uri;
   156 }
   157 
   158 /** 
   159  * Gets the starting offset of a substring inside a given string.
   160  * 
   161  * @param haystack The given string to be searched for patterns.
   162  * @param needle The substring that should be matched over the haystack.
   163  * 
   164  * @return The starting offset to the given substring, or <code>-1</code> if the
   165  * 				 haystack function parameter doesn't contains the needle string argument.
   166  */
   167 static gint 
   168 gmyth_strstr (const gchar *haystack, const gchar *needle)
   169 {
   170 	
   171 	gchar *strPos;
   172 	
   173 	if (haystack == NULL || needle == NULL)
   174 		return -1;
   175 	strPos = strstr(haystack, needle);
   176 	if (strPos == NULL)
   177 		return -1;
   178 		
   179 	return (strPos - haystack);
   180 
   181 }
   182 
   183 /** 
   184  * Checks if a URI is absolute.
   185  * 
   186  * @param uri The GMythURI instance.
   187  * 
   188  * @return <code>true</code>, if the URI is absolute.
   189  */
   190 static gboolean
   191 gmyth_uri_isabsolute (const GMythURI *uri)
   192 {
   193 	gboolean ret = FALSE;
   194 	
   195 	g_return_val_if_fail( uri != NULL && uri->uri != NULL && uri->protocol != NULL, FALSE );
   196 	
   197 	if ( gmyth_strstr( uri->uri->str, GMYTH_URI_PROTOCOL_DELIM ) == 0 || strlen(uri->protocol->str) > 0 )
   198 		ret = TRUE;
   199 		
   200 	return ret;	
   201 }
   202 
   203 /** 
   204  * Searches for the first reverse character occurrence, from a given 
   205  * list of characters, inside a given string.
   206  * 
   207  * @param str The given string to be searched for characters occurrence.
   208  * @param chars The characters list. If this string returns 4 on strlen, there are
   209  * 						  four possible characters to be matched.
   210  * @param nchars The number of characters to be matched, which has at most 
   211  * 							 strlen(chars).
   212  * 
   213  * @return The starting offset to the first character occurrence, 
   214  *         or <code>-1</code> if the no character of the list could be found.
   215  */
   216 static gint
   217 gmyth_strrchr( const gchar *str, const gchar *chars, const gint nchars )
   218 {
   219 
   220 	gint strLen;
   221 	gint i, j;
   222 	
   223 	if ( str == NULL || chars == NULL )
   224 		return -1;
   225 		
   226 	strLen = strlen( str );
   227 	for ( i= (strLen-1); 0 <= i; i-- ) {
   228 		for ( j=0; j<nchars; j++ ) {
   229 			if ( str[i] == chars[j] )
   230 				return i;
   231 		}
   232 	}
   233 
   234 	return -1;
   235 
   236 }
   237 
   238 static gchar*
   239 gmyth_uri_print_field( const GString* field )
   240 {
   241 	if ( field != NULL && field->str != NULL && strlen(field->str) > 0 )
   242 		return field->str;
   243 	else
   244 		return "";		
   245 }
   246 
   247 /** 
   248  * Parses a URI string into a GMythURI instance.
   249  * 
   250  * @param uri The GMythURI instance.
   251  * @param value The URI string to be parsed.
   252  *
   253  */
   254 static void
   255 gmyth_uri_parser_setup_and_new( GMythURI *uri, const gchar *value )
   256 {
   257 	
   258 	gint 		uriLen;
   259 	gint 		currIdx;
   260 	gint 		protoIdx;
   261 	gint 		atIdx;
   262 	gint 		colonIdx;
   263 	gint 		shashIdx;
   264 	gint 		eIdx;
   265 	gchar 	*host;
   266 	gint 		eblacketIdx;
   267 	gint 		hostLen;
   268 	gint 		sharpIdx;
   269 	/*
   270 	gint 		questionIdx;
   271 	gint 		queryLen;
   272 	*/
   273 	
   274 	uriLen = strlen(value);
   275 	uri->uri = g_string_new( g_strdup (value) );
   276 		
   277 	currIdx = 0;
   278 	
   279 	/*** Protocol ****/
   280 	protoIdx = gmyth_strstr (value, GMYTH_URI_PROTOCOL_DELIM);
   281 	if (0 < protoIdx) {
   282         uri->protocol = g_string_new_len (value, protoIdx);
   283 		currIdx += protoIdx + strlen( GMYTH_URI_PROTOCOL_DELIM );
   284 	}
   285 
   286 	/*** User (Password) ****/
   287 	atIdx = gmyth_strstr( value+currIdx, GMYTH_URI_USER_DELIM );
   288 	if ( 0 < atIdx ) {
   289 		colonIdx = gmyth_strstr( value+currIdx, GMYTH_URI_COLON_DELIM );
   290 
   291 		if (0 < colonIdx && colonIdx < atIdx) {
   292             uri->user = g_string_new_len (value+currIdx, colonIdx);
   293             uri->password = g_string_new_len (value+currIdx+colonIdx+1, atIdx - (colonIdx+1));
   294 		}
   295 		else
   296             uri->user = g_string_new_len (value+currIdx, atIdx - currIdx);
   297 		currIdx += atIdx + 1;
   298 	}
   299 
   300 	/*** Host (Port) ****/
   301 	shashIdx = gmyth_strstr( value+currIdx, GMYTH_URI_SLASH_DELIM );
   302 	if (0 < shashIdx)
   303         uri->host = g_string_new_len (value+currIdx, shashIdx);
   304 	else if ( gmyth_uri_isabsolute(uri) == TRUE )
   305         uri->host = g_string_new_len (value+currIdx, strlen (value) - currIdx);
   306 
   307 	host = gmyth_uri_get_host(uri);
   308 	colonIdx = gmyth_strrchr (host, GMYTH_URI_COLON_DELIM, 1);
   309 	eblacketIdx = gmyth_strrchr (host, GMYTH_URI_EBLACET_DELIM, 1);
   310 	if ( ( 0 < colonIdx ) && ( eblacketIdx < colonIdx ) ) {
   311         GString *portStr = NULL;
   312 		GString *hostStr = g_string_new  (host != NULL ? host : "");
   313 
   314 		hostLen = hostStr->len;
   315 		/**** host ****/
   316 		uri->host = g_string_erase (uri->host, 0, hostLen);
   317 		uri->host = g_string_insert_len (uri->host, 0, hostStr->str, colonIdx);
   318 		if (0 < hostLen) {
   319 			if (host[0] == '[' && host[hostLen-1] == ']')
   320                 uri->host = g_string_new_len (hostStr->str+1, colonIdx-2);
   321 		}
   322 		/**** port ****/
   323 		portStr = g_string_new_len (hostStr->str+colonIdx+1, hostLen-colonIdx-1);
   324 		uri->port = (gint)g_ascii_strtoull( portStr->str, NULL, 10 );
   325 		g_string_free (portStr, TRUE);
   326 		g_string_free (hostStr, TRUE);
   327 	}
   328 	else {
   329         const gchar* protocol = gmyth_uri_get_protocol(uri);
   330 		uri->port = GMYTH_URI_KNKOWN_PORT;
   331 		if ( strcmp(protocol, GMYTH_URI_PROTOCOL_HTTP) == 0 )
   332 			uri->port = GMYTH_URI_DEFAULT_HTTP_PORT;
   333 		if ( strcmp(protocol, GMYTH_URI_PROTOCOL_FTP) == 0 )
   334 			uri->port = GMYTH_URI_DEFAULT_FTP_PORT;
   335 	}
   336 	
   337 	if (shashIdx > 0) currIdx += shashIdx;
   338 	
   339 	/*
   340 		Handle relative URL
   341 	*/
   342 	if (gmyth_uri_isabsolute(uri) == FALSE)
   343 	{
   344 
   345 		if (shashIdx != 0)
   346 		{
   347 			/* Add slash delimiter at the beginning of the URL,
   348 			   if it doesn't exist 
   349 			*/
   350 			uri->path = g_string_new( GMYTH_URI_SLASH_DELIM );
   351 		}
   352 		uri->path = g_string_append( uri->path, value );
   353 		
   354 	} else {
   355 		/* First set path simply to the rest of URI */
   356 		uri->path = g_string_new_len (value+currIdx,  uriLen-currIdx );
   357 	}
   358 	
   359 	gmyth_debug( "uri value:  %s", value );
   360 	uri->query = g_string_new ( g_strstr_len( value, strlen(value), GMYTH_URI_QUESTION_DELIM ) );
   361 	
   362 	eIdx = gmyth_strstr( value+currIdx, GMYTH_URI_QUESTION_DELIM );
   363 	
   364 	if ( 0 < eIdx ) {
   365 		uri->query = g_string_new ( g_strstr_len( value, strlen(value), GMYTH_URI_QUESTION_DELIM ) );
   366 		gmyth_debug( "query = %s", uri->query->str );
   367 	}
   368 	
   369 	/**** Path (Query/Fragment) ****/
   370 	sharpIdx = gmyth_strstr(value+currIdx, GMYTH_URI_E_DELIM);
   371 	if (0 < sharpIdx) {
   372 		uri->path = g_string_append_len( uri->path, value+currIdx, sharpIdx);
   373 		uri->fragment = g_string_new_len (value+currIdx+sharpIdx+1, uriLen-(currIdx+sharpIdx+1));
   374 	}	
   375 
   376 	gmyth_debug( "[%s] GMythURI: host = %s, port = %d, path = %s, query = %s, fragment = %s, "\
   377 								"user = %s, password = %s.\n", __FUNCTION__, gmyth_uri_print_field( uri->host ), uri->port,
   378 													gmyth_uri_print_field( uri->path ), gmyth_uri_print_field( uri->query ), gmyth_uri_print_field( uri->fragment ),
   379 													gmyth_uri_print_field ( uri->user ), gmyth_uri_print_field( uri->password ) );
   380 
   381 }
   382 
   383 /** 
   384  * Compares 2 URI instances, and checks them for equality.
   385  * 
   386  * @param uri The first GMythURI instance for comparison.
   387  * @param uri The second GMythURI instance for comparison.
   388  * 
   389  * @return <code>true</code>, if these two URI instances are equals.
   390  */
   391 gboolean
   392 gmyth_uri_is_equals( GMythURI* uri1, GMythURI* uri2 )
   393 {
   394 	return ( g_ascii_strcasecmp( gmyth_uri_get_host( uri1 ), gmyth_uri_get_host( uri2 ) ) == 0 &&
   395 				gmyth_uri_get_port( uri1 ) == gmyth_uri_get_port( uri2 ) );
   396 }
   397 
   398 /** 
   399  * Checks if the URI instance represents a LiveTV recording.
   400  * 
   401  * @param uri The GMythURI instance.
   402  * 
   403  * @return <code>true</code>, if the URI points to LiveTV content.
   404  */
   405 gboolean
   406 gmyth_uri_is_livetv( GMythURI* uri )
   407 {
   408 	gboolean ret = FALSE;
   409 	
   410 	g_return_val_if_fail( uri != NULL && uri->uri != NULL && uri->uri->str != NULL, FALSE );
   411 	
   412 	ret = ( g_strstr_len( uri->uri->str, strlen( uri->uri->str ), "/?" ) != NULL ) ||
   413 				( g_strstr_len( uri->uri->str, strlen( uri->uri->str ), "livetv" ) != NULL );
   414 	
   415 	if ( ret )
   416 		gmyth_debug( "This URI is a LiveTV recording..." );
   417 	
   418 	return ret;
   419 	
   420 }
   421 
   422 /** 
   423  * Gets the channel name fro a URI instance.
   424  * 
   425  * @param uri The GMythURI instance.
   426  * 
   427  * @return The channel name, got from the substring "?channel=[channel_name]"
   428  * 				 of the URI string.
   429  */
   430 gchar*
   431 gmyth_uri_get_channel_name( GMythURI* uri )
   432 {
   433 	gchar* channel = NULL;
   434 	
   435 	g_return_val_if_fail( uri != NULL && uri->uri != NULL && uri->uri->str != NULL, FALSE );
   436 	
   437 	gchar *channel_query = g_strstr_len( gmyth_uri_get_query( uri ), strlen( gmyth_uri_get_query( uri ) ), "channel" );
   438 	
   439 	if ( channel_query != NULL )
   440 	{
   441 		gchar **chan_key_value = g_strsplit( gmyth_uri_get_query( uri ), "=", 2 );
   442 		
   443 		/* gmyth_debug( "Channel tuple is [ %s, %s ]", chan_key_value[0], chan_key_value[1] ); */
   444 
   445 		if ( chan_key_value[1] != NULL && strlen( chan_key_value[1] ) > 0 )
   446 		{
   447 			channel = g_strdup( chan_key_value[1] ); 
   448 		}
   449 
   450 		if ( chan_key_value != NULL )		
   451 			g_strfreev( chan_key_value );
   452 	}
   453 	
   454 	gmyth_debug( "Got channel decimal value from the URI: %s", channel );
   455 
   456 	return channel;
   457 	
   458 }
   459 
   460 /** 
   461  * Gets the channel number from a URI instance.
   462  * 
   463  * @param uri The GMythURI instance.
   464  * 
   465  * @return The channel number, got from the substring "?channel=[channel_number]"
   466  * 				 of the URI string, or <code>-1</code> it if couldn't be converted.
   467  */
   468 gint
   469 gmyth_uri_get_channel_num( GMythURI* uri )
   470 {
   471 	gchar *channel_name = gmyth_uri_get_channel_name( uri );
   472 	
   473 	if ( channel_name != NULL )
   474 	{
   475 		return g_ascii_strtoull( channel_name, NULL, 10 ); 
   476 	}
   477 	
   478 	return -1;
   479 	
   480 }