]> git.sesse.net Git - vlc/blobdiff - src/text/strings.c
Spare 236 relocations, mark data as constant.
[vlc] / src / text / strings.c
index 10bf1484e7cc207cdbf182ea12826773fd573a04..ef67623b0ab32cb6ab43a3e9b7f41ef41b60fb8b 100644 (file)
 /*****************************************************************************
  * Preamble
  *****************************************************************************/
-#include <vlc/vlc.h>
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
 #include <assert.h>
 
 /* Needed by str_format_time */
@@ -233,6 +237,133 @@ char *encode_URI_component( const char *psz_url )
     return strdup( psz_enc );
 }
 
+static const struct xml_entity_s
+{
+    char    psz_entity[9];
+    uint8_t i_length;
+    char    psz_char[4];
+} p_xml_entities[] = {
+    /* Important: this list has to be in alphabetical order (psz_entity-wise) */
+    { "&AElig;", 7, "Æ" },
+    { "&Aacute;", 8, "Á" },
+    { "&Acirc;", 7, "Â" },
+    { "&Agrave;", 8, "À" },
+    { "&Aring;", 7, "Å" },
+    { "&Atilde;", 8, "Ã" },
+    { "&Auml;", 6, "Ä" },
+    { "&Ccedil;", 8, "Ç" },
+    { "&Dagger;", 8, "‡" },
+    { "&ETH;", 5, "Ð" },
+    { "&Eacute;", 8, "É" },
+    { "&Ecirc;", 7, "Ê" },
+    { "&Egrave;", 8, "È" },
+    { "&Euml;", 6, "Ë" },
+    { "&Iacute;", 8, "Í" },
+    { "&Icirc;", 7, "Î" },
+    { "&Igrave;", 8, "Ì" },
+    { "&Iuml;", 6, "Ï" },
+    { "&Ntilde;", 8, "Ñ" },
+    { "&OElig;", 7, "Œ" },
+    { "&Oacute;", 8, "Ó" },
+    { "&Ocirc;", 7, "Ô" },
+    { "&Ograve;", 8, "Ò" },
+    { "&Oslash;", 8, "Ø" },
+    { "&Otilde;", 8, "Õ" },
+    { "&Ouml;", 6, "Ö" },
+    { "&Scaron;", 8, "Š" },
+    { "&THORN;", 7, "Þ" },
+    { "&Uacute;", 8, "Ú" },
+    { "&Ucirc;", 7, "Û" },
+    { "&Ugrave;", 8, "Ù" },
+    { "&Uuml;", 6, "Ü" },
+    { "&Yacute;", 8, "Ý" },
+    { "&Yuml;", 6, "Ÿ" },
+    { "&aacute;", 8, "á" },
+    { "&acirc;", 7, "â" },
+    { "&acute;", 7, "´" },
+    { "&aelig;", 7, "æ" },
+    { "&agrave;", 8, "à" },
+    { "&aring;", 7, "å" },
+    { "&atilde;", 8, "ã" },
+    { "&auml;", 6, "ä" },
+    { "&bdquo;", 7, "„" },
+    { "&brvbar;", 8, "¦" },
+    { "&ccedil;", 8, "ç" },
+    { "&cedil;", 7, "¸" },
+    { "&cent;", 6, "¢" },
+    { "&circ;", 6, "ˆ" },
+    { "&copy;", 6, "©" },
+    { "&curren;", 8, "¤" },
+    { "&dagger;", 8, "†" },
+    { "&deg;", 5, "°" },
+    { "&divide;", 8, "÷" },
+    { "&eacute;", 8, "é" },
+    { "&ecirc;", 7, "ê" },
+    { "&egrave;", 8, "è" },
+    { "&eth;", 5, "ð" },
+    { "&euml;", 6, "ë" },
+    { "&euro;", 6, "€" },
+    { "&frac12;", 8, "½" },
+    { "&frac14;", 8, "¼" },
+    { "&frac34;", 8, "¾" },
+    { "&hellip;", 8, "…" },
+    { "&iacute;", 8, "í" },
+    { "&icirc;", 7, "î" },
+    { "&iexcl;", 7, "¡" },
+    { "&igrave;", 8, "ì" },
+    { "&iquest;", 8, "¿" },
+    { "&iuml;", 6, "ï" },
+    { "&laquo;", 7, "«" },
+    { "&ldquo;", 7, "“" },
+    { "&lsaquo;", 8, "‹" },
+    { "&lsquo;", 7, "‘" },
+    { "&macr;", 6, "¯" },
+    { "&mdash;", 7, "—" },
+    { "&micro;", 7, "µ" },
+    { "&middot;", 8, "·" },
+    { "&ndash;", 7, "–" },
+    { "&not;", 5, "¬" },
+    { "&ntilde;", 8, "ñ" },
+    { "&oacute;", 8, "ó" },
+    { "&ocirc;", 7, "ô" },
+    { "&oelig;", 7, "œ" },
+    { "&ograve;", 8, "ò" },
+    { "&ordf;", 6, "ª" },
+    { "&ordm;", 6, "º" },
+    { "&oslash;", 8, "ø" },
+    { "&otilde;", 8, "õ" },
+    { "&ouml;", 6, "ö" },
+    { "&para;", 6, "¶" },
+    { "&permil;", 8, "‰" },
+    { "&plusmn;", 8, "±" },
+    { "&pound;", 7, "£" },
+    { "&raquo;", 7, "»" },
+    { "&rdquo;", 7, "”" },
+    { "&reg;", 5, "®" },
+    { "&rsaquo;", 8, "›" },
+    { "&rsquo;", 7, "’" },
+    { "&sbquo;", 7, "‚" },
+    { "&scaron;", 8, "š" },
+    { "&sect;", 6, "§" },
+    { "&shy;", 5, "­" },
+    { "&sup1;", 6, "¹" },
+    { "&sup2;", 6, "²" },
+    { "&sup3;", 6, "³" },
+    { "&szlig;", 7, "ß" },
+    { "&thorn;", 7, "þ" },
+    { "&tilde;", 7, "˜" },
+    { "&times;", 7, "×" },
+    { "&trade;", 7, "™" },
+    { "&uacute;", 8, "ú" },
+    { "&ucirc;", 7, "û" },
+    { "&ugrave;", 8, "ù" },
+    { "&uml;", 5, "¨" },
+    { "&uuml;", 6, "ü" },
+    { "&yacute;", 8, "ý" },
+    { "&yen;", 5, "¥" },
+    { "&yuml;", 6, "ÿ" },
+};
+
 /**
  * Converts "&lt;", "&gt;" and "&amp;" to "<", ">" and "&"
  * \param string to convert
@@ -251,18 +382,12 @@ void resolve_xml_special_chars( char *psz_value )
                 *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( "&lt;", 4, '<' )
-            else TRY_CHAR( "&gt;", 4, '>' )
             else TRY_CHAR( "&amp;", 5, '&' )
-            else TRY_CHAR( "&quot;", 6, '"' )
             else TRY_CHAR( "&apos;", 6, '\'' )
+            else TRY_CHAR( "&gt;", 4, '>' )
+            else TRY_CHAR( "&quot;", 6, '"' )
+#undef TRY_CHAR
             else if( psz_value[1] == '#' )
             {
                 char *psz_end;
@@ -288,128 +413,40 @@ void resolve_xml_special_chars( char *psz_value )
                     psz_value++;
                 }
             }
-            else TRY_LONGCHAR( "&Agrave;", 8, "À" )
-            else TRY_LONGCHAR( "&Aacute;", 8, "Á" )
-            else TRY_LONGCHAR( "&Acirc;", 7, "Â" )
-            else TRY_LONGCHAR( "&Atilde;", 8, "Ã" )
-            else TRY_LONGCHAR( "&Auml;", 6, "Ä" )
-            else TRY_LONGCHAR( "&Aring;", 7, "Å" )
-            else TRY_LONGCHAR( "&AElig;", 7, "Æ" )
-            else TRY_LONGCHAR( "&Ccedil;", 8, "Ç" )
-            else TRY_LONGCHAR( "&Egrave;", 8, "È" )
-            else TRY_LONGCHAR( "&Eacute;", 8, "É" )
-            else TRY_LONGCHAR( "&Ecirc;", 7, "Ê" )
-            else TRY_LONGCHAR( "&Euml;", 6, "Ë" )
-            else TRY_LONGCHAR( "&Igrave;", 8, "Ì" )
-            else TRY_LONGCHAR( "&Iacute;", 8, "Í" )
-            else TRY_LONGCHAR( "&Icirc;", 7, "Î" )
-            else TRY_LONGCHAR( "&Iuml;", 6, "Ï" )
-            else TRY_LONGCHAR( "&ETH;", 5, "Ð" )
-            else TRY_LONGCHAR( "&Ntilde;", 8, "Ñ" )
-            else TRY_LONGCHAR( "&Ograve;", 8, "Ò" )
-            else TRY_LONGCHAR( "&Oacute;", 8, "Ó" )
-            else TRY_LONGCHAR( "&Ocirc;", 7, "Ô" )
-            else TRY_LONGCHAR( "&Otilde;", 8, "Õ" )
-            else TRY_LONGCHAR( "&Ouml;", 6, "Ö" )
-            else TRY_LONGCHAR( "&Oslash;", 8, "Ø" )
-            else TRY_LONGCHAR( "&Ugrave;", 8, "Ù" )
-            else TRY_LONGCHAR( "&Uacute;", 8, "Ú" )
-            else TRY_LONGCHAR( "&Ucirc;", 7, "Û" )
-            else TRY_LONGCHAR( "&Uuml;", 6, "Ü" )
-            else TRY_LONGCHAR( "&Yacute;", 8, "Ý" )
-            else TRY_LONGCHAR( "&THORN;", 7, "Þ" )
-            else TRY_LONGCHAR( "&szlig;", 7, "ß" )
-            else TRY_LONGCHAR( "&agrave;", 8, "à" )
-            else TRY_LONGCHAR( "&aacute;", 8, "á" )
-            else TRY_LONGCHAR( "&acirc;", 7, "â" )
-            else TRY_LONGCHAR( "&atilde;", 8, "ã" )
-            else TRY_LONGCHAR( "&auml;", 6, "ä" )
-            else TRY_LONGCHAR( "&aring;", 7, "å" )
-            else TRY_LONGCHAR( "&aelig;", 7, "æ" )
-            else TRY_LONGCHAR( "&ccedil;", 8, "ç" )
-            else TRY_LONGCHAR( "&egrave;", 8, "è" )
-            else TRY_LONGCHAR( "&eacute;", 8, "é" )
-            else TRY_LONGCHAR( "&ecirc;", 7, "ê" )
-            else TRY_LONGCHAR( "&euml;", 6, "ë" )
-            else TRY_LONGCHAR( "&igrave;", 8, "ì" )
-            else TRY_LONGCHAR( "&iacute;", 8, "í" )
-            else TRY_LONGCHAR( "&icirc;", 7, "î" )
-            else TRY_LONGCHAR( "&iuml;", 6, "ï" )
-            else TRY_LONGCHAR( "&eth;", 5, "ð" )
-            else TRY_LONGCHAR( "&ntilde;", 8, "ñ" )
-            else TRY_LONGCHAR( "&ograve;", 8, "ò" )
-            else TRY_LONGCHAR( "&oacute;", 8, "ó" )
-            else TRY_LONGCHAR( "&ocirc;", 7, "ô" )
-            else TRY_LONGCHAR( "&otilde;", 8, "õ" )
-            else TRY_LONGCHAR( "&ouml;", 6, "ö" )
-            else TRY_LONGCHAR( "&oslash;", 8, "ø" )
-            else TRY_LONGCHAR( "&ugrave;", 8, "ù" )
-            else TRY_LONGCHAR( "&uacute;", 8, "ú" )
-            else TRY_LONGCHAR( "&ucirc;", 7, "û" )
-            else TRY_LONGCHAR( "&uuml;", 6, "ü" )
-            else TRY_LONGCHAR( "&yacute;", 8, "ý" )
-            else TRY_LONGCHAR( "&thorn;", 7, "þ" )
-            else TRY_LONGCHAR( "&yuml;", 6, "ÿ" )
-            else TRY_LONGCHAR( "&iexcl;", 7, "¡" )
-            else TRY_LONGCHAR( "&curren;", 8, "¤" )
-            else TRY_LONGCHAR( "&cent;", 6, "¢" )
-            else TRY_LONGCHAR( "&pound;", 7, "£" )
-            else TRY_LONGCHAR( "&yen;", 5, "¥" )
-            else TRY_LONGCHAR( "&brvbar;", 8, "¦" )
-            else TRY_LONGCHAR( "&sect;", 6, "§" )
-            else TRY_LONGCHAR( "&uml;", 5, "¨" )
-            else TRY_LONGCHAR( "&copy;", 6, "©" )
-            else TRY_LONGCHAR( "&ordf;", 6, "ª" )
-            else TRY_LONGCHAR( "&laquo;", 7, "«" )
-            else TRY_LONGCHAR( "&not;", 5, "¬" )
-            else TRY_LONGCHAR( "&shy;", 5, "­" )
-            else TRY_LONGCHAR( "&reg;", 5, "®" )
-            else TRY_LONGCHAR( "&trade;", 7, "™" )
-            else TRY_LONGCHAR( "&macr;", 6, "¯" )
-            else TRY_LONGCHAR( "&deg;", 5, "°" )
-            else TRY_LONGCHAR( "&plusmn;", 8, "±" )
-            else TRY_LONGCHAR( "&sup2;", 6, "²" )
-            else TRY_LONGCHAR( "&sup3;", 6, "³" )
-            else TRY_LONGCHAR( "&acute;", 7, "´" )
-            else TRY_LONGCHAR( "&micro;", 7, "µ" )
-            else TRY_LONGCHAR( "&para;", 6, "¶" )
-            else TRY_LONGCHAR( "&middot;", 8, "·" )
-            else TRY_LONGCHAR( "&cedil;", 7, "¸" )
-            else TRY_LONGCHAR( "&sup1;", 6, "¹" )
-            else TRY_LONGCHAR( "&ordm;", 6, "º" )
-            else TRY_LONGCHAR( "&raquo;", 7, "»" )
-            else TRY_LONGCHAR( "&frac14;", 8, "¼" )
-            else TRY_LONGCHAR( "&frac12;", 8, "½" )
-            else TRY_LONGCHAR( "&frac34;", 8, "¾" )
-            else TRY_LONGCHAR( "&iquest;", 8, "¿" )
-            else TRY_LONGCHAR( "&times;", 7, "×" )
-            else TRY_LONGCHAR( "&divide;", 8, "÷" )
-            else TRY_LONGCHAR( "&OElig;", 7, "Œ" )
-            else TRY_LONGCHAR( "&oelig;", 7, "œ" )
-            else TRY_LONGCHAR( "&Scaron;", 8, "Š" )
-            else TRY_LONGCHAR( "&scaron;", 8, "š" )
-            else TRY_LONGCHAR( "&Yuml;", 6, "Ÿ" )
-            else TRY_LONGCHAR( "&circ;", 6, "ˆ" )
-            else TRY_LONGCHAR( "&tilde;", 7, "˜" )
-            else TRY_LONGCHAR( "&ndash;", 7, "–" )
-            else TRY_LONGCHAR( "&mdash;", 7, "—" )
-            else TRY_LONGCHAR( "&lsquo;", 7, "‘" )
-            else TRY_LONGCHAR( "&rsquo;", 7, "’" )
-            else TRY_LONGCHAR( "&sbquo;", 7, "‚" )
-            else TRY_LONGCHAR( "&ldquo;", 7, "“" )
-            else TRY_LONGCHAR( "&rdquo;", 7, "”" )
-            else TRY_LONGCHAR( "&bdquo;", 7, "„" )
-            else TRY_LONGCHAR( "&dagger;", 8, "†" )
-            else TRY_LONGCHAR( "&Dagger;", 8, "‡" )
-            else TRY_LONGCHAR( "&hellip;", 8, "…" )
-            else TRY_LONGCHAR( "&permil;", 8, "‰" )
-            else TRY_LONGCHAR( "&lsaquo;", 8, "‹" )
-            else TRY_LONGCHAR( "&rsaquo;", 8, "›" )
-            else TRY_LONGCHAR( "&euro;", 6, "€" )
             else
             {
-                *p_pos = *psz_value;
-                psz_value++;
+                const size_t i_entities = sizeof( p_xml_entities ) /
+                                          sizeof( p_xml_entities[0] );
+                assert( i_entities < 128 );
+                size_t step = 128>>1;
+                size_t i = step-1;
+                int cmp = -1;
+                while( step )
+                {
+                    step >>= 1;
+                    if( i >= i_entities )
+                        cmp = -1;
+                    else
+                        cmp = strncmp( psz_value, p_xml_entities[i].psz_entity,
+                                       p_xml_entities[i].i_length );
+                    if( cmp == 0 )
+                    {
+                        strncpy( p_pos, p_xml_entities[i].psz_char,
+                                 p_xml_entities[i].i_length );
+                        p_pos += strlen( p_xml_entities[i].psz_char ) - 1;
+                        psz_value += p_xml_entities[i].i_length;
+                        break;
+                    }
+                    else if( cmp < 0 )
+                        i -= step;
+                    else
+                        i += step;
+                }
+                if( cmp != 0 )
+                {
+                    *p_pos = *psz_value;
+                    psz_value++;
+                }
             }
         }
         else
@@ -555,7 +592,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 )
@@ -614,129 +651,165 @@ 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 )                                     \
+#define INSERT_STRING( string )                                     \
+                    if( string != NULL )                            \
+                    {                                               \
+                        int len = strlen( string );                 \
+                        dst = realloc( dst, i_size = i_size + len );\
+                        memcpy( (dst+d), string, len );             \
+                        d += len;                                   \
+                        free( string );                             \
+                    }                                               \
+                    else if( !b_empty_if_na )                       \
+                    {                                               \
+                        *(dst+d) = '-';                             \
+                        d++;                                        \
+                    }                                               \
+
+/* same than INSERT_STRING, except that string won't be freed */
+#define INSERT_STRING_NO_FREE( string )                             \
                     {                                               \
-                        psz_meta = string;                          \
-                        if( string )                                \
-                        {                                           \
-                            int len = strlen( psz_meta );           \
-                            dst = realloc( dst,                     \
-                                   i_size = i_size + len + 1 );     \
-                            strncpy( d, psz_meta, len+1 );          \
-                            d += len;                               \
-                            free( psz_meta );                       \
-                        }                                           \
-                        else                                        \
-                        {                                           \
-                                *d = '-';                           \
-                                d++;                                \
-                        }                                           \
+                        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;
+    bool b_is_format = false;
+    bool b_empty_if_na = false;
     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;
+    playlist_t *p_playlist = pl_Hold( p_object );
+    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 )
         {
             switch( *s )
             {
-                char *psz_meta; /* used by INSERT_STRING */
                 case 'a':
-                    INSERT_STRING( p_item, input_item_GetArtist(p_item) );
+                    if( p_item )
+                    {
+                        INSERT_STRING( input_item_GetArtist( p_item ) );
+                    }
                     break;
                 case 'b':
-                    INSERT_STRING( p_item, input_item_GetAlbum(p_item) );
+                    if( p_item )
+                    {
+                        INSERT_STRING( input_item_GetAlbum( p_item ) );
+                    }
                     break;
                 case 'c':
-                    INSERT_STRING( p_item, input_item_GetCopyright(p_item) );
+                    if( p_item )
+                    {
+                        INSERT_STRING( input_item_GetCopyright( p_item ) );
+                    }
                     break;
                 case 'd':
-                    INSERT_STRING( p_item, input_item_GetDescription(p_item) );
+                    if( p_item )
+                    {
+                        INSERT_STRING( input_item_GetDescription( p_item ) );
+                    }
                     break;
                 case 'e':
-                    INSERT_STRING( p_item, input_item_GetEncodedBy(p_item) );
+                    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, input_item_GetGenre(p_item) );
+                    if( p_item )
+                    {
+                        INSERT_STRING( input_item_GetGenre( p_item ) );
+                    }
                     break;
                 case 'l':
-                    INSERT_STRING( p_item, input_item_GetLanguage(p_item) );
+                    if( p_item )
+                    {
+                        INSERT_STRING( input_item_GetLanguage( p_item ) );
+                    }
                     break;
                 case 'n':
-                    INSERT_STRING( p_item, input_item_GetTrackNum(p_item) );
+                    if( p_item )
+                    {
+                        INSERT_STRING( input_item_GetTrackNum( p_item ) );
+                    }
                     break;
                 case 'p':
-                    INSERT_STRING( p_item, input_item_GetNowPlaying(p_item) );
+                    if( p_item )
+                    {
+                        INSERT_STRING( input_item_GetNowPlaying( p_item ) );
+                    }
                     break;
                 case 'r':
-                    INSERT_STRING( p_item, input_item_GetRating(p_item) );
+                    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 = var_GetNonEmptyString( p_input, "sub-language" );
+                    if( lang == NULL )
                         lang = strdup( b_empty_if_na ? "" : "-" );
-                    }
-                    INSERT_STRING( 1, lang );
-                    free( lang );
+                    INSERT_STRING( lang );
                     break;
                 }
                 case 't':
