]> git.sesse.net Git - vlc/commitdiff
New VLM quoting and escaping logic that is more like the usual C one[1]
authorRémi Denis-Courmont <rem@videolan.org>
Sun, 3 Dec 2006 07:05:21 +0000 (07:05 +0000)
committerRémi Denis-Courmont <rem@videolan.org>
Sun, 3 Dec 2006 07:05:21 +0000 (07:05 +0000)
- Do not validate quotes recursively (there is no reason to do that)
  and it is really unlike anything else.
- Do not allow escaping non-ASCII (to avoid UTF-8 breakages)
  or non-printable characters.
[1] we don't support every features of C escaping though

src/misc/vlm.c

index eaeeb01596c60bd3c0c8f16be9dd3e9d541115ad..b580a267419066dc530a9137dd6bd674bea2513d 100644 (file)
@@ -253,89 +253,88 @@ int vlm_Load( vlm_t *p_vlm, const char *psz_file )
     return 0;
 }
 
-/*****************************************************************************
- * FindEndCommand
- *****************************************************************************/
-static const char *FindEndCommand( const char *psz_sent )
+/**
+ * FindCommandEnd: look for the end of a possibly quoted string
+ * @return NULL on mal-formatted string,
+ * pointer paste the last character otherwise.
+ */
+static const char *FindCommandEnd (const char *psz_sent)
 {
-    vlc_bool_t b_escape = VLC_FALSE;
+    char quote = psz_sent[0], c;
+    static const char quotes[] = "'\"";
+
+    if (quote && (strchr (quotes, quote) == NULL))
+        quote = '\0';
 
-    switch( *psz_sent )
+    while ((c = *psz_sent) != '\0')
     {
-    case '\"':
-        psz_sent++;
-        while( ( *psz_sent != '\"' || b_escape == VLC_TRUE )
-               && ( *psz_sent != '\0' ) )
+        if (c == '\\')
         {
-            if( *psz_sent == '\'' && b_escape == VLC_FALSE )
-            {
-                psz_sent = FindEndCommand( psz_sent );
-                if( psz_sent == NULL ) return NULL;
-            }
-            else if( *psz_sent++ == '\\' && b_escape == VLC_FALSE )
-                b_escape = VLC_TRUE;
-            else
-                b_escape = VLC_FALSE;
-        }
+            if (*psz_sent == '\0')
+                return NULL; // cannot escape "nothing"
 
-        if( *psz_sent == '\"' )
-        {
-            psz_sent++;
-            return psz_sent;
+            psz_sent++; // skips escaped character
         }
+        else
+        if (c == quote) // non-escaped matching quote
+            return psz_sent + 1;
+        else
+        if (isblank (c)) // non-escaped blank
+            return psz_sent;
 
-        /* *psz_sent == '\0' -> number of " is incorrect */
-        else return NULL;
-
-        break;
-
-    case '\'':
         psz_sent++;
-        while( ( *psz_sent != '\'' || b_escape == VLC_TRUE )
-                 && ( *psz_sent != '\0' ) )
-        {
-            if( *psz_sent == '\"' && b_escape == VLC_FALSE )
-            {
-                psz_sent = FindEndCommand( psz_sent );
-                if( psz_sent == NULL ) return NULL;
-            }
-            else if( *psz_sent++ == '\\' && b_escape == VLC_FALSE )
-                b_escape = VLC_TRUE;
-            else
-                b_escape = VLC_FALSE;
-        }
+    }
 
-        if( *psz_sent == '\'' )
-        {
-            psz_sent++;
-            return psz_sent;
-        }
+    // error (NULL) if we could not find a matching quote
+    return quote ? NULL : psz_sent;
+}
 
-        /* *psz_sent == '\0' -> number of " is incorrect */
-        else return NULL;
 
-        break;
+/**
+ * Unescape (C-style) a nul-terminated string.
+ * Note that in and out can be identical.
+ *
+ * @param out output buffer (at least <strlen (in) + 1> characters long)
+ * @param in nul-terminated string to be unescaped
+ *
+ * @return 0 on success, -1 on error.
+ */
+static int Unescape (char *out, const char *in)
+{
+    char c;
 
-    default: /* now we can look for spaces */
-        while( ( *psz_sent != ' ' ) && ( *psz_sent != '\0' ) )
+    while ((c = *in++) != '\0')
+    {
+        if (c == '\\')
         {
-            if( ( ( *psz_sent == '\'' ) || ( *psz_sent == '\"' ) )
-                && b_escape == VLC_FALSE )
+            switch (c = *in++)
             {
-                psz_sent = FindEndCommand( psz_sent );
-                if( psz_sent == NULL ) return NULL;
+                case 'n':
+                    *out++ = '\n';
+                    continue;
+
+                case 't':
+                    *out++ = '\t';
+                    continue;
+
+                case 'r':
+                    *out++ = '\r';
+                    continue;
             }
-            else if( *psz_sent++ == '\\' && b_escape == VLC_FALSE )
-                b_escape = VLC_TRUE;
-            else
-                b_escape = VLC_FALSE;
 
+            // Only allow printable ASCII characters
+            // (in particular, no nul and no extended characters)
+            if (c < 32)
+                return -1;
         }
-
-        return psz_sent;
+        *out++ = c;
     }
+
+    *out = '\0';
+    return 0;
 }
 
+
 /*****************************************************************************
  * ExecuteCommand: The main state machine
  *****************************************************************************
@@ -353,7 +352,6 @@ static int ExecuteCommand( vlm_t *p_vlm, const char *psz_command,
     /* First, parse the line and cut it */
     while( *psz_cmd != '\0' )
     {
-
         if( *psz_cmd == ' ' || *psz_cmd == '\t' )
         {
             psz_cmd++;
@@ -361,10 +359,6 @@ static int ExecuteCommand( vlm_t *p_vlm, const char *psz_command,
         else
         {
             const char *psz_temp;
-            const char *psz_buf;
-            char *psz_dst;
-            vlc_bool_t b_escape = VLC_FALSE;
-            int   i_temp;
 
             /* support for comments */
             if( i_command == 0 && *psz_cmd == '#')
@@ -373,7 +367,7 @@ static int ExecuteCommand( vlm_t *p_vlm, const char *psz_command,
                 goto success;
             }
 
-            psz_temp = FindEndCommand( psz_cmd );
+            psz_temp = FindCommandEnd( psz_cmd );
 
             if( psz_temp == NULL )
             {
@@ -381,31 +375,14 @@ static int ExecuteCommand( vlm_t *p_vlm, const char *psz_command,
                 goto error;
             }
 
-            i_temp = psz_temp - psz_cmd;
-
             ppsz_command = realloc( ppsz_command, (i_command + 1) *
                                     sizeof(char*) );
-            ppsz_command[ i_command ] = malloc( (i_temp + 1) * sizeof(char) );
+            ppsz_command[i_command] = strndup (psz_cmd, psz_temp - psz_cmd);
 
             /* unescape ", ' and \ ... and everything else */
-            psz_buf = psz_cmd;
-            psz_dst = ppsz_command[ i_command ];
-            while( i_temp-- )
-            {
-                if( *psz_buf == '\\' && b_escape == VLC_FALSE )
-                    b_escape = VLC_TRUE;
-                else
-                {
-                    b_escape = VLC_FALSE;
-                    *psz_dst = *psz_buf;
-                    psz_dst++;
-                }
-                psz_buf++;
-            }
-            *psz_dst = '\0';
+            Unescape (ppsz_command[i_command], ppsz_command[i_command]);
 
             i_command++;
-
             psz_cmd = psz_temp;
         }
     }