//-----------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation.
//
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
using System;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using System.Threading;
using Microsoft.Isam.Esent.Interop.Implementation;
///
/// Contains several helper functions that are useful in the test binary.
/// In particular, it contains functionality that is not available in
/// reduced-functionality environments (such as CoreClr).
///
internal static class LibraryHelpers
{
/// Provides a platform-specific character used to separate directory levels in a path string that reflects a hierarchical file system organization.
/// 1
public static readonly char DirectorySeparatorChar = '\\';
/// Provides a platform-specific alternate character used to separate directory levels in a path string that reflects a hierarchical file system organization.
/// 1
public static readonly char AltDirectorySeparatorChar = '/';
///
/// Gets an ASCII encoder.
///
public static Encoding EncodingASCII
{
get
{
#if MANAGEDESENT_ON_CORECLR
return SlowAsciiEncoding.Encoding;
#else
return Encoding.ASCII;
#endif
}
}
///
/// Gets a new ASCII encoder. It's preferred to use EncodingASCII, but some applications (e.g. tests)
/// may want a different Encoding object.
///
public static Encoding NewEncodingASCII
{
get
{
#if MANAGEDESENT_ON_CORECLR
return new SlowAsciiEncoding();
#else
return new ASCIIEncoding();
#endif
}
}
// This should be dead code when running on Core CLR; This is only called by
// GetIndexInfoFromIndexlist() when called on a pre-Win8 system, and Core CLR
// is only on Win8 anyway.
#if !MANAGEDESENT_ON_CORECLR
///
/// Creates a CultureInfo object when given the LCID.
///
///
/// The lcid passed in.
///
///
/// A CultureInfo object.
///
public static CultureInfo CreateCultureInfoByLcid(int lcid)
{
return new CultureInfo(lcid);
}
#endif // !MANAGEDESENT_ON_CORECLR
///
/// Allocates memory on the native heap.
///
/// A pointer to native memory.
/// The size of the memory desired.
public static IntPtr MarshalAllocHGlobal(int size)
{
#if MANAGEDESENT_ON_CORECLR && !MANAGEDESENT_ON_WSA
return Win32.NativeMethods.LocalAlloc(0, new UIntPtr((uint)size));
#else
return Marshal.AllocHGlobal(size);
#endif
}
///
/// Frees memory that was allocated on the native heap.
///
/// A pointer to native memory.
public static void MarshalFreeHGlobal(IntPtr buffer)
{
#if MANAGEDESENT_ON_CORECLR && !MANAGEDESENT_ON_WSA
Win32.NativeMethods.LocalFree(buffer);
#else
Marshal.FreeHGlobal(buffer);
#endif
}
/// Copies the contents of a managed into unmanaged memory.
/// The address, in unmanaged memory, to where the was copied, or 0 if is null.
/// A managed string to be copied.
/// The method could not allocate enough native heap memory.
/// The parameter exceeds the maximum length allowed by the operating system.
public static IntPtr MarshalStringToHGlobalUni(string managedString)
{
#if MANAGEDESENT_ON_CORECLR && !MANAGEDESENT_ON_WSA
return MyStringToHGlobalUni(managedString);
#else
return Marshal.StringToHGlobalUni(managedString);
#endif
}
///
/// Retrieves the managed ID of the current thread.
///
/// The ID of the current thread.
public static int GetCurrentManagedThreadId()
{
#if MANAGEDESENT_ON_CORECLR
return Environment.CurrentManagedThreadId;
#else
return Thread.CurrentThread.ManagedThreadId;
#endif
}
///
/// Cancels an requested for the current thread.
///
/// Abort was not invoked on the current thread. The caller does not have the required security permission for the current thread. 2
public static void ThreadResetAbort()
{
#if MANAGEDESENT_ON_CORECLR
// Do nothing.
#else
Thread.ResetAbort();
#endif
}
// FUTURE-2013/12/16-martinc. It appears that all of this hacking for running on Core CLR may no longer be necessary.
// We initially ported to an early version of Core CLR that had a lot of functionality missing. By the time
// Windows Store Apps came out in Windows 8, many of these functions were added back.
#if MANAGEDESENT_ON_CORECLR && !MANAGEDESENT_ON_WSA
// System.Runtime.InteropServices.Marshal
/// Copies the contents of a managed into unmanaged memory.
/// The address, in unmanaged memory, to where the was copied, or 0 if is null.
/// A managed string to be copied.
/// The method could not allocate enough native heap memory.
/// The parameter exceeds the maximum length allowed by the operating system.
[SecurityCritical]
private static unsafe IntPtr MyStringToHGlobalUni(string managedString)
{
if (managedString == null)
{
return IntPtr.Zero;
}
int charCountWithNull = managedString.Length + 1;
int byteCount = charCountWithNull * sizeof(char);
if (byteCount < managedString.Length)
{
throw new ArgumentOutOfRangeException("managedString");
}
UIntPtr sizetdwBytes = new UIntPtr((uint)byteCount);
IntPtr rawBuffer = Win32.NativeMethods.LocalAlloc(0, sizetdwBytes);
if (rawBuffer == IntPtr.Zero)
{
throw new OutOfMemoryException();
}
fixed (char* sourcePointer = managedString)
{
byte* destPointer = (byte*)rawBuffer;
var unicodeEncoding = new System.Text.UnicodeEncoding();
int bytesWritten = unicodeEncoding.GetBytes(sourcePointer, charCountWithNull, destPointer, byteCount);
}
return rawBuffer;
}
#endif // MANAGEDESENT_ON_CORECLR && !MANAGEDESENT_ON_WSA
/// Returns a equivalent to the specified OLE Automation Date.
/// A that represents the same date and time as .
/// An OLE Automation Date value.
/// The date is not a valid OLE Automation Date value.
/// 1
public static DateTime FromOADate(double d)
{
#if MANAGEDESENT_ON_CORECLR
return new DateTime(DoubleDateToTicks(d), DateTimeKind.Unspecified);
#else
return DateTime.FromOADate(d);
#endif
}
#if MANAGEDESENT_ON_CORECLR
///
/// Copied from the reflected implementation.
///
/// The date, as a 64bit integer.
/// The date, as a double representation.
internal static double TicksToOADate(long value)
{
if (value == 0L)
{
return 0.0;
}
if (value < 864000000000L)
{
value += 599264352000000000L;
}
if (value < 31241376000000000L)
{
throw new OverflowException();
}
long num = (value - 599264352000000000L) / 10000L;
if (num < 0L)
{
long num2 = num % 86400000L;
if (num2 != 0L)
{
num -= (86400000L + num2) * 2L;
}
}
return (double)num / 86400000.0;
}
///
/// Copied from the reflected implementation.
///
/// The date, as a double representation.
/// The date, as a 64bit integer.
internal static long DoubleDateToTicks(double value)
{
if (value >= 2958466.0 || value <= -657435.0)
{
throw new ArgumentException("value does not represent a valid date", "value");
}
long num = (long)((value * 86400000.0) + ((value >= 0.0) ? 0.5 : -0.5));
if (num < 0L)
{
num -= (num % 86400000L) * 2L;
}
num += 59926435200000L;
if (num < 0L || num >= 315537897600000L)
{
throw new ArgumentException("value does not represent a valid date", "value");
}
return num * 10000L;
}
#endif
}
}