-                    INSERT_STRING( p_item, input_item_GetTitle(p_item) );
+                    if( p_item )
+                    {
+                        INSERT_STRING( input_item_GetTitle( p_item ) );
+                    }
                     break;
                 case 'u':
-                    INSERT_STRING( p_item, input_item_GetURL(p_item) );
+                    if( p_item )
+                    {
+                        INSERT_STRING( input_item_GetURL( p_item ) );
+                    }
                     break;
                 case 'A':
-                    INSERT_STRING( p_item, input_item_GetDate(p_item) );
+                    if( p_item )
+                    {
+                        INSERT_STRING( input_item_GetDate( p_item ) );
+                    }
                     break;
                 case 'B':
                     if( p_input )
@@ -748,7 +821,7 @@ char *__str_format_meta( vlc_object_t *p_object, const char *string )
                     {
                         sprintf( buf, b_empty_if_na ? "" : "-" );
                     }
-                    INSERT_STRING( 1, buf );
+                    INSERT_STRING_NO_FREE( buf );
                     break;
                 case 'C':
                     if( p_input )
@@ -760,24 +833,28 @@ char *__str_format_meta( vlc_object_t *p_object, const char *string )
                     {
                         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, 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 )
@@ -789,38 +866,39 @@ char *__str_format_meta( vlc_object_t *p_object, const char *string )
                     {
                         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, 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 = var_GetNonEmptyString( p_input,
+                                                      "audio-language" );
+                    if( lang == NULL )
                         lang = strdup( b_empty_if_na ? "" : "-" );
-                    }
-                    INSERT_STRING( 1, lang );
-                    free( lang );
+                    INSERT_STRING( lang );
                     break;
                 }
                 case 'P':
