strings.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:34k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * strings.c: String related functions
  3.  *****************************************************************************
  4.  * Copyright (C) 2006 the VideoLAN team
  5.  * Copyright (C) 2008-2009 Rémi Denis-Courmont
  6.  * $Id: 283b9b60437aba75f93a97329d8d165117e7b253 $
  7.  *
  8.  * Authors: Antoine Cellerier <dionoea at videolan dot org>
  9.  *          Daniel Stranger <vlc at schmaller dot de>
  10.  *          Rémi Denis-Courmont <rem # videolan org>
  11.  *
  12.  * This program is free software; you can redistribute it and/or modify
  13.  * it under the terms of the GNU General Public License as published by
  14.  * the Free Software Foundation; either version 2 of the License, or
  15.  * (at your option) any later version.
  16.  *
  17.  * This program is distributed in the hope that it will be useful,
  18.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.  * GNU General Public License for more details.
  21.  *
  22.  * You should have received a copy of the GNU General Public License
  23.  * along with this program; if not, write to the Free Software
  24.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  25.  *****************************************************************************/
  26. /*****************************************************************************
  27.  * Preamble
  28.  *****************************************************************************/
  29. #ifdef HAVE_CONFIG_H
  30. # include "config.h"
  31. #endif
  32. #include <vlc_common.h>
  33. #include <assert.h>
  34. /* Needed by str_format_time */
  35. #include <time.h>
  36. #include <limits.h>
  37. /* Needed by str_format_meta */
  38. #include <vlc_input.h>
  39. #include <vlc_meta.h>
  40. #include <vlc_playlist.h>
  41. #include <vlc_aout.h>
  42. #include <vlc_strings.h>
  43. #include <vlc_url.h>
  44. #include <vlc_charset.h>
  45. /**
  46.  * Decode encoded URI component. See also decode_URI().
  47.  * return decoded duplicated string
  48.  */
  49. char *decode_URI_duplicate( const char *psz )
  50. {
  51.     char *psz_dup = strdup( psz );
  52.     decode_URI( psz_dup );
  53.     return psz_dup;
  54. }
  55. /**
  56.  * Decode an encoded URI component in place.
  57.  * <b>This function does NOT decode entire URIs.</b>
  58.  * It decodes components (e.g. host name, directory, file name).
  59.  * Decoded URIs do not exist in the real world (see RFC3986 §2.4).
  60.  * Complete URIs are always "encoded" (or they are syntaxically invalid).
  61.  *
  62.  * Note that URI encoding is different from Javascript escaping. Especially,
  63.  * white spaces and Unicode non-ASCII code points are encoded differently.
  64.  *
  65.  * return psz on success, NULL if it was not properly encoded
  66.  */
  67. char *decode_URI( char *psz )
  68. {
  69.     unsigned char *in = (unsigned char *)psz, *out = in, c;
  70.     if( psz == NULL )
  71.         return NULL;
  72.     while( ( c = *in++ ) != '' )
  73.     {
  74.         switch( c )
  75.         {
  76.             case '%':
  77.             {
  78.                 char hex[3];
  79.                 if( ( ( hex[0] = *in++ ) == 0 )
  80.                  || ( ( hex[1] = *in++ ) == 0 ) )
  81.                     return NULL;
  82.                 hex[2] = '';
  83.                 *out++ = (unsigned char)strtoul( hex, NULL, 0x10 );
  84.                 break;
  85.             }
  86.             case '+': /* This is HTTP forms, not URI decoding... */
  87.                 *out++ = ' ';
  88.                 break;
  89.             default:
  90.                 /* Inserting non-ASCII or non-printable characters is unsafe,
  91.                  * and no sane browser will send these unencoded */
  92.                 if( ( c < 32 ) || ( c > 127 ) )
  93.                     *out++ = '?';
  94.                 else
  95.                     *out++ = c;
  96.         }
  97.     }
  98.     *out = '';
  99.     EnsureUTF8( psz );
  100.     return psz;
  101. }
  102. static inline bool isurisafe( int c )
  103. {
  104.     /* These are the _unreserved_ URI characters (RFC3986 §2.3) */
  105.     return ( (unsigned char)( c - 'a' ) < 26 )
  106.             || ( (unsigned char)( c - 'A' ) < 26 )
  107.             || ( (unsigned char)( c - '0' ) < 10 )
  108.             || ( strchr( "-._~", c ) != NULL );
  109. }
  110. static char *encode_URI_bytes (const char *psz_uri, size_t len)
  111. {
  112.     char *psz_enc = malloc (3 * len + 1), *out = psz_enc;
  113.     if (psz_enc == NULL)
  114.         return NULL;
  115.     for (size_t i = 0; i < len; i++)
  116.     {
  117.         static const char hex[16] = "0123456789ABCDEF";
  118.         uint8_t c = *psz_uri;
  119.         if( isurisafe( c ) )
  120.             *out++ = c;
  121.         /* This is URI encoding, not HTTP forms:
  122.          * Space is encoded as '%20', not '+'. */
  123.         else
  124.         {
  125.             *out++ = '%';
  126.             *out++ = hex[c >> 4];
  127.             *out++ = hex[c & 0xf];
  128.         }
  129.         psz_uri++;
  130.     }
  131.     *out++ = '';
  132.     out = realloc (psz_enc, out - psz_enc);
  133.     return out ? out : psz_enc; /* realloc() can fail (safe) */
  134. }
  135. /**
  136.  * Encodes an URI component (RFC3986 §2).
  137.  *
  138.  * @param psz_uri nul-terminated UTF-8 representation of the component.
  139.  * Obviously, you can't pass an URI containing a nul character, but you don't
  140.  * want to do that, do you?
  141.  *
  142.  * @return encoded string (must be free()'d), or NULL for ENOMEM.
  143.  */
  144. char *encode_URI_component( const char *psz_uri )
  145. {
  146.     return encode_URI_bytes (psz_uri, strlen (psz_uri));
  147. }
  148. static const struct xml_entity_s
  149. {
  150.     char    psz_entity[8];
  151.     char    psz_char[4];
  152. } xml_entities[] = {
  153.     /* Important: this list has to be in alphabetical order (psz_entity-wise) */
  154.     { "AElig;",  "Æ" },
  155.     { "Aacute;", "Á" },
  156.     { "Acirc;",  "Â" },
  157.     { "Agrave;", "À" },
  158.     { "Aring;",  "Å" },
  159.     { "Atilde;", "Ã" },
  160.     { "Auml;",   "Ä" },
  161.     { "Ccedil;", "Ç" },
  162.     { "Dagger;", "‡" },
  163.     { "ETH;",    "Ð" },
  164.     { "Eacute;", "É" },
  165.     { "Ecirc;",  "Ê" },
  166.     { "Egrave;", "È" },
  167.     { "Euml;",   "Ë" },
  168.     { "Iacute;", "Í" },
  169.     { "Icirc;",  "Î" },
  170.     { "Igrave;", "Ì" },
  171.     { "Iuml;",   "Ï" },
  172.     { "Ntilde;", "Ñ" },
  173.     { "OElig;",  "Œ" },
  174.     { "Oacute;", "Ó" },
  175.     { "Ocirc;",  "Ô" },
  176.     { "Ograve;", "Ò" },
  177.     { "Oslash;", "Ø" },
  178.     { "Otilde;", "Õ" },
  179.     { "Ouml;",   "Ö" },
  180.     { "Scaron;", "Š" },
  181.     { "THORN;",  "Þ" },
  182.     { "Uacute;", "Ú" },
  183.     { "Ucirc;",  "Û" },
  184.     { "Ugrave;", "Ù" },
  185.     { "Uuml;",   "Ü" },
  186.     { "Yacute;", "Ý" },
  187.     { "Yuml;",   "Ÿ" },
  188.     { "aacute;", "á" },
  189.     { "acirc;",  "â" },
  190.     { "acute;",  "´" },
  191.     { "aelig;",  "æ" },
  192.     { "agrave;", "à" },
  193.     { "amp;",    "&" },
  194.     { "apos;",   "'" },
  195.     { "aring;",  "å" },
  196.     { "atilde;", "ã" },
  197.     { "auml;",   "ä" },
  198.     { "bdquo;",  "„" },
  199.     { "brvbar;", "¦" },
  200.     { "ccedil;", "ç" },
  201.     { "cedil;",  "¸" },
  202.     { "cent;",   "¢" },
  203.     { "circ;",   "ˆ" },
  204.     { "copy;",   "©" },
  205.     { "curren;", "¤" },
  206.     { "dagger;", "†" },
  207.     { "deg;",    "°" },
  208.     { "divide;", "÷" },
  209.     { "eacute;", "é" },
  210.     { "ecirc;",  "ê" },
  211.     { "egrave;", "è" },
  212.     { "eth;",    "ð" },
  213.     { "euml;",   "ë" },
  214.     { "euro;",   "€" },
  215.     { "frac12;", "½" },
  216.     { "frac14;", "¼" },
  217.     { "frac34;", "¾" },
  218.     { "gt;",     ">" },
  219.     { "hellip;", "…" },
  220.     { "iacute;", "í" },
  221.     { "icirc;",  "î" },
  222.     { "iexcl;",  "¡" },
  223.     { "igrave;", "ì" },
  224.     { "iquest;", "¿" },
  225.     { "iuml;",   "ï" },
  226.     { "laquo;",  "«" },
  227.     { "ldquo;",  "“" },
  228.     { "lsaquo;", "‹" },
  229.     { "lsquo;",  "‘" },
  230.     { "lt;",     "<" },
  231.     { "macr;",   "¯" },
  232.     { "mdash;",  "—" },
  233.     { "micro;",  "µ" },
  234.     { "middot;", "·" },
  235.     { "nbsp;",   "xc2xa0" },
  236.     { "ndash;",  "–" },
  237.     { "not;",    "¬" },
  238.     { "ntilde;", "ñ" },
  239.     { "oacute;", "ó" },
  240.     { "ocirc;",  "ô" },
  241.     { "oelig;",  "œ" },
  242.     { "ograve;", "ò" },
  243.     { "ordf;",   "ª" },
  244.     { "ordm;",   "º" },
  245.     { "oslash;", "ø" },
  246.     { "otilde;", "õ" },
  247.     { "ouml;",   "ö" },
  248.     { "para;",   "¶" },
  249.     { "permil;", "‰" },
  250.     { "plusmn;", "±" },
  251.     { "pound;",  "£" },
  252.     { "quot;",   """ },
  253.     { "raquo;",  "»" },
  254.     { "rdquo;",  "”" },
  255.     { "reg;",    "®" },
  256.     { "rsaquo;", "›" },
  257.     { "rsquo;",  "’" },
  258.     { "sbquo;",  "‚" },
  259.     { "scaron;", "š" },
  260.     { "sect;",   "§" },
  261.     { "shy;",    "­" },
  262.     { "sup1;",   "¹" },
  263.     { "sup2;",   "²" },
  264.     { "sup3;",   "³" },
  265.     { "szlig;",  "ß" },
  266.     { "thorn;",  "þ" },
  267.     { "tilde;",  "˜" },
  268.     { "times;",  "×" },
  269.     { "trade;",  "™" },
  270.     { "uacute;", "ú" },
  271.     { "ucirc;",  "û" },
  272.     { "ugrave;", "ù" },
  273.     { "uml;",    "¨" },
  274.     { "uuml;",   "ü" },
  275.     { "yacute;", "ý" },
  276.     { "yen;",    "¥" },
  277.     { "yuml;",   "ÿ" },
  278. };
  279. static int cmp_entity (const void *key, const void *elem)
  280. {
  281.     const struct xml_entity_s *ent = elem;
  282.     const char *name = key;
  283.     return strncmp (name, ent->psz_entity, strlen (ent->psz_entity));
  284. }
  285. /**
  286.  * Converts "&lt;", "&gt;" and "&amp;" to "<", ">" and "&"
  287.  * param string to convert
  288.  */
  289. void resolve_xml_special_chars( char *psz_value )
  290. {
  291.     char *p_pos = psz_value;
  292.     while ( *psz_value )
  293.     {
  294.         if( *psz_value == '&' )
  295.         {
  296.             if( psz_value[1] == '#' )
  297.             {   /* &#xxx; Unicode code point */
  298.                 char *psz_end;
  299.                 unsigned long cp = strtoul( psz_value+2, &psz_end, 10 );
  300.                 if( *psz_end == ';' )
  301.                 {
  302.                     psz_value = psz_end + 1;
  303.                     if( cp == 0 )
  304.                         (void)0; /* skip nuls */
  305.                     else
  306.                     if( cp <= 0x7F )
  307.                     {
  308.                         *p_pos =            cp;
  309.                     }
  310.                     else
  311.                     /* Unicode code point outside ASCII.
  312.                      * &#xxx; representation is longer than UTF-8 :) */
  313.                     if( cp <= 0x7FF )
  314.                     {
  315.                         *p_pos++ = 0xC0 |  (cp >>  6);
  316.                         *p_pos   = 0x80 |  (cp        & 0x3F);
  317.                     }
  318.                     else
  319.                     if( cp <= 0xFFFF )
  320.                     {
  321.                         *p_pos++ = 0xE0 |  (cp >> 12);
  322.                         *p_pos++ = 0x80 | ((cp >>  6) & 0x3F);
  323.                         *p_pos   = 0x80 |  (cp        & 0x3F);
  324.                     }
  325.                     else
  326.                     if( cp <= 0x1FFFFF ) /* Outside the BMP */
  327.                     {   /* Unicode stops at 10FFFF, but who cares? */
  328.                         *p_pos++ = 0xF0 |  (cp >> 18);
  329.                         *p_pos++ = 0x80 | ((cp >> 12) & 0x3F);
  330.                         *p_pos++ = 0x80 | ((cp >>  6) & 0x3F);
  331.                         *p_pos   = 0x80 |  (cp        & 0x3F);
  332.                     }
  333.                 }
  334.                 else
  335.                 {
  336.                     /* Invalid entity number */
  337.                     *p_pos = *psz_value;
  338.                     psz_value++;
  339.                 }
  340.             }
  341.             else
  342.             {   /* Well-known XML entity */
  343.                 const struct xml_entity_s *ent;
  344.                 ent = bsearch (psz_value + 1, xml_entities,
  345.                                sizeof (xml_entities) / sizeof (*ent),
  346.                                sizeof (*ent), cmp_entity);
  347.                 if (ent != NULL)
  348.                 {
  349.                     size_t olen = strlen (ent->psz_char);
  350.                     memcpy (p_pos, ent->psz_char, olen);
  351.                     p_pos += olen - 1;
  352.                     psz_value += strlen (ent->psz_entity) + 1;
  353.                 }
  354.                 else
  355.                 {   /* No match */
  356.                     *p_pos = *psz_value;
  357.                     psz_value++;
  358.                 }
  359.             }
  360.         }
  361.         else
  362.         {
  363.             *p_pos = *psz_value;
  364.             psz_value++;
  365.         }
  366.         p_pos++;
  367.     }
  368.     *p_pos = '';
  369. }
  370. /**
  371.  * Converts '<', '>', '"', ''' and '&' to their html entities
  372.  * param psz_content simple element content that is to be converted
  373.  */
  374. char *convert_xml_special_chars( const char *psz_content )
  375. {
  376.     char *psz_temp = malloc( 6 * strlen( psz_content ) + 1 );
  377.     const char *p_from = psz_content;
  378.     char *p_to   = psz_temp;
  379.     while ( *p_from )
  380.     {
  381.         if ( *p_from == '<' )
  382.         {
  383.             strcpy( p_to, "&lt;" );
  384.             p_to += 4;
  385.         }
  386.         else if ( *p_from == '>' )
  387.         {
  388.             strcpy( p_to, "&gt;" );
  389.             p_to += 4;
  390.         }
  391.         else if ( *p_from == '&' )
  392.         {
  393.             strcpy( p_to, "&amp;" );
  394.             p_to += 5;
  395.         }
  396.         else if( *p_from == '"' )
  397.         {
  398.             strcpy( p_to, "&quot;" );
  399.             p_to += 6;
  400.         }
  401.         else if( *p_from == ''' )
  402.         {
  403.             strcpy( p_to, "&#039;" );
  404.             p_to += 6;
  405.         }
  406.         else
  407.         {
  408.             *p_to = *p_from;
  409.             p_to++;
  410.         }
  411.         p_from++;
  412.     }
  413.     *p_to = '';
  414.     return psz_temp;
  415. }
  416. /* Base64 encoding */
  417. char *vlc_b64_encode_binary( const uint8_t *src, size_t i_src )
  418. {
  419.     static const char b64[] =
  420.            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  421.     char *ret = malloc( ( i_src + 4 ) * 4 / 3 );
  422.     char *dst = ret;
  423.     if( dst == NULL )
  424.         return NULL;
  425.     while( i_src > 0 )
  426.     {
  427.         /* pops (up to) 3 bytes of input, push 4 bytes */
  428.         uint32_t v;
  429.         /* 1/3 -> 1/4 */
  430.         v = *src++ << 24;
  431.         *dst++ = b64[v >> 26];
  432.         v = v << 6;
  433.         /* 2/3 -> 2/4 */
  434.         if( i_src >= 2 )
  435.             v |= *src++ << 22;
  436.         *dst++ = b64[v >> 26];
  437.         v = v << 6;
  438.         /* 3/3 -> 3/4 */
  439.         if( i_src >= 3 )
  440.             v |= *src++ << 20; // 3/3
  441.         *dst++ = ( i_src >= 2 ) ? b64[v >> 26] : '='; // 3/4
  442.         v = v << 6;
  443.         /* -> 4/4 */
  444.         *dst++ = ( i_src >= 3 ) ? b64[v >> 26] : '='; // 4/4
  445.         if( i_src <= 3 )
  446.             break;
  447.         i_src -= 3;
  448.     }
  449.     *dst = '';
  450.     return ret;
  451. }
  452. char *vlc_b64_encode( const char *src )
  453. {
  454.     if( src )
  455.         return vlc_b64_encode_binary( (const uint8_t*)src, strlen(src) );
  456.     else
  457.         return vlc_b64_encode_binary( (const uint8_t*)"", 0 );
  458. }
  459. /* Base64 decoding */
  460. size_t vlc_b64_decode_binary_to_buffer( uint8_t *p_dst, size_t i_dst, const char *p_src )
  461. {
  462.     static const int b64[256] = {
  463.         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 00-0F */
  464.         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 10-1F */
  465.         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,  /* 20-2F */
  466.         52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,  /* 30-3F */
  467.         -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,  /* 40-4F */
  468.         15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,  /* 50-5F */
  469.         -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,  /* 60-6F */
  470.         41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1,  /* 70-7F */
  471.         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 80-8F */
  472.         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 90-9F */
  473.         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* A0-AF */
  474.         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* B0-BF */
  475.         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* C0-CF */
  476.         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* D0-DF */
  477.         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* E0-EF */
  478.         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1   /* F0-FF */
  479.     };
  480.     uint8_t *p_start = p_dst;
  481.     uint8_t *p = (uint8_t *)p_src;
  482.     int i_level;
  483.     int i_last;
  484.     for( i_level = 0, i_last = 0; (size_t)( p_dst - p_start ) < i_dst && *p != ''; p++ )
  485.     {
  486.         const int c = b64[(unsigned int)*p];
  487.         if( c == -1 )
  488.             continue;
  489.         switch( i_level )
  490.         {
  491.             case 0:
  492.                 i_level++;
  493.                 break;
  494.             case 1:
  495.                 *p_dst++ = ( i_last << 2 ) | ( ( c >> 4)&0x03 );
  496.                 i_level++;
  497.                 break;
  498.             case 2:
  499.                 *p_dst++ = ( ( i_last << 4 )&0xf0 ) | ( ( c >> 2 )&0x0f );
  500.                 i_level++;
  501.                 break;
  502.             case 3:
  503.                 *p_dst++ = ( ( i_last &0x03 ) << 6 ) | c;
  504.                 i_level = 0;
  505.         }
  506.         i_last = c;
  507.     }
  508.     return p_dst - p_start;
  509. }
  510. size_t vlc_b64_decode_binary( uint8_t **pp_dst, const char *psz_src )
  511. {
  512.     const int i_src = strlen( psz_src );
  513.     uint8_t   *p_dst;
  514.     *pp_dst = p_dst = malloc( i_src );
  515.     if( !p_dst )
  516.         return 0;
  517.     return  vlc_b64_decode_binary_to_buffer( p_dst, i_src, psz_src );
  518. }
  519. char *vlc_b64_decode( const char *psz_src )
  520. {
  521.     const int i_src = strlen( psz_src );
  522.     char *p_dst = malloc( i_src + 1 );
  523.     size_t i_dst;
  524.     if( !p_dst )
  525.         return NULL;
  526.     i_dst = vlc_b64_decode_binary_to_buffer( (uint8_t*)p_dst, i_src, psz_src );
  527.     p_dst[i_dst] = '';
  528.     return p_dst;
  529. }
  530. /**
  531.  * Formats current time into a heap-allocated string.
  532.  * @param tformat time format (as with C strftime())
  533.  * @return an allocated string (must be free()'d), or NULL on memory error.
  534.  */
  535. char *str_format_time( const char *tformat )
  536. {
  537.     time_t curtime;
  538.     struct tm loctime;
  539.     if (strcmp (tformat, "") == 0)
  540.         return strdup (""); /* corner case w.r.t. strftime() return value */
  541.     /* Get the current time.  */
  542.     time( &curtime );
  543.     /* Convert it to local time representation.  */
  544.     localtime_r( &curtime, &loctime );
  545.     for (size_t buflen = strlen (tformat) + 32;; buflen += 32)
  546.     {
  547.         char *str = malloc (buflen);
  548.         if (str == NULL)
  549.             return NULL;
  550.         size_t len = strftime (str, buflen, tformat, &loctime);
  551.         if (len > 0)
  552.         {
  553.             char *ret = realloc (str, len + 1);
  554.             return ret ? ret : str; /* <- this cannot fail */
  555.         }
  556.     }
  557.     assert (0);
  558. }
  559. #define INSERT_STRING( string )                                     
  560.                     if( string != NULL )                            
  561.                     {                                               
  562.                         int len = strlen( string );                 
  563.                         dst = realloc( dst, i_size = i_size + len );
  564.                         memcpy( (dst+d), string, len );             
  565.                         d += len;                                   
  566.                         free( string );                             
  567.                     }                                               
  568.                     else if( !b_empty_if_na )                       
  569.                     {                                               
  570.                         *(dst+d) = '-';                             
  571.                         d++;                                        
  572.                     }                                               
  573. /* same than INSERT_STRING, except that string won't be freed */
  574. #define INSERT_STRING_NO_FREE( string )                             
  575.                     {                                               
  576.                         int len = strlen( string );                 
  577.                         dst = realloc( dst, i_size = i_size + len );
  578.                         memcpy( dst+d, string, len );               
  579.                         d += len;                                   
  580.                     }
  581. char *__str_format_meta( vlc_object_t *p_object, const char *string )
  582. {
  583.     const char *s = string;
  584.     bool b_is_format = false;
  585.     bool b_empty_if_na = false;
  586.     char buf[10];
  587.     int i_size = strlen( string ) + 1; /* +1 to store '' */
  588.     char *dst = strdup( string );
  589.     if( !dst ) return NULL;
  590.     int d = 0;
  591.     playlist_t *p_playlist = pl_Hold( p_object );
  592.     input_thread_t *p_input = playlist_CurrentInput( p_playlist );
  593.     input_item_t *p_item = NULL;
  594.     pl_Release( p_object );
  595.     if( p_input )
  596.     {
  597.         p_item = input_GetItem(p_input);
  598.     }
  599.     while( *s )
  600.     {
  601.         if( b_is_format )
  602.         {
  603.             switch( *s )
  604.             {
  605.                 case 'a':
  606.                     if( p_item )
  607.                     {
  608.                         INSERT_STRING( input_item_GetArtist( p_item ) );
  609.                     }
  610.                     break;
  611.                 case 'b':
  612.                     if( p_item )
  613.                     {
  614.                         INSERT_STRING( input_item_GetAlbum( p_item ) );
  615.                     }
  616.                     break;
  617.                 case 'c':
  618.                     if( p_item )
  619.                     {
  620.                         INSERT_STRING( input_item_GetCopyright( p_item ) );
  621.                     }
  622.                     break;
  623.                 case 'd':
  624.                     if( p_item )
  625.                     {
  626.                         INSERT_STRING( input_item_GetDescription( p_item ) );
  627.                     }
  628.                     break;
  629.                 case 'e':
  630.                     if( p_item )
  631.                     {
  632.                         INSERT_STRING( input_item_GetEncodedBy( p_item ) );
  633.                     }
  634.                     break;
  635.                 case 'f':
  636.                     if( p_item && p_item->p_stats )
  637.                     {
  638.                         vlc_mutex_lock( &p_item->p_stats->lock );
  639.                         snprintf( buf, 10, "%d",
  640.                                   p_item->p_stats->i_displayed_pictures );
  641.                         vlc_mutex_unlock( &p_item->p_stats->lock );
  642.                     }
  643.                     else
  644.                     {
  645.                         sprintf( buf, b_empty_if_na ? "" : "-" );
  646.                     }
  647.                     INSERT_STRING_NO_FREE( buf );
  648.                     break;
  649.                 case 'g':
  650.                     if( p_item )
  651.                     {
  652.                         INSERT_STRING( input_item_GetGenre( p_item ) );
  653.                     }
  654.                     break;
  655.                 case 'l':
  656.                     if( p_item )
  657.                     {
  658.                         INSERT_STRING( input_item_GetLanguage( p_item ) );
  659.                     }
  660.                     break;
  661.                 case 'n':
  662.                     if( p_item )
  663.                     {
  664.                         INSERT_STRING( input_item_GetTrackNum( p_item ) );
  665.                     }
  666.                     break;
  667.                 case 'p':
  668.                     if( p_item )
  669.                     {
  670.                         INSERT_STRING( input_item_GetNowPlaying( p_item ) );
  671.                     }
  672.                     break;
  673.                 case 'r':
  674.                     if( p_item )
  675.                     {
  676.                         INSERT_STRING( input_item_GetRating( p_item ) );
  677.                     }
  678.                     break;
  679.                 case 's':
  680.                 {
  681.                     char *lang = NULL;
  682.                     if( p_input )
  683.                         lang = var_GetNonEmptyString( p_input, "sub-language" );
  684.                     if( lang == NULL )
  685.                         lang = strdup( b_empty_if_na ? "" : "-" );
  686.                     INSERT_STRING( lang );
  687.                     break;
  688.                 }
  689.                 case 't':
  690.                     if( p_item )
  691.                     {
  692.                         INSERT_STRING( input_item_GetTitle( p_item ) );
  693.                     }
  694.                     break;
  695.                 case 'u':
  696.                     if( p_item )
  697.                     {
  698.                         INSERT_STRING( input_item_GetURL( p_item ) );
  699.                     }
  700.                     break;
  701.                 case 'A':
  702.                     if( p_item )
  703.                     {
  704.                         INSERT_STRING( input_item_GetDate( p_item ) );
  705.                     }
  706.                     break;
  707.                 case 'B':
  708.                     if( p_input )
  709.                     {
  710.                         snprintf( buf, 10, "%d",
  711.                                   var_GetInteger( p_input, "bit-rate" )/1000 );
  712.                     }
  713.                     else
  714.                     {
  715.                         sprintf( buf, b_empty_if_na ? "" : "-" );
  716.                     }
  717.                     INSERT_STRING_NO_FREE( buf );
  718.                     break;
  719.                 case 'C':
  720.                     if( p_input )
  721.                     {
  722.                         snprintf( buf, 10, "%d",
  723.                                   var_GetInteger( p_input, "chapter" ) );
  724.                     }
  725.                     else
  726.                     {
  727.                         sprintf( buf, b_empty_if_na ? "" : "-" );
  728.                     }
  729.                     INSERT_STRING_NO_FREE( buf );
  730.                     break;
  731.                 case 'D':
  732.                     if( p_item )
  733.                     {
  734.                         mtime_t i_duration = input_item_GetDuration( p_item );
  735.                         sprintf( buf, "%02d:%02d:%02d",
  736.                                  (int)(i_duration/(3600000000)),
  737.                                  (int)((i_duration/(60000000))%60),
  738.                                  (int)((i_duration/1000000)%60) );
  739.                     }
  740.                     else
  741.                     {
  742.                         sprintf( buf, b_empty_if_na ? "" : "--:--:--" );
  743.                     }
  744.                     INSERT_STRING_NO_FREE( buf );
  745.                     break;
  746.                 case 'F':
  747.                     if( p_item )
  748.                     {
  749.                         INSERT_STRING( input_item_GetURI( p_item ) );
  750.                     }
  751.                     break;
  752.                 case 'I':
  753.                     if( p_input )
  754.                     {
  755.                         snprintf( buf, 10, "%d",
  756.                                   var_GetInteger( p_input, "title" ) );
  757.                     }
  758.                     else
  759.                     {
  760.                         sprintf( buf, b_empty_if_na ? "" : "-" );
  761.                     }
  762.                     INSERT_STRING_NO_FREE( buf );
  763.                     break;
  764.                 case 'L':
  765.                     if( p_item && p_input )
  766.                     {
  767.                         mtime_t i_duration = input_item_GetDuration( p_item );
  768.                         int64_t i_time = var_GetTime( p_input, "time" );
  769.                         sprintf( buf, "%02d:%02d:%02d",
  770.                      (int)( ( i_duration - i_time ) / 3600000000 ),
  771.                      (int)( ( ( i_duration - i_time ) / 60000000 ) % 60 ),
  772.                      (int)( ( ( i_duration - i_time ) / 1000000 ) % 60 ) );
  773.                     }
  774.                     else
  775.                     {
  776.                         sprintf( buf, b_empty_if_na ? "" : "--:--:--" );
  777.                     }
  778.                     INSERT_STRING_NO_FREE( buf );
  779.                     break;
  780.                 case 'N':
  781.                     if( p_item )
  782.                     {
  783.                         INSERT_STRING( input_item_GetName( p_item ) );
  784.                     }
  785.                     break;
  786.                 case 'O':
  787.                 {
  788.                     char *lang = NULL;
  789.                     if( p_input )
  790.                         lang = var_GetNonEmptyString( p_input,
  791.                                                       "audio-language" );
  792.                     if( lang == NULL )
  793.                         lang = strdup( b_empty_if_na ? "" : "-" );
  794.                     INSERT_STRING( lang );
  795.                     break;
  796.                 }
  797.                 case 'P':
  798.                     if( p_input )
  799.                     {
  800.                         snprintf( buf, 10, "%2.1lf",
  801.                                   var_GetFloat( p_input, "position" ) * 100. );
  802.                     }
  803.                     else
  804.                     {
  805.                         sprintf( buf, b_empty_if_na ? "" : "--.-%%" );
  806.                     }
  807.                     INSERT_STRING_NO_FREE( buf );
  808.                     break;
  809.                 case 'R':
  810.                     if( p_input )
  811.                     {
  812.                         int r = var_GetInteger( p_input, "rate" );
  813.                         snprintf( buf, 10, "%d.%d", r/1000, r%1000 );
  814.                     }
  815.                     else
  816.                     {
  817.                         sprintf( buf, b_empty_if_na ? "" : "-" );
  818.                     }
  819.                     INSERT_STRING_NO_FREE( buf );
  820.                     break;
  821.                 case 'S':
  822.                     if( p_input )
  823.                     {
  824.                         int r = var_GetInteger( p_input, "sample-rate" );
  825.                         snprintf( buf, 10, "%d.%d", r/1000, (r/100)%10 );
  826.                     }
  827.                     else
  828.                     {
  829.                         sprintf( buf, b_empty_if_na ? "" : "-" );
  830.                     }
  831.                     INSERT_STRING_NO_FREE( buf );
  832.                     break;
  833.                 case 'T':
  834.                     if( p_input )
  835.                     {
  836.                         int64_t i_time = var_GetTime( p_input, "time" );
  837.                         sprintf( buf, "%02d:%02d:%02d",
  838.                             (int)( i_time / ( 3600000000 ) ),
  839.                             (int)( ( i_time / ( 60000000 ) ) % 60 ),
  840.                             (int)( ( i_time / 1000000 ) % 60 ) );
  841.                     }
  842.                     else
  843.                     {
  844.                         sprintf( buf, b_empty_if_na ? "" :  "--:--:--" );
  845.                     }
  846.                     INSERT_STRING_NO_FREE( buf );
  847.                     break;
  848.                 case 'U':
  849.                     if( p_item )
  850.                     {
  851.                         INSERT_STRING( input_item_GetPublisher( p_item ) );
  852.                     }
  853.                     break;
  854.                 case 'V':
  855.                 {
  856.                     audio_volume_t volume;
  857.                     aout_VolumeGet( p_object, &volume );
  858.                     snprintf( buf, 10, "%d", volume );
  859.                     INSERT_STRING_NO_FREE( buf );
  860.                     break;
  861.                 }
  862.                 case '_':
  863.                     *(dst+d) = 'n';
  864.                     d++;
  865.                     break;
  866.                 case ' ':
  867.                     b_empty_if_na = true;
  868.                     break;
  869.                 default:
  870.                     *(dst+d) = *s;
  871.                     d++;
  872.                     break;
  873.             }
  874.             if( *s != ' ' )
  875.                 b_is_format = false;
  876.         }
  877.         else if( *s == '$' )
  878.         {
  879.             b_is_format = true;
  880.             b_empty_if_na = false;
  881.         }
  882.         else
  883.         {
  884.             *(dst+d) = *s;
  885.             d++;
  886.         }
  887.         s++;
  888.     }
  889.     *(dst+d) = '';
  890.     if( p_input )
  891.         vlc_object_release( p_input );
  892.     return dst;
  893. }
  894. #undef INSERT_STRING
  895. #undef INSERT_STRING_NO_FREE
  896. /**
  897.  * Apply str format time and str format meta
  898.  */
  899. char *__str_format( vlc_object_t *p_this, const char *psz_src )
  900. {
  901.     char *psz_buf1, *psz_buf2;
  902.     psz_buf1 = str_format_time( psz_src );
  903.     psz_buf2 = str_format_meta( p_this, psz_buf1 );
  904.     free( psz_buf1 );
  905.     return psz_buf2;
  906. }
  907. /**
  908.  * Remove forbidden characters from filenames (including slashes)
  909.  */
  910. char* filename_sanitize( const char *str_origin )
  911. {
  912.     char *str = strdup( str_origin );
  913.     char *str_base = str;
  914.     if( *str == '.' && (str[1] == '' || (str[1] == '.' && str[2] == '' ) ) )
  915.     {
  916.         while( *str )
  917.         {
  918.             *str = '_';
  919.             str++;
  920.         }
  921.         return str_base;
  922.     }
  923. #if defined( WIN32 )
  924.     // Change leading spaces into underscores
  925.     while( *str && *str == ' ' )
  926.         *str++ = '_';
  927. #endif
  928.     while( *str )
  929.     {
  930.         switch( *str )
  931.         {
  932.             case '/':
  933. #if defined( __APPLE__ )
  934.             case ':':
  935. #elif defined( WIN32 )
  936.             case '\':
  937.             case '*':
  938.             case '"':
  939.             case '?':
  940.             case ':':
  941.             case '|':
  942.             case '<':
  943.             case '>':
  944. #endif
  945.                 *str = '_';
  946.         }
  947.         str++;
  948.     }
  949. #if defined( WIN32 )
  950.     // Change trailing spaces into underscores
  951.     str--;
  952.     while( str != str_base )
  953.     {
  954.         if( *str != ' ' )
  955.             break;
  956.         *str-- = '_';
  957.     }
  958. #endif
  959.     return str_base;
  960. }
  961. /**
  962.  * Remove forbidden characters from full paths (leaves slashes)
  963.  */
  964. void path_sanitize( char *str )
  965. {
  966. #ifdef WIN32
  967.     /* check drive prefix if path is absolute */
  968.     if( (((unsigned char)(str[0] - 'A') < 26)
  969.       || ((unsigned char)(str[0] - 'a') < 26)) && (':' == str[1]) )
  970.         str += 2;
  971. #endif
  972.     while( *str )
  973.     {
  974. #if defined( __APPLE__ )
  975.         if( *str == ':' )
  976.             *str = '_';
  977. #elif defined( WIN32 )
  978.         if( strchr( "*"?:|<>", *str ) )
  979.             *str = '_';
  980.         if( *str == '/' )
  981.             *str = DIR_SEP_CHAR;
  982. #endif
  983.         str++;
  984.     }
  985. }
  986. #include <vlc_url.h>
  987. /**
  988.  * Convert a file path to an URI. If already an URI, do nothing.
  989.  */
  990. char *make_URI (const char *path)
  991. {
  992.     if (path == NULL)
  993.         return NULL;
  994.     if (strstr (path, "://") != NULL)
  995.         return strdup (path); /* Already an URI */
  996.     /* Note: VLC cannot handle URI schemes without double slash after the
  997.      * scheme name (such as mailto: or news:). */
  998.     char *buf;
  999. #ifdef WIN32
  1000.     if (isalpha (path[0]) && (path[1] == ':'))
  1001.     {
  1002.         if (asprintf (&buf, "file:///%c:", path[0]) == -1)
  1003.             buf = NULL;
  1004.         path += 2;
  1005.     }
  1006.     else
  1007. #endif
  1008.     if (!strncmp (path, "\\", 2))
  1009.     {   /* Windows UNC paths */
  1010. #ifndef WIN32
  1011.         /* \hostsharepath -> smb://host/share/path */
  1012.         if (strchr (path + 2, '\') != NULL)
  1013.         {   /* Convert antislashes to slashes */
  1014.             char *dup = strdup (path);
  1015.             if (dup == NULL)
  1016.                 return NULL;
  1017.             for (size_t i = 2; dup[i]; i++)
  1018.                 if (dup[i] == '\')
  1019.                     dup[i] = DIR_SEP_CHAR;
  1020.             char *ret = make_URI (dup);
  1021.             free (dup);
  1022.             return ret;
  1023.         }
  1024. # define SMB_SCHEME "smb"
  1025. #else
  1026.         /* \hostsharepath -> file://host/share/path */
  1027. # define SMB_SCHEME "file"
  1028. #endif
  1029.         size_t hostlen = strcspn (path + 2, DIR_SEP);
  1030.         buf = malloc (sizeof (SMB_SCHEME) + 3 + hostlen);
  1031.         if (buf != NULL)
  1032.             snprintf (buf, sizeof (SMB_SCHEME) + 3 + hostlen,
  1033.                       SMB_SCHEME"://%s", path + 2);
  1034.         path += 2 + hostlen;
  1035.     }
  1036.     else
  1037.     if (path[0] != DIR_SEP_CHAR)
  1038.     {   /* Relative path: prepend the current working directory */
  1039.         char cwd[PATH_MAX];
  1040.         if (getcwd (cwd, sizeof (cwd)) == NULL) /* FIXME: UTF8? */
  1041.             return NULL;
  1042.         if (asprintf (&buf, "%s/%s", cwd, path) == -1)
  1043.             return NULL;
  1044.         char *ret = make_URI (buf);
  1045.         free (buf);
  1046.         return ret;
  1047.     }
  1048.     else
  1049.         buf = strdup ("file://");
  1050.     if (buf == NULL)
  1051.         return NULL;
  1052.     assert (path[0] == DIR_SEP_CHAR);
  1053.     /* Absolute file path */
  1054.     for (const char *ptr = path + 1;; ptr++)
  1055.     {
  1056.         size_t len = strcspn (ptr, DIR_SEP);
  1057.         char *component = encode_URI_bytes (ptr, len);
  1058.         if (component == NULL)
  1059.         {
  1060.             free (buf);
  1061.             return NULL;
  1062.         }
  1063.         char *uri;
  1064.         int val = asprintf (&uri, "%s/%s", buf, component);
  1065.         free (component);
  1066.         free (buf);
  1067.         if (val == -1)
  1068.             return NULL;
  1069.         buf = uri;
  1070.         ptr += len;
  1071.         if (*ptr == '')
  1072.             return buf;
  1073.     }
  1074. }