// 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
{
///
/// Configuration used for reading and writing CSV data.
///
public record CsvConfiguration : IReaderConfiguration, IWriterConfiguration
{
private string newLine = "\r\n";
///
public virtual bool AllowComments { get; set; }
///
public virtual BadDataFound BadDataFound { get; set; } = ConfigurationFunctions.BadDataFound;
///
public virtual int BufferSize { get; set; } = 0x1000;
///
public virtual bool CacheFields { get; set; }
///
public virtual char Comment { get; set; } = '#';
///
public virtual bool CountBytes { get; set; }
///
public virtual CultureInfo CultureInfo { get; protected set; }
///
public virtual string Delimiter { get; set; }
///
public virtual bool DetectDelimiter { get; set; }
///
public virtual GetDelimiter GetDelimiter { get; set; } = ConfigurationFunctions.GetDelimiter;
///
public virtual string[] DetectDelimiterValues { get; set; } = new[] { ",", ";", "|", "\t" };
///
public virtual bool DetectColumnCountChanges { get; set; }
///
public virtual IComparer? DynamicPropertySort { get; set; }
///
public virtual Encoding Encoding { get; set; } = Encoding.UTF8;
///
public virtual char Escape { get; set; } = '"';
///
public virtual bool ExceptionMessagesContainRawData { get; set; } = true;
///
public virtual GetConstructor GetConstructor { get; set; } = ConfigurationFunctions.GetConstructor;
///
public virtual GetDynamicPropertyName GetDynamicPropertyName { get; set; } = ConfigurationFunctions.GetDynamicPropertyName;
///
public virtual bool HasHeaderRecord { get; set; } = true;
///
public virtual HeaderValidated HeaderValidated { get; set; } = ConfigurationFunctions.HeaderValidated;
///
public virtual bool IgnoreBlankLines { get; set; } = true;
///
public virtual bool IgnoreReferences { get; set; }
///
public virtual bool IncludePrivateMembers { get; set; }
///
public virtual char[] InjectionCharacters { get; set; } = new[] { '=', '@', '+', '-', '\t', '\r' };
///
public virtual char InjectionEscapeCharacter { get; set; } = '\'';
///
public virtual InjectionOptions InjectionOptions { get; set; }
///
public bool IsNewLineSet { get; private set; }
///
public virtual bool LineBreakInQuotedFieldIsBadData { get; set; }
///
public double MaxFieldSize { get; set; }
///
public virtual MemberTypes MemberTypes { get; set; } = MemberTypes.Properties;
///
public virtual MissingFieldFound MissingFieldFound { get; set; } = ConfigurationFunctions.MissingFieldFound;
///
public virtual CsvMode Mode { get; set; }
///
public virtual string NewLine
{
get => newLine;
set
{
IsNewLineSet = true;
newLine = value;
}
}
///
public virtual PrepareHeaderForMatch PrepareHeaderForMatch { get; set; } = ConfigurationFunctions.PrepareHeaderForMatch;
///
public virtual int ProcessFieldBufferSize { get; set; } = 1024;
///
public virtual char Quote { get; set; } = '"';
///
public virtual ReadingExceptionOccurred ReadingExceptionOccurred { get; set; } = ConfigurationFunctions.ReadingExceptionOccurred;
///
public virtual ReferenceHeaderPrefix? ReferenceHeaderPrefix { get; set; }
///
public ShouldQuote ShouldQuote { get; set; } = ConfigurationFunctions.ShouldQuote;
///
public virtual ShouldSkipRecord? ShouldSkipRecord { get; set; }
///
public virtual ShouldUseConstructorParameters ShouldUseConstructorParameters { get; set; } = ConfigurationFunctions.ShouldUseConstructorParameters;
///
public virtual TrimOptions TrimOptions { get; set; }
///
public virtual bool UseNewObjectForNullReferenceMembers { get; set; } = true;
///
public virtual char[] WhiteSpaceChars { get; set; } = new char[] { ' ' };
///
/// Initializes a new instance of the class
/// using the given . Since
/// uses for it's default, the given
/// will be used instead.
///
/// The culture information.
/// The type that contains the configuration attributes.
/// This will call automatically.
public CsvConfiguration(CultureInfo cultureInfo, Type? attributesType = null)
{
CultureInfo = cultureInfo;
Delimiter = cultureInfo.TextInfo.ListSeparator;
if (attributesType != null)
{
ApplyAttributes(attributesType);
}
}
///
/// Validates the configuration.
///
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.");
}
///
/// Applies class level attribute to configuration.
///
/// Type with attributes.
public CsvConfiguration ApplyAttributes()
{
return ApplyAttributes(typeof(T));
}
///
/// Applies class level attribute to configuration.
///
/// Type with attributes.
public CsvConfiguration ApplyAttributes(Type type)
{
var attributes = type.GetCustomAttributes().OfType();
foreach (var attribute in attributes)
{
attribute.ApplyTo(this);
}
return this;
}
}
}