1 /*****************************************************************************
2 * xurl.c: URL manipulation functions
3 *****************************************************************************
4 * Copyright (C) 2003-2004 Commonwealth Scientific and Industrial Research
5 * Organisation (CSIRO) Australia
6 * Copyright (C) 2004-2008 the VideoLAN team
10 * Authors: Andre Pang <Andre.Pang@csiro.au>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25 *****************************************************************************/
34 static char *streallocat( char *psz_string, const char *psz_to_append );
36 char *XURL_FindQuery ( char *psz_url );
37 static char *XURL_FindHostname ( char *psz_url );
38 static char *XURL_FindPath ( char *psz_url );
39 static char *XURL_FindFragment ( char *psz_url );
42 char *XURL_Join( char *psz_url1, char *psz_url2 )
44 if( XURL_IsAbsolute( psz_url1 ) )
45 return XURL_Concat( psz_url1, psz_url2 );
47 return XURL_Concat( psz_url2, psz_url1 );
50 /* TODO: replace XURL_Concat's rel/absolute calculation with the one
51 * specified by RFC2396, and also test it on their test suite :) */
54 char *XURL_Concat( char *psz_url, char *psz_append )
56 char *psz_return_value = NULL;
58 if( XURL_IsAbsolute( psz_append ) )
59 return strdup( psz_append );
61 if( XURL_IsAbsolute( psz_url ) )
63 if( XURL_HasAbsolutePath( psz_append ) )
67 psz_concat_url = XURL_GetSchemeAndHostname( psz_url );
69 psz_concat_url = streallocat( psz_concat_url, psz_append );
71 fprintf( stderr, "XURL_Concat: concat is \"%s\"\n",
74 psz_return_value = psz_concat_url;
78 /* psz_append is a relative URL */
81 /* strip off last path component */
82 psz_new_url = XURL_GetHead( psz_url );
83 psz_new_url = streallocat( psz_new_url, psz_append );
85 psz_return_value = psz_new_url;
90 /* not an absolute URL */
91 if( XURL_HasAbsolutePath( psz_append ) == false )
93 char *psz_new_url = XURL_GetHead( psz_url );
95 psz_new_url = streallocat( psz_new_url, psz_append );
96 psz_return_value = psz_new_url;
100 /* URL to append has an absolute path -- just use that instead */
101 psz_return_value = strdup( psz_append );
105 return psz_return_value;
109 bool XURL_IsAbsolute( char *psz_url )
111 if( XURL_FindHostname( psz_url ) == NULL )
114 fprintf( stderr, "XURL_IsAbsolute(%s) returning false\n", psz_url );
121 fprintf( stderr, "XURL_IsAbsolute(%s) returning true\n", psz_url );
128 bool XURL_HasFragment( char *psz_url )
130 if( XURL_FindFragment( psz_url ) == NULL )
137 char *XURL_FindHostname( char *psz_url )
139 char *psz_return_value = NULL;
141 char *psz_scheme_separator = strstr( psz_url, "://" );
142 if( psz_scheme_separator != NULL)
144 char *psz_hostname = psz_scheme_separator + strlen( "://" );
145 if( *psz_hostname != '\0')
146 psz_return_value = psz_hostname;
149 fprintf( stderr, "XURL_FindHostname(%s): returning \"%s\"\n",
150 psz_url, psz_return_value );
154 return psz_return_value;
158 bool XURL_HasAbsolutePath( char *psz_url )
160 #ifdef XURL_WIN32_PATHING
161 if( psz_url[0] == '/' || psz_url[0] == '\\' )
163 if( psz_url[0] == '/' )
171 char *XURL_GetHostname( char *psz_url )
173 char *psz_return_value = NULL;
174 char *psz_hostname = XURL_FindHostname( psz_url );
176 if( psz_hostname != NULL )
178 char *psz_new_hostname;
179 size_t i_hostname_length;
181 char *psz_one_past_end_of_hostname = strchr( psz_hostname, '/' );
182 if( psz_one_past_end_of_hostname != NULL)
184 /* Found a '/' after the hostname, so copy characters between
185 * the hostname and the '/' to a new string */
186 i_hostname_length = psz_one_past_end_of_hostname -
191 /* Didn't find a '/', so copy from the start of the hostname
192 * until the end of the string */
193 i_hostname_length = strlen( psz_url ) - ( psz_hostname - psz_url );
196 /* Copy hostname to a new string */
197 psz_new_hostname = malloc( i_hostname_length );
198 if( psz_new_hostname == NULL )
200 strncpy( psz_new_hostname, psz_hostname, i_hostname_length );
203 fprintf (stderr, "XURL_GetHostname: psz_new_hostname is \"%s\"\n",
206 psz_return_value = psz_new_hostname;
210 /* Didn't find a hostname */
214 return psz_return_value;
218 char *XURL_GetSchemeAndHostname( char *psz_url )
220 char *psz_scheme = NULL,
221 *psz_hostname = NULL,
222 *psz_scheme_and_hostname = NULL;
224 psz_scheme = XURL_GetScheme( psz_url );
225 psz_hostname = XURL_GetHostname( psz_url );
226 if( psz_hostname && psz_scheme )
228 if( asprintf( &psz_scheme_and_hostname, "%s://%s", psz_scheme, psz_hostname ) == -1)
229 psz_scheme_and_hostname = NULL;
232 free( psz_hostname );
234 return psz_scheme_and_hostname;
237 static char *XURL_FindFragment( char *psz_url )
239 char *pc_hash = NULL;
240 char *pc_return_value = NULL;
242 pc_hash = strchr( psz_url, '#' );
243 if( pc_hash != NULL )
244 pc_return_value = pc_hash;
246 return pc_return_value;
249 char *XURL_FindQuery( char *psz_url )
251 char *pc_question_mark = NULL;
252 char *pc_return_value = NULL;
254 pc_question_mark = strchr( psz_url, '?' );
255 if( pc_question_mark != NULL )
256 pc_return_value = pc_question_mark;
258 return pc_return_value;
262 char *XURL_GetScheme( char *psz_url )
265 size_t i_scheme_length;
268 if( XURL_IsAbsolute( psz_url ) == false )
269 return strdup( "file" );
271 /* this strchr will always succeed since we have an absolute URL, and thus
273 psz_colon = strchr( psz_url, ':' );
275 i_scheme_length = psz_colon - psz_url;
277 new_scheme = malloc( i_scheme_length );
278 if( new_scheme == NULL )
281 strncpy( new_scheme, psz_url, i_scheme_length );
286 bool XURL_IsFileURL( char *psz_url )
289 char *psz_scheme = XURL_GetScheme( psz_url );
291 if( strcasecmp( psz_scheme, "file" ) == 0 )
292 b_return_value = true;
294 b_return_value = false;
298 return b_return_value;
302 static char *XURL_FindPath( char *psz_url )
304 if( XURL_IsAbsolute( psz_url ) )
306 char *psz_start_of_hostname = XURL_FindHostname( psz_url );
307 if( psz_start_of_hostname != NULL )
308 return strchr( psz_start_of_hostname, '/' );
314 if( XURL_HasAbsolutePath( psz_url ) == true )
322 char *XURL_GetPath( char *psz_url )
324 char *psz_return_value = NULL;
325 char *psz_path = NULL;
326 char *pc_question_mark = NULL;
327 char *pc_fragment = NULL;
329 psz_path = strdup( XURL_FindPath( psz_url ) );
331 fprintf( stderr, "XURL_GetPath: XURL_FindPath returning \"%s\"\n",
334 psz_return_value = psz_path;
336 pc_question_mark = XURL_FindQuery( psz_path );
337 if( pc_question_mark != NULL )
339 int i_path_length = pc_question_mark - psz_path;
340 *( psz_path + i_path_length ) = '\0';
343 pc_fragment = XURL_FindFragment( psz_path );
344 if( pc_fragment != NULL )
347 fprintf( stderr, "XURL_GetPath: XURL_FindFragment returned \"%s\"\n",
350 int i_path_length = pc_fragment - psz_path;
351 *( psz_path + i_path_length ) = '\0';
355 fprintf( stderr, "XURL_GetPath returning \"%s\"\n", psz_return_value );
358 return psz_return_value;
362 char *XURL_GetHead( const char *psz_path )
367 /* kill everything up to the last / (including the /) */
368 #ifdef XURL_WIN32_PATHING
369 /* Windows: Try looking for a \ first; if we don't find one, look for / */
370 pc_last_slash = strrchr( psz_path, '\\' );
371 if( pc_last_slash == NULL )
372 pc_last_slash = strrchr( psz_path, '/' );
374 pc_last_slash = strrchr( psz_path, '/' );
376 if( pc_last_slash == NULL )
378 psz_path_head = strdup( psz_path );
382 size_t i_characters_until_last_slash;
384 i_characters_until_last_slash = pc_last_slash - psz_path;
385 psz_path_head = xmalloc( i_characters_until_last_slash + 1 );
386 strncpy( psz_path_head, psz_path, i_characters_until_last_slash + 1 );
388 /* terminate the resulting string with '\0' */
390 i_characters_until_last_slash) = '\0';
393 /* append a trailing / */
394 streallocat( psz_path_head, "/" );
396 return psz_path_head;
400 char *XURL_GetWithoutFragment( char *psz_url )
402 char *psz_return_value = NULL;
405 psz_fragment = XURL_FindFragment( psz_url );
406 if( psz_fragment == NULL )
408 psz_return_value = strdup( psz_url );
412 size_t i_pre_fragment_length;
413 char *psz_without_fragment;
415 i_pre_fragment_length = psz_fragment - psz_url;
417 psz_without_fragment = malloc( i_pre_fragment_length + 1 );
418 if( psz_without_fragment == NULL )
420 psz_return_value = NULL;
424 memcpy( psz_without_fragment, psz_url, i_pre_fragment_length );
425 *( psz_without_fragment + i_pre_fragment_length ) = '\0';
426 psz_return_value = psz_without_fragment;
430 return psz_return_value;
433 static char *streallocat( char *psz_string, const char *psz_to_append )
435 size_t i_new_string_length = strlen( psz_string ) +
436 strlen( psz_to_append ) + 1;
438 psz_string = xrealloc( psz_string, i_new_string_length );
440 return strcat( psz_string, psz_to_append );