private static string VerifyBoundary(string boundary)
        {
            if ((null == boundary) || (70 < boundary.Length))
            {
                throw Error.BatchStreamInvalidDelimiter(boundary);
            }

            foreach (char c in boundary)
            {
                if ((127 < (int)c) || Char.IsWhiteSpace(c) || Char.IsControl(c))
                {
                    throw Error.BatchStreamInvalidDelimiter(boundary);
                }
            }

            return("--" + boundary);
        }
        internal bool MoveNext()
        {
            #region dispose previous content stream
            if (null == this.reader || this.disposeWithContentStreamDispose)
            {
                return(false);
            }

            if (null != this.contentStream)
            {
                this.contentStream.Dispose();
            }

            Debug.Assert(0 <= this.byteLength, "negative byteLength");
            Debug.Assert(0 <= this.batchLength, "negative batchLength");
            #endregion

            #region initialize start state to EndBatch or EndChangeSet
            switch (this.batchState)
            {
            case BatchStreamState.EndBatch:
                Debug.Assert(null == this.batchBoundary, "non-null batch boundary");
                Debug.Assert(null == this.changesetBoundary, "non-null changesetBoundary boundary");
                throw Error.BatchStreamInvalidBatchFormat();

            case BatchStreamState.Get:
            case BatchStreamState.GetResponse:
                this.ClearPreviousOperationInformation();
                goto case BatchStreamState.StartBatch;

            case BatchStreamState.StartBatch:
            case BatchStreamState.EndChangeSet:
                Debug.Assert(null != this.batchBoundary, "null batch boundary");
                Debug.Assert(null == this.changesetBoundary, "non-null changeset boundary");
                this.batchState  = BatchStreamState.EndBatch;
                this.batchLength = Int32.MaxValue;
                break;

            case BatchStreamState.BeginChangeSet:
                Debug.Assert(null != this.batchBoundary, "null batch boundary");
                Debug.Assert(null != this.contentHeaders, "null contentHeaders");
                Debug.Assert(null != this.changesetBoundary, "null changeset boundary");
                this.contentHeaders    = null;
                this.changesetEncoding = null;
                this.batchState        = BatchStreamState.EndChangeSet;
                break;

            case BatchStreamState.ChangeResponse:
            case BatchStreamState.Delete:
                Debug.Assert(null != this.changesetBoundary, "null changeset boundary");
                this.ClearPreviousOperationInformation();
                this.batchState = BatchStreamState.EndChangeSet;
                break;

            case BatchStreamState.Post:
            case BatchStreamState.Put:
            case BatchStreamState.Merge:
                Debug.Assert(null != this.changesetBoundary, "null changeset boundary");
                this.batchState = BatchStreamState.EndChangeSet;
                break;

            default:
                Debug.Assert(false, "unknown state");
                throw Error.BatchStreamInvalidBatchFormat();
            }

            Debug.Assert(null == this.contentHeaders, "non-null content headers");
            Debug.Assert(null == this.contentStream, "non-null content stream");

            Debug.Assert(null == this.statusCode, "non-null statusCode");

            Debug.Assert(
                this.batchState == BatchStreamState.EndBatch ||
                this.batchState == BatchStreamState.EndChangeSet,
                "unexpected state at start");
            #endregion

            #region read --delimiter
            string delimiter = this.ReadLine();
            if (String.IsNullOrEmpty(delimiter))
            {
                delimiter = this.ReadLine();
            }

            if (String.IsNullOrEmpty(delimiter))
            {
                throw Error.BatchStreamInvalidBatchFormat();
            }

            if (delimiter.EndsWith("--", StringComparison.Ordinal))
            {
                delimiter = delimiter.Substring(0, delimiter.Length - 2);

                if ((null != this.changesetBoundary) && (delimiter == this.changesetBoundary))
                {
                    Debug.Assert(this.batchState == BatchStreamState.EndChangeSet, "bad changeset boundary state");

                    this.changesetBoundary = null;
                    return(true);
                }
                else if (delimiter == this.batchBoundary)
                {
                    if (BatchStreamState.EndChangeSet == this.batchState)
                    {
                        throw Error.BatchStreamMissingEndChangesetDelimiter();
                    }

                    this.changesetBoundary = null;
                    this.batchBoundary     = null;
                    if (this.byteLength != 0)
                    {
                        throw Error.BatchStreamMoreDataAfterEndOfBatch();
                    }

                    return(false);
                }
                else
                {
                    throw Error.BatchStreamInvalidDelimiter(delimiter);
                }
            }
            else if ((null != this.changesetBoundary) && (delimiter == this.changesetBoundary))
            {
                Debug.Assert(this.batchState == BatchStreamState.EndChangeSet, "bad changeset boundary state");
            }
            else if (delimiter == this.batchBoundary)
            {
                if (this.batchState != BatchStreamState.EndBatch)
                {
                    if (this.batchState == BatchStreamState.EndChangeSet)
                    {
                        throw Error.BatchStreamMissingEndChangesetDelimiter();
                    }
                    else
                    {
                        throw Error.BatchStreamInvalidBatchFormat();
                    }
                }
            }
            else
            {
                throw Error.BatchStreamInvalidDelimiter(delimiter);
            }

            #endregion

            #region read header with values in this form (([^:]*:.*)\r\n)*\r\n
            this.ReadContentHeaders();
            #endregion

            #region should start changeset?
            string contentType;
            bool   readHttpHeaders = false;
            if (this.contentHeaders.TryGetValue(XmlConstants.HttpContentType, out contentType))
            {
                if (String.Equals(contentType, XmlConstants.MimeApplicationHttp, StringComparison.OrdinalIgnoreCase))
                {
                    if (this.contentHeaders.Count != 2)
                    {
                        throw Error.BatchStreamInvalidNumberOfHeadersAtOperationStart(
                                  XmlConstants.HttpContentType,
                                  XmlConstants.HttpContentTransferEncoding);
                    }

                    string transferEncoding;
                    if (!this.contentHeaders.TryGetValue(XmlConstants.HttpContentTransferEncoding, out transferEncoding) ||
                        XmlConstants.BatchRequestContentTransferEncoding != transferEncoding)
                    {
                        throw Error.BatchStreamMissingOrInvalidContentEncodingHeader(
                                  XmlConstants.HttpContentTransferEncoding,
                                  XmlConstants.BatchRequestContentTransferEncoding);
                    }

                    readHttpHeaders = true;
                }
                else if (BatchStreamState.EndBatch == this.batchState)
                {
                    string   boundary;
                    Encoding encoding;
                    if (GetBoundaryAndEncodingFromMultipartMixedContentType(contentType, out boundary, out encoding))
                    {
                        this.changesetBoundary = VerifyBoundary(boundary);
                        this.changesetEncoding = encoding;
                        this.batchState        = BatchStreamState.BeginChangeSet;
                    }
                    else
                    {
                        throw Error.BatchStreamInvalidContentTypeSpecified(
                                  XmlConstants.HttpContentType,
                                  contentType,
                                  XmlConstants.MimeApplicationHttp,
                                  XmlConstants.MimeMultiPartMixed);
                    }

                    if (this.contentHeaders.Count > 2 ||
                        (this.contentHeaders.Count == 2 && !this.contentHeaders.ContainsKey(XmlConstants.HttpContentLength)))
                    {
                        throw Error.BatchStreamInvalidNumberOfHeadersAtChangeSetStart(XmlConstants.HttpContentType, XmlConstants.HttpContentLength);
                    }
                }
                else
                {
                    throw Error.BatchStreamInvalidContentTypeSpecified(
                              XmlConstants.HttpContentType,
                              contentType,
                              XmlConstants.MimeApplicationHttp,
                              XmlConstants.MimeMultiPartMixed);
                }
            }
            else
            {
                throw Error.BatchStreamMissingContentTypeHeader(XmlConstants.HttpContentType);
            }
            #endregion

            #region what is the operation and uri?
            if (readHttpHeaders)
            {
                this.ReadHttpHeaders();

                this.contentHeaders.TryGetValue(XmlConstants.HttpContentType, out contentType);
            }
            #endregion


            #region does content have a fixed length?
            string text   = null;
            int    length = -1;
            if (this.contentHeaders.TryGetValue(XmlConstants.HttpContentLength, out text))
            {
                length = Int32.Parse(text, CultureInfo.InvariantCulture);
                if (length < 0)
                {
                    throw Error.BatchStreamInvalidContentLengthSpecified(text);
                }

                if (this.batchState == BatchStreamState.BeginChangeSet)
                {
                    this.batchLength = length;
                }
                else if (length != 0)
                {
                    Debug.Assert(
                        this.batchState == BatchStreamState.Delete ||
                        this.batchState == BatchStreamState.Get ||
                        this.batchState == BatchStreamState.Post ||
                        this.batchState == BatchStreamState.Put ||
                        this.batchState == BatchStreamState.Merge,
                        "unexpected contentlength location");
                    this.contentStream = new StreamWithLength(this, length);
                }
            }
            else
            {
                if (this.batchState == BatchStreamState.EndBatch)
                {
                    this.batchLength = Int32.MaxValue;
                }

                if (this.batchState != BatchStreamState.BeginChangeSet)
                {
                    this.contentStream = new StreamWithDelimiter(this);
                }
            }

            #endregion

            Debug.Assert(
                this.batchState == BatchStreamState.BeginChangeSet ||
                (this.batchRequest && (this.batchState == BatchStreamState.Delete ||
                                       this.batchState == BatchStreamState.Get ||
                                       this.batchState == BatchStreamState.Post ||
                                       this.batchState == BatchStreamState.Put ||
                                       this.batchState == BatchStreamState.Merge)) ||
                (!this.batchRequest && (this.batchState == BatchStreamState.GetResponse ||
                                        this.batchState == BatchStreamState.ChangeResponse)),
                "unexpected state at return");

            #region enforce if contentStream is expected, caller needs to enforce if contentStream is not expected
            if (null == this.contentStream)
            {
                switch (this.batchState)
                {
                case BatchStreamState.BeginChangeSet:
                case BatchStreamState.Delete:
                case BatchStreamState.Get:
                case BatchStreamState.ChangeResponse:
                case BatchStreamState.GetResponse:
                    break;

                case BatchStreamState.Post:
                case BatchStreamState.Put:
                case BatchStreamState.Merge:
                default:
                    throw Error.BatchStreamContentExpected(this.batchState);
                }
            }
            #endregion

            #region enforce if contentType not is expected, caller needs to enforce if contentType is expected
            if (!String.IsNullOrEmpty(contentType))
            {
                switch (this.batchState)
                {
                case BatchStreamState.BeginChangeSet:
                case BatchStreamState.Post:
                case BatchStreamState.Put:
                case BatchStreamState.Merge:
                case BatchStreamState.GetResponse:
                case BatchStreamState.ChangeResponse:
                    break;

                case BatchStreamState.Get:
                case BatchStreamState.Delete:
                default:
                    throw Error.BatchStreamContentUnexpected(this.batchState);
                }
            }
            #endregion

            return(true);
        }