]> git.sesse.net Git - vlc/blob - modules/codec/cmml/xurl.c
bad1ecad1e44eeb469ea85a737959cb6d396ccf5
[vlc] / modules / codec / cmml / xurl.c
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
7  *
8  * $Id$
9  *
10  * Authors: Andre Pang <Andre.Pang@csiro.au>
11  *
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.
16  *
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.
21  *
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  *****************************************************************************/
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <stdio.h>
31
32 #include "xurl.h"
33
34 static char *streallocat( char *psz_string, char *psz_to_append );
35
36 #ifndef HAVE_STRDUP
37 static char *xurl_strdup( const char *psz_string );
38 #else
39 #define xurl_strdup strdup
40 #endif
41
42 static char *XURL_FindHostname          ( char *psz_url );
43 static char *XURL_FindPath              ( char *psz_url );
44 static char *XURL_FindFragment          ( char *psz_url );
45
46
47 char *XURL_Join( char *psz_url1, char *psz_url2 )
48 {
49     if( XURL_IsAbsolute( psz_url1 ) )
50         return XURL_Concat( psz_url1, psz_url2 );
51     else
52         return XURL_Concat( psz_url2, psz_url1 );
53
54     return NULL;
55 }
56
57 /* TODO: replace XURL_Concat's rel/absolute calculation with the one
58  * specified by RFC2396, and also test it on their test suite :) */
59
60
61 char *XURL_Concat( char *psz_url, char *psz_append )
62 {
63     char *psz_return_value = NULL;
64
65     if( XURL_IsAbsolute( psz_append ) == XURL_TRUE )
66         return strdup( psz_append );
67
68     if( XURL_IsAbsolute( psz_url ) )
69     {
70         if( XURL_HasAbsolutePath( psz_append ) )
71         {
72             char *psz_concat_url;
73
74             psz_concat_url = XURL_GetSchemeAndHostname( psz_url );
75
76             psz_concat_url = streallocat( psz_concat_url, psz_append );
77 #ifdef XURL_DEBUG
78             fprintf( stderr, "XURL_Concat: concat is \"%s\"\n",
79                      psz_concat_url );
80 #endif
81             psz_return_value = psz_concat_url;
82         }
83         else
84         {
85             /* psz_append is a relative URL */
86             char *psz_new_url;
87  
88             /* strip off last path component */
89             psz_new_url = XURL_GetHead( psz_url );
90             psz_new_url = streallocat( psz_new_url, psz_append );
91
92             psz_return_value = psz_new_url;
93         }
94     }
95     else
96     {
97         /* not an absolute URL */
98         if( XURL_HasAbsolutePath( psz_append ) == XURL_FALSE )
99         {
100             char *psz_new_url = XURL_GetHead( psz_url );
101
102             psz_new_url = streallocat( psz_new_url, psz_append );
103             psz_return_value = psz_new_url;
104         }
105         else
106         {
107             /* URL to append has an absolute path -- just use that instead */
108             psz_return_value = xurl_strdup( psz_append );
109         }
110     }
111
112     return psz_return_value;
113 }
114
115
116 XURL_Bool XURL_IsAbsolute( char *psz_url )
117 {
118     if( XURL_FindHostname( psz_url ) == NULL )
119     {
120 #ifdef XURL_DEBUG
121         fprintf( stderr, "XURL_IsAbsolute(%s) returning false\n", psz_url );
122 #endif
123         return XURL_FALSE;
124     }
125     else
126     {
127 #ifdef XURL_DEBUG
128         fprintf( stderr, "XURL_IsAbsolute(%s) returning true\n", psz_url );
129 #endif
130         return XURL_TRUE;
131     }
132 }
133
134
135 XURL_Bool XURL_HasFragment( char *psz_url )
136 {
137     if( XURL_FindFragment( psz_url ) == NULL )
138         return XURL_FALSE;
139     else
140         return XURL_TRUE;
141 }
142
143
144 char *XURL_FindHostname( char *psz_url )
145 {
146     char *psz_return_value = NULL;
147
148     char *psz_scheme_separator = strstr( psz_url, "://" );
149     if( psz_scheme_separator != NULL)
150     {
151         char *psz_hostname = psz_scheme_separator + strlen( "://" );
152         if( *psz_hostname != '\0') psz_return_value = psz_hostname;
153
154 #ifdef XURL_DEBUG
155         fprintf( stderr, "XURL_FindHostname(%s): returning \"%s\"\n",
156                  psz_url, psz_return_value );
157 #endif
158     }
159
160     return psz_return_value;
161 }
162
163
164 XURL_Bool XURL_HasAbsolutePath( char *psz_url )
165 {
166 #ifdef XURL_WIN32_PATHING
167     if( psz_url[0] == '/' || psz_url[0] == '\\' )
168 #else
169     if( psz_url[0] == '/' )
170 #endif
171         return XURL_TRUE;
172     else
173         return XURL_FALSE;
174 }
175
176
177 char *XURL_GetHostname( char *psz_url )
178 {
179     char *psz_return_value = NULL;
180     char *psz_hostname = XURL_FindHostname( psz_url );
181
182     if( psz_hostname != NULL )
183     {
184         char *psz_new_hostname;
185         size_t i_hostname_length;
186
187         char *psz_one_past_end_of_hostname = strchr( psz_hostname, '/' );
188         if( psz_one_past_end_of_hostname != NULL)
189         {
190             /* Found a '/' after the hostname, so copy characters between
191              * the hostname and the '/' to a new string */
192             i_hostname_length = psz_one_past_end_of_hostname -
193                 psz_hostname;
194         }
195         else
196         {
197             /* Didn't find a '/', so copy from the start of the hostname
198              * until the end of the string */
199             i_hostname_length = strlen( psz_url ) - ( psz_hostname - psz_url );
200         }
201
202         /* Copy hostname to a new string */
203         psz_new_hostname = xurl_malloc( i_hostname_length );
204         if (psz_new_hostname == NULL) return NULL;
205         strncpy( psz_new_hostname, psz_hostname, i_hostname_length );
206
207 #ifdef XURL_DEBUG
208         fprintf (stderr, "XURL_GetHostname: psz_new_hostname is \"%s\"\n",
209                  psz_new_hostname );
210 #endif
211         psz_return_value = psz_new_hostname;
212     }
213     else
214     {
215         /* Didn't find a hostname */
216         return NULL;
217     }
218
219     return psz_return_value;
220 }
221
222
223 char *XURL_GetSchemeAndHostname( char *psz_url )
224 {
225     char *psz_scheme, *psz_hostname, *psz_scheme_and_hostname;
226
227     psz_scheme = XURL_GetScheme( psz_url );
228     if( psz_scheme == NULL ) return NULL;
229
230     psz_hostname = XURL_GetHostname( psz_url );
231     if( psz_hostname == NULL ) return NULL;
232
233     /* malloc +1 for the terminating '\0' */
234     psz_scheme_and_hostname = xurl_malloc(
235             strlen( psz_scheme ) + strlen( "://" ) +
236             strlen( psz_hostname ) + 1);
237     if( psz_scheme_and_hostname == NULL ) return NULL;
238     (void) strcpy( psz_scheme_and_hostname, psz_scheme );
239     (void) strcat( psz_scheme_and_hostname, "://" );
240     (void) strcat( psz_scheme_and_hostname, psz_hostname );
241
242     if (psz_scheme_and_hostname == NULL ) return NULL;
243     return psz_scheme_and_hostname;
244 }
245
246 static
247 char *XURL_FindFragment( char *psz_url )
248 {
249     char *pc_hash = NULL;
250     char *pc_return_value = NULL;
251  
252     pc_hash = strchr( psz_url, '#' );
253     if( pc_hash != NULL )
254     {
255         pc_return_value = pc_hash;
256     }
257
258     return pc_return_value;
259 }
260
261
262 char *XURL_FindQuery( char *psz_url )
263 {
264     char *pc_question_mark = NULL;
265     char *pc_return_value = NULL;
266  
267     pc_question_mark = strchr( psz_url, '?' );
268     if( pc_question_mark != NULL )
269     {
270         pc_return_value = pc_question_mark;
271     }
272
273     return pc_return_value;
274 }
275
276
277 char *XURL_GetScheme( char *psz_url )
278 {
279     char *psz_colon;
280     size_t i_scheme_length;
281     char *new_scheme;
282
283     if( XURL_IsAbsolute( psz_url ) == XURL_FALSE ) return strdup( "file" );
284
285     /* this strchr will always succeed since we have an absolute URL, and thus
286      * a scheme */
287     psz_colon = strchr( psz_url, ':' );
288
289     i_scheme_length = psz_colon - psz_url;
290
291     new_scheme = xurl_malloc( i_scheme_length );
292     if( new_scheme == NULL ) return NULL;
293
294     strncpy( new_scheme, psz_url, i_scheme_length );
295
296     return new_scheme;
297 }
298
299
300 XURL_Bool XURL_IsFileURL( char *psz_url )
301 {
302     XURL_Bool b_return_value;
303     char *psz_scheme = XURL_GetScheme( psz_url );
304
305     if( strcasecmp( psz_scheme, "file" ) == 0 )
306         b_return_value = XURL_TRUE;
307     else
308         b_return_value = XURL_FALSE;
309
310     xurl_free( psz_scheme );
311
312     return b_return_value;
313 }
314
315 #ifndef HAVE_STRDUP
316 static
317 char *xurl_strdup( const char *psz_string )
318 {
319     size_t i_length;
320     char *psz_new_string;
321
322     if( !psz_string ) return NULL;
323  
324     i_length = strlen( psz_string ) + 1;
325     psz_new_string = (char *) xurl_malloc( i_length );
326     if( psz_new_string == NULL ) return NULL;
327
328     memcpy( psz_new_string, psz_string, i_length );
329
330     return psz_new_string;
331 }
332 #endif
333
334 static
335 char *XURL_FindPath( char *psz_url )
336 {
337     char *psz_return_value = NULL;
338
339     if( XURL_IsAbsolute( psz_url ) == XURL_TRUE )
340     {
341         char *psz_start_of_hostname = XURL_FindHostname( psz_url );
342         if( psz_start_of_hostname != NULL )
343         {
344             char *psz_start_of_path = strchr( psz_start_of_hostname, '/' );
345             psz_return_value = psz_start_of_path;
346         }
347     }
348     else
349     {
350         if( XURL_HasAbsolutePath( psz_url ) == XURL_TRUE )
351         {
352             psz_return_value = psz_url;
353         }
354         else
355         {
356             return xurl_strdup (".");
357         }
358     }
359
360     return psz_return_value;
361 }
362
363
364 char *XURL_GetPath( char *psz_url )
365 {
366     char *psz_return_value = NULL;
367     char *psz_path = NULL;
368     char *pc_question_mark = NULL;
369     char *pc_fragment = NULL;
370
371     psz_path = xurl_strdup( XURL_FindPath( psz_url ) );
372 #ifdef XURL_DEBUG
373     fprintf( stderr, "XURL_GetPath: XURL_FindPath returning \"%s\"\n",
374              psz_path );
375 #endif
376     psz_return_value = psz_path;
377
378     pc_question_mark = XURL_FindQuery( psz_path );
379     if( pc_question_mark != NULL )
380     {
381         int i_path_length = pc_question_mark - psz_path;
382         *( psz_path + i_path_length ) = '\0';
383     }
384
385     pc_fragment = XURL_FindFragment( psz_path );
386     if( pc_fragment != NULL )
387     {
388 #ifdef XURL_DEBUG
389         fprintf( stderr, "XURL_GetPath: XURL_FindFragment returned \"%s\"\n",
390                  pc_fragment );
391 #endif
392         int i_path_length = pc_fragment - psz_path;
393         *( psz_path + i_path_length ) = '\0';
394     }
395
396 #ifdef XURL_DEBUG
397     fprintf( stderr, "XURL_GetPath returning \"%s\"\n", psz_return_value );
398 #endif
399
400     return psz_return_value;
401 }
402
403
404 char *XURL_GetHead( const char *psz_path )
405 {
406     char *psz_path_head;
407     char *pc_last_slash;
408
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, '/' );
415 #else
416     pc_last_slash = strrchr( psz_path, '/' );
417 #endif
418     if( pc_last_slash == NULL )
419     {
420         psz_path_head = xurl_strdup( psz_path );
421     }
422     else
423     {
424         size_t i_characters_until_last_slash;
425
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 );
431
432         /* terminate the resulting string with '\0' */
433         *(psz_path_head +
434                 i_characters_until_last_slash) = '\0';
435     }
436
437     /* append a trailing / */
438     streallocat( psz_path_head, "/" );
439
440     return psz_path_head;
441 }
442
443
444 char *XURL_GetWithoutFragment( char *psz_url )
445 {
446     char *psz_return_value = NULL;
447     char *psz_fragment;
448
449     psz_fragment = XURL_FindFragment( psz_url );
450     if( psz_fragment == NULL )
451     {
452         psz_return_value = xurl_strdup( psz_url );
453     }
454     else
455     {
456         size_t i_pre_fragment_length;
457         char *psz_without_fragment;
458
459         i_pre_fragment_length = psz_fragment - psz_url;
460
461         psz_without_fragment = xurl_malloc( i_pre_fragment_length + 1 );
462         if( psz_without_fragment == NULL )
463         {
464             psz_return_value = NULL;
465         }
466         else
467         {
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;
471         }
472     }
473  
474     return psz_return_value;
475 }
476
477 static
478 char *streallocat( char *psz_string, char *psz_to_append )
479 {
480     size_t i_new_string_length = strlen( psz_string ) +
481         strlen( psz_to_append ) + 1;
482
483     psz_string = (char *) realloc( psz_string, i_new_string_length );
484  
485     return strcat( psz_string, psz_to_append );
486 }
487