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;
69 while( ( c = *in++ ) != '\0' )
75 char val[5], *pval = val;
85 if( ( *pval++ = *in++ ) == '\0' )
87 if( ( *pval++ = *in++ ) == '\0' )
93 if( ( *pval++ = *in++ ) == '\0' )
98 cp = strtoul( val, NULL, 0x10 );
104 *out++ = (( cp >> 6) | 0xc0);
105 *out++ = (( cp & 0x3f) | 0x80);
109 assert( cp < 0x10000 );
110 *out++ = (( cp >> 12) | 0xe0);
111 *out++ = (((cp >> 6) & 0x3f) | 0x80);
112 *out++ = (( cp & 0x3f) | 0x80);
117 /* + is not a special case - it means plus, not space. */
120 /* Inserting non-ASCII or non-printable characters is unsafe,
121 * and no sane browser will send these unencoded */
122 if( ( c < 32 ) || ( c > 127 ) )
132 * Decode encoded URI string
133 * \return decoded duplicated string
135 char *decode_URI_duplicate( const char *psz )
137 char *psz_dup = strdup( psz );
138 decode_URI( psz_dup );
143 * Decode encoded URI string in place
146 void decode_URI( char *psz )
148 unsigned char *in = (unsigned char *)psz, *out = in, c;
152 while( ( c = *in++ ) != '\0' )
160 if( ( ( hex[0] = *in++ ) == 0 )
161 || ( ( hex[1] = *in++ ) == 0 ) )
165 *out++ = (unsigned char)strtoul( hex, NULL, 0x10 );
174 /* Inserting non-ASCII or non-printable characters is unsafe,
175 * and no sane browser will send these unencoded */
176 if( ( c < 32 ) || ( c > 127 ) )
186 static inline int isurlsafe( int c )
188 return ( (unsigned char)( c - 'a' ) < 26 )
189 || ( (unsigned char)( c - 'A' ) < 26 )
190 || ( (unsigned char)( c - '0' ) < 10 )
191 /* Hmm, we should not encode character that are allowed in URLs
192 * (even if they are not URL-safe), nor URL-safe characters.
193 * We still encode some of them because of Microsoft's crap browser.
195 || ( strchr( "-_.", c ) != NULL );
198 static inline char url_hexchar( int c )
200 return ( c < 10 ) ? c + '0' : c + 'A' - 10;
204 * encode_URI_component
205 * Encodes an URI component.
207 * @param psz_url nul-terminated UTF-8 representation of the component.
208 * Obviously, you can't pass an URI containing a nul character, but you don't
209 * want to do that, do you?
211 * @return encoded string (must be free()'d)
213 char *encode_URI_component( const char *psz_url )
215 char psz_enc[3 * strlen( psz_url ) + 1], *out = psz_enc;
218 for( in = (const uint8_t *)psz_url; *in; in++ )
230 *out++ = url_hexchar( c >> 4 );
231 *out++ = url_hexchar( c & 0xf );
236 return strdup( psz_enc );
240 * Converts "<", ">" and "&" to "<", ">" and "&"
241 * \param string to convert
243 void resolve_xml_special_chars( char *psz_value )
245 char *p_pos = psz_value;
249 if( !strncmp( psz_value, "<", 4 ) )
254 else if( !strncmp( psz_value, ">", 4 ) )
259 else if( !strncmp( psz_value, "&", 5 ) )
264 else if( !strncmp( psz_value, """, 6 ) )
269 else if( !strncmp( psz_value, "'", 6 ) )
287 * Converts '<', '>', '\"', '\'' and '&' to their html entities
288 * \param psz_content simple element content that is to be converted
290 char *convert_xml_special_chars( const char *psz_content )
292 char *psz_temp = malloc( 6 * strlen( psz_content ) + 1 );
293 const char *p_from = psz_content;
294 char *p_to = psz_temp;
298 if ( *p_from == '<' )
300 strcpy( p_to, "<" );
303 else if ( *p_from == '>' )
305 strcpy( p_to, ">" );
308 else if ( *p_from == '&' )
310 strcpy( p_to, "&" );
313 else if( *p_from == '\"' )
315 strcpy( p_to, """ );
318 else if( *p_from == '\'' )
320 strcpy( p_to, "'" );
335 /* Base64 encoding */
336 char *vlc_b64_encode_binary( const uint8_t *src, size_t i_src )
338 static const char b64[] =
339 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
341 char *ret = malloc( ( i_src + 4 ) * 4 / 3 );
349 /* pops (up to) 3 bytes of input, push 4 bytes */
354 *dst++ = b64[v >> 26];
360 *dst++ = b64[v >> 26];
365 v |= *src++ << 20; // 3/3
366 *dst++ = ( i_src >= 2 ) ? b64[v >> 26] : '='; // 3/4
370 *dst++ = ( i_src >= 3 ) ? b64[v >> 26] : '='; // 4/4
382 char *vlc_b64_encode( const char *src )
385 return vlc_b64_encode_binary( (const uint8_t*)src, strlen(src) );
387 return vlc_b64_encode_binary( (const uint8_t*)"", 0 );
390 /* Base64 decoding */
391 size_t vlc_b64_decode_binary_to_buffer( uint8_t *p_dst, size_t i_dst, const char *p_src )
393 static const int b64[256] = {
394 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 00-0F */
395 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 10-1F */
396 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, /* 20-2F */
397 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1, /* 30-3F */
398 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, /* 40-4F */
399 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, /* 50-5F */
400 -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, /* 60-6F */
401 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, /* 70-7F */
402 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 80-8F */
403 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 90-9F */
404 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* A0-AF */
405 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* B0-BF */
406 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* C0-CF */
407 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* D0-DF */
408 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* E0-EF */
409 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 /* F0-FF */
411 uint8_t *p_start = p_dst;
412 uint8_t *p = (uint8_t *)p_src;
417 for( i_level = 0, i_last = 0; i_dst > 0 && *p != '\0'; i_dst--, p++ )
419 const int c = b64[(unsigned int)*p];
429 *p_dst++ = ( i_last << 2 ) | ( ( c >> 4)&0x03 );
433 *p_dst++ = ( ( i_last << 4 )&0xf0 ) | ( ( c >> 2 )&0x0f );
437 *p_dst++ = ( ( i_last &0x03 ) << 6 ) | c;
443 return p_dst - p_start;
445 size_t vlc_b64_decode_binary( uint8_t **pp_dst, const char *psz_src )
447 const int i_src = strlen( psz_src );
450 *pp_dst = p_dst = malloc( i_src );
453 return vlc_b64_decode_binary_to_buffer( p_dst, i_src, psz_src );
455 char *vlc_b64_decode( const char *psz_src )
457 const int i_src = strlen( psz_src );
458 char *p_dst = malloc( i_src + 1 );
463 i_dst = vlc_b64_decode_binary_to_buffer( (uint8_t*)p_dst, i_src, psz_src );
469 /****************************************************************************
470 * String formating functions
471 ****************************************************************************/
472 char *str_format_time( const char *tformat )
476 #if defined(HAVE_LOCALTIME_R)
482 /* Get the current time. */
483 curtime = time( NULL );
485 /* Convert it to local time representation. */
486 #if defined(HAVE_LOCALTIME_R)
487 localtime_r( &curtime, &loctime );
488 strftime( buffer, 255, tformat, &loctime );
490 loctime = localtime( &curtime );
491 strftime( buffer, 255, tformat, loctime );
493 return strdup( buffer );
496 #define INSERT_STRING( check, string ) \
497 if( check && string ) \
499 int len = strlen( string ); \
500 dst = realloc( dst, \
501 i_size = i_size + len + 1 ); \
502 strncpy( d, string, len+1 ); \
510 char *__str_format_meta( vlc_object_t *p_object, const char *string )
512 const char *s = string;
513 char *dst = malloc( 1000 );
517 int i_size = strlen( string );
519 playlist_t *p_playlist = pl_Yield( p_object );
520 input_thread_t *p_input = p_playlist->p_input;
521 input_item_t *p_item = NULL;
522 pl_Release( p_object );
525 vlc_object_yield( p_input );
526 p_item = input_GetItem(p_input);
528 vlc_mutex_lock( &p_item->lock );
531 sprintf( dst, string );
540 INSERT_STRING( p_item && p_item->p_meta,
541 p_item->p_meta->psz_artist );
544 INSERT_STRING( p_item && p_item->p_meta,
545 p_item->p_meta->psz_album );
548 INSERT_STRING( p_item && p_item->p_meta,
549 p_item->p_meta->psz_copyright );
552 INSERT_STRING( p_item && p_item->p_meta,
553 p_item->p_meta->psz_description );
556 INSERT_STRING( p_item && p_item->p_meta,
557 p_item->p_meta->psz_encodedby );
560 INSERT_STRING( p_item && p_item->p_meta,
561 p_item->p_meta->psz_genre );
564 INSERT_STRING( p_item && p_item->p_meta,
565 p_item->p_meta->psz_language );
568 INSERT_STRING( p_item && p_item->p_meta,
569 p_item->p_meta->psz_tracknum );
572 INSERT_STRING( p_item && p_item->p_meta,
573 p_item->p_meta->psz_nowplaying );
576 INSERT_STRING( p_item && p_item->p_meta,
577 p_item->p_meta->psz_rating );
584 lang = var_GetString( p_input, "sub-language" );
588 lang = strdup( "-" );
590 INSERT_STRING( 1, lang );
595 INSERT_STRING( p_item && p_item->p_meta,
596 p_item->p_meta->psz_title );
599 INSERT_STRING( p_item && p_item->p_meta,
600 p_item->p_meta->psz_url );
603 INSERT_STRING( p_item && p_item->p_meta,
604 p_item->p_meta->psz_date );
609 snprintf( buf, 10, "%d",
610 var_GetInteger( p_input, "bit-rate" )/1000 );
616 INSERT_STRING( 1, buf );
621 snprintf( buf, 10, "%d",
622 var_GetInteger( p_input, "chapter" ) );
628 INSERT_STRING( 1, buf );
633 sprintf( buf, "%02d:%02d:%02d",
634 (int)(p_item->i_duration/(3600000000)),
635 (int)((p_item->i_duration/(60000000))%60),
636 (int)((p_item->i_duration/1000000)%60) );
640 sprintf( buf, "--:--:--" );
642 INSERT_STRING( 1, buf );
645 INSERT_STRING( p_item, p_item->psz_uri );
650 snprintf( buf, 10, "%d",
651 var_GetInteger( p_input, "title" ) );
657 INSERT_STRING( 1, buf );
660 if( p_item && p_input )
662 sprintf( buf, "%02d:%02d:%02d",
663 (int)((p_item->i_duration-p_input->i_time)/(3600000000)),
664 (int)(((p_item->i_duration-p_input->i_time)/(60000000))%60),
665 (int)(((p_item->i_duration-p_input->i_time)/1000000)%60) );
669 sprintf( buf, "--:--:--" );
671 INSERT_STRING( 1, buf );
674 INSERT_STRING( p_item, p_item->psz_name );
681 lang = var_GetString( p_input, "audio-language" );
685 lang = strdup( "-" );
687 INSERT_STRING( 1, lang );
694 snprintf( buf, 10, "%2.1lf",
695 var_GetFloat( p_input, "position" ) * 100. );
699 sprintf( buf, "--.-%%" );
701 INSERT_STRING( 1, buf );
706 int r = var_GetInteger( p_input, "rate" );
707 snprintf( buf, 10, "%d.%d", r/1000, r%1000 );
713 INSERT_STRING( 1, buf );
718 int r = var_GetInteger( p_input, "sample-rate" );
719 snprintf( buf, 10, "%d.%d", r/1000, (r/100)%10 );
725 INSERT_STRING( 1, buf );
730 sprintf( buf, "%02d:%02d:%02d",
731 (int)(p_input->i_time/(3600000000)),
732 (int)((p_input->i_time/(60000000))%60),
733 (int)((p_input->i_time/1000000)%60) );
737 sprintf( buf, "--:--:--" );
739 INSERT_STRING( 1, buf );
742 INSERT_STRING( p_item && p_item->p_meta,
743 p_item->p_meta->psz_publisher );
747 audio_volume_t volume;
748 aout_VolumeGet( p_object, &volume );
749 snprintf( buf, 10, "%d", volume );
750 INSERT_STRING( 1, buf );
780 vlc_object_release( p_input );
782 vlc_mutex_unlock( &p_item->lock );
789 * Apply str format time and str format meta
791 char *__str_format( vlc_object_t *p_this, const char *psz_src )
793 char *psz_buf1, *psz_buf2;
794 psz_buf1 = str_format_time( psz_src );
795 psz_buf2 = str_format_meta( p_this, psz_buf1 );
801 * Remove forbidden characters from filenames (including slashes)
803 void filename_sanitize( char *str )
805 if( *str == '.' && (str[1] == '\0' || (str[1] == '.' && str[2] == '\0' ) ) )
837 * Remove forbidden characters from full paths (leaves slashes)
839 void path_sanitize( char *str )
843 * Uncomment the two blocks to prevent /../ or /./, i'm not sure that we
846 char *prev = str - 1;
849 /* check drive prefix if path is absolute */
850 if( isalpha(*str) && (':' == *(str+1)) )
875 if( str - prev == 2 && prev[1] == '.' )
879 else if( str - prev == 3 && prev[1] == '.' && prev[2] == '.' )