public ExtractedInfo(LineInfo line, int extractTo)
 {
     mLine = line;
     ExtractedFrom = line.mCurrentPos;
     ExtractedTo = extractTo - 1;
     //CharsRemoved = ExtractedTo - ExtractedFrom + 1;
     //ExtraLines = 0;
     //	NewRestOfLine = null;
 }
        protected override ExtractedInfo ExtractFieldString(LineInfo line)
        {
            if (mIsOptional && line.IsEOL())
                return ExtractedInfo.Empty;


            if (mQuoteChar == '\0')
                return BasicExtractString(line);
            else
            {
                //TODO: UnComment and Fix

                if (mTrimMode == TrimMode.Both || mTrimMode == TrimMode.Left)
                {
                    //int pos = line.mCurrentPos;
                    line.TrimStart(mTrimChars);
//					from2 = from.TrimStart(mTrimChars);
                    //res.CharsRemoved = line.mCurrentPos - pos;
                }

                var quotedStr = mQuoteChar.ToString();
                if (line.StartsWith(quotedStr))
                {
//					ExtractedInfo res = null;
//					res = new ExtractedInfo(line, line.mCurrentPos);

                    return StringHelper.ExtractQuotedString(line, mQuoteChar, mQuoteMultiline == MultilineMode.AllowForBoth || mQuoteMultiline == MultilineMode.AllowForRead);
//					if (mQuoteMultiline == MultilineMode.AllowForBoth || mQuoteMultiline == MultilineMode.AllowForRead)
//					{
//
//						//res.ExtractedString = ei.ExtractedString;
//						//res.CharsRemoved += ei.CharsRemoved;
//						//res.ExtraLines = ei.ExtraLines;
//						//res.NewRestOfLine = ei.NewRestOfLine;
//					}
//					else
//					{
//						return StringHelper.ExtractQuotedString(from2, mQuoteChar, out index);
//						//res.CharsRemoved += index;
//					}

                    //	return res;
                }
                else
                {
                    if (mQuoteMode == QuoteMode.OptionalForBoth || mQuoteMode == QuoteMode.OptionalForRead)
                        return BasicExtractString(line);
                    else if (line.StartsWithTrim(quotedStr))
                        throw new BadUsageException("The field '" + mFieldInfo.Name + "' has spaces before the QuotedChar at line " + line.mReader.LineNumber.ToString() + ". Use the TrimAttribute to by pass this error. Field String: " + line.CurrentString);
                    else
                        throw new BadUsageException("The field '" + mFieldInfo.Name + "' not begin with the QuotedChar at line " + line.mReader.LineNumber.ToString() + ". You can use FieldQuoted(QuoteMode.OptionalForRead) to allow optional quoted field.. Field String: " + line.CurrentString);
                }
            }
        }
        protected override ExtractedInfo ExtractFieldString(LineInfo line)
        {
            if (line.CurrentLength == 0)
            {
                if (mIsOptional)
                    return ExtractedInfo.Empty;
                else
                    throw new BadUsageException("End Of Line found processing the field: " + mFieldInfo.Name + " at line " + line.mReader.LineNumber.ToString() + ". (You need to mark it as [FieldOptional] if you want to avoid this exception)");
            }

            ExtractedInfo res;

            if (line.CurrentLength < mFieldLength)
                if (mFixedMode == FixedMode.AllowLessChars || mFixedMode == FixedMode.AllowVariableLength)
                    res = new ExtractedInfo(line);
                else
                    throw new BadUsageException("The string '" + line.CurrentString + "' (length " + line.CurrentLength.ToString() + ") at line " + line.mReader.LineNumber.ToString() + " has less chars than the defined for " + mFieldInfo.Name + " (" + mFieldLength.ToString() + "). You can use the [FixedLengthRecord(FixedMode.AllowLessChars)] to avoid this problem.");
            else if (mIsLast && line.CurrentLength > mFieldLength && mFixedMode != FixedMode.AllowMoreChars && mFixedMode != FixedMode.AllowVariableLength)
                throw new BadUsageException("The string '" + line.CurrentString + "' (length " + line.CurrentLength.ToString() + ") at line " + line.mReader.LineNumber.ToString() + " has more chars than the defined for the last field " + mFieldInfo.Name + " (" + mFieldLength.ToString() + ").You can use the [FixedLengthRecord(FixedMode.AllowMoreChars)] to avoid this problem.");
            else
                res = new ExtractedInfo(line, line.mCurrentPos + mFieldLength);

            return res;
        }
        private ExtractedInfo BasicExtractString(LineInfo line)
        {
            ExtractedInfo res;

            if (mIsLast)
                res = new ExtractedInfo(line);
            else
            {
                int sepPos;

                sepPos = line.IndexOf(mSeparator);

                if (sepPos == -1)
                {
                    if (mNextIsOptional == false)
                    {
                        string msg = null;

                        if (mIsFirst && line.EmptyFromPos())
                            msg = "The line " + line.mReader.LineNumber.ToString() + " is empty. Maybe you need to use the attribute [IgnoreEmptyLines] in your record class.";
                        else
                            msg = "The delimiter '" + mSeparator + "' can´t be found after the field '" + mFieldInfo.Name + "' at line " + line.mReader.LineNumber.ToString() + " (the record has less fields, the delimiter is wrong or the next field must be marked as optional).";

                        throw new FileHelpersException(msg);
                    }
                    else
                        sepPos = line.mLine.Length - 1;
                }

                res = new ExtractedInfo(line, sepPos);
            }
            return res;
        }
        internal object StringToRecord(LineInfo line)
        {
            if (MustIgnoreLine(line.mLineStr))
                return null;


            var mValues = new object[mFieldCount];

            // array that holds the fields values

            for (var i = 0; i < mFieldCount; i++)
            {
                mValues[i] = mFields[i].ExtractValue(line);
            }

            CreateAssingMethods();

            try
            {
                // Asign all values via dinamic method that creates an object and assign values
                return mCreateHandler(mValues);
            }
            catch (InvalidCastException)
            {
                // Occurrs when the a custom converter returns an invalid value for the field.
                for (var i = 0; i < mFieldCount; i++)
                {
                    if (mValues[i] != null && ! mFields[i].mFieldType.IsInstanceOfType(mValues[i]))
                        throw new ConvertException(null, mFields[i].mFieldType, mFields[i].mFieldInfo.Name, line.mReader.LineNumber, -1, "The converter for the field: " + mFields[i].mFieldInfo.Name + " returns an object of Type: " + mValues[i].GetType().Name + " and the field is of type: " + mFields[i].mFieldType.Name);
                }
                return null;
            }
        }
        internal static ExtractedInfo ExtractQuotedString(LineInfo line, char quoteChar, bool allowMultiline)
        {
            //			if (line.mReader == null)
            //				throw new BadUsageException("The reader can´t be null");

            if (line.IsEOL())
                throw new BadUsageException("An empty String found and can be parsed like a QuotedString try to use SafeExtractQuotedString");

            if (line.mLine[line.mCurrentPos] != quoteChar)
                throw new BadUsageException("The source string not begins with the quote char: " + quoteChar);

            var res = new StringBuilder(32);
            //int lines = 0;

            var firstFound = false;

            var i = line.mCurrentPos + 1;
            //bool mustContinue = true;

            while (line.mLineStr != null)
            {
                while (i < line.mLine.Length)
                {
                    if (line.mLine[i] == quoteChar)
                    {
                        if (firstFound)
                        {
                            // Is an escaped quoted char
                            res.Append(quoteChar);
                            firstFound = false;
                        }
                        else
                        {
                            firstFound = true;
                        }
                    }
                    else
                    {
                        if (firstFound)
                        {
                            // This was the end of the string

                            line.mCurrentPos = i;
                            return new ExtractedInfo(res.ToString());
//							ExtractedInfo ei = ;
//							return ei;
                        }
                        else
                        {
                            res.Append(line.mLine[i]);
                        }
                    }
                    i++;
                }


                if (firstFound)
                {
                    line.mCurrentPos = i;
                    return new ExtractedInfo(res.ToString());
                }
                else
                {
                    if (allowMultiline == false)
                        throw new BadUsageException("The current field has an UnClosed quoted string. Complete line: " + res);

                    line.ReadNextLine();
                    res.Append(NewLine);
                    //lines++;
                    i = 0;
                }
            }

            throw new BadUsageException("The current field has an unclosed quoted string. Complete Filed String: " + res);
        }
        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
                    {
                        var from = fieldString.ExtractedString();
                        val = mConvertProvider.StringToField(from);

                        if (val == null)
                            val = GetNullValue();
                    }
                }

                return val;
            }
            catch (ConvertException ex)
            {
                var e = ConvertException.ReThrowException(ex, mFieldInfo.Name, line.mReader.LineNumber, fieldString.ExtractedFrom + 1);
                throw e;
            }
        }
// object[] values, int index, ForwardReader reader
        internal object ExtractValue(LineInfo line)
        {
            //-> extract only what I need

            if (mInNewLine)
            {
                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.");
            }

            var 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);
//			}
        }
 protected abstract ExtractedInfo ExtractFieldString(LineInfo line);