diff --git a/src/Xamarin.Android.Build.Tasks/MonoDroid.FSharp.targets b/src/Xamarin.Android.Build.Tasks/MonoDroid.FSharp.targets
new file mode 100644
index 00000000000..743d84bde21
--- /dev/null
+++ b/src/Xamarin.Android.Build.Tasks/MonoDroid.FSharp.targets
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/Xamarin.Android.Build.Tasks/Novell.MonoDroid.CSharp.targets b/src/Xamarin.Android.Build.Tasks/Novell.MonoDroid.CSharp.targets
new file mode 100644
index 00000000000..8901664f2c4
--- /dev/null
+++ b/src/Xamarin.Android.Build.Tasks/Novell.MonoDroid.CSharp.targets
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/Xamarin.Android.Build.Tasks/Novell.MonoDroid.Common.targets b/src/Xamarin.Android.Build.Tasks/Novell.MonoDroid.Common.targets
new file mode 100644
index 00000000000..fc2a4de3d97
--- /dev/null
+++ b/src/Xamarin.Android.Build.Tasks/Novell.MonoDroid.Common.targets
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/AndroidResource.cs b/src/Xamarin.Android.Build.Tasks/Utilities/AndroidResource.cs
new file mode 100644
index 00000000000..629be141b66
--- /dev/null
+++ b/src/Xamarin.Android.Build.Tasks/Utilities/AndroidResource.cs
@@ -0,0 +1,252 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
+using System.Xml.Linq;
+using System.Xml.XPath;
+
+namespace Monodroid {
+ static class AndroidResource {
+
+ public static void UpdateXmlResource (string filename, Dictionary acwMap, IEnumerable additionalDirectories = null)
+ {
+ // use a temporary file so we only update the real file if things actually changed
+ string tmpfile = filename + ".bk";
+ try {
+ XDocument doc = XDocument.Load (filename, LoadOptions.SetLineInfo);
+
+ // The assumption here is that the file we're fixing up is in a directory below the
+ // obj/${Configuration}/res/ directory and so appending ../gives us the actual path to
+ // 'res/'
+ UpdateXmlResource (Path.Combine (Path.GetDirectoryName (filename), ".."), doc.Root, acwMap, additionalDirectories);
+ using (var stream = File.OpenWrite (tmpfile))
+ using (var xw = new LinePreservedXmlWriter (new StreamWriter (stream)))
+ xw.WriteNode (doc.CreateNavigator (), false);
+ Xamarin.Android.Tasks.MonoAndroidHelper.CopyIfChanged (tmpfile, filename);
+ File.Delete (tmpfile);
+ }
+ catch (Exception e) {
+ if (File.Exists (tmpfile)) {
+ File.Delete (tmpfile);
+ }
+ Console.Error.WriteLine ("AndroidResgen: Warning while updating Resource XML '{0}': {1}", filename, e.Message);
+ return;
+ }
+ }
+
+ static readonly XNamespace android = "http://schemas.android.com/apk/res/android";
+ static readonly XNamespace res_auto = "http://schemas.android.com/apk/res-auto";
+ static readonly Regex r = new Regex (@"^@\+?(?[^:]+:)?(anim|color|drawable|layout|menu)/(?.*)$");
+ static readonly string[] fixResourcesAliasPaths = {
+ "/resources/item",
+ "/resources/integer-array/item",
+ "/resources/array/item",
+ "/resources/style/item",
+ };
+
+ public static void UpdateXmlResource (XElement e)
+ {
+ UpdateXmlResource (e, new Dictionary ());
+ }
+
+ public static void UpdateXmlResource (XElement e, Dictionary acwMap)
+ {
+ UpdateXmlResource (null, e, acwMap);
+ }
+
+ static IEnumerable Prepend (this IEnumerable l, T another) where T : XNode
+ {
+ yield return another;
+ foreach (var e in l)
+ yield return e;
+ }
+
+ static void UpdateXmlResource (string resourcesBasePath, XElement e, Dictionary acwMap, IEnumerable additionalDirectories = null)
+ {
+ foreach (var elem in GetElements (e).Prepend (e)) {
+ TryFixCustomView (elem, acwMap);
+ }
+
+ foreach (var path in fixResourcesAliasPaths) {
+ foreach(XElement item in e.XPathSelectElements (path).Prepend (e)) {
+ TryFixResourceAlias (item, resourcesBasePath, additionalDirectories);
+ }
+ }
+
+ foreach (XAttribute a in GetAttributes (e)) {
+ if (a.IsNamespaceDeclaration)
+ continue;
+
+ if (TryFixFragment (a, acwMap))
+ continue;
+
+ if (TryFixResAuto (a, acwMap))
+ continue;
+
+ if (TryFixCustomClassAttribute (a, acwMap))
+ continue;
+
+ if (a.Name.Namespace != android &&
+ !(a.Name.LocalName == "layout" && a.Name.Namespace == XNamespace.None &&
+ a.Parent.Name.LocalName == "include" && a.Parent.Name.Namespace == XNamespace.None))
+ continue;
+
+ Match m = r.Match (a.Value);
+ if (!m.Success)
+ continue;
+ if (m.Groups ["package"].Success)
+ continue;
+ a.Value = TryLowercaseValue (a.Value, resourcesBasePath, additionalDirectories);
+ }
+ }
+
+ static bool ResourceNeedsToBeLowerCased (string value, string resourceBasePath, IEnumerable additionalDirectories)
+ {
+ // Might be a bit of an overkill, but the data comes (indirectly) from the user since it's the
+ // path to the msbuild's intermediate output directory and that location can be changed by the
+ // user. It's better to be safe than sorry.
+ resourceBasePath = (resourceBasePath ?? String.Empty).Trim ();
+ if (String.IsNullOrEmpty (resourceBasePath))
+ return true;
+
+ // Avoid resource names that are all whitespace
+ value = (value ?? String.Empty).Trim ();
+ if (String.IsNullOrEmpty (value))
+ return false; // let's save some time
+ if (value.Length < 4 || value [0] != '@') // 4 is the minimum length since we need a string
+ // that is at least of the following
+ // form: @x/y. Checking it here saves some time
+ // below.
+ return true;
+
+ string filePath = null;
+ int slash = value.IndexOf ('/');
+ int colon = value.IndexOf (':');
+ if (colon == -1)
+ colon = 0;
+
+ // Determine the the potential definition file's path based on the resource type.
+ string dirPrefix = value.Substring (colon + 1, slash - colon - 1).ToLowerInvariant ();
+ string fileNamePattern = value.Substring (slash + 1).ToLowerInvariant () + ".*";
+
+ if (Directory.EnumerateDirectories (resourceBasePath, dirPrefix + "*").Any (dir => Directory.EnumerateFiles (dir, fileNamePattern).Any ()))
+ return true;
+
+ // check additional directories if we have them incase the resource is in a library project
+ if (additionalDirectories != null)
+ foreach (var additionalDirectory in additionalDirectories)
+ if (Directory.EnumerateDirectories (additionalDirectory, dirPrefix + "*").Any (dir => Directory.EnumerateFiles (dir, fileNamePattern).Any ()))
+ return true;
+
+ // No need to change the reference case.
+ return false;
+ }
+
+ static IEnumerable GetAttributes (XElement e)
+ {
+ foreach (XAttribute a in e.Attributes ())
+ yield return a;
+ foreach (XElement c in e.Elements ())
+ foreach (XAttribute a in GetAttributes (c))
+ yield return a;
+ }
+
+ static IEnumerable GetElements (XElement e)
+ {
+ foreach (var a in e.Elements ()) {
+ yield return a;
+
+ foreach (var b in GetElements (a))
+ yield return b;
+ }
+ }
+
+ private static void TryFixResourceAlias (XElement elem, string resourceBasePath, IEnumerable additionalDirectories)
+ {
+ // Looks for any resources aliases:
+ // - @layout/Page1
+ // - @drawable/Page1
+ // and corrects the alias to be lower case.
+ if (elem.Name == "item" && !string.IsNullOrEmpty(elem.Value) ) {
+ string value = elem.Value.Trim();
+ Match m = r.Match (value);
+ if (m.Success) {
+ elem.Value = TryLowercaseValue (elem.Value, resourceBasePath, additionalDirectories);
+ }
+ }
+ }
+
+ private static bool TryFixFragment (XAttribute attr, Dictionary acwMap)
+ {
+ // Looks for any:
+ // acwMap)
+ {
+ if (attr.Name.Namespace != res_auto)
+ return false;
+ switch (attr.Name.LocalName) {
+ case "rectLayout":
+ case "roundLayout":
+ attr.Value = attr.Value.ToLowerInvariant ();
+ return true;
+ }
+ return false;
+ }
+
+ private static bool TryFixCustomView (XElement elem, Dictionary acwMap)
+ {
+ // Looks for any acwMap)
+ {
+ /* Some attributes reference a Java class name.
+ * try to convert those like for TryFixCustomView
+ */
+ if (attr.Name != (res_auto + "layout_behavior") // For custom CoordinatorLayout behavior
+ && (attr.Parent.Name != "transition" || attr.Name.LocalName != "class")) // For custom transitions
+ return false;
+
+ string mappedValue;
+ if (!acwMap.TryGetValue (attr.Value, out mappedValue))
+ return false;
+
+ attr.Value = mappedValue;
+ return true;
+ }
+
+ private static string TryLowercaseValue (string value, string resourceBasePath, IEnumerable additionalDirectories)
+ {
+ int s = value.LastIndexOf ('/');
+ if (s >= 0) {
+ if (ResourceNeedsToBeLowerCased (value, resourceBasePath, additionalDirectories))
+ return value.Substring (0, s) + "/" + value.Substring (s+1).ToLowerInvariant ();
+ }
+ return value;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/Features.cs b/src/Xamarin.Android.Build.Tasks/Utilities/Features.cs
new file mode 100644
index 00000000000..a8c499a9124
--- /dev/null
+++ b/src/Xamarin.Android.Build.Tasks/Utilities/Features.cs
@@ -0,0 +1,5 @@
+namespace Xamarin.Android.Tools {
+
+ static class Features {
+ }
+}
diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/Files.cs b/src/Xamarin.Android.Build.Tasks/Utilities/Files.cs
new file mode 100644
index 00000000000..8f9ed7459ab
--- /dev/null
+++ b/src/Xamarin.Android.Build.Tasks/Utilities/Files.cs
@@ -0,0 +1,252 @@
+using System;
+using System.IO;
+using System.Security.Cryptography;
+
+using Ionic.Zip;
+#if MSBUILD
+using Microsoft.Build.Utilities;
+#endif
+
+namespace Xamarin.Android.Tools {
+
+ static class Files {
+
+ public static bool Archive (string target, Action archiver)
+ {
+ string newTarget = target + ".new";
+
+ archiver (newTarget);
+
+ bool changed = CopyIfChanged (newTarget, target);
+
+ try {
+ File.Delete (newTarget);
+ } catch {
+ }
+
+ return changed;
+ }
+
+ public static bool ArchiveZip (string target, Action archiver)
+ {
+ string newTarget = target + ".new";
+
+ archiver (newTarget);
+
+ bool changed = CopyIfZipChanged (newTarget, target);
+
+ try {
+ File.Delete (newTarget);
+ } catch {
+ }
+
+ return changed;
+ }
+
+ public static bool CopyIfChanged (string source, string destination)
+ {
+ if (HasFileChanged (source, destination)) {
+ var directory = Path.GetDirectoryName (destination);
+ if (!string.IsNullOrEmpty (directory))
+ Directory.CreateDirectory (directory);
+
+ File.Copy (source, destination, true);
+ return true;
+ }/* else
+ Console.WriteLine ("Skipping copying {0}, unchanged", Path.GetFileName (destination));*/
+
+ return false;
+ }
+
+ public static bool CopyIfZipChanged (Stream source, string destination)
+ {
+ string hash;
+ if (HasZipChanged (source, destination, out hash)) {
+ Directory.CreateDirectory (Path.GetDirectoryName (destination));
+ source.Position = 0;
+ using (var f = File.Create (destination)) {
+ source.CopyTo (f);
+ }
+#if TESTCACHE
+ if (hash != null)
+ File.WriteAllText (destination + ".hash", hash);
+#endif
+ return true;
+ }/* else
+ Console.WriteLine ("Skipping copying {0}, unchanged", Path.GetFileName (destination));*/
+
+ return false;
+ }
+
+ public static bool CopyIfZipChanged (string source, string destination)
+ {
+ string hash;
+ if (HasZipChanged (source, destination, out hash)) {
+ Directory.CreateDirectory (Path.GetDirectoryName (destination));
+
+ File.Copy (source, destination, true);
+#if TESTCACHE
+ if (hash != null)
+ File.WriteAllText (destination + ".hash", hash);
+#endif
+ return true;
+ }/* else
+ Console.WriteLine ("Skipping copying {0}, unchanged", Path.GetFileName (destination));*/
+
+ return false;
+ }
+
+ public static bool HasZipChanged (Stream source, string destination, out string hash)
+ {
+ hash = null;
+
+ string src_hash = hash = HashZip (source);
+
+ if (!File.Exists (destination))
+ return true;
+
+ string dst_hash = HashZip (destination);
+
+ if (src_hash == null || dst_hash == null)
+ return true;
+
+ return src_hash != dst_hash;
+ }
+
+ public static bool HasZipChanged (string source, string destination, out string hash)
+ {
+ hash = null;
+ if (!File.Exists (source))
+ return true;
+
+ string src_hash = hash = HashZip (source);
+
+ if (!File.Exists (destination))
+ return true;
+
+ string dst_hash = HashZip (destination);
+
+ if (src_hash == null || dst_hash == null)
+ return true;
+
+ return src_hash != dst_hash;
+ }
+
+ // This is for if the file contents have changed. Often we have to
+ // regenerate a file, but we don't want to update it if hasn't changed
+ // so that incremental build is as efficient as possible
+ public static bool HasFileChanged (string source, string destination)
+ {
+ // If either are missing, that's definitely a change
+ if (!File.Exists (source) || !File.Exists (destination))
+ return true;
+
+ var src_hash = HashFile (source);
+ var dst_hash = HashFile (destination);
+
+ // If the hashed don't match, then the file has changed
+ if (src_hash != dst_hash)
+ return true;
+
+ return false;
+ }
+
+ static string HashZip (Stream stream)
+ {
+ string hashes = String.Empty;
+
+ try {
+ var ro = new ReadOptions () {
+ Encoding = System.Text.Encoding.UTF8,
+ };
+ using (var zip = Ionic.Zip.ZipFile.Read (stream, ro)) {
+ foreach (var item in zip) {
+ hashes += String.Format ("{0}{1}", item.FileName, item.Crc);
+ }
+ }
+ } catch {
+ return null;
+ }
+ return hashes;
+ }
+
+ static string HashZip (string filename)
+ {
+ string hashes = String.Empty;
+
+ try {
+ // check cache
+ if (File.Exists (filename + ".hash"))
+ return File.ReadAllText (filename + ".hash");
+
+ using (var zip = ReadZipFile (filename)) {
+ foreach (var item in zip) {
+ hashes += String.Format ("{0}{1}", item.FileName, item.Crc);
+ }
+ }
+ } catch {
+ return null;
+ }
+ return hashes;
+ }
+
+ public static ZipFile ReadZipFile (string filename)
+ {
+ var zip = new ZipFile (new System.Text.UTF8Encoding (false));
+ zip.CaseSensitiveRetrieval = true;
+ zip.Initialize (filename);
+ return zip;
+ }
+
+ public static void ExtractAll(ZipFile zip, string destination,
+ ExtractExistingFileAction extractExitingFileAction = ExtractExistingFileAction.OverwriteSilently)
+ {
+ foreach (var entry in zip.Entries) {
+
+ if (string.Equals(entry.FileName, "__MACOSX", StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(entry.FileName, ".DS_Store", StringComparison.OrdinalIgnoreCase))
+ continue;
+ entry.Extract (destination, extractExitingFileAction);
+ }
+ }
+
+ public static string HashFile (string filename)
+ {
+ using (HashAlgorithm hashAlg = new SHA1Managed ()) {
+ return HashFile (filename, hashAlg);
+ }
+ }
+
+ public static string HashFile (string filename, HashAlgorithm hashAlg)
+ {
+ using (Stream file = new FileStream (filename, FileMode.Open, FileAccess.Read)) {
+ byte[] hash = hashAlg.ComputeHash (file);
+
+ return BitConverter.ToString (hash);
+ }
+ }
+
+ public static string HashStream (Stream stream)
+ {
+ using (HashAlgorithm hashAlg = new SHA1Managed ()) {
+ byte[] hash = hashAlg.ComputeHash (stream);
+ return BitConverter.ToString (hash);
+ }
+ }
+
+ public static void DeleteFile (string filename, object log)
+ {
+ try {
+ File.Delete (filename);
+ } catch (Exception ex) {
+#if MSBUILD
+ var helper = log as TaskLoggingHelper;
+ helper.LogErrorFromException (ex);
+#else
+ Console.Error.WriteLine (ex.ToString ());
+#endif
+ }
+ }
+ }
+}
+
diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/LinePreservedXmlWriter.cs b/src/Xamarin.Android.Build.Tasks/Utilities/LinePreservedXmlWriter.cs
new file mode 100644
index 00000000000..34769a8ef4a
--- /dev/null
+++ b/src/Xamarin.Android.Build.Tasks/Utilities/LinePreservedXmlWriter.cs
@@ -0,0 +1,144 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Xml;
+using System.Xml.XPath;
+
+namespace Monodroid
+{
+ public class LinePreservedXmlWriter : XmlTextWriter
+ {
+ LinePreservedTextWriter tw;
+
+ static LinePreservedTextWriter GetLinePreservedTextWriter (TextWriter w)
+ {
+ var tw = w as LinePreservedTextWriter;
+ if (tw == null)
+ tw = new LinePreservedTextWriter (w);
+ return tw;
+ }
+
+ public LinePreservedXmlWriter (TextWriter w)
+ : this (GetLinePreservedTextWriter (w))
+ {
+ }
+
+ internal LinePreservedXmlWriter (LinePreservedTextWriter w)
+ : base (w)
+ {
+ this.tw = w;
+ }
+
+ XPathNavigator nav;
+
+ public override void WriteNode (XPathNavigator navigator, bool defattr)
+ {
+ XPathNavigator bak = nav;
+ this.nav = navigator;
+ IXmlLineInfo li = navigator as IXmlLineInfo;
+ if (li != null)
+ tw.ProceedTo (li.LineNumber, li.LinePosition);
+ base.WriteNode (navigator, defattr);
+ this.nav = bak;
+ }
+
+ public override void WriteStartAttribute (string prefix, string localName, string namespaceUri)
+ {
+ if (nav != null)
+ Proceed (nav as IXmlLineInfo);
+ base.WriteStartAttribute (prefix, localName, namespaceUri);
+ }
+
+ public override void WriteStartElement (string prefix, string localName, string namespaceUri)
+ {
+ if (nav != null)
+ Proceed (nav as IXmlLineInfo);
+ base.WriteStartElement (prefix, localName, namespaceUri);
+ }
+
+ void Proceed (IXmlLineInfo li)
+ {
+ if (li == null || !li.HasLineInfo ())
+ return;
+ tw.ProceedTo (li.LineNumber, li.LinePosition);
+ }
+ }
+
+ class LinePreservedTextWriter : TextWriter
+ {
+ TextWriter w;
+ int line = 1;
+
+ public LinePreservedTextWriter (TextWriter w)
+ {
+ this.w = w;
+ }
+
+ public override System.Text.Encoding Encoding {
+ get { return Encoding.Unicode; }
+ }
+
+ public void ProceedTo (int line, int column)
+ {
+ if (line <= 0)
+ return;
+ bool wrote = this.line < line;
+ while (this.line < line)
+ WriteLine ();
+ if (wrote)
+ Write (new string (' ', column));
+ }
+
+ public override void Close ()
+ {
+ w.Close ();
+ }
+
+ public override void Flush ()
+ {
+ w.Flush ();
+ }
+
+ public override void Write (char value)
+ {
+ w.Write (value);
+ if (value == '\n')
+ line++;
+ }
+
+ public override void Write (char[] buffer, int index, int count)
+ {
+ w.Write (buffer, index, count);
+ int next = index;
+ while (next < index + count) {
+ int idx = Array.IndexOf (buffer, '\n', next, count + (index - next));
+ if (idx < 0)
+ break;
+ line++;
+ next = idx + 1;
+ }
+ }
+
+ public override void Write (string value)
+ {
+ w.Write (value);
+ int next = 0;
+ while (next < value.Length) {
+ int idx = value.IndexOf ('\n', next);
+ if (idx < 0)
+ break;
+ line++;
+ next = idx + 1;
+ }
+ }
+
+ public override void WriteLine ()
+ {
+ w.WriteLine ();
+ line++;
+ }
+ }
+}
+
diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/MD2Managed.cs b/src/Xamarin.Android.Build.Tasks/Utilities/MD2Managed.cs
new file mode 100644
index 00000000000..caaa7f1ed35
--- /dev/null
+++ b/src/Xamarin.Android.Build.Tasks/Utilities/MD2Managed.cs
@@ -0,0 +1,197 @@
+//
+// MD2Managed.cs - Message Digest 2 Managed Implementation
+//
+// Author:
+// Sebastien Pouliot (sebastien@ximian.com)
+//
+// (C) 2001-2003 Motus Technologies Inc. (http://www.motus.com)
+// Copyright (C) 2004-2005,2010 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;
+
+namespace Mono.Security.Cryptography {
+
+ // References:
+ // a. RFC1319: The MD2 Message-Digest Algorithm
+ // http://www.ietf.org/rfc/rfc1319.txt
+
+#if !INSIDE_CORLIB
+ public
+#endif
+ class MD2Managed : System.Security.Cryptography.HashAlgorithm {
+
+ private byte[] state;
+ private byte[] checksum;
+ private byte[] buffer;
+ private int count;
+ private byte[] x;
+
+ ///
+ /// Permutation of 0..255 constructed from the digits of pi. It gives a
+ /// "random" nonlinear byte substitution operation.
+ ///
+ private static readonly byte[] PI_SUBST = {
+ 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
+ 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
+ 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
+ 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
+ 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
+ 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
+ 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
+ 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
+ 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
+ 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
+ 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
+ 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
+ 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
+ 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
+ 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
+ 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
+ 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
+ 31, 26, 219, 153, 141, 51, 159, 17, 131, 20 };
+
+ private byte[] Padding (int nLength)
+ {
+ if (nLength > 0) {
+ byte[] padding = new byte [nLength];
+ for (int i = 0; i < padding.Length; i++)
+ padding[i] = (byte) nLength;
+ return padding;
+ }
+ return null;
+ }
+
+ //--- constructor -----------------------------------------------------------
+
+ public MD2Managed () : base ()
+ {
+ // we allocate the context memory
+ state = new byte [16];
+ checksum = new byte [16];
+ buffer = new byte [16];
+ x = new byte [48];
+ // the initialize our context
+ Initialize ();
+ }
+
+ public override void Initialize ()
+ {
+ count = 0;
+ Array.Clear (state, 0, 16);
+ Array.Clear (checksum, 0, 16);
+ Array.Clear (buffer, 0, 16);
+ // Zeroize sensitive information
+ Array.Clear (x, 0, 48);
+ }
+
+ protected override void HashCore (byte[] array, int ibStart, int cbSize)
+ {
+ int i;
+
+ /* Update number of bytes mod 16 */
+ int index = count;
+ count = (int) (index + cbSize) & 0xf;
+
+ int partLen = 16 - index;
+
+ /* Transform as many times as possible. */
+ if (cbSize >= partLen) {
+ // MD2_memcpy((POINTER)&context->buffer[index], (POINTER)input, partLen);
+ Buffer.BlockCopy (array, ibStart, buffer, index, partLen);
+ // MD2Transform (context->state, context->checksum, context->buffer);
+ MD2Transform (state, checksum, buffer, 0);
+
+ for (i = partLen; i + 15 < cbSize; i += 16) {
+ // MD2Transform (context->state, context->checksum, &input[i]);
+ MD2Transform (state, checksum, array, ibStart + i);
+ }
+
+ index = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ // MD2_memcpy((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i);
+ Buffer.BlockCopy (array, ibStart + i, buffer, index, (cbSize - i));
+ }
+
+ protected override byte[] HashFinal ()
+ {
+ // Pad out to multiple of 16.
+ int index = count;
+ int padLen = 16 - index;
+
+ // is padding needed ? required if length not a multiple of 16.
+ if (padLen > 0)
+ HashCore (Padding (padLen), 0, padLen);
+
+ // Extend with checksum
+ HashCore (checksum, 0, 16);
+
+ // Store state in digest
+ byte[] digest = (byte[]) state.Clone ();
+
+ // Zeroize sensitive information.
+ Initialize ();
+
+ return digest;
+ }
+
+ //--- private methods ---------------------------------------------------
+
+ ///
+ /// MD2 basic transformation. Transforms state and updates checksum
+ /// based on block.
+ ///
+ private void MD2Transform (byte[] state, byte[] checksum, byte[] block, int index)
+ {
+ /* Form encryption block from state, block, state ^ block. */
+ // MD2_memcpy ((POINTER)x, (POINTER)state, 16);
+ Buffer.BlockCopy (state, 0, x, 0, 16);
+ // MD2_memcpy ((POINTER)x+16, (POINTER)block, 16);
+ Buffer.BlockCopy (block, index, x, 16, 16);
+
+ // for (i = 0; i < 16; i++) x[i+32] = state[i] ^ block[i];
+ for (int i = 0; i < 16; i++)
+ x [i+32] = (byte) ((byte) state [i] ^ (byte) block [index + i]);
+
+ /* Encrypt block (18 rounds). */
+ int t = 0;
+ for (int i = 0; i < 18; i++) {
+ for (int j = 0; j < 48; j++ )
+ t = x [j] ^= PI_SUBST [t];
+ t = (t + i) & 0xff;
+ }
+
+ /* Save new state */
+ // MD2_memcpy ((POINTER)state, (POINTER)x, 16);
+ Buffer.BlockCopy (x, 0, state, 0, 16);
+
+ /* Update checksum. */
+ t = checksum [15];
+ for (int i = 0; i < 16; i++)
+ t = checksum [i] ^= PI_SUBST [block [index + i] ^ t];
+ }
+ }
+}
diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.props b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.props
new file mode 100644
index 00000000000..81ea71d5ffc
--- /dev/null
+++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.props
@@ -0,0 +1,6 @@
+
+
+ Unknown
+ <_JavaInteropReferences>Java.interop;System.Runtime
+
+