private void ParseCurrentEntry(out AtomEntry targetEntry) { Debug.Assert(this.reader.NodeType == XmlNodeType.Element, "this.reader.NodeType == XmlNodeType.Element"); var callbackResult = this.entryCallback(this.reader); Debug.Assert(callbackResult.Key != null, "callbackResult.Key != null"); this.readers.Push(this.reader); this.reader = callbackResult.Key; this.reader.Read(); Debug.Assert(this.reader.LocalName == "entry", "this.reader.LocalName == 'entry' - otherwise we're not reading the subtree"); bool hasContent = false; targetEntry = new AtomEntry(); targetEntry.DataValues = new List <AtomContentProperty>(); targetEntry.Tag = callbackResult.Value; targetEntry.ETagText = this.reader.GetAttribute(XmlConstants.AtomETagAttributeName, XmlConstants.DataWebMetadataNamespace); while (this.reader.Read()) { if (ShouldIgnoreNode(this.reader)) { continue; } if (this.reader.NodeType == XmlNodeType.Element) { int depth = this.reader.Depth; string elementName = this.reader.LocalName; string namespaceURI = this.reader.NamespaceURI; if (namespaceURI == XmlConstants.AtomNamespace) { if (elementName == XmlConstants.AtomCategoryElementName && targetEntry.TypeName == null) { string text = this.reader.GetAttributeEx(XmlConstants.AtomCategorySchemeAttributeName, XmlConstants.AtomNamespace); if (text == this.typeScheme) { targetEntry.TypeName = this.reader.GetAttributeEx(XmlConstants.AtomCategoryTermAttributeName, XmlConstants.AtomNamespace); } } else if (elementName == XmlConstants.AtomContentElementName) { hasContent = true; this.ParseCurrentContent(targetEntry); } else if (elementName == XmlConstants.AtomIdElementName && targetEntry.Identity == null) { string idText = ReadElementStringForText(this.reader); idText = Util.ReferenceIdentity(idText); Uri idUri = Util.CreateUri(idText, UriKind.RelativeOrAbsolute); if (!idUri.IsAbsoluteUri) { throw Error.InvalidOperation(Strings.Context_TrackingExpectsAbsoluteUri); } targetEntry.Identity = idText; } else if (elementName == XmlConstants.AtomLinkElementName) { this.ParseCurrentLink(targetEntry); } } else if (namespaceURI == XmlConstants.DataWebMetadataNamespace) { if (elementName == XmlConstants.AtomPropertiesElementName) { if (targetEntry.MediaLinkEntry.HasValue && !targetEntry.MediaLinkEntry.Value) { throw Error.InvalidOperation(Strings.Deserialize_ContentPlusPropertiesNotAllowed); } targetEntry.MediaLinkEntry = true; if (!this.reader.IsEmptyElement) { this.ReadCurrentProperties(targetEntry.DataValues); } } } SkipToEndAtDepth(this.reader, depth); } } if (targetEntry.Identity == null) { throw Error.InvalidOperation(Strings.Deserialize_MissingIdElement); } if (!hasContent) { throw Error.BatchStreamContentExpected(BatchStreamState.GetResponse); } this.reader = this.readers.Pop(); }
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); }