1 /*****************************************************************************
2 * strings.c: String related functions
3 *****************************************************************************
4 * Copyright (C) 2006 the VideoLAN team
7 * Authors: Antoine Cellerier <dionoea at videolan dot org>
8 * Daniel Stranger <vlc at schmaller dot de>
9 * RĂ©mi Denis-Courmont <rem # videolan org>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
26 /*****************************************************************************
28 *****************************************************************************/
35 /* Needed by str_format_time */
38 /* Needed by str_format_meta */
39 #include <vlc_input.h>
41 #include <vlc_playlist.h>
44 #include <vlc_strings.h>
46 #include <vlc_charset.h>
49 * Unescape URI encoded string
50 * \return decoded duplicated string
52 char *unescape_URI_duplicate( const char *psz )
54 char *psz_dup = strdup( psz );
55 unescape_URI( psz_dup );
60 * Unescape URI encoded string in place
63 void unescape_URI( char *psz )
65 unsigned char *in = (unsigned char *)psz, *out = in, c;
67 while( ( c = *in++ ) != '\0' )
73 char val[5], *pval = val;
83 if( ( *pval++ = *in++ ) == '\0' )
85 if( ( *pval++ = *in++ ) == '\0' )
91 if( ( *pval++ = *in++ ) == '\0' )
96 cp = strtoul( val, NULL, 0x10 );
102 *out++ = (( cp >> 6) | 0xc0);
103 *out++ = (( cp & 0x3f) | 0x80);
107 assert( cp < 0x10000 );
108 *out++ = (( cp >> 12) | 0xe0);
109 *out++ = (((cp >> 6) & 0x3f) | 0x80);
110 *out++ = (( cp & 0x3f) | 0x80);
115 /* + is not a special case - it means plus, not space. */
118 /* Inserting non-ASCII or non-printable characters is unsafe,
119 * and no sane browser will send these unencoded */
120 if( ( c < 32 ) || ( c > 127 ) )
130 * Decode encoded URI string
131 * \return decoded duplicated string
133 char *decode_URI_duplicate( const char *psz )
135 char *psz_dup = strdup( psz );
136 decode_URI( psz_dup );
141 * Decode encoded URI string in place
144 void decode_URI( char *psz )
146 unsigned char *in = (unsigned char *)psz, *out = in, c;
148 while( ( c = *in++ ) != '\0' )
156 if( ( ( hex[0] = *in++ ) == 0 )
157 || ( ( hex[1] = *in++ ) == 0 ) )
161 *out++ = (unsigned char)strtoul( hex, NULL, 0x10 );
170 /* Inserting non-ASCII or non-printable characters is unsafe,
171 * and no sane browser will send these unencoded */
172 if( ( c < 32 ) || ( c > 127 ) )
182 static inline int isurlsafe( int c )
184 return ( (unsigned char)( c - 'a' ) < 26 )
185 || ( (unsigned char)( c - 'A' ) < 26 )
186 || ( (unsigned char)( c - '0' ) < 10 )
187 /* Hmm, we should not encode character that are allowed in URLs
188 * (even if they are not URL-safe), nor URL-safe characters.
189 * We still encode some of them because of Microsoft's crap browser.
191 || ( strchr( "-_.", c ) != NULL );
194 static inline char url_hexchar( int c )
196 return ( c < 10 ) ? c + '0' : c + 'A' - 10;
200 * encode_URI_component
201 * Encodes an URI component.
203 * @param psz_url nul-terminated UTF-8 representation of the component.
204 * Obviously, you can't pass an URI containing a nul character, but you don't
205 * want to do that, do you?
207 * @return encoded string (must be free()'d)
209 char *encode_URI_component( const char *psz_url )
211 char psz_enc[3 * strlen( psz_url ) + 1], *out = psz_enc;
214 for( in = (const uint8_t *)psz_url; *in; in++ )
226 *out++ = url_hexchar( c >> 4 );
227 *out++ = url_hexchar( c & 0xf );
232 return strdup( psz_enc );
236 * Converts "<", ">" and "&" to "<", ">" and "&"
237 * \param string to convert
239 void resolve_xml_special_chars( char *psz_value )
241 char *p_pos = psz_value;
245 if( !strncmp( psz_value, "<", 4 ) )
250 else if( !strncmp( psz_value, ">", 4 ) )
255 else if( !strncmp( psz_value, "&", 5 ) )
260 else if( !strncmp( psz_value, """, 6 ) )
265 else if( !strncmp( psz_value, "'", 6 ) )
283 * Converts '<', '>', '\"', '\'' and '&' to their html entities
284 * \param psz_content simple element content that is to be converted
286 char *convert_xml_special_chars( const char *psz_content )
288 char *psz_temp = malloc( 6 * strlen( psz_content ) + 1 );
289 const char *p_from = psz_content;
290 char *p_to = psz_temp;
294 if ( *p_from == '<' )
296 strcpy( p_to, "<" );
299 else if ( *p_from == '>' )
301 strcpy( p_to, ">" );
304 else if ( *p_from == '&' )
306 strcpy( p_to, "&" );
309 else if( *p_from == '\"' )
311 strcpy( p_to, """ );
314 else if( *p_from == '\'' )
316 strcpy( p_to, "'" );
331 /****************************************************************************
332 * String formating functions
333 ****************************************************************************/
334 char *str_format_time( const char *tformat )
338 #if defined(HAVE_LOCALTIME_R)
344 /* Get the current time. */
345 curtime = time( NULL );
347 /* Convert it to local time representation. */
348 #if defined(HAVE_LOCALTIME_R)
349 localtime_r( &curtime, &loctime );
350 strftime( buffer, 255, tformat, &loctime );
352 loctime = localtime( &curtime );
353 strftime( buffer, 255, tformat, loctime );
355 return strdup( buffer );
358 #define INSERT_STRING( check, string ) \
359 if( check && string ) \
361 int len = strlen( string ); \
362 dst = realloc( dst, \
363 i_size = i_size + len + 1 ); \
364 strncpy( d, string, len+1 ); \
372 char *__str_format_meta( vlc_object_t *p_object, const char *string )
374 const char *s = string;
375 char *dst = malloc( 1000 );
379 int i_size = strlen( string );
381 playlist_t *p_playlist = pl_Yield( p_object );
382 input_thread_t *p_input = p_playlist->p_input;
383 input_item_t *p_item = NULL;
384 pl_Release( p_object );
387 vlc_object_yield( p_input );
388 p_item = input_GetItem(p_input);
390 vlc_mutex_lock( &p_item->lock );
393 sprintf( dst, string );
402 INSERT_STRING( p_item && p_item->p_meta,
403 p_item->p_meta->psz_artist );
406 INSERT_STRING( p_item && p_item->p_meta,
407 p_item->p_meta->psz_album );
410 INSERT_STRING( p_item && p_item->p_meta,
411 p_item->p_meta->psz_copyright );
414 INSERT_STRING( p_item && p_item->p_meta,
415 p_item->p_meta->psz_description );
418 INSERT_STRING( p_item && p_item->p_meta,
419 p_item->p_meta->psz_encodedby );
422 INSERT_STRING( p_item && p_item->p_meta,
423 p_item->p_meta->psz_genre );
426 INSERT_STRING( p_item && p_item->p_meta,
427 p_item->p_meta->psz_language );
430 INSERT_STRING( p_item && p_item->p_meta,
431 p_item->p_meta->psz_tracknum );
434 INSERT_STRING( p_item && p_item->p_meta,
435 p_item->p_meta->psz_nowplaying );
438 INSERT_STRING( p_item && p_item->p_meta,
439 p_item->p_meta->psz_rating );
446 lang = var_GetString( p_input, "sub-language" );
450 lang = strdup( "-" );
452 INSERT_STRING( 1, lang );
457 INSERT_STRING( p_item && p_item->p_meta,
458 p_item->p_meta->psz_title );
461 INSERT_STRING( p_item && p_item->p_meta,
462 p_item->p_meta->psz_url );
465 INSERT_STRING( p_item && p_item->p_meta,
466 p_item->p_meta->psz_date );
471 snprintf( buf, 10, "%d",
472 var_GetInteger( p_input, "bit-rate" )/1000 );
478 INSERT_STRING( 1, buf );
483 snprintf( buf, 10, "%d",
484 var_GetInteger( p_input, "chapter" ) );
490 INSERT_STRING( 1, buf );
495 sprintf( buf, "%02d:%02d:%02d",
496 (int)(p_item->i_duration/(3600000000)),
497 (int)((p_item->i_duration/(60000000))%60),
498 (int)((p_item->i_duration/1000000)%60) );
502 sprintf( buf, "--:--:--" );
504 INSERT_STRING( 1, buf );
507 INSERT_STRING( p_item, p_item->psz_uri );
512 snprintf( buf, 10, "%d",
513 var_GetInteger( p_input, "title" ) );
519 INSERT_STRING( 1, buf );
522 if( p_item && p_input )
524 sprintf( buf, "%02d:%02d:%02d",
525 (int)((p_item->i_duration-p_input->i_time)/(3600000000)),
526 (int)(((p_item->i_duration-p_input->i_time)/(60000000))%60),
527 (int)(((p_item->i_duration-p_input->i_time)/1000000)%60) );
531 sprintf( buf, "--:--:--" );
533 INSERT_STRING( 1, buf );
536 INSERT_STRING( p_item, p_item->psz_name );
543 lang = var_GetString( p_input, "audio-language" );
547 lang = strdup( "-" );
549 INSERT_STRING( 1, lang );
556 snprintf( buf, 10, "%2.1lf",
557 var_GetFloat( p_input, "position" ) * 100. );
561 sprintf( buf, "--.-%%" );
563 INSERT_STRING( 1, buf );
568 int r = var_GetInteger( p_input, "rate" );
569 snprintf( buf, 10, "%d.%d", r/1000, r%1000 );
575 INSERT_STRING( 1, buf );
580 int r = var_GetInteger( p_input, "sample-rate" );
581 snprintf( buf, 10, "%d.%d", r/1000, (r/100)%10 );
587 INSERT_STRING( 1, buf );
592 sprintf( buf, "%02d:%02d:%02d",
593 (int)(p_input->i_time/(3600000000)),
594 (int)((p_input->i_time/(60000000))%60),
595 (int)((p_input->i_time/1000000)%60) );
599 sprintf( buf, "--:--:--" );
601 INSERT_STRING( 1, buf );
604 INSERT_STRING( p_item && p_item->p_meta,
605 p_item->p_meta->psz_publisher );
609 audio_volume_t volume;
610 aout_VolumeGet( p_object, &volume );
611 snprintf( buf, 10, "%d", volume );
612 INSERT_STRING( 1, buf );
642 vlc_object_release( p_input );
644 vlc_mutex_unlock( &p_item->lock );
651 * Apply str format time and str format meta
653 char *__str_format( vlc_object_t *p_this, const char *psz_src )
655 char *psz_buf1, *psz_buf2;
656 psz_buf1 = str_format_time( psz_src );
657 psz_buf2 = str_format_meta( p_this, psz_buf1 );
663 * Remove forbidden characters from filenames (including slashes)
665 void filename_sanitize( char *str )
690 * Remove forbidden characters from full paths (leaves slashes)
692 void path_sanitize( char *str )