DSInternals/Src/Microsoft.Database.Isam/converter.cs

294 lines
12 KiB
C#

// ---------------------------------------------------------------------------
// <copyright file="converter.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------
// <summary>
// </summary>
// ---------------------------------------------------------------------
namespace Microsoft.Database.Isam
{
using System;
using System.Globalization;
using System.Text;
using Microsoft.Isam.Esent.Interop;
using Microsoft.Isam.Esent.Interop.Vista;
/// <summary>
/// Convert an array of Bytes to/from a CLR object, given the type of the underlying column
/// </summary>
/// <remarks>
/// The Interop layer operates with Byte arrays. The Converter class provides methods to convert
/// an array of bytes retrieved from the Interop layer into a CLR object and to convert a CLR
/// object into an array of bytes.
/// </remarks>
internal class Converter
{
/// <summary>
/// Given a column type and an object, convert the object to an array of bytes
/// </summary>
/// <remarks>
/// This method uses System.Convert and System.BitConverter to do automatic type conversion (e.g. String -> Boolean)
/// </remarks>
/// <param name="type">The type of the database column that this object is to be stored in</param>
/// <param name="isASCII">For text columns, is the column an ASCII column. Ignored for other types</param>
/// <param name="o">The object to be converted</param>
/// <returns>An array of bytes representing the object</returns>
/// <exception cref="InvalidCastException">This conversion is not supported</exception>
/// <exception cref="ArgumentOutOfRangeException">Unknown column type</exception>
public static byte[] BytesFromObject(JET_coltyp type, bool isASCII, object o)
{
if (o is DBNull)
{
return null;
}
if (null == o)
{
return null;
}
switch (type)
{
case JET_coltyp.Nil:
throw new ArgumentOutOfRangeException("type", "Nil is not valid");
case JET_coltyp.Bit:
return BitConverter.GetBytes(Convert.ToBoolean(o));
case JET_coltyp.UnsignedByte:
byte[] bytes = new byte[1];
bytes[0] = (byte)o;
return bytes;
case JET_coltyp.Short:
return BitConverter.GetBytes(Convert.ToInt16(o));
case JET_coltyp.Long:
return BitConverter.GetBytes(Convert.ToInt32(o));
case VistaColtyp.LongLong:
return BitConverter.GetBytes(Convert.ToInt64(o));
case JET_coltyp.Currency:
return BitConverter.GetBytes(Convert.ToInt64(o));
case JET_coltyp.IEEESingle:
return BitConverter.GetBytes(Convert.ToSingle(o));
case JET_coltyp.IEEEDouble:
return BitConverter.GetBytes(Convert.ToDouble(o));
case VistaColtyp.UnsignedShort:
return BitConverter.GetBytes(Convert.ToUInt16(o));
case VistaColtyp.UnsignedLong:
return BitConverter.GetBytes(Convert.ToUInt32(o));
case JET_coltyp.Binary:
return (byte[])o;
case JET_coltyp.LongBinary:
return (byte[])o;
case JET_coltyp.DateTime:
// Internally DateTime is stored as a double, mapping to a COLEDateTime
DateTime datetime = Convert.ToDateTime(o);
double oleDateTime = datetime.ToOADate();
return BitConverter.GetBytes(oleDateTime);
case JET_coltyp.Text:
if (isASCII)
{
return Encoding.ASCII.GetBytes(o.ToString());
}
else
{
return Encoding.Unicode.GetBytes(o.ToString());
}
case JET_coltyp.LongText:
if (isASCII)
{
return Encoding.ASCII.GetBytes(o.ToString());
}
else
{
return Encoding.Unicode.GetBytes(o.ToString());
}
case VistaColtyp.GUID:
if (o is string)
{
Guid guid = new Guid((string)o);
return guid.ToByteArray();
}
else if (o is byte[])
{
Guid guid = new Guid((byte[])o);
return guid.ToByteArray();
}
else
{
// if o isn't a Guid, this will throw an exception
return ((Guid)o).ToByteArray();
}
default:
throw new ArgumentOutOfRangeException("type", "unknown type");
}
}
/// <summary>
/// Given a column type and a Byte array, convert the bytes into a CLR object
/// </summary>
/// <remarks>
/// This method uses System.BitConverter to do the conversion
/// </remarks>
/// <param name="type">The type of the database column that this bytes were retrieved from</param>
/// <param name="isASCII">For text columns, is the column an ASCII column. Ignored for other types</param>
/// <param name="value">The bytes to be converted</param>
/// <returns>An Object constructed from the bytes or DBNull for a null value</returns>
/// <exception cref="ArgumentOutOfRangeException">Unknown column type or incorrect Byte array size</exception>
public static object ObjectFromBytes(JET_coltyp type, bool isASCII, byte[] value)
{
if (null == value)
{
return DBNull.Value;
}
switch (type)
{
case JET_coltyp.Nil:
throw new ArgumentOutOfRangeException("type", "Nil is not valid");
case JET_coltyp.Bit:
return BitConverter.ToBoolean(value, 0);
case JET_coltyp.UnsignedByte:
return value[0];
case JET_coltyp.Short:
return BitConverter.ToInt16(value, 0);
case JET_coltyp.Long:
return BitConverter.ToInt32(value, 0);
case VistaColtyp.LongLong:
return BitConverter.ToInt64(value, 0);
case JET_coltyp.Currency:
return BitConverter.ToInt64(value, 0);
case JET_coltyp.IEEESingle:
return BitConverter.ToSingle(value, 0);
case JET_coltyp.IEEEDouble:
return BitConverter.ToDouble(value, 0);
case VistaColtyp.UnsignedShort:
return BitConverter.ToUInt16(value, 0);
case VistaColtyp.UnsignedLong:
return BitConverter.ToUInt32(value, 0);
case JET_coltyp.Binary:
return value;
case JET_coltyp.LongBinary:
return value;
case JET_coltyp.Text:
if (isASCII)
{
return new string(Encoding.ASCII.GetChars(value));
}
else
{
return new string(Encoding.Unicode.GetChars(value));
}
case JET_coltyp.LongText:
if (isASCII)
{
return new string(Encoding.ASCII.GetChars(value));
}
else
{
return new string(Encoding.Unicode.GetChars(value));
}
case VistaColtyp.GUID:
return new Guid(value);
case JET_coltyp.DateTime:
// Internally DateTime is stored as a double, mapping to a COLEDateTime
return DateTime.FromOADate(BitConverter.ToDouble(value, 0));
default:
throw new ArgumentOutOfRangeException("type", "unknown type");
}
}
/// <summary>
/// Converts from <see cref="CompareOptions"/> to <see cref="UnicodeIndexFlags"/>.
/// </summary>
/// <param name="options">The value to convert.</param>
/// <returns>A <see cref="UnicodeIndexFlags"/> value equivalent to <paramref name="options"/>.</returns>
/// <exception cref="System.ArgumentException">CompareOptions.Ordinal is not supported;compareOptions</exception>
internal static UnicodeIndexFlags UnicodeFlagsFromCompareOptions(CompareOptions options)
{
UnicodeIndexFlags unicodeflags = UnicodeIndexFlags.None;
if (IsCompareOptionSet(options, CompareOptions.IgnoreCase))
{
unicodeflags |= UnicodeIndexFlags.CaseInsensitive;
}
if (IsCompareOptionSet(options, CompareOptions.IgnoreKanaType))
{
unicodeflags |= UnicodeIndexFlags.KanaInsensitive;
}
if (IsCompareOptionSet(options, CompareOptions.IgnoreNonSpace))
{
unicodeflags |= UnicodeIndexFlags.AccentInsensitive;
}
if (IsCompareOptionSet(options, CompareOptions.IgnoreSymbols))
{
unicodeflags |= UnicodeIndexFlags.IgnoreSymbols;
}
if (IsCompareOptionSet(options, CompareOptions.IgnoreWidth))
{
unicodeflags |= UnicodeIndexFlags.WidthInsensitive;
}
if (IsCompareOptionSet(options, CompareOptions.StringSort))
{
unicodeflags |= UnicodeIndexFlags.StringSort;
}
if (IsCompareOptionSet(options, CompareOptions.Ordinal))
{
throw new ArgumentException("CompareOptions.Ordinal is not supported", "compareOptions");
}
return unicodeflags;
}
/// <summary>
/// Converts unicodeIndexFlags to a ulong, suitable for dwMapFlags.
/// </summary>
/// <param name="unicodeIndexFlags">A UnicodeIndexFlags value.</param>
/// <returns>A value suitable for calling by LCMapString.</returns>
internal static uint MapFlagsFromUnicodeIndexFlags(UnicodeIndexFlags unicodeIndexFlags)
{
return (uint)unicodeIndexFlags;
}
/// <summary>
/// Converts <see cref="ColumnFlags"/> to a <see cref="ColumndefGrbit"/>, suitable for ESE function calls.
/// </summary>
/// <param name="columnFlags">A <see cref="ColumnFlags"/> value.</param>
/// <returns>A ColumndefGrbit suitable for function calls.</returns>
internal static ColumndefGrbit ColumndefGrbitFromColumnFlags(ColumnFlags columnFlags)
{
return (ColumndefGrbit)columnFlags;
}
/// <summary>
/// Determines whether all of the the specified options in <paramref name="optionsMask"/>
/// are set in <paramref name="optionsToTest"/>.
/// </summary>
/// <param name="optionsToTest">The value to test.</param>
/// <param name="optionsMask">The optionsMask.</param>
/// <returns>
/// Whether all of the the specified options in <paramref name="optionsMask"/>
/// </returns>
private static bool IsCompareOptionSet(CompareOptions optionsToTest, CompareOptions optionsMask)
{
if ((optionsToTest & optionsMask) == optionsMask)
{
return true;
}
return false;
}
}
}