private static IList ReadRawCsvRow(TextReader reader)
{
IList retVal = new List<string>();
StringBuilder currentValue = new StringBuilder();
bool insideQuotes = false;
bool keepGoing = true;
bool eof = false;
bool wasQuoted = false;
while (keepGoing)
{
int intChar = reader.Read();
if (intChar == -1)
{
// done reading.
keepGoing = false;
eof = true;
}
else
{
char nextChar = (char) intChar;
switch (nextChar)
{
case '"':
if (insideQuotes)
{
// This either means the end of the quotes, or it means an
// escaped quote.
int peekedChar = reader.Peek();
if (peekedChar == -1)
{
// No more chars, can't be an escaped quote.
insideQuotes = false;
}
else
{
if (((char)peekedChar) == '"')
{
// Two quotes in a row means an escaped quote.
currentValue.Append('"');
// Since we verified the next char is a quote,
// pull it off the reader.
reader.Read();
}
else
{
// Next char is not another quote, so this is
// the closing quote.
insideQuotes = false;
}
}
}
// If we're NOT inside quotes, we are now.
else
{
insideQuotes = true;
wasQuoted = true;
}
break;
case ',':
// If inside quotes, it's a normal char.
if (insideQuotes)
{
currentValue.Append(nextChar);
}
else
{
// Not inside quotes, it means the break between values.
// If the value was quoted, add it exactly as is.
if (wasQuoted)
{
retVal.Add(currentValue.ToString());
}
else
{
// If not quoted, trim it.
string val = currentValue.ToString().Trim();
if (val.Length == 0)
{
// If it trimmed to nothing, assume null.
retVal.Add(null);
}
else
{
retVal.Add(val);
}
}
currentValue.Remove(0, currentValue.Length);
}
break;
case '\r':
// If we're NOT inside quotes, ignore it as whitespace.
if (insideQuotes)
{
currentValue.Append(nextChar);
}
break;
case '\n':
// If we're NOT inside quotes, this indicates the end of a row.
if (insideQuotes)
{
currentValue.Append(nextChar);
}
else
{
keepGoing = false;
}
break;
default:
// Any other char, just add it to the current token.
currentValue.Append(nextChar);
break;
}
}
}
// Check if we had just finished a value when we ran out of data
if (currentValue.Length > 0)
{
retVal.Add(currentValue.ToString().Trim());
}
// If we read nothing and we're at the end of the file, return null
// to indicate that.
if (eof && retVal.Count == 0)
{
retVal = null;
}
return retVal;
}