void ParseMultipartValue(Stream stream, char[] boundary)
{
var state = ReadMultipartState.ReadingBoundary;
var headerBuffer = new MemoryStream();
var buffer = new MemoryStream();
var bufferInReadingBoundary = new MemoryStream();
var boundaryLength = 0;
var lastBufferIsString = false;
string lastName = null;
int intB;
while ((intB = stream.ReadByte()) != -1)
{
// checking boundary
var b = (byte)intB;
if (b == boundary[boundaryLength++])
{
if (boundaryLength == boundary.Length)
{
// matched, go to next sequence.
boundaryLength = 0;
bufferInReadingBoundary.Position = 0;
state = ReadMultipartState.ReadingHeader;
// flush buffer
if (buffer.Position != 0)
{
if (lastName == null) break;
var key = lastName;
if (lastBufferIsString)
{
var bytes = buffer.GetBuffer();
var value = Encoding.UTF8.GetString(bytes, 0, (int)buffer.Position).Trim('\r', '\n');
object result;
if (values.TryGetValue(key, out result))
{
if (result is string)
{
// second
values[key] = new List<string>() { (string)result, value };
}
else
{
// third
((List<string>)result).Add(value);
}
}
else
{
// first
values[key] = value;
}
}
else
{
var bytes = buffer.GetBuffer();
var preSkipCount = 0;
var postSkipCount = 0;
if (bytes.Length > 4)
{
if (bytes[0] == '\r')
{
preSkipCount++;
if (bytes[1] == '\n') preSkipCount++;
}
if (bytes[buffer.Position - 1] == '\n')
{
postSkipCount++;
if (bytes[buffer.Position - 2] == '\r') postSkipCount++;
}
}
var value = new byte[buffer.Position - preSkipCount - postSkipCount];
Buffer.BlockCopy(bytes, preSkipCount, value, 0, value.Length);
object result;
if (values.TryGetValue(key, out result))
{
if (result is byte[])
{
// second
values[key] = new List<byte[]>() { (byte[])result, value };
}
else
{
// third
((List<byte[]>)result).Add(value);
}
}
else
{
// first
values[key] = value;
}
}
lastBufferIsString = false;
lastName = null;
buffer.Position = 0;
}
continue;
}
else
{
bufferInReadingBoundary.WriteByte(b);
}
// check new boundary
continue;
}
else
{
if (bufferInReadingBoundary.Position != 0)
{
var bufArray = bufferInReadingBoundary.GetBuffer();
for (int i = 0; i < bufferInReadingBoundary.Position; i++)
{
buffer.WriteByte(bufArray[i]);
}
bufferInReadingBoundary.Position = 0;
}
boundaryLength = 0;
}
if (state == ReadMultipartState.ReadingHeader)
{
// ReadLine
headerBuffer.WriteByte(b);
bool foundR = false;
while ((intB = stream.ReadByte()) != -1)
{
b = (byte)intB;
if (b == '\r')
{
foundR = true;
continue;
}
else if (foundR && b == '\n')
{
foundR = false;
// finish buffer.
var stringBuffer = headerBuffer.GetBuffer();
var headerString = Encoding.UTF8.GetString(stringBuffer, 0, (int)headerBuffer.Position).Trim('\r', '\n');
if (headerString.StartsWith("Content-Type") && headerString.Contains("text/plain"))
{
lastBufferIsString = true;
}
if (headerString.StartsWith("Content-Disposition"))
{
lastName = nameRegex.Match(headerString).Groups[1].Value;
state = ReadMultipartState.ReadingValue;
}
headerBuffer.Position = 0;
break;
}
headerBuffer.WriteByte(b);
}
}
else
{
buffer.WriteByte(b);
}
}
}
}