SkipPastCRLF(IReadChunkBytes Source) {
int BytesRead;
int Current;
bool Escape;
bool InQS;
bool HaveCR;
bool HaveLF;
BytesRead = 0;
Escape = false;
InQS = false;
HaveCR = false;
HaveLF = false;
GlobalLog.Enter("SkipPastCRLF");
// Loop through the buffer, looking at each byte. We have a
// pseudo state machine going here, and the action we take
// with each byte depends on the state.
Current = Source.NextByte;
BytesRead++;
while (Current != -1) {
// If we saw a CR last time, it must be followed by an unescaped
// LF, otherwise it's an error. If it is followed by a LF, and
// we're not in a quoted string, then we've found our termination.
// If we are in a quoted string, this could be the start of a LWS
// production. Remember that, and next time through we'll
// check to make sure that this is an LWS production.
if (HaveCR) {
if (Current != '\n') {
// CR w/o a trailing LF is an error.
GlobalLog.Leave("SkipPastCRLF", 0);
return 0;
}
else {
if (Escape) {
// We have an CR, but they're trying to escape the
// LF. This is an error.
GlobalLog.Leave("SkipPastCRLF", 0);
return 0;
}
// If we're not in a quoted string, we're done.
if (!InQS) {
// We've found the terminating CRLF pair.
GlobalLog.Leave("SkipPastCRLF", 0);
return BytesRead;
}
else {
// We're in a quoted string, so set HaveLF
// so we remember to check for a LWS production next
// time.
HaveLF = true;
// We've proceessed this byte, set Escape so we don't
// do it again.
Escape = true;
}
}
// We're past the CR now, don't remember it any more.
HaveCR = false;
}
else {
// If HaveLF is set, we must be in a quoted string and have
// seen a CRLF pair. Make sure this character is a space or
// tab.
if (HaveLF) {
// We have a LF. For this to be valid, we have to have a
// space or tab be the next character.
if (Current != ' ' && Current != '\t') {
// Not a continuation, so return an error.
GlobalLog.Leave("SkipPastCRLF", 0);
return 0;
}
Escape = true; // Don't process this byte again.
HaveLF = false;
}
}
// If we're escaping, just skip the next character.
if (!Escape) {
switch (Current) {
case '"':
if (InQS) {
InQS = false;
}
else {
InQS = true;
}
break;
case '\\':
if (InQS) {
Escape = true;
}
break;
case '\r':
HaveCR = true;
break;
case '\n':
// If we get here, we have a LF without a preceding CR.
// This is an error.
GlobalLog.Leave("SkipPastCRLF", 0);
return 0;
default:
break;
}
}
else {
// We're escaping, do nothing but rest the Escape flag.
Escape = false;
}
Current = Source.NextByte;
BytesRead++;
}
// If we get here, we never saw the terminating CRLF, so return -1.
GlobalLog.Leave("SkipPastCRLF", -1);
return -1;
}