Browse Source

Implementing encodeUri

Sebastien Ros 11 years ago
parent
commit
09781f1121

+ 1 - 0
Jint.Tests.Ecma/Ecma/15.1.2.4.cs

@@ -2,6 +2,7 @@ using Xunit;
 
 
 namespace Jint.Tests.Ecma
 namespace Jint.Tests.Ecma
 {
 {
+    [Trait("Category", "Pass")]
     public class Test_15_1_2_4 : EcmaTest
     public class Test_15_1_2_4 : EcmaTest
     {
     {
         [Fact]
         [Fact]

+ 1 - 0
Jint.Tests.Ecma/Ecma/15.1.2.5.cs

@@ -2,6 +2,7 @@ using Xunit;
 
 
 namespace Jint.Tests.Ecma
 namespace Jint.Tests.Ecma
 {
 {
+    [Trait("Category", "Pass")]
     public class Test_15_1_2_5 : EcmaTest
     public class Test_15_1_2_5 : EcmaTest
     {
     {
         [Fact]
         [Fact]

+ 1 - 0
Jint.Tests.Ecma/Ecma/15.1.3.3.cs

@@ -2,6 +2,7 @@ using Xunit;
 
 
 namespace Jint.Tests.Ecma
 namespace Jint.Tests.Ecma
 {
 {
+    [Trait("Category", "Pass")]
     public class Test_15_1_3_3 : EcmaTest
     public class Test_15_1_3_3 : EcmaTest
     {
     {
         [Fact]
         [Fact]

+ 1 - 0
Jint.Tests.Ecma/Ecma/15.1.3.4.cs

@@ -2,6 +2,7 @@ using Xunit;
 
 
 namespace Jint.Tests.Ecma
 namespace Jint.Tests.Ecma
 {
 {
+    [Trait("Category", "Pass")]
     public class Test_15_1_3_4 : EcmaTest
     public class Test_15_1_3_4 : EcmaTest
     {
     {
         [Fact]
         [Fact]

+ 137 - 49
Jint/Native/Global/GlobalObject.cs

@@ -1,4 +1,6 @@
 using System;
 using System;
+using System.Linq;
+using System.Text;
 using Jint.Native.Object;
 using Jint.Native.Object;
 using Jint.Runtime;
 using Jint.Runtime;
 using Jint.Runtime.Interop;
 using Jint.Runtime.Interop;
@@ -13,10 +15,8 @@ namespace Jint.Native.Global
 
 
         public static GlobalObject CreateGlobalObject(Engine engine)
         public static GlobalObject CreateGlobalObject(Engine engine)
         {
         {
-            var global = new GlobalObject(engine);
-            global.Prototype = null;
-            global.Extensible = true;
-            
+            var global = new GlobalObject(engine) {Prototype = null, Extensible = true};
+
             return global;
             return global;
         }
         }
 
 
@@ -52,12 +52,12 @@ namespace Jint.Native.Global
             // Global object functions
             // Global object functions
             FastAddProperty("parseInt", new ClrFunctionInstance<object, double>(Engine, ParseInt, 2), false, false, false);
             FastAddProperty("parseInt", new ClrFunctionInstance<object, double>(Engine, ParseInt, 2), false, false, false);
             FastAddProperty("parseFloat", new ClrFunctionInstance<object, double>(Engine, ParseFloat, 1), false, false, false);
             FastAddProperty("parseFloat", new ClrFunctionInstance<object, double>(Engine, ParseFloat, 1), false, false, false);
-            FastAddProperty("isNaN", new ClrFunctionInstance<object, bool>(Engine, IsNaN), false, false, false);
-            FastAddProperty("isFinite", new ClrFunctionInstance<object, bool>(Engine, IsFinite), false, false, false);
-            FastAddProperty("decodeURI", new ClrFunctionInstance<object, string>(Engine, DecodeUri), false, false, false);
-            FastAddProperty("decodeURIComponent", new ClrFunctionInstance<object, string>(Engine, DecodeUriComponent), false, false, false);
-            FastAddProperty("encodeURI", new ClrFunctionInstance<object, string>(Engine, EncodeUri), false, false, false);
-            FastAddProperty("encodeURIComponent", new ClrFunctionInstance<object, string>(Engine, EncodeUriComponent), false, false, false);
+            FastAddProperty("isNaN", new ClrFunctionInstance<object, bool>(Engine, IsNaN ,1), false, false, false);
+            FastAddProperty("isFinite", new ClrFunctionInstance<object, bool>(Engine, IsFinite, 1), false, false, false);
+            FastAddProperty("decodeURI", new ClrFunctionInstance<object, string>(Engine, DecodeUri, 1), false, false, false);
+            FastAddProperty("decodeURIComponent", new ClrFunctionInstance<object, string>(Engine, DecodeUriComponent, 1), false, false, false);
+            FastAddProperty("encodeURI", new ClrFunctionInstance<object, string>(Engine, EncodeUri, 1), false, false, false);
+            FastAddProperty("encodeURIComponent", new ClrFunctionInstance<object, string>(Engine, EncodeUriComponent, 1), false, false, false);
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -207,7 +207,8 @@ namespace Jint.Native.Global
                     separator = '.';
                     separator = '.';
                     break;
                     break;
                 }
                 }
-                else if(c == 'e' || c == 'E')
+                
+                if(c == 'e' || c == 'E')
                 {
                 {
                     i++;
                     i++;
                     separator = 'e';
                     separator = 'e';
@@ -355,8 +356,17 @@ namespace Jint.Native.Global
             return Uri.UnescapeDataString(arguments[0].ToString().Replace("+", " "));
             return Uri.UnescapeDataString(arguments[0].ToString().Replace("+", " "));
         }
         }
 
 
-        private static readonly char[] ReservedEncoded = new [] { ';', ',', '/', '?', ':', '@', '&', '=', '+', '$', '#' };
-        private static readonly char[] ReservedEncodedComponent = new [] { '-', '_', '.', '!', '~', '*', '\'', '(', ')', '[', ']' };
+        private static readonly char[] UriReserved = {';', '/', '?', ':', '@', '&', '=', '+', '$', ','};
+
+        private static readonly char[] UriUnescaped =
+        {
+            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+            'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
+            'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_', '.', '!',
+            '~', '*', '\'', '(', ')'
+        };
+
+        private static readonly  char[] HexaMap = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
 
 
         /// <summary>
         /// <summary>
         /// http://www.ecma-international.org/ecma-262/5.1/#sec-15.1.3.2
         /// http://www.ecma-international.org/ecma-262/5.1/#sec-15.1.3.2
@@ -364,67 +374,145 @@ namespace Jint.Native.Global
         /// <param name="thisObject"></param>
         /// <param name="thisObject"></param>
         /// <param name="arguments"></param>
         /// <param name="arguments"></param>
         /// <returns></returns>
         /// <returns></returns>
-        public static string EncodeUri(object thisObject, object[] arguments)
+        public string EncodeUri(object thisObject, object[] arguments)
         {
         {
-            if (arguments.Length < 1 || arguments[0] == Undefined.Instance)
-            {
-                return "";
-            }
-
-            string encoded = Uri.EscapeDataString(arguments[0].ToString());
-
-            foreach (char c in ReservedEncoded)
-            {
-                encoded = encoded.Replace(Uri.EscapeDataString(c.ToString()), c.ToString());
-            }
+            var uriString = TypeConverter.ToString(arguments.At(0));
+            var unescapedUriSet = UriReserved.Concat(UriUnescaped).Concat(new [] {'#'}).ToArray();
 
 
-            foreach (char c in ReservedEncodedComponent)
-            {
-                encoded = encoded.Replace(Uri.EscapeDataString(c.ToString()), c.ToString());
-            }
-
-            return encoded.ToUpper();
+            return Encode(uriString, unescapedUriSet);
         }
         }
 
 
+
         /// <summary>
         /// <summary>
-        /// http://www.ecma-international.org/ecma-262/5.1/#sec-15.1.3.3
+        /// http://www.ecma-international.org/ecma-262/5.1/#sec-15.1.3.4
         /// </summary>
         /// </summary>
         /// <param name="thisObject"></param>
         /// <param name="thisObject"></param>
         /// <param name="arguments"></param>
         /// <param name="arguments"></param>
         /// <returns></returns>
         /// <returns></returns>
-        public static string DecodeUriComponent(object thisObject, object[] arguments)
+        public string EncodeUriComponent(object thisObject, object[] arguments)
         {
         {
-            if (arguments.Length < 1 || arguments[0] == Undefined.Instance)
+            var uriString = TypeConverter.ToString(arguments.At(0));
+
+            return Encode(uriString, UriUnescaped);
+        }
+
+        private string Encode(string uriString, char[] unescapedUriSet)
+        {
+            var strLen = uriString.Length;
+            var r = new StringBuilder(uriString.Length);
+            for (var k = 0; k< strLen; k++)
             {
             {
-                return "";
+                var c = uriString[k];
+                if (System.Array.IndexOf(unescapedUriSet, c) != -1)
+                {
+                    r.Append(c);
+                }
+                else
+                {
+                    if (c >= 0xDC00 && c <= 0xDBFF)
+                    {
+                        throw new JavaScriptException(Engine.UriError);
+                    }
+
+                    int v;
+                    if (c < 0xD800 || c > 0xDBFF)
+                    {
+                        v = c;
+                    }
+                    else
+                    {
+                        k++;
+                        if (k == strLen)
+                        {
+                            throw new JavaScriptException(Engine.UriError);
+                        }
+
+                        var kChar = (int) uriString[k];
+                        if (kChar < 0xDC00 || kChar > 0xDFFF)
+                        {
+                            throw new JavaScriptException(Engine.UriError);
+                        }
+
+                        v = (c - 0xD800) * 0x400 + (kChar - 0xDC00) + 0x10000;
+                    }
+
+                    byte[] octets;
+
+                    if (v >= 0 && v <= 0x007F)
+                    {
+                        // 00000000 0zzzzzzz -> 0zzzzzzz
+                        octets = new[] { (byte)v };
+                    }
+                    else if (v <= 0x07FF)
+                    {
+                        // 00000yyy yyzzzzzz ->	110yyyyy ; 10zzzzzz
+                        octets = new[]
+                        {
+                            (byte)(0xC0 | (v >> 6)), 
+                            (byte)(0x80 | (v & 0x3F))
+                        };
+                    }
+                    else if (v <= 0xD7FF)
+                    {
+                        // xxxxyyyy yyzzzzzz -> 1110xxxx; 10yyyyyy; 10zzzzzz	
+                        octets = new[]
+                        {
+                            (byte)(0xE0 | (v >> 12)), 
+                            (byte)(0x80 | ((v >> 6) & 0x3F)), 
+                            (byte)(0x80 | (v & 0x3F))
+                        };
+                    }
+                    else if (v <= 0xDFFF)
+                    {
+                        throw new JavaScriptException(Engine.UriError);
+                    }
+                    else if (v <= 0xFFFF)
+                    {
+                        octets = new[]
+                        {
+                            (byte) (0xE0 | (v >> 12)),
+                            (byte) (0x80 | ((v >> 6) & 0x3F)),
+                            (byte) (0x80 | (v & 0x3F))
+                        };
+                    }
+                    else
+                    {
+                        octets = new[]
+                        {
+                            (byte) (0xF0 | (v >> 18)),
+                            (byte) (0x80 | (v >> 12 & 0x3F)),
+                            (byte) (0x80 | (v >> 6 & 0x3F)),
+                            (byte) (0x80 | (v >> 0 & 0x3F))
+                        };
+                    }
+
+                    for (var j = 0; j < octets.Length; j++)
+                    {
+                        var jOctet = octets[j];
+                        var x1 = HexaMap[jOctet / 16];
+                        var x2 = HexaMap[jOctet % 16];
+                        r.Append('%').Append(x1).Append(x2);
+                    }
+                }
             }
             }
 
 
-            return Uri.UnescapeDataString(arguments[0].ToString().Replace("+", " "));
-        }
+            return r.ToString();
+        } 
 
 
         /// <summary>
         /// <summary>
-        /// http://www.ecma-international.org/ecma-262/5.1/#sec-15.1.3.4
+        /// http://www.ecma-international.org/ecma-262/5.1/#sec-15.1.3.3
         /// </summary>
         /// </summary>
         /// <param name="thisObject"></param>
         /// <param name="thisObject"></param>
         /// <param name="arguments"></param>
         /// <param name="arguments"></param>
         /// <returns></returns>
         /// <returns></returns>
-        public static string EncodeUriComponent(object thisObject, object[] arguments)
+        public static string DecodeUriComponent(object thisObject, object[] arguments)
         {
         {
             if (arguments.Length < 1 || arguments[0] == Undefined.Instance)
             if (arguments.Length < 1 || arguments[0] == Undefined.Instance)
             {
             {
                 return "";
                 return "";
             }
             }
 
 
-            string encoded = Uri.EscapeDataString(arguments[0].ToString());
-
-            foreach (char c in ReservedEncodedComponent)
-            {
-                encoded = encoded.Replace(Uri.EscapeDataString(c.ToString()), c.ToString().ToUpper());
-            }
-
-            return encoded;
+            return Uri.UnescapeDataString(arguments[0].ToString().Replace("+", " "));
         }
         }
-
-
     }
     }
 }
 }