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 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, char *psz_to_append );
37 static char *xurl_strdup( const char *psz_string );
39 #define xurl_strdup strdup
42 char *XURL_FindQuery ( char *psz_url );
43 static char *XURL_FindHostname ( char *psz_url );
44 static char *XURL_FindPath ( char *psz_url );
45 static char *XURL_FindFragment ( char *psz_url );
48 char *XURL_Join( char *psz_url1, char *psz_url2 )
50 if( XURL_IsAbsolute( psz_url1 ) )
51 return XURL_Concat( psz_url1, psz_url2 );
53 return XURL_Concat( psz_url2, psz_url1 );
58 /* TODO: replace XURL_Concat's rel/absolute calculation with the one
59 * specified by RFC2396, and also test it on their test suite :) */
62 char *XURL_Concat( char *psz_url, char *psz_append )
64 char *psz_return_value = NULL;
66 if( XURL_IsAbsolute( psz_append ) == XURL_TRUE )
67 return strdup( psz_append );
69 if( XURL_IsAbsolute( psz_url ) )
71 if( XURL_HasAbsolutePath( psz_append ) )
75 psz_concat_url = XURL_GetSchemeAndHostname( psz_url );
77 psz_concat_url = streallocat( psz_concat_url, psz_append );
79 fprintf( stderr, "XURL_Concat: concat is \"%s\"\n",
82 psz_return_value = psz_concat_url;
86 /* psz_append is a relative URL */
89 /* strip off last path component */
90 psz_new_url = XURL_GetHead( psz_url );
91 psz_new_url = streallocat( psz_new_url, psz_append );
93 psz_return_value = psz_new_url;
98 /* not an absolute URL */
99 if( XURL_HasAbsolutePath( psz_append ) == XURL_FALSE )
101 char *psz_new_url = XURL_GetHead( psz_url );
103 psz_new_url = streallocat( psz_new_url, psz_append );
104 psz_return_value = psz_new_url;
108 /* URL to append has an absolute path -- just use that instead */
109 psz_return_value = xurl_strdup( psz_append );
113 return psz_return_value;
117 XURL_Bool XURL_IsAbsolute( char *psz_url )
119 if( XURL_FindHostname( psz_url ) == NULL )
122 fprintf( stderr, "XURL_IsAbsolute(%s) returning false\n", psz_url );
129 fprintf( stderr, "XURL_IsAbsolute(%s) returning true\n", psz_url );
136 XURL_Bool XURL_HasFragment( char *psz_url )
138 if( XURL_FindFragment( psz_url ) == NULL )
145 char *XURL_FindHostname( char *psz_url )
147 char *psz_return_value = NULL;
149 char *psz_scheme_separator = strstr( psz_url, "://" );
150 if( psz_scheme_separator != NULL)
152 char *psz_hostname = psz_scheme_separator + strlen( "://" );
153 if( *psz_hostname != '\0') psz_return_value = psz_hostname;
156 fprintf( stderr, "XURL_FindHostname(%s): returning \"%s\"\n",
157 psz_url, psz_return_value );
161 return psz_return_value;
165 XURL_Bool XURL_HasAbsolutePath( char *psz_url )
167 #ifdef XURL_WIN32_PATHING
168 if( psz_url[0] == '/' || psz_url[0] == '\\' )
170 if( psz_url[0] == '/' )
178 char *XURL_GetHostname( char *psz_url )
180 char *psz_return_value = NULL;
181 char *psz_hostname = XURL_FindHostname( psz_url );
183 if( psz_hostname != NULL )
185 char *psz_new_hostname;
186 size_t i_hostname_length;
188 char *psz_one_past_end_of_hostname = strchr( psz_hostname, '/' );
189 if( psz_one_past_end_of_hostname != NULL)
191 /* Found a '/' after the hostname, so copy characters between
192 * the hostname and the '/' to a new string */
193 i_hostname_length = psz_one_past_end_of_hostname -
198 /* Didn't find a '/', so copy from the start of the hostname
199 * until the end of the string */
200 i_hostname_length = strlen( psz_url ) - ( psz_hostname - psz_url );
203 /* Copy hostname to a new string */
204 psz_new_hostname = xurl_malloc( i_hostname_length );
205 if (psz_new_hostname == NULL) return NULL;
206 strncpy( psz_new_hostname, psz_hostname, i_hostname_length );
209 fprintf (stderr, "XURL_GetHostname: psz_new_hostname is \"%s\"\n",
212 psz_return_value = psz_new_hostname;
216 /* Didn't find a hostname */
220 return psz_return_value;
224 char *XURL_GetSchemeAndHostname( char *psz_url )
226 char *psz_scheme, *psz_hostname, *psz_scheme_and_hostname;
228 psz_scheme = XURL_GetScheme( psz_url );
229 if( psz_scheme == NULL ) return NULL;
231 psz_hostname = XURL_GetHostname( psz_url );
232 if( psz_hostname == NULL ) return NULL;
234 /* malloc +1 for the terminating '\0' */
235 psz_scheme_and_hostname = xurl_malloc(
236 strlen( psz_scheme ) + strlen( "://" ) +
237 strlen( psz_hostname ) + 1);
238 if( psz_scheme_and_hostname == NULL ) return NULL;
239 (void) strcpy( psz_scheme_and_hostname, psz_scheme );
240 (void) strcat( psz_scheme_and_hostname, "://" );
241 (void) strcat( psz_scheme_and_hostname, psz_hostname );
243 if (psz_scheme_and_hostname == NULL ) return NULL;
244 return psz_scheme_and_hostname;
248 char *XURL_FindFragment( char *psz_url )
250 char *pc_hash = NULL;
251 char *pc_return_value = NULL;
253 pc_hash = strchr( psz_url, '#' );
254 if( pc_hash != NULL )
256 pc_return_value = pc_hash;
259 return pc_return_value;
262 char *XURL_FindQuery( char *psz_url )
264 char *pc_question_mark = NULL;
265 char *pc_return_value = NULL;
267 pc_question_mark = strchr( psz_url, '?' );
268 if( pc_question_mark != NULL )
270 pc_return_value = pc_question_mark;
273 return pc_return_value;
277 char *XURL_GetScheme( char *psz_url )
280 size_t i_scheme_length;
283 if( XURL_IsAbsolute( psz_url ) == XURL_FALSE ) return strdup( "file" );
285 /* this strchr will always succeed since we have an absolute URL, and thus
287 psz_colon = strchr( psz_url, ':' );
289 i_scheme_length = psz_colon - psz_url;
291 new_scheme = xurl_malloc( i_scheme_length );
292 if( new_scheme == NULL ) return NULL;
294 strncpy( new_scheme, psz_url, i_scheme_length );
300 XURL_Bool XURL_IsFileURL( char *psz_url )
302 XURL_Bool b_return_value;
303 char *psz_scheme = XURL_GetScheme( psz_url );
305 if( strcasecmp( psz_scheme, "file" ) == 0 )
306 b_return_value = XURL_TRUE;
308 b_return_value = XURL_FALSE;
310 xurl_free( psz_scheme );
312 return b_return_value;
317 char *xurl_strdup( const char *psz_string )
320 char *psz_new_string;
322 if( !psz_string ) return NULL;
324 i_length = strlen( psz_string ) + 1;
325 psz_new_string = (char *) xurl_malloc( i_length );
326 if( psz_new_string == NULL ) return NULL;
328 memcpy( psz_new_string, psz_string, i_length );
330 return psz_new_string;
335 char *XURL_FindPath( char *psz_url )
337 char *psz_return_value = NULL;
339 if( XURL_IsAbsolute( psz_url ) == XURL_TRUE )
341 char *psz_start_of_hostname = XURL_FindHostname( psz_url );
342 if( psz_start_of_hostname != NULL )
344 char *psz_start_of_path = strchr( psz_start_of_hostname, '/' );
345 psz_return_value = psz_start_of_path;
350 if( XURL_HasAbsolutePath( psz_url ) == XURL_TRUE )
352 psz_return_value = psz_url;
356 return xurl_strdup (".");
360 return psz_return_value;
364 char *XURL_GetPath( char *psz_url )
366 char *psz_return_value = NULL;
367 char *psz_path = NULL;
368 char *pc_question_mark = NULL;
369 char *pc_fragment = NULL;
371 psz_path = xurl_strdup( XURL_FindPath( psz_url ) );
373 fprintf( stderr, "XURL_GetPath: XURL_FindPath returning \"%s\"\n",
376 psz_return_value = psz_path;
378 pc_question_mark = XURL_FindQuery( psz_path );
379 if( pc_question_mark != NULL )
381 int i_path_length = pc_question_mark - psz_path;
382 *( psz_path + i_path_length ) = '\0';
385 pc_fragment = XURL_FindFragment( psz_path );
386 if( pc_fragment != NULL )
389 fprintf( stderr, "XURL_GetPath: XURL_FindFragment returned \"%s\"\n",
392 int i_path_length = pc_fragment - psz_path;
393 *( psz_path + i_path_length ) = '\0';
397 fprintf( stderr, "XURL_GetPath returning \"%s\"\n", psz_return_value );
400 return psz_return_value;
404 char *XURL_GetHead( const char *psz_path )
409 /* kill everything up to the last / (including the /) */
410 #ifdef XURL_WIN32_PATHING
411 /* Windows: Try looking for a \ first; if we don't find one, look for / */
412 pc_last_slash = strrchr( psz_path, '\\' );
413 if( pc_last_slash == NULL )
414 pc_last_slash = strrchr( psz_path, '/' );
416 pc_last_slash = strrchr( psz_path, '/' );
418 if( pc_last_slash == NULL )
420 psz_path_head = xurl_strdup( psz_path );
424 size_t i_characters_until_last_slash;
426 i_characters_until_last_slash = pc_last_slash - psz_path;
427 psz_path_head = malloc(
428 ( i_characters_until_last_slash + 1 ) * sizeof(char) );
429 (void) strncpy( psz_path_head, psz_path,
430 i_characters_until_last_slash + 1 );
432 /* terminate the resulting string with '\0' */
434 i_characters_until_last_slash) = '\0';
437 /* append a trailing / */
438 streallocat( psz_path_head, "/" );
440 return psz_path_head;
444 char *XURL_GetWithoutFragment( char *psz_url )
446 char *psz_return_value = NULL;
449 psz_fragment = XURL_FindFragment( psz_url );
450 if( psz_fragment == NULL )
452 psz_return_value = xurl_strdup( psz_url );
456 size_t i_pre_fragment_length;
457 char *psz_without_fragment;
459 i_pre_fragment_length = psz_fragment - psz_url;
461 psz_without_fragment = xurl_malloc( i_pre_fragment_length + 1 );
462 if( psz_without_fragment == NULL )
464 psz_return_value = NULL;
468 memcpy( psz_without_fragment, psz_url, i_pre_fragment_length );
469 *( psz_without_fragment + i_pre_fragment_length ) = '\0';
470 psz_return_value = psz_without_fragment;
474 return psz_return_value;
478 char *streallocat( char *psz_string, char *psz_to_append )
480 size_t i_new_string_length = strlen( psz_string ) +
481 strlen( psz_to_append ) + 1;
483 psz_string = (char *) realloc( psz_string, i_new_string_length );
485 return strcat( psz_string, psz_to_append );