@@ -833,7 +911,7 @@ char *__str_format_meta( vlc_object_t *p_object, const char *string )
                     {
                         sprintf( buf, b_empty_if_na ? "" : "--.-%%" );
                     }
-                    INSERT_STRING( 1, buf );
+                    INSERT_STRING_NO_FREE( buf );
                     break;
                 case 'R':
                     if( p_input )
@@ -845,7 +923,7 @@ char *__str_format_meta( vlc_object_t *p_object, const char *string )
                     {
                         sprintf( buf, b_empty_if_na ? "" : "-" );
                     }
-                    INSERT_STRING( 1, buf );
+                    INSERT_STRING_NO_FREE( buf );
                     break;
                 case 'S':
                     if( p_input )
@@ -857,73 +935,74 @@ char *__str_format_meta( vlc_object_t *p_object, const char *string )
                     {
                         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, b_empty_if_na ? "" :  "--:--:--" );
                     }
-                    INSERT_STRING( 1, buf );
+                    INSERT_STRING_NO_FREE( buf );
                     break;
                 case 'U':
-                    INSERT_STRING( p_item, input_item_GetPublisher(p_item) );
+                    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;
+                    b_empty_if_na = true;
                     break;
 
                 default:
-                    *d = *s;
+                    *(dst+d) = *s;
                     d++;
                     break;
             }
             if( *s != ' ' )
-                b_is_format = 0;
+                b_is_format = false;
         }
         else if( *s == '$' )
         {
-            b_is_format = 1;
-            b_empty_if_na = 0;
+            b_is_format = true;
+            b_empty_if_na = false;
         }
         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;
 }
+#undef INSERT_STRING
+#undef INSERT_STRING_NO_FREE
 
 /**
  * Apply str format time and str format meta
@@ -957,7 +1036,9 @@ void filename_sanitize( char *str )
         switch( *str )
         {
             case '/':
-#ifdef WIN32
+#if defined( __APPLE__ )
+            case ':':
+#elif defined( WIN32 )
             case '\\':
             case '*':
             case '"':
@@ -992,7 +1073,10 @@ void path_sanitize( char *str )
 #endif
     while( *str )
     {
-#ifdef WIN32
+#if defined( __APPLE__ )
+        if( *str == ':' )
+            *str = '_';
+#elif defined( WIN32 )
         switch( *str )
         {
             case '*':