]> git.sesse.net Git - vlc/blobdiff - src/text/strings.c
A few sprintf()+n in text/strings.c
[vlc] / src / text / strings.c
index 8a0229ce20ccb5e7b56546ffe5e87efd2841cd2a..c73dec683335cad5362926ee4ae1ecc35769472c 100644 (file)
@@ -2,6 +2,7 @@
  * strings.c: String related functions
  *****************************************************************************
  * Copyright (C) 2006 the VideoLAN team
+ * Copyright (C) 2008-2009 Rémi Denis-Courmont
  * $Id$
  *
  * Authors: Antoine Cellerier <dionoea at videolan dot org>
@@ -35,6 +36,7 @@
 
 /* Needed by str_format_time */
 #include <time.h>
+#include <limits.h>
 
 /* Needed by str_format_meta */
 #include <vlc_input.h>
 #include <vlc_charset.h>
 
 /**
- * Unescape URI encoded string
- * \return decoded duplicated string
- */
-char *unescape_URI_duplicate( const char *psz )
-{
-    char *psz_dup = strdup( psz );
-    unescape_URI( psz_dup );
-    return psz_dup;
-}
-
-/**
- * Unescape URI encoded string in place
- * \return nothing
- */
-void unescape_URI( char *psz )
-{
-    unsigned char *in = (unsigned char *)psz, *out = in, c;
-    if( psz == NULL )
-        return;
-
-    while( ( c = *in++ ) != '\0' )
-    {
-        switch( c )
-        {
-            case '%':
-            {
-                char val[5], *pval = val;
-                unsigned long cp;
-
-                switch( c = *in++ )
-                {
-                    case '\0':
-                        return;
-
-                    case 'u':
-                    case 'U':
-                        if( ( *pval++ = *in++ ) == '\0' )
-                            return;
-                        if( ( *pval++ = *in++ ) == '\0' )
-                            return;
-                        c = *in++;
-
-                    default:
-                        *pval++ = c;
-                        if( ( *pval++ = *in++ ) == '\0' )
-                            return;
-                        *pval = '\0';
-                }
-
-                cp = strtoul( val, NULL, 0x10 );
-                if( cp < 0x80 )
-                    *out++ = cp;
-                else
-                if( cp < 0x800 )
-                {
-                    *out++ = (( cp >>  6)         | 0xc0);
-                    *out++ = (( cp        & 0x3f) | 0x80);
-                }
-                else
-                {
-                    assert( cp < 0x10000 );
-                    *out++ = (( cp >> 12)         | 0xe0);
-                    *out++ = (((cp >>  6) & 0x3f) | 0x80);
-                    *out++ = (( cp        & 0x3f) | 0x80);
-                }
-                break;
-            }
-
-            /* + is not a special case - it means plus, not space. */
-
-            default:
-                /* Inserting non-ASCII or non-printable characters is unsafe,
-                 * and no sane browser will send these unencoded */
-                if( ( c < 32 ) || ( c > 127 ) )
-                    *out++ = '?';
-                else
-                    *out++ = c;
-        }
-    }
-    *out = '\0';
-}
-
-/**
- * Decode encoded URI string
+ * Decode encoded URI component. See also decode_URI().
  * \return decoded duplicated string
  */
 char *decode_URI_duplicate( const char *psz )
@@ -141,14 +60,23 @@ char *decode_URI_duplicate( const char *psz )
 }
 
 /**
- * Decode encoded URI string in place
- * \return nothing
+ * Decode an encoded URI component in place.
+ * <b>This function does NOT decode entire URIs.</b>
+ * It decodes components (e.g. host name, directory, file name).
+ * Decoded URIs do not exist in the real world (see RFC3986 §2.4).
+ * Complete URIs are always "encoded" (or they are syntaxically invalid).
+ *
+ * Note that URI encoding is different from Javascript escaping. Especially,
+ * white spaces and Unicode non-ASCII code points are encoded differently.
+ *
+ * \return psz on success, NULL if it was not properly encoded
  */
-void decode_URI( char *psz )
+char *decode_URI( char *psz )
 {
     unsigned char *in = (unsigned char *)psz, *out = in, c;
+
     if( psz == NULL )
-        return;
+        return NULL;
 
     while( ( c = *in++ ) != '\0' )
     {
@@ -160,14 +88,14 @@ void decode_URI( char *psz )
 
                 if( ( ( hex[0] = *in++ ) == 0 )
                  || ( ( hex[1] = *in++ ) == 0 ) )
-                    return;
+                    return NULL;
 
                 hex[2] = '\0';
                 *out++ = (unsigned char)strtoul( hex, NULL, 0x10 );
                 break;
             }
 
-            case '+':
+            case '+': /* This is HTTP forms, not URI decoding... */
                 *out++ = ' ';
                 break;
 
@@ -182,6 +110,7 @@ void decode_URI( char *psz )
     }
     *out = '\0';
     EnsureUTF8( psz );
+    return psz;
 }
 
 static inline bool isurisafe( int c )
@@ -193,23 +122,13 @@ static inline bool isurisafe( int c )
             || ( strchr( "-._~", c ) != NULL );
 }
 
-/**
- * Encodes an URI component (RFC3986 §2).
- *
- * @param psz_uri nul-terminated UTF-8 representation of the component.
- * Obviously, you can't pass an URI containing a nul character, but you don't
- * want to do that, do you?
- *
- * @return encoded string (must be free()'d), or NULL for ENOMEM.
- */
-char *encode_URI_component( const char *psz_uri )
+static char *encode_URI_bytes (const char *psz_uri, size_t len)
 {
-    char *psz_enc = malloc ((3 * strlen (psz_uri)) + 1), *out = psz_enc;
-
+    char *psz_enc = malloc (3 * len + 1), *out = psz_enc;
     if (psz_enc == NULL)
         return NULL;
 
-    while (*psz_uri)
+    for (size_t i = 0; i < len; i++)
     {
         static const char hex[16] = "0123456789ABCDEF";
         uint8_t c = *psz_uri;
@@ -232,6 +151,21 @@ char *encode_URI_component( const char *psz_uri )
     return out ? out : psz_enc; /* realloc() can fail (safe) */
 }
 
+/**
+ * Encodes an URI component (RFC3986 §2).
+ *
+ * @param psz_uri nul-terminated UTF-8 representation of the component.
+ * Obviously, you can't pass an URI containing a nul character, but you don't
+ * want to do that, do you?
+ *
+ * @return encoded string (must be free()'d), or NULL for ENOMEM.
+ */
+char *encode_URI_component( const char *psz_uri )
+{
+    return encode_URI_bytes (psz_uri, strlen (psz_uri));
+}
+
+
 static const struct xml_entity_s
 {
     char    psz_entity[8];
@@ -858,14 +792,14 @@ char *__str_format_meta( vlc_object_t *p_object, const char *string )
                     if( p_item )
                     {
                         mtime_t i_duration = input_item_GetDuration( p_item );
-                        sprintf( buf, "%02d:%02d:%02d",
+                        snprintf( buf, 10, "%02d:%02d:%02d",
                                  (int)(i_duration/(3600000000)),
                                  (int)((i_duration/(60000000))%60),
                                  (int)((i_duration/1000000)%60) );
                     }
                     else
                     {
-                        sprintf( buf, b_empty_if_na ? "" : "--:--:--" );
+                        snprintf( buf, 10, b_empty_if_na ? "" : "--:--:--" );
                     }
                     INSERT_STRING_NO_FREE( buf );
                     break;
@@ -892,14 +826,14 @@ char *__str_format_meta( vlc_object_t *p_object, const char *string )
                     {
                         mtime_t i_duration = input_item_GetDuration( p_item );
                         int64_t i_time = var_GetInteger( p_input, "time" );
-                        sprintf( buf, "%02d:%02d:%02d",
+                        snprintf( buf, 10, "%02d:%02d:%02d",
                      (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 ? "" : "--:--:--" );
+                        snprintf( buf, 10, b_empty_if_na ? "" : "--:--:--" );
                     }
                     INSERT_STRING_NO_FREE( buf );
                     break;
@@ -928,7 +862,7 @@ char *__str_format_meta( vlc_object_t *p_object, const char *string )
                     }
                     else
                     {
-                        sprintf( buf, b_empty_if_na ? "" : "--.-%%" );
+                        snprintf( buf, 10, b_empty_if_na ? "" : "--.-%%" );
                     }
                     INSERT_STRING_NO_FREE( buf );
                     break;
@@ -960,14 +894,14 @@ char *__str_format_meta( vlc_object_t *p_object, const char *string )
                     if( p_input )
                     {
                         int64_t i_time = var_GetInteger( p_input, "time" );
-                        sprintf( buf, "%02d:%02d:%02d",
+                        snprintf( buf, 10, "%02d:%02d:%02d",
                             (int)( i_time / ( 3600000000 ) ),
                             (int)( ( i_time / ( 60000000 ) ) % 60 ),
                             (int)( ( i_time / 1000000 ) % 60 ) );
                     }
                     else
                     {
-                        sprintf( buf, b_empty_if_na ? "" :  "--:--:--" );
+                        snprintf( buf, 10, b_empty_if_na ? "" :  "--:--:--" );
                     }
                     INSERT_STRING_NO_FREE( buf );
                     break;
@@ -1120,3 +1054,78 @@ void path_sanitize( char *str )
         str++;
     }
 }
+
+#include <vlc_url.h>
+
+/**
+ * Convert a file path to an URI. If already an URI, do nothing.
+ */
+char *make_URI (const char *path)
+{
+    if (path == NULL)
+        return NULL;
+    if (strstr (path, "://") != NULL)
+        return strdup (path); /* Already an URI */
+    /* Note: VLC cannot handle URI schemes without double slash after the
+     * scheme name (such as mailto: or news:). */
+
+    char *buf;
+#ifdef WIN32
+    if (isalpha (path[0]) && (path[1] == ':'))
+    {
+        if (asprintf (&buf, "file:///%c:", path[0]) == -1)
+            buf = NULL;
+        path += 2;
+    }
+    else
+#endif
+#if 0
+    /* Windows UNC paths (file://host/share/path instead of file:///path) */
+    if (!strncmp (path, "\\\\", 2))
+    {
+        path += 2;
+        buf = strdup ("file://");
+    }
+    else
+#endif
+    if (path[0] != DIR_SEP_CHAR)
+    {   /* Relative path: prepend the current working directory */
+        char cwd[PATH_MAX];
+
+        if (getcwd (cwd, sizeof (cwd)) == NULL) /* FIXME: UTF8? */
+            return NULL;
+        if (asprintf (&buf, "%s/%s", cwd, path) == -1)
+            return NULL;
+        char *ret = make_URI (buf);
+        free (buf);
+        return ret;
+    }
+    else
+        buf = strdup ("file://");
+    if (buf == NULL)
+        return NULL;
+
+    assert (path[0] == DIR_SEP_CHAR);
+
+    /* Absolute file path */
+    for (const char *ptr = path + 1;; ptr++)
+    {
+        size_t len = strcspn (ptr, DIR_SEP);
+        char *component = encode_URI_bytes (ptr, len);
+        if (component == NULL)
+        {
+            free (buf);
+            return NULL;
+        }
+        char *uri;
+        int val = asprintf (&uri, "%s/%s", buf, component);
+        free (component);
+        free (buf);
+        if (val == -1)
+            return NULL;
+        buf = uri;
+        ptr += len;
+        if (*ptr == '\0')
+            return buf;
+    }
+}