Implement percent url encoder and decoder
[libi2ncommon] / src / restricted_html.cpp
index a157564..d59bcff 100644 (file)
@@ -25,6 +25,8 @@ on this file might be covered by the GNU General Public License.
  */
 
 #include <string>
+#include <sstream>
+#include <iomanip>
 
 #include <stringfunc.hxx>
 #include <restricted_html.hpp>
@@ -37,4 +39,129 @@ namespace I2n
 
 
 
+/**
+ * @brief Replace all "+" characters found in s to spaces (" ").
+ *
+ * @param s string that will be modified.
+ */
+static void unescape_space(string &s)
+{
+    string::size_type pos;
+    while ((pos=s.find('+')) != string::npos)
+        s[pos]=' ';
+}
+
+/**
+ * @brief Converts a hexadecimal sequence to its respective character.
+ *
+ * @param s string of size 2. Example: "77"
+ * @return respective character represented by the hex sequence.
+ */
+static char x2c(const string& s)
+{
+    char digit;
+    digit=(s[0]>='A' ? ((s[0] & 0xdf)-'A')+10 : (s[0]-'0'));
+    digit*=16;
+    digit+=(s[1]>='A' ? ((s[1] & 0xdf)-'A')+10 : (s[1]-'0'));
+    return digit;
+}
+
+/**
+ * @brief Scan a string to find escaped hex chars in the format "%HH" and replace
+ * for their respective character.
+ * Example: "www%2E" becomes "www."
+ *
+ * @param s String that will be modified.
+ */
+static void unescape_hex(string& s)
+{
+    static char hex_escape='%';
+    string::size_type escape_pos;
+    string hex_seq;
+    string rest=s;
+    for (s=""; ((escape_pos=rest.find(hex_escape)) != string::npos);)
+    {
+        if (escape_pos+2<static_cast<unsigned int>(rest.length())
+            && ::isalnum(rest[escape_pos+1]) && ::isalnum(rest[escape_pos+2]))
+        {
+            hex_seq=rest.substr(escape_pos+1,2);
+            s=s+rest.substr(0,escape_pos)+x2c(hex_seq);
+            rest=rest.erase(0,escape_pos+3);
+        }
+        else
+        {
+            s=s+rest.substr(0,escape_pos+1);
+            rest=rest.erase(0,escape_pos+1);
+        }
+    }
+    s+=rest;
+}
+
+/**
+* @brief Decode url that contains percent-encoding. Replace space " " with "+".
+* Example: "%77%77%77%2E" becomes "www."
+*
+* @param s url string.
+* @return the decoded string.
+*/
+string decode_url(string s)
+{
+    unescape_space (s);
+    unescape_hex (s);
+    return (s);
+}
+
+/**
+ * @brief Verify if the parameter character requires encoding, If it is non
+ * alphanumeric or valid ascii signs.
+ *
+ * @param c character to be verified.
+ * @return true if the character should be encoded.
+ */
+bool needs_encoding (const char &c)
+{
+    // some valid ascii signs
+    if (c == '_' || c == '-')
+        return false;
+
+    // is digit?
+    if (c > 47 && c < 58)
+        return false;
+
+    // is uppercase letter?
+    if (c > 64 && c < 91)
+        return false;
+
+    // is lowercase letter?
+    if (c > 96 && c < 123)
+        return false;
+
+    return true;
+}
+
+/**
+* @brief Encode url with percent-encoding. Any non-alphanumeric character is
+* converted to its hex value with the percent character (%) as prefix, except "_"
+* and "-". Replace space " " with "+".
+*
+* @param s url string.
+* @return the encoded url string.
+*/
+string encode_url(string s)
+{
+    // convert non-alphanumeric characters to hex, convert space to +
+    ostringstream out;
+    for (string::iterator pos2=s.begin(); pos2 != s.end(); pos2++)
+    {
+        if (*pos2 == ' ')
+            out << '+';
+        else if (needs_encoding (*pos2))
+            out << '%' << std::uppercase << setw(2) << setfill('0') << \
+                std::hex << (int)(unsigned char)*pos2;
+        else
+            out << (*pos2);
+    }
+
+    return out.str();
+}
 } // eo namespace I2n