summaryrefslogtreecommitdiff
path: root/Runtime/Managed/CrossDomainPolicyParser
diff options
context:
space:
mode:
Diffstat (limited to 'Runtime/Managed/CrossDomainPolicyParser')
-rw-r--r--Runtime/Managed/CrossDomainPolicyParser/CrossDomainPolicyParser.csproj71
-rw-r--r--Runtime/Managed/CrossDomainPolicyParser/CrossDomainPolicyParser.jam46
-rw-r--r--Runtime/Managed/CrossDomainPolicyParser/CrossDomainPolicyParser.sln41
-rw-r--r--Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/AddressFamily.cs73
-rw-r--r--Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/BaseDomainPolicy.cs147
-rw-r--r--Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/CrossDomainPolicyManager.cs245
-rw-r--r--Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/FlashCrossDomainPolicy.cs213
-rw-r--r--Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/FlashCrossDomainPolicyParser.cs265
-rw-r--r--Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/ICrossDomainPolicy.cs42
-rw-r--r--Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/IPAddress.cs503
-rw-r--r--Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/IPv6Address.cs478
-rw-r--r--Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/Locale.cs14
-rw-r--r--Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/MiniParser.cs628
-rw-r--r--Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/NoAccessPolicy.cs46
-rw-r--r--Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/PolicyDownloadPolicy.cs59
-rw-r--r--Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/SiteOfOriginPolicy.cs55
-rw-r--r--Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/UnityExtra.cs48
-rw-r--r--Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/Uri.cs2225
-rw-r--r--Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/UriFormatException.cs72
-rw-r--r--Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/UriHostNameType.cs62
-rw-r--r--Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/UriKind.cs42
-rw-r--r--Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/UriPartial.cs44
-rw-r--r--Runtime/Managed/CrossDomainPolicyParser/Properties/AssemblyInfo.cs37
-rw-r--r--Runtime/Managed/CrossDomainPolicyParser/Tests/CrossDomainPolicyParserTests.csproj71
-rw-r--r--Runtime/Managed/CrossDomainPolicyParser/Tests/FlashPolicyParserSocketTests.cs124
-rw-r--r--Runtime/Managed/CrossDomainPolicyParser/Tests/FlashPolicyParserTests.cs209
-rw-r--r--Runtime/Managed/CrossDomainPolicyParser/Tests/Properties/AssemblyInfo.cs36
-rw-r--r--Runtime/Managed/CrossDomainPolicyParser/Tests/UriToolsTests.cs23
-rw-r--r--Runtime/Managed/CrossDomainPolicyParser/UnityCrossDomainHelper.cs213
-rw-r--r--Runtime/Managed/CrossDomainPolicyParser/UriTools.cs20
30 files changed, 6152 insertions, 0 deletions
diff --git a/Runtime/Managed/CrossDomainPolicyParser/CrossDomainPolicyParser.csproj b/Runtime/Managed/CrossDomainPolicyParser/CrossDomainPolicyParser.csproj
new file mode 100644
index 0000000..07b5653
--- /dev/null
+++ b/Runtime/Managed/CrossDomainPolicyParser/CrossDomainPolicyParser.csproj
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{31C2F345-D887-49DD-A1F6-741CABD74A42}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>CrossDomainPolicyParser</RootNamespace>
+ <AssemblyName>CrossDomainPolicyParser</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="Mono.Forks\AddressFamily.cs" />
+ <Compile Include="Mono.Forks\BaseDomainPolicy.cs" />
+ <Compile Include="Mono.Forks\CrossDomainPolicyManager.cs" />
+ <Compile Include="Mono.Forks\FlashCrossDomainPolicy.cs" />
+ <Compile Include="Mono.Forks\FlashCrossDomainPolicyParser.cs" />
+ <Compile Include="Mono.Forks\ICrossDomainPolicy.cs" />
+ <Compile Include="Mono.Forks\IPAddress.cs" />
+ <Compile Include="Mono.Forks\IPv6Address.cs" />
+ <Compile Include="Mono.Forks\Locale.cs" />
+ <Compile Include="Mono.Forks\MiniParser.cs" />
+ <Compile Include="Mono.Forks\NoAccessPolicy.cs" />
+ <Compile Include="Mono.Forks\PolicyDownloadPolicy.cs" />
+ <Compile Include="Mono.Forks\SiteOfOriginPolicy.cs" />
+ <Compile Include="Mono.Forks\UnityExtra.cs" />
+ <Compile Include="Mono.Forks\Uri.cs" />
+ <Compile Include="Mono.Forks\UriFormatException.cs" />
+ <Compile Include="Mono.Forks\UriHostNameType.cs" />
+ <Compile Include="Mono.Forks\UriKind.cs" />
+ <Compile Include="Mono.Forks\UriPartial.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="UnityCrossDomainHelper.cs" />
+ <Compile Include="UriTools.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Reference Include="UnityEngine">
+ <HintPath>..\..\..\build\ManagedAssemblies\UnityEngine.dll</HintPath>
+ <Private>False</Private>
+ </Reference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
diff --git a/Runtime/Managed/CrossDomainPolicyParser/CrossDomainPolicyParser.jam b/Runtime/Managed/CrossDomainPolicyParser/CrossDomainPolicyParser.jam
new file mode 100644
index 0000000..e56959a
--- /dev/null
+++ b/Runtime/Managed/CrossDomainPolicyParser/CrossDomainPolicyParser.jam
@@ -0,0 +1,46 @@
+SubDir TOP Runtime Managed CrossDomainPolicyParser ;
+
+ActiveProject CrossDomainPolicyParser ;
+
+NotFile CrossDomainPolicyParser ;
+local csfiles = @($(TOP)/Runtime/Managed/CrossDomainPolicyParser/**/*.cs:W=$(TOP)/:X=Tests) ;
+
+# Globbing hack
+if $(PLATFORM) in linux32 linux64
+{
+ csfiles = [ Split [ Shell "find $(TOP)/Runtime/Managed/CrossDomainPolicyParser -name '*.cs'" ] : ";
+" ] ;
+ csfiles = $(csfiles:W=$(TOP)/) ;
+ csfiles = $(csfiles:X=Tests) ;
+}
+SEARCH on $(csfiles:G=CrossDomainPolicyParser) = $(TOP) ;
+
+local unityenginelocation_crossdomain = $(unityenginelocation_editor) ;
+unityenginelocation_crossdomain ?= $(unityenginelocation_webplayer) ;
+
+local targetdirs ;
+local tempdir ;
+if $(OS) = NT
+{
+ tempdir = $(TOP)/build/temp ;
+ targetdirs += $(TOP)/build/WindowsEditor/Data/Managed ;
+ targetdirs += $(TOP)/build/WindowsWebplayer/Data/lib ;
+ targetdirs += $(TOP)/build/Windows64WebPlayer/Data/lib ;
+ targetdirs += $(TOP)/build/Windows64Editor/Data/Managed ;
+} else
+{
+ tempdir = $(TOP)/build/temp ;
+ targetdirs += $(TOP)/build/MacEditor/Unity.app/Contents/Frameworks/Managed ;
+}
+
+local temp = $(tempdir)/CrossDomainPolicyParser.dll ;
+MkDir $(tempdir) ;
+Depends $(temp) : $(tempdir) ;
+Depends $(temp) : $(unityenginelocation_crossdomain) ;
+
+BuildAssembly CrossDomainPolicyParser : 2.0 : $(temp) : $(csfiles) : : $(unityenginelocation_crossdomain:T) ;
+
+for targetdir in $(targetdirs)
+{
+ CopyFile : $(targetdir)/CrossDomainPolicyParser.dll : $(temp) ;
+}
diff --git a/Runtime/Managed/CrossDomainPolicyParser/CrossDomainPolicyParser.sln b/Runtime/Managed/CrossDomainPolicyParser/CrossDomainPolicyParser.sln
new file mode 100644
index 0000000..f8bd348
--- /dev/null
+++ b/Runtime/Managed/CrossDomainPolicyParser/CrossDomainPolicyParser.sln
@@ -0,0 +1,41 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrossDomainPolicyParser", "CrossDomainPolicyParser.csproj", "{31C2F345-D887-49DD-A1F6-741CABD74A42}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrossDomainPolicyParserTests", "Tests\CrossDomainPolicyParserTests.csproj", "{5C04DB87-3B34-43B4-B164-86CE4361DC7B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnityEngine", "..\..\..\Projects\CSharp\UnityEngine.csproj", "{F0499708-3EB6-4026-8362-97E6FFC4E7C8}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Unity.TestableAssemblyMaker", "..\..\..\Tools\Unity.TestableAssemblyMaker\Unity.TestableAssemblyMaker.csproj", "{3C2CC5A1-0663-458A-AF4B-52248977DDF3}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {31C2F345-D887-49DD-A1F6-741CABD74A42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {31C2F345-D887-49DD-A1F6-741CABD74A42}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {31C2F345-D887-49DD-A1F6-741CABD74A42}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {31C2F345-D887-49DD-A1F6-741CABD74A42}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3C2CC5A1-0663-458A-AF4B-52248977DDF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3C2CC5A1-0663-458A-AF4B-52248977DDF3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3C2CC5A1-0663-458A-AF4B-52248977DDF3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3C2CC5A1-0663-458A-AF4B-52248977DDF3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5C04DB87-3B34-43B4-B164-86CE4361DC7B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5C04DB87-3B34-43B4-B164-86CE4361DC7B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5C04DB87-3B34-43B4-B164-86CE4361DC7B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5C04DB87-3B34-43B4-B164-86CE4361DC7B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F0499708-3EB6-4026-8362-97E6FFC4E7C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F0499708-3EB6-4026-8362-97E6FFC4E7C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F0499708-3EB6-4026-8362-97E6FFC4E7C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F0499708-3EB6-4026-8362-97E6FFC4E7C8}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(MonoDevelopProperties) = preSolution
+ StartupItem = CrossDomainPolicyParser.csproj
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/AddressFamily.cs b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/AddressFamily.cs
new file mode 100644
index 0000000..5277509
--- /dev/null
+++ b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/AddressFamily.cs
@@ -0,0 +1,73 @@
+// AddressFamily.cs
+//
+// This code was automatically generated from
+// ECMA CLI XML Library Specification.
+// Generator: libgen.xsl [1.0; (C) Sergey Chaban (serge@wildwestsoftware.com)]
+// Created: Wed, 5 Sep 2001 06:31:59 UTC
+// Source file: AllTypes.xml
+// URL: http://msdn.microsoft.com/net/ecma/AllTypes.xml
+//
+// (C) 2001 Ximian, Inc. http://www.ximian.com
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+
+namespace MonoForks.System.Net.Sockets {
+
+
+#if ONLY_1_1
+ [Serializable]
+#endif
+ public enum AddressFamily {
+ Unknown = -1,
+ Unspecified = 0,
+ Unix = 1,
+ InterNetwork = 2,
+ ImpLink = 3,
+ Pup = 4,
+ Chaos = 5,
+ NS = 6,
+ Ipx = 6,
+ Iso = 7,
+ Osi = 7,
+ Ecma = 8,
+ DataKit = 9,
+ Ccitt = 10,
+ Sna = 11,
+ DecNet = 12,
+ DataLink = 13,
+ Lat = 14,
+ HyperChannel = 15,
+ AppleTalk = 16,
+ NetBios = 17,
+ VoiceView = 18,
+ FireFox = 19,
+ Banyan = 21,
+ Atm = 22,
+ InterNetworkV6 = 23,
+ Cluster = 24,
+ Ieee12844 = 25,
+ Irda = 26,
+ NetworkDesigners = 28,
+ Max = 29,
+ }
+}
diff --git a/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/BaseDomainPolicy.cs b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/BaseDomainPolicy.cs
new file mode 100644
index 0000000..34fe6fa
--- /dev/null
+++ b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/BaseDomainPolicy.cs
@@ -0,0 +1,147 @@
+//
+// BaseDomainPolicy.cs
+//
+// Authors:
+// Atsushi Enomoto <atsushi@ximian.com>
+// Moonlight List (moonlight-list@lists.ximian.com)
+//
+// Copyright (C) 2009 Novell, Inc. http://www.novell.com
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+#define NET_2_1
+#if NET_2_1
+
+using System;
+using MonoForks.System;
+using System.Collections.Generic;
+using System.IO;
+using MonoForks.System.Net;
+#if !TEST
+using MonoForks.System.Windows.Interop;
+#endif
+
+// Base class for shared stuff between the Silverlight and Flash policies
+// e.g. Headers and Domain comparison
+
+namespace MonoForks.System.Windows.Browser.Net {
+
+ abstract class BaseDomainPolicy : ICrossDomainPolicy {
+#if TEST
+ static public Uri ApplicationUri { get; set; }
+#else
+ static public Uri ApplicationUri {
+ get { return PluginHost.RootUri; }
+ }
+#endif
+ static string root;
+
+ static public string ApplicationRoot {
+ get {
+ if (root == null)
+ root = CrossDomainPolicyManager.GetRoot (ApplicationUri);
+ return root;
+ }
+ }
+
+ public class Headers {
+
+ class PrefixComparer : IEqualityComparer<string> {
+
+ public bool Equals (string x, string y)
+ {
+ int check_length = x.Length - 1;
+ if ((x.Length > 0) && (x [check_length] == '*'))
+ return (String.Compare (x, 0, y, 0, check_length, StringComparison.OrdinalIgnoreCase) == 0);
+
+ return (String.Compare (x, y, StringComparison.OrdinalIgnoreCase) == 0);
+ }
+
+ public int GetHashCode (string obj)
+ {
+ return (obj == null) ? 0 : obj.GetHashCode ();
+ }
+ }
+
+ static PrefixComparer pc = new PrefixComparer ();
+
+ private List<string> list;
+
+ public Headers ()
+ {
+ }
+
+ public bool AllowAllHeaders { get; private set; }
+
+ public bool IsAllowed (string[] headers)
+ {
+ if (AllowAllHeaders)
+ return true;
+
+ if (headers == null || headers.Length == 0)
+ return true;
+
+ foreach(var h in headers)
+ {
+ bool found = false;
+ foreach(var item in list)
+ if (pc.Equals(item,h)) found = true;
+ if (!found) return false;
+ }
+ return true;
+ }
+
+ public void SetHeaders (string raw)
+ {
+ if (raw == "*") {
+ AllowAllHeaders = true;
+ list = null;
+ } else if (raw != null) {
+ string [] headers = raw.Split (',');
+ list = new List<string> (headers.Length + 1);
+ list.Add ("Content-Type");
+ for (int i = 0; i < headers.Length; i++) {
+ string s = headers [i].Trim ();
+ if (!String.IsNullOrEmpty (s))
+ list.Add (s);
+ }
+ } else {
+ // without a specified 'http-request-headers' no header, expect Content-Type, is allowed
+ AllowAllHeaders = false;
+ list = new List<string> (1);
+ list.Add ("Content-Type");
+ }
+ }
+ }
+
+ public bool IsAllowed (WebRequest request)
+ {
+ var keys = request.Headers.Keys;
+ string[] AllKeys = new string[keys.Count];
+ keys.CopyTo(AllKeys,0);
+ return IsAllowed (request.RequestUri, AllKeys);
+ }
+
+ abstract public bool IsAllowed (Uri uri, params string [] headerKeys);
+ }
+}
+
+#endif
+
diff --git a/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/CrossDomainPolicyManager.cs b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/CrossDomainPolicyManager.cs
new file mode 100644
index 0000000..a73eadc
--- /dev/null
+++ b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/CrossDomainPolicyManager.cs
@@ -0,0 +1,245 @@
+//
+// CrossDomainPolicyManager.cs
+//
+// Authors:
+// Atsushi Enomoto <atsushi@ximian.com>
+// Moonlight List (moonlight-list@lists.ximian.com)
+//
+// Copyright (C) 2009 Novell, Inc. http://www.novell.com
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+#define NET_2_1
+#if NET_2_1
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using MonoForks.System.Windows.Interop;
+using System.Security;
+using System.Reflection;
+
+namespace MonoForks.System.Windows.Browser.Net
+{
+ internal static class CrossDomainPolicyManager
+ {
+
+ public static string GetRoot(Uri uri)
+ {
+ if ((uri.Scheme == "http" && uri.Port == 80) || (uri.Scheme == "https" && uri.Port == 443) || (uri.Port == -1))
+ return String.Format("{0}://{1}/", uri.Scheme, uri.DnsSafeHost);
+ else
+ return String.Format("{0}://{1}:{2}/", uri.Scheme, uri.DnsSafeHost, uri.Port);
+ }
+
+ public const string ClientAccessPolicyFile = "/clientaccesspolicy.xml";
+ public const string CrossDomainFile = "/crossdomain.xml";
+
+ const int Timeout = 10000;
+
+ // Web Access Policy
+
+ static Dictionary<string, ICrossDomainPolicy> policies = new Dictionary<string, ICrossDomainPolicy>();
+
+ static internal ICrossDomainPolicy PolicyDownloadPolicy = new PolicyDownloadPolicy();
+ static ICrossDomainPolicy site_of_origin_policy = new SiteOfOriginPolicy();
+ static ICrossDomainPolicy no_access_policy = new NoAccessPolicy();
+
+ static Uri GetRootUri(Uri uri)
+ {
+ return new Uri(GetRoot(uri));
+ }
+
+ public static Uri GetSilverlightPolicyUri(Uri uri)
+ {
+ return new Uri(GetRootUri(uri), CrossDomainPolicyManager.ClientAccessPolicyFile);
+ }
+
+ public static Uri GetFlashPolicyUri(Uri uri)
+ {
+ return new Uri(GetRootUri(uri), CrossDomainPolicyManager.CrossDomainFile);
+ }
+
+ public static ICrossDomainPolicy GetCachedWebPolicy(Uri uri)
+ {
+ //Debug.Log("Got to GetCachedWebPolicy");
+ //Debug.Log("debug1. uri: " + uri.ToString() + " pluginhost.sourceuri: " + PluginHost.SourceUri);
+ //Debug.Log("debug1.1 pluginhost.rooturi: " + PluginHost.RootUri);
+ // if we request an Uri from the same site then we return an "always positive" policy
+ if (SiteOfOriginPolicy.HasSameOrigin(uri, PluginHost.SourceUri))
+ return site_of_origin_policy;
+
+ //Debug.Log("debug2");
+
+ //if this is a request for a crossdomainfile, then we allow it.
+ //TODO: Make this more secure.
+ string postfix = "";
+ if (!uri.IsDefaultPort) postfix = ":" + uri.Port;
+
+ if (uri.ToString() == uri.Scheme + "://" + uri.Host + postfix + "/crossdomain.xml") return PolicyDownloadPolicy;
+
+ //Debug.Log("debug3");
+ // otherwise we search for an already downloaded policy for the web site
+ string root = GetRoot(uri);
+ ICrossDomainPolicy policy = null;
+ policies.TryGetValue(root, out policy);
+ // and we return it (if we have it) or null (if we dont)
+ //Debug.Log("debug4: " + policy);
+ return policy;
+ }
+
+ private static void AddPolicy(Uri responseUri, ICrossDomainPolicy policy)
+ {
+ string root = GetRoot(responseUri);
+ try
+ {
+ policies.Add(root, policy);
+ }
+ catch (ArgumentException)
+ {
+ // it's possible another request already added this root
+ }
+ }
+
+ /*
+ public static ICrossDomainPolicy BuildSilverlightPolicy (HttpWebResponse response)
+ {
+ // return null if no Silverlight policy was found, since we offer a second chance with a flash policy
+ if (response.StatusCode != HttpStatusCode.OK)
+ return null;
+
+ ICrossDomainPolicy policy = null;
+ try {
+ policy = ClientAccessPolicy.FromStream (response.GetResponseStream ());
+ if (policy != null)
+ policies.Add (GetRoot (response.ResponseUri), policy);
+ } catch (Exception ex) {
+ Console.WriteLine (String.Format ("CrossDomainAccessManager caught an exception while reading {0}: {1}",
+ response.ResponseUri, ex.Message));
+ // and ignore.
+ }
+ return policy;
+ }
+
+ public static ICrossDomainPolicy BuildFlashPolicy (HttpWebResponse response)
+ {
+ bool ok = response.StatusCode == HttpStatusCode.OK;
+ return BuildFlashPolicy(ok, response.ResponseUri, response.GetResponseStream(), response.Headers);
+ }
+ */
+ public static ICrossDomainPolicy BuildFlashPolicy(bool statuscodeOK, Uri uri, Stream responsestream, Dictionary<string, string> responseheaders)
+ {
+ ICrossDomainPolicy policy = null;
+ if (statuscodeOK)
+ {
+ try
+ {
+ policy = FlashCrossDomainPolicy.FromStream(responsestream);
+ }
+ catch (Exception ex)
+ {
+ Log.Msg(String.Format("BuildFlashPolicy caught an exception while parsing {0}: {1}",
+ uri, ex.Message));
+ throw;
+ }
+ if (policy != null)
+ {
+ // see DRT# 864 and 865
+ Log.Msg("crossdomain.xml was succesfully parsed");
+ string site_control = null;
+ responseheaders.TryGetValue("X-Permitted-Cross-Domain-Policies", out site_control);
+ if (!String.IsNullOrEmpty(site_control))
+ (policy as FlashCrossDomainPolicy).SiteControl = site_control;
+ }
+ }
+
+ // the flash policy was the last chance, keep a NoAccess into the cache
+ if (policy == null)
+ policy = no_access_policy;
+
+ AddPolicy(uri, policy);
+ return policy;
+ }
+
+ public static void ClearCache()
+ {
+ policies.Clear();
+ }
+
+ // Socket Policy
+ //
+ // - we connect once to a site for the entire application life time
+ // - this returns us a policy file (silverlight format only) or else no access is granted
+ // - this policy file
+ // - can contain multiple policies
+ // - can apply to multiple domains
+ // - can grant access to several resources
+
+ static readonly Dictionary<string, FlashCrossDomainPolicy> SocketPoliciesByIp = new Dictionary<string, FlashCrossDomainPolicy>();
+ const int PolicyPort = 843;
+
+ static public bool CheckSocketEndPoint(string connecting_to_ip, int port)
+ {
+ return CheckSocketEndPoint(connecting_to_ip,port,PolicyPort);
+ }
+
+ static public bool CheckSocketEndPoint(string connecting_to_ip, int port, int policyport)
+ {
+ var policy = FlashCrossDomainPolicyFor(connecting_to_ip, policyport, 3000);
+ return policy.IsSocketConnectionAllowed(port);
+ }
+
+ public static FlashCrossDomainPolicy FlashCrossDomainPolicyFor(string connecting_to_ip, int policyport, int timeout)
+ {
+ FlashCrossDomainPolicy cachedPolicy;
+ if (SocketPoliciesByIp.TryGetValue(connecting_to_ip, out cachedPolicy))
+ {
+ Log.Msg(String.Format("Policy for host {0} found in the cache.", connecting_to_ip));
+ return cachedPolicy;
+ }
+
+ try
+ {
+ FlashCrossDomainPolicy policy = RetrieveFlashCrossDomainPolicyFrom(connecting_to_ip, policyport,timeout);
+ policy.PolicyPort = policyport;
+ SocketPoliciesByIp.Add(connecting_to_ip, policy);
+ return policy;
+ }
+ catch (Exception ex)
+ {
+ Log.Msg(String.Format("{0} caught an exception while checking endpoint {1}: {2}", typeof(CrossDomainPolicyManager).Name, connecting_to_ip, ex));
+ return FlashCrossDomainPolicy.DenyPolicy;
+ }
+ }
+
+ [SecuritySafeCritical]
+ private static FlashCrossDomainPolicy RetrieveFlashCrossDomainPolicyFrom(string host, int port, int timeout)
+ {
+ var type = Type.GetType("System.Net.Sockets.SocketPolicyClient, System");
+ var stream = (Stream)type.InvokeMember("GetPolicyStreamForIP", BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.NonPublic, null, null, new object[] { host, port, timeout });
+
+ if (stream == null) throw new Exception("got back null stream from getpolicystream");
+ return FlashCrossDomainPolicy.FromStream(stream);
+ }
+ }
+}
+
+#endif
+
diff --git a/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/FlashCrossDomainPolicy.cs b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/FlashCrossDomainPolicy.cs
new file mode 100644
index 0000000..cbeb571
--- /dev/null
+++ b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/FlashCrossDomainPolicy.cs
@@ -0,0 +1,213 @@
+//
+// FlashCrossDomainPolicy.cs
+//
+// Author:
+// Atsushi Enomoto <atsushi@ximian.com>
+// Moonlight List (moonlight-list@lists.ximian.com)
+//
+// Copyright (C) 2009 Novell, Inc. http://www.novell.com
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+#define NET_2_1
+#if NET_2_1
+
+using System;
+using MonoForks.System;
+using System.Collections.Generic;
+using System.IO;
+using MonoForks.System.Net;
+using UnityEngine;
+
+namespace MonoForks.System.Windows.Browser.Net {
+
+ partial class FlashCrossDomainPolicy : BaseDomainPolicy {
+
+ private string site_control;
+ public int PolicyPort { get; set; }
+
+ public FlashCrossDomainPolicy ()
+ {
+ AllowedAccesses = new List<AllowAccessFrom> ();
+ AllowedHttpRequestHeaders = new List<AllowHttpRequestHeadersFrom> ();
+ PolicyPort = 843;
+ }
+
+ public static FlashCrossDomainPolicy DenyPolicy = new FlashCrossDomainPolicy();
+
+ public List<AllowAccessFrom> AllowedAccesses { get; private set; }
+ public List<AllowHttpRequestHeadersFrom> AllowedHttpRequestHeaders { get; private set; }
+
+ public string SiteControl {
+ get { return String.IsNullOrEmpty (site_control) ? "all" : site_control; }
+ set { site_control = value; }
+ }
+
+ public bool IsSocketConnectionAllowed(int port)
+ {
+ foreach(var allowed in AllowedAccesses)
+ {
+ if (allowed.IsSocketConnectionAllowed (port, PolicyPort))
+ return true;
+ }
+ return false;
+ }
+
+ public override bool IsAllowed (Uri uri, string [] headerKeys)
+ {
+ switch (SiteControl) {
+ case "all":
+ case "master-only":
+ case "by-ftp-filename":
+ break;
+ default:
+ // others, e.g. 'none', are not supported/accepted
+ Log.Msg("rejected because SiteControl does not have a valid value");
+ return false;
+ }
+ bool any = false;
+ if (AllowedAccesses.Count > 0)
+ {
+ foreach (var a in AllowedAccesses)
+ {
+ if (a.IsAllowed(uri, headerKeys))
+ {
+ any = true;
+ }
+ }
+ }
+ if (!any)
+ {
+ Log.Msg("Rejected because there was no AllowedAcces entry in the crossdomain file allowing this request.");
+ return false;
+ }
+
+ if (AllowedHttpRequestHeaders.Count > 0)
+ foreach(var h in AllowedHttpRequestHeaders)
+ if (h.IsRejected(uri,headerKeys)) return false;
+
+ return true;
+ }
+
+ public class AllowAccessFrom {
+
+ public AllowAccessFrom ()
+ {
+ Secure = true; // true by default
+ }
+
+ public string Domain { get; set; }
+ public bool AllowAnyPort { get; set; }
+ public int [] ToPorts { get; set; }
+ public bool Secure { get; set; }
+
+ public bool IsAllowed (Uri uri, string [] headerKeys)
+ {
+ Log.Msg("Checking if "+uri+" is a valid domain");
+ if (!CheckDomain(uri)) return false;
+
+ if (!AllowAnyPort && ToPorts != null && Array.IndexOf(ToPorts, uri.Port) < 0)
+ {
+ Log.Msg("requested port: "+uri.Port+" is not allowed by specified portrange");
+ return false;
+ }
+
+ // if Secure is false then it allows applications from HTTP to download data from HTTPS servers
+ if (!Secure)
+ return true;
+ // if Secure is true then only application on HTTPS servers can access data on HTTPS servers
+ if (ApplicationUri.Scheme == Uri.UriSchemeHttps)
+ return (uri.Scheme == Uri.UriSchemeHttps);
+ // otherwise FILE/HTTP applications can access HTTP uris
+
+ Log.Msg("All requirements met, the request is approved");
+ return true;
+ }
+
+ public bool IsSocketConnectionAllowed(int port, int policyport)
+ {
+ if (policyport>1024 && port<1024) return false;
+
+ bool portok = false;
+
+ if (AllowAnyPort) portok = true;
+ if (ToPorts != null)
+ {
+ foreach (int allowedport in ToPorts)
+ {
+ if (allowedport == port)
+ portok = true;
+ }
+ if (!portok) return false;
+ }
+ //for now we only support socket policies that say all domains are fine.
+ return (Domain == "*");
+ }
+
+ bool CheckDomain(Uri uri)
+ {
+ Log.Msg("Checking request-host: "+uri.Host+" against valid domain: "+Domain);
+ if (Domain == "*") return true;
+ if (ApplicationUri.Host == Domain) return true;
+
+ if (Domain[0] != '*') return false;
+ string match = Domain.Substring(1, Domain.Length - 1);
+ if (uri.Host.EndsWith(match)) return true;
+
+ return false;
+ }
+ }
+
+ public class AllowHttpRequestHeadersFrom {
+
+ public AllowHttpRequestHeadersFrom ()
+ {
+ Headers = new Headers ();
+ }
+
+ public string Domain { get; set; }
+ public bool AllowAllHeaders { get; set; }
+ public Headers Headers { get; private set; }
+ public bool Secure { get; set; }
+
+ public bool IsRejected (Uri uri, string [] headerKeys)
+ {
+ // "A Flash policy file must allow access to all domains to be used by the Silverlight runtime."
+ // http://msdn.microsoft.com/en-us/library/cc645032(VS.95).aspx
+ //if (Domain != "*")
+ // return false;
+
+ if (Headers.IsAllowed (headerKeys))
+ return false;
+
+ // if Secure is false then it allows applications from HTTP to download data from HTTPS servers
+ if (!Secure)
+ return true;
+ // if Secure is true then only application on HTTPS servers can access data on HTTPS servers
+ if (ApplicationUri.Scheme == Uri.UriSchemeHttps)
+ return (uri.Scheme == Uri.UriSchemeHttps);
+ // otherwise FILE/HTTP applications can access HTTP uris
+ return true;
+ }
+ }
+ }
+}
+
+#endif
diff --git a/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/FlashCrossDomainPolicyParser.cs b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/FlashCrossDomainPolicyParser.cs
new file mode 100644
index 0000000..980089a
--- /dev/null
+++ b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/FlashCrossDomainPolicyParser.cs
@@ -0,0 +1,265 @@
+//
+// FlashCrossDomainPolicyParser.cs
+//
+// Author:
+// Atsushi Enomoto <atsushi@ximian.com>
+// Moonlight List (moonlight-list@lists.ximian.com)
+//
+// Copyright (C) 2009 Novell, Inc. http://www.novell.com
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#define NET_2_1
+#if NET_2_1
+
+using System;
+using System.IO;
+using System.Collections;
+using System.Text;
+using MonoForks.Mono.Xml;
+
+/*
+
+Specification: http://www.adobe.com/devnet/articles/crossdomain_policy_file_spec.html
+
+# This grammar is based on the xsd from Adobe, but the schema is wrong.
+# It should have used interleave (all). Some crossdomain.xml are invalidated.
+# (For example, try mono-xmltool --validate-xsd http://www.adobe.com/xml/schemas/PolicyFile.xsd http://twitter.com/crossdomain.xml)
+
+default namespace = ""
+
+grammar {
+
+start = cross-domain-policy
+
+cross-domain-policy = element cross-domain-policy {
+ element site-control {
+ attribute permitted-cross-domain-policies {
+ "all" | "by-contract-type" | "by-ftp-filename" | "master-only" | "none"
+ }
+ }?,
+ element allow-access-from {
+ attribute domain { text },
+ attribute to-ports { text }?,
+ attribute secure { xs:boolean }?
+ }*,
+ element allow-http-request-headers-from {
+ attribute domain { text },
+ attribute headers { text },
+ attribute secure { xs:boolean }?
+ }*,
+ element allow-access-from-identity {
+ element signatory {
+ element certificate {
+ attribute fingerprint { text },
+ attribute fingerprint-algorithm { text }
+ }
+ }
+ }*
+}
+
+}
+
+*/
+
+namespace MonoForks.System.Windows.Browser.Net
+{
+
+ partial class FlashCrossDomainPolicy {
+
+ static public bool ReadBooleanAttribute(MiniParser.IAttrList attrs, string attribute)
+ {
+ switch (attrs.GetValue(attribute))
+ {
+ case null:
+ case "true":
+ return true;
+ case "false":
+ return false;
+ default:
+ throw new Exception("Invalid boolean attribute: " + attribute);
+ }
+ }
+ class Reader : MiniParser.IReader
+ {
+ public Reader(Stream stream)
+ {
+ this.stream = stream;
+ }
+ public int Read()
+ {
+ return stream.ReadByte();
+ }
+
+ Stream stream;
+ }
+
+ static public FlashCrossDomainPolicy FromStream(Stream originalStream)
+ {
+ Log.Msg("received policy");
+
+ var stream = StripTrailing0(originalStream);
+ if (stream.Length == 0)
+ throw new ArgumentException("Policy can't be constructed from empty stream.");
+
+ FlashCrossDomainPolicy cdp = new FlashCrossDomainPolicy ();
+ Handler handler = new Handler(cdp);
+ Reader r = new Reader(stream);
+ MiniParser p = new MiniParser();
+ p.Parse(r, handler);
+
+ // if none supplied set a default for headers
+ if (cdp.AllowedHttpRequestHeaders.Count == 0)
+ {
+ var h = new AllowHttpRequestHeadersFrom() { Domain = "*", Secure = true };
+ h.Headers.SetHeaders(null); // defaults
+ cdp.AllowedHttpRequestHeaders.Add(h);
+ }
+ Log.Msg("done parsing policy");
+ return cdp;
+ }
+
+ private static MemoryStream StripTrailing0(Stream stream)
+ {
+ //crazy inefficient, but only happens on very small streams.
+ var dupe = new MemoryStream();
+ while(true)
+ {
+ var b = stream.ReadByte();
+ if (b==0 || b==-1) break;
+ dupe.WriteByte((byte)b);
+ }
+ dupe.Seek(0, SeekOrigin.Begin);
+ return dupe;
+ }
+
+ class Handler : MiniParser.IHandler
+ {
+ public Handler(FlashCrossDomainPolicy cdp)
+ {
+ this.cdp = cdp;
+ }
+
+
+ // IContentHandler
+
+ private string current = null;
+ private Stack stack = new Stack();
+ FlashCrossDomainPolicy cdp;
+
+ public void OnStartElement(string name, MiniParser.IAttrList attrs)
+ {
+ Log.Msg("Parsing: "+name);
+ if (current == null)
+ {
+ if (name != "cross-domain-policy") throw new Exception("Expected root element to be <cross-domain-policy>. found "+name+" instead");
+ }
+ else
+ {
+ if (current == "cross-domain-policy")
+ {
+ switch (name)
+ {
+ case "site-control":
+ cdp.SiteControl = attrs.GetValue("permitted-cross-domain-policies");
+ break;
+ case "allow-access-from":
+ var a = new AllowAccessFrom()
+ {
+ Domain = attrs.GetValue("domain"),
+ Secure = ReadBooleanAttribute(attrs, "secure")
+ };
+
+ var p = attrs.GetValue ("to-ports");
+ if (p == "*")
+ a.AllowAnyPort = true;
+ else if (p != null)
+ {
+ var ports = new ArrayList();
+ string[] ports_string = p.Split (',');
+ foreach(string portstring in ports_string)
+ {
+ if (portstring.Contains("-"))
+ {
+ string[] s = portstring.Split('-');
+ if (s.Length != 2) continue;
+ int startport;
+ int endport;
+ if (!Int32.TryParse(s[0], out startport)) continue;
+ if (!Int32.TryParse(s[1], out endport)) continue;
+ for (int i = startport; i != endport; i++)
+ {
+ ports.Add(i);
+ }
+ }
+ else
+ {
+ int port;
+ if (Int32.TryParse(portstring, out port))
+ ports.Add(port);
+ }
+ }
+ a.ToPorts = (int[]) ports.ToArray(typeof(int));
+ }
+ cdp.AllowedAccesses.Add(a);
+ break;
+ case "allow-http-request-headers-from":
+ var h = new AllowHttpRequestHeadersFrom()
+ {
+ Domain = attrs.GetValue("domain"),
+ Secure = ReadBooleanAttribute(attrs, "secure")
+ };
+ h.Headers.SetHeaders(attrs.GetValue("headers"));
+ cdp.AllowedHttpRequestHeaders.Add(h);
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ throw new Exception("Invalid element " + name);
+ }
+ }
+ stack.Push(name);
+ current = name;
+ Log.Msg(name);
+ // attributes
+ int n = attrs.Length;
+ for (int i = 0; i < n; i++)
+ Log.Msg(" " + attrs.GetName(i) + ": " + attrs.GetValue(i));
+ }
+
+ public void OnEndElement(string name)
+ {
+ stack.Pop();
+ current = stack.Count>0 ? (string)stack.Peek() : null;
+ }
+
+ public void OnStartParsing(MiniParser parser) { }
+ public void OnChars(string ch) { }
+ public void OnEndParsing(MiniParser parser) { }
+ }
+ }
+}
+
+#endif
+
diff --git a/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/ICrossDomainPolicy.cs b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/ICrossDomainPolicy.cs
new file mode 100644
index 0000000..67c846f
--- /dev/null
+++ b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/ICrossDomainPolicy.cs
@@ -0,0 +1,42 @@
+//
+// System.Windows.Browser.Net.ICrossDomainPolicy interface
+//
+// Contact:
+// Moonlight List (moonlight-list@lists.ximian.com)
+//
+// Copyright (C) 2009 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+#define NET_2_1
+#if NET_2_1
+
+using MonoForks.System.Net;
+
+namespace MonoForks.System.Windows.Browser.Net {
+
+ interface ICrossDomainPolicy {
+
+ bool IsAllowed (WebRequest request);
+ }
+}
+
+#endif
+
diff --git a/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/IPAddress.cs b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/IPAddress.cs
new file mode 100644
index 0000000..61b254f
--- /dev/null
+++ b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/IPAddress.cs
@@ -0,0 +1,503 @@
+//
+// System.Net.IPAddress.cs
+//
+// Author:
+// Miguel de Icaza (miguel@ximian.com)
+// Lawrence Pit (loz@cable.a2000.nl)
+//
+// (C) Ximian, Inc. http://www.ximian.com
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Globalization;
+using MonoForks.System;
+using MonoForks.System.Net;
+using MonoForks.System.Net.Sockets;
+using System.Runtime.InteropServices;
+
+namespace MonoForks.System.Net {
+
+ /// <remarks>
+ /// Encapsulates an IP Address.
+ /// </remarks>
+ [Serializable]
+ public class IPAddress {
+ // Don't change the name of this field without also
+ // changing socket-io.c in the runtime
+ // The IP address is stored in little-endian order inside the int,
+ // meaning the lower order bytes contain the netid
+ private long m_Address;
+ private AddressFamily m_Family;
+ private ushort[] m_Numbers; /// ip6 Stored in network order (as ip4)
+ private long m_ScopeId;
+
+ public static readonly IPAddress Any = new IPAddress(0);
+ public static readonly IPAddress Broadcast = IPAddress.Parse ("255.255.255.255");
+ public static readonly IPAddress Loopback = IPAddress.Parse ("127.0.0.1");
+ public static readonly IPAddress None = IPAddress.Parse ("255.255.255.255");
+ public static readonly IPAddress IPv6Any = IPAddress.ParseIPV6 ("::");
+ public static readonly IPAddress IPv6Loopback = IPAddress.ParseIPV6 ("::1");
+ public static readonly IPAddress IPv6None = IPAddress.ParseIPV6 ("::");
+
+ private static short SwapShort (short number)
+ {
+ return (short) ( ((number >> 8) & 0xFF) | ((number << 8) & 0xFF00) );
+ }
+
+ private static int SwapInt (int number)
+ {
+ return (((number >> 24) & 0xFF)
+ | ((number >> 08) & 0xFF00)
+ | ((number << 08) & 0xFF0000)
+ | ((number << 24)));
+ }
+
+ private static long SwapLong(long number)
+ {
+ return (((number >> 56) & 0xFF)
+ | ((number >> 40) & 0xFF00)
+ | ((number >> 24) & 0xFF0000)
+ | ((number >> 08) & 0xFF000000)
+ | ((number << 08) & 0xFF00000000)
+ | ((number << 24) & 0xFF0000000000)
+ | ((number << 40) & 0xFF000000000000)
+ | ((number << 56)));
+ }
+
+ public static short HostToNetworkOrder(short host) {
+ if (!BitConverter.IsLittleEndian)
+ return(host);
+
+ return SwapShort (host);
+ }
+
+ public static int HostToNetworkOrder(int host) {
+ if (!BitConverter.IsLittleEndian)
+ return(host);
+
+ return SwapInt (host);
+ }
+
+ public static long HostToNetworkOrder(long host) {
+ if (!BitConverter.IsLittleEndian)
+ return(host);
+
+ return SwapLong (host);
+ }
+
+ public static short NetworkToHostOrder(short network) {
+ if (!BitConverter.IsLittleEndian)
+ return(network);
+
+ return SwapShort (network);
+ }
+
+ public static int NetworkToHostOrder(int network) {
+ if (!BitConverter.IsLittleEndian)
+ return(network);
+
+ return SwapInt (network);
+ }
+
+ public static long NetworkToHostOrder(long network) {
+ if (!BitConverter.IsLittleEndian)
+ return(network);
+
+ return SwapLong (network);
+ }
+
+ /// <summary>
+ /// Constructor from a 32-bit constant with the address bytes in
+ /// little-endian order (the lower order bytes contain the netid)
+ /// </summary>
+ public IPAddress (long addr)
+ {
+ m_Address = addr;
+ m_Family = AddressFamily.InterNetwork;
+ }
+
+ public IPAddress (byte[] address)
+ {
+ if (address == null)
+ throw new ArgumentNullException ("address");
+
+ int len = address.Length;
+
+#if NET_2_0
+ if (len != 16 && len != 4)
+ throw new ArgumentException ("An invalid IP address was specified.",
+ "address");
+#else
+ if (len != 16)
+ throw new ArgumentException ("address");
+#endif
+
+ if (len == 16) {
+ m_Numbers = new ushort [8];
+ Buffer.BlockCopy(address, 0, m_Numbers, 0, 16);
+ m_Family = AddressFamily.InterNetworkV6;
+ m_ScopeId = 0;
+ } else {
+ m_Address = ((uint) address [3] << 24) + (address [2] << 16) +
+ (address [1] << 8) + address [0];
+ m_Family = AddressFamily.InterNetwork;
+ }
+ }
+
+ public IPAddress(byte[] address, long scopeId)
+ {
+ if (address == null)
+ throw new ArgumentNullException ("address");
+
+ if (address.Length != 16)
+#if NET_2_0
+ throw new ArgumentException ("An invalid IP address was specified.",
+ "address");
+#else
+ throw new ArgumentException("address");
+#endif
+
+ m_Numbers = new ushort [8];
+ Buffer.BlockCopy(address, 0, m_Numbers, 0, 16);
+ m_Family = AddressFamily.InterNetworkV6;
+ m_ScopeId = scopeId;
+ }
+
+ internal IPAddress(ushort[] address, long scopeId)
+ {
+ m_Numbers = address;
+
+ for(int i=0; i<8; i++)
+ m_Numbers[i] = (ushort)HostToNetworkOrder((short)m_Numbers[i]);
+
+ m_Family = AddressFamily.InterNetworkV6;
+ m_ScopeId = scopeId;
+ }
+
+ public static IPAddress Parse (string ipString)
+ {
+ IPAddress ret;
+ if (TryParse (ipString, out ret))
+ return ret;
+ throw new FormatException ("An invalid IP address was specified.");
+ }
+
+#if NET_2_0
+ public
+#else
+ internal
+#endif
+ static bool TryParse (string ipString, out IPAddress address)
+ {
+ if (ipString == null)
+ throw new ArgumentNullException ("ipString");
+
+ if ((address = ParseIPV4 (ipString)) == null)
+ if ((address = ParseIPV6 (ipString)) == null)
+ return false;
+ return true;
+ }
+
+ private static IPAddress ParseIPV4 (string ip)
+ {
+#if ONLY_1_1
+ if (ip.Length == 0 || ip == " ")
+ return new IPAddress (0);
+#endif
+
+ int pos = ip.IndexOf (' ');
+ if (pos != -1) {
+#if NET_2_0
+ string [] nets = ip.Substring (pos + 1).Split (new char [] {'.'});
+ if (nets.Length > 0) {
+ string lastNet = nets [nets.Length - 1];
+ if (lastNet.Length == 0)
+ return null;
+#if NET_2_1 //workaround for smcs, as it generate code that can't access string.GetEnumerator ()
+ foreach (char c in lastNet.ToCharArray ())
+#else
+ foreach (char c in lastNet)
+#endif
+ if (!Uri.IsHexDigit (c))
+ return null;
+ }
+#endif
+ ip = ip.Substring (0, pos);
+ }
+
+ if (ip.Length == 0 || ip [ip.Length - 1] == '.')
+ return null;
+
+ string [] ips = ip.Split (new char [] {'.'});
+ if (ips.Length > 4)
+ return null;
+
+ // Make the number in network order
+ try {
+ long a = 0;
+ long val = 0;
+ for (int i = 0; i < ips.Length; i++) {
+ string subnet = ips [i];
+ if ((3 <= subnet.Length && subnet.Length <= 4) &&
+ (subnet [0] == '0') && (subnet [1] == 'x' || subnet [1] == 'X')) {
+ if (subnet.Length == 3)
+ val = (byte) Uri.FromHex (subnet [2]);
+ else
+ val = (byte) ((Uri.FromHex (subnet [2]) << 4) | Uri.FromHex (subnet [3]));
+ } else if (subnet.Length == 0)
+ return null;
+ else if (subnet [0] == '0') {
+ // octal
+ val = 0;
+ for (int j = 1; j < subnet.Length; j++) {
+ if ('0' <= subnet [j] && subnet [j] <= '7')
+ val = (val << 3) + subnet [j] - '0';
+ else
+ return null;
+ }
+ }
+ else {
+#if NET_2_0
+ if (!Int64.TryParse (subnet, NumberStyles.None, null, out val))
+ return null;
+#else
+ val = long.Parse (subnet, NumberStyles.None);
+#endif
+ }
+
+ if (i == (ips.Length - 1))
+ i = 3;
+ else if (val > 0xFF)
+ return null; // e.g. 256.0.0.1
+ for (int j = 0; val > 0; j++, val /= 0x100)
+ a |= (val & 0xFF) << ((i - j) << 3);
+ }
+
+ return (new IPAddress (a));
+ } catch (Exception) {
+ return null;
+ }
+ }
+
+ private static IPAddress ParseIPV6 (string ip)
+ {
+ IPv6Address newIPv6Address;
+
+ if (IPv6Address.TryParse(ip, out newIPv6Address))
+ return new IPAddress (newIPv6Address.Address, newIPv6Address.ScopeId);
+ return null;
+ }
+
+ [Obsolete("This property is obsolete. Use GetAddressBytes.")]
+ public long Address
+ {
+ get {
+ if(m_Family != AddressFamily.InterNetwork)
+ throw new Exception("The attempted operation is not supported for the type of object referenced");
+
+ return m_Address;
+ }
+ set {
+ /* no need to do this test, ms.net accepts any value.
+ if (value < 0 || value > 0x00000000FFFFFFFF)
+ throw new ArgumentOutOfRangeException (
+ "the address must be between 0 and 0xFFFFFFFF");
+ */
+
+ if(m_Family != AddressFamily.InterNetwork)
+ throw new Exception("The attempted operation is not supported for the type of object referenced");
+
+ m_Address = value;
+ }
+ }
+
+ internal long InternalIPv4Address {
+ get { return m_Address; }
+ }
+
+#if NET_2_0
+ public bool IsIPv6LinkLocal {
+ get {
+ if (m_Family == AddressFamily.InterNetwork)
+ return false;
+ int v = NetworkToHostOrder ((short) m_Numbers [0]) & 0xFFF0;
+ return 0xFE80 <= v && v < 0xFEC0;
+ }
+ }
+
+ public bool IsIPv6SiteLocal {
+ get {
+ if (m_Family == AddressFamily.InterNetwork)
+ return false;
+ int v = NetworkToHostOrder ((short) m_Numbers [0]) & 0xFFF0;
+ return 0xFEC0 <= v && v < 0xFF00;
+ }
+ }
+
+ public bool IsIPv6Multicast {
+ get {
+ return m_Family != AddressFamily.InterNetwork &&
+ ((ushort) NetworkToHostOrder ((short) m_Numbers [0]) & 0xFF00) == 0xFF00;
+ }
+ }
+#endif
+
+ public long ScopeId {
+ get {
+ if(m_Family != AddressFamily.InterNetworkV6)
+ throw new Exception("The attempted operation is not supported for the type of object referenced");
+
+ return m_ScopeId;
+ }
+ set {
+ if(m_Family != AddressFamily.InterNetworkV6)
+ throw new Exception("The attempted operation is not supported for the type of object referenced");
+
+ m_ScopeId = value;
+ }
+ }
+
+ public byte [] GetAddressBytes ()
+ {
+ if(m_Family == AddressFamily.InterNetworkV6) {
+ byte [] addressBytes = new byte [16];
+ Buffer.BlockCopy (m_Numbers, 0, addressBytes, 0, 16);
+ return addressBytes;
+ } else {
+ return new byte [4] { (byte)(m_Address & 0xFF),
+ (byte)((m_Address >> 8) & 0xFF),
+ (byte)((m_Address >> 16) & 0xFF),
+ (byte)(m_Address >> 24) };
+ }
+ }
+
+ public AddressFamily AddressFamily
+ {
+ get {
+ return m_Family;
+ }
+ }
+
+
+ /// <summary>
+ /// Used to tell whether an address is a loopback.
+ /// All IP addresses of the form 127.X.Y.Z, where X, Y, and Z are in
+ /// the range 0-255, are loopback addresses.
+ /// </summary>
+ /// <param name="addr">Address to compare</param>
+ /// <returns></returns>
+ public static bool IsLoopback (IPAddress addr)
+ {
+ if(addr.m_Family == AddressFamily.InterNetwork)
+ return (addr.m_Address & 0xFF) == 127;
+ else {
+ for(int i=0; i<6; i++) {
+ if(addr.m_Numbers[i] != 0)
+ return false;
+ }
+
+ return NetworkToHostOrder((short)addr.m_Numbers[7]) == 1;
+ }
+ }
+
+ /// <summary>
+ /// Overrides System.Object.ToString to return
+ /// this object rendered in a quad-dotted notation
+ /// </summary>
+ public override string ToString ()
+ {
+ if(m_Family == AddressFamily.InterNetwork)
+ return ToString (m_Address);
+ else
+ {
+ ushort[] numbers = m_Numbers.Clone() as ushort[];
+
+ for(int i=0; i<numbers.Length; i++)
+ numbers[i] = (ushort)NetworkToHostOrder((short)numbers[i]);
+
+ IPv6Address v6 = new IPv6Address(numbers);
+ v6.ScopeId = ScopeId;
+ return v6.ToString();
+ }
+ }
+
+ /// <summary>
+ /// Returns this object rendered in a quad-dotted notation
+ /// </summary>
+ static string ToString (long addr)
+ {
+ // addr is in network order
+ return (addr & 0xff).ToString () + "." +
+ ((addr >> 8) & 0xff).ToString () + "." +
+ ((addr >> 16) & 0xff).ToString () + "." +
+ ((addr >> 24) & 0xff).ToString ();
+ }
+
+ /// <returns>
+ /// Whether both objects are equal.
+ /// </returns>
+ public override bool Equals (object other)
+ {
+ if (other is System.Net.IPAddress){
+ IPAddress otherAddr = other as IPAddress;
+
+ if(AddressFamily != otherAddr.AddressFamily)
+ return false;
+
+ if(AddressFamily == AddressFamily.InterNetwork) {
+ return m_Address == otherAddr.m_Address;
+ } else {
+ ushort[] vals = otherAddr.m_Numbers;
+
+ for(int i=0; i<8; i++)
+ if(m_Numbers[i] != vals[i])
+ return false;
+
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public override int GetHashCode ()
+ {
+ if(m_Family == AddressFamily.InterNetwork)
+ return (int)m_Address;
+ else
+ return Hash (((((int) m_Numbers[0]) << 16) + m_Numbers [1]),
+ ((((int) m_Numbers [2]) << 16) + m_Numbers [3]),
+ ((((int) m_Numbers [4]) << 16) + m_Numbers [5]),
+ ((((int) m_Numbers [6]) << 16) + m_Numbers [7]));
+ }
+
+ private static int Hash (int i, int j, int k, int l)
+ {
+ return i ^ (j << 13 | j >> 19) ^ (k << 26 | k >> 6) ^ (l << 7 | l >> 25);
+ }
+
+#pragma warning disable 169
+ // Added for serialization compatibility with MS.NET
+ private int m_HashCode;
+#pragma warning restore
+
+ }
+}
diff --git a/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/IPv6Address.cs b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/IPv6Address.cs
new file mode 100644
index 0000000..4d9e7d3
--- /dev/null
+++ b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/IPv6Address.cs
@@ -0,0 +1,478 @@
+//
+// System.Net.IPv6Address.cs
+//
+// Author:
+// Lawrence Pit (loz@cable.a2000.nl)
+//
+// Note I: This class is not defined in the specs of .Net
+//
+// Note II : The name of this class is perhaps unfortunate as it turns
+// out that in ms.net there's an internal class called
+// IPv6Address in namespace System.
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+
+using System;
+using System.Globalization;
+using MonoForks.System;
+using MonoForks.System.Net;
+using MonoForks.System.Net.Sockets;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace MonoForks.System.Net {
+
+ /// <remarks>
+ /// Encapsulates an IPv6 Address.
+ /// See RFC 2373 for more info on IPv6 addresses.
+ /// </remarks>
+ [Serializable]
+ internal class IPv6Address {
+ private ushort [] address;
+ private int prefixLength;
+ private long scopeId = 0;
+
+ public static readonly IPv6Address Loopback = IPv6Address.Parse ("::1");
+ public static readonly IPv6Address Unspecified = IPv6Address.Parse ("::");
+
+ public IPv6Address (ushort [] addr)
+ {
+ if (addr == null)
+ throw new ArgumentNullException ("addr");
+ if (addr.Length != 8)
+ throw new ArgumentException ("addr");
+ address = addr;
+ }
+
+ public IPv6Address (ushort [] addr, int prefixLength) : this (addr)
+ {
+ if (prefixLength < 0 || prefixLength > 128)
+ throw new ArgumentException ("prefixLength");
+ this.prefixLength = prefixLength;
+ }
+
+ public IPv6Address (ushort [] addr, int prefixLength, int scopeId) : this (addr, prefixLength)
+ {
+ this.scopeId = scopeId;
+ }
+
+ public static IPv6Address Parse (string ipString)
+ {
+ if (ipString == null)
+ throw new ArgumentNullException ("ipString");
+
+ IPv6Address result;
+ if (TryParse (ipString, out result))
+ return result;
+ throw new FormatException ("Not a valid IPv6 address");
+ }
+
+ static int Fill (ushort [] addr, string ipString)
+ {
+ int p = 0;
+ int slot = 0;
+
+ if (ipString.Length == 0)
+ return 0;
+
+ // Catch double uses of ::
+ if (ipString.IndexOf ("::") != -1)
+ return -1;
+
+ for (int i = 0; i < ipString.Length; i++){
+ char c = ipString [i];
+ int n;
+
+ if (c == ':'){
+ // Trailing : is not allowed.
+ if (i == ipString.Length-1)
+ return -1;
+
+ if (slot == 8)
+ return -1;
+
+ addr [slot++] = (ushort) p;
+ p = 0;
+ continue;
+ } if ('0' <= c && c <= '9')
+ n = (int) (c - '0');
+ else if ('a' <= c && c <= 'f')
+ n = (int) (c - 'a' + 10);
+ else if ('A' <= c && c <= 'F')
+ n = (int) (c - 'A' + 10);
+ else
+ return -1;
+ p = (p << 4) + n;
+ if (p > UInt16.MaxValue)
+ return -1;
+ }
+
+ if (slot == 8)
+ return -1;
+
+ addr [slot++] = (ushort) p;
+
+ return slot;
+ }
+
+ static bool TryParse (string prefix, out int res)
+ {
+#if NET_2_0
+ return Int32.TryParse (prefix, NumberStyles.Integer, CultureInfo.InvariantCulture, out res);
+#else
+ try {
+ res = Int32.Parse (prefix, NumberStyles.Integer, CultureInfo.InvariantCulture);
+ } catch (Exception) {
+ res = -1;
+ return false;
+ }
+
+ return true;
+#endif
+ }
+
+ public static bool TryParse (string ipString, out IPv6Address result)
+ {
+ result = null;
+ if (ipString == null)
+ return false;
+
+ if (ipString.Length > 2 &&
+ ipString [0] == '[' &&
+ ipString [ipString.Length - 1] == ']')
+ ipString = ipString.Substring (1, ipString.Length - 2);
+
+ if (ipString.Length < 2)
+ return false;
+
+ int prefixLen = 0;
+ int scopeId = 0;
+ int pos = ipString.LastIndexOf ('/');
+ if (pos != -1) {
+ string prefix = ipString.Substring (pos + 1);
+ if (!TryParse (prefix , out prefixLen))
+ prefixLen = -1;
+ if (prefixLen < 0 || prefixLen > 128)
+ return false;
+ ipString = ipString.Substring (0, pos);
+ } else {
+ pos = ipString.LastIndexOf ('%');
+ if (pos != -1) {
+ string prefix = ipString.Substring (pos + 1);
+ if (!TryParse (prefix, out scopeId))
+ scopeId = 0;
+ ipString = ipString.Substring (0, pos);
+ }
+ }
+
+ //
+ // At this point the prefix/suffixes have been removed
+ // and we only have to deal with the ipv4 or ipv6 addressed
+ //
+ ushort [] addr = new ushort [8];
+
+ //
+ // Is there an ipv4 address at the end?
+ //
+ bool ipv4 = false;
+ int pos2 = ipString.LastIndexOf (':');
+ if (pos2 == -1)
+ return false;
+
+ int slots = 0;
+ if (pos2 < (ipString.Length - 1)) {
+ string ipv4Str = ipString.Substring (pos2 + 1);
+ if (ipv4Str.IndexOf ('.') != -1) {
+ IPAddress ip;
+
+ if (!IPAddress.TryParse (ipv4Str, out ip))
+ return false;
+
+ long a = ip.InternalIPv4Address;
+ addr [6] = (ushort) (((int) (a & 0xff) << 8) + ((int) ((a >> 8) & 0xff)));
+ addr [7] = (ushort) (((int) ((a >> 16) & 0xff) << 8) + ((int) ((a >> 24) & 0xff)));
+ if (pos2 > 0 && ipString [pos2 - 1] == ':')
+ ipString = ipString.Substring (0, pos2 + 1);
+ else
+ ipString = ipString.Substring (0, pos2);
+ ipv4 = true;
+ slots = 2;
+ }
+ }
+
+ //
+ // Only an ipv6 block remains, either:
+ // "hexnumbers::hexnumbers", "hexnumbers::" or "hexnumbers"
+ //
+ int c = ipString.IndexOf ("::");
+ if (c != -1){
+ int right_slots = Fill (addr, ipString.Substring (c+2));
+ if (right_slots == -1){
+ return false;
+ }
+
+ if (right_slots + slots > 8){
+ return false;
+ }
+
+ int d = 8-slots-right_slots;
+ for (int i = right_slots; i > 0; i--){
+ addr [i+d-1] = addr [i-1];
+ addr [i-1] = 0;
+ }
+
+ int left_slots = Fill (addr, ipString.Substring (0, c));
+ if (left_slots == -1)
+ return false;
+
+ if (left_slots + right_slots + slots > 7)
+ return false;
+ } else {
+ if (Fill (addr, ipString) != 8-slots)
+ return false;
+ }
+
+ // Now check the results in the ipv6-address range only
+ bool ipv6 = false;
+ for (int i = 0; i < slots; i++){
+ if (addr [i] != 0 || i == 5 && addr [i] != 0xffff)
+ ipv6 = true;
+ }
+
+ // check IPv4 validity
+ if (ipv4 && !ipv6) {
+ for (int i = 0; i < 5; i++) {
+ if (addr [i] != 0)
+ return false;
+ }
+
+ if (addr [5] != 0 && addr [5] != 0xffff)
+ return false;
+ }
+
+ result = new IPv6Address (addr, prefixLen, scopeId);
+ return true;
+ }
+
+ public ushort [] Address {
+ get { return address; }
+ }
+
+ public int PrefixLength {
+ get { return this.prefixLength; }
+ }
+
+ public long ScopeId {
+ get {
+ return scopeId;
+ }
+ set {
+ scopeId = value;
+ }
+ }
+
+ public ushort this [int index] {
+ get { return address [index]; }
+ }
+
+ public AddressFamily AddressFamily {
+ get { return AddressFamily.InterNetworkV6; }
+ }
+
+ public static bool IsLoopback (IPv6Address addr)
+ {
+ if (addr.address [7] != 1)
+ return false;
+
+ int x = addr.address [6] >> 8;
+ if (x != 0x7f && x != 0)
+ return false;
+
+ for (int i = 0; i < 4; i++) {
+ if (addr.address [i] != 0)
+ return false;
+ }
+
+ if (addr.address [5] != 0 && addr.address [5] != 0xffff)
+ return false;
+
+ return true;
+ }
+
+ private static ushort SwapUShort (ushort number)
+ {
+ return (ushort) ( ((number >> 8) & 0xFF) + ((number << 8) & 0xFF00) );
+ }
+
+ // Convert the address into a format expected by the IPAddress (long) ctor
+ private int AsIPv4Int ()
+ {
+ return (SwapUShort (address [7]) << 16) + SwapUShort (address [6]);
+ }
+
+ public bool IsIPv4Compatible ()
+ {
+ for (int i = 0; i < 6; i++)
+ if (address [i] != 0)
+ return false;
+ return (AsIPv4Int () > 1);
+ }
+
+ public bool IsIPv4Mapped ()
+ {
+ for (int i = 0; i < 5; i++)
+ if (address [i] != 0)
+ return false;
+ return address [5] == 0xffff;
+ }
+
+ /// <summary>
+ /// Overrides System.Object.ToString to return
+ /// this object rendered in a canonicalized notation
+ /// </summary>
+ public override string ToString ()
+ {
+ StringBuilder s = new StringBuilder ();
+
+
+ if(IsIPv4Compatible() || IsIPv4Mapped())
+ {
+ s.Append("::");
+
+ if(IsIPv4Mapped())
+ s.Append("ffff:");
+
+ s.Append(new IPAddress( AsIPv4Int ()).ToString ());
+
+ return s.ToString ();
+ }
+ else
+ {
+ int bestChStart = -1; // Best chain start
+ int bestChLen = 0; // Best chain length
+ int currChLen = 0; // Current chain length
+
+ // Looks for the longest zero chain
+ for (int i=0; i<8; i++)
+ {
+ if (address[i] != 0)
+ {
+ if ((currChLen > bestChLen)
+ && (currChLen > 1))
+ {
+ bestChLen = currChLen;
+ bestChStart = i - currChLen;
+ }
+ currChLen = 0;
+ }
+ else
+ currChLen++;
+ }
+ if ((currChLen > bestChLen)
+ && (currChLen > 1))
+ {
+ bestChLen = currChLen;
+ bestChStart = 8 - currChLen;
+ }
+
+ // makes the string
+ if (bestChStart == 0)
+ s.Append(":");
+ for (int i=0; i<8; i++)
+ {
+ if (i == bestChStart)
+ {
+ s.Append (":");
+ i += (bestChLen - 1);
+ continue;
+ }
+ s.AppendFormat("{0:x}", address [i]);
+ if (i < 7) s.Append (':');
+ }
+ }
+ if (scopeId != 0)
+ s.Append ('%').Append (scopeId);
+ return s.ToString ();
+ }
+
+ public string ToString (bool fullLength)
+ {
+ if (!fullLength)
+ return ToString ();
+
+ StringBuilder sb = new StringBuilder ();
+ for (int i=0; i < address.Length - 1; i++) {
+ sb.AppendFormat ("{0:X4}:", address [i]);
+ }
+ sb.AppendFormat ("{0:X4}", address [address.Length - 1]);
+ return sb.ToString ();
+ }
+
+ /// <returns>
+ /// Whether both objects are equal.
+ /// </returns>
+ public override bool Equals (object other)
+ {
+ System.Net.IPv6Address ipv6 = other as System.Net.IPv6Address;
+ if (ipv6 != null) {
+ for (int i = 0; i < 8; i++)
+ if (this.address [i] != ipv6.address [i])
+ return false;
+ return true;
+ }
+
+ System.Net.IPAddress ipv4 = other as System.Net.IPAddress;
+ if (ipv4 != null) {
+ for (int i = 0; i < 5; i++)
+ if (address [i] != 0)
+ return false;
+
+ if (address [5] != 0 && address [5] != 0xffff)
+ return false;
+
+ long a = ipv4.InternalIPv4Address;
+ if (address [6] != (ushort) (((int) (a & 0xff) << 8) + ((int) ((a >> 8) & 0xff))) ||
+ address [7] != (ushort) (((int) ((a >> 16) & 0xff) << 8) + ((int) ((a >> 24) & 0xff))))
+ return false;
+
+ return true;
+ }
+
+ return false;
+ }
+
+ public override int GetHashCode ()
+ {
+ return Hash (((((int) address [0]) << 16) + address [1]),
+ ((((int) address [2]) << 16) + address [3]),
+ ((((int) address [4]) << 16) + address [5]),
+ ((((int) address [6]) << 16) + address [7]));
+ }
+
+ private static int Hash (int i, int j, int k, int l)
+ {
+ return i ^ (j << 13 | j >> 19) ^ (k << 26 | k >> 6) ^ (l << 7 | l >> 25);
+ }
+ }
+}
diff --git a/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/Locale.cs b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/Locale.cs
new file mode 100644
index 0000000..27a4f39
--- /dev/null
+++ b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/Locale.cs
@@ -0,0 +1,14 @@
+internal class MonoTODOAttribute : System.Attribute
+{
+ public MonoTODOAttribute(string s)
+ {
+}
+}
+
+internal static class Locale
+{
+ public static string GetText(string s)
+ {
+ return s;
+ }
+}
diff --git a/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/MiniParser.cs b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/MiniParser.cs
new file mode 100644
index 0000000..8934ffc
--- /dev/null
+++ b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/MiniParser.cs
@@ -0,0 +1,628 @@
+//
+// System.Security.Cryptography.MiniParser: Internal XML parser implementation
+//
+// Authors:
+// Sergey Chaban
+//
+// Copyright (c) 2001, 2002 Wild West Software
+// Copyright (c) 2002 Sergey Chaban
+// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Text;
+using System.Collections;
+using System.Globalization;
+
+namespace MonoForks.Mono.Xml
+{
+
+#if INSIDE_CORLIB
+ internal
+#else
+// [CLSCompliant(false)]
+ public
+#endif
+class MiniParser {
+
+ public interface IReader {
+ int Read();
+ }
+
+ public interface IAttrList {
+ int Length {get;}
+ bool IsEmpty {get;}
+ string GetName(int i);
+ string GetValue(int i);
+ string GetValue(string name);
+ void ChangeValue(string name, string newValue);
+ string[] Names {get;}
+ string[] Values {get;}
+ }
+
+ public interface IMutableAttrList : IAttrList {
+ void Clear();
+ void Add(string name, string value);
+ void CopyFrom(IAttrList attrs);
+ void Remove(int i);
+ void Remove(string name);
+ }
+
+ public interface IHandler {
+ void OnStartParsing(MiniParser parser);
+ void OnStartElement(string name, IAttrList attrs);
+ void OnEndElement(string name);
+ void OnChars(string ch);
+ void OnEndParsing(MiniParser parser);
+ }
+
+ public class HandlerAdapter : IHandler {
+ public HandlerAdapter() {}
+ public void OnStartParsing(MiniParser parser) {}
+ public void OnStartElement(string name, IAttrList attrs) {}
+ public void OnEndElement(string name) {}
+ public void OnChars(string ch) {}
+ public void OnEndParsing(MiniParser parser) {}
+ }
+
+ private enum CharKind : byte {
+ LEFT_BR = 0,
+ RIGHT_BR = 1,
+ SLASH = 2,
+ PI_MARK = 3,
+ EQ = 4,
+ AMP = 5,
+ SQUOTE = 6,
+ DQUOTE = 7,
+ BANG = 8,
+ LEFT_SQBR = 9,
+ SPACE = 0xA,
+ RIGHT_SQBR = 0xB,
+ TAB = 0xC,
+ CR = 0xD,
+ EOL = 0xE,
+ CHARS = 0xF,
+ UNKNOWN = 0x1F
+ }
+
+ private enum ActionCode : byte {
+ START_ELEM = 0,
+ END_ELEM = 1,
+ END_NAME = 2,
+ SET_ATTR_NAME = 3,
+ SET_ATTR_VAL = 4,
+ SEND_CHARS = 5,
+ START_CDATA = 6,
+ END_CDATA = 7,
+ ERROR = 8,
+ STATE_CHANGE = 9,
+ FLUSH_CHARS_STATE_CHANGE = 0xA,
+ ACC_CHARS_STATE_CHANGE = 0xB,
+ ACC_CDATA = 0xC,
+ PROC_CHAR_REF = 0xD,
+ UNKNOWN = 0xF
+ }
+
+ public class AttrListImpl : IMutableAttrList {
+ protected ArrayList names;
+ protected ArrayList values;
+
+ public AttrListImpl() : this(0) {}
+
+ public AttrListImpl(int initialCapacity) {
+ if (initialCapacity <= 0) {
+ names = new ArrayList();
+ values = new ArrayList();
+ } else {
+ names = new ArrayList(initialCapacity);
+ values = new ArrayList(initialCapacity);
+ }
+ }
+
+ public AttrListImpl(IAttrList attrs)
+ : this(attrs != null ? attrs.Length : 0) {
+ if (attrs != null) this.CopyFrom(attrs);
+ }
+
+ public int Length {
+ get {return names.Count;}
+ }
+
+ public bool IsEmpty {
+ get {return this.Length != 0;}
+ }
+
+ public string GetName(int i) {
+ string res = null;
+ if (i >= 0 && i < this.Length) {
+ res = names[i] as string;
+ }
+ return res;
+ }
+
+ public string GetValue(int i) {
+ string res = null;
+ if (i >= 0 && i < this.Length) {
+ res = values[i] as string;
+ }
+ return res;
+ }
+
+ public string GetValue(string name) {
+ return this.GetValue(names.IndexOf(name));
+ }
+
+ public void ChangeValue(string name, string newValue) {
+ int i = names.IndexOf(name);
+ if (i >= 0 && i < this.Length) {
+ values[i] = newValue;
+ }
+ }
+
+ public string[] Names {
+ get {return names.ToArray(typeof(string)) as string[];}
+ }
+
+ public string[] Values {
+ get {return values.ToArray(typeof(string)) as string[];}
+ }
+
+ public void Clear() {
+ names.Clear();
+ values.Clear();
+ }
+
+ public void Add(string name, string value) {
+ names.Add(name);
+ values.Add(value);
+ }
+
+ public void Remove(int i) {
+ if (i >= 0) {
+ names.RemoveAt(i);
+ values.RemoveAt(i);
+ }
+ }
+
+ public void Remove(string name) {
+ this.Remove(names.IndexOf(name));
+ }
+
+ public void CopyFrom(IAttrList attrs) {
+ if (attrs != null && ((object)this == (object)attrs)) {
+ this.Clear();
+ int n = attrs.Length;
+ for (int i = 0; i < n; i++) {
+ this.Add(attrs.GetName(i), attrs.GetValue(i));
+ }
+ }
+ }
+ }
+
+ public class XMLError : Exception {
+ protected string descr;
+ protected int line, column;
+ public XMLError() : this("Unknown") {}
+ public XMLError(string descr) : this(descr, -1, -1) {}
+ public XMLError(string descr, int line, int column)
+ : base(descr) {
+ this.descr = descr;
+ this.line = line;
+ this.column = column;
+ }
+ public int Line {get {return line;}}
+ public int Column {get {return column;}}
+ public override string ToString() {
+ return (String.Format("{0} @ (line = {1}, col = {2})", descr, line, column));
+ }
+ }
+
+ private static readonly int INPUT_RANGE = 13;
+ private static readonly ushort[] tbl = {
+ (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 1), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 0), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ERROR << 8) | 128), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ERROR << 8) | 128), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 128), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 128), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 128), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 128), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 128), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 128), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 128), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 128), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 128),
+ (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 2), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 133), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 16), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.FLUSH_CHARS_STATE_CHANGE << 8) | 4),
+ (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.END_ELEM << 8) | 0), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 2), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 2), (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129),
+ (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 5), (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3),
+ (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 4), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.END_NAME << 8) | 6), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.END_NAME << 8) | 7), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.END_NAME << 8) | 8), (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129),
+ (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 0), (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3),
+ (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 0), (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ERROR << 8) | 129),
+ (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.FLUSH_CHARS_STATE_CHANGE << 8) | 1), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.PROC_CHAR_REF << 8) | 10), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 7), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10),
+ (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 9), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.START_ELEM << 8) | 6), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.START_ELEM << 8) | 7), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 8), (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129),
+ (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 9), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.SET_ATTR_NAME << 8) | 11), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 12), (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 130),
+ (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 13), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.PROC_CHAR_REF << 8) | 10), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10),
+ (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 14), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 15), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 11), (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 132), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ERROR << 8) | 132), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 132), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 132), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 132), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 132), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 132), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 132), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 132), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ERROR << 8) | 132),
+ (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.SET_ATTR_NAME << 8) | 11), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 12), (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ERROR << 8) | 130),
+ (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.SEND_CHARS << 8) | 2), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 16), (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 134), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 134), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 134), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 134), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 134), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 134), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 134), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ERROR << 8) | 134), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 134), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 134), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ERROR << 8) | 134),
+ (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.SET_ATTR_VAL << 8) | 17), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.PROC_CHAR_REF << 8) | 14), (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14),
+ (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.SET_ATTR_VAL << 8) | 17), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.PROC_CHAR_REF << 8) | 15), (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15),
+ (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.START_CDATA << 8) | 18), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 0), (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19),
+ (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.START_ELEM << 8) | 6), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.START_ELEM << 8) | 7), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 17), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 9), (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129),
+ (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.END_CDATA << 8) | 10), (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18),
+ (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19),
+ (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.UNKNOWN << 8) | 255),
+ 0xFFFF
+ };
+
+ protected static string[] errors = {
+ /* 0 */ "Expected element",
+ /* 1 */ "Invalid character in tag",
+ /* 2 */ "No '='",
+ /* 3 */ "Invalid character entity",
+ /* 4 */ "Invalid attr value",
+ /* 5 */ "Empty tag",
+ /* 6 */ "No end tag",
+ /* 7 */ "Bad entity ref"
+ };
+
+ protected int line;
+ protected int col;
+ protected int[] twoCharBuff;
+ protected bool splitCData;
+
+ public MiniParser() {
+ twoCharBuff = new int[2];
+ splitCData = false;
+ Reset();
+ }
+
+ public void Reset() {
+ line = 0;
+ col = 0;
+ }
+
+ protected static bool StrEquals(string str, StringBuilder sb, int sbStart, int len) {
+ if (len != str.Length) return false;
+ for (int i = 0; i < len; i++) {
+ if (str[i] != sb[sbStart + i]) return false;
+ }
+ return true;
+ }
+
+ protected void FatalErr(string descr) {
+ throw new XMLError(descr, this.line, this.col);
+ }
+
+ protected static int Xlat(int charCode, int state) {
+ int p = state * INPUT_RANGE;
+ int n = Math.Min(tbl.Length - p, INPUT_RANGE);
+ for (;--n >= 0;) {
+ ushort code = tbl[p];
+ if (charCode == (code >> 12)) return (code & 0xFFF);
+ p++;
+ }
+ return 0xFFF;
+ }
+
+ public void Parse(IReader reader, IHandler handler) {
+ if (reader == null) throw new ArgumentNullException("reader");
+ if (handler == null) handler = new HandlerAdapter();
+
+ AttrListImpl attrList = new AttrListImpl();
+ string lastAttrName = null;
+ Stack tagStack = new Stack();
+ string elementName = null;
+ line = 1;
+ col = 0;
+ int currCh = 0;
+ int stateCode = 0;
+ StringBuilder sbChars = new StringBuilder();
+ bool seenCData = false;
+ bool isComment = false;
+ bool isDTD = false;
+ int bracketSwitch = 0;
+
+ handler.OnStartParsing(this);
+
+ while (true) {
+ ++this.col;
+
+ currCh = reader.Read();
+
+ if (currCh == -1) {
+ if (stateCode != 0) {
+ FatalErr("Unexpected EOF");
+ }
+ break;
+ }
+
+ int charCode = "<>/?=&'\"![ ]\t\r\n".IndexOf((char)currCh) & 0xF;
+ if (charCode == (int)CharKind.CR) continue; // ignore
+ // whitepace ::= (#x20 | #x9 | #xd | #xa)+
+ if (charCode == (int)CharKind.TAB) charCode = (int)CharKind.SPACE; // tab == space
+ if (charCode == (int)CharKind.EOL) {
+ this.col = 0;
+ this.line++;
+ charCode = (int)CharKind.SPACE;
+ }
+
+ int actionCode = MiniParser.Xlat(charCode, stateCode);
+ stateCode = actionCode & 0xFF;
+ // Ignore newline inside attribute value.
+ if (currCh == '\n' && (stateCode == 0xE || stateCode == 0xF)) continue;
+ actionCode >>= 8;
+
+ if (stateCode >= 0x80) {
+ if (stateCode == 0xFF) {
+ FatalErr("State dispatch error.");
+ } else {
+ FatalErr(errors[stateCode ^ 0x80]);
+ }
+ }
+
+ switch (actionCode) {
+ case (int)ActionCode.START_ELEM:
+ handler.OnStartElement(elementName, attrList);
+ if (currCh != '/') {
+ tagStack.Push(elementName);
+ } else {
+ handler.OnEndElement(elementName);
+ }
+ attrList.Clear();
+ break;
+
+ case (int)ActionCode.END_ELEM:
+ elementName = sbChars.ToString();
+ sbChars = new StringBuilder();
+ string endName = null;
+ if (tagStack.Count == 0 ||
+ elementName != (endName = tagStack.Pop() as string)) {
+ if (endName == null) {
+ FatalErr("Tag stack underflow");
+ } else {
+ FatalErr(String.Format("Expected end tag '{0}' but found '{1}'", elementName, endName));
+ }
+ }
+ handler.OnEndElement(elementName);
+ break;
+
+ case (int)ActionCode.END_NAME:
+ elementName = sbChars.ToString();
+ sbChars = new StringBuilder();
+ if (currCh != '/' && currCh != '>') break;
+ goto case (int)ActionCode.START_ELEM;
+
+ case (int)ActionCode.SET_ATTR_NAME:
+ lastAttrName = sbChars.ToString();
+ sbChars = new StringBuilder();
+ break;
+
+ case (int)ActionCode.SET_ATTR_VAL:
+ if (lastAttrName == null) FatalErr("Internal error.");
+ attrList.Add(lastAttrName, sbChars.ToString());
+ sbChars = new StringBuilder();
+ lastAttrName = null;
+ break;
+
+ case (int)ActionCode.SEND_CHARS:
+ handler.OnChars(sbChars.ToString());
+ sbChars = new StringBuilder();
+ break;
+
+ case (int)ActionCode.START_CDATA:
+ string cdata = "CDATA[";
+ isComment = false;
+ isDTD = false;
+
+ if (currCh == '-') {
+ currCh = reader.Read();
+
+ if (currCh != '-') FatalErr("Invalid comment");
+
+ this.col++;
+ isComment = true;
+ twoCharBuff[0] = -1;
+ twoCharBuff[1] = -1;
+ } else {
+ if (currCh != '[') {
+ isDTD = true;
+ bracketSwitch = 0;
+ break;
+ }
+
+ for (int i = 0; i < cdata.Length; i++) {
+ if (reader.Read() != cdata[i]) {
+ this.col += i+1;
+ break;
+ }
+ }
+ this.col += cdata.Length;
+ seenCData = true;
+ }
+ break;
+
+ case (int)ActionCode.END_CDATA:
+ int n = 0;
+ currCh = ']';
+
+ while (currCh == ']') {
+ currCh = reader.Read();
+ n++;
+ }
+
+ if (currCh != '>') {
+ for (int i = 0; i < n; i++) sbChars.Append(']');
+ sbChars.Append((char)currCh);
+ stateCode = 0x12;
+ } else {
+ for (int i = 0; i < n-2; i++) sbChars.Append(']');
+ seenCData = false;
+ }
+
+ this.col += n;
+ break;
+
+ case (int)ActionCode.ERROR:
+ FatalErr(String.Format("Error {0}", stateCode));
+ break;
+
+ case (int)ActionCode.STATE_CHANGE:
+ break;
+
+ case (int)ActionCode.FLUSH_CHARS_STATE_CHANGE:
+ sbChars = new StringBuilder();
+ if (currCh != '<') goto case (int)ActionCode.ACC_CHARS_STATE_CHANGE;
+ break;
+
+ case (int)ActionCode.ACC_CHARS_STATE_CHANGE:
+ sbChars.Append((char)currCh);
+ break;
+
+ case (int)ActionCode.ACC_CDATA:
+ if (isComment) {
+ if (currCh == '>'
+ && twoCharBuff[0] == '-'
+ && twoCharBuff[1] == '-') {
+ isComment = false;
+ stateCode = 0;
+ } else {
+ twoCharBuff[0] = twoCharBuff[1];
+ twoCharBuff[1] = currCh;
+ }
+ } else if (isDTD) {
+ if (currCh == '<' || currCh == '>') bracketSwitch ^= 1;
+ if (currCh == '>' && bracketSwitch != 0) {
+ isDTD = false;
+ stateCode = 0;
+ }
+ } else {
+ if (this.splitCData
+ && sbChars.Length > 0
+ && seenCData) {
+ handler.OnChars(sbChars.ToString());
+ sbChars = new StringBuilder();
+ }
+ seenCData = false;
+ sbChars.Append((char)currCh);
+ }
+ break;
+
+ case (int)ActionCode.PROC_CHAR_REF:
+ currCh = reader.Read();
+ int cl = this.col + 1;
+ if (currCh == '#') { // character reference
+ int r = 10;
+ int chCode = 0;
+ int nDigits = 0;
+ currCh = reader.Read();
+ cl++;
+
+ if (currCh == 'x') {
+ currCh = reader.Read();
+ cl++;
+ r=16;
+ }
+
+ NumberStyles style = r == 16 ? NumberStyles.HexNumber : NumberStyles.Integer;
+
+ while (true) {
+ int x = -1;
+ if (Char.IsNumber((char)currCh) || "abcdef".IndexOf(Char.ToLower((char)currCh)) != -1) {
+ try {
+ x = Int32.Parse(new string((char)currCh, 1), style);
+ } catch (FormatException) {x = -1;}
+ }
+ if (x == -1) break;
+ chCode *= r;
+ chCode += x;
+ nDigits++;
+ currCh = reader.Read();
+ cl++;
+ }
+
+ if (currCh == ';' && nDigits > 0) {
+ sbChars.Append((char)chCode);
+ } else {
+ FatalErr("Bad char ref");
+ }
+ } else {
+ // entity reference
+ string entityRefChars = "aglmopqstu"; // amp | apos | quot | gt | lt
+ string entities = "&'\"><";
+
+ int pos = 0;
+ int entIdx = 0xF;
+ int predShift = 0;
+
+ int sbLen = sbChars.Length;
+
+ while (true) {
+ if (pos != 0xF) pos = entityRefChars.IndexOf((char)currCh) & 0xF;
+ if (pos == 0xF) FatalErr(errors[7]);
+ sbChars.Append((char)currCh);
+
+ int path = "\uFF35\u3F8F\u4F8F\u0F5F\uFF78\uE1F4\u2299\uEEFF\uEEFF\uFF4F"[pos];
+ int lBr = (path >> 4) & 0xF;
+ int rBr = path & 0xF;
+ int lPred = path >> 12;
+ int rPred = (path >> 8) & 0xF;
+ currCh = reader.Read();
+ cl++;
+ pos = 0xF;
+ if (lBr != 0xF && currCh == entityRefChars[lBr]) {
+ if (lPred < 0xE) entIdx = lPred;
+// pred = lPred;
+ predShift = 12; // left
+ } else if (rBr != 0xF && currCh == entityRefChars[rBr]) {
+ if (rPred < 0xE) entIdx = rPred;
+// pred = rPred;
+ predShift = 8; // right
+ } else if (currCh == ';') {
+ if (entIdx != 0xF
+ && predShift != 0
+ && ((path >> predShift) & 0xF) == 0xE) break;
+ continue; // pos == 0xF
+ }
+
+ pos=0;
+
+ }
+
+ int l = cl - this.col - 1;
+
+ if ((l > 0 && l < 5)
+ &&(StrEquals("amp", sbChars, sbLen, l)
+ || StrEquals("apos", sbChars, sbLen, l)
+ || StrEquals("quot", sbChars, sbLen, l)
+ || StrEquals("lt", sbChars, sbLen, l)
+ || StrEquals("gt", sbChars, sbLen, l))
+ ) {
+ sbChars.Length = sbLen;
+ sbChars.Append(entities[entIdx]);
+ } else FatalErr(errors[7]);
+ }
+
+ this.col = cl;
+ break;
+
+ default:
+ FatalErr(String.Format("Unexpected action code - {0}.", actionCode));
+ break;
+ }
+ } // while (true)
+
+ handler.OnEndParsing(this);
+
+ } // Parse
+
+}
+
+}
diff --git a/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/NoAccessPolicy.cs b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/NoAccessPolicy.cs
new file mode 100644
index 0000000..166a1d4
--- /dev/null
+++ b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/NoAccessPolicy.cs
@@ -0,0 +1,46 @@
+//
+// System.Windows.Browser.Net.PolicyDownloadPolicy class
+//
+// Contact:
+// Moonlight List (moonlight-list@lists.ximian.com)
+//
+// Copyright (C) 2009 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+#define NET_2_1
+#if NET_2_1
+
+using MonoForks.System;
+using MonoForks.System.Net;
+
+namespace MonoForks.System.Windows.Browser.Net {
+
+ sealed class NoAccessPolicy : ICrossDomainPolicy {
+
+ public bool IsAllowed (WebRequest request)
+ {
+ return false;
+ }
+ }
+}
+
+#endif
+
diff --git a/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/PolicyDownloadPolicy.cs b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/PolicyDownloadPolicy.cs
new file mode 100644
index 0000000..4ea405e
--- /dev/null
+++ b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/PolicyDownloadPolicy.cs
@@ -0,0 +1,59 @@
+//
+// System.Windows.Browser.Net.PolicyDownloadPolicy class
+//
+// Contact:
+// Moonlight List (moonlight-list@lists.ximian.com)
+//
+// Copyright (C) 2009 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#define NET_2_1
+#if NET_2_1
+
+using System;
+using MonoForks.System;
+using MonoForks.System.Net;
+
+namespace MonoForks.System.Windows.Browser.Net {
+
+ sealed class PolicyDownloadPolicy : ICrossDomainPolicy {
+
+ public bool IsAllowed (WebRequest request)
+ {
+ return IsLocalPathPolicy (request.RequestUri);
+ }
+
+ static public bool IsLocalPathPolicy (Uri uri)
+ {
+ string local = uri.LocalPath;
+ if (String.CompareOrdinal (local, CrossDomainPolicyManager.ClientAccessPolicyFile) == 0)
+ return true;
+ if (String.CompareOrdinal (local, CrossDomainPolicyManager.CrossDomainFile) == 0)
+ return true;
+
+ return false;
+ }
+ }
+}
+
+#endif
+
diff --git a/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/SiteOfOriginPolicy.cs b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/SiteOfOriginPolicy.cs
new file mode 100644
index 0000000..d84fbf4
--- /dev/null
+++ b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/SiteOfOriginPolicy.cs
@@ -0,0 +1,55 @@
+//
+// System.Windows.Browser.Net.SiteOfOriginPolicy class
+//
+// Contact:
+// Moonlight List (moonlight-list@lists.ximian.com)
+//
+// Copyright (C) 2009 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#define NET_2_1
+#if NET_2_1
+
+using MonoForks.System;
+using MonoForks.System.Net;
+
+namespace MonoForks.System.Windows.Browser.Net {
+
+ sealed class SiteOfOriginPolicy : ICrossDomainPolicy {
+
+ public bool IsAllowed (WebRequest request)
+ {
+ // a WebRequest to the site of origin (SOO) is always granted
+ return true;
+ }
+
+ // helper to determine if two Uri share the same origin (policy wise)
+ static public bool HasSameOrigin (Uri a, Uri b)
+ {
+ return ((a.Scheme == b.Scheme) && (a.DnsSafeHost == b.DnsSafeHost) &&
+ ((a.Port == -1) || (b.Port == -1) || (a.Port == b.Port)));
+ }
+ }
+}
+
+#endif
+
diff --git a/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/UnityExtra.cs b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/UnityExtra.cs
new file mode 100644
index 0000000..f085b16
--- /dev/null
+++ b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/UnityExtra.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Collections.Generic;
+using MonoForks.System.Net;
+using MonoForks.System;
+
+namespace MonoForks.System.Windows.Interop
+{
+ public class PluginHost
+ {
+ static public Uri SourceUri
+ {
+ get
+ {
+ return new Uri(UnityEngine.UnityCrossDomainHelper.GetWebSecurityHostUri());
+ }
+ }
+ static public Uri RootUri
+ {
+ get
+ {
+ return new Uri(GetRoot(SourceUri));
+ }
+ }
+
+ private static string GetRoot(Uri uri)
+ {
+ if ((uri.Scheme == "http" && uri.Port == 80) || (uri.Scheme == "https" && uri.Port == 443) || (uri.Port == -1))
+ return String.Format("{0}://{1}", uri.Scheme, uri.DnsSafeHost);
+ else
+ return String.Format("{0}://{1}:{2}", uri.Scheme, uri.DnsSafeHost, uri.Port);
+ }
+
+ }
+}
+
+namespace MonoForks.System.Net
+{
+ internal class WebRequest
+ {
+ public WebRequest(MonoForks.System.Uri requesturi, Dictionary<string,string> headers)
+ {
+ this.RequestUri = requesturi;
+ this.Headers = headers;
+ }
+ public MonoForks.System.Uri RequestUri { get; set; }
+ public Dictionary<string,string> Headers { get; set; }
+ }
+}
diff --git a/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/Uri.cs b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/Uri.cs
new file mode 100644
index 0000000..0bf4011
--- /dev/null
+++ b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/Uri.cs
@@ -0,0 +1,2225 @@
+//
+// System.Uri
+//
+// Authors:
+// Lawrence Pit (loz@cable.a2000.nl)
+// Garrett Rooney (rooneg@electricjellyfish.net)
+// Ian MacLean (ianm@activestate.com)
+// Ben Maurer (bmaurer@users.sourceforge.net)
+// Atsushi Enomoto (atsushi@ximian.com)
+// Sebastien Pouliot <sebastien@ximian.com>
+// Stephane Delcroix <stephane@delcroix.org>
+//
+// (C) 2001 Garrett Rooney
+// (C) 2003 Ian MacLean
+// (C) 2003 Ben Maurer
+// Copyright (C) 2003,2005 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// See RFC 2396 for more info on URI's.
+//
+// TODO: optimize by parsing host string only once
+//
+//using System.ComponentModel;
+using System.IO;
+using MonoForks.System.Net;
+using System;
+using System.Runtime.Serialization;
+using System.Text;
+using System.Collections;
+using System.Globalization;
+
+//
+// Disable warnings on Obsolete methods being used
+//
+#pragma warning disable 612
+
+namespace MonoForks.System {
+
+ [Serializable]
+#if NET_2_0
+ [TypeConverter (typeof (UriTypeConverter))]
+ public class Uri : ISerializable {
+#else
+ public class Uri : MarshalByRefObject, ISerializable {
+#endif
+ // NOTES:
+ // o scheme excludes the scheme delimiter
+ // o port is -1 to indicate no port is defined
+ // o path is empty or starts with / when scheme delimiter == "://"
+ // o query is empty or starts with ? char, escaped.
+ // o fragment is empty or starts with # char, unescaped.
+ // o all class variables are in escaped format when they are escapable,
+ // except cachedToString.
+ // o UNC is supported, as starts with "\\" for windows,
+ // or "//" with unix.
+
+ private bool isUnixFilePath;
+ private string source;
+ private string scheme = String.Empty;
+ private string host = String.Empty;
+ private int port = -1;
+ private string path = String.Empty;
+ private string query = String.Empty;
+ private string fragment = String.Empty;
+ private string userinfo = String.Empty;
+ private bool isUnc;
+ private bool isOpaquePart;
+ private bool isAbsoluteUri = true;
+
+ private string [] segments;
+
+ private bool userEscaped;
+ private string cachedAbsoluteUri;
+ private string cachedToString;
+ private string cachedLocalPath;
+ private int cachedHashCode;
+
+ private static readonly string hexUpperChars = "0123456789ABCDEF";
+
+ // Fields
+
+ public static readonly string SchemeDelimiter = "://";
+ public static readonly string UriSchemeFile = "file";
+ public static readonly string UriSchemeFtp = "ftp";
+ public static readonly string UriSchemeGopher = "gopher";
+ public static readonly string UriSchemeHttp = "http";
+ public static readonly string UriSchemeHttps = "https";
+ public static readonly string UriSchemeMailto = "mailto";
+ public static readonly string UriSchemeNews = "news";
+ public static readonly string UriSchemeNntp = "nntp";
+#if NET_2_0
+ public static readonly string UriSchemeNetPipe = "net.pipe";
+ public static readonly string UriSchemeNetTcp = "net.tcp";
+#endif
+
+ // Constructors
+
+#if NET_2_1
+ public Uri (string uriString) : this (uriString, UriKind.Absolute)
+ {
+ }
+#else
+ public Uri (string uriString) : this (uriString, false)
+ {
+ }
+#endif
+ protected Uri (SerializationInfo serializationInfo,
+ StreamingContext streamingContext) :
+ this (serializationInfo.GetString ("AbsoluteUri"), true)
+ {
+ }
+
+#if NET_2_0
+ public Uri (string uriString, UriKind uriKind)
+ {
+ source = uriString;
+ ParseUri (uriKind);
+
+ switch (uriKind) {
+ case UriKind.Absolute:
+ if (!IsAbsoluteUri)
+ throw new UriFormatException("Invalid URI: The format of the URI could not be "
+ + "determined.");
+ break;
+ case UriKind.Relative:
+ if (IsAbsoluteUri)
+ throw new UriFormatException("Invalid URI: The format of the URI could not be "
+ + "determined because the parameter 'uriString' represents an absolute URI.");
+ break;
+ case UriKind.RelativeOrAbsolute:
+ break;
+ default:
+ string msg = Locale.GetText ("Invalid UriKind value '{0}'.", uriKind);
+ throw new ArgumentException (msg);
+ }
+ }
+
+ //
+ // An exception-less constructor, returns success
+ // condition on the out parameter `success'.
+ //
+ Uri (string uriString, UriKind uriKind, out bool success)
+ {
+ if (uriString == null) {
+ success = false;
+ return;
+ }
+
+ if (uriKind != UriKind.RelativeOrAbsolute &&
+ uriKind != UriKind.Absolute &&
+ uriKind != UriKind.Relative) {
+ string msg = Locale.GetText ("Invalid UriKind value '{0}'.", uriKind);
+ throw new ArgumentException (msg);
+ }
+
+ source = uriString;
+ if (ParseNoExceptions (uriKind, uriString) != null)
+ success = false;
+ else {
+ success = true;
+
+ switch (uriKind) {
+ case UriKind.Absolute:
+ if (!IsAbsoluteUri)
+ success = false;
+ break;
+ case UriKind.Relative:
+ if (IsAbsoluteUri)
+ success = false;
+ break;
+ case UriKind.RelativeOrAbsolute:
+ break;
+ default:
+ success = false;
+ break;
+ }
+ }
+ }
+
+ public Uri (Uri baseUri, Uri relativeUri)
+ {
+ Merge (baseUri, relativeUri == null ? String.Empty : relativeUri.OriginalString);
+ // FIXME: this should call UriParser.Resolve
+ }
+
+ // note: doc says that dontEscape is always false but tests show otherwise
+ [Obsolete]
+ public Uri (string uriString, bool dontEscape)
+ {
+ userEscaped = dontEscape;
+ source = uriString;
+ ParseUri (UriKind.Absolute);
+ if (!isAbsoluteUri)
+ throw new UriFormatException("Invalid URI: The format of the URI could not be "
+ + "determined: " + uriString);
+ }
+#else
+ public Uri (string uriString, bool dontEscape)
+ {
+ userEscaped = dontEscape;
+ source = uriString;
+ Parse ();
+ if (!isAbsoluteUri)
+ throw new UriFormatException("Invalid URI: The format of the URI could not be "
+ + "determined.");
+ }
+#endif
+
+ public Uri (Uri baseUri, string relativeUri)
+ {
+ Merge (baseUri, relativeUri);
+ // FIXME: this should call UriParser.Resolve
+ }
+
+#if NET_2_0
+ [Obsolete ("dontEscape is always false")]
+#endif
+ public Uri (Uri baseUri, string relativeUri, bool dontEscape)
+ {
+ userEscaped = dontEscape;
+ Merge (baseUri, relativeUri);
+ }
+
+ private void Merge (Uri baseUri, string relativeUri)
+ {
+#if NET_2_0
+ if (baseUri == null)
+ throw new ArgumentNullException ("baseUri");
+ if (!baseUri.IsAbsoluteUri)
+ throw new ArgumentOutOfRangeException ("baseUri");
+ if (relativeUri == null)
+ relativeUri = String.Empty;
+#else
+ if (baseUri == null)
+ throw new NullReferenceException ("baseUri");
+#endif
+ // See RFC 2396 Par 5.2 and Appendix C
+
+ // Check Windows UNC (for // it is scheme/host separator)
+ if (relativeUri.Length >= 2 && relativeUri [0] == '\\' && relativeUri [1] == '\\') {
+ source = relativeUri;
+#if NET_2_0
+ ParseUri (UriKind.Absolute);
+#else
+ Parse ();
+#endif
+ return;
+ }
+
+ int pos = relativeUri.IndexOf (':');
+ if (pos != -1) {
+
+ int pos2 = relativeUri.IndexOfAny (new char [] {'/', '\\', '?'});
+
+ // pos2 < 0 ... e.g. mailto
+ // pos2 > pos ... to block ':' in query part
+ if (pos2 > pos || pos2 < 0) {
+ // in some cases, it is equivanent to new Uri (relativeUri, dontEscape):
+ // 1) when the URI scheme in the
+ // relative path is different from that
+ // of the baseUri, or
+ // 2) the URI scheme is non-standard
+ // ones (non-standard URIs are always
+ // treated as absolute here), or
+ // 3) the relative URI path is absolute.
+ if (String.CompareOrdinal (baseUri.Scheme, 0, relativeUri, 0, pos) != 0 ||
+ !IsPredefinedScheme (baseUri.Scheme) ||
+ relativeUri.Length > pos + 1 &&
+ relativeUri [pos + 1] == '/') {
+ source = relativeUri;
+#if NET_2_0
+ ParseUri (UriKind.Absolute);
+#else
+ Parse ();
+#endif
+ return;
+ }
+ else
+ relativeUri = relativeUri.Substring (pos + 1);
+ }
+ }
+
+ this.scheme = baseUri.scheme;
+ this.host = baseUri.host;
+ this.port = baseUri.port;
+ this.userinfo = baseUri.userinfo;
+ this.isUnc = baseUri.isUnc;
+ this.isUnixFilePath = baseUri.isUnixFilePath;
+ this.isOpaquePart = baseUri.isOpaquePart;
+
+ if (relativeUri == String.Empty) {
+ this.path = baseUri.path;
+ this.query = baseUri.query;
+ this.fragment = baseUri.fragment;
+ return;
+ }
+
+ // 8 fragment
+ // Note that in relative constructor, file URI cannot handle '#' as a filename character, but just regarded as a fragment identifier.
+ pos = relativeUri.IndexOf ('#');
+ if (pos != -1) {
+ if (userEscaped)
+ fragment = relativeUri.Substring (pos);
+ else
+ fragment = "#" + EscapeString (relativeUri.Substring (pos+1));
+ relativeUri = relativeUri.Substring (0, pos);
+ }
+
+ // 6 query
+ pos = relativeUri.IndexOf ('?');
+ if (pos != -1) {
+ query = relativeUri.Substring (pos);
+ if (!userEscaped)
+ query = EscapeString (query);
+ relativeUri = relativeUri.Substring (0, pos);
+ }
+
+ if (relativeUri.Length > 0 && relativeUri [0] == '/') {
+ if (relativeUri.Length > 1 && relativeUri [1] == '/') {
+ source = scheme + ':' + relativeUri;
+#if NET_2_0
+ ParseUri (UriKind.Absolute);
+#else
+ Parse ();
+#endif
+ return;
+ } else {
+ path = relativeUri;
+ if (!userEscaped)
+ path = EscapeString (path);
+ return;
+ }
+ }
+
+ // par 5.2 step 6 a)
+ path = baseUri.path;
+ if (relativeUri.Length > 0 || query.Length > 0) {
+ pos = path.LastIndexOf ('/');
+ if (pos >= 0)
+ path = path.Substring (0, pos + 1);
+ }
+
+ if(relativeUri.Length == 0)
+ return;
+
+ // 6 b)
+ path += relativeUri;
+
+ // 6 c)
+ int startIndex = 0;
+ while (true) {
+ pos = path.IndexOf ("./", startIndex);
+ if (pos == -1)
+ break;
+ if (pos == 0)
+ path = path.Remove (0, 2);
+ else if (path [pos - 1] != '.')
+ path = path.Remove (pos, 2);
+ else
+ startIndex = pos + 1;
+ }
+
+ // 6 d)
+ if (path.Length > 1 &&
+ path [path.Length - 1] == '.' &&
+ path [path.Length - 2] == '/')
+ path = path.Remove (path.Length - 1, 1);
+
+ // 6 e)
+ startIndex = 0;
+ while (true) {
+ pos = path.IndexOf ("/../", startIndex);
+ if (pos == -1)
+ break;
+ if (pos == 0) {
+ startIndex = 3;
+ continue;
+ }
+ int pos2 = path.LastIndexOf ('/', pos - 1);
+ if (pos2 == -1) {
+ startIndex = pos + 1;
+ } else {
+ if (path.Substring (pos2 + 1, pos - pos2 - 1) != "..")
+ path = path.Remove (pos2 + 1, pos - pos2 + 3);
+ else
+ startIndex = pos + 1;
+ }
+ }
+
+ // 6 f)
+ if (path.Length > 3 && path.EndsWith ("/..")) {
+ pos = path.LastIndexOf ('/', path.Length - 4);
+ if (pos != -1)
+ if (path.Substring (pos + 1, path.Length - pos - 4) != "..")
+ path = path.Remove (pos + 1, path.Length - pos - 1);
+ }
+
+ if (!userEscaped)
+ path = EscapeString (path);
+ }
+
+ // Properties
+
+ public string AbsolutePath {
+ get {
+#if NET_2_0
+ EnsureAbsoluteUri ();
+ switch (Scheme) {
+ case "mailto":
+ case "file":
+ // faster (mailto) and special (file) cases
+ return path;
+ default:
+ if (path.Length == 0) {
+ string start = Scheme + SchemeDelimiter;
+ if (path.StartsWith (start))
+ return "/";
+ else
+ return String.Empty;
+ }
+ return path;
+ }
+#else
+ return path;
+#endif
+ }
+ }
+
+ public string AbsoluteUri {
+ get {
+ EnsureAbsoluteUri ();
+ if (cachedAbsoluteUri == null) {
+ cachedAbsoluteUri = GetLeftPart (UriPartial.Path);
+ if (query.Length > 0)
+ cachedAbsoluteUri += query;
+ if (fragment.Length > 0)
+ cachedAbsoluteUri += fragment;
+ }
+ return cachedAbsoluteUri;
+ }
+ }
+
+ public string Authority {
+ get {
+ EnsureAbsoluteUri ();
+ return (GetDefaultPort (Scheme) == port)
+ ? host : host + ":" + port;
+ }
+ }
+
+ public string Fragment {
+ get {
+ EnsureAbsoluteUri ();
+ return fragment;
+ }
+ }
+
+ public string Host {
+ get {
+ EnsureAbsoluteUri ();
+ return host;
+ }
+ }
+#if !NET_2_1
+ public UriHostNameType HostNameType {
+ get {
+ EnsureAbsoluteUri ();
+ UriHostNameType ret = CheckHostName (Host);
+ if (ret != UriHostNameType.Unknown)
+ return ret;
+#if NET_2_0
+ switch (Scheme) {
+ case "mailto":
+ return UriHostNameType.Basic;
+ default:
+ return (IsFile) ? UriHostNameType.Basic : ret;
+ }
+#else
+ // looks it always returns Basic...
+ return UriHostNameType.Basic; //.Unknown;
+#endif
+ }
+ }
+
+#endif // NET_2_1
+
+ public bool IsDefaultPort {
+ get {
+ EnsureAbsoluteUri ();
+ return GetDefaultPort (Scheme) == port;
+ }
+ }
+
+ public bool IsFile {
+ get {
+ EnsureAbsoluteUri ();
+ return (Scheme == UriSchemeFile);
+ }
+ }
+
+#if !NET_2_1
+ public bool IsLoopback {
+ get {
+ EnsureAbsoluteUri ();
+
+ if (Host.Length == 0) {
+#if NET_2_0
+ return IsFile;
+#else
+ return false;
+#endif
+ }
+
+ if (host == "loopback" || host == "localhost")
+ return true;
+
+ IPAddress result;
+ if (IPAddress.TryParse (host, out result))
+ if (IPAddress.Loopback.Equals (result))
+ return true;
+
+ IPv6Address result6;
+ if (IPv6Address.TryParse (host, out result6)){
+ if (IPv6Address.IsLoopback (result6))
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+#endif // NET_2_1
+
+ public bool IsUnc {
+ // rule: This should be true only if
+ // - uri string starts from "\\", or
+ // - uri string starts from "//" (Samba way)
+ get {
+ EnsureAbsoluteUri ();
+ return isUnc;
+ }
+ }
+
+ public string LocalPath {
+ get {
+ EnsureAbsoluteUri ();
+ if (cachedLocalPath != null)
+ return cachedLocalPath;
+ if (!IsFile)
+ return AbsolutePath;
+
+ bool windows = (path.Length > 3 && path [1] == ':' &&
+ (path [2] == '\\' || path [2] == '/'));
+
+ if (!IsUnc) {
+ string p = Unescape (path);
+ bool replace = windows;
+#if ONLY_1_1
+ replace |= (System.IO.Path.DirectorySeparatorChar == '\\');
+#endif
+ if (replace)
+ cachedLocalPath = p.Replace ('/', '\\');
+ else
+ cachedLocalPath = p;
+ } else {
+ // support *nix and W32 styles
+ if (path.Length > 1 && path [1] == ':')
+ cachedLocalPath = Unescape (path.Replace (Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar));
+
+ // LAMESPEC: ok, now we cannot determine
+ // if such URI like "file://foo/bar" is
+ // Windows UNC or unix file path, so
+ // they should be handled differently.
+ else if (global::System.IO.Path.DirectorySeparatorChar == '\\') {
+ string h = host;
+ if (path.Length > 0) {
+#if NET_2_0
+ if ((path.Length > 1) || (path[0] != '/')) {
+ h += path.Replace ('/', '\\');
+ }
+#else
+ h += path.Replace ('/', '\\');
+#endif
+ }
+ cachedLocalPath = "\\\\" + Unescape (h);
+ } else
+ cachedLocalPath = Unescape (path);
+ }
+ if (cachedLocalPath.Length == 0)
+ cachedLocalPath = Path.DirectorySeparatorChar.ToString ();
+ return cachedLocalPath;
+ }
+ }
+
+ public string PathAndQuery {
+ get {
+ EnsureAbsoluteUri ();
+ return path + Query;
+ }
+ }
+
+ public int Port {
+ get {
+ EnsureAbsoluteUri ();
+ return port;
+ }
+ }
+
+ public string Query {
+ get {
+ EnsureAbsoluteUri ();
+ return query;
+ }
+ }
+
+ public string Scheme {
+ get {
+ EnsureAbsoluteUri ();
+ return scheme;
+ }
+ }
+
+ public string [] Segments {
+ get {
+ EnsureAbsoluteUri ();
+ if (segments != null)
+ return segments;
+
+ if (path.Length == 0) {
+ segments = new string [0];
+ return segments;
+ }
+
+ string [] parts = path.Split ('/');
+ segments = parts;
+ bool endSlash = path.EndsWith ("/");
+ if (parts.Length > 0 && endSlash) {
+ string [] newParts = new string [parts.Length - 1];
+ Array.Copy (parts, 0, newParts, 0, parts.Length - 1);
+ parts = newParts;
+ }
+
+ int i = 0;
+ if (IsFile && path.Length > 1 && path [1] == ':') {
+ string [] newParts = new string [parts.Length + 1];
+ Array.Copy (parts, 1, newParts, 2, parts.Length - 1);
+ parts = newParts;
+ parts [0] = path.Substring (0, 2);
+ parts [1] = String.Empty;
+ i++;
+ }
+
+ int end = parts.Length;
+ for (; i < end; i++)
+ if (i != end - 1 || endSlash)
+ parts [i] += '/';
+
+ segments = parts;
+ return segments;
+ }
+ }
+
+ public bool UserEscaped {
+ get { return userEscaped; }
+ }
+
+ public string UserInfo {
+ get {
+ EnsureAbsoluteUri ();
+ return userinfo;
+ }
+ }
+
+//#if NET_2_0
+ [MonoTODO ("add support for IPv6 address")]
+ public string DnsSafeHost {
+ get {
+ EnsureAbsoluteUri ();
+ return Unescape (Host);
+ }
+ }
+
+ public bool IsAbsoluteUri {
+ get { return isAbsoluteUri; }
+ }
+//#endif
+ // LAMESPEC: source field is supplied in such case that this
+ // property makes sense. For such case that source field is
+ // not supplied (i.e. .ctor(Uri, string), this property
+ // makes no sense. To avoid silly regression it just returns
+ // ToString() value now. See bug #78374.
+#if NET_2_0
+ public
+#else
+ internal
+#endif
+ string OriginalString {
+ get { return source != null ? source : ToString (); }
+ }
+
+ // Methods
+
+ public static UriHostNameType CheckHostName (string name)
+ {
+ if (name == null || name.Length == 0)
+ return UriHostNameType.Unknown;
+
+ if (IsIPv4Address (name))
+ return UriHostNameType.IPv4;
+
+ if (IsDomainAddress (name))
+ return UriHostNameType.Dns;
+
+ IPv6Address addr;
+ if (IPv6Address.TryParse (name, out addr))
+ return UriHostNameType.IPv6;
+
+ return UriHostNameType.Unknown;
+ }
+
+ internal static bool IsIPv4Address (string name)
+ {
+ string [] captures = name.Split (new char [] {'.'});
+ if (captures.Length != 4)
+ return false;
+
+ for (int i = 0; i < 4; i++) {
+ int length;
+
+ length = captures [i].Length;
+ if (length == 0)
+ return false;
+ uint number;
+#if NET_2_0
+ if (!UInt32.TryParse (captures [i], out number))
+ return false;
+#else
+ try {
+ number = UInt32.Parse (captures [i]);
+ } catch (Exception) {
+ return false;
+ }
+#endif
+ if (number > 255)
+ return false;
+ }
+ return true;
+ }
+
+ internal static bool IsDomainAddress (string name)
+ {
+ int len = name.Length;
+
+ int count = 0;
+ for (int i = 0; i < len; i++) {
+ char c = name [i];
+ if (count == 0) {
+ if (!Char.IsLetterOrDigit (c))
+ return false;
+ } else if (c == '.') {
+ count = 0;
+ } else if (!Char.IsLetterOrDigit (c) && c != '-' && c != '_') {
+ return false;
+ }
+ if (++count == 64)
+ return false;
+ }
+
+ return true;
+ }
+#if !NET_2_1
+
+#if NET_2_0
+ [Obsolete("This method does nothing, it has been obsoleted")]
+#endif
+ protected virtual void Canonicalize ()
+ {
+ //
+ // This is flagged in the Microsoft documentation as used
+ // internally, no longer in use, and Obsolete.
+ //
+ }
+
+ [MonoTODO ("Find out what this should do")]
+#if NET_2_0
+ [Obsolete]
+#endif
+ protected virtual void CheckSecurity ()
+ {
+ }
+
+#endif // NET_2_1
+
+ // defined in RFC3986 as = ALPHA *( ALPHA / DIGIT / "+" / "-" / ".")
+ public static bool CheckSchemeName (string schemeName)
+ {
+ if (schemeName == null || schemeName.Length == 0)
+ return false;
+
+ if (!IsAlpha (schemeName [0]))
+ return false;
+
+ int len = schemeName.Length;
+ for (int i = 1; i < len; i++) {
+ char c = schemeName [i];
+ if (!Char.IsDigit (c) && !IsAlpha (c) && c != '.' && c != '+' && c != '-')
+ return false;
+ }
+
+ return true;
+ }
+
+ private static bool IsAlpha (char c)
+ {
+#if NET_2_0
+ // as defined in rfc2234
+ // %x41-5A / %x61-7A (A-Z / a-z)
+ int i = (int) c;
+ return (((i >= 0x41) && (i <= 0x5A)) || ((i >= 0x61) && (i <= 0x7A)));
+#else
+ // Fx 1.x got this too large
+ return Char.IsLetter (c);
+#endif
+ }
+
+ public override bool Equals (object comparant)
+ {
+ if (comparant == null)
+ return false;
+
+ Uri uri = comparant as Uri;
+ if ((object) uri == null) {
+ string s = comparant as String;
+ if (s == null)
+ return false;
+ uri = new Uri (s);
+ }
+
+ return InternalEquals (uri);
+ }
+
+ // Assumes: uri != null
+ bool InternalEquals (Uri uri)
+ {
+#if NET_2_0
+ if (this.isAbsoluteUri != uri.isAbsoluteUri)
+ return false;
+ if (!this.isAbsoluteUri)
+ return this.source == uri.source;
+#endif
+
+ CultureInfo inv = CultureInfo.InvariantCulture;
+ return this.scheme.ToLower (inv) == uri.scheme.ToLower (inv)
+ && this.host.ToLower (inv) == uri.host.ToLower (inv)
+ && this.port == uri.port
+#if NET_2_0
+ && this.query == uri.query
+#else
+ // Note: MS.NET 1.x has bug - ignores query check altogether
+ && this.query.ToLower (inv) == uri.query.ToLower (inv)
+#endif
+ && this.path == uri.path;
+ }
+
+#if NET_2_0
+ public static bool operator == (Uri u1, Uri u2)
+ {
+ return object.Equals(u1, u2);
+ }
+
+ public static bool operator != (Uri u1, Uri u2)
+ {
+ return !(u1 == u2);
+ }
+#endif
+
+ public override int GetHashCode ()
+ {
+ if (cachedHashCode == 0) {
+ CultureInfo inv = CultureInfo.InvariantCulture;
+ if (isAbsoluteUri) {
+ cachedHashCode = scheme.ToLower (inv).GetHashCode ()
+ ^ host.ToLower (inv).GetHashCode ()
+ ^ port
+#if NET_2_0
+ ^ query.GetHashCode ()
+#else
+ ^ query.ToLower (inv).GetHashCode ()
+#endif
+ ^ path.GetHashCode ();
+ }
+ else {
+ cachedHashCode = source.GetHashCode ();
+ }
+ }
+ return cachedHashCode;
+ }
+
+ public string GetLeftPart (UriPartial part)
+ {
+ EnsureAbsoluteUri ();
+ int defaultPort;
+ switch (part) {
+ case UriPartial.Scheme :
+ return scheme + GetOpaqueWiseSchemeDelimiter ();
+ case UriPartial.Authority :
+ if ((scheme == Uri.UriSchemeMailto) || (scheme == Uri.UriSchemeNews))
+ return String.Empty;
+
+ StringBuilder s = new StringBuilder ();
+ s.Append (scheme);
+ s.Append (GetOpaqueWiseSchemeDelimiter ());
+ if (path.Length > 1 && path [1] == ':' && (Uri.UriSchemeFile == scheme))
+ s.Append ('/'); // win32 file
+ if (userinfo.Length > 0)
+ s.Append (userinfo).Append ('@');
+ s.Append (host);
+ defaultPort = GetDefaultPort (scheme);
+ if ((port != -1) && (port != defaultPort))
+ s.Append (':').Append (port);
+ return s.ToString ();
+ case UriPartial.Path :
+ StringBuilder sb = new StringBuilder ();
+ sb.Append (scheme);
+ sb.Append (GetOpaqueWiseSchemeDelimiter ());
+ if (path.Length > 1 && path [1] == ':' && (Uri.UriSchemeFile == scheme))
+ sb.Append ('/'); // win32 file
+ if (userinfo.Length > 0)
+ sb.Append (userinfo).Append ('@');
+ sb.Append (host);
+ defaultPort = GetDefaultPort (scheme);
+ if ((port != -1) && (port != defaultPort))
+ sb.Append (':').Append (port);
+
+ if (path.Length > 0) {
+#if NET_2_0
+ switch (Scheme) {
+ case "mailto":
+ case "news":
+ sb.Append (path);
+ break;
+ default:
+ sb.Append (Reduce (path));
+ break;
+ }
+#else
+ sb.Append (path);
+#endif
+ }
+ return sb.ToString ();
+ }
+ return null;
+ }
+
+ public static int FromHex (char digit)
+ {
+ if ('0' <= digit && digit <= '9') {
+ return (int) (digit - '0');
+ }
+
+ if ('a' <= digit && digit <= 'f')
+ return (int) (digit - 'a' + 10);
+
+ if ('A' <= digit && digit <= 'F')
+ return (int) (digit - 'A' + 10);
+
+ throw new ArgumentException ("digit");
+ }
+
+ public static string HexEscape (char character)
+ {
+ if (character > 255) {
+ throw new ArgumentOutOfRangeException ("character");
+ }
+
+ return "%" + hexUpperChars [((character & 0xf0) >> 4)]
+ + hexUpperChars [((character & 0x0f))];
+ }
+
+ public static char HexUnescape (string pattern, ref int index)
+ {
+ if (pattern == null)
+ throw new ArgumentException ("pattern");
+
+ if (index < 0 || index >= pattern.Length)
+ throw new ArgumentOutOfRangeException ("index");
+
+ if (!IsHexEncoding (pattern, index))
+ return pattern [index++];
+
+ index++;
+ int msb = FromHex (pattern [index++]);
+ int lsb = FromHex (pattern [index++]);
+ return (char) ((msb << 4) | lsb);
+ }
+
+ public static bool IsHexDigit (char digit)
+ {
+ return (('0' <= digit && digit <= '9') ||
+ ('a' <= digit && digit <= 'f') ||
+ ('A' <= digit && digit <= 'F'));
+ }
+
+ public static bool IsHexEncoding (string pattern, int index)
+ {
+ if ((index + 3) > pattern.Length)
+ return false;
+
+ return ((pattern [index++] == '%') &&
+ IsHexDigit (pattern [index++]) &&
+ IsHexDigit (pattern [index]));
+ }
+
+#if NET_2_0
+ //
+ // Implemented by copying most of the MakeRelative code
+ //
+ public Uri MakeRelativeUri (Uri uri)
+ {
+ if (uri == null)
+ throw new ArgumentNullException ("uri");
+
+ if (Host != uri.Host || Scheme != uri.Scheme)
+ return uri;
+
+ string result = String.Empty;
+ if (this.path != uri.path){
+ string [] segments = this.Segments;
+ string [] segments2 = uri.Segments;
+
+ int k = 0;
+ int max = Math.Min (segments.Length, segments2.Length);
+ for (; k < max; k++)
+ if (segments [k] != segments2 [k])
+ break;
+
+ for (int i = k + 1; i < segments.Length; i++)
+ result += "../";
+ for (int i = k; i < segments2.Length; i++)
+ result += segments2 [i];
+
+ }
+ uri.AppendQueryAndFragment (ref result);
+
+ return new Uri (result, UriKind.Relative);
+ }
+
+ [Obsolete ("Use MakeRelativeUri(Uri uri) instead.")]
+#endif
+ public string MakeRelative (Uri toUri)
+ {
+ if ((this.Scheme != toUri.Scheme) ||
+ (this.Authority != toUri.Authority))
+ return toUri.ToString ();
+
+ string result = String.Empty;
+ if (this.path != toUri.path){
+ string [] segments = this.Segments;
+ string [] segments2 = toUri.Segments;
+ int k = 0;
+ int max = Math.Min (segments.Length, segments2.Length);
+ for (; k < max; k++)
+ if (segments [k] != segments2 [k])
+ break;
+
+ for (int i = k + 1; i < segments.Length; i++)
+ result += "../";
+ for (int i = k; i < segments2.Length; i++)
+ result += segments2 [i];
+ }
+
+ // Important: MakeRelative does not append fragment or query.
+
+ return result;
+ }
+
+ void AppendQueryAndFragment (ref string result)
+ {
+ if (query.Length > 0) {
+ string q = query [0] == '?' ? '?' + Unescape (query.Substring (1), false) : Unescape (query, false);
+ result += q;
+ }
+ if (fragment.Length > 0)
+ result += fragment;
+ }
+
+ public override string ToString ()
+ {
+ if (cachedToString != null)
+ return cachedToString;
+
+ if (isAbsoluteUri)
+ cachedToString = Unescape (GetLeftPart (UriPartial.Path), true);
+ else {
+ // Everything is contained in path in this case.
+ cachedToString = Unescape (path);
+ }
+
+ AppendQueryAndFragment (ref cachedToString);
+ return cachedToString;
+ }
+
+#if NET_2_0
+ protected void GetObjectData (SerializationInfo info, StreamingContext context)
+ {
+ info.AddValue ("AbsoluteUri", this.AbsoluteUri);
+ }
+#endif
+
+ void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context)
+ {
+ info.AddValue ("AbsoluteUri", this.AbsoluteUri);
+ }
+
+
+ // Internal Methods
+
+#if NET_2_0
+ [Obsolete]
+#endif
+ protected virtual void Escape ()
+ {
+ path = EscapeString (path);
+ }
+
+#if NET_2_0
+ [Obsolete]
+#endif
+ protected static string EscapeString (string str)
+ {
+ return EscapeString (str, false, true, true);
+ }
+
+ internal static string EscapeString (string str, bool escapeReserved, bool escapeHex, bool escapeBrackets)
+ {
+ if (str == null)
+ return String.Empty;
+
+ StringBuilder s = new StringBuilder ();
+ int len = str.Length;
+ for (int i = 0; i < len; i++) {
+ // reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","
+ // mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
+ // control = <US-ASCII coded characters 00-1F and 7F hexadecimal>
+ // space = <US-ASCII coded character 20 hexadecimal>
+ // delims = "<" | ">" | "#" | "%" | <">
+ // unwise = "{" | "}" | "|" | "\" | "^" | "[" | "]" | "`"
+
+ // check for escape code already placed in str,
+ // i.e. for encoding that follows the pattern
+ // "%hexhex" in a string, where "hex" is a digit from 0-9
+ // or a letter from A-F (case-insensitive).
+ if (IsHexEncoding (str,i)) {
+ // if ,yes , copy it as is
+ s.Append(str.Substring (i, 3));
+ i += 2;
+ continue;
+ }
+
+ byte [] data = Encoding.UTF8.GetBytes (new char[] {str[i]});
+ int length = data.Length;
+ for (int j = 0; j < length; j++) {
+ char c = (char) data [j];
+ if ((c <= 0x20) || (c >= 0x7f) ||
+ ("<>%\"{}|\\^`".IndexOf (c) != -1) ||
+ (escapeHex && (c == '#')) ||
+ (escapeBrackets && (c == '[' || c == ']')) ||
+ (escapeReserved && (";/?:@&=+$,".IndexOf (c) != -1))) {
+ s.Append (HexEscape (c));
+ continue;
+ }
+ s.Append (c);
+ }
+ }
+
+ return s.ToString ();
+ }
+
+ // On .NET 1.x, this method is called from .ctor(). When overriden, we
+ // can avoid the "absolute uri" constraints of the .ctor() by
+ // overriding with custom code.
+#if NET_2_0
+ [Obsolete("The method has been deprecated. It is not used by the system.")]
+#endif
+ protected virtual void Parse ()
+ {
+#if !NET_2_0
+ ParseUri (UriKind.Absolute);
+#endif
+ }
+
+ private void ParseUri (UriKind kind)
+ {
+ Parse (kind, source);
+
+ if (userEscaped)
+ return;
+
+ host = EscapeString (host, false, true, false);
+ if (host.Length > 1 && host [0] != '[' && host [host.Length - 1] != ']') {
+ // host name present (but not an IPv6 address)
+ host = host.ToLower (CultureInfo.InvariantCulture);
+ }
+
+ if (path.Length > 0) {
+ path = EscapeString (path);
+ }
+ }
+
+#if NET_2_0
+ [Obsolete]
+#endif
+ protected virtual string Unescape (string str)
+ {
+ return Unescape (str, false);
+ }
+
+ internal static string Unescape (string str, bool excludeSpecial)
+ {
+ if (str == null)
+ return String.Empty;
+ StringBuilder s = new StringBuilder ();
+ int len = str.Length;
+ for (int i = 0; i < len; i++) {
+ char c = str [i];
+ if (c == '%') {
+ char surrogate;
+ char x = HexUnescapeMultiByte (str, ref i, out surrogate);
+ if (excludeSpecial && x == '#')
+ s.Append ("%23");
+ else if (excludeSpecial && x == '%')
+ s.Append ("%25");
+ else if (excludeSpecial && x == '?')
+ s.Append ("%3F");
+ else {
+ s.Append (x);
+ if (surrogate != char.MinValue)
+ s.Append (surrogate);
+ }
+ i--;
+ } else
+ s.Append (c);
+ }
+ return s.ToString ();
+ }
+
+
+ // Private Methods
+
+ private void ParseAsWindowsUNC (string uriString)
+ {
+ scheme = UriSchemeFile;
+ port = -1;
+ fragment = String.Empty;
+ query = String.Empty;
+ isUnc = true;
+
+ uriString = uriString.TrimStart (new char [] {'\\'});
+ int pos = uriString.IndexOf ('\\');
+ if (pos > 0) {
+ path = uriString.Substring (pos);
+ host = uriString.Substring (0, pos);
+ } else { // "\\\\server"
+ host = uriString;
+ path = String.Empty;
+ }
+ path = path.Replace ("\\", "/");
+ }
+
+ //
+ // Returns null on success, string with error on failure
+ //
+ private string ParseAsWindowsAbsoluteFilePath (string uriString)
+ {
+ if (uriString.Length > 2 && uriString [2] != '\\' && uriString [2] != '/')
+ return "Relative file path is not allowed.";
+ scheme = UriSchemeFile;
+ host = String.Empty;
+ port = -1;
+ path = uriString.Replace ("\\", "/");
+ fragment = String.Empty;
+ query = String.Empty;
+
+ return null;
+ }
+
+ private void ParseAsUnixAbsoluteFilePath (string uriString)
+ {
+ isUnixFilePath = true;
+ scheme = UriSchemeFile;
+ port = -1;
+ fragment = String.Empty;
+ query = String.Empty;
+ host = String.Empty;
+ path = null;
+
+ if (uriString.Length >= 2 && uriString [0] == '/' && uriString [1] == '/') {
+ uriString = uriString.TrimStart (new char [] {'/'});
+ // Now we don't regard //foo/bar as "foo" host.
+ /*
+ int pos = uriString.IndexOf ('/');
+ if (pos > 0) {
+ path = '/' + uriString.Substring (pos + 1);
+ host = uriString.Substring (0, pos);
+ } else { // "///server"
+ host = uriString;
+ path = String.Empty;
+ }
+ */
+ path = '/' + uriString;
+ }
+ if (path == null)
+ path = uriString;
+ }
+
+ //
+ // This parse method will throw exceptions on failure
+ //
+ private void Parse (UriKind kind, string uriString)
+ {
+ if (uriString == null)
+ throw new ArgumentNullException ("uriString");
+
+ string s = ParseNoExceptions (kind, uriString);
+ if (s != null)
+ throw new UriFormatException (s);
+ }
+
+ //
+ // This parse method will not throw exceptions on failure
+ //
+ // Returns null on success, or a description of the error in the parsing
+ //
+ private string ParseNoExceptions (UriKind kind, string uriString)
+ {
+ //
+ // From RFC 2396 :
+ //
+ // ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
+ // 12 3 4 5 6 7 8 9
+ //
+
+ uriString = uriString.Trim();
+ int len = uriString.Length;
+
+ if (len == 0){
+ if (kind == UriKind.Relative || kind == UriKind.RelativeOrAbsolute){
+ isAbsoluteUri = false;
+ return null;
+ }
+ }
+
+ if (len <= 1 && (kind != UriKind.Relative))
+ return "Absolute URI is too short";
+
+ int pos = 0;
+
+ // 1, 2
+ // Identify Windows path, unix path, or standard URI.
+ pos = uriString.IndexOf (':');
+ if (pos == 0) {
+ return "Invalid URI: The format of the URI could not be determined.";
+ } else if (pos < 0) {
+ // It must be Unix file path or Windows UNC
+ if (uriString [0] == '/' && Path.DirectorySeparatorChar == '/'){
+ ParseAsUnixAbsoluteFilePath (uriString);
+#if NET_2_1
+ isAbsoluteUri = false;
+#else
+ if (kind == UriKind.Relative)
+ isAbsoluteUri = false;
+#endif
+
+ } else if (uriString.Length >= 2 && uriString [0] == '\\' && uriString [1] == '\\')
+ ParseAsWindowsUNC (uriString);
+ else {
+ /* Relative path */
+ isAbsoluteUri = false;
+ path = uriString;
+ }
+ return null;
+ } else if (pos == 1) {
+ if (!IsAlpha (uriString [0]))
+ return "URI scheme must start with a letter.";
+ // This means 'a:' == windows full path.
+ string msg = ParseAsWindowsAbsoluteFilePath (uriString);
+ if (msg != null)
+ return msg;
+ return null;
+ }
+
+ // scheme
+ scheme = uriString.Substring (0, pos).ToLower (CultureInfo.InvariantCulture);
+
+ // Check scheme name characters as specified in RFC2396.
+ // Note: different checks in 1.x and 2.0
+ if (!CheckSchemeName (scheme))
+ return Locale.GetText ("URI scheme must start with a letter and must consist of one of alphabet, digits, '+', '-' or '.' character.");
+
+ // from here we're practically working on uriString.Substring(startpos,endpos-startpos)
+ int startpos = pos + 1;
+ int endpos = uriString.Length;
+
+ // 8 fragment
+ pos = uriString.IndexOf ('#', startpos);
+ if (!IsUnc && pos != -1) {
+ if (userEscaped)
+ fragment = uriString.Substring (pos);
+ else
+ fragment = "#" + EscapeString (uriString.Substring (pos+1));
+
+ endpos = pos;
+ }
+
+ // 6 query
+ pos = uriString.IndexOf ('?', startpos, endpos-startpos);
+ if (pos != -1) {
+ query = uriString.Substring (pos, endpos-pos);
+ endpos = pos;
+ if (!userEscaped)
+ query = EscapeString (query);
+ }
+
+ // 3
+ if (IsPredefinedScheme (scheme) && scheme != UriSchemeMailto && scheme != UriSchemeNews && (
+ (endpos-startpos < 2) ||
+ (endpos-startpos >= 2 && uriString [startpos] == '/' && uriString [startpos+1] != '/')))
+ return "Invalid URI: The Authority/Host could not be parsed.";
+
+
+ bool startsWithSlashSlash = endpos-startpos >= 2 && uriString [startpos] == '/' && uriString [startpos+1] == '/';
+ bool unixAbsPath = scheme == UriSchemeFile && startsWithSlashSlash && (endpos-startpos == 2 || uriString [startpos+2] == '/');
+ bool windowsFilePath = false;
+ if (startsWithSlashSlash) {
+ if (kind == UriKind.Relative)
+ return "Absolute URI when we expected a relative one";
+
+ if (scheme != UriSchemeMailto && scheme != UriSchemeNews)
+ startpos += 2;
+
+ if (scheme == UriSchemeFile) {
+ int num_leading_slash = 2;
+ for (int i = startpos; i < endpos; i++) {
+ if (uriString [i] != '/')
+ break;
+ num_leading_slash++;
+ }
+ if (num_leading_slash >= 4) {
+ unixAbsPath = false;
+ while (startpos < endpos && uriString[startpos] == '/') {
+ startpos++;
+ }
+ } else if (num_leading_slash >= 3) {
+ startpos += 1;
+ }
+ }
+
+ if (endpos - startpos > 1 && uriString [startpos + 1] == ':') {
+ unixAbsPath = false;
+ windowsFilePath = true;
+ }
+
+ } else if (!IsPredefinedScheme (scheme)) {
+ path = uriString.Substring(startpos, endpos-startpos);
+ isOpaquePart = true;
+ return null;
+ }
+
+ // 5 path
+ if (unixAbsPath) {
+ pos = -1;
+ } else {
+ pos = uriString.IndexOf ('/', startpos, endpos-startpos);
+ if (pos == -1 && windowsFilePath)
+ pos = uriString.IndexOf ('\\', startpos, endpos-startpos);
+ }
+
+ if (pos == -1) {
+ if ((scheme != Uri.UriSchemeMailto) &&
+#if ONLY_1_1
+ (scheme != Uri.UriSchemeFile) &&
+#endif
+ (scheme != Uri.UriSchemeNews))
+ path = "/";
+ } else {
+ path = uriString.Substring (pos, endpos-pos);
+ endpos = pos;
+ }
+
+ // 4.a user info
+ pos = uriString.IndexOf ('@', startpos, endpos-startpos);
+ if (pos != -1) {
+ userinfo = uriString.Substring (startpos, pos-startpos);
+ startpos = pos + 1;
+ }
+
+ // 4.b port
+ port = -1;
+ if (unixAbsPath)
+ pos = -1;
+ else
+ pos = uriString.LastIndexOf (':', endpos-1, endpos-startpos);
+ if (pos != -1 && pos != endpos - 1) {
+ string portStr = uriString.Substring(pos + 1, endpos - (pos + 1));
+ if (portStr.Length > 0 && portStr[portStr.Length - 1] != ']') {
+#if NET_2_0
+ if (!Int32.TryParse (portStr, NumberStyles.Integer, CultureInfo.InvariantCulture, out port) ||
+ port < 0 || port > UInt16.MaxValue)
+ return "Invalid URI: Invalid port number";
+ endpos = pos;
+#else
+ try {
+ port = (int) UInt32.Parse (portStr, CultureInfo.InvariantCulture);
+ endpos = pos;
+ } catch (Exception) {
+ return "Invalid URI: Invalid port number";
+ }
+#endif
+ } else {
+ if (port == -1) {
+ port = GetDefaultPort (scheme);
+ }
+ }
+ } else {
+ if (port == -1) {
+ port = GetDefaultPort (scheme);
+ }
+ }
+
+ // 4 authority
+ uriString = uriString.Substring(startpos, endpos-startpos);
+ host = uriString;
+
+ if (unixAbsPath) {
+ path = Reduce ('/' + uriString);
+ host = String.Empty;
+ } else if (host.Length == 2 && host [1] == ':') {
+ // windows filepath
+ path = host + path;
+ host = String.Empty;
+ } else if (isUnixFilePath) {
+ uriString = "//" + uriString;
+ host = String.Empty;
+ } else if (scheme == UriSchemeFile) {
+ isUnc = true;
+ } else if (scheme == UriSchemeNews) {
+ // no host for 'news', misinterpreted path
+ if (host.Length > 0) {
+ path = host;
+ host = String.Empty;
+ }
+ } else if (host.Length == 0 &&
+ (scheme == UriSchemeHttp || scheme == UriSchemeGopher || scheme == UriSchemeNntp ||
+ scheme == UriSchemeHttps || scheme == UriSchemeFtp)) {
+ return "Invalid URI: The hostname could not be parsed";
+ }
+
+ bool badhost = ((host.Length > 0) && (CheckHostName (host) == UriHostNameType.Unknown));
+ if (!badhost && (host.Length > 1) && (host[0] == '[') && (host[host.Length - 1] == ']')) {
+ IPv6Address ipv6addr;
+
+ if (IPv6Address.TryParse (host, out ipv6addr))
+ host = "[" + ipv6addr.ToString (true) + "]";
+ else
+ badhost = true;
+ }
+#if NET_2_0
+ if (badhost && (Parser is DefaultUriParser || Parser == null))
+ return Locale.GetText ("Invalid URI: The hostname could not be parsed. (" + host + ")");
+
+ UriFormatException ex = null;
+ if (Parser != null)
+ Parser.InitializeAndValidate (this, out ex);
+ if (ex != null)
+ return ex.Message;
+#else
+ if (badhost)
+ return Locale.GetText ("Invalid URI: The hostname could not be parsed. (" + host + ")");
+#endif
+
+ if ((scheme != Uri.UriSchemeMailto) &&
+ (scheme != Uri.UriSchemeNews) &&
+ (scheme != Uri.UriSchemeFile)) {
+ path = Reduce (path);
+ }
+
+ return null;
+ }
+
+ private static string Reduce (string path)
+ {
+ // quick out, allocation-free, for a common case
+ if (path == "/")
+ return path;
+
+ // replace '\', %5C ('\') and %2f ('/') into '/'
+ // other escaped values seems to survive this step
+ StringBuilder res = new StringBuilder();
+ for (int i=0; i < path.Length; i++) {
+ char c = path [i];
+ switch (c) {
+ case '\\':
+ res.Append ('/');
+ break;
+ case '%':
+ if (i < path.Length - 2) {
+ char c1 = path [i + 1];
+ char c2 = Char.ToUpper (path [i + 2]);
+ if (((c1 == '2') && (c2 == 'F')) || ((c1 == '5') && (c2 == 'C'))) {
+ res.Append ('/');
+ i += 2;
+ } else {
+ res.Append (c);
+ }
+ } else {
+ res.Append (c);
+ }
+ break;
+ default:
+ res.Append (c);
+ break;
+ }
+ }
+ path = res.ToString ();
+ ArrayList result = new ArrayList ();
+
+ for (int startpos = 0; startpos < path.Length; ) {
+ int endpos = path.IndexOf('/', startpos);
+ if (endpos == -1) endpos = path.Length;
+ string current = path.Substring (startpos, endpos-startpos);
+ startpos = endpos + 1;
+ if (current.Length == 0 || current == "." )
+ continue;
+
+ if (current == "..") {
+ int resultCount = result.Count;
+#if NET_2_0
+ // in 2.0 profile, skip leading ".." parts
+ if (resultCount == 0) {
+ continue;
+ }
+
+ result.RemoveAt (resultCount - 1);
+ continue;
+#else
+ // in 1.x profile, retain leading ".." parts, and only reduce
+ // URI is previous part is not ".."
+ if (resultCount > 0) {
+ if ((string) result[resultCount - 1] != "..") {
+ result.RemoveAt (resultCount - 1);
+ continue;
+ }
+ }
+#endif
+ }
+
+ result.Add (current);
+ }
+
+ if (result.Count == 0)
+ return "/";
+
+ res.Length = 0;
+ if (path [0] == '/')
+ res.Append ('/');
+
+ bool first = true;
+ foreach (string part in result) {
+ if (first) {
+ first = false;
+ } else {
+ res.Append ('/');
+ }
+ res.Append(part);
+ }
+
+ if (path.EndsWith ("/"))
+ res.Append ('/');
+
+ return res.ToString();
+ }
+
+ // A variant of HexUnescape() which can decode multi-byte escaped
+ // sequences such as (e.g.) %E3%81%8B into a single character
+ private static char HexUnescapeMultiByte (string pattern, ref int index, out char surrogate)
+ {
+ surrogate = char.MinValue;
+
+ if (pattern == null)
+ throw new ArgumentException ("pattern");
+
+ if (index < 0 || index >= pattern.Length)
+ throw new ArgumentOutOfRangeException ("index");
+
+ if (!IsHexEncoding (pattern, index))
+ return pattern [index++];
+
+ int orig_index = index++;
+ int msb = FromHex (pattern [index++]);
+ int lsb = FromHex (pattern [index++]);
+
+ // We might be dealing with a multi-byte character:
+ // The number of ones at the top-end of the first byte will tell us
+ // how many bytes will make up this character.
+ int msb_copy = msb;
+ int num_bytes = 0;
+ while ((msb_copy & 0x8) == 0x8) {
+ num_bytes++;
+ msb_copy <<= 1;
+ }
+
+ // We might be dealing with a single-byte character:
+ // If there was only 0 or 1 leading ones then we're not dealing
+ // with a multi-byte character.
+ if (num_bytes <= 1)
+ return (char) ((msb << 4) | lsb);
+
+ // Now that we know how many bytes *should* follow, we'll check them
+ // to ensure we are dealing with a valid multi-byte character.
+ byte [] chars = new byte [num_bytes];
+ bool all_invalid = false;
+ chars[0] = (byte) ((msb << 4) | lsb);
+
+ for (int i = 1; i < num_bytes; i++) {
+ if (!IsHexEncoding (pattern, index++)) {
+ all_invalid = true;
+ break;
+ }
+
+ // All following bytes must be in the form 10xxxxxx
+ int cur_msb = FromHex (pattern [index++]);
+ if ((cur_msb & 0xc) != 0x8) {
+ all_invalid = true;
+ break;
+ }
+
+ int cur_lsb = FromHex (pattern [index++]);
+ chars[i] = (byte) ((cur_msb << 4) | cur_lsb);
+ }
+
+ // If what looked like a multi-byte character is invalid, then we'll
+ // just return the first byte as a single byte character.
+ if (all_invalid) {
+ index = orig_index + 3;
+ return (char) chars[0];
+ }
+
+ // Otherwise, we're dealing with a valid multi-byte character.
+ // We need to ignore the leading ones from the first byte:
+ byte mask = (byte) 0xFF;
+ mask >>= (num_bytes + 1);
+ int result = chars[0] & mask;
+
+ // The result will now be built up from the following bytes.
+ for (int i = 1; i < num_bytes; i++) {
+ // Ignore upper two bits
+ result <<= 6;
+ result |= (chars[i] & 0x3F);
+ }
+
+ if (result <= 0xFFFF) {
+ return (char) result;
+ } else {
+ // We need to handle this as a UTF16 surrogate (i.e. return
+ // two characters)
+ result -= 0x10000;
+ surrogate = (char) ((result & 0x3FF) | 0xDC00);
+ return (char) ((result >> 10) | 0xD800);
+ }
+ }
+
+ private struct UriScheme
+ {
+ public string scheme;
+ public string delimiter;
+ public int defaultPort;
+
+ public UriScheme (string s, string d, int p)
+ {
+ scheme = s;
+ delimiter = d;
+ defaultPort = p;
+ }
+ };
+
+ static UriScheme [] schemes = new UriScheme [] {
+ new UriScheme (UriSchemeHttp, SchemeDelimiter, 80),
+ new UriScheme (UriSchemeHttps, SchemeDelimiter, 443),
+ new UriScheme (UriSchemeFtp, SchemeDelimiter, 21),
+ new UriScheme (UriSchemeFile, SchemeDelimiter, -1),
+ new UriScheme (UriSchemeMailto, ":", 25),
+ new UriScheme (UriSchemeNews, ":", 119),
+ new UriScheme (UriSchemeNntp, SchemeDelimiter, 119),
+ new UriScheme (UriSchemeGopher, SchemeDelimiter, 70),
+ };
+
+ internal static string GetSchemeDelimiter (string scheme)
+ {
+ for (int i = 0; i < schemes.Length; i++)
+ if (schemes [i].scheme == scheme)
+ return schemes [i].delimiter;
+ return Uri.SchemeDelimiter;
+ }
+
+ internal static int GetDefaultPort (string scheme)
+ {
+#if NET_2_0
+ UriParser parser = UriParser.GetParser (scheme);
+ if (parser == null)
+ return -1;
+ return parser.DefaultPort;
+#else
+ for (int i = 0; i < schemes.Length; i++)
+ if (schemes [i].scheme == scheme)
+ return schemes [i].defaultPort;
+ return -1;
+#endif
+ }
+
+ private string GetOpaqueWiseSchemeDelimiter ()
+ {
+ if (isOpaquePart)
+ return ":";
+ else
+ return GetSchemeDelimiter (scheme);
+ }
+
+#if NET_2_0
+ [Obsolete]
+#endif
+ protected virtual bool IsBadFileSystemCharacter (char ch)
+ {
+ // It does not always overlap with InvalidPathChars.
+ int chInt = (int) ch;
+ if (chInt < 32 || (chInt < 64 && chInt > 57))
+ return true;
+ switch (chInt) {
+ case 0:
+ case 34: // "
+ case 38: // &
+ case 42: // *
+ case 44: // ,
+ case 47: // /
+ case 92: // \
+ case 94: // ^
+ case 124: // |
+ return true;
+ }
+
+ return false;
+ }
+
+#if NET_2_0
+ [Obsolete]
+#endif
+ protected static bool IsExcludedCharacter (char ch)
+ {
+ if (ch <= 32 || ch >= 127)
+ return true;
+
+ if (ch == '"' || ch == '#' || ch == '%' || ch == '<' ||
+ ch == '>' || ch == '[' || ch == '\\' || ch == ']' ||
+ ch == '^' || ch == '`' || ch == '{' || ch == '|' ||
+ ch == '}')
+ return true;
+ return false;
+ }
+
+ internal static bool MaybeUri (string s)
+ {
+ int p = s.IndexOf (':');
+ if (p == -1)
+ return false;
+
+ if (p >= 10)
+ return false;
+
+ return IsPredefinedScheme (s.Substring (0, p));
+ }
+
+ private static bool IsPredefinedScheme (string scheme)
+ {
+ switch (scheme) {
+ case "http":
+ case "https":
+ case "file":
+ case "ftp":
+ case "nntp":
+ case "gopher":
+ case "mailto":
+ case "news":
+#if NET_2_0
+ case "net.pipe":
+ case "net.tcp":
+#endif
+ return true;
+ default:
+ return false;
+ }
+ }
+
+#if NET_2_0
+ [Obsolete]
+#endif
+ protected virtual bool IsReservedCharacter (char ch)
+ {
+ if (ch == '$' || ch == '&' || ch == '+' || ch == ',' ||
+ ch == '/' || ch == ':' || ch == ';' || ch == '=' ||
+ ch == '@')
+ return true;
+ return false;
+ }
+#if NET_2_0
+ [NonSerialized]
+ private UriParser parser;
+
+ private UriParser Parser {
+ get {
+ if (parser == null) {
+ parser = UriParser.GetParser (Scheme);
+ // no specific parser ? then use a default one
+ if (parser == null)
+ parser = new DefaultUriParser ("*");
+ }
+ return parser;
+ }
+ set { parser = value; }
+ }
+
+ public string GetComponents (UriComponents components, UriFormat format)
+ {
+ return Parser.GetComponents (this, components, format);
+ }
+
+ public bool IsBaseOf (Uri uri)
+ {
+ return Parser.IsBaseOf (this, uri);
+ }
+
+ public bool IsWellFormedOriginalString ()
+ {
+ // funny, but it does not use the Parser's IsWellFormedOriginalString().
+ return EscapeString (OriginalString) == OriginalString;
+ }
+
+ // static methods
+
+ private const int MaxUriLength = 32766;
+
+ public static int Compare (Uri uri1, Uri uri2, UriComponents partsToCompare, UriFormat compareFormat, StringComparison comparisonType)
+ {
+ if ((comparisonType < StringComparison.CurrentCulture) || (comparisonType > StringComparison.OrdinalIgnoreCase)) {
+ string msg = Locale.GetText ("Invalid StringComparison value '{0}'", comparisonType);
+ throw new ArgumentException ("comparisonType", msg);
+ }
+
+ if ((uri1 == null) && (uri2 == null))
+ return 0;
+
+ string s1 = uri1.GetComponents (partsToCompare, compareFormat);
+ string s2 = uri2.GetComponents (partsToCompare, compareFormat);
+ return String.Compare (s1, s2, comparisonType);
+ }
+
+ //
+ // The rules for EscapeDataString
+ //
+ static bool NeedToEscapeDataChar (char b)
+ {
+ return !((b >= 'A' && b <= 'Z') ||
+ (b >= 'a' && b <= 'z') ||
+ (b >= '0' && b <= '9') ||
+ b == '_' || b == '~' || b == '!' || b == '\'' ||
+ b == '(' || b == ')' || b == '*' || b == '-' || b == '.');
+ }
+
+ public static string EscapeDataString (string stringToEscape)
+ {
+ if (stringToEscape == null)
+ throw new ArgumentNullException ("stringToEscape");
+
+ if (stringToEscape.Length > MaxUriLength) {
+ string msg = Locale.GetText ("Uri is longer than the maximum {0} characters.");
+ throw new UriFormatException (msg);
+ }
+ bool escape = false;
+ foreach (char c in stringToEscape){
+ if (NeedToEscapeDataChar (c)){
+ escape = true;
+ break;
+ }
+ }
+ if (!escape){
+ return stringToEscape;
+ }
+
+ StringBuilder sb = new StringBuilder ();
+ byte [] bytes = Encoding.UTF8.GetBytes (stringToEscape);
+ foreach (byte b in bytes){
+ if (NeedToEscapeDataChar ((char) b))
+ sb.Append (HexEscape ((char) b));
+ else
+ sb.Append ((char) b);
+ }
+ return sb.ToString ();
+ }
+
+ //
+ // The rules for EscapeUriString
+ //
+ static bool NeedToEscapeUriChar (char b)
+ {
+ return !((b >= 'A' && b <= 'Z') ||
+ (b >= 'a' && b <= 'z') ||
+ (b >= '&' && b <= ';') ||
+ b == '!' || b == '#' || b == '$' || b == '=' ||
+ b == '?' || b == '@' || b == '_' || b == '~');
+ }
+
+ public static string EscapeUriString (string stringToEscape)
+ {
+ if (stringToEscape == null)
+ throw new ArgumentNullException ("stringToEscape");
+
+ if (stringToEscape.Length > MaxUriLength) {
+ string msg = Locale.GetText ("Uri is longer than the maximum {0} characters.");
+ throw new UriFormatException (msg);
+ }
+
+ bool escape = false;
+ foreach (char c in stringToEscape){
+ if (NeedToEscapeUriChar (c)){
+ escape = true;
+ break;
+ }
+ }
+ if (!escape)
+ return stringToEscape;
+
+ StringBuilder sb = new StringBuilder ();
+ byte [] bytes = Encoding.UTF8.GetBytes (stringToEscape);
+ foreach (byte b in bytes){
+ if (NeedToEscapeUriChar ((char) b))
+ sb.Append (HexEscape ((char) b));
+ else
+ sb.Append ((char) b);
+ }
+ return sb.ToString ();
+ }
+
+ public static bool IsWellFormedUriString (string uriString, UriKind uriKind)
+ {
+ if (uriString == null)
+ return false;
+
+ Uri uri;
+ if (Uri.TryCreate (uriString, uriKind, out uri))
+ return uri.IsWellFormedOriginalString ();
+ return false;
+ }
+
+ public static bool TryCreate (string uriString, UriKind uriKind, out Uri result)
+ {
+ bool success;
+
+ Uri r = new Uri (uriString, uriKind, out success);
+ if (success) {
+ result = r;
+ return true;
+ }
+ result = null;
+ return false;
+ }
+
+ // [MonoTODO ("rework code to avoid exception catching")]
+ public static bool TryCreate (Uri baseUri, string relativeUri, out Uri result)
+ {
+ try {
+ // FIXME: this should call UriParser.Resolve
+ result = new Uri (baseUri, relativeUri);
+ return true;
+ } catch (UriFormatException) {
+ result = null;
+ return false;
+ }
+ }
+
+ //[MonoTODO ("rework code to avoid exception catching")]
+ public static bool TryCreate (Uri baseUri, Uri relativeUri, out Uri result)
+ {
+ try {
+ // FIXME: this should call UriParser.Resolve
+ result = new Uri (baseUri, relativeUri.OriginalString);
+ return true;
+ } catch (UriFormatException) {
+ result = null;
+ return false;
+ }
+ }
+
+ public static string UnescapeDataString (string stringToUnescape)
+ {
+ if (stringToUnescape == null)
+ throw new ArgumentNullException ("stringToUnescape");
+
+ if (stringToUnescape.IndexOf ('%') == -1 && stringToUnescape.IndexOf ('+') == -1)
+ return stringToUnescape;
+
+ StringBuilder output = new StringBuilder ();
+ long len = stringToUnescape.Length;
+ MemoryStream bytes = new MemoryStream ();
+ int xchar;
+
+ for (int i = 0; i < len; i++) {
+ if (stringToUnescape [i] == '%' && i + 2 < len && stringToUnescape [i + 1] != '%') {
+ if (stringToUnescape [i + 1] == 'u' && i + 5 < len) {
+ if (bytes.Length > 0) {
+ output.Append (GetChars (bytes, Encoding.UTF8));
+ bytes.SetLength (0);
+ }
+
+ xchar = GetChar (stringToUnescape, i + 2, 4);
+ if (xchar != -1) {
+ output.Append ((char) xchar);
+ i += 5;
+ }
+ else {
+ output.Append ('%');
+ }
+ }
+ else if ((xchar = GetChar (stringToUnescape, i + 1, 2)) != -1) {
+ bytes.WriteByte ((byte) xchar);
+ i += 2;
+ }
+ else {
+ output.Append ('%');
+ }
+ continue;
+ }
+
+ if (bytes.Length > 0) {
+ output.Append (GetChars (bytes, Encoding.UTF8));
+ bytes.SetLength (0);
+ }
+
+ output.Append (stringToUnescape [i]);
+ }
+
+ if (bytes.Length > 0) {
+ output.Append (GetChars (bytes, Encoding.UTF8));
+ }
+
+ bytes = null;
+ return output.ToString ();
+ }
+
+ private static int GetInt (byte b)
+ {
+ char c = (char) b;
+ if (c >= '0' && c <= '9')
+ return c - '0';
+
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+
+ return -1;
+ }
+
+ private static int GetChar (string str, int offset, int length)
+ {
+ int val = 0;
+ int end = length + offset;
+ for (int i = offset; i < end; i++) {
+ char c = str [i];
+ if (c > 127)
+ return -1;
+
+ int current = GetInt ((byte) c);
+ if (current == -1)
+ return -1;
+ val = (val << 4) + current;
+ }
+
+ return val;
+ }
+
+ private static char [] GetChars (MemoryStream b, Encoding e)
+ {
+ return e.GetChars (b.GetBuffer (), 0, (int) b.Length);
+ }
+
+
+ private void EnsureAbsoluteUri ()
+ {
+ if (!IsAbsoluteUri)
+ throw new InvalidOperationException ("This operation is not supported for a relative URI.");
+ }
+#else
+ private void EnsureAbsoluteUri ()
+ {
+ }
+#endif
+ }
+}
diff --git a/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/UriFormatException.cs b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/UriFormatException.cs
new file mode 100644
index 0000000..8506b93
--- /dev/null
+++ b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/UriFormatException.cs
@@ -0,0 +1,72 @@
+//
+// System.UriFormatException.cs
+//
+// Author:
+// Scott Sanders (scott@stonecobra.com)
+// Duncan Mak (duncan@ximian.com)
+//
+// (C) 2001 Scott Sanders
+// (C) 2002 Ximian, Inc.
+// Copyright (C) 2005, 2008 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Globalization;
+using System.Runtime.Serialization;
+
+namespace MonoForks.System {
+
+ [Serializable]
+ public class UriFormatException : FormatException, ISerializable
+ {
+
+ // Constructors
+ public UriFormatException ()
+ : base (Locale.GetText("Invalid URI format"))
+ {
+ }
+
+ public UriFormatException (string message)
+ : base (message)
+ {
+ }
+#if NET_2_1
+ public UriFormatException (string message, Exception exception)
+ : base (message, exception)
+ {
+ }
+#endif
+ protected UriFormatException (SerializationInfo info, StreamingContext context)
+ : base (info, context)
+ {
+ }
+
+ // Methods
+
+ // This effectively kills the LinkDemand from Exception.GetObjectData (if someone
+ // use the ISerializable interface to serialize the object). See unit tests.
+ void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context)
+ {
+ base.GetObjectData (info, context);
+ }
+ }
+}
diff --git a/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/UriHostNameType.cs b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/UriHostNameType.cs
new file mode 100644
index 0000000..0ae13ef
--- /dev/null
+++ b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/UriHostNameType.cs
@@ -0,0 +1,62 @@
+// UriHostNameType.cs
+//
+// This code was automatically generated from
+// ECMA CLI XML Library Specification.
+// Generator: libgen.xsl [1.0; (C) Sergey Chaban (serge@wildwestsoftware.com)]
+// Created: Wed, 5 Sep 2001 06:33:14 UTC
+// Source file: AllTypes.xml
+// URL: http://msdn.microsoft.com/net/ecma/AllTypes.xml
+//
+// (C) 2001 Ximian, Inc. http://www.ximian.com
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+
+namespace MonoForks.System {
+
+
+ /// <summary>
+ /// </summary>
+ public enum UriHostNameType {
+
+ /// <summary>
+ /// </summary>
+ Unknown = 0,
+
+ /// <summary>
+ /// </summary>
+ Basic = 1,
+
+ /// <summary>
+ /// </summary>
+ Dns = 2,
+
+ /// <summary>
+ /// </summary>
+ IPv4 = 3,
+
+ /// <summary>
+ /// </summary>
+ IPv6 = 4,
+ } // UriHostNameType
+
+} // System
diff --git a/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/UriKind.cs b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/UriKind.cs
new file mode 100644
index 0000000..2437c56
--- /dev/null
+++ b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/UriKind.cs
@@ -0,0 +1,42 @@
+//
+// System.UriKind enumeration
+//
+// Author:
+// Sebastien Pouliot <sebastien@ximian.com>
+//
+// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+namespace MonoForks.System {
+
+#if NET_2_0
+ public
+#else
+ internal
+#endif
+ enum UriKind {
+
+ RelativeOrAbsolute,
+ Absolute,
+ Relative,
+ }
+}
diff --git a/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/UriPartial.cs b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/UriPartial.cs
new file mode 100644
index 0000000..f85bc23
--- /dev/null
+++ b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/UriPartial.cs
@@ -0,0 +1,44 @@
+// UriPartial.cs
+//
+// This code was automatically generated from
+// ECMA CLI XML Library Specification.
+// Generator: libgen.xsl [1.0; (C) Sergey Chaban (serge@wildwestsoftware.com)]
+// Created: Wed, 5 Sep 2001 06:33:21 UTC
+// Source file: AllTypes.xml
+// URL: http://msdn.microsoft.com/net/ecma/AllTypes.xml
+//
+// (C) 2001 Ximian, Inc. http://www.ximian.com
+// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+namespace MonoForks.System {
+
+ public enum UriPartial {
+
+ Scheme = 0,
+ Authority = 1,
+ Path = 2,
+#if NET_2_0
+ Query
+#endif
+ }
+}
diff --git a/Runtime/Managed/CrossDomainPolicyParser/Properties/AssemblyInfo.cs b/Runtime/Managed/CrossDomainPolicyParser/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..85cb64b
--- /dev/null
+++ b/Runtime/Managed/CrossDomainPolicyParser/Properties/AssemblyInfo.cs
@@ -0,0 +1,37 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("CrossDomainPolicyParser")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("CrossDomainPolicyParser")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2010")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("f17522fc-5e6b-43ea-baf9-8af61d9740f0")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: InternalsVisibleTo("CrossDomainPolicyParserTests")]
diff --git a/Runtime/Managed/CrossDomainPolicyParser/Tests/CrossDomainPolicyParserTests.csproj b/Runtime/Managed/CrossDomainPolicyParser/Tests/CrossDomainPolicyParserTests.csproj
new file mode 100644
index 0000000..0e27635
--- /dev/null
+++ b/Runtime/Managed/CrossDomainPolicyParser/Tests/CrossDomainPolicyParserTests.csproj
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{5C04DB87-3B34-43B4-B164-86CE4361DC7B}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>CrossDomainPolicyParserTests</RootNamespace>
+ <AssemblyName>CrossDomainPolicyParserTests</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Xml.Linq">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data.DataSetExtensions">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ <Reference Include="nunit.framework, Version=2.5.3.9345, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\..\..\..\Tools\NUnit\bin\nunit.framework.dll</HintPath>
+ </Reference>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="FlashPolicyParserSocketTests.cs" />
+ <Compile Include="FlashPolicyParserTests.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="UriToolsTests.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\CrossDomainPolicyParser.csproj">
+ <Project>{31C2F345-D887-49DD-A1F6-741CABD74A42}</Project>
+ <Name>CrossDomainPolicyParser</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/Runtime/Managed/CrossDomainPolicyParser/Tests/FlashPolicyParserSocketTests.cs b/Runtime/Managed/CrossDomainPolicyParser/Tests/FlashPolicyParserSocketTests.cs
new file mode 100644
index 0000000..8e0f62b
--- /dev/null
+++ b/Runtime/Managed/CrossDomainPolicyParser/Tests/FlashPolicyParserSocketTests.cs
@@ -0,0 +1,124 @@
+using System.IO;
+using System.Text;
+using MonoForks.System.Windows.Browser.Net;
+using NUnit.Framework;
+
+namespace CrossDomainPolicyParserTests
+{
+ [TestFixture]
+ public class FlashPolicyParserSocketTests
+ {
+ [Test]
+ public void AllDomains_AllPorts_IsAllowed()
+ {
+ string policy = @"<?xml version='1.0'?>
+<cross-domain-policy>
+ <allow-access-from domain=""*"" to-ports=""*"" />
+</cross-domain-policy>";
+ Assert.IsTrue(RequestAllowed(policy, 123));
+ }
+
+ [Test]
+ public void AllDomains_AllPorts_Trailing0_IsAllowed()
+ {
+ string policy = @"<?xml version='1.0'?>
+<cross-domain-policy>
+ <allow-access-from domain=""*"" to-ports=""*"" />
+</cross-domain-policy>" + "\0";
+ Assert.IsTrue(RequestAllowed(policy, 123));
+ }
+
+ [Test]
+ public void AllDomains_UsingSpecificPorts_IsAllowed()
+ {
+ string policy = @"<?xml version='1.0'?>
+<cross-domain-policy>
+ <allow-access-from domain=""*"" to-ports=""1010,1020"" />
+</cross-domain-policy>";
+ Assert.IsTrue(RequestAllowed(policy, 1020));
+ }
+
+ [Test]
+ public void AllDomains_OutsideSpecificPorts_IsDisAllowed()
+ {
+ string policy = @"<?xml version='1.0'?>
+<cross-domain-policy>
+ <allow-access-from domain=""*"" to-ports=""1010,1030"" />
+</cross-domain-policy>";
+ Assert.IsFalse(RequestAllowed(policy, 1020));
+ }
+
+ [Test]
+ public void AllDomains_OutsidePortRange_IsDisAllowed()
+ {
+ string policy = @"<?xml version='1.0'?>
+<cross-domain-policy>
+ <allow-access-from domain=""*"" to-ports=""1030-1040"" />
+</cross-domain-policy>";
+ Assert.IsFalse(RequestAllowed(policy, 1020));
+ }
+
+ [Test]
+ public void AllDomains_InsidePortRange_IsAllowed()
+ {
+ string policy = @"<?xml version='1.0'?>
+<cross-domain-policy>
+ <allow-access-from domain=""*"" to-ports=""1030-1040"" />
+</cross-domain-policy>";
+ Assert.IsTrue(RequestAllowed(policy, 1035));
+ }
+
+ [Test]
+ public void PolicyReceivedFromHigherThan1024_DisallowsAccessToBelow1024Ports()
+ {
+ string policy = @"<?xml version='1.0'?>
+<cross-domain-policy>
+ <allow-access-from domain=""*"" to-ports=""1000-1040"" />
+</cross-domain-policy>";
+ Assert.IsFalse(RequestAllowed(policy, 1010, 1300));
+ }
+
+ [Test]
+ public void PolicyReceivedFromHigherThan1024_AllowsAccessToAbove1024Ports()
+ {
+ string policy = @"<?xml version='1.0'?>
+<cross-domain-policy>
+ <allow-access-from domain=""*"" to-ports=""1000-1040"" />
+</cross-domain-policy>";
+ Assert.IsTrue(RequestAllowed(policy, 1035, 1300));
+ }
+
+ [Test]
+ public void PolicyReceivedFromLowerThan1024_AllowsAccessToBelow1024Ports()
+ {
+ string policy = @"<?xml version='1.0'?>
+<cross-domain-policy>
+ <allow-access-from domain=""*"" to-ports=""1000-1040"" />
+</cross-domain-policy>";
+ Assert.IsTrue(RequestAllowed(policy, 1010, 1000));
+ }
+ [Test]
+ public void PolicyReceivedFromLowerThan1024_AllowsAccessToAbove1024Ports()
+ {
+ string policy = @"<?xml version='1.0'?>
+<cross-domain-policy>
+ <allow-access-from domain=""*"" to-ports=""1000-1040"" />
+</cross-domain-policy>";
+ Assert.IsTrue(RequestAllowed(policy, 1030, 1000));
+ }
+
+ private bool RequestAllowed(string xdomain, int port)
+ {
+ return RequestAllowed(xdomain, port, 843);
+ }
+
+ private bool RequestAllowed(string xdomain, int port, int policyport)
+ {
+ var ms = new MemoryStream(Encoding.UTF8.GetBytes(xdomain));
+ var policy = FlashCrossDomainPolicy.FromStream(ms);
+ policy.PolicyPort = policyport;
+ return policy.IsSocketConnectionAllowed(port);
+ }
+
+ }
+} \ No newline at end of file
diff --git a/Runtime/Managed/CrossDomainPolicyParser/Tests/FlashPolicyParserTests.cs b/Runtime/Managed/CrossDomainPolicyParser/Tests/FlashPolicyParserTests.cs
new file mode 100644
index 0000000..976ba92
--- /dev/null
+++ b/Runtime/Managed/CrossDomainPolicyParser/Tests/FlashPolicyParserTests.cs
@@ -0,0 +1,209 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using MonoForks.Mono.Xml;
+using MonoForks.System.Net;
+using NUnit.Framework;
+using MonoForks.System.Windows.Browser.Net;
+using UnityEngine;
+using Uri = MonoForks.System.Uri;
+
+namespace CrossDomainPolicyParserTests
+{
+ [TestFixture]
+ public class FlashPolicyParserTests
+ {
+ static string XDomainGlobal =
+@"<?xml version=""1.0""?>
+<!DOCTYPE cross-domain-policy SYSTEM ""http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd"">
+<cross-domain-policy>
+ <allow-access-from domain=""*"" />
+</cross-domain-policy>";
+
+ string http_hosted = "http://www.host.com/coolgame.unity3d";
+ string https_hosted = "https://secure.host.net/coolgame.unity3d";
+ string file_hosted = "file:///coolgame.unity3";
+
+ [Test]
+ public void GlobalXDomainAcceptsRequestOnSameDomain()
+ {
+ string requesturl = "http://www.mach8.nl/index.html";
+
+ Assert.IsTrue(RequestAllowed(XDomainGlobal, requesturl, http_hosted));
+ }
+ [Test]
+ public void GlobalXDomainAcceptsRequestOnSubDomain()
+ {
+ string requesturl = "http://subdomain.mach8.nl/index.html";
+
+ Assert.IsTrue(RequestAllowed(XDomainGlobal, requesturl, http_hosted));
+ }
+
+ [Test]
+ public void GlobalXDomainAllowsSecureRequestWhenHostedNonSecure()
+ {
+ string requesturl = "https://www.mach8.nl/index.html";
+
+ Assert.IsTrue(RequestAllowed(XDomainGlobal, requesturl, http_hosted));
+ }
+ [Test]
+ public void GlobalXDomainAcceptsSecureRequestWhenHostedSecure()
+ {
+ string requesturl = "https://www.mach8.nl/index.html";
+
+ Assert.IsTrue(RequestAllowed(XDomainGlobal, requesturl, https_hosted));
+ }
+ [Test]
+ public void GlobalXDomainDeniesNonSecureRequestWhenHostedSecure()
+ {
+ string requesturl = "http://www.mach8.nl/index.html";
+ Assert.IsFalse(RequestAllowed(XDomainGlobal, requesturl, https_hosted));
+ }
+
+ [Test]
+ public void AllDomain_Secure()
+ {
+ string policy = @"<?xml version=""1.0""?>
+<!DOCTYPE cross-domain-policy SYSTEM ""http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd"">
+<cross-domain-policy>
+ <allow-access-from domain=""*"" secure=""true""/>
+</cross-domain-policy>";
+
+ Assert.IsTrue(RequestAllowed(policy, "http://www.host.com", http_hosted));
+ }
+
+ [Test]
+ public void WhenRequestURLMatchesWildCardAccessIsAllowed()
+ {
+ string policy = @"<?xml version=""1.0""?>
+<cross-domain-policy>
+ <allow-access-from domain=""*.mydomain.nl"" />
+</cross-domain-policy>";
+
+ Assert.IsTrue(RequestAllowed(policy, "http://subdomain.mydomain.nl", http_hosted));
+ }
+
+ [Test]
+ public void WhenRequestURLDoesNotMatchWildCardAccessIsDisallowed()
+ {
+ string policy = @"<?xml version=""1.0""?>
+<cross-domain-policy>
+ <allow-access-from domain=""*.mydomain.nl"" />
+</cross-domain-policy>";
+
+ Assert.IsFalse(RequestAllowed(policy, "http://subdomain.myotherdomain.nl", http_hosted));
+ }
+
+
+ [Test]
+ public void AllDomains_NoDTD()
+ {
+ string policy = @"<?xml version='1.0'?><cross-domain-policy><allow-access-from domain='*'/></cross-domain-policy>";
+
+ Assert.IsTrue(RequestAllowed(policy, "http://www.host.com", http_hosted));
+ }
+
+ [Test]
+ public void AllDomains_NoXmlHeader()
+ {
+ string policy = @"<cross-domain-policy>
+ <allow-access-from domain=""*"" to-ports=""*""/>
+</cross-domain-policy> ";
+ Assert.IsTrue(RequestAllowed(policy, "http://www.host.com", http_hosted));
+ }
+
+ [Test]
+ public void AllDomains_PermittedCrossDomainPolicies_All()
+ {
+ // 'all' is the default value
+ // http://www.adobe.com/devnet/articles/crossdomain_policy_file_spec.html#site-control-permitted-cross-domain-policies
+ string policy = @"<?xml version='1.0'?>
+<!DOCTYPE cross-domain-policy SYSTEM 'http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd'>
+<cross-domain-policy>
+ <site-control permitted-cross-domain-policies='all' />
+ <allow-access-from domain='*' />
+</cross-domain-policy>";
+
+ Assert.IsTrue(RequestAllowed(policy, "http://www.host.com", http_hosted));
+ }
+
+ [Test]
+ public void AllDomains_PermittedCrossDomainPolicies_MasterOnly()
+ {
+ string policy = @"<?xml version='1.0'?>
+<!DOCTYPE cross-domain-policy SYSTEM 'http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd'>
+<cross-domain-policy>
+ <site-control permitted-cross-domain-policies='master-only' />
+ <allow-access-from domain='*' />
+</cross-domain-policy>";
+
+ Assert.IsTrue(RequestAllowed(policy, "http://www.host.com", http_hosted));
+ }
+
+ [Test]
+ public void AllDomains_PermittedCrossDomainPolicies_None()
+ {
+ string policy = @"<?xml version='1.0'?>
+<!DOCTYPE cross-domain-policy SYSTEM 'http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd'>
+<cross-domain-policy>
+ <site-control permitted-cross-domain-policies='none' />
+ <allow-access-from domain='*' />
+</cross-domain-policy>";
+ Assert.IsFalse(RequestAllowed(policy, "http://www.host.com", http_hosted));
+ }
+
+ [Test]
+ public void AllDomains_PermittedCrossDomainPolicies_ByContentType()
+ {
+ string policy = @"<?xml version='1.0'?>
+<!DOCTYPE cross-domain-policy SYSTEM 'http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd'>
+<cross-domain-policy>
+ <site-control permitted-cross-domain-policies='by-content-type' />
+ <allow-access-from domain='*' />
+</cross-domain-policy>";
+ Assert.IsFalse(RequestAllowed(policy, "http://www.host.com", http_hosted));
+ }
+
+ [Test]
+ public void AllDomains_PermittedCrossDomainPolicies_ByFtpFilename()
+ {
+ string policy = @"<?xml version='1.0'?>
+<!DOCTYPE cross-domain-policy SYSTEM 'http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd'>
+<cross-domain-policy>
+ <site-control permitted-cross-domain-policies='by-ftp-filename' />
+ <allow-access-from domain='*' />
+</cross-domain-policy>";
+ Assert.IsTrue(RequestAllowed(policy, "http://www.host.com", http_hosted));
+ }
+
+ [Test]
+ [ExpectedException(typeof(MiniParser.XMLError))]
+ public void IllformedPolicyIsRejected()
+ {
+ FlashCrossDomainPolicyFromString("bogus", "http://www.host.com");
+ }
+
+ [Test]
+ [ExpectedException(typeof(ArgumentException))]
+ public void EmptyPolicyStringIsRejected()
+ {
+ FlashCrossDomainPolicyFromString("", "http://www.host.com");
+ }
+
+ private bool RequestAllowed(string xdomain, string requesturl, string hosturl)
+ {
+ FlashCrossDomainPolicy policy = FlashCrossDomainPolicyFromString(xdomain, hosturl);
+ var wr = new WebRequest(new Uri(requesturl), new Dictionary<string, string>());
+ return policy.IsAllowed(wr);
+ }
+
+ private FlashCrossDomainPolicy FlashCrossDomainPolicyFromString(string xdomain, string hosturl)
+ {
+ UnityCrossDomainHelper.SetWebSecurityHostUriDelegate(() => hosturl);
+
+ var ms = new MemoryStream(Encoding.UTF8.GetBytes(xdomain));
+ return FlashCrossDomainPolicy.FromStream(ms);
+ }
+ }
+}
diff --git a/Runtime/Managed/CrossDomainPolicyParser/Tests/Properties/AssemblyInfo.cs b/Runtime/Managed/CrossDomainPolicyParser/Tests/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..5fd4c99
--- /dev/null
+++ b/Runtime/Managed/CrossDomainPolicyParser/Tests/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("CrossDomainPolicyParserTests")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("CrossDomainPolicyParserTests")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2010")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("c40d4596-1c43-4f37-b7fa-545a543577f3")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Runtime/Managed/CrossDomainPolicyParser/Tests/UriToolsTests.cs b/Runtime/Managed/CrossDomainPolicyParser/Tests/UriToolsTests.cs
new file mode 100644
index 0000000..7a29b00
--- /dev/null
+++ b/Runtime/Managed/CrossDomainPolicyParser/Tests/UriToolsTests.cs
@@ -0,0 +1,23 @@
+using CrossDomainPolicyParser;
+using MonoForks.System;
+using NUnit.Framework;
+
+namespace CrossDomainPolicyParserTests
+{
+ [TestFixture]
+ public class UriToolsTests
+ {
+ [Test]
+ public void MakeUriWorksForRelativeUri()
+ {
+ Uri uri = UriTools.MakeUri("http://mydomain.com/mygame.unity3d", "test.png");
+ Assert.AreEqual("mydomain.com",uri.Host);
+ }
+ [Test]
+ public void MakeUriWorksForAbsoluteUri()
+ {
+ Uri uri = UriTools.MakeUri("http://mydomain.com/mygame.unity3d", "http://www.google.com/test.png");
+ Assert.AreEqual("www.google.com", uri.Host);
+ }
+ }
+}
diff --git a/Runtime/Managed/CrossDomainPolicyParser/UnityCrossDomainHelper.cs b/Runtime/Managed/CrossDomainPolicyParser/UnityCrossDomainHelper.cs
new file mode 100644
index 0000000..e43ba59
--- /dev/null
+++ b/Runtime/Managed/CrossDomainPolicyParser/UnityCrossDomainHelper.cs
@@ -0,0 +1,213 @@
+using System;
+using System.Reflection;
+using System.Security;
+using System.Text;
+using CrossDomainPolicyParser;
+using System.IO;
+using System.Collections.Generic;
+using MonoForks.System.Windows.Browser.Net;
+
+internal class Log
+{
+ public delegate void LogDelegate(string msg);
+
+ static LogDelegate logger;
+
+ static public void SetLog(LogDelegate ld)
+ {
+ logger = ld;
+ }
+
+ static public void Msg(string msg)
+ {
+ if (logger != null) logger(msg);
+ }
+}
+
+namespace UnityEngine
+{
+ public class UnityCrossDomainHelper
+ {
+ public enum SecurityPolicy
+ {
+ DontKnowYet = 0,
+ AllowAccess = 1,
+ DenyAccess = 2
+ }
+
+ public delegate string GetWebSecurityHostUriDelegate();
+ private static GetWebSecurityHostUriDelegate getWebSecurityHostUriDelegate = DefaultGetWebSecurityHostUri;
+ static WWWPolicyProvider wwwPolicyProvider = new WWWPolicyProvider();
+
+ static public string GetWebSecurityHostUri()
+ {
+ return getWebSecurityHostUriDelegate();
+ }
+
+ static internal void SetWebSecurityHostUriDelegate(GetWebSecurityHostUriDelegate d)
+ {
+ getWebSecurityHostUriDelegate = d;
+ }
+
+ static string DefaultGetWebSecurityHostUri()
+ {
+ return Application.webSecurityHostUrl;
+ }
+
+ public static void ClearCache()
+ {
+ wwwPolicyProvider.ClearCache();
+ CrossDomainPolicyManager.ClearCache();
+ }
+
+ interface IPolicyProvider
+ {
+ Stream GetPolicy(string url);
+ }
+
+ class WWWPolicyProvider : IPolicyProvider
+ {
+ Dictionary<string,WWW> policyDownloads = new Dictionary<string, WWW>();
+
+ public void ClearCache()
+ {
+ policyDownloads.Clear();
+ }
+
+ public Stream GetPolicy(string policyurl)
+ {
+ WWW downloadInProgress = null;
+ policyDownloads.TryGetValue(policyurl, out downloadInProgress);
+
+ if (downloadInProgress != null)
+ {
+ if (!downloadInProgress.isDone) return null;
+
+ bool statuscodeOK = downloadInProgress.error == null;
+
+ if (!statuscodeOK) throw new InvalidOperationException("Unable to download policy");
+ if (statuscodeOK)
+ {
+ Log.Msg("Download had OK statuscode");
+ Log.Msg("Received the following crossdomain.xml");
+ Log.Msg("----------");
+ Log.Msg(downloadInProgress.text);
+ Log.Msg("----------");
+ return new MemoryStream(downloadInProgress.bytes);
+ }
+
+ }
+
+ //okay, we hadn't started downloading the policy, lets start the policy download.
+ var www = new WWW(policyurl);
+ policyDownloads.Add(policyurl, www);
+ return null;
+ }
+ }
+
+ class WebRequestPolicyProvider : IPolicyProvider
+ {
+ private MethodInfo methodinfo;
+
+ public WebRequestPolicyProvider(MethodInfo mi)
+ {
+ methodinfo = mi;
+ }
+
+ [System.Security.SecuritySafeCritical]
+ public Stream GetPolicy(string policy_url)
+ {
+ var proxy = System.Environment.GetEnvironmentVariable("UNITY_PROXYSERVER");
+ if (string.IsNullOrEmpty(proxy))
+ proxy = null;
+ object result = methodinfo.Invoke(null, new object[] {policy_url, proxy});
+ return (Stream) result;
+ }
+ }
+
+ public static SecurityPolicy GetSecurityPolicy(string requesturi_string)
+ {
+ return GetSecurityPolicy(requesturi_string, wwwPolicyProvider);
+ }
+
+ public static bool GetSecurityPolicyForDotNetWebRequest(string requesturi_string, MethodInfo policyProvidingMethod)
+ {
+ var provider = new WebRequestPolicyProvider(policyProvidingMethod);
+
+ return GetSecurityPolicy(requesturi_string, provider) == SecurityPolicy.AllowAccess;
+ }
+
+ static SecurityPolicy GetSecurityPolicy(string requesturi_string, IPolicyProvider policyProvider)
+ {
+ var requesturi = UriTools.MakeUri(Application.webSecurityHostUrl, requesturi_string);
+ if (requesturi.Scheme=="file")
+ {
+ //Editor-In-WebMode is allowed to read files from file://
+ if (Application.isEditor) return SecurityPolicy.AllowAccess;
+
+ //Webplayer itself is allowed to read files from file:// as long as it is hosted on file:// itself as well.
+ var hostedat = new MonoForks.System.Uri(Application.webSecurityHostUrl);
+ if (Application.isWebPlayer && hostedat.Scheme == "file") return SecurityPolicy.AllowAccess;
+
+ //other scenarios of accessing file:// are not allowed
+ return SecurityPolicy.DenyAccess;
+ }
+
+ //todo: force absolute
+ ICrossDomainPolicy policy = CrossDomainPolicyManager.GetCachedWebPolicy(requesturi);
+ if (policy != null)
+ {
+ var request = new MonoForks.System.Net.WebRequest(requesturi, new Dictionary<string, string>());
+ SecurityPolicy allowed = policy.IsAllowed(request) ? SecurityPolicy.AllowAccess : SecurityPolicy.DenyAccess;
+ return allowed;
+ }
+
+ if (ShouldEnableLogging())
+ Log.SetLog(Console.WriteLine);
+
+ Log.Msg("Determining crossdomain.xml location for request: " + requesturi);
+ var policyURI = CrossDomainPolicyManager.GetFlashPolicyUri(requesturi);
+
+ Stream s;
+ try
+ {
+ s = policyProvider.GetPolicy(policyURI.ToString());
+ if (s == null) return SecurityPolicy.DontKnowYet;
+ CrossDomainPolicyManager.BuildFlashPolicy(true, policyURI, s, new Dictionary<string, string>());
+ } catch (InvalidOperationException)
+ {
+ return SecurityPolicy.DenyAccess;
+ }
+ catch (MonoForks.Mono.Xml.MiniParser.XMLError xe)
+ {
+ Debug.Log (string.Format ("Error reading crossdomain policy: {0}", xe.Message));
+ return SecurityPolicy.DenyAccess;
+ }
+ return GetSecurityPolicy(requesturi_string, policyProvider);
+ }
+
+ [SecuritySafeCritical]
+ private static bool ShouldEnableLogging()
+ {
+ return Environment.GetEnvironmentVariable("ENABLE_CROSSDOMAIN_LOGGING")=="1";
+ }
+
+ static public bool CheckSocketEndPoint(string connecting_to_ip, int port)
+ {
+ Log.Msg("CheckSocketEndpoint called for "+connecting_to_ip+" with port: "+port);
+
+ if (!Application.webSecurityEnabled) return true;
+
+ bool result = CrossDomainPolicyManager.CheckSocketEndPoint(connecting_to_ip,port);
+ Log.Msg("CheckSocketENdpoint returns :"+result);
+ return result;
+ }
+ static public bool PrefetchSocketPolicy(string ip, int policyport, int timeout)
+ {
+ if (!Application.webSecurityEnabled) return false;
+ var policy = CrossDomainPolicyManager.FlashCrossDomainPolicyFor(ip, policyport, timeout);
+ return policy != FlashCrossDomainPolicy.DenyPolicy;
+ }
+
+ }
+}
diff --git a/Runtime/Managed/CrossDomainPolicyParser/UriTools.cs b/Runtime/Managed/CrossDomainPolicyParser/UriTools.cs
new file mode 100644
index 0000000..6fafc86
--- /dev/null
+++ b/Runtime/Managed/CrossDomainPolicyParser/UriTools.cs
@@ -0,0 +1,20 @@
+using System;
+using Uri = MonoForks.System.Uri;
+
+namespace CrossDomainPolicyParser
+{
+ class UriTools
+ {
+ public static Uri MakeUri(string gameurl, string url)
+ {
+ if ((!url.ToLower().StartsWith("http://")) && (!url.ToLower().StartsWith("https://")) && (!url.ToLower().StartsWith("file://")))
+ url = GetBaseUrl(gameurl) + "/" +url;
+ Log.Msg("About to parse url: " + url);
+ return new Uri(url);
+ }
+ static string GetBaseUrl(string url)
+ {
+ return url.Substring(0, url.LastIndexOf('/'));
+ }
+ }
+}