context: /**************************************************************************\
      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)
          {
  
gt:             if (url == null)