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