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 /* Base64 encoding */
332 char *vlc_b64_encode_binary( const uint8_t *src, size_t i_src )
334 static const char b64[] =
335 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
337 char *ret = malloc( ( i_src + 4 ) * 4 / 3 );
345 /* pops (up to) 3 bytes of input, push 4 bytes */
350 *dst++ = b64[v >> 26];
356 *dst++ = b64[v >> 26];
361 v |= *src++ << 20; // 3/3
362 *dst++ = ( i_src >= 2 ) ? b64[v >> 26] : '='; // 3/4
366 *dst++ = ( i_src >= 3 ) ? b64[v >> 26] : '='; // 4/4
378 char *vlc_b64_encode( const char *src )
381 return vlc_b64_encode_binary( (const uint8_t*)src, strlen(src) );
383 return vlc_b64_encode_binary( (const uint8_t*)"", 0 );
386 /* Base64 decoding */
387 size_t vlc_b64_decode_binary_to_buffer( uint8_t *p_dst, size_t i_dst, const char *p_src )
389 static const int b64[256] = {
390 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 00-0F */
391 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 10-1F */
392 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, /* 20-2F */
393 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1, /* 30-3F */
394 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, /* 40-4F */
395 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, /* 50-5F */
396 -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, /* 60-6F */
397 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, /* 70-7F */
398 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 80-8F */
399 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 90-9F */
400 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* A0-AF */
401 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* B0-BF */
402 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* C0-CF */
403 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* D0-DF */
404 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* E0-EF */
405 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 /* F0-FF */
407 uint8_t *p_start = p_dst;
408 uint8_t *p = (uint8_t *)p_src;
413 for( i_level = 0, i_last = 0; i_dst > 0 && *p != '\0'; i_dst--, p++ )
415 const int c = b64[(unsigned int)*p];
425 *p_dst++ = ( i_last << 2 ) | ( ( c >> 4)&0x03 );
429 *p_dst++ = ( ( i_last << 4 )&0xf0 ) | ( ( c >> 2 )&0x0f );
433 *p_dst++ = ( ( i_last &0x03 ) << 6 ) | c;
439 return p_dst - p_start;
441 size_t vlc_b64_decode_binary( uint8_t **pp_dst, const char *psz_src )
443 const int i_src = strlen( psz_src );
446 *pp_dst = p_dst = malloc( i_src );
449 return vlc_b64_decode_binary_to_buffer( p_dst, i_src, psz_src );
451 char *vlc_b64_decode( const char *psz_src )
453 const int i_src = strlen( psz_src );
454 char *p_dst = malloc( i_src + 1 );
459 i_dst = vlc_b64_decode_binary_to_buffer( (uint8_t*)p_dst, i_src, psz_src );
465 /****************************************************************************
466 * String formating functions
467 ****************************************************************************/
468 char *str_format_time( const char *tformat )
472 #if defined(HAVE_LOCALTIME_R)
478 /* Get the current time. */
479 curtime = time( NULL );
481 /* Convert it to local time representation. */
482 #if defined(HAVE_LOCALTIME_R)
483 localtime_r( &curtime, &loctime );
484 strftime( buffer, 255, tformat, &loctime );
486 loctime = localtime( &curtime );
487 strftime( buffer, 255, tformat, loctime );
489 return strdup( buffer );
492 #define INSERT_STRING( check, string ) \
493 if( check && string ) \
495 int len = strlen( string ); \
496 dst = realloc( dst, \
497 i_size = i_size + len + 1 ); \
498 strncpy( d, string, len+1 ); \
506 char *__str_format_meta( vlc_object_t *p_object, const char *string )
508 const char *s = string;
509 char *dst = malloc( 1000 );
513 int i_size = strlen( string );
515 playlist_t *p_playlist = pl_Yield( p_object );
516 input_thread_t *p_input = p_playlist->p_input;
517 input_item_t *p_item = NULL;
518 pl_Release( p_object );
521 vlc_object_yield( p_input );
522 p_item = input_GetItem(p_input);
524 vlc_mutex_lock( &p_item->lock );
527 sprintf( dst, string );
536 INSERT_STRING( p_item && p_item->p_meta,
537 p_item->p_meta->psz_artist );
540 INSERT_STRING( p_item && p_item->p_meta,
541 p_item->p_meta->psz_album );
544 INSERT_STRING( p_item && p_item->p_meta,
545 p_item->p_meta->psz_copyright );
548 INSERT_STRING( p_item && p_item->p_meta,
549 p_item->p_meta->psz_description );
552 INSERT_STRING( p_item && p_item->p_meta,
553 p_item->p_meta->psz_encodedby );
556 INSERT_STRING( p_item && p_item->p_meta,
557 p_item->p_meta->psz_genre );
560 INSERT_STRING( p_item && p_item->p_meta,
561 p_item->p_meta->psz_language );
564 INSERT_STRING( p_item && p_item->p_meta,
565 p_item->p_meta->psz_tracknum );
568 INSERT_STRING( p_item && p_item->p_meta,
569 p_item->p_meta->psz_nowplaying );
572 INSERT_STRING( p_item && p_item->p_meta,
573 p_item->p_meta->psz_rating );
580 lang = var_GetString( p_input, "sub-language" );
584 lang = strdup( "-" );
586 INSERT_STRING( 1, lang );
591 INSERT_STRING( p_item && p_item->p_meta,
592 p_item->p_meta->psz_title );
595 INSERT_STRING( p_item && p_item->p_meta,
596 p_item->p_meta->psz_url );
599 INSERT_STRING( p_item && p_item->p_meta,
600 p_item->p_meta->psz_date );
605 snprintf( buf, 10, "%d",
606 var_GetInteger( p_input, "bit-rate" )/1000 );
612 INSERT_STRING( 1, buf );
617 snprintf( buf, 10, "%d",
618 var_GetInteger( p_input, "chapter" ) );
624 INSERT_STRING( 1, buf );
629 sprintf( buf, "%02d:%02d:%02d",
630 (int)(p_item->i_duration/(3600000000)),
631 (int)((p_item->i_duration/(60000000))%60),
632 (int)((p_item->i_duration/1000000)%60) );
636 sprintf( buf, "--:--:--" );
638 INSERT_STRING( 1, buf );
641 INSERT_STRING( p_item, p_item->psz_uri );
646 snprintf( buf, 10, "%d",
647 var_GetInteger( p_input, "title" ) );
653 INSERT_STRING( 1, buf );
656 if( p_item && p_input )
658 sprintf( buf, "%02d:%02d:%02d",
659 (int)((p_item->i_duration-p_input->i_time)/(3600000000)),
660 (int)(((p_item->i_duration-p_input->i_time)/(60000000))%60),
661 (int)(((p_item->i_duration-p_input->i_time)/1000000)%60) );
665 sprintf( buf, "--:--:--" );
667 INSERT_STRING( 1, buf );
670 INSERT_STRING( p_item, p_item->psz_name );
677 lang = var_GetString( p_input, "audio-language" );
681 lang = strdup( "-" );
683 INSERT_STRING( 1, lang );
690 snprintf( buf, 10, "%2.1lf",
691 var_GetFloat( p_input, "position" ) * 100. );
695 sprintf( buf, "--.-%%" );
697 INSERT_STRING( 1, buf );
702 int r = var_GetInteger( p_input, "rate" );
703 snprintf( buf, 10, "%d.%d", r/1000, r%1000 );
709 INSERT_STRING( 1, buf );
714 int r = var_GetInteger( p_input, "sample-rate" );
715 snprintf( buf, 10, "%d.%d", r/1000, (r/100)%10 );
721 INSERT_STRING( 1, buf );
726 sprintf( buf, "%02d:%02d:%02d",
727 (int)(p_input->i_time/(3600000000)),
728 (int)((p_input->i_time/(60000000))%60),
729 (int)((p_input->i_time/1000000)%60) );
733 sprintf( buf, "--:--:--" );
735 INSERT_STRING( 1, buf );
738 INSERT_STRING( p_item && p_item->p_meta,
739 p_item->p_meta->psz_publisher );
743 audio_volume_t volume;
744 aout_VolumeGet( p_object, &volume );
745 snprintf( buf, 10, "%d", volume );
746 INSERT_STRING( 1, buf );
776 vlc_object_release( p_input );
778 vlc_mutex_unlock( &p_item->lock );
785 * Apply str format time and str format meta
787 char *__str_format( vlc_object_t *p_this, const char *psz_src )
789 char *psz_buf1, *psz_buf2;
790 psz_buf1 = str_format_time( psz_src );
791 psz_buf2 = str_format_meta( p_this, psz_buf1 );
797 * Remove forbidden characters from filenames (including slashes)
799 void filename_sanitize( char *str )
801 if( *str == '.' && (str[1] == '\0' || (str[1] == '.' && str[2] == '\0' ) ) )
833 * Remove forbidden characters from full paths (leaves slashes)
835 void path_sanitize( char *str )
839 * Uncomment the two blocks to prevent /../ or /./, i'm not sure that we
842 char *prev = str - 1;
845 /* check drive prefix if path is absolute */
846 if( isalpha(*str) && (':' == *(str+1)) )
871 if( str - prev == 2 && prev[1] == '.' )
875 else if( str - prev == 3 && prev[1] == '.' && prev[2] == '.' )