1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //------------------------------------------------------------
8 using System.Collections.Generic;
9 using System.Globalization;
12 using System.Runtime.Serialization;
14 using System.Security;
15 using System.Security.Permissions;
17 public interface IXmlMtomReaderInitializer
19 void SetInput(byte[] buffer, int offset, int count, Encoding[] encodings, string contentType, XmlDictionaryReaderQuotas quotas, int maxBufferSize, OnXmlDictionaryReaderClose onClose);
20 void SetInput(Stream stream, Encoding[] encodings, string contentType, XmlDictionaryReaderQuotas quotas, int maxBufferSize, OnXmlDictionaryReaderClose onClose);
23 class XmlMtomReader : XmlDictionaryReader, IXmlLineInfo, IXmlMtomReaderInitializer
26 XmlDictionaryReader xmlReader;
27 XmlDictionaryReader infosetReader;
28 MimeReader mimeReader;
29 Dictionary<string, MimePart> mimeParts;
30 OnXmlDictionaryReaderClose onClose;
31 bool readingBinaryElement;
36 public XmlMtomReader()
40 internal static void DecrementBufferQuota(int maxBuffer, ref int remaining, int size)
42 if (remaining - size <= 0)
45 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.MtomBufferQuotaExceeded, maxBuffer)));
53 void SetReadEncodings(Encoding[] encodings)
55 if (encodings == null)
56 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("encodings");
58 for (int i = 0; i < encodings.Length; i++)
60 if (encodings[i] == null)
61 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(String.Format(CultureInfo.InvariantCulture, "encodings[{0}]", i));
64 this.encodings = new Encoding[encodings.Length];
65 encodings.CopyTo(this.encodings, 0);
68 void CheckContentType(string contentType)
70 if (contentType != null && contentType.Length == 0)
71 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.MtomContentTypeInvalid), "contentType"));
74 public void SetInput(byte[] buffer, int offset, int count, Encoding[] encodings, string contentType, XmlDictionaryReaderQuotas quotas, int maxBufferSize, OnXmlDictionaryReaderClose onClose)
76 SetInput(new MemoryStream(buffer, offset, count), encodings, contentType, quotas, maxBufferSize, onClose);
79 public void SetInput(Stream stream, Encoding[] encodings, string contentType, XmlDictionaryReaderQuotas quotas, int maxBufferSize, OnXmlDictionaryReaderClose onClose)
81 SetReadEncodings(encodings);
82 CheckContentType(contentType);
83 Initialize(stream, contentType, quotas, maxBufferSize);
84 this.onClose = onClose;
87 void Initialize(Stream stream, string contentType, XmlDictionaryReaderQuotas quotas, int maxBufferSize)
90 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("stream");
92 this.maxBufferSize = maxBufferSize;
93 this.bufferRemaining = maxBufferSize;
95 string boundary, start, startInfo;
97 if (contentType == null)
99 MimeMessageReader messageReader = new MimeMessageReader(stream);
100 MimeHeaders messageHeaders = messageReader.ReadHeaders(this.maxBufferSize, ref this.bufferRemaining);
101 ReadMessageMimeVersionHeader(messageHeaders.MimeVersion);
102 ReadMessageContentTypeHeader(messageHeaders.ContentType, out boundary, out start, out startInfo);
103 stream = messageReader.GetContentStream();
105 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.MtomMessageInvalidContent)));
109 ReadMessageContentTypeHeader(new ContentTypeHeader(contentType), out boundary, out start, out startInfo);
112 this.mimeReader = new MimeReader(stream, boundary);
113 this.mimeParts = null;
114 this.readingBinaryElement = false;
116 MimePart infosetPart = (start == null) ? ReadRootMimePart() : ReadMimePart(GetStartUri(start));
117 byte[] infosetBytes = infosetPart.GetBuffer(this.maxBufferSize, ref this.bufferRemaining);
118 int infosetByteCount = (int)infosetPart.Length;
120 Encoding encoding = ReadRootContentTypeHeader(infosetPart.Headers.ContentType, this.encodings, startInfo);
121 CheckContentTransferEncodingOnRoot(infosetPart.Headers.ContentTransferEncoding);
123 IXmlTextReaderInitializer initializer = xmlReader as IXmlTextReaderInitializer;
125 if (initializer != null)
126 initializer.SetInput(infosetBytes, 0, infosetByteCount, encoding, quotas, null);
128 xmlReader = XmlDictionaryReader.CreateTextReader(infosetBytes, 0, infosetByteCount, encoding, quotas, null);
131 public override XmlDictionaryReaderQuotas Quotas
135 return this.xmlReader.Quotas;
139 void ReadMessageMimeVersionHeader(MimeVersionHeader header)
141 if (header != null && header.Version != MimeVersionHeader.Default.Version)
142 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.MtomMessageInvalidMimeVersion, header.Version, MimeVersionHeader.Default.Version)));
145 void ReadMessageContentTypeHeader(ContentTypeHeader header, out string boundary, out string start, out string startInfo)
148 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.MtomMessageContentTypeNotFound)));
150 if (String.Compare(MtomGlobals.MediaType, header.MediaType, StringComparison.OrdinalIgnoreCase) != 0
151 || String.Compare(MtomGlobals.MediaSubtype, header.MediaSubtype, StringComparison.OrdinalIgnoreCase) != 0)
152 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.MtomMessageNotMultipart, MtomGlobals.MediaType, MtomGlobals.MediaSubtype)));
155 if (!header.Parameters.TryGetValue(MtomGlobals.TypeParam, out type) || MtomGlobals.XopType != type)
156 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.MtomMessageNotApplicationXopXml, MtomGlobals.XopType)));
158 if (!header.Parameters.TryGetValue(MtomGlobals.BoundaryParam, out boundary))
159 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.MtomMessageRequiredParamNotSpecified, MtomGlobals.BoundaryParam)));
160 if (!MailBnfHelper.IsValidMimeBoundary(boundary))
161 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.MtomBoundaryInvalid, boundary)));
163 if (!header.Parameters.TryGetValue(MtomGlobals.StartParam, out start))
166 if (!header.Parameters.TryGetValue(MtomGlobals.StartInfoParam, out startInfo))
170 Encoding ReadRootContentTypeHeader(ContentTypeHeader header, Encoding[] expectedEncodings, string expectedType)
173 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.MtomRootContentTypeNotFound)));
175 if (String.Compare(MtomGlobals.XopMediaType, header.MediaType, StringComparison.OrdinalIgnoreCase) != 0
176 || String.Compare(MtomGlobals.XopMediaSubtype, header.MediaSubtype, StringComparison.OrdinalIgnoreCase) != 0)
177 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.MtomRootNotApplicationXopXml, MtomGlobals.XopMediaType, MtomGlobals.XopMediaSubtype)));
180 if (!header.Parameters.TryGetValue(MtomGlobals.CharsetParam, out charset)
181 || charset == null || charset.Length == 0)
182 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.MtomRootRequiredParamNotSpecified, MtomGlobals.CharsetParam)));
183 Encoding encoding = null;
184 for (int i = 0; i < encodings.Length; i++)
186 if (String.Compare(charset, expectedEncodings[i].WebName, StringComparison.OrdinalIgnoreCase) == 0)
188 encoding = expectedEncodings[i];
192 if (encoding == null)
194 // Check for alternate names
195 if (String.Compare(charset, "utf-16LE", StringComparison.OrdinalIgnoreCase) == 0)
197 for (int i = 0; i < encodings.Length; i++)
199 if (String.Compare(expectedEncodings[i].WebName, Encoding.Unicode.WebName, StringComparison.OrdinalIgnoreCase) == 0)
201 encoding = expectedEncodings[i];
206 else if (String.Compare(charset, "utf-16BE", StringComparison.OrdinalIgnoreCase) == 0)
208 for (int i = 0; i < encodings.Length; i++)
210 if (String.Compare(expectedEncodings[i].WebName, Encoding.BigEndianUnicode.WebName, StringComparison.OrdinalIgnoreCase) == 0)
212 encoding = expectedEncodings[i];
218 if (encoding == null)
220 StringBuilder expectedCharSetStr = new StringBuilder();
221 for (int i = 0; i < encodings.Length; i++)
223 if (expectedCharSetStr.Length != 0)
224 expectedCharSetStr.Append(" | ");
225 expectedCharSetStr.Append(encodings[i].WebName);
227 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.MtomRootUnexpectedCharset, charset, expectedCharSetStr.ToString())));
231 if (expectedType != null)
234 if (!header.Parameters.TryGetValue(MtomGlobals.TypeParam, out rootType)
235 || rootType == null || rootType.Length == 0)
236 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.MtomRootRequiredParamNotSpecified, MtomGlobals.TypeParam)));
237 if (rootType != expectedType)
238 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.MtomRootUnexpectedType, rootType, expectedType)));
244 // 7bit is default encoding in the absence of content-transfer-encoding header
245 void CheckContentTransferEncodingOnRoot(ContentTransferEncodingHeader header)
247 if (header != null && header.ContentTransferEncoding == ContentTransferEncoding.Other)
248 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.MtomContentTransferEncodingNotSupported,
250 ContentTransferEncodingHeader.SevenBit.ContentTransferEncodingValue,
251 ContentTransferEncodingHeader.EightBit.ContentTransferEncodingValue,
252 ContentTransferEncodingHeader.Binary.ContentTransferEncodingValue)));
255 void CheckContentTransferEncodingOnBinaryPart(ContentTransferEncodingHeader header)
258 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.MtomContentTransferEncodingNotPresent,
259 ContentTransferEncodingHeader.Binary.ContentTransferEncodingValue)));
260 else if (header.ContentTransferEncoding != ContentTransferEncoding.Binary)
261 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.MtomInvalidTransferEncodingForMimePart,
262 header.Value, ContentTransferEncodingHeader.Binary.ContentTransferEncodingValue)));
265 string GetStartUri(string startUri)
267 if (startUri.StartsWith("<", StringComparison.Ordinal))
269 if (startUri.EndsWith(">", StringComparison.Ordinal))
272 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.MtomInvalidStartUri, startUri)));
275 return String.Format(CultureInfo.InvariantCulture, "<{0}>", startUri);
278 public override bool Read()
280 bool retVal = xmlReader.Read();
282 if (xmlReader.NodeType == XmlNodeType.Element)
284 XopIncludeReader binaryDataReader = null;
285 if (xmlReader.IsStartElement(MtomGlobals.XopIncludeLocalName, MtomGlobals.XopIncludeNamespace))
288 while (xmlReader.MoveToNextAttribute())
290 if (xmlReader.LocalName == MtomGlobals.XopIncludeHrefLocalName && xmlReader.NamespaceURI == MtomGlobals.XopIncludeHrefNamespace)
291 uri = xmlReader.Value;
292 else if (xmlReader.NamespaceURI == MtomGlobals.XopIncludeNamespace)
293 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.MtomXopIncludeInvalidXopAttributes, xmlReader.LocalName, MtomGlobals.XopIncludeNamespace)));
296 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.MtomXopIncludeHrefNotSpecified, MtomGlobals.XopIncludeHrefLocalName)));
298 MimePart mimePart = ReadMimePart(uri);
300 CheckContentTransferEncodingOnBinaryPart(mimePart.Headers.ContentTransferEncoding);
302 this.part = mimePart;
303 binaryDataReader = new XopIncludeReader(mimePart, xmlReader);
304 binaryDataReader.Read();
306 xmlReader.MoveToElement();
307 if (xmlReader.IsEmptyElement)
313 int xopDepth = xmlReader.Depth;
314 xmlReader.ReadStartElement();
316 while (xmlReader.Depth > xopDepth)
318 if (xmlReader.IsStartElement() && xmlReader.NamespaceURI == MtomGlobals.XopIncludeNamespace)
319 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.MtomXopIncludeInvalidXopElement, xmlReader.LocalName, MtomGlobals.XopIncludeNamespace)));
324 xmlReader.ReadEndElement();
328 if (binaryDataReader != null)
330 this.xmlReader.MoveToContent();
331 this.infosetReader = this.xmlReader;
332 this.xmlReader = binaryDataReader;
333 binaryDataReader = null;
337 if (xmlReader.ReadState == ReadState.EndOfFile && infosetReader != null)
339 // Read past the containing EndElement if necessary
341 retVal = infosetReader.Read();
343 this.part.Release(this.maxBufferSize, ref this.bufferRemaining);
344 xmlReader = infosetReader;
345 infosetReader = null;
351 MimePart ReadMimePart(string uri)
353 MimePart part = null;
355 if (uri == null || uri.Length == 0)
356 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.MtomInvalidEmptyURI)));
358 string contentID = null;
359 if (uri.StartsWith(MimeGlobals.ContentIDScheme, StringComparison.Ordinal))
360 contentID = String.Format(CultureInfo.InvariantCulture, "<{0}>", Uri.UnescapeDataString(uri.Substring(MimeGlobals.ContentIDScheme.Length)));
361 else if (uri.StartsWith("<", StringComparison.Ordinal))
364 if (contentID == null)
365 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.MtomInvalidCIDUri, uri)));
367 if (mimeParts != null && mimeParts.TryGetValue(contentID, out part))
369 if (part.ReferencedFromInfoset)
370 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.MtomMimePartReferencedMoreThanOnce, contentID)));
374 int maxMimeParts = AppSettings.MaxMimeParts;
375 while (part == null && mimeReader.ReadNextPart())
377 MimeHeaders headers = mimeReader.ReadHeaders(this.maxBufferSize, ref this.bufferRemaining);
378 Stream contentStream = mimeReader.GetContentStream();
379 if (contentStream == null)
380 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.MtomMessageInvalidContentInMimePart)));
382 ContentIDHeader contentIDHeader = (headers == null) ? null : headers.ContentID;
383 if (contentIDHeader == null || contentIDHeader.Value == null)
385 // Skip content if Content-ID header is not present
387 byte[] bytes = new byte[size];
392 read = contentStream.Read(bytes, 0, size);
398 string currentContentID = headers.ContentID.Value;
399 MimePart currentPart = new MimePart(contentStream, headers);
400 if (mimeParts == null)
401 mimeParts = new Dictionary<string, MimePart>();
403 mimeParts.Add(currentContentID, currentPart);
405 if (mimeParts.Count > maxMimeParts)
406 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.MaxMimePartsExceeded, maxMimeParts, AppSettings.MaxMimePartsAppSettingsString)));
408 if (currentContentID.Equals(contentID))
411 currentPart.GetBuffer(this.maxBufferSize, ref this.bufferRemaining);
415 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.MtomPartNotFound, uri)));
418 part.ReferencedFromInfoset = true;
422 MimePart ReadRootMimePart()
424 MimePart part = null;
426 if (!mimeReader.ReadNextPart())
427 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.MtomRootPartNotFound)));
429 MimeHeaders headers = mimeReader.ReadHeaders(this.maxBufferSize, ref this.bufferRemaining);
430 Stream contentStream = mimeReader.GetContentStream();
431 if (contentStream == null)
432 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.MtomMessageInvalidContentInMimePart)));
433 part = new MimePart(contentStream, headers);
438 void AdvanceToContentOnElement()
440 if (NodeType != XmlNodeType.Attribute)
446 public override int AttributeCount
450 return xmlReader.AttributeCount;
454 public override string BaseURI
458 return xmlReader.BaseURI;
462 public override bool CanReadBinaryContent
466 return xmlReader.CanReadBinaryContent;
470 public override bool CanReadValueChunk
474 return xmlReader.CanReadValueChunk;
478 public override bool CanResolveEntity
482 return xmlReader.CanResolveEntity;
486 public override void Close()
490 OnXmlDictionaryReaderClose onClose = this.onClose;
500 if (Fx.IsFatal(e)) throw;
502 throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(e);
507 public override int Depth
511 return xmlReader.Depth;
515 public override bool EOF
519 return xmlReader.EOF;
523 public override string GetAttribute(int index)
525 return xmlReader.GetAttribute(index);
528 public override string GetAttribute(string name)
530 return xmlReader.GetAttribute(name);
533 public override string GetAttribute(string name, string ns)
535 return xmlReader.GetAttribute(name, ns);
538 public override string GetAttribute(XmlDictionaryString localName, XmlDictionaryString ns)
540 return xmlReader.GetAttribute(localName, ns);
543 public override ArraySegment<byte> GetSubset(bool advance)
545 return xmlReader.GetSubset(advance);
548 public override bool HasAttributes
552 return xmlReader.HasAttributes;
556 public override bool HasValue
560 return xmlReader.HasValue;
564 public override bool IsDefault
568 return xmlReader.IsDefault;
572 public override bool IsEmptyElement
576 return xmlReader.IsEmptyElement;
580 public override bool IsLocalName(string localName)
582 return xmlReader.IsLocalName(localName);
585 public override bool IsLocalName(XmlDictionaryString localName)
587 return xmlReader.IsLocalName(localName);
590 public override bool IsNamespaceUri(string ns)
592 return xmlReader.IsNamespaceUri(ns);
595 public override bool IsNamespaceUri(XmlDictionaryString ns)
597 return xmlReader.IsNamespaceUri(ns);
600 public override bool IsStartElement()
602 return xmlReader.IsStartElement();
605 public override bool IsStartElement(string localName)
607 return xmlReader.IsStartElement(localName);
610 public override bool IsStartElement(string localName, string ns)
612 return xmlReader.IsStartElement(localName, ns);
615 public override bool IsStartElement(XmlDictionaryString localName, XmlDictionaryString ns)
617 return xmlReader.IsStartElement(localName, ns);
620 public override bool IsStartSubsetElement()
622 return xmlReader.IsStartSubsetElement();
625 public override string LocalName
629 return xmlReader.LocalName;
633 public override string LookupNamespace(string ns)
635 return xmlReader.LookupNamespace(ns);
638 public override void MoveToAttribute(int index)
640 xmlReader.MoveToAttribute(index);
643 public override bool MoveToAttribute(string name)
645 return xmlReader.MoveToAttribute(name);
648 public override bool MoveToAttribute(string name, string ns)
650 return xmlReader.MoveToAttribute(name, ns);
653 public override bool MoveToElement()
655 return xmlReader.MoveToElement();
658 public override bool MoveToFirstAttribute()
660 return xmlReader.MoveToFirstAttribute();
663 public override bool MoveToNextAttribute()
665 return xmlReader.MoveToNextAttribute();
668 public override string Name
672 return xmlReader.Name;
676 public override string NamespaceURI
680 return xmlReader.NamespaceURI;
684 public override XmlNameTable NameTable
688 return xmlReader.NameTable;
692 public override XmlNodeType NodeType
696 return xmlReader.NodeType;
700 public override string Prefix
704 return xmlReader.Prefix;
708 public override char QuoteChar
712 return xmlReader.QuoteChar;
716 public override bool ReadAttributeValue()
718 return xmlReader.ReadAttributeValue();
721 public override object ReadContentAs(Type returnType, IXmlNamespaceResolver namespaceResolver)
723 AdvanceToContentOnElement();
724 return xmlReader.ReadContentAs(returnType, namespaceResolver);
727 public override byte[] ReadContentAsBase64()
729 AdvanceToContentOnElement();
730 return xmlReader.ReadContentAsBase64();
733 public override int ReadValueAsBase64(byte[] buffer, int offset, int count)
735 AdvanceToContentOnElement();
736 return xmlReader.ReadValueAsBase64(buffer, offset, count);
739 public override int ReadContentAsBase64(byte[] buffer, int offset, int count)
741 AdvanceToContentOnElement();
742 return xmlReader.ReadContentAsBase64(buffer, offset, count);
745 public override int ReadElementContentAsBase64(byte[] buffer, int offset, int count)
747 if (!readingBinaryElement)
756 readingBinaryElement = true;
759 int i = ReadContentAsBase64(buffer, offset, count);
764 readingBinaryElement = false;
770 public override int ReadElementContentAsBinHex(byte[] buffer, int offset, int count)
772 if (!readingBinaryElement)
781 readingBinaryElement = true;
784 int i = ReadContentAsBinHex(buffer, offset, count);
789 readingBinaryElement = false;
795 public override int ReadContentAsBinHex(byte[] buffer, int offset, int count)
797 AdvanceToContentOnElement();
798 return xmlReader.ReadContentAsBinHex(buffer, offset, count);
801 public override bool ReadContentAsBoolean()
803 AdvanceToContentOnElement();
804 return xmlReader.ReadContentAsBoolean();
807 public override int ReadContentAsChars(char[] chars, int index, int count)
809 AdvanceToContentOnElement();
810 return xmlReader.ReadContentAsChars(chars, index, count);
813 public override DateTime ReadContentAsDateTime()
815 AdvanceToContentOnElement();
816 return xmlReader.ReadContentAsDateTime();
819 public override decimal ReadContentAsDecimal()
821 AdvanceToContentOnElement();
822 return xmlReader.ReadContentAsDecimal();
825 public override double ReadContentAsDouble()
827 AdvanceToContentOnElement();
828 return xmlReader.ReadContentAsDouble();
831 public override int ReadContentAsInt()
833 AdvanceToContentOnElement();
834 return xmlReader.ReadContentAsInt();
837 public override long ReadContentAsLong()
839 AdvanceToContentOnElement();
840 return xmlReader.ReadContentAsLong();
843 public override ICollection ReadContentAsList()
845 AdvanceToContentOnElement();
846 return xmlReader.ReadContentAsList();
849 public override object ReadContentAsObject()
851 AdvanceToContentOnElement();
852 return xmlReader.ReadContentAsObject();
855 public override float ReadContentAsFloat()
857 AdvanceToContentOnElement();
858 return xmlReader.ReadContentAsFloat();
861 public override string ReadContentAsString()
863 AdvanceToContentOnElement();
864 return xmlReader.ReadContentAsString();
867 public override string ReadInnerXml()
869 return xmlReader.ReadInnerXml();
872 public override string ReadOuterXml()
874 return xmlReader.ReadOuterXml();
877 public override ReadState ReadState
881 if (xmlReader.ReadState != ReadState.Interactive && infosetReader != null)
882 return infosetReader.ReadState;
884 return xmlReader.ReadState;
888 public override int ReadValueChunk(char[] buffer, int index, int count)
890 return xmlReader.ReadValueChunk(buffer, index, count);
893 public override void ResolveEntity()
895 xmlReader.ResolveEntity();
898 public override XmlReaderSettings Settings
902 return xmlReader.Settings;
906 public override void Skip()
911 public override string this[int index]
915 return xmlReader[index];
919 public override string this[string name]
923 return xmlReader[name];
927 public override string this[string name, string ns]
931 return xmlReader[name, ns];
935 public override string Value
939 return xmlReader.Value;
943 public override Type ValueType
947 return xmlReader.ValueType;
951 public override string XmlLang
955 return xmlReader.XmlLang;
959 public override XmlSpace XmlSpace
963 return xmlReader.XmlSpace;
967 public bool HasLineInfo()
969 if (xmlReader.ReadState == ReadState.Closed)
972 IXmlLineInfo lineInfo = xmlReader as IXmlLineInfo;
973 if (lineInfo == null)
975 return lineInfo.HasLineInfo();
978 public int LineNumber
982 if (xmlReader.ReadState == ReadState.Closed)
985 IXmlLineInfo lineInfo = xmlReader as IXmlLineInfo;
986 if (lineInfo == null)
988 return lineInfo.LineNumber;
992 public int LinePosition
996 if (xmlReader.ReadState == ReadState.Closed)
999 IXmlLineInfo lineInfo = xmlReader as IXmlLineInfo;
1000 if (lineInfo == null)
1002 return lineInfo.LinePosition;
1006 internal class MimePart
1009 MimeHeaders headers;
1011 bool isReferencedFromInfoset;
1013 internal MimePart(Stream stream, MimeHeaders headers)
1015 this.stream = stream;
1016 this.headers = headers;
1019 internal Stream Stream
1021 get { return stream; }
1024 internal MimeHeaders Headers
1026 get { return headers; }
1029 internal bool ReferencedFromInfoset
1031 get { return isReferencedFromInfoset; }
1032 set { isReferencedFromInfoset = value; }
1035 internal long Length
1037 get { return stream.CanSeek ? stream.Length : 0; }
1040 internal byte[] GetBuffer(int maxBuffer, ref int remaining)
1044 MemoryStream bufferedStream = stream.CanSeek ? new MemoryStream((int)stream.Length) : new MemoryStream();
1046 byte[] bytes = new byte[size];
1052 read = stream.Read(bytes, 0, size);
1053 XmlMtomReader.DecrementBufferQuota(maxBuffer, ref remaining, read);
1055 bufferedStream.Write(bytes, 0, read);
1059 bufferedStream.Seek(0, SeekOrigin.Begin);
1060 buffer = bufferedStream.GetBuffer();
1061 stream = bufferedStream;
1066 internal void Release(int maxBuffer, ref int remaining)
1068 remaining += (int)this.Length;
1069 this.headers.Release(ref remaining);
1073 internal class XopIncludeReader : XmlDictionaryReader, IXmlLineInfo
1075 int chunkSize = 4096; // Just a default. Serves as a max chunk size.
1079 ReadState readState;
1080 XmlDictionaryReader parentReader;
1083 XmlNodeType nodeType;
1084 MemoryStream binHexStream;
1088 bool finishedStream;
1090 public XopIncludeReader(MimePart part, XmlDictionaryReader reader)
1093 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("part");
1095 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
1098 this.parentReader = reader;
1099 this.readState = ReadState.Initial;
1100 this.nodeType = XmlNodeType.None;
1101 this.chunkSize = Math.Min(reader.Quotas.MaxBytesPerRead, chunkSize);
1102 this.bytesRemaining = this.chunkSize;
1103 this.finishedStream = false;
1106 public override XmlDictionaryReaderQuotas Quotas
1110 return this.parentReader.Quotas;
1114 public override XmlNodeType NodeType
1118 return (readState == ReadState.Interactive) ? nodeType : parentReader.NodeType;
1122 public override bool Read()
1127 case ReadState.Initial:
1128 readState = ReadState.Interactive;
1129 nodeType = XmlNodeType.Text;
1131 case ReadState.Interactive:
1132 if (this.finishedStream || (this.bytesRemaining == this.chunkSize && this.stringValue == null))
1134 readState = ReadState.EndOfFile;
1135 nodeType = XmlNodeType.EndElement;
1139 this.bytesRemaining = this.chunkSize;
1142 case ReadState.EndOfFile:
1143 nodeType = XmlNodeType.None;
1147 this.stringValue = null;
1148 this.binHexStream = null;
1149 this.valueOffset = 0;
1150 this.valueCount = 0;
1151 this.stringOffset = 0;
1156 public override int ReadValueAsBase64(byte[] buffer, int offset, int count)
1159 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("buffer");
1162 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", SR.GetString(SR.ValueMustBeNonNegative)));
1163 if (offset > buffer.Length)
1164 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", SR.GetString(SR.OffsetExceedsBufferSize, buffer.Length)));
1166 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.ValueMustBeNonNegative)));
1167 if (count > buffer.Length - offset)
1168 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.SizeExceedsRemainingBufferSpace, buffer.Length - offset)));
1170 if (this.stringValue != null)
1172 count = Math.Min(count, this.valueCount);
1175 Buffer.BlockCopy(this.valueBuffer, this.valueOffset, buffer, offset, count);
1176 this.valueOffset += count;
1177 this.valueCount -= count;
1182 if (this.bytesRemaining < count)
1183 count = this.bytesRemaining;
1186 if (readState == ReadState.Interactive)
1188 while (read < count)
1190 int actual = part.Stream.Read(buffer, offset + read, count - read);
1193 this.finishedStream = true;
1199 this.bytesRemaining -= read;
1203 public override int ReadContentAsBase64(byte[] buffer, int offset, int count)
1206 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("buffer");
1209 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", SR.GetString(SR.ValueMustBeNonNegative)));
1210 if (offset > buffer.Length)
1211 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", SR.GetString(SR.OffsetExceedsBufferSize, buffer.Length)));
1213 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.ValueMustBeNonNegative)));
1214 if (count > buffer.Length - offset)
1215 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.SizeExceedsRemainingBufferSpace, buffer.Length - offset)));
1217 if (this.valueCount > 0)
1219 count = Math.Min(count, this.valueCount);
1220 Buffer.BlockCopy(this.valueBuffer, this.valueOffset, buffer, offset, count);
1221 this.valueOffset += count;
1222 this.valueCount -= count;
1226 if (this.chunkSize < count)
1227 count = this.chunkSize;
1230 if (readState == ReadState.Interactive)
1232 while (read < count)
1234 int actual = part.Stream.Read(buffer, offset + read, count - read);
1237 this.finishedStream = true;
1244 this.bytesRemaining = this.chunkSize;
1248 public override int ReadContentAsBinHex(byte[] buffer, int offset, int count)
1251 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("buffer");
1254 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", SR.GetString(SR.ValueMustBeNonNegative)));
1255 if (offset > buffer.Length)
1256 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", SR.GetString(SR.OffsetExceedsBufferSize, buffer.Length)));
1258 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.ValueMustBeNonNegative)));
1259 if (count > buffer.Length - offset)
1260 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.SizeExceedsRemainingBufferSpace, buffer.Length - offset)));
1262 if (this.chunkSize < count)
1263 count = this.chunkSize;
1267 while (read < count)
1269 if (binHexStream == null)
1273 binHexStream = new MemoryStream(new BinHexEncoding().GetBytes(this.Value));
1275 catch (FormatException e) // Wrap format exceptions from decoding document contents
1277 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(e.Message, e));
1281 int actual = binHexStream.Read(buffer, offset + read, count - read);
1284 this.finishedStream = true;
1295 // Trim off the consumed chars
1296 if (this.stringValue != null && consumed > 0)
1298 this.stringValue = this.stringValue.Substring(consumed * 2);
1299 this.stringOffset = Math.Max(0, this.stringOffset - consumed * 2);
1301 this.bytesRemaining = this.chunkSize;
1306 public override int ReadValueChunk(char[] chars, int offset, int count)
1309 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("chars");
1312 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", SR.GetString(SR.ValueMustBeNonNegative)));
1313 if (offset > chars.Length)
1314 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", SR.GetString(SR.OffsetExceedsBufferSize, chars.Length)));
1316 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.ValueMustBeNonNegative)));
1317 if (count > chars.Length - offset)
1318 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.SizeExceedsRemainingBufferSpace, chars.Length - offset)));
1320 if (readState != ReadState.Interactive)
1323 // Copy characters from the Value property
1324 string str = this.Value;
1325 count = Math.Min(stringValue.Length - stringOffset, count);
1328 stringValue.CopyTo(stringOffset, chars, offset, count);
1329 stringOffset += count;
1334 public override string Value
1338 if (readState != ReadState.Interactive)
1339 return String.Empty;
1341 if (stringValue == null)
1343 // Compute the bytes to read
1344 int byteCount = this.bytesRemaining;
1345 byteCount -= byteCount % 3;
1347 // Handle trailing bytes
1348 if (this.valueCount > 0 && this.valueOffset > 0)
1350 Buffer.BlockCopy(this.valueBuffer, this.valueOffset, this.valueBuffer, 0, this.valueCount);
1351 this.valueOffset = 0;
1353 byteCount -= this.valueCount;
1355 // Resize buffer if needed
1356 if (this.valueBuffer == null)
1358 this.valueBuffer = new byte[byteCount];
1360 else if (this.valueBuffer.Length < byteCount)
1362 Array.Resize(ref this.valueBuffer, byteCount);
1364 byte[] buffer = this.valueBuffer;
1366 // Fill up the buffer
1369 while (byteCount > 0)
1371 read = part.Stream.Read(buffer, offset, byteCount);
1374 this.finishedStream = true;
1378 this.bytesRemaining -= read;
1379 this.valueCount += read;
1384 // Convert the bytes
1385 this.stringValue = Convert.ToBase64String(buffer, 0, this.valueCount);
1387 return this.stringValue;
1391 public override string ReadContentAsString()
1393 int stringContentQuota = this.Quotas.MaxStringContentLength;
1394 StringBuilder sb = new StringBuilder();
1397 string val = this.Value;
1398 if (val.Length > stringContentQuota)
1399 XmlExceptionHelper.ThrowMaxStringContentLengthExceeded(this, this.Quotas.MaxStringContentLength);
1400 stringContentQuota -= val.Length;
1403 return sb.ToString();
1406 public override int AttributeCount
1411 public override string BaseURI
1413 get { return parentReader.BaseURI; }
1416 public override bool CanReadBinaryContent
1418 get { return true; }
1421 public override bool CanReadValueChunk
1423 get { return true; }
1426 public override bool CanResolveEntity
1428 get { return parentReader.CanResolveEntity; }
1431 public override void Close()
1434 readState = ReadState.Closed;
1439 if (binHexStream != null)
1441 binHexStream.Close();
1442 binHexStream = null;
1446 public override int Depth
1450 return (readState == ReadState.Interactive) ? parentReader.Depth + 1 : parentReader.Depth;
1454 public override bool EOF
1456 get { return readState == ReadState.EndOfFile; }
1459 public override string GetAttribute(int index)
1464 public override string GetAttribute(string name)
1469 public override string GetAttribute(string name, string ns)
1474 public override string GetAttribute(XmlDictionaryString localName, XmlDictionaryString ns)
1479 public override bool HasAttributes
1481 get { return false; }
1484 public override bool HasValue
1486 get { return readState == ReadState.Interactive; }
1489 public override bool IsDefault
1491 get { return false; }
1494 public override bool IsEmptyElement
1496 get { return false; }
1499 public override bool IsLocalName(string localName)
1504 public override bool IsLocalName(XmlDictionaryString localName)
1509 public override bool IsNamespaceUri(string ns)
1514 public override bool IsNamespaceUri(XmlDictionaryString ns)
1519 public override bool IsStartElement()
1524 public override bool IsStartElement(string localName)
1529 public override bool IsStartElement(string localName, string ns)
1534 public override bool IsStartElement(XmlDictionaryString localName, XmlDictionaryString ns)
1539 public override bool IsStartSubsetElement()
1544 public override string LocalName
1548 return (readState == ReadState.Interactive) ? String.Empty : parentReader.LocalName;
1552 public override string LookupNamespace(string ns)
1554 return parentReader.LookupNamespace(ns);
1557 public override void MoveToAttribute(int index)
1561 public override bool MoveToAttribute(string name)
1566 public override bool MoveToAttribute(string name, string ns)
1571 public override bool MoveToElement()
1576 public override bool MoveToFirstAttribute()
1581 public override bool MoveToNextAttribute()
1586 public override string Name
1590 return (readState == ReadState.Interactive) ? String.Empty : parentReader.Name;
1594 public override string NamespaceURI
1598 return (readState == ReadState.Interactive) ? String.Empty : parentReader.NamespaceURI;
1602 public override XmlNameTable NameTable
1604 get { return parentReader.NameTable; }
1607 public override string Prefix
1611 return (readState == ReadState.Interactive) ? String.Empty : parentReader.Prefix;
1615 public override char QuoteChar
1617 get { return parentReader.QuoteChar; }
1620 public override bool ReadAttributeValue()
1625 public override string ReadInnerXml()
1627 return ReadContentAsString();
1630 public override string ReadOuterXml()
1632 return ReadContentAsString();
1635 public override ReadState ReadState
1637 get { return readState; }
1640 public override void ResolveEntity()
1644 public override XmlReaderSettings Settings
1646 get { return parentReader.Settings; }
1649 public override void Skip()
1654 public override string this[int index]
1656 get { return null; }
1659 public override string this[string name]
1661 get { return null; }
1664 public override string this[string name, string ns]
1666 get { return null; }
1669 public override string XmlLang
1671 get { return parentReader.XmlLang; }
1674 public override XmlSpace XmlSpace
1676 get { return parentReader.XmlSpace; }
1679 public override Type ValueType
1683 return (readState == ReadState.Interactive) ? typeof(byte[]) : parentReader.ValueType;
1687 bool IXmlLineInfo.HasLineInfo()
1689 return ((IXmlLineInfo)parentReader).HasLineInfo();
1692 int IXmlLineInfo.LineNumber
1696 return ((IXmlLineInfo)parentReader).LineNumber;
1700 int IXmlLineInfo.LinePosition
1704 return ((IXmlLineInfo)parentReader).LinePosition;
1710 internal class MimeMessageReader
1712 static byte[] CRLFCRLF = new byte[] { (byte)'\r', (byte)'\n', (byte)'\r', (byte)'\n' };
1714 bool getContentStreamCalled;
1715 MimeHeaderReader mimeHeaderReader;
1716 DelimittedStreamReader reader;
1718 public MimeMessageReader(Stream stream)
1721 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("stream");
1723 this.reader = new DelimittedStreamReader(stream);
1724 this.mimeHeaderReader = new MimeHeaderReader(this.reader.GetNextStream(CRLFCRLF));
1727 public Stream GetContentStream()
1729 if (getContentStreamCalled)
1730 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MimeMessageGetContentStreamCalledAlready)));
1732 mimeHeaderReader.Close();
1734 Stream s = reader.GetNextStream(null);
1736 getContentStreamCalled = true;
1741 public MimeHeaders ReadHeaders(int maxBuffer, ref int remaining)
1743 MimeHeaders headers = new MimeHeaders();
1744 while (mimeHeaderReader.Read(maxBuffer, ref remaining))
1746 headers.Add(mimeHeaderReader.Name, mimeHeaderReader.Value, ref remaining);
1752 internal class MimeReader
1754 static byte[] CRLFCRLF = new byte[] { (byte)'\r', (byte)'\n', (byte)'\r', (byte)'\n' };
1756 byte[] boundaryBytes;
1758 Stream currentStream;
1759 MimeHeaderReader mimeHeaderReader;
1760 DelimittedStreamReader reader;
1761 byte[] scratch = new byte[2];
1763 public MimeReader(Stream stream, string boundary)
1766 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("stream");
1767 if (boundary == null)
1768 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("boundary");
1770 this.reader = new DelimittedStreamReader(stream);
1771 this.boundaryBytes = MimeWriter.GetBoundaryBytes(boundary);
1773 // Need to ensure that the content begins with a CRLF, in case the
1774 // outer construct has consumed the trailing CRLF
1775 this.reader.Push(this.boundaryBytes, 0, 2);
1780 this.reader.Close();
1783 /// Gets the content preceding the first part of the MIME multi-part message
1784 public string Preface
1788 if (content == null)
1790 Stream s = this.reader.GetNextStream(this.boundaryBytes);
1791 content = new StreamReader(s, System.Text.Encoding.ASCII, false, 256).ReadToEnd();
1793 if (content == null)
1794 content = string.Empty;
1800 public Stream GetContentStream()
1802 Fx.Assert(content != null, "");
1804 mimeHeaderReader.Close();
1806 return reader.GetNextStream(this.boundaryBytes);
1809 public bool ReadNextPart()
1811 string content = Preface;
1813 if (currentStream != null)
1815 currentStream.Close();
1816 currentStream = null;
1819 Stream stream = reader.GetNextStream(CRLFCRLF);
1824 if (BlockRead(stream, scratch, 0, 2) == 2)
1826 if (scratch[0] == '\r' && scratch[1] == '\n')
1828 if (mimeHeaderReader == null)
1829 mimeHeaderReader = new MimeHeaderReader(stream);
1831 mimeHeaderReader.Reset(stream);
1834 else if (scratch[0] == '-' && scratch[1] == '-')
1836 int read = BlockRead(stream, scratch, 0, 2);
1838 if (read < 2 || (scratch[0] == '\r' && scratch[1] == '\n'))
1843 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.MimeReaderTruncated)));
1846 public MimeHeaders ReadHeaders(int maxBuffer, ref int remaining)
1848 MimeHeaders headers = new MimeHeaders();
1849 while (mimeHeaderReader.Read(maxBuffer, ref remaining))
1851 headers.Add(mimeHeaderReader.Name, mimeHeaderReader.Value, ref remaining);
1856 int BlockRead(Stream stream, byte[] buffer, int offset, int count)
1861 int r = stream.Read(buffer, offset + read, count - read);
1865 } while (read < count);
1871 internal class DelimittedStreamReader
1873 bool canGetNextStream = true;
1875 // used for closing the reader, and validating that only one stream can be reading at a time.
1876 DelimittedReadStream currentStream;
1882 BufferedReadStream stream;
1884 public DelimittedStreamReader(Stream stream)
1886 this.stream = new BufferedReadStream(stream);
1891 this.stream.Close();
1894 // Closes the current stream. If the current stream is not the same as the caller, nothing is done.
1895 void Close(DelimittedReadStream caller)
1897 if (currentStream == caller)
1899 if (delimitter == null)
1905 if (scratch == null)
1907 scratch = new byte[1024];
1909 while (0 != Read(caller, this.scratch, 0, this.scratch.Length));
1912 currentStream = null;
1916 // Gets the next logical stream delimitted by the given sequence.
1917 public Stream GetNextStream(byte[] delimitter)
1919 if (currentStream != null)
1921 currentStream.Close();
1922 currentStream = null;
1925 if (!canGetNextStream)
1928 this.delimitter = delimitter;
1930 canGetNextStream = delimitter != null;
1932 currentStream = new DelimittedReadStream(this);
1934 return currentStream;
1944 MatchState MatchDelimitter(byte[] buffer, int start, int end)
1946 if (this.delimitter.Length > end - start)
1948 for (int i = end - start - 1; i >= 1; i--)
1950 if (buffer[start + i] != delimitter[i])
1951 return MatchState.False;
1953 return MatchState.InsufficientData;
1955 for (int i = delimitter.Length - 1; i >= 1; i--)
1957 if (buffer[start + i] != delimitter[i])
1958 return MatchState.False;
1960 return MatchState.True;
1963 int ProcessRead(byte[] buffer, int offset, int read)
1965 // nothing to process if 0 bytes were read
1969 for (int ptr = offset, end = offset + read; ptr < end; ptr++)
1971 if (buffer[ptr] == delimitter[0])
1973 switch (MatchDelimitter(buffer, ptr, end))
1975 case MatchState.True:
1977 int actual = ptr - offset;
1978 ptr += this.delimitter.Length;
1979 this.stream.Push(buffer, ptr, end - ptr);
1980 this.currentStream = null;
1983 case MatchState.False:
1985 case MatchState.InsufficientData:
1987 int actual = ptr - offset;
1990 this.stream.Push(buffer, ptr, end - ptr);
2004 int Read(DelimittedReadStream caller, byte[] buffer, int offset, int count)
2006 if (this.currentStream != caller)
2009 int read = this.stream.Read(buffer, offset, count);
2012 this.canGetNextStream = false;
2013 this.currentStream = null;
2017 // If delimitter is null, read until the underlying stream returns 0 bytes
2018 if (this.delimitter == null)
2021 // Scans the read data for the delimitter. If found, the number of bytes read are adjusted
2022 // to account for the number of bytes up to but not including the delimitter.
2023 int actual = ProcessRead(buffer, offset, read);
2027 if (this.matchBuffer == null || this.matchBuffer.Length < this.delimitter.Length - read)
2028 this.matchBuffer = new byte[this.delimitter.Length - read];
2030 int matched = this.stream.ReadBlock(this.matchBuffer, 0, this.delimitter.Length - read);
2032 if (MatchRemainder(read, matched))
2034 this.currentStream = null;
2039 this.stream.Push(this.matchBuffer, 0, matched);
2042 for (; i < read; i++)
2044 if (buffer[i] == this.delimitter[0])
2049 this.stream.Push(buffer, offset + i, read - i);
2058 bool MatchRemainder(int start, int count)
2060 if (start + count != this.delimitter.Length)
2063 for (count--; count >= 0; count--)
2065 if (this.delimitter[start + count] != this.matchBuffer[count])
2071 internal void Push(byte[] buffer, int offset, int count)
2073 this.stream.Push(buffer, offset, count);
2076 class DelimittedReadStream : Stream
2078 DelimittedStreamReader reader;
2080 public DelimittedReadStream(DelimittedStreamReader reader)
2083 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
2085 this.reader = reader;
2088 public override bool CanRead
2090 get { return true; }
2093 public override bool CanSeek
2095 get { return false; }
2098 public override bool CanWrite
2100 get { return false; }
2103 public override long Length
2105 #pragma warning suppress 56503 // Microsoft, required by the XmlReader
2106 get { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.SeekNotSupportedOnStream, this.GetType().FullName))); }
2109 public override long Position
2113 #pragma warning suppress 56503 // Microsoft, required by the XmlReader
2114 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.SeekNotSupportedOnStream, this.GetType().FullName)));
2116 set { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.SeekNotSupportedOnStream, this.GetType().FullName))); }
2119 public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
2121 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.WriteNotSupportedOnStream, this.GetType().FullName)));
2124 public override void Close()
2129 public override void EndWrite(IAsyncResult asyncResult)
2131 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.WriteNotSupportedOnStream, this.GetType().FullName)));
2134 public override void Flush()
2136 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.WriteNotSupportedOnStream, this.GetType().FullName)));
2139 public override int Read(byte[] buffer, int offset, int count)
2142 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("buffer");
2145 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", SR.GetString(SR.ValueMustBeNonNegative)));
2146 if (offset > buffer.Length)
2147 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", SR.GetString(SR.OffsetExceedsBufferSize, buffer.Length)));
2149 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.ValueMustBeNonNegative)));
2150 if (count > buffer.Length - offset)
2151 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.SizeExceedsRemainingBufferSpace, buffer.Length - offset)));
2153 return reader.Read(this, buffer, offset, count);
2156 public override long Seek(long offset, SeekOrigin origin)
2158 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.SeekNotSupportedOnStream, this.GetType().FullName)));
2161 public override void SetLength(long value)
2163 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.WriteNotSupportedOnStream, this.GetType().FullName)));
2166 public override void Write(byte[] buffer, int offset, int count)
2168 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.WriteNotSupportedOnStream, this.GetType().FullName)));
2174 internal class MimeHeaders
2176 static class Constants
2178 public const string ContentTransferEncoding = "content-transfer-encoding";
2179 public const string ContentID = "content-id";
2180 public const string ContentType = "content-type";
2181 public const string MimeVersion = "mime-version";
2184 Dictionary<string, MimeHeader> headers = new Dictionary<string, MimeHeader>();
2186 public MimeHeaders()
2190 public ContentTypeHeader ContentType
2195 if (headers.TryGetValue(Constants.ContentType, out header))
2196 return header as ContentTypeHeader;
2201 public ContentIDHeader ContentID
2206 if (headers.TryGetValue(Constants.ContentID, out header))
2207 return header as ContentIDHeader;
2212 public ContentTransferEncodingHeader ContentTransferEncoding
2217 if (headers.TryGetValue(Constants.ContentTransferEncoding, out header))
2218 return header as ContentTransferEncodingHeader;
2223 public MimeVersionHeader MimeVersion
2228 if (headers.TryGetValue(Constants.MimeVersion, out header))
2229 return header as MimeVersionHeader;
2234 public void Add(string name, string value, ref int remaining)
2237 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("name");
2240 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
2244 case Constants.ContentType:
2245 Add(new ContentTypeHeader(value));
2247 case Constants.ContentID:
2248 Add(new ContentIDHeader(name, value));
2250 case Constants.ContentTransferEncoding:
2251 Add(new ContentTransferEncodingHeader(value));
2253 case Constants.MimeVersion:
2254 Add(new MimeVersionHeader(value));
2257 // Skip any fields that are not recognized
2258 // Content-description is currently not stored since it is not used
2260 remaining += value.Length * sizeof(char);
2263 remaining += name.Length * sizeof(char);
2266 public void Add(MimeHeader header)
2269 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("header");
2271 MimeHeader existingHeader;
2272 if (headers.TryGetValue(header.Name, out existingHeader))
2273 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.MimeReaderHeaderAlreadyExists, header.Name)));
2275 headers.Add(header.Name, header);
2278 public void Release(ref int remaining)
2280 foreach (MimeHeader header in this.headers.Values)
2282 remaining += header.Value.Length * sizeof(char);
2288 internal class MimeHeader
2293 public MimeHeader(string name, string value)
2296 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("name");
2319 internal class ContentTypeHeader : MimeHeader
2321 public readonly static ContentTypeHeader Default = new ContentTypeHeader("application/octet-stream");
2323 public ContentTypeHeader(string value)
2324 : base("content-type", value)
2330 Dictionary<string, string> parameters;
2332 public string MediaType
2336 if (this.mediaType == null && Value != null)
2339 return this.mediaType;
2343 public string MediaSubtype
2347 if (this.subType == null && Value != null)
2350 return this.subType;
2354 public Dictionary<string, string> Parameters
2358 if (this.parameters == null)
2363 this.parameters = new Dictionary<string, string>();
2365 return this.parameters;
2371 if (this.parameters == null)
2374 this.parameters = new Dictionary<string, string>();
2375 this.mediaType = MailBnfHelper.ReadToken(Value, ref offset, null);
2376 if (offset >= Value.Length || Value[offset++] != '/')
2377 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.MimeContentTypeHeaderInvalid)));
2378 this.subType = MailBnfHelper.ReadToken(Value, ref offset, null);
2380 while (MailBnfHelper.SkipCFWS(Value, ref offset))
2382 if (offset >= Value.Length || Value[offset++] != ';')
2383 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.MimeContentTypeHeaderInvalid)));
2385 if (!MailBnfHelper.SkipCFWS(Value, ref offset))
2388 string paramAttribute = MailBnfHelper.ReadParameterAttribute(Value, ref offset, null);
2389 if (paramAttribute == null || offset >= Value.Length || Value[offset++] != '=')
2390 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.MimeContentTypeHeaderInvalid)));
2391 string paramValue = MailBnfHelper.ReadParameterValue(Value, ref offset, null);
2393 this.parameters.Add(paramAttribute.ToLowerInvariant(), paramValue);
2396 if (this.parameters.ContainsKey(MtomGlobals.StartInfoParam))
2398 // This allows us to maintain back compat with Orcas clients while allowing clients
2399 // following the spec (with action inside start-info) to interop with RFC 2387
2400 string startInfo = this.parameters[MtomGlobals.StartInfoParam];
2402 // we're only interested in finding the action here - skipping past the content type to the first ;
2403 int startInfoOffset = startInfo.IndexOf(';');
2404 if (startInfoOffset > -1)
2406 // keep going through the start-info string until we've reached the end of the stream
2407 while (MailBnfHelper.SkipCFWS(startInfo, ref startInfoOffset))
2409 // after having read through an attribute=value pair, we always expect to be at a ;
2410 if (startInfo[startInfoOffset] == ';')
2416 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.MimeContentTypeHeaderInvalid)));
2418 string paramAttribute = MailBnfHelper.ReadParameterAttribute(startInfo, ref startInfoOffset, null);
2419 if (paramAttribute == null || startInfoOffset >= startInfo.Length || startInfo[startInfoOffset++] != '=')
2420 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.MimeContentTypeHeaderInvalid)));
2421 string paramValue = MailBnfHelper.ReadParameterValue(startInfo, ref startInfoOffset, null);
2423 if (paramAttribute == MtomGlobals.ActionParam)
2425 this.parameters[MtomGlobals.ActionParam] = paramValue;
2435 enum ContentTransferEncoding
2444 internal class ContentTransferEncodingHeader : MimeHeader
2446 ContentTransferEncoding contentTransferEncoding;
2447 string contentTransferEncodingValue;
2449 public readonly static ContentTransferEncodingHeader Binary = new ContentTransferEncodingHeader(ContentTransferEncoding.Binary, "binary");
2450 public readonly static ContentTransferEncodingHeader EightBit = new ContentTransferEncodingHeader(ContentTransferEncoding.EightBit, "8bit");
2451 public readonly static ContentTransferEncodingHeader SevenBit = new ContentTransferEncodingHeader(ContentTransferEncoding.SevenBit, "7bit");
2453 public ContentTransferEncodingHeader(string value)
2454 : base("content-transfer-encoding", value.ToLowerInvariant())
2458 public ContentTransferEncodingHeader(ContentTransferEncoding contentTransferEncoding, string value)
2459 : base("content-transfer-encoding", null)
2461 this.contentTransferEncoding = contentTransferEncoding;
2462 this.contentTransferEncodingValue = value;
2465 public ContentTransferEncoding ContentTransferEncoding
2470 return this.contentTransferEncoding;
2474 public string ContentTransferEncodingValue
2479 return this.contentTransferEncodingValue;
2485 if (this.contentTransferEncodingValue == null)
2488 this.contentTransferEncodingValue = (Value.Length == 0) ? Value : ((Value[0] == '"') ? MailBnfHelper.ReadQuotedString(Value, ref offset, null) : MailBnfHelper.ReadToken(Value, ref offset, null));
2489 switch (this.contentTransferEncodingValue)
2492 this.contentTransferEncoding = ContentTransferEncoding.SevenBit;
2495 this.contentTransferEncoding = ContentTransferEncoding.EightBit;
2498 this.contentTransferEncoding = ContentTransferEncoding.Binary;
2501 this.contentTransferEncoding = ContentTransferEncoding.Other;
2508 internal class ContentIDHeader : MimeHeader
2510 public ContentIDHeader(string name, string value)
2516 internal class MimeVersionHeader : MimeHeader
2518 public static readonly MimeVersionHeader Default = new MimeVersionHeader("1.0");
2520 public MimeVersionHeader(string value)
2521 : base("mime-version", value)
2527 public string Version
2531 if (this.version == null && Value != null)
2533 return this.version;
2539 // shortcut for the most common case.
2542 this.version = "1.0";
2548 if (!MailBnfHelper.SkipCFWS(Value, ref offset))
2549 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.MimeVersionHeaderInvalid)));
2551 StringBuilder builder = new StringBuilder();
2552 MailBnfHelper.ReadDigits(Value, ref offset, builder);
2554 if ((!MailBnfHelper.SkipCFWS(Value, ref offset) || offset >= Value.Length || Value[offset++] != '.') || !MailBnfHelper.SkipCFWS(Value, ref offset))
2555 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.MimeVersionHeaderInvalid)));
2557 builder.Append('.');
2559 MailBnfHelper.ReadDigits(Value, ref offset, builder);
2561 this.version = builder.ToString();
2566 internal class MimeHeaderReader
2579 byte[] buffer = new byte[1024];
2583 ReadState readState = ReadState.ReadName;
2586 public MimeHeaderReader(Stream stream)
2589 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("stream");
2591 this.stream = stream;
2613 readState = ReadState.EOF;
2616 public bool Read(int maxBuffer, ref int remaining)
2621 while (readState != ReadState.EOF)
2623 if (offset == maxOffset)
2625 maxOffset = stream.Read(this.buffer, 0, this.buffer.Length);
2630 if (ProcessBuffer(maxBuffer, ref remaining))
2634 return value != null;
2637 [Fx.Tag.SecurityNote(Critical = "Calls unsafe code", Safe = "Demands for FullTrust")]
2638 [SecuritySafeCritical]
2639 [PermissionSet(SecurityAction.Demand, Unrestricted = true)]
2640 bool ProcessBuffer(int maxBuffer, ref int remaining)
2644 fixed (byte* pBuffer = this.buffer)
2646 byte* start = pBuffer + this.offset;
2647 byte* end = pBuffer + this.maxOffset;
2652 case ReadState.ReadName:
2653 for (; ptr < end; ptr++)
2657 AppendName(new string((sbyte*)start, 0, (int)(ptr - start)), maxBuffer, ref remaining);
2659 goto case ReadState.SkipWS;
2663 // convert to lower case up front.
2664 if (*ptr >= 'A' && *ptr <= 'Z')
2668 else if (*ptr < 33 || *ptr > 126)
2670 if (name == null && *ptr == (byte)'\r')
2673 if (ptr >= end || *ptr != '\n')
2674 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.MimeReaderMalformedHeader)));
2675 goto case ReadState.EOF;
2678 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.MimeHeaderInvalidCharacter, (char)(*ptr), ((int)(*ptr)).ToString("X", CultureInfo.InvariantCulture))));
2682 AppendName(new string((sbyte*)start, 0, (int)(ptr - start)), maxBuffer, ref remaining);
2683 readState = ReadState.ReadName;
2685 case ReadState.SkipWS:
2686 for (; ptr < end; ptr++)
2687 if (*ptr != (byte)'\t' && *ptr != ' ')
2688 goto case ReadState.ReadValue;
2689 readState = ReadState.SkipWS;
2691 case ReadState.ReadValue:
2693 for (; ptr < end; ptr++)
2695 if (*ptr == (byte)'\r')
2697 AppendValue(new string((sbyte*)start, 0, (int)(ptr - start)), maxBuffer, ref remaining);
2699 goto case ReadState.ReadLF;
2701 else if (*ptr == (byte)'\n')
2703 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.MimeReaderMalformedHeader)));
2706 AppendValue(new string((sbyte*)start, 0, (int)(ptr - start)), maxBuffer, ref remaining);
2707 readState = ReadState.ReadValue;
2709 case ReadState.ReadLF:
2712 if (*ptr != (byte)'\n')
2713 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.MimeReaderMalformedHeader)));
2715 goto case ReadState.ReadWS;
2717 readState = ReadState.ReadLF;
2719 case ReadState.ReadWS:
2722 if (*ptr != (byte)' ' && *ptr != (byte)'\t')
2724 readState = ReadState.ReadName;
2725 offset = (int)(ptr - pBuffer);
2728 goto case ReadState.ReadValue;
2730 readState = ReadState.ReadWS;
2733 readState = ReadState.EOF;
2734 offset = (int)(ptr - pBuffer);
2737 offset = (int)(ptr - pBuffer);
2747 if (readState != ReadState.ReadWS && readState != ReadState.ReadValue)
2748 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.MimeReaderMalformedHeader)));
2750 readState = ReadState.EOF;
2756 // Resets the mail field reader to the new stream to reuse buffers
2757 public void Reset(Stream stream)
2760 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("stream");
2762 if (readState != ReadState.EOF)
2763 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MimeReaderResetCalledBeforeEOF)));
2765 this.stream = stream;
2766 readState = ReadState.ReadName;
2773 void AppendValue(string value, int maxBuffer, ref int remaining)
2775 XmlMtomReader.DecrementBufferQuota(maxBuffer, ref remaining, value.Length * sizeof(char));
2776 if (this.value == null)
2779 this.value += value;
2782 void AppendName(string value, int maxBuffer, ref int remaining)
2784 XmlMtomReader.DecrementBufferQuota(maxBuffer, ref remaining, value.Length * sizeof(char));
2785 if (this.name == null)
2793 internal class BufferedReadStream : Stream
2796 byte[] storedBuffer;
2801 public BufferedReadStream(Stream stream)
2802 : this(stream, false)
2806 public BufferedReadStream(Stream stream, bool readMore)
2809 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("stream");
2811 this.stream = stream;
2812 this.readMore = readMore;
2815 public override bool CanWrite
2817 get { return false; }
2820 public override bool CanSeek
2822 get { return false; }
2825 public override bool CanRead
2827 get { return stream.CanRead; }
2830 public override long Length
2834 #pragma warning suppress 56503 // Microsoft, required by the Stream contract
2835 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.SeekNotSupportedOnStream, stream.GetType().FullName)));
2839 public override long Position
2843 #pragma warning suppress 56503 // Microsoft, required by the Stream contract
2844 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.SeekNotSupportedOnStream, stream.GetType().FullName)));
2848 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.SeekNotSupportedOnStream, stream.GetType().FullName)));
2852 public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
2855 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.ReadNotSupportedOnStream, stream.GetType().FullName)));
2857 return stream.BeginRead(buffer, offset, count, callback, state);
2860 public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
2862 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.WriteNotSupportedOnStream, stream.GetType().FullName)));
2865 public override void Close()
2870 public override int EndRead(IAsyncResult asyncResult)
2873 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.ReadNotSupportedOnStream, stream.GetType().FullName)));
2875 return stream.EndRead(asyncResult);
2878 public override void EndWrite(IAsyncResult asyncResult)
2880 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.WriteNotSupportedOnStream, stream.GetType().FullName)));
2883 public override void Flush()
2888 public override int Read(byte[] buffer, int offset, int count)
2891 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.ReadNotSupportedOnStream, stream.GetType().FullName)));
2894 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("buffer");
2897 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", SR.GetString(SR.ValueMustBeNonNegative)));
2898 if (offset > buffer.Length)
2899 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", SR.GetString(SR.OffsetExceedsBufferSize, buffer.Length)));
2901 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.ValueMustBeNonNegative)));
2902 if (count > buffer.Length - offset)
2903 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.SizeExceedsRemainingBufferSpace, buffer.Length - offset)));
2906 if (this.storedOffset < this.storedLength)
2908 read = Math.Min(count, this.storedLength - this.storedOffset);
2909 Buffer.BlockCopy(this.storedBuffer, this.storedOffset, buffer, offset, read);
2910 this.storedOffset += read;
2911 if (read == count || !this.readMore)
2916 return read + stream.Read(buffer, offset, count);
2919 public override int ReadByte()
2921 if (this.storedOffset < this.storedLength)
2922 return (int)this.storedBuffer[this.storedOffset++];
2924 return base.ReadByte();
2927 public int ReadBlock(byte[] buffer, int offset, int count)
2931 while (total < count && (read = Read(buffer, offset + total, count - total)) != 0)
2938 public void Push(byte[] buffer, int offset, int count)
2943 if (this.storedOffset == this.storedLength)
2945 if (this.storedBuffer == null || this.storedBuffer.Length < count)
2946 this.storedBuffer = new byte[count];
2947 this.storedOffset = 0;
2948 this.storedLength = count;
2952 // if there's room to just insert before existing data
2953 if (count <= this.storedOffset)
2954 this.storedOffset -= count;
2955 // if there's room in the buffer but need to shift things over
2956 else if (count <= this.storedBuffer.Length - this.storedLength + this.storedOffset)
2958 Buffer.BlockCopy(this.storedBuffer, this.storedOffset, this.storedBuffer, count, this.storedLength - this.storedOffset);
2959 this.storedLength += count - this.storedOffset;
2960 this.storedOffset = 0;
2964 byte[] newBuffer = new byte[count + this.storedLength - this.storedOffset];
2965 Buffer.BlockCopy(this.storedBuffer, this.storedOffset, newBuffer, count, this.storedLength - this.storedOffset);
2966 this.storedLength += count - this.storedOffset;
2967 this.storedOffset = 0;
2968 this.storedBuffer = newBuffer;
2971 Buffer.BlockCopy(buffer, offset, this.storedBuffer, this.storedOffset, count);
2974 public override long Seek(long offset, SeekOrigin origin)
2976 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.SeekNotSupportedOnStream, stream.GetType().FullName)));
2979 public override void SetLength(long value)
2981 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.SeekNotSupportedOnStream, stream.GetType().FullName)));
2984 public override void Write(byte[] buffer, int offset, int count)
2986 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.WriteNotSupportedOnStream, stream.GetType().FullName)));
2990 internal static class MailBnfHelper
2992 static bool[] s_fqtext = new bool[128];
2993 static bool[] s_ttext = new bool[128];
2994 static bool[] s_digits = new bool[128];
2995 static bool[] s_boundary = new bool[128];
2997 static MailBnfHelper()
2999 // fqtext = %d1-9 / %d11 / %d12 / %d14-33 / %d35-91 / %d93-127
3000 for (int i = 1; i <= 9; i++) { s_fqtext[i] = true; }
3001 s_fqtext[11] = true;
3002 s_fqtext[12] = true;
3003 for (int i = 14; i <= 33; i++) { s_fqtext[i] = true; }
3004 for (int i = 35; i <= 91; i++) { s_fqtext[i] = true; }
3005 for (int i = 93; i <= 127; i++) { s_fqtext[i] = true; }
3007 // ttext = %d33-126 except '()<>@,;:\"/[]?='
3008 for (int i = 33; i <= 126; i++) { s_ttext[i] = true; }
3009 s_ttext['('] = false;
3010 s_ttext[')'] = false;
3011 s_ttext['<'] = false;
3012 s_ttext['>'] = false;
3013 s_ttext['@'] = false;
3014 s_ttext[','] = false;
3015 s_ttext[';'] = false;
3016 s_ttext[':'] = false;
3017 s_ttext['\\'] = false;
3018 s_ttext['"'] = false;
3019 s_ttext['/'] = false;
3020 s_ttext['['] = false;
3021 s_ttext[']'] = false;
3022 s_ttext['?'] = false;
3023 s_ttext['='] = false;
3026 for (int i = 48; i <= 57; i++)
3029 // boundary = DIGIT / ALPHA / "'" / "(" / ")" / "+" / "_" / "," / "-" / "." / "/" / ":" / "=" / "?" / " "
3030 // cannot end with " "
3031 for (int i = '0'; i <= '9'; i++) { s_boundary[i] = true; }
3032 for (int i = 'A'; i <= 'Z'; i++) { s_boundary[i] = true; }
3033 for (int i = 'a'; i <= 'z'; i++) { s_boundary[i] = true; }
3034 s_boundary['\''] = true;
3035 s_boundary['('] = true;
3036 s_boundary[')'] = true;
3037 s_boundary['+'] = true;
3038 s_boundary['_'] = true;
3039 s_boundary[','] = true;
3040 s_boundary['-'] = true;
3041 s_boundary['.'] = true;
3042 s_boundary['/'] = true;
3043 s_boundary[':'] = true;
3044 s_boundary['='] = true;
3045 s_boundary['?'] = true;
3046 s_boundary[' '] = true;
3049 public static bool SkipCFWS(string data, ref int offset)
3052 for (; offset < data.Length; offset++)
3054 if (data[offset] > 127)
3055 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.MimeHeaderInvalidCharacter, data[offset], ((int)data[offset]).ToString("X", CultureInfo.InvariantCulture))));
3056 else if (data[offset] == '\\' && comments > 0)
3058 else if (data[offset] == '(')
3060 else if (data[offset] == ')')
3062 else if (data[offset] != ' ' && data[offset] != '\t' && comments == 0)
3068 public static string ReadQuotedString(string data, ref int offset, StringBuilder builder)
3070 // assume first char is the opening quote
3071 int start = ++offset;
3072 StringBuilder localBuilder = (builder != null ? builder : new StringBuilder());
3073 for (; offset < data.Length; offset++)
3075 if (data[offset] == '\\')
3077 localBuilder.Append(data, start, offset - start);
3081 else if (data[offset] == '"')
3083 localBuilder.Append(data, start, offset - start);
3085 return (builder != null ? null : localBuilder.ToString());
3087 else if (!(data[offset] < s_fqtext.Length && s_fqtext[data[offset]]))
3089 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.MimeHeaderInvalidCharacter, data[offset], ((int)data[offset]).ToString("X", CultureInfo.InvariantCulture))));
3092 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.MimeReaderMalformedHeader)));
3095 public static string ReadParameterAttribute(string data, ref int offset, StringBuilder builder)
3097 if (!SkipCFWS(data, ref offset))
3100 return ReadToken(data, ref offset, null);
3103 public static string ReadParameterValue(string data, ref int offset, StringBuilder builder)
3105 if (!SkipCFWS(data, ref offset))
3106 return string.Empty;
3108 if (offset < data.Length && data[offset] == '"')
3109 return ReadQuotedString(data, ref offset, builder);
3111 return ReadToken(data, ref offset, builder);
3114 public static string ReadToken(string data, ref int offset, StringBuilder builder)
3117 for (; offset < data.Length; offset++)
3119 if (data[offset] > s_ttext.Length)
3121 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.MimeHeaderInvalidCharacter, data[offset], ((int)data[offset]).ToString("X", CultureInfo.InvariantCulture))));
3123 else if (!s_ttext[data[offset]])
3128 return data.Substring(start, offset - start);
3131 public static string ReadDigits(string data, ref int offset, StringBuilder builder)
3134 StringBuilder localBuilder = (builder != null ? builder : new StringBuilder());
3135 for (; offset < data.Length && data[offset] < s_digits.Length && s_digits[data[offset]]; offset++);
3136 localBuilder.Append(data, start, offset - start);
3137 return (builder != null ? null : localBuilder.ToString());
3140 public static bool IsValidMimeBoundary(string data)
3142 int length = (data == null) ? 0 : data.Length;
3143 if (length == 0 || length > 70 || data[length - 1] == ' ')
3146 for (int i = 0; i < length; i++)
3148 if (!(data[i] < s_boundary.Length && s_boundary[data[i]]))