X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Ftext%2Fstrings.c;h=5d1395782375435cf10a18dedb84537c235b7578;hb=b99613a3e91faf43a090c46176c046a5844ef820;hp=8da2e33f2457243b770edce78885c375f11315cf;hpb=d2910851e0b1feb21b3c3c453703995f10dd0348;p=vlc diff --git a/src/text/strings.c b/src/text/strings.c index 8da2e33f24..5d13957823 100644 --- a/src/text/strings.c +++ b/src/text/strings.c @@ -26,10 +26,11 @@ /***************************************************************************** * Preamble *****************************************************************************/ -#include -#include -#include -#include +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include #include /* Needed by str_format_time */ @@ -63,6 +64,8 @@ char *unescape_URI_duplicate( const char *psz ) void unescape_URI( char *psz ) { unsigned char *in = (unsigned char *)psz, *out = in, c; + if( psz == NULL ) + return; while( ( c = *in++ ) != '\0' ) { @@ -144,6 +147,8 @@ char *decode_URI_duplicate( const char *psz ) void decode_URI( char *psz ) { unsigned char *in = (unsigned char *)psz, *out = in, c; + if( psz == NULL ) + return; while( ( c = *in++ ) != '\0' ) { @@ -242,30 +247,174 @@ void resolve_xml_special_chars( char *psz_value ) while ( *psz_value ) { - if( !strncmp( psz_value, "<", 4 ) ) - { - *p_pos = '<'; - psz_value += 4; - } - else if( !strncmp( psz_value, ">", 4 ) ) - { - *p_pos = '>'; - psz_value += 4; - } - else if( !strncmp( psz_value, "&", 5 ) ) - { - *p_pos = '&'; - psz_value += 5; - } - else if( !strncmp( psz_value, """, 6 ) ) + if( *psz_value == '&' ) { - *p_pos = '\"'; - psz_value += 6; - } - else if( !strncmp( psz_value, "'", 6 ) ) - { - *p_pos = '\''; - psz_value += 6; +#define TRY_CHAR( src, len, dst ) \ + if( !strncmp( psz_value, src, len ) ) \ + { \ + *p_pos = dst; \ + psz_value += len; \ + } +#define TRY_LONGCHAR( src, len, dst ) \ + if( !strncmp( psz_value, src, len ) ) \ + { \ + strncpy( p_pos, dst, strlen( dst ) ); \ + p_pos += strlen( dst ) - 1; \ + psz_value += len; \ + } + TRY_CHAR( "<", 4, '<' ) + else TRY_CHAR( ">", 4, '>' ) + else TRY_CHAR( "&", 5, '&' ) + else TRY_CHAR( """, 6, '"' ) + else TRY_CHAR( "'", 6, '\'' ) + else if( psz_value[1] == '#' ) + { + char *psz_end; + int i = strtol( psz_value+2, &psz_end, 10 ); + if( *psz_end == ';' ) + { + if( i >= 32 && i <= 126 ) + { + *p_pos = (char)i; + psz_value = psz_end+1; + } + else + { + /* Unhandled code, FIXME */ + *p_pos = *psz_value; + psz_value++; + } + } + else + { + /* Invalid entity number */ + *p_pos = *psz_value; + psz_value++; + } + } + else TRY_LONGCHAR( "À", 8, "À" ) + else TRY_LONGCHAR( "Á", 8, "Á" ) + else TRY_LONGCHAR( "Â", 7, "Â" ) + else TRY_LONGCHAR( "Ã", 8, "Ã" ) + else TRY_LONGCHAR( "Ä", 6, "Ä" ) + else TRY_LONGCHAR( "Å", 7, "Å" ) + else TRY_LONGCHAR( "Æ", 7, "Æ" ) + else TRY_LONGCHAR( "Ç", 8, "Ç" ) + else TRY_LONGCHAR( "È", 8, "È" ) + else TRY_LONGCHAR( "É", 8, "É" ) + else TRY_LONGCHAR( "Ê", 7, "Ê" ) + else TRY_LONGCHAR( "Ë", 6, "Ë" ) + else TRY_LONGCHAR( "Ì", 8, "Ì" ) + else TRY_LONGCHAR( "Í", 8, "Í" ) + else TRY_LONGCHAR( "Î", 7, "Î" ) + else TRY_LONGCHAR( "Ï", 6, "Ï" ) + else TRY_LONGCHAR( "Ð", 5, "Ð" ) + else TRY_LONGCHAR( "Ñ", 8, "Ñ" ) + else TRY_LONGCHAR( "Ò", 8, "Ò" ) + else TRY_LONGCHAR( "Ó", 8, "Ó" ) + else TRY_LONGCHAR( "Ô", 7, "Ô" ) + else TRY_LONGCHAR( "Õ", 8, "Õ" ) + else TRY_LONGCHAR( "Ö", 6, "Ö" ) + else TRY_LONGCHAR( "Ø", 8, "Ø" ) + else TRY_LONGCHAR( "Ù", 8, "Ù" ) + else TRY_LONGCHAR( "Ú", 8, "Ú" ) + else TRY_LONGCHAR( "Û", 7, "Û" ) + else TRY_LONGCHAR( "Ü", 6, "Ü" ) + else TRY_LONGCHAR( "Ý", 8, "Ý" ) + else TRY_LONGCHAR( "Þ", 7, "Þ" ) + else TRY_LONGCHAR( "ß", 7, "ß" ) + else TRY_LONGCHAR( "à", 8, "à" ) + else TRY_LONGCHAR( "á", 8, "á" ) + else TRY_LONGCHAR( "â", 7, "â" ) + else TRY_LONGCHAR( "ã", 8, "ã" ) + else TRY_LONGCHAR( "ä", 6, "ä" ) + else TRY_LONGCHAR( "å", 7, "Ã¥" ) + else TRY_LONGCHAR( "æ", 7, "æ" ) + else TRY_LONGCHAR( "ç", 8, "ç" ) + else TRY_LONGCHAR( "è", 8, "è" ) + else TRY_LONGCHAR( "é", 8, "é" ) + else TRY_LONGCHAR( "ê", 7, "ê" ) + else TRY_LONGCHAR( "ë", 6, "ë" ) + else TRY_LONGCHAR( "ì", 8, "ì" ) + else TRY_LONGCHAR( "í", 8, "í" ) + else TRY_LONGCHAR( "î", 7, "î" ) + else TRY_LONGCHAR( "ï", 6, "ï" ) + else TRY_LONGCHAR( "ð", 5, "ð" ) + else TRY_LONGCHAR( "ñ", 8, "ñ" ) + else TRY_LONGCHAR( "ò", 8, "ò" ) + else TRY_LONGCHAR( "ó", 8, "ó" ) + else TRY_LONGCHAR( "ô", 7, "ô" ) + else TRY_LONGCHAR( "õ", 8, "õ" ) + else TRY_LONGCHAR( "ö", 6, "ö" ) + else TRY_LONGCHAR( "ø", 8, "ø" ) + else TRY_LONGCHAR( "ù", 8, "ù" ) + else TRY_LONGCHAR( "ú", 8, "ú" ) + else TRY_LONGCHAR( "û", 7, "û" ) + else TRY_LONGCHAR( "ü", 6, "ü" ) + else TRY_LONGCHAR( "ý", 8, "ý" ) + else TRY_LONGCHAR( "þ", 7, "þ" ) + else TRY_LONGCHAR( "ÿ", 6, "ÿ" ) + else TRY_LONGCHAR( "¡", 7, "¡" ) + else TRY_LONGCHAR( "¤", 8, "¤" ) + else TRY_LONGCHAR( "¢", 6, "¢" ) + else TRY_LONGCHAR( "£", 7, "£" ) + else TRY_LONGCHAR( "¥", 5, "Â¥" ) + else TRY_LONGCHAR( "¦", 8, "¦" ) + else TRY_LONGCHAR( "§", 6, "§" ) + else TRY_LONGCHAR( "¨", 5, "¨" ) + else TRY_LONGCHAR( "©", 6, "©" ) + else TRY_LONGCHAR( "ª", 6, "ª" ) + else TRY_LONGCHAR( "«", 7, "«" ) + else TRY_LONGCHAR( "¬", 5, "¬" ) + else TRY_LONGCHAR( "­", 5, "­" ) + else TRY_LONGCHAR( "®", 5, "®" ) + else TRY_LONGCHAR( "™", 7, "™" ) + else TRY_LONGCHAR( "¯", 6, "¯" ) + else TRY_LONGCHAR( "°", 5, "°" ) + else TRY_LONGCHAR( "±", 8, "±" ) + else TRY_LONGCHAR( "²", 6, "²" ) + else TRY_LONGCHAR( "³", 6, "³" ) + else TRY_LONGCHAR( "´", 7, "´" ) + else TRY_LONGCHAR( "µ", 7, "µ" ) + else TRY_LONGCHAR( "¶", 6, "¶" ) + else TRY_LONGCHAR( "·", 8, "·" ) + else TRY_LONGCHAR( "¸", 7, "¸" ) + else TRY_LONGCHAR( "¹", 6, "¹" ) + else TRY_LONGCHAR( "º", 6, "º" ) + else TRY_LONGCHAR( "»", 7, "»" ) + else TRY_LONGCHAR( "¼", 8, "¼" ) + else TRY_LONGCHAR( "½", 8, "½" ) + else TRY_LONGCHAR( "¾", 8, "¾" ) + else TRY_LONGCHAR( "¿", 8, "¿" ) + else TRY_LONGCHAR( "×", 7, "×" ) + else TRY_LONGCHAR( "÷", 8, "÷" ) + else TRY_LONGCHAR( "Œ", 7, "Œ" ) + else TRY_LONGCHAR( "œ", 7, "œ" ) + else TRY_LONGCHAR( "Š", 8, "Å " ) + else TRY_LONGCHAR( "š", 8, "Å¡" ) + else TRY_LONGCHAR( "Ÿ", 6, "Ÿ" ) + else TRY_LONGCHAR( "ˆ", 6, "ˆ" ) + else TRY_LONGCHAR( "˜", 7, "˜" ) + else TRY_LONGCHAR( "–", 7, "–" ) + else TRY_LONGCHAR( "—", 7, "—" ) + else TRY_LONGCHAR( "‘", 7, "‘" ) + else TRY_LONGCHAR( "’", 7, "’" ) + else TRY_LONGCHAR( "‚", 7, "‚" ) + else TRY_LONGCHAR( "“", 7, "“" ) + else TRY_LONGCHAR( "”", 7, "”" ) + else TRY_LONGCHAR( "„", 7, "„" ) + else TRY_LONGCHAR( "†", 8, "†" ) + else TRY_LONGCHAR( "‡", 8, "‡" ) + else TRY_LONGCHAR( "…", 8, "…" ) + else TRY_LONGCHAR( "‰", 8, "‰" ) + else TRY_LONGCHAR( "‹", 8, "‹" ) + else TRY_LONGCHAR( "›", 8, "›" ) + else TRY_LONGCHAR( "€", 6, "€" ) + else + { + *p_pos = *psz_value; + psz_value++; + } } else { @@ -410,7 +559,7 @@ size_t vlc_b64_decode_binary_to_buffer( uint8_t *p_dst, size_t i_dst, const char int i_level; int i_last; - for( i_level = 0, i_last = 0; i_dst > 0 && *p != '\0'; i_dst--, p++ ) + for( i_level = 0, i_last = 0; (size_t)( p_dst - p_start ) < i_dst && *p != '\0'; p++ ) { const int c = b64[(unsigned int)*p]; if( c == -1 ) @@ -469,63 +618,60 @@ char *str_format_time( const char *tformat ) { char buffer[255]; time_t curtime; -#if defined(HAVE_LOCALTIME_R) struct tm loctime; -#else - struct tm *loctime; -#endif /* Get the current time. */ curtime = time( NULL ); /* Convert it to local time representation. */ -#if defined(HAVE_LOCALTIME_R) localtime_r( &curtime, &loctime ); strftime( buffer, 255, tformat, &loctime ); -#else - loctime = localtime( &curtime ); - strftime( buffer, 255, tformat, loctime ); -#endif return strdup( buffer ); } -#define INSERT_STRING( check, string ) \ - if( check && string ) \ +#define INSERT_STRING( string ) \ + if( string != NULL ) \ { \ int len = strlen( string ); \ - dst = realloc( dst, \ - i_size = i_size + len + 1 ); \ - strncpy( d, string, len+1 ); \ + dst = realloc( dst, i_size = i_size + len );\ + memcpy( (dst+d), string, len ); \ d += len; \ + free( string ); \ } \ else \ { \ - *d = '-'; \ + *(dst+d) = '-'; \ d++; \ + } \ + +/* same than INSERT_STRING, except that string won't be freed */ +#define INSERT_STRING_NO_FREE( string ) \ + { \ + int len = strlen( string ); \ + dst = realloc( dst, i_size = i_size + len );\ + memcpy( dst+d, string, len ); \ + d += len; \ } char *__str_format_meta( vlc_object_t *p_object, const char *string ) { const char *s = string; - char *dst = malloc( 1000 ); - char *d = dst; int b_is_format = 0; + int b_empty_if_na = 0; char buf[10]; - int i_size = strlen( string ); + int i_size = strlen( string ) + 1; /* +1 to store '\0' */ + char *dst = strdup( string ); + if( !dst ) return NULL; + int d = 0; playlist_t *p_playlist = pl_Yield( p_object ); - input_thread_t *p_input = p_playlist->p_input; + input_thread_t *p_input = playlist_CurrentInput( p_playlist ); input_item_t *p_item = NULL; pl_Release( p_object ); if( p_input ) { - vlc_object_yield( p_input ); p_item = input_GetItem(p_input); - if( p_item ) - vlc_mutex_lock( &p_item->lock ); } - sprintf( dst, string ); - while( *s ) { if( b_is_format ) @@ -533,71 +679,104 @@ char *__str_format_meta( vlc_object_t *p_object, const char *string ) switch( *s ) { case 'a': - INSERT_STRING( p_item && p_item->p_meta, - p_item->p_meta->psz_artist ); + if( p_item ) + { + INSERT_STRING( input_item_GetArtist( p_item ) ); + } break; case 'b': - INSERT_STRING( p_item && p_item->p_meta, - p_item->p_meta->psz_album ); + if( p_item ) + { + INSERT_STRING( input_item_GetAlbum( p_item ) ); + } break; case 'c': - INSERT_STRING( p_item && p_item->p_meta, - p_item->p_meta->psz_copyright ); + if( p_item ) + { + INSERT_STRING( input_item_GetCopyright( p_item ) ); + } break; case 'd': - INSERT_STRING( p_item && p_item->p_meta, - p_item->p_meta->psz_description ); + if( p_item ) + { + INSERT_STRING( input_item_GetDescription( p_item ) ); + } break; case 'e': - INSERT_STRING( p_item && p_item->p_meta, - p_item->p_meta->psz_encodedby ); + if( p_item ) + { + INSERT_STRING( input_item_GetEncodedBy( p_item ) ); + } + break; + case 'f': + if( p_item && p_item->p_stats ) + { + snprintf( buf, 10, "%d", + p_item->p_stats->i_displayed_pictures ); + } + else + { + sprintf( buf, b_empty_if_na ? "" : "-" ); + } + INSERT_STRING_NO_FREE( buf ); break; case 'g': - INSERT_STRING( p_item && p_item->p_meta, - p_item->p_meta->psz_genre ); + if( p_item ) + { + INSERT_STRING( input_item_GetGenre( p_item ) ); + } break; case 'l': - INSERT_STRING( p_item && p_item->p_meta, - p_item->p_meta->psz_language ); + if( p_item ) + { + INSERT_STRING( input_item_GetLanguage( p_item ) ); + } break; case 'n': - INSERT_STRING( p_item && p_item->p_meta, - p_item->p_meta->psz_tracknum ); + if( p_item ) + { + INSERT_STRING( input_item_GetTrackNum( p_item ) ); + } break; case 'p': - INSERT_STRING( p_item && p_item->p_meta, - p_item->p_meta->psz_nowplaying ); + if( p_item ) + { + INSERT_STRING( input_item_GetNowPlaying( p_item ) ); + } break; case 'r': - INSERT_STRING( p_item && p_item->p_meta, - p_item->p_meta->psz_rating ); + if( p_item ) + { + INSERT_STRING( input_item_GetRating( p_item ) ); + } break; case 's': { - char *lang; + char *lang = NULL; if( p_input ) - { - lang = var_GetString( p_input, "sub-language" ); - } - else - { - lang = strdup( "-" ); - } - INSERT_STRING( 1, lang ); - free( lang ); + lang = var_GetNonEmptyString( p_input, "sub-language" ); + if( lang == NULL ) + lang = strdup( b_empty_if_na ? "" : "-" ); + INSERT_STRING( lang ); break; } case 't': - INSERT_STRING( p_item && p_item->p_meta, - p_item->p_meta->psz_title ); + if( p_item ) + { + INSERT_STRING( input_item_GetTitle( p_item ) ); + } break; case 'u': - INSERT_STRING( p_item && p_item->p_meta, - p_item->p_meta->psz_url ); + if( p_item ) + { + INSERT_STRING( input_item_GetURL( p_item ) ); + } break; case 'A': - INSERT_STRING( p_item && p_item->p_meta, - p_item->p_meta->psz_date ); + if( p_item ) + { + INSERT_STRING( input_item_GetDate( p_item ) ); + } break; case 'B': if( p_input ) @@ -607,9 +786,9 @@ char *__str_format_meta( vlc_object_t *p_object, const char *string ) } else { - sprintf( buf, "-" ); + sprintf( buf, b_empty_if_na ? "" : "-" ); } - INSERT_STRING( 1, buf ); + INSERT_STRING_NO_FREE( buf ); break; case 'C': if( p_input ) @@ -619,26 +798,30 @@ char *__str_format_meta( vlc_object_t *p_object, const char *string ) } else { - sprintf( buf, "-" ); + sprintf( buf, b_empty_if_na ? "" : "-" ); } - INSERT_STRING( 1, buf ); + INSERT_STRING_NO_FREE( buf ); break; case 'D': if( p_item ) { + mtime_t i_duration = input_item_GetDuration( p_item ); sprintf( buf, "%02d:%02d:%02d", - (int)(p_item->i_duration/(3600000000)), - (int)((p_item->i_duration/(60000000))%60), - (int)((p_item->i_duration/1000000)%60) ); + (int)(i_duration/(3600000000)), + (int)((i_duration/(60000000))%60), + (int)((i_duration/1000000)%60) ); } else { - sprintf( buf, "--:--:--" ); + sprintf( buf, b_empty_if_na ? "" : "--:--:--" ); } - INSERT_STRING( 1, buf ); + INSERT_STRING_NO_FREE( buf ); break; case 'F': - INSERT_STRING( p_item, p_item->psz_uri ); + if( p_item ) + { + INSERT_STRING( input_item_GetURI( p_item ) ); + } break; case 'I': if( p_input ) @@ -648,40 +831,41 @@ char *__str_format_meta( vlc_object_t *p_object, const char *string ) } else { - sprintf( buf, "-" ); + sprintf( buf, b_empty_if_na ? "" : "-" ); } - INSERT_STRING( 1, buf ); + INSERT_STRING_NO_FREE( buf ); break; case 'L': if( p_item && p_input ) { + mtime_t i_duration = input_item_GetDuration( p_item ); + int64_t i_time = p_input->i_time; sprintf( buf, "%02d:%02d:%02d", - (int)((p_item->i_duration-p_input->i_time)/(3600000000)), - (int)(((p_item->i_duration-p_input->i_time)/(60000000))%60), - (int)(((p_item->i_duration-p_input->i_time)/1000000)%60) ); + (int)( ( i_duration - i_time ) / 3600000000 ), + (int)( ( ( i_duration - i_time ) / 60000000 ) % 60 ), + (int)( ( ( i_duration - i_time ) / 1000000 ) % 60 ) ); } else { - sprintf( buf, "--:--:--" ); + sprintf( buf, b_empty_if_na ? "" : "--:--:--" ); } - INSERT_STRING( 1, buf ); + INSERT_STRING_NO_FREE( buf ); break; case 'N': - INSERT_STRING( p_item, p_item->psz_name ); + if( p_item ) + { + INSERT_STRING( input_item_GetName( p_item ) ); + } break; case 'O': { - char *lang; + char *lang = NULL; if( p_input ) - { - lang = var_GetString( p_input, "audio-language" ); - } - else - { - lang = strdup( "-" ); - } - INSERT_STRING( 1, lang ); - free( lang ); + lang = var_GetNonEmptyString( p_input, + "audio-language" ); + if( lang == NULL ) + lang = strdup( b_empty_if_na ? "" : "-" ); + INSERT_STRING( lang ); break; } case 'P': @@ -692,9 +876,9 @@ char *__str_format_meta( vlc_object_t *p_object, const char *string ) } else { - sprintf( buf, "--.-%%" ); + sprintf( buf, b_empty_if_na ? "" : "--.-%%" ); } - INSERT_STRING( 1, buf ); + INSERT_STRING_NO_FREE( buf ); break; case 'R': if( p_input ) @@ -704,9 +888,9 @@ char *__str_format_meta( vlc_object_t *p_object, const char *string ) } else { - sprintf( buf, "-" ); + sprintf( buf, b_empty_if_na ? "" : "-" ); } - INSERT_STRING( 1, buf ); + INSERT_STRING_NO_FREE( buf ); break; case 'S': if( p_input ) @@ -716,67 +900,71 @@ char *__str_format_meta( vlc_object_t *p_object, const char *string ) } else { - sprintf( buf, "-" ); + sprintf( buf, b_empty_if_na ? "" : "-" ); } - INSERT_STRING( 1, buf ); + INSERT_STRING_NO_FREE( buf ); break; case 'T': if( p_input ) { sprintf( buf, "%02d:%02d:%02d", - (int)(p_input->i_time/(3600000000)), - (int)((p_input->i_time/(60000000))%60), - (int)((p_input->i_time/1000000)%60) ); + (int)( p_input->i_time / ( 3600000000 ) ), + (int)( ( p_input->i_time / ( 60000000 ) ) % 60 ), + (int)( ( p_input->i_time / 1000000 ) % 60 ) ); } else { - sprintf( buf, "--:--:--" ); + sprintf( buf, b_empty_if_na ? "" : "--:--:--" ); } - INSERT_STRING( 1, buf ); + INSERT_STRING_NO_FREE( buf ); break; case 'U': - INSERT_STRING( p_item && p_item->p_meta, - p_item->p_meta->psz_publisher ); + if( p_item ) + { + INSERT_STRING( input_item_GetPublisher( p_item ) ); + } break; case 'V': { audio_volume_t volume; aout_VolumeGet( p_object, &volume ); snprintf( buf, 10, "%d", volume ); - INSERT_STRING( 1, buf ); + INSERT_STRING_NO_FREE( buf ); break; } case '_': - *d = '\n'; + *(dst+d) = '\n'; d++; break; + case ' ': + b_empty_if_na = 1; + break; + default: - *d = *s; + *(dst+d) = *s; d++; break; } - b_is_format = 0; + if( *s != ' ' ) + b_is_format = 0; } else if( *s == '$' ) { b_is_format = 1; + b_empty_if_na = 0; } else { - *d = *s; + *(dst+d) = *s; d++; } s++; } - *d = '\0'; + *(dst+d) = '\0'; if( p_input ) - { vlc_object_release( p_input ); - if( p_item ) - vlc_mutex_unlock( &p_item->lock ); - } return dst; } @@ -813,7 +1001,9 @@ void filename_sanitize( char *str ) switch( *str ) { case '/': -#ifdef WIN32 +#if defined( __APPLE__ ) + case ':': +#elif defined( WIN32 ) case '\\': case '*': case '"': @@ -848,7 +1038,10 @@ void path_sanitize( char *str ) #endif while( *str ) { -#ifdef WIN32 +#if defined( __APPLE__ ) + if( *str == ':' ) + *str = '_'; +#elif defined( WIN32 ) switch( *str ) { case '*':