mirror of
https://github.com/mgroves/MonodroidStockPortfolio.git
synced 2025-01-06 03:00:18 +00:00
353 lines
9.5 KiB
C#
353 lines
9.5 KiB
C#
|
#region " <20> Copyright 2005-07 to Marcos Meli - http://www.marcosmeli.com.ar"
|
|||
|
|
|||
|
// Errors, suggestions, contributions, send a mail to: marcos@filehelpers.com.
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
using System;
|
|||
|
using System.Reflection;
|
|||
|
using System.Text;
|
|||
|
|
|||
|
namespace FileHelpers
|
|||
|
{
|
|||
|
|
|||
|
|
|||
|
/// <summary>Base class for all Field Types. Implements all the basic functionality of a field in a typed file.</summary>
|
|||
|
internal abstract class FieldBase
|
|||
|
{
|
|||
|
#region " Private & Internal Fields "
|
|||
|
|
|||
|
private static Type strType = typeof (string);
|
|||
|
|
|||
|
internal Type mFieldType;
|
|||
|
internal bool mIsStringField;
|
|||
|
internal FieldInfo mFieldInfo;
|
|||
|
|
|||
|
internal TrimMode mTrimMode = TrimMode.None;
|
|||
|
internal Char[] mTrimChars = null;
|
|||
|
internal bool mIsOptional = false;
|
|||
|
internal bool mNextIsOptional = false;
|
|||
|
internal bool mInNewLine = false;
|
|||
|
|
|||
|
internal bool mIsFirst = false;
|
|||
|
internal bool mIsLast = false;
|
|||
|
internal bool mTrailingArray = false;
|
|||
|
|
|||
|
|
|||
|
internal object mNullValue = null;
|
|||
|
//internal bool mNullValueOnWrite = false;
|
|||
|
|
|||
|
#if NET_2_0
|
|||
|
private bool mIsNullableType = false;
|
|||
|
#endif
|
|||
|
#endregion
|
|||
|
|
|||
|
#region " Constructor "
|
|||
|
|
|||
|
protected FieldBase(FieldInfo fi)
|
|||
|
{
|
|||
|
mFieldInfo = fi;
|
|||
|
mFieldType = mFieldInfo.FieldType;
|
|||
|
mIsStringField = mFieldType == strType;
|
|||
|
|
|||
|
object[] attribs = fi.GetCustomAttributes(typeof (FieldConverterAttribute), true);
|
|||
|
|
|||
|
if (attribs.Length > 0)
|
|||
|
{
|
|||
|
FieldConverterAttribute conv = (FieldConverterAttribute)attribs[0];
|
|||
|
mConvertProvider = conv.Converter;
|
|||
|
conv.ValidateTypes(mFieldInfo);
|
|||
|
}
|
|||
|
else
|
|||
|
mConvertProvider = ConvertHelpers.GetDefaultConverter(fi.Name, mFieldType);
|
|||
|
|
|||
|
if (mConvertProvider != null)
|
|||
|
mConvertProvider.mDestinationType = fi.FieldType;
|
|||
|
|
|||
|
attribs = fi.GetCustomAttributes(typeof (FieldNullValueAttribute), true);
|
|||
|
|
|||
|
if (attribs.Length > 0)
|
|||
|
{
|
|||
|
mNullValue = ((FieldNullValueAttribute) attribs[0]).NullValue;
|
|||
|
// mNullValueOnWrite = ((FieldNullValueAttribute) attribs[0]).NullValueOnWrite;
|
|||
|
|
|||
|
if (mNullValue != null)
|
|||
|
{
|
|||
|
if (! mFieldType.IsAssignableFrom(mNullValue.GetType()))
|
|||
|
throw new BadUsageException("The NullValue is of type: " + mNullValue.GetType().Name +
|
|||
|
" that is not asignable to the field " + mFieldInfo.Name + " of type: " +
|
|||
|
mFieldType.Name);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
#if NET_2_0
|
|||
|
mIsNullableType = mFieldType.IsValueType &&
|
|||
|
mFieldType.IsGenericType &&
|
|||
|
mFieldType.GetGenericTypeDefinition() == typeof(Nullable<>);
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
|
|||
|
private static char[] WhitespaceChars = new char[]
|
|||
|
{
|
|||
|
'\t', '\n', '\v', '\f', '\r', ' ', '\x00a0', '\u2000', '\u2001', '\u2002', '\u2003', '\u2004', '\u2005', '\u2006', '\u2007', '\u2008',
|
|||
|
'\u2009', '\u200a', '\u200b', '\u3000', '\ufeff'
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
#region " MustOverride (String Handling) "
|
|||
|
|
|||
|
protected abstract ExtractedInfo ExtractFieldString(LineInfo line);
|
|||
|
|
|||
|
protected abstract void CreateFieldString(StringBuilder sb, object fieldValue);
|
|||
|
|
|||
|
protected string BaseFieldString(object fieldValue)
|
|||
|
{
|
|||
|
if (mConvertProvider == null)
|
|||
|
{
|
|||
|
if (fieldValue == null)
|
|||
|
return string.Empty;
|
|||
|
else
|
|||
|
return fieldValue.ToString();
|
|||
|
|
|||
|
// else if (mNullValueOnWrite && fieldValue.Equals(mNullValue))
|
|||
|
// res = string.Empty;
|
|||
|
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return mConvertProvider.FieldToString(fieldValue);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
protected int mCharsToDiscard = 0;
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
internal ConverterBase mConvertProvider;
|
|||
|
|
|||
|
#region " ExtractValue "
|
|||
|
|
|||
|
// object[] values, int index, ForwardReader reader
|
|||
|
internal object ExtractValue(LineInfo line)
|
|||
|
{
|
|||
|
//-> extract only what I need
|
|||
|
|
|||
|
if (this.mInNewLine == true)
|
|||
|
{
|
|||
|
if (line.EmptyFromPos() == false)
|
|||
|
throw new BadUsageException("Text '" + line.CurrentString +
|
|||
|
"' found before the new line of the field: " + mFieldInfo.Name +
|
|||
|
" (this is not allowed when you use [FieldInNewLine])");
|
|||
|
|
|||
|
line.ReLoad(line.mReader.ReadNextLine());
|
|||
|
|
|||
|
if (line.mLineStr == null)
|
|||
|
throw new BadUsageException("End of stream found parsing the field " + mFieldInfo.Name +
|
|||
|
". Please check the class record.");
|
|||
|
}
|
|||
|
|
|||
|
ExtractedInfo info = ExtractFieldString(line);
|
|||
|
if (info.mCustomExtractedString == null)
|
|||
|
line.mCurrentPos = info.ExtractedTo + 1;
|
|||
|
|
|||
|
line.mCurrentPos += mCharsToDiscard; //total;
|
|||
|
|
|||
|
return AssignFromString(info, line);
|
|||
|
|
|||
|
|
|||
|
//-> discard the part that I use
|
|||
|
|
|||
|
|
|||
|
//TODO: Uncoment this for Quoted Handling
|
|||
|
// if (info.NewRestOfLine != null)
|
|||
|
// {
|
|||
|
// if (info.NewRestOfLine.Length < CharsToDiscard())
|
|||
|
// return info.NewRestOfLine;
|
|||
|
// else
|
|||
|
// return info.NewRestOfLine.Substring(CharsToDiscard());
|
|||
|
// }
|
|||
|
// else
|
|||
|
// {
|
|||
|
// int total;
|
|||
|
// if (info.CharsRemoved >= line.mLine.Length)
|
|||
|
// total = line.mLine.Length;
|
|||
|
// else
|
|||
|
// total = info.CharsRemoved + CharsToDiscard();
|
|||
|
|
|||
|
//return buffer.Substring(total);
|
|||
|
// }
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
#region " AssignFromString "
|
|||
|
|
|||
|
internal object AssignFromString(ExtractedInfo fieldString, LineInfo line)
|
|||
|
{
|
|||
|
object val;
|
|||
|
|
|||
|
switch (mTrimMode)
|
|||
|
{
|
|||
|
case TrimMode.None:
|
|||
|
break;
|
|||
|
|
|||
|
case TrimMode.Both:
|
|||
|
fieldString.TrimBoth(mTrimChars);
|
|||
|
break;
|
|||
|
|
|||
|
case TrimMode.Left:
|
|||
|
fieldString.TrimStart(mTrimChars);
|
|||
|
break;
|
|||
|
|
|||
|
case TrimMode.Right:
|
|||
|
fieldString.TrimEnd(mTrimChars);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
try
|
|||
|
{
|
|||
|
|
|||
|
if (mConvertProvider == null)
|
|||
|
{
|
|||
|
if (mIsStringField)
|
|||
|
val = fieldString.ExtractedString();
|
|||
|
else
|
|||
|
{
|
|||
|
// Trim it to use Convert.ChangeType
|
|||
|
fieldString.TrimBoth(WhitespaceChars);
|
|||
|
|
|||
|
if (fieldString.Length == 0)
|
|||
|
{
|
|||
|
// Empty stand for null
|
|||
|
val = GetNullValue();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
val = Convert.ChangeType(fieldString.ExtractedString(), mFieldType, null);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
else
|
|||
|
{
|
|||
|
if (mConvertProvider.CustomNullHandling == false &&
|
|||
|
fieldString.HasOnlyThisChars(WhitespaceChars))
|
|||
|
{
|
|||
|
val = GetNullValue();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
string from = fieldString.ExtractedString();
|
|||
|
val = mConvertProvider.StringToField(from);
|
|||
|
|
|||
|
if (val == null)
|
|||
|
val = GetNullValue();
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return val;
|
|||
|
}
|
|||
|
catch (ConvertException ex)
|
|||
|
{
|
|||
|
throw ConvertException.ReThrowException(ex, mFieldInfo.Name, line.mReader.LineNumber, fieldString.ExtractedFrom + 1);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private object GetNullValue()
|
|||
|
{
|
|||
|
if (mNullValue == null)
|
|||
|
{
|
|||
|
if (mFieldType.IsValueType)
|
|||
|
{
|
|||
|
|
|||
|
#if NET_2_0
|
|||
|
if ( mIsNullableType )
|
|||
|
return null;
|
|||
|
|
|||
|
throw new BadUsageException("Null Value found for the field '" + mFieldInfo.Name + "' in the class '" +
|
|||
|
mFieldInfo.DeclaringType.Name +
|
|||
|
"'. You must specify a FieldNullValue attribute because this is a ValueType and can<61>t be null or you can use the Nullable Types feature of the .NET framework.");
|
|||
|
#else
|
|||
|
throw new BadUsageException("Null Value found for the field '" + mFieldInfo.Name + "' in the class '" +
|
|||
|
mFieldInfo.DeclaringType.Name +
|
|||
|
"'. You must specify a FieldNullValueAttribute because this is a ValueType and can<61>t be null.");
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
}
|
|||
|
else
|
|||
|
return null;
|
|||
|
}
|
|||
|
else
|
|||
|
return mNullValue;
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region " CreateValueForField "
|
|||
|
|
|||
|
public object CreateValueForField(object fieldValue)
|
|||
|
{
|
|||
|
object val = null;
|
|||
|
|
|||
|
if (fieldValue == null)
|
|||
|
{
|
|||
|
if (mNullValue == null)
|
|||
|
{
|
|||
|
if (mFieldType.IsValueType)
|
|||
|
throw new BadUsageException("Null Value found. You must specify a NullValueAttribute in the " + mFieldInfo.Name +
|
|||
|
" field of type " + mFieldInfo.FieldType.Name + ", because this is a ValueType.");
|
|||
|
else
|
|||
|
val = null;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
val = mNullValue;
|
|||
|
}
|
|||
|
}
|
|||
|
else if (mFieldType == fieldValue)
|
|||
|
val = fieldValue;
|
|||
|
else
|
|||
|
{
|
|||
|
if (mConvertProvider == null)
|
|||
|
val = Convert.ChangeType(fieldValue, mFieldType, null);
|
|||
|
else
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
val = Convert.ChangeType(fieldValue, mFieldType, null);
|
|||
|
}
|
|||
|
catch
|
|||
|
{
|
|||
|
val = mConvertProvider.StringToField(fieldValue.ToString());
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return val;
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region " AssignToString "
|
|||
|
|
|||
|
internal void AssignToString(StringBuilder sb, object fieldValue)
|
|||
|
{
|
|||
|
if (this.mInNewLine == true)
|
|||
|
sb.Append(StringHelper.NewLine);
|
|||
|
|
|||
|
CreateFieldString(sb, fieldValue);
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
}
|
|||
|
}
|