context: /********************************************************
   * ADO.NET 2.0 Data Provider for SQLite Version 3.X
   * Written by Robert Simpson (robert@blackcastlesoft.com)
   *
   * Released to the public domain, use at your own risk!
   ********************************************************/
  
  namespace System.Data.DenverDB
  {
    using System;
  
  #if !NET_COMPACT_20 && TRACE_WARNING
    using System.Diagnostics;
  #endif
  
    using System.Runtime.InteropServices;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Text;
  
    /// <summary>
    /// This base class provides datatype conversion services for the SQLite provider.
    /// </summary>
    public abstract class SQLiteConvert
    {
      /// <summary>
      /// The fallback default database type when one cannot be obtained from an
      /// existing connection instance.
      /// </summary>
      internal const DbType FallbackDefaultDbType = DbType.Object;
  
      /// <summary>
      /// The fallback default database type name when one cannot be obtained from
      /// an existing connection instance.
      /// </summary>
      internal static readonly string FallbackDefaultTypeName = String.Empty;
  
      /// <summary>
      /// The value for the Unix epoch (e.g. January 1, 1970 at midnight, in UTC).
      /// </summary>
      protected static readonly DateTime UnixEpoch =
          new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
  
      /// <summary>
      /// The value of the OLE Automation epoch represented as a Julian day.
      /// </summary>
      private static readonly double OleAutomationEpochAsJulianDay = 2415018.5;
  
      /// <summary>
      /// The format string for DateTime values when using the InvariantCulture or CurrentCulture formats.
      /// </summary>
      private const string FullFormat = "yyyy-MM-ddTHH:mm:ss.fffffffK";
  
      /// <summary>
      /// An array of ISO-8601 DateTime formats that we support parsing.
      /// </summary>
      private static string[] _datetimeFormats = new string[] {
        "THHmmssK",
        "THHmmK",
        "HH:mm:ss.FFFFFFFK",
        "HH:mm:ssK",
        "HH:mmK",
        "yyyy-MM-dd HH:mm:ss.FFFFFFFK", /* NOTE: UTC default (5). */
        "yyyy-MM-dd HH:mm:ssK",
        "yyyy-MM-dd HH:mmK",
        "yyyy-MM-ddTHH:mm:ss.FFFFFFFK",
        "yyyy-MM-ddTHH:mmK",
        "yyyy-MM-ddTHH:mm:ssK",
        "yyyyMMddHHmmssK",
        "yyyyMMddHHmmK",
        "yyyyMMddTHHmmssFFFFFFFK",
        "THHmmss",
        "THHmm",
        "HH:mm:ss.FFFFFFF",
        "HH:mm:ss",
        "HH:mm",
        "yyyy-MM-dd HH:mm:ss.FFFFFFF", /* NOTE: Non-UTC default (19). */
        "yyyy-MM-dd HH:mm:ss",
        "yyyy-MM-dd HH:mm",
        "yyyy-MM-ddTHH:mm:ss.FFFFFFF",
        "yyyy-MM-ddTHH:mm",
        "yyyy-MM-ddTHH:mm:ss",
        "yyyyMMddHHmmss",
        "yyyyMMddHHmm",
        "yyyyMMddTHHmmssFFFFFFF",
        "yyyy-MM-dd",
        "yyyyMMdd",
        "yy-MM-dd"
      };
  
      /// <summary>
      /// The internal default format for UTC DateTime values when converting
      /// to a string.
      /// </summary>
      private static readonly string _datetimeFormatUtc = _datetimeFormats[5];
  
      /// <summary>
      /// The internal default format for local DateTime values when converting
      /// to a string.
      /// </summary>
      private static readonly string _datetimeFormatLocal = _datetimeFormats[19];
  
      /// <summary>
      /// An UTF-8 Encoding instance, so we can convert strings to and from UTF-8
      /// </summary>
      private static Encoding _utf8 = new UTF8Encoding();
      /// <summary>
      /// The default DateTime format for this instance.
      /// </summary>
      internal SQLiteDateFormats _datetimeFormat;
      /// <summary>
      /// The default DateTimeKind for this instance.
      /// </summary>
      internal DateTimeKind _datetimeKind;
      /// <summary>
      /// The default DateTime format string for this instance.
      /// </summary>
      internal string _datetimeFormatString = null;
      /// <summary>
      /// Initializes the conversion class
      /// </summary>
      /// <param name="fmt">The default date/time format to use for this instance</param>
      /// <param name="kind">The DateTimeKind to use.</param>
      /// <param name="fmtString">The DateTime format string to use.</param>
      internal SQLiteConvert(
          SQLiteDateFormats fmt,
          DateTimeKind kind,
          string fmtString
          )
      {
        _datetimeFormat = fmt;
        _datetimeKind = kind;
        _datetimeFormatString = fmtString;
      }
  
      #region UTF-8 Conversion Functions
      /// <summary>
      /// Converts a string to a UTF-8 encoded byte array sized to include a null-terminating character.
      /// </summary>
      /// <param name="sourceText">The string to convert to UTF-8</param>
      /// <returns>A byte array containing the converted string plus an extra 0 terminating byte at the end of the array.</returns>
      public static byte[] ToUTF8(string sourceText)
      {
        Byte[] byteArray;
        int nlen = _utf8.GetByteCount(sourceText) + 1;
  
        byteArray = new byte[nlen];
        nlen = _utf8.GetBytes(sourceText, 0, sourceText.Length, byteArray, 0);
        byteArray[nlen] = 0;
  
        return byteArray;
      }
  
      /// <summary>
      /// Convert a DateTime to a UTF-8 encoded, zero-terminated byte array.
      /// </summary>
      /// <remarks>
      /// This function is a convenience function, which first calls ToString() on the DateTime, and then calls ToUTF8() with the
      /// string result.
      /// </remarks>
      /// <param name="dateTimeValue">The DateTime to convert.</param>
      /// <returns>The UTF-8 encoded string, including a 0 terminating byte at the end of the array.</returns>
      public byte[] ToUTF8(DateTime dateTimeValue)
      {
        return ToUTF8(ToString(dateTimeValue));
      }
  
      /// <summary>
      /// Converts a UTF-8 encoded IntPtr of the specified length into a .NET string
      /// </summary>
      /// <param name="nativestring">The pointer to the memory where the UTF-8 string is encoded</param>
      /// <param name="nativestringlen">The number of bytes to decode</param>
      /// <returns>A string containing the translated character(s)</returns>
      public virtual string ToString(IntPtr nativestring, int nativestringlen)
      {
        return UTF8ToString(nativestring, nativestringlen);
      }
  
      /// <summary>
      /// Converts a UTF-8 encoded IntPtr of the specified length into a .NET string
      /// </summary>
      /// <param name="nativestring">The pointer to the memory where the UTF-8 string is encoded</param>
      /// <param name="nativestringlen">The number of bytes to decode</param>
      /// <returns>A string containing the translated character(s)</returns>
      public static string UTF8ToString(IntPtr nativestring, int nativestringlen)
      {
        if (nativestring == IntPtr.Zero || nativestringlen == 0) return String.Empty;
        if (nativestringlen < 0)
        {
          nativestringlen = 0;
  
          while (Marshal.ReadByte(nativestring, nativestringlen) != 0)
            nativestringlen++;
  
          if (nativestringlen == 0) return String.Empty;
        }
  
        byte[] byteArray = new byte[nativestringlen];
  
        Marshal.Copy(nativestring, byteArray, 0, nativestringlen);
  
        return _utf8.GetString(byteArray, 0, nativestringlen);
      }
  
  
      #endregion
  
      #region DateTime Conversion Functions
      /// <summary>
      /// Converts a string into a DateTime, using the DateTimeFormat, DateTimeKind,
      /// and DateTimeFormatString specified for the connection when it was opened.
      /// </summary>
      /// <remarks>
      /// Acceptable ISO8601 DateTime formats are:
      /// <list type="bullet">
      /// <item><description>THHmmssK</description></item>
      /// <item><description>THHmmK</description></item>
      /// <item><description>HH:mm:ss.FFFFFFFK</description></item>
      /// <item><description>HH:mm:ssK</description></item>
      /// <item><description>HH:mmK</description></item>
      /// <item><description>yyyy-MM-dd HH:mm:ss.FFFFFFFK</description></item>
      /// <item><description>yyyy-MM-dd HH:mm:ssK</description></item>
      /// <item><description>yyyy-MM-dd HH:mmK</description></item>
      /// <item><description>yyyy-MM-ddTHH:mm:ss.FFFFFFFK</description></item>
      /// <item><description>yyyy-MM-ddTHH:mmK</description></item>
      /// <item><description>yyyy-MM-ddTHH:mm:ssK</description></item>
      /// <item><description>yyyyMMddHHmmssK</description></item>
      /// <item><description>yyyyMMddHHmmK</description></item>
      /// <item><description>yyyyMMddTHHmmssFFFFFFFK</description></item>
      /// <item><description>THHmmss</description></item>
      /// <item><description>THHmm</description></item>
      /// <item><description>HH:mm:ss.FFFFFFF</description></item>
      /// <item><description>HH:mm:ss</description></item>
      /// <item><description>HH:mm</description></item>
      /// <item><description>yyyy-MM-dd HH:mm:ss.FFFFFFF</description></item>
      /// <item><description>yyyy-MM-dd HH:mm:ss</description></item>
      /// <item><description>yyyy-MM-dd HH:mm</description></item>
      /// <item><description>yyyy-MM-ddTHH:mm:ss.FFFFFFF</description></item>
      /// <item><description>yyyy-MM-ddTHH:mm</description></item>
      /// <item><description>yyyy-MM-ddTHH:mm:ss</description></item>
      /// <item><description>yyyyMMddHHmmss</description></item>
      /// <item><description>yyyyMMddHHmm</description></item>
      /// <item><description>yyyyMMddTHHmmssFFFFFFF</description></item>
      /// <item><description>yyyy-MM-dd</description></item>
      /// <item><description>yyyyMMdd</description></item>
      /// <item><description>yy-MM-dd</description></item>
      /// </list>
      /// If the string cannot be matched to one of the above formats -OR-
      /// the DateTimeFormatString if one was provided, an exception will
      /// be thrown.
      /// </remarks>
      /// <param name="dateText">The string containing either a long integer number of 100-nanosecond units since
      /// System.DateTime.MinValue, a Julian day double, an integer number of seconds since the Unix epoch, a
      /// culture-independent formatted date and time string, a formatted date and time string in the current
      /// culture, or an ISO8601-format string.</param>
      /// <returns>A DateTime value</returns>
      public DateTime ToDateTime(string dateText)
      {
        return ToDateTime(dateText, _datetimeFormat, _datetimeKind, _datetimeFormatString);
      }
  
      /// <summary>
      /// Converts a string into a DateTime, using the specified DateTimeFormat,
      /// DateTimeKind and DateTimeFormatString.
      /// </summary>
      /// <remarks>
      /// Acceptable ISO8601 DateTime formats are:
      /// <list type="bullet">
      /// <item><description>THHmmssK</description></item>
      /// <item><description>THHmmK</description></item>
      /// <item><description>HH:mm:ss.FFFFFFFK</description></item>
      /// <item><description>HH:mm:ssK</description></item>
      /// <item><description>HH:mmK</description></item>
      /// <item><description>yyyy-MM-dd HH:mm:ss.FFFFFFFK</description></item>
      /// <item><description>yyyy-MM-dd HH:mm:ssK</description></item>
      /// <item><description>yyyy-MM-dd HH:mmK</description></item>
      /// <item><description>yyyy-MM-ddTHH:mm:ss.FFFFFFFK</description></item>
      /// <item><description>yyyy-MM-ddTHH:mmK</description></item>
      /// <item><description>yyyy-MM-ddTHH:mm:ssK</description></item>
      /// <item><description>yyyyMMddHHmmssK</description></item>
      /// <item><description>yyyyMMddHHmmK</description></item>
      /// <item><description>yyyyMMddTHHmmssFFFFFFFK</description></item>
      /// <item><description>THHmmss</description></item>
      /// <item><description>THHmm</description></item>
      /// <item><description>HH:mm:ss.FFFFFFF</description></item>
      /// <item><description>HH:mm:ss</description></item>
      /// <item><description>HH:mm</description></item>
      /// <item><description>yyyy-MM-dd HH:mm:ss.FFFFFFF</description></item>
      /// <item><description>yyyy-MM-dd HH:mm:ss</description></item>
      /// <item><description>yyyy-MM-dd HH:mm</description></item>
      /// <item><description>yyyy-MM-ddTHH:mm:ss.FFFFFFF</description></item>
      /// <item><description>yyyy-MM-ddTHH:mm</description></item>
      /// <item><description>yyyy-MM-ddTHH:mm:ss</description></item>
      /// <item><description>yyyyMMddHHmmss</description></item>
      /// <item><description>yyyyMMddHHmm</description></item>
      /// <item><description>yyyyMMddTHHmmssFFFFFFF</description></item>
      /// <item><description>yyyy-MM-dd</description></item>
      /// <item><description>yyyyMMdd</description></item>
      /// <item><description>yy-MM-dd</description></item>
      /// </list>
      /// If the string cannot be matched to one of the above formats -OR-
      /// the DateTimeFormatString if one was provided, an exception will
      /// be thrown.
      /// </remarks>
      /// <param name="dateText">The string containing either a long integer number of 100-nanosecond units since
      /// System.DateTime.MinValue, a Julian day double, an integer number of seconds since the Unix epoch, a
      /// culture-independent formatted date and time string, a formatted date and time string in the current
      /// culture, or an ISO8601-format string.</param>
      /// <param name="format">The SQLiteDateFormats to use.</param>
      /// <param name="kind">The DateTimeKind to use.</param>
      /// <param name="formatString">The DateTime format string to use.</param>
      /// <returns>A DateTime value</returns>
      public static DateTime ToDateTime(
          string dateText,
          SQLiteDateFormats format,
          DateTimeKind kind,
          string formatString
          )
      {
          switch (format)
          {
              case SQLiteDateFormats.Ticks:
                  {
                      return ToDateTime(Convert.ToInt64(
                          dateText, CultureInfo.InvariantCulture), kind);
                  }
              case SQLiteDateFormats.JulianDay:
                  {
                      return ToDateTime(Convert.ToDouble(
                          dateText, CultureInfo.InvariantCulture), kind);
                  }
              case SQLiteDateFormats.UnixEpoch:
                  {
                      return ToDateTime(Convert.ToInt32(
                          dateText, CultureInfo.InvariantCulture), kind);
                  }
              case SQLiteDateFormats.InvariantCulture:
                  {
                      if (formatString != null)
                          return DateTime.SpecifyKind(DateTime.ParseExact(
                              dateText, formatString,
                              DateTimeFormatInfo.InvariantInfo,
                              kind == DateTimeKind.Utc ?
                                  DateTimeStyles.AdjustToUniversal :
                                  DateTimeStyles.None),
                              kind);
                      else
                          return DateTime.SpecifyKind(DateTime.Parse(
                              dateText, DateTimeFormatInfo.InvariantInfo,
                              kind == DateTimeKind.Utc ?
                                  DateTimeStyles.AdjustToUniversal :
                                  DateTimeStyles.None),
                              kind);
                  }
              case SQLiteDateFormats.CurrentCulture:
                  {
                      if (formatString != null)
                          return DateTime.SpecifyKind(DateTime.ParseExact(
                              dateText, formatString,
                              DateTimeFormatInfo.CurrentInfo,
                              kind == DateTimeKind.Utc ?
                                  DateTimeStyles.AdjustToUniversal :
                                  DateTimeStyles.None),
                              kind);
                      else
                          return DateTime.SpecifyKind(DateTime.Parse(
                              dateText, DateTimeFormatInfo.CurrentInfo,
                              kind == DateTimeKind.Utc ?
                                  DateTimeStyles.AdjustToUniversal :
                                  DateTimeStyles.None),
                              kind);
                  }
              default: /* ISO-8601 */
                  {
                      if (formatString != null)
                          return DateTime.SpecifyKind(DateTime.ParseExact(
                              dateText, formatString,
                              DateTimeFormatInfo.InvariantInfo,
                              kind == DateTimeKind.Utc ?
                                  DateTimeStyles.AdjustToUniversal :
                                  DateTimeStyles.None),
                              kind);
                      else
                          return DateTime.SpecifyKind(DateTime.ParseExact(
                              dateText, _datetimeFormats,
                              DateTimeFormatInfo.InvariantInfo,
                              kind == DateTimeKind.Utc ?
                                  DateTimeStyles.AdjustToUniversal :
                                  DateTimeStyles.None),
                              kind);
                  }
          }
      }
  
      /// <summary>
      /// Converts a julianday value into a DateTime
      /// </summary>
      /// <param name="julianDay">The value to convert</param>
      /// <returns>A .NET DateTime</returns>
      public DateTime ToDateTime(double julianDay)
      {
        return ToDateTime(julianDay, _datetimeKind);
      }
  
      /// <summary>
      /// Converts a julianday value into a DateTime
      /// </summary>
      /// <param name="julianDay">The value to convert</param>
      /// <param name="kind">The DateTimeKind to use.</param>
      /// <returns>A .NET DateTime</returns>
      public static DateTime ToDateTime(double julianDay, DateTimeKind kind)
      {
          return DateTime.SpecifyKind(
              DateTime.FromOADate(julianDay - OleAutomationEpochAsJulianDay), kind);
      }
  
      /// <summary>
      /// Converts the specified number of seconds from the Unix epoch into a
      /// <see cref="DateTime" /> value.
      /// </summary>
      /// <param name="seconds">
      /// The number of whole seconds since the Unix epoch.
      /// </param>
      /// <param name="kind">
      /// Either Utc or Local time.
      /// </param>
      /// <returns>
      /// The new <see cref="DateTime" /> value.
      /// </returns>
      internal static DateTime ToDateTime(int seconds, DateTimeKind kind)
      {
          return DateTime.SpecifyKind(UnixEpoch.AddSeconds(seconds), kind);
      }
  
      /// <summary>
      /// Converts the specified number of ticks since the epoch into a
      /// <see cref="DateTime" /> value.
      /// </summary>
      /// <param name="ticks">
      /// The number of whole ticks since the epoch.
      /// </param>
      /// <param name="kind">
      /// Either Utc or Local time.
      /// </param>
      /// <returns>
      /// The new <see cref="DateTime" /> value.
      /// </returns>
      internal static DateTime ToDateTime(long ticks, DateTimeKind kind)
      {
          return new DateTime(ticks, kind);
      }
  
      /// <summary>
      /// Converts a DateTime struct to a JulianDay double
      /// </summary>
      /// <param name="value">The DateTime to convert</param>
      /// <returns>The JulianDay value the Datetime represents</returns>
      public static double ToJulianDay(DateTime value)
      {
        return value.ToOADate() + OleAutomationEpochAsJulianDay;
      }
  
      /// <summary>
      /// Converts a DateTime struct to the whole number of seconds since the
      /// Unix epoch.
      /// </summary>
      /// <param name="value">The DateTime to convert</param>
      /// <returns>The whole number of seconds since the Unix epoch</returns>
      public static long ToUnixEpoch(DateTime value)
      {
          return (value.Subtract(UnixEpoch).Ticks / TimeSpan.TicksPerSecond);
      }
  
      /// <summary>
      /// Returns the DateTime format string to use for the specified DateTimeKind.
      /// If <paramref name="formatString" /> is not null, it will be returned verbatim.
      /// </summary>
      /// <param name="kind">The DateTimeKind to use.</param>
      /// <param name="formatString">The DateTime format string to use.</param>
      /// <returns>
      /// The DateTime format string to use for the specified DateTimeKind.
      /// </returns>
      private static string GetDateTimeKindFormat(
          DateTimeKind kind,
          string formatString
          )
      {
          if (formatString != null) return formatString;
          return (kind == DateTimeKind.Utc) ? _datetimeFormatUtc : _datetimeFormatLocal;
      }
  
      /// <summary>
      /// Converts a string into a DateTime, using the DateTimeFormat, DateTimeKind,
      /// and DateTimeFormatString specified for the connection when it was opened.
      /// </summary>
      /// <param name="dateValue">The DateTime value to convert</param>
      /// <returns>Either a string containing the long integer number of 100-nanosecond units since System.DateTime.MinValue, a
      /// Julian day double, an integer number of seconds since the Unix epoch, a culture-independent formatted date and time
      /// string, a formatted date and time string in the current culture, or an ISO8601-format date/time string.</returns>
      public string ToString(DateTime dateValue)
      {
          return ToString(dateValue, _datetimeFormat, _datetimeKind, _datetimeFormatString);
      }
  
      /// <summary>
      /// Converts a string into a DateTime, using the DateTimeFormat, DateTimeKind,
      /// and DateTimeFormatString specified for the connection when it was opened.
      /// </summary>
      /// <param name="dateValue">The DateTime value to convert</param>
      /// <param name="format">The SQLiteDateFormats to use.</param>
      /// <param name="kind">The DateTimeKind to use.</param>
      /// <param name="formatString">The DateTime format string to use.</param>
      /// <returns>Either a string containing the long integer number of 100-nanosecond units since System.DateTime.MinValue, a
      /// Julian day double, an integer number of seconds since the Unix epoch, a culture-independent formatted date and time
      /// string, a formatted date and time string in the current culture, or an ISO8601-format date/time string.</returns>
      public static string ToString(
          DateTime dateValue,
          SQLiteDateFormats format,
          DateTimeKind kind,
          string formatString
          )
      {
          switch (format)
          {
              case SQLiteDateFormats.Ticks:
                  return dateValue.Ticks.ToString(CultureInfo.InvariantCulture);
              case SQLiteDateFormats.JulianDay:
                  return ToJulianDay(dateValue).ToString(CultureInfo.InvariantCulture);
              case SQLiteDateFormats.UnixEpoch:
                  return ((long)(dateValue.Subtract(UnixEpoch).Ticks / TimeSpan.TicksPerSecond)).ToString();
              case SQLiteDateFormats.InvariantCulture:
                  return dateValue.ToString((formatString != null) ?
                      formatString : FullFormat, CultureInfo.InvariantCulture);
              case SQLiteDateFormats.CurrentCulture:
                  return dateValue.ToString((formatString != null) ?
                      formatString : FullFormat, CultureInfo.CurrentCulture);
              default:
                  return (dateValue.Kind == DateTimeKind.Unspecified) ?
                      DateTime.SpecifyKind(dateValue, kind).ToString(
                          GetDateTimeKindFormat(kind, formatString),
                              CultureInfo.InvariantCulture) : dateValue.ToString(
                          GetDateTimeKindFormat(dateValue.Kind, formatString),
                              CultureInfo.InvariantCulture);
          }
      }
  
      /// <summary>
      /// Internal function to convert a UTF-8 encoded IntPtr of the specified length to a DateTime.
      /// </summary>
      /// <remarks>
      /// This is a convenience function, which first calls ToString() on the IntPtr to convert it to a string, then calls
      /// ToDateTime() on the string to return a DateTime.
      /// </remarks>
      /// <param name="ptr">A pointer to the UTF-8 encoded string</param>
      /// <param name="len">The length in bytes of the string</param>
      /// <returns>The parsed DateTime value</returns>
      internal DateTime ToDateTime(IntPtr ptr, int len)
      {
        return ToDateTime(ToString(ptr, len));
      }
      #endregion
  
      /// <summary>
      /// Smart method of splitting a string.  Skips quoted elements, removes the quotes.
      /// </summary>
      /// <remarks>
      /// This split function works somewhat like the String.Split() function in that it breaks apart a string into
      /// pieces and returns the pieces as an array.  The primary differences are:
      /// <list type="bullet">
      /// <item><description>Only one character can be provided as a separator character</description></item>
      /// <item><description>Quoted text inside the string is skipped over when searching for the separator, and the quotes are removed.</description></item>
      /// </list>
      /// Thus, if splitting the following string looking for a comma:<br/>
      /// One,Two, "Three, Four", Five<br/>
      /// <br/>
      /// The resulting array would contain<br/>
      /// [0] One<br/>
      /// [1] Two<br/>
      /// [2] Three, Four<br/>
      /// [3] Five<br/>
      /// <br/>
      /// Note that the leading and trailing spaces were removed from each item during the split.
      /// </remarks>
      /// <param name="source">Source string to split apart</param>
      /// <param name="separator">Separator character</param>
      /// <returns>A string array of the split up elements</returns>
      public static string[] Split(string source, char separator)
      {
        char[] toks = new char[2] { '\"', separator };
        char[] quot = new char[1] { '\"' };
        int n = 0;
        List<string> ls = new List<string>();
        string s;
  
        while (source.Length > 0)
        {
          n = source.IndexOfAny(toks, n);
          if (n == -1) break;
          if (source[n] == toks[0])
          {
            //source = source.Remove(n, 1);
            n = source.IndexOfAny(quot, n + 1);
            if (n == -1)
            {
              //source = "\"" + source;
              break;
            }
            n++;
            //source = source.Remove(n, 1);
          }
          else
          {
            s = source.Substring(0, n).Trim();
            if (s.Length > 1 && s[0] == quot[0] && s[s.Length - 1] == s[0])
              s = s.Substring(1, s.Length - 2);
  
            source = source.Substring(n + 1).Trim();
            if (s.Length > 0) ls.Add(s);
            n = 0;
          }
        }
        if (source.Length > 0)
        {
          s = source.Trim();
          if (s.Length > 1 && s[0] == quot[0] && s[s.Length - 1] == s[0])
            s = s.Substring(1, s.Length - 2);
          ls.Add(s);
        }
  
        string[] ar = new string[ls.Count];
        ls.CopyTo(ar, 0);
  
        return ar;
      }
  
      /// <summary>
      /// Splits the specified string into multiple strings based on a separator
      /// and returns the result as an array of strings.
      /// </summary>
      /// <param name="value">
      /// The string to split into pieces based on the separator character.  If
      /// this string is null, null will always be returned.  If this string is
      /// empty, an array of zero strings will always be returned.
      /// </param>
      /// <param name="separator">
      /// The character used to divide the original string into sub-strings.
      /// This character cannot be a backslash or a double-quote; otherwise, no
      /// work will be performed and null will be returned.
      /// </param>
      /// <param name="keepQuote">
      /// If this parameter is non-zero, all double-quote characters will be
      /// retained in the returned list of strings; otherwise, they will be
      /// dropped.
      /// </param>
      /// <param name="error">
      /// Upon failure, this parameter will be modified to contain an appropriate
      /// error message.
      /// </param>
      /// <returns>
      /// The new array of strings or null if the input string is null -OR- the
      /// separator character is a backslash or a double-quote -OR- the string
      /// contains an unbalanced backslash or double-quote character.
      /// </returns>
      internal static string[] NewSplit(
          string value,
          char separator,
          bool keepQuote,
          ref string error
          )
      {
          const char EscapeChar = '\\';
          const char QuoteChar = '\"';
  
          //
          // NOTE: It is illegal for the separator character to be either a
          //       backslash or a double-quote because both of those characters
          //       are used for escaping other characters (e.g. the separator
          //       character).
          //
          if ((separator == EscapeChar) || (separator == QuoteChar))
          {
              error = "separator character cannot be the escape or quote characters";
              return null;
          }
  
          if (value == null)
          {
              error = "string value to split cannot be null";
              return null;
          }
  
          int length = value.Length;
  
          if (length == 0)
              return new string[0];
  
          List<string> list = new List<string>();
          StringBuilder element = new StringBuilder();
          int index = 0;
          bool escape = false;
          bool quote = false;
  
          while (index < length)
          {
              char character = value[index++];
  
              if (escape)
              {
                  //
                  // HACK: Only consider the escape character to be an actual
                  //       "escape" if it is followed by a reserved character;
                  //       otherwise, emit the original escape character and
                  //       the current character in an effort to help preserve
                  //       the original string content.
                  //
                  if ((character != EscapeChar) &&
                      (character != QuoteChar) &&
                      (character != separator))
                  {
                      element.Append(EscapeChar);
                  }
  
                  element.Append(character);
                  escape = false;
              }
              else if (character == EscapeChar)
              {
                  escape = true;
              }
              else if (character == QuoteChar)
              {
                  if (keepQuote)
                      element.Append(character);
  
                  quote = !quote;
              }
              else if (character == separator)
              {
                  if (quote)
                  {
                      element.Append(character);
                  }
                  else
                  {
                      list.Add(element.ToString());
                      element.Length = 0;
                  }
              }
              else
              {
                  element.Append(character);
              }
          }
  
          //
          // NOTE: An unbalanced escape or quote character in the string is
          //       considered to be a fatal error; therefore, return null.
          //
          if (escape || quote)
          {
              error = "unbalanced escape or quote character found";
              return null;
          }
  
          if (element.Length > 0)
              list.Add(element.ToString());
  
          return list.ToArray();
      }
  
      /// <summary>
      /// Queries and returns the string representation for an object, using the
      /// specified (or current) format provider.
      /// </summary>
      /// <param name="obj">
      /// The object instance to return the string representation for.
      /// </param>
      /// <param name="provider">
      /// The format provider to use -OR- null if the current format provider for
      /// the thread should be used instead.
      /// </param>
      /// <returns>
      /// The string representation for the object instance -OR- null if the
      /// object instance is also null.
      /// </returns>
      public static string ToStringWithProvider(
          object obj,
          IFormatProvider provider
          )
      {
          if (obj == null)
              return null; /* null --> null */
  
          if (obj is string)
              return (string)obj; /* identity */
  
          IConvertible convertible = obj as IConvertible;
  
          if (convertible != null)
              return convertible.ToString(provider);
  
          return obj.ToString(); /* not IConvertible */
      }
  
      /// <summary>
      /// Attempts to convert an arbitrary object to the Boolean data type.
      /// Null object values are converted to false.  Throws an exception
      /// upon failure.
      /// </summary>
      /// <param name="obj">
      /// The object value to convert.
      /// </param>
      /// <param name="provider">
      /// The format provider to use.
      /// </param>
      /// <param name="viaFramework">
      /// If non-zero, a string value will be converted using the
      /// <see cref="Convert.ToBoolean(Object, IFormatProvider)" />
      /// method; otherwise, the <see cref="ToBoolean(String)" />
      /// method will be used.
      /// </param>
      /// <returns>
      /// The converted boolean value.
      /// </returns>
      internal static bool ToBoolean(
          object obj,
          IFormatProvider provider,
          bool viaFramework
          )
      {
          if (obj == null)
              return false;
  
          TypeCode typeCode = Type.GetTypeCode(obj.GetType());
  
          switch (typeCode)
          {
              case TypeCode.Empty:
              case TypeCode.DBNull:
                  return false;
              case TypeCode.Boolean:
                  return (bool)obj;
              case TypeCode.Char:
                  return ((char)obj) != (char)0 ? true : false;
              case TypeCode.SByte:
                  return ((sbyte)obj) != (sbyte)0 ? true : false;
              case TypeCode.Byte:
                  return ((byte)obj) != (byte)0 ? true : false;
              case TypeCode.Int16:
                  return ((short)obj) != (short)0 ? true : false;
              case TypeCode.UInt16:
                  return ((ushort)obj) != (ushort)0 ? true : false;
              case TypeCode.Int32:
                  return ((int)obj) != (int)0 ? true : false;
              case TypeCode.UInt32:
                  return ((uint)obj) != (uint)0 ? true : false;
              case TypeCode.Int64:
                  return ((long)obj) != (long)0 ? true : false;
              case TypeCode.UInt64:
                  return ((ulong)obj) != (ulong)0 ? true : false;
              case TypeCode.Single:
                  return ((float)obj) != (float)0.0 ? true : false;
              case TypeCode.Double:
                  return ((double)obj) != (double)0.0 ? true : false;
              case TypeCode.Decimal:
                  return ((decimal)obj) != Decimal.Zero ? true : false;
              case TypeCode.String:
                  return viaFramework ?
                      Convert.ToBoolean(obj, provider) :
                      ToBoolean(ToStringWithProvider(obj, provider));
              default:
                  throw new SQLiteException(String.Format(
                      CultureInfo.CurrentCulture,
                      "Cannot convert type {0} to boolean",
                      typeCode));
          }
      }
  
      /// <summary>
      /// Convert a value to true or false.
      /// </summary>
      /// <param name="source">A string or number representing true or false</param>
      /// <returns></returns>
      public static bool ToBoolean(object source)
      {
        if (source is bool) return (bool)source;
  
        return ToBoolean(ToStringWithProvider(
            source, CultureInfo.InvariantCulture));
      }
  
      /// <summary>
      /// Convert a string to true or false.
      /// </summary>
      /// <param name="source">A string representing true or false</param>
      /// <returns></returns>
      /// <remarks>
      /// "yes", "no", "y", "n", "0", "1", "on", "off" as well as Boolean.FalseString and Boolean.TrueString will all be
      /// converted to a proper boolean value.
      /// </remarks>
      public static bool ToBoolean(string source)
      {
        if (String.Compare(source, bool.TrueString, StringComparison.OrdinalIgnoreCase) == 0) return true;
        else if (String.Compare(source, bool.FalseString, StringComparison.OrdinalIgnoreCase) == 0) return false;
  
        switch(source.ToLower(CultureInfo.InvariantCulture))
        {
          case "yes":
          case "y":
          case "1":
          case "on":
            return true;
          case "no":
          case "n":
          case "0":
          case "off":
            return false;
          default:
            throw new ArgumentException("source");
        }
      }
  
      #region Type Conversions
      /// <summary>
      /// Converts a SQLiteType to a .NET Type object
      /// </summary>
      /// <param name="t">The SQLiteType to convert</param>
      /// <returns>Returns a .NET Type object</returns>
      internal static Type SQLiteTypeToType(SQLiteType t)
      {
        if (t.Type == DbType.Object)
          return _affinitytotype[(int)t.Affinity];
        else
          return SQLiteConvert.DbTypeToType(t.Type);
      }
  
      private static Type[] _affinitytotype = {
        typeof(object),   // Uninitialized (0)
        typeof(Int64),    // Int64 (1)
        typeof(Double),   // Double (2)
        typeof(string),   // Text (3)
        typeof(byte[]),   // Blob (4)
        typeof(object),   // Null (5)
        typeof(DateTime), // DateTime (10)
        typeof(object)    // None (11)
      };
  
      /// <summary>
      /// For a given intrinsic type, return a DbType
      /// </summary>
      /// <param name="typ">The native type to convert</param>
      /// <returns>The corresponding (closest match) DbType</returns>
      internal static DbType TypeToDbType(Type typ)
      {
        TypeCode tc = Type.GetTypeCode(typ);
        if (tc == TypeCode.Object)
        {
          if (typ == typeof(byte[])) return DbType.Binary;
          if (typ == typeof(Guid)) return DbType.Guid;
          return DbType.String;
        }
        return _typetodbtype[(int)tc];
      }
  
      private static DbType[] _typetodbtype = {
        DbType.Object,   // Empty (0)
        DbType.Binary,   // Object (1)
        DbType.Object,   // DBNull (2)
        DbType.Boolean,  // Boolean (3)
        DbType.SByte,    // Char (4)
        DbType.SByte,    // SByte (5)
        DbType.Byte,     // Byte (6)
        DbType.Int16,    // Int16 (7)
        DbType.UInt16,   // UInt16 (8)
        DbType.Int32,    // Int32 (9)
        DbType.UInt32,   // UInt32 (10)
        DbType.Int64,    // Int64 (11)
        DbType.UInt64,   // UInt64 (12)
        DbType.Single,   // Single (13)
        DbType.Double,   // Double (14)
        DbType.Decimal,  // Decimal (15)
        DbType.DateTime, // DateTime (16)
        DbType.Object,   // ?? (17)
        DbType.String    // String (18)
      };
  
      /// <summary>
      /// Returns the ColumnSize for the given DbType
      /// </summary>
      /// <param name="typ">The DbType to get the size of</param>
      /// <returns></returns>
      internal static int DbTypeToColumnSize(DbType typ)
      {
        return _dbtypetocolumnsize[(int)typ];
      }
  
      private static int[] _dbtypetocolumnsize = {
        int.MaxValue, // AnsiString (0)
        int.MaxValue, // Binary (1)
        1,            // Byte (2)
        1,            // Boolean (3)
        8,            // Currency (4)
        8,            // Date (5)
        8,            // DateTime (6)
        8,            // Decimal (7)
        8,            // Double (8)
        16,           // Guid (9)
        2,            // Int16 (10)
        4,            // Int32 (11)
        8,            // Int64 (12)
        int.MaxValue, // Object (13)
        1,            // SByte (14)
        4,            // Single (15)
        int.MaxValue, // String (16)
        8,            // Time (17)
        2,            // UInt16 (18)
        4,            // UInt32 (19)
        8,            // UInt64 (20)
        8,            // VarNumeric (21)
        int.MaxValue, // AnsiStringFixedLength (22)
        int.MaxValue, // StringFixedLength (23)
        int.MaxValue, // ?? (24)
        int.MaxValue  // Xml (25)
      };
  
      internal static object DbTypeToNumericPrecision(DbType typ)
      {
        return _dbtypetonumericprecision[(int)typ];
      }
  
      private static object[] _dbtypetonumericprecision = {
        DBNull.Value, // AnsiString (0)
        DBNull.Value, // Binary (1)
        3,            // Byte (2)
        DBNull.Value, // Boolean (3)
        19,           // Currency (4)
        DBNull.Value, // Date (5)
        DBNull.Value, // DateTime (6)
        53,           // Decimal (7)
        53,           // Double (8)
        DBNull.Value, // Guid (9)
        5,            // Int16 (10)
        10,           // Int32 (11)
        19,           // Int64 (12)
        DBNull.Value, // Object (13)
        3,            // SByte (14)
        24,           // Single (15)
        DBNull.Value, // String (16)
        DBNull.Value, // Time (17)
        5,            // UInt16 (18)
        10,           // UInt32 (19)
        19,           // UInt64 (20)
        53,           // VarNumeric (21)
        DBNull.Value, // AnsiStringFixedLength (22)
        DBNull.Value, // StringFixedLength (23)
        DBNull.Value, // ?? (24)
        DBNull.Value  // Xml (25)
      };
  
      internal static object DbTypeToNumericScale(DbType typ)
      {
        return _dbtypetonumericscale[(int)typ];
      }
  
      private static object[] _dbtypetonumericscale = {
        DBNull.Value, // AnsiString (0)
        DBNull.Value, // Binary (1)
        0,            // Byte (2)
        DBNull.Value, // Boolean (3)
        4,            // Currency (4)
        DBNull.Value, // Date (5)
        DBNull.Value, // DateTime (6)
        DBNull.Value, // Decimal (7)
        DBNull.Value, // Double (8)
        DBNull.Value, // Guid (9)
        0,            // Int16 (10)
        0,            // Int32 (11)
        0,            // Int64 (12)
        DBNull.Value, // Object (13)
        0,            // SByte (14)
        DBNull.Value, // Single (15)
        DBNull.Value, // String (16)
        DBNull.Value, // Time (17)
        0,            // UInt16 (18)
        0,            // UInt32 (19)
        0,            // UInt64 (20)
        0,            // VarNumeric (21)
  
gt:       DBNull.Value, // AnsiStringFixedLength (22)