1 
2 using System;
3 using System.Xml;
4 using System.Diagnostics;
5 using System.Collections;
6 using System.Collections.Generic;
7 
8 using System.Threading.Tasks;
9 
10 namespace System.Xml {
11 
12     //
13     // XmlCharCheckingReaderWithNS
14     //
15     internal partial class XmlCharCheckingReader : XmlWrappingReader {
16 
ReadAsync()17         public override async Task< bool > ReadAsync() {
18             switch ( state ) {
19                 case State.Initial:
20                     state = State.Interactive;
21                     if ( base.reader.ReadState == ReadState.Initial ) {
22                         goto case State.Interactive;
23                     }
24                     break;
25 
26                 case State.Error:
27                     return false;
28 
29                 case State.InReadBinary:
30                     await FinishReadBinaryAsync().ConfigureAwait(false);
31                     state = State.Interactive;
32                     goto case State.Interactive;
33 
34                 case State.Interactive:
35                     if ( !await base.reader.ReadAsync().ConfigureAwait(false) ) {
36                         return false;
37                     }
38                     break;
39 
40                 default:
41                     Debug.Assert( false );
42                     return false;
43             }
44 
45             XmlNodeType nodeType = base.reader.NodeType;
46 
47             if ( !checkCharacters ) {
48                 switch ( nodeType ) {
49                     case XmlNodeType.Comment:
50                         if ( ignoreComments ) {
51                             return await ReadAsync().ConfigureAwait(false);
52                         }
53                         break;
54                     case XmlNodeType.Whitespace:
55                         if ( ignoreWhitespace ) {
56                             return await ReadAsync().ConfigureAwait(false);
57                         }
58                         break;
59                     case XmlNodeType.ProcessingInstruction:
60                         if ( ignorePis ) {
61                             return await ReadAsync().ConfigureAwait(false);
62                         }
63                         break;
64                     case XmlNodeType.DocumentType:
65                         if ( dtdProcessing == DtdProcessing.Prohibit ) {
66                             Throw( Res.Xml_DtdIsProhibitedEx, string.Empty );
67                         }
68                         else if ( dtdProcessing == DtdProcessing.Ignore ) {
69                             return await ReadAsync().ConfigureAwait(false);
70                         }
71                         break;
72                 }
73                 return true;
74             }
75             else {
76                 switch ( nodeType ) {
77                     case XmlNodeType.Element:
78                         if ( checkCharacters ) {
79                             // check element name
80                             ValidateQName( base.reader.Prefix, base.reader.LocalName );
81 
82                             // check values of attributes
83                             if ( base.reader.MoveToFirstAttribute() ) {
84                                 do {
85                                     ValidateQName( base.reader.Prefix, base.reader.LocalName );
86                                     CheckCharacters( base.reader.Value );
87                                 } while ( base.reader.MoveToNextAttribute() );
88 
89                                 base.reader.MoveToElement();
90                             }
91                         }
92                         break;
93 
94                     case XmlNodeType.Text:
95                     case XmlNodeType.CDATA:
96                         if ( checkCharacters ) {
97                             CheckCharacters( await base.reader.GetValueAsync().ConfigureAwait(false) );
98                         }
99                         break;
100 
101                     case XmlNodeType.EntityReference:
102                         if ( checkCharacters ) {
103                             // check name
104                             ValidateQName( base.reader.Name );
105                         }
106                         break;
107 
108                     case XmlNodeType.ProcessingInstruction:
109                         if ( ignorePis ) {
110                             return await ReadAsync().ConfigureAwait(false);
111                         }
112                         if ( checkCharacters ) {
113                             ValidateQName( base.reader.Name );
114                             CheckCharacters( base.reader.Value );
115                         }
116                         break;
117 
118                     case XmlNodeType.Comment:
119                         if ( ignoreComments ) {
120                             return await ReadAsync().ConfigureAwait(false);
121                         }
122                         if ( checkCharacters ) {
123                             CheckCharacters( base.reader.Value );
124                         }
125                         break;
126 
127                     case XmlNodeType.DocumentType:
128                         if ( dtdProcessing == DtdProcessing.Prohibit ) {
129                             Throw( Res.Xml_DtdIsProhibitedEx, string.Empty );
130                         }
131                         else if ( dtdProcessing == DtdProcessing.Ignore ) {
132                             return await ReadAsync().ConfigureAwait(false);
133                         }
134                         if ( checkCharacters ) {
135                             ValidateQName( base.reader.Name );
136                             CheckCharacters( base.reader.Value );
137 
138                             string str;
139                             str = base.reader.GetAttribute( "SYSTEM" );
140                             if ( str != null ) {
141                                 CheckCharacters( str );
142                             }
143 
144                             str = base.reader.GetAttribute( "PUBLIC" );
145                             if ( str != null ) {
146                                 int i;
147                                 if ( ( i = xmlCharType.IsPublicId( str ) ) >= 0 ) {
148                                     Throw( Res.Xml_InvalidCharacter, XmlException.BuildCharExceptionArgs( str, i ) );
149                                 }
150                             }
151                         }
152                         break;
153 
154                     case XmlNodeType.Whitespace:
155                         if ( ignoreWhitespace ) {
156                             return await ReadAsync().ConfigureAwait(false);
157                         }
158                         if ( checkCharacters ) {
159                             CheckWhitespace( await base.reader.GetValueAsync().ConfigureAwait(false) );
160                         }
161                         break;
162 
163                     case XmlNodeType.SignificantWhitespace:
164                         if ( checkCharacters ) {
165                             CheckWhitespace( await base.reader.GetValueAsync().ConfigureAwait(false) );
166                         }
167                         break;
168 
169                     case XmlNodeType.EndElement:
170                         if ( checkCharacters ) {
171                             ValidateQName( base.reader.Prefix, base.reader.LocalName );
172                         }
173                         break;
174 
175                     default:
176                         break;
177                 }
178                 lastNodeType = nodeType;
179                 return true;
180             }
181         }
182 
ReadContentAsBase64Async( byte[] buffer, int index, int count )183         public override async Task< int > ReadContentAsBase64Async( byte[] buffer, int index, int count ) {
184             if (ReadState != ReadState.Interactive) {
185                 return 0;
186             }
187 
188             if ( state != State.InReadBinary ) {
189                 // forward ReadBase64Chunk calls into the base (wrapped) reader if possible, i.e. if it can read binary and we
190                 // should not check characters
191                 if ( base.CanReadBinaryContent && ( !checkCharacters ) ) {
192                     readBinaryHelper = null;
193                     state = State.InReadBinary;
194                     return await base.ReadContentAsBase64Async( buffer, index, count ).ConfigureAwait(false);
195                 }
196                 // the wrapped reader cannot read chunks or we are on an element where we should check characters or ignore white spaces
197                 else {
198                     readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset( readBinaryHelper, this );
199                 }
200             }
201             else {
202                 // forward calls into wrapped reader
203                 if ( readBinaryHelper == null ) {
204                     return await base.ReadContentAsBase64Async( buffer, index, count ).ConfigureAwait(false);
205                 }
206             }
207 
208             // turn off InReadBinary state in order to have a normal Read() behavior when called from readBinaryHelper
209             state = State.Interactive;
210 
211             // call to the helper
212             int readCount = await readBinaryHelper.ReadContentAsBase64Async(buffer, index, count).ConfigureAwait(false);
213 
214             // turn on InReadBinary in again and return
215             state = State.InReadBinary;
216             return readCount;
217         }
218 
ReadContentAsBinHexAsync( byte[] buffer, int index, int count )219         public override async Task< int > ReadContentAsBinHexAsync( byte[] buffer, int index, int count ) {
220             if (ReadState != ReadState.Interactive) {
221                 return 0;
222             }
223 
224             if ( state != State.InReadBinary ) {
225                 // forward ReadBinHexChunk calls into the base (wrapped) reader if possible, i.e. if it can read chunks and we
226                 // should not check characters
227                 if ( base.CanReadBinaryContent && ( !checkCharacters ) ) {
228                     readBinaryHelper = null;
229                     state = State.InReadBinary;
230                     return await base.ReadContentAsBinHexAsync( buffer, index, count ).ConfigureAwait(false);
231                 }
232                 // the wrapped reader cannot read chunks or we are on an element where we should check characters or ignore white spaces
233                 else {
234                     readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset( readBinaryHelper, this );
235                 }
236             }
237             else {
238                 // forward calls into wrapped reader
239                 if ( readBinaryHelper == null ) {
240                     return await base.ReadContentAsBinHexAsync( buffer, index, count ).ConfigureAwait(false);
241                 }
242             }
243 
244             // turn off InReadBinary state in order to have a normal Read() behavior when called from readBinaryHelper
245             state = State.Interactive;
246 
247             // call to the helper
248             int readCount = await readBinaryHelper.ReadContentAsBinHexAsync(buffer, index, count).ConfigureAwait(false);
249 
250             // turn on InReadBinary in again and return
251             state = State.InReadBinary;
252             return readCount;
253         }
254 
ReadElementContentAsBase64Async( byte[] buffer, int index, int count )255         public override async Task< int > ReadElementContentAsBase64Async( byte[] buffer, int index, int count ) {
256             // check arguments
257             if (buffer == null) {
258                 throw new ArgumentNullException("buffer");
259             }
260             if (count < 0) {
261                 throw new ArgumentOutOfRangeException("count");
262             }
263             if (index < 0) {
264                 throw new ArgumentOutOfRangeException("index");
265             }
266             if (buffer.Length - index < count) {
267                 throw new ArgumentOutOfRangeException("count");
268             }
269 
270             if (ReadState != ReadState.Interactive) {
271                 return 0;
272             }
273 
274             if ( state != State.InReadBinary ) {
275                 // forward ReadBase64Chunk calls into the base (wrapped) reader if possible, i.e. if it can read binary and we
276                 // should not check characters
277                 if ( base.CanReadBinaryContent && ( !checkCharacters ) ) {
278                     readBinaryHelper = null;
279                     state = State.InReadBinary;
280                     return await base.ReadElementContentAsBase64Async( buffer, index, count ).ConfigureAwait(false);
281                 }
282                 // the wrapped reader cannot read chunks or we are on an element where we should check characters or ignore white spaces
283                 else {
284                     readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset( readBinaryHelper, this );
285                 }
286             }
287             else {
288                 // forward calls into wrapped reader
289                 if ( readBinaryHelper == null ) {
290                     return await base.ReadElementContentAsBase64Async( buffer, index, count ).ConfigureAwait(false);
291                 }
292             }
293 
294             // turn off InReadBinary state in order to have a normal Read() behavior when called from readBinaryHelper
295             state = State.Interactive;
296 
297             // call to the helper
298             int readCount = await readBinaryHelper.ReadElementContentAsBase64Async(buffer, index, count).ConfigureAwait(false);
299 
300             // turn on InReadBinary in again and return
301             state = State.InReadBinary;
302             return readCount;
303         }
304 
ReadElementContentAsBinHexAsync( byte[] buffer, int index, int count )305         public override async Task< int > ReadElementContentAsBinHexAsync( byte[] buffer, int index, int count ) {
306             // check arguments
307             if (buffer == null) {
308                 throw new ArgumentNullException("buffer");
309             }
310             if (count < 0) {
311                 throw new ArgumentOutOfRangeException("count");
312             }
313             if (index < 0) {
314                 throw new ArgumentOutOfRangeException("index");
315             }
316             if (buffer.Length - index < count) {
317                 throw new ArgumentOutOfRangeException("count");
318             }
319             if (ReadState != ReadState.Interactive) {
320                 return 0;
321             }
322 
323             if ( state != State.InReadBinary ) {
324                 // forward ReadBinHexChunk calls into the base (wrapped) reader if possible, i.e. if it can read chunks and we
325                 // should not check characters
326                 if ( base.CanReadBinaryContent && ( !checkCharacters ) ) {
327                     readBinaryHelper = null;
328                     state = State.InReadBinary;
329                     return await base.ReadElementContentAsBinHexAsync( buffer, index, count ).ConfigureAwait(false);
330                 }
331                 // the wrapped reader cannot read chunks or we are on an element where we should check characters or ignore white spaces
332                 else {
333                     readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset( readBinaryHelper, this );
334                 }
335             }
336             else {
337                 // forward calls into wrapped reader
338                 if ( readBinaryHelper == null ) {
339                     return await base.ReadElementContentAsBinHexAsync( buffer, index, count ).ConfigureAwait(false);
340                 }
341             }
342 
343             // turn off InReadBinary state in order to have a normal Read() behavior when called from readBinaryHelper
344             state = State.Interactive;
345 
346             // call to the helper
347             int readCount = await readBinaryHelper.ReadElementContentAsBinHexAsync(buffer, index, count).ConfigureAwait(false);
348 
349             // turn on InReadBinary in again and return
350             state = State.InReadBinary;
351             return readCount;
352         }
353 
FinishReadBinaryAsync()354         private async Task FinishReadBinaryAsync() {
355             state = State.Interactive;
356             if ( readBinaryHelper != null ) {
357                 await readBinaryHelper.FinishAsync().ConfigureAwait(false);
358             }
359         }
360 
361     }
362 }
363