diff --git a/Ooui.Forms/DisplayAlert.cs b/Ooui.Forms/DisplayAlert.cs index fae811a..0770cfa 100644 --- a/Ooui.Forms/DisplayAlert.cs +++ b/Ooui.Forms/DisplayAlert.cs @@ -1,4 +1,4 @@ -using System.Web; +using System; using Xamarin.Forms.Internals; namespace Ooui.Forms @@ -31,7 +31,7 @@ namespace Ooui.Forms ClassName = "close" }; - _closeButton.AppendChild(new Span(HttpUtility.HtmlDecode("×"))); + _closeButton.AppendChild(new Span("×")); var h4 = new Heading(4) { diff --git a/Ooui.Forms/Forms.cs b/Ooui.Forms/Forms.cs index c648cfa..e8e22e9 100644 --- a/Ooui.Forms/Forms.cs +++ b/Ooui.Forms/Forms.cs @@ -21,7 +21,7 @@ namespace Xamarin.Forms return; IsInitialized = true; - Log.Listeners.Add (new DelegateLogListener ((c, m) => Trace.WriteLine (m, c))); + Log.Listeners.Add (new DelegateLogListener ((c, m) => System.Diagnostics.Debug.WriteLine (m, c))); Device.SetIdiom (TargetIdiom.Desktop); Device.PlatformServices = new OouiPlatformServices (); @@ -64,7 +64,11 @@ namespace Xamarin.Forms public Assembly[] GetAssemblies () { +#if PCL + return new[] { typeof (Xamarin.Forms.View).GetTypeInfo ().Assembly, typeof (Forms.OouiPlatformServices).GetTypeInfo ().Assembly }; +#else return AppDomain.CurrentDomain.GetAssemblies (); +#endif } public string GetMD5Hash (string input) @@ -140,6 +144,31 @@ namespace Xamarin.Forms } } +#if PCL + + public delegate void TimerCallback(object state); + + public sealed class Timer : CancellationTokenSource, IDisposable + { + public Timer (TimerCallback callback, object state, int dueTime, int period) + { + Task.Run (async () => { + await Task.Delay (dueTime).ConfigureAwait (false); + if (!IsCancellationRequested) + callback (state); + while (!IsCancellationRequested) { + await Task.Delay (period).ConfigureAwait (false); + if (!IsCancellationRequested) + callback (state); + } + }); + } + + public new void Dispose() { base.Cancel(); } + } + +#endif + public void QuitApplication() { } diff --git a/Ooui.Forms/Ooui.Forms.csproj b/Ooui.Forms/Ooui.Forms.csproj index 440e8f2..b439ba6 100644 --- a/Ooui.Forms/Ooui.Forms.csproj +++ b/Ooui.Forms/Ooui.Forms.csproj @@ -9,16 +9,14 @@ https://github.com/praeclarum/Ooui https://github.com/praeclarum/Ooui/blob/master/LICENSE https://github.com/praeclarum/Ooui.git - netstandard2.0 + netstandard2.0;netstandard1.0 + true - - true - - - - true + + PCL + diff --git a/Ooui.Forms/PageExtensions.cs b/Ooui.Forms/PageExtensions.cs index 4ffe01d..b2174cb 100644 --- a/Ooui.Forms/PageExtensions.cs +++ b/Ooui.Forms/PageExtensions.cs @@ -5,6 +5,7 @@ namespace Xamarin.Forms { public static class PageExtensions { +#if !PCL public static void Publish (this Xamarin.Forms.Page page, string path) { Ooui.UI.Publish (path, () => page.CreateElement ()); @@ -15,6 +16,7 @@ namespace Xamarin.Forms var lazyPage = new Lazy ((() => page.CreateElement ()), true); Ooui.UI.Publish (path, () => lazyPage.Value); } +#endif public static Ooui.Element GetOouiElement (this Xamarin.Forms.Page page) { diff --git a/Ooui.Forms/Platform.cs b/Ooui.Forms/Platform.cs index 96197cb..635fe97 100644 --- a/Ooui.Forms/Platform.cs +++ b/Ooui.Forms/Platform.cs @@ -4,7 +4,6 @@ using System.Threading.Tasks; using Ooui.Forms.Renderers; using Xamarin.Forms; using Xamarin.Forms.Internals; -using System.Web; namespace Ooui.Forms { @@ -142,7 +141,7 @@ namespace Ooui.Forms void AddChild (VisualElement view) { if (!Application.IsApplicationOrNull (view.RealParent)) - Console.Error.WriteLine ("Tried to add parented view to canvas directly"); + System.Diagnostics.Debug.WriteLine ("Tried to add parented view to canvas directly"); if (GetRenderer (view) == null) { var viewRenderer = CreateRenderer (view); @@ -152,7 +151,7 @@ namespace Ooui.Forms viewRenderer.SetElementSize (new Size (640, 480)); } else - Console.Error.WriteLine ("Potential view double add"); + System.Diagnostics.Debug.WriteLine ("Potential view double add"); } void HandleRendererStyle_PropertyChanged (object sender, System.ComponentModel.PropertyChangedEventArgs e) diff --git a/Ooui.Forms/Renderers/ImageRenderer.cs b/Ooui.Forms/Renderers/ImageRenderer.cs index 3f9e6e2..7b429bc 100644 --- a/Ooui.Forms/Renderers/ImageRenderer.cs +++ b/Ooui.Forms/Renderers/ImageRenderer.cs @@ -139,8 +139,12 @@ namespace Ooui.Forms.Renderers public sealed class FileImageSourceHandler : IImageSourceHandler { +#pragma warning disable 1998 public async Task LoadImageAsync (ImageSource imagesource, CancellationToken cancelationToken = default (CancellationToken), float scale = 1f) { +#if PCL + return null; +#else string image = null; var filesource = imagesource as FileImageSource; var file = filesource?.File; @@ -155,6 +159,7 @@ namespace Ooui.Forms.Renderers } } return image; +#endif } } @@ -162,6 +167,9 @@ namespace Ooui.Forms.Renderers { public async Task LoadImageAsync (ImageSource imagesource, CancellationToken cancelationToken = default (CancellationToken), float scale = 1f) { +#if PCL + return null; +#else string image = null; var streamsource = imagesource as StreamImageSource; if (streamsource?.Stream != null) { @@ -171,7 +179,7 @@ namespace Ooui.Forms.Renderers using (var outputStream = new System.IO.MemoryStream (data)) { await streamImage.CopyToAsync (outputStream, 4096, cancelationToken).ConfigureAwait (false); } - var hash = Ooui.UI.Hash (data); + var hash = Ooui.Utilities.Hash (data); var etag = "\"" + hash + "\""; image = "/images/" + hash; if (Ooui.UI.TryGetFileContentAtPath (image, out var file) && file.Etag == etag) { @@ -188,6 +196,7 @@ namespace Ooui.Forms.Renderers System.Diagnostics.Debug.WriteLine ("Could not load image: {0}", streamsource); } return image; +#endif } } diff --git a/Ooui.Forms/ResourcesProvider.cs b/Ooui.Forms/ResourcesProvider.cs index c0c05a3..c71be52 100644 --- a/Ooui.Forms/ResourcesProvider.cs +++ b/Ooui.Forms/ResourcesProvider.cs @@ -40,3 +40,12 @@ namespace Ooui.Forms } } } + +#if PCL +namespace System.Collections.Concurrent +{ + class ConcurrentDictionary : Dictionary + { + } +} +#endif diff --git a/Ooui.Wasm/ooui-sample.html b/Ooui.Wasm/ooui-sample.html index cfb1dfb..f47470c 100644 --- a/Ooui.Wasm/ooui-sample.html +++ b/Ooui.Wasm/ooui-sample.html @@ -44,6 +44,9 @@ "System.Xml.dll", "System.Xml.ReaderWriter.dll", "System.Xml.XDocument.dll", + "Xamarin.Forms.Core.dll", + "Xamarin.Forms.Platform.dll", + "Xamarin.Forms.Xaml.dll", "Ooui.dll", mainAsmName + ".dll" ]; diff --git a/Ooui/UI.cs b/Ooui/UI.cs index 893ef63..dc87fa9 100644 --- a/Ooui/UI.cs +++ b/Ooui/UI.cs @@ -14,10 +14,8 @@ namespace Ooui public const int MaxFps = 30; #if !PCL - static readonly ManualResetEvent started = new ManualResetEvent (false); - [ThreadStatic] - static System.Security.Cryptography.SHA256 sha256; + static readonly ManualResetEvent started = new ManualResetEvent (false); static CancellationTokenSource serverCts; @@ -82,22 +80,7 @@ namespace Ooui clientJsBytes = Encoding.UTF8.GetBytes (r.ReadToEnd ()); } } - clientJsEtag = "\"" + Hash (clientJsBytes) + "\""; - } - - public static string Hash (byte[] bytes) - { - var sha = sha256; - if (sha == null) { - sha = System.Security.Cryptography.SHA256.Create (); - sha256 = sha; - } - var data = sha.ComputeHash (bytes); - StringBuilder sBuilder = new StringBuilder (); - for (int i = 0; i < data.Length; i++) { - sBuilder.Append (data[i].ToString ("x2")); - } - return sBuilder.ToString (); + clientJsEtag = "\"" + Utilities.Hash (clientJsBytes) + "\""; } static void Publish (string path, RequestHandler handler) @@ -129,13 +112,13 @@ namespace Ooui if (contentType == null) { contentType = GuessContentType (path, filePath); } - var etag = "\"" + Hash (data) + "\""; + var etag = "\"" + Utilities.Hash (data) + "\""; Publish (path, new DataHandler (data, etag, contentType)); } public static void PublishFile (string path, byte[] data, string contentType) { - var etag = "\"" + Hash (data) + "\""; + var etag = "\"" + Utilities.Hash (data) + "\""; Publish (path, new DataHandler (data, etag, contentType)); } @@ -180,7 +163,7 @@ namespace Ooui public static void PublishJson (string path, object value) { var data = JsonHandler.GetData (value); - var etag = "\"" + Hash (data) + "\""; + var etag = "\"" + Utilities.Hash (data) + "\""; Publish (path, new DataHandler (data, etag, JsonHandler.ContentType)); } @@ -379,13 +362,18 @@ namespace Ooui } } + static string EscapeHtml (string text) + { + return text.Replace ("&", "&").Replace ("<", "<"); + } + public static void RenderTemplate (TextWriter writer, string webSocketPath, string title, string initialHtml) { writer.Write (@" "); - writer.Write (title.Replace ("&", "&").Replace ("<", "<")); + writer.Write (EscapeHtml (title)); writer.Write (@" "); diff --git a/Ooui/Utilities.cs b/Ooui/Utilities.cs new file mode 100644 index 0000000..a850099 --- /dev/null +++ b/Ooui/Utilities.cs @@ -0,0 +1,69 @@ +using System; +using System.Text; + +namespace Ooui +{ + public static class Utilities + { +#if PCL + + static readonly uint[] crcTable; + + static Utilities () + { + uint p = 0x04C11DB7; + crcTable = new uint[256]; + for (uint c = 0; c <= 0xFF; c++) { + crcTable[c] = CrcReflect (c, 8) << 24; + for (uint i = 0; i < 8; i++) { + crcTable[c] = (crcTable[c] << 1) ^ (((crcTable[c] & (1u << 31)) != 0) ? p : 0); + } + crcTable[c] = CrcReflect (crcTable[c], 32); + } + } + + static uint CrcReflect (uint r, byte c) + { + uint v = 0; + for (int i = 1; i < (c + 1); i++) { + if ((r & 1) != 0) { + v |= (1u << (c - i)); + } + r >>= 1; + } + return v; + } + + public static string Hash (byte[] bytes) + { + uint crc = 0xffffffffu; + for (var i = 0; i < bytes.Length; i++) { + crc = (crc >> 8) ^ crcTable[(crc & 0xff) ^ bytes[i]]; + } + crc ^= 0xffffffffu; + return crc.ToString ("x8"); + } + +#else + + [ThreadStatic] + static System.Security.Cryptography.SHA256 sha256; + + public static string Hash (byte[] bytes) + { + var sha = sha256; + if (sha == null) { + sha = System.Security.Cryptography.SHA256.Create (); + sha256 = sha; + } + var data = sha.ComputeHash (bytes); + StringBuilder sBuilder = new StringBuilder (); + for (int i = 0; i < data.Length; i++) { + sBuilder.Append (data[i].ToString ("x2")); + } + return sBuilder.ToString (); + } + +#endif + } +}