private static IEnumerable<KeyValuePair<string, string>> ParsePairs(string str)
{
Debug.Assert(str != null);
int lastObjectStart = 0;
bool inQuote = false;
bool valueIsInQuote = false;
bool inKey = true;
bool lastWasBackslash = false;
string lastKey = "";
for (int n = 0; n < str.Length; n++)
{
if (inKey)
{
if (str[n] == ';')
{
if (n - lastObjectStart == 0)
{
// handle: separator occours twice
lastObjectStart++;
}
else
{
// separator occours in key name
throw new ArgumentException("invalid char ';' in key found.");
}
}
else if (str[n] == '=')
{
lastKey = str.Substring(lastObjectStart, n - lastObjectStart).Trim();
lastObjectStart = n + 1;
inKey = false;
}
}
else
{
if (inQuote)
{
if (str[n] == '"' && !lastWasBackslash)
{
inQuote = false;
valueIsInQuote = true;
}
else if (str[n] == '\\')
{
lastWasBackslash = !lastWasBackslash;
}
else
{
lastWasBackslash = false;
}
}
else
{
if (str[n] == '=')
{
throw new ArgumentException("invalid char '=' in value found.");
}
else if (str[n] == '"')
{
if (n - lastObjectStart > 0)
{
throw new ArgumentException("invalid char '\"' in value found.");
}
inQuote = true;
lastObjectStart++;
}
else if (str[n] == ';')
{
yield return new KeyValuePair<string, string>(lastKey, str.Substring(lastObjectStart, n - lastObjectStart - (valueIsInQuote ? 1 : 0)).Trim());
lastObjectStart = n + 1;
inKey = true;
valueIsInQuote = false;
lastKey = "";
}
}
}
}
if (str.Length - lastObjectStart > 0)
{
if (inQuote)
{
throw new ArgumentException("string not closed");
}
else
{
yield return new KeyValuePair<string, string>(lastKey, str.Substring(lastObjectStart, str.Length - lastObjectStart - (valueIsInQuote ? 1 : 0)).Trim());
}
}
}