diff options
Diffstat (limited to 'ThirdParty/CsvHelper-master/src/CsvHelper')
199 files changed, 18616 insertions, 0 deletions
diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/ArrayHelper.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/ArrayHelper.cs new file mode 100644 index 0000000..16b15db --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/ArrayHelper.cs @@ -0,0 +1,78 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace CsvHelper +{ + /// <summary> + /// Methods to help with arrays. + /// </summary> + public static class ArrayHelper + { + /// <summary> + /// Trims the characters off the start and end of the buffer + /// by updating the start and length arguments. + /// </summary> + /// <param name="buffer">The buffer.</param> + /// <param name="start">The start.</param> + /// <param name="length">The length.</param> + /// <param name="trimChars">The characters to trim.</param> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Trim(char[] buffer, ref int start, ref int length, char[] trimChars) + { + // Trim start. + for (var i = start; i < start + length; i++) + { + var c = buffer[i]; + if (!Contains(trimChars, c)) + { + break; + } + + start++; + length--; + } + + // Trim end. + for (var i = start + length - 1; i > start; i--) + { + var c = buffer[i]; + if (!Contains(trimChars, c)) + { + break; + } + + length--; + } + } + + /// <summary> + /// Determines whether this given array contains the given character. + /// </summary> + /// <param name="array">The array to search.</param> + /// <param name="c">The character to look for.</param> + /// <returns> + /// <c>true</c> if the array contains the characters, otherwise <c>false</c>. + /// </returns> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool Contains(char[] array, in char c) + { + for (var i = 0; i < array.Length; i++) + { + if (array[i] == c) + { + return true; + } + } + + return false; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/BadDataException.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/BadDataException.cs new file mode 100644 index 0000000..9aecd38 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/BadDataException.cs @@ -0,0 +1,67 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper +{ + /// <summary> + /// Represents errors that occur due to bad data. + /// </summary> + [Serializable] + public class BadDataException : CsvHelperException + { + /// <summary> + /// The full field unedited. + /// </summary> + public readonly string Field; + + /// <summary> + /// The full row unedited. + /// </summary> + public readonly string RawRecord; + + /// <summary> + /// Initializes a new instance of the <see cref="BadDataException"/> class. + /// </summary> + /// <param name="field">The full field unedited.</param> + /// <param name="rawRecord">The full row unedited.</param> + /// <param name="context">The reading context.</param> + public BadDataException(string field, string rawRecord, CsvContext context) : base(context) + { + Field = field; + RawRecord = rawRecord; + } + + /// <summary> + /// Initializes a new instance of the <see cref="BadDataException"/> class + /// with a specified error message. + /// </summary> + /// <param name="field">The full field unedited.</param> + /// <param name="rawRecord">The full row unedited.</param> + /// <param name="context">The reading context.</param> + /// <param name="message">The message that describes the error.</param> + public BadDataException(string field, string rawRecord, CsvContext context, string message) : base(context, message) + { + Field = field; + RawRecord = rawRecord; + } + + /// <summary> + /// Initializes a new instance of the <see cref="BadDataException"/> class + /// with a specified error message and a reference to the inner exception that + /// is the cause of this exception. + /// </summary> + /// <param name="field">The full field unedited.</param> + /// <param name="rawRecord">The full row unedited.</param> + /// <param name="context">The reading context.</param> + /// <param name="message">The error message that explains the reason for the exception.</param> + /// <param name="innerException">The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.</param> + public BadDataException(string field, string rawRecord, CsvContext context, string message, Exception innerException) : base(context, message, innerException) + { + Field = field; + RawRecord = rawRecord; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/AllowCommentsAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/AllowCommentsAttribute.cs new file mode 100644 index 0000000..1490cc9 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/AllowCommentsAttribute.cs @@ -0,0 +1,35 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// A value indicating if comments are allowed. + /// </summary> + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public class AllowCommentsAttribute : Attribute, IClassMapper + { + /// <summary> + /// Gets a value indicating if comments are allowed. + /// </summary> + public bool AllowComments { get; private set; } + + /// <summary> + /// A value indicating if comments are allowed. + /// </summary> + /// <param name="allowComments">The value indicating id comments are allowed.</param> + public AllowCommentsAttribute(bool allowComments) + { + AllowComments = allowComments; + } + + /// <inheritdoc /> + public void ApplyTo(CsvConfiguration configuration) + { + configuration.AllowComments = AllowComments; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/BooleanFalseValuesAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/BooleanFalseValuesAttribute.cs new file mode 100644 index 0000000..b26315b --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/BooleanFalseValuesAttribute.cs @@ -0,0 +1,52 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// The string values used to represent a boolean false when converting. + /// </summary> + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)] + public class BooleanFalseValuesAttribute : Attribute, IMemberMapper, IParameterMapper + { + /// <summary> + /// Gets the false values. + /// </summary> + public string[] FalseValues { get; private set; } + + /// <summary> + /// The string values used to represent a boolean false when converting. + /// </summary> + /// <param name="falseValue">The false values.</param> + public BooleanFalseValuesAttribute(string falseValue) + { + FalseValues = new string[] { falseValue }; + } + + /// <summary> + /// The string values used to represent a boolean false when converting. + /// </summary> + /// <param name="falseValues">The false values.</param> + public BooleanFalseValuesAttribute(params string[] falseValues) + { + FalseValues = falseValues; + } + + /// <inheritdoc /> + public void ApplyTo(MemberMap memberMap) + { + memberMap.Data.TypeConverterOptions.BooleanFalseValues.Clear(); + memberMap.Data.TypeConverterOptions.BooleanFalseValues.AddRange(FalseValues); + } + + /// <inheritdoc /> + public void ApplyTo(ParameterMap parameterMap) + { + parameterMap.Data.TypeConverterOptions.BooleanFalseValues.Clear(); + parameterMap.Data.TypeConverterOptions.BooleanFalseValues.AddRange(FalseValues); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/BooleanTrueValuesAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/BooleanTrueValuesAttribute.cs new file mode 100644 index 0000000..3a9b591 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/BooleanTrueValuesAttribute.cs @@ -0,0 +1,52 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// The string values used to represent a boolean true when converting. + /// </summary> + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)] + public class BooleanTrueValuesAttribute : Attribute, IMemberMapper, IParameterMapper + { + /// <summary> + /// Gets the true values. + /// </summary> + public string[] TrueValues { get; private set; } + + /// <summary> + /// The string values used to represent a boolean true when converting. + /// </summary> + /// <param name="trueValue"></param> + public BooleanTrueValuesAttribute(string trueValue) + { + TrueValues = new string[] { trueValue }; + } + + /// <summary> + /// The string values used to represent a boolean true when converting. + /// </summary> + /// <param name="trueValues"></param> + public BooleanTrueValuesAttribute(params string[] trueValues) + { + TrueValues = trueValues; + } + + /// <inheritdoc /> + public void ApplyTo(MemberMap memberMap) + { + memberMap.Data.TypeConverterOptions.BooleanTrueValues.Clear(); + memberMap.Data.TypeConverterOptions.BooleanTrueValues.AddRange(TrueValues); + } + + /// <inheritdoc /> + public void ApplyTo(ParameterMap parameterMap) + { + parameterMap.Data.TypeConverterOptions.BooleanTrueValues.Clear(); + parameterMap.Data.TypeConverterOptions.BooleanTrueValues.AddRange(TrueValues); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/BufferSizeAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/BufferSizeAttribute.cs new file mode 100644 index 0000000..f74e98e --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/BufferSizeAttribute.cs @@ -0,0 +1,36 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// The size of the buffer used for parsing and writing CSV files. + /// Default is 0x1000. + /// </summary> + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public class BufferSizeAttribute : Attribute, IClassMapper + { + /// <summary> + /// The buffer size. + /// </summary> + public int BufferSize { get; private set; } + + /// <summary> + /// The size of the buffer used for parsing and writing CSV files. + /// </summary> + /// <param name="bufferSize"></param> + public BufferSizeAttribute(int bufferSize) + { + BufferSize = bufferSize; + } + + /// <inheritdoc /> + public void ApplyTo(CsvConfiguration configuration) + { + configuration.BufferSize = BufferSize; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/CacheFieldsAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/CacheFieldsAttribute.cs new file mode 100644 index 0000000..1f6b859 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/CacheFieldsAttribute.cs @@ -0,0 +1,36 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// Cache fields that are created when parsing. + /// Default is false. + /// </summary> + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public class CacheFieldsAttribute : Attribute, IClassMapper + { + /// <summary> + /// Cache fields that are created when parsing. + /// </summary> + public bool CacheFields { get; private set; } + + /// <summary> + /// Cache fields that are created when parsing. + /// </summary> + /// <param name="cacheFields"></param> + public CacheFieldsAttribute(bool cacheFields) + { + CacheFields = cacheFields; + } + + /// <inheritdoc /> + public void ApplyTo(CsvConfiguration configuration) + { + configuration.CacheFields = CacheFields; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/CommentAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/CommentAttribute.cs new file mode 100644 index 0000000..c0c6124 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/CommentAttribute.cs @@ -0,0 +1,36 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// The character used to denote a line that is commented out. + /// Default is #. + /// </summary> + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public class CommentAttribute : Attribute, IClassMapper + { + /// <summary> + /// Gets the character used to denote a line that is commented out. + /// </summary> + public char Comment { get; private set; } + + /// <summary> + /// The character used to denote a line that is commented out. + /// </summary> + /// <param name="comment">The comment character.</param> + public CommentAttribute(char comment) + { + Comment = comment; + } + + /// <inheritdoc /> + public void ApplyTo(CsvConfiguration configuration) + { + configuration.Comment = Comment; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/ConstantAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/ConstantAttribute.cs new file mode 100644 index 0000000..5dd2dc5 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/ConstantAttribute.cs @@ -0,0 +1,47 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// The constant value that will be used for every record when + /// reading and writing. This value will always be used no matter + /// what other mapping configurations are specified. + /// </summary> + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)] + public class ConstantAttribute : Attribute, IMemberMapper, IParameterMapper + { + /// <summary> + /// Gets the constant. + /// </summary> + public object Constant { get; private set; } + + /// <summary> + /// The constant value that will be used for every record when + /// reading and writing. This value will always be used no matter + /// what other mapping configurations are specified. + /// </summary> + /// <param name="constant">The constant.</param> + public ConstantAttribute(object constant) + { + Constant = constant; + } + + /// <inheritdoc /> + public void ApplyTo(MemberMap memberMap) + { + memberMap.Data.Constant = Constant; + memberMap.Data.IsConstantSet = true; + } + + /// <inheritdoc /> + public void ApplyTo(ParameterMap parameterMap) + { + parameterMap.Data.Constant = Constant; + parameterMap.Data.IsConstantSet = true; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/CountBytesAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/CountBytesAttribute.cs new file mode 100644 index 0000000..165784e --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/CountBytesAttribute.cs @@ -0,0 +1,45 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Text; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// A value indicating whether the number of bytes should + /// be counted while parsing. Default is false. This will slow down parsing + /// because it needs to get the byte count of every char for the given encoding. + /// The <see cref="Encoding"/> needs to be set correctly for this to be accurate. + /// </summary> + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public class CountBytesAttribute : Attribute, IClassMapper + { + /// <summary> + /// A value indicating whether the number of bytes should + /// be counted while parsing. Default is false. This will slow down parsing + /// because it needs to get the byte count of every char for the given encoding. + /// The <see cref="Encoding"/> needs to be set correctly for this to be accurate. + /// </summary> + public bool CountBytes { get; private set; } + + /// <summary> + /// A value indicating whether the number of bytes should + /// be counted while parsing. Default is false. This will slow down parsing + /// because it needs to get the byte count of every char for the given encoding. + /// The <see cref="Encoding"/> needs to be set correctly for this to be accurate. + /// </summary> + /// <param name="countBytes"></param> + public CountBytesAttribute(bool countBytes) + { + CountBytes = countBytes; + } + + /// <inheritdoc /> + public void ApplyTo(CsvConfiguration configuration) + { + configuration.CountBytes = CountBytes; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/CultureInfoAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/CultureInfoAttribute.cs new file mode 100644 index 0000000..47940fb --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/CultureInfoAttribute.cs @@ -0,0 +1,46 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Globalization; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// The <see cref="CultureInfo"/> used when type converting. + /// This will override the global <see cref="CsvConfiguration.CultureInfo"/> + /// setting. Or set the same if the attribute is specified on class level. + /// </summary> + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)] + public class CultureInfoAttribute : Attribute, IMemberMapper, IParameterMapper + { + /// <summary> + /// Gets the culture info. + /// </summary> + public CultureInfo CultureInfo { get; private set; } + + /// <summary> + /// The <see cref="CultureInfo"/> used when type converting. + /// This will override the global <see cref="CsvConfiguration.CultureInfo"/> + /// setting. Or set the same if the attribute is specified on class level. + /// </summary> + /// <param name="culture">The culture.</param> + public CultureInfoAttribute(string culture) + { + CultureInfo = CultureInfo.GetCultureInfo(culture); + } + + /// <inheritdoc /> + public void ApplyTo(MemberMap memberMap) + { + memberMap.Data.TypeConverterOptions.CultureInfo = CultureInfo; + } + + /// <inheritdoc /> + public void ApplyTo(ParameterMap parameterMap) + { + parameterMap.Data.TypeConverterOptions.CultureInfo = CultureInfo; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/DateTimeStylesAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/DateTimeStylesAttribute.cs new file mode 100644 index 0000000..42fd789 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/DateTimeStylesAttribute.cs @@ -0,0 +1,44 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Globalization; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// The <see cref="DateTimeStyles"/> to use when type converting. + /// This is used when doing any <see cref="DateTime"/> conversions. + /// </summary> + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)] + public class DateTimeStylesAttribute : Attribute, IMemberMapper, IParameterMapper + { + /// <summary> + /// Gets the date time styles. + /// </summary> + public DateTimeStyles DateTimeStyles { get; private set; } + + /// <summary> + /// The <see cref="DateTimeStyles"/> to use when type converting. + /// This is used when doing any <see cref="DateTime"/> conversions. + /// </summary> + /// <param name="dateTimeStyles">The date time styles.</param> + public DateTimeStylesAttribute(DateTimeStyles dateTimeStyles) + { + DateTimeStyles = dateTimeStyles; + } + + /// <inheritdoc /> + public void ApplyTo(MemberMap memberMap) + { + memberMap.Data.TypeConverterOptions.DateTimeStyle = DateTimeStyles; + } + + /// <inheritdoc /> + public void ApplyTo(ParameterMap parameterMap) + { + parameterMap.Data.TypeConverterOptions.DateTimeStyle = DateTimeStyles; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/DefaultAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/DefaultAttribute.cs new file mode 100644 index 0000000..f2e4e46 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/DefaultAttribute.cs @@ -0,0 +1,45 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// The default value that will be used when reading when + /// the CSV field is empty. + /// </summary> + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)] + public class DefaultAttribute : Attribute, IMemberMapper, IParameterMapper + { + /// <summary> + /// Gets the default value. + /// </summary> + public object Default { get; private set; } + + /// <summary> + /// The default value that will be used when reading when + /// the CSV field is empty. + /// </summary> + /// <param name="defaultValue">The default value</param> + public DefaultAttribute(object defaultValue) + { + Default = defaultValue; + } + + /// <inheritdoc /> + public void ApplyTo(MemberMap memberMap) + { + memberMap.Data.Default = Default; + memberMap.Data.IsDefaultSet = true; + } + + /// <inheritdoc /> + public void ApplyTo(ParameterMap parameterMap) + { + parameterMap.Data.Default = Default; + parameterMap.Data.IsDefaultSet = true; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/DelimiterAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/DelimiterAttribute.cs new file mode 100644 index 0000000..b8b53f6 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/DelimiterAttribute.cs @@ -0,0 +1,35 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// The delimiter used to separate fields. + /// </summary> + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public class DelimiterAttribute : Attribute, IClassMapper + { + /// <summary> + /// Gets the delimiter. + /// </summary> + public string Delimiter { get; private set; } + + /// <summary> + /// The delimiter used to separate fields. + /// </summary> + /// <param name="delimiter">The delimiter.</param> + public DelimiterAttribute(string delimiter) + { + Delimiter = delimiter; + } + + /// <inheritdoc /> + public void ApplyTo(CsvConfiguration configuration) + { + configuration.Delimiter = Delimiter; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/DetectColumnCountChangesAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/DetectColumnCountChangesAttribute.cs new file mode 100644 index 0000000..f31aaf8 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/DetectColumnCountChangesAttribute.cs @@ -0,0 +1,40 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// A value indicating whether changes in the column + /// count should be detected. If true, a <see cref="BadDataException"/> + /// will be thrown if a different column count is detected. + /// </summary> + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public class DetectColumnCountChangesAttribute : Attribute, IClassMapper + { + /// <summary> + /// A value indicating whether changes in the column + /// count should be detected. If true, a <see cref="BadDataException"/> + /// will be thrown if a different column count is detected. + /// </summary> + public bool DetectColumnCountChanges { get; private set; } + + /// <summary> + /// A value indicating whether changes in the column + /// count should be detected. If true, a <see cref="BadDataException"/> + /// will be thrown if a different column count is detected. + /// </summary> + public DetectColumnCountChangesAttribute(bool detectColumnCountChanges) + { + DetectColumnCountChanges = detectColumnCountChanges; + } + + /// <inheritdoc /> + public void ApplyTo(CsvConfiguration configuration) + { + configuration.DetectColumnCountChanges = DetectColumnCountChanges; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/DetectDelimiterAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/DetectDelimiterAttribute.cs new file mode 100644 index 0000000..2c7da45 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/DetectDelimiterAttribute.cs @@ -0,0 +1,35 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// Detect the delimiter instead of using the delimiter from configuration. + /// Default is <c>false</c>. + /// </summary> + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public class DetectDelimiterAttribute : Attribute, IClassMapper + { + /// <summary> + /// Detect the delimiter instead of using the delimiter from configuration. + /// </summary> + public bool DetectDelimiter { get; private set; } + + /// <summary> + /// Detect the delimiter instead of using the delimiter from configuration. + /// </summary> + public DetectDelimiterAttribute(bool detectDelimiter) + { + DetectDelimiter = detectDelimiter; + } + + /// <inheritdoc /> + public void ApplyTo(CsvConfiguration configuration) + { + configuration.DetectDelimiter = DetectDelimiter; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/DetectDelimiterValuesAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/DetectDelimiterValuesAttribute.cs new file mode 100644 index 0000000..af641df --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/DetectDelimiterValuesAttribute.cs @@ -0,0 +1,37 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Text.RegularExpressions; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// The possible delimiter values used when detecting the delimiter. + /// Default is [",", ";", "|", "\t"]. + /// </summary> + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public class DetectDelimiterValuesAttribute : Attribute, IClassMapper + { + /// <summary> + /// The possible delimiter values used when detecting the delimiter. + /// </summary> + public string[] DetectDelimiterValues { get; private set; } + + /// <summary> + /// The possible delimiter values used when detecting the delimiter. + /// </summary> + /// <param name="detectDelimiterValues">Whitespace separated list of values.</param> + public DetectDelimiterValuesAttribute(string detectDelimiterValues) + { + DetectDelimiterValues = Regex.Split(detectDelimiterValues, @"\s+"); + } + + /// <inheritdoc /> + public void ApplyTo(CsvConfiguration configuration) + { + configuration.DetectDelimiterValues = DetectDelimiterValues; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/EncodingAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/EncodingAttribute.cs new file mode 100644 index 0000000..ee378ba --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/EncodingAttribute.cs @@ -0,0 +1,36 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Text; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// The encoding used when counting bytes. + /// </summary> + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public class EncodingAttribute : Attribute, IClassMapper + { + /// <summary> + /// Gets the encoding used when counting bytes. + /// </summary> + public Encoding Encoding { get; private set; } + + /// <summary> + /// The encoding used when counting bytes. + /// </summary> + /// <param name="encoding">The encoding.</param> + public EncodingAttribute(string encoding) + { + Encoding = Encoding.GetEncoding(encoding); + } + + /// <inheritdoc /> + public void ApplyTo(CsvConfiguration configuration) + { + configuration.Encoding = Encoding; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/EnumIgnoreCaseAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/EnumIgnoreCaseAttribute.cs new file mode 100644 index 0000000..c2b25c9 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/EnumIgnoreCaseAttribute.cs @@ -0,0 +1,41 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// Ignore case when parsing enums. + /// </summary> + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)] + public class EnumIgnoreCaseAttribute : Attribute, IMemberMapper, IMemberReferenceMapper, IParameterMapper + { + /// <inheritdoc/> + public void ApplyTo(MemberMap memberMap) + { + memberMap.Data.TypeConverterOptions.EnumIgnoreCase = true; + } + + /// <inheritdoc/> + public void ApplyTo(MemberReferenceMap referenceMap) + { + foreach (var memberMap in referenceMap.Data.Mapping.MemberMaps) + { + ApplyTo(memberMap); + } + } + + /// <inheritdoc/> + public void ApplyTo(ParameterMap parameterMap) + { + parameterMap.Data.TypeConverterOptions.EnumIgnoreCase = true; + } + + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/EscapeAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/EscapeAttribute.cs new file mode 100644 index 0000000..0d20d50 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/EscapeAttribute.cs @@ -0,0 +1,35 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// The escape character used to escape a quote inside a field. + /// </summary> + [AttributeUsage( AttributeTargets.Class, AllowMultiple = false, Inherited = true )] + public class EscapeAttribute : Attribute, IClassMapper + { + /// <summary> + /// Gets the escape character used to escape a quote inside a field. + /// </summary> + public char Escape { get; private set; } + + /// <summary> + /// The escape character used to escape a quote inside a field. + /// </summary> + /// <param name="escape">The escape character.</param> + public EscapeAttribute( char escape ) + { + Escape = escape; + } + + /// <inheritdoc /> + public void ApplyTo(CsvConfiguration configuration) + { + configuration.Escape = Escape; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/ExceptionMessagesContainRawDataAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/ExceptionMessagesContainRawDataAttribute.cs new file mode 100644 index 0000000..2cb9608 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/ExceptionMessagesContainRawDataAttribute.cs @@ -0,0 +1,39 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// A value indicating if exception messages contain raw CSV data. + /// <c>true</c> if exception contain raw CSV data, otherwise <c>false</c>. + /// Default is <c>true</c>. + /// </summary> + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public class ExceptionMessagesContainRawDataAttribute : Attribute, IClassMapper + { + /// <summary> + /// A value indicating if exception messages contain raw CSV data. + /// <c>true</c> if exception contain raw CSV data, otherwise <c>false</c>. + /// </summary> + public bool ExceptionMessagesContainRawData { get; private set; } + + /// <summary> + /// A value indicating if exception messages contain raw CSV data. + /// <c>true</c> if exception contain raw CSV data, otherwise <c>false</c>. + /// </summary> + /// <param name="exceptionMessagesContainRawData"></param> + public ExceptionMessagesContainRawDataAttribute(bool exceptionMessagesContainRawData) + { + ExceptionMessagesContainRawData = exceptionMessagesContainRawData; + } + + /// <inheritdoc /> + public void ApplyTo(CsvConfiguration configuration) + { + configuration.ExceptionMessagesContainRawData = ExceptionMessagesContainRawData; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/FormatAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/FormatAttribute.cs new file mode 100644 index 0000000..b42d8ed --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/FormatAttribute.cs @@ -0,0 +1,50 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// The string format to be used when type converting. + /// </summary> + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)] + public class FormatAttribute : Attribute, IMemberMapper, IParameterMapper + { + /// <summary> + /// Gets the formats. + /// </summary> + public string[] Formats { get; private set; } + + /// <summary> + /// The string format to be used when type converting. + /// </summary> + /// <param name="format">The format.</param> + public FormatAttribute(string format) + { + Formats = new string[] { format }; + } + + /// <summary> + /// The string format to be used when type converting. + /// </summary> + /// <param name="formats">The formats.</param> + public FormatAttribute(params string[] formats) + { + Formats = formats; + } + + /// <inheritdoc /> + public void ApplyTo(MemberMap memberMap) + { + memberMap.Data.TypeConverterOptions.Formats = Formats; + } + + /// <inheritdoc /> + public void ApplyTo(ParameterMap parameterMap) + { + parameterMap.Data.TypeConverterOptions.Formats = Formats; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/HasHeaderRecordAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/HasHeaderRecordAttribute.cs new file mode 100644 index 0000000..b0d93ae --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/HasHeaderRecordAttribute.cs @@ -0,0 +1,35 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// A value indicating if the CSV file has a header record. + /// </summary> + [AttributeUsage( AttributeTargets.Class, AllowMultiple = false, Inherited = true )] + public class HasHeaderRecordAttribute : Attribute, IClassMapper + { + /// <summary> + /// Gets a value indicating if the CSV file has a header record. + /// </summary> + public bool HasHeaderRecord { get; private set; } + + /// <summary> + /// A value indicating if the CSV file has a header record. + /// </summary> + /// <param name="hasHeaderRecord">A value indicating if the CSV file has a header record.</param> + public HasHeaderRecordAttribute( bool hasHeaderRecord ) + { + HasHeaderRecord = hasHeaderRecord; + } + + /// <inheritdoc /> + public void ApplyTo(CsvConfiguration configuration) + { + configuration.HasHeaderRecord = HasHeaderRecord; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/HeaderPrefixAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/HeaderPrefixAttribute.cs new file mode 100644 index 0000000..4ae8227 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/HeaderPrefixAttribute.cs @@ -0,0 +1,73 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// Appends a prefix to the header of each field of the reference member. + /// </summary> + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)] + public class HeaderPrefixAttribute : Attribute, IMemberReferenceMapper, IParameterReferenceMapper + { + /// <summary> + /// Gets the prefix. + /// </summary> + public string? Prefix { get; private set; } + + /// <summary> + /// Gets a value indicating if the prefix should inherit parent prefixes. + /// </summary> + public bool Inherit { get; private set; } + + /// <summary> + /// Appends a prefix to the header of each field of the reference member. + /// </summary> + public HeaderPrefixAttribute() { } + + /// <summary> + /// Appends a prefix to the header of each field of the reference member. + /// </summary> + /// <param name="prefix">The prefix.</param> + public HeaderPrefixAttribute(string prefix) + { + Prefix = prefix; + } + + /// <summary> + /// Appends a prefix to the header of each field of the reference member. + /// </summary> + /// <param name="inherit">Inherits parent object prefixes.</param> + public HeaderPrefixAttribute(bool inherit) + { + Inherit = inherit; + } + + /// <summary> + /// Appends a prefix to the header of each field of the reference member. + /// </summary> + /// <param name="prefix">The prefix.</param> + /// <param name="inherit">Inherits parent object prefixes.</param> + public HeaderPrefixAttribute(string prefix, bool inherit) + { + Prefix = prefix; + Inherit = inherit; + } + + /// <inheritdoc /> + public void ApplyTo(MemberReferenceMap referenceMap) + { + referenceMap.Data.Inherit = Inherit; + referenceMap.Data.Prefix = Prefix ?? referenceMap.Data.Member.Name + "."; + } + + /// <inheritdoc /> + public void ApplyTo(ParameterReferenceMap referenceMap) + { + referenceMap.Data.Inherit = Inherit; + referenceMap.Data.Prefix = Prefix ?? referenceMap.Data.Parameter.Name + "."; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/IClassMapper.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/IClassMapper.cs new file mode 100644 index 0000000..d395ac9 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/IClassMapper.cs @@ -0,0 +1,19 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// Defines methods to enable pluggable configuration. + /// </summary> + public interface IClassMapper + { + /// <summary> + /// Applies configuration. + /// </summary> + /// <param name="configuration">The configuration to apply to.</param> + void ApplyTo(CsvConfiguration configuration); + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/IMemberMapper.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/IMemberMapper.cs new file mode 100644 index 0000000..b8701f1 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/IMemberMapper.cs @@ -0,0 +1,20 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// Defines methods to enable pluggable configuration of member mapping. + /// </summary> + public interface IMemberMapper + { + /// <summary> + /// Applies configuration to the given <see cref="MemberMap"/>. + /// </summary> + /// <param name="memberMap">The member map.</param> + void ApplyTo(MemberMap memberMap); + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/IMemberReferenceMapper.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/IMemberReferenceMapper.cs new file mode 100644 index 0000000..c9c4d32 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/IMemberReferenceMapper.cs @@ -0,0 +1,20 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// Defines methods to enable pluggable configuration of member reference mapping. + /// </summary> + public interface IMemberReferenceMapper + { + /// <summary> + /// Applies configuration to the given <see cref="MemberReferenceMap" />. + /// </summary> + /// <param name="referenceMap">The reference map.</param> + void ApplyTo(MemberReferenceMap referenceMap); + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/IParameterMapper.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/IParameterMapper.cs new file mode 100644 index 0000000..0b5c289 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/IParameterMapper.cs @@ -0,0 +1,24 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// Defines methods to enable pluggable configuration of parameter mapping. + /// </summary> + public interface IParameterMapper + { + /// <summary> + /// Applies configuration to the given <see cref="ParameterMap"/>. + /// </summary> + /// <param name="parameterMap">The parameter map.</param> + void ApplyTo(ParameterMap parameterMap); + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/IParameterReferenceMapper.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/IParameterReferenceMapper.cs new file mode 100644 index 0000000..ea4fc50 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/IParameterReferenceMapper.cs @@ -0,0 +1,24 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// Defines methods to enable pluggable configuration of parameter reference mapping. + /// </summary> + public interface IParameterReferenceMapper + { + /// <summary> + /// Applies configuration to the given <see cref="ParameterReferenceMap" />. + /// </summary> + /// <param name="referenceMap">The reference map.</param> + void ApplyTo(ParameterReferenceMap referenceMap); + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/IgnoreAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/IgnoreAttribute.cs new file mode 100644 index 0000000..41a199a --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/IgnoreAttribute.cs @@ -0,0 +1,41 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Reflection; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// Ignore the member when reading and writing. + /// If this member has already been mapped as a reference + /// member, either by a class map, or by automapping, calling + /// this method will not ignore all the child members down the + /// tree that have already been mapped. + /// </summary> + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)] + public class IgnoreAttribute : Attribute, IMemberMapper, IMemberReferenceMapper, IParameterMapper + { + /// <inheritdoc /> + public void ApplyTo(MemberMap memberMap) + { + memberMap.Data.Ignore = true; + } + + /// <inheritdoc /> + public void ApplyTo(MemberReferenceMap referenceMap) + { + foreach (var memberMap in referenceMap.Data.Mapping.MemberMaps) + { + ApplyTo(memberMap); + } + } + + /// <inheritdoc /> + public void ApplyTo(ParameterMap parameterMap) + { + parameterMap.Data.Ignore = true; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/IgnoreBaseAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/IgnoreBaseAttribute.cs new file mode 100644 index 0000000..066be2e --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/IgnoreBaseAttribute.cs @@ -0,0 +1,20 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// Ignores base classes when auto mapping. + /// </summary> + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public class IgnoreBaseAttribute : Attribute + { + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/IgnoreBlankLinesAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/IgnoreBlankLinesAttribute.cs new file mode 100644 index 0000000..c270568 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/IgnoreBlankLinesAttribute.cs @@ -0,0 +1,35 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// A value indicating if blank lines should be ignored when reading. + /// </summary> + [AttributeUsage( AttributeTargets.Class, AllowMultiple = false, Inherited = true )] + public class IgnoreBlankLinesAttribute : Attribute, IClassMapper + { + /// <summary> + /// Gets a value indicating if blank lines should be ignored when reading. + /// </summary> + public bool IgnoreBlankLines { get; private set; } + + /// <summary> + /// A value indicating if blank lines should be ignored when reading. + /// </summary> + /// <param name="ignoreBlankLines">The Ignore Blank Lines Flag.</param> + public IgnoreBlankLinesAttribute( bool ignoreBlankLines ) + { + IgnoreBlankLines = ignoreBlankLines; + } + + /// <inheritdoc /> + public void ApplyTo(CsvConfiguration configuration) + { + configuration.IgnoreBlankLines = IgnoreBlankLines; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/IgnoreReferencesAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/IgnoreReferencesAttribute.cs new file mode 100644 index 0000000..05e7b0e --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/IgnoreReferencesAttribute.cs @@ -0,0 +1,41 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// Gets a value indicating whether references + /// should be ignored when auto mapping. <c>true</c> to ignore + /// references, otherwise <c>false</c>. Default is false. + /// </summary> + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public class IgnoreReferencesAttribute : Attribute, IClassMapper + { + /// <summary> + /// Gets a value indicating whether references + /// should be ignored when auto mapping. <c>true</c> to ignore + /// references, otherwise <c>false</c>. Default is false. + /// </summary> + public bool IgnoreReferences { get; private set; } + + /// <summary> + /// Gets a value indicating whether references + /// should be ignored when auto mapping. <c>true</c> to ignore + /// references, otherwise <c>false</c>. Default is false. + /// </summary> + /// <param name="ignoreReferences">Ignore references value.</param> + public IgnoreReferencesAttribute(bool ignoreReferences) + { + IgnoreReferences = ignoreReferences; + } + + /// <inheritdoc /> + public void ApplyTo(CsvConfiguration configuration) + { + configuration.IgnoreReferences = IgnoreReferences; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/IncludePrivateMembersAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/IncludePrivateMembersAttribute.cs new file mode 100644 index 0000000..92c7c1b --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/IncludePrivateMembersAttribute.cs @@ -0,0 +1,35 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// A value indicating if private member should be read from and written to. + /// </summary> + [AttributeUsage( AttributeTargets.Class, AllowMultiple = false, Inherited = true )] + public class IncludePrivateMembersAttribute : Attribute, IClassMapper + { + /// <summary> + /// Gets a value indicating if private member should be read from and written to. + /// </summary> + public bool IncludePrivateMembers { get; private set; } + + /// <summary> + /// A value indicating if private member should be read from and written to. + /// </summary> + /// <param name="includePrivateMembers">The Include Private Members Flag.</param> + public IncludePrivateMembersAttribute( bool includePrivateMembers ) + { + IncludePrivateMembers = includePrivateMembers; + } + + /// <inheritdoc /> + public void ApplyTo(CsvConfiguration configuration) + { + configuration.IncludePrivateMembers = IncludePrivateMembers; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/IndexAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/IndexAttribute.cs new file mode 100644 index 0000000..e469741 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/IndexAttribute.cs @@ -0,0 +1,57 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// When reading, is used to get the field at + /// the given index. When writing, the fields + /// will be written in the order of the field + /// indexes. + /// </summary> + [AttributeUsage( AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true )] + public class IndexAttribute : Attribute, IMemberMapper, IParameterMapper + { + /// <summary> + /// Gets the index. + /// </summary> + public int Index { get; private set; } + + /// <summary> + /// Gets the index end. + /// </summary> + public int IndexEnd { get; private set; } + + /// <summary> + /// When reading, is used to get the field at + /// the given index. When writing, the fields + /// will be written in the order of the field + /// indexes. + /// </summary> + /// <param name="index">The index.</param> + /// <param name="indexEnd">The index end.</param> + public IndexAttribute( int index, int indexEnd = -1 ) + { + Index = index; + IndexEnd = indexEnd; + } + + /// <inheritdoc /> + public void ApplyTo(MemberMap memberMap) + { + memberMap.Data.Index = Index; + memberMap.Data.IndexEnd = IndexEnd; + memberMap.Data.IsIndexSet = true; + } + + /// <inheritdoc /> + public void ApplyTo(ParameterMap parameterMap) + { + parameterMap.Data.Index = Index; + parameterMap.Data.IsIndexSet = true; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/InjectionCharactersAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/InjectionCharactersAttribute.cs new file mode 100644 index 0000000..66f6964 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/InjectionCharactersAttribute.cs @@ -0,0 +1,37 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Linq; +using System.Text.RegularExpressions; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// Gets the characters that are used for injection attacks. + /// </summary> + public class InjectionCharactersAttribute : Attribute, IClassMapper + { + /// <summary> + /// Gets the characters that are used for injection attacks. + /// Default is '=', '@', '+', '-', '\t', '\r'. + /// </summary> + public char[] InjectionCharacters { get; private set; } + + /// <summary> + /// Gets the characters that are used for injection attacks. + /// </summary> + /// <param name="injectionCharacters"></param> + public InjectionCharactersAttribute(string injectionCharacters) + { + InjectionCharacters = Regex.Split(injectionCharacters, @"\s+").Select(s => s[0]).ToArray(); + } + + /// <inheritdoc /> + public void ApplyTo(CsvConfiguration configuration) + { + configuration.InjectionCharacters = InjectionCharacters; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/InjectionEscapeCharacterAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/InjectionEscapeCharacterAttribute.cs new file mode 100644 index 0000000..1db163d --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/InjectionEscapeCharacterAttribute.cs @@ -0,0 +1,35 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// The character used to escape a detected injection. + /// </summary> + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public class InjectionEscapeCharacterAttribute : Attribute, IClassMapper + { + /// <summary> + /// The character used to escape a detected injection. + /// </summary> + public char InjectionEscapeCharacter { get; private set; } + + /// <summary> + /// The character used to escape a detected injection. + /// </summary> + /// <param name="injectionEscapeCharacter"></param> + public InjectionEscapeCharacterAttribute(char injectionEscapeCharacter) + { + InjectionEscapeCharacter = injectionEscapeCharacter; + } + + /// <inheritdoc /> + public void ApplyTo(CsvConfiguration configuration) + { + configuration.InjectionEscapeCharacter = InjectionEscapeCharacter; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/InjectionOptionsAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/InjectionOptionsAttribute.cs new file mode 100644 index 0000000..db97300 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/InjectionOptionsAttribute.cs @@ -0,0 +1,35 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// The injection options. + /// </summary> + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public class InjectionOptionsAttribute : Attribute, IClassMapper + { + /// <summary> + /// The injection options. + /// </summary> + public InjectionOptions InjectionOptions { get; private set; } + + /// <summary> + /// The injection options. + /// </summary> + /// <param name="injectionOptions"></param> + public InjectionOptionsAttribute(InjectionOptions injectionOptions) + { + InjectionOptions = injectionOptions; + } + + /// <inheritdoc /> + public void ApplyTo(CsvConfiguration configuration) + { + configuration.InjectionOptions = InjectionOptions; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/LineBreakInQuotedFieldIsBadDataAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/LineBreakInQuotedFieldIsBadDataAttribute.cs new file mode 100644 index 0000000..db95cbc --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/LineBreakInQuotedFieldIsBadDataAttribute.cs @@ -0,0 +1,39 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// A value indicating if a line break found in a quote field should + /// be considered bad data. <c>true</c> to consider a line break bad data, otherwise <c>false</c>. + /// Defaults to false. + /// </summary> + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public class LineBreakInQuotedFieldIsBadDataAttribute : Attribute, IClassMapper + { + /// <summary> + /// A value indicating if a line break found in a quote field should + /// be considered bad data. <c>true</c> to consider a line break bad data, otherwise <c>false</c>. + /// </summary> + public bool LineBreakInQuotedFieldIsBadData { get; private set; } + + /// <summary> + /// A value indicating if a line break found in a quote field should + /// be considered bad data. <c>true</c> to consider a line break bad data, otherwise <c>false</c>. + /// </summary> + /// <param name="lineBreakInQuotedFieldIsBadData"></param> + public LineBreakInQuotedFieldIsBadDataAttribute(bool lineBreakInQuotedFieldIsBadData) + { + LineBreakInQuotedFieldIsBadData = lineBreakInQuotedFieldIsBadData; + } + + /// <inheritdoc /> + public void ApplyTo(CsvConfiguration configuration) + { + configuration.LineBreakInQuotedFieldIsBadData = LineBreakInQuotedFieldIsBadData; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/MaxFieldSizeAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/MaxFieldSizeAttribute.cs new file mode 100644 index 0000000..1d5c837 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/MaxFieldSizeAttribute.cs @@ -0,0 +1,40 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// Gets or sets the maximum size of a field. + /// Defaults to 0, indicating maximum field size is not checked. + /// </summary> + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public class MaxFieldSizeAttribute : Attribute, IClassMapper + { + /// <summary> + /// Gets or sets the maximum size of a field. + /// </summary> + public double MaxFieldSize { get; private set; } + + /// <summary> + /// Gets or sets the maximum size of a field. + /// </summary> + /// <param name="maxFieldSize"></param> + public MaxFieldSizeAttribute(double maxFieldSize) + { + MaxFieldSize = maxFieldSize; + } + + /// <inheritdoc /> + public void ApplyTo(CsvConfiguration configuration) + { + configuration.MaxFieldSize = MaxFieldSize; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/MemberTypesAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/MemberTypesAttribute.cs new file mode 100644 index 0000000..e07e86f --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/MemberTypesAttribute.cs @@ -0,0 +1,40 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// The member types that are used when auto mapping. + /// MemberTypes are flags, so you can choose more than one. + /// Default is Properties. + /// </summary> + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public class MemberTypesAttribute : Attribute, IClassMapper + { + /// <summary> + /// The member types that are used when auto mapping. + /// MemberTypes are flags, so you can choose more than one. + /// Default is Properties. + /// </summary> + public MemberTypes MemberTypes { get; private set; } + + /// <summary> + /// The member types that are used when auto mapping. + /// MemberTypes are flags, so you can choose more than one. + /// Default is Properties. + /// </summary> + public MemberTypesAttribute(MemberTypes memberTypes) + { + MemberTypes = memberTypes; + } + + /// <inheritdoc /> + public void ApplyTo(CsvConfiguration configuration) + { + configuration.MemberTypes = MemberTypes; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/ModeAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/ModeAttribute.cs new file mode 100644 index 0000000..448a543 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/ModeAttribute.cs @@ -0,0 +1,38 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// The mode. + /// See <see cref="CsvMode"/> for more details. + /// </summary> + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public class ModeAttribute : Attribute, IClassMapper + { + /// <summary> + /// The mode. + /// See <see cref="CsvMode"/> for more details. + /// </summary> + public CsvMode Mode { get; private set; } + + /// <summary> + /// The mode. + /// See <see cref="CsvMode"/> for more details. + /// </summary> + /// <param name="mode"></param> + public ModeAttribute(CsvMode mode) + { + Mode = mode; + } + + /// <inheritdoc /> + public void ApplyTo(CsvConfiguration configuration) + { + configuration.Mode = Mode; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/NameAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/NameAttribute.cs new file mode 100644 index 0000000..f1220e4 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/NameAttribute.cs @@ -0,0 +1,77 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// When reading, is used to get the field + /// at the index of the name if there was a + /// header specified. It will look for the + /// first name match in the order listed. + /// When writing, sets the name of the + /// field in the header record. + /// The first name will be used. + /// </summary> + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)] + public class NameAttribute : Attribute, IMemberMapper, IParameterMapper + { + /// <summary> + /// Gets the names. + /// </summary> + public string[] Names { get; private set; } + + /// <summary> + /// When reading, is used to get the field + /// at the index of the name if there was a + /// header specified. It will look for the + /// first name match in the order listed. + /// When writing, sets the name of the + /// field in the header record. + /// The first name will be used. + /// </summary> + /// <param name="name">The name</param> + public NameAttribute(string name) + { + Names = new string[] { name }; + } + + /// <summary> + /// When reading, is used to get the field + /// at the index of the name if there was a + /// header specified. It will look for the + /// first name match in the order listed. + /// When writing, sets the name of the + /// field in the header record. + /// The first name will be used. + /// </summary> + /// <param name="names">The names.</param> + public NameAttribute(params string[] names) + { + if (names == null || names.Length == 0) + { + throw new ArgumentNullException(nameof(names)); + } + + Names = names; + } + + /// <inheritdoc /> + public void ApplyTo(MemberMap memberMap) + { + memberMap.Data.Names.Clear(); + memberMap.Data.Names.AddRange(Names); + memberMap.Data.IsNameSet = true; + } + + /// <inheritdoc /> + public void ApplyTo(ParameterMap parameterMap) + { + parameterMap.Data.Names.Clear(); + parameterMap.Data.Names.AddRange(Names); + parameterMap.Data.IsNameSet = true; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/NameIndexAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/NameIndexAttribute.cs new file mode 100644 index 0000000..e3d1dfa --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/NameIndexAttribute.cs @@ -0,0 +1,45 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// When reading, is used to get the + /// index of the name used when there + /// are multiple names that are the same. + /// </summary> + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)] + public class NameIndexAttribute : Attribute, IMemberMapper, IParameterMapper + { + /// <summary> + /// The name index. + /// </summary> + public int NameIndex { get; private set; } + + /// <summary> + /// When reading, is used to get the + /// index of the name used when there + /// are multiple names that are the same. + /// </summary> + /// <param name="nameIndex">The name index.</param> + public NameIndexAttribute(int nameIndex) + { + NameIndex = nameIndex; + } + + /// <inheritdoc /> + public void ApplyTo(MemberMap memberMap) + { + memberMap.Data.NameIndex = NameIndex; + } + + /// <inheritdoc /> + public void ApplyTo(ParameterMap parameterMap) + { + parameterMap.Data.NameIndex = NameIndex; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/NewLineAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/NewLineAttribute.cs new file mode 100644 index 0000000..a2bdbd2 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/NewLineAttribute.cs @@ -0,0 +1,39 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// The newline string to use. Default is \r\n (CRLF). + /// When writing, this value is always used. + /// When reading, this value is only used if explicitly set. + /// If not set, the parser uses one of \r\n, \r, or \n. + /// </summary> + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public class NewLineAttribute : Attribute, IClassMapper + { + /// The newline string to use. Default is \r\n (CRLF). + /// When writing, this value is always used. + /// When reading, this value is only used if explicitly set. + /// If not set, the parser uses one of \r\n, \r, or \n. + public string NewLine { get; private set; } + + /// The newline string to use. Default is \r\n (CRLF). + /// When writing, this value is always used. + /// When reading, this value is only used if explicitly set. + /// If not set, the parser uses one of \r\n, \r, or \n. + public NewLineAttribute(string newLine) + { + NewLine = newLine; + } + + /// <inheritdoc /> + public void ApplyTo(CsvConfiguration configuration) + { + configuration.NewLine = NewLine; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/NullValuesAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/NullValuesAttribute.cs new file mode 100644 index 0000000..8c87e28 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/NullValuesAttribute.cs @@ -0,0 +1,52 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// The string values used to represent null when converting. + /// </summary> + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)] + public class NullValuesAttribute : Attribute, IMemberMapper, IParameterMapper + { + /// <summary> + /// Gets the null values. + /// </summary> + public string[] NullValues { get; private set; } + + /// <summary> + /// The string values used to represent null when converting. + /// </summary> + /// <param name="nullValue">The null values.</param> + public NullValuesAttribute(string nullValue) + { + NullValues = new string[] { nullValue }; + } + + /// <summary> + /// The string values used to represent null when converting. + /// </summary> + /// <param name="nullValues">The null values.</param> + public NullValuesAttribute(params string[] nullValues) + { + NullValues = nullValues; + } + + /// <inheritdoc /> + public void ApplyTo(MemberMap memberMap) + { + memberMap.Data.TypeConverterOptions.NullValues.Clear(); + memberMap.Data.TypeConverterOptions.NullValues.AddRange(NullValues); + } + + /// <inheritdoc /> + public void ApplyTo(ParameterMap parameterMap) + { + parameterMap.Data.TypeConverterOptions.NullValues.Clear(); + parameterMap.Data.TypeConverterOptions.NullValues.AddRange(NullValues); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/NumberStylesAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/NumberStylesAttribute.cs new file mode 100644 index 0000000..1cd37fb --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/NumberStylesAttribute.cs @@ -0,0 +1,44 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Globalization; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// The <see cref="NumberStyles"/> to use when type converting. + /// This is used when doing any number conversions. + /// </summary> + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)] + public class NumberStylesAttribute : Attribute, IMemberMapper, IParameterMapper + { + /// <summary> + /// Gets the number styles. + /// </summary> + public NumberStyles NumberStyles { get; private set; } + + /// <summary> + /// The <see cref="NumberStyles"/> to use when type converting. + /// This is used when doing any number conversions. + /// </summary> + /// <param name="numberStyles">The number styles.</param> + public NumberStylesAttribute(NumberStyles numberStyles) + { + NumberStyles = numberStyles; + } + + /// <inheritdoc /> + public void ApplyTo(MemberMap memberMap) + { + memberMap.Data.TypeConverterOptions.NumberStyles = NumberStyles; + } + + /// <inheritdoc /> + public void ApplyTo(ParameterMap parameterMap) + { + parameterMap.Data.TypeConverterOptions.NumberStyles = NumberStyles; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/OptionalAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/OptionalAttribute.cs new file mode 100644 index 0000000..5348c85 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/OptionalAttribute.cs @@ -0,0 +1,27 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// Ignore the member when reading if no matching field name can be found. + /// </summary> + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)] + public class OptionalAttribute : Attribute, IMemberMapper, IParameterMapper + { + /// <inheritdoc /> + public void ApplyTo(MemberMap memberMap) + { + memberMap.Data.IsOptional = true; + } + + /// <inheritdoc /> + public void ApplyTo(ParameterMap parameterMap) + { + parameterMap.Data.IsOptional = true; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/ProcessFieldBufferSizeAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/ProcessFieldBufferSizeAttribute.cs new file mode 100644 index 0000000..81f6178 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/ProcessFieldBufferSizeAttribute.cs @@ -0,0 +1,36 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// The size of the buffer used when processing fields. + /// Default is 1024. + /// </summary> + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public class ProcessFieldBufferSizeAttribute : Attribute, IClassMapper + { + /// <summary> + /// The size of the buffer used when processing fields. + /// </summary> + public int ProcessFieldBufferSize { get; private set; } + + /// <summary> + /// The size of the buffer used when processing fields. + /// </summary> + /// <param name="processFieldBufferSize"></param> + public ProcessFieldBufferSizeAttribute(int processFieldBufferSize) + { + ProcessFieldBufferSize = processFieldBufferSize; + } + + /// <inheritdoc /> + public void ApplyTo(CsvConfiguration configuration) + { + configuration.ProcessFieldBufferSize = ProcessFieldBufferSize; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/QuoteAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/QuoteAttribute.cs new file mode 100644 index 0000000..93b5887 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/QuoteAttribute.cs @@ -0,0 +1,35 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// The character used to quote fields. + /// </summary> + [AttributeUsage( AttributeTargets.Class, AllowMultiple = false, Inherited = true )] + public class QuoteAttribute : Attribute, IClassMapper + { + /// <summary> + /// Gets the character used to quote fields. + /// </summary> + public char Quote { get; private set; } + + /// <summary> + /// The character used to quote fields. + /// </summary> + /// <param name="quote">The quote character.</param> + public QuoteAttribute( char quote ) + { + Quote = quote; + } + + /// <inheritdoc /> + public void ApplyTo(CsvConfiguration configuration) + { + configuration.Quote = Quote; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/TrimOptionsAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/TrimOptionsAttribute.cs new file mode 100644 index 0000000..1b2f645 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/TrimOptionsAttribute.cs @@ -0,0 +1,35 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// The fields trimming options. + /// </summary> + [AttributeUsage( AttributeTargets.Class, AllowMultiple = false, Inherited = true )] + public class TrimOptionsAttribute : Attribute, IClassMapper + { + /// <summary> + /// Gets the fields trimming options. + /// </summary> + public TrimOptions TrimOptions { get; private set; } + + /// <summary> + /// The fields trimming options. + /// </summary> + /// <param name="trimOptions">The TrimOptions.</param> + public TrimOptionsAttribute( TrimOptions trimOptions ) + { + TrimOptions = trimOptions; + } + + /// <inheritdoc /> + public void ApplyTo(CsvConfiguration configuration) + { + configuration.TrimOptions = TrimOptions; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/TypeConverterAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/TypeConverterAttribute.cs new file mode 100644 index 0000000..f3900ec --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/TypeConverterAttribute.cs @@ -0,0 +1,57 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using CsvHelper.TypeConversion; +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// Specifies the <see cref="TypeConverter"/> to use + /// when converting the member to and from a CSV field. + /// </summary> + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)] + public class TypeConverterAttribute : Attribute, IMemberMapper, IParameterMapper + { + /// <summary> + /// Gets the type converter. + /// </summary> + public ITypeConverter TypeConverter { get; private set; } + + /// <summary> + /// Specifies the <see cref="TypeConverter"/> to use + /// when converting the member to and from a CSV field. + /// </summary> + /// <param name="typeConverterType">The type of the <see cref="ITypeConverter"/>.</param> + public TypeConverterAttribute(Type typeConverterType) : this(typeConverterType, new object[0]) { } + + /// <summary> + /// Specifies the <see cref="TypeConverter"/> to use + /// when converting the member to and from a CSV field. + /// </summary> + /// <param name="typeConverterType">The type of the <see cref="ITypeConverter"/>.</param> + /// <param name="constructorArgs">Type constructor arguments for the type converter.</param> + public TypeConverterAttribute(Type typeConverterType, params object[] constructorArgs) + { + if (typeConverterType == null) + { + throw new ArgumentNullException(nameof(typeConverterType)); + } + + TypeConverter = ObjectResolver.Current.Resolve(typeConverterType, constructorArgs) as ITypeConverter ?? throw new ArgumentException($"Type '{typeConverterType.FullName}' does not implement {nameof(ITypeConverter)}"); + } + + /// <inheritdoc /> + public void ApplyTo(MemberMap memberMap) + { + memberMap.Data.TypeConverter = TypeConverter; + } + + /// <inheritdoc /> + public void ApplyTo(ParameterMap parameterMap) + { + parameterMap.Data.TypeConverter = TypeConverter; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/UseNewObjectForNullReferenceMembersAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/UseNewObjectForNullReferenceMembersAttribute.cs new file mode 100644 index 0000000..6bfbf37 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/UseNewObjectForNullReferenceMembersAttribute.cs @@ -0,0 +1,47 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// Gets a value indicating that during writing if a new + /// object should be created when a reference member is null. + /// True to create a new object and use it's defaults for the + /// fields, or false to leave the fields empty for all the + /// reference member's member. + /// </summary> + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public class UseNewObjectForNullReferenceMembersAttribute : Attribute, IClassMapper + { + /// <summary> + /// Gets a value indicating that during writing if a new + /// object should be created when a reference member is null. + /// True to create a new object and use it's defaults for the + /// fields, or false to leave the fields empty for all the + /// reference member's member. + /// </summary> + public bool UseNewObjectForNullReferenceMembers { get; private set; } + + /// <summary> + /// Gets a value indicating that during writing if a new + /// object should be created when a reference member is null. + /// True to create a new object and use it's defaults for the + /// fields, or false to leave the fields empty for all the + /// reference member's member. + /// </summary> + /// <param name="useNewObjectForNullReferenceMembers">The value.</param> + public UseNewObjectForNullReferenceMembersAttribute(bool useNewObjectForNullReferenceMembers) + { + UseNewObjectForNullReferenceMembers = useNewObjectForNullReferenceMembers; + } + + /// <inheritdoc /> + public void ApplyTo(CsvConfiguration configuration) + { + configuration.UseNewObjectForNullReferenceMembers = UseNewObjectForNullReferenceMembers; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/WhiteSpaceCharsAttribute.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/WhiteSpaceCharsAttribute.cs new file mode 100644 index 0000000..ef8f7cb --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/Attributes/WhiteSpaceCharsAttribute.cs @@ -0,0 +1,41 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Linq; +using System.Text.RegularExpressions; + +namespace CsvHelper.Configuration.Attributes +{ + /// <summary> + /// Characters considered whitespace. + /// Used when trimming fields. + /// Default is [' ']. + /// </summary> + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public class WhiteSpaceCharsAttribute : Attribute, IClassMapper + { + /// <summary> + /// Characters considered whitespace. + /// Used when trimming fields. + /// </summary> + public char[] WhiteSpaceChars { get; private set; } + + /// <summary> + /// Characters considered whitespace. + /// Used when trimming fields. + /// </summary> + /// <param name="whiteSpaceChars"></param> + public WhiteSpaceCharsAttribute(string whiteSpaceChars) + { + WhiteSpaceChars = Regex.Split(whiteSpaceChars, @"\s").Select(s => s[0]).ToArray(); + } + + /// <inheritdoc /> + public void ApplyTo(CsvConfiguration configuration) + { + configuration.WhiteSpaceChars = WhiteSpaceChars; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/ClassMap.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/ClassMap.cs new file mode 100644 index 0000000..b000693 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/ClassMap.cs @@ -0,0 +1,648 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using CsvHelper.Configuration.Attributes; +using CsvHelper.TypeConversion; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; + +namespace CsvHelper.Configuration +{ + ///<summary> + /// Maps class members to CSV fields. + ///</summary> + public abstract class ClassMap + { + private static readonly List<Type> enumerableConverters = new List<Type> + { + typeof(ArrayConverter), + typeof(CollectionGenericConverter), + typeof(EnumerableConverter), + typeof(IDictionaryConverter), + typeof(IDictionaryGenericConverter), + typeof(IEnumerableConverter), + typeof(IEnumerableGenericConverter) + }; + + /// <summary> + /// The type of the class this map is for. + /// </summary> + public virtual Type ClassType { get; private set; } + + /// <summary> + /// The class constructor parameter mappings. + /// </summary> + public virtual List<ParameterMap> ParameterMaps { get; } = new List<ParameterMap>(); + + /// <summary> + /// The class member mappings. + /// </summary> + public virtual MemberMapCollection MemberMaps { get; } = new MemberMapCollection(); + + /// <summary> + /// The class member reference mappings. + /// </summary> + public virtual MemberReferenceMapCollection ReferenceMaps { get; } = new MemberReferenceMapCollection(); + + /// <summary> + /// Allow only internal creation of CsvClassMap. + /// </summary> + /// <param name="classType">The type of the class this map is for.</param> + internal ClassMap(Type classType) + { + ClassType = classType; + } + + /// <summary> + /// Maps a member to a CSV field. + /// </summary> + /// <param name="classType">The type of the class this map is for. This may not be the same type + /// as the member.DeclaringType or the current ClassType due to nested member mappings.</param> + /// <param name="member">The member to map.</param> + /// <param name="useExistingMap">If true, an existing map will be used if available. + /// If false, a new map is created for the same member.</param> + /// <returns>The member mapping.</returns> + public MemberMap Map(Type classType, MemberInfo member, bool useExistingMap = true) + { + if (useExistingMap) + { + var existingMap = MemberMaps.Find(member); + if (existingMap != null) + { + return existingMap; + } + } + + var memberMap = MemberMap.CreateGeneric(classType, member); + memberMap.Data.Index = GetMaxIndex() + 1; + MemberMaps.Add(memberMap); + + return memberMap; + } + + /// <summary> + /// Maps a non-member to a CSV field. This allows for writing + /// data that isn't mapped to a class member. + /// </summary> + /// <returns>The member mapping.</returns> + public virtual MemberMap<object, object> Map() + { + var memberMap = new MemberMap<object, object>(null); + memberMap.Data.Index = GetMaxIndex() + 1; + MemberMaps.Add(memberMap); + + return memberMap; + } + + /// <summary> + /// Maps a member to another class map. + /// </summary> + /// <param name="classMapType">The type of the class map.</param> + /// <param name="member">The member.</param> + /// <param name="constructorArgs">Constructor arguments used to create the reference map.</param> + /// <returns>The reference mapping for the member.</returns> + public virtual MemberReferenceMap References(Type classMapType, MemberInfo member, params object[] constructorArgs) + { + if (!typeof(ClassMap).IsAssignableFrom(classMapType)) + { + throw new InvalidOperationException($"Argument {nameof(classMapType)} is not a CsvClassMap."); + } + + var existingMap = ReferenceMaps.Find(member); + + if (existingMap != null) + { + return existingMap; + } + + var map = (ClassMap)ObjectResolver.Current.Resolve(classMapType, constructorArgs); + map.ReIndex(GetMaxIndex() + 1); + var reference = new MemberReferenceMap(member, map); + ReferenceMaps.Add(reference); + + return reference; + } + + /// <summary> + /// Maps a constructor parameter to a CSV field. + /// </summary> + /// <param name="name">The name of the constructor parameter.</param> + public virtual ParameterMap Parameter(string name) + { + if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullException(nameof(name)); + + var args = new GetConstructorArgs(ClassType); + + return Parameter(() => ConfigurationFunctions.GetConstructor(args), name); + } + + /// <summary> + /// Maps a constructor parameter to a CSV field. + /// </summary> + /// <param name="getConstructor">A function that returns the <see cref="ConstructorInfo"/> for the constructor.</param> + /// <param name="name">The name of the constructor parameter.</param> + public virtual ParameterMap Parameter(Func<ConstructorInfo> getConstructor, string name) + { + if (getConstructor == null) throw new ArgumentNullException(nameof(getConstructor)); + if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullException(nameof(name)); + + var constructor = getConstructor(); + var parameters = constructor.GetParameters(); + var parameter = parameters.SingleOrDefault(p => p.Name == name); + if (parameter == null) + { + throw new ConfigurationException($"Constructor {constructor.GetDefinition()} doesn't contain a paramter with name '{name}'."); + } + + return Parameter(constructor, parameter); + } + + /// <summary> + /// Maps a constructor parameter to a CSV field. + /// </summary> + /// <param name="constructor">The <see cref="ConstructorInfo"/> for the constructor.</param> + /// <param name="parameter">The <see cref="ParameterInfo"/> for the constructor parameter.</param> + public virtual ParameterMap Parameter(ConstructorInfo constructor, ParameterInfo parameter) + { + if (constructor == null) throw new ArgumentNullException(nameof(constructor)); + if (parameter == null) throw new ArgumentNullException(nameof(parameter)); + + if (!constructor.GetParameters().Contains(parameter)) + { + throw new ConfigurationException($"Constructor {constructor.GetDefinition()} doesn't contain parameter '{parameter.GetDefinition()}'."); + } + + var parameterMap = new ParameterMap(parameter); + parameterMap.Data.Index = GetMaxIndex(isParameter: true) + 1; + ParameterMaps.Add(parameterMap); + + return parameterMap; + } + + /// <summary> + /// Auto maps all members for the given type. If a member + /// is mapped again it will override the existing map. + /// </summary> + /// <param name="culture">The culture.</param> + public virtual void AutoMap(CultureInfo culture) + { + AutoMap(new CsvConfiguration(culture)); + } + + /// <summary> + /// Auto maps all members for the given type. If a member + /// is mapped again it will override the existing map. + /// </summary> + /// <param name="configuration">The configuration.</param> + public virtual void AutoMap(CsvConfiguration configuration) + { + AutoMap(new CsvContext(configuration)); + } + + /// <summary> + /// Auto maps all members for the given type. If a member + /// is mapped again it will override the existing map. + /// </summary> + /// <param name="context">The context.</param> + public virtual void AutoMap(CsvContext context) + { + var type = GetGenericType(); + if (typeof(IEnumerable).IsAssignableFrom(type)) + { + throw new ConfigurationException("Types that inherit IEnumerable cannot be auto mapped. " + + "Did you accidentally call GetRecord or WriteRecord which " + + "acts on a single record instead of calling GetRecords or " + + "WriteRecords which acts on a list of records?"); + } + + var mapParents = new LinkedList<Type>(); + var args = new ShouldUseConstructorParametersArgs(type); + if (context.Configuration.ShouldUseConstructorParameters(args)) + { + // This type doesn't have a parameterless constructor so we can't create an + // instance and set it's member. Constructor parameters need to be created + // instead. Writing only uses getters, so members will also be mapped + // for writing purposes. + AutoMapConstructorParameters(this, context, mapParents); + } + + AutoMapMembers(this, context, mapParents); + } + + /// <summary> + /// Get the largest index for the + /// members and references. + /// </summary> + /// <returns>The max index.</returns> + public virtual int GetMaxIndex(bool isParameter = false) + { + if (isParameter) + { + return ParameterMaps.Select(parameterMap => parameterMap.GetMaxIndex()).DefaultIfEmpty(-1).Max(); + } + + if (MemberMaps.Count == 0 && ReferenceMaps.Count == 0) + { + return -1; + } + + var indexes = new List<int>(); + if (MemberMaps.Count > 0) + { + indexes.Add(MemberMaps.Max(pm => pm.Data.Index)); + } + + if (ReferenceMaps.Count > 0) + { + indexes.AddRange(ReferenceMaps.Select(referenceMap => referenceMap.GetMaxIndex())); + } + + return indexes.Max(); + } + + /// <summary> + /// Resets the indexes based on the given start index. + /// </summary> + /// <param name="indexStart">The index start.</param> + /// <returns>The last index + 1.</returns> + public virtual int ReIndex(int indexStart = 0) + { + foreach (var parameterMap in ParameterMaps) + { + parameterMap.Data.Index = indexStart + parameterMap.Data.Index; + } + + foreach (var memberMap in MemberMaps) + { + if (!memberMap.Data.IsIndexSet) + { + memberMap.Data.Index = indexStart + memberMap.Data.Index; + } + } + + foreach (var referenceMap in ReferenceMaps) + { + indexStart = referenceMap.Data.Mapping.ReIndex(indexStart); + } + + return indexStart; + } + + /// <summary> + /// Auto maps the given map and checks for circular references as it goes. + /// </summary> + /// <param name="map">The map to auto map.</param> + /// <param name="context">The context.</param> + /// <param name="mapParents">The list of parents for the map.</param> + /// <param name="indexStart">The index starting point.</param> + protected virtual void AutoMapMembers(ClassMap map, CsvContext context, LinkedList<Type> mapParents, int indexStart = 0) + { + var type = map.GetGenericType(); + + var flags = BindingFlags.Instance | BindingFlags.Public; + if (context.Configuration.IncludePrivateMembers) + { + flags = flags | BindingFlags.NonPublic; + } + + var members = new List<MemberInfo>(); + if ((context.Configuration.MemberTypes & MemberTypes.Properties) == MemberTypes.Properties) + { + // We need to go up the declaration tree and find the actual type the property + // exists on and use that PropertyInfo instead. This is so we can get the private + // set method for the property. + var properties = new List<PropertyInfo>(); + foreach (var property in ReflectionHelper.GetUniqueProperties(type, flags)) + { + if (properties.Any(p => p.Name == property.Name)) + { + // Multiple properties could have the same name if a child class property + // is hiding a parent class property by using `new`. It's possible that + // the order of the properties returned + continue; + } + + properties.Add(ReflectionHelper.GetDeclaringProperty(type, property, flags)); + } + + members.AddRange(properties); + } + + if ((context.Configuration.MemberTypes & MemberTypes.Fields) == MemberTypes.Fields) + { + // We need to go up the declaration tree and find the actual type the field + // exists on and use that FieldInfo instead. + var fields = new List<MemberInfo>(); + foreach (var field in ReflectionHelper.GetUniqueFields(type, flags)) + { + if (fields.Any(p => p.Name == field.Name)) + { + // Multiple fields could have the same name if a child class field + // is hiding a parent class field by using `new`. It's possible that + // the order of the fields returned + continue; + } + + if (!field.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Any()) + { + fields.Add(ReflectionHelper.GetDeclaringField(type, field, flags)); + } + } + + members.AddRange(fields); + } + + foreach (var member in members) + { + if (member.GetCustomAttribute<IgnoreAttribute>() != null) + { + // Ignore this member including its tree if it's a reference. + continue; + } + + var typeConverterType = context.TypeConverterCache.GetConverter(member).GetType(); + + if (context.Configuration.HasHeaderRecord && enumerableConverters.Contains(typeConverterType)) + { + // Enumerable converters can't write the header properly, so skip it. + continue; + } + + var memberTypeInfo = member.MemberType().GetTypeInfo(); + var isDefaultConverter = typeConverterType == typeof(DefaultTypeConverter); + if (isDefaultConverter) + { + // If the type is not one covered by our type converters + // and it has a parameterless constructor, create a + // reference map for it. + + if (context.Configuration.IgnoreReferences) + { + continue; + } + + if (CheckForCircularReference(member.MemberType(), mapParents)) + { + continue; + } + + mapParents.AddLast(type); + var refMapType = typeof(DefaultClassMap<>).MakeGenericType(member.MemberType()); + var refMap = (ClassMap)ObjectResolver.Current.Resolve(refMapType); + + if (memberTypeInfo.HasConstructor() && !memberTypeInfo.HasParameterlessConstructor() && !memberTypeInfo.IsUserDefinedStruct()) + { + AutoMapConstructorParameters(refMap, context, mapParents, Math.Max(map.GetMaxIndex() + 1, indexStart)); + } + + // Need to use Max here for nested types. + AutoMapMembers(refMap, context, mapParents, Math.Max(map.GetMaxIndex() + 1, indexStart)); + mapParents.Drop(mapParents.Find(type)); + + if (refMap.MemberMaps.Count > 0 || refMap.ReferenceMaps.Count > 0) + { + var referenceMap = new MemberReferenceMap(member, refMap); + if (context.Configuration.ReferenceHeaderPrefix != null) + { + var args = new ReferenceHeaderPrefixArgs(member.MemberType(), member.Name); + referenceMap.Data.Prefix = context.Configuration.ReferenceHeaderPrefix(args); + } + + ApplyAttributes(referenceMap); + + map.ReferenceMaps.Add(referenceMap); + } + } + else + { + // Only add the member map if it can be converted later on. + // If the member will use the default converter, don't add it because + // we don't want the .ToString() value to be used when auto mapping. + + // Use the top of the map tree. This will maps that have been auto mapped + // to later on get a reference to a map by doing map.Map( m => m.A.B.C.Id ) + // and it will return the correct parent map type of A instead of C. + var classType = mapParents.First?.Value ?? map.ClassType; + var memberMap = MemberMap.CreateGeneric(classType, member); + + // Use global values as the starting point. + memberMap.Data.TypeConverterOptions = TypeConverterOptions.Merge(new TypeConverterOptions(), context.TypeConverterOptionsCache.GetOptions(member.MemberType()), memberMap.Data.TypeConverterOptions); + memberMap.Data.Index = map.GetMaxIndex() + 1; + + ApplyAttributes(memberMap); + + map.MemberMaps.Add(memberMap); + } + } + + map.ReIndex(indexStart); + } + + /// <summary> + /// Auto maps the given map using constructor parameters. + /// </summary> + /// <param name="map">The map.</param> + /// <param name="context">The context.</param> + /// <param name="mapParents">The list of parents for the map.</param> + /// <param name="indexStart">The index starting point.</param> + protected virtual void AutoMapConstructorParameters(ClassMap map, CsvContext context, LinkedList<Type> mapParents, int indexStart = 0) + { + var type = map.GetGenericType(); + var args = new GetConstructorArgs(map.ClassType); + var constructor = context.Configuration.GetConstructor(args); + var parameters = constructor.GetParameters(); + + foreach (var parameter in parameters) + { + var parameterMap = new ParameterMap(parameter); + + if (parameter.GetCustomAttributes<IgnoreAttribute>(true).Any() || parameter.GetCustomAttributes<ConstantAttribute>(true).Any()) + { + // If there is an IgnoreAttribute or ConstantAttribute, we still need to add a map because a constructor requires + // all parameters to be present. A default value will be used later on. + + ApplyAttributes(parameterMap); + map.ParameterMaps.Add(parameterMap); + continue; + } + + var typeConverterType = context.TypeConverterCache.GetConverter(parameter.ParameterType).GetType(); + var memberTypeInfo = parameter.ParameterType.GetTypeInfo(); + var isDefaultConverter = typeConverterType == typeof(DefaultTypeConverter); + if (isDefaultConverter && (memberTypeInfo.HasParameterlessConstructor() || memberTypeInfo.IsUserDefinedStruct())) + { + // If the type is not one covered by our type converters + // and it has a parameterless constructor, create a + // reference map for it. + + if (context.Configuration.IgnoreReferences) + { + throw new InvalidOperationException($"Configuration '{nameof(CsvConfiguration.IgnoreReferences)}' can't be true " + + "when using types without a default constructor. Constructor parameters " + + "are used and all members including references must be used."); + } + + if (CheckForCircularReference(parameter.ParameterType, mapParents)) + { + throw new InvalidOperationException($"A circular reference was detected in constructor paramter '{parameter.Name}'." + + "Since all parameters must be supplied for a constructor, this parameter can't be skipped."); + } + + mapParents.AddLast(type); + var refMapType = typeof(DefaultClassMap<>).MakeGenericType(parameter.ParameterType); + var refMap = (ClassMap)ObjectResolver.Current.Resolve(refMapType); + AutoMapMembers(refMap, context, mapParents, Math.Max(map.GetMaxIndex(isParameter: true) + 1, indexStart)); + mapParents.Drop(mapParents.Find(type)); + + var referenceMap = new ParameterReferenceMap(parameter, refMap); + if (context.Configuration.ReferenceHeaderPrefix != null) + { + var referenceHeaderPrefix = new ReferenceHeaderPrefixArgs(memberTypeInfo.MemberType(), memberTypeInfo.Name); + referenceMap.Data.Prefix = context.Configuration.ReferenceHeaderPrefix(referenceHeaderPrefix); + } + + ApplyAttributes(referenceMap); + + parameterMap.ReferenceMap = referenceMap; + } + else if (isDefaultConverter && context.Configuration.ShouldUseConstructorParameters(new ShouldUseConstructorParametersArgs(parameter.ParameterType))) + { + // If the type is not one covered by our type converters + // and it should use contructor parameters, create a + // constructor map for it. + + mapParents.AddLast(type); + var constructorMapType = typeof(DefaultClassMap<>).MakeGenericType(parameter.ParameterType); + var constructorMap = (ClassMap)ObjectResolver.Current.Resolve(constructorMapType); + // Need to use Max here for nested types. + AutoMapConstructorParameters(constructorMap, context, mapParents, Math.Max(map.GetMaxIndex(isParameter: true) + 1, indexStart)); + mapParents.Drop(mapParents.Find(type)); + + parameterMap.ConstructorTypeMap = constructorMap; + } + else + { + parameterMap.Data.TypeConverterOptions = TypeConverterOptions.Merge(new TypeConverterOptions(), context.TypeConverterOptionsCache.GetOptions(parameter.ParameterType), parameterMap.Data.TypeConverterOptions); + parameterMap.Data.Index = map.GetMaxIndex(isParameter: true) + 1; + + ApplyAttributes(parameterMap); + } + + map.ParameterMaps.Add(parameterMap); + } + + map.ReIndex(indexStart); + } + + /// <summary> + /// Checks for circular references. + /// </summary> + /// <param name="type">The type to check for.</param> + /// <param name="mapParents">The list of parents to check against.</param> + /// <returns>A value indicating if a circular reference was found. + /// True if a circular reference was found, otherwise false.</returns> + protected virtual bool CheckForCircularReference(Type type, LinkedList<Type> mapParents) + { + if (mapParents.Count == 0) + { + return false; + } + + var node = mapParents.Last; + while (true) + { + if (node?.Value == type) + { + return true; + } + + node = node?.Previous; + if (node == null) + { + break; + } + } + + return false; + } + + /// <summary> + /// Gets the generic type for this class map. + /// </summary> + protected virtual Type GetGenericType() + { + return GetType().GetTypeInfo().BaseType?.GetGenericArguments()[0] ?? throw new ConfigurationException(); + } + + /// <summary> + /// Applies attribute configurations to the map. + /// </summary> + /// <param name="parameterMap">The parameter map.</param> + protected virtual void ApplyAttributes(ParameterMap parameterMap) + { + var parameter = parameterMap.Data.Parameter; + var attributes = parameter.GetCustomAttributes().OfType<IParameterMapper>(); + + foreach (var attribute in attributes) + { + attribute.ApplyTo(parameterMap); + } + } + + /// <summary> + /// Applies attribute configurations to the map. + /// </summary> + /// <param name="referenceMap">The parameter reference map.</param> + protected virtual void ApplyAttributes(ParameterReferenceMap referenceMap) + { + var parameter = referenceMap.Data.Parameter; + var attributes = parameter.GetCustomAttributes().OfType<IParameterReferenceMapper>(); + + foreach (var attribute in attributes) + { + attribute.ApplyTo(referenceMap); + } + } + + /// <summary> + /// Applies attribute configurations to the map. + /// </summary> + /// <param name="memberMap">The member map.</param> + protected virtual void ApplyAttributes(MemberMap memberMap) + { + if (memberMap.Data.Member == null) + { + return; + } + + var member = memberMap.Data.Member; + var attributes = member.GetCustomAttributes().OfType<IMemberMapper>(); + + foreach (var attribute in attributes) + { + attribute.ApplyTo(memberMap); + } + } + + /// <summary> + /// Applies attribute configurations to the map. + /// </summary> + /// <param name="referenceMap">The member reference map.</param> + protected virtual void ApplyAttributes(MemberReferenceMap referenceMap) + { + var member = referenceMap.Data.Member; + var attributes = member.GetCustomAttributes().OfType<IMemberReferenceMapper>(); + + foreach (var attribute in attributes) + { + attribute.ApplyTo(referenceMap); + } + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/ClassMapBuilder.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/ClassMapBuilder.cs new file mode 100644 index 0000000..fbe2e6a --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/ClassMapBuilder.cs @@ -0,0 +1,432 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Linq.Expressions; +using CsvHelper.TypeConversion; +using System.Collections; + +namespace CsvHelper.Configuration +{ + /// <summary> + /// Has mapping capabilities. + /// </summary> + /// <typeparam name="TClass">The class type.</typeparam> + public interface IHasMap<TClass> : IBuildableClass<TClass> + { + /// <summary> + /// Maps a member to a CSV field. + /// </summary> + /// <param name="expression">The member to map.</param> + /// <param name="useExistingMap">If true, an existing map will be used if available. + /// If false, a new map is created for the same member.</param> + /// <returns>The member mapping.</returns> + IHasMapOptions<TClass, TMember> Map<TMember>(Expression<Func<TClass, TMember>> expression, bool useExistingMap = true); + } + + /// <summary> + /// Options after a mapping call. + /// </summary> + /// <typeparam name="TClass">The class type.</typeparam> + /// <typeparam name="TMember">The member type.</typeparam> + public interface IHasMapOptions<TClass, TMember> : + IHasMap<TClass>, + IHasTypeConverter<TClass, TMember>, + IHasIndex<TClass, TMember>, + IHasName<TClass, TMember>, + IHasOptional<TClass, TMember>, + IHasConvertUsing<TClass, TMember>, + IHasDefault<TClass, TMember>, + IHasConstant<TClass, TMember>, + IHasValidate<TClass, TMember> + { } + + /// <summary> + /// Has type converter capabilities. + /// </summary> + /// <typeparam name="TClass">The class type.</typeparam> + /// <typeparam name="TMember">The member type.</typeparam> + public interface IHasTypeConverter<TClass, TMember> : IBuildableClass<TClass> + { + /// <summary> + /// Specifies the <see cref="TypeConverter"/> to use + /// when converting the member to and from a CSV field. + /// </summary> + /// <param name="typeConverter">The TypeConverter to use.</param> + IHasTypeConverterOptions<TClass, TMember> TypeConverter(ITypeConverter typeConverter); + + /// <summary> + /// Specifies the <see cref="TypeConverter"/> to use + /// when converting the member to and from a CSV field. + /// </summary> + /// <typeparam name="TConverter">The <see cref="System.Type"/> of the + /// <see cref="TypeConverter"/> to use.</typeparam> + IHasTypeConverterOptions<TClass, TMember> TypeConverter<TConverter>() where TConverter : ITypeConverter; + } + + /// <summary> + /// Options after a type converter call. + /// </summary> + /// <typeparam name="TClass">The class type.</typeparam> + /// <typeparam name="TMember">The member type.</typeparam> + public interface IHasTypeConverterOptions<TClass, TMember> : + IHasMap<TClass>, + IHasDefault<TClass, TMember>, + IHasValidate<TClass, TMember> + { } + + /// <summary> + /// Has index capabilities. + /// </summary> + /// <typeparam name="TClass">The class type.</typeparam> + /// <typeparam name="TMember">The member type.</typeparam> + public interface IHasIndex<TClass, TMember> : IBuildableClass<TClass> + { + /// <summary> + /// When reading, is used to get the field at + /// the given index. When writing, the fields + /// will be written in the order of the field + /// indexes. + /// </summary> + /// <param name="index">The index of the CSV field.</param> + /// <param name="indexEnd">The end index used when mapping to an <see cref="IEnumerable"/> member.</param> + IHasIndexOptions<TClass, TMember> Index(int index, int indexEnd = -1); + } + + /// <summary> + /// Options after an index call. + /// </summary> + /// <typeparam name="TClass">The class type.</typeparam> + /// <typeparam name="TMember">The member type.</typeparam> + public interface IHasIndexOptions<TClass, TMember> : + IHasMap<TClass>, + IHasTypeConverter<TClass, TMember>, + IHasName<TClass, TMember>, + IHasDefault<TClass, TMember>, + IHasValidate<TClass, TMember> + { } + + /// <summary> + /// Has optional capabilities. + /// </summary> + /// <typeparam name="TClass">The class type.</typeparam> + /// <typeparam name="TMember">The member type.</typeparam> + public interface IHasOptional<TClass, TMember> : IBuildableClass<TClass> + { + /// <summary> + /// Ignore the member when reading if no matching field name can be found. + /// </summary> + IHasOptionalOptions<TClass, TMember> Optional(); + } + + /// <summary> + /// Options after an optional call. + /// </summary> + /// <typeparam name="TClass">The class type.</typeparam> + /// <typeparam name="TMember">The member type.</typeparam> + public interface IHasOptionalOptions<TClass, TMember> : + IHasMap<TClass>, + IHasTypeConverter<TClass, TMember>, + IHasName<TClass, TMember>, + IHasDefault<TClass, TMember>, + IHasValidate<TClass, TMember> + { } + + /// <summary> + /// Has name capabilities. + /// </summary> + /// <typeparam name="TClass">The class type.</typeparam> + /// <typeparam name="TMember">The member type.</typeparam> + public interface IHasName<TClass, TMember> : IBuildableClass<TClass> + { + /// <summary> + /// When reading, is used to get the field + /// at the index of the name if there was a + /// header specified. It will look for the + /// first name match in the order listed. + /// When writing, sets the name of the + /// field in the header record. + /// The first name will be used. + /// </summary> + /// <param name="names">The possible names of the CSV field.</param> + IHasNameOptions<TClass, TMember> Name(params string[] names); + } + + /// <summary> + /// Options after a name call. + /// </summary> + /// <typeparam name="TClass">The class type.</typeparam> + /// <typeparam name="TMember">The member type.</typeparam> + public interface IHasNameOptions<TClass, TMember> : + IHasMap<TClass>, + IHasTypeConverter<TClass, TMember>, + IHasNameIndex<TClass, TMember>, + IHasDefault<TClass, TMember>, + IHasValidate<TClass, TMember> + { } + + /// <summary> + /// Has name index capabilities. + /// </summary> + /// <typeparam name="TClass">The class type.</typeparam> + /// <typeparam name="TMember">The member type.</typeparam> + public interface IHasNameIndex<TClass, TMember> : IBuildableClass<TClass> + { + /// <summary> + /// When reading, is used to get the + /// index of the name used when there + /// are multiple names that are the same. + /// </summary> + /// <param name="index">The index of the name.</param> + IHasNameIndexOptions<TClass, TMember> NameIndex(int index); + } + + /// <summary> + /// Options after a name index call. + /// </summary> + /// <typeparam name="TClass">The class type.</typeparam> + /// <typeparam name="TMember">The member type.</typeparam> + public interface IHasNameIndexOptions<TClass, TMember> : + IHasMap<TClass>, + IHasTypeConverter<TClass, TMember>, + IHasDefault<TClass, TMember>, + IHasValidate<TClass, TMember> + { } + + /// <summary> + /// Has convert using capabilities. + /// </summary> + /// <typeparam name="TClass">The class type.</typeparam> + /// <typeparam name="TMember">The member type.</typeparam> + public interface IHasConvertUsing<TClass, TMember> : IBuildableClass<TClass> + { + /// <summary> + /// Specifies an expression to be used to convert data in the + /// row to the member. + /// </summary> + /// <param name="convertExpression">The convert expression.</param> + IHasMap<TClass> ConvertUsing(ConvertFromString<TMember> convertExpression); + + /// <summary> + /// Specifies an expression to be used to convert the object + /// to a field. + /// </summary> + /// <param name="convertExpression">The convert expression.</param> + IHasMap<TClass> ConvertUsing(ConvertToString<TClass> convertExpression); + } + + /// <summary> + /// Has default capabilities. + /// </summary> + /// <typeparam name="TClass">The class type.</typeparam> + /// <typeparam name="TMember">The member type.</typeparam> + public interface IHasDefault<TClass, TMember> : IBuildableClass<TClass> + { + /// <summary> + /// The default value that will be used when reading when + /// the CSV field is empty. + /// </summary> + /// <param name="defaultValue">The default value.</param> + IHasDefaultOptions<TClass, TMember> Default(TMember defaultValue); + + /// <summary> + /// The default value that will be used when reading when + /// the CSV field is empty. This value is not type checked + /// and will use a <see cref="ITypeConverter"/> to convert + /// the field. This could potentially have runtime errors. + /// </summary> + /// <param name="defaultValue">The default value.</param> + IHasDefaultOptions<TClass, TMember> Default(string defaultValue); + } + + /// <summary> + /// Options after a default call. + /// </summary> + /// <typeparam name="TClass">The class type.</typeparam> + /// <typeparam name="TMember">The member type.</typeparam> + public interface IHasDefaultOptions<TClass, TMember> : + IHasMap<TClass>, + IHasValidate<TClass, TMember> + { } + + /// <summary> + /// Has constant capabilities. + /// </summary> + /// <typeparam name="TClass">The class type.</typeparam> + /// <typeparam name="TMember">The member type.</typeparam> + public interface IHasConstant<TClass, TMember> : IBuildableClass<TClass> + { + /// <summary> + /// The constant value that will be used for every record when + /// reading and writing. This value will always be used no matter + /// what other mapping configurations are specified. + /// </summary> + /// <param name="value">The constant value.</param> + IHasMap<TClass> Constant(TMember value); + } + + /// <summary> + /// Has validate capabilities. + /// </summary> + /// <typeparam name="TClass">The class type.</typeparam> + /// <typeparam name="TMember">The member type.</typeparam> + public interface IHasValidate<TClass, TMember> : IBuildableClass<TClass> + { + /// <summary> + /// The validate expression that will be called on every field when reading. + /// The expression should return true if the field is valid. + /// If false is returned, a <see cref="ValidationException"/> + /// will be thrown. + /// </summary> + /// <param name="validateExpression">The validation expression.</param> + IHasMap<TClass> Validate(Validate validateExpression); + } + + /// <summary> + /// Has build capabilities. + /// </summary> + /// <typeparam name="TClass">The class type.</typeparam> + public interface IBuildableClass<TClass> + { + /// <summary> + /// Builds the <see cref="ClassMap{TClass}"/>. + /// </summary> + ClassMap<TClass> Build(); + } + + internal class ClassMapBuilder<TClass> : IHasMap<TClass> + { + private readonly ClassMap<TClass> map; + + public ClassMapBuilder() + { + map = new BuilderClassMap<TClass>(); + } + + public IHasMapOptions<TClass, TMember> Map<TMember>(Expression<Func<TClass, TMember>> expression, bool useExistingMap = true) + { + return new MemberMapBuilder<TClass, TMember>(map, map.Map(expression, useExistingMap)); + } + + public ClassMap<TClass> Build() + { + return map; + } + + private class BuilderClassMap<T> : ClassMap<T> { } + } + + internal class MemberMapBuilder<TClass, TMember> : + IHasMap<TClass>, + IHasMapOptions<TClass, TMember>, + IHasTypeConverter<TClass, TMember>, + IHasTypeConverterOptions<TClass, TMember>, + IHasIndex<TClass, TMember>, + IHasIndexOptions<TClass, TMember>, + IHasName<TClass, TMember>, + IHasNameOptions<TClass, TMember>, + IHasNameIndex<TClass, TMember>, + IHasNameIndexOptions<TClass, TMember>, + IHasOptional<TClass, TMember>, + IHasOptionalOptions<TClass, TMember>, + IHasConvertUsing<TClass, TMember>, + IHasDefault<TClass, TMember>, + IHasDefaultOptions<TClass, TMember>, + IHasConstant<TClass, TMember>, + IHasValidate<TClass, TMember> + { + private readonly ClassMap<TClass> classMap; + private readonly MemberMap<TClass, TMember> memberMap; + + public MemberMapBuilder(ClassMap<TClass> classMap, MemberMap<TClass, TMember> memberMap) + { + this.classMap = classMap; + this.memberMap = memberMap; + } + +#pragma warning disable CS0693 // Type parameter has the same name as the type parameter from outer type + public IHasMapOptions<TClass, TMember> Map<TMember>(Expression<Func<TClass, TMember>> expression, bool useExistingMap = true) + { + return new MemberMapBuilder<TClass, TMember>(classMap, classMap.Map(expression, useExistingMap)); + } +#pragma warning restore CS0693 // Type parameter has the same name as the type parameter from outer type + + public IHasMap<TClass> ConvertUsing(ConvertFromString<TMember> convertExpression) + { + memberMap.Convert(convertExpression); + return this; + } + + public IHasMap<TClass> ConvertUsing(ConvertToString<TClass> convertExpression) + { + memberMap.Convert(convertExpression); + return this; + } + + public IHasDefaultOptions<TClass, TMember> Default(TMember defaultValue) + { + memberMap.Default(defaultValue); + return this; + } + + public IHasDefaultOptions<TClass, TMember> Default(string defaultValue) + { + memberMap.Default(defaultValue); + return this; + } + + public IHasIndexOptions<TClass, TMember> Index(int index, int indexEnd = -1) + { + memberMap.Index(index, indexEnd); + return this; + } + + public IHasNameOptions<TClass, TMember> Name(params string[] names) + { + memberMap.Name(names); + return this; + } + + public IHasNameIndexOptions<TClass, TMember> NameIndex(int index) + { + memberMap.NameIndex(index); + return this; + } + + public IHasOptionalOptions<TClass, TMember> Optional() + { + memberMap.Optional(); + return this; + } + + public IHasTypeConverterOptions<TClass, TMember> TypeConverter(ITypeConverter typeConverter) + { + memberMap.TypeConverter(typeConverter); + return this; + } + + public IHasTypeConverterOptions<TClass, TMember> TypeConverter<TConverter>() where TConverter : ITypeConverter + { + memberMap.TypeConverter<TConverter>(); + return this; + } + + public IHasMap<TClass> Constant(TMember value) + { + memberMap.Constant(value); + return this; + } + + public IHasMap<TClass> Validate(Validate validateExpression) + { + memberMap.Validate(validateExpression); + return this; + } + + public ClassMap<TClass> Build() + { + return classMap; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/ClassMapCollection.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/ClassMapCollection.cs new file mode 100644 index 0000000..f66a284 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/ClassMapCollection.cs @@ -0,0 +1,188 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace CsvHelper.Configuration +{ + /// <summary> + /// Collection that holds CsvClassMaps for record types. + /// </summary> + public class ClassMapCollection + { + private readonly Dictionary<Type, ClassMap> data = new Dictionary<Type, ClassMap>(); + private readonly CsvContext context; + + /// <summary> + /// Gets the <see cref="ClassMap"/> for the specified record type. + /// </summary> + /// <value> + /// The <see cref="ClassMap"/>. + /// </value> + /// <param name="type">The record type.</param> + /// <returns>The <see cref="ClassMap"/> for the specified record type.</returns> + public virtual ClassMap? this[Type type] + { + get + { + // Go up the inheritance tree to find the matching type. + // We can't use IsAssignableFrom because both a child + // and it's parent/grandparent/etc could be mapped. + var currentType = type; + while (true) + { + if (data.TryGetValue(currentType, out var map)) + { + return map; + } + + currentType = currentType.GetTypeInfo().BaseType; + if (currentType == null) + { + return null; + } + } + } + } + + /// <summary> + /// Creates a new instance using the given configuration. + /// </summary> + /// <param name="context">The context.</param> + public ClassMapCollection(CsvContext context) + { + this.context = context; + } + + /// <summary> + /// Finds the <see cref="ClassMap"/> for the specified record type. + /// </summary> + /// <typeparam name="T">The record type.</typeparam> + /// <returns>The <see cref="ClassMap"/> for the specified record type.</returns> + public virtual ClassMap<T>? Find<T>() + { + return (ClassMap<T>?)this[typeof(T)]; + } + + /// <summary> + /// Adds the specified map for it's record type. If a map + /// already exists for the record type, the specified + /// map will replace it. + /// </summary> + /// <param name="map">The map.</param> + internal virtual void Add(ClassMap map) + { + SetMapDefaults(map); + + var type = GetGenericCsvClassMapType(map.GetType()).GetGenericArguments().First(); + + data[type] = map; + } + + /// <summary> + /// Removes the class map. + /// </summary> + /// <param name="classMapType">The class map type.</param> + internal virtual void Remove(Type classMapType) + { + if (!typeof(ClassMap).IsAssignableFrom(classMapType)) + { + throw new ArgumentException("The class map type must inherit from CsvClassMap."); + } + + var type = GetGenericCsvClassMapType(classMapType).GetGenericArguments().First(); + + data.Remove(type); + } + + /// <summary> + /// Removes all maps. + /// </summary> + internal virtual void Clear() + { + data.Clear(); + } + + /// <summary> + /// Goes up the inheritance tree to find the type instance of CsvClassMap{}. + /// </summary> + /// <param name="type">The type to traverse.</param> + /// <returns>The type that is CsvClassMap{}.</returns> + private Type GetGenericCsvClassMapType(Type type) + { + if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(ClassMap<>)) + { + return type; + } + + return GetGenericCsvClassMapType(type.GetTypeInfo().BaseType); + } + + /// <summary> + /// Sets defaults for the mapping tree. The defaults used + /// to be set inside the classes, but this didn't allow for + /// the TypeConverter to be created from the Configuration's + /// TypeConverterFactory. + /// </summary> + /// <param name="map">The map to set defaults on.</param> + private void SetMapDefaults(ClassMap map) + { + foreach (var parameterMap in map.ParameterMaps) + { + if (parameterMap.ConstructorTypeMap != null) + { + SetMapDefaults(parameterMap.ConstructorTypeMap); + } + else if (parameterMap.ReferenceMap != null) + { + SetMapDefaults(parameterMap.ReferenceMap.Data.Mapping); + } + else + { + if (parameterMap.Data.TypeConverter == null) + { + parameterMap.Data.TypeConverter = context.TypeConverterCache.GetConverter(parameterMap.Data.Parameter.ParameterType); + } + + if (parameterMap.Data.Names.Count == 0) + { + parameterMap.Data.Names.Add(parameterMap.Data.Parameter.Name); + } + } + } + + foreach (var memberMap in map.MemberMaps) + { + if (memberMap.Data.Member == null) + { + continue; + } + + if (memberMap.Data.TypeConverter == null && memberMap.Data.ReadingConvertExpression == null && memberMap.Data.WritingConvertExpression == null) + { + memberMap.Data.TypeConverter = context.TypeConverterCache.GetConverter(memberMap.Data.Member.MemberType()); + } + + if (memberMap.Data.Names.Count == 0) + { + memberMap.Data.Names.Add(memberMap.Data.Member.Name); + } + } + + foreach (var referenceMap in map.ReferenceMaps) + { + SetMapDefaults(referenceMap.Data.Mapping); + + if (context.Configuration.ReferenceHeaderPrefix != null) + { + var args = new ReferenceHeaderPrefixArgs(referenceMap.Data.Member.MemberType(), referenceMap.Data.Member.Name); + referenceMap.Data.Prefix = context.Configuration.ReferenceHeaderPrefix(args); + } + } + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/ClassMap`1.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/ClassMap`1.cs new file mode 100644 index 0000000..d14c317 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/ClassMap`1.cs @@ -0,0 +1,112 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Linq.Expressions; +using System.Reflection; + +namespace CsvHelper.Configuration +{ + /// <summary> + /// Maps class members to CSV fields. + /// </summary> + /// <typeparam name="TClass">The <see cref="System.Type"/> of class to map.</typeparam> + public abstract class ClassMap<TClass> : ClassMap + { + /// <summary> + /// Creates an instance of <see cref="ClassMap{TClass}"/>. + /// </summary> + public ClassMap() : base(typeof(TClass)) { } + + /// <summary> + /// Maps a member to a CSV field. + /// </summary> + /// <param name="expression">The member to map.</param> + /// <param name="useExistingMap">If true, an existing map will be used if available. + /// If false, a new map is created for the same member.</param> + /// <returns>The member mapping.</returns> + public virtual MemberMap<TClass, TMember> Map<TMember>(Expression<Func<TClass, TMember>> expression, bool useExistingMap = true) + { + var (classMap, member) = GetMemberMap(expression); + var memberMap = classMap.Map(typeof(TClass), member, useExistingMap); ; + + return (MemberMap<TClass, TMember>)memberMap; + } + + /// <summary> + /// Maps a member to a CSV field. + /// </summary> + /// <param name="expression">The member to map.</param> + /// <param name="useExistingMap">If true, an existing map will be used if available. + /// If false, a new map is created for the same member.</param> + /// <returns>The member mapping.</returns> + public virtual MemberMap Map<T>(Expression<Func<T, object>> expression, bool useExistingMap = true) + { + var (classMap, member) = GetMemberMap(expression); + var memberMap = classMap.Map(typeof(TClass), member, useExistingMap); + + return memberMap; + } + + /// <summary> + /// Meant for internal use only. + /// Maps a member to another class map. When this is used, accessing a property through + /// sub-property mapping later won't work. You can only use one or the other. When using + /// this, ConvertUsing will also not work. + /// </summary> + /// <typeparam name="TClassMap">The type of the class map.</typeparam> + /// <param name="expression">The expression.</param> + /// <param name="constructorArgs">Constructor arguments used to create the reference map.</param> + /// <returns>The reference mapping for the member.</returns> + public virtual MemberReferenceMap References<TClassMap>(Expression<Func<TClass, object>> expression, params object[] constructorArgs) where TClassMap : ClassMap + { + var member = ReflectionHelper.GetMember(expression); + return References(typeof(TClassMap), member, constructorArgs); + } + + private (ClassMap, MemberInfo) GetMemberMap<TModel, TProperty>(Expression<Func<TModel, TProperty>> expression) + { + var stack = ReflectionHelper.GetMembers(expression); + if (stack.Count == 0) + { + throw new InvalidOperationException($"No members were found in expression '{expression}'."); + } + + ClassMap currentClassMap = this; + MemberInfo member; + + if (stack.Count > 1) + { + // We need to add a reference map for every sub member. + while (stack.Count > 1) + { + member = stack.Pop(); + Type mapType; + var property = member as PropertyInfo; + var field = member as FieldInfo; + if (property != null) + { + mapType = typeof(DefaultClassMap<>).MakeGenericType(property.PropertyType); + } + else if (field != null) + { + mapType = typeof(DefaultClassMap<>).MakeGenericType(field.FieldType); + } + else + { + throw new InvalidOperationException("The given expression was not a property or a field."); + } + + var referenceMap = currentClassMap.References(mapType, member); + currentClassMap = referenceMap.Data.Mapping; + } + } + + // Add the member map to the last reference map. + member = stack.Pop(); + + return (currentClassMap, member); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/ConfigurationException.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/ConfigurationException.cs new file mode 100644 index 0000000..8a9bba1 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/ConfigurationException.cs @@ -0,0 +1,36 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration +{ + /// <summary> + /// Represents configuration errors that occur. + /// </summary> + [Serializable] + public class ConfigurationException : CsvHelperException + { + /// <summary> + /// Initializes a new instance of the <see cref="ConfigurationException"/> class. + /// </summary> + public ConfigurationException() { } + + /// <summary> + /// Initializes a new instance of the <see cref="ConfigurationException"/> class + /// with a specified error message. + /// </summary> + /// <param name="message">The message that describes the error.</param> + public ConfigurationException( string message ) : base( message ) { } + + /// <summary> + /// Initializes a new instance of the <see cref="ConfigurationException"/> class + /// with a specified error message and a reference to the inner exception that + /// is the cause of this exception. + /// </summary> + /// <param name="message">The error message that explains the reason for the exception.</param> + /// <param name="innerException">The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.</param> + public ConfigurationException( string message, Exception innerException ) : base( message, innerException ) { } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/ConfigurationFunctions.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/ConfigurationFunctions.cs new file mode 100644 index 0000000..0cf7259 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/ConfigurationFunctions.cs @@ -0,0 +1,267 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using CsvHelper.Delegates; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; + +namespace CsvHelper.Configuration +{ + /// <summary>Holds the default callback methods for delegate members of <c>CsvHelper.Configuration.Configuration</c>.</summary> + public static class ConfigurationFunctions + { + private static readonly char[] lineEndingChars = new char[] { '\r', '\n' }; + + /// <summary> + /// Throws a <see cref="ValidationException"/> if <see name="HeaderValidatedArgs.InvalidHeaders"/> is not empty. + /// </summary> + public static void HeaderValidated(HeaderValidatedArgs args) + { + if (args.InvalidHeaders.Count() == 0) + { + return; + } + + var errorMessage = new StringBuilder(); + foreach (var invalidHeader in args.InvalidHeaders) + { + errorMessage.AppendLine($"Header with name '{string.Join("' or '", invalidHeader.Names)}'[{invalidHeader.Index}] was not found."); + } + + if (args.Context.Reader.HeaderRecord != null) + { + foreach (var header in args.Context.Reader.HeaderRecord) + { + errorMessage.AppendLine($"Headers: '{string.Join("', '", args.Context.Reader.HeaderRecord)}'"); + } + } + + var messagePostfix = + $"If you are expecting some headers to be missing and want to ignore this validation, " + + $"set the configuration {nameof(HeaderValidated)} to null. You can also change the " + + $"functionality to do something else, like logging the issue."; + errorMessage.AppendLine(messagePostfix); + + throw new HeaderValidationException(args.Context, args.InvalidHeaders, errorMessage.ToString()); + } + + /// <summary> + /// Throws a <c>MissingFieldException</c>. + /// </summary> + public static void MissingFieldFound(MissingFieldFoundArgs args) + { + var messagePostfix = $"You can ignore missing fields by setting {nameof(MissingFieldFound)} to null."; + + // Get by index. + + if (args.HeaderNames == null || args.HeaderNames.Length == 0) + { + throw new MissingFieldException(args.Context, $"Field at index '{args.Index}' does not exist. {messagePostfix}"); + } + + // Get by name. + + var indexText = args.Index > 0 ? $" at field index '{args.Index}'" : string.Empty; + + if (args.HeaderNames.Length == 1) + { + throw new MissingFieldException(args.Context, $"Field with name '{args.HeaderNames[0]}'{indexText} does not exist. {messagePostfix}"); + } + + throw new MissingFieldException(args.Context, $"Field containing names '{string.Join("' or '", args.HeaderNames)}'{indexText} does not exist. {messagePostfix}"); + } + + /// <summary> + /// Throws a <see cref="BadDataException"/>. + /// </summary> + public static void BadDataFound(BadDataFoundArgs args) + { + throw new BadDataException(args.Field, args.RawRecord, args.Context, $"You can ignore bad data by setting {nameof(BadDataFound)} to null."); + } + + /// <summary> + /// Throws the given <see name="ReadingExceptionOccurredArgs.Exception"/>. + /// </summary> + public static bool ReadingExceptionOccurred(ReadingExceptionOccurredArgs args) + { + return true; + } + + /// <summary> + /// Returns true if the field contains a <see cref="IWriterConfiguration.Quote"/>, + /// starts with a space, ends with a space, contains \r or \n, or contains + /// the <see cref="IWriterConfiguration.Delimiter"/>. + /// </summary> + /// <param name="args">The args.</param> + /// <returns><c>true</c> if the field should be quoted, otherwise <c>false</c>.</returns> + public static bool ShouldQuote(ShouldQuoteArgs args) + { + var config = args.Row.Configuration; + + var shouldQuote = !string.IsNullOrEmpty(args.Field) && + ( + args.Field.Contains(config.Quote) // Contains quote + || args.Field[0] == ' ' // Starts with a space + || args.Field[args.Field.Length - 1] == ' ' // Ends with a space + || (config.Delimiter.Length > 0 && args.Field.Contains(config.Delimiter)) // Contains delimiter + || !config.IsNewLineSet && args.Field.IndexOfAny(lineEndingChars) > -1 // Contains line ending characters + || config.IsNewLineSet && args.Field.Contains(config.NewLine) // Contains newline + ); + + return shouldQuote; + } + + /// <summary> + /// Returns the <see name="PrepareHeaderForMatchArgs.Header"/> as given. + /// </summary> + public static string PrepareHeaderForMatch(PrepareHeaderForMatchArgs args) + { + return args.Header; + } + + /// <summary> + /// Returns <c>true</c> if <paramref name="args.ParameterType"/>: + /// 1. does not have a parameterless constructor + /// 2. has a constructor + /// 3. is not a value type + /// 4. is not a primitive + /// 5. is not an enum + /// 6. is not an interface + /// 7. TypeCode is an Object. + /// </summary> + public static bool ShouldUseConstructorParameters(ShouldUseConstructorParametersArgs args) + { + return !args.ParameterType.HasParameterlessConstructor() + && args.ParameterType.HasConstructor() + && !args.ParameterType.IsValueType + && !args.ParameterType.IsPrimitive + && !args.ParameterType.IsEnum + && !args.ParameterType.IsInterface + && Type.GetTypeCode(args.ParameterType) == TypeCode.Object; + } + + /// <summary> + /// Returns the type's constructor with the most parameters. + /// If two constructors have the same number of parameters, then + /// there is no guarantee which one will be returned. If you have + /// that situation, you should probably implement this function yourself. + /// </summary> + public static ConstructorInfo GetConstructor(GetConstructorArgs args) + { + return args.ClassType.GetConstructorWithMostParameters(); + } + + /// <summary> + /// Returns the header name ran through <see cref="PrepareHeaderForMatch(PrepareHeaderForMatchArgs)"/>. + /// If no header exists, property names will be Field1, Field2, Field3, etc. + /// </summary> + /// <param name="args">The args.</param> + public static string GetDynamicPropertyName(GetDynamicPropertyNameArgs args) + { + if (args.Context.Reader.HeaderRecord == null) + { + return $"Field{args.FieldIndex + 1}"; + } + + var header = args.Context.Reader.HeaderRecord[args.FieldIndex]; + var prepareHeaderForMatchArgs = new PrepareHeaderForMatchArgs(header, args.FieldIndex); + header = args.Context.Reader.Configuration.PrepareHeaderForMatch(prepareHeaderForMatchArgs); + + return header; + } + + /// <summary> + /// Detects the delimiter based on the given text. + /// Return the detected delimiter or null if one wasn't found. + /// </summary> + /// <param name="args">The args.</param> + public static string? GetDelimiter(GetDelimiterArgs args) + { + var text = args.Text; + var config = args.Configuration; + + if (config.Mode == CsvMode.RFC4180) + { + // Remove text in between pairs of quotes. + text = Regex.Replace(text, $"{config.Quote}.*?{config.Quote}", string.Empty, RegexOptions.Singleline); + } + else if (config.Mode == CsvMode.Escape) + { + // Remove escaped characters. + text = Regex.Replace(text, $"({config.Escape}.)", string.Empty, RegexOptions.Singleline); + } + + var newLine = config.NewLine; + if ((new[] { "\r\n", "\r", "\n" }).Contains(newLine)) + { + newLine = "\r\n|\r|\n"; + } + + var lineDelimiterCounts = new List<Dictionary<string, int>>(); + while (text.Length > 0) + { + // Since all escaped text has been removed, we can reliably read line by line. + var match = Regex.Match(text, newLine); + var line = match.Success ? text.Substring(0, match.Index + match.Length) : text; + + var delimiterCounts = new Dictionary<string, int>(); + foreach (var delimiter in config.DetectDelimiterValues) + { + // Escape regex special chars to use as regex pattern. + var pattern = Regex.Replace(delimiter, @"([.$^{\[(|)*+?\\])", "\\$1"); + delimiterCounts[delimiter] = Regex.Matches(line, pattern).Count; + } + + lineDelimiterCounts.Add(delimiterCounts); + + text = match.Success ? text.Substring(match.Index + match.Length) : string.Empty; + } + + if (lineDelimiterCounts.Count > 1) + { + // The last line isn't complete and can't be used to reliably detect a delimiter. + lineDelimiterCounts.Remove(lineDelimiterCounts.Last()); + } + + // Rank only the delimiters that appear on every line. + var delimiters = + ( + from counts in lineDelimiterCounts + from count in counts + group count by count.Key into g + where g.All(x => x.Value > 0) + let sum = g.Sum(x => x.Value) + orderby sum descending + select new + { + Delimiter = g.Key, + Count = sum + } + ).ToList(); + + string? newDelimiter = null; + if (delimiters.Any(x => x.Delimiter == config.CultureInfo.TextInfo.ListSeparator) && lineDelimiterCounts.Count > 1) + { + // The culture's separator is on every line. Assume this is the delimiter. + newDelimiter = config.CultureInfo.TextInfo.ListSeparator; + } + else + { + // Choose the highest ranked delimiter. + newDelimiter = delimiters.Select(x => x.Delimiter).FirstOrDefault(); + } + + if (newDelimiter != null) + { + config.Validate(); + } + + return newDelimiter ?? config.Delimiter; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/CsvConfiguration.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/CsvConfiguration.cs new file mode 100644 index 0000000..51636a2 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/CsvConfiguration.cs @@ -0,0 +1,240 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using CsvHelper.Configuration.Attributes; +using CsvHelper.Delegates; +using CsvHelper.TypeConversion; + +namespace CsvHelper.Configuration +{ + /// <summary> + /// Configuration used for reading and writing CSV data. + /// </summary> + public record CsvConfiguration : IReaderConfiguration, IWriterConfiguration + { + private string newLine = "\r\n"; + + /// <inheritdoc/> + public virtual bool AllowComments { get; set; } + + /// <inheritdoc/> + public virtual BadDataFound BadDataFound { get; set; } = ConfigurationFunctions.BadDataFound; + + /// <inheritdoc/> + public virtual int BufferSize { get; set; } = 0x1000; + + /// <inheritdoc/> + public virtual bool CacheFields { get; set; } + + /// <inheritdoc/> + public virtual char Comment { get; set; } = '#'; + + /// <inheritdoc/> + public virtual bool CountBytes { get; set; } + + /// <inheritdoc/> + public virtual CultureInfo CultureInfo { get; protected set; } + + /// <inheritdoc/> + public virtual string Delimiter { get; set; } + + /// <inheritdoc/> + public virtual bool DetectDelimiter { get; set; } + + /// <inheritdoc/> + public virtual GetDelimiter GetDelimiter { get; set; } = ConfigurationFunctions.GetDelimiter; + + /// <inheritdoc/> + public virtual string[] DetectDelimiterValues { get; set; } = new[] { ",", ";", "|", "\t" }; + + /// <inheritdoc/> + public virtual bool DetectColumnCountChanges { get; set; } + + /// <inheritdoc/> + public virtual IComparer<string>? DynamicPropertySort { get; set; } + + /// <inheritdoc/> + public virtual Encoding Encoding { get; set; } = Encoding.UTF8; + + /// <inheritdoc/> + public virtual char Escape { get; set; } = '"'; + + /// <inheritdoc/> + public virtual bool ExceptionMessagesContainRawData { get; set; } = true; + + /// <inheritdoc/> + public virtual GetConstructor GetConstructor { get; set; } = ConfigurationFunctions.GetConstructor; + + /// <inheritdoc/> + public virtual GetDynamicPropertyName GetDynamicPropertyName { get; set; } = ConfigurationFunctions.GetDynamicPropertyName; + + /// <inheritdoc/> + public virtual bool HasHeaderRecord { get; set; } = true; + + /// <inheritdoc/> + public virtual HeaderValidated HeaderValidated { get; set; } = ConfigurationFunctions.HeaderValidated; + + /// <inheritdoc/> + public virtual bool IgnoreBlankLines { get; set; } = true; + + /// <inheritdoc/> + public virtual bool IgnoreReferences { get; set; } + + /// <inheritdoc/> + public virtual bool IncludePrivateMembers { get; set; } + + /// <inheritdoc/> + public virtual char[] InjectionCharacters { get; set; } = new[] { '=', '@', '+', '-', '\t', '\r' }; + + /// <inheritdoc/> + public virtual char InjectionEscapeCharacter { get; set; } = '\''; + + /// <inheritdoc /> + public virtual InjectionOptions InjectionOptions { get; set; } + + /// <inheritdoc/> + public bool IsNewLineSet { get; private set; } + + /// <inheritdoc/> + public virtual bool LineBreakInQuotedFieldIsBadData { get; set; } + + /// <inheritdoc/> + public double MaxFieldSize { get; set; } + + /// <inheritdoc/> + public virtual MemberTypes MemberTypes { get; set; } = MemberTypes.Properties; + + /// <inheritdoc/> + public virtual MissingFieldFound MissingFieldFound { get; set; } = ConfigurationFunctions.MissingFieldFound; + + /// <inheritdoc/> + public virtual CsvMode Mode { get; set; } + + /// <inheritdoc/> + public virtual string NewLine + { + get => newLine; + set + { + IsNewLineSet = true; + newLine = value; + } + } + + /// <inheritdoc/> + public virtual PrepareHeaderForMatch PrepareHeaderForMatch { get; set; } = ConfigurationFunctions.PrepareHeaderForMatch; + + /// <inheritdoc/> + public virtual int ProcessFieldBufferSize { get; set; } = 1024; + + /// <inheritdoc/> + public virtual char Quote { get; set; } = '"'; + + /// <inheritdoc/> + public virtual ReadingExceptionOccurred ReadingExceptionOccurred { get; set; } = ConfigurationFunctions.ReadingExceptionOccurred; + + /// <inheritdoc/> + public virtual ReferenceHeaderPrefix? ReferenceHeaderPrefix { get; set; } + + /// <inheritdoc/> + public ShouldQuote ShouldQuote { get; set; } = ConfigurationFunctions.ShouldQuote; + + /// <inheritdoc/> + public virtual ShouldSkipRecord? ShouldSkipRecord { get; set; } + + /// <inheritdoc/> + public virtual ShouldUseConstructorParameters ShouldUseConstructorParameters { get; set; } = ConfigurationFunctions.ShouldUseConstructorParameters; + + /// <inheritdoc/> + public virtual TrimOptions TrimOptions { get; set; } + + /// <inheritdoc/> + public virtual bool UseNewObjectForNullReferenceMembers { get; set; } = true; + + /// <inheritdoc/> + public virtual char[] WhiteSpaceChars { get; set; } = new char[] { ' ' }; + + /// <summary> + /// Initializes a new instance of the <see cref="CsvConfiguration"/> class + /// using the given <see cref="System.Globalization.CultureInfo"/>. Since <see cref="Delimiter"/> + /// uses <see cref="CultureInfo"/> for it's default, the given <see cref="System.Globalization.CultureInfo"/> + /// will be used instead. + /// </summary> + /// <param name="cultureInfo">The culture information.</param> + /// <param name="attributesType">The type that contains the configuration attributes. + /// This will call <see cref="ApplyAttributes(Type)"/> automatically.</param> + public CsvConfiguration(CultureInfo cultureInfo, Type? attributesType = null) + { + CultureInfo = cultureInfo; + Delimiter = cultureInfo.TextInfo.ListSeparator; + + if (attributesType != null) + { + ApplyAttributes(attributesType); + } + } + + /// <summary> + /// Validates the configuration. + /// </summary> + public void Validate() + { + var escape = Escape.ToString(); + var quote = Quote.ToString(); + var lineEndings = new[] { "\r", "\n", "\r\n" }; + var whiteSpaceChars = WhiteSpaceChars.Select(c => c.ToString()).ToArray(); + + // Escape + if (escape == Delimiter) throw new ConfigurationException($"The escape character '{Escape}' and delimiter '{Delimiter}' cannot be the same."); + if (escape == NewLine && IsNewLineSet) throw new ConfigurationException($"The escape character '{Escape}' and new line '{NewLine}' cannot be the same."); + if (lineEndings.Contains(Escape.ToString()) && !IsNewLineSet) throw new ConfigurationException($"The escape character '{Escape}' cannot be a line ending. ('\\r', '\\n', '\\r\\n')"); + if (whiteSpaceChars.Contains(escape)) throw new ConfigurationException($"The escape character '{Escape}' cannot be a WhiteSpaceChar."); + + // Quote + if (quote == Delimiter) throw new ConfigurationException($"The quote character '{Quote}' and the delimiter '{Delimiter}' cannot be the same."); + if (quote == NewLine && IsNewLineSet) throw new ConfigurationException($"The quote character '{Quote}' and new line '{NewLine}' cannot be the same."); + if (lineEndings.Contains(quote)) throw new ConfigurationException($"The quote character '{Quote}' cannot be a line ending. ('\\r', '\\n', '\\r\\n')"); + if (whiteSpaceChars.Contains(quote)) throw new ConfigurationException($"The quote character '{Quote}' cannot be a WhiteSpaceChar."); + + // Delimiter + if (Delimiter == NewLine && IsNewLineSet) throw new ConfigurationException($"The delimiter '{Delimiter}' and new line '{NewLine}' cannot be the same."); + if (lineEndings.Contains(Delimiter)) throw new ConfigurationException($"The delimiter '{Delimiter}' cannot be a line ending. ('\\r', '\\n', '\\r\\n')"); + if (whiteSpaceChars.Contains(Delimiter)) throw new ConfigurationException($"The delimiter '{Delimiter}' cannot be a WhiteSpaceChar."); + + // Detect Delimiter + if (DetectDelimiter && DetectDelimiterValues.Length == 0) throw new ConfigurationException($"At least one value is required for {nameof(DetectDelimiterValues)} when {nameof(DetectDelimiter)} is enabled."); + } + + /// <summary> + /// Applies class level attribute to configuration. + /// </summary> + /// <typeparam name="T">Type with attributes.</typeparam> + public CsvConfiguration ApplyAttributes<T>() + { + return ApplyAttributes(typeof(T)); + } + + /// <summary> + /// Applies class level attribute to configuration. + /// </summary> + /// <param name="type">Type with attributes.</param> + public CsvConfiguration ApplyAttributes(Type type) + { + var attributes = type.GetCustomAttributes().OfType<IClassMapper>(); + foreach (var attribute in attributes) + { + attribute.ApplyTo(this); + } + + return this; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/DefaultClassMap`1.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/DefaultClassMap`1.cs new file mode 100644 index 0000000..2e1b88b --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/DefaultClassMap`1.cs @@ -0,0 +1,15 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +namespace CsvHelper.Configuration +{ + /// <summary> + /// A default <see cref="ClassMap{T}"/> that can be used + /// to create a class map dynamically. + /// </summary> + /// <typeparam name="T"></typeparam> + public class DefaultClassMap<T> : ClassMap<T> + { + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/IParserConfiguration.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/IParserConfiguration.cs new file mode 100644 index 0000000..dec8594 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/IParserConfiguration.cs @@ -0,0 +1,176 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using CsvHelper.Delegates; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Text; + +namespace CsvHelper.Configuration +{ + /// <summary> + /// Configuration used for the <see cref="IParser"/>. + /// </summary> + public interface IParserConfiguration + { + /// <summary> + /// Gets the culture info used to read an write CSV files. + /// </summary> + CultureInfo CultureInfo { get; } + + /// <summary> + /// Cache fields that are created when parsing. + /// Default is false. + /// </summary> + bool CacheFields { get; } + + /// <summary> + /// The newline string to use. Default is \r\n (CRLF). + /// When writing, this value is always used. + /// When reading, this value is only used if explicitly set. + /// If not set, the parser uses one of \r\n, \r, or \n. + /// </summary> + string NewLine { get; } + + /// <summary> + /// A value indicating if <see cref="NewLine"/> was set. + /// </summary> + /// <value> + /// <c>true</c> if <see cref="NewLine"/> was set. <c>false</c> if <see cref="NewLine"/> is the default. + /// </value> + bool IsNewLineSet { get; } + + /// <summary> + /// The mode. + /// See <see cref="CsvMode"/> for more details. + /// </summary> + CsvMode Mode { get; } + + /// <summary> + /// Gets the size of the buffer + /// used for parsing and writing CSV files. + /// Default is 0x1000. + /// </summary> + int BufferSize { get; } + + /// <summary> + /// The size of the buffer used when processing fields. + /// Default is 1024. + /// </summary> + int ProcessFieldBufferSize { get; } + + /// <summary> + /// Gets a value indicating whether the number of bytes should + /// be counted while parsing. Default is false. This will slow down parsing + /// because it needs to get the byte count of every char for the given encoding. + /// The <see cref="Encoding"/> needs to be set correctly for this to be accurate. + /// </summary> + bool CountBytes { get; } + + /// <summary> + /// Gets the encoding used when counting bytes. + /// </summary> + Encoding Encoding { get; } + + /// <summary> + /// Gets the function that is called when bad field data is found. A field + /// has bad data if it contains a quote and the field is not quoted (escaped). + /// You can supply your own function to do other things like logging the issue + /// instead of throwing an exception. + /// </summary> + BadDataFound BadDataFound { get; } + + /// <summary> + /// Gets or sets the maximum size of a field. + /// Defaults to 0, indicating maximum field size is not checked. + /// </summary> + double MaxFieldSize { get; } + + /// <summary> + /// Gets a value indicating if a line break found in a quote field should + /// be considered bad data. <c>true</c> to consider a line break bad data, otherwise <c>false</c>. + /// Defaults to false. + /// </summary> + bool LineBreakInQuotedFieldIsBadData { get; } + + /// <summary> + /// Gets the character used to denote + /// a line that is commented out. Default is '#'. + /// </summary> + char Comment { get; } + + /// <summary> + /// Gets a value indicating if comments are allowed. + /// <c>true</c> to allow commented out lines, otherwise <c>false</c>. + /// </summary> + bool AllowComments { get; } + + /// <summary> + /// Gets a value indicating if blank lines + /// should be ignored when reading. + /// <c>true</c> to ignore, otherwise <c>false</c>. Default is true. + /// </summary> + bool IgnoreBlankLines { get; } + + /// <summary> + /// Gets the character used to quote fields. + /// Default is '"'. + /// </summary> + char Quote { get; } + + /// <summary> + /// The delimiter used to separate fields. + /// Default is <see cref="TextInfo.ListSeparator"/>. + /// </summary> + string Delimiter { get; } + + /// <summary> + /// Detect the delimiter instead of using the delimiter from configuration. + /// Default is <c>false</c>. + /// </summary> + bool DetectDelimiter { get; } + + /// <summary> + /// Gets the function that is called when <see cref="DetectDelimiter"/> is enabled. + /// </summary> + GetDelimiter GetDelimiter { get; } + + /// <summary> + /// The possible delimiter values used when detecting the delimiter. + /// Default is [",", ";", "|", "\t"]. + /// </summary> + string[] DetectDelimiterValues { get; } + + /// <summary> + /// The character used to escape characters. + /// Default is '"'. + /// </summary> + char Escape { get; } + + /// <summary> + /// Gets the field trimming options. + /// </summary> + TrimOptions TrimOptions { get; } + + /// <summary> + /// Characters considered whitespace. + /// Used when trimming fields. + /// Default is [' ']. + /// </summary> + char[] WhiteSpaceChars { get; } + + /// <summary> + /// A value indicating if exception messages contain raw CSV data. + /// <c>true</c> if exception contain raw CSV data, otherwise <c>false</c>. + /// Default is <c>true</c>. + /// </summary> + bool ExceptionMessagesContainRawData { get; } + + /// <summary> + /// Validates the configuration. + /// </summary> + void Validate(); + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/IReaderConfiguration.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/IReaderConfiguration.cs new file mode 100644 index 0000000..a1250e6 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/IReaderConfiguration.cs @@ -0,0 +1,111 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Globalization; +using CsvHelper.TypeConversion; +using System.Reflection; +using System.Collections.Generic; +using System.IO; + +namespace CsvHelper.Configuration +{ + /// <summary> + /// Configuration used for the <see cref="IReader"/>. + /// </summary> + public interface IReaderConfiguration : IParserConfiguration + { + /// <summary> + /// Gets a value indicating if the + /// CSV file has a header record. + /// Default is true. + /// </summary> + bool HasHeaderRecord { get; } + + /// <summary> + /// Gets the function that is called when a header validation check is ran. The default function + /// will throw a <see cref="ValidationException"/> if there is no header for a given member mapping. + /// You can supply your own function to do other things like logging the issue instead of throwing an exception. + /// </summary> + HeaderValidated HeaderValidated { get; } + + /// <summary> + /// Gets the function that is called when a missing field is found. The default function will + /// throw a <see cref="MissingFieldException"/>. You can supply your own function to do other things + /// like logging the issue instead of throwing an exception. + /// </summary> + MissingFieldFound MissingFieldFound { get; } + + /// <summary> + /// Gets the function that is called when a reading exception occurs. + /// The default function will re-throw the given exception. If you want to ignore + /// reading exceptions, you can supply your own function to do other things like + /// logging the issue. + /// </summary> + ReadingExceptionOccurred ReadingExceptionOccurred { get; } + + /// <summary> + /// Prepares the header field for matching against a member name. + /// The header field and the member name are both ran through this function. + /// You should do things like trimming, removing whitespace, removing underscores, + /// and making casing changes to ignore case. + /// </summary> + PrepareHeaderForMatch PrepareHeaderForMatch { get; } + + /// <summary> + /// Determines if constructor parameters should be used to create + /// the class instead of the default constructor and members. + /// </summary> + ShouldUseConstructorParameters ShouldUseConstructorParameters { get; } + + /// <summary> + /// Chooses the constructor to use for constructor mapping. + /// </summary> + GetConstructor GetConstructor { get; } + + /// <summary> + /// Gets the name to use for the property of the dynamic object. + /// </summary> + GetDynamicPropertyName GetDynamicPropertyName { get; } + + /// <summary> + /// Gets a value indicating whether references + /// should be ignored when auto mapping. <c>true</c> to ignore + /// references, otherwise <c>false</c>. Default is false. + /// </summary> + bool IgnoreReferences { get; } + + /// <summary> + /// Gets the callback that will be called to + /// determine whether to skip the given record or not. + /// </summary> + ShouldSkipRecord? ShouldSkipRecord { get; } + + /// <summary> + /// Gets a value indicating if private + /// member should be read from and written to. + /// <c>true</c> to include private member, otherwise <c>false</c>. Default is false. + /// </summary> + bool IncludePrivateMembers { get; } + + /// <summary> + /// Gets a callback that will return the prefix for a reference header. + /// </summary> + ReferenceHeaderPrefix ReferenceHeaderPrefix { get; } + + /// <summary> + /// Gets a value indicating whether changes in the column + /// count should be detected. If true, a <see cref="BadDataException"/> + /// will be thrown if a different column count is detected. + /// </summary> + bool DetectColumnCountChanges { get; } + + /// <summary> + /// Gets the member types that are used when auto mapping. + /// MemberTypes are flags, so you can choose more than one. + /// Default is Properties. + /// </summary> + MemberTypes MemberTypes { get; } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/IWriterConfiguration.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/IWriterConfiguration.cs new file mode 100644 index 0000000..349c493 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/IWriterConfiguration.cs @@ -0,0 +1,168 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System.Globalization; +using System.Collections.Generic; +using System.IO; + +namespace CsvHelper.Configuration +{ + /// <summary> + /// Configuration used for the <see cref="IWriter"/>. + /// </summary> + public interface IWriterConfiguration + { + /// <summary> + /// Gets the size of the buffer + /// used for parsing and writing CSV files. + /// Default is 0x1000. + /// </summary> + int BufferSize { get; } + + /// <summary> + /// The mode. + /// See <see cref="CsvMode"/> for more details. + /// </summary> + CsvMode Mode { get; } + + /// <summary> + /// Gets the delimiter used to separate fields. + /// Default is ','; + /// </summary> + string Delimiter { get; } + + /// <summary> + /// Gets the character used to quote fields. + /// Default is '"'. + /// </summary> + char Quote { get; } + + /// <summary> + /// The character used to escape characters. + /// Default is '"'. + /// </summary> + char Escape { get; } + + /// <summary> + /// Gets the field trimming options. + /// </summary> + TrimOptions TrimOptions { get; } + + /// <summary> + /// Gets the injection options. + /// </summary> + InjectionOptions InjectionOptions { get; } + + /// <summary> + /// Gets the characters that are used for injection attacks. + /// </summary> + char[] InjectionCharacters { get; } + + /// <summary> + /// Gets the character used to escape a detected injection. + /// </summary> + char InjectionEscapeCharacter { get; } + + /// <summary> + /// The newline string to use. Default is \r\n (CRLF). + /// When writing, this value is always used. + /// When reading, this value is only used if explicitly set. If not set, + /// the parser uses one of \r\n, \r, or \n. + /// </summary> + string NewLine { get; } + + /// <summary> + /// A value indicating if <see cref="NewLine"/> was set. + /// </summary> + /// <value> + /// <c>true</c> if <see cref="NewLine"/> was set. <c>false</c> if <see cref="NewLine"/> is the default. + /// </value> + bool IsNewLineSet { get; } + + /// <summary> + /// Gets a function that is used to determine if a field should get quoted + /// when writing. + /// </summary> + ShouldQuote ShouldQuote { get; } + + /// <summary> + /// Gets the culture info used to read and write CSV files. + /// </summary> + CultureInfo CultureInfo { get; } + + /// <summary> + /// Gets a value indicating if comments are allowed. + /// True to allow commented out lines, otherwise false. + /// </summary> + bool AllowComments { get; } + + /// <summary> + /// Gets the character used to denote + /// a line that is commented out. Default is '#'. + /// </summary> + char Comment { get; } + + /// <summary> + /// Gets a value indicating if the + /// CSV file has a header record. + /// Default is true. + /// </summary> + bool HasHeaderRecord { get; } + + /// <summary> + /// Gets a value indicating whether references + /// should be ignored when auto mapping. True to ignore + /// references, otherwise false. Default is false. + /// </summary> + bool IgnoreReferences { get; } + + /// <summary> + /// Gets a value indicating if private + /// member should be read from and written to. + /// True to include private member, otherwise false. Default is false. + /// </summary> + bool IncludePrivateMembers { get; } + + /// <summary> + /// Gets a callback that will return the prefix for a reference header. + /// </summary> + ReferenceHeaderPrefix ReferenceHeaderPrefix { get; } + + /// <summary> + /// Gets the member types that are used when auto mapping. + /// MemberTypes are flags, so you can choose more than one. + /// Default is Properties. + /// </summary> + MemberTypes MemberTypes { get; } + + /// <summary> + /// Gets a value indicating that during writing if a new + /// object should be created when a reference member is null. + /// True to create a new object and use it's defaults for the + /// fields, or false to leave the fields empty for all the + /// reference member's member. + /// </summary> + bool UseNewObjectForNullReferenceMembers { get; } + + /// <summary> + /// Gets the comparer used to order the properties + /// of dynamic objects when writing. The default is null, + /// which will preserve the order the object properties + /// were created with. + /// </summary> + IComparer<string> DynamicPropertySort { get; } + + /// <summary> + /// A value indicating if exception messages contain raw CSV data. + /// <c>true</c> if exception contain raw CSV data, otherwise <c>false</c>. + /// Default is <c>true</c>. + /// </summary> + bool ExceptionMessagesContainRawData { get; } + + /// <summary> + /// Validates the configuration. + /// </summary> + void Validate(); + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/InjectionOptions.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/InjectionOptions.cs new file mode 100644 index 0000000..a7dc20e --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/InjectionOptions.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CsvHelper.Configuration +{ + /// <summary> + /// Options for handling injection attacks. + /// </summary> + public enum InjectionOptions + { + /// <summary> + /// No injection protection. + /// </summary> + None = 0, + /// <summary> + /// Escape injection characters. + /// </summary> + Escape, + /// <summary> + /// Strip injection characters. + /// </summary> + Strip, + /// <summary> + /// Throw an exception if injection characters are detected. + /// </summary> + Exception, + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/MemberMap.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/MemberMap.cs new file mode 100644 index 0000000..006595d --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/MemberMap.cs @@ -0,0 +1,244 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using CsvHelper.TypeConversion; +using System; +using System.Collections; +using System.Diagnostics; +using System.Linq.Expressions; +using System.Reflection; + +namespace CsvHelper.Configuration +{ + /// <summary> + /// Mapping info for a member to a CSV field. + /// </summary> + [DebuggerDisplay("Member = {Data.Member}, Names = {string.Join(\",\", Data.Names)}, Index = {Data.Index}, Ignore = {Data.Ignore}, Member = {Data.Member}, TypeConverter = {Data.TypeConverter}")] + public abstract class MemberMap + { + /// <summary> + /// Gets the member map data. + /// </summary> + public virtual MemberMapData Data { get; protected set; } + + /// <summary> + /// Type converter options. + /// </summary> + public virtual MemberMapTypeConverterOption TypeConverterOption { get; protected set; } + + /// <summary> + /// Creates an instance of <see cref="MemberMap"/> using the given Type and <see cref="MemberInfo"/>. + /// </summary> + /// <param name="classType">Type of the class the member being mapped belongs to.</param> + /// <param name="member">The member being mapped.</param> + public static MemberMap CreateGeneric(Type classType, MemberInfo member) + { + var memberMapType = typeof(MemberMap<,>).MakeGenericType(classType, member.MemberType()); + var memberMap = (MemberMap)ObjectResolver.Current.Resolve(memberMapType, member); + + return memberMap; + } + + /// <summary> + /// When reading, is used to get the field + /// at the index of the name if there was a + /// header specified. It will look for the + /// first name match in the order listed. + /// When writing, sets the name of the + /// field in the header record. + /// The first name will be used. + /// </summary> + /// <param name="names">The possible names of the CSV field.</param> + public virtual MemberMap Name(params string[] names) + { + if (names == null || names.Length == 0) + { + throw new ArgumentNullException(nameof(names)); + } + + Data.Names.Clear(); + Data.Names.AddRange(names); + Data.IsNameSet = true; + + return this; + } + + /// <summary> + /// When reading, is used to get the + /// index of the name used when there + /// are multiple names that are the same. + /// </summary> + /// <param name="index">The index of the name.</param> + public virtual MemberMap NameIndex(int index) + { + Data.NameIndex = index; + + return this; + } + + /// <summary> + /// When reading, is used to get the field at + /// the given index. When writing, the fields + /// will be written in the order of the field + /// indexes. + /// </summary> + /// <param name="index">The index of the CSV field.</param> + /// <param name="indexEnd">The end index used when mapping to an <see cref="IEnumerable"/> member.</param> + public virtual MemberMap Index(int index, int indexEnd = -1) + { + Data.Index = index; + Data.IsIndexSet = true; + Data.IndexEnd = indexEnd; + + return this; + } + + /// <summary> + /// Ignore the member when reading and writing. + /// If this member has already been mapped as a reference + /// member, either by a class map, or by automapping, calling + /// this method will not ignore all the child members down the + /// tree that have already been mapped. + /// </summary> + public virtual MemberMap Ignore() + { + Data.Ignore = true; + + return this; + } + + /// <summary> + /// Ignore the member when reading and writing. + /// If this member has already been mapped as a reference + /// member, either by a class map, or by automapping, calling + /// this method will not ignore all the child members down the + /// tree that have already been mapped. + /// </summary> + /// <param name="ignore">True to ignore, otherwise false.</param> + public virtual MemberMap Ignore(bool ignore) + { + Data.Ignore = ignore; + + return this; + } + + /// <summary> + /// The default value that will be used when reading when + /// the CSV field is empty. + /// </summary> + /// <param name="defaultValue">The default value.</param> + /// <param name="useOnConversionFailure">Use default on conversion failure.</param> + public virtual MemberMap Default(object? defaultValue, bool useOnConversionFailure = false) + { + if (defaultValue == null && Data.Member.MemberType().IsValueType) + { + throw new ArgumentException($"Member of type '{Data.Member.MemberType().FullName}' can't have a default value of null."); + } + + if (defaultValue != null && !Data.Member.MemberType().IsAssignableFrom(defaultValue.GetType())) + { + throw new ArgumentException($"Default of type '{defaultValue.GetType().FullName}' is not assignable to '{Data.Member.MemberType().FullName}'."); + } + + Data.Default = defaultValue; + Data.IsDefaultSet = true; + Data.UseDefaultOnConversionFailure = useOnConversionFailure; + + return this; + } + + /// <summary> + /// The constant value that will be used for every record when + /// reading and writing. This value will always be used no matter + /// what other mapping configurations are specified. + /// </summary> + /// <param name="constantValue">The constant value.</param> + public virtual MemberMap Constant(object constantValue) + { + if (constantValue == null && Data.Member.MemberType().IsValueType) + { + throw new ArgumentException($"Member of type '{Data.Member.MemberType().FullName}' can't have a constant value of null."); + } + + if (constantValue != null && !Data.Member.MemberType().IsAssignableFrom(constantValue.GetType())) + { + throw new ArgumentException($"Constant of type '{constantValue.GetType().FullName}' is not assignable to '{Data.Member.MemberType().FullName}'."); + } + + Data.Constant = constantValue; + Data.IsConstantSet = true; + + return this; + } + + /// <summary> + /// Specifies the <see cref="TypeConverter"/> to use + /// when converting the member to and from a CSV field. + /// </summary> + /// <param name="typeConverter">The TypeConverter to use.</param> + public virtual MemberMap TypeConverter(ITypeConverter typeConverter) + { + Data.TypeConverter = typeConverter; + + return this; + } + + /// <summary> + /// Specifies the <see cref="TypeConverter"/> to use + /// when converting the member to and from a CSV field. + /// </summary> + /// <typeparam name="TConverter">The <see cref="System.Type"/> of the + /// <see cref="TypeConverter"/> to use.</typeparam> + public virtual MemberMap TypeConverter<TConverter>() where TConverter : ITypeConverter + { + TypeConverter(ObjectResolver.Current.Resolve<TConverter>()); + + return this; + } + + /// <summary> + /// Ignore the member when reading if no matching field name can be found. + /// </summary> + public virtual MemberMap Optional() + { + Data.IsOptional = true; + + return this; + } + + /// <summary> + /// Specifies an expression to be used to validate a field when reading. + /// </summary> + /// <param name="validateExpression"></param> + public virtual MemberMap Validate(Validate validateExpression) + { + return Validate(validateExpression, args => $"Field '{args.Field}' is not valid."); + } + + /// <summary> + /// Specifies an expression to be used to validate a field when reading along with specified exception message. + /// </summary> + /// <param name="validateExpression"></param> + /// <param name="validateMessageExpression"></param> + public virtual MemberMap Validate(Validate validateExpression, ValidateMessage validateMessageExpression) + { + var fieldParameter = Expression.Parameter(typeof(ValidateArgs), "field"); + var validateCallExpression = Expression.Call( + Expression.Constant(validateExpression.Target), + validateExpression.Method, + fieldParameter + ); + var messageCallExpression = Expression.Call( + Expression.Constant(validateMessageExpression.Target), + validateMessageExpression.Method, + fieldParameter + ); + + Data.ValidateExpression = Expression.Lambda<Validate>(validateCallExpression, fieldParameter); + Data.ValidateMessageExpression = Expression.Lambda<ValidateMessage>(messageCallExpression, fieldParameter); + + return this; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/MemberMapCollection.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/MemberMapCollection.cs new file mode 100644 index 0000000..0532544 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/MemberMapCollection.cs @@ -0,0 +1,247 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; + +namespace CsvHelper.Configuration +{ + /// <summary> + /// A collection that holds <see cref="MemberMap"/>'s. + /// </summary> + [DebuggerDisplay("Count = {list.Count}")] + public class MemberMapCollection : IList<MemberMap> + { + private readonly List<MemberMap> list = new List<MemberMap>(); + private readonly IComparer<MemberMap> comparer; + + /// <summary> + /// Gets the number of elements contained in the <see cref="T:System.Collections.Generic.ICollection`1"/>. + /// </summary> + /// <returns> + /// The number of elements contained in the <see cref="T:System.Collections.Generic.ICollection`1"/>. + /// </returns> + public virtual int Count => list.Count; + + /// <summary> + /// Gets a value indicating whether the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only. + /// </summary> + /// <returns> + /// true if the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only; otherwise, false. + /// </returns> + public virtual bool IsReadOnly => false; + + /// <summary> + /// Initializes a new instance of the <see cref="MemberMapCollection"/> class. + /// </summary> + public MemberMapCollection() : this(new MemberMapComparer()) { } + + /// <summary> + /// Initializes a new instance of the <see cref="MemberMapCollection"/> class. + /// </summary> + /// <param name="comparer">The comparer to use when sorting the member maps.</param> + public MemberMapCollection(IComparer<MemberMap> comparer) + { + this.comparer = comparer; + } + + /// <summary> + /// Returns an enumerator that iterates through the collection. + /// </summary> + /// <returns> + /// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection. + /// </returns> + /// <filterpriority>1</filterpriority> + public virtual IEnumerator<MemberMap> GetEnumerator() + { + return list.GetEnumerator(); + } + + /// <summary> + /// Returns an enumerator that iterates through a collection. + /// </summary> + /// <returns> + /// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection. + /// </returns> + /// <filterpriority>2</filterpriority> + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + /// <summary> + /// Adds an item to the <see cref="T:System.Collections.Generic.ICollection`1"/>. + /// </summary> + /// <param name="item">The object to add to the <see cref="T:System.Collections.Generic.ICollection`1"/>. + /// </param><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only. + /// </exception> + public virtual void Add(MemberMap item) + { + list.Add(item); + list.Sort(comparer); + } + + /// <summary> + /// Adds a range of items to the <see cref="T:System.Collections.Generic.ICollection`1"/>. + /// </summary> + /// <param name="collection">The collection to add.</param> + public virtual void AddRange(ICollection<MemberMap> collection) + { + list.AddRange(collection); + list.Sort(comparer); + } + + /// <summary> + /// Removes all items from the <see cref="T:System.Collections.Generic.ICollection`1"/>. + /// </summary> + /// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only. + /// </exception> + public virtual void Clear() + { + list.Clear(); + } + + /// <summary> + /// Determines whether the <see cref="T:System.Collections.Generic.ICollection`1"/> contains a specific value. + /// </summary> + /// <returns> + /// true if <paramref name="item"/> is found in the <see cref="T:System.Collections.Generic.ICollection`1"/>; otherwise, false. + /// </returns> + /// <param name="item">The object to locate in the <see cref="T:System.Collections.Generic.ICollection`1"/>. + /// </param> + public virtual bool Contains(MemberMap item) + { + return list.Contains(item); + } + + /// <summary> + /// Copies the elements of the <see cref="T:System.Collections.Generic.ICollection`1"/> to an <see cref="T:System.Array"/>, starting at a particular <see cref="T:System.Array"/> index. + /// </summary> + /// <param name="array">The one-dimensional <see cref="T:System.Array"/> that is the destination of the elements copied from <see cref="T:System.Collections.Generic.ICollection`1"/>. The <see cref="T:System.Array"/> must have zero-based indexing.</param><param name="arrayIndex">The zero-based index in <paramref name="array"/> at which copying begins.</param><exception cref="T:System.ArgumentNullException"><paramref name="array"/> is null.</exception><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="arrayIndex"/> is less than 0.</exception><exception cref="T:System.ArgumentException">The number of elements in the source <see cref="T:System.Collections.Generic.ICollection`1"/> is greater than the available space from <paramref name="arrayIndex"/> to the end of the destination <paramref name="array"/>.</exception> + public virtual void CopyTo(MemberMap[] array, int arrayIndex) + { + list.CopyTo(array, arrayIndex); + } + + /// <summary> + /// Removes the first occurrence of a specific object from the <see cref="T:System.Collections.Generic.ICollection`1"/>. + /// </summary> + /// <returns> + /// true if <paramref name="item"/> was successfully removed from the <see cref="T:System.Collections.Generic.ICollection`1"/>; otherwise, false. This method also returns false if <paramref name="item"/> is not found in the original <see cref="T:System.Collections.Generic.ICollection`1"/>. + /// </returns> + /// <param name="item">The object to remove from the <see cref="T:System.Collections.Generic.ICollection`1"/>. + /// </param><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only. + /// </exception> + public virtual bool Remove(MemberMap item) + { + return list.Remove(item); + } + + /// <summary> + /// Determines the index of a specific item in the <see cref="T:System.Collections.Generic.IList`1"/>. + /// </summary> + /// <returns> + /// The index of <paramref name="item"/> if found in the list; otherwise, -1. + /// </returns> + /// <param name="item">The object to locate in the <see cref="T:System.Collections.Generic.IList`1"/>. + /// </param> + public virtual int IndexOf(MemberMap item) + { + return list.IndexOf(item); + } + + /// <summary> + /// Inserts an item to the <see cref="T:System.Collections.Generic.IList`1"/> at the specified index. + /// </summary> + /// <param name="index">The zero-based index at which <paramref name="item"/> should be inserted. + /// </param><param name="item">The object to insert into the <see cref="T:System.Collections.Generic.IList`1"/>. + /// </param><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="index"/> is not a valid index in the <see cref="T:System.Collections.Generic.IList`1"/>. + /// </exception><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.IList`1"/> is read-only. + /// </exception> + public virtual void Insert(int index, MemberMap item) + { + list.Insert(index, item); + } + + /// <summary> + /// Removes the <see cref="T:System.Collections.Generic.IList`1"/> item at the specified index. + /// </summary> + /// <param name="index">The zero-based index of the item to remove. + /// </param><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="index"/> is not a valid index in the <see cref="T:System.Collections.Generic.IList`1"/>. + /// </exception><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.IList`1"/> is read-only. + /// </exception> + public virtual void RemoveAt(int index) + { + list.RemoveAt(index); + } + + /// <summary> + /// Gets or sets the element at the specified index. + /// </summary> + /// <returns> + /// The element at the specified index. + /// </returns> + /// <param name="index">The zero-based index of the element to get or set. + /// </param><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="index"/> is not a valid index in the <see cref="T:System.Collections.Generic.IList`1"/>. + /// </exception><exception cref="T:System.NotSupportedException">The member is set and the <see cref="T:System.Collections.Generic.IList`1"/> is read-only. + /// </exception> + public virtual MemberMap this[int index] + { + get { return list[index]; } + set { list[index] = value; } + } + + /// <summary> + /// Finds the <see cref="MemberMap"/> using the given member expression. + /// </summary> + /// <typeparam name="T">The <see cref="System.Type"/> the member is on.</typeparam> + /// <param name="expression">The member expression.</param> + /// <returns>The <see cref="MemberMap"/> for the given expression, or null if not found.</returns> + public virtual MemberMap? Find<T>(Expression<Func<T, object>> expression) + { + var member = ReflectionHelper.GetMember(expression); + return Find(member); + } + + /// <summary> + /// Finds the <see cref="MemberMap"/> using the given member. + /// </summary> + /// <param name="member">The member.</param> + /// <returns>The <see cref="MemberMap"/> for the given expression, or null if not found.</returns> + public virtual MemberMap? Find(MemberInfo member) + { + var existingMap = list.SingleOrDefault(m => + m.Data.Member == member || + m.Data.Member != null && + m.Data.Member.Name == member.Name && + ( + m.Data.Member.DeclaringType.IsAssignableFrom(member.DeclaringType) || + member.DeclaringType.IsAssignableFrom(m.Data.Member.DeclaringType) + ) + ); + + return existingMap; + } + + /// <summary> + /// Adds the members from the mapping. This will recursively + /// traverse the mapping tree and add all members for + /// reference maps. + /// </summary> + /// <param name="mapping">The mapping where the members are added from.</param> + public virtual void AddMembers(ClassMap mapping) + { + AddRange(mapping.MemberMaps); + foreach (var refmap in mapping.ReferenceMaps) + { + AddMembers(refmap.Data.Mapping); + } + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/MemberMapComparer.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/MemberMapComparer.cs new file mode 100644 index 0000000..84cdf6c --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/MemberMapComparer.cs @@ -0,0 +1,74 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; + +namespace CsvHelper.Configuration +{ + /// <summary> + /// Used to compare <see cref="MemberMap"/>s. + /// The order is by field index ascending. Any + /// fields that don't have an index are pushed + /// to the bottom. + /// </summary> + internal class MemberMapComparer : IComparer<MemberMap> + { + /// <summary> + /// Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other. + /// </summary> + /// <returns> + /// Value + /// Condition + /// Less than zero + /// <paramref name="x"/> is less than <paramref name="y"/>. + /// Zero + /// <paramref name="x"/> equals <paramref name="y"/>. + /// Greater than zero + /// <paramref name="x"/> is greater than <paramref name="y"/>. + /// </returns> + /// <param name="x">The first object to compare. + /// </param><param name="y">The second object to compare. + /// </param><exception cref="T:System.ArgumentException">Neither <paramref name="x"/> nor <paramref name="y"/> implements the <see cref="T:System.IComparable"/> interface. + /// -or- + /// <paramref name="x"/> and <paramref name="y"/> are of different types and neither one can handle comparisons with the other. + /// </exception><filterpriority>2</filterpriority> + public virtual int Compare( object x, object y ) + { + var xMember = x as MemberMap; + var yMember = y as MemberMap; + return Compare( xMember, yMember ); + } + + /// <summary> + /// Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other. + /// </summary> + /// <returns> + /// Value + /// Condition + /// Less than zero + /// <paramref name="x"/> is less than <paramref name="y"/>. + /// Zero + /// <paramref name="x"/> equals <paramref name="y"/>. + /// Greater than zero + /// <paramref name="x"/> is greater than <paramref name="y"/>. + /// </returns> + /// <param name="x">The first object to compare. + /// </param><param name="y">The second object to compare. + /// </param> + public virtual int Compare( MemberMap x, MemberMap y ) + { + if( x == null ) + { + throw new ArgumentNullException( nameof( x ) ); + } + if( y == null ) + { + throw new ArgumentNullException( nameof( y ) ); + } + + return x.Data.Index.CompareTo( y.Data.Index ); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/MemberMapData.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/MemberMapData.cs new file mode 100644 index 0000000..07d696a --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/MemberMapData.cs @@ -0,0 +1,167 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System.Reflection; +using CsvHelper.TypeConversion; +using System.Linq.Expressions; +using System; + +namespace CsvHelper.Configuration +{ + /// <summary> + /// The configured data for the member map. + /// </summary> + public class MemberMapData + { + /// <summary> + /// Gets the member type. + /// </summary> + public virtual Type Type + { + get + { + if (Member != null) + { + return Member.MemberType(); + } + + if (IsConstantSet) + { + return Constant?.GetType() ?? typeof(string); + } + + if (IsDefaultSet) + { + return Default?.GetType() ?? typeof(string); + } + + return typeof(string); + } + } + + /// <summary> + /// Gets the <see cref="MemberInfo"/> that the data + /// is associated with. + /// </summary> + public virtual MemberInfo? Member { get; private set; } + + /// <summary> + /// Gets the list of column names. + /// </summary> + public virtual MemberNameCollection Names { get; } = new MemberNameCollection(); + + /// <summary> + /// Gets or sets the index of the name. + /// This is used if there are multiple + /// columns with the same names. + /// </summary> + public virtual int NameIndex { get; set; } + + /// <summary> + /// Gets or sets a value indicating if the name was + /// explicitly set. True if it was explicitly set, + /// otherwise false. + /// </summary> + public virtual bool IsNameSet { get; set; } + + /// <summary> + /// Gets or sets the column index. + /// </summary> + public virtual int Index { get; set; } = -1; + + /// <summary> + /// Gets or sets the index end. The Index end is used to specify a range for use + /// with a collection member. Index is used as the start of the range, and IndexEnd + /// is the end of the range. + /// </summary> + public virtual int IndexEnd { get; set; } = -1; + + /// <summary> + /// Gets or sets a value indicating if the index was + /// explicitly set. True if it was explicitly set, + /// otherwise false. + /// </summary> + public virtual bool IsIndexSet { get; set; } + + /// <summary> + /// Gets or sets the type converter. + /// </summary> + public virtual ITypeConverter? TypeConverter { get; set; } + + /// <summary> + /// Gets or sets the type converter options. + /// </summary> + public virtual TypeConverterOptions TypeConverterOptions { get; set; } = new TypeConverterOptions(); + + /// <summary> + /// Gets or sets a value indicating whether the field should be ignored. + /// </summary> + public virtual bool Ignore { get; set; } + + /// <summary> + /// Gets or sets the default value used when a CSV field is empty. + /// </summary> + public virtual object? Default { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether this instance is default value set. + /// the default value was explicitly set. True if it was + /// explicitly set, otherwise false. + /// </summary> + public virtual bool IsDefaultSet { get; set; } + + /// <summary> + /// Gets or setse a value indicating if the default value should be used when + /// a type conversion failure happens. <c>true</c> to use the default, otherwise + /// <c>false</c>. + /// </summary> + public virtual bool UseDefaultOnConversionFailure { get; set; } + + /// <summary> + /// Gets or sets the constant value used for every record. + /// </summary> + public virtual object? Constant { get; set; } + + /// <summary> + /// Gets or sets a value indicating if a constant was explicitly set. + /// </summary> + public virtual bool IsConstantSet { get; set; } + + /// <summary> + /// Gets or sets the expression used to convert data in the + /// row to the member. + /// </summary> + public virtual Expression ReadingConvertExpression { get; set; } + + /// <summary> + /// Gets or sets the expression to be used to convert the object + /// to a field. + /// </summary> + public virtual Expression WritingConvertExpression { get; set; } + + /// <summary> + /// Gets or sets the expression use to validate a field. + /// </summary> + public virtual Expression ValidateExpression { get; set; } + + /// <summary> + /// Gets or sets the expression used to get the validation message when validation fails. + /// </summary> + public virtual Expression ValidateMessageExpression { get; set; } + + /// <summary> + /// Gets or sets a value indicating if a field is optional. + /// </summary> + public virtual bool IsOptional { get; set; } + + /// <summary> + /// Initializes a new instance of the <see cref="MemberMapData"/> class. + /// </summary> + /// <param name="member">The member.</param> + public MemberMapData(MemberInfo? member) + { + Member = member; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/MemberMapTypeConverterOption.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/MemberMapTypeConverterOption.cs new file mode 100644 index 0000000..bafad45 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/MemberMapTypeConverterOption.cs @@ -0,0 +1,167 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Globalization; + +namespace CsvHelper.Configuration +{ + /// <summary> + /// Sets type converter options on a member map. + /// </summary> + public class MemberMapTypeConverterOption + { + private readonly MemberMap memberMap; + + /// <summary> + /// Creates a new instance using the given <see cref="MemberMap"/>. + /// </summary> + /// <param name="memberMap">The member map the options are being applied to.</param> + public MemberMapTypeConverterOption(MemberMap memberMap) + { + this.memberMap = memberMap; + } + + /// <summary> + /// The <see cref="CultureInfo"/> used when type converting. + /// This will override the global <see cref="CsvConfiguration.CultureInfo"/> + /// setting. + /// </summary> + /// <param name="cultureInfo">The culture info.</param> + public virtual MemberMap CultureInfo(CultureInfo cultureInfo) + { + memberMap.Data.TypeConverterOptions.CultureInfo = cultureInfo; + + return memberMap; + } + + /// <summary> + /// The <see cref="DateTimeStyles"/> to use when type converting. + /// This is used when doing any <see cref="DateTime"/> conversions. + /// </summary> + /// <param name="dateTimeStyle">The date time style.</param> + public virtual MemberMap DateTimeStyles(DateTimeStyles dateTimeStyle) + { + memberMap.Data.TypeConverterOptions.DateTimeStyle = dateTimeStyle; + + return memberMap; + } + + /// <summary> + /// The <see cref="TimeSpanStyles"/> to use when type converting. + /// This is used when doing <see cref="TimeSpan"/> converting. + /// </summary> + /// <param name="timeSpanStyles">The time span styles.</param> + public virtual MemberMap TimespanStyles(TimeSpanStyles timeSpanStyles) + { + memberMap.Data.TypeConverterOptions.TimeSpanStyle = timeSpanStyles; + + return memberMap; + } + + /// <summary> + /// The <see cref="NumberStyles"/> to use when type converting. + /// This is used when doing any number conversions. + /// </summary> + /// <param name="numberStyle"></param> + public virtual MemberMap NumberStyles(NumberStyles numberStyle) + { + memberMap.Data.TypeConverterOptions.NumberStyles = numberStyle; + + return memberMap; + } + + /// <summary> + /// The string format to be used when type converting. + /// </summary> + /// <param name="formats">The format.</param> + public virtual MemberMap Format(params string[] formats) + { + memberMap.Data.TypeConverterOptions.Formats = formats; + + return memberMap; + } + + /// <summary> + /// The <see cref="UriKind"/> to use when converting. + /// This is used when doing <see cref="Uri"/> conversions. + /// </summary> + /// <param name="uriKind">Kind of the URI.</param> + public virtual MemberMap UriKind(UriKind uriKind) + { + memberMap.Data.TypeConverterOptions.UriKind = uriKind; + + return memberMap; + } + + /// <summary> + /// The string values used to represent a boolean when converting. + /// </summary> + /// <param name="isTrue">A value indicating whether true values or false values are being set.</param> + /// <param name="clearValues">A value indication if the current values should be cleared before adding the new ones.</param> + /// <param name="booleanValues">The string boolean values.</param> + public virtual MemberMap BooleanValues(bool isTrue, bool clearValues = true, params string[] booleanValues) + { + if (isTrue) + { + if (clearValues) + { + memberMap.Data.TypeConverterOptions.BooleanTrueValues.Clear(); + } + + memberMap.Data.TypeConverterOptions.BooleanTrueValues.AddRange(booleanValues); + } + else + { + if (clearValues) + { + memberMap.Data.TypeConverterOptions.BooleanFalseValues.Clear(); + } + + memberMap.Data.TypeConverterOptions.BooleanFalseValues.AddRange(booleanValues); + } + + return memberMap; + } + + /// <summary> + /// The string values used to represent null when converting. + /// </summary> + /// <param name="nullValues">The values that represent null.</param> + /// <returns></returns> + public virtual MemberMap NullValues(params string[] nullValues) + { + return NullValues(true, nullValues); + } + + /// <summary> + /// The string values used to represent null when converting. + /// </summary> + /// <param name="clearValues">A value indication if the current values should be cleared before adding the new ones.</param> + /// <param name="nullValues">The values that represent null.</param> + /// <returns></returns> + public virtual MemberMap NullValues(bool clearValues, params string[] nullValues) + { + if (clearValues) + { + memberMap.Data.TypeConverterOptions.NullValues.Clear(); + } + + memberMap.Data.TypeConverterOptions.NullValues.AddRange(nullValues); + + return memberMap; + } + + /// <summary> + /// Ignore case when parsing enums. + /// </summary> + /// <param name="ignoreCase"><c>true</c> to ignore case, otherwise <c>false</c>.</param> + public virtual MemberMap EnumIgnoreCase(bool ignoreCase = true) + { + memberMap.Data.TypeConverterOptions.EnumIgnoreCase = ignoreCase; + + return memberMap; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/MemberMap`1.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/MemberMap`1.cs new file mode 100644 index 0000000..590f05a --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/MemberMap`1.cs @@ -0,0 +1,270 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using CsvHelper.TypeConversion; +using System; +using System.Collections; +using System.Linq.Expressions; +using System.Reflection; + +namespace CsvHelper.Configuration +{ + /// <summary> + /// Mapping info for a member to a CSV field. + /// </summary> + public class MemberMap<TClass, TMember> : MemberMap + { + /// <summary> + /// Creates a new <see cref="MemberMap"/> instance using the specified member. + /// </summary> + public MemberMap(MemberInfo? member) + { + TypeConverterOption = new MemberMapTypeConverterOption(this); + + Data = new MemberMapData(member); + } + + /// <summary> + /// When reading, is used to get the field + /// at the index of the name if there was a + /// header specified. It will look for the + /// first name match in the order listed. + /// When writing, sets the name of the + /// field in the header record. + /// The first name will be used. + /// </summary> + /// <param name="names">The possible names of the CSV field.</param> + public new virtual MemberMap<TClass, TMember> Name(params string[] names) + { + if (names == null || names.Length == 0) + { + throw new ArgumentNullException(nameof(names)); + } + + Data.Names.Clear(); + Data.Names.AddRange(names); + Data.IsNameSet = true; + + return this; + } + + /// <summary> + /// When reading, is used to get the + /// index of the name used when there + /// are multiple names that are the same. + /// </summary> + /// <param name="index">The index of the name.</param> + public new virtual MemberMap<TClass, TMember> NameIndex(int index) + { + Data.NameIndex = index; + + return this; + } + + /// <summary> + /// When reading, is used to get the field at + /// the given index. When writing, the fields + /// will be written in the order of the field + /// indexes. + /// </summary> + /// <param name="index">The index of the CSV field.</param> + /// <param name="indexEnd">The end index used when mapping to an <see cref="IEnumerable"/> member.</param> + public new virtual MemberMap<TClass, TMember> Index(int index, int indexEnd = -1) + { + Data.Index = index; + Data.IsIndexSet = true; + Data.IndexEnd = indexEnd; + + return this; + } + + /// <summary> + /// Ignore the member when reading and writing. + /// If this member has already been mapped as a reference + /// member, either by a class map, or by automapping, calling + /// this method will not ignore all the child members down the + /// tree that have already been mapped. + /// </summary> + public new virtual MemberMap<TClass, TMember> Ignore() + { + Data.Ignore = true; + + return this; + } + + /// <summary> + /// Ignore the member when reading and writing. + /// If this member has already been mapped as a reference + /// member, either by a class map, or by automapping, calling + /// this method will not ignore all the child members down the + /// tree that have already been mapped. + /// </summary> + /// <param name="ignore">True to ignore, otherwise false.</param> + public new virtual MemberMap<TClass, TMember> Ignore(bool ignore) + { + Data.Ignore = ignore; + + return this; + } + + /// <summary> + /// The default value that will be used when reading when + /// the CSV field is empty. + /// </summary> + /// <param name="defaultValue">The default value.</param> + /// <param name="useOnConversionFailure">Use default on conversion failure.</param> + public virtual MemberMap<TClass, TMember> Default(TMember defaultValue, bool useOnConversionFailure = false) + { + Data.Default = defaultValue; + Data.IsDefaultSet = true; + Data.UseDefaultOnConversionFailure = useOnConversionFailure; + + return this; + } + + /// <summary> + /// The default value that will be used when reading when + /// the CSV field is empty. This value is not type checked + /// and will use a <see cref="ITypeConverter"/> to convert + /// the field. This could potentially have runtime errors. + /// </summary> + /// <param name="defaultValue">The default value.</param> + /// <param name="useOnConversionFailure">Use default on conversion failure.</param> + public virtual MemberMap<TClass, TMember> Default(string defaultValue, bool useOnConversionFailure = false) + { + Data.Default = defaultValue; + Data.IsDefaultSet = true; + Data.UseDefaultOnConversionFailure = useOnConversionFailure; + + return this; + } + + /// <summary> + /// The constant value that will be used for every record when + /// reading and writing. This value will always be used no matter + /// what other mapping configurations are specified. + /// </summary> + /// <param name="constantValue">The constant value.</param> + public virtual MemberMap<TClass, TMember> Constant(TMember? constantValue) + { + Data.Constant = constantValue; + Data.IsConstantSet = true; + + return this; + } + + /// <summary> + /// Specifies the <see cref="TypeConverter"/> to use + /// when converting the member to and from a CSV field. + /// </summary> + /// <param name="typeConverter">The TypeConverter to use.</param> + public new virtual MemberMap<TClass, TMember> TypeConverter(ITypeConverter typeConverter) + { + Data.TypeConverter = typeConverter; + + return this; + } + + /// <summary> + /// Specifies the <see cref="TypeConverter"/> to use + /// when converting the member to and from a CSV field. + /// </summary> + /// <typeparam name="TConverter">The <see cref="System.Type"/> of the + /// <see cref="TypeConverter"/> to use.</typeparam> + public new virtual MemberMap<TClass, TMember> TypeConverter<TConverter>() where TConverter : ITypeConverter + { + TypeConverter(ObjectResolver.Current.Resolve<TConverter>()); + + return this; + } + + /// <summary> + /// Specifies an expression to be used to convert data in the + /// row to the member. + /// </summary> + /// <param name="convertFromStringFunction">The convert expression.</param> + public virtual MemberMap<TClass, TMember> Convert(ConvertFromString<TMember> convertFromStringFunction) + { + var instance = convertFromStringFunction.Target != null ? Expression.Constant(convertFromStringFunction.Target) : null; + var fieldParameter = Expression.Parameter(typeof(ConvertFromStringArgs), "args"); + var methodExpression = Expression.Call + ( + instance, + convertFromStringFunction.Method, + fieldParameter + ); + var lambdaExpression = Expression.Lambda<ConvertFromString<TMember>>(methodExpression, fieldParameter); + + Data.ReadingConvertExpression = lambdaExpression; + + return this; + } + + /// <summary> + /// Specifies an expression to be used to convert the object + /// to a field. + /// </summary> + /// <param name="convertToStringFunction">The convert expression.</param> + public virtual MemberMap<TClass, TMember> Convert(ConvertToString<TClass> convertToStringFunction) + { + var instance = convertToStringFunction.Target != null ? Expression.Constant(convertToStringFunction.Target) : null; + var fieldParameter = Expression.Parameter(typeof(ConvertToStringArgs<TClass>), "args"); + var methodExpression = Expression.Call + ( + instance, + convertToStringFunction.Method, + fieldParameter + ); + var lambdaExpression = Expression.Lambda<ConvertToString<TClass>>(methodExpression, fieldParameter); + + Data.WritingConvertExpression = lambdaExpression; + + return this; + } + + /// <summary> + /// Ignore the member when reading if no matching field name can be found. + /// </summary> + public new virtual MemberMap<TClass, TMember> Optional() + { + Data.IsOptional = true; + + return this; + } + + /// <summary> + /// Specifies an expression to be used to validate a field when reading. + /// </summary> + /// <param name="validateExpression"></param> + public new virtual MemberMap<TClass, TMember> Validate(Validate validateExpression) + { + return Validate(validateExpression, args => $"Field '{args.Field}' is not valid."); + } + + /// <summary> + /// Specifies an expression to be used to validate a field when reading along with specified exception message. + /// </summary> + /// <param name="validateExpression"></param> + /// <param name="validateMessageExpression"></param> + public new virtual MemberMap<TClass, TMember> Validate(Validate validateExpression, ValidateMessage validateMessageExpression) + { + var fieldParameter = Expression.Parameter(typeof(ValidateArgs), "args"); + var validateCallExpression = Expression.Call( + Expression.Constant(validateExpression.Target), + validateExpression.Method, + fieldParameter + ); + var messageCallExpression = Expression.Call( + Expression.Constant(validateMessageExpression.Target), + validateMessageExpression.Method, + fieldParameter + ); + + Data.ValidateExpression = Expression.Lambda<Validate>(validateCallExpression, fieldParameter); + Data.ValidateMessageExpression = Expression.Lambda<ValidateMessage>(messageCallExpression, fieldParameter); + + return this; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/MemberNameCollection.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/MemberNameCollection.cs new file mode 100644 index 0000000..fb9db4a --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/MemberNameCollection.cs @@ -0,0 +1,98 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System.Collections; +using System.Collections.Generic; + +namespace CsvHelper.Configuration +{ + /// <summary> + /// A collection that holds member names. + /// </summary> + public class MemberNameCollection : IEnumerable<string> + { + private readonly List<string> names = new List<string>(); + + /// <summary> + /// Gets the name at the given index. If a prefix is set, + /// it will be prepended to the name. + /// </summary> + /// <param name="index"></param> + /// <returns></returns> + public string this[int index] + { + get { return Prefix + names[index]; } + set { names[index] = value; } + } + + /// <summary> + /// Gets the prefix to use for each name. + /// </summary> + public string Prefix { get; set; } + + /// <summary> + /// Gets the raw list of names without + /// the prefix being prepended. + /// </summary> + public List<string> Names => names; + + /// <summary> + /// Gets the count. + /// </summary> + public int Count => names.Count; + + /// <summary> + /// Adds the given name to the collection. + /// </summary> + /// <param name="name">The name to add.</param> + public void Add(string name) + { + names.Add(name); + } + + /// <summary> + /// Clears all names from the collection. + /// </summary> + public void Clear() + { + names.Clear(); + } + + /// <summary> + /// Adds a range of names to the collection. + /// </summary> + /// <param name="names">The range to add.</param> + public void AddRange(IEnumerable<string> names) + { + this.names.AddRange(names); + } + + /// <summary> + /// Returns an enumerator that iterates through the collection. + /// </summary> + /// <returns> + /// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection. + /// </returns> + /// <filterpriority>1</filterpriority> + public IEnumerator<string> GetEnumerator() + { + for (var i = 0; i < names.Count; i++) + { + yield return this[i]; + } + } + + /// <summary> + /// Returns an enumerator that iterates through a collection. + /// </summary> + /// <returns> + /// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection. + /// </returns> + /// <filterpriority>2</filterpriority> + IEnumerator IEnumerable.GetEnumerator() + { + return names.GetEnumerator(); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/MemberReferenceMap.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/MemberReferenceMap.cs new file mode 100644 index 0000000..66dca90 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/MemberReferenceMap.cs @@ -0,0 +1,68 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Diagnostics; +using System.Reflection; + +namespace CsvHelper.Configuration +{ + /// <summary> + /// Mapping info for a reference member mapping to a class. + /// </summary> + [DebuggerDisplay("Member = {Data.Member}, Prefix = {Data.Prefix}")] + public class MemberReferenceMap + { + private readonly MemberReferenceMapData data; + + /// <summary> + /// Gets the member reference map data. + /// </summary> + public MemberReferenceMapData Data => data; + + /// <summary> + /// Initializes a new instance of the <see cref="MemberReferenceMap"/> class. + /// </summary> + /// <param name="member">The member.</param> + /// <param name="mapping">The <see cref="ClassMap"/> to use for the reference map.</param> + public MemberReferenceMap(MemberInfo member, ClassMap mapping) + { + if (mapping == null) + { + throw new ArgumentNullException(nameof(mapping)); + } + + data = new MemberReferenceMapData(member, mapping); + } + + /// <summary> + /// Appends a prefix to the header of each field of the reference member. + /// </summary> + /// <param name="prefix">The prefix to be prepended to headers of each reference member.</param> + /// <param name="inherit">Inherit parent prefixes.</param> + /// <returns>The current <see cref="MemberReferenceMap" /></returns> + public MemberReferenceMap Prefix(string? prefix = null, bool inherit = false) + { + if (string.IsNullOrEmpty(prefix)) + { + prefix = data.Member.Name + "."; + } + + data.Inherit = inherit; + data.Prefix = prefix; + + return this; + } + + /// <summary> + /// Get the largest index for the + /// members and references. + /// </summary> + /// <returns>The max index.</returns> + internal int GetMaxIndex() + { + return data.Mapping.GetMaxIndex(); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/MemberReferenceMapCollection.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/MemberReferenceMapCollection.cs new file mode 100644 index 0000000..c8745ed --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/MemberReferenceMapCollection.cs @@ -0,0 +1,164 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; + +namespace CsvHelper.Configuration +{ + /// <summary> + /// A collection that holds <see cref="MemberReferenceMap"/>'s. + /// </summary> + [DebuggerDisplay("Count = {list.Count}")] + public class MemberReferenceMapCollection : IList<MemberReferenceMap> + { + private readonly List<MemberReferenceMap> list = new List<MemberReferenceMap>(); + + /// <summary>Gets the number of elements contained in the <see cref="T:System.Collections.Generic.ICollection`1" />.</summary> + /// <returns>The number of elements contained in the <see cref="T:System.Collections.Generic.ICollection`1" />.</returns> + public virtual int Count => list.Count; + + /// <summary>Gets a value indicating whether the <see cref="T:System.Collections.Generic.ICollection`1" /> is read-only.</summary> + /// <returns>true if the <see cref="T:System.Collections.Generic.ICollection`1" /> is read-only; otherwise, false.</returns> + public virtual bool IsReadOnly => false; + + /// <summary>Gets or sets the element at the specified index.</summary> + /// <returns>The element at the specified index.</returns> + /// <param name="index">The zero-based index of the element to get or set.</param> + /// <exception cref="T:System.ArgumentOutOfRangeException"> + /// <paramref name="index" /> is not a valid index in the <see cref="T:System.Collections.Generic.IList`1" />.</exception> + /// <exception cref="T:System.NotSupportedException">The member is set and the <see cref="T:System.Collections.Generic.IList`1" /> is read-only.</exception> + public virtual MemberReferenceMap this[int index] + { + get => list[index]; + set => list[index] = value; + } + + /// <summary>Returns an enumerator that iterates through the collection.</summary> + /// <returns>A <see cref="T:System.Collections.Generic.IEnumerator`1" /> that can be used to iterate through the collection.</returns> + /// <filterpriority>1</filterpriority> + public virtual IEnumerator<MemberReferenceMap> GetEnumerator() + { + return list.GetEnumerator(); + } + + /// <summary>Returns an enumerator that iterates through a collection.</summary> + /// <returns>An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.</returns> + /// <filterpriority>2</filterpriority> + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + /// <summary>Adds an item to the <see cref="T:System.Collections.Generic.ICollection`1" />.</summary> + /// <param name="item">The object to add to the <see cref="T:System.Collections.Generic.ICollection`1" />.</param> + /// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1" /> is read-only.</exception> + public virtual void Add(MemberReferenceMap item) + { + list.Add(item); + } + + /// <summary>Removes all items from the <see cref="T:System.Collections.Generic.ICollection`1" />.</summary> + /// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1" /> is read-only. </exception> + public virtual void Clear() + { + list.Clear(); + } + + /// <summary>Determines whether the <see cref="T:System.Collections.Generic.ICollection`1" /> contains a specific value.</summary> + /// <returns>true if <paramref name="item" /> is found in the <see cref="T:System.Collections.Generic.ICollection`1" />; otherwise, false.</returns> + /// <param name="item">The object to locate in the <see cref="T:System.Collections.Generic.ICollection`1" />.</param> + public virtual bool Contains(MemberReferenceMap item) + { + return list.Contains(item); + } + + /// <summary>Copies the elements of the <see cref="T:System.Collections.Generic.ICollection`1" /> to an <see cref="T:System.Array" />, starting at a particular <see cref="T:System.Array" /> index.</summary> + /// <param name="array">The one-dimensional <see cref="T:System.Array" /> that is the destination of the elements copied from <see cref="T:System.Collections.Generic.ICollection`1" />. The <see cref="T:System.Array" /> must have zero-based indexing.</param> + /// <param name="arrayIndex">The zero-based index in <paramref name="array" /> at which copying begins.</param> + /// <exception cref="T:System.ArgumentNullException"> + /// <paramref name="array" /> is null.</exception> + /// <exception cref="T:System.ArgumentOutOfRangeException"> + /// <paramref name="arrayIndex" /> is less than 0.</exception> + /// <exception cref="T:System.ArgumentException">The number of elements in the source <see cref="T:System.Collections.Generic.ICollection`1" /> is greater than the available space from <paramref name="arrayIndex" /> to the end of the destination <paramref name="array" />.</exception> + public virtual void CopyTo(MemberReferenceMap[] array, int arrayIndex) + { + list.CopyTo(array, arrayIndex); + } + + /// <summary>Removes the first occurrence of a specific object from the <see cref="T:System.Collections.Generic.ICollection`1" />.</summary> + /// <returns>true if <paramref name="item" /> was successfully removed from the <see cref="T:System.Collections.Generic.ICollection`1" />; otherwise, false. This method also returns false if <paramref name="item" /> is not found in the original <see cref="T:System.Collections.Generic.ICollection`1" />.</returns> + /// <param name="item">The object to remove from the <see cref="T:System.Collections.Generic.ICollection`1" />.</param> + /// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1" /> is read-only.</exception> + public virtual bool Remove(MemberReferenceMap item) + { + return list.Remove(item); + } + + /// <summary>Determines the index of a specific item in the <see cref="T:System.Collections.Generic.IList`1" />.</summary> + /// <returns>The index of <paramref name="item" /> if found in the list; otherwise, -1.</returns> + /// <param name="item">The object to locate in the <see cref="T:System.Collections.Generic.IList`1" />.</param> + public virtual int IndexOf(MemberReferenceMap item) + { + return list.IndexOf(item); + } + + /// <summary>Inserts an item to the <see cref="T:System.Collections.Generic.IList`1" /> at the specified index.</summary> + /// <param name="index">The zero-based index at which <paramref name="item" /> should be inserted.</param> + /// <param name="item">The object to insert into the <see cref="T:System.Collections.Generic.IList`1" />.</param> + /// <exception cref="T:System.ArgumentOutOfRangeException"> + /// <paramref name="index" /> is not a valid index in the <see cref="T:System.Collections.Generic.IList`1" />.</exception> + /// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.IList`1" /> is read-only.</exception> + public virtual void Insert(int index, MemberReferenceMap item) + { + list.Insert(index, item); + } + + /// <summary>Removes the <see cref="T:System.Collections.Generic.IList`1" /> item at the specified index.</summary> + /// <param name="index">The zero-based index of the item to remove.</param> + /// <exception cref="T:System.ArgumentOutOfRangeException"> + /// <paramref name="index" /> is not a valid index in the <see cref="T:System.Collections.Generic.IList`1" />.</exception> + /// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.IList`1" /> is read-only.</exception> + public virtual void RemoveAt(int index) + { + list.RemoveAt(index); + } + + /// <summary> + /// Finds the <see cref="MemberReferenceMap"/> using the given member expression. + /// </summary> + /// <typeparam name="T">The <see cref="System.Type"/> the member is on.</typeparam> + /// <param name="expression">The member expression.</param> + /// <returns>The <see cref="MemberReferenceMap"/> for the given expression, or null if not found.</returns> + public virtual MemberReferenceMap? Find<T>(Expression<Func<T, object>> expression) + { + var member = ReflectionHelper.GetMember(expression); + return Find(member); + } + + /// <summary> + /// Finds the <see cref="MemberReferenceMap"/> using the given member. + /// </summary> + /// <param name="member">The member.</param> + /// <returns>The <see cref="MemberReferenceMap"/> for the given expression, or null if not found.</returns> + public virtual MemberReferenceMap? Find(MemberInfo member) + { + var existingMap = list.SingleOrDefault(m => + m.Data.Member == member || + m.Data.Member.Name == member.Name && + ( + m.Data.Member.DeclaringType.IsAssignableFrom(member.DeclaringType) || + member.DeclaringType.IsAssignableFrom(m.Data.Member.DeclaringType) + ) + ); + + return existingMap; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/MemberReferenceMapData.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/MemberReferenceMapData.cs new file mode 100644 index 0000000..0726a35 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/MemberReferenceMapData.cs @@ -0,0 +1,68 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System.Reflection; + +namespace CsvHelper.Configuration +{ + /// <summary> + /// The configuration data for the reference map. + /// </summary> + public class MemberReferenceMapData + { + private string prefix; + + /// <summary> + /// Gets or sets the header prefix to use. + /// </summary> + public virtual string Prefix + { + get { return prefix; } + set + { + prefix = value; + foreach (var memberMap in Mapping.MemberMaps) + { + memberMap.Data.Names.Prefix = value; + } + + if (Inherit) + { + foreach (var memberRef in Mapping.ReferenceMaps) + { + memberRef.Data.Prefix = memberRef.Data.Prefix == null ? value : string.Concat(value, memberRef.Data.Prefix); + } + } + } + } + + /// <summary> + /// Gets or sets a value indicating if a prefix should inherit its parent. + /// <c>true</c> to inherit, otherwise <c>false</c>. + /// </summary> + public virtual bool Inherit { get; set; } + + /// <summary> + /// Gets the <see cref="MemberInfo"/> that the data + /// is associated with. + /// </summary> + public virtual MemberInfo Member { get; private set; } + + /// <summary> + /// Gets the mapping this is a reference for. + /// </summary> + public ClassMap Mapping { get; private set; } + + /// <summary> + /// Initializes a new instance of the <see cref="MemberReferenceMapData"/> class. + /// </summary> + /// <param name="member">The member.</param> + /// <param name="mapping">The mapping this is a reference for.</param> + public MemberReferenceMapData(MemberInfo member, ClassMap mapping) + { + Member = member; + Mapping = mapping; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/MemberTypes.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/MemberTypes.cs new file mode 100644 index 0000000..378524f --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/MemberTypes.cs @@ -0,0 +1,32 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration +{ + /// <summary> + /// Flags for the type of members that + /// can be used for auto mapping. + /// </summary> + [Flags] + public enum MemberTypes + { + /// <summary> + /// No members. This is not a valid value + /// and will cause an exception if used. + /// </summary> + None = 0, + + /// <summary> + /// Properties on a class. + /// </summary> + Properties = 1, + + /// <summary> + /// Fields on a class. + /// </summary> + Fields = 2 + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/ParameterMap.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/ParameterMap.cs new file mode 100644 index 0000000..991cc8b --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/ParameterMap.cs @@ -0,0 +1,212 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using CsvHelper.TypeConversion; +using System; +using System.Diagnostics; +using System.Reflection; + +namespace CsvHelper.Configuration +{ + /// <summary> + /// Mapping for a constructor parameter. + /// This may contain value type data, a constructor type map, + /// or a reference map, depending on the type of the parameter. + /// </summary> + [DebuggerDisplay("Data = {Data}")] + public class ParameterMap + { + /// <summary> + /// Gets the parameter map data. + /// </summary> + public virtual ParameterMapData Data { get; protected set; } + + /// <summary> + /// Type converter options. + /// </summary> + public virtual ParameterMapTypeConverterOption TypeConverterOption { get; protected set; } + + /// <summary> + /// Gets or sets the map for a constructor type. + /// </summary> + public virtual ClassMap ConstructorTypeMap { get; set; } + + /// <summary> + /// Gets or sets the map for a reference type. + /// </summary> + public virtual ParameterReferenceMap ReferenceMap { get; set; } + + /// <summary> + /// Creates an instance of <see cref="ParameterMap"/> using + /// the given information. + /// </summary> + /// <param name="parameter">The parameter being mapped.</param> + public ParameterMap(ParameterInfo parameter) + { + TypeConverterOption = new ParameterMapTypeConverterOption(this); + + Data = new ParameterMapData(parameter); + } + + /// <summary> + /// When reading, is used to get the field + /// at the index of the name if there was a + /// header specified. It will look for the + /// first name match in the order listed. + /// When writing, sets the name of the + /// field in the header record. + /// The first name will be used. + /// </summary> + /// <param name="names">The possible names of the CSV field.</param> + public virtual ParameterMap Name(params string[] names) + { + if (names == null || names.Length == 0) + { + throw new ArgumentNullException(nameof(names)); + } + + Data.Names.Clear(); + Data.Names.AddRange(names); + Data.IsNameSet = true; + + return this; + } + + /// <summary> + /// When reading, is used to get the + /// index of the name used when there + /// are multiple names that are the same. + /// </summary> + /// <param name="index">The index of the name.</param> + public virtual ParameterMap NameIndex(int index) + { + Data.NameIndex = index; + + return this; + } + + /// <summary> + /// When reading, is used to get the field at + /// the given index. When writing, the fields + /// will be written in the order of the field + /// indexes. + /// </summary> + /// <param name="index">The index of the CSV field.</param> + public virtual ParameterMap Index(int index) + { + Data.Index = index; + Data.IsIndexSet = true; + + return this; + } + + /// <summary> + /// Ignore the parameter when reading and writing. + /// </summary> + public virtual ParameterMap Ignore() + { + Data.Ignore = true; + + return this; + } + + /// <summary> + /// Ignore the parameter when reading and writing. + /// </summary> + /// <param name="ignore">True to ignore, otherwise false.</param> + public virtual ParameterMap Ignore(bool ignore) + { + Data.Ignore = ignore; + + return this; + } + + /// <summary> + /// The default value that will be used when reading when + /// the CSV field is empty. + /// </summary> + /// <param name="defaultValue">The default value.</param> + public virtual ParameterMap Default(object? defaultValue) + { + if (defaultValue == null && Data.Parameter.ParameterType.IsValueType) + { + throw new ArgumentException($"Parameter of type '{Data.Parameter.ParameterType.FullName}' can't have a default value of null."); + } + + if (defaultValue != null && defaultValue.GetType() != Data.Parameter.ParameterType) + { + throw new ArgumentException($"Default of type '{defaultValue.GetType().FullName}' does not match parameter of type '{Data.Parameter.ParameterType.FullName}'."); + } + + Data.Default = defaultValue; + Data.IsDefaultSet = true; + + return this; + } + + /// <summary> + /// The constant value that will be used for every record when + /// reading and writing. This value will always be used no matter + /// what other mapping configurations are specified. + /// </summary> + /// <param name="constantValue">The constant value.</param> + public virtual ParameterMap Constant(object? constantValue) + { + if (constantValue == null && Data.Parameter.ParameterType.IsValueType) + { + throw new ArgumentException($"Parameter of type '{Data.Parameter.ParameterType.FullName}' can't have a constant value of null."); + } + + if (constantValue != null && constantValue.GetType() != Data.Parameter.ParameterType) + { + throw new ArgumentException($"Constant of type '{constantValue.GetType().FullName}' does not match parameter of type '{Data.Parameter.ParameterType.FullName}'."); + } + + Data.Constant = constantValue; + Data.IsConstantSet = true; + + return this; + } + + /// <summary> + /// The field is optional. + /// </summary> + public virtual ParameterMap Optional() + { + Data.IsOptional = true; + + return this; + } + + /// <summary> + /// Specifies the <see cref="TypeConverter"/> to use + /// when converting the parameter to and from a CSV field. + /// </summary> + /// <param name="typeConverter">The TypeConverter to use.</param> + public virtual ParameterMap TypeConverter(ITypeConverter typeConverter) + { + Data.TypeConverter = typeConverter; + + return this; + } + + /// <summary> + /// Specifies the <see cref="TypeConverter"/> to use + /// when converting the parameter to and from a CSV field. + /// </summary> + /// <typeparam name="TConverter">The <see cref="System.Type"/> of the + /// <see cref="TypeConverter"/> to use.</typeparam> + public virtual ParameterMap TypeConverter<TConverter>() where TConverter : ITypeConverter + { + TypeConverter(ObjectResolver.Current.Resolve<TConverter>()); + + return this; + } + + internal int GetMaxIndex() + { + return ReferenceMap?.GetMaxIndex() ?? Data.Index; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/ParameterMapData.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/ParameterMapData.cs new file mode 100644 index 0000000..a83edbe --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/ParameterMapData.cs @@ -0,0 +1,106 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using CsvHelper.TypeConversion; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; + +namespace CsvHelper.Configuration +{ + /// <summary> + /// The constructor parameter data for the map. + /// </summary> + [DebuggerDisplay("Index = {Index}, Names = {string.Join(\", \", Names)}, Parameter = {Parameter}")] + public class ParameterMapData + { + /// <summary> + /// Gets the <see cref="ParameterInfo"/> that the data + /// is associated with. + /// </summary> + public virtual ParameterInfo Parameter { get; private set; } + + /// <summary> + /// Gets the list of column names. + /// </summary> + public virtual MemberNameCollection Names { get; } = new MemberNameCollection(); + + /// <summary> + /// Gets or sets the index of the name. + /// This is used if there are multiple + /// columns with the same names. + /// </summary> + public virtual int NameIndex { get; set; } + + /// <summary> + /// Gets or sets a value indicating if the name was + /// explicitly set. True if it was explicitly set, + /// otherwise false. + /// </summary> + public virtual bool IsNameSet { get; set; } + + /// <summary> + /// Gets or sets the column index. + /// </summary> + public virtual int Index { get; set; } = -1; + + /// <summary> + /// Gets or sets a value indicating if the index was + /// explicitly set. True if it was explicitly set, + /// otherwise false. + /// </summary> + public virtual bool IsIndexSet { get; set; } + + /// <summary> + /// Gets or sets the type converter. + /// </summary> + public virtual ITypeConverter TypeConverter { get; set; } + + /// <summary> + /// Gets or sets the type converter options. + /// </summary> + public virtual TypeConverterOptions TypeConverterOptions { get; set; } = new TypeConverterOptions(); + + /// <summary> + /// Gets or sets a value indicating whether the field should be ignored. + /// </summary> + public virtual bool Ignore { get; set; } + + /// <summary> + /// Gets or sets the default value used when a CSV field is empty. + /// </summary> + public virtual object? Default { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether this instance is default value set. + /// the default value was explicitly set. True if it was + /// explicitly set, otherwise false. + /// </summary> + public virtual bool IsDefaultSet { get; set; } + + /// <summary> + /// Gets or sets the constant value used for every record. + /// </summary> + public virtual object? Constant { get; set; } + + /// <summary> + /// Gets or sets a value indicating if a constant was explicitly set. + /// </summary> + public virtual bool IsConstantSet { get; set; } + + /// <summary> + /// Gets or sets a value indicating if a field is optional. + /// </summary> + public virtual bool IsOptional { get; set; } + + /// <summary> + /// Initializes a new instance of the <see cref="ParameterMapData"/> class. + /// </summary> + /// <param name="parameter">The constructor parameter.</param> + public ParameterMapData(ParameterInfo parameter) + { + Parameter = parameter; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/ParameterMapTypeConverterOption.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/ParameterMapTypeConverterOption.cs new file mode 100644 index 0000000..4b3d82a --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/ParameterMapTypeConverterOption.cs @@ -0,0 +1,160 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CsvHelper.Configuration +{ + /// <summary> + /// Sets type converter options on a parameter map. + /// </summary> + public class ParameterMapTypeConverterOption + { + private readonly ParameterMap parameterMap; + + /// <summary> + /// Creates a new instance using the given <see cref="ParameterMap"/>. + /// </summary> + /// <param name="parameterMap">The member map the options are being applied to.</param> + public ParameterMapTypeConverterOption(ParameterMap parameterMap) + { + this.parameterMap = parameterMap; + } + + /// <summary> + /// The <see cref="CultureInfo"/> used when type converting. + /// This will override the global <see cref="CsvConfiguration.CultureInfo"/> + /// setting. + /// </summary> + /// <param name="cultureInfo">The culture info.</param> + public virtual ParameterMap CultureInfo(CultureInfo cultureInfo) + { + parameterMap.Data.TypeConverterOptions.CultureInfo = cultureInfo; + + return parameterMap; + } + + /// <summary> + /// The <see cref="DateTimeStyles"/> to use when type converting. + /// This is used when doing any <see cref="DateTime"/> conversions. + /// </summary> + /// <param name="dateTimeStyle">The date time style.</param> + public virtual ParameterMap DateTimeStyles(DateTimeStyles dateTimeStyle) + { + parameterMap.Data.TypeConverterOptions.DateTimeStyle = dateTimeStyle; + + return parameterMap; + } + + /// <summary> + /// The <see cref="TimeSpanStyles"/> to use when type converting. + /// This is used when doing <see cref="TimeSpan"/> converting. + /// </summary> + /// <param name="timeSpanStyles">The time span styles.</param> + public virtual ParameterMap TimespanStyles(TimeSpanStyles timeSpanStyles) + { + parameterMap.Data.TypeConverterOptions.TimeSpanStyle = timeSpanStyles; + + return parameterMap; + } + + /// <summary> + /// The <see cref="NumberStyles"/> to use when type converting. + /// This is used when doing any number conversions. + /// </summary> + /// <param name="numberStyle"></param> + public virtual ParameterMap NumberStyles(NumberStyles numberStyle) + { + parameterMap.Data.TypeConverterOptions.NumberStyles = numberStyle; + + return parameterMap; + } + + /// <summary> + /// The string format to be used when type converting. + /// </summary> + /// <param name="formats">The format.</param> + public virtual ParameterMap Format(params string[] formats) + { + parameterMap.Data.TypeConverterOptions.Formats = formats; + + return parameterMap; + } + + /// <summary> + /// The <see cref="UriKind"/> to use when converting. + /// This is used when doing <see cref="Uri"/> conversions. + /// </summary> + /// <param name="uriKind">Kind of the URI.</param> + public virtual ParameterMap UriKind(UriKind uriKind) + { + parameterMap.Data.TypeConverterOptions.UriKind = uriKind; + + return parameterMap; + } + + /// <summary> + /// The string values used to represent a boolean when converting. + /// </summary> + /// <param name="isTrue">A value indicating whether true values or false values are being set.</param> + /// <param name="clearValues">A value indication if the current values should be cleared before adding the new ones.</param> + /// <param name="booleanValues">The string boolean values.</param> + public virtual ParameterMap BooleanValues(bool isTrue, bool clearValues = true, params string[] booleanValues) + { + if (isTrue) + { + if (clearValues) + { + parameterMap.Data.TypeConverterOptions.BooleanTrueValues.Clear(); + } + + parameterMap.Data.TypeConverterOptions.BooleanTrueValues.AddRange(booleanValues); + } + else + { + if (clearValues) + { + parameterMap.Data.TypeConverterOptions.BooleanFalseValues.Clear(); + } + + parameterMap.Data.TypeConverterOptions.BooleanFalseValues.AddRange(booleanValues); + } + + return parameterMap; + } + + /// <summary> + /// The string values used to represent null when converting. + /// </summary> + /// <param name="nullValues">The values that represent null.</param> + /// <returns></returns> + public virtual ParameterMap NullValues(params string[] nullValues) + { + return NullValues(true, nullValues); + } + + /// <summary> + /// The string values used to represent null when converting. + /// </summary> + /// <param name="clearValues">A value indication if the current values should be cleared before adding the new ones.</param> + /// <param name="nullValues">The values that represent null.</param> + /// <returns></returns> + public virtual ParameterMap NullValues(bool clearValues, params string[] nullValues) + { + if (clearValues) + { + parameterMap.Data.TypeConverterOptions.NullValues.Clear(); + } + + parameterMap.Data.TypeConverterOptions.NullValues.AddRange(nullValues); + + return parameterMap; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/ParameterReferenceMap.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/ParameterReferenceMap.cs new file mode 100644 index 0000000..7e9a5f3 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/ParameterReferenceMap.cs @@ -0,0 +1,66 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Reflection; + +namespace CsvHelper.Configuration +{ + /// <summary> + /// Mapping info for a reference parameter mapping to a class. + /// </summary> + public class ParameterReferenceMap + { + private readonly ParameterReferenceMapData data; + + /// <summary> + /// Gets the parameter reference map data. + /// </summary> + public ParameterReferenceMapData Data => data; + + /// <summary> + /// Initializes a new instance of the <see cref="ParameterReferenceMap"/> class. + /// </summary> + /// <param name="parameter">The parameter.</param> + /// <param name="mapping">The <see cref="ClassMap"/> to use for the reference map.</param> + public ParameterReferenceMap(ParameterInfo parameter, ClassMap mapping) + { + if (mapping == null) + { + throw new ArgumentNullException(nameof(mapping)); + } + + data = new ParameterReferenceMapData(parameter, mapping); + } + + /// <summary> + /// Appends a prefix to the header of each field of the reference parameter. + /// </summary> + /// <param name="prefix">The prefix to be prepended to headers of each reference parameter.</param> + /// <param name="inherit">Inherit parent prefixes.</param> + /// <returns>The current <see cref="ParameterReferenceMap" /></returns> + public ParameterReferenceMap Prefix(string prefix = null, bool inherit = false) + { + if (string.IsNullOrEmpty(prefix)) + { + prefix = data.Parameter.Name + "."; + } + + data.Inherit = inherit; + data.Prefix = prefix; + + return this; + } + + /// <summary> + /// Get the largest index for the + /// members and references. + /// </summary> + /// <returns>The max index.</returns> + internal int GetMaxIndex() + { + return data.Mapping.GetMaxIndex(); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/ParameterReferenceMapData.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/ParameterReferenceMapData.cs new file mode 100644 index 0000000..ab2a28d --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/ParameterReferenceMapData.cs @@ -0,0 +1,70 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System.Diagnostics; +using System.Reflection; + +namespace CsvHelper.Configuration +{ + /// <summary> + /// The configuration data for the reference map. + /// </summary> + [DebuggerDisplay( "Prefix = {Prefix}, Parameter = {Parameter}" )] + public class ParameterReferenceMapData + { + private string prefix; + + /// <summary> + /// Gets or sets the header prefix to use. + /// </summary> + public virtual string Prefix + { + get { return prefix; } + set + { + prefix = value; + foreach( var memberMap in Mapping.MemberMaps ) + { + memberMap.Data.Names.Prefix = value; + } + + if (Inherit) + { + foreach (var memberRef in Mapping.ReferenceMaps) + { + memberRef.Data.Prefix = memberRef.Data.Prefix == null ? value : string.Concat(value, memberRef.Data.Prefix); + } + } + } + } + + /// <summary> + /// Gets or sets a value indicating if a prefix should inherit its parent. + /// <c>true</c> to inherit, otherwise <c>false</c>. + /// </summary> + public virtual bool Inherit { get; set; } + + /// <summary> + /// Gets the <see cref="ParameterInfo"/> that the data + /// is associated with. + /// </summary> + public virtual ParameterInfo Parameter { get; private set; } + + /// <summary> + /// Gets the mapping this is a reference for. + /// </summary> + public ClassMap Mapping { get; private set; } + + /// <summary> + /// Initializes a new instance of the <see cref="ParameterReferenceMapData"/> class. + /// </summary> + /// <param name="parameter">The parameter.</param> + /// <param name="mapping">The mapping this is a reference for.</param> + public ParameterReferenceMapData( ParameterInfo parameter, ClassMap mapping ) + { + Parameter = parameter; + Mapping = mapping; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/TrimOptions.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/TrimOptions.cs new file mode 100644 index 0000000..5555c92 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Configuration/TrimOptions.cs @@ -0,0 +1,30 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Configuration +{ + /// <summary> + /// Options for trimming of fields. + /// </summary> + [Flags] + public enum TrimOptions + { + /// <summary> + /// No trimming. + /// </summary> + None = 0, + + /// <summary> + /// Trims the whitespace around a field. + /// </summary> + Trim = 1, + + /// <summary> + /// Trims the whitespace inside of quotes around a field. + /// </summary> + InsideQuotes = 2 + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/CsvContext.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvContext.cs new file mode 100644 index 0000000..27c5d00 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvContext.cs @@ -0,0 +1,202 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using CsvHelper.Configuration; +using CsvHelper.TypeConversion; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CsvHelper +{ + /// <summary> + /// Share state for CsvHelper. + /// </summary> + public class CsvContext + { + /// <summary> + /// Gets or sets the <see cref="TypeConverterOptionsCache"/>. + /// </summary> + public virtual TypeConverterOptionsCache TypeConverterOptionsCache { get; set; } = new TypeConverterOptionsCache(); + + /// <summary> + /// Gets or sets the <see cref="TypeConverterOptionsCache"/>. + /// </summary> + public virtual TypeConverterCache TypeConverterCache { get; set; } = new TypeConverterCache(); + + /// <summary> + /// The configured <see cref="ClassMap"/>s. + /// </summary> + public virtual ClassMapCollection Maps { get; private set; } + + /// <summary> + /// Gets the parser. + /// </summary> + public IParser Parser { get; private set; } + + /// <summary> + /// Gets the reader. + /// </summary> + public IReader Reader { get; internal set; } + + /// <summary> + /// Gets the writer. + /// </summary> + public IWriter Writer { get; internal set; } + + /// <summary> + /// Gets the configuration. + /// </summary> + public CsvConfiguration Configuration { get; private set; } + + /// <summary> + /// Initializes a new instance of the <see cref="CsvContext"/> class. + /// </summary> + /// <param name="reader">The reader.</param> + public CsvContext(IReader reader) + { + Reader = reader; + Parser = reader.Parser; + Configuration = reader.Configuration as CsvConfiguration ?? throw new InvalidOperationException($"{nameof(IReader)}.{nameof(IReader.Configuration)} must be of type {nameof(CsvConfiguration)} to be used in the context."); + Maps = new ClassMapCollection(this); + } + + /// <summary> + /// Initializes a new instance of the <see cref="CsvContext"/> class. + /// </summary> + /// <param name="parser">The parser.</param> + public CsvContext(IParser parser) + { + Parser = parser; + Configuration = parser.Configuration as CsvConfiguration ?? throw new InvalidOperationException($"{nameof(IParser)}.{nameof(IParser.Configuration)} must be of type {nameof(CsvConfiguration)} to be used in the context."); + Maps = new ClassMapCollection(this); + } + + /// <summary> + /// Initializes a new instance of the <see cref="CsvContext"/> class. + /// </summary> + /// <param name="writer">The writer.</param> + public CsvContext(IWriter writer) + { + Writer = writer; + Configuration = writer.Configuration as CsvConfiguration ?? throw new InvalidOperationException($"{nameof(IWriter)}.{nameof(IWriter.Configuration)} must be of type {nameof(CsvConfiguration)} to be used in the context."); + Maps = new ClassMapCollection(this); + } + + /// <summary> + /// Initializes a new instance of the <see cref="CsvContext"/> class. + /// </summary> + /// <param name="configuration">The configuration.</param> + public CsvContext(CsvConfiguration configuration) + { + Configuration = configuration; + Maps = new ClassMapCollection(this); + } + + /// <summary> + /// Use a <see cref="ClassMap{T}" /> to configure mappings. + /// When using a class map, no members are mapped by default. + /// Only member specified in the mapping are used. + /// </summary> + /// <typeparam name="TMap">The type of mapping class to use.</typeparam> + public virtual TMap RegisterClassMap<TMap>() where TMap : ClassMap + { + var map = ObjectResolver.Current.Resolve<TMap>(); + RegisterClassMap(map); + + return map; + } + + /// <summary> + /// Use a <see cref="ClassMap{T}" /> to configure mappings. + /// When using a class map, no members are mapped by default. + /// Only members specified in the mapping are used. + /// </summary> + /// <param name="classMapType">The type of mapping class to use.</param> + public virtual ClassMap RegisterClassMap(Type classMapType) + { + if (!typeof(ClassMap).IsAssignableFrom(classMapType)) + { + throw new ArgumentException("The class map type must inherit from CsvClassMap."); + } + + var map = (ClassMap)ObjectResolver.Current.Resolve(classMapType); + RegisterClassMap(map); + + return map; + } + + /// <summary> + /// Registers the class map. + /// </summary> + /// <param name="map">The class map to register.</param> + public virtual void RegisterClassMap(ClassMap map) + { + if (map.MemberMaps.Count == 0 && map.ReferenceMaps.Count == 0 && map.ParameterMaps.Count == 0) + { + throw new ConfigurationException("No mappings were specified in the CsvClassMap."); + } + + Maps.Add(map); + } + + /// <summary> + /// Unregisters the class map. + /// </summary> + /// <typeparam name="TMap">The map type to unregister.</typeparam> + public virtual void UnregisterClassMap<TMap>() + where TMap : ClassMap + { + UnregisterClassMap(typeof(TMap)); + } + + /// <summary> + /// Unregisters the class map. + /// </summary> + /// <param name="classMapType">The map type to unregister.</param> + public virtual void UnregisterClassMap(Type classMapType) + { + Maps.Remove(classMapType); + } + + /// <summary> + /// Unregisters all class maps. + /// </summary> + public virtual void UnregisterClassMap() + { + Maps.Clear(); + } + + /// <summary> + /// Generates a <see cref="ClassMap"/> for the type. + /// </summary> + /// <typeparam name="T">The type to generate the map for.</typeparam> + /// <returns>The generate map.</returns> + public virtual ClassMap<T> AutoMap<T>() + { + var map = ObjectResolver.Current.Resolve<DefaultClassMap<T>>(); + map.AutoMap(this); + Maps.Add(map); + + return map; + } + + /// <summary> + /// Generates a <see cref="ClassMap"/> for the type. + /// </summary> + /// <param name="type">The type to generate for the map.</param> + /// <returns>The generate map.</returns> + public virtual ClassMap AutoMap(Type type) + { + var mapType = typeof(DefaultClassMap<>).MakeGenericType(type); + var map = (ClassMap)ObjectResolver.Current.Resolve(mapType); + map.AutoMap(this); + Maps.Add(map); + + return map; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/CsvDataReader.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvDataReader.cs new file mode 100644 index 0000000..0e67cf9 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvDataReader.cs @@ -0,0 +1,387 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Data; +using System.Globalization; +using System.Linq; + +namespace CsvHelper +{ + /// <summary> + /// Provides a means of reading a CSV file forward-only by using CsvReader. + /// </summary> + /// <seealso cref="System.Data.IDataReader" /> + public class CsvDataReader : IDataReader + { + private readonly CsvReader csv; + private readonly DataTable schemaTable; + private bool skipNextRead; + + /// <inheritdoc /> + public object this[int i] + { + get + { + return csv[i] ?? string.Empty; + } + } + + /// <inheritdoc /> + public object this[string name] + { + get + { + return csv[name] ?? string.Empty; + } + } + + /// <inheritdoc /> + public int Depth + { + get + { + return 0; + } + } + + /// <inheritdoc /> + public bool IsClosed { get; private set; } + + /// <inheritdoc /> + public int RecordsAffected + { + get + { + return 0; + } + } + + /// <inheritdoc /> + public int FieldCount + { + get + { + return csv?.Parser.Count ?? 0; + } + } + + /// <summary> + /// Initializes a new instance of the <see cref="CsvDataReader"/> class. + /// </summary> + /// <param name="csv">The CSV.</param> + /// <param name="schemaTable">The DataTable representing the file schema.</param> + public CsvDataReader(CsvReader csv, DataTable? schemaTable = null) + { + this.csv = csv; + + csv.Read(); + + if (csv.Configuration.HasHeaderRecord) + { + csv.ReadHeader(); + } + else + { + skipNextRead = true; + } + + this.schemaTable = schemaTable ?? GetSchemaTable(); + } + + /// <inheritdoc /> + public void Close() + { + Dispose(); + } + + /// <inheritdoc /> + public void Dispose() + { + csv.Dispose(); + IsClosed = true; + } + + /// <inheritdoc /> + public bool GetBoolean(int i) + { + return csv.GetField<bool>(i); + } + + /// <inheritdoc /> + public byte GetByte(int i) + { + return csv.GetField<byte>(i); + } + + /// <inheritdoc /> + public long GetBytes(int i, long fieldOffset, byte[]? buffer, int bufferoffset, int length) + { + var bytes = csv.GetField<byte[]>(i); + + buffer ??= new byte[bytes.Length]; + + Array.Copy(bytes, fieldOffset, buffer, bufferoffset, length); + + return bytes.Length; + } + + /// <inheritdoc /> + public char GetChar(int i) + { + return csv.GetField<char>(i); + } + + /// <inheritdoc /> + public long GetChars(int i, long fieldoffset, char[]? buffer, int bufferoffset, int length) + { + var chars = csv.GetField(i).ToCharArray(); + + buffer ??= new char[chars.Length]; + + Array.Copy(chars, fieldoffset, buffer, bufferoffset, length); + + return chars.Length; + } + + /// <inheritdoc /> + public IDataReader GetData(int i) + { + throw new NotSupportedException(); + } + + /// <inheritdoc /> + public string GetDataTypeName(int i) + { + if (i >= schemaTable.Rows.Count) + { + throw new IndexOutOfRangeException($"SchemaTable does not contain a definition for field '{i}'."); + } + + var row = schemaTable.Rows[i]; + var field = row["DataType"] as Type; + + if (field == null) + { + throw new InvalidOperationException($"SchemaTable does not contain a 'DataType' of type 'Type' for field '{i}'."); + } + + return field.Name; + } + + /// <inheritdoc /> + public DateTime GetDateTime(int i) + { + return csv.GetField<DateTime>(i); + } + + /// <inheritdoc /> + public decimal GetDecimal(int i) + { + return csv.GetField<decimal>(i); + } + + /// <inheritdoc /> + public double GetDouble(int i) + { + return csv.GetField<double>(i); + } + + /// <inheritdoc /> + public Type GetFieldType(int i) + { + return typeof(string); + } + + /// <inheritdoc /> + public float GetFloat(int i) + { + return csv.GetField<float>(i); + } + + /// <inheritdoc /> + public Guid GetGuid(int i) + { + return csv.GetField<Guid>(i); + } + + /// <inheritdoc /> + public short GetInt16(int i) + { + return csv.GetField<short>(i); + } + + /// <inheritdoc /> + public int GetInt32(int i) + { + return csv.GetField<int>(i); + } + + /// <inheritdoc /> + public long GetInt64(int i) + { + return csv.GetField<long>(i); + } + + /// <inheritdoc /> + public string GetName(int i) + { + return csv.Configuration.HasHeaderRecord + ? csv.HeaderRecord[i] + : string.Empty; + } + + /// <inheritdoc /> + public int GetOrdinal(string name) + { + var index = csv.GetFieldIndex(name, isTryGet: true); + if (index >= 0) + { + return index; + } + + var args = new PrepareHeaderForMatchArgs(name, 0); + var namePrepared = csv.Configuration.PrepareHeaderForMatch(args); + + var headerRecord = csv.HeaderRecord; + for (var i = 0; i < headerRecord.Length; i++) + { + args = new PrepareHeaderForMatchArgs(headerRecord[i], i); + var headerPrepared = csv.Configuration.PrepareHeaderForMatch(args); + if (csv.Configuration.CultureInfo.CompareInfo.Compare(namePrepared, headerPrepared, CompareOptions.IgnoreCase) == 0) + { + return i; + } + } + + throw new IndexOutOfRangeException($"Field with name '{name}' and prepared name '{namePrepared}' was not found."); + } + + /// <inheritdoc /> + public DataTable GetSchemaTable() + { + if (schemaTable != null) + { + return schemaTable; + } + + // https://docs.microsoft.com/en-us/dotnet/api/system.data.datatablereader.getschematable?view=netframework-4.7.2 + var dt = new DataTable("SchemaTable"); + dt.Columns.Add("AllowDBNull", typeof(bool)); + dt.Columns.Add("AutoIncrementSeed", typeof(long)); + dt.Columns.Add("AutoIncrementStep", typeof(long)); + dt.Columns.Add("BaseCatalogName"); + dt.Columns.Add("BaseColumnName"); + dt.Columns.Add("BaseColumnNamespace"); + dt.Columns.Add("BaseSchemaName"); + dt.Columns.Add("BaseTableName"); + dt.Columns.Add("BaseTableNamespace"); + dt.Columns.Add("ColumnName"); + dt.Columns.Add("ColumnMapping", typeof(MappingType)); + dt.Columns.Add("ColumnOrdinal", typeof(int)); + dt.Columns.Add("ColumnSize", typeof(int)); + dt.Columns.Add("DataType", typeof(Type)); + dt.Columns.Add("DefaultValue", typeof(object)); + dt.Columns.Add("Expression"); + dt.Columns.Add("IsAutoIncrement", typeof(bool)); + dt.Columns.Add("IsKey", typeof(bool)); + dt.Columns.Add("IsLong", typeof(bool)); + dt.Columns.Add("IsReadOnly", typeof(bool)); + dt.Columns.Add("IsRowVersion", typeof(bool)); + dt.Columns.Add("IsUnique", typeof(bool)); + dt.Columns.Add("NumericPrecision", typeof(short)); + dt.Columns.Add("NumericScale", typeof(short)); + dt.Columns.Add("ProviderType", typeof(int)); + + if (csv.Configuration.HasHeaderRecord) + { + var header = csv.HeaderRecord; + + for (var i = 0; i < header.Length; i++) + { + var row = dt.NewRow(); + row["AllowDBNull"] = true; + row["AutoIncrementSeed"] = DBNull.Value; + row["AutoIncrementStep"] = DBNull.Value; + row["BaseCatalogName"] = null; + row["BaseColumnName"] = header[i]; + row["BaseColumnNamespace"] = null; + row["BaseSchemaName"] = null; + row["BaseTableName"] = null; + row["BaseTableNamespace"] = null; + row["ColumnName"] = header[i]; + row["ColumnMapping"] = MappingType.Element; + row["ColumnOrdinal"] = i; + row["ColumnSize"] = int.MaxValue; + row["DataType"] = typeof(string); + row["DefaultValue"] = null; + row["Expression"] = null; + row["IsAutoIncrement"] = false; + row["IsKey"] = false; + row["IsLong"] = false; + row["IsReadOnly"] = true; + row["IsRowVersion"] = false; + row["IsUnique"] = false; + row["NumericPrecision"] = DBNull.Value; + row["NumericScale"] = DBNull.Value; + row["ProviderType"] = DbType.String; + + dt.Rows.Add(row); + } + } + + return dt; + } + + /// <inheritdoc /> + public string GetString(int i) + { + return csv.GetField(i) ?? string.Empty; + } + + /// <inheritdoc /> + public object GetValue(int i) + { + return IsDBNull(i) ? DBNull.Value : (csv.GetField(i) ?? string.Empty); + } + + /// <inheritdoc /> + public int GetValues(object[] values) + { + for (var i = 0; i < values.Length; i++) + { + values[i] = IsDBNull(i) ? DBNull.Value : (csv.GetField(i) ?? string.Empty); + } + + return csv.Parser.Count; + } + + /// <inheritdoc /> + public bool IsDBNull(int i) + { + var field = csv.GetField(i); + var nullValues = csv.Context.TypeConverterOptionsCache.GetOptions<string>().NullValues; + + return field == null || nullValues.Contains(field); + } + + /// <inheritdoc /> + public bool NextResult() + { + return false; + } + + /// <inheritdoc /> + public bool Read() + { + if (skipNextRead) + { + skipNextRead = false; + return true; + } + + return csv.Read(); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/CsvHelper.csproj b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvHelper.csproj new file mode 100644 index 0000000..28dcaad --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvHelper.csproj @@ -0,0 +1,92 @@ +<Project Sdk="Microsoft.NET.Sdk"> + <PropertyGroup> + <!-- Assembly --> + <AssemblyTitle>CsvHelper</AssemblyTitle> + <Description>A library for reading and writing CSV files. Extremely fast, flexible, and easy to use. Supports reading and writing of custom class objects.</Description> + <Copyright>Copyright © 2009-2022 Josh Close</Copyright> + <Authors>Josh Close</Authors> + + <!-- Build --> + <AssemblyName>CsvHelper</AssemblyName> + <TargetFrameworks>net6.0;netstandard2.1;netstandard2.0;net47;net462</TargetFrameworks> + <!--<TargetFrameworks>net60</TargetFrameworks>--> + <LangVersion>latest</LangVersion> + <RootNamespace>CsvHelper</RootNamespace> + <DefaultLanguage>en-US</DefaultLanguage> + <GenerateDocumentationFile>true</GenerateDocumentationFile> + <ContinuousIntegrationBuild>true</ContinuousIntegrationBuild> + <!--<Nullable>enable</Nullable> + <WarningsAsErrors>nullable</WarningsAsErrors>--> + + <!-- Sign --> + <SignAssembly>true</SignAssembly> + <AssemblyOriginatorKeyFile>CsvHelper.snk</AssemblyOriginatorKeyFile> + <PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign> + + <!-- NuGet --> + <PackageId>CsvHelper</PackageId> + <PackageTags>csv;csvhelper;comma;separated;value;delimited</PackageTags> + <PackageIcon>Icon.png</PackageIcon> + <PackageIconUrl>https://raw.github.com/JoshClose/CsvHelper/master/logo/Comma-Small.png</PackageIconUrl> + <PackageProjectUrl>https://joshclose.github.io/CsvHelper/</PackageProjectUrl> + <PackageReleaseNotes>https://joshclose.github.io/CsvHelper/change-log</PackageReleaseNotes> + <PackageLicenseExpression>MS-PL OR Apache-2.0</PackageLicenseExpression> + <PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance> + <PublishRepositoryUrl>true</PublishRepositoryUrl> + <RepositoryUrl>https://github.com/JoshClose/CsvHelper</RepositoryUrl> + <RepositoryType>git</RepositoryType> + <IncludeSymbols>true</IncludeSymbols> + <SymbolPackageFormat>snupkg</SymbolPackageFormat> + <EmbedUntrackedSources>true</EmbedUntrackedSources> + </PropertyGroup> + + <ItemGroup> + <None Remove="*.ncrunchproject" /> + </ItemGroup> + + <ItemGroup> + <None Include="Icon.png" Pack="true" PackagePath="\" /> + </ItemGroup> + + <!-- .NET 4.5 --> + <ItemGroup Condition="'$(TargetFramework)' == 'net45'"> + <PackageReference Include="Microsoft.CSharp" Version="4.3.0" /> + <PackageReference Include="System.Memory" Version="4.5.0" /> + <PackageReference Include="System.ValueTuple" Version="4.3.0" /> + </ItemGroup> + + <!-- .NET 4.7 --> + <ItemGroup Condition="'$(TargetFramework)' == 'net47'"> + <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="1.0.0" /> + <PackageReference Include="Microsoft.Bcl.HashCode" Version="1.0.0" /> + <PackageReference Include="Microsoft.CSharp" Version="4.3.0" /> + <PackageReference Include="System.Memory" Version="4.5.0" /> + <PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.2" /> + </ItemGroup> + + <!-- .NET Standard 2.0 --> + <ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'"> + <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="1.0.0" /> + <PackageReference Include="Microsoft.Bcl.HashCode" Version="1.0.0" /> + <PackageReference Include="Microsoft.CSharp" Version="4.3.0" /> + <PackageReference Include="System.Memory" Version="4.5.0" /> + <PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.2" /> + </ItemGroup> + + <!-- .NET Standard 2.1 --> + <ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.1'"> + <PackageReference Include="Microsoft.CSharp" Version="4.3.0" /> + </ItemGroup> + + <ItemGroup> + <PackageReference Include="Microsoft.SourceLink.GitHub" Version="[1.0.0]"> + <PrivateAssets>all</PrivateAssets> + <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> + </PackageReference> + </ItemGroup> + + <ItemGroup> + <Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" /> + </ItemGroup> + +</Project>
\ No newline at end of file diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/CsvHelper.net45.v3.ncrunchproject b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvHelper.net45.v3.ncrunchproject new file mode 100644 index 0000000..9d694dc --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvHelper.net45.v3.ncrunchproject @@ -0,0 +1,5 @@ +<ProjectConfiguration> + <Settings> + <PreventSigningOfAssembly>True</PreventSigningOfAssembly> + </Settings> +</ProjectConfiguration>
\ No newline at end of file diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/CsvHelper.net47.v3.ncrunchproject b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvHelper.net47.v3.ncrunchproject new file mode 100644 index 0000000..9d694dc --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvHelper.net47.v3.ncrunchproject @@ -0,0 +1,5 @@ +<ProjectConfiguration> + <Settings> + <PreventSigningOfAssembly>True</PreventSigningOfAssembly> + </Settings> +</ProjectConfiguration>
\ No newline at end of file diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/CsvHelper.net5.0.v3.ncrunchproject b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvHelper.net5.0.v3.ncrunchproject new file mode 100644 index 0000000..9d694dc --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvHelper.net5.0.v3.ncrunchproject @@ -0,0 +1,5 @@ +<ProjectConfiguration> + <Settings> + <PreventSigningOfAssembly>True</PreventSigningOfAssembly> + </Settings> +</ProjectConfiguration>
\ No newline at end of file diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/CsvHelper.net50.v3.ncrunchproject b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvHelper.net50.v3.ncrunchproject new file mode 100644 index 0000000..9d694dc --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvHelper.net50.v3.ncrunchproject @@ -0,0 +1,5 @@ +<ProjectConfiguration> + <Settings> + <PreventSigningOfAssembly>True</PreventSigningOfAssembly> + </Settings> +</ProjectConfiguration>
\ No newline at end of file diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/CsvHelper.net6.0.v3.ncrunchproject b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvHelper.net6.0.v3.ncrunchproject new file mode 100644 index 0000000..9d694dc --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvHelper.net6.0.v3.ncrunchproject @@ -0,0 +1,5 @@ +<ProjectConfiguration> + <Settings> + <PreventSigningOfAssembly>True</PreventSigningOfAssembly> + </Settings> +</ProjectConfiguration>
\ No newline at end of file diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/CsvHelper.net60.v3.ncrunchproject b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvHelper.net60.v3.ncrunchproject new file mode 100644 index 0000000..9d694dc --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvHelper.net60.v3.ncrunchproject @@ -0,0 +1,5 @@ +<ProjectConfiguration> + <Settings> + <PreventSigningOfAssembly>True</PreventSigningOfAssembly> + </Settings> +</ProjectConfiguration>
\ No newline at end of file diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/CsvHelper.netstandard2.0.v3.ncrunchproject b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvHelper.netstandard2.0.v3.ncrunchproject new file mode 100644 index 0000000..9d694dc --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvHelper.netstandard2.0.v3.ncrunchproject @@ -0,0 +1,5 @@ +<ProjectConfiguration> + <Settings> + <PreventSigningOfAssembly>True</PreventSigningOfAssembly> + </Settings> +</ProjectConfiguration>
\ No newline at end of file diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/CsvHelper.netstandard2.1.v3.ncrunchproject b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvHelper.netstandard2.1.v3.ncrunchproject new file mode 100644 index 0000000..9d694dc --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvHelper.netstandard2.1.v3.ncrunchproject @@ -0,0 +1,5 @@ +<ProjectConfiguration> + <Settings> + <PreventSigningOfAssembly>True</PreventSigningOfAssembly> + </Settings> +</ProjectConfiguration>
\ No newline at end of file diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/CsvHelper.snk b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvHelper.snk Binary files differnew file mode 100644 index 0000000..8c9bfaf --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvHelper.snk diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/CsvHelperException.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvHelperException.cs new file mode 100644 index 0000000..10e0cdc --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvHelperException.cs @@ -0,0 +1,144 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using CsvHelper.Configuration; +using System; +using System.Text; + +namespace CsvHelper +{ + /// <summary> + /// Represents errors that occur in CsvHelper. + /// </summary> + [Serializable] + public class CsvHelperException : Exception + { + [NonSerialized] + private readonly CsvContext context; + + /// <summary> + /// Gets the context. + /// </summary> + public CsvContext Context => context; + + /// <summary> + /// Initializes a new instance of the CsvHelperException class. + /// </summary> + internal protected CsvHelperException() : base() { } + + /// <summary> + /// Initializes a new instance of the CsvHelperException class. + /// </summary> + /// <param name="message">The message that describes the error.</param> + internal protected CsvHelperException(string message) : base(message) { } + + /// <summary> + /// Initializes a new instance of the CsvHelperException class. + /// </summary> + /// <param name="message">The error message that explains the reason for the exception.</param> + /// <param name="innerException">The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.</param> + internal protected CsvHelperException(string message, Exception innerException) : base(message, innerException) { } + + /// <summary> + /// Initializes a new instance of the <see cref="CsvHelperException"/> class. + /// </summary> + public CsvHelperException(CsvContext context) + { + this.context = context; + } + + /// <summary> + /// Initializes a new instance of the <see cref="CsvHelperException"/> class + /// with a specified error message. + /// </summary> + /// <param name="context">The context.</param> + /// <param name="message">The message that describes the error.</param> + public CsvHelperException(CsvContext context, string message) : base(AddDetails(message, context)) + { + this.context = context; + } + + /// <summary> + /// Initializes a new instance of the <see cref="CsvHelperException"/> class + /// with a specified error message and a reference to the inner exception that + /// is the cause of this exception. + /// </summary> + /// <param name="context">The context.</param> + /// <param name="message">The error message that explains the reason for the exception.</param> + /// <param name="innerException">The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.</param> + public CsvHelperException(CsvContext context, string message, Exception innerException) : base(AddDetails(message, context), innerException) + { + this.context = context; + } + + private static string AddDetails(string message, CsvContext context) + { + var indent = new string(' ', 3); + + var details = new StringBuilder(); + + if (context.Reader != null) + { + details.AppendLine($"{nameof(IReader)} state:"); + details.AppendLine($"{indent}{nameof(IReader.ColumnCount)}: {context.Reader.ColumnCount}"); + details.AppendLine($"{indent}{nameof(IReader.CurrentIndex)}: {context.Reader.CurrentIndex}"); + try + { + var record = new StringBuilder(); + if (context.Reader.HeaderRecord != null) + { + record.Append("[\""); + record.Append(string.Join("\",\"", context.Reader.HeaderRecord)); + record.Append("\"]"); + } + + details.AppendLine($"{indent}{nameof(IReader.HeaderRecord)}:{Environment.NewLine}{record}"); + } + catch { } + } + + if (context.Parser != null) + { + details.AppendLine($"{nameof(IParser)} state:"); + details.AppendLine($"{indent}{nameof(IParser.ByteCount)}: {context.Parser.ByteCount}"); + details.AppendLine($"{indent}{nameof(IParser.CharCount)}: {context.Parser.CharCount}"); + details.AppendLine($"{indent}{nameof(IParser.Row)}: {context.Parser.Row}"); + details.AppendLine($"{indent}{nameof(IParser.RawRow)}: {context.Parser.RawRow}"); + details.AppendLine($"{indent}{nameof(IParser.Count)}: {context.Parser.Count}"); + + try + { + var rawRecord = context.Configuration.ExceptionMessagesContainRawData + ? context.Parser.RawRecord + : $"Hidden because {nameof(IParserConfiguration.ExceptionMessagesContainRawData)} is false."; + details.AppendLine($"{indent}{nameof(IParser.RawRecord)}:{Environment.NewLine}{rawRecord}"); + } + catch { } + } + + if (context.Writer != null) + { + details.AppendLine($"{nameof(IWriter)} state:"); + details.AppendLine($"{indent}{nameof(IWriter.Row)}: {context.Writer.Row}"); + details.AppendLine($"{indent}{nameof(IWriter.Index)}: {context.Writer.Index}"); + + var record = new StringBuilder(); + if (context.Writer.HeaderRecord != null) + { + record.Append("["); + if (context.Writer.HeaderRecord.Length > 0) + { + record.Append("\""); + record.Append(string.Join("\",\"", context.Writer.HeaderRecord)); + record.Append("\""); + } + record.Append("]"); + } + details.AppendLine($"{indent}{nameof(IWriter.HeaderRecord)}:{Environment.NewLine}{context.Writer.Row}"); + } + + return $"{message}{Environment.NewLine}{details}"; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/CsvMode.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvMode.cs new file mode 100644 index 0000000..af11bab --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvMode.cs @@ -0,0 +1,43 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using CsvHelper.Configuration; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CsvHelper +{ + /// <summary> + /// Mode to use when parsing and writing. + /// </summary> + public enum CsvMode + { + /// <summary> + /// Uses RFC 4180 format (default). + /// If a field contains a <see cref="CsvConfiguration.Delimiter"/> or <see cref="CsvConfiguration.NewLine"/>, + /// it is wrapped in <see cref="CsvConfiguration.Quote"/>s. + /// If quoted field contains a <see cref="CsvConfiguration.Quote"/>, it is preceded by <see cref="CsvConfiguration.Escape"/>. + /// </summary> + RFC4180 = 0, + + /// <summary> + /// Uses escapes. + /// If a field contains a <see cref="CsvConfiguration.Delimiter"/>, <see cref="CsvConfiguration.NewLine"/>, + /// or <see cref="CsvConfiguration.Escape"/>, it is preceded by <see cref="CsvConfiguration.Escape"/>. + /// Newline defaults to \n. + /// </summary> + Escape, + + /// <summary> + /// Doesn't use quotes or escapes. + /// This will ignore quoting and escape characters. This means a field cannot contain a + /// <see cref="CsvConfiguration.Delimiter"/>, <see cref="CsvConfiguration.Quote"/>, or + /// <see cref="CsvConfiguration.NewLine"/>, as they cannot be escaped. + /// </summary> + NoEscape + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/CsvParser.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvParser.cs new file mode 100644 index 0000000..6d0db59 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvParser.cs @@ -0,0 +1,1194 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using CsvHelper.Configuration; +using CsvHelper.Delegates; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace CsvHelper +{ + /// <summary> + /// Parses a CSV file. + /// </summary> + public class CsvParser : IParser, IDisposable + { + private readonly IParserConfiguration configuration; + private readonly FieldCache fieldCache = new FieldCache(); + private readonly TextReader reader; + private readonly char quote; + private readonly char escape; + private readonly bool countBytes; + private readonly Encoding encoding; + private readonly bool ignoreBlankLines; + private readonly char comment; + private readonly bool allowComments; + private readonly BadDataFound badDataFound; + private readonly bool lineBreakInQuotedFieldIsBadData; + private readonly TrimOptions trimOptions; + private readonly char[] whiteSpaceChars; + private readonly bool leaveOpen; + private readonly CsvMode mode; + private readonly string newLine; + private readonly char newLineFirstChar; + private readonly bool isNewLineSet; + private readonly bool cacheFields; + private readonly string[] delimiterValues; + private readonly bool detectDelimiter; + private readonly double maxFieldSize; + + private string delimiter; + private char delimiterFirstChar; + private char[] buffer; + private int bufferSize; + private int charsRead; + private int bufferPosition; + private int rowStartPosition; + private int fieldStartPosition; + private int row; + private int rawRow; + private long charCount; + private long byteCount; + private bool inQuotes; + private bool inEscape; + private Field[] fields; + private string[] processedFields; + private int fieldsPosition; + private bool disposed; + private int quoteCount; + private char[] processFieldBuffer; + private int processFieldBufferSize; + private ParserState state; + private int delimiterPosition = 1; + private int newLinePosition = 1; + private bool fieldIsBadData; + private bool fieldIsQuoted; + private bool isProcessingField; + private bool isRecordProcessed; + private string[]? record; + + /// <inheritdoc/> + public long CharCount => charCount; + + /// <inheritdoc/> + public long ByteCount => byteCount; + + /// <inheritdoc/> + public int Row => row; + + /// <inheritdoc/> + public string[]? Record + { + get + { + if (isRecordProcessed == true) + { + return this.record; + } + + if (fieldsPosition == 0) + { + return null; + } + + var record = new string[fieldsPosition]; + + for (var i = 0; i < record.Length; i++) + { + record[i] = this[i]; + } + + this.record = record; + isRecordProcessed = true; + + return this.record; + } + } + + /// <inheritdoc/> + public string RawRecord => new string(buffer, rowStartPosition, bufferPosition - rowStartPosition); + + /// <inheritdoc/> + public int Count => fieldsPosition; + + /// <inheritdoc/> + public int RawRow => rawRow; + + /// <inheritdoc/> + public string Delimiter => delimiter; + + /// <inheritdoc/> + public CsvContext Context { get; private set; } + + /// <inheritdoc/> + public IParserConfiguration Configuration => configuration; + + /// <inheritdoc/> + public string this[int index] + { + get + { + if (isProcessingField) + { + var message = + $"You can't access {nameof(IParser)}[int] or {nameof(IParser)}.{nameof(IParser.Record)} inside of the {nameof(BadDataFound)} callback. " + + $"Use {nameof(BadDataFoundArgs)}.{nameof(BadDataFoundArgs.Field)} and {nameof(BadDataFoundArgs)}.{nameof(BadDataFoundArgs.RawRecord)} instead." + ; + + throw new ParserException(Context, message); + } + + isProcessingField = true; + + var field = GetField(index); + + isProcessingField = false; + + return field; + } + } + + /// <summary> + /// Initializes a new instance of the <see cref="CsvParser"/> class. + /// </summary> + /// <param name="reader">The reader.</param> + /// <param name="culture">The culture.</param> + /// <param name="leaveOpen">if set to <c>true</c> [leave open].</param> + public CsvParser(TextReader reader, CultureInfo culture, bool leaveOpen = false) : this(reader, new CsvConfiguration(culture), leaveOpen) { } + + /// <summary> + /// Initializes a new instance of the <see cref="CsvParser"/> class. + /// </summary> + /// <param name="reader">The reader.</param> + /// <param name="configuration">The configuration.</param> + /// <param name="leaveOpen">if set to <c>true</c> [leave open].</param> + public CsvParser(TextReader reader, IParserConfiguration configuration, bool leaveOpen = false) + { + this.reader = reader ?? throw new ArgumentNullException(nameof(reader)); + this.configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); + + configuration.Validate(); + + Context = new CsvContext(this); + + allowComments = configuration.AllowComments; + badDataFound = configuration.BadDataFound; + bufferSize = configuration.BufferSize; + cacheFields = configuration.CacheFields; + comment = configuration.Comment; + countBytes = configuration.CountBytes; + delimiter = configuration.Delimiter; + delimiterFirstChar = configuration.Delimiter[0]; + delimiterValues = configuration.DetectDelimiterValues; + detectDelimiter = configuration.DetectDelimiter; + encoding = configuration.Encoding; + escape = configuration.Escape; + ignoreBlankLines = configuration.IgnoreBlankLines; + isNewLineSet = configuration.IsNewLineSet; + this.leaveOpen = leaveOpen; + lineBreakInQuotedFieldIsBadData = configuration.LineBreakInQuotedFieldIsBadData; + maxFieldSize = configuration.MaxFieldSize; + newLine = configuration.NewLine; + newLineFirstChar = configuration.NewLine[0]; + mode = configuration.Mode; + processFieldBufferSize = configuration.ProcessFieldBufferSize; + quote = configuration.Quote; + whiteSpaceChars = configuration.WhiteSpaceChars; + trimOptions = configuration.TrimOptions; + + buffer = new char[bufferSize]; + processFieldBuffer = new char[processFieldBufferSize]; + fields = new Field[128]; + processedFields = new string[128]; + } + + /// <inheritdoc/> + public bool Read() + { + isRecordProcessed = false; + rowStartPosition = bufferPosition; + fieldStartPosition = rowStartPosition; + fieldsPosition = 0; + quoteCount = 0; + row++; + rawRow++; + var c = '\0'; + var cPrev = c; + + while (true) + { + if (bufferPosition >= charsRead) + { + if (!FillBuffer()) + { + return ReadEndOfFile(); + } + + if (row == 1 && detectDelimiter) + { + DetectDelimiter(); + } + } + + if (ReadLine(ref c, ref cPrev) == ReadLineResult.Complete) + { + return true; + } + } + } + + /// <inheritdoc/> + public async Task<bool> ReadAsync() + { + isRecordProcessed = false; + rowStartPosition = bufferPosition; + fieldStartPosition = rowStartPosition; + fieldsPosition = 0; + quoteCount = 0; + row++; + rawRow++; + var c = '\0'; + var cPrev = c; + + while (true) + { + if (bufferPosition >= charsRead) + { + if (!await FillBufferAsync().ConfigureAwait(false)) + { + return ReadEndOfFile(); + } + + if (row == 1 && detectDelimiter) + { + DetectDelimiter(); + } + } + + if (ReadLine(ref c, ref cPrev) == ReadLineResult.Complete) + { + return true; + } + } + } + + private void DetectDelimiter() + { + var text = new string(buffer, 0, charsRead); + var newDelimiter = configuration.GetDelimiter(new GetDelimiterArgs(text, configuration)); + if (newDelimiter != null) + { + delimiter = newDelimiter; + delimiterFirstChar = newDelimiter[0]; + configuration.Validate(); + } + } + + private ReadLineResult ReadLine(ref char c, ref char cPrev) + { + while (bufferPosition < charsRead) + { + if (state != ParserState.None) + { + // Continue the state before doing anything else. + ReadLineResult result; + switch (state) + { + case ParserState.Spaces: + result = ReadSpaces(ref c); + break; + case ParserState.BlankLine: + result = ReadBlankLine(ref c); + break; + case ParserState.Delimiter: + result = ReadDelimiter(ref c); + break; + case ParserState.LineEnding: + result = ReadLineEnding(ref c); + break; + case ParserState.NewLine: + result = ReadNewLine(ref c); + break; + default: + throw new InvalidOperationException($"Parser state '{state}' is not valid."); + } + + var shouldReturn = + // Buffer needs to be filled. + result == ReadLineResult.Incomplete || + // Done reading row. + result == ReadLineResult.Complete && (state == ParserState.LineEnding || state == ParserState.NewLine) + ; + + if (result == ReadLineResult.Complete) + { + state = ParserState.None; + } + + if (shouldReturn) + { + return result; + } + } + + cPrev = c; + c = buffer[bufferPosition]; + bufferPosition++; + charCount++; + + if (countBytes) + { + byteCount += encoding.GetByteCount(new char[] { c }); + } + + if (maxFieldSize > 0 && bufferPosition - fieldStartPosition - 1 > maxFieldSize) + { + throw new MaxFieldSizeException(Context); + } + + var isFirstCharOfRow = rowStartPosition == bufferPosition - 1; + if (isFirstCharOfRow && (allowComments && c == comment || ignoreBlankLines && ((c == '\r' || c == '\n') && !isNewLineSet || c == newLineFirstChar && isNewLineSet))) + { + state = ParserState.BlankLine; + var result = ReadBlankLine(ref c); + if (result == ReadLineResult.Complete) + { + state = ParserState.None; + + continue; + } + else + { + return ReadLineResult.Incomplete; + } + } + + if (mode == CsvMode.RFC4180) + { + var isFirstCharOfField = fieldStartPosition == bufferPosition - 1; + if (isFirstCharOfField) + { + if ((trimOptions & TrimOptions.Trim) == TrimOptions.Trim && ArrayHelper.Contains(whiteSpaceChars, c)) + { + // Skip through whitespace. This is so we can process the field later. + var result = ReadSpaces(ref c); + if (result == ReadLineResult.Incomplete) + { + fieldStartPosition = bufferPosition; + return result; + } + } + + // Fields are only quoted if the first character is a quote. + // If not, read until a delimiter or newline is found. + fieldIsQuoted = c == quote; + } + + if (fieldIsQuoted) + { + if (c == quote || c == escape) + { + quoteCount++; + + if (!inQuotes && !isFirstCharOfField && cPrev != escape) + { + fieldIsBadData = true; + } + else if (!fieldIsBadData) + { + // Don't process field quotes after bad data has been detected. + inQuotes = !inQuotes; + } + } + + if (inQuotes) + { + if (c == '\r' || c == '\n' && cPrev != '\r') + { + rawRow++; + } + + // We don't care about anything else if we're in quotes. + continue; + } + } + else + { + if (c == quote || c == escape) + { + // If the field isn't quoted but contains a + // quote or escape, it's has bad data. + fieldIsBadData = true; + } + } + } + else if (mode == CsvMode.Escape) + { + if (inEscape) + { + inEscape = false; + + continue; + } + + if (c == escape) + { + inEscape = true; + + continue; + } + } + + if (c == delimiterFirstChar) + { + state = ParserState.Delimiter; + var result = ReadDelimiter(ref c); + if (result == ReadLineResult.Incomplete) + { + return result; + } + + state = ParserState.None; + + continue; + } + + if (!isNewLineSet && (c == '\r' || c == '\n')) + { + state = ParserState.LineEnding; + var result = ReadLineEnding(ref c); + if (result == ReadLineResult.Complete) + { + state = ParserState.None; + } + + return result; + } + + if (isNewLineSet && c == newLineFirstChar) + { + state = ParserState.NewLine; + var result = ReadNewLine(ref c); + if (result == ReadLineResult.Complete) + { + state = ParserState.None; + } + + return result; + } + } + + return ReadLineResult.Incomplete; + } + + private ReadLineResult ReadSpaces(ref char c) + { + while (ArrayHelper.Contains(whiteSpaceChars, c)) + { + if (bufferPosition >= charsRead) + { + return ReadLineResult.Incomplete; + } + + c = buffer[bufferPosition]; + bufferPosition++; + charCount++; + if (countBytes) + { + byteCount += encoding.GetByteCount(new char[] { c }); + } + } + + return ReadLineResult.Complete; + } + + private ReadLineResult ReadBlankLine(ref char c) + { + while (bufferPosition < charsRead) + { + if (c == '\r' || c == '\n') + { + var result = ReadLineEnding(ref c); + if (result == ReadLineResult.Complete) + { + rowStartPosition = bufferPosition; + fieldStartPosition = rowStartPosition; + row++; + rawRow++; + } + + return result; + } + + c = buffer[bufferPosition]; + bufferPosition++; + charCount++; + if (countBytes) + { + byteCount += encoding.GetByteCount(new char[] { c }); + } + } + + return ReadLineResult.Incomplete; + } + + private ReadLineResult ReadDelimiter(ref char c) + { + for (var i = delimiterPosition; i < delimiter.Length; i++) + { + if (bufferPosition >= charsRead) + { + return ReadLineResult.Incomplete; + } + + delimiterPosition++; + + c = buffer[bufferPosition]; + if (c != delimiter[i]) + { + c = buffer[bufferPosition - 1]; + delimiterPosition = 1; + + return ReadLineResult.Complete; + } + + bufferPosition++; + charCount++; + if (countBytes) + { + byteCount += encoding.GetByteCount(new[] { c }); + } + + if (bufferPosition >= charsRead) + { + return ReadLineResult.Incomplete; + } + } + + AddField(fieldStartPosition, bufferPosition - fieldStartPosition - delimiter.Length); + + fieldStartPosition = bufferPosition; + delimiterPosition = 1; + fieldIsBadData = false; + + return ReadLineResult.Complete; + } + + private ReadLineResult ReadLineEnding(ref char c) + { + var lessChars = 1; + + if (c == '\r') + { + if (bufferPosition >= charsRead) + { + return ReadLineResult.Incomplete; + } + + c = buffer[bufferPosition]; + + if (c == '\n') + { + lessChars++; + bufferPosition++; + charCount++; + if (countBytes) + { + byteCount += encoding.GetByteCount(new char[] { c }); + } + } + } + + if (state == ParserState.LineEnding) + { + AddField(fieldStartPosition, bufferPosition - fieldStartPosition - lessChars); + } + + fieldIsBadData = false; + + return ReadLineResult.Complete; + } + + private ReadLineResult ReadNewLine(ref char c) + { + for (var i = newLinePosition; i < newLine.Length; i++) + { + if (bufferPosition >= charsRead) + { + return ReadLineResult.Incomplete; + } + + newLinePosition++; + + c = buffer[bufferPosition]; + if (c != newLine[i]) + { + c = buffer[bufferPosition - 1]; + newLinePosition = 1; + + return ReadLineResult.Complete; + } + + bufferPosition++; + charCount++; + if (countBytes) + { + byteCount += encoding.GetByteCount(new[] { c }); + } + + if (bufferPosition >= charsRead) + { + return ReadLineResult.Incomplete; + } + } + + AddField(fieldStartPosition, bufferPosition - fieldStartPosition - newLine.Length); + + fieldStartPosition = bufferPosition; + newLinePosition = 1; + fieldIsBadData = false; + + return ReadLineResult.Complete; + } + + private bool ReadEndOfFile() + { + var state = this.state; + this.state = ParserState.None; + + if (state == ParserState.BlankLine) + { + return false; + } + + if (state == ParserState.Delimiter) + { + AddField(fieldStartPosition, bufferPosition - fieldStartPosition - delimiter.Length); + + fieldStartPosition = bufferPosition; + + AddField(fieldStartPosition, bufferPosition - fieldStartPosition); + + return true; + } + + if (state == ParserState.LineEnding) + { + AddField(fieldStartPosition, bufferPosition - fieldStartPosition - 1); + + return true; + } + + if (state == ParserState.NewLine) + { + AddField(fieldStartPosition, bufferPosition - fieldStartPosition - newLine.Length); + + return true; + } + + if (rowStartPosition < bufferPosition) + { + AddField(fieldStartPosition, bufferPosition - fieldStartPosition); + } + + return fieldsPosition > 0; + } + + private void AddField(int start, int length) + { + if (fieldsPosition >= fields.Length) + { + var newSize = fields.Length * 2; + Array.Resize(ref fields, newSize); + Array.Resize(ref processedFields, newSize); + } + + ref var field = ref fields[fieldsPosition]; + field.Start = start - rowStartPosition; + field.Length = length; + field.QuoteCount = quoteCount; + field.IsBad = fieldIsBadData; + field.IsProcessed = false; + + fieldsPosition++; + quoteCount = 0; + } + + private bool FillBuffer() + { + // Don't forget the async method below. + + if (rowStartPosition == 0 && charCount > 0 && charsRead == bufferSize) + { + // The record is longer than the memory buffer. Increase the buffer. + bufferSize *= 2; + var tempBuffer = new char[bufferSize]; + buffer.CopyTo(tempBuffer, 0); + buffer = tempBuffer; + } + + var charsLeft = Math.Max(charsRead - rowStartPosition, 0); + + Array.Copy(buffer, rowStartPosition, buffer, 0, charsLeft); + + fieldStartPosition -= rowStartPosition; + rowStartPosition = 0; + bufferPosition = charsLeft; + + charsRead = reader.Read(buffer, charsLeft, buffer.Length - charsLeft); + if (charsRead == 0) + { + return false; + } + + charsRead += charsLeft; + + return true; + } + + private async Task<bool> FillBufferAsync() + { + if (rowStartPosition == 0 && charCount > 0 && charsRead == bufferSize) + { + // The record is longer than the memory buffer. Increase the buffer. + bufferSize *= 2; + var tempBuffer = new char[bufferSize]; + buffer.CopyTo(tempBuffer, 0); + buffer = tempBuffer; + } + + var charsLeft = Math.Max(charsRead - rowStartPosition, 0); + + Array.Copy(buffer, rowStartPosition, buffer, 0, charsLeft); + + fieldStartPosition -= rowStartPosition; + rowStartPosition = 0; + bufferPosition = charsLeft; + + charsRead = await reader.ReadAsync(buffer, charsLeft, buffer.Length - charsLeft).ConfigureAwait(false); + if (charsRead == 0) + { + return false; + } + + charsRead += charsLeft; + + return true; + } + + private string GetField(int index) + { + if (index > fieldsPosition) + { + throw new IndexOutOfRangeException(); + } + + ref var field = ref fields[index]; + + if (field.Length == 0) + { + return string.Empty; + } + + if (field.IsProcessed) + { + return processedFields[index]; + } + + var start = field.Start + rowStartPosition; + var length = field.Length; + var quoteCount = field.QuoteCount; + + ProcessedField processedField; + switch (mode) + { + case CsvMode.RFC4180: + processedField = field.IsBad + ? ProcessRFC4180BadField(start, length) + : ProcessRFC4180Field(start, length, quoteCount); + break; + case CsvMode.Escape: + processedField = ProcessEscapeField(start, length); + break; + case CsvMode.NoEscape: + processedField = ProcessNoEscapeField(start, length); + break; + default: + throw new InvalidOperationException($"ParseMode '{mode}' is not handled."); + } + + var value = cacheFields + ? fieldCache.GetField(processedField.Buffer, processedField.Start, processedField.Length) + : new string(processedField.Buffer, processedField.Start, processedField.Length); + + processedFields[index] = value; + field.IsProcessed = true; + + return value; + } + + /// <summary> + /// Processes a field that complies with RFC4180. + /// </summary> + /// <param name="start">The start index of the field.</param> + /// <param name="length">The length of the field.</param> + /// <param name="quoteCount">The number of counted quotes.</param> + /// <returns>The processed field.</returns> + protected ProcessedField ProcessRFC4180Field(int start, int length, int quoteCount) + { + var newStart = start; + var newLength = length; + + if ((trimOptions & TrimOptions.Trim) == TrimOptions.Trim) + { + ArrayHelper.Trim(buffer, ref newStart, ref newLength, whiteSpaceChars); + } + + if (quoteCount == 0) + { + // Not quoted. + // No processing needed. + + return new ProcessedField(newStart, newLength, buffer); + } + + if (buffer[newStart] != quote || buffer[newStart + newLength - 1] != quote || newLength == 1 && buffer[newStart] == quote) + { + // If the field doesn't have quotes on the ends, or the field is a single quote char, it's bad data. + return ProcessRFC4180BadField(start, length); + } + + if (lineBreakInQuotedFieldIsBadData) + { + for (var i = newStart; i < newStart + newLength; i++) + { + if (buffer[i] == '\r' || buffer[i] == '\n') + { + return ProcessRFC4180BadField(start, length); + } + } + } + + // Remove the quotes from the ends. + newStart += 1; + newLength -= 2; + + if ((trimOptions & TrimOptions.InsideQuotes) == TrimOptions.InsideQuotes) + { + ArrayHelper.Trim(buffer, ref newStart, ref newLength, whiteSpaceChars); + } + + if (quoteCount == 2) + { + // The only quotes are the ends of the field. + // No more processing is needed. + return new ProcessedField(newStart, newLength, buffer); + } + + if (newLength > processFieldBuffer.Length) + { + // Make sure the field processing buffer is large engough. + while (newLength > processFieldBufferSize) + { + processFieldBufferSize *= 2; + } + + processFieldBuffer = new char[processFieldBufferSize]; + } + + // Remove escapes. + var inEscape = false; + var position = 0; + for (var i = newStart; i < newStart + newLength; i++) + { + var c = buffer[i]; + + if (inEscape) + { + inEscape = false; + } + else if (c == escape) + { + inEscape = true; + + continue; + } + + processFieldBuffer[position] = c; + position++; + } + + return new ProcessedField(0, position, processFieldBuffer); + } + + /// <summary> + /// Processes a field that does not comply with RFC4180. + /// </summary> + /// <param name="start">The start index of the field.</param> + /// <param name="length">The length of the field.</param> + /// <returns>The processed field.</returns> + protected ProcessedField ProcessRFC4180BadField(int start, int length) + { + // If field is already known to be bad, different rules can be applied. + + var args = new BadDataFoundArgs(new string(buffer, start, length), RawRecord, Context); + badDataFound?.Invoke(args); + + var newStart = start; + var newLength = length; + + if ((trimOptions & TrimOptions.Trim) == TrimOptions.Trim) + { + ArrayHelper.Trim(buffer, ref newStart, ref newLength, whiteSpaceChars); + } + + if (buffer[newStart] != quote) + { + // If the field doesn't start with a quote, don't process it. + return new ProcessedField(newStart, newLength, buffer); + } + + if (newLength > processFieldBuffer.Length) + { + // Make sure the field processing buffer is large engough. + while (newLength > processFieldBufferSize) + { + processFieldBufferSize *= 2; + } + + processFieldBuffer = new char[processFieldBufferSize]; + } + + // Remove escapes until the last quote is found. + var inEscape = false; + var position = 0; + var c = '\0'; + var doneProcessing = false; + for (var i = newStart + 1; i < newStart + newLength; i++) + { + var cPrev = c; + c = buffer[i]; + + // a,"b",c + // a,"b "" c",d + // a,"b "c d",e + + if (inEscape) + { + inEscape = false; + + if (c == quote) + { + // Ignore the quote after an escape. + continue; + } + else if (cPrev == quote) + { + // The escape and quote are the same character. + // This is the end of the field. + // Don't process escapes for the rest of the field. + doneProcessing = true; + } + } + + if (c == escape && !doneProcessing) + { + inEscape = true; + + continue; + } + + processFieldBuffer[position] = c; + position++; + } + + return new ProcessedField(0, position, processFieldBuffer); + } + + /// <summary> + /// Processes an escaped field. + /// </summary> + /// <param name="start">The start index of the field.</param> + /// <param name="length">The length of the field.</param> + /// <returns>The processed field.</returns> + protected ProcessedField ProcessEscapeField(int start, int length) + { + var newStart = start; + var newLength = length; + + if ((trimOptions & TrimOptions.Trim) == TrimOptions.Trim) + { + ArrayHelper.Trim(buffer, ref newStart, ref newLength, whiteSpaceChars); + } + + if (newLength > processFieldBuffer.Length) + { + // Make sure the field processing buffer is large engough. + while (newLength > processFieldBufferSize) + { + processFieldBufferSize *= 2; + } + + processFieldBuffer = new char[processFieldBufferSize]; + } + + // Remove escapes. + var inEscape = false; + var position = 0; + for (var i = newStart; i < newStart + newLength; i++) + { + var c = buffer[i]; + + if (inEscape) + { + inEscape = false; + } + else if (c == escape) + { + inEscape = true; + continue; + } + + processFieldBuffer[position] = c; + position++; + } + + return new ProcessedField(0, position, processFieldBuffer); + } + + /// <inheritdoc/> + /// <summary> + /// Processes an non-escaped field. + /// </summary> + /// <param name="start">The start index of the field.</param> + /// <param name="length">The length of the field.</param> + /// <returns>The processed field.</returns> + protected ProcessedField ProcessNoEscapeField(int start, int length) + { + var newStart = start; + var newLength = length; + + if ((trimOptions & TrimOptions.Trim) == TrimOptions.Trim) + { + ArrayHelper.Trim(buffer, ref newStart, ref newLength, whiteSpaceChars); + } + + return new ProcessedField(newStart, newLength, buffer); + } + + /// <inheritdoc/> + public void Dispose() + { + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + + /// <summary> + /// Disposes the object. + /// </summary> + /// <param name="disposing">Indicates if the object is being disposed.</param> + protected virtual void Dispose(bool disposing) + { + if (disposed) + { + return; + } + + if (disposing) + { + // Dispose managed state (managed objects) + + if (!leaveOpen) + { + reader?.Dispose(); + } + } + + // Free unmanaged resources (unmanaged objects) and override finalizer + // Set large fields to null + + disposed = true; + } + + /// <summary> + /// Processes a raw field based on configuration. + /// This will remove quotes, remove escapes, and trim if configured to. + /// </summary> + [DebuggerDisplay("Start = {Start}, Length = {Length}, Buffer.Length = {Buffer.Length}")] + protected readonly struct ProcessedField + { + /// <summary> + /// The start of the field in the buffer. + /// </summary> + public readonly int Start; + + /// <summary> + /// The length of the field in the buffer. + /// </summary> + public readonly int Length; + + /// <summary> + /// The buffer that contains the field. + /// </summary> + public readonly char[] Buffer; + + /// <summary> + /// Creates a new instance of ProcessedField. + /// </summary> + /// <param name="start">The start of the field in the buffer.</param> + /// <param name="length">The length of the field in the buffer.</param> + /// <param name="buffer">The buffer that contains the field.</param> + public ProcessedField(int start, int length, char[] buffer) + { + Start = start; + Length = length; + Buffer = buffer; + } + } + + private enum ReadLineResult + { + None = 0, + Complete, + Incomplete, + } + + private enum ParserState + { + None = 0, + Spaces, + BlankLine, + Delimiter, + LineEnding, + NewLine, + } + + [DebuggerDisplay("Start = {Start}, Length = {Length}, QuoteCount = {QuoteCount}, IsBad = {IsBad}")] + private struct Field + { + /// <summary> + /// Starting position of the field. + /// This is an offset from <see cref="rowStartPosition"/>. + /// </summary> + public int Start; + + public int Length; + + public int QuoteCount; + + public bool IsBad; + + public bool IsProcessed; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/CsvReader.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvReader.cs new file mode 100644 index 0000000..2b8ee84 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvReader.cs @@ -0,0 +1,1419 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.IO; +using CsvHelper.Configuration; +using CsvHelper.TypeConversion; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using CsvHelper.Expressions; +using System.Globalization; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Configuration; + +namespace CsvHelper +{ + /// <summary> + /// Reads data that was parsed from <see cref="IParser" />. + /// </summary> + public class CsvReader : IReader + { + private readonly Lazy<RecordManager> recordManager; + private readonly bool detectColumnCountChanges; + private readonly Dictionary<string, List<int>> namedIndexes = new Dictionary<string, List<int>>(); + private readonly Dictionary<string, (string, int)> namedIndexCache = new Dictionary<string, (string, int)>(); + private readonly Dictionary<Type, TypeConverterOptions> typeConverterOptionsCache = new Dictionary<Type, TypeConverterOptions>(); + private readonly MemberMapData reusableMemberMapData = new MemberMapData(null); + private readonly bool hasHeaderRecord; + private readonly HeaderValidated headerValidated; + private readonly ShouldSkipRecord? shouldSkipRecord; + private readonly ReadingExceptionOccurred readingExceptionOccurred; + private readonly CultureInfo cultureInfo; + private readonly bool ignoreBlankLines; + private readonly MissingFieldFound missingFieldFound; + private readonly bool includePrivateMembers; + private readonly PrepareHeaderForMatch prepareHeaderForMatch; + + private CsvContext context; + private bool disposed; + private IParser parser; + private int columnCount; + private int currentIndex = -1; + private bool hasBeenRead; + private string[]? headerRecord; + + /// <inheritdoc/> + public virtual int ColumnCount => columnCount; + + /// <inheritdoc/> + public virtual int CurrentIndex => currentIndex; + + /// <inheritdoc/> + public virtual string[]? HeaderRecord => headerRecord; + + /// <inheritdoc/> + public virtual CsvContext Context => context; + + /// <inheritdoc/> + public virtual IReaderConfiguration Configuration { get; private set; } + + /// <inheritdoc/> + public virtual IParser Parser => parser; + + /// <summary> + /// Creates a new CSV reader using the given <see cref="TextReader" />. + /// </summary> + /// <param name="reader">The reader.</param> + /// <param name="culture">The culture.</param> + /// <param name="leaveOpen"><c>true</c> to leave the <see cref="TextReader"/> open after the <see cref="CsvReader"/> object is disposed, otherwise <c>false</c>.</param> + public CsvReader(TextReader reader, CultureInfo culture, bool leaveOpen = false) : this(new CsvParser(reader, culture, leaveOpen)) { } + + /// <summary> + /// Creates a new CSV reader using the given <see cref="TextReader" /> and + /// <see cref="CsvHelper.Configuration.CsvConfiguration" /> and <see cref="CsvParser" /> as the default parser. + /// </summary> + /// <param name="reader">The reader.</param> + /// <param name="configuration">The configuration.</param> + /// <param name="leaveOpen"><c>true</c> to leave the <see cref="TextReader"/> open after the <see cref="CsvReader"/> object is disposed, otherwise <c>false</c>.</param> + public CsvReader(TextReader reader, IReaderConfiguration configuration, bool leaveOpen = false) : this(new CsvParser(reader, configuration, leaveOpen)) { } + + /// <summary> + /// Creates a new CSV reader using the given <see cref="IParser" />. + /// </summary> + /// <param name="parser">The <see cref="IParser" /> used to parse the CSV file.</param> + public CsvReader(IParser parser) + { + Configuration = parser.Configuration as IReaderConfiguration ?? throw new ConfigurationException($"The {nameof(IParser)} configuration must implement {nameof(IReaderConfiguration)} to be used in {nameof(CsvReader)}."); + + this.parser = parser ?? throw new ArgumentNullException(nameof(parser)); + context = parser.Context ?? throw new InvalidOperationException($"For {nameof(IParser)} to be used in {nameof(CsvReader)}, {nameof(IParser.Context)} must also implement {nameof(CsvContext)}."); + context.Reader = this; + recordManager = new Lazy<RecordManager>(() => ObjectResolver.Current.Resolve<RecordManager>(this)); + + cultureInfo = Configuration.CultureInfo; + detectColumnCountChanges = Configuration.DetectColumnCountChanges; + hasHeaderRecord = Configuration.HasHeaderRecord; + headerValidated = Configuration.HeaderValidated; + ignoreBlankLines = Configuration.IgnoreBlankLines; + includePrivateMembers = Configuration.IncludePrivateMembers; + missingFieldFound = Configuration.MissingFieldFound; + prepareHeaderForMatch = Configuration.PrepareHeaderForMatch; + readingExceptionOccurred = Configuration.ReadingExceptionOccurred; + shouldSkipRecord = Configuration.ShouldSkipRecord; + } + + /// <inheritdoc/> + public virtual bool ReadHeader() + { + if (!hasHeaderRecord) + { + throw new ReaderException(context, "Configuration.HasHeaderRecord is false."); + } + + headerRecord = parser.Record; + ParseNamedIndexes(); + + return headerRecord != null; + } + + /// <summary> + /// Validates the header to be of the given type. + /// </summary> + /// <typeparam name="T">The expected type of the header</typeparam> + public virtual void ValidateHeader<T>() + { + ValidateHeader(typeof(T)); + } + + /// <summary> + /// Validates the header to be of the given type. + /// </summary> + /// <param name="type">The expected type of the header.</param> + public virtual void ValidateHeader(Type type) + { + if (hasHeaderRecord == false) + { + throw new InvalidOperationException($"Validation can't be performed on a the header if no header exists. {nameof(Configuration.HasHeaderRecord)} can't be false."); + } + + CheckHasBeenRead(); + + if (headerRecord == null) + { + throw new InvalidOperationException($"The header must be read before it can be validated."); + } + + if (context.Maps[type] == null) + { + context.Maps.Add(context.AutoMap(type)); + } + + var map = context.Maps[type]; + var invalidHeaders = new List<InvalidHeader>(); + ValidateHeader(map, invalidHeaders); + + var args = new HeaderValidatedArgs(invalidHeaders.ToArray(), context); + headerValidated?.Invoke(args); + } + + /// <summary> + /// Validates the header to be of the given type. + /// </summary> + /// <param name="map">The mapped classes.</param> + /// <param name="invalidHeaders">The invalid headers.</param> + protected virtual void ValidateHeader(ClassMap map, List<InvalidHeader> invalidHeaders) + { + foreach (var parameter in map.ParameterMaps) + { + if (parameter.Data.Ignore) + { + continue; + } + + if (parameter.Data.IsConstantSet) + { + // If ConvertUsing and Constant don't require a header. + continue; + } + + if (parameter.Data.IsIndexSet && !parameter.Data.IsNameSet) + { + // If there is only an index set, we don't want to validate the header name. + continue; + } + + if (parameter.ConstructorTypeMap != null) + { + ValidateHeader(parameter.ConstructorTypeMap, invalidHeaders); + } + else if (parameter.ReferenceMap != null) + { + ValidateHeader(parameter.ReferenceMap.Data.Mapping, invalidHeaders); + } + else + { + var index = GetFieldIndex(parameter.Data.Names, parameter.Data.NameIndex, true); + var isValid = index != -1 || parameter.Data.IsOptional; + if (!isValid) + { + invalidHeaders.Add(new InvalidHeader { Index = parameter.Data.NameIndex, Names = parameter.Data.Names.ToList() }); + } + } + } + + foreach (var memberMap in map.MemberMaps) + { + if (memberMap.Data.Ignore || !CanRead(memberMap)) + { + continue; + } + + if (memberMap.Data.ReadingConvertExpression != null || memberMap.Data.IsConstantSet) + { + // If ConvertUsing and Constant don't require a header. + continue; + } + + if (memberMap.Data.IsIndexSet && !memberMap.Data.IsNameSet) + { + // If there is only an index set, we don't want to validate the header name. + continue; + } + + var index = GetFieldIndex(memberMap.Data.Names, memberMap.Data.NameIndex, true); + var isValid = index != -1 || memberMap.Data.IsOptional; + if (!isValid) + { + invalidHeaders.Add(new InvalidHeader { Index = memberMap.Data.NameIndex, Names = memberMap.Data.Names.ToList() }); + } + } + + foreach (var referenceMap in map.ReferenceMaps) + { + if (!CanRead(referenceMap)) + { + continue; + } + + ValidateHeader(referenceMap.Data.Mapping, invalidHeaders); + } + } + + /// <inheritdoc/> + public virtual bool Read() + { + // Don't forget about the async method below! + + bool hasMoreRecords; + do + { + hasMoreRecords = parser.Read(); + hasBeenRead = true; + } + while (hasMoreRecords && (shouldSkipRecord?.Invoke(new ShouldSkipRecordArgs(this)) ?? false)); + + currentIndex = -1; + + if (detectColumnCountChanges && hasMoreRecords) + { + if (columnCount > 0 && columnCount != parser.Count) + { + var csvException = new BadDataException(string.Empty, parser.RawRecord, context, "An inconsistent number of columns has been detected."); + + var args = new ReadingExceptionOccurredArgs(csvException); + if (readingExceptionOccurred?.Invoke(args) ?? true) + { + throw csvException; + } + } + + columnCount = parser.Count; + } + + return hasMoreRecords; + } + + /// <inheritdoc/> + public virtual async Task<bool> ReadAsync() + { + bool hasMoreRecords; + do + { + hasMoreRecords = await parser.ReadAsync().ConfigureAwait(false); + hasBeenRead = true; + } + while (hasMoreRecords && (shouldSkipRecord?.Invoke(new ShouldSkipRecordArgs(this)) ?? false)); + + currentIndex = -1; + + if (detectColumnCountChanges && hasMoreRecords) + { + if (columnCount > 0 && columnCount != parser.Count) + { + var csvException = new BadDataException(string.Empty, parser.RawRecord, context, "An inconsistent number of columns has been detected."); + + var args = new ReadingExceptionOccurredArgs(csvException); + if (readingExceptionOccurred?.Invoke(args) ?? true) + { + throw csvException; + } + } + + columnCount = parser.Count; + } + + return hasMoreRecords; + } + + /// <inheritdoc/> + public virtual string? this[int index] + { + get + { + CheckHasBeenRead(); + + return GetField(index); + } + } + + /// <inheritdoc/> + public virtual string? this[string name] + { + get + { + CheckHasBeenRead(); + + return GetField(name); + } + } + + /// <inheritdoc/> + public virtual string? this[string name, int index] + { + get + { + CheckHasBeenRead(); + + return GetField(name, index); + } + } + + /// <inheritdoc/> + public virtual string? GetField(int index) + { + CheckHasBeenRead(); + + // Set the current index being used so we + // have more information if an error occurs + // when reading records. + currentIndex = index; + + if (index >= parser.Count || index < 0) + { + var args = new MissingFieldFoundArgs(null, index, context); + missingFieldFound?.Invoke(args); + return default; + } + + var field = parser[index]; + + return field; + } + + /// <inheritdoc/> + public virtual string? GetField(string name) + { + CheckHasBeenRead(); + + var index = GetFieldIndex(name); + if (index < 0) + { + return null; + } + + return GetField(index); + } + + /// <inheritdoc/> + public virtual string? GetField(string name, int index) + { + CheckHasBeenRead(); + + var fieldIndex = GetFieldIndex(name, index); + if (fieldIndex < 0) + { + return null; + } + + return GetField(fieldIndex); + } + + /// <inheritdoc/> + public virtual object? GetField(Type type, int index) + { + CheckHasBeenRead(); + + var converter = context.TypeConverterCache.GetConverter(type); + return GetField(type, index, converter); + } + + /// <inheritdoc/> + public virtual object? GetField(Type type, string name) + { + CheckHasBeenRead(); + + var converter = context.TypeConverterCache.GetConverter(type); + return GetField(type, name, converter); + } + + /// <inheritdoc/> + public virtual object? GetField(Type type, string name, int index) + { + CheckHasBeenRead(); + + var converter = context.TypeConverterCache.GetConverter(type); + return GetField(type, name, index, converter); + } + + /// <inheritdoc/> + public virtual object? GetField(Type type, int index, ITypeConverter converter) + { + CheckHasBeenRead(); + + reusableMemberMapData.Index = index; + reusableMemberMapData.TypeConverter = converter; + if (!typeConverterOptionsCache.TryGetValue(type, out TypeConverterOptions typeConverterOptions)) + { + typeConverterOptions = TypeConverterOptions.Merge(new TypeConverterOptions { CultureInfo = cultureInfo }, context.TypeConverterOptionsCache.GetOptions(type)); + typeConverterOptionsCache.Add(type, typeConverterOptions); + } + + reusableMemberMapData.TypeConverterOptions = typeConverterOptions; + + var field = GetField(index); + return converter.ConvertFromString(field, this, reusableMemberMapData); + } + + /// <inheritdoc/> + public virtual object? GetField(Type type, string name, ITypeConverter converter) + { + CheckHasBeenRead(); + + var index = GetFieldIndex(name); + return GetField(type, index, converter); + } + + /// <inheritdoc/> + public virtual object? GetField(Type type, string name, int index, ITypeConverter converter) + { + CheckHasBeenRead(); + + var fieldIndex = GetFieldIndex(name, index); + return GetField(type, fieldIndex, converter); + } + + /// <inheritdoc/> + public virtual T? GetField<T>(int index) + { + CheckHasBeenRead(); + + var converter = context.TypeConverterCache.GetConverter<T>(); + return GetField<T>(index, converter); + } + + /// <inheritdoc/> + public virtual T? GetField<T>(string name) + { + CheckHasBeenRead(); + + var converter = context.TypeConverterCache.GetConverter<T>(); + return GetField<T>(name, converter); + } + + /// <inheritdoc/> + public virtual T? GetField<T>(string name, int index) + { + CheckHasBeenRead(); + + var converter = context.TypeConverterCache.GetConverter<T>(); + return GetField<T>(name, index, converter); + } + + /// <inheritdoc/> + public virtual T? GetField<T>(int index, ITypeConverter converter) + { + CheckHasBeenRead(); + + if (index >= parser.Count || index < 0) + { + currentIndex = index; + var args = new MissingFieldFoundArgs(null, index, context); + missingFieldFound?.Invoke(args); + + return default; + } + + return (T)GetField(typeof(T), index, converter); + } + + /// <inheritdoc/> + public virtual T? GetField<T>(string name, ITypeConverter converter) + { + CheckHasBeenRead(); + + var index = GetFieldIndex(name); + return GetField<T>(index, converter); + } + + /// <inheritdoc/> + public virtual T? GetField<T>(string name, int index, ITypeConverter converter) + { + CheckHasBeenRead(); + + var fieldIndex = GetFieldIndex(name, index); + return GetField<T>(fieldIndex, converter); + } + + /// <inheritdoc/> + public virtual T? GetField<T, TConverter>(int index) where TConverter : ITypeConverter + { + CheckHasBeenRead(); + + var converter = ObjectResolver.Current.Resolve<TConverter>(); + return GetField<T>(index, converter); + } + + /// <inheritdoc/> + public virtual T? GetField<T, TConverter>(string name) where TConverter : ITypeConverter + { + CheckHasBeenRead(); + + var converter = ObjectResolver.Current.Resolve<TConverter>(); + return GetField<T>(name, converter); + } + + /// <inheritdoc/> + public virtual T? GetField<T, TConverter>(string name, int index) where TConverter : ITypeConverter + { + CheckHasBeenRead(); + + var converter = ObjectResolver.Current.Resolve<TConverter>(); + return GetField<T>(name, index, converter); + } + + /// <inheritdoc/> + public virtual bool TryGetField(Type type, int index, out object? field) + { + CheckHasBeenRead(); + + var converter = context.TypeConverterCache.GetConverter(type); + return TryGetField(type, index, converter, out field); + } + + /// <inheritdoc/> + public virtual bool TryGetField(Type type, string name, out object? field) + { + CheckHasBeenRead(); + + var converter = context.TypeConverterCache.GetConverter(type); + return TryGetField(type, name, converter, out field); + } + + /// <inheritdoc/> + public virtual bool TryGetField(Type type, string name, int index, out object? field) + { + CheckHasBeenRead(); + + var converter = context.TypeConverterCache.GetConverter(type); + return TryGetField(type, name, index, converter, out field); + } + + /// <inheritdoc/> + public virtual bool TryGetField(Type type, int index, ITypeConverter converter, out object? field) + { + CheckHasBeenRead(); + + // TypeConverter.IsValid() just wraps a + // ConvertFrom() call in a try/catch, so lets not + // do it twice and just do it ourselves. + try + { + field = GetField(type, index, converter); + return true; + } + catch + { + field = type.GetTypeInfo().IsValueType ? ObjectResolver.Current.Resolve(type) : null; + return false; + } + } + + /// <inheritdoc/> + public virtual bool TryGetField(Type type, string name, ITypeConverter converter, out object? field) + { + CheckHasBeenRead(); + + var index = GetFieldIndex(name, isTryGet: true); + if (index == -1) + { + field = type.GetTypeInfo().IsValueType ? ObjectResolver.Current.Resolve(type) : null; + return false; + } + + return TryGetField(type, index, converter, out field); + } + + /// <inheritdoc/> + public virtual bool TryGetField(Type type, string name, int index, ITypeConverter converter, out object? field) + { + CheckHasBeenRead(); + + var fieldIndex = GetFieldIndex(name, index, true); + if (fieldIndex == -1) + { + field = type.GetTypeInfo().IsValueType ? ObjectResolver.Current.Resolve(type) : null; + return false; + } + + return TryGetField(type, fieldIndex, converter, out field); + } + + /// <inheritdoc/> + public virtual bool TryGetField<T>(int index, out T? field) + { + CheckHasBeenRead(); + + var converter = context.TypeConverterCache.GetConverter<T>(); + return TryGetField(index, converter, out field); + } + + /// <inheritdoc/> + public virtual bool TryGetField<T>(string name, out T? field) + { + CheckHasBeenRead(); + + var converter = context.TypeConverterCache.GetConverter<T>(); + return TryGetField(name, converter, out field); + } + + /// <inheritdoc/> + public virtual bool TryGetField<T>(string name, int index, out T? field) + { + CheckHasBeenRead(); + + var converter = context.TypeConverterCache.GetConverter<T>(); + return TryGetField(name, index, converter, out field); + } + + /// <inheritdoc/> + public virtual bool TryGetField<T>(int index, ITypeConverter converter, out T? field) + { + CheckHasBeenRead(); + + // TypeConverter.IsValid() just wraps a + // ConvertFrom() call in a try/catch, so lets not + // do it twice and just do it ourselves. + try + { + field = GetField<T>(index, converter); + return true; + } + catch + { + field = default; + return false; + } + } + + /// <inheritdoc/> + public virtual bool TryGetField<T>(string name, ITypeConverter converter, out T? field) + { + CheckHasBeenRead(); + + var index = GetFieldIndex(name, isTryGet: true); + if (index == -1) + { + field = default; + return false; + } + + return TryGetField(index, converter, out field); + } + + /// <inheritdoc/> + public virtual bool TryGetField<T>(string name, int index, ITypeConverter converter, out T? field) + { + CheckHasBeenRead(); + + var fieldIndex = GetFieldIndex(name, index, true); + if (fieldIndex == -1) + { + field = default; + return false; + } + + return TryGetField(fieldIndex, converter, out field); + } + + /// <inheritdoc/> + public virtual bool TryGetField<T, TConverter>(int index, out T? field) where TConverter : ITypeConverter + { + CheckHasBeenRead(); + + var converter = ObjectResolver.Current.Resolve<TConverter>(); + return TryGetField(index, converter, out field); + } + + /// <inheritdoc/> + public virtual bool TryGetField<T, TConverter>(string name, out T? field) where TConverter : ITypeConverter + { + CheckHasBeenRead(); + + var converter = ObjectResolver.Current.Resolve<TConverter>(); + return TryGetField(name, converter, out field); + } + + /// <inheritdoc/> + public virtual bool TryGetField<T, TConverter>(string name, int index, out T? field) where TConverter : ITypeConverter + { + CheckHasBeenRead(); + + var converter = ObjectResolver.Current.Resolve<TConverter>(); + return TryGetField(name, index, converter, out field); + } + + /// <inheritdoc/> + public virtual T? GetRecord<T>() + { + CheckHasBeenRead(); + + if (headerRecord == null && hasHeaderRecord) + { + ReadHeader(); + ValidateHeader<T>(); + + if (!Read()) + { + return default; + } + } + + T record; + try + { + record = recordManager.Value.Create<T>(); + } + catch (Exception ex) + { + var csvHelperException = ex as CsvHelperException ?? new ReaderException(context, "An unexpected error occurred.", ex); + + var args = new ReadingExceptionOccurredArgs(csvHelperException); + if (readingExceptionOccurred?.Invoke(args) ?? true) + { + if (ex is CsvHelperException) + { + throw; + } + else + { + throw csvHelperException; + } + } + + record = default; + } + + return record; + } + + /// <inheritdoc/> + public virtual T? GetRecord<T>(T anonymousTypeDefinition) + { + if (anonymousTypeDefinition == null) + { + throw new ArgumentNullException(nameof(anonymousTypeDefinition)); + } + + if (!anonymousTypeDefinition.GetType().IsAnonymous()) + { + throw new ArgumentException($"Argument is not an anonymous type.", nameof(anonymousTypeDefinition)); + } + + return GetRecord<T>(); + } + + /// <inheritdoc/> + public virtual object? GetRecord(Type type) + { + CheckHasBeenRead(); + + if (headerRecord == null && hasHeaderRecord) + { + ReadHeader(); + ValidateHeader(type); + + if (!Read()) + { + return null; + } + } + + object record; + try + { + record = recordManager.Value.Create(type); + } + catch (Exception ex) + { + var csvHelperException = ex as CsvHelperException ?? new ReaderException(context, "An unexpected error occurred.", ex); + + var args = new ReadingExceptionOccurredArgs(csvHelperException); + if (readingExceptionOccurred?.Invoke(args) ?? true) + { + if (ex is CsvHelperException) + { + throw; + } + else + { + throw csvHelperException; + } + } + + record = default; + } + + return record; + } + + /// <inheritdoc/> + public virtual IEnumerable<T> GetRecords<T>() + { + if (disposed) + { + throw new ObjectDisposedException(nameof(CsvReader), + "GetRecords<T>() returns an IEnumerable<T> that yields records. This means that the method isn't actually called until " + + "you try and access the values. e.g. .ToList() Did you create CsvReader inside a using block and are now trying to access " + + "the records outside of that using block?" + ); + } + + // Don't need to check if it's been read + // since we're doing the reading ourselves. + + if (hasHeaderRecord && headerRecord == null) + { + if (!Read()) + { + yield break; + } + + ReadHeader(); + ValidateHeader<T>(); + } + + while (Read()) + { + T record; + try + { + record = recordManager.Value.Create<T>(); + } + catch (Exception ex) + { + var csvHelperException = ex as CsvHelperException ?? new ReaderException(context, "An unexpected error occurred.", ex); + + var args = new ReadingExceptionOccurredArgs(csvHelperException); + if (readingExceptionOccurred?.Invoke(args) ?? true) + { + if (ex is CsvHelperException) + { + throw; + } + else + { + throw csvHelperException; + } + } + + // If the callback doesn't throw, keep going. + continue; + } + + yield return record; + } + } + + /// <inheritdoc/> + public virtual IEnumerable<T> GetRecords<T>(T anonymousTypeDefinition) + { + if (anonymousTypeDefinition == null) + { + throw new ArgumentNullException(nameof(anonymousTypeDefinition)); + } + + if (!anonymousTypeDefinition.GetType().IsAnonymous()) + { + throw new ArgumentException($"Argument is not an anonymous type.", nameof(anonymousTypeDefinition)); + } + + return GetRecords<T>(); + } + + /// <inheritdoc/> + public virtual IEnumerable<object?> GetRecords(Type type) + { + if (disposed) + { + throw new ObjectDisposedException(nameof(CsvReader), + "GetRecords<object>() returns an IEnumerable<T> that yields records. This means that the method isn't actually called until " + + "you try and access the values. e.g. .ToList() Did you create CsvReader inside a using block and are now trying to access " + + "the records outside of that using block?" + ); + } + + // Don't need to check if it's been read + // since we're doing the reading ourselves. + + if (hasHeaderRecord && headerRecord == null) + { + if (!Read()) + { + yield break; + } + + ReadHeader(); + ValidateHeader(type); + } + + while (Read()) + { + object? record; + try + { + record = recordManager.Value.Create(type); + } + catch (Exception ex) + { + var csvHelperException = ex as CsvHelperException ?? new ReaderException(context, "An unexpected error occurred.", ex); + + var args = new ReadingExceptionOccurredArgs(csvHelperException); + if (readingExceptionOccurred?.Invoke(args) ?? true) + { + if (ex is CsvHelperException) + { + throw; + } + else + { + throw csvHelperException; + } + } + + // If the callback doesn't throw, keep going. + continue; + } + + yield return record; + } + } + + /// <inheritdoc/> + public virtual IEnumerable<T> EnumerateRecords<T>(T record) + { + if (disposed) + { + throw new ObjectDisposedException(nameof(CsvReader), + "GetRecords<T>() returns an IEnumerable<T> that yields records. This means that the method isn't actually called until " + + "you try and access the values. e.g. .ToList() Did you create CsvReader inside a using block and are now trying to access " + + "the records outside of that using block?" + ); + } + + // Don't need to check if it's been read + // since we're doing the reading ourselves. + + if (hasHeaderRecord && headerRecord == null) + { + if (!Read()) + { + yield break; + } + + ReadHeader(); + ValidateHeader<T>(); + } + + while (Read()) + { + try + { + recordManager.Value.Hydrate(record); + } + catch (Exception ex) + { + var csvHelperException = ex as CsvHelperException ?? new ReaderException(context, "An unexpected error occurred.", ex); + + var args = new ReadingExceptionOccurredArgs(csvHelperException); + if (readingExceptionOccurred?.Invoke(args) ?? true) + { + if (ex is CsvHelperException) + { + throw; + } + else + { + throw csvHelperException; + } + } + + // If the callback doesn't throw, keep going. + continue; + } + + yield return record; + } + } + +#if !NET45 + /// <inheritdoc/> + public virtual async IAsyncEnumerable<T> GetRecordsAsync<T>([EnumeratorCancellation] CancellationToken cancellationToken = default(CancellationToken)) + { + if (disposed) + { + throw new ObjectDisposedException(nameof(CsvReader), + "GetRecords<T>() returns an IEnumerable<T> that yields records. This means that the method isn't actually called until " + + "you try and access the values. Did you create CsvReader inside a using block and are now trying to access " + + "the records outside of that using block?" + ); + } + + // Don't need to check if it's been read + // since we're doing the reading ourselves. + + if (hasHeaderRecord && headerRecord == null) + { + if (!await ReadAsync().ConfigureAwait(false)) + { + yield break; + } + + ReadHeader(); + ValidateHeader<T>(); + } + + while (await ReadAsync().ConfigureAwait(false)) + { + cancellationToken.ThrowIfCancellationRequested(); + T record; + try + { + record = recordManager.Value.Create<T>(); + } + catch (Exception ex) + { + var csvHelperException = ex as CsvHelperException ?? new ReaderException(context, "An unexpected error occurred.", ex); + + var args = new ReadingExceptionOccurredArgs(csvHelperException); + if (readingExceptionOccurred?.Invoke(args) ?? true) + { + if (ex is CsvHelperException) + { + throw; + } + else + { + throw csvHelperException; + } + } + + // If the callback doesn't throw, keep going. + continue; + } + + yield return record; + } + } + + /// <inheritdoc/> + public virtual IAsyncEnumerable<T> GetRecordsAsync<T>(T anonymousTypeDefinition, CancellationToken cancellationToken = default) + { + if (anonymousTypeDefinition == null) + { + throw new ArgumentNullException(nameof(anonymousTypeDefinition)); + } + + if (!anonymousTypeDefinition.GetType().IsAnonymous()) + { + throw new ArgumentException($"Argument is not an anonymous type.", nameof(anonymousTypeDefinition)); + } + + return GetRecordsAsync<T>(cancellationToken); + } + + /// <inheritdoc/> + public virtual async IAsyncEnumerable<object?> GetRecordsAsync(Type type, [EnumeratorCancellation] CancellationToken cancellationToken = default) + { + if (disposed) + { + throw new ObjectDisposedException(nameof(CsvReader), + "GetRecords<object>() returns an IEnumerable<T> that yields records. This means that the method isn't actually called until " + + "you try and access the values. Did you create CsvReader inside a using block and are now trying to access " + + "the records outside of that using block?" + ); + } + + // Don't need to check if it's been read + // since we're doing the reading ourselves. + + if (hasHeaderRecord && headerRecord == null) + { + if (!await ReadAsync().ConfigureAwait(false)) + { + yield break; + } + + ReadHeader(); + ValidateHeader(type); + } + + while (await ReadAsync().ConfigureAwait(false)) + { + cancellationToken.ThrowIfCancellationRequested(); + object record; + try + { + record = recordManager.Value.Create(type); + } + catch (Exception ex) + { + var csvHelperException = ex as CsvHelperException ?? new ReaderException(context, "An unexpected error occurred.", ex); + + var args = new ReadingExceptionOccurredArgs(csvHelperException); + if (readingExceptionOccurred?.Invoke(args) ?? true) + { + if (ex is CsvHelperException) + { + throw; + } + else + { + throw csvHelperException; + } + } + + // If the callback doesn't throw, keep going. + continue; + } + + yield return record; + } + } + + /// <inheritdoc/> + public virtual async IAsyncEnumerable<T> EnumerateRecordsAsync<T>(T record, [EnumeratorCancellation] CancellationToken cancellationToken = default) + { + if (disposed) + { + throw new ObjectDisposedException(nameof(CsvReader), + "GetRecords<T>() returns an IEnumerable<T> that yields records. This means that the method isn't actually called until " + + "you try and access the values. Did you create CsvReader inside a using block and are now trying to access " + + "the records outside of that using block?" + ); + } + + // Don't need to check if it's been read + // since we're doing the reading ourselves. + + if (hasHeaderRecord && headerRecord == null) + { + if (!await ReadAsync().ConfigureAwait(false)) + { + yield break; + } + + ReadHeader(); + ValidateHeader<T>(); + } + + while (await ReadAsync().ConfigureAwait(false)) + { + cancellationToken.ThrowIfCancellationRequested(); + try + { + recordManager.Value.Hydrate(record); + } + catch (Exception ex) + { + var csvHelperException = ex as CsvHelperException ?? new ReaderException(context, "An unexpected error occurred.", ex); + + var args = new ReadingExceptionOccurredArgs(csvHelperException); + if (readingExceptionOccurred?.Invoke(args) ?? true) + { + if (ex is CsvHelperException) + { + throw; + } + else + { + throw csvHelperException; + } + } + + // If the callback doesn't throw, keep going. + continue; + } + + yield return record; + } + } +#endif + + /// <summary> + /// Gets the index of the field with the given name. + /// </summary> + /// <param name="name">The name of the field.</param> + /// <param name="index">The index of the field.</param> + /// <param name="isTryGet">Indicates if a TryGet is executed.</param> + /// <returns>The index of the field.</returns> + public virtual int GetFieldIndex(string name, int index = 0, bool isTryGet = false) + { + return GetFieldIndex(new[] { name }, index, isTryGet); + } + + /// <summary> + /// Gets the index of the field with the given name. + /// </summary> + /// <param name="names">The names of the field.</param> + /// <param name="index">The index of the field.</param> + /// <param name="isTryGet">Indicates if a TryGet is executed.</param> + /// <param name="isOptional">Indicates if the field is optional.</param> + /// <returns>The index of the field.</returns> + public virtual int GetFieldIndex(IEnumerable<string> names, int index = 0, bool isTryGet = false, bool isOptional = false) + { + if (names == null) + { + throw new ArgumentNullException(nameof(names)); + } + + if (!hasHeaderRecord) + { + throw new ReaderException(context, "There is no header record to determine the index by name."); + } + + if (headerRecord == null) + { + throw new ReaderException(context, "The header has not been read. You must call ReadHeader() before any fields can be retrieved by name."); + } + + // Caching the named index speeds up mappings that use ConvertUsing tremendously. + var nameKey = string.Join("_", names) + index; + if (namedIndexCache.TryGetValue(nameKey, out var cache)) + { + (var cachedName, var cachedIndex) = cache; + return namedIndexes[cachedName][cachedIndex]; + } + + // Check all possible names for this field. + string name = null; + var i = 0; + foreach (var n in names) + { + // Get the list of indexes for this name. + var args = new PrepareHeaderForMatchArgs(n, i); + var fieldName = prepareHeaderForMatch(args); + if (namedIndexes.ContainsKey(fieldName)) + { + name = fieldName; + break; + } + + i++; + } + + // Check if the index position exists. + if (name == null || index >= namedIndexes[name].Count) + { + // It doesn't exist. The field is missing. + if (!isTryGet && !isOptional) + { + var args = new MissingFieldFoundArgs(names.ToArray(), index, context); + missingFieldFound?.Invoke(args); + } + + return -1; + } + + namedIndexCache.Add(nameKey, (name, index)); + + return namedIndexes[name][index]; + } + + /// <summary> + /// Indicates if values can be read. + /// </summary> + /// <param name="memberMap">The member map.</param> + /// <returns>True if values can be read.</returns> + public virtual bool CanRead(MemberMap memberMap) + { + var cantRead = + // Ignored member; + memberMap.Data.Ignore; + + var property = memberMap.Data.Member as PropertyInfo; + if (property != null) + { + cantRead = cantRead || + // Properties that don't have a public setter + // and we are honoring the accessor modifier. + property.GetSetMethod() == null && !includePrivateMembers || + // Properties that don't have a setter at all. + property.GetSetMethod(true) == null; + } + + return !cantRead; + } + + /// <summary> + /// Indicates if values can be read. + /// </summary> + /// <param name="memberReferenceMap">The member reference map.</param> + /// <returns>True if values can be read.</returns> + public virtual bool CanRead(MemberReferenceMap memberReferenceMap) + { + var cantRead = false; + + var property = memberReferenceMap.Data.Member as PropertyInfo; + if (property != null) + { + cantRead = + // Properties that don't have a public setter + // and we are honoring the accessor modifier. + property.GetSetMethod() == null && !includePrivateMembers || + // Properties that don't have a setter at all. + property.GetSetMethod(true) == null; + } + + return !cantRead; + } + + /// <inheritdoc/> + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// <summary> + /// Disposes the object. + /// </summary> + /// <param name="disposing">Indicates if the object is being disposed.</param> + protected virtual void Dispose(bool disposing) + { + if (disposed) + { + return; + } + + // Dispose managed state (managed objects) + if (disposing) + { + parser.Dispose(); + } + + // Free unmanaged resources (unmanaged objects) and override finalizer + // Set large fields to null + context = null; + + disposed = true; + } + + /// <summary> + /// Checks if the file has been read. + /// </summary> + /// <exception cref="ReaderException">Thrown when the file has not yet been read.</exception> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected virtual void CheckHasBeenRead() + { + if (!hasBeenRead) + { + throw new ReaderException(context, "You must call read on the reader before accessing its data."); + } + } + + /// <summary> + /// Parses the named indexes. + /// </summary> + /// <exception cref="ReaderException">Thrown when no header record was found.</exception> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected virtual void ParseNamedIndexes() + { + if (headerRecord == null) + { + throw new ReaderException(context, "No header record was found."); + } + + namedIndexes.Clear(); + namedIndexCache.Clear(); + + for (var i = 0; i < headerRecord.Length; i++) + { + var args = new PrepareHeaderForMatchArgs(headerRecord[i], i); + var name = prepareHeaderForMatch(args); + if (namedIndexes.TryGetValue(name, out var index)) + { + index.Add(i); + } + else + { + namedIndexes[name] = new List<int> { i }; + } + } + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/CsvWriter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvWriter.cs new file mode 100644 index 0000000..4120926 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvWriter.cs @@ -0,0 +1,842 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using CsvHelper.Configuration; +using CsvHelper.TypeConversion; +using System.Linq; +using System.Linq.Expressions; +using System.Dynamic; +using System.Threading.Tasks; +using CsvHelper.Expressions; +using System.Globalization; +using System.Runtime.CompilerServices; +using System.Text; +using System.Buffers; +using System.Threading; + +#pragma warning disable 649 +#pragma warning disable 169 + +namespace CsvHelper +{ + /// <summary> + /// Used to write CSV files. + /// </summary> + public class CsvWriter : IWriter + { + private readonly TextWriter writer; + private readonly CsvContext context; + private readonly Lazy<RecordManager> recordManager; + private readonly TypeConverterCache typeConverterCache; + private readonly TrimOptions trimOptions; + private readonly ShouldQuote shouldQuote; + private readonly MemberMapData reusableMemberMapData = new MemberMapData(null); + private readonly Dictionary<Type, TypeConverterOptions> typeConverterOptionsCache = new Dictionary<Type, TypeConverterOptions>(); + private readonly string quoteString; + private readonly char quote; + private readonly CultureInfo cultureInfo; + private readonly char comment; + private readonly bool hasHeaderRecord; + private readonly bool includePrivateMembers; + private readonly IComparer<string> dynamicPropertySort; + private readonly string delimiter; + private readonly bool leaveOpen; + private readonly string newLine; + private readonly char[] injectionCharacters; + private readonly char injectionEscapeCharacter; + private readonly InjectionOptions injectionOptions; + private readonly CsvMode mode; + private readonly string escapeString; + private readonly string escapeQuoteString; + private readonly string escapeDelimiterString; + private readonly string escapeNewlineString; + private readonly string escapeEscapeString; + + private bool disposed; + private bool hasHeaderBeenWritten; + private int row = 1; + private int index; + private char[] buffer; + private int bufferSize; + private int bufferPosition; + private Type fieldType; + + /// <inheritdoc/> + public virtual string[] HeaderRecord { get; private set; } + + /// <inheritdoc/> + public virtual int Row => row; + + /// <inheritdoc/> + public virtual int Index => index; + + /// <inheritdoc/> + public virtual CsvContext Context => context; + + /// <inheritdoc/> + public virtual IWriterConfiguration Configuration { get; private set; } + + /// <summary> + /// Initializes a new instance of the <see cref="CsvWriter"/> class. + /// </summary> + /// <param name="writer">The writer.</param> + /// <param name="culture">The culture.</param> + /// <param name="leaveOpen"><c>true</c> to leave the <see cref="TextWriter"/> open after the <see cref="CsvWriter"/> object is disposed, otherwise <c>false</c>.</param> + public CsvWriter(TextWriter writer, CultureInfo culture, bool leaveOpen = false) : this(writer, new CsvConfiguration(culture), leaveOpen) { } + + /// <summary> + /// Initializes a new instance of the <see cref="CsvWriter"/> class. + /// </summary> + /// <param name="writer">The writer.</param> + /// <param name="configuration">The configuration.</param> + /// <param name="leaveOpen"><c>true</c> to leave the <see cref="TextWriter"/> open after the <see cref="CsvWriter"/> object is disposed, otherwise <c>false</c>.</param> + public CsvWriter(TextWriter writer, IWriterConfiguration configuration, bool leaveOpen = false) + { + configuration.Validate(); + + this.writer = writer; + Configuration = configuration; + context = new CsvContext(this); + typeConverterCache = context.TypeConverterCache; + recordManager = new Lazy<RecordManager>(() => ObjectResolver.Current.Resolve<RecordManager>(this)); + + comment = configuration.Comment; + bufferSize = configuration.BufferSize; + delimiter = configuration.Delimiter; + cultureInfo = configuration.CultureInfo; + dynamicPropertySort = configuration.DynamicPropertySort; + escapeDelimiterString = new string(configuration.Delimiter.SelectMany(c => new[] { configuration.Escape, c }).ToArray()); + escapeNewlineString = new string(configuration.NewLine.SelectMany(c => new[] { configuration.Escape, c }).ToArray()); + escapeQuoteString = new string(new[] { configuration.Escape, configuration.Quote }); + escapeEscapeString = new string(new[] { configuration.Escape, configuration.Escape }); + hasHeaderRecord = configuration.HasHeaderRecord; + includePrivateMembers = configuration.IncludePrivateMembers; + injectionCharacters = configuration.InjectionCharacters; + injectionEscapeCharacter = configuration.InjectionEscapeCharacter; + this.leaveOpen = leaveOpen; + mode = configuration.Mode; + newLine = configuration.NewLine; + quote = configuration.Quote; + quoteString = configuration.Quote.ToString(); + escapeString = configuration.Escape.ToString(); + injectionOptions = configuration.InjectionOptions; + shouldQuote = configuration.ShouldQuote; + trimOptions = configuration.TrimOptions; + + buffer = new char[bufferSize]; + } + + /// <inheritdoc/> + public virtual void WriteConvertedField(string field, Type fieldType) + { + this.fieldType = fieldType; + + if (field == null) + { + return; + } + + WriteField(field); + } + + /// <inheritdoc/> + public virtual void WriteField(string field) + { + if (field != null && (trimOptions & TrimOptions.Trim) == TrimOptions.Trim) + { + field = field.Trim(); + } + + fieldType ??= typeof(string); + + var args = new ShouldQuoteArgs(field, fieldType, this); + var shouldQuoteResult = shouldQuote(args); + + WriteField(field, shouldQuoteResult); + } + + /// <inheritdoc/> + public virtual void WriteField(string field, bool shouldQuote) + { + if (mode == CsvMode.RFC4180) + { + // All quotes must be escaped. + if (shouldQuote) + { + if (escapeString != quoteString) + { + field = field?.Replace(escapeString, escapeEscapeString); + } + + field = field?.Replace(quoteString, escapeQuoteString); + field = quote + field + quote; + } + } + else if (mode == CsvMode.Escape) + { + field = field? + .Replace(escapeString, escapeEscapeString) + .Replace(quoteString, escapeQuoteString) + .Replace(delimiter, escapeDelimiterString) + .Replace(newLine, escapeNewlineString); + } + + if (injectionOptions != InjectionOptions.None) + { + field = SanitizeForInjection(field); + } + + if (index > 0) + { + WriteToBuffer(delimiter); + } + + WriteToBuffer(field); + index++; + fieldType = null; + } + + /// <inheritdoc/> + public virtual void WriteField<T>(T field) + { + var type = field == null ? typeof(string) : field.GetType(); + var converter = typeConverterCache.GetConverter(type); + WriteField(field, converter); + } + + /// <inheritdoc/> + public virtual void WriteField<T>(T field, ITypeConverter converter) + { + var type = field == null ? typeof(string) : field.GetType(); + reusableMemberMapData.TypeConverter = converter; + if (!typeConverterOptionsCache.TryGetValue(type, out TypeConverterOptions typeConverterOptions)) + { + typeConverterOptions = TypeConverterOptions.Merge(new TypeConverterOptions { CultureInfo = cultureInfo }, context.TypeConverterOptionsCache.GetOptions(type)); + typeConverterOptionsCache.Add(type, typeConverterOptions); + } + + reusableMemberMapData.TypeConverterOptions = typeConverterOptions; + + var fieldString = converter.ConvertToString(field, this, reusableMemberMapData); + + WriteConvertedField(fieldString, type); + } + + /// <inheritdoc/> + public virtual void WriteField<T, TConverter>(T field) + { + var converter = typeConverterCache.GetConverter<TConverter>(); + + WriteField(field, converter); + } + + /// <inheritdoc/> + public virtual void WriteComment(string text) + { + WriteField(comment + text, false); + } + + /// <inheritdoc/> + public virtual void WriteHeader<T>() + { + WriteHeader(typeof(T)); + } + + /// <inheritdoc/> + public virtual void WriteHeader(Type type) + { + if (type == null) + { + throw new ArgumentNullException(nameof(type)); + } + + if (type == typeof(object)) + { + return; + } + + if (context.Maps[type] == null) + { + context.Maps.Add(context.AutoMap(type)); + } + + var members = new MemberMapCollection(); + members.AddMembers(context.Maps[type]); + + var headerRecord = new List<string>(); + + foreach (var member in members) + { + if (CanWrite(member)) + { + if (member.Data.IndexEnd >= member.Data.Index) + { + var count = member.Data.IndexEnd - member.Data.Index + 1; + for (var i = 1; i <= count; i++) + { + var header = member.Data.Names.FirstOrDefault() + i; + WriteField(header); + headerRecord.Add(header); + } + } + else + { + var header = member.Data.Names.FirstOrDefault(); + WriteField(header); + headerRecord.Add(header); + } + } + } + + HeaderRecord = headerRecord.ToArray(); + + hasHeaderBeenWritten = true; + } + + /// <summary> + /// Writes a dynamic header record. + /// </summary> + /// <param name="record">The header record to write.</param> + /// <exception cref="ArgumentNullException">Thrown when no record is passed.</exception> + public virtual void WriteDynamicHeader(IDynamicMetaObjectProvider record) + { + if (record == null) + { + throw new ArgumentNullException(nameof(record)); + } + + var metaObject = record.GetMetaObject(Expression.Constant(record)); + var names = metaObject.GetDynamicMemberNames().ToList(); + if (dynamicPropertySort != null) + { + names = names.OrderBy(name => name, dynamicPropertySort).ToList(); + } + + HeaderRecord = names.ToArray(); + + foreach (var name in names) + { + WriteField(name); + } + + hasHeaderBeenWritten = true; + } + + /// <inheritdoc/> + public virtual void WriteRecord<T>(T? record) + { + try + { + recordManager.Value.Write(record); + } + catch (TargetInvocationException ex) + { + if (ex.InnerException != null) + { + throw ex.InnerException; + } + else + { + throw; + } + } + catch (Exception ex) when (ex is not CsvHelperException) + { + throw new WriterException(context, "An unexpected error occurred. See inner exception for details.", ex); + } + } + + /// <inheritdoc/> + public virtual void WriteRecords(IEnumerable records) + { + // Changes in this method require changes in method WriteRecords<T>(IEnumerable<T> records) also. + + try + { + if (WriteHeader(records)) + { + NextRecord(); + } + + foreach (var record in records) + { + if (record == null) + { + // Since every record could be a different type, just write a blank line. + NextRecord(); + continue; + } + + WriteRecord(record); + NextRecord(); + } + } + catch (Exception ex) when (ex is not CsvHelperException) + { + throw new WriterException(context, "An unexpected error occurred. See inner exception for details.", ex); + } + } + + /// <inheritdoc/> + public virtual void WriteRecords<T>(IEnumerable<T> records) + { + // Changes in this method require changes in method WriteRecords(IEnumerable records) also. + + try + { + if (WriteHeader(records)) + { + NextRecord(); + } + + foreach (var record in records) + { + WriteRecord(record); + NextRecord(); + } + } + catch (Exception ex) when (ex is not CsvHelperException) + { + throw new WriterException(context, "An unexpected error occurred. See inner exception for details.", ex); + } + } + + /// <inheritdoc/> + public virtual async Task WriteRecordsAsync(IEnumerable records, CancellationToken cancellationToken = default) + { + // These methods should all be the same; + // - WriteRecordsAsync(IEnumerable records) + // - WriteRecordsAsync<T>(IEnumerable<T> records) + // - WriteRecordsAsync<T>(IAsyncEnumerable<T> records) + + try + { + if (WriteHeader(records)) + { + await NextRecordAsync().ConfigureAwait(false); + } + + foreach (var record in records) + { + cancellationToken.ThrowIfCancellationRequested(); + + WriteRecord(record); + await NextRecordAsync().ConfigureAwait(false); + } + } + catch (Exception ex) when (ex is not CsvHelperException) + { + throw new WriterException(context, "An unexpected error occurred. See inner exception for details.", ex); + } + } + + /// <inheritdoc/> + public virtual async Task WriteRecordsAsync<T>(IEnumerable<T> records, CancellationToken cancellationToken = default) + { + // These methods should all be the same; + // - WriteRecordsAsync(IEnumerable records) + // - WriteRecordsAsync<T>(IEnumerable<T> records) + // - WriteRecordsAsync<T>(IAsyncEnumerable<T> records) + + try + { + if (WriteHeader(records)) + { + await NextRecordAsync().ConfigureAwait(false); + } + + foreach (var record in records) + { + cancellationToken.ThrowIfCancellationRequested(); + + WriteRecord(record); + await NextRecordAsync().ConfigureAwait(false); + } + } + catch (Exception ex) when (ex is not CsvHelperException) + { + throw new WriterException(context, "An unexpected error occurred. See inner exception for details.", ex); + } + } + +#if !NET45 + /// <inheritdoc/> + public virtual async Task WriteRecordsAsync<T>(IAsyncEnumerable<T> records, CancellationToken cancellationToken = default) + { + // These methods should all be the same; + // - WriteRecordsAsync(IEnumerable records) + // - WriteRecordsAsync<T>(IEnumerable<T> records) + // - WriteRecordsAsync<T>(IAsyncEnumerable<T> records) + + try + { + if (await WriteHeaderAsync(records)) + { + await NextRecordAsync().ConfigureAwait(false); + } + + await foreach (var record in records.ConfigureAwait(false)) + { + cancellationToken.ThrowIfCancellationRequested(); + + WriteRecord(record); + await NextRecordAsync().ConfigureAwait(false); + } + } + catch (Exception ex) when (ex is not CsvHelperException) + { + throw new WriterException(context, "An unexpected error occurred. See inner exception for details.", ex); + } + } +#endif + + /// <inheritdoc/> + public virtual void NextRecord() + { + WriteToBuffer(newLine); + FlushBuffer(); + + index = 0; + row++; + } + + /// <inheritdoc/> + public virtual async Task NextRecordAsync() + { + WriteToBuffer(newLine); + await FlushBufferAsync().ConfigureAwait(false); + + index = 0; + row++; + } + + /// <inheritdoc/> + public virtual void Flush() + { + FlushBuffer(); + writer.Flush(); + } + + /// <inheritdoc/> + public virtual async Task FlushAsync() + { + await FlushBufferAsync().ConfigureAwait(false); + await writer.FlushAsync().ConfigureAwait(false); + } + + /// <summary> + /// Flushes the buffer. + /// </summary> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected virtual void FlushBuffer() + { + writer.Write(buffer, 0, bufferPosition); + bufferPosition = 0; + } + + /// <summary> + /// Asynchronously flushes the buffer. + /// </summary> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected virtual async Task FlushBufferAsync() + { + await writer.WriteAsync(buffer, 0, bufferPosition).ConfigureAwait(false); + bufferPosition = 0; + } + + /// <summary> + /// Indicates if values can be written. + /// </summary> + /// <param name="memberMap">The member map.</param> + /// <returns>True if values can be written.</returns> + public virtual bool CanWrite(MemberMap memberMap) + { + var cantWrite = + // Ignored members. + memberMap.Data.Ignore; + + if (memberMap.Data.Member is PropertyInfo property) + { + cantWrite = cantWrite || + // Properties that don't have a public getter + // and we are honoring the accessor modifier. + property.GetGetMethod() == null && !includePrivateMembers || + // Properties that don't have a getter at all. + property.GetGetMethod(true) == null; + } + + return !cantWrite; + } + + /// <summary> + /// Determines the type for the given record. + /// </summary> + /// <typeparam name="T">The type of the record.</typeparam> + /// <param name="record">The record to determine the type of.</param> + /// <returns>The System.Type for the record.</returns> + public virtual Type GetTypeForRecord<T>(T record) + { + var type = typeof(T); + if (type == typeof(object)) + { + type = record.GetType(); + } + + return type; + } + + /// <summary> + /// Sanitizes the given field, before it is injected. + /// </summary> + /// <param name="field">The field to sanitize.</param> + /// <returns>The sanitized field.</returns> + /// <exception cref="WriterException">Thrown when an injection character is found in the field.</exception> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected virtual string SanitizeForInjection(string field) + { + if (string.IsNullOrEmpty(field)) + { + return field; + } + + int injectionCharIndex; + if (ArrayHelper.Contains(injectionCharacters, field[0])) + { + injectionCharIndex = 0; + } + else if (field[0] == quote && field[field.Length - 1] == quote && ArrayHelper.Contains(injectionCharacters, field[1])) + { + injectionCharIndex = 1; + } + else + { + return field; + } + + if (injectionOptions == InjectionOptions.Exception) + { + throw new WriterException(context, $"Injection character '{field[injectionCharIndex]}' detected"); + } + + if (injectionOptions == InjectionOptions.Escape) + { + if (injectionCharIndex == 0) + { + // =1+"2 -> "'=1+""2" + field = quoteString + injectionEscapeCharacter + field.Replace(quoteString, escapeQuoteString) + quoteString; + } + else + { + // "=1+2" -> "'=1+2" + field = quoteString + injectionEscapeCharacter + field.Substring(injectionCharIndex); + } + } + else if (injectionOptions == InjectionOptions.Strip) + { + while (true) + { + field = field.Substring(1); + + if (field.Length == 0 || !ArrayHelper.Contains(injectionCharacters, field[0])) + { + break; + } + } + + if (injectionCharIndex == 1) + { + field = quoteString + field; + } + } + + return field; + } + + /// <summary> + /// Writes the given value to the buffer. + /// </summary> + /// <param name="value">The value to write.</param> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected void WriteToBuffer(string value) + { + var length = value?.Length ?? 0; + + if (value == null || length == 0) + { + return; + } + + var lengthNeeded = bufferPosition + length; + if (lengthNeeded >= bufferSize) + { + while (lengthNeeded >= bufferSize) + { + bufferSize *= 2; + } + + Array.Resize(ref buffer, bufferSize); + } + + value.CopyTo(0, buffer, bufferPosition, length); + + bufferPosition += length; + } + + /// <inheritdoc/> + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// <summary> + /// Disposes the object. + /// </summary> + /// <param name="disposing">Indicates if the object is being disposed.</param> + protected virtual void Dispose(bool disposing) + { + if (disposed) + { + return; + } + + Flush(); + + if (disposing) + { + // Dispose managed state (managed objects) + + if (!leaveOpen) + { + writer.Dispose(); + } + } + + // Free unmanaged resources (unmanaged objects) and override finalizer + // Set large fields to null + + buffer = null; + + disposed = true; + } + +#if !NET45 && !NET47 && !NETSTANDARD2_0 + /// <inheritdoc/> + public async ValueTask DisposeAsync() + { + await DisposeAsync(true).ConfigureAwait(false); + GC.SuppressFinalize(this); + } + + /// <inheritdoc/> + protected virtual async ValueTask DisposeAsync(bool disposing) + { + if (disposed) + { + return; + } + + await FlushAsync().ConfigureAwait(false); + + if (disposing) + { + // Dispose managed state (managed objects) + + if (!leaveOpen) + { + await writer.DisposeAsync().ConfigureAwait(false); + } + } + + // Free unmanaged resources (unmanaged objects) and override finalizer + // Set large fields to null + + buffer = null; + + disposed = true; + } +#endif + +#if !NET45 + private async Task<bool> WriteHeaderAsync<T>(IAsyncEnumerable<T> records) + { + if (!hasHeaderRecord || hasHeaderBeenWritten) + { + return false; + } + + var recordType = typeof(T); + var isPrimitive = recordType.GetTypeInfo().IsPrimitive; + if (!isPrimitive && recordType != typeof(object)) + { + WriteHeader(recordType); + return hasHeaderBeenWritten; + } + + return WriteHeader(await records.FirstOrDefaultAsync()); + } +#endif + + private bool WriteHeader<T>(IEnumerable<T> records) + { + if (!hasHeaderRecord || hasHeaderBeenWritten) + { + return false; + } + + var recordType = typeof(T); + var isPrimitive = recordType.GetTypeInfo().IsPrimitive; + if (!isPrimitive && recordType != typeof(object)) + { + WriteHeader(recordType); + return hasHeaderBeenWritten; + } + + return WriteHeader(records.FirstOrDefault()); + } + + private bool WriteHeader(IEnumerable records) + { + object? record = null; + foreach (var r in records) + { + if (r != null) + { + record = r; + } + } + + return WriteHeader(record); + } + + private bool WriteHeader(object? record) + { + if (record == null) + { + return false; + } + + if (record is IDynamicMetaObjectProvider dynamicObject) + { + WriteDynamicHeader(dynamicObject); + return true; + } + + var recordType = record.GetType(); + var isPrimitive = recordType.GetTypeInfo().IsPrimitive; + if (!isPrimitive) + { + WriteHeader(recordType); + return true; + } + + return false; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/BadDataFound.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/BadDataFound.cs new file mode 100644 index 0000000..5f25912 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/BadDataFound.cs @@ -0,0 +1,52 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CsvHelper +{ + /// <summary> + /// Function that gets called when bad data is found. + /// </summary> + /// <param name="args">The args.</param> + public delegate void BadDataFound(BadDataFoundArgs args); + + /// <summary> + /// Information about the field that caused <see cref="BadDataFound"/> to be called. + /// </summary> + public readonly struct BadDataFoundArgs + { + /// <summary> + /// The full field unedited. + /// </summary> + public readonly string Field; + + /// <summary> + /// The full row unedited. + /// </summary> + public readonly string RawRecord; + + /// <summary> + /// The context. + /// </summary> + public readonly CsvContext Context; + + /// <summary> + /// Creates a new instance of BadDataFoundArgs. + /// </summary> + /// <param name="field">The full field unedited.</param> + /// <param name="rawRecord">The full row unedited.</param> + /// <param name="context">The context.</param> + public BadDataFoundArgs(string field, string rawRecord, CsvContext context) + { + Field = field; + RawRecord = rawRecord; + Context = context; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/ConvertFromString.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/ConvertFromString.cs new file mode 100644 index 0000000..48b2512 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/ConvertFromString.cs @@ -0,0 +1,40 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CsvHelper +{ + /// <summary> + /// Function that converts a string into an object. + /// </summary> + /// <typeparam name="TMember">The type of the member.</typeparam> + /// <param name="args">The args.</param> + /// <returns>The class object.</returns> + public delegate TMember ConvertFromString<TMember>(ConvertFromStringArgs args); + + /// <summary> + /// <see cref="ConvertFromString{TMember}"/> args. + /// </summary> + public readonly struct ConvertFromStringArgs + { + /// <summary> + /// The row. + /// </summary> + public readonly IReaderRow Row; + + /// <summary> + /// Creates a new instance of ConvertFromStringArgs. + /// </summary> + /// <param name="row">The row.</param> + public ConvertFromStringArgs(IReaderRow row) + { + Row = row; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/ConvertToString.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/ConvertToString.cs new file mode 100644 index 0000000..478526e --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/ConvertToString.cs @@ -0,0 +1,41 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CsvHelper +{ + /// <summary> + /// Function that converts an object into a string. + /// </summary> + /// <typeparam name="TClass">The type of the class.</typeparam> + /// <param name="args">The args.</param> + /// <returns>The string.</returns> + public delegate string ConvertToString<TClass>(ConvertToStringArgs<TClass> args); + + /// <summary> + /// <see cref="ConvertToString{TClass}"/> args. + /// </summary> + /// <typeparam name="TClass">The value to convert.</typeparam> + public readonly struct ConvertToStringArgs<TClass> + { + /// <summary> + /// The value to convert. + /// </summary> + public readonly TClass Value; + + /// <summary> + /// Creates a new instance of ConvertToStringArgs{TClass}. + /// </summary> + /// <param name="value">The value to convert.</param> + public ConvertToStringArgs(TClass value) + { + Value = value; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/GetConstructor.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/GetConstructor.cs new file mode 100644 index 0000000..8678a5c --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/GetConstructor.cs @@ -0,0 +1,38 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace CsvHelper +{ + /// <summary> + /// Function that chooses the constructor to use for constructor mapping. + /// </summary> + public delegate ConstructorInfo GetConstructor(GetConstructorArgs args); + + /// <summary> + /// GetConstructor args. + /// </summary> + public readonly struct GetConstructorArgs + { + /// <summary> + /// The class type. + /// </summary> + public readonly Type ClassType; + + /// <summary> + /// Creates a new instance of GetConstructorArgs. + /// </summary> + /// <param name="classType">The class type.</param> + public GetConstructorArgs(Type classType) + { + ClassType = classType; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/GetDelimiter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/GetDelimiter.cs new file mode 100644 index 0000000..2593200 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/GetDelimiter.cs @@ -0,0 +1,44 @@ +using CsvHelper.Configuration; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CsvHelper.Delegates +{ + /// <summary> + /// Function that resolves the delimiter from the given text. + /// Returns null if no delimiter is found. + /// </summary> + /// <param name="args"></param> + /// <returns></returns> + public delegate string? GetDelimiter(GetDelimiterArgs args); + + /// <summary> + /// GetDelimiter args. + /// </summary> + public readonly struct GetDelimiterArgs + { + /// <summary> + /// The text to resolve the delimiter from. + /// </summary> + public readonly string Text; + + /// <summary> + /// The configuration. + /// </summary> + public readonly IParserConfiguration Configuration; + + /// <summary> + /// Creates an instance of GetDelimiterArgs. + /// </summary> + /// <param name="text">The text to resolve the delimiter from.</param> + /// <param name="configuration">The configuration.</param> + public GetDelimiterArgs(string text, IParserConfiguration configuration) + { + Text = text; + Configuration = configuration; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/GetDynamicPropertyName.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/GetDynamicPropertyName.cs new file mode 100644 index 0000000..4a761d6 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/GetDynamicPropertyName.cs @@ -0,0 +1,44 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CsvHelper +{ + /// <summary> + /// Function that gets the name to use for the property of the dynamic object. + /// </summary> + public delegate string GetDynamicPropertyName(GetDynamicPropertyNameArgs args); + + /// <summary> + /// GetDynamicPropertyName args. + /// </summary> + public readonly struct GetDynamicPropertyNameArgs + { + /// <summary> + /// The field index. + /// </summary> + public readonly int FieldIndex; + + /// <summary> + /// The context. + /// </summary> + public readonly CsvContext Context; + + /// <summary> + /// Creates a new instance of GetDynamicPropertyNameArgs. + /// </summary> + /// <param name="fieldIndex">The field index.</param> + /// <param name="context">The context.</param> + public GetDynamicPropertyNameArgs(int fieldIndex, CsvContext context) + { + FieldIndex = fieldIndex; + Context = context; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/HeaderValidated.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/HeaderValidated.cs new file mode 100644 index 0000000..07836d3 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/HeaderValidated.cs @@ -0,0 +1,46 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CsvHelper +{ + /// <summary> + /// Function that is called when a header validation check is ran. The default function + /// will throw a <see cref="ValidationException"/> if there is no header for a given member mapping. + /// You can supply your own function to do other things like logging the issue instead of throwing an exception. + /// </summary> + public delegate void HeaderValidated(HeaderValidatedArgs args); + + /// <summary> + /// HeaderValidated args. + /// </summary> + public readonly struct HeaderValidatedArgs + { + /// <summary> + /// The invalid headers. + /// </summary> + public readonly InvalidHeader[] InvalidHeaders; + + /// <summary> + /// The context. + /// </summary> + public readonly CsvContext Context; + + /// <summary> + /// Creates a new instance of HeaderValidatedArgs. + /// </summary> + /// <param name="invalidHeaders">The invalid headers.</param> + /// <param name="context">The context.</param> + public HeaderValidatedArgs(InvalidHeader[] invalidHeaders, CsvContext context) + { + InvalidHeaders = invalidHeaders; + Context = context; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/MissingFieldFound.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/MissingFieldFound.cs new file mode 100644 index 0000000..cb725fb --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/MissingFieldFound.cs @@ -0,0 +1,53 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CsvHelper +{ + /// <summary> + /// Function that is called when a missing field is found. The default function will + /// throw a <see cref="MissingFieldException"/>. You can supply your own function to do other things + /// like logging the issue instead of throwing an exception. + /// </summary> + public delegate void MissingFieldFound(MissingFieldFoundArgs args); + + /// <summary> + /// MissingFieldFound args. + /// </summary> + public readonly struct MissingFieldFoundArgs + { + /// <summary> + /// The header names. + /// </summary> + public readonly string[]? HeaderNames; + + /// <summary> + /// The index. + /// </summary> + public readonly int Index; + + /// <summary> + /// The context. + /// </summary> + public readonly CsvContext Context; + + /// <summary> + /// Creates a new instance of MissingFieldFoundArgs. + /// </summary> + /// <param name="headerNames">The header names.</param> + /// <param name="index">The index.</param> + /// <param name="context">The context.</param> + public MissingFieldFoundArgs(string[]? headerNames, int index, CsvContext context) + { + HeaderNames = headerNames; + Index = index; + Context = context; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/PrepareHeaderForMatch.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/PrepareHeaderForMatch.cs new file mode 100644 index 0000000..061e493 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/PrepareHeaderForMatch.cs @@ -0,0 +1,47 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CsvHelper +{ + /// <summary> + /// Function that prepares the header field for matching against a member name. + /// The header field and the member name are both ran through this function. + /// You should do things like trimming, removing whitespace, removing underscores, + /// and making casing changes to ignore case. + /// </summary> + public delegate string PrepareHeaderForMatch(PrepareHeaderForMatchArgs args); + + /// <summary> + /// PrepareHeaderForMatch args. + /// </summary> + public readonly struct PrepareHeaderForMatchArgs + { + /// <summary> + /// The header. + /// </summary> + public readonly string Header; + + /// <summary> + /// The field index. + /// </summary> + public readonly int FieldIndex; + + /// <summary> + /// Creates a new instance of PrepareHeaderForMatchArgs. + /// </summary> + /// <param name="header">The header.</param> + /// <param name="fieldIndex">The field index.</param> + public PrepareHeaderForMatchArgs(string header, int fieldIndex) + { + Header = header; + FieldIndex = fieldIndex; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/ReadingExceptionOccurred.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/ReadingExceptionOccurred.cs new file mode 100644 index 0000000..c3737ef --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/ReadingExceptionOccurred.cs @@ -0,0 +1,40 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CsvHelper +{ + /// <summary> + /// Function that is called when a reading exception occurs. + /// The default function will re-throw the given exception. If you want to ignore + /// reading exceptions, you can supply your own function to do other things like + /// logging the issue. + /// </summary> + public delegate bool ReadingExceptionOccurred(ReadingExceptionOccurredArgs args); + + /// <summary> + /// ReadingExceptionOccurred args. + /// </summary> + public readonly struct ReadingExceptionOccurredArgs + { + /// <summary> + /// The exception. + /// </summary> + public readonly CsvHelperException Exception; + + /// <summary> + /// Creates a new instance of ReadingExceptionOccurredArgs. + /// </summary> + /// <param name="exception">The exception.</param> + public ReadingExceptionOccurredArgs(CsvHelperException exception) + { + Exception = exception; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/ReferenceHeaderPrefix.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/ReferenceHeaderPrefix.cs new file mode 100644 index 0000000..d42d49f --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/ReferenceHeaderPrefix.cs @@ -0,0 +1,44 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CsvHelper +{ + /// <summary> + /// Function that will return the prefix for a reference header. + /// </summary> + public delegate string ReferenceHeaderPrefix(ReferenceHeaderPrefixArgs args); + + /// <summary> + /// ReferenceHeaderPrefix args. + /// </summary> + public readonly struct ReferenceHeaderPrefixArgs + { + /// <summary> + /// The member type. + /// </summary> + public readonly Type MemberType; + + /// <summary> + /// The member name. + /// </summary> + public readonly string MemberName; + + /// <summary> + /// Creates a new instance of ReferenceHeaderPrefixArgs. + /// </summary> + /// <param name="memberType">The member type.</param> + /// <param name="memberName">The member name.</param> + public ReferenceHeaderPrefixArgs(Type memberType, string memberName) + { + MemberType = memberType; + MemberName = memberName; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/ShouldQuote.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/ShouldQuote.cs new file mode 100644 index 0000000..ab84ba3 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/ShouldQuote.cs @@ -0,0 +1,51 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CsvHelper +{ + /// <summary> + /// Function that is used to determine if a field should get quoted when writing. + /// </summary> + public delegate bool ShouldQuote(ShouldQuoteArgs args); + + /// <summary> + /// ShouldQuote args. + /// </summary> + public readonly struct ShouldQuoteArgs + { + /// <summary> + /// The field. + /// </summary> + public readonly string Field; + + /// <summary> + /// The field type. + /// </summary> + public readonly Type FieldType; + + /// <summary> + /// The row. + /// </summary> + public readonly IWriterRow Row; + + /// <summary> + /// Creates a new instance of ShouldQuoteArgs. + /// </summary> + /// <param name="field">The field.</param> + /// <param name="fieldType">The field type.</param> + /// <param name="row">The row.</param> + public ShouldQuoteArgs(string field, Type fieldType, IWriterRow row) + { + Field = field; + FieldType = fieldType; + Row = row; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/ShouldSkipRecord.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/ShouldSkipRecord.cs new file mode 100644 index 0000000..cf87633 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/ShouldSkipRecord.cs @@ -0,0 +1,37 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CsvHelper +{ + /// <summary> + /// Function that determines whether to skip the given record or not. + /// </summary> + public delegate bool ShouldSkipRecord(ShouldSkipRecordArgs args); + + /// <summary> + /// ShouldSkipRecord args. + /// </summary> + public readonly struct ShouldSkipRecordArgs + { + /// <summary> + /// The record. + /// </summary> + public readonly IReaderRow Row; + + /// <summary> + /// Creates a new instance of ShouldSkipRecordArgs. + /// </summary> + /// <param name="row">The row.</param> + public ShouldSkipRecordArgs(IReaderRow row) + { + Row = row; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/ShouldUseConstructorParameters.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/ShouldUseConstructorParameters.cs new file mode 100644 index 0000000..cfbacd5 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/ShouldUseConstructorParameters.cs @@ -0,0 +1,38 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CsvHelper +{ + /// <summary> + /// Function that determines if constructor parameters should be used to create + /// the class instead of the default constructor and members. + /// </summary> + public delegate bool ShouldUseConstructorParameters(ShouldUseConstructorParametersArgs args); + + /// <summary> + /// ShouldUseConstructorParameters args. + /// </summary> + public readonly struct ShouldUseConstructorParametersArgs + { + /// <summary> + /// The parameter type. + /// </summary> + public readonly Type ParameterType; + + /// <summary> + /// Creates a new instance of ShouldUseConstructorParametersArgs. + /// </summary> + /// <param name="parameterType">The parameter type.</param> + public ShouldUseConstructorParametersArgs(Type parameterType) + { + ParameterType = parameterType; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/Validate.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/Validate.cs new file mode 100644 index 0000000..b2a42ea --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Delegates/Validate.cs @@ -0,0 +1,53 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CsvHelper +{ + /// <summary> + /// Function that validates a field. + /// </summary> + /// <param name="args">The args.</param> + /// <returns><c>true</c> if the field is valid, otherwise <c>false</c>.</returns> + public delegate bool Validate(ValidateArgs args); + + /// <summary> + /// Function that gets the exception message when validation fails. + /// </summary> + /// <param name="args">The args.</param> + /// <returns>The exception message.</returns> + public delegate string ValidateMessage(ValidateArgs args); + + /// <summary> + /// Validate args. + /// </summary> + public readonly struct ValidateArgs + { + /// <summary> + /// The field. + /// </summary> + public readonly string Field; + + /// <summary> + /// The row. + /// </summary> + public readonly IReaderRow Row; + + /// <summary> + /// Creates a new instance of ValidateArgs. + /// </summary> + /// <param name="field">The field.</param> + /// <param name="row">The row.</param> + public ValidateArgs(string field, IReaderRow row) + { + Field = field; + Row = row; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/EnumerableExtensions.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/EnumerableExtensions.cs new file mode 100644 index 0000000..a15b20b --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/EnumerableExtensions.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CsvHelper +{ + internal static class EnumerableExtensions + { +#if !NET45 + public static async Task<T?> FirstOrDefaultAsync<T>(this IAsyncEnumerable<T> collection) + { + await foreach (var o in collection.ConfigureAwait(false)) + { + if (o != null) + { + return o; + } + } + + return default(T); + } +#endif + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/DynamicRecordCreator.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/DynamicRecordCreator.cs new file mode 100644 index 0000000..b93390f --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/DynamicRecordCreator.cs @@ -0,0 +1,61 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Dynamic; + +namespace CsvHelper.Expressions +{ + /// <summary> + /// Creates dynamic records. + /// </summary> + public class DynamicRecordCreator : RecordCreator + { + /// <summary> + /// Initializes a new instance. + /// </summary> + /// <param name="reader">The reader.</param> + public DynamicRecordCreator(CsvReader reader) : base(reader) { } + + /// <summary> + /// Creates a <see cref="Delegate"/> of type <see cref="Func{T}"/> + /// that will create a record of the given type using the current + /// reader row. + /// </summary> + /// <param name="recordType">The record type.</param> + protected override Delegate CreateCreateRecordDelegate(Type recordType) => (Func<dynamic>)CreateDynamicRecord; + + /// <summary> + /// Creates a dynamic record of the current reader row. + /// </summary> + protected virtual dynamic CreateDynamicRecord() + { + var obj = new ExpandoObject(); + var dict = obj as IDictionary<string, object>; + if (Reader.HeaderRecord != null) + { + for (var i = 0; i < Reader.HeaderRecord.Length; i++) + { + var args = new GetDynamicPropertyNameArgs(i, Reader.Context); + var propertyName = Reader.Configuration.GetDynamicPropertyName(args); + Reader.TryGetField(i, out string field); + dict.Add(propertyName, field); + } + } + else + { + for (var i = 0; i < Reader.Parser.Count; i++) + { + var args = new GetDynamicPropertyNameArgs(i, Reader.Context); + var propertyName = Reader.Configuration.GetDynamicPropertyName(args); + var field = Reader.GetField(i); + dict.Add(propertyName, field); + } + } + + return obj; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/DynamicRecordWriter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/DynamicRecordWriter.cs new file mode 100644 index 0000000..a9ee401 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/DynamicRecordWriter.cs @@ -0,0 +1,75 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using Microsoft.CSharp.RuntimeBinder; +using System; +using System.Collections; +using System.Dynamic; +using System.Linq; +using System.Linq.Expressions; +using System.Runtime.CompilerServices; + +namespace CsvHelper.Expressions +{ + /// <summary> + /// Write dynamic records. + /// </summary> + public class DynamicRecordWriter : RecordWriter + { + private readonly Hashtable getters = new Hashtable(); + + /// <summary> + /// Initializes a new instance using the given writer. + /// </summary> + /// <param name="writer">The writer.</param> + public DynamicRecordWriter(CsvWriter writer) : base(writer) { } + + /// <summary> + /// Creates a <see cref="Delegate"/> of type <see cref="Action{T}"/> + /// that will write the given record using the current writer row. + /// </summary> + /// <typeparam name="T">The record type.</typeparam> + /// <param name="record">The record.</param> + protected override Action<T> CreateWriteDelegate<T>(T record) + { + // http://stackoverflow.com/a/14011692/68499 + + Action<T> action = r => + { + var provider = (IDynamicMetaObjectProvider)r; + var type = provider.GetType(); + + var parameterExpression = Expression.Parameter(typeof(T), "record"); + var metaObject = provider.GetMetaObject(parameterExpression); + var memberNames = metaObject.GetDynamicMemberNames(); + if (Writer.Configuration.DynamicPropertySort != null) + { + memberNames = memberNames.OrderBy(name => name, Writer.Configuration.DynamicPropertySort); + } + + foreach (var name in memberNames) + { + var value = GetValue(name, provider); + Writer.WriteField(value); + } + }; + + return action; + } + + private object GetValue(string name, IDynamicMetaObjectProvider target) + { + // https://stackoverflow.com/a/30757547/68499 + + var callSite = (CallSite<Func<CallSite, IDynamicMetaObjectProvider, object>>)getters[name]; + if (callSite == null) + { + var getMemberBinder = Binder.GetMember(CSharpBinderFlags.None, name, typeof(DynamicRecordWriter), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }); + getters[name] = callSite = CallSite<Func<CallSite, IDynamicMetaObjectProvider, object>>.Create(getMemberBinder); + } + + return callSite.Target(callSite, target); + } + } +}
\ No newline at end of file diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/ExpandoObjectRecordWriter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/ExpandoObjectRecordWriter.cs new file mode 100644 index 0000000..f0a5e67 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/ExpandoObjectRecordWriter.cs @@ -0,0 +1,49 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Linq; + +namespace CsvHelper.Expressions +{ + /// <summary> + /// Writes expando objects. + /// </summary> + public class ExpandoObjectRecordWriter : RecordWriter + { + /// <summary> + /// Initializes a new instance using the given writer. + /// </summary> + /// <param name="writer">The writer.</param> + public ExpandoObjectRecordWriter(CsvWriter writer) : base(writer) { } + + /// <summary> + /// Creates a <see cref="Delegate"/> of type <see cref="Action{T}"/> + /// that will write the given record using the current writer row. + /// </summary> + /// <typeparam name="T">The record type.</typeparam> + /// <param name="record">The record.</param> + protected override Action<T> CreateWriteDelegate<T>(T record) + { + Action<T> action = r => + { + var dict = ((IDictionary<string, object>)r).AsEnumerable(); + + if (Writer.Configuration.DynamicPropertySort != null) + { + dict = dict.OrderBy(pair => pair.Key, Writer.Configuration.DynamicPropertySort); + } + + var values = dict.Select(pair => pair.Value); + foreach (var val in values) + { + Writer.WriteField(val); + } + }; + + return action; + } + } +}
\ No newline at end of file diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/ExpressionManager.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/ExpressionManager.cs new file mode 100644 index 0000000..42ac8a6 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/ExpressionManager.cs @@ -0,0 +1,490 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using CsvHelper.Configuration; +using CsvHelper.TypeConversion; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; + +namespace CsvHelper.Expressions +{ + /// <summary> + /// Manages expression creation. + /// </summary> + public class ExpressionManager + { + private readonly CsvReader reader; + private readonly CsvWriter writer; + + /// <summary> + /// Initializes a new instance using the given reader. + /// </summary> + /// <param name="reader">The reader.</param> + public ExpressionManager(CsvReader reader) + { + this.reader = reader; + } + + /// <summary> + /// Initializes a new instance using the given writer. + /// </summary> + /// <param name="writer">The writer.</param> + public ExpressionManager(CsvWriter writer) + { + this.writer = writer; + } + + /// <summary> + /// Creates the constructor arguments used to create a type. + /// </summary> + /// <param name="map">The mapping to create the arguments for.</param> + /// <param name="argumentExpressions">The arguments that will be added to the mapping.</param> + public virtual void CreateConstructorArgumentExpressionsForMapping(ClassMap map, List<Expression> argumentExpressions) + { + foreach (var parameterMap in map.ParameterMaps) + { + if (parameterMap.Data.IsConstantSet) + { + var constantExpression = Expression.Convert(Expression.Constant(parameterMap.Data.Constant), parameterMap.Data.Parameter.ParameterType); + argumentExpressions.Add(constantExpression); + + continue; + } + + if (parameterMap.Data.Ignore) + { + Expression defaultExpression; + if (parameterMap.Data.IsDefaultSet) + { + defaultExpression = Expression.Convert(Expression.Constant(parameterMap.Data.Default), parameterMap.Data.Parameter.ParameterType); + } + else if (parameterMap.Data.Parameter.HasDefaultValue) + { + defaultExpression = Expression.Convert(Expression.Constant(parameterMap.Data.Parameter.DefaultValue), parameterMap.Data.Parameter.ParameterType); + } + else + { + defaultExpression = Expression.Default(parameterMap.Data.Parameter.ParameterType); + } + + argumentExpressions.Add(defaultExpression); + + continue; + } + + if (parameterMap.ConstructorTypeMap != null) + { + // Constructor parameter type. + var arguments = new List<Expression>(); + CreateConstructorArgumentExpressionsForMapping(parameterMap.ConstructorTypeMap, arguments); + var args = new GetConstructorArgs(parameterMap.ConstructorTypeMap.ClassType); + var constructorExpression = Expression.New(reader.Configuration.GetConstructor(args), arguments); + + argumentExpressions.Add(constructorExpression); + } + else if (parameterMap.ReferenceMap != null) + { + // Reference type. + + var referenceAssignments = new List<MemberAssignment>(); + CreateMemberAssignmentsForMapping(parameterMap.ReferenceMap.Data.Mapping, referenceAssignments); + + var referenceBody = CreateInstanceAndAssignMembers(parameterMap.ReferenceMap.Data.Parameter.ParameterType, referenceAssignments); + argumentExpressions.Add(referenceBody); + } + else + { + // Value type. + + int index; + if (reader.Configuration.HasHeaderRecord && (parameterMap.Data.IsNameSet || !parameterMap.Data.IsIndexSet)) + { + // Use name. + index = reader.GetFieldIndex(parameterMap.Data.Names, parameterMap.Data.NameIndex, parameterMap.Data.IsOptional); + if (index == -1) + { + if (parameterMap.Data.IsDefaultSet || parameterMap.Data.IsOptional) + { + var defaultExpression = CreateDefaultExpression(parameterMap, Expression.Constant(string.Empty)); + argumentExpressions.Add(defaultExpression); + continue; + } + + // Skip if the index was not found. + continue; + } + } + else if (!parameterMap.Data.IsIndexSet && parameterMap.Data.IsOptional) + { + // If there wasn't an index explicitly, use a default value since constructors need all + // arguments to be created. + var defaultExpression = CreateDefaultExpression(parameterMap, Expression.Constant(string.Empty)); + argumentExpressions.Add(defaultExpression); + continue; + } + else + { + // Use index. + index = parameterMap.Data.Index; + } + + // Get the field using the field index. + var method = typeof(IReaderRow).GetProperty("Item", typeof(string), new[] { typeof(int) }).GetGetMethod(); + Expression fieldExpression = Expression.Call(Expression.Constant(reader), method, Expression.Constant(index, typeof(int))); + + if (parameterMap.Data.IsDefaultSet) + { + fieldExpression = CreateDefaultExpression(parameterMap, fieldExpression); + } + else + { + fieldExpression = CreateTypeConverterExpression(parameterMap, fieldExpression); + } + + argumentExpressions.Add(fieldExpression); + } + } + } + + /// <summary> + /// Creates the member assignments for the given <see cref="ClassMap"/>. + /// </summary> + /// <param name="mapping">The mapping to create the assignments for.</param> + /// <param name="assignments">The assignments that will be added to from the mapping.</param> + public virtual void CreateMemberAssignmentsForMapping(ClassMap mapping, List<MemberAssignment> assignments) + { + foreach (var memberMap in mapping.MemberMaps) + { + var fieldExpression = CreateGetFieldExpression(memberMap); + if (fieldExpression == null) + { + continue; + } + + assignments.Add(Expression.Bind(memberMap.Data.Member, fieldExpression)); + } + + foreach (var referenceMap in mapping.ReferenceMaps) + { + if (!reader.CanRead(referenceMap)) + { + continue; + } + + Expression referenceBody; + if (referenceMap.Data.Mapping.ParameterMaps.Count > 0) + { + var arguments = new List<Expression>(); + CreateConstructorArgumentExpressionsForMapping(referenceMap.Data.Mapping, arguments); + var args = new GetConstructorArgs(referenceMap.Data.Mapping.ClassType); + referenceBody = Expression.New(reader.Configuration.GetConstructor(args), arguments); + } + else + { + var referenceAssignments = new List<MemberAssignment>(); + CreateMemberAssignmentsForMapping(referenceMap.Data.Mapping, referenceAssignments); + referenceBody = CreateInstanceAndAssignMembers(referenceMap.Data.Member.MemberType(), referenceAssignments); + } + + assignments.Add(Expression.Bind(referenceMap.Data.Member, referenceBody)); + } + } + + /// <summary> + /// Creates an expression the represents getting the field for the given + /// member and converting it to the member's type. + /// </summary> + /// <param name="memberMap">The mapping for the member.</param> + public virtual Expression? CreateGetFieldExpression(MemberMap memberMap) + { + if (memberMap.Data.ReadingConvertExpression != null) + { + // The user is providing the expression to do the conversion. + Expression exp = Expression.Invoke(memberMap.Data.ReadingConvertExpression, Expression.Constant(new ConvertFromStringArgs(reader))); + return Expression.Convert(exp, memberMap.Data.Member.MemberType()); + } + + if (!reader.CanRead(memberMap)) + { + return null; + } + + if (memberMap.Data.IsConstantSet) + { + return Expression.Convert(Expression.Constant(memberMap.Data.Constant), memberMap.Data.Member.MemberType()); + } + + if (memberMap.Data.TypeConverter == null) + { + // Skip if the type isn't convertible. + return null; + } + + int index; + if (reader.Configuration.HasHeaderRecord && (memberMap.Data.IsNameSet || !memberMap.Data.IsIndexSet)) + { + // Use the name. + index = reader.GetFieldIndex(memberMap.Data.Names, memberMap.Data.NameIndex, memberMap.Data.IsOptional); + if (index == -1) + { + if (memberMap.Data.IsDefaultSet) + { + return CreateDefaultExpression(memberMap, Expression.Constant(string.Empty)); + } + + // Skip if the index was not found. + return null; + } + } + else + { + // Use the index. + index = memberMap.Data.Index; + } + + // Get the field using the field index. + var method = typeof(IReaderRow).GetProperty("Item", typeof(string), new[] { typeof(int) }).GetGetMethod(); + Expression fieldExpression = Expression.Call(Expression.Constant(reader), method, Expression.Constant(index, typeof(int))); + + // Validate the field. + if (memberMap.Data.ValidateExpression != null) + { + var constructor = typeof(ValidateArgs).GetConstructor(new Type[] { typeof(string), typeof(IReaderRow) }); + var args = Expression.New(constructor, fieldExpression, Expression.Constant(reader)); + var validateExpression = Expression.IsFalse(Expression.Invoke(memberMap.Data.ValidateExpression, args)); + var validationExceptionConstructor = typeof(FieldValidationException).GetConstructor(new Type[] { typeof(CsvContext), typeof(string), typeof(string) }); + var messageExpression = Expression.Invoke(memberMap.Data.ValidateMessageExpression, args); + var newValidationExceptionExpression = Expression.New(validationExceptionConstructor, Expression.Constant(reader.Context), fieldExpression, messageExpression); + var throwExpression = Expression.Throw(newValidationExceptionExpression); + fieldExpression = Expression.Block( + // If the validate method returns false, throw an exception. + Expression.IfThen(validateExpression, throwExpression), + fieldExpression + ); + } + + if (memberMap.Data.IsDefaultSet) + { + return CreateDefaultExpression(memberMap, fieldExpression); + } + + fieldExpression = CreateTypeConverterExpression(memberMap, fieldExpression); + + return fieldExpression; + } + + /// <summary> + /// Creates a member expression for the given member on the record. + /// This will recursively traverse the mapping to find the member + /// and create a safe member accessor for each level as it goes. + /// </summary> + /// <param name="recordExpression">The current member expression.</param> + /// <param name="mapping">The mapping to look for the member to map on.</param> + /// <param name="memberMap">The member map to look for on the mapping.</param> + /// <returns>An Expression to access the given member.</returns> + public virtual Expression? CreateGetMemberExpression(Expression recordExpression, ClassMap mapping, MemberMap memberMap) + { + if (mapping.MemberMaps.Any(mm => mm == memberMap)) + { + // The member is on this level. + if (memberMap.Data.Member is PropertyInfo) + { + return Expression.Property(recordExpression, (PropertyInfo)memberMap.Data.Member); + } + + if (memberMap.Data.Member is FieldInfo) + { + return Expression.Field(recordExpression, (FieldInfo)memberMap.Data.Member); + } + } + + // The member isn't on this level of the mapping. + // We need to search down through the reference maps. + foreach (var refMap in mapping.ReferenceMaps) + { + var wrapped = refMap.Data.Member.GetMemberExpression(recordExpression); + var memberExpression = CreateGetMemberExpression(wrapped, refMap.Data.Mapping, memberMap); + if (memberExpression == null) + { + continue; + } + + if (refMap.Data.Member.MemberType().GetTypeInfo().IsValueType) + { + return memberExpression; + } + + var nullCheckExpression = Expression.Equal(wrapped, Expression.Constant(null)); + + var isValueType = memberMap.Data.Member.MemberType().GetTypeInfo().IsValueType; + var isGenericType = isValueType && memberMap.Data.Member.MemberType().GetTypeInfo().IsGenericType; + Type memberType; + if (isValueType && !isGenericType && !writer.Configuration.UseNewObjectForNullReferenceMembers) + { + memberType = typeof(Nullable<>).MakeGenericType(memberMap.Data.Member.MemberType()); + memberExpression = Expression.Convert(memberExpression, memberType); + } + else + { + memberType = memberMap.Data.Member.MemberType(); + } + + var defaultValueExpression = isValueType && !isGenericType + ? (Expression)Expression.New(memberType) + : Expression.Constant(null, memberType); + var conditionExpression = Expression.Condition(nullCheckExpression, defaultValueExpression, memberExpression); + return conditionExpression; + } + + return null; + } + + /// <summary> + /// Creates an instance of the given type using <see cref="IObjectResolver"/>, then assigns + /// the given member assignments to that instance. + /// </summary> + /// <param name="recordType">The type of the record we're creating.</param> + /// <param name="assignments">The member assignments that will be assigned to the created instance.</param> + /// <returns>A <see cref="BlockExpression"/> representing the instance creation and assignments.</returns> + public virtual BlockExpression CreateInstanceAndAssignMembers(Type recordType, List<MemberAssignment> assignments) + { + var expressions = new List<Expression>(); + var createInstanceMethod = typeof(IObjectResolver).GetMethod(nameof(IObjectResolver.Resolve), new Type[] { typeof(Type), typeof(object[]) }); + var instanceExpression = Expression.Convert(Expression.Call(Expression.Constant(ObjectResolver.Current), createInstanceMethod, Expression.Constant(recordType), Expression.Constant(new object[0])), recordType); + var variableExpression = Expression.Variable(instanceExpression.Type, "instance"); + expressions.Add(Expression.Assign(variableExpression, instanceExpression)); + expressions.AddRange(assignments.Select(b => Expression.Assign(Expression.MakeMemberAccess(variableExpression, b.Member), b.Expression))); + expressions.Add(variableExpression); + var variables = new ParameterExpression[] { variableExpression }; + var blockExpression = Expression.Block(variables, expressions); + + return blockExpression; + } + + /// <summary> + /// Creates an expression that converts the field expression using a type converter. + /// </summary> + /// <param name="memberMap">The mapping for the member.</param> + /// <param name="fieldExpression">The field expression.</param> + public virtual Expression CreateTypeConverterExpression(MemberMap memberMap, Expression fieldExpression) + { + memberMap.Data.TypeConverterOptions = TypeConverterOptions.Merge(new TypeConverterOptions { CultureInfo = reader.Configuration.CultureInfo }, reader.Context.TypeConverterOptionsCache.GetOptions(memberMap.Data.Member.MemberType()), memberMap.Data.TypeConverterOptions); + + Expression typeConverterFieldExpression = Expression.Call(Expression.Constant(memberMap.Data.TypeConverter), nameof(ITypeConverter.ConvertFromString), null, fieldExpression, Expression.Constant(reader), Expression.Constant(memberMap.Data)); + typeConverterFieldExpression = Expression.Convert(typeConverterFieldExpression, memberMap.Data.Member.MemberType()); + + return typeConverterFieldExpression; + } + + /// <summary> + /// Creates an expression that converts the field expression using a type converter. + /// </summary> + /// <param name="parameterMap">The mapping for the parameter.</param> + /// <param name="fieldExpression">The field expression.</param> + public virtual Expression CreateTypeConverterExpression(ParameterMap parameterMap, Expression fieldExpression) + { + parameterMap.Data.TypeConverterOptions = TypeConverterOptions.Merge + ( + new TypeConverterOptions { CultureInfo = reader.Configuration.CultureInfo }, + reader.Context.TypeConverterOptionsCache.GetOptions(parameterMap.Data.Parameter.ParameterType), + parameterMap.Data.TypeConverterOptions + ); + + var memberMapData = new MemberMapData(null) + { + Constant = parameterMap.Data.Constant, + Default = parameterMap.Data.Default, + Ignore = parameterMap.Data.Ignore, + Index = parameterMap.Data.Index, + IsConstantSet = parameterMap.Data.IsConstantSet, + IsDefaultSet = parameterMap.Data.IsDefaultSet, + IsIndexSet = parameterMap.Data.IsIndexSet, + IsNameSet = parameterMap.Data.IsNameSet, + NameIndex = parameterMap.Data.NameIndex, + TypeConverter = parameterMap.Data.TypeConverter, + TypeConverterOptions = parameterMap.Data.TypeConverterOptions + }; + memberMapData.Names.AddRange(parameterMap.Data.Names); + + Expression typeConverterFieldExpression = Expression.Call(Expression.Constant(parameterMap.Data.TypeConverter), nameof(ITypeConverter.ConvertFromString), null, fieldExpression, Expression.Constant(reader), Expression.Constant(memberMapData)); + typeConverterFieldExpression = Expression.Convert(typeConverterFieldExpression, parameterMap.Data.Parameter.ParameterType); + + return typeConverterFieldExpression; + } + + /// <summary> + /// Creates a default expression if field expression is empty. + /// </summary> + /// <param name="memberMap">The mapping for the member.</param> + /// <param name="fieldExpression">The field expression.</param> + public virtual Expression CreateDefaultExpression(MemberMap memberMap, Expression fieldExpression) + { + var typeConverterExpression = CreateTypeConverterExpression(memberMap, fieldExpression); + + // Create default value expression. + Expression defaultValueExpression; + if (memberMap.Data.Member.MemberType() != typeof(string) && memberMap.Data.Default != null && memberMap.Data.Default.GetType() == typeof(string)) + { + // The default is a string but the member type is not. Use a converter. + defaultValueExpression = Expression.Call(Expression.Constant(memberMap.Data.TypeConverter), nameof(ITypeConverter.ConvertFromString), null, Expression.Constant(memberMap.Data.Default), Expression.Constant(reader), Expression.Constant(memberMap.Data)); + } + else + { + // The member type and default type match. + defaultValueExpression = Expression.Constant(memberMap.Data.Default); + } + + defaultValueExpression = Expression.Convert(defaultValueExpression, memberMap.Data.Member.MemberType()); + + // If null, use string.Empty. + var coalesceExpression = Expression.Coalesce(fieldExpression, Expression.Constant(string.Empty)); + + // Check if the field is an empty string. + var checkFieldEmptyExpression = Expression.Equal(Expression.Convert(coalesceExpression, typeof(string)), Expression.Constant(string.Empty, typeof(string))); + + // Use a default value if the field is an empty string. + fieldExpression = Expression.Condition(checkFieldEmptyExpression, defaultValueExpression, typeConverterExpression); + + return fieldExpression; + } + + /// <summary> + /// Creates a default expression if field expression is empty. + /// </summary> + /// <param name="parameterMap">The mapping for the parameter.</param> + /// <param name="fieldExpression">The field expression.</param> + public virtual Expression CreateDefaultExpression(ParameterMap parameterMap, Expression fieldExpression) + { + var typeConverterExpression = CreateTypeConverterExpression(parameterMap, fieldExpression); + + // Create default value expression. + Expression defaultValueExpression; + if (parameterMap.Data.Parameter.ParameterType != typeof(string) && parameterMap.Data.Default != null && parameterMap.Data.Default.GetType() == typeof(string)) + { + // The default is a string but the member type is not. Use a converter. + //defaultValueExpression = Expression.Call(Expression.Constant(parameterMap.Data.TypeConverter), nameof(ITypeConverter.ConvertFromString), null, Expression.Constant(parameterMap.Data.Default), Expression.Constant(reader), Expression.Constant(memberMap.Data)); + defaultValueExpression = CreateTypeConverterExpression(parameterMap, Expression.Constant(parameterMap.Data.Default)); + } + else + { + // The member type and default type match. + defaultValueExpression = Expression.Convert(Expression.Constant(parameterMap.Data.Default), parameterMap.Data.Parameter.ParameterType); + } + + // If null, use string.Empty. + var coalesceExpression = Expression.Coalesce(fieldExpression, Expression.Constant(string.Empty)); + + // Check if the field is an empty string. + var checkFieldEmptyExpression = Expression.Equal(Expression.Convert(coalesceExpression, typeof(string)), Expression.Constant(string.Empty, typeof(string))); + + // Use a default value if the field is an empty string. + fieldExpression = Expression.Condition(checkFieldEmptyExpression, defaultValueExpression, typeConverterExpression); + + return fieldExpression; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/ObjectRecordCreator.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/ObjectRecordCreator.cs new file mode 100644 index 0000000..9adc951 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/ObjectRecordCreator.cs @@ -0,0 +1,66 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Linq.Expressions; + +namespace CsvHelper.Expressions +{ + /// <summary> + /// Creates objects. + /// </summary> + public class ObjectRecordCreator : RecordCreator + { + /// <summary> + /// Initializes a new instance using the given reader. + /// </summary> + /// <param name="reader"></param> + public ObjectRecordCreator(CsvReader reader) : base(reader) { } + + /// <summary> + /// Creates a <see cref="Delegate"/> of type <see cref="Func{T}"/> + /// that will create a record of the given type using the current + /// reader row. + /// </summary> + /// <param name="recordType">The record type.</param> + protected override Delegate CreateCreateRecordDelegate(Type recordType) + { + if (Reader.Context.Maps[recordType] == null) + { + Reader.Context.Maps.Add(Reader.Context.AutoMap(recordType)); + } + + var map = Reader.Context.Maps[recordType]; + + Expression body; + + if (map.ParameterMaps.Count > 0) + { + // This is a constructor parameter type. + var arguments = new List<Expression>(); + ExpressionManager.CreateConstructorArgumentExpressionsForMapping(map, arguments); + + var args = new GetConstructorArgs(map.ClassType); + body = Expression.New(Reader.Configuration.GetConstructor(args), arguments); + } + else + { + var assignments = new List<MemberAssignment>(); + ExpressionManager.CreateMemberAssignmentsForMapping(map, assignments); + + if (assignments.Count == 0) + { + throw new ReaderException(Reader.Context, $"No members are mapped for type '{recordType.FullName}'."); + } + + body = ExpressionManager.CreateInstanceAndAssignMembers(recordType, assignments); + } + + var funcType = typeof(Func<>).MakeGenericType(recordType); + + return Expression.Lambda(funcType, body).Compile(); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/ObjectRecordWriter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/ObjectRecordWriter.cs new file mode 100644 index 0000000..08fc79b --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/ObjectRecordWriter.cs @@ -0,0 +1,124 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using CsvHelper.Configuration; +using CsvHelper.TypeConversion; +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Reflection; + +namespace CsvHelper.Expressions +{ + /// <summary> + /// Writes objects. + /// </summary> + public class ObjectRecordWriter : RecordWriter + { + /// <summary> + /// Initializes a new instance using the given writer. + /// </summary> + /// <param name="writer">The writer.</param> + public ObjectRecordWriter(CsvWriter writer) : base(writer) { } + + /// <summary> + /// Creates a <see cref="Delegate"/> of type <see cref="Action{T}"/> + /// that will write the given record using the current writer row. + /// </summary> + /// <typeparam name="T">The record type.</typeparam> + /// <param name="record">The record.</param> + protected override Action<T> CreateWriteDelegate<T>(T record) + { + var type = Writer.GetTypeForRecord(record); + + if (Writer.Context.Maps[type] == null) + { + Writer.Context.Maps.Add(Writer.Context.AutoMap(type)); + } + + var recordParameter = Expression.Parameter(typeof(T), "record"); + var recordParameterConverted = Expression.Convert(recordParameter, type); + + // Get a list of all the members so they will + // be sorted properly. + var members = new MemberMapCollection(); + members.AddMembers(Writer.Context.Maps[type]); + + if (members.Count == 0) + { + throw new WriterException(Writer.Context, $"No properties are mapped for type '{type.FullName}'."); + } + + var delegates = new List<Action<T>>(); + + foreach (var memberMap in members) + { + if (memberMap.Data.WritingConvertExpression != null) + { + // The user is providing the expression to do the conversion. + var constructor = typeof(ConvertToStringArgs<T>).GetConstructor(new Type[] { typeof(T) }); + var args = Expression.New(constructor, recordParameterConverted); + Expression exp = Expression.Invoke(memberMap.Data.WritingConvertExpression, args); + exp = Expression.Call(Expression.Constant(Writer), nameof(Writer.WriteField), null, exp); + delegates.Add(Expression.Lambda<Action<T>>(exp, recordParameter).Compile()); + continue; + } + + if (!Writer.CanWrite(memberMap)) + { + continue; + } + + Expression fieldExpression; + + if (memberMap.Data.IsConstantSet) + { + if (memberMap.Data.Constant == null) + { + fieldExpression = Expression.Constant(string.Empty); + } + else + { + fieldExpression = Expression.Constant(memberMap.Data.Constant); + var typeConverterExpression = Expression.Constant(Writer.Context.TypeConverterCache.GetConverter(memberMap.Data.Constant.GetType())); + var method = typeof(ITypeConverter).GetMethod(nameof(ITypeConverter.ConvertToString)); + fieldExpression = Expression.Convert(fieldExpression, typeof(object)); + fieldExpression = Expression.Call(typeConverterExpression, method, fieldExpression, Expression.Constant(Writer), Expression.Constant(memberMap.Data)); + } + } + else + { + if (memberMap.Data.TypeConverter == null) + { + // Skip if the type isn't convertible. + continue; + } + + fieldExpression = ExpressionManager.CreateGetMemberExpression(recordParameterConverted, Writer.Context.Maps[type], memberMap); + + var typeConverterExpression = Expression.Constant(memberMap.Data.TypeConverter); + memberMap.Data.TypeConverterOptions = TypeConverterOptions.Merge(new TypeConverterOptions { CultureInfo = Writer.Configuration.CultureInfo }, Writer.Context.TypeConverterOptionsCache.GetOptions(memberMap.Data.Member.MemberType()), memberMap.Data.TypeConverterOptions); + + var method = typeof(ITypeConverter).GetMethod(nameof(ITypeConverter.ConvertToString)); + fieldExpression = Expression.Convert(fieldExpression, typeof(object)); + fieldExpression = Expression.Call(typeConverterExpression, method, fieldExpression, Expression.Constant(Writer), Expression.Constant(memberMap.Data)); + + if (type.GetTypeInfo().IsClass) + { + var areEqualExpression = Expression.Equal(recordParameterConverted, Expression.Constant(null)); + fieldExpression = Expression.Condition(areEqualExpression, Expression.Constant(string.Empty), fieldExpression); + } + } + + var writeFieldMethodCall = Expression.Call(Expression.Constant(Writer), nameof(Writer.WriteConvertedField), null, fieldExpression, Expression.Constant(memberMap.Data.Type)); + + delegates.Add(Expression.Lambda<Action<T>>(writeFieldMethodCall, recordParameter).Compile()); + } + + var action = CombineDelegates(delegates) ?? new Action<T>((T parameter) => { }); + + return action; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/PrimitiveRecordCreator.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/PrimitiveRecordCreator.cs new file mode 100644 index 0000000..3e1cfd0 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/PrimitiveRecordCreator.cs @@ -0,0 +1,49 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using CsvHelper.Configuration; +using CsvHelper.TypeConversion; +using System; +using System.Linq.Expressions; + +namespace CsvHelper.Expressions +{ + /// <summary> + /// Creates primitive records. + /// </summary> + public class PrimitiveRecordCreator : RecordCreator + { + /// <summary> + /// Initializes a new instance using the given reader. + /// </summary> + /// <param name="reader">The reader.</param> + public PrimitiveRecordCreator(CsvReader reader) : base(reader) { } + + /// <summary> + /// Creates a <see cref="Delegate"/> of type <see cref="Func{T}"/> + /// that will create a record of the given type using the current + /// reader row. + /// </summary> + /// <param name="recordType">The record type.</param> + protected override Delegate CreateCreateRecordDelegate(Type recordType) + { + var method = typeof(IReaderRow).GetProperty("Item", typeof(string), new[] { typeof(int) }).GetGetMethod(); + Expression fieldExpression = Expression.Call(Expression.Constant(Reader), method, Expression.Constant(0, typeof(int))); + + var memberMapData = new MemberMapData(null) + { + Index = 0, + TypeConverter = Reader.Context.TypeConverterCache.GetConverter(recordType) + }; + memberMapData.TypeConverterOptions = TypeConverterOptions.Merge(new TypeConverterOptions { CultureInfo = Reader.Configuration.CultureInfo }, Reader.Context.TypeConverterOptionsCache.GetOptions(recordType)); + + fieldExpression = Expression.Call(Expression.Constant(memberMapData.TypeConverter), "ConvertFromString", null, fieldExpression, Expression.Constant(Reader), Expression.Constant(memberMapData)); + fieldExpression = Expression.Convert(fieldExpression, recordType); + + var funcType = typeof(Func<>).MakeGenericType(recordType); + + return Expression.Lambda(funcType, fieldExpression).Compile(); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/PrimitiveRecordWriter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/PrimitiveRecordWriter.cs new file mode 100644 index 0000000..128c5c3 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/PrimitiveRecordWriter.cs @@ -0,0 +1,57 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using CsvHelper.Configuration; +using CsvHelper.TypeConversion; +using System; +using System.Linq.Expressions; + +namespace CsvHelper.Expressions +{ + /// <summary> + /// Writes primitives. + /// </summary> + public class PrimitiveRecordWriter : RecordWriter + { + /// <summary> + /// Initializes a new instance using the given writer. + /// </summary> + /// <param name="writer">The writer.</param> + public PrimitiveRecordWriter(CsvWriter writer) : base(writer) { } + + /// <summary> + /// Creates a <see cref="Delegate"/> of type <see cref="Action{T}"/> + /// that will write the given record using the current writer row. + /// </summary> + /// <typeparam name="T">The record type.</typeparam> + /// <param name="record">The record.</param> + protected override Action<T> CreateWriteDelegate<T>(T record) + { + var type = Writer.GetTypeForRecord(record); + + var recordParameter = Expression.Parameter(typeof(T), "record"); + + Expression fieldExpression = Expression.Convert(recordParameter, typeof(object)); + + var typeConverter = Writer.Context.TypeConverterCache.GetConverter(type); + var typeConverterExpression = Expression.Constant(typeConverter); + var method = typeof(ITypeConverter).GetMethod(nameof(ITypeConverter.ConvertToString)); + + var memberMapData = new MemberMapData(null) + { + Index = 0, + TypeConverter = typeConverter, + TypeConverterOptions = TypeConverterOptions.Merge(new TypeConverterOptions(), Writer.Context.TypeConverterOptionsCache.GetOptions(type)) + }; + memberMapData.TypeConverterOptions.CultureInfo = Writer.Configuration.CultureInfo; + + fieldExpression = Expression.Call(typeConverterExpression, method, fieldExpression, Expression.Constant(Writer), Expression.Constant(memberMapData)); + fieldExpression = Expression.Call(Expression.Constant(Writer), nameof(Writer.WriteConvertedField), null, fieldExpression, Expression.Constant(type)); + + var action = Expression.Lambda<Action<T>>(fieldExpression, recordParameter).Compile(); + + return action; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/RecordCreator.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/RecordCreator.cs new file mode 100644 index 0000000..d14f0d6 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/RecordCreator.cs @@ -0,0 +1,107 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace CsvHelper.Expressions +{ + /// <summary> + /// Base implementation for classes that create records. + /// </summary> + public abstract class RecordCreator + { + private readonly Dictionary<Type, Delegate> createRecordFuncs = new Dictionary<Type, Delegate>(); + + /// <summary> + /// The reader. + /// </summary> + protected CsvReader Reader { get; private set; } + + /// <summary> + /// The expression manager. + /// </summary> + protected ExpressionManager ExpressionManager { get; private set; } + + /// <summary> + /// Initializes a new instance using the given reader. + /// </summary> + /// <param name="reader">The reader.</param> + public RecordCreator(CsvReader reader) + { + Reader = reader; + ExpressionManager = new ExpressionManager(reader); + } + + /// <summary> + /// Create a record of the given type using the current row. + /// </summary> + /// <typeparam name="T">The record type.</typeparam> + public T Create<T>() + { + try + { + return ((Func<T>)GetCreateRecordDelegate(typeof(T))).Invoke(); + } + catch (TargetInvocationException ex) + { + if (ex.InnerException != null) + { + throw ex.InnerException; + } + else + { + throw; + } + } + } + + /// <summary> + /// Create a record of the given type using the current row. + /// </summary> + /// <param name="recordType">The record type.</param> + public object? Create(Type recordType) + { + try + { + return GetCreateRecordDelegate(recordType).DynamicInvoke(); + } + catch (TargetInvocationException ex) + { + if (ex.InnerException != null) + { + throw ex.InnerException; + } + else + { + throw; + } + } + } + + /// <summary> + /// Gets the delegate to create a record for the given record type. + /// If the delegate doesn't exist, one will be created and cached. + /// </summary> + /// <param name="recordType">The record type.</param> + protected virtual Delegate GetCreateRecordDelegate(Type recordType) + { + if (!createRecordFuncs.TryGetValue(recordType, out Delegate func)) + { + createRecordFuncs[recordType] = func = CreateCreateRecordDelegate(recordType); + } + + return func; + } + + /// <summary> + /// Creates a <see cref="Delegate"/> of type <see cref="Func{T}"/> + /// that will create a record of the given type using the current + /// reader row. + /// </summary> + /// <param name="recordType">The record type.</param> + protected abstract Delegate CreateCreateRecordDelegate(Type recordType); + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/RecordCreatorFactory.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/RecordCreatorFactory.cs new file mode 100644 index 0000000..b785115 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/RecordCreatorFactory.cs @@ -0,0 +1,51 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Reflection; + +namespace CsvHelper.Expressions +{ + /// <summary> + /// Factory to create record creators. + /// </summary> + public class RecordCreatorFactory + { + private readonly CsvReader reader; + private readonly DynamicRecordCreator dynamicRecordCreator; + private readonly PrimitiveRecordCreator primitiveRecordCreator; + private readonly ObjectRecordCreator objectRecordCreator; + + /// <summary> + /// Initializes a new instance using the given reader. + /// </summary> + /// <param name="reader">The reader.</param> + public RecordCreatorFactory(CsvReader reader) + { + this.reader = reader; + dynamicRecordCreator = new DynamicRecordCreator(reader); + primitiveRecordCreator = new PrimitiveRecordCreator(reader); + objectRecordCreator = new ObjectRecordCreator(reader); + } + + /// <summary> + /// Creates a record creator for the given record type. + /// </summary> + /// <param name="recordType">The record type.</param> + public virtual RecordCreator MakeRecordCreator(Type recordType) + { + if (recordType == typeof(object)) + { + return dynamicRecordCreator; + } + + if (recordType.GetTypeInfo().IsPrimitive) + { + return primitiveRecordCreator; + } + + return objectRecordCreator; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/RecordHydrator.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/RecordHydrator.cs new file mode 100644 index 0000000..7de4ddb --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/RecordHydrator.cs @@ -0,0 +1,126 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Reflection; + +namespace CsvHelper.Expressions +{ + /// <summary> + /// Hydrates members of an existing record. + /// </summary> + public class RecordHydrator + { + private readonly CsvReader reader; + private readonly ExpressionManager expressionManager; + private readonly Dictionary<Type, Delegate> hydrateRecordActions = new Dictionary<Type, Delegate>(); + + /// <summary> + /// Creates a new instance using the given reader. + /// </summary> + /// <param name="reader">The reader.</param> + public RecordHydrator(CsvReader reader) + { + this.reader = reader; + expressionManager = ObjectResolver.Current.Resolve<ExpressionManager>(reader); + } + + /// <summary> + /// Hydrates members of the given record using the current reader row. + /// </summary> + /// <typeparam name="T">The record type.</typeparam> + /// <param name="record">The record.</param> + public void Hydrate<T>(T record) + { + try + { + GetHydrateRecordAction<T>()(record); + } + catch (TargetInvocationException ex) + { + if (ex.InnerException != null) + { + throw ex.InnerException; + } + else + { + throw; + } + } + } + + /// <summary> + /// Gets the action delegate used to hydrate a custom class object's members with data from the reader. + /// </summary> + /// <typeparam name="T">The record type.</typeparam> + protected virtual Action<T> GetHydrateRecordAction<T>() + { + var recordType = typeof(T); + + if (!hydrateRecordActions.TryGetValue(recordType, out Delegate action)) + { + hydrateRecordActions[recordType] = action = CreateHydrateRecordAction<T>(); + } + + return (Action<T>)action; + } + + /// <summary> + /// Creates the action delegate used to hydrate a record's members with data from the reader. + /// </summary> + /// <typeparam name="T">The record type.</typeparam> + protected virtual Action<T> CreateHydrateRecordAction<T>() + { + var recordType = typeof(T); + + if (reader.Context.Maps[recordType] == null) + { + reader.Context.Maps.Add(reader.Context.AutoMap(recordType)); + } + + var mapping = reader.Context.Maps[recordType]; + + var recordTypeParameter = Expression.Parameter(recordType, "record"); + var memberAssignments = new List<Expression>(); + + foreach (var memberMap in mapping.MemberMaps) + { + var fieldExpression = expressionManager.CreateGetFieldExpression(memberMap); + if (fieldExpression == null) + { + continue; + } + + var memberTypeParameter = Expression.Parameter(memberMap.Data.Member.MemberType(), "member"); + var memberAccess = Expression.MakeMemberAccess(recordTypeParameter, memberMap.Data.Member); + var memberAssignment = Expression.Assign(memberAccess, fieldExpression); + memberAssignments.Add(memberAssignment); + } + + foreach (var referenceMap in mapping.ReferenceMaps) + { + if (!reader.CanRead(referenceMap)) + { + continue; + } + + var referenceAssignments = new List<MemberAssignment>(); + expressionManager.CreateMemberAssignmentsForMapping(referenceMap.Data.Mapping, referenceAssignments); + + var referenceBody = expressionManager.CreateInstanceAndAssignMembers(referenceMap.Data.Member.MemberType(), referenceAssignments); + + var memberTypeParameter = Expression.Parameter(referenceMap.Data.Member.MemberType(), "referenceMember"); + var memberAccess = Expression.MakeMemberAccess(recordTypeParameter, referenceMap.Data.Member); + var memberAssignment = Expression.Assign(memberAccess, referenceBody); + memberAssignments.Add(memberAssignment); + } + + var body = Expression.Block(memberAssignments); + + return Expression.Lambda<Action<T>>(body, recordTypeParameter).Compile(); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/RecordManager.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/RecordManager.cs new file mode 100644 index 0000000..eef3d6e --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/RecordManager.cs @@ -0,0 +1,80 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.Expressions +{ + /// <summary> + /// Manages record manipulation. + /// </summary> + public class RecordManager + { + private readonly CsvReader reader; + private readonly RecordCreatorFactory recordCreatorFactory; + private readonly RecordHydrator recordHydrator; + private readonly RecordWriterFactory recordWriterFactory; + + /// <summary> + /// Initializes a new instance using the given reader. + /// </summary> + /// <param name="reader"></param> + public RecordManager(CsvReader reader) + { + this.reader = reader; + recordCreatorFactory = ObjectResolver.Current.Resolve<RecordCreatorFactory>(reader); + recordHydrator = ObjectResolver.Current.Resolve<RecordHydrator>(reader); + } + + /// <summary> + /// Initializes a new instance using the given writer. + /// </summary> + /// <param name="writer">The writer.</param> + public RecordManager(CsvWriter writer) + { + recordWriterFactory = ObjectResolver.Current.Resolve<RecordWriterFactory>(writer); + } + + /// <summary> + /// Creates a record of the given type using the current reader row. + /// </summary> + /// <typeparam name="T">The type of record to create.</typeparam> + public T Create<T>() + { + var recordCreator = recordCreatorFactory.MakeRecordCreator(typeof(T)); + return recordCreator.Create<T>(); + } + + /// <summary> + /// Creates a record of the given type using the current reader row. + /// </summary> + /// <param name="recordType">The type of record to create.</param> + public object? Create(Type recordType) + { + var recordCreator = recordCreatorFactory.MakeRecordCreator(recordType); + return recordCreator.Create(recordType); + } + + /// <summary> + /// Hydrates the given record using the current reader row. + /// </summary> + /// <typeparam name="T">The type of the record.</typeparam> + /// <param name="record">The record to hydrate.</param> + public void Hydrate<T>(T record) + { + recordHydrator.Hydrate(record); + } + + /// <summary> + /// Writes the given record to the current writer row. + /// </summary> + /// <typeparam name="T">The type of the record.</typeparam> + /// <param name="record">The record.</param> + public void Write<T>(T record) + { + var recordWriter = recordWriterFactory.MakeRecordWriter(record); + recordWriter.Write(record); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/RecordWriter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/RecordWriter.cs new file mode 100644 index 0000000..ca1194f --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/RecordWriter.cs @@ -0,0 +1,109 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace CsvHelper.Expressions +{ + /// <summary> + /// Base implementation for classes that write records. + /// </summary> + public abstract class RecordWriter + { + private readonly Dictionary<int, Delegate> typeActions = new Dictionary<int, Delegate>(); + + /// <summary> + /// Gets the writer. + /// </summary> + protected CsvWriter Writer { get; private set; } + + /// <summary> + /// The expression manager. + /// </summary> + protected ExpressionManager ExpressionManager { get; private set; } + + /// <summary> + /// Initializes a new instance using the given writer. + /// </summary> + /// <param name="writer">The writer.</param> + public RecordWriter(CsvWriter writer) + { + Writer = writer; + ExpressionManager = ObjectResolver.Current.Resolve<ExpressionManager>(writer); + } + + /// <summary> + /// Writes the record to the current row. + /// </summary> + /// <typeparam name="T">Type of the record.</typeparam> + /// <param name="record">The record.</param> + public void Write<T>(T record) + { + try + { + GetWriteDelegate(record)(record); + } + catch (TargetInvocationException ex) + { + if (ex.InnerException != null) + { + throw ex.InnerException; + } + else + { + throw; + } + } + } + + /// <summary> + /// Gets the delegate to write the given record. + /// If the delegate doesn't exist, one will be created and cached. + /// </summary> + /// <typeparam name="T">The record type.</typeparam> + /// <param name="record">The record.</param> + protected Action<T> GetWriteDelegate<T>(T record) + { + var type = typeof(T); + var typeKeyName = type.AssemblyQualifiedName; + if (type == typeof(object)) + { + type = record.GetType(); + typeKeyName += $"|{type.AssemblyQualifiedName}"; + } + + int typeKey = typeKeyName.GetHashCode(); + + if (!typeActions.TryGetValue(typeKey, out Delegate action)) + { + typeActions[typeKey] = action = CreateWriteDelegate(record); + } + + return (Action<T>)action; + } + + /// <summary> + /// Creates a <see cref="Delegate"/> of type <see cref="Action{T}"/> + /// that will write the given record using the current writer row. + /// </summary> + /// <typeparam name="T">The record type.</typeparam> + /// <param name="record">The record.</param> + protected abstract Action<T> CreateWriteDelegate<T>(T record); + + /// <summary> + /// Combines the delegates into a single multicast delegate. + /// This is needed because Silverlight doesn't have the + /// Delegate.Combine( params Delegate[] ) overload. + /// </summary> + /// <param name="delegates">The delegates to combine.</param> + /// <returns>A multicast delegate combined from the given delegates.</returns> + protected virtual Action<T> CombineDelegates<T>(IEnumerable<Action<T>> delegates) + { + return (Action<T>)delegates.Aggregate<Delegate, Delegate>(null, Delegate.Combine); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/RecordWriterFactory.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/RecordWriterFactory.cs new file mode 100644 index 0000000..4f27001 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Expressions/RecordWriterFactory.cs @@ -0,0 +1,61 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System.Dynamic; +using System.Reflection; + +namespace CsvHelper.Expressions +{ + /// <summary> + /// Factory to create record writers. + /// </summary> + public class RecordWriterFactory + { + private readonly CsvWriter writer; + private readonly ExpandoObjectRecordWriter expandoObjectRecordWriter; + private readonly DynamicRecordWriter dynamicRecordWriter; + private readonly PrimitiveRecordWriter primitiveRecordWriter; + private readonly ObjectRecordWriter objectRecordWriter; + + /// <summary> + /// Initializes a new instance using the given writer. + /// </summary> + /// <param name="writer">The writer.</param> + public RecordWriterFactory(CsvWriter writer) + { + this.writer = writer; + expandoObjectRecordWriter = new ExpandoObjectRecordWriter(writer); + dynamicRecordWriter = new DynamicRecordWriter(writer); + primitiveRecordWriter = new PrimitiveRecordWriter(writer); + objectRecordWriter = new ObjectRecordWriter(writer); + } + + /// <summary> + /// Creates a new record writer for the given record. + /// </summary> + /// <typeparam name="T">The type of the record.</typeparam> + /// <param name="record">The record.</param> + public virtual RecordWriter MakeRecordWriter<T>(T record) + { + var type = writer.GetTypeForRecord(record); + + if (record is ExpandoObject expandoObject) + { + return expandoObjectRecordWriter; + } + + if (record is IDynamicMetaObjectProvider dynamicObject) + { + return dynamicRecordWriter; + } + + if (type.GetTypeInfo().IsPrimitive) + { + return primitiveRecordWriter; + } + + return objectRecordWriter; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Factory.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Factory.cs new file mode 100644 index 0000000..80db167 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Factory.cs @@ -0,0 +1,108 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System.Globalization; +using System.IO; +using CsvHelper.Configuration; + +namespace CsvHelper +{ + /// <summary> + /// Creates CsvHelper classes. + /// </summary> + public class Factory : IFactory + { + /// <summary> + /// Creates an <see cref="IParser"/>. + /// </summary> + /// <param name="reader">The text reader to use for the csv parser.</param> + /// <param name="configuration">The configuration to use for the csv parser.</param> + /// <returns>The created parser.</returns> + public virtual IParser CreateParser(TextReader reader, Configuration.CsvConfiguration configuration) + { + return new CsvParser(reader, configuration); + } + + /// <summary> + /// Creates an <see cref="IParser" />. + /// </summary> + /// <param name="reader">The text reader to use for the csv parser.</param> + /// <param name="cultureInfo">The culture information.</param> + /// <returns> + /// The created parser. + /// </returns> + public virtual IParser CreateParser(TextReader reader, CultureInfo cultureInfo) + { + return new CsvParser(reader, cultureInfo); + } + + /// <summary> + /// Creates an <see cref="IReader"/>. + /// </summary> + /// <param name="reader">The text reader to use for the csv reader.</param> + /// <param name="configuration">The configuration to use for the reader.</param> + /// <returns>The created reader.</returns> + public virtual IReader CreateReader(TextReader reader, Configuration.CsvConfiguration configuration) + { + return new CsvReader(reader, configuration); + } + + /// <summary> + /// Creates an <see cref="IReader" />. + /// </summary> + /// <param name="reader">The text reader to use for the csv reader.</param> + /// <param name="cultureInfo">The culture information.</param> + /// <returns> + /// The created reader. + /// </returns> + public virtual IReader CreateReader(TextReader reader, CultureInfo cultureInfo) + { + return new CsvReader(reader, cultureInfo); + } + + /// <summary> + /// Creates an <see cref="IReader"/>. + /// </summary> + /// <param name="parser">The parser used to create the reader.</param> + /// <returns>The created reader.</returns> + public virtual IReader CreateReader(IParser parser) + { + return new CsvReader(parser); + } + + /// <summary> + /// Creates an <see cref="IWriter"/>. + /// </summary> + /// <param name="writer">The text writer to use for the csv writer.</param> + /// <param name="configuration">The configuration to use for the writer.</param> + /// <returns>The created writer.</returns> + public virtual IWriter CreateWriter(TextWriter writer, Configuration.CsvConfiguration configuration) + { + return new CsvWriter(writer, configuration); + } + + /// <summary> + /// Creates an <see cref="IWriter" />. + /// </summary> + /// <param name="writer">The text writer to use for the csv writer.</param> + /// <param name="cultureInfo">The culture information.</param> + /// <returns> + /// The created writer. + /// </returns> + public virtual IWriter CreateWriter(TextWriter writer, CultureInfo cultureInfo) + { + return new CsvWriter(writer, cultureInfo); + } + + /// <summary> + /// Access point for fluent interface to dynamically build a <see cref="ClassMap{T}"/> + /// </summary> + /// <typeparam name="T">Type you will be making a class map for</typeparam> + /// <returns>Options to further configure the <see cref="ClassMap{T}"/></returns> + public IHasMap<T> CreateClassMapBuilder<T>() + { + return new ClassMapBuilder<T>(); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/FieldCache.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/FieldCache.cs new file mode 100644 index 0000000..665a650 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/FieldCache.cs @@ -0,0 +1,137 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +// https://blog.markvincze.com/back-to-basics-dictionary-part-2-net-implementation/ + +namespace CsvHelper +{ + /// <summary> + /// Caches fields. + /// Based on C#'s <see cref="Dictionary{TKey, TValue}"/>. + /// </summary> + internal class FieldCache + { + private readonly int maxFieldSize; + private int size; + private int[] buckets; + private Entry[] entries; + private int count; + + public FieldCache(int initialSize = 128, int maxFieldSize = 128) + { + this.maxFieldSize = maxFieldSize; + size = initialSize; + buckets = new int[size]; + entries = new Entry[size]; + } + + public string GetField(char[] buffer, int start, int length) + { + if (length == 0) + { + return string.Empty; + } + + if (length > maxFieldSize) + { + return new string(buffer, start, length); + } + + var hashCode = GetHashCode(buffer, start, length); + ref var bucket = ref GetBucket(hashCode); + int i = bucket - 1; + while ((uint)i < (uint)entries.Length) + { + ref var entry = ref entries[i]; + + if (entry.HashCode == hashCode && entry.Value.AsSpan().SequenceEqual(new Span<char>(buffer, start, length))) + { + return entry.Value; + } + + i = entry.Next; + } + + if (count == entries.Length) + { + Resize(); + bucket = ref GetBucket(hashCode); + } + + ref var reference = ref entries[count]; + reference.HashCode = hashCode; + reference.Next = bucket - 1; + reference.Value = new string(buffer, start, length); + bucket = count + 1; + count++; + + return reference.Value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private uint GetHashCode(char[] buffer, int start, int length) + { + unchecked + { + uint hash = 17; + for (var i = start; i < start + length; i++) + { + hash = hash * 31 + buffer[i]; + } + + return hash; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private ref int GetBucket(uint hashCode) + { + return ref buckets[hashCode & buckets.Length - 1]; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void Resize() + { + size *= 2; + + var tempEntries = new Entry[size]; + + Array.Copy(entries, tempEntries, count); + + buckets = new int[size]; + + for (int i = 0; i < count; i++) + { + ref var tempEntry = ref tempEntries[i]; + + if (tempEntry.Next >= -1) + { + ref var bucket = ref GetBucket(tempEntry.HashCode); + tempEntry.Next = bucket - 1; + bucket = i + 1; + } + } + + entries = tempEntries; + } + + [DebuggerDisplay("HashCode = {HashCode}, Next = {Next}, Value = {Value}")] + private struct Entry + { + public uint HashCode; + + public int Next; + + public string Value; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/FieldValidationException.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/FieldValidationException.cs new file mode 100644 index 0000000..9f4eacd --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/FieldValidationException.cs @@ -0,0 +1,55 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper +{ + /// <summary> + /// Represents a user supplied field validation failure. + /// </summary> + public class FieldValidationException : ValidationException + { + /// <summary> + /// Gets the field that failed validation. + /// </summary> + public string Field { get; private set; } + + /// <summary> + /// Initializes a new instance of the <see cref="ValidationException"/> class. + /// </summary> + /// <param name="context">The reading context.</param> + /// <param name="field">The field that failed validation.</param> + public FieldValidationException(CsvContext context, string field) : base(context) + { + Field = field; + } + + /// <summary> + /// Initializes a new instance of the <see cref="ValidationException"/> class + /// with a specified error message. + /// </summary> + /// <param name="context">The reading context.</param> + /// <param name="field">The field that failed validation.</param> + /// <param name="message">The message that describes the error.</param> + public FieldValidationException(CsvContext context, string field, string message) : base(context, message) + { + Field = field; + } + + /// <summary> + /// Initializes a new instance of the <see cref="ValidationException"/> class + /// with a specified error message and a reference to the inner exception that + /// is the cause of this exception. + /// </summary> + /// <param name="context">The reading context.</param> + /// <param name="field">The field that failed validation.</param> + /// <param name="message">The error message that explains the reason for the exception.</param> + /// <param name="innerException">The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.</param> + public FieldValidationException(CsvContext context, string field, string message, Exception innerException) : base(context, message, innerException) + { + Field = field; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/HeaderValidationException.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/HeaderValidationException.cs new file mode 100644 index 0000000..ded47b8 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/HeaderValidationException.cs @@ -0,0 +1,55 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper +{ + /// <summary> + /// Represents a header validation failure. + /// </summary> + public class HeaderValidationException : ValidationException + { + /// <summary> + /// Gets the invalid headers. + /// </summary> + public InvalidHeader[] InvalidHeaders { get; private set; } + + /// <summary> + /// Initializes a new instance of the <see cref="ValidationException"/> class. + /// </summary> + /// <param name="context">The reading context.</param> + /// <param name="invalidHeaders">The invalid headers.</param> + public HeaderValidationException(CsvContext context, InvalidHeader[] invalidHeaders) : base(context) + { + InvalidHeaders = invalidHeaders; + } + + /// <summary> + /// Initializes a new instance of the <see cref="ValidationException"/> class + /// with a specified error message. + /// </summary> + /// <param name="context">The reading context.</param> + /// <param name="invalidHeaders">The invalid headers.</param> + /// <param name="message">The message that describes the error.</param> + public HeaderValidationException(CsvContext context, InvalidHeader[] invalidHeaders, string message) : base(context, message) + { + InvalidHeaders = invalidHeaders; + } + + /// <summary> + /// Initializes a new instance of the <see cref="ValidationException"/> class + /// with a specified error message and a reference to the inner exception that + /// is the cause of this exception. + /// </summary> + /// <param name="context">The reading context.</param> + /// <param name="invalidHeaders">The invalid headers.</param> + /// <param name="message">The error message that explains the reason for the exception.</param> + /// <param name="innerException">The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.</param> + public HeaderValidationException(CsvContext context, InvalidHeader[] invalidHeaders, string message, Exception innerException) : base(context, message, innerException) + { + InvalidHeaders = invalidHeaders; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/IFactory.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/IFactory.cs new file mode 100644 index 0000000..bf857b5 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/IFactory.cs @@ -0,0 +1,85 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System.Globalization; +using System.IO; +using CsvHelper.Configuration; + +namespace CsvHelper +{ + /// <summary> + /// Defines methods used to create + /// CsvHelper classes. + /// </summary> + public interface IFactory + { + /// <summary> + /// Creates an <see cref="IParser"/>. + /// </summary> + /// <param name="reader">The text reader to use for the csv parser.</param> + /// <param name="configuration">The configuration to use for the csv parser.</param> + /// <returns>The created parser.</returns> + IParser CreateParser(TextReader reader, Configuration.CsvConfiguration configuration); + + /// <summary> + /// Creates an <see cref="IParser" />. + /// </summary> + /// <param name="reader">The text reader to use for the csv parser.</param> + /// <param name="cultureInfo">The culture information.</param> + /// <returns> + /// The created parser. + /// </returns> + IParser CreateParser(TextReader reader, CultureInfo cultureInfo); + + /// <summary> + /// Creates an <see cref="IReader"/>. + /// </summary> + /// <param name="reader">The text reader to use for the csv reader.</param> + /// <param name="configuration">The configuration to use for the reader.</param> + /// <returns>The created reader.</returns> + IReader CreateReader(TextReader reader, Configuration.CsvConfiguration configuration); + + /// <summary> + /// Creates an <see cref="IReader" />. + /// </summary> + /// <param name="reader">The text reader to use for the csv reader.</param> + /// <param name="cultureInfo">The culture information.</param> + /// <returns> + /// The created reader. + /// </returns> + IReader CreateReader(TextReader reader, CultureInfo cultureInfo); + + /// <summary> + /// Creates an <see cref="IReader"/>. + /// </summary> + /// <param name="parser">The parser used to create the reader.</param> + /// <returns>The created reader.</returns> + IReader CreateReader(IParser parser); + + /// <summary> + /// Creates an <see cref="IWriter"/>. + /// </summary> + /// <param name="writer">The text writer to use for the csv writer.</param> + /// <param name="configuration">The configuration to use for the writer.</param> + /// <returns>The created writer.</returns> + IWriter CreateWriter(TextWriter writer, Configuration.CsvConfiguration configuration); + + /// <summary> + /// Creates an <see cref="IWriter" />. + /// </summary> + /// <param name="writer">The text writer to use for the csv writer.</param> + /// <param name="cultureInfo">The culture information.</param> + /// <returns> + /// The created writer. + /// </returns> + IWriter CreateWriter(TextWriter writer, CultureInfo cultureInfo); + + /// <summary> + /// Provides a fluent interface for dynamically creating <see cref="ClassMap{T}"/>s + /// </summary> + /// <typeparam name="T">Type of class to map</typeparam> + /// <returns>Next available options</returns> + IHasMap<T> CreateClassMapBuilder<T>(); + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/IObjectResolver.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/IObjectResolver.cs new file mode 100644 index 0000000..c419114 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/IObjectResolver.cs @@ -0,0 +1,57 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper +{ + /// <summary> + /// Defines the functionality of a class that creates objects + /// from a given type. + /// </summary> + public interface IObjectResolver + { + /// <summary> + /// A value indicating if the resolver's <see cref="CanResolve"/> + /// returns false that an object will still be created using + /// CsvHelper's object creation. True to fallback, otherwise false. + /// Default value is true. + /// </summary> + bool UseFallback { get; } + + /// <summary> + /// A value indicating if the resolver is able to resolve + /// the given type. True if the type can be resolved, + /// otherwise false. + /// </summary> + Func<Type, bool> CanResolve { get; } + + /// <summary> + /// The function that creates an object from a given type. + /// </summary> + Func<Type, object[], object> ResolveFunction { get; } + + /// <summary> + /// Creates an object from the given type using the <see cref="ResolveFunction"/> + /// function. If <see cref="CanResolve"/> is false, the object will be + /// created using CsvHelper's default object creation. If <see cref="UseFallback"/> + /// is false, an exception is thrown. + /// </summary> + /// <param name="type">The type to create an instance from. The created object + /// may not be the same type as the given type.</param> + /// <param name="constructorArgs">Constructor arguments used to create the type.</param> + object Resolve( Type type, params object[] constructorArgs ); + + /// <summary> + /// Creates an object from the given type using the <see cref="ResolveFunction"/> + /// function. If <see cref="CanResolve"/> is false, the object will be + /// created using CsvHelper's default object creation. If <see cref="UseFallback"/> + /// is false, an exception is thrown. + /// </summary> + /// <typeparam name="T">The type to create an instance from. The created object + /// may not be the same type as the given type.</typeparam> + /// <param name="constructorArgs">Constructor arguments used to create the type.</param> + T Resolve<T>( params object[] constructorArgs ); + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/IParser.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/IParser.cs new file mode 100644 index 0000000..040a701 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/IParser.cs @@ -0,0 +1,89 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using CsvHelper.Configuration; +using System.Threading.Tasks; + +namespace CsvHelper +{ + /// <summary> + /// Defines methods used the parse a CSV file. + /// </summary> + public interface IParser : IDisposable + { + /// <summary> + /// Gets the count of how many bytes have been read. + /// <see cref="IParserConfiguration.CountBytes"/> needs + /// to be enabled for this value to be populated. + /// </summary> + long ByteCount { get; } + + /// <summary> + /// Gets the count of how many characters have been read. + /// </summary> + long CharCount { get; } + + /// <summary> + /// Gets the number of fields for the current row. + /// </summary> + int Count { get; } + + /// <summary> + /// Gets the field at the specified index for the current row. + /// </summary> + /// <param name="index">The index.</param> + /// <returns>The field.</returns> + string this[int index] { get; } + + /// <summary> + /// Gets the record for the current row. Note: + /// It is much more efficient to only get the fields you need. If + /// you need all fields, then use this. + /// </summary> + string[]? Record { get; } + + /// <summary> + /// Gets the raw record for the current row. + /// </summary> + string RawRecord { get; } + + /// <summary> + /// Gets the CSV row the parser is currently on. + /// </summary> + int Row { get; } + + /// <summary> + /// Gets the raw row the parser is currently on. + /// </summary> + int RawRow { get; } + + /// <summary> + /// The delimiter the parser is using. + /// </summary> + string Delimiter { get; } + + /// <summary> + /// Gets the reading context. + /// </summary> + CsvContext Context { get; } + + /// <summary> + /// Gets the configuration. + /// </summary> + IParserConfiguration Configuration { get; } + + /// <summary> + /// Reads a record from the CSV file. + /// </summary> + /// <returns>True if there are more records to read, otherwise false.</returns> + bool Read(); + + /// <summary> + /// Reads a record from the CSV file asynchronously. + /// </summary> + /// <returns>True if there are more records to read, otherwise false.</returns> + Task<bool> ReadAsync(); + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/IReader.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/IReader.cs new file mode 100644 index 0000000..3eb598e --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/IReader.cs @@ -0,0 +1,126 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using System.Threading; + +namespace CsvHelper +{ + /// <summary> + /// Defines methods used to read parsed data + /// from a CSV file. + /// </summary> + public interface IReader : IReaderRow, IDisposable + { + /// <summary> + /// Reads the header record without reading the first row. + /// </summary> + /// <returns>True if there are more records, otherwise false.</returns> + bool ReadHeader(); + + /// <summary> + /// Advances the reader to the next record. This will not read headers. + /// You need to call <see cref="Read"/> then <see cref="ReadHeader"/> + /// for the headers to be read. + /// </summary> + /// <returns>True if there are more records, otherwise false.</returns> + bool Read(); + + /// <summary> + /// Advances the reader to the next record. This will not read headers. + /// You need to call <see cref="ReadAsync"/> then <see cref="ReadHeader"/> + /// for the headers to be read. + /// </summary> + /// <returns>True if there are more records, otherwise false.</returns> + Task<bool> ReadAsync(); + + /// <summary> + /// Gets all the records in the CSV file and + /// converts each to <see cref="Type"/> T. The Read method + /// should not be used when using this. + /// </summary> + /// <typeparam name="T">The <see cref="Type"/> of the record.</typeparam> + /// <returns>An <see cref="IEnumerable{T}" /> of records.</returns> + IEnumerable<T> GetRecords<T>(); + + /// <summary> + /// Gets all the records in the CSV file and converts + /// each to <see cref="System.Type"/> T. The read method + /// should not be used when using this. + /// </summary> + /// <typeparam name="T">The <see cref="System.Type"/> of the record.</typeparam> + /// <param name="anonymousTypeDefinition">The anonymous type definition to use for the records.</param> + /// <returns>An <see cref="IEnumerable{T}"/> of records.</returns> + IEnumerable<T> GetRecords<T>(T anonymousTypeDefinition); + + /// <summary> + /// Gets all the records in the CSV file and + /// converts each to <see cref="Type"/> T. The Read method + /// should not be used when using this. + /// </summary> + /// <param name="type">The <see cref="Type"/> of the record.</param> + /// <returns>An <see cref="IEnumerable{Object}" /> of records.</returns> + IEnumerable<object> GetRecords(Type type); + + /// <summary> + /// Enumerates the records hydrating the given record instance with row data. + /// The record instance is re-used and not cleared on each enumeration. + /// This only works for streaming rows. If any methods are called on the projection + /// that force the evaluation of the IEnumerable, such as ToList(), the entire list + /// will contain the same instance of the record, which is the last row. + /// </summary> + /// <typeparam name="T">The type of the record.</typeparam> + /// <param name="record">The record to fill each enumeration.</param> + /// <returns>An <see cref="IEnumerable{T}"/> of records.</returns> + IEnumerable<T> EnumerateRecords<T>(T record); + +#if !NET45 + /// <summary> + /// Gets all the records in the CSV file and + /// converts each to <see cref="Type"/> T. The Read method + /// should not be used when using this. + /// </summary> + /// <typeparam name="T">The <see cref="Type"/> of the record.</typeparam> + /// <param name="cancellationToken">The cancellation token to stop the writing.</param> + /// <returns>An <see cref="IAsyncEnumerable{T}" /> of records.</returns> + IAsyncEnumerable<T> GetRecordsAsync<T>(CancellationToken cancellationToken = default(CancellationToken)); + + /// <summary> + /// Gets all the records in the CSV file and converts + /// each to <see cref="System.Type"/> T. The read method + /// should not be used when using this. + /// </summary> + /// <typeparam name="T">The <see cref="System.Type"/> of the record.</typeparam> + /// <param name="anonymousTypeDefinition">The anonymous type definition to use for the records.</param> + /// <param name="cancellationToken">The cancellation token to stop the writing.</param> + /// <returns>An <see cref="IAsyncEnumerable{T}"/> of records.</returns> + IAsyncEnumerable<T> GetRecordsAsync<T>(T anonymousTypeDefinition, CancellationToken cancellationToken = default(CancellationToken)); + + /// <summary> + /// Gets all the records in the CSV file and + /// converts each to <see cref="Type"/> T. The Read method + /// should not be used when using this. + /// </summary> + /// <param name="type">The <see cref="Type"/> of the record.</param> + /// <param name="cancellationToken">The cancellation token to stop the writing.</param> + /// <returns>An <see cref="IAsyncEnumerable{Object}" /> of records.</returns> + IAsyncEnumerable<object> GetRecordsAsync(Type type, CancellationToken cancellationToken = default(CancellationToken)); + + /// <summary> + /// Enumerates the records hydrating the given record instance with row data. + /// The record instance is re-used and not cleared on each enumeration. + /// This only works for streaming rows. If any methods are called on the projection + /// that force the evaluation of the IEnumerable, such as ToList(), the entire list + /// will contain the same instance of the record, which is the last row. + /// </summary> + /// <typeparam name="T">The type of the record.</typeparam> + /// <param name="record">The record to fill each enumeration.</param> + /// /// <param name="cancellationToken">The cancellation token to stop the writing.</param> + /// <returns>An <see cref="IAsyncEnumerable{T}"/> of records.</returns> + IAsyncEnumerable<T> EnumerateRecordsAsync<T>(T record, CancellationToken cancellationToken = default(CancellationToken)); +#endif + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/IReaderRow.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/IReaderRow.cs new file mode 100644 index 0000000..0d75a53 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/IReaderRow.cs @@ -0,0 +1,428 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using CsvHelper.Configuration; +using CsvHelper.TypeConversion; + +namespace CsvHelper +{ + /// <summary> + /// Defines methods used to read parsed data + /// from a CSV file row. + /// </summary> + public interface IReaderRow + { + /// <summary> + /// Gets the column count of the current row. + /// This should match <see cref="IParser.Count"/>. + /// </summary> + int ColumnCount { get; } + + /// <summary> + /// Gets the field index the reader is currently on. + /// </summary> + int CurrentIndex { get; } + + /// <summary> + /// Gets the header record. + /// </summary> + string[]? HeaderRecord { get; } + + /// <summary> + /// Gets the parser. + /// </summary> + IParser Parser { get; } + + /// <summary> + /// Gets the reading context. + /// </summary> + CsvContext Context { get; } + + /// <summary> + /// Gets or sets the configuration. + /// </summary> + IReaderConfiguration Configuration { get; } + + /// <summary> + /// Gets the raw field at position (column) index. + /// </summary> + /// <param name="index">The zero based index of the field.</param> + /// <returns>The raw field.</returns> + string? this[int index] { get; } + + /// <summary> + /// Gets the raw field at position (column) name. + /// </summary> + /// <param name="name">The named index of the field.</param> + /// <returns>The raw field.</returns> + string? this[string name] { get; } + + /// <summary> + /// Gets the raw field at position (column) name. + /// </summary> + /// <param name="name">The named index of the field.</param> + /// <param name="index">The zero based index of the field.</param> + /// <returns>The raw field.</returns> + string? this[string name, int index] { get; } + + /// <summary> + /// Gets the raw field at position (column) index. + /// </summary> + /// <param name="index">The zero based index of the field.</param> + /// <returns>The raw field.</returns> + string? GetField(int index); + + /// <summary> + /// Gets the raw field at position (column) name. + /// </summary> + /// <param name="name">The named index of the field.</param> + /// <returns>The raw field.</returns> + string? GetField(string name); + + /// <summary> + /// Gets the raw field at position (column) name and the index + /// instance of that field. The index is used when there are + /// multiple columns with the same header name. + /// </summary> + /// <param name="name">The named index of the field.</param> + /// <param name="index">The zero based index of the instance of the field.</param> + /// <returns>The raw field.</returns> + string? GetField(string name, int index); + + /// <summary> + /// Gets the field converted to <see cref="Object"/> using + /// the specified <see cref="ITypeConverter"/>. + /// </summary> + /// <param name="type">The type of the field.</param> + /// <param name="index">The index of the field.</param> + /// <returns>The field converted to <see cref="Object"/>.</returns> + object? GetField(Type type, int index); + + /// <summary> + /// Gets the field converted to <see cref="Object"/> using + /// the specified <see cref="ITypeConverter"/>. + /// </summary> + /// <param name="type">The type of the field.</param> + /// <param name="name">The named index of the field.</param> + /// <returns>The field converted to <see cref="Object"/>.</returns> + object? GetField(Type type, string name); + + /// <summary> + /// Gets the field converted to <see cref="Object"/> using + /// the specified <see cref="ITypeConverter"/>. + /// </summary> + /// <param name="type">The type of the field.</param> + /// <param name="name">The named index of the field.</param> + /// <param name="index">The zero based index of the instance of the field.</param> + /// <returns>The field converted to <see cref="Object"/>.</returns> + object? GetField(Type type, string name, int index); + + /// <summary> + /// Gets the field converted to <see cref="Object"/> using + /// the specified <see cref="ITypeConverter"/>. + /// </summary> + /// <param name="type">The type of the field.</param> + /// <param name="index">The index of the field.</param> + /// <param name="converter">The <see cref="ITypeConverter"/> used to convert the field to <see cref="Object"/>.</param> + /// <returns>The field converted to <see cref="Object"/>.</returns> + object? GetField(Type type, int index, ITypeConverter converter); + + /// <summary> + /// Gets the field converted to <see cref="Object"/> using + /// the specified <see cref="ITypeConverter"/>. + /// </summary> + /// <param name="type">The type of the field.</param> + /// <param name="name">The named index of the field.</param> + /// <param name="converter">The <see cref="ITypeConverter"/> used to convert the field to <see cref="Object"/>.</param> + /// <returns>The field converted to <see cref="Object"/>.</returns> + object? GetField(Type type, string name, ITypeConverter converter); + + /// <summary> + /// Gets the field converted to <see cref="Object"/> using + /// the specified <see cref="ITypeConverter"/>. + /// </summary> + /// <param name="type">The type of the field.</param> + /// <param name="name">The named index of the field.</param> + /// <param name="index">The zero based index of the instance of the field.</param> + /// <param name="converter">The <see cref="ITypeConverter"/> used to convert the field to <see cref="Object"/>.</param> + /// <returns>The field converted to <see cref="Object"/>.</returns> + object? GetField(Type type, string name, int index, ITypeConverter converter); + + /// <summary> + /// Gets the field converted to <see cref="Type"/> T at position (column) index. + /// </summary> + /// <typeparam name="T">The <see cref="Type"/> of the field.</typeparam> + /// <param name="index">The zero based index of the field.</param> + /// <returns>The field converted to <see cref="Type"/> T.</returns> + T? GetField<T>(int index); + + /// <summary> + /// Gets the field converted to <see cref="Type"/> T at position (column) name. + /// </summary> + /// <typeparam name="T">The <see cref="Type"/> of the field.</typeparam> + /// <param name="name">The named index of the field.</param> + /// <returns>The field converted to <see cref="Type"/> T.</returns> + T? GetField<T>(string name); + + /// <summary> + /// Gets the field converted to <see cref="Type"/> T at position + /// (column) name and the index instance of that field. The index + /// is used when there are multiple columns with the same header name. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="name">The named index of the field.</param> + /// <param name="index">The zero based index of the instance of the field.</param> + /// <returns></returns> + T? GetField<T>(string name, int index); + + /// <summary> + /// Gets the field converted to <see cref="Type"/> T at position (column) index using + /// the given <see cref="ITypeConverter" />. + /// </summary> + /// <typeparam name="T">The <see cref="Type"/> of the field.</typeparam> + /// <param name="index">The zero based index of the field.</param> + /// <param name="converter">The <see cref="ITypeConverter"/> used to convert the field to <see cref="Type"/> T.</param> + /// <returns>The field converted to <see cref="Type"/> T.</returns> + T? GetField<T>(int index, ITypeConverter converter); + + /// <summary> + /// Gets the field converted to <see cref="Type"/> T at position (column) name using + /// the given <see cref="ITypeConverter" />. + /// </summary> + /// <typeparam name="T">The <see cref="Type"/> of the field.</typeparam> + /// <param name="name">The named index of the field.</param> + /// <param name="converter">The <see cref="ITypeConverter"/> used to convert the field to <see cref="Type"/> T.</param> + /// <returns>The field converted to <see cref="Type"/> T.</returns> + T? GetField<T>(string name, ITypeConverter converter); + + /// <summary> + /// Gets the field converted to <see cref="Type"/> T at position + /// (column) name and the index instance of that field. The index + /// is used when there are multiple columns with the same header name. + /// </summary> + /// <typeparam name="T">The <see cref="Type"/> of the field.</typeparam> + /// <param name="name">The named index of the field.</param> + /// <param name="index">The zero based index of the instance of the field.</param> + /// <param name="converter">The <see cref="ITypeConverter"/> used to convert the field to <see cref="Type"/> T.</param> + /// <returns>The field converted to <see cref="Type"/> T.</returns> + T? GetField<T>(string name, int index, ITypeConverter converter); + + /// <summary> + /// Gets the field converted to <see cref="Type"/> T at position (column) index using + /// the given <see cref="ITypeConverter" />. + /// </summary> + /// <typeparam name="T">The <see cref="Type"/> of the field.</typeparam> + /// <typeparam name="TConverter">The <see cref="ITypeConverter"/> used to convert the field to <see cref="Type"/> T.</typeparam> + /// <param name="index">The zero based index of the field.</param> + /// <returns>The field converted to <see cref="Type"/> T.</returns> + T? GetField<T, TConverter>(int index) where TConverter : ITypeConverter; + + /// <summary> + /// Gets the field converted to <see cref="Type"/> T at position (column) name using + /// the given <see cref="ITypeConverter" />. + /// </summary> + /// <typeparam name="T">The <see cref="Type"/> of the field.</typeparam> + /// <typeparam name="TConverter">The <see cref="ITypeConverter"/> used to convert the field to <see cref="Type"/> T.</typeparam> + /// <param name="name">The named index of the field.</param> + /// <returns>The field converted to <see cref="Type"/> T.</returns> + T? GetField<T, TConverter>(string name) where TConverter : ITypeConverter; + + /// <summary> + /// Gets the field converted to <see cref="Type"/> T at position + /// (column) name and the index instance of that field. The index + /// is used when there are multiple columns with the same header name. + /// </summary> + /// <typeparam name="T">The <see cref="Type"/> of the field.</typeparam> + /// <typeparam name="TConverter">The <see cref="ITypeConverter"/> used to convert the field to <see cref="Type"/> T.</typeparam> + /// <param name="name">The named index of the field.</param> + /// <param name="index">The zero based index of the instance of the field.</param> + /// <returns>The field converted to <see cref="Type"/> T.</returns> + T? GetField<T, TConverter>(string name, int index) where TConverter : ITypeConverter; + + /// <summary> + /// Gets the field converted to <see cref="System.Type"/> T at position (column) index. + /// </summary> + /// <param name="type">The <see cref="System.Type"/> of the field.</param> + /// <param name="index">The zero based index of the field.</param> + /// <param name="field">The field converted to type T.</param> + /// <returns>A value indicating if the get was successful.</returns> + bool TryGetField(Type type, int index, out object? field); + + /// <summary> + /// Gets the field converted to <see cref="System.Type"/> T at position (column) name. + /// </summary> + /// <param name="type">The <see cref="System.Type"/> of the field.</param> + /// <param name="name">The named index of the field.</param> + /// <param name="field">The field converted to <see cref="System.Type"/> T.</param> + /// <returns>A value indicating if the get was successful.</returns> + bool TryGetField(Type type, string name, out object? field); + + /// <summary> + /// Gets the field converted to <see cref="System.Type"/> T at position + /// (column) name and the index instance of that field. The index + /// is used when there are multiple columns with the same header name. + /// </summary> + /// <param name="type">The <see cref="System.Type"/> of the field.</param> + /// <param name="name">The named index of the field.</param> + /// <param name="index">The zero based index of the instance of the field.</param> + /// <param name="field">The field converted to <see cref="System.Type"/> T.</param> + /// <returns>A value indicating if the get was successful.</returns> + bool TryGetField(Type type, string name, int index, out object? field); + + /// <summary> + /// Gets the field converted to <see cref="System.Type"/> T at position (column) index + /// using the specified <see cref="ITypeConverter" />. + /// </summary> + /// <param name="type">The <see cref="System.Type"/> of the field.</param> + /// <param name="index">The zero based index of the field.</param> + /// <param name="converter">The <see cref="ITypeConverter"/> used to convert the field to <see cref="System.Type"/> T.</param> + /// <param name="field">The field converted to <see cref="System.Type"/> T.</param> + /// <returns>A value indicating if the get was successful.</returns> + bool TryGetField(Type type, int index, ITypeConverter converter, out object? field); + + /// <summary> + /// Gets the field converted to <see cref="System.Type"/> T at position (column) name + /// using the specified <see cref="ITypeConverter"/>. + /// </summary> + /// <param name="type">The <see cref="System.Type"/> of the field.</param> + /// <param name="name">The named index of the field.</param> + /// <param name="converter">The <see cref="ITypeConverter"/> used to convert the field to <see cref="System.Type"/> T.</param> + /// <param name="field">The field converted to <see cref="System.Type"/> T.</param> + /// <returns>A value indicating if the get was successful.</returns> + bool TryGetField(Type type, string name, ITypeConverter converter, out object? field); + + /// <summary> + /// Gets the field converted to <see cref="System.Type"/> T at position (column) name + /// using the specified <see cref="ITypeConverter"/>. + /// </summary> + /// <param name="type">The <see cref="System.Type"/> of the field.</param> + /// <param name="name">The named index of the field.</param> + /// <param name="index">The zero based index of the instance of the field.</param> + /// <param name="converter">The <see cref="ITypeConverter"/> used to convert the field to <see cref="System.Type"/> T.</param> + /// <param name="field">The field converted to <see cref="System.Type"/> T.</param> + /// <returns>A value indicating if the get was successful.</returns> + bool TryGetField(Type type, string name, int index, ITypeConverter converter, out object? field); + + /// <summary> + /// Gets the field converted to <see cref="Type"/> T at position (column) index. + /// </summary> + /// <typeparam name="T">The <see cref="Type"/> of the field.</typeparam> + /// <param name="index">The zero based index of the field.</param> + /// <param name="field">The field converted to type T.</param> + /// <returns>A value indicating if the get was successful.</returns> + bool TryGetField<T>(int index, out T? field); + + /// <summary> + /// Gets the field converted to <see cref="Type"/> T at position (column) name. + /// </summary> + /// <typeparam name="T">The <see cref="Type"/> of the field.</typeparam> + /// <param name="name">The named index of the field.</param> + /// <param name="field">The field converted to <see cref="Type"/> T.</param> + /// <returns>A value indicating if the get was successful.</returns> + bool TryGetField<T>(string name, out T? field); + + /// <summary> + /// Gets the field converted to <see cref="Type"/> T at position + /// (column) name and the index instance of that field. The index + /// is used when there are multiple columns with the same header name. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="name">The named index of the field.</param> + /// <param name="index">The zero based index of the instance of the field.</param> + /// <param name="field">The field converted to <see cref="Type"/> T.</param> + /// <returns>A value indicating if the get was successful.</returns> + bool TryGetField<T>(string name, int index, out T? field); + + /// <summary> + /// Gets the field converted to <see cref="Type"/> T at position (column) index + /// using the specified <see cref="ITypeConverter" />. + /// </summary> + /// <typeparam name="T">The <see cref="Type"/> of the field.</typeparam> + /// <param name="index">The zero based index of the field.</param> + /// <param name="converter">The <see cref="ITypeConverter"/> used to convert the field to <see cref="Type"/> T.</param> + /// <param name="field">The field converted to <see cref="Type"/> T.</param> + /// <returns>A value indicating if the get was successful.</returns> + bool TryGetField<T>(int index, ITypeConverter converter, out T? field); + + /// <summary> + /// Gets the field converted to <see cref="Type"/> T at position (column) name + /// using the specified <see cref="ITypeConverter"/>. + /// </summary> + /// <typeparam name="T">The <see cref="Type"/> of the field.</typeparam> + /// <param name="name">The named index of the field.</param> + /// <param name="converter">The <see cref="ITypeConverter"/> used to convert the field to <see cref="Type"/> T.</param> + /// <param name="field">The field converted to <see cref="Type"/> T.</param> + /// <returns>A value indicating if the get was successful.</returns> + bool TryGetField<T>(string name, ITypeConverter converter, out T? field); + + /// <summary> + /// Gets the field converted to <see cref="Type"/> T at position (column) name + /// using the specified <see cref="ITypeConverter"/>. + /// </summary> + /// <typeparam name="T">The <see cref="Type"/> of the field.</typeparam> + /// <param name="name">The named index of the field.</param> + /// <param name="index">The zero based index of the instance of the field.</param> + /// <param name="converter">The <see cref="ITypeConverter"/> used to convert the field to <see cref="Type"/> T.</param> + /// <param name="field">The field converted to <see cref="Type"/> T.</param> + /// <returns>A value indicating if the get was successful.</returns> + bool TryGetField<T>(string name, int index, ITypeConverter converter, out T? field); + + /// <summary> + /// Gets the field converted to <see cref="Type"/> T at position (column) index + /// using the specified <see cref="ITypeConverter" />. + /// </summary> + /// <typeparam name="T">The <see cref="Type"/> of the field.</typeparam> + /// <typeparam name="TConverter">The <see cref="ITypeConverter"/> used to convert the field to <see cref="Type"/> T.</typeparam> + /// <param name="index">The zero based index of the field.</param> + /// <param name="field">The field converted to <see cref="Type"/> T.</param> + /// <returns>A value indicating if the get was successful.</returns> + bool TryGetField<T, TConverter>(int index, out T? field) where TConverter : ITypeConverter; + + /// <summary> + /// Gets the field converted to <see cref="Type"/> T at position (column) name + /// using the specified <see cref="ITypeConverter"/>. + /// </summary> + /// <typeparam name="T">The <see cref="Type"/> of the field.</typeparam> + /// <typeparam name="TConverter">The <see cref="ITypeConverter"/> used to convert the field to <see cref="Type"/> T.</typeparam> + /// <param name="name">The named index of the field.</param> + /// <param name="field">The field converted to <see cref="Type"/> T.</param> + /// <returns>A value indicating if the get was successful.</returns> + bool TryGetField<T, TConverter>(string name, out T? field) where TConverter : ITypeConverter; + + /// <summary> + /// Gets the field converted to <see cref="Type"/> T at position (column) name + /// using the specified <see cref="ITypeConverter"/>. + /// </summary> + /// <typeparam name="T">The <see cref="Type"/> of the field.</typeparam> + /// <typeparam name="TConverter">The <see cref="ITypeConverter"/> used to convert the field to <see cref="Type"/> T.</typeparam> + /// <param name="name">The named index of the field.</param> + /// <param name="index">The zero based index of the instance of the field.</param> + /// <param name="field">The field converted to <see cref="Type"/> T.</param> + /// <returns>A value indicating if the get was successful.</returns> + bool TryGetField<T, TConverter>(string name, int index, out T? field) where TConverter : ITypeConverter; + + /// <summary> + /// Gets the record converted into <see cref="Type"/> T. + /// </summary> + /// <typeparam name="T">The <see cref="Type"/> of the record.</typeparam> + /// <returns>The record converted to <see cref="Type"/> T.</returns> + T? GetRecord<T>(); + + /// <summary> + /// Get the record converted into <see cref="System.Type"/> T. + /// </summary> + /// <typeparam name="T">The <see cref="System.Type"/> of the record.</typeparam> + /// <param name="anonymousTypeDefinition">The anonymous type definition to use for the record.</param> + /// <returns>The record converted to <see cref="System.Type"/> T.</returns> + T? GetRecord<T>(T anonymousTypeDefinition); + + /// <summary> + /// Gets the record. + /// </summary> + /// <param name="type">The <see cref="Type"/> of the record.</param> + /// <returns>The record.</returns> + object? GetRecord(Type type); + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/IWriter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/IWriter.cs new file mode 100644 index 0000000..f181b0d --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/IWriter.cs @@ -0,0 +1,86 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections; +using System.IO; +using System.Threading.Tasks; +using System.Collections.Generic; +using System.Threading; + +namespace CsvHelper +{ + /// <summary> + /// Defines methods used to write to a CSV file. + /// </summary> + public interface IWriter : IWriterRow, IDisposable +#if !NET45 && !NET47 && !NETSTANDARD2_0 + , IAsyncDisposable +#endif + { + /// <summary> + /// Flushes the internal buffer to the <see cref="TextWriter"/> then + /// flushes the <see cref="TextWriter"/>. + /// </summary> + void Flush(); + + /// <summary> + /// Flushes the internal buffer to the <see cref="TextWriter"/> then + /// flushes the <see cref="TextWriter"/>. + /// </summary> + Task FlushAsync(); + + /// <summary> + /// Ends writing of the current record and starts a new record. + /// This flushes the buffer to the <see cref="TextWriter"/> but + /// does not flush the <see cref="TextWriter"/>. + /// </summary> + void NextRecord(); + + /// <summary> + /// Ends writing of the current record and starts a new record. + /// This flushes the buffer to the <see cref="TextWriter"/> but + /// does not flush the <see cref="TextWriter"/>. + /// </summary> + Task NextRecordAsync(); + + /// <summary> + /// Writes the list of records to the CSV file. + /// </summary> + /// <param name="records">The records to write.</param> + void WriteRecords(IEnumerable records); + + /// <summary> + /// Writes the list of records to the CSV file. + /// </summary> + /// <typeparam name="T">Record type.</typeparam> + /// <param name="records">The records to write.</param> + void WriteRecords<T>(IEnumerable<T> records); + + /// <summary> + /// Writes the list of records to the CSV file. + /// </summary> + /// <param name="records">The records to write.</param> + /// <param name="cancellationToken">The cancellation token to stop the writing.</param> + Task WriteRecordsAsync(IEnumerable records, CancellationToken cancellationToken = default); + + /// <summary> + /// Writes the list of records to the CSV file. + /// </summary> + /// <typeparam name="T">Record type.</typeparam> + /// <param name="records">The records to write.</param> + /// <param name="cancellationToken">The cancellation token to stop the writing.</param> + Task WriteRecordsAsync<T>(IEnumerable<T> records, CancellationToken cancellationToken = default); + +#if !NET45 + /// <summary> + /// Writes the list of records to the CSV file. + /// </summary> + /// <typeparam name="T">Record type.</typeparam> + /// <param name="records">The records to write.</param> + /// <param name="cancellationToken">The cancellation token to stop the writing.</param> + Task WriteRecordsAsync<T>(IAsyncEnumerable<T> records, CancellationToken cancellationToken = default); +#endif + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/IWriterRow.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/IWriterRow.cs new file mode 100644 index 0000000..3b773b1 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/IWriterRow.cs @@ -0,0 +1,135 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using CsvHelper.Configuration; +using CsvHelper.TypeConversion; + +namespace CsvHelper +{ + /// <summary> + /// Defines methods used to write a CSV row. + /// </summary> + public interface IWriterRow + { + /// <summary> + /// The header record. + /// </summary> + string[] HeaderRecord { get; } + + /// <summary> + /// The current row. + /// </summary> + int Row { get; } + + /// <summary> + /// The current field index. + /// </summary> + int Index { get; } + + /// <summary> + /// Gets the writing context. + /// </summary> + CsvContext Context { get; } + + /// <summary> + /// Gets or sets the configuration. + /// </summary> + IWriterConfiguration Configuration { get; } + + /// <summary> + /// Writes a field that has already been converted to a + /// <see cref="string"/> from an <see cref="ITypeConverter"/>. + /// If the field is null, it won't get written. A type converter + /// will always return a string, even if field is null. If the + /// converter returns a null, it means that the converter has already + /// written data, and the returned value should not be written. + /// </summary> + /// <param name="field">The converted field to write.</param> + /// <param name="fieldType">The type of the field before it was converted into a string.</param> + void WriteConvertedField(string field, Type fieldType); + + /// <summary> + /// Writes the field to the CSV file. The field + /// may get quotes added to it. + /// When all fields are written for a record, + /// <see cref="IWriter.NextRecord()" /> must be called + /// to complete writing of the current record. + /// </summary> + /// <param name="field">The field to write.</param> + void WriteField(string field); + + /// <summary> + /// Writes the field to the CSV file. This will + /// ignore any need to quote and ignore + /// <see cref="CsvHelper.Configuration.CsvConfiguration.ShouldQuote"/> + /// and just quote based on the shouldQuote + /// parameter. + /// When all fields are written for a record, + /// <see cref="IWriter.NextRecord()" /> must be called + /// to complete writing of the current record. + /// </summary> + /// <param name="field">The field to write.</param> + /// <param name="shouldQuote">True to quote the field, otherwise false.</param> + void WriteField(string field, bool shouldQuote); + + /// <summary> + /// Writes the field to the CSV file. + /// When all fields are written for a record, + /// <see cref="IWriter.NextRecord()" /> must be called + /// to complete writing of the current record. + /// </summary> + /// <typeparam name="T">The type of the field.</typeparam> + /// <param name="field">The field to write.</param> + void WriteField<T>(T field); + + /// <summary> + /// Writes the field to the CSV file. + /// When all fields are written for a record, + /// <see cref="IWriter.NextRecord" /> must be called + /// to complete writing of the current record. + /// </summary> + /// <typeparam name="T">The type of the field.</typeparam> + /// <param name="field">The field to write.</param> + /// <param name="converter">The converter used to convert the field into a string.</param> + void WriteField<T>(T field, ITypeConverter converter); + + /// <summary> + /// Writes the field to the CSV file + /// using the given <see cref="ITypeConverter"/>. + /// When all fields are written for a record, + /// <see cref="IWriter.NextRecord()" /> must be called + /// to complete writing of the current record. + /// </summary> + /// <typeparam name="T">The type of the field.</typeparam> + /// <typeparam name="TConverter">The type of the converter.</typeparam> + /// <param name="field">The field to write.</param> + void WriteField<T, TConverter>(T field); + + /// <summary> + /// Writes a comment. + /// </summary> + /// <param name="comment">The comment to write.</param> + void WriteComment(string comment); + + /// <summary> + /// Writes the header record from the given members. + /// </summary> + /// <typeparam name="T">The type of the record.</typeparam> + void WriteHeader<T>(); + + /// <summary> + /// Writes the header record from the given members. + /// </summary> + /// <param name="type">The type of the record.</param> + void WriteHeader(Type type); + + /// <summary> + /// Writes the record to the CSV file. + /// </summary> + /// <typeparam name="T">The type of the record.</typeparam> + /// <param name="record">The record to write.</param> + void WriteRecord<T>(T record); + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Icon.png b/ThirdParty/CsvHelper-master/src/CsvHelper/Icon.png Binary files differnew file mode 100644 index 0000000..e8c5d82 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Icon.png diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/InvalidHeader.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/InvalidHeader.cs new file mode 100644 index 0000000..0383623 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/InvalidHeader.cs @@ -0,0 +1,28 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CsvHelper +{ + /// <summary> + /// Invalid header information. + /// </summary> + public class InvalidHeader + { + /// <summary> + /// Header names mapped to a CSV field that couldn't be found. + /// </summary> + public List<string> Names { get; set; } = new List<string>(); + + /// <summary> + /// Header name index maped to a CSV field that couldn't be found. + /// </summary> + public int Index { get; set; } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/LinkedListExtensions.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/LinkedListExtensions.cs new file mode 100644 index 0000000..ffe6fdd --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/LinkedListExtensions.cs @@ -0,0 +1,29 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System.Collections.Generic; + +namespace CsvHelper +{ + internal static class LinkedListExtensions + { + public static void Drop<T>(this LinkedList<T> list, LinkedListNode<T>? node) + { + if (list.Count == 0) + { + return; + } + + while (list.Count > 0) + { + var nodeToRemove = list.Last; + list.RemoveLast(); + if (nodeToRemove == node) + { + break; + } + } + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/MaxFieldSizeException.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/MaxFieldSizeException.cs new file mode 100644 index 0000000..fd3bc21 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/MaxFieldSizeException.cs @@ -0,0 +1,39 @@ +// Copyright 2009-2019 Josh Close and Contributors +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper +{ + /// <summary> + /// Represents an error due to a field that is too large. + /// </summary> + [Serializable] + public class MaxFieldSizeException : CsvHelperException + { + /// <summary> + /// Initializes a new instance of the <see cref="MaxFieldSizeException"/> class. + /// </summary> + /// <param name="context">The reading context.</param> + public MaxFieldSizeException(CsvContext context) : base(context) { } + + /// <summary> + /// Initializes a new instance of the <see cref="MaxFieldSizeException"/> class + /// with a specified error message. + /// </summary> + /// <param name="context">The reading context.</param> + /// <param name="message">The message that describes the error.</param> + public MaxFieldSizeException(CsvContext context, string message) : base(context, message) { } + + /// <summary> + /// Initializes a new instance of the <see cref="MaxFieldSizeException"/> class + /// with a specified error message and a reference to the inner exception that + /// is the cause of this exception. + /// </summary> + /// <param name="context">The reading context.</param> + /// <param name="message">The error message that explains the reason for the exception.</param> + /// <param name="innerException">The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.</param> + public MaxFieldSizeException(CsvContext context, string message, Exception innerException) : base(context, message, innerException) { } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/MissingFieldException.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/MissingFieldException.cs new file mode 100644 index 0000000..2b93dd4 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/MissingFieldException.cs @@ -0,0 +1,40 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper +{ + /// <summary> + /// Represents an error caused because a field is missing + /// in the header while reading a CSV file. + /// </summary> + [Serializable] + public class MissingFieldException : ReaderException + { + /// <summary> + /// Initializes a new instance of the <see cref="MissingFieldException"/> class. + /// </summary> + /// <param name="context">The reading context.</param> + public MissingFieldException(CsvContext context) : base(context) { } + + /// <summary> + /// Initializes a new instance of the <see cref="MissingFieldException"/> class + /// with a specified error message. + /// </summary> + /// <param name="context">The reading context.</param> + /// <param name="message">The message that describes the error.</param> + public MissingFieldException(CsvContext context, string message) : base(context, message) { } + + /// <summary> + /// Initializes a new instance of the <see cref="MissingFieldException"/> class + /// with a specified error message and a reference to the inner exception that + /// is the cause of this exception. + /// </summary> + /// <param name="context">The reading context.</param> + /// <param name="message">The error message that explains the reason for the exception.</param> + /// <param name="innerException">The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.</param> + public MissingFieldException(CsvContext context, string message, Exception innerException) : base(context, message, innerException) { } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/ObjectCreator.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/ObjectCreator.cs new file mode 100644 index 0000000..4e1789e --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/ObjectCreator.cs @@ -0,0 +1,218 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace CsvHelper +{ + /// <summary> + /// Efficiently creates instances of object types. + /// </summary> + public class ObjectCreator + { + private readonly Dictionary<int, Func<object[], object>> cache = new Dictionary<int, Func<object[], object>>(); + + /// <summary> + /// Creates an instance of type T using the given arguments. + /// </summary> + /// <typeparam name="T">The type to create an instance of.</typeparam> + /// <param name="args">The constrcutor arguments.</param> + public T CreateInstance<T>(params object[] args) + { + return (T)CreateInstance(typeof(T), args); + } + + /// <summary> + /// Creates an instance of the given type using the given arguments. + /// </summary> + /// <param name="type">The type to create an instance of.</param> + /// <param name="args">The constructor arguments.</param> + public object CreateInstance(Type type, params object[] args) + { + var func = GetFunc(type, args); + + return func(args); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private Func<object[], object> GetFunc(Type type, object[] args) + { + var argTypes = GetArgTypes(args); + var key = GetConstructorCacheKey(type, argTypes); + if (!cache.TryGetValue(key, out var func)) + { + cache[key] = func = CreateInstanceFunc(type, argTypes); + } + + return func; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Type[] GetArgTypes(object[] args) + { + var argTypes = new Type[args.Length]; + for (var i = 0; i < args.Length; i++) + { + argTypes[i] = args[i]?.GetType() ?? typeof(object); + } + + return argTypes; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int GetConstructorCacheKey(Type type, Type[] args) + { +#if !NET45 + var hashCode = new HashCode(); + hashCode.Add(type.GetHashCode()); + for (var i = 0; i < args.Length; i++) + { + hashCode.Add(args[i].GetHashCode()); + } + + return hashCode.ToHashCode(); +#else + unchecked + { + var hash = 17; + hash = hash * 31 + type.GetHashCode(); + for (var i = 0; i < args.Length; i++) + { + hash = hash * 31 + (args[i].GetHashCode()); + } + + return hash; + } +#endif + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Func<object[], object> CreateInstanceFunc(Type type, Type[] argTypes) + { + var parameterExpression = Expression.Parameter(typeof(object[]), "args"); + + Expression body; + if (type.IsValueType) + { + if (argTypes.Length > 0) + { + throw GetConstructorNotFoundException(type, argTypes); + } + + body = Expression.Convert(Expression.Default(type), typeof(object)); + } + else + { + var constructors = type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + var constructor = GetConstructor(constructors, type, argTypes); + + var parameters = constructor.GetParameters(); + var parameterTypes = new Type[parameters.Length]; + for (var i = 0; i < parameters.Length; i++) + { + parameterTypes[i] = parameters[i].ParameterType; + } + + var arguments = new List<Expression>(); + for (var i = 0; i < parameterTypes.Length; i++) + { + var parameterType = parameterTypes[i]; + var arrayIndexExpression = Expression.ArrayIndex(parameterExpression, Expression.Constant(i)); + var convertExpression = Expression.Convert(arrayIndexExpression, parameterType); + arguments.Add(convertExpression); + } + + body = Expression.New(constructor, arguments); + } + + var lambda = Expression.Lambda<Func<object[], object>>(body, new[] { parameterExpression }); + var func = lambda.Compile(); + + return func; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ConstructorInfo GetConstructor(ConstructorInfo[] constructors, Type type, Type[] argTypes) + { + var matchType = MatchType.Exact; + var fuzzyMatches = new List<ConstructorInfo>(); + for (var i = 0; i < constructors.Length; i++) + { + var constructor = constructors[i]; + var parameters = constructors[i].GetParameters(); + + if (parameters.Length != argTypes.Length) + { + continue; + } + + for (var j = 0; j < parameters.Length && j < argTypes.Length; j++) + { + var parameterType = parameters[j].ParameterType; + var argType = argTypes[j]; + + if (argType == parameterType) + { + matchType = MatchType.Exact; + continue; + } + + if (!parameterType.IsValueType && (parameterType.IsAssignableFrom(argType) || argType == typeof(object))) + { + matchType = MatchType.Fuzzy; + continue; + } + + matchType = MatchType.None; + break; + } + + if (matchType == MatchType.Exact) + { + // Only possible to have one exact match. + return constructor; + } + + if (matchType == MatchType.Fuzzy) + { + fuzzyMatches.Add(constructor); + } + } + + if (fuzzyMatches.Count == 1) + { + return fuzzyMatches[0]; + } + + if (fuzzyMatches.Count > 1) + { + throw new AmbiguousMatchException(); + } + + throw GetConstructorNotFoundException(type, argTypes); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static MissingMethodException GetConstructorNotFoundException(Type type, Type[] argTypes) + { + var signature = $"{type.FullName}({string.Join(", ", argTypes.Select(a => a.FullName))})"; + + throw new MissingMethodException($"Constructor '{signature}' was not found."); + } + + private enum MatchType + { + None = 0, + Exact = 1, + Fuzzy = 2 + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/ObjectResolver.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/ObjectResolver.cs new file mode 100644 index 0000000..99a17e0 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/ObjectResolver.cs @@ -0,0 +1,143 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper +{ + /// <summary> + /// Creates objects from a given type. + /// </summary> + public class ObjectResolver : IObjectResolver + { + private static IObjectResolver current; + private readonly ObjectCreator objectCreator = new ObjectCreator(); + + /// <summary> + /// Gets or sets the current resolver. + /// Use an instance of this instead if at all possible. + /// </summary> + public static IObjectResolver Current + { + get + { + return current; + } + set + { + if (value == null) + { + throw new InvalidOperationException($"{nameof(IObjectResolver)} cannot be null."); + } + + current = value; + } + } + + /// <summary> + /// A value indicating if the resolver's <see cref="CanResolve"/> + /// returns false that an object will still be created using + /// CsvHelper's object creation. True to fallback, otherwise false. + /// Default value is true. + /// </summary> + public bool UseFallback { get; private set; } + + /// <summary> + /// A function that returns a value indicating if the resolver + /// is able to resolve the given type. True if the type can be + /// resolved, otherwise false. + /// </summary> + public Func<Type, bool> CanResolve { get; private set; } + + /// <summary> + /// The function that creates an object from a given type. + /// </summary> + public Func<Type, object[], object> ResolveFunction { get; private set; } + + static ObjectResolver() + { + var objectCreator = new ObjectCreator(); + var locker = new object(); + current = new ObjectResolver(type => true, (type, args) => + { + lock (locker) + { + return objectCreator.CreateInstance(type, args); + } + }); + } + + /// <summary> + /// Creates an instance of the object resolver using default values. + /// </summary> + public ObjectResolver() + { + CanResolve = type => true; + ResolveFunction = ResolveWithObjectCreator; + UseFallback = true; + } + + /// <summary> + /// Creates an instance of the object resolver using the given can create function + /// and create function. + /// </summary> + /// <param name="canResolve">A function that returns a value indicating if the resolver + /// is able to resolve the given type. True if the type can be + /// resolved, otherwise false.</param> + /// <param name="resolveFunction">The function that creates an object from a given type.</param> + /// <param name="useFallback">A value indicating if the resolver's <see cref="CanResolve"/> + /// returns false that an object will still be created using + /// CsvHelper's object creation. True to fallback, otherwise false. + /// Default value is true.</param> + public ObjectResolver(Func<Type, bool> canResolve, Func<Type, object[], object> resolveFunction, bool useFallback = true) + { + CanResolve = canResolve ?? throw new ArgumentNullException(nameof(canResolve)); + ResolveFunction = resolveFunction ?? throw new ArgumentNullException(nameof(resolveFunction)); + UseFallback = useFallback; + } + + /// <summary> + /// Creates an object from the given type using the <see cref="ResolveFunction"/> + /// function. If <see cref="CanResolve"/> is false, the object will be + /// created using CsvHelper's default object creation. If <see cref="UseFallback"/> + /// is false, an exception is thrown. + /// </summary> + /// <param name="type">The type to create an instance from. The created object + /// may not be the same type as the given type.</param> + /// <param name="constructorArgs">Constructor arguments used to create the type.</param> + public object Resolve(Type type, params object[] constructorArgs) + { + if (CanResolve(type)) + { + return ResolveFunction(type, constructorArgs); + } + + if (UseFallback) + { + return objectCreator.CreateInstance(type, constructorArgs); + } + + throw new CsvHelperException($"Type '{type.FullName}' can't be resolved and fallback is turned off."); + } + + /// <summary> + /// Creates an object from the given type using the <see cref="ResolveFunction"/> + /// function. If <see cref="CanResolve"/> is false, the object will be + /// created using CsvHelper's default object creation. If <see cref="UseFallback"/> + /// is false, an exception is thrown. + /// </summary> + /// <typeparam name="T">The type to create an instance from. The created object + /// may not be the same type as the given type.</typeparam> + /// <param name="constructorArgs">Constructor arguments used to create the type.</param> + public T Resolve<T>(params object[] constructorArgs) + { + return (T)Resolve(typeof(T), constructorArgs); + } + + private object ResolveWithObjectCreator(Type type, params object[] args) + { + return objectCreator.CreateInstance(type, args); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/ParserException.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/ParserException.cs new file mode 100644 index 0000000..a7c57e2 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/ParserException.cs @@ -0,0 +1,39 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper +{ + /// <summary> + /// Represents errors that occur while parsing a CSV file. + /// </summary> + [Serializable] + public class ParserException : CsvHelperException + { + /// <summary> + /// Initializes a new instance of the <see cref="ParserException"/> class. + /// </summary> + /// <param name="context">The reading context.</param> + public ParserException(CsvContext context) : base(context) { } + + /// <summary> + /// Initializes a new instance of the <see cref="ParserException"/> class + /// with a specified error message. + /// </summary> + /// <param name="context">The reading context.</param> + /// <param name="message">The message that describes the error.</param> + public ParserException(CsvContext context, string message) : base(context, message) { } + + /// <summary> + /// Initializes a new instance of the <see cref="ParserException"/> class + /// with a specified error message and a reference to the inner exception that + /// is the cause of this exception. + /// </summary> + /// <param name="context">The reading context.</param> + /// <param name="message">The error message that explains the reason for the exception.</param> + /// <param name="innerException">The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.</param> + public ParserException(CsvContext context, string message, Exception innerException) : base(context, message, innerException) { } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/Properties/AssemblyInfo.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..95c1366 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/Properties/AssemblyInfo.cs @@ -0,0 +1,13 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Runtime.CompilerServices; + +[assembly: CLSCompliant(true)] +#if NCRUNCH +[assembly: InternalsVisibleTo("CsvHelper.Tests")] +#else +[assembly: InternalsVisibleTo("CsvHelper.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001000db97564beef98ad18a76ba31f769fab92b14341c9c37ed12f8004bb2a1a7fe42ad829b0e285915a816f05a32325c5e0ba83bd69d8f4d26a0785ccf446749842ad038f7325601a99c59a323dfa7ecf210139159da0aad1822b5d9c9be6d914ecbaa8b8c908c4af798a89b8777010971d81975079a49662ced398c742ff186a94")] +#endif diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/ReaderException.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/ReaderException.cs new file mode 100644 index 0000000..94e2421 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/ReaderException.cs @@ -0,0 +1,39 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper +{ + /// <summary> + /// Represents errors that occur while reading a CSV file. + /// </summary> + [Serializable] + public class ReaderException : CsvHelperException + { + /// <summary> + /// Initializes a new instance of the <see cref="ReaderException"/> class. + /// </summary> + /// <param name="context">The reading context.</param> + public ReaderException(CsvContext context) : base(context) { } + + /// <summary> + /// Initializes a new instance of the <see cref="ReaderException"/> class + /// with a specified error message. + /// </summary> + /// <param name="context">The reading context.</param> + /// <param name="message">The message that describes the error.</param> + public ReaderException(CsvContext context, string message) : base(context, message) { } + + /// <summary> + /// Initializes a new instance of the <see cref="ReaderException"/> class + /// with a specified error message and a reference to the inner exception that + /// is the cause of this exception. + /// </summary> + /// <param name="context">The reading context.</param> + /// <param name="message">The error message that explains the reason for the exception.</param> + /// <param name="innerException">The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.</param> + public ReaderException(CsvContext context, string message, Exception innerException) : base(context, message, innerException) { } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/ReflectionExtensions.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/ReflectionExtensions.cs new file mode 100644 index 0000000..e67c0b8 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/ReflectionExtensions.cs @@ -0,0 +1,155 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Reflection; +using System.Linq.Expressions; +using System.Runtime.CompilerServices; +using System.Linq; + +namespace CsvHelper +{ + /// <summary> + /// Extensions to help with reflection. + /// </summary> + public static class ReflectionExtensions + { + /// <summary> + /// Gets the type from the member. + /// </summary> + /// <param name="member">The member to get the type from.</param> + /// <returns>The type.</returns> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Type MemberType(this MemberInfo member) + { + var property = member as PropertyInfo; + if (property != null) + { + return property.PropertyType; + } + + var field = member as FieldInfo; + if (field != null) + { + return field.FieldType; + } + + throw new InvalidOperationException("Member is not a property or a field."); + } + + /// <summary> + /// Gets a member expression for the member. + /// </summary> + /// <param name="member">The member to get the expression for.</param> + /// <param name="expression">The member expression.</param> + /// <returns>The member expression.</returns> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static MemberExpression GetMemberExpression(this MemberInfo member, Expression expression) + { + var property = member as PropertyInfo; + if (property != null) + { + return Expression.Property(expression, property); + } + + var field = member as FieldInfo; + if (field != null) + { + return Expression.Field(expression, field); + } + + throw new InvalidOperationException("Member is not a property or a field."); + } + + /// <summary> + /// Gets a value indicating if the given type is anonymous. + /// True for anonymous, otherwise false. + /// </summary> + /// <param name="type">The type.</param> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsAnonymous(this Type type) + { + if (type == null) + { + throw new ArgumentNullException(nameof(type)); + } + + // https://stackoverflow.com/a/2483054/68499 + var isAnonymous = Attribute.IsDefined(type, typeof(CompilerGeneratedAttribute), false) + && type.IsGenericType + && type.Name.Contains("AnonymousType") + && (type.Name.StartsWith("<>") || type.Name.StartsWith("VB$")) + && (type.Attributes & TypeAttributes.Public) != TypeAttributes.Public; + + return isAnonymous; + } + + /// <summary> + /// Gets a value indicating if the given type has a parameterless constructor. + /// True if it has a parameterless constructor, otherwise false. + /// </summary> + /// <param name="type">The type.</param> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool HasParameterlessConstructor(this Type type) + { + return type.GetConstructor(new Type[0]) != null; + } + + /// <summary> + /// Gets a value indicating if the given type has any constructors. + /// </summary> + /// <param name="type">The type.</param> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool HasConstructor(this Type type) + { + return type.GetConstructors().Length > 0; + } + + /// <summary> + /// Gets the constructor that contains the most parameters. + /// </summary> + /// <param name="type">The type.</param> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ConstructorInfo GetConstructorWithMostParameters(this Type type) + { + return type.GetConstructors() + .OrderByDescending(c => c.GetParameters().Length) + .First(); + } + + /// <summary> + /// Gets a value indicating if the type is a user defined struct. + /// True if it is a user defined struct, otherwise false. + /// </summary> + /// <param name="type">The type.</param> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsUserDefinedStruct(this Type type) + { + return type.IsValueType && !type.IsPrimitive && !type.IsEnum; + } + + /// <summary> + /// Gets a string representation of the constructor. + /// </summary> + /// <param name="constructor">The constructor.</param> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string GetDefinition(this ConstructorInfo constructor) + { + var parameters = constructor.GetParameters(); + var definition = $"{constructor.Name}({string.Join(", ", parameters.Select(p => p.GetDefinition()))})"; + + return definition; + } + + /// <summary> + /// Gets a string representation of the parameter. + /// </summary> + /// <param name="parameter">The parameter.</param> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string GetDefinition(this ParameterInfo parameter) + { + return $"{parameter.ParameterType.Name} {parameter.Name}"; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/ReflectionHelper.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/ReflectionHelper.cs new file mode 100644 index 0000000..b026186 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/ReflectionHelper.cs @@ -0,0 +1,204 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Runtime.CompilerServices; +using CsvHelper.Configuration; +using CsvHelper.Configuration.Attributes; + +namespace CsvHelper +{ + /// <summary> + /// Common reflection tasks. + /// </summary> + internal static class ReflectionHelper + { + /// <summary> + /// Gets the <see cref="PropertyInfo"/> from the type where the property was declared. + /// </summary> + /// <param name="type">The type the property belongs to.</param> + /// <param name="property">The property to search.</param> + /// <param name="flags">Flags for how the property is retrieved.</param> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PropertyInfo GetDeclaringProperty(Type type, PropertyInfo property, BindingFlags flags) + { + if (property.DeclaringType != type) + { + var declaringProperty = property.DeclaringType.GetProperty(property.Name, flags); + return GetDeclaringProperty(property.DeclaringType, declaringProperty, flags); + } + + return property; + } + + /// <summary> + /// Gets the <see cref="FieldInfo"/> from the type where the field was declared. + /// </summary> + /// <param name="type">The type the field belongs to.</param> + /// <param name="field">The field to search.</param> + /// <param name="flags">Flags for how the field is retrieved.</param> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static FieldInfo GetDeclaringField(Type type, FieldInfo field, BindingFlags flags) + { + if (field.DeclaringType != type) + { + var declaringField = field.DeclaringType.GetField(field.Name, flags); + return GetDeclaringField(field.DeclaringType, declaringField, flags); + } + + return field; + } + + /// <summary> + /// Walk up the inheritance tree collecting properties. This will get a unique set of properties in the + /// case where parents have the same property names as children. + /// </summary> + /// <param name="type">The <see cref="Type"/> to get properties for.</param> + /// <param name="flags">The flags for getting the properties.</param> + /// <param name="overwrite">If true, parent class properties that are hidden by `new` child properties will be overwritten.</param> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static List<PropertyInfo> GetUniqueProperties(Type type, BindingFlags flags, bool overwrite = false) + { + var ignoreBase = type.GetCustomAttribute(typeof(IgnoreBaseAttribute)) != null; + + var properties = new Dictionary<string, PropertyInfo>(); + + flags |= BindingFlags.DeclaredOnly; + var currentType = type; + while (currentType != null) + { + var currentProperties = currentType.GetProperties(flags); + foreach (var property in currentProperties) + { + if (!properties.ContainsKey(property.Name) || overwrite) + { + properties[property.Name] = property; + } + } + + if (ignoreBase) + { + break; + } + + currentType = currentType.BaseType; + } + + return properties.Values.ToList(); + } + + /// <summary> + /// Walk up the inheritance tree collecting fields. This will get a unique set of fields in the + /// case where parents have the same field names as children. + /// </summary> + /// <param name="type">The <see cref="Type"/> to get fields for.</param> + /// <param name="flags">The flags for getting the fields.</param> + /// <param name="overwrite">If true, parent class fields that are hidden by `new` child fields will be overwritten.</param> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static List<FieldInfo> GetUniqueFields(Type type, BindingFlags flags, bool overwrite = false) + { + var ignoreBase = type.GetCustomAttribute(typeof(IgnoreBaseAttribute)) != null; + + var fields = new Dictionary<string, FieldInfo>(); + + flags |= BindingFlags.DeclaredOnly; + var currentType = type; + while (currentType != null) + { + var currentFields = currentType.GetFields(flags); + foreach (var field in currentFields) + { + if (!fields.ContainsKey(field.Name) || overwrite) + { + fields[field.Name] = field; + } + } + + if (ignoreBase) + { + break; + } + + currentType = currentType.BaseType; + } + + return fields.Values.ToList(); + } + + /// <summary> + /// Gets the property from the expression. + /// </summary> + /// <typeparam name="TModel">The type of the model.</typeparam> + /// <typeparam name="TProperty">The type of the property.</typeparam> + /// <param name="expression">The expression.</param> + /// <returns>The <see cref="PropertyInfo"/> for the expression.</returns> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static MemberInfo GetMember<TModel, TProperty>(Expression<Func<TModel, TProperty>> expression) + { + var member = GetMemberExpression(expression.Body).Member; + var property = member as PropertyInfo; + if (property != null) + { + return property; + } + + var field = member as FieldInfo; + if (field != null) + { + return field; + } + + throw new ConfigurationException($"'{member.Name}' is not a member."); + } + + /// <summary> + /// Gets the member inheritance chain as a stack. + /// </summary> + /// <typeparam name="TModel">The type of the model.</typeparam> + /// <typeparam name="TProperty">The type of the property.</typeparam> + /// <param name="expression">The member expression.</param> + /// <returns>The inheritance chain for the given member expression as a stack.</returns> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Stack<MemberInfo> GetMembers<TModel, TProperty>(Expression<Func<TModel, TProperty>> expression) + { + var stack = new Stack<MemberInfo>(); + + var currentExpression = expression.Body; + while (true) + { + var memberExpression = GetMemberExpression(currentExpression); + if (memberExpression == null) + { + break; + } + + stack.Push(memberExpression.Member); + currentExpression = memberExpression.Expression; + } + + return stack; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static MemberExpression? GetMemberExpression(Expression expression) + { + MemberExpression? memberExpression = null; + if (expression.NodeType == ExpressionType.Convert) + { + var body = (UnaryExpression)expression; + memberExpression = body.Operand as MemberExpression; + } + else if (expression.NodeType == ExpressionType.MemberAccess) + { + memberExpression = expression as MemberExpression; + } + + return memberExpression; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/ArrayConverter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/ArrayConverter.cs new file mode 100644 index 0000000..fb30ae1 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/ArrayConverter.cs @@ -0,0 +1,73 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Linq; +using CsvHelper.Configuration; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Converts an <see cref="Array"/> to and from a <see cref="string"/>. + /// </summary> + public class ArrayConverter : IEnumerableConverter + { + /// <summary> + /// Converts the string to an object. + /// </summary> + /// <param name="text">The string to convert to an object.</param> + /// <param name="row">The <see cref="IReaderRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being created.</param> + /// <returns>The object created from the string.</returns> + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + Array array; + var type = memberMapData.Member.MemberType().GetElementType(); + var converter = row.Context.TypeConverterCache.GetConverter(type); + + if (memberMapData.IsNameSet || row.Configuration.HasHeaderRecord && !memberMapData.IsIndexSet) + { + // Use the name. + var list = new List<object>(); + var nameIndex = 0; + while (true) + { + if (!row.TryGetField(type, memberMapData.Names.FirstOrDefault(), nameIndex, out var field)) + { + break; + } + + list.Add(field); + nameIndex++; + } + + array = (Array)ObjectResolver.Current.Resolve(memberMapData.Member.MemberType(), list.Count); + for (var i = 0; i < list.Count; i++) + { + array.SetValue(list[i], i); + } + } + else + { + // Use the index. + var indexEnd = memberMapData.IndexEnd < memberMapData.Index + ? row.Parser.Count - 1 + : memberMapData.IndexEnd; + + var arraySize = indexEnd - memberMapData.Index + 1; + array = (Array)ObjectResolver.Current.Resolve(memberMapData.Member.MemberType(), arraySize); + var arrayIndex = 0; + for (var i = memberMapData.Index; i <= indexEnd; i++) + { + var field = converter.ConvertFromString(row.GetField(i), row, memberMapData); + array.SetValue(field, arrayIndex); + arrayIndex++; + } + } + + return array; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/BigIntegerConverter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/BigIntegerConverter.cs new file mode 100644 index 0000000..efc06c9 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/BigIntegerConverter.cs @@ -0,0 +1,57 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using CsvHelper.Configuration; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Converts a <see cref="BigInteger"/> to and from a <see cref="string"/>. + /// </summary> + public class BigIntegerConverter : DefaultTypeConverter + { + /// <summary> + /// Converts the object to a string. + /// </summary> + /// <param name="value">The object to convert to a string.</param> + /// <param name="row">The <see cref="IWriterRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being written.</param> + /// <returns>The string representation of the object.</returns> + public override string? ConvertToString(object? value, IWriterRow row, MemberMapData memberMapData) + { + if (value is BigInteger bi && memberMapData.TypeConverterOptions.Formats?.FirstOrDefault() == null) + { + return bi.ToString("R", memberMapData.TypeConverterOptions.CultureInfo); + } + + return base.ConvertToString(value, row, memberMapData); + } + + /// <summary> + /// Converts the string to an object. + /// </summary> + /// <param name="text">The string to convert to an object.</param> + /// <param name="row">The <see cref="IReaderRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being created.</param> + /// <returns>The object created from the string.</returns> + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + var numberStyle = memberMapData.TypeConverterOptions.NumberStyles ?? NumberStyles.Integer; + + if (BigInteger.TryParse(text, numberStyle, memberMapData.TypeConverterOptions.CultureInfo, out var bi)) + { + return bi; + } + + return base.ConvertFromString(text, row, memberMapData); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/BooleanConverter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/BooleanConverter.cs new file mode 100644 index 0000000..6ab2a9c --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/BooleanConverter.cs @@ -0,0 +1,72 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System.Globalization; +using System.Linq; +using CsvHelper.Configuration; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Converts a <see cref="bool"/> to and from a <see cref="string"/>. + /// </summary> + public class BooleanConverter : DefaultTypeConverter + { + /// <inheritdoc/> + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + if (bool.TryParse(text, out var b)) + { + return b; + } + + if (short.TryParse(text, out var sh)) + { + if (sh == 0) + { + return false; + } + if (sh == 1) + { + return true; + } + } + + var t = (text ?? string.Empty).Trim(); + foreach (var trueValue in memberMapData.TypeConverterOptions.BooleanTrueValues) + { + if (memberMapData.TypeConverterOptions.CultureInfo.CompareInfo.Compare(trueValue, t, CompareOptions.IgnoreCase) == 0) + { + return true; + } + } + + foreach (var falseValue in memberMapData.TypeConverterOptions.BooleanFalseValues) + { + if (memberMapData.TypeConverterOptions.CultureInfo.CompareInfo.Compare(falseValue, t, CompareOptions.IgnoreCase) == 0) + { + return false; + } + } + + return base.ConvertFromString(text, row, memberMapData); + } + + /// <inheritdoc/> + public override string? ConvertToString(object? value, IWriterRow row, MemberMapData memberMapData) + { + var b = value as bool?; + if (b == true && memberMapData.TypeConverterOptions.BooleanTrueValues.Count > 0) + { + return memberMapData.TypeConverterOptions.BooleanTrueValues.First(); + } + else if (b == false && memberMapData.TypeConverterOptions.BooleanFalseValues.Count > 0) + { + return memberMapData.TypeConverterOptions.BooleanFalseValues.First(); + } + + return base.ConvertToString(value, row, memberMapData); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/ByteArrayConverter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/ByteArrayConverter.cs new file mode 100644 index 0000000..1f6c382 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/ByteArrayConverter.cs @@ -0,0 +1,126 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Text; +using CsvHelper.Configuration; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Converts a <see cref="T:Byte[]"/> to and from a <see cref="string"/>. + /// </summary> + public class ByteArrayConverter : DefaultTypeConverter + { + private readonly ByteArrayConverterOptions options; + private readonly string HexStringPrefix; + private readonly byte ByteLength; + + /// <summary> + /// Creates a new ByteArrayConverter using the given <see cref="ByteArrayConverterOptions"/>. + /// </summary> + /// <param name="options">The options.</param> + public ByteArrayConverter(ByteArrayConverterOptions options = ByteArrayConverterOptions.Hexadecimal | ByteArrayConverterOptions.HexInclude0x) + { + // Defaults to the literal format used by C# for whole numbers, and SQL Server for binary data. + this.options = options; + ValidateOptions(); + + HexStringPrefix = (options & ByteArrayConverterOptions.HexDashes) == ByteArrayConverterOptions.HexDashes ? "-" : string.Empty; + ByteLength = (options & ByteArrayConverterOptions.HexDashes) == ByteArrayConverterOptions.HexDashes ? (byte)3 : (byte)2; + } + + /// <summary> + /// Converts the object to a string. + /// </summary> + /// <param name="value">The object to convert to a string.</param> + /// <param name="row">The <see cref="IWriterRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being written.</param> + /// <returns>The string representation of the object.</returns> + public override string? ConvertToString(object? value, IWriterRow row, MemberMapData memberMapData) + { + if (value is byte[] byteArray) + { + return (options & ByteArrayConverterOptions.Base64) == ByteArrayConverterOptions.Base64 + ? Convert.ToBase64String(byteArray) + : ByteArrayToHexString(byteArray); + } + + return base.ConvertToString(value, row, memberMapData); + } + + /// <summary> + /// Converts the string to an object. + /// </summary> + /// <param name="text">The string to convert to an object.</param> + /// <param name="row">The <see cref="IReaderRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being created.</param> + /// <returns>The object created from the string.</returns> + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + if (text != null) + { + return (options & ByteArrayConverterOptions.Base64) == ByteArrayConverterOptions.Base64 + ? Convert.FromBase64String(text) + : HexStringToByteArray(text); + } + + return base.ConvertFromString(text, row, memberMapData); + } + + private string ByteArrayToHexString(byte[] byteArray) + { + var hexString = new StringBuilder(); + + if ((options & ByteArrayConverterOptions.HexInclude0x) == ByteArrayConverterOptions.HexInclude0x) + { + hexString.Append("0x"); + } + + if (byteArray.Length >= 1) + { + hexString.Append(byteArray[0].ToString("X2")); + } + + for (var i = 1; i < byteArray.Length; i++) + { + hexString.Append(HexStringPrefix + byteArray[i].ToString("X2")); + } + + return hexString.ToString(); + } + + private byte[] HexStringToByteArray(string hex) + { + var has0x = hex.StartsWith("0x"); + + var length = has0x + ? (hex.Length - 1) / ByteLength + : hex.Length + 1 / ByteLength; + var byteArray = new byte[length]; + var has0xOffset = has0x ? 1 : 0; + + for (var stringIndex = has0xOffset * 2; stringIndex < hex.Length; stringIndex += ByteLength) + { + byteArray[(stringIndex - has0xOffset) / ByteLength] = Convert.ToByte(hex.Substring(stringIndex, 2), 16); + } + + return byteArray; + } + + private void ValidateOptions() + { + if ((options & ByteArrayConverterOptions.Base64) == ByteArrayConverterOptions.Base64) + { + if ((options & (ByteArrayConverterOptions.HexInclude0x | ByteArrayConverterOptions.HexDashes | ByteArrayConverterOptions.Hexadecimal)) != ByteArrayConverterOptions.None) + { + throw new ConfigurationException($"{nameof(ByteArrayConverter)} must be configured exclusively with HexDecimal options, or exclusively with Base64 options. Was {options.ToString()}") + { + Data = { { "options", options } } + }; + } + } + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/ByteArrayConverterOptions.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/ByteArrayConverterOptions.cs new file mode 100644 index 0000000..2ce9d7c --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/ByteArrayConverterOptions.cs @@ -0,0 +1,44 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Options for converting byte arrays. + /// </summary> + [Flags] + public enum ByteArrayConverterOptions + { + /// <summary> + /// No options. + /// </summary> + None = 0, + + // TypeOptions + + /// <summary> + /// Hexadecimal encoding. + /// </summary> + Hexadecimal = 1, + + /// <summary> + /// Base64 encoding. + /// </summary> + Base64 = 2, + + // HexFormattingOptions + + /// <summary> + /// Use dashes in between hex values. + /// </summary> + HexDashes = 4, + + /// <summary> + /// Prefix hex number with 0x. + /// </summary> + HexInclude0x = 8, + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/ByteConverter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/ByteConverter.cs new file mode 100644 index 0000000..7583bd7 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/ByteConverter.cs @@ -0,0 +1,34 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System.Globalization; +using CsvHelper.Configuration; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Converts a <see cref="byte"/> to and from a <see cref="string"/>. + /// </summary> + public class ByteConverter : DefaultTypeConverter + { + /// <summary> + /// Converts the string to an object. + /// </summary> + /// <param name="text">The string to convert to an object.</param> + /// <param name="row">The <see cref="IReaderRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being created.</param> + /// <returns>The object created from the string.</returns> + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + var numberStyle = memberMapData.TypeConverterOptions.NumberStyles ?? NumberStyles.Integer; + + if (byte.TryParse(text, numberStyle, memberMapData.TypeConverterOptions.CultureInfo, out var b)) + { + return b; + } + + return base.ConvertFromString(text, row, memberMapData); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/CharConverter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/CharConverter.cs new file mode 100644 index 0000000..fa3d487 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/CharConverter.cs @@ -0,0 +1,36 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using CsvHelper.Configuration; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Converts a <see cref="char"/> to and from a <see cref="string"/>. + /// </summary> + public class CharConverter : DefaultTypeConverter + { + /// <summary> + /// Converts the string to an object. + /// </summary> + /// <param name="text">The string to convert to an object.</param> + /// <param name="row">The <see cref="IReaderRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being created.</param> + /// <returns>The object created from the string.</returns> + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + if (text != null && text.Length > 1) + { + text = text.Trim(); + } + + if (char.TryParse(text, out var c)) + { + return c; + } + + return base.ConvertFromString(text, row, memberMapData); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/CollectionConverterFactory.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/CollectionConverterFactory.cs new file mode 100644 index 0000000..0fb8c90 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/CollectionConverterFactory.cs @@ -0,0 +1,175 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace CsvHelper.TypeConversion +{ + /// <inheritdoc /> + public class CollectionConverterFactory : ITypeConverterFactory + { + private int dictionaryTypeHashCode = typeof(IDictionary).GetHashCode(); + private List<int> enumerableTypeHashCodes = new List<int> + { + typeof(IList).GetHashCode(), + typeof(ICollection).GetHashCode(), + typeof(IEnumerable).GetHashCode(), + }; + + /// <inheritdoc /> + public bool CanCreate(Type type) + { + switch (type) + { + case IList: + case IDictionary: + case ICollection: + case IEnumerable: + return true; + } + + if (type.IsArray) + { + // ArrayConverter + return true; + } + + if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>)) + { + // IDictionaryGenericConverter + return true; + } + + if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(IDictionary<,>)) + { + // IDictionaryGenericConverter + return true; + } + + if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)) + { + // CollectionGenericConverter + return true; + } + + if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(Collection<>)) + { + // CollectionGenericConverter + return true; + } + + if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(IList<>)) + { + // IEnumerableGenericConverter + return true; + } + + if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(ICollection<>)) + { + // IEnumerableGenericConverter + return true; + } + + if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>)) + { + // IEnumerableGenericConverter + return true; + } + + // A specific IEnumerable converter doesn't exist. + if (typeof(IEnumerable).IsAssignableFrom(type)) + { + // EnumerableConverter + return true; + } + + return false; + } + + /// <inheritdoc /> + public bool Create(Type type, TypeConverterCache cache, out ITypeConverter typeConverter) + { + var typeHashCode = type.GetHashCode(); + + if (typeHashCode == dictionaryTypeHashCode) + { + typeConverter = new IDictionaryConverter(); + return true; + } + + if (enumerableTypeHashCodes.Contains(typeHashCode)) + { + typeConverter = new IEnumerableConverter(); + return true; + } + + if (type.IsArray) + { + typeConverter = new ArrayConverter(); + return true; + } + + var isGenericType = type.GetTypeInfo().IsGenericType; + var genericTypeDefinition = type.GetGenericTypeDefinition(); + + if (isGenericType && genericTypeDefinition == typeof(Dictionary<,>)) + { + typeConverter = new IDictionaryGenericConverter(); + return true; + } + + if (isGenericType && genericTypeDefinition == typeof(IDictionary<,>)) + { + typeConverter = new IDictionaryGenericConverter(); + return true; + } + + if (isGenericType && genericTypeDefinition == typeof(List<>)) + { + typeConverter = new CollectionGenericConverter(); + return true; + } + + if (isGenericType && genericTypeDefinition == typeof(Collection<>)) + { + typeConverter = new CollectionGenericConverter(); + return true; + } + + if (isGenericType && genericTypeDefinition == typeof(IList<>)) + { + typeConverter = new IEnumerableGenericConverter(); + return true; + } + + if (isGenericType && genericTypeDefinition == typeof(ICollection<>)) + { + typeConverter = new IEnumerableGenericConverter(); + return true; + } + + if (isGenericType && genericTypeDefinition == typeof(IEnumerable<>)) + { + typeConverter = new IEnumerableGenericConverter(); + return true; + } + + // A specific IEnumerable converter doesn't exist. + if (typeof(IEnumerable).IsAssignableFrom(type)) + { + typeConverter = new EnumerableConverter(); + return true; + } + + throw new InvalidOperationException($"Cannot create collection converter for type '{type.FullName}'."); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/CollectionGenericConverter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/CollectionGenericConverter.cs new file mode 100644 index 0000000..9026f6a --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/CollectionGenericConverter.cs @@ -0,0 +1,64 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System.Collections; +using System.Collections.ObjectModel; +using System.Linq; +using CsvHelper.Configuration; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Converts a <see cref="Collection{T}"/> to and from a <see cref="string"/>. + /// </summary> + public class CollectionGenericConverter : IEnumerableConverter + { + /// <summary> + /// Converts the string to an object. + /// </summary> + /// <param name="text">The string to convert to an object.</param> + /// <param name="row">The <see cref="IReaderRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being created.</param> + /// <returns>The object created from the string.</returns> + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + // Since we're using the MemberType here, this converter can be used for multiple types + // as long as they implement IList. + var list = (IList)ObjectResolver.Current.Resolve(memberMapData.Member.MemberType()); + var type = memberMapData.Member.MemberType().GetGenericArguments()[0]; + var converter = row.Context.TypeConverterCache.GetConverter(type); + + if (memberMapData.IsNameSet || row.Configuration.HasHeaderRecord && !memberMapData.IsIndexSet) + { + // Use the name. + var nameIndex = 0; + while (true) + { + if (!row.TryGetField(type, memberMapData.Names.FirstOrDefault(), nameIndex, out var field)) + { + break; + } + + list.Add(field); + nameIndex++; + } + } + else + { + // Use the index. + var indexEnd = memberMapData.IndexEnd < memberMapData.Index + ? row.Parser.Count - 1 + : memberMapData.IndexEnd; + + for (var i = memberMapData.Index; i <= indexEnd; i++) + { + var field = converter.ConvertFromString(row.GetField(i), row, memberMapData); + list.Add(field); + } + } + + return list; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/DateOnlyConverter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/DateOnlyConverter.cs new file mode 100644 index 0000000..faedb82 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/DateOnlyConverter.cs @@ -0,0 +1,40 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +#if NET6_0 +using CsvHelper.Configuration; +using System; +using System.Globalization; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Converts a <see cref="DateOnly"/> to and from a <see cref="string"/>. + /// </summary> + public class DateOnlyConverter : DefaultTypeConverter + { + /// <summary> + /// Converts the string to an object. + /// </summary> + /// <param name="text">The string to convert to an object.</param> + /// <param name="row">The <see cref="IReaderRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being created.</param> + /// <returns>The object created from the string.</returns> + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + if (text == null) + { + return base.ConvertFromString(null, row, memberMapData); + } + + var formatProvider = (IFormatProvider)memberMapData.TypeConverterOptions.CultureInfo.GetFormat(typeof(DateTimeFormatInfo)) ?? memberMapData.TypeConverterOptions.CultureInfo; + var dateTimeStyle = memberMapData.TypeConverterOptions.DateTimeStyle ?? DateTimeStyles.None; + + return memberMapData.TypeConverterOptions.Formats == null || memberMapData.TypeConverterOptions.Formats.Length == 0 + ? DateOnly.Parse(text, formatProvider, dateTimeStyle) + : DateOnly.ParseExact(text, memberMapData.TypeConverterOptions.Formats, formatProvider, dateTimeStyle); + } + } +} +#endif diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/DateTimeConverter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/DateTimeConverter.cs new file mode 100644 index 0000000..b67f133 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/DateTimeConverter.cs @@ -0,0 +1,43 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using CsvHelper.Configuration; +using System; +using System.Globalization; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Converts a <see cref="DateTime"/> to and from a <see cref="string"/>. + /// </summary> + public class DateTimeConverter : DefaultTypeConverter + { + /// <summary> + /// Converts the string to an object. + /// </summary> + /// <param name="text">The string to convert to an object.</param> + /// <param name="row">The <see cref="IReaderRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being created.</param> + /// <returns>The object created from the string.</returns> + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + if (text == null) + { + return base.ConvertFromString(null, row, memberMapData); + } + + var formatProvider = (IFormatProvider)memberMapData.TypeConverterOptions.CultureInfo.GetFormat(typeof(DateTimeFormatInfo)) ?? memberMapData.TypeConverterOptions.CultureInfo; + var dateTimeStyle = memberMapData.TypeConverterOptions.DateTimeStyle ?? DateTimeStyles.None; + + DateTime dateTime; + var success = memberMapData.TypeConverterOptions.Formats == null || memberMapData.TypeConverterOptions.Formats.Length == 0 + ? DateTime.TryParse(text, formatProvider, dateTimeStyle, out dateTime) + : DateTime.TryParseExact(text, memberMapData.TypeConverterOptions.Formats, formatProvider, dateTimeStyle, out dateTime); + + return success + ? dateTime + : base.ConvertFromString(text, row, memberMapData); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/DateTimeOffsetConverter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/DateTimeOffsetConverter.cs new file mode 100644 index 0000000..88ad90e --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/DateTimeOffsetConverter.cs @@ -0,0 +1,43 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Globalization; +using CsvHelper.Configuration; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Converts a <see cref="DateTimeOffset"/> to and from a <see cref="string"/>. + /// </summary> + public class DateTimeOffsetConverter : DefaultTypeConverter + { + /// <summary> + /// Converts the string to an object. + /// </summary> + /// <param name="text">The string to convert to an object.</param> + /// <param name="row">The <see cref="IReaderRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being created.</param> + /// <returns>The object created from the string.</returns> + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + if (text == null) + { + return base.ConvertFromString(null, row, memberMapData); + } + + var formatProvider = (IFormatProvider)memberMapData.TypeConverterOptions.CultureInfo.GetFormat(typeof(DateTimeFormatInfo)) ?? memberMapData.TypeConverterOptions.CultureInfo; + var dateTimeStyle = memberMapData.TypeConverterOptions.DateTimeStyle ?? DateTimeStyles.None; + + DateTimeOffset dateTimeOffset; + var success = memberMapData.TypeConverterOptions.Formats == null || memberMapData.TypeConverterOptions.Formats.Length == 0 + ? DateTimeOffset.TryParse(text, formatProvider, dateTimeStyle, out dateTimeOffset) + : DateTimeOffset.TryParseExact(text, memberMapData.TypeConverterOptions.Formats, formatProvider, dateTimeStyle, out dateTimeOffset); + + return success + ? dateTimeOffset + : base.ConvertFromString(null, row, memberMapData); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/DecimalConverter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/DecimalConverter.cs new file mode 100644 index 0000000..855167e --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/DecimalConverter.cs @@ -0,0 +1,34 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System.Globalization; +using CsvHelper.Configuration; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Converts a <see cref="decimal"/> to and from a <see cref="string"/>. + /// </summary> + public class DecimalConverter : DefaultTypeConverter + { + /// <summary> + /// Converts the string to an object. + /// </summary> + /// <param name="text">The string to convert to an object.</param> + /// <param name="row">The <see cref="IReaderRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being created.</param> + /// <returns>The object created from the string.</returns> + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + var numberStyle = memberMapData.TypeConverterOptions.NumberStyles ?? NumberStyles.Number; + + if (decimal.TryParse(text, numberStyle, memberMapData.TypeConverterOptions.CultureInfo, out var d)) + { + return d; + } + + return base.ConvertFromString(text, row, memberMapData); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/DefaultTypeConverter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/DefaultTypeConverter.cs new file mode 100644 index 0000000..57bf11d --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/DefaultTypeConverter.cs @@ -0,0 +1,62 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using CsvHelper.Configuration; +using System.Linq; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Converts an <see cref="object"/> to and from a <see cref="string"/>. + /// </summary> + public class DefaultTypeConverter : ITypeConverter + { + /// <inheritdoc/> + public virtual object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + if (memberMapData.UseDefaultOnConversionFailure && memberMapData.IsDefaultSet && memberMapData.Member.MemberType() == memberMapData.Default?.GetType()) + { + return memberMapData.Default; + } + + if (!row.Configuration.ExceptionMessagesContainRawData) + { + text = $"Hidden because {nameof(IParserConfiguration.ExceptionMessagesContainRawData)} is false."; + } + + text ??= string.Empty; + + var message = + $"The conversion cannot be performed.{Environment.NewLine}" + + $" Text: '{text}'{Environment.NewLine}" + + $" MemberName: {memberMapData.Member?.Name}{Environment.NewLine}" + + $" MemberType: {memberMapData.Member?.MemberType().FullName}{Environment.NewLine}" + + $" TypeConverter: '{memberMapData.TypeConverter?.GetType().FullName}'"; + throw new TypeConverterException(this, memberMapData, text, row.Context, message); + } + + /// <inheritdoc/> + public virtual string? ConvertToString(object? value, IWriterRow row, MemberMapData memberMapData) + { + if (value == null) + { + if (memberMapData.TypeConverterOptions.NullValues.Count > 0) + { + return memberMapData.TypeConverterOptions.NullValues.First(); + } + + return string.Empty; + } + + if (value is IFormattable formattable) + { + var format = memberMapData.TypeConverterOptions.Formats?.FirstOrDefault(); + return formattable.ToString(format, memberMapData.TypeConverterOptions.CultureInfo); + } + + return value?.ToString() ?? string.Empty; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/DoubleConverter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/DoubleConverter.cs new file mode 100644 index 0000000..b330831 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/DoubleConverter.cs @@ -0,0 +1,57 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Globalization; +using System.Linq; +using CsvHelper.Configuration; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Converts a <see cref="double"/> to and from a <see cref="string"/>. + /// </summary> + public class DoubleConverter : DefaultTypeConverter + { + private Lazy<string> defaultFormat = new Lazy<string>(() => double.TryParse(double.MaxValue.ToString("R"), out var _) ? "R" : "G17"); + + /// <summary> + /// Converts the object to a string. + /// </summary> + /// <param name="value">The object to convert to a string.</param> + /// <param name="row">The <see cref="IWriterRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being written.</param> + /// <returns>The string representation of the object.</returns> + public override string? ConvertToString(object? value, IWriterRow row, MemberMapData memberMapData) + { + var format = memberMapData.TypeConverterOptions.Formats?.FirstOrDefault() ?? defaultFormat.Value; + + if (value is double d) + { + return d.ToString(format, memberMapData.TypeConverterOptions.CultureInfo); + } + + return base.ConvertToString(value, row, memberMapData); + } + + /// <summary> + /// Converts the string to an object. + /// </summary> + /// <param name="text">The string to convert to an object.</param> + /// <param name="row">The <see cref="IReaderRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being created.</param> + /// <returns>The object created from the string.</returns> + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + var numberStyle = memberMapData.TypeConverterOptions.NumberStyles ?? NumberStyles.Float | NumberStyles.AllowThousands; + + if (double.TryParse(text, numberStyle, memberMapData.TypeConverterOptions.CultureInfo, out var d)) + { + return d; + } + + return base.ConvertFromString(text, row, memberMapData); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/EnumConverter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/EnumConverter.cs new file mode 100644 index 0000000..023a4f3 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/EnumConverter.cs @@ -0,0 +1,121 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using CsvHelper.Configuration; +using CsvHelper.Configuration.Attributes; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Converts an <see cref="Enum"/> to and from a <see cref="string"/>. + /// </summary> + public class EnumConverter : DefaultTypeConverter + { + private readonly Type type; + private readonly Dictionary<string, string> enumNamesByAttributeNames = new Dictionary<string, string>(); + private readonly Dictionary<string, string> enumNamesByAttributeNamesIgnoreCase = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); + private readonly Dictionary<object, string> attributeNamesByEnumValues = new Dictionary<object, string>(); + + // enumNamesByAttributeNames + // enumNamesByAttributeNamesIgnoreCase + // [Name("Foo")]:One + + // attributeNamesByEnumValues + // 1:[Name("Foo")] + + /// <summary> + /// Creates a new <see cref="EnumConverter"/> for the given <see cref="Enum"/> <see cref="System.Type"/>. + /// </summary> + /// <param name="type">The type of the Enum.</param> + public EnumConverter(Type type) + { + if (!typeof(Enum).GetTypeInfo().IsAssignableFrom(type.GetTypeInfo())) + { + throw new ArgumentException($"'{type.FullName}' is not an Enum."); + } + + this.type = type; + + foreach (var value in Enum.GetValues(type)) + { + var enumName = Enum.GetName(type, value) ?? string.Empty; + + var nameAttribute = type.GetField(enumName)?.GetCustomAttribute<NameAttribute>(); + if (nameAttribute != null && nameAttribute.Names.Length > 0) + { + foreach (var attributeName in nameAttribute.Names) + { + if (!enumNamesByAttributeNames.ContainsKey(attributeName)) + { + enumNamesByAttributeNames.Add(attributeName, enumName); + } + + if (!enumNamesByAttributeNamesIgnoreCase.ContainsKey(attributeName)) + { + enumNamesByAttributeNamesIgnoreCase.Add(attributeName, enumName); + } + + if (!attributeNamesByEnumValues.ContainsKey(value)) + { + attributeNamesByEnumValues.Add(value, attributeName); + } + } + } + } + } + + /// <inheritdoc/> + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + var ignoreCase = memberMapData.TypeConverterOptions.EnumIgnoreCase ?? false; + + if (text != null) + { + var dict = ignoreCase + ? enumNamesByAttributeNamesIgnoreCase + : enumNamesByAttributeNames; + if (dict.TryGetValue(text, out var name)) + { + return Enum.Parse(type, name); + } + } + +#if NET45 || NET47 || NETSTANDARD2_0 + try + { + return Enum.Parse(type, text, ignoreCase); + } + catch + { + return base.ConvertFromString(text, row, memberMapData); + } +#else + if (Enum.TryParse(type, text, ignoreCase, out var value)) + { + return value; + } + else + { + return base.ConvertFromString(text, row, memberMapData); + } +#endif + } + + /// <inheritdoc/> + public override string? ConvertToString(object? value, IWriterRow row, MemberMapData memberMapData) + { + if (value != null && attributeNamesByEnumValues.TryGetValue(value, out var name)) + { + return name; + } + + return base.ConvertToString(value, row, memberMapData); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/EnumConverterFactory.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/EnumConverterFactory.cs new file mode 100644 index 0000000..5918552 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/EnumConverterFactory.cs @@ -0,0 +1,35 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper.TypeConversion +{ + /// <inheritdoc /> + public class EnumConverterFactory : ITypeConverterFactory + { + /// <inheritdoc /> + public bool CanCreate(Type type) + { + return typeof(Enum).IsAssignableFrom(type); + } + + /// <inheritdoc /> + public bool Create(Type type, TypeConverterCache cache, out ITypeConverter typeConverter) + { + if (cache.Contains(typeof(Enum))) + { + // If the user has registered a converter for the generic Enum type, + // that converter will be used as a default for all enums. + typeConverter = cache.GetConverter<Enum>(); + + return false; + } + + typeConverter = new EnumConverter(type); + + return true; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/EnumerableConverter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/EnumerableConverter.cs new file mode 100644 index 0000000..0a6a06d --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/EnumerableConverter.cs @@ -0,0 +1,48 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System.Collections; +using CsvHelper.Configuration; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Throws an exception when used. This is here so that it's apparent + /// that there is no support for <see cref="IEnumerable"/> type conversion. A custom + /// converter will need to be created to have a field convert to and + /// from an IEnumerable. + /// </summary> + public class EnumerableConverter : DefaultTypeConverter + { + /// <summary> + /// Throws an exception. + /// </summary> + /// <param name="text">The string to convert to an object.</param> + /// <param name="row">The <see cref="IReaderRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being created.</param> + /// <returns>The object created from the string.</returns> + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + var message = "Converting IEnumerable types is not supported for a single field. " + + "If you want to do this, create your own ITypeConverter and register " + + "it in the TypeConverterFactory by calling AddConverter."; + throw new TypeConverterException(this, memberMapData, text, row.Context, message); + } + + /// <summary> + /// Throws an exception. + /// </summary> + /// <param name="value">The object to convert to a string.</param> + /// <param name="row">The <see cref="IWriterRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being written.</param> + /// <returns>The string representation of the object.</returns> + public override string? ConvertToString(object? value, IWriterRow row, MemberMapData memberMapData) + { + var message = "Converting IEnumerable types is not supported for a single field. " + + "If you want to do this, create your own ITypeConverter and register " + + "it in the TypeConverterFactory by calling AddConverter."; + throw new TypeConverterException(this, memberMapData, value, row.Context, message); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/GuidConverter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/GuidConverter.cs new file mode 100644 index 0000000..7639201 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/GuidConverter.cs @@ -0,0 +1,32 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using CsvHelper.Configuration; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Converts a <see cref="Guid"/> to and from a <see cref="string"/>. + /// </summary> + public class GuidConverter : DefaultTypeConverter + { + /// <summary> + /// Converts the string to an object. + /// </summary> + /// <param name="text">The string to convert to an object.</param> + /// <param name="row">The <see cref="IReaderRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being created.</param> + /// <returns>The object created from the string.</returns> + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + if (text == null) + { + return base.ConvertFromString(text, row, memberMapData); + } + + return new Guid(text); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/IDictionaryConverter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/IDictionaryConverter.cs new file mode 100644 index 0000000..830756f --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/IDictionaryConverter.cs @@ -0,0 +1,65 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System.Collections; +using System.Collections.Generic; +using CsvHelper.Configuration; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Converts an <see cref="IDictionary"/> to and from a <see cref="string"/>. + /// </summary> + public class IDictionaryConverter : DefaultTypeConverter + { + /// <summary> + /// Converts the object to a string. + /// </summary> + /// <param name="value">The object to convert to a string.</param> + /// <param name="row">The <see cref="IWriterRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being written.</param> + /// <returns>The string representation of the object.</returns> + public override string? ConvertToString(object? value, IWriterRow row, MemberMapData memberMapData) + { + var dictionary = value as IDictionary; + if (dictionary == null) + { + return base.ConvertToString(value, row, memberMapData); + } + + foreach (DictionaryEntry entry in dictionary) + { + row.WriteField(entry.Value); + } + + return null; + } + + /// <summary> + /// Converts the string to an object. + /// </summary> + /// <param name="text">The string to convert to an object.</param> + /// <param name="row">The <see cref="IReaderRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being created.</param> + /// <returns>The object created from the string.</returns> + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + var dictionary = new Dictionary<string, string>(); + + var indexEnd = memberMapData.IndexEnd < memberMapData.Index + ? row.Parser.Count - 1 + : memberMapData.IndexEnd; + + for (var i = memberMapData.Index; i <= indexEnd; i++) + { + if (row.TryGetField(i, out string field)) + { + dictionary.Add(row.HeaderRecord[i], field); + } + } + + return dictionary; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/IDictionaryGenericConverter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/IDictionaryGenericConverter.cs new file mode 100644 index 0000000..5c2dea2 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/IDictionaryGenericConverter.cs @@ -0,0 +1,46 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System.Collections; +using System.Collections.Generic; +using CsvHelper.Configuration; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Converts an <see cref="IDictionary{TKey, TValue}"/> to and from a <see cref="string"/>. + /// </summary> + public class IDictionaryGenericConverter : IDictionaryConverter + { + /// <summary> + /// Converts the string to an object. + /// </summary> + /// <param name="text">The string to convert to an object.</param> + /// <param name="row">The <see cref="IReaderRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being created.</param> + /// <returns>The object created from the string.</returns> + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + var keyType = memberMapData.Member.MemberType().GetGenericArguments()[0]; + var valueType = memberMapData.Member.MemberType().GetGenericArguments()[1]; + var dictionaryType = typeof(Dictionary<,>); + dictionaryType = dictionaryType.MakeGenericType(keyType, valueType); + var dictionary = (IDictionary)ObjectResolver.Current.Resolve(dictionaryType); + var converter = row.Context.TypeConverterCache.GetConverter(valueType); + + var indexEnd = memberMapData.IndexEnd < memberMapData.Index + ? row.Parser.Count - 1 + : memberMapData.IndexEnd; + + for (var i = memberMapData.Index; i <= indexEnd; i++) + { + var field = converter.ConvertFromString(row.GetField(i), row, memberMapData); + + dictionary.Add(row.HeaderRecord[i], field); + } + + return dictionary; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/IEnumerableConverter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/IEnumerableConverter.cs new file mode 100644 index 0000000..45ef579 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/IEnumerableConverter.cs @@ -0,0 +1,85 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using CsvHelper.Configuration; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Converts an <see cref="IEnumerable"/> to and from a <see cref="string"/>. + /// </summary> + public class IEnumerableConverter : DefaultTypeConverter + { + /// <summary> + /// Converts the object to a string. + /// </summary> + /// <param name="value">The object to convert to a string.</param> + /// <param name="row"></param> + /// <param name="memberMapData"></param> + /// <returns>The string representation of the object.</returns> + public override string? ConvertToString(object? value, IWriterRow row, MemberMapData memberMapData) + { + var list = value as IEnumerable; + if (list == null) + { + return base.ConvertToString(value, row, memberMapData); + } + + foreach (var item in list) + { + row.WriteField(item.ToString()); + } + + return null; + } + + /// <summary> + /// Converts the string to an object. + /// </summary> + /// <param name="text">The string to convert to an object.</param> + /// <param name="row">The <see cref="IReaderRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being created.</param> + /// <returns>The object created from the string.</returns> + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + var list = new List<string>(); + + if (memberMapData.IsNameSet || row.Configuration.HasHeaderRecord && !memberMapData.IsIndexSet) + { + // Use the name. + var nameIndex = 0; + while (true) + { + if (!row.TryGetField(memberMapData.Names.FirstOrDefault(), nameIndex, out string field)) + { + break; + } + + list.Add(field); + nameIndex++; + } + } + else + { + // Use the index. + var indexEnd = memberMapData.IndexEnd < memberMapData.Index + ? row.Parser.Count - 1 + : memberMapData.IndexEnd; + + for (var i = memberMapData.Index; i <= indexEnd; i++) + { + if (row.TryGetField(i, out string field)) + { + list.Add(field); + } + } + } + + return list; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/IEnumerableGenericConverter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/IEnumerableGenericConverter.cs new file mode 100644 index 0000000..6718f31 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/IEnumerableGenericConverter.cs @@ -0,0 +1,65 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using CsvHelper.Configuration; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Converts an <see cref="IEnumerable{T}"/> to and from a <see cref="string"/>. + /// </summary> + public class IEnumerableGenericConverter : IEnumerableConverter + { + /// <summary> + /// Converts the string to an object. + /// </summary> + /// <param name="text">The string to convert to an object.</param> + /// <param name="row">The <see cref="IReaderRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being created.</param> + /// <returns>The object created from the string.</returns> + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + var type = memberMapData.Member.MemberType().GetGenericArguments()[0]; + var listType = typeof(List<>); + listType = listType.MakeGenericType(type); + var list = (IList)ObjectResolver.Current.Resolve(listType); + var converter = row.Context.TypeConverterCache.GetConverter(type); + + if (memberMapData.IsNameSet || row.Configuration.HasHeaderRecord && !memberMapData.IsIndexSet) + { + // Use the name. + var nameIndex = 0; + while (true) + { + if (!row.TryGetField(type, memberMapData.Names.FirstOrDefault(), nameIndex, out var field)) + { + break; + } + + list.Add(field); + nameIndex++; + } + } + else + { + // Use the index. + var indexEnd = memberMapData.IndexEnd < memberMapData.Index + ? row.Parser.Count - 1 + : memberMapData.IndexEnd; + + for (var i = memberMapData.Index; i <= indexEnd; i++) + { + var field = converter.ConvertFromString(row.GetField(i), row, memberMapData); + + list.Add(field); + } + } + + return list; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/ITypeConverter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/ITypeConverter.cs new file mode 100644 index 0000000..5eb5961 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/ITypeConverter.cs @@ -0,0 +1,32 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using CsvHelper.Configuration; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Converts objects to and from strings. + /// </summary> + public interface ITypeConverter + { + /// <summary> + /// Converts the string to an object. + /// </summary> + /// <param name="text">The string to convert to an object.</param> + /// <param name="row">The <see cref="IReaderRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being created.</param> + /// <returns>The object created from the string.</returns> + object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData); + + /// <summary> + /// Converts the object to a string. + /// </summary> + /// <param name="value">The object to convert to a string.</param> + /// <param name="row">The <see cref="IWriterRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being written.</param> + /// <returns>The string representation of the object.</returns> + string? ConvertToString(object? value, IWriterRow row, MemberMapData memberMapData); + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/ITypeConverterFactory.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/ITypeConverterFactory.cs new file mode 100644 index 0000000..67fbda9 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/ITypeConverterFactory.cs @@ -0,0 +1,33 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Produces <see cref="ITypeConverter"/> for the specified <see cref="System.Type"/> + /// </summary> + public interface ITypeConverterFactory + { + /// <summary> + /// Determines if the factory can create a type converter for the given type. + /// </summary> + /// <param name="type">The <see cref="Type"/> to be checked</param> + /// <returns><c>true</c> if the factory can create the type, otherwise <c>false</c>.</returns> + bool CanCreate(Type type); + + /// <summary> + /// Creates a type converter for the given type and assigns it to the given out typeConverter parameter. + /// </summary> + /// <param name="type">The type to create the converter for.</param> + /// <param name="cache">The type converter cache.</param> + /// <param name="typeConverter">The parameter to set the converter to.</param> + /// <returns><c>true</c> if the converter should be added to the cache, otherwise <c>false</c>.</returns> + bool Create(Type type, TypeConverterCache cache, out ITypeConverter typeConverter); + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/Int16Converter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/Int16Converter.cs new file mode 100644 index 0000000..630559f --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/Int16Converter.cs @@ -0,0 +1,34 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System.Globalization; +using CsvHelper.Configuration; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Converts a <see cref="short"/> to and from a <see cref="string"/>. + /// </summary> + public class Int16Converter : DefaultTypeConverter + { + /// <summary> + /// Converts the string to an object. + /// </summary> + /// <param name="text">The string to convert to an object.</param> + /// <param name="row">The <see cref="IReaderRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being created.</param> + /// <returns>The object created from the string.</returns> + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + var numberStyle = memberMapData.TypeConverterOptions.NumberStyles ?? NumberStyles.Integer; + + if (short.TryParse(text, numberStyle, memberMapData.TypeConverterOptions.CultureInfo, out var s)) + { + return s; + } + + return base.ConvertFromString(text, row, memberMapData); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/Int32Converter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/Int32Converter.cs new file mode 100644 index 0000000..61b0f9c --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/Int32Converter.cs @@ -0,0 +1,34 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System.Globalization; +using CsvHelper.Configuration; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Converts an <see cref="int"/> to and from a <see cref="string"/>. + /// </summary> + public class Int32Converter : DefaultTypeConverter + { + /// <summary> + /// Converts the string to an object. + /// </summary> + /// <param name="text">The string to convert to an object.</param> + /// <param name="row">The <see cref="IReaderRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being created.</param> + /// <returns>The object created from the string.</returns> + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + var numberStyle = memberMapData.TypeConverterOptions.NumberStyles ?? NumberStyles.Integer; + + if (int.TryParse(text, numberStyle, memberMapData.TypeConverterOptions.CultureInfo, out var i)) + { + return i; + } + + return base.ConvertFromString(text, row, memberMapData); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/Int64Converter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/Int64Converter.cs new file mode 100644 index 0000000..47f717d --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/Int64Converter.cs @@ -0,0 +1,34 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System.Globalization; +using CsvHelper.Configuration; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Converts an <see cref="long"/> to and from a <see cref="string"/>. + /// </summary> + public class Int64Converter : DefaultTypeConverter + { + /// <summary> + /// Converts the string to an object. + /// </summary> + /// <param name="text">The string to convert to an object.</param> + /// <param name="row">The <see cref="IReaderRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being created.</param> + /// <returns>The object created from the string.</returns> + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + var numberStyle = memberMapData.TypeConverterOptions.NumberStyles ?? NumberStyles.Integer; + + if (long.TryParse(text, numberStyle, memberMapData.TypeConverterOptions.CultureInfo, out var l)) + { + return l; + } + + return base.ConvertFromString(text, row, memberMapData); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/NullableConverter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/NullableConverter.cs new file mode 100644 index 0000000..89ce969 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/NullableConverter.cs @@ -0,0 +1,94 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using CsvHelper.Configuration; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Converts a <see cref="Nullable{T}"/> to and from a <see cref="string"/>. + /// </summary> + public class NullableConverter : DefaultTypeConverter + { + /// <summary> + /// Gets the type of the nullable. + /// </summary> + /// <value> + /// The type of the nullable. + /// </value> + public Type NullableType { get; private set; } + + /// <summary> + /// Gets the underlying type of the nullable. + /// </summary> + /// <value> + /// The underlying type. + /// </value> + public Type UnderlyingType { get; private set; } + + /// <summary> + /// Gets the type converter for the underlying type. + /// </summary> + /// <value> + /// The type converter. + /// </value> + public ITypeConverter UnderlyingTypeConverter { get; private set; } + + /// <summary> + /// Creates a new <see cref="NullableConverter"/> for the given <see cref="Nullable{T}"/> <see cref="Type"/>. + /// </summary> + /// <param name="type">The nullable type.</param> + /// <param name="typeConverterFactory">The type converter factory.</param> + /// <exception cref="System.ArgumentException">type is not a nullable type.</exception> + public NullableConverter(Type type, TypeConverterCache typeConverterFactory) + { + NullableType = type; + UnderlyingType = Nullable.GetUnderlyingType(type); + if (UnderlyingType == null) + { + throw new ArgumentException("type is not a nullable type."); + } + + UnderlyingTypeConverter = typeConverterFactory.GetConverter(UnderlyingType); + } + + /// <summary> + /// Converts the string to an object. + /// </summary> + /// <param name="text">The string to convert to an object.</param> + /// <param name="row">The <see cref="IReaderRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being created.</param> + /// <returns>The object created from the string.</returns> + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + if (string.IsNullOrEmpty(text)) + { + return null; + } + + foreach (var nullValue in memberMapData.TypeConverterOptions.NullValues) + { + if (text == nullValue) + { + return null; + } + } + + return UnderlyingTypeConverter.ConvertFromString(text, row, memberMapData); + } + + /// <summary> + /// Converts the object to a string. + /// </summary> + /// <param name="value">The object to convert to a string.</param> + /// <param name="row"></param> + /// <param name="memberMapData"></param> + /// <returns>The string representation of the object.</returns> + public override string? ConvertToString(object? value, IWriterRow row, MemberMapData memberMapData) + { + return UnderlyingTypeConverter.ConvertToString(value, row, memberMapData); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/NullableConverterFactory.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/NullableConverterFactory.cs new file mode 100644 index 0000000..2991348 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/NullableConverterFactory.cs @@ -0,0 +1,28 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Linq; + +namespace CsvHelper.TypeConversion +{ + /// <inheritdoc /> + public class NullableConverterFactory : ITypeConverterFactory + { + /// <inheritdoc /> + public bool CanCreate(Type type) + { + return (type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>))); + } + + /// <inheritdoc /> + public bool Create(Type type, TypeConverterCache cache, out ITypeConverter typeConverter) + { + typeConverter = new NullableConverter(type, cache); + + return true; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/SByteConverter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/SByteConverter.cs new file mode 100644 index 0000000..816a58a --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/SByteConverter.cs @@ -0,0 +1,34 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System.Globalization; +using CsvHelper.Configuration; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Converts a <see cref="sbyte"/> to and from a <see cref="string"/>. + /// </summary> + public class SByteConverter : DefaultTypeConverter + { + /// <summary> + /// Converts the string to an object. + /// </summary> + /// <param name="text">The string to convert to an object.</param> + /// <param name="row">The <see cref="IReaderRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being created.</param> + /// <returns>The object created from the string.</returns> + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + var numberStyle = memberMapData.TypeConverterOptions.NumberStyles ?? NumberStyles.Integer; + + if (sbyte.TryParse(text, numberStyle, memberMapData.TypeConverterOptions.CultureInfo, out var sb)) + { + return sb; + } + + return base.ConvertFromString(text, row, memberMapData); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/SingleConverter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/SingleConverter.cs new file mode 100644 index 0000000..c6a8ecc --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/SingleConverter.cs @@ -0,0 +1,57 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System.Globalization; +using CsvHelper.Configuration; +using System; +using System.Linq; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Converts a <see cref="Single"/> to and from a <see cref="string"/>. + /// </summary> + public class SingleConverter : DefaultTypeConverter + { + private Lazy<string> defaultFormat = new Lazy<string>(() => float.TryParse(float.MaxValue.ToString("R"), out var _) ? "R" : "G9"); + + /// <summary> + /// Converts the object to a string. + /// </summary> + /// <param name="value">The object to convert to a string.</param> + /// <param name="row">The <see cref="IWriterRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being written.</param> + /// <returns>The string representation of the object.</returns> + public override string? ConvertToString(object? value, IWriterRow row, MemberMapData memberMapData) + { + var format = memberMapData.TypeConverterOptions.Formats?.FirstOrDefault() ?? defaultFormat.Value; + + if (value is float f) + { + return f.ToString(format, memberMapData.TypeConverterOptions.CultureInfo); + } + + return base.ConvertToString(value, row, memberMapData); + } + + /// <summary> + /// Converts the string to an object. + /// </summary> + /// <param name="text">The string to convert to an object.</param> + /// <param name="row">The <see cref="IReaderRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being created.</param> + /// <returns>The object created from the string.</returns> + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + var numberStyle = memberMapData.TypeConverterOptions.NumberStyles ?? NumberStyles.Float | NumberStyles.AllowThousands; + + if (float.TryParse(text, numberStyle, memberMapData.TypeConverterOptions.CultureInfo, out var f)) + { + return f; + } + + return base.ConvertFromString(text, row, memberMapData); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/StringConverter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/StringConverter.cs new file mode 100644 index 0000000..6196973 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/StringConverter.cs @@ -0,0 +1,39 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using CsvHelper.Configuration; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Converts a <see cref="string"/> to and from a <see cref="string"/>. + /// </summary> + public class StringConverter : DefaultTypeConverter + { + /// <summary> + /// Converts the string to an object. + /// </summary> + /// <param name="text">The string to convert to an object.</param> + /// <param name="row">The <see cref="IReaderRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being created.</param> + /// <returns>The object created from the string.</returns> + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + if (text == null) + { + return string.Empty; + } + + foreach (var nullValue in memberMapData.TypeConverterOptions.NullValues) + { + if (text == nullValue) + { + return null; + } + } + + return text; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/TimeOnlyConverter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/TimeOnlyConverter.cs new file mode 100644 index 0000000..a877b93 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/TimeOnlyConverter.cs @@ -0,0 +1,40 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +#if NET6_0 +using CsvHelper.Configuration; +using System; +using System.Globalization; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Converts a <see cref="TimeOnly"/> to and from a <see cref="string"/>. + /// </summary> + public class TimeOnlyConverter : DefaultTypeConverter + { + /// <summary> + /// Converts the string to an object. + /// </summary> + /// <param name="text">The string to convert to an object.</param> + /// <param name="row">The <see cref="IReaderRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being created.</param> + /// <returns>The object created from the string.</returns> + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + if (text == null) + { + return base.ConvertFromString(null, row, memberMapData); + } + + var formatProvider = (IFormatProvider)memberMapData.TypeConverterOptions.CultureInfo.GetFormat(typeof(DateTimeFormatInfo)) ?? memberMapData.TypeConverterOptions.CultureInfo; + var dateTimeStyle = memberMapData.TypeConverterOptions.DateTimeStyle ?? DateTimeStyles.None; + + return memberMapData.TypeConverterOptions.Formats == null || memberMapData.TypeConverterOptions.Formats.Length == 0 + ? TimeOnly.Parse(text, formatProvider, dateTimeStyle) + : TimeOnly.ParseExact(text, memberMapData.TypeConverterOptions.Formats, formatProvider, dateTimeStyle); + } + } +} +#endif diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/TimeSpanConverter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/TimeSpanConverter.cs new file mode 100644 index 0000000..8424475 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/TimeSpanConverter.cs @@ -0,0 +1,41 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Globalization; +using CsvHelper.Configuration; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Converts a <see cref="TimeSpan"/> to and from a <see cref="string"/>. + /// </summary> + public class TimeSpanConverter : DefaultTypeConverter + { + /// <summary> + /// Converts the string to an object. + /// </summary> + /// <param name="text">The string to convert to an object.</param> + /// <param name="row">The <see cref="IReaderRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being created.</param> + /// <returns>The object created from the string.</returns> + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + var formatProvider = (IFormatProvider)memberMapData.TypeConverterOptions.CultureInfo; + + var timeSpanStyle = memberMapData.TypeConverterOptions.TimeSpanStyle ?? TimeSpanStyles.None; + if (memberMapData.TypeConverterOptions.Formats != null && TimeSpan.TryParseExact(text, memberMapData.TypeConverterOptions.Formats, formatProvider, timeSpanStyle, out var span)) + { + return span; + } + + if (memberMapData.TypeConverterOptions.Formats == null && TimeSpan.TryParse(text, formatProvider, out span)) + { + return span; + } + + return base.ConvertFromString(text, row, memberMapData); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/TypeConverter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/TypeConverter.cs new file mode 100644 index 0000000..4a0f428 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/TypeConverter.cs @@ -0,0 +1,52 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using CsvHelper.Configuration; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Throws an exception when used. This is here so that it's apparent + /// that there is no support for <see cref="Type"/> type conversion. A custom + /// converter will need to be created to have a field convert to and + /// from <see cref="Type"/>. + /// </summary> + public class TypeConverter : DefaultTypeConverter + { + /// <summary> + /// Throws an exception. + /// </summary> + /// <param name="text">The string to convert to an object.</param> + /// <param name="row">The <see cref="IReaderRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being created.</param> + /// <returns>The object created from the string.</returns> + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + var message = "Converting System.Type is not supported. " + + "If you want to do this, create your own ITypeConverter and register " + + "it in the TypeConverterFactory by calling AddConverter."; + throw new TypeConverterException(this, memberMapData, text ?? string.Empty, row.Context, message); + } + + /// <summary> + /// Throws an exception. + /// </summary> + /// <param name="value">The object to convert to a string.</param> + /// <param name="row">The <see cref="IWriterRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being written.</param> + /// <returns>The string representation of the object.</returns> + public override string? ConvertToString(object? value, IWriterRow row, MemberMapData memberMapData) + { + var message = "Converting System.Type is not supported. " + + "If you want to do this, create your own ITypeConverter and register " + + "it in the TypeConverterFactory by calling AddConverter."; + throw new TypeConverterException(this, memberMapData, value, row.Context, message); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/TypeConverterCache.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/TypeConverterCache.cs new file mode 100644 index 0000000..2f7d4dc --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/TypeConverterCache.cs @@ -0,0 +1,242 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using CsvHelper.Configuration.Attributes; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Numerics; +using System.Reflection; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Caches <see cref="ITypeConverter"/>s for a given type. + /// </summary> + public class TypeConverterCache + { + private readonly Dictionary<Type, ITypeConverter> typeConverters = new Dictionary<Type, ITypeConverter>(); + private readonly List<ITypeConverterFactory> typeConverterFactories = new List<ITypeConverterFactory>(); + private readonly Dictionary<Type, ITypeConverterFactory> typeConverterFactoryCache = new Dictionary<Type, ITypeConverterFactory>(); + + /// <summary> + /// Initializes the <see cref="TypeConverterCache" /> class. + /// </summary> + public TypeConverterCache() + { + CreateDefaultConverters(); + } + + /// <summary> + /// Determines if there is a converter registered for the given type. + /// </summary> + /// <param name="type">The type to check.</param> + /// <returns><c>true</c> if the converter is registered, otherwise false.</returns> + public bool Contains(Type type) + { + return typeConverters.ContainsKey(type); + } + + /// <summary> + /// Adds the <see cref="ITypeConverterFactory"/>. + /// Factories are queried in order of being added and first factory that handles the type is used for creating the <see cref="ITypeConverter"/>. + /// </summary> + /// <param name="typeConverterFactory">Type converter factory</param> + public void AddConverterFactory(ITypeConverterFactory typeConverterFactory) + { + if (typeConverterFactory == null) + { + throw new ArgumentNullException(nameof(typeConverterFactory)); + } + + typeConverterFactories.Add(typeConverterFactory); + } + + /// <summary> + /// Adds the <see cref="ITypeConverter"/> for the given <see cref="System.Type"/>. + /// </summary> + /// <param name="type">The type the converter converts.</param> + /// <param name="typeConverter">The type converter that converts the type.</param> + public void AddConverter(Type type, ITypeConverter typeConverter) + { + if (type == null) + { + throw new ArgumentNullException(nameof(type)); + } + + if (typeConverter == null) + { + throw new ArgumentNullException(nameof(typeConverter)); + } + + typeConverters[type] = typeConverter; + } + + /// <summary> + /// Adds the <see cref="ITypeConverter"/> for the given <see cref="System.Type"/>. + /// </summary> + /// <typeparam name="T">The type the converter converts.</typeparam> + /// <param name="typeConverter">The type converter that converts the type.</param> + public void AddConverter<T>(ITypeConverter typeConverter) + { + if (typeConverter == null) + { + throw new ArgumentNullException(nameof(typeConverter)); + } + + typeConverters[typeof(T)] = typeConverter; + } + + /// <summary> + /// Adds the given <see cref="ITypeConverter"/> to all registered types. + /// </summary> + /// <param name="typeConverter">The type converter.</param> + public void AddConverter(ITypeConverter typeConverter) + { + foreach (var type in typeConverters.Keys) + { + typeConverters[type] = typeConverter; + } + } + + /// <summary> + /// Removes the <see cref="ITypeConverter"/> for the given <see cref="System.Type"/>. + /// </summary> + /// <param name="type">The type to remove the converter for.</param> + public void RemoveConverter(Type type) + { + if (type == null) + { + throw new ArgumentNullException(nameof(type)); + } + + typeConverters.Remove(type); + } + + /// <summary> + /// Removes the <see cref="ITypeConverter"/> for the given <see cref="System.Type"/>. + /// </summary> + /// <typeparam name="T">The type to remove the converter for.</typeparam> + public void RemoveConverter<T>() + { + RemoveConverter(typeof(T)); + } + + /// <summary> + /// Removes the ITypeConverterFactory. + /// </summary> + /// <param name="typeConverterFactory">The ITypeConverterFactory to remove.</param> + public void RemoveConverterFactory(ITypeConverterFactory typeConverterFactory) + { + typeConverterFactories.Remove(typeConverterFactory); + var toRemove = typeConverterFactoryCache.Where(pair => pair.Value == typeConverterFactory); + foreach (var pair in toRemove) + { + typeConverterFactoryCache.Remove(pair.Key); + } + } + + /// <summary> + /// Gets the converter for the given <see cref="System.Type"/>. + /// </summary> + /// <param name="type">The type to get the converter for.</param> + /// <returns>The <see cref="ITypeConverter"/> for the given <see cref="System.Type"/>.</returns> + public ITypeConverter GetConverter(Type type) + { + if (type == null) + { + throw new ArgumentNullException(nameof(type)); + } + + if (typeConverters.TryGetValue(type, out ITypeConverter typeConverter)) + { + return typeConverter; + } + + if (!typeConverterFactoryCache.TryGetValue(type, out var factory)) + { + factory = typeConverterFactories.FirstOrDefault(f => f.CanCreate(type)); + if (factory != null) + { + typeConverterFactoryCache[type] = factory; + } + } + + if (factory != null) + { + if (factory.Create(type, this, out typeConverter)) + { + AddConverter(type, typeConverter); + } + + return typeConverter; + } + + return new DefaultTypeConverter(); + } + + /// <summary> + /// Gets the converter for the given member. If an attribute is + /// found on the member, that will be used, otherwise the cache + /// will be used. + /// </summary> + /// <param name="member">The member to get the converter for.</param> + public ITypeConverter GetConverter(MemberInfo member) + { + var typeConverterAttribute = member.GetCustomAttribute<TypeConverterAttribute>(); + if (typeConverterAttribute != null) + { + return typeConverterAttribute.TypeConverter; + } + + return GetConverter(member.MemberType()); + } + + /// <summary> + /// Gets the converter for the given <see cref="System.Type"/>. + /// </summary> + /// <typeparam name="T">The type to get the converter for.</typeparam> + /// <returns>The <see cref="ITypeConverter"/> for the given <see cref="System.Type"/>.</returns> + public ITypeConverter GetConverter<T>() + { + return GetConverter(typeof(T)); + } + + private void CreateDefaultConverters() + { + AddConverter(typeof(BigInteger), new BigIntegerConverter()); + AddConverter(typeof(bool), new BooleanConverter()); + AddConverter(typeof(byte), new ByteConverter()); + AddConverter(typeof(byte[]), new ByteArrayConverter()); + AddConverter(typeof(char), new CharConverter()); + AddConverter(typeof(DateTime), new DateTimeConverter()); + AddConverter(typeof(DateTimeOffset), new DateTimeOffsetConverter()); + AddConverter(typeof(decimal), new DecimalConverter()); + AddConverter(typeof(double), new DoubleConverter()); + AddConverter(typeof(float), new SingleConverter()); + AddConverter(typeof(Guid), new GuidConverter()); + AddConverter(typeof(short), new Int16Converter()); + AddConverter(typeof(int), new Int32Converter()); + AddConverter(typeof(long), new Int64Converter()); + AddConverter(typeof(sbyte), new SByteConverter()); + AddConverter(typeof(string), new StringConverter()); + AddConverter(typeof(TimeSpan), new TimeSpanConverter()); + AddConverter(typeof(Type), new TypeConverter()); + AddConverter(typeof(ushort), new UInt16Converter()); + AddConverter(typeof(uint), new UInt32Converter()); + AddConverter(typeof(ulong), new UInt64Converter()); + AddConverter(typeof(Uri), new UriConverter()); +#if NET6_0 + AddConverter(typeof(DateOnly), new DateOnlyConverter()); + AddConverter(typeof(TimeOnly), new TimeOnlyConverter()); +#endif + + AddConverterFactory(new EnumConverterFactory()); + AddConverterFactory(new NullableConverterFactory()); + AddConverterFactory(new CollectionConverterFactory()); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/TypeConverterException.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/TypeConverterException.cs new file mode 100644 index 0000000..970c195 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/TypeConverterException.cs @@ -0,0 +1,132 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using CsvHelper.Configuration; +using System; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Represents errors that occur while reading a CSV file. + /// </summary> + [Serializable] + public class TypeConverterException : CsvHelperException + { + /// <summary> + /// The text used in ConvertFromString. + /// </summary> + public string Text { get; private set; } + + /// <summary> + /// The value used in ConvertToString. + /// </summary> + public object Value { get; private set; } + + /// <summary> + /// The type converter. + /// </summary> + public ITypeConverter TypeConverter { get; private set; } + + /// <summary> + /// The member map data used in ConvertFromString and ConvertToString. + /// </summary> + public MemberMapData MemberMapData { get; private set; } + + /// <summary> + /// Initializes a new instance of the <see cref="TypeConverterException"/> class. + /// </summary> + /// <param name="typeConverter">The type converter.</param> + /// <param name="memberMapData">The member map data.</param> + /// <param name="text">The text.</param> + /// <param name="context">The reading context.</param> + public TypeConverterException(ITypeConverter typeConverter, MemberMapData memberMapData, string text, CsvContext context) : base(context) + { + TypeConverter = typeConverter; + MemberMapData = memberMapData; + Text = text; + } + + /// <summary> + /// Initializes a new instance of the <see cref="TypeConverterException"/> class. + /// </summary> + /// <param name="typeConverter">The type converter.</param> + /// <param name="memberMapData">The member map data.</param> + /// <param name="value">The value.</param> + /// <param name="context">The writing context.</param> + public TypeConverterException(ITypeConverter typeConverter, MemberMapData memberMapData, object value, CsvContext context) : base(context) + { + TypeConverter = typeConverter; + MemberMapData = memberMapData; + Value = value; + } + + /// <summary> + /// Initializes a new instance of the <see cref="TypeConverterException"/> class + /// with a specified error message. + /// </summary> + /// <param name="typeConverter">The type converter.</param> + /// <param name="memberMapData">The member map data.</param> + /// <param name="text">The text.</param> + /// <param name="context">The reading context.</param> + /// <param name="message">The message that describes the error.</param> + public TypeConverterException(ITypeConverter typeConverter, MemberMapData memberMapData, string text, CsvContext context, string message) : base(context, message) + { + TypeConverter = typeConverter; + MemberMapData = memberMapData; + Text = text; + } + + /// <summary> + /// Initializes a new instance of the <see cref="TypeConverterException"/> class + /// with a specified error message. + /// </summary> + /// <param name="typeConverter">The type converter.</param> + /// <param name="memberMapData">The member map data.</param> + /// <param name="value">The value.</param> + /// <param name="context">The writing context.</param> + /// <param name="message">The message that describes the error.</param> + public TypeConverterException(ITypeConverter typeConverter, MemberMapData memberMapData, object value, CsvContext context, string message) : base(context, message) + { + TypeConverter = typeConverter; + MemberMapData = memberMapData; + Value = value; + } + + /// <summary> + /// Initializes a new instance of the <see cref="TypeConverterException"/> class + /// with a specified error message and a reference to the inner exception that + /// is the cause of this exception. + /// </summary> + /// <param name="typeConverter">The type converter.</param> + /// <param name="memberMapData">The member map data.</param> + /// <param name="text">The text.</param> + /// <param name="context">The reading context.</param> + /// <param name="message">The error message that explains the reason for the exception.</param> + /// <param name="innerException">The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.</param> + public TypeConverterException(ITypeConverter typeConverter, MemberMapData memberMapData, string text, CsvContext context, string message, Exception innerException) : base(context, message, innerException) + { + TypeConverter = typeConverter; + MemberMapData = memberMapData; + Text = text; + } + + /// <summary> + /// Initializes a new instance of the <see cref="TypeConverterException"/> class + /// with a specified error message and a reference to the inner exception that + /// is the cause of this exception. + /// </summary> + /// <param name="typeConverter">The type converter.</param> + /// <param name="memberMapData">The member map data.</param> + /// <param name="value">The value.</param> + /// <param name="context">The writing context.</param> + /// <param name="message">The error message that explains the reason for the exception.</param> + /// <param name="innerException">The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.</param> + public TypeConverterException(ITypeConverter typeConverter, MemberMapData memberMapData, object value, CsvContext context, string message, Exception innerException) : base(context, message, innerException) + { + TypeConverter = typeConverter; + MemberMapData = memberMapData; + Value = value; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/TypeConverterOptions.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/TypeConverterOptions.cs new file mode 100644 index 0000000..4a8e51f --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/TypeConverterOptions.cs @@ -0,0 +1,157 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Options used when doing type conversion. + /// </summary> + public class TypeConverterOptions + { + private static readonly string[] defaultBooleanTrueValues = { }; + private static readonly string[] defaultBooleanFalseValues = { }; + private static readonly string[] defaultNullValues = { }; + + /// <summary> + /// Gets or sets the culture info. + /// </summary> + public CultureInfo CultureInfo { get; set; } + + /// <summary> + /// Gets or sets the date time style. + /// </summary> + public DateTimeStyles? DateTimeStyle { get; set; } + + /// <summary> + /// Gets or sets the time span style. + /// </summary> + public TimeSpanStyles? TimeSpanStyle { get; set; } + + /// <summary> + /// Gets or sets the number style. + /// </summary> + public NumberStyles? NumberStyles { get; set; } + + /// <summary> + /// Gets or sets the string format. + /// </summary> + public string[] Formats { get; set; } + + /// <summary> + /// Gets or sets the <see cref="UriKind"/>. + /// </summary> + public UriKind? UriKind { get; set; } + + /// <summary> + /// Ingore case when parsing enums. Default is false. + /// </summary> + public bool? EnumIgnoreCase { get; set; } + + /// <summary> + /// Gets the list of values that can be + /// used to represent a boolean of true. + /// </summary> + public List<string> BooleanTrueValues { get; } = new List<string>(defaultBooleanTrueValues); + + /// <summary> + /// Gets the list of values that can be + /// used to represent a boolean of false. + /// </summary> + public List<string> BooleanFalseValues { get; } = new List<string>(defaultBooleanFalseValues); + + /// <summary> + /// Gets the list of values that can be used to represent a null value. + /// </summary> + public List<string> NullValues { get; } = new List<string>(defaultNullValues); + + /// <summary> + /// Merges TypeConverterOptions by applying the values of sources in order on to each other. + /// The first object is the source object. + /// </summary> + /// <param name="sources">The sources that will be applied.</param> + /// <returns>The updated source object.</returns> + public static TypeConverterOptions? Merge(params TypeConverterOptions[] sources) + { + if (sources == null || sources.Length == 0) + { + return null; + } + + var options = sources[0]; + + for (var i = 1; i < sources.Length; i++) + { + var source = sources[i]; + + if (source == null) + { + continue; + } + + if (source.CultureInfo != null) + { + options.CultureInfo = source.CultureInfo; + } + + if (source.DateTimeStyle != null) + { + options.DateTimeStyle = source.DateTimeStyle; + } + + if (source.TimeSpanStyle != null) + { + options.TimeSpanStyle = source.TimeSpanStyle; + } + + if (source.NumberStyles != null) + { + options.NumberStyles = source.NumberStyles; + } + + if (source.Formats != null) + { + options.Formats = source.Formats; + } + + if (source.UriKind != null) + { + options.UriKind = source.UriKind; + } + + if (source.EnumIgnoreCase != null) + { + options.EnumIgnoreCase = source.EnumIgnoreCase; + } + + // Only change the values if they are different than the defaults. + // This means there were explicit changes made to the options. + + if (!defaultBooleanTrueValues.SequenceEqual(source.BooleanTrueValues)) + { + options.BooleanTrueValues.Clear(); + options.BooleanTrueValues.AddRange(source.BooleanTrueValues); + } + + if (!defaultBooleanFalseValues.SequenceEqual(source.BooleanFalseValues)) + { + options.BooleanFalseValues.Clear(); + options.BooleanFalseValues.AddRange(source.BooleanFalseValues); + } + + if (!defaultNullValues.SequenceEqual(source.NullValues)) + { + options.NullValues.Clear(); + options.NullValues.AddRange(source.NullValues); + } + } + + return options; + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/TypeConverterOptionsCache.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/TypeConverterOptionsCache.cs new file mode 100644 index 0000000..37e0d99 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/TypeConverterOptionsCache.cs @@ -0,0 +1,108 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; +using System.Collections.Generic; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Caches <see cref="TypeConverterOptions"/> for a given type. + /// </summary> + public class TypeConverterOptionsCache + { + private Dictionary<Type, TypeConverterOptions> typeConverterOptions = new Dictionary<Type, TypeConverterOptions>(); + + /// <summary> + /// Adds the <see cref="TypeConverterOptions"/> for the given <see cref="Type"/>. + /// </summary> + /// <param name="type">The type the options are for.</param> + /// <param name="options">The options.</param> + public void AddOptions(Type type, TypeConverterOptions options) + { + if (type == null) + { + throw new ArgumentNullException(nameof(type)); + } + + typeConverterOptions[type] = options ?? throw new ArgumentNullException(nameof(options)); + } + + /// <summary> + /// Adds the <see cref="TypeConverterOptions"/> for the given <see cref="Type"/>. + /// </summary> + /// <typeparam name="T">The type the options are for.</typeparam> + /// <param name="options">The options.</param> + public void AddOptions<T>(TypeConverterOptions options) + { + AddOptions(typeof(T), options); + } + + /// <summary> + /// Adds the given <see cref="TypeConverterOptions"/> to all registered types. + /// </summary> + /// <param name="options"></param> + public void AddOptions(TypeConverterOptions options) + { + foreach (var type in typeConverterOptions.Keys) + { + typeConverterOptions[type] = options; + } + } + + /// <summary> + /// Removes the <see cref="TypeConverterOptions"/> for the given type. + /// </summary> + /// <param name="type">The type to remove the options for.</param> + public void RemoveOptions(Type type) + { + if (type == null) + { + throw new ArgumentNullException(nameof(type)); + } + + typeConverterOptions.Remove(type); + } + + /// <summary> + /// Removes the <see cref="TypeConverterOptions"/> for the given type. + /// </summary> + /// <typeparam name="T">The type to remove the options for.</typeparam> + public void RemoveOptions<T>() + { + RemoveOptions(typeof(T)); + } + + /// <summary> + /// Get the <see cref="TypeConverterOptions"/> for the given <see cref="Type"/>. + /// </summary> + /// <param name="type">The type the options are for.</param> + /// <returns>The options for the given type.</returns> + public TypeConverterOptions GetOptions(Type type) + { + if (type == null) + { + throw new ArgumentNullException(); + } + + if (!typeConverterOptions.TryGetValue(type, out var options)) + { + options = new TypeConverterOptions(); + typeConverterOptions.Add(type, options); + } + + return options; + } + + /// <summary> + /// Get the <see cref="TypeConverterOptions"/> for the given <see cref="Type"/>. + /// </summary> + /// <typeparam name="T">The type the options are for.</typeparam> + /// <returns>The options for the given type.</returns> + public TypeConverterOptions GetOptions<T>() + { + return GetOptions(typeof(T)); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/UInt16Converter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/UInt16Converter.cs new file mode 100644 index 0000000..429c1b7 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/UInt16Converter.cs @@ -0,0 +1,34 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System.Globalization; +using CsvHelper.Configuration; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Converts a <see cref="ushort"/> to and from a <see cref="string"/>. + /// </summary> + public class UInt16Converter : DefaultTypeConverter + { + /// <summary> + /// Converts the string to an object. + /// </summary> + /// <param name="text">The string to convert to an object.</param> + /// <param name="row">The <see cref="IReaderRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being created.</param> + /// <returns>The object created from the string.</returns> + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + var numberStyle = memberMapData.TypeConverterOptions.NumberStyles ?? NumberStyles.Integer; + + if (ushort.TryParse(text, numberStyle, memberMapData.TypeConverterOptions.CultureInfo, out var us)) + { + return us; + } + + return base.ConvertFromString(text, row, memberMapData); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/UInt32Converter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/UInt32Converter.cs new file mode 100644 index 0000000..52c0e90 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/UInt32Converter.cs @@ -0,0 +1,34 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System.Globalization; +using CsvHelper.Configuration; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Converts a <see cref="uint"/> to and from a <see cref="string"/>. + /// </summary> + public class UInt32Converter : DefaultTypeConverter + { + /// <summary> + /// Converts the string to an object. + /// </summary> + /// <param name="text">The string to convert to an object.</param> + /// <param name="row">The <see cref="IReaderRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being created.</param> + /// <returns>The object created from the string.</returns> + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + var numberStyle = memberMapData.TypeConverterOptions.NumberStyles ?? NumberStyles.Integer; + + if (uint.TryParse(text, numberStyle, memberMapData.TypeConverterOptions.CultureInfo, out var ui)) + { + return ui; + } + + return base.ConvertFromString(text, row, memberMapData); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/UInt64Converter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/UInt64Converter.cs new file mode 100644 index 0000000..c74a8e7 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/UInt64Converter.cs @@ -0,0 +1,34 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System.Globalization; +using CsvHelper.Configuration; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Converts a <see cref="ulong"/> to and from a <see cref="string"/>. + /// </summary> + public class UInt64Converter : DefaultTypeConverter + { + /// <summary> + /// Converts the string to an object. + /// </summary> + /// <param name="text">The string to convert to an object.</param> + /// <param name="row">The <see cref="IReaderRow"/> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData"/> for the member being created.</param> + /// <returns>The object created from the string.</returns> + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + var numberStyle = memberMapData.TypeConverterOptions.NumberStyles ?? NumberStyles.Integer; + + if (ulong.TryParse(text, numberStyle, memberMapData.TypeConverterOptions.CultureInfo, out var ul)) + { + return ul; + } + + return base.ConvertFromString(text, row, memberMapData); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/UriConverter.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/UriConverter.cs new file mode 100644 index 0000000..3552180 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/TypeConversion/UriConverter.cs @@ -0,0 +1,40 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using CsvHelper.Configuration; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CsvHelper.TypeConversion +{ + /// <summary> + /// Converts a <see cref="Uri"/> to and from a <see cref="string"/>. + /// </summary> + public class UriConverter : DefaultTypeConverter + { + /// <summary> + /// Converts the <see cref="string"/> to a <see cref="Uri"/>. + /// </summary> + /// <param name="text">The string to convert to an object.</param> + /// <param name="row">The <see cref="IReaderRow" /> for the current record.</param> + /// <param name="memberMapData">The <see cref="MemberMapData" /> for the member being created.</param> + /// <returns> + /// The <see cref="Uri"/> created from the string. + /// </returns> + public override object? ConvertFromString(string? text, IReaderRow row, MemberMapData memberMapData) + { + var uriKind = memberMapData.TypeConverterOptions.UriKind ?? default; + + if (Uri.TryCreate(text, uriKind, out var uri)) + { + return uri; + } + + return base.ConvertFromString(text, row, memberMapData); + } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/ValidationException.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/ValidationException.cs new file mode 100644 index 0000000..f7f3267 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/ValidationException.cs @@ -0,0 +1,39 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper +{ + /// <summary> + /// Represents a user supplied validation failure. + /// </summary> + [Serializable] + public abstract class ValidationException : CsvHelperException + { + /// <summary> + /// Initializes a new instance of the <see cref="ValidationException"/> class. + /// </summary> + /// <param name="context">The reading context.</param> + public ValidationException(CsvContext context) : base(context) { } + + /// <summary> + /// Initializes a new instance of the <see cref="ValidationException"/> class + /// with a specified error message. + /// </summary> + /// <param name="context">The reading context.</param> + /// <param name="message">The message that describes the error.</param> + public ValidationException(CsvContext context, string message) : base(context, message) { } + + /// <summary> + /// Initializes a new instance of the <see cref="ValidationException"/> class + /// with a specified error message and a reference to the inner exception that + /// is the cause of this exception. + /// </summary> + /// <param name="context">The reading context.</param> + /// <param name="message">The error message that explains the reason for the exception.</param> + /// <param name="innerException">The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.</param> + public ValidationException(CsvContext context, string message, Exception innerException) : base(context, message, innerException) { } + } +} diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/WriterException.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/WriterException.cs new file mode 100644 index 0000000..596fa51 --- /dev/null +++ b/ThirdParty/CsvHelper-master/src/CsvHelper/WriterException.cs @@ -0,0 +1,39 @@ +// Copyright 2009-2022 Josh Close +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// https://github.com/JoshClose/CsvHelper +using System; + +namespace CsvHelper +{ + /// <summary> + /// Represents errors that occur while writing a CSV file. + /// </summary> + [Serializable] + public class WriterException : CsvHelperException + { + /// <summary> + /// Initializes a new instance of the <see cref="WriterException"/> class. + /// </summary> + /// <param name="context">The writing context.</param> + public WriterException(CsvContext context) : base(context) { } + + /// <summary> + /// Initializes a new instance of the <see cref="WriterException"/> class + /// with a specified error message. + /// </summary> + /// <param name="context">The writing context.</param> + /// <param name="message">The message that describes the error.</param> + public WriterException(CsvContext context, string message) : base(context, message) { } + + /// <summary> + /// Initializes a new instance of the <see cref="WriterException"/> class + /// with a specified error message and a reference to the inner exception that + /// is the cause of this exception. + /// </summary> + /// <param name="context">The writing context.</param> + /// <param name="message">The error message that explains the reason for the exception.</param> + /// <param name="innerException">The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.</param> + public WriterException(CsvContext context, string message, Exception innerException) : base(context, message, innerException) { } + } +} |