private void TryProcess(MultiPartHandler multiPartHandler, bool skipFirstCrNl) { DelimiterDetector detector = new DelimiterDetector(_boundary); if (skipFirstCrNl) { byte[] crnl = new byte[]{0x0d,0x0a}; // 0x0d = cr; 0x0a = nl detector.update(crnl, 0, 2); } DelimiterIndicator indicator = findFirstDelimiterIndicator(detector); if (null == indicator) { BaseException e = new BaseException(this, "null == indicator; expected delimiter at start of stream"); throw e; } if (!(indicator is DelimiterFound)) { log.error("unimplemented: support for `DelimiterIndicator` types that are not `DelimiterFound`"); throw new BaseException(this, "!(indicator is DelimiterFound); indicator.GetType().Name", indicator.GetType().Name); } DelimiterFound delimiterFound = (DelimiterFound)indicator; _currentOffset = delimiterFound.EndOfDelimiter; while (!delimiterFound.IsCloseDelimiter) { delimiterFound = ProcessPart(multiPartHandler, detector); } multiPartHandler.FoundCloseDelimiter(); while (0 != _contentRemaining) { FillBuffer(); } }
// can return null if not indicator was found (partial or complete) private DelimiterFound findFirstDelimiterIndicator(DelimiterDetector detector) { if (_currentOffset == _bufferEnd) { FillBuffer(); } DelimiterIndicator indicator = detector.update(_buffer, _currentOffset, _bufferEnd); if (null == indicator) { throw new BaseException(this, "null == indicator, could not find first delimiter; _boundary = '{0}'", _boundary); } if (!(indicator is DelimiterFound) ) { log.error("unimplemented: support for `DelimiterIndicator` types that are not `DelimiterFound`"); throw new BaseException(this, "!(indicator is DelimiterFound); indicator.GetType().Name", indicator.GetType().Name); } return (DelimiterFound)indicator; }
private DelimiterFound TryProcessPart(PartHandler partHandler, DelimiterDetector detector) { MutableData stringBuffer = new MutableData(); String line = ReadLine(stringBuffer); while ( 0 != line.Length ) { int firstColon = line.IndexOf(":"); if (-1 == firstColon) { throw new BaseException(this, "-1 == firstColon; line = '{0}'", line); } String name = line.Substring(0, firstColon).ToLower(); // headers are case insensitive String value = line.Substring(firstColon + 1).Trim(); partHandler.HandleHeader(name, value); line = ReadLine(stringBuffer); } PartialDelimiterMatched partialDelimiterMatched = null; bool partCompleted = false; while (!partCompleted) { DelimiterIndicator delimiterIndicator = detector.update(_buffer, _currentOffset, _bufferEnd); // nothing detected ? if (null == delimiterIndicator) { // write existing partial match (if it exists) { WritePartialDelimiter(partialDelimiterMatched, partHandler); partialDelimiterMatched = null; } int length = _bufferEnd - _currentOffset; partHandler.HandleBytes(_buffer, _currentOffset, length); FillBuffer(); continue; } if (delimiterIndicator is DelimiterFound) { DelimiterFound delimiterFound = (DelimiterFound)delimiterIndicator; // more content to add ? if (!delimiterFound.CompletesPartialMatch) { // write existing partial match (if it exists) { WritePartialDelimiter(partialDelimiterMatched, partHandler); partialDelimiterMatched = null; } int length = delimiterFound.StartOfDelimiter - _currentOffset; partHandler.HandleBytes(_buffer, _currentOffset, length); } else // delimiterFound completesPartialMatch { partialDelimiterMatched = null; } _currentOffset = delimiterFound.EndOfDelimiter; partHandler.PartCompleted(); partCompleted = true; // not required, but signalling intent return delimiterFound; } if (delimiterIndicator is PartialDelimiterMatched) { // write existing partial match (if it exists) { WritePartialDelimiter(partialDelimiterMatched, partHandler); } partialDelimiterMatched = (PartialDelimiterMatched)delimiterIndicator; byte[] matchingBytes = partialDelimiterMatched.MatchingBytes; int startOfMatch = _bufferEnd - matchingBytes.Length; if (startOfMatch < _currentOffset) { // can happen when the delimiter straddles 2 distinct buffer reads of size `BUFFER_SIZE` startOfMatch = _currentOffset; } else { int length = startOfMatch - _currentOffset; partHandler.HandleBytes(_buffer, _currentOffset, length); } FillBuffer(); } } // will never happen ... we hope throw new BaseException(this, "unexpected code path followed"); }
// used for testing only internal DelimiterIndicator skipToNextDelimiterIndicator() { DelimiterDetector detector = new DelimiterDetector(_boundary); if (_currentOffset == _bufferEnd) { FillBuffer(); } DelimiterIndicator indicator = detector.update(_buffer, _currentOffset, _bufferEnd); if (null == indicator) { return null; } if( indicator is DelimiterFound ) { DelimiterFound delimiterFound = (DelimiterFound)indicator; _currentOffset = delimiterFound.EndOfDelimiter; } return indicator; }