[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[vidalia-svn] r4350: Add support for escaping and unescaping non-ASCII characters (vidalia/trunk/src/common)



Author: edmanm
Date: 2010-07-14 11:43:39 -0400 (Wed, 14 Jul 2010)
New Revision: 4350

Modified:
   vidalia/trunk/src/common/stringutil.cpp
Log:

Add support for escaping and unescaping non-ASCII characters in strings
using the local 8-bit character encoding.


Modified: vidalia/trunk/src/common/stringutil.cpp
===================================================================
--- vidalia/trunk/src/common/stringutil.cpp	2010-07-07 15:02:30 UTC (rev 4349)
+++ vidalia/trunk/src/common/stringutil.cpp	2010-07-14 15:43:39 UTC (rev 4350)
@@ -123,44 +123,119 @@
   return hex;
 }
 
-/** Given a string <b>str</b>, this function returns a quoted string with all
- * '"' and '\' characters escaped with a single '\'. */
+/** Given an ASCII string <b>str</b>, this function returns a quoted string
+ * with all escaped characters unescaped. Non-ASCII characters in the string
+ * will be converted to the local 8-bit character encoding and encoded using
+ * an escaped octal sequence. The returned string will thus contain only
+ * printable ASCII characters. */
 QString
 string_escape(const QString &str)
 {
-  QString out;
-  out.append("\"");
-  for (int i = 0; i < str.length(); i++) {
-    if (str[i] == '\"' || str[i] == '\\')
-      out.append('\\');
-    out.append(str[i]);
+  QByteArray in;
+  QByteArray out;
+  char c;
+
+  in = str.toLocal8Bit();
+  out.append('\"');
+  for (int i = 0; i < in.length(); i++) {
+    c = in[i];
+    switch (c) {
+      case '\"':
+        out.append("\\\"");
+        break;
+      case '\\':
+        out.append("\\\\");
+        break;
+      case '\n':
+        out.append("\\n");
+        break;
+      case '\r':
+        out.append("\\r");
+        break;
+      case '\t':
+        out.append("\\t");
+        break;
+      default:
+        if (QChar(c).isPrint() && c < 127) {
+          out.append(c);
+        } else {
+          out.append('\\');
+          out.append(QString::number(c, 8).toAscii());
+        }
+    }
   }
-  out.append("\"");
-  return out;
+  out.append('\"');
+  return QString::fromAscii(out);
 }
 
 /** Given a quoted string <b>str</b>, this function returns an unquoted,
- * unescaped string. <b>str</b> must start and end with an unescaped quote. */
+ * unescaped string. <b>str</b> must start and end with an unescaped DQUOTE,
+ * The input string must contain only ASCII characters; however, non-ASCII
+ * characters can be included by encoding their byte sequences in either
+ * escaped hexadecimal (e.g., "\xFF") or octal (e.g., "\301"). The result
+ * will be converted to a QString using the local 8-bit encoding. */
 QString
 string_unescape(const QString &str, bool *ok)
 {
-  QString out;
- 
+  QByteArray out;
+  int i;
+
   /* The string must start and end with an unescaped dquote */
-  if (str.length() < 2 || !str.startsWith("\"") || !str.endsWith("\"") ||
-      (str.endsWith("\\\"") && !str.endsWith("\\\\\""))) {
-    if (ok)
-      *ok = false;
-    return QString();
+  if (str.length() < 2)
+    goto err;
+  if (! str.startsWith("\"") || ! str.endsWith("\""))
+    goto err;
+  if (str.endsWith("\\\"") && ! str.endsWith("\\\\\""))
+    goto err;
+
+  i = 1;
+  while (i < str.length()-1) {
+    if (str[i] == QLatin1Char('\\')) {
+      QChar c = str[++i];
+      if (c == QLatin1Char('n')) {
+        out.append('\n');
+      } else if (c == QLatin1Char('r')) {
+        out.append('\r');
+      } else if (c == QLatin1Char('t')) {
+        out.append('\t');
+      } else if (c == QLatin1Char('x')) {
+        if (i + 2 >= str.length())
+          goto err;
+        bool isHex;
+        char val = static_cast<char>(str.mid(i+1, 2).toUInt(&isHex, 16));
+        if (! isHex)
+          goto err;
+        out.append(val);
+        i = i + 2;
+      } else if (c.isDigit()) {
+        if (i + 2 >= str.length())
+          goto err;
+        bool isOctal;
+        uint val = str.mid(i, 3).toUInt(&isOctal, 8);
+        if (! isOctal || val > 255)
+          goto err;
+        out.append(static_cast<char>(val));
+        i = i + 2;
+      } else {
+        out.append(str[i].toLatin1());
+      }
+    } else if (str[i] == QLatin1Char('\"')) {
+      /* Unescaped DQUOTE in the middle of the string, so terminate
+       * processing and return a failure. */
+      goto err;
+    } else {
+      out.append(str[i].toLatin1());
+    }
+    i++;
   }
-  for (int i = 1; i < str.length()-1; i++) {
-    if (str[i] == '\\')
-      i++;
-    out.append(str[i]);
-  }
   if (ok)
     *ok = true;
-  return out;
+  return QString::fromLocal8Bit(out.data());
+
+err:
+  if (ok)
+    *ok = false;
+  return QString();
 }
 
 /** Parses a series of space-separated key[=value|="value"] tokens from