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();
            }

        }
        private DelimiterFound ProcessPart(MultiPartHandler multiPartHandler, DelimiterDetector detector)
        {

            PartHandler partHandler = multiPartHandler.FoundPartDelimiter();

            try
            {
                return TryProcessPart(partHandler, detector);
            }
            catch (Exception e)
            {
                partHandler.HandleException(e);
                throw e;
            }

        }
        // 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;

        }