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 *****************************************************************************/
33 #include <vlc_memory.h>
37 static char *streallocat( char *psz_string, const char *psz_to_append );
39 char *XURL_FindQuery ( char *psz_url );
40 static char *XURL_FindHostname ( char *psz_url );
41 static char *XURL_FindPath ( char *psz_url );
42 static char *XURL_FindFragment ( char *psz_url );
45 char *XURL_Join( char *psz_url1, char *psz_url2 )
47 if( XURL_IsAbsolute( psz_url1 ) )
48 return XURL_Concat( psz_url1, psz_url2 );
50 return XURL_Concat( psz_url2, psz_url1 );
53 /* TODO: replace XURL_Concat's rel/absolute calculation with the one
54 * specified by RFC2396, and also test it on their test suite :) */
57 char *XURL_Concat( char *psz_url, char *psz_append )
59 char *psz_return_value = NULL;
61 if( XURL_IsAbsolute( psz_append ) )
62 return strdup( psz_append );
64 if( XURL_IsAbsolute( psz_url ) )
66 if( XURL_HasAbsolutePath( psz_append ) )
70 psz_concat_url = XURL_GetSchemeAndHostname( psz_url );
72 psz_concat_url = streallocat( psz_concat_url, psz_append );
74 fprintf( stderr, "XURL_Concat: concat is \"%s\"\n",
77 psz_return_value = psz_concat_url;
81 /* psz_append is a relative URL */
84 /* strip off last path component */
85 psz_new_url = XURL_GetHead( psz_url );
86 psz_new_url = streallocat( psz_new_url, psz_append );
88 psz_return_value = psz_new_url;
93 /* not an absolute URL */
94 if( XURL_HasAbsolutePath( psz_append ) == false )
96 char *psz_new_url = XURL_GetHead( psz_url );
98 psz_new_url = streallocat( psz_new_url, psz_append );
99 psz_return_value = psz_new_url;
103 /* URL to append has an absolute path -- just use that instead */
104 psz_return_value = strdup( psz_append );
108 return psz_return_value;
112 bool XURL_IsAbsolute( char *psz_url )
114 if( XURL_FindHostname( psz_url ) == NULL )
117 fprintf( stderr, "XURL_IsAbsolute(%s) returning false\n", psz_url );
124 fprintf( stderr, "XURL_IsAbsolute(%s) returning true\n", psz_url );
131 bool XURL_HasFragment( char *psz_url )
133 if( XURL_FindFragment( psz_url ) == NULL )
140 char *XURL_FindHostname( char *psz_url )
142 char *psz_return_value = NULL;
144 char *psz_scheme_separator = strstr( psz_url, "://" );
145 if( psz_scheme_separator != NULL)
147 char *psz_hostname = psz_scheme_separator + strlen( "://" );
148 if( *psz_hostname != '\0')
149 psz_return_value = psz_hostname;
152 fprintf( stderr, "XURL_FindHostname(%s): returning \"%s\"\n",
153 psz_url, psz_return_value );
157 return psz_return_value;
161 bool XURL_HasAbsolutePath( char *psz_url )
163 #ifdef XURL_WIN32_PATHING
164 if( psz_url[0] == '/' || psz_url[0] == '\\' )
166 if( psz_url[0] == '/' )
174 char *XURL_GetHostname( char *psz_url )
176 char *psz_return_value = NULL;
177 char *psz_hostname = XURL_FindHostname( psz_url );
179 if( psz_hostname != NULL )
181 char *psz_new_hostname;
182 size_t i_hostname_length;
184 char *psz_one_past_end_of_hostname = strchr( psz_hostname, '/' );
185 if( psz_one_past_end_of_hostname != NULL)
187 /* Found a '/' after the hostname, so copy characters between
188 * the hostname and the '/' to a new string */
189 i_hostname_length = psz_one_past_end_of_hostname -
194 /* Didn't find a '/', so copy from the start of the hostname
195 * until the end of the string */
196 i_hostname_length = strlen( psz_url ) - ( psz_hostname - psz_url );
199 /* Copy hostname to a new string */
200 psz_new_hostname = malloc( i_hostname_length );
201 if( psz_new_hostname == NULL )
203 strncpy( psz_new_hostname, psz_hostname, i_hostname_length );
206 fprintf (stderr, "XURL_GetHostname: psz_new_hostname is \"%s\"\n",
209 psz_return_value = psz_new_hostname;
213 /* Didn't find a hostname */
217 return psz_return_value;
221 char *XURL_GetSchemeAndHostname( char *psz_url )
223 char *psz_scheme = NULL,
224 *psz_hostname = NULL,
225 *psz_scheme_and_hostname = NULL;
227 psz_scheme = XURL_GetScheme( psz_url );
228 psz_hostname = XURL_GetHostname( psz_url );
229 if( psz_hostname && psz_scheme )
231 if( asprintf( &psz_scheme_and_hostname, "%s://%s", psz_scheme, psz_hostname ) == -1)
232 psz_scheme_and_hostname = NULL;
235 free( psz_hostname );
237 return psz_scheme_and_hostname;
240 static char *XURL_FindFragment( char *psz_url )
242 char *pc_hash = NULL;
243 char *pc_return_value = NULL;
245 pc_hash = strchr( psz_url, '#' );
246 if( pc_hash != NULL )
247 pc_return_value = pc_hash;
249 return pc_return_value;
252 char *XURL_FindQuery( char *psz_url )
254 char *pc_question_mark = NULL;
255 char *pc_return_value = NULL;
257 pc_question_mark = strchr( psz_url, '?' );
258 if( pc_question_mark != NULL )
259 pc_return_value = pc_question_mark;
261 return pc_return_value;
265 char *XURL_GetScheme( char *psz_url )
268 size_t i_scheme_length;
271 if( XURL_IsAbsolute( psz_url ) == false )
272 return strdup( "file" );
274 /* this strchr will always succeed since we have an absolute URL, and thus
276 psz_colon = strchr( psz_url, ':' );
278 i_scheme_length = psz_colon - psz_url;
280 new_scheme = malloc( i_scheme_length );
281 if( new_scheme == NULL )
284 strncpy( new_scheme, psz_url, i_scheme_length );
289 bool XURL_IsFileURL( char *psz_url )
292 char *psz_scheme = XURL_GetScheme( psz_url );
294 if( strcasecmp( psz_scheme, "file" ) == 0 )
295 b_return_value = true;
297 b_return_value = false;
301 return b_return_value;
305 static char *XURL_FindPath( char *psz_url )
307 if( XURL_IsAbsolute( psz_url ) )
309 char *psz_start_of_hostname = XURL_FindHostname( psz_url );
310 if( psz_start_of_hostname != NULL )
311 return strchr( psz_start_of_hostname, '/' );
317 if( XURL_HasAbsolutePath( psz_url ) == true )
325 char *XURL_GetPath( char *psz_url )
327 char *psz_return_value = NULL;
328 char *psz_path = NULL;
329 char *pc_question_mark = NULL;
330 char *pc_fragment = NULL;
332 psz_path = strdup( XURL_FindPath( psz_url ) );
334 fprintf( stderr, "XURL_GetPath: XURL_FindPath returning \"%s\"\n",
337 psz_return_value = psz_path;
339 pc_question_mark = XURL_FindQuery( psz_path );
340 if( pc_question_mark != NULL )
342 int i_path_length = pc_question_mark - psz_path;
343 *( psz_path + i_path_length ) = '\0';
346 pc_fragment = XURL_FindFragment( psz_path );
347 if( pc_fragment != NULL )
350 fprintf( stderr, "XURL_GetPath: XURL_FindFragment returned \"%s\"\n",
353 int i_path_length = pc_fragment - psz_path;
354 *( psz_path + i_path_length ) = '\0';
358 fprintf( stderr, "XURL_GetPath returning \"%s\"\n", psz_return_value );
361 return psz_return_value;
365 char *XURL_GetHead( const char *psz_path )
370 /* kill everything up to the last / (including the /) */
371 #ifdef XURL_WIN32_PATHING
372 /* Windows: Try looking for a \ first; if we don't find one, look for / */
373 pc_last_slash = strrchr( psz_path, '\\' );
374 if( pc_last_slash == NULL )
375 pc_last_slash = strrchr( psz_path, '/' );
377 pc_last_slash = strrchr( psz_path, '/' );
379 if( pc_last_slash == NULL )
381 psz_path_head = strdup( psz_path );
385 size_t i_characters_until_last_slash;
387 i_characters_until_last_slash = pc_last_slash - psz_path;
388 psz_path_head = malloc( i_characters_until_last_slash + 1 );
389 assert( psz_path_head );
390 strncpy( psz_path_head, psz_path, i_characters_until_last_slash + 1 );
392 /* terminate the resulting string with '\0' */
394 i_characters_until_last_slash) = '\0';
397 /* append a trailing / */
398 streallocat( psz_path_head, "/" );
400 return psz_path_head;
404 char *XURL_GetWithoutFragment( char *psz_url )
406 char *psz_return_value = NULL;
409 psz_fragment = XURL_FindFragment( psz_url );
410 if( psz_fragment == NULL )
412 psz_return_value = strdup( psz_url );
416 size_t i_pre_fragment_length;
417 char *psz_without_fragment;
419 i_pre_fragment_length = psz_fragment - psz_url;
421 psz_without_fragment = malloc( i_pre_fragment_length + 1 );
422 if( psz_without_fragment == NULL )
424 psz_return_value = NULL;
428 memcpy( psz_without_fragment, psz_url, i_pre_fragment_length );
429 *( psz_without_fragment + i_pre_fragment_length ) = '\0';
430 psz_return_value = psz_without_fragment;
434 return psz_return_value;
437 static char *streallocat( char *psz_string, const char *psz_to_append )
439 size_t i_new_string_length = strlen( psz_string ) +
440 strlen( psz_to_append ) + 1;
442 psz_string = realloc_or_free( psz_string, i_new_string_length );
443 assert( psz_string );
445 return strcat( psz_string, psz_to_append );