Merge pull request #4680 from lambdageek/bug-49721-take2
[mono.git] / mcs / class / System / System.Net / IPv6Address.cs
index d2103b24f79699e5e547a23fe75181cec7a8eb7a..3592427d41e04b17fea2d4af5700ea4a14a1bd1c 100644 (file)
@@ -1,16 +1,8 @@
 //\r
-// System.Net.IPv6Address.cs\r
+// System.Net.IPv6AddressFormatter.cs\r
 //\r
 // Author:\r
 //   Lawrence Pit (loz@cable.a2000.nl)\r
-//\r
-// Note I: This class is not defined in the specs of .Net\r
-//\r
-// Note II : The name of this class is perhaps unfortunate as it turns\r
-//           out that in ms.net there's an internal class called\r
-//           IPv6Address in namespace System.\r
-//\r
-\r
 //\r
 // Permission is hereby granted, free of charge, to any person obtaining\r
 // a copy of this software and associated documentation files (the\r
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
 //\r
 \r
-\r
-using System;\r
 using System.Globalization;\r
-using System.Net.Sockets;\r
-using System.Runtime.InteropServices;\r
 using System.Text;\r
 \r
 namespace System.Net {\r
 \r
-       /// <remarks>\r
-       ///   Encapsulates an IPv6 Address.\r
-       ///   See RFC 2373 for more info on IPv6 addresses.\r
-       /// </remarks>\r
-       [Serializable]\r
-       internal class IPv6Address {\r
-               private ushort [] address;\r
-               private int prefixLength;\r
-               private long scopeId = 0;\r
-\r
-               public static readonly IPv6Address Loopback = IPv6Address.Parse ("::1");\r
-               public static readonly IPv6Address Unspecified = IPv6Address.Parse ("::");\r
+       struct IPv6AddressFormatter\r
+       {\r
+               ushort [] address;\r
+               long scopeId;\r
 \r
-               public IPv6Address (ushort [] addr)\r
-               {\r
-                       if (addr == null)\r
-                               throw new ArgumentNullException ("addr");       \r
-                       if (addr.Length != 8)   \r
-                               throw new ArgumentException ("addr");\r
-                       address = addr;                 \r
-               }\r
-               \r
-               public IPv6Address (ushort [] addr, int prefixLength) : this (addr)\r
-               {\r
-                       if (prefixLength < 0 || prefixLength > 128)\r
-                               throw new ArgumentException ("prefixLength");\r
-                       this.prefixLength = prefixLength;\r
-               }\r
-       \r
-               public IPv6Address (ushort [] addr, int prefixLength, int scopeId) : this (addr, prefixLength)\r
+               public IPv6AddressFormatter (ushort[] addr, long scopeId)\r
                {\r
+                       this.address = addr;\r
                        this.scopeId = scopeId;\r
                }\r
 \r
-               public static IPv6Address Parse (string ipString)\r
-               {\r
-                       if (ipString == null)\r
-                               throw new ArgumentNullException ("ipString");\r
-\r
-                       IPv6Address result;\r
-                       if (TryParse (ipString, out result))\r
-                               return result;\r
-                       throw new FormatException ("Not a valid IPv6 address");\r
-               }\r
-\r
-               static int Fill (ushort [] addr, string ipString)\r
-               {\r
-                       int p = 0;\r
-                       int pdigits = 0;\r
-                       int slot = 0;\r
-\r
-                       if (ipString.Length == 0)\r
-                               return 0;\r
-                       \r
-                       // Catch double uses of ::\r
-                       if (ipString.IndexOf ("::", StringComparison.Ordinal) != -1)\r
-                               return -1;\r
-\r
-                       for (int i = 0; i < ipString.Length; i++){\r
-                               char c = ipString [i];\r
-                               int n;\r
-\r
-                               if (c == ':'){\r
-                                       // Leading : is not allowed.\r
-                                       if (i == 0)\r
-                                               return -1;\r
-                                      \r
-                                       // Trailing : is not allowed.\r
-                                       if (i == ipString.Length-1)\r
-                                               return -1;\r
-                                       \r
-                                       if (slot == 8)\r
-                                               return -1;\r
-                                       \r
-                                       addr [slot++] = (ushort) p;\r
-                                       p = 0;\r
-                                       pdigits = 0;\r
-                                       continue;\r
-                               }\r
-                               pdigits++;\r
-                               if (pdigits > 4)\r
-                                       return -1;\r
-                               if ('0' <= c && c <= '9')\r
-                                       n = (int) (c - '0');\r
-                               else if ('a' <= c && c <= 'f')\r
-                                       n = (int) (c - 'a' + 10);\r
-                               else if ('A' <= c && c <= 'F')\r
-                                       n = (int) (c - 'A' + 10);\r
-                               else \r
-                                       return -1;\r
-                               p = (p << 4) + n;\r
-                               if (p > UInt16.MaxValue)\r
-                                       return -1;\r
-                       }\r
-\r
-                       if (slot == 8)\r
-                               return -1;\r
-                       \r
-                       addr [slot++] = (ushort) p;\r
-\r
-                       return slot;\r
-               }\r
-\r
-               static bool TryParse (string prefix, out int res)\r
-               {\r
-                       return Int32.TryParse (prefix, NumberStyles.Integer, CultureInfo.InvariantCulture, out res);\r
-               }\r
-               \r
-               public static bool TryParse (string ipString, out IPv6Address result)\r
-               {\r
-                       result = null;\r
-                       if (ipString == null)\r
-                               return false;\r
-\r
-                       if (ipString.Length > 2 && \r
-                           ipString [0] == '[' && \r
-                           ipString [ipString.Length - 1] == ']')\r
-                               ipString = ipString.Substring (1, ipString.Length - 2);\r
-\r
-                       if (ipString.Length  < 2)\r
-                               return false;\r
-\r
-                       int prefixLen = 0;\r
-                       int scopeId = 0;\r
-                       int pos = ipString.LastIndexOf ('/');\r
-                       if (pos != -1) {\r
-                               string prefix = ipString.Substring (pos + 1);\r
-                               if (!TryParse (prefix , out prefixLen))\r
-                                       prefixLen = -1;\r
-                               if (prefixLen < 0 || prefixLen > 128)\r
-                                       return false;\r
-                               ipString = ipString.Substring (0, pos);\r
-                       } else {\r
-                               pos = ipString.LastIndexOf ('%');\r
-                               if (pos != -1) {\r
-                                       string prefix = ipString.Substring (pos + 1);\r
-                                       if (!TryParse (prefix, out scopeId))\r
-                                               scopeId = 0;\r
-                                       ipString = ipString.Substring (0, pos);\r
-                               }                       \r
-                       }\r
-\r
-                       //\r
-                       // At this point the prefix/suffixes have been removed\r
-                       // and we only have to deal with the ipv4 or ipv6 addressed\r
-                       //\r
-                       ushort [] addr = new ushort [8];\r
-\r
-                       //\r
-                       // Is there an ipv4 address at the end?\r
-                       //\r
-                       int pos2 = ipString.LastIndexOf (':');\r
-                       if (pos2 == -1)\r
-                               return false;\r
-\r
-                       int slots = 0;\r
-                       if (pos2 < (ipString.Length - 1)) {\r
-                               string ipv4Str = ipString.Substring (pos2 + 1);\r
-                               if (ipv4Str.IndexOf ('.') != -1) {\r
-                                       IPAddress ip;\r
-                                       \r
-                                       if (!IPAddress.TryParse (ipv4Str, out ip))\r
-                                               return false;\r
-                                       \r
-                                       long a = ip.InternalIPv4Address;\r
-                                       addr [6] = (ushort) (((int) (a & 0xff) << 8) + ((int) ((a >> 8) & 0xff)));\r
-                                       addr [7] = (ushort) (((int) ((a >> 16) & 0xff) << 8) + ((int) ((a >> 24) & 0xff)));\r
-                                       if (pos2 > 0 && ipString [pos2 - 1] == ':') \r
-                                               ipString = ipString.Substring (0, pos2 + 1);\r
-                                       else\r
-                                               ipString = ipString.Substring (0, pos2);\r
-                                       slots = 2;\r
-                               }\r
-                       }       \r
-\r
-                       //\r
-                       // Only an ipv6 block remains, either:\r
-                       // "hexnumbers::hexnumbers", "hexnumbers::" or "hexnumbers"\r
-                       //\r
-                       int c = ipString.IndexOf ("::", StringComparison.Ordinal);\r
-                       if (c != -1){\r
-                               int right_slots = Fill (addr, ipString.Substring (c+2));\r
-                               if (right_slots == -1){\r
-                                       return false;\r
-                               }\r
-\r
-                               if (right_slots + slots > 8){\r
-                                       return false;\r
-                               }\r
-\r
-                               int d = 8-slots-right_slots;\r
-                               for (int i = right_slots; i > 0; i--){\r
-                                       addr [i+d-1] = addr [i-1];\r
-                                       addr [i-1] = 0;\r
-                               }\r
-                               \r
-                               int left_slots = Fill (addr, ipString.Substring (0, c));\r
-                               if (left_slots == -1)\r
-                                       return false;\r
-\r
-                               if (left_slots + right_slots + slots > 7)\r
-                                       return false;\r
-                       } else {\r
-                               if (Fill (addr, ipString) != 8-slots)\r
-                                       return false;\r
-                       }\r
-\r
-                       result = new IPv6Address (addr, prefixLen, scopeId);\r
-                       return true;\r
-               }\r
-\r
-               public ushort [] Address {\r
-                       get { return address; }\r
-               }\r
-\r
-               public int PrefixLength {\r
-                       get { return this.prefixLength; }\r
-               }\r
-               \r
-               public long ScopeId {\r
-                       get {\r
-                               return scopeId;\r
-                       }\r
-                       set {\r
-                               scopeId = value;\r
-                       }\r
-               }\r
-\r
-               public ushort this [int index] {\r
-                       get { return address [index]; }\r
-               }               \r
-\r
-               public AddressFamily AddressFamily {\r
-                       get { return AddressFamily.InterNetworkV6; }\r
-               }\r
-\r
-               public static bool IsLoopback (IPv6Address addr)\r
-               {\r
-                       if (addr.address [7] != 1)\r
-                               return false;\r
-\r
-                       int x = addr.address [6] >> 8;\r
-                       if (x != 0x7f && x != 0)\r
-                               return false;\r
-\r
-                       for (int i = 0; i < 4; i++) {\r
-                               if (addr.address [i] != 0)\r
-                                       return false;\r
-                       }\r
-\r
-                       if (addr.address [5] != 0 && addr.address [5] != 0xffff)\r
-                               return false;\r
-\r
-                       return true;\r
-               }\r
-\r
-               private static ushort SwapUShort (ushort number)\r
+               static ushort SwapUShort (ushort number)\r
                {\r
                        return (ushort) ( ((number >> 8) & 0xFF) + ((number << 8) & 0xFF00) );\r
                }\r
 \r
                // Convert the address into a format expected by the IPAddress (long) ctor\r
                // This needs to be unsigned to satisfy the '> 1' test in IsIPv4Compatible()\r
-               private uint AsIPv4Int ()\r
+               uint AsIPv4Int ()\r
                {\r
                        return (uint)(SwapUShort (address [7]) << 16) + SwapUShort (address [6]);\r
                }                       \r
 \r
-               public bool IsIPv4Compatible ()\r
+               bool IsIPv4Compatible ()\r
                {\r
                        for (int i = 0; i < 6; i++) \r
                                if (address [i] != 0)\r
@@ -323,7 +66,7 @@ namespace System.Net {
                        return (AsIPv4Int () > 1);\r
                }\r
                \r
-               public bool IsIPv4Mapped ()\r
+               bool IsIPv4Mapped ()\r
                {\r
                        for (int i = 0; i < 5; i++) \r
                                if (address [i] != 0)\r
@@ -338,10 +81,6 @@ namespace System.Net {
                        return address [5] == 0xffff;\r
                }\r
                \r
-               /// <summary>\r
-               ///   Overrides System.Object.ToString to return\r
-               ///   this object rendered in a canonicalized notation\r
-               /// </summary>\r
                public override string ToString ()\r
                {\r
                        StringBuilder s = new StringBuilder ();\r
@@ -358,112 +97,52 @@ namespace System.Net {
 \r
                                return s.ToString ();\r
                        }\r
-                       else\r
-                       {\r
-                               int bestChStart = -1; // Best chain start\r
-                               int bestChLen = 0; // Best chain length\r
-                               int currChLen = 0; // Current chain length\r
+                       \r
+                       int bestChStart = -1; // Best chain start\r
+                       int bestChLen = 0; // Best chain length\r
+                       int currChLen = 0; // Current chain length\r
 \r
-                               // Looks for the longest zero chain\r
-                               for (int i=0; i<8; i++)\r
+                       // Looks for the longest zero chain\r
+                       for (int i=0; i<8; i++)\r
+                       {\r
+                               if (address[i] != 0)\r
                                {\r
-                                       if (address[i] != 0)\r
+                                       if ((currChLen > bestChLen) \r
+                                               && (currChLen > 1))\r
                                        {\r
-                                               if ((currChLen > bestChLen) \r
-                                                       && (currChLen > 1))\r
-                                               {\r
-                                                       bestChLen = currChLen;\r
-                                                       bestChStart = i - currChLen;\r
-                                               }\r
-                                               currChLen = 0;\r
+                                               bestChLen = currChLen;\r
+                                               bestChStart = i - currChLen;\r
                                        }\r
-                                       else\r
-                                               currChLen++;\r
-                               }\r
-                               if ((currChLen > bestChLen) \r
-                                       && (currChLen > 1))\r
-                               {\r
-                                       bestChLen = currChLen;\r
-                                       bestChStart = 8 - currChLen;\r
+                                       currChLen = 0;\r
                                }\r
+                               else\r
+                                       currChLen++;\r
+                       }\r
+                       if ((currChLen > bestChLen) \r
+                               && (currChLen > 1))\r
+                       {\r
+                               bestChLen = currChLen;\r
+                               bestChStart = 8 - currChLen;\r
+                       }\r
 \r
-                               // makes the string\r
-                               if (bestChStart == 0)\r
-                                       s.Append(":");\r
-                               for (int i=0; i<8; i++)\r
+                       // makes the string\r
+                       if (bestChStart == 0)\r
+                               s.Append(":");\r
+                       for (int i=0; i<8; i++)\r
+                       {\r
+                               if (i == bestChStart)\r
                                {\r
-                                       if (i == bestChStart)\r
-                                       {\r
-                                               s.Append (":");\r
-                                               i += (bestChLen - 1);\r
-                                               continue;\r
-                                       }\r
-                                       s.AppendFormat("{0:x}", address [i]);\r
-                                       if (i < 7) s.Append (':');\r
+                                       s.Append (":");\r
+                                       i += (bestChLen - 1);\r
+                                       continue;\r
                                }\r
+                               s.AppendFormat("{0:x}", address [i]);\r
+                               if (i < 7) s.Append (':');\r
                        }\r
+                       \r
                        if (scopeId != 0)\r
                                s.Append ('%').Append (scopeId);\r
                        return s.ToString ();\r
                }\r
-\r
-               public string ToString (bool fullLength)\r
-               {\r
-                       if (!fullLength)\r
-                               return ToString ();\r
-\r
-                       StringBuilder sb = new StringBuilder ();\r
-                       for (int i=0; i < address.Length - 1; i++) {\r
-                               sb.AppendFormat ("{0:X4}:", address [i]);\r
-                       }\r
-                       sb.AppendFormat ("{0:X4}", address [address.Length - 1]);\r
-                       return sb.ToString ();\r
-               }\r
-\r
-               /// <returns>\r
-               ///   Whether both objects are equal.\r
-               /// </returns>\r
-               public override bool Equals (object other)\r
-               {\r
-                       System.Net.IPv6Address ipv6 = other as System.Net.IPv6Address;\r
-                       if (ipv6 != null) {\r
-                               for (int i = 0; i < 8; i++) \r
-                                       if (this.address [i] != ipv6.address [i])\r
-                                               return false;\r
-                               return true;\r
-                       }\r
-                       \r
-                       System.Net.IPAddress ipv4 = other as System.Net.IPAddress;\r
-                       if (ipv4 != null) {\r
-                               for (int i = 0; i < 5; i++) \r
-                                       if (address [i] != 0)\r
-                                               return false;\r
-\r
-                               if (address [5] != 0 && address [5] != 0xffff)\r
-                                       return false;\r
-\r
-                               long a = ipv4.InternalIPv4Address;\r
-                               if (address [6] != (ushort) (((int) (a & 0xff) << 8) + ((int) ((a >> 8) & 0xff))) ||\r
-                                   address [7] != (ushort) (((int) ((a >> 16) & 0xff) << 8) + ((int) ((a >> 24) & 0xff))))\r
-                                       return false;\r
-\r
-                               return true;\r
-                       }\r
-                       \r
-                       return false;\r
-               }\r
-\r
-               public override int GetHashCode ()\r
-               {\r
-                       return Hash (((((int) address [0]) << 16) + address [1]), \r
-                                               ((((int) address [2]) << 16) + address [3]),\r
-                                               ((((int) address [4]) << 16) + address [5]),\r
-                                               ((((int) address [6]) << 16) + address [7]));\r
-               }\r
-               \r
-               private static int Hash (int i, int j, int k, int l) \r
-               {\r
-                       return i ^ (j << 13 | j >> 19) ^ (k << 26 | k >> 6) ^ (l << 7 | l >> 25);\r
-               }\r
        }\r
 }\r