| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053 |
- /*************************************************************************************
- Extended WPF Toolkit
- Copyright (C) 2007-2013 Xceed Software Inc.
- This program is provided to you under the terms of the Microsoft Public
- License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
- For more features, controls, and fast professional support,
- pick up the Plus Edition at http://xceed.com/wpf_toolkit
- Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids
- ***********************************************************************************/
- /**************************************************************************\
- Copyright Microsoft Corporation. All Rights Reserved.
- \**************************************************************************/
- // This file contains general utilities to aid in development.
- // Classes here generally shouldn't be exposed publicly since
- // they're not particular to any library functionality.
- // Because the classes here are internal, it's likely this file
- // might be included in multiple assemblies.
- namespace Standard
- {
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Diagnostics.CodeAnalysis;
- using System.Globalization;
- using System.IO;
- using System.Reflection;
- using System.Runtime.InteropServices;
- using System.Security.Cryptography;
- using System.Text;
- using System.Windows;
- using System.Windows.Media;
- using System.Windows.Media.Imaging;
- internal static partial class Utility
- {
- private static readonly Version _osVersion = Environment.OSVersion.Version;
- private static readonly Version _presentationFrameworkVersion = Assembly.GetAssembly(typeof(Window)).GetName().Version;
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- private static bool _MemCmp(IntPtr left, IntPtr right, long cb)
- {
- int offset = 0;
- for (; offset < (cb - sizeof(Int64)); offset += sizeof(Int64))
- {
- Int64 left64 = Marshal.ReadInt64(left, offset);
- Int64 right64 = Marshal.ReadInt64(right, offset);
- if (left64 != right64)
- {
- return false;
- }
- }
- for (; offset < cb; offset += sizeof(byte))
- {
- byte left8 = Marshal.ReadByte(left, offset);
- byte right8 = Marshal.ReadByte(right, offset);
- if (left8 != right8)
- {
- return false;
- }
- }
- return true;
- }
- /// <summary>The native RGB macro.</summary>
- /// <param name="c"></param>
- /// <returns></returns>
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- public static int RGB(Color c)
- {
- return c.R | (c.G << 8) | (c.B << 16);
- }
- /// <summary>Convert a native integer that represent a color with an alpha channel into a Color struct.</summary>
- /// <param name="color">The integer that represents the color. Its bits are of the format 0xAARRGGBB.</param>
- /// <returns>A Color representation of the parameter.</returns>
- public static Color ColorFromArgbDword(uint color)
- {
- return Color.FromArgb(
- (byte)((color & 0xFF000000) >> 24),
- (byte)((color & 0x00FF0000) >> 16),
- (byte)((color & 0x0000FF00) >> 8),
- (byte)((color & 0x000000FF) >> 0));
- }
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- public static int GET_X_LPARAM(IntPtr lParam)
- {
- return LOWORD(lParam.ToInt32());
- }
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- public static int GET_Y_LPARAM(IntPtr lParam)
- {
- return HIWORD(lParam.ToInt32());
- }
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- public static int HIWORD(int i)
- {
- return (short)(i >> 16);
- }
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- public static int LOWORD(int i)
- {
- return (short)(i & 0xFFFF);
- }
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
- public static bool AreStreamsEqual(Stream left, Stream right)
- {
- if (null == left)
- {
- return right == null;
- }
- if (null == right)
- {
- return false;
- }
- if (!left.CanRead || !right.CanRead)
- {
- throw new NotSupportedException("The streams can't be read for comparison");
- }
- if (left.Length != right.Length)
- {
- return false;
- }
- var length = (int)left.Length;
- // seek to beginning
- left.Position = 0;
- right.Position = 0;
- // total bytes read
- int totalReadLeft = 0;
- int totalReadRight = 0;
- // bytes read on this iteration
- int cbReadLeft = 0;
- int cbReadRight = 0;
- // where to store the read data
- var leftBuffer = new byte[512];
- var rightBuffer = new byte[512];
- // pin the left buffer
- GCHandle handleLeft = GCHandle.Alloc(leftBuffer, GCHandleType.Pinned);
- IntPtr ptrLeft = handleLeft.AddrOfPinnedObject();
- // pin the right buffer
- GCHandle handleRight = GCHandle.Alloc(rightBuffer, GCHandleType.Pinned);
- IntPtr ptrRight = handleRight.AddrOfPinnedObject();
- try
- {
- while (totalReadLeft < length)
- {
- Assert.AreEqual(totalReadLeft, totalReadRight);
- cbReadLeft = left.Read(leftBuffer, 0, leftBuffer.Length);
- cbReadRight = right.Read(rightBuffer, 0, rightBuffer.Length);
- // verify the contents are an exact match
- if (cbReadLeft != cbReadRight)
- {
- return false;
- }
- if (!_MemCmp(ptrLeft, ptrRight, cbReadLeft))
- {
- return false;
- }
- totalReadLeft += cbReadLeft;
- totalReadRight += cbReadRight;
- }
- Assert.AreEqual(cbReadLeft, cbReadRight);
- Assert.AreEqual(totalReadLeft, totalReadRight);
- Assert.AreEqual(length, totalReadLeft);
- return true;
- }
- finally
- {
- handleLeft.Free();
- handleRight.Free();
- }
- }
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- public static bool GuidTryParse(string guidString, out Guid guid)
- {
- Verify.IsNeitherNullNorEmpty(guidString, "guidString");
- try
- {
- guid = new Guid(guidString);
- return true;
- }
- catch (FormatException)
- {
- }
- catch (OverflowException)
- {
- }
- // Doesn't seem to be a valid guid.
- guid = default(Guid);
- return false;
- }
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- public static bool IsFlagSet(int value, int mask)
- {
- return 0 != (value & mask);
- }
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- public static bool IsFlagSet(uint value, uint mask)
- {
- return 0 != (value & mask);
- }
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- public static bool IsFlagSet(long value, long mask)
- {
- return 0 != (value & mask);
- }
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- public static bool IsFlagSet(ulong value, ulong mask)
- {
- return 0 != (value & mask);
- }
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- public static bool IsOSVistaOrNewer
- {
- get { return _osVersion >= new Version(6, 0); }
- }
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- public static bool IsOSWindows7OrNewer
- {
- get { return _osVersion >= new Version(6, 1); }
- }
- /// <summary>
- /// Is this using WPF4?
- /// </summary>
- /// <remarks>
- /// There are a few specific bugs in Window in 3.5SP1 and below that require workarounds
- /// when handling WM_NCCALCSIZE on the HWND.
- /// </remarks>
- public static bool IsPresentationFrameworkVersionLessThan4
- {
- get { return _presentationFrameworkVersion < new Version(4, 0); }
- }
- // Caller is responsible for destroying the HICON
- // Caller is responsible to ensure that GDI+ has been initialized.
- [SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- public static IntPtr GenerateHICON(ImageSource image, Size dimensions)
- {
- if (image == null)
- {
- return IntPtr.Zero;
- }
- // If we're getting this from a ".ico" resource, then it comes through as a BitmapFrame.
- // We can use leverage this as a shortcut to get the right 16x16 representation
- // because DrawImage doesn't do that for us.
- var bf = image as BitmapFrame;
- if (bf != null)
- {
- bf = GetBestMatch(bf.Decoder.Frames, (int)dimensions.Width, (int)dimensions.Height);
- }
- else
- {
- // Constrain the dimensions based on the aspect ratio.
- var drawingDimensions = new Rect(0, 0, dimensions.Width, dimensions.Height);
- // There's no reason to assume that the requested image dimensions are square.
- double renderRatio = dimensions.Width / dimensions.Height;
- double aspectRatio = image.Width / image.Height;
- // If it's smaller than the requested size, then place it in the middle and pad the image.
- if (image.Width <= dimensions.Width && image.Height <= dimensions.Height)
- {
- drawingDimensions = new Rect((dimensions.Width - image.Width) / 2, (dimensions.Height - image.Height) / 2, image.Width, image.Height);
- }
- else if (renderRatio > aspectRatio)
- {
- double scaledRenderWidth = (image.Width / image.Height) * dimensions.Width;
- drawingDimensions = new Rect((dimensions.Width - scaledRenderWidth) / 2, 0, scaledRenderWidth, dimensions.Height);
- }
- else if (renderRatio < aspectRatio)
- {
- double scaledRenderHeight = (image.Height / image.Width) * dimensions.Height;
- drawingDimensions = new Rect(0, (dimensions.Height - scaledRenderHeight) / 2, dimensions.Width, scaledRenderHeight);
- }
- var dv = new DrawingVisual();
- DrawingContext dc = dv.RenderOpen();
- dc.DrawImage(image, drawingDimensions);
- dc.Close();
- var bmp = new RenderTargetBitmap((int)dimensions.Width, (int)dimensions.Height, 96, 96, PixelFormats.Pbgra32);
- bmp.Render(dv);
- bf = BitmapFrame.Create(bmp);
- }
- // Using GDI+ to convert to an HICON.
- // I'd rather not duplicate their code.
- using (MemoryStream memstm = new MemoryStream())
- {
- BitmapEncoder enc = new PngBitmapEncoder();
- enc.Frames.Add(bf);
- enc.Save(memstm);
- using (var istm = new ManagedIStream(memstm))
- {
- // We are not bubbling out GDI+ errors when creating the native image fails.
- IntPtr bitmap = IntPtr.Zero;
- try
- {
- Status gpStatus = NativeMethods.GdipCreateBitmapFromStream(istm, out bitmap);
- if (Status.Ok != gpStatus)
- {
- return IntPtr.Zero;
- }
- IntPtr hicon;
- gpStatus = NativeMethods.GdipCreateHICONFromBitmap(bitmap, out hicon);
- if (Status.Ok != gpStatus)
- {
- return IntPtr.Zero;
- }
- // Caller is responsible for freeing this.
- return hicon;
- }
- finally
- {
- Utility.SafeDisposeImage(ref bitmap);
- }
- }
- }
- }
- public static BitmapFrame GetBestMatch(IList<BitmapFrame> frames, int width, int height)
- {
- return _GetBestMatch(frames, _GetBitDepth(), width, height);
- }
- private static int _MatchImage(BitmapFrame frame, int bitDepth, int width, int height, int bpp)
- {
- int score = 2 * _WeightedAbs(bpp, bitDepth, false) +
- _WeightedAbs(frame.PixelWidth, width, true) +
- _WeightedAbs(frame.PixelHeight, height, true);
- return score;
- }
- private static int _WeightedAbs(int valueHave, int valueWant, bool fPunish)
- {
- int diff = (valueHave - valueWant);
- if (diff < 0)
- {
- diff = (fPunish ? -2 : -1) * diff;
- }
- return diff;
- }
- /// From a list of BitmapFrames find the one that best matches the requested dimensions.
- /// The methods used here are copied from Win32 sources. We want to be consistent with
- /// system behaviors.
- private static BitmapFrame _GetBestMatch(IList<BitmapFrame> frames, int bitDepth, int width, int height)
- {
- int bestScore = int.MaxValue;
- int bestBpp = 0;
- int bestIndex = 0;
- bool isBitmapIconDecoder = frames[0].Decoder is IconBitmapDecoder;
- for (int i = 0; i < frames.Count && bestScore != 0; ++i)
- {
- int currentIconBitDepth = isBitmapIconDecoder ? frames[i].Thumbnail.Format.BitsPerPixel : frames[i].Format.BitsPerPixel;
- if (currentIconBitDepth == 0)
- {
- currentIconBitDepth = 8;
- }
- int score = _MatchImage(frames[i], bitDepth, width, height, currentIconBitDepth);
- if (score < bestScore)
- {
- bestIndex = i;
- bestBpp = currentIconBitDepth;
- bestScore = score;
- }
- else if (score == bestScore)
- {
- // Tie breaker: choose the higher color depth. If that fails, choose first one.
- if (bestBpp < currentIconBitDepth)
- {
- bestIndex = i;
- bestBpp = currentIconBitDepth;
- }
- }
- }
- return frames[bestIndex];
- }
- // This can be cached. It's not going to change under reasonable circumstances.
- private static int s_bitDepth; // = 0;
- private static int _GetBitDepth()
- {
- if (s_bitDepth == 0)
- {
- using (SafeDC dc = SafeDC.GetDesktop())
- {
- s_bitDepth = NativeMethods.GetDeviceCaps(dc, DeviceCap.BITSPIXEL) * NativeMethods.GetDeviceCaps(dc, DeviceCap.PLANES);
- }
- }
- return s_bitDepth;
- }
- /// <summary>
- /// Simple guard against the exceptions that File.Delete throws on null and empty strings.
- /// </summary>
- /// <param name="path">The path to delete. Unlike File.Delete, this can be null or empty.</param>
- /// <remarks>
- /// Note that File.Delete, and by extension SafeDeleteFile, does not throw an exception
- /// if the file does not exist.
- /// </remarks>
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- public static void SafeDeleteFile(string path)
- {
- if (!string.IsNullOrEmpty(path))
- {
- File.Delete(path);
- }
- }
- /// <summary>GDI's DeleteObject</summary>
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- public static void SafeDeleteObject(ref IntPtr gdiObject)
- {
- IntPtr p = gdiObject;
- gdiObject = IntPtr.Zero;
- if (IntPtr.Zero != p)
- {
- NativeMethods.DeleteObject(p);
- }
- }
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- public static void SafeDestroyIcon(ref IntPtr hicon)
- {
- IntPtr p = hicon;
- hicon = IntPtr.Zero;
- if (IntPtr.Zero != p)
- {
- NativeMethods.DestroyIcon(p);
- }
- }
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- public static void SafeDestroyWindow(ref IntPtr hwnd)
- {
- IntPtr p = hwnd;
- hwnd = IntPtr.Zero;
- if (NativeMethods.IsWindow(p))
- {
- NativeMethods.DestroyWindow(p);
- }
- }
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- public static void SafeDispose<T>(ref T disposable) where T : IDisposable
- {
- // Dispose can safely be called on an object multiple times.
- IDisposable t = disposable;
- disposable = default(T);
- if (null != t)
- {
- t.Dispose();
- }
- }
- /// <summary>GDI+'s DisposeImage</summary>
- /// <param name="gdipImage"></param>
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- public static void SafeDisposeImage(ref IntPtr gdipImage)
- {
- IntPtr p = gdipImage;
- gdipImage = IntPtr.Zero;
- if (IntPtr.Zero != p)
- {
- NativeMethods.GdipDisposeImage(p);
- }
- }
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
- public static void SafeCoTaskMemFree(ref IntPtr ptr)
- {
- IntPtr p = ptr;
- ptr = IntPtr.Zero;
- if (IntPtr.Zero != p)
- {
- Marshal.FreeCoTaskMem(p);
- }
- }
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
- public static void SafeFreeHGlobal(ref IntPtr hglobal)
- {
- IntPtr p = hglobal;
- hglobal = IntPtr.Zero;
- if (IntPtr.Zero != p)
- {
- Marshal.FreeHGlobal(p);
- }
- }
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
- public static void SafeRelease<T>(ref T comObject) where T : class
- {
- T t = comObject;
- comObject = default(T);
- if (null != t)
- {
- Assert.IsTrue(Marshal.IsComObject(t));
- Marshal.ReleaseComObject(t);
- }
- }
- /// <summary>
- /// Utility to help classes catenate their properties for implementing ToString().
- /// </summary>
- /// <param name="source">The StringBuilder to catenate the results into.</param>
- /// <param name="propertyName">The name of the property to be catenated.</param>
- /// <param name="value">The value of the property to be catenated.</param>
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- public static void GeneratePropertyString(StringBuilder source, string propertyName, string value)
- {
- Assert.IsNotNull(source);
- Assert.IsFalse(string.IsNullOrEmpty(propertyName));
- if (0 != source.Length)
- {
- source.Append(' ');
- }
- source.Append(propertyName);
- source.Append(": ");
- if (string.IsNullOrEmpty(value))
- {
- source.Append("<null>");
- }
- else
- {
- source.Append('\"');
- source.Append(value);
- source.Append('\"');
- }
- }
- /// <summary>
- /// Generates ToString functionality for a struct. This is an expensive way to do it,
- /// it exists for the sake of debugging while classes are in flux.
- /// Eventually this should just be removed and the classes should
- /// do this without reflection.
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="object"></param>
- /// <returns></returns>
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- [Obsolete]
- public static string GenerateToString<T>(T @object) where T : struct
- {
- var sbRet = new StringBuilder();
- foreach (PropertyInfo property in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance))
- {
- if (0 != sbRet.Length)
- {
- sbRet.Append(", ");
- }
- Assert.AreEqual(0, property.GetIndexParameters().Length);
- object value = property.GetValue(@object, null);
- string format = null == value ? "{0}: <null>" : "{0}: \"{1}\"";
- sbRet.AppendFormat(format, property.Name, value);
- }
- return sbRet.ToString();
- }
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- public static void CopyStream(Stream destination, Stream source)
- {
- Assert.IsNotNull(source);
- Assert.IsNotNull(destination);
- destination.Position = 0;
- // If we're copying from, say, a web stream, don't fail because of this.
- if (source.CanSeek)
- {
- source.Position = 0;
- // Consider that this could throw because
- // the source stream doesn't know it's size...
- destination.SetLength(source.Length);
- }
- var buffer = new byte[4096];
- int cbRead;
- do
- {
- cbRead = source.Read(buffer, 0, buffer.Length);
- if (0 != cbRead)
- {
- destination.Write(buffer, 0, cbRead);
- }
- }
- while (buffer.Length == cbRead);
- // Reset the Seek pointer before returning.
- destination.Position = 0;
- }
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- public static string HashStreamMD5(Stream stm)
- {
- stm.Position = 0;
- var hashBuilder = new StringBuilder();
- using (MD5 md5 = MD5.Create())
- {
- foreach (byte b in md5.ComputeHash(stm))
- {
- hashBuilder.Append(b.ToString("x2", CultureInfo.InvariantCulture));
- }
- }
- return hashBuilder.ToString();
- }
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- public static void EnsureDirectory(string path)
- {
- if (!Directory.Exists(Path.GetDirectoryName(path)))
- {
- Directory.CreateDirectory(Path.GetDirectoryName(path));
- }
- }
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- public static bool MemCmp(byte[] left, byte[] right, int cb)
- {
- Assert.IsNotNull(left);
- Assert.IsNotNull(right);
- Assert.IsTrue(cb <= Math.Min(left.Length, right.Length));
- // pin this buffer
- GCHandle handleLeft = GCHandle.Alloc(left, GCHandleType.Pinned);
- IntPtr ptrLeft = handleLeft.AddrOfPinnedObject();
- // pin the other buffer
- GCHandle handleRight = GCHandle.Alloc(right, GCHandleType.Pinned);
- IntPtr ptrRight = handleRight.AddrOfPinnedObject();
- bool fRet = _MemCmp(ptrLeft, ptrRight, cb);
- handleLeft.Free();
- handleRight.Free();
- return fRet;
- }
- private class _UrlDecoder
- {
- private readonly Encoding _encoding;
- private readonly char[] _charBuffer;
- private readonly byte[] _byteBuffer;
- private int _byteCount;
- private int _charCount;
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- public _UrlDecoder(int size, Encoding encoding)
- {
- _encoding = encoding;
- _charBuffer = new char[size];
- _byteBuffer = new byte[size];
- }
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- public void AddByte(byte b)
- {
- _byteBuffer[_byteCount++] = b;
- }
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- public void AddChar(char ch)
- {
- _FlushBytes();
- _charBuffer[_charCount++] = ch;
- }
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- private void _FlushBytes()
- {
- if (_byteCount > 0)
- {
- _charCount += _encoding.GetChars(_byteBuffer, 0, _byteCount, _charBuffer, _charCount);
- _byteCount = 0;
- }
- }
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- public string GetString()
- {
- _FlushBytes();
- if (_charCount > 0)
- {
- return new string(_charBuffer, 0, _charCount);
- }
- return "";
- }
- }
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- public static string UrlDecode(string url)
- {
- if (url == null)
- {
- return null;
- }
- var decoder = new _UrlDecoder(url.Length, Encoding.UTF8);
- int length = url.Length;
- for (int i = 0; i < length; ++i)
- {
- char ch = url[i];
- if (ch == '+')
- {
- decoder.AddByte((byte)' ');
- continue;
- }
- if (ch == '%' && i < length - 2)
- {
- // decode %uXXXX into a Unicode character.
- if (url[i + 1] == 'u' && i < length - 5)
- {
- int a = _HexToInt(url[i + 2]);
- int b = _HexToInt(url[i + 3]);
- int c = _HexToInt(url[i + 4]);
- int d = _HexToInt(url[i + 5]);
- if (a >= 0 && b >= 0 && c >= 0 && d >= 0)
- {
- decoder.AddChar((char)((a << 12) | (b << 8) | (c << 4) | d));
- i += 5;
- continue;
- }
- }
- else
- {
- // decode %XX into a Unicode character.
- int a = _HexToInt(url[i + 1]);
- int b = _HexToInt(url[i + 2]);
- if (a >= 0 && b >= 0)
- {
- decoder.AddByte((byte)((a << 4) | b));
- i += 2;
- continue;
- }
- }
- }
- // Add any 7bit character as a byte.
- if ((ch & 0xFF80) == 0)
- {
- decoder.AddByte((byte)ch);
- }
- else
- {
- decoder.AddChar(ch);
- }
- }
- return decoder.GetString();
- }
- /// <summary>
- /// Encodes a URL string. Duplicated functionality from System.Web.HttpUtility.UrlEncode.
- /// </summary>
- /// <param name="url"></param>
- /// <returns></returns>
- /// <remarks>
- /// Duplicated from System.Web.HttpUtility because System.Web isn't part of the client profile.
- /// URL Encoding replaces ' ' with '+' and unsafe ASCII characters with '%XX'.
- /// Safe characters are defined in RFC2396 (http://www.ietf.org/rfc/rfc2396.txt).
- /// They are the 7-bit ASCII alphanumerics and the mark characters "-_.!~*'()".
- /// This implementation does not treat '~' as a safe character to be consistent with the System.Web version.
- /// </remarks>
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- public static string UrlEncode(string url)
- {
- if (url == null)
- {
- return null;
- }
- byte[] bytes = Encoding.UTF8.GetBytes(url);
- bool needsEncoding = false;
- int unsafeCharCount = 0;
- foreach (byte b in bytes)
- {
- if (b == ' ')
- {
- needsEncoding = true;
- }
- else if (!_UrlEncodeIsSafe(b))
- {
- ++unsafeCharCount;
- needsEncoding = true;
- }
- }
- if (needsEncoding)
- {
- var buffer = new byte[bytes.Length + (unsafeCharCount * 2)];
- int writeIndex = 0;
- foreach (byte b in bytes)
- {
- if (_UrlEncodeIsSafe(b))
- {
- buffer[writeIndex++] = b;
- }
- else if (b == ' ')
- {
- buffer[writeIndex++] = (byte)'+';
- }
- else
- {
- buffer[writeIndex++] = (byte)'%';
- buffer[writeIndex++] = _IntToHex((b >> 4) & 0xF);
- buffer[writeIndex++] = _IntToHex(b & 0xF);
- }
- }
- bytes = buffer;
- Assert.AreEqual(buffer.Length, writeIndex);
- }
- return Encoding.ASCII.GetString(bytes);
- }
- // HttpUtility's UrlEncode is slightly different from the RFC.
- // RFC2396 describes unreserved characters as alphanumeric or
- // the list "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
- // The System.Web version unnecessarily escapes '~', which should be okay...
- // Keeping that same pattern here just to be consistent.
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- private static bool _UrlEncodeIsSafe(byte b)
- {
- if (_IsAsciiAlphaNumeric(b))
- {
- return true;
- }
- switch ((char)b)
- {
- case '-':
- case '_':
- case '.':
- case '!':
- //case '~':
- case '*':
- case '\'':
- case '(':
- case ')':
- return true;
- }
- return false;
- }
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- private static bool _IsAsciiAlphaNumeric(byte b)
- {
- return (b >= 'a' && b <= 'z')
- || (b >= 'A' && b <= 'Z')
- || (b >= '0' && b <= '9');
- }
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- private static byte _IntToHex(int n)
- {
- Assert.BoundedInteger(0, n, 16);
- if (n <= 9)
- {
- return (byte)(n + '0');
- }
- return (byte)(n - 10 + 'A');
- }
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- private static int _HexToInt(char h)
- {
- if (h >= '0' && h <= '9')
- {
- return h - '0';
- }
- if (h >= 'a' && h <= 'f')
- {
- return h - 'a' + 10;
- }
- if (h >= 'A' && h <= 'F')
- {
- return h - 'A' + 10;
- }
- Assert.Fail("Invalid hex character " + h);
- return -1;
- }
- public static void AddDependencyPropertyChangeListener(object component, DependencyProperty property, EventHandler listener)
- {
- if (component == null)
- {
- return;
- }
- Assert.IsNotNull(property);
- Assert.IsNotNull(listener);
- DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(property, component.GetType());
- dpd.AddValueChanged(component, listener);
- }
- public static void RemoveDependencyPropertyChangeListener(object component, DependencyProperty property, EventHandler listener)
- {
- if (component == null)
- {
- return;
- }
- Assert.IsNotNull(property);
- Assert.IsNotNull(listener);
- DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(property, component.GetType());
- dpd.RemoveValueChanged(component, listener);
- }
- #region Extension Methods
- public static bool IsThicknessNonNegative(Thickness thickness)
- {
- if (!IsDoubleFiniteAndNonNegative(thickness.Top))
- {
- return false;
- }
- if (!IsDoubleFiniteAndNonNegative(thickness.Left))
- {
- return false;
- }
- if (!IsDoubleFiniteAndNonNegative(thickness.Bottom))
- {
- return false;
- }
- if (!IsDoubleFiniteAndNonNegative(thickness.Right))
- {
- return false;
- }
- return true;
- }
- public static bool IsCornerRadiusValid(CornerRadius cornerRadius)
- {
- if (!IsDoubleFiniteAndNonNegative(cornerRadius.TopLeft))
- {
- return false;
- }
- if (!IsDoubleFiniteAndNonNegative(cornerRadius.TopRight))
- {
- return false;
- }
- if (!IsDoubleFiniteAndNonNegative(cornerRadius.BottomLeft))
- {
- return false;
- }
- if (!IsDoubleFiniteAndNonNegative(cornerRadius.BottomRight))
- {
- return false;
- }
- return true;
- }
- public static bool IsDoubleFiniteAndNonNegative(double d)
- {
- if (double.IsNaN(d) || double.IsInfinity(d) || d < 0)
- {
- return false;
- }
- return true;
- }
- #endregion
- }
- }